LCOV - code coverage report
Current view: top level - dev/usb - udcf.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 296 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13