1//! Implements typical patterns for `ioctl` usage.
2
3use super::{Ioctl, IoctlOutput, Opcode};
4
5use crate::backend::c;
6use crate::io::Result;
7
8use core::ptr::addr_of_mut;
9use core::{fmt, mem};
10
11/// Implements an `ioctl` with no real arguments.
12///
13/// To compute a value for the `OPCODE` argument, see the functions in the
14/// [`opcode`] module.
15///
16/// [`opcode`]: crate::ioctl::opcode
17pub struct NoArg<const OPCODE: Opcode> {}
18
19impl<const OPCODE: Opcode> fmt::Debug for NoArg<OPCODE> {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 f.debug_tuple(name:"NoArg").field(&OPCODE).finish()
22 }
23}
24
25impl<const OPCODE: Opcode> NoArg<OPCODE> {
26 /// Create a new no-argument `ioctl` object.
27 ///
28 /// # Safety
29 ///
30 /// - `OPCODE` must provide a valid opcode.
31 #[inline]
32 pub const unsafe fn new() -> Self {
33 Self {}
34 }
35}
36
37unsafe impl<const OPCODE: Opcode> Ioctl for NoArg<OPCODE> {
38 type Output = ();
39
40 const IS_MUTATING: bool = false;
41
42 fn opcode(&self) -> self::Opcode {
43 OPCODE
44 }
45
46 fn as_ptr(&mut self) -> *mut c::c_void {
47 core::ptr::null_mut()
48 }
49
50 unsafe fn output_from_ptr(_: IoctlOutput, _: *mut c::c_void) -> Result<Self::Output> {
51 Ok(())
52 }
53}
54
55/// Implements the traditional “getter” pattern for `ioctl`s.
56///
57/// Some `ioctl`s just read data into the userspace. As this is a popular
58/// pattern, this structure implements it.
59///
60/// To compute a value for the `OPCODE` argument, see the functions in the
61/// [`opcode`] module.
62///
63/// [`opcode`]: crate::ioctl::opcode
64pub struct Getter<const OPCODE: Opcode, Output> {
65 /// The output data.
66 output: mem::MaybeUninit<Output>,
67}
68
69impl<const OPCODE: Opcode, Output> fmt::Debug for Getter<OPCODE, Output> {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 f.debug_tuple(name:"Getter").field(&OPCODE).finish()
72 }
73}
74
75impl<const OPCODE: Opcode, Output> Getter<OPCODE, Output> {
76 /// Create a new getter-style `ioctl` object.
77 ///
78 /// # Safety
79 ///
80 /// - `OPCODE` must provide a valid opcode.
81 /// - For this opcode, `Output` must be the type that the kernel expects
82 /// to write into.
83 #[inline]
84 pub const unsafe fn new() -> Self {
85 Self {
86 output: mem::MaybeUninit::uninit(),
87 }
88 }
89}
90
91unsafe impl<const OPCODE: Opcode, Output> Ioctl for Getter<OPCODE, Output> {
92 type Output = Output;
93
94 const IS_MUTATING: bool = true;
95
96 fn opcode(&self) -> self::Opcode {
97 OPCODE
98 }
99
100 fn as_ptr(&mut self) -> *mut c::c_void {
101 self.output.as_mut_ptr().cast()
102 }
103
104 unsafe fn output_from_ptr(_: IoctlOutput, ptr: *mut c::c_void) -> Result<Self::Output> {
105 Ok(ptr.cast::<Output>().read())
106 }
107}
108
109/// Implements the pattern for `ioctl`s where a pointer argument is given to
110/// the `ioctl`.
111///
112/// The opcode must be read-only.
113///
114/// To compute a value for the `OPCODE` argument, see the functions in the
115/// [`opcode`] module.
116///
117/// [`opcode`]: crate::ioctl::opcode
118pub struct Setter<const OPCODE: Opcode, Input> {
119 /// The input data.
120 input: Input,
121}
122
123impl<const OPCODE: Opcode, Input: fmt::Debug> fmt::Debug for Setter<OPCODE, Input> {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 f&mut DebugTuple<'_, '_>.debug_tuple(name:"Setter")
126 .field(&OPCODE)
127 .field(&self.input)
128 .finish()
129 }
130}
131
132impl<const OPCODE: Opcode, Input> Setter<OPCODE, Input> {
133 /// Create a new pointer setter-style `ioctl` object.
134 ///
135 /// # Safety
136 ///
137 /// - `OPCODE` must provide a valid opcode.
138 /// - For this opcode, `Input` must be the type that the kernel expects to
139 /// get.
140 #[inline]
141 pub const unsafe fn new(input: Input) -> Self {
142 Self { input }
143 }
144}
145
146unsafe impl<const OPCODE: Opcode, Input> Ioctl for Setter<OPCODE, Input> {
147 type Output = ();
148
149 const IS_MUTATING: bool = false;
150
151 fn opcode(&self) -> self::Opcode {
152 OPCODE
153 }
154
155 fn as_ptr(&mut self) -> *mut c::c_void {
156 addr_of_mut!(self.input).cast::<c::c_void>()
157 }
158
159 unsafe fn output_from_ptr(_: IoctlOutput, _: *mut c::c_void) -> Result<Self::Output> {
160 Ok(())
161 }
162}
163
164/// Implements an “updater” pattern for `ioctl`s.
165///
166/// The ioctl takes a reference to a struct that it reads its input from,
167/// then writes output to the same struct.
168///
169/// To compute a value for the `OPCODE` argument, see the functions in the
170/// [`opcode`] module.
171///
172/// [`opcode`]: crate::ioctl::opcode
173pub struct Updater<'a, const OPCODE: Opcode, Value> {
174 /// Reference to input/output data.
175 value: &'a mut Value,
176}
177
178impl<'a, const OPCODE: Opcode, Value> Updater<'a, OPCODE, Value> {
179 /// Create a new pointer updater-style `ioctl` object.
180 ///
181 /// # Safety
182 ///
183 /// - `OPCODE` must provide a valid opcode.
184 /// - For this opcode, `Value` must be the type that the kernel expects to
185 /// get.
186 #[inline]
187 pub unsafe fn new(value: &'a mut Value) -> Self {
188 Self { value }
189 }
190}
191
192unsafe impl<'a, const OPCODE: Opcode, T> Ioctl for Updater<'a, OPCODE, T> {
193 type Output = ();
194
195 const IS_MUTATING: bool = true;
196
197 fn opcode(&self) -> self::Opcode {
198 OPCODE
199 }
200
201 fn as_ptr(&mut self) -> *mut c::c_void {
202 (self.value as *mut T).cast()
203 }
204
205 unsafe fn output_from_ptr(_output: IoctlOutput, _ptr: *mut c::c_void) -> Result<()> {
206 Ok(())
207 }
208}
209
210/// Implements an `ioctl` that passes an integer into the `ioctl`.
211///
212/// To compute a value for the `OPCODE` argument, see the functions in the
213/// [`opcode`] module.
214///
215/// [`opcode`]: crate::ioctl::opcode
216pub struct IntegerSetter<const OPCODE: Opcode> {
217 /// The value to pass in.
218 ///
219 /// For strict provenance preservation, this is a pointer.
220 value: *mut c::c_void,
221}
222
223impl<const OPCODE: Opcode> IntegerSetter<OPCODE> {
224 /// Create a new integer `Ioctl` helper containing a `usize`.
225 ///
226 /// # Safety
227 ///
228 /// - `OPCODE` must provide a valid opcode.
229 /// - For this opcode, it must expect an integer.
230 /// - The integer is in the valid range for this opcode.
231 #[inline]
232 pub const unsafe fn new_usize(value: usize) -> Self {
233 Self { value: value as _ }
234 }
235
236 /// Create a new integer `Ioctl` helper containing a `*mut c_void`.
237 ///
238 /// # Safety
239 ///
240 /// - `OPCODE` must provide a valid opcode.
241 /// - For this opcode, it must expect an integer.
242 /// - The integer is in the valid range for this opcode.
243 #[inline]
244 pub const unsafe fn new_pointer(value: *mut c::c_void) -> Self {
245 Self { value }
246 }
247}
248
249unsafe impl<const OPCODE: Opcode> Ioctl for IntegerSetter<OPCODE> {
250 type Output = ();
251
252 const IS_MUTATING: bool = false;
253
254 fn opcode(&self) -> self::Opcode {
255 OPCODE
256 }
257
258 fn as_ptr(&mut self) -> *mut c::c_void {
259 self.value
260 }
261
262 unsafe fn output_from_ptr(
263 _out: IoctlOutput,
264 _extract_output: *mut c::c_void,
265 ) -> Result<Self::Output> {
266 Ok(())
267 }
268}
269