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