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::{fmt, mem}; |
10 | |
11 | /// Implements an `ioctl` with no real arguments. |
12 | pub struct NoArg<Opcode> { |
13 | /// The opcode. |
14 | _opcode: PhantomData<Opcode>, |
15 | } |
16 | |
17 | impl<Opcode: CompileTimeOpcode> fmt::Debug for NoArg<Opcode> { |
18 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
19 | f.debug_tuple(name:"NoArg" ).field(&Opcode::OPCODE).finish() |
20 | } |
21 | } |
22 | |
23 | impl<Opcode: CompileTimeOpcode> NoArg<Opcode> { |
24 | /// Create a new no-argument `ioctl` object. |
25 | /// |
26 | /// # Safety |
27 | /// |
28 | /// - `Opcode` must provide a valid opcode. |
29 | #[inline ] |
30 | pub unsafe fn new() -> Self { |
31 | Self { |
32 | _opcode: PhantomData, |
33 | } |
34 | } |
35 | } |
36 | |
37 | unsafe impl<Opcode: CompileTimeOpcode> Ioctl for NoArg<Opcode> { |
38 | type Output = (); |
39 | |
40 | const IS_MUTATING: bool = false; |
41 | const OPCODE: self::Opcode = Opcode::OPCODE; |
42 | |
43 | fn as_ptr(&mut self) -> *mut c::c_void { |
44 | core::ptr::null_mut() |
45 | } |
46 | |
47 | unsafe fn output_from_ptr(_: IoctlOutput, _: *mut c::c_void) -> Result<Self::Output> { |
48 | Ok(()) |
49 | } |
50 | } |
51 | |
52 | /// Implements the traditional "getter" pattern for `ioctl`s. |
53 | /// |
54 | /// Some `ioctl`s just read data into the userspace. As this is a popular |
55 | /// pattern this structure implements it. |
56 | pub struct Getter<Opcode, Output> { |
57 | /// The output data. |
58 | output: mem::MaybeUninit<Output>, |
59 | |
60 | /// The opcode. |
61 | _opcode: PhantomData<Opcode>, |
62 | } |
63 | |
64 | impl<Opcode: CompileTimeOpcode, Output> fmt::Debug for Getter<Opcode, Output> { |
65 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
66 | f.debug_tuple(name:"Getter" ).field(&Opcode::OPCODE).finish() |
67 | } |
68 | } |
69 | |
70 | impl<Opcode: CompileTimeOpcode, Output> Getter<Opcode, Output> { |
71 | /// Create a new getter-style `ioctl` object. |
72 | /// |
73 | /// # Safety |
74 | /// |
75 | /// - `Opcode` must provide a valid opcode. |
76 | /// - For this opcode, `Output` must be the type that the kernel expects to |
77 | /// write into. |
78 | #[inline ] |
79 | pub unsafe fn new() -> Self { |
80 | Self { |
81 | output: mem::MaybeUninit::uninit(), |
82 | _opcode: PhantomData, |
83 | } |
84 | } |
85 | } |
86 | |
87 | unsafe impl<Opcode: CompileTimeOpcode, Output> Ioctl for Getter<Opcode, Output> { |
88 | type Output = Output; |
89 | |
90 | const IS_MUTATING: bool = true; |
91 | const OPCODE: self::Opcode = Opcode::OPCODE; |
92 | |
93 | fn as_ptr(&mut self) -> *mut c::c_void { |
94 | self.output.as_mut_ptr().cast() |
95 | } |
96 | |
97 | unsafe fn output_from_ptr(_: IoctlOutput, ptr: *mut c::c_void) -> Result<Self::Output> { |
98 | Ok(ptr.cast::<Output>().read()) |
99 | } |
100 | } |
101 | |
102 | /// Implements the pattern for `ioctl`s where a pointer argument is given to |
103 | /// the `ioctl`. |
104 | /// |
105 | /// The opcode must be read-only. |
106 | pub struct Setter<Opcode, Input> { |
107 | /// The input data. |
108 | input: Input, |
109 | |
110 | /// The opcode. |
111 | _opcode: PhantomData<Opcode>, |
112 | } |
113 | |
114 | impl<Opcode: CompileTimeOpcode, Input: fmt::Debug> fmt::Debug for Setter<Opcode, Input> { |
115 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
116 | f&mut DebugTuple<'_, '_>.debug_tuple(name:"Setter" ) |
117 | .field(&Opcode::OPCODE) |
118 | .field(&self.input) |
119 | .finish() |
120 | } |
121 | } |
122 | |
123 | impl<Opcode: CompileTimeOpcode, Input> Setter<Opcode, Input> { |
124 | /// Create a new pointer setter-style `ioctl` object. |
125 | /// |
126 | /// # Safety |
127 | /// |
128 | /// - `Opcode` must provide a valid opcode. |
129 | /// - For this opcode, `Input` must be the type that the kernel expects to |
130 | /// get. |
131 | #[inline ] |
132 | pub unsafe fn new(input: Input) -> Self { |
133 | Self { |
134 | input, |
135 | _opcode: PhantomData, |
136 | } |
137 | } |
138 | } |
139 | |
140 | unsafe impl<Opcode: CompileTimeOpcode, Input> Ioctl for Setter<Opcode, Input> { |
141 | type Output = (); |
142 | |
143 | const IS_MUTATING: bool = false; |
144 | const OPCODE: self::Opcode = Opcode::OPCODE; |
145 | |
146 | fn as_ptr(&mut self) -> *mut c::c_void { |
147 | &mut self.input as *mut Input as *mut c::c_void |
148 | } |
149 | |
150 | unsafe fn output_from_ptr(_: IoctlOutput, _: *mut c::c_void) -> Result<Self::Output> { |
151 | Ok(()) |
152 | } |
153 | } |
154 | |
155 | /// Trait for something that provides an `ioctl` opcode at compile time. |
156 | pub trait CompileTimeOpcode { |
157 | /// The opcode. |
158 | const OPCODE: Opcode; |
159 | } |
160 | |
161 | /// Provides a bad opcode at compile time. |
162 | pub struct BadOpcode<const OPCODE: RawOpcode>; |
163 | |
164 | impl<const OPCODE: RawOpcode> CompileTimeOpcode for BadOpcode<OPCODE> { |
165 | const OPCODE: Opcode = Opcode::old(OPCODE); |
166 | } |
167 | |
168 | /// Provides a read code at compile time. |
169 | /// |
170 | /// This corresponds to the C macro `_IOR(GROUP, NUM, Data)`. |
171 | #[cfg (any(linux_kernel, bsd))] |
172 | pub struct ReadOpcode<const GROUP: u8, const NUM: u8, Data>(Data); |
173 | |
174 | #[cfg (any(linux_kernel, bsd))] |
175 | impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for ReadOpcode<GROUP, NUM, Data> { |
176 | const OPCODE: Opcode = Opcode::read::<Data>(GROUP, NUM); |
177 | } |
178 | |
179 | /// Provides a write code at compile time. |
180 | /// |
181 | /// This corresponds to the C macro `_IOW(GROUP, NUM, Data)`. |
182 | #[cfg (any(linux_kernel, bsd))] |
183 | pub struct WriteOpcode<const GROUP: u8, const NUM: u8, Data>(Data); |
184 | |
185 | #[cfg (any(linux_kernel, bsd))] |
186 | impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for WriteOpcode<GROUP, NUM, Data> { |
187 | const OPCODE: Opcode = Opcode::write::<Data>(GROUP, NUM); |
188 | } |
189 | |
190 | /// Provides a read/write code at compile time. |
191 | /// |
192 | /// This corresponds to the C macro `_IOWR(GROUP, NUM, Data)`. |
193 | #[cfg (any(linux_kernel, bsd))] |
194 | pub struct ReadWriteOpcode<const GROUP: u8, const NUM: u8, Data>(Data); |
195 | |
196 | #[cfg (any(linux_kernel, bsd))] |
197 | impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for ReadWriteOpcode<GROUP, NUM, Data> { |
198 | const OPCODE: Opcode = Opcode::read_write::<Data>(GROUP, NUM); |
199 | } |
200 | |
201 | /// Provides a `None` code at compile time. |
202 | /// |
203 | /// This corresponds to the C macro `_IO(GROUP, NUM)` when `Data` is zero |
204 | /// sized. |
205 | #[cfg (any(linux_kernel, bsd))] |
206 | pub struct NoneOpcode<const GROUP: u8, const NUM: u8, Data>(Data); |
207 | |
208 | #[cfg (any(linux_kernel, bsd))] |
209 | impl<const GROUP: u8, const NUM: u8, Data> CompileTimeOpcode for NoneOpcode<GROUP, NUM, Data> { |
210 | const OPCODE: Opcode = Opcode::none::<Data>(GROUP, NUM); |
211 | } |
212 | |