Some UPSes contain HID report descriptors that fail to correctly
describe the contents of reports.  For example, the OpenUPS
descriptor fails to set the units, logical maximum and logical
minimum before the corresponding `main item' as required by the HID
specification.

This commit allows an override HID report descriptor to be given to
usbhid-ups which replaces the one produced by the UPS, allowing the
report descriptors to be properly parsed.

With an appropriately fixed report descriptor, OpenUPS reports correct
battery current (+ve for charging, -ve for discharging.)
---
 drivers/usbhid-ups.c | 40 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/drivers/usbhid-ups.c b/drivers/usbhid-ups.c
index 954fa54..5a4d6db 100644
--- a/drivers/usbhid-ups.c
+++ b/drivers/usbhid-ups.c
@@ -748,6 +748,8 @@ void upsdrv_makevartable(void)
 #else
        addvar(VAR_VALUE, "notification", "Set notification type, (ignored, 
only for backward compatibility)");
 #endif
+
+       addvar(VAR_VALUE, "hid_descriptor", "Replacement HID descriptor file");
 }
 
 #define        MAX_EVENT_NUM   32
@@ -1093,16 +1095,52 @@ static void process_boolean_info(const char *nutvalue)
 static int callback(hid_dev_handle_t udev, HIDDevice_t *hd, unsigned char 
*rdbuf, int rdlen)
 {
        int i;
-       const char *mfr = NULL, *model = NULL, *serial = NULL;
+       const char *mfr = NULL, *model = NULL, *serial = NULL, *descfile;
 #ifndef SHUT_MODE
        int ret;
 #endif
        upsdebugx(2, "Report Descriptor size = %d", rdlen);
        upsdebug_hex(3, "Report Descriptor", rdbuf, rdlen);
 
+       /* Check whether we have an override descriptor */
+       descfile = getval("hid_descriptor");
+       if (descfile) {
+               unsigned char *buf;
+               size_t size;
+               FILE *f;
+
+               f = fopen(descfile, "r");
+               if (!f) {
+                       upslog_with_errno(LOG_ERR, "Can't open %s", descfile);
+                       return 0;
+               }
+
+               fseek(f, 0, SEEK_END);
+               size = ftell(f);
+
+               fseek(f, 0, SEEK_SET);
+
+               buf = xmalloc(size);
+
+               if (fread(buf, size, 1, f) != 1) {
+                       upslog_with_errno(LOG_CRIT, "Short read of %s", 
descfile);
+                       fclose(f);
+                       free(buf);
+                       return 0;
+               }
+               fclose(f);
+
+               rdbuf = buf;
+               rdlen = size;
+       }
+
        /* Parse Report Descriptor */
        Free_ReportDesc(pDesc);
        pDesc = Parse_ReportDesc(rdbuf, rdlen);
+
+       if (descfile)
+               free(rdbuf);
+
        if (!pDesc) {
                upsdebug_with_errno(1, "Failed to parse report descriptor!");
                return 0;
-- 
2.7.4


-- 
Russell King

_______________________________________________
Nut-upsdev mailing list
Nut-upsdev@lists.alioth.debian.org
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/nut-upsdev

Reply via email to