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