OSDN Git Service

Fill fence sequence after emit ioctl.
[android-x86/external-libdrm.git] / libdrm / xf86drm.c
index a2a2e28..4265c32 100644 (file)
  * DEALINGS IN THE SOFTWARE.
  */
 
-#ifdef HAVE_XORG_CONFIG_H
-#include <xorg-config.h>
-#endif
-
-#ifdef XFree86Server
-# include "xf86.h"
-# include "xf86_OSproc.h"
-# include "drm.h"
-# include "xf86_ansic.h"
-# define _DRM_MALLOC xalloc
-# define _DRM_FREE   xfree
-# ifndef XFree86LOADER
-#  include <sys/mman.h>
-# endif
-#else
-# include <stdio.h>
-# include <stdlib.h>
-# include <unistd.h>
-# include <string.h>
-# include <ctype.h>
-# include <fcntl.h>
-# include <errno.h>
-# include <signal.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-# define stat_t struct stat
-# include <sys/ioctl.h>
-# include <sys/mman.h>
-# include <sys/time.h>
-# include <stdarg.h>
-# define _DRM_MALLOC malloc
-# define _DRM_FREE   free
-# include "drm.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
 #endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#define stat_t struct stat
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <stdarg.h>
 
 /* Not all systems have MAP_FAILED defined */
 #ifndef MAP_FAILED
 
 #define DRM_MSG_VERBOSITY 3
 
+static drmServerInfoPtr drm_server_info;
+
+void drmSetServerInfo(drmServerInfoPtr info)
+{
+    drm_server_info = info;
+}
+
 /**
  * Output a message to stderr.
  *
  * \internal
  * This function is a wrapper around vfprintf().
  */
+
+static int drmDebugPrint(const char *format, va_list ap)
+{
+    return vfprintf(stderr, format, ap);
+}
+
+static int (*drm_debug_print)(const char *format, va_list ap) = drmDebugPrint;
+
 static void
 drmMsg(const char *format, ...)
 {
     va_list    ap;
-
-#ifndef XFree86Server
     const char *env;
-    if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose"))
-#endif
+    if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) || drm_server_info)
     {
        va_start(ap, format);
-#ifdef XFree86Server
-       xf86VDrvMsgVerb(-1, X_NONE, DRM_MSG_VERBOSITY, format, ap);
-#else
-       vfprintf(stderr, format, ap);
-#endif
+       if (drm_server_info) {
+         drm_server_info->debug_print(format,ap);
+       } else {
+         drm_debug_print(format, ap);
+       }
        va_end(ap);
     }
 }
 
+void
+drmSetDebugMsgFunction(int (*debug_msg_ptr)(const char *format, va_list ap))
+{
+    drm_debug_print = debug_msg_ptr;
+}
+
 static void *drmHashTable = NULL; /* Context switch callbacks */
 
-typedef struct drmHashEntry {
-    int      fd;
-    void     (*f)(int, void *, void *);
-    void     *tagTable;
-} drmHashEntry;
+void *drmGetHashTable(void)
+{
+    return drmHashTable;
+}
 
 void *drmMalloc(int size)
 {
     void *pt;
-    if ((pt = _DRM_MALLOC(size))) memset(pt, 0, size);
+    if ((pt = malloc(size)))
+       memset(pt, 0, size);
     return pt;
 }
 
 void drmFree(void *pt)
 {
-    if (pt) _DRM_FREE(pt);
+    if (pt)
+       free(pt);
 }
 
 /* drmStrdup can't use strdup(3), since it doesn't call _DRM_MALLOC... */
@@ -159,7 +162,7 @@ static char *drmStrdup(const char *s)
     if (!s)
         return NULL;
 
-    retval = _DRM_MALLOC(strlen(s)+1);
+    retval = malloc(strlen(s)+1);
     if (!retval)
         return NULL;
 
@@ -178,13 +181,14 @@ static unsigned long drmGetKeyFromFd(int fd)
     return st.st_rdev;
 }
 
-static drmHashEntry *drmGetEntry(int fd)
+drmHashEntry *drmGetEntry(int fd)
 {
     unsigned long key = drmGetKeyFromFd(fd);
     void          *value;
     drmHashEntry  *entry;
 
-    if (!drmHashTable) drmHashTable = drmHashCreate();
+    if (!drmHashTable)
+       drmHashTable = drmHashCreate();
 
     if (drmHashLookup(drmHashTable, key, &value)) {
        entry           = drmMalloc(sizeof(*entry));
@@ -265,24 +269,24 @@ static int drmOpenDevice(long dev, int minor)
     stat_t          st;
     char            buf[64];
     int             fd;
-    mode_t          devmode = DRM_DEV_MODE;
+    mode_t          devmode = DRM_DEV_MODE, serv_mode;
     int             isroot  = !geteuid();
-#if defined(XFree86Server)
     uid_t           user    = DRM_DEV_UID;
-    gid_t           group   = DRM_DEV_GID;
-#endif
-
+    gid_t           group   = DRM_DEV_GID, serv_group;
+    
     sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor);
     drmMsg("drmOpenDevice: node name is %s\n", buf);
 
-#if defined(XFree86Server)
-    devmode  = xf86ConfigDRI.mode ? xf86ConfigDRI.mode : DRM_DEV_MODE;
-    devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
-    group = (xf86ConfigDRI.group >= 0) ? xf86ConfigDRI.group : DRM_DEV_GID;
-#endif
+    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 (stat(DRM_DIR_NAME, &st)) {
-       if (!isroot) return DRM_ERR_NOT_ROOT;
+       if (!isroot)
+           return DRM_ERR_NOT_ROOT;
        mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
        chown(DRM_DIR_NAME, 0, 0); /* root:root */
        chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
@@ -290,36 +294,41 @@ static int drmOpenDevice(long dev, int minor)
 
     /* Check if the device node exists and create it if necessary. */
     if (stat(buf, &st)) {
-       if (!isroot) return DRM_ERR_NOT_ROOT;
+       if (!isroot)
+           return DRM_ERR_NOT_ROOT;
        remove(buf);
        mknod(buf, S_IFCHR | devmode, dev);
     }
-#if defined(XFree86Server)
-    chown(buf, user, group);
-    chmod(buf, devmode);
-#endif
+
+    if (drm_server_info) {
+       chown(buf, user, group);
+       chmod(buf, devmode);
+    }
 
     fd = open(buf, O_RDWR, 0);
     drmMsg("drmOpenDevice: open result is %d, (%s)\n",
                fd, fd < 0 ? strerror(errno) : "OK");
-    if (fd >= 0) return fd;
+    if (fd >= 0)
+       return fd;
 
     /* Check if the device node is not what we expect it to be, and recreate it
      * and try again if so.
      */
     if (st.st_rdev != dev) {
-       if (!isroot) return DRM_ERR_NOT_ROOT;
+       if (!isroot)
+           return DRM_ERR_NOT_ROOT;
        remove(buf);
        mknod(buf, S_IFCHR | devmode, dev);
-#if defined(XFree86Server)
-       chown(buf, user, group);
-       chmod(buf, devmode);
-#endif
+       if (drm_server_info) {
+           chown(buf, user, group);
+           chmod(buf, devmode);
+       }
     }
     fd = open(buf, O_RDWR, 0);
     drmMsg("drmOpenDevice: open result is %d, (%s)\n",
                fd, fd < 0 ? strerror(errno) : "OK");
-    if (fd >= 0) return fd;
+    if (fd >= 0)
+       return fd;
 
     drmMsg("drmOpenDevice: Open failed\n");
     remove(buf);
@@ -344,10 +353,12 @@ static int drmOpenMinor(int minor, int create)
     int  fd;
     char buf[64];
     
-    if (create) return drmOpenDevice(makedev(DRM_MAJOR, minor), minor);
+    if (create)
+       return drmOpenDevice(makedev(DRM_MAJOR, minor), minor);
     
     sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor);
-    if ((fd = open(buf, O_RDWR, 0)) >= 0) return fd;
+    if ((fd = open(buf, O_RDWR, 0)) >= 0)
+       return fd;
     return -errno;
 }
 
