# Copyright 2015 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

include <uapi/asm/ioctl.h>
include <uapi/linux/fcntl.h>
include <uapi/drm/drm.h>
include <uapi/drm/drm_mode.h>
include <uapi/drm/drm_fourcc.h>
include <linux/agp_backend.h>

resource fd_dri[fd]
resource drmctx[int32]
resource drm_agp_handle[intptr]
resource drm_gem_handle[int32]
resource drm_gem_name[int32]
resource drm_obj_id[int32]
resource drm_crtc_id[drm_obj_id]
resource drm_connector_id[drm_obj_id]
resource drm_fb_id[drm_obj_id]

syz_open_dev$dri(dev ptr[in, string["/dev/dri/card#"]], id intptr, flags flags[open_flags]) fd_dri
syz_open_dev$dricontrol(dev ptr[in, string["/dev/dri/controlD#"]], id intptr, flags flags[open_flags]) fd_dri
syz_open_dev$drirender(dev ptr[in, string["/dev/dri/renderD#"]], id intptr, flags flags[open_flags]) fd_dri
openat$drirender128(fd const[AT_FDCWD], file ptr[in, string["/dev/dri/renderD128"]], flags flags[open_flags], mode const[0]) fd_dri

ioctl$DRM_IOCTL_VERSION(fd fd_dri, cmd const[DRM_IOCTL_VERSION], arg ptr[inout, drm_version])
ioctl$DRM_IOCTL_GET_UNIQUE(fd fd_dri, cmd const[DRM_IOCTL_GET_UNIQUE], arg ptr[in, drm_unique$out])
ioctl$DRM_IOCTL_GET_MAGIC(fd fd_dri, cmd const[DRM_IOCTL_GET_MAGIC], arg ptr[in, int32])
ioctl$DRM_IOCTL_IRQ_BUSID(fd fd_dri, cmd const[DRM_IOCTL_IRQ_BUSID], arg ptr[inout, drm_irq_busid])
ioctl$DRM_IOCTL_GET_MAP(fd fd_dri, cmd const[DRM_IOCTL_GET_MAP], arg ptr[inout, drm_map$DRM_IOCTL_GET_MAP])
ioctl$DRM_IOCTL_GET_CLIENT(fd fd_dri, cmd const[DRM_IOCTL_GET_CLIENT], arg ptr[inout, drm_client])
ioctl$DRM_IOCTL_GET_STATS(fd fd_dri, cmd const[DRM_IOCTL_GET_STATS], arg buffer[out])
ioctl$DRM_IOCTL_GET_CAP(fd fd_dri, cmd const[DRM_IOCTL_GET_CAP], arg ptr[in, drm_get_cap])
ioctl$DRM_IOCTL_SET_CLIENT_CAP(fd fd_dri, cmd const[DRM_IOCTL_SET_CLIENT_CAP], arg ptr[in, drm_get_cap])
ioctl$DRM_IOCTL_SET_VERSION(fd fd_dri, cmd const[DRM_IOCTL_SET_VERSION], arg ptr[in, drm_set_version])
ioctl$DRM_IOCTL_SET_UNIQUE(fd fd_dri, cmd const[DRM_IOCTL_SET_UNIQUE], arg ptr[in, drm_unique$in])
ioctl$DRM_IOCTL_AUTH_MAGIC(fd fd_dri, cmd const[DRM_IOCTL_AUTH_MAGIC], arg ptr[in, int32])
ioctl$DRM_IOCTL_ADD_MAP(fd fd_dri, cmd const[DRM_IOCTL_ADD_MAP], arg ptr[inout, drm_map$DRM_IOCTL_ADD_MAP])
ioctl$DRM_IOCTL_RM_MAP(fd fd_dri, cmd const[DRM_IOCTL_RM_MAP], arg ptr[in, drm_map$DRM_IOCTL_RM_MAP])
ioctl$DRM_IOCTL_SET_SAREA_CTX(fd fd_dri, cmd const[DRM_IOCTL_SET_SAREA_CTX], arg ptr[in, drm_ctx_priv_map])
ioctl$DRM_IOCTL_GET_SAREA_CTX(fd fd_dri, cmd const[DRM_IOCTL_GET_SAREA_CTX], arg ptr[in, drm_ctx_priv_map])
ioctl$DRM_IOCTL_SET_MASTER(fd fd_dri, cmd const[DRM_IOCTL_SET_MASTER])
ioctl$DRM_IOCTL_DROP_MASTER(fd fd_dri, cmd const[DRM_IOCTL_DROP_MASTER])
ioctl$DRM_IOCTL_ADD_CTX(fd fd_dri, cmd const[DRM_IOCTL_ADD_CTX], arg ptr[out, drm_ctx])
ioctl$DRM_IOCTL_RM_CTX(fd fd_dri, cmd const[DRM_IOCTL_RM_CTX], arg ptr[in, drm_ctx])
ioctl$DRM_IOCTL_GET_CTX(fd fd_dri, cmd const[DRM_IOCTL_GET_CTX], arg ptr[in, drm_ctx])
ioctl$DRM_IOCTL_SWITCH_CTX(fd fd_dri, cmd const[DRM_IOCTL_SWITCH_CTX], arg ptr[in, drm_ctx])
ioctl$DRM_IOCTL_NEW_CTX(fd fd_dri, cmd const[DRM_IOCTL_NEW_CTX], arg ptr[in, drm_ctx])
ioctl$DRM_IOCTL_RES_CTX(fd fd_dri, cmd const[DRM_IOCTL_RES_CTX], arg ptr[in, drm_ctx_res])
ioctl$DRM_IOCTL_LOCK(fd fd_dri, cmd const[DRM_IOCTL_LOCK], arg ptr[in, drm_lock])
ioctl$DRM_IOCTL_UNLOCK(fd fd_dri, cmd const[DRM_IOCTL_UNLOCK], arg ptr[in, drm_lock])
ioctl$DRM_IOCTL_ADD_BUFS(fd fd_dri, cmd const[DRM_IOCTL_ADD_BUFS], arg ptr[in, drm_buf_desc])
ioctl$DRM_IOCTL_MARK_BUFS(fd fd_dri, cmd const[DRM_IOCTL_MARK_BUFS], arg ptr[in, drm_buf_desc])
ioctl$DRM_IOCTL_INFO_BUFS(fd fd_dri, cmd const[DRM_IOCTL_INFO_BUFS], arg ptr[in, drm_buf_desc])
ioctl$DRM_IOCTL_MAP_BUFS(fd fd_dri, cmd const[DRM_IOCTL_MAP_BUFS], arg ptr[in, drm_buf_map])
ioctl$DRM_IOCTL_FREE_BUFS(fd fd_dri, cmd const[DRM_IOCTL_FREE_BUFS], arg ptr[in, drm_buf_free])
ioctl$DRM_IOCTL_DMA(fd fd_dri, cmd const[DRM_IOCTL_DMA], arg ptr[in, drm_dma])
ioctl$DRM_IOCTL_CONTROL(fd fd_dri, cmd const[DRM_IOCTL_CONTROL], arg ptr[in, drm_control])
ioctl$DRM_IOCTL_AGP_ACQUIRE(fd fd_dri, cmd const[DRM_IOCTL_AGP_ACQUIRE])
ioctl$DRM_IOCTL_AGP_RELEASE(fd fd_dri, cmd const[DRM_IOCTL_AGP_RELEASE])
ioctl$DRM_IOCTL_AGP_ENABLE(fd fd_dri, cmd const[DRM_IOCTL_AGP_ENABLE], arg ptr[in, int32])
ioctl$DRM_IOCTL_AGP_INFO(fd fd_dri, cmd const[DRM_IOCTL_AGP_INFO], arg buffer[out])
ioctl$DRM_IOCTL_AGP_ALLOC(fd fd_dri, cmd const[DRM_IOCTL_AGP_ALLOC], arg ptr[inout, drm_agp_buffer$DRM_IOCTL_AGP_ALLOC])
ioctl$DRM_IOCTL_AGP_FREE(fd fd_dri, cmd const[DRM_IOCTL_AGP_FREE], arg ptr[in, drm_agp_buffer$DRM_IOCTL_AGP_FREE])
ioctl$DRM_IOCTL_AGP_BIND(fd fd_dri, cmd const[DRM_IOCTL_AGP_BIND], arg ptr[in, drm_agp_binding])
ioctl$DRM_IOCTL_AGP_UNBIND(fd fd_dri, cmd const[DRM_IOCTL_AGP_UNBIND], arg ptr[in, drm_agp_binding])
ioctl$DRM_IOCTL_SG_ALLOC(fd fd_dri, cmd const[DRM_IOCTL_SG_ALLOC], arg ptr[in, drm_scatter_gather])
ioctl$DRM_IOCTL_SG_FREE(fd fd_dri, cmd const[DRM_IOCTL_SG_FREE], arg ptr[in, drm_scatter_gather])
ioctl$DRM_IOCTL_WAIT_VBLANK(fd fd_dri, cmd const[DRM_IOCTL_WAIT_VBLANK], arg ptr[in, drm_wait_vblank_request])
ioctl$DRM_IOCTL_MODESET_CTL(fd fd_dri, cmd const[DRM_IOCTL_MODESET_CTL], arg ptr[in, drm_modeset_ctl])
ioctl$DRM_IOCTL_GEM_OPEN(fd fd_dri, cmd const[DRM_IOCTL_GEM_OPEN], arg ptr[inout, drm_gem_open])
ioctl$DRM_IOCTL_GEM_CLOSE(fd fd_dri, cmd const[DRM_IOCTL_GEM_CLOSE], arg ptr[in, drm_gem_close])
ioctl$DRM_IOCTL_GEM_FLINK(fd fd_dri, cmd const[DRM_IOCTL_GEM_FLINK], arg ptr[inout, drm_gem_flink])
ioctl$DRM_IOCTL_MODE_GETRESOURCES(fd fd_dri, cmd const[DRM_IOCTL_MODE_GETRESOURCES], arg ptr[inout, drm_mode_card_res])
ioctl$DRM_IOCTL_PRIME_HANDLE_TO_FD(fd fd_dri, cmd const[DRM_IOCTL_PRIME_HANDLE_TO_FD], arg ptr[inout, drm_prime_handle$DRM_IOCTL_PRIME_HANDLE_TO_FD])
ioctl$DRM_IOCTL_PRIME_FD_TO_HANDLE(fd fd_dri, cmd const[DRM_IOCTL_PRIME_FD_TO_HANDLE], arg ptr[inout, drm_prime_handle$DRM_IOCTL_PRIME_FD_TO_HANDLE])
ioctl$DRM_IOCTL_MODE_GETPLANERESOURCES(fd fd_dri, cmd const[DRM_IOCTL_MODE_GETPLANERESOURCES], arg ptr[inout, drm_mode_get_plane_res])
ioctl$DRM_IOCTL_MODE_GETCRTC(fd fd_dri, cmd const[DRM_IOCTL_MODE_GETCRTC], arg ptr[inout, drm_mode_crtc$DRM_IOCTL_MODE_GETCRTC])
ioctl$DRM_IOCTL_MODE_SETCRTC(fd fd_dri, cmd const[DRM_IOCTL_MODE_SETCRTC], arg ptr[in, drm_mode_crtc$DRM_IOCTL_MODE_SETCRTC])

