summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNikolai Kondrashov <Nikolai.Kondrashov@redhat.com>2014-07-12 21:02:33 +0300
committerNikolai Kondrashov <Nikolai.Kondrashov@redhat.com>2014-07-12 21:02:33 +0300
commitcc74aae8d020e0ddd069dbb107900cec54e56cd5 (patch)
tree398a64e5f3b76f1c045c083a9129beb13a82f154 /lib
parent10f8a6ba71e416605f8e0521198554ffbf72ad9a (diff)
downloadusbhid-dump-cc74aae8d020e0ddd069dbb107900cec54e56cd5.tar.gz
Retrieve declared descriptor size
Request transfer of report descriptor with the destination buffer size equal to report descriptor size declared in HID descriptor, instead of the maximum possible report descriptor size. Only fall back to the maximum possible size, if report descriptor size cannot be retrieved. This fixes ERROR_PIPE when retrieving report descriptors from some devices (e.g. Waltop Vega tablet).
Diffstat (limited to 'lib')
-rw-r--r--lib/iface.c4
-rw-r--r--lib/iface_list.c57
2 files changed, 53 insertions, 8 deletions
diff --git a/lib/iface.c b/lib/iface.c
index 7209188..2cd9ea0 100644
--- a/lib/iface.c
+++ b/lib/iface.c
@@ -45,7 +45,8 @@ uhd_iface *
uhd_iface_new(const uhd_dev *dev,
uint8_t number,
uint8_t int_in_ep_addr,
- uint16_t int_in_ep_maxp)
+ uint16_t int_in_ep_maxp,
+ uint16_t rd_len)
{
uhd_iface *iface;
libusb_device *lusb_dev;
@@ -60,6 +61,7 @@ uhd_iface_new(const uhd_dev *dev,
iface->number = number;
iface->int_in_ep_addr = int_in_ep_addr;
iface->int_in_ep_maxp = int_in_ep_maxp;
+ iface->rd_len = rd_len;
iface->detached = false;
iface->claimed = false;
iface->submitted = false;
diff --git a/lib/iface_list.c b/lib/iface_list.c
index 1b028b1..bd208aa 100644
--- a/lib/iface_list.c
+++ b/lib/iface_list.c
@@ -27,6 +27,7 @@
#include "config.h"
#include "uhd/iface_list.h"
+#include "uhd/misc.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
@@ -76,6 +77,10 @@ uhd_iface_list_new(uhd_dev *dev_list,
uhd_dev *dev;
struct libusb_config_descriptor *config = NULL;
const struct libusb_interface *lusb_iface;
+ const struct libusb_interface_descriptor *iface_desc;
+ const uhd_hid_descriptor *hid_desc;
+ const uhd_hid_descriptor_extra *hid_desc_extra;
+ uint16_t rd_len;
const struct libusb_endpoint_descriptor *ep_list;
uint8_t ep_num;
const struct libusb_endpoint_descriptor *ep;
@@ -101,14 +106,51 @@ uhd_iface_list_new(uhd_dev *dev_list,
lusb_iface - config->interface < config->bNumInterfaces;
lusb_iface++)
{
- /* Skip interfaces with altsettings and non-HID interfaces */
- if (lusb_iface->num_altsetting != 1 ||
- lusb_iface->altsetting->bInterfaceClass != LIBUSB_CLASS_HID)
+ /* Skip interfaces with altsettings */
+ if (lusb_iface->num_altsetting != 1)
continue;
+ iface_desc = lusb_iface->altsetting;
+
+ /* Skip non-HID interfaces */
+ if (iface_desc->bInterfaceClass != LIBUSB_CLASS_HID)
+ continue;
+
+ /*
+ * Try to retrieve report descriptor length
+ */
+ rd_len = UHD_MAX_DESCRIPTOR_SIZE;
+ /* If interface descriptor has space for a HID descriptor */
+ if (iface_desc->extra_length >= (int)sizeof(uhd_hid_descriptor))
+ {
+ hid_desc = (const uhd_hid_descriptor *)iface_desc->extra;
+ /* If this is truly a HID class descriptor */
+ if (hid_desc->bDescriptorType == LIBUSB_DT_HID)
+ {
+ /* For each extra HID descriptor entry */
+ for (hid_desc_extra = hid_desc->extra;
+ hid_desc_extra <
+ hid_desc->extra + hid_desc->bNumDescriptors &&
+ (uint8_t *)hid_desc_extra <
+ (uint8_t *)hid_desc + hid_desc->bLength &&
+ (unsigned char *)hid_desc_extra <
+ iface_desc->extra +
+ iface_desc->extra_length;
+ hid_desc_extra++) {
+ /* If this is a report descriptor entry */
+ if (hid_desc_extra->bDescriptorType ==
+ LIBUSB_DT_REPORT)
+ {
+ rd_len = hid_desc_extra->wDescriptorLength;
+ break;
+ }
+ }
+ }
+ }
+
/* Retrieve endpoint list */
- ep_list = lusb_iface->altsetting->endpoint;
- ep_num = lusb_iface->altsetting->bNumEndpoints;
+ ep_list = iface_desc->endpoint;
+ ep_num = iface_desc->bNumEndpoints;
/* For each endpoint */
for (ep = ep_list; (ep - ep_list) < ep_num; ep++)
@@ -123,8 +165,9 @@ uhd_iface_list_new(uhd_dev *dev_list,
/* Create the interface */
iface = uhd_iface_new(
dev,
- lusb_iface->altsetting->bInterfaceNumber,
- ep->bEndpointAddress, ep->wMaxPacketSize);
+ iface_desc->bInterfaceNumber,
+ ep->bEndpointAddress, ep->wMaxPacketSize,
+ rd_len);
if (iface == NULL)
{
err = LIBUSB_ERROR_NO_MEM;