1use crate::ffi::{WdiDeviceInfo, WdiLogLevel, WdiOptionsCreateList, WdiOptionsPrepareDriver, WdiOptionsInstallDriver};
8use crate::ffi::{wdi_create_list, wdi_destroy_list, wdi_prepare_driver, wdi_install_driver, wdi_set_log_level};
9use std::ffi::{CStr, CString};
10use std::fmt;
11use std::os::raw::c_int;
12use std::ptr;
13
14pub enum LogLevel {
17 Debug,
18 Info,
19 Warning,
20 Error,
21 None,
22}
23
24impl From<log::LevelFilter> for LogLevel {
25 fn from(level: log::LevelFilter) -> Self {
26 match level {
28 log::LevelFilter::Trace => LogLevel::Debug,
29 log::LevelFilter::Debug => LogLevel::Info,
30 log::LevelFilter::Info => LogLevel::Warning,
31 log::LevelFilter::Warn => LogLevel::Error,
32 log::LevelFilter::Error => LogLevel::Error,
33 log::LevelFilter::Off => LogLevel::None,
34 }
35 }
36}
37
38impl From<log::Level> for LogLevel {
39 fn from(level: log::Level) -> Self {
40 match level {
42 log::Level::Trace => LogLevel::Debug,
43 log::Level::Debug => LogLevel::Info,
44 log::Level::Info => LogLevel::Warning,
45 log::Level::Warn => LogLevel::Error,
46 log::Level::Error => LogLevel::Error,
47 }
48 }
49}
50
51impl From<LogLevel> for c_int {
52 fn from(level: LogLevel) -> Self {
53 match level {
54 LogLevel::Debug => 0,
55 LogLevel::Info => 1,
56 LogLevel::Warning => 2,
57 LogLevel::Error => 3,
58 LogLevel::None => 4,
59 }
60 }
61}
62
63impl From<WdiLogLevel> for LogLevel {
64 fn from(level: WdiLogLevel) -> Self {
65 match level {
66 WdiLogLevel::Debug => LogLevel::Debug,
67 WdiLogLevel::Info => LogLevel::Info,
68 WdiLogLevel::Warning => LogLevel::Warning,
69 WdiLogLevel::Error => LogLevel::Error,
70 WdiLogLevel::None => LogLevel::None,
71 }
72 }
73}
74
75#[derive(Debug)]
77pub enum Error {
78 Io,
79 InvalidParam,
80 Access,
81 NoDevice,
82 NotFound,
83 Busy,
84 Timeout,
85 Overflow,
86 PendingInstallation,
87 Interrupted,
88 Resource,
89 NotSupported,
90 Exists,
91 UserCancel,
92 NeedsAdmin,
93 Wow64,
94 InfSyntax,
95 CatMissing,
96 Unsigned,
97 Other,
98 Unknown(c_int),
99}
100
101impl Error {
102 fn from_code(code: c_int) -> Result<(), Self> {
103 match code {
104 0 => Ok(()),
105 -1 => Err(Error::Io),
106 -2 => Err(Error::InvalidParam),
107 -3 => Err(Error::Access),
108 -4 => Err(Error::NoDevice),
109 -5 => Err(Error::NotFound),
110 -6 => Err(Error::Busy),
111 -7 => Err(Error::Timeout),
112 -8 => Err(Error::Overflow),
113 -9 => Err(Error::PendingInstallation),
114 -10 => Err(Error::Interrupted),
115 -11 => Err(Error::Resource),
116 -12 => Err(Error::NotSupported),
117 -13 => Err(Error::Exists),
118 -14 => Err(Error::UserCancel),
119 -15 => Err(Error::NeedsAdmin),
120 -16 => Err(Error::Wow64),
121 -17 => Err(Error::InfSyntax),
122 -18 => Err(Error::CatMissing),
123 -19 => Err(Error::Unsigned),
124 -99 => Err(Error::Other),
125 code => Err(Error::Unknown(code)),
126 }
127 }
128}
129
130impl fmt::Display for Error {
131 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132 write!(f, "{:?}", self)
133 }
134}
135
136impl std::error::Error for Error {}
137
138#[derive(Debug, Clone, Copy)]
140pub enum DriverType {
141 WinUsb,
142 LibUsb0,
143 LibUsbK,
144 Cdc,
145 User,
146}
147
148impl DriverType {
149 fn to_c_int(self) -> c_int {
150 match self {
151 DriverType::WinUsb => 0,
152 DriverType::LibUsb0 => 1,
153 DriverType::LibUsbK => 2,
154 DriverType::Cdc => 3,
155 DriverType::User => 4,
156 }
157 }
158}
159
160#[derive(Debug, Clone)]
162pub struct Device {
163 pub vid: u16,
164 pub pid: u16,
165 pub is_composite: bool,
166 pub mi: u8,
167 pub desc: Option<String>,
168 pub driver: Option<String>,
169 pub device_id: Option<String>,
170 pub hardware_id: Option<String>,
171 pub compatible_id: Option<String>,
172 pub upper_filter: Option<String>,
173 pub driver_version: u64,
174}
175
176impl Device {
177 unsafe fn from_raw(raw: *const WdiDeviceInfo) -> Self {
178 let raw = unsafe { &*raw };
179 Device {
180 vid: raw.vid,
181 pid: raw.pid,
182 is_composite: raw.is_composite != 0,
183 mi: raw.mi,
184 desc: unsafe{ ptr_to_string(raw.desc) },
185 driver: unsafe{ ptr_to_string(raw.driver) },
186 device_id: unsafe{ ptr_to_string(raw.device_id) },
187 hardware_id: unsafe{ ptr_to_string(raw.hardware_id) },
188 compatible_id: unsafe{ ptr_to_string(raw.compatible_id) },
189 upper_filter: unsafe{ ptr_to_string(raw.upper_filter) },
190 driver_version: raw.driver_version,
191 }
192 }
193}
194
195impl std::fmt::Display for Device {
196 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
197 write!(
198 f,
199 "{:04X}:{:04X} {}",
200 self.vid,
201 self.pid,
202 self.desc.as_deref().unwrap_or("(no description)")
203 )
204 }
205}
206
207unsafe fn ptr_to_string(ptr: *mut i8) -> Option<String> {
208 if ptr.is_null() {
209 None
210 } else {
211 unsafe { CStr::from_ptr(ptr).to_str().ok().map(|s| s.to_owned()) }
212 }
213}
214
215#[derive(Debug)]
219pub struct DeviceList {
220 head: *mut WdiDeviceInfo,
221}
222
223impl DeviceList {
224 pub fn iter(&self) -> DeviceIter {
226 DeviceIter {
227 current: self.head,
228 }
229 }
230
231 pub fn len(&self) -> usize {
233 self.iter().count()
234 }
235
236 pub fn is_empty(&self) -> bool {
238 self.head.is_null()
239 }
240
241 pub fn get(&self, index: usize) -> Option<Device> {
243 self.iter().nth(index)
244 }
245
246 pub fn from_vid_pid(&self, vid: u16, pid: u16) -> Vec<Device> {
248 self.iter()
249 .filter(|d| d.vid == vid && d.pid == pid)
250 .collect()
251 }
252}
253
254impl Drop for DeviceList {
255 fn drop(&mut self) {
256 if !self.head.is_null() {
257 unsafe {
258 wdi_destroy_list(self.head);
259 }
260 }
261 }
262}
263
264pub struct DeviceIter {
266 current: *mut WdiDeviceInfo,
267}
268
269impl Iterator for DeviceIter {
270 type Item = Device;
271
272 fn next(&mut self) -> Option<Self::Item> {
273 if self.current.is_null() {
274 None
275 } else {
276 unsafe {
277 let device = Device::from_raw(self.current);
278 self.current = (*self.current).next;
279 Some(device)
280 }
281 }
282 }
283}
284
285#[derive(Debug, Clone)]
287pub struct CreateListOptions {
288 pub list_all: bool,
289 pub list_hubs: bool,
290 pub trim_whitespaces: bool,
291}
292
293impl Default for CreateListOptions {
294 fn default() -> Self {
295 CreateListOptions {
296 list_all: false,
297 list_hubs: false,
298 trim_whitespaces: true,
299 }
300 }
301}
302
303pub fn create_list(options: CreateListOptions) -> Result<DeviceList, Error> {
308 let mut opts = WdiOptionsCreateList {
309 list_all: options.list_all as c_int,
310 list_hubs: options.list_hubs as c_int,
311 trim_whitespaces: options.trim_whitespaces as c_int,
312 };
313
314 let mut list: *mut WdiDeviceInfo = ptr::null_mut();
315
316 unsafe {
317 let result = wdi_create_list(&mut list, &mut opts);
318 Error::from_code(result)?;
319 }
320
321 Ok(DeviceList { head: list })
322}
323
324#[derive(Debug, Clone)]
328pub struct PrepareDriverOptions {
329 pub driver_type: DriverType,
330 pub vendor_name: Option<String>,
331 pub device_guid: Option<String>,
332 pub disable_cat: bool,
333 pub disable_signing: bool,
334 pub cert_subject: Option<String>,
335 pub use_wcid_driver: bool,
336
337 pub external_inf: bool,
340}
341
342impl Default for PrepareDriverOptions {
343 fn default() -> Self {
344 PrepareDriverOptions {
345 driver_type: DriverType::WinUsb,
346 vendor_name: None,
347 device_guid: None,
348 disable_cat: false,
349 disable_signing: false,
350 cert_subject: None,
351 use_wcid_driver: false,
352 external_inf: false,
353 }
354 }
355}
356
357pub fn prepare_driver(
368 device: &Device,
369 path: &str,
370 inf_name: &str,
371 options: &PrepareDriverOptions,
372) -> Result<(), Error> {
373 let path_c = CString::new(path).map_err(|_| Error::InvalidParam)?;
374 let inf_name_c = CString::new(inf_name).map_err(|_| Error::InvalidParam)?;
375
376 let desc_c = device.desc.as_ref()
378 .and_then(|s| CString::new(s.as_str()).ok());
379 let driver_c = device.driver.as_ref()
380 .and_then(|s| CString::new(s.as_str()).ok());
381 let device_id_c = device.device_id.as_ref()
382 .and_then(|s| CString::new(s.as_str()).ok());
383 let hardware_id_c = device.hardware_id.as_ref()
384 .and_then(|s| CString::new(s.as_str()).ok());
385 let compatible_id_c = device.compatible_id.as_ref()
386 .and_then(|s| CString::new(s.as_str()).ok());
387 let upper_filter_c = device.upper_filter.as_ref()
388 .and_then(|s| CString::new(s.as_str()).ok());
389
390 let vendor_name_c = options.vendor_name.as_ref()
391 .and_then(|s| CString::new(s.as_str()).ok());
392 let device_guid_c = options.device_guid.as_ref()
393 .and_then(|s| CString::new(s.as_str()).ok());
394 let cert_subject_c = options.cert_subject.as_ref()
395 .and_then(|s| CString::new(s.as_str()).ok());
396
397 let mut device_info = WdiDeviceInfo {
398 next: ptr::null_mut(),
399 vid: device.vid,
400 pid: device.pid,
401 is_composite: device.is_composite as c_int,
402 mi: device.mi,
403 desc: desc_c.as_ref().map_or(ptr::null_mut(), |c| c.as_ptr() as *mut i8),
404 driver: driver_c.as_ref().map_or(ptr::null_mut(), |c| c.as_ptr() as *mut i8),
405 device_id: device_id_c.as_ref().map_or(ptr::null_mut(), |c| c.as_ptr() as *mut i8),
406 hardware_id: hardware_id_c.as_ref().map_or(ptr::null_mut(), |c| c.as_ptr() as *mut i8),
407 compatible_id: compatible_id_c.as_ref().map_or(ptr::null_mut(), |c| c.as_ptr() as *mut i8),
408 upper_filter: upper_filter_c.as_ref().map_or(ptr::null_mut(), |c| c.as_ptr() as *mut i8),
409 driver_version: device.driver_version,
410 };
411
412 let mut opts = WdiOptionsPrepareDriver {
413 driver_type: options.driver_type.to_c_int(),
414 vendor_name: vendor_name_c.as_ref().map_or(ptr::null_mut(), |c| c.as_ptr() as *mut i8),
415 device_guid: device_guid_c.as_ref().map_or(ptr::null_mut(), |c| c.as_ptr() as *mut i8),
416 disable_cat: options.disable_cat as c_int,
417 disable_signing: options.disable_signing as c_int,
418 cert_subject: cert_subject_c.as_ref().map_or(ptr::null_mut(), |c| c.as_ptr() as *mut i8),
419 use_wcid_driver: options.use_wcid_driver as c_int,
420 external_inf: options.external_inf as c_int,
421 };
422
423 unsafe {
424 let result = wdi_prepare_driver(
425 &mut device_info,
426 path_c.as_ptr(),
427 inf_name_c.as_ptr(),
428 &mut opts,
429 );
430 Error::from_code(result)?;
431 }
432
433 Ok(())
434}
435
436#[derive(Debug, Clone)]
440pub struct InstallDriverOptions {
441 pub install_filter_driver: bool,
442 pub pending_install_timeout: u32,
445}
446
447impl InstallDriverOptions {
448 pub const DEFAULT_PENDING_INSTALL_TIMEOUT: u32 = 120000;
450}
451
452impl Default for InstallDriverOptions {
453 fn default() -> Self {
454 InstallDriverOptions {
455 install_filter_driver: false,
456 pending_install_timeout: Self::DEFAULT_PENDING_INSTALL_TIMEOUT,
457 }
458 }
459}
460
461pub fn install_driver(
475 device: &Device,
476 path: &str,
477 inf_name: &str,
478 options: &InstallDriverOptions,
479) -> Result<(), Error> {
480 let path_c = CString::new(path).map_err(|_| Error::InvalidParam)?;
481 let inf_name_c = CString::new(inf_name).map_err(|_| Error::InvalidParam)?;
482
483 let desc_c = device.desc.as_ref()
485 .and_then(|s| CString::new(s.as_str()).ok());
486 let driver_c = device.driver.as_ref()
487 .and_then(|s| CString::new(s.as_str()).ok());
488 let device_id_c = device.device_id.as_ref()
489 .and_then(|s| CString::new(s.as_str()).ok());
490 let hardware_id_c = device.hardware_id.as_ref()
491 .and_then(|s| CString::new(s.as_str()).ok());
492 let compatible_id_c = device.compatible_id.as_ref()
493 .and_then(|s| CString::new(s.as_str()).ok());
494 let upper_filter_c = device.upper_filter.as_ref()
495 .and_then(|s| CString::new(s.as_str()).ok());
496
497 let mut device_info = WdiDeviceInfo {
498 next: ptr::null_mut(),
499 vid: device.vid,
500 pid: device.pid,
501 is_composite: device.is_composite as c_int,
502 mi: device.mi,
503 desc: desc_c.as_ref().map_or(ptr::null_mut(), |c| c.as_ptr() as *mut i8),
504 driver: driver_c.as_ref().map_or(ptr::null_mut(), |c| c.as_ptr() as *mut i8),
505 device_id: device_id_c.as_ref().map_or(ptr::null_mut(), |c| c.as_ptr() as *mut i8),
506 hardware_id: hardware_id_c.as_ref().map_or(ptr::null_mut(), |c| c.as_ptr() as *mut i8),
507 compatible_id: compatible_id_c.as_ref().map_or(ptr::null_mut(), |c| c.as_ptr() as *mut i8),
508 upper_filter: upper_filter_c.as_ref().map_or(ptr::null_mut(), |c| c.as_ptr() as *mut i8),
509 driver_version: device.driver_version,
510 };
511
512 let mut opts = WdiOptionsInstallDriver {
513 hwnd: ptr::null_mut(),
514 install_filter_driver: options.install_filter_driver as c_int,
515 pending_install_timeout: options.pending_install_timeout,
516 };
517
518 unsafe {
519 let result = wdi_install_driver(
520 &mut device_info,
521 path_c.as_ptr(),
522 inf_name_c.as_ptr(),
523 &mut opts,
524 );
525 Error::from_code(result)?;
526 }
527
528 Ok(())
529}
530
531pub fn set_log_level(level: LogLevel) -> Result<(), Error> {
533 unsafe {
534 let result = wdi_set_log_level(level.into());
535 Error::from_code(result)
536 }
537}