[PATCH libdrm 2/3] xf86drm: Add USB support
Thierry Reding
thierry.reding at gmail.com
Fri Dec 23 17:49:16 UTC 2016
Allow DRM/KMS devices hosted on USB to be detected by the drmDevice
infrastructure.
Signed-off-by: Thierry Reding <thierry.reding at gmail.com>
---
Note that this is completely untested because I don't have a UDL device
for testing. I'm fairly confident that this will work, though, and it'd
be nice to include it before the new platform and host1x busses because
support for it existed in the kernel longer than for platform devices.
xf86drm.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
xf86drm.h | 13 ++++++
2 files changed, 156 insertions(+)
diff --git a/xf86drm.c b/xf86drm.c
index 6a271000af82..f0171c34c958 100644
--- a/xf86drm.c
+++ b/xf86drm.c
@@ -2902,6 +2902,9 @@ static int drmParseSubsystemType(int maj, int min)
if (strncmp(name, "/pci", 4) == 0)
return DRM_BUS_PCI;
+ if (strncmp(name, "/usb", 4) == 0)
+ return DRM_BUS_USB;
+
return -EINVAL;
#elif defined(__OpenBSD__)
return DRM_BUS_PCI;
@@ -2988,6 +2991,10 @@ static int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b)
switch (a->bustype) {
case DRM_BUS_PCI:
return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo));
+
+ case DRM_BUS_USB:
+ return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo));
+
default:
break;
}
@@ -3231,6 +3238,125 @@ free_device:
return ret;
}
+static char *sysfs_uevent_get(const char *path, const char *key)
+{
+ char filename[PATH_MAX], *line = NULL, *value = NULL;
+ size_t size = 0, len = strlen(key);
+ ssize_t num;
+ FILE *fp;
+
+ snprintf(filename, PATH_MAX, "%s/uevent", path);
+
+ fp = fopen(filename, "r");
+ if (!fp)
+ return NULL;
+
+ while ((num = getline(&line, &size, fp)) >= 0) {
+ if ((strncmp(line, key, len) == 0) && (line[len] == '=')) {
+ char *start = line + len + 1, *end = line + num - 1;
+
+ if (*end != '\n')
+ end++;
+
+ value = strndup(start, end - start);
+ break;
+ }
+ }
+
+ free(line);
+ fclose(fp);
+
+ return value;
+}
+
+static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info)
+{
+ char path[PATH_MAX + 1], *value;
+ unsigned int bus, dev;
+ int ret;
+
+ snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device", maj, min);
+
+ value = sysfs_uevent_get(path, "BUSNUM");
+ ret = sscanf(value, "%03u", &bus);
+ free(value);
+
+ if (ret <= 0)
+ return -errno;
+
+ value = sysfs_uevent_get(path, "DEVNUM");
+ ret = sscanf(value, "%03u", &dev);
+ free(value);
+
+ if (ret <= 0)
+ return -errno;
+
+ info->bus = bus;
+ info->dev = dev;
+
+ return 0;
+}
+
+static int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info)
+{
+ char path[PATH_MAX + 1], *value;
+ unsigned int vendor, product;
+ int ret;
+
+ snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device", maj, min);
+
+ value = sysfs_uevent_get(path, "PRODUCT");
+ ret = sscanf(value, "%x/%x", &vendor, &product);
+ free(value);
+
+ if (ret <= 0)
+ return -errno;
+
+ info->vendor = vendor;
+ info->product = product;
+
+ return 0;
+}
+
+static int drmProcessUsbDevice(drmDevicePtr *device, const char *node,
+ int node_type, int maj, int min,
+ bool fetch_deviceinfo, uint32_t flags)
+{
+ drmDevicePtr dev;
+ char *ptr;
+ int ret;
+
+ dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo),
+ sizeof(drmUsbDeviceInfo), &ptr);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->bustype = DRM_BUS_USB;
+
+ dev->businfo.usb = (drmUsbBusInfoPtr)ptr;
+
+ ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb);
+ if (ret < 0)
+ goto free_device;
+
+ if (fetch_deviceinfo) {
+ ptr += sizeof(drmUsbBusInfo);
+ dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr;
+
+ ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb);
+ if (ret < 0)
+ goto free_device;
+ }
+
+ *device = dev;
+
+ return 0;
+
+free_device:
+ free(dev);
+ return ret;
+}
+
/* Consider devices located on the same bus as duplicate and fold the respective
* entries into a single one.
*
@@ -3402,6 +3528,14 @@ int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
goto free_devices;
break;
+
+ case DRM_BUS_USB:
+ ret = drmProcessUsbDevice(&d, node, node_type, maj, min, true, flags);
+ if (ret)
+ goto free_devices;
+
+ break;
+
default:
continue;
}
@@ -3533,6 +3667,15 @@ int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices)
goto free_devices;
break;
+
+ case DRM_BUS_USB:
+ ret = drmProcessUsbDevice(&device, node, node_type, maj, min,
+ devices != NULL, flags);
+ if (ret)
+ goto free_devices;
+
+ break;
+
default:
continue;
}
diff --git a/xf86drm.h b/xf86drm.h
index b340fc46cd44..65d5321950fc 100644
--- a/xf86drm.h
+++ b/xf86drm.h
@@ -767,6 +767,7 @@ extern char *drmGetPrimaryDeviceNameFromFd(int fd);
extern char *drmGetRenderDeviceNameFromFd(int fd);
#define DRM_BUS_PCI 0
+#define DRM_BUS_USB 1
typedef struct _drmPciBusInfo {
uint16_t domain;
@@ -783,15 +784,27 @@ typedef struct _drmPciDeviceInfo {
uint8_t revision_id;
} drmPciDeviceInfo, *drmPciDeviceInfoPtr;
+typedef struct _drmUsbBusInfo {
+ uint8_t bus;
+ uint8_t dev;
+} drmUsbBusInfo, *drmUsbBusInfoPtr;
+
+typedef struct _drmUsbDeviceInfo {
+ uint16_t vendor;
+ uint16_t product;
+} drmUsbDeviceInfo, *drmUsbDeviceInfoPtr;
+
typedef struct _drmDevice {
char **nodes; /* DRM_NODE_MAX sized array */
int available_nodes; /* DRM_NODE_* bitmask */
int bustype;
union {
drmPciBusInfoPtr pci;
+ drmUsbBusInfoPtr usb;
} businfo;
union {
drmPciDeviceInfoPtr pci;
+ drmUsbDeviceInfoPtr usb;
} deviceinfo;
} drmDevice, *drmDevicePtr;
--
2.11.0
More information about the dri-devel
mailing list