xref: /aosp_15_r20/external/virtio-media/device/src/devices/v4l2_device_proxy.rs (revision 1b4853f54772485c5dd4001ae33a7a958bcc97a1)
1 // Copyright 2024 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! This module uses `v4l2r` to proxy a host V4L2 device into the guest.
6 
7 use std::collections::BTreeMap;
8 use std::io::Result as IoResult;
9 use std::os::fd::AsFd;
10 use std::os::fd::BorrowedFd;
11 use std::os::fd::OwnedFd;
12 use std::path::PathBuf;
13 use std::sync::Arc;
14 use std::time::Duration;
15 
16 use log::error;
17 use log::warn;
18 use v4l2r::bindings::v4l2_audio;
19 use v4l2r::bindings::v4l2_audioout;
20 use v4l2r::bindings::v4l2_control;
21 use v4l2r::bindings::v4l2_create_buffers;
22 use v4l2r::bindings::v4l2_decoder_cmd;
23 use v4l2r::bindings::v4l2_dv_timings;
24 use v4l2r::bindings::v4l2_dv_timings_cap;
25 use v4l2r::bindings::v4l2_enc_idx;
26 use v4l2r::bindings::v4l2_encoder_cmd;
27 use v4l2r::bindings::v4l2_event;
28 use v4l2r::bindings::v4l2_event_subscription;
29 use v4l2r::bindings::v4l2_ext_control;
30 use v4l2r::bindings::v4l2_ext_controls;
31 use v4l2r::bindings::v4l2_fmtdesc;
32 use v4l2r::bindings::v4l2_format;
33 use v4l2r::bindings::v4l2_frequency;
34 use v4l2r::bindings::v4l2_frequency_band;
35 use v4l2r::bindings::v4l2_frmivalenum;
36 use v4l2r::bindings::v4l2_frmsizeenum;
37 use v4l2r::bindings::v4l2_input;
38 use v4l2r::bindings::v4l2_modulator;
39 use v4l2r::bindings::v4l2_output;
40 use v4l2r::bindings::v4l2_query_ext_ctrl;
41 use v4l2r::bindings::v4l2_queryctrl;
42 use v4l2r::bindings::v4l2_querymenu;
43 use v4l2r::bindings::v4l2_rect;
44 use v4l2r::bindings::v4l2_requestbuffers;
45 use v4l2r::bindings::v4l2_standard;
46 use v4l2r::bindings::v4l2_std_id;
47 use v4l2r::bindings::v4l2_streamparm;
48 use v4l2r::bindings::v4l2_tuner;
49 use v4l2r::device::poller::DeviceEvent;
50 use v4l2r::device::poller::PollEvent;
51 use v4l2r::device::poller::Poller;
52 pub use v4l2r::device::Device as V4l2Device;
53 use v4l2r::device::DeviceConfig;
54 use v4l2r::device::DeviceOpenError;
55 use v4l2r::ioctl::AudioMode;
56 use v4l2r::ioctl::BufferFlags;
57 use v4l2r::ioctl::CtrlId;
58 use v4l2r::ioctl::CtrlWhich;
59 use v4l2r::ioctl::DqBufError;
60 use v4l2r::ioctl::DqBufIoctlError;
61 use v4l2r::ioctl::DqEventError;
62 use v4l2r::ioctl::EventType as V4l2EventType;
63 use v4l2r::ioctl::ExpbufFlags;
64 use v4l2r::ioctl::ExtControlError;
65 use v4l2r::ioctl::IntoErrno;
66 use v4l2r::ioctl::QueryCapError;
67 use v4l2r::ioctl::QueryCtrlFlags;
68 use v4l2r::ioctl::SelectionFlags;
69 use v4l2r::ioctl::SelectionTarget;
70 use v4l2r::ioctl::SelectionType;
71 use v4l2r::ioctl::SubscribeEventFlags;
72 use v4l2r::ioctl::TunerMode;
73 use v4l2r::ioctl::TunerTransmissionFlags;
74 use v4l2r::ioctl::TunerType;
75 use v4l2r::ioctl::V4l2Buffer;
76 use v4l2r::ioctl::V4l2PlanesWithBacking;
77 use v4l2r::ioctl::V4l2PlanesWithBackingMut;
78 use v4l2r::memory::Memory;
79 use v4l2r::memory::MemoryType;
80 use v4l2r::memory::UserPtr;
81 use v4l2r::QueueDirection;
82 use v4l2r::QueueType;
83 
84 use crate::ioctl::virtio_media_dispatch_ioctl;
85 use crate::ioctl::IoctlResult;
86 use crate::ioctl::VirtioMediaIoctlHandler;
87 use crate::mmap::MmapMappingManager;
88 use crate::protocol::DequeueBufferEvent;
89 use crate::protocol::SessionEvent;
90 use crate::protocol::SgEntry;
91 use crate::protocol::V4l2Event;
92 use crate::protocol::V4l2Ioctl;
93 use crate::protocol::VIRTIO_MEDIA_MMAP_FLAG_RW;
94 use crate::GuestMemoryRange;
95 use crate::VirtioMediaDevice;
96 use crate::VirtioMediaDeviceSession;
97 use crate::VirtioMediaEventQueue;
98 use crate::VirtioMediaGuestMemoryMapper;
99 use crate::VirtioMediaHostMemoryMapper;
100 
101 type GuestAddrType = <UserPtr as Memory>::RawBacking;
102 
guest_v4l2_buffer_to_host<M: VirtioMediaGuestMemoryMapper>( guest_buffer: &V4l2Buffer, guest_regions: Vec<Vec<SgEntry>>, m: &M, ) -> anyhow::Result<(V4l2Buffer, Vec<M::GuestMemoryMapping>)>103 fn guest_v4l2_buffer_to_host<M: VirtioMediaGuestMemoryMapper>(
104     guest_buffer: &V4l2Buffer,
105     guest_regions: Vec<Vec<SgEntry>>,
106     m: &M,
107 ) -> anyhow::Result<(V4l2Buffer, Vec<M::GuestMemoryMapping>)> {
108     let mut resources = vec![];
109     // The host buffer is a copy of the guest's with its plane resources updated.
110     let mut host_buffer = guest_buffer.clone();
111     let writable = host_buffer.queue().direction() == QueueDirection::Capture;
112 
113     if let V4l2PlanesWithBackingMut::UserPtr(host_planes) =
114         host_buffer.planes_with_backing_iter_mut()
115     {
116         for (mut host_plane, mem_regions) in
117             host_planes.filter(|p| *p.length > 0).zip(guest_regions)
118         {
119             let mut mapping = m.new_mapping(mem_regions)?;
120 
121             host_plane.set_userptr(if writable {
122                 mapping.as_mut_ptr()
123             } else {
124                 mapping.as_ptr()
125             } as GuestAddrType);
126             resources.push(mapping);
127         }
128     };
129 
130     Ok((host_buffer, resources))
131 }
132 
133 /// Restore the user pointers of `host_buffer` using the values in `initial_guest_buffer`, if the buffer's
134 /// memory type is `USERPTR`. This allows a buffer processed on the host to be passed back to the
135 /// guest with the correct values.
host_v4l2_buffer_to_guest<R>( host_buffer: &V4l2Buffer, userptr_buffers: &BTreeMap<GuestAddrType, V4l2UserPlaneInfo<R>>, ) -> anyhow::Result<V4l2Buffer>136 fn host_v4l2_buffer_to_guest<R>(
137     host_buffer: &V4l2Buffer,
138     userptr_buffers: &BTreeMap<GuestAddrType, V4l2UserPlaneInfo<R>>,
139 ) -> anyhow::Result<V4l2Buffer> {
140     // The guest buffer is a copy of the host's with its plane resources updated.
141     let mut guest_buffer = host_buffer.clone();
142 
143     if let V4l2PlanesWithBackingMut::UserPtr(host_planes) =
144         guest_buffer.planes_with_backing_iter_mut()
145     {
146         for mut plane in host_planes.filter(|p| p.userptr() != 0) {
147             let host_userptr = plane.userptr();
148             let guest_userptr = userptr_buffers
149                 .get(&(host_userptr as GuestAddrType))
150                 .map(|p| p.guest_addr)
151                 .ok_or_else(|| {
152                     anyhow::anyhow!("host buffer address 0x{:x} not registered!", host_userptr)
153                 })?;
154             plane.set_userptr(guest_userptr as GuestAddrType);
155         }
156     }
157 
158     Ok(guest_buffer)
159 }
160 
161 #[derive(Clone, Copy, Debug)]
162 enum ExtCtrlIoctl {
163     Get,
164     Set,
165     Try,
166 }
167 
perform_ext_ctrls_ioctl<M: VirtioMediaGuestMemoryMapper>( ioctl: ExtCtrlIoctl, device: &V4l2Device, mem: &M, which: CtrlWhich, ctrls: ( &mut v4l2_ext_controls, &mut Vec<v4l2_ext_control>, Vec<Vec<SgEntry>>, ), ) -> Result<(), ExtControlError>168 fn perform_ext_ctrls_ioctl<M: VirtioMediaGuestMemoryMapper>(
169     ioctl: ExtCtrlIoctl,
170     device: &V4l2Device,
171     mem: &M,
172     which: CtrlWhich,
173     ctrls: (
174         &mut v4l2_ext_controls,
175         &mut Vec<v4l2_ext_control>,
176         Vec<Vec<SgEntry>>,
177     ),
178 ) -> Result<(), ExtControlError> {
179     let (ctrls, ctrl_array, mem_regions) = ctrls;
180     // TODO only backup the addresses of controls which size of > 0 for efficiency? Also keep track
181     // of the control index so we don't make a mistake if the host changes the control size.
182     let ctrl_array_backup = ctrl_array.clone();
183 
184     // Read the payloads for all the controls with one.
185     let mut payloads = ctrl_array
186         .iter()
187         .filter(|ctrl| ctrl.size > 0)
188         .zip(mem_regions)
189         .map(|(_, sgs)| mem.new_mapping(sgs))
190         // TODO remove unwrap
191         .collect::<anyhow::Result<Vec<_>>>()
192         .unwrap();
193 
194     // Patch the pointers to the payloads.
195     for (ctrl, payload) in ctrl_array
196         .iter_mut()
197         .filter(|ctrl| ctrl.size > 0)
198         .zip(payloads.iter_mut())
199     {
200         ctrl.__bindgen_anon_1.ptr = payload.as_mut_ptr() as *mut libc::c_void;
201     }
202 
203     let res = match ioctl {
204         ExtCtrlIoctl::Get => v4l2r::ioctl::g_ext_ctrls(device, which, ctrl_array.as_mut_slice()),
205         ExtCtrlIoctl::Set => v4l2r::ioctl::s_ext_ctrls(device, which, ctrl_array.as_mut_slice()),
206         ExtCtrlIoctl::Try => v4l2r::ioctl::try_ext_ctrls(device, which, ctrl_array.as_mut_slice()),
207     };
208 
209     // Restore guest addresses in the controls array.
210     for (ctrl, ctrl_backup) in ctrl_array
211         .iter_mut()
212         .zip(ctrl_array_backup.iter())
213         .filter(|(_, ctrl)| ctrl.size > 0)
214     {
215         ctrl.__bindgen_anon_1.ptr = unsafe { ctrl_backup.__bindgen_anon_1.ptr };
216     }
217 
218     if let Err(e) = &res {
219         ctrls.error_idx = e.error_idx;
220     }
221 
222     res
223 }
224 
225 /// Information about a given USERPTR memory plane.
226 struct V4l2UserPlaneInfo<R> {
227     /// Queue the buffer belongs to.
228     queue: QueueType,
229     /// Buffer index.
230     index: u8,
231 
232     guest_addr: GuestAddrType,
233     _guest_resource: R,
234 }
235 
236 pub struct V4l2Session<M: VirtioMediaGuestMemoryMapper> {
237     id: u32,
238     device: Arc<V4l2Device>,
239     /// Proxy epoll for polling `device`. We need to use a proxy here because V4L2 events are
240     /// signaled using `EPOLLPRI`, and we sometimes need to stop listening to the `CAPTURE` queue.
241     /// `poller`'s FD is what is actually added to the client's session poller.
242     poller: Poller,
243 
244     /// Type of the capture queue, if one has been set up.
245     capture_queue_type: Option<QueueType>,
246     /// Type of the output queue, if one has been set up.
247     output_queue_type: Option<QueueType>,
248 
249     capture_streaming: bool,
250     capture_num_queued: usize,
251 
252     output_streaming: bool,
253     output_num_queued: usize,
254 
255     /// Map of host USERPTR addresses to guest USERPTR addresses. Only used for queues which memory
256     /// type is USERPTR.
257     ///
258     /// TODO this is not properly cleared. We should probably record the session ID and queue in
259     /// order to remove the records upon REQBUFS or session deletion?
260     userptr_buffers: BTreeMap<GuestAddrType, V4l2UserPlaneInfo<M::GuestMemoryMapping>>,
261 }
262 
263 impl<M: VirtioMediaGuestMemoryMapper> VirtioMediaDeviceSession for V4l2Session<M> {
poll_fd(&self) -> Option<BorrowedFd>264     fn poll_fd(&self) -> Option<BorrowedFd> {
265         Some(self.poller.as_fd())
266     }
267 }
268 
269 impl<M> V4l2Session<M>
270 where
271     M: VirtioMediaGuestMemoryMapper,
272 {
new(id: u32, device: Arc<V4l2Device>) -> Self273     fn new(id: u32, device: Arc<V4l2Device>) -> Self {
274         // Only listen to V4L2 events for now.
275         let mut poller = Poller::new(Arc::clone(&device)).unwrap();
276         poller.enable_event(DeviceEvent::V4L2Event).unwrap();
277 
278         Self {
279             id,
280             device,
281             poller,
282             capture_queue_type: None,
283             output_queue_type: None,
284             capture_streaming: false,
285             capture_num_queued: 0,
286             output_streaming: false,
287             output_num_queued: 0,
288             userptr_buffers: Default::default(),
289         }
290     }
291 
292     /// Returns whether this session should be polling for CAPTURE buffers in its current state.
should_poll_capture(&self) -> bool293     fn should_poll_capture(&self) -> bool {
294         self.capture_streaming && self.capture_num_queued > 0
295     }
296 
register_userptr_addresses( &mut self, host_buffer: &V4l2Buffer, guest_buffer: &V4l2Buffer, guest_resources: Vec<M::GuestMemoryMapping>, )297     fn register_userptr_addresses(
298         &mut self,
299         host_buffer: &V4l2Buffer,
300         guest_buffer: &V4l2Buffer,
301         guest_resources: Vec<M::GuestMemoryMapping>,
302     ) {
303         if let V4l2PlanesWithBacking::UserPtr(host_planes) = host_buffer.planes_with_backing_iter()
304         {
305             if let V4l2PlanesWithBacking::UserPtr(guest_planes) =
306                 guest_buffer.planes_with_backing_iter()
307             {
308                 for ((host_userptr, guest_plane), guest_resource) in host_planes
309                     .map(|p| p.userptr())
310                     .zip(guest_planes)
311                     .filter(|(h, _)| *h != 0)
312                     .zip(guest_resources.into_iter())
313                 {
314                     let plane_info = {
315                         V4l2UserPlaneInfo {
316                             queue: guest_buffer.queue(),
317                             index: guest_buffer.index() as u8,
318                             guest_addr: guest_plane.userptr(),
319                             _guest_resource: guest_resource,
320                         }
321                     };
322                     self.userptr_buffers.insert(host_userptr, plane_info);
323                 }
324             }
325         }
326     }
327 }
328 
329 /// Information about a given MMAP memory plane.
330 ///
331 /// We keep these around indexed by the memory offset in order to service MMAP commands. Only used
332 /// if the memory type of the queue is MMAP.
333 struct V4l2MmapPlaneInfo {
334     /// ID of the session the buffer belongs to.
335     session_id: u32,
336     /// Queue the buffer belongs to.
337     queue: QueueType,
338     /// Buffer index.
339     index: u8,
340     /// Plane index.
341     plane: u8,
342     /// Guest address at which the buffer has been mapped.
343     map_address: u64,
344     /// Whether the buffer is still active from the device's point of view.
345     active: bool,
346 }
347 
348 /// A host V4L2 device that can be proxied into a virtio-media guest.
349 pub struct V4l2ProxyDevice<
350     Q: VirtioMediaEventQueue,
351     M: VirtioMediaGuestMemoryMapper,
352     HM: VirtioMediaHostMemoryMapper,
353 > {
354     /// `/dev/videoX` host device path.
355     device_path: PathBuf,
356 
357     mem: M,
358     evt_queue: Q,
359 
360     /// Map of memory offsets to detailed buffer information. Only used for queues which memory
361     /// type is MMAP.
362     mmap_buffers: BTreeMap<u32, V4l2MmapPlaneInfo>,
363 
364     mmap_manager: MmapMappingManager<HM>,
365 }
366 
367 #[derive(Debug)]
368 pub struct DequeueEventError(pub i32);
369 #[derive(Debug)]
370 pub struct DequeueBufferError(pub i32);
371 
372 impl<Q, M, HM> V4l2ProxyDevice<Q, M, HM>
373 where
374     Q: VirtioMediaEventQueue,
375     M: VirtioMediaGuestMemoryMapper,
376     HM: VirtioMediaHostMemoryMapper,
377 {
new(device_path: PathBuf, evt_queue: Q, mem: M, mapper: HM) -> Self378     pub fn new(device_path: PathBuf, evt_queue: Q, mem: M, mapper: HM) -> Self {
379         Self {
380             mem,
381             evt_queue,
382             device_path,
383             mmap_buffers: Default::default(),
384             mmap_manager: MmapMappingManager::from(mapper),
385         }
386     }
387 
delete_session(&mut self, session: &V4l2Session<M>)388     fn delete_session(&mut self, session: &V4l2Session<M>) {
389         // Mark all buffers from this session as being inactive.
390         for (&offset, buffer) in self.mmap_buffers.iter_mut() {
391             if buffer.session_id == session.id {
392                 self.mmap_manager.unregister_buffer(offset);
393                 buffer.active = false;
394             }
395         }
396         // Garbage-collect buffers that can be deleted.
397         self.mmap_buffers.retain(|_, b| b.active);
398     }
399 
400     /// Clear all the previous buffer information for this queue, and insert new information if the
401     /// memory type is MMAP.
update_mmap_offsets( &mut self, session: &mut V4l2Session<M>, queue: QueueType, range: std::ops::Range<u32>, )402     fn update_mmap_offsets(
403         &mut self,
404         session: &mut V4l2Session<M>,
405         queue: QueueType,
406         range: std::ops::Range<u32>,
407     ) {
408         // Remove buffers that have been deallocated.
409         self.mmap_buffers
410             .iter_mut()
411             .filter(|(_, b)| b.session_id == session.id && b.queue == queue)
412             .filter(|(_, b)| range.is_empty() || b.index as u32 >= range.start)
413             .for_each(|(&offset, b)| {
414                 self.mmap_manager.unregister_buffer(offset);
415                 b.active = false;
416             });
417         // Garbage-collect buffers that can be deleted.
418         self.mmap_buffers.retain(|_, b| b.active);
419 
420         for i in range {
421             let buffer =
422                 match v4l2r::ioctl::querybuf::<V4l2Buffer>(&session.device, queue, i as usize) {
423                     Ok(buffer) => buffer,
424                     Err(e) => {
425                         warn!("failed to query newly allocated buffer: {:#}", e);
426                         continue;
427                     }
428                 };
429 
430             if let V4l2PlanesWithBacking::Mmap(planes) = buffer.planes_with_backing_iter() {
431                 for (j, plane) in planes.enumerate() {
432                     let offset = plane.mem_offset();
433 
434                     self.mmap_manager
435                         .register_buffer(Some(offset), *plane.length)
436                         .unwrap();
437 
438                     self.mmap_buffers.insert(
439                         offset,
440                         V4l2MmapPlaneInfo {
441                             session_id: session.id,
442                             queue,
443                             index: buffer.index() as u8,
444                             plane: j as u8,
445                             map_address: 0,
446                             active: true,
447                         },
448                     );
449                 }
450             };
451         }
452 
453         // If we allocated on the capture or output queue successfully, remember its type.
454         // TODO this should be somewhere else?
455         match queue {
456             QueueType::VideoCapture | QueueType::VideoCaptureMplane => {
457                 session.capture_queue_type = Some(queue);
458             }
459             QueueType::VideoOutput | QueueType::VideoOutputMplane => {
460                 session.output_queue_type = Some(queue);
461             }
462             _ => (),
463         }
464     }
465 
466     /// Dequeue all pending events for `session` and send them to the guest.
467     ///
468     /// In case of error, the session should be considered invalid and destroyed.
dequeue_events(&mut self, session: &mut V4l2Session<M>) -> Result<(), DequeueEventError>469     fn dequeue_events(&mut self, session: &mut V4l2Session<M>) -> Result<(), DequeueEventError> {
470         loop {
471             match v4l2r::ioctl::dqevent::<v4l2_event>(&session.device) {
472                 Ok(event) => self
473                     .evt_queue
474                     .send_event(V4l2Event::Event(SessionEvent::new(session.id, event))),
475                 Err(DqEventError::NotReady) => return Ok(()),
476                 Err(e) => {
477                     let err = e.into_errno();
478                     self.evt_queue.send_error(session.id, err);
479                     return Err(DequeueEventError(err));
480                 }
481             }
482         }
483     }
484 
485     /// Attempt to dequeue all processed OUTPUT buffers and send the corresponding events to
486     /// `evt_queue`.
487     ///
488     /// In case of error, the session should be considered invalid and destroyed.
dequeue_output_buffers( &mut self, session: &mut V4l2Session<M>, ) -> Result<(), DequeueBufferError>489     fn dequeue_output_buffers(
490         &mut self,
491         session: &mut V4l2Session<M>,
492     ) -> Result<(), DequeueBufferError> {
493         let output_queue_type = match session.output_queue_type {
494             Some(queue_type) => queue_type,
495             None => return Ok(()),
496         };
497 
498         if !session.output_streaming || session.output_num_queued == 0 {
499             return Ok(());
500         }
501 
502         loop {
503             match v4l2r::ioctl::dqbuf::<V4l2Buffer>(&session.device, output_queue_type) {
504                 Ok(buffer) => {
505                     // Drop buffer information. This also syncs the buffer content if it has been shadowed.
506                     session.userptr_buffers.retain(|_, v| {
507                         Some(v.queue) != session.output_queue_type
508                             || v.index != buffer.index() as u8
509                     });
510                     self.evt_queue
511                         .send_event(V4l2Event::DequeueBuffer(DequeueBufferEvent::new(
512                             session.id, buffer,
513                         )))
514                 }
515                 Err(DqBufError::IoctlError(DqBufIoctlError::Eos))
516                 | Err(DqBufError::IoctlError(DqBufIoctlError::NotReady)) => return Ok(()),
517                 Err(e) => {
518                     let err = e.into_errno();
519                     self.evt_queue.send_error(session.id, err);
520                     return Err(DequeueBufferError(err));
521                 }
522             };
523         }
524     }
525 
526     /// Attempt to dequeue a single CAPTURE buffer and send the corresponding event to `evt_queue`.
527     ///
528     /// In case of error, the session should be considered invalid and destroyed.
dequeue_capture_buffer( &mut self, session: &mut V4l2Session<M>, ) -> Result<(), DequeueBufferError>529     fn dequeue_capture_buffer(
530         &mut self,
531         session: &mut V4l2Session<M>,
532     ) -> Result<(), DequeueBufferError> {
533         let capture_queue_type = match session.capture_queue_type {
534             Some(queue_type) => queue_type,
535             None => return Ok(()),
536         };
537 
538         let v4l2_buffer =
539             match v4l2r::ioctl::dqbuf::<V4l2Buffer>(&session.device, capture_queue_type) {
540                 Ok(buffer) => buffer,
541                 Err(DqBufError::IoctlError(DqBufIoctlError::Eos)) => return Ok(()),
542                 Err(DqBufError::IoctlError(DqBufIoctlError::NotReady)) => return Ok(()),
543                 Err(e) => {
544                     let err = e.into_errno();
545                     self.evt_queue.send_error(session.id, err);
546                     return Err(DequeueBufferError(err));
547                 }
548             };
549 
550         // Drop buffer information. This also syncs the buffer content if it has been shadowed.
551         session.userptr_buffers.retain(|_, v| {
552             Some(v.queue) != session.capture_queue_type || v.index != v4l2_buffer.index() as u8
553         });
554 
555         let capture_polling_active = session.should_poll_capture();
556         session.capture_num_queued -= 1;
557         if (capture_polling_active && session.capture_num_queued == 0) ||
558             // This may or may not be needed...
559             v4l2_buffer.flags().contains(BufferFlags::LAST)
560         {
561             if let Err(e) = session.poller.disable_event(DeviceEvent::CaptureReady) {
562                 error!("cannot disable CAPTURE polling after last buffer: {}", e);
563             }
564         }
565 
566         self.evt_queue
567             .send_event(V4l2Event::DequeueBuffer(DequeueBufferEvent::new(
568                 session.id,
569                 v4l2_buffer,
570             )));
571 
572         Ok(())
573     }
574 }
575 
576 impl<Q, M, HM> VirtioMediaIoctlHandler for V4l2ProxyDevice<Q, M, HM>
577 where
578     Q: VirtioMediaEventQueue,
579     M: VirtioMediaGuestMemoryMapper,
580     HM: VirtioMediaHostMemoryMapper,
581 {
582     type Session = V4l2Session<M>;
583 
enum_fmt( &mut self, session: &Self::Session, queue: QueueType, index: u32, ) -> IoctlResult<v4l2_fmtdesc>584     fn enum_fmt(
585         &mut self,
586         session: &Self::Session,
587         queue: QueueType,
588         index: u32,
589     ) -> IoctlResult<v4l2_fmtdesc> {
590         v4l2r::ioctl::enum_fmt(&session.device, queue, index).map_err(IntoErrno::into_errno)
591     }
592 
g_fmt(&mut self, session: &Self::Session, queue: QueueType) -> IoctlResult<v4l2_format>593     fn g_fmt(&mut self, session: &Self::Session, queue: QueueType) -> IoctlResult<v4l2_format> {
594         v4l2r::ioctl::g_fmt(&session.device, queue).map_err(IntoErrno::into_errno)
595     }
596 
s_fmt( &mut self, session: &mut Self::Session, _queue: QueueType, format: v4l2_format, ) -> IoctlResult<v4l2_format>597     fn s_fmt(
598         &mut self,
599         session: &mut Self::Session,
600         _queue: QueueType,
601         format: v4l2_format,
602     ) -> IoctlResult<v4l2_format> {
603         v4l2r::ioctl::s_fmt(&mut session.device, format).map_err(IntoErrno::into_errno)
604     }
605 
reqbufs( &mut self, session: &mut Self::Session, queue: QueueType, memory: MemoryType, count: u32, ) -> IoctlResult<v4l2_requestbuffers>606     fn reqbufs(
607         &mut self,
608         session: &mut Self::Session,
609         queue: QueueType,
610         memory: MemoryType,
611         count: u32,
612     ) -> IoctlResult<v4l2_requestbuffers> {
613         let mut reqbufs: v4l2_requestbuffers =
614             v4l2r::ioctl::reqbufs(&session.device, queue, memory, count)
615                 .map_err(IntoErrno::into_errno)?;
616 
617         // We do not support requests at the moment, so do not advertize them.
618         reqbufs.capabilities &= !v4l2r::bindings::V4L2_BUF_CAP_SUPPORTS_REQUESTS;
619 
620         self.update_mmap_offsets(session, queue, 0..reqbufs.count);
621 
622         match queue {
623             QueueType::VideoCapture | QueueType::VideoCaptureMplane => {
624                 // REQBUFS(0) is an implicit STREAMOFF.
625                 if reqbufs.count == 0 {
626                     let was_polling_capture = session.should_poll_capture();
627                     session.capture_streaming = false;
628                     session.capture_num_queued = 0;
629                     if was_polling_capture {
630                         if let Err(e) = session.poller.disable_event(DeviceEvent::CaptureReady) {
631                             error!(
632                                 "cannot disable CAPTURE polling after REQBUFS(0) ioctl: {}",
633                                 e
634                             );
635                         }
636                     }
637                 }
638             }
639             QueueType::VideoOutput | QueueType::VideoOutputMplane => {
640                 // REQBUFS(0) is an implicit STREAMOFF.
641                 if reqbufs.count == 0 {
642                     session.output_streaming = false;
643                     session.output_num_queued = 0;
644                 }
645             }
646             _ => (),
647         }
648 
649         Ok(reqbufs)
650     }
651 
querybuf( &mut self, session: &Self::Session, queue: QueueType, index: u32, ) -> IoctlResult<V4l2Buffer>652     fn querybuf(
653         &mut self,
654         session: &Self::Session,
655         queue: QueueType,
656         index: u32,
657     ) -> IoctlResult<V4l2Buffer> {
658         v4l2r::ioctl::querybuf(&session.device, queue, index as usize)
659             .map_err(IntoErrno::into_errno)
660             .and_then(|host_buffer| {
661                 host_v4l2_buffer_to_guest(&host_buffer, &session.userptr_buffers).map_err(|e| {
662                     error!("{:#}", e.context("while performing QUERYBUF ioctl"));
663                     libc::EINVAL
664                 })
665             })
666     }
667 
streamon(&mut self, session: &mut Self::Session, queue: QueueType) -> IoctlResult<()>668     fn streamon(&mut self, session: &mut Self::Session, queue: QueueType) -> IoctlResult<()> {
669         v4l2r::ioctl::streamon(&session.device, queue).map_err(IntoErrno::into_errno)?;
670 
671         match queue {
672             QueueType::VideoCapture | QueueType::VideoCaptureMplane
673                 if !session.capture_streaming =>
674             {
675                 session.capture_streaming = true;
676                 if session.should_poll_capture() {
677                     if let Err(e) = session.poller.enable_event(DeviceEvent::CaptureReady) {
678                         error!("cannot enable CAPTURE polling after STREAMON ioctl: {}", e);
679                     }
680                 }
681             }
682             QueueType::VideoOutput | QueueType::VideoOutputMplane if !session.output_streaming => {
683                 session.output_streaming = true;
684             }
685             _ => (),
686         }
687 
688         Ok(())
689     }
690 
streamoff(&mut self, session: &mut Self::Session, queue: QueueType) -> IoctlResult<()>691     fn streamoff(&mut self, session: &mut Self::Session, queue: QueueType) -> IoctlResult<()> {
692         v4l2r::ioctl::streamoff(&session.device, queue).map_err(IntoErrno::into_errno)?;
693 
694         match queue {
695             QueueType::VideoCapture | QueueType::VideoCaptureMplane => {
696                 let was_polling_capture = session.should_poll_capture();
697                 session.capture_streaming = false;
698                 session.capture_num_queued = 0;
699                 if was_polling_capture {
700                     if let Err(e) = session.poller.disable_event(DeviceEvent::CaptureReady) {
701                         error!(
702                             "cannot disable CAPTURE polling after STREAMOFF ioctl: {}",
703                             e
704                         );
705                     }
706                 }
707             }
708             QueueType::VideoOutput | QueueType::VideoOutputMplane => {
709                 session.output_streaming = false;
710                 session.output_num_queued = 0;
711             }
712             _ => (),
713         }
714 
715         Ok(())
716     }
717 
qbuf( &mut self, session: &mut Self::Session, guest_buffer: V4l2Buffer, guest_regions: Vec<Vec<SgEntry>>, ) -> IoctlResult<V4l2Buffer>718     fn qbuf(
719         &mut self,
720         session: &mut Self::Session,
721         guest_buffer: V4l2Buffer,
722         guest_regions: Vec<Vec<SgEntry>>,
723     ) -> IoctlResult<V4l2Buffer> {
724         // Proactively dequeue output buffers we are done with. Errors can be ignored in
725         // this context.
726         let _ = self.dequeue_output_buffers(session);
727 
728         let (host_buffer, guest_resources) =
729             guest_v4l2_buffer_to_host(&guest_buffer, guest_regions, &self.mem)
730                 .map_err(|_| libc::EINVAL)?;
731         session.register_userptr_addresses(&host_buffer, &guest_buffer, guest_resources);
732         let queue = host_buffer.queue();
733         let out_buffer = v4l2r::ioctl::qbuf(&session.device, host_buffer)
734             .map_err(|e| e.into_errno())
735             .and_then(|host_out_buffer| {
736                 // TODO if we had a PREPARE_BUF before, do we need to patch the addresses
737                 // from the buffer given at that time?
738                 host_v4l2_buffer_to_guest(&host_out_buffer, &session.userptr_buffers).map_err(|e| {
739                     error!("{:#}", e.context("while processing QBUF"));
740                     libc::EINVAL
741                 })
742             })?;
743 
744         match queue {
745             QueueType::VideoCapture | QueueType::VideoCaptureMplane => {
746                 let was_polling_capture = session.should_poll_capture();
747                 session.capture_num_queued += 1;
748                 if !was_polling_capture && session.should_poll_capture() {
749                     if let Err(e) = session.poller.enable_event(DeviceEvent::CaptureReady) {
750                         error!("cannot enable CAPTURE polling after QBUF ioctl: {}", e);
751                     }
752                 }
753             }
754             QueueType::VideoOutput | QueueType::VideoOutputMplane => {
755                 session.output_num_queued += 1;
756             }
757             _ => (),
758         }
759 
760         Ok(out_buffer)
761     }
762 
g_parm( &mut self, session: &Self::Session, queue: QueueType, ) -> IoctlResult<v4l2_streamparm>763     fn g_parm(
764         &mut self,
765         session: &Self::Session,
766         queue: QueueType,
767     ) -> IoctlResult<v4l2_streamparm> {
768         v4l2r::ioctl::g_parm(&session.device, queue).map_err(|e| e.into_errno())
769     }
770 
s_parm( &mut self, session: &mut Self::Session, parm: v4l2_streamparm, ) -> IoctlResult<v4l2_streamparm>771     fn s_parm(
772         &mut self,
773         session: &mut Self::Session,
774         parm: v4l2_streamparm,
775     ) -> IoctlResult<v4l2_streamparm> {
776         v4l2r::ioctl::s_parm(&session.device, parm).map_err(|e| e.into_errno())
777     }
778 
g_std(&mut self, session: &Self::Session) -> IoctlResult<v4l2_std_id>779     fn g_std(&mut self, session: &Self::Session) -> IoctlResult<v4l2_std_id> {
780         v4l2r::ioctl::g_std(&session.device).map_err(|e| e.into_errno())
781     }
782 
s_std(&mut self, session: &mut Self::Session, std: v4l2_std_id) -> IoctlResult<()>783     fn s_std(&mut self, session: &mut Self::Session, std: v4l2_std_id) -> IoctlResult<()> {
784         v4l2r::ioctl::s_std(&session.device, std).map_err(|e| e.into_errno())
785     }
786 
enumstd(&mut self, session: &Self::Session, index: u32) -> IoctlResult<v4l2_standard>787     fn enumstd(&mut self, session: &Self::Session, index: u32) -> IoctlResult<v4l2_standard> {
788         v4l2r::ioctl::enumstd(&session.device, index).map_err(|e| e.into_errno())
789     }
790 
enuminput(&mut self, session: &Self::Session, index: u32) -> IoctlResult<v4l2_input>791     fn enuminput(&mut self, session: &Self::Session, index: u32) -> IoctlResult<v4l2_input> {
792         v4l2r::ioctl::enuminput(&session.device, index as usize).map_err(|e| e.into_errno())
793     }
794 
g_ctrl(&mut self, session: &Self::Session, id: u32) -> IoctlResult<v4l2_control>795     fn g_ctrl(&mut self, session: &Self::Session, id: u32) -> IoctlResult<v4l2_control> {
796         v4l2r::ioctl::g_ctrl(&session.device, id)
797             .map(|value| v4l2_control { id, value })
798             .map_err(|e| e.into_errno())
799     }
800 
s_ctrl( &mut self, session: &mut Self::Session, id: u32, value: i32, ) -> IoctlResult<v4l2_control>801     fn s_ctrl(
802         &mut self,
803         session: &mut Self::Session,
804         id: u32,
805         value: i32,
806     ) -> IoctlResult<v4l2_control> {
807         v4l2r::ioctl::s_ctrl(&session.device, id, value)
808             .map(|value| v4l2_control { id, value })
809             .map_err(|e| e.into_errno())
810     }
811 
g_tuner(&mut self, session: &Self::Session, index: u32) -> IoctlResult<v4l2_tuner>812     fn g_tuner(&mut self, session: &Self::Session, index: u32) -> IoctlResult<v4l2_tuner> {
813         v4l2r::ioctl::g_tuner(&session.device, index).map_err(|e| e.into_errno())
814     }
815 
s_tuner( &mut self, session: &mut Self::Session, index: u32, mode: TunerMode, ) -> IoctlResult<()>816     fn s_tuner(
817         &mut self,
818         session: &mut Self::Session,
819         index: u32,
820         mode: TunerMode,
821     ) -> IoctlResult<()> {
822         v4l2r::ioctl::s_tuner(&session.device, index, mode).map_err(|e| e.into_errno())
823     }
824 
g_audio(&mut self, session: &Self::Session) -> IoctlResult<v4l2_audio>825     fn g_audio(&mut self, session: &Self::Session) -> IoctlResult<v4l2_audio> {
826         v4l2r::ioctl::g_audio(&session.device).map_err(|e| e.into_errno())
827     }
828 
s_audio( &mut self, session: &mut Self::Session, index: u32, mode: Option<AudioMode>, ) -> IoctlResult<()>829     fn s_audio(
830         &mut self,
831         session: &mut Self::Session,
832         index: u32,
833         mode: Option<AudioMode>,
834     ) -> IoctlResult<()> {
835         v4l2r::ioctl::s_audio(&session.device, index, mode).map_err(|e| e.into_errno())
836     }
837 
queryctrl( &mut self, session: &Self::Session, id: v4l2r::ioctl::CtrlId, flags: v4l2r::ioctl::QueryCtrlFlags, ) -> IoctlResult<v4l2_queryctrl>838     fn queryctrl(
839         &mut self,
840         session: &Self::Session,
841         id: v4l2r::ioctl::CtrlId,
842         flags: v4l2r::ioctl::QueryCtrlFlags,
843     ) -> IoctlResult<v4l2_queryctrl> {
844         v4l2r::ioctl::queryctrl(&session.device, id, flags).map_err(|e| e.into_errno())
845     }
846 
querymenu( &mut self, session: &Self::Session, id: u32, index: u32, ) -> IoctlResult<v4l2_querymenu>847     fn querymenu(
848         &mut self,
849         session: &Self::Session,
850         id: u32,
851         index: u32,
852     ) -> IoctlResult<v4l2_querymenu> {
853         v4l2r::ioctl::querymenu(&session.device, id, index).map_err(|e| e.into_errno())
854     }
855 
g_input(&mut self, session: &Self::Session) -> IoctlResult<i32>856     fn g_input(&mut self, session: &Self::Session) -> IoctlResult<i32> {
857         v4l2r::ioctl::g_input(&session.device)
858             .map(|i| i as i32)
859             .map_err(|e| e.into_errno())
860     }
861 
s_input(&mut self, session: &mut Self::Session, input: i32) -> IoctlResult<i32>862     fn s_input(&mut self, session: &mut Self::Session, input: i32) -> IoctlResult<i32> {
863         v4l2r::ioctl::s_input(&session.device, input as usize)
864             .map(|i| i as i32)
865             .map_err(|e| e.into_errno())
866     }
867 
g_output(&mut self, session: &Self::Session) -> IoctlResult<i32>868     fn g_output(&mut self, session: &Self::Session) -> IoctlResult<i32> {
869         v4l2r::ioctl::g_output(&session.device)
870             .map(|o| o as i32)
871             .map_err(|e| e.into_errno())
872     }
873 
s_output(&mut self, session: &mut Self::Session, output: i32) -> IoctlResult<i32>874     fn s_output(&mut self, session: &mut Self::Session, output: i32) -> IoctlResult<i32> {
875         v4l2r::ioctl::s_output(&session.device, output as usize)
876             .map(|()| output)
877             .map_err(|e| e.into_errno())
878     }
879 
enumoutput(&mut self, session: &Self::Session, index: u32) -> IoctlResult<v4l2_output>880     fn enumoutput(&mut self, session: &Self::Session, index: u32) -> IoctlResult<v4l2_output> {
881         v4l2r::ioctl::enumoutput(&session.device, index as usize).map_err(|e| e.into_errno())
882     }
883 
g_audout(&mut self, session: &Self::Session) -> IoctlResult<v4l2_audioout>884     fn g_audout(&mut self, session: &Self::Session) -> IoctlResult<v4l2_audioout> {
885         v4l2r::ioctl::g_audout(&session.device).map_err(|e| e.into_errno())
886     }
887 
s_audout(&mut self, session: &mut Self::Session, index: u32) -> IoctlResult<()>888     fn s_audout(&mut self, session: &mut Self::Session, index: u32) -> IoctlResult<()> {
889         v4l2r::ioctl::s_audout(&session.device, index).map_err(|e| e.into_errno())
890     }
891 
g_modulator(&mut self, session: &Self::Session, index: u32) -> IoctlResult<v4l2_modulator>892     fn g_modulator(&mut self, session: &Self::Session, index: u32) -> IoctlResult<v4l2_modulator> {
893         v4l2r::ioctl::g_modulator(&session.device, index).map_err(|e| e.into_errno())
894     }
895 
s_modulator( &mut self, session: &mut Self::Session, index: u32, flags: TunerTransmissionFlags, ) -> IoctlResult<()>896     fn s_modulator(
897         &mut self,
898         session: &mut Self::Session,
899         index: u32,
900         flags: TunerTransmissionFlags,
901     ) -> IoctlResult<()> {
902         v4l2r::ioctl::s_modulator(&session.device, index, flags).map_err(|e| e.into_errno())
903     }
904 
g_frequency(&mut self, session: &Self::Session, tuner: u32) -> IoctlResult<v4l2_frequency>905     fn g_frequency(&mut self, session: &Self::Session, tuner: u32) -> IoctlResult<v4l2_frequency> {
906         v4l2r::ioctl::g_frequency(&session.device, tuner).map_err(|e| e.into_errno())
907     }
908 
s_frequency( &mut self, session: &mut Self::Session, tuner: u32, type_: TunerType, frequency: u32, ) -> IoctlResult<()>909     fn s_frequency(
910         &mut self,
911         session: &mut Self::Session,
912         tuner: u32,
913         type_: TunerType,
914         frequency: u32,
915     ) -> IoctlResult<()> {
916         v4l2r::ioctl::s_frequency(&session.device, tuner, type_, frequency)
917             .map_err(|e| e.into_errno())
918     }
919 
querystd(&mut self, session: &Self::Session) -> IoctlResult<v4l2_std_id>920     fn querystd(&mut self, session: &Self::Session) -> IoctlResult<v4l2_std_id> {
921         v4l2r::ioctl::querystd::<v4l2_std_id>(&session.device).map_err(|e| e.into_errno())
922     }
923 
try_fmt( &mut self, session: &Self::Session, _queue: QueueType, format: v4l2_format, ) -> IoctlResult<v4l2_format>924     fn try_fmt(
925         &mut self,
926         session: &Self::Session,
927         _queue: QueueType,
928         format: v4l2_format,
929     ) -> IoctlResult<v4l2_format> {
930         v4l2r::ioctl::try_fmt::<_, v4l2_format>(&session.device, format).map_err(|e| e.into_errno())
931     }
932 
enumaudio(&mut self, session: &Self::Session, index: u32) -> IoctlResult<v4l2_audio>933     fn enumaudio(&mut self, session: &Self::Session, index: u32) -> IoctlResult<v4l2_audio> {
934         v4l2r::ioctl::enumaudio::<v4l2_audio>(&session.device, index).map_err(|e| e.into_errno())
935     }
936 
enumaudout(&mut self, session: &Self::Session, index: u32) -> IoctlResult<v4l2_audioout>937     fn enumaudout(&mut self, session: &Self::Session, index: u32) -> IoctlResult<v4l2_audioout> {
938         v4l2r::ioctl::enumaudout::<v4l2_audioout>(&session.device, index)
939             .map_err(|e| e.into_errno())
940     }
941 
g_ext_ctrls( &mut self, session: &Self::Session, which: CtrlWhich, ctrls: &mut v4l2_ext_controls, ctrl_array: &mut Vec<v4l2_ext_control>, user_regions: Vec<Vec<SgEntry>>, ) -> IoctlResult<()>942     fn g_ext_ctrls(
943         &mut self,
944         session: &Self::Session,
945         which: CtrlWhich,
946         ctrls: &mut v4l2_ext_controls,
947         ctrl_array: &mut Vec<v4l2_ext_control>,
948         user_regions: Vec<Vec<SgEntry>>,
949     ) -> IoctlResult<()> {
950         perform_ext_ctrls_ioctl(
951             ExtCtrlIoctl::Get,
952             &session.device,
953             &self.mem,
954             which,
955             (ctrls, ctrl_array, user_regions),
956         )
957         .map_err(|e| e.into_errno())
958     }
959 
s_ext_ctrls( &mut self, session: &mut Self::Session, which: CtrlWhich, ctrls: &mut v4l2_ext_controls, ctrl_array: &mut Vec<v4l2_ext_control>, user_regions: Vec<Vec<SgEntry>>, ) -> IoctlResult<()>960     fn s_ext_ctrls(
961         &mut self,
962         session: &mut Self::Session,
963         which: CtrlWhich,
964         ctrls: &mut v4l2_ext_controls,
965         ctrl_array: &mut Vec<v4l2_ext_control>,
966         user_regions: Vec<Vec<SgEntry>>,
967     ) -> IoctlResult<()> {
968         perform_ext_ctrls_ioctl(
969             ExtCtrlIoctl::Set,
970             &session.device,
971             &self.mem,
972             which,
973             (ctrls, ctrl_array, user_regions),
974         )
975         .map_err(|e| e.into_errno())
976     }
977 
try_ext_ctrls( &mut self, session: &Self::Session, which: CtrlWhich, ctrls: &mut v4l2_ext_controls, ctrl_array: &mut Vec<v4l2_ext_control>, user_regions: Vec<Vec<SgEntry>>, ) -> IoctlResult<()>978     fn try_ext_ctrls(
979         &mut self,
980         session: &Self::Session,
981         which: CtrlWhich,
982         ctrls: &mut v4l2_ext_controls,
983         ctrl_array: &mut Vec<v4l2_ext_control>,
984         user_regions: Vec<Vec<SgEntry>>,
985     ) -> IoctlResult<()> {
986         perform_ext_ctrls_ioctl(
987             ExtCtrlIoctl::Try,
988             &session.device,
989             &self.mem,
990             which,
991             (ctrls, ctrl_array, user_regions),
992         )
993         .map_err(|e| e.into_errno())
994     }
995 
enum_framesizes( &mut self, session: &Self::Session, index: u32, pixel_format: u32, ) -> IoctlResult<v4l2_frmsizeenum>996     fn enum_framesizes(
997         &mut self,
998         session: &Self::Session,
999         index: u32,
1000         pixel_format: u32,
1001     ) -> IoctlResult<v4l2_frmsizeenum> {
1002         v4l2r::ioctl::enum_frame_sizes(&session.device, index, pixel_format.into())
1003             .map_err(|e| e.into_errno())
1004     }
1005 
enum_frameintervals( &mut self, session: &Self::Session, index: u32, pixel_format: u32, width: u32, height: u32, ) -> IoctlResult<v4l2_frmivalenum>1006     fn enum_frameintervals(
1007         &mut self,
1008         session: &Self::Session,
1009         index: u32,
1010         pixel_format: u32,
1011         width: u32,
1012         height: u32,
1013     ) -> IoctlResult<v4l2_frmivalenum> {
1014         v4l2r::ioctl::enum_frame_intervals(
1015             &session.device,
1016             index,
1017             pixel_format.into(),
1018             width,
1019             height,
1020         )
1021         .map_err(|e| e.into_errno())
1022     }
1023 
g_enc_index(&mut self, session: &Self::Session) -> IoctlResult<v4l2_enc_idx>1024     fn g_enc_index(&mut self, session: &Self::Session) -> IoctlResult<v4l2_enc_idx> {
1025         v4l2r::ioctl::g_enc_index(&session.device).map_err(|e| e.into_errno())
1026     }
1027 
encoder_cmd( &mut self, session: &mut Self::Session, cmd: v4l2_encoder_cmd, ) -> IoctlResult<v4l2_encoder_cmd>1028     fn encoder_cmd(
1029         &mut self,
1030         session: &mut Self::Session,
1031         cmd: v4l2_encoder_cmd,
1032     ) -> IoctlResult<v4l2_encoder_cmd> {
1033         v4l2r::ioctl::encoder_cmd(&session.device, cmd).map_err(|e| e.into_errno())
1034     }
1035 
try_encoder_cmd( &mut self, session: &Self::Session, cmd: v4l2_encoder_cmd, ) -> IoctlResult<v4l2_encoder_cmd>1036     fn try_encoder_cmd(
1037         &mut self,
1038         session: &Self::Session,
1039         cmd: v4l2_encoder_cmd,
1040     ) -> IoctlResult<v4l2_encoder_cmd> {
1041         v4l2r::ioctl::try_encoder_cmd(&session.device, cmd).map_err(|e| e.into_errno())
1042     }
1043 
s_dv_timings( &mut self, session: &mut Self::Session, timings: v4l2_dv_timings, ) -> IoctlResult<v4l2_dv_timings>1044     fn s_dv_timings(
1045         &mut self,
1046         session: &mut Self::Session,
1047         timings: v4l2_dv_timings,
1048     ) -> IoctlResult<v4l2_dv_timings> {
1049         v4l2r::ioctl::s_dv_timings(&session.device, timings).map_err(|e| e.into_errno())
1050     }
1051 
g_dv_timings(&mut self, session: &Self::Session) -> IoctlResult<v4l2_dv_timings>1052     fn g_dv_timings(&mut self, session: &Self::Session) -> IoctlResult<v4l2_dv_timings> {
1053         v4l2r::ioctl::g_dv_timings(&session.device).map_err(|e| e.into_errno())
1054     }
1055 
subscribe_event( &mut self, session: &mut Self::Session, event: V4l2EventType, flags: SubscribeEventFlags, ) -> IoctlResult<()>1056     fn subscribe_event(
1057         &mut self,
1058         session: &mut Self::Session,
1059         event: V4l2EventType,
1060         flags: SubscribeEventFlags,
1061     ) -> IoctlResult<()> {
1062         v4l2r::ioctl::subscribe_event(&session.device, event, flags).map_err(|e| e.into_errno())?;
1063 
1064         // Make sure the initial event it put into the eventq before we return.
1065         if flags.contains(SubscribeEventFlags::SEND_INITIAL) {
1066             // This sends the potential events before the command response,
1067             // ensuring the guest will be able to see them alongside the response.
1068             let _ = self.dequeue_events(session).err();
1069         }
1070 
1071         Ok(())
1072     }
1073 
unsubscribe_event( &mut self, session: &mut Self::Session, event: v4l2_event_subscription, ) -> IoctlResult<()>1074     fn unsubscribe_event(
1075         &mut self,
1076         session: &mut Self::Session,
1077         event: v4l2_event_subscription,
1078     ) -> IoctlResult<()> {
1079         if event.type_ == v4l2r::bindings::V4L2_EVENT_ALL {
1080             v4l2r::ioctl::unsubscribe_all_events(&session.device)
1081         } else {
1082             let event = V4l2EventType::try_from(&event).map_err(|_| libc::EINVAL)?;
1083 
1084             v4l2r::ioctl::unsubscribe_event(&session.device, event)
1085         }
1086         .map_err(|e| e.into_errno())
1087     }
1088 
create_bufs( &mut self, session: &mut Self::Session, count: u32, queue: QueueType, memory: MemoryType, format: v4l2_format, ) -> IoctlResult<v4l2_create_buffers>1089     fn create_bufs(
1090         &mut self,
1091         session: &mut Self::Session,
1092         count: u32,
1093         queue: QueueType,
1094         memory: MemoryType,
1095         format: v4l2_format,
1096     ) -> IoctlResult<v4l2_create_buffers> {
1097         let create_bufs = v4l2r::ioctl::create_bufs::<_, v4l2_create_buffers>(
1098             &session.device,
1099             count,
1100             memory,
1101             format,
1102         )
1103         .map_err(|e| (e.into_errno()))?;
1104 
1105         let bufs_range = create_bufs.index..(create_bufs.index + create_bufs.count);
1106         self.update_mmap_offsets(session, queue, bufs_range);
1107 
1108         Ok(create_bufs)
1109     }
1110 
prepare_buf( &mut self, session: &mut Self::Session, guest_buffer: V4l2Buffer, guest_regions: Vec<Vec<SgEntry>>, ) -> IoctlResult<V4l2Buffer>1111     fn prepare_buf(
1112         &mut self,
1113         session: &mut Self::Session,
1114         guest_buffer: V4l2Buffer,
1115         guest_regions: Vec<Vec<SgEntry>>,
1116     ) -> IoctlResult<V4l2Buffer> {
1117         let (host_buffer, guest_resources) =
1118             guest_v4l2_buffer_to_host(&guest_buffer, guest_regions, &self.mem)
1119                 .map_err(|_| libc::EINVAL)?;
1120         session.register_userptr_addresses(&host_buffer, &guest_buffer, guest_resources);
1121         v4l2r::ioctl::prepare_buf(&session.device, host_buffer)
1122             .map_err(|e| e.into_errno())
1123             .and_then(|host_out_buffer| {
1124                 host_v4l2_buffer_to_guest(&host_out_buffer, &session.userptr_buffers).map_err(|e| {
1125                     error!("{:#}", e.context("while processing PREPARE_BUF"));
1126                     libc::EINVAL
1127                 })
1128             })
1129     }
1130 
g_selection( &mut self, session: &Self::Session, sel_type: SelectionType, sel_target: SelectionTarget, ) -> IoctlResult<v4l2_rect>1131     fn g_selection(
1132         &mut self,
1133         session: &Self::Session,
1134         sel_type: SelectionType,
1135         sel_target: SelectionTarget,
1136     ) -> IoctlResult<v4l2_rect> {
1137         v4l2r::ioctl::g_selection(&session.device, sel_type, sel_target).map_err(|e| e.into_errno())
1138     }
1139 
s_selection( &mut self, session: &mut Self::Session, sel_type: SelectionType, sel_target: SelectionTarget, sel_rect: v4l2_rect, sel_flags: SelectionFlags, ) -> IoctlResult<v4l2_rect>1140     fn s_selection(
1141         &mut self,
1142         session: &mut Self::Session,
1143         sel_type: SelectionType,
1144         sel_target: SelectionTarget,
1145         sel_rect: v4l2_rect,
1146         sel_flags: SelectionFlags,
1147     ) -> IoctlResult<v4l2_rect> {
1148         v4l2r::ioctl::s_selection(&session.device, sel_type, sel_target, sel_rect, sel_flags)
1149             .map_err(|e| e.into_errno())
1150     }
1151 
decoder_cmd( &mut self, session: &mut Self::Session, cmd: v4l2_decoder_cmd, ) -> IoctlResult<v4l2_decoder_cmd>1152     fn decoder_cmd(
1153         &mut self,
1154         session: &mut Self::Session,
1155         cmd: v4l2_decoder_cmd,
1156     ) -> IoctlResult<v4l2_decoder_cmd> {
1157         v4l2r::ioctl::decoder_cmd(&session.device, cmd).map_err(|e| e.into_errno())
1158     }
1159 
try_decoder_cmd( &mut self, session: &Self::Session, cmd: v4l2_decoder_cmd, ) -> IoctlResult<v4l2_decoder_cmd>1160     fn try_decoder_cmd(
1161         &mut self,
1162         session: &Self::Session,
1163         cmd: v4l2_decoder_cmd,
1164     ) -> IoctlResult<v4l2_decoder_cmd> {
1165         v4l2r::ioctl::try_decoder_cmd(&session.device, cmd).map_err(|e| e.into_errno())
1166     }
1167 
enum_dv_timings( &mut self, session: &Self::Session, index: u32, ) -> IoctlResult<v4l2_dv_timings>1168     fn enum_dv_timings(
1169         &mut self,
1170         session: &Self::Session,
1171         index: u32,
1172     ) -> IoctlResult<v4l2_dv_timings> {
1173         v4l2r::ioctl::enum_dv_timings(&session.device, index).map_err(|e| e.into_errno())
1174     }
1175 
query_dv_timings(&mut self, session: &Self::Session) -> IoctlResult<v4l2_dv_timings>1176     fn query_dv_timings(&mut self, session: &Self::Session) -> IoctlResult<v4l2_dv_timings> {
1177         v4l2r::ioctl::query_dv_timings(&session.device).map_err(|e| e.into_errno())
1178     }
1179 
dv_timings_cap(&self, session: &Self::Session) -> IoctlResult<v4l2_dv_timings_cap>1180     fn dv_timings_cap(&self, session: &Self::Session) -> IoctlResult<v4l2_dv_timings_cap> {
1181         v4l2r::ioctl::dv_timings_cap(&session.device).map_err(|e| e.into_errno())
1182     }
1183 
enum_freq_bands( &self, session: &Self::Session, tuner: u32, type_: TunerType, index: u32, ) -> IoctlResult<v4l2_frequency_band>1184     fn enum_freq_bands(
1185         &self,
1186         session: &Self::Session,
1187         tuner: u32,
1188         type_: TunerType,
1189         index: u32,
1190     ) -> IoctlResult<v4l2_frequency_band> {
1191         v4l2r::ioctl::enum_freq_bands(&session.device, tuner, type_, index)
1192             .map_err(|e| e.into_errno())
1193     }
1194 
query_ext_ctrl( &mut self, session: &Self::Session, id: CtrlId, flags: QueryCtrlFlags, ) -> IoctlResult<v4l2_query_ext_ctrl>1195     fn query_ext_ctrl(
1196         &mut self,
1197         session: &Self::Session,
1198         id: CtrlId,
1199         flags: QueryCtrlFlags,
1200     ) -> IoctlResult<v4l2_query_ext_ctrl> {
1201         v4l2r::ioctl::query_ext_ctrl::<v4l2_query_ext_ctrl>(&session.device, id, flags)
1202             .map_err(|e| e.into_errno())
1203     }
1204 }
1205 
1206 impl<Q, M, HM, Reader, Writer> VirtioMediaDevice<Reader, Writer> for V4l2ProxyDevice<Q, M, HM>
1207 where
1208     Q: VirtioMediaEventQueue,
1209     M: VirtioMediaGuestMemoryMapper,
1210     HM: VirtioMediaHostMemoryMapper,
1211     Reader: std::io::Read,
1212     Writer: std::io::Write,
1213 {
1214     type Session = V4l2Session<M>;
1215 
new_session(&mut self, session_id: u32) -> Result<Self::Session, i32>1216     fn new_session(&mut self, session_id: u32) -> Result<Self::Session, i32> {
1217         match V4l2Device::open(&self.device_path, DeviceConfig::new().non_blocking_dqbuf()) {
1218             Ok(device) => Ok(V4l2Session::new(session_id, Arc::new(device))),
1219             Err(DeviceOpenError::OpenError(e)) => Err(e as i32),
1220             Err(DeviceOpenError::QueryCapError(QueryCapError::IoctlError(e))) => Err(e as i32),
1221         }
1222     }
1223 
close_session(&mut self, session: Self::Session)1224     fn close_session(&mut self, session: Self::Session) {
1225         self.delete_session(&session)
1226     }
1227 
do_mmap( &mut self, session: &mut Self::Session, flags: u32, offset: u32, ) -> Result<(u64, u64), i32>1228     fn do_mmap(
1229         &mut self,
1230         session: &mut Self::Session,
1231         flags: u32,
1232         offset: u32,
1233     ) -> Result<(u64, u64), i32> {
1234         let rw = (flags & VIRTIO_MEDIA_MMAP_FLAG_RW) != 0;
1235 
1236         let plane_info = self
1237             .mmap_buffers
1238             .get_mut(&offset)
1239             .ok_or(libc::EINVAL)?;
1240 
1241         // Export the FD for the plane and cache it if needed.
1242         //
1243         // We must NOT cache this result to reuse in case of multiple MMAP requests. If we do, then
1244         // there is the risk that a session requests a buffer belonging to another one. The call
1245         // the `expbuf` also serves as a permission check that the requesting session indeed has
1246         // access to the buffer.
1247         let exported_fd = v4l2r::ioctl::expbuf::<OwnedFd>(
1248             &session.device,
1249             plane_info.queue,
1250             plane_info.index as usize,
1251             plane_info.plane as usize,
1252             if rw {
1253                 ExpbufFlags::RDWR
1254             } else {
1255                 ExpbufFlags::RDONLY
1256             },
1257         )
1258         .map_err(|e| e.into_errno())?;
1259 
1260         let (mapping_addr, mapping_size) = self
1261             .mmap_manager
1262             .create_mapping(offset, exported_fd.as_fd(), rw)
1263             // TODO: better error mapping?
1264             .map_err(|_| libc::EINVAL)?;
1265 
1266         plane_info.map_address = mapping_addr;
1267         Ok((mapping_addr, mapping_size))
1268     }
1269 
do_munmap(&mut self, guest_addr: u64) -> Result<(), i32>1270     fn do_munmap(&mut self, guest_addr: u64) -> Result<(), i32> {
1271         self.mmap_manager
1272             .remove_mapping(guest_addr)
1273             .map(|_| ())
1274             .map_err(|_| libc::EINVAL)
1275     }
1276 
do_ioctl( &mut self, session: &mut Self::Session, ioctl: V4l2Ioctl, reader: &mut Reader, writer: &mut Writer, ) -> IoResult<()>1277     fn do_ioctl(
1278         &mut self,
1279         session: &mut Self::Session,
1280         ioctl: V4l2Ioctl,
1281         reader: &mut Reader,
1282         writer: &mut Writer,
1283     ) -> IoResult<()> {
1284         virtio_media_dispatch_ioctl(self, session, ioctl, reader, writer)
1285     }
1286 
process_events(&mut self, session: &mut Self::Session) -> Result<(), i32>1287     fn process_events(&mut self, session: &mut Self::Session) -> Result<(), i32> {
1288         let events = session
1289             .poller
1290             .poll(Some(Duration::ZERO))
1291             .map_err(|_| libc::EIO)?;
1292 
1293         let mut has_event = false;
1294 
1295         for event in events {
1296             has_event = true;
1297 
1298             match event {
1299                 PollEvent::Device(DeviceEvent::CaptureReady) => {
1300                     self.dequeue_capture_buffer(session).map_err(|e| e.0)?;
1301                     // Try to release OUTPUT buffers while we are at it.
1302                     self.dequeue_output_buffers(session).map_err(|e| e.0)?;
1303                 }
1304                 PollEvent::Device(DeviceEvent::V4L2Event) => {
1305                     self.dequeue_events(session).map_err(|e| e.0)?
1306                 }
1307                 _ => panic!(),
1308             }
1309         }
1310 
1311         if !has_event {
1312             log::warn!("process_events called but no event was pending");
1313         }
1314 
1315         Ok(())
1316     }
1317 }
1318