Skip to main content

v4l2r/ioctl/
g_parm.rs

1use std::os::unix::io::AsRawFd;
2
3use nix::errno::Errno;
4use thiserror::Error;
5
6use crate::bindings::v4l2_standard;
7use crate::bindings::v4l2_std_id;
8use crate::bindings::v4l2_streamparm;
9use crate::QueueType;
10
11#[doc(hidden)]
12mod ioctl {
13    use crate::bindings::v4l2_standard;
14    use crate::bindings::v4l2_std_id;
15    use crate::bindings::v4l2_streamparm;
16
17    nix::ioctl_readwrite!(vidioc_g_parm, b'V', 21, v4l2_streamparm);
18    nix::ioctl_readwrite!(vidioc_s_parm, b'V', 22, v4l2_streamparm);
19    nix::ioctl_read!(vidioc_g_std, b'V', 23, v4l2_std_id);
20    nix::ioctl_write_ptr!(vidioc_s_std, b'V', 24, v4l2_std_id);
21    nix::ioctl_readwrite!(vidioc_enumstd, b'V', 25, v4l2_standard);
22    nix::ioctl_read!(vidioc_querystd, b'V', 63, v4l2_std_id);
23}
24
25#[derive(Debug, Error)]
26pub enum GParmError {
27    #[error("ioctl error: {0}")]
28    IoctlError(Errno),
29}
30
31impl From<GParmError> for Errno {
32    fn from(err: GParmError) -> Self {
33        match err {
34            GParmError::IoctlError(e) => e,
35        }
36    }
37}
38
39/// Safe wrapper around the `VIDIOC_G_PARM` ioctl.
40pub fn g_parm<O: From<v4l2_streamparm>>(
41    fd: &impl AsRawFd,
42    queue: QueueType,
43) -> Result<O, GParmError> {
44    let mut parm = v4l2_streamparm {
45        type_: queue as u32,
46        ..Default::default()
47    };
48
49    match unsafe { ioctl::vidioc_g_parm(fd.as_raw_fd(), &mut parm) } {
50        Ok(_) => Ok(O::from(parm)),
51        Err(e) => Err(GParmError::IoctlError(e)),
52    }
53}
54
55/// Safe wrapper around the `VIDIOC_S_PARM` ioctl.
56pub fn s_parm<I: Into<v4l2_streamparm>, O: From<v4l2_streamparm>>(
57    fd: &impl AsRawFd,
58    parm: I,
59) -> Result<O, GParmError> {
60    let mut parm = parm.into();
61
62    match unsafe { ioctl::vidioc_s_parm(fd.as_raw_fd(), &mut parm) } {
63        Ok(_) => Ok(O::from(parm)),
64        Err(e) => Err(GParmError::IoctlError(e)),
65    }
66}
67
68/// Safe wrapper around the `VIDIOC_G_STD` ioctl.
69pub fn g_std<O: From<v4l2_std_id>>(fd: &impl AsRawFd) -> Result<O, GParmError> {
70    let mut std_id: v4l2_std_id = 0;
71
72    match unsafe { ioctl::vidioc_g_std(fd.as_raw_fd(), &mut std_id) } {
73        Ok(_) => Ok(O::from(std_id)),
74        Err(e) => Err(GParmError::IoctlError(e)),
75    }
76}
77
78#[derive(Debug, Error)]
79pub enum SStdError {
80    #[error("unsupported standard requested")]
81    Unsupported,
82    #[error("ioctl error: {0}")]
83    IoctlError(Errno),
84}
85
86impl From<SStdError> for Errno {
87    fn from(err: SStdError) -> Self {
88        match err {
89            SStdError::Unsupported => Errno::EINVAL,
90            SStdError::IoctlError(e) => e,
91        }
92    }
93}
94
95/// Safe wrapper around the `VIDIOC_S_STD` ioctl.
96pub fn s_std<I: Into<v4l2_std_id>>(fd: &impl AsRawFd, std_id: I) -> Result<(), SStdError> {
97    let std_id = std_id.into();
98
99    match unsafe { ioctl::vidioc_s_std(fd.as_raw_fd(), &std_id) } {
100        Ok(_) => Ok(()),
101        Err(Errno::EINVAL) => Err(SStdError::Unsupported),
102        Err(e) => Err(SStdError::IoctlError(e)),
103    }
104}
105
106#[derive(Debug, Error)]
107pub enum EnumStdError {
108    #[error("requested index is out of bounds")]
109    OutOfBounds,
110    #[error("standard video timings are not supported for this input or output")]
111    Unsupported,
112    #[error("ioctl error: {0}")]
113    IoctlError(Errno),
114}
115
116impl From<EnumStdError> for Errno {
117    fn from(err: EnumStdError) -> Self {
118        match err {
119            EnumStdError::OutOfBounds => Errno::EINVAL,
120            EnumStdError::Unsupported => Errno::ENODATA,
121            EnumStdError::IoctlError(e) => e,
122        }
123    }
124}
125
126/// Safe wrapper around the `VIDIOC_ENUMSTD` ioctl.
127pub fn enumstd<O: From<v4l2_standard>>(fd: &impl AsRawFd, index: u32) -> Result<O, EnumStdError> {
128    let mut standard = v4l2_standard {
129        index,
130        ..Default::default()
131    };
132
133    match unsafe { ioctl::vidioc_enumstd(fd.as_raw_fd(), &mut standard) } {
134        Ok(_) => Ok(O::from(standard)),
135        Err(Errno::EINVAL) => Err(EnumStdError::OutOfBounds),
136        Err(Errno::ENODATA) => Err(EnumStdError::Unsupported),
137        Err(e) => Err(EnumStdError::IoctlError(e)),
138    }
139}
140
141/// Safe wrapper around the `VIDIOC_QUERYSTD` ioctl.
142pub fn querystd<O: From<v4l2_std_id>>(fd: &impl AsRawFd) -> Result<O, GParmError> {
143    let mut std_id: v4l2_std_id = 0;
144
145    match unsafe { ioctl::vidioc_querystd(fd.as_raw_fd(), &mut std_id) } {
146        Ok(_) => Ok(O::from(std_id)),
147        Err(e) => Err(GParmError::IoctlError(e)),
148    }
149}