Skip to content

Commit 52c6cd9

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

File tree

1 file changed

+80
-1
lines changed

1 file changed

+80
-1
lines changed

libusb/hid.c

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ struct hid_device_ {
9595
int interface;
9696

9797
uint16_t report_descriptor_size;
98+
size_t max_input_size;
9899

99100
/* Endpoint information */
100101
int input_endpoint;
@@ -135,6 +136,7 @@ static libusb_context *usb_context = NULL;
135136

136137
uint16_t get_usb_code_for_current_locale(void);
137138
static int return_data(hid_device *dev, unsigned char *data, size_t length);
139+
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);
138140

139141
static hid_device *new_hid_device(void)
140142
{
@@ -276,6 +278,73 @@ static int get_usage(uint8_t *report_descriptor, size_t size,
276278
return -1; /* failure */
277279
}
278280

281+
/* Retrieves the largest input report size (in bits, count * size) from the
282+
report descriptor. The algorithm is simple, as it just returns the first
283+
Usage and Usage Page that it finds in the descriptor.
284+
285+
Requires an opened device with *claimed interface*.
286+
287+
The return value is the size on success and -1 on failure. */
288+
static size_t get_max_input_size(libusb_device_handle *handle, int interface_num, uint16_t expected_report_descriptor_size)
289+
{
290+
int i = 0;
291+
int size_code;
292+
int data_len, key_size;
293+
294+
int64_t report_size = 0, report_count = 0;
295+
ssize_t max_size = -1;
296+
297+
unsigned char report_descriptor[HID_API_MAX_REPORT_DESCRIPTOR_SIZE];
298+
299+
int desc_size = hid_get_report_descriptor_libusb(handle, interface_num, expected_report_descriptor_size, report_descriptor, sizeof(report_descriptor));
300+
if (desc_size < 0) {
301+
return -1;
302+
}
303+
304+
while (i < desc_size) {
305+
int key = report_descriptor[i];
306+
int key_cmd = key & 0xfc;
307+
308+
if ((key & 0xf0) == 0xf0) {
309+
/* This is a Long Item. The next byte contains the
310+
length of the data section (value) for this key.
311+
See the HID specification, version 1.11, section
312+
6.2.2.3, titled "Long Items." */
313+
if (i+1 < desc_size)
314+
data_len = report_descriptor[i+1];
315+
else
316+
data_len = 0; /* malformed report */
317+
key_size = 3;
318+
} else {
319+
/* This is a Short Item. The bottom two bits of the
320+
key contain the size code for the data section
321+
(value) for this key. Refer to the HID
322+
specification, version 1.11, section 6.2.2.2,
323+
titled "Short Items." */
324+
size_code = key & 0x3;
325+
data_len = (size_code < 3) ? size_code : 4;
326+
key_size = 1;
327+
}
328+
329+
if (key_cmd == 0x94) {
330+
report_count = get_bytes(report_descriptor, desc_size, data_len, i);
331+
}
332+
if (key_cmd == 0x74) {
333+
report_size = get_bytes(report_descriptor, desc_size, data_len, i);
334+
}
335+
if (key_cmd == 0x80) { // Input
336+
ssize_t size = report_count * report_size;
337+
if (size > max_size)
338+
max_size = size;
339+
}
340+
341+
/* Skip over this key and it's associated data */
342+
i += data_len + key_size;
343+
}
344+
345+
return max_size;
346+
}
347+
279348
#if defined(__FreeBSD__) && __FreeBSD__ < 10
280349
/* The libusb version included in FreeBSD < 10 doesn't have this function. In
281350
mainline libusb, it's inlined in libusb.h. This function will bear a striking
@@ -1024,7 +1093,16 @@ static void *read_thread(void *param)
10241093
int res;
10251094
hid_device *dev = param;
10261095
uint8_t *buf;
1027-
const size_t length = dev->input_ep_max_packet_size;
1096+
size_t length;
1097+
if (dev->max_input_size > 0) {
1098+
/* max_input_size is in bits. Convert to bytes (rounding up).
1099+
Then add one byte for the report ID byte. */
1100+
length = ((dev->max_input_size + 7) / 8) + 1;
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_size = get_max_input_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)