@@ -371,7 +382,8 @@ int drmAvailable(void)
     if ((fd = drmOpenMinor(0, 1)) < 0) {
 #ifdef __linux__
        /* Try proc for backward Linux compatibility */
-       if (!access("/proc/dri/0", R_OK)) return 1;
+       if (!access("/proc/dri/0", R_OK))
+           return 1;
 #endif
        return 0;
     }
@@ -422,7 +434,8 @@ static int drmOpenByBusid(const char *busid)
                drmFreeBusid(buf);
                return fd;
            }
-           if (buf) drmFreeBusid(buf);
+           if (buf)
+               drmFreeBusid(buf);
            close(fd);
        }
     }
@@ -452,16 +465,16 @@ static int drmOpenByName(const char *name)
     char *        id;
     
     if (!drmAvailable()) {
-#if !defined(XFree86Server)
-       return -1;
-#else
-        /* try to load the kernel module now */
-        if (!xf86LoadKernelModule(name)) {
-            ErrorF("[drm] failed to load kernel module \"%s\"\n",
-                  name);
-            return -1;
-        }
-#endif
+       if (!drm_server_info) {
+           return -1;
+       }
+       else {
+           /* try to load the kernel module now */
+           if (!drm_server_info->load_module(name)) {
+               drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
+               return -1;
+           }
+       }
     }
 
     /*
@@ -543,21 +556,16 @@ static int drmOpenByName(const char *name)
  */
 int drmOpen(const char *name, const char *busid)
 {
-#ifdef XFree86Server
-    if (!drmAvailable() && name != NULL) {
+    if (!drmAvailable() && name != NULL && drm_server_info) {
        /* try to load the kernel */
-       if (!xf86LoadKernelModule(name)) {
-           ErrorF("[drm] failed to load kernel module \"%s\"\n",
-                  name);
+       if (!drm_server_info->load_module(name)) {
+           drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
            return -1;
        }
     }
-#endif
 
     if (busid) {
-       int fd;
-
-       fd = drmOpenByBusid(busid);
+       int fd = drmOpenByBusid(busid);
        if (fd >= 0)
            return fd;
     }
@@ -580,10 +588,11 @@ int drmOpen(const char *name, const char *busid)
  */
 void drmFreeVersion(drmVersionPtr v)
 {
-    if (!v) return;
-    if (v->name) drmFree(v->name);
-    if (v->date) drmFree(v->date);
-    if (v->desc) drmFree(v->desc);
+    if (!v)
+       return;
+    drmFree(v->name);
+    drmFree(v->date);
+    drmFree(v->desc);
     drmFree(v);
 }
 
@@ -599,10 +608,11 @@ void drmFreeVersion(drmVersionPtr v)
  */
 static void drmFreeKernelVersion(drm_version_t *v)
 {
-    if (!v) return;
-    if (v->name) drmFree(v->name);
-    if (v->date) drmFree(v->date);
-    if (v->desc) drmFree(v->desc);
+    if (!v)
+       return;
+    drmFree(v->name);
+    drmFree(v->date);
+    drmFree(v->desc);
     drmFree(v);
 }
 
@@ -706,15 +716,17 @@ drmVersionPtr drmGetLibVersion(int fd)
     drm_version_t *version = drmMalloc(sizeof(*version));
 
     /* Version history:
+     *   NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
      *   revision 1.0.x = original DRM interface with no drmGetLibVersion
      *                    entry point and many drm<Device> extensions
      *   revision 1.1.x = added drmCommand entry points for device extensions
      *                    added drmGetLibVersion to identify libdrm.a version
      *   revision 1.2.x = added drmSetInterfaceVersion
      *                    modified drmOpen to handle both busid and name
+     *   revision 1.3.x = added server + memory manager
      */
     version->version_major      = 1;
-    version->version_minor      = 2;
+    version->version_minor      = 3;
     version->version_patchlevel = 0;
 
     return (drmVersionPtr)version;
@@ -754,9 +766,11 @@ char *drmGetBusid(int fd)
     u.unique_len = 0;
     u.unique     = NULL;
 
-    if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL;
+    if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
+       return NULL;
     u.unique = drmMalloc(u.unique_len + 1);
-    if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL;
+    if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
+       return NULL;
     u.unique[u.unique_len] = '\0';
 
     return u.unique;
@@ -793,7 +807,8 @@ int drmGetMagic(int fd, drm_magic_t * magic)
     drm_auth_t auth;
 
     *magic = 0;
-    if (ioctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
+       return -errno;
     *magic = auth.magic;
     return 0;
 }
@@ -803,7 +818,8 @@ int drmAuthMagic(int fd, drm_magic_t magic)
     drm_auth_t auth;
 
     auth.magic = magic;
-    if (ioctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
+       return -errno;
     return 0;
 }
 
@@ -867,8 +883,10 @@ int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
     map.handle  = 0;
     map.type    = type;
     map.flags   = flags;
-    if (ioctl(fd, DRM_IOCTL_ADD_MAP, &map)) return -errno;
-    if (handle) *handle = (drm_handle_t)map.handle;
+    if (ioctl(fd, DRM_IOCTL_ADD_MAP, &map))
+       return -errno;
+    if (handle)
+       *handle = (drm_handle_t)map.handle;
     return 0;
 }
 
@@ -878,7 +896,8 @@ int drmRmMap(int fd, drm_handle_t handle)
 
     map.handle = (void *)handle;
 
-    if(ioctl(fd, DRM_IOCTL_RM_MAP, &map)) return -errno;
+    if(ioctl(fd, DRM_IOCTL_RM_MAP, &map))
+       return -errno;
     return 0;
 }
 
@@ -910,7 +929,8 @@ int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
     request.flags     = flags;
     request.agp_start = agp_offset;
 
-    if (ioctl(fd, DRM_IOCTL_ADD_BUFS, &request)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_ADD_BUFS, &request))
+       return -errno;
     return request.count;
 }
 
