OSDN Git Service

tests/amdgpu: add semaphore test
[android-x86/external-libdrm.git] / xf86drm.c
index a783a28..7e28b4f 100644 (file)
--- a/xf86drm.c
+++ b/xf86drm.c
@@ -36,6 +36,7 @@
 #endif
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <unistd.h>
 #include <string.h>
 #include <strings.h>
@@ -44,6 +45,7 @@
 #include <stddef.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <limits.h>
 #include <signal.h>
 #include <time.h>
 #include <sys/types.h>
 #define DRM_MAJOR 226          /* Linux */
 #endif
 
-/*
- * This definition needs to be changed on some systems if dev_t is a structure.
- * If there is a header file we can get it from, there would be best.
- */
-#ifndef makedev
-#define makedev(x,y)    ((dev_t)(((x) << 8) | (y)))
-#endif
-
 #define DRM_MSG_VERBOSITY 3
 
 #define memclear(s) memset(&s, 0, sizeof(s))
@@ -2981,7 +2975,7 @@ static int drmParsePciDeviceInfo(const char *d_name,
 #endif
 }
 
-static void drmFreeDevice(drmDevicePtr *device)
+void drmFreeDevice(drmDevicePtr *device)
 {
     if (device == NULL)
         return;
@@ -3001,6 +2995,189 @@ void drmFreeDevices(drmDevicePtr devices[], int count)
         drmFreeDevice(&devices[i]);
 }
 
