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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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