@@ -922,9 +942,11 @@ int drmMarkBufs(int fd, double low, double high)
     info.count = 0;
     info.list  = NULL;
 
-    if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) return -EINVAL;
+    if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info))
+       return -EINVAL;
 
-    if (!info.count) return -EINVAL;
+    if (!info.count)
+       return -EINVAL;
 
     if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
        return -ENOMEM;
@@ -970,7 +992,8 @@ int drmFreeBufs(int fd, int count, int *list)
 
     request.count = count;
     request.list  = list;
-    if (ioctl(fd, DRM_IOCTL_FREE_BUFS, &request)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_FREE_BUFS, &request))
+       return -errno;
     return 0;
 }
 
@@ -1018,7 +1041,8 @@ int drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address)
 {
     static unsigned long pagesize_mask = 0;
 
-    if (fd < 0) return -EINVAL;
+    if (fd < 0)
+       return -EINVAL;
 
     if (!pagesize_mask)
        pagesize_mask = getpagesize() - 1;
@@ -1026,7 +1050,8 @@ int drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address)
     size = (size + pagesize_mask) & ~pagesize_mask;
 
     *address = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
-    if (*address == MAP_FAILED) return -errno;
+    if (*address == MAP_FAILED)
+       return -errno;
     return 0;
 }
 
@@ -1056,7 +1081,8 @@ drmBufInfoPtr drmGetBufInfo(int fd)
     info.count = 0;
     info.list  = NULL;
 
-    if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) return NULL;
+    if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info))
+       return NULL;
 
     if (info.count) {
        if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
@@ -1106,9 +1132,11 @@ drmBufMapPtr drmMapBufs(int fd)
     bufs.count = 0;
     bufs.list  = NULL;
     bufs.virtual = NULL;
-    if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) return NULL;
+    if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
+       return NULL;
 
-    if (!bufs.count) return NULL;
+    if (!bufs.count)
+       return NULL;
 
        if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
            return NULL;
@@ -1263,20 +1291,25 @@ drm_context_t *drmGetReservedContextList(int fd, int *count)
 
     res.count    = 0;
     res.contexts = NULL;
-    if (ioctl(fd, DRM_IOCTL_RES_CTX, &res)) return NULL;
+    if (ioctl(fd, DRM_IOCTL_RES_CTX, &res))
+       return NULL;
 
-    if (!res.count) return NULL;
+    if (!res.count)
+       return NULL;
 
-    if (!(list   = drmMalloc(res.count * sizeof(*list)))) return NULL;
+    if (!(list   = drmMalloc(res.count * sizeof(*list))))
+       return NULL;
     if (!(retval = drmMalloc(res.count * sizeof(*retval)))) {
        drmFree(list);
        return NULL;
     }
 
     res.contexts = list;
-    if (ioctl(fd, DRM_IOCTL_RES_CTX, &res)) return NULL;
+    if (ioctl(fd, DRM_IOCTL_RES_CTX, &res))
+       return NULL;
 
-    for (i = 0; i < res.count; i++) retval[i] = list[i].handle;
+    for (i = 0; i < res.count; i++)
+       retval[i] = list[i].handle;
     drmFree(list);
 
     *count = res.count;
@@ -1311,7 +1344,8 @@ int drmCreateContext(int fd, drm_context_t *handle)
     drm_ctx_t ctx;
 
     ctx.flags = 0;     /* Modified with functions below */
-    if (ioctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
+       return -errno;
     *handle = ctx.handle;
     return 0;
 }
@@ -1321,7 +1355,8 @@ int drmSwitchToContext(int fd, drm_context_t context)
     drm_ctx_t ctx;
 
     ctx.handle = context;
-    if (ioctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
+       return -errno;
     return 0;
 }
 
@@ -1337,9 +1372,12 @@ int drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags)
      */
     ctx.handle = context;
     ctx.flags  = 0;
-    if (flags & DRM_CONTEXT_PRESERVED) ctx.flags |= _DRM_CONTEXT_PRESERVED;
-    if (flags & DRM_CONTEXT_2DONLY)    ctx.flags |= _DRM_CONTEXT_2DONLY;
-    if (ioctl(fd, DRM_IOCTL_MOD_CTX, &ctx)) return -errno;
+    if (flags & DRM_CONTEXT_PRESERVED)
+       ctx.flags |= _DRM_CONTEXT_PRESERVED;
+    if (flags & DRM_CONTEXT_2DONLY)
+       ctx.flags |= _DRM_CONTEXT_2DONLY;
+    if (ioctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
+       return -errno;
     return 0;
 }
 
@@ -1349,10 +1387,13 @@ int drmGetContextFlags(int fd, drm_context_t context,
     drm_ctx_t ctx;
 
     ctx.handle = context;
-    if (ioctl(fd, DRM_IOCTL_GET_CTX, &ctx)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_GET_CTX, &ctx))
+       return -errno;
     *flags = 0;
-    if (ctx.flags & _DRM_CONTEXT_PRESERVED) *flags |= DRM_CONTEXT_PRESERVED;
-    if (ctx.flags & _DRM_CONTEXT_2DONLY)    *flags |= DRM_CONTEXT_2DONLY;
+    if (ctx.flags & _DRM_CONTEXT_PRESERVED)
+       *flags |= DRM_CONTEXT_PRESERVED;
+    if (ctx.flags & _DRM_CONTEXT_2DONLY)
+       *flags |= DRM_CONTEXT_2DONLY;
     return 0;
 }
 
@@ -1377,14 +1418,16 @@ int drmDestroyContext(int fd, drm_context_t handle)
 {
     drm_ctx_t ctx;
     ctx.handle = handle;
-    if (ioctl(fd, DRM_IOCTL_RM_CTX, &ctx)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_RM_CTX, &ctx))
+       return -errno;
     return 0;
 }
 
 int drmCreateDrawable(int fd, drm_drawable_t *handle)
 {
     drm_draw_t draw;
-    if (ioctl(fd, DRM_IOCTL_ADD_DRAW, &draw)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
+       return -errno;
     *handle = draw.handle;
     return 0;
 }
@@ -1393,7 +1436,25 @@ int drmDestroyDrawable(int fd, drm_drawable_t handle)
 {
     drm_draw_t draw;
     draw.handle = handle;
-    if (ioctl(fd, DRM_IOCTL_RM_DRAW, &draw)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_RM_DRAW, &draw))
+       return -errno;
+    return 0;
+}
+
+int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
+                          drm_drawable_info_type_t type, unsigned int num,
+                          void *data)
+{
+    drm_update_draw_t update;
+
+    update.handle = handle;
+    update.type = type;
+    update.num = num;
+    update.data = (unsigned long long)(unsigned long)data;
+
+    if (ioctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
+       return -errno;
+
     return 0;
 }
 
@@ -1411,7 +1472,8 @@ int drmDestroyDrawable(int fd, drm_drawable_t handle)
  */
 int drmAgpAcquire(int fd)
 {
-    if (ioctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
+       return -errno;
     return 0;
 }
 
@@ -1428,7 +1490,8 @@ int drmAgpAcquire(int fd)
  */
 int drmAgpRelease(int fd)
 {
-    if (ioctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
+       return -errno;
     return 0;
 }
 
@@ -1450,7 +1513,8 @@ int drmAgpEnable(int fd, unsigned long mode)
     drm_agp_mode_t m;
 
     m.mode = mode;
-    if (ioctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
+       return -errno;
     return 0;
 }
 
@@ -1480,8 +1544,10 @@ int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
     b.size   = size;
     b.handle = 0;
     b.type   = type;
-    if (ioctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) return -errno;
-    if (address != 0UL) *address = b.physical;
+    if (ioctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
+       return -errno;
+    if (address != 0UL)
+       *address = b.physical;
     *handle = b.handle;
     return 0;
 }
@@ -1505,7 +1571,8 @@ int drmAgpFree(int fd, drm_handle_t handle)
 
     b.size   = 0;
     b.handle = handle;
-    if (ioctl(fd, DRM_IOCTL_AGP_FREE, &b)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_AGP_FREE, &b))
+       return -errno;
     return 0;
 }
 
@@ -1529,7 +1596,8 @@ int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
 
     b.handle = handle;
     b.offset = offset;
-    if (ioctl(fd, DRM_IOCTL_AGP_BIND, &b)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_AGP_BIND, &b))
+       return -errno;
     return 0;
 }
 
@@ -1552,7 +1620,8 @@ int drmAgpUnbind(int fd, drm_handle_t handle)
 
     b.handle = handle;
     b.offset = 0;
-    if (ioctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
+       return -errno;
     return 0;
 }
 
@@ -1572,7 +1641,8 @@ int drmAgpVersionMajor(int fd)
 {
     drm_agp_info_t i;
 
-    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i))
+       return -errno;
     return i.agp_version_major;
 }
 
@@ -1592,7 +1662,8 @@ int drmAgpVersionMinor(int fd)
 {
     drm_agp_info_t i;
 
-    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i))
+       return -errno;
     return i.agp_version_minor;
 }
 
@@ -1612,7 +1683,8 @@ unsigned long drmAgpGetMode(int fd)
 {
     drm_agp_info_t i;
 
-    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i))
+       return 0;
     return i.mode;
 }
 
@@ -1632,7 +1704,8 @@ unsigned long drmAgpBase(int fd)
 {
     drm_agp_info_t i;
 
-    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i))
+       return 0;
     return i.aperture_base;
 }
 
@@ -1652,7 +1725,8 @@ unsigned long drmAgpSize(int fd)
 {
     drm_agp_info_t i;
 
-    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i))
+       return 0;
     return i.aperture_size;
 }
 
@@ -1672,7 +1746,8 @@ unsigned long drmAgpMemoryUsed(int fd)
 {
     drm_agp_info_t i;
 
-    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i))
+       return 0;
     return i.memory_used;
 }
 
@@ -1692,7 +1767,8 @@ unsigned long drmAgpMemoryAvail(int fd)
 {
     drm_agp_info_t i;
 
-    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i))
+       return 0;
     return i.memory_allowed;
 }
 
@@ -1712,7 +1788,8 @@ unsigned int drmAgpVendorId(int fd)
 {
     drm_agp_info_t i;
 
-    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i))
+       return 0;
     return i.id_vendor;
 }
 
@@ -1732,7 +1809,8 @@ unsigned int drmAgpDeviceId(int fd)
 {
     drm_agp_info_t i;
 
-    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+    if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i))
+       return 0;
     return i.id_device;
 }
 
@@ -1743,7 +1821,8 @@ int drmScatterGatherAlloc(int fd, unsigned long size, drm_handle_t *handle)
     *handle = 0;
     sg.size   = size;
     sg.handle = 0;
-    if (ioctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
+       return -errno;
     *handle = sg.handle;
     return 0;
 }
@@ -1754,7 +1833,8 @@ int drmScatterGatherFree(int fd, drm_handle_t handle)
 
     sg.size   = 0;
     sg.handle = handle;
-    if (ioctl(fd, DRM_IOCTL_SG_FREE, &sg)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_SG_FREE, &sg))
+       return -errno;
     return 0;
 }
 
@@ -1784,12 +1864,21 @@ int drmWaitVBlank(int fd, drmVBlankPtr vbl)
 int drmError(int err, const char *label)
 {
     switch (err) {
-    case DRM_ERR_NO_DEVICE: fprintf(stderr, "%s: no device\n", label);   break;
-    case DRM_ERR_NO_ACCESS: fprintf(stderr, "%s: no access\n", label);   break;
-    case DRM_ERR_NOT_ROOT:  fprintf(stderr, "%s: not root\n", label);    break;
-    case DRM_ERR_INVALID:   fprintf(stderr, "%s: invalid args\n", label);break;
+    case DRM_ERR_NO_DEVICE:
+       fprintf(stderr, "%s: no device\n", label);
+       break;
+    case DRM_ERR_NO_ACCESS:
+       fprintf(stderr, "%s: no access\n", label);
+       break;
+    case DRM_ERR_NOT_ROOT:
+       fprintf(stderr, "%s: not root\n", label);
+       break;
+    case DRM_ERR_INVALID:
+       fprintf(stderr, "%s: invalid args\n", label);
+       break;
     default:
-       if (err < 0) err = -err;
+       if (err < 0)
+           err = -err;
        fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
        break;
     }
@@ -1815,7 +1904,8 @@ int drmCtlInstHandler(int fd, int irq)
 
     ctl.func  = DRM_INST_HANDLER;
     ctl.irq   = irq;
-    if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl))
+       return -errno;
     return 0;
 }
 
@@ -1837,7 +1927,8 @@ int drmCtlUninstHandler(int fd)
 
     ctl.func  = DRM_UNINST_HANDLER;
     ctl.irq   = 0;
-    if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl))
+       return -errno;
     return 0;
 }
 
@@ -1853,7 +1944,8 @@ int drmFinish(int fd, int context, drmLockFlags flags)
     if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
     if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
     if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
-    if (ioctl(fd, DRM_IOCTL_FINISH, &lock)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_FINISH, &lock))
+       return -errno;
     return 0;
 }
 
@@ -1878,7 +1970,8 @@ int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
     p.busnum  = busnum;
     p.devnum  = devnum;
     p.funcnum = funcnum;
-    if (ioctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
+       return -errno;
     return p.irq;
 }
 
@@ -1905,7 +1998,8 @@ void *drmGetContextTag(int fd, drm_context_t context)
     drmHashEntry  *entry = drmGetEntry(fd);
     void          *value;
 
-    if (drmHashLookup(entry->tagTable, context, &value)) return NULL;
+    if (drmHashLookup(entry->tagTable, context, &value))
+       return NULL;
 
     return value;
 }
@@ -1918,7 +2012,8 @@ int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
     map.ctx_id = ctx_id;
     map.handle = (void *)handle;
 
-    if (ioctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
+       return -errno;
     return 0;
 }
 
@@ -1929,8 +2024,10 @@ int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
 
     map.ctx_id = ctx_id;
 
-    if (ioctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map)) return -errno;
-    if (handle) *handle = (drm_handle_t)map.handle;
+    if (ioctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
+       return -errno;
+    if (handle)
+       *handle = (drm_handle_t)map.handle;
 
     return 0;
 }
@@ -1942,7 +2039,8 @@ int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
     drm_map_t map;
 
     map.offset = idx;
-    if (ioctl(fd, DRM_IOCTL_GET_MAP, &map)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_GET_MAP, &map))
+       return -errno;
     *offset = map.offset;
     *size   = map.size;
     *type   = map.type;
@@ -1958,7 +2056,8 @@ int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
     drm_client_t client;
 
     client.idx = idx;
-    if (ioctl(fd, DRM_IOCTL_GET_CLIENT, &client)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_GET_CLIENT, &client))
+       return -errno;
     *auth      = client.auth;
     *pid       = client.pid;
     *uid       = client.uid;
@@ -1972,7 +2071,8 @@ int drmGetStats(int fd, drmStatsT *stats)
     drm_stats_t s;
     int         i;
 
-    if (ioctl(fd, DRM_IOCTL_GET_STATS, &s)) return -errno;
+    if (ioctl(fd, DRM_IOCTL_GET_STATS, &s))
+       return -errno;
 
     stats->count = 0;
     memset(stats, 0, sizeof(*stats));
@@ -2237,48 +2337,72 @@ int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data,
     return 0;
 }
 
-int drmFenceCreate(int fd, int shareable, int class,unsigned type, 
-                  int emit, 
+
+/*
+ * Valid flags are 
+ * DRM_FENCE_FLAG_EMIT
+ * DRM_FENCE_FLAG_SHAREABLE
+ * DRM_FENCE_MASK_DRIVER
+ */
+
+int drmFenceCreate(int fd, unsigned flags, int fence_class, unsigned type,
                   drmFence *fence)
 {
     drm_fence_arg_t arg;
-    
+
+    memset(&arg, 0, sizeof(arg));
+    arg.flags = flags;
     arg.type = type;
-    arg.class = class;
-    arg.flags = (shareable) ? DRM_FENCE_FLAG_SHAREABLE : 0;
-    arg.flags |= (emit) ? DRM_FENCE_FLAG_EMIT : 0;
-    arg.op = drm_fence_create;
-    if (ioctl(fd, DRM_IOCTL_FENCE, &arg))
+    arg.fence_class = fence_class;
+
+    if (ioctl(fd, DRM_IOCTL_FENCE_CREATE, &arg))
        return -errno;
     fence->handle = arg.handle;
-    fence->class = arg.class;
+    fence->fence_class = arg.fence_class;
     fence->type = arg.type;
+    fence->flags = arg.flags;
     fence->signaled = 0;
     return 0;
 }
-    
-int drmFenceDestroy(int fd, const drmFence *fence)
+
+/*
+ * Valid flags are 
+ * DRM_FENCE_FLAG_SHAREABLE
+ * DRM_FENCE_MASK_DRIVER
+ */
+
+int drmFenceBuffers(int fd, unsigned flags, uint32_t fence_class, drmFence *fence)
 {
     drm_fence_arg_t arg;
-   
-    arg.handle = fence->handle;
-    arg.op = drm_fence_destroy;
-    if (ioctl(fd, DRM_IOCTL_FENCE, &arg))
+
+    memset(&arg, 0, sizeof(arg));
+    arg.flags = flags;
+    arg.fence_class = fence_class;
+
+    if (ioctl(fd, DRM_IOCTL_FENCE_BUFFERS, &arg))
        return -errno;
+    fence->handle = arg.handle;
+    fence->fence_class = arg.fence_class;
+    fence->type = arg.type;
+    fence->flags = arg.flags;
+    fence->sequence = arg.sequence;
+    fence->signaled = 0;
     return 0;
 }
 
 int drmFenceReference(int fd, unsigned handle, drmFence *fence)
 {
     drm_fence_arg_t arg;
-   
+
+    memset(&arg, 0, sizeof(arg));
     arg.handle = handle;
-    arg.op = drm_fence_reference;
-    if (ioctl(fd, DRM_IOCTL_FENCE, &arg))
+
+    if (ioctl(fd, DRM_IOCTL_FENCE_REFERENCE, &arg))
        return -errno;
     fence->handle = arg.handle;
-    fence->class = arg.class;
+    fence->fence_class = arg.fence_class;
     fence->type = arg.type;
+    fence->flags = arg.flags;
     fence->signaled = arg.signaled;
     return 0;
 }
@@ -2286,10 +2410,11 @@ int drmFenceReference(int fd, unsigned handle, drmFence *fence)
 int drmFenceUnreference(int fd, const drmFence *fence)
 {
     drm_fence_arg_t arg;
-   
+
+    memset(&arg, 0, sizeof(arg));
     arg.handle = fence->handle;
-    arg.op = drm_fence_unreference;
-    if (ioctl(fd, DRM_IOCTL_FENCE, &arg))
+
+    if (ioctl(fd, DRM_IOCTL_FENCE_UNREFERENCE, &arg))
        return -errno;
     return 0;
 }
@@ -2297,69 +2422,541 @@ int drmFenceUnreference(int fd, const drmFence *fence)
 int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type)
 {
     drm_fence_arg_t arg;
-   
+
+    memset(&arg, 0, sizeof(arg));
     arg.handle = fence->handle;
     arg.type = flush_type;
-    arg.op = drm_fence_flush;
-    if (ioctl(fd, DRM_IOCTL_FENCE, &arg))
+
+    if (ioctl(fd, DRM_IOCTL_FENCE_FLUSH, &arg))
        return -errno;
-    fence->class = arg.class;
+    fence->fence_class = arg.fence_class;
     fence->type = arg.type;
     fence->signaled = arg.signaled;
-    return 0;
+    return arg.error;
 }
 
-int drmFenceSignaled(int fd, drmFence *fence)
+int drmFenceUpdate(int fd, drmFence *fence)
 {
     drm_fence_arg_t arg;
-   
+
+    memset(&arg, 0, sizeof(arg));
     arg.handle = fence->handle;
-    arg.op = drm_fence_signaled;
-    if (ioctl(fd, DRM_IOCTL_FENCE, &arg))
+
+    if (ioctl(fd, DRM_IOCTL_FENCE_SIGNALED, &arg))
        return -errno;
-    fence->class = arg.class;
+    fence->fence_class = arg.fence_class;
     fence->type = arg.type;
     fence->signaled = arg.signaled;
     return 0;
 }
 
-int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type)
+int drmFenceSignaled(int fd, drmFence *fence, unsigned fenceType, 
+                    int *signaled)
+{
+    if ((fence->flags & DRM_FENCE_FLAG_SHAREABLE) ||
+       ((fenceType & fence->signaled) != fenceType)) {
+       int ret = drmFenceFlush(fd, fence, fenceType);
+       if (ret)
+           return ret;
+    }
+
+    *signaled = ((fenceType & fence->signaled) == fenceType);
+
+    return 0;
+}
+
+/*
+ * Valid flags are 
+ * DRM_FENCE_FLAG_SHAREABLE
+ * DRM_FENCE_MASK_DRIVER
+ */
+
+
+int drmFenceEmit(int fd, unsigned flags, drmFence *fence, unsigned emit_type)
 {
     drm_fence_arg_t arg;
-   
+
+    memset(&arg, 0, sizeof(arg));
+    arg.fence_class = fence->fence_class;
+    arg.flags = flags;
     arg.handle = fence->handle;
     arg.type = emit_type;
-    arg.op = drm_fence_emit;
-    if (ioctl(fd, DRM_IOCTL_FENCE, &arg))
+
+    if (ioctl(fd, DRM_IOCTL_FENCE_EMIT, &arg))
        return -errno;
-    fence->class = arg.class;
+    fence->fence_class = arg.fence_class;
     fence->type = arg.type;
     fence->signaled = arg.signaled;
+    fence->sequence = arg.sequence;
+    return 0;
+}
+
+/*
+ * Valid flags are 
+ * DRM_FENCE_FLAG_WAIT_LAZY
+ * DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS
+ */
+
+#define DRM_IOCTL_TIMEOUT_USEC 3000000UL
+
+static unsigned long
+drmTimeDiff(struct timeval *now, struct timeval *then)
+{
+    uint64_t val;
+
+    val = now->tv_sec - then->tv_sec;
+    val *= 1000000LL;
+    val += now->tv_usec;
+    val -= then->tv_usec;
+
+    return (unsigned long) val;
+}
+
+static int
+drmIoctlTimeout(int fd, unsigned long request, void *argp)
+{
+    int haveThen = 0;
+    struct timeval then, now;
+    int ret;
+
+    do {
+       ret = ioctl(fd, request, argp);
+       if (ret != 0 && errno == EAGAIN) {
+           if (!haveThen) {
+               gettimeofday(&then, NULL);
+               haveThen = 1;
+           }
+           gettimeofday(&now, NULL);
+       }
+    } while (ret != 0 && errno == EAGAIN && 
+            drmTimeDiff(&now, &then) < DRM_IOCTL_TIMEOUT_USEC);
+    
+    if (ret != 0)
+       return ((errno == EAGAIN) ? -EBUSY : -errno);
+
     return 0;
 }
     
-int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, 
-                int lazy, int ignore_signals)
+       
+
+
+int drmFenceWait(int fd, unsigned flags, drmFence *fence, unsigned flush_type)
 {
     drm_fence_arg_t arg;
     int ret;
 
+    if (flush_type == 0) {
+       flush_type = fence->type;
+    }
+
+    if (!(fence->flags & DRM_FENCE_FLAG_SHAREABLE)) {
+       if ((flush_type & fence->signaled) == flush_type) {
+           return 0;
+       }
+    }
+
+    memset(&arg, 0, sizeof(arg));
     arg.handle = fence->handle;
     arg.type = flush_type;
-    arg.flags = (lazy) ? DRM_FENCE_FLAG_WAIT_LAZY : 0;
-    arg.flags |= (ignore_signals) ? DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS : 0;
-    arg.op = drm_fence_wait;
-    do {
-       ret = ioctl(fd, DRM_IOCTL_FENCE, &arg);
-    } while (ret != 0 && errno == EAGAIN);
+    arg.flags = flags;
+
 
+    ret = drmIoctlTimeout(fd, DRM_IOCTL_FENCE_WAIT, &arg);
     if (ret)
-       return -errno;
+       return ret;
 
-    fence->class = arg.class;
+    fence->fence_class = arg.fence_class;
     fence->type = arg.type;
     fence->signaled = arg.signaled;
-    return 0;
+    return arg.error;
 }    
 
+static void drmBOCopyReply(const struct drm_bo_info_rep *rep, drmBO *buf)
+{
+    buf->handle = rep->handle;
+    buf->flags = rep->flags;
+    buf->size = rep->size;
+    buf->offset = rep->offset;
+    buf->mapHandle = rep->arg_handle;
+    buf->mask = rep->mask;
+    buf->start = rep->buffer_start;
+    buf->fenceFlags = rep->fence_flags;
+    buf->replyFlags = rep->rep_flags;
+    buf->pageAlignment = rep->page_alignment;
+    buf->tileInfo = rep->tile_info;
+    buf->hwTileStride = rep->hw_tile_stride;
+    buf->desiredTileStride = rep->desired_tile_stride;
+}
+
+
+
+int drmBOCreate(int fd, unsigned long size,
+               unsigned pageAlignment, void *user_buffer,
+               uint64_t mask,
+               unsigned hint, drmBO *buf)
+{
+    struct drm_bo_create_arg arg;
+    struct drm_bo_create_req *req = &arg.d.req;
+    struct drm_bo_info_rep *rep = &arg.d.rep;
+    int ret;
+
+    memset(buf, 0, sizeof(*buf));
+    memset(&arg, 0, sizeof(arg));
+    req->mask = mask;
+    req->hint = hint;
+    req->size = size;
+    req->page_alignment = pageAlignment;
+    req->buffer_start = (unsigned long) user_buffer;
+
+    buf->virtual = NULL;
+
+    ret = drmIoctlTimeout(fd, DRM_IOCTL_BO_CREATE, &arg);
+    if (ret)
+       return ret;
+
+    drmBOCopyReply(rep, buf);
+    buf->virtual = user_buffer;
+    buf->mapCount = 0;
+
+    return 0;
+}
+
+int drmBOReference(int fd, unsigned handle, drmBO *buf)
+{
+    struct drm_bo_reference_info_arg arg;
+    struct drm_bo_handle_arg *req = &arg.d.req;
+    struct drm_bo_info_rep *rep = &arg.d.rep;
+    
+    memset(&arg, 0, sizeof(arg));
+    req->handle = handle;
+    
+    if (ioctl(fd, DRM_IOCTL_BO_REFERENCE, &arg))
+       return -errno;
+
+    drmBOCopyReply(rep, buf);
+    buf->mapVirtual = NULL;
+    buf->mapCount = 0;
+    buf->virtual = NULL;
+
+    return 0;
+}
+
+int drmBOUnreference(int fd, drmBO *buf)
+{
+    struct drm_bo_handle_arg arg;
+
+    if (buf->mapVirtual && buf->mapHandle) {
+       (void) munmap(buf->mapVirtual, buf->start + buf->size);
+       buf->mapVirtual = NULL;
+       buf->virtual = NULL;
+    }
+
+    memset(&arg, 0, sizeof(arg));
+    arg.handle = buf->handle;
+
+    if (ioctl(fd, DRM_IOCTL_BO_UNREFERENCE, &arg))
+       return -errno;
+
+    buf->handle = 0;
+    return 0;
+}   
+
+
+/*
+ * Flags can be  DRM_BO_FLAG_READ, DRM_BO_FLAG_WRITE or'ed together
+ * Hint currently be DRM_BO_HINT_DONT_BLOCK, which makes the
+ * call return an -EBUSY if it can' immediately honor the mapping request.
+ */
+
+int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint,
+            void **address)
+{
+    struct drm_bo_map_wait_idle_arg arg;
+    struct drm_bo_info_req *req = &arg.d.req;
+    struct drm_bo_info_rep *rep = &arg.d.rep;
+    int ret = 0;
+
+    /*
+     * Make sure we have a virtual address of the buffer.
+     */
 
+    if (!buf->virtual) {
+       drmAddress virtual;
+       virtual = mmap(0, buf->size + buf->start, 
+                      PROT_READ | PROT_WRITE, MAP_SHARED,
+                      fd, buf->mapHandle);
+       if (virtual == MAP_FAILED) {
+           ret = -errno;
+       }
+       if (ret) 
+           return ret;
+       buf->mapVirtual = virtual;
+       buf->virtual = ((char *) virtual) + buf->start;
+    }
+
+    memset(&arg, 0, sizeof(arg));
+    req->handle = buf->handle;
+    req->mask = mapFlags;
+    req->hint = mapHint;
+
+    /*
+     * May hang if the buffer object is busy.
+     * This IOCTL synchronizes the buffer.
+     */
+    
+    ret = drmIoctlTimeout(fd, DRM_IOCTL_BO_MAP, &arg);
+    if (ret)
+       return ret;
+
+    drmBOCopyReply(rep, buf);  
+    buf->mapFlags = mapFlags;
+    ++buf->mapCount;
+    *address = buf->virtual;
+
+    return 0;
+}
+
+
+int drmBOUnmap(int fd, drmBO *buf)
+{
+    struct drm_bo_handle_arg arg;
+
+    memset(&arg, 0, sizeof(arg));
+    arg.handle = buf->handle;
+
+    if (ioctl(fd, DRM_IOCTL_BO_UNMAP, &arg)) {
+       return -errno;
+    }
+    buf->mapCount--;
+    return 0;
+}
+
+int drmBOSetStatus(int fd, drmBO *buf, 
+                  uint64_t flags, uint64_t mask,
+                  unsigned int hint, 
+                  unsigned int desired_tile_stride,
+                  unsigned int tile_info)
+{
+
+    struct drm_bo_map_wait_idle_arg arg;
+    struct drm_bo_info_req *req = &arg.d.req;
+    struct drm_bo_info_rep *rep = &arg.d.rep;
+    int ret = 0;
+
+    memset(&arg, 0, sizeof(arg));
+    req->mask = mask;
+    req->flags = flags;
+    req->handle = buf->handle;
+    req->hint = hint;
+    req->desired_tile_stride = desired_tile_stride;
+    req->tile_info = tile_info;
+    
+    ret = drmIoctlTimeout(fd, DRM_IOCTL_BO_SETSTATUS, &arg);
+    if (ret) 
+           return ret;
+
+    drmBOCopyReply(rep, buf);
+    return 0;
+}
+           
+
+int drmBOInfo(int fd, drmBO *buf)
+{
+    struct drm_bo_reference_info_arg arg;
+    struct drm_bo_handle_arg *req = &arg.d.req;
+    struct drm_bo_info_rep *rep = &arg.d.rep;
+    int ret = 0;
+
+    memset(&arg, 0, sizeof(arg));
+    req->handle = buf->handle;
+
+    ret = ioctl(fd, DRM_IOCTL_BO_INFO, &arg);
+    if (ret) 
+       return -errno;
+
+    drmBOCopyReply(rep, buf);
+    return 0;
+}
+
+int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint)
+{
+    struct drm_bo_map_wait_idle_arg arg;
+    struct drm_bo_info_req *req = &arg.d.req;
+    struct drm_bo_info_rep *rep = &arg.d.rep;
+    int ret = 0;
+
+    if ((buf->flags & DRM_BO_FLAG_SHAREABLE) ||
+       (buf->replyFlags & DRM_BO_REP_BUSY)) {
+        memset(&arg, 0, sizeof(arg));
+       req->handle = buf->handle;
+       req->hint = hint;
+
+       ret = drmIoctlTimeout(fd, DRM_IOCTL_BO_WAIT_IDLE, &arg);
+       if (ret) 
+           return ret;
+
+       drmBOCopyReply(rep, buf);
+    }
+    return 0;
+}
+       
+int drmBOBusy(int fd, drmBO *buf, int *busy)
+{
+    if (!(buf->flags & DRM_BO_FLAG_SHAREABLE) &&
+       !(buf->replyFlags & DRM_BO_REP_BUSY)) {
+       *busy = 0;
+       return 0;
+    }
+    else {
+       int ret = drmBOInfo(fd, buf);
+       if (ret)
+           return ret;
+       *busy = (buf->replyFlags & DRM_BO_REP_BUSY);
+       return 0;
+    }
+}
+    
+int drmMMInit(int fd, unsigned long pOffset, unsigned long pSize,
+             unsigned memType)
+{
+    struct drm_mm_init_arg arg;
+
+    memset(&arg, 0, sizeof(arg));
+
+    arg.magic = DRM_BO_INIT_MAGIC;
+    arg.major = DRM_BO_INIT_MAJOR;
+    arg.minor = DRM_BO_INIT_MINOR;
+    arg.p_offset = pOffset;
+    arg.p_size = pSize;
+    arg.mem_type = memType;
+
+    if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg))
+       return -errno;
+    return 0;  
+}
+
+int drmMMTakedown(int fd, unsigned memType)
+{
+    struct drm_mm_type_arg arg;
+
+    memset(&arg, 0, sizeof(arg));
+    arg.mem_type = memType;
+
+    if (ioctl(fd, DRM_IOCTL_MM_TAKEDOWN, &arg))
+       return -errno;
+    return 0;  
+}
+
+/*
+ * If this function returns an error, and lockBM was set to 1,
+ * the buffer manager is NOT locked.
+ */
+
+int drmMMLock(int fd, unsigned memType, int lockBM, int ignoreNoEvict)
+{
+    struct drm_mm_type_arg arg;
+
+    memset(&arg, 0, sizeof(arg));
+    arg.mem_type = memType;
+    arg.lock_flags |= (lockBM) ? DRM_BO_LOCK_UNLOCK_BM : 0;
+    arg.lock_flags |= (ignoreNoEvict) ? DRM_BO_LOCK_IGNORE_NO_EVICT : 0;
+
+    return drmIoctlTimeout(fd, DRM_IOCTL_MM_LOCK, &arg);
+}
+
+int drmMMUnlock(int fd, unsigned memType, int unlockBM)
+{
+    struct drm_mm_type_arg arg;
+
+    memset(&arg, 0, sizeof(arg));
+    
+    arg.mem_type = memType;
+    arg.lock_flags |= (unlockBM) ? DRM_BO_LOCK_UNLOCK_BM : 0;
+
+    return drmIoctlTimeout(fd, DRM_IOCTL_MM_UNLOCK, &arg);
+}
+
+int drmBOVersion(int fd, unsigned int *major,
+                unsigned int *minor,
+                unsigned int *patchlevel)
+{
+    struct drm_bo_version_arg arg;
+    int ret;
+
+    memset(&arg, 0, sizeof(arg));
+    ret = ioctl(fd, DRM_IOCTL_BO_VERSION, &arg);
+    if (ret)
+       return -errno;
+
+    if (major)
+       *major = arg.major;
+    if (minor)
+       *minor = arg.minor;
+    if (patchlevel)
+       *patchlevel = arg.patchlevel;
+
+    return 0;
+}
+
+
+
+#define DRM_MAX_FDS 16
+static struct {
+    char *BusID;
+    int fd;
+    int refcount;
+} connection[DRM_MAX_FDS];
+
+static int nr_fds = 0;
+
+int drmOpenOnce(void *unused, 
+               const char *BusID,
+               int *newlyopened)
+{
+    int i;
+    int fd;
+   
+    for (i = 0; i < nr_fds; i++)
+       if (strcmp(BusID, connection[i].BusID) == 0) {
+           connection[i].refcount++;
+           *newlyopened = 0;
+           return connection[i].fd;
+       }
+
+    fd = drmOpen(unused, BusID);
+    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;
+    *newlyopened = 1;
+
+    if (0)
+       fprintf(stderr, "saved connection %d for %s %d\n", 
+               nr_fds, connection[nr_fds].BusID, 
+               strcmp(BusID, connection[nr_fds].BusID));
+
+    nr_fds++;
+
+    return fd;
+}
+
+void drmCloseOnce(int fd)
+{
+    int i;
+
+    for (i = 0; i < nr_fds; i++) {
+       if (fd == connection[i].fd) {
+           if (--connection[i].refcount == 0) {
+               drmClose(connection[i].fd);
+               free(connection[i].BusID);
+           
+               if (i < --nr_fds) 
+                   connection[i] = connection[nr_fds];
+
+               return;
+           }
+       }
+    }
+}