On 2013.04.13 04:59, Xiaofan Chen wrote:
* if I'm contributing time to libusbx development that it would be more
useful if it was working on hotplug (or other features in the next
milestone)

Since hotplug could potentially affect the event handling part, it
is better to work on hotplug first.

Also, bear in mind that we have had a working hotplug implementation for all of Linux + OS X + Windows, for almost 3 years now.

Have a look at the old hp branch of my old repository of libusb:
http://git.libusb.org/?p=libusb/libusb-pbatard.git;a=shortlog;h=refs/heads/hp;js=1

Also, as per https://github.com/libusbx/libusbx/issues/9, some people have been successfully maintaining it and using it on their own.

This implementation shouldn't be too difficult to bring up to speed for libusbx and is likely something I'd have done by now ...if it wasn't for that that unplanned WinCE integration. ;) NB: this is not criticism, just a measure of the fact that, with developers not having the luxury to work full time on an Open Source project, and with people constantly pulling to have that project go in their specific direction, new developments are inherently slow.

Oh, and since I'm discussing hotplug, I'll point out that while we had a tri-platform implementation of hotplug, that could have been used by libusb to provide the feature (and avoid leaving a main platform out in their current proposal), as per their habit, and this is one of the reasons I'm weary about API proposals that don't concern themselves too much about implementation, they _chose_ to ignore existing work in order to (as far as I can tell) be able to go through yet another self-gratifying design session of an abstract API.

So that's almost 3 years of having been able to implement our #1 feature request going down the drain, for the sake of not leaving anybody else bring actual working code to do the actual deciding of the oh-so-important API...

But you can also work on future milestone items if it is kind
of independent to other features, eg, the USB 3.0 descriptor
parsing.

* don't send apis, send working code :)

Not really true. I think both are needed. Usually the API proposals
come first. On the other hand, API proposals need to consider
the potential implementation hurdles at least in the three major
platforms (Linux, Mac OS X and Windows).

If API proposals can come before implementation code, and since this is somewhat related, as libusb is also in the process of adding an USB 3.0 descriptor API (though this time by reusing a slightly flawed old code proposal), I guess there's _no_ point in telling Nathan that:

1. libusbx has had a patch for BOS implementation, based on the same proposal, but that _actually_ fetches and caches the new descriptors. I've actually been mentioning that one a few times, in order to get people to help complete the missing _code_ for Linux and OS X. As far as I can see, and just like the original patch, the libusb implementation only does the parsing, but not the fetching/caching, which I can't help but find a bit limiting for our users, as it probably won't meet their expectations.
For reference, this whole thing is referenced as libusbx issue #15:
https://github.com/libusbx/libusbx/issues/15 and I'm also reattaching that patch to this post.

2. Because libusb ignored the proposal above, its current BOS implementation also ignores the USB 3.0 specs and overlooks the fact that the device capability descriptors is not limited to USB 2.0 Extension only but can be one or a concatenation of Wireless USB, USB 2.0 Extension (9.6.2.1), SuperSpeed USB Device Capability (9.6.2.2) or Container ID for USB 3.0 hubs (9.6.2.3).

IMO using an up to date working implementation proposal must happen in parallel to introducing an API. As it stands, if libusb goes to release, they will most likely have to break their newly introduced USB 3.0 descriptor API in a future release (specifically struct libusb_bos_descriptor) when someone asks for the ability to process wireless or hub caps.

Now, the reason we haven't integrated this patch into libusbx, about one year ago, is precisely because I wanted to have at least another platform besides Windows that did the fetching and caching of the new descriptors, to try to alleviate the kind of bad surprises that having an API that has only really been tested on a single platform can bring...

So in essence, and this is the point I was trying to make earlier, adding APIs is cheap, but if the code doesn't follow in parallel of that effort, or if you ignore existing/updated code and (re)do your own thing, you _are_ going to miss important elements, and your oh-so-nice abstract API might very well come tumbling down.

Regards,

/Pete
>From f688d97409e83fceb436c3d0025710bcd0b78c88 Mon Sep 17 00:00:00 2001
From: Pete Batard <p...@akeo.ie>
Date: Mon, 4 Jun 2012 01:13:51 +0100
Subject: [PATCH] Core: Add support for BOS and Endpoint Companion USB 3.0
 descriptors

* Adds new libusb_get_bos_descriptor and libusb_free_bos_descriptor
  calls to the API
