1 /* $OpenBSD: umbg.c,v 1.17 2011/07/03 15:47:17 matthew Exp $ */ 2 3 /* 4 * Copyright (c) 2007 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/syslog.h> 30 #include <sys/time.h> 31 #include <sys/sensors.h> 32 33 #include <dev/usb/usb.h> 34 #include <dev/usb/usbdi.h> 35 #include <dev/usb/usbdi_util.h> 36 #include <dev/usb/usbdevs.h> 37 38 #ifdef UMBG_DEBUG 39 #define DPRINTFN(n, x) do { if (umbgdebug > (n)) printf x; } while (0) 40 int umbgdebug = 0; 41 #else 42 #define DPRINTFN(n, x) 43 #endif 44 #define DPRINTF(x) DPRINTFN(0, x) 45 46 #ifdef UMBG_DEBUG 47 #define TRUSTTIME ((long) 60) 48 #else 49 #define TRUSTTIME ((long) 12 * 60 * 60) /* degrade OK > WARN > CRIT */ 50 #endif 51 52 struct umbg_softc { 53 struct device sc_dev; /* base device */ 54 usbd_device_handle sc_udev; /* USB device */ 55 usbd_interface_handle sc_iface; /* data interface */ 56 57 int sc_bulkin_no; 58 usbd_pipe_handle sc_bulkin_pipe; 59 int sc_bulkout_no; 60 usbd_pipe_handle sc_bulkout_pipe; 61 62 struct timeout sc_to; /* get time from device */ 63 struct usb_task sc_task; 64 65 struct timeout sc_it_to; /* invalidate sensor */ 66 67 usb_device_request_t sc_req; 68 69 struct ksensor sc_timedelta; /* timedelta */ 70 struct ksensor sc_signal; /* signal quality and status */ 71 struct ksensordev sc_sensordev; 72 }; 73 74 struct mbg_time { 75 u_int8_t hundreds; 76 u_int8_t sec; 77 u_int8_t min; 78 u_int8_t hour; 79 u_int8_t mday; 80 u_int8_t wday; /* 1 (monday) - 7 (sunday) */ 81 u_int8_t mon; 82 u_int8_t year; /* 0 - 99 */ 83 u_int8_t status; 84 u_int8_t signal; 85 int8_t utc_off; 86 }; 87 88 struct mbg_time_hr { 89 u_int32_t sec; /* always UTC */ 90 u_int32_t frac; /* fractions of second */ 91 int32_t utc_off; /* informal only, in seconds */ 92 u_int16_t status; 93 u_int8_t signal; 94 }; 95 96 /* mbg_time.status bits */ 97 #define MBG_FREERUN 0x01 /* clock running on xtal */ 98 #define MBG_DST_ENA 0x02 /* DST enabled */ 99 #define MBG_SYNC 0x04 /* clock synced at least once */ 100 #define MBG_DST_CHG 0x08 /* DST change announcement */ 101 #define MBG_UTC 0x10 /* special UTC firmware is installed */ 102 #define MBG_LEAP 0x20 /* announcement of a leap second */ 103 #define MBG_IFTM 0x40 /* current time was set from host */ 104 #define MBG_INVALID 0x80 /* time invalid, batt. was disconn. */ 105 106 /* commands */ 107 #define MBG_GET_TIME 0x00 108 #define MBG_GET_SYNC_TIME 0x02 109 #define MBG_GET_TIME_HR 0x03 110 #define MBG_SET_TIME 0x10 111 #define MBG_GET_TZCODE 0x32 112 #define MBG_SET_TZCODE 0x33 113 #define MBG_GET_FW_ID_1 0x40 114 #define MBG_GET_FW_ID_2 0x41 115 #define MBG_GET_SERNUM 0x42 116 117 /* timezone codes (for MBG_{GET|SET}_TZCODE) */ 118 #define MBG_TZCODE_CET_CEST 0x00 119 #define MBG_TZCODE_CET 0x01 120 #define MBG_TZCODE_UTC 0x02 121 #define MBG_TZCODE_EET_EEST 0x03 122 123 /* misc. constants */ 124 #define MBG_FIFO_LEN 16 125 #define MBG_ID_LEN (2 * MBG_FIFO_LEN + 1) 126 #define MBG_BUSY 0x01 127 #define MBG_SIG_BIAS 55 128 #define MBG_SIG_MAX 68 129 #define NSECPERSEC 1000000000LL /* nanoseconds per second */ 130 #define HRDIVISOR 0x100000000LL /* for hi-res timestamp */ 131 132 static int t_wait, t_trust; 133 134 void umbg_intr(void *); 135 void umbg_it_intr(void *); 136 137 int umbg_match(struct device *, void *, void *); 138 void umbg_attach(struct device *, struct device *, void *); 139 int umbg_detach(struct device *, int); 140 int umbg_activate(struct device *, int); 141 142 void umbg_task(void *); 143 144 int umbg_read(struct umbg_softc *, u_int8_t cmd, char *buf, size_t len, 145 struct timespec *tstamp); 146 147 struct cfdriver umbg_cd = { 148 NULL, "umbg", DV_DULL 149 }; 150 151 const struct cfattach umbg_ca = { 152 sizeof(struct umbg_softc), 153 umbg_match, 154 umbg_attach, 155 umbg_detach, 156 umbg_activate 157 }; 158 159 int 160 umbg_match(struct device *parent, void *match, void *aux) 161 { 162 struct usb_attach_arg *uaa = aux; 163 164 if (uaa->iface != NULL) 165 return UMATCH_NONE; 166 167 return uaa->vendor == USB_VENDOR_MEINBERG && 168 uaa->product == USB_PRODUCT_MEINBERG_USB5131 ? 169 UMATCH_VENDOR_PRODUCT : UMATCH_NONE; 170 } 171 172 void 173 umbg_attach(struct device *parent, struct device *self, void *aux) 174 { 175 struct umbg_softc *sc = (struct umbg_softc *)self; 176 struct usb_attach_arg *uaa = aux; 177 usbd_device_handle dev = uaa->device; 178 usbd_interface_handle iface = uaa->iface; 179 struct mbg_time tframe; 180 usb_endpoint_descriptor_t *ed; 181 usbd_status err; 182 int signal; 183 #ifdef UMBG_DEBUG 184 char fw_id[MBG_ID_LEN]; 185 #endif 186 sc->sc_udev = dev; 187 188 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 189 sizeof(sc->sc_sensordev.xname)); 190 191 sc->sc_timedelta.type = SENSOR_TIMEDELTA; 192 sc->sc_timedelta.status = SENSOR_S_UNKNOWN; 193 strlcpy(sc->sc_timedelta.desc, "USB5131", 194 sizeof(sc->sc_timedelta.desc)); 195 sensor_attach(&sc->sc_sensordev, &sc->sc_timedelta); 196 197 sc->sc_signal.type = SENSOR_PERCENT; 198 strlcpy(sc->sc_signal.desc, "Signal", sizeof(sc->sc_signal.desc)); 199 sensor_attach(&sc->sc_sensordev, &sc->sc_signal); 200 sensordev_install(&sc->sc_sensordev); 201 202 usb_init_task(&sc->sc_task, umbg_task, sc, USB_TASK_TYPE_GENERIC); 203 timeout_set(&sc->sc_to, umbg_intr, sc); 204 timeout_set(&sc->sc_it_to, umbg_it_intr, sc); 205 206 if ((err = usbd_set_config_index(dev, 0, 1))) { 207 printf("%s: failed to set configuration, err=%s\n", 208 sc->sc_dev.dv_xname, usbd_errstr(err)); 209 goto fishy; 210 } 211 212 if ((err = usbd_device2interface_handle(dev, 0, &iface))) { 213 printf("%s: failed to get interface, err=%s\n", 214 sc->sc_dev.dv_xname, usbd_errstr(err)); 215 goto fishy; 216 } 217 218 ed = usbd_interface2endpoint_descriptor(iface, 0); 219 sc->sc_bulkin_no = ed->bEndpointAddress; 220 ed = usbd_interface2endpoint_descriptor(iface, 1); 221 sc->sc_bulkout_no = ed->bEndpointAddress; 222 223 sc->sc_iface = iface; 224 225 err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 226 USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe); 227 if (err) { 228 printf("%s: open rx pipe failed: %s\n", sc->sc_dev.dv_xname, 229 usbd_errstr(err)); 230 goto fishy; 231 } 232 233 err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no, 234 USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe); 235 if (err) { 236 printf("%s: open tx pipe failed: %s\n", sc->sc_dev.dv_xname, 237 usbd_errstr(err)); 238 goto fishy; 239 } 240 241 printf("%s: ", sc->sc_dev.dv_xname); 242 if (umbg_read(sc, MBG_GET_TIME, (char *)&tframe, 243 sizeof(struct mbg_time), NULL)) { 244 sc->sc_signal.status = SENSOR_S_CRIT; 245 printf("unknown status"); 246 } else { 247 sc->sc_signal.status = SENSOR_S_OK; 248 signal = tframe.signal - MBG_SIG_BIAS; 249 if (signal < 0) 250 signal = 0; 251 else if (signal > MBG_SIG_MAX) 252 signal = MBG_SIG_MAX; 253 sc->sc_signal.value = signal; 254 255 if (tframe.status & MBG_SYNC) 256 printf("synchronized"); 257 else 258 printf("not synchronized"); 259 if (tframe.status & MBG_FREERUN) { 260 sc->sc_signal.status = SENSOR_S_WARN; 261 printf(", freerun"); 262 } 263 if (tframe.status & MBG_IFTM) 264 printf(", time set from host"); 265 } 266 #ifdef UMBG_DEBUG 267 if (umbg_read(sc, MBG_GET_FW_ID_1, fw_id, MBG_FIFO_LEN, NULL) || 268 umbg_read(sc, MBG_GET_FW_ID_2, &fw_id[MBG_FIFO_LEN], MBG_FIFO_LEN, 269 NULL)) 270 printf(", firmware unknown"); 271 else { 272 fw_id[MBG_ID_LEN - 1] = '\0'; 273 printf(", firmware %s", fw_id); 274 } 275 #endif 276 printf("\n"); 277 278 t_wait = 5; 279 280 t_trust = TRUSTTIME; 281 282 usb_add_task(sc->sc_udev, &sc->sc_task); 283 return; 284 285 fishy: 286 usbd_deactivate(sc->sc_udev); 287 } 288 289 int 290 umbg_detach(struct device *self, int flags) 291 { 292 struct umbg_softc *sc = (struct umbg_softc *)self; 293 usbd_status err; 294 295 if (timeout_initialized(&sc->sc_to)) 296 timeout_del(&sc->sc_to); 297 if (timeout_initialized(&sc->sc_it_to)) 298 timeout_del(&sc->sc_it_to); 299 300 usb_rem_task(sc->sc_udev, &sc->sc_task); 301 302 if (sc->sc_bulkin_pipe != NULL) { 303 err = usbd_abort_pipe(sc->sc_bulkin_pipe); 304 if (err) 305 printf("%s: abort rx pipe failed: %s\n", 306 sc->sc_dev.dv_xname, usbd_errstr(err)); 307 err = usbd_close_pipe(sc->sc_bulkin_pipe); 308 if (err) 309 printf("%s: close rx pipe failed: %s\n", 310 sc->sc_dev.dv_xname, usbd_errstr(err)); 311 sc->sc_bulkin_pipe = NULL; 312 } 313 if (sc->sc_bulkout_pipe != NULL) { 314 err = usbd_abort_pipe(sc->sc_bulkout_pipe); 315 if (err) 316 printf("%s: abort tx pipe failed: %s\n", 317 sc->sc_dev.dv_xname, usbd_errstr(err)); 318 err = usbd_close_pipe(sc->sc_bulkout_pipe); 319 if (err) 320 printf("%s: close tx pipe failed: %s\n", 321 sc->sc_dev.dv_xname, usbd_errstr(err)); 322 sc->sc_bulkout_pipe = NULL; 323 } 324 325 /* Unregister the clock with the kernel */ 326 sensordev_deinstall(&sc->sc_sensordev); 327 328 return 0; 329 } 330 331 void 332 umbg_intr(void *xsc) 333 { 334 struct umbg_softc *sc = xsc; 335 usb_add_task(sc->sc_udev, &sc->sc_task); 336 } 337 338 /* umbg_task_hr() read a high resolution timestamp from the device. */ 339 void 340 umbg_task(void *arg) 341 { 342 struct umbg_softc *sc = (struct umbg_softc *)arg; 343 struct mbg_time_hr tframe; 344 struct timespec tstamp; 345 int64_t tlocal, trecv; 346 int signal; 347 348 if (usbd_is_dying(sc->sc_udev)) 349 return; 350 351 if (umbg_read(sc, MBG_GET_TIME_HR, (char *)&tframe, sizeof(tframe), 352 &tstamp)) { 353 sc->sc_signal.status = SENSOR_S_CRIT; 354 goto bail_out; 355 } 356 if (tframe.status & MBG_INVALID) { 357 sc->sc_signal.status = SENSOR_S_CRIT; 358 goto bail_out; 359 } 360 361 tlocal = tstamp.tv_sec * NSECPERSEC + tstamp.tv_nsec; 362 trecv = letoh32(tframe.sec) * NSECPERSEC + 363 (letoh32(tframe.frac) * NSECPERSEC >> 32); 364 365 sc->sc_timedelta.value = tlocal - trecv; 366 if (sc->sc_timedelta.status == SENSOR_S_UNKNOWN || 367 !(letoh16(tframe.status) & MBG_FREERUN)) { 368 sc->sc_timedelta.status = SENSOR_S_OK; 369 timeout_add_sec(&sc->sc_it_to, t_trust); 370 } 371 372 sc->sc_timedelta.tv.tv_sec = tstamp.tv_sec; 373 sc->sc_timedelta.tv.tv_usec = tstamp.tv_nsec / 1000; 374 375 signal = tframe.signal - MBG_SIG_BIAS; 376 if (signal < 0) 377 signal = 0; 378 else if (signal > MBG_SIG_MAX) 379 signal = MBG_SIG_MAX; 380 381 sc->sc_signal.value = signal * 100000 / MBG_SIG_MAX; 382 sc->sc_signal.status = letoh16(tframe.status) & MBG_FREERUN ? 383 SENSOR_S_WARN : SENSOR_S_OK; 384 sc->sc_signal.tv.tv_sec = sc->sc_timedelta.tv.tv_sec; 385 sc->sc_signal.tv.tv_usec = sc->sc_timedelta.tv.tv_usec; 386 387 bail_out: 388 timeout_add_sec(&sc->sc_to, t_wait); 389 390 } 391 392 /* send a command and read back results */ 393 int 394 umbg_read(struct umbg_softc *sc, u_int8_t cmd, char *buf, size_t len, 395 struct timespec *tstamp) 396 { 397 usbd_status err; 398 usbd_xfer_handle xfer; 399 400 xfer = usbd_alloc_xfer(sc->sc_udev); 401 if (xfer == NULL) { 402 DPRINTF(("%s: alloc xfer failed\n", sc->sc_dev.dv_xname)); 403 return -1; 404 } 405 406 usbd_setup_xfer(xfer, sc->sc_bulkout_pipe, NULL, &cmd, sizeof(cmd), 407 USBD_SHORT_XFER_OK, USBD_DEFAULT_TIMEOUT, NULL); 408 if (tstamp) 409 nanotime(tstamp); 410 err = usbd_sync_transfer(xfer); 411 if (err) { 412 DPRINTF(("%s: sending of command failed: %s\n", 413 sc->sc_dev.dv_xname, usbd_errstr(err))); 414 usbd_free_xfer(xfer); 415 return -1; 416 } 417 418 usbd_setup_xfer(xfer, sc->sc_bulkin_pipe, NULL, buf, len, 419 USBD_SHORT_XFER_OK, USBD_DEFAULT_TIMEOUT, NULL); 420 421 err = usbd_sync_transfer(xfer); 422 usbd_free_xfer(xfer); 423 if (err) { 424 DPRINTF(("%s: reading data failed: %s\n", 425 sc->sc_dev.dv_xname, usbd_errstr(err))); 426 return -1; 427 } 428 return 0; 429 } 430 431 void 432 umbg_it_intr(void *xsc) 433 { 434 struct umbg_softc *sc = xsc; 435 436 if (usbd_is_dying(sc->sc_udev)) 437 return; 438 439 if (sc->sc_timedelta.status == SENSOR_S_OK) { 440 sc->sc_timedelta.status = SENSOR_S_WARN; 441 /* 442 * further degrade in TRUSTTIME seconds if the clocks remains 443 * free running. 444 */ 445 timeout_add_sec(&sc->sc_it_to, t_trust); 446 } else 447 sc->sc_timedelta.status = SENSOR_S_CRIT; 448 } 449 450 int 451 umbg_activate(struct device *self, int act) 452 { 453 struct umbg_softc *sc = (struct umbg_softc *)self; 454 455 switch (act) { 456 case DVACT_DEACTIVATE: 457 usbd_deactivate(sc->sc_udev); 458 break; 459 } 460 return 0; 461 } 462