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.
This commit is contained in:
Poul-Henning Kamp 2001-09-22 16:34:59 +00:00
parent 940205d5e8
commit bd61b8e81d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=83818

View File

@ -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;
@ -81,24 +83,92 @@ ppsidentify(driver_t *driver, device_t parent)
BUS_ADD_CHILD(parent, 0, PPS_NAME, 0);
}
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;
sc = DEVTOSOFTC(ppsdev);
bzero(sc, sizeof(struct pps_data));
unit = device_get_unit(ppsdev);
dev = make_dev(&pps_cdevsw, unit,
UID_ROOT, GID_WHEEL, 0644, PPS_NAME "%d", unit);
device_t ppbus;
int unit, i;
device_set_desc(ppsdev, "Pulse per second Timing Interface");
sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT;
pps_init(&sc->pps);
sc = DEVTOSOFTC(ppsdev);
bzero(sc, sizeof(struct pps_data));
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);
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.ppsparam.mode = 0; /* PHK ??? */
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);
ppb_wdtr(ppbus, 0);
ppb_wctr(ppbus, 0);
/* Note: the interrupt handler is automatically detached */
ppb_release_bus(ppbus, ppsdev);
sc->pps_open = 0;
/* Note: the interrupt handler is automatically detached */
ppb_set_mode(ppbus, PPB_COMPATIBLE);
ppb_release_bus(ppbus, ppsdev);
}
return(0);
}
static void
ppshcpoll(void *arg)
{
struct pps_data *sc = arg;
int i, j, k, l;
struct timecounter *tc;
unsigned count;
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[] = {