Back to index

libdrm  2.4.37
xf86drm.c
Go to the documentation of this file.
00001 
00009 /*
00010  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
00011  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
00012  * All Rights Reserved.
00013  *
00014  * Permission is hereby granted, free of charge, to any person obtaining a
00015  * copy of this software and associated documentation files (the "Software"),
00016  * to deal in the Software without restriction, including without limitation
00017  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00018  * and/or sell copies of the Software, and to permit persons to whom the
00019  * Software is furnished to do so, subject to the following conditions:
00020  *
00021  * The above copyright notice and this permission notice (including the next
00022  * paragraph) shall be included in all copies or substantial portions of the
00023  * Software.
00024  *
00025  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00026  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00027  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00028  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
00029  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00030  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00031  * DEALINGS IN THE SOFTWARE.
00032  */
00033 
00034 #ifdef HAVE_CONFIG_H
00035 # include <config.h>
00036 #endif
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include <unistd.h>
00040 #include <string.h>
00041 #include <strings.h>
00042 #include <ctype.h>
00043 #include <fcntl.h>
00044 #include <errno.h>
00045 #include <signal.h>
00046 #include <time.h>
00047 #include <sys/types.h>
00048 #include <sys/stat.h>
00049 #define stat_t struct stat
00050 #include <sys/ioctl.h>
00051 #include <sys/mman.h>
00052 #include <sys/time.h>
00053 #include <stdarg.h>
00054 
00055 /* Not all systems have MAP_FAILED defined */
00056 #ifndef MAP_FAILED
00057 #define MAP_FAILED ((void *)-1)
00058 #endif
00059 
00060 #include "xf86drm.h"
00061 
00062 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
00063 #define DRM_MAJOR 145
00064 #endif
00065 
00066 #ifdef __NetBSD__
00067 #define DRM_MAJOR 34
00068 #endif
00069 
00070 # ifdef __OpenBSD__
00071 #  define DRM_MAJOR 81
00072 # endif
00073 
00074 #ifndef DRM_MAJOR
00075 #define DRM_MAJOR 226              /* Linux */
00076 #endif
00077 
00078 /*
00079  * This definition needs to be changed on some systems if dev_t is a structure.
00080  * If there is a header file we can get it from, there would be best.
00081  */
00082 #ifndef makedev
00083 #define makedev(x,y)    ((dev_t)(((x) << 8) | (y)))
00084 #endif
00085 
00086 #define DRM_MSG_VERBOSITY 3
00087 
00088 #define DRM_NODE_CONTROL 0
00089 #define DRM_NODE_RENDER 1
00090 
00091 static drmServerInfoPtr drm_server_info;
00092 
00093 void drmSetServerInfo(drmServerInfoPtr info)
00094 {
00095     drm_server_info = info;
00096 }
00097 
00107 static int drmDebugPrint(const char *format, va_list ap)
00108 {
00109     return vfprintf(stderr, format, ap);
00110 }
00111 
00112 static int (*drm_debug_print)(const char *format, va_list ap) = drmDebugPrint;
00113 
00114 void
00115 drmMsg(const char *format, ...)
00116 {
00117     va_list   ap;
00118     const char *env;
00119     if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) || drm_server_info)
00120     {
00121        va_start(ap, format);
00122        if (drm_server_info) {
00123          drm_server_info->debug_print(format,ap);
00124        } else {
00125          drm_debug_print(format, ap);
00126        }
00127        va_end(ap);
00128     }
00129 }
00130 
00131 void
00132 drmSetDebugMsgFunction(int (*debug_msg_ptr)(const char *format, va_list ap))
00133 {
00134     drm_debug_print = debug_msg_ptr;
00135 }
00136 
00137 static void *drmHashTable = NULL; /* Context switch callbacks */
00138 
00139 void *drmGetHashTable(void)
00140 {
00141     return drmHashTable;
00142 }
00143 
00144 void *drmMalloc(int size)
00145 {
00146     void *pt;
00147     if ((pt = malloc(size)))
00148        memset(pt, 0, size);
00149     return pt;
00150 }
00151 
00152 void drmFree(void *pt)
00153 {
00154     if (pt)
00155        free(pt);
00156 }
00157 
00161 int
00162 drmIoctl(int fd, unsigned long request, void *arg)
00163 {
00164     int       ret;
00165 
00166     do {
00167        ret = ioctl(fd, request, arg);
00168     } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
00169     return ret;
00170 }
00171 
00172 static unsigned long drmGetKeyFromFd(int fd)
00173 {
00174     stat_t     st;
00175 
00176     st.st_rdev = 0;
00177     fstat(fd, &st);
00178     return st.st_rdev;
00179 }
00180 
00181 drmHashEntry *drmGetEntry(int fd)
00182 {
00183     unsigned long key = drmGetKeyFromFd(fd);
00184     void          *value;
00185     drmHashEntry  *entry;
00186 
00187     if (!drmHashTable)
00188        drmHashTable = drmHashCreate();
00189 
00190     if (drmHashLookup(drmHashTable, key, &value)) {
00191        entry           = drmMalloc(sizeof(*entry));
00192        entry->fd       = fd;
00193        entry->f        = NULL;
00194        entry->tagTable = drmHashCreate();
00195        drmHashInsert(drmHashTable, key, entry);
00196     } else {
00197        entry = value;
00198     }
00199     return entry;
00200 }
00201 
00215 static int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
00216 {
00217     /* First, check if the IDs are exactly the same */
00218     if (strcasecmp(id1, id2) == 0)
00219        return 1;
00220 
00221     /* Try to match old/new-style PCI bus IDs. */
00222     if (strncasecmp(id1, "pci", 3) == 0) {
00223        unsigned int o1, b1, d1, f1;
00224        unsigned int o2, b2, d2, f2;
00225        int ret;
00226 
00227        ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
00228        if (ret != 4) {
00229            o1 = 0;
00230            ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
00231            if (ret != 3)
00232               return 0;
00233        }
00234 
00235        ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
00236        if (ret != 4) {
00237            o2 = 0;
00238            ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
00239            if (ret != 3)
00240               return 0;
00241        }
00242 
00243        /* If domains aren't properly supported by the kernel interface,
00244         * just ignore them, which sucks less than picking a totally random
00245         * card with "open by name"
00246         */
00247        if (!pci_domain_ok)
00248               o1 = o2 = 0;
00249 
00250        if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
00251            return 0;
00252        else
00253            return 1;
00254     }
00255     return 0;
00256 }
00257 
00272 static int chown_check_return(const char *path, uid_t owner, gid_t group)
00273 {
00274        int rv;
00275 
00276        do {
00277               rv = chown(path, owner, group);
00278        } while (rv != 0 && errno == EINTR);
00279 
00280        if (rv == 0)
00281               return 0;
00282 
00283        drmMsg("Failed to change owner or group for file %s! %d: %s\n",
00284                      path, errno, strerror(errno));
00285        return -1;
00286 }
00287 
00301 static int drmOpenDevice(long dev, int minor, int type)
00302 {
00303     stat_t          st;
00304     char            buf[64];
00305     int             fd;
00306     mode_t          devmode = DRM_DEV_MODE, serv_mode;
00307     int             isroot  = !geteuid();
00308     uid_t           user    = DRM_DEV_UID;
00309     gid_t           group   = DRM_DEV_GID, serv_group;
00310     
00311     sprintf(buf, type ? DRM_DEV_NAME : DRM_CONTROL_DEV_NAME, DRM_DIR_NAME, minor);
00312     drmMsg("drmOpenDevice: node name is %s\n", buf);
00313 
00314     if (drm_server_info) {
00315        drm_server_info->get_perms(&serv_group, &serv_mode);
00316        devmode  = serv_mode ? serv_mode : DRM_DEV_MODE;
00317        devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
00318        group = (serv_group >= 0) ? serv_group : DRM_DEV_GID;
00319     }
00320 
00321 #if !defined(UDEV)
00322     if (stat(DRM_DIR_NAME, &st)) {
00323        if (!isroot)
00324            return DRM_ERR_NOT_ROOT;
00325        mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
00326        chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
00327        chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
00328     }
00329 
00330     /* Check if the device node exists and create it if necessary. */
00331     if (stat(buf, &st)) {
00332        if (!isroot)
00333            return DRM_ERR_NOT_ROOT;
00334        remove(buf);
00335        mknod(buf, S_IFCHR | devmode, dev);
00336     }
00337 
00338     if (drm_server_info) {
00339        chown_check_return(buf, user, group);
00340        chmod(buf, devmode);
00341     }
00342 #else
00343     /* if we modprobed then wait for udev */
00344     {
00345        int udev_count = 0;
00346 wait_for_udev:
00347         if (stat(DRM_DIR_NAME, &st)) {
00348               usleep(20);
00349               udev_count++;
00350 
00351               if (udev_count == 50)
00352                      return -1;
00353               goto wait_for_udev;
00354        }
00355 
00356        if (stat(buf, &st)) {
00357               usleep(20);
00358               udev_count++;
00359 
00360               if (udev_count == 50)
00361                      return -1;
00362               goto wait_for_udev;
00363        }
00364     }
00365 #endif
00366 
00367     fd = open(buf, O_RDWR, 0);
00368     drmMsg("drmOpenDevice: open result is %d, (%s)\n",
00369               fd, fd < 0 ? strerror(errno) : "OK");
00370     if (fd >= 0)
00371        return fd;
00372 
00373 #if !defined(UDEV)
00374     /* Check if the device node is not what we expect it to be, and recreate it
00375      * and try again if so.
00376      */
00377     if (st.st_rdev != dev) {
00378        if (!isroot)
00379            return DRM_ERR_NOT_ROOT;
00380        remove(buf);
00381        mknod(buf, S_IFCHR | devmode, dev);
00382        if (drm_server_info) {
00383            chown_check_return(buf, user, group);
00384            chmod(buf, devmode);
00385        }
00386     }
00387     fd = open(buf, O_RDWR, 0);
00388     drmMsg("drmOpenDevice: open result is %d, (%s)\n",
00389               fd, fd < 0 ? strerror(errno) : "OK");
00390     if (fd >= 0)
00391        return fd;
00392 
00393     drmMsg("drmOpenDevice: Open failed\n");
00394     remove(buf);
00395 #endif
00396     return -errno;
00397 }
00398 
00399 
00412 static int drmOpenMinor(int minor, int create, int type)
00413 {
00414     int  fd;
00415     char buf[64];
00416     
00417     if (create)
00418        return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
00419     
00420     sprintf(buf, type ? DRM_DEV_NAME : DRM_CONTROL_DEV_NAME, DRM_DIR_NAME, minor);
00421     if ((fd = open(buf, O_RDWR, 0)) >= 0)
00422        return fd;
00423     return -errno;
00424 }
00425 
00426 
00437 int drmAvailable(void)
00438 {
00439     drmVersionPtr version;
00440     int           retval = 0;
00441     int           fd;
00442 
00443     if ((fd = drmOpenMinor(0, 1, DRM_NODE_RENDER)) < 0) {
00444 #ifdef __linux__
00445        /* Try proc for backward Linux compatibility */
00446        if (!access("/proc/dri/0", R_OK))
00447            return 1;
00448 #endif
00449        return 0;
00450     }
00451     
00452     if ((version = drmGetVersion(fd))) {
00453        retval = 1;
00454        drmFreeVersion(version);
00455     }
00456     close(fd);
00457 
00458     return retval;
00459 }
00460 
00461 
00475 static int drmOpenByBusid(const char *busid)
00476 {
00477     int        i, pci_domain_ok = 1;
00478     int        fd;
00479     const char *buf;
00480     drmSetVersion sv;
00481 
00482     drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
00483     for (i = 0; i < DRM_MAX_MINOR; i++) {
00484        fd = drmOpenMinor(i, 1, DRM_NODE_RENDER);
00485        drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
00486        if (fd >= 0) {
00487            /* We need to try for 1.4 first for proper PCI domain support
00488             * and if that fails, we know the kernel is busted
00489             */
00490            sv.drm_di_major = 1;
00491            sv.drm_di_minor = 4;
00492            sv.drm_dd_major = -1;   /* Don't care */
00493            sv.drm_dd_minor = -1;   /* Don't care */
00494            if (drmSetInterfaceVersion(fd, &sv)) {
00495 #ifndef __alpha__
00496               pci_domain_ok = 0;
00497 #endif
00498               sv.drm_di_major = 1;
00499               sv.drm_di_minor = 1;
00500               sv.drm_dd_major = -1;       /* Don't care */
00501               sv.drm_dd_minor = -1;       /* Don't care */
00502               drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n",fd);
00503               drmSetInterfaceVersion(fd, &sv);
00504            }
00505            buf = drmGetBusid(fd);
00506            drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
00507            if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
00508               drmFreeBusid(buf);
00509               return fd;
00510            }
00511            if (buf)
00512               drmFreeBusid(buf);
00513            close(fd);
00514        }
00515     }
00516     return -1;
00517 }
00518 
00519 
00534 static int drmOpenByName(const char *name)
00535 {
00536     int           i;
00537     int           fd;
00538     drmVersionPtr version;
00539     char *        id;
00540     
00541     if (!drmAvailable()) {
00542        if (!drm_server_info) {
00543            return -1;
00544        }
00545        else {
00546            /* try to load the kernel module now */
00547            if (!drm_server_info->load_module(name)) {
00548               drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
00549               return -1;
00550            }
00551        }
00552     }
00553 
00554     /*
00555      * Open the first minor number that matches the driver name and isn't
00556      * already in use.  If it's in use it will have a busid assigned already.
00557      */
00558     for (i = 0; i < DRM_MAX_MINOR; i++) {
00559        if ((fd = drmOpenMinor(i, 1, DRM_NODE_RENDER)) >= 0) {
00560            if ((version = drmGetVersion(fd))) {
00561               if (!strcmp(version->name, name)) {
00562                   drmFreeVersion(version);
00563                   id = drmGetBusid(fd);
00564                   drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
00565                   if (!id || !*id) {
00566                      if (id)
00567                          drmFreeBusid(id);
00568                      return fd;
00569                   } else {
00570                      drmFreeBusid(id);
00571                   }
00572               } else {
00573                   drmFreeVersion(version);
00574               }
00575            }
00576            close(fd);
00577        }
00578     }
00579 
00580 #ifdef __linux__
00581     /* Backward-compatibility /proc support */
00582     for (i = 0; i < 8; i++) {
00583        char proc_name[64], buf[512];
00584        char *driver, *pt, *devstring;
00585        int  retcode;
00586        
00587        sprintf(proc_name, "/proc/dri/%d/name", i);
00588        if ((fd = open(proc_name, 0, 0)) >= 0) {
00589            retcode = read(fd, buf, sizeof(buf)-1);
00590            close(fd);
00591            if (retcode) {
00592               buf[retcode-1] = '\0';
00593               for (driver = pt = buf; *pt && *pt != ' '; ++pt)
00594                   ;
00595               if (*pt) { /* Device is next */
00596                   *pt = '\0';
00597                   if (!strcmp(driver, name)) { /* Match */
00598                      for (devstring = ++pt; *pt && *pt != ' '; ++pt)
00599                          ;
00600                      if (*pt) { /* Found busid */
00601                          return drmOpenByBusid(++pt);
00602                      } else { /* No busid */
00603                          return drmOpenDevice(strtol(devstring, NULL, 0),i, DRM_NODE_RENDER);
00604                      }
00605                   }
00606               }
00607            }
00608        }
00609     }
00610 #endif
00611 
00612     return -1;
00613 }
00614 
00615 
00631 int drmOpen(const char *name, const char *busid)
00632 {
00633     if (!drmAvailable() && name != NULL && drm_server_info) {
00634        /* try to load the kernel */
00635        if (!drm_server_info->load_module(name)) {
00636            drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
00637            return -1;
00638        }
00639     }
00640 
00641     if (busid) {
00642        int fd = drmOpenByBusid(busid);
00643        if (fd >= 0)
00644            return fd;
00645     }
00646     
00647     if (name)
00648        return drmOpenByName(name);
00649 
00650     return -1;
00651 }
00652 
00653 int drmOpenControl(int minor)
00654 {
00655     return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
00656 }
00657 
00667 void drmFreeVersion(drmVersionPtr v)
00668 {
00669     if (!v)
00670        return;
00671     drmFree(v->name);
00672     drmFree(v->date);
00673     drmFree(v->desc);
00674     drmFree(v);
00675 }
00676 
00677 
00687 static void drmFreeKernelVersion(drm_version_t *v)
00688 {
00689     if (!v)
00690        return;
00691     drmFree(v->name);
00692     drmFree(v->date);
00693     drmFree(v->desc);
00694     drmFree(v);
00695 }
00696 
00697 
00708 static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
00709 {
00710     d->version_major      = s->version_major;
00711     d->version_minor      = s->version_minor;
00712     d->version_patchlevel = s->version_patchlevel;
00713     d->name_len           = s->name_len;
00714     d->name               = strdup(s->name);
00715     d->date_len           = s->date_len;
00716     d->date               = strdup(s->date);
00717     d->desc_len           = s->desc_len;
00718     d->desc               = strdup(s->desc);
00719 }
00720 
00721 
00737 drmVersionPtr drmGetVersion(int fd)
00738 {
00739     drmVersionPtr retval;
00740     drm_version_t *version = drmMalloc(sizeof(*version));
00741 
00742     version->name_len    = 0;
00743     version->name        = NULL;
00744     version->date_len    = 0;
00745     version->date        = NULL;
00746     version->desc_len    = 0;
00747     version->desc        = NULL;
00748 
00749     if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
00750        drmFreeKernelVersion(version);
00751        return NULL;
00752     }
00753 
00754     if (version->name_len)
00755        version->name    = drmMalloc(version->name_len + 1);
00756     if (version->date_len)
00757        version->date    = drmMalloc(version->date_len + 1);
00758     if (version->desc_len)
00759        version->desc    = drmMalloc(version->desc_len + 1);
00760 
00761     if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
00762        drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
00763        drmFreeKernelVersion(version);
00764        return NULL;
00765     }
00766 
00767     /* The results might not be null-terminated strings, so terminate them. */
00768     if (version->name_len) version->name[version->name_len] = '\0';
00769     if (version->date_len) version->date[version->date_len] = '\0';
00770     if (version->desc_len) version->desc[version->desc_len] = '\0';
00771 
00772     retval = drmMalloc(sizeof(*retval));
00773     drmCopyVersion(retval, version);
00774     drmFreeKernelVersion(version);
00775     return retval;
00776 }
00777 
00778 
00792 drmVersionPtr drmGetLibVersion(int fd)
00793 {
00794     drm_version_t *version = drmMalloc(sizeof(*version));
00795 
00796     /* Version history:
00797      *   NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
00798      *   revision 1.0.x = original DRM interface with no drmGetLibVersion
00799      *                    entry point and many drm<Device> extensions
00800      *   revision 1.1.x = added drmCommand entry points for device extensions
00801      *                    added drmGetLibVersion to identify libdrm.a version
00802      *   revision 1.2.x = added drmSetInterfaceVersion
00803      *                    modified drmOpen to handle both busid and name
00804      *   revision 1.3.x = added server + memory manager
00805      */
00806     version->version_major      = 1;
00807     version->version_minor      = 3;
00808     version->version_patchlevel = 0;
00809 
00810     return (drmVersionPtr)version;
00811 }
00812 
00813 int drmGetCap(int fd, uint64_t capability, uint64_t *value)
00814 {
00815        struct drm_get_cap cap = { capability, 0 };
00816        int ret;
00817 
00818        ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
00819        if (ret)
00820               return ret;
00821 
00822        *value = cap.value;
00823        return 0;
00824 }
00825 
00834 void drmFreeBusid(const char *busid)
00835 {
00836     drmFree((void *)busid);
00837 }
00838 
00839 
00852 char *drmGetBusid(int fd)
00853 {
00854     drm_unique_t u;
00855 
00856     u.unique_len = 0;
00857     u.unique     = NULL;
00858 
00859     if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
00860        return NULL;
00861     u.unique = drmMalloc(u.unique_len + 1);
00862     if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
00863        return NULL;
00864     u.unique[u.unique_len] = '\0';
00865 
00866     return u.unique;
00867 }
00868 
00869 
00882 int drmSetBusid(int fd, const char *busid)
00883 {
00884     drm_unique_t u;
00885 
00886     u.unique     = (char *)busid;
00887     u.unique_len = strlen(busid);
00888 
00889     if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
00890        return -errno;
00891     }
00892     return 0;
00893 }
00894 
00895 int drmGetMagic(int fd, drm_magic_t * magic)
00896 {
00897     drm_auth_t auth;
00898 
00899     *magic = 0;
00900     if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
00901        return -errno;
00902     *magic = auth.magic;
00903     return 0;
00904 }
00905 
00906 int drmAuthMagic(int fd, drm_magic_t magic)
00907 {
00908     drm_auth_t auth;
00909 
00910     auth.magic = magic;
00911     if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
00912        return -errno;
00913     return 0;
00914 }
00915 
00966 int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
00967              drmMapFlags flags, drm_handle_t *handle)
00968 {
00969     drm_map_t map;
00970 
00971     map.offset  = offset;
00972     map.size    = size;
00973     map.handle  = 0;
00974     map.type    = type;
00975     map.flags   = flags;
00976     if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
00977        return -errno;
00978     if (handle)
00979        *handle = (drm_handle_t)(uintptr_t)map.handle;
00980     return 0;
00981 }
00982 
00983 int drmRmMap(int fd, drm_handle_t handle)
00984 {
00985     drm_map_t map;
00986 
00987     map.handle = (void *)(uintptr_t)handle;
00988 
00989     if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
00990        return -errno;
00991     return 0;
00992 }
00993 
01010 int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
01011               int agp_offset)
01012 {
01013     drm_buf_desc_t request;
01014 
01015     request.count     = count;
01016     request.size      = size;
01017     request.low_mark  = 0;
01018     request.high_mark = 0;
01019     request.flags     = flags;
01020     request.agp_start = agp_offset;
01021 
01022     if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
01023        return -errno;
01024     return request.count;
01025 }
01026 
01027 int drmMarkBufs(int fd, double low, double high)
01028 {
01029     drm_buf_info_t info;
01030     int            i;
01031 
01032     info.count = 0;
01033     info.list  = NULL;
01034 
01035     if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
01036        return -EINVAL;
01037 
01038     if (!info.count)
01039        return -EINVAL;
01040 
01041     if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
01042        return -ENOMEM;
01043 
01044     if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
01045        int retval = -errno;
01046        drmFree(info.list);
01047        return retval;
01048     }
01049 
01050     for (i = 0; i < info.count; i++) {
01051        info.list[i].low_mark  = low  * info.list[i].count;
01052        info.list[i].high_mark = high * info.list[i].count;
01053        if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
01054            int retval = -errno;
01055            drmFree(info.list);
01056            return retval;
01057        }
01058     }
01059     drmFree(info.list);
01060 
01061     return 0;
01062 }
01063 
01079 int drmFreeBufs(int fd, int count, int *list)
01080 {
01081     drm_buf_free_t request;
01082 
01083     request.count = count;
01084     request.list  = list;
01085     if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
01086        return -errno;
01087     return 0;
01088 }
01089 
01090 
01099 int drmClose(int fd)
01100 {
01101     unsigned long key    = drmGetKeyFromFd(fd);
01102     drmHashEntry  *entry = drmGetEntry(fd);
01103 
01104     drmHashDestroy(entry->tagTable);
01105     entry->fd       = 0;
01106     entry->f        = NULL;
01107     entry->tagTable = NULL;
01108 
01109     drmHashDelete(drmHashTable, key);
01110     drmFree(entry);
01111 
01112     return close(fd);
01113 }
01114 
01115 
01130 int drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address)
01131 {
01132     static unsigned long pagesize_mask = 0;
01133 
01134     if (fd < 0)
01135        return -EINVAL;
01136 
01137     if (!pagesize_mask)
01138        pagesize_mask = getpagesize() - 1;
01139 
01140     size = (size + pagesize_mask) & ~pagesize_mask;
01141 
01142     *address = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
01143     if (*address == MAP_FAILED)
01144        return -errno;
01145     return 0;
01146 }
01147 
01148 
01160 int drmUnmap(drmAddress address, drmSize size)
01161 {
01162     return munmap(address, size);
01163 }
01164 
01165 drmBufInfoPtr drmGetBufInfo(int fd)
01166 {
01167     drm_buf_info_t info;
01168     drmBufInfoPtr  retval;
01169     int            i;
01170 
01171     info.count = 0;
01172     info.list  = NULL;
01173 
01174     if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
01175        return NULL;
01176 
01177     if (info.count) {
01178        if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
01179            return NULL;
01180 
01181        if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
01182            drmFree(info.list);
01183            return NULL;
01184        }
01185 
01186        retval = drmMalloc(sizeof(*retval));
01187        retval->count = info.count;
01188        retval->list  = drmMalloc(info.count * sizeof(*retval->list));
01189        for (i = 0; i < info.count; i++) {
01190            retval->list[i].count     = info.list[i].count;
01191            retval->list[i].size      = info.list[i].size;
01192            retval->list[i].low_mark  = info.list[i].low_mark;
01193            retval->list[i].high_mark = info.list[i].high_mark;
01194        }
01195        drmFree(info.list);
01196        return retval;
01197     }
01198     return NULL;
01199 }
01200 
01216 drmBufMapPtr drmMapBufs(int fd)
01217 {
01218     drm_buf_map_t bufs;
01219     drmBufMapPtr  retval;
01220     int           i;
01221 
01222     bufs.count = 0;
01223     bufs.list  = NULL;
01224     bufs.virtual = NULL;
01225     if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
01226        return NULL;
01227 
01228     if (!bufs.count)
01229        return NULL;
01230 
01231        if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
01232            return NULL;
01233 
01234        if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
01235            drmFree(bufs.list);
01236            return NULL;
01237        }
01238 
01239        retval = drmMalloc(sizeof(*retval));
01240        retval->count = bufs.count;
01241        retval->list  = drmMalloc(bufs.count * sizeof(*retval->list));
01242        for (i = 0; i < bufs.count; i++) {
01243            retval->list[i].idx     = bufs.list[i].idx;
01244            retval->list[i].total   = bufs.list[i].total;
01245            retval->list[i].used    = 0;
01246            retval->list[i].address = bufs.list[i].address;
01247        }
01248 
01249        drmFree(bufs.list);
01250        
01251        return retval;
01252 }
01253 
01254 
01264 int drmUnmapBufs(drmBufMapPtr bufs)
01265 {
01266     int i;
01267 
01268     for (i = 0; i < bufs->count; i++) {
01269        munmap(bufs->list[i].address, bufs->list[i].total);
01270     }
01271 
01272     drmFree(bufs->list);
01273     drmFree(bufs);
01274        
01275     return 0;
01276 }
01277 
01278 
01279 #define DRM_DMA_RETRY              16
01280 
01293 int drmDMA(int fd, drmDMAReqPtr request)
01294 {
01295     drm_dma_t dma;
01296     int ret, i = 0;
01297 
01298     dma.context         = request->context;
01299     dma.send_count      = request->send_count;
01300     dma.send_indices    = request->send_list;
01301     dma.send_sizes      = request->send_sizes;
01302     dma.flags           = request->flags;
01303     dma.request_count   = request->request_count;
01304     dma.request_size    = request->request_size;
01305     dma.request_indices = request->request_list;
01306     dma.request_sizes   = request->request_sizes;
01307     dma.granted_count   = 0;
01308 
01309     do {
01310        ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
01311     } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
01312 
01313     if ( ret == 0 ) {
01314        request->granted_count = dma.granted_count;
01315        return 0;
01316     } else {
01317        return -errno;
01318     }
01319 }
01320 
01321 
01336 int drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
01337 {
01338     drm_lock_t lock;
01339 
01340     lock.context = context;
01341     lock.flags   = 0;
01342     if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
01343     if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
01344     if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
01345     if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
01346     if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
01347     if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
01348 
01349     while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock))
01350        ;
01351     return 0;
01352 }
01353 
01366 int drmUnlock(int fd, drm_context_t context)
01367 {
01368     drm_lock_t lock;
01369 
01370     lock.context = context;
01371     lock.flags   = 0;
01372     return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
01373 }
01374 
01375 drm_context_t *drmGetReservedContextList(int fd, int *count)
01376 {
01377     drm_ctx_res_t res;
01378     drm_ctx_t     *list;
01379     drm_context_t * retval;
01380     int           i;
01381 
01382     res.count    = 0;
01383     res.contexts = NULL;
01384     if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
01385        return NULL;
01386 
01387     if (!res.count)
01388        return NULL;
01389 
01390     if (!(list   = drmMalloc(res.count * sizeof(*list))))
01391        return NULL;
01392     if (!(retval = drmMalloc(res.count * sizeof(*retval)))) {
01393        drmFree(list);
01394        return NULL;
01395     }
01396 
01397     res.contexts = list;
01398     if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
01399        return NULL;
01400 
01401     for (i = 0; i < res.count; i++)
01402        retval[i] = list[i].handle;
01403     drmFree(list);
01404 
01405     *count = res.count;
01406     return retval;
01407 }
01408 
01409 void drmFreeReservedContextList(drm_context_t *pt)
01410 {
01411     drmFree(pt);
01412 }
01413 
01432 int drmCreateContext(int fd, drm_context_t *handle)
01433 {
01434     drm_ctx_t ctx;
01435 
01436     ctx.flags = 0;   /* Modified with functions below */
01437     if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
01438        return -errno;
01439     *handle = ctx.handle;
01440     return 0;
01441 }
01442 
01443 int drmSwitchToContext(int fd, drm_context_t context)
01444 {
01445     drm_ctx_t ctx;
01446 
01447     ctx.handle = context;
01448     if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
01449        return -errno;
01450     return 0;
01451 }
01452 
01453 int drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags)
01454 {
01455     drm_ctx_t ctx;
01456 
01457     /*
01458      * Context preserving means that no context switches are done between DMA
01459      * buffers from one context and the next.  This is suitable for use in the
01460      * X server (which promises to maintain hardware context), or in the
01461      * client-side library when buffers are swapped on behalf of two threads.
01462      */
01463     ctx.handle = context;
01464     ctx.flags  = 0;
01465     if (flags & DRM_CONTEXT_PRESERVED)
01466        ctx.flags |= _DRM_CONTEXT_PRESERVED;
01467     if (flags & DRM_CONTEXT_2DONLY)
01468        ctx.flags |= _DRM_CONTEXT_2DONLY;
01469     if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
01470        return -errno;
01471     return 0;
01472 }
01473 
01474 int drmGetContextFlags(int fd, drm_context_t context,
01475                        drm_context_tFlagsPtr flags)
01476 {
01477     drm_ctx_t ctx;
01478 
01479     ctx.handle = context;
01480     if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
01481        return -errno;
01482     *flags = 0;
01483     if (ctx.flags & _DRM_CONTEXT_PRESERVED)
01484        *flags |= DRM_CONTEXT_PRESERVED;
01485     if (ctx.flags & _DRM_CONTEXT_2DONLY)
01486        *flags |= DRM_CONTEXT_2DONLY;
01487     return 0;
01488 }
01489 
01507 int drmDestroyContext(int fd, drm_context_t handle)
01508 {
01509     drm_ctx_t ctx;
01510     ctx.handle = handle;
01511     if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
01512        return -errno;
01513     return 0;
01514 }
01515 
01516 int drmCreateDrawable(int fd, drm_drawable_t *handle)
01517 {
01518     drm_draw_t draw;
01519     if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
01520        return -errno;
01521     *handle = draw.handle;
01522     return 0;
01523 }
01524 
01525 int drmDestroyDrawable(int fd, drm_drawable_t handle)
01526 {
01527     drm_draw_t draw;
01528     draw.handle = handle;
01529     if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
01530        return -errno;
01531     return 0;
01532 }
01533 
01534 int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
01535                         drm_drawable_info_type_t type, unsigned int num,
01536                         void *data)
01537 {
01538     drm_update_draw_t update;
01539 
01540     update.handle = handle;
01541     update.type = type;
01542     update.num = num;
01543     update.data = (unsigned long long)(unsigned long)data;
01544 
01545     if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
01546        return -errno;
01547 
01548     return 0;
01549 }
01550 
01563 int drmAgpAcquire(int fd)
01564 {
01565     if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
01566        return -errno;
01567     return 0;
01568 }
01569 
01570 
01581 int drmAgpRelease(int fd)
01582 {
01583     if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
01584        return -errno;
01585     return 0;
01586 }
01587 
01588 
01601 int drmAgpEnable(int fd, unsigned long mode)
01602 {
01603     drm_agp_mode_t m;
01604 
01605     m.mode = mode;
01606     if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
01607        return -errno;
01608     return 0;
01609 }
01610 
01611 
01628 int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
01629               unsigned long *address, drm_handle_t *handle)
01630 {
01631     drm_agp_buffer_t b;
01632 
01633     *handle = DRM_AGP_NO_HANDLE;
01634     b.size   = size;
01635     b.handle = 0;
01636     b.type   = type;
01637     if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
01638        return -errno;
01639     if (address != 0UL)
01640        *address = b.physical;
01641     *handle = b.handle;
01642     return 0;
01643 }
01644 
01645 
01658 int drmAgpFree(int fd, drm_handle_t handle)
01659 {
01660     drm_agp_buffer_t b;
01661 
01662     b.size   = 0;
01663     b.handle = handle;
01664     if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
01665        return -errno;
01666     return 0;
01667 }
01668 
01669 
01683 int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
01684 {
01685     drm_agp_binding_t b;
01686 
01687     b.handle = handle;
01688     b.offset = offset;
01689     if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
01690        return -errno;
01691     return 0;
01692 }
01693 
01694 
01707 int drmAgpUnbind(int fd, drm_handle_t handle)
01708 {
01709     drm_agp_binding_t b;
01710 
01711     b.handle = handle;
01712     b.offset = 0;
01713     if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
01714        return -errno;
01715     return 0;
01716 }
01717 
01718 
01730 int drmAgpVersionMajor(int fd)
01731 {
01732     drm_agp_info_t i;
01733 
01734     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
01735        return -errno;
01736     return i.agp_version_major;
01737 }
01738 
01739 
01751 int drmAgpVersionMinor(int fd)
01752 {
01753     drm_agp_info_t i;
01754 
01755     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
01756        return -errno;
01757     return i.agp_version_minor;
01758 }
01759 
01760 
01772 unsigned long drmAgpGetMode(int fd)
01773 {
01774     drm_agp_info_t i;
01775 
01776     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
01777        return 0;
01778     return i.mode;
01779 }
01780 
01781 
01793 unsigned long drmAgpBase(int fd)
01794 {
01795     drm_agp_info_t i;
01796 
01797     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
01798        return 0;
01799     return i.aperture_base;
01800 }
01801 
01802 
01814 unsigned long drmAgpSize(int fd)
01815 {
01816     drm_agp_info_t i;
01817 
01818     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
01819        return 0;
01820     return i.aperture_size;
01821 }
01822 
01823 
01835 unsigned long drmAgpMemoryUsed(int fd)
01836 {
01837     drm_agp_info_t i;
01838 
01839     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
01840        return 0;
01841     return i.memory_used;
01842 }
01843 
01844 
01856 unsigned long drmAgpMemoryAvail(int fd)
01857 {
01858     drm_agp_info_t i;
01859 
01860     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
01861        return 0;
01862     return i.memory_allowed;
01863 }
01864 
01865 
01877 unsigned int drmAgpVendorId(int fd)
01878 {
01879     drm_agp_info_t i;
01880 
01881     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
01882        return 0;
01883     return i.id_vendor;
01884 }
01885 
01886 
01898 unsigned int drmAgpDeviceId(int fd)
01899 {
01900     drm_agp_info_t i;
01901 
01902     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
01903        return 0;
01904     return i.id_device;
01905 }
01906 
01907 int drmScatterGatherAlloc(int fd, unsigned long size, drm_handle_t *handle)
01908 {
01909     drm_scatter_gather_t sg;
01910 
01911     *handle = 0;
01912     sg.size   = size;
01913     sg.handle = 0;
01914     if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
01915        return -errno;
01916     *handle = sg.handle;
01917     return 0;
01918 }
01919 
01920 int drmScatterGatherFree(int fd, drm_handle_t handle)
01921 {
01922     drm_scatter_gather_t sg;
01923 
01924     sg.size   = 0;
01925     sg.handle = handle;
01926     if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
01927        return -errno;
01928     return 0;
01929 }
01930 
01942 int drmWaitVBlank(int fd, drmVBlankPtr vbl)
01943 {
01944     struct timespec timeout, cur;
01945     int ret;
01946 
01947     ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
01948     if (ret < 0) {
01949        fprintf(stderr, "clock_gettime failed: %s\n", strerror(ret));
01950        goto out;
01951     }
01952     timeout.tv_sec++;
01953 
01954     do {
01955        ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
01956        vbl->request.type &= ~DRM_VBLANK_RELATIVE;
01957        if (ret && errno == EINTR) {
01958               clock_gettime(CLOCK_MONOTONIC, &cur);
01959               /* Timeout after 1s */
01960               if (cur.tv_sec > timeout.tv_sec + 1 ||
01961                  (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
01962                   timeout.tv_nsec)) {
01963                      errno = EBUSY;
01964                      ret = -1;
01965                      break;
01966               }
01967        }
01968     } while (ret && errno == EINTR);
01969 
01970 out:
01971     return ret;
01972 }
01973 
01974 int drmError(int err, const char *label)
01975 {
01976     switch (err) {
01977     case DRM_ERR_NO_DEVICE:
01978        fprintf(stderr, "%s: no device\n", label);
01979        break;
01980     case DRM_ERR_NO_ACCESS:
01981        fprintf(stderr, "%s: no access\n", label);
01982        break;
01983     case DRM_ERR_NOT_ROOT:
01984        fprintf(stderr, "%s: not root\n", label);
01985        break;
01986     case DRM_ERR_INVALID:
01987        fprintf(stderr, "%s: invalid args\n", label);
01988        break;
01989     default:
01990        if (err < 0)
01991            err = -err;
01992        fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
01993        break;
01994     }
01995 
01996     return 1;
01997 }
01998 
02011 int drmCtlInstHandler(int fd, int irq)
02012 {
02013     drm_control_t ctl;
02014 
02015     ctl.func  = DRM_INST_HANDLER;
02016     ctl.irq   = irq;
02017     if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
02018        return -errno;
02019     return 0;
02020 }
02021 
02022 
02034 int drmCtlUninstHandler(int fd)
02035 {
02036     drm_control_t ctl;
02037 
02038     ctl.func  = DRM_UNINST_HANDLER;
02039     ctl.irq   = 0;
02040     if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
02041        return -errno;
02042     return 0;
02043 }
02044 
02045 int drmFinish(int fd, int context, drmLockFlags flags)
02046 {
02047     drm_lock_t lock;
02048 
02049     lock.context = context;
02050     lock.flags   = 0;
02051     if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
02052     if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
02053     if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
02054     if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
02055     if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
02056     if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
02057     if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock))
02058        return -errno;
02059     return 0;
02060 }
02061 
02076 int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
02077 {
02078     drm_irq_busid_t p;
02079 
02080     p.busnum  = busnum;
02081     p.devnum  = devnum;
02082     p.funcnum = funcnum;
02083     if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
02084        return -errno;
02085     return p.irq;
02086 }
02087 
02088 int drmAddContextTag(int fd, drm_context_t context, void *tag)
02089 {
02090     drmHashEntry  *entry = drmGetEntry(fd);
02091 
02092     if (drmHashInsert(entry->tagTable, context, tag)) {
02093        drmHashDelete(entry->tagTable, context);
02094        drmHashInsert(entry->tagTable, context, tag);
02095     }
02096     return 0;
02097 }
02098 
02099 int drmDelContextTag(int fd, drm_context_t context)
02100 {
02101     drmHashEntry  *entry = drmGetEntry(fd);
02102 
02103     return drmHashDelete(entry->tagTable, context);
02104 }
02105 
02106 void *drmGetContextTag(int fd, drm_context_t context)
02107 {
02108     drmHashEntry  *entry = drmGetEntry(fd);
02109     void          *value;
02110 
02111     if (drmHashLookup(entry->tagTable, context, &value))
02112        return NULL;
02113 
02114     return value;
02115 }
02116 
02117 int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
02118                                 drm_handle_t handle)
02119 {
02120     drm_ctx_priv_map_t map;
02121 
02122     map.ctx_id = ctx_id;
02123     map.handle = (void *)(uintptr_t)handle;
02124 
02125     if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
02126        return -errno;
02127     return 0;
02128 }
02129 
02130 int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
02131                                 drm_handle_t *handle)
02132 {
02133     drm_ctx_priv_map_t map;
02134 
02135     map.ctx_id = ctx_id;
02136 
02137     if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
02138        return -errno;
02139     if (handle)
02140        *handle = (drm_handle_t)(uintptr_t)map.handle;
02141 
02142     return 0;
02143 }
02144 
02145 int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
02146              drmMapType *type, drmMapFlags *flags, drm_handle_t *handle,
02147              int *mtrr)
02148 {
02149     drm_map_t map;
02150 
02151     map.offset = idx;
02152     if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
02153        return -errno;
02154     *offset = map.offset;
02155     *size   = map.size;
02156     *type   = map.type;
02157     *flags  = map.flags;
02158     *handle = (unsigned long)map.handle;
02159     *mtrr   = map.mtrr;
02160     return 0;
02161 }
02162 
02163 int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
02164                unsigned long *magic, unsigned long *iocs)
02165 {
02166     drm_client_t client;
02167 
02168     client.idx = idx;
02169     if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
02170        return -errno;
02171     *auth      = client.auth;
02172     *pid       = client.pid;
02173     *uid       = client.uid;
02174     *magic     = client.magic;
02175     *iocs      = client.iocs;
02176     return 0;
02177 }
02178 
02179 int drmGetStats(int fd, drmStatsT *stats)
02180 {
02181     drm_stats_t s;
02182     int         i;
02183 
02184     if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
02185        return -errno;
02186 
02187     stats->count = 0;
02188     memset(stats, 0, sizeof(*stats));
02189     if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
02190        return -1;
02191 
02192 #define SET_VALUE                              \
02193     stats->data[i].long_format = "%-20.20s";   \
02194     stats->data[i].rate_format = "%8.8s";      \
02195     stats->data[i].isvalue     = 1;            \
02196     stats->data[i].verbose     = 0
02197 
02198 #define SET_COUNT                              \
02199     stats->data[i].long_format = "%-20.20s";   \
02200     stats->data[i].rate_format = "%5.5s";      \
02201     stats->data[i].isvalue     = 0;            \
02202     stats->data[i].mult_names  = "kgm";        \
02203     stats->data[i].mult        = 1000;         \
02204     stats->data[i].verbose     = 0
02205 
02206 #define SET_BYTE                               \
02207     stats->data[i].long_format = "%-20.20s";   \
02208     stats->data[i].rate_format = "%5.5s";      \
02209     stats->data[i].isvalue     = 0;            \
02210     stats->data[i].mult_names  = "KGM";        \
02211     stats->data[i].mult        = 1024;         \
02212     stats->data[i].verbose     = 0
02213 
02214 
02215     stats->count = s.count;
02216     for (i = 0; i < s.count; i++) {
02217        stats->data[i].value = s.data[i].value;
02218        switch (s.data[i].type) {
02219        case _DRM_STAT_LOCK:
02220            stats->data[i].long_name = "Lock";
02221            stats->data[i].rate_name = "Lock";
02222            SET_VALUE;
02223            break;
02224        case _DRM_STAT_OPENS:
02225            stats->data[i].long_name = "Opens";
02226            stats->data[i].rate_name = "O";
02227            SET_COUNT;
02228            stats->data[i].verbose   = 1;
02229            break;
02230        case _DRM_STAT_CLOSES:
02231            stats->data[i].long_name = "Closes";
02232            stats->data[i].rate_name = "Lock";
02233            SET_COUNT;
02234            stats->data[i].verbose   = 1;
02235            break;
02236        case _DRM_STAT_IOCTLS:
02237            stats->data[i].long_name = "Ioctls";
02238            stats->data[i].rate_name = "Ioc/s";
02239            SET_COUNT;
02240            break;
02241        case _DRM_STAT_LOCKS:
02242            stats->data[i].long_name = "Locks";
02243            stats->data[i].rate_name = "Lck/s";
02244            SET_COUNT;
02245            break;
02246        case _DRM_STAT_UNLOCKS:
02247            stats->data[i].long_name = "Unlocks";
02248            stats->data[i].rate_name = "Unl/s";
02249            SET_COUNT;
02250            break;
02251        case _DRM_STAT_IRQ:
02252            stats->data[i].long_name = "IRQs";
02253            stats->data[i].rate_name = "IRQ/s";
02254            SET_COUNT;
02255            break;
02256        case _DRM_STAT_PRIMARY:
02257            stats->data[i].long_name = "Primary Bytes";
02258            stats->data[i].rate_name = "PB/s";
02259            SET_BYTE;
02260            break;
02261        case _DRM_STAT_SECONDARY:
02262            stats->data[i].long_name = "Secondary Bytes";
02263            stats->data[i].rate_name = "SB/s";
02264            SET_BYTE;
02265            break;
02266        case _DRM_STAT_DMA:
02267            stats->data[i].long_name = "DMA";
02268            stats->data[i].rate_name = "DMA/s";
02269            SET_COUNT;
02270            break;
02271        case _DRM_STAT_SPECIAL:
02272            stats->data[i].long_name = "Special DMA";
02273            stats->data[i].rate_name = "dma/s";
02274            SET_COUNT;
02275            break;
02276        case _DRM_STAT_MISSED:
02277            stats->data[i].long_name = "Miss";
02278            stats->data[i].rate_name = "Ms/s";
02279            SET_COUNT;
02280            break;
02281        case _DRM_STAT_VALUE:
02282            stats->data[i].long_name = "Value";
02283            stats->data[i].rate_name = "Value";
02284            SET_VALUE;
02285            break;
02286        case _DRM_STAT_BYTE:
02287            stats->data[i].long_name = "Bytes";
02288            stats->data[i].rate_name = "B/s";
02289            SET_BYTE;
02290            break;
02291        case _DRM_STAT_COUNT:
02292        default:
02293            stats->data[i].long_name = "Count";
02294            stats->data[i].rate_name = "Cnt/s";
02295            SET_COUNT;
02296            break;
02297        }
02298     }
02299     return 0;
02300 }
02301 
02316 int drmSetInterfaceVersion(int fd, drmSetVersion *version)
02317 {
02318     int retcode = 0;
02319     drm_set_version_t sv;
02320 
02321     sv.drm_di_major = version->drm_di_major;
02322     sv.drm_di_minor = version->drm_di_minor;
02323     sv.drm_dd_major = version->drm_dd_major;
02324     sv.drm_dd_minor = version->drm_dd_minor;
02325 
02326     if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
02327        retcode = -errno;
02328     }
02329 
02330     version->drm_di_major = sv.drm_di_major;
02331     version->drm_di_minor = sv.drm_di_minor;
02332     version->drm_dd_major = sv.drm_dd_major;
02333     version->drm_dd_minor = sv.drm_dd_minor;
02334 
02335     return retcode;
02336 }
02337 
02350 int drmCommandNone(int fd, unsigned long drmCommandIndex)
02351 {
02352     void *data = NULL; /* dummy */
02353     unsigned long request;
02354 
02355     request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
02356 
02357     if (drmIoctl(fd, request, data)) {
02358        return -errno;
02359     }
02360     return 0;
02361 }
02362 
02363 
02378 int drmCommandRead(int fd, unsigned long drmCommandIndex, void *data,
02379                    unsigned long size)
02380 {
02381     unsigned long request;
02382 
02383     request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE, 
02384        DRM_COMMAND_BASE + drmCommandIndex, size);
02385 
02386     if (drmIoctl(fd, request, data)) {
02387        return -errno;
02388     }
02389     return 0;
02390 }
02391 
02392 
02407 int drmCommandWrite(int fd, unsigned long drmCommandIndex, void *data,
02408                     unsigned long size)
02409 {
02410     unsigned long request;
02411 
02412     request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE, 
02413        DRM_COMMAND_BASE + drmCommandIndex, size);
02414 
02415     if (drmIoctl(fd, request, data)) {
02416        return -errno;
02417     }
02418     return 0;
02419 }
02420 
02421 
02436 int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data,
02437                         unsigned long size)
02438 {
02439     unsigned long request;
02440 
02441     request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE, 
02442        DRM_COMMAND_BASE + drmCommandIndex, size);
02443 
02444     if (drmIoctl(fd, request, data))
02445        return -errno;
02446     return 0;
02447 }
02448 
02449 #define DRM_MAX_FDS 16
02450 static struct {
02451     char *BusID;
02452     int fd;
02453     int refcount;
02454 } connection[DRM_MAX_FDS];
02455 
02456 static int nr_fds = 0;
02457 
02458 int drmOpenOnce(void *unused, 
02459               const char *BusID,
02460               int *newlyopened)
02461 {
02462     int i;
02463     int fd;
02464    
02465     for (i = 0; i < nr_fds; i++)
02466        if (strcmp(BusID, connection[i].BusID) == 0) {
02467            connection[i].refcount++;
02468            *newlyopened = 0;
02469            return connection[i].fd;
02470        }
02471 
02472     fd = drmOpen(unused, BusID);
02473     if (fd <= 0 || nr_fds == DRM_MAX_FDS)
02474        return fd;
02475    
02476     connection[nr_fds].BusID = strdup(BusID);
02477     connection[nr_fds].fd = fd;
02478     connection[nr_fds].refcount = 1;
02479     *newlyopened = 1;
02480 
02481     if (0)
02482        fprintf(stderr, "saved connection %d for %s %d\n", 
02483               nr_fds, connection[nr_fds].BusID, 
02484               strcmp(BusID, connection[nr_fds].BusID));
02485 
02486     nr_fds++;
02487 
02488     return fd;
02489 }
02490 
02491 void drmCloseOnce(int fd)
02492 {
02493     int i;
02494 
02495     for (i = 0; i < nr_fds; i++) {
02496        if (fd == connection[i].fd) {
02497            if (--connection[i].refcount == 0) {
02498               drmClose(connection[i].fd);
02499               free(connection[i].BusID);
02500            
02501               if (i < --nr_fds) 
02502                   connection[i] = connection[nr_fds];
02503 
02504               return;
02505            }
02506        }
02507     }
02508 }
02509 
02510 int drmSetMaster(int fd)
02511 {
02512        return ioctl(fd, DRM_IOCTL_SET_MASTER, 0);
02513 }
02514 
02515 int drmDropMaster(int fd)
02516 {
02517        return ioctl(fd, DRM_IOCTL_DROP_MASTER, 0);
02518 }
02519 
02520 char *drmGetDeviceNameFromFd(int fd)
02521 {
02522        char name[128];
02523        struct stat sbuf;
02524        dev_t d;
02525        int i;
02526 
02527        /* The whole drmOpen thing is a fiasco and we need to find a way
02528         * back to just using open(2).  For now, however, lets just make
02529         * things worse with even more ad hoc directory walking code to
02530         * discover the device file name. */
02531 
02532        fstat(fd, &sbuf);
02533        d = sbuf.st_rdev;
02534 
02535        for (i = 0; i < DRM_MAX_MINOR; i++) {
02536               snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
02537               if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
02538                      break;
02539        }
02540        if (i == DRM_MAX_MINOR)
02541               return NULL;
02542 
02543        return strdup(name);
02544 }