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