summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding2016-12-21 17:39:36 -0600
committerThierry Reding2017-01-20 09:25:53 -0600
commitf8484ccbd12ba33ea5b3895efb7a39d986271be0 (patch)
tree842d2450df0e3f9751d0c9253f4eab1342e36e89
parent2e57bba870399926e1a0d0be3f4918a0a8432474 (diff)
downloadexternal-libdrm-f8484ccbd12ba33ea5b3895efb7a39d986271be0.tar.gz
external-libdrm-f8484ccbd12ba33ea5b3895efb7a39d986271be0.tar.xz
external-libdrm-f8484ccbd12ba33ea5b3895efb7a39d986271be0.zip
xf86drm: Add USB support
Allow DRM/KMS devices hosted on USB to be detected by the drmDevice infrastructure. v4: - continue on error to process USB devices v3: - guard Linux-specific sysfs parsing code with #ifdef __linux__ v2: - make sysfs_uevent_get() more flexible using a format string Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
-rw-r--r--xf86drm.c175
-rw-r--r--xf86drm.h13
2 files changed, 188 insertions, 0 deletions
diff --git a/xf86drm.c b/xf86drm.c
index 7766bfe9..58e9ce04 100644
--- a/xf86drm.c
+++ b/xf86drm.c
@@ -2886,6 +2886,50 @@ char *drmGetRenderDeviceNameFromFd(int fd)
2886 return drmGetMinorNameForFD(fd, DRM_NODE_RENDER); 2886 return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
2887} 2887}
2888 2888
2889#ifdef __linux__
2890static char * DRM_PRINTFLIKE(2, 3)
2891sysfs_uevent_get(const char *path, const char *fmt, ...)
2892{
2893 char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL;
2894 size_t size = 0, len;
2895 ssize_t num;
2896 va_list ap;
2897 FILE *fp;
2898
2899 va_start(ap, fmt);
2900 num = vasprintf(&key, fmt, ap);
2901 va_end(ap);
2902 len = num;
2903
2904 snprintf(filename, sizeof(filename), "%s/uevent", path);
2905
2906 fp = fopen(filename, "r");
2907 if (!fp) {
2908 free(key);
2909 return NULL;
2910 }
2911
2912 while ((num = getline(&line, &size, fp)) >= 0) {
2913 if ((strncmp(line, key, len) == 0) && (line[len] == '=')) {
2914 char *start = line + len + 1, *end = line + num - 1;
2915
2916 if (*end != '\n')
2917 end++;
2918
2919 value = strndup(start, end - start);
2920 break;
2921 }
2922 }
2923
2924 free(line);
2925 fclose(fp);
2926
2927 free(key);
2928
2929 return value;
2930}
2931#endif
2932
2889static int drmParseSubsystemType(int maj, int min) 2933static int drmParseSubsystemType(int maj, int min)
2890{ 2934{
2891#ifdef __linux__ 2935#ifdef __linux__
@@ -2906,6 +2950,9 @@ static int drmParseSubsystemType(int maj, int min)
2906 if (strncmp(name, "/pci", 4) == 0) 2950 if (strncmp(name, "/pci", 4) == 0)
2907 return DRM_BUS_PCI; 2951 return DRM_BUS_PCI;
2908 2952
2953 if (strncmp(name, "/usb", 4) == 0)
2954 return DRM_BUS_USB;
2955
2909 return -EINVAL; 2956 return -EINVAL;
2910#elif defined(__OpenBSD__) 2957#elif defined(__OpenBSD__)
2911 return DRM_BUS_PCI; 2958 return DRM_BUS_PCI;
@@ -2992,6 +3039,10 @@ static int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b)
2992 switch (a->bustype) { 3039 switch (a->bustype) {
2993 case DRM_BUS_PCI: 3040 case DRM_BUS_PCI:
2994 return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)); 3041 return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo));
3042
3043 case DRM_BUS_USB:
3044 return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo));
3045
2995 default: 3046 default:
2996 break; 3047 break;
2997 } 3048 }
@@ -3235,6 +3286,113 @@ free_device:
3235 return ret; 3286 return ret;
3236} 3287}
3237 3288
3289static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info)
3290{
3291#ifdef __linux__
3292 char path[PATH_MAX + 1], *value;
3293 unsigned int bus, dev;
3294 int ret;
3295
3296 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3297
3298 value = sysfs_uevent_get(path, "BUSNUM");
3299 if (!value)
3300 return -ENOENT;
3301
3302 ret = sscanf(value, "%03u", &bus);
3303 free(value);
3304
3305 if (ret <= 0)
3306 return -errno;
3307
3308 value = sysfs_uevent_get(path, "DEVNUM");
3309 if (!value)
3310 return -ENOENT;
3311
3312 ret = sscanf(value, "%03u", &dev);
3313 free(value);
3314
3315 if (ret <= 0)
3316 return -errno;
3317
3318 info->bus = bus;
3319 info->dev = dev;
3320
3321 return 0;
3322#else
3323#warning "Missing implementation of drmParseUsbBusInfo"
3324 return -EINVAL;
3325#endif
3326}
3327
3328static int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info)
3329{
3330#ifdef __linux__
3331 char path[PATH_MAX + 1], *value;
3332 unsigned int vendor, product;
3333 int ret;
3334
3335 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3336
3337 value = sysfs_uevent_get(path, "PRODUCT");
3338 if (!value)
3339 return -ENOENT;
3340
3341 ret = sscanf(value, "%x/%x", &vendor, &product);
3342 free(value);
3343
3344 if (ret <= 0)
3345 return -errno;
3346
3347 info->vendor = vendor;
3348 info->product = product;
3349
3350 return 0;
3351#else
3352#warning "Missing implementation of drmParseUsbDeviceInfo"
3353 return -EINVAL;
3354#endif
3355}
3356
3357static int drmProcessUsbDevice(drmDevicePtr *device, const char *node,
3358 int node_type, int maj, int min,
3359 bool fetch_deviceinfo, uint32_t flags)
3360{
3361 drmDevicePtr dev;
3362 char *ptr;
3363 int ret;
3364
3365 dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo),
3366 sizeof(drmUsbDeviceInfo), &ptr);
3367 if (!dev)
3368 return -ENOMEM;
3369
3370 dev->bustype = DRM_BUS_USB;
3371
3372 dev->businfo.usb = (drmUsbBusInfoPtr)ptr;
3373
3374 ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb);
3375 if (ret < 0)
3376 goto free_device;
3377
3378 if (fetch_deviceinfo) {
3379 ptr += sizeof(drmUsbBusInfo);
3380 dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr;
3381
3382 ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb);
3383 if (ret < 0)
3384 goto free_device;
3385 }
3386
3387 *device = dev;
3388
3389 return 0;
3390
3391free_device:
3392 free(dev);
3393 return ret;
3394}
3395
3238/* Consider devices located on the same bus as duplicate and fold the respective 3396/* Consider devices located on the same bus as duplicate and fold the respective
3239 * entries into a single one. 3397 * entries into a single one.
3240 * 3398 *
@@ -3410,6 +3568,14 @@ int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
3410 continue; 3568 continue;
3411 3569
3412 break; 3570 break;
3571
3572 case DRM_BUS_USB:
3573 ret = drmProcessUsbDevice(&d, node, node_type, maj, min, true, flags);
3574 if (ret)
3575 continue;
3576
3577 break;
3578
3413 default: 3579 default:
3414 continue; 3580 continue;
3415 } 3581 }
@@ -3541,6 +3707,15 @@ int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices)
3541 continue; 3707 continue;
3542 3708
3543 break; 3709 break;
3710
3711 case DRM_BUS_USB:
3712 ret = drmProcessUsbDevice(&device, node, node_type, maj, min,
3713 devices != NULL, flags);
3714 if (ret)
3715 goto free_devices;
3716
3717 break;
3718
3544 default: 3719 default:
3545 continue; 3720 continue;
3546 } 3721 }
diff --git a/xf86drm.h b/xf86drm.h
index b340fc46..65d53219 100644
--- a/xf86drm.h
+++ b/xf86drm.h
@@ -767,6 +767,7 @@ extern char *drmGetPrimaryDeviceNameFromFd(int fd);
767extern char *drmGetRenderDeviceNameFromFd(int fd); 767extern char *drmGetRenderDeviceNameFromFd(int fd);
768 768
769#define DRM_BUS_PCI 0 769#define DRM_BUS_PCI 0
770#define DRM_BUS_USB 1
770 771
771typedef struct _drmPciBusInfo { 772typedef struct _drmPciBusInfo {
772 uint16_t domain; 773 uint16_t domain;
@@ -783,15 +784,27 @@ typedef struct _drmPciDeviceInfo {
783 uint8_t revision_id; 784 uint8_t revision_id;
784} drmPciDeviceInfo, *drmPciDeviceInfoPtr; 785} drmPciDeviceInfo, *drmPciDeviceInfoPtr;
785 786
787typedef struct _drmUsbBusInfo {
788 uint8_t bus;
789 uint8_t dev;
790} drmUsbBusInfo, *drmUsbBusInfoPtr;
791
792typedef struct _drmUsbDeviceInfo {
793 uint16_t vendor;
794 uint16_t product;
795} drmUsbDeviceInfo, *drmUsbDeviceInfoPtr;
796
786typedef struct _drmDevice { 797typedef struct _drmDevice {
787 char **nodes; /* DRM_NODE_MAX sized array */ 798 char **nodes; /* DRM_NODE_MAX sized array */
788 int available_nodes; /* DRM_NODE_* bitmask */ 799 int available_nodes; /* DRM_NODE_* bitmask */
789 int bustype; 800 int bustype;
790 union { 801 union {
791 drmPciBusInfoPtr pci; 802 drmPciBusInfoPtr pci;
803 drmUsbBusInfoPtr usb;
792 } businfo; 804 } businfo;
793 union { 805 union {
794 drmPciDeviceInfoPtr pci; 806 drmPciDeviceInfoPtr pci;
807 drmUsbDeviceInfoPtr usb;
795 } deviceinfo; 808 } deviceinfo;
796} drmDevice, *drmDevicePtr; 809} drmDevice, *drmDevicePtr;
797 810