From 4a86cbbed0c6d74a8b68ec72b8de8e48905d4015 Mon Sep 17 00:00:00 2001 From: Martin Peres Date: Sat, 15 Dec 2012 18:49:06 +0100 Subject: drm: allow opening the drm device by type (control, render or render_only) Signed-off-by: Martin Peres --- tests/name_from_fd.c | 19 ++++++---- xf86drm.c | 105 ++++++++++++++++++++++++++++++++++++++++----------- xf86drm.h | 7 ++++ 3 files changed, 100 insertions(+), 31 deletions(-) diff --git a/tests/name_from_fd.c b/tests/name_from_fd.c index 330c8ff0..8e1a1978 100644 --- a/tests/name_from_fd.c +++ b/tests/name_from_fd.c @@ -41,17 +41,20 @@ int main(int argc, char **argv) { int fd, ret; drm_set_version_t sv, version; - const char *name = "/dev/dri/card0"; + const char *name[2] = { "/dev/dri/card0", "/dev/dri/renderD128" }; char *v; + int i; - fd = open("/dev/dri/card0", O_RDWR); - if (fd == -1) - return 0; + for (i = 0; i < 2; i++) { + fd = open(name[i], O_RDWR); + if (fd > 0) { + v = drmGetDeviceNameFromFd(fd); + close(fd); + assert(v != NULL); + assert(strcmp(name[i], v) == 0); + } + } - v = drmGetDeviceNameFromFd(fd); - close(fd); - - assert(strcmp(name, v) == 0); drmFree(v); return 0; diff --git a/xf86drm.c b/xf86drm.c index 2a74c807..eb0549d6 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -85,9 +85,6 @@ #define DRM_MSG_VERBOSITY 3 -#define DRM_NODE_CONTROL 0 -#define DRM_NODE_RENDER 1 - static drmServerInfoPtr drm_server_info; void drmSetServerInfo(drmServerInfoPtr info) @@ -285,11 +282,52 @@ static int chown_check_return(const char *path, uid_t owner, gid_t group) return -1; } +/** + * Generate the device name according to its type. + * + * \param buf buffer that will hold the device path after the call. + * \param len length of the buffer. + * \param base_dir base directory used to generate the path. If NULL, it + * defaults to DRM_DIR_NAME ("/dev/dri"). + * \param type the type of device (control, render or render_only). + * \param minor number of the device. + */ +static void drmDevicePath(char *buf, size_t len, const char *base_dir, int type, + int minor) +{ + const char *dev_name = NULL; + + switch (type) + { + case DRM_NODE_CONTROL: + dev_name = DRM_CONTROL_DEV_NAME; + /* we do not increase minor by 64 not to change the current + * behaviour even though I couldn't find who uses this type! + */ + break; + case DRM_NODE_RENDER_ONLY: + dev_name = DRM_RENDER_ONLY_DEV_NAME; + minor += 128; + break; + default: + drmMsg("drmDevicePath: unknown type %d, default to render.\n", type); + case DRM_NODE_RENDER: + dev_name = DRM_DEV_NAME; + break; + } + + if (!base_dir) + base_dir = DRM_DIR_NAME; + + snprintf(buf, len, dev_name, base_dir, minor); +} + /** * Open the DRM device, creating it if necessary. * * \param dev major and minor numbers of the device. * \param minor minor number of the device. + * \param type the type of device we want to open (control, render or render_only). * * \return a file descriptor on success, or a negative value on error. * @@ -308,7 +346,7 @@ static int drmOpenDevice(long dev, int minor, int type) uid_t user = DRM_DEV_UID; gid_t group = DRM_DEV_GID, serv_group; - sprintf(buf, type ? DRM_DEV_NAME : DRM_CONTROL_DEV_NAME, DRM_DIR_NAME, minor); + drmDevicePath(buf, sizeof(buf), NULL, type, minor); drmMsg("drmOpenDevice: node name is %s\n", buf); if (drm_server_info) { @@ -417,7 +455,7 @@ static int drmOpenMinor(int minor, int create, int type) if (create) return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type); - sprintf(buf, type ? DRM_DEV_NAME : DRM_CONTROL_DEV_NAME, DRM_DIR_NAME, minor); + drmDevicePath(buf, sizeof(buf), NULL, type, minor); if ((fd = open(buf, O_RDWR, 0)) >= 0) return fd; return -errno; @@ -472,7 +510,7 @@ int drmAvailable(void) * * \sa drmOpenMinor() and drmGetBusid(). */ -static int drmOpenByBusid(const char *busid) +static int drmOpenByBusid(const char *busid, int type) { int i, pci_domain_ok = 1; int fd; @@ -481,7 +519,7 @@ static int drmOpenByBusid(const char *busid) drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid); for (i = 0; i < DRM_MAX_MINOR; i++) { - fd = drmOpenMinor(i, 1, DRM_NODE_RENDER); + fd = drmOpenMinor(i, 1, type); drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd); if (fd >= 0) { /* We need to try for 1.4 first for proper PCI domain support @@ -531,7 +569,7 @@ static int drmOpenByBusid(const char *busid) * * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid(). */ -static int drmOpenByName(const char *name) +static int drmOpenByName(const char *name, int type) { int i; int fd; @@ -556,7 +594,7 @@ static int drmOpenByName(const char *name) * already in use. If it's in use it will have a busid assigned already. */ for (i = 0; i < DRM_MAX_MINOR; i++) { - if ((fd = drmOpenMinor(i, 1, DRM_NODE_RENDER)) >= 0) { + if ((fd = drmOpenMinor(i, 1, type)) >= 0) { if ((version = drmGetVersion(fd))) { if (!strcmp(version->name, name)) { drmFreeVersion(version); @@ -598,9 +636,9 @@ static int drmOpenByName(const char *name) for (devstring = ++pt; *pt && *pt != ' '; ++pt) ; if (*pt) { /* Found busid */ - return drmOpenByBusid(++pt); + return drmOpenByBusid(++pt, type); } else { /* No busid */ - return drmOpenDevice(strtol(devstring, NULL, 0),i, DRM_NODE_RENDER); + return drmOpenDevice(strtol(devstring, NULL, 0),i, type); } } } @@ -621,6 +659,7 @@ static int drmOpenByName(const char *name) * * \param name driver name. Not referenced if bus ID is supplied. * \param busid bus ID. Zero if not known. + * \param type type of node wanted (control, render or render_only). * * \return a file descriptor on success, or a negative value on error. * @@ -628,7 +667,7 @@ static int drmOpenByName(const char *name) * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() * otherwise. */ -int drmOpen(const char *name, const char *busid) +int drmOpenType(const char *name, const char *busid, int type) { if (!drmAvailable() && name != NULL && drm_server_info) { /* try to load the kernel */ @@ -639,17 +678,37 @@ int drmOpen(const char *name, const char *busid) } if (busid) { - int fd = drmOpenByBusid(busid); + int fd = drmOpenByBusid(busid, type); if (fd >= 0) return fd; } if (name) - return drmOpenByName(name); + return drmOpenByName(name, type); return -1; } +/** + * Open the DRM device. + * + * Looks up the specified name and bus ID, and opens the device found. The + * entry in /dev/dri is created if necessary and if called by root. + * + * \param name driver name. Not referenced if bus ID is supplied. + * \param busid bus ID. Zero if not known. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() + * otherwise. + */ +int drmOpen(const char *name, const char *busid) +{ + return drmOpenType(name, busid, DRM_NODE_RENDER); +} + int drmOpenControl(int minor) { return drmOpenMinor(minor, 0, DRM_NODE_CONTROL); @@ -2522,7 +2581,7 @@ char *drmGetDeviceNameFromFd(int fd) char name[128]; struct stat sbuf; dev_t d; - int i; + int type, i; /* The whole drmOpen thing is a fiasco and we need to find a way * back to just using open(2). For now, however, lets just make @@ -2532,15 +2591,15 @@ char *drmGetDeviceNameFromFd(int fd) fstat(fd, &sbuf); d = sbuf.st_rdev; - for (i = 0; i < DRM_MAX_MINOR; i++) { - snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i); - if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d) - break; + for (type = DRM_NODE_RENDER; type <= DRM_NODE_RENDER_ONLY; type++) { + for (i = 0; i < DRM_MAX_MINOR; i++) { + drmDevicePath(name, sizeof(name), NULL, type, i); + if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d) + return strdup(name); + } } - if (i == DRM_MAX_MINOR) - return NULL; - - return strdup(name); + + return NULL; } int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd) diff --git a/xf86drm.h b/xf86drm.h index 5ecb2846..d727ce1b 100644 --- a/xf86drm.h +++ b/xf86drm.h @@ -47,6 +47,10 @@ extern "C" { #define DRM_MAX_MINOR 16 #endif +#define DRM_NODE_CONTROL 0 +#define DRM_NODE_RENDER 1 +#define DRM_NODE_RENDER_ONLY 2 + #if defined(__linux__) #define DRM_IOCTL_NR(n) _IOC_NR(n) @@ -78,6 +82,7 @@ extern "C" { #define DRM_DIR_NAME "/dev/dri" #define DRM_DEV_NAME "%s/card%d" +#define DRM_RENDER_ONLY_DEV_NAME "%s/renderD%d" #define DRM_CONTROL_DEV_NAME "%s/controlD%d" #define DRM_PROC_NAME "/proc/dri/" /* For backward Linux compatibility */ @@ -544,6 +549,7 @@ do { register unsigned int __old __asm("o0"); \ /* General user-level programmer's API: unprivileged */ extern int drmAvailable(void); +extern int drmOpenType(const char *name, const char *busid, int type); extern int drmOpen(const char *name, const char *busid); extern int drmOpenControl(int minor); extern int drmClose(int fd); @@ -694,6 +700,7 @@ extern int drmSLLookupNeighbors(void *l, unsigned long key, unsigned long *prev_key, void **prev_value, unsigned long *next_key, void **next_value); +extern int drmOpenTypeOnce(void *unused, const char *BusID, int *newlyopened, int type); extern int drmOpenOnce(void *unused, const char *BusID, int *newlyopened); extern void drmCloseOnce(int fd); extern void drmMsg(const char *format, ...); -- cgit v1.2.3