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