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 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>( fd: &impl AsRawFd, index: usize, ) -> Result { 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 { 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 { 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>( fd: &impl AsRawFd, index: usize, ) -> Result { 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 { 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)), } }