1 //! Abstracts the different kinds of backing memory (`MMAP`, `USERPTR`,
2 //! `DMABUF`) supported by V4L2.
3 //!
4 //! V4L2 allows to use either memory that is provided by the device itself
5 //! (MMAP) or memory imported via user allocation (USERPTR) or the dma-buf
6 //! subsystem (DMABUF). This results in 2 very different behaviors and 3 memory
7 //! types that we need to model.
8 //!
9 //! The `Memory` trait represents these memory types and is thus implemented
10 //! by exacly 3 types: `MMAP`, `UserPtr`, and `DMABuf`. These types do very
11 //! little apart from providing a constant with the corresponding V4L2 memory
12 //! type they model, and implement the `SelfBacked` (for MMAP) or `Imported`
13 //! (for `UserPtr` and `DMABuf`) traits to indicate where their memory comes
14 //! from.
15 //!
16 //! The `PlaneHandle` trait is used by types which can bind to one of these
17 //! memory types, i.e. a type that can represent a single memory plane of a
18 //! buffer. For `MMAP` memory this is a void type (since `MMAP` provides its
19 //! own memory). `UserPtr`, a `Vec<u8>` can adequately be used as backing
20 //! memory, and for `DMABuf` we will use a file descriptor. For handles that
21 //! can be mapped into the user address-space (and indeed for `MMAP` this is
22 //! the only way to access the memory), the `Mappable` trait can be implemented.
23 //!
24 //! The set of handles that make all the planes for a given buffer is
25 //! represented by the `BufferHandles` trait. This trait is more abstract since
26 //! we may want to decide at runtime the kind of memory we want to use ;
27 //! therefore this trait does not have any particular kind of memory attached to
28 //! it. `PrimitiveBufferHandles` is used to represent plane handles which memory
29 //! type is known at compilation time, and thus includes a reference to a
30 //! `PlaneHandle` type and by transition its `Memory` type.
31 mod dmabuf;
32 mod mmap;
33 mod userptr;
34 
35 pub use dmabuf::*;
36 pub use mmap::*;
37 pub use userptr::*;
38 
39 use crate::{
40     bindings::{self, v4l2_buffer__bindgen_ty_1, v4l2_plane__bindgen_ty_1},
41     ioctl::{PlaneMapping, QueryBufPlane},
42 };
43 use enumn::N;
44 use std::fmt::Debug;
45 use std::os::unix::io::AsFd;
46 
47 /// All the supported V4L2 memory types.
48 #[derive(Debug, Clone, Copy, PartialEq, Eq, N)]
49 #[repr(u32)]
50 pub enum MemoryType {
51     Mmap = bindings::v4l2_memory_V4L2_MEMORY_MMAP,
52     UserPtr = bindings::v4l2_memory_V4L2_MEMORY_USERPTR,
53     Overlay = bindings::v4l2_memory_V4L2_MEMORY_OVERLAY,
54     DmaBuf = bindings::v4l2_memory_V4L2_MEMORY_DMABUF,
55 }
56 
57 /// Trait describing a memory type that can be used to back V4L2 buffers.
58 pub trait Memory: 'static {
59     /// The memory type represented.
60     const MEMORY_TYPE: MemoryType;
61     /// The final type of the memory backing information in `struct v4l2_buffer` or `struct
62     /// v4l2_plane`.
63     type RawBacking;
64 
65     /// Returns a reference to the memory backing information for `m` that is relevant for this
66     /// memory type.
67     ///
68     /// # Safety
69     ///
70     /// The caller must ensure that `m` indeed belongs to a buffer of this memory type.
get_plane_buffer_backing(m: &bindings::v4l2_plane__bindgen_ty_1) -> &Self::RawBacking71     unsafe fn get_plane_buffer_backing(m: &bindings::v4l2_plane__bindgen_ty_1)
72         -> &Self::RawBacking;
73 
74     /// Returns a reference to the memory backing information for `m` that is relevant for this memory type.
75     ///
76     /// # Safety
77     ///
78     /// The caller must ensure that `m` indeed belongs to a buffer of this memory type.
get_single_planar_buffer_backing( m: &bindings::v4l2_buffer__bindgen_ty_1, ) -> &Self::RawBacking79     unsafe fn get_single_planar_buffer_backing(
80         m: &bindings::v4l2_buffer__bindgen_ty_1,
81     ) -> &Self::RawBacking;
82 
83     /// Returns a mutable reference to the memory backing information for `m` that is relevant for
84     /// this memory type.
85     ///
86     /// # Safety
87     ///
88     /// The caller must ensure that `m` indeed belongs to a buffer of this memory type.
get_plane_buffer_backing_mut( m: &mut bindings::v4l2_plane__bindgen_ty_1, ) -> &mut Self::RawBacking89     unsafe fn get_plane_buffer_backing_mut(
90         m: &mut bindings::v4l2_plane__bindgen_ty_1,
91     ) -> &mut Self::RawBacking;
92 
93     /// Returns a mutable reference to the memory backing information for `m` that is relevant for
94     /// this memory type.
95     ///
96     /// # Safety
97     ///
98     /// The caller must ensure that `m` indeed belongs to a buffer of this memory type.
get_single_planar_buffer_backing_mut( m: &mut bindings::v4l2_buffer__bindgen_ty_1, ) -> &mut Self::RawBacking99     unsafe fn get_single_planar_buffer_backing_mut(
100         m: &mut bindings::v4l2_buffer__bindgen_ty_1,
101     ) -> &mut Self::RawBacking;
102 }
103 
104 /// Trait for memory types that provide their own memory, i.e. MMAP.
105 pub trait SelfBacked: Memory + Default {}
106 
107 /// Trait for memory types to which external memory must be attached to, i.e. UserPtr and
108 /// DMABuf.
109 pub trait Imported: Memory {}
110 
111 /// Trait for a handle that represents actual data for a single place. A buffer
112 /// will have as many of these as it has planes.
113 pub trait PlaneHandle: Debug + Send + 'static {
114     /// The kind of memory the handle attaches to.
115     type Memory: Memory;
116 
117     /// Fill a plane of a multi-planar V4L2 buffer with the handle's information.
fill_v4l2_plane(&self, plane: &mut bindings::v4l2_plane)118     fn fill_v4l2_plane(&self, plane: &mut bindings::v4l2_plane);
119 }
120 
121 // Trait for plane handles that provide access to their content through a map()
122 // method (typically, MMAP buffers).
123 pub trait Mappable: PlaneHandle {
124     /// Return a `PlaneMapping` enabling access to the memory of this handle.
map<D: AsFd>(device: &D, plane_info: &QueryBufPlane) -> Option<PlaneMapping>125     fn map<D: AsFd>(device: &D, plane_info: &QueryBufPlane) -> Option<PlaneMapping>;
126 }
127 
128 /// Trait for structures providing all the handles of a single buffer.
129 pub trait BufferHandles: Send + Debug + 'static {
130     /// Enumeration of all the `MemoryType` supported by this type. Typically
131     /// a subset of `MemoryType` or `MemoryType` itself.
132     type SupportedMemoryType: Into<MemoryType> + Send + Clone + Copy;
133 
134     /// Number of planes.
len(&self) -> usize135     fn len(&self) -> usize;
136     /// Fill a plane of a multi-planar V4L2 buffer with the `index` handle's information.
fill_v4l2_plane(&self, index: usize, plane: &mut bindings::v4l2_plane)137     fn fill_v4l2_plane(&self, index: usize, plane: &mut bindings::v4l2_plane);
138 
139     /// Returns true if there are no handles here (unlikely).
is_empty(&self) -> bool140     fn is_empty(&self) -> bool {
141         self.len() == 0
142     }
143 }
144 
145 /// Implementation of `BufferHandles` for all vectors of `PlaneHandle`. This is
146 /// The simplest way to use primitive handles.
147 impl<P: PlaneHandle> BufferHandles for Vec<P> {
148     type SupportedMemoryType = MemoryType;
149 
len(&self) -> usize150     fn len(&self) -> usize {
151         self.len()
152     }
153 
fill_v4l2_plane(&self, index: usize, plane: &mut bindings::v4l2_plane)154     fn fill_v4l2_plane(&self, index: usize, plane: &mut bindings::v4l2_plane) {
155         self[index].fill_v4l2_plane(plane);
156     }
157 }
158 
159 /// Trait for plane handles for which the final memory type is known at compile
160 /// time.
161 pub trait PrimitiveBufferHandles: BufferHandles {
162     type HandleType: PlaneHandle;
163     const MEMORY_TYPE: Self::SupportedMemoryType;
164 }
165 
166 /// Implementation of `PrimitiveBufferHandles` for all vectors of `PlaneHandle`.
167 impl<P: PlaneHandle> PrimitiveBufferHandles for Vec<P> {
168     type HandleType = P;
169     const MEMORY_TYPE: Self::SupportedMemoryType = P::Memory::MEMORY_TYPE;
170 }
171 
172 /// Conversion from `v4l2_buffer`'s backing information to `v4l2_plane`'s.
173 impl From<(&v4l2_buffer__bindgen_ty_1, MemoryType)> for v4l2_plane__bindgen_ty_1 {
from((m, memory): (&v4l2_buffer__bindgen_ty_1, MemoryType)) -> Self174     fn from((m, memory): (&v4l2_buffer__bindgen_ty_1, MemoryType)) -> Self {
175         match memory {
176             MemoryType::Mmap => v4l2_plane__bindgen_ty_1 {
177                 // Safe because the buffer type is determined to be MMAP.
178                 mem_offset: unsafe { m.offset },
179             },
180             MemoryType::UserPtr => v4l2_plane__bindgen_ty_1 {
181                 // Safe because the buffer type is determined to be USERPTR.
182                 userptr: unsafe { m.userptr },
183             },
184             MemoryType::DmaBuf => v4l2_plane__bindgen_ty_1 {
185                 // Safe because the buffer type is determined to be DMABUF.
186                 fd: unsafe { m.fd },
187             },
188             MemoryType::Overlay => Default::default(),
189         }
190     }
191 }
192 
193 /// Conversion from `v4l2_plane`'s backing information to `v4l2_buffer`'s.
194 impl From<(&v4l2_plane__bindgen_ty_1, MemoryType)> for v4l2_buffer__bindgen_ty_1 {
from((m, memory): (&v4l2_plane__bindgen_ty_1, MemoryType)) -> Self195     fn from((m, memory): (&v4l2_plane__bindgen_ty_1, MemoryType)) -> Self {
196         match memory {
197             MemoryType::Mmap => v4l2_buffer__bindgen_ty_1 {
198                 // Safe because the buffer type is determined to be MMAP.
199                 offset: unsafe { m.mem_offset },
200             },
201             MemoryType::UserPtr => v4l2_buffer__bindgen_ty_1 {
202                 // Safe because the buffer type is determined to be USERPTR.
203                 userptr: unsafe { m.userptr },
204             },
205             MemoryType::DmaBuf => v4l2_buffer__bindgen_ty_1 {
206                 // Safe because the buffer type is determined to be DMABUF.
207                 fd: unsafe { m.fd },
208             },
209             MemoryType::Overlay => Default::default(),
210         }
211     }
212 }
213 
214 #[cfg(test)]
215 mod tests {
216     use crate::bindings::v4l2_buffer__bindgen_ty_1;
217     use crate::bindings::v4l2_plane__bindgen_ty_1;
218     use crate::memory::MemoryType;
219 
220     #[test]
221     // Purpose of this test is dubious as the members are overlapping anyway.
plane_m_to_buffer_m()222     fn plane_m_to_buffer_m() {
223         let plane_m = v4l2_plane__bindgen_ty_1 {
224             mem_offset: 0xfeedc0fe,
225         };
226         assert_eq!(
227             unsafe { v4l2_buffer__bindgen_ty_1::from((&plane_m, MemoryType::Mmap)).offset },
228             0xfeedc0fe
229         );
230 
231         let plane_m = v4l2_plane__bindgen_ty_1 {
232             userptr: 0xfeedc0fe,
233         };
234         assert_eq!(
235             unsafe { v4l2_buffer__bindgen_ty_1::from((&plane_m, MemoryType::UserPtr)).userptr },
236             0xfeedc0fe
237         );
238 
239         let plane_m = v4l2_plane__bindgen_ty_1 { fd: 0x76543210 };
240         assert_eq!(
241             unsafe { v4l2_buffer__bindgen_ty_1::from((&plane_m, MemoryType::DmaBuf)).fd },
242             0x76543210
243         );
244     }
245 
246     #[test]
247     // Purpose of this test is dubious as the members are overlapping anyway.
buffer_m_to_plane_m()248     fn buffer_m_to_plane_m() {
249         let buffer_m = v4l2_buffer__bindgen_ty_1 { offset: 0xfeedc0fe };
250         assert_eq!(
251             unsafe { v4l2_plane__bindgen_ty_1::from((&buffer_m, MemoryType::Mmap)).mem_offset },
252             0xfeedc0fe
253         );
254 
255         let buffer_m = v4l2_buffer__bindgen_ty_1 {
256             userptr: 0xfeedc0fe,
257         };
258         assert_eq!(
259             unsafe { v4l2_plane__bindgen_ty_1::from((&buffer_m, MemoryType::UserPtr)).userptr },
260             0xfeedc0fe
261         );
262 
263         let buffer_m = v4l2_buffer__bindgen_ty_1 { fd: 0x76543210 };
264         assert_eq!(
265             unsafe { v4l2_plane__bindgen_ty_1::from((&buffer_m, MemoryType::DmaBuf)).fd },
266             0x76543210
267         );
268     }
269 }
270