ioctl$DRM_IOCTL_MODE_GETPLANE(fd fd_dri, cmd const[DRM_IOCTL_MODE_GETPLANE], arg ptr[inout, drm_mode_get_plane])
ioctl$DRM_IOCTL_MODE_SETPLANE(fd fd_dri, cmd const[DRM_IOCTL_MODE_SETPLANE], arg ptr[in, drm_mode_set_plane])

resource drm_plane_id[drm_obj_id]

drm_mode_get_plane_res {
	ids	ptr64[out, array[drm_plane_id]]
	cnt	len[ids, int32]
}

drm_mode_get_plane {
	plane_id		drm_plane_id	(in)
# These are outputs:
	crtc_id			drm_crtc_id
	fb_id			drm_fb_id
	possible_crtcs		const[0, int32]
	gamma_size		const[0, int32]
	count_format_types	len[format_type_ptr, int32]
	format_type_ptr		ptr64[out, array[int32]]
}

drm_mode_set_plane {
	plane_id	drm_plane_id
	crtc_id		drm_crtc_id
	fb_id		drm_fb_id
	flags		int32
	crtc_x		int32
	crtc_y		int32
	crtc_w		int32
	crtc_h		int32
	src_x		int32
	src_y		int32
	src_h		int32
	src_w		int32
}

