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