diff options
-rw-r--r-- | libusb/os/linux_usbfs.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c index 2b81189..b814ff9 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -1081,6 +1081,74 @@ static int sysfs_scan_device(struct libusb_context *ctx, devname); } +static void sysfs_analyze_topology(struct discovered_devs *discdevs) +{ + struct linux_device_priv *priv; + int i, j; + struct libusb_device *dev1, *dev2; + const char *sysfs_dir1, *sysfs_dir2; + const char *p; + int n, boundary_char; + + /* Fill in the port_number and parent_dev fields for each device */ + + for (i = 0; i < discdevs->len; ++i) { + dev1 = discdevs->devices[i]; + priv = _device_priv(dev1); + if (!priv) + continue; + sysfs_dir1 = priv->sysfs_dir; + + /* Root hubs have sysfs_dir names of the form "usbB", + * where B is the bus number. All other devices have + * sysfs_dir names of the form "B-P[.P ...]", where the + * P values are port numbers leading from the root hub + * to the device. + */ + + /* Root hubs don't have parents or port numbers */ + if (sysfs_dir1[0] == 'u') + continue; + + /* The rightmost component is the device's port number */ + p = strrchr(sysfs_dir1, '.'); + if (!p) { + p = strchr(sysfs_dir1, '-'); + if (!p) + continue; /* Should never happen */ + } + dev1->port_number = atoi(p + 1); + + /* Search for the parent device */ + boundary_char = *p; + n = p - sysfs_dir1; + for (j = 0; j < discdevs->len; ++j) { + dev2 = discdevs->devices[j]; + priv = _device_priv(dev2); + if (!priv) + continue; + sysfs_dir2 = priv->sysfs_dir; + + if (boundary_char == '-') { + /* The parent's name must begin with 'usb'; + * skip past that part of sysfs_dir2. + */ + if (sysfs_dir2[0] != 'u') + continue; + sysfs_dir2 += 3; + } + + /* The remainder of the parent's name must be equal to + * the first n bytes of sysfs_dir1. + */ + if (memcmp(sysfs_dir1, sysfs_dir2, n) == 0 && !sysfs_dir2[n]) { + dev1->parent_dev = dev2; + break; + } + } + } +} + static int sysfs_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs) { @@ -1113,6 +1181,7 @@ static int sysfs_get_device_list(struct libusb_context *ctx, if (!r) *_discdevs = discdevs; closedir(devices); + sysfs_analyze_topology(discdevs); return r; } |