> From: Thierry Reding <thierry.reding@xxxxxxxxx> > Date: Thu, 12 Jan 2017 23:04:27 +0100 > > Allow DRM/KMS devices hosted on USB to be detected by the drmDevice > infrastructure. > > v2: > - make sysfs_uevent_get() more flexible using a format string > > Signed-off-by: Thierry Reding <thierry.reding@xxxxxxxxx> All this sysfs parsing stuff is highly Linux-specific and should probably be #ifdef __linux__. Returning -EINVAL on non-Linux platforms for usb and host1x should be fine. Cheers, Mark > --- > xf86drm.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > xf86drm.h | 13 +++++ > 2 files changed, 176 insertions(+) > > diff --git a/xf86drm.c b/xf86drm.c > index c123650a1e23..27cd6eb5193e 100644 > --- a/xf86drm.c > +++ b/xf86drm.c > @@ -2906,6 +2906,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; > @@ -2992,6 +2995,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; > } > @@ -3235,6 +3242,145 @@ free_device: > return ret; > } > > +static char * DRM_PRINTFLIKE(2, 3) > +sysfs_uevent_get(const char *path, const char *fmt, ...) > +{ > + char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL; > + size_t size = 0, len; > + ssize_t num; > + va_list ap; > + FILE *fp; > + > + va_start(ap, fmt); > + num = vasprintf(&key, fmt, ap); > + va_end(ap); > + len = num; > + > + snprintf(filename, sizeof(filename), "%s/uevent", path); > + > + fp = fopen(filename, "r"); > + if (!fp) { > + free(key); > + 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); > + > + free(key); > + > + 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, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); > + > + value = sysfs_uevent_get(path, "BUSNUM"); > + if (!value) > + return -ENOENT; > + > + ret = sscanf(value, "%03u", &bus); > + free(value); > + > + if (ret <= 0) > + return -errno; > + > + value = sysfs_uevent_get(path, "DEVNUM"); > + if (!value) > + return -ENOENT; > + > + 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, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); > + > + value = sysfs_uevent_get(path, "PRODUCT"); > + if (!value) > + return -ENOENT; > + > + 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. > * > @@ -3410,6 +3556,14 @@ int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) > continue; > > break; > + > + case DRM_BUS_USB: > + ret = drmProcessUsbDevice(&d, node, node_type, maj, min, true, flags); > + if (ret) > + goto free_devices; > + > + break; > + > default: > continue; > } > @@ -3541,6 +3695,15 @@ int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices) > continue; > > 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 > > _______________________________________________ > xorg-devel@xxxxxxxxxxx: X.Org development > Archives: http://lists.x.org/archives/xorg-devel > Info: https://lists.x.org/mailman/listinfo/xorg-devel > > _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel