OSDN Git Service

amdgpu: serialize drmPrimeFDToHandle
[android-x86/external-libdrm.git] / xf86drm.c
index d900b4b..4b66612 100644 (file)
--- 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>
 #include <sys/ioctl.h>
 #include <sys/time.h>
 #include <stdarg.h>
+#ifdef HAVE_SYS_MKDEV_H
+# include <sys/mkdev.h> /* defines major(), minor(), and makedev() on Solaris */
+#endif
+#include <math.h>
 
 /* Not all systems have MAP_FAILED defined */
 #ifndef MAP_FAILED
 #endif
 
 #include "xf86drm.h"
-#include "libdrm.h"
+#include "libdrm_macros.h"
+
+#ifdef __OpenBSD__
+#define DRM_PRIMARY_MINOR_NAME "drm"
+#define DRM_CONTROL_MINOR_NAME "drmC"
+#define DRM_RENDER_MINOR_NAME  "drmR"
+#else
+#define DRM_PRIMARY_MINOR_NAME "card"
+#define DRM_CONTROL_MINOR_NAME "controlD"
+#define DRM_RENDER_MINOR_NAME  "renderD"
+#endif
 
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
 #define DRM_MAJOR 145
 #define DRM_MAJOR 34
 #endif
 
-# ifdef __OpenBSD__
-#  define DRM_MAJOR 81
-# endif
+#ifdef __OpenBSD__
+#ifdef __i386__
+#define DRM_MAJOR 88
+#else
+#define DRM_MAJOR 87
+#endif
+#endif /* __OpenBSD__ */
 
 #ifndef DRM_MAJOR
 #define DRM_MAJOR 226          /* Linux */
 
 #define DRM_MSG_VERBOSITY 3
 
-#define DRM_NODE_CONTROL 0
-#define DRM_NODE_RENDER 1
+#define memclear(s) memset(&s, 0, sizeof(s))
 
 static drmServerInfoPtr drm_server_info;
 
@@ -110,11 +129,6 @@ drmDebugPrint(const char *format, va_list ap)
     return vfprintf(stderr, format, ap);
 }
 
-typedef int DRM_PRINTFLIKE(1, 0) (*debug_msg_func_t)(const char *format,
-                                                    va_list ap);
-
-static debug_msg_func_t drm_debug_print = drmDebugPrint;
-
 void
 drmMsg(const char *format, ...)
 {
@@ -126,18 +140,12 @@ drmMsg(const char *format, ...)
        if (drm_server_info) {
          drm_server_info->debug_print(format,ap);
        } else {
-         drm_debug_print(format, ap);
+         drmDebugPrint(format, ap);
        }
        va_end(ap);
     }
 }
 
-void
-drmSetDebugMsgFunction(debug_msg_func_t debug_msg_ptr)
-{
-    drm_debug_print = debug_msg_ptr;
-}
-
 static void *drmHashTable = NULL; /* Context switch callbacks */
 
 void *drmGetHashTable(void)
@@ -147,16 +155,12 @@ void *drmGetHashTable(void)
 
 void *drmMalloc(int size)
 {
-    void *pt;
-    if ((pt = malloc(size)))
-       memset(pt, 0, size);
-    return pt;
+    return calloc(1, size);
 }
 
 void drmFree(void *pt)
 {
-    if (pt)
-       free(pt);
+    free(pt);
 }
 
 /**
@@ -273,6 +277,7 @@ static int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
  * If any other failure happened then it will output error mesage using
  * drmMsg() call.
  */
+#if !defined(UDEV)
 static int chown_check_return(const char *path, uid_t owner, gid_t group)
 {
        int rv;
@@ -288,6 +293,7 @@ static int chown_check_return(const char *path, uid_t owner, gid_t group)
                        path, errno, strerror(errno));
        return -1;
 }
+#endif
 
 /**
  * Open the DRM device, creating it if necessary.
@@ -302,24 +308,41 @@ static int chown_check_return(const char *path, uid_t owner, gid_t group)
  * special file node with the major and minor numbers specified by \p dev and
  * parent directory if necessary and was called by root.
  */
-static int drmOpenDevice(long dev, int minor, int type)
+static int drmOpenDevice(dev_t dev, int minor, int type)
 {
     stat_t          st;
+    const char      *dev_name;
     char            buf[64];
     int             fd;
     mode_t          devmode = DRM_DEV_MODE, serv_mode;
+    gid_t           serv_group;
+#if !defined(UDEV)
     int             isroot  = !geteuid();
     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);