ioctl$DRM_IOCTL_MODE_CURSOR(fd fd_dri, cmd const[DRM_IOCTL_MODE_CURSOR], arg ptr[in, drm_mode_cursor])
ioctl$DRM_IOCTL_MODE_CURSOR2(fd fd_dri, cmd const[DRM_IOCTL_MODE_CURSOR2], arg ptr[in, drm_mode_cursor2])

drm_mode_cursor {
	flags	flags[drm_mode_cursor_flags, int32]
	crtc_id	drm_crtc_id
	x	int32
	y	int32
	width	int32
	height	int32
	handle	int32
}

drm_mode_cursor2 {
	flags	flags[drm_mode_cursor_flags, int32]
	crtc_id	drm_crtc_id
	x	int32
	y	int32
	width	int32
	height	int32
	handle	int32
	hot_x	int32
	hot_y	int32
}

drm_mode_cursor_flags = DRM_MODE_CURSOR_BO, DRM_MODE_CURSOR_MOVE

ioctl$DRM_IOCTL_MODE_GETGAMMA(fd fd_dri, cmd const[DRM_IOCTL_MODE_GETGAMMA], arg ptr[in, drm_mode_crtc_lut])
ioctl$DRM_IOCTL_MODE_SETGAMMA(fd fd_dri, cmd const[DRM_IOCTL_MODE_SETGAMMA], arg ptr[in, drm_mode_crtc_lut])

drm_mode_crtc_lut {
	crtc_id		drm_crtc_id
# gamma_size needs to be equal to gamma_size passed to DRM_IOCTL_MODE_SETCRTC.
	gamma_size	len[red, int32]
	red		ptr64[in, array[int16]]
# NEED: these should be of the same size as red.
	green		ptr64[in, array[int16]]
	blue		ptr64[in, array[int16]]
}

ioctl$DRM_IOCTL_MODE_GETENCODER(fd fd_dri, cmd const[DRM_IOCTL_MODE_GETENCODER], arg ptr[inout, drm_mode_get_encoder])

resource drm_encoder_id[drm_obj_id]

drm_mode_get_encoder {
	encoder_id	drm_encoder_id	(in)
# Outputs:
	encoder_type	const[0, int32]
	crtc_id		drm_crtc_id	(out)
	possible_crtcs	const[0, int32]
	possible_clones	const[0, int32]
}

ioctl$DRM_IOCTL_MODE_GETCONNECTOR(fd fd_dri, cmd const[DRM_IOCTL_MODE_GETCONNECTOR], arg ptr[inout, drm_mode_get_connector])

resource drm_prop_id[drm_obj_id]

drm_mode_get_connector {
# Everything except for connector_id are outputs.
	encoders_ptr		ptr64[out, array[drm_encoder_id]]
	modes_ptr		ptr64[out, array[drm_mode_modeinfo]]
	props_ptr		ptr64[out, array[drm_prop_id]]
	prop_values_ptr		ptr64[out, array[int64]]
	count_modes		len[modes_ptr, int32]
	count_props		len[props_ptr, int32]
	count_encoders		len[encoders_ptr, int32]
	encoder_id		drm_encoder_id	(out)
	connector_id		drm_connector_id	(in)
	connector_type		const[0, int32]
	connector_type_id	const[0, int32]
	connection		const[0, int32]
	mm_width		const[0, int32]
	mm_height		const[0, int32]
	subpixel		const[0, int32]
	pad			const[0, int32]
}

