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