1use core::ffi::c_void;
4use core::ptr::NonNull;
5
6use super::driver::UnicodeStringRaw;
7use super::error::{status, KmError, KmResult, NtStatus};
8use super::string::UnicodeString;
9
10#[repr(C)]
12pub struct DeviceObjectRaw {
13 pub type_: i16,
14 pub size: u16,
15 pub reference_count: i32,
16 pub driver_object: *mut c_void,
17 pub next_device: *mut DeviceObjectRaw,
18 pub attached_device: *mut DeviceObjectRaw,
19 pub current_irp: *mut c_void,
20 pub timer: *mut c_void,
21 pub flags: u32,
22 pub characteristics: u32,
23 pub vpb: *mut c_void,
24 pub device_extension: *mut c_void,
25 pub device_type: u32,
26 pub stack_size: i8,
27 }
29
30#[repr(u32)]
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum DeviceType {
34 Unknown = 0x00000022,
35 Beep = 0x00000001,
36 CdRom = 0x00000002,
37 CdRomFileSystem = 0x00000003,
38 Controller = 0x00000004,
39 Disk = 0x00000007,
40 DiskFileSystem = 0x00000008,
41 FileSystem = 0x00000009,
42 Keyboard = 0x0000000b,
43 Mouse = 0x0000000f,
44 Network = 0x00000012,
45 Null = 0x00000015,
46 Parallel = 0x00000016,
47 Physical = 0x00000017,
48 Printer = 0x00000018,
49 Scanner = 0x00000019,
50 Serial = 0x0000001b,
51 Screen = 0x0000001c,
52 Sound = 0x0000001d,
53 Transport = 0x00000021,
54 Ks = 0x0000002f,
55}
56
57#[repr(u32)]
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub enum DeviceCharacteristics {
61 None = 0,
62 RemovableMedia = 0x00000001,
63 ReadOnlyDevice = 0x00000002,
64 FloppyDiskette = 0x00000004,
65 WriteOnceMedia = 0x00000008,
66 RemoteDevice = 0x00000010,
67 DeviceIsMounted = 0x00000020,
68 VirtualVolume = 0x00000040,
69 SecureOpen = 0x00000100,
70}
71
72pub mod DeviceFlags {
74 pub const NONE: u32 = 0;
75 pub const BUFFERED_IO: u32 = 0x00000004;
76 pub const DIRECT_IO: u32 = 0x00000010;
77 pub const DO_EXCLUSIVE: u32 = 0x00000800;
78 pub const POWER_PAGEABLE: u32 = 0x00001000;
79 pub const DO_DEVICE_INITIALIZING: u32 = 0x00000080;
80
81 pub const DO_BUFFERED_IO: u32 = BUFFERED_IO;
83 pub const DO_DIRECT_IO: u32 = DIRECT_IO;
84}
85
86pub struct Device {
88 raw: NonNull<DeviceObjectRaw>,
89 symbolic_link: Option<UnicodeString>,
90}
91
92impl Device {
93 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
98 NonNull::new(ptr as *mut DeviceObjectRaw).map(|raw| Self {
99 raw,
100 symbolic_link: None,
101 })
102 }
103
104 pub fn as_raw(&self) -> *mut DeviceObjectRaw {
106 self.raw.as_ptr()
107 }
108
109 pub fn set_flags(&mut self, flags: u32) {
111 unsafe {
113 (*self.raw.as_ptr()).flags = flags;
114 }
115 }
116
117 pub fn add_flag(&mut self, flag: u32) {
119 unsafe {
121 (*self.raw.as_ptr()).flags |= flag;
122 }
123 }
124
125 pub fn remove_flag(&mut self, flag: u32) {
127 unsafe {
129 (*self.raw.as_ptr()).flags &= !flag;
130 }
131 }
132
133 pub fn flags(&self) -> u32 {
135 unsafe { (*self.raw.as_ptr()).flags }
137 }
138
139 pub fn device_type(&self) -> u32 {
141 unsafe { (*self.raw.as_ptr()).device_type }
143 }
144
145 pub fn extension<T>(&self) -> Option<&T> {
147 unsafe {
149 let ext = (*self.raw.as_ptr()).device_extension;
150 if ext.is_null() {
151 None
152 } else {
153 Some(&*(ext as *const T))
154 }
155 }
156 }
157
158 pub fn extension_mut<T>(&mut self) -> Option<&mut T> {
160 unsafe {
162 let ext = (*self.raw.as_ptr()).device_extension;
163 if ext.is_null() {
164 None
165 } else {
166 Some(&mut *(ext as *mut T))
167 }
168 }
169 }
170
171 pub fn create_symbolic_link(&mut self, link_name: &UnicodeString, device_name: &UnicodeString) -> KmResult<()> {
173 let status = unsafe {
175 IoCreateSymbolicLink(
176 link_name.as_ptr() as *const _,
177 device_name.as_ptr() as *const _,
178 )
179 };
180
181 if !status::nt_success(status) {
182 return Err(KmError::SymbolicLinkFailed {
183 reason: "IoCreateSymbolicLink failed",
184 });
185 }
186
187 Ok(())
188 }
189
190 pub fn delete_symbolic_link(link_name: &UnicodeString) -> KmResult<()> {
192 let status = unsafe {
194 IoDeleteSymbolicLink(link_name.as_ptr() as *const _)
195 };
196
197 if !status::nt_success(status) {
198 return Err(KmError::SymbolicLinkFailed {
199 reason: "IoDeleteSymbolicLink failed",
200 });
201 }
202
203 Ok(())
204 }
205
206 pub fn set_buffered_io(&mut self) {
208 self.add_flag(DeviceFlags::BUFFERED_IO);
209 }
210
211 pub fn set_direct_io(&mut self) {
213 self.add_flag(DeviceFlags::DIRECT_IO);
214 }
215
216 pub fn initialization_complete(&mut self) {
218 self.remove_flag(DeviceFlags::DO_DEVICE_INITIALIZING);
219 }
220}
221
222impl Drop for Device {
223 fn drop(&mut self) {
224 }
227}
228
229pub fn delete_device(device: *mut c_void) {
231 if !device.is_null() {
232 unsafe {
234 IoDeleteDevice(device);
235 }
236 }
237}
238
239pub struct DeviceBuilder<'a> {
241 driver: &'a mut super::driver::Driver,
242 name: Option<UnicodeString>,
243 symbolic_link: Option<UnicodeString>,
244 device_type: u32,
245 characteristics: u32,
246 exclusive: bool,
247 flags: u32,
248}
249
250impl<'a> DeviceBuilder<'a> {
251 pub fn new(driver: &'a mut super::driver::Driver) -> Self {
253 Self {
254 driver,
255 name: None,
256 symbolic_link: None,
257 device_type: DeviceType::Unknown as u32,
258 characteristics: 0,
259 exclusive: false,
260 flags: 0,
261 }
262 }
263
264 pub fn name(mut self, name: UnicodeString) -> Self {
266 self.name = Some(name);
267 self
268 }
269
270 pub fn symbolic_link(mut self, link: UnicodeString) -> Self {
272 self.symbolic_link = Some(link);
273 self
274 }
275
276 pub fn device_type(mut self, dtype: DeviceType) -> Self {
278 self.device_type = dtype as u32;
279 self
280 }
281
282 pub fn characteristics(mut self, chars: u32) -> Self {
284 self.characteristics = chars;
285 self
286 }
287
288 pub fn exclusive(mut self) -> Self {
290 self.exclusive = true;
291 self
292 }
293
294 pub fn buffered_io(mut self) -> Self {
296 self.flags |= DeviceFlags::BUFFERED_IO;
297 self
298 }
299
300 pub fn direct_io(mut self) -> Self {
302 self.flags |= DeviceFlags::DIRECT_IO;
303 self
304 }
305
306 pub fn build(self) -> KmResult<Device> {
308 let name = self.name.ok_or(KmError::InvalidParameter {
309 context: "device name required",
310 })?;
311
312 let mut device = self.driver.create_device(
313 &name,
314 self.device_type,
315 self.characteristics,
316 self.exclusive,
317 )?;
318
319 if self.flags != 0 {
320 device.add_flag(self.flags);
321 }
322
323 if let Some(ref link) = self.symbolic_link {
324 device.create_symbolic_link(link, &name)?;
325 }
326
327 device.initialization_complete();
328
329 Ok(device)
330 }
331}
332
333extern "system" {
335 fn IoDeleteDevice(DeviceObject: *mut c_void);
336 fn IoCreateSymbolicLink(
337 SymbolicLinkName: *const c_void,
338 DeviceName: *const c_void,
339 ) -> NtStatus;
340 fn IoDeleteSymbolicLink(SymbolicLinkName: *const c_void) -> NtStatus;
341}