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