From 9bf44223d4c0eabbfbf8f9e979767fe424008ec0 Mon Sep 17 00:00:00 2001 From: Chris Dickens Date: Tue, 13 Sep 2016 22:09:50 -0700 Subject: [PATCH] Windows: Fix possible false error message during device enumeration 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 --- libusb/os/windows_winusb.c | 18 ++++++++++++------ libusb/os/windows_winusb.h | 2 -- libusb/version_nano.h | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libusb/os/windows_winusb.c b/libusb/os/windows_winusb.c index 81cceef..d1d2749 100644 --- a/libusb/os/windows_winusb.c +++ b/libusb/os/windows_winusb.c @@ -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) diff --git a/libusb/os/windows_winusb.h b/libusb/os/windows_winusb.h index 49c1df5..a259374 100644 --- a/libusb/os/windows_winusb.h +++ b/libusb/os/windows_winusb.h @@ -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; diff --git a/libusb/version_nano.h b/libusb/version_nano.h index e7cb421..59027da 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 11150 +#define LIBUSB_NANO 11151 -- 2.7.4