diff options
author | phk <phk@FreeBSD.org> | 2001-09-22 16:34:59 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2001-09-22 16:34:59 +0000 |
commit | 505b425ab926e05e0da7c15cbf439a087551732f (patch) | |
tree | ade25dcf444668903d2333eea6ad4c7413448d01 /sys | |
parent | d83406693a6fa64bd70b2c2279c0f51a2309ca61 (diff) | |
download | FreeBSD-src-505b425ab926e05e0da7c15cbf439a087551732f.zip FreeBSD-src-505b425ab926e05e0da7c15cbf439a087551732f.tar.gz |
Give the pps driver an additional 8 inputs if we can persuade the
ppc to go into EPP mode. These 8 inputs are timestamped in polled
loop so their resolution will be nanoseconds but their granularity
will only be 1/hz.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/ppbus/pps.c | 197 |
1 files changed, 154 insertions, 43 deletions
diff --git a/sys/dev/ppbus/pps.c b/sys/dev/ppbus/pps.c index 3b69097..5809400 100644 --- a/sys/dev/ppbus/pps.c +++ b/sys/dev/ppbus/pps.c @@ -34,22 +34,24 @@ #define PPS_NAME "pps" /* our official name */ struct pps_data { - int pps_open; struct ppb_device pps_dev; - struct pps_state pps; + struct pps_state pps[9]; + dev_t devs[9]; + device_t ppsdev; + device_t ppbus; + int busy; + struct callout_handle timeout; + int lastdata; struct resource *intr_resource; /* interrupt resource */ void *intr_cookie; /* interrupt registration cookie */ }; static void ppsintr(void *arg); +static void ppshcpoll(void *arg); #define DEVTOSOFTC(dev) \ ((struct pps_data *)device_get_softc(dev)) -#define UNITOSOFTC(unit) \ - ((struct pps_data *)devclass_get_softc(pps_devclass, (unit))) -#define UNITODEVICE(unit) \ - (devclass_get_device(pps_devclass, (unit))) static devclass_t pps_devclass; @@ -82,23 +84,91 @@ ppsidentify(driver_t *driver, device_t parent) } static int +ppstry(device_t ppbus, int send, int expect) +{ + int i; + + ppb_wdtr(ppbus, send); + i = ppb_rdtr(ppbus); + printf("S: %02x E: %02x G: %02x\n", send, expect, i); + return (i != expect); +} + +static int ppsprobe(device_t ppsdev) { struct pps_data *sc; dev_t dev; - int unit; + device_t ppbus; + int unit, i; + + device_set_desc(ppsdev, "Pulse per second Timing Interface"); sc = DEVTOSOFTC(ppsdev); bzero(sc, sizeof(struct pps_data)); - - unit = device_get_unit(ppsdev); + sc->ppsdev = ppsdev; + ppbus = sc->ppbus = device_get_parent(ppsdev); + unit = device_get_unit(ppbus); dev = make_dev(&pps_cdevsw, unit, UID_ROOT, GID_WHEEL, 0644, PPS_NAME "%d", unit); - - device_set_desc(ppsdev, "Pulse per second Timing Interface"); - - sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; - pps_init(&sc->pps); + sc->devs[0] = dev; + sc->pps[0].ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; + dev->si_drv1 = sc; + dev->si_drv2 = (void*)0; + pps_init(&sc->pps[0]); + + if (ppb_request_bus(ppbus, ppsdev, PPB_DONTWAIT)) + return (0); + + + do { + i = ppb_set_mode(sc->ppbus, PPB_EPP); + printf("EPP: %d %d\n", i, PPB_IN_EPP_MODE(sc->ppbus)); + if (i == -1) + break; + i = 0; + ppb_wctr(ppbus, i); + if (ppstry(ppbus, 0x00, 0x00)) + break; + if (ppstry(ppbus, 0x55, 0x55)) + break; + if (ppstry(ppbus, 0xaa, 0xaa)) + break; + if (ppstry(ppbus, 0xff, 0xff)) + break; + + i = IRQENABLE | PCD | STROBE | nINIT | SELECTIN; + ppb_wctr(ppbus, i); + printf("CTR = %02x (%02x)\n", ppb_rctr(ppbus), i); + if (ppstry(ppbus, 0x00, 0x00)) + break; + if (ppstry(ppbus, 0x55, 0x00)) + break; + if (ppstry(ppbus, 0xaa, 0x00)) + break; + if (ppstry(ppbus, 0xff, 0x00)) + break; + + i = IRQENABLE | PCD | nINIT | SELECTIN; + ppb_wctr(ppbus, i); + printf("CTR = %02x (%02x)\n", ppb_rctr(ppbus), i); + ppstry(ppbus, 0x00, 0xff); + ppstry(ppbus, 0x55, 0xff); + ppstry(ppbus, 0xaa, 0xff); + ppstry(ppbus, 0xff, 0xff); + + for (i = 1; i < 9; i++) { + dev = make_dev(&pps_cdevsw, unit + 0x10000 * i, + UID_ROOT, GID_WHEEL, 0644, PPS_NAME "%db%d", unit, i - 1); + sc->devs[i] = dev; + sc->pps[i].ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR; + dev->si_drv1 = sc; + dev->si_drv2 = (void*)i; + pps_init(&sc->pps[i]); + } + } while (0); + i = ppb_set_mode(sc->ppbus, PPB_COMPATIBLE); + ppb_release_bus(ppbus, ppsdev); return (0); } @@ -106,7 +176,7 @@ static int ppsattach(device_t dev) { struct pps_data *sc = DEVTOSOFTC(dev); - device_t ppbus = device_get_parent(dev); + device_t ppbus = sc->ppbus; int irq, zero = 0; /* retrieve the ppbus irq */ @@ -127,13 +197,14 @@ ppsattach(device_t dev) static int ppsopen(dev_t dev, int flags, int fmt, struct thread *td) { - u_int unit = minor(dev); - struct pps_data *sc = UNITOSOFTC(unit); - device_t ppsdev = UNITODEVICE(unit); - device_t ppbus = device_get_parent(ppsdev); - int error; + struct pps_data *sc = dev->si_drv1; + int subdev = (int)dev->si_drv2; + int error, i; + + if (!sc->busy) { + device_t ppsdev = sc->ppsdev; + device_t ppbus = sc->ppbus; - if (!sc->pps_open) { if (ppb_request_bus(ppbus, ppsdev, PPB_WAIT|PPB_INTR)) return (EINTR); @@ -145,39 +216,79 @@ ppsopen(dev_t dev, int flags, int fmt, struct thread *td) return (error); } - ppb_wctr(ppbus, 0); - ppb_wctr(ppbus, IRQENABLE); - sc->pps_open = 1; - } + i = ppb_set_mode(sc->ppbus, PPB_PS2); + printf("EPP: %d %d\n", i, PPB_IN_EPP_MODE(sc->ppbus)); + i = IRQENABLE | PCD | nINIT | SELECTIN; + ppb_wctr(ppbus, i); + } + if (subdev > 0 && !(sc->busy & ~1)) { + sc->timeout = timeout(ppshcpoll, sc, 1); + sc->lastdata = ppb_rdtr(sc->ppbus); + } + sc->busy |= (1 << subdev); return(0); } static int ppsclose(dev_t dev, int flags, int fmt, struct thread *td) { - u_int unit = minor(dev); - struct pps_data *sc = UNITOSOFTC(unit); - device_t ppsdev = UNITODEVICE(unit); - device_t ppbus = device_get_parent(ppsdev); + struct pps_data *sc = dev->si_drv1; + int subdev = (int)dev->si_drv2; + + sc->pps[subdev].ppsparam.mode = 0; /* PHK ??? */ + sc->busy &= ~(1 << subdev); + if (subdev > 0 && !(sc->busy & ~1)) + untimeout(ppshcpoll, sc, sc->timeout); + if (!sc->busy) { + device_t ppsdev = sc->ppsdev; + device_t ppbus = sc->ppbus; + + ppb_wdtr(ppbus, 0); + ppb_wctr(ppbus, 0); - sc->pps.ppsparam.mode = 0; /* PHK ??? */ + /* Note: the interrupt handler is automatically detached */ + ppb_set_mode(ppbus, PPB_COMPATIBLE); + ppb_release_bus(ppbus, ppsdev); + } + return(0); +} - ppb_wdtr(ppbus, 0); - ppb_wctr(ppbus, 0); +static void +ppshcpoll(void *arg) +{ + struct pps_data *sc = arg; + int i, j, k, l; + struct timecounter *tc; + unsigned count; - /* Note: the interrupt handler is automatically detached */ - ppb_release_bus(ppbus, ppsdev); - sc->pps_open = 0; - return(0); + if (!(sc->busy & ~1)) + return; + sc->timeout = timeout(ppshcpoll, sc, 1); + i = ppb_rdtr(sc->ppbus); + if (i == sc->lastdata) + return; + tc = timecounter; + count = timecounter->tc_get_timecount(tc); + l = sc->lastdata ^ i; + k = 1; + for (j = 1; j < 9; j ++) { + if (l & k) + pps_event(&sc->pps[j], tc, count, + i & k ? + PPS_CAPTUREASSERT : PPS_CAPTURECLEAR + ); + k += k; + } + sc->lastdata = i; } static void ppsintr(void *arg) { device_t ppsdev = (device_t)arg; - device_t ppbus = device_get_parent(ppsdev); struct pps_data *sc = DEVTOSOFTC(ppsdev); + device_t ppbus = sc->ppbus; struct timecounter *tc; unsigned count; @@ -185,20 +296,20 @@ ppsintr(void *arg) count = timecounter->tc_get_timecount(tc); if (!(ppb_rstr(ppbus) & nACK)) return; - if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) + if (sc->pps[0].ppsparam.mode & PPS_ECHOASSERT) ppb_wctr(ppbus, IRQENABLE | AUTOFEED); - pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT); - if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) + pps_event(&sc->pps[0], tc, count, PPS_CAPTUREASSERT); + if (sc->pps[0].ppsparam.mode & PPS_ECHOASSERT) ppb_wctr(ppbus, IRQENABLE); } static int ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct thread *td) { - u_int unit = minor(dev); - struct pps_data *sc = UNITOSOFTC(unit); + struct pps_data *sc = dev->si_drv1; + int subdev = (int)dev->si_drv2; - return (pps_ioctl(cmd, data, &sc->pps)); + return (pps_ioctl(cmd, data, &sc->pps[subdev])); } static device_method_t pps_methods[] = { |