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::os::unix::io::AsFd; 45 use std::{fmt::Debug, ops::Deref}; 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 indexables of `PlaneHandle` (e.g. [`std::vec::Vec`]). 146 /// 147 /// This is The simplest way to use primitive handles. 148 impl<P, Q> BufferHandles for Q 149 where 150 P: PlaneHandle, 151 Q: Send + Debug + 'static + Deref<Target = [P]>, 152 { 153 type SupportedMemoryType = MemoryType; 154 len(&self) -> usize155 fn len(&self) -> usize { 156 self.deref().len() 157 } 158 fill_v4l2_plane(&self, index: usize, plane: &mut bindings::v4l2_plane)159 fn fill_v4l2_plane(&self, index: usize, plane: &mut bindings::v4l2_plane) { 160 self.deref()[index].fill_v4l2_plane(plane); 161 } 162 } 163 164 /// Trait for plane handles for which the final memory type is known at compile 165 /// time. 166 pub trait PrimitiveBufferHandles: BufferHandles { 167 type HandleType: PlaneHandle; 168 const MEMORY_TYPE: Self::SupportedMemoryType; 169 } 170 171 /// Implementation of `PrimitiveBufferHandles` for all indexables of `PlaneHandle` (e.g. 172 /// [`std::vec::Vec`]). 173 impl<P, Q> PrimitiveBufferHandles for Q 174 where 175 P: PlaneHandle, 176 Q: Send + Debug + 'static + Deref<Target = [P]>, 177 { 178 type HandleType = P; 179 const MEMORY_TYPE: Self::SupportedMemoryType = P::Memory::MEMORY_TYPE; 180 } 181 182 /// Conversion from `v4l2_buffer`'s backing information to `v4l2_plane`'s. 183 impl From<(&v4l2_buffer__bindgen_ty_1, MemoryType)> for v4l2_plane__bindgen_ty_1 { from((m, memory): (&v4l2_buffer__bindgen_ty_1, MemoryType)) -> Self184 fn from((m, memory): (&v4l2_buffer__bindgen_ty_1, MemoryType)) -> Self { 185 match memory { 186 MemoryType::Mmap => v4l2_plane__bindgen_ty_1 { 187 // Safe because the buffer type is determined to be MMAP. 188 mem_offset: unsafe { m.offset }, 189 }, 190 MemoryType::UserPtr => v4l2_plane__bindgen_ty_1 { 191 // Safe because the buffer type is determined to be USERPTR. 192 userptr: unsafe { m.userptr }, 193 }, 194 MemoryType::DmaBuf => v4l2_plane__bindgen_ty_1 { 195 // Safe because the buffer type is determined to be DMABUF. 196 fd: unsafe { m.fd }, 197 }, 198 MemoryType::Overlay => Default::default(), 199 } 200 } 201 } 202 203 /// Conversion from `v4l2_plane`'s backing information to `v4l2_buffer`'s. 204 impl From<(&v4l2_plane__bindgen_ty_1, MemoryType)> for v4l2_buffer__bindgen_ty_1 { from((m, memory): (&v4l2_plane__bindgen_ty_1, MemoryType)) -> Self205 fn from((m, memory): (&v4l2_plane__bindgen_ty_1, MemoryType)) -> Self { 206 match memory { 207 MemoryType::Mmap => v4l2_buffer__bindgen_ty_1 { 208 // Safe because the buffer type is determined to be MMAP. 209 offset: unsafe { m.mem_offset }, 210 }, 211 MemoryType::UserPtr => v4l2_buffer__bindgen_ty_1 { 212 // Safe because the buffer type is determined to be USERPTR. 213 userptr: unsafe { m.userptr }, 214 }, 215 MemoryType::DmaBuf => v4l2_buffer__bindgen_ty_1 { 216 // Safe because the buffer type is determined to be DMABUF. 217 fd: unsafe { m.fd }, 218 }, 219 MemoryType::Overlay => Default::default(), 220 } 221 } 222 } 223 224 #[cfg(test)] 225 mod tests { 226 use crate::bindings::v4l2_buffer__bindgen_ty_1; 227 use crate::bindings::v4l2_plane__bindgen_ty_1; 228 use crate::memory::MemoryType; 229 230 #[test] 231 // Purpose of this test is dubious as the members are overlapping anyway. plane_m_to_buffer_m()232 fn plane_m_to_buffer_m() { 233 let plane_m = v4l2_plane__bindgen_ty_1 { 234 mem_offset: 0xfeedc0fe, 235 }; 236 assert_eq!( 237 unsafe { v4l2_buffer__bindgen_ty_1::from((&plane_m, MemoryType::Mmap)).offset }, 238 0xfeedc0fe 239 ); 240 241 let plane_m = v4l2_plane__bindgen_ty_1 { 242 userptr: 0xfeedc0fe, 243 }; 244 assert_eq!( 245 unsafe { v4l2_buffer__bindgen_ty_1::from((&plane_m, MemoryType::UserPtr)).userptr }, 246 0xfeedc0fe 247 ); 248 249 let plane_m = v4l2_plane__bindgen_ty_1 { fd: 0x76543210 }; 250 assert_eq!( 251 unsafe { v4l2_buffer__bindgen_ty_1::from((&plane_m, MemoryType::DmaBuf)).fd }, 252 0x76543210 253 ); 254 } 255 256 #[test] 257 // Purpose of this test is dubious as the members are overlapping anyway. buffer_m_to_plane_m()258 fn buffer_m_to_plane_m() { 259 let buffer_m = v4l2_buffer__bindgen_ty_1 { offset: 0xfeedc0fe }; 260 assert_eq!( 261 unsafe { v4l2_plane__bindgen_ty_1::from((&buffer_m, MemoryType::Mmap)).mem_offset }, 262 0xfeedc0fe 263 ); 264 265 let buffer_m = v4l2_buffer__bindgen_ty_1 { 266 userptr: 0xfeedc0fe, 267 }; 268 assert_eq!( 269 unsafe { v4l2_plane__bindgen_ty_1::from((&buffer_m, MemoryType::UserPtr)).userptr }, 270 0xfeedc0fe 271 ); 272 273 let buffer_m = v4l2_buffer__bindgen_ty_1 { fd: 0x76543210 }; 274 assert_eq!( 275 unsafe { v4l2_plane__bindgen_ty_1::from((&buffer_m, MemoryType::DmaBuf)).fd }, 276 0x76543210 277 ); 278 } 279 } 280