Skip to content

Commit fe758f9

Browse files
author
Stephen
committed
Properly determine libusb read size for large reports
Fixes libusb#274
1 parent 0ab6c14 commit fe758f9

File tree

1 file changed

+80
-1
lines changed

1 file changed

+80
-1
lines changed

libusb/hid.c

+80-1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ struct hid_device_ {
9595
int interface;
9696

9797
uint16_t report_descriptor_size;
98+
/* Includes report number. */
99+
size_t max_input_report_size;
98100

99101
/* Endpoint information */
100102
int input_endpoint;
@@ -135,6 +137,7 @@ static libusb_context *usb_context = NULL;
135137

136138
uint16_t get_usb_code_for_current_locale(void);
137139
static int return_data(hid_device *dev, unsigned char *data, size_t length);
140+
static int hid_get_report_descriptor_libusb(libusb_device_handle *handle, int interface_num, uint16_t expected_report_descriptor_size, unsigned char *buf, size_t buf_size);
138141

139142
static hid_device *new_hid_device(void)
140143
{
@@ -276,6 +279,74 @@ static int get_usage(uint8_t *report_descriptor, size_t size,
276279
return -1; /* failure */
277280
}
278281

282+
/* Retrieves the largest input report size (in bytes) from the report descriptor.
283+
284+
Requires an opened device with *claimed interface*.
285+
286+
The return value is the size on success and -1 on failure. */
287+
static size_t get_max_input_report_size(libusb_device_handle *handle, int interface_num, uint16_t expected_report_descriptor_size)
288+
{
289+
int i = 0;
290+
int size_code;
291+
int data_len, key_size;
292+
293+
int64_t report_size = 0, report_count = 0;
294+
ssize_t max_size = -1;
295+
296+
unsigned char report_descriptor[HID_API_MAX_REPORT_DESCRIPTOR_SIZE];
297+
298+
int desc_size = hid_get_report_descriptor_libusb(handle, interface_num, expected_report_descriptor_size, report_descriptor, sizeof(report_descriptor));
299+
if (desc_size < 0) {
300+
return -1;
301+
}
302+
303+
while (i < desc_size) {
304+
int key = report_descriptor[i];
305+
int key_cmd = key & 0xfc;
306+
307+
if ((key & 0xf0) == 0xf0) {
308+
/* This is a Long Item. The next byte contains the
309+
length of the data section (value) for this key.
310+
See the HID specification, version 1.11, section
311+
6.2.2.3, titled "Long Items." */
312+
if (i+1 < desc_size)
313+
data_len = report_descriptor[i+1];
314+
else
315+
data_len = 0; /* malformed report */
316+
key_size = 3;
317+
} else {
318+
/* This is a Short Item. The bottom two bits of the
319+
key contain the size code for the data section
320+
(value) for this key. Refer to the HID
321+
specification, version 1.11, section 6.2.2.2,
322+
titled "Short Items." */
323+
size_code = key & 0x3;
324+
data_len = (size_code < 3) ? size_code : 4;
325+
key_size = 1;
326+
}
327+
328+
if (key_cmd == 0x94) {
329+
report_count = get_bytes(report_descriptor, desc_size, data_len, i);
330+
}
331+
if (key_cmd == 0x74) {
332+
report_size = get_bytes(report_descriptor, desc_size, data_len, i);
333+
}
334+
if (key_cmd == 0x80) { // Input
335+
/* report_size is in bits. Determine the total size (count * size),
336+
convert to bytes (rounded up), and add one byte for the report
337+
number. */
338+
ssize_t size = (((report_count * report_size) + 7) / 8) + 1;
339+
if (size > max_size)
340+
max_size = size;
341+
}
342+
343+
/* Skip over this key and it's associated data */
344+
i += data_len + key_size;
345+
}
346+
347+
return max_size;
348+
}
349+
279350
#if defined(__FreeBSD__) && __FreeBSD__ < 10
280351
/* The libusb version included in FreeBSD < 10 doesn't have this function. In
281352
mainline libusb, it's inlined in libusb.h. This function will bear a striking
@@ -1024,7 +1095,14 @@ static void *read_thread(void *param)
10241095
int res;
10251096
hid_device *dev = param;
10261097
uint8_t *buf;
1027-
const size_t length = dev->input_ep_max_packet_size;
1098+
size_t length;
1099+
if (dev->max_input_report_size > 0) {
1100+
length = dev->max_input_report_size;
1101+
} else {
1102+
/* If we were unable to reliably determine the maximum input size, fall back
1103+
to the max packet size. */
1104+
length = dev->input_ep_max_packet_size;
1105+
}
10281106

10291107
/* Set up the transfer object. */
10301108
buf = (uint8_t*) malloc(length);
@@ -1216,6 +1294,7 @@ static int hidapi_initialize_device(hid_device *dev, const struct libusb_interfa
12161294
dev->interface = intf_desc->bInterfaceNumber;
12171295

12181296
dev->report_descriptor_size = get_report_descriptor_size_from_interface_descriptors(intf_desc);
1297+
dev->max_input_report_size = get_max_input_report_size(dev->device_handle, dev->interface, dev->report_descriptor_size);
12191298

12201299
dev->input_endpoint = 0;
12211300
dev->input_ep_max_packet_size = 0;

0 commit comments

Comments
 (0)