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