Merge aca0b1d811656bbb573708160463bdfafa6a9177 on remote branch

Change-Id: I9c7d3b41fc6b49a316bfb3d19bc0ae8f996ae86a
diff --git a/xf86drm.c b/xf86drm.c
index 953fc76..155c5a8 100644
--- a/xf86drm.c
+++ b/xf86drm.c
@@ -2998,10 +2998,10 @@
 /* Little white lie to avoid major rework of the existing code */
 #define DRM_BUS_VIRTIO 0x10
 
-static int drmParseSubsystemType(int maj, int min)
-{
 #ifdef __linux__
-    char path[PATH_MAX + 1];
+static int get_subsystem_type(const char *device_path)
+{
+    char path[PATH_MAX + 1] = "";
     char link[PATH_MAX + 1] = "";
     char *name;
     struct {
@@ -3016,8 +3016,8 @@
         { "/virtio", DRM_BUS_VIRTIO },
     };
 
-    snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem",
-             maj, min);
+    strncpy(path, device_path, PATH_MAX);
+    strncat(path, "/subsystem", PATH_MAX);
 
     if (readlink(path, link, PATH_MAX) < 0)
         return -errno;
@@ -3032,6 +3032,27 @@
     }
 
     return -EINVAL;
+}
+#endif
+
+static int drmParseSubsystemType(int maj, int min)
+{
+#ifdef __linux__
+    char path[PATH_MAX + 1] = "";
+    char real_path[PATH_MAX + 1] = "";
+    int subsystem_type;
+
+    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
+    if (!realpath(path, real_path))
+        return -errno;
+    snprintf(path, sizeof(path), "%s", real_path);
+
+    subsystem_type = get_subsystem_type(path);
+    if (subsystem_type == DRM_BUS_VIRTIO) {
+        strncat(path, "/..", PATH_MAX);
+        subsystem_type = get_subsystem_type(path);
+    }
+    return subsystem_type;
 #elif defined(__OpenBSD__) || defined(__DragonFly__)
     return DRM_BUS_PCI;
 #else
@@ -3733,7 +3754,6 @@
 
     switch (subsystem_type) {
     case DRM_BUS_PCI:
-    case DRM_BUS_VIRTIO:
         return drmProcessPciDevice(device, node, node_type, maj, min,
                                    fetch_deviceinfo, flags);
     case DRM_BUS_USB: