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