ioctl$DRM_IOCTL_MODE_GETPROPERTY(fd fd_dri, cmd const[DRM_IOCTL_MODE_GETPROPERTY], arg ptr[inout, drm_mode_get_property])
ioctl$DRM_IOCTL_MODE_SETPROPERTY(fd fd_dri, cmd const[DRM_IOCTL_MODE_SETPROPERTY], arg ptr[in, drm_mode_connector_set_property])
ioctl$DRM_IOCTL_MODE_GETPROPBLOB(fd fd_dri, cmd const[DRM_IOCTL_MODE_GETPROPBLOB], arg ptr[in, drm_mode_get_blob])
ioctl$DRM_IOCTL_MODE_OBJ_GETPROPERTIES(fd fd_dri, cmd const[DRM_IOCTL_MODE_OBJ_GETPROPERTIES], arg ptr[inout, drm_mode_obj_get_properties])
ioctl$DRM_IOCTL_MODE_OBJ_SETPROPERTY(fd fd_dri, cmd const[DRM_IOCTL_MODE_OBJ_SETPROPERTY], arg ptr[in, drm_mode_obj_set_property])
ioctl$DRM_IOCTL_MODE_CREATEPROPBLOB(fd fd_dri, cmd const[DRM_IOCTL_MODE_CREATEPROPBLOB], arg ptr[inout, drm_mode_create_blob])
ioctl$DRM_IOCTL_MODE_DESTROYPROPBLOB(fd fd_dri, cmd const[DRM_IOCTL_MODE_DESTROYPROPBLOB], arg ptr[in, drm_mode_destroy_blob])

drm_mode_get_property {
	values_ptr		ptr64[out, array[int64]]
	enum_blob_ptr		ptr64[out, array[drm_mode_property_enum]]
	prop_id			drm_prop_id	(in)
	flags			const[0, int32]
	name			array[const[0, int8], DRM_PROP_NAME_LEN]
	count_values		len[values_ptr, int32]
	count_enum_blobs	len[enum_blob_ptr, int32]
}

drm_mode_property_enum {
	value	int64
	name	array[const[0, int8], DRM_PROP_NAME_LEN]
}

drm_mode_connector_set_property {
	value		int64
	prop_id		drm_prop_id
	connector_id	drm_connector_id
}

drm_mode_obj_set_property {
	value		int64
	prop_id		drm_prop_id
	obj_id		drm_obj_id
	obj_type	flags[drm_obj_type, int32]
}

drm_obj_type = DRM_MODE_OBJECT_CRTC, DRM_MODE_OBJECT_CONNECTOR, DRM_MODE_OBJECT_ENCODER, DRM_MODE_OBJECT_MODE, DRM_MODE_OBJECT_PROPERTY, DRM_MODE_OBJECT_FB, DRM_MODE_OBJECT_BLOB, DRM_MODE_OBJECT_PLANE, DRM_MODE_OBJECT_ANY

drm_mode_obj_get_properties {
	props_ptr	ptr64[out, array[drm_prop_id]]
# NEED: this should be the same size as props_ptr.
	prop_values_ptr	ptr64[out, array[int64]]
	count_props	len[props_ptr, int32]
	obj_id		drm_obj_id	(in)
	obj_type	flags[drm_obj_type, int32]
}

resource drm_blob_id[drm_obj_id]

drm_mode_get_blob {
	blob_id	drm_blob_id
	length	len[data, int32]
	data	ptr64[out, array[int8]]
}

drm_mode_create_blob {
	data	ptr64[in, array[int8]]
	length	len[data, int32]
	blob_id	drm_blob_id	(out)
}

drm_mode_destroy_blob {
	blob_id	drm_blob_id
}

ioctl$DRM_IOCTL_MODE_GETFB(fd fd_dri, cmd const[DRM_IOCTL_MODE_GETFB], arg ptr[inout, drm_mode_fb_cmd$DRM_IOCTL_MODE_GETFB])
ioctl$DRM_IOCTL_MODE_ADDFB(fd fd_dri, cmd const[DRM_IOCTL_MODE_ADDFB], arg ptr[in, drm_mode_fb_cmd$DRM_IOCTL_MODE_ADDFB])
ioctl$DRM_IOCTL_MODE_GETFB2(fd fd_dri, cmd const[DRM_IOCTL_MODE_GETFB2], arg ptr[inout, drm_mode_fb_cmd2$DRM_IOCTL_MODE_GETFB2])
ioctl$DRM_IOCTL_MODE_ADDFB2(fd fd_dri, cmd const[DRM_IOCTL_MODE_ADDFB2], arg ptr[in, drm_mode_fb_cmd2$DRM_IOCTL_MODE_ADDFB2])

drm_mode_fb_cmd$DRM_IOCTL_MODE_GETFB {
	fb_id	drm_fb_id	(in)
	width	int32	(out)
	height	int32	(out)
	pitch	int32	(out)
	bpp	int32	(out)
	depth	int32	(out)
	handle	int32	(out)
}

drm_mode_fb_cmd$DRM_IOCTL_MODE_ADDFB {
	fb_id	drm_fb_id
	width	int32
	height	int32
	pitch	int32
	bpp	int32
	depth	int32
	handle	int32
}

drm_mode_fb_cmd2$DRM_IOCTL_MODE_GETFB2 {
	fb_id		drm_fb_id	(in)
	width		int32
	height		int32
	pixel_format	int32
	flags		flags[drm_mode_fb_flags, int32]
	handles		array[drm_gem_handle, 4]	(out)
	pitches		array[int32, 4]
	offsets		array[int32, 4]
	modifier	array[int64, 4]
}

drm_mode_fb_cmd2$DRM_IOCTL_MODE_ADDFB2 {
	fb_id		drm_fb_id
	width		int32
	height		int32
	pixel_format	int32
	flags		flags[drm_mode_fb_flags, int32]
	handles		array[drm_gem_handle, 4]
	pitches		array[int32, 4]
	offsets		array[int32, 4]
	modifier	array[int64, 4]
}

drm_mode_fb_flags = DRM_MODE_FB_INTERLACED, DRM_MODE_FB_MODIFIERS

ioctl$DRM_IOCTL_MODE_RMFB(fd fd_dri, cmd const[DRM_IOCTL_MODE_RMFB], arg ptr[in, drm_fb_id])
ioctl$DRM_IOCTL_MODE_PAGE_FLIP(fd fd_dri, cmd const[DRM_IOCTL_MODE_PAGE_FLIP], arg ptr[in, drm_mode_crtc_page_flip_target])

drm_mode_crtc_page_flip_target {
	crtc_id		drm_crtc_id
	fb_id		drm_fb_id
	flags		flags[drm_page_flip_flags, int32]
	sequence	int32
	user_data	int64
}

drm_page_flip_flags = DRM_MODE_PAGE_FLIP_EVENT, DRM_MODE_PAGE_FLIP_ASYNC, DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE, DRM_MODE_PAGE_FLIP_TARGET_RELATIVE

ioctl$DRM_IOCTL_MODE_DIRTYFB(fd fd_dri, cmd const[DRM_IOCTL_MODE_DIRTYFB], arg ptr[in, drm_mode_fb_dirty_cmd])

drm_mode_fb_dirty_cmd {
	fb_id		drm_fb_id
	flags		flags[drm_mode_fb_dirty_flags, int32]
	color		int32
	num_clips	len[clips_ptr, int32]
	clips_ptr	ptr64[in, array[drm_clip_rect]]
}

drm_clip_rect {
	x1	int16
	y1	int16
	x2	int16
	y2	int16
}

drm_mode_fb_dirty_flags = DRM_MODE_FB_DIRTY_ANNOTATE_COPY, DRM_MODE_FB_DIRTY_ANNOTATE_FILL

ioctl$DRM_IOCTL_MODE_CREATE_DUMB(fd fd_dri, cmd const[DRM_IOCTL_MODE_CREATE_DUMB], arg ptr[inout, drm_mode_create_dumb])
ioctl$DRM_IOCTL_MODE_MAP_DUMB(fd fd_dri, cmd const[DRM_IOCTL_MODE_MAP_DUMB], arg ptr[inout, drm_mode_map_dumb])
ioctl$DRM_IOCTL_MODE_DESTROY_DUMB(fd fd_dri, cmd const[DRM_IOCTL_MODE_DESTROY_DUMB], arg ptr[in, drm_mode_destroy_dumb])

resource drm_dumb_handle[int32]

drm_mode_create_dumb {
	height	int32	(in)
	width	int32	(in)
	bpp	int32	(in)
# flags does not seem to be used by any driver.
	flags	const[0, int32]
	handle	drm_dumb_handle	(out)
	pitch	int32	(out)
	size	int64	(out)
}

drm_mode_map_dumb {
	handle	drm_dumb_handle	(in)
	pad	const[0, int32]
	offset	int64	(out)
}

drm_mode_destroy_dumb {
	handle	drm_dumb_handle
}

ioctl$DRM_IOCTL_MODE_ATOMIC(fd fd_dri, cmd const[DRM_IOCTL_MODE_ATOMIC], arg ptr[in, drm_mode_atomic])

drm_mode_atomic {
	flags		flags[drm_mode_atomic_flags, int32]
	count_objs	len[objs_ptr, int32]
	objs_ptr	ptr64[in, array[drm_obj_id]]
# NEED: this array is probably parallel to objs_ptr.
	count_props_ptr	ptr64[in, array[int32]]
	props_ptr	ptr64[in, array[drm_prop_id]]
	prop_values_ptr	ptr64[in, array[int64]]
	reserved	const[0, int64]
	user_data	int64
}

drm_mode_atomic_flags = DRM_MODE_PAGE_FLIP_EVENT, DRM_MODE_ATOMIC_TEST_ONLY, DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_ATOMIC_ALLOW_MODESET

resource fd_drm_syncobj[fd]
resource drm_syncobj[int32]

# TODO: drm_syncpoint should be a resource and it used to be.
# But it was produced only by drm_syncobj_wait/drm_syncobj_timeline_wait.first_signaled
# which actually returns some int32 index rather than int64 syncpoint.
# Once it was fixed nothing produces drm_syncpoint anymore, so it was downgraded to plain int.
# resource drm_syncpoint[int64]
type drm_syncpoint int64

# See https://www.kernel.org/doc/html/latest/gpu/drm-mm.html#drm-sync-objects
# for more details
ioctl$DRM_IOCTL_SYNCOBJ_CREATE(fd fd_dri, cmd const[DRM_IOCTL_SYNCOBJ_CREATE], arg ptr[inout, drm_syncobj_create])
ioctl$DRM_IOCTL_SYNCOBJ_DESTROY(fd fd_dri, cmd const[DRM_IOCTL_SYNCOBJ_DESTROY], arg ptr[in, drm_syncobj_destroy])
ioctl$DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD_SYNC_FILE(fd fd_dri, cmd const[DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD], arg ptr[inout, drm_syncobj_handle$to_sync_file])
ioctl$DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD_FD(fd fd_dri, cmd const[DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD], arg ptr[inout, drm_syncobj_handle$to_fd])
ioctl$DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE_SYNC_FILE(fd fd_dri, cmd const[DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE], arg ptr[inout, drm_syncobj_handle$from_sync_file])
ioctl$DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE_FD(fd fd_dri, cmd const[DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE], arg ptr[inout, drm_syncobj_handle$from_fd])
ioctl$DRM_IOCTL_SYNCOBJ_TRANSFER(fd fd_dri, cmd const[DRM_IOCTL_SYNCOBJ_TRANSFER], arg ptr[inout, drm_syncobj_transfer])
ioctl$DRM_IOCTL_SYNCOBJ_WAIT(fd fd_dri, cmd const[DRM_IOCTL_SYNCOBJ_WAIT], arg ptr[inout, drm_syncobj_wait])
ioctl$DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT(fd fd_dri, cmd const[DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT], arg ptr[inout, drm_syncobj_timeline_wait])
ioctl$DRM_IOCTL_SYNCOBJ_RESET(fd fd_dri, cmd const[DRM_IOCTL_SYNCOBJ_RESET], arg ptr[in, drm_syncobj_array])
ioctl$DRM_IOCTL_SYNCOBJ_SIGNAL(fd fd_dri, cmd const[DRM_IOCTL_SYNCOBJ_SIGNAL], arg ptr[in, drm_syncobj_array])
ioctl$DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL(fd fd_dri, cmd const[DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL], arg ptr[in, drm_syncobj_timeline_array])
ioctl$DRM_IOCTL_SYNCOBJ_QUERY(fd fd_dri, cmd const[DRM_IOCTL_SYNCOBJ_QUERY], arg ptr[inout, drm_syncobj_timeline_array])

drm_syncobj_create {
	handle	drm_syncobj	(out)
	flags	flags[drm_syncobj_create_flags, int32]	(in)
}

drm_syncobj_destroy {
	handle	drm_syncobj
	pad	const[0, int32]
}

drm_syncobj_handle$to_sync_file {
	handle	drm_syncobj	(in)
	flags	const[DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE, int32]
	fd	fd_sync_file	(out)
	pad	const[0, int32]
}

drm_syncobj_handle$to_fd {
	handle	drm_syncobj	(in)
	flags	const[0, int32]
	fd	fd_drm_syncobj	(out)
	pad	const[0, int32]
}

drm_syncobj_handle$from_sync_file {
	handle	drm_syncobj	(out)
	flags	const[DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE, int32]
	fd	fd_sync_file	(in)
	pad	const[0, int32]
}

drm_syncobj_handle$from_fd {
	handle	drm_syncobj	(out)
	flags	const[0, int32]
	fd	fd_drm_syncobj	(in)
	pad	const[0, int32]
}

drm_syncobj_transfer {
	src_handle	drm_syncobj	(in)
	dst_handle	drm_syncobj	(in)
	src_point	drm_syncpoint	(in)
	dst_point	drm_syncpoint	(in)
	flags		flags[drm_syncobj_wait_flags, int32]	(in)
	pad		const[0, int32]
}

drm_syncobj_wait {
	handles		ptr64[in, array[drm_syncobj]]
	timeout_nsec	int64	(in)
	count_handles	len[handles, int32]
	flags		flags[drm_syncobj_wait_flags, int32]	(in)
	first_signaled	int32	(out)
	pad		const[0, int32]
}

drm_syncobj_timeline_wait {
	handles		ptr64[in, array[drm_syncobj]]
	points		ptr64[in, array[drm_syncpoint]]
	timeout_nsec	int64
	count_handles	len[handles, int32]
	flags		flags[drm_syncobj_wait_flags, int32]	(in)
	first_signaled	int32	(out)
	pad		const[0, int32]
}

drm_syncobj_array {
	handles		ptr64[in, array[drm_syncobj]]
	count_handles	len[handles, int32]
	pad		const[0, int32]
}

drm_syncobj_timeline_array {
	handles		ptr64[in, array[drm_syncobj]]
	points		ptr64[inout, array[drm_syncpoint]]
	count_handles	len[handles, int32]
	flags		flags[drm_syncobj_query_flags, int32]	(in)
}

# TODO: describe SEQUENCE ioctls (but we don't have DRIVER_MODESET hardware).
#ioctl$DRM_IOCTL_CRTC_GET_SEQUENCE(fd fd_dri, cmd const[DRM_IOCTL_CRTC_GET_SEQUENCE], arg ptr[in, XXXXX])
#ioctl$DRM_IOCTL_CRTC_QUEUE_SEQUENCE(fd fd_dri, cmd const[DRM_IOCTL_CRTC_QUEUE_SEQUENCE], arg ptr[in, XXXXX])

ioctl$DRM_IOCTL_MODE_CREATE_LEASE(fd fd_dri, cmd const[DRM_IOCTL_MODE_CREATE_LEASE], arg ptr[inout, drm_mode_create_lease])
ioctl$DRM_IOCTL_MODE_LIST_LESSEES(fd fd_dri, cmd const[DRM_IOCTL_MODE_LIST_LESSEES], arg ptr[in, drm_mode_list_lessees])
ioctl$DRM_IOCTL_MODE_GET_LEASE(fd fd_dri, cmd const[DRM_IOCTL_MODE_GET_LEASE], arg ptr[inout, drm_mode_get_lease])
ioctl$DRM_IOCTL_MODE_REVOKE_LEASE(fd fd_dri, cmd const[DRM_IOCTL_MODE_REVOKE_LEASE], arg ptr[in, drm_mode_revoke_lease])

