1*81508fe3Sjsg /* $OpenBSD: umbg.c,v 1.29 2024/05/23 03:21:09 jsg Exp $ */
22c06c139Smbalmer
32c06c139Smbalmer /*
42c06c139Smbalmer * Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org>
52c06c139Smbalmer *
62c06c139Smbalmer * Permission to use, copy, modify, and distribute this software for any
72c06c139Smbalmer * purpose with or without fee is hereby granted, provided that the above
82c06c139Smbalmer * copyright notice and this permission notice appear in all copies.
92c06c139Smbalmer *
102c06c139Smbalmer * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
112c06c139Smbalmer * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
122c06c139Smbalmer * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
132c06c139Smbalmer * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
142c06c139Smbalmer * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
152c06c139Smbalmer * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
162c06c139Smbalmer * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
172c06c139Smbalmer */
182c06c139Smbalmer
192c06c139Smbalmer #include <sys/param.h>
202c06c139Smbalmer #include <sys/systm.h>
212c06c139Smbalmer #include <sys/device.h>
222c06c139Smbalmer #include <sys/time.h>
232c06c139Smbalmer #include <sys/sensors.h>
24b047b92cStedu #include <sys/timeout.h>
252c06c139Smbalmer
262c06c139Smbalmer #include <dev/usb/usb.h>
272c06c139Smbalmer #include <dev/usb/usbdi.h>
282c06c139Smbalmer #include <dev/usb/usbdevs.h>
292c06c139Smbalmer
302c06c139Smbalmer #ifdef UMBG_DEBUG
312c06c139Smbalmer #define DPRINTFN(n, x) do { if (umbgdebug > (n)) printf x; } while (0)
322c06c139Smbalmer int umbgdebug = 0;
332c06c139Smbalmer #else
342c06c139Smbalmer #define DPRINTFN(n, x)
352c06c139Smbalmer #endif
362c06c139Smbalmer #define DPRINTF(x) DPRINTFN(0, x)
372c06c139Smbalmer
382c06c139Smbalmer #ifdef UMBG_DEBUG
392c06c139Smbalmer #define TRUSTTIME ((long) 60)
402c06c139Smbalmer #else
412c06c139Smbalmer #define TRUSTTIME ((long) 12 * 60 * 60) /* degrade OK > WARN > CRIT */
422c06c139Smbalmer #endif
432c06c139Smbalmer
442c06c139Smbalmer struct umbg_softc {
452c06c139Smbalmer struct device sc_dev; /* base device */
46ab0b1be7Smglocker struct usbd_device *sc_udev; /* USB device */
47ab0b1be7Smglocker struct usbd_interface *sc_iface; /* data interface */
482c06c139Smbalmer
492c06c139Smbalmer int sc_bulkin_no;
50ab0b1be7Smglocker struct usbd_pipe *sc_bulkin_pipe;
512c06c139Smbalmer int sc_bulkout_no;
52ab0b1be7Smglocker struct usbd_pipe *sc_bulkout_pipe;
532c06c139Smbalmer
542c06c139Smbalmer struct timeout sc_to; /* get time from device */
552c06c139Smbalmer struct usb_task sc_task;
562c06c139Smbalmer
572c06c139Smbalmer struct timeout sc_it_to; /* invalidate sensor */
582c06c139Smbalmer
592c06c139Smbalmer usb_device_request_t sc_req;
602c06c139Smbalmer
612c06c139Smbalmer struct ksensor sc_timedelta; /* timedelta */
622c06c139Smbalmer struct ksensor sc_signal; /* signal quality and status */
632c06c139Smbalmer struct ksensordev sc_sensordev;
642c06c139Smbalmer };
652c06c139Smbalmer
662c06c139Smbalmer struct mbg_time {
672c06c139Smbalmer u_int8_t hundreds;
682c06c139Smbalmer u_int8_t sec;
692c06c139Smbalmer u_int8_t min;
702c06c139Smbalmer u_int8_t hour;
712c06c139Smbalmer u_int8_t mday;
722c06c139Smbalmer u_int8_t wday; /* 1 (monday) - 7 (sunday) */
732c06c139Smbalmer u_int8_t mon;
742c06c139Smbalmer u_int8_t year; /* 0 - 99 */
752c06c139Smbalmer u_int8_t status;
762c06c139Smbalmer u_int8_t signal;
772c06c139Smbalmer int8_t utc_off;
782c06c139Smbalmer };
792c06c139Smbalmer
802c06c139Smbalmer struct mbg_time_hr {
81fede6f61Smbalmer u_int32_t sec; /* always UTC */
822c06c139Smbalmer u_int32_t frac; /* fractions of second */
83fede6f61Smbalmer int32_t utc_off; /* informal only, in seconds */
842c06c139Smbalmer u_int16_t status;
852c06c139Smbalmer u_int8_t signal;
862c06c139Smbalmer };
872c06c139Smbalmer
882c06c139Smbalmer /* mbg_time.status bits */
892c06c139Smbalmer #define MBG_FREERUN 0x01 /* clock running on xtal */
902c06c139Smbalmer #define MBG_DST_ENA 0x02 /* DST enabled */
912c06c139Smbalmer #define MBG_SYNC 0x04 /* clock synced at least once */
922c06c139Smbalmer #define MBG_DST_CHG 0x08 /* DST change announcement */
932c06c139Smbalmer #define MBG_UTC 0x10 /* special UTC firmware is installed */
942c06c139Smbalmer #define MBG_LEAP 0x20 /* announcement of a leap second */
952c06c139Smbalmer #define MBG_IFTM 0x40 /* current time was set from host */
969c0b2136Smbalmer #define MBG_INVALID 0x80 /* time invalid, batt. was disconn. */
972c06c139Smbalmer
982c06c139Smbalmer /* commands */
992c06c139Smbalmer #define MBG_GET_TIME 0x00
1002c06c139Smbalmer #define MBG_GET_SYNC_TIME 0x02
1012c06c139Smbalmer #define MBG_GET_TIME_HR 0x03
1022c06c139Smbalmer #define MBG_SET_TIME 0x10
1032c06c139Smbalmer #define MBG_GET_TZCODE 0x32
1042c06c139Smbalmer #define MBG_SET_TZCODE 0x33
1052c06c139Smbalmer #define MBG_GET_FW_ID_1 0x40
1062c06c139Smbalmer #define MBG_GET_FW_ID_2 0x41
1072c06c139Smbalmer #define MBG_GET_SERNUM 0x42
1082c06c139Smbalmer
1092c06c139Smbalmer /* timezone codes (for MBG_{GET|SET}_TZCODE) */
1102c06c139Smbalmer #define MBG_TZCODE_CET_CEST 0x00
1112c06c139Smbalmer #define MBG_TZCODE_CET 0x01
1122c06c139Smbalmer #define MBG_TZCODE_UTC 0x02
1132c06c139Smbalmer #define MBG_TZCODE_EET_EEST 0x03
1142c06c139Smbalmer
1152c06c139Smbalmer /* misc. constants */
1162c06c139Smbalmer #define MBG_FIFO_LEN 16
1172c06c139Smbalmer #define MBG_ID_LEN (2 * MBG_FIFO_LEN + 1)
1182c06c139Smbalmer #define MBG_BUSY 0x01
1192c06c139Smbalmer #define MBG_SIG_BIAS 55
1202c06c139Smbalmer #define MBG_SIG_MAX 68
1212c06c139Smbalmer #define NSECPERSEC 1000000000LL /* nanoseconds per second */
1222c06c139Smbalmer #define HRDIVISOR 0x100000000LL /* for hi-res timestamp */
1232c06c139Smbalmer
1242c06c139Smbalmer static int t_wait, t_trust;
1252c06c139Smbalmer
1262c06c139Smbalmer void umbg_intr(void *);
1272c06c139Smbalmer void umbg_it_intr(void *);
1282c06c139Smbalmer
1292c06c139Smbalmer int umbg_match(struct device *, void *, void *);
1302c06c139Smbalmer void umbg_attach(struct device *, struct device *, void *);
1312c06c139Smbalmer int umbg_detach(struct device *, int);
1322c06c139Smbalmer
1332c06c139Smbalmer void umbg_task(void *);
1342c06c139Smbalmer
1352c06c139Smbalmer int umbg_read(struct umbg_softc *, u_int8_t cmd, char *buf, size_t len,
1362c06c139Smbalmer struct timespec *tstamp);
1372c06c139Smbalmer
1382c06c139Smbalmer struct cfdriver umbg_cd = {
1392c06c139Smbalmer NULL, "umbg", DV_DULL
1402c06c139Smbalmer };
1412c06c139Smbalmer
1422c06c139Smbalmer const struct cfattach umbg_ca = {
143cf8c8cdaSmpi sizeof(struct umbg_softc), umbg_match, umbg_attach, umbg_detach
1442c06c139Smbalmer };
1452c06c139Smbalmer
1462c06c139Smbalmer int
umbg_match(struct device * parent,void * match,void * aux)1472c06c139Smbalmer umbg_match(struct device *parent, void *match, void *aux)
1482c06c139Smbalmer {
1492c06c139Smbalmer struct usb_attach_arg *uaa = aux;
1502c06c139Smbalmer
151c0d38480Smpi if (uaa->iface == NULL)
1522c06c139Smbalmer return UMATCH_NONE;
1532c06c139Smbalmer
154dd567292Ssthen return uaa->vendor == USB_VENDOR_MEINBERG && (
155dd567292Ssthen uaa->product == USB_PRODUCT_MEINBERG_USB5131 ||
156dd567292Ssthen uaa->product == USB_PRODUCT_MEINBERG_DCF600USB) ?
1572c06c139Smbalmer UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
1582c06c139Smbalmer }
1592c06c139Smbalmer
1602c06c139Smbalmer void
umbg_attach(struct device * parent,struct device * self,void * aux)1612c06c139Smbalmer umbg_attach(struct device *parent, struct device *self, void *aux)
1622c06c139Smbalmer {
1632c06c139Smbalmer struct umbg_softc *sc = (struct umbg_softc *)self;
1642c06c139Smbalmer struct usb_attach_arg *uaa = aux;
165ab0b1be7Smglocker struct usbd_device *dev = uaa->device;
166ab0b1be7Smglocker struct usbd_interface *iface = uaa->iface;
1672c06c139Smbalmer struct mbg_time tframe;
1682c06c139Smbalmer usb_endpoint_descriptor_t *ed;
1692c06c139Smbalmer usbd_status err;
1702c06c139Smbalmer int signal;
171dd567292Ssthen const char *desc;
1722c06c139Smbalmer #ifdef UMBG_DEBUG
1732c06c139Smbalmer char fw_id[MBG_ID_LEN];
1742c06c139Smbalmer #endif
1758881fd2fSmbalmer sc->sc_udev = dev;
1768881fd2fSmbalmer
1778881fd2fSmbalmer strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
1788881fd2fSmbalmer sizeof(sc->sc_sensordev.xname));
1798881fd2fSmbalmer
1808881fd2fSmbalmer sc->sc_timedelta.type = SENSOR_TIMEDELTA;
1818881fd2fSmbalmer sc->sc_timedelta.status = SENSOR_S_UNKNOWN;
182dd567292Ssthen
183dd567292Ssthen switch (uaa->product) {
184dd567292Ssthen case USB_PRODUCT_MEINBERG_DCF600USB:
185dd567292Ssthen desc = "DCF600USB";
186dd567292Ssthen break;
187dd567292Ssthen case USB_PRODUCT_MEINBERG_USB5131:
188dd567292Ssthen desc = "USB5131";
189dd567292Ssthen break;
190dd567292Ssthen default:
191dd567292Ssthen desc = "Unspecified Radio clock";
192dd567292Ssthen }
193dd567292Ssthen strlcpy(sc->sc_timedelta.desc, desc,
1948881fd2fSmbalmer sizeof(sc->sc_timedelta.desc));
1958881fd2fSmbalmer sensor_attach(&sc->sc_sensordev, &sc->sc_timedelta);
1968881fd2fSmbalmer
1978881fd2fSmbalmer sc->sc_signal.type = SENSOR_PERCENT;
1988881fd2fSmbalmer strlcpy(sc->sc_signal.desc, "Signal", sizeof(sc->sc_signal.desc));
1998881fd2fSmbalmer sensor_attach(&sc->sc_sensordev, &sc->sc_signal);
2008881fd2fSmbalmer sensordev_install(&sc->sc_sensordev);
2018881fd2fSmbalmer
202c33449aaSjakemsr usb_init_task(&sc->sc_task, umbg_task, sc, USB_TASK_TYPE_GENERIC);
2038881fd2fSmbalmer timeout_set(&sc->sc_to, umbg_intr, sc);
2048881fd2fSmbalmer timeout_set(&sc->sc_it_to, umbg_it_intr, sc);
2052c06c139Smbalmer
2062c06c139Smbalmer if ((err = usbd_device2interface_handle(dev, 0, &iface))) {
2079c0b2136Smbalmer printf("%s: failed to get interface, err=%s\n",
2089c0b2136Smbalmer sc->sc_dev.dv_xname, usbd_errstr(err));
2092c06c139Smbalmer goto fishy;
2102c06c139Smbalmer }
2112c06c139Smbalmer
2122c06c139Smbalmer ed = usbd_interface2endpoint_descriptor(iface, 0);
2132c06c139Smbalmer sc->sc_bulkin_no = ed->bEndpointAddress;
2142c06c139Smbalmer ed = usbd_interface2endpoint_descriptor(iface, 1);
2152c06c139Smbalmer sc->sc_bulkout_no = ed->bEndpointAddress;
2162c06c139Smbalmer
2172c06c139Smbalmer sc->sc_iface = iface;
2182c06c139Smbalmer
2192c06c139Smbalmer err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no,
2202c06c139Smbalmer USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe);
2212c06c139Smbalmer if (err) {
2222c06c139Smbalmer printf("%s: open rx pipe failed: %s\n", sc->sc_dev.dv_xname,
2232c06c139Smbalmer usbd_errstr(err));
2242c06c139Smbalmer goto fishy;
2252c06c139Smbalmer }
2262c06c139Smbalmer
2272c06c139Smbalmer err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
2282c06c139Smbalmer USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
2292c06c139Smbalmer if (err) {
2302c06c139Smbalmer printf("%s: open tx pipe failed: %s\n", sc->sc_dev.dv_xname,
2312c06c139Smbalmer usbd_errstr(err));
2322c06c139Smbalmer goto fishy;
2332c06c139Smbalmer }
2342c06c139Smbalmer
2352c06c139Smbalmer printf("%s: ", sc->sc_dev.dv_xname);
2362c06c139Smbalmer if (umbg_read(sc, MBG_GET_TIME, (char *)&tframe,
2372c06c139Smbalmer sizeof(struct mbg_time), NULL)) {
2382c06c139Smbalmer sc->sc_signal.status = SENSOR_S_CRIT;
2392c06c139Smbalmer printf("unknown status");
2402c06c139Smbalmer } else {
2412c06c139Smbalmer sc->sc_signal.status = SENSOR_S_OK;
2422c06c139Smbalmer signal = tframe.signal - MBG_SIG_BIAS;
2432c06c139Smbalmer if (signal < 0)
2442c06c139Smbalmer signal = 0;
2452c06c139Smbalmer else if (signal > MBG_SIG_MAX)
2462c06c139Smbalmer signal = MBG_SIG_MAX;
2472c06c139Smbalmer sc->sc_signal.value = signal;
2482c06c139Smbalmer
2492c06c139Smbalmer if (tframe.status & MBG_SYNC)
2502c06c139Smbalmer printf("synchronized");
2512c06c139Smbalmer else
2522c06c139Smbalmer printf("not synchronized");
2532c06c139Smbalmer if (tframe.status & MBG_FREERUN) {
2542c06c139Smbalmer sc->sc_signal.status = SENSOR_S_WARN;
2552c06c139Smbalmer printf(", freerun");
2562c06c139Smbalmer }
2572c06c139Smbalmer if (tframe.status & MBG_IFTM)
2582c06c139Smbalmer printf(", time set from host");
2592c06c139Smbalmer }
2602c06c139Smbalmer #ifdef UMBG_DEBUG
2612c06c139Smbalmer if (umbg_read(sc, MBG_GET_FW_ID_1, fw_id, MBG_FIFO_LEN, NULL) ||
2622c06c139Smbalmer umbg_read(sc, MBG_GET_FW_ID_2, &fw_id[MBG_FIFO_LEN], MBG_FIFO_LEN,
2632c06c139Smbalmer NULL))
2642c06c139Smbalmer printf(", firmware unknown");
2652c06c139Smbalmer else {
2662c06c139Smbalmer fw_id[MBG_ID_LEN - 1] = '\0';
2672c06c139Smbalmer printf(", firmware %s", fw_id);
2682c06c139Smbalmer }
2692c06c139Smbalmer #endif
2702c06c139Smbalmer printf("\n");
2712c06c139Smbalmer
272e15e1c8cSblambert t_wait = 5;
2732c06c139Smbalmer
274e15e1c8cSblambert t_trust = TRUSTTIME;
2752c06c139Smbalmer
2762c06c139Smbalmer usb_add_task(sc->sc_udev, &sc->sc_task);
2772c06c139Smbalmer return;
2782c06c139Smbalmer
2792c06c139Smbalmer fishy:
2807b043b62Sjakemsr usbd_deactivate(sc->sc_udev);
2812c06c139Smbalmer }
2822c06c139Smbalmer
2832c06c139Smbalmer int
umbg_detach(struct device * self,int flags)2842c06c139Smbalmer umbg_detach(struct device *self, int flags)
2852c06c139Smbalmer {
2862c06c139Smbalmer struct umbg_softc *sc = (struct umbg_softc *)self;
2872c06c139Smbalmer usbd_status err;
2882c06c139Smbalmer
289c7438bddSjakemsr if (timeout_initialized(&sc->sc_to))
2902c06c139Smbalmer timeout_del(&sc->sc_to);
291c7438bddSjakemsr if (timeout_initialized(&sc->sc_it_to))
2922c06c139Smbalmer timeout_del(&sc->sc_it_to);
2932c06c139Smbalmer
294289f8943Sderaadt usb_rem_task(sc->sc_udev, &sc->sc_task);
295289f8943Sderaadt
2962c06c139Smbalmer if (sc->sc_bulkin_pipe != NULL) {
2972c06c139Smbalmer err = usbd_close_pipe(sc->sc_bulkin_pipe);
2982c06c139Smbalmer if (err)
2992c06c139Smbalmer printf("%s: close rx pipe failed: %s\n",
3002c06c139Smbalmer sc->sc_dev.dv_xname, usbd_errstr(err));
3012c06c139Smbalmer sc->sc_bulkin_pipe = NULL;
3022c06c139Smbalmer }
3032c06c139Smbalmer if (sc->sc_bulkout_pipe != NULL) {
3042c06c139Smbalmer err = usbd_close_pipe(sc->sc_bulkout_pipe);
3052c06c139Smbalmer if (err)
3062c06c139Smbalmer printf("%s: close tx pipe failed: %s\n",
3072c06c139Smbalmer sc->sc_dev.dv_xname, usbd_errstr(err));
3082c06c139Smbalmer sc->sc_bulkout_pipe = NULL;
3092c06c139Smbalmer }
3102c06c139Smbalmer
3112c06c139Smbalmer /* Unregister the clock with the kernel */
3122c06c139Smbalmer sensordev_deinstall(&sc->sc_sensordev);
3132c06c139Smbalmer
3142c06c139Smbalmer return 0;
3152c06c139Smbalmer }
3162c06c139Smbalmer
3172c06c139Smbalmer void
umbg_intr(void * xsc)3182c06c139Smbalmer umbg_intr(void *xsc)
3192c06c139Smbalmer {
3202c06c139Smbalmer struct umbg_softc *sc = xsc;
3212c06c139Smbalmer usb_add_task(sc->sc_udev, &sc->sc_task);
3222c06c139Smbalmer }
3232c06c139Smbalmer
3242c06c139Smbalmer /* umbg_task_hr() read a high resolution timestamp from the device. */
3252c06c139Smbalmer void
umbg_task(void * arg)3262c06c139Smbalmer umbg_task(void *arg)
3272c06c139Smbalmer {
3282c06c139Smbalmer struct umbg_softc *sc = (struct umbg_softc *)arg;
3292c06c139Smbalmer struct mbg_time_hr tframe;
3302c06c139Smbalmer struct timespec tstamp;
3312c06c139Smbalmer int64_t tlocal, trecv;
3322c06c139Smbalmer int signal;
3332c06c139Smbalmer
3347b043b62Sjakemsr if (usbd_is_dying(sc->sc_udev))
3352c06c139Smbalmer return;
3362c06c139Smbalmer
3372c06c139Smbalmer if (umbg_read(sc, MBG_GET_TIME_HR, (char *)&tframe, sizeof(tframe),
3382c06c139Smbalmer &tstamp)) {
3392c06c139Smbalmer sc->sc_signal.status = SENSOR_S_CRIT;
3402c06c139Smbalmer goto bail_out;
3412c06c139Smbalmer }
3422c06c139Smbalmer if (tframe.status & MBG_INVALID) {
3432c06c139Smbalmer sc->sc_signal.status = SENSOR_S_CRIT;
3442c06c139Smbalmer goto bail_out;
3452c06c139Smbalmer }
3462c06c139Smbalmer
3472c06c139Smbalmer tlocal = tstamp.tv_sec * NSECPERSEC + tstamp.tv_nsec;
348fede6f61Smbalmer trecv = letoh32(tframe.sec) * NSECPERSEC +
3492c06c139Smbalmer (letoh32(tframe.frac) * NSECPERSEC >> 32);
3502c06c139Smbalmer
3512c06c139Smbalmer sc->sc_timedelta.value = tlocal - trecv;
3522c06c139Smbalmer if (sc->sc_timedelta.status == SENSOR_S_UNKNOWN ||
3532c06c139Smbalmer !(letoh16(tframe.status) & MBG_FREERUN)) {
3542c06c139Smbalmer sc->sc_timedelta.status = SENSOR_S_OK;
355e15e1c8cSblambert timeout_add_sec(&sc->sc_it_to, t_trust);
3562c06c139Smbalmer }
3572c06c139Smbalmer
3582c06c139Smbalmer sc->sc_timedelta.tv.tv_sec = tstamp.tv_sec;
3592c06c139Smbalmer sc->sc_timedelta.tv.tv_usec = tstamp.tv_nsec / 1000;
3602c06c139Smbalmer
3612c06c139Smbalmer signal = tframe.signal - MBG_SIG_BIAS;
3622c06c139Smbalmer if (signal < 0)
3632c06c139Smbalmer signal = 0;
3642c06c139Smbalmer else if (signal > MBG_SIG_MAX)
3652c06c139Smbalmer signal = MBG_SIG_MAX;
3662c06c139Smbalmer
3672c06c139Smbalmer sc->sc_signal.value = signal * 100000 / MBG_SIG_MAX;
3682c06c139Smbalmer sc->sc_signal.status = letoh16(tframe.status) & MBG_FREERUN ?
3692c06c139Smbalmer SENSOR_S_WARN : SENSOR_S_OK;
3702c06c139Smbalmer sc->sc_signal.tv.tv_sec = sc->sc_timedelta.tv.tv_sec;
3712c06c139Smbalmer sc->sc_signal.tv.tv_usec = sc->sc_timedelta.tv.tv_usec;
3722c06c139Smbalmer
3732c06c139Smbalmer bail_out:
374e15e1c8cSblambert timeout_add_sec(&sc->sc_to, t_wait);
3752c06c139Smbalmer
3762c06c139Smbalmer }
3772c06c139Smbalmer
3782c06c139Smbalmer /* send a command and read back results */
3792c06c139Smbalmer int
umbg_read(struct umbg_softc * sc,u_int8_t cmd,char * buf,size_t len,struct timespec * tstamp)3802c06c139Smbalmer umbg_read(struct umbg_softc *sc, u_int8_t cmd, char *buf, size_t len,
3812c06c139Smbalmer struct timespec *tstamp)
3822c06c139Smbalmer {
3832c06c139Smbalmer usbd_status err;
384ab0b1be7Smglocker struct usbd_xfer *xfer;
3852c06c139Smbalmer
3862c06c139Smbalmer xfer = usbd_alloc_xfer(sc->sc_udev);
3872c06c139Smbalmer if (xfer == NULL) {
3882c06c139Smbalmer DPRINTF(("%s: alloc xfer failed\n", sc->sc_dev.dv_xname));
3892c06c139Smbalmer return -1;
3902c06c139Smbalmer }
3912c06c139Smbalmer
3922c06c139Smbalmer usbd_setup_xfer(xfer, sc->sc_bulkout_pipe, NULL, &cmd, sizeof(cmd),
393aa88c704Smpi USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS, USBD_DEFAULT_TIMEOUT, NULL);
3942c06c139Smbalmer if (tstamp)
3952c06c139Smbalmer nanotime(tstamp);
396aa88c704Smpi err = usbd_transfer(xfer);
3972c06c139Smbalmer if (err) {
3982c06c139Smbalmer DPRINTF(("%s: sending of command failed: %s\n",
3992c06c139Smbalmer sc->sc_dev.dv_xname, usbd_errstr(err)));
4002c06c139Smbalmer usbd_free_xfer(xfer);
4012c06c139Smbalmer return -1;
4022c06c139Smbalmer }
4032c06c139Smbalmer
4042c06c139Smbalmer usbd_setup_xfer(xfer, sc->sc_bulkin_pipe, NULL, buf, len,
405aa88c704Smpi USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS, USBD_DEFAULT_TIMEOUT, NULL);
4062c06c139Smbalmer
407aa88c704Smpi err = usbd_transfer(xfer);
4082c06c139Smbalmer usbd_free_xfer(xfer);
4092c06c139Smbalmer if (err) {
4102c06c139Smbalmer DPRINTF(("%s: reading data failed: %s\n",
4112c06c139Smbalmer sc->sc_dev.dv_xname, usbd_errstr(err)));
4122c06c139Smbalmer return -1;
4132c06c139Smbalmer }
4142c06c139Smbalmer return 0;
4152c06c139Smbalmer }
4162c06c139Smbalmer
4172c06c139Smbalmer void
umbg_it_intr(void * xsc)4182c06c139Smbalmer umbg_it_intr(void *xsc)
4192c06c139Smbalmer {
4202c06c139Smbalmer struct umbg_softc *sc = xsc;
4212c06c139Smbalmer
4227b043b62Sjakemsr if (usbd_is_dying(sc->sc_udev))
4232c06c139Smbalmer return;
4242c06c139Smbalmer
4252c06c139Smbalmer if (sc->sc_timedelta.status == SENSOR_S_OK) {
4262c06c139Smbalmer sc->sc_timedelta.status = SENSOR_S_WARN;
4272c06c139Smbalmer /*
4282c06c139Smbalmer * further degrade in TRUSTTIME seconds if the clocks remains
4292c06c139Smbalmer * free running.
4302c06c139Smbalmer */
431e15e1c8cSblambert timeout_add_sec(&sc->sc_it_to, t_trust);
4322c06c139Smbalmer } else
4332c06c139Smbalmer sc->sc_timedelta.status = SENSOR_S_CRIT;
4342c06c139Smbalmer }
435