Home | History | Annotate | Download | only in libdrm
      1 /**
      2  * \file xf86drm.c
      3  * User-level interface to DRM device
      4  *
      5  * \author Rickard E. (Rik) Faith <faith (at) valinux.com>
      6  * \author Kevin E. Martin <martin (at) valinux.com>
      7  */
      8 
      9 /*
     10  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
     11  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
     12  * All Rights Reserved.
     13  *
     14  * Permission is hereby granted, free of charge, to any person obtaining a
     15  * copy of this software and associated documentation files (the "Software"),
     16  * to deal in the Software without restriction, including without limitation
     17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     18  * and/or sell copies of the Software, and to permit persons to whom the
     19  * Software is furnished to do so, subject to the following conditions:
     20  *
     21  * The above copyright notice and this permission notice (including the next
     22  * paragraph) shall be included in all copies or substantial portions of the
     23  * Software.
     24  *
     25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     26  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     27  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     28  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     29  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     30  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     31  * DEALINGS IN THE SOFTWARE.
     32  */
     33 
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <stdbool.h>
     37 #include <unistd.h>
     38 #include <string.h>
     39 #include <strings.h>
     40 #include <ctype.h>
     41 #include <dirent.h>
     42 #include <stddef.h>
     43 #include <fcntl.h>
     44 #include <errno.h>
     45 #include <limits.h>
     46 #include <signal.h>
     47 #include <time.h>
     48 #include <sys/types.h>
     49 #include <sys/stat.h>
     50 #define stat_t struct stat
     51 #include <sys/ioctl.h>
     52 #include <sys/time.h>
     53 #include <stdarg.h>
     54 #ifdef MAJOR_IN_MKDEV
     55 #include <sys/mkdev.h>
     56 #endif
     57 #ifdef MAJOR_IN_SYSMACROS
     58 #include <sys/sysmacros.h>
     59 #endif
     60 #include <math.h>
     61 
     62 /* Not all systems have MAP_FAILED defined */
     63 #ifndef MAP_FAILED
     64 #define MAP_FAILED ((void *)-1)
     65 #endif
     66 
     67 #include "xf86drm.h"
     68 #include "libdrm_macros.h"
     69 
     70 #include "util_math.h"
     71 
     72 #ifdef __OpenBSD__
     73 #define DRM_PRIMARY_MINOR_NAME  "drm"
     74 #define DRM_CONTROL_MINOR_NAME  "drmC"
     75 #define DRM_RENDER_MINOR_NAME   "drmR"
     76 #else
     77 #define DRM_PRIMARY_MINOR_NAME  "card"
     78 #define DRM_CONTROL_MINOR_NAME  "controlD"
     79 #define DRM_RENDER_MINOR_NAME   "renderD"
     80 #endif
     81 
     82 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
     83 #define DRM_MAJOR 145
     84 #endif
     85 
     86 #ifdef __NetBSD__
     87 #define DRM_MAJOR 34
     88 #endif
     89 
     90 #ifdef __OpenBSD__
     91 #ifdef __i386__
     92 #define DRM_MAJOR 88
     93 #else
     94 #define DRM_MAJOR 87
     95 #endif
     96 #endif /* __OpenBSD__ */
     97 
     98 #ifndef DRM_MAJOR
     99 #define DRM_MAJOR 226 /* Linux */
    100 #endif
    101 
    102 #ifdef __OpenBSD__
    103 struct drm_pciinfo {
    104 	uint16_t	domain;
    105 	uint8_t		bus;
    106 	uint8_t		dev;
    107 	uint8_t		func;
    108 	uint16_t	vendor_id;
    109 	uint16_t	device_id;
    110 	uint16_t	subvendor_id;
    111 	uint16_t	subdevice_id;
    112 	uint8_t		revision_id;
    113 };
    114 
    115 #define DRM_IOCTL_GET_PCIINFO	DRM_IOR(0x15, struct drm_pciinfo)
    116 #endif
    117 
    118 #define DRM_MSG_VERBOSITY 3
    119 
    120 #define memclear(s) memset(&s, 0, sizeof(s))
    121 
    122 static drmServerInfoPtr drm_server_info;
    123 
    124 void drmSetServerInfo(drmServerInfoPtr info)
    125 {
    126     drm_server_info = info;
    127 }
    128 
    129 /**
    130  * Output a message to stderr.
    131  *
    132  * \param format printf() like format string.
    133  *
    134  * \internal
    135  * This function is a wrapper around vfprintf().
    136  */
    137 
    138 static int DRM_PRINTFLIKE(1, 0)
    139 drmDebugPrint(const char *format, va_list ap)
    140 {
    141     return vfprintf(stderr, format, ap);
    142 }
    143 
    144 void
    145 drmMsg(const char *format, ...)
    146 {
    147     va_list ap;
    148     const char *env;
    149     if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) ||
    150         (drm_server_info && drm_server_info->debug_print))
    151     {
    152         va_start(ap, format);
    153         if (drm_server_info) {
    154             drm_server_info->debug_print(format,ap);
    155         } else {
    156             drmDebugPrint(format, ap);
    157         }
    158         va_end(ap);
    159     }
    160 }
    161 
    162 static void *drmHashTable = NULL; /* Context switch callbacks */
    163 
    164 void *drmGetHashTable(void)
    165 {
    166     return drmHashTable;
    167 }
    168 
    169 void *drmMalloc(int size)
    170 {
    171     return calloc(1, size);
    172 }
    173 
    174 void drmFree(void *pt)
    175 {
    176     free(pt);
    177 }
    178 
    179 /**
    180  * Call ioctl, restarting if it is interupted
    181  */
    182 int
    183 drmIoctl(int fd, unsigned long request, void *arg)
    184 {
    185     int ret;
    186 
    187     do {
    188         ret = ioctl(fd, request, arg);
    189     } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
    190     return ret;
    191 }
    192 
    193 static unsigned long drmGetKeyFromFd(int fd)
    194 {
    195     stat_t     st;
    196 
    197     st.st_rdev = 0;
    198     fstat(fd, &st);
    199     return st.st_rdev;
    200 }
    201 
    202 drmHashEntry *drmGetEntry(int fd)
    203 {
    204     unsigned long key = drmGetKeyFromFd(fd);
    205     void          *value;
    206     drmHashEntry  *entry;
    207 
    208     if (!drmHashTable)
    209         drmHashTable = drmHashCreate();
    210 
    211     if (drmHashLookup(drmHashTable, key, &value)) {
    212         entry           = drmMalloc(sizeof(*entry));
    213         entry->fd       = fd;
    214         entry->f        = NULL;
    215         entry->tagTable = drmHashCreate();
    216         drmHashInsert(drmHashTable, key, entry);
    217     } else {
    218         entry = value;
    219     }
    220     return entry;
    221 }
    222 
    223 /**
    224  * Compare two busid strings
    225  *
    226  * \param first
    227  * \param second
    228  *
    229  * \return 1 if matched.
    230  *
    231  * \internal
    232  * This function compares two bus ID strings.  It understands the older
    233  * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format.  In the format, o is
    234  * domain, b is bus, d is device, f is function.
    235  */
    236 static int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
    237 {
    238     /* First, check if the IDs are exactly the same */
    239     if (strcasecmp(id1, id2) == 0)
    240         return 1;
    241 
    242     /* Try to match old/new-style PCI bus IDs. */
    243     if (strncasecmp(id1, "pci", 3) == 0) {
    244         unsigned int o1, b1, d1, f1;
    245         unsigned int o2, b2, d2, f2;
    246         int ret;
    247 
    248         ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
    249         if (ret != 4) {
    250             o1 = 0;
    251             ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
    252             if (ret != 3)
    253                 return 0;
    254         }
    255 
    256         ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
    257         if (ret != 4) {
    258             o2 = 0;
    259             ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
    260             if (ret != 3)
    261                 return 0;
    262         }
    263 
    264         /* If domains aren't properly supported by the kernel interface,
    265          * just ignore them, which sucks less than picking a totally random
    266          * card with "open by name"
    267          */
    268         if (!pci_domain_ok)
    269             o1 = o2 = 0;
    270 
    271         if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
    272             return 0;
    273         else
    274             return 1;
    275     }
    276     return 0;
    277 }
    278 
    279 /**
    280  * Handles error checking for chown call.
    281  *
    282  * \param path to file.
    283  * \param id of the new owner.
    284  * \param id of the new group.
    285  *
    286  * \return zero if success or -1 if failure.
    287  *
    288  * \internal
    289  * Checks for failure. If failure was caused by signal call chown again.
    290  * If any other failure happened then it will output error mesage using
    291  * drmMsg() call.
    292  */
    293 #if !UDEV
    294 static int chown_check_return(const char *path, uid_t owner, gid_t group)
    295 {
    296         int rv;
    297 
    298         do {
    299             rv = chown(path, owner, group);
    300         } while (rv != 0 && errno == EINTR);
    301 
    302         if (rv == 0)
    303             return 0;
    304 
    305         drmMsg("Failed to change owner or group for file %s! %d: %s\n",
    306                path, errno, strerror(errno));
    307         return -1;
    308 }
    309 #endif
    310 
    311 /**
    312  * Open the DRM device, creating it if necessary.
    313  *
    314  * \param dev major and minor numbers of the device.
    315  * \param minor minor number of the device.
    316  *
    317  * \return a file descriptor on success, or a negative value on error.
    318  *
    319  * \internal
    320  * Assembles the device name from \p minor and opens it, creating the device
    321  * special file node with the major and minor numbers specified by \p dev and
    322  * parent directory if necessary and was called by root.
    323  */
    324 static int drmOpenDevice(dev_t dev, int minor, int type)
    325 {
    326     stat_t          st;
    327     const char      *dev_name;
    328     char            buf[64];
    329     int             fd;
    330     mode_t          devmode = DRM_DEV_MODE, serv_mode;
    331     gid_t           serv_group;
    332 #if !UDEV
    333     int             isroot  = !geteuid();
    334     uid_t           user    = DRM_DEV_UID;
    335     gid_t           group   = DRM_DEV_GID;
    336 #endif
    337 
    338     switch (type) {
    339     case DRM_NODE_PRIMARY:
    340         dev_name = DRM_DEV_NAME;
    341         break;
    342     case DRM_NODE_CONTROL:
    343         dev_name = DRM_CONTROL_DEV_NAME;
    344         break;
    345     case DRM_NODE_RENDER:
    346         dev_name = DRM_RENDER_DEV_NAME;
    347         break;
    348     default:
    349         return -EINVAL;
    350     };
    351 
    352     sprintf(buf, dev_name, DRM_DIR_NAME, minor);
    353     drmMsg("drmOpenDevice: node name is %s\n", buf);
    354 
    355     if (drm_server_info && drm_server_info->get_perms) {
    356         drm_server_info->get_perms(&serv_group, &serv_mode);
    357         devmode  = serv_mode ? serv_mode : DRM_DEV_MODE;
    358         devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
    359     }
    360 
    361 #if !UDEV
    362     if (stat(DRM_DIR_NAME, &st)) {
    363         if (!isroot)
    364             return DRM_ERR_NOT_ROOT;
    365         mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
    366         chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
    367         chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
    368     }
    369 
    370     /* Check if the device node exists and create it if necessary. */
    371     if (stat(buf, &st)) {
    372         if (!isroot)
    373             return DRM_ERR_NOT_ROOT;
    374         remove(buf);
    375         mknod(buf, S_IFCHR | devmode, dev);
    376     }
    377 
    378     if (drm_server_info && drm_server_info->get_perms) {
    379         group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
    380         chown_check_return(buf, user, group);
    381         chmod(buf, devmode);
    382     }
    383 #else
    384     /* if we modprobed then wait for udev */
    385     {
    386         int udev_count = 0;
    387 wait_for_udev:
    388         if (stat(DRM_DIR_NAME, &st)) {
    389             usleep(20);
    390             udev_count++;
    391 
    392             if (udev_count == 50)
    393                 return -1;
    394             goto wait_for_udev;
    395         }
    396 
    397         if (stat(buf, &st)) {
    398             usleep(20);
    399             udev_count++;
    400 
    401             if (udev_count == 50)
    402                 return -1;
    403             goto wait_for_udev;
    404         }
    405     }
    406 #endif
    407 
    408     fd = open(buf, O_RDWR, 0);
    409     drmMsg("drmOpenDevice: open result is %d, (%s)\n",
    410            fd, fd < 0 ? strerror(errno) : "OK");
    411     if (fd >= 0)
    412         return fd;
    413 
    414 #if !UDEV
    415     /* Check if the device node is not what we expect it to be, and recreate it
    416      * and try again if so.
    417      */
    418     if (st.st_rdev != dev) {
    419         if (!isroot)
    420             return DRM_ERR_NOT_ROOT;
    421         remove(buf);
    422         mknod(buf, S_IFCHR | devmode, dev);
    423         if (drm_server_info && drm_server_info->get_perms) {
    424             chown_check_return(buf, user, group);
    425             chmod(buf, devmode);
    426         }
    427     }
    428     fd = open(buf, O_RDWR, 0);
    429     drmMsg("drmOpenDevice: open result is %d, (%s)\n",
    430            fd, fd < 0 ? strerror(errno) : "OK");
    431     if (fd >= 0)
    432         return fd;
    433 
    434     drmMsg("drmOpenDevice: Open failed\n");
    435     remove(buf);
    436 #endif
    437     return -errno;
    438 }
    439 
    440 
    441 /**
    442  * Open the DRM device
    443  *
    444  * \param minor device minor number.
    445  * \param create allow to create the device if set.
    446  *
    447  * \return a file descriptor on success, or a negative value on error.
    448  *
    449  * \internal
    450  * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
    451  * name from \p minor and opens it.
    452  */
    453 static int drmOpenMinor(int minor, int create, int type)
    454 {
    455     int  fd;
    456     char buf[64];
    457     const char *dev_name;
    458 
    459     if (create)
    460         return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
    461 
    462     switch (type) {
    463     case DRM_NODE_PRIMARY:
    464         dev_name = DRM_DEV_NAME;
    465         break;
    466     case DRM_NODE_CONTROL:
    467         dev_name = DRM_CONTROL_DEV_NAME;
    468         break;
    469     case DRM_NODE_RENDER:
    470         dev_name = DRM_RENDER_DEV_NAME;
    471         break;
    472     default:
    473         return -EINVAL;
    474     };
    475 
    476     sprintf(buf, dev_name, DRM_DIR_NAME, minor);
    477     if ((fd = open(buf, O_RDWR, 0)) >= 0)
    478         return fd;
    479     return -errno;
    480 }
    481 
    482 
    483 /**
    484  * Determine whether the DRM kernel driver has been loaded.
    485  *
    486  * \return 1 if the DRM driver is loaded, 0 otherwise.
    487  *
    488  * \internal
    489  * Determine the presence of the kernel driver by attempting to open the 0
    490  * minor and get version information.  For backward compatibility with older
    491  * Linux implementations, /proc/dri is also checked.
    492  */
    493 int drmAvailable(void)
    494 {
    495     drmVersionPtr version;
    496     int           retval = 0;
    497     int           fd;
    498 
    499     if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
    500 #ifdef __linux__
    501         /* Try proc for backward Linux compatibility */
    502         if (!access("/proc/dri/0", R_OK))
    503             return 1;
    504 #endif
    505         return 0;
    506     }
    507 
    508     if ((version = drmGetVersion(fd))) {
    509         retval = 1;
    510         drmFreeVersion(version);
    511     }
    512     close(fd);
    513 
    514     return retval;
    515 }
    516 
    517 static int drmGetMinorBase(int type)
    518 {
    519     switch (type) {
    520     case DRM_NODE_PRIMARY:
    521         return 0;
    522     case DRM_NODE_CONTROL:
    523         return 64;
    524     case DRM_NODE_RENDER:
    525         return 128;
    526     default:
    527         return -1;
    528     };
    529 }
    530 
    531 static int drmGetMinorType(int minor)
    532 {
    533     int type = minor >> 6;
    534 
    535     if (minor < 0)
    536         return -1;
    537 
    538     switch (type) {
    539     case DRM_NODE_PRIMARY:
    540     case DRM_NODE_CONTROL:
    541     case DRM_NODE_RENDER:
    542         return type;
    543     default:
    544         return -1;
    545     }
    546 }
    547 
    548 static const char *drmGetMinorName(int type)
    549 {
    550     switch (type) {
    551     case DRM_NODE_PRIMARY:
    552         return DRM_PRIMARY_MINOR_NAME;
    553     case DRM_NODE_CONTROL:
    554         return DRM_CONTROL_MINOR_NAME;
    555     case DRM_NODE_RENDER:
    556         return DRM_RENDER_MINOR_NAME;
    557     default:
    558         return NULL;
    559     }
    560 }
    561 
    562 /**
    563  * Open the device by bus ID.
    564  *
    565  * \param busid bus ID.
    566  * \param type device node type.
    567  *
    568  * \return a file descriptor on success, or a negative value on error.
    569  *
    570  * \internal
    571  * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
    572  * comparing the device bus ID with the one supplied.
    573  *
    574  * \sa drmOpenMinor() and drmGetBusid().
    575  */
    576 static int drmOpenByBusid(const char *busid, int type)
    577 {
    578     int        i, pci_domain_ok = 1;
    579     int        fd;
    580     const char *buf;
    581     drmSetVersion sv;
    582     int        base = drmGetMinorBase(type);
    583 
    584     if (base < 0)
    585         return -1;
    586 
    587     drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
    588     for (i = base; i < base + DRM_MAX_MINOR; i++) {
    589         fd = drmOpenMinor(i, 1, type);
    590         drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
    591         if (fd >= 0) {
    592             /* We need to try for 1.4 first for proper PCI domain support
    593              * and if that fails, we know the kernel is busted
    594              */
    595             sv.drm_di_major = 1;
    596             sv.drm_di_minor = 4;
    597             sv.drm_dd_major = -1;        /* Don't care */
    598             sv.drm_dd_minor = -1;        /* Don't care */
    599             if (drmSetInterfaceVersion(fd, &sv)) {
    600 #ifndef __alpha__
    601                 pci_domain_ok = 0;
    602 #endif
    603                 sv.drm_di_major = 1;
    604                 sv.drm_di_minor = 1;
    605                 sv.drm_dd_major = -1;       /* Don't care */
    606                 sv.drm_dd_minor = -1;       /* Don't care */
    607                 drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
    608                 drmSetInterfaceVersion(fd, &sv);
    609             }
    610             buf = drmGetBusid(fd);
    611             drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
    612             if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
    613                 drmFreeBusid(buf);
    614                 return fd;
    615             }
    616             if (buf)
    617                 drmFreeBusid(buf);
    618             close(fd);
    619         }
    620     }
    621     return -1;
    622 }
    623 
    624 
    625 /**
    626  * Open the device by name.
    627  *
    628  * \param name driver name.
    629  * \param type the device node type.
    630  *
    631  * \return a file descriptor on success, or a negative value on error.
    632  *
    633  * \internal
    634  * This function opens the first minor number that matches the driver name and
    635  * isn't already in use.  If it's in use it then it will already have a bus ID
    636  * assigned.
    637  *
    638  * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
    639  */
    640 static int drmOpenByName(const char *name, int type)
    641 {
    642     int           i;
    643     int           fd;
    644     drmVersionPtr version;
    645     char *        id;
    646     int           base = drmGetMinorBase(type);
    647 
    648     if (base < 0)
    649         return -1;
    650 
    651     /*
    652      * Open the first minor number that matches the driver name and isn't
    653      * already in use.  If it's in use it will have a busid assigned already.
    654      */
    655     for (i = base; i < base + DRM_MAX_MINOR; i++) {
    656         if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
    657             if ((version = drmGetVersion(fd))) {
    658                 if (!strcmp(version->name, name)) {
    659                     drmFreeVersion(version);
    660                     id = drmGetBusid(fd);
    661                     drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
    662                     if (!id || !*id) {
    663                         if (id)
    664                             drmFreeBusid(id);
    665                         return fd;
    666                     } else {
    667                         drmFreeBusid(id);
    668                     }
    669                 } else {
    670                     drmFreeVersion(version);
    671                 }
    672             }
    673             close(fd);
    674         }
    675     }
    676 
    677 #ifdef __linux__
    678     /* Backward-compatibility /proc support */
    679     for (i = 0; i < 8; i++) {
    680         char proc_name[64], buf[512];
    681         char *driver, *pt, *devstring;
    682         int  retcode;
    683 
    684         sprintf(proc_name, "/proc/dri/%d/name", i);
    685         if ((fd = open(proc_name, 0, 0)) >= 0) {
    686             retcode = read(fd, buf, sizeof(buf)-1);
    687             close(fd);
    688             if (retcode) {
    689                 buf[retcode-1] = '\0';
    690                 for (driver = pt = buf; *pt && *pt != ' '; ++pt)
    691                     ;
    692                 if (*pt) { /* Device is next */
    693                     *pt = '\0';
    694                     if (!strcmp(driver, name)) { /* Match */
    695                         for (devstring = ++pt; *pt && *pt != ' '; ++pt)
    696                             ;
    697                         if (*pt) { /* Found busid */
    698                             return drmOpenByBusid(++pt, type);
    699                         } else { /* No busid */
    700                             return drmOpenDevice(strtol(devstring, NULL, 0),i, type);
    701                         }
    702                     }
    703                 }
    704             }
    705         }
    706     }
    707 #endif
    708 
    709     return -1;
    710 }
    711 
    712 
    713 /**
    714  * Open the DRM device.
    715  *
    716  * Looks up the specified name and bus ID, and opens the device found.  The
    717  * entry in /dev/dri is created if necessary and if called by root.
    718  *
    719  * \param name driver name. Not referenced if bus ID is supplied.
    720  * \param busid bus ID. Zero if not known.
    721  *
    722  * \return a file descriptor on success, or a negative value on error.
    723  *
    724  * \internal
    725  * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
    726  * otherwise.
    727  */
    728 int drmOpen(const char *name, const char *busid)
    729 {
    730     return drmOpenWithType(name, busid, DRM_NODE_PRIMARY);
    731 }
    732 
    733 /**
    734  * Open the DRM device with specified type.
    735  *
    736  * Looks up the specified name and bus ID, and opens the device found.  The
    737  * entry in /dev/dri is created if necessary and if called by root.
    738  *
    739  * \param name driver name. Not referenced if bus ID is supplied.
    740  * \param busid bus ID. Zero if not known.
    741  * \param type the device node type to open, PRIMARY, CONTROL or RENDER
    742  *
    743  * \return a file descriptor on success, or a negative value on error.
    744  *
    745  * \internal
    746  * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
    747  * otherwise.
    748  */
    749 int drmOpenWithType(const char *name, const char *busid, int type)
    750 {
    751     if (name != NULL && drm_server_info &&
    752         drm_server_info->load_module && !drmAvailable()) {
    753         /* try to load the kernel module */
    754         if (!drm_server_info->load_module(name)) {
    755             drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
    756             return -1;
    757         }
    758     }
    759 
    760     if (busid) {
    761         int fd = drmOpenByBusid(busid, type);
    762         if (fd >= 0)
    763             return fd;
    764     }
    765 
    766     if (name)
    767         return drmOpenByName(name, type);
    768 
    769     return -1;
    770 }
    771 
    772 int drmOpenControl(int minor)
    773 {
    774     return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
    775 }
    776 
    777 int drmOpenRender(int minor)
    778 {
    779     return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
    780 }
    781 
    782 /**
    783  * Free the version information returned by drmGetVersion().
    784  *
    785  * \param v pointer to the version information.
    786  *
    787  * \internal
    788  * It frees the memory pointed by \p %v as well as all the non-null strings
    789  * pointers in it.
    790  */
    791 void drmFreeVersion(drmVersionPtr v)
    792 {
    793     if (!v)
    794         return;
    795     drmFree(v->name);
    796     drmFree(v->date);
    797     drmFree(v->desc);
    798     drmFree(v);
    799 }
    800 
    801 
    802 /**
    803  * Free the non-public version information returned by the kernel.
    804  *
    805  * \param v pointer to the version information.
    806  *
    807  * \internal
    808  * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
    809  * the non-null strings pointers in it.
    810  */
    811 static void drmFreeKernelVersion(drm_version_t *v)
    812 {
    813     if (!v)
    814         return;
    815     drmFree(v->name);
    816     drmFree(v->date);
    817     drmFree(v->desc);
    818     drmFree(v);
    819 }
    820 
    821 
    822 /**
    823  * Copy version information.
    824  *
    825  * \param d destination pointer.
    826  * \param s source pointer.
    827  *
    828  * \internal
    829  * Used by drmGetVersion() to translate the information returned by the ioctl
    830  * interface in a private structure into the public structure counterpart.
    831  */
    832 static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
    833 {
    834     d->version_major      = s->version_major;
    835     d->version_minor      = s->version_minor;
    836     d->version_patchlevel = s->version_patchlevel;
    837     d->name_len           = s->name_len;
    838     d->name               = strdup(s->name);
    839     d->date_len           = s->date_len;
    840     d->date               = strdup(s->date);
    841     d->desc_len           = s->desc_len;
    842     d->desc               = strdup(s->desc);
    843 }
    844 
    845 
    846 /**
    847  * Query the driver version information.
    848  *
    849  * \param fd file descriptor.
    850  *
    851  * \return pointer to a drmVersion structure which should be freed with
    852  * drmFreeVersion().
    853  *
    854  * \note Similar information is available via /proc/dri.
    855  *
    856  * \internal
    857  * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
    858  * first with zeros to get the string lengths, and then the actually strings.
    859  * It also null-terminates them since they might not be already.
    860  */
    861 drmVersionPtr drmGetVersion(int fd)
    862 {
    863     drmVersionPtr retval;
    864     drm_version_t *version = drmMalloc(sizeof(*version));
    865 
    866     if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
    867         drmFreeKernelVersion(version);
    868         return NULL;
    869     }
    870 
    871     if (version->name_len)
    872         version->name    = drmMalloc(version->name_len + 1);
    873     if (version->date_len)
    874         version->date    = drmMalloc(version->date_len + 1);
    875     if (version->desc_len)
    876         version->desc    = drmMalloc(version->desc_len + 1);
    877 
    878     if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
    879         drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
    880         drmFreeKernelVersion(version);
    881         return NULL;
    882     }
    883 
    884     /* The results might not be null-terminated strings, so terminate them. */
    885     if (version->name_len) version->name[version->name_len] = '\0';
    886     if (version->date_len) version->date[version->date_len] = '\0';
    887     if (version->desc_len) version->desc[version->desc_len] = '\0';
    888 
    889     retval = drmMalloc(sizeof(*retval));
    890     drmCopyVersion(retval, version);
    891     drmFreeKernelVersion(version);
    892     return retval;
    893 }
    894 
    895 
    896 /**
    897  * Get version information for the DRM user space library.
    898  *
    899  * This version number is driver independent.
    900  *
    901  * \param fd file descriptor.
    902  *
    903  * \return version information.
    904  *
    905  * \internal
    906  * This function allocates and fills a drm_version structure with a hard coded
    907  * version number.
    908  */
    909 drmVersionPtr drmGetLibVersion(int fd)
    910 {
    911     drm_version_t *version = drmMalloc(sizeof(*version));
    912 
    913     /* Version history:
    914      *   NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
    915      *   revision 1.0.x = original DRM interface with no drmGetLibVersion
    916      *                    entry point and many drm<Device> extensions
    917      *   revision 1.1.x = added drmCommand entry points for device extensions
    918      *                    added drmGetLibVersion to identify libdrm.a version
    919      *   revision 1.2.x = added drmSetInterfaceVersion
    920      *                    modified drmOpen to handle both busid and name
    921      *   revision 1.3.x = added server + memory manager
    922      */
    923     version->version_major      = 1;
    924     version->version_minor      = 3;
    925     version->version_patchlevel = 0;
    926 
    927     return (drmVersionPtr)version;
    928 }
    929 
    930 int drmGetCap(int fd, uint64_t capability, uint64_t *value)
    931 {
    932     struct drm_get_cap cap;
    933     int ret;
    934 
    935     memclear(cap);
    936     cap.capability = capability;
    937 
    938     ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
    939     if (ret)
    940         return ret;
    941 
    942     *value = cap.value;
    943     return 0;
    944 }
    945 
    946 int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
    947 {
    948     struct drm_set_client_cap cap;
    949 
    950     memclear(cap);
    951     cap.capability = capability;
    952     cap.value = value;
    953 
    954     return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
    955 }
    956 
    957 /**
    958  * Free the bus ID information.
    959  *
    960  * \param busid bus ID information string as given by drmGetBusid().
    961  *
    962  * \internal
    963  * This function is just frees the memory pointed by \p busid.
    964  */
    965 void drmFreeBusid(const char *busid)
    966 {
    967     drmFree((void *)busid);
    968 }
    969 
    970 
    971 /**
    972  * Get the bus ID of the device.
    973  *
    974  * \param fd file descriptor.
    975  *
    976  * \return bus ID string.
    977  *
    978  * \internal
    979  * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
    980  * get the string length and data, passing the arguments in a drm_unique
    981  * structure.
    982  */
    983 char *drmGetBusid(int fd)
    984 {
    985     drm_unique_t u;
    986 
    987     memclear(u);
    988 
    989     if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
    990         return NULL;
    991     u.unique = drmMalloc(u.unique_len + 1);
    992     if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) {
    993         drmFree(u.unique);
    994         return NULL;
    995     }
    996     u.unique[u.unique_len] = '\0';
    997 
    998     return u.unique;
    999 }
   1000 
   1001 
   1002 /**
   1003  * Set the bus ID of the device.
   1004  *
   1005  * \param fd file descriptor.
   1006  * \param busid bus ID string.
   1007  *
   1008  * \return zero on success, negative on failure.
   1009  *
   1010  * \internal
   1011  * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
   1012  * the arguments in a drm_unique structure.
   1013  */
   1014 int drmSetBusid(int fd, const char *busid)
   1015 {
   1016     drm_unique_t u;
   1017 
   1018     memclear(u);
   1019     u.unique     = (char *)busid;
   1020     u.unique_len = strlen(busid);
   1021 
   1022     if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
   1023         return -errno;
   1024     }
   1025     return 0;
   1026 }
   1027 
   1028 int drmGetMagic(int fd, drm_magic_t * magic)
   1029 {
   1030     drm_auth_t auth;
   1031 
   1032     memclear(auth);
   1033 
   1034     *magic = 0;
   1035     if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
   1036         return -errno;
   1037     *magic = auth.magic;
   1038     return 0;
   1039 }
   1040 
   1041 int drmAuthMagic(int fd, drm_magic_t magic)
   1042 {
   1043     drm_auth_t auth;
   1044 
   1045     memclear(auth);
   1046     auth.magic = magic;
   1047     if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
   1048         return -errno;
   1049     return 0;
   1050 }
   1051 
   1052 /**
   1053  * Specifies a range of memory that is available for mapping by a
   1054  * non-root process.
   1055  *
   1056  * \param fd file descriptor.
   1057  * \param offset usually the physical address. The actual meaning depends of
   1058  * the \p type parameter. See below.
   1059  * \param size of the memory in bytes.
   1060  * \param type type of the memory to be mapped.
   1061  * \param flags combination of several flags to modify the function actions.
   1062  * \param handle will be set to a value that may be used as the offset
   1063  * parameter for mmap().
   1064  *
   1065  * \return zero on success or a negative value on error.
   1066  *
   1067  * \par Mapping the frame buffer
   1068  * For the frame buffer
   1069  * - \p offset will be the physical address of the start of the frame buffer,
   1070  * - \p size will be the size of the frame buffer in bytes, and
   1071  * - \p type will be DRM_FRAME_BUFFER.
   1072  *
   1073  * \par
   1074  * The area mapped will be uncached. If MTRR support is available in the
   1075  * kernel, the frame buffer area will be set to write combining.
   1076  *
   1077  * \par Mapping the MMIO register area
   1078  * For the MMIO register area,
   1079  * - \p offset will be the physical address of the start of the register area,
   1080  * - \p size will be the size of the register area bytes, and
   1081  * - \p type will be DRM_REGISTERS.
   1082  * \par
   1083  * The area mapped will be uncached.
   1084  *
   1085  * \par Mapping the SAREA
   1086  * For the SAREA,
   1087  * - \p offset will be ignored and should be set to zero,
   1088  * - \p size will be the desired size of the SAREA in bytes,
   1089  * - \p type will be DRM_SHM.
   1090  *
   1091  * \par
   1092  * A shared memory area of the requested size will be created and locked in
   1093  * kernel memory. This area may be mapped into client-space by using the handle
   1094  * returned.
   1095  *
   1096  * \note May only be called by root.
   1097  *
   1098  * \internal
   1099  * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
   1100  * the arguments in a drm_map structure.
   1101  */
   1102 int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
   1103               drmMapFlags flags, drm_handle_t *handle)
   1104 {
   1105     drm_map_t map;
   1106 
   1107     memclear(map);
   1108     map.offset  = offset;
   1109     map.size    = size;
   1110     map.type    = type;
   1111     map.flags   = flags;
   1112     if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
   1113         return -errno;
   1114     if (handle)
   1115         *handle = (drm_handle_t)(uintptr_t)map.handle;
   1116     return 0;
   1117 }
   1118 
   1119 int drmRmMap(int fd, drm_handle_t handle)
   1120 {
   1121     drm_map_t map;
   1122 
   1123     memclear(map);
   1124     map.handle = (void *)(uintptr_t)handle;
   1125 
   1126     if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
   1127         return -errno;
   1128     return 0;
   1129 }
   1130 
   1131 /**
   1132  * Make buffers available for DMA transfers.
   1133  *
   1134  * \param fd file descriptor.
   1135  * \param count number of buffers.
   1136  * \param size size of each buffer.
   1137  * \param flags buffer allocation flags.
   1138  * \param agp_offset offset in the AGP aperture
   1139  *
   1140  * \return number of buffers allocated, negative on error.
   1141  *
   1142  * \internal
   1143  * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
   1144  *
   1145  * \sa drm_buf_desc.
   1146  */
   1147 int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
   1148                int agp_offset)
   1149 {
   1150     drm_buf_desc_t request;
   1151 
   1152     memclear(request);
   1153     request.count     = count;
   1154     request.size      = size;
   1155     request.flags     = flags;
   1156     request.agp_start = agp_offset;
   1157 
   1158     if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
   1159         return -errno;
   1160     return request.count;
   1161 }
   1162 
   1163 int drmMarkBufs(int fd, double low, double high)
   1164 {
   1165     drm_buf_info_t info;
   1166     int            i;
   1167 
   1168     memclear(info);
   1169 
   1170     if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
   1171         return -EINVAL;
   1172 
   1173     if (!info.count)
   1174         return -EINVAL;
   1175 
   1176     if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
   1177         return -ENOMEM;
   1178 
   1179     if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
   1180         int retval = -errno;
   1181         drmFree(info.list);
   1182         return retval;
   1183     }
   1184 
   1185     for (i = 0; i < info.count; i++) {
   1186         info.list[i].low_mark  = low  * info.list[i].count;
   1187         info.list[i].high_mark = high * info.list[i].count;
   1188         if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
   1189             int retval = -errno;
   1190             drmFree(info.list);
   1191             return retval;
   1192         }
   1193     }
   1194     drmFree(info.list);
   1195 
   1196     return 0;
   1197 }
   1198 
   1199 /**
   1200  * Free buffers.
   1201  *
   1202  * \param fd file descriptor.
   1203  * \param count number of buffers to free.
   1204  * \param list list of buffers to be freed.
   1205  *
   1206  * \return zero on success, or a negative value on failure.
   1207  *
   1208  * \note This function is primarily used for debugging.
   1209  *
   1210  * \internal
   1211  * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
   1212  * the arguments in a drm_buf_free structure.
   1213  */
   1214 int drmFreeBufs(int fd, int count, int *list)
   1215 {
   1216     drm_buf_free_t request;
   1217 
   1218     memclear(request);
   1219     request.count = count;
   1220     request.list  = list;
   1221     if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
   1222         return -errno;
   1223     return 0;
   1224 }
   1225 
   1226 
   1227 /**
   1228  * Close the device.
   1229  *
   1230  * \param fd file descriptor.
   1231  *
   1232  * \internal
   1233  * This function closes the file descriptor.
   1234  */
   1235 int drmClose(int fd)
   1236 {
   1237     unsigned long key    = drmGetKeyFromFd(fd);
   1238     drmHashEntry  *entry = drmGetEntry(fd);
   1239 
   1240     drmHashDestroy(entry->tagTable);
   1241     entry->fd       = 0;
   1242     entry->f        = NULL;
   1243     entry->tagTable = NULL;
   1244 
   1245     drmHashDelete(drmHashTable, key);
   1246     drmFree(entry);
   1247 
   1248     return close(fd);
   1249 }
   1250 
   1251 
   1252 /**
   1253  * Map a region of memory.
   1254  *
   1255  * \param fd file descriptor.
   1256  * \param handle handle returned by drmAddMap().
   1257  * \param size size in bytes. Must match the size used by drmAddMap().
   1258  * \param address will contain the user-space virtual address where the mapping
   1259  * begins.
   1260  *
   1261  * \return zero on success, or a negative value on failure.
   1262  *
   1263  * \internal
   1264  * This function is a wrapper for mmap().
   1265  */
   1266 int drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address)
   1267 {
   1268     static unsigned long pagesize_mask = 0;
   1269 
   1270     if (fd < 0)
   1271         return -EINVAL;
   1272 
   1273     if (!pagesize_mask)
   1274         pagesize_mask = getpagesize() - 1;
   1275 
   1276     size = (size + pagesize_mask) & ~pagesize_mask;
   1277 
   1278     *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
   1279     if (*address == MAP_FAILED)
   1280         return -errno;
   1281     return 0;
   1282 }
   1283 
   1284 
   1285 /**
   1286  * Unmap mappings obtained with drmMap().
   1287  *
   1288  * \param address address as given by drmMap().
   1289  * \param size size in bytes. Must match the size used by drmMap().
   1290  *
   1291  * \return zero on success, or a negative value on failure.
   1292  *
   1293  * \internal
   1294  * This function is a wrapper for munmap().
   1295  */
   1296 int drmUnmap(drmAddress address, drmSize size)
   1297 {
   1298     return drm_munmap(address, size);
   1299 }
   1300 
   1301 drmBufInfoPtr drmGetBufInfo(int fd)
   1302 {
   1303     drm_buf_info_t info;
   1304     drmBufInfoPtr  retval;
   1305     int            i;
   1306 
   1307     memclear(info);
   1308 
   1309     if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
   1310         return NULL;
   1311 
   1312     if (info.count) {
   1313         if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
   1314             return NULL;
   1315 
   1316         if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
   1317             drmFree(info.list);
   1318             return NULL;
   1319         }
   1320 
   1321         retval = drmMalloc(sizeof(*retval));
   1322         retval->count = info.count;
   1323         retval->list  = drmMalloc(info.count * sizeof(*retval->list));
   1324         for (i = 0; i < info.count; i++) {
   1325             retval->list[i].count     = info.list[i].count;
   1326             retval->list[i].size      = info.list[i].size;
   1327             retval->list[i].low_mark  = info.list[i].low_mark;
   1328             retval->list[i].high_mark = info.list[i].high_mark;
   1329         }
   1330         drmFree(info.list);
   1331         return retval;
   1332     }
   1333     return NULL;
   1334 }
   1335 
   1336 /**
   1337  * Map all DMA buffers into client-virtual space.
   1338  *
   1339  * \param fd file descriptor.
   1340  *
   1341  * \return a pointer to a ::drmBufMap structure.
   1342  *
   1343  * \note The client may not use these buffers until obtaining buffer indices
   1344  * with drmDMA().
   1345  *
   1346  * \internal
   1347  * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
   1348  * information about the buffers in a drm_buf_map structure into the
   1349  * client-visible data structures.
   1350  */
   1351 drmBufMapPtr drmMapBufs(int fd)
   1352 {
   1353     drm_buf_map_t bufs;
   1354     drmBufMapPtr  retval;
   1355     int           i;
   1356 
   1357     memclear(bufs);
   1358     if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
   1359         return NULL;
   1360 
   1361     if (!bufs.count)
   1362         return NULL;
   1363 
   1364     if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
   1365         return NULL;
   1366 
   1367     if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
   1368         drmFree(bufs.list);
   1369         return NULL;
   1370     }
   1371 
   1372     retval = drmMalloc(sizeof(*retval));
   1373     retval->count = bufs.count;
   1374     retval->list  = drmMalloc(bufs.count * sizeof(*retval->list));
   1375     for (i = 0; i < bufs.count; i++) {
   1376         retval->list[i].idx     = bufs.list[i].idx;
   1377         retval->list[i].total   = bufs.list[i].total;
   1378         retval->list[i].used    = 0;
   1379         retval->list[i].address = bufs.list[i].address;
   1380     }
   1381 
   1382     drmFree(bufs.list);
   1383     return retval;
   1384 }
   1385 
   1386 
   1387 /**
   1388  * Unmap buffers allocated with drmMapBufs().
   1389  *
   1390  * \return zero on success, or negative value on failure.
   1391  *
   1392  * \internal
   1393  * Calls munmap() for every buffer stored in \p bufs and frees the
   1394  * memory allocated by drmMapBufs().
   1395  */
   1396 int drmUnmapBufs(drmBufMapPtr bufs)
   1397 {
   1398     int i;
   1399 
   1400     for (i = 0; i < bufs->count; i++) {
   1401         drm_munmap(bufs->list[i].address, bufs->list[i].total);
   1402     }
   1403 
   1404     drmFree(bufs->list);
   1405     drmFree(bufs);
   1406     return 0;
   1407 }
   1408 
   1409 
   1410 #define DRM_DMA_RETRY  16
   1411 
   1412 /**
   1413  * Reserve DMA buffers.
   1414  *
   1415  * \param fd file descriptor.
   1416  * \param request
   1417  *
   1418  * \return zero on success, or a negative value on failure.
   1419  *
   1420  * \internal
   1421  * Assemble the arguments into a drm_dma structure and keeps issuing the
   1422  * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
   1423  */
   1424 int drmDMA(int fd, drmDMAReqPtr request)
   1425 {
   1426     drm_dma_t dma;
   1427     int ret, i = 0;
   1428 
   1429     dma.context         = request->context;
   1430     dma.send_count      = request->send_count;
   1431     dma.send_indices    = request->send_list;
   1432     dma.send_sizes      = request->send_sizes;
   1433     dma.flags           = request->flags;
   1434     dma.request_count   = request->request_count;
   1435     dma.request_size    = request->request_size;
   1436     dma.request_indices = request->request_list;
   1437     dma.request_sizes   = request->request_sizes;
   1438     dma.granted_count   = 0;
   1439 
   1440     do {
   1441         ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
   1442     } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
   1443 
   1444     if ( ret == 0 ) {
   1445         request->granted_count = dma.granted_count;
   1446         return 0;
   1447     } else {
   1448         return -errno;
   1449     }
   1450 }
   1451 
   1452 
   1453 /**
   1454  * Obtain heavyweight hardware lock.
   1455  *
   1456  * \param fd file descriptor.
   1457  * \param context context.
   1458  * \param flags flags that determine the sate of the hardware when the function
   1459  * returns.
   1460  *
   1461  * \return always zero.
   1462  *
   1463  * \internal
   1464  * This function translates the arguments into a drm_lock structure and issue
   1465  * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
   1466  */
   1467 int drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
   1468 {
   1469     drm_lock_t lock;
   1470 
   1471     memclear(lock);
   1472     lock.context = context;
   1473     lock.flags   = 0;
   1474     if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
   1475     if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
   1476     if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
   1477     if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
   1478     if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
   1479     if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
   1480 
   1481     while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock))
   1482         ;
   1483     return 0;
   1484 }
   1485 
   1486 /**
   1487  * Release the hardware lock.
   1488  *
   1489  * \param fd file descriptor.
   1490  * \param context context.
   1491  *
   1492  * \return zero on success, or a negative value on failure.
   1493  *
   1494  * \internal
   1495  * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
   1496  * argument in a drm_lock structure.
   1497  */
   1498 int drmUnlock(int fd, drm_context_t context)
   1499 {
   1500     drm_lock_t lock;
   1501 
   1502     memclear(lock);
   1503     lock.context = context;
   1504     return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
   1505 }
   1506 
   1507 drm_context_t *drmGetReservedContextList(int fd, int *count)
   1508 {
   1509     drm_ctx_res_t res;
   1510     drm_ctx_t     *list;
   1511     drm_context_t * retval;
   1512     int           i;
   1513 
   1514     memclear(res);
   1515     if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
   1516         return NULL;
   1517 
   1518     if (!res.count)
   1519         return NULL;
   1520 
   1521     if (!(list   = drmMalloc(res.count * sizeof(*list))))
   1522         return NULL;
   1523     if (!(retval = drmMalloc(res.count * sizeof(*retval))))
   1524         goto err_free_list;
   1525 
   1526     res.contexts = list;
   1527     if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
   1528         goto err_free_context;
   1529 
   1530     for (i = 0; i < res.count; i++)
   1531         retval[i] = list[i].handle;
   1532     drmFree(list);
   1533 
   1534     *count = res.count;
   1535     return retval;
   1536 
   1537 err_free_list:
   1538     drmFree(list);
   1539 err_free_context:
   1540     drmFree(retval);
   1541     return NULL;
   1542 }
   1543 
   1544 void drmFreeReservedContextList(drm_context_t *pt)
   1545 {
   1546     drmFree(pt);
   1547 }
   1548 
   1549 /**
   1550  * Create context.
   1551  *
   1552  * Used by the X server during GLXContext initialization. This causes
   1553  * per-context kernel-level resources to be allocated.
   1554  *
   1555  * \param fd file descriptor.
   1556  * \param handle is set on success. To be used by the client when requesting DMA
   1557  * dispatch with drmDMA().
   1558  *
   1559  * \return zero on success, or a negative value on failure.
   1560  *
   1561  * \note May only be called by root.
   1562  *
   1563  * \internal
   1564  * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
   1565  * argument in a drm_ctx structure.
   1566  */
   1567 int drmCreateContext(int fd, drm_context_t *handle)
   1568 {
   1569     drm_ctx_t ctx;
   1570 
   1571     memclear(ctx);
   1572     if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
   1573         return -errno;
   1574     *handle = ctx.handle;
   1575     return 0;
   1576 }
   1577 
   1578 int drmSwitchToContext(int fd, drm_context_t context)
   1579 {
   1580     drm_ctx_t ctx;
   1581 
   1582     memclear(ctx);
   1583     ctx.handle = context;
   1584     if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
   1585         return -errno;
   1586     return 0;
   1587 }
   1588 
   1589 int drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags)
   1590 {
   1591     drm_ctx_t ctx;
   1592 
   1593     /*
   1594      * Context preserving means that no context switches are done between DMA
   1595      * buffers from one context and the next.  This is suitable for use in the
   1596      * X server (which promises to maintain hardware context), or in the
   1597      * client-side library when buffers are swapped on behalf of two threads.
   1598      */
   1599     memclear(ctx);
   1600     ctx.handle = context;
   1601     if (flags & DRM_CONTEXT_PRESERVED)
   1602         ctx.flags |= _DRM_CONTEXT_PRESERVED;
   1603     if (flags & DRM_CONTEXT_2DONLY)
   1604         ctx.flags |= _DRM_CONTEXT_2DONLY;
   1605     if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
   1606         return -errno;
   1607     return 0;
   1608 }
   1609 
   1610 int drmGetContextFlags(int fd, drm_context_t context,
   1611                        drm_context_tFlagsPtr flags)
   1612 {
   1613     drm_ctx_t ctx;
   1614 
   1615     memclear(ctx);
   1616     ctx.handle = context;
   1617     if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
   1618         return -errno;
   1619     *flags = 0;
   1620     if (ctx.flags & _DRM_CONTEXT_PRESERVED)
   1621         *flags |= DRM_CONTEXT_PRESERVED;
   1622     if (ctx.flags & _DRM_CONTEXT_2DONLY)
   1623         *flags |= DRM_CONTEXT_2DONLY;
   1624     return 0;
   1625 }
   1626 
   1627 /**
   1628  * Destroy context.
   1629  *
   1630  * Free any kernel-level resources allocated with drmCreateContext() associated
   1631  * with the context.
   1632  *
   1633  * \param fd file descriptor.
   1634  * \param handle handle given by drmCreateContext().
   1635  *
   1636  * \return zero on success, or a negative value on failure.
   1637  *
   1638  * \note May only be called by root.
   1639  *
   1640  * \internal
   1641  * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
   1642  * argument in a drm_ctx structure.
   1643  */
   1644 int drmDestroyContext(int fd, drm_context_t handle)
   1645 {
   1646     drm_ctx_t ctx;
   1647 
   1648     memclear(ctx);
   1649     ctx.handle = handle;
   1650     if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
   1651         return -errno;
   1652     return 0;
   1653 }
   1654 
   1655 int drmCreateDrawable(int fd, drm_drawable_t *handle)
   1656 {
   1657     drm_draw_t draw;
   1658 
   1659     memclear(draw);
   1660     if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
   1661         return -errno;
   1662     *handle = draw.handle;
   1663     return 0;
   1664 }
   1665 
   1666 int drmDestroyDrawable(int fd, drm_drawable_t handle)
   1667 {
   1668     drm_draw_t draw;
   1669 
   1670     memclear(draw);
   1671     draw.handle = handle;
   1672     if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
   1673         return -errno;
   1674     return 0;
   1675 }
   1676 
   1677 int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
   1678                           drm_drawable_info_type_t type, unsigned int num,
   1679                           void *data)
   1680 {
   1681     drm_update_draw_t update;
   1682 
   1683     memclear(update);
   1684     update.handle = handle;
   1685     update.type = type;
   1686     update.num = num;
   1687     update.data = (unsigned long long)(unsigned long)data;
   1688 
   1689     if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
   1690         return -errno;
   1691 
   1692     return 0;
   1693 }
   1694 
   1695 int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence, uint64_t *ns)
   1696 {
   1697     struct drm_crtc_get_sequence get_seq;
   1698     int ret;
   1699 
   1700     memclear(get_seq);
   1701     get_seq.crtc_id = crtcId;
   1702     ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq);
   1703     if (ret)
   1704         return ret;
   1705 
   1706     if (sequence)
   1707         *sequence = get_seq.sequence;
   1708     if (ns)
   1709         *ns = get_seq.sequence_ns;
   1710     return 0;
   1711 }
   1712 
   1713 int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags, uint64_t sequence,
   1714                          uint64_t *sequence_queued, uint64_t user_data)
   1715 {
   1716     struct drm_crtc_queue_sequence queue_seq;
   1717     int ret;
   1718 
   1719     memclear(queue_seq);
   1720     queue_seq.crtc_id = crtcId;
   1721     queue_seq.flags = flags;
   1722     queue_seq.sequence = sequence;
   1723     queue_seq.user_data = user_data;
   1724 
   1725     ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq);
   1726     if (ret == 0 && sequence_queued)
   1727         *sequence_queued = queue_seq.sequence;
   1728 
   1729     return ret;
   1730 }
   1731 
   1732 /**
   1733  * Acquire the AGP device.
   1734  *
   1735  * Must be called before any of the other AGP related calls.
   1736  *
   1737  * \param fd file descriptor.
   1738  *
   1739  * \return zero on success, or a negative value on failure.
   1740  *
   1741  * \internal
   1742  * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
   1743  */
   1744 int drmAgpAcquire(int fd)
   1745 {
   1746     if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
   1747         return -errno;
   1748     return 0;
   1749 }
   1750 
   1751 
   1752 /**
   1753  * Release the AGP device.
   1754  *
   1755  * \param fd file descriptor.
   1756  *
   1757  * \return zero on success, or a negative value on failure.
   1758  *
   1759  * \internal
   1760  * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
   1761  */
   1762 int drmAgpRelease(int fd)
   1763 {
   1764     if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
   1765         return -errno;
   1766     return 0;
   1767 }
   1768 
   1769 
   1770 /**
   1771  * Set the AGP mode.
   1772  *
   1773  * \param fd file descriptor.
   1774  * \param mode AGP mode.
   1775  *
   1776  * \return zero on success, or a negative value on failure.
   1777  *
   1778  * \internal
   1779  * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
   1780  * argument in a drm_agp_mode structure.
   1781  */
   1782 int drmAgpEnable(int fd, unsigned long mode)
   1783 {
   1784     drm_agp_mode_t m;
   1785 
   1786     memclear(m);
   1787     m.mode = mode;
   1788     if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
   1789         return -errno;
   1790     return 0;
   1791 }
   1792 
   1793 
   1794 /**
   1795  * Allocate a chunk of AGP memory.
   1796  *
   1797  * \param fd file descriptor.
   1798  * \param size requested memory size in bytes. Will be rounded to page boundary.
   1799  * \param type type of memory to allocate.
   1800  * \param address if not zero, will be set to the physical address of the
   1801  * allocated memory.
   1802  * \param handle on success will be set to a handle of the allocated memory.
   1803  *
   1804  * \return zero on success, or a negative value on failure.
   1805  *
   1806  * \internal
   1807  * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
   1808  * arguments in a drm_agp_buffer structure.
   1809  */
   1810 int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
   1811                 unsigned long *address, drm_handle_t *handle)
   1812 {
   1813     drm_agp_buffer_t b;
   1814 
   1815     memclear(b);
   1816     *handle = DRM_AGP_NO_HANDLE;
   1817     b.size   = size;
   1818     b.type   = type;
   1819     if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
   1820         return -errno;
   1821     if (address != 0UL)
   1822         *address = b.physical;
   1823     *handle = b.handle;
   1824     return 0;
   1825 }
   1826 
   1827 
   1828 /**
   1829  * Free a chunk of AGP memory.
   1830  *
   1831  * \param fd file descriptor.
   1832  * \param handle handle to the allocated memory, as given by drmAgpAllocate().
   1833  *
   1834  * \return zero on success, or a negative value on failure.
   1835  *
   1836  * \internal
   1837  * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
   1838  * argument in a drm_agp_buffer structure.
   1839  */
   1840 int drmAgpFree(int fd, drm_handle_t handle)
   1841 {
   1842     drm_agp_buffer_t b;
   1843 
   1844     memclear(b);
   1845     b.handle = handle;
   1846     if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
   1847         return -errno;
   1848     return 0;
   1849 }
   1850 
   1851 
   1852 /**
   1853  * Bind a chunk of AGP memory.
   1854  *
   1855  * \param fd file descriptor.
   1856  * \param handle handle to the allocated memory, as given by drmAgpAllocate().
   1857  * \param offset offset in bytes. It will round to page boundary.
   1858  *
   1859  * \return zero on success, or a negative value on failure.
   1860  *
   1861  * \internal
   1862  * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
   1863  * argument in a drm_agp_binding structure.
   1864  */
   1865 int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
   1866 {
   1867     drm_agp_binding_t b;
   1868 
   1869     memclear(b);
   1870     b.handle = handle;
   1871     b.offset = offset;
   1872     if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
   1873         return -errno;
   1874     return 0;
   1875 }
   1876 
   1877 
   1878 /**
   1879  * Unbind a chunk of AGP memory.
   1880  *
   1881  * \param fd file descriptor.
   1882  * \param handle handle to the allocated memory, as given by drmAgpAllocate().
   1883  *
   1884  * \return zero on success, or a negative value on failure.
   1885  *
   1886  * \internal
   1887  * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
   1888  * the argument in a drm_agp_binding structure.
   1889  */
   1890 int drmAgpUnbind(int fd, drm_handle_t handle)
   1891 {
   1892     drm_agp_binding_t b;
   1893 
   1894     memclear(b);
   1895     b.handle = handle;
   1896     if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
   1897         return -errno;
   1898     return 0;
   1899 }
   1900 
   1901 
   1902 /**
   1903  * Get AGP driver major version number.
   1904  *
   1905  * \param fd file descriptor.
   1906  *
   1907  * \return major version number on success, or a negative value on failure..
   1908  *
   1909  * \internal
   1910  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
   1911  * necessary information in a drm_agp_info structure.
   1912  */
   1913 int drmAgpVersionMajor(int fd)
   1914 {
   1915     drm_agp_info_t i;
   1916 
   1917     memclear(i);
   1918 
   1919     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
   1920         return -errno;
   1921     return i.agp_version_major;
   1922 }
   1923 
   1924 
   1925 /**
   1926  * Get AGP driver minor version number.
   1927  *
   1928  * \param fd file descriptor.
   1929  *
   1930  * \return minor version number on success, or a negative value on failure.
   1931  *
   1932  * \internal
   1933  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
   1934  * necessary information in a drm_agp_info structure.
   1935  */
   1936 int drmAgpVersionMinor(int fd)
   1937 {
   1938     drm_agp_info_t i;
   1939 
   1940     memclear(i);
   1941 
   1942     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
   1943         return -errno;
   1944     return i.agp_version_minor;
   1945 }
   1946 
   1947 
   1948 /**
   1949  * Get AGP mode.
   1950  *
   1951  * \param fd file descriptor.
   1952  *
   1953  * \return mode on success, or zero on failure.
   1954  *
   1955  * \internal
   1956  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
   1957  * necessary information in a drm_agp_info structure.
   1958  */
   1959 unsigned long drmAgpGetMode(int fd)
   1960 {
   1961     drm_agp_info_t i;
   1962 
   1963     memclear(i);
   1964 
   1965     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
   1966         return 0;
   1967     return i.mode;
   1968 }
   1969 
   1970 
   1971 /**
   1972  * Get AGP aperture base.
   1973  *
   1974  * \param fd file descriptor.
   1975  *
   1976  * \return aperture base on success, zero on failure.
   1977  *
   1978  * \internal
   1979  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
   1980  * necessary information in a drm_agp_info structure.
   1981  */
   1982 unsigned long drmAgpBase(int fd)
   1983 {
   1984     drm_agp_info_t i;
   1985 
   1986     memclear(i);
   1987 
   1988     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
   1989         return 0;
   1990     return i.aperture_base;
   1991 }
   1992 
   1993 
   1994 /**
   1995  * Get AGP aperture size.
   1996  *
   1997  * \param fd file descriptor.
   1998  *
   1999  * \return aperture size on success, zero on failure.
   2000  *
   2001  * \internal
   2002  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
   2003  * necessary information in a drm_agp_info structure.
   2004  */
   2005 unsigned long drmAgpSize(int fd)
   2006 {
   2007     drm_agp_info_t i;
   2008 
   2009     memclear(i);
   2010 
   2011     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
   2012         return 0;
   2013     return i.aperture_size;
   2014 }
   2015 
   2016 
   2017 /**
   2018  * Get used AGP memory.
   2019  *
   2020  * \param fd file descriptor.
   2021  *
   2022  * \return memory used on success, or zero on failure.
   2023  *
   2024  * \internal
   2025  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
   2026  * necessary information in a drm_agp_info structure.
   2027  */
   2028 unsigned long drmAgpMemoryUsed(int fd)
   2029 {
   2030     drm_agp_info_t i;
   2031 
   2032     memclear(i);
   2033 
   2034     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
   2035         return 0;
   2036     return i.memory_used;
   2037 }
   2038 
   2039 
   2040 /**
   2041  * Get available AGP memory.
   2042  *
   2043  * \param fd file descriptor.
   2044  *
   2045  * \return memory available on success, or zero on failure.
   2046  *
   2047  * \internal
   2048  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
   2049  * necessary information in a drm_agp_info structure.
   2050  */
   2051 unsigned long drmAgpMemoryAvail(int fd)
   2052 {
   2053     drm_agp_info_t i;
   2054 
   2055     memclear(i);
   2056 
   2057     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
   2058         return 0;
   2059     return i.memory_allowed;
   2060 }
   2061 
   2062 
   2063 /**
   2064  * Get hardware vendor ID.
   2065  *
   2066  * \param fd file descriptor.
   2067  *
   2068  * \return vendor ID on success, or zero on failure.
   2069  *
   2070  * \internal
   2071  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
   2072  * necessary information in a drm_agp_info structure.
   2073  */
   2074 unsigned int drmAgpVendorId(int fd)
   2075 {
   2076     drm_agp_info_t i;
   2077 
   2078     memclear(i);
   2079 
   2080     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
   2081         return 0;
   2082     return i.id_vendor;
   2083 }
   2084 
   2085 
   2086 /**
   2087  * Get hardware device ID.
   2088  *
   2089  * \param fd file descriptor.
   2090  *
   2091  * \return zero on success, or zero on failure.
   2092  *
   2093  * \internal
   2094  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
   2095  * necessary information in a drm_agp_info structure.
   2096  */
   2097 unsigned int drmAgpDeviceId(int fd)
   2098 {
   2099     drm_agp_info_t i;
   2100 
   2101     memclear(i);
   2102 
   2103     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
   2104         return 0;
   2105     return i.id_device;
   2106 }
   2107 
   2108 int drmScatterGatherAlloc(int fd, unsigned long size, drm_handle_t *handle)
   2109 {
   2110     drm_scatter_gather_t sg;
   2111 
   2112     memclear(sg);
   2113 
   2114     *handle = 0;
   2115     sg.size   = size;
   2116     if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
   2117         return -errno;
   2118     *handle = sg.handle;
   2119     return 0;
   2120 }
   2121 
   2122 int drmScatterGatherFree(int fd, drm_handle_t handle)
   2123 {
   2124     drm_scatter_gather_t sg;
   2125 
   2126     memclear(sg);
   2127     sg.handle = handle;
   2128     if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
   2129         return -errno;
   2130     return 0;
   2131 }
   2132 
   2133 /**
   2134  * Wait for VBLANK.
   2135  *
   2136  * \param fd file descriptor.
   2137  * \param vbl pointer to a drmVBlank structure.
   2138  *
   2139  * \return zero on success, or a negative value on failure.
   2140  *
   2141  * \internal
   2142  * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
   2143  */
   2144 int drmWaitVBlank(int fd, drmVBlankPtr vbl)
   2145 {
   2146     struct timespec timeout, cur;
   2147     int ret;
   2148 
   2149     ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
   2150     if (ret < 0) {
   2151         fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno));
   2152         goto out;
   2153     }
   2154     timeout.tv_sec++;
   2155 
   2156     do {
   2157        ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
   2158        vbl->request.type &= ~DRM_VBLANK_RELATIVE;
   2159        if (ret && errno == EINTR) {
   2160            clock_gettime(CLOCK_MONOTONIC, &cur);
   2161            /* Timeout after 1s */
   2162            if (cur.tv_sec > timeout.tv_sec + 1 ||
   2163                (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
   2164                 timeout.tv_nsec)) {
   2165                    errno = EBUSY;
   2166                    ret = -1;
   2167                    break;
   2168            }
   2169        }
   2170     } while (ret && errno == EINTR);
   2171 
   2172 out:
   2173     return ret;
   2174 }
   2175 
   2176 int drmError(int err, const char *label)
   2177 {
   2178     switch (err) {
   2179     case DRM_ERR_NO_DEVICE:
   2180         fprintf(stderr, "%s: no device\n", label);
   2181         break;
   2182     case DRM_ERR_NO_ACCESS:
   2183         fprintf(stderr, "%s: no access\n", label);
   2184         break;
   2185     case DRM_ERR_NOT_ROOT:
   2186         fprintf(stderr, "%s: not root\n", label);
   2187         break;
   2188     case DRM_ERR_INVALID:
   2189         fprintf(stderr, "%s: invalid args\n", label);
   2190         break;
   2191     default:
   2192         if (err < 0)
   2193             err = -err;
   2194         fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
   2195         break;
   2196     }
   2197 
   2198     return 1;
   2199 }
   2200 
   2201 /**
   2202  * Install IRQ handler.
   2203  *
   2204  * \param fd file descriptor.
   2205  * \param irq IRQ number.
   2206  *
   2207  * \return zero on success, or a negative value on failure.
   2208  *
   2209  * \internal
   2210  * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
   2211  * argument in a drm_control structure.
   2212  */
   2213 int drmCtlInstHandler(int fd, int irq)
   2214 {
   2215     drm_control_t ctl;
   2216 
   2217     memclear(ctl);
   2218     ctl.func  = DRM_INST_HANDLER;
   2219     ctl.irq   = irq;
   2220     if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
   2221         return -errno;
   2222     return 0;
   2223 }
   2224 
   2225 
   2226 /**
   2227  * Uninstall IRQ handler.
   2228  *
   2229  * \param fd file descriptor.
   2230  *
   2231  * \return zero on success, or a negative value on failure.
   2232  *
   2233  * \internal
   2234  * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
   2235  * argument in a drm_control structure.
   2236  */
   2237 int drmCtlUninstHandler(int fd)
   2238 {
   2239     drm_control_t ctl;
   2240 
   2241     memclear(ctl);
   2242     ctl.func  = DRM_UNINST_HANDLER;
   2243     ctl.irq   = 0;
   2244     if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
   2245         return -errno;
   2246     return 0;
   2247 }
   2248 
   2249 int drmFinish(int fd, int context, drmLockFlags flags)
   2250 {
   2251     drm_lock_t lock;
   2252 
   2253     memclear(lock);
   2254     lock.context = context;
   2255     if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
   2256     if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
   2257     if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
   2258     if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
   2259     if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
   2260     if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
   2261     if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock))
   2262         return -errno;
   2263     return 0;
   2264 }
   2265 
   2266 /**
   2267  * Get IRQ from bus ID.
   2268  *
   2269  * \param fd file descriptor.
   2270  * \param busnum bus number.
   2271  * \param devnum device number.
   2272  * \param funcnum function number.
   2273  *
   2274  * \return IRQ number on success, or a negative value on failure.
   2275  *
   2276  * \internal
   2277  * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
   2278  * arguments in a drm_irq_busid structure.
   2279  */
   2280 int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
   2281 {
   2282     drm_irq_busid_t p;
   2283 
   2284     memclear(p);
   2285     p.busnum  = busnum;
   2286     p.devnum  = devnum;
   2287     p.funcnum = funcnum;
   2288     if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
   2289         return -errno;
   2290     return p.irq;
   2291 }
   2292 
   2293 int drmAddContextTag(int fd, drm_context_t context, void *tag)
   2294 {
   2295     drmHashEntry  *entry = drmGetEntry(fd);
   2296 
   2297     if (drmHashInsert(entry->tagTable, context, tag)) {
   2298         drmHashDelete(entry->tagTable, context);
   2299         drmHashInsert(entry->tagTable, context, tag);
   2300     }
   2301     return 0;
   2302 }
   2303 
   2304 int drmDelContextTag(int fd, drm_context_t context)
   2305 {
   2306     drmHashEntry  *entry = drmGetEntry(fd);
   2307 
   2308     return drmHashDelete(entry->tagTable, context);
   2309 }
   2310 
   2311 void *drmGetContextTag(int fd, drm_context_t context)
   2312 {
   2313     drmHashEntry  *entry = drmGetEntry(fd);
   2314     void          *value;
   2315 
   2316     if (drmHashLookup(entry->tagTable, context, &value))
   2317         return NULL;
   2318 
   2319     return value;
   2320 }
   2321 
   2322 int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
   2323                                 drm_handle_t handle)
   2324 {
   2325     drm_ctx_priv_map_t map;
   2326 
   2327     memclear(map);
   2328     map.ctx_id = ctx_id;
   2329     map.handle = (void *)(uintptr_t)handle;
   2330 
   2331     if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
   2332         return -errno;
   2333     return 0;
   2334 }
   2335 
   2336 int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
   2337                                 drm_handle_t *handle)
   2338 {
   2339     drm_ctx_priv_map_t map;
   2340 
   2341     memclear(map);
   2342     map.ctx_id = ctx_id;
   2343 
   2344     if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
   2345         return -errno;
   2346     if (handle)
   2347         *handle = (drm_handle_t)(uintptr_t)map.handle;
   2348 
   2349     return 0;
   2350 }
   2351 
   2352 int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
   2353               drmMapType *type, drmMapFlags *flags, drm_handle_t *handle,
   2354               int *mtrr)
   2355 {
   2356     drm_map_t map;
   2357 
   2358     memclear(map);
   2359     map.offset = idx;
   2360     if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
   2361         return -errno;
   2362     *offset = map.offset;
   2363     *size   = map.size;
   2364     *type   = map.type;
   2365     *flags  = map.flags;
   2366     *handle = (unsigned long)map.handle;
   2367     *mtrr   = map.mtrr;
   2368     return 0;
   2369 }
   2370 
   2371 int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
   2372                  unsigned long *magic, unsigned long *iocs)
   2373 {
   2374     drm_client_t client;
   2375 
   2376     memclear(client);
   2377     client.idx = idx;
   2378     if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
   2379         return -errno;
   2380     *auth      = client.auth;
   2381     *pid       = client.pid;
   2382     *uid       = client.uid;
   2383     *magic     = client.magic;
   2384     *iocs      = client.iocs;
   2385     return 0;
   2386 }
   2387 
   2388 int drmGetStats(int fd, drmStatsT *stats)
   2389 {
   2390     drm_stats_t s;
   2391     unsigned    i;
   2392 
   2393     memclear(s);
   2394     if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
   2395         return -errno;
   2396 
   2397     stats->count = 0;
   2398     memset(stats, 0, sizeof(*stats));
   2399     if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
   2400         return -1;
   2401 
   2402 #define SET_VALUE                              \
   2403     stats->data[i].long_format = "%-20.20s";   \
   2404     stats->data[i].rate_format = "%8.8s";      \
   2405     stats->data[i].isvalue     = 1;            \
   2406     stats->data[i].verbose     = 0
   2407 
   2408 #define SET_COUNT                              \
   2409     stats->data[i].long_format = "%-20.20s";   \
   2410     stats->data[i].rate_format = "%5.5s";      \
   2411     stats->data[i].isvalue     = 0;            \
   2412     stats->data[i].mult_names  = "kgm";        \
   2413     stats->data[i].mult        = 1000;         \
   2414     stats->data[i].verbose     = 0
   2415 
   2416 #define SET_BYTE                               \
   2417     stats->data[i].long_format = "%-20.20s";   \
   2418     stats->data[i].rate_format = "%5.5s";      \
   2419     stats->data[i].isvalue     = 0;            \
   2420     stats->data[i].mult_names  = "KGM";        \
   2421     stats->data[i].mult        = 1024;         \
   2422     stats->data[i].verbose     = 0
   2423 
   2424 
   2425     stats->count = s.count;
   2426     for (i = 0; i < s.count; i++) {
   2427         stats->data[i].value = s.data[i].value;
   2428         switch (s.data[i].type) {
   2429         case _DRM_STAT_LOCK:
   2430             stats->data[i].long_name = "Lock";
   2431             stats->data[i].rate_name = "Lock";
   2432             SET_VALUE;
   2433             break;
   2434         case _DRM_STAT_OPENS:
   2435             stats->data[i].long_name = "Opens";
   2436             stats->data[i].rate_name = "O";
   2437             SET_COUNT;
   2438             stats->data[i].verbose   = 1;
   2439             break;
   2440         case _DRM_STAT_CLOSES:
   2441             stats->data[i].long_name = "Closes";
   2442             stats->data[i].rate_name = "Lock";
   2443             SET_COUNT;
   2444             stats->data[i].verbose   = 1;
   2445             break;
   2446         case _DRM_STAT_IOCTLS:
   2447             stats->data[i].long_name = "Ioctls";
   2448             stats->data[i].rate_name = "Ioc/s";
   2449             SET_COUNT;
   2450             break;
   2451         case _DRM_STAT_LOCKS:
   2452             stats->data[i].long_name = "Locks";
   2453             stats->data[i].rate_name = "Lck/s";
   2454             SET_COUNT;
   2455             break;
   2456         case _DRM_STAT_UNLOCKS:
   2457             stats->data[i].long_name = "Unlocks";
   2458             stats->data[i].rate_name = "Unl/s";
   2459             SET_COUNT;
   2460             break;
   2461         case _DRM_STAT_IRQ:
   2462             stats->data[i].long_name = "IRQs";
   2463             stats->data[i].rate_name = "IRQ/s";
   2464             SET_COUNT;
   2465             break;
   2466         case _DRM_STAT_PRIMARY:
   2467             stats->data[i].long_name = "Primary Bytes";
   2468             stats->data[i].rate_name = "PB/s";
   2469             SET_BYTE;
   2470             break;
   2471         case _DRM_STAT_SECONDARY:
   2472             stats->data[i].long_name = "Secondary Bytes";
   2473             stats->data[i].rate_name = "SB/s";
   2474             SET_BYTE;
   2475             break;
   2476         case _DRM_STAT_DMA:
   2477             stats->data[i].long_name = "DMA";
   2478             stats->data[i].rate_name = "DMA/s";
   2479             SET_COUNT;
   2480             break;
   2481         case _DRM_STAT_SPECIAL:
   2482             stats->data[i].long_name = "Special DMA";
   2483             stats->data[i].rate_name = "dma/s";
   2484             SET_COUNT;
   2485             break;
   2486         case _DRM_STAT_MISSED:
   2487             stats->data[i].long_name = "Miss";
   2488             stats->data[i].rate_name = "Ms/s";
   2489             SET_COUNT;
   2490             break;
   2491         case _DRM_STAT_VALUE:
   2492             stats->data[i].long_name = "Value";
   2493             stats->data[i].rate_name = "Value";
   2494             SET_VALUE;
   2495             break;
   2496         case _DRM_STAT_BYTE:
   2497             stats->data[i].long_name = "Bytes";
   2498             stats->data[i].rate_name = "B/s";
   2499             SET_BYTE;
   2500             break;
   2501         case _DRM_STAT_COUNT:
   2502         default:
   2503             stats->data[i].long_name = "Count";
   2504             stats->data[i].rate_name = "Cnt/s";
   2505             SET_COUNT;
   2506             break;
   2507         }
   2508     }
   2509     return 0;
   2510 }
   2511 
   2512 /**
   2513  * Issue a set-version ioctl.
   2514  *
   2515  * \param fd file descriptor.
   2516  * \param drmCommandIndex command index
   2517  * \param data source pointer of the data to be read and written.
   2518  * \param size size of the data to be read and written.
   2519  *
   2520  * \return zero on success, or a negative value on failure.
   2521  *
   2522  * \internal
   2523  * It issues a read-write ioctl given by
   2524  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
   2525  */
   2526 int drmSetInterfaceVersion(int fd, drmSetVersion *version)
   2527 {
   2528     int retcode = 0;
   2529     drm_set_version_t sv;
   2530 
   2531     memclear(sv);
   2532     sv.drm_di_major = version->drm_di_major;
   2533     sv.drm_di_minor = version->drm_di_minor;
   2534     sv.drm_dd_major = version->drm_dd_major;
   2535     sv.drm_dd_minor = version->drm_dd_minor;
   2536 
   2537     if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
   2538         retcode = -errno;
   2539     }
   2540 
   2541     version->drm_di_major = sv.drm_di_major;
   2542     version->drm_di_minor = sv.drm_di_minor;
   2543     version->drm_dd_major = sv.drm_dd_major;
   2544     version->drm_dd_minor = sv.drm_dd_minor;
   2545 
   2546     return retcode;
   2547 }
   2548 
   2549 /**
   2550  * Send a device-specific command.
   2551  *
   2552  * \param fd file descriptor.
   2553  * \param drmCommandIndex command index
   2554  *
   2555  * \return zero on success, or a negative value on failure.
   2556  *
   2557  * \internal
   2558  * It issues a ioctl given by
   2559  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
   2560  */
   2561 int drmCommandNone(int fd, unsigned long drmCommandIndex)
   2562 {
   2563     unsigned long request;
   2564 
   2565     request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
   2566 
   2567     if (drmIoctl(fd, request, NULL)) {
   2568         return -errno;
   2569     }
   2570     return 0;
   2571 }
   2572 
   2573 
   2574 /**
   2575  * Send a device-specific read command.
   2576  *
   2577  * \param fd file descriptor.
   2578  * \param drmCommandIndex command index
   2579  * \param data destination pointer of the data to be read.
   2580  * \param size size of the data to be read.
   2581  *
   2582  * \return zero on success, or a negative value on failure.
   2583  *
   2584  * \internal
   2585  * It issues a read ioctl given by
   2586  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
   2587  */
   2588 int drmCommandRead(int fd, unsigned long drmCommandIndex, void *data,
   2589                    unsigned long size)
   2590 {
   2591     unsigned long request;
   2592 
   2593     request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
   2594         DRM_COMMAND_BASE + drmCommandIndex, size);
   2595 
   2596     if (drmIoctl(fd, request, data)) {
   2597         return -errno;
   2598     }
   2599     return 0;
   2600 }
   2601 
   2602 
   2603 /**
   2604  * Send a device-specific write command.
   2605  *
   2606  * \param fd file descriptor.
   2607  * \param drmCommandIndex command index
   2608  * \param data source pointer of the data to be written.
   2609  * \param size size of the data to be written.
   2610  *
   2611  * \return zero on success, or a negative value on failure.
   2612  *
   2613  * \internal
   2614  * It issues a write ioctl given by
   2615  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
   2616  */
   2617 int drmCommandWrite(int fd, unsigned long drmCommandIndex, void *data,
   2618                     unsigned long size)
   2619 {
   2620     unsigned long request;
   2621 
   2622     request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
   2623         DRM_COMMAND_BASE + drmCommandIndex, size);
   2624 
   2625     if (drmIoctl(fd, request, data)) {
   2626         return -errno;
   2627     }
   2628     return 0;
   2629 }
   2630 
   2631 
   2632 /**
   2633  * Send a device-specific read-write command.
   2634  *
   2635  * \param fd file descriptor.
   2636  * \param drmCommandIndex command index
   2637  * \param data source pointer of the data to be read and written.
   2638  * \param size size of the data to be read and written.
   2639  *
   2640  * \return zero on success, or a negative value on failure.
   2641  *
   2642  * \internal
   2643  * It issues a read-write ioctl given by
   2644  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
   2645  */
   2646 int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data,
   2647                         unsigned long size)
   2648 {
   2649     unsigned long request;
   2650 
   2651     request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
   2652         DRM_COMMAND_BASE + drmCommandIndex, size);
   2653 
   2654     if (drmIoctl(fd, request, data))
   2655         return -errno;
   2656     return 0;
   2657 }
   2658 
   2659 #define DRM_MAX_FDS 16
   2660 static struct {
   2661     char *BusID;
   2662     int fd;
   2663     int refcount;
   2664     int type;
   2665 } connection[DRM_MAX_FDS];
   2666 
   2667 static int nr_fds = 0;
   2668 
   2669 int drmOpenOnce(void *unused,
   2670                 const char *BusID,
   2671                 int *newlyopened)
   2672 {
   2673     return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
   2674 }
   2675 
   2676 int drmOpenOnceWithType(const char *BusID, int *newlyopened, int type)
   2677 {
   2678     int i;
   2679     int fd;
   2680 
   2681     for (i = 0; i < nr_fds; i++)
   2682         if ((strcmp(BusID, connection[i].BusID) == 0) &&
   2683             (connection[i].type == type)) {
   2684             connection[i].refcount++;
   2685             *newlyopened = 0;
   2686             return connection[i].fd;
   2687         }
   2688 
   2689     fd = drmOpenWithType(NULL, BusID, type);
   2690     if (fd < 0 || nr_fds == DRM_MAX_FDS)
   2691         return fd;
   2692 
   2693     connection[nr_fds].BusID = strdup(BusID);
   2694     connection[nr_fds].fd = fd;
   2695     connection[nr_fds].refcount = 1;
   2696     connection[nr_fds].type = type;
   2697     *newlyopened = 1;
   2698 
   2699     if (0)
   2700         fprintf(stderr, "saved connection %d for %s %d\n",
   2701                 nr_fds, connection[nr_fds].BusID,
   2702                 strcmp(BusID, connection[nr_fds].BusID));
   2703 
   2704     nr_fds++;
   2705 
   2706     return fd;
   2707 }
   2708 
   2709 void drmCloseOnce(int fd)
   2710 {
   2711     int i;
   2712 
   2713     for (i = 0; i < nr_fds; i++) {
   2714         if (fd == connection[i].fd) {
   2715             if (--connection[i].refcount == 0) {
   2716                 drmClose(connection[i].fd);
   2717                 free(connection[i].BusID);
   2718 
   2719                 if (i < --nr_fds)
   2720                     connection[i] = connection[nr_fds];
   2721 
   2722                 return;
   2723             }
   2724         }
   2725     }
   2726 }
   2727 
   2728 int drmSetMaster(int fd)
   2729 {
   2730         return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
   2731 }
   2732 
   2733 int drmDropMaster(int fd)
   2734 {
   2735         return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
   2736 }
   2737 
   2738 char *drmGetDeviceNameFromFd(int fd)
   2739 {
   2740     char name[128];
   2741     struct stat sbuf;
   2742     dev_t d;
   2743     int i;
   2744 
   2745     /* The whole drmOpen thing is a fiasco and we need to find a way
   2746      * back to just using open(2).  For now, however, lets just make
   2747      * things worse with even more ad hoc directory walking code to
   2748      * discover the device file name. */
   2749 
   2750     fstat(fd, &sbuf);
   2751     d = sbuf.st_rdev;
   2752 
   2753     for (i = 0; i < DRM_MAX_MINOR; i++) {
   2754         snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
   2755         if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
   2756             break;
   2757     }
   2758     if (i == DRM_MAX_MINOR)
   2759         return NULL;
   2760 
   2761     return strdup(name);
   2762 }
   2763 
   2764 int drmGetNodeTypeFromFd(int fd)
   2765 {
   2766     struct stat sbuf;
   2767     int maj, min, type;
   2768 
   2769     if (fstat(fd, &sbuf))
   2770         return -1;
   2771 
   2772     maj = major(sbuf.st_rdev);
   2773     min = minor(sbuf.st_rdev);
   2774 
   2775     if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) {
   2776         errno = EINVAL;
   2777         return -1;
   2778     }
   2779 
   2780     type = drmGetMinorType(min);
   2781     if (type == -1)
   2782         errno = ENODEV;
   2783     return type;
   2784 }
   2785 
   2786 int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd)
   2787 {
   2788     struct drm_prime_handle args;
   2789     int ret;
   2790 
   2791     memclear(args);
   2792     args.fd = -1;
   2793     args.handle = handle;
   2794     args.flags = flags;
   2795     ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
   2796     if (ret)
   2797         return ret;
   2798 
   2799     *prime_fd = args.fd;
   2800     return 0;
   2801 }
   2802 
   2803 int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
   2804 {
   2805     struct drm_prime_handle args;
   2806     int ret;
   2807 
   2808     memclear(args);
   2809     args.fd = prime_fd;
   2810     ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
   2811     if (ret)
   2812         return ret;
   2813 
   2814     *handle = args.handle;
   2815     return 0;
   2816 }
   2817 
   2818 static char *drmGetMinorNameForFD(int fd, int type)
   2819 {
   2820 #ifdef __linux__
   2821     DIR *sysdir;
   2822     struct dirent *ent;
   2823     struct stat sbuf;
   2824     const char *name = drmGetMinorName(type);
   2825     int len;
   2826     char dev_name[64], buf[64];
   2827     int maj, min;
   2828 
   2829     if (!name)
   2830         return NULL;
   2831 
   2832     len = strlen(name);
   2833 
   2834     if (fstat(fd, &sbuf))
   2835         return NULL;
   2836 
   2837     maj = major(sbuf.st_rdev);
   2838     min = minor(sbuf.st_rdev);
   2839 
   2840     if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
   2841         return NULL;
   2842 
   2843     snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
   2844 
   2845     sysdir = opendir(buf);
   2846     if (!sysdir)
   2847         return NULL;
   2848 
   2849     while ((ent = readdir(sysdir))) {
   2850         if (strncmp(ent->d_name, name, len) == 0) {
   2851             snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
   2852                  ent->d_name);
   2853 
   2854             closedir(sysdir);
   2855             return strdup(dev_name);
   2856         }
   2857     }
   2858     return NULL;
   2859 #else
   2860     struct stat sbuf;
   2861     char buf[PATH_MAX + 1];
   2862     const char *dev_name;
   2863     unsigned int maj, min;
   2864     int n, base;
   2865 
   2866     if (fstat(fd, &sbuf))
   2867         return NULL;
   2868 
   2869     maj = major(sbuf.st_rdev);
   2870     min = minor(sbuf.st_rdev);
   2871 
   2872     if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
   2873         return NULL;
   2874 
   2875     switch (type) {
   2876     case DRM_NODE_PRIMARY:
   2877         dev_name = DRM_DEV_NAME;
   2878         break;
   2879     case DRM_NODE_CONTROL:
   2880         dev_name = DRM_CONTROL_DEV_NAME;
   2881         break;
   2882     case DRM_NODE_RENDER:
   2883         dev_name = DRM_RENDER_DEV_NAME;
   2884         break;
   2885     default:
   2886         return NULL;
   2887     };
   2888 
   2889     base = drmGetMinorBase(type);
   2890     if (base < 0)
   2891         return NULL;
   2892 
   2893     n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min - base);
   2894     if (n == -1 || n >= sizeof(buf))
   2895         return NULL;
   2896 
   2897     return strdup(buf);
   2898 #endif
   2899 }
   2900 
   2901 char *drmGetPrimaryDeviceNameFromFd(int fd)
   2902 {
   2903     return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
   2904 }
   2905 
   2906 char *drmGetRenderDeviceNameFromFd(int fd)
   2907 {
   2908     return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
   2909 }
   2910 
   2911 #ifdef __linux__
   2912 static char * DRM_PRINTFLIKE(2, 3)
   2913 sysfs_uevent_get(const char *path, const char *fmt, ...)
   2914 {
   2915     char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL;
   2916     size_t size = 0, len;
   2917     ssize_t num;
   2918     va_list ap;
   2919     FILE *fp;
   2920 
   2921     va_start(ap, fmt);
   2922     num = vasprintf(&key, fmt, ap);
   2923     va_end(ap);
   2924     len = num;
   2925 
   2926     snprintf(filename, sizeof(filename), "%s/uevent", path);
   2927 
   2928     fp = fopen(filename, "r");
   2929     if (!fp) {
   2930         free(key);
   2931         return NULL;
   2932     }
   2933 
   2934     while ((num = getline(&line, &size, fp)) >= 0) {
   2935         if ((strncmp(line, key, len) == 0) && (line[len] == '=')) {
   2936             char *start = line + len + 1, *end = line + num - 1;
   2937 
   2938             if (*end != '\n')
   2939                 end++;
   2940 
   2941             value = strndup(start, end - start);
   2942             break;
   2943         }
   2944     }
   2945 
   2946     free(line);
   2947     fclose(fp);
   2948 
   2949     free(key);
   2950 
   2951     return value;
   2952 }
   2953 #endif
   2954 
   2955 static int drmParseSubsystemType(int maj, int min)
   2956 {
   2957 #ifdef __linux__
   2958     char path[PATH_MAX + 1];
   2959     char link[PATH_MAX + 1] = "";
   2960     char *name;
   2961 
   2962     snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem",
   2963              maj, min);
   2964 
   2965     if (readlink(path, link, PATH_MAX) < 0)
   2966         return -errno;
   2967 
   2968     name = strrchr(link, '/');
   2969     if (!name)
   2970         return -EINVAL;
   2971 
   2972     if (strncmp(name, "/pci", 4) == 0)
   2973         return DRM_BUS_PCI;
   2974 
   2975     if (strncmp(name, "/usb", 4) == 0)
   2976         return DRM_BUS_USB;
   2977 
   2978     if (strncmp(name, "/platform", 9) == 0)
   2979         return DRM_BUS_PLATFORM;
   2980 
   2981     if (strncmp(name, "/host1x", 7) == 0)
   2982         return DRM_BUS_HOST1X;
   2983 
   2984     return -EINVAL;
   2985 #elif defined(__OpenBSD__)
   2986     return DRM_BUS_PCI;
   2987 #else
   2988 #warning "Missing implementation of drmParseSubsystemType"
   2989     return -EINVAL;
   2990 #endif
   2991 }
   2992 
   2993 static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
   2994 {
   2995 #ifdef __linux__
   2996     unsigned int domain, bus, dev, func;
   2997     char path[PATH_MAX + 1], *value;
   2998     int num;
   2999 
   3000     snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
   3001 
   3002     value = sysfs_uevent_get(path, "PCI_SLOT_NAME");
   3003     if (!value)
   3004         return -ENOENT;
   3005 
   3006     num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func);
   3007     free(value);
   3008 
   3009     if (num != 4)
   3010         return -EINVAL;
   3011 
   3012     info->domain = domain;
   3013     info->bus = bus;
   3014     info->dev = dev;
   3015     info->func = func;
   3016 
   3017     return 0;
   3018 #elif defined(__OpenBSD__)
   3019     struct drm_pciinfo pinfo;
   3020     int fd, type;
   3021 
   3022     type = drmGetMinorType(min);
   3023     if (type == -1)
   3024         return -ENODEV;
   3025 
   3026     fd = drmOpenMinor(min, 0, type);
   3027     if (fd < 0)
   3028         return -errno;
   3029 
   3030     if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
   3031         close(fd);
   3032         return -errno;
   3033     }
   3034     close(fd);
   3035 
   3036     info->domain = pinfo.domain;
   3037     info->bus = pinfo.bus;
   3038     info->dev = pinfo.dev;
   3039     info->func = pinfo.func;
   3040 
   3041     return 0;
   3042 #else
   3043 #warning "Missing implementation of drmParsePciBusInfo"
   3044     return -EINVAL;
   3045 #endif
   3046 }
   3047 
   3048 int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b)
   3049 {
   3050     if (a == NULL || b == NULL)
   3051         return 0;
   3052 
   3053     if (a->bustype != b->bustype)
   3054         return 0;
   3055 
   3056     switch (a->bustype) {
   3057     case DRM_BUS_PCI:
   3058         return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0;
   3059 
   3060     case DRM_BUS_USB:
   3061         return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0;
   3062 
   3063     case DRM_BUS_PLATFORM:
   3064         return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0;
   3065 
   3066     case DRM_BUS_HOST1X:
   3067         return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0;
   3068 
   3069     default:
   3070         break;
   3071     }
   3072 
   3073     return 0;
   3074 }
   3075 
   3076 static int drmGetNodeType(const char *name)
   3077 {
   3078     if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
   3079         sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
   3080         return DRM_NODE_PRIMARY;
   3081 
   3082     if (strncmp(name, DRM_CONTROL_MINOR_NAME,
   3083         sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0)
   3084         return DRM_NODE_CONTROL;
   3085 
   3086     if (strncmp(name, DRM_RENDER_MINOR_NAME,
   3087         sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
   3088         return DRM_NODE_RENDER;
   3089 
   3090     return -EINVAL;
   3091 }
   3092 
   3093 static int drmGetMaxNodeName(void)
   3094 {
   3095     return sizeof(DRM_DIR_NAME) +
   3096            MAX3(sizeof(DRM_PRIMARY_MINOR_NAME),
   3097                 sizeof(DRM_CONTROL_MINOR_NAME),
   3098                 sizeof(DRM_RENDER_MINOR_NAME)) +
   3099            3 /* length of the node number */;
   3100 }
   3101 
   3102 #ifdef __linux__
   3103 static int parse_separate_sysfs_files(int maj, int min,
   3104                                       drmPciDeviceInfoPtr device,
   3105                                       bool ignore_revision)
   3106 {
   3107 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
   3108     static const char *attrs[] = {
   3109       "revision", /* Older kernels are missing the file, so check for it first */
   3110       "vendor",
   3111       "device",
   3112       "subsystem_vendor",
   3113       "subsystem_device",
   3114     };
   3115     char path[PATH_MAX + 1];
   3116     unsigned int data[ARRAY_SIZE(attrs)];
   3117     FILE *fp;
   3118     int ret;
   3119 
   3120     for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) {
   3121         snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/%s", maj, min,
   3122                  attrs[i]);
   3123         fp = fopen(path, "r");
   3124         if (!fp)
   3125             return -errno;
   3126 
   3127         ret = fscanf(fp, "%x", &data[i]);
   3128         fclose(fp);
   3129         if (ret != 1)
   3130             return -errno;
   3131 
   3132     }
   3133 
   3134     device->revision_id = ignore_revision ? 0xff : data[0] & 0xff;
   3135     device->vendor_id = data[1] & 0xffff;
   3136     device->device_id = data[2] & 0xffff;
   3137     device->subvendor_id = data[3] & 0xffff;
   3138     device->subdevice_id = data[4] & 0xffff;
   3139 
   3140     return 0;
   3141 }
   3142 
   3143 static int parse_config_sysfs_file(int maj, int min,
   3144                                    drmPciDeviceInfoPtr device)
   3145 {
   3146     char path[PATH_MAX + 1];
   3147     unsigned char config[64];
   3148     int fd, ret;
   3149 
   3150     snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/config", maj, min);
   3151     fd = open(path, O_RDONLY);
   3152     if (fd < 0)
   3153         return -errno;
   3154 
   3155     ret = read(fd, config, sizeof(config));
   3156     close(fd);
   3157     if (ret < 0)
   3158         return -errno;
   3159 
   3160     device->vendor_id = config[0] | (config[1] << 8);
   3161     device->device_id = config[2] | (config[3] << 8);
   3162     device->revision_id = config[8];
   3163     device->subvendor_id = config[44] | (config[45] << 8);
   3164     device->subdevice_id = config[46] | (config[47] << 8);
   3165 
   3166     return 0;
   3167 }
   3168 #endif
   3169 
   3170 static int drmParsePciDeviceInfo(int maj, int min,
   3171                                  drmPciDeviceInfoPtr device,
   3172                                  uint32_t flags)
   3173 {
   3174 #ifdef __linux__
   3175     if (!(flags & DRM_DEVICE_GET_PCI_REVISION))
   3176         return parse_separate_sysfs_files(maj, min, device, true);
   3177 
   3178     if (parse_separate_sysfs_files(maj, min, device, false))
   3179         return parse_config_sysfs_file(maj, min, device);
   3180 
   3181     return 0;
   3182 #elif defined(__OpenBSD__)
   3183     struct drm_pciinfo pinfo;
   3184     int fd, type;
   3185 
   3186     type = drmGetMinorType(min);
   3187     if (type == -1)
   3188         return -ENODEV;
   3189 
   3190     fd = drmOpenMinor(min, 0, type);
   3191     if (fd < 0)
   3192         return -errno;
   3193 
   3194     if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
   3195         close(fd);
   3196         return -errno;
   3197     }
   3198     close(fd);
   3199 
   3200     device->vendor_id = pinfo.vendor_id;
   3201     device->device_id = pinfo.device_id;
   3202     device->revision_id = pinfo.revision_id;
   3203     device->subvendor_id = pinfo.subvendor_id;
   3204     device->subdevice_id = pinfo.subdevice_id;
   3205 
   3206     return 0;
   3207 #else
   3208 #warning "Missing implementation of drmParsePciDeviceInfo"
   3209     return -EINVAL;
   3210 #endif
   3211 }
   3212 
   3213 static void drmFreePlatformDevice(drmDevicePtr device)
   3214 {
   3215     if (device->deviceinfo.platform) {
   3216         if (device->deviceinfo.platform->compatible) {
   3217             char **compatible = device->deviceinfo.platform->compatible;
   3218 
   3219             while (*compatible) {
   3220                 free(*compatible);
   3221                 compatible++;
   3222             }
   3223 
   3224             free(device->deviceinfo.platform->compatible);
   3225         }
   3226     }
   3227 }
   3228 
   3229 static void drmFreeHost1xDevice(drmDevicePtr device)
   3230 {
   3231     if (device->deviceinfo.host1x) {
   3232         if (device->deviceinfo.host1x->compatible) {
   3233             char **compatible = device->deviceinfo.host1x->compatible;
   3234 
   3235             while (*compatible) {
   3236                 free(*compatible);
   3237                 compatible++;
   3238             }
   3239 
   3240             free(device->deviceinfo.host1x->compatible);
   3241         }
   3242     }
   3243 }
   3244 
   3245 void drmFreeDevice(drmDevicePtr *device)
   3246 {
   3247     if (device == NULL)
   3248         return;
   3249 
   3250     if (*device) {
   3251         switch ((*device)->bustype) {
   3252         case DRM_BUS_PLATFORM:
   3253             drmFreePlatformDevice(*device);
   3254             break;
   3255 
   3256         case DRM_BUS_HOST1X:
   3257             drmFreeHost1xDevice(*device);
   3258             break;
   3259         }
   3260     }
   3261 
   3262     free(*device);
   3263     *device = NULL;
   3264 }
   3265 
   3266 void drmFreeDevices(drmDevicePtr devices[], int count)
   3267 {
   3268     int i;
   3269 
   3270     if (devices == NULL)
   3271         return;
   3272 
   3273     for (i = 0; i < count; i++)
   3274         if (devices[i])
   3275             drmFreeDevice(&devices[i]);
   3276 }
   3277 
   3278 static drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node,
   3279                                    size_t bus_size, size_t device_size,
   3280                                    char **ptrp)
   3281 {
   3282     size_t max_node_length, extra, size;
   3283     drmDevicePtr device;
   3284     unsigned int i;
   3285     char *ptr;
   3286 
   3287     max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
   3288     extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length);
   3289 
   3290     size = sizeof(*device) + extra + bus_size + device_size;
   3291 
   3292     device = calloc(1, size);
   3293     if (!device)
   3294         return NULL;
   3295 
   3296     device->available_nodes = 1 << type;
   3297 
   3298     ptr = (char *)device + sizeof(*device);
   3299     device->nodes = (char **)ptr;
   3300 
   3301     ptr += DRM_NODE_MAX * sizeof(void *);
   3302 
   3303     for (i = 0; i < DRM_NODE_MAX; i++) {
   3304         device->nodes[i] = ptr;
   3305         ptr += max_node_length;
   3306     }
   3307 
   3308     memcpy(device->nodes[type], node, max_node_length);
   3309 
   3310     *ptrp = ptr;
   3311 
   3312     return device;
   3313 }
   3314 
   3315 static int drmProcessPciDevice(drmDevicePtr *device,
   3316                                const char *node, int node_type,
   3317                                int maj, int min, bool fetch_deviceinfo,
   3318                                uint32_t flags)
   3319 {
   3320     drmDevicePtr dev;
   3321     char *addr;
   3322     int ret;
   3323 
   3324     dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo),
   3325                          sizeof(drmPciDeviceInfo), &addr);
   3326     if (!dev)
   3327         return -ENOMEM;
   3328 
   3329     dev->bustype = DRM_BUS_PCI;
   3330 
   3331     dev->businfo.pci = (drmPciBusInfoPtr)addr;
   3332 
   3333     ret = drmParsePciBusInfo(maj, min, dev->businfo.pci);
   3334     if (ret)
   3335         goto free_device;
   3336 
   3337     // Fetch the device info if the user has requested it
   3338     if (fetch_deviceinfo) {
   3339         addr += sizeof(drmPciBusInfo);
   3340         dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
   3341 
   3342         ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags);
   3343         if (ret)
   3344             goto free_device;
   3345     }
   3346 
   3347     *device = dev;
   3348 
   3349     return 0;
   3350 
   3351 free_device:
   3352     free(dev);
   3353     return ret;
   3354 }
   3355 
   3356 static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info)
   3357 {
   3358 #ifdef __linux__
   3359     char path[PATH_MAX + 1], *value;
   3360     unsigned int bus, dev;
   3361     int ret;
   3362 
   3363     snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
   3364 
   3365     value = sysfs_uevent_get(path, "BUSNUM");
   3366     if (!value)
   3367         return -ENOENT;
   3368 
   3369     ret = sscanf(value, "%03u", &bus);
   3370     free(value);
   3371 
   3372     if (ret <= 0)
   3373         return -errno;
   3374 
   3375     value = sysfs_uevent_get(path, "DEVNUM");
   3376     if (!value)
   3377         return -ENOENT;
   3378 
   3379     ret = sscanf(value, "%03u", &dev);
   3380     free(value);
   3381 
   3382     if (ret <= 0)
   3383         return -errno;
   3384 
   3385     info->bus = bus;
   3386     info->dev = dev;
   3387 
   3388     return 0;
   3389 #else
   3390 #warning "Missing implementation of drmParseUsbBusInfo"
   3391     return -EINVAL;
   3392 #endif
   3393 }
   3394 
   3395 static int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info)
   3396 {
   3397 #ifdef __linux__
   3398     char path[PATH_MAX + 1], *value;
   3399     unsigned int vendor, product;
   3400     int ret;
   3401 
   3402     snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
   3403 
   3404     value = sysfs_uevent_get(path, "PRODUCT");
   3405     if (!value)
   3406         return -ENOENT;
   3407 
   3408     ret = sscanf(value, "%x/%x", &vendor, &product);
   3409     free(value);
   3410 
   3411     if (ret <= 0)
   3412         return -errno;
   3413 
   3414     info->vendor = vendor;
   3415     info->product = product;
   3416 
   3417     return 0;
   3418 #else
   3419 #warning "Missing implementation of drmParseUsbDeviceInfo"
   3420     return -EINVAL;
   3421 #endif
   3422 }
   3423 
   3424 static int drmProcessUsbDevice(drmDevicePtr *device, const char *node,
   3425                                int node_type, int maj, int min,
   3426                                bool fetch_deviceinfo, uint32_t flags)
   3427 {
   3428     drmDevicePtr dev;
   3429     char *ptr;
   3430     int ret;
   3431 
   3432     dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo),
   3433                          sizeof(drmUsbDeviceInfo), &ptr);
   3434     if (!dev)
   3435         return -ENOMEM;
   3436 
   3437     dev->bustype = DRM_BUS_USB;
   3438 
   3439     dev->businfo.usb = (drmUsbBusInfoPtr)ptr;
   3440 
   3441     ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb);
   3442     if (ret < 0)
   3443         goto free_device;
   3444 
   3445     if (fetch_deviceinfo) {
   3446         ptr += sizeof(drmUsbBusInfo);
   3447         dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr;
   3448 
   3449         ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb);
   3450         if (ret < 0)
   3451             goto free_device;
   3452     }
   3453 
   3454     *device = dev;
   3455 
   3456     return 0;
   3457 
   3458 free_device:
   3459     free(dev);
   3460     return ret;
   3461 }
   3462 
   3463 static int drmParsePlatformBusInfo(int maj, int min, drmPlatformBusInfoPtr info)
   3464 {
   3465 #ifdef __linux__
   3466     char path[PATH_MAX + 1], *name;
   3467 
   3468     snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
   3469 
   3470     name = sysfs_uevent_get(path, "OF_FULLNAME");
   3471     if (!name)
   3472         return -ENOENT;
   3473 
   3474     strncpy(info->fullname, name, DRM_PLATFORM_DEVICE_NAME_LEN);
   3475     info->fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0';
   3476     free(name);
   3477 
   3478     return 0;
   3479 #else
   3480 #warning "Missing implementation of drmParsePlatformBusInfo"
   3481     return -EINVAL;
   3482 #endif
   3483 }
   3484 
   3485 static int drmParsePlatformDeviceInfo(int maj, int min,
   3486                                       drmPlatformDeviceInfoPtr info)
   3487 {
   3488 #ifdef __linux__
   3489     char path[PATH_MAX + 1], *value;
   3490     unsigned int count, i;
   3491     int err;
   3492 
   3493     snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
   3494 
   3495     value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
   3496     if (!value)
   3497         return -ENOENT;
   3498 
   3499     sscanf(value, "%u", &count);
   3500     free(value);
   3501 
   3502     info->compatible = calloc(count + 1, sizeof(*info->compatible));
   3503     if (!info->compatible)
   3504         return -ENOMEM;
   3505 
   3506     for (i = 0; i < count; i++) {
   3507         value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
   3508         if (!value) {
   3509             err = -ENOENT;
   3510             goto free;
   3511         }
   3512 
   3513         info->compatible[i] = value;
   3514     }
   3515 
   3516     return 0;
   3517 
   3518 free:
   3519     while (i--)
   3520         free(info->compatible[i]);
   3521 
   3522     free(info->compatible);
   3523     return err;
   3524 #else
   3525 #warning "Missing implementation of drmParsePlatformDeviceInfo"
   3526     return -EINVAL;
   3527 #endif
   3528 }
   3529 
   3530 static int drmProcessPlatformDevice(drmDevicePtr *device,
   3531                                     const char *node, int node_type,
   3532                                     int maj, int min, bool fetch_deviceinfo,
   3533                                     uint32_t flags)
   3534 {
   3535     drmDevicePtr dev;
   3536     char *ptr;
   3537     int ret;
   3538 
   3539     dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo),
   3540                          sizeof(drmPlatformDeviceInfo), &ptr);
   3541     if (!dev)
   3542         return -ENOMEM;
   3543 
   3544     dev->bustype = DRM_BUS_PLATFORM;
   3545 
   3546     dev->businfo.platform = (drmPlatformBusInfoPtr)ptr;
   3547 
   3548     ret = drmParsePlatformBusInfo(maj, min, dev->businfo.platform);
   3549     if (ret < 0)
   3550         goto free_device;
   3551 
   3552     if (fetch_deviceinfo) {
   3553         ptr += sizeof(drmPlatformBusInfo);
   3554         dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr;
   3555 
   3556         ret = drmParsePlatformDeviceInfo(maj, min, dev->deviceinfo.platform);
   3557         if (ret < 0)
   3558             goto free_device;
   3559     }
   3560 
   3561     *device = dev;
   3562 
   3563     return 0;
   3564 
   3565 free_device:
   3566     free(dev);
   3567     return ret;
   3568 }
   3569 
   3570 static int drmParseHost1xBusInfo(int maj, int min, drmHost1xBusInfoPtr info)
   3571 {
   3572 #ifdef __linux__
   3573     char path[PATH_MAX + 1], *name;
   3574 
   3575     snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
   3576 
   3577     name = sysfs_uevent_get(path, "OF_FULLNAME");
   3578     if (!name)
   3579         return -ENOENT;
   3580 
   3581     strncpy(info->fullname, name, DRM_HOST1X_DEVICE_NAME_LEN);
   3582     info->fullname[DRM_HOST1X_DEVICE_NAME_LEN - 1] = '\0';
   3583     free(name);
   3584 
   3585     return 0;
   3586 #else
   3587 #warning "Missing implementation of drmParseHost1xBusInfo"
   3588     return -EINVAL;
   3589 #endif
   3590 }
   3591 
   3592 static int drmParseHost1xDeviceInfo(int maj, int min,
   3593                                     drmHost1xDeviceInfoPtr info)
   3594 {
   3595 #ifdef __linux__
   3596     char path[PATH_MAX + 1], *value;
   3597     unsigned int count, i;
   3598     int err;
   3599 
   3600     snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
   3601 
   3602     value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
   3603     if (!value)
   3604         return -ENOENT;
   3605 
   3606     sscanf(value, "%u", &count);
   3607     free(value);
   3608 
   3609     info->compatible = calloc(count + 1, sizeof(*info->compatible));
   3610     if (!info->compatible)
   3611         return -ENOMEM;
   3612 
   3613     for (i = 0; i < count; i++) {
   3614         value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
   3615         if (!value) {
   3616             err = -ENOENT;
   3617             goto free;
   3618         }
   3619 
   3620         info->compatible[i] = value;
   3621     }
   3622 
   3623     return 0;
   3624 
   3625 free:
   3626     while (i--)
   3627         free(info->compatible[i]);
   3628 
   3629     free(info->compatible);
   3630     return err;
   3631 #else
   3632 #warning "Missing implementation of drmParseHost1xDeviceInfo"
   3633     return -EINVAL;
   3634 #endif
   3635 }
   3636 
   3637 static int drmProcessHost1xDevice(drmDevicePtr *device,
   3638                                   const char *node, int node_type,
   3639                                   int maj, int min, bool fetch_deviceinfo,
   3640                                   uint32_t flags)
   3641 {
   3642     drmDevicePtr dev;
   3643     char *ptr;
   3644     int ret;
   3645 
   3646     dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo),
   3647                          sizeof(drmHost1xDeviceInfo), &ptr);
   3648     if (!dev)
   3649         return -ENOMEM;
   3650 
   3651     dev->bustype = DRM_BUS_HOST1X;
   3652 
   3653     dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr;
   3654 
   3655     ret = drmParseHost1xBusInfo(maj, min, dev->businfo.host1x);
   3656     if (ret < 0)
   3657         goto free_device;
   3658 
   3659     if (fetch_deviceinfo) {
   3660         ptr += sizeof(drmHost1xBusInfo);
   3661         dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr;
   3662 
   3663         ret = drmParseHost1xDeviceInfo(maj, min, dev->deviceinfo.host1x);
   3664         if (ret < 0)
   3665             goto free_device;
   3666     }
   3667 
   3668     *device = dev;
   3669 
   3670     return 0;
   3671 
   3672 free_device:
   3673     free(dev);
   3674     return ret;
   3675 }
   3676 
   3677 /* Consider devices located on the same bus as duplicate and fold the respective
   3678  * entries into a single one.
   3679  *
   3680  * Note: this leaves "gaps" in the array, while preserving the length.
   3681  */
   3682 static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
   3683 {
   3684     int node_type, i, j;
   3685 
   3686     for (i = 0; i < count; i++) {
   3687         for (j = i + 1; j < count; j++) {
   3688             if (drmDevicesEqual(local_devices[i], local_devices[j])) {
   3689                 local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
   3690                 node_type = log2(local_devices[j]->available_nodes);
   3691                 memcpy(local_devices[i]->nodes[node_type],
   3692                        local_devices[j]->nodes[node_type], drmGetMaxNodeName());
   3693                 drmFreeDevice(&local_devices[j]);
   3694             }
   3695         }
   3696     }
   3697 }
   3698 
   3699 /* Check that the given flags are valid returning 0 on success */
   3700 static int
   3701 drm_device_validate_flags(uint32_t flags)
   3702 {
   3703         return (flags & ~DRM_DEVICE_GET_PCI_REVISION);
   3704 }
   3705 
   3706 /**
   3707  * Get information about the opened drm device
   3708  *
   3709  * \param fd file descriptor of the drm device
   3710  * \param flags feature/behaviour bitmask
   3711  * \param device the address of a drmDevicePtr where the information
   3712  *               will be allocated in stored
   3713  *
   3714  * \return zero on success, negative error code otherwise.
   3715  *
   3716  * \note Unlike drmGetDevice it does not retrieve the pci device revision field
   3717  * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
   3718  */
   3719 int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
   3720 {
   3721 #ifdef __OpenBSD__
   3722     /*
   3723      * DRI device nodes on OpenBSD are not in their own directory, they reside
   3724      * in /dev along with a large number of statically generated /dev nodes.
   3725      * Avoid stat'ing all of /dev needlessly by implementing this custom path.
   3726      */
   3727     drmDevicePtr     d;
   3728     struct stat      sbuf;
   3729     char             node[PATH_MAX + 1];
   3730     const char      *dev_name;
   3731     int              node_type, subsystem_type;
   3732     int              maj, min, n, ret, base;
   3733 
   3734     if (fd == -1 || device == NULL)
   3735         return -EINVAL;
   3736 
   3737     if (fstat(fd, &sbuf))
   3738         return -errno;
   3739 
   3740     maj = major(sbuf.st_rdev);
   3741     min = minor(sbuf.st_rdev);
   3742 
   3743     if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
   3744         return -EINVAL;
   3745 
   3746     node_type = drmGetMinorType(min);
   3747     if (node_type == -1)
   3748         return -ENODEV;
   3749 
   3750     switch (node_type) {
   3751     case DRM_NODE_PRIMARY:
   3752         dev_name = DRM_DEV_NAME;
   3753         break;
   3754     case DRM_NODE_CONTROL:
   3755         dev_name = DRM_CONTROL_DEV_NAME;
   3756         break;
   3757     case DRM_NODE_RENDER:
   3758         dev_name = DRM_RENDER_DEV_NAME;
   3759         break;
   3760     default:
   3761         return -EINVAL;
   3762     };
   3763 
   3764     base = drmGetMinorBase(node_type);
   3765     if (base < 0)
   3766         return -EINVAL;
   3767 
   3768     n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base);
   3769     if (n == -1 || n >= PATH_MAX)
   3770       return -errno;
   3771     if (stat(node, &sbuf))
   3772         return -EINVAL;
   3773 
   3774     subsystem_type = drmParseSubsystemType(maj, min);
   3775     if (subsystem_type != DRM_BUS_PCI)
   3776         return -ENODEV;
   3777 
   3778     ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
   3779     if (ret)
   3780         return ret;
   3781 
   3782     *device = d;
   3783 
   3784     return 0;
   3785 #else
   3786     drmDevicePtr *local_devices;
   3787     drmDevicePtr d;
   3788     DIR *sysdir;
   3789     struct dirent *dent;
   3790     struct stat sbuf;
   3791     char node[PATH_MAX + 1];
   3792     int node_type, subsystem_type;
   3793     int maj, min;
   3794     int ret, i, node_count;
   3795     int max_count = 16;
   3796     dev_t find_rdev;
   3797 
   3798     if (drm_device_validate_flags(flags))
   3799         return -EINVAL;
   3800 
   3801     if (fd == -1 || device == NULL)
   3802         return -EINVAL;
   3803 
   3804     if (fstat(fd, &sbuf))
   3805         return -errno;
   3806 
   3807     find_rdev = sbuf.st_rdev;
   3808     maj = major(sbuf.st_rdev);
   3809     min = minor(sbuf.st_rdev);
   3810 
   3811     if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
   3812         return -EINVAL;
   3813 
   3814     subsystem_type = drmParseSubsystemType(maj, min);
   3815 
   3816     local_devices = calloc(max_count, sizeof(drmDevicePtr));
   3817     if (local_devices == NULL)
   3818         return -ENOMEM;
   3819 
   3820     sysdir = opendir(DRM_DIR_NAME);
   3821     if (!sysdir) {
   3822         ret = -errno;
   3823         goto free_locals;
   3824     }
   3825 
   3826     i = 0;
   3827     while ((dent = readdir(sysdir))) {
   3828         node_type = drmGetNodeType(dent->d_name);
   3829         if (node_type < 0)
   3830             continue;
   3831 
   3832         snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
   3833         if (stat(node, &sbuf))
   3834             continue;
   3835 
   3836         maj = major(sbuf.st_rdev);
   3837         min = minor(sbuf.st_rdev);
   3838 
   3839         if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
   3840             continue;
   3841 
   3842         if (drmParseSubsystemType(maj, min) != subsystem_type)
   3843             continue;
   3844 
   3845         switch (subsystem_type) {
   3846         case DRM_BUS_PCI:
   3847             ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
   3848             if (ret)
   3849                 continue;
   3850 
   3851             break;
   3852 
   3853         case DRM_BUS_USB:
   3854             ret = drmProcessUsbDevice(&d, node, node_type, maj, min, true, flags);
   3855             if (ret)
   3856                 continue;
   3857 
   3858             break;
   3859 
   3860         case DRM_BUS_PLATFORM:
   3861             ret = drmProcessPlatformDevice(&d, node, node_type, maj, min, true, flags);
   3862             if (ret)
   3863                 continue;
   3864 
   3865             break;
   3866 
   3867         case DRM_BUS_HOST1X:
   3868             ret = drmProcessHost1xDevice(&d, node, node_type, maj, min, true, flags);
   3869             if (ret)
   3870                 continue;
   3871 
   3872             break;
   3873 
   3874         default:
   3875             continue;
   3876         }
   3877 
   3878         if (i >= max_count) {
   3879             drmDevicePtr *temp;
   3880 
   3881             max_count += 16;
   3882             temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
   3883             if (!temp)
   3884                 goto free_devices;
   3885             local_devices = temp;
   3886         }
   3887 
   3888         /* store target at local_devices[0] for ease to use below */
   3889         if (find_rdev == sbuf.st_rdev && i) {
   3890             local_devices[i] = local_devices[0];
   3891             local_devices[0] = d;
   3892         }
   3893         else
   3894             local_devices[i] = d;
   3895         i++;
   3896     }
   3897     node_count = i;
   3898 
   3899     drmFoldDuplicatedDevices(local_devices, node_count);
   3900 
   3901     *device = local_devices[0];
   3902     drmFreeDevices(&local_devices[1], node_count - 1);
   3903 
   3904     closedir(sysdir);
   3905     free(local_devices);
   3906     if (*device == NULL)
   3907         return -ENODEV;
   3908     return 0;
   3909 
   3910 free_devices:
   3911     drmFreeDevices(local_devices, i);
   3912     closedir(sysdir);
   3913 
   3914 free_locals:
   3915     free(local_devices);
   3916     return ret;
   3917 #endif
   3918 }
   3919 
   3920 /**
   3921  * Get information about the opened drm device
   3922  *
   3923  * \param fd file descriptor of the drm device
   3924  * \param device the address of a drmDevicePtr where the information
   3925  *               will be allocated in stored
   3926  *
   3927  * \return zero on success, negative error code otherwise.
   3928  */
   3929 int drmGetDevice(int fd, drmDevicePtr *device)
   3930 {
   3931     return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device);
   3932 }
   3933 
   3934 /**
   3935  * Get drm devices on the system
   3936  *
   3937  * \param flags feature/behaviour bitmask
   3938  * \param devices the array of devices with drmDevicePtr elements
   3939  *                can be NULL to get the device number first
   3940  * \param max_devices the maximum number of devices for the array
   3941  *
   3942  * \return on error - negative error code,
   3943  *         if devices is NULL - total number of devices available on the system,
   3944  *         alternatively the number of devices stored in devices[], which is
   3945  *         capped by the max_devices.
   3946  *
   3947  * \note Unlike drmGetDevices it does not retrieve the pci device revision field
   3948  * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
   3949  */
   3950 int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices)
   3951 {
   3952     drmDevicePtr *local_devices;
   3953     drmDevicePtr device;
   3954     DIR *sysdir;
   3955     struct dirent *dent;
   3956     struct stat sbuf;
   3957     char node[PATH_MAX + 1];
   3958     int node_type, subsystem_type;
   3959     int maj, min;
   3960     int ret, i, node_count, device_count;
   3961     int max_count = 16;
   3962 
   3963     if (drm_device_validate_flags(flags))
   3964         return -EINVAL;
   3965 
   3966     local_devices = calloc(max_count, sizeof(drmDevicePtr));
   3967     if (local_devices == NULL)
   3968         return -ENOMEM;
   3969 
   3970     sysdir = opendir(DRM_DIR_NAME);
   3971     if (!sysdir) {
   3972         ret = -errno;
   3973         goto free_locals;
   3974     }
   3975 
   3976     i = 0;
   3977     while ((dent = readdir(sysdir))) {
   3978         node_type = drmGetNodeType(dent->d_name);
   3979         if (node_type < 0)
   3980             continue;
   3981 
   3982         snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
   3983         if (stat(node, &sbuf))
   3984             continue;
   3985 
   3986         maj = major(sbuf.st_rdev);
   3987         min = minor(sbuf.st_rdev);
   3988 
   3989         if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
   3990             continue;
   3991 
   3992         subsystem_type = drmParseSubsystemType(maj, min);
   3993 
   3994         if (subsystem_type < 0)
   3995             continue;
   3996 
   3997         switch (subsystem_type) {
   3998         case DRM_BUS_PCI:
   3999             ret = drmProcessPciDevice(&device, node, node_type,
   4000                                       maj, min, devices != NULL, flags);
   4001             if (ret)
   4002                 continue;
   4003 
   4004             break;
   4005 
   4006         case DRM_BUS_USB:
   4007             ret = drmProcessUsbDevice(&device, node, node_type, maj, min,
   4008                                       devices != NULL, flags);
   4009             if (ret)
   4010                 continue;
   4011 
   4012             break;
   4013 
   4014         case DRM_BUS_PLATFORM:
   4015             ret = drmProcessPlatformDevice(&device, node, node_type, maj, min,
   4016                                            devices != NULL, flags);
   4017             if (ret)
   4018                 continue;
   4019 
   4020             break;
   4021 
   4022         case DRM_BUS_HOST1X:
   4023             ret = drmProcessHost1xDevice(&device, node, node_type, maj, min,
   4024                                          devices != NULL, flags);
   4025             if (ret)
   4026                 continue;
   4027 
   4028             break;
   4029 
   4030         default:
   4031             continue;
   4032         }
   4033 
   4034         if (i >= max_count) {
   4035             drmDevicePtr *temp;
   4036 
   4037             max_count += 16;
   4038             temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
   4039             if (!temp)
   4040                 goto free_devices;
   4041             local_devices = temp;
   4042         }
   4043 
   4044         local_devices[i] = device;
   4045         i++;
   4046     }
   4047     node_count = i;
   4048 
   4049     drmFoldDuplicatedDevices(local_devices, node_count);
   4050 
   4051     device_count = 0;
   4052     for (i = 0; i < node_count; i++) {
   4053         if (!local_devices[i])
   4054             continue;
   4055 
   4056         if ((devices != NULL) && (device_count < max_devices))
   4057             devices[device_count] = local_devices[i];
   4058         else
   4059             drmFreeDevice(&local_devices[i]);
   4060 
   4061         device_count++;
   4062     }
   4063 
   4064     closedir(sysdir);
   4065     free(local_devices);
   4066     return device_count;
   4067 
   4068 free_devices:
   4069     drmFreeDevices(local_devices, i);
   4070     closedir(sysdir);
   4071 
   4072 free_locals:
   4073     free(local_devices);
   4074     return ret;
   4075 }
   4076 
   4077 /**
   4078  * Get drm devices on the system
   4079  *
   4080  * \param devices the array of devices with drmDevicePtr elements
   4081  *                can be NULL to get the device number first
   4082  * \param max_devices the maximum number of devices for the array
   4083  *
   4084  * \return on error - negative error code,
   4085  *         if devices is NULL - total number of devices available on the system,
   4086  *         alternatively the number of devices stored in devices[], which is
   4087  *         capped by the max_devices.
   4088  */
   4089 int drmGetDevices(drmDevicePtr devices[], int max_devices)
   4090 {
   4091     return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices);
   4092 }
   4093 
   4094 char *drmGetDeviceNameFromFd2(int fd)
   4095 {
   4096 #ifdef __linux__
   4097     struct stat sbuf;
   4098     char path[PATH_MAX + 1], *value;
   4099     unsigned int maj, min;
   4100 
   4101     if (fstat(fd, &sbuf))
   4102         return NULL;
   4103 
   4104     maj = major(sbuf.st_rdev);
   4105     min = minor(sbuf.st_rdev);
   4106 
   4107     if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
   4108         return NULL;
   4109 
   4110     snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min);
   4111 
   4112     value = sysfs_uevent_get(path, "DEVNAME");
   4113     if (!value)
   4114         return NULL;
   4115 
   4116     snprintf(path, sizeof(path), "/dev/%s", value);
   4117     free(value);
   4118 
   4119     return strdup(path);
   4120 #else
   4121     struct stat      sbuf;
   4122     char             node[PATH_MAX + 1];
   4123     const char      *dev_name;
   4124     int              node_type;
   4125     int              maj, min, n, base;
   4126 
   4127     if (fstat(fd, &sbuf))
   4128         return NULL;
   4129 
   4130     maj = major(sbuf.st_rdev);
   4131     min = minor(sbuf.st_rdev);
   4132 
   4133     if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
   4134         return NULL;
   4135 
   4136     node_type = drmGetMinorType(min);
   4137     if (node_type == -1)
   4138         return NULL;
   4139 
   4140     switch (node_type) {
   4141     case DRM_NODE_PRIMARY:
   4142         dev_name = DRM_DEV_NAME;
   4143         break;
   4144     case DRM_NODE_CONTROL:
   4145         dev_name = DRM_CONTROL_DEV_NAME;
   4146         break;
   4147     case DRM_NODE_RENDER:
   4148         dev_name = DRM_RENDER_DEV_NAME;
   4149         break;
   4150     default:
   4151         return NULL;
   4152     };
   4153 
   4154     base = drmGetMinorBase(node_type);
   4155     if (base < 0)
   4156         return NULL;
   4157 
   4158     n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base);
   4159     if (n == -1 || n >= PATH_MAX)
   4160       return NULL;
   4161 
   4162     return strdup(node);
   4163 #endif
   4164 }
   4165 
   4166 int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle)
   4167 {
   4168     struct drm_syncobj_create args;
   4169     int ret;
   4170 
   4171     memclear(args);
   4172     args.flags = flags;
   4173     args.handle = 0;
   4174     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args);
   4175     if (ret)
   4176         return ret;
   4177     *handle = args.handle;
   4178     return 0;
   4179 }
   4180 
   4181 int drmSyncobjDestroy(int fd, uint32_t handle)
   4182 {
   4183     struct drm_syncobj_destroy args;
   4184 
   4185     memclear(args);
   4186     args.handle = handle;
   4187     return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args);
   4188 }
   4189 
   4190 int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd)
   4191 {
   4192     struct drm_syncobj_handle args;
   4193     int ret;
   4194 
   4195     memclear(args);
   4196     args.fd = -1;
   4197     args.handle = handle;
   4198     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
   4199     if (ret)
   4200         return ret;
   4201     *obj_fd = args.fd;
   4202     return 0;
   4203 }
   4204 
   4205 int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle)
   4206 {
   4207     struct drm_syncobj_handle args;
   4208     int ret;
   4209 
   4210     memclear(args);
   4211     args.fd = obj_fd;
   4212     args.handle = 0;
   4213     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
   4214     if (ret)
   4215         return ret;
   4216     *handle = args.handle;
   4217     return 0;
   4218 }
   4219 
   4220 int drmSyncobjImportSyncFile(int fd, uint32_t handle, int sync_file_fd)
   4221 {
   4222     struct drm_syncobj_handle args;
   4223 
   4224     memclear(args);
   4225     args.fd = sync_file_fd;
   4226     args.handle = handle;
   4227     args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE;
   4228     return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
   4229 }
   4230 
   4231 int drmSyncobjExportSyncFile(int fd, uint32_t handle, int *sync_file_fd)
   4232 {
   4233     struct drm_syncobj_handle args;
   4234     int ret;
   4235 
   4236     memclear(args);
   4237     args.fd = -1;
   4238     args.handle = handle;
   4239     args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE;
   4240     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
   4241     if (ret)
   4242         return ret;
   4243     *sync_file_fd = args.fd;
   4244     return 0;
   4245 }
   4246 
   4247 int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles,
   4248                    int64_t timeout_nsec, unsigned flags,
   4249                    uint32_t *first_signaled)
   4250 {
   4251     struct drm_syncobj_wait args;
   4252     int ret;
   4253 
   4254     memclear(args);
   4255     args.handles = (uintptr_t)handles;
   4256     args.timeout_nsec = timeout_nsec;
   4257     args.count_handles = num_handles;
   4258     args.flags = flags;
   4259 
   4260     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args);
   4261     if (ret < 0)
   4262         return -errno;
   4263 
   4264     if (first_signaled)
   4265         *first_signaled = args.first_signaled;
   4266     return ret;
   4267 }
   4268 
   4269 int drmSyncobjReset(int fd, const uint32_t *handles, uint32_t handle_count)
   4270 {
   4271     struct drm_syncobj_array args;
   4272     int ret;
   4273 
   4274     memclear(args);
   4275     args.handles = (uintptr_t)handles;
   4276     args.count_handles = handle_count;
   4277 
   4278     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args);
   4279     return ret;
   4280 }
   4281 
   4282 int drmSyncobjSignal(int fd, const uint32_t *handles, uint32_t handle_count)
   4283 {
   4284     struct drm_syncobj_array args;
   4285     int ret;
   4286 
   4287     memclear(args);
   4288     args.handles = (uintptr_t)handles;
   4289     args.count_handles = handle_count;
   4290 
   4291     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args);
   4292     return ret;
   4293 }
   4294