OSDN Git Service

a9f5c29469f8b0c91d6ef5d0ba21201af58071eb
[android-x86/external-libdrm.git] / xf86drm.c
1 /**
2  * \file xf86drm.c 
3  * User-level interface to DRM device
4  *
5  * \author Rickard E. (Rik) Faith <faith@valinux.com>
6  * \author Kevin E. Martin <martin@valinux.com>
7  */
8
9 /*
10  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
11  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
12  * All Rights Reserved.
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the "Software"),
16  * to deal in the Software without restriction, including without limitation
17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  * and/or sell copies of the Software, and to permit persons to whom the
19  * Software is furnished to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice (including the next
22  * paragraph) shall be included in all copies or substantial portions of the
23  * Software.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
28  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
29  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
30  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31  * DEALINGS IN THE SOFTWARE.
32  */
33
34 #ifdef HAVE_CONFIG_H
35 # include <config.h>
36 #endif
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <stdbool.h>
40 #include <unistd.h>
41 #include <string.h>
42 #include <strings.h>
43 #include <ctype.h>
44 #include <dirent.h>
45 #include <stddef.h>
46 #include <fcntl.h>
47 #include <errno.h>
48 #include <signal.h>
49 #include <time.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #define stat_t struct stat
53 #include <sys/ioctl.h>
54 #include <sys/time.h>
55 #include <stdarg.h>
56 #ifdef HAVE_SYS_MKDEV_H
57 # include <sys/mkdev.h> /* defines major(), minor(), and makedev() on Solaris */
58 #endif
59 #include <math.h>
60
61 /* Not all systems have MAP_FAILED defined */
62 #ifndef MAP_FAILED
63 #define MAP_FAILED ((void *)-1)
64 #endif
65
66 #include "xf86drm.h"
67 #include "libdrm_macros.h"
68
69 #include "util_math.h"
70
71 #ifdef __OpenBSD__
72 #define DRM_PRIMARY_MINOR_NAME  "drm"
73 #define DRM_CONTROL_MINOR_NAME  "drmC"
74 #define DRM_RENDER_MINOR_NAME   "drmR"
75 #else
76 #define DRM_PRIMARY_MINOR_NAME  "card"
77 #define DRM_CONTROL_MINOR_NAME  "controlD"
78 #define DRM_RENDER_MINOR_NAME   "renderD"
79 #endif
80
81 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
82 #define DRM_MAJOR 145
83 #endif
84
85 #ifdef __NetBSD__
86 #define DRM_MAJOR 34
87 #endif
88
89 #ifdef __OpenBSD__
90 #ifdef __i386__
91 #define DRM_MAJOR 88
92 #else
93 #define DRM_MAJOR 87
94 #endif
95 #endif /* __OpenBSD__ */
96
97 #ifndef DRM_MAJOR
98 #define DRM_MAJOR 226           /* Linux */
99 #endif
100
101 #define DRM_MSG_VERBOSITY 3
102
103 #define memclear(s) memset(&s, 0, sizeof(s))
104
105 static drmServerInfoPtr drm_server_info;
106
107 void drmSetServerInfo(drmServerInfoPtr info)
108 {
109     drm_server_info = info;
110 }
111
112 /**
113  * Output a message to stderr.
114  *
115  * \param format printf() like format string.
116  *
117  * \internal
118  * This function is a wrapper around vfprintf().
119  */
120
121 static int DRM_PRINTFLIKE(1, 0)
122 drmDebugPrint(const char *format, va_list ap)
123 {
124     return vfprintf(stderr, format, ap);
125 }
126
127 void
128 drmMsg(const char *format, ...)
129 {
130     va_list     ap;
131     const char *env;
132     if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) ||
133         (drm_server_info && drm_server_info->debug_print))
134     {
135         va_start(ap, format);
136         if (drm_server_info) {
137           drm_server_info->debug_print(format,ap);
138         } else {
139           drmDebugPrint(format, ap);
140         }
141         va_end(ap);
142     }
143 }
144
145 static void *drmHashTable = NULL; /* Context switch callbacks */
146
147 void *drmGetHashTable(void)
148 {
149     return drmHashTable;
150 }
151
152 void *drmMalloc(int size)
153 {
154     return calloc(1, size);
155 }
156
157 void drmFree(void *pt)
158 {
159     free(pt);
160 }
161
162 /**
163  * Call ioctl, restarting if it is interupted
164  */
165 int
166 drmIoctl(int fd, unsigned long request, void *arg)
167 {
168     int ret;
169
170     do {
171         ret = ioctl(fd, request, arg);
172     } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
173     return ret;
174 }
175
176 static unsigned long drmGetKeyFromFd(int fd)
177 {
178     stat_t     st;
179
180     st.st_rdev = 0;
181     fstat(fd, &st);
182     return st.st_rdev;
183 }
184
185 drmHashEntry *drmGetEntry(int fd)
186 {
187     unsigned long key = drmGetKeyFromFd(fd);
188     void          *value;
189     drmHashEntry  *entry;
190
191     if (!drmHashTable)
192         drmHashTable = drmHashCreate();
193
194     if (drmHashLookup(drmHashTable, key, &value)) {
195         entry           = drmMalloc(sizeof(*entry));
196         entry->fd       = fd;
197         entry->f        = NULL;
198         entry->tagTable = drmHashCreate();
199         drmHashInsert(drmHashTable, key, entry);
200     } else {
201         entry = value;
202     }
203     return entry;
204 }
205
206 /**
207  * Compare two busid strings
208  *
209  * \param first
210  * \param second
211  *
212  * \return 1 if matched.
213  *
214  * \internal
215  * This function compares two bus ID strings.  It understands the older
216  * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format.  In the format, o is
217  * domain, b is bus, d is device, f is function.
218  */
219 static int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
220 {
221     /* First, check if the IDs are exactly the same */
222     if (strcasecmp(id1, id2) == 0)
223         return 1;
224
225     /* Try to match old/new-style PCI bus IDs. */
226     if (strncasecmp(id1, "pci", 3) == 0) {
227         unsigned int o1, b1, d1, f1;
228         unsigned int o2, b2, d2, f2;
229         int ret;
230
231         ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
232         if (ret != 4) {
233             o1 = 0;
234             ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
235             if (ret != 3)
236                 return 0;
237         }
238
239         ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
240         if (ret != 4) {
241             o2 = 0;
242             ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
243             if (ret != 3)
244                 return 0;
245         }
246
247         /* If domains aren't properly supported by the kernel interface,
248          * just ignore them, which sucks less than picking a totally random
249          * card with "open by name"
250          */
251         if (!pci_domain_ok)
252                 o1 = o2 = 0;
253
254         if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
255             return 0;
256         else
257             return 1;
258     }
259     return 0;
260 }
261
262 /**
263  * Handles error checking for chown call.
264  *
265  * \param path to file.
266  * \param id of the new owner.
267  * \param id of the new group.
268  *
269  * \return zero if success or -1 if failure.
270  *
271  * \internal
272  * Checks for failure. If failure was caused by signal call chown again.
273  * If any other failure happened then it will output error mesage using
274  * drmMsg() call.
275  */
276 #if !defined(UDEV)
277 static int chown_check_return(const char *path, uid_t owner, gid_t group)
278 {
279         int rv;
280
281         do {
282                 rv = chown(path, owner, group);
283         } while (rv != 0 && errno == EINTR);
284
285         if (rv == 0)
286                 return 0;
287
288         drmMsg("Failed to change owner or group for file %s! %d: %s\n",
289                         path, errno, strerror(errno));
290         return -1;
291 }
292 #endif
293
294 /**
295  * Open the DRM device, creating it if necessary.
296  *
297  * \param dev major and minor numbers of the device.
298  * \param minor minor number of the device.
299  * 
300  * \return a file descriptor on success, or a negative value on error.
301  *
302  * \internal
303  * Assembles the device name from \p minor and opens it, creating the device
304  * special file node with the major and minor numbers specified by \p dev and
305  * parent directory if necessary and was called by root.
306  */
307 static int drmOpenDevice(dev_t dev, int minor, int type)
308 {
309     stat_t          st;
310     const char      *dev_name;
311     char            buf[64];
312     int             fd;
313     mode_t          devmode = DRM_DEV_MODE, serv_mode;
314     gid_t           serv_group;
315 #if !defined(UDEV)
316     int             isroot  = !geteuid();
317     uid_t           user    = DRM_DEV_UID;
318     gid_t           group   = DRM_DEV_GID;
319 #endif
320
321     switch (type) {
322     case DRM_NODE_PRIMARY:
323             dev_name = DRM_DEV_NAME;
324             break;
325     case DRM_NODE_CONTROL:
326             dev_name = DRM_CONTROL_DEV_NAME;
327             break;
328     case DRM_NODE_RENDER:
329             dev_name = DRM_RENDER_DEV_NAME;
330             break;
331     default:
332             return -EINVAL;
333     };
334
335     sprintf(buf, dev_name, DRM_DIR_NAME, minor);
336     drmMsg("drmOpenDevice: node name is %s\n", buf);
337
338     if (drm_server_info && drm_server_info->get_perms) {
339         drm_server_info->get_perms(&serv_group, &serv_mode);
340         devmode  = serv_mode ? serv_mode : DRM_DEV_MODE;
341         devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
342     }
343
344 #if !defined(UDEV)
345     if (stat(DRM_DIR_NAME, &st)) {
346         if (!isroot)
347             return DRM_ERR_NOT_ROOT;
348         mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
349         chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
350         chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
351     }
352
353     /* Check if the device node exists and create it if necessary. */
354     if (stat(buf, &st)) {
355         if (!isroot)
356             return DRM_ERR_NOT_ROOT;
357         remove(buf);
358         mknod(buf, S_IFCHR | devmode, dev);
359     }
360
361     if (drm_server_info && drm_server_info->get_perms) {
362         group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
363         chown_check_return(buf, user, group);
364         chmod(buf, devmode);
365     }
366 #else
367     /* if we modprobed then wait for udev */
368     {
369         int udev_count = 0;
370 wait_for_udev:
371         if (stat(DRM_DIR_NAME, &st)) {
372                 usleep(20);
373                 udev_count++;
374
375                 if (udev_count == 50)
376                         return -1;
377                 goto wait_for_udev;
378         }
379
380         if (stat(buf, &st)) {
381                 usleep(20);
382                 udev_count++;
383
384                 if (udev_count == 50)
385                         return -1;
386                 goto wait_for_udev;
387         }
388     }
389 #endif
390
391     fd = open(buf, O_RDWR, 0);
392     drmMsg("drmOpenDevice: open result is %d, (%s)\n",
393                 fd, fd < 0 ? strerror(errno) : "OK");
394     if (fd >= 0)
395         return fd;
396
397 #if !defined(UDEV)
398     /* Check if the device node is not what we expect it to be, and recreate it
399      * and try again if so.
400      */
401     if (st.st_rdev != dev) {
402         if (!isroot)
403             return DRM_ERR_NOT_ROOT;
404         remove(buf);
405         mknod(buf, S_IFCHR | devmode, dev);
406         if (drm_server_info && drm_server_info->get_perms) {
407             chown_check_return(buf, user, group);
408             chmod(buf, devmode);
409         }
410     }
411     fd = open(buf, O_RDWR, 0);
412     drmMsg("drmOpenDevice: open result is %d, (%s)\n",
413                 fd, fd < 0 ? strerror(errno) : "OK");
414     if (fd >= 0)
415         return fd;
416
417     drmMsg("drmOpenDevice: Open failed\n");
418     remove(buf);
419 #endif
420     return -errno;
421 }
422
423
424 /**
425  * Open the DRM device
426  *
427  * \param minor device minor number.
428  * \param create allow to create the device if set.
429  *
430  * \return a file descriptor on success, or a negative value on error.
431  * 
432  * \internal
433  * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
434  * name from \p minor and opens it.
435  */
436 static int drmOpenMinor(int minor, int create, int type)
437 {
438     int  fd;
439     char buf[64];
440     const char *dev_name;
441     
442     if (create)
443         return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
444     
445     switch (type) {
446     case DRM_NODE_PRIMARY:
447             dev_name = DRM_DEV_NAME;
448             break;
449     case DRM_NODE_CONTROL:
450             dev_name = DRM_CONTROL_DEV_NAME;
451             break;
452     case DRM_NODE_RENDER:
453             dev_name = DRM_RENDER_DEV_NAME;
454             break;
455     default:
456             return -EINVAL;
457     };
458
459     sprintf(buf, dev_name, DRM_DIR_NAME, minor);
460     if ((fd = open(buf, O_RDWR, 0)) >= 0)
461         return fd;
462     return -errno;
463 }
464
465
466 /**
467  * Determine whether the DRM kernel driver has been loaded.
468  * 
469  * \return 1 if the DRM driver is loaded, 0 otherwise.
470  *
471  * \internal 
472  * Determine the presence of the kernel driver by attempting to open the 0
473  * minor and get version information.  For backward compatibility with older
474  * Linux implementations, /proc/dri is also checked.
475  */
476 int drmAvailable(void)
477 {
478     drmVersionPtr version;
479     int           retval = 0;
480     int           fd;
481
482     if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
483 #ifdef __linux__
484         /* Try proc for backward Linux compatibility */
485         if (!access("/proc/dri/0", R_OK))
486             return 1;
487 #endif
488         return 0;
489     }
490     
491     if ((version = drmGetVersion(fd))) {
492         retval = 1;
493         drmFreeVersion(version);
494     }
495     close(fd);
496
497     return retval;
498 }
499
500 static int drmGetMinorBase(int type)
501 {
502     switch (type) {
503     case DRM_NODE_PRIMARY:
504         return 0;
505     case DRM_NODE_CONTROL:
506         return 64;
507     case DRM_NODE_RENDER:
508         return 128;
509     default:
510         return -1;
511     };
512 }
513
514 static int drmGetMinorType(int minor)
515 {
516     int type = minor >> 6;
517
518     if (minor < 0)
519         return -1;
520
521     switch (type) {
522     case DRM_NODE_PRIMARY:
523     case DRM_NODE_CONTROL:
524     case DRM_NODE_RENDER:
525         return type;
526     default:
527         return -1;
528     }
529 }
530
531 static const char *drmGetMinorName(int type)
532 {
533     switch (type) {
534     case DRM_NODE_PRIMARY:
535         return DRM_PRIMARY_MINOR_NAME;
536     case DRM_NODE_CONTROL:
537         return DRM_CONTROL_MINOR_NAME;
538     case DRM_NODE_RENDER:
539         return DRM_RENDER_MINOR_NAME;
540     default:
541         return NULL;
542     }
543 }
544
545 /**
546  * Open the device by bus ID.
547  *
548  * \param busid bus ID.
549  * \param type device node type.
550  *
551  * \return a file descriptor on success, or a negative value on error.
552  *
553  * \internal
554  * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
555  * comparing the device bus ID with the one supplied.
556  *
557  * \sa drmOpenMinor() and drmGetBusid().
558  */
559 static int drmOpenByBusid(const char *busid, int type)
560 {
561     int        i, pci_domain_ok = 1;
562     int        fd;
563     const char *buf;
564     drmSetVersion sv;
565     int        base = drmGetMinorBase(type);
566
567     if (base < 0)
568         return -1;
569
570     drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
571     for (i = base; i < base + DRM_MAX_MINOR; i++) {
572         fd = drmOpenMinor(i, 1, type);
573         drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
574         if (fd >= 0) {
575             /* We need to try for 1.4 first for proper PCI domain support
576              * and if that fails, we know the kernel is busted
577              */
578             sv.drm_di_major = 1;
579             sv.drm_di_minor = 4;
580             sv.drm_dd_major = -1;       /* Don't care */
581             sv.drm_dd_minor = -1;       /* Don't care */
582             if (drmSetInterfaceVersion(fd, &sv)) {
583 #ifndef __alpha__
584                 pci_domain_ok = 0;
585 #endif
586                 sv.drm_di_major = 1;
587                 sv.drm_di_minor = 1;
588                 sv.drm_dd_major = -1;       /* Don't care */
589                 sv.drm_dd_minor = -1;       /* Don't care */
590                 drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
591                 drmSetInterfaceVersion(fd, &sv);
592             }
593             buf = drmGetBusid(fd);
594             drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
595             if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
596                 drmFreeBusid(buf);
597                 return fd;
598             }
599             if (buf)
600                 drmFreeBusid(buf);
601             close(fd);
602         }
603     }
604     return -1;
605 }
606
607
608 /**
609  * Open the device by name.
610  *
611  * \param name driver name.
612  * \param type the device node type.
613  * 
614  * \return a file descriptor on success, or a negative value on error.
615  * 
616  * \internal
617  * This function opens the first minor number that matches the driver name and
618  * isn't already in use.  If it's in use it then it will already have a bus ID
619  * assigned.
620  * 
621  * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
622  */
623 static int drmOpenByName(const char *name, int type)
624 {
625     int           i;
626     int           fd;
627     drmVersionPtr version;
628     char *        id;
629     int           base = drmGetMinorBase(type);
630
631     if (base < 0)
632         return -1;
633
634     /*
635      * Open the first minor number that matches the driver name and isn't
636      * already in use.  If it's in use it will have a busid assigned already.
637      */
638     for (i = base; i < base + DRM_MAX_MINOR; i++) {
639         if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
640             if ((version = drmGetVersion(fd))) {
641                 if (!strcmp(version->name, name)) {
642                     drmFreeVersion(version);
643                     id = drmGetBusid(fd);
644                     drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
645                     if (!id || !*id) {
646                         if (id)
647                             drmFreeBusid(id);
648                         return fd;
649                     } else {
650                         drmFreeBusid(id);
651                     }
652                 } else {
653                     drmFreeVersion(version);
654                 }
655             }
656             close(fd);
657         }
658     }
659
660 #ifdef __linux__
661     /* Backward-compatibility /proc support */
662     for (i = 0; i < 8; i++) {
663         char proc_name[64], buf[512];
664         char *driver, *pt, *devstring;
665         int  retcode;
666         
667         sprintf(proc_name, "/proc/dri/%d/name", i);
668         if ((fd = open(proc_name, 0, 0)) >= 0) {
669             retcode = read(fd, buf, sizeof(buf)-1);
670             close(fd);
671             if (retcode) {
672                 buf[retcode-1] = '\0';
673                 for (driver = pt = buf; *pt && *pt != ' '; ++pt)
674                     ;
675                 if (*pt) { /* Device is next */
676                     *pt = '\0';
677                     if (!strcmp(driver, name)) { /* Match */
678                         for (devstring = ++pt; *pt && *pt != ' '; ++pt)
679                             ;
680                         if (*pt) { /* Found busid */
681                             return drmOpenByBusid(++pt, type);
682                         } else { /* No busid */
683                             return drmOpenDevice(strtol(devstring, NULL, 0),i, type);
684                         }
685                     }
686                 }
687             }
688         }
689     }
690 #endif
691
692     return -1;
693 }
694
695
696 /**
697  * Open the DRM device.
698  *
699  * Looks up the specified name and bus ID, and opens the device found.  The
700  * entry in /dev/dri is created if necessary and if called by root.
701  *
702  * \param name driver name. Not referenced if bus ID is supplied.
703  * \param busid bus ID. Zero if not known.
704  * 
705  * \return a file descriptor on success, or a negative value on error.
706  * 
707  * \internal
708  * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
709  * otherwise.
710  */
711 int drmOpen(const char *name, const char *busid)
712 {
713     return drmOpenWithType(name, busid, DRM_NODE_PRIMARY);
714 }
715
716 /**
717  * Open the DRM device with specified type.
718  *
719  * Looks up the specified name and bus ID, and opens the device found.  The
720  * entry in /dev/dri is created if necessary and if called by root.
721  *
722  * \param name driver name. Not referenced if bus ID is supplied.
723  * \param busid bus ID. Zero if not known.
724  * \param type the device node type to open, PRIMARY, CONTROL or RENDER
725  *
726  * \return a file descriptor on success, or a negative value on error.
727  *
728  * \internal
729  * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
730  * otherwise.
731  */
732 int drmOpenWithType(const char *name, const char *busid, int type)
733 {
734     if (!drmAvailable() && name != NULL && drm_server_info &&
735         drm_server_info->load_module) {
736         /* try to load the kernel module */
737         if (!drm_server_info->load_module(name)) {
738             drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
739             return -1;
740         }
741     }
742
743     if (busid) {
744         int fd = drmOpenByBusid(busid, type);
745         if (fd >= 0)
746             return fd;
747     }
748     
749     if (name)
750         return drmOpenByName(name, type);
751
752     return -1;
753 }
754
755 int drmOpenControl(int minor)
756 {
757     return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
758 }
759
760 int drmOpenRender(int minor)
761 {
762     return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
763 }
764
765 /**
766  * Free the version information returned by drmGetVersion().
767  *
768  * \param v pointer to the version information.
769  *
770  * \internal
771  * It frees the memory pointed by \p %v as well as all the non-null strings
772  * pointers in it.
773  */
774 void drmFreeVersion(drmVersionPtr v)
775 {
776     if (!v)
777         return;
778     drmFree(v->name);
779     drmFree(v->date);
780     drmFree(v->desc);
781     drmFree(v);
782 }
783
784
785 /**
786  * Free the non-public version information returned by the kernel.
787  *
788  * \param v pointer to the version information.
789  *
790  * \internal
791  * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
792  * the non-null strings pointers in it.
793  */
794 static void drmFreeKernelVersion(drm_version_t *v)
795 {
796     if (!v)
797         return;
798     drmFree(v->name);
799     drmFree(v->date);
800     drmFree(v->desc);
801     drmFree(v);
802 }
803
804
805 /**
806  * Copy version information.
807  * 
808  * \param d destination pointer.
809  * \param s source pointer.
810  * 
811  * \internal
812  * Used by drmGetVersion() to translate the information returned by the ioctl
813  * interface in a private structure into the public structure counterpart.
814  */
815 static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
816 {
817     d->version_major      = s->version_major;
818     d->version_minor      = s->version_minor;
819     d->version_patchlevel = s->version_patchlevel;
820     d->name_len           = s->name_len;
821     d->name               = strdup(s->name);
822     d->date_len           = s->date_len;
823     d->date               = strdup(s->date);
824     d->desc_len           = s->desc_len;
825     d->desc               = strdup(s->desc);
826 }
827
828
829 /**
830  * Query the driver version information.
831  *
832  * \param fd file descriptor.
833  * 
834  * \return pointer to a drmVersion structure which should be freed with
835  * drmFreeVersion().
836  * 
837  * \note Similar information is available via /proc/dri.
838  * 
839  * \internal
840  * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
841  * first with zeros to get the string lengths, and then the actually strings.
842  * It also null-terminates them since they might not be already.
843  */
844 drmVersionPtr drmGetVersion(int fd)
845 {
846     drmVersionPtr retval;
847     drm_version_t *version = drmMalloc(sizeof(*version));
848
849     memclear(*version);
850
851     if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
852         drmFreeKernelVersion(version);
853         return NULL;
854     }
855
856     if (version->name_len)
857         version->name    = drmMalloc(version->name_len + 1);
858     if (version->date_len)
859         version->date    = drmMalloc(version->date_len + 1);
860     if (version->desc_len)
861         version->desc    = drmMalloc(version->desc_len + 1);
862
863     if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
864         drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
865         drmFreeKernelVersion(version);
866         return NULL;
867     }
868
869     /* The results might not be null-terminated strings, so terminate them. */
870     if (version->name_len) version->name[version->name_len] = '\0';
871     if (version->date_len) version->date[version->date_len] = '\0';
872     if (version->desc_len) version->desc[version->desc_len] = '\0';
873
874     retval = drmMalloc(sizeof(*retval));
875     drmCopyVersion(retval, version);
876     drmFreeKernelVersion(version);
877     return retval;
878 }
879
880
881 /**
882  * Get version information for the DRM user space library.
883  * 
884  * This version number is driver independent.
885  * 
886  * \param fd file descriptor.
887  *
888  * \return version information.
889  * 
890  * \internal
891  * This function allocates and fills a drm_version structure with a hard coded
892  * version number.
893  */
894 drmVersionPtr drmGetLibVersion(int fd)
895 {
896     drm_version_t *version = drmMalloc(sizeof(*version));
897
898     /* Version history:
899      *   NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
900      *   revision 1.0.x = original DRM interface with no drmGetLibVersion
901      *                    entry point and many drm<Device> extensions
902      *   revision 1.1.x = added drmCommand entry points for device extensions
903      *                    added drmGetLibVersion to identify libdrm.a version
904      *   revision 1.2.x = added drmSetInterfaceVersion
905      *                    modified drmOpen to handle both busid and name
906      *   revision 1.3.x = added server + memory manager
907      */
908     version->version_major      = 1;
909     version->version_minor      = 3;
910     version->version_patchlevel = 0;
911
912     return (drmVersionPtr)version;
913 }
914
915 int drmGetCap(int fd, uint64_t capability, uint64_t *value)
916 {
917         struct drm_get_cap cap;
918         int ret;
919
920         memclear(cap);
921         cap.capability = capability;
922
923         ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
924         if (ret)
925                 return ret;
926
927         *value = cap.value;
928         return 0;
929 }
930
931 int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
932 {
933         struct drm_set_client_cap cap;
934
935         memclear(cap);
936         cap.capability = capability;
937         cap.value = value;
938
939         return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
940 }
941
942 /**
943  * Free the bus ID information.
944  *
945  * \param busid bus ID information string as given by drmGetBusid().
946  *
947  * \internal
948  * This function is just frees the memory pointed by \p busid.
949  */
950 void drmFreeBusid(const char *busid)
951 {
952     drmFree((void *)busid);
953 }
954
955
956 /**
957  * Get the bus ID of the device.
958  *
959  * \param fd file descriptor.
960  *
961  * \return bus ID string.
962  *
963  * \internal
964  * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
965  * get the string length and data, passing the arguments in a drm_unique
966  * structure.
967  */
968 char *drmGetBusid(int fd)
969 {
970     drm_unique_t u;
971
972     memclear(u);
973
974     if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
975         return NULL;
976     u.unique = drmMalloc(u.unique_len + 1);
977     if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
978         return NULL;
979     u.unique[u.unique_len] = '\0';
980
981     return u.unique;
982 }
983
984
985 /**
986  * Set the bus ID of the device.
987  *
988  * \param fd file descriptor.
989  * \param busid bus ID string.
990  *
991  * \return zero on success, negative on failure.
992  *
993  * \internal
994  * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
995  * the arguments in a drm_unique structure.
996  */
997 int drmSetBusid(int fd, const char *busid)
998 {
999     drm_unique_t u;
1000
1001     memclear(u);
1002     u.unique     = (char *)busid;
1003     u.unique_len = strlen(busid);
1004
1005     if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
1006         return -errno;
1007     }
1008     return 0;
1009 }
1010
1011 int drmGetMagic(int fd, drm_magic_t * magic)
1012 {
1013     drm_auth_t auth;
1014
1015     memclear(auth);
1016
1017     *magic = 0;
1018     if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
1019         return -errno;
1020     *magic = auth.magic;
1021     return 0;
1022 }
1023
1024 int drmAuthMagic(int fd, drm_magic_t magic)
1025 {
1026     drm_auth_t auth;
1027
1028     memclear(auth);
1029     auth.magic = magic;
1030     if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
1031         return -errno;
1032     return 0;
1033 }
1034
1035 /**
1036  * Specifies a range of memory that is available for mapping by a
1037  * non-root process.
1038  *
1039  * \param fd file descriptor.
1040  * \param offset usually the physical address. The actual meaning depends of
1041  * the \p type parameter. See below.
1042  * \param size of the memory in bytes.
1043  * \param type type of the memory to be mapped.
1044  * \param flags combination of several flags to modify the function actions.
1045  * \param handle will be set to a value that may be used as the offset
1046  * parameter for mmap().
1047  * 
1048  * \return zero on success or a negative value on error.
1049  *
1050  * \par Mapping the frame buffer
1051  * For the frame buffer
1052  * - \p offset will be the physical address of the start of the frame buffer,
1053  * - \p size will be the size of the frame buffer in bytes, and
1054  * - \p type will be DRM_FRAME_BUFFER.
1055  *
1056  * \par
1057  * The area mapped will be uncached. If MTRR support is available in the
1058  * kernel, the frame buffer area will be set to write combining. 
1059  *
1060  * \par Mapping the MMIO register area
1061  * For the MMIO register area,
1062  * - \p offset will be the physical address of the start of the register area,
1063  * - \p size will be the size of the register area bytes, and
1064  * - \p type will be DRM_REGISTERS.
1065  * \par
1066  * The area mapped will be uncached. 
1067  * 
1068  * \par Mapping the SAREA
1069  * For the SAREA,
1070  * - \p offset will be ignored and should be set to zero,
1071  * - \p size will be the desired size of the SAREA in bytes,
1072  * - \p type will be DRM_SHM.
1073  * 
1074  * \par
1075  * A shared memory area of the requested size will be created and locked in
1076  * kernel memory. This area may be mapped into client-space by using the handle
1077  * returned. 
1078  * 
1079  * \note May only be called by root.
1080  *
1081  * \internal
1082  * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
1083  * the arguments in a drm_map structure.
1084  */
1085 int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
1086               drmMapFlags flags, drm_handle_t *handle)
1087 {
1088     drm_map_t map;
1089
1090     memclear(map);
1091     map.offset  = offset;
1092     map.size    = size;
1093     map.type    = type;
1094     map.flags   = flags;
1095     if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
1096         return -errno;
1097     if (handle)
1098         *handle = (drm_handle_t)(uintptr_t)map.handle;
1099     return 0;
1100 }
1101
1102 int drmRmMap(int fd, drm_handle_t handle)
1103 {
1104     drm_map_t map;
1105
1106     memclear(map);
1107     map.handle = (void *)(uintptr_t)handle;
1108
1109     if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
1110         return -errno;
1111     return 0;
1112 }
1113
1114 /**
1115  * Make buffers available for DMA transfers.
1116  * 
1117  * \param fd file descriptor.
1118  * \param count number of buffers.
1119  * \param size size of each buffer.
1120  * \param flags buffer allocation flags.
1121  * \param agp_offset offset in the AGP aperture 
1122  *
1123  * \return number of buffers allocated, negative on error.
1124  *
1125  * \internal
1126  * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
1127  *
1128  * \sa drm_buf_desc.
1129  */
1130 int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
1131                int agp_offset)
1132 {
1133     drm_buf_desc_t request;
1134
1135     memclear(request);
1136     request.count     = count;
1137     request.size      = size;
1138     request.flags     = flags;
1139     request.agp_start = agp_offset;
1140
1141     if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
1142         return -errno;
1143     return request.count;
1144 }
1145
1146 int drmMarkBufs(int fd, double low, double high)
1147 {
1148     drm_buf_info_t info;
1149     int            i;
1150
1151     memclear(info);
1152
1153     if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1154         return -EINVAL;
1155
1156     if (!info.count)
1157         return -EINVAL;
1158
1159     if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1160         return -ENOMEM;
1161
1162     if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1163         int retval = -errno;
1164         drmFree(info.list);
1165         return retval;
1166     }
1167
1168     for (i = 0; i < info.count; i++) {
1169         info.list[i].low_mark  = low  * info.list[i].count;
1170         info.list[i].high_mark = high * info.list[i].count;
1171         if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
1172             int retval = -errno;
1173             drmFree(info.list);
1174             return retval;
1175         }
1176     }
1177     drmFree(info.list);
1178
1179     return 0;
1180 }
1181
1182 /**
1183  * Free buffers.
1184  *
1185  * \param fd file descriptor.
1186  * \param count number of buffers to free.
1187  * \param list list of buffers to be freed.
1188  *
1189  * \return zero on success, or a negative value on failure.
1190  * 
1191  * \note This function is primarily used for debugging.
1192  * 
1193  * \internal
1194  * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
1195  * the arguments in a drm_buf_free structure.
1196  */
1197 int drmFreeBufs(int fd, int count, int *list)
1198 {
1199     drm_buf_free_t request;
1200
1201     memclear(request);
1202     request.count = count;
1203     request.list  = list;
1204     if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
1205         return -errno;
1206     return 0;
1207 }
1208
1209
1210 /**
1211  * Close the device.
1212  *
1213  * \param fd file descriptor.
1214  *
1215  * \internal
1216  * This function closes the file descriptor.
1217  */
1218 int drmClose(int fd)
1219 {
1220     unsigned long key    = drmGetKeyFromFd(fd);
1221     drmHashEntry  *entry = drmGetEntry(fd);
1222
1223     drmHashDestroy(entry->tagTable);
1224     entry->fd       = 0;
1225     entry->f        = NULL;
1226     entry->tagTable = NULL;
1227
1228     drmHashDelete(drmHashTable, key);
1229     drmFree(entry);
1230
1231     return close(fd);
1232 }
1233
1234
1235 /**
1236  * Map a region of memory.
1237  *
1238  * \param fd file descriptor.
1239  * \param handle handle returned by drmAddMap().
1240  * \param size size in bytes. Must match the size used by drmAddMap().
1241  * \param address will contain the user-space virtual address where the mapping
1242  * begins.
1243  *
1244  * \return zero on success, or a negative value on failure.
1245  * 
1246  * \internal
1247  * This function is a wrapper for mmap().
1248  */
1249 int drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address)
1250 {
1251     static unsigned long pagesize_mask = 0;
1252
1253     if (fd < 0)
1254         return -EINVAL;
1255
1256     if (!pagesize_mask)
1257         pagesize_mask = getpagesize() - 1;
1258
1259     size = (size + pagesize_mask) & ~pagesize_mask;
1260
1261     *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
1262     if (*address == MAP_FAILED)
1263         return -errno;
1264     return 0;
1265 }
1266
1267
1268 /**
1269  * Unmap mappings obtained with drmMap().
1270  *
1271  * \param address address as given by drmMap().
1272  * \param size size in bytes. Must match the size used by drmMap().
1273  * 
1274  * \return zero on success, or a negative value on failure.
1275  *
1276  * \internal
1277  * This function is a wrapper for munmap().
1278  */
1279 int drmUnmap(drmAddress address, drmSize size)
1280 {
1281     return drm_munmap(address, size);
1282 }
1283
1284 drmBufInfoPtr drmGetBufInfo(int fd)
1285 {
1286     drm_buf_info_t info;
1287     drmBufInfoPtr  retval;
1288     int            i;
1289
1290     memclear(info);
1291
1292     if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1293         return NULL;
1294
1295     if (info.count) {
1296         if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1297             return NULL;
1298
1299         if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1300             drmFree(info.list);
1301             return NULL;
1302         }
1303
1304         retval = drmMalloc(sizeof(*retval));
1305         retval->count = info.count;
1306         retval->list  = drmMalloc(info.count * sizeof(*retval->list));
1307         for (i = 0; i < info.count; i++) {
1308             retval->list[i].count     = info.list[i].count;
1309             retval->list[i].size      = info.list[i].size;
1310             retval->list[i].low_mark  = info.list[i].low_mark;
1311             retval->list[i].high_mark = info.list[i].high_mark;
1312         }
1313         drmFree(info.list);
1314         return retval;
1315     }
1316     return NULL;
1317 }
1318
1319 /**
1320  * Map all DMA buffers into client-virtual space.
1321  *
1322  * \param fd file descriptor.
1323  *
1324  * \return a pointer to a ::drmBufMap structure.
1325  *
1326  * \note The client may not use these buffers until obtaining buffer indices
1327  * with drmDMA().
1328  * 
1329  * \internal
1330  * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
1331  * information about the buffers in a drm_buf_map structure into the
1332  * client-visible data structures.
1333  */ 
1334 drmBufMapPtr drmMapBufs(int fd)
1335 {
1336     drm_buf_map_t bufs;
1337     drmBufMapPtr  retval;
1338     int           i;
1339
1340     memclear(bufs);
1341     if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
1342         return NULL;
1343
1344     if (!bufs.count)
1345         return NULL;
1346
1347         if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
1348             return NULL;
1349
1350         if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
1351             drmFree(bufs.list);
1352             return NULL;
1353         }
1354
1355         retval = drmMalloc(sizeof(*retval));
1356         retval->count = bufs.count;
1357         retval->list  = drmMalloc(bufs.count * sizeof(*retval->list));
1358         for (i = 0; i < bufs.count; i++) {
1359             retval->list[i].idx     = bufs.list[i].idx;
1360             retval->list[i].total   = bufs.list[i].total;
1361             retval->list[i].used    = 0;
1362             retval->list[i].address = bufs.list[i].address;
1363         }
1364
1365         drmFree(bufs.list);
1366         
1367         return retval;
1368 }
1369
1370
1371 /**
1372  * Unmap buffers allocated with drmMapBufs().
1373  *
1374  * \return zero on success, or negative value on failure.
1375  *
1376  * \internal
1377  * Calls munmap() for every buffer stored in \p bufs and frees the
1378  * memory allocated by drmMapBufs().
1379  */
1380 int drmUnmapBufs(drmBufMapPtr bufs)
1381 {
1382     int i;
1383
1384     for (i = 0; i < bufs->count; i++) {
1385         drm_munmap(bufs->list[i].address, bufs->list[i].total);
1386     }
1387
1388     drmFree(bufs->list);
1389     drmFree(bufs);
1390         
1391     return 0;
1392 }
1393
1394
1395 #define DRM_DMA_RETRY           16
1396
1397 /**
1398  * Reserve DMA buffers.
1399  *
1400  * \param fd file descriptor.
1401  * \param request 
1402  * 
1403  * \return zero on success, or a negative value on failure.
1404  *
1405  * \internal
1406  * Assemble the arguments into a drm_dma structure and keeps issuing the
1407  * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
1408  */
1409 int drmDMA(int fd, drmDMAReqPtr request)
1410 {
1411     drm_dma_t dma;
1412     int ret, i = 0;
1413
1414     dma.context         = request->context;
1415     dma.send_count      = request->send_count;
1416     dma.send_indices    = request->send_list;
1417     dma.send_sizes      = request->send_sizes;
1418     dma.flags           = request->flags;
1419     dma.request_count   = request->request_count;
1420     dma.request_size    = request->request_size;
1421     dma.request_indices = request->request_list;
1422     dma.request_sizes   = request->request_sizes;
1423     dma.granted_count   = 0;
1424
1425     do {
1426         ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
1427     } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
1428
1429     if ( ret == 0 ) {
1430         request->granted_count = dma.granted_count;
1431         return 0;
1432     } else {
1433         return -errno;
1434     }
1435 }
1436
1437
1438 /**
1439  * Obtain heavyweight hardware lock.
1440  *
1441  * \param fd file descriptor.
1442  * \param context context.
1443  * \param flags flags that determine the sate of the hardware when the function
1444  * returns.
1445  * 
1446  * \return always zero.
1447  * 
1448  * \internal
1449  * This function translates the arguments into a drm_lock structure and issue
1450  * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
1451  */
1452 int drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
1453 {
1454     drm_lock_t lock;
1455
1456     memclear(lock);
1457     lock.context = context;
1458     lock.flags   = 0;
1459     if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
1460     if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
1461     if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
1462     if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
1463     if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
1464     if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
1465
1466     while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock))
1467         ;
1468     return 0;
1469 }
1470
1471 /**
1472  * Release the hardware lock.
1473  *
1474  * \param fd file descriptor.
1475  * \param context context.
1476  * 
1477  * \return zero on success, or a negative value on failure.
1478  * 
1479  * \internal
1480  * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
1481  * argument in a drm_lock structure.
1482  */
1483 int drmUnlock(int fd, drm_context_t context)
1484 {
1485     drm_lock_t lock;
1486
1487     memclear(lock);
1488     lock.context = context;
1489     return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
1490 }
1491
1492 drm_context_t *drmGetReservedContextList(int fd, int *count)
1493 {
1494     drm_ctx_res_t res;
1495     drm_ctx_t     *list;
1496     drm_context_t * retval;
1497     int           i;
1498
1499     memclear(res);
1500     if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
1501         return NULL;
1502
1503     if (!res.count)
1504         return NULL;
1505
1506     if (!(list   = drmMalloc(res.count * sizeof(*list))))
1507         return NULL;
1508     if (!(retval = drmMalloc(res.count * sizeof(*retval)))) {
1509         drmFree(list);
1510         return NULL;
1511     }
1512
1513     res.contexts = list;
1514     if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
1515         return NULL;
1516
1517     for (i = 0; i < res.count; i++)
1518         retval[i] = list[i].handle;
1519     drmFree(list);
1520
1521     *count = res.count;
1522     return retval;
1523 }
1524
1525 void drmFreeReservedContextList(drm_context_t *pt)
1526 {
1527     drmFree(pt);
1528 }
1529
1530 /**
1531  * Create context.
1532  *
1533  * Used by the X server during GLXContext initialization. This causes
1534  * per-context kernel-level resources to be allocated.
1535  *
1536  * \param fd file descriptor.
1537  * \param handle is set on success. To be used by the client when requesting DMA
1538  * dispatch with drmDMA().
1539  * 
1540  * \return zero on success, or a negative value on failure.
1541  * 
1542  * \note May only be called by root.
1543  * 
1544  * \internal
1545  * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
1546  * argument in a drm_ctx structure.
1547  */
1548 int drmCreateContext(int fd, drm_context_t *handle)
1549 {
1550     drm_ctx_t ctx;
1551
1552     memclear(ctx);
1553     if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
1554         return -errno;
1555     *handle = ctx.handle;
1556     return 0;
1557 }
1558
1559 int drmSwitchToContext(int fd, drm_context_t context)
1560 {
1561     drm_ctx_t ctx;
1562
1563     memclear(ctx);
1564     ctx.handle = context;
1565     if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
1566         return -errno;
1567     return 0;
1568 }
1569
1570 int drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags)
1571 {
1572     drm_ctx_t ctx;
1573
1574     /*
1575      * Context preserving means that no context switches are done between DMA
1576      * buffers from one context and the next.  This is suitable for use in the
1577      * X server (which promises to maintain hardware context), or in the
1578      * client-side library when buffers are swapped on behalf of two threads.
1579      */
1580     memclear(ctx);
1581     ctx.handle = context;
1582     if (flags & DRM_CONTEXT_PRESERVED)
1583         ctx.flags |= _DRM_CONTEXT_PRESERVED;
1584     if (flags & DRM_CONTEXT_2DONLY)
1585         ctx.flags |= _DRM_CONTEXT_2DONLY;
1586     if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
1587         return -errno;
1588     return 0;
1589 }
1590
1591 int drmGetContextFlags(int fd, drm_context_t context,
1592                        drm_context_tFlagsPtr flags)
1593 {
1594     drm_ctx_t ctx;
1595
1596     memclear(ctx);
1597     ctx.handle = context;
1598     if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
1599         return -errno;
1600     *flags = 0;
1601     if (ctx.flags & _DRM_CONTEXT_PRESERVED)
1602         *flags |= DRM_CONTEXT_PRESERVED;
1603     if (ctx.flags & _DRM_CONTEXT_2DONLY)
1604         *flags |= DRM_CONTEXT_2DONLY;
1605     return 0;
1606 }
1607
1608 /**
1609  * Destroy context.
1610  *
1611  * Free any kernel-level resources allocated with drmCreateContext() associated
1612  * with the context.
1613  * 
1614  * \param fd file descriptor.
1615  * \param handle handle given by drmCreateContext().
1616  * 
1617  * \return zero on success, or a negative value on failure.
1618  * 
1619  * \note May only be called by root.
1620  * 
1621  * \internal
1622  * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
1623  * argument in a drm_ctx structure.
1624  */
1625 int drmDestroyContext(int fd, drm_context_t handle)
1626 {
1627     drm_ctx_t ctx;
1628
1629     memclear(ctx);
1630     ctx.handle = handle;
1631     if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
1632         return -errno;
1633     return 0;
1634 }
1635
1636 int drmCreateDrawable(int fd, drm_drawable_t *handle)
1637 {
1638     drm_draw_t draw;
1639
1640     memclear(draw);
1641     if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
1642         return -errno;
1643     *handle = draw.handle;
1644     return 0;
1645 }
1646
1647 int drmDestroyDrawable(int fd, drm_drawable_t handle)
1648 {
1649     drm_draw_t draw;
1650
1651     memclear(draw);
1652     draw.handle = handle;
1653     if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
1654         return -errno;
1655     return 0;
1656 }
1657
1658 int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
1659                            drm_drawable_info_type_t type, unsigned int num,
1660                            void *data)
1661 {
1662     drm_update_draw_t update;
1663
1664     memclear(update);
1665     update.handle = handle;
1666     update.type = type;
1667     update.num = num;
1668     update.data = (unsigned long long)(unsigned long)data;
1669
1670     if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
1671         return -errno;
1672
1673     return 0;
1674 }
1675
1676 /**
1677  * Acquire the AGP device.
1678  *
1679  * Must be called before any of the other AGP related calls.
1680  *
1681  * \param fd file descriptor.
1682  * 
1683  * \return zero on success, or a negative value on failure.
1684  * 
1685  * \internal
1686  * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
1687  */
1688 int drmAgpAcquire(int fd)
1689 {
1690     if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
1691         return -errno;
1692     return 0;
1693 }
1694
1695
1696 /**
1697  * Release the AGP device.
1698  *
1699  * \param fd file descriptor.
1700  * 
1701  * \return zero on success, or a negative value on failure.
1702  * 
1703  * \internal
1704  * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
1705  */
1706 int drmAgpRelease(int fd)
1707 {
1708     if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
1709         return -errno;
1710     return 0;
1711 }
1712
1713
1714 /**
1715  * Set the AGP mode.
1716  *
1717  * \param fd file descriptor.
1718  * \param mode AGP mode.
1719  * 
1720  * \return zero on success, or a negative value on failure.
1721  * 
1722  * \internal
1723  * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
1724  * argument in a drm_agp_mode structure.
1725  */
1726 int drmAgpEnable(int fd, unsigned long mode)
1727 {
1728     drm_agp_mode_t m;
1729
1730     memclear(m);
1731     m.mode = mode;
1732     if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
1733         return -errno;
1734     return 0;
1735 }
1736
1737
1738 /**
1739  * Allocate a chunk of AGP memory.
1740  *
1741  * \param fd file descriptor.
1742  * \param size requested memory size in bytes. Will be rounded to page boundary.
1743  * \param type type of memory to allocate.
1744  * \param address if not zero, will be set to the physical address of the
1745  * allocated memory.
1746  * \param handle on success will be set to a handle of the allocated memory.
1747  * 
1748  * \return zero on success, or a negative value on failure.
1749  * 
1750  * \internal
1751  * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
1752  * arguments in a drm_agp_buffer structure.
1753  */
1754 int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
1755                 unsigned long *address, drm_handle_t *handle)
1756 {
1757     drm_agp_buffer_t b;
1758
1759     memclear(b);
1760     *handle = DRM_AGP_NO_HANDLE;
1761     b.size   = size;
1762     b.type   = type;
1763     if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
1764         return -errno;
1765     if (address != 0UL)
1766         *address = b.physical;
1767     *handle = b.handle;
1768     return 0;
1769 }
1770
1771
1772 /**
1773  * Free a chunk of AGP memory.
1774  *
1775  * \param fd file descriptor.
1776  * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1777  * 
1778  * \return zero on success, or a negative value on failure.
1779  * 
1780  * \internal
1781  * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
1782  * argument in a drm_agp_buffer structure.
1783  */
1784 int drmAgpFree(int fd, drm_handle_t handle)
1785 {
1786     drm_agp_buffer_t b;
1787
1788     memclear(b);
1789     b.handle = handle;
1790     if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
1791         return -errno;
1792     return 0;
1793 }
1794
1795
1796 /**
1797  * Bind a chunk of AGP memory.
1798  *
1799  * \param fd file descriptor.
1800  * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1801  * \param offset offset in bytes. It will round to page boundary.
1802  * 
1803  * \return zero on success, or a negative value on failure.
1804  * 
1805  * \internal
1806  * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
1807  * argument in a drm_agp_binding structure.
1808  */
1809 int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
1810 {
1811     drm_agp_binding_t b;
1812
1813     memclear(b);
1814     b.handle = handle;
1815     b.offset = offset;
1816     if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
1817         return -errno;
1818     return 0;
1819 }
1820
1821
1822 /**
1823  * Unbind a chunk of AGP memory.
1824  *
1825  * \param fd file descriptor.
1826  * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1827  * 
1828  * \return zero on success, or a negative value on failure.
1829  * 
1830  * \internal
1831  * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
1832  * the argument in a drm_agp_binding structure.
1833  */
1834 int drmAgpUnbind(int fd, drm_handle_t handle)
1835 {
1836     drm_agp_binding_t b;
1837
1838     memclear(b);
1839     b.handle = handle;
1840     if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
1841         return -errno;
1842     return 0;
1843 }
1844
1845
1846 /**
1847  * Get AGP driver major version number.
1848  *
1849  * \param fd file descriptor.
1850  * 
1851  * \return major version number on success, or a negative value on failure..
1852  * 
1853  * \internal
1854  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1855  * necessary information in a drm_agp_info structure.
1856  */
1857 int drmAgpVersionMajor(int fd)
1858 {
1859     drm_agp_info_t i;
1860
1861     memclear(i);
1862
1863     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1864         return -errno;
1865     return i.agp_version_major;
1866 }
1867
1868
1869 /**
1870  * Get AGP driver minor version number.
1871  *
1872  * \param fd file descriptor.
1873  * 
1874  * \return minor version number on success, or a negative value on failure.
1875  * 
1876  * \internal
1877  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1878  * necessary information in a drm_agp_info structure.
1879  */
1880 int drmAgpVersionMinor(int fd)
1881 {
1882     drm_agp_info_t i;
1883
1884     memclear(i);
1885
1886     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1887         return -errno;
1888     return i.agp_version_minor;
1889 }
1890
1891
1892 /**
1893  * Get AGP mode.
1894  *
1895  * \param fd file descriptor.
1896  * 
1897  * \return mode on success, or zero on failure.
1898  * 
1899  * \internal
1900  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1901  * necessary information in a drm_agp_info structure.
1902  */
1903 unsigned long drmAgpGetMode(int fd)
1904 {
1905     drm_agp_info_t i;
1906
1907     memclear(i);
1908
1909     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1910         return 0;
1911     return i.mode;
1912 }
1913
1914
1915 /**
1916  * Get AGP aperture base.
1917  *
1918  * \param fd file descriptor.
1919  * 
1920  * \return aperture base on success, zero on failure.
1921  * 
1922  * \internal
1923  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1924  * necessary information in a drm_agp_info structure.
1925  */
1926 unsigned long drmAgpBase(int fd)
1927 {
1928     drm_agp_info_t i;
1929
1930     memclear(i);
1931
1932     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1933         return 0;
1934     return i.aperture_base;
1935 }
1936
1937
1938 /**
1939  * Get AGP aperture size.
1940  *
1941  * \param fd file descriptor.
1942  * 
1943  * \return aperture size on success, zero on failure.
1944  * 
1945  * \internal
1946  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1947  * necessary information in a drm_agp_info structure.
1948  */
1949 unsigned long drmAgpSize(int fd)
1950 {
1951     drm_agp_info_t i;
1952
1953     memclear(i);
1954
1955     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1956         return 0;
1957     return i.aperture_size;
1958 }
1959
1960
1961 /**
1962  * Get used AGP memory.
1963  *
1964  * \param fd file descriptor.
1965  * 
1966  * \return memory used on success, or zero on failure.
1967  * 
1968  * \internal
1969  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1970  * necessary information in a drm_agp_info structure.
1971  */
1972 unsigned long drmAgpMemoryUsed(int fd)
1973 {
1974     drm_agp_info_t i;
1975
1976     memclear(i);
1977
1978     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1979         return 0;
1980     return i.memory_used;
1981 }
1982
1983
1984 /**
1985  * Get available AGP memory.
1986  *
1987  * \param fd file descriptor.
1988  * 
1989  * \return memory available on success, or zero on failure.
1990  * 
1991  * \internal
1992  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1993  * necessary information in a drm_agp_info structure.
1994  */
1995 unsigned long drmAgpMemoryAvail(int fd)
1996 {
1997     drm_agp_info_t i;
1998
1999     memclear(i);
2000
2001     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2002         return 0;
2003     return i.memory_allowed;
2004 }
2005
2006
2007 /**
2008  * Get hardware vendor ID.
2009  *
2010  * \param fd file descriptor.
2011  * 
2012  * \return vendor ID on success, or zero on failure.
2013  * 
2014  * \internal
2015  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2016  * necessary information in a drm_agp_info structure.
2017  */
2018 unsigned int drmAgpVendorId(int fd)
2019 {
2020     drm_agp_info_t i;
2021
2022     memclear(i);
2023
2024     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2025         return 0;
2026     return i.id_vendor;
2027 }
2028
2029
2030 /**
2031  * Get hardware device ID.
2032  *
2033  * \param fd file descriptor.
2034  * 
2035  * \return zero on success, or zero on failure.
2036  * 
2037  * \internal
2038  * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2039  * necessary information in a drm_agp_info structure.
2040  */
2041 unsigned int drmAgpDeviceId(int fd)
2042 {
2043     drm_agp_info_t i;
2044
2045     memclear(i);
2046
2047     if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2048         return 0;
2049     return i.id_device;
2050 }
2051
2052 int drmScatterGatherAlloc(int fd, unsigned long size, drm_handle_t *handle)
2053 {
2054     drm_scatter_gather_t sg;
2055
2056     memclear(sg);
2057
2058     *handle = 0;
2059     sg.size   = size;
2060     if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
2061         return -errno;
2062     *handle = sg.handle;
2063     return 0;
2064 }
2065
2066 int drmScatterGatherFree(int fd, drm_handle_t handle)
2067 {
2068     drm_scatter_gather_t sg;
2069
2070     memclear(sg);
2071     sg.handle = handle;
2072     if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
2073         return -errno;
2074     return 0;
2075 }
2076
2077 /**
2078  * Wait for VBLANK.
2079  *
2080  * \param fd file descriptor.
2081  * \param vbl pointer to a drmVBlank structure.
2082  * 
2083  * \return zero on success, or a negative value on failure.
2084  * 
2085  * \internal
2086  * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
2087  */
2088 int drmWaitVBlank(int fd, drmVBlankPtr vbl)
2089 {
2090     struct timespec timeout, cur;
2091     int ret;
2092
2093     ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
2094     if (ret < 0) {
2095         fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno));
2096         goto out;
2097     }
2098     timeout.tv_sec++;
2099
2100     do {
2101        ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
2102        vbl->request.type &= ~DRM_VBLANK_RELATIVE;
2103        if (ret && errno == EINTR) {
2104                clock_gettime(CLOCK_MONOTONIC, &cur);
2105                /* Timeout after 1s */
2106                if (cur.tv_sec > timeout.tv_sec + 1 ||
2107                    (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
2108                     timeout.tv_nsec)) {
2109                        errno = EBUSY;
2110                        ret = -1;
2111                        break;
2112                }
2113        }
2114     } while (ret && errno == EINTR);
2115
2116 out:
2117     return ret;
2118 }
2119
2120 int drmError(int err, const char *label)
2121 {
2122     switch (err) {
2123     case DRM_ERR_NO_DEVICE:
2124         fprintf(stderr, "%s: no device\n", label);
2125         break;
2126     case DRM_ERR_NO_ACCESS:
2127         fprintf(stderr, "%s: no access\n", label);
2128         break;
2129     case DRM_ERR_NOT_ROOT:
2130         fprintf(stderr, "%s: not root\n", label);
2131         break;
2132     case DRM_ERR_INVALID:
2133         fprintf(stderr, "%s: invalid args\n", label);
2134         break;
2135     default:
2136         if (err < 0)
2137             err = -err;
2138         fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
2139         break;
2140     }
2141
2142     return 1;
2143 }
2144
2145 /**
2146  * Install IRQ handler.
2147  *
2148  * \param fd file descriptor.
2149  * \param irq IRQ number.
2150  * 
2151  * \return zero on success, or a negative value on failure.
2152  * 
2153  * \internal
2154  * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
2155  * argument in a drm_control structure.
2156  */
2157 int drmCtlInstHandler(int fd, int irq)
2158 {
2159     drm_control_t ctl;
2160
2161     memclear(ctl);
2162     ctl.func  = DRM_INST_HANDLER;
2163     ctl.irq   = irq;
2164     if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2165         return -errno;
2166     return 0;
2167 }
2168
2169
2170 /**
2171  * Uninstall IRQ handler.
2172  *
2173  * \param fd file descriptor.
2174  * 
2175  * \return zero on success, or a negative value on failure.
2176  * 
2177  * \internal
2178  * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
2179  * argument in a drm_control structure.
2180  */
2181 int drmCtlUninstHandler(int fd)
2182 {
2183     drm_control_t ctl;
2184
2185     memclear(ctl);
2186     ctl.func  = DRM_UNINST_HANDLER;
2187     ctl.irq   = 0;
2188     if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2189         return -errno;
2190     return 0;
2191 }
2192
2193 int drmFinish(int fd, int context, drmLockFlags flags)
2194 {
2195     drm_lock_t lock;
2196
2197     memclear(lock);
2198     lock.context = context;
2199     if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
2200     if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
2201     if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
2202     if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
2203     if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
2204     if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
2205     if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock))
2206         return -errno;
2207     return 0;
2208 }
2209
2210 /**
2211  * Get IRQ from bus ID.
2212  *
2213  * \param fd file descriptor.
2214  * \param busnum bus number.
2215  * \param devnum device number.
2216  * \param funcnum function number.
2217  * 
2218  * \return IRQ number on success, or a negative value on failure.
2219  * 
2220  * \internal
2221  * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
2222  * arguments in a drm_irq_busid structure.
2223  */
2224 int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
2225 {
2226     drm_irq_busid_t p;
2227
2228     memclear(p);
2229     p.busnum  = busnum;
2230     p.devnum  = devnum;
2231     p.funcnum = funcnum;
2232     if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
2233         return -errno;
2234     return p.irq;
2235 }
2236
2237 int drmAddContextTag(int fd, drm_context_t context, void *tag)
2238 {
2239     drmHashEntry  *entry = drmGetEntry(fd);
2240
2241     if (drmHashInsert(entry->tagTable, context, tag)) {
2242         drmHashDelete(entry->tagTable, context);
2243         drmHashInsert(entry->tagTable, context, tag);
2244     }
2245     return 0;
2246 }
2247
2248 int drmDelContextTag(int fd, drm_context_t context)
2249 {
2250     drmHashEntry  *entry = drmGetEntry(fd);
2251
2252     return drmHashDelete(entry->tagTable, context);
2253 }
2254
2255 void *drmGetContextTag(int fd, drm_context_t context)
2256 {
2257     drmHashEntry  *entry = drmGetEntry(fd);
2258     void          *value;
2259
2260     if (drmHashLookup(entry->tagTable, context, &value))
2261         return NULL;
2262
2263     return value;
2264 }
2265
2266 int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
2267                                 drm_handle_t handle)
2268 {
2269     drm_ctx_priv_map_t map;
2270
2271     memclear(map);
2272     map.ctx_id = ctx_id;
2273     map.handle = (void *)(uintptr_t)handle;
2274
2275     if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
2276         return -errno;
2277     return 0;
2278 }
2279
2280 int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
2281                                 drm_handle_t *handle)
2282 {
2283     drm_ctx_priv_map_t map;
2284
2285     memclear(map);
2286     map.ctx_id = ctx_id;
2287
2288     if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
2289         return -errno;
2290     if (handle)
2291         *handle = (drm_handle_t)(uintptr_t)map.handle;
2292
2293     return 0;
2294 }
2295
2296 int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
2297               drmMapType *type, drmMapFlags *flags, drm_handle_t *handle,
2298               int *mtrr)
2299 {
2300     drm_map_t map;
2301
2302     memclear(map);
2303     map.offset = idx;
2304     if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
2305         return -errno;
2306     *offset = map.offset;
2307     *size   = map.size;
2308     *type   = map.type;
2309     *flags  = map.flags;
2310     *handle = (unsigned long)map.handle;
2311     *mtrr   = map.mtrr;
2312     return 0;
2313 }
2314
2315 int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
2316                  unsigned long *magic, unsigned long *iocs)
2317 {
2318     drm_client_t client;
2319
2320     memclear(client);
2321     client.idx = idx;
2322     if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
2323         return -errno;
2324     *auth      = client.auth;
2325     *pid       = client.pid;
2326     *uid       = client.uid;
2327     *magic     = client.magic;
2328     *iocs      = client.iocs;
2329     return 0;
2330 }
2331
2332 int drmGetStats(int fd, drmStatsT *stats)
2333 {
2334     drm_stats_t s;
2335     unsigned    i;
2336
2337     memclear(s);
2338     if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
2339         return -errno;
2340
2341     stats->count = 0;
2342     memset(stats, 0, sizeof(*stats));
2343     if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
2344         return -1;
2345
2346 #define SET_VALUE                              \
2347     stats->data[i].long_format = "%-20.20s";   \
2348     stats->data[i].rate_format = "%8.8s";      \
2349     stats->data[i].isvalue     = 1;            \
2350     stats->data[i].verbose     = 0
2351
2352 #define SET_COUNT                              \
2353     stats->data[i].long_format = "%-20.20s";   \
2354     stats->data[i].rate_format = "%5.5s";      \
2355     stats->data[i].isvalue     = 0;            \
2356     stats->data[i].mult_names  = "kgm";        \
2357     stats->data[i].mult        = 1000;         \
2358     stats->data[i].verbose     = 0
2359
2360 #define SET_BYTE                               \
2361     stats->data[i].long_format = "%-20.20s";   \
2362     stats->data[i].rate_format = "%5.5s";      \
2363     stats->data[i].isvalue     = 0;            \
2364     stats->data[i].mult_names  = "KGM";        \
2365     stats->data[i].mult        = 1024;         \
2366     stats->data[i].verbose     = 0
2367
2368
2369     stats->count = s.count;
2370     for (i = 0; i < s.count; i++) {
2371         stats->data[i].value = s.data[i].value;
2372         switch (s.data[i].type) {
2373         case _DRM_STAT_LOCK:
2374             stats->data[i].long_name = "Lock";
2375             stats->data[i].rate_name = "Lock";
2376             SET_VALUE;
2377             break;
2378         case _DRM_STAT_OPENS:
2379             stats->data[i].long_name = "Opens";
2380             stats->data[i].rate_name = "O";
2381             SET_COUNT;
2382             stats->data[i].verbose   = 1;
2383             break;
2384         case _DRM_STAT_CLOSES:
2385             stats->data[i].long_name = "Closes";
2386             stats->data[i].rate_name = "Lock";
2387             SET_COUNT;
2388             stats->data[i].verbose   = 1;
2389             break;
2390         case _DRM_STAT_IOCTLS:
2391             stats->data[i].long_name = "Ioctls";
2392             stats->data[i].rate_name = "Ioc/s";
2393             SET_COUNT;
2394             break;
2395         case _DRM_STAT_LOCKS:
2396             stats->data[i].long_name = "Locks";
2397             stats->data[i].rate_name = "Lck/s";
2398             SET_COUNT;
2399             break;
2400         case _DRM_STAT_UNLOCKS:
2401             stats->data[i].long_name = "Unlocks";
2402             stats->data[i].rate_name = "Unl/s";
2403             SET_COUNT;
2404             break;
2405         case _DRM_STAT_IRQ:
2406             stats->data[i].long_name = "IRQs";
2407             stats->data[i].rate_name = "IRQ/s";
2408             SET_COUNT;
2409             break;
2410         case _DRM_STAT_PRIMARY:
2411             stats->data[i].long_name = "Primary Bytes";
2412             stats->data[i].rate_name = "PB/s";
2413             SET_BYTE;
2414             break;
2415         case _DRM_STAT_SECONDARY:
2416             stats->data[i].long_name = "Secondary Bytes";
2417             stats->data[i].rate_name = "SB/s";
2418             SET_BYTE;
2419             break;
2420         case _DRM_STAT_DMA:
2421             stats->data[i].long_name = "DMA";
2422             stats->data[i].rate_name = "DMA/s";
2423             SET_COUNT;
2424             break;
2425         case _DRM_STAT_SPECIAL:
2426             stats->data[i].long_name = "Special DMA";
2427             stats->data[i].rate_name = "dma/s";
2428             SET_COUNT;
2429             break;
2430         case _DRM_STAT_MISSED:
2431             stats->data[i].long_name = "Miss";
2432             stats->data[i].rate_name = "Ms/s";
2433             SET_COUNT;
2434             break;
2435         case _DRM_STAT_VALUE:
2436             stats->data[i].long_name = "Value";
2437             stats->data[i].rate_name = "Value";
2438             SET_VALUE;
2439             break;
2440         case _DRM_STAT_BYTE:
2441             stats->data[i].long_name = "Bytes";
2442             stats->data[i].rate_name = "B/s";
2443             SET_BYTE;
2444             break;
2445         case _DRM_STAT_COUNT:
2446         default:
2447             stats->data[i].long_name = "Count";
2448             stats->data[i].rate_name = "Cnt/s";
2449             SET_COUNT;
2450             break;
2451         }
2452     }
2453     return 0;
2454 }
2455
2456 /**
2457  * Issue a set-version ioctl.
2458  *
2459  * \param fd file descriptor.
2460  * \param drmCommandIndex command index 
2461  * \param data source pointer of the data to be read and written.
2462  * \param size size of the data to be read and written.
2463  * 
2464  * \return zero on success, or a negative value on failure.
2465  * 
2466  * \internal
2467  * It issues a read-write ioctl given by 
2468  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2469  */
2470 int drmSetInterfaceVersion(int fd, drmSetVersion *version)
2471 {
2472     int retcode = 0;
2473     drm_set_version_t sv;
2474
2475     memclear(sv);
2476     sv.drm_di_major = version->drm_di_major;
2477     sv.drm_di_minor = version->drm_di_minor;
2478     sv.drm_dd_major = version->drm_dd_major;
2479     sv.drm_dd_minor = version->drm_dd_minor;
2480
2481     if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
2482         retcode = -errno;
2483     }
2484
2485     version->drm_di_major = sv.drm_di_major;
2486     version->drm_di_minor = sv.drm_di_minor;
2487     version->drm_dd_major = sv.drm_dd_major;
2488     version->drm_dd_minor = sv.drm_dd_minor;
2489
2490     return retcode;
2491 }
2492
2493 /**
2494  * Send a device-specific command.
2495  *
2496  * \param fd file descriptor.
2497  * \param drmCommandIndex command index 
2498  * 
2499  * \return zero on success, or a negative value on failure.
2500  * 
2501  * \internal
2502  * It issues a ioctl given by 
2503  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2504  */
2505 int drmCommandNone(int fd, unsigned long drmCommandIndex)
2506 {
2507     unsigned long request;
2508
2509     request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
2510
2511     if (drmIoctl(fd, request, NULL)) {
2512         return -errno;
2513     }
2514     return 0;
2515 }
2516
2517
2518 /**
2519  * Send a device-specific read command.
2520  *
2521  * \param fd file descriptor.
2522  * \param drmCommandIndex command index 
2523  * \param data destination pointer of the data to be read.
2524  * \param size size of the data to be read.
2525  * 
2526  * \return zero on success, or a negative value on failure.
2527  *
2528  * \internal
2529  * It issues a read ioctl given by 
2530  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2531  */
2532 int drmCommandRead(int fd, unsigned long drmCommandIndex, void *data,
2533                    unsigned long size)
2534 {
2535     unsigned long request;
2536
2537     request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE, 
2538         DRM_COMMAND_BASE + drmCommandIndex, size);
2539
2540     if (drmIoctl(fd, request, data)) {
2541         return -errno;
2542     }
2543     return 0;
2544 }
2545
2546
2547 /**
2548  * Send a device-specific write command.
2549  *
2550  * \param fd file descriptor.
2551  * \param drmCommandIndex command index 
2552  * \param data source pointer of the data to be written.
2553  * \param size size of the data to be written.
2554  * 
2555  * \return zero on success, or a negative value on failure.
2556  * 
2557  * \internal
2558  * It issues a write ioctl given by 
2559  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2560  */
2561 int drmCommandWrite(int fd, unsigned long drmCommandIndex, void *data,
2562                     unsigned long size)
2563 {
2564     unsigned long request;
2565
2566     request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE, 
2567         DRM_COMMAND_BASE + drmCommandIndex, size);
2568
2569     if (drmIoctl(fd, request, data)) {
2570         return -errno;
2571     }
2572     return 0;
2573 }
2574
2575
2576 /**
2577  * Send a device-specific read-write command.
2578  *
2579  * \param fd file descriptor.
2580  * \param drmCommandIndex command index 
2581  * \param data source pointer of the data to be read and written.
2582  * \param size size of the data to be read and written.
2583  * 
2584  * \return zero on success, or a negative value on failure.
2585  * 
2586  * \internal
2587  * It issues a read-write ioctl given by 
2588  * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2589  */
2590 int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data,
2591                         unsigned long size)
2592 {
2593     unsigned long request;
2594
2595     request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE, 
2596         DRM_COMMAND_BASE + drmCommandIndex, size);
2597
2598     if (drmIoctl(fd, request, data))
2599         return -errno;
2600     return 0;
2601 }
2602
2603 #define DRM_MAX_FDS 16
2604 static struct {
2605     char *BusID;
2606     int fd;
2607     int refcount;
2608     int type;
2609 } connection[DRM_MAX_FDS];
2610
2611 static int nr_fds = 0;
2612
2613 int drmOpenOnce(void *unused, 
2614                 const char *BusID,
2615                 int *newlyopened)
2616 {
2617     return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
2618 }
2619
2620 int drmOpenOnceWithType(const char *BusID, int *newlyopened, int type)
2621 {
2622     int i;
2623     int fd;
2624    
2625     for (i = 0; i < nr_fds; i++)
2626         if ((strcmp(BusID, connection[i].BusID) == 0) &&
2627             (connection[i].type == type)) {
2628             connection[i].refcount++;
2629             *newlyopened = 0;
2630             return connection[i].fd;
2631         }
2632
2633     fd = drmOpenWithType(NULL, BusID, type);
2634     if (fd < 0 || nr_fds == DRM_MAX_FDS)
2635         return fd;
2636    
2637     connection[nr_fds].BusID = strdup(BusID);
2638     connection[nr_fds].fd = fd;
2639     connection[nr_fds].refcount = 1;
2640     connection[nr_fds].type = type;
2641     *newlyopened = 1;
2642
2643     if (0)
2644         fprintf(stderr, "saved connection %d for %s %d\n", 
2645                 nr_fds, connection[nr_fds].BusID, 
2646                 strcmp(BusID, connection[nr_fds].BusID));
2647
2648     nr_fds++;
2649
2650     return fd;
2651 }
2652
2653 void drmCloseOnce(int fd)
2654 {
2655     int i;
2656
2657     for (i = 0; i < nr_fds; i++) {
2658         if (fd == connection[i].fd) {
2659             if (--connection[i].refcount == 0) {
2660                 drmClose(connection[i].fd);
2661                 free(connection[i].BusID);
2662             
2663                 if (i < --nr_fds) 
2664                     connection[i] = connection[nr_fds];
2665
2666                 return;
2667             }
2668         }
2669     }
2670 }
2671
2672 int drmSetMaster(int fd)
2673 {
2674         return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
2675 }
2676
2677 int drmDropMaster(int fd)
2678 {
2679         return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
2680 }
2681
2682 char *drmGetDeviceNameFromFd(int fd)
2683 {
2684         char name[128];
2685         struct stat sbuf;
2686         dev_t d;
2687         int i;
2688
2689         /* The whole drmOpen thing is a fiasco and we need to find a way
2690          * back to just using open(2).  For now, however, lets just make
2691          * things worse with even more ad hoc directory walking code to
2692          * discover the device file name. */
2693
2694         fstat(fd, &sbuf);
2695         d = sbuf.st_rdev;
2696
2697         for (i = 0; i < DRM_MAX_MINOR; i++) {
2698                 snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
2699                 if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
2700                         break;
2701         }
2702         if (i == DRM_MAX_MINOR)
2703                 return NULL;
2704
2705         return strdup(name);
2706 }
2707
2708 int drmGetNodeTypeFromFd(int fd)
2709 {
2710         struct stat sbuf;
2711         int maj, min, type;
2712
2713         if (fstat(fd, &sbuf))
2714                 return -1;
2715
2716         maj = major(sbuf.st_rdev);
2717         min = minor(sbuf.st_rdev);
2718
2719         if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) {
2720                 errno = EINVAL;
2721                 return -1;
2722         }
2723
2724         type = drmGetMinorType(min);
2725         if (type == -1)
2726                 errno = ENODEV;
2727         return type;
2728 }
2729
2730 int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd)
2731 {
2732         struct drm_prime_handle args;
2733         int ret;
2734
2735         memclear(args);
2736         args.fd = -1;
2737         args.handle = handle;
2738         args.flags = flags;
2739         ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
2740         if (ret)
2741                 return ret;
2742
2743         *prime_fd = args.fd;
2744         return 0;
2745 }
2746
2747 int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
2748 {
2749         struct drm_prime_handle args;
2750         int ret;
2751
2752         memclear(args);
2753         args.fd = prime_fd;
2754         ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
2755         if (ret)
2756                 return ret;
2757
2758         *handle = args.handle;
2759         return 0;
2760 }
2761
2762 static char *drmGetMinorNameForFD(int fd, int type)
2763 {
2764 #ifdef __linux__
2765         DIR *sysdir;
2766         struct dirent *pent, *ent;
2767         struct stat sbuf;
2768         const char *name = drmGetMinorName(type);
2769         int len;
2770         char dev_name[64], buf[64];
2771         long name_max;
2772         int maj, min;
2773
2774         if (!name)
2775                 return NULL;
2776
2777         len = strlen(name);
2778
2779         if (fstat(fd, &sbuf))
2780                 return NULL;
2781
2782         maj = major(sbuf.st_rdev);
2783         min = minor(sbuf.st_rdev);
2784
2785         if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
2786                 return NULL;
2787
2788         snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
2789
2790         sysdir = opendir(buf);
2791         if (!sysdir)
2792                 return NULL;
2793
2794         name_max = fpathconf(dirfd(sysdir), _PC_NAME_MAX);
2795         if (name_max == -1)
2796                 goto out_close_dir;
2797
2798         pent = malloc(offsetof(struct dirent, d_name) + name_max + 1);
2799         if (pent == NULL)
2800                  goto out_close_dir;
2801
2802         while (readdir_r(sysdir, pent, &ent) == 0 && ent != NULL) {
2803                 if (strncmp(ent->d_name, name, len) == 0) {
2804                         snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
2805                                  ent->d_name);
2806
2807                         free(pent);
2808                         closedir(sysdir);
2809
2810                         return strdup(dev_name);
2811                 }
2812         }
2813
2814         free(pent);
2815
2816 out_close_dir:
2817         closedir(sysdir);
2818 #else
2819 #warning "Missing implementation of drmGetMinorNameForFD"
2820 #endif
2821         return NULL;
2822 }
2823
2824 char *drmGetPrimaryDeviceNameFromFd(int fd)
2825 {
2826         return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
2827 }
2828
2829 char *drmGetRenderDeviceNameFromFd(int fd)
2830 {
2831         return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
2832 }
2833
2834 static int drmParseSubsystemType(int maj, int min)
2835 {
2836 #ifdef __linux__
2837     char path[PATH_MAX + 1];
2838     char link[PATH_MAX + 1] = "";
2839     char *name;
2840
2841     snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem",
2842              maj, min);
2843
2844     if (readlink(path, link, PATH_MAX) < 0)
2845         return -errno;
2846
2847     name = strrchr(link, '/');
2848     if (!name)
2849         return -EINVAL;
2850
2851     if (strncmp(name, "/pci", 4) == 0)
2852         return DRM_BUS_PCI;
2853
2854     return -EINVAL;
2855 #else
2856 #warning "Missing implementation of drmParseSubsystemType"
2857     return -EINVAL;
2858 #endif
2859 }
2860
2861 static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
2862 {
2863 #ifdef __linux__
2864     char path[PATH_MAX + 1];
2865     char data[128];
2866     char *str;
2867     int domain, bus, dev, func;
2868     int fd, ret;
2869
2870     snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/uevent", maj, min);
2871     fd = open(path, O_RDONLY);
2872     if (fd < 0)
2873         return -errno;
2874
2875     ret = read(fd, data, sizeof(data));
2876     close(fd);
2877     if (ret < 0)
2878         return -errno;
2879
2880 #define TAG "PCI_SLOT_NAME="
2881     str = strstr(data, TAG);
2882     if (str == NULL)
2883         return -EINVAL;
2884
2885     if (sscanf(str, TAG "%04x:%02x:%02x.%1u",
2886                &domain, &bus, &dev, &func) != 4)
2887         return -EINVAL;
2888 #undef TAG
2889
2890     info->domain = domain;
2891     info->bus = bus;
2892     info->dev = dev;
2893     info->func = func;
2894
2895     return 0;
2896 #else
2897 #warning "Missing implementation of drmParsePciBusInfo"
2898     return -EINVAL;
2899 #endif
2900 }
2901
2902 static int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b)
2903 {
2904     if (a == NULL || b == NULL)
2905         return -1;
2906
2907     if (a->bustype != b->bustype)
2908         return -1;
2909
2910     switch (a->bustype) {
2911     case DRM_BUS_PCI:
2912         return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo));
2913     default:
2914         break;
2915     }
2916
2917     return -1;
2918 }
2919
2920 static int drmGetNodeType(const char *name)
2921 {
2922     if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
2923         sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
2924         return DRM_NODE_PRIMARY;
2925
2926     if (strncmp(name, DRM_CONTROL_MINOR_NAME,
2927         sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0)
2928         return DRM_NODE_CONTROL;
2929
2930     if (strncmp(name, DRM_RENDER_MINOR_NAME,
2931         sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
2932         return DRM_NODE_RENDER;
2933
2934     return -EINVAL;
2935 }
2936
2937 static int drmGetMaxNodeName(void)
2938 {
2939     return sizeof(DRM_DIR_NAME) +
2940            MAX3(sizeof(DRM_PRIMARY_MINOR_NAME),
2941                 sizeof(DRM_CONTROL_MINOR_NAME),
2942                 sizeof(DRM_RENDER_MINOR_NAME)) +
2943            3 /* lenght of the node number */;
2944 }
2945
2946 static int drmParsePciDeviceInfo(const char *d_name,
2947                                  drmPciDeviceInfoPtr device)
2948 {
2949 #ifdef __linux__
2950     char path[PATH_MAX + 1];
2951     unsigned char config[64];
2952     int fd, ret;
2953
2954     snprintf(path, PATH_MAX, "/sys/class/drm/%s/device/config", d_name);
2955     fd = open(path, O_RDONLY);
2956     if (fd < 0)
2957         return -errno;
2958
2959     ret = read(fd, config, sizeof(config));
2960     close(fd);
2961     if (ret < 0)
2962         return -errno;
2963
2964     device->vendor_id = config[0] | (config[1] << 8);
2965     device->device_id = config[2] | (config[3] << 8);
2966     device->revision_id = config[8];
2967     device->subvendor_id = config[44] | (config[45] << 8);
2968     device->subdevice_id = config[46] | (config[47] << 8);
2969
2970     return 0;
2971 #else
2972 #warning "Missing implementation of drmParsePciDeviceInfo"
2973     return -EINVAL;
2974 #endif
2975 }
2976
2977 void drmFreeDevice(drmDevicePtr *device)
2978 {
2979     if (device == NULL)
2980         return;
2981
2982     free(*device);
2983     *device = NULL;
2984 }
2985
2986 void drmFreeDevices(drmDevicePtr devices[], int count)
2987 {
2988     int i;
2989
2990     if (devices == NULL)
2991         return;
2992
2993     for (i = 0; i < count && devices[i] != NULL; i++)
2994         drmFreeDevice(&devices[i]);
2995 }
2996
2997 static int drmProcessPciDevice(drmDevicePtr *device, const char *d_name,
2998                                const char *node, int node_type,
2999                                int maj, int min, bool fetch_deviceinfo)
3000 {
3001     const int max_node_str = drmGetMaxNodeName();
3002     int ret, i;
3003     void *addr;
3004
3005     addr = *device = calloc(1, sizeof(drmDevice) +
3006                                (DRM_NODE_MAX *
3007                                 (sizeof(void *) + max_node_str)) +
3008                                sizeof(drmPciBusInfo) +
3009                                sizeof(drmPciDeviceInfo));
3010     if (!*device)
3011         return -ENOMEM;
3012
3013     (*device)->bustype = DRM_BUS_PCI;
3014     (*device)->available_nodes = 1 << node_type;
3015
3016     addr += sizeof(drmDevice);
3017     (*device)->nodes = addr;
3018
3019     addr += DRM_NODE_MAX * sizeof(void *);
3020     for (i = 0; i < DRM_NODE_MAX; i++) {
3021         (*device)->nodes[i] = addr;
3022         addr += max_node_str;
3023     }
3024     memcpy((*device)->nodes[node_type], node, max_node_str);
3025
3026     (*device)->businfo.pci = addr;
3027
3028     ret = drmParsePciBusInfo(maj, min, (*device)->businfo.pci);
3029     if (ret)
3030         goto free_device;
3031
3032     // Fetch the device info if the user has requested it
3033     if (fetch_deviceinfo) {
3034         addr += sizeof(drmPciBusInfo);
3035         (*device)->deviceinfo.pci = addr;
3036
3037         ret = drmParsePciDeviceInfo(d_name, (*device)->deviceinfo.pci);
3038         if (ret)
3039             goto free_device;
3040     }
3041     return 0;
3042
3043 free_device:
3044     free(*device);
3045     *device = NULL;
3046     return ret;
3047 }
3048
3049 static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
3050 {
3051     int node_type, i, j;
3052
3053     for (i = 0; i < count; i++) {
3054         for (j = i + 1; j < count; j++) {
3055             if (drmCompareBusInfo(local_devices[i], local_devices[j]) == 0) {
3056                 local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
3057                 node_type = log2(local_devices[j]->available_nodes);
3058                 memcpy(local_devices[i]->nodes[node_type],
3059                        local_devices[j]->nodes[node_type], drmGetMaxNodeName());
3060                 drmFreeDevice(&local_devices[j]);
3061             }
3062         }
3063     }
3064 }
3065
3066 /**
3067  * Get information about the opened drm device
3068  *
3069  * \param fd file descriptor of the drm device
3070  * \param device the address of a drmDevicePtr where the information
3071  *               will be allocated in stored
3072  *
3073  * \return zero on success, negative error code otherwise.
3074  */
3075 int drmGetDevice(int fd, drmDevicePtr *device)
3076 {
3077     drmDevicePtr *local_devices;
3078     drmDevicePtr d;
3079     DIR *sysdir;
3080     struct dirent *dent;
3081     struct stat sbuf;
3082     char node[PATH_MAX + 1];
3083     int node_type, subsystem_type;
3084     int maj, min;
3085     int ret, i, node_count;
3086     int max_count = 16;
3087
3088     if (fd == -1 || device == NULL)
3089         return -EINVAL;
3090
3091     if (fstat(fd, &sbuf))
3092         return -errno;
3093
3094     maj = major(sbuf.st_rdev);
3095     min = minor(sbuf.st_rdev);
3096
3097     if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3098         return -EINVAL;
3099
3100     subsystem_type = drmParseSubsystemType(maj, min);
3101
3102     local_devices = calloc(max_count, sizeof(drmDevicePtr));
3103     if (local_devices == NULL)
3104         return -ENOMEM;
3105
3106     sysdir = opendir(DRM_DIR_NAME);
3107     if (!sysdir) {
3108         ret = -errno;
3109         goto close_sysdir;
3110     }
3111
3112     i = 0;
3113     while ((dent = readdir(sysdir))) {
3114         node_type = drmGetNodeType(dent->d_name);
3115         if (node_type < 0)
3116             continue;
3117
3118         snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
3119         if (stat(node, &sbuf))
3120             continue;
3121
3122         maj = major(sbuf.st_rdev);
3123         min = minor(sbuf.st_rdev);
3124
3125         if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3126             continue;
3127
3128         if (drmParseSubsystemType(maj, min) != subsystem_type)
3129             continue;
3130
3131         switch (subsystem_type) {
3132         case DRM_BUS_PCI:
3133             ret = drmProcessPciDevice(&d, dent->d_name, node, node_type,
3134                                       maj, min, true);
3135             if (ret)
3136                 goto free_devices;
3137
3138             break;
3139         default:
3140             fprintf(stderr, "The subsystem type is not supported yet\n");
3141             break;
3142         }
3143
3144         if (i >= max_count) {
3145             drmDevicePtr *temp;
3146
3147             max_count += 16;
3148             temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
3149             if (!temp)
3150                 goto free_devices;
3151             local_devices = temp;
3152         }
3153
3154         local_devices[i] = d;
3155         i++;
3156     }
3157     node_count = i;
3158
3159     /* Fold nodes into a single device if they share the same bus info */
3160     drmFoldDuplicatedDevices(local_devices, node_count);
3161
3162     *device = local_devices[0];
3163     for (i = 1; i < node_count && local_devices[i]; i++)
3164             drmFreeDevice(&local_devices[i]);
3165
3166     free(local_devices);
3167     closedir(sysdir);
3168     return 0;
3169
3170 free_devices:
3171     drmFreeDevices(local_devices, i);
3172     free(local_devices);
3173
3174 close_sysdir:
3175     closedir(sysdir);
3176     return ret;
3177 }
3178
3179 /**
3180  * Get drm devices on the system
3181  *
3182  * \param devices the array of devices with drmDevicePtr elements
3183  *                can be NULL to get the device number first
3184  * \param max_devices the maximum number of devices for the array
3185  *
3186  * \return on error - negative error code,
3187  *         if devices is NULL - total number of devices available on the system,
3188  *         alternatively the number of devices stored in devices[], which is
3189  *         capped by the max_devices.
3190  */
3191 int drmGetDevices(drmDevicePtr devices[], int max_devices)
3192 {
3193     drmDevicePtr *local_devices;
3194     drmDevicePtr device;
3195     DIR *sysdir;
3196     struct dirent *dent;
3197     struct stat sbuf;
3198     char node[PATH_MAX + 1];
3199     int node_type, subsystem_type;
3200     int maj, min;
3201     int ret, i, node_count, device_count;
3202     int max_count = 16;
3203
3204     local_devices = calloc(max_count, sizeof(drmDevicePtr));
3205     if (local_devices == NULL)
3206         return -ENOMEM;
3207
3208     sysdir = opendir(DRM_DIR_NAME);
3209     if (!sysdir) {
3210         ret = -errno;
3211         goto close_sysdir;
3212     }
3213
3214     i = 0;
3215     while ((dent = readdir(sysdir))) {
3216         node_type = drmGetNodeType(dent->d_name);
3217         if (node_type < 0)
3218             continue;
3219
3220         snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
3221         if (stat(node, &sbuf))
3222             continue;
3223
3224         maj = major(sbuf.st_rdev);
3225         min = minor(sbuf.st_rdev);
3226
3227         if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3228             continue;
3229
3230         subsystem_type = drmParseSubsystemType(maj, min);
3231
3232         if (subsystem_type < 0)
3233             continue;
3234
3235         switch (subsystem_type) {
3236         case DRM_BUS_PCI:
3237             ret = drmProcessPciDevice(&device, dent->d_name, node, node_type,
3238                                       maj, min, devices != NULL);
3239             if (ret)
3240                 goto free_devices;
3241
3242             break;
3243         default:
3244             fprintf(stderr, "The subsystem type is not supported yet\n");
3245             break;
3246         }
3247
3248         if (i >= max_count) {
3249             drmDevicePtr *temp;
3250
3251             max_count += 16;
3252             temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
3253             if (!temp)
3254                 goto free_devices;
3255             local_devices = temp;
3256         }
3257
3258         local_devices[i] = device;
3259         i++;
3260     }
3261     node_count = i;
3262
3263     /* Fold nodes into a single device if they share the same bus info */
3264     drmFoldDuplicatedDevices(local_devices, node_count);
3265
3266     device_count = 0;
3267     for (i = 0; i < node_count && local_devices[i]; i++) {
3268         if ((devices != NULL) && (device_count < max_devices))
3269             devices[device_count] = local_devices[i];
3270         else
3271             drmFreeDevice(&local_devices[i]);
3272
3273         device_count++;
3274     }
3275
3276     free(local_devices);
3277     closedir(sysdir);
3278     return device_count;
3279
3280 free_devices:
3281     drmFreeDevices(local_devices, i);
3282     free(local_devices);
3283
3284 close_sysdir:
3285     closedir(sysdir);
3286     return ret;
3287 }