4 * Generic USB module for libusb.
8 * Copyright (C) 2005 Adam Kropelin
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU General
12 * Public License as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this program; if not, write to the Free
21 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26 #include "../usb_common.h"
32 * When we are traversing the USB reports given by the UPS and we find
33 * an entry corresponding to an entry in the known_info table above,
34 * we make the following USB_INFO entry in the info table of our
37 typedef struct s_usb_info
{
38 unsigned usage_code
; /* usage code wanted */
39 unsigned unit_exponent
; /* exponent */
40 unsigned unit
; /* units */
41 int data_type
; /* data type */
42 hid_item_t item
; /* HID item (for read) */
43 hid_item_t witem
; /* HID item (for write) */
44 int report_len
; /* Length of containing report */
45 int ci
; /* which CI does this usage represent? */
46 int value
; /* Previous value of this item */
50 * This "private" structure is returned to us in the driver private
51 * field, and allows us to get to all the info we keep on each UPS.
52 * The info field is malloced for each command we want and the UPS
55 typedef struct s_usb_data
{
56 usb_dev_handle
*fd
; /* Our UPS control pipe fd when open */
57 report_desc_t rdesc
; /* Device's report descrptor */
58 USB_INFO
*info
[CI_MAXCI
+ 1]; /* Info pointers for each command */
61 int pusb_ups_get_capabilities(UPSINFO
*ups
, const struct s_known_info
*known_info
)
63 int i
, input
, feature
, ci
, phys
, logi
;
64 USB_DATA
*my_data
= (USB_DATA
*)ups
->driver_internal_data
;
65 hid_item_t input_item
, feature_item
, item
;
70 for (i
= 0; known_info
[i
].usage_code
; i
++) {
71 ci
= known_info
[i
].ci
;
72 phys
= known_info
[i
].physical
;
73 logi
= known_info
[i
].logical
;
75 if (ci
!= CI_NONE
&& !my_data
->info
[ci
]) {
77 /* Try to find an INPUT report containing this usage */
78 input
= hidu_locate_item(
80 known_info
[i
].usage_code
, /* Match usage code */
81 -1, /* Don't care about application */
82 (phys
== P_ANY
) ? -1 : phys
, /* Match physical usage */
83 (logi
== P_ANY
) ? -1 : logi
, /* Match logical usage */
84 HID_KIND_INPUT
, /* Match feature type */
87 /* Try to find a FEATURE report containing this usage */
88 feature
= hidu_locate_item(
90 known_info
[i
].usage_code
, /* Match usage code */
91 -1, /* Don't care about application */
92 (phys
== P_ANY
) ? -1 : phys
, /* Match physical usage */
93 (logi
== P_ANY
) ? -1 : logi
, /* Match logical usage */
94 HID_KIND_FEATURE
, /* Match feature type */
98 * Choose which report to use. We prefer FEATURE since some UPSes
99 * have broken INPUT reports, but we will fall back on INPUT if
100 * FEATURE is not available.
107 continue; // No valid report, bail
109 ups
->UPS_Cap
[ci
] = true;
110 ups
->UPS_Cmd
[ci
] = known_info
[i
].usage_code
;
112 info
= (USB_INFO
*)malloc(sizeof(USB_INFO
));
115 Error_abort0("Out of memory.\n");
118 // Populate READ report data
119 my_data
->info
[ci
] = info
;
120 memset(info
, 0, sizeof(*info
));
122 info
->usage_code
= item
.usage
;
123 info
->unit_exponent
= item
.unit_exponent
;
124 info
->unit
= item
.unit
;
125 info
->data_type
= known_info
[i
].data_type
;
127 info
->report_len
= hid_report_size( /* +1 for report id */
128 my_data
->rdesc
, item
.kind
, item
.report_ID
) + 1;
129 Dmsg6(200, "Got READ ci=%d, rpt=%d (len=%d), usage=0x%x (len=%d), kind=0x%02x\n",
130 ci
, item
.report_ID
, info
->report_len
,
131 known_info
[i
].usage_code
, item
.report_size
, item
.kind
);
133 // If we have a FEATURE report, use that as the writable report
136 Dmsg6(200, "Got WRITE ci=%d, rpt=%d (len=%d), usage=0x%x (len=%d), kind=0x%02x\n",
137 ci
, item
.report_ID
, info
->report_len
,
138 known_info
[i
].usage_code
, item
.report_size
, item
.kind
);
143 ups
->UPS_Cap
[CI_STATUS
] = true; /* we always have status flag */
148 static bool populate_uval(UPSINFO
*ups
, USB_INFO
*info
, unsigned char *data
, USB_VALUE
*uval
)
150 USB_DATA
*my_data
= (USB_DATA
*)ups
->driver_internal_data
;
155 /* data+1 skips the report tag byte */
156 info
->value
= hid_get_data(data
+1, &info
->item
);
158 exponent
= info
->unit_exponent
;
160 exponent
= exponent
- 16;
162 if (info
->data_type
== T_INDEX
) { /* get string */
163 if (info
->value
== 0)
166 str
= hidu_get_string(my_data
->fd
, info
->value
);
170 astrncpy(val
.sValue
, str
, sizeof(val
.sValue
));
171 val
.value_type
= V_STRING
;
173 Dmsg4(200, "Def val=%d exp=%d sVal=\"%s\" ci=%d\n", info
->value
,
174 exponent
, val
.sValue
, info
->ci
);
175 } else if (info
->data_type
== T_UNITS
) {
176 val
.value_type
= V_DOUBLE
;
178 switch (info
->unit
) {
180 val
.UnitName
= "Volts";
181 exponent
-= 7; /* remove bias */
184 exponent
+= 2; /* remove bias */
185 val
.UnitName
= "Amps";
188 val
.UnitName
= "Hertz";
191 val
.UnitName
= "Seconds";
194 exponent
-= 7; /* remove bias */
195 val
.UnitName
= "Watts";
198 val
.UnitName
= "Degrees K";
201 val
.UnitName
= "AmpSecs";
203 val
.dValue
= info
->value
;
205 val
.dValue
= ((double)info
->value
) * pow_ten(exponent
);
209 val
.value_type
= V_INTEGER
;
210 val
.iValue
= info
->value
;
215 val
.dValue
= info
->value
;
217 val
.dValue
= ((double)info
->value
) * pow_ten(exponent
);
219 // Store a (possibly truncated) copy of the floating point value in the
220 // integer field as well.
221 val
.iValue
= (int)val
.dValue
;
223 Dmsg4(200, "Def val=%d exp=%d dVal=%f ci=%d\n", info
->value
,
224 exponent
, val
.dValue
, info
->ci
);
225 } else { /* should be T_NONE */
228 val
.value_type
= V_INTEGER
;
229 val
.iValue
= info
->value
;
232 val
.dValue
= info
->value
;
234 val
.dValue
= ((double)info
->value
) * pow_ten(exponent
);
236 Dmsg4(200, "Def val=%d exp=%d dVal=%f ci=%d\n", info
->value
,
237 exponent
, val
.dValue
, info
->ci
);
240 memcpy(uval
, &val
, sizeof(*uval
));
247 int pusb_get_value(UPSINFO
*ups
, int ci
, USB_VALUE
*uval
)
249 USB_DATA
*my_data
= (USB_DATA
*)ups
->driver_internal_data
;
250 USB_INFO
*info
= my_data
->info
[ci
];
251 unsigned char data
[20];
255 * Note we need to check info since CI_STATUS is always true
256 * even when the UPS doesn't directly support that CI.
258 if (!UPS_HAS_CAP(ci
) || !info
)
259 return false; /* UPS does not have capability */
262 * Clear the destination buffer. In the case of a short transfer (see
263 * below) this will increase the likelihood of extracting the correct
264 * value in spite of the missing data.
266 memset(data
, 0, sizeof(data
));
268 /* Fetch the proper report */
269 len
= hidu_get_report(my_data
->fd
, &info
->item
, data
, info
->report_len
);
274 * Some UPSes seem to have broken firmware that sends a different number
275 * of bytes (usually fewer) than the report descriptor specifies. On
276 * UHCI controllers under *BSD, this can lead to random lockups. To
277 * reduce the likelihood of a lockup, we adjust our expected length to
278 * match the actual as soon as a mismatch is detected, so future
279 * transfers will have the proper lengths from the outset. NOTE that
280 * the data returned may not be parsed properly (since the parsing is
281 * necessarily based on the report descriptor) but given that HID
282 * reports are in little endian byte order and we cleared the buffer
283 * above, chances are good that we will actually extract the right
284 * value in spite of the UPS's brokenness.
286 if (info
->report_len
!= len
) {
287 Dmsg4(100, "Report length mismatch, fixing "
288 "(id=%d, ci=%d, expected=%d, actual=%d)\n",
289 info
->item
.report_ID
, ci
, info
->report_len
, len
);
290 info
->report_len
= len
;
293 /* Populate a uval struct using the raw report data */
294 return populate_uval(ups
, info
, data
, uval
);
297 static void reinitialize_private_structure(UPSINFO
*ups
)
299 USB_DATA
*my_data
= (USB_DATA
*)ups
->driver_internal_data
;
302 Dmsg0(200, "Reinitializing private structure.\n");
304 * We are being reinitialized, so clear the Cap
305 * array, and release previously allocated memory.
307 for (k
= 0; k
<= CI_MAXCI
; k
++) {
308 ups
->UPS_Cap
[k
] = false;
309 if (my_data
->info
[k
] != NULL
) {
310 free(my_data
->info
[k
]);
311 my_data
->info
[k
] = NULL
;
316 int init_device(UPSINFO
*ups
, struct usb_device
*dev
)
318 USB_DATA
*my_data
= (USB_DATA
*)ups
->driver_internal_data
;
321 unsigned char* rdesc
;
324 /* Open the device with libusb */
327 Dmsg0(100, "Unable to open device.\n");
331 #ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
333 * Attempt to detach the kernel driver so we can drive
334 * this device from userspace. Don't worry if this fails;
335 * that just means the driver was already detached.
337 rc
= usb_detach_kernel_driver_np(fd
, 0);
340 /* Check device serial number, if user specified one */
341 if (ups
->device
[0] != '\0')
343 /* Fetch serial number from device */
345 if (dev
->descriptor
.iSerialNumber
== 0 ||
346 (tmpser
= hidu_get_string(fd
, dev
->descriptor
.iSerialNumber
)) == NULL
)
349 Dmsg0(100, "Device does not report serial number.\n");
353 /* Remove leading/trailing whitespace */
354 astring
serial(tmpser
);
357 /* Check against user specification, ignoring case */
358 Dmsg2(100, "device='%s', user='%s'\n", serial
.str(), ups
->device
);
359 if (strcasecmp(serial
, ups
->device
))
366 /* Choose config #1 */
367 rc
= usb_set_configuration(fd
, 1);
370 Dmsg2(100, "Unable to set configuration (%d) %s.\n", rc
, usb_strerror());
374 /* Claim the interface */
375 rc
= usb_claim_interface(fd
, 0);
378 Dmsg2(100, "Unable to claim interface (%d) %s.\n", rc
, usb_strerror());
382 /* Fetch the report descritor */
383 rdesc
= hidu_fetch_report_descriptor(fd
, &rdesclen
);
386 Dmsg0(100, "Unable to fetch report descriptor.\n");
390 /* Initialize hid parser with this descriptor */
391 my_data
->rdesc
= hid_use_report_desc(rdesc
, rdesclen
);
393 if (!my_data
->rdesc
) {
395 Dmsg0(100, "Unable to init parser with report descriptor.\n");
399 /* Does this device have an UPS application collection? */
400 if (!hidu_locate_item(
402 UPS_USAGE
, /* Match usage code */
403 -1, /* Don't care about application */
404 -1, /* Don't care about physical usage */
405 -1, /* Don't care about logical */
406 HID_KIND_COLLECTION
, /* Match collection type */
408 hid_dispose_report_desc(my_data
->rdesc
);
410 Dmsg0(100, "Device does not have an UPS application collection.\n");
418 int open_usb_device(UPSINFO
*ups
)
422 struct usb_device
* dev
;
424 /* Initialize libusb */
425 Dmsg0(200, "Initializing libusb\n");
428 /* Enumerate usb busses and devices */
429 i
= usb_find_busses();
430 Dmsg1(200, "Found %d USB busses\n", i
);
431 i
= usb_find_devices();
432 Dmsg1(200, "Found %d USB devices\n", i
);
434 /* Iterate over all devices, checking for idVendor=APC */
435 bus
= usb_get_busses();
441 Dmsg4(200, "%s:%s - %04x:%04x\n",
442 bus
->dirname
, dev
->filename
,
443 dev
->descriptor
.idVendor
, dev
->descriptor
.idProduct
);
445 if (dev
->descriptor
.idVendor
== VENDOR_APC
) {
446 Dmsg2(200, "Trying device %s:%s\n", bus
->dirname
, dev
->filename
);
447 if (init_device(ups
, dev
)) {
448 /* Successfully found and initialized an UPS */
459 /* Failed to find an UPS */
464 * Called if there is an ioctl() or read() error, we close() and
465 * re open() the port since the device was probably unplugged.
467 static int usb_link_check(UPSINFO
*ups
)
469 bool comm_err
= true;
472 USB_DATA
*my_data
= (USB_DATA
*)ups
->driver_internal_data
;
473 static bool linkcheck
= false;
478 linkcheck
= true; /* prevent recursion */
481 Dmsg0(200, "link_check comm lost\n");
483 /* Don't warn until we try to get it at least 2 times and fail */
484 for (tlog
= LINK_RETRY_INTERVAL
* 2; comm_err
; tlog
-= (LINK_RETRY_INTERVAL
)) {
487 tlog
= 10 * 60; /* notify every 10 minutes */
488 log_event(ups
, event_msg
[CMDCOMMFAILURE
].level
,
489 event_msg
[CMDCOMMFAILURE
].msg
);
490 if (once
) { /* execute script once */
491 execute_command(ups
, ups_event
[CMDCOMMFAILURE
]);
496 /* Retry every LINK_RETRY_INTERVAL seconds */
497 sleep(LINK_RETRY_INTERVAL
);
500 usb_reset(my_data
->fd
);
501 usb_close(my_data
->fd
);
503 hid_dispose_report_desc(my_data
->rdesc
);
504 reinitialize_private_structure(ups
);
507 if (open_usb_device(ups
) && usb_ups_get_capabilities(ups
) &&
508 usb_ups_read_static_data(ups
)) {
516 generate_event(ups
, CMDCOMMOK
);
517 ups
->clear_commlost();
518 Dmsg0(200, "link check comm OK.\n");
526 * libusb-win32, pthreads, and compat.h all have different ideas
527 * of what ETIMEDOUT is on mingw. We need to make sure we match
528 * libusb-win32's error.h in that case, so override ETIMEDOUT.
531 # define LIBUSB_ETIMEDOUT 116
533 # define LIBUSB_ETIMEDOUT ETIMEDOUT
536 int pusb_ups_check_state(UPSINFO
*ups
)
540 unsigned char buf
[20];
541 USB_DATA
*my_data
= (USB_DATA
*)ups
->driver_internal_data
;
542 struct timeval now
, exit
;
547 /* Figure out when we need to exit by */
548 gettimeofday(&exit
, NULL
);
549 exit
.tv_sec
+= ups
->wait_time
;
553 /* Figure out how long until we have to exit */
554 gettimeofday(&now
, NULL
);
555 timeout
= TV_DIFF_MS(now
, exit
);
557 /* Done already? How time flies... */
561 Dmsg1(200, "Timeout=%d\n", timeout
);
562 retval
= usb_interrupt_read(my_data
->fd
, USB_ENDPOINT_IN
|1, (char*)buf
, sizeof(buf
), timeout
);
564 if (retval
== 0 || retval
== -LIBUSB_ETIMEDOUT
) {
565 /* No events available in ups->wait_time seconds. */
567 } else if (retval
== -EINTR
|| retval
== -EAGAIN
) {
570 } else if (retval
< 0) {
572 Dmsg2(200, "usb_interrupt_read error: (%d) %s\n", retval
, strerror(-retval
));
573 usb_link_check(ups
); /* link is down, wait */
577 if (debug_level
>= 300) {
578 logf("Interrupt data: ");
579 for (i
= 0; i
< retval
; i
++)
580 logf("%02x, ", buf
[i
]);
587 * Iterate over all CIs, firing off events for any that are
588 * affected by this report.
590 for (ci
=0; ci
<CI_MAXCI
; ci
++) {
591 if (ups
->UPS_Cap
[ci
] && my_data
->info
[ci
] &&
592 my_data
->info
[ci
]->item
.report_ID
== buf
[0]) {
595 * Check if we received fewer bytes of data from the UPS than we
596 * should have. If so, ignore the report since we can't process it
597 * reliably. If we go ahead and try to process it we may get
598 * sporradic bad readings. UPSes we've seen this issue on so far
601 * "Back-UPS CS 650 FW:817.v7 .I USB FW:v7"
602 * "Back-UPS CS 500 FW:808.q8.I USB FW:q8"
604 if (my_data
->info
[ci
]->report_len
!= retval
) {
605 Dmsg4(100, "Report length mismatch, ignoring "
606 "(id=%d, ci=%d, expected=%d, actual=%d)\n",
607 my_data
->info
[ci
]->item
.report_ID
, ci
,
608 my_data
->info
[ci
]->report_len
, retval
);
609 break; /* don't continue since other CIs will be just as wrong */
612 /* Ignore this event if the value has not changed */
613 value
= hid_get_data(buf
+1, &my_data
->info
[ci
]->item
);
614 if (my_data
->info
[ci
]->value
== value
) {
615 Dmsg3(200, "Ignoring unchanged value (ci=%d, rpt=%d, val=%d)\n",
620 Dmsg3(200, "Processing changed value (ci=%d, rpt=%d, val=%d)\n",
623 /* Populate a uval and report it to the upper layer */
624 populate_uval(ups
, my_data
->info
[ci
], buf
, &uval
);
625 if (usb_report_event(ups
, ci
, &uval
)) {
627 * The upper layer considers this an important event,
628 * so we will return after processing any remaining
629 * CIs for this report.
645 * This is called once by the core code and is the first
648 int pusb_ups_open(UPSINFO
*ups
)
650 USB_DATA
*my_data
= (USB_DATA
*)ups
->driver_internal_data
;
652 /* Set libusb debug level */
653 usb_set_debug(debug_level
/100);
656 if (my_data
== NULL
) {
657 my_data
= (USB_DATA
*)malloc(sizeof(USB_DATA
));
658 if (my_data
== NULL
) {
659 log_event(ups
, LOG_ERR
, "Out of memory.");
664 memset(my_data
, 0, sizeof(USB_DATA
));
665 ups
->driver_internal_data
= my_data
;
667 reinitialize_private_structure(ups
);
670 if (!open_usb_device(ups
)) {
672 Error_abort0("Cannot find UPS device --\n"
673 "For a link to detailed USB trouble shooting information,\n"
674 "please see <http://www.apcupsd.com/support.html>.\n");
678 * Note, we set ups->fd here so the "core" of apcupsd doesn't
679 * think we are a slave, which is what happens when it is -1.
680 * (ADK: Actually this only appears to be true for apctest as
681 * apcupsd proper uses the UPS_slave flag.)
682 * Internally, we use the fd in our own private space
691 int pusb_ups_close(UPSINFO
*ups
)
693 /* Should we be politely closing fds here or anything? */
696 if (ups
->driver_internal_data
) {
697 free(ups
->driver_internal_data
);
698 ups
->driver_internal_data
= NULL
;
705 int pusb_ups_setup(UPSINFO
*ups
)
711 int pusb_read_int_from_ups(UPSINFO
*ups
, int ci
, int *value
)
715 if (!pusb_get_value(ups
, ci
, &val
))
722 int pusb_write_int_to_ups(UPSINFO
*ups
, int ci
, int value
, const char *name
)
724 USB_DATA
*my_data
= (USB_DATA
*)ups
->driver_internal_data
;
726 int old_value
, new_value
;
727 unsigned char rpt
[20];
729 if (ups
->UPS_Cap
[ci
] && my_data
->info
[ci
] && my_data
->info
[ci
]->witem
.report_ID
) {
730 info
= my_data
->info
[ci
]; /* point to our info structure */
732 if (hidu_get_report(my_data
->fd
, &info
->item
, rpt
, info
->report_len
) < 1) {
733 Dmsg1(000, "get_report for kill power function %s failed.\n", name
);
737 old_value
= hid_get_data(rpt
+ 1, &info
->item
);
739 hid_set_data(rpt
+ 1, &info
->witem
, value
);
741 if (!hidu_set_report(my_data
->fd
, &info
->witem
, rpt
, info
->report_len
)) {
742 Dmsg1(000, "set_report for kill power function %s failed.\n", name
);
746 if (hidu_get_report(my_data
->fd
, &info
->item
, rpt
, info
->report_len
) < 1) {
747 Dmsg1(000, "get_report for kill power function %s failed.\n", name
);
751 new_value
= hid_get_data(rpt
+ 1, &info
->item
);
753 Dmsg3(100, "function %s ci=%d value=%d OK.\n", name
, ci
, value
);
754 Dmsg4(100, "%s before=%d set=%d after=%d\n", name
, old_value
, value
, new_value
);
758 Dmsg2(000, "function %s ci=%d not available in this UPS.\n", name
, ci
);