1#![allow(clippy::too_many_arguments)]
6
7use crate::ioctl;
8use drm_sys::*;
9
10use std::{io, os::unix::io::BorrowedFd};
11
12pub 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
54pub 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
84pub 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
98pub 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
125pub 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
139pub 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
170pub 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
179pub 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
199pub 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
213pub 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
245pub 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
269pub 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#[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#[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#[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
379pub 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
465pub 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
479pub 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
516pub 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
554pub 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 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
591pub 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
611pub 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
647pub 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
665pub 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
676pub 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
717pub 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
739pub 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 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
763pub 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
789pub 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
809pub 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
837pub 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
865pub 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
876pub mod dumbbuffer {
880 use crate::ioctl;
881 use drm_sys::*;
882
883 use std::{io, os::unix::io::BorrowedFd};
884
885 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 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 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}