diff options
author | Emil Velikov <emil.l.velikov@gmail.com> | 2015-03-07 00:58:39 +0000 |
---|---|---|
committer | Emil Velikov <emil.l.velikov@gmail.com> | 2015-03-10 18:14:40 +0000 |
commit | 0ca03a4087a550646de7f26b6b53a932e8546474 (patch) | |
tree | 38eb3eca83bdd1260767a437b1482a6d5bd9c736 | |
parent | b374a59e0e2ef52fed737f6db9ee1e40caca46ea (diff) |
drm: add drmGet(Primary|Render)DeviceNameFromFd functions
Currently most places assume reliable primary(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 or render device name, given an fd. The latter may belong to
either the master, control or render node device.
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.
v4:
- Update commit message to reflect the function name changes.
Cc: Frank Binns <frank.binns@imgtec.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: David Herrmann <dh.herrmann@googlemail.com>
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Reviewed-by: Frank Binns <frank.binns@imgtec.com>
-rw-r--r-- | xf86drm.c | 84 | ||||
-rw-r--r-- | xf86drm.h | 3 |
2 files changed, 87 insertions, 0 deletions
@@ -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); +} @@ -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 |