resource drm_lessee_id[int32]

drm_mode_create_lease {
	object_ids	ptr64[in, array[drm_obj_id]]	(in)
	object_count	len[object_ids, int32]	(in)
	flags		flags[drm_mode_create_lease_flag, int32]	(in)
	lessee_id	drm_lessee_id	(out)
	fd		fd	(out)
}

drm_mode_create_lease_flag = O_CLOEXEC, O_NONBLOCK

drm_mode_list_lessees {
	count_lessees	len[lessees_ptr, int32]
	pad		const[0, int32]
	lessees_ptr	ptr64[out, array[drm_lessee_id]]
}

drm_mode_get_lease {
	count_objects	len[objects_ptr, int32]
	pad		const[0, int32]
	objects_ptr	ptr64[out, array[drm_obj_id]]
}

drm_mode_revoke_lease {
	lessee_id	drm_lessee_id
}

drm_version {
	maj	int32
	min	int32
	patch	int32
	namelen	len[name, intptr]
	name	buffer[out]
	datelen	len[date, intptr]
	date	buffer[out]
	desclen	len[desc, intptr]
	desc	buffer[out]
}

drm_unique$in {
	len	len[uni, intptr]
	uni	buffer[in]
}

drm_unique$out {
	len	len[uni, intptr]
	uni	buffer[out]
}

drm_irq_busid {
	irq	int32	(out)
	bus	int32	(in)
	dev	int32	(in)
	func	int32	(in)
}

drm_map$DRM_IOCTL_GET_MAP {
	off	vma	(inout)
	size	intptr	(out)
	type	int32	(out)
	flags	int32	(out)
	handle	vma	(out)
	mtrr	int32	(out)
}

drm_map$DRM_IOCTL_ADD_MAP {
	off	vma	(in)
	size	intptr	(in)
	type	flags[drm_map_type, int32]	(in)
	flags	flags[drm_map_flags, int32]	(in)
	handle	vma	(out)
	mtrr	int32	(out)
}

drm_map$DRM_IOCTL_RM_MAP {
# Only handle is used.
	off	const[0, intptr]
	size	const[0, intptr]
	type	const[0, int32]
	flags	const[0, int32]
	handle	vma
	mtrr	const[0, int32]
}

drm_client {
	idx	int32
	auth	int32
	pid	alignptr[pid]
	uid	alignptr[uid]
	magic	intptr
	iocs	intptr
}

drm_get_cap {
	cap	flags[drm_cap, int64]
	val	const[0, int64]
}

drm_cap = DRM_CAP_DUMB_BUFFER, DRM_CAP_VBLANK_HIGH_CRTC, DRM_CAP_DUMB_PREFERRED_DEPTH, DRM_CAP_DUMB_PREFER_SHADOW, DRM_CAP_PRIME, DRM_PRIME_CAP_IMPORT, DRM_PRIME_CAP_EXPORT, DRM_CAP_TIMESTAMP_MONOTONIC, DRM_CAP_ASYNC_PAGE_FLIP, DRM_CAP_CURSOR_WIDTH, DRM_CAP_CURSOR_HEIGHT, DRM_CAP_ADDFB2_MODIFIERS, DRM_CAP_PAGE_FLIP_TARGET, DRM_CAP_CRTC_IN_VBLANK_EVENT, DRM_CAP_SYNCOBJ, DRM_CAP_SYNCOBJ_TIMELINE

drm_set_version {
	di_maj	int32
	di_min	int32
	dd_maj	int32
	dd_min	int32
}

drm_ctx_priv_map {
	ctxid	drmctx
	handle	buffer[out]
}

drm_ctx {
	handle	drmctx
	flags	flags[drm_ctx_flags, int32]
}

drm_ctx_res {
	count	len[context, int32]
	context	ptr[out, array[drm_ctx]]
}

drm_lock {
	context	drmctx
	flags	flags[drm_lock_flags, int32]
}

drm_buf_desc {
	count	int32
	size	int32
	lomark	int32
	himark	int32
	flags	flags[drm_buf_flags, int32]
# TODO: what is agp addresses? should it be a special type?
	agpaddr	intptr
}

drm_buf_map {
	count	len[list, int32]
	virtual	buffer[out]
	list	ptr[in, array[drm_buf_pub]]
}

drm_buf_pub {
	idx	int32
	total	len[addr, int32]
	used	int32
	addr	buffer[out]
}

drm_buf_free {
	count	len[list, int32]
	list	ptr[in, array[int32]]
}

drm_dma {
	context	drmctx
	sendcnt	len[sendind, int32]
	sendind	ptr[in, array[int32]]
	sendsiz	ptr[in, array[int32]]
	flags	flags[drm_dma_flags, int32]
	reqcnd	len[reqind, int32]
	reqsiz0	int32
	reqind	ptr[in, array[int32]]
	reqsiz	ptr[in, array[int32]]
	granted	const[0, int32]
}

drm_control {
	func	flags[drm_control_type, int32]
	irq	int32
}

drm_agp_buffer$DRM_IOCTL_AGP_ALLOC {
	size	intptr	(in)
	handle	drm_agp_handle	(out)
	type	flags[drm_agp_mem_type, intptr]	(in)
	physic	intptr	(out)
}

