mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-28 16:43:09 +00:00
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:
parent
940205d5e8
commit
bd61b8e81d
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=83818
@ -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[] = {
|
||||
|
Loading…
Reference in New Issue
Block a user