Line data Source code
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 0 : udcf_match(struct device *parent, void *match, void *aux)
146 : {
147 0 : struct usb_attach_arg *uaa = aux;
148 :
149 0 : if (uaa->iface == NULL)
150 0 : return UMATCH_NONE;
151 :
152 0 : return (usb_lookup(udcf_devs, uaa->vendor, uaa->product) != NULL ?
153 : UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
154 0 : }
155 :
156 : void
157 0 : udcf_attach(struct device *parent, struct device *self, void *aux)
158 : {
159 0 : struct udcf_softc *sc = (struct udcf_softc *)self;
160 0 : struct usb_attach_arg *uaa = aux;
161 0 : struct usbd_device *dev = uaa->device;
162 0 : struct usbd_interface *iface;
163 0 : struct timeval t;
164 : usbd_status err;
165 :
166 0 : switch (uaa->product) {
167 : case USB_PRODUCT_GUDE_DCF:
168 0 : sc->sc_signal = udcf_nc_signal;
169 0 : strlcpy(sc->sc_sensor.desc, "DCF77",
170 : sizeof(sc->sc_sensor.desc));
171 0 : break;
172 : case USB_PRODUCT_FTDI_DCF:
173 0 : sc->sc_signal = udcf_ft232r_signal;
174 0 : strlcpy(sc->sc_sensor.desc, "DCF77",
175 : sizeof(sc->sc_sensor.desc));
176 0 : break;
177 : }
178 :
179 0 : usb_init_task(&sc->sc_task, udcf_probe, sc, USB_TASK_TYPE_GENERIC);
180 0 : usb_init_task(&sc->sc_bv_task, udcf_bv_probe, sc, USB_TASK_TYPE_GENERIC);
181 0 : usb_init_task(&sc->sc_mg_task, udcf_mg_probe, sc, USB_TASK_TYPE_GENERIC);
182 0 : usb_init_task(&sc->sc_sl_task, udcf_sl_probe, sc, USB_TASK_TYPE_GENERIC);
183 :
184 0 : timeout_set(&sc->sc_to, udcf_intr, sc);
185 0 : timeout_set(&sc->sc_bv_to, udcf_bv_intr, sc);
186 0 : timeout_set(&sc->sc_mg_to, udcf_mg_intr, sc);
187 0 : timeout_set(&sc->sc_sl_to, udcf_sl_intr, sc);
188 0 : timeout_set(&sc->sc_it_to, udcf_it_intr, sc);
189 :
190 0 : strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
191 : sizeof(sc->sc_sensordev.xname));
192 :
193 0 : sc->sc_sensor.type = SENSOR_TIMEDELTA;
194 0 : sc->sc_sensor.status = SENSOR_S_UNKNOWN;
195 0 : 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 0 : sensordev_install(&sc->sc_sensordev);
205 :
206 0 : sc->sc_udev = dev;
207 0 : 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 0 : sc->sc_iface = iface;
214 :
215 0 : sc->sc_level = 0;
216 0 : sc->sc_minute = 0;
217 0 : sc->sc_last_mg = 0L;
218 :
219 0 : sc->sc_sync = 1;
220 :
221 0 : sc->sc_current = 0L;
222 0 : sc->sc_next = 0L;
223 0 : sc->sc_nrecv = 0;
224 0 : sc->sc_last = 0L;
225 0 : sc->sc_last_tv.tv_sec = 0L;
226 :
227 0 : switch (uaa->product) {
228 : case USB_PRODUCT_GUDE_DCF:
229 0 : if (udcf_nc_init_hw(sc))
230 : goto fishy;
231 : break;
232 : case USB_PRODUCT_FTDI_DCF:
233 0 : if (udcf_ft232r_init_hw(sc))
234 : goto fishy;
235 : break;
236 : }
237 :
238 : /* convert timevals to hz */
239 0 : t.tv_sec = 0L;
240 0 : t.tv_usec = 150000L;
241 0 : t_bv = tvtohz(&t);
242 :
243 0 : t.tv_usec = 450000L;
244 0 : t_mgsync = tvtohz(&t);
245 :
246 0 : t.tv_usec = 950000L;
247 0 : t_sync = tvtohz(&t);
248 :
249 0 : t.tv_sec = 1L;
250 0 : t.tv_usec = 500000L;
251 0 : t_mg = tvtohz(&t);
252 :
253 0 : t.tv_sec = 3L;
254 0 : t.tv_usec = 0L;
255 0 : t_sl = tvtohz(&t);
256 :
257 0 : t.tv_sec = 5L;
258 0 : t_wait = tvtohz(&t);
259 :
260 0 : t.tv_sec = DPERIOD1;
261 0 : t_warn = tvtohz(&t);
262 :
263 0 : t.tv_sec = DPERIOD2;
264 0 : t_crit = tvtohz(&t);
265 :
266 : /* Give the receiver some slack to stabilize */
267 0 : timeout_add(&sc->sc_to, t_wait);
268 :
269 : /* Detect signal loss */
270 0 : timeout_add(&sc->sc_sl_to, t_wait + t_sl);
271 :
272 : DPRINTF(("synchronizing\n"));
273 0 : return;
274 :
275 : fishy:
276 : DPRINTF(("udcf_attach failed\n"));
277 0 : usbd_deactivate(sc->sc_udev);
278 0 : }
279 :
280 : int
281 0 : udcf_detach(struct device *self, int flags)
282 : {
283 0 : struct udcf_softc *sc = (struct udcf_softc *)self;
284 :
285 0 : if (timeout_initialized(&sc->sc_to))
286 0 : timeout_del(&sc->sc_to);
287 0 : if (timeout_initialized(&sc->sc_bv_to))
288 0 : timeout_del(&sc->sc_bv_to);
289 0 : if (timeout_initialized(&sc->sc_mg_to))
290 0 : timeout_del(&sc->sc_mg_to);
291 0 : if (timeout_initialized(&sc->sc_sl_to))
292 0 : timeout_del(&sc->sc_sl_to);
293 0 : if (timeout_initialized(&sc->sc_it_to))
294 0 : timeout_del(&sc->sc_it_to);
295 :
296 : /* Unregister the clock with the kernel */
297 0 : sensordev_deinstall(&sc->sc_sensordev);
298 0 : usb_rem_task(sc->sc_udev, &sc->sc_task);
299 0 : usb_rem_task(sc->sc_udev, &sc->sc_bv_task);
300 0 : usb_rem_task(sc->sc_udev, &sc->sc_mg_task);
301 0 : usb_rem_task(sc->sc_udev, &sc->sc_sl_task);
302 :
303 0 : return 0;
304 : }
305 :
306 : /* udcf_intr runs in an interrupt context */
307 : void
308 0 : udcf_intr(void *xsc)
309 : {
310 0 : struct udcf_softc *sc = xsc;
311 0 : usb_add_task(sc->sc_udev, &sc->sc_task);
312 0 : }
313 :
314 : /* bit value detection */
315 : void
316 0 : udcf_bv_intr(void *xsc)
317 : {
318 0 : struct udcf_softc *sc = xsc;
319 0 : usb_add_task(sc->sc_udev, &sc->sc_bv_task);
320 0 : }
321 :
322 : /* minute gap detection */
323 : void
324 0 : udcf_mg_intr(void *xsc)
325 : {
326 0 : struct udcf_softc *sc = xsc;
327 0 : usb_add_task(sc->sc_udev, &sc->sc_mg_task);
328 0 : }
329 :
330 : /* signal loss detection */
331 : void
332 0 : udcf_sl_intr(void *xsc)
333 : {
334 0 : struct udcf_softc *sc = xsc;
335 0 : usb_add_task(sc->sc_udev, &sc->sc_sl_task);
336 0 : }
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 0 : udcf_nc_init_hw(struct udcf_softc *sc)
345 : {
346 : usbd_status err;
347 0 : usb_device_request_t req;
348 0 : uWord result;
349 0 : int actlen;
350 :
351 : /* Prepare the USB request to probe the value */
352 0 : sc->sc_req.bmRequestType = UT_READ_VENDOR_DEVICE;
353 0 : sc->sc_req.bRequest = 1;
354 0 : USETW(sc->sc_req.wValue, 0);
355 0 : USETW(sc->sc_req.wIndex, UDCF_READ_IDX);
356 0 : USETW(sc->sc_req.wLength, 1);
357 :
358 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
359 0 : req.bRequest = 0;
360 0 : USETW(req.wValue, 0);
361 0 : USETW(req.wIndex, 0);
362 0 : USETW(req.wLength, 0);
363 0 : 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 0 : return -1;
367 : }
368 :
369 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
370 0 : req.bRequest = 0;
371 0 : USETW(req.wValue, UDCF_CTRL_VAL);
372 0 : USETW(req.wIndex, UDCF_CTRL_IDX);
373 0 : USETW(req.wLength, 0);
374 0 : 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 0 : return -1;
378 : }
379 0 : return 0;
380 0 : }
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 0 : udcf_ft232r_init_hw(struct udcf_softc *sc)
388 : {
389 : usbd_status err;
390 0 : usb_device_request_t req;
391 :
392 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
393 0 : req.bRequest = FT232R_RESET;
394 : /* 0 resets the SIO */
395 0 : USETW(req.wValue,FT232R_RESET);
396 0 : USETW(req.wIndex, 0);
397 0 : USETW(req.wLength, 0);
398 0 : err = usbd_do_request(sc->sc_udev, &req, NULL);
399 0 : if (err) {
400 : DPRINTF(("failed to reset ftdi\n"));
401 0 : return -1;
402 : }
403 0 : return 0;
404 0 : }
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 0 : udcf_nc_signal(struct udcf_softc *sc)
413 : {
414 0 : int actlen;
415 0 : unsigned char data;
416 :
417 0 : 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 0 : return -1;
421 0 : return data & 0x01;
422 0 : }
423 :
424 : /* pick up the signal level through the FTDI FT232R chip */
425 : int
426 0 : udcf_ft232r_signal(struct udcf_softc *sc)
427 : {
428 0 : usb_device_request_t req;
429 0 : int actlen;
430 0 : u_int16_t data;
431 :
432 0 : req.bmRequestType = UT_READ_VENDOR_DEVICE;
433 0 : req.bRequest = FT232R_STATUS;
434 0 : USETW(req.wValue, 0);
435 0 : USETW(req.wIndex, 0);
436 0 : USETW(req.wLength, 2);
437 0 : 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 0 : return -1;
441 : }
442 : DPRINTFN(2, ("ftdi status 0x%04x\n", data));
443 0 : return data & FT232R_RI ? 0 : 1;
444 0 : }
445 :
446 : /* udcf_probe runs in a process context. */
447 : void
448 0 : udcf_probe(void *xsc)
449 : {
450 0 : struct udcf_softc *sc = xsc;
451 0 : struct timespec now;
452 : int data;
453 :
454 0 : if (usbd_is_dying(sc->sc_udev))
455 0 : return;
456 :
457 0 : data = sc->sc_signal(sc);
458 0 : if (data == -1)
459 0 : return;
460 :
461 0 : if (data) {
462 0 : sc->sc_level = 1;
463 0 : timeout_add(&sc->sc_to, 1);
464 0 : return;
465 : }
466 :
467 0 : if (sc->sc_level == 0)
468 0 : return;
469 :
470 : /* the beginning of a second */
471 0 : sc->sc_level = 0;
472 0 : if (sc->sc_minute == 1) {
473 0 : if (sc->sc_sync) {
474 : DPRINTF(("start collecting bits\n"));
475 0 : sc->sc_sync = 0;
476 0 : } else {
477 : /* provide the timedelta */
478 0 : microtime(&sc->sc_sensor.tv);
479 0 : nanotime(&now);
480 0 : sc->sc_current = sc->sc_next;
481 0 : sc->sc_sensor.value = (int64_t)(now.tv_sec -
482 0 : sc->sc_current) * 1000000000LL + now.tv_nsec;
483 :
484 0 : 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 0 : timeout_add(&sc->sc_it_to, t_warn);
492 : }
493 0 : sc->sc_minute = 0;
494 0 : }
495 :
496 0 : timeout_add(&sc->sc_to, t_sync); /* resync in 950 ms */
497 :
498 : /* no clock and bit detection during sync */
499 0 : if (!sc->sc_sync) {
500 : /* detect bit value */
501 0 : timeout_add(&sc->sc_bv_to, t_bv);
502 0 : }
503 0 : timeout_add(&sc->sc_mg_to, t_mg); /* detect minute gap */
504 0 : timeout_add(&sc->sc_sl_to, t_sl); /* detect signal loss */
505 0 : }
506 :
507 : /* detect the bit value */
508 : void
509 0 : udcf_bv_probe(void *xsc)
510 : {
511 0 : struct udcf_softc *sc = xsc;
512 : int data;
513 :
514 0 : if (usbd_is_dying(sc->sc_udev))
515 0 : return;
516 :
517 0 : data = sc->sc_signal(sc);
518 0 : if (data == -1) {
519 : DPRINTF(("bit detection failed\n"));
520 0 : return;
521 : }
522 :
523 : DPRINTFN(1, (data ? "0" : "1"));
524 0 : if (!(data))
525 0 : sc->sc_tbits |= sc->sc_mask;
526 0 : sc->sc_mask <<= 1;
527 0 : }
528 :
529 : /* detect the minute gap */
530 : void
531 0 : udcf_mg_probe(void *xsc)
532 : {
533 0 : struct udcf_softc *sc = xsc;
534 0 : struct clock_ymdhms ymdhm;
535 0 : 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 0 : if (sc->sc_sync) {
547 0 : sc->sc_minute = 1;
548 0 : goto cleanbits;
549 : }
550 :
551 0 : if (time_second - sc->sc_last_mg < 57) {
552 : DPRINTF(("\nunexpected gap, resync\n"));
553 0 : sc->sc_sync = sc->sc_minute = 1;
554 0 : goto cleanbits;
555 : }
556 :
557 : /* extract bits w/o parity */
558 0 : m_bit = sc->sc_tbits & 1;
559 0 : r_bit = sc->sc_tbits >> 15 & 1;
560 0 : a1_bit = sc->sc_tbits >> 16 & 1;
561 0 : z1_bit = sc->sc_tbits >> 17 & 1;
562 0 : z2_bit = sc->sc_tbits >> 18 & 1;
563 0 : a2_bit = sc->sc_tbits >> 19 & 1;
564 0 : s_bit = sc->sc_tbits >> 20 & 1;
565 0 : p1_bit = sc->sc_tbits >> 28 & 1;
566 0 : p2_bit = sc->sc_tbits >> 35 & 1;
567 0 : p3_bit = sc->sc_tbits >> 58 & 1;
568 :
569 0 : minute_bits = sc->sc_tbits >> 21 & 0x7f;
570 0 : hour_bits = sc->sc_tbits >> 29 & 0x3f;
571 0 : day_bits = sc->sc_tbits >> 36 & 0x3f;
572 0 : wday = (sc->sc_tbits >> 42) & 0x07;
573 0 : month_bits = sc->sc_tbits >> 45 & 0x1f;
574 0 : year_bits = sc->sc_tbits >> 50 & 0xff;
575 :
576 : /* validate time information */
577 0 : p1 = (parity >> (minute_bits & 0x0f) & 1) ^
578 0 : (parity >> (minute_bits >> 4) & 1);
579 :
580 0 : p2 = (parity >> (hour_bits & 0x0f) & 1) ^
581 0 : (parity >> (hour_bits >> 4) & 1);
582 :
583 0 : p3 = (parity >> (day_bits & 0x0f) & 1) ^
584 0 : (parity >> (day_bits >> 4) & 1) ^
585 0 : ((parity >> wday) & 1) ^ (parity >> (month_bits & 0x0f) & 1) ^
586 0 : (parity >> (month_bits >> 4) & 1) ^
587 0 : (parity >> (year_bits & 0x0f) & 1) ^
588 0 : (parity >> (year_bits >> 4) & 1);
589 :
590 0 : if (m_bit == 0 && s_bit == 1 && p1 == p1_bit && p2 == p2_bit &&
591 0 : p3 == p3_bit && (z1_bit ^ z2_bit)) {
592 :
593 : /* Decode time */
594 0 : if ((ymdhm.dt_year = 2000 + FROMBCD(year_bits)) > 2037) {
595 : DPRINTF(("year out of range, resync\n"));
596 0 : sc->sc_sync = 1;
597 0 : goto cleanbits;
598 : }
599 0 : ymdhm.dt_min = FROMBCD(minute_bits);
600 0 : ymdhm.dt_hour = FROMBCD(hour_bits);
601 0 : ymdhm.dt_day = FROMBCD(day_bits);
602 0 : ymdhm.dt_mon = FROMBCD(month_bits);
603 0 : ymdhm.dt_sec = 0;
604 :
605 0 : sc->sc_next = clock_ymdhms_to_secs(&ymdhm);
606 0 : getmicrouptime(&monotime);
607 :
608 : /* convert to coordinated universal time */
609 0 : 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 0 : if (sc->sc_last) {
620 0 : tdiff_recv = sc->sc_next - sc->sc_last;
621 0 : tdiff_local = monotime.tv_sec - sc->sc_last_tv.tv_sec;
622 0 : 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 0 : if (skew && skew * 100LL / tdiff_local > MAX_SKEW) {
633 : DPRINTF(("skew out of tolerated range\n"));
634 : goto cleanbits;
635 : } else {
636 0 : if (sc->sc_nrecv < 2) {
637 0 : sc->sc_nrecv++;
638 : DPRINTF(("got frame %d\n",
639 : sc->sc_nrecv));
640 0 : } else {
641 : DPRINTF(("data is valid\n"));
642 0 : sc->sc_minute = 1;
643 : }
644 : }
645 : } else {
646 : DPRINTF(("received the first frame\n"));
647 0 : sc->sc_nrecv = 1;
648 : }
649 :
650 : /* record the time received and when it was received */
651 0 : sc->sc_last = sc->sc_next;
652 0 : sc->sc_last_tv.tv_sec = monotime.tv_sec;
653 0 : } else {
654 : DPRINTF(("\nparity error, resync\n"));
655 0 : sc->sc_sync = sc->sc_minute = 1;
656 : }
657 :
658 : cleanbits:
659 0 : timeout_add(&sc->sc_to, t_mgsync); /* re-sync in 450 ms */
660 0 : sc->sc_last_mg = time_second;
661 0 : sc->sc_tbits = 0LL;
662 0 : sc->sc_mask = 1LL;
663 0 : }
664 :
665 : /* detect signal loss */
666 : void
667 0 : udcf_sl_probe(void *xsc)
668 : {
669 0 : struct udcf_softc *sc = xsc;
670 :
671 0 : if (usbd_is_dying(sc->sc_udev))
672 0 : return;
673 :
674 : DPRINTF(("no signal\n"));
675 0 : sc->sc_sync = 1;
676 0 : timeout_add(&sc->sc_to, t_wait);
677 0 : timeout_add(&sc->sc_sl_to, t_wait + t_sl);
678 0 : }
679 :
680 : /* invalidate timedelta (called in an interrupt context) */
681 : void
682 0 : udcf_it_intr(void *xsc)
683 : {
684 0 : struct udcf_softc *sc = xsc;
685 :
686 0 : if (usbd_is_dying(sc->sc_udev))
687 0 : return;
688 :
689 0 : if (sc->sc_sensor.status == SENSOR_S_OK) {
690 0 : 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 0 : timeout_add(&sc->sc_it_to, t_crit);
696 0 : } else {
697 0 : sc->sc_sensor.status = SENSOR_S_CRIT;
698 0 : sc->sc_nrecv = 0;
699 : }
700 0 : }
|