summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Anderson <scott@anderso.nz>2020-01-31 16:18:19 +1300
committerEmil Velikov <emil.l.velikov@gmail.com>2020-04-24 08:53:53 +0000
commitbf63f8acdc94164ad29d1d56270964245b39f277 (patch)
tree9e69372a0bdb27df7b2491adceaab996cbdeaf1d
parent57df07572ce45a1b60bae6fb89770388d3abd6dd (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.c48
1 files changed, 46 insertions, 2 deletions
diff --git a/xf86drm.c b/xf86drm.c
index a341c4a7..08e5cafb 100644
--- a/xf86drm.c
+++ b/xf86drm.c
@@ -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)