[Nut-upsdev] [PATCH 2/3] Add generic facility to override HID report descriptor in usbhid-ups

Russell King rmk at armlinux.org.uk
Sun Feb 4 00:19:40 UTC 2018


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



More information about the Nut-upsdev mailing list