Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions hidapi/hidapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
53 changes: 34 additions & 19 deletions libusb/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 &&
Expand Down Expand Up @@ -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 {
Expand All @@ -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;
Expand Down
60 changes: 12 additions & 48 deletions linux/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand All @@ -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;

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 0 additions & 2 deletions mac/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down