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