drm_ffi/
mode.rs

1//!
2//! Bindings to the DRM's modesetting capabilities.
3//!
4
5#![allow(clippy::too_many_arguments)]
6
7use crate::ioctl;
8use drm_sys::*;
9
10use std::{io, os::unix::io::BorrowedFd};
11
12/// Enumerate most card resources.
13pub fn get_resources(
14    fd: BorrowedFd<'_>,
15    mut fbs: Option<&mut Vec<u32>>,
16    mut crtcs: Option<&mut Vec<u32>>,
17    mut connectors: Option<&mut Vec<u32>>,
18    mut encoders: Option<&mut Vec<u32>>,
19) -> io::Result<drm_mode_card_res> {
20    let mut sizes = drm_mode_card_res::default();
21    unsafe {
22        ioctl::mode::get_resources(fd, &mut sizes)?;
23    }
24
25    map_reserve!(fbs, sizes.count_fbs as usize);
26    map_reserve!(crtcs, sizes.count_crtcs as usize);
27    map_reserve!(connectors, sizes.count_connectors as usize);
28    map_reserve!(encoders, sizes.count_encoders as usize);
29
30    let mut res = drm_mode_card_res {
31        fb_id_ptr: map_ptr!(&fbs),
32        crtc_id_ptr: map_ptr!(&crtcs),
33        connector_id_ptr: map_ptr!(&connectors),
34        encoder_id_ptr: map_ptr!(&encoders),
35        count_fbs: map_len!(&fbs),
36        count_crtcs: map_len!(&crtcs),
37        count_connectors: map_len!(&connectors),
38        count_encoders: map_len!(&encoders),
39        ..Default::default()
40    };
41
42    unsafe {
43        ioctl::mode::get_resources(fd, &mut res)?;
44    }
45
46    map_set!(fbs, res.count_fbs as usize);
47    map_set!(crtcs, res.count_crtcs as usize);
48    map_set!(connectors, res.count_connectors as usize);
49    map_set!(encoders, res.count_encoders as usize);
50
51    Ok(res)
52}
53
54/// Enumerate plane resources.
55pub fn get_plane_resources(
56    fd: BorrowedFd<'_>,
57    mut planes: Option<&mut Vec<u32>>,
58) -> io::Result<drm_mode_get_plane_res> {
59    let mut sizes = drm_mode_get_plane_res::default();
60    unsafe {
61        ioctl::mode::get_plane_resources(fd, &mut sizes)?;
62    }
63
64    if planes.is_none() {
65        return Ok(sizes);
66    }
67
68    map_reserve!(planes, sizes.count_planes as usize);
69
70    let mut res = drm_mode_get_plane_res {
71        plane_id_ptr: map_ptr!(&planes),
72        count_planes: sizes.count_planes,
73    };
74
75    unsafe {
76        ioctl::mode::get_plane_resources(fd, &mut res)?;
77    }
78
79    map_set!(planes, res.count_planes as usize);
80
81    Ok(res)
82}
83
84/// Get info about a framebuffer.
85pub fn get_framebuffer(fd: BorrowedFd<'_>, fb_id: u32) -> io::Result<drm_mode_fb_cmd> {
86    let mut info = drm_mode_fb_cmd {
87        fb_id,
88        ..Default::default()
89    };
90
91    unsafe {
92        ioctl::mode::get_fb(fd, &mut info)?;
93    }
94
95    Ok(info)
96}
97
98/// Add a new framebuffer.
99pub fn add_fb(
100    fd: BorrowedFd<'_>,
101    width: u32,
102    height: u32,
103    pitch: u32,
104    bpp: u32,
105    depth: u32,
106    handle: u32,
107) -> io::Result<drm_mode_fb_cmd> {
108    let mut fb = drm_mode_fb_cmd {
109        width,
110        height,
111        pitch,
112        bpp,
113        depth,
114        handle,
115        ..Default::default()
116    };
117
118    unsafe {
119        ioctl::mode::add_fb(fd, &mut fb)?;
120    }
121
122    Ok(fb)
123}
124
125/// Get info about a framebuffer (with modifiers).
126pub fn get_framebuffer2(fd: BorrowedFd<'_>, fb_id: u32) -> io::Result<drm_mode_fb_cmd2> {
127    let mut info = drm_mode_fb_cmd2 {
128        fb_id,
129        ..Default::default()
130    };
131
132    unsafe {
133        ioctl::mode::get_fb2(fd, &mut info)?;
134    }
135
136    Ok(info)
137}
138
139/// Add a new framebuffer (with modifiers)
140pub fn add_fb2(
141    fd: BorrowedFd<'_>,
142    width: u32,
143    height: u32,
144    fmt: u32,
145    handles: &[u32; 4],
146    pitches: &[u32; 4],
147    offsets: &[u32; 4],
148    modifier: &[u64; 4],
149    flags: u32,
150) -> io::Result<drm_mode_fb_cmd2> {
151    let mut fb = drm_mode_fb_cmd2 {
152        width,
153        height,
154        pixel_format: fmt,
155        flags,
156        handles: *handles,
157        pitches: *pitches,
158        offsets: *offsets,
159        modifier: *modifier,
160        ..Default::default()
161    };
162
163    unsafe {
164        ioctl::mode::add_fb2(fd, &mut fb)?;
165    }
166
167    Ok(fb)
168}
169
170/// Remove a framebuffer.
171pub fn rm_fb(fd: BorrowedFd<'_>, mut id: u32) -> io::Result<()> {
172    unsafe {
173        ioctl::mode::rm_fb(fd, &mut id)?;
174    }
175
176    Ok(())
177}
178
179/// Mark a framebuffer as dirty.
180pub fn dirty_fb(
181    fd: BorrowedFd<'_>,
182    fb_id: u32,
183    clips: &[drm_clip_rect],
184) -> io::Result<drm_mode_fb_dirty_cmd> {
185    let mut dirty = drm_mode_fb_dirty_cmd {
186        fb_id,
187        num_clips: clips.len() as _,
188        clips_ptr: clips.as_ptr() as _,
189        ..Default::default()
190    };
191
192    unsafe {
193        ioctl::mode::dirty_fb(fd, &mut dirty)?;
194    }
195
196    Ok(dirty)
197}
198
199/// Get info about a CRTC
200pub fn get_crtc(fd: BorrowedFd<'_>, crtc_id: u32) -> io::Result<drm_mode_crtc> {
201    let mut info = drm_mode_crtc {
202        crtc_id,
203        ..Default::default()
204    };
205
206    unsafe {
207        ioctl::mode::get_crtc(fd, &mut info)?;
208    }
209
210    Ok(info)
211}
212
213/// Set CRTC state
214pub fn set_crtc(
215    fd: BorrowedFd<'_>,
216    crtc_id: u32,
217    fb_id: u32,
218    x: u32,
219    y: u32,
220    conns: &[u32],
221    mode: Option<drm_mode_modeinfo>,
222) -> io::Result<drm_mode_crtc> {
223    let mut crtc = drm_mode_crtc {
224        set_connectors_ptr: conns.as_ptr() as _,
225        count_connectors: conns.len() as _,
226        crtc_id,
227        fb_id,
228        x,
229        y,
230        mode_valid: match mode {
231            Some(_) => 1,
232            None => 0,
233        },
234        mode: mode.unwrap_or_default(),
235        ..Default::default()
236    };
237
238    unsafe {
239        ioctl::mode::set_crtc(fd, &mut crtc)?;
240    }
241
242    Ok(crtc)
243}
244
245/// Get CRTC gamma ramp
246pub fn get_gamma(
247    fd: BorrowedFd<'_>,
248    crtc_id: u32,
249    size: usize,
250    red: &mut [u16],
251    green: &mut [u16],
252    blue: &mut [u16],
253) -> io::Result<drm_mode_crtc_lut> {
254    let mut lut = drm_mode_crtc_lut {
255        crtc_id,
256        gamma_size: size as _,
257        red: red.as_mut_ptr() as _,
258        green: green.as_mut_ptr() as _,
259        blue: blue.as_mut_ptr() as _,
260    };
261
262    unsafe {
263        ioctl::mode::get_gamma(fd, &mut lut)?;
264    }
265
266    Ok(lut)
267}
268
269/// Set CRTC gamma ramp
270pub fn set_gamma(
271    fd: BorrowedFd<'_>,
272    crtc_id: u32,
273    size: usize,
274    red: &[u16],
275    green: &[u16],
276    blue: &[u16],
277) -> io::Result<drm_mode_crtc_lut> {
278    let mut lut = drm_mode_crtc_lut {
279        crtc_id,
280        gamma_size: size as _,
281        red: red.as_ptr() as _,
282        green: green.as_ptr() as _,
283        blue: blue.as_ptr() as _,
284    };
285
286    unsafe {
287        ioctl::mode::set_gamma(fd, &mut lut)?;
288    }
289
290    Ok(lut)
291}
292
293/// Set cursor state
294///
295/// The buffer must be allocated using the buffer manager of the driver (GEM or TTM). It is not
296/// allowed to be a dumb buffer.
297#[deprecated = "use a cursor plane instead"]
298pub fn set_cursor(
299    fd: BorrowedFd<'_>,
300    crtc_id: u32,
301    buf_id: u32,
302    width: u32,
303    height: u32,
304) -> io::Result<drm_mode_cursor> {
305    let mut cursor = drm_mode_cursor {
306        flags: DRM_MODE_CURSOR_BO,
307        crtc_id,
308        width,
309        height,
310        handle: buf_id,
311        ..Default::default()
312    };
313
314    unsafe {
315        ioctl::mode::cursor(fd, &mut cursor)?;
316    }
317
318    Ok(cursor)
319}
320
321/// Set cursor state (with hotspot position)
322///
323/// The buffer must be allocated using the buffer manager of the driver (GEM or TTM). It is not
324/// allowed to be a dumb buffer.
325///
326/// The hotspot position is used to coordinate the guest and host cursor location in case of
327/// virtualization.
328#[deprecated = "use a cursor plane instead"]
329pub fn set_cursor2(
330    fd: BorrowedFd<'_>,
331    crtc_id: u32,
332    buf_id: u32,
333    width: u32,
334    height: u32,
335    hot_x: i32,
336    hot_y: i32,
337) -> io::Result<drm_mode_cursor2> {
338    let mut cursor = drm_mode_cursor2 {
339        flags: DRM_MODE_CURSOR_BO,
340        crtc_id,
341        width,
342        height,
343        handle: buf_id,
344        hot_x,
345        hot_y,
346        ..Default::default()
347    };
348
349    unsafe {
350        ioctl::mode::cursor2(fd, &mut cursor)?;
351    }
352
353    Ok(cursor)
354}
355
356/// Move cursor
357#[deprecated = "use a cursor plane instead"]
358pub fn move_cursor(
359    fd: BorrowedFd<'_>,
360    crtc_id: u32,
361    x: i32,
362    y: i32,
363) -> io::Result<drm_mode_cursor> {
364    let mut cursor = drm_mode_cursor {
365        flags: DRM_MODE_CURSOR_MOVE,
366        crtc_id,
367        x,
368        y,
369        ..Default::default()
370    };
371
372    unsafe {
373        ioctl::mode::cursor(fd, &mut cursor)?;
374    }
375
376    Ok(cursor)
377}
378
379/// Get info about a connector
380pub fn get_connector(
381    fd: BorrowedFd<'_>,
382    connector_id: u32,
383    mut props: Option<&mut Vec<u32>>,
384    mut prop_values: Option<&mut Vec<u64>>,
385    mut modes: Option<&mut Vec<drm_mode_modeinfo>>,
386    mut encoders: Option<&mut Vec<u32>>,
387    force_probe: bool,
388) -> io::Result<drm_mode_get_connector> {
389    assert_eq!(props.is_some(), prop_values.is_some());
390
391    let tmp_mode = drm_mode_modeinfo::default();
392    let mut sizes = drm_mode_get_connector {
393        connector_id,
394        modes_ptr: if force_probe {
395            0
396        } else {
397            &tmp_mode as *const _ as _
398        },
399        count_modes: if force_probe { 0 } else { 1 },
400        ..Default::default()
401    };
402
403    unsafe {
404        ioctl::mode::get_connector(fd, &mut sizes)?;
405    }
406
407    let info = loop {
408        map_reserve!(props, sizes.count_props as usize);
409        map_reserve!(prop_values, sizes.count_props as usize);
410        map_reserve!(modes, sizes.count_modes as usize);
411        map_reserve!(encoders, sizes.count_encoders as usize);
412
413        let mut info = drm_mode_get_connector {
414            connector_id,
415            encoders_ptr: map_ptr!(&encoders),
416            modes_ptr: match &mut modes {
417                Some(b) => b.as_mut_ptr() as _,
418                None => {
419                    if force_probe {
420                        0 as _
421                    } else {
422                        &tmp_mode as *const _ as _
423                    }
424                }
425            },
426            props_ptr: map_ptr!(&props),
427            prop_values_ptr: map_ptr!(&prop_values),
428            count_modes: match &modes {
429                Some(b) => b.capacity() as _,
430                None => {
431                    if force_probe {
432                        0
433                    } else {
434                        1
435                    }
436                }
437            },
438            count_props: map_len!(&props),
439            count_encoders: map_len!(&encoders),
440            ..Default::default()
441        };
442
443        unsafe {
444            ioctl::mode::get_connector(fd, &mut info)?;
445        }
446
447        if info.count_modes == sizes.count_modes
448            && info.count_encoders == sizes.count_encoders
449            && info.count_props == sizes.count_props
450        {
451            break info;
452        } else {
453            sizes = info;
454        }
455    };
456
457    map_set!(modes, info.count_modes as usize);
458    map_set!(props, info.count_props as usize);
459    map_set!(prop_values, info.count_props as usize);
460    map_set!(encoders, info.count_encoders as usize);
461
462    Ok(info)
463}
464
465/// Get info about an encoder
466pub fn get_encoder(fd: BorrowedFd<'_>, encoder_id: u32) -> io::Result<drm_mode_get_encoder> {
467    let mut info = drm_mode_get_encoder {
468        encoder_id,
469        ..Default::default()
470    };
471
472    unsafe {
473        ioctl::mode::get_encoder(fd, &mut info)?;
474    }
475
476    Ok(info)
477}
478
479/// Get info about a plane.
480pub fn get_plane(
481    fd: BorrowedFd<'_>,
482    plane_id: u32,
483    mut formats: Option<&mut Vec<u32>>,
484) -> io::Result<drm_mode_get_plane> {
485    let mut sizes = drm_mode_get_plane {
486        plane_id,
487        ..Default::default()
488    };
489
490    unsafe {
491        ioctl::mode::get_plane(fd, &mut sizes)?;
492    }
493
494    if formats.is_none() {
495        return Ok(sizes);
496    }
497
498    map_reserve!(formats, sizes.count_format_types as usize);
499
500    let mut info = drm_mode_get_plane {
501        plane_id,
502        count_format_types: sizes.count_format_types,
503        format_type_ptr: map_ptr!(&formats),
504        ..Default::default()
505    };
506
507    unsafe {
508        ioctl::mode::get_plane(fd, &mut info)?;
509    }
510
511    map_set!(formats, info.count_format_types as usize);
512
513    Ok(info)
514}
515
516/// Set plane state.
517pub fn set_plane(
518    fd: BorrowedFd<'_>,
519    plane_id: u32,
520    crtc_id: u32,
521    fb_id: u32,
522    flags: u32,
523    crtc_x: i32,
524    crtc_y: i32,
525    crtc_w: u32,
526    crtc_h: u32,
527    src_x: u32,
528    src_y: u32,
529    src_w: u32,
530    src_h: u32,
531) -> io::Result<drm_mode_set_plane> {
532    let mut plane = drm_mode_set_plane {
533        plane_id,
534        crtc_id,
535        fb_id,
536        flags,
537        crtc_x,
538        crtc_y,
539        crtc_w,
540        crtc_h,
541        src_x,
542        src_y,
543        src_h,
544        src_w,
545    };
546
547    unsafe {
548        ioctl::mode::set_plane(fd, &mut plane)?;
549    }
550
551    Ok(plane)
552}
553
554/// Get property
555pub fn get_property(
556    fd: BorrowedFd<'_>,
557    prop_id: u32,
558    mut values: Option<&mut Vec<u64>>,
559    mut enums: Option<&mut Vec<drm_mode_property_enum>>,
560) -> io::Result<drm_mode_get_property> {
561    let mut prop = drm_mode_get_property {
562        prop_id,
563        ..Default::default()
564    };
565
566    unsafe {
567        ioctl::mode::get_property(fd, &mut prop)?;
568    }
569
570    // There is no need to call get_property() twice if there is nothing else to retrieve.
571    if prop.count_values == 0 && prop.count_enum_blobs == 0 {
572        return Ok(prop);
573    }
574
575    map_reserve!(values, prop.count_values as usize);
576    map_reserve!(enums, prop.count_enum_blobs as usize);
577
578    prop.values_ptr = map_ptr!(&values);
579    prop.enum_blob_ptr = map_ptr!(&enums);
580
581    unsafe {
582        ioctl::mode::get_property(fd, &mut prop)?;
583    }
584
585    map_set!(values, prop.count_values as usize);
586    map_set!(enums, prop.count_enum_blobs as usize);
587
588    Ok(prop)
589}
590
591/// Set property
592pub fn set_connector_property(
593    fd: BorrowedFd<'_>,
594    connector_id: u32,
595    prop_id: u32,
596    value: u64,
597) -> io::Result<drm_mode_connector_set_property> {
598    let mut prop = drm_mode_connector_set_property {
599        value,
600        prop_id,
601        connector_id,
602    };
603
604    unsafe {
605        ioctl::mode::connector_set_property(fd, &mut prop)?;
606    }
607
608    Ok(prop)
609}
610
611/// Get the value of a property blob
612pub fn get_property_blob(
613    fd: BorrowedFd<'_>,
614    blob_id: u32,
615    mut data: Option<&mut Vec<u8>>,
616) -> io::Result<drm_mode_get_blob> {
617    let mut sizes = drm_mode_get_blob {
618        blob_id,
619        ..Default::default()
620    };
621
622    unsafe {
623        ioctl::mode::get_blob(fd, &mut sizes)?;
624    }
625
626    if data.is_none() {
627        return Ok(sizes);
628    }
629
630    map_reserve!(data, sizes.length as usize);
631
632    let mut blob = drm_mode_get_blob {
633        blob_id,
634        length: sizes.length,
635        data: map_ptr!(&data),
636    };
637
638    unsafe {
639        ioctl::mode::get_blob(fd, &mut blob)?;
640    }
641
642    map_set!(data, blob.length as usize);
643
644    Ok(blob)
645}
646
647/// Create a property blob
648pub fn create_property_blob(
649    fd: BorrowedFd<'_>,
650    data: &mut [u8],
651) -> io::Result<drm_mode_create_blob> {
652    let mut blob = drm_mode_create_blob {
653        data: data.as_mut_ptr() as _,
654        length: data.len() as _,
655        ..Default::default()
656    };
657
658    unsafe {
659        ioctl::mode::create_blob(fd, &mut blob)?;
660    }
661
662    Ok(blob)
663}
664
665/// Destroy a property blob
666pub fn destroy_property_blob(fd: BorrowedFd<'_>, id: u32) -> io::Result<drm_mode_destroy_blob> {
667    let mut blob = drm_mode_destroy_blob { blob_id: id };
668
669    unsafe {
670        ioctl::mode::destroy_blob(fd, &mut blob)?;
671    }
672
673    Ok(blob)
674}
675
676/// Get properties from an object
677pub fn get_properties(
678    fd: BorrowedFd<'_>,
679    obj_id: u32,
680    obj_type: u32,
681    mut props: Option<&mut Vec<u32>>,
682    mut values: Option<&mut Vec<u64>>,
683) -> io::Result<drm_mode_obj_get_properties> {
684    assert_eq!(props.is_some(), values.is_some());
685
686    let mut sizes = drm_mode_obj_get_properties {
687        obj_id,
688        obj_type,
689        ..Default::default()
690    };
691
692    unsafe {
693        ioctl::mode::obj_get_properties(fd, &mut sizes)?;
694    }
695
696    map_reserve!(props, sizes.count_props as usize);
697    map_reserve!(values, sizes.count_props as usize);
698
699    let mut info = drm_mode_obj_get_properties {
700        props_ptr: map_ptr!(&props),
701        prop_values_ptr: map_ptr!(&values),
702        count_props: map_len!(&props),
703        obj_id,
704        obj_type,
705    };
706
707    unsafe {
708        ioctl::mode::obj_get_properties(fd, &mut info)?;
709    }
710
711    map_set!(props, info.count_props as usize);
712    map_set!(values, info.count_props as usize);
713
714    Ok(info)
715}
716
717/// Set the properties of an object
718pub fn set_property(
719    fd: BorrowedFd<'_>,
720    prop_id: u32,
721    obj_id: u32,
722    obj_type: u32,
723    value: u64,
724) -> io::Result<()> {
725    let mut prop = drm_mode_obj_set_property {
726        value,
727        prop_id,
728        obj_id,
729        obj_type,
730    };
731
732    unsafe {
733        ioctl::mode::obj_set_property(fd, &mut prop)?;
734    }
735
736    Ok(())
737}
738
739/// Schedule a page flip
740pub fn page_flip(
741    fd: BorrowedFd<'_>,
742    crtc_id: u32,
743    fb_id: u32,
744    flags: u32,
745    sequence: u32,
746) -> io::Result<()> {
747    let mut flip = drm_mode_crtc_page_flip {
748        crtc_id,
749        fb_id,
750        flags,
751        // Same struct as drm_mode_crtc_page_flip_target
752        reserved: sequence,
753        user_data: crtc_id as _,
754    };
755
756    unsafe {
757        ioctl::mode::crtc_page_flip(fd, &mut flip)?;
758    }
759
760    Ok(())
761}
762
763/// Atomically set properties
764pub fn atomic_commit(
765    fd: BorrowedFd<'_>,
766    flags: u32,
767    objs: &mut [u32],
768    prop_counts: &mut [u32],
769    props: &mut [u32],
770    values: &mut [u64],
771) -> io::Result<()> {
772    let mut atomic = drm_mode_atomic {
773        flags,
774        count_objs: objs.len() as _,
775        objs_ptr: objs.as_mut_ptr() as _,
776        count_props_ptr: prop_counts.as_mut_ptr() as _,
777        props_ptr: props.as_mut_ptr() as _,
778        prop_values_ptr: values.as_mut_ptr() as _,
779        ..Default::default()
780    };
781
782    unsafe {
783        ioctl::mode::atomic(fd, &mut atomic)?;
784    }
785
786    Ok(())
787}
788
789/// Create a drm lease
790pub fn create_lease(
791    fd: BorrowedFd<'_>,
792    objects: &[u32],
793    flags: u32,
794) -> io::Result<drm_mode_create_lease> {
795    let mut data = drm_mode_create_lease {
796        object_ids: objects.as_ptr() as _,
797        object_count: objects.len() as u32,
798        flags,
799        ..Default::default()
800    };
801
802    unsafe {
803        ioctl::mode::create_lease(fd, &mut data)?;
804    }
805
806    Ok(data)
807}
808
809/// List all active drm leases
810pub fn list_lessees(
811    fd: BorrowedFd<'_>,
812    mut lessees: Option<&mut Vec<u32>>,
813) -> io::Result<drm_mode_list_lessees> {
814    let mut sizes = drm_mode_list_lessees::default();
815
816    unsafe {
817        ioctl::mode::list_lessees(fd, &mut sizes)?;
818    };
819
820    map_reserve!(lessees, sizes.count_lessees as usize);
821
822    let mut data = drm_mode_list_lessees {
823        lessees_ptr: map_ptr!(&lessees),
824        count_lessees: map_len!(&lessees),
825        ..Default::default()
826    };
827
828    unsafe {
829        ioctl::mode::list_lessees(fd, &mut data)?;
830    };
831
832    map_set!(lessees, data.count_lessees as usize);
833
834    Ok(data)
835}
836
837/// Get leased objects for a lease file descriptor
838pub fn get_lease(
839    fd: BorrowedFd<'_>,
840    mut objects: Option<&mut Vec<u32>>,
841) -> io::Result<drm_mode_get_lease> {
842    let mut sizes = drm_mode_get_lease::default();
843
844    unsafe {
845        ioctl::mode::get_lease(fd, &mut sizes)?;
846    }
847
848    map_reserve!(objects, sizes.count_objects as usize);
849
850    let mut data = drm_mode_get_lease {
851        count_objects: map_len!(&objects),
852        objects_ptr: map_ptr!(&objects),
853        ..Default::default()
854    };
855
856    unsafe {
857        ioctl::mode::get_lease(fd, &mut data)?;
858    }
859
860    map_set!(objects, data.count_objects as usize);
861
862    Ok(data)
863}
864
865/// Revoke previously issued lease
866pub fn revoke_lease(fd: BorrowedFd<'_>, lessee_id: u32) -> io::Result<()> {
867    let mut data = drm_mode_revoke_lease { lessee_id };
868
869    unsafe {
870        ioctl::mode::revoke_lease(fd, &mut data)?;
871    }
872
873    Ok(())
874}
875
876///
877/// Dumbbuffers are basic buffers that can be used for scanout.
878///
879pub mod dumbbuffer {
880    use crate::ioctl;
881    use drm_sys::*;
882
883    use std::{io, os::unix::io::BorrowedFd};
884
885    /// Create a dumb buffer
886    pub fn create(
887        fd: BorrowedFd<'_>,
888        width: u32,
889        height: u32,
890        bpp: u32,
891        flags: u32,
892    ) -> io::Result<drm_mode_create_dumb> {
893        let mut db = drm_mode_create_dumb {
894            height,
895            width,
896            bpp,
897            flags,
898            ..Default::default()
899        };
900
901        unsafe {
902            ioctl::mode::create_dumb(fd, &mut db)?;
903        }
904
905        Ok(db)
906    }
907
908    /// Destroy a dumb buffer
909    pub fn destroy(fd: BorrowedFd<'_>, handle: u32) -> io::Result<drm_mode_destroy_dumb> {
910        let mut db = drm_mode_destroy_dumb { handle };
911
912        unsafe {
913            ioctl::mode::destroy_dumb(fd, &mut db)?;
914        }
915
916        Ok(db)
917    }
918
919    /// Map a dump buffer and prep it for an mmap
920    pub fn map(
921        fd: BorrowedFd<'_>,
922        handle: u32,
923        pad: u32,
924        offset: u64,
925    ) -> io::Result<drm_mode_map_dumb> {
926        let mut map = drm_mode_map_dumb {
927            handle,
928            pad,
929            offset,
930        };
931
932        unsafe {
933            ioctl::mode::map_dumb(fd, &mut map)?;
934        }
935
936        Ok(map)
937    }
938}