mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usbutils.git
synced 2024-11-15 06:53:43 +08:00
sysfs: Don't return bogus data for devices under a hub
commitdddb696e01
("lsusb: Read unkown names from sysfs device desc.") added code to query a device's self-reported vendor and product names from sysfs in the case where no names were present in the udev hwdb. However, as far as I can tell that code was and still is totally broken for any device that isn't directly under a root hub: this is because it uses the libusb_get_port_number() function, which only returns the leaf port number, but treats the returned number as if it's a full device path. For example, when trying to query sysfs for the device 2-8.3 (a device on Port 3 of a hub that's on Port 8 of Bus 2), it will instead erroneously query device 2-3, ignoring the first hub altogether. This results in nonsensical output from lsusb, such as a device identified as a "Bose Corp. Steam Controller". To fix the issue, use the libusb_get_port_numbers() function to get a full list of port numbers from the root and use that to construct the proper dotted devpath. Additionally, special case root devices, which have the sysfs name "usbN", where "N" is the bus number. Thanks to Tian Yunhao, who submitted a different fix for this same issue, for spotting that last piece. Fixes:dddb696e01
("lsusb: Read unkown names from sysfs device desc.") Signed-off-by: Thomas Hebb <tommyhebb@gmail.com>
This commit is contained in:
parent
c37f33cf31
commit
151eea8fb4
7
lsusb.c
7
lsusb.c
@ -3703,7 +3703,8 @@ static int list_devices(libusb_context *ctx, int busnum, int devnum, int vendori
|
||||
libusb_device *dev = list[i];
|
||||
uint8_t bnum = libusb_get_bus_number(dev);
|
||||
uint8_t dnum = libusb_get_device_address(dev);
|
||||
uint8_t pnum = libusb_get_port_number(dev);
|
||||
char sysfs_name[PATH_MAX];
|
||||
get_sysfs_name(sysfs_name, sizeof(sysfs_name), dev);
|
||||
|
||||
if ((busnum != -1 && busnum != bnum) ||
|
||||
(devnum != -1 && devnum != dnum))
|
||||
@ -3716,13 +3717,13 @@ static int list_devices(libusb_context *ctx, int busnum, int devnum, int vendori
|
||||
|
||||
vendor_len = get_vendor_string(vendor, sizeof(vendor), desc.idVendor);
|
||||
if (vendor_len == 0)
|
||||
read_sysfs_prop(vendor, sizeof(vendor), bnum, pnum,
|
||||
read_sysfs_prop(vendor, sizeof(vendor), sysfs_name,
|
||||
"manufacturer");
|
||||
|
||||
product_len = get_product_string(product, sizeof(product),
|
||||
desc.idVendor, desc.idProduct);
|
||||
if (product_len == 0)
|
||||
read_sysfs_prop(product, sizeof(product), bnum, pnum,
|
||||
read_sysfs_prop(product, sizeof(product), sysfs_name,
|
||||
"product");
|
||||
|
||||
if (verblevel > 0)
|
||||
|
38
sysfs.c
38
sysfs.c
@ -10,17 +10,49 @@
|
||||
#include <stdio.h>
|
||||
#include <linux/limits.h>
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#include "sysfs.h"
|
||||
|
||||
#define SYSFS_DEV_ATTR_PATH "/sys/bus/usb/devices/%d-%d/%s"
|
||||
/*
|
||||
* The documentation of libusb_get_port_numbers() says "As per the USB 3.0
|
||||
* specs, the current maximum limit for the depth is 7."
|
||||
*/
|
||||
#define USB_MAX_DEPTH 7
|
||||
|
||||
int read_sysfs_prop(char *buf, size_t size, uint8_t bnum, uint8_t pnum, char *propname)
|
||||
#define SYSFS_DEV_ATTR_PATH "/sys/bus/usb/devices/%s/%s"
|
||||
|
||||
int get_sysfs_name(char *buf, size_t size, libusb_device *dev)
|
||||
{
|
||||
int len = 0;
|
||||
uint8_t bnum = libusb_get_bus_number(dev);
|
||||
uint8_t pnums[USB_MAX_DEPTH];
|
||||
int num_pnums;
|
||||
|
||||
buf[0] = '\0';
|
||||
|
||||
num_pnums = libusb_get_port_numbers(dev, pnums, sizeof(pnums));
|
||||
if (num_pnums == LIBUSB_ERROR_OVERFLOW) {
|
||||
return -1;
|
||||
} else if (num_pnums == 0) {
|
||||
/* Special-case root devices */
|
||||
return snprintf(buf, size, "usb%d", bnum);
|
||||
}
|
||||
|
||||
len += snprintf(buf, size, "%d-", bnum);
|
||||
for (int i = 0; i < num_pnums; i++)
|
||||
len += snprintf(buf + len, size - len, i ? ".%d" : "%d", pnums[i]);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int read_sysfs_prop(char *buf, size_t size, char *sysfs_name, char *propname)
|
||||
{
|
||||
int n, fd;
|
||||
char path[PATH_MAX];
|
||||
|
||||
buf[0] = '\0';
|
||||
snprintf(path, sizeof(path), SYSFS_DEV_ATTR_PATH, bnum, pnum, propname);
|
||||
snprintf(path, sizeof(path), SYSFS_DEV_ATTR_PATH, sysfs_name, propname);
|
||||
fd = open(path, O_RDONLY);
|
||||
|
||||
if (fd == -1)
|
||||
|
3
sysfs.h
3
sysfs.h
@ -7,7 +7,8 @@
|
||||
#define _SYSFS_H
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
extern int read_sysfs_prop(char *buf, size_t size, uint8_t bnum, uint8_t pnum, char *propname);
|
||||
int get_sysfs_name(char *buf, size_t size, libusb_device *dev);
|
||||
extern int read_sysfs_prop(char *buf, size_t size, char *sysfs_name, char *propname);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
#endif /* _SYSFS_H */
|
||||
|
Loading…
Reference in New Issue
Block a user