1 //! Implements typical patterns for `ioctl` usage. 2 3 use super::{Ioctl, IoctlOutput, Opcode, RawOpcode}; 4 5 use crate::backend::c; 6 use crate::io::Result; 7 8 use core::marker::PhantomData; 9 use core::ptr::addr_of_mut; 10 use core::{fmt, mem}; 11 12 /// Implements an `ioctl` with no real arguments. 13 pub struct NoArg<Opcode> { 14 /// The opcode. 15 _opcode: PhantomData<Opcode>, 16 } 17 18 impl<Opcode: CompileTimeOpcode> fmt::Debug for NoArg<Opcode> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result19 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 20 f.debug_tuple("NoArg").field(&Opcode::OPCODE).finish() 21 } 22 } 23 24 impl<Opcode: CompileTimeOpcode> NoArg<Opcode> { 25 /// Create a new no-argument `ioctl` object. 26 /// 27 /// # Safety 28 /// 29 /// - `Opcode` must provide a valid opcode. 30 #[inline] new() -> Self31 pub unsafe fn new() -> Self { 32 Self { 33 _opcode: PhantomData, 34 } 35 } 36 } 37 38 unsafe impl<Opcode: CompileTimeOpcode> Ioctl for NoArg<Opcode> { 39 type Output = (); 40 41 const IS_MUTATING: bool = false; 42 const OPCODE: self::Opcode = Opcode::OPCODE; 43 as_ptr(&mut self) -> *mut c::c_void44 fn as_ptr(&mut self) -> *mut c::c_void { 45 core::ptr::null_mut() 46 } 47 output_from_ptr(_: IoctlOutput, _: *mut c::c_void) -> Result<Self::Output>48 unsafe fn output_from_ptr(_: IoctlOutput, _: *mut c::c_void) -> Result<Self::Output> { 49 Ok(()) 50 } 51 } 52 53 /// Implements the traditional “getter” pattern for `ioctl`s. 54 /// 55 /// Some `ioctl`s just read data into the userspace. As this is a popular 56 /// pattern this structure implements it. 57 pub struct Getter<Opcode, Output> { 58 /// The output data. 59 output: mem::MaybeUninit<Output>, 60 61 /// The opcode. 62 _opcode: PhantomData<Opcode>, 63 } 64 65 impl<Opcode: CompileTimeOpcode, Output> fmt::Debug for Getter<Opcode, Output> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 67 f.debug_tuple("Getter").field(&Opcode::OPCODE).finish() 68 } 69 } 70 71 impl<Opcode: CompileTimeOpcode, Output> Getter<Opcode, Output> { 72 /// Create a new getter-style `ioctl` object. 73 /// 74 /// # Safety 75 /// 76 /// - `Opcode` must provide a valid opcode. 77 /// - For this opcode, `Output` must be the type that the kernel expects to 78 /// write into. 79 #[inline] new() -> Self80 pub unsafe fn new() -> Self { 81 Self { 82 output: mem::MaybeUninit::uninit(), 83 _opcode: PhantomData, 84 } 85 } 86 } 87 88 unsafe impl<Opcode: CompileTimeOpcode, Output> Ioctl for Getter<Opcode, Output> { 89 type Output = Output; 90 91 const IS_MUTATING: bool = true; 92 const OPCODE: self::Opcode = Opcode::OPCODE; 93 as_ptr(&mut self) -> *mut c::c_void94 fn as_ptr(&mut self) -> *mut c::c_void { 95 self.output.as_mut_ptr().cast() 96 } 97 output_from_ptr(_: IoctlOutput, ptr: *mut c::c_void) -> Result<Self::Output>98 unsafe fn output_from_ptr(_: IoctlOutput, ptr: *mut c::c_void) -> Result<Self::Output> { 99 Ok(ptr.cast::<Output>().read()) 100 } 101 } 102 103 /// Implements the pattern for `ioctl`s where a pointer argument is given to 104 /// the `ioctl`. 105 /// 106 /// The opcode must be read-only. 107 pub struct Setter<Opcode, Input> { 108 /// The input data. 109 input: Input, 110 111 /// The opcode. 112 _opcode: PhantomData<Opcode>, 113 } 114 115 impl<Opcode: CompileTimeOpcode, Input: fmt::Debug> fmt::Debug for Setter<Opcode, Input> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 117 f.debug_tuple("Setter") 118 .field(&Opcode::OPCODE) 119 .field(&self.input) 120 .finish() 121 } 122 } 123 124 impl<Opcode: CompileTimeOpcode, Input> Setter<Opcode, Input> { 125 /// Create a new pointer setter-style `ioctl` object. 126 /// 127 /// # Safety 128 /// 129 /// - `Opcode` must provide a valid opcode. 130 /// - For this opcode, `Input` must be the type that the kernel expects to 131 /// get. 132 #[inline] new(input: Input) -> Self133 pub unsafe fn new(input: Input) -> Self { 134 Self { 135 input, 136 _opcode: PhantomData, 137 } 138 } 139 } 140 141 unsafe impl<Opcode: CompileTimeOpcode, Input> Ioctl for Setter<Opcode, Input> { 142 type Output = (); 143 144 const IS_MUTATING: bool = false; 145 const OPCODE: self::Opcode = Opcode::OPCODE; 146 as_ptr(&mut self) -> *mut c::c_void147 fn as_ptr(&mut self) -> *mut c::c_void { 148 addr_of_mut!(self.input).cast::<c::c_void>() 149 } 150 output_from_ptr(_: IoctlOutput, _: *mut c::c_void) -> Result<Self::Output>151 unsafe fn output_from_ptr(_: IoctlOutput, _: *mut c::c_void) -> Result<Self::Output> { 152 Ok(()) 153 } 154 } 155 156 /// Implements an “updater” pattern for `ioctl`s. 157 /// 158 /// The ioctl takes a reference to a struct that it reads its input from, 159 /// then writes output to the same struct. 160 pub struct Updater<'a, Opcode, Value> { 161 /// Reference to input/output data. 162 value: &'a mut Value, 163 164 /// The opcode. 165 _opcode: PhantomData<Opcode>, 166 } 167 168 impl<'a, Opcode: CompileTimeOpcode, Value> Updater<'a, Opcode, Value> { 169 /// Create a new pointer updater-style `ioctl` object. 170 /// 171 /// # Safety 172 /// 173 /// - `Opcode` must provide a valid opcode. 174 /// - For this opcode, `Value` must be the type that the kernel expects to 175 /// get. 176 #[inline] new(value: &'a mut Value) -> Self177 pub unsafe fn new(value: &'a mut Value) -> Self { 178 Self { 179 value, 180 _opcode: PhantomData, 181 } 182 } 183 } 184 185 unsafe impl<'a, Opcode: CompileTimeOpcode, T> Ioctl for Updater<'a, Opcode, T> { 186 type Output = (); 187 188 const IS_MUTATING: bool = true; 189 const OPCODE: self::Opcode = Opcode::OPCODE; 190 as_ptr(&mut self) -> *mut c::c_void191 fn as_ptr(&mut self) -> *mut c::c_void { 192 (self.value as *mut T).cast() 193 } 194 output_from_ptr(_output: IoctlOutput, _ptr: *mut c::c_void) -> Result<()>195 unsafe fn output_from_ptr(_output: IoctlOutput, _ptr: *mut c::c_void) -> Result<()> { 196 Ok(()) 197 } 198 } 199 200 /// Trait for something that provides an `ioctl` opcode at compile time. 201 pub trait CompileTimeOpcode { 202 /// The opcode. 203 const OPCODE: Opcode; 204 } 205 206 /// Provides a bad opcode at compile time. 207 pub struct BadOpcode<const OPCODE: RawOpcode>; 208 209 impl<const OPCODE: RawOpcode> CompileTimeOpcode for BadOpcode<OPCODE> { 210 const OPCODE: Opcode = Opcode::old(OPCODE); 211 } 212 213 /// Provides a read code at compile time. 214 /// 215 /// This corresponds to the C macro `_IOR(GROUP, NUM, Data)`. 216 #[cfg(any(linux_kernel, bsd))] 217 pub struct ReadOpcode<const GROUP: u8, const NUM: u8, Data>(Data); 218 219 #[cfg(any(linux_kernel, bsd))] 220 impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for ReadOpcode<GROUP, NUM, Data> { 221 const OPCODE: Opcode = Opcode::read::<Data>(GROUP, NUM); 222 } 223 224 /// Provides a write code at compile time. 225 /// 226 /// This corresponds to the C macro `_IOW(GROUP, NUM, Data)`. 227 #[cfg(any(linux_kernel, bsd))] 228 pub struct WriteOpcode<const GROUP: u8, const NUM: u8, Data>(Data); 229 230 #[cfg(any(linux_kernel, bsd))] 231 impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for WriteOpcode<GROUP, NUM, Data> { 232 const OPCODE: Opcode = Opcode::write::<Data>(GROUP, NUM); 233 } 234 235 /// Provides a read/write code at compile time. 236 /// 237 /// This corresponds to the C macro `_IOWR(GROUP, NUM, Data)`. 238 #[cfg(any(linux_kernel, bsd))] 239 pub struct ReadWriteOpcode<const GROUP: u8, const NUM: u8, Data>(Data); 240 241 #[cfg(any(linux_kernel, bsd))] 242 impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for ReadWriteOpcode<GROUP, NUM, Data> { 243 const OPCODE: Opcode = Opcode::read_write::<Data>(GROUP, NUM); 244 } 245 246 /// Provides a `None` code at compile time. 247 /// 248 /// This corresponds to the C macro `_IO(GROUP, NUM)` when `Data` is zero 249 /// sized. 250 #[cfg(any(linux_kernel, bsd))] 251 pub struct NoneOpcode<const GROUP: u8, const NUM: u8, Data>(Data); 252 253 #[cfg(any(linux_kernel, bsd))] 254 impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for NoneOpcode<GROUP, NUM, Data> { 255 const OPCODE: Opcode = Opcode::none::<Data>(GROUP, NUM); 256 } 257