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> { |
19 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
20 | f.debug_tuple(name:"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 ] |
31 | 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 | |
44 | fn as_ptr(&mut self) -> *mut c::c_void { |
45 | core::ptr::null_mut() |
46 | } |
47 | |
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> { |
66 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
67 | f.debug_tuple(name:"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 ] |
80 | 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 | |
94 | fn as_ptr(&mut self) -> *mut c::c_void { |
95 | self.output.as_mut_ptr().cast() |
96 | } |
97 | |
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> { |
116 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
117 | f&mut DebugTuple<'_, '_>.debug_tuple(name:"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 ] |
133 | 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 | |
147 | fn as_ptr(&mut self) -> *mut c::c_void { |
148 | addr_of_mut!(self.input).cast::<c::c_void>() |
149 | } |
150 | |
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 ] |
177 | 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 | |
191 | fn as_ptr(&mut self) -> *mut c::c_void { |
192 | (self.value as *mut T).cast() |
193 | } |
194 | |
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 | |