summaryrefslogtreecommitdiffstats
path: root/sys/dev/ppbus
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2001-09-22 16:34:59 +0000
committerphk <phk@FreeBSD.org>2001-09-22 16:34:59 +0000
commit505b425ab926e05e0da7c15cbf439a087551732f (patch)
treeade25dcf444668903d2333eea6ad4c7413448d01 /sys/dev/ppbus
parentd83406693a6fa64bd70b2c2279c0f51a2309ca61 (diff)
downloadFreeBSD-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/dev/ppbus')
-rw-r--r--sys/dev/ppbus/pps.c197
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[] = {
OpenPOWER on IntegriCloud