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