linux: Deal with devices being enumerated before their parents are
authorHans de Goede <hdegoede@redhat.com>
Thu, 16 May 2013 15:13:11 +0000 (17:13 +0200)
committerHans de Goede <hdegoede@redhat.com>
Thu, 16 May 2013 15:18:33 +0000 (17:18 +0200)
The linux netlink enumeration code processes devices in readdir order, which
means devices may get enumerated before their parent is, IE on my system
readdir order is (ls -U)
1-1   usb4       2-1.8        6-0:1.0    1-1.4.3    1-1.4.4.1:1.0
2-1   usb5       6-1.4        6-1:1.0    1-1.4.4    1-1.4.4.1:1.1
6-1   usb6       3-0:1.0      2-1.8:1.0  1-0:1.0    1-1.4.4.1:1.2
7-1   usb7       1-1.4.3:1.0  2-1.8:1.1  1-1:1.0
usb1  1-1.4.4.1  1-1.4.4:1.0  2-1.8:1.2  6-1.4:1.0
usb2  1-1.4:1.0  4-0:1.0      7-0:1.0    2-0:1.0
usb3  1-1.4      5-0:1.0      7-1:1.0    2-1:1.0

So 1.4.4.1 will get added (way) before 1.4.4 and indeed:
[ 0.002243] [00004055] libusbx: debug [linux_get_device_address] scan 1-1.4.4.1
Dev 0x1973bc0 (1-1.4.4.1) has parent (nil)

This patch fixes this by forcing enumeration of the parent from
linux_parent_dev.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
libusb/os/linux_usbfs.c
libusb/version_nano.h

index 0159f81..bb8e8c2 100644 (file)
@@ -118,6 +118,7 @@ static usbi_mutex_static_t hotplug_lock = USBI_MUTEX_INITIALIZER;
 static int linux_start_event_monitor(void);
 static int linux_stop_event_monitor(void);
 static int linux_scan_devices(struct libusb_context *ctx);
+static int sysfs_scan_device(struct libusb_context *ctx, const char *devname);
 
 #if !defined(USE_UDEV)
 static int linux_default_scan_devices (struct libusb_context *ctx);
@@ -1098,7 +1099,7 @@ static struct libusb_device *linux_parent_dev(struct libusb_context *ctx, const
 {
        struct libusb_device *dev, *parent_dev = NULL;
        char *parent_sysfs_dir, *tmp;
-       int ret;
+       int ret, add_parent = 1;
 
        /* XXX -- can we figure out the topology when using usbfs? */
        if (NULL == sysfs_dir || 0 == strncmp(sysfs_dir, "usb", 3)) {
@@ -1126,6 +1127,7 @@ static struct libusb_device *linux_parent_dev(struct libusb_context *ctx, const
                }
        }
 
+retry:
        /* find the parent in the context */
        usbi_mutex_lock(&ctx->usb_devs_lock);
        list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) {
@@ -1137,6 +1139,14 @@ static struct libusb_device *linux_parent_dev(struct libusb_context *ctx, const
        }
        usbi_mutex_unlock(&ctx->usb_devs_lock);
 
+       if (!parent_dev && add_parent) {
+               usbi_dbg("parent_dev %s not enumerated yet, enumerating now",
+                        parent_sysfs_dir);
+               sysfs_scan_device(ctx, parent_sysfs_dir);
+               add_parent = 0;
+               goto retry;
+       }
+
        free (parent_sysfs_dir);
        return parent_dev;
 }
@@ -1305,6 +1315,7 @@ static int usbfs_get_device_list(struct libusb_context *ctx)
        return r;
 
 }
+#endif
 
 static int sysfs_scan_device(struct libusb_context *ctx, const char *devname)
 {
@@ -1320,6 +1331,7 @@ static int sysfs_scan_device(struct libusb_context *ctx, const char *devname)
                devname);
 }
 
+#if !defined(USE_UDEV)
 static int sysfs_get_device_list(struct libusb_context *ctx)
 {
        DIR *devices = opendir(SYSFS_DEVICE_PATH);
index 9d2fc4a..880c722 100644 (file)
@@ -1 +1 @@
-#define LIBUSB_NANO 10682
+#define LIBUSB_NANO 10683