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