|  | use std::ffi::c_int; | 
|  | use std::os::unix::io::AsRawFd; | 
|  |  | 
|  | use nix::errno::Errno; | 
|  | use thiserror::Error; | 
|  |  | 
|  | use crate::bindings::v4l2_input; | 
|  | use crate::bindings::v4l2_output; | 
|  |  | 
|  | #[doc(hidden)] | 
|  | mod ioctl { | 
|  | use std::ffi::c_int; | 
|  |  | 
|  | use crate::bindings::v4l2_input; | 
|  | use crate::bindings::v4l2_output; | 
|  |  | 
|  | nix::ioctl_readwrite!(vidioc_enuminput, b'V', 26, v4l2_input); | 
|  | nix::ioctl_read!(vidioc_g_input, b'V', 38, c_int); | 
|  | nix::ioctl_readwrite!(vidioc_s_input, b'V', 39, c_int); | 
|  |  | 
|  | nix::ioctl_read!(vidioc_g_output, b'V', 46, c_int); | 
|  | nix::ioctl_readwrite!(vidioc_s_output, b'V', 47, c_int); | 
|  | nix::ioctl_readwrite!(vidioc_enumoutput, b'V', 48, v4l2_output); | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Error)] | 
|  | pub enum SelectionError { | 
|  | #[error("selection {0} is out of range")] | 
|  | OutOfRange(usize), | 
|  | #[error("ioctl error: {0}")] | 
|  | IoctlError(Errno), | 
|  | } | 
|  |  | 
|  | impl From<SelectionError> for Errno { | 
|  | fn from(err: SelectionError) -> Self { | 
|  | match err { | 
|  | SelectionError::OutOfRange(_) => Errno::EINVAL, | 
|  | SelectionError::IoctlError(e) => e, | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Safe wrapper around the `VIDIOC_ENUMINPUT` ioctl. | 
|  | pub fn enuminput<R: From<v4l2_input>>( | 
|  | fd: &impl AsRawFd, | 
|  | index: usize, | 
|  | ) -> Result<R, SelectionError> { | 
|  | let mut input = v4l2_input { | 
|  | index: index as u32, | 
|  | ..Default::default() | 
|  | }; | 
|  |  | 
|  | match unsafe { ioctl::vidioc_enuminput(fd.as_raw_fd(), &mut input) } { | 
|  | Ok(_) => Ok(R::from(input)), | 
|  | Err(Errno::EINVAL) => Err(SelectionError::OutOfRange(index)), | 
|  | Err(e) => Err(SelectionError::IoctlError(e)), | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Safe wrapper around the `VIDIOC_G_INPUT` ioctl. | 
|  | pub fn g_input(fd: &impl AsRawFd) -> Result<usize, Errno> { | 
|  | let mut input: c_int = 0; | 
|  |  | 
|  | unsafe { ioctl::vidioc_g_input(fd.as_raw_fd(), &mut input) }.map(|r| r as usize) | 
|  | } | 
|  |  | 
|  | /// Safe wrapper around the `VIDIOC_S_INPUT` ioctl. | 
|  | /// | 
|  | /// Returns the updated `index` upon success. | 
|  | pub fn s_input(fd: &impl AsRawFd, index: usize) -> Result<usize, SelectionError> { | 
|  | let mut input: c_int = index as c_int; | 
|  |  | 
|  | match unsafe { ioctl::vidioc_s_input(fd.as_raw_fd(), &mut input) } { | 
|  | Ok(_) => Ok(input as usize), | 
|  | Err(Errno::EINVAL) => Err(SelectionError::OutOfRange(index)), | 
|  | Err(e) => Err(SelectionError::IoctlError(e)), | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Safe wrapper around the `VIDIOC_ENUMOUTPUT` ioctl. | 
|  | pub fn enumoutput<R: From<v4l2_output>>( | 
|  | fd: &impl AsRawFd, | 
|  | index: usize, | 
|  | ) -> Result<R, SelectionError> { | 
|  | let mut output = v4l2_output { | 
|  | index: index as u32, | 
|  | ..Default::default() | 
|  | }; | 
|  |  | 
|  | match unsafe { ioctl::vidioc_enumoutput(fd.as_raw_fd(), &mut output) } { | 
|  | Ok(_) => Ok(R::from(output)), | 
|  | Err(Errno::EINVAL) => Err(SelectionError::OutOfRange(index)), | 
|  | Err(e) => Err(SelectionError::IoctlError(e)), | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Safe wrapper around the `VIDIOC_G_OUTPUT` ioctl. | 
|  | pub fn g_output(fd: &impl AsRawFd) -> Result<usize, Errno> { | 
|  | let mut output: c_int = 0; | 
|  |  | 
|  | unsafe { ioctl::vidioc_g_output(fd.as_raw_fd(), &mut output) }.map(|r| r as usize) | 
|  | } | 
|  |  | 
|  | /// Safe wrapper around the `VIDIOC_S_OUTPUT` ioctl. | 
|  | pub fn s_output(fd: &impl AsRawFd, index: usize) -> Result<(), SelectionError> { | 
|  | let mut output: c_int = index as c_int; | 
|  |  | 
|  | match unsafe { ioctl::vidioc_s_output(fd.as_raw_fd(), &mut output) } { | 
|  | Ok(_) => Ok(()), | 
|  | Err(Errno::EINVAL) => Err(SelectionError::OutOfRange(index)), | 
|  | Err(e) => Err(SelectionError::IoctlError(e)), | 
|  | } | 
|  | } |