+    gid_t           group   = DRM_DEV_GID;
+#endif
+
+    switch (type) {
+    case DRM_NODE_PRIMARY:
+           dev_name = DRM_DEV_NAME;
+           break;
+    case DRM_NODE_CONTROL:
+           dev_name = DRM_CONTROL_DEV_NAME;
+           break;
+    case DRM_NODE_RENDER:
+           dev_name = DRM_RENDER_DEV_NAME;
+           break;
+    default:
+           return -EINVAL;
+    };
+
+    sprintf(buf, dev_name, DRM_DIR_NAME, minor);
     drmMsg("drmOpenDevice: node name is %s\n", buf);
 
     if (drm_server_info) {
        drm_server_info->get_perms(&serv_group, &serv_mode);
        devmode  = serv_mode ? serv_mode : DRM_DEV_MODE;
        devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
-       group = (serv_group >= 0) ? serv_group : DRM_DEV_GID;
     }
 
 #if !defined(UDEV)
@@ -340,6 +363,7 @@ static int drmOpenDevice(long dev, int minor, int type)
     }
 
     if (drm_server_info) {
+       group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
        chown_check_return(buf, user, group);
        chmod(buf, devmode);
     }
@@ -417,11 +441,26 @@ static int drmOpenMinor(int minor, int create, int type)
 {
     int  fd;
     char buf[64];
+    const char *dev_name;
     
     if (create)
        return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
     
-    sprintf(buf, type ? DRM_DEV_NAME : DRM_CONTROL_DEV_NAME, DRM_DIR_NAME, minor);
+    switch (type) {
+    case DRM_NODE_PRIMARY:
+           dev_name = DRM_DEV_NAME;
+           break;
+    case DRM_NODE_CONTROL:
+           dev_name = DRM_CONTROL_DEV_NAME;
+           break;
+    case DRM_NODE_RENDER:
+           dev_name = DRM_RENDER_DEV_NAME;
+           break;
+    default:
+           return -EINVAL;
+    };
+
+    sprintf(buf, dev_name, DRM_DIR_NAME, minor);
     if ((fd = open(buf, O_RDWR, 0)) >= 0)
        return fd;
     return -errno;
@@ -444,7 +483,7 @@ int drmAvailable(void)
     int           retval = 0;
     int           fd;
 
-    if ((fd = drmOpenMinor(0, 1, DRM_NODE_RENDER)) < 0) {
+    if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
 #ifdef __linux__
        /* Try proc for backward Linux compatibility */
        if (!access("/proc/dri/0", R_OK))
@@ -462,11 +501,56 @@ int drmAvailable(void)
     return retval;
 }
 
+static int drmGetMinorBase(int type)
+{
+    switch (type) {
+    case DRM_NODE_PRIMARY:
+        return 0;
+    case DRM_NODE_CONTROL:
+        return 64;
+    case DRM_NODE_RENDER:
+        return 128;
+    default:
+        return -1;
+    };
+}
+
+static int drmGetMinorType(int minor)
+{
+    int type = minor >> 6;
+
+    if (minor < 0)
+        return -1;
+
+    switch (type) {
+    case DRM_NODE_PRIMARY:
+    case DRM_NODE_CONTROL:
+    case DRM_NODE_RENDER:
+        return type;
+    default:
+        return -1;
+    }
+}
+
+static const char *drmGetMinorName(int type)
+{
+    switch (type) {
+    case DRM_NODE_PRIMARY:
+        return DRM_PRIMARY_MINOR_NAME;
+    case DRM_NODE_CONTROL:
+        return DRM_CONTROL_MINOR_NAME;
+    case DRM_NODE_RENDER:
+        return DRM_RENDER_MINOR_NAME;
+    default:
+        return NULL;
+    }
+}
 
 /**
  * Open the device by bus ID.
  *
  * \param busid bus ID.
+ * \param type device node type.
  *
  * \return a file descriptor on success, or a negative value on error.
  *
@@ -476,16 +560,20 @@ 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;
     const char *buf;
     drmSetVersion sv;
+    int        base = drmGetMinorBase(type);
+
+    if (base < 0)
+        return -1;
 
     drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
-    for (i = 0; i < DRM_MAX_MINOR; i++) {
-       fd = drmOpenMinor(i, 1, DRM_NODE_RENDER);
+    for (i = base; i < base + DRM_MAX_MINOR; i++) {
+       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
@@ -525,6 +613,7 @@ static int drmOpenByBusid(const char *busid)
  * Open the device by name.
  *
  * \param name driver name.
+ * \param type the device node type.
  * 
  * \return a file descriptor on success, or a negative value on error.
  * 
@@ -535,19 +624,23 @@ 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;
     drmVersionPtr version;
     char *        id;
+    int           base = drmGetMinorBase(type);
+
+    if (base < 0)
+        return -1;
 
     /*
      * Open the first minor number that matches the driver name and isn't
      * 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) {
+    for (i = base; i < base + DRM_MAX_MINOR; i++) {
+       if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
            if ((version = drmGetVersion(fd))) {
                if (!strcmp(version->name, name)) {
                    drmFreeVersion(version);
@@ -589,9 +682,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,8 +714,29 @@ static int drmOpenByName(const char *name)
  */
 int drmOpen(const char *name, const char *busid)
 {
+    return drmOpenWithType(name, busid, DRM_NODE_PRIMARY);
+}
+
+/**
+ * Open the DRM device with specified type.
+ *
+ * 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.
+ * \param type the device node type to open, PRIMARY, CONTROL or RENDER
+ *
+ * \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 drmOpenWithType(const char *name, const char *busid, int type)
+{
     if (!drmAvailable() && name != NULL && drm_server_info) {
-       /* try to load the kernel */
+       /* try to load the kernel module */
        if (!drm_server_info->load_module(name)) {
            drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
            return -1;
@@ -630,13 +744,13 @@ 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;
 }
@@ -646,6 +760,11 @@ int drmOpenControl(int minor)
     return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
 }
 
