diff --git a/hidapi/hidapi.h b/hidapi/hidapi.h index fe0d19a21..2b261f122 100644 --- a/hidapi/hidapi.h +++ b/hidapi/hidapi.h @@ -88,6 +88,14 @@ */ #define HID_API_VERSION_STR HID_API_TO_VERSION_STR(HID_API_VERSION_MAJOR, HID_API_VERSION_MINOR, HID_API_VERSION_PATCH) +/** @brief Maximum expected HID Report descriptor size in bytes. + + Since version 0.13.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 13, 0) + + @ingroup API +*/ +#define HID_API_MAX_REPORT_DESCRIPTOR_SIZE 4096 + #ifdef __cplusplus extern "C" { #endif diff --git a/libusb/hid.c b/libusb/hid.c index fade044f0..13e8fdb8c 100644 --- a/libusb/hid.c +++ b/libusb/hid.c @@ -564,28 +564,43 @@ int HID_API_EXPORT hid_exit(void) return 0; } -/** - * Requires an opened device with *claimed interface*. - */ -static void fill_device_info_usage(struct hid_device_info *cur_dev, libusb_device_handle *handle, int interface_num, uint16_t report_descriptor_size) +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) { - unsigned char data[4096]; - unsigned short page = 0, usage = 0; + unsigned char tmp[HID_API_MAX_REPORT_DESCRIPTOR_SIZE]; - if (report_descriptor_size > 4096) - report_descriptor_size = 4096; + if (expected_report_descriptor_size > HID_API_MAX_REPORT_DESCRIPTOR_SIZE) + expected_report_descriptor_size = HID_API_MAX_REPORT_DESCRIPTOR_SIZE; /* Get the HID Report Descriptor. See USB HID Specificatin, sectin 7.1.1 */ - 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); + int res = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8), interface_num, tmp, expected_report_descriptor_size, 5000); + if (res < 0) { + LOG("libusb_control_transfer() for getting the HID Report descriptor failed with %d: %s\n", res, libusb_error_name(res)); + return -1; + } + + if (res > (int)buf_size) + res = (int)buf_size; + + memcpy(buf, tmp, (size_t)res); + return res; +} + +/** + * Requires an opened device with *claimed interface*. + */ +static void fill_device_info_usage(struct hid_device_info *cur_dev, libusb_device_handle *handle, int interface_num, uint16_t expected_report_descriptor_size) +{ + unsigned char hid_report_descriptor[HID_API_MAX_REPORT_DESCRIPTOR_SIZE]; + unsigned short page = 0, usage = 0; + + int res = hid_get_report_descriptor_libusb(handle, interface_num, expected_report_descriptor_size, hid_report_descriptor, sizeof(hid_report_descriptor)); if (res >= 0) { /* Parse the usage and usage page out of the report descriptor. */ - get_usage(data, res, &page, &usage); + get_usage(hid_report_descriptor, res, &page, &usage); } - else - LOG("libusb_control_transfer() for getting the HID report descriptor failed with %d: %s\n", res, libusb_error_name(res)); cur_dev->usage_page = page; cur_dev->usage = usage; @@ -619,7 +634,7 @@ static void invasive_fill_device_info_usage(struct hid_device_info *cur_dev, lib LOG("Can't release the interface.\n"); } else - LOG("Can't claim interface %d\n", res); + LOG("Can't claim interface: (%d) %s\n", res, libusb_error_name(res)); #ifdef DETACH_KERNEL_DRIVER /* Re-attach kernel driver if necessary. */ @@ -675,7 +690,7 @@ static uint16_t get_report_descriptor_size_from_interface_descriptors(const stru { int i = 0; int found_hid_report_descriptor = 0; - uint16_t result = 4096; + uint16_t result = HID_API_MAX_REPORT_DESCRIPTOR_SIZE; const unsigned char *extra = intf_desc->extra; int extra_length = intf_desc->extra_length; @@ -943,7 +958,7 @@ static void read_callback(struct libusb_transfer *transfer) /* Re-submit the transfer object. */ res = libusb_submit_transfer(transfer); if (res != 0) { - LOG("Unable to submit URB. libusb error code: %d\n", res); + LOG("Unable to submit URB: (%d) %s\n", res, libusb_error_name(res)); dev->shutdown_thread = 1; dev->transfer_loop_finished = 1; } @@ -981,7 +996,7 @@ static void *read_thread(void *param) res = libusb_handle_events(usb_context); if (res < 0) { /* There was an error. */ - LOG("read_thread(): libusb reports error # %d\n", res); + LOG("read_thread(): (%d) %s\n", res, libusb_error_name(res)); /* Break out of this loop only on fatal error.*/ if (res != LIBUSB_ERROR_BUSY && @@ -1036,7 +1051,7 @@ static int hidapi_initialize_device(hid_device *dev, int config_number, const st if (libusb_kernel_driver_active(dev->device_handle, intf_desc->bInterfaceNumber) == 1) { res = libusb_detach_kernel_driver(dev->device_handle, intf_desc->bInterfaceNumber); if (res < 0) { - LOG("Unable to detach Kernel Driver\n"); + LOG("Unable to detach Kernel Driver: (%d) %s\n", res, libusb_error_name(res)); return 0; } else { @@ -1047,13 +1062,13 @@ static int hidapi_initialize_device(hid_device *dev, int config_number, const st #endif res = libusb_claim_interface(dev->device_handle, intf_desc->bInterfaceNumber); if (res < 0) { - LOG("can't claim interface %d: %d\n", intf_desc->bInterfaceNumber, res); + LOG("can't claim interface %d: (%d) %s\n", intf_desc->bInterfaceNumber, res, libusb_error_name(res)); #ifdef DETACH_KERNEL_DRIVER if (dev->is_driver_detached) { res = libusb_attach_kernel_driver(dev->device_handle, intf_desc->bInterfaceNumber); if (res < 0) - LOG("Failed to reattach the driver to kernel.\n"); + LOG("Failed to reattach the driver to kernel: (%d) %s\n", res, libusb_error_name(res)); } #endif return 0; diff --git a/linux/hid.c b/linux/hid.c index 35d936f5c..c9ddec071 100644 --- a/linux/hid.c +++ b/linux/hid.c @@ -71,7 +71,6 @@ struct hid_device_ { int device_handle; int blocking; - int uses_numbered_reports; wchar_t *last_error_str; struct hid_device_info* device_info; }; @@ -88,9 +87,12 @@ static wchar_t *last_global_error_str = NULL; static hid_device *new_hid_device(void) { hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device)); + if (dev == NULL) { + return NULL; + } + dev->device_handle = -1; dev->blocking = 1; - dev->uses_numbered_reports = 0; dev->last_error_str = NULL; dev->device_info = NULL; @@ -242,34 +244,6 @@ static int get_hid_item_size(__u8 *report_descriptor, unsigned int pos, __u32 si return 0; } -/* uses_numbered_reports() returns 1 if report_descriptor describes a device - which contains numbered reports. */ -static int uses_numbered_reports(__u8 *report_descriptor, __u32 size) { - unsigned int i = 0; - int data_len, key_size; - - while (i < size) { - int key = report_descriptor[i]; - - /* Check for the Report ID key */ - if (key == 0x85/*Report ID*/) { - /* This device has a Report ID, which means it uses - numbered reports. */ - return 1; - } - - /* Determine data_len and key_size */ - if (!get_hid_item_size(report_descriptor, i, size, &data_len, &key_size)) - return 0; /* malformed report */ - - /* Skip over this key and its associated data */ - i += data_len + key_size; - } - - /* Didn't find a Report ID key. Device doesn't use numbered reports. */ - return 0; -} - /* * Get bytes from a HID Report Descriptor. * Only call with a num_bytes of 0, 1, 2, or 4. @@ -988,32 +962,22 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path) /* register_global_error: global error is reset by hid_init */ dev = new_hid_device(); + if (!dev) { + register_global_error("Couldn't allocate memory"); + return NULL; + } dev->device_handle = open(path, O_RDWR | O_CLOEXEC); - /* If we have a good handle, return it. */ if (dev->device_handle >= 0) { - /* Get the report descriptor */ int res, desc_size = 0; - struct hidraw_report_descriptor rpt_desc; - - memset(&rpt_desc, 0x0, sizeof(rpt_desc)); - /* Get Report Descriptor Size */ + /* Make sure this is a HIDRAW device - responds to HIDIOCGRDESCSIZE */ res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size); - if (res < 0) - register_device_error_format(dev, "ioctl (GRDESCSIZE): %s", strerror(errno)); - - /* Get Report Descriptor */ - rpt_desc.size = desc_size; - res = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc); if (res < 0) { - register_device_error_format(dev, "ioctl (GRDESC): %s", strerror(errno)); - } else { - /* Determine if this device uses numbered reports. */ - dev->uses_numbered_reports = - uses_numbered_reports(rpt_desc.value, - rpt_desc.size); + hid_close(dev); + register_device_error_format(dev, "ioctl(GRDESCSIZE) error for '%s', not a HIDRAW device?: %s", path, strerror(errno)); + return NULL; } return dev; diff --git a/mac/hid.c b/mac/hid.c index 20d44f41f..7a20f197f 100644 --- a/mac/hid.c +++ b/mac/hid.c @@ -124,7 +124,6 @@ struct hid_device_ { IOHIDDeviceRef device_handle; IOOptionBits open_options; int blocking; - int uses_numbered_reports; int disconnected; CFStringRef run_loop_mode; CFRunLoopRef run_loop; @@ -148,7 +147,6 @@ static hid_device *new_hid_device(void) dev->device_handle = NULL; dev->open_options = device_open_options; dev->blocking = 1; - dev->uses_numbered_reports = 0; dev->disconnected = 0; dev->run_loop_mode = NULL; dev->run_loop = NULL;