linux_drm/
ioctl.rs

1use core::ffi::c_int as int;
2use core::ffi::c_ulong as ulong;
3use core::ptr::null_mut;
4
5use linux_io::fd::ioctl::{
6    ioctl_no_arg, ioctl_write, ioctl_writeread, IoDevice, IoctlReqNoArgs, IoctlReqWrite,
7    IoctlReqWriteRead,
8};
9
10pub struct DrmCardDevice;
11
12impl IoDevice for DrmCardDevice {}
13
14const DRM_IOCTL_BASE: ulong = 100;
15
16#[allow(non_snake_case)]
17const fn _IO(nr: ulong) -> ulong {
18    linux_io::fd::ioctl::_IO(DRM_IOCTL_BASE, nr)
19}
20
21#[allow(non_snake_case)]
22const fn _IOW<T>(nr: ulong) -> ulong {
23    linux_io::fd::ioctl::_IOW(DRM_IOCTL_BASE, nr, core::mem::size_of::<T>() as _)
24}
25
26#[allow(non_snake_case)]
27const fn _IOR<T>(nr: ulong) -> ulong {
28    linux_io::fd::ioctl::_IOR(DRM_IOCTL_BASE, nr, core::mem::size_of::<T>() as _)
29}
30
31#[allow(non_snake_case)]
32const fn _IOWR<T>(nr: ulong) -> ulong {
33    linux_io::fd::ioctl::_IOWR(DRM_IOCTL_BASE, nr, core::mem::size_of::<T>() as _)
34}
35
36/// Fixed-point unsigned 16.16-bit number type, represented as [`u32`].
37#[allow(non_camel_case_types)]
38#[derive(Copy, Clone, Debug)]
39#[repr(transparent)]
40pub struct fixedu16_16(u32);
41
42impl fixedu16_16 {
43    #[inline(always)]
44    pub fn from_u16(v: u16) -> Self {
45        Self((v as u32) << 16)
46    }
47
48    #[inline(always)]
49    pub fn from_u16_frac(w: u16, f: u16) -> Self {
50        Self(((w as u32) << 16) | (f as u32))
51    }
52
53    #[inline(always)]
54    pub fn as_raw_u32(self) -> u32 {
55        self.0
56    }
57}
58
59impl From<u16> for fixedu16_16 {
60    #[inline(always)]
61    fn from(value: u16) -> Self {
62        Self::from_u16(value)
63    }
64}
65
66impl From<u8> for fixedu16_16 {
67    #[inline(always)]
68    fn from(value: u8) -> Self {
69        Self::from_u16(value as u16)
70    }
71}
72
73macro_rules! impl_zeroed {
74    ($t:ty) => {
75        impl $t {
76            #[inline(always)]
77            pub const fn zeroed() -> Self {
78                // Safety: All of the field types in $t must
79                // treat all-zeroes as a valid bit pattern.
80                unsafe { ::core::mem::zeroed() }
81            }
82        }
83
84        /// The default value is the result of [`Self::zeroed`].
85        impl ::core::default::Default for $t {
86            #[inline(always)]
87            fn default() -> Self {
88                Self::zeroed()
89            }
90        }
91    };
92}
93
94#[repr(C)]
95#[derive(Clone, Copy, Debug)]
96pub struct DrmVersion {
97    pub version_major: int,
98    pub version_minor: int,
99    pub version_patchlevel: int,
100    name_len: usize,
101    name: *mut i8,
102    date_len: usize,
103    date: *mut i8,
104    desc_len: usize,
105    desc: *mut i8,
106}
107
108impl_zeroed!(DrmVersion);
109
110impl DrmVersion {
111    #[inline(always)]
112    pub unsafe fn set_name_ptr(&mut self, ptr: *mut i8, len: usize) {
113        self.name = ptr;
114        self.name_len = len;
115    }
116
117    #[inline(always)]
118    pub fn clear_name_ptr(&mut self) {
119        self.name = null_mut();
120        self.name_len = 0;
121    }
122
123    #[inline(always)]
124    pub fn name_len(&self) -> usize {
125        self.name_len
126    }
127
128    #[inline(always)]
129    pub unsafe fn set_date_ptr(&mut self, ptr: *mut i8, len: usize) {
130        self.date = ptr;
131        self.date_len = len;
132    }
133
134    #[inline(always)]
135    pub fn clear_date_ptr(&mut self) {
136        self.date = null_mut();
137        self.date_len = 0;
138    }
139
140    #[inline(always)]
141    pub fn date_len(&self) -> usize {
142        self.date_len
143    }
144
145    #[inline(always)]
146    pub unsafe fn set_desc_ptr(&mut self, ptr: *mut i8, len: usize) {
147        self.desc = ptr;
148        self.desc_len = len;
149    }
150
151    #[inline(always)]
152    pub fn clear_desc_ptr(&mut self) {
153        self.desc = null_mut();
154        self.desc_len = 0;
155    }
156
157    #[inline(always)]
158    pub fn desc_len(&self) -> usize {
159        self.desc_len
160    }
161}
162
163pub const DRM_IOCTL_VERSION: IoctlReqWriteRead<DrmCardDevice, DrmVersion, int> =
164    unsafe { ioctl_writeread(_IOWR::<DrmVersion>(0x00)) };
165
166#[repr(C)]
167#[derive(Clone, Copy, Debug)]
168pub struct DrmSetVersion {
169    pub drm_di_major: int,
170    pub drm_di_minor: int,
171    pub drm_dd_major: int,
172    pub drm_dd_minor: int,
173}
174
175impl_zeroed!(DrmSetVersion);
176
177pub const DRM_IOCTL_SET_VERSION: IoctlReqWriteRead<DrmCardDevice, DrmSetVersion, int> =
178    unsafe { ioctl_writeread(_IOWR::<DrmSetVersion>(0x07)) };
179
180pub const DRM_IOCTL_SET_MASTER: IoctlReqNoArgs<DrmCardDevice, int> =
181    unsafe { ioctl_no_arg(_IO(0x1e)) };
182
183pub const DRM_IOCTL_DROP_MASTER: IoctlReqNoArgs<DrmCardDevice, int> =
184    unsafe { ioctl_no_arg(_IO(0x1f)) };
185
186#[repr(C)]
187#[derive(Clone, Copy, Debug)]
188pub struct DrmGetCap {
189    pub capability: DrmCap,
190    pub value: u64,
191}
192
193impl_zeroed!(DrmGetCap);
194
195#[derive(Copy, Clone, Debug, PartialEq, Eq)]
196#[repr(transparent)]
197pub struct DrmCap(pub u64);
198
199pub const DRM_IOCTL_GET_CAP: IoctlReqWriteRead<DrmCardDevice, DrmGetCap, int> =
200    unsafe { ioctl_writeread(_IOWR::<DrmGetCap>(0x0c)) };
201
202/// If set to 1, the driver supports creating "dumb buffers" via [`DRM_IOCTL_MODE_CREATE_DUMB`].
203pub const DRM_CAP_DUMB_BUFFER: DrmCap = DrmCap(0x1);
204/// If set to 1, the kernel supports specifying a CRTC index
205/// in the high bits of [`DrmWaitVblankRequest::type`].
206pub const DRM_CAP_VBLANK_HIGH_CRTC: DrmCap = DrmCap(0x2);
207/// The preferred bit depth for "dumb buffers".
208///
209/// The bit depth is the number of bits used to indicate the color of a single
210/// pixel excluding any padding. This is different from the number of bits per
211/// pixel. For instance, XRGB8888 has a bit depth of 24 but has 32 bits per
212/// pixel.
213///
214/// This preference only applies to dumb buffers, and is irrelevant for
215/// other types of buffers.
216pub const DRM_CAP_DUMB_PREFERRED_DEPTH: DrmCap = DrmCap(0x3);
217/// If set to 1, the driver prefers userspace to render to a shadow buffer
218/// instead of directly rendering to a dumb buffer. For best speed, userspace
219/// should do streaming ordered memory copies into the dumb buffer and never
220/// read from it.
221///
222/// This preference only applies to dumb buffers, and is irrelevant for
223/// other types of buffers.
224pub const DRM_CAP_DUMB_PREFER_SHADOW: DrmCap = DrmCap(0x4);
225/// Bitfield of supported PRIME sharing capabilities. See [`DRM_PRIME_CAP_IMPORT`]
226/// and [`DRM_PRIME_CAP_EXPORT`].
227///
228/// Starting from kernel version 6.6, both `DRM_PRIME_CAP_IMPORT` and
229/// `DRM_PRIME_CAP_EXPORT` are always advertised.
230///
231/// PRIME buffers are exposed as dma-buf file descriptors.
232pub const DRM_CAP_PRIME: DrmCap = DrmCap(0x5);
233/// If this bit is set in [`DRM_CAP_PRIME`], the driver supports importing PRIME
234/// buffers via [`DRM_IOCTL_PRIME_FD_TO_HANDLE`].
235pub const DRM_PRIME_CAP_IMPORT: DrmCap = DrmCap(0x1);
236/// If this bit is set in [`DRM_CAP_PRIME`], the driver supports exporting PRIME
237/// buffers via [`DRM_IOCTL_PRIME_HANDLE_TO_FD`].
238pub const DRM_PRIME_CAP_EXPORT: DrmCap = DrmCap(0x2);
239/// If set to 0, the kernel will report timestamps with `CLOCK_REALTIME` in
240/// [`crate::event::raw::DrmEventVblank`]. If set to 1, the kernel will report
241/// timestamps with `CLOCK_MONOTONIC`.
242///
243/// Starting from kernel version 2.6.39, the default value for this capability
244/// is 1. Starting kernel version 4.15, this capability is always set to 1.
245pub const DRM_CAP_TIMESTAMP_MONOTONIC: DrmCap = DrmCap(0x6);
246/// If set to 1, the driver supports [`DRM_MODE_PAGE_FLIP_ASYNC`] for legacy
247/// page-flips.
248pub const DRM_CAP_ASYNC_PAGE_FLIP: DrmCap = DrmCap(0x7);
249/// A plane width that is valid to use for a cursor plane.
250pub const DRM_CAP_CURSOR_WIDTH: DrmCap = DrmCap(0x8);
251/// A plane height that is valid to use for a cursor plane.
252pub const DRM_CAP_CURSOR_HEIGHT: DrmCap = DrmCap(0x9);
253/// If set to 1, the driver supports supplying modifiers in [`DRM_IOCTL_MODE_ADDFB2`].
254pub const DRM_CAP_ADDFB2_MODIFIERS: DrmCap = DrmCap(0x10);
255pub const DRM_CAP_PAGE_FLIP_TARGET: DrmCap = DrmCap(0x11);
256/// If set to 1, the kernel supports reporting the CRTC ID in
257/// [`crate::event::raw::DrmEventVblank::crtc_id`] for
258/// [`crate::event::raw::DRM_EVENT_VBLANK`] and
259/// [`crate::event::raw::DRM_EVENT_FLIP_COMPLETE`] events.
260///
261/// Starting kernel version 4.12, this capability is always set to 1.
262pub const DRM_CAP_CRTC_IN_VBLANK_EVENT: DrmCap = DrmCap(0x12);
263/// If set to 1, the driver supports sync objects.
264pub const DRM_CAP_SYNCOBJ: DrmCap = DrmCap(0x13);
265/// If set to 1, the driver supports timeline operations on sync objects.
266pub const DRM_CAP_SYNCOBJ_TIMELINE: DrmCap = DrmCap(0x14);
267/// If set to 1, the driver supports [`DRM_MODE_PAGE_FLIP_ASYNC`] for atomic commits.
268pub const DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP: DrmCap = DrmCap(0x15);
269
270#[repr(C)]
271#[derive(Clone, Copy, Debug)]
272pub struct DrmSetClientCap {
273    pub capability: DrmClientCap,
274    pub value: u64,
275}
276
277impl_zeroed!(DrmSetClientCap);
278
279#[derive(Copy, Clone, Debug, PartialEq, Eq)]
280#[repr(transparent)]
281pub struct DrmClientCap(pub u64);
282
283pub const DRM_IOCTL_SET_CLIENT_CAP: IoctlReqWrite<DrmCardDevice, DrmSetClientCap, int> =
284    unsafe { ioctl_write(_IOW::<DrmSetClientCap>(0x0d)) };
285
286/// If set to 1, the DRM core will expose the stereo 3D capabilities of the
287/// monitor by advertising the supported 3D layouts in the flags of struct
288/// drm_mode_modeinfo.
289pub const DRM_CLIENT_CAP_STEREO_3D: DrmClientCap = DrmClientCap(1);
290
291/// If set to 1, the DRM core will expose all planes (overlay, primary, and
292/// cursor) to userspace.
293pub const DRM_CLIENT_CAP_UNIVERSAL_PLANES: DrmClientCap = DrmClientCap(2);
294
295/// If set to 1, the DRM core will expose atomic properties to userspace.
296pub const DRM_CLIENT_CAP_ATOMIC: DrmClientCap = DrmClientCap(3);
297
298/// If set to 1, the DRM core will provide aspect ratio information in modes.
299pub const DRM_CLIENT_CAP_ASPECT_RATIO: DrmClientCap = DrmClientCap(4);
300
301/// If set to 1, the DRM core will expose special connectors to be used for
302/// writing back to memory the scene setup in the commit. Depends on client
303/// also supporting DRM_CLIENT_CAP_ATOMIC
304pub const DRM_CLIENT_CAP_WRITEBACK_CONNECTORS: DrmClientCap = DrmClientCap(5);
305
306/// Drivers for para-virtualized hardware (e.g. `vmwgfx`, `qxl`, `virtio` and
307/// `virtualbox`) have additional restrictions for cursor planes (thus
308/// making cursor planes on those drivers not truly universal,) e.g.
309/// they need cursor planes to act like one would expect from a mouse
310/// cursor and have correctly set hotspot properties.
311/// If this client cap is not set the DRM core will hide cursor plane on
312/// those virtualized drivers because not setting it implies that the
313/// client is not capable of dealing with those extra restictions.
314/// Clients which do set cursor hotspot and treat the cursor plane
315/// like a mouse cursor should set this property.
316/// The client must enable [`DRM_CLIENT_CAP_ATOMIC`] first.
317///
318/// Setting this property on drivers which do not special case
319/// cursor planes (i.e. non-virtualized drivers) will return
320/// [`linux_io::result::EOPNOTSUPP`], which can be used by userspace
321/// to gauge requirements of the hardware/drivers they're running on.
322///
323/// This capability is always supported for atomic-capable virtualized
324/// drivers starting from kernel version 6.6.
325pub const DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT: DrmClientCap = DrmClientCap(6);
326
327#[repr(C)]
328#[derive(Debug)]
329pub struct DrmModeCardRes {
330    fb_id_ptr: u64,
331    crtc_id_ptr: u64,
332    connector_id_ptr: u64,
333    encoder_id_ptr: u64,
334    count_fbs: u32,
335    count_crtcs: u32,
336    count_connectors: u32,
337    count_encoders: u32,
338    pub min_width: u32,
339    pub max_width: u32,
340    pub min_height: u32,
341    pub max_height: u32,
342}
343
344impl_zeroed!(DrmModeCardRes);
345
346impl DrmModeCardRes {
347    #[inline(always)]
348    pub unsafe fn set_fb_id_ptr(&mut self, ptr: *mut u32, len: u32) {
349        self.fb_id_ptr = ptr as u64;
350        self.count_fbs = len;
351    }
352
353    #[inline(always)]
354    pub fn clear_fb_id_ptr(&mut self) {
355        self.fb_id_ptr = 0;
356        self.count_fbs = 0;
357    }
358
359    #[inline(always)]
360    pub fn count_fbs(&mut self) -> u32 {
361        self.count_fbs
362    }
363
364    #[inline(always)]
365    pub unsafe fn set_crtc_id_ptr(&mut self, ptr: *mut u32, len: u32) {
366        self.crtc_id_ptr = ptr as u64;
367        self.count_crtcs = len;
368    }
369
370    #[inline(always)]
371    pub fn clear_crtc_id_ptr(&mut self) {
372        self.crtc_id_ptr = 0;
373        self.count_crtcs = 0;
374    }
375
376    #[inline(always)]
377    pub fn count_crtcs(&mut self) -> u32 {
378        self.count_crtcs
379    }
380
381    #[inline(always)]
382    pub unsafe fn set_connector_id_ptr(&mut self, ptr: *mut u32, len: u32) {
383        self.connector_id_ptr = ptr as u64;
384        self.count_connectors = len;
385    }
386
387    #[inline(always)]
388    pub fn clear_connector_id_ptr(&mut self) {
389        self.connector_id_ptr = 0;
390        self.count_connectors = 0;
391    }
392
393    #[inline(always)]
394    pub fn count_connectors(&mut self) -> u32 {
395        self.count_connectors
396    }
397
398    #[inline(always)]
399    pub unsafe fn set_encoder_id_ptr(&mut self, ptr: *mut u32, len: u32) {
400        self.encoder_id_ptr = ptr as u64;
401        self.count_encoders = len;
402    }
403
404    #[inline(always)]
405    pub fn clear_encoder_id_ptr(&mut self) {
406        self.encoder_id_ptr = 0;
407        self.count_encoders = 0;
408    }
409
410    #[inline(always)]
411    pub fn count_encoders(&mut self) -> u32 {
412        self.count_encoders
413    }
414}
415
416pub const DRM_IOCTL_MODE_GETRESOURCES: IoctlReqWriteRead<DrmCardDevice, DrmModeCardRes, int> =
417    unsafe { ioctl_writeread(_IOWR::<DrmModeCardRes>(0xa0)) };
418
419#[repr(C)]
420#[derive(Debug)]
421pub struct DrmModeInfo {
422    pub clock: u32,
423    pub hdisplay: u16,
424    pub hsync_start: u16,
425    pub hsync_end: u16,
426    pub htotal: u16,
427    pub hskew: u16,
428    pub vdisplay: u16,
429    pub vsync_start: u16,
430    pub vsync_end: u16,
431    pub vtotal: u16,
432    pub vscan: u16,
433    pub vrefresh: u32,
434    pub flags: u32,
435    pub typ: u32,
436    pub name: [core::ffi::c_char; 32],
437}
438
439pub const DRM_MODE_TYPE_PREFERRED: u32 = 1 << 3;
440pub const DRM_MODE_TYPE_USERDEF: u32 = 1 << 5;
441pub const DRM_MODE_TYPE_DRIVER: u32 = 1 << 6;
442
443#[repr(C)]
444#[derive(Debug)]
445pub struct DrmModeGetConnector {
446    encoders_ptr: u64,
447    modes_ptr: u64,
448    props_ptr: u64,
449    prop_values_ptr: u64,
450    count_modes: u32,
451    count_props: u32,
452    count_encoders: u32,
453    pub encoder_id: u32,
454    pub connector_id: u32,
455    pub connector_type: u32,
456    pub connector_type_id: u32,
457    pub connection: u32,
458    pub mm_width: u32,
459    pub mm_height: u32,
460    pub subpixel: u32,
461    #[doc(hidden)]
462    pub _pad: u32,
463}
464
465impl_zeroed!(DrmModeGetConnector);
466
467impl DrmModeGetConnector {
468    #[inline(always)]
469    pub unsafe fn set_encoders_ptr(&mut self, ptr: *mut u32, len: u32) {
470        self.encoders_ptr = ptr as u64;
471        self.count_encoders = len;
472    }
473
474    #[inline(always)]
475    pub fn clear_encoders_ptr(&mut self) {
476        self.encoders_ptr = 0;
477        self.count_encoders = 0;
478    }
479
480    #[inline(always)]
481    pub fn count_encoders(&self) -> u32 {
482        self.count_encoders
483    }
484
485    #[inline(always)]
486    pub unsafe fn set_modes_ptr(&mut self, ptr: *mut DrmModeInfo, len: u32) {
487        self.modes_ptr = ptr as u64;
488        self.count_modes = len;
489    }
490
491    #[inline(always)]
492    pub fn clear_modes_ptr(&mut self) {
493        self.modes_ptr = 0;
494        self.count_modes = 0;
495    }
496
497    #[inline(always)]
498    pub fn count_modes(&self) -> u32 {
499        self.count_modes
500    }
501
502    #[inline(always)]
503    pub unsafe fn set_props_ptrs(&mut self, ids_ptr: *mut u32, vals_ptr: *mut u64, len: u32) {
504        self.props_ptr = ids_ptr as u64;
505        self.prop_values_ptr = vals_ptr as u64;
506        self.count_props = len;
507    }
508
509    #[inline(always)]
510    pub fn clear_props_ptrs(&mut self) {
511        self.props_ptr = 0;
512        self.prop_values_ptr = 0;
513        self.count_props = 0;
514    }
515
516    #[inline(always)]
517    pub fn count_props(&self) -> u32 {
518        self.count_props
519    }
520}
521
522pub const DRM_IOCTL_MODE_GETCONNECTOR: IoctlReqWriteRead<DrmCardDevice, DrmModeGetConnector, int> =
523    unsafe { ioctl_writeread(_IOWR::<DrmModeGetConnector>(0xa7)) };
524
525#[repr(C)]
526#[derive(Debug)]
527pub struct DrmModeGetEncoder {
528    pub encoder_id: u32,
529    pub encoder_type: u32,
530    pub crtc_id: u32,
531    pub possible_crtcs: u32,
532    pub possible_clones: u32,
533}
534
535impl_zeroed!(DrmModeGetEncoder);
536
537pub const DRM_IOCTL_MODE_GETENCODER: IoctlReqWriteRead<DrmCardDevice, DrmModeGetEncoder, int> =
538    unsafe { ioctl_writeread(_IOWR::<DrmModeGetEncoder>(0xa6)) };
539
540#[repr(C)]
541#[derive(Debug)]
542pub struct DrmModeCrtc {
543    set_connectors_ptr: u64,
544    count_connectors: u32,
545    pub crtc_id: u32,
546    pub fb_id: u32,
547    pub x: u32,
548    pub y: u32,
549    pub gamma_size: u32,
550    pub mode_valid: u32,
551    pub mode: DrmModeInfo,
552}
553
554impl_zeroed!(DrmModeCrtc);
555
556impl DrmModeCrtc {
557    pub unsafe fn set_set_connectors_ptr(&mut self, ptr: *const u32, len: u32) {
558        self.set_connectors_ptr = ptr as u64;
559        self.count_connectors = len;
560    }
561
562    pub fn clear_set_connectors_ptr(&mut self) {
563        self.set_connectors_ptr = 0;
564        self.count_connectors = 0;
565    }
566}
567
568pub const DRM_IOCTL_MODE_GETCRTC: IoctlReqWriteRead<DrmCardDevice, DrmModeCrtc, int> =
569    unsafe { ioctl_writeread(_IOWR::<DrmModeCrtc>(0xa1)) };
570
571pub const DRM_IOCTL_MODE_SETCRTC: IoctlReqWriteRead<DrmCardDevice, DrmModeCrtc, int> =
572    unsafe { ioctl_writeread(_IOWR::<DrmModeCrtc>(0xa2)) };
573
574#[repr(C)]
575#[derive(Debug)]
576pub struct DrmModeCreateDumb {
577    pub height: u32,
578    pub width: u32,
579    pub bpp: u32,
580    pub flags: u32,
581    pub handle: u32,
582    pub pitch: u32,
583    pub size: u64,
584}
585
586impl_zeroed!(DrmModeCreateDumb);
587
588pub const DRM_IOCTL_MODE_CREATE_DUMB: IoctlReqWriteRead<DrmCardDevice, DrmModeCreateDumb, int> =
589    unsafe { ioctl_writeread(_IOWR::<DrmModeCreateDumb>(0xb2)) };
590
591#[repr(C)]
592#[derive(Debug)]
593pub struct DrmModeMapDumb {
594    pub handle: u32,
595    pub pad: u32,
596    pub offset: u64,
597}
598
599impl_zeroed!(DrmModeMapDumb);
600
601pub const DRM_IOCTL_MODE_MAP_DUMB: IoctlReqWriteRead<DrmCardDevice, DrmModeMapDumb, int> =
602    unsafe { ioctl_writeread(_IOWR::<DrmModeMapDumb>(0xb3)) };
603
604#[repr(C)]
605#[derive(Debug)]
606pub struct DrmModeDestroyDumb {
607    pub handle: u32,
608}
609
610impl_zeroed!(DrmModeDestroyDumb);
611
612pub const DRM_IOCTL_MODE_DESTROY_DUMB: IoctlReqWriteRead<DrmCardDevice, DrmModeDestroyDumb, int> =
613    unsafe { ioctl_writeread(_IOWR::<DrmModeDestroyDumb>(0xb4)) };
614
615#[repr(C)]
616#[derive(Debug)]
617pub struct DrmModeFbCmd {
618    pub fb_id: u32,
619    pub width: u32,
620    pub height: u32,
621    pub pitch: u32,
622    pub bpp: u32,
623    pub depth: u32,
624    pub handle: u32,
625}
626
627impl_zeroed!(DrmModeFbCmd);
628
629pub const DRM_IOCTL_MODE_GETFB: IoctlReqWriteRead<DrmCardDevice, DrmModeFbCmd, int> =
630    unsafe { ioctl_writeread(_IOWR::<DrmModeFbCmd>(0xad)) };
631
632pub const DRM_IOCTL_MODE_ADDFB: IoctlReqWriteRead<DrmCardDevice, DrmModeFbCmd, int> =
633    unsafe { ioctl_writeread(_IOWR::<DrmModeFbCmd>(0xae)) };
634
635pub const DRM_IOCTL_MODE_RMFB: IoctlReqWriteRead<DrmCardDevice, linux_unsafe::uint, int> =
636    unsafe { ioctl_writeread(_IOWR::<linux_unsafe::uint>(0xaf)) };
637
638#[repr(C)]
639#[derive(Debug)]
640pub struct DrmModeFbDirtyCmd {
641    pub fb_id: u32,
642    pub flags: u32,
643    pub color: u32,
644    num_clips: u32,
645    clips_ptr: u64,
646}
647
648impl_zeroed!(DrmModeFbDirtyCmd);
649
650impl DrmModeFbDirtyCmd {
651    #[inline(always)]
652    pub unsafe fn set_clips_ptr(&mut self, ptr: *const DrmClipRect, len: u32) {
653        self.clips_ptr = ptr as u64;
654        self.num_clips = len;
655    }
656
657    #[inline(always)]
658    pub fn clear_clips_ptr(&mut self) {
659        self.clips_ptr = 0;
660        self.num_clips = 0;
661    }
662}
663
664///
665/// Mark a region of a framebuffer as dirty.
666///
667/// Some hardware does not automatically update display contents
668/// as a hardware or software draw to a framebuffer. This ioctl
669/// allows userspace to tell the kernel and the hardware what
670/// regions of the framebuffer have changed.
671///
672/// The kernel or hardware is free to update more then just the
673/// region specified by the clip rects. The kernel or hardware
674/// may also delay and/or coalesce several calls to dirty into a
675/// single update.
676///
677/// Userspace may annotate the updates, the annotates are a
678/// promise made by the caller that the change is either a copy
679/// of pixels or a fill of a single color in the region specified.
680///
681/// If the [`DRM_MODE_FB_DIRTY_ANNOTATE_COPY`] flag is given then
682/// the number of updated regions are half of num_clips given,
683/// where the clip rects are paired in src and dst. The width and
684/// height of each one of the pairs must match.
685///
686/// If the [`DRM_MODE_FB_DIRTY_ANNOTATE_FILL`] flag is given the caller
687/// promises that the region specified of the clip rects is filled
688/// completely with a single color as given in the color argument.
689///
690pub const DRM_IOCTL_MODE_DIRTYFB: IoctlReqWriteRead<DrmCardDevice, DrmModeFbDirtyCmd, int> =
691    unsafe { ioctl_writeread(_IOWR::<DrmModeFbDirtyCmd>(0xb1)) };
692
693pub const DRM_MODE_FB_DIRTY_ANNOTATE_COPY: u32 = 0x01;
694pub const DRM_MODE_FB_DIRTY_ANNOTATE_FILL: u32 = 0x02;
695pub const DRM_MODE_FB_DIRTY_FLAGS: u32 = 0x03;
696pub const DRM_MODE_FB_DIRTY_MAX_CLIPS: u32 = 256;
697
698pub struct DrmClipRect {
699    pub x1: linux_unsafe::ushort,
700    pub y1: linux_unsafe::ushort,
701    pub x2: linux_unsafe::ushort,
702    pub y2: linux_unsafe::ushort,
703}
704
705#[repr(C)]
706#[derive(Debug)]
707pub struct DrmModeCrtcPageFlip {
708    pub crtc_id: u32,
709    pub fb_id: u32,
710    pub flags: u32,
711    /// Must always be set to zero.
712    pub reserved: u32,
713    pub user_data: u64,
714}
715
716impl_zeroed!(DrmModeCrtcPageFlip);
717
718/// Request a page flip on the specified crtc.
719///
720/// This ioctl will ask KMS to schedule a page flip for the specified
721/// crtc.  Once any pending rendering targeting the specified fb (as of
722/// ioctl time) has completed, the crtc will be reprogrammed to display
723/// that fb after the next vertical refresh.  The ioctl returns
724/// immediately, but subsequent rendering to the current fb will block
725/// in the execbuffer ioctl until the page flip happens.  If a page
726/// flip is already pending as the ioctl is called, EBUSY will be
727/// returned.
728///
729/// Flag [`DRM_MODE_PAGE_FLIP_EVENT`] requests that drm sends back a vblank
730/// event (see drm.h: struct drm_event_vblank) when the page flip is
731/// done.  The user_data field passed in with this ioctl will be
732/// returned as the user_data field in the vblank event struct.
733///
734/// Flag [`DRM_MODE_PAGE_FLIP_ASYNC`] requests that the flip happen
735/// 'as soon as possible', meaning that it not delay waiting for vblank.
736/// This may cause tearing on the screen.
737///
738/// The reserved field must be zero.
739pub const DRM_IOCTL_MODE_PAGE_FLIP: IoctlReqWriteRead<DrmCardDevice, DrmModeCrtcPageFlip, int> =
740    unsafe { ioctl_writeread(_IOWR::<DrmModeCrtcPageFlip>(0xb0)) };
741
742/// Request that the kernel sends back a vblank event (see
743/// struct drm_event_vblank) with the [`crate::event::raw::DRM_EVENT_FLIP_COMPLETE`]
744/// type when the page-flip is done.
745pub const DRM_MODE_PAGE_FLIP_EVENT: u32 = 0x01;
746/// Request that the page-flip is performed as soon as possible, ie. with no
747/// delay due to waiting for vblank. This may cause tearing to be visible on
748/// the screen.
749///
750/// When used with atomic uAPI, the driver will return an error if the hardware
751/// doesn't support performing an asynchronous page-flip for this update.
752/// User-space should handle this, e.g. by falling back to a regular page-flip.
753///
754/// Note, some hardware might need to perform one last synchronous page-flip
755/// before being able to switch to asynchronous page-flips. As an exception,
756/// the driver will return success even though that first page-flip is not
757/// asynchronous.
758pub const DRM_MODE_PAGE_FLIP_ASYNC: u32 = 0x02;
759pub const DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE: u32 = 0x4;
760pub const DRM_MODE_PAGE_FLIP_TARGET_RELATIVE: u32 = 0x8;
761pub const DRM_MODE_PAGE_FLIP_TARGET: u32 =
762    DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE;
763/// Bitmask of flags suitable for [`DrmModeCrtcPageFlip::flags`].
764pub const DRM_MODE_PAGE_FLIP_FLAGS: u32 =
765    DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_ASYNC | DRM_MODE_PAGE_FLIP_TARGET;
766
767pub const DRM_MODE_CURSOR_BO: u32 = 0x01;
768pub const DRM_MODE_CURSOR_MOVE: u32 = 0x02;
769pub const DRM_MODE_CURSOR_FLAGS: u32 = 0x03;
770
771#[repr(C)]
772#[derive(Debug)]
773pub struct DrmModeAtomic {
774    pub flags: u32,
775    count_objs: u32,
776    objs_ptr: u64,
777    count_props_ptr: u64,
778    props_ptr: u64,
779    prop_values_ptr: u64,
780    pub reserved: u64,
781    pub user_data: u64,
782}
783
784pub struct DrmModeAtomicPtrs {
785    pub objs_ptr: *const u32,
786    pub count_props_ptr: *const u32,
787    pub count_objs: u32,
788
789    pub props_ptr: *const u32,
790    pub prop_values_ptr: *const u64,
791}
792
793impl_zeroed!(DrmModeAtomic);
794
795impl DrmModeAtomic {
796    #[inline(always)]
797    pub unsafe fn set_ptrs(&mut self, ptrs: DrmModeAtomicPtrs) {
798        self.objs_ptr = ptrs.objs_ptr as u64;
799        self.count_props_ptr = ptrs.count_props_ptr as u64;
800        self.count_objs = ptrs.count_objs;
801        self.props_ptr = ptrs.props_ptr as u64;
802        self.prop_values_ptr = ptrs.prop_values_ptr as u64;
803    }
804
805    #[inline(always)]
806    pub unsafe fn clear_ptrs(&mut self) {
807        self.objs_ptr = 0;
808        self.count_props_ptr = 0;
809        self.count_objs = 0;
810        self.props_ptr = 0;
811        self.prop_values_ptr = 0;
812    }
813}
814
815pub const DRM_IOCTL_MODE_ATOMIC: IoctlReqWriteRead<DrmCardDevice, DrmModeAtomic, int> =
816    unsafe { ioctl_writeread(_IOWR::<DrmModeAtomic>(0xbc)) };
817
818/// Do not apply the atomic commit, and instead check whether the hardware supports
819/// this configuration.
820pub const DRM_MODE_ATOMIC_TEST_ONLY: u32 = 0x0100;
821
822/// Do not block while applying the atomic commit. The [`DRM_IOCTL_MODE_ATOMIC`]
823/// request returns immediately instead of waiting for the changes to be applied
824/// in hardware. Note, the driver will still check whether the update can be
825/// applied before retuning.
826pub const DRM_MODE_ATOMIC_NONBLOCK: u32 = 0x0200;
827
828/// Allow the update to result in temporary or transient visible artifacts while
829/// the update is being applied. Applying the update may also take significantly
830/// more time than a page flip. All visual artifacts will disappear by the time
831/// the update is completed, as signalled through the vblank event's timestamp.
832///
833/// This flag must be set when the KMS update might cause visible artifacts.
834/// Without this flag such KMS update will return an `EINVAL` error. What kind of
835/// update may cause visible artifacts depends on the driver and the hardware.
836/// User-space that needs to know beforehand if an update might cause visible
837/// artifacts can use [`DRM_MODE_ATOMIC_TEST_ONLY`] without
838/// [`DRM_MODE_ATOMIC_ALLOW_MODESET`] to see if it fails.
839///
840/// To the best of the driver's knowledge, visual artifacts are guaranteed to
841/// not appear when this flag is not set. Some sinks might display visual
842/// artifacts outside of the driver's control.
843pub const DRM_MODE_ATOMIC_ALLOW_MODESET: u32 = 0x0400;
844
845/// Bitfield of flags accepted by [`DRM_IOCTL_MODE_ATOMIC`] in
846/// [`DrmModeAtomic::flags`].
847pub const DRM_MODE_ATOMIC_FLAGS: u32 = DRM_MODE_PAGE_FLIP_EVENT
848    | DRM_MODE_PAGE_FLIP_ASYNC
849    | DRM_MODE_ATOMIC_TEST_ONLY
850    | DRM_MODE_ATOMIC_NONBLOCK
851    | DRM_MODE_ATOMIC_ALLOW_MODESET;
852
853#[repr(C)]
854#[derive(Debug)]
855pub struct DrmModeObjGetProperties {
856    props_ptr: u64,
857    prop_values_ptr: u64,
858    count_props: u32,
859    pub obj_id: u32,
860    pub obj_type: u32,
861}
862
863impl_zeroed!(DrmModeObjGetProperties);
864
865impl DrmModeObjGetProperties {
866    pub unsafe fn set_prop_ptrs(&mut self, ids_ptr: *mut u32, values_ptr: *mut u64, len: u32) {
867        self.props_ptr = ids_ptr as u64;
868        self.prop_values_ptr = values_ptr as u64;
869        self.count_props = len;
870    }
871
872    pub fn clear_prop_attrs(&mut self) {
873        self.props_ptr = 0;
874        self.prop_values_ptr = 0;
875        self.count_props = 0;
876    }
877
878    pub fn count_props(&self) -> u32 {
879        self.count_props
880    }
881}
882
883pub const DRM_IOCTL_MODE_OBJ_GETPROPERTIES: IoctlReqWriteRead<
884    DrmCardDevice,
885    DrmModeObjGetProperties,
886    int,
887> = unsafe { ioctl_writeread(_IOWR::<DrmModeObjGetProperties>(0xb9)) };
888
889#[repr(C)]
890#[derive(Debug)]
891pub struct DrmModeObjSetProperty {
892    pub value: u64,
893    pub prop_id: u32,
894    pub obj_id: u32,
895    pub obj_type: u32,
896}
897
898impl_zeroed!(DrmModeObjSetProperty);
899
900pub const DRM_IOCTL_MODE_OBJ_SETPROPERTY: IoctlReqWriteRead<
901    DrmCardDevice,
902    DrmModeObjSetProperty,
903    int,
904> = unsafe { ioctl_writeread(_IOWR::<DrmModeObjSetProperty>(0xba)) };
905
906pub const DRM_MODE_OBJECT_CRTC: u32 = 0xcccccccc;
907pub const DRM_MODE_OBJECT_CONNECTOR: u32 = 0xc0c0c0c0;
908pub const DRM_MODE_OBJECT_ENCODER: u32 = 0xe0e0e0e0;
909pub const DRM_MODE_OBJECT_MODE: u32 = 0xdededede;
910pub const DRM_MODE_OBJECT_PROPERTY: u32 = 0xb0b0b0b0;
911pub const DRM_MODE_OBJECT_FB: u32 = 0xfbfbfbfb;
912pub const DRM_MODE_OBJECT_BLOB: u32 = 0xbbbbbbbb;
913pub const DRM_MODE_OBJECT_PLANE: u32 = 0xeeeeeeee;
914pub const DRM_MODE_OBJECT_ANY: u32 = 0;
915
916#[repr(C)]
917#[derive(Debug)]
918pub struct DrmModeGetPlaneRes {
919    plane_id_ptr: u64,
920    count_planes: u32,
921}
922
923impl_zeroed!(DrmModeGetPlaneRes);
924
925impl DrmModeGetPlaneRes {
926    #[inline(always)]
927    pub unsafe fn set_plane_id_ptr(&mut self, ptr: *mut u32, len: u32) {
928        self.plane_id_ptr = ptr as u64;
929        self.count_planes = len;
930    }
931
932    #[inline(always)]
933    pub fn clear_plane_id_ptr(&mut self) {
934        self.plane_id_ptr = 0;
935        self.count_planes = 0;
936    }
937
938    #[inline(always)]
939    pub fn count_planes(&self) -> u32 {
940        self.count_planes
941    }
942}
943
944pub const DRM_IOCTL_MODE_GETPLANERESOURCES: IoctlReqWriteRead<
945    DrmCardDevice,
946    DrmModeGetPlaneRes,
947    int,
948> = unsafe { ioctl_writeread(_IOWR::<DrmModeGetPlaneRes>(0xb5)) };
949
950#[repr(C)]
951#[derive(Debug)]
952pub struct DrmModeGetPlane {
953    pub plane_id: u32,
954    pub crtc_id: u32,
955    pub fb_id: u32,
956    pub possible_crtcs: u32,
957    pub gamma_size: u32,
958    count_format_types: u32,
959    format_type_ptr: u64,
960}
961
962impl_zeroed!(DrmModeGetPlane);
963
964impl DrmModeGetPlane {
965    #[inline(always)]
966    pub unsafe fn set_format_type_ptr(&mut self, ptr: *mut u32, len: u32) {
967        self.format_type_ptr = ptr as u64;
968        self.count_format_types = len;
969    }
970
971    #[inline(always)]
972    pub fn clear_format_type_ptr(&mut self) {
973        self.format_type_ptr = 0;
974        self.count_format_types = 0;
975    }
976
977    #[inline(always)]
978    pub fn count_format_types(&self) -> u32 {
979        self.count_format_types
980    }
981}
982
983pub const DRM_IOCTL_MODE_GETPLANE: IoctlReqWriteRead<DrmCardDevice, DrmModeGetPlane, int> =
984    unsafe { ioctl_writeread(_IOWR::<DrmModeGetPlane>(0xb6)) };
985
986#[repr(C)]
987#[derive(Debug)]
988pub struct DrmModeSetPlane {
989    pub plane_id: u32,
990    pub crtc_id: u32,
991    pub fb_id: u32, // fb object contains surface format type
992    pub flags: u32, // DRM_MODE_PRESENT_ flags
993
994    pub crtc_x: i32,
995    pub crtc_y: i32,
996    pub crtc_w: u32,
997    pub crtc_h: u32,
998
999    pub src_x: fixedu16_16,
1000    pub src_y: fixedu16_16,
1001    pub src_h: fixedu16_16,
1002    pub src_w: fixedu16_16,
1003}
1004
1005impl_zeroed!(DrmModeSetPlane);
1006
1007pub const DRM_IOCTL_MODE_SETPLANE: IoctlReqWriteRead<DrmCardDevice, DrmModeSetPlane, int> =
1008    unsafe { ioctl_writeread(_IOWR::<DrmModeSetPlane>(0xb7)) };
1009
1010pub const DRM_MODE_PRESENT_TOP_FIELD: u32 = 1 << 0;
1011pub const DRM_MODE_PRESENT_BOTTOM_FIELD: u32 = 1 << 1;
1012
1013#[repr(C)]
1014#[derive(Debug, Clone)]
1015pub struct DrmModeGetProperty {
1016    values_ptr: u64,
1017    enum_blob_ptr: u64,
1018    pub prop_id: u32,
1019    pub flags: u32,
1020    pub name: [u8; DRM_PROP_NAME_LEN],
1021    count_values: u32,
1022    count_enum_blobs: u32,
1023}
1024
1025impl_zeroed!(DrmModeGetProperty);
1026
1027impl DrmModeGetProperty {
1028    /// Set the `values_ptr` and `count_values` fields.
1029    ///
1030    /// # Safety
1031    ///
1032    /// `ptr` must point to an array of `u64` with at least length `len`, and
1033    /// that pointer must remain valid throughout any subsequent ioctl calls
1034    /// using this object.
1035    #[inline(always)]
1036    pub unsafe fn set_values_ptr(&mut self, ptr: *mut u64, len: u32) {
1037        self.values_ptr = ptr as u64;
1038        self.count_values = len;
1039    }
1040
1041    #[inline(always)]
1042    pub fn clear_values_ptr(&mut self) {
1043        self.values_ptr = 0;
1044        self.count_values = 0;
1045    }
1046
1047    #[inline(always)]
1048    pub fn count_values(&self) -> u32 {
1049        self.count_values
1050    }
1051
1052    /// Set the `values_ptr` and `count_values` fields.
1053    ///
1054    /// # Safety
1055    ///
1056    /// `ptr` must point to an array of `DrmModePropertyEnum` with at least
1057    /// length `len`, and that pointer must remain valid throughout any
1058    /// subsequent ioctl calls using this object.
1059    #[inline(always)]
1060    pub unsafe fn set_enum_blob_ptr(&mut self, ptr: *mut DrmModePropertyEnum, len: u32) {
1061        self.enum_blob_ptr = ptr as u64;
1062        self.count_enum_blobs = len;
1063    }
1064
1065    #[inline(always)]
1066    pub fn clear_enum_blob_ptr(&mut self) {
1067        self.enum_blob_ptr = 0;
1068        self.count_enum_blobs = 0;
1069    }
1070
1071    #[inline(always)]
1072    pub fn count_enum_blobs(&self) -> u32 {
1073        self.count_enum_blobs
1074    }
1075}
1076
1077#[repr(C)]
1078#[derive(Debug, Clone)]
1079pub struct DrmModePropertyEnum {
1080    pub value: u64,
1081    pub name: [u8; DRM_PROP_NAME_LEN],
1082}
1083
1084impl_zeroed!(DrmModePropertyEnum);
1085
1086/// User-space can perform a `GETPROPERTY` request to retrieve information about a
1087/// property. The same property may be attached to multiple objects.
1088///
1089/// The meaning of [`DrmModeGetProperty::values_ptr`] changes depending on the
1090/// property type.
1091///
1092/// [`DrmModeGetProperty::enum_blob_ptr`] and [`DrmModeGetProperty::count_enum_blobs`]
1093/// are only meaningful when the property has the type [`DRM_MODE_PROP_ENUM`] or
1094/// [`DRM_MODE_PROP_BITMASK`]. For backwards compatibility, the kernel will always set
1095/// [`DrmModeGetProperty::count_enum_blobs`] to
1096/// zero when the property has the type [`DRM_MODE_PROP_BLOB`]. User-space must
1097/// ignore these two fields if the property has a different type.
1098///
1099/// Userspace is expected to retrieve values and enums by performing this request
1100/// at least twice: the first time to retrieve the number of elements, the
1101/// second time to retrieve the elements themselves.
1102///
1103/// To retrieve the number of elements, set [`DrmModeGetProperty::count_values`]
1104/// and [`DrmModeGetProperty::count_enum_blobs`] to zero. [`DrmModeGetProperty::count_values`]
1105/// will be updated with the number of elements. If the property has the type
1106/// [`DRM_MODE_PROP_ENUM`] or [`DRM_MODE_PROP_BITMASK`], [`DrmModeGetProperty::count_enum_blobs`]
1107/// will be updated as well.
1108///
1109/// To retrieve the elements themselves, allocate an array for
1110/// [`DrmModeGetProperty::values_ptr`] and set [`DrmModeGetProperty::count_values`] to
1111/// its capacity. If the property has the type [`DRM_MODE_PROP_ENUM`] or [`DRM_MODE_PROP_BITMASK`],
1112/// allocate an array for [`DrmModeGetProperty::enum_blob_ptr`] and set
1113/// [`DrmModeGetProperty::count_enum_blobs`] to its capacity. Sending the request
1114/// again will then fill the arrays.
1115pub const DRM_IOCTL_MODE_GETPROPERTY: IoctlReqWriteRead<DrmCardDevice, DrmModeGetProperty, int> =
1116    unsafe { ioctl_writeread(_IOWR::<DrmModeGetProperty>(0xaa)) };
1117
1118pub const DRM_PROP_NAME_LEN: usize = 32;
1119
1120pub const DRM_MODE_PROP_PENDING: u32 = 1 << 0;
1121pub const DRM_MODE_PROP_RANGE: u32 = 1 << 1;
1122pub const DRM_MODE_PROP_IMMUTABLE: u32 = 1 << 2;
1123pub const DRM_MODE_PROP_ENUM: u32 = 1 << 3;
1124pub const DRM_MODE_PROP_BLOB: u32 = 1 << 4;
1125pub const DRM_MODE_PROP_BITMASK: u32 = 1 << 5;
1126pub const DRM_MODE_PROP_LEGACY_TYPE: u32 =
1127    DRM_MODE_PROP_RANGE | DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BLOB | DRM_MODE_PROP_BITMASK;
1128pub const DRM_MODE_PROP_EXTENDED_TYPE: u32 = 0x0000ffc0;
1129pub const DRM_MODE_PROP_OBJECT: u32 = DRM_MODE_PROP_TYPE(1);
1130pub const DRM_MODE_PROP_SIGNED_RANGE: u32 = DRM_MODE_PROP_TYPE(2);
1131
1132#[allow(non_snake_case)]
1133#[inline(always)]
1134pub const fn DRM_MODE_PROP_TYPE(n: u32) -> u32 {
1135    n << 6
1136}
1137
1138#[repr(C)]
1139#[derive(Debug)]
1140pub struct DrmModeCreateBlob {
1141    data: u64,
1142    length: u32,
1143    pub blob_id: u32,
1144}
1145
1146impl_zeroed!(DrmModeCreateBlob);
1147
1148impl DrmModeCreateBlob {
1149    /// Set the `data` and `length` fields.
1150    ///
1151    /// # Safety
1152    ///
1153    /// `ptr` must point to the start of an array of bytes of length `len`,
1154    /// and that pointer must remain valid throughout any subsequent ioctl
1155    /// calls using this object.
1156    pub unsafe fn set_data(&mut self, ptr: *const u8, len: u32) {
1157        self.data = ptr as u64;
1158        self.length = len;
1159    }
1160
1161    pub fn clear_data(&mut self) {
1162        self.data = 0;
1163        self.length = 0;
1164    }
1165}
1166
1167pub const DRM_IOCTL_MODE_CREATEPROPBLOB: IoctlReqWriteRead<DrmCardDevice, DrmModeCreateBlob, int> =
1168    unsafe { ioctl_writeread(_IOWR::<DrmModeCreateBlob>(0xbd)) };
1169
1170#[repr(C)]
1171#[derive(Debug)]
1172pub struct DrmModeDestroyBlob {
1173    pub blob_id: u32,
1174}
1175
1176impl_zeroed!(DrmModeDestroyBlob);
1177
1178pub const DRM_IOCTL_MODE_DESTROYPROPBLOB: IoctlReqWriteRead<
1179    DrmCardDevice,
1180    DrmModeDestroyBlob,
1181    int,
1182> = unsafe { ioctl_writeread(_IOWR::<DrmModeDestroyBlob>(0xbe)) };