* Original patch by Maya Erez <me...@codeaurora.org>
* BOS readout currently limited to Windows backend only
---
 examples/xusb.c         |   13 ++++++
 libusb/descriptor.c     |  107 +++++++++++++++++++++++++++++++++++++++++++++--
 libusb/libusb-1.0.def   |    4 ++
 libusb/libusb.h         |   78 +++++++++++++++++++++++++++++++++-
 libusb/libusbi.h        |   22 ++++++++++
 libusb/os/darwin_usb.c  |    6 +++
 libusb/os/linux_usbfs.c |    8 ++++
 libusb/os/openbsd_usb.c |   10 +++++
 libusb/os/windows_usb.c |   95 +++++++++++++++++++++++++++++++++++++++++
 libusb/os/windows_usb.h |   37 ++++++++++++++++
 10 files changed, 376 insertions(+), 6 deletions(-)

diff --git a/examples/xusb.c b/examples/xusb.c
index c158727..06ef3a6 100644
--- a/examples/xusb.c
+++ b/examples/xusb.c
@@ -734,6 +734,7 @@ static int test_device(uint16_t vid, uint16_t pid)
        libusb_device_handle *handle;
        libusb_device *dev;
        uint8_t bus, port_path[8];
+       struct libusb_bos_descriptor *bos_desc;
        struct libusb_config_descriptor *conf_desc;
        const struct libusb_endpoint_descriptor *endpoint;
        int i, j, k, r;
@@ -785,6 +786,12 @@ static int test_device(uint16_t vid, uint16_t pid)
        string_index[1] = dev_desc.iProduct;
        string_index[2] = dev_desc.iSerialNumber;
 
+       if (libusb_get_bos_descriptor(dev, &bos_desc) == LIBUSB_SUCCESS) {
+               printf("\nReading BOS Descriptor:");
+               display_buffer_hex((unsigned char*)bos_desc, 
bos_desc->wTotalLength);
+               libusb_free_bos_descriptor(bos_desc);
+       }
+
        printf("\nReading configuration descriptors:\n");
        CALL_CHECK(libusb_get_config_descriptor(dev, 0, &conf_desc));
        nb_ifaces = conf_desc->bNumInterfaces;
@@ -823,6 +830,12 @@ static int test_device(uint16_t vid, uint16_t pid)
                                }
                                printf("           max packet size: %04X\n", 
endpoint->wMaxPacketSize);
                                printf("          polling interval: %02X\n", 
endpoint->bInterval);
+                               // Endpoint Companion
+                               if (endpoint->ep_comp) {
+                                       printf("                 bMaxBurst: 
%02X\n", endpoint->ep_comp->bMaxBurst);
+                                       printf("              bmAttributes: 
%02X\n", endpoint->ep_comp->bmAttributes);
+                                       printf("         wBytesPerInterval: 
%04X\n", endpoint->ep_comp->wBytesPerInterval);
+                               }
                        }
                }
        }
diff --git a/libusb/descriptor.c b/libusb/descriptor.c
index 590d1dc..5e27549 100644
--- a/libusb/descriptor.c
+++ b/libusb/descriptor.c
@@ -22,6 +22,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdio.h>
 
 #include "libusbi.h"
 
@@ -75,6 +76,36 @@ static void clear_endpoint(struct libusb_endpoint_descriptor 
*endpoint)
                free((unsigned char *) endpoint->extra);
 }
 
+static int parse_endpoint_comp(struct libusb_context *ctx,
+       struct libusb_endpoint_companion_descriptor *ep_comp, unsigned char 
*buffer, int size)
+{
+       struct usb_descriptor_header header;
+       int parsed = 0;
+
+       usbi_parse_descriptor(buffer, "bb", &header, 0);
+
+       /* Everything should be fine being passed into here, but we sanity 
check JIC */
+       if (header.bLength > size) {
+               usbi_err(ctx, "ran out of descriptors parsing");
+               return LIBUSB_ERROR_NO_MEM;
+       }
+
+       if (header.bDescriptorType != LIBUSB_DT_ENDPOINT_COMPANION) {
+               usbi_err(ctx, "unexpected descriptor %x (expected %x)",
+                       header.bDescriptorType, LIBUSB_DT_ENDPOINT_COMPANION);
+               return parsed;
+       }
+
+       if (header.bLength >= LIBUSB_DT_ENDPOINT_COMP_SIZE)
+               usbi_parse_descriptor(buffer, "bbbbw", ep_comp, 0);
+
+       buffer += header.bLength;
+       size -= header.bLength;
+       parsed += header.bLength;
+
+       return parsed;
+}
+
 static int parse_endpoint(struct libusb_context *ctx,
        struct libusb_endpoint_descriptor *endpoint, unsigned char *buffer,
        int size, int host_endian)
