3 * User-level interface to DRM device
5 * \author Rickard E. (Rik) Faith <faith@valinux.com>
6 * \author Kevin E. Martin <martin@valinux.com>
10 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
11 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
12 * All Rights Reserved.
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:
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
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.
48 #include <sys/types.h>
50 #define stat_t struct stat
51 #include <sys/ioctl.h>
55 #include <sys/mkdev.h>
57 #ifdef MAJOR_IN_SYSMACROS
58 #include <sys/sysmacros.h>
61 #include <sys/sysctl.h>
66 #if defined(__FreeBSD__)
67 #include <sys/param.h>
68 #include <sys/pciio.h>
71 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
73 /* Not all systems have MAP_FAILED defined */
75 #define MAP_FAILED ((void *)-1)
79 #include "libdrm_macros.h"
80 #include "drm_fourcc.h"
82 #include "util_math.h"
98 #endif /* __OpenBSD__ */
101 #define DRM_MAJOR 226 /* Linux */
104 #if defined(__OpenBSD__) || defined(__DragonFly__)
112 uint16_t subvendor_id
;
113 uint16_t subdevice_id
;
117 #define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo)
120 #define DRM_MSG_VERBOSITY 3
122 #define memclear(s) memset(&s, 0, sizeof(s))
124 static drmServerInfoPtr drm_server_info
;
126 static bool drmNodeIsDRM(int maj
, int min
);
127 static char *drmGetMinorNameForFD(int fd
, int type
);
129 #define DRM_MODIFIER(v, f, f_name) \
130 .modifier = DRM_FORMAT_MOD_##v ## _ ##f, \
131 .modifier_name = #f_name
133 #define DRM_MODIFIER_INVALID(v, f_name) \
134 .modifier = DRM_FORMAT_MOD_INVALID, .modifier_name = #f_name
136 #define DRM_MODIFIER_LINEAR(v, f_name) \
137 .modifier = DRM_FORMAT_MOD_LINEAR, .modifier_name = #f_name
139 /* Intel is abit special as the format doesn't follow other vendors naming
141 #define DRM_MODIFIER_INTEL(f, f_name) \
142 .modifier = I915_FORMAT_MOD_##f, .modifier_name = #f_name
144 struct drmFormatModifierInfo
{
146 const char *modifier_name
;
149 struct drmFormatModifierVendorInfo
{
151 const char *vendor_name
;
154 #include "generated_static_table_fourcc.h"
156 struct drmVendorInfo
{
158 char *(*vendor_cb
)(uint64_t modifier
);
161 struct drmFormatVendorModifierInfo
{
163 const char *modifier_name
;
167 drmGetFormatModifierNameFromArm(uint64_t modifier
);
170 drmGetFormatModifierNameFromNvidia(uint64_t modifier
);
173 drmGetFormatModifierNameFromAmd(uint64_t modifier
);
176 drmGetFormatModifierNameFromAmlogic(uint64_t modifier
);
179 drmGetFormatModifierNameFromVivante(uint64_t modifier
);
181 static const struct drmVendorInfo modifier_format_vendor_table
[] = {
182 { DRM_FORMAT_MOD_VENDOR_ARM
, drmGetFormatModifierNameFromArm
},
183 { DRM_FORMAT_MOD_VENDOR_NVIDIA
, drmGetFormatModifierNameFromNvidia
},
184 { DRM_FORMAT_MOD_VENDOR_AMD
, drmGetFormatModifierNameFromAmd
},
185 { DRM_FORMAT_MOD_VENDOR_AMLOGIC
, drmGetFormatModifierNameFromAmlogic
},
186 { DRM_FORMAT_MOD_VENDOR_VIVANTE
, drmGetFormatModifierNameFromVivante
},
189 #ifndef AFBC_FORMAT_MOD_MODE_VALUE_MASK
190 #define AFBC_FORMAT_MOD_MODE_VALUE_MASK 0x000fffffffffffffULL
193 static const struct drmFormatVendorModifierInfo arm_mode_value_table
[] = {
194 { AFBC_FORMAT_MOD_YTR
, "YTR" },
195 { AFBC_FORMAT_MOD_SPLIT
, "SPLIT" },
196 { AFBC_FORMAT_MOD_SPARSE
, "SPARSE" },
197 { AFBC_FORMAT_MOD_CBR
, "CBR" },
198 { AFBC_FORMAT_MOD_TILED
, "TILED" },
199 { AFBC_FORMAT_MOD_SC
, "SC" },
200 { AFBC_FORMAT_MOD_DB
, "DB" },
201 { AFBC_FORMAT_MOD_BCH
, "BCH" },
202 { AFBC_FORMAT_MOD_USM
, "USM" },
205 static bool is_x_t_amd_gfx9_tile(uint64_t tile
)
208 case AMD_FMT_MOD_TILE_GFX9_64K_S_X
:
209 case AMD_FMT_MOD_TILE_GFX9_64K_D_X
:
210 case AMD_FMT_MOD_TILE_GFX9_64K_R_X
:
218 drmGetAfbcFormatModifierNameFromArm(uint64_t modifier
, FILE *fp
)
220 uint64_t mode_value
= modifier
& AFBC_FORMAT_MOD_MODE_VALUE_MASK
;
221 uint64_t block_size
= mode_value
& AFBC_FORMAT_MOD_BLOCK_SIZE_MASK
;
223 const char *block
= NULL
;
224 const char *mode
= NULL
;
225 bool did_print_mode
= false;
227 /* add block, can only have a (single) block */
228 switch (block_size
) {
229 case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
:
232 case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8
:
235 case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4
:
238 case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4
:
247 fprintf(fp
, "BLOCK_SIZE=%s,", block
);
250 for (unsigned int i
= 0; i
< ARRAY_SIZE(arm_mode_value_table
); i
++) {
251 if (arm_mode_value_table
[i
].modifier
& mode_value
) {
252 mode
= arm_mode_value_table
[i
].modifier_name
;
253 if (!did_print_mode
) {
254 fprintf(fp
, "MODE=%s", mode
);
255 did_print_mode
= true;
257 fprintf(fp
, "|%s", mode
);
266 drmGetAfrcFormatModifierNameFromArm(uint64_t modifier
, FILE *fp
)
269 for (unsigned int i
= 0; i
< 2; ++i
) {
270 uint64_t coding_unit_block
=
271 (modifier
>> (i
* 4)) & AFRC_FORMAT_MOD_CU_SIZE_MASK
;
272 const char *coding_unit_size
= NULL
;
274 switch (coding_unit_block
) {
275 case AFRC_FORMAT_MOD_CU_SIZE_16
:
276 coding_unit_size
= "CU_16";
278 case AFRC_FORMAT_MOD_CU_SIZE_24
:
279 coding_unit_size
= "CU_24";
281 case AFRC_FORMAT_MOD_CU_SIZE_32
:
282 coding_unit_size
= "CU_32";
286 if (!coding_unit_size
) {
294 fprintf(fp
, "P0=%s,", coding_unit_size
);
296 fprintf(fp
, "P12=%s,", coding_unit_size
);
301 (modifier
& AFRC_FORMAT_MOD_LAYOUT_SCAN
) == AFRC_FORMAT_MOD_LAYOUT_SCAN
;
311 drmGetFormatModifierNameFromArm(uint64_t modifier
)
313 uint64_t type
= (modifier
>> 52) & 0xf;
317 char *modifier_name
= NULL
;
320 fp
= open_memstream(&modifier_name
, &size
);
325 case DRM_FORMAT_MOD_ARM_TYPE_AFBC
:
326 result
= drmGetAfbcFormatModifierNameFromArm(modifier
, fp
);
328 case DRM_FORMAT_MOD_ARM_TYPE_AFRC
:
329 result
= drmGetAfrcFormatModifierNameFromArm(modifier
, fp
);
331 /* misc type is already handled by the static table */
332 case DRM_FORMAT_MOD_ARM_TYPE_MISC
:
344 return modifier_name
;
348 drmGetFormatModifierNameFromNvidia(uint64_t modifier
)
350 uint64_t height
, kind
, gen
, sector
, compression
;
352 height
= modifier
& 0xf;
353 kind
= (modifier
>> 12) & 0xff;
355 gen
= (modifier
>> 20) & 0x3;
356 sector
= (modifier
>> 22) & 0x1;
357 compression
= (modifier
>> 23) & 0x7;
359 /* just in case there could other simpler modifiers, not yet added, avoid
360 * testing against TEGRA_TILE */
361 if ((modifier
& 0x10) == 0x10) {
363 asprintf(&mod_nvidia
, "BLOCK_LINEAR_2D,HEIGHT=%"PRIu64
",KIND=%"PRIu64
","
364 "GEN=%"PRIu64
",SECTOR=%"PRIu64
",COMPRESSION=%"PRIu64
"", height
,
365 kind
, gen
, sector
, compression
);
373 drmGetFormatModifierNameFromAmdDcc(uint64_t modifier
, FILE *fp
)
375 uint64_t dcc_max_compressed_block
=
376 AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK
, modifier
);
377 uint64_t dcc_retile
= AMD_FMT_MOD_GET(DCC_RETILE
, modifier
);
379 const char *dcc_max_compressed_block_str
= NULL
;
384 fprintf(fp
, ",DCC_RETILE");
386 if (!dcc_retile
&& AMD_FMT_MOD_GET(DCC_PIPE_ALIGN
, modifier
))
387 fprintf(fp
, ",DCC_PIPE_ALIGN");
389 if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B
, modifier
))
390 fprintf(fp
, ",DCC_INDEPENDENT_64B");
392 if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B
, modifier
))
393 fprintf(fp
, ",DCC_INDEPENDENT_128B");
395 switch (dcc_max_compressed_block
) {
396 case AMD_FMT_MOD_DCC_BLOCK_64B
:
397 dcc_max_compressed_block_str
= "64B";
399 case AMD_FMT_MOD_DCC_BLOCK_128B
:
400 dcc_max_compressed_block_str
= "128B";
402 case AMD_FMT_MOD_DCC_BLOCK_256B
:
403 dcc_max_compressed_block_str
= "256B";
407 if (dcc_max_compressed_block_str
)
408 fprintf(fp
, ",DCC_MAX_COMPRESSED_BLOCK=%s",
409 dcc_max_compressed_block_str
);
411 if (AMD_FMT_MOD_GET(DCC_CONSTANT_ENCODE
, modifier
))
412 fprintf(fp
, ",DCC_CONSTANT_ENCODE");
416 drmGetFormatModifierNameFromAmdTile(uint64_t modifier
, FILE *fp
)
418 uint64_t pipe_xor_bits
, bank_xor_bits
, packers
, rb
;
419 uint64_t pipe
, pipe_align
, dcc
, dcc_retile
, tile_version
;
421 pipe_align
= AMD_FMT_MOD_GET(DCC_PIPE_ALIGN
, modifier
);
422 pipe_xor_bits
= AMD_FMT_MOD_GET(PIPE_XOR_BITS
, modifier
);
423 dcc
= AMD_FMT_MOD_GET(DCC
, modifier
);
424 dcc_retile
= AMD_FMT_MOD_GET(DCC_RETILE
, modifier
);
425 tile_version
= AMD_FMT_MOD_GET(TILE_VERSION
, modifier
);
427 fprintf(fp
, ",PIPE_XOR_BITS=%"PRIu64
, pipe_xor_bits
);
429 if (tile_version
== AMD_FMT_MOD_TILE_VER_GFX9
) {
430 bank_xor_bits
= AMD_FMT_MOD_GET(BANK_XOR_BITS
, modifier
);
431 fprintf(fp
, ",BANK_XOR_BITS=%"PRIu64
, bank_xor_bits
);
434 if (tile_version
== AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS
) {
435 packers
= AMD_FMT_MOD_GET(PACKERS
, modifier
);
436 fprintf(fp
, ",PACKERS=%"PRIu64
, packers
);
439 if (dcc
&& tile_version
== AMD_FMT_MOD_TILE_VER_GFX9
) {
440 rb
= AMD_FMT_MOD_GET(RB
, modifier
);
441 fprintf(fp
, ",RB=%"PRIu64
, rb
);
444 if (dcc
&& tile_version
== AMD_FMT_MOD_TILE_VER_GFX9
&&
445 (dcc_retile
|| pipe_align
)) {
446 pipe
= AMD_FMT_MOD_GET(PIPE
, modifier
);
447 fprintf(fp
, ",PIPE_%"PRIu64
, pipe
);
452 drmGetFormatModifierNameFromAmd(uint64_t modifier
)
454 uint64_t tile
, tile_version
, dcc
;
456 char *mod_amd
= NULL
;
459 const char *str_tile
= NULL
;
460 const char *str_tile_version
= NULL
;
462 tile
= AMD_FMT_MOD_GET(TILE
, modifier
);
463 tile_version
= AMD_FMT_MOD_GET(TILE_VERSION
, modifier
);
464 dcc
= AMD_FMT_MOD_GET(DCC
, modifier
);
466 fp
= open_memstream(&mod_amd
, &size
);
471 switch (tile_version
) {
472 case AMD_FMT_MOD_TILE_VER_GFX9
:
473 str_tile_version
= "GFX9";
475 case AMD_FMT_MOD_TILE_VER_GFX10
:
476 str_tile_version
= "GFX10";
478 case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS
:
479 str_tile_version
= "GFX10_RBPLUS";
481 case AMD_FMT_MOD_TILE_VER_GFX11
:
482 str_tile_version
= "GFX11";
486 if (str_tile_version
) {
487 fprintf(fp
, "%s", str_tile_version
);
496 case AMD_FMT_MOD_TILE_GFX9_64K_S
:
497 str_tile
= "GFX9_64K_S";
499 case AMD_FMT_MOD_TILE_GFX9_64K_D
:
500 str_tile
= "GFX9_64K_D";
502 case AMD_FMT_MOD_TILE_GFX9_64K_S_X
:
503 str_tile
= "GFX9_64K_S_X";
505 case AMD_FMT_MOD_TILE_GFX9_64K_D_X
:
506 str_tile
= "GFX9_64K_D_X";
508 case AMD_FMT_MOD_TILE_GFX9_64K_R_X
:
509 str_tile
= "GFX9_64K_R_X";
511 case AMD_FMT_MOD_TILE_GFX11_256K_R_X
:
512 str_tile
= "GFX11_256K_R_X";
517 fprintf(fp
, ",%s", str_tile
);
520 drmGetFormatModifierNameFromAmdDcc(modifier
, fp
);
522 if (tile_version
>= AMD_FMT_MOD_TILE_VER_GFX9
&& is_x_t_amd_gfx9_tile(tile
))
523 drmGetFormatModifierNameFromAmdTile(modifier
, fp
);
530 drmGetFormatModifierNameFromAmlogic(uint64_t modifier
)
532 uint64_t layout
= modifier
& 0xff;
533 uint64_t options
= (modifier
>> 8) & 0xff;
534 char *mod_amlogic
= NULL
;
536 const char *layout_str
;
537 const char *opts_str
;
540 case AMLOGIC_FBC_LAYOUT_BASIC
:
541 layout_str
= "BASIC";
543 case AMLOGIC_FBC_LAYOUT_SCATTER
:
544 layout_str
= "SCATTER";
547 layout_str
= "INVALID_LAYOUT";
551 if (options
& AMLOGIC_FBC_OPTION_MEM_SAVING
)
552 opts_str
= "MEM_SAVING";
556 asprintf(&mod_amlogic
, "FBC,LAYOUT=%s,OPTIONS=%s", layout_str
, opts_str
);
561 drmGetFormatModifierNameFromVivante(uint64_t modifier
)
563 const char *color_tiling
, *tile_status
, *compression
;
564 char *mod_vivante
= NULL
;
566 switch (modifier
& VIVANTE_MOD_TS_MASK
) {
570 case VIVANTE_MOD_TS_64_4
:
571 tile_status
= ",TS=64B_4";
573 case VIVANTE_MOD_TS_64_2
:
574 tile_status
= ",TS=64B_2";
576 case VIVANTE_MOD_TS_128_4
:
577 tile_status
= ",TS=128B_4";
579 case VIVANTE_MOD_TS_256_4
:
580 tile_status
= ",TS=256B_4";
583 tile_status
= ",TS=UNKNOWN";
587 switch (modifier
& VIVANTE_MOD_COMP_MASK
) {
591 case VIVANTE_MOD_COMP_DEC400
:
592 compression
= ",COMP=DEC400";
595 compression
= ",COMP=UNKNOWN";
599 switch (modifier
& ~VIVANTE_MOD_EXT_MASK
) {
601 color_tiling
= "LINEAR";
603 case DRM_FORMAT_MOD_VIVANTE_TILED
:
604 color_tiling
= "TILED";
606 case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED
:
607 color_tiling
= "SUPER_TILED";
609 case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED
:
610 color_tiling
= "SPLIT_TILED";
612 case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED
:
613 color_tiling
= "SPLIT_SUPER_TILED";
616 color_tiling
= "UNKNOWN";
620 asprintf(&mod_vivante
, "%s%s%s", color_tiling
, tile_status
, compression
);
624 static unsigned log2_int(unsigned x
)
632 if ((unsigned)(1 << l
) > x
) {
640 drm_public
void drmSetServerInfo(drmServerInfoPtr info
)
642 drm_server_info
= info
;
646 * Output a message to stderr.
648 * \param format printf() like format string.
651 * This function is a wrapper around vfprintf().
654 static int DRM_PRINTFLIKE(1, 0)
655 drmDebugPrint(const char *format
, va_list ap
)
657 return vfprintf(stderr
, format
, ap
);
661 drmMsg(const char *format
, ...)
665 if (((env
= getenv("LIBGL_DEBUG")) && strstr(env
, "verbose")) ||
666 (drm_server_info
&& drm_server_info
->debug_print
))
668 va_start(ap
, format
);
669 if (drm_server_info
) {
670 drm_server_info
->debug_print(format
,ap
);
672 drmDebugPrint(format
, ap
);
678 static void *drmHashTable
= NULL
; /* Context switch callbacks */
680 drm_public
void *drmGetHashTable(void)
685 drm_public
void *drmMalloc(int size
)
687 return calloc(1, size
);
690 drm_public
void drmFree(void *pt
)
696 * Call ioctl, restarting if it is interrupted
699 drmIoctl(int fd
, unsigned long request
, void *arg
)
704 ret
= ioctl(fd
, request
, arg
);
705 } while (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
709 static unsigned long drmGetKeyFromFd(int fd
)
718 drm_public drmHashEntry
*drmGetEntry(int fd
)
720 unsigned long key
= drmGetKeyFromFd(fd
);
725 drmHashTable
= drmHashCreate();
727 if (drmHashLookup(drmHashTable
, key
, &value
)) {
728 entry
= drmMalloc(sizeof(*entry
));
731 entry
->tagTable
= drmHashCreate();
732 drmHashInsert(drmHashTable
, key
, entry
);
740 * Compare two busid strings
745 * \return 1 if matched.
748 * This function compares two bus ID strings. It understands the older
749 * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is
750 * domain, b is bus, d is device, f is function.
752 static int drmMatchBusID(const char *id1
, const char *id2
, int pci_domain_ok
)
754 /* First, check if the IDs are exactly the same */
755 if (strcasecmp(id1
, id2
) == 0)
758 /* Try to match old/new-style PCI bus IDs. */
759 if (strncasecmp(id1
, "pci", 3) == 0) {
760 unsigned int o1
, b1
, d1
, f1
;
761 unsigned int o2
, b2
, d2
, f2
;
764 ret
= sscanf(id1
, "pci:%04x:%02x:%02x.%u", &o1
, &b1
, &d1
, &f1
);
767 ret
= sscanf(id1
, "PCI:%u:%u:%u", &b1
, &d1
, &f1
);
772 ret
= sscanf(id2
, "pci:%04x:%02x:%02x.%u", &o2
, &b2
, &d2
, &f2
);
775 ret
= sscanf(id2
, "PCI:%u:%u:%u", &b2
, &d2
, &f2
);
780 /* If domains aren't properly supported by the kernel interface,
781 * just ignore them, which sucks less than picking a totally random
782 * card with "open by name"
787 if ((o1
!= o2
) || (b1
!= b2
) || (d1
!= d2
) || (f1
!= f2
))
796 * Handles error checking for chown call.
798 * \param path to file.
799 * \param id of the new owner.
800 * \param id of the new group.
802 * \return zero if success or -1 if failure.
805 * Checks for failure. If failure was caused by signal call chown again.
806 * If any other failure happened then it will output error message using
810 static int chown_check_return(const char *path
, uid_t owner
, gid_t group
)
815 rv
= chown(path
, owner
, group
);
816 } while (rv
!= 0 && errno
== EINTR
);
821 drmMsg("Failed to change owner or group for file %s! %d: %s\n",
822 path
, errno
, strerror(errno
));
827 static const char *drmGetDeviceName(int type
)
830 case DRM_NODE_PRIMARY
:
832 case DRM_NODE_RENDER
:
833 return DRM_RENDER_DEV_NAME
;
839 * Open the DRM device, creating it if necessary.
841 * \param dev major and minor numbers of the device.
842 * \param minor minor number of the device.
844 * \return a file descriptor on success, or a negative value on error.
847 * Assembles the device name from \p minor and opens it, creating the device
848 * special file node with the major and minor numbers specified by \p dev and
849 * parent directory if necessary and was called by root.
851 static int drmOpenDevice(dev_t dev
, int minor
, int type
)
854 const char *dev_name
= drmGetDeviceName(type
);
855 char buf
[DRM_NODE_NAME_MAX
];
857 mode_t devmode
= DRM_DEV_MODE
, serv_mode
;
860 int isroot
= !geteuid();
861 uid_t user
= DRM_DEV_UID
;
862 gid_t group
= DRM_DEV_GID
;
868 sprintf(buf
, dev_name
, DRM_DIR_NAME
, minor
);
869 drmMsg("drmOpenDevice: node name is %s\n", buf
);
871 if (drm_server_info
&& drm_server_info
->get_perms
) {
872 drm_server_info
->get_perms(&serv_group
, &serv_mode
);
873 devmode
= serv_mode
? serv_mode
: DRM_DEV_MODE
;
874 devmode
&= ~(S_IXUSR
|S_IXGRP
|S_IXOTH
);
878 if (stat(DRM_DIR_NAME
, &st
)) {
880 return DRM_ERR_NOT_ROOT
;
881 mkdir(DRM_DIR_NAME
, DRM_DEV_DIRMODE
);
882 chown_check_return(DRM_DIR_NAME
, 0, 0); /* root:root */
883 chmod(DRM_DIR_NAME
, DRM_DEV_DIRMODE
);
886 /* Check if the device node exists and create it if necessary. */
887 if (stat(buf
, &st
)) {
889 return DRM_ERR_NOT_ROOT
;
891 mknod(buf
, S_IFCHR
| devmode
, dev
);
894 if (drm_server_info
&& drm_server_info
->get_perms
) {
895 group
= ((int)serv_group
>= 0) ? serv_group
: DRM_DEV_GID
;
896 chown_check_return(buf
, user
, group
);
900 /* if we modprobed then wait for udev */
904 if (stat(DRM_DIR_NAME
, &st
)) {
908 if (udev_count
== 50)
913 if (stat(buf
, &st
)) {
917 if (udev_count
== 50)
924 fd
= open(buf
, O_RDWR
| O_CLOEXEC
);
925 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
926 fd
, fd
< 0 ? strerror(errno
) : "OK");
931 /* Check if the device node is not what we expect it to be, and recreate it
932 * and try again if so.
934 if (st
.st_rdev
!= dev
) {
936 return DRM_ERR_NOT_ROOT
;
938 mknod(buf
, S_IFCHR
| devmode
, dev
);
939 if (drm_server_info
&& drm_server_info
->get_perms
) {
940 chown_check_return(buf
, user
, group
);
944 fd
= open(buf
, O_RDWR
| O_CLOEXEC
);
945 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
946 fd
, fd
< 0 ? strerror(errno
) : "OK");
950 drmMsg("drmOpenDevice: Open failed\n");
958 * Open the DRM device
960 * \param minor device minor number.
961 * \param create allow to create the device if set.
963 * \return a file descriptor on success, or a negative value on error.
966 * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
967 * name from \p minor and opens it.
969 static int drmOpenMinor(int minor
, int create
, int type
)
972 char buf
[DRM_NODE_NAME_MAX
];
973 const char *dev_name
= drmGetDeviceName(type
);
976 return drmOpenDevice(makedev(DRM_MAJOR
, minor
), minor
, type
);
981 sprintf(buf
, dev_name
, DRM_DIR_NAME
, minor
);
982 if ((fd
= open(buf
, O_RDWR
| O_CLOEXEC
)) >= 0)
989 * Determine whether the DRM kernel driver has been loaded.
991 * \return 1 if the DRM driver is loaded, 0 otherwise.
994 * Determine the presence of the kernel driver by attempting to open the 0
995 * minor and get version information. For backward compatibility with older
996 * Linux implementations, /proc/dri is also checked.
998 drm_public
int drmAvailable(void)
1000 drmVersionPtr version
;
1004 if ((fd
= drmOpenMinor(0, 1, DRM_NODE_PRIMARY
)) < 0) {
1006 /* Try proc for backward Linux compatibility */
1007 if (!access("/proc/dri/0", R_OK
))
1013 if ((version
= drmGetVersion(fd
))) {
1015 drmFreeVersion(version
);
1022 static int drmGetMinorBase(int type
)
1025 case DRM_NODE_PRIMARY
:
1027 case DRM_NODE_RENDER
:
1034 static int drmGetMinorType(int major
, int minor
)
1037 char name
[SPECNAMELEN
];
1040 if (!devname_r(makedev(major
, minor
), S_IFCHR
, name
, sizeof(name
)))
1043 if (sscanf(name
, "drm/%d", &id
) != 1) {
1044 // If not in /dev/drm/ we have the type in the name
1045 if (sscanf(name
, "dri/card%d\n", &id
) >= 1)
1046 return DRM_NODE_PRIMARY
;
1047 else if (sscanf(name
, "dri/renderD%d\n", &id
) >= 1)
1048 return DRM_NODE_RENDER
;
1054 char path
[DRM_NODE_NAME_MAX
];
1055 const char *dev_name
;
1058 for (i
= DRM_NODE_PRIMARY
; i
< DRM_NODE_MAX
; i
++) {
1059 dev_name
= drmGetDeviceName(i
);
1062 snprintf(path
, sizeof(path
), dev_name
, DRM_DIR_NAME
, minor
);
1063 if (!access(path
, F_OK
))
1070 static const char *drmGetMinorName(int type
)
1073 case DRM_NODE_PRIMARY
:
1074 return DRM_PRIMARY_MINOR_NAME
;
1075 case DRM_NODE_RENDER
:
1076 return DRM_RENDER_MINOR_NAME
;
1083 * Open the device by bus ID.
1085 * \param busid bus ID.
1086 * \param type device node type.
1088 * \return a file descriptor on success, or a negative value on error.
1091 * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
1092 * comparing the device bus ID with the one supplied.
1094 * \sa drmOpenMinor() and drmGetBusid().
1096 static int drmOpenByBusid(const char *busid
, int type
)
1098 int i
, pci_domain_ok
= 1;
1102 int base
= drmGetMinorBase(type
);
1107 drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid
);
1108 for (i
= base
; i
< base
+ DRM_MAX_MINOR
; i
++) {
1109 fd
= drmOpenMinor(i
, 1, type
);
1110 drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd
);
1112 /* We need to try for 1.4 first for proper PCI domain support
1113 * and if that fails, we know the kernel is busted
1115 sv
.drm_di_major
= 1;
1116 sv
.drm_di_minor
= 4;
1117 sv
.drm_dd_major
= -1; /* Don't care */
1118 sv
.drm_dd_minor
= -1; /* Don't care */
1119 if (drmSetInterfaceVersion(fd
, &sv
)) {
1123 sv
.drm_di_major
= 1;
1124 sv
.drm_di_minor
= 1;
1125 sv
.drm_dd_major
= -1; /* Don't care */
1126 sv
.drm_dd_minor
= -1; /* Don't care */
1127 drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
1128 drmSetInterfaceVersion(fd
, &sv
);
1130 buf
= drmGetBusid(fd
);
1131 drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf
);
1132 if (buf
&& drmMatchBusID(buf
, busid
, pci_domain_ok
)) {
1146 * Open the device by name.
1148 * \param name driver name.
1149 * \param type the device node type.
1151 * \return a file descriptor on success, or a negative value on error.
1154 * This function opens the first minor number that matches the driver name and
1155 * isn't already in use. If it's in use it then it will already have a bus ID
1158 * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
1160 static int drmOpenByName(const char *name
, int type
)
1164 drmVersionPtr version
;
1166 int base
= drmGetMinorBase(type
);
1172 * Open the first minor number that matches the driver name and isn't
1173 * already in use. If it's in use it will have a busid assigned already.
1175 for (i
= base
; i
< base
+ DRM_MAX_MINOR
; i
++) {
1176 if ((fd
= drmOpenMinor(i
, 1, type
)) >= 0) {
1177 if ((version
= drmGetVersion(fd
))) {
1178 if (!strcmp(version
->name
, name
)) {
1179 drmFreeVersion(version
);
1180 id
= drmGetBusid(fd
);
1181 drmMsg("drmGetBusid returned '%s'\n", id
? id
: "NULL");
1190 drmFreeVersion(version
);
1198 /* Backward-compatibility /proc support */
1199 for (i
= 0; i
< 8; i
++) {
1200 char proc_name
[64], buf
[512];
1201 char *driver
, *pt
, *devstring
;
1204 sprintf(proc_name
, "/proc/dri/%d/name", i
);
1205 if ((fd
= open(proc_name
, O_RDONLY
)) >= 0) {
1206 retcode
= read(fd
, buf
, sizeof(buf
)-1);
1209 buf
[retcode
-1] = '\0';
1210 for (driver
= pt
= buf
; *pt
&& *pt
!= ' '; ++pt
)
1212 if (*pt
) { /* Device is next */
1214 if (!strcmp(driver
, name
)) { /* Match */
1215 for (devstring
= ++pt
; *pt
&& *pt
!= ' '; ++pt
)
1217 if (*pt
) { /* Found busid */
1218 return drmOpenByBusid(++pt
, type
);
1219 } else { /* No busid */
1220 return drmOpenDevice(strtol(devstring
, NULL
, 0),i
, type
);
1234 * Open the DRM device.
1236 * Looks up the specified name and bus ID, and opens the device found. The
1237 * entry in /dev/dri is created if necessary and if called by root.
1239 * \param name driver name. Not referenced if bus ID is supplied.
1240 * \param busid bus ID. Zero if not known.
1242 * \return a file descriptor on success, or a negative value on error.
1245 * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
1248 drm_public
int drmOpen(const char *name
, const char *busid
)
1250 return drmOpenWithType(name
, busid
, DRM_NODE_PRIMARY
);
1254 * Open the DRM device with specified type.
1256 * Looks up the specified name and bus ID, and opens the device found. The
1257 * entry in /dev/dri is created if necessary and if called by root.
1259 * \param name driver name. Not referenced if bus ID is supplied.
1260 * \param busid bus ID. Zero if not known.
1261 * \param type the device node type to open, PRIMARY or RENDER
1263 * \return a file descriptor on success, or a negative value on error.
1266 * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
1269 drm_public
int drmOpenWithType(const char *name
, const char *busid
, int type
)
1271 if (name
!= NULL
&& drm_server_info
&&
1272 drm_server_info
->load_module
&& !drmAvailable()) {
1273 /* try to load the kernel module */
1274 if (!drm_server_info
->load_module(name
)) {
1275 drmMsg("[drm] failed to load kernel module \"%s\"\n", name
);
1281 int fd
= drmOpenByBusid(busid
, type
);
1287 return drmOpenByName(name
, type
);
1292 drm_public
int drmOpenControl(int minor
)
1297 drm_public
int drmOpenRender(int minor
)
1299 return drmOpenMinor(minor
, 0, DRM_NODE_RENDER
);
1303 * Free the version information returned by drmGetVersion().
1305 * \param v pointer to the version information.
1308 * It frees the memory pointed by \p %v as well as all the non-null strings
1311 drm_public
void drmFreeVersion(drmVersionPtr v
)
1323 * Free the non-public version information returned by the kernel.
1325 * \param v pointer to the version information.
1328 * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
1329 * the non-null strings pointers in it.
1331 static void drmFreeKernelVersion(drm_version_t
*v
)
1343 * Copy version information.
1345 * \param d destination pointer.
1346 * \param s source pointer.
1349 * Used by drmGetVersion() to translate the information returned by the ioctl
1350 * interface in a private structure into the public structure counterpart.
1352 static void drmCopyVersion(drmVersionPtr d
, const drm_version_t
*s
)
1354 d
->version_major
= s
->version_major
;
1355 d
->version_minor
= s
->version_minor
;
1356 d
->version_patchlevel
= s
->version_patchlevel
;
1357 d
->name_len
= s
->name_len
;
1358 d
->name
= strdup(s
->name
);
1359 d
->date_len
= s
->date_len
;
1360 d
->date
= strdup(s
->date
);
1361 d
->desc_len
= s
->desc_len
;
1362 d
->desc
= strdup(s
->desc
);
1367 * Query the driver version information.
1369 * \param fd file descriptor.
1371 * \return pointer to a drmVersion structure which should be freed with
1374 * \note Similar information is available via /proc/dri.
1377 * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
1378 * first with zeros to get the string lengths, and then the actually strings.
1379 * It also null-terminates them since they might not be already.
1381 drm_public drmVersionPtr
drmGetVersion(int fd
)
1383 drmVersionPtr retval
;
1384 drm_version_t
*version
= drmMalloc(sizeof(*version
));
1386 if (drmIoctl(fd
, DRM_IOCTL_VERSION
, version
)) {
1387 drmFreeKernelVersion(version
);
1391 if (version
->name_len
)
1392 version
->name
= drmMalloc(version
->name_len
+ 1);
1393 if (version
->date_len
)
1394 version
->date
= drmMalloc(version
->date_len
+ 1);
1395 if (version
->desc_len
)
1396 version
->desc
= drmMalloc(version
->desc_len
+ 1);
1398 if (drmIoctl(fd
, DRM_IOCTL_VERSION
, version
)) {
1399 drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno
));
1400 drmFreeKernelVersion(version
);
1404 /* The results might not be null-terminated strings, so terminate them. */
1405 if (version
->name_len
) version
->name
[version
->name_len
] = '\0';
1406 if (version
->date_len
) version
->date
[version
->date_len
] = '\0';
1407 if (version
->desc_len
) version
->desc
[version
->desc_len
] = '\0';
1409 retval
= drmMalloc(sizeof(*retval
));
1410 drmCopyVersion(retval
, version
);
1411 drmFreeKernelVersion(version
);
1417 * Get version information for the DRM user space library.
1419 * This version number is driver independent.
1421 * \param fd file descriptor.
1423 * \return version information.
1426 * This function allocates and fills a drm_version structure with a hard coded
1429 drm_public drmVersionPtr
drmGetLibVersion(int fd
)
1431 drm_version_t
*version
= drmMalloc(sizeof(*version
));
1434 * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
1435 * revision 1.0.x = original DRM interface with no drmGetLibVersion
1436 * entry point and many drm<Device> extensions
1437 * revision 1.1.x = added drmCommand entry points for device extensions
1438 * added drmGetLibVersion to identify libdrm.a version
1439 * revision 1.2.x = added drmSetInterfaceVersion
1440 * modified drmOpen to handle both busid and name
1441 * revision 1.3.x = added server + memory manager
1443 version
->version_major
= 1;
1444 version
->version_minor
= 3;
1445 version
->version_patchlevel
= 0;
1447 return (drmVersionPtr
)version
;
1450 drm_public
int drmGetCap(int fd
, uint64_t capability
, uint64_t *value
)
1452 struct drm_get_cap cap
;
1456 cap
.capability
= capability
;
1458 ret
= drmIoctl(fd
, DRM_IOCTL_GET_CAP
, &cap
);
1466 drm_public
int drmSetClientCap(int fd
, uint64_t capability
, uint64_t value
)
1468 struct drm_set_client_cap cap
;
1471 cap
.capability
= capability
;
1474 return drmIoctl(fd
, DRM_IOCTL_SET_CLIENT_CAP
, &cap
);
1478 * Free the bus ID information.
1480 * \param busid bus ID information string as given by drmGetBusid().
1483 * This function is just frees the memory pointed by \p busid.
1485 drm_public
void drmFreeBusid(const char *busid
)
1487 drmFree((void *)busid
);
1492 * Get the bus ID of the device.
1494 * \param fd file descriptor.
1496 * \return bus ID string.
1499 * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
1500 * get the string length and data, passing the arguments in a drm_unique
1503 drm_public
char *drmGetBusid(int fd
)
1509 if (drmIoctl(fd
, DRM_IOCTL_GET_UNIQUE
, &u
))
1511 u
.unique
= drmMalloc(u
.unique_len
+ 1);
1512 if (drmIoctl(fd
, DRM_IOCTL_GET_UNIQUE
, &u
)) {
1516 u
.unique
[u
.unique_len
] = '\0';
1523 * Set the bus ID of the device.
1525 * \param fd file descriptor.
1526 * \param busid bus ID string.
1528 * \return zero on success, negative on failure.
1531 * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
1532 * the arguments in a drm_unique structure.
1534 drm_public
int drmSetBusid(int fd
, const char *busid
)
1539 u
.unique
= (char *)busid
;
1540 u
.unique_len
= strlen(busid
);
1542 if (drmIoctl(fd
, DRM_IOCTL_SET_UNIQUE
, &u
)) {
1548 drm_public
int drmGetMagic(int fd
, drm_magic_t
* magic
)
1555 if (drmIoctl(fd
, DRM_IOCTL_GET_MAGIC
, &auth
))
1557 *magic
= auth
.magic
;
1561 drm_public
int drmAuthMagic(int fd
, drm_magic_t magic
)
1567 if (drmIoctl(fd
, DRM_IOCTL_AUTH_MAGIC
, &auth
))
1573 * Specifies a range of memory that is available for mapping by a
1576 * \param fd file descriptor.
1577 * \param offset usually the physical address. The actual meaning depends of
1578 * the \p type parameter. See below.
1579 * \param size of the memory in bytes.
1580 * \param type type of the memory to be mapped.
1581 * \param flags combination of several flags to modify the function actions.
1582 * \param handle will be set to a value that may be used as the offset
1583 * parameter for mmap().
1585 * \return zero on success or a negative value on error.
1587 * \par Mapping the frame buffer
1588 * For the frame buffer
1589 * - \p offset will be the physical address of the start of the frame buffer,
1590 * - \p size will be the size of the frame buffer in bytes, and
1591 * - \p type will be DRM_FRAME_BUFFER.
1594 * The area mapped will be uncached. If MTRR support is available in the
1595 * kernel, the frame buffer area will be set to write combining.
1597 * \par Mapping the MMIO register area
1598 * For the MMIO register area,
1599 * - \p offset will be the physical address of the start of the register area,
1600 * - \p size will be the size of the register area bytes, and
1601 * - \p type will be DRM_REGISTERS.
1603 * The area mapped will be uncached.
1605 * \par Mapping the SAREA
1607 * - \p offset will be ignored and should be set to zero,
1608 * - \p size will be the desired size of the SAREA in bytes,
1609 * - \p type will be DRM_SHM.
1612 * A shared memory area of the requested size will be created and locked in
1613 * kernel memory. This area may be mapped into client-space by using the handle
1616 * \note May only be called by root.
1619 * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
1620 * the arguments in a drm_map structure.
1622 drm_public
int drmAddMap(int fd
, drm_handle_t offset
, drmSize size
, drmMapType type
,
1623 drmMapFlags flags
, drm_handle_t
*handle
)
1628 map
.offset
= offset
;
1630 map
.type
= (enum drm_map_type
)type
;
1631 map
.flags
= (enum drm_map_flags
)flags
;
1632 if (drmIoctl(fd
, DRM_IOCTL_ADD_MAP
, &map
))
1635 *handle
= (drm_handle_t
)(uintptr_t)map
.handle
;
1639 drm_public
int drmRmMap(int fd
, drm_handle_t handle
)
1644 map
.handle
= (void *)(uintptr_t)handle
;
1646 if(drmIoctl(fd
, DRM_IOCTL_RM_MAP
, &map
))
1652 * Make buffers available for DMA transfers.
1654 * \param fd file descriptor.
1655 * \param count number of buffers.
1656 * \param size size of each buffer.
1657 * \param flags buffer allocation flags.
1658 * \param agp_offset offset in the AGP aperture
1660 * \return number of buffers allocated, negative on error.
1663 * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
1667 drm_public
int drmAddBufs(int fd
, int count
, int size
, drmBufDescFlags flags
,
1670 drm_buf_desc_t request
;
1673 request
.count
= count
;
1674 request
.size
= size
;
1675 request
.flags
= (int)flags
;
1676 request
.agp_start
= agp_offset
;
1678 if (drmIoctl(fd
, DRM_IOCTL_ADD_BUFS
, &request
))
1680 return request
.count
;
1683 drm_public
int drmMarkBufs(int fd
, double low
, double high
)
1685 drm_buf_info_t info
;
1690 if (drmIoctl(fd
, DRM_IOCTL_INFO_BUFS
, &info
))
1696 if (!(info
.list
= drmMalloc(info
.count
* sizeof(*info
.list
))))
1699 if (drmIoctl(fd
, DRM_IOCTL_INFO_BUFS
, &info
)) {
1700 int retval
= -errno
;
1705 for (i
= 0; i
< info
.count
; i
++) {
1706 info
.list
[i
].low_mark
= low
* info
.list
[i
].count
;
1707 info
.list
[i
].high_mark
= high
* info
.list
[i
].count
;
1708 if (drmIoctl(fd
, DRM_IOCTL_MARK_BUFS
, &info
.list
[i
])) {
1709 int retval
= -errno
;
1722 * \param fd file descriptor.
1723 * \param count number of buffers to free.
1724 * \param list list of buffers to be freed.
1726 * \return zero on success, or a negative value on failure.
1728 * \note This function is primarily used for debugging.
1731 * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
1732 * the arguments in a drm_buf_free structure.
1734 drm_public
int drmFreeBufs(int fd
, int count
, int *list
)
1736 drm_buf_free_t request
;
1739 request
.count
= count
;
1740 request
.list
= list
;
1741 if (drmIoctl(fd
, DRM_IOCTL_FREE_BUFS
, &request
))
1750 * \param fd file descriptor.
1753 * This function closes the file descriptor.
1755 drm_public
int drmClose(int fd
)
1757 unsigned long key
= drmGetKeyFromFd(fd
);
1758 drmHashEntry
*entry
= drmGetEntry(fd
);
1760 drmHashDestroy(entry
->tagTable
);
1763 entry
->tagTable
= NULL
;
1765 drmHashDelete(drmHashTable
, key
);
1773 * Map a region of memory.
1775 * \param fd file descriptor.
1776 * \param handle handle returned by drmAddMap().
1777 * \param size size in bytes. Must match the size used by drmAddMap().
1778 * \param address will contain the user-space virtual address where the mapping
1781 * \return zero on success, or a negative value on failure.
1784 * This function is a wrapper for mmap().
1786 drm_public
int drmMap(int fd
, drm_handle_t handle
, drmSize size
,
1787 drmAddressPtr address
)
1789 static unsigned long pagesize_mask
= 0;
1795 pagesize_mask
= getpagesize() - 1;
1797 size
= (size
+ pagesize_mask
) & ~pagesize_mask
;
1799 *address
= drm_mmap(0, size
, PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, handle
);
1800 if (*address
== MAP_FAILED
)
1807 * Unmap mappings obtained with drmMap().
1809 * \param address address as given by drmMap().
1810 * \param size size in bytes. Must match the size used by drmMap().
1812 * \return zero on success, or a negative value on failure.
1815 * This function is a wrapper for munmap().
1817 drm_public
int drmUnmap(drmAddress address
, drmSize size
)
1819 return drm_munmap(address
, size
);
1822 drm_public drmBufInfoPtr
drmGetBufInfo(int fd
)
1824 drm_buf_info_t info
;
1825 drmBufInfoPtr retval
;
1830 if (drmIoctl(fd
, DRM_IOCTL_INFO_BUFS
, &info
))
1834 if (!(info
.list
= drmMalloc(info
.count
* sizeof(*info
.list
))))
1837 if (drmIoctl(fd
, DRM_IOCTL_INFO_BUFS
, &info
)) {
1842 retval
= drmMalloc(sizeof(*retval
));
1843 retval
->count
= info
.count
;
1844 if (!(retval
->list
= drmMalloc(info
.count
* sizeof(*retval
->list
)))) {
1850 for (i
= 0; i
< info
.count
; i
++) {
1851 retval
->list
[i
].count
= info
.list
[i
].count
;
1852 retval
->list
[i
].size
= info
.list
[i
].size
;
1853 retval
->list
[i
].low_mark
= info
.list
[i
].low_mark
;
1854 retval
->list
[i
].high_mark
= info
.list
[i
].high_mark
;
1863 * Map all DMA buffers into client-virtual space.
1865 * \param fd file descriptor.
1867 * \return a pointer to a ::drmBufMap structure.
1869 * \note The client may not use these buffers until obtaining buffer indices
1873 * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
1874 * information about the buffers in a drm_buf_map structure into the
1875 * client-visible data structures.
1877 drm_public drmBufMapPtr
drmMapBufs(int fd
)
1880 drmBufMapPtr retval
;
1884 if (drmIoctl(fd
, DRM_IOCTL_MAP_BUFS
, &bufs
))
1890 if (!(bufs
.list
= drmMalloc(bufs
.count
* sizeof(*bufs
.list
))))
1893 if (drmIoctl(fd
, DRM_IOCTL_MAP_BUFS
, &bufs
)) {
1898 retval
= drmMalloc(sizeof(*retval
));
1899 retval
->count
= bufs
.count
;
1900 retval
->list
= drmMalloc(bufs
.count
* sizeof(*retval
->list
));
1901 for (i
= 0; i
< bufs
.count
; i
++) {
1902 retval
->list
[i
].idx
= bufs
.list
[i
].idx
;
1903 retval
->list
[i
].total
= bufs
.list
[i
].total
;
1904 retval
->list
[i
].used
= 0;
1905 retval
->list
[i
].address
= bufs
.list
[i
].address
;
1914 * Unmap buffers allocated with drmMapBufs().
1916 * \return zero on success, or negative value on failure.
1919 * Calls munmap() for every buffer stored in \p bufs and frees the
1920 * memory allocated by drmMapBufs().
1922 drm_public
int drmUnmapBufs(drmBufMapPtr bufs
)
1926 for (i
= 0; i
< bufs
->count
; i
++) {
1927 drm_munmap(bufs
->list
[i
].address
, bufs
->list
[i
].total
);
1930 drmFree(bufs
->list
);
1936 #define DRM_DMA_RETRY 16
1939 * Reserve DMA buffers.
1941 * \param fd file descriptor.
1944 * \return zero on success, or a negative value on failure.
1947 * Assemble the arguments into a drm_dma structure and keeps issuing the
1948 * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
1950 drm_public
int drmDMA(int fd
, drmDMAReqPtr request
)
1955 dma
.context
= request
->context
;
1956 dma
.send_count
= request
->send_count
;
1957 dma
.send_indices
= request
->send_list
;
1958 dma
.send_sizes
= request
->send_sizes
;
1959 dma
.flags
= (enum drm_dma_flags
)request
->flags
;
1960 dma
.request_count
= request
->request_count
;
1961 dma
.request_size
= request
->request_size
;
1962 dma
.request_indices
= request
->request_list
;
1963 dma
.request_sizes
= request
->request_sizes
;
1964 dma
.granted_count
= 0;
1967 ret
= ioctl( fd
, DRM_IOCTL_DMA
, &dma
);
1968 } while ( ret
&& errno
== EAGAIN
&& i
++ < DRM_DMA_RETRY
);
1971 request
->granted_count
= dma
.granted_count
;
1980 * Obtain heavyweight hardware lock.
1982 * \param fd file descriptor.
1983 * \param context context.
1984 * \param flags flags that determine the state of the hardware when the function
1987 * \return always zero.
1990 * This function translates the arguments into a drm_lock structure and issue
1991 * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
1993 drm_public
int drmGetLock(int fd
, drm_context_t context
, drmLockFlags flags
)
1998 lock
.context
= context
;
2000 if (flags
& DRM_LOCK_READY
) lock
.flags
|= _DRM_LOCK_READY
;
2001 if (flags
& DRM_LOCK_QUIESCENT
) lock
.flags
|= _DRM_LOCK_QUIESCENT
;
2002 if (flags
& DRM_LOCK_FLUSH
) lock
.flags
|= _DRM_LOCK_FLUSH
;
2003 if (flags
& DRM_LOCK_FLUSH_ALL
) lock
.flags
|= _DRM_LOCK_FLUSH_ALL
;
2004 if (flags
& DRM_HALT_ALL_QUEUES
) lock
.flags
|= _DRM_HALT_ALL_QUEUES
;
2005 if (flags
& DRM_HALT_CUR_QUEUES
) lock
.flags
|= _DRM_HALT_CUR_QUEUES
;
2007 while (drmIoctl(fd
, DRM_IOCTL_LOCK
, &lock
))
2013 * Release the hardware lock.
2015 * \param fd file descriptor.
2016 * \param context context.
2018 * \return zero on success, or a negative value on failure.
2021 * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
2022 * argument in a drm_lock structure.
2024 drm_public
int drmUnlock(int fd
, drm_context_t context
)
2029 lock
.context
= context
;
2030 return drmIoctl(fd
, DRM_IOCTL_UNLOCK
, &lock
);
2033 drm_public drm_context_t
*drmGetReservedContextList(int fd
, int *count
)
2037 drm_context_t
* retval
;
2041 if (drmIoctl(fd
, DRM_IOCTL_RES_CTX
, &res
))
2047 if (!(list
= drmMalloc(res
.count
* sizeof(*list
))))
2049 if (!(retval
= drmMalloc(res
.count
* sizeof(*retval
))))
2052 res
.contexts
= list
;
2053 if (drmIoctl(fd
, DRM_IOCTL_RES_CTX
, &res
))
2054 goto err_free_context
;
2056 for (i
= 0; i
< res
.count
; i
++)
2057 retval
[i
] = list
[i
].handle
;
2070 drm_public
void drmFreeReservedContextList(drm_context_t
*pt
)
2078 * Used by the X server during GLXContext initialization. This causes
2079 * per-context kernel-level resources to be allocated.
2081 * \param fd file descriptor.
2082 * \param handle is set on success. To be used by the client when requesting DMA
2083 * dispatch with drmDMA().
2085 * \return zero on success, or a negative value on failure.
2087 * \note May only be called by root.
2090 * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
2091 * argument in a drm_ctx structure.
2093 drm_public
int drmCreateContext(int fd
, drm_context_t
*handle
)
2098 if (drmIoctl(fd
, DRM_IOCTL_ADD_CTX
, &ctx
))
2100 *handle
= ctx
.handle
;
2104 drm_public
int drmSwitchToContext(int fd
, drm_context_t context
)
2109 ctx
.handle
= context
;
2110 if (drmIoctl(fd
, DRM_IOCTL_SWITCH_CTX
, &ctx
))
2115 drm_public
int drmSetContextFlags(int fd
, drm_context_t context
,
2116 drm_context_tFlags flags
)
2121 * Context preserving means that no context switches are done between DMA
2122 * buffers from one context and the next. This is suitable for use in the
2123 * X server (which promises to maintain hardware context), or in the
2124 * client-side library when buffers are swapped on behalf of two threads.
2127 ctx
.handle
= context
;
2128 if (flags
& DRM_CONTEXT_PRESERVED
)
2129 ctx
.flags
|= _DRM_CONTEXT_PRESERVED
;
2130 if (flags
& DRM_CONTEXT_2DONLY
)
2131 ctx
.flags
|= _DRM_CONTEXT_2DONLY
;
2132 if (drmIoctl(fd
, DRM_IOCTL_MOD_CTX
, &ctx
))
2137 drm_public
int drmGetContextFlags(int fd
, drm_context_t context
,
2138 drm_context_tFlagsPtr flags
)
2143 ctx
.handle
= context
;
2144 if (drmIoctl(fd
, DRM_IOCTL_GET_CTX
, &ctx
))
2147 if (ctx
.flags
& _DRM_CONTEXT_PRESERVED
)
2148 *flags
|= DRM_CONTEXT_PRESERVED
;
2149 if (ctx
.flags
& _DRM_CONTEXT_2DONLY
)
2150 *flags
|= DRM_CONTEXT_2DONLY
;
2157 * Free any kernel-level resources allocated with drmCreateContext() associated
2160 * \param fd file descriptor.
2161 * \param handle handle given by drmCreateContext().
2163 * \return zero on success, or a negative value on failure.
2165 * \note May only be called by root.
2168 * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
2169 * argument in a drm_ctx structure.
2171 drm_public
int drmDestroyContext(int fd
, drm_context_t handle
)
2176 ctx
.handle
= handle
;
2177 if (drmIoctl(fd
, DRM_IOCTL_RM_CTX
, &ctx
))
2182 drm_public
int drmCreateDrawable(int fd
, drm_drawable_t
*handle
)
2187 if (drmIoctl(fd
, DRM_IOCTL_ADD_DRAW
, &draw
))
2189 *handle
= draw
.handle
;
2193 drm_public
int drmDestroyDrawable(int fd
, drm_drawable_t handle
)
2198 draw
.handle
= handle
;
2199 if (drmIoctl(fd
, DRM_IOCTL_RM_DRAW
, &draw
))
2204 drm_public
int drmUpdateDrawableInfo(int fd
, drm_drawable_t handle
,
2205 drm_drawable_info_type_t type
,
2206 unsigned int num
, void *data
)
2208 drm_update_draw_t update
;
2211 update
.handle
= handle
;
2214 update
.data
= (unsigned long long)(unsigned long)data
;
2216 if (drmIoctl(fd
, DRM_IOCTL_UPDATE_DRAW
, &update
))
2222 drm_public
int drmCrtcGetSequence(int fd
, uint32_t crtcId
, uint64_t *sequence
,
2225 struct drm_crtc_get_sequence get_seq
;
2229 get_seq
.crtc_id
= crtcId
;
2230 ret
= drmIoctl(fd
, DRM_IOCTL_CRTC_GET_SEQUENCE
, &get_seq
);
2235 *sequence
= get_seq
.sequence
;
2237 *ns
= get_seq
.sequence_ns
;
2241 drm_public
int drmCrtcQueueSequence(int fd
, uint32_t crtcId
, uint32_t flags
,
2243 uint64_t *sequence_queued
,
2246 struct drm_crtc_queue_sequence queue_seq
;
2249 memclear(queue_seq
);
2250 queue_seq
.crtc_id
= crtcId
;
2251 queue_seq
.flags
= flags
;
2252 queue_seq
.sequence
= sequence
;
2253 queue_seq
.user_data
= user_data
;
2255 ret
= drmIoctl(fd
, DRM_IOCTL_CRTC_QUEUE_SEQUENCE
, &queue_seq
);
2256 if (ret
== 0 && sequence_queued
)
2257 *sequence_queued
= queue_seq
.sequence
;
2263 * Acquire the AGP device.
2265 * Must be called before any of the other AGP related calls.
2267 * \param fd file descriptor.
2269 * \return zero on success, or a negative value on failure.
2272 * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
2274 drm_public
int drmAgpAcquire(int fd
)
2276 if (drmIoctl(fd
, DRM_IOCTL_AGP_ACQUIRE
, NULL
))
2283 * Release the AGP device.
2285 * \param fd file descriptor.
2287 * \return zero on success, or a negative value on failure.
2290 * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
2292 drm_public
int drmAgpRelease(int fd
)
2294 if (drmIoctl(fd
, DRM_IOCTL_AGP_RELEASE
, NULL
))
2303 * \param fd file descriptor.
2304 * \param mode AGP mode.
2306 * \return zero on success, or a negative value on failure.
2309 * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
2310 * argument in a drm_agp_mode structure.
2312 drm_public
int drmAgpEnable(int fd
, unsigned long mode
)
2318 if (drmIoctl(fd
, DRM_IOCTL_AGP_ENABLE
, &m
))
2325 * Allocate a chunk of AGP memory.
2327 * \param fd file descriptor.
2328 * \param size requested memory size in bytes. Will be rounded to page boundary.
2329 * \param type type of memory to allocate.
2330 * \param address if not zero, will be set to the physical address of the
2332 * \param handle on success will be set to a handle of the allocated memory.
2334 * \return zero on success, or a negative value on failure.
2337 * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
2338 * arguments in a drm_agp_buffer structure.
2340 drm_public
int drmAgpAlloc(int fd
, unsigned long size
, unsigned long type
,
2341 unsigned long *address
, drm_handle_t
*handle
)
2346 *handle
= DRM_AGP_NO_HANDLE
;
2349 if (drmIoctl(fd
, DRM_IOCTL_AGP_ALLOC
, &b
))
2352 *address
= b
.physical
;
2359 * Free a chunk of AGP memory.
2361 * \param fd file descriptor.
2362 * \param handle handle to the allocated memory, as given by drmAgpAllocate().
2364 * \return zero on success, or a negative value on failure.
2367 * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
2368 * argument in a drm_agp_buffer structure.
2370 drm_public
int drmAgpFree(int fd
, drm_handle_t handle
)
2376 if (drmIoctl(fd
, DRM_IOCTL_AGP_FREE
, &b
))
2383 * Bind a chunk of AGP memory.
2385 * \param fd file descriptor.
2386 * \param handle handle to the allocated memory, as given by drmAgpAllocate().
2387 * \param offset offset in bytes. It will round to page boundary.
2389 * \return zero on success, or a negative value on failure.
2392 * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
2393 * argument in a drm_agp_binding structure.
2395 drm_public
int drmAgpBind(int fd
, drm_handle_t handle
, unsigned long offset
)
2397 drm_agp_binding_t b
;
2402 if (drmIoctl(fd
, DRM_IOCTL_AGP_BIND
, &b
))
2409 * Unbind a chunk of AGP memory.
2411 * \param fd file descriptor.
2412 * \param handle handle to the allocated memory, as given by drmAgpAllocate().
2414 * \return zero on success, or a negative value on failure.
2417 * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
2418 * the argument in a drm_agp_binding structure.
2420 drm_public
int drmAgpUnbind(int fd
, drm_handle_t handle
)
2422 drm_agp_binding_t b
;
2426 if (drmIoctl(fd
, DRM_IOCTL_AGP_UNBIND
, &b
))
2433 * Get AGP driver major version number.
2435 * \param fd file descriptor.
2437 * \return major version number on success, or a negative value on failure..
2440 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2441 * necessary information in a drm_agp_info structure.
2443 drm_public
int drmAgpVersionMajor(int fd
)
2449 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2451 return i
.agp_version_major
;
2456 * Get AGP driver minor version number.
2458 * \param fd file descriptor.
2460 * \return minor version number on success, or a negative value on failure.
2463 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2464 * necessary information in a drm_agp_info structure.
2466 drm_public
int drmAgpVersionMinor(int fd
)
2472 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2474 return i
.agp_version_minor
;
2481 * \param fd file descriptor.
2483 * \return mode on success, or zero on failure.
2486 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2487 * necessary information in a drm_agp_info structure.
2489 drm_public
unsigned long drmAgpGetMode(int fd
)
2495 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2502 * Get AGP aperture base.
2504 * \param fd file descriptor.
2506 * \return aperture base on success, zero on failure.
2509 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2510 * necessary information in a drm_agp_info structure.
2512 drm_public
unsigned long drmAgpBase(int fd
)
2518 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2520 return i
.aperture_base
;
2525 * Get AGP aperture size.
2527 * \param fd file descriptor.
2529 * \return aperture size on success, zero on failure.
2532 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2533 * necessary information in a drm_agp_info structure.
2535 drm_public
unsigned long drmAgpSize(int fd
)
2541 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2543 return i
.aperture_size
;
2548 * Get used AGP memory.
2550 * \param fd file descriptor.
2552 * \return memory used on success, or zero on failure.
2555 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2556 * necessary information in a drm_agp_info structure.
2558 drm_public
unsigned long drmAgpMemoryUsed(int fd
)
2564 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2566 return i
.memory_used
;
2571 * Get available AGP memory.
2573 * \param fd file descriptor.
2575 * \return memory available on success, or zero on failure.
2578 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2579 * necessary information in a drm_agp_info structure.
2581 drm_public
unsigned long drmAgpMemoryAvail(int fd
)
2587 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2589 return i
.memory_allowed
;
2594 * Get hardware vendor ID.
2596 * \param fd file descriptor.
2598 * \return vendor ID on success, or zero on failure.
2601 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2602 * necessary information in a drm_agp_info structure.
2604 drm_public
unsigned int drmAgpVendorId(int fd
)
2610 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2617 * Get hardware device ID.
2619 * \param fd file descriptor.
2621 * \return zero on success, or zero on failure.
2624 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2625 * necessary information in a drm_agp_info structure.
2627 drm_public
unsigned int drmAgpDeviceId(int fd
)
2633 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2638 drm_public
int drmScatterGatherAlloc(int fd
, unsigned long size
,
2639 drm_handle_t
*handle
)
2641 drm_scatter_gather_t sg
;
2647 if (drmIoctl(fd
, DRM_IOCTL_SG_ALLOC
, &sg
))
2649 *handle
= sg
.handle
;
2653 drm_public
int drmScatterGatherFree(int fd
, drm_handle_t handle
)
2655 drm_scatter_gather_t sg
;
2659 if (drmIoctl(fd
, DRM_IOCTL_SG_FREE
, &sg
))
2667 * \param fd file descriptor.
2668 * \param vbl pointer to a drmVBlank structure.
2670 * \return zero on success, or a negative value on failure.
2673 * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
2675 drm_public
int drmWaitVBlank(int fd
, drmVBlankPtr vbl
)
2677 struct timespec timeout
, cur
;
2680 ret
= clock_gettime(CLOCK_MONOTONIC
, &timeout
);
2682 fprintf(stderr
, "clock_gettime failed: %s\n", strerror(errno
));
2688 ret
= ioctl(fd
, DRM_IOCTL_WAIT_VBLANK
, vbl
);
2689 vbl
->request
.type
&= ~DRM_VBLANK_RELATIVE
;
2690 if (ret
&& errno
== EINTR
) {
2691 clock_gettime(CLOCK_MONOTONIC
, &cur
);
2692 /* Timeout after 1s */
2693 if (cur
.tv_sec
> timeout
.tv_sec
+ 1 ||
2694 (cur
.tv_sec
== timeout
.tv_sec
&& cur
.tv_nsec
>=
2701 } while (ret
&& errno
== EINTR
);
2707 drm_public
int drmError(int err
, const char *label
)
2710 case DRM_ERR_NO_DEVICE
:
2711 fprintf(stderr
, "%s: no device\n", label
);
2713 case DRM_ERR_NO_ACCESS
:
2714 fprintf(stderr
, "%s: no access\n", label
);
2716 case DRM_ERR_NOT_ROOT
:
2717 fprintf(stderr
, "%s: not root\n", label
);
2719 case DRM_ERR_INVALID
:
2720 fprintf(stderr
, "%s: invalid args\n", label
);
2725 fprintf( stderr
, "%s: error %d (%s)\n", label
, err
, strerror(err
) );
2733 * Install IRQ handler.
2735 * \param fd file descriptor.
2736 * \param irq IRQ number.
2738 * \return zero on success, or a negative value on failure.
2741 * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
2742 * argument in a drm_control structure.
2744 drm_public
int drmCtlInstHandler(int fd
, int irq
)
2749 ctl
.func
= DRM_INST_HANDLER
;
2751 if (drmIoctl(fd
, DRM_IOCTL_CONTROL
, &ctl
))
2758 * Uninstall IRQ handler.
2760 * \param fd file descriptor.
2762 * \return zero on success, or a negative value on failure.
2765 * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
2766 * argument in a drm_control structure.
2768 drm_public
int drmCtlUninstHandler(int fd
)
2773 ctl
.func
= DRM_UNINST_HANDLER
;
2775 if (drmIoctl(fd
, DRM_IOCTL_CONTROL
, &ctl
))
2780 drm_public
int drmFinish(int fd
, int context
, drmLockFlags flags
)
2785 lock
.context
= context
;
2786 if (flags
& DRM_LOCK_READY
) lock
.flags
|= _DRM_LOCK_READY
;
2787 if (flags
& DRM_LOCK_QUIESCENT
) lock
.flags
|= _DRM_LOCK_QUIESCENT
;
2788 if (flags
& DRM_LOCK_FLUSH
) lock
.flags
|= _DRM_LOCK_FLUSH
;
2789 if (flags
& DRM_LOCK_FLUSH_ALL
) lock
.flags
|= _DRM_LOCK_FLUSH_ALL
;
2790 if (flags
& DRM_HALT_ALL_QUEUES
) lock
.flags
|= _DRM_HALT_ALL_QUEUES
;
2791 if (flags
& DRM_HALT_CUR_QUEUES
) lock
.flags
|= _DRM_HALT_CUR_QUEUES
;
2792 if (drmIoctl(fd
, DRM_IOCTL_FINISH
, &lock
))
2798 * Get IRQ from bus ID.
2800 * \param fd file descriptor.
2801 * \param busnum bus number.
2802 * \param devnum device number.
2803 * \param funcnum function number.
2805 * \return IRQ number on success, or a negative value on failure.
2808 * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
2809 * arguments in a drm_irq_busid structure.
2811 drm_public
int drmGetInterruptFromBusID(int fd
, int busnum
, int devnum
,
2819 p
.funcnum
= funcnum
;
2820 if (drmIoctl(fd
, DRM_IOCTL_IRQ_BUSID
, &p
))
2825 drm_public
int drmAddContextTag(int fd
, drm_context_t context
, void *tag
)
2827 drmHashEntry
*entry
= drmGetEntry(fd
);
2829 if (drmHashInsert(entry
->tagTable
, context
, tag
)) {
2830 drmHashDelete(entry
->tagTable
, context
);
2831 drmHashInsert(entry
->tagTable
, context
, tag
);
2836 drm_public
int drmDelContextTag(int fd
, drm_context_t context
)
2838 drmHashEntry
*entry
= drmGetEntry(fd
);
2840 return drmHashDelete(entry
->tagTable
, context
);
2843 drm_public
void *drmGetContextTag(int fd
, drm_context_t context
)
2845 drmHashEntry
*entry
= drmGetEntry(fd
);
2848 if (drmHashLookup(entry
->tagTable
, context
, &value
))
2854 drm_public
int drmAddContextPrivateMapping(int fd
, drm_context_t ctx_id
,
2855 drm_handle_t handle
)
2857 drm_ctx_priv_map_t map
;
2860 map
.ctx_id
= ctx_id
;
2861 map
.handle
= (void *)(uintptr_t)handle
;
2863 if (drmIoctl(fd
, DRM_IOCTL_SET_SAREA_CTX
, &map
))
2868 drm_public
int drmGetContextPrivateMapping(int fd
, drm_context_t ctx_id
,
2869 drm_handle_t
*handle
)
2871 drm_ctx_priv_map_t map
;
2874 map
.ctx_id
= ctx_id
;
2876 if (drmIoctl(fd
, DRM_IOCTL_GET_SAREA_CTX
, &map
))
2879 *handle
= (drm_handle_t
)(uintptr_t)map
.handle
;
2884 drm_public
int drmGetMap(int fd
, int idx
, drm_handle_t
*offset
, drmSize
*size
,
2885 drmMapType
*type
, drmMapFlags
*flags
,
2886 drm_handle_t
*handle
, int *mtrr
)
2892 if (drmIoctl(fd
, DRM_IOCTL_GET_MAP
, &map
))
2894 *offset
= map
.offset
;
2896 *type
= (drmMapType
)map
.type
;
2897 *flags
= (drmMapFlags
)map
.flags
;
2898 *handle
= (unsigned long)map
.handle
;
2903 drm_public
int drmGetClient(int fd
, int idx
, int *auth
, int *pid
, int *uid
,
2904 unsigned long *magic
, unsigned long *iocs
)
2906 drm_client_t client
;
2910 if (drmIoctl(fd
, DRM_IOCTL_GET_CLIENT
, &client
))
2912 *auth
= client
.auth
;
2915 *magic
= client
.magic
;
2916 *iocs
= client
.iocs
;
2920 drm_public
int drmGetStats(int fd
, drmStatsT
*stats
)
2926 if (drmIoctl(fd
, DRM_IOCTL_GET_STATS
, &s
))
2930 memset(stats
, 0, sizeof(*stats
));
2931 if (s
.count
> sizeof(stats
->data
)/sizeof(stats
->data
[0]))
2935 stats->data[i].long_format = "%-20.20s"; \
2936 stats->data[i].rate_format = "%8.8s"; \
2937 stats->data[i].isvalue = 1; \
2938 stats->data[i].verbose = 0
2941 stats->data[i].long_format = "%-20.20s"; \
2942 stats->data[i].rate_format = "%5.5s"; \
2943 stats->data[i].isvalue = 0; \
2944 stats->data[i].mult_names = "kgm"; \
2945 stats->data[i].mult = 1000; \
2946 stats->data[i].verbose = 0
2949 stats->data[i].long_format = "%-20.20s"; \
2950 stats->data[i].rate_format = "%5.5s"; \
2951 stats->data[i].isvalue = 0; \
2952 stats->data[i].mult_names = "KGM"; \
2953 stats->data[i].mult = 1024; \
2954 stats->data[i].verbose = 0
2957 stats
->count
= s
.count
;
2958 for (i
= 0; i
< s
.count
; i
++) {
2959 stats
->data
[i
].value
= s
.data
[i
].value
;
2960 switch (s
.data
[i
].type
) {
2961 case _DRM_STAT_LOCK
:
2962 stats
->data
[i
].long_name
= "Lock";
2963 stats
->data
[i
].rate_name
= "Lock";
2966 case _DRM_STAT_OPENS
:
2967 stats
->data
[i
].long_name
= "Opens";
2968 stats
->data
[i
].rate_name
= "O";
2970 stats
->data
[i
].verbose
= 1;
2972 case _DRM_STAT_CLOSES
:
2973 stats
->data
[i
].long_name
= "Closes";
2974 stats
->data
[i
].rate_name
= "Lock";
2976 stats
->data
[i
].verbose
= 1;
2978 case _DRM_STAT_IOCTLS
:
2979 stats
->data
[i
].long_name
= "Ioctls";
2980 stats
->data
[i
].rate_name
= "Ioc/s";
2983 case _DRM_STAT_LOCKS
:
2984 stats
->data
[i
].long_name
= "Locks";
2985 stats
->data
[i
].rate_name
= "Lck/s";
2988 case _DRM_STAT_UNLOCKS
:
2989 stats
->data
[i
].long_name
= "Unlocks";
2990 stats
->data
[i
].rate_name
= "Unl/s";
2994 stats
->data
[i
].long_name
= "IRQs";
2995 stats
->data
[i
].rate_name
= "IRQ/s";
2998 case _DRM_STAT_PRIMARY
:
2999 stats
->data
[i
].long_name
= "Primary Bytes";
3000 stats
->data
[i
].rate_name
= "PB/s";
3003 case _DRM_STAT_SECONDARY
:
3004 stats
->data
[i
].long_name
= "Secondary Bytes";
3005 stats
->data
[i
].rate_name
= "SB/s";
3009 stats
->data
[i
].long_name
= "DMA";
3010 stats
->data
[i
].rate_name
= "DMA/s";
3013 case _DRM_STAT_SPECIAL
:
3014 stats
->data
[i
].long_name
= "Special DMA";
3015 stats
->data
[i
].rate_name
= "dma/s";
3018 case _DRM_STAT_MISSED
:
3019 stats
->data
[i
].long_name
= "Miss";
3020 stats
->data
[i
].rate_name
= "Ms/s";
3023 case _DRM_STAT_VALUE
:
3024 stats
->data
[i
].long_name
= "Value";
3025 stats
->data
[i
].rate_name
= "Value";
3028 case _DRM_STAT_BYTE
:
3029 stats
->data
[i
].long_name
= "Bytes";
3030 stats
->data
[i
].rate_name
= "B/s";
3033 case _DRM_STAT_COUNT
:
3035 stats
->data
[i
].long_name
= "Count";
3036 stats
->data
[i
].rate_name
= "Cnt/s";
3045 * Issue a set-version ioctl.
3047 * \param fd file descriptor.
3048 * \param drmCommandIndex command index
3049 * \param data source pointer of the data to be read and written.
3050 * \param size size of the data to be read and written.
3052 * \return zero on success, or a negative value on failure.
3055 * It issues a read-write ioctl given by
3056 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
3058 drm_public
int drmSetInterfaceVersion(int fd
, drmSetVersion
*version
)
3061 drm_set_version_t sv
;
3064 sv
.drm_di_major
= version
->drm_di_major
;
3065 sv
.drm_di_minor
= version
->drm_di_minor
;
3066 sv
.drm_dd_major
= version
->drm_dd_major
;
3067 sv
.drm_dd_minor
= version
->drm_dd_minor
;
3069 if (drmIoctl(fd
, DRM_IOCTL_SET_VERSION
, &sv
)) {
3073 version
->drm_di_major
= sv
.drm_di_major
;
3074 version
->drm_di_minor
= sv
.drm_di_minor
;
3075 version
->drm_dd_major
= sv
.drm_dd_major
;
3076 version
->drm_dd_minor
= sv
.drm_dd_minor
;
3082 * Send a device-specific command.
3084 * \param fd file descriptor.
3085 * \param drmCommandIndex command index
3087 * \return zero on success, or a negative value on failure.
3090 * It issues a ioctl given by
3091 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
3093 drm_public
int drmCommandNone(int fd
, unsigned long drmCommandIndex
)
3095 unsigned long request
;
3097 request
= DRM_IO( DRM_COMMAND_BASE
+ drmCommandIndex
);
3099 if (drmIoctl(fd
, request
, NULL
)) {
3107 * Send a device-specific read command.
3109 * \param fd file descriptor.
3110 * \param drmCommandIndex command index
3111 * \param data destination pointer of the data to be read.
3112 * \param size size of the data to be read.
3114 * \return zero on success, or a negative value on failure.
3117 * It issues a read ioctl given by
3118 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
3120 drm_public
int drmCommandRead(int fd
, unsigned long drmCommandIndex
,
3121 void *data
, unsigned long size
)
3123 unsigned long request
;
3125 request
= DRM_IOC( DRM_IOC_READ
, DRM_IOCTL_BASE
,
3126 DRM_COMMAND_BASE
+ drmCommandIndex
, size
);
3128 if (drmIoctl(fd
, request
, data
)) {
3136 * Send a device-specific write command.
3138 * \param fd file descriptor.
3139 * \param drmCommandIndex command index
3140 * \param data source pointer of the data to be written.
3141 * \param size size of the data to be written.
3143 * \return zero on success, or a negative value on failure.
3146 * It issues a write ioctl given by
3147 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
3149 drm_public
int drmCommandWrite(int fd
, unsigned long drmCommandIndex
,
3150 void *data
, unsigned long size
)
3152 unsigned long request
;
3154 request
= DRM_IOC( DRM_IOC_WRITE
, DRM_IOCTL_BASE
,
3155 DRM_COMMAND_BASE
+ drmCommandIndex
, size
);
3157 if (drmIoctl(fd
, request
, data
)) {
3165 * Send a device-specific read-write command.
3167 * \param fd file descriptor.
3168 * \param drmCommandIndex command index
3169 * \param data source pointer of the data to be read and written.
3170 * \param size size of the data to be read and written.
3172 * \return zero on success, or a negative value on failure.
3175 * It issues a read-write ioctl given by
3176 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
3178 drm_public
int drmCommandWriteRead(int fd
, unsigned long drmCommandIndex
,
3179 void *data
, unsigned long size
)
3181 unsigned long request
;
3183 request
= DRM_IOC( DRM_IOC_READ
|DRM_IOC_WRITE
, DRM_IOCTL_BASE
,
3184 DRM_COMMAND_BASE
+ drmCommandIndex
, size
);
3186 if (drmIoctl(fd
, request
, data
))
3191 #define DRM_MAX_FDS 16
3197 } connection
[DRM_MAX_FDS
];
3199 static int nr_fds
= 0;
3201 drm_public
int drmOpenOnce(void *unused
, const char *BusID
, int *newlyopened
)
3203 return drmOpenOnceWithType(BusID
, newlyopened
, DRM_NODE_PRIMARY
);
3206 drm_public
int drmOpenOnceWithType(const char *BusID
, int *newlyopened
,
3212 for (i
= 0; i
< nr_fds
; i
++)
3213 if ((strcmp(BusID
, connection
[i
].BusID
) == 0) &&
3214 (connection
[i
].type
== type
)) {
3215 connection
[i
].refcount
++;
3217 return connection
[i
].fd
;
3220 fd
= drmOpenWithType(NULL
, BusID
, type
);
3221 if (fd
< 0 || nr_fds
== DRM_MAX_FDS
)
3224 connection
[nr_fds
].BusID
= strdup(BusID
);
3225 connection
[nr_fds
].fd
= fd
;
3226 connection
[nr_fds
].refcount
= 1;
3227 connection
[nr_fds
].type
= type
;
3231 fprintf(stderr
, "saved connection %d for %s %d\n",
3232 nr_fds
, connection
[nr_fds
].BusID
,
3233 strcmp(BusID
, connection
[nr_fds
].BusID
));
3240 drm_public
void drmCloseOnce(int fd
)
3244 for (i
= 0; i
< nr_fds
; i
++) {
3245 if (fd
== connection
[i
].fd
) {
3246 if (--connection
[i
].refcount
== 0) {
3247 drmClose(connection
[i
].fd
);
3248 free(connection
[i
].BusID
);
3251 connection
[i
] = connection
[nr_fds
];
3259 drm_public
int drmSetMaster(int fd
)
3261 return drmIoctl(fd
, DRM_IOCTL_SET_MASTER
, NULL
);
3264 drm_public
int drmDropMaster(int fd
)
3266 return drmIoctl(fd
, DRM_IOCTL_DROP_MASTER
, NULL
);
3269 drm_public
int drmIsMaster(int fd
)
3271 /* Detect master by attempting something that requires master.
3273 * Authenticating magic tokens requires master and 0 is an
3274 * internal kernel detail which we could use. Attempting this on
3275 * a master fd would fail therefore fail with EINVAL because 0
3278 * A non-master fd will fail with EACCES, as the kernel checks
3279 * for master before attempting to do anything else.
3281 * Since we don't want to leak implementation details, use
3284 return drmAuthMagic(fd
, 0) != -EACCES
;
3287 drm_public
char *drmGetDeviceNameFromFd(int fd
)
3294 if (fstat(fd
, &sbuf
))
3297 maj
= major(sbuf
.st_rdev
);
3298 min
= minor(sbuf
.st_rdev
);
3299 nodetype
= drmGetMinorType(maj
, min
);
3300 return drmGetMinorNameForFD(fd
, nodetype
);
3307 /* The whole drmOpen thing is a fiasco and we need to find a way
3308 * back to just using open(2). For now, however, lets just make
3309 * things worse with even more ad hoc directory walking code to
3310 * discover the device file name. */
3315 for (i
= 0; i
< DRM_MAX_MINOR
; i
++) {
3316 snprintf(name
, sizeof name
, DRM_DEV_NAME
, DRM_DIR_NAME
, i
);
3317 if (stat(name
, &sbuf
) == 0 && sbuf
.st_rdev
== d
)
3320 if (i
== DRM_MAX_MINOR
)
3323 return strdup(name
);
3327 static bool drmNodeIsDRM(int maj
, int min
)
3333 snprintf(path
, sizeof(path
), "/sys/dev/char/%d:%d/device/drm",
3335 return stat(path
, &sbuf
) == 0;
3336 #elif defined(__FreeBSD__)
3337 char name
[SPECNAMELEN
];
3339 if (!devname_r(makedev(maj
, min
), S_IFCHR
, name
, sizeof(name
)))
3341 /* Handle drm/ and dri/ as both are present in different FreeBSD version
3342 * FreeBSD on amd64/i386/powerpc external kernel modules create node in
3343 * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates
3344 * only device nodes in /dev/dri/ */
3345 return (!strncmp(name
, "drm/", 4) || !strncmp(name
, "dri/", 4));
3347 return maj
== DRM_MAJOR
;
3351 drm_public
int drmGetNodeTypeFromFd(int fd
)
3356 if (fstat(fd
, &sbuf
))
3359 maj
= major(sbuf
.st_rdev
);
3360 min
= minor(sbuf
.st_rdev
);
3362 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
)) {
3367 type
= drmGetMinorType(maj
, min
);
3373 drm_public
int drmPrimeHandleToFD(int fd
, uint32_t handle
, uint32_t flags
,
3376 struct drm_prime_handle args
;
3381 args
.handle
= handle
;
3383 ret
= drmIoctl(fd
, DRM_IOCTL_PRIME_HANDLE_TO_FD
, &args
);
3387 *prime_fd
= args
.fd
;
3391 drm_public
int drmPrimeFDToHandle(int fd
, int prime_fd
, uint32_t *handle
)
3393 struct drm_prime_handle args
;
3398 ret
= drmIoctl(fd
, DRM_IOCTL_PRIME_FD_TO_HANDLE
, &args
);
3402 *handle
= args
.handle
;
3406 drm_public
int drmCloseBufferHandle(int fd
, uint32_t handle
)
3408 struct drm_gem_close args
;
3411 args
.handle
= handle
;
3412 return drmIoctl(fd
, DRM_IOCTL_GEM_CLOSE
, &args
);
3415 static char *drmGetMinorNameForFD(int fd
, int type
)
3421 const char *name
= drmGetMinorName(type
);
3423 char dev_name
[64], buf
[64];
3431 if (fstat(fd
, &sbuf
))
3434 maj
= major(sbuf
.st_rdev
);
3435 min
= minor(sbuf
.st_rdev
);
3437 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
))
3440 snprintf(buf
, sizeof(buf
), "/sys/dev/char/%d:%d/device/drm", maj
, min
);
3442 sysdir
= opendir(buf
);
3446 while ((ent
= readdir(sysdir
))) {
3447 if (strncmp(ent
->d_name
, name
, len
) == 0) {
3448 if (snprintf(dev_name
, sizeof(dev_name
), DRM_DIR_NAME
"/%s",
3453 return strdup(dev_name
);
3459 #elif defined(__FreeBSD__)
3461 char dname
[SPECNAMELEN
];
3463 char name
[SPECNAMELEN
];
3464 int id
, maj
, min
, nodetype
, i
;
3466 if (fstat(fd
, &sbuf
))
3469 maj
= major(sbuf
.st_rdev
);
3470 min
= minor(sbuf
.st_rdev
);
3472 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
))
3475 if (!devname_r(sbuf
.st_rdev
, S_IFCHR
, dname
, sizeof(dname
)))
3478 /* Handle both /dev/drm and /dev/dri
3479 * FreeBSD on amd64/i386/powerpc external kernel modules create node in
3480 * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates
3481 * only device nodes in /dev/dri/ */
3483 /* Get the node type represented by fd so we can deduce the target name */
3484 nodetype
= drmGetMinorType(maj
, min
);
3487 mname
= drmGetMinorName(type
);
3489 for (i
= 0; i
< SPECNAMELEN
; i
++) {
3490 if (isalpha(dname
[i
]) == 0 && dname
[i
] != '/')
3493 if (dname
[i
] == '\0')
3496 id
= (int)strtol(&dname
[i
], NULL
, 10);
3497 id
-= drmGetMinorBase(nodetype
);
3498 snprintf(name
, sizeof(name
), DRM_DIR_NAME
"/%s%d", mname
,
3499 id
+ drmGetMinorBase(type
));
3501 return strdup(name
);
3504 char buf
[PATH_MAX
+ 1];
3505 const char *dev_name
= drmGetDeviceName(type
);
3506 unsigned int maj
, min
;
3509 if (fstat(fd
, &sbuf
))
3512 maj
= major(sbuf
.st_rdev
);
3513 min
= minor(sbuf
.st_rdev
);
3515 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
))
3521 n
= snprintf(buf
, sizeof(buf
), dev_name
, DRM_DIR_NAME
, min
);
3522 if (n
== -1 || n
>= sizeof(buf
))
3529 drm_public
char *drmGetPrimaryDeviceNameFromFd(int fd
)
3531 return drmGetMinorNameForFD(fd
, DRM_NODE_PRIMARY
);
3534 drm_public
char *drmGetRenderDeviceNameFromFd(int fd
)
3536 return drmGetMinorNameForFD(fd
, DRM_NODE_RENDER
);
3540 static char * DRM_PRINTFLIKE(2, 3)
3541 sysfs_uevent_get(const char *path
, const char *fmt
, ...)
3543 char filename
[PATH_MAX
+ 1], *key
, *line
= NULL
, *value
= NULL
;
3544 size_t size
= 0, len
;
3550 num
= vasprintf(&key
, fmt
, ap
);
3554 snprintf(filename
, sizeof(filename
), "%s/uevent", path
);
3556 fp
= fopen(filename
, "r");
3562 while ((num
= getline(&line
, &size
, fp
)) >= 0) {
3563 if ((strncmp(line
, key
, len
) == 0) && (line
[len
] == '=')) {
3564 char *start
= line
+ len
+ 1, *end
= line
+ num
- 1;
3569 value
= strndup(start
, end
- start
);
3583 /* Little white lie to avoid major rework of the existing code */
3584 #define DRM_BUS_VIRTIO 0x10
3587 static int get_subsystem_type(const char *device_path
)
3589 char path
[PATH_MAX
+ 1] = "";
3590 char link
[PATH_MAX
+ 1] = "";
3596 { "/pci", DRM_BUS_PCI
},
3597 { "/usb", DRM_BUS_USB
},
3598 { "/platform", DRM_BUS_PLATFORM
},
3599 { "/spi", DRM_BUS_PLATFORM
},
3600 { "/host1x", DRM_BUS_HOST1X
},
3601 { "/virtio", DRM_BUS_VIRTIO
},
3604 strncpy(path
, device_path
, PATH_MAX
);
3605 strncat(path
, "/subsystem", PATH_MAX
);
3607 if (readlink(path
, link
, PATH_MAX
) < 0)
3610 name
= strrchr(link
, '/');
3614 for (unsigned i
= 0; i
< ARRAY_SIZE(bus_types
); i
++) {
3615 if (strncmp(name
, bus_types
[i
].name
, strlen(bus_types
[i
].name
)) == 0)
3616 return bus_types
[i
].bus_type
;
3623 static int drmParseSubsystemType(int maj
, int min
)
3626 char path
[PATH_MAX
+ 1] = "";
3627 char real_path
[PATH_MAX
+ 1] = "";
3630 snprintf(path
, sizeof(path
), "/sys/dev/char/%d:%d/device", maj
, min
);
3632 subsystem_type
= get_subsystem_type(path
);
3633 /* Try to get the parent (underlying) device type */
3634 if (subsystem_type
== DRM_BUS_VIRTIO
) {
3635 /* Assume virtio-pci on error */
3636 if (!realpath(path
, real_path
))
3637 return DRM_BUS_VIRTIO
;
3638 strncat(path
, "/..", PATH_MAX
);
3639 subsystem_type
= get_subsystem_type(path
);
3640 if (subsystem_type
< 0)
3641 return DRM_BUS_VIRTIO
;
3643 return subsystem_type
;
3644 #elif defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD__)
3647 #warning "Missing implementation of drmParseSubsystemType"
3654 get_pci_path(int maj
, int min
, char *pci_path
)
3656 char path
[PATH_MAX
+ 1], *term
;
3658 snprintf(path
, sizeof(path
), "/sys/dev/char/%d:%d/device", maj
, min
);
3659 if (!realpath(path
, pci_path
)) {
3660 strcpy(pci_path
, path
);
3664 term
= strrchr(pci_path
, '/');
3665 if (term
&& strncmp(term
, "/virtio", 7) == 0)
3671 static int get_sysctl_pci_bus_info(int maj
, int min
, drmPciBusInfoPtr info
)
3673 char dname
[SPECNAMELEN
];
3674 char sysctl_name
[16];
3675 char sysctl_val
[256];
3677 int id
, type
, nelem
;
3678 unsigned int rdev
, majmin
, domain
, bus
, dev
, func
;
3680 rdev
= makedev(maj
, min
);
3681 if (!devname_r(rdev
, S_IFCHR
, dname
, sizeof(dname
)))
3684 if (sscanf(dname
, "drm/%d\n", &id
) != 1)
3686 type
= drmGetMinorType(maj
, min
);
3690 /* BUG: This above section is iffy, since it mandates that a driver will
3691 * create both card and render node.
3692 * If it does not, the next DRM device will create card#X and
3693 * renderD#(128+X)-1.
3694 * This is a possibility in FreeBSD but for now there is no good way for
3695 * obtaining the info.
3698 case DRM_NODE_PRIMARY
:
3700 case DRM_NODE_RENDER
:
3707 if (snprintf(sysctl_name
, sizeof(sysctl_name
), "hw.dri.%d.busid", id
) <= 0)
3709 sysctl_len
= sizeof(sysctl_val
);
3710 if (sysctlbyname(sysctl_name
, sysctl_val
, &sysctl_len
, NULL
, 0))
3713 #define bus_fmt "pci:%04x:%02x:%02x.%u"
3715 nelem
= sscanf(sysctl_val
, bus_fmt
, &domain
, &bus
, &dev
, &func
);
3718 info
->domain
= domain
;
3727 static int drmParsePciBusInfo(int maj
, int min
, drmPciBusInfoPtr info
)
3730 unsigned int domain
, bus
, dev
, func
;
3731 char pci_path
[PATH_MAX
+ 1], *value
;
3734 get_pci_path(maj
, min
, pci_path
);
3736 value
= sysfs_uevent_get(pci_path
, "PCI_SLOT_NAME");
3740 num
= sscanf(value
, "%04x:%02x:%02x.%1u", &domain
, &bus
, &dev
, &func
);
3746 info
->domain
= domain
;
3752 #elif defined(__OpenBSD__) || defined(__DragonFly__)
3753 struct drm_pciinfo pinfo
;
3756 type
= drmGetMinorType(maj
, min
);
3760 fd
= drmOpenMinor(min
, 0, type
);
3764 if (drmIoctl(fd
, DRM_IOCTL_GET_PCIINFO
, &pinfo
)) {
3770 info
->domain
= pinfo
.domain
;
3771 info
->bus
= pinfo
.bus
;
3772 info
->dev
= pinfo
.dev
;
3773 info
->func
= pinfo
.func
;
3776 #elif defined(__FreeBSD__)
3777 return get_sysctl_pci_bus_info(maj
, min
, info
);
3779 #warning "Missing implementation of drmParsePciBusInfo"
3784 drm_public
int drmDevicesEqual(drmDevicePtr a
, drmDevicePtr b
)
3786 if (a
== NULL
|| b
== NULL
)
3789 if (a
->bustype
!= b
->bustype
)
3792 switch (a
->bustype
) {
3794 return memcmp(a
->businfo
.pci
, b
->businfo
.pci
, sizeof(drmPciBusInfo
)) == 0;
3797 return memcmp(a
->businfo
.usb
, b
->businfo
.usb
, sizeof(drmUsbBusInfo
)) == 0;
3799 case DRM_BUS_PLATFORM
:
3800 return memcmp(a
->businfo
.platform
, b
->businfo
.platform
, sizeof(drmPlatformBusInfo
)) == 0;
3802 case DRM_BUS_HOST1X
:
3803 return memcmp(a
->businfo
.host1x
, b
->businfo
.host1x
, sizeof(drmHost1xBusInfo
)) == 0;
3812 static int drmGetNodeType(const char *name
)
3814 if (strncmp(name
, DRM_RENDER_MINOR_NAME
,
3815 sizeof(DRM_RENDER_MINOR_NAME
) - 1) == 0)
3816 return DRM_NODE_RENDER
;
3818 if (strncmp(name
, DRM_PRIMARY_MINOR_NAME
,
3819 sizeof(DRM_PRIMARY_MINOR_NAME
) - 1) == 0)
3820 return DRM_NODE_PRIMARY
;
3825 static int drmGetMaxNodeName(void)
3827 return sizeof(DRM_DIR_NAME
) +
3828 MAX3(sizeof(DRM_PRIMARY_MINOR_NAME
),
3829 sizeof(DRM_CONTROL_MINOR_NAME
),
3830 sizeof(DRM_RENDER_MINOR_NAME
)) +
3831 3 /* length of the node number */;
3835 static int parse_separate_sysfs_files(int maj
, int min
,
3836 drmPciDeviceInfoPtr device
,
3837 bool ignore_revision
)
3839 static const char *attrs
[] = {
3840 "revision", /* Older kernels are missing the file, so check for it first */
3846 char path
[PATH_MAX
+ 1], pci_path
[PATH_MAX
+ 1];
3847 unsigned int data
[ARRAY_SIZE(attrs
)];
3851 get_pci_path(maj
, min
, pci_path
);
3853 for (unsigned i
= ignore_revision
? 1 : 0; i
< ARRAY_SIZE(attrs
); i
++) {
3854 if (snprintf(path
, PATH_MAX
, "%s/%s", pci_path
, attrs
[i
]) < 0)
3857 fp
= fopen(path
, "r");
3861 ret
= fscanf(fp
, "%x", &data
[i
]);
3868 device
->revision_id
= ignore_revision
? 0xff : data
[0] & 0xff;
3869 device
->vendor_id
= data
[1] & 0xffff;
3870 device
->device_id
= data
[2] & 0xffff;
3871 device
->subvendor_id
= data
[3] & 0xffff;
3872 device
->subdevice_id
= data
[4] & 0xffff;
3877 static int parse_config_sysfs_file(int maj
, int min
,
3878 drmPciDeviceInfoPtr device
)
3880 char path
[PATH_MAX
+ 1], pci_path
[PATH_MAX
+ 1];
3881 unsigned char config
[64];
3884 get_pci_path(maj
, min
, pci_path
);
3886 if (snprintf(path
, PATH_MAX
, "%s/config", pci_path
) < 0)
3889 fd
= open(path
, O_RDONLY
);
3893 ret
= read(fd
, config
, sizeof(config
));
3898 device
->vendor_id
= config
[0] | (config
[1] << 8);
3899 device
->device_id
= config
[2] | (config
[3] << 8);
3900 device
->revision_id
= config
[8];
3901 device
->subvendor_id
= config
[44] | (config
[45] << 8);
3902 device
->subdevice_id
= config
[46] | (config
[47] << 8);
3908 static int drmParsePciDeviceInfo(int maj
, int min
,
3909 drmPciDeviceInfoPtr device
,
3913 if (!(flags
& DRM_DEVICE_GET_PCI_REVISION
))
3914 return parse_separate_sysfs_files(maj
, min
, device
, true);
3916 if (parse_separate_sysfs_files(maj
, min
, device
, false))
3917 return parse_config_sysfs_file(maj
, min
, device
);
3920 #elif defined(__OpenBSD__) || defined(__DragonFly__)
3921 struct drm_pciinfo pinfo
;
3924 type
= drmGetMinorType(maj
, min
);
3928 fd
= drmOpenMinor(min
, 0, type
);
3932 if (drmIoctl(fd
, DRM_IOCTL_GET_PCIINFO
, &pinfo
)) {
3938 device
->vendor_id
= pinfo
.vendor_id
;
3939 device
->device_id
= pinfo
.device_id
;
3940 device
->revision_id
= pinfo
.revision_id
;
3941 device
->subvendor_id
= pinfo
.subvendor_id
;
3942 device
->subdevice_id
= pinfo
.subdevice_id
;
3945 #elif defined(__FreeBSD__)
3947 struct pci_conf_io pc
;
3948 struct pci_match_conf patterns
[1];
3949 struct pci_conf results
[1];
3952 if (get_sysctl_pci_bus_info(maj
, min
, &info
) != 0)
3955 fd
= open("/dev/pci", O_RDONLY
);
3959 bzero(&patterns
, sizeof(patterns
));
3960 patterns
[0].pc_sel
.pc_domain
= info
.domain
;
3961 patterns
[0].pc_sel
.pc_bus
= info
.bus
;
3962 patterns
[0].pc_sel
.pc_dev
= info
.dev
;
3963 patterns
[0].pc_sel
.pc_func
= info
.func
;
3964 patterns
[0].flags
= PCI_GETCONF_MATCH_DOMAIN
| PCI_GETCONF_MATCH_BUS
3965 | PCI_GETCONF_MATCH_DEV
| PCI_GETCONF_MATCH_FUNC
;
3966 bzero(&pc
, sizeof(struct pci_conf_io
));
3967 pc
.num_patterns
= 1;
3968 pc
.pat_buf_len
= sizeof(patterns
);
3969 pc
.patterns
= patterns
;
3970 pc
.match_buf_len
= sizeof(results
);
3971 pc
.matches
= results
;
3973 if (ioctl(fd
, PCIOCGETCONF
, &pc
) || pc
.status
== PCI_GETCONF_ERROR
) {
3980 device
->vendor_id
= results
[0].pc_vendor
;
3981 device
->device_id
= results
[0].pc_device
;
3982 device
->subvendor_id
= results
[0].pc_subvendor
;
3983 device
->subdevice_id
= results
[0].pc_subdevice
;
3984 device
->revision_id
= results
[0].pc_revid
;
3988 #warning "Missing implementation of drmParsePciDeviceInfo"
3993 static void drmFreePlatformDevice(drmDevicePtr device
)
3995 if (device
->deviceinfo
.platform
) {
3996 if (device
->deviceinfo
.platform
->compatible
) {
3997 char **compatible
= device
->deviceinfo
.platform
->compatible
;
3999 while (*compatible
) {
4004 free(device
->deviceinfo
.platform
->compatible
);
4009 static void drmFreeHost1xDevice(drmDevicePtr device
)
4011 if (device
->deviceinfo
.host1x
) {
4012 if (device
->deviceinfo
.host1x
->compatible
) {
4013 char **compatible
= device
->deviceinfo
.host1x
->compatible
;
4015 while (*compatible
) {
4020 free(device
->deviceinfo
.host1x
->compatible
);
4025 drm_public
void drmFreeDevice(drmDevicePtr
*device
)
4031 switch ((*device
)->bustype
) {
4032 case DRM_BUS_PLATFORM
:
4033 drmFreePlatformDevice(*device
);
4036 case DRM_BUS_HOST1X
:
4037 drmFreeHost1xDevice(*device
);
4046 drm_public
void drmFreeDevices(drmDevicePtr devices
[], int count
)
4050 if (devices
== NULL
)
4053 for (i
= 0; i
< count
; i
++)
4055 drmFreeDevice(&devices
[i
]);
4058 static drmDevicePtr
drmDeviceAlloc(unsigned int type
, const char *node
,
4059 size_t bus_size
, size_t device_size
,
4062 size_t max_node_length
, extra
, size
;
4063 drmDevicePtr device
;
4067 max_node_length
= ALIGN(drmGetMaxNodeName(), sizeof(void *));
4068 extra
= DRM_NODE_MAX
* (sizeof(void *) + max_node_length
);
4070 size
= sizeof(*device
) + extra
+ bus_size
+ device_size
;
4072 device
= calloc(1, size
);
4076 device
->available_nodes
= 1 << type
;
4078 ptr
= (char *)device
+ sizeof(*device
);
4079 device
->nodes
= (char **)ptr
;
4081 ptr
+= DRM_NODE_MAX
* sizeof(void *);
4083 for (i
= 0; i
< DRM_NODE_MAX
; i
++) {
4084 device
->nodes
[i
] = ptr
;
4085 ptr
+= max_node_length
;
4088 memcpy(device
->nodes
[type
], node
, max_node_length
);
4095 static int drmProcessPciDevice(drmDevicePtr
*device
,
4096 const char *node
, int node_type
,
4097 int maj
, int min
, bool fetch_deviceinfo
,
4104 dev
= drmDeviceAlloc(node_type
, node
, sizeof(drmPciBusInfo
),
4105 sizeof(drmPciDeviceInfo
), &addr
);
4109 dev
->bustype
= DRM_BUS_PCI
;
4111 dev
->businfo
.pci
= (drmPciBusInfoPtr
)addr
;
4113 ret
= drmParsePciBusInfo(maj
, min
, dev
->businfo
.pci
);
4117 // Fetch the device info if the user has requested it
4118 if (fetch_deviceinfo
) {
4119 addr
+= sizeof(drmPciBusInfo
);
4120 dev
->deviceinfo
.pci
= (drmPciDeviceInfoPtr
)addr
;
4122 ret
= drmParsePciDeviceInfo(maj
, min
, dev
->deviceinfo
.pci
, flags
);
4137 static int drm_usb_dev_path(int maj
, int min
, char *path
, size_t len
)
4139 char *value
, *tmp_path
, *slash
;
4140 bool usb_device
, usb_interface
;
4142 snprintf(path
, len
, "/sys/dev/char/%d:%d/device", maj
, min
);
4144 value
= sysfs_uevent_get(path
, "DEVTYPE");
4148 usb_device
= strcmp(value
, "usb_device") == 0;
4149 usb_interface
= strcmp(value
, "usb_interface") == 0;
4157 /* The parent of a usb_interface is a usb_device */
4159 tmp_path
= realpath(path
, NULL
);
4163 slash
= strrchr(tmp_path
, '/');
4171 if (snprintf(path
, len
, "%s", tmp_path
) >= (int)len
) {
4181 static int drmParseUsbBusInfo(int maj
, int min
, drmUsbBusInfoPtr info
)
4184 char path
[PATH_MAX
+ 1], *value
;
4185 unsigned int bus
, dev
;
4188 ret
= drm_usb_dev_path(maj
, min
, path
, sizeof(path
));
4192 value
= sysfs_uevent_get(path
, "BUSNUM");
4196 ret
= sscanf(value
, "%03u", &bus
);
4202 value
= sysfs_uevent_get(path
, "DEVNUM");
4206 ret
= sscanf(value
, "%03u", &dev
);
4217 #warning "Missing implementation of drmParseUsbBusInfo"
4222 static int drmParseUsbDeviceInfo(int maj
, int min
, drmUsbDeviceInfoPtr info
)
4225 char path
[PATH_MAX
+ 1], *value
;
4226 unsigned int vendor
, product
;
4229 ret
= drm_usb_dev_path(maj
, min
, path
, sizeof(path
));
4233 value
= sysfs_uevent_get(path
, "PRODUCT");
4237 ret
= sscanf(value
, "%x/%x", &vendor
, &product
);
4243 info
->vendor
= vendor
;
4244 info
->product
= product
;
4248 #warning "Missing implementation of drmParseUsbDeviceInfo"
4253 static int drmProcessUsbDevice(drmDevicePtr
*device
, const char *node
,
4254 int node_type
, int maj
, int min
,
4255 bool fetch_deviceinfo
, uint32_t flags
)
4261 dev
= drmDeviceAlloc(node_type
, node
, sizeof(drmUsbBusInfo
),
4262 sizeof(drmUsbDeviceInfo
), &ptr
);
4266 dev
->bustype
= DRM_BUS_USB
;
4268 dev
->businfo
.usb
= (drmUsbBusInfoPtr
)ptr
;
4270 ret
= drmParseUsbBusInfo(maj
, min
, dev
->businfo
.usb
);
4274 if (fetch_deviceinfo
) {
4275 ptr
+= sizeof(drmUsbBusInfo
);
4276 dev
->deviceinfo
.usb
= (drmUsbDeviceInfoPtr
)ptr
;
4278 ret
= drmParseUsbDeviceInfo(maj
, min
, dev
->deviceinfo
.usb
);
4292 static int drmParseOFBusInfo(int maj
, int min
, char *fullname
)
4295 char path
[PATH_MAX
+ 1], *name
, *tmp_name
;
4297 snprintf(path
, sizeof(path
), "/sys/dev/char/%d:%d/device", maj
, min
);
4299 name
= sysfs_uevent_get(path
, "OF_FULLNAME");
4302 /* If the device lacks OF data, pick the MODALIAS info */
4303 name
= sysfs_uevent_get(path
, "MODALIAS");
4307 /* .. and strip the MODALIAS=[platform,usb...]: part. */
4308 tmp_name
= strrchr(name
, ':');
4316 strncpy(fullname
, tmp_name
, DRM_PLATFORM_DEVICE_NAME_LEN
);
4317 fullname
[DRM_PLATFORM_DEVICE_NAME_LEN
- 1] = '\0';
4322 #warning "Missing implementation of drmParseOFBusInfo"
4327 static int drmParseOFDeviceInfo(int maj
, int min
, char ***compatible
)
4330 char path
[PATH_MAX
+ 1], *value
, *tmp_name
;
4331 unsigned int count
, i
;
4334 snprintf(path
, sizeof(path
), "/sys/dev/char/%d:%d/device", maj
, min
);
4336 value
= sysfs_uevent_get(path
, "OF_COMPATIBLE_N");
4338 sscanf(value
, "%u", &count
);
4341 /* Assume one entry if the device lack OF data */
4345 *compatible
= calloc(count
+ 1, sizeof(char *));
4349 for (i
= 0; i
< count
; i
++) {
4350 value
= sysfs_uevent_get(path
, "OF_COMPATIBLE_%u", i
);
4353 /* If the device lacks OF data, pick the MODALIAS info */
4354 value
= sysfs_uevent_get(path
, "MODALIAS");
4360 /* .. and strip the MODALIAS=[platform,usb...]: part. */
4361 tmp_name
= strrchr(value
, ':');
4366 tmp_name
= strdup(tmp_name
+ 1);
4370 (*compatible
)[i
] = tmp_name
;
4377 free((*compatible
)[i
]);
4382 #warning "Missing implementation of drmParseOFDeviceInfo"
4387 static int drmProcessPlatformDevice(drmDevicePtr
*device
,
4388 const char *node
, int node_type
,
4389 int maj
, int min
, bool fetch_deviceinfo
,
4396 dev
= drmDeviceAlloc(node_type
, node
, sizeof(drmPlatformBusInfo
),
4397 sizeof(drmPlatformDeviceInfo
), &ptr
);
4401 dev
->bustype
= DRM_BUS_PLATFORM
;
4403 dev
->businfo
.platform
= (drmPlatformBusInfoPtr
)ptr
;
4405 ret
= drmParseOFBusInfo(maj
, min
, dev
->businfo
.platform
->fullname
);
4409 if (fetch_deviceinfo
) {
4410 ptr
+= sizeof(drmPlatformBusInfo
);
4411 dev
->deviceinfo
.platform
= (drmPlatformDeviceInfoPtr
)ptr
;
4413 ret
= drmParseOFDeviceInfo(maj
, min
, &dev
->deviceinfo
.platform
->compatible
);
4427 static int drmProcessHost1xDevice(drmDevicePtr
*device
,
4428 const char *node
, int node_type
,
4429 int maj
, int min
, bool fetch_deviceinfo
,
4436 dev
= drmDeviceAlloc(node_type
, node
, sizeof(drmHost1xBusInfo
),
4437 sizeof(drmHost1xDeviceInfo
), &ptr
);
4441 dev
->bustype
= DRM_BUS_HOST1X
;
4443 dev
->businfo
.host1x
= (drmHost1xBusInfoPtr
)ptr
;
4445 ret
= drmParseOFBusInfo(maj
, min
, dev
->businfo
.host1x
->fullname
);
4449 if (fetch_deviceinfo
) {
4450 ptr
+= sizeof(drmHost1xBusInfo
);
4451 dev
->deviceinfo
.host1x
= (drmHost1xDeviceInfoPtr
)ptr
;
4453 ret
= drmParseOFDeviceInfo(maj
, min
, &dev
->deviceinfo
.host1x
->compatible
);
4468 process_device(drmDevicePtr
*device
, const char *d_name
,
4469 int req_subsystem_type
,
4470 bool fetch_deviceinfo
, uint32_t flags
)
4473 char node
[PATH_MAX
+ 1];
4474 int node_type
, subsystem_type
;
4475 unsigned int maj
, min
;
4477 node_type
= drmGetNodeType(d_name
);
4481 snprintf(node
, PATH_MAX
, "%s/%s", DRM_DIR_NAME
, d_name
);
4482 if (stat(node
, &sbuf
))
4485 maj
= major(sbuf
.st_rdev
);
4486 min
= minor(sbuf
.st_rdev
);
4488 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
))
4491 subsystem_type
= drmParseSubsystemType(maj
, min
);
4492 if (req_subsystem_type
!= -1 && req_subsystem_type
!= subsystem_type
)
4495 switch (subsystem_type
) {
4497 case DRM_BUS_VIRTIO
:
4498 return drmProcessPciDevice(device
, node
, node_type
, maj
, min
,
4499 fetch_deviceinfo
, flags
);
4501 return drmProcessUsbDevice(device
, node
, node_type
, maj
, min
,
4502 fetch_deviceinfo
, flags
);
4503 case DRM_BUS_PLATFORM
:
4504 return drmProcessPlatformDevice(device
, node
, node_type
, maj
, min
,
4505 fetch_deviceinfo
, flags
);
4506 case DRM_BUS_HOST1X
:
4507 return drmProcessHost1xDevice(device
, node
, node_type
, maj
, min
,
4508 fetch_deviceinfo
, flags
);
4514 /* Consider devices located on the same bus as duplicate and fold the respective
4515 * entries into a single one.
4517 * Note: this leaves "gaps" in the array, while preserving the length.
4519 static void drmFoldDuplicatedDevices(drmDevicePtr local_devices
[], int count
)
4521 int node_type
, i
, j
;
4523 for (i
= 0; i
< count
; i
++) {
4524 for (j
= i
+ 1; j
< count
; j
++) {
4525 if (drmDevicesEqual(local_devices
[i
], local_devices
[j
])) {
4526 local_devices
[i
]->available_nodes
|= local_devices
[j
]->available_nodes
;
4527 node_type
= log2_int(local_devices
[j
]->available_nodes
);
4528 memcpy(local_devices
[i
]->nodes
[node_type
],
4529 local_devices
[j
]->nodes
[node_type
], drmGetMaxNodeName());
4530 drmFreeDevice(&local_devices
[j
]);
4536 /* Check that the given flags are valid returning 0 on success */
4538 drm_device_validate_flags(uint32_t flags
)
4540 return (flags
& ~DRM_DEVICE_GET_PCI_REVISION
);
4544 drm_device_has_rdev(drmDevicePtr device
, dev_t find_rdev
)
4548 for (int i
= 0; i
< DRM_NODE_MAX
; i
++) {
4549 if (device
->available_nodes
& 1 << i
) {
4550 if (stat(device
->nodes
[i
], &sbuf
) == 0 &&
4551 sbuf
.st_rdev
== find_rdev
)
4559 * The kernel drm core has a number of places that assume maximum of
4560 * 3x64 devices nodes. That's 64 for each of primary, control and
4561 * render nodes. Rounded it up to 256 for simplicity.
4563 #define MAX_DRM_NODES 256
4566 * Get information about a device from its dev_t identifier
4568 * \param find_rdev dev_t identifier of the device
4569 * \param flags feature/behaviour bitmask
4570 * \param device the address of a drmDevicePtr where the information
4571 * will be allocated in stored
4573 * \return zero on success, negative error code otherwise.
4575 drm_public
int drmGetDeviceFromDevId(dev_t find_rdev
, uint32_t flags
, drmDevicePtr
*device
)
4579 * DRI device nodes on OpenBSD are not in their own directory, they reside
4580 * in /dev along with a large number of statically generated /dev nodes.
4581 * Avoid stat'ing all of /dev needlessly by implementing this custom path.
4584 char node
[PATH_MAX
+ 1];
4585 const char *dev_name
;
4586 int node_type
, subsystem_type
;
4587 int maj
, min
, n
, ret
;
4592 maj
= major(find_rdev
);
4593 min
= minor(find_rdev
);
4595 if (!drmNodeIsDRM(maj
, min
))
4598 node_type
= drmGetMinorType(maj
, min
);
4599 if (node_type
== -1)
4602 dev_name
= drmGetDeviceName(node_type
);
4606 n
= snprintf(node
, PATH_MAX
, dev_name
, DRM_DIR_NAME
, min
);
4607 if (n
== -1 || n
>= PATH_MAX
)
4609 if (stat(node
, &sbuf
))
4612 subsystem_type
= drmParseSubsystemType(maj
, min
);
4613 if (subsystem_type
!= DRM_BUS_PCI
)
4616 ret
= drmProcessPciDevice(&d
, node
, node_type
, maj
, min
, true, flags
);
4624 drmDevicePtr local_devices
[MAX_DRM_NODES
];
4627 struct dirent
*dent
;
4630 int ret
, i
, node_count
;
4632 if (drm_device_validate_flags(flags
))
4638 maj
= major(find_rdev
);
4639 min
= minor(find_rdev
);
4641 if (!drmNodeIsDRM(maj
, min
))
4644 subsystem_type
= drmParseSubsystemType(maj
, min
);
4645 if (subsystem_type
< 0)
4646 return subsystem_type
;
4648 sysdir
= opendir(DRM_DIR_NAME
);
4653 while ((dent
= readdir(sysdir
))) {
4654 ret
= process_device(&d
, dent
->d_name
, subsystem_type
, true, flags
);
4658 if (i
>= MAX_DRM_NODES
) {
4659 fprintf(stderr
, "More than %d drm nodes detected. "
4660 "Please report a bug - that should not happen.\n"
4661 "Skipping extra nodes\n", MAX_DRM_NODES
);
4664 local_devices
[i
] = d
;
4669 drmFoldDuplicatedDevices(local_devices
, node_count
);
4673 for (i
= 0; i
< node_count
; i
++) {
4674 if (!local_devices
[i
])
4677 if (drm_device_has_rdev(local_devices
[i
], find_rdev
))
4678 *device
= local_devices
[i
];
4680 drmFreeDevice(&local_devices
[i
]);
4684 if (*device
== NULL
)
4690 drm_public
int drmGetNodeTypeFromDevId(dev_t devid
)
4692 int maj
, min
, node_type
;
4697 if (!drmNodeIsDRM(maj
, min
))
4700 node_type
= drmGetMinorType(maj
, min
);
4701 if (node_type
== -1)
4708 * Get information about the opened drm device
4710 * \param fd file descriptor of the drm device
4711 * \param flags feature/behaviour bitmask
4712 * \param device the address of a drmDevicePtr where the information
4713 * will be allocated in stored
4715 * \return zero on success, negative error code otherwise.
4717 * \note Unlike drmGetDevice it does not retrieve the pci device revision field
4718 * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
4720 drm_public
int drmGetDevice2(int fd
, uint32_t flags
, drmDevicePtr
*device
)
4727 if (fstat(fd
, &sbuf
))
4730 if (!S_ISCHR(sbuf
.st_mode
))
4733 return drmGetDeviceFromDevId(sbuf
.st_rdev
, flags
, device
);
4737 * Get information about the opened drm device
4739 * \param fd file descriptor of the drm device
4740 * \param device the address of a drmDevicePtr where the information
4741 * will be allocated in stored
4743 * \return zero on success, negative error code otherwise.
4745 drm_public
int drmGetDevice(int fd
, drmDevicePtr
*device
)
4747 return drmGetDevice2(fd
, DRM_DEVICE_GET_PCI_REVISION
, device
);
4751 * Get drm devices on the system
4753 * \param flags feature/behaviour bitmask
4754 * \param devices the array of devices with drmDevicePtr elements
4755 * can be NULL to get the device number first
4756 * \param max_devices the maximum number of devices for the array
4758 * \return on error - negative error code,
4759 * if devices is NULL - total number of devices available on the system,
4760 * alternatively the number of devices stored in devices[], which is
4761 * capped by the max_devices.
4763 * \note Unlike drmGetDevices it does not retrieve the pci device revision field
4764 * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
4766 drm_public
int drmGetDevices2(uint32_t flags
, drmDevicePtr devices
[],
4769 drmDevicePtr local_devices
[MAX_DRM_NODES
];
4770 drmDevicePtr device
;
4772 struct dirent
*dent
;
4773 int ret
, i
, node_count
, device_count
;
4775 if (drm_device_validate_flags(flags
))
4778 sysdir
= opendir(DRM_DIR_NAME
);
4783 while ((dent
= readdir(sysdir
))) {
4784 ret
= process_device(&device
, dent
->d_name
, -1, devices
!= NULL
, flags
);
4788 if (i
>= MAX_DRM_NODES
) {
4789 fprintf(stderr
, "More than %d drm nodes detected. "
4790 "Please report a bug - that should not happen.\n"
4791 "Skipping extra nodes\n", MAX_DRM_NODES
);
4794 local_devices
[i
] = device
;
4799 drmFoldDuplicatedDevices(local_devices
, node_count
);
4802 for (i
= 0; i
< node_count
; i
++) {
4803 if (!local_devices
[i
])
4806 if ((devices
!= NULL
) && (device_count
< max_devices
))
4807 devices
[device_count
] = local_devices
[i
];
4809 drmFreeDevice(&local_devices
[i
]);
4816 if (devices
!= NULL
)
4817 return MIN2(device_count
, max_devices
);
4819 return device_count
;
4823 * Get drm devices on the system
4825 * \param devices the array of devices with drmDevicePtr elements
4826 * can be NULL to get the device number first
4827 * \param max_devices the maximum number of devices for the array
4829 * \return on error - negative error code,
4830 * if devices is NULL - total number of devices available on the system,
4831 * alternatively the number of devices stored in devices[], which is
4832 * capped by the max_devices.
4834 drm_public
int drmGetDevices(drmDevicePtr devices
[], int max_devices
)
4836 return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION
, devices
, max_devices
);
4839 drm_public
char *drmGetDeviceNameFromFd2(int fd
)
4843 char path
[PATH_MAX
+ 1], *value
;
4844 unsigned int maj
, min
;
4846 if (fstat(fd
, &sbuf
))
4849 maj
= major(sbuf
.st_rdev
);
4850 min
= minor(sbuf
.st_rdev
);
4852 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
))
4855 snprintf(path
, sizeof(path
), "/sys/dev/char/%d:%d", maj
, min
);
4857 value
= sysfs_uevent_get(path
, "DEVNAME");
4861 snprintf(path
, sizeof(path
), "/dev/%s", value
);
4864 return strdup(path
);
4865 #elif defined(__FreeBSD__)
4866 return drmGetDeviceNameFromFd(fd
);
4869 char node
[PATH_MAX
+ 1];
4870 const char *dev_name
;
4874 if (fstat(fd
, &sbuf
))
4877 maj
= major(sbuf
.st_rdev
);
4878 min
= minor(sbuf
.st_rdev
);
4880 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
))
4883 node_type
= drmGetMinorType(maj
, min
);
4884 if (node_type
== -1)
4887 dev_name
= drmGetDeviceName(node_type
);
4891 n
= snprintf(node
, PATH_MAX
, dev_name
, DRM_DIR_NAME
, min
);
4892 if (n
== -1 || n
>= PATH_MAX
)
4895 return strdup(node
);
4899 drm_public
int drmSyncobjCreate(int fd
, uint32_t flags
, uint32_t *handle
)
4901 struct drm_syncobj_create args
;
4907 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_CREATE
, &args
);
4910 *handle
= args
.handle
;
4914 drm_public
int drmSyncobjDestroy(int fd
, uint32_t handle
)
4916 struct drm_syncobj_destroy args
;
4919 args
.handle
= handle
;
4920 return drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_DESTROY
, &args
);
4923 drm_public
int drmSyncobjHandleToFD(int fd
, uint32_t handle
, int *obj_fd
)
4925 struct drm_syncobj_handle args
;
4930 args
.handle
= handle
;
4931 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD
, &args
);
4938 drm_public
int drmSyncobjFDToHandle(int fd
, int obj_fd
, uint32_t *handle
)
4940 struct drm_syncobj_handle args
;
4946 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE
, &args
);
4949 *handle
= args
.handle
;
4953 drm_public
int drmSyncobjImportSyncFile(int fd
, uint32_t handle
,
4956 struct drm_syncobj_handle args
;
4959 args
.fd
= sync_file_fd
;
4960 args
.handle
= handle
;
4961 args
.flags
= DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE
;
4962 return drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE
, &args
);
4965 drm_public
int drmSyncobjExportSyncFile(int fd
, uint32_t handle
,
4968 struct drm_syncobj_handle args
;
4973 args
.handle
= handle
;
4974 args
.flags
= DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE
;
4975 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD
, &args
);
4978 *sync_file_fd
= args
.fd
;
4982 drm_public
int drmSyncobjWait(int fd
, uint32_t *handles
, unsigned num_handles
,
4983 int64_t timeout_nsec
, unsigned flags
,
4984 uint32_t *first_signaled
)
4986 struct drm_syncobj_wait args
;
4990 args
.handles
= (uintptr_t)handles
;
4991 args
.timeout_nsec
= timeout_nsec
;
4992 args
.count_handles
= num_handles
;
4995 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_WAIT
, &args
);
5000 *first_signaled
= args
.first_signaled
;
5004 drm_public
int drmSyncobjReset(int fd
, const uint32_t *handles
,
5005 uint32_t handle_count
)
5007 struct drm_syncobj_array args
;
5011 args
.handles
= (uintptr_t)handles
;
5012 args
.count_handles
= handle_count
;
5014 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_RESET
, &args
);
5018 drm_public
int drmSyncobjSignal(int fd
, const uint32_t *handles
,
5019 uint32_t handle_count
)
5021 struct drm_syncobj_array args
;
5025 args
.handles
= (uintptr_t)handles
;
5026 args
.count_handles
= handle_count
;
5028 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_SIGNAL
, &args
);
5032 drm_public
int drmSyncobjTimelineSignal(int fd
, const uint32_t *handles
,
5033 uint64_t *points
, uint32_t handle_count
)
5035 struct drm_syncobj_timeline_array args
;
5039 args
.handles
= (uintptr_t)handles
;
5040 args
.points
= (uintptr_t)points
;
5041 args
.count_handles
= handle_count
;
5043 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL
, &args
);
5047 drm_public
int drmSyncobjTimelineWait(int fd
, uint32_t *handles
, uint64_t *points
,
5048 unsigned num_handles
,
5049 int64_t timeout_nsec
, unsigned flags
,
5050 uint32_t *first_signaled
)
5052 struct drm_syncobj_timeline_wait args
;
5056 args
.handles
= (uintptr_t)handles
;
5057 args
.points
= (uintptr_t)points
;
5058 args
.timeout_nsec
= timeout_nsec
;
5059 args
.count_handles
= num_handles
;
5062 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT
, &args
);
5067 *first_signaled
= args
.first_signaled
;
5072 drm_public
int drmSyncobjQuery(int fd
, uint32_t *handles
, uint64_t *points
,
5073 uint32_t handle_count
)
5075 struct drm_syncobj_timeline_array args
;
5079 args
.handles
= (uintptr_t)handles
;
5080 args
.points
= (uintptr_t)points
;
5081 args
.count_handles
= handle_count
;
5083 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_QUERY
, &args
);
5089 drm_public
int drmSyncobjQuery2(int fd
, uint32_t *handles
, uint64_t *points
,
5090 uint32_t handle_count
, uint32_t flags
)
5092 struct drm_syncobj_timeline_array args
;
5095 args
.handles
= (uintptr_t)handles
;
5096 args
.points
= (uintptr_t)points
;
5097 args
.count_handles
= handle_count
;
5100 return drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_QUERY
, &args
);
5104 drm_public
int drmSyncobjTransfer(int fd
,
5105 uint32_t dst_handle
, uint64_t dst_point
,
5106 uint32_t src_handle
, uint64_t src_point
,
5109 struct drm_syncobj_transfer args
;
5113 args
.src_handle
= src_handle
;
5114 args
.dst_handle
= dst_handle
;
5115 args
.src_point
= src_point
;
5116 args
.dst_point
= dst_point
;
5119 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_TRANSFER
, &args
);
5124 drm_public
int drmSyncobjEventfd(int fd
, uint32_t handle
, uint64_t point
, int ev_fd
,
5127 struct drm_syncobj_eventfd args
;
5130 args
.handle
= handle
;
5135 return drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_EVENTFD
, &args
);
5139 drmGetFormatModifierFromSimpleTokens(uint64_t modifier
)
5143 for (i
= 0; i
< ARRAY_SIZE(drm_format_modifier_table
); i
++) {
5144 if (drm_format_modifier_table
[i
].modifier
== modifier
)
5145 return strdup(drm_format_modifier_table
[i
].modifier_name
);
5151 /** Retrieves a human-readable representation of a vendor (as a string) from
5152 * the format token modifier
5154 * \param modifier the format modifier token
5155 * \return a char pointer to the human-readable form of the vendor. Caller is
5156 * responsible for freeing it.
5159 drmGetFormatModifierVendor(uint64_t modifier
)
5162 uint8_t vendor
= fourcc_mod_get_vendor(modifier
);
5164 for (i
= 0; i
< ARRAY_SIZE(drm_format_modifier_vendor_table
); i
++) {
5165 if (drm_format_modifier_vendor_table
[i
].vendor
== vendor
)
5166 return strdup(drm_format_modifier_vendor_table
[i
].vendor_name
);
5172 /** Retrieves a human-readable representation string from a format token
5175 * If the dedicated function was not able to extract a valid name or searching
5176 * the format modifier was not in the table, this function would return NULL.
5178 * \param modifier the token format
5179 * \return a malloc'ed string representation of the modifier. Caller is
5180 * responsible for freeing the string returned.
5184 drmGetFormatModifierName(uint64_t modifier
)
5186 uint8_t vendorid
= fourcc_mod_get_vendor(modifier
);
5187 char *modifier_found
= NULL
;
5190 for (i
= 0; i
< ARRAY_SIZE(modifier_format_vendor_table
); i
++) {
5191 if (modifier_format_vendor_table
[i
].vendor
== vendorid
)
5192 modifier_found
= modifier_format_vendor_table
[i
].vendor_cb(modifier
);
5195 if (!modifier_found
)
5196 return drmGetFormatModifierFromSimpleTokens(modifier
);
5198 return modifier_found
;
5202 * Get a human-readable name for a DRM FourCC format.
5204 * \param format The format.
5205 * \return A malloc'ed string containing the format name. Caller is responsible
5209 drmGetFormatName(uint32_t format
)
5215 be
= (format
& DRM_FORMAT_BIG_ENDIAN
) ? "_BE" : "";
5216 format
&= ~DRM_FORMAT_BIG_ENDIAN
;
5218 if (format
== DRM_FORMAT_INVALID
)
5219 return strdup("INVALID");
5221 code
[0] = (char) ((format
>> 0) & 0xFF);
5222 code
[1] = (char) ((format
>> 8) & 0xFF);
5223 code
[2] = (char) ((format
>> 16) & 0xFF);
5224 code
[3] = (char) ((format
>> 24) & 0xFF);
5227 /* Trim spaces at the end */
5228 for (i
= 3; i
> 0 && code
[i
] == ' '; i
--)
5231 str_size
= strlen(code
) + strlen(be
) + 1;
5232 str
= malloc(str_size
);
5236 snprintf(str
, str_size
, "%s%s", code
, be
);