From fde4969176822fe54197b6baa78f8b0ef900baba Mon Sep 17 00:00:00 2001 From: frank Date: Tue, 19 May 2015 23:31:05 +0800 Subject: Add device enumeration interface (v4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an interface for enumerating PCI devices on a system. v3: switch to udev/sysfs for the enumeration v4: fix warnings Signed-off-by: Frank Min Reviewed-by: Christian König Reviewed-by: Alex Deucher Reviewed-by: Jammy Zhou --- Makefile.am | 7 +++-- xf86drm.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ xf86drm.h | 19 ++++++++++++ 3 files changed, 124 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 13df80c5..ffd334ad 100644 --- a/Makefile.am +++ b/Makefile.am @@ -95,12 +95,15 @@ SUBDIRS = \ libdrm_la_LTLIBRARIES = libdrm.la libdrm_ladir = $(libdir) libdrm_la_LDFLAGS = -version-number 2:4:0 -no-undefined -libdrm_la_LIBADD = @CLOCK_LIB@ +libdrm_la_LIBADD = \ + @CLOCK_LIB@ \ + @LIBUDEV_LIBS@ libdrm_la_CPPFLAGS = -I$(top_srcdir)/include/drm AM_CFLAGS = \ $(WARN_CFLAGS) \ - $(VALGRIND_CFLAGS) + $(VALGRIND_CFLAGS) \ + $(LIBUDEV_CFLAGS) libdrm_la_SOURCES = $(LIBDRM_FILES) diff --git a/xf86drm.c b/xf86drm.c index f7c45f88..b5a174bd 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -63,6 +63,7 @@ #include "xf86drm.h" #include "libdrm_macros.h" +#include "libudev.h" #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) #define DRM_MAJOR 145 @@ -2817,3 +2818,102 @@ char *drmGetRenderDeviceNameFromFd(int fd) { return drmGetMinorNameForFD(fd, DRM_NODE_RENDER); } + +/** +* Enumerate the GPU devices on the system +* +* \param devs device array set to return the device information +* (if NULL, the number of device is returned) +* \param vendor the vendor ID for GPU devices to list +* (optional, if not specified, all GPU devices are returned) +* +* \return the number of GPU devices +*/ +int drmGetPciDevices(drmPciDevicePtr devSet, uint16_t vendorId) +{ + struct udev *udev = NULL; + struct udev_enumerate *udev_enumerate; + struct udev_list_entry *list_entry; + struct udev_device *device; + int drmDevCount = 0; + int vendor = 0; + int devid = 0; + int subvendor = 0; + int subdevid = 0; + int revid = 0xff; + int domain = 0; + int bus = 0; + int dev = 0; + int func = 0; + char config[64] = {0}; + char node[128] = {'\0'}; + char slot[] = "0000:00:00.0"; + const char *info = NULL; + int fd = 0; + int ret = 0; + + udev = udev_new(); + if (udev == NULL) { + fprintf(stderr, "no context\n"); + return -EINVAL; + } + udev_enumerate = udev_enumerate_new(udev); + if (udev_enumerate == NULL) + return -EINVAL; + udev_enumerate_add_match_subsystem(udev_enumerate, "drm"); + udev_enumerate_add_match_property(udev_enumerate, "DEVTYPE", "drm_minor"); + + udev_enumerate_scan_devices(udev_enumerate); + + udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) { + device = udev_device_new_from_syspath(udev_enumerate_get_udev(udev_enumerate), + udev_list_entry_get_name(list_entry)); + if (device != NULL) { + info = udev_device_get_property_value(device, "MINOR"); + if (!strcmp(info, "0")) { + strcpy(node, udev_device_get_syspath(device)); + info = strstr(node, "/drm"); + strncpy(slot, info - strlen(slot), strlen(slot)); + if (sscanf(slot, "%4x:%2x:%2x.%1x", &domain, &bus, &dev, &func) != 4) { + domain = 0; + bus = 0; + dev = 0; + func = 0; + } + strcpy(node + strlen(node), "/device/config"); + + fd = open(node, O_RDONLY); + if (fd >= 0) { + ret = read(fd, config, 64); + if (ret == 64) { + vendor = config[0] + (config[1] << 8); + devid = config[2] + (config[3] << 8); + revid = config[8]; + subdevid = config[44] + (config[45] << 8); + } + close(fd); + } + + if((vendorId == 0) || (vendorId == vendor)) { + if(devSet != NULL) { + devSet[drmDevCount].domain = domain; + devSet[drmDevCount].bus = bus; + devSet[drmDevCount].dev = dev; + devSet[drmDevCount].func = func; + devSet[drmDevCount].vendor_id = vendor; + devSet[drmDevCount].device_id = devid; + devSet[drmDevCount].subdevice_id = subdevid; + devSet[drmDevCount].subvendor_id = subvendor; + devSet[drmDevCount].revision_id = revid; + } + drmDevCount++; + } + } + } + udev_device_unref(device); + } + udev_enumerate_unref(udev_enumerate); + udev_unref(udev); + + return drmDevCount; +} diff --git a/xf86drm.h b/xf86drm.h index 40c55c92..2610934f 100644 --- a/xf86drm.h +++ b/xf86drm.h @@ -342,6 +342,24 @@ typedef struct _drmSetVersion { int drm_dd_minor; } drmSetVersion, *drmSetVersionPtr; +/** + * Structure to a general pci gpu device + * + * \sa drmGetDevices() + * +*/ +typedef struct _drmPciDevice { + uint16_t domain; + uint8_t bus; + uint8_t dev; + uint8_t func; + uint16_t vendor_id; + uint16_t device_id; + uint16_t subvendor_id; + uint16_t subdevice_id; + uint8_t revision_id; +} drmPciDevice, *drmPciDevicePtr; + #define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock) #define DRM_LOCK_HELD 0x80000000U /**< Hardware lock is held */ @@ -552,6 +570,7 @@ do { register unsigned int __old __asm("o0"); \ /* General user-level programmer's API: unprivileged */ extern int drmAvailable(void); extern int drmOpen(const char *name, const char *busid); +extern int drmGetPciDevices(drmPciDevicePtr devSet, uint16_t vendorId); #define DRM_NODE_PRIMARY 0 #define DRM_NODE_CONTROL 1 -- cgit v1.2.3