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. |
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. |
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. |
85 | pub fn get_framebuffer(fd: BorrowedFd<'_>, fb_id: u32) -> io::Result<drm_mode_fb_cmd> { |
86 | let mut info: drm_mode_fb_cmd = 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. |
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 = 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). |
126 | pub fn get_framebuffer2(fd: BorrowedFd<'_>, fb_id: u32) -> io::Result<drm_mode_fb_cmd2> { |
127 | let mut info: drm_mode_fb_cmd2 = 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) |
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 = 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. |
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. |
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 = 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 |
200 | pub fn get_crtc(fd: BorrowedFd<'_>, crtc_id: u32) -> io::Result<drm_mode_crtc> { |
201 | let mut info: drm_mode_crtc = 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 |
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 = 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 |
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 = 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 |
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 = 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" ] |
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 = 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" ] |
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 = 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" ] |
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 = 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 |
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 |
460 | pub fn get_encoder(fd: BorrowedFd<'_>, encoder_id: u32) -> io::Result<drm_mode_get_encoder> { |
461 | let mut info: drm_mode_get_encoder = 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. |
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. |
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 = 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 |
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 |
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 = 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 |
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 |
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 = 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 |
660 | pub fn destroy_property_blob(fd: BorrowedFd<'_>, id: u32) -> io::Result<drm_mode_destroy_blob> { |
661 | let mut blob: drm_mode_destroy_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 |
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 |
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 = 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 |
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 = 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 |
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 = 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 |
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 = 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 |
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 = 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 = 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 |
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 = 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 = 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 |
860 | pub fn revoke_lease(fd: BorrowedFd<'_>, lessee_id: u32) -> io::Result<()> { |
861 | let mut data: drm_mode_revoke_lease = 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 |
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 |
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 |
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 | |