xref: /freebsd/sys/dev/ppbus/pps.c (revision a05a680469a7ac77b195021fed74e3aa58152dd7)
1 /*-
2  * SPDX-License-Identifier: Beerware
3  *
4  * ----------------------------------------------------------------------------
5  * "THE BEER-WARE LICENSE" (Revision 42):
6  * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
7  * can do whatever you want with this stuff. If we meet some day, and you think
8  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
9  * ----------------------------------------------------------------------------
10  *
11  *
12  * This driver implements a draft-mogul-pps-api-02.txt PPS source.
13  *
14  * The input pin is pin#10
15  * The echo output pin is pin#14
16  *
17  */
18 
19 #include <sys/param.h>
20 #include <sys/lock.h>
21 #include <sys/kernel.h>
22 #include <sys/systm.h>
23 #include <sys/module.h>
24 #include <sys/sx.h>
25 #include <sys/bus.h>
26 #include <sys/conf.h>
27 #include <sys/timepps.h>
28 #include <machine/bus.h>
29 #include <machine/resource.h>
30 #include <sys/rman.h>
31 
32 #include <dev/ppbus/ppbconf.h>
33 #include "ppbus_if.h"
34 #include <dev/ppbus/ppbio.h>
35 
36 #define PPS_NAME	"pps"		/* our official name */
37 
38 #define PRVERBOSE(fmt, arg...)	if (bootverbose) printf(fmt, ##arg);
39 
40 struct pps_data {
41 	struct	ppb_device pps_dev;
42 	struct	pps_state pps[9];
43 	struct cdev *devs[9];
44 	device_t ppsdev;
45 	device_t ppbus;
46 	int	busy;
47 	struct callout timeout;
48 	int	lastdata;
49 
50 	struct sx lock;
51 	struct resource *intr_resource;	/* interrupt resource */
52 	void *intr_cookie;		/* interrupt registration cookie */
53 };
54 
55 static void	ppsintr(void *arg);
56 static void 	ppshcpoll(void *arg);
57 
58 #define DEVTOSOFTC(dev) \
59 	((struct pps_data *)device_get_softc(dev))
60 
61 static	d_open_t	ppsopen;
62 static	d_close_t	ppsclose;
63 static	d_ioctl_t	ppsioctl;
64 
65 static struct cdevsw pps_cdevsw = {
66 	.d_version =	D_VERSION,
67 	.d_open =	ppsopen,
68 	.d_close =	ppsclose,
69 	.d_ioctl =	ppsioctl,
70 	.d_name =	PPS_NAME,
71 };
72 
73 static void
74 ppsidentify(driver_t *driver, device_t parent)
75 {
76 
77 	device_t dev;
78 
79 	dev = device_find_child(parent, PPS_NAME, -1);
80 	if (!dev)
81 		BUS_ADD_CHILD(parent, 0, PPS_NAME, DEVICE_UNIT_ANY);
82 }
83 
84 static int
85 ppstry(device_t ppbus, int send, int expect)
86 {
87 	int i;
88 
89 	ppb_wdtr(ppbus, send);
90 	i = ppb_rdtr(ppbus);
91 	PRVERBOSE("S: %02x E: %02x G: %02x\n", send, expect, i);
92 	return (i != expect);
93 }
94 
95 static int
96 ppsprobe(device_t ppsdev)
97 {
98 	device_set_desc(ppsdev, "Pulse per second Timing Interface");
99 
100 	return (0);
101 }
102 
103 static int
104 ppsattach(device_t dev)
105 {
106 	struct pps_data *sc = DEVTOSOFTC(dev);
107 	device_t ppbus = device_get_parent(dev);
108 	struct cdev *d;
109 	int error, i, unit, rid = 0;
110 
111 	/* declare our interrupt handler */
112 	sc->intr_resource = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
113 	    RF_SHAREABLE);
114 
115 	/* interrupts seem mandatory */
116 	if (sc->intr_resource == NULL) {
117 		device_printf(dev, "Unable to allocate interrupt resource\n");
118 		return (ENXIO);
119 	}
120 
121 	error = bus_setup_intr(dev, sc->intr_resource,
122 	    INTR_TYPE_TTY | INTR_MPSAFE, NULL, ppsintr,
123 	    sc, &sc->intr_cookie);
124 	if (error) {
125 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->intr_resource);
126 		device_printf(dev, "Unable to register interrupt handler\n");
127 		return (error);
128 	}
129 
130 	sx_init(&sc->lock, "pps");
131 	ppb_init_callout(ppbus, &sc->timeout, 0);
132 	sc->ppsdev = dev;
133 	sc->ppbus = ppbus;
134 	unit = device_get_unit(ppbus);
135 	d = make_dev(&pps_cdevsw, unit,
136 	    UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", unit);
137 	sc->devs[0] = d;
138 	sc->pps[0].ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT;
139 	sc->pps[0].driver_abi = PPS_ABI_VERSION;
140 	sc->pps[0].driver_mtx = ppb_get_lock(ppbus);
141 	d->si_drv1 = sc;
142 	d->si_drv2 = (void*)0;
143 	pps_init_abi(&sc->pps[0]);
144 
145 	ppb_lock(ppbus);
146 	if (ppb_request_bus(ppbus, dev, PPB_DONTWAIT)) {
147 		ppb_unlock(ppbus);
148 		return (0);
149 	}
150 
151 	do {
152 		i = ppb_set_mode(sc->ppbus, PPB_EPP);
153 		PRVERBOSE("EPP: %d %d\n", i, PPB_IN_EPP_MODE(sc->ppbus));
154 		if (i == -1)
155 			break;
156 		i = 0;
157 		ppb_wctr(ppbus, i);
158 		if (ppstry(ppbus, 0x00, 0x00))
159 			break;
160 		if (ppstry(ppbus, 0x55, 0x55))
161 			break;
162 		if (ppstry(ppbus, 0xaa, 0xaa))
163 			break;
164 		if (ppstry(ppbus, 0xff, 0xff))
165 			break;
166 
167 		i = IRQENABLE | PCD | STROBE | nINIT | SELECTIN;
168 		ppb_wctr(ppbus, i);
169 		PRVERBOSE("CTR = %02x (%02x)\n", ppb_rctr(ppbus), i);
170 		if (ppstry(ppbus, 0x00, 0x00))
171 			break;
172 		if (ppstry(ppbus, 0x55, 0x00))
173 			break;
174 		if (ppstry(ppbus, 0xaa, 0x00))
175 			break;
176 		if (ppstry(ppbus, 0xff, 0x00))
177 			break;
178 
179 		i = IRQENABLE | PCD | nINIT | SELECTIN;
180 		ppb_wctr(ppbus, i);
181 		PRVERBOSE("CTR = %02x (%02x)\n", ppb_rctr(ppbus), i);
182 		ppstry(ppbus, 0x00, 0xff);
183 		ppstry(ppbus, 0x55, 0xff);
184 		ppstry(ppbus, 0xaa, 0xff);
185 		ppstry(ppbus, 0xff, 0xff);
186 		ppb_unlock(ppbus);
187 
188 		for (i = 1; i < 9; i++) {
189 			d = make_dev(&pps_cdevsw, unit + 0x10000 * i,
190 			  UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%db%d", unit, i - 1);
191 			sc->devs[i] = d;
192 			sc->pps[i].ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR;
193 			sc->pps[i].driver_abi = PPS_ABI_VERSION;
194 			sc->pps[i].driver_mtx = ppb_get_lock(ppbus);
195 			d->si_drv1 = sc;
196 			d->si_drv2 = (void *)(intptr_t)i;
197 			pps_init_abi(&sc->pps[i]);
198 		}
199 		ppb_lock(ppbus);
200 	} while (0);
201 	i = ppb_set_mode(sc->ppbus, PPB_COMPATIBLE);
202 	ppb_release_bus(ppbus, dev);
203 	ppb_unlock(ppbus);
204 
205 	return (0);
206 }
207 
208 static	int
209 ppsopen(struct cdev *dev, int flags, int fmt, struct thread *td)
210 {
211 	struct pps_data *sc = dev->si_drv1;
212 	device_t ppbus = sc->ppbus;
213 	int subdev = (intptr_t)dev->si_drv2;
214 	int i;
215 
216 	/*
217 	 * The sx lock is here solely to serialize open()'s to close
218 	 * the race of concurrent open()'s when pps(4) doesn't own the
219 	 * ppbus.
220 	 */
221 	sx_xlock(&sc->lock);
222 	ppb_lock(ppbus);
223 	if (!sc->busy) {
224 		device_t ppsdev = sc->ppsdev;
225 
226 		if (ppb_request_bus(ppbus, ppsdev, PPB_WAIT|PPB_INTR)) {
227 			ppb_unlock(ppbus);
228 			sx_xunlock(&sc->lock);
229 			return (EINTR);
230 		}
231 
232 		i = ppb_set_mode(sc->ppbus, PPB_PS2);
233 		PRVERBOSE("EPP: %d %d\n", i, PPB_IN_EPP_MODE(sc->ppbus));
234 
235 		i = IRQENABLE | PCD | nINIT | SELECTIN;
236 		ppb_wctr(ppbus, i);
237 	}
238 	if (subdev > 0 && !(sc->busy & ~1)) {
239 		/* XXX: Timeout of 1?  hz/100 instead perhaps? */
240 		callout_reset(&sc->timeout, 1, ppshcpoll, sc);
241 		sc->lastdata = ppb_rdtr(sc->ppbus);
242 	}
243 	sc->busy |= (1 << subdev);
244 	ppb_unlock(ppbus);
245 	sx_xunlock(&sc->lock);
246 	return(0);
247 }
248 
249 static	int
250 ppsclose(struct cdev *dev, int flags, int fmt, struct thread *td)
251 {
252 	struct pps_data *sc = dev->si_drv1;
253 	int subdev = (intptr_t)dev->si_drv2;
254 
255 	sx_xlock(&sc->lock);
256 	sc->pps[subdev].ppsparam.mode = 0;	/* PHK ??? */
257 	ppb_lock(sc->ppbus);
258 	sc->busy &= ~(1 << subdev);
259 	if (subdev > 0 && !(sc->busy & ~1))
260 		callout_stop(&sc->timeout);
261 	if (!sc->busy) {
262 		device_t ppsdev = sc->ppsdev;
263 		device_t ppbus = sc->ppbus;
264 
265 		ppb_wdtr(ppbus, 0);
266 		ppb_wctr(ppbus, 0);
267 
268 		ppb_set_mode(ppbus, PPB_COMPATIBLE);
269 		ppb_release_bus(ppbus, ppsdev);
270 	}
271 	ppb_unlock(sc->ppbus);
272 	sx_xunlock(&sc->lock);
273 	return(0);
274 }
275 
276 static void
277 ppshcpoll(void *arg)
278 {
279 	struct pps_data *sc = arg;
280 	int i, j, k, l;
281 
282 	KASSERT(sc->busy & ~1, ("pps polling w/o opened devices"));
283 	i = ppb_rdtr(sc->ppbus);
284 	if (i == sc->lastdata)
285 		return;
286 	l = sc->lastdata ^ i;
287 	k = 1;
288 	for (j = 1; j < 9; j ++) {
289 		if (l & k) {
290 			pps_capture(&sc->pps[j]);
291 			pps_event(&sc->pps[j],
292 			    i & k ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR);
293 		}
294 		k += k;
295 	}
296 	sc->lastdata = i;
297 	callout_reset(&sc->timeout, 1, ppshcpoll, sc);
298 }
299 
300 static void
301 ppsintr(void *arg)
302 {
303 	struct pps_data *sc = (struct pps_data *)arg;
304 
305 	ppb_assert_locked(sc->ppbus);
306 	pps_capture(&sc->pps[0]);
307 	if (!(ppb_rstr(sc->ppbus) & nACK))
308 		return;
309 
310 	if (sc->pps[0].ppsparam.mode & PPS_ECHOASSERT)
311 		ppb_wctr(sc->ppbus, IRQENABLE | AUTOFEED);
312 	pps_event(&sc->pps[0], PPS_CAPTUREASSERT);
313 	if (sc->pps[0].ppsparam.mode & PPS_ECHOASSERT)
314 		ppb_wctr(sc->ppbus, IRQENABLE);
315 }
316 
317 static int
318 ppsioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td)
319 {
320 	struct pps_data *sc = dev->si_drv1;
321 	int subdev = (intptr_t)dev->si_drv2;
322 	int err;
323 
324 	ppb_lock(sc->ppbus);
325 	err = pps_ioctl(cmd, data, &sc->pps[subdev]);
326 	ppb_unlock(sc->ppbus);
327 	return (err);
328 }
329 
330 static device_method_t pps_methods[] = {
331 	/* device interface */
332 	DEVMETHOD(device_identify,	ppsidentify),
333 	DEVMETHOD(device_probe,		ppsprobe),
334 	DEVMETHOD(device_attach,	ppsattach),
335 	{ 0, 0 }
336 };
337 
338 static driver_t pps_driver = {
339 	PPS_NAME,
340 	pps_methods,
341 	sizeof(struct pps_data),
342 };
343 
344 DRIVER_MODULE(pps, ppbus, pps_driver, 0, 0);
345 MODULE_DEPEND(pps, ppbus, 1, 1, 1);
346