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