1#![no_std]
19#![cfg_attr(not(feature = "stable_polyfill"), feature(ptr_metadata))]
20#![cfg_attr(not(feature = "stable_polyfill"), feature(ascii_char))]
21
22extern crate alloc;
23
24pub mod event;
26pub mod ioctl;
28pub mod modeset;
30pub mod result;
31
32mod util;
33
34use core::iter::{self, zip};
35use core::ptr::null_mut;
36
37use alloc::sync::Arc;
38use alloc::vec::Vec;
39use linux_io::fd::ioctl::IoctlReq;
40use modeset::{
41 BlobId, BufferObjectId, ConnectorId, CrtcId, EncoderId, EncoderState, FramebufferId, ModeInfo,
42 ModeProp, PlaneId,
43};
44use result::{Error, InitError};
45
46#[repr(transparent)]
47#[derive(Debug)]
48pub struct Card {
49 f: Arc<linux_io::File<ioctl::DrmCardDevice>>,
50}
51
52impl Card {
53 pub fn open(path: impl AsRef<core::ffi::CStr>) -> Result<Self, InitError> {
59 let f = linux_io::File::open(path.as_ref(), linux_io::OpenOptions::read_write())?;
60 Self::from_file(f)
61 }
62
63 pub fn from_file<D>(f: linux_io::File<D>) -> Result<Self, InitError> {
68 let f: linux_io::File<ioctl::DrmCardDevice> = unsafe { f.to_device(ioctl::DrmCardDevice) };
76 let ret = Self { f: Arc::new(f) };
77 let mut v = ioctl::DrmVersion::zeroed();
78 ret.ioctl(ioctl::DRM_IOCTL_VERSION, &mut v)?;
79 Ok(ret)
80 }
81
82 pub unsafe fn from_file_unchecked<D>(f: linux_io::File<D>) -> Self {
85 let f: linux_io::File<ioctl::DrmCardDevice> = unsafe { f.to_device(ioctl::DrmCardDevice) };
86 Self { f: Arc::new(f) }
87 }
88
89 pub fn fd(&self) -> linux_unsafe::int {
96 self.f.fd()
97 }
98
99 pub fn api_version(&self) -> Result<ApiVersion, Error> {
101 let mut v = ioctl::DrmVersion::zeroed();
102 self.ioctl(ioctl::DRM_IOCTL_VERSION, &mut v)?;
103 Ok(ApiVersion {
104 major: v.version_major as i64,
105 minor: v.version_minor as i64,
106 patch: v.version_patchlevel as i64,
107 })
108 }
109
110 pub fn read_driver_name<'a>(&self, into: &'a mut [u8]) -> Result<&'a mut [u8], Error> {
112 let mut v = ioctl::DrmVersion::zeroed();
113 let ptr = into.as_mut_ptr();
114 unsafe { v.set_name_ptr(ptr as *mut _, into.len()) };
115 self.ioctl(ioctl::DRM_IOCTL_VERSION, &mut v)?;
116 Ok(&mut into[..v.name_len()])
117 }
118
119 pub fn driver_name(&self) -> Result<Vec<u8>, Error> {
121 let mut v = ioctl::DrmVersion::zeroed();
122 self.ioctl(ioctl::DRM_IOCTL_VERSION, &mut v)?;
123 let len = v.name_len();
124 let mut ret = vec_with_capacity::<u8>(len)?;
125 v = ioctl::DrmVersion::zeroed();
126 unsafe { v.set_name_ptr(ret.as_mut_ptr() as *mut _, len) };
127 self.ioctl(ioctl::DRM_IOCTL_VERSION, &mut v)?;
128 unsafe { ret.set_len(v.name_len()) };
129 Ok(ret)
130 }
131
132 #[inline(always)]
134 pub fn get_device_cap(&self, capability: DeviceCap) -> Result<u64, Error> {
135 self.get_device_cap_raw(capability.into())
136 }
137
138 #[inline]
140 pub fn get_device_cap_raw(&self, capability: ioctl::DrmCap) -> Result<u64, Error> {
141 let mut s = ioctl::DrmGetCap {
142 capability,
143 value: 0,
144 };
145 self.ioctl(ioctl::DRM_IOCTL_GET_CAP, &mut s)?;
146 Ok(s.value)
147 }
148
149 #[inline(always)]
151 pub fn set_client_cap(&mut self, capability: ClientCap, value: u64) -> Result<(), Error> {
152 self.set_client_cap_raw(capability.into(), value)
153 }
154
155 #[inline]
158 pub fn set_client_cap_raw(
159 &mut self,
160 capability: ioctl::DrmClientCap,
161 value: u64,
162 ) -> Result<(), Error> {
163 let s = ioctl::DrmSetClientCap { capability, value };
164 self.ioctl(ioctl::DRM_IOCTL_SET_CLIENT_CAP, &s)?;
165 Ok(())
166 }
167
168 #[inline]
171 pub fn become_master(&mut self) -> Result<(), Error> {
172 self.ioctl(ioctl::DRM_IOCTL_SET_MASTER, ())?;
173 Ok(())
174 }
175
176 #[inline]
179 pub fn drop_master(&mut self) -> Result<(), Error> {
180 self.ioctl(ioctl::DRM_IOCTL_DROP_MASTER, ())?;
181 Ok(())
182 }
183
184 pub fn property_meta(
188 &self,
189 prop_id: modeset::PropertyId,
190 ) -> Result<modeset::ObjectPropMeta, Error> {
191 let mut tmp = ioctl::DrmModeGetProperty::zeroed();
192 tmp.prop_id = prop_id.0;
193 self.ioctl(ioctl::DRM_IOCTL_MODE_GETPROPERTY, &mut tmp)?;
194 if !tmp.name.is_ascii() {
195 return Err(Error::NotSupported);
200 }
201 Ok(modeset::ObjectPropMeta::new(tmp, &self))
202 }
203
204 pub fn object_properties(
209 &self,
210 obj_id: impl Into<modeset::ObjectId>,
211 ) -> Result<Vec<modeset::ModeProp>, Error> {
212 fn real_object_properties(
213 card: &Card,
214 obj_id: modeset::ObjectId,
215 ) -> Result<Vec<modeset::ModeProp>, Error> {
216 let (type_id, raw_id) = obj_id.as_raw_type_and_id();
217 let mut tmp = ioctl::DrmModeObjGetProperties::zeroed();
218 tmp.obj_type = type_id;
219 tmp.obj_id = raw_id;
220 card.ioctl(ioctl::DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &mut tmp)?;
221
222 loop {
226 let prop_count = tmp.count_props() as usize;
227
228 let mut prop_ids = vec_with_capacity::<u32>(prop_count)?;
229 let mut prop_values = vec_with_capacity::<u64>(prop_count)?;
230
231 unsafe {
232 tmp.set_prop_ptrs(
233 prop_ids.as_mut_ptr(),
234 prop_values.as_mut_ptr(),
235 prop_count as u32,
236 )
237 };
238
239 card.ioctl(ioctl::DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &mut tmp)?;
240
241 let new_prop_count = tmp.count_props() as usize;
242 if new_prop_count != prop_count {
243 continue;
246 }
247
248 unsafe {
252 prop_ids.set_len(prop_count);
253 prop_values.set_len(prop_count);
254 };
255 return Ok(iter::zip(prop_ids.into_iter(), prop_values.into_iter())
256 .map(|(id, val)| modeset::ModeProp {
257 prop_id: modeset::PropertyId(id),
258 value: val,
259 })
260 .collect());
261 }
262 }
263 real_object_properties(self, obj_id.into())
264 }
265
266 pub fn each_object_property_meta(
273 &self,
274 obj_id: impl Into<modeset::ObjectId>,
275 mut f: impl FnMut(modeset::ObjectPropMeta, u64),
276 ) -> Result<(), Error> {
277 let obj_id = obj_id.into();
278 let (type_id, raw_id) = obj_id.as_raw_type_and_id();
279 let mut tmp = ioctl::DrmModeObjGetProperties::zeroed();
280 tmp.obj_type = type_id;
281 tmp.obj_id = raw_id;
282 self.ioctl(ioctl::DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &mut tmp)?;
283 if tmp.count_props() == 0 {
284 return Ok(());
285 }
286
287 let (prop_ids, prop_values) = loop {
288 let prop_count = tmp.count_props() as usize;
289 let mut prop_ids = vec_with_capacity::<u32>(prop_count)?;
290 let mut prop_values = vec_with_capacity::<u64>(prop_count)?;
291 unsafe {
292 tmp.set_prop_ptrs(
293 prop_ids.as_mut_ptr(),
294 prop_values.as_mut_ptr(),
295 prop_count as u32,
296 )
297 };
298 self.ioctl(ioctl::DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &mut tmp)?;
299
300 let new_prop_count = tmp.count_props() as usize;
301 if new_prop_count != prop_count {
302 continue;
305 }
306
307 unsafe {
310 prop_ids.set_len(prop_count);
311 prop_values.set_len(prop_count);
312 };
313 break (prop_ids, prop_values);
314 };
315
316 for (prop_id, value) in zip(prop_ids, prop_values) {
317 let mut raw = ioctl::DrmModeGetProperty::zeroed();
318 raw.prop_id = prop_id;
319 self.ioctl(ioctl::DRM_IOCTL_MODE_GETPROPERTY, &mut raw)?;
320 if !raw.name.is_ascii() {
326 continue;
327 }
328 f(modeset::ObjectPropMeta::new(raw, &self), value);
329 }
330
331 Ok(())
332 }
333
334 pub fn resources(&self) -> Result<modeset::CardResources, Error> {
339 let mut ret = loop {
343 let mut r = ioctl::DrmModeCardRes::zeroed();
344 self.ioctl(ioctl::DRM_IOCTL_MODE_GETRESOURCES, &mut r)?;
345 let fb_count = r.count_fbs() as usize;
346 let connector_count = r.count_connectors() as usize;
347 let crtc_count = r.count_crtcs() as usize;
348 let encoder_count = r.count_encoders() as usize;
349
350 let mut fb_ids = vec_with_capacity::<FramebufferId>(fb_count)?;
351 let mut connector_ids = vec_with_capacity::<ConnectorId>(connector_count)?;
352 let mut crtc_ids = vec_with_capacity::<CrtcId>(crtc_count)?;
353 let mut encoder_ids = vec_with_capacity::<EncoderId>(encoder_count)?;
354
355 r = ioctl::DrmModeCardRes::zeroed();
356 unsafe {
357 r.set_fb_id_ptr(fb_ids.as_mut_ptr() as *mut u32, fb_count as u32);
358 r.set_connector_id_ptr(
359 connector_ids.as_mut_ptr() as *mut u32,
360 connector_count as u32,
361 );
362 r.set_crtc_id_ptr(crtc_ids.as_mut_ptr() as *mut u32, crtc_count as u32);
363 r.set_encoder_id_ptr(encoder_ids.as_mut_ptr() as *mut u32, encoder_count as u32);
364 };
365
366 self.ioctl(ioctl::DRM_IOCTL_MODE_GETRESOURCES, &mut r)?;
367 if r.count_fbs() as usize != fb_count {
371 continue;
372 }
373 if r.count_connectors() as usize != connector_count {
374 continue;
375 }
376 if r.count_crtcs() as usize != crtc_count {
377 continue;
378 }
379 if r.count_encoders() as usize != encoder_count {
380 continue;
381 }
382
383 unsafe {
387 fb_ids.set_len(fb_count);
388 connector_ids.set_len(connector_count);
389 crtc_ids.set_len(crtc_count);
390 encoder_ids.set_len(encoder_count);
391 };
392 break modeset::CardResources {
393 fb_ids,
394 connector_ids,
395 crtc_ids,
396 encoder_ids,
397 plane_ids: Vec::new(),
398 min_width: r.min_width,
399 max_width: r.max_width,
400 min_height: r.min_height,
401 max_height: r.max_height,
402 };
403 };
404
405 loop {
408 let mut tmp = ioctl::DrmModeGetPlaneRes::zeroed();
409 self.ioctl(ioctl::DRM_IOCTL_MODE_GETPLANERESOURCES, &mut tmp)?;
410
411 let plane_count = tmp.count_planes() as usize;
412 let mut plane_ids = vec_with_capacity::<modeset::PlaneId>(plane_count)?;
413 unsafe { tmp.set_plane_id_ptr(plane_ids.as_mut_ptr() as *mut u32, plane_count as u32) };
414
415 self.ioctl(ioctl::DRM_IOCTL_MODE_GETPLANERESOURCES, &mut tmp)?;
416 if tmp.count_planes() as usize != plane_count {
417 continue;
419 }
420
421 unsafe {
424 plane_ids.set_len(plane_count);
425 };
426 ret.plane_ids = plane_ids;
427 return Ok(ret);
428 }
429 }
430
431 pub fn connector_state(
433 &self,
434 connector_id: ConnectorId,
435 ) -> Result<modeset::ConnectorState, Error> {
436 loop {
439 let mut tmp = ioctl::DrmModeGetConnector::zeroed();
440 tmp.connector_id = connector_id.0;
441 self.ioctl(ioctl::DRM_IOCTL_MODE_GETCONNECTOR, &mut tmp)?;
442
443 let mode_count = tmp.count_modes();
444 let encoder_count = tmp.count_encoders();
445 let prop_count = tmp.count_props();
446
447 let mut modes = vec_with_capacity::<ioctl::DrmModeInfo>(mode_count as usize)?;
448 let mut ret_modes = vec_with_capacity::<ModeInfo>(mode_count as usize)?;
449 let mut encoder_ids = vec_with_capacity::<u32>(encoder_count as usize)?;
450 let mut prop_ids = vec_with_capacity::<u32>(prop_count as usize)?;
451 let mut prop_values = vec_with_capacity::<u64>(prop_count as usize)?;
452 let mut ret_props = vec_with_capacity::<ModeProp>(prop_count as usize)?;
453
454 tmp = ioctl::DrmModeGetConnector::zeroed();
455 tmp.connector_id = connector_id.0;
456 unsafe {
457 tmp.set_modes_ptr(modes.as_mut_ptr(), mode_count);
458 tmp.set_encoders_ptr(encoder_ids.as_mut_ptr(), encoder_count);
459 tmp.set_props_ptrs(prop_ids.as_mut_ptr(), prop_values.as_mut_ptr(), prop_count);
460 };
461 self.ioctl(ioctl::DRM_IOCTL_MODE_GETCONNECTOR, &mut tmp)?;
462
463 if tmp.count_modes() != mode_count
464 || tmp.count_props() != prop_count
465 || tmp.count_encoders() != encoder_count
466 {
467 continue;
469 }
470
471 unsafe {
475 modes.set_len(mode_count as usize);
476 encoder_ids.set_len(encoder_count as usize);
477 prop_ids.set_len(prop_count as usize);
478 prop_values.set_len(prop_count as usize);
479 }
480
481 ret_modes.extend(modes.into_iter().map(|raw| {
482 let r: modeset::ModeInfo = raw.into();
483 r
484 }));
485 ret_props.extend(
486 core::iter::zip(prop_ids.iter().copied(), prop_values.iter().copied()).map(
487 |(prop_id, value)| ModeProp {
488 prop_id: modeset::PropertyId(prop_id),
489 value,
490 },
491 ),
492 );
493 return Ok(modeset::ConnectorState {
494 id: ConnectorId(tmp.connector_id),
495 current_encoder_id: EncoderId(tmp.encoder_id),
496 connector_type: tmp.connector_type.into(),
497 connector_type_id: tmp.connector_type_id,
498 connection_state: tmp.connection.into(),
499 width_mm: tmp.mm_width,
500 height_mm: tmp.mm_height,
501 subpixel_type: tmp.subpixel.into(),
502 modes: ret_modes,
503 props: ret_props,
504 available_encoder_ids: encoder_ids,
505 });
506 }
507 }
508
509 pub fn encoder_state(&self, encoder_id: EncoderId) -> Result<modeset::EncoderState, Error> {
511 let mut tmp = ioctl::DrmModeGetEncoder::zeroed();
512 tmp.encoder_id = encoder_id.0;
513 self.ioctl(ioctl::DRM_IOCTL_MODE_GETENCODER, &mut tmp)?;
514 Ok(EncoderState {
515 encoder_id: EncoderId(tmp.encoder_id),
516 encoder_type: tmp.encoder_type,
517 current_crtc_id: CrtcId(tmp.crtc_id),
518 possible_crtcs: tmp.possible_crtcs,
519 possible_clones: tmp.possible_clones,
520 })
521 }
522
523 pub fn crtc_state(&self, crtc_id: CrtcId) -> Result<modeset::CrtcState, Error> {
525 let mut tmp = ioctl::DrmModeCrtc::zeroed();
526 tmp.crtc_id = crtc_id.0;
527 self.ioctl(ioctl::DRM_IOCTL_MODE_GETCRTC, &mut tmp)?;
528 Ok(tmp.into())
529 }
530
531 pub fn plane_state(&self, plane_id: PlaneId) -> Result<modeset::PlaneState, Error> {
533 let mut tmp = ioctl::DrmModeGetPlane::zeroed();
534 tmp.plane_id = plane_id.0;
535 self.ioctl(ioctl::DRM_IOCTL_MODE_GETPLANE, &mut tmp)?;
536 Ok(modeset::PlaneState {
537 id: PlaneId(tmp.plane_id),
538 crtc_id: CrtcId(tmp.crtc_id),
539 fb_id: FramebufferId(tmp.fb_id),
540 possible_crtcs: tmp.possible_crtcs,
541 gamma_size: tmp.gamma_size,
542 })
543 }
544
545 pub fn atomic_commit(
554 &mut self,
555 req: &modeset::AtomicRequest,
556 flags: modeset::AtomicCommitFlags,
557 user_data: u64,
558 ) -> Result<(), Error> {
559 let mut tmp = ioctl::DrmModeAtomic::zeroed();
560 let mut raw_parts = req.for_ioctl_req();
561 unsafe {
562 tmp.set_ptrs(ioctl::DrmModeAtomicPtrs {
563 count_objs: raw_parts.obj_ids.len() as u32,
564 objs_ptr: raw_parts.obj_ids.as_mut_ptr(),
565 count_props_ptr: raw_parts.obj_prop_counts.as_mut_ptr(),
566 props_ptr: raw_parts.prop_ids.as_mut_ptr(),
567 prop_values_ptr: raw_parts.prop_values.as_mut_ptr(),
568 })
569 };
570 tmp.flags = flags.0;
571 tmp.user_data = user_data;
572
573 self.ioctl(ioctl::DRM_IOCTL_MODE_ATOMIC, &mut tmp)?;
574 Ok(())
575 }
576
577 pub fn new_property_blob<'card, 'content>(
584 &'card self,
585 content: &'content [u8],
586 ) -> Result<modeset::BlobHandle, Error> {
587 let mut tmp = ioctl::DrmModeCreateBlob::zeroed();
588 if content.len() > (u32::MAX as usize) {
589 return Err(Error::Invalid);
590 }
591 unsafe { tmp.set_data(content.as_ptr(), content.len() as u32) };
592 self.ioctl(ioctl::DRM_IOCTL_MODE_CREATEPROPBLOB, &mut tmp)?;
593 Ok(modeset::BlobHandle {
594 id: Some(BlobId(tmp.blob_id)),
595 f: Arc::downgrade(&self.f),
596 })
597 }
598
599 pub fn reset_crtc(&mut self, crtc_id: u32) -> Result<modeset::CrtcState, Error> {
601 let mut tmp = ioctl::DrmModeCrtc::zeroed();
602 tmp.crtc_id = crtc_id;
603 self.ioctl(ioctl::DRM_IOCTL_MODE_SETCRTC, &mut tmp)?;
604 Ok(tmp.into())
605 }
606
607 pub fn set_crtc_dumb_buffer(
610 &mut self,
611 crtc_id: CrtcId,
612 buf: &modeset::DumbBuffer,
613 mode: &ModeInfo,
614 conn_ids: &[ConnectorId],
615 ) -> Result<modeset::CrtcState, Error> {
616 let mut tmp = ioctl::DrmModeCrtc::zeroed();
617 tmp.crtc_id = crtc_id.0;
618 if conn_ids.len() > (u32::MAX as usize) {
619 return Err(Error::Invalid);
620 }
621 unsafe {
622 tmp.set_set_connectors_ptr(conn_ids.as_ptr() as *const u32, conn_ids.len() as u32)
623 };
624 tmp.fb_id = buf.fb_id.0;
625 tmp.mode = mode.into();
626 tmp.mode_valid = 1;
627
628 self.ioctl(ioctl::DRM_IOCTL_MODE_SETCRTC, &mut tmp)?;
629 Ok(tmp.into())
630 }
631
632 pub fn crtc_page_flip_dumb_buffer(
635 &mut self,
636 crtd_id: CrtcId,
637 buf: &modeset::DumbBuffer,
638 flags: modeset::PageFlipFlags,
639 ) -> Result<(), Error> {
640 let mut tmp = ioctl::DrmModeCrtcPageFlip::zeroed();
641 tmp.crtc_id = crtd_id.0;
642 tmp.fb_id = buf.fb_id.0;
643 tmp.flags = flags.into();
644 self.ioctl(ioctl::DRM_IOCTL_MODE_PAGE_FLIP, &mut tmp)?;
645 Ok(())
646 }
647
648 pub fn create_dumb_buffer(
651 &self,
652 req: modeset::DumbBufferRequest,
653 ) -> Result<modeset::DumbBuffer, Error> {
654 let mut buf_req = ioctl::DrmModeCreateDumb::zeroed();
655 buf_req.width = req.width;
656 buf_req.height = req.height;
657 buf_req.bpp = req.bpp;
658 self.ioctl(ioctl::DRM_IOCTL_MODE_CREATE_DUMB, &mut buf_req)?;
659 let buffer_handle = buf_req.handle;
660 let mut cleanup_db = util::Cleanup::new(|| {
661 let mut msg = crate::ioctl::DrmModeDestroyDumb::zeroed();
662 msg.handle = buffer_handle;
663 let _ = self.ioctl(crate::ioctl::DRM_IOCTL_MODE_DESTROY_DUMB, &mut msg);
664 });
665
666 let mut fb_req = ioctl::DrmModeFbCmd::zeroed();
667 fb_req.width = buf_req.width;
668 fb_req.height = buf_req.height;
669 fb_req.bpp = buf_req.bpp;
670 fb_req.depth = req.depth;
671 fb_req.pitch = buf_req.pitch;
672 fb_req.handle = buf_req.handle;
673 self.ioctl(ioctl::DRM_IOCTL_MODE_ADDFB, &mut fb_req)?;
674 let mut fb_id = fb_req.fb_id;
675 let mut cleanup_fb = util::Cleanup::new(|| {
676 let _ = self.ioctl(crate::ioctl::DRM_IOCTL_MODE_RMFB, &mut fb_id);
677 });
678
679 let mut map_req = ioctl::DrmModeMapDumb::zeroed();
680 map_req.handle = buf_req.handle;
681 self.ioctl(ioctl::DRM_IOCTL_MODE_MAP_DUMB, &mut map_req)?;
682
683 let buf_ptr = unsafe {
684 self.f.mmap_raw(
685 map_req.offset as _,
686 buf_req.size as usize,
687 null_mut(),
688 0b11, 0x01, )?
691 };
692
693 cleanup_fb.cancel();
696 cleanup_db.cancel();
697 Ok(modeset::DumbBuffer {
698 width: buf_req.width,
699 height: buf_req.height,
700 bpp: buf_req.bpp,
701 pitch: buf_req.pitch,
702 ptr: buf_ptr as *mut u8,
703 len: buf_req.size as usize,
704 fb_id: FramebufferId(fb_req.fb_id),
705 buffer_handle: BufferObjectId(buf_req.handle),
706 file: Arc::downgrade(&self.f),
707 })
708 }
709
710 pub fn read_events_raw<'a>(
727 &self,
728 buf: &'a mut [u8],
729 ) -> Result<impl Iterator<Item = &'a event::raw::DrmEvent> + 'a, Error> {
730 let len = self.f.read(buf)?;
731 let buf = &buf[0..len];
732 Ok(event::raw::events_from_bytes(buf))
733 }
734
735 pub fn read_events<'a>(
752 &self,
753 buf: &'a mut [u8],
754 ) -> Result<impl Iterator<Item = event::DrmEvent> + 'a, Error> {
755 let raws = self.read_events_raw(buf)?;
756 Ok(raws.map(|raw| event::DrmEvent::from_raw(raw)))
757 }
758
759 #[inline]
761 pub fn close(self) -> linux_io::result::Result<()> {
762 let f = self.take_file()?;
763 f.close()
764 }
765
766 pub fn take_file(self) -> linux_io::result::Result<linux_io::File<ioctl::DrmCardDevice>> {
768 Arc::into_inner(self.f).ok_or(linux_io::result::EBUSY)
769 }
770
771 #[inline(always)]
773 pub fn borrow_file(&self) -> &linux_io::File<ioctl::DrmCardDevice> {
774 self.f.as_ref()
775 }
776
777 #[inline(always)]
779 pub fn ioctl<'a, Req: IoctlReq<'a, ioctl::DrmCardDevice> + Copy>(
780 &'a self,
781 request: Req,
782 arg: Req::ExtArg,
783 ) -> linux_io::result::Result<Req::Result> {
784 drm_ioctl(&self.f, request, arg)
785 }
786}
787
788pub(crate) fn drm_ioctl<'a, Req: IoctlReq<'a, ioctl::DrmCardDevice> + Copy>(
789 f: &'a linux_io::File<ioctl::DrmCardDevice>,
790 request: Req,
791 arg: Req::ExtArg,
792) -> linux_io::result::Result<Req::Result> {
793 let arg_ptr = &arg as *const _;
801 loop {
802 let arg = unsafe { core::ptr::read(arg_ptr) };
803 let ret = f.ioctl(request, arg);
804 if !matches!(ret, Err(linux_io::result::EINTR)) {
805 return ret;
806 }
807 }
808}
809
810impl<D> TryFrom<linux_io::File<D>> for Card {
811 type Error = InitError;
812
813 #[inline(always)]
814 fn try_from(value: linux_io::File<D>) -> Result<Self, InitError> {
815 Card::from_file(value)
816 }
817}
818
819#[derive(Debug)]
821pub struct ApiVersion {
822 pub major: i64,
823 pub minor: i64,
824 pub patch: i64,
825}
826
827impl core::fmt::Display for ApiVersion {
828 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
829 f.write_fmt(format_args!("{}.{}.{}", self.major, self.minor, self.patch))
830 }
831}
832
833#[repr(u64)]
835#[non_exhaustive]
836pub enum DeviceCap {
837 DumbBuffer = ioctl::DRM_CAP_DUMB_BUFFER.0,
838 VBlankHighCrtc = ioctl::DRM_CAP_VBLANK_HIGH_CRTC.0,
839 DumbPreferredDepth = ioctl::DRM_CAP_DUMB_PREFERRED_DEPTH.0,
840 DumbPreferShadow = ioctl::DRM_CAP_DUMB_PREFER_SHADOW.0,
841 Prime = ioctl::DRM_CAP_PRIME.0,
842 TimestampMonotonic = ioctl::DRM_CAP_TIMESTAMP_MONOTONIC.0,
843 AsyncPageFlip = ioctl::DRM_CAP_ASYNC_PAGE_FLIP.0,
844 CursorWidth = ioctl::DRM_CAP_CURSOR_WIDTH.0,
845 CursorHeight = ioctl::DRM_CAP_CURSOR_HEIGHT.0,
846 Addfb2Modifiers = ioctl::DRM_CAP_ADDFB2_MODIFIERS.0,
847 PageFlipTarget = ioctl::DRM_CAP_PAGE_FLIP_TARGET.0,
848 CrtcInVblankEvent = ioctl::DRM_CAP_CRTC_IN_VBLANK_EVENT.0,
849 Syncobj = ioctl::DRM_CAP_SYNCOBJ.0,
850 SyncobjTimeline = ioctl::DRM_CAP_SYNCOBJ_TIMELINE.0,
851}
852
853impl From<DeviceCap> for ioctl::DrmCap {
854 #[inline(always)]
855 fn from(value: DeviceCap) -> Self {
856 ioctl::DrmCap(value as u64)
859 }
860}
861
862#[repr(u64)]
864#[non_exhaustive]
865pub enum ClientCap {
866 Stereo3d = ioctl::DRM_CLIENT_CAP_STEREO_3D.0,
867 UniversalPlanes = ioctl::DRM_CLIENT_CAP_UNIVERSAL_PLANES.0,
868 Atomic = ioctl::DRM_CLIENT_CAP_ATOMIC.0,
869 AspectRatio = ioctl::DRM_CLIENT_CAP_ASPECT_RATIO.0,
870 WritebackConnectors = ioctl::DRM_CLIENT_CAP_WRITEBACK_CONNECTORS.0,
871 CursorPlaneHotspot = ioctl::DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT.0,
872}
873
874impl From<ClientCap> for ioctl::DrmClientCap {
875 #[inline(always)]
876 fn from(value: ClientCap) -> Self {
877 ioctl::DrmClientCap(value as u64)
880 }
881}
882
883pub(crate) fn vec_with_capacity<T>(
890 capacity: usize,
891) -> Result<Vec<T>, alloc::collections::TryReserveError> {
892 let mut ret = Vec::<T>::new();
893 ret.try_reserve_exact(capacity)?;
894 Ok(ret)
895}