Windows: Fix possible false error message during device enumeration
authorChris Dickens <christopher.a.dickens@gmail.com>
Wed, 14 Sep 2016 05:09:50 +0000 (22:09 -0700)
committerNathan Hjelm <hjelmn@me.com>
Sat, 1 Oct 2016 12:59:11 +0000 (06:59 -0600)
During early phases of enumeration, it is possible for a device to be
enumerated before its parent. When this occurs, the device assigned as
the parent will actually be a grandparent. During later phases of
enumeration, the parent device will in fact exist but will not match
what has already been assigned to the device.

This commit adds code to check for and update the parent device when
this situation occurs.

Closes #206

Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
libusb/os/windows_winusb.c
libusb/os/windows_winusb.h
libusb/version_nano.h

index 81cceef..d1d2749 100644 (file)
@@ -864,12 +864,12 @@ static int force_hcd_device_descriptor(struct libusb_device *dev)
        priv->dev_descriptor.bNumConfigurations = 1;
        priv->active_config = 1;
 
-       if (priv->parent_dev == NULL) {
+       if (dev->parent_dev == NULL) {
                usbi_err(ctx, "program assertion failed - HCD hub has no parent");
                return LIBUSB_ERROR_NO_DEVICE;
        }
 
-       parent_priv = _device_priv(priv->parent_dev);
+       parent_priv = _device_priv(dev->parent_dev);
        if (sscanf(parent_priv->path, "\\\\.\\PCI#VEN_%04x&DEV_%04x%*s", &vid, &pid) == 2) {
                priv->dev_descriptor.idVendor = (uint16_t)vid;
                priv->dev_descriptor.idProduct = (uint16_t)pid;
@@ -1043,7 +1043,6 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d
        priv->port = port_number;
        dev->port_number = port_number;
        priv->depth = parent_priv->depth + 1;
-       priv->parent_dev = parent_dev;
        dev->parent_dev = parent_dev;
 
        // If the device address is already set, we can stop here
@@ -1521,9 +1520,16 @@ static int windows_get_device_list(struct libusb_context *ctx, struct discovered
                                                session_id, dev->bus_number, dev->device_address);
 
                                        priv = _device_priv(dev);
-                                       if (priv->parent_dev != NULL) {
-                                               if (priv->parent_dev != parent_dev) {
-                                                       usbi_err(ctx, "program assertion failed - existing device should share parent");
+                                       if ((parent_dev != NULL) && (dev->parent_dev != NULL)) {
+                                               if (dev->parent_dev != parent_dev) {
+                                                       // It is possible for the actual parent device to not have existed at the
+                                                       // time of enumeration, so the currently assigned parent may in fact be a
+                                                       // grandparent.  If the devices differ, we assume the "new" parent device
+                                                       // is in fact closer to the device.
+                                                        usbi_dbg("updating parent device [session %lX -> %lX]",
+                                                                dev->parent_dev->session_data, parent_dev->session_data);
+                                                       libusb_unref_device(dev->parent_dev);
+                                                       dev->parent_dev = parent_dev;
                                                } else {
                                                        // We hold a reference to parent_dev instance, but this device already
                                                        // has a parent_dev reference (only one per child)
index 49c1df5..a259374 100644 (file)
@@ -201,7 +201,6 @@ struct windows_device_priv {
        uint8_t depth; // distance to HCD
        uint8_t port;  // port number on the hub
        uint8_t active_config;
-       struct libusb_device *parent_dev; // access to parent is required for usermode ops
        struct windows_usb_api_backend const *apib;
        char *path;  // device interface path
        int sub_api; // for WinUSB-like APIs
@@ -231,7 +230,6 @@ static inline struct windows_device_priv *windows_device_priv_init(struct libusb
 
        p->depth = 0;
        p->port = 0;
-       p->parent_dev = NULL;
        p->path = NULL;
        p->apib = &usb_api_backend[USB_API_UNSUPPORTED];
        p->sub_api = SUB_API_NOTSET;
index e7cb421..59027da 100644 (file)
@@ -1 +1 @@
-#define LIBUSB_NANO 11150
+#define LIBUSB_NANO 11151