+static int drmProcessPciDevice(drmDevicePtr *device, const char *d_name,
+                               const char *node, int node_type,
+                               int maj, int min, bool fetch_deviceinfo)
+{
+    const int max_node_str = drmGetMaxNodeName();
+    int ret, i;
+    char *addr;
+
+    *device = calloc(1, sizeof(drmDevice) +
+                    (DRM_NODE_MAX * (sizeof(void *) + max_node_str)) +
+                    sizeof(drmPciBusInfo) +
+                    sizeof(drmPciDeviceInfo));
+    if (!*device)
+        return -ENOMEM;
+
+    addr = (char*)*device;
+  
+    (*device)->bustype = DRM_BUS_PCI;
+    (*device)->available_nodes = 1 << node_type;
+
+    addr += sizeof(drmDevice);
+    (*device)->nodes = (char**)addr;
+
+    addr += DRM_NODE_MAX * sizeof(void *);
+    for (i = 0; i < DRM_NODE_MAX; i++) {
+        (*device)->nodes[i] = addr;
+        addr += max_node_str;
+    }
+    memcpy((*device)->nodes[node_type], node, max_node_str);
+
+    (*device)->businfo.pci = (drmPciBusInfoPtr)addr;
+
+    ret = drmParsePciBusInfo(maj, min, (*device)->businfo.pci);
+    if (ret)
+        goto free_device;
+
+    // Fetch the device info if the user has requested it
+    if (fetch_deviceinfo) {
+        addr += sizeof(drmPciBusInfo);
+        (*device)->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
+
+        ret = drmParsePciDeviceInfo(d_name, (*device)->deviceinfo.pci);
+        if (ret)
+            goto free_device;
+    }
+    return 0;
+
+free_device:
+    free(*device);
+    *device = NULL;
+    return ret;
+}
+
+static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
+{
+    int node_type, i, j;
+
+    for (i = 0; i < count; i++) {
+        for (j = i + 1; j < count; j++) {
+            if (drmCompareBusInfo(local_devices[i], local_devices[j]) == 0) {
+                local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
+                node_type = log2(local_devices[j]->available_nodes);
+                memcpy(local_devices[i]->nodes[node_type],
+                       local_devices[j]->nodes[node_type], drmGetMaxNodeName());
+                drmFreeDevice(&local_devices[j]);
+            }
+        }
+    }
+}
+
+/**
+ * Get information about the opened drm device
+ *
+ * \param fd file descriptor of the drm device
+ * \param device the address of a drmDevicePtr where the information
+ *               will be allocated in stored
+ *
+ * \return zero on success, negative error code otherwise.
+ */
+int drmGetDevice(int fd, drmDevicePtr *device)
+{
+    drmDevicePtr *local_devices;
+    drmDevicePtr d;
+    DIR *sysdir;
+    struct dirent *dent;
+    struct stat sbuf;
+    char node[PATH_MAX + 1];
+    int node_type, subsystem_type;
+    int maj, min;
+    int ret, i, node_count;
+    int max_count = 16;
+
+    if (fd == -1 || device == NULL)
+        return -EINVAL;
+
+    if (fstat(fd, &sbuf))
+        return -errno;
+
+    maj = major(sbuf.st_rdev);
+    min = minor(sbuf.st_rdev);
+
+    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+        return -EINVAL;
+
+    subsystem_type = drmParseSubsystemType(maj, min);
+
+    local_devices = calloc(max_count, sizeof(drmDevicePtr));
+    if (local_devices == NULL)
+        return -ENOMEM;
+
+    sysdir = opendir(DRM_DIR_NAME);
+    if (!sysdir) {
+        ret = -errno;
+        goto free_locals;
+    }
+
+    i = 0;
+    while ((dent = readdir(sysdir))) {
+        node_type = drmGetNodeType(dent->d_name);
+        if (node_type < 0)
+            continue;
+
+        snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
+        if (stat(node, &sbuf))
+            continue;
+
+        maj = major(sbuf.st_rdev);
+        min = minor(sbuf.st_rdev);
+
+        if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+            continue;
+
+        if (drmParseSubsystemType(maj, min) != subsystem_type)
+            continue;
+
+        switch (subsystem_type) {
+        case DRM_BUS_PCI:
+            ret = drmProcessPciDevice(&d, dent->d_name, node, node_type,
+                                      maj, min, true);
+            if (ret)
+                goto free_devices;
+
+            break;
+        default:
+            fprintf(stderr, "The subsystem type is not supported yet\n");
+            continue;
+        }
+
+        if (i >= max_count) {
+            drmDevicePtr *temp;
+
+            max_count += 16;
+            temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
+            if (!temp)
+                goto free_devices;
+            local_devices = temp;
+        }
+
+        local_devices[i] = d;
+        i++;
+    }
+    node_count = i;
+
+    /* Fold nodes into a single device if they share the same bus info */
+    drmFoldDuplicatedDevices(local_devices, node_count);
+
+    *device = local_devices[0];
+    for (i = 1; i < node_count && local_devices[i]; i++)
+            drmFreeDevice(&local_devices[i]);
+
+    closedir(sysdir);
+    free(local_devices);
+    return 0;
+
+free_devices:
+    drmFreeDevices(local_devices, i);
+    closedir(sysdir);
+
+free_locals:
+    free(local_devices);
+    return ret;
+}
+
 /**
  * Get drm devices on the system
  *
@@ -3021,12 +3198,10 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices)
     struct dirent *dent;
     struct stat sbuf;
     char node[PATH_MAX + 1];
-    const int max_node_str = drmGetMaxNodeName();
     int node_type, subsystem_type;
     int maj, min;
-    int ret, i, j, node_count, device_count;
+    int ret, i, node_count, device_count;
     int max_count = 16;
-    void *addr;
 
     local_devices = calloc(max_count, sizeof(drmDevicePtr));
     if (local_devices == NULL)
@@ -3035,7 +3210,7 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices)
     sysdir = opendir(DRM_DIR_NAME);
     if (!sysdir) {
         ret = -errno;
-        goto close_sysdir;
+        goto free_locals;
     }
 
     i = 0;
@@ -3061,48 +3236,15 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices)
 
         switch (subsystem_type) {
         case DRM_BUS_PCI:
-            addr = device = calloc(1, sizeof(drmDevice) +
-                                      (DRM_NODE_MAX *
-                                       (sizeof(void *) + max_node_str)) +
-                                      sizeof(drmPciBusInfo) +
-                                      sizeof(drmPciDeviceInfo));
-            if (!device)
-                goto free_devices;
-
-            device->bustype = subsystem_type;
-            device->available_nodes = 1 << node_type;
-
-            addr += sizeof(drmDevice);
-            device->nodes = addr;
-
-            addr += DRM_NODE_MAX * sizeof(void *);
-            for (j = 0; j < DRM_NODE_MAX; j++) {
-                device->nodes[j] = addr;
-                addr += max_node_str;
-            }
-            memcpy(device->nodes[node_type], node, max_node_str);
-
-            device->businfo.pci = addr;
-
-            ret = drmParsePciBusInfo(maj, min, device->businfo.pci);
+            ret = drmProcessPciDevice(&device, dent->d_name, node, node_type,
+                                      maj, min, devices != NULL);
             if (ret)
                 goto free_devices;
 
-            // Fetch the device info if the user has requested it
-            if (devices != NULL) {
-                addr += sizeof(drmPciBusInfo);
-                device->deviceinfo.pci = addr;
-
-                ret = drmParsePciDeviceInfo(dent->d_name,
-                                            device->deviceinfo.pci);
-                if (ret)
-                    goto free_devices;
-            }
-
             break;
         default:
             fprintf(stderr, "The subsystem type is not supported yet\n");
-            break;
+            continue;
         }
 
         if (i >= max_count) {
@@ -3121,17 +3263,7 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices)
     node_count = i;
 
     /* Fold nodes into a single device if they share the same bus info */
-    for (i = 0; i < node_count; i++) {
-        for (j = i + 1; j < node_count; j++) {
-            if (drmCompareBusInfo(local_devices[i], local_devices[j]) == 0) {
-                local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
-                node_type = log2(local_devices[j]->available_nodes);
-                memcpy(local_devices[i]->nodes[node_type],
-                       local_devices[j]->nodes[node_type], max_node_str);
-                drmFreeDevice(&local_devices[j]);
-            }
-        }
-    }
+    drmFoldDuplicatedDevices(local_devices, node_count);
 
     device_count = 0;
     for (i = 0; i < node_count && local_devices[i]; i++) {
@@ -3143,15 +3275,15 @@ int drmGetDevices(drmDevicePtr devices[], int max_devices)
         device_count++;
     }
 
-    free(local_devices);
     closedir(sysdir);
+    free(local_devices);
     return device_count;
 
 free_devices:
     drmFreeDevices(local_devices, i);
-    free(local_devices);
-
-close_sysdir:
     closedir(sysdir);
+
+free_locals:
+    free(local_devices);
     return ret;
 }