linux_drm/event/
raw.rs

1/// A raw DRM event.
2///
3/// This is a dynamically-sized type because DRM returns events of varying
4/// sizes. DRM events typically come from reading the file descriptor
5/// associated with a "card" device.
6///
7/// If you have a byte slice you've read from a card device then you can
8/// use [`DrmEvent::from_bytes`] to safely build a `DrmEvent` from the
9/// first event, if any.
10#[cfg_attr(feature = "stable_polyfill", derive(ptr_meta::Pointee))]
11#[repr(C)]
12pub struct DrmEvent {
13    pub hdr: DrmEventHeader,
14    pub body: [u8],
15}
16
17impl DrmEvent {
18    const HEADER_LEN: usize = core::mem::size_of::<DrmEventHeader>();
19
20    /// Given a reference to the header part of a valid event,
21    /// reinterprets it into a full [`DrmEvent`] object.
22    ///
23    /// # Safety
24    ///
25    /// The given reference must be to a valid header that is
26    /// at the start of an event object whose length matches that
27    /// given in the header. The result is a wide pointer
28    /// that tracks the body length, which safe Rust cannot
29    /// modify and so can be relied on by safe methods of
30    /// [`DrmEvent`] while the header length cannot.
31    pub unsafe fn from_event_header<'a>(hdr: &'a DrmEventHeader) -> &'a DrmEvent {
32        let ptr = hdr as *const _ as *const ();
33        #[cfg(feature = "stable_polyfill")]
34        let ptr = ptr_meta::from_raw_parts(ptr, hdr.len as usize - Self::HEADER_LEN);
35
36        #[cfg(not(feature = "stable_polyfill"))]
37        let ptr = core::ptr::from_raw_parts(ptr, hdr.len as usize - Self::HEADER_LEN);
38        &*ptr
39    }
40
41    /// Given a byte slice that contains zero or more DRM
42    /// events, obtain the first event and a slice of the remaining
43    /// bytes, or `None` if there aren't enough bytes left to extract
44    /// even one event.
45    ///
46    /// The returned event does not necessarily have valid
47    /// content. The only checking done by this function is
48    /// that there are enough bytes in the slice for the
49    /// length claimed in the header field.
50    pub fn from_bytes<'a>(buf: &'a [u8]) -> Option<(&'a DrmEvent, &'a [u8])> {
51        if buf.len() < Self::HEADER_LEN {
52            return None;
53        }
54        let hdr_bytes = &buf[0..Self::HEADER_LEN];
55        // Safety: We checked above that we have at least enough bytes for
56        // an event header, and all bit patterns are defined values for
57        // DrmEventHeader.
58        let hdr = unsafe { &*(hdr_bytes.as_ptr() as *const DrmEventHeader) };
59        let claimed_len = hdr.len as usize;
60        if buf.len() < claimed_len {
61            // The header thinks there are more bytes in this event
62            // than we have left in our slice, so clearly something
63            // has gone wrong here but we'll treat it as if there
64            // aren't any more events.
65            return None;
66        }
67        // Safety: We've checked that the header isn't asking for more
68        // bytes than we have.
69        let ret = unsafe { Self::from_event_header(hdr) };
70        Some((ret, &buf[claimed_len..]))
71    }
72
73    /// Get the length of the body in bytes.
74    ///
75    /// This is based on the information stored in the wide pointer
76    /// underlying `self`, and so ignores the length given in
77    /// the header.
78    pub fn body_len(&self) -> usize {
79        let ptr = self as *const DrmEvent;
80
81        #[cfg(not(feature = "stable_polyfill"))]
82        let (_, body_len) = ptr.to_raw_parts();
83
84        #[cfg(feature = "stable_polyfill")]
85        let (_, body_len) = ptr_meta::to_raw_parts(ptr);
86
87        body_len
88    }
89
90    /// Get the body of the event as a raw byte slice.
91    #[inline(always)]
92    pub fn body_bytes(&self) -> &[u8] {
93        &self.body
94    }
95
96    /// Get a pointer to the event body that interprets it as a
97    /// value of `T`.
98    ///
99    /// Dereferencing the returned pointer is undefined behavior
100    /// unless the body is long enough to contain a `T` and
101    /// contains a valid representation of `T`.
102    #[inline(always)]
103    pub fn body_ptr<T: Sized>(&self) -> *const T {
104        &self.body as *const _ as *const T
105    }
106
107    /// Get a reference to the body interpreted as type `T`
108    /// only if the body is at least long enough to fit
109    /// a value of that type.
110    ///
111    /// # Safety
112    ///
113    /// Caller must ensure that the raw body is a valid
114    /// representation of `T`. If all bit patterns are
115    /// valid representations of `T` then this is always
116    /// safe but the result might still be nonsense.
117    pub unsafe fn body_as<T>(&self) -> Option<&T> {
118        let min_size = core::mem::size_of::<T>();
119        if self.body_len() < min_size {
120            return None;
121        }
122        Some(self.body_as_unchecked::<T>())
123    }
124
125    /// Returns a reference to the body interpreted as type `T`
126    /// without checking whether the header's indicated length
127    /// is long enough for that type.
128    ///
129    /// # Safety
130    ///
131    /// Caller must ensure that there's enough valid memory after
132    /// the event header for a `T` and that the data there is
133    /// a valid representation of `T`.
134    #[inline(always)]
135    pub unsafe fn body_as_unchecked<T>(&self) -> &T {
136        let ptr = self.body_ptr::<T>();
137        &*ptr
138    }
139}
140
141/// Raw DRM event header.
142#[repr(C)]
143#[derive(Clone, Copy, Debug)]
144pub struct DrmEventHeader {
145    pub typ: u32,
146    pub len: u32,
147}
148
149/// Vertical blanking event.
150///
151/// This event is sent in response to `DRM_IOCTL_WAIT_VBLANK` with the
152/// `DRM_VBLANK_EVENT` flag set.
153///
154/// The event body type is [`DrmEventVblank`].
155pub const DRM_EVENT_VBLANK: u32 = 0x01;
156
157/// Page-flip completion event.
158///
159/// This event is sent in response to an atomic commit or legacy page-flip with
160/// the `DRM_MODE_PAGE_FLIP_EVENT` flag set.
161///
162/// The event body type is [`DrmEventVblank`].
163pub const DRM_EVENT_FLIP_COMPLETE: u32 = 0x02;
164
165/// CRTC sequence event.
166///
167/// This event is sent in response to `DRM_IOCTL_CRTC_QUEUE_SEQUENCE`.
168///
169/// The event body type is [`DrmEventCrtcSequence`].
170pub const DRM_EVENT_CRTC_SEQUENCE: u32 = 0x03;
171
172/// The body of a [`DRM_EVENT_VBLANK`] event.
173#[repr(C)]
174#[derive(Clone, Copy, Debug)]
175pub struct DrmEventVblank {
176    pub user_data: u64,
177    pub tv_sec: u32,
178    pub tv_usec: u32,
179    pub sequence: u32,
180    pub crtc_id: u32, // always zero in older kernels that don't support this
181}
182
183/// The body of a [`DRM_EVENT_CRTC_SEQUENCE`] event.
184#[repr(C)]
185#[derive(Clone, Copy, Debug)]
186pub struct DrmEventCrtcSequence {
187    pub user_data: u64,
188    pub time_ns: i64,
189    pub sequence: u64,
190}
191
192pub fn events_from_bytes<'a>(buf: &'a [u8]) -> impl Iterator<Item = &'a DrmEvent> + 'a {
193    DrmEventsFromBytes { remain: buf }
194}
195
196struct DrmEventsFromBytes<'a> {
197    remain: &'a [u8],
198}
199
200impl<'a> Iterator for DrmEventsFromBytes<'a> {
201    type Item = &'a DrmEvent;
202
203    fn next(&mut self) -> Option<Self::Item> {
204        let (ret, remain) = DrmEvent::from_bytes(self.remain)?;
205        self.remain = remain;
206        Some(ret)
207    }
208}