1 /* $OpenBSD: usps.c,v 1.1 2011/09/16 15:48:19 yuo Exp $ */ 2 3 /* 4 * Copyright (c) 2011 Yojiro UO <yuo@nui.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 DISCAIMS 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 /* Driver for usb smart power strip FX-5204PS */ 20 21 #include <sys/param.h> 22 #include <sys/proc.h> 23 #include <sys/systm.h> 24 #include <sys/kernel.h> 25 #include <sys/malloc.h> 26 #include <sys/device.h> 27 #include <sys/conf.h> 28 #include <sys/sensors.h> 29 30 #include <dev/usb/usb.h> 31 #include <dev/usb/usbdi.h> 32 #include <dev/usb/usbdi_util.h> 33 #include <dev/usb/usbdevs.h> 34 35 #ifdef USB_DEBUG 36 #define USPS_DEBUG 37 #endif 38 39 #ifdef USPS_DEBUG 40 int uspsdebug = 0; 41 #define DPRINTFN(n, x) do { if (uspsdebug > (n)) printf x; } while (0) 42 #else 43 #define DPRINTFN(n, x) 44 #endif 45 46 #define DPRINTF(x) DPRINTFN(0, x) 47 48 #define USPS_UPDATE_TICK 1 /* sec */ 49 #define USPS_TIMEOUT 1000 /* ms */ 50 #define USPS_INTR_TICKS 50 /* ms */ 51 52 /* protocol */ 53 #define USPS_CMD_START 0x01 54 #define USPS_CMD_VALUE 0x20 55 #define USPS_CMD_GET_FIRMWARE 0xc0 56 #define USPS_CMD_GET_SERIAL 0xc1 57 #define USPS_CMD_GET_VOLTAGE 0xb0 58 #define USPS_CMD_GET_TEMP 0xb4 59 #define USPS_CMD_GET_FREQ 0xa1 60 #define USPS_CMD_GET_UNK0 0xa2 61 62 #define USPS_MODE_WATTAGE 0x10 63 #define USPS_MODE_CURRENT 0x30 64 65 #define FX5204_NUM_PORTS 4 66 67 struct usps_port_sensor { 68 struct ksensor ave; 69 struct ksensor min; 70 struct ksensor max; 71 int vave, vmin, vmax; 72 }; 73 74 struct usps_softc { 75 struct device sc_dev; 76 usbd_device_handle sc_udev; 77 usbd_interface_handle sc_iface; 78 usbd_pipe_handle sc_ipipe; 79 int sc_isize; 80 usbd_xfer_handle sc_xfer; 81 uint8_t sc_buf[16]; 82 uint8_t *sc_intrbuf; 83 84 u_char sc_dying; 85 uint16_t sc_flag; 86 87 /* device info */ 88 uint8_t sc_firmware_version[2]; 89 uint32_t sc_device_serial; 90 91 /* sensor framework */ 92 struct usps_port_sensor sc_port_sensor[FX5204_NUM_PORTS]; 93 struct usps_port_sensor sc_total_sensor; 94 struct ksensor sc_voltage_sensor; 95 struct ksensor sc_frequency_sensor; 96 struct ksensor sc_temp_sensor; 97 struct ksensor sc_serial_sensor; 98 struct ksensordev sc_sensordev; 99 struct sensor_task *sc_sensortask; 100 101 int sc_count; 102 }; 103 104 struct usps_port_pkt { 105 uint8_t header; /* should be 0x80 */ 106 uint16_t seq; 107 uint8_t padding[5]; 108 uint16_t port[4]; 109 } __packed; /* 16 byte length struct */ 110 111 static const struct usb_devno usps_devs[] = { 112 { USB_VENDOR_FUJITSUCOMP, USB_PRODUCT_FUJITSUCOMP_FX5204PS}, 113 }; 114 #define usps_lookup(v, p) usb_lookup(usps_devs, v, p) 115 116 int usps_match(struct device *, void *, void *); 117 void usps_attach(struct device *, struct device *, void *); 118 int usps_detach(struct device *, int); 119 int usps_activate(struct device *, int); 120 void usps_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); 121 122 usbd_status usps_cmd(struct usps_softc *, uint8_t, uint16_t, uint16_t); 123 usbd_status usps_set_measurement_mode(struct usps_softc *, int); 124 125 void usps_get_device_info(struct usps_softc *); 126 void usps_refresh(void *); 127 void usps_refresh_temp(struct usps_softc *); 128 void usps_refresh_power(struct usps_softc *); 129 void usps_refresh_ports(struct usps_softc *); 130 131 struct cfdriver usps_cd = { 132 NULL, "usps", DV_DULL 133 }; 134 135 const struct cfattach usps_ca = { 136 sizeof(struct usps_softc), 137 usps_match, 138 usps_attach, 139 usps_detach, 140 usps_activate, 141 }; 142 143 int 144 usps_match(struct device *parent, void *match, void *aux) 145 { 146 struct usb_attach_arg *uaa = aux; 147 148 if (uaa->iface != NULL) 149 return UMATCH_NONE; 150 151 if (usps_lookup(uaa->vendor, uaa->product) == NULL) 152 return UMATCH_NONE; 153 154 return (UMATCH_VENDOR_PRODUCT); 155 } 156 157 void 158 usps_attach(struct device *parent, struct device *self, void *aux) 159 { 160 struct usps_softc *sc = (struct usps_softc *)self; 161 struct usb_attach_arg *uaa = aux; 162 usb_interface_descriptor_t *id; 163 usb_endpoint_descriptor_t *ed; 164 int ep_ibulk, ep_obulk, ep_intr; 165 usbd_status err; 166 int i; 167 168 sc->sc_udev = uaa->device; 169 170 #define USPS_USB_IFACE 0 171 #define USPS_USB_CONFIG 1 172 173 /* set configuration */ 174 if ((err = usbd_set_config_no(sc->sc_udev, USPS_USB_CONFIG, 0)) != 0){ 175 printf("%s: failed to set config %d: %s\n", 176 sc->sc_dev.dv_xname, USPS_USB_CONFIG, usbd_errstr(err)); 177 return; 178 } 179 180 /* get interface handle */ 181 if ((err = usbd_device2interface_handle(sc->sc_udev, USPS_USB_IFACE, 182 &sc->sc_iface)) != 0) { 183 printf("%s: failed to get interface %d: %s\n", 184 sc->sc_dev.dv_xname, USPS_USB_IFACE, usbd_errstr(err)); 185 return; 186 } 187 188 /* find endpoints */ 189 ep_ibulk = ep_obulk = ep_intr = -1; 190 id = usbd_get_interface_descriptor(sc->sc_iface); 191 for (i = 0; i < id->bNumEndpoints; i++) { 192 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 193 if (ed == NULL) { 194 printf("%s: failed to get endpoint %d descriptor\n", 195 sc->sc_dev.dv_xname, i); 196 return; 197 } 198 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 199 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) 200 ep_ibulk = ed->bEndpointAddress; 201 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 202 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) 203 ep_obulk = ed->bEndpointAddress; 204 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 205 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT){ 206 ep_intr = ed->bEndpointAddress; 207 sc->sc_isize = UGETW(ed->wMaxPacketSize); 208 } 209 } 210 211 if (ep_intr == -1) { 212 printf("%s: no data endpoint found\n", sc->sc_dev.dv_xname); 213 return; 214 } 215 216 usps_get_device_info(sc); 217 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 218 sizeof(sc->sc_sensordev.xname)); 219 220 /* attach sensor */ 221 sc->sc_voltage_sensor.type = SENSOR_VOLTS_AC; 222 sc->sc_frequency_sensor.type = SENSOR_FREQ; 223 sc->sc_temp_sensor.type = SENSOR_TEMP; 224 sc->sc_serial_sensor.type = SENSOR_INTEGER; 225 sensor_attach(&sc->sc_sensordev, &sc->sc_voltage_sensor); 226 sensor_attach(&sc->sc_sensordev, &sc->sc_frequency_sensor); 227 sensor_attach(&sc->sc_sensordev, &sc->sc_temp_sensor); 228 sensor_attach(&sc->sc_sensordev, &sc->sc_serial_sensor); 229 230 sc->sc_serial_sensor.value = sc->sc_device_serial; 231 strlcpy(sc->sc_serial_sensor.desc, "unit serial#", 232 sizeof(sc->sc_serial_sensor.desc)); 233 234 /* 235 * XXX: the device has mode of par port sensor, Watt of Ampair. 236 * currently only watt mode is selected. 237 */ 238 usps_set_measurement_mode(sc, USPS_MODE_WATTAGE); 239 for (i = 0; i < FX5204_NUM_PORTS; i++) { 240 sc->sc_port_sensor[i].ave.type = SENSOR_WATTS; 241 sc->sc_port_sensor[i].min.type = SENSOR_WATTS; 242 sc->sc_port_sensor[i].max.type = SENSOR_WATTS; 243 sensor_attach(&sc->sc_sensordev, &sc->sc_port_sensor[i].ave); 244 sensor_attach(&sc->sc_sensordev, &sc->sc_port_sensor[i].min); 245 sensor_attach(&sc->sc_sensordev, &sc->sc_port_sensor[i].max); 246 (void)snprintf(sc->sc_port_sensor[i].ave.desc, 247 sizeof(sc->sc_port_sensor[i].ave.desc), 248 "port#%d (average)", i); 249 (void)snprintf(sc->sc_port_sensor[i].min.desc, 250 sizeof(sc->sc_port_sensor[i].min.desc), 251 "port#%d (min)", i); 252 (void)snprintf(sc->sc_port_sensor[i].max.desc, 253 sizeof(sc->sc_port_sensor[i].max.desc), 254 "port#%d (max)", i); 255 } 256 257 sc->sc_total_sensor.ave.type = SENSOR_WATTS; 258 sc->sc_total_sensor.min.type = SENSOR_WATTS; 259 sc->sc_total_sensor.max.type = SENSOR_WATTS; 260 sensor_attach(&sc->sc_sensordev, &sc->sc_total_sensor.ave); 261 sensor_attach(&sc->sc_sensordev, &sc->sc_total_sensor.min); 262 sensor_attach(&sc->sc_sensordev, &sc->sc_total_sensor.max); 263 (void)snprintf(sc->sc_total_sensor.ave.desc, 264 sizeof(sc->sc_total_sensor.ave.desc), "total (average)", i); 265 (void)snprintf(sc->sc_total_sensor.min.desc, 266 sizeof(sc->sc_total_sensor.ave.desc), "total (min)", i); 267 (void)snprintf(sc->sc_total_sensor.max.desc, 268 sizeof(sc->sc_total_sensor.ave.desc), "total (max)", i); 269 270 sc->sc_sensortask = sensor_task_register(sc, usps_refresh, 271 USPS_UPDATE_TICK); 272 if (sc->sc_sensortask == NULL) { 273 printf(", unable to register update task\n"); 274 goto fail; 275 } 276 277 printf("%s: device#=%d, firmware version=V%02dL%02d\n", 278 sc->sc_dev.dv_xname, sc->sc_device_serial, 279 sc->sc_firmware_version[0], 280 sc->sc_firmware_version[1]); 281 282 sensordev_install(&sc->sc_sensordev); 283 284 /* open interrupt endpoint */ 285 sc->sc_intrbuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); 286 if (sc->sc_intrbuf == NULL) 287 goto fail; 288 err = usbd_open_pipe_intr(sc->sc_iface, ep_intr, 289 USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_intrbuf, 290 sc->sc_isize, usps_intr, USPS_INTR_TICKS); 291 if (err) { 292 printf("%s: could not open intr pipe %s\n", 293 sc->sc_dev.dv_xname, usbd_errstr(err)); 294 goto fail; 295 } 296 297 DPRINTF(("usps_attach: complete\n")); 298 return; 299 300 fail: 301 if (sc->sc_ipipe != NULL) 302 usbd_close_pipe(sc->sc_ipipe); 303 if (sc->sc_xfer != NULL) 304 usbd_free_xfer(sc->sc_xfer); 305 if (sc->sc_intrbuf != NULL) 306 free(sc->sc_intrbuf, M_USBDEV); 307 } 308 309 int 310 usps_detach(struct device *self, int flags) 311 { 312 struct usps_softc *sc = (struct usps_softc *)self; 313 int i, rv = 0, s; 314 315 sc->sc_dying = 1; 316 317 s = splusb(); 318 if (sc->sc_ipipe != NULL) { 319 usbd_abort_pipe(sc->sc_ipipe); 320 usbd_close_pipe(sc->sc_ipipe); 321 if (sc->sc_intrbuf != NULL) 322 free(sc->sc_intrbuf, M_USBDEV); 323 sc->sc_ipipe = NULL; 324 } 325 if (sc->sc_xfer != NULL) 326 usbd_free_xfer(sc->sc_xfer); 327 splx(s); 328 329 wakeup(&sc->sc_sensortask); 330 sensordev_deinstall(&sc->sc_sensordev); 331 sensor_detach(&sc->sc_sensordev, &sc->sc_voltage_sensor); 332 sensor_detach(&sc->sc_sensordev, &sc->sc_frequency_sensor); 333 sensor_detach(&sc->sc_sensordev, &sc->sc_temp_sensor); 334 sensor_detach(&sc->sc_sensordev, &sc->sc_serial_sensor); 335 for (i = 0; i < FX5204_NUM_PORTS; i++) { 336 sensor_detach(&sc->sc_sensordev, &sc->sc_port_sensor[i].ave); 337 sensor_detach(&sc->sc_sensordev, &sc->sc_port_sensor[i].min); 338 sensor_detach(&sc->sc_sensordev, &sc->sc_port_sensor[i].max); 339 } 340 sensor_detach(&sc->sc_sensordev, &sc->sc_total_sensor.ave); 341 sensor_detach(&sc->sc_sensordev, &sc->sc_total_sensor.min); 342 sensor_detach(&sc->sc_sensordev, &sc->sc_total_sensor.max); 343 344 if (sc->sc_sensortask != NULL) 345 sensor_task_unregister(sc->sc_sensortask); 346 347 return (rv); 348 } 349 350 int 351 usps_activate(struct device *self, int act) 352 { 353 struct usps_softc *sc = (struct usps_softc *)self; 354 355 switch (act) { 356 case DVACT_DEACTIVATE: 357 sc->sc_dying = 1; 358 break; 359 } 360 return (0); 361 } 362 363 usbd_status 364 usps_cmd(struct usps_softc *sc, uint8_t cmd, uint16_t val, uint16_t len) 365 { 366 usb_device_request_t req; 367 usbd_status err; 368 369 req.bmRequestType = UT_READ_VENDOR_DEVICE; 370 req.bRequest = cmd; 371 USETW(req.wValue, val); 372 USETW(req.wIndex, 0); 373 USETW(req.wLength, len); 374 375 err = usbd_do_request(sc->sc_udev, &req, &sc->sc_buf); 376 if (err) { 377 printf("%s: could not issue sensor cmd: %s\n", 378 sc->sc_dev.dv_xname, usbd_errstr(err)); 379 return (EIO); 380 } 381 382 return (0); 383 } 384 385 usbd_status 386 usps_set_measurement_mode(struct usps_softc *sc, int mode) 387 { 388 usb_device_request_t req; 389 usbd_status err; 390 391 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 392 req.bRequest = USPS_CMD_START; 393 USETW(req.wValue, 0); 394 USETW(req.wIndex, 0); 395 USETW(req.wLength, 0); 396 397 err = usbd_do_request(sc->sc_udev, &req, &sc->sc_buf); 398 if (err) { 399 printf("%s: fail to set sensor mode: %s\n", 400 sc->sc_dev.dv_xname, usbd_errstr(err)); 401 return (EIO); 402 } 403 404 req.bRequest = USPS_CMD_VALUE; 405 USETW(req.wValue, mode); 406 407 err = usbd_do_request(sc->sc_udev, &req, &sc->sc_buf); 408 if (err) { 409 printf("%s: could not set sensor mode: %s\n", 410 sc->sc_dev.dv_xname, usbd_errstr(err)); 411 return (EIO); 412 } 413 414 return (0); 415 } 416 417 void 418 usps_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) 419 { 420 struct usps_softc *sc = priv; 421 struct usps_port_pkt *pkt; 422 struct usps_port_sensor *ps; 423 int i, total; 424 425 if (sc->sc_dying) 426 return; 427 428 if (status != USBD_NORMAL_COMPLETION) { 429 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 430 return; 431 if (status == USBD_STALLED) 432 usbd_clear_endpoint_stall_async(sc->sc_ipipe); 433 return; 434 } 435 436 /* process intr packet */ 437 if (sc->sc_intrbuf == NULL) 438 return; 439 440 pkt = (struct usps_port_pkt *)sc->sc_intrbuf; 441 442 total = 0; 443 for (i = 0; i < FX5204_NUM_PORTS; i++) { 444 ps = &sc->sc_port_sensor[i]; 445 if (sc->sc_count == 0) 446 ps->vmax = ps->vmin = pkt->port[i]; 447 if (pkt->port[i] > ps->vmax) 448 ps->vmax = pkt->port[i]; 449 if (pkt->port[i] < ps->vmin) 450 ps->vmin = pkt->port[i]; 451 ps->vave = 452 (ps->vave * sc->sc_count + pkt->port[i])/(sc->sc_count +1); 453 total += pkt->port[i]; 454 } 455 456 /* calculate ports total */ 457 ps = &sc->sc_total_sensor; 458 if (sc->sc_count == 0) 459 ps->vmax = ps->vmin = total; 460 if (total > ps->vmax) 461 ps->vmax = total; 462 if (total < ps->vmin) 463 ps->vmin = total; 464 ps->vave = (ps->vave * sc->sc_count + total)/(sc->sc_count +1); 465 466 sc->sc_count++; 467 } 468 469 void 470 usps_get_device_info(struct usps_softc *sc) 471 { 472 int serial; 473 474 /* get Firmware version */ 475 usps_cmd(sc, USPS_CMD_GET_FIRMWARE, 0, 2); 476 sc->sc_firmware_version[0] = 477 (sc->sc_buf[0]>>4) * 10 + (sc->sc_buf[0] & 0xf); 478 sc->sc_firmware_version[1] = 479 (sc->sc_buf[1]>>4) * 10 + (sc->sc_buf[1] & 0xf); 480 481 /* get device serial number */ 482 usps_cmd(sc, USPS_CMD_GET_SERIAL, 0, 3); 483 484 serial = 0; 485 serial += ((sc->sc_buf[0]>>4) * 10 + (sc->sc_buf[0] & 0xf)) * 10000; 486 serial += ((sc->sc_buf[1]>>4) * 10 + (sc->sc_buf[1] & 0xf)) * 100; 487 serial += ((sc->sc_buf[2]>>4) * 10 + (sc->sc_buf[2] & 0xf)); 488 sc->sc_device_serial = serial; 489 } 490 491 void 492 usps_refresh(void *arg) 493 { 494 struct usps_softc *sc = arg; 495 496 usps_refresh_temp(sc); 497 usps_refresh_power(sc); 498 usps_refresh_ports(sc); 499 } 500 501 void 502 usps_refresh_ports(struct usps_softc *sc) 503 { 504 int i; 505 struct usps_port_sensor *ps; 506 507 /* update port values */ 508 for (i = 0; i < FX5204_NUM_PORTS; i++) { 509 ps = &sc->sc_port_sensor[i]; 510 ps->ave.value = ps->vave * 1000000; 511 ps->min.value = ps->vmin * 1000000; 512 ps->max.value = ps->vmax * 1000000; 513 } 514 515 /* update total value */ 516 ps = &sc->sc_total_sensor; 517 ps->ave.value = ps->vave * 1000000; 518 ps->min.value = ps->vmin * 1000000; 519 ps->max.value = ps->vmax * 1000000; 520 521 sc->sc_count = 0; 522 } 523 524 void 525 usps_refresh_temp(struct usps_softc *sc) 526 { 527 int temp; 528 529 if (usps_cmd(sc, USPS_CMD_GET_TEMP, 0, 2) != 0) { 530 DPRINTF(("%s: temperature data read error\n", 531 sc->sc_dev.dv_xname)); 532 sc->sc_temp_sensor.flags |= SENSOR_FINVALID; 533 return; 534 } 535 temp = (sc->sc_buf[1] << 8) + sc->sc_buf[0]; 536 sc->sc_temp_sensor.value = (temp * 10000) + 273150000; 537 sc->sc_temp_sensor.flags &= ~SENSOR_FINVALID; 538 } 539 540 void 541 usps_refresh_power(struct usps_softc *sc) 542 { 543 int v; 544 uint val; 545 uint64_t f; 546 547 /* update source voltage */ 548 if (usps_cmd(sc, USPS_CMD_GET_VOLTAGE, 0, 1) != 0) { 549 DPRINTF(("%s: voltage data read error\n", sc->sc_dev.dv_xname)); 550 sc->sc_voltage_sensor.flags |= SENSOR_FINVALID; 551 return; 552 } 553 554 v = sc->sc_buf[0] * 1000000; 555 sc->sc_voltage_sensor.value = v; 556 sc->sc_voltage_sensor.flags &= ~SENSOR_FINVALID; 557 558 /* update source frequency */ 559 if (usps_cmd(sc, USPS_CMD_GET_FREQ, 0, 8) != 0) { 560 DPRINTF(("%s: frequency data read error\n", 561 sc->sc_dev.dv_xname)); 562 sc->sc_frequency_sensor.flags |= SENSOR_FINVALID; 563 return; 564 } 565 566 if (sc->sc_buf[7] == 0 && sc->sc_buf[6] == 0) { 567 /* special case */ 568 f = 0; 569 } else { 570 val = (sc->sc_buf[1] << 8) + sc->sc_buf[0]; 571 if (val == 0) { 572 /* guard against "division by zero" */ 573 sc->sc_frequency_sensor.flags |= SENSOR_FINVALID; 574 return; 575 } 576 f = 2000000L; 577 f *= 1000000L; 578 f /= val; 579 } 580 581 sc->sc_frequency_sensor.value = f; 582 sc->sc_frequency_sensor.flags &= ~SENSOR_FINVALID; 583 } 584