summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding2016-12-21 10:59:04 -0600
committerThierry Reding2017-01-20 09:27:20 -0600
commit7b1f37f474d6bdf09b0a7f17bdb89398dbcf0c74 (patch)
tree58f4d7cbadc43648b2a063ab1b013f50253a4dcf
parentf8484ccbd12ba33ea5b3895efb7a39d986271be0 (diff)
downloadexternal-libdrm-7b1f37f474d6bdf09b0a7f17bdb89398dbcf0c74.tar.gz
external-libdrm-7b1f37f474d6bdf09b0a7f17bdb89398dbcf0c74.tar.xz
external-libdrm-7b1f37f474d6bdf09b0a7f17bdb89398dbcf0c74.zip
xf86drm: Add platform and host1x bus support
ARM SoCs usually have their DRM/KMS devices on the platform bus, so add support for that to enable these devices to be used with the drmDevice infrastructure. NVIDIA Tegra SoCs have an additional level in the hierarchy and DRM/KMS devices can also be on the host1x bus. This is mostly equivalent to the platform bus. v4: - continue on error to process platform or host1x device v3: - guard Linux-specific sysfs parsing code with #ifdef __linux__ v2: - be careful not to overflow the full name - read compatible strings into device info Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com> Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--xf86drm.c300
-rw-r--r--xf86drm.h30
2 files changed, 328 insertions, 2 deletions
diff --git a/xf86drm.c b/xf86drm.c
index 58e9ce04..89181c81 100644
--- a/xf86drm.c
+++ b/xf86drm.c
@@ -2953,6 +2953,12 @@ static int drmParseSubsystemType(int maj, int min)
2953 if (strncmp(name, "/usb", 4) == 0) 2953 if (strncmp(name, "/usb", 4) == 0)
2954 return DRM_BUS_USB; 2954 return DRM_BUS_USB;
2955 2955
2956 if (strncmp(name, "/platform", 9) == 0)
2957 return DRM_BUS_PLATFORM;
2958
2959 if (strncmp(name, "/host1x", 7) == 0)
2960 return DRM_BUS_HOST1X;
2961
2956 return -EINVAL; 2962 return -EINVAL;
2957#elif defined(__OpenBSD__) 2963#elif defined(__OpenBSD__)
2958 return DRM_BUS_PCI; 2964 return DRM_BUS_PCI;
@@ -3043,6 +3049,12 @@ static int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b)
3043 case DRM_BUS_USB: 3049 case DRM_BUS_USB:
3044 return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)); 3050 return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo));
3045 3051
3052 case DRM_BUS_PLATFORM:
3053 return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo));
3054
3055 case DRM_BUS_HOST1X:
3056 return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo));
3057
3046 default: 3058 default:
3047 break; 3059 break;
3048 } 3060 }
@@ -3187,11 +3199,55 @@ static int drmParsePciDeviceInfo(int maj, int min,
3187#endif 3199#endif
3188} 3200}
3189 3201
3202static void drmFreePlatformDevice(drmDevicePtr device)
3203{
3204 if (device->deviceinfo.platform) {
3205 if (device->deviceinfo.platform->compatible) {
3206 char **compatible = device->deviceinfo.platform->compatible;
3207
3208 while (*compatible) {
3209 free(*compatible);
3210 compatible++;
3211 }
3212
3213 free(device->deviceinfo.platform->compatible);
3214 }
3215 }
3216}
3217
3218static void drmFreeHost1xDevice(drmDevicePtr device)
3219{
3220 if (device->deviceinfo.host1x) {
3221 if (device->deviceinfo.host1x->compatible) {
3222 char **compatible = device->deviceinfo.host1x->compatible;
3223
3224 while (*compatible) {
3225 free(*compatible);
3226 compatible++;
3227 }
3228
3229 free(device->deviceinfo.host1x->compatible);
3230 }
3231 }
3232}
3233
3190void drmFreeDevice(drmDevicePtr *device) 3234void drmFreeDevice(drmDevicePtr *device)
3191{ 3235{
3192 if (device == NULL) 3236 if (device == NULL)
3193 return; 3237 return;
3194 3238
3239 if (*device) {
3240 switch ((*device)->bustype) {
3241 case DRM_BUS_PLATFORM:
3242 drmFreePlatformDevice(*device);
3243 break;
3244
3245 case DRM_BUS_HOST1X:
3246 drmFreeHost1xDevice(*device);
3247 break;
3248 }
3249 }
3250
3195 free(*device); 3251 free(*device);
3196 *device = NULL; 3252 *device = NULL;
3197} 3253}
@@ -3393,6 +3449,220 @@ free_device:
3393 return ret; 3449 return ret;
3394} 3450}
3395 3451
3452static int drmParsePlatformBusInfo(int maj, int min, drmPlatformBusInfoPtr info)
3453{
3454#ifdef __linux__
3455 char path[PATH_MAX + 1], *name;
3456
3457 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3458
3459 name = sysfs_uevent_get(path, "OF_FULLNAME");
3460 if (!name)
3461 return -ENOENT;
3462
3463 strncpy(info->fullname, name, DRM_PLATFORM_DEVICE_NAME_LEN);
3464 info->fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0';
3465 free(name);
3466
3467 return 0;
3468#else
3469#warning "Missing implementation of drmParsePlatformBusInfo"
3470 return -EINVAL;
3471#endif
3472}
3473
3474static int drmParsePlatformDeviceInfo(int maj, int min,
3475 drmPlatformDeviceInfoPtr info)
3476{
3477#ifdef __linux__
3478 char path[PATH_MAX + 1], *value;
3479 unsigned int count, i;
3480 int err;
3481
3482 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3483
3484 value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
3485 if (!value)
3486 return -ENOENT;
3487
3488 sscanf(value, "%u", &count);
3489 free(value);
3490
3491 info->compatible = calloc(count + 1, sizeof(*info->compatible));
3492 if (!info->compatible)
3493 return -ENOMEM;
3494
3495 for (i = 0; i < count; i++) {
3496 value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
3497 if (!value) {
3498 err = -ENOENT;
3499 goto free;
3500 }
3501
3502 info->compatible[i] = value;
3503 }
3504
3505 return 0;
3506
3507free:
3508 while (i--)
3509 free(info->compatible[i]);
3510
3511 free(info->compatible);
3512 return err;
3513#else
3514#warning "Missing implementation of drmParsePlatformDeviceInfo"
3515 return -EINVAL;
3516#endif
3517}
3518
3519static int drmProcessPlatformDevice(drmDevicePtr *device,
3520 const char *node, int node_type,
3521 int maj, int min, bool fetch_deviceinfo,
3522 uint32_t flags)
3523{
3524 drmDevicePtr dev;
3525 char *ptr;
3526 int ret;
3527
3528 dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo),
3529 sizeof(drmPlatformDeviceInfo), &ptr);
3530 if (!dev)
3531 return -ENOMEM;
3532
3533 dev->bustype = DRM_BUS_PLATFORM;
3534
3535 dev->businfo.platform = (drmPlatformBusInfoPtr)ptr;
3536
3537 ret = drmParsePlatformBusInfo(maj, min, dev->businfo.platform);
3538 if (ret < 0)
3539 goto free_device;
3540
3541 if (fetch_deviceinfo) {
3542 ptr += sizeof(drmPlatformBusInfo);
3543 dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr;
3544
3545 ret = drmParsePlatformDeviceInfo(maj, min, dev->deviceinfo.platform);
3546 if (ret < 0)
3547 goto free_device;
3548 }
3549
3550 *device = dev;
3551
3552 return 0;
3553
3554free_device:
3555 free(dev);
3556 return ret;
3557}
3558
3559static int drmParseHost1xBusInfo(int maj, int min, drmHost1xBusInfoPtr info)
3560{
3561#ifdef __linux__
3562 char path[PATH_MAX + 1], *name;
3563
3564 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3565
3566 name = sysfs_uevent_get(path, "OF_FULLNAME");
3567 if (!name)
3568 return -ENOENT;
3569
3570 strncpy(info->fullname, name, DRM_HOST1X_DEVICE_NAME_LEN);
3571 info->fullname[DRM_HOST1X_DEVICE_NAME_LEN - 1] = '\0';
3572 free(name);
3573
3574 return 0;
3575#else
3576#warning "Missing implementation of drmParseHost1xBusInfo"
3577 return -EINVAL;
3578#endif
3579}
3580
3581static int drmParseHost1xDeviceInfo(int maj, int min,
3582 drmHost1xDeviceInfoPtr info)
3583{
3584#ifdef __linux__
3585 char path[PATH_MAX + 1], *value;
3586 unsigned int count, i;
3587 int err;
3588
3589 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3590
3591 value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
3592 if (!value)
3593 return -ENOENT;
3594
3595 sscanf(value, "%u", &count);
3596 free(value);
3597
3598 info->compatible = calloc(count + 1, sizeof(*info->compatible));
3599 if (!info->compatible)
3600 return -ENOMEM;
3601
3602 for (i = 0; i < count; i++) {
3603 value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
3604 if (!value) {
3605 err = -ENOENT;
3606 goto free;
3607 }
3608
3609 info->compatible[i] = value;
3610 }
3611
3612 return 0;
3613
3614free:
3615 while (i--)
3616 free(info->compatible[i]);
3617
3618 free(info->compatible);
3619 return err;
3620#else
3621#warning "Missing implementation of drmParseHost1xDeviceInfo"
3622 return -EINVAL;
3623#endif
3624}
3625
3626static int drmProcessHost1xDevice(drmDevicePtr *device,
3627 const char *node, int node_type,
3628 int maj, int min, bool fetch_deviceinfo,
3629 uint32_t flags)
3630{
3631 drmDevicePtr dev;
3632 char *ptr;
3633 int ret;
3634
3635 dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo),
3636 sizeof(drmHost1xDeviceInfo), &ptr);
3637 if (!dev)
3638 return -ENOMEM;
3639
3640 dev->bustype = DRM_BUS_HOST1X;
3641
3642 dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr;
3643
3644 ret = drmParseHost1xBusInfo(maj, min, dev->businfo.host1x);
3645 if (ret < 0)
3646 goto free_device;
3647
3648 if (fetch_deviceinfo) {
3649 ptr += sizeof(drmHost1xBusInfo);
3650 dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr;
3651
3652 ret = drmParseHost1xDeviceInfo(maj, min, dev->deviceinfo.host1x);
3653 if (ret < 0)
3654 goto free_device;
3655 }
3656
3657 *device = dev;
3658
3659 return 0;
3660
3661free_device:
3662 free(dev);
3663 return ret;
3664}
3665
3396/* Consider devices located on the same bus as duplicate and fold the respective 3666/* Consider devices located on the same bus as duplicate and fold the respective
3397 * entries into a single one. 3667 * entries into a single one.
3398 * 3668 *
@@ -3576,6 +3846,20 @@ int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
3576 3846
3577 break; 3847 break;
3578 3848
3849 case DRM_BUS_PLATFORM:
3850 ret = drmProcessPlatformDevice(&d, node, node_type, maj, min, true, flags);
3851 if (ret)
3852 continue;
3853
3854 break;
3855
3856 case DRM_BUS_HOST1X:
3857 ret = drmProcessHost1xDevice(&d, node, node_type, maj, min, true, flags);
3858 if (ret)
3859 continue;
3860
3861 break;
3862
3579 default: 3863 default:
3580 continue; 3864 continue;
3581 } 3865 }
@@ -3716,6 +4000,22 @@ int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices)
3716 4000
3717 break; 4001 break;
3718 4002
4003 case DRM_BUS_PLATFORM:
4004 ret = drmProcessPlatformDevice(&device, node, node_type, maj, min,
4005 devices != NULL, flags);
4006 if (ret)
4007 goto free_devices;
4008
4009 break;
4010
4011 case DRM_BUS_HOST1X:
4012 ret = drmProcessHost1xDevice(&device, node, node_type, maj, min,
4013 devices != NULL, flags);
4014 if (ret)
4015 goto free_devices;
4016
4017 break;
4018
3719 default: 4019 default:
3720 continue; 4020 continue;
3721 } 4021 }
diff --git a/xf86drm.h b/xf86drm.h
index 65d53219..0d927018 100644
--- a/xf86drm.h
+++ b/xf86drm.h
@@ -766,8 +766,10 @@ extern int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle);
766extern char *drmGetPrimaryDeviceNameFromFd(int fd); 766extern 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#define DRM_BUS_USB 1
771#define DRM_BUS_PLATFORM 2
772#define DRM_BUS_HOST1X 3
771 773
772typedef struct _drmPciBusInfo { 774typedef struct _drmPciBusInfo {
773 uint16_t domain; 775 uint16_t domain;
@@ -794,6 +796,26 @@ typedef struct _drmUsbDeviceInfo {
794 uint16_t product; 796 uint16_t product;
795} drmUsbDeviceInfo, *drmUsbDeviceInfoPtr; 797} drmUsbDeviceInfo, *drmUsbDeviceInfoPtr;
796 798
799#define DRM_PLATFORM_DEVICE_NAME_LEN 512
800
801typedef struct _drmPlatformBusInfo {
802 char fullname[DRM_PLATFORM_DEVICE_NAME_LEN];
803} drmPlatformBusInfo, *drmPlatformBusInfoPtr;
804
805typedef struct _drmPlatformDeviceInfo {
806 char **compatible; /* NULL terminated list of compatible strings */
807} drmPlatformDeviceInfo, *drmPlatformDeviceInfoPtr;
808
809#define DRM_HOST1X_DEVICE_NAME_LEN 512
810
811typedef struct _drmHost1xBusInfo {
812 char fullname[DRM_HOST1X_DEVICE_NAME_LEN];
813} drmHost1xBusInfo, *drmHost1xBusInfoPtr;
814
815typedef struct _drmHost1xDeviceInfo {
816 char **compatible; /* NULL terminated list of compatible strings */
817} drmHost1xDeviceInfo, *drmHost1xDeviceInfoPtr;
818
797typedef struct _drmDevice { 819typedef struct _drmDevice {
798 char **nodes; /* DRM_NODE_MAX sized array */ 820 char **nodes; /* DRM_NODE_MAX sized array */
799 int available_nodes; /* DRM_NODE_* bitmask */ 821 int available_nodes; /* DRM_NODE_* bitmask */
@@ -801,10 +823,14 @@ typedef struct _drmDevice {
801 union { 823 union {
802 drmPciBusInfoPtr pci; 824 drmPciBusInfoPtr pci;
803 drmUsbBusInfoPtr usb; 825 drmUsbBusInfoPtr usb;
826 drmPlatformBusInfoPtr platform;
827 drmHost1xBusInfoPtr host1x;
804 } businfo; 828 } businfo;
805 union { 829 union {
806 drmPciDeviceInfoPtr pci; 830 drmPciDeviceInfoPtr pci;
807 drmUsbDeviceInfoPtr usb; 831 drmUsbDeviceInfoPtr usb;
832 drmPlatformDeviceInfoPtr platform;
833 drmHost1xDeviceInfoPtr host1x;
808 } deviceinfo; 834 } deviceinfo;
809} drmDevice, *drmDevicePtr; 835} drmDevice, *drmDevicePtr;
810 836