xref: /freebsd/sys/dev/ppbus/pps.c (revision c62aa65b2a7a6492e712a69c58a35347aa441a98)
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 
19aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
20aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
21aad970f1SDavid E. O'Brien 
22507e2e44SPoul-Henning Kamp #include <sys/param.h>
232067d312SJohn Baldwin #include <sys/lock.h>
24507e2e44SPoul-Henning Kamp #include <sys/kernel.h>
25507e2e44SPoul-Henning Kamp #include <sys/systm.h>
260f210c92SNicolas Souchu #include <sys/module.h>
272067d312SJohn Baldwin #include <sys/sx.h>
280f210c92SNicolas Souchu #include <sys/bus.h>
29507e2e44SPoul-Henning Kamp #include <sys/conf.h>
308afeddf0SPoul-Henning Kamp #include <sys/timepps.h>
310f210c92SNicolas Souchu #include <machine/bus.h>
320f210c92SNicolas Souchu #include <machine/resource.h>
330f210c92SNicolas Souchu #include <sys/rman.h>
34507e2e44SPoul-Henning Kamp 
35507e2e44SPoul-Henning Kamp #include <dev/ppbus/ppbconf.h>
360f210c92SNicolas Souchu #include "ppbus_if.h"
370f210c92SNicolas Souchu #include <dev/ppbus/ppbio.h>
38507e2e44SPoul-Henning Kamp 
391a03ce6cSPoul-Henning Kamp #define PPS_NAME	"pps"		/* our official name */
40507e2e44SPoul-Henning Kamp 
41daefef7cSPeter Wemm #define PRVERBOSE(fmt, arg...)	if (bootverbose) printf(fmt, ##arg);
42d7e53105SWarner Losh 
431a03ce6cSPoul-Henning Kamp struct pps_data {
4495f0f58cSPoul-Henning Kamp 	struct	ppb_device pps_dev;
45bd61b8e8SPoul-Henning Kamp 	struct	pps_state pps[9];
4689c9c53dSPoul-Henning Kamp 	struct cdev *devs[9];
47bd61b8e8SPoul-Henning Kamp 	device_t ppsdev;
48bd61b8e8SPoul-Henning Kamp 	device_t ppbus;
49bd61b8e8SPoul-Henning Kamp 	int	busy;
502067d312SJohn Baldwin 	struct callout timeout;
51bd61b8e8SPoul-Henning Kamp 	int	lastdata;
520f210c92SNicolas Souchu 
532067d312SJohn Baldwin 	struct sx lock;
540f210c92SNicolas Souchu 	struct resource *intr_resource;	/* interrupt resource */
550f210c92SNicolas Souchu 	void *intr_cookie;		/* interrupt registration cookie */
561a03ce6cSPoul-Henning Kamp };
57507e2e44SPoul-Henning Kamp 
582067d312SJohn Baldwin static void	ppsintr(void *arg);
59bd61b8e8SPoul-Henning Kamp static void 	ppshcpoll(void *arg);
60507e2e44SPoul-Henning Kamp 
610f210c92SNicolas Souchu #define DEVTOSOFTC(dev) \
620f210c92SNicolas Souchu 	((struct pps_data *)device_get_softc(dev))
63507e2e44SPoul-Henning Kamp 
640f210c92SNicolas Souchu static devclass_t pps_devclass;
65507e2e44SPoul-Henning Kamp 
6695f0f58cSPoul-Henning Kamp static	d_open_t	ppsopen;
6795f0f58cSPoul-Henning Kamp static	d_close_t	ppsclose;
688afeddf0SPoul-Henning Kamp static	d_ioctl_t	ppsioctl;
69507e2e44SPoul-Henning Kamp 
704e2f199eSPoul-Henning Kamp static struct cdevsw pps_cdevsw = {
71dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
727ac40f5fSPoul-Henning Kamp 	.d_open =	ppsopen,
737ac40f5fSPoul-Henning Kamp 	.d_close =	ppsclose,
747ac40f5fSPoul-Henning Kamp 	.d_ioctl =	ppsioctl,
757ac40f5fSPoul-Henning Kamp 	.d_name =	PPS_NAME,
764e2f199eSPoul-Henning Kamp };
77507e2e44SPoul-Henning Kamp 
780f063508SPeter Wemm static void
790f063508SPeter Wemm ppsidentify(driver_t *driver, device_t parent)
800f063508SPeter Wemm {
810f063508SPeter Wemm 
82a5c7e3bbSGuido van Rooij 	device_t dev;
83a5c7e3bbSGuido van Rooij 
84ae6b868aSJohn Baldwin 	dev = device_find_child(parent, PPS_NAME, -1);
85a5c7e3bbSGuido van Rooij 	if (!dev)
86338cad62SBernd Walter 		BUS_ADD_CHILD(parent, 0, PPS_NAME, -1);
870f063508SPeter Wemm }
880f063508SPeter Wemm 
890f210c92SNicolas Souchu static int
90bd61b8e8SPoul-Henning Kamp ppstry(device_t ppbus, int send, int expect)
91bd61b8e8SPoul-Henning Kamp {
92bd61b8e8SPoul-Henning Kamp 	int i;
93bd61b8e8SPoul-Henning Kamp 
94bd61b8e8SPoul-Henning Kamp 	ppb_wdtr(ppbus, send);
95bd61b8e8SPoul-Henning Kamp 	i = ppb_rdtr(ppbus);
96d7e53105SWarner Losh 	PRVERBOSE("S: %02x E: %02x G: %02x\n", send, expect, i);
97bd61b8e8SPoul-Henning Kamp 	return (i != expect);
98bd61b8e8SPoul-Henning Kamp }
99bd61b8e8SPoul-Henning Kamp 
100bd61b8e8SPoul-Henning Kamp static int
1010f210c92SNicolas Souchu ppsprobe(device_t ppsdev)
102507e2e44SPoul-Henning Kamp {
1030f210c92SNicolas Souchu 	device_set_desc(ppsdev, "Pulse per second Timing Interface");
104507e2e44SPoul-Henning Kamp 
105d7e53105SWarner Losh 	return (0);
106d7e53105SWarner Losh }
107d7e53105SWarner Losh 
108d7e53105SWarner Losh static int
109d7e53105SWarner Losh ppsattach(device_t dev)
110d7e53105SWarner Losh {
111d7e53105SWarner Losh 	struct pps_data *sc = DEVTOSOFTC(dev);
112d7e53105SWarner Losh 	device_t ppbus = device_get_parent(dev);
11389c9c53dSPoul-Henning Kamp 	struct cdev *d;
1142067d312SJohn Baldwin 	int error, i, unit, rid = 0;
115d7e53105SWarner Losh 
116d7e53105SWarner Losh 	/* declare our interrupt handler */
117ca3d3795SJohn Baldwin 	sc->intr_resource = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
118ca3d3795SJohn Baldwin 	    RF_SHAREABLE);
119ca3d3795SJohn Baldwin 
120d7e53105SWarner Losh 	/* interrupts seem mandatory */
1212067d312SJohn Baldwin 	if (sc->intr_resource == NULL) {
1222067d312SJohn Baldwin 		device_printf(dev, "Unable to allocate interrupt resource\n");
123d7e53105SWarner Losh 		return (ENXIO);
1242067d312SJohn Baldwin 	}
125d7e53105SWarner Losh 
1262067d312SJohn Baldwin 	error = bus_setup_intr(dev, sc->intr_resource,
1272067d312SJohn Baldwin 	    INTR_TYPE_TTY | INTR_MPSAFE, NULL, ppsintr,
1282067d312SJohn Baldwin 	    sc, &sc->intr_cookie);
1292067d312SJohn Baldwin 	if (error) {
1302067d312SJohn Baldwin 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->intr_resource);
1312067d312SJohn Baldwin 		device_printf(dev, "Unable to register interrupt handler\n");
1322067d312SJohn Baldwin 		return (error);
1332067d312SJohn Baldwin 	}
1342067d312SJohn Baldwin 
1352067d312SJohn Baldwin 	sx_init(&sc->lock, "pps");
1362067d312SJohn Baldwin 	ppb_init_callout(ppbus, &sc->timeout, 0);
137d7e53105SWarner Losh 	sc->ppsdev = dev;
138d7e53105SWarner Losh 	sc->ppbus = ppbus;
139bd61b8e8SPoul-Henning Kamp 	unit = device_get_unit(ppbus);
140d7e53105SWarner Losh 	d = make_dev(&pps_cdevsw, unit,
1412066d8e7SRobert Watson 	    UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", unit);
142d7e53105SWarner Losh 	sc->devs[0] = d;
143bd61b8e8SPoul-Henning Kamp 	sc->pps[0].ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT;
144*c62aa65bSWarner Losh 	sc->pps[0].driver_abi = PPS_ABI_VERSION;
145*c62aa65bSWarner Losh 	sc->pps[0].driver_mtx = ppb_get_lock(ppbus);
146d7e53105SWarner Losh 	d->si_drv1 = sc;
147d7e53105SWarner Losh 	d->si_drv2 = (void*)0;
148*c62aa65bSWarner Losh 	pps_init_abi(&sc->pps[0]);
149bd61b8e8SPoul-Henning Kamp 
1502067d312SJohn Baldwin 	ppb_lock(ppbus);
1512067d312SJohn Baldwin 	if (ppb_request_bus(ppbus, dev, PPB_DONTWAIT)) {
1522067d312SJohn Baldwin 		ppb_unlock(ppbus);
153bd61b8e8SPoul-Henning Kamp 		return (0);
1542067d312SJohn Baldwin 	}
155bd61b8e8SPoul-Henning Kamp 
156bd61b8e8SPoul-Henning Kamp 	do {
157bd61b8e8SPoul-Henning Kamp 		i = ppb_set_mode(sc->ppbus, PPB_EPP);
158d7e53105SWarner Losh 		PRVERBOSE("EPP: %d %d\n", i, PPB_IN_EPP_MODE(sc->ppbus));
159bd61b8e8SPoul-Henning Kamp 		if (i == -1)
160bd61b8e8SPoul-Henning Kamp 			break;
161bd61b8e8SPoul-Henning Kamp 		i = 0;
162bd61b8e8SPoul-Henning Kamp 		ppb_wctr(ppbus, i);
163bd61b8e8SPoul-Henning Kamp 		if (ppstry(ppbus, 0x00, 0x00))
164bd61b8e8SPoul-Henning Kamp 			break;
165bd61b8e8SPoul-Henning Kamp 		if (ppstry(ppbus, 0x55, 0x55))
166bd61b8e8SPoul-Henning Kamp 			break;
167bd61b8e8SPoul-Henning Kamp 		if (ppstry(ppbus, 0xaa, 0xaa))
168bd61b8e8SPoul-Henning Kamp 			break;
169bd61b8e8SPoul-Henning Kamp 		if (ppstry(ppbus, 0xff, 0xff))
170bd61b8e8SPoul-Henning Kamp 			break;
171bd61b8e8SPoul-Henning Kamp 
172bd61b8e8SPoul-Henning Kamp 		i = IRQENABLE | PCD | STROBE | nINIT | SELECTIN;
173bd61b8e8SPoul-Henning Kamp 		ppb_wctr(ppbus, i);
174d7e53105SWarner Losh 		PRVERBOSE("CTR = %02x (%02x)\n", ppb_rctr(ppbus), i);
175bd61b8e8SPoul-Henning Kamp 		if (ppstry(ppbus, 0x00, 0x00))
176bd61b8e8SPoul-Henning Kamp 			break;
177bd61b8e8SPoul-Henning Kamp 		if (ppstry(ppbus, 0x55, 0x00))
178bd61b8e8SPoul-Henning Kamp 			break;
179bd61b8e8SPoul-Henning Kamp 		if (ppstry(ppbus, 0xaa, 0x00))
180bd61b8e8SPoul-Henning Kamp 			break;
181bd61b8e8SPoul-Henning Kamp 		if (ppstry(ppbus, 0xff, 0x00))
182bd61b8e8SPoul-Henning Kamp 			break;
183bd61b8e8SPoul-Henning Kamp 
184bd61b8e8SPoul-Henning Kamp 		i = IRQENABLE | PCD | nINIT | SELECTIN;
185bd61b8e8SPoul-Henning Kamp 		ppb_wctr(ppbus, i);
186d7e53105SWarner Losh 		PRVERBOSE("CTR = %02x (%02x)\n", ppb_rctr(ppbus), i);
187bd61b8e8SPoul-Henning Kamp 		ppstry(ppbus, 0x00, 0xff);
188bd61b8e8SPoul-Henning Kamp 		ppstry(ppbus, 0x55, 0xff);
189bd61b8e8SPoul-Henning Kamp 		ppstry(ppbus, 0xaa, 0xff);
190bd61b8e8SPoul-Henning Kamp 		ppstry(ppbus, 0xff, 0xff);
1912067d312SJohn Baldwin 		ppb_unlock(ppbus);
192bd61b8e8SPoul-Henning Kamp 
193bd61b8e8SPoul-Henning Kamp 		for (i = 1; i < 9; i++) {
194d7e53105SWarner Losh 			d = make_dev(&pps_cdevsw, unit + 0x10000 * i,
1952066d8e7SRobert Watson 			  UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%db%d", unit, i - 1);
196d7e53105SWarner Losh 			sc->devs[i] = d;
197bd61b8e8SPoul-Henning Kamp 			sc->pps[i].ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR;
198*c62aa65bSWarner Losh 			sc->pps[i].driver_abi = PPS_ABI_VERSION;
199*c62aa65bSWarner Losh 			sc->pps[i].driver_mtx = ppb_get_lock(ppbus);
200d7e53105SWarner Losh 			d->si_drv1 = sc;
201a885bb60SJohn Baldwin 			d->si_drv2 = (void *)(intptr_t)i;
202*c62aa65bSWarner Losh 			pps_init_abi(&sc->pps[i]);
203bd61b8e8SPoul-Henning Kamp 		}
2042067d312SJohn Baldwin 		ppb_lock(ppbus);
205bd61b8e8SPoul-Henning Kamp 	} while (0);
206bd61b8e8SPoul-Henning Kamp 	i = ppb_set_mode(sc->ppbus, PPB_COMPATIBLE);
207d7e53105SWarner Losh 	ppb_release_bus(ppbus, dev);
2082067d312SJohn Baldwin 	ppb_unlock(ppbus);
2090f210c92SNicolas Souchu 
2100f210c92SNicolas Souchu 	return (0);
211507e2e44SPoul-Henning Kamp }
212507e2e44SPoul-Henning Kamp 
213507e2e44SPoul-Henning Kamp static	int
21489c9c53dSPoul-Henning Kamp ppsopen(struct cdev *dev, int flags, int fmt, struct thread *td)
215507e2e44SPoul-Henning Kamp {
216bd61b8e8SPoul-Henning Kamp 	struct pps_data *sc = dev->si_drv1;
2172067d312SJohn Baldwin 	device_t ppbus = sc->ppbus;
218a885bb60SJohn Baldwin 	int subdev = (intptr_t)dev->si_drv2;
2192067d312SJohn Baldwin 	int i;
220507e2e44SPoul-Henning Kamp 
2212067d312SJohn Baldwin 	/*
2222067d312SJohn Baldwin 	 * The sx lock is here solely to serialize open()'s to close
2232067d312SJohn Baldwin 	 * the race of concurrent open()'s when pps(4) doesn't own the
2242067d312SJohn Baldwin 	 * ppbus.
2252067d312SJohn Baldwin 	 */
2262067d312SJohn Baldwin 	sx_xlock(&sc->lock);
2272067d312SJohn Baldwin 	ppb_lock(ppbus);
228bd61b8e8SPoul-Henning Kamp 	if (!sc->busy) {
229bd61b8e8SPoul-Henning Kamp 		device_t ppsdev = sc->ppsdev;
230bd61b8e8SPoul-Henning Kamp 
2312067d312SJohn Baldwin 		if (ppb_request_bus(ppbus, ppsdev, PPB_WAIT|PPB_INTR)) {
2322067d312SJohn Baldwin 			ppb_unlock(ppbus);
2332067d312SJohn Baldwin 			sx_xunlock(&sc->lock);
234507e2e44SPoul-Henning Kamp 			return (EINTR);
2350f210c92SNicolas Souchu 		}
2360f210c92SNicolas Souchu 
237bd61b8e8SPoul-Henning Kamp 		i = ppb_set_mode(sc->ppbus, PPB_PS2);
238d7e53105SWarner Losh 		PRVERBOSE("EPP: %d %d\n", i, PPB_IN_EPP_MODE(sc->ppbus));
239507e2e44SPoul-Henning Kamp 
240bd61b8e8SPoul-Henning Kamp 		i = IRQENABLE | PCD | nINIT | SELECTIN;
241bd61b8e8SPoul-Henning Kamp 		ppb_wctr(ppbus, i);
242bd61b8e8SPoul-Henning Kamp 	}
243bd61b8e8SPoul-Henning Kamp 	if (subdev > 0 && !(sc->busy & ~1)) {
2442067d312SJohn Baldwin 		/* XXX: Timeout of 1?  hz/100 instead perhaps? */
2452067d312SJohn Baldwin 		callout_reset(&sc->timeout, 1, ppshcpoll, sc);
246bd61b8e8SPoul-Henning Kamp 		sc->lastdata = ppb_rdtr(sc->ppbus);
247bd61b8e8SPoul-Henning Kamp 	}
248bd61b8e8SPoul-Henning Kamp 	sc->busy |= (1 << subdev);
2492067d312SJohn Baldwin 	ppb_unlock(ppbus);
2502067d312SJohn Baldwin 	sx_xunlock(&sc->lock);
251507e2e44SPoul-Henning Kamp 	return(0);
252507e2e44SPoul-Henning Kamp }
253507e2e44SPoul-Henning Kamp 
254507e2e44SPoul-Henning Kamp static	int
25589c9c53dSPoul-Henning Kamp ppsclose(struct cdev *dev, int flags, int fmt, struct thread *td)
256507e2e44SPoul-Henning Kamp {
257bd61b8e8SPoul-Henning Kamp 	struct pps_data *sc = dev->si_drv1;
258a885bb60SJohn Baldwin 	int subdev = (intptr_t)dev->si_drv2;
259507e2e44SPoul-Henning Kamp 
2602067d312SJohn Baldwin 	sx_xlock(&sc->lock);
261bd61b8e8SPoul-Henning Kamp 	sc->pps[subdev].ppsparam.mode = 0;	/* PHK ??? */
2622067d312SJohn Baldwin 	ppb_lock(sc->ppbus);
263bd61b8e8SPoul-Henning Kamp 	sc->busy &= ~(1 << subdev);
264bd61b8e8SPoul-Henning Kamp 	if (subdev > 0 && !(sc->busy & ~1))
2652067d312SJohn Baldwin 		callout_stop(&sc->timeout);
266bd61b8e8SPoul-Henning Kamp 	if (!sc->busy) {
267bd61b8e8SPoul-Henning Kamp 		device_t ppsdev = sc->ppsdev;
268bd61b8e8SPoul-Henning Kamp 		device_t ppbus = sc->ppbus;
26920240fa3SNicolas Souchu 
2700f210c92SNicolas Souchu 		ppb_wdtr(ppbus, 0);
2710f210c92SNicolas Souchu 		ppb_wctr(ppbus, 0);
27220240fa3SNicolas Souchu 
273bd61b8e8SPoul-Henning Kamp 		ppb_set_mode(ppbus, PPB_COMPATIBLE);
2740f210c92SNicolas Souchu 		ppb_release_bus(ppbus, ppsdev);
275bd61b8e8SPoul-Henning Kamp 	}
2762067d312SJohn Baldwin 	ppb_unlock(sc->ppbus);
2772067d312SJohn Baldwin 	sx_xunlock(&sc->lock);
278507e2e44SPoul-Henning Kamp 	return(0);
279507e2e44SPoul-Henning Kamp }
280507e2e44SPoul-Henning Kamp 
281507e2e44SPoul-Henning Kamp static void
282bd61b8e8SPoul-Henning Kamp ppshcpoll(void *arg)
283bd61b8e8SPoul-Henning Kamp {
284bd61b8e8SPoul-Henning Kamp 	struct pps_data *sc = arg;
285bd61b8e8SPoul-Henning Kamp 	int i, j, k, l;
286bd61b8e8SPoul-Henning Kamp 
2872067d312SJohn Baldwin 	KASSERT(sc->busy & ~1, ("pps polling w/o opened devices"));
288bd61b8e8SPoul-Henning Kamp 	i = ppb_rdtr(sc->ppbus);
289bd61b8e8SPoul-Henning Kamp 	if (i == sc->lastdata)
290bd61b8e8SPoul-Henning Kamp 		return;
291bd61b8e8SPoul-Henning Kamp 	l = sc->lastdata ^ i;
292bd61b8e8SPoul-Henning Kamp 	k = 1;
293bd61b8e8SPoul-Henning Kamp 	for (j = 1; j < 9; j ++) {
2947bf758bfSPoul-Henning Kamp 		if (l & k) {
2957bf758bfSPoul-Henning Kamp 			pps_capture(&sc->pps[j]);
2967bf758bfSPoul-Henning Kamp 			pps_event(&sc->pps[j],
2977bf758bfSPoul-Henning Kamp 			    i & k ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR);
2987bf758bfSPoul-Henning Kamp 		}
299bd61b8e8SPoul-Henning Kamp 		k += k;
300bd61b8e8SPoul-Henning Kamp 	}
301bd61b8e8SPoul-Henning Kamp 	sc->lastdata = i;
3022067d312SJohn Baldwin 	callout_reset(&sc->timeout, 1, ppshcpoll, sc);
303bd61b8e8SPoul-Henning Kamp }
304bd61b8e8SPoul-Henning Kamp 
3052067d312SJohn Baldwin static void
3060f210c92SNicolas Souchu ppsintr(void *arg)
307507e2e44SPoul-Henning Kamp {
3083aabc159SWarner Losh 	struct pps_data *sc = (struct pps_data *)arg;
309507e2e44SPoul-Henning Kamp 
3102067d312SJohn Baldwin 	ppb_assert_locked(sc->ppbus);
3117bf758bfSPoul-Henning Kamp 	pps_capture(&sc->pps[0]);
3123aabc159SWarner Losh 	if (!(ppb_rstr(sc->ppbus) & nACK))
3132067d312SJohn Baldwin 		return;
3142067d312SJohn Baldwin 
315bd61b8e8SPoul-Henning Kamp 	if (sc->pps[0].ppsparam.mode & PPS_ECHOASSERT)
3163aabc159SWarner Losh 		ppb_wctr(sc->ppbus, IRQENABLE | AUTOFEED);
3177bf758bfSPoul-Henning Kamp 	pps_event(&sc->pps[0], PPS_CAPTUREASSERT);
3183aabc159SWarner Losh 	if (sc->pps[0].ppsparam.mode & PPS_ECHOASSERT)
3193aabc159SWarner Losh 		ppb_wctr(sc->ppbus, IRQENABLE);
320507e2e44SPoul-Henning Kamp }
321507e2e44SPoul-Henning Kamp 
322507e2e44SPoul-Henning Kamp static int
32389c9c53dSPoul-Henning Kamp ppsioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td)
324507e2e44SPoul-Henning Kamp {
325bd61b8e8SPoul-Henning Kamp 	struct pps_data *sc = dev->si_drv1;
326a885bb60SJohn Baldwin 	int subdev = (intptr_t)dev->si_drv2;
32776061701SWarner Losh 	int err;
328507e2e44SPoul-Henning Kamp 
3292067d312SJohn Baldwin 	ppb_lock(sc->ppbus);
33076061701SWarner Losh 	err = pps_ioctl(cmd, data, &sc->pps[subdev]);
3312067d312SJohn Baldwin 	ppb_unlock(sc->ppbus);
33276061701SWarner Losh 	return (err);
3338afeddf0SPoul-Henning Kamp }
334507e2e44SPoul-Henning Kamp 
3350f063508SPeter Wemm static device_method_t pps_methods[] = {
3360f063508SPeter Wemm 	/* device interface */
3370f063508SPeter Wemm 	DEVMETHOD(device_identify,	ppsidentify),
3380f063508SPeter Wemm 	DEVMETHOD(device_probe,		ppsprobe),
3390f063508SPeter Wemm 	DEVMETHOD(device_attach,	ppsattach),
3400f063508SPeter Wemm 	{ 0, 0 }
3410f063508SPeter Wemm };
3420f063508SPeter Wemm 
3430f063508SPeter Wemm static driver_t pps_driver = {
3440f063508SPeter Wemm 	PPS_NAME,
3450f063508SPeter Wemm 	pps_methods,
3460f063508SPeter Wemm 	sizeof(struct pps_data),
3470f063508SPeter Wemm };
3480f210c92SNicolas Souchu DRIVER_MODULE(pps, ppbus, pps_driver, pps_devclass, 0, 0);
349f5fd5611SRuslan Ermilov MODULE_DEPEND(pps, ppbus, 1, 1, 1);
350