drm_agp_buffer$DRM_IOCTL_AGP_FREE {
# Only handle is used.
	size	const[0, intptr]
	handle	drm_agp_handle
	type	const[0, intptr]
	physic	const[0, intptr]
}

drm_agp_binding {
	handle	drm_agp_handle
	offset	intptr
}

drm_scatter_gather {
	size	intptr
	handle	drm_agp_handle
}

drm_wait_vblank_request {
	type	flags[drm_vblank_seq_type, int32]
	seq	int32
	signal	intptr
}

drm_modeset_ctl {
	crtc	int32
	cmd	int32
}

drm_gem_open {
	name	drm_gem_name	(in)
	handle	drm_gem_handle	(out)
	size	int64	(out)
}

drm_gem_close {
	handle	drm_gem_handle
	pad	const[0, int32]
}

drm_gem_flink {
	handle	drm_gem_handle	(in)
	name	drm_gem_name	(out)
}

drm_mode_card_res {
	fbid	ptr64[out, array[drm_fb_id]]
	crtcid	ptr64[out, array[drm_crtc_id]]
	connid	ptr64[out, array[drm_connector_id]]
	encid	ptr64[out, array[drm_encoder_id]]
	nfbid	len[fbid, int32]
	ncrtcid	len[crtcid, int32]
	nconnid	len[connid, int32]
	nencid	len[encid, int32]
	maxw	const[0, int32]
	maxh	const[0, int32]
	minw	const[0, int32]
	minh	const[0, int32]
}

drm_prime_handle$DRM_IOCTL_PRIME_HANDLE_TO_FD {
	handle	drm_gem_handle	(in)
	flags	flags[dup_flags, int32]	(in)
	fd	fd_dri	(out)
}

drm_prime_handle$DRM_IOCTL_PRIME_FD_TO_HANDLE {
	handle	drm_gem_handle	(out)
	flags	const[0, int32]
	fd	fd_dri	(in)
}

drm_mode_crtc$DRM_IOCTL_MODE_GETCRTC {
	set_connectors_ptr	ptr64[in, array[const[0, int32]]]
	count_connectors	len[set_connectors_ptr, int32]
	crtc_id			drm_crtc_id	(in)
	fb_id			drm_fb_id	(out)
	x			int32	(out)
	y			int32	(out)
	gamma_size		int32	(out)
	mode_valid		int32	(out)
	mode			drm_mode_modeinfo	(out)
}

drm_mode_crtc$DRM_IOCTL_MODE_SETCRTC {
	set_connectors_ptr	ptr64[in, array[drm_connector_id]]
	count_connectors	len[set_connectors_ptr, int32]
	crtc_id			drm_crtc_id
	fb_id			drm_fb_id
	x			int32
	y			int32
	gamma_size		int32
	mode_valid		int32
	mode			drm_mode_modeinfo
}

drm_mode_modeinfo {
	clock		int32
	hdisplay	int16
	hsync_start	int16
	hsync_end	int16
	htotal		int16
	hskew		int16
	vdisplay	int16
	vsync_start	int16
	vsync_end	int16
	vtotal		int16
	vscan		int16
	vrefresh	int32
	flags		int32
	type		int32
	name		array[int8, DRM_DISPLAY_MODE_LEN]
}

drm_agp_mem_type = 0, 1, 2, AGP_USER_MEMORY, AGP_USER_CACHED_MEMORY
drm_map_type = _DRM_FRAME_BUFFER, _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, _DRM_SCATTER_GATHER, _DRM_CONSISTENT
drm_map_flags = _DRM_RESTRICTED, _DRM_READ_ONLY, _DRM_LOCKED, _DRM_KERNEL, _DRM_WRITE_COMBINING, _DRM_CONTAINS_LOCK, _DRM_REMOVABLE, _DRM_DRIVER
drm_ctx_flags = _DRM_CONTEXT_PRESERVED, _DRM_CONTEXT_2DONLY
drm_lock_flags = _DRM_LOCK_READY, _DRM_LOCK_QUIESCENT, _DRM_LOCK_FLUSH, _DRM_LOCK_FLUSH_ALL, _DRM_HALT_ALL_QUEUES, _DRM_HALT_CUR_QUEUES
drm_buf_flags = _DRM_PAGE_ALIGN, _DRM_AGP_BUFFER, _DRM_SG_BUFFER, _DRM_FB_BUFFER, _DRM_PCI_BUFFER_RO
drm_dma_flags = _DRM_DMA_BLOCK, _DRM_DMA_WHILE_LOCKED, _DRM_DMA_PRIORITY, _DRM_DMA_WAIT, _DRM_DMA_SMALLER_OK, _DRM_DMA_LARGER_OK
drm_control_type = DRM_ADD_COMMAND, DRM_RM_COMMAND, DRM_INST_HANDLER, DRM_UNINST_HANDLER
drm_vblank_seq_type = _DRM_VBLANK_ABSOLUTE, _DRM_VBLANK_RELATIVE, _DRM_VBLANK_HIGH_CRTC_MASK, _DRM_VBLANK_EVENT, _DRM_VBLANK_FLIP, _DRM_VBLANK_NEXTONMISS, _DRM_VBLANK_SECONDARY, _DRM_VBLANK_SIGNAL
drm_syncobj_create_flags = DRM_SYNCOBJ_CREATE_SIGNALED
drm_syncobj_wait_flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE
drm_syncobj_query_flags = DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED
