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
This commit is contained in:
parent
3f27092854
commit
95e1f0d684
@ -111,7 +111,8 @@ hid_clear_local(struct hid_item *c)
|
|||||||
|
|
||||||
c->loc.count = 0;
|
c->loc.count = 0;
|
||||||
c->loc.size = 0;
|
c->loc.size = 0;
|
||||||
c->usage = 0;
|
c->nusages = 0;
|
||||||
|
memset(c->usages, 0, sizeof(c->usages));
|
||||||
c->usage_minimum = 0;
|
c->usage_minimum = 0;
|
||||||
c->usage_maximum = 0;
|
c->usage_maximum = 0;
|
||||||
c->designator_index = 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");
|
DPRINTFN(1, "Using last usage\n");
|
||||||
dval = s->usage_last;
|
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 ++;
|
s->icount ++;
|
||||||
/*
|
/*
|
||||||
* Only copy HID item, increment position and return
|
* 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->collection = dval;
|
||||||
c->collevel++;
|
c->collevel++;
|
||||||
c->usage = s->usage_last;
|
c->usage = s->usage_last;
|
||||||
|
c->nusages = 1;
|
||||||
*h = *c;
|
*h = *c;
|
||||||
return (1);
|
return (1);
|
||||||
case 11: /* Feature */
|
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_data *d;
|
||||||
struct hid_item h;
|
struct hid_item h;
|
||||||
|
int i;
|
||||||
|
|
||||||
for (d = hid_start_parse(desc, size, 1 << k); hid_get_item(d, &h);) {
|
for (d = hid_start_parse(desc, size, 1 << k); hid_get_item(d, &h);) {
|
||||||
if (h.kind == k && h.usage == u) {
|
for (i = 0; i < h.nusages; i++) {
|
||||||
if (index--)
|
if (h.kind == k && h.usages[i] == u) {
|
||||||
continue;
|
if (index--)
|
||||||
if (loc != NULL)
|
break;
|
||||||
*loc = h.loc;
|
if (loc != NULL)
|
||||||
if (flags != NULL)
|
*loc = h.loc;
|
||||||
*flags = h.flags;
|
if (flags != NULL)
|
||||||
if (id != NULL)
|
*flags = h.flags;
|
||||||
*id = h.report_ID;
|
if (id != NULL)
|
||||||
hid_end_parse(d);
|
*id = h.report_ID;
|
||||||
return (1);
|
hid_end_parse(d);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (loc != NULL)
|
if (loc != NULL)
|
||||||
|
@ -208,6 +208,8 @@ struct usb_hid_descriptor {
|
|||||||
#if defined(_KERNEL) || defined(_STANDALONE)
|
#if defined(_KERNEL) || defined(_STANDALONE)
|
||||||
struct usb_config_descriptor;
|
struct usb_config_descriptor;
|
||||||
|
|
||||||
|
#define HID_ITEM_MAXUSAGE 4
|
||||||
|
|
||||||
enum hid_kind {
|
enum hid_kind {
|
||||||
hid_input, hid_output, hid_feature, hid_collection, hid_endcollection
|
hid_input, hid_output, hid_feature, hid_collection, hid_endcollection
|
||||||
};
|
};
|
||||||
@ -229,7 +231,11 @@ struct hid_item {
|
|||||||
int32_t unit;
|
int32_t unit;
|
||||||
int32_t report_ID;
|
int32_t report_ID;
|
||||||
/* Local */
|
/* Local */
|
||||||
int32_t usage;
|
int nusages;
|
||||||
|
union {
|
||||||
|
int32_t usage;
|
||||||
|
int32_t usages[HID_ITEM_MAXUSAGE];
|
||||||
|
};
|
||||||
int32_t usage_minimum;
|
int32_t usage_minimum;
|
||||||
int32_t usage_maximum;
|
int32_t usage_maximum;
|
||||||
int32_t designator_index;
|
int32_t designator_index;
|
||||||
|
Loading…
Reference in New Issue
Block a user