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