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
);
178 static const struct drmVendorInfo modifier_format_vendor_table
[] = {
179 { DRM_FORMAT_MOD_VENDOR_ARM
, drmGetFormatModifierNameFromArm
},
180 { DRM_FORMAT_MOD_VENDOR_NVIDIA
, drmGetFormatModifierNameFromNvidia
},
181 { DRM_FORMAT_MOD_VENDOR_AMD
, drmGetFormatModifierNameFromAmd
},
182 { DRM_FORMAT_MOD_VENDOR_AMLOGIC
, drmGetFormatModifierNameFromAmlogic
},
185 #ifndef AFBC_FORMAT_MOD_MODE_VALUE_MASK
186 #define AFBC_FORMAT_MOD_MODE_VALUE_MASK 0x000fffffffffffffULL
189 static const struct drmFormatVendorModifierInfo arm_mode_value_table
[] = {
190 { AFBC_FORMAT_MOD_YTR
, "YTR" },
191 { AFBC_FORMAT_MOD_SPLIT
, "SPLIT" },
192 { AFBC_FORMAT_MOD_SPARSE
, "SPARSE" },
193 { AFBC_FORMAT_MOD_CBR
, "CBR" },
194 { AFBC_FORMAT_MOD_TILED
, "TILED" },
195 { AFBC_FORMAT_MOD_SC
, "SC" },
196 { AFBC_FORMAT_MOD_DB
, "DB" },
197 { AFBC_FORMAT_MOD_BCH
, "BCH" },
198 { AFBC_FORMAT_MOD_USM
, "USM" },
201 static bool is_x_t_amd_gfx9_tile(uint64_t tile
)
204 case AMD_FMT_MOD_TILE_GFX9_64K_S_X
:
205 case AMD_FMT_MOD_TILE_GFX9_64K_D_X
:
206 case AMD_FMT_MOD_TILE_GFX9_64K_R_X
:
214 drmGetFormatModifierNameFromArm(uint64_t modifier
)
216 uint64_t type
= (modifier
>> 52) & 0xf;
217 uint64_t mode_value
= modifier
& AFBC_FORMAT_MOD_MODE_VALUE_MASK
;
218 uint64_t block_size
= mode_value
& AFBC_FORMAT_MOD_BLOCK_SIZE_MASK
;
221 char *modifier_name
= NULL
;
225 const char *block
= NULL
;
226 const char *mode
= NULL
;
227 bool did_print_mode
= false;
229 /* misc type is already handled by the static table */
230 if (type
!= DRM_FORMAT_MOD_ARM_TYPE_AFBC
)
233 fp
= open_memstream(&modifier_name
, &size
);
237 /* add block, can only have a (single) block */
238 switch (block_size
) {
239 case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
:
242 case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8
:
245 case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4
:
248 case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4
:
259 fprintf(fp
, "BLOCK_SIZE=%s,", block
);
262 for (i
= 0; i
< ARRAY_SIZE(arm_mode_value_table
); i
++) {
263 if (arm_mode_value_table
[i
].modifier
& mode_value
) {
264 mode
= arm_mode_value_table
[i
].modifier_name
;
265 if (!did_print_mode
) {
266 fprintf(fp
, "MODE=%s", mode
);
267 did_print_mode
= true;
269 fprintf(fp
, "|%s", mode
);
275 return modifier_name
;
279 drmGetFormatModifierNameFromNvidia(uint64_t modifier
)
281 uint64_t height
, kind
, gen
, sector
, compression
;
283 height
= modifier
& 0xf;
284 kind
= (modifier
>> 12) & 0xff;
286 gen
= (modifier
>> 20) & 0x3;
287 sector
= (modifier
>> 22) & 0x1;
288 compression
= (modifier
>> 23) & 0x7;
290 /* just in case there could other simpler modifiers, not yet added, avoid
291 * testing against TEGRA_TILE */
292 if ((modifier
& 0x10) == 0x10) {
294 asprintf(&mod_nvidia
, "BLOCK_LINEAR_2D,HEIGHT=%"PRIu64
",KIND=%"PRIu64
","
295 "GEN=%"PRIu64
",SECTOR=%"PRIu64
",COMPRESSION=%"PRIu64
"", height
,
296 kind
, gen
, sector
, compression
);
304 drmGetFormatModifierNameFromAmdDcc(uint64_t modifier
, FILE *fp
)
306 uint64_t dcc_max_compressed_block
=
307 AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK
, modifier
);
308 uint64_t dcc_retile
= AMD_FMT_MOD_GET(DCC_RETILE
, modifier
);
310 const char *dcc_max_compressed_block_str
= NULL
;
315 fprintf(fp
, ",DCC_RETILE");
317 if (!dcc_retile
&& AMD_FMT_MOD_GET(DCC_PIPE_ALIGN
, modifier
))
318 fprintf(fp
, ",DCC_PIPE_ALIGN");
320 if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B
, modifier
))
321 fprintf(fp
, ",DCC_INDEPENDENT_64B");
323 if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B
, modifier
))
324 fprintf(fp
, ",DCC_INDEPENDENT_128B");
326 switch (dcc_max_compressed_block
) {
327 case AMD_FMT_MOD_DCC_BLOCK_64B
:
328 dcc_max_compressed_block_str
= "64B";
330 case AMD_FMT_MOD_DCC_BLOCK_128B
:
331 dcc_max_compressed_block_str
= "128B";
333 case AMD_FMT_MOD_DCC_BLOCK_256B
:
334 dcc_max_compressed_block_str
= "256B";
338 if (dcc_max_compressed_block_str
)
339 fprintf(fp
, ",DCC_MAX_COMPRESSED_BLOCK=%s",
340 dcc_max_compressed_block_str
);
342 if (AMD_FMT_MOD_GET(DCC_CONSTANT_ENCODE
, modifier
))
343 fprintf(fp
, ",DCC_CONSTANT_ENCODE");
347 drmGetFormatModifierNameFromAmdTile(uint64_t modifier
, FILE *fp
)
349 uint64_t pipe_xor_bits
, bank_xor_bits
, packers
, rb
;
350 uint64_t pipe
, pipe_align
, dcc
, dcc_retile
, tile_version
;
352 pipe_align
= AMD_FMT_MOD_GET(DCC_PIPE_ALIGN
, modifier
);
353 pipe_xor_bits
= AMD_FMT_MOD_GET(PIPE_XOR_BITS
, modifier
);
354 dcc
= AMD_FMT_MOD_GET(DCC
, modifier
);
355 dcc_retile
= AMD_FMT_MOD_GET(DCC_RETILE
, modifier
);
356 tile_version
= AMD_FMT_MOD_GET(TILE_VERSION
, modifier
);
358 fprintf(fp
, ",PIPE_XOR_BITS=%"PRIu64
, pipe_xor_bits
);
360 if (tile_version
== AMD_FMT_MOD_TILE_VER_GFX9
) {
361 bank_xor_bits
= AMD_FMT_MOD_GET(BANK_XOR_BITS
, modifier
);
362 fprintf(fp
, ",BANK_XOR_BITS=%"PRIu64
, bank_xor_bits
);
365 if (tile_version
== AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS
) {
366 packers
= AMD_FMT_MOD_GET(PACKERS
, modifier
);
367 fprintf(fp
, ",PACKERS=%"PRIu64
, packers
);
370 if (dcc
&& tile_version
== AMD_FMT_MOD_TILE_VER_GFX9
) {
371 rb
= AMD_FMT_MOD_GET(RB
, modifier
);
372 fprintf(fp
, ",RB=%"PRIu64
, rb
);
375 if (dcc
&& tile_version
== AMD_FMT_MOD_TILE_VER_GFX9
&&
376 (dcc_retile
|| pipe_align
)) {
377 pipe
= AMD_FMT_MOD_GET(PIPE
, modifier
);
378 fprintf(fp
, ",PIPE_%"PRIu64
, pipe
);
383 drmGetFormatModifierNameFromAmd(uint64_t modifier
)
385 uint64_t tile
, tile_version
, dcc
;
387 char *mod_amd
= NULL
;
390 const char *str_tile
= NULL
;
391 const char *str_tile_version
= NULL
;
393 tile
= AMD_FMT_MOD_GET(TILE
, modifier
);
394 tile_version
= AMD_FMT_MOD_GET(TILE_VERSION
, modifier
);
395 dcc
= AMD_FMT_MOD_GET(DCC
, modifier
);
397 fp
= open_memstream(&mod_amd
, &size
);
402 switch (tile_version
) {
403 case AMD_FMT_MOD_TILE_VER_GFX9
:
404 str_tile_version
= "GFX9";
406 case AMD_FMT_MOD_TILE_VER_GFX10
:
407 str_tile_version
= "GFX10";
409 case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS
:
410 str_tile_version
= "GFX10_RBPLUS";
414 if (str_tile_version
) {
415 fprintf(fp
, "%s", str_tile_version
);
424 case AMD_FMT_MOD_TILE_GFX9_64K_S
:
425 str_tile
= "GFX9_64K_S";
427 case AMD_FMT_MOD_TILE_GFX9_64K_D
:
428 str_tile
= "GFX9_64K_D";
430 case AMD_FMT_MOD_TILE_GFX9_64K_S_X
:
431 str_tile
= "GFX9_64K_S_X";
433 case AMD_FMT_MOD_TILE_GFX9_64K_D_X
:
434 str_tile
= "GFX9_64K_D_X";
436 case AMD_FMT_MOD_TILE_GFX9_64K_R_X
:
437 str_tile
= "GFX9_64K_R_X";
442 fprintf(fp
, ",%s", str_tile
);
445 drmGetFormatModifierNameFromAmdDcc(modifier
, fp
);
447 if (tile_version
>= AMD_FMT_MOD_TILE_VER_GFX9
&& is_x_t_amd_gfx9_tile(tile
))
448 drmGetFormatModifierNameFromAmdTile(modifier
, fp
);
455 drmGetFormatModifierNameFromAmlogic(uint64_t modifier
)
457 uint64_t layout
= modifier
& 0xff;
458 uint64_t options
= (modifier
>> 8) & 0xff;
459 char *mod_amlogic
= NULL
;
461 const char *layout_str
;
462 const char *opts_str
;
465 case AMLOGIC_FBC_LAYOUT_BASIC
:
466 layout_str
= "BASIC";
468 case AMLOGIC_FBC_LAYOUT_SCATTER
:
469 layout_str
= "SCATTER";
472 layout_str
= "INVALID_LAYOUT";
476 if (options
& AMLOGIC_FBC_OPTION_MEM_SAVING
)
477 opts_str
= "MEM_SAVING";
481 asprintf(&mod_amlogic
, "FBC,LAYOUT=%s,OPTIONS=%s", layout_str
, opts_str
);
485 static unsigned log2_int(unsigned x
)
493 if ((unsigned)(1 << l
) > x
) {
501 drm_public
void drmSetServerInfo(drmServerInfoPtr info
)
503 drm_server_info
= info
;
507 * Output a message to stderr.
509 * \param format printf() like format string.
512 * This function is a wrapper around vfprintf().
515 static int DRM_PRINTFLIKE(1, 0)
516 drmDebugPrint(const char *format
, va_list ap
)
518 return vfprintf(stderr
, format
, ap
);
522 drmMsg(const char *format
, ...)
526 if (((env
= getenv("LIBGL_DEBUG")) && strstr(env
, "verbose")) ||
527 (drm_server_info
&& drm_server_info
->debug_print
))
529 va_start(ap
, format
);
530 if (drm_server_info
) {
531 drm_server_info
->debug_print(format
,ap
);
533 drmDebugPrint(format
, ap
);
539 static void *drmHashTable
= NULL
; /* Context switch callbacks */
541 drm_public
void *drmGetHashTable(void)
546 drm_public
void *drmMalloc(int size
)
548 return calloc(1, size
);
551 drm_public
void drmFree(void *pt
)
557 * Call ioctl, restarting if it is interrupted
560 drmIoctl(int fd
, unsigned long request
, void *arg
)
565 ret
= ioctl(fd
, request
, arg
);
566 } while (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
570 static unsigned long drmGetKeyFromFd(int fd
)
579 drm_public drmHashEntry
*drmGetEntry(int fd
)
581 unsigned long key
= drmGetKeyFromFd(fd
);
586 drmHashTable
= drmHashCreate();
588 if (drmHashLookup(drmHashTable
, key
, &value
)) {
589 entry
= drmMalloc(sizeof(*entry
));
592 entry
->tagTable
= drmHashCreate();
593 drmHashInsert(drmHashTable
, key
, entry
);
601 * Compare two busid strings
606 * \return 1 if matched.
609 * This function compares two bus ID strings. It understands the older
610 * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is
611 * domain, b is bus, d is device, f is function.
613 static int drmMatchBusID(const char *id1
, const char *id2
, int pci_domain_ok
)
615 /* First, check if the IDs are exactly the same */
616 if (strcasecmp(id1
, id2
) == 0)
619 /* Try to match old/new-style PCI bus IDs. */
620 if (strncasecmp(id1
, "pci", 3) == 0) {
621 unsigned int o1
, b1
, d1
, f1
;
622 unsigned int o2
, b2
, d2
, f2
;
625 ret
= sscanf(id1
, "pci:%04x:%02x:%02x.%u", &o1
, &b1
, &d1
, &f1
);
628 ret
= sscanf(id1
, "PCI:%u:%u:%u", &b1
, &d1
, &f1
);
633 ret
= sscanf(id2
, "pci:%04x:%02x:%02x.%u", &o2
, &b2
, &d2
, &f2
);
636 ret
= sscanf(id2
, "PCI:%u:%u:%u", &b2
, &d2
, &f2
);
641 /* If domains aren't properly supported by the kernel interface,
642 * just ignore them, which sucks less than picking a totally random
643 * card with "open by name"
648 if ((o1
!= o2
) || (b1
!= b2
) || (d1
!= d2
) || (f1
!= f2
))
657 * Handles error checking for chown call.
659 * \param path to file.
660 * \param id of the new owner.
661 * \param id of the new group.
663 * \return zero if success or -1 if failure.
666 * Checks for failure. If failure was caused by signal call chown again.
667 * If any other failure happened then it will output error message using
671 static int chown_check_return(const char *path
, uid_t owner
, gid_t group
)
676 rv
= chown(path
, owner
, group
);
677 } while (rv
!= 0 && errno
== EINTR
);
682 drmMsg("Failed to change owner or group for file %s! %d: %s\n",
683 path
, errno
, strerror(errno
));
688 static const char *drmGetDeviceName(int type
)
691 case DRM_NODE_PRIMARY
:
693 case DRM_NODE_CONTROL
:
694 return DRM_CONTROL_DEV_NAME
;
695 case DRM_NODE_RENDER
:
696 return DRM_RENDER_DEV_NAME
;
702 * Open the DRM device, creating it if necessary.
704 * \param dev major and minor numbers of the device.
705 * \param minor minor number of the device.
707 * \return a file descriptor on success, or a negative value on error.
710 * Assembles the device name from \p minor and opens it, creating the device
711 * special file node with the major and minor numbers specified by \p dev and
712 * parent directory if necessary and was called by root.
714 static int drmOpenDevice(dev_t dev
, int minor
, int type
)
717 const char *dev_name
= drmGetDeviceName(type
);
718 char buf
[DRM_NODE_NAME_MAX
];
720 mode_t devmode
= DRM_DEV_MODE
, serv_mode
;
723 int isroot
= !geteuid();
724 uid_t user
= DRM_DEV_UID
;
725 gid_t group
= DRM_DEV_GID
;
731 sprintf(buf
, dev_name
, DRM_DIR_NAME
, minor
);
732 drmMsg("drmOpenDevice: node name is %s\n", buf
);
734 if (drm_server_info
&& drm_server_info
->get_perms
) {
735 drm_server_info
->get_perms(&serv_group
, &serv_mode
);
736 devmode
= serv_mode
? serv_mode
: DRM_DEV_MODE
;
737 devmode
&= ~(S_IXUSR
|S_IXGRP
|S_IXOTH
);
741 if (stat(DRM_DIR_NAME
, &st
)) {
743 return DRM_ERR_NOT_ROOT
;
744 mkdir(DRM_DIR_NAME
, DRM_DEV_DIRMODE
);
745 chown_check_return(DRM_DIR_NAME
, 0, 0); /* root:root */
746 chmod(DRM_DIR_NAME
, DRM_DEV_DIRMODE
);
749 /* Check if the device node exists and create it if necessary. */
750 if (stat(buf
, &st
)) {
752 return DRM_ERR_NOT_ROOT
;
754 mknod(buf
, S_IFCHR
| devmode
, dev
);
757 if (drm_server_info
&& drm_server_info
->get_perms
) {
758 group
= ((int)serv_group
>= 0) ? serv_group
: DRM_DEV_GID
;
759 chown_check_return(buf
, user
, group
);
763 /* if we modprobed then wait for udev */
767 if (stat(DRM_DIR_NAME
, &st
)) {
771 if (udev_count
== 50)
776 if (stat(buf
, &st
)) {
780 if (udev_count
== 50)
787 fd
= open(buf
, O_RDWR
| O_CLOEXEC
, 0);
788 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
789 fd
, fd
< 0 ? strerror(errno
) : "OK");
794 /* Check if the device node is not what we expect it to be, and recreate it
795 * and try again if so.
797 if (st
.st_rdev
!= dev
) {
799 return DRM_ERR_NOT_ROOT
;
801 mknod(buf
, S_IFCHR
| devmode
, dev
);
802 if (drm_server_info
&& drm_server_info
->get_perms
) {
803 chown_check_return(buf
, user
, group
);
807 fd
= open(buf
, O_RDWR
| O_CLOEXEC
, 0);
808 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
809 fd
, fd
< 0 ? strerror(errno
) : "OK");
813 drmMsg("drmOpenDevice: Open failed\n");
821 * Open the DRM device
823 * \param minor device minor number.
824 * \param create allow to create the device if set.
826 * \return a file descriptor on success, or a negative value on error.
829 * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
830 * name from \p minor and opens it.
832 static int drmOpenMinor(int minor
, int create
, int type
)
835 char buf
[DRM_NODE_NAME_MAX
];
836 const char *dev_name
= drmGetDeviceName(type
);
839 return drmOpenDevice(makedev(DRM_MAJOR
, minor
), minor
, type
);
844 sprintf(buf
, dev_name
, DRM_DIR_NAME
, minor
);
845 if ((fd
= open(buf
, O_RDWR
| O_CLOEXEC
, 0)) >= 0)
852 * Determine whether the DRM kernel driver has been loaded.
854 * \return 1 if the DRM driver is loaded, 0 otherwise.
857 * Determine the presence of the kernel driver by attempting to open the 0
858 * minor and get version information. For backward compatibility with older
859 * Linux implementations, /proc/dri is also checked.
861 drm_public
int drmAvailable(void)
863 drmVersionPtr version
;
867 if ((fd
= drmOpenMinor(0, 1, DRM_NODE_PRIMARY
)) < 0) {
869 /* Try proc for backward Linux compatibility */
870 if (!access("/proc/dri/0", R_OK
))
876 if ((version
= drmGetVersion(fd
))) {
878 drmFreeVersion(version
);
885 static int drmGetMinorBase(int type
)
888 case DRM_NODE_PRIMARY
:
890 case DRM_NODE_CONTROL
:
892 case DRM_NODE_RENDER
:
899 static int drmGetMinorType(int major
, int minor
)
902 char name
[SPECNAMELEN
];
905 if (!devname_r(makedev(major
, minor
), S_IFCHR
, name
, sizeof(name
)))
908 if (sscanf(name
, "drm/%d", &id
) != 1) {
909 // If not in /dev/drm/ we have the type in the name
910 if (sscanf(name
, "dri/card%d\n", &id
) >= 1)
911 return DRM_NODE_PRIMARY
;
912 else if (sscanf(name
, "dri/control%d\n", &id
) >= 1)
913 return DRM_NODE_CONTROL
;
914 else if (sscanf(name
, "dri/renderD%d\n", &id
) >= 1)
915 return DRM_NODE_RENDER
;
921 int type
= minor
>> 6;
927 case DRM_NODE_PRIMARY
:
928 case DRM_NODE_CONTROL
:
929 case DRM_NODE_RENDER
:
936 static const char *drmGetMinorName(int type
)
939 case DRM_NODE_PRIMARY
:
940 return DRM_PRIMARY_MINOR_NAME
;
941 case DRM_NODE_CONTROL
:
942 return DRM_CONTROL_MINOR_NAME
;
943 case DRM_NODE_RENDER
:
944 return DRM_RENDER_MINOR_NAME
;
951 * Open the device by bus ID.
953 * \param busid bus ID.
954 * \param type device node type.
956 * \return a file descriptor on success, or a negative value on error.
959 * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
960 * comparing the device bus ID with the one supplied.
962 * \sa drmOpenMinor() and drmGetBusid().
964 static int drmOpenByBusid(const char *busid
, int type
)
966 int i
, pci_domain_ok
= 1;
970 int base
= drmGetMinorBase(type
);
975 drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid
);
976 for (i
= base
; i
< base
+ DRM_MAX_MINOR
; i
++) {
977 fd
= drmOpenMinor(i
, 1, type
);
978 drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd
);
980 /* We need to try for 1.4 first for proper PCI domain support
981 * and if that fails, we know the kernel is busted
985 sv
.drm_dd_major
= -1; /* Don't care */
986 sv
.drm_dd_minor
= -1; /* Don't care */
987 if (drmSetInterfaceVersion(fd
, &sv
)) {
993 sv
.drm_dd_major
= -1; /* Don't care */
994 sv
.drm_dd_minor
= -1; /* Don't care */
995 drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
996 drmSetInterfaceVersion(fd
, &sv
);
998 buf
= drmGetBusid(fd
);
999 drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf
);
1000 if (buf
&& drmMatchBusID(buf
, busid
, pci_domain_ok
)) {
1014 * Open the device by name.
1016 * \param name driver name.
1017 * \param type the device node type.
1019 * \return a file descriptor on success, or a negative value on error.
1022 * This function opens the first minor number that matches the driver name and
1023 * isn't already in use. If it's in use it then it will already have a bus ID
1026 * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
1028 static int drmOpenByName(const char *name
, int type
)
1032 drmVersionPtr version
;
1034 int base
= drmGetMinorBase(type
);
1040 * Open the first minor number that matches the driver name and isn't
1041 * already in use. If it's in use it will have a busid assigned already.
1043 for (i
= base
; i
< base
+ DRM_MAX_MINOR
; i
++) {
1044 if ((fd
= drmOpenMinor(i
, 1, type
)) >= 0) {
1045 if ((version
= drmGetVersion(fd
))) {
1046 if (!strcmp(version
->name
, name
)) {
1047 drmFreeVersion(version
);
1048 id
= drmGetBusid(fd
);
1049 drmMsg("drmGetBusid returned '%s'\n", id
? id
: "NULL");
1058 drmFreeVersion(version
);
1066 /* Backward-compatibility /proc support */
1067 for (i
= 0; i
< 8; i
++) {
1068 char proc_name
[64], buf
[512];
1069 char *driver
, *pt
, *devstring
;
1072 sprintf(proc_name
, "/proc/dri/%d/name", i
);
1073 if ((fd
= open(proc_name
, O_RDONLY
, 0)) >= 0) {
1074 retcode
= read(fd
, buf
, sizeof(buf
)-1);
1077 buf
[retcode
-1] = '\0';
1078 for (driver
= pt
= buf
; *pt
&& *pt
!= ' '; ++pt
)
1080 if (*pt
) { /* Device is next */
1082 if (!strcmp(driver
, name
)) { /* Match */
1083 for (devstring
= ++pt
; *pt
&& *pt
!= ' '; ++pt
)
1085 if (*pt
) { /* Found busid */
1086 return drmOpenByBusid(++pt
, type
);
1087 } else { /* No busid */
1088 return drmOpenDevice(strtol(devstring
, NULL
, 0),i
, type
);
1102 * Open the DRM device.
1104 * Looks up the specified name and bus ID, and opens the device found. The
1105 * entry in /dev/dri is created if necessary and if called by root.
1107 * \param name driver name. Not referenced if bus ID is supplied.
1108 * \param busid bus ID. Zero if not known.
1110 * \return a file descriptor on success, or a negative value on error.
1113 * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
1116 drm_public
int drmOpen(const char *name
, const char *busid
)
1118 return drmOpenWithType(name
, busid
, DRM_NODE_PRIMARY
);
1122 * Open the DRM device with specified type.
1124 * Looks up the specified name and bus ID, and opens the device found. The
1125 * entry in /dev/dri is created if necessary and if called by root.
1127 * \param name driver name. Not referenced if bus ID is supplied.
1128 * \param busid bus ID. Zero if not known.
1129 * \param type the device node type to open, PRIMARY, CONTROL or RENDER
1131 * \return a file descriptor on success, or a negative value on error.
1134 * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
1137 drm_public
int drmOpenWithType(const char *name
, const char *busid
, int type
)
1139 if (name
!= NULL
&& drm_server_info
&&
1140 drm_server_info
->load_module
&& !drmAvailable()) {
1141 /* try to load the kernel module */
1142 if (!drm_server_info
->load_module(name
)) {
1143 drmMsg("[drm] failed to load kernel module \"%s\"\n", name
);
1149 int fd
= drmOpenByBusid(busid
, type
);
1155 return drmOpenByName(name
, type
);
1160 drm_public
int drmOpenControl(int minor
)
1162 return drmOpenMinor(minor
, 0, DRM_NODE_CONTROL
);
1165 drm_public
int drmOpenRender(int minor
)
1167 return drmOpenMinor(minor
, 0, DRM_NODE_RENDER
);
1171 * Free the version information returned by drmGetVersion().
1173 * \param v pointer to the version information.
1176 * It frees the memory pointed by \p %v as well as all the non-null strings
1179 drm_public
void drmFreeVersion(drmVersionPtr v
)
1191 * Free the non-public version information returned by the kernel.
1193 * \param v pointer to the version information.
1196 * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
1197 * the non-null strings pointers in it.
1199 static void drmFreeKernelVersion(drm_version_t
*v
)
1211 * Copy version information.
1213 * \param d destination pointer.
1214 * \param s source pointer.
1217 * Used by drmGetVersion() to translate the information returned by the ioctl
1218 * interface in a private structure into the public structure counterpart.
1220 static void drmCopyVersion(drmVersionPtr d
, const drm_version_t
*s
)
1222 d
->version_major
= s
->version_major
;
1223 d
->version_minor
= s
->version_minor
;
1224 d
->version_patchlevel
= s
->version_patchlevel
;
1225 d
->name_len
= s
->name_len
;
1226 d
->name
= strdup(s
->name
);
1227 d
->date_len
= s
->date_len
;
1228 d
->date
= strdup(s
->date
);
1229 d
->desc_len
= s
->desc_len
;
1230 d
->desc
= strdup(s
->desc
);
1235 * Query the driver version information.
1237 * \param fd file descriptor.
1239 * \return pointer to a drmVersion structure which should be freed with
1242 * \note Similar information is available via /proc/dri.
1245 * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
1246 * first with zeros to get the string lengths, and then the actually strings.
1247 * It also null-terminates them since they might not be already.
1249 drm_public drmVersionPtr
drmGetVersion(int fd
)
1251 drmVersionPtr retval
;
1252 drm_version_t
*version
= drmMalloc(sizeof(*version
));
1254 if (drmIoctl(fd
, DRM_IOCTL_VERSION
, version
)) {
1255 drmFreeKernelVersion(version
);
1259 if (version
->name_len
)
1260 version
->name
= drmMalloc(version
->name_len
+ 1);
1261 if (version
->date_len
)
1262 version
->date
= drmMalloc(version
->date_len
+ 1);
1263 if (version
->desc_len
)
1264 version
->desc
= drmMalloc(version
->desc_len
+ 1);
1266 if (drmIoctl(fd
, DRM_IOCTL_VERSION
, version
)) {
1267 drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno
));
1268 drmFreeKernelVersion(version
);
1272 /* The results might not be null-terminated strings, so terminate them. */
1273 if (version
->name_len
) version
->name
[version
->name_len
] = '\0';
1274 if (version
->date_len
) version
->date
[version
->date_len
] = '\0';
1275 if (version
->desc_len
) version
->desc
[version
->desc_len
] = '\0';
1277 retval
= drmMalloc(sizeof(*retval
));
1278 drmCopyVersion(retval
, version
);
1279 drmFreeKernelVersion(version
);
1285 * Get version information for the DRM user space library.
1287 * This version number is driver independent.
1289 * \param fd file descriptor.
1291 * \return version information.
1294 * This function allocates and fills a drm_version structure with a hard coded
1297 drm_public drmVersionPtr
drmGetLibVersion(int fd
)
1299 drm_version_t
*version
= drmMalloc(sizeof(*version
));
1302 * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
1303 * revision 1.0.x = original DRM interface with no drmGetLibVersion
1304 * entry point and many drm<Device> extensions
1305 * revision 1.1.x = added drmCommand entry points for device extensions
1306 * added drmGetLibVersion to identify libdrm.a version
1307 * revision 1.2.x = added drmSetInterfaceVersion
1308 * modified drmOpen to handle both busid and name
1309 * revision 1.3.x = added server + memory manager
1311 version
->version_major
= 1;
1312 version
->version_minor
= 3;
1313 version
->version_patchlevel
= 0;
1315 return (drmVersionPtr
)version
;
1318 drm_public
int drmGetCap(int fd
, uint64_t capability
, uint64_t *value
)
1320 struct drm_get_cap cap
;
1324 cap
.capability
= capability
;
1326 ret
= drmIoctl(fd
, DRM_IOCTL_GET_CAP
, &cap
);
1334 drm_public
int drmSetClientCap(int fd
, uint64_t capability
, uint64_t value
)
1336 struct drm_set_client_cap cap
;
1339 cap
.capability
= capability
;
1342 return drmIoctl(fd
, DRM_IOCTL_SET_CLIENT_CAP
, &cap
);
1346 * Free the bus ID information.
1348 * \param busid bus ID information string as given by drmGetBusid().
1351 * This function is just frees the memory pointed by \p busid.
1353 drm_public
void drmFreeBusid(const char *busid
)
1355 drmFree((void *)busid
);
1360 * Get the bus ID of the device.
1362 * \param fd file descriptor.
1364 * \return bus ID string.
1367 * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
1368 * get the string length and data, passing the arguments in a drm_unique
1371 drm_public
char *drmGetBusid(int fd
)
1377 if (drmIoctl(fd
, DRM_IOCTL_GET_UNIQUE
, &u
))
1379 u
.unique
= drmMalloc(u
.unique_len
+ 1);
1380 if (drmIoctl(fd
, DRM_IOCTL_GET_UNIQUE
, &u
)) {
1384 u
.unique
[u
.unique_len
] = '\0';
1391 * Set the bus ID of the device.
1393 * \param fd file descriptor.
1394 * \param busid bus ID string.
1396 * \return zero on success, negative on failure.
1399 * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
1400 * the arguments in a drm_unique structure.
1402 drm_public
int drmSetBusid(int fd
, const char *busid
)
1407 u
.unique
= (char *)busid
;
1408 u
.unique_len
= strlen(busid
);
1410 if (drmIoctl(fd
, DRM_IOCTL_SET_UNIQUE
, &u
)) {
1416 drm_public
int drmGetMagic(int fd
, drm_magic_t
* magic
)
1423 if (drmIoctl(fd
, DRM_IOCTL_GET_MAGIC
, &auth
))
1425 *magic
= auth
.magic
;
1429 drm_public
int drmAuthMagic(int fd
, drm_magic_t magic
)
1435 if (drmIoctl(fd
, DRM_IOCTL_AUTH_MAGIC
, &auth
))
1441 * Specifies a range of memory that is available for mapping by a
1444 * \param fd file descriptor.
1445 * \param offset usually the physical address. The actual meaning depends of
1446 * the \p type parameter. See below.
1447 * \param size of the memory in bytes.
1448 * \param type type of the memory to be mapped.
1449 * \param flags combination of several flags to modify the function actions.
1450 * \param handle will be set to a value that may be used as the offset
1451 * parameter for mmap().
1453 * \return zero on success or a negative value on error.
1455 * \par Mapping the frame buffer
1456 * For the frame buffer
1457 * - \p offset will be the physical address of the start of the frame buffer,
1458 * - \p size will be the size of the frame buffer in bytes, and
1459 * - \p type will be DRM_FRAME_BUFFER.
1462 * The area mapped will be uncached. If MTRR support is available in the
1463 * kernel, the frame buffer area will be set to write combining.
1465 * \par Mapping the MMIO register area
1466 * For the MMIO register area,
1467 * - \p offset will be the physical address of the start of the register area,
1468 * - \p size will be the size of the register area bytes, and
1469 * - \p type will be DRM_REGISTERS.
1471 * The area mapped will be uncached.
1473 * \par Mapping the SAREA
1475 * - \p offset will be ignored and should be set to zero,
1476 * - \p size will be the desired size of the SAREA in bytes,
1477 * - \p type will be DRM_SHM.
1480 * A shared memory area of the requested size will be created and locked in
1481 * kernel memory. This area may be mapped into client-space by using the handle
1484 * \note May only be called by root.
1487 * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
1488 * the arguments in a drm_map structure.
1490 drm_public
int drmAddMap(int fd
, drm_handle_t offset
, drmSize size
, drmMapType type
,
1491 drmMapFlags flags
, drm_handle_t
*handle
)
1496 map
.offset
= offset
;
1500 if (drmIoctl(fd
, DRM_IOCTL_ADD_MAP
, &map
))
1503 *handle
= (drm_handle_t
)(uintptr_t)map
.handle
;
1507 drm_public
int drmRmMap(int fd
, drm_handle_t handle
)
1512 map
.handle
= (void *)(uintptr_t)handle
;
1514 if(drmIoctl(fd
, DRM_IOCTL_RM_MAP
, &map
))
1520 * Make buffers available for DMA transfers.
1522 * \param fd file descriptor.
1523 * \param count number of buffers.
1524 * \param size size of each buffer.
1525 * \param flags buffer allocation flags.
1526 * \param agp_offset offset in the AGP aperture
1528 * \return number of buffers allocated, negative on error.
1531 * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
1535 drm_public
int drmAddBufs(int fd
, int count
, int size
, drmBufDescFlags flags
,
1538 drm_buf_desc_t request
;
1541 request
.count
= count
;
1542 request
.size
= size
;
1543 request
.flags
= flags
;
1544 request
.agp_start
= agp_offset
;
1546 if (drmIoctl(fd
, DRM_IOCTL_ADD_BUFS
, &request
))
1548 return request
.count
;
1551 drm_public
int drmMarkBufs(int fd
, double low
, double high
)
1553 drm_buf_info_t info
;
1558 if (drmIoctl(fd
, DRM_IOCTL_INFO_BUFS
, &info
))
1564 if (!(info
.list
= drmMalloc(info
.count
* sizeof(*info
.list
))))
1567 if (drmIoctl(fd
, DRM_IOCTL_INFO_BUFS
, &info
)) {
1568 int retval
= -errno
;
1573 for (i
= 0; i
< info
.count
; i
++) {
1574 info
.list
[i
].low_mark
= low
* info
.list
[i
].count
;
1575 info
.list
[i
].high_mark
= high
* info
.list
[i
].count
;
1576 if (drmIoctl(fd
, DRM_IOCTL_MARK_BUFS
, &info
.list
[i
])) {
1577 int retval
= -errno
;
1590 * \param fd file descriptor.
1591 * \param count number of buffers to free.
1592 * \param list list of buffers to be freed.
1594 * \return zero on success, or a negative value on failure.
1596 * \note This function is primarily used for debugging.
1599 * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
1600 * the arguments in a drm_buf_free structure.
1602 drm_public
int drmFreeBufs(int fd
, int count
, int *list
)
1604 drm_buf_free_t request
;
1607 request
.count
= count
;
1608 request
.list
= list
;
1609 if (drmIoctl(fd
, DRM_IOCTL_FREE_BUFS
, &request
))
1618 * \param fd file descriptor.
1621 * This function closes the file descriptor.
1623 drm_public
int drmClose(int fd
)
1625 unsigned long key
= drmGetKeyFromFd(fd
);
1626 drmHashEntry
*entry
= drmGetEntry(fd
);
1628 drmHashDestroy(entry
->tagTable
);
1631 entry
->tagTable
= NULL
;
1633 drmHashDelete(drmHashTable
, key
);
1641 * Map a region of memory.
1643 * \param fd file descriptor.
1644 * \param handle handle returned by drmAddMap().
1645 * \param size size in bytes. Must match the size used by drmAddMap().
1646 * \param address will contain the user-space virtual address where the mapping
1649 * \return zero on success, or a negative value on failure.
1652 * This function is a wrapper for mmap().
1654 drm_public
int drmMap(int fd
, drm_handle_t handle
, drmSize size
,
1655 drmAddressPtr address
)
1657 static unsigned long pagesize_mask
= 0;
1663 pagesize_mask
= getpagesize() - 1;
1665 size
= (size
+ pagesize_mask
) & ~pagesize_mask
;
1667 *address
= drm_mmap(0, size
, PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, handle
);
1668 if (*address
== MAP_FAILED
)
1675 * Unmap mappings obtained with drmMap().
1677 * \param address address as given by drmMap().
1678 * \param size size in bytes. Must match the size used by drmMap().
1680 * \return zero on success, or a negative value on failure.
1683 * This function is a wrapper for munmap().
1685 drm_public
int drmUnmap(drmAddress address
, drmSize size
)
1687 return drm_munmap(address
, size
);
1690 drm_public drmBufInfoPtr
drmGetBufInfo(int fd
)
1692 drm_buf_info_t info
;
1693 drmBufInfoPtr retval
;
1698 if (drmIoctl(fd
, DRM_IOCTL_INFO_BUFS
, &info
))
1702 if (!(info
.list
= drmMalloc(info
.count
* sizeof(*info
.list
))))
1705 if (drmIoctl(fd
, DRM_IOCTL_INFO_BUFS
, &info
)) {
1710 retval
= drmMalloc(sizeof(*retval
));
1711 retval
->count
= info
.count
;
1712 if (!(retval
->list
= drmMalloc(info
.count
* sizeof(*retval
->list
)))) {
1718 for (i
= 0; i
< info
.count
; i
++) {
1719 retval
->list
[i
].count
= info
.list
[i
].count
;
1720 retval
->list
[i
].size
= info
.list
[i
].size
;
1721 retval
->list
[i
].low_mark
= info
.list
[i
].low_mark
;
1722 retval
->list
[i
].high_mark
= info
.list
[i
].high_mark
;
1731 * Map all DMA buffers into client-virtual space.
1733 * \param fd file descriptor.
1735 * \return a pointer to a ::drmBufMap structure.
1737 * \note The client may not use these buffers until obtaining buffer indices
1741 * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
1742 * information about the buffers in a drm_buf_map structure into the
1743 * client-visible data structures.
1745 drm_public drmBufMapPtr
drmMapBufs(int fd
)
1748 drmBufMapPtr retval
;
1752 if (drmIoctl(fd
, DRM_IOCTL_MAP_BUFS
, &bufs
))
1758 if (!(bufs
.list
= drmMalloc(bufs
.count
* sizeof(*bufs
.list
))))
1761 if (drmIoctl(fd
, DRM_IOCTL_MAP_BUFS
, &bufs
)) {
1766 retval
= drmMalloc(sizeof(*retval
));
1767 retval
->count
= bufs
.count
;
1768 retval
->list
= drmMalloc(bufs
.count
* sizeof(*retval
->list
));
1769 for (i
= 0; i
< bufs
.count
; i
++) {
1770 retval
->list
[i
].idx
= bufs
.list
[i
].idx
;
1771 retval
->list
[i
].total
= bufs
.list
[i
].total
;
1772 retval
->list
[i
].used
= 0;
1773 retval
->list
[i
].address
= bufs
.list
[i
].address
;
1782 * Unmap buffers allocated with drmMapBufs().
1784 * \return zero on success, or negative value on failure.
1787 * Calls munmap() for every buffer stored in \p bufs and frees the
1788 * memory allocated by drmMapBufs().
1790 drm_public
int drmUnmapBufs(drmBufMapPtr bufs
)
1794 for (i
= 0; i
< bufs
->count
; i
++) {
1795 drm_munmap(bufs
->list
[i
].address
, bufs
->list
[i
].total
);
1798 drmFree(bufs
->list
);
1804 #define DRM_DMA_RETRY 16
1807 * Reserve DMA buffers.
1809 * \param fd file descriptor.
1812 * \return zero on success, or a negative value on failure.
1815 * Assemble the arguments into a drm_dma structure and keeps issuing the
1816 * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
1818 drm_public
int drmDMA(int fd
, drmDMAReqPtr request
)
1823 dma
.context
= request
->context
;
1824 dma
.send_count
= request
->send_count
;
1825 dma
.send_indices
= request
->send_list
;
1826 dma
.send_sizes
= request
->send_sizes
;
1827 dma
.flags
= request
->flags
;
1828 dma
.request_count
= request
->request_count
;
1829 dma
.request_size
= request
->request_size
;
1830 dma
.request_indices
= request
->request_list
;
1831 dma
.request_sizes
= request
->request_sizes
;
1832 dma
.granted_count
= 0;
1835 ret
= ioctl( fd
, DRM_IOCTL_DMA
, &dma
);
1836 } while ( ret
&& errno
== EAGAIN
&& i
++ < DRM_DMA_RETRY
);
1839 request
->granted_count
= dma
.granted_count
;
1848 * Obtain heavyweight hardware lock.
1850 * \param fd file descriptor.
1851 * \param context context.
1852 * \param flags flags that determine the state of the hardware when the function
1855 * \return always zero.
1858 * This function translates the arguments into a drm_lock structure and issue
1859 * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
1861 drm_public
int drmGetLock(int fd
, drm_context_t context
, drmLockFlags flags
)
1866 lock
.context
= context
;
1868 if (flags
& DRM_LOCK_READY
) lock
.flags
|= _DRM_LOCK_READY
;
1869 if (flags
& DRM_LOCK_QUIESCENT
) lock
.flags
|= _DRM_LOCK_QUIESCENT
;
1870 if (flags
& DRM_LOCK_FLUSH
) lock
.flags
|= _DRM_LOCK_FLUSH
;
1871 if (flags
& DRM_LOCK_FLUSH_ALL
) lock
.flags
|= _DRM_LOCK_FLUSH_ALL
;
1872 if (flags
& DRM_HALT_ALL_QUEUES
) lock
.flags
|= _DRM_HALT_ALL_QUEUES
;
1873 if (flags
& DRM_HALT_CUR_QUEUES
) lock
.flags
|= _DRM_HALT_CUR_QUEUES
;
1875 while (drmIoctl(fd
, DRM_IOCTL_LOCK
, &lock
))
1881 * Release the hardware lock.
1883 * \param fd file descriptor.
1884 * \param context context.
1886 * \return zero on success, or a negative value on failure.
1889 * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
1890 * argument in a drm_lock structure.
1892 drm_public
int drmUnlock(int fd
, drm_context_t context
)
1897 lock
.context
= context
;
1898 return drmIoctl(fd
, DRM_IOCTL_UNLOCK
, &lock
);
1901 drm_public drm_context_t
*drmGetReservedContextList(int fd
, int *count
)
1905 drm_context_t
* retval
;
1909 if (drmIoctl(fd
, DRM_IOCTL_RES_CTX
, &res
))
1915 if (!(list
= drmMalloc(res
.count
* sizeof(*list
))))
1917 if (!(retval
= drmMalloc(res
.count
* sizeof(*retval
))))
1920 res
.contexts
= list
;
1921 if (drmIoctl(fd
, DRM_IOCTL_RES_CTX
, &res
))
1922 goto err_free_context
;
1924 for (i
= 0; i
< res
.count
; i
++)
1925 retval
[i
] = list
[i
].handle
;
1938 drm_public
void drmFreeReservedContextList(drm_context_t
*pt
)
1946 * Used by the X server during GLXContext initialization. This causes
1947 * per-context kernel-level resources to be allocated.
1949 * \param fd file descriptor.
1950 * \param handle is set on success. To be used by the client when requesting DMA
1951 * dispatch with drmDMA().
1953 * \return zero on success, or a negative value on failure.
1955 * \note May only be called by root.
1958 * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
1959 * argument in a drm_ctx structure.
1961 drm_public
int drmCreateContext(int fd
, drm_context_t
*handle
)
1966 if (drmIoctl(fd
, DRM_IOCTL_ADD_CTX
, &ctx
))
1968 *handle
= ctx
.handle
;
1972 drm_public
int drmSwitchToContext(int fd
, drm_context_t context
)
1977 ctx
.handle
= context
;
1978 if (drmIoctl(fd
, DRM_IOCTL_SWITCH_CTX
, &ctx
))
1983 drm_public
int drmSetContextFlags(int fd
, drm_context_t context
,
1984 drm_context_tFlags flags
)
1989 * Context preserving means that no context switches are done between DMA
1990 * buffers from one context and the next. This is suitable for use in the
1991 * X server (which promises to maintain hardware context), or in the
1992 * client-side library when buffers are swapped on behalf of two threads.
1995 ctx
.handle
= context
;
1996 if (flags
& DRM_CONTEXT_PRESERVED
)
1997 ctx
.flags
|= _DRM_CONTEXT_PRESERVED
;
1998 if (flags
& DRM_CONTEXT_2DONLY
)
1999 ctx
.flags
|= _DRM_CONTEXT_2DONLY
;
2000 if (drmIoctl(fd
, DRM_IOCTL_MOD_CTX
, &ctx
))
2005 drm_public
int drmGetContextFlags(int fd
, drm_context_t context
,
2006 drm_context_tFlagsPtr flags
)
2011 ctx
.handle
= context
;
2012 if (drmIoctl(fd
, DRM_IOCTL_GET_CTX
, &ctx
))
2015 if (ctx
.flags
& _DRM_CONTEXT_PRESERVED
)
2016 *flags
|= DRM_CONTEXT_PRESERVED
;
2017 if (ctx
.flags
& _DRM_CONTEXT_2DONLY
)
2018 *flags
|= DRM_CONTEXT_2DONLY
;
2025 * Free any kernel-level resources allocated with drmCreateContext() associated
2028 * \param fd file descriptor.
2029 * \param handle handle given by drmCreateContext().
2031 * \return zero on success, or a negative value on failure.
2033 * \note May only be called by root.
2036 * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
2037 * argument in a drm_ctx structure.
2039 drm_public
int drmDestroyContext(int fd
, drm_context_t handle
)
2044 ctx
.handle
= handle
;
2045 if (drmIoctl(fd
, DRM_IOCTL_RM_CTX
, &ctx
))
2050 drm_public
int drmCreateDrawable(int fd
, drm_drawable_t
*handle
)
2055 if (drmIoctl(fd
, DRM_IOCTL_ADD_DRAW
, &draw
))
2057 *handle
= draw
.handle
;
2061 drm_public
int drmDestroyDrawable(int fd
, drm_drawable_t handle
)
2066 draw
.handle
= handle
;
2067 if (drmIoctl(fd
, DRM_IOCTL_RM_DRAW
, &draw
))
2072 drm_public
int drmUpdateDrawableInfo(int fd
, drm_drawable_t handle
,
2073 drm_drawable_info_type_t type
,
2074 unsigned int num
, void *data
)
2076 drm_update_draw_t update
;
2079 update
.handle
= handle
;
2082 update
.data
= (unsigned long long)(unsigned long)data
;
2084 if (drmIoctl(fd
, DRM_IOCTL_UPDATE_DRAW
, &update
))
2090 drm_public
int drmCrtcGetSequence(int fd
, uint32_t crtcId
, uint64_t *sequence
,
2093 struct drm_crtc_get_sequence get_seq
;
2097 get_seq
.crtc_id
= crtcId
;
2098 ret
= drmIoctl(fd
, DRM_IOCTL_CRTC_GET_SEQUENCE
, &get_seq
);
2103 *sequence
= get_seq
.sequence
;
2105 *ns
= get_seq
.sequence_ns
;
2109 drm_public
int drmCrtcQueueSequence(int fd
, uint32_t crtcId
, uint32_t flags
,
2111 uint64_t *sequence_queued
,
2114 struct drm_crtc_queue_sequence queue_seq
;
2117 memclear(queue_seq
);
2118 queue_seq
.crtc_id
= crtcId
;
2119 queue_seq
.flags
= flags
;
2120 queue_seq
.sequence
= sequence
;
2121 queue_seq
.user_data
= user_data
;
2123 ret
= drmIoctl(fd
, DRM_IOCTL_CRTC_QUEUE_SEQUENCE
, &queue_seq
);
2124 if (ret
== 0 && sequence_queued
)
2125 *sequence_queued
= queue_seq
.sequence
;
2131 * Acquire the AGP device.
2133 * Must be called before any of the other AGP related calls.
2135 * \param fd file descriptor.
2137 * \return zero on success, or a negative value on failure.
2140 * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
2142 drm_public
int drmAgpAcquire(int fd
)
2144 if (drmIoctl(fd
, DRM_IOCTL_AGP_ACQUIRE
, NULL
))
2151 * Release the AGP device.
2153 * \param fd file descriptor.
2155 * \return zero on success, or a negative value on failure.
2158 * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
2160 drm_public
int drmAgpRelease(int fd
)
2162 if (drmIoctl(fd
, DRM_IOCTL_AGP_RELEASE
, NULL
))
2171 * \param fd file descriptor.
2172 * \param mode AGP mode.
2174 * \return zero on success, or a negative value on failure.
2177 * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
2178 * argument in a drm_agp_mode structure.
2180 drm_public
int drmAgpEnable(int fd
, unsigned long mode
)
2186 if (drmIoctl(fd
, DRM_IOCTL_AGP_ENABLE
, &m
))
2193 * Allocate a chunk of AGP memory.
2195 * \param fd file descriptor.
2196 * \param size requested memory size in bytes. Will be rounded to page boundary.
2197 * \param type type of memory to allocate.
2198 * \param address if not zero, will be set to the physical address of the
2200 * \param handle on success will be set to a handle of the allocated memory.
2202 * \return zero on success, or a negative value on failure.
2205 * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
2206 * arguments in a drm_agp_buffer structure.
2208 drm_public
int drmAgpAlloc(int fd
, unsigned long size
, unsigned long type
,
2209 unsigned long *address
, drm_handle_t
*handle
)
2214 *handle
= DRM_AGP_NO_HANDLE
;
2217 if (drmIoctl(fd
, DRM_IOCTL_AGP_ALLOC
, &b
))
2220 *address
= b
.physical
;
2227 * Free a chunk of AGP memory.
2229 * \param fd file descriptor.
2230 * \param handle handle to the allocated memory, as given by drmAgpAllocate().
2232 * \return zero on success, or a negative value on failure.
2235 * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
2236 * argument in a drm_agp_buffer structure.
2238 drm_public
int drmAgpFree(int fd
, drm_handle_t handle
)
2244 if (drmIoctl(fd
, DRM_IOCTL_AGP_FREE
, &b
))
2251 * Bind a chunk of AGP memory.
2253 * \param fd file descriptor.
2254 * \param handle handle to the allocated memory, as given by drmAgpAllocate().
2255 * \param offset offset in bytes. It will round to page boundary.
2257 * \return zero on success, or a negative value on failure.
2260 * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
2261 * argument in a drm_agp_binding structure.
2263 drm_public
int drmAgpBind(int fd
, drm_handle_t handle
, unsigned long offset
)
2265 drm_agp_binding_t b
;
2270 if (drmIoctl(fd
, DRM_IOCTL_AGP_BIND
, &b
))
2277 * Unbind a chunk of AGP memory.
2279 * \param fd file descriptor.
2280 * \param handle handle to the allocated memory, as given by drmAgpAllocate().
2282 * \return zero on success, or a negative value on failure.
2285 * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
2286 * the argument in a drm_agp_binding structure.
2288 drm_public
int drmAgpUnbind(int fd
, drm_handle_t handle
)
2290 drm_agp_binding_t b
;
2294 if (drmIoctl(fd
, DRM_IOCTL_AGP_UNBIND
, &b
))
2301 * Get AGP driver major version number.
2303 * \param fd file descriptor.
2305 * \return major version number on success, or a negative value on failure..
2308 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2309 * necessary information in a drm_agp_info structure.
2311 drm_public
int drmAgpVersionMajor(int fd
)
2317 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2319 return i
.agp_version_major
;
2324 * Get AGP driver minor version number.
2326 * \param fd file descriptor.
2328 * \return minor version number on success, or a negative value on failure.
2331 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2332 * necessary information in a drm_agp_info structure.
2334 drm_public
int drmAgpVersionMinor(int fd
)
2340 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2342 return i
.agp_version_minor
;
2349 * \param fd file descriptor.
2351 * \return mode on success, or zero on failure.
2354 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2355 * necessary information in a drm_agp_info structure.
2357 drm_public
unsigned long drmAgpGetMode(int fd
)
2363 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2370 * Get AGP aperture base.
2372 * \param fd file descriptor.
2374 * \return aperture base on success, zero on failure.
2377 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2378 * necessary information in a drm_agp_info structure.
2380 drm_public
unsigned long drmAgpBase(int fd
)
2386 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2388 return i
.aperture_base
;
2393 * Get AGP aperture size.
2395 * \param fd file descriptor.
2397 * \return aperture size on success, zero on failure.
2400 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2401 * necessary information in a drm_agp_info structure.
2403 drm_public
unsigned long drmAgpSize(int fd
)
2409 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2411 return i
.aperture_size
;
2416 * Get used AGP memory.
2418 * \param fd file descriptor.
2420 * \return memory used on success, or zero on failure.
2423 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2424 * necessary information in a drm_agp_info structure.
2426 drm_public
unsigned long drmAgpMemoryUsed(int fd
)
2432 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2434 return i
.memory_used
;
2439 * Get available AGP memory.
2441 * \param fd file descriptor.
2443 * \return memory available on success, or zero on failure.
2446 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2447 * necessary information in a drm_agp_info structure.
2449 drm_public
unsigned long drmAgpMemoryAvail(int fd
)
2455 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2457 return i
.memory_allowed
;
2462 * Get hardware vendor ID.
2464 * \param fd file descriptor.
2466 * \return vendor ID on success, or zero on failure.
2469 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2470 * necessary information in a drm_agp_info structure.
2472 drm_public
unsigned int drmAgpVendorId(int fd
)
2478 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2485 * Get hardware device ID.
2487 * \param fd file descriptor.
2489 * \return zero on success, or zero on failure.
2492 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2493 * necessary information in a drm_agp_info structure.
2495 drm_public
unsigned int drmAgpDeviceId(int fd
)
2501 if (drmIoctl(fd
, DRM_IOCTL_AGP_INFO
, &i
))
2506 drm_public
int drmScatterGatherAlloc(int fd
, unsigned long size
,
2507 drm_handle_t
*handle
)
2509 drm_scatter_gather_t sg
;
2515 if (drmIoctl(fd
, DRM_IOCTL_SG_ALLOC
, &sg
))
2517 *handle
= sg
.handle
;
2521 drm_public
int drmScatterGatherFree(int fd
, drm_handle_t handle
)
2523 drm_scatter_gather_t sg
;
2527 if (drmIoctl(fd
, DRM_IOCTL_SG_FREE
, &sg
))
2535 * \param fd file descriptor.
2536 * \param vbl pointer to a drmVBlank structure.
2538 * \return zero on success, or a negative value on failure.
2541 * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
2543 drm_public
int drmWaitVBlank(int fd
, drmVBlankPtr vbl
)
2545 struct timespec timeout
, cur
;
2548 ret
= clock_gettime(CLOCK_MONOTONIC
, &timeout
);
2550 fprintf(stderr
, "clock_gettime failed: %s\n", strerror(errno
));
2556 ret
= ioctl(fd
, DRM_IOCTL_WAIT_VBLANK
, vbl
);
2557 vbl
->request
.type
&= ~DRM_VBLANK_RELATIVE
;
2558 if (ret
&& errno
== EINTR
) {
2559 clock_gettime(CLOCK_MONOTONIC
, &cur
);
2560 /* Timeout after 1s */
2561 if (cur
.tv_sec
> timeout
.tv_sec
+ 1 ||
2562 (cur
.tv_sec
== timeout
.tv_sec
&& cur
.tv_nsec
>=
2569 } while (ret
&& errno
== EINTR
);
2575 drm_public
int drmError(int err
, const char *label
)
2578 case DRM_ERR_NO_DEVICE
:
2579 fprintf(stderr
, "%s: no device\n", label
);
2581 case DRM_ERR_NO_ACCESS
:
2582 fprintf(stderr
, "%s: no access\n", label
);
2584 case DRM_ERR_NOT_ROOT
:
2585 fprintf(stderr
, "%s: not root\n", label
);
2587 case DRM_ERR_INVALID
:
2588 fprintf(stderr
, "%s: invalid args\n", label
);
2593 fprintf( stderr
, "%s: error %d (%s)\n", label
, err
, strerror(err
) );
2601 * Install IRQ handler.
2603 * \param fd file descriptor.
2604 * \param irq IRQ number.
2606 * \return zero on success, or a negative value on failure.
2609 * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
2610 * argument in a drm_control structure.
2612 drm_public
int drmCtlInstHandler(int fd
, int irq
)
2617 ctl
.func
= DRM_INST_HANDLER
;
2619 if (drmIoctl(fd
, DRM_IOCTL_CONTROL
, &ctl
))
2626 * Uninstall IRQ handler.
2628 * \param fd file descriptor.
2630 * \return zero on success, or a negative value on failure.
2633 * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
2634 * argument in a drm_control structure.
2636 drm_public
int drmCtlUninstHandler(int fd
)
2641 ctl
.func
= DRM_UNINST_HANDLER
;
2643 if (drmIoctl(fd
, DRM_IOCTL_CONTROL
, &ctl
))
2648 drm_public
int drmFinish(int fd
, int context
, drmLockFlags flags
)
2653 lock
.context
= context
;
2654 if (flags
& DRM_LOCK_READY
) lock
.flags
|= _DRM_LOCK_READY
;
2655 if (flags
& DRM_LOCK_QUIESCENT
) lock
.flags
|= _DRM_LOCK_QUIESCENT
;
2656 if (flags
& DRM_LOCK_FLUSH
) lock
.flags
|= _DRM_LOCK_FLUSH
;
2657 if (flags
& DRM_LOCK_FLUSH_ALL
) lock
.flags
|= _DRM_LOCK_FLUSH_ALL
;
2658 if (flags
& DRM_HALT_ALL_QUEUES
) lock
.flags
|= _DRM_HALT_ALL_QUEUES
;
2659 if (flags
& DRM_HALT_CUR_QUEUES
) lock
.flags
|= _DRM_HALT_CUR_QUEUES
;
2660 if (drmIoctl(fd
, DRM_IOCTL_FINISH
, &lock
))
2666 * Get IRQ from bus ID.
2668 * \param fd file descriptor.
2669 * \param busnum bus number.
2670 * \param devnum device number.
2671 * \param funcnum function number.
2673 * \return IRQ number on success, or a negative value on failure.
2676 * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
2677 * arguments in a drm_irq_busid structure.
2679 drm_public
int drmGetInterruptFromBusID(int fd
, int busnum
, int devnum
,
2687 p
.funcnum
= funcnum
;
2688 if (drmIoctl(fd
, DRM_IOCTL_IRQ_BUSID
, &p
))
2693 drm_public
int drmAddContextTag(int fd
, drm_context_t context
, void *tag
)
2695 drmHashEntry
*entry
= drmGetEntry(fd
);
2697 if (drmHashInsert(entry
->tagTable
, context
, tag
)) {
2698 drmHashDelete(entry
->tagTable
, context
);
2699 drmHashInsert(entry
->tagTable
, context
, tag
);
2704 drm_public
int drmDelContextTag(int fd
, drm_context_t context
)
2706 drmHashEntry
*entry
= drmGetEntry(fd
);
2708 return drmHashDelete(entry
->tagTable
, context
);
2711 drm_public
void *drmGetContextTag(int fd
, drm_context_t context
)
2713 drmHashEntry
*entry
= drmGetEntry(fd
);
2716 if (drmHashLookup(entry
->tagTable
, context
, &value
))
2722 drm_public
int drmAddContextPrivateMapping(int fd
, drm_context_t ctx_id
,
2723 drm_handle_t handle
)
2725 drm_ctx_priv_map_t map
;
2728 map
.ctx_id
= ctx_id
;
2729 map
.handle
= (void *)(uintptr_t)handle
;
2731 if (drmIoctl(fd
, DRM_IOCTL_SET_SAREA_CTX
, &map
))
2736 drm_public
int drmGetContextPrivateMapping(int fd
, drm_context_t ctx_id
,
2737 drm_handle_t
*handle
)
2739 drm_ctx_priv_map_t map
;
2742 map
.ctx_id
= ctx_id
;
2744 if (drmIoctl(fd
, DRM_IOCTL_GET_SAREA_CTX
, &map
))
2747 *handle
= (drm_handle_t
)(uintptr_t)map
.handle
;
2752 drm_public
int drmGetMap(int fd
, int idx
, drm_handle_t
*offset
, drmSize
*size
,
2753 drmMapType
*type
, drmMapFlags
*flags
,
2754 drm_handle_t
*handle
, int *mtrr
)
2760 if (drmIoctl(fd
, DRM_IOCTL_GET_MAP
, &map
))
2762 *offset
= map
.offset
;
2766 *handle
= (unsigned long)map
.handle
;
2771 drm_public
int drmGetClient(int fd
, int idx
, int *auth
, int *pid
, int *uid
,
2772 unsigned long *magic
, unsigned long *iocs
)
2774 drm_client_t client
;
2778 if (drmIoctl(fd
, DRM_IOCTL_GET_CLIENT
, &client
))
2780 *auth
= client
.auth
;
2783 *magic
= client
.magic
;
2784 *iocs
= client
.iocs
;
2788 drm_public
int drmGetStats(int fd
, drmStatsT
*stats
)
2794 if (drmIoctl(fd
, DRM_IOCTL_GET_STATS
, &s
))
2798 memset(stats
, 0, sizeof(*stats
));
2799 if (s
.count
> sizeof(stats
->data
)/sizeof(stats
->data
[0]))
2803 stats->data[i].long_format = "%-20.20s"; \
2804 stats->data[i].rate_format = "%8.8s"; \
2805 stats->data[i].isvalue = 1; \
2806 stats->data[i].verbose = 0
2809 stats->data[i].long_format = "%-20.20s"; \
2810 stats->data[i].rate_format = "%5.5s"; \
2811 stats->data[i].isvalue = 0; \
2812 stats->data[i].mult_names = "kgm"; \
2813 stats->data[i].mult = 1000; \
2814 stats->data[i].verbose = 0
2817 stats->data[i].long_format = "%-20.20s"; \
2818 stats->data[i].rate_format = "%5.5s"; \
2819 stats->data[i].isvalue = 0; \
2820 stats->data[i].mult_names = "KGM"; \
2821 stats->data[i].mult = 1024; \
2822 stats->data[i].verbose = 0
2825 stats
->count
= s
.count
;
2826 for (i
= 0; i
< s
.count
; i
++) {
2827 stats
->data
[i
].value
= s
.data
[i
].value
;
2828 switch (s
.data
[i
].type
) {
2829 case _DRM_STAT_LOCK
:
2830 stats
->data
[i
].long_name
= "Lock";
2831 stats
->data
[i
].rate_name
= "Lock";
2834 case _DRM_STAT_OPENS
:
2835 stats
->data
[i
].long_name
= "Opens";
2836 stats
->data
[i
].rate_name
= "O";
2838 stats
->data
[i
].verbose
= 1;
2840 case _DRM_STAT_CLOSES
:
2841 stats
->data
[i
].long_name
= "Closes";
2842 stats
->data
[i
].rate_name
= "Lock";
2844 stats
->data
[i
].verbose
= 1;
2846 case _DRM_STAT_IOCTLS
:
2847 stats
->data
[i
].long_name
= "Ioctls";
2848 stats
->data
[i
].rate_name
= "Ioc/s";
2851 case _DRM_STAT_LOCKS
:
2852 stats
->data
[i
].long_name
= "Locks";
2853 stats
->data
[i
].rate_name
= "Lck/s";
2856 case _DRM_STAT_UNLOCKS
:
2857 stats
->data
[i
].long_name
= "Unlocks";
2858 stats
->data
[i
].rate_name
= "Unl/s";
2862 stats
->data
[i
].long_name
= "IRQs";
2863 stats
->data
[i
].rate_name
= "IRQ/s";
2866 case _DRM_STAT_PRIMARY
:
2867 stats
->data
[i
].long_name
= "Primary Bytes";
2868 stats
->data
[i
].rate_name
= "PB/s";
2871 case _DRM_STAT_SECONDARY
:
2872 stats
->data
[i
].long_name
= "Secondary Bytes";
2873 stats
->data
[i
].rate_name
= "SB/s";
2877 stats
->data
[i
].long_name
= "DMA";
2878 stats
->data
[i
].rate_name
= "DMA/s";
2881 case _DRM_STAT_SPECIAL
:
2882 stats
->data
[i
].long_name
= "Special DMA";
2883 stats
->data
[i
].rate_name
= "dma/s";
2886 case _DRM_STAT_MISSED
:
2887 stats
->data
[i
].long_name
= "Miss";
2888 stats
->data
[i
].rate_name
= "Ms/s";
2891 case _DRM_STAT_VALUE
:
2892 stats
->data
[i
].long_name
= "Value";
2893 stats
->data
[i
].rate_name
= "Value";
2896 case _DRM_STAT_BYTE
:
2897 stats
->data
[i
].long_name
= "Bytes";
2898 stats
->data
[i
].rate_name
= "B/s";
2901 case _DRM_STAT_COUNT
:
2903 stats
->data
[i
].long_name
= "Count";
2904 stats
->data
[i
].rate_name
= "Cnt/s";
2913 * Issue a set-version ioctl.
2915 * \param fd file descriptor.
2916 * \param drmCommandIndex command index
2917 * \param data source pointer of the data to be read and written.
2918 * \param size size of the data to be read and written.
2920 * \return zero on success, or a negative value on failure.
2923 * It issues a read-write ioctl given by
2924 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2926 drm_public
int drmSetInterfaceVersion(int fd
, drmSetVersion
*version
)
2929 drm_set_version_t sv
;
2932 sv
.drm_di_major
= version
->drm_di_major
;
2933 sv
.drm_di_minor
= version
->drm_di_minor
;
2934 sv
.drm_dd_major
= version
->drm_dd_major
;
2935 sv
.drm_dd_minor
= version
->drm_dd_minor
;
2937 if (drmIoctl(fd
, DRM_IOCTL_SET_VERSION
, &sv
)) {
2941 version
->drm_di_major
= sv
.drm_di_major
;
2942 version
->drm_di_minor
= sv
.drm_di_minor
;
2943 version
->drm_dd_major
= sv
.drm_dd_major
;
2944 version
->drm_dd_minor
= sv
.drm_dd_minor
;
2950 * Send a device-specific command.
2952 * \param fd file descriptor.
2953 * \param drmCommandIndex command index
2955 * \return zero on success, or a negative value on failure.
2958 * It issues a ioctl given by
2959 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2961 drm_public
int drmCommandNone(int fd
, unsigned long drmCommandIndex
)
2963 unsigned long request
;
2965 request
= DRM_IO( DRM_COMMAND_BASE
+ drmCommandIndex
);
2967 if (drmIoctl(fd
, request
, NULL
)) {
2975 * Send a device-specific read command.
2977 * \param fd file descriptor.
2978 * \param drmCommandIndex command index
2979 * \param data destination pointer of the data to be read.
2980 * \param size size of the data to be read.
2982 * \return zero on success, or a negative value on failure.
2985 * It issues a read ioctl given by
2986 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2988 drm_public
int drmCommandRead(int fd
, unsigned long drmCommandIndex
,
2989 void *data
, unsigned long size
)
2991 unsigned long request
;
2993 request
= DRM_IOC( DRM_IOC_READ
, DRM_IOCTL_BASE
,
2994 DRM_COMMAND_BASE
+ drmCommandIndex
, size
);
2996 if (drmIoctl(fd
, request
, data
)) {
3004 * Send a device-specific write command.
3006 * \param fd file descriptor.
3007 * \param drmCommandIndex command index
3008 * \param data source pointer of the data to be written.
3009 * \param size size of the data to be written.
3011 * \return zero on success, or a negative value on failure.
3014 * It issues a write ioctl given by
3015 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
3017 drm_public
int drmCommandWrite(int fd
, unsigned long drmCommandIndex
,
3018 void *data
, unsigned long size
)
3020 unsigned long request
;
3022 request
= DRM_IOC( DRM_IOC_WRITE
, DRM_IOCTL_BASE
,
3023 DRM_COMMAND_BASE
+ drmCommandIndex
, size
);
3025 if (drmIoctl(fd
, request
, data
)) {
3033 * Send a device-specific read-write command.
3035 * \param fd file descriptor.
3036 * \param drmCommandIndex command index
3037 * \param data source pointer of the data to be read and written.
3038 * \param size size of the data to be read and written.
3040 * \return zero on success, or a negative value on failure.
3043 * It issues a read-write ioctl given by
3044 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
3046 drm_public
int drmCommandWriteRead(int fd
, unsigned long drmCommandIndex
,
3047 void *data
, unsigned long size
)
3049 unsigned long request
;
3051 request
= DRM_IOC( DRM_IOC_READ
|DRM_IOC_WRITE
, DRM_IOCTL_BASE
,
3052 DRM_COMMAND_BASE
+ drmCommandIndex
, size
);
3054 if (drmIoctl(fd
, request
, data
))
3059 #define DRM_MAX_FDS 16
3065 } connection
[DRM_MAX_FDS
];
3067 static int nr_fds
= 0;
3069 drm_public
int drmOpenOnce(void *unused
, const char *BusID
, int *newlyopened
)
3071 return drmOpenOnceWithType(BusID
, newlyopened
, DRM_NODE_PRIMARY
);
3074 drm_public
int drmOpenOnceWithType(const char *BusID
, int *newlyopened
,
3080 for (i
= 0; i
< nr_fds
; i
++)
3081 if ((strcmp(BusID
, connection
[i
].BusID
) == 0) &&
3082 (connection
[i
].type
== type
)) {
3083 connection
[i
].refcount
++;
3085 return connection
[i
].fd
;
3088 fd
= drmOpenWithType(NULL
, BusID
, type
);
3089 if (fd
< 0 || nr_fds
== DRM_MAX_FDS
)
3092 connection
[nr_fds
].BusID
= strdup(BusID
);
3093 connection
[nr_fds
].fd
= fd
;
3094 connection
[nr_fds
].refcount
= 1;
3095 connection
[nr_fds
].type
= type
;
3099 fprintf(stderr
, "saved connection %d for %s %d\n",
3100 nr_fds
, connection
[nr_fds
].BusID
,
3101 strcmp(BusID
, connection
[nr_fds
].BusID
));
3108 drm_public
void drmCloseOnce(int fd
)
3112 for (i
= 0; i
< nr_fds
; i
++) {
3113 if (fd
== connection
[i
].fd
) {
3114 if (--connection
[i
].refcount
== 0) {
3115 drmClose(connection
[i
].fd
);
3116 free(connection
[i
].BusID
);
3119 connection
[i
] = connection
[nr_fds
];
3127 drm_public
int drmSetMaster(int fd
)
3129 return drmIoctl(fd
, DRM_IOCTL_SET_MASTER
, NULL
);
3132 drm_public
int drmDropMaster(int fd
)
3134 return drmIoctl(fd
, DRM_IOCTL_DROP_MASTER
, NULL
);
3137 drm_public
int drmIsMaster(int fd
)
3139 /* Detect master by attempting something that requires master.
3141 * Authenticating magic tokens requires master and 0 is an
3142 * internal kernel detail which we could use. Attempting this on
3143 * a master fd would fail therefore fail with EINVAL because 0
3146 * A non-master fd will fail with EACCES, as the kernel checks
3147 * for master before attempting to do anything else.
3149 * Since we don't want to leak implementation details, use
3152 return drmAuthMagic(fd
, 0) != -EACCES
;
3155 drm_public
char *drmGetDeviceNameFromFd(int fd
)
3162 if (fstat(fd
, &sbuf
))
3165 maj
= major(sbuf
.st_rdev
);
3166 min
= minor(sbuf
.st_rdev
);
3167 nodetype
= drmGetMinorType(maj
, min
);
3168 return drmGetMinorNameForFD(fd
, nodetype
);
3175 /* The whole drmOpen thing is a fiasco and we need to find a way
3176 * back to just using open(2). For now, however, lets just make
3177 * things worse with even more ad hoc directory walking code to
3178 * discover the device file name. */
3183 for (i
= 0; i
< DRM_MAX_MINOR
; i
++) {
3184 snprintf(name
, sizeof name
, DRM_DEV_NAME
, DRM_DIR_NAME
, i
);
3185 if (stat(name
, &sbuf
) == 0 && sbuf
.st_rdev
== d
)
3188 if (i
== DRM_MAX_MINOR
)
3191 return strdup(name
);
3195 static bool drmNodeIsDRM(int maj
, int min
)
3201 snprintf(path
, sizeof(path
), "/sys/dev/char/%d:%d/device/drm",
3203 return stat(path
, &sbuf
) == 0;
3204 #elif defined(__FreeBSD__)
3205 char name
[SPECNAMELEN
];
3207 if (!devname_r(makedev(maj
, min
), S_IFCHR
, name
, sizeof(name
)))
3209 /* Handle drm/ and dri/ as both are present in different FreeBSD version
3210 * FreeBSD on amd64/i386/powerpc external kernel modules create node in
3211 * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates
3212 * only device nodes in /dev/dri/ */
3213 return (!strncmp(name
, "drm/", 4) || !strncmp(name
, "dri/", 4));
3215 return maj
== DRM_MAJOR
;
3219 drm_public
int drmGetNodeTypeFromFd(int fd
)
3224 if (fstat(fd
, &sbuf
))
3227 maj
= major(sbuf
.st_rdev
);
3228 min
= minor(sbuf
.st_rdev
);
3230 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
)) {
3235 type
= drmGetMinorType(maj
, min
);
3241 drm_public
int drmPrimeHandleToFD(int fd
, uint32_t handle
, uint32_t flags
,
3244 struct drm_prime_handle args
;
3249 args
.handle
= handle
;
3251 ret
= drmIoctl(fd
, DRM_IOCTL_PRIME_HANDLE_TO_FD
, &args
);
3255 *prime_fd
= args
.fd
;
3259 drm_public
int drmPrimeFDToHandle(int fd
, int prime_fd
, uint32_t *handle
)
3261 struct drm_prime_handle args
;
3266 ret
= drmIoctl(fd
, DRM_IOCTL_PRIME_FD_TO_HANDLE
, &args
);
3270 *handle
= args
.handle
;
3274 static char *drmGetMinorNameForFD(int fd
, int type
)
3280 const char *name
= drmGetMinorName(type
);
3282 char dev_name
[64], buf
[64];
3290 if (fstat(fd
, &sbuf
))
3293 maj
= major(sbuf
.st_rdev
);
3294 min
= minor(sbuf
.st_rdev
);
3296 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
))
3299 snprintf(buf
, sizeof(buf
), "/sys/dev/char/%d:%d/device/drm", maj
, min
);
3301 sysdir
= opendir(buf
);
3305 while ((ent
= readdir(sysdir
))) {
3306 if (strncmp(ent
->d_name
, name
, len
) == 0) {
3307 snprintf(dev_name
, sizeof(dev_name
), DRM_DIR_NAME
"/%s",
3311 return strdup(dev_name
);
3317 #elif defined(__FreeBSD__)
3319 char dname
[SPECNAMELEN
];
3321 char name
[SPECNAMELEN
];
3322 int id
, maj
, min
, nodetype
, i
;
3324 if (fstat(fd
, &sbuf
))
3327 maj
= major(sbuf
.st_rdev
);
3328 min
= minor(sbuf
.st_rdev
);
3330 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
))
3333 if (!devname_r(sbuf
.st_rdev
, S_IFCHR
, dname
, sizeof(dname
)))
3336 /* Handle both /dev/drm and /dev/dri
3337 * FreeBSD on amd64/i386/powerpc external kernel modules create node in
3338 * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates
3339 * only device nodes in /dev/dri/ */
3341 /* Get the node type represented by fd so we can deduce the target name */
3342 nodetype
= drmGetMinorType(maj
, min
);
3345 mname
= drmGetMinorName(type
);
3347 for (i
= 0; i
< SPECNAMELEN
; i
++) {
3348 if (isalpha(dname
[i
]) == 0 && dname
[i
] != '/')
3351 if (dname
[i
] == '\0')
3354 id
= (int)strtol(&dname
[i
], NULL
, 10);
3355 id
-= drmGetMinorBase(nodetype
);
3356 snprintf(name
, sizeof(name
), DRM_DIR_NAME
"/%s%d", mname
,
3357 id
+ drmGetMinorBase(type
));
3359 return strdup(name
);
3362 char buf
[PATH_MAX
+ 1];
3363 const char *dev_name
= drmGetDeviceName(type
);
3364 unsigned int maj
, min
;
3367 if (fstat(fd
, &sbuf
))
3370 maj
= major(sbuf
.st_rdev
);
3371 min
= minor(sbuf
.st_rdev
);
3373 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
))
3379 n
= snprintf(buf
, sizeof(buf
), dev_name
, DRM_DIR_NAME
, min
);
3380 if (n
== -1 || n
>= sizeof(buf
))
3387 drm_public
char *drmGetPrimaryDeviceNameFromFd(int fd
)
3389 return drmGetMinorNameForFD(fd
, DRM_NODE_PRIMARY
);
3392 drm_public
char *drmGetRenderDeviceNameFromFd(int fd
)
3394 return drmGetMinorNameForFD(fd
, DRM_NODE_RENDER
);
3398 static char * DRM_PRINTFLIKE(2, 3)
3399 sysfs_uevent_get(const char *path
, const char *fmt
, ...)
3401 char filename
[PATH_MAX
+ 1], *key
, *line
= NULL
, *value
= NULL
;
3402 size_t size
= 0, len
;
3408 num
= vasprintf(&key
, fmt
, ap
);
3412 snprintf(filename
, sizeof(filename
), "%s/uevent", path
);
3414 fp
= fopen(filename
, "r");
3420 while ((num
= getline(&line
, &size
, fp
)) >= 0) {
3421 if ((strncmp(line
, key
, len
) == 0) && (line
[len
] == '=')) {
3422 char *start
= line
+ len
+ 1, *end
= line
+ num
- 1;
3427 value
= strndup(start
, end
- start
);
3441 /* Little white lie to avoid major rework of the existing code */
3442 #define DRM_BUS_VIRTIO 0x10
3445 static int get_subsystem_type(const char *device_path
)
3447 char path
[PATH_MAX
+ 1] = "";
3448 char link
[PATH_MAX
+ 1] = "";
3454 { "/pci", DRM_BUS_PCI
},
3455 { "/usb", DRM_BUS_USB
},
3456 { "/platform", DRM_BUS_PLATFORM
},
3457 { "/spi", DRM_BUS_PLATFORM
},
3458 { "/host1x", DRM_BUS_HOST1X
},
3459 { "/virtio", DRM_BUS_VIRTIO
},
3462 strncpy(path
, device_path
, PATH_MAX
);
3463 strncat(path
, "/subsystem", PATH_MAX
);
3465 if (readlink(path
, link
, PATH_MAX
) < 0)
3468 name
= strrchr(link
, '/');
3472 for (unsigned i
= 0; i
< ARRAY_SIZE(bus_types
); i
++) {
3473 if (strncmp(name
, bus_types
[i
].name
, strlen(bus_types
[i
].name
)) == 0)
3474 return bus_types
[i
].bus_type
;
3481 static int drmParseSubsystemType(int maj
, int min
)
3484 char path
[PATH_MAX
+ 1] = "";
3485 char real_path
[PATH_MAX
+ 1] = "";
3488 snprintf(path
, sizeof(path
), "/sys/dev/char/%d:%d/device", maj
, min
);
3490 subsystem_type
= get_subsystem_type(path
);
3491 /* Try to get the parent (underlying) device type */
3492 if (subsystem_type
== DRM_BUS_VIRTIO
) {
3493 /* Assume virtio-pci on error */
3494 if (!realpath(path
, real_path
))
3495 return DRM_BUS_VIRTIO
;
3496 strncat(path
, "/..", PATH_MAX
);
3497 subsystem_type
= get_subsystem_type(path
);
3498 if (subsystem_type
< 0)
3499 return DRM_BUS_VIRTIO
;
3501 return subsystem_type
;
3502 #elif defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD__)
3505 #warning "Missing implementation of drmParseSubsystemType"
3512 get_pci_path(int maj
, int min
, char *pci_path
)
3514 char path
[PATH_MAX
+ 1], *term
;
3516 snprintf(path
, sizeof(path
), "/sys/dev/char/%d:%d/device", maj
, min
);
3517 if (!realpath(path
, pci_path
)) {
3518 strcpy(pci_path
, path
);
3522 term
= strrchr(pci_path
, '/');
3523 if (term
&& strncmp(term
, "/virtio", 7) == 0)
3529 static int get_sysctl_pci_bus_info(int maj
, int min
, drmPciBusInfoPtr info
)
3531 char dname
[SPECNAMELEN
];
3532 char sysctl_name
[16];
3533 char sysctl_val
[256];
3535 int id
, type
, nelem
;
3536 unsigned int rdev
, majmin
, domain
, bus
, dev
, func
;
3538 rdev
= makedev(maj
, min
);
3539 if (!devname_r(rdev
, S_IFCHR
, dname
, sizeof(dname
)))
3542 if (sscanf(dname
, "drm/%d\n", &id
) != 1)
3544 type
= drmGetMinorType(maj
, min
);
3548 /* BUG: This above section is iffy, since it mandates that a driver will
3549 * create both card and render node.
3550 * If it does not, the next DRM device will create card#X and
3551 * renderD#(128+X)-1.
3552 * This is a possibility in FreeBSD but for now there is no good way for
3553 * obtaining the info.
3556 case DRM_NODE_PRIMARY
:
3558 case DRM_NODE_CONTROL
:
3561 case DRM_NODE_RENDER
:
3568 if (snprintf(sysctl_name
, sizeof(sysctl_name
), "hw.dri.%d.busid", id
) <= 0)
3570 sysctl_len
= sizeof(sysctl_val
);
3571 if (sysctlbyname(sysctl_name
, sysctl_val
, &sysctl_len
, NULL
, 0))
3574 #define bus_fmt "pci:%04x:%02x:%02x.%u"
3576 nelem
= sscanf(sysctl_val
, bus_fmt
, &domain
, &bus
, &dev
, &func
);
3579 info
->domain
= domain
;
3588 static int drmParsePciBusInfo(int maj
, int min
, drmPciBusInfoPtr info
)
3591 unsigned int domain
, bus
, dev
, func
;
3592 char pci_path
[PATH_MAX
+ 1], *value
;
3595 get_pci_path(maj
, min
, pci_path
);
3597 value
= sysfs_uevent_get(pci_path
, "PCI_SLOT_NAME");
3601 num
= sscanf(value
, "%04x:%02x:%02x.%1u", &domain
, &bus
, &dev
, &func
);
3607 info
->domain
= domain
;
3613 #elif defined(__OpenBSD__) || defined(__DragonFly__)
3614 struct drm_pciinfo pinfo
;
3617 type
= drmGetMinorType(maj
, min
);
3621 fd
= drmOpenMinor(min
, 0, type
);
3625 if (drmIoctl(fd
, DRM_IOCTL_GET_PCIINFO
, &pinfo
)) {
3631 info
->domain
= pinfo
.domain
;
3632 info
->bus
= pinfo
.bus
;
3633 info
->dev
= pinfo
.dev
;
3634 info
->func
= pinfo
.func
;
3637 #elif defined(__FreeBSD__)
3638 return get_sysctl_pci_bus_info(maj
, min
, info
);
3640 #warning "Missing implementation of drmParsePciBusInfo"
3645 drm_public
int drmDevicesEqual(drmDevicePtr a
, drmDevicePtr b
)
3647 if (a
== NULL
|| b
== NULL
)
3650 if (a
->bustype
!= b
->bustype
)
3653 switch (a
->bustype
) {
3655 return memcmp(a
->businfo
.pci
, b
->businfo
.pci
, sizeof(drmPciBusInfo
)) == 0;
3658 return memcmp(a
->businfo
.usb
, b
->businfo
.usb
, sizeof(drmUsbBusInfo
)) == 0;
3660 case DRM_BUS_PLATFORM
:
3661 return memcmp(a
->businfo
.platform
, b
->businfo
.platform
, sizeof(drmPlatformBusInfo
)) == 0;
3663 case DRM_BUS_HOST1X
:
3664 return memcmp(a
->businfo
.host1x
, b
->businfo
.host1x
, sizeof(drmHost1xBusInfo
)) == 0;
3673 static int drmGetNodeType(const char *name
)
3675 if (strncmp(name
, DRM_CONTROL_MINOR_NAME
,
3676 sizeof(DRM_CONTROL_MINOR_NAME
) - 1) == 0)
3677 return DRM_NODE_CONTROL
;
3679 if (strncmp(name
, DRM_RENDER_MINOR_NAME
,
3680 sizeof(DRM_RENDER_MINOR_NAME
) - 1) == 0)
3681 return DRM_NODE_RENDER
;
3683 if (strncmp(name
, DRM_PRIMARY_MINOR_NAME
,
3684 sizeof(DRM_PRIMARY_MINOR_NAME
) - 1) == 0)
3685 return DRM_NODE_PRIMARY
;
3690 static int drmGetMaxNodeName(void)
3692 return sizeof(DRM_DIR_NAME
) +
3693 MAX3(sizeof(DRM_PRIMARY_MINOR_NAME
),
3694 sizeof(DRM_CONTROL_MINOR_NAME
),
3695 sizeof(DRM_RENDER_MINOR_NAME
)) +
3696 3 /* length of the node number */;
3700 static int parse_separate_sysfs_files(int maj
, int min
,
3701 drmPciDeviceInfoPtr device
,
3702 bool ignore_revision
)
3704 static const char *attrs
[] = {
3705 "revision", /* Older kernels are missing the file, so check for it first */
3711 char path
[PATH_MAX
+ 1], pci_path
[PATH_MAX
+ 1];
3712 unsigned int data
[ARRAY_SIZE(attrs
)];
3716 get_pci_path(maj
, min
, pci_path
);
3718 for (unsigned i
= ignore_revision
? 1 : 0; i
< ARRAY_SIZE(attrs
); i
++) {
3719 snprintf(path
, PATH_MAX
, "%s/%s", pci_path
, attrs
[i
]);
3720 fp
= fopen(path
, "r");
3724 ret
= fscanf(fp
, "%x", &data
[i
]);
3731 device
->revision_id
= ignore_revision
? 0xff : data
[0] & 0xff;
3732 device
->vendor_id
= data
[1] & 0xffff;
3733 device
->device_id
= data
[2] & 0xffff;
3734 device
->subvendor_id
= data
[3] & 0xffff;
3735 device
->subdevice_id
= data
[4] & 0xffff;
3740 static int parse_config_sysfs_file(int maj
, int min
,
3741 drmPciDeviceInfoPtr device
)
3743 char path
[PATH_MAX
+ 1], pci_path
[PATH_MAX
+ 1];
3744 unsigned char config
[64];
3747 get_pci_path(maj
, min
, pci_path
);
3749 snprintf(path
, PATH_MAX
, "%s/config", pci_path
);
3750 fd
= open(path
, O_RDONLY
);
3754 ret
= read(fd
, config
, sizeof(config
));
3759 device
->vendor_id
= config
[0] | (config
[1] << 8);
3760 device
->device_id
= config
[2] | (config
[3] << 8);
3761 device
->revision_id
= config
[8];
3762 device
->subvendor_id
= config
[44] | (config
[45] << 8);
3763 device
->subdevice_id
= config
[46] | (config
[47] << 8);
3769 static int drmParsePciDeviceInfo(int maj
, int min
,
3770 drmPciDeviceInfoPtr device
,
3774 if (!(flags
& DRM_DEVICE_GET_PCI_REVISION
))
3775 return parse_separate_sysfs_files(maj
, min
, device
, true);
3777 if (parse_separate_sysfs_files(maj
, min
, device
, false))
3778 return parse_config_sysfs_file(maj
, min
, device
);
3781 #elif defined(__OpenBSD__) || defined(__DragonFly__)
3782 struct drm_pciinfo pinfo
;
3785 type
= drmGetMinorType(maj
, min
);
3789 fd
= drmOpenMinor(min
, 0, type
);
3793 if (drmIoctl(fd
, DRM_IOCTL_GET_PCIINFO
, &pinfo
)) {
3799 device
->vendor_id
= pinfo
.vendor_id
;
3800 device
->device_id
= pinfo
.device_id
;
3801 device
->revision_id
= pinfo
.revision_id
;
3802 device
->subvendor_id
= pinfo
.subvendor_id
;
3803 device
->subdevice_id
= pinfo
.subdevice_id
;
3806 #elif defined(__FreeBSD__)
3808 struct pci_conf_io pc
;
3809 struct pci_match_conf patterns
[1];
3810 struct pci_conf results
[1];
3813 if (get_sysctl_pci_bus_info(maj
, min
, &info
) != 0)
3816 fd
= open("/dev/pci", O_RDONLY
, 0);
3820 bzero(&patterns
, sizeof(patterns
));
3821 patterns
[0].pc_sel
.pc_domain
= info
.domain
;
3822 patterns
[0].pc_sel
.pc_bus
= info
.bus
;
3823 patterns
[0].pc_sel
.pc_dev
= info
.dev
;
3824 patterns
[0].pc_sel
.pc_func
= info
.func
;
3825 patterns
[0].flags
= PCI_GETCONF_MATCH_DOMAIN
| PCI_GETCONF_MATCH_BUS
3826 | PCI_GETCONF_MATCH_DEV
| PCI_GETCONF_MATCH_FUNC
;
3827 bzero(&pc
, sizeof(struct pci_conf_io
));
3828 pc
.num_patterns
= 1;
3829 pc
.pat_buf_len
= sizeof(patterns
);
3830 pc
.patterns
= patterns
;
3831 pc
.match_buf_len
= sizeof(results
);
3832 pc
.matches
= results
;
3834 if (ioctl(fd
, PCIOCGETCONF
, &pc
) || pc
.status
== PCI_GETCONF_ERROR
) {
3841 device
->vendor_id
= results
[0].pc_vendor
;
3842 device
->device_id
= results
[0].pc_device
;
3843 device
->subvendor_id
= results
[0].pc_subvendor
;
3844 device
->subdevice_id
= results
[0].pc_subdevice
;
3845 device
->revision_id
= results
[0].pc_revid
;
3849 #warning "Missing implementation of drmParsePciDeviceInfo"
3854 static void drmFreePlatformDevice(drmDevicePtr device
)
3856 if (device
->deviceinfo
.platform
) {
3857 if (device
->deviceinfo
.platform
->compatible
) {
3858 char **compatible
= device
->deviceinfo
.platform
->compatible
;
3860 while (*compatible
) {
3865 free(device
->deviceinfo
.platform
->compatible
);
3870 static void drmFreeHost1xDevice(drmDevicePtr device
)
3872 if (device
->deviceinfo
.host1x
) {
3873 if (device
->deviceinfo
.host1x
->compatible
) {
3874 char **compatible
= device
->deviceinfo
.host1x
->compatible
;
3876 while (*compatible
) {
3881 free(device
->deviceinfo
.host1x
->compatible
);
3886 drm_public
void drmFreeDevice(drmDevicePtr
*device
)
3892 switch ((*device
)->bustype
) {
3893 case DRM_BUS_PLATFORM
:
3894 drmFreePlatformDevice(*device
);
3897 case DRM_BUS_HOST1X
:
3898 drmFreeHost1xDevice(*device
);
3907 drm_public
void drmFreeDevices(drmDevicePtr devices
[], int count
)
3911 if (devices
== NULL
)
3914 for (i
= 0; i
< count
; i
++)
3916 drmFreeDevice(&devices
[i
]);
3919 static drmDevicePtr
drmDeviceAlloc(unsigned int type
, const char *node
,
3920 size_t bus_size
, size_t device_size
,
3923 size_t max_node_length
, extra
, size
;
3924 drmDevicePtr device
;
3928 max_node_length
= ALIGN(drmGetMaxNodeName(), sizeof(void *));
3929 extra
= DRM_NODE_MAX
* (sizeof(void *) + max_node_length
);
3931 size
= sizeof(*device
) + extra
+ bus_size
+ device_size
;
3933 device
= calloc(1, size
);
3937 device
->available_nodes
= 1 << type
;
3939 ptr
= (char *)device
+ sizeof(*device
);
3940 device
->nodes
= (char **)ptr
;
3942 ptr
+= DRM_NODE_MAX
* sizeof(void *);
3944 for (i
= 0; i
< DRM_NODE_MAX
; i
++) {
3945 device
->nodes
[i
] = ptr
;
3946 ptr
+= max_node_length
;
3949 memcpy(device
->nodes
[type
], node
, max_node_length
);
3956 static int drmProcessPciDevice(drmDevicePtr
*device
,
3957 const char *node
, int node_type
,
3958 int maj
, int min
, bool fetch_deviceinfo
,
3965 dev
= drmDeviceAlloc(node_type
, node
, sizeof(drmPciBusInfo
),
3966 sizeof(drmPciDeviceInfo
), &addr
);
3970 dev
->bustype
= DRM_BUS_PCI
;
3972 dev
->businfo
.pci
= (drmPciBusInfoPtr
)addr
;
3974 ret
= drmParsePciBusInfo(maj
, min
, dev
->businfo
.pci
);
3978 // Fetch the device info if the user has requested it
3979 if (fetch_deviceinfo
) {
3980 addr
+= sizeof(drmPciBusInfo
);
3981 dev
->deviceinfo
.pci
= (drmPciDeviceInfoPtr
)addr
;
3983 ret
= drmParsePciDeviceInfo(maj
, min
, dev
->deviceinfo
.pci
, flags
);
3998 static int drm_usb_dev_path(int maj
, int min
, char *path
, size_t len
)
4000 char *value
, *tmp_path
, *slash
;
4002 snprintf(path
, len
, "/sys/dev/char/%d:%d/device", maj
, min
);
4004 value
= sysfs_uevent_get(path
, "DEVTYPE");
4008 if (strcmp(value
, "usb_device") == 0)
4010 if (strcmp(value
, "usb_interface") != 0)
4013 /* The parent of a usb_interface is a usb_device */
4015 tmp_path
= realpath(path
, NULL
);
4019 slash
= strrchr(tmp_path
, '/');
4027 if (snprintf(path
, len
, "%s", tmp_path
) >= (int)len
) {
4037 static int drmParseUsbBusInfo(int maj
, int min
, drmUsbBusInfoPtr info
)
4040 char path
[PATH_MAX
+ 1], *value
;
4041 unsigned int bus
, dev
;
4044 ret
= drm_usb_dev_path(maj
, min
, path
, sizeof(path
));
4048 value
= sysfs_uevent_get(path
, "BUSNUM");
4052 ret
= sscanf(value
, "%03u", &bus
);
4058 value
= sysfs_uevent_get(path
, "DEVNUM");
4062 ret
= sscanf(value
, "%03u", &dev
);
4073 #warning "Missing implementation of drmParseUsbBusInfo"
4078 static int drmParseUsbDeviceInfo(int maj
, int min
, drmUsbDeviceInfoPtr info
)
4081 char path
[PATH_MAX
+ 1], *value
;
4082 unsigned int vendor
, product
;
4085 ret
= drm_usb_dev_path(maj
, min
, path
, sizeof(path
));
4089 value
= sysfs_uevent_get(path
, "PRODUCT");
4093 ret
= sscanf(value
, "%x/%x", &vendor
, &product
);
4099 info
->vendor
= vendor
;
4100 info
->product
= product
;
4104 #warning "Missing implementation of drmParseUsbDeviceInfo"
4109 static int drmProcessUsbDevice(drmDevicePtr
*device
, const char *node
,
4110 int node_type
, int maj
, int min
,
4111 bool fetch_deviceinfo
, uint32_t flags
)
4117 dev
= drmDeviceAlloc(node_type
, node
, sizeof(drmUsbBusInfo
),
4118 sizeof(drmUsbDeviceInfo
), &ptr
);
4122 dev
->bustype
= DRM_BUS_USB
;
4124 dev
->businfo
.usb
= (drmUsbBusInfoPtr
)ptr
;
4126 ret
= drmParseUsbBusInfo(maj
, min
, dev
->businfo
.usb
);
4130 if (fetch_deviceinfo
) {
4131 ptr
+= sizeof(drmUsbBusInfo
);
4132 dev
->deviceinfo
.usb
= (drmUsbDeviceInfoPtr
)ptr
;
4134 ret
= drmParseUsbDeviceInfo(maj
, min
, dev
->deviceinfo
.usb
);
4148 static int drmParseOFBusInfo(int maj
, int min
, char *fullname
)
4151 char path
[PATH_MAX
+ 1], *name
, *tmp_name
;
4153 snprintf(path
, sizeof(path
), "/sys/dev/char/%d:%d/device", maj
, min
);
4155 name
= sysfs_uevent_get(path
, "OF_FULLNAME");
4158 /* If the device lacks OF data, pick the MODALIAS info */
4159 name
= sysfs_uevent_get(path
, "MODALIAS");
4163 /* .. and strip the MODALIAS=[platform,usb...]: part. */
4164 tmp_name
= strrchr(name
, ':');
4172 strncpy(fullname
, tmp_name
, DRM_PLATFORM_DEVICE_NAME_LEN
);
4173 fullname
[DRM_PLATFORM_DEVICE_NAME_LEN
- 1] = '\0';
4178 #warning "Missing implementation of drmParseOFBusInfo"
4183 static int drmParseOFDeviceInfo(int maj
, int min
, char ***compatible
)
4186 char path
[PATH_MAX
+ 1], *value
, *tmp_name
;
4187 unsigned int count
, i
;
4190 snprintf(path
, sizeof(path
), "/sys/dev/char/%d:%d/device", maj
, min
);
4192 value
= sysfs_uevent_get(path
, "OF_COMPATIBLE_N");
4194 sscanf(value
, "%u", &count
);
4197 /* Assume one entry if the device lack OF data */
4201 *compatible
= calloc(count
+ 1, sizeof(char *));
4205 for (i
= 0; i
< count
; i
++) {
4206 value
= sysfs_uevent_get(path
, "OF_COMPATIBLE_%u", i
);
4209 /* If the device lacks OF data, pick the MODALIAS info */
4210 value
= sysfs_uevent_get(path
, "MODALIAS");
4216 /* .. and strip the MODALIAS=[platform,usb...]: part. */
4217 tmp_name
= strrchr(value
, ':');
4222 tmp_name
= strdup(tmp_name
+ 1);
4226 (*compatible
)[i
] = tmp_name
;
4233 free((*compatible
)[i
]);
4238 #warning "Missing implementation of drmParseOFDeviceInfo"
4243 static int drmProcessPlatformDevice(drmDevicePtr
*device
,
4244 const char *node
, int node_type
,
4245 int maj
, int min
, bool fetch_deviceinfo
,
4252 dev
= drmDeviceAlloc(node_type
, node
, sizeof(drmPlatformBusInfo
),
4253 sizeof(drmPlatformDeviceInfo
), &ptr
);
4257 dev
->bustype
= DRM_BUS_PLATFORM
;
4259 dev
->businfo
.platform
= (drmPlatformBusInfoPtr
)ptr
;
4261 ret
= drmParseOFBusInfo(maj
, min
, dev
->businfo
.platform
->fullname
);
4265 if (fetch_deviceinfo
) {
4266 ptr
+= sizeof(drmPlatformBusInfo
);
4267 dev
->deviceinfo
.platform
= (drmPlatformDeviceInfoPtr
)ptr
;
4269 ret
= drmParseOFDeviceInfo(maj
, min
, &dev
->deviceinfo
.platform
->compatible
);
4283 static int drmProcessHost1xDevice(drmDevicePtr
*device
,
4284 const char *node
, int node_type
,
4285 int maj
, int min
, bool fetch_deviceinfo
,
4292 dev
= drmDeviceAlloc(node_type
, node
, sizeof(drmHost1xBusInfo
),
4293 sizeof(drmHost1xDeviceInfo
), &ptr
);
4297 dev
->bustype
= DRM_BUS_HOST1X
;
4299 dev
->businfo
.host1x
= (drmHost1xBusInfoPtr
)ptr
;
4301 ret
= drmParseOFBusInfo(maj
, min
, dev
->businfo
.host1x
->fullname
);
4305 if (fetch_deviceinfo
) {
4306 ptr
+= sizeof(drmHost1xBusInfo
);
4307 dev
->deviceinfo
.host1x
= (drmHost1xDeviceInfoPtr
)ptr
;
4309 ret
= drmParseOFDeviceInfo(maj
, min
, &dev
->deviceinfo
.host1x
->compatible
);
4324 process_device(drmDevicePtr
*device
, const char *d_name
,
4325 int req_subsystem_type
,
4326 bool fetch_deviceinfo
, uint32_t flags
)
4329 char node
[PATH_MAX
+ 1];
4330 int node_type
, subsystem_type
;
4331 unsigned int maj
, min
;
4333 node_type
= drmGetNodeType(d_name
);
4337 snprintf(node
, PATH_MAX
, "%s/%s", DRM_DIR_NAME
, d_name
);
4338 if (stat(node
, &sbuf
))
4341 maj
= major(sbuf
.st_rdev
);
4342 min
= minor(sbuf
.st_rdev
);
4344 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
))
4347 subsystem_type
= drmParseSubsystemType(maj
, min
);
4348 if (req_subsystem_type
!= -1 && req_subsystem_type
!= subsystem_type
)
4351 switch (subsystem_type
) {
4353 case DRM_BUS_VIRTIO
:
4354 return drmProcessPciDevice(device
, node
, node_type
, maj
, min
,
4355 fetch_deviceinfo
, flags
);
4357 return drmProcessUsbDevice(device
, node
, node_type
, maj
, min
,
4358 fetch_deviceinfo
, flags
);
4359 case DRM_BUS_PLATFORM
:
4360 return drmProcessPlatformDevice(device
, node
, node_type
, maj
, min
,
4361 fetch_deviceinfo
, flags
);
4362 case DRM_BUS_HOST1X
:
4363 return drmProcessHost1xDevice(device
, node
, node_type
, maj
, min
,
4364 fetch_deviceinfo
, flags
);
4370 /* Consider devices located on the same bus as duplicate and fold the respective
4371 * entries into a single one.
4373 * Note: this leaves "gaps" in the array, while preserving the length.
4375 static void drmFoldDuplicatedDevices(drmDevicePtr local_devices
[], int count
)
4377 int node_type
, i
, j
;
4379 for (i
= 0; i
< count
; i
++) {
4380 for (j
= i
+ 1; j
< count
; j
++) {
4381 if (drmDevicesEqual(local_devices
[i
], local_devices
[j
])) {
4382 local_devices
[i
]->available_nodes
|= local_devices
[j
]->available_nodes
;
4383 node_type
= log2_int(local_devices
[j
]->available_nodes
);
4384 memcpy(local_devices
[i
]->nodes
[node_type
],
4385 local_devices
[j
]->nodes
[node_type
], drmGetMaxNodeName());
4386 drmFreeDevice(&local_devices
[j
]);
4392 /* Check that the given flags are valid returning 0 on success */
4394 drm_device_validate_flags(uint32_t flags
)
4396 return (flags
& ~DRM_DEVICE_GET_PCI_REVISION
);
4400 drm_device_has_rdev(drmDevicePtr device
, dev_t find_rdev
)
4404 for (int i
= 0; i
< DRM_NODE_MAX
; i
++) {
4405 if (device
->available_nodes
& 1 << i
) {
4406 if (stat(device
->nodes
[i
], &sbuf
) == 0 &&
4407 sbuf
.st_rdev
== find_rdev
)
4415 * The kernel drm core has a number of places that assume maximum of
4416 * 3x64 devices nodes. That's 64 for each of primary, control and
4417 * render nodes. Rounded it up to 256 for simplicity.
4419 #define MAX_DRM_NODES 256
4422 * Get information about the opened drm device
4424 * \param fd file descriptor of the drm device
4425 * \param flags feature/behaviour bitmask
4426 * \param device the address of a drmDevicePtr where the information
4427 * will be allocated in stored
4429 * \return zero on success, negative error code otherwise.
4431 * \note Unlike drmGetDevice it does not retrieve the pci device revision field
4432 * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
4434 drm_public
int drmGetDevice2(int fd
, uint32_t flags
, drmDevicePtr
*device
)
4438 * DRI device nodes on OpenBSD are not in their own directory, they reside
4439 * in /dev along with a large number of statically generated /dev nodes.
4440 * Avoid stat'ing all of /dev needlessly by implementing this custom path.
4444 char node
[PATH_MAX
+ 1];
4445 const char *dev_name
;
4446 int node_type
, subsystem_type
;
4447 int maj
, min
, n
, ret
;
4449 if (fd
== -1 || device
== NULL
)
4452 if (fstat(fd
, &sbuf
))
4455 maj
= major(sbuf
.st_rdev
);
4456 min
= minor(sbuf
.st_rdev
);
4458 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
))
4461 node_type
= drmGetMinorType(maj
, min
);
4462 if (node_type
== -1)
4465 dev_name
= drmGetDeviceName(node_type
);
4469 n
= snprintf(node
, PATH_MAX
, dev_name
, DRM_DIR_NAME
, min
);
4470 if (n
== -1 || n
>= PATH_MAX
)
4472 if (stat(node
, &sbuf
))
4475 subsystem_type
= drmParseSubsystemType(maj
, min
);
4476 if (subsystem_type
!= DRM_BUS_PCI
)
4479 ret
= drmProcessPciDevice(&d
, node
, node_type
, maj
, min
, true, flags
);
4487 drmDevicePtr local_devices
[MAX_DRM_NODES
];
4490 struct dirent
*dent
;
4494 int ret
, i
, node_count
;
4497 if (drm_device_validate_flags(flags
))
4500 if (fd
== -1 || device
== NULL
)
4503 if (fstat(fd
, &sbuf
))
4506 find_rdev
= sbuf
.st_rdev
;
4507 maj
= major(sbuf
.st_rdev
);
4508 min
= minor(sbuf
.st_rdev
);
4510 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
))
4513 subsystem_type
= drmParseSubsystemType(maj
, min
);
4514 if (subsystem_type
< 0)
4515 return subsystem_type
;
4517 sysdir
= opendir(DRM_DIR_NAME
);
4522 while ((dent
= readdir(sysdir
))) {
4523 ret
= process_device(&d
, dent
->d_name
, subsystem_type
, true, flags
);
4527 if (i
>= MAX_DRM_NODES
) {
4528 fprintf(stderr
, "More than %d drm nodes detected. "
4529 "Please report a bug - that should not happen.\n"
4530 "Skipping extra nodes\n", MAX_DRM_NODES
);
4533 local_devices
[i
] = d
;
4538 drmFoldDuplicatedDevices(local_devices
, node_count
);
4542 for (i
= 0; i
< node_count
; i
++) {
4543 if (!local_devices
[i
])
4546 if (drm_device_has_rdev(local_devices
[i
], find_rdev
))
4547 *device
= local_devices
[i
];
4549 drmFreeDevice(&local_devices
[i
]);
4553 if (*device
== NULL
)
4560 * Get information about the opened drm device
4562 * \param fd file descriptor of the drm device
4563 * \param device the address of a drmDevicePtr where the information
4564 * will be allocated in stored
4566 * \return zero on success, negative error code otherwise.
4568 drm_public
int drmGetDevice(int fd
, drmDevicePtr
*device
)
4570 return drmGetDevice2(fd
, DRM_DEVICE_GET_PCI_REVISION
, device
);
4574 * Get drm devices on the system
4576 * \param flags feature/behaviour bitmask
4577 * \param devices the array of devices with drmDevicePtr elements
4578 * can be NULL to get the device number first
4579 * \param max_devices the maximum number of devices for the array
4581 * \return on error - negative error code,
4582 * if devices is NULL - total number of devices available on the system,
4583 * alternatively the number of devices stored in devices[], which is
4584 * capped by the max_devices.
4586 * \note Unlike drmGetDevices it does not retrieve the pci device revision field
4587 * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
4589 drm_public
int drmGetDevices2(uint32_t flags
, drmDevicePtr devices
[],
4592 drmDevicePtr local_devices
[MAX_DRM_NODES
];
4593 drmDevicePtr device
;
4595 struct dirent
*dent
;
4596 int ret
, i
, node_count
, device_count
;
4598 if (drm_device_validate_flags(flags
))
4601 sysdir
= opendir(DRM_DIR_NAME
);
4606 while ((dent
= readdir(sysdir
))) {
4607 ret
= process_device(&device
, dent
->d_name
, -1, devices
!= NULL
, flags
);
4611 if (i
>= MAX_DRM_NODES
) {
4612 fprintf(stderr
, "More than %d drm nodes detected. "
4613 "Please report a bug - that should not happen.\n"
4614 "Skipping extra nodes\n", MAX_DRM_NODES
);
4617 local_devices
[i
] = device
;
4622 drmFoldDuplicatedDevices(local_devices
, node_count
);
4625 for (i
= 0; i
< node_count
; i
++) {
4626 if (!local_devices
[i
])
4629 if ((devices
!= NULL
) && (device_count
< max_devices
))
4630 devices
[device_count
] = local_devices
[i
];
4632 drmFreeDevice(&local_devices
[i
]);
4639 if (devices
!= NULL
)
4640 return MIN2(device_count
, max_devices
);
4642 return device_count
;
4646 * Get drm devices on the system
4648 * \param devices the array of devices with drmDevicePtr elements
4649 * can be NULL to get the device number first
4650 * \param max_devices the maximum number of devices for the array
4652 * \return on error - negative error code,
4653 * if devices is NULL - total number of devices available on the system,
4654 * alternatively the number of devices stored in devices[], which is
4655 * capped by the max_devices.
4657 drm_public
int drmGetDevices(drmDevicePtr devices
[], int max_devices
)
4659 return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION
, devices
, max_devices
);
4662 drm_public
char *drmGetDeviceNameFromFd2(int fd
)
4666 char path
[PATH_MAX
+ 1], *value
;
4667 unsigned int maj
, min
;
4669 if (fstat(fd
, &sbuf
))
4672 maj
= major(sbuf
.st_rdev
);
4673 min
= minor(sbuf
.st_rdev
);
4675 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
))
4678 snprintf(path
, sizeof(path
), "/sys/dev/char/%d:%d", maj
, min
);
4680 value
= sysfs_uevent_get(path
, "DEVNAME");
4684 snprintf(path
, sizeof(path
), "/dev/%s", value
);
4687 return strdup(path
);
4688 #elif defined(__FreeBSD__)
4689 return drmGetDeviceNameFromFd(fd
);
4692 char node
[PATH_MAX
+ 1];
4693 const char *dev_name
;
4697 if (fstat(fd
, &sbuf
))
4700 maj
= major(sbuf
.st_rdev
);
4701 min
= minor(sbuf
.st_rdev
);
4703 if (!drmNodeIsDRM(maj
, min
) || !S_ISCHR(sbuf
.st_mode
))
4706 node_type
= drmGetMinorType(maj
, min
);
4707 if (node_type
== -1)
4710 dev_name
= drmGetDeviceName(node_type
);
4714 n
= snprintf(node
, PATH_MAX
, dev_name
, DRM_DIR_NAME
, min
);
4715 if (n
== -1 || n
>= PATH_MAX
)
4718 return strdup(node
);
4722 drm_public
int drmSyncobjCreate(int fd
, uint32_t flags
, uint32_t *handle
)
4724 struct drm_syncobj_create args
;
4730 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_CREATE
, &args
);
4733 *handle
= args
.handle
;
4737 drm_public
int drmSyncobjDestroy(int fd
, uint32_t handle
)
4739 struct drm_syncobj_destroy args
;
4742 args
.handle
= handle
;
4743 return drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_DESTROY
, &args
);
4746 drm_public
int drmSyncobjHandleToFD(int fd
, uint32_t handle
, int *obj_fd
)
4748 struct drm_syncobj_handle args
;
4753 args
.handle
= handle
;
4754 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD
, &args
);
4761 drm_public
int drmSyncobjFDToHandle(int fd
, int obj_fd
, uint32_t *handle
)
4763 struct drm_syncobj_handle args
;
4769 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE
, &args
);
4772 *handle
= args
.handle
;
4776 drm_public
int drmSyncobjImportSyncFile(int fd
, uint32_t handle
,
4779 struct drm_syncobj_handle args
;
4782 args
.fd
= sync_file_fd
;
4783 args
.handle
= handle
;
4784 args
.flags
= DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE
;
4785 return drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE
, &args
);
4788 drm_public
int drmSyncobjExportSyncFile(int fd
, uint32_t handle
,
4791 struct drm_syncobj_handle args
;
4796 args
.handle
= handle
;
4797 args
.flags
= DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE
;
4798 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD
, &args
);
4801 *sync_file_fd
= args
.fd
;
4805 drm_public
int drmSyncobjWait(int fd
, uint32_t *handles
, unsigned num_handles
,
4806 int64_t timeout_nsec
, unsigned flags
,
4807 uint32_t *first_signaled
)
4809 struct drm_syncobj_wait args
;
4813 args
.handles
= (uintptr_t)handles
;
4814 args
.timeout_nsec
= timeout_nsec
;
4815 args
.count_handles
= num_handles
;
4818 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_WAIT
, &args
);
4823 *first_signaled
= args
.first_signaled
;
4827 drm_public
int drmSyncobjReset(int fd
, const uint32_t *handles
,
4828 uint32_t handle_count
)
4830 struct drm_syncobj_array args
;
4834 args
.handles
= (uintptr_t)handles
;
4835 args
.count_handles
= handle_count
;
4837 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_RESET
, &args
);
4841 drm_public
int drmSyncobjSignal(int fd
, const uint32_t *handles
,
4842 uint32_t handle_count
)
4844 struct drm_syncobj_array args
;
4848 args
.handles
= (uintptr_t)handles
;
4849 args
.count_handles
= handle_count
;
4851 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_SIGNAL
, &args
);
4855 drm_public
int drmSyncobjTimelineSignal(int fd
, const uint32_t *handles
,
4856 uint64_t *points
, uint32_t handle_count
)
4858 struct drm_syncobj_timeline_array args
;
4862 args
.handles
= (uintptr_t)handles
;
4863 args
.points
= (uintptr_t)points
;
4864 args
.count_handles
= handle_count
;
4866 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL
, &args
);
4870 drm_public
int drmSyncobjTimelineWait(int fd
, uint32_t *handles
, uint64_t *points
,
4871 unsigned num_handles
,
4872 int64_t timeout_nsec
, unsigned flags
,
4873 uint32_t *first_signaled
)
4875 struct drm_syncobj_timeline_wait args
;
4879 args
.handles
= (uintptr_t)handles
;
4880 args
.points
= (uintptr_t)points
;
4881 args
.timeout_nsec
= timeout_nsec
;
4882 args
.count_handles
= num_handles
;
4885 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT
, &args
);
4890 *first_signaled
= args
.first_signaled
;
4895 drm_public
int drmSyncobjQuery(int fd
, uint32_t *handles
, uint64_t *points
,
4896 uint32_t handle_count
)
4898 struct drm_syncobj_timeline_array args
;
4902 args
.handles
= (uintptr_t)handles
;
4903 args
.points
= (uintptr_t)points
;
4904 args
.count_handles
= handle_count
;
4906 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_QUERY
, &args
);
4912 drm_public
int drmSyncobjQuery2(int fd
, uint32_t *handles
, uint64_t *points
,
4913 uint32_t handle_count
, uint32_t flags
)
4915 struct drm_syncobj_timeline_array args
;
4918 args
.handles
= (uintptr_t)handles
;
4919 args
.points
= (uintptr_t)points
;
4920 args
.count_handles
= handle_count
;
4923 return drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_QUERY
, &args
);
4927 drm_public
int drmSyncobjTransfer(int fd
,
4928 uint32_t dst_handle
, uint64_t dst_point
,
4929 uint32_t src_handle
, uint64_t src_point
,
4932 struct drm_syncobj_transfer args
;
4936 args
.src_handle
= src_handle
;
4937 args
.dst_handle
= dst_handle
;
4938 args
.src_point
= src_point
;
4939 args
.dst_point
= dst_point
;
4942 ret
= drmIoctl(fd
, DRM_IOCTL_SYNCOBJ_TRANSFER
, &args
);
4948 drmGetFormatModifierFromSimpleTokens(uint64_t modifier
)
4952 for (i
= 0; i
< ARRAY_SIZE(drm_format_modifier_table
); i
++) {
4953 if (drm_format_modifier_table
[i
].modifier
== modifier
)
4954 return strdup(drm_format_modifier_table
[i
].modifier_name
);
4960 /** Retrieves a human-readable representation of a vendor (as a string) from
4961 * the format token modifier
4963 * \param modifier the format modifier token
4964 * \return a char pointer to the human-readable form of the vendor. Caller is
4965 * responsible for freeing it.
4968 drmGetFormatModifierVendor(uint64_t modifier
)
4971 uint8_t vendor
= fourcc_mod_get_vendor(modifier
);
4973 for (i
= 0; i
< ARRAY_SIZE(drm_format_modifier_vendor_table
); i
++) {
4974 if (drm_format_modifier_vendor_table
[i
].vendor
== vendor
)
4975 return strdup(drm_format_modifier_vendor_table
[i
].vendor_name
);
4981 /** Retrieves a human-readable representation string from a format token
4984 * If the dedicated function was not able to extract a valid name or searching
4985 * the format modifier was not in the table, this function would return NULL.
4987 * \param modifier the token format
4988 * \return a malloc'ed string representation of the modifier. Caller is
4989 * responsible for freeing the string returned.
4993 drmGetFormatModifierName(uint64_t modifier
)
4995 uint8_t vendorid
= fourcc_mod_get_vendor(modifier
);
4996 char *modifier_found
= NULL
;
4999 for (i
= 0; i
< ARRAY_SIZE(modifier_format_vendor_table
); i
++) {
5000 if (modifier_format_vendor_table
[i
].vendor
== vendorid
)
5001 modifier_found
= modifier_format_vendor_table
[i
].vendor_cb(modifier
);
5004 if (!modifier_found
)
5005 return drmGetFormatModifierFromSimpleTokens(modifier
);
5007 return modifier_found
;