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: 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
get_encoder(fd: BorrowedFd<'_>, encoder_id: u32) -> io::Result<drm_mode_get_encoder>466 pub 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.
get_plane( fd: BorrowedFd<'_>, plane_id: u32, mut formats: Option<&mut Vec<u32>>, ) -> io::Result<drm_mode_get_plane>480 pub 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.
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>517 pub 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
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>555 pub 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
set_connector_property( fd: BorrowedFd<'_>, connector_id: u32, prop_id: u32, value: u64, ) -> io::Result<drm_mode_connector_set_property>592 pub 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
get_property_blob( fd: BorrowedFd<'_>, blob_id: u32, mut data: Option<&mut Vec<u8>>, ) -> io::Result<drm_mode_get_blob>612 pub 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
create_property_blob( fd: BorrowedFd<'_>, data: &mut [u8], ) -> io::Result<drm_mode_create_blob>648 pub 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
destroy_property_blob(fd: BorrowedFd<'_>, id: u32) -> io::Result<drm_mode_destroy_blob>666 pub 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
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>677 pub 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
set_property( fd: BorrowedFd<'_>, prop_id: u32, obj_id: u32, obj_type: u32, value: u64, ) -> io::Result<()>718 pub 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
page_flip( fd: BorrowedFd<'_>, crtc_id: u32, fb_id: u32, flags: u32, sequence: u32, ) -> io::Result<()>740 pub 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
atomic_commit( fd: BorrowedFd<'_>, flags: u32, objs: &mut [u32], prop_counts: &mut [u32], props: &mut [u32], values: &mut [u64], ) -> io::Result<()>764 pub 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
create_lease( fd: BorrowedFd<'_>, objects: &[u32], flags: u32, ) -> io::Result<drm_mode_create_lease>790 pub 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
list_lessees( fd: BorrowedFd<'_>, mut lessees: Option<&mut Vec<u32>>, ) -> io::Result<drm_mode_list_lessees>810 pub 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
get_lease( fd: BorrowedFd<'_>, mut objects: Option<&mut Vec<u32>>, ) -> io::Result<drm_mode_get_lease>838 pub 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
revoke_lease(fd: BorrowedFd<'_>, lessee_id: u32) -> io::Result<()>866 pub 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 ///
879 pub 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
create( fd: BorrowedFd<'_>, width: u32, height: u32, bpp: u32, flags: u32, ) -> io::Result<drm_mode_create_dumb>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
destroy(fd: BorrowedFd<'_>, handle: u32) -> io::Result<drm_mode_destroy_dumb>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
map( fd: BorrowedFd<'_>, handle: u32, pad: u32, offset: u64, ) -> io::Result<drm_mode_map_dumb>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 }
939