1 | //! Implements typical patterns for `ioctl` usage. |
2 | |
3 | use super::{Ioctl, IoctlOutput, Opcode}; |
4 | |
5 | use crate::backend::c; |
6 | use crate::io::Result; |
7 | |
8 | use core::ptr::addr_of_mut; |
9 | use 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 |
17 | pub struct NoArg<const OPCODE: Opcode> {} |
18 | |
19 | impl<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 | |
25 | impl<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 | |
37 | unsafe 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 |
64 | pub struct Getter<const OPCODE: Opcode, Output> { |
65 | /// The output data. |
66 | output: mem::MaybeUninit<Output>, |
67 | } |
68 | |
69 | impl<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 | |
75 | impl<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 | |
91 | unsafe 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 |
118 | pub struct Setter<const OPCODE: Opcode, Input> { |
119 | /// The input data. |
120 | input: Input, |
121 | } |
122 | |
123 | impl<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 | |
132 | impl<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 | |
146 | unsafe 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 |
173 | pub struct Updater<'a, const OPCODE: Opcode, Value> { |
174 | /// Reference to input/output data. |
175 | value: &'a mut Value, |
176 | } |
177 | |
178 | impl<'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 | |
192 | unsafe 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 |
216 | pub 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 | |
223 | impl<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 | |
249 | unsafe 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 | |