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