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