• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //!
2 //! Bindings to the DRM's modesetting capabilities.
3 //!
4 
5 #![allow(clippy::too_many_arguments)]
6 
7 use crate::ioctl;
8 use drm_sys::*;
9 
10 use std::{io, os::unix::io::BorrowedFd};
11 
12 /// Enumerate most card resources.
get_resources( fd: BorrowedFd<'_>, mut fbs: Option<&mut Vec<u32>>, mut crtcs: Option<&mut Vec<u32>>, mut connectors: Option<&mut Vec<u32>>, mut encoders: Option<&mut Vec<u32>>, ) -> io::Result<drm_mode_card_res>13 pub 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.
get_plane_resources( fd: BorrowedFd<'_>, mut planes: Option<&mut Vec<u32>>, ) -> io::Result<drm_mode_get_plane_res>55 pub 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.
get_framebuffer(fd: BorrowedFd<'_>, fb_id: u32) -> io::Result<drm_mode_fb_cmd>85 pub 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.
add_fb( fd: BorrowedFd<'_>, width: u32, height: u32, pitch: u32, bpp: u32, depth: u32, handle: u32, ) -> io::Result<drm_mode_fb_cmd>99 pub 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).
get_framebuffer2(fd: BorrowedFd<'_>, fb_id: u32) -> io::Result<drm_mode_fb_cmd2>126 pub 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)
add_fb2( fd: BorrowedFd<'_>, width: u32, height: u32, fmt: u32, handles: &[u32; 4], pitches: &[u32; 4], offsets: &[u32; 4], modifier: &[u64; 4], flags: u32, ) -> io::Result<drm_mode_fb_cmd2>140 pub 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.
rm_fb(fd: BorrowedFd<'_>, mut id: u32) -> io::Result<()>171 pub 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.
dirty_fb( fd: BorrowedFd<'_>, fb_id: u32, clips: &[drm_clip_rect], ) -> io::Result<drm_mode_fb_dirty_cmd>180 pub 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
get_crtc(fd: BorrowedFd<'_>, crtc_id: u32) -> io::Result<drm_mode_crtc>200 pub 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
set_crtc( fd: BorrowedFd<'_>, crtc_id: u32, fb_id: u32, x: u32, y: u32, conns: &[u32], mode: Option<drm_mode_modeinfo>, ) -> io::Result<drm_mode_crtc>214 pub 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
get_gamma( fd: BorrowedFd<'_>, crtc_id: u32, size: usize, red: &mut [u16], green: &mut [u16], blue: &mut [u16], ) -> io::Result<drm_mode_crtc_lut>246 pub 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
set_gamma( fd: BorrowedFd<'_>, crtc_id: u32, size: usize, red: &[u16], green: &[u16], blue: &[u16], ) -> io::Result<drm_mode_crtc_lut>270 pub 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"]
set_cursor( fd: BorrowedFd<'_>, crtc_id: u32, buf_id: u32, width: u32, height: u32, ) -> io::Result<drm_mode_cursor>298 pub 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"]
set_cursor2( fd: BorrowedFd<'_>, crtc_id: u32, buf_id: u32, width: u32, height: u32, hot_x: i32, hot_y: i32, ) -> io::Result<drm_mode_cursor2>329 pub 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"]
move_cursor( fd: BorrowedFd<'_>, crtc_id: u32, x: i32, y: i32, ) -> io::Result<drm_mode_cursor>358 pub 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
get_connector( fd: BorrowedFd<'_>, connector_id: u32, mut props: Option<&mut Vec<u32>>, mut prop_values: Option<&mut Vec<u64>>, mut modes: Option<&mut Vec<drm_mode_modeinfo>>, mut encoders: Option<&mut Vec<u32>>, force_probe: bool, ) -> io::Result<drm_mode_get_connector>380 pub 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: u32::from(!force_probe),
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 => u32::from(!force_probe),
431             },
432             count_props: map_len!(&props),
433             count_encoders: map_len!(&encoders),
434             ..Default::default()
435         };
436 
437         unsafe {
438             ioctl::mode::get_connector(fd, &mut info)?;
439         }
440 
441         if info.count_modes == sizes.count_modes
442             && info.count_encoders == sizes.count_encoders
443             && info.count_props == sizes.count_props
444         {
445             break info;
446         } else {
447             sizes = info;
448         }
449     };
450 
451     map_set!(modes, info.count_modes as usize);
452     map_set!(props, info.count_props as usize);
453     map_set!(prop_values, info.count_props as usize);
454     map_set!(encoders, info.count_encoders as usize);
455 
456     Ok(info)
457 }
458 
459 /// Get info about an encoder
get_encoder(fd: BorrowedFd<'_>, encoder_id: u32) -> io::Result<drm_mode_get_encoder>460 pub fn get_encoder(fd: BorrowedFd<'_>, encoder_id: u32) -> io::Result<drm_mode_get_encoder> {
461     let mut info = drm_mode_get_encoder {
462         encoder_id,
463         ..Default::default()
464     };
465 
466     unsafe {
467         ioctl::mode::get_encoder(fd, &mut info)?;
468     }
469 
470     Ok(info)
471 }
472 
473 /// Get info about a plane.
get_plane( fd: BorrowedFd<'_>, plane_id: u32, mut formats: Option<&mut Vec<u32>>, ) -> io::Result<drm_mode_get_plane>474 pub fn get_plane(
475     fd: BorrowedFd<'_>,
476     plane_id: u32,
477     mut formats: Option<&mut Vec<u32>>,
478 ) -> io::Result<drm_mode_get_plane> {
479     let mut sizes = drm_mode_get_plane {
480         plane_id,
481         ..Default::default()
482     };
483 
484     unsafe {
485         ioctl::mode::get_plane(fd, &mut sizes)?;
486     }
487 
488     if formats.is_none() {
489         return Ok(sizes);
490     }
491 
492     map_reserve!(formats, sizes.count_format_types as usize);
493 
494     let mut info = drm_mode_get_plane {
495         plane_id,
496         count_format_types: sizes.count_format_types,
497         format_type_ptr: map_ptr!(&formats),
498         ..Default::default()
499     };
500 
501     unsafe {
502         ioctl::mode::get_plane(fd, &mut info)?;
503     }
504 
505     map_set!(formats, info.count_format_types as usize);
506 
507     Ok(info)
508 }
509 
510 /// Set plane state.
set_plane( fd: BorrowedFd<'_>, plane_id: u32, crtc_id: u32, fb_id: u32, flags: u32, crtc_x: i32, crtc_y: i32, crtc_w: u32, crtc_h: u32, src_x: u32, src_y: u32, src_w: u32, src_h: u32, ) -> io::Result<drm_mode_set_plane>511 pub fn set_plane(
512     fd: BorrowedFd<'_>,
513     plane_id: u32,
514     crtc_id: u32,
515     fb_id: u32,
516     flags: u32,
517     crtc_x: i32,
518     crtc_y: i32,
519     crtc_w: u32,
520     crtc_h: u32,
521     src_x: u32,
522     src_y: u32,
523     src_w: u32,
524     src_h: u32,
525 ) -> io::Result<drm_mode_set_plane> {
526     let mut plane = drm_mode_set_plane {
527         plane_id,
528         crtc_id,
529         fb_id,
530         flags,
531         crtc_x,
532         crtc_y,
533         crtc_w,
534         crtc_h,
535         src_x,
536         src_y,
537         src_h,
538         src_w,
539     };
540 
541     unsafe {
542         ioctl::mode::set_plane(fd, &mut plane)?;
543     }
544 
545     Ok(plane)
546 }
547 
548 /// Get property
get_property( fd: BorrowedFd<'_>, prop_id: u32, mut values: Option<&mut Vec<u64>>, mut enums: Option<&mut Vec<drm_mode_property_enum>>, ) -> io::Result<drm_mode_get_property>549 pub fn get_property(
550     fd: BorrowedFd<'_>,
551     prop_id: u32,
552     mut values: Option<&mut Vec<u64>>,
553     mut enums: Option<&mut Vec<drm_mode_property_enum>>,
554 ) -> io::Result<drm_mode_get_property> {
555     let mut prop = drm_mode_get_property {
556         prop_id,
557         ..Default::default()
558     };
559 
560     unsafe {
561         ioctl::mode::get_property(fd, &mut prop)?;
562     }
563 
564     // There is no need to call get_property() twice if there is nothing else to retrieve.
565     if prop.count_values == 0 && prop.count_enum_blobs == 0 {
566         return Ok(prop);
567     }
568 
569     map_reserve!(values, prop.count_values as usize);
570     map_reserve!(enums, prop.count_enum_blobs as usize);
571 
572     prop.values_ptr = map_ptr!(&values);
573     prop.enum_blob_ptr = map_ptr!(&enums);
574 
575     unsafe {
576         ioctl::mode::get_property(fd, &mut prop)?;
577     }
578 
579     map_set!(values, prop.count_values as usize);
580     map_set!(enums, prop.count_enum_blobs as usize);
581 
582     Ok(prop)
583 }
584 
585 /// Set property
set_connector_property( fd: BorrowedFd<'_>, connector_id: u32, prop_id: u32, value: u64, ) -> io::Result<drm_mode_connector_set_property>586 pub fn set_connector_property(
587     fd: BorrowedFd<'_>,
588     connector_id: u32,
589     prop_id: u32,
590     value: u64,
591 ) -> io::Result<drm_mode_connector_set_property> {
592     let mut prop = drm_mode_connector_set_property {
593         value,
594         prop_id,
595         connector_id,
596     };
597 
598     unsafe {
599         ioctl::mode::connector_set_property(fd, &mut prop)?;
600     }
601 
602     Ok(prop)
603 }
604 
605 /// Get the value of a property blob
get_property_blob( fd: BorrowedFd<'_>, blob_id: u32, mut data: Option<&mut Vec<u8>>, ) -> io::Result<drm_mode_get_blob>606 pub fn get_property_blob(
607     fd: BorrowedFd<'_>,
608     blob_id: u32,
609     mut data: Option<&mut Vec<u8>>,
610 ) -> io::Result<drm_mode_get_blob> {
611     let mut sizes = drm_mode_get_blob {
612         blob_id,
613         ..Default::default()
614     };
615 
616     unsafe {
617         ioctl::mode::get_blob(fd, &mut sizes)?;
618     }
619 
620     if data.is_none() {
621         return Ok(sizes);
622     }
623 
624     map_reserve!(data, sizes.length as usize);
625 
626     let mut blob = drm_mode_get_blob {
627         blob_id,
628         length: sizes.length,
629         data: map_ptr!(&data),
630     };
631 
632     unsafe {
633         ioctl::mode::get_blob(fd, &mut blob)?;
634     }
635 
636     map_set!(data, blob.length as usize);
637 
638     Ok(blob)
639 }
640 
641 /// Create a property blob
create_property_blob( fd: BorrowedFd<'_>, data: &mut [u8], ) -> io::Result<drm_mode_create_blob>642 pub fn create_property_blob(
643     fd: BorrowedFd<'_>,
644     data: &mut [u8],
645 ) -> io::Result<drm_mode_create_blob> {
646     let mut blob = drm_mode_create_blob {
647         data: data.as_mut_ptr() as _,
648         length: data.len() as _,
649         ..Default::default()
650     };
651 
652     unsafe {
653         ioctl::mode::create_blob(fd, &mut blob)?;
654     }
655 
656     Ok(blob)
657 }
658 
659 /// Destroy a property blob
destroy_property_blob(fd: BorrowedFd<'_>, id: u32) -> io::Result<drm_mode_destroy_blob>660 pub fn destroy_property_blob(fd: BorrowedFd<'_>, id: u32) -> io::Result<drm_mode_destroy_blob> {
661     let mut blob = drm_mode_destroy_blob { blob_id: id };
662 
663     unsafe {
664         ioctl::mode::destroy_blob(fd, &mut blob)?;
665     }
666 
667     Ok(blob)
668 }
669 
670 /// Get properties from an object
get_properties( fd: BorrowedFd<'_>, obj_id: u32, obj_type: u32, mut props: Option<&mut Vec<u32>>, mut values: Option<&mut Vec<u64>>, ) -> io::Result<drm_mode_obj_get_properties>671 pub fn get_properties(
672     fd: BorrowedFd<'_>,
673     obj_id: u32,
674     obj_type: u32,
675     mut props: Option<&mut Vec<u32>>,
676     mut values: Option<&mut Vec<u64>>,
677 ) -> io::Result<drm_mode_obj_get_properties> {
678     assert_eq!(props.is_some(), values.is_some());
679 
680     let mut sizes = drm_mode_obj_get_properties {
681         obj_id,
682         obj_type,
683         ..Default::default()
684     };
685 
686     unsafe {
687         ioctl::mode::obj_get_properties(fd, &mut sizes)?;
688     }
689 
690     map_reserve!(props, sizes.count_props as usize);
691     map_reserve!(values, sizes.count_props as usize);
692 
693     let mut info = drm_mode_obj_get_properties {
694         props_ptr: map_ptr!(&props),
695         prop_values_ptr: map_ptr!(&values),
696         count_props: map_len!(&props),
697         obj_id,
698         obj_type,
699     };
700 
701     unsafe {
702         ioctl::mode::obj_get_properties(fd, &mut info)?;
703     }
704 
705     map_set!(props, info.count_props as usize);
706     map_set!(values, info.count_props as usize);
707 
708     Ok(info)
709 }
710 
711 /// Set the properties of an object
set_property( fd: BorrowedFd<'_>, prop_id: u32, obj_id: u32, obj_type: u32, value: u64, ) -> io::Result<()>712 pub fn set_property(
713     fd: BorrowedFd<'_>,
714     prop_id: u32,
715     obj_id: u32,
716     obj_type: u32,
717     value: u64,
718 ) -> io::Result<()> {
719     let mut prop = drm_mode_obj_set_property {
720         value,
721         prop_id,
722         obj_id,
723         obj_type,
724     };
725 
726     unsafe {
727         ioctl::mode::obj_set_property(fd, &mut prop)?;
728     }
729 
730     Ok(())
731 }
732 
733 /// Schedule a page flip
page_flip( fd: BorrowedFd<'_>, crtc_id: u32, fb_id: u32, flags: u32, sequence: u32, ) -> io::Result<()>734 pub fn page_flip(
735     fd: BorrowedFd<'_>,
736     crtc_id: u32,
737     fb_id: u32,
738     flags: u32,
739     sequence: u32,
740 ) -> io::Result<()> {
741     let mut flip = drm_mode_crtc_page_flip {
742         crtc_id,
743         fb_id,
744         flags,
745         // Same struct as drm_mode_crtc_page_flip_target
746         reserved: sequence,
747         user_data: crtc_id as _,
748     };
749 
750     unsafe {
751         ioctl::mode::crtc_page_flip(fd, &mut flip)?;
752     }
753 
754     Ok(())
755 }
756 
757 /// Atomically set properties
atomic_commit( fd: BorrowedFd<'_>, flags: u32, objs: &mut [u32], prop_counts: &mut [u32], props: &mut [u32], values: &mut [u64], ) -> io::Result<()>758 pub fn atomic_commit(
759     fd: BorrowedFd<'_>,
760     flags: u32,
761     objs: &mut [u32],
762     prop_counts: &mut [u32],
763     props: &mut [u32],
764     values: &mut [u64],
765 ) -> io::Result<()> {
766     let mut atomic = drm_mode_atomic {
767         flags,
768         count_objs: objs.len() as _,
769         objs_ptr: objs.as_mut_ptr() as _,
770         count_props_ptr: prop_counts.as_mut_ptr() as _,
771         props_ptr: props.as_mut_ptr() as _,
772         prop_values_ptr: values.as_mut_ptr() as _,
773         ..Default::default()
774     };
775 
776     unsafe {
777         ioctl::mode::atomic(fd, &mut atomic)?;
778     }
779 
780     Ok(())
781 }
782 
783 /// Create a drm lease
create_lease( fd: BorrowedFd<'_>, objects: &[u32], flags: u32, ) -> io::Result<drm_mode_create_lease>784 pub fn create_lease(
785     fd: BorrowedFd<'_>,
786     objects: &[u32],
787     flags: u32,
788 ) -> io::Result<drm_mode_create_lease> {
789     let mut data = drm_mode_create_lease {
790         object_ids: objects.as_ptr() as _,
791         object_count: objects.len() as u32,
792         flags,
793         ..Default::default()
794     };
795 
796     unsafe {
797         ioctl::mode::create_lease(fd, &mut data)?;
798     }
799 
800     Ok(data)
801 }
802 
803 /// List all active drm leases
list_lessees( fd: BorrowedFd<'_>, mut lessees: Option<&mut Vec<u32>>, ) -> io::Result<drm_mode_list_lessees>804 pub fn list_lessees(
805     fd: BorrowedFd<'_>,
806     mut lessees: Option<&mut Vec<u32>>,
807 ) -> io::Result<drm_mode_list_lessees> {
808     let mut sizes = drm_mode_list_lessees::default();
809 
810     unsafe {
811         ioctl::mode::list_lessees(fd, &mut sizes)?;
812     };
813 
814     map_reserve!(lessees, sizes.count_lessees as usize);
815 
816     let mut data = drm_mode_list_lessees {
817         lessees_ptr: map_ptr!(&lessees),
818         count_lessees: map_len!(&lessees),
819         ..Default::default()
820     };
821 
822     unsafe {
823         ioctl::mode::list_lessees(fd, &mut data)?;
824     };
825 
826     map_set!(lessees, data.count_lessees as usize);
827 
828     Ok(data)
829 }
830 
831 /// Get leased objects for a lease file descriptor
get_lease( fd: BorrowedFd<'_>, mut objects: Option<&mut Vec<u32>>, ) -> io::Result<drm_mode_get_lease>832 pub fn get_lease(
833     fd: BorrowedFd<'_>,
834     mut objects: Option<&mut Vec<u32>>,
835 ) -> io::Result<drm_mode_get_lease> {
836     let mut sizes = drm_mode_get_lease::default();
837 
838     unsafe {
839         ioctl::mode::get_lease(fd, &mut sizes)?;
840     }
841 
842     map_reserve!(objects, sizes.count_objects as usize);
843 
844     let mut data = drm_mode_get_lease {
845         count_objects: map_len!(&objects),
846         objects_ptr: map_ptr!(&objects),
847         ..Default::default()
848     };
849 
850     unsafe {
851         ioctl::mode::get_lease(fd, &mut data)?;
852     }
853 
854     map_set!(objects, data.count_objects as usize);
855 
856     Ok(data)
857 }
858 
859 /// Revoke previously issued lease
revoke_lease(fd: BorrowedFd<'_>, lessee_id: u32) -> io::Result<()>860 pub fn revoke_lease(fd: BorrowedFd<'_>, lessee_id: u32) -> io::Result<()> {
861     let mut data = drm_mode_revoke_lease { lessee_id };
862 
863     unsafe {
864         ioctl::mode::revoke_lease(fd, &mut data)?;
865     }
866 
867     Ok(())
868 }
869 
870 ///
871 /// Dumbbuffers are basic buffers that can be used for scanout.
872 ///
873 pub mod dumbbuffer {
874     use crate::ioctl;
875     use drm_sys::*;
876 
877     use std::{io, os::unix::io::BorrowedFd};
878 
879     /// Create a dumb buffer
create( fd: BorrowedFd<'_>, width: u32, height: u32, bpp: u32, flags: u32, ) -> io::Result<drm_mode_create_dumb>880     pub fn create(
881         fd: BorrowedFd<'_>,
882         width: u32,
883         height: u32,
884         bpp: u32,
885         flags: u32,
886     ) -> io::Result<drm_mode_create_dumb> {
887         let mut db = drm_mode_create_dumb {
888             height,
889             width,
890             bpp,
891             flags,
892             ..Default::default()
893         };
894 
895         unsafe {
896             ioctl::mode::create_dumb(fd, &mut db)?;
897         }
898 
899         Ok(db)
900     }
901 
902     /// Destroy a dumb buffer
destroy(fd: BorrowedFd<'_>, handle: u32) -> io::Result<drm_mode_destroy_dumb>903     pub fn destroy(fd: BorrowedFd<'_>, handle: u32) -> io::Result<drm_mode_destroy_dumb> {
904         let mut db = drm_mode_destroy_dumb { handle };
905 
906         unsafe {
907             ioctl::mode::destroy_dumb(fd, &mut db)?;
908         }
909 
910         Ok(db)
911     }
912 
913     /// Map a dump buffer and prep it for an mmap
map( fd: BorrowedFd<'_>, handle: u32, pad: u32, offset: u64, ) -> io::Result<drm_mode_map_dumb>914     pub fn map(
915         fd: BorrowedFd<'_>,
916         handle: u32,
917         pad: u32,
918         offset: u64,
919     ) -> io::Result<drm_mode_map_dumb> {
920         let mut map = drm_mode_map_dumb {
921             handle,
922             pad,
923             offset,
924         };
925 
926         unsafe {
927             ioctl::mode::map_dumb(fd, &mut map)?;
928         }
929 
930         Ok(map)
931     }
932 }
933