Skip to content

Commit ea38f65

Browse files
authored
libusb: fix HID Report descriptor request (signal11#444)
- pass the actual HID Report descriptor size (from HID descriptor); - interface_num has to be wIndex, and not as part of wValue for LIBUSB_DT_REPORT request;
1 parent 7793462 commit ea38f65

File tree

1 file changed

+71
-7
lines changed

1 file changed

+71
-7
lines changed

libusb/hid.c

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ struct hid_device_ {
151151
/* The interface number of the HID */
152152
int interface;
153153

154+
uint16_t report_descriptor_size;
155+
154156
/* Endpoint information */
155157
int input_endpoint;
156158
int output_endpoint;
@@ -565,13 +567,18 @@ int HID_API_EXPORT hid_exit(void)
565567
/**
566568
* Requires an opened device with *claimed interface*.
567569
*/
568-
static void fill_device_info_usage(struct hid_device_info *cur_dev, libusb_device_handle *handle, int interface_num)
570+
static void fill_device_info_usage(struct hid_device_info *cur_dev, libusb_device_handle *handle, int interface_num, uint16_t report_descriptor_size)
569571
{
570572
unsigned char data[4096];
571573
unsigned short page = 0, usage = 0;
572574

573-
/* Get the HID Report Descriptor. */
574-
int res = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8)|interface_num, 0, data, sizeof(data), 5000);
575+
if (report_descriptor_size > 4096)
576+
report_descriptor_size = 4096;
577+
578+
/* Get the HID Report Descriptor.
579+
See USB HID Specificatin, sectin 7.1.1
580+
*/
581+
int res = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8), interface_num, data, report_descriptor_size, 5000);
575582
if (res >= 0) {
576583
/* Parse the usage and usage page
577584
out of the report descriptor. */
@@ -585,7 +592,7 @@ static void fill_device_info_usage(struct hid_device_info *cur_dev, libusb_devic
585592
}
586593

587594
#ifdef INVASIVE_GET_USAGE
588-
static void invasive_fill_device_info_usage(struct hid_device_info *cur_dev, libusb_device_handle *handle, int interface_num)
595+
static void invasive_fill_device_info_usage(struct hid_device_info *cur_dev, libusb_device_handle *handle, int interface_num, uint16_t report_descriptor_size)
589596
{
590597
int res = 0;
591598

@@ -604,7 +611,7 @@ static void invasive_fill_device_info_usage(struct hid_device_info *cur_dev, lib
604611

605612
res = libusb_claim_interface(handle, interface_num);
606613
if (res >= 0) {
607-
fill_device_info_usage(cur_dev, handle, interface_num);
614+
fill_device_info_usage(cur_dev, handle, interface_num, report_descriptor_size);
608615

609616
/* Release the interface */
610617
res = libusb_release_interface(handle, interface_num);
@@ -662,6 +669,59 @@ static struct hid_device_info * create_device_info_for_device(libusb_device *dev
662669
return cur_dev;
663670
}
664671

672+
static uint16_t get_report_descriptor_size_from_interface_descriptors(const struct libusb_interface_descriptor *intf_desc)
673+
{
674+
int i = 0;
675+
int found_hid_report_descriptor = 0;
676+
uint16_t result = 4096;
677+
const unsigned char *extra = intf_desc->extra;
678+
int extra_length = intf_desc->extra_length;
679+
680+
/*
681+
"extra" contains a HID descriptor
682+
See section 6.2.1 of HID 1.1 specification.
683+
*/
684+
685+
while (extra_length >= 2) { /* Descriptor header: bLength/bDescriptorType */
686+
if (extra[1] == LIBUSB_DT_HID) { /* bDescriptorType */
687+
if (extra_length < 6) {
688+
LOG("Broken HID descriptor: not enough data\n");
689+
break;
690+
}
691+
unsigned char bNumDescriptors = extra[5];
692+
if (extra_length < (6 + 3 * bNumDescriptors)) {
693+
LOG("Broken HID descriptor: not enough data for Report metadata\n");
694+
break;
695+
}
696+
for (i = 0; i < bNumDescriptors; i++) {
697+
if (extra[6 + 3 * i] == LIBUSB_DT_REPORT) {
698+
result = (uint16_t)extra[6 + 3 * i + 2] << 8 | extra[6 + 3 * i + 1];
699+
found_hid_report_descriptor = 1;
700+
break;
701+
}
702+
}
703+
704+
if (!found_hid_report_descriptor) {
705+
/* We expect to find exactly 1 HID descriptor (LIBUSB_DT_HID)
706+
which should contain exactly one HID Report Descriptor metadata (LIBUSB_DT_REPORT). */
707+
LOG("Broken HID descriptor: missing Report descriptor\n");
708+
}
709+
break;
710+
}
711+
712+
if (extra[0] == 0) { /* bLength */
713+
LOG("Broken HID Interface descriptors: zero-sized descriptor\n");
714+
break;
715+
}
716+
717+
/* Iterate over to the next Descriptor */
718+
extra_length -= extra[0];
719+
extra += extra[0];
720+
}
721+
722+
return result;
723+
}
724+
665725
struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
666726
{
667727
libusb_device **devs;
@@ -741,7 +801,9 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
741801
field in the hid_device_info struct to distinguish
742802
between interfaces. */
743803
if (handle) {
744-
invasive_fill_device_info_usage(tmp, handle, intf_desc->bInterfaceNumber);
804+
uint16_t report_descriptor_size = get_report_descriptor_size_from_interface_descriptors(intf_desc);
805+
806+
invasive_fill_device_info_usage(tmp, handle, intf_desc->bInterfaceNumber, report_descriptor_size);
745807
}
746808
#endif /* INVASIVE_GET_USAGE */
747809

@@ -1004,6 +1066,8 @@ static int hidapi_initialize_device(hid_device *dev, int config_number, const st
10041066
dev->config_number = config_number;
10051067
dev->interface = intf_desc->bInterfaceNumber;
10061068

1069+
dev->report_descriptor_size = get_report_descriptor_size_from_interface_descriptors(intf_desc);
1070+
10071071
dev->input_endpoint = 0;
10081072
dev->input_ep_max_packet_size = 0;
10091073
dev->output_endpoint = 0;
@@ -1522,7 +1586,7 @@ HID_API_EXPORT struct hid_device_info *HID_API_CALL hid_get_device_info(hid_devi
15221586
// device error already set by create_device_info_for_device, if any
15231587

15241588
if (dev->device_info) {
1525-
fill_device_info_usage(dev->device_info, dev->device_handle, dev->interface);
1589+
fill_device_info_usage(dev->device_info, dev->device_handle, dev->interface, dev->report_descriptor_size);
15261590
}
15271591
}
15281592

0 commit comments

Comments
 (0)