The branch main has been updated by wulf:

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

commit 95e1f0d6847060f9c7d90b6b7655b64029929efd
Author:     Vladimir Kondratyev <vladi...@kondratyev.su>
AuthorDate: 2020-12-24 11:46:24 +0000
Commit:     Vladimir Kondratyev <w...@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;
_______________________________________________
dev-commits-src-main@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
To unsubscribe, send any mail to "dev-commits-src-main-unsubscr...@freebsd.org"

Reply via email to