Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 7 Jan 2021 23:20:51 GMT
From:      Vladimir Kondratyev <wulf@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 95e1f0d68470 - main - Allow HID report descriptor parser to return more then 1 usage per item
Message-ID:  <202101072320.107NKpQM063442@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by wulf:

URL: https://cgit.FreeBSD.org/src/commit/?id=95e1f0d6847060f9c7d90b6b7655b64029929efd

commit 95e1f0d6847060f9c7d90b6b7655b64029929efd
Author:     Vladimir Kondratyev <vladimir@kondratyev.su>
AuthorDate: 2020-12-24 11:46:24 +0000
Commit:     Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2021-01-07 23:18:41 +0000

    Allow HID report descriptor parser to return more then 1 usage per item
    
    This handles parsing of following descriptor, containing array of
    usages:
    
    0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
    0x09, 0x80,        // Usage (Sys Control)
    0xA1, 0x01,        // Collection (Application)
    0x75, 0x02,        //   Report Size (2)
    0x95, 0x01,        //   Report Count (1)
    0x15, 0x01,        //   Logical Minimum (1)
    0x25, 0x03,        //   Logical Maximum (3)
    0x09, 0x82,        //   Usage (Sys Sleep)
    0x09, 0x81,        //   Usage (Sys Power Down)
    0x09, 0x83,        //   Usage (Sys Wake Up)
    0x81, 0x60,        //   Input (Data,Array,Abs)
    0x75, 0x06,        //   Report Size (6)
    0x81, 0x03,        //   Input (Const,Var,Abs)
    0xC0,              // End Collection
    
    Our current parser returns only first usage (Sys Sleep) and loses next
    two. Set HID_ITEM_MAXUSAGE limit relatively low as existing code
    usually allocates hid_item on stack.
    
    Also tweak hid_locate() to support hid items with multiple usages.
    
    Reviewed by:    hselasky
    Differential Revision:  https://reviews.freebsd.org/D27748
---
 sys/dev/usb/usb_hid.c | 39 +++++++++++++++++++++++++++------------
 sys/dev/usb/usbhid.h  |  8 +++++++-
 2 files changed, 34 insertions(+), 13 deletions(-)

diff --git a/sys/dev/usb/usb_hid.c b/sys/dev/usb/usb_hid.c
index dd0c8d4b42ac..22e5fb5446c3 100644
--- a/sys/dev/usb/usb_hid.c
+++ b/sys/dev/usb/usb_hid.c
@@ -111,7 +111,8 @@ hid_clear_local(struct hid_item *c)
 
 	c->loc.count = 0;
 	c->loc.size = 0;
-	c->usage = 0;
+	c->nusages = 0;
+	memset(c->usages, 0, sizeof(c->usages));
 	c->usage_minimum = 0;
 	c->usage_maximum = 0;
 	c->designator_index = 0;
@@ -273,6 +274,16 @@ hid_get_item(struct hid_data *s, struct hid_item *h)
 			DPRINTFN(1, "Using last usage\n");
 			dval = s->usage_last;
 		}
+		c->nusages = 1;
+		/* array type HID item may have multiple usages */
+		while ((c->flags & HIO_VARIABLE) == 0 && s->ousage == 0 &&
+		    s->iusage < s->nusage && c->nusages < HID_ITEM_MAXUSAGE)
+			c->usages[c->nusages++] = s->usages_min[s->iusage++];
+		if ((c->flags & HIO_VARIABLE) == 0 && s->ousage == 0 &&
+		    s->iusage < s->nusage)
+			DPRINTFN(0, "HID_ITEM_MAXUSAGE should be increased "
+			    "up to %hhu to parse the HID report descriptor\n",
+			    s->nusage);
 		s->icount ++;
 		/* 
 		 * Only copy HID item, increment position and return
@@ -381,6 +392,7 @@ hid_get_item(struct hid_data *s, struct hid_item *h)
 				c->collection = dval;
 				c->collevel++;
 				c->usage = s->usage_last;
+				c->nusages = 1;
 				*h = *c;
 				return (1);
 			case 11:	/* Feature */
@@ -620,19 +632,22 @@ hid_locate(const void *desc, usb_size_t size, int32_t u, enum hid_kind k,
 {
 	struct hid_data *d;
 	struct hid_item h;
+	int i;
 
 	for (d = hid_start_parse(desc, size, 1 << k); hid_get_item(d, &h);) {
-		if (h.kind == k && h.usage == u) {
-			if (index--)
-				continue;
-			if (loc != NULL)
-				*loc = h.loc;
-			if (flags != NULL)
-				*flags = h.flags;
-			if (id != NULL)
-				*id = h.report_ID;
-			hid_end_parse(d);
-			return (1);
+		for (i = 0; i < h.nusages; i++) {
+			if (h.kind == k && h.usages[i] == u) {
+				if (index--)
+					break;
+				if (loc != NULL)
+					*loc = h.loc;
+				if (flags != NULL)
+					*flags = h.flags;
+				if (id != NULL)
+					*id = h.report_ID;
+				hid_end_parse(d);
+				return (1);
+			}
 		}
 	}
 	if (loc != NULL)
diff --git a/sys/dev/usb/usbhid.h b/sys/dev/usb/usbhid.h
index 30949ea9a62a..926c404dca55 100644
--- a/sys/dev/usb/usbhid.h
+++ b/sys/dev/usb/usbhid.h
@@ -208,6 +208,8 @@ struct usb_hid_descriptor {
 #if defined(_KERNEL) || defined(_STANDALONE)
 struct usb_config_descriptor;
 
+#define	HID_ITEM_MAXUSAGE	4
+
 enum hid_kind {
 	hid_input, hid_output, hid_feature, hid_collection, hid_endcollection
 };
@@ -229,7 +231,11 @@ struct hid_item {
 	int32_t	unit;
 	int32_t	report_ID;
 	/* Local */
-	int32_t	usage;
+	int	nusages;
+	union {
+		int32_t	usage;
+		int32_t usages[HID_ITEM_MAXUSAGE];
+	};
 	int32_t	usage_minimum;
 	int32_t	usage_maximum;
 	int32_t	designator_index;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202101072320.107NKpQM063442>