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