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