1 use std::ffi::c_int;
2 use std::os::unix::io::AsRawFd;
3
4 use nix::errno::Errno;
5 use thiserror::Error;
6
7 use crate::bindings::v4l2_input;
8 use crate::bindings::v4l2_output;
9
10 #[doc(hidden)]
11 mod ioctl {
12 use std::ffi::c_int;
13
14 use crate::bindings::v4l2_input;
15 use crate::bindings::v4l2_output;
16
17 nix::ioctl_readwrite!(vidioc_enuminput, b'V', 26, v4l2_input);
18 nix::ioctl_read!(vidioc_g_input, b'V', 38, c_int);
19 nix::ioctl_readwrite!(vidioc_s_input, b'V', 39, c_int);
20
21 nix::ioctl_read!(vidioc_g_output, b'V', 46, c_int);
22 nix::ioctl_readwrite!(vidioc_s_output, b'V', 47, c_int);
23 nix::ioctl_readwrite!(vidioc_enumoutput, b'V', 48, v4l2_output);
24 }
25
26 #[derive(Debug, Error)]
27 pub enum SelectionError {
28 #[error("selection {0} is out of range")]
29 OutOfRange(usize),
30 #[error("ioctl error: {0}")]
31 IoctlError(Errno),
32 }
33
34 impl From<SelectionError> for Errno {
from(err: SelectionError) -> Self35 fn from(err: SelectionError) -> Self {
36 match err {
37 SelectionError::OutOfRange(_) => Errno::EINVAL,
38 SelectionError::IoctlError(e) => e,
39 }
40 }
41 }
42
43 /// Safe wrapper around the `VIDIOC_ENUMINPUT` ioctl.
enuminput<R: From<v4l2_input>>( fd: &impl AsRawFd, index: usize, ) -> Result<R, SelectionError>44 pub fn enuminput<R: From<v4l2_input>>(
45 fd: &impl AsRawFd,
46 index: usize,
47 ) -> Result<R, SelectionError> {
48 let mut input = v4l2_input {
49 index: index as u32,
50 ..Default::default()
51 };
52
53 match unsafe { ioctl::vidioc_enuminput(fd.as_raw_fd(), &mut input) } {
54 Ok(_) => Ok(R::from(input)),
55 Err(Errno::EINVAL) => Err(SelectionError::OutOfRange(index)),
56 Err(e) => Err(SelectionError::IoctlError(e)),
57 }
58 }
59
60 /// Safe wrapper around the `VIDIOC_G_INPUT` ioctl.
g_input(fd: &impl AsRawFd) -> Result<usize, Errno>61 pub fn g_input(fd: &impl AsRawFd) -> Result<usize, Errno> {
62 let mut input: c_int = 0;
63
64 unsafe { ioctl::vidioc_g_input(fd.as_raw_fd(), &mut input) }.map(|r| r as usize)
65 }
66
67 /// Safe wrapper around the `VIDIOC_S_INPUT` ioctl.
68 ///
69 /// Returns the updated `index` upon success.
s_input(fd: &impl AsRawFd, index: usize) -> Result<usize, SelectionError>70 pub fn s_input(fd: &impl AsRawFd, index: usize) -> Result<usize, SelectionError> {
71 let mut input: c_int = index as c_int;
72
73 match unsafe { ioctl::vidioc_s_input(fd.as_raw_fd(), &mut input) } {
74 Ok(_) => Ok(input as usize),
75 Err(Errno::EINVAL) => Err(SelectionError::OutOfRange(index)),
76 Err(e) => Err(SelectionError::IoctlError(e)),
77 }
78 }
79
80 /// Safe wrapper around the `VIDIOC_ENUMOUTPUT` ioctl.
enumoutput<R: From<v4l2_output>>( fd: &impl AsRawFd, index: usize, ) -> Result<R, SelectionError>81 pub fn enumoutput<R: From<v4l2_output>>(
82 fd: &impl AsRawFd,
83 index: usize,
84 ) -> Result<R, SelectionError> {
85 let mut output = v4l2_output {
86 index: index as u32,
87 ..Default::default()
88 };
89
90 match unsafe { ioctl::vidioc_enumoutput(fd.as_raw_fd(), &mut output) } {
91 Ok(_) => Ok(R::from(output)),
92 Err(Errno::EINVAL) => Err(SelectionError::OutOfRange(index)),
93 Err(e) => Err(SelectionError::IoctlError(e)),
94 }
95 }
96
97 /// Safe wrapper around the `VIDIOC_G_OUTPUT` ioctl.
g_output(fd: &impl AsRawFd) -> Result<usize, Errno>98 pub fn g_output(fd: &impl AsRawFd) -> Result<usize, Errno> {
99 let mut output: c_int = 0;
100
101 unsafe { ioctl::vidioc_g_output(fd.as_raw_fd(), &mut output) }.map(|r| r as usize)
102 }
103
104 /// Safe wrapper around the `VIDIOC_S_OUTPUT` ioctl.
s_output(fd: &impl AsRawFd, index: usize) -> Result<(), SelectionError>105 pub fn s_output(fd: &impl AsRawFd, index: usize) -> Result<(), SelectionError> {
106 let mut output: c_int = index as c_int;
107
108 match unsafe { ioctl::vidioc_s_output(fd.as_raw_fd(), &mut output) } {
109 Ok(_) => Ok(()),
110 Err(Errno::EINVAL) => Err(SelectionError::OutOfRange(index)),
111 Err(e) => Err(SelectionError::IoctlError(e)),
112 }
113 }
114