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