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