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