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