@@ -83,7 +114,7 @@ static int parse_endpoint(struct libusb_context *ctx,
        unsigned char *extra;
        unsigned char *begin;
        int parsed = 0;
-       int len;
+       int len, retval;
 
        usbi_parse_descriptor(buffer, "bb", &header, 0);
 
@@ -109,6 +140,26 @@ static int parse_endpoint(struct libusb_context *ctx,
        size -= header.bLength;
        parsed += header.bLength;
 
+       /* check if we have a companion descriptor */
+       usbi_parse_descriptor(buffer, "bb", &header, 0);
+       if (header.bDescriptorType == LIBUSB_DT_ENDPOINT_COMPANION) {
+               endpoint->ep_comp = (struct 
libusb_endpoint_companion_descriptor *)
+                       malloc(sizeof(struct 
libusb_endpoint_companion_descriptor));
+               if (!endpoint->ep_comp) {
+                       usbi_err(ctx, "couldn't allocate memory for endpoint 
companion");
+                       return LIBUSB_ERROR_NO_MEM;
+               }
+
+               memset(endpoint->ep_comp, 0, sizeof(struct 
libusb_endpoint_companion_descriptor));
+               retval = parse_endpoint_comp(ctx, endpoint->ep_comp, buffer, 
size);
+               if (retval < 0)
+                       return retval;
+
+               buffer += retval;
+               parsed += retval;
+               size -= retval;
+       }
+
        /* Skip over the rest of the Class Specific or Vendor Specific */
        /*  descriptors */
        begin = buffer;
@@ -124,7 +175,8 @@ static int parse_endpoint(struct libusb_context *ctx,
                if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
                                (header.bDescriptorType == LIBUSB_DT_INTERFACE) 
||
                                (header.bDescriptorType == LIBUSB_DT_CONFIG) ||
-                               (header.bDescriptorType == LIBUSB_DT_DEVICE))
+                               (header.bDescriptorType == LIBUSB_DT_DEVICE) ||
+                               (header.bDescriptorType == 
LIBUSB_DT_ENDPOINT_COMPANION))
                        break;
 
                usbi_dbg("skipping descriptor %x", header.bDescriptorType);
@@ -235,7 +287,8 @@ static int parse_interface(libusb_context *ctx,
                        if ((header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
                                        (header.bDescriptorType == 
LIBUSB_DT_ENDPOINT) ||
                                        (header.bDescriptorType == 
LIBUSB_DT_CONFIG) ||
-                                       (header.bDescriptorType == 
LIBUSB_DT_DEVICE))
+                                       (header.bDescriptorType == 
LIBUSB_DT_DEVICE) ||
+                                       (header.bDescriptorType == 
LIBUSB_DT_ENDPOINT_COMPANION))
                                break;
 
                        buffer += header.bLength;
@@ -383,7 +436,8 @@ static int parse_configuration(struct libusb_context *ctx,
                        if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
                                        (header.bDescriptorType == 
LIBUSB_DT_INTERFACE) ||
                                        (header.bDescriptorType == 
LIBUSB_DT_CONFIG) ||
-                                       (header.bDescriptorType == 
LIBUSB_DT_DEVICE))
+                                       (header.bDescriptorType == 
LIBUSB_DT_DEVICE) ||
+                                       (header.bDescriptorType == 
LIBUSB_DT_ENDPOINT_COMPANION))
                                break;
 
                        usbi_dbg("skipping descriptor 0x%x\n", 
header.bDescriptorType);
@@ -455,6 +509,51 @@ int API_EXPORTED 
libusb_get_device_descriptor(libusb_device *dev,
 }
 
 /** \ingroup desc
+ * Get the USB 3.0 BOS descriptor for a given device.
+ *
+ * This is a non-blocking function; the BOS descriptor is cached in memory.
+ *
+ * \param dev the device
+ * \param desc output location for the USB BOS descriptor. Only
+ * valid if 0 was returned. Must be freed with libusb_free_bos_descriptor()
+ * after use.
+ * \returns 0 on success or a LIBUSB_ERROR code on failure
+ */
+int API_EXPORTED libusb_get_bos_descriptor(libusb_device *dev,
+       struct libusb_bos_descriptor **bos)
+{
+       int host_endian = 0;
+       int r;
+
+       usbi_dbg("");
+       r = usbi_backend->get_bos_descriptor(dev, bos, &host_endian);
+       if (r < 0)
+               return r;
+
+       if (!host_endian) {
+               (*bos)->wTotalLength = libusb_le16_to_cpu((*bos)->wTotalLength);
+       }
+       return 0;
+}
+
+/** \ingroup desc
+ * Free a configuration descriptor obtained from
+ * libusb_get_active_config_descriptor() or libusb_get_config_descriptor().
+ * It is safe to call this function with a NULL config parameter, in which
+ * case the function simply returns.
+ *
+ * \param config the configuration descriptor to free
+ */
+void API_EXPORTED libusb_free_bos_descriptor(
+       struct libusb_bos_descriptor *bos)
+{
+       if (!bos)
+               return;
+
+       free(bos);
+}
+
+/** \ingroup desc
  * Get the USB configuration descriptor for the currently active configuration.
  * This is a non-blocking function which does not involve any requests being
  * sent to the device.
diff --git a/libusb/libusb-1.0.def b/libusb/libusb-1.0.def
index 847b785..0fc5245 100644
--- a/libusb/libusb-1.0.def
+++ b/libusb/libusb-1.0.def
@@ -26,6 +26,8 @@ EXPORTS
   libusb_event_handling_ok@4 = libusb_event_handling_ok
   libusb_exit
   libusb_exit@4 = libusb_exit
+  libusb_free_bos_descriptor
+  libusb_free_bos_descriptor@4 = libusb_free_bos_descriptor
   libusb_free_config_descriptor
   libusb_free_config_descriptor@4 = libusb_free_config_descriptor
   libusb_free_device_list
@@ -34,6 +36,8 @@ EXPORTS
   libusb_free_transfer@4 = libusb_free_transfer
   libusb_get_active_config_descriptor
   libusb_get_active_config_descriptor@8 = libusb_get_active_config_descriptor
+  libusb_get_bos_descriptor
+  libusb_get_bos_descriptor@8 = libusb_get_bos_descriptor
   libusb_get_bus_number
   libusb_get_bus_number@4 = libusb_get_bus_number
   libusb_get_config_descriptor
diff --git a/libusb/libusb.h b/libusb/libusb.h
index fd231ea..ad1bd8a 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -229,6 +229,15 @@ enum libusb_descriptor_type {
 
        /** Hub descriptor */
        LIBUSB_DT_HUB = 0x29,
+
+       /** BOS descriptor */
+       LIBUSB_DT_BOS = 0x0f,
+
+       /** Device Capability descriptor */
+       LIBUSB_DT_DEVICE_CAPABILITY = 0x10,
+
+       /** SuperSpeed Endpoint Companion descriptor */
+       LIBUSB_DT_ENDPOINT_COMPANION = 0x30
 };
 
 /* Descriptor sizes per descriptor type */
@@ -238,6 +247,7 @@ enum libusb_descriptor_type {
 #define LIBUSB_DT_ENDPOINT_SIZE                7
 #define LIBUSB_DT_ENDPOINT_AUDIO_SIZE  9       /* Audio extension */
 #define LIBUSB_DT_HUB_NONVAR_SIZE              7
+#define LIBUSB_DT_ENDPOINT_COMP_SIZE   6
 
 #define LIBUSB_ENDPOINT_ADDRESS_MASK   0x0f    /* in bEndpointAddress */
 #define LIBUSB_ENDPOINT_DIR_MASK               0x80
@@ -444,6 +454,32 @@ struct libusb_device_descriptor {
        uint8_t  bNumConfigurations;
 };
 
+/* USB_DT_ENDPOINT_COMPANION: SuperSpeed Endpoint Companion descriptor */
+struct libusb_endpoint_companion_descriptor {
+
+       /** Size of this descriptor (in bytes) */
+       uint8_t  bLength;
+
+       /** Descriptor type. Will have value
+        * \ref libusb_descriptor_type::LIBUSB_DT_ENDPOINT_COMPANION in
+        * this context. */
+       uint8_t  bDescriptorType;
+
+       /** The maximum number of packets the endpoint can send or
+        *  recieve as part of a burst. */
+       uint8_t  bMaxBurst;
+
+       /** In bulk EP: bits 4:0 represents the maximum number of
+        *  streams the EP supports. In isochronous EP: bits 1:0
+        *  represents the Mult - a zero based value that determines
+        *  the maximum number of packets within a service interval  */
+       uint8_t  bmAttributes;
+
+       /** The total number of bytes this EP will transfer every
+        *  service interval. valid only for periodic EPs. */
+       uint16_t wBytesPerInterval;
+};
+
 /** \ingroup desc
  * A structure representing the standard USB endpoint descriptor. This
  * descriptor is documented in section 9.6.3 of the USB 2.0 specification.
@@ -486,7 +522,10 @@ struct libusb_endpoint_descriptor {
        /** For audio devices only: the address if the synch endpoint */
        uint8_t  bSynchAddress;
 
-       /** Extra descriptors. If libusbx encounters unknown endpoint 
descriptors,
+       /** The endpoint companion descriptor */
+       struct libusb_endpoint_companion_descriptor *ep_comp;
+
+       /** Extra descriptors. If libusb encounters unknown endpoint 
descriptors,
         * it will store them here, should you wish to parse them. */
        const unsigned char *extra;
 
@@ -602,6 +641,39 @@ struct libusb_config_descriptor {
        int extra_length;
 };
 
+/** \ingroup desc
+ * A structure representing the Binary Device Object Store (BOS)
+ * descriptor.
+ * This descriptor is documented in section 9.6.2 of the USB 3.0
+ * specification. All multiple-byte fields are represented in
+ * host-endian format.
+ */
+struct libusb_bos_descriptor {
+       /** Size of this descriptor (in bytes) */
+       uint8_t  bLength;
+
+       /** Descriptor type. Will have value
+        * \ref libusb_descriptor_type::LIBUSB_DT_BOS LIBUSB_DT_BOS
+        * in this context. */
+       uint8_t  bDescriptorType;
+
+       /** Total length of data returned for this configuration */
+       uint16_t wTotalLength;
+
+       /** The number of separate device capability descriptors in the BOS */
+       uint8_t  bNumDeviceCaps;
+
+       /** device capability descriptors data. As per the USB 3.0 specs,
+        * can be one or a concatenation of Wireless USB, USB 2.0 Extension
+        * (9.6.2.1), SuperSpeed USB Device Capability (9.6.2.2) or Container
+        * ID for USB 3.0 hubs (9.6.2.3) */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+       const unsigned char device_caps[]; /* valid C99 code */
+#else
+       const unsigned char device_caps[0]; /* non-standard, but usually 
working code */
+#endif
+};
+
 /** \ingroup asyncio
  * Setup packet for control transfers. */
 struct libusb_control_setup {
@@ -985,6 +1057,10 @@ int LIBUSB_CALL 
libusb_get_configuration(libusb_device_handle *dev,
        int *config);
 int LIBUSB_CALL libusb_get_device_descriptor(libusb_device *dev,
        struct libusb_device_descriptor *desc);
+int LIBUSB_CALL libusb_get_bos_descriptor(libusb_device *dev,
+       struct libusb_bos_descriptor **bos);
+void LIBUSB_CALL libusb_free_bos_descriptor(
+       struct libusb_bos_descriptor *bos);
 int LIBUSB_CALL libusb_get_active_config_descriptor(libusb_device *dev,
        struct libusb_config_descriptor **config);
 int LIBUSB_CALL libusb_get_config_descriptor(libusb_device *dev,
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index 9de56a1..b188954 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -563,6 +563,28 @@ struct usbi_os_backend {
        int (*get_device_descriptor)(struct libusb_device *device,
                unsigned char *buffer, int *host_endian);
 
+       /* Retrieve the BOS descriptor from a device.
+        *
+        * The descriptor should be retrieved from memory, NOT via bus I/O to 
the
+        * device. This means that you may have to cache it in a private 
structure
+        * during get_device_list enumeration. Alternatively, you may be able
+        * to retrieve it from a kernel interface.
+        *
+        * Because a BOS descriptor is variable in size, this function is 
required
+        * to allocate its own BOS buffer (which will then be freed by calling
+        * libusb_free_bos_descriptor).
+        *
+        * This function is called when the user requests to read the BOS 
descriptor.
+        *
+        * This function is expected to return the descriptor in bus-endian 
format
+        * (LE). If it returns the multi-byte values in host-endian format,
+        * set the host_endian output parameter to "1".
+        *
+        * Return 0 on success or a LIBUSB_ERROR code on failure.
+        */
+       int (*get_bos_descriptor)(struct libusb_device *device,
+               struct libusb_bos_descriptor **bos, int *host_endian);
+
        /* Get the ACTIVE configuration descriptor for a device.
         *
         * The descriptor should be retrieved from memory, NOT via bus I/O to 
the
diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
index ac67b35..a742f4a 100644
--- a/libusb/os/darwin_usb.c
+++ b/libusb/os/darwin_usb.c
@@ -460,6 +460,11 @@ static int darwin_get_device_descriptor(struct 
libusb_device *dev, unsigned char
   return 0;
 }
 
+static int darwin_get_bos_descriptor(struct libusb_device *dev, struct 
libusb_bos_descriptor **bos, int *host_endian) {
+
+  return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
 static int get_configuration_index (struct libusb_device *dev, int 
config_value) {
   struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
   UInt8 i, numConfig;
@@ -1770,6 +1775,7 @@ const struct usbi_os_backend darwin_backend = {
        .exit = darwin_exit,
        .get_device_list = darwin_get_device_list,
        .get_device_descriptor = darwin_get_device_descriptor,
+       .get_bos_descriptor = darwin_get_bos_descriptor,
        .get_active_config_descriptor = darwin_get_active_config_descriptor,
        .get_config_descriptor = darwin_get_config_descriptor,
 
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index a01fff8..54856e9 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -111,6 +111,7 @@ static int sysfs_has_descriptors = 0;
 struct linux_device_priv {
        char *sysfs_dir;
        unsigned char *dev_descriptor;
+       struct libusb_bos_descriptor *bos_descriptor; 
        unsigned char *config_descriptor;
 };
 
@@ -518,6 +519,12 @@ static int op_get_device_descriptor(struct libusb_device 
*dev,
        }
 }
 
+static int op_get_bos_descriptor(struct libusb_device *dev,
+       struct libusb_bos_descriptor **bos, int *host_endian)
+{
+       return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
 static int usbfs_get_active_config_descriptor(struct libusb_device *dev,
        unsigned char *buffer, size_t len)
 {
@@ -2467,6 +2474,7 @@ const struct usbi_os_backend linux_usbfs_backend = {
        .exit = NULL,
        .get_device_list = op_get_device_list,
        .get_device_descriptor = op_get_device_descriptor,
+       .get_bos_descriptor = op_get_bos_descriptor,
        .get_active_config_descriptor = op_get_active_config_descriptor,
        .get_config_descriptor = op_get_config_descriptor,
 
diff --git a/libusb/os/openbsd_usb.c b/libusb/os/openbsd_usb.c
index 88e2c7a..9755869 100644
--- a/libusb/os/openbsd_usb.c
+++ b/libusb/os/openbsd_usb.c
@@ -54,6 +54,8 @@ static void obsd_close(struct libusb_device_handle *);
 
 static int obsd_get_device_descriptor(struct libusb_device *, unsigned char *,
     int *);
+static int obsd_get_bos_descriptor(struct libusb_device *,
+    struct libusb_bos_descriptor **, int *);
 static int obsd_get_active_config_descriptor(struct libusb_device *,
     unsigned char *, size_t, int *);
 static int obsd_get_config_descriptor(struct libusb_device *, uint8_t,
@@ -96,6 +98,7 @@ const struct usbi_os_backend openbsd_backend = {
        obsd_close,
 
        obsd_get_device_descriptor,
+       obsd_get_bos_descriptor,
        obsd_get_active_config_descriptor,
        obsd_get_config_descriptor,
 
@@ -253,6 +256,13 @@ obsd_get_device_descriptor(struct libusb_device *dev, 
unsigned char *buf,
 }
 
 int
+obsd_get_bos_descriptor(struct libusb_device *dev, struct 
libusb_bos_descriptor **bos,
+    int *host_endian)
+{
+       return (LIBUSB_ERROR_NOT_SUPPORTED);
+}
+
+int
 obsd_get_active_config_descriptor(struct libusb_device *dev,
     unsigned char *buf, size_t len, int *host_endian)
 {
diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c
index dbebfaf..1893aa2 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -985,6 +985,84 @@ static int cache_config_descriptors(struct libusb_device 
*dev, HANDLE hub_handle
 }
 
 /*
+ * fetch and cache all the BOS descriptors through I/O
+ */
+static int cache_bos_descriptors(struct libusb_device *dev, HANDLE hub_handle, 
char* device_id)
+{
+       DWORD size, ret_size;
+       struct libusb_context *ctx = DEVICE_CTX(dev);
+       struct windows_device_priv *priv = _device_priv(dev);
+       int r = LIBUSB_ERROR_OTHER;
+
+       USB_BOS_DESCRIPTOR_SHORT bos_buf_short;                                 
        // dummy request
+       PUSB_DESCRIPTOR_REQUEST_WITH_DATA bos_buf_actual = NULL;        // 
actual request
+
+       size = sizeof(bos_buf_short);
+       memset(&bos_buf_short, 0, size);
+
+       bos_buf_short.req.ConnectionIndex = (ULONG)priv->port;
+       bos_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
+       bos_buf_short.req.SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
+       bos_buf_short.req.SetupPacket.wValue = (USB_BOS_DESCRIPTOR_TYPE << 8) | 
0;
+       bos_buf_short.req.SetupPacket.wIndex = 0;
+       bos_buf_short.req.SetupPacket.wLength = 
sizeof(USB_BOS_DESCRIPTOR_HEADER);      // sizeof(bos_buf_short);
+
+       // Dummy call to get the required data size. Initial failures are 
reported as info rather
+       // than error as they can occur for non-penalizing situations, such as 
with some hubs.
+       if (!DeviceIoControl(hub_handle, 
IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &bos_buf_short, size,
+               &bos_buf_short, size, &ret_size, NULL)) {
+               // An error is to be expected for non 3.0 devices
+               return LIBUSB_ERROR_IO;
+       }
+
+       if ((ret_size != size) || (bos_buf_short.data.wTotalLength < 
sizeof(USB_BOS_DESCRIPTOR_HEADER))) {
+               usbi_info(ctx, "unexpected BOS descriptor size (dummy) for 
'%s'.", device_id);
+               return LIBUSB_ERROR_IO;
+       }
+
+       size = sizeof(USB_DESCRIPTOR_REQUEST) + bos_buf_short.data.wTotalLength;
+       if ((bos_buf_actual = (PUSB_DESCRIPTOR_REQUEST_WITH_DATA) calloc(1, 
size)) == NULL) {
+               usbi_err(ctx, "could not allocate BOS descriptor buffer for 
'%s'.", device_id);
+               return LIBUSB_ERROR_NO_MEM;
+       }
+
+       // Actual call
+       bos_buf_actual->ConnectionIndex = (ULONG)priv->port;
+       bos_buf_actual->SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
+       bos_buf_actual->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
+       bos_buf_actual->SetupPacket.wValue = (USB_BOS_DESCRIPTOR_TYPE << 8) | 0;
+       bos_buf_actual->SetupPacket.wIndex = 0;
+       bos_buf_actual->SetupPacket.wLength = (USHORT)(size - 
sizeof(USB_DESCRIPTOR_REQUEST));
+
+       if (!DeviceIoControl(hub_handle, 
IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, bos_buf_actual, size,
+               bos_buf_actual, size, &ret_size, NULL)) {
+               usbi_err(ctx, "could not access BOS descriptor (actual) for 
'%s': %s", device_id, windows_error_str(0));
+               r = LIBUSB_ERROR_IO;
+               goto err;
+       }
+
+       if (size != ret_size) {
+               usbi_err(ctx, "unexpected configuration descriptor size 
(actual) for '%s'.", device_id);
+               r = LIBUSB_ERROR_IO;
+               goto err;
+       }
+
+       priv->bos_descriptor = (struct 
libusb_bos_descriptor*)malloc(bos_buf_actual->SetupPacket.wLength);
+       if (priv->bos_descriptor == NULL) {
+               r = LIBUSB_ERROR_NO_MEM;
+               goto err;
+       }
+
+       memcpy(priv->bos_descriptor, &bos_buf_actual->Data[0], 
bos_buf_actual->SetupPacket.wLength);
+       usbi_dbg("cached BOS descriptor (%d bytes)", 
bos_buf_actual->SetupPacket.wLength);
+       r = LIBUSB_SUCCESS;
+
+err:
+       safe_free(bos_buf_actual);
+       return r;
+}
+
+/*
  * Populate a libusbx device structure
  */
 static int init_device(struct libusb_device* dev, struct libusb_device* 
parent_dev,
@@ -1067,6 +1145,7 @@ static int init_device(struct libusb_device* dev, struct 
libusb_device* parent_d
                        dev->num_configurations = 0;
                        priv->dev_descriptor.bNumConfigurations = 0;
                }
+               cache_bos_descriptors(dev, handle, device_id);
                safe_closehandle(handle);
 
                if (conn_info.DeviceAddress > UINT8_MAX) {
@@ -1652,6 +1731,21 @@ static int windows_get_device_descriptor(struct 
libusb_device *dev, unsigned cha
        return LIBUSB_SUCCESS;
 }
 
+static int windows_get_bos_descriptor(struct libusb_device *dev, struct 
libusb_bos_descriptor **bos, int *host_endian)
+{
+       struct windows_device_priv *priv = _device_priv(dev);
+
+       if (priv->bos_descriptor == NULL)
+               return LIBUSB_ERROR_NOT_FOUND;
+
+       *bos = (struct libusb_bos_descriptor 
*)malloc(priv->bos_descriptor->wTotalLength);
+       if (*bos == NULL)
+               return LIBUSB_ERROR_NO_MEM;
+       memcpy(*bos, priv->bos_descriptor, priv->bos_descriptor->wTotalLength);
+       *host_endian = 0;
+       return LIBUSB_SUCCESS;
+}
+
 static int windows_get_config_descriptor(struct libusb_device *dev, uint8_t 
config_index, unsigned char *buffer, size_t len, int *host_endian)
 {
        struct windows_device_priv *priv = _device_priv(dev);
@@ -2182,6 +2276,7 @@ const struct usbi_os_backend windows_backend = {
        windows_close,
 
        windows_get_device_descriptor,
+       windows_get_bos_descriptor,
        windows_get_active_config_descriptor,
        windows_get_config_descriptor,
 
diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h
index 331f75c..0cb2a39 100644
--- a/libusb/os/windows_usb.h
+++ b/libusb/os/windows_usb.h
@@ -245,6 +245,7 @@ struct windows_device_priv {
        uint8_t active_config;
        USB_DEVICE_DESCRIPTOR dev_descriptor;
        unsigned char **config_descriptor;      // list of pointers to the 
cached config descriptors
+       struct libusb_bos_descriptor *bos_descriptor;
 };
 
 static inline struct windows_device_priv *_device_priv(struct libusb_device 
*dev) {
@@ -263,6 +264,7 @@ static inline void windows_device_priv_init(libusb_device* 
dev) {
        p->hid = NULL;
        p->active_config = 0;
        p->config_descriptor = NULL;
+       p->bos_descriptor = NULL;
        memset(&(p->dev_descriptor), 0, sizeof(USB_DEVICE_DESCRIPTOR));
        for (i=0; i<USB_MAXINTERFACES; i++) {
                p->usb_interface[i].path = NULL;
@@ -282,6 +284,7 @@ static inline void 
windows_device_priv_release(libusb_device* dev) {
                        safe_free(p->config_descriptor[i]);
        }
        safe_free(p->config_descriptor);
+       safe_free(p->bos_descriptor);
        safe_free(p->hid);
        for (i=0; i<USB_MAXINTERFACES; i++) {
                safe_free(p->usb_interface[i].path);
@@ -386,6 +389,7 @@ typedef RETURN_TYPE CONFIGRET;
 #define USB_STRING_DESCRIPTOR_TYPE              LIBUSB_DT_STRING
 #define USB_INTERFACE_DESCRIPTOR_TYPE           LIBUSB_DT_INTERFACE
 #define USB_ENDPOINT_DESCRIPTOR_TYPE            LIBUSB_DT_ENDPOINT
+#define USB_BOS_DESCRIPTOR_TYPE                 LIBUSB_DT_BOS
 
 #define USB_REQUEST_GET_STATUS                  LIBUSB_REQUEST_GET_STATUS
 #define USB_REQUEST_CLEAR_FEATURE               LIBUSB_REQUEST_CLEAR_FEATURE
@@ -515,6 +519,27 @@ typedef struct USB_CONFIGURATION_DESCRIPTOR_SHORT {
        USB_CONFIGURATION_DESCRIPTOR data;
 } USB_CONFIGURATION_DESCRIPTOR_SHORT;
 
+typedef struct USB_BOS_DESCRIPTOR_HEADER {
+  UCHAR  bLength;
+  UCHAR  bDescriptorType;
+  USHORT wTotalLength;
+  UCHAR  bNumDeviceCaps;
+} USB_BOS_DESCRIPTOR_HEADER;
+
+typedef struct USB_BOS_DESCRIPTOR_SHORT {
+       struct {
+               ULONG ConnectionIndex;
+               struct {
+                       UCHAR bmRequest;
+                       UCHAR bRequest;
+                       USHORT wValue;
+                       USHORT wIndex;
+                       USHORT wLength;
+               } SetupPacket;
+       } req;
+       USB_BOS_DESCRIPTOR_HEADER data;
+} USB_BOS_DESCRIPTOR_SHORT;
+
 typedef struct USB_ENDPOINT_DESCRIPTOR {
   UCHAR  bLength;
   UCHAR  bDescriptorType;
@@ -536,6 +561,18 @@ typedef struct USB_DESCRIPTOR_REQUEST {
 //     UCHAR  Data[0];
 } USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST;
 
+typedef struct USB_DESCRIPTOR_REQUEST_WITH_DATA {
+       ULONG  ConnectionIndex;
+       struct {
+               UCHAR  bmRequest;
+               UCHAR  bRequest;
+               USHORT  wValue;
+               USHORT  wIndex;
+               USHORT  wLength;
+       } SetupPacket;
+       UCHAR  Data[1];
+} USB_DESCRIPTOR_REQUEST_WITH_DATA, *PUSB_DESCRIPTOR_REQUEST_WITH_DATA;
+
 typedef struct USB_HUB_DESCRIPTOR {
        UCHAR  bDescriptorLength;
        UCHAR  bDescriptorType;
-- 
1.7.10.msysgit.1

------------------------------------------------------------------------------
Precog is a next-generation analytics platform capable of advanced
analytics on semi-structured data. The platform includes APIs for building
apps and a phenomenal toolset for data science. Developers can use
our toolset for easy data analysis & visualization. Get a free account!
http://www2.precog.com/precogplatform/slashdotnewsletter
_______________________________________________
libusbx-devel mailing list
libusbx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libusbx-devel

Reply via email to