Currently most places assume reliable master <> render node mapping.
Although this may work in some cases, it is not correct.

Add a couple of helpers that hide the details and provide the name of
the master/render device name, given an render/master FD.

v2:
 - Rename Device and Primary to Master (aka the /dev/dri/cardX device).
 - Check for the file via readdir_r() rather than stat().
 - Wrap the check into a single function.
 - Return NULL for non-linux platforms.

v3:
 - Don't segfault if name is NULL.
 - Update function names, as suggested by Frank Binns.

Cc: Frank Binns <frank.binns at imgtec.com>
Cc: Daniel Vetter <daniel.vetter at ffwll.ch>
Cc: David Herrmann <dh.herrmann at googlemail.com>
Signed-off-by: Emil Velikov <emil.l.velikov at gmail.com>
Reviewed-by: Frank Binns <frank.binns at imgtec.com>
---

Hi all,

I'm planning to push this Monday afternoon. If you have any comments or 
suggestions please go ahead.

Cheers,
Emil


 xf86drm.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 xf86drm.h |  3 +++
 2 files changed, 87 insertions(+)

diff --git a/xf86drm.c b/xf86drm.c
index e117bc6..194cd35 100644
--- a/xf86drm.c
+++ b/xf86drm.c
@@ -40,6 +40,8 @@
 #include <string.h>
 #include <strings.h>
 #include <ctype.h>
+#include <dirent.h>
+#include <stddef.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <signal.h>
@@ -522,6 +524,20 @@ static int drmGetMinorType(int minor)
     }
 }

+static const char *drmGetMinorName(int type)
+{
+    switch (type) {
+    case DRM_NODE_PRIMARY:
+        return "card";
+    case DRM_NODE_CONTROL:
+        return "controlD";
+    case DRM_NODE_RENDER:
+        return "renderD";
+    default:
+        return NULL;
+    }
+}
+
 /**
  * Open the device by bus ID.
  *
@@ -2736,3 +2752,71 @@ int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t 
*handle)
        return 0;
 }

+static char *drmGetMinorNameForFD(int fd, int type)
+{
+#ifdef __linux__
+       DIR *sysdir;
+       struct dirent *pent, *ent;
+       struct stat sbuf;
+       const char *name = drmGetMinorName(type);
+       int len;
+       char dev_name[64], buf[64];
+       long name_max;
+       int maj, min;
+
+       if (!name)
+               return NULL;
+
+       len = strlen(name);
+
+       if (fstat(fd, &sbuf))
+               return NULL;
+
+       maj = major(sbuf.st_rdev);
+       min = minor(sbuf.st_rdev);
+
+       if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+               return NULL;
+
+       snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
+
+       sysdir = opendir(buf);
+       if (!sysdir)
+               return NULL;
+
+       name_max = fpathconf(dirfd(sysdir), _PC_NAME_MAX);
+       if (name_max == -1)
+               goto out_close_dir;
+
+       pent = malloc(offsetof(struct dirent, d_name) + name_max + 1);
+       if (pent == NULL)
+                goto out_close_dir;
+
+       while (readdir_r(sysdir, pent, &ent) == 0 && ent != NULL) {
+               if (strncmp(ent->d_name, name, len) == 0) {
+                       free(pent);
+                       closedir(sysdir);
+
+                       snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
+                                ent->d_name);
+                       return strdup(dev_name);
+               }
+       }
+
+       free(pent);
+
+out_close_dir:
+       closedir(sysdir);
+#endif
+       return NULL;
+}
+
+char *drmGetPrimaryDeviceNameFromFd(int fd)
+{
+       return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
+}
+
+char *drmGetRenderDeviceNameFromFd(int fd)
+{
+       return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
+}
diff --git a/xf86drm.h b/xf86drm.h
index afd38a1..40c55c9 100644
--- a/xf86drm.h
+++ b/xf86drm.h
@@ -749,6 +749,9 @@ extern int drmGetNodeTypeFromFd(int fd);
 extern int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int 
*prime_fd);
 extern int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle);

+extern char *drmGetPrimaryDeviceNameFromFd(int fd);
+extern char *drmGetRenderDeviceNameFromFd(int fd);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
-- 
2.3.1

Reply via email to