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