diff options
author | Scott Anderson <scott@anderso.nz> | 2020-01-31 16:18:19 +1300 |
---|---|---|
committer | Emil Velikov <emil.l.velikov@gmail.com> | 2020-04-24 08:53:53 +0000 |
commit | bf63f8acdc94164ad29d1d56270964245b39f277 (patch) | |
tree | 9e69372a0bdb27df7b2491adceaab996cbdeaf1d | |
parent | 57df07572ce45a1b60bae6fb89770388d3abd6dd (diff) |
libdrm: Handle usb_interface devices for usb parsing
Currently the code expects that the device found at
/sys/char/$maj:$min/device for USB devices is a "usb_device". However,
at least for some devices, such as for the udl driver, they are instead
a "usb_interface".
A usb_interface is a child of the usb_device we're interested in, so we
walk up one in the /sys path to get there.
For example, with a USB device I have, trimmed to show the relevant
information:
```
$ udevadm info /dev/dri/card1
P: /devices/pci0000:00/0000:00:01.3/0000:02:00.0/usb1/1-4/1-4:1.0/drm/card1
E: DEVTYPE=drm_minor
$ udevadm info /sys/devices/pci0000:00/0000:00:01.3/0000:02:00.0/usb1/1-4/1-4:1.0
E: DEVTYPE=usb_interface
E: DRIVER=udl
$ udevadm info /sys/devices/pci0000:00/0000:00:01.3/0000:02:00.0/usb1/1-4
E: DEVTYPE=usb_device
E: DRIVER=usb
E: BUSNUM=001
E: DEVNUM=009
```
Signed-off-by: Scott Anderson <scott@anderso.nz>
-rw-r--r-- | xf86drm.c | 48 |
1 files changed, 46 insertions, 2 deletions
@@ -3611,6 +3611,46 @@ free_device: return ret; } +#ifdef __linux__ +static int drm_usb_dev_path(int maj, int min, char *path, size_t len) +{ + char *value, *tmp_path, *slash; + + snprintf(path, len, "/sys/dev/char/%d:%d/device", maj, min); + + value = sysfs_uevent_get(path, "DEVTYPE"); + if (!value) + return -ENOENT; + + if (strcmp(value, "usb_device") == 0) + return 0; + if (strcmp(value, "usb_interface") != 0) + return -ENOTSUP; + + /* The parent of a usb_interface is a usb_device */ + + tmp_path = realpath(path, NULL); + if (!tmp_path) + return -errno; + + slash = strrchr(tmp_path, '/'); + if (!slash) { + free(tmp_path); + return -EINVAL; + } + + *slash = '\0'; + + if (snprintf(path, len, "%s", tmp_path) >= (int)len) { + free(tmp_path); + return -EINVAL; + } + + free(tmp_path); + return 0; +} +#endif + static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info) { #ifdef __linux__ @@ -3618,7 +3658,9 @@ static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info) unsigned int bus, dev; int ret; - snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + ret = drm_usb_dev_path(maj, min, path, sizeof(path)); + if (ret < 0) + return ret; value = sysfs_uevent_get(path, "BUSNUM"); if (!value) @@ -3657,7 +3699,9 @@ static int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info) unsigned int vendor, product; int ret; - snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + ret = drm_usb_dev_path(maj, min, path, sizeof(path)); + if (ret < 0) + return ret; value = sysfs_uevent_get(path, "PRODUCT"); if (!value) |