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