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 <christopher.a.dickens@gmail.com>
This commit is contained in:
Chris Dickens
2016-09-13 22:09:50 -07:00
committed by Nathan Hjelm
parent 4eca418ef5
commit 9bf44223d4
3 changed files with 13 additions and 9 deletions
+12 -6
View 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)
-2
View 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;
+1 -1
View File
@@ -1 +1 @@
#define LIBUSB_NANO 11150
#define LIBUSB_NANO 11151