1098ca2bdSWarner Losh /*- 264de3fddSPedro F. Giffuni * SPDX-License-Identifier: Beerware 364de3fddSPedro F. Giffuni * 4507e2e44SPoul-Henning Kamp * ---------------------------------------------------------------------------- 5507e2e44SPoul-Henning Kamp * "THE BEER-WARE LICENSE" (Revision 42): 6507e2e44SPoul-Henning Kamp * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you 7507e2e44SPoul-Henning Kamp * can do whatever you want with this stuff. If we meet some day, and you think 8507e2e44SPoul-Henning Kamp * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 9507e2e44SPoul-Henning Kamp * ---------------------------------------------------------------------------- 10507e2e44SPoul-Henning Kamp * 11389825d5SPoul-Henning Kamp * 12389825d5SPoul-Henning Kamp * This driver implements a draft-mogul-pps-api-02.txt PPS source. 13389825d5SPoul-Henning Kamp * 14389825d5SPoul-Henning Kamp * The input pin is pin#10 15389825d5SPoul-Henning Kamp * The echo output pin is pin#14 16507e2e44SPoul-Henning Kamp * 17507e2e44SPoul-Henning Kamp */ 18507e2e44SPoul-Henning Kamp 19507e2e44SPoul-Henning Kamp #include <sys/param.h> 202067d312SJohn Baldwin #include <sys/lock.h> 21507e2e44SPoul-Henning Kamp #include <sys/kernel.h> 22507e2e44SPoul-Henning Kamp #include <sys/systm.h> 230f210c92SNicolas Souchu #include <sys/module.h> 242067d312SJohn Baldwin #include <sys/sx.h> 250f210c92SNicolas Souchu #include <sys/bus.h> 26507e2e44SPoul-Henning Kamp #include <sys/conf.h> 278afeddf0SPoul-Henning Kamp #include <sys/timepps.h> 280f210c92SNicolas Souchu #include <machine/bus.h> 290f210c92SNicolas Souchu #include <machine/resource.h> 300f210c92SNicolas Souchu #include <sys/rman.h> 31507e2e44SPoul-Henning Kamp 32507e2e44SPoul-Henning Kamp #include <dev/ppbus/ppbconf.h> 330f210c92SNicolas Souchu #include "ppbus_if.h" 340f210c92SNicolas Souchu #include <dev/ppbus/ppbio.h> 35507e2e44SPoul-Henning Kamp 361a03ce6cSPoul-Henning Kamp #define PPS_NAME "pps" /* our official name */ 37507e2e44SPoul-Henning Kamp 38daefef7cSPeter Wemm #define PRVERBOSE(fmt, arg...) if (bootverbose) printf(fmt, ##arg); 39d7e53105SWarner Losh 401a03ce6cSPoul-Henning Kamp struct pps_data { 4195f0f58cSPoul-Henning Kamp struct ppb_device pps_dev; 42bd61b8e8SPoul-Henning Kamp struct pps_state pps[9]; 4389c9c53dSPoul-Henning Kamp struct cdev *devs[9]; 44bd61b8e8SPoul-Henning Kamp device_t ppsdev; 45bd61b8e8SPoul-Henning Kamp device_t ppbus; 46bd61b8e8SPoul-Henning Kamp int busy; 472067d312SJohn Baldwin struct callout timeout; 48bd61b8e8SPoul-Henning Kamp int lastdata; 490f210c92SNicolas Souchu 502067d312SJohn Baldwin struct sx lock; 510f210c92SNicolas Souchu struct resource *intr_resource; /* interrupt resource */ 520f210c92SNicolas Souchu void *intr_cookie; /* interrupt registration cookie */ 531a03ce6cSPoul-Henning Kamp }; 54507e2e44SPoul-Henning Kamp 552067d312SJohn Baldwin static void ppsintr(void *arg); 56bd61b8e8SPoul-Henning Kamp static void ppshcpoll(void *arg); 57507e2e44SPoul-Henning Kamp 580f210c92SNicolas Souchu #define DEVTOSOFTC(dev) \ 590f210c92SNicolas Souchu ((struct pps_data *)device_get_softc(dev)) 60507e2e44SPoul-Henning Kamp 6195f0f58cSPoul-Henning Kamp static d_open_t ppsopen; 6295f0f58cSPoul-Henning Kamp static d_close_t ppsclose; 638afeddf0SPoul-Henning Kamp static d_ioctl_t ppsioctl; 64507e2e44SPoul-Henning Kamp 654e2f199eSPoul-Henning Kamp static struct cdevsw pps_cdevsw = { 66dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 677ac40f5fSPoul-Henning Kamp .d_open = ppsopen, 687ac40f5fSPoul-Henning Kamp .d_close = ppsclose, 697ac40f5fSPoul-Henning Kamp .d_ioctl = ppsioctl, 707ac40f5fSPoul-Henning Kamp .d_name = PPS_NAME, 714e2f199eSPoul-Henning Kamp }; 72507e2e44SPoul-Henning Kamp 730f063508SPeter Wemm static void 740f063508SPeter Wemm ppsidentify(driver_t *driver, device_t parent) 750f063508SPeter Wemm { 760f063508SPeter Wemm 77a5c7e3bbSGuido van Rooij device_t dev; 78a5c7e3bbSGuido van Rooij 79ae6b868aSJohn Baldwin dev = device_find_child(parent, PPS_NAME, -1); 80a5c7e3bbSGuido van Rooij if (!dev) 81*a05a6804SWarner Losh BUS_ADD_CHILD(parent, 0, PPS_NAME, DEVICE_UNIT_ANY); 820f063508SPeter Wemm } 830f063508SPeter Wemm 840f210c92SNicolas Souchu static int 85bd61b8e8SPoul-Henning Kamp ppstry(device_t ppbus, int send, int expect) 86bd61b8e8SPoul-Henning Kamp { 87bd61b8e8SPoul-Henning Kamp int i; 88bd61b8e8SPoul-Henning Kamp 89bd61b8e8SPoul-Henning Kamp ppb_wdtr(ppbus, send); 90bd61b8e8SPoul-Henning Kamp i = ppb_rdtr(ppbus); 91d7e53105SWarner Losh PRVERBOSE("S: %02x E: %02x G: %02x\n", send, expect, i); 92bd61b8e8SPoul-Henning Kamp return (i != expect); 93bd61b8e8SPoul-Henning Kamp } 94bd61b8e8SPoul-Henning Kamp 95bd61b8e8SPoul-Henning Kamp static int 960f210c92SNicolas Souchu ppsprobe(device_t ppsdev) 97507e2e44SPoul-Henning Kamp { 980f210c92SNicolas Souchu device_set_desc(ppsdev, "Pulse per second Timing Interface"); 99507e2e44SPoul-Henning Kamp 100d7e53105SWarner Losh return (0); 101d7e53105SWarner Losh } 102d7e53105SWarner Losh 103d7e53105SWarner Losh static int 104d7e53105SWarner Losh ppsattach(device_t dev) 105d7e53105SWarner Losh { 106d7e53105SWarner Losh struct pps_data *sc = DEVTOSOFTC(dev); 107d7e53105SWarner Losh device_t ppbus = device_get_parent(dev); 10889c9c53dSPoul-Henning Kamp struct cdev *d; 1092067d312SJohn Baldwin int error, i, unit, rid = 0; 110d7e53105SWarner Losh 111d7e53105SWarner Losh /* declare our interrupt handler */ 112ca3d3795SJohn Baldwin sc->intr_resource = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 113ca3d3795SJohn Baldwin RF_SHAREABLE); 114ca3d3795SJohn Baldwin 115d7e53105SWarner Losh /* interrupts seem mandatory */ 1162067d312SJohn Baldwin if (sc->intr_resource == NULL) { 1172067d312SJohn Baldwin device_printf(dev, "Unable to allocate interrupt resource\n"); 118d7e53105SWarner Losh return (ENXIO); 1192067d312SJohn Baldwin } 120d7e53105SWarner Losh 1212067d312SJohn Baldwin error = bus_setup_intr(dev, sc->intr_resource, 1222067d312SJohn Baldwin INTR_TYPE_TTY | INTR_MPSAFE, NULL, ppsintr, 1232067d312SJohn Baldwin sc, &sc->intr_cookie); 1242067d312SJohn Baldwin if (error) { 1252067d312SJohn Baldwin bus_release_resource(dev, SYS_RES_IRQ, 0, sc->intr_resource); 1262067d312SJohn Baldwin device_printf(dev, "Unable to register interrupt handler\n"); 1272067d312SJohn Baldwin return (error); 1282067d312SJohn Baldwin } 1292067d312SJohn Baldwin 1302067d312SJohn Baldwin sx_init(&sc->lock, "pps"); 1312067d312SJohn Baldwin ppb_init_callout(ppbus, &sc->timeout, 0); 132d7e53105SWarner Losh sc->ppsdev = dev; 133d7e53105SWarner Losh sc->ppbus = ppbus; 134bd61b8e8SPoul-Henning Kamp unit = device_get_unit(ppbus); 135d7e53105SWarner Losh d = make_dev(&pps_cdevsw, unit, 1362066d8e7SRobert Watson UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", unit); 137d7e53105SWarner Losh sc->devs[0] = d; 138bd61b8e8SPoul-Henning Kamp sc->pps[0].ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; 139c62aa65bSWarner Losh sc->pps[0].driver_abi = PPS_ABI_VERSION; 140c62aa65bSWarner Losh sc->pps[0].driver_mtx = ppb_get_lock(ppbus); 141d7e53105SWarner Losh d->si_drv1 = sc; 142d7e53105SWarner Losh d->si_drv2 = (void*)0; 143c62aa65bSWarner Losh pps_init_abi(&sc->pps[0]); 144bd61b8e8SPoul-Henning Kamp 1452067d312SJohn Baldwin ppb_lock(ppbus); 1462067d312SJohn Baldwin if (ppb_request_bus(ppbus, dev, PPB_DONTWAIT)) { 1472067d312SJohn Baldwin ppb_unlock(ppbus); 148bd61b8e8SPoul-Henning Kamp return (0); 1492067d312SJohn Baldwin } 150bd61b8e8SPoul-Henning Kamp 151bd61b8e8SPoul-Henning Kamp do { 152bd61b8e8SPoul-Henning Kamp i = ppb_set_mode(sc->ppbus, PPB_EPP); 153d7e53105SWarner Losh PRVERBOSE("EPP: %d %d\n", i, PPB_IN_EPP_MODE(sc->ppbus)); 154bd61b8e8SPoul-Henning Kamp if (i == -1) 155bd61b8e8SPoul-Henning Kamp break; 156bd61b8e8SPoul-Henning Kamp i = 0; 157bd61b8e8SPoul-Henning Kamp ppb_wctr(ppbus, i); 158bd61b8e8SPoul-Henning Kamp if (ppstry(ppbus, 0x00, 0x00)) 159bd61b8e8SPoul-Henning Kamp break; 160bd61b8e8SPoul-Henning Kamp if (ppstry(ppbus, 0x55, 0x55)) 161bd61b8e8SPoul-Henning Kamp break; 162bd61b8e8SPoul-Henning Kamp if (ppstry(ppbus, 0xaa, 0xaa)) 163bd61b8e8SPoul-Henning Kamp break; 164bd61b8e8SPoul-Henning Kamp if (ppstry(ppbus, 0xff, 0xff)) 165bd61b8e8SPoul-Henning Kamp break; 166bd61b8e8SPoul-Henning Kamp 167bd61b8e8SPoul-Henning Kamp i = IRQENABLE | PCD | STROBE | nINIT | SELECTIN; 168bd61b8e8SPoul-Henning Kamp ppb_wctr(ppbus, i); 169d7e53105SWarner Losh PRVERBOSE("CTR = %02x (%02x)\n", ppb_rctr(ppbus), i); 170bd61b8e8SPoul-Henning Kamp if (ppstry(ppbus, 0x00, 0x00)) 171bd61b8e8SPoul-Henning Kamp break; 172bd61b8e8SPoul-Henning Kamp if (ppstry(ppbus, 0x55, 0x00)) 173bd61b8e8SPoul-Henning Kamp break; 174bd61b8e8SPoul-Henning Kamp if (ppstry(ppbus, 0xaa, 0x00)) 175bd61b8e8SPoul-Henning Kamp break; 176bd61b8e8SPoul-Henning Kamp if (ppstry(ppbus, 0xff, 0x00)) 177bd61b8e8SPoul-Henning Kamp break; 178bd61b8e8SPoul-Henning Kamp 179bd61b8e8SPoul-Henning Kamp i = IRQENABLE | PCD | nINIT | SELECTIN; 180bd61b8e8SPoul-Henning Kamp ppb_wctr(ppbus, i); 181d7e53105SWarner Losh PRVERBOSE("CTR = %02x (%02x)\n", ppb_rctr(ppbus), i); 182bd61b8e8SPoul-Henning Kamp ppstry(ppbus, 0x00, 0xff); 183bd61b8e8SPoul-Henning Kamp ppstry(ppbus, 0x55, 0xff); 184bd61b8e8SPoul-Henning Kamp ppstry(ppbus, 0xaa, 0xff); 185bd61b8e8SPoul-Henning Kamp ppstry(ppbus, 0xff, 0xff); 1862067d312SJohn Baldwin ppb_unlock(ppbus); 187bd61b8e8SPoul-Henning Kamp 188bd61b8e8SPoul-Henning Kamp for (i = 1; i < 9; i++) { 189d7e53105SWarner Losh d = make_dev(&pps_cdevsw, unit + 0x10000 * i, 1902066d8e7SRobert Watson UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%db%d", unit, i - 1); 191d7e53105SWarner Losh sc->devs[i] = d; 192bd61b8e8SPoul-Henning Kamp sc->pps[i].ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR; 193c62aa65bSWarner Losh sc->pps[i].driver_abi = PPS_ABI_VERSION; 194c62aa65bSWarner Losh sc->pps[i].driver_mtx = ppb_get_lock(ppbus); 195d7e53105SWarner Losh d->si_drv1 = sc; 196a885bb60SJohn Baldwin d->si_drv2 = (void *)(intptr_t)i; 197c62aa65bSWarner Losh pps_init_abi(&sc->pps[i]); 198bd61b8e8SPoul-Henning Kamp } 1992067d312SJohn Baldwin ppb_lock(ppbus); 200bd61b8e8SPoul-Henning Kamp } while (0); 201bd61b8e8SPoul-Henning Kamp i = ppb_set_mode(sc->ppbus, PPB_COMPATIBLE); 202d7e53105SWarner Losh ppb_release_bus(ppbus, dev); 2032067d312SJohn Baldwin ppb_unlock(ppbus); 2040f210c92SNicolas Souchu 2050f210c92SNicolas Souchu return (0); 206507e2e44SPoul-Henning Kamp } 207507e2e44SPoul-Henning Kamp 208507e2e44SPoul-Henning Kamp static int 20989c9c53dSPoul-Henning Kamp ppsopen(struct cdev *dev, int flags, int fmt, struct thread *td) 210507e2e44SPoul-Henning Kamp { 211bd61b8e8SPoul-Henning Kamp struct pps_data *sc = dev->si_drv1; 2122067d312SJohn Baldwin device_t ppbus = sc->ppbus; 213a885bb60SJohn Baldwin int subdev = (intptr_t)dev->si_drv2; 2142067d312SJohn Baldwin int i; 215507e2e44SPoul-Henning Kamp 2162067d312SJohn Baldwin /* 2172067d312SJohn Baldwin * The sx lock is here solely to serialize open()'s to close 2182067d312SJohn Baldwin * the race of concurrent open()'s when pps(4) doesn't own the 2192067d312SJohn Baldwin * ppbus. 2202067d312SJohn Baldwin */ 2212067d312SJohn Baldwin sx_xlock(&sc->lock); 2222067d312SJohn Baldwin ppb_lock(ppbus); 223bd61b8e8SPoul-Henning Kamp if (!sc->busy) { 224bd61b8e8SPoul-Henning Kamp device_t ppsdev = sc->ppsdev; 225bd61b8e8SPoul-Henning Kamp 2262067d312SJohn Baldwin if (ppb_request_bus(ppbus, ppsdev, PPB_WAIT|PPB_INTR)) { 2272067d312SJohn Baldwin ppb_unlock(ppbus); 2282067d312SJohn Baldwin sx_xunlock(&sc->lock); 229507e2e44SPoul-Henning Kamp return (EINTR); 2300f210c92SNicolas Souchu } 2310f210c92SNicolas Souchu 232bd61b8e8SPoul-Henning Kamp i = ppb_set_mode(sc->ppbus, PPB_PS2); 233d7e53105SWarner Losh PRVERBOSE("EPP: %d %d\n", i, PPB_IN_EPP_MODE(sc->ppbus)); 234507e2e44SPoul-Henning Kamp 235bd61b8e8SPoul-Henning Kamp i = IRQENABLE | PCD | nINIT | SELECTIN; 236bd61b8e8SPoul-Henning Kamp ppb_wctr(ppbus, i); 237bd61b8e8SPoul-Henning Kamp } 238bd61b8e8SPoul-Henning Kamp if (subdev > 0 && !(sc->busy & ~1)) { 2392067d312SJohn Baldwin /* XXX: Timeout of 1? hz/100 instead perhaps? */ 2402067d312SJohn Baldwin callout_reset(&sc->timeout, 1, ppshcpoll, sc); 241bd61b8e8SPoul-Henning Kamp sc->lastdata = ppb_rdtr(sc->ppbus); 242bd61b8e8SPoul-Henning Kamp } 243bd61b8e8SPoul-Henning Kamp sc->busy |= (1 << subdev); 2442067d312SJohn Baldwin ppb_unlock(ppbus); 2452067d312SJohn Baldwin sx_xunlock(&sc->lock); 246507e2e44SPoul-Henning Kamp return(0); 247507e2e44SPoul-Henning Kamp } 248507e2e44SPoul-Henning Kamp 249507e2e44SPoul-Henning Kamp static int 25089c9c53dSPoul-Henning Kamp ppsclose(struct cdev *dev, int flags, int fmt, struct thread *td) 251507e2e44SPoul-Henning Kamp { 252bd61b8e8SPoul-Henning Kamp struct pps_data *sc = dev->si_drv1; 253a885bb60SJohn Baldwin int subdev = (intptr_t)dev->si_drv2; 254507e2e44SPoul-Henning Kamp 2552067d312SJohn Baldwin sx_xlock(&sc->lock); 256bd61b8e8SPoul-Henning Kamp sc->pps[subdev].ppsparam.mode = 0; /* PHK ??? */ 2572067d312SJohn Baldwin ppb_lock(sc->ppbus); 258bd61b8e8SPoul-Henning Kamp sc->busy &= ~(1 << subdev); 259bd61b8e8SPoul-Henning Kamp if (subdev > 0 && !(sc->busy & ~1)) 2602067d312SJohn Baldwin callout_stop(&sc->timeout); 261bd61b8e8SPoul-Henning Kamp if (!sc->busy) { 262bd61b8e8SPoul-Henning Kamp device_t ppsdev = sc->ppsdev; 263bd61b8e8SPoul-Henning Kamp device_t ppbus = sc->ppbus; 26420240fa3SNicolas Souchu 2650f210c92SNicolas Souchu ppb_wdtr(ppbus, 0); 2660f210c92SNicolas Souchu ppb_wctr(ppbus, 0); 26720240fa3SNicolas Souchu 268bd61b8e8SPoul-Henning Kamp ppb_set_mode(ppbus, PPB_COMPATIBLE); 2690f210c92SNicolas Souchu ppb_release_bus(ppbus, ppsdev); 270bd61b8e8SPoul-Henning Kamp } 2712067d312SJohn Baldwin ppb_unlock(sc->ppbus); 2722067d312SJohn Baldwin sx_xunlock(&sc->lock); 273507e2e44SPoul-Henning Kamp return(0); 274507e2e44SPoul-Henning Kamp } 275507e2e44SPoul-Henning Kamp 276507e2e44SPoul-Henning Kamp static void 277bd61b8e8SPoul-Henning Kamp ppshcpoll(void *arg) 278bd61b8e8SPoul-Henning Kamp { 279bd61b8e8SPoul-Henning Kamp struct pps_data *sc = arg; 280bd61b8e8SPoul-Henning Kamp int i, j, k, l; 281bd61b8e8SPoul-Henning Kamp 2822067d312SJohn Baldwin KASSERT(sc->busy & ~1, ("pps polling w/o opened devices")); 283bd61b8e8SPoul-Henning Kamp i = ppb_rdtr(sc->ppbus); 284bd61b8e8SPoul-Henning Kamp if (i == sc->lastdata) 285bd61b8e8SPoul-Henning Kamp return; 286bd61b8e8SPoul-Henning Kamp l = sc->lastdata ^ i; 287bd61b8e8SPoul-Henning Kamp k = 1; 288bd61b8e8SPoul-Henning Kamp for (j = 1; j < 9; j ++) { 2897bf758bfSPoul-Henning Kamp if (l & k) { 2907bf758bfSPoul-Henning Kamp pps_capture(&sc->pps[j]); 2917bf758bfSPoul-Henning Kamp pps_event(&sc->pps[j], 2927bf758bfSPoul-Henning Kamp i & k ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR); 2937bf758bfSPoul-Henning Kamp } 294bd61b8e8SPoul-Henning Kamp k += k; 295bd61b8e8SPoul-Henning Kamp } 296bd61b8e8SPoul-Henning Kamp sc->lastdata = i; 2972067d312SJohn Baldwin callout_reset(&sc->timeout, 1, ppshcpoll, sc); 298bd61b8e8SPoul-Henning Kamp } 299bd61b8e8SPoul-Henning Kamp 3002067d312SJohn Baldwin static void 3010f210c92SNicolas Souchu ppsintr(void *arg) 302507e2e44SPoul-Henning Kamp { 3033aabc159SWarner Losh struct pps_data *sc = (struct pps_data *)arg; 304507e2e44SPoul-Henning Kamp 3052067d312SJohn Baldwin ppb_assert_locked(sc->ppbus); 3067bf758bfSPoul-Henning Kamp pps_capture(&sc->pps[0]); 3073aabc159SWarner Losh if (!(ppb_rstr(sc->ppbus) & nACK)) 3082067d312SJohn Baldwin return; 3092067d312SJohn Baldwin 310bd61b8e8SPoul-Henning Kamp if (sc->pps[0].ppsparam.mode & PPS_ECHOASSERT) 3113aabc159SWarner Losh ppb_wctr(sc->ppbus, IRQENABLE | AUTOFEED); 3127bf758bfSPoul-Henning Kamp pps_event(&sc->pps[0], PPS_CAPTUREASSERT); 3133aabc159SWarner Losh if (sc->pps[0].ppsparam.mode & PPS_ECHOASSERT) 3143aabc159SWarner Losh ppb_wctr(sc->ppbus, IRQENABLE); 315507e2e44SPoul-Henning Kamp } 316507e2e44SPoul-Henning Kamp 317507e2e44SPoul-Henning Kamp static int 31889c9c53dSPoul-Henning Kamp ppsioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) 319507e2e44SPoul-Henning Kamp { 320bd61b8e8SPoul-Henning Kamp struct pps_data *sc = dev->si_drv1; 321a885bb60SJohn Baldwin int subdev = (intptr_t)dev->si_drv2; 32276061701SWarner Losh int err; 323507e2e44SPoul-Henning Kamp 3242067d312SJohn Baldwin ppb_lock(sc->ppbus); 32576061701SWarner Losh err = pps_ioctl(cmd, data, &sc->pps[subdev]); 3262067d312SJohn Baldwin ppb_unlock(sc->ppbus); 32776061701SWarner Losh return (err); 3288afeddf0SPoul-Henning Kamp } 329507e2e44SPoul-Henning Kamp 3300f063508SPeter Wemm static device_method_t pps_methods[] = { 3310f063508SPeter Wemm /* device interface */ 3320f063508SPeter Wemm DEVMETHOD(device_identify, ppsidentify), 3330f063508SPeter Wemm DEVMETHOD(device_probe, ppsprobe), 3340f063508SPeter Wemm DEVMETHOD(device_attach, ppsattach), 3350f063508SPeter Wemm { 0, 0 } 3360f063508SPeter Wemm }; 3370f063508SPeter Wemm 3380f063508SPeter Wemm static driver_t pps_driver = { 3390f063508SPeter Wemm PPS_NAME, 3400f063508SPeter Wemm pps_methods, 3410f063508SPeter Wemm sizeof(struct pps_data), 3420f063508SPeter Wemm }; 3436d588090SJohn Baldwin 3446d588090SJohn Baldwin DRIVER_MODULE(pps, ppbus, pps_driver, 0, 0); 345f5fd5611SRuslan Ermilov MODULE_DEPEND(pps, ppbus, 1, 1, 1); 346