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