OSDN Git Service

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