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