xref: /openbsd-src/sys/dev/usb/udcf.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: udcf.c,v 1.58 2014/07/12 20:26:33 mpi Exp $ */
2 
3 /*
4  * Copyright (c) 2006, 2007, 2008 Marc Balmer <mbalmer@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/kernel.h>
22 #include <sys/conf.h>
23 #include <sys/file.h>
24 #include <sys/select.h>
25 #include <sys/device.h>
26 #include <sys/poll.h>
27 #include <sys/time.h>
28 #include <sys/sensors.h>
29 #include <sys/timeout.h>
30 
31 #include <dev/usb/usb.h>
32 #include <dev/usb/usbdi.h>
33 #include <dev/usb/usbdi_util.h>
34 #include <dev/usb/usbdevs.h>
35 
36 #ifdef UDCF_DEBUG
37 #define DPRINTFN(n, x)	do { if (udcfdebug > (n)) printf x; } while (0)
38 int udcfdebug = 0;
39 #else
40 #define DPRINTFN(n, x)
41 #endif
42 #define DPRINTF(x)	DPRINTFN(0, x)
43 
44 #define UDCF_READ_IDX	0x1f
45 
46 #define UDCF_CTRL_IDX	0x33
47 #define UDCF_CTRL_VAL	0x98
48 
49 #define FT232R_RESET	0x00	/* reset USB request */
50 #define FT232R_STATUS	0x05	/* get modem status USB request */
51 #define FT232R_RI	0x40	/* ring indicator */
52 
53 #define DPERIOD1	((long) 5 * 60)		/* degrade OK -> WARN */
54 #define DPERIOD2	((long) 15 * 60)	/* degrade WARN -> CRIT */
55 
56 /* max. skew of received time diff vs. measured time diff in percent. */
57 #define MAX_SKEW	5
58 
59 #define CLOCK_DCF77	0
60 #define CLOCK_HBG	1
61 
62 static const char	*clockname[2] = {
63 	"DCF77",
64 	"HBG" };
65 
66 struct udcf_softc {
67 	struct device		sc_dev;		/* base device */
68 	struct usbd_device	*sc_udev;	/* USB device */
69 	struct usbd_interface	*sc_iface;	/* data interface */
70 
71 	struct timeout		sc_to;
72 	struct usb_task		sc_task;
73 
74 	struct timeout		sc_bv_to;	/* bit-value detect */
75 	struct timeout		sc_db_to;	/* debounce */
76 	struct timeout		sc_mg_to;	/* minute-gap detect */
77 	struct timeout		sc_sl_to;	/* signal-loss detect */
78 	struct timeout		sc_it_to;	/* invalidate time */
79 	struct timeout		sc_ct_to;	/* detect clock type */
80 	struct usb_task		sc_bv_task;
81 	struct usb_task		sc_mg_task;
82 	struct usb_task		sc_sl_task;
83 	struct usb_task		sc_ct_task;
84 
85 	usb_device_request_t	sc_req;
86 
87 	int			sc_detect_ct;	/* != 0: autodetect type */
88 	int			sc_clocktype;	/* DCF77 or HBG */
89 	int			sc_sync;	/* 1 during sync */
90 	u_int64_t		sc_mask;	/* 64 bit mask */
91 	u_int64_t		sc_tbits;	/* Time bits */
92 	int			sc_minute;
93 	int			sc_level;
94 	time_t			sc_last_mg;
95 	int			(*sc_signal)(struct udcf_softc *);
96 
97 	time_t			sc_current;	/* current time */
98 	time_t			sc_next;	/* time to become valid next */
99 	time_t			sc_last;
100 	int			sc_nrecv;	/* consecutive valid times */
101 	struct timeval		sc_last_tv;	/* uptime of last valid time */
102 	struct ksensor		sc_sensor;
103 #ifdef UDCF_DEBUG
104 	struct ksensor		sc_skew;	/* recv vs local skew */
105 #endif
106 	struct ksensordev	sc_sensordev;
107 };
108 
109 /*
110  * timeouts being used in hz:
111  * t_bv		bit value detection (150ms)
112  * t_ct		detect clocktype (250ms)
113  * t_sync	sync (950ms)
114  * t_mg		minute gap detection (1500ms)
115  * t_mgsync	resync after a minute gap (450ms)
116  * t_sl		detect signal loss (3sec)
117  * t_wait	wait (5sec)
118  * t_warn	degrade sensor status to warning (5min)
119  * t_crit	degrade sensor status to critical (15min)
120  */
121 static int t_bv, t_ct, t_sync, t_mg, t_sl, t_mgsync, t_wait, t_warn, t_crit;
122 
123 void	udcf_intr(void *);
124 void	udcf_probe(void *);
125 
126 void	udcf_bv_intr(void *);
127 void	udcf_mg_intr(void *);
128 void	udcf_sl_intr(void *);
129 void	udcf_it_intr(void *);
130 void	udcf_ct_intr(void *);
131 void	udcf_bv_probe(void *);
132 void	udcf_mg_probe(void *);
133 void	udcf_sl_probe(void *);
134 void	udcf_ct_probe(void *);
135 
136 int udcf_match(struct device *, void *, void *);
137 void udcf_attach(struct device *, struct device *, void *);
138 int udcf_detach(struct device *, int);
139 
140 int udcf_nc_signal(struct udcf_softc *);
141 int udcf_nc_init_hw(struct udcf_softc *);
142 int udcf_ft232r_signal(struct udcf_softc *);
143 int udcf_ft232r_init_hw(struct udcf_softc *);
144 
145 struct cfdriver udcf_cd = {
146 	NULL, "udcf", DV_DULL
147 };
148 
149 const struct cfattach udcf_ca = {
150 	sizeof(struct udcf_softc), udcf_match, udcf_attach, udcf_detach,
151 };
152 
153 static const struct usb_devno udcf_devs[] = {
154 	{ USB_VENDOR_GUDE, USB_PRODUCT_GUDE_DCF },
155 	{ USB_VENDOR_FTDI, USB_PRODUCT_FTDI_DCF },
156 	{ USB_VENDOR_FTDI, USB_PRODUCT_FTDI_HBG }
157 };
158 
159 int
160 udcf_match(struct device *parent, void *match, void *aux)
161 {
162 	struct usb_attach_arg		*uaa = aux;
163 
164 	if (uaa->iface != NULL)
165 		return UMATCH_NONE;
166 
167 	return (usb_lookup(udcf_devs, uaa->vendor, uaa->product) != NULL ?
168 	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
169 }
170 
171 void
172 udcf_attach(struct device *parent, struct device *self, void *aux)
173 {
174 	struct udcf_softc		*sc = (struct udcf_softc *)self;
175 	struct usb_attach_arg		*uaa = aux;
176 	struct usbd_device		*dev = uaa->device;
177 	struct usbd_interface		*iface;
178 	struct timeval			 t;
179 	usbd_status			 err;
180 
181 	switch (uaa->product) {
182 	case USB_PRODUCT_GUDE_DCF:
183 		sc->sc_detect_ct = 1;
184 		sc->sc_signal = udcf_nc_signal;
185 		strlcpy(sc->sc_sensor.desc, "Unknown",
186 		    sizeof(sc->sc_sensor.desc));
187 		break;
188 	case USB_PRODUCT_FTDI_DCF:
189 		sc->sc_signal = udcf_ft232r_signal;
190 		strlcpy(sc->sc_sensor.desc, clockname[CLOCK_DCF77],
191 		    sizeof(sc->sc_sensor.desc));
192 		break;
193 	case USB_PRODUCT_FTDI_HBG:
194 		sc->sc_signal = udcf_ft232r_signal;
195 		strlcpy(sc->sc_sensor.desc, clockname[CLOCK_HBG],
196 		    sizeof(sc->sc_sensor.desc));
197 		break;
198 	}
199 
200 	usb_init_task(&sc->sc_task, udcf_probe, sc, USB_TASK_TYPE_GENERIC);
201 	usb_init_task(&sc->sc_bv_task, udcf_bv_probe, sc, USB_TASK_TYPE_GENERIC);
202 	usb_init_task(&sc->sc_mg_task, udcf_mg_probe, sc, USB_TASK_TYPE_GENERIC);
203 	usb_init_task(&sc->sc_sl_task, udcf_sl_probe, sc, USB_TASK_TYPE_GENERIC);
204 
205 	timeout_set(&sc->sc_to, udcf_intr, sc);
206 	timeout_set(&sc->sc_bv_to, udcf_bv_intr, sc);
207 	timeout_set(&sc->sc_mg_to, udcf_mg_intr, sc);
208 	timeout_set(&sc->sc_sl_to, udcf_sl_intr, sc);
209 	timeout_set(&sc->sc_it_to, udcf_it_intr, sc);
210 
211 	if (sc->sc_detect_ct) {
212 		usb_init_task(&sc->sc_ct_task, udcf_ct_probe, sc,
213 		    USB_TASK_TYPE_GENERIC);
214 		timeout_set(&sc->sc_ct_to, udcf_ct_intr, sc);
215 	}
216 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
217 	    sizeof(sc->sc_sensordev.xname));
218 
219 	sc->sc_sensor.type = SENSOR_TIMEDELTA;
220 	sc->sc_sensor.status = SENSOR_S_UNKNOWN;
221 	sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
222 
223 #ifdef UDCF_DEBUG
224 	sc->sc_skew.type = SENSOR_TIMEDELTA;
225 	sc->sc_skew.status = SENSOR_S_UNKNOWN;
226 	strlcpy(sc->sc_skew.desc, "local clock skew",
227 	    sizeof(sc->sc_skew.desc));
228 	sensor_attach(&sc->sc_sensordev, &sc->sc_skew);
229 #endif
230 	sensordev_install(&sc->sc_sensordev);
231 
232 	sc->sc_udev = dev;
233 	if ((err = usbd_set_config_index(dev, 0, 1))) {
234 		DPRINTF(("%s: failed to set configuration, err=%s\n",
235 		    sc->sc_dev.dv_xname, usbd_errstr(err)));
236 		goto fishy;
237 	}
238 
239 	if ((err = usbd_device2interface_handle(dev, 0, &iface))) {
240 		DPRINTF(("%s: failed to get interface, err=%s\n",
241 		    sc->sc_dev.dv_xname, usbd_errstr(err)));
242 		goto fishy;
243 	}
244 
245 	sc->sc_iface = iface;
246 
247 	sc->sc_clocktype = -1;
248 	sc->sc_level = 0;
249 	sc->sc_minute = 0;
250 	sc->sc_last_mg = 0L;
251 
252 	sc->sc_sync = 1;
253 
254 	sc->sc_current = 0L;
255 	sc->sc_next = 0L;
256 	sc->sc_nrecv = 0;
257 	sc->sc_last = 0L;
258 	sc->sc_last_tv.tv_sec = 0L;
259 
260 	switch (uaa->product) {
261 	case USB_PRODUCT_GUDE_DCF:
262 		if (udcf_nc_init_hw(sc))
263 			goto fishy;
264 		break;
265 	case USB_PRODUCT_FTDI_DCF:	/* FALLTHROUGH */
266 	case USB_PRODUCT_FTDI_HBG:
267 		if (udcf_ft232r_init_hw(sc))
268 			goto fishy;
269 		break;
270 	}
271 
272 	/* convert timevals to hz */
273 	t.tv_sec = 0L;
274 	t.tv_usec = 150000L;
275 	t_bv = tvtohz(&t);
276 
277 	t.tv_usec = 450000L;
278 	t_mgsync = tvtohz(&t);
279 
280 	t.tv_usec = 950000L;
281 	t_sync = tvtohz(&t);
282 
283 	t.tv_sec = 1L;
284 	t.tv_usec = 500000L;
285 	t_mg = tvtohz(&t);
286 
287 	t.tv_sec = 3L;
288 	t.tv_usec = 0L;
289 	t_sl = tvtohz(&t);
290 
291 	t.tv_sec = 5L;
292 	t_wait = tvtohz(&t);
293 
294 	t.tv_sec = DPERIOD1;
295 	t_warn = tvtohz(&t);
296 
297 	t.tv_sec = DPERIOD2;
298 	t_crit = tvtohz(&t);
299 
300 	if (sc->sc_detect_ct) {
301 		t.tv_sec = 0L;
302 		t.tv_usec = 250000L;
303 		t_ct = tvtohz(&t);
304 	}
305 
306 	/* Give the receiver some slack to stabilize */
307 	timeout_add(&sc->sc_to, t_wait);
308 
309 	/* Detect signal loss */
310 	timeout_add(&sc->sc_sl_to, t_wait + t_sl);
311 
312 	DPRINTF(("synchronizing\n"));
313 	return;
314 
315 fishy:
316 	DPRINTF(("udcf_attach failed\n"));
317 	usbd_deactivate(sc->sc_udev);
318 }
319 
320 int
321 udcf_detach(struct device *self, int flags)
322 {
323 	struct udcf_softc	*sc = (struct udcf_softc *)self;
324 
325 	if (timeout_initialized(&sc->sc_to))
326 		timeout_del(&sc->sc_to);
327 	if (timeout_initialized(&sc->sc_bv_to))
328 		timeout_del(&sc->sc_bv_to);
329 	if (timeout_initialized(&sc->sc_mg_to))
330 		timeout_del(&sc->sc_mg_to);
331 	if (timeout_initialized(&sc->sc_sl_to))
332 		timeout_del(&sc->sc_sl_to);
333 	if (timeout_initialized(&sc->sc_it_to))
334 		timeout_del(&sc->sc_it_to);
335 	if (sc->sc_detect_ct) {
336 		if (timeout_initialized(&sc->sc_ct_to))
337 			timeout_del(&sc->sc_ct_to);
338 	}
339 
340 	/* Unregister the clock with the kernel */
341 	sensordev_deinstall(&sc->sc_sensordev);
342 	usb_rem_task(sc->sc_udev, &sc->sc_task);
343 	usb_rem_task(sc->sc_udev, &sc->sc_bv_task);
344 	usb_rem_task(sc->sc_udev, &sc->sc_mg_task);
345 	usb_rem_task(sc->sc_udev, &sc->sc_sl_task);
346 	if (sc->sc_detect_ct)
347 		usb_rem_task(sc->sc_udev, &sc->sc_ct_task);
348 
349 	return 0;
350 }
351 
352 /* udcf_intr runs in an interrupt context */
353 void
354 udcf_intr(void *xsc)
355 {
356 	struct udcf_softc *sc = xsc;
357 	usb_add_task(sc->sc_udev, &sc->sc_task);
358 }
359 
360 /* bit value detection */
361 void
362 udcf_bv_intr(void *xsc)
363 {
364 	struct udcf_softc *sc = xsc;
365 	usb_add_task(sc->sc_udev, &sc->sc_bv_task);
366 }
367 
368 /* minute gap detection */
369 void
370 udcf_mg_intr(void *xsc)
371 {
372 	struct udcf_softc *sc = xsc;
373 	usb_add_task(sc->sc_udev, &sc->sc_mg_task);
374 }
375 
376 /* signal loss detection */
377 void
378 udcf_sl_intr(void *xsc)
379 {
380 	struct udcf_softc *sc = xsc;
381 	usb_add_task(sc->sc_udev, &sc->sc_sl_task);
382 }
383 
384 /* detect the clock type (DCF77 or HBG) */
385 void
386 udcf_ct_intr(void *xsc)
387 {
388 	struct udcf_softc *sc = xsc;
389 	usb_add_task(sc->sc_udev, &sc->sc_ct_task);
390 }
391 
392 /*
393  * initialize the Expert mouseCLOCK USB devices, they use a NetCologne
394  * chip to interface the receiver.  Power must be supplied to the
395  * receiver and the receiver must be turned on.
396  */
397 int
398 udcf_nc_init_hw(struct udcf_softc *sc)
399 {
400 	usbd_status			 err;
401 	usb_device_request_t		 req;
402 	uWord				 result;
403 	int				 actlen;
404 
405 	/* Prepare the USB request to probe the value */
406 	sc->sc_req.bmRequestType = UT_READ_VENDOR_DEVICE;
407 	sc->sc_req.bRequest = 1;
408 	USETW(sc->sc_req.wValue, 0);
409 	USETW(sc->sc_req.wIndex, UDCF_READ_IDX);
410 	USETW(sc->sc_req.wLength, 1);
411 
412 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
413 	req.bRequest = 0;
414 	USETW(req.wValue, 0);
415 	USETW(req.wIndex, 0);
416 	USETW(req.wLength, 0);
417 	if ((err = usbd_do_request_flags(sc->sc_udev, &req, &result,
418 	    USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT))) {
419 		DPRINTF(("failed to turn on power for receiver\n"));
420 		return -1;
421 	}
422 
423 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
424 	req.bRequest = 0;
425 	USETW(req.wValue, UDCF_CTRL_VAL);
426 	USETW(req.wIndex, UDCF_CTRL_IDX);
427 	USETW(req.wLength, 0);
428 	if ((err = usbd_do_request_flags(sc->sc_udev, &req, &result,
429 	    USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT))) {
430 		DPRINTF(("failed to turn on receiver\n"));
431 		return -1;
432 	}
433 	return 0;
434 }
435 
436 /*
437  * initialize the Expert mouseCLOCK USB II devices, they use an FTDI
438  * FT232R chip to interface the receiver.  Only reset the chip.
439  */
440 int
441 udcf_ft232r_init_hw(struct udcf_softc *sc)
442 {
443 	usbd_status		err;
444 	usb_device_request_t	req;
445 
446 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
447 	req.bRequest = FT232R_RESET;
448 	/* 0 resets the SIO */
449 	USETW(req.wValue,FT232R_RESET);
450 	USETW(req.wIndex, 0);
451 	USETW(req.wLength, 0);
452 	err = usbd_do_request(sc->sc_udev, &req, NULL);
453 	if (err) {
454 		DPRINTF(("failed to reset ftdi\n"));
455 		return -1;
456 	}
457 	return 0;
458 }
459 
460 /*
461  * return 1 during high-power-, 0 during low-power-emission
462  * If bit 0 is set, the transmitter emits at full power.
463  * During the low-power emission we decode a zero bit.
464  */
465 int
466 udcf_nc_signal(struct udcf_softc *sc)
467 {
468 	int		actlen;
469 	unsigned char	data;
470 
471 	if (usbd_do_request_flags(sc->sc_udev, &sc->sc_req, &data,
472 	    USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT))
473 		/* This happens if we pull the receiver */
474 		return -1;
475 	return data & 0x01;
476 }
477 
478 /* pick up the signal level through the FTDI FT232R chip */
479 int
480 udcf_ft232r_signal(struct udcf_softc *sc)
481 {
482 	usb_device_request_t	req;
483 	int			actlen;
484 	u_int16_t		data;
485 
486 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
487 	req.bRequest = FT232R_STATUS;
488 	USETW(req.wValue, 0);
489 	USETW(req.wIndex, 0);
490 	USETW(req.wLength, 2);
491 	if (usbd_do_request_flags(sc->sc_udev, &req, &data,
492 	    USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT)) {
493 		DPRINTFN(2, ("error reading ftdi modem status\n"));
494 		return -1;
495 	}
496 	DPRINTFN(2, ("ftdi status 0x%04x\n", data));
497 	return data & FT232R_RI ? 0 : 1;
498 }
499 
500 /* udcf_probe runs in a process context. */
501 void
502 udcf_probe(void *xsc)
503 {
504 	struct udcf_softc	*sc = xsc;
505 	struct timespec		 now;
506 	int			 data;
507 
508 	if (usbd_is_dying(sc->sc_udev))
509 		return;
510 
511 	data = sc->sc_signal(sc);
512 	if (data == -1)
513 		return;
514 
515 	if (data) {
516 		sc->sc_level = 1;
517 		timeout_add(&sc->sc_to, 1);
518 		return;
519 	}
520 
521 	if (sc->sc_level == 0)
522 		return;
523 
524 	/* the beginning of a second */
525 	sc->sc_level = 0;
526 	if (sc->sc_minute == 1) {
527 		if (sc->sc_sync) {
528 			DPRINTF(("start collecting bits\n"));
529 			sc->sc_sync = 0;
530 			if (sc->sc_sensor.status == SENSOR_S_UNKNOWN &&
531 			    sc->sc_detect_ct)
532 				sc->sc_clocktype = -1;
533 		} else {
534 			/* provide the timedelta */
535 			microtime(&sc->sc_sensor.tv);
536 			nanotime(&now);
537 			sc->sc_current = sc->sc_next;
538 			sc->sc_sensor.value = (int64_t)(now.tv_sec -
539 			    sc->sc_current) * 1000000000LL + now.tv_nsec;
540 
541 			/* set the clocktype and make sensor valid */
542 			if (sc->sc_sensor.status == SENSOR_S_UNKNOWN &&
543 			    sc->sc_detect_ct) {
544 				strlcpy(sc->sc_sensor.desc, sc->sc_clocktype ?
545 				    clockname[CLOCK_HBG] :
546 				    clockname[CLOCK_DCF77],
547 				    sizeof(sc->sc_sensor.desc));
548 			}
549 			sc->sc_sensor.status = SENSOR_S_OK;
550 
551 			/*
552 			 * if no valid time information is received
553 			 * during the next 5 minutes, the sensor state
554 			 * will be degraded to SENSOR_S_WARN
555 			 */
556 			timeout_add(&sc->sc_it_to, t_warn);
557 		}
558 		sc->sc_minute = 0;
559 	}
560 
561 	timeout_add(&sc->sc_to, t_sync);	/* resync in 950 ms */
562 
563 	/* no clock and bit detection during sync */
564 	if (!sc->sc_sync) {
565 		/* detect bit value */
566 		timeout_add(&sc->sc_bv_to, t_bv);
567 
568 		/* detect clocktype */
569 		if (sc->sc_detect_ct && sc->sc_clocktype == -1)
570 			timeout_add(&sc->sc_ct_to, t_ct);
571 	}
572 	timeout_add(&sc->sc_mg_to, t_mg);	/* detect minute gap */
573 	timeout_add(&sc->sc_sl_to, t_sl);	/* detect signal loss */
574 }
575 
576 /* detect the bit value */
577 void
578 udcf_bv_probe(void *xsc)
579 {
580 	struct udcf_softc	*sc = xsc;
581 	int			 data;
582 
583 	if (usbd_is_dying(sc->sc_udev))
584 		return;
585 
586 	data = sc->sc_signal(sc);
587 	if (data == -1) {
588 		DPRINTF(("bit detection failed\n"));
589 		return;
590 	}
591 
592 	DPRINTFN(1, (data ? "0" : "1"));
593 	if (!(data))
594 		sc->sc_tbits |= sc->sc_mask;
595 	sc->sc_mask <<= 1;
596 }
597 
598 /* detect the minute gap */
599 void
600 udcf_mg_probe(void *xsc)
601 {
602 	struct udcf_softc	*sc = xsc;
603 	struct clock_ymdhms	 ymdhm;
604 	struct timeval		 monotime;
605 	int			 tdiff_recv, tdiff_local;
606 	int			 skew;
607 	int			 minute_bits, hour_bits, day_bits;
608 	int			 month_bits, year_bits, wday;
609 	int			 p1, p2, p3;
610 	int			 p1_bit, p2_bit, p3_bit;
611 	int			 r_bit, a1_bit, a2_bit, z1_bit, z2_bit;
612 	int			 s_bit, m_bit;
613 	u_int32_t		 parity = 0x6996;
614 
615 	if (sc->sc_sync) {
616 		sc->sc_minute = 1;
617 		goto cleanbits;
618 	}
619 
620 	if (time_second - sc->sc_last_mg < 57) {
621 		DPRINTF(("\nunexpected gap, resync\n"));
622 		sc->sc_sync = sc->sc_minute = 1;
623 		goto cleanbits;
624 	}
625 
626 	/* extract bits w/o parity */
627 	m_bit = sc->sc_tbits & 1;
628 	r_bit = sc->sc_tbits >> 15 & 1;
629 	a1_bit = sc->sc_tbits >> 16 & 1;
630 	z1_bit = sc->sc_tbits >> 17 & 1;
631 	z2_bit = sc->sc_tbits >> 18 & 1;
632 	a2_bit = sc->sc_tbits >> 19 & 1;
633 	s_bit = sc->sc_tbits >> 20 & 1;
634 	p1_bit = sc->sc_tbits >> 28 & 1;
635 	p2_bit = sc->sc_tbits >> 35 & 1;
636 	p3_bit = sc->sc_tbits >> 58 & 1;
637 
638 	minute_bits = sc->sc_tbits >> 21 & 0x7f;
639 	hour_bits = sc->sc_tbits >> 29 & 0x3f;
640 	day_bits = sc->sc_tbits >> 36 & 0x3f;
641 	wday = (sc->sc_tbits >> 42) & 0x07;
642 	month_bits = sc->sc_tbits >> 45 & 0x1f;
643 	year_bits = sc->sc_tbits >> 50 & 0xff;
644 
645 	/* validate time information */
646 	p1 = (parity >> (minute_bits & 0x0f) & 1) ^
647 	    (parity >> (minute_bits >> 4) & 1);
648 
649 	p2 = (parity >> (hour_bits & 0x0f) & 1) ^
650 	    (parity >> (hour_bits >> 4) & 1);
651 
652 	p3 = (parity >> (day_bits & 0x0f) & 1) ^
653 	    (parity >> (day_bits >> 4) & 1) ^
654 	    ((parity >> wday) & 1) ^ (parity >> (month_bits & 0x0f) & 1) ^
655 	    (parity >> (month_bits >> 4) & 1) ^
656 	    (parity >> (year_bits & 0x0f) & 1) ^
657 	    (parity >> (year_bits >> 4) & 1);
658 
659 	if (m_bit == 0 && s_bit == 1 && p1 == p1_bit && p2 == p2_bit &&
660 	    p3 == p3_bit && (z1_bit ^ z2_bit)) {
661 
662 		/* Decode time */
663 		if ((ymdhm.dt_year = 2000 + FROMBCD(year_bits)) > 2037) {
664 			DPRINTF(("year out of range, resync\n"));
665 			sc->sc_sync = 1;
666 			goto cleanbits;
667 		}
668 		ymdhm.dt_min = FROMBCD(minute_bits);
669 		ymdhm.dt_hour = FROMBCD(hour_bits);
670 		ymdhm.dt_day = FROMBCD(day_bits);
671 		ymdhm.dt_mon = FROMBCD(month_bits);
672 		ymdhm.dt_sec = 0;
673 
674 		sc->sc_next = clock_ymdhms_to_secs(&ymdhm);
675 		getmicrouptime(&monotime);
676 
677 		/* convert to coordinated universal time */
678 		sc->sc_next -= z1_bit ? 7200 : 3600;
679 
680 		DPRINTF(("\n%02d.%02d.%04d %02d:%02d:00 %s",
681 		    ymdhm.dt_day, ymdhm.dt_mon, ymdhm.dt_year,
682 		    ymdhm.dt_hour, ymdhm.dt_min, z1_bit ? "CEST" : "CET"));
683 		DPRINTF((r_bit ? ", call bit" : ""));
684 		DPRINTF((a1_bit ? ", dst chg ann." : ""));
685 		DPRINTF((a2_bit ? ", leap sec ann." : ""));
686 		DPRINTF(("\n"));
687 
688 		if (sc->sc_last) {
689 			tdiff_recv = sc->sc_next - sc->sc_last;
690 			tdiff_local = monotime.tv_sec - sc->sc_last_tv.tv_sec;
691 			skew = abs(tdiff_local - tdiff_recv);
692 #ifdef UDCF_DEBUG
693 			if (sc->sc_skew.status == SENSOR_S_UNKNOWN)
694 				sc->sc_skew.status = SENSOR_S_CRIT;
695 			sc->sc_skew.value = skew * 1000000000LL;
696 			getmicrotime(&sc->sc_skew.tv);
697 #endif
698 			DPRINTF(("local = %d, recv = %d, skew = %d\n",
699 			    tdiff_local, tdiff_recv, skew));
700 
701 			if (skew && skew * 100LL / tdiff_local > MAX_SKEW) {
702 				DPRINTF(("skew out of tolerated range\n"));
703 				goto cleanbits;
704 			} else {
705 				if (sc->sc_nrecv < 2) {
706 					sc->sc_nrecv++;
707 					DPRINTF(("got frame %d\n",
708 					    sc->sc_nrecv));
709 				} else {
710 					DPRINTF(("data is valid\n"));
711 					sc->sc_minute = 1;
712 				}
713 			}
714 		} else {
715 			DPRINTF(("received the first frame\n"));
716 			sc->sc_nrecv = 1;
717 		}
718 
719 		/* record the time received and when it was received */
720 		sc->sc_last = sc->sc_next;
721 		sc->sc_last_tv.tv_sec = monotime.tv_sec;
722 	} else {
723 		DPRINTF(("\nparity error, resync\n"));
724 		sc->sc_sync = sc->sc_minute = 1;
725 	}
726 
727 cleanbits:
728 	timeout_add(&sc->sc_to, t_mgsync);	/* re-sync in 450 ms */
729 	sc->sc_last_mg = time_second;
730 	sc->sc_tbits = 0LL;
731 	sc->sc_mask = 1LL;
732 }
733 
734 /* detect signal loss */
735 void
736 udcf_sl_probe(void *xsc)
737 {
738 	struct udcf_softc *sc = xsc;
739 
740 	if (usbd_is_dying(sc->sc_udev))
741 		return;
742 
743 	DPRINTF(("no signal\n"));
744 	sc->sc_sync = 1;
745 	timeout_add(&sc->sc_to, t_wait);
746 	timeout_add(&sc->sc_sl_to, t_wait + t_sl);
747 }
748 
749 /* invalidate timedelta (called in an interrupt context) */
750 void
751 udcf_it_intr(void *xsc)
752 {
753 	struct udcf_softc *sc = xsc;
754 
755 	if (usbd_is_dying(sc->sc_udev))
756 		return;
757 
758 	if (sc->sc_sensor.status == SENSOR_S_OK) {
759 		sc->sc_sensor.status = SENSOR_S_WARN;
760 		/*
761 		 * further degrade in 15 minutes if we dont receive any new
762 		 * time information
763 		 */
764 		timeout_add(&sc->sc_it_to, t_crit);
765 	} else {
766 		sc->sc_sensor.status = SENSOR_S_CRIT;
767 		sc->sc_nrecv = 0;
768 	}
769 }
770 
771 /* detect clock type.  used for older devices only. */
772 void
773 udcf_ct_probe(void *xsc)
774 {
775 	struct udcf_softc	*sc = xsc;
776 	int			 data;
777 
778 	if (usbd_is_dying(sc->sc_udev))
779 		return;
780 
781 	data = sc->sc_signal(sc);
782 	if (data == -1) {
783 		DPRINTF(("clocktype detection failed\n"));
784 		return;
785 	}
786 
787 	sc->sc_clocktype = data ? 0 : 1;
788 	DPRINTF(("\nclocktype is %s\n", sc->sc_clocktype ?
789 		clockname[CLOCK_HBG] : clockname[CLOCK_DCF77]));
790 }
791 
792