+int drmOpenRender(int minor)
+{
+    return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
+}
+
 /**
  * Free the version information returned by drmGetVersion().
  *
@@ -730,12 +849,7 @@ drmVersionPtr drmGetVersion(int fd)
     drmVersionPtr retval;
     drm_version_t *version = drmMalloc(sizeof(*version));
 
-    version->name_len    = 0;
-    version->name        = NULL;
-    version->date_len    = 0;
-    version->date        = NULL;
-    version->desc_len    = 0;
-    version->desc        = NULL;
+    memclear(*version);
 
     if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
        drmFreeKernelVersion(version);
@@ -803,9 +917,12 @@ drmVersionPtr drmGetLibVersion(int fd)
 
 int drmGetCap(int fd, uint64_t capability, uint64_t *value)
 {
-       struct drm_get_cap cap = { capability, 0 };
+       struct drm_get_cap cap;
        int ret;
 
+       memclear(cap);
+       cap.capability = capability;
+
        ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
        if (ret)
                return ret;
@@ -816,7 +933,11 @@ int drmGetCap(int fd, uint64_t capability, uint64_t *value)
 
 int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
 {
-       struct drm_set_client_cap cap  = { capability, value };
+       struct drm_set_client_cap cap;
+
+       memclear(cap);
+       cap.capability = capability;
+       cap.value = value;
 
        return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
 }
@@ -851,8 +972,7 @@ char *drmGetBusid(int fd)
 {
     drm_unique_t u;
 
-    u.unique_len = 0;
-    u.unique     = NULL;
+    memclear(u);
 
     if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
        return NULL;
@@ -881,6 +1001,7 @@ int drmSetBusid(int fd, const char *busid)
 {
     drm_unique_t u;
 
+    memclear(u);
     u.unique     = (char *)busid;
     u.unique_len = strlen(busid);
 
@@ -894,6 +1015,8 @@ int drmGetMagic(int fd, drm_magic_t * magic)
 {
     drm_auth_t auth;
 
+    memclear(auth);
+
     *magic = 0;
     if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
        return -errno;
@@ -905,6 +1028,7 @@ int drmAuthMagic(int fd, drm_magic_t magic)
 {
     drm_auth_t auth;
 
+    memclear(auth);
     auth.magic = magic;
     if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
        return -errno;
@@ -966,9 +1090,9 @@ int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
 {
     drm_map_t map;
 
+    memclear(map);
     map.offset  = offset;
     map.size    = size;
-    map.handle  = 0;
     map.type    = type;
     map.flags   = flags;
     if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
@@ -982,6 +1106,7 @@ int drmRmMap(int fd, drm_handle_t handle)
 {
     drm_map_t map;
 
+    memclear(map);
     map.handle = (void *)(uintptr_t)handle;
 
     if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
@@ -1010,10 +1135,9 @@ int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
 {
     drm_buf_desc_t request;
 
+    memclear(request);
     request.count     = count;
     request.size      = size;
-    request.low_mark  = 0;
-    request.high_mark = 0;
     request.flags     = flags;
     request.agp_start = agp_offset;
 
@@ -1027,8 +1151,7 @@ int drmMarkBufs(int fd, double low, double high)
     drm_buf_info_t info;
     int            i;
 
-    info.count = 0;
-    info.list  = NULL;
+    memclear(info);
 
     if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
        return -EINVAL;
@@ -1078,6 +1201,7 @@ int drmFreeBufs(int fd, int count, int *list)
 {
     drm_buf_free_t request;
 
+    memclear(request);
     request.count = count;
     request.list  = list;
     if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
@@ -1166,8 +1290,7 @@ drmBufInfoPtr drmGetBufInfo(int fd)
     drmBufInfoPtr  retval;
     int            i;
 
-    info.count = 0;
-    info.list  = NULL;
+    memclear(info);
 
     if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
        return NULL;
@@ -1217,9 +1340,7 @@ drmBufMapPtr drmMapBufs(int fd)
     drmBufMapPtr  retval;
     int           i;
 
-    bufs.count = 0;
-    bufs.list  = NULL;
-    bufs.virtual = NULL;
+    memclear(bufs);
     if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
        return NULL;
 
@@ -1335,6 +1456,7 @@ int drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
 {
     drm_lock_t lock;
 
+    memclear(lock);
     lock.context = context;
     lock.flags   = 0;
     if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
@@ -1365,8 +1487,8 @@ int drmUnlock(int fd, drm_context_t context)
 {
     drm_lock_t lock;
 
+    memclear(lock);
     lock.context = context;
-    lock.flags   = 0;
     return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
 }
 
@@ -1377,8 +1499,7 @@ drm_context_t *drmGetReservedContextList(int fd, int *count)
     drm_context_t * retval;
     int           i;
 
-    res.count    = 0;
-    res.contexts = NULL;
+    memclear(res);
     if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
        return NULL;
 
@@ -1431,7 +1552,7 @@ int drmCreateContext(int fd, drm_context_t *handle)
 {
     drm_ctx_t ctx;
 
-    ctx.flags = 0;     /* Modified with functions below */
+    memclear(ctx);
     if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
        return -errno;
     *handle = ctx.handle;
@@ -1442,6 +1563,7 @@ int drmSwitchToContext(int fd, drm_context_t context)
 {
     drm_ctx_t ctx;
 
+    memclear(ctx);
     ctx.handle = context;
     if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
        return -errno;
@@ -1458,8 +1580,8 @@ int drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags)
      * X server (which promises to maintain hardware context), or in the
      * client-side library when buffers are swapped on behalf of two threads.
      */
+    memclear(ctx);
     ctx.handle = context;
-    ctx.flags  = 0;
     if (flags & DRM_CONTEXT_PRESERVED)
        ctx.flags |= _DRM_CONTEXT_PRESERVED;
     if (flags & DRM_CONTEXT_2DONLY)
@@ -1474,6 +1596,7 @@ int drmGetContextFlags(int fd, drm_context_t context,
 {
     drm_ctx_t ctx;
 
+    memclear(ctx);
     ctx.handle = context;
     if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
        return -errno;
@@ -1505,6 +1628,8 @@ int drmGetContextFlags(int fd, drm_context_t context,
 int drmDestroyContext(int fd, drm_context_t handle)
 {
     drm_ctx_t ctx;
+
+    memclear(ctx);
     ctx.handle = handle;
     if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
        return -errno;
@@ -1514,6 +1639,8 @@ int drmDestroyContext(int fd, drm_context_t handle)
 int drmCreateDrawable(int fd, drm_drawable_t *handle)
 {
     drm_draw_t draw;
+
+    memclear(draw);
     if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
        return -errno;
     *handle = draw.handle;
@@ -1523,6 +1650,8 @@ int drmCreateDrawable(int fd, drm_drawable_t *handle)
 int drmDestroyDrawable(int fd, drm_drawable_t handle)
 {
     drm_draw_t draw;
+
+    memclear(draw);
     draw.handle = handle;
     if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
        return -errno;
@@ -1535,6 +1664,7 @@ int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
 {
     drm_update_draw_t update;
 
+    memclear(update);
     update.handle = handle;
     update.type = type;
     update.num = num;
@@ -1600,6 +1730,7 @@ int drmAgpEnable(int fd, unsigned long mode)
 {
     drm_agp_mode_t m;
 
+    memclear(m);
     m.mode = mode;
     if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
        return -errno;
@@ -1628,9 +1759,9 @@ int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
 {
     drm_agp_buffer_t b;
 
+    memclear(b);
     *handle = DRM_AGP_NO_HANDLE;
     b.size   = size;
-    b.handle = 0;
     b.type   = type;
     if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
        return -errno;
@@ -1657,7 +1788,7 @@ int drmAgpFree(int fd, drm_handle_t handle)
 {
     drm_agp_buffer_t b;
 
-    b.size   = 0;
+    memclear(b);
     b.handle = handle;
     if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
        return -errno;
@@ -1682,6 +1813,7 @@ int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
 {
     drm_agp_binding_t b;
 
+    memclear(b);
     b.handle = handle;
     b.offset = offset;
     if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
@@ -1706,8 +1838,8 @@ int drmAgpUnbind(int fd, drm_handle_t handle)
 {
     drm_agp_binding_t b;
 
+    memclear(b);
     b.handle = handle;
-    b.offset = 0;
     if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
        return -errno;
     return 0;
@@ -1729,6 +1861,8 @@ int drmAgpVersionMajor(int fd)
 {
     drm_agp_info_t i;
 
+    memclear(i);
+
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
        return -errno;
     return i.agp_version_major;
@@ -1750,6 +1884,8 @@ int drmAgpVersionMinor(int fd)
 {
     drm_agp_info_t i;
 
+    memclear(i);
+
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
        return -errno;
     return i.agp_version_minor;
@@ -1771,6 +1907,8 @@ unsigned long drmAgpGetMode(int fd)
 {
     drm_agp_info_t i;
 
+    memclear(i);
+
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
        return 0;
     return i.mode;
@@ -1792,6 +1930,8 @@ unsigned long drmAgpBase(int fd)
 {
     drm_agp_info_t i;
 
+    memclear(i);
+
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
        return 0;
     return i.aperture_base;
@@ -1813,6 +1953,8 @@ unsigned long drmAgpSize(int fd)
 {
     drm_agp_info_t i;
 
+    memclear(i);
+
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
        return 0;
     return i.aperture_size;
@@ -1834,6 +1976,8 @@ unsigned long drmAgpMemoryUsed(int fd)
 {
     drm_agp_info_t i;
 
+    memclear(i);
+
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
        return 0;
     return i.memory_used;
@@ -1855,6 +1999,8 @@ unsigned long drmAgpMemoryAvail(int fd)
 {
     drm_agp_info_t i;
 
+    memclear(i);
+
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
        return 0;
     return i.memory_allowed;
@@ -1876,6 +2022,8 @@ unsigned int drmAgpVendorId(int fd)
 {
     drm_agp_info_t i;
 
+    memclear(i);
+
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
        return 0;
     return i.id_vendor;
@@ -1897,6 +2045,8 @@ unsigned int drmAgpDeviceId(int fd)
 {
     drm_agp_info_t i;
 
+    memclear(i);
+
     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
        return 0;
     return i.id_device;
@@ -1906,9 +2056,10 @@ int drmScatterGatherAlloc(int fd, unsigned long size, drm_handle_t *handle)
 {
     drm_scatter_gather_t sg;
 
+    memclear(sg);
+
     *handle = 0;
     sg.size   = size;
-    sg.handle = 0;
     if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
        return -errno;
     *handle = sg.handle;
@@ -1919,7 +2070,7 @@ int drmScatterGatherFree(int fd, drm_handle_t handle)
 {
     drm_scatter_gather_t sg;
 
-    sg.size   = 0;
+    memclear(sg);
     sg.handle = handle;
     if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
        return -errno;
@@ -2010,6 +2161,7 @@ int drmCtlInstHandler(int fd, int irq)
 {
     drm_control_t ctl;
 
+    memclear(ctl);
     ctl.func  = DRM_INST_HANDLER;
     ctl.irq   = irq;
     if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
@@ -2033,6 +2185,7 @@ int drmCtlUninstHandler(int fd)
 {
     drm_control_t ctl;
 
+    memclear(ctl);
     ctl.func  = DRM_UNINST_HANDLER;
     ctl.irq   = 0;
     if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
@@ -2044,8 +2197,8 @@ int drmFinish(int fd, int context, drmLockFlags flags)
 {
     drm_lock_t lock;
 
+    memclear(lock);
     lock.context = context;
-    lock.flags   = 0;
     if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
     if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
     if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
@@ -2075,6 +2228,7 @@ int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
 {
     drm_irq_busid_t p;
 
+    memclear(p);
     p.busnum  = busnum;
     p.devnum  = devnum;
     p.funcnum = funcnum;
@@ -2117,6 +2271,7 @@ int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
 {
     drm_ctx_priv_map_t map;
 
+    memclear(map);
     map.ctx_id = ctx_id;
     map.handle = (void *)(uintptr_t)handle;
 
@@ -2130,6 +2285,7 @@ int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
 {
     drm_ctx_priv_map_t map;
 
+    memclear(map);
     map.ctx_id = ctx_id;
 
     if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
@@ -2146,6 +2302,7 @@ int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
 {
     drm_map_t map;
 
+    memclear(map);
     map.offset = idx;
     if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
        return -errno;
@@ -2163,6 +2320,7 @@ int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
 {
     drm_client_t client;
 
+    memclear(client);
     client.idx = idx;
     if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
        return -errno;
@@ -2177,8 +2335,9 @@ int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
 int drmGetStats(int fd, drmStatsT *stats)
 {
     drm_stats_t s;
-    int         i;
+    unsigned    i;
 
+    memclear(s);
     if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
        return -errno;
 
@@ -2316,6 +2475,7 @@ int drmSetInterfaceVersion(int fd, drmSetVersion *version)
     int retcode = 0;
     drm_set_version_t sv;
 
+    memclear(sv);
     sv.drm_di_major = version->drm_di_major;
     sv.drm_di_minor = version->drm_di_minor;
     sv.drm_dd_major = version->drm_dd_major;
@@ -2347,12 +2507,11 @@ int drmSetInterfaceVersion(int fd, drmSetVersion *version)
  */
 int drmCommandNone(int fd, unsigned long drmCommandIndex)
 {
-    void *data = NULL; /* dummy */
     unsigned long request;
 
     request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
 
-    if (drmIoctl(fd, request, data)) {
+    if (drmIoctl(fd, request, NULL)) {
        return -errno;
     }
     return 0;
@@ -2449,6 +2608,7 @@ static struct {
     char *BusID;
     int fd;
     int refcount;
+    int type;
 } connection[DRM_MAX_FDS];
 
 static int nr_fds = 0;
@@ -2457,23 +2617,30 @@ int drmOpenOnce(void *unused,
                const char *BusID,
                int *newlyopened)
 {
+    return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
+}
+
+int drmOpenOnceWithType(const char *BusID, int *newlyopened, int type)
+{
     int i;
     int fd;
    
     for (i = 0; i < nr_fds; i++)
-       if (strcmp(BusID, connection[i].BusID) == 0) {
+       if ((strcmp(BusID, connection[i].BusID) == 0) &&
+           (connection[i].type == type)) {
            connection[i].refcount++;
            *newlyopened = 0;
            return connection[i].fd;
        }
 
-    fd = drmOpen(unused, BusID);
-    if (fd <= 0 || nr_fds == DRM_MAX_FDS)
+    fd = drmOpenWithType(NULL, BusID, type);
+    if (fd < 0 || nr_fds == DRM_MAX_FDS)
        return fd;
    
     connection[nr_fds].BusID = strdup(BusID);
     connection[nr_fds].fd = fd;
     connection[nr_fds].refcount = 1;
+    connection[nr_fds].type = type;
     *newlyopened = 1;
 
     if (0)
@@ -2507,12 +2674,12 @@ void drmCloseOnce(int fd)
 
 int drmSetMaster(int fd)
 {
-       return ioctl(fd, DRM_IOCTL_SET_MASTER, 0);
+       return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
 }
 
 int drmDropMaster(int fd)
 {
-       return ioctl(fd, DRM_IOCTL_DROP_MASTER, 0);
+       return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
 }
 
 char *drmGetDeviceNameFromFd(int fd)
@@ -2541,11 +2708,35 @@ char *drmGetDeviceNameFromFd(int fd)
        return strdup(name);
 }
 
+int drmGetNodeTypeFromFd(int fd)
+{
+       struct stat sbuf;
+       int maj, min, type;
+
+       if (fstat(fd, &sbuf))
+               return -1;
+
+       maj = major(sbuf.st_rdev);
+       min = minor(sbuf.st_rdev);
+
+       if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       type = drmGetMinorType(min);
+       if (type == -1)
+               errno = ENODEV;
+       return type;
+}
+
 int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd)
 {
        struct drm_prime_handle args;
        int ret;
 
+       memclear(args);
+       args.fd = -1;
        args.handle = handle;
        args.flags = flags;
        ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
@@ -2561,8 +2752,8 @@ int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
        struct drm_prime_handle args;
        int ret;
 
+       memclear(args);
        args.fd = prime_fd;
-       args.flags = 0;
        ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
        if (ret)
                return ret;
@@ -2571,3 +2762,422 @@ 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) {
+                       snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
+                                ent->d_name);
+
+                       free(pent);
+                       closedir(sysdir);
+
+                       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);
+}
+
+#ifdef __linux__
+static int drmParseSubsystemType(const char *str)
+{
+    char link[PATH_MAX + 1] = "";
+    char *name;
+
+    if (readlink(str, link, PATH_MAX) < 0)
+        return -EINVAL;
+
+    name = strrchr(link, '/');
+    if (!name)
+        return -EINVAL;
+
+    name++;
+
+    if (strncmp(name, "pci", 3) == 0)
+        return DRM_BUS_PCI;
+
+    return -EINVAL;
+}
+
+static int drmParsePciBusInfo(const char *str, drmPciBusInfoPtr info)
+{
+    int domain, bus, dev, func;
+    char *value;
+
+    if (str == NULL)
+        return -EINVAL;
+
+    value = strstr(str, "PCI_SLOT_NAME=");
+    if (value == NULL)
+        return -EINVAL;
+
+    value += strlen("PCI_SLOT_NAME=");
+
+    if (sscanf(value, "%04x:%02x:%02x.%1u",
+               &domain, &bus, &dev, &func) != 4)
+        return -EINVAL;
+
+    info->domain = domain;
+    info->bus = bus;
+    info->dev = dev;
+    info->func = func;
+
+    return 0;
+}
+
+static int drmSameDevice(drmDevicePtr a, drmDevicePtr b)
+{
+    if (a->bustype != b->bustype)
+        return 0;
+
+    switch (a->bustype) {
+    case DRM_BUS_PCI:
+        if (memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0)
+            return 1;
+    default:
+        break;
+    }
+
+    return 0;
+}
+
+static int drmGetNodeType(const char *name)
+{
+    if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
+        sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
+        return DRM_NODE_PRIMARY;
+
+    if (strncmp(name, DRM_CONTROL_MINOR_NAME,
+        sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0)
+        return DRM_NODE_CONTROL;
+
+    if (strncmp(name, DRM_RENDER_MINOR_NAME,
+        sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
+        return DRM_NODE_RENDER;
+
+    return -EINVAL;
+}
+
+static int drmParsePciDeviceInfo(const unsigned char *config,
+                                 drmPciDeviceInfoPtr device)
+{
+    if (config == NULL)
+        return -EINVAL;
+
+    device->vendor_id = config[0] | (config[1] << 8);
+    device->device_id = config[2] | (config[3] << 8);
+    device->revision_id = config[8];
+    device->subvendor_id = config[44] | (config[45] << 8);
+    device->subdevice_id = config[46] | (config[47] << 8);
+
+    return 0;
+}
+
+static void drmFreeDevice(drmDevicePtr device)
+{
+    int i;
+
+    if (device == NULL)
+        return;
+
+    if (device->nodes != NULL)
+        for (i = 0; i < DRM_NODE_MAX; i++)
+            free(device->nodes[i]);
+
+    free(device->nodes);
+    free(device->businfo.pci);
+    free(device->deviceinfo.pci);
+}
+
+void drmFreeDevices(drmDevicePtr devices[], int count)
+{
+    int i;
+
+    if (devices == NULL)
+        return;
+
+    for (i = 0; i < count; i++) {
+        drmFreeDevice(devices[i]);
+        free(devices[i]);
+        devices[i] = NULL;
+    }
+}
+
+/**
+ * Get drm devices on the system
+ *
+ * \param devices the array of devices with drmDevicePtr elements
+ *                can be NULL to get the device number first
+ * \param max_devices the maximum number of devices for the array
+ *
+ * \return on error - negative error code,
+ *         if devices is NULL - total number of devices available on the system,
+ *         alternatively the number of devices stored in devices[], which is
+ *         capped by the max_devices.
+ */
+int drmGetDevices(drmDevicePtr devices[], int max_devices)
+{
+    drmDevicePtr devs = NULL;
+    drmPciBusInfoPtr pcibus = NULL;
+    drmPciDeviceInfoPtr pcidevice = NULL;
+    DIR *sysdir = NULL;
+    struct dirent *dent = NULL;
+    struct stat sbuf = {0};
+    char node[PATH_MAX + 1] = "";
+    char path[PATH_MAX + 1] = "";
+    char data[128] = "";
+    unsigned char config[64] = "";
+    int node_type, subsystem_type;
+    int maj, min;
+    int fd;
+    int ret, i = 0, j, node_count, device_count = 0;
+    int max_count = 16;
+    int *duplicated = NULL;
+
+    devs = calloc(max_count, sizeof(*devs));
+    if (devs == NULL)
+        return -ENOMEM;
+
+    sysdir = opendir(DRM_DIR_NAME);
+    if (!sysdir) {
+        ret = -errno;
+        goto free_locals;
+    }
+
+    while ((dent = readdir(sysdir))) {
+        node_type = drmGetNodeType(dent->d_name);
+        if (node_type < 0)
+            continue;
+
+        snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
+        if (stat(node, &sbuf))
+            continue;
+
+        maj = major(sbuf.st_rdev);
+        min = minor(sbuf.st_rdev);
+
+        if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+            continue;
+
+        snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem",
+                 maj, min);
+        subsystem_type = drmParseSubsystemType(path);
+
+        if (subsystem_type < 0)
+            continue;
+
+        switch (subsystem_type) {
+        case DRM_BUS_PCI:
+            pcibus = calloc(1, sizeof(*pcibus));
+            if (pcibus == NULL) {
+                ret = -ENOMEM;
+                goto free_locals;
+            }
+
+            snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/uevent",
+                     maj, min);
+            fd = open(path, O_RDONLY);
+            if (fd < 0) {
+                ret = -errno;
+                goto free_locals;
+            }
+            ret = read(fd, data, sizeof(data));
+            if (ret < 0) {
+                ret = -errno;
+                close(fd);
+                goto free_locals;
+            }
+
+            ret = drmParsePciBusInfo(data, pcibus);
+            close(fd);
+            if (ret)
+                goto free_locals;
+
+            if (i >= max_count) {
+                max_count += 16;
+                devs = realloc(devs, max_count * sizeof(*devs));
+            }
+
+            devs[i].businfo.pci = pcibus;
+            devs[i].bustype = subsystem_type;
+            devs[i].nodes = calloc(DRM_NODE_MAX, sizeof(char *));
+            if (devs[i].nodes == NULL) {
+                ret = -ENOMEM;
+                goto free_locals;
+            }
+            devs[i].nodes[node_type] = strdup(node);
+            if (devs[i].nodes[node_type] == NULL) {
+                ret = -ENOMEM;
+                goto free_locals;
+            }
+            devs[i].available_nodes = 1 << node_type;
+
+            if (devices != NULL) {
+                snprintf(path, PATH_MAX, "/sys/class/drm/%s/device/config",
+                         dent->d_name);
+                fd = open(path, O_RDONLY);
+                if (fd < 0) {
+                     ret = -errno;
+                     goto free_locals;
+                }
+                ret = read(fd, config, 64);
+                if (ret < 0) {
+                    ret = -errno;
+                    close(fd);
+                    goto free_locals;
+                }
+
+                pcidevice = calloc(1, sizeof(*pcidevice));
+                if (pcidevice == NULL) {
+                    ret = -ENOMEM;
+                    goto free_locals;
+                }
+
+                ret = drmParsePciDeviceInfo(config, pcidevice);
+                if (ret)
+                    goto free_locals;
+
+                devs[i].deviceinfo.pci = pcidevice;
+                close(fd);
+            }
+            break;
+        default:
+            fprintf(stderr, "The subsystem type is not supported yet\n");
+            break;
+        }
+        i++;
+    }
+
+    node_count = i;
+
+    /* merge duplicated devices with same domain/bus/device/func IDs */
+    duplicated = calloc(node_count, sizeof(*duplicated));
+    if (duplicated == NULL) {
+        ret = -ENOMEM;
+        goto free_locals;
+    }
+
+    for (i = 0; i < node_count; i++) {
+        for (j = i+1; j < node_count; j++) {
+            if (duplicated[i] || duplicated[j])
+                continue;
+            if (drmSameDevice(&devs[i], &devs[j])) {
+                duplicated[j] = 1;
+                devs[i].available_nodes |= devs[j].available_nodes;
+                node_type = log2(devs[j].available_nodes);
+                devs[i].nodes[node_type] = devs[j].nodes[node_type];
+                free(devs[j].nodes);
+                free(devs[j].businfo.pci);
+                free(devs[j].deviceinfo.pci);
+            }
+        }
+    }
+
+    for (i = 0; i < node_count; i++) {
+        if(duplicated[i] == 0) {
+            if ((devices != NULL) && (device_count < max_devices)) {
+                devices[device_count] = calloc(1, sizeof(drmDevice));
+                if (devices[device_count] == NULL) {
+                    ret = -ENOMEM;
+                    break;
+                }
+                memcpy(devices[device_count], &devs[i], sizeof(drmDevice));
+            } else
+                drmFreeDevice(&devs[i]);
+            device_count++;
+        }
+    }
+
+    if (i < node_count) {
+        drmFreeDevices(devices, device_count);
+        for ( ; i < node_count; i++)
+            if(duplicated[i] == 0)
+                drmFreeDevice(&devs[i]);
+    } else
+        ret = device_count;
+
+    free(duplicated);
+    free(devs);
+    closedir(sysdir);
+    return ret;
+
+free_locals:
+    for (j = 0; j < i; j++)
+        drmFreeDevice(&devs[j]);
+    free(pcidevice);
+    free(pcibus);
+    free(devs);
+    closedir(sysdir);
+    return ret;
+}
+#else
+void drmFreeDevices(drmDevicePtr devices[], int count)
+{
+    (void)devices;
+    (void)count;
+}
+
+int drmGetDevices(drmDevicePtr devices[], int max_devices)
+{
+    (void)devices;
+    (void)max_devices;
+    return -EINVAL;
+}
+
+#warning "Missing implementation of drmGetDevices/drmFreeDevices"
+
+#endif