libs: display: drm: fix set_device_path_from_fd
authorHaihao Xiang <haihao.xiang@intel.com>
Mon, 25 Jan 2021 06:45:47 +0000 (14:45 +0800)
committerHaihao Xiang <haihao.xiang@intel.com>
Thu, 28 Jan 2021 01:48:56 +0000 (09:48 +0800)
drmGetBusid() (GET_UNIQUE ioctl) won't return a valid bus id when
drmSetInterfaceVersion() (SET_VERSION ioctl) hasn't been called(see[1]),
so we can't get the right device path. Running test-display will get the
error below:

** (test-display:18630): ERROR **: 10:26:00.434: could not create Gst/VA
display

Calling drmSetInterfaceVersion() before drmGetBusid() can't fix this
issue because a special permission is required for SET_VERSION ioctl.

This patch retrieves the device path from file descriptor via
g_file_read_link()

[1] https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/drm_ioctl.c#L48-L104

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/-/merge_requests/412>

gst-libs/gst/vaapi/gstvaapidisplay_drm.c

index ecc5a14..d575ffd 100644 (file)
 #define DEBUG_VAAPI_DISPLAY 1
 #include "gstvaapidebug.h"
 
+#ifndef MAXPATHLEN
+#if defined(PATH_MAX)
+#define MAXPATHLEN PATH_MAX
+#elif defined(_PC_PATH_MAX)
+#define MAXPATHLEN sysconf(_PC_PATH_MAX)
+#else
+#define MAXPATHLEN 2048
+#endif
+#endif
+
 G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiDisplayDRM, gst_vaapi_display_drm,
     GST_TYPE_VAAPI_DISPLAY);
 
@@ -182,14 +192,9 @@ set_device_path_from_fd (GstVaapiDisplay * display, gint drm_device)
 {
   GstVaapiDisplayDRMPrivate *const priv =
       GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
-  const gchar *busid, *path, *str;
-  gsize busid_length, path_length;
-  struct udev *udev = NULL;
-  struct udev_device *device;
-  struct udev_enumerate *e = NULL;
-  struct udev_list_entry *l;
   gboolean success = FALSE;
-  gint i;
+  gchar fd_name[MAXPATHLEN];
+  GError *error = NULL;
 
   g_free (priv->device_path);
   priv->device_path = NULL;
@@ -197,61 +202,23 @@ set_device_path_from_fd (GstVaapiDisplay * display, gint drm_device)
   if (drm_device < 0)
     goto end;
 
-  busid = drmGetBusid (drm_device);
-  if (!busid)
-    goto end;
-
-  for (i = 0; allowed_subsystems[i] != NULL; i++) {
-    busid_length = strlen (allowed_subsystems[i]);
-
-    if (strncmp (busid, allowed_subsystems[i], busid_length) == 0) {
-      busid += busid_length + 1;
-      busid_length = strlen (busid);
-    }
-  }
-
-  if (allowed_subsystems[i] == NULL)
-    goto end;
-
-  udev = udev_new ();
-  if (!udev)
-    goto end;
+  sprintf (fd_name, "/proc/%d/fd/%d", getpid (), drm_device);
+  priv->device_path = g_file_read_link (fd_name, &error);
 
-  e = udev_enumerate_new (udev);
-  if (!e)
+  if (error) {
+    g_error_free (error);
     goto end;
+  }
 
-  udev_enumerate_add_match_subsystem (e, "drm");
-  udev_enumerate_scan_devices (e);
-  udev_list_entry_foreach (l, udev_enumerate_get_list_entry (e)) {
-    path = udev_list_entry_get_name (l);
-    str = strstr (path, busid);
-    if (!str || str <= path || str[-1] != '/')
-      continue;
-
-    path_length = strlen (path);
-    if (str + busid_length >= path + path_length)
-      continue;
-    if (strncmp (&str[busid_length], "/drm/card", 9) != 0 &&
-        strncmp (&str[busid_length], "/drm/renderD", 12) != 0)
-      continue;
-
-    device = udev_device_new_from_syspath (udev, path);
-    if (!device)
-      continue;
-
-    path = udev_device_get_devnode (device);
-    priv->device_path = g_strdup (path);
-    udev_device_unref (device);
-    break;
+  if (g_str_has_prefix (priv->device_path, "/dev/dri/card") ||
+      g_str_has_prefix (priv->device_path, "/dev/dri/renderD"))
+    success = TRUE;
+  else {
+    g_free (priv->device_path);
+    priv->device_path = NULL;
   }
-  success = TRUE;
 
 end:
-  if (e)
-    udev_enumerate_unref (e);
-  if (udev)
-    udev_unref (udev);
   return success;
 }