//! Implements typical patterns for `ioctl` usage. use super::{Ioctl, IoctlOutput, Opcode}; use crate::backend::c; use crate::io::Result; use core::ptr::addr_of_mut; use core::{fmt, mem}; /// Implements an `ioctl` with no real arguments. /// /// To compute a value for the `OPCODE` argument, see the functions in the /// [`opcode`] module. /// /// [`opcode`]: crate::ioctl::opcode pub struct NoArg {} impl fmt::Debug for NoArg { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("NoArg").field(&OPCODE).finish() } } impl NoArg { /// Create a new no-argument `ioctl` object. /// /// # Safety /// /// - `OPCODE` must provide a valid opcode. #[inline] pub const unsafe fn new() -> Self { Self {} } } unsafe impl Ioctl for NoArg { type Output = (); const IS_MUTATING: bool = false; fn opcode(&self) -> self::Opcode { OPCODE } fn as_ptr(&mut self) -> *mut c::c_void { core::ptr::null_mut() } unsafe fn output_from_ptr(_: IoctlOutput, _: *mut c::c_void) -> Result { Ok(()) } } /// Implements the traditional “getter” pattern for `ioctl`s. /// /// Some `ioctl`s just read data into the userspace. As this is a popular /// pattern, this structure implements it. /// /// To compute a value for the `OPCODE` argument, see the functions in the /// [`opcode`] module. /// /// [`opcode`]: crate::ioctl::opcode pub struct Getter { /// The output data. output: mem::MaybeUninit, } impl fmt::Debug for Getter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Getter").field(&OPCODE).finish() } } impl Getter { /// Create a new getter-style `ioctl` object. /// /// # Safety /// /// - `OPCODE` must provide a valid opcode. /// - For this opcode, `Output` must be the type that the kernel expects /// to write into. #[inline] pub const unsafe fn new() -> Self { Self { output: mem::MaybeUninit::uninit(), } } } unsafe impl Ioctl for Getter { type Output = Output; const IS_MUTATING: bool = true; fn opcode(&self) -> self::Opcode { OPCODE } fn as_ptr(&mut self) -> *mut c::c_void { self.output.as_mut_ptr().cast() } unsafe fn output_from_ptr(_: IoctlOutput, ptr: *mut c::c_void) -> Result { Ok(ptr.cast::().read()) } } /// Implements the pattern for `ioctl`s where a pointer argument is given to /// the `ioctl`. /// /// The opcode must be read-only. /// /// To compute a value for the `OPCODE` argument, see the functions in the /// [`opcode`] module. /// /// [`opcode`]: crate::ioctl::opcode pub struct Setter { /// The input data. input: Input, } impl fmt::Debug for Setter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Setter") .field(&OPCODE) .field(&self.input) .finish() } } impl Setter { /// Create a new pointer setter-style `ioctl` object. /// /// # Safety /// /// - `OPCODE` must provide a valid opcode. /// - For this opcode, `Input` must be the type that the kernel expects to /// get. #[inline] pub const unsafe fn new(input: Input) -> Self { Self { input } } } unsafe impl Ioctl for Setter { type Output = (); const IS_MUTATING: bool = false; fn opcode(&self) -> self::Opcode { OPCODE } fn as_ptr(&mut self) -> *mut c::c_void { addr_of_mut!(self.input).cast::() } unsafe fn output_from_ptr(_: IoctlOutput, _: *mut c::c_void) -> Result { Ok(()) } } /// Implements an “updater” pattern for `ioctl`s. /// /// The ioctl takes a reference to a struct that it reads its input from, /// then writes output to the same struct. /// /// To compute a value for the `OPCODE` argument, see the functions in the /// [`opcode`] module. /// /// [`opcode`]: crate::ioctl::opcode pub struct Updater<'a, const OPCODE: Opcode, Value> { /// Reference to input/output data. value: &'a mut Value, } impl<'a, const OPCODE: Opcode, Value> Updater<'a, OPCODE, Value> { /// Create a new pointer updater-style `ioctl` object. /// /// # Safety /// /// - `OPCODE` must provide a valid opcode. /// - For this opcode, `Value` must be the type that the kernel expects to /// get. #[inline] pub unsafe fn new(value: &'a mut Value) -> Self { Self { value } } } unsafe impl<'a, const OPCODE: Opcode, T> Ioctl for Updater<'a, OPCODE, T> { type Output = (); const IS_MUTATING: bool = true; fn opcode(&self) -> self::Opcode { OPCODE } fn as_ptr(&mut self) -> *mut c::c_void { (self.value as *mut T).cast() } unsafe fn output_from_ptr(_output: IoctlOutput, _ptr: *mut c::c_void) -> Result<()> { Ok(()) } } /// Implements an `ioctl` that passes an integer into the `ioctl`. /// /// To compute a value for the `OPCODE` argument, see the functions in the /// [`opcode`] module. /// /// [`opcode`]: crate::ioctl::opcode pub struct IntegerSetter { /// The value to pass in. /// /// For strict provenance preservation, this is a pointer. value: *mut c::c_void, } impl IntegerSetter { /// Create a new integer `Ioctl` helper containing a `usize`. /// /// # Safety /// /// - `OPCODE` must provide a valid opcode. /// - For this opcode, it must expect an integer. /// - The integer is in the valid range for this opcode. #[inline] pub const unsafe fn new_usize(value: usize) -> Self { Self { value: value as _ } } /// Create a new integer `Ioctl` helper containing a `*mut c_void`. /// /// # Safety /// /// - `OPCODE` must provide a valid opcode. /// - For this opcode, it must expect an integer. /// - The integer is in the valid range for this opcode. #[inline] pub const unsafe fn new_pointer(value: *mut c::c_void) -> Self { Self { value } } } unsafe impl Ioctl for IntegerSetter { type Output = (); const IS_MUTATING: bool = false; fn opcode(&self) -> self::Opcode { OPCODE } fn as_ptr(&mut self) -> *mut c::c_void { self.value } unsafe fn output_from_ptr( _out: IoctlOutput, _extract_output: *mut c::c_void, ) -> Result { Ok(()) } }