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