diff --git a/src/device.rs b/src/device.rs index b5f57aa..a357af4 100644 --- a/src/device.rs +++ b/src/device.rs @@ -3,7 +3,6 @@ use std::time::Duration; use log::info; -use rusb::{DeviceHandle, UsbContext}; use crate::{ commands::{control::ProbeInfo, ChipUID, RawCommand, Response}, @@ -146,7 +145,7 @@ impl WchLink { /// Switch from DAP mode to RV mode // ref: https://github.com/cjacker/wchlinke-mode-switch/blob/main/main.c pub fn try_switch_from_rv_to_dap(nth: usize) -> Result<()> { - let mut dev = USB::open_nth(VENDOR_ID, PRODUCT_ID, nth)?; + let dev = USB::open_nth(VENDOR_ID, PRODUCT_ID, nth)?; info!("Switch mode for WCH-LinkRV"); let mut dev = WchLink { @@ -182,17 +181,12 @@ pub fn try_switch_from_dap_to_rv(nth: usize) -> Result<() } /// Check connected USB device -pub fn check_usb_device() -> Result<()> { - let context = rusb::Context::new()?; - log::trace!("Acquired libusb context."); - - for device in context.devices()?.iter() { - let desc = device.device_descriptor()?; - if desc.vendor_id() == VENDOR_ID && desc.product_id() == PRODUCT_ID { - log::info!("Found WCH-LinkRV, {:?}", device); - } else if desc.vendor_id() == VENDOR_ID_DAP && desc.product_id() == PRODUCT_ID_DAP { - log::info!("Found WCH-LinkDAP, {:?}", device); - } +pub fn check_all_devices() -> Result<()> { + for dev in usb_device::list_devices(VENDOR_ID, PRODUCT_ID)? { + log::info!("Found WCH-LinkRV, {:?}", dev); + } + for dev in usb_device::list_devices(VENDOR_ID_DAP, PRODUCT_ID_DAP)? { + log::info!("Found WCH-LinkDAP, {:?}", dev); } Ok(()) diff --git a/src/main.rs b/src/main.rs index c4d46c8..91b9a94 100644 --- a/src/main.rs +++ b/src/main.rs @@ -180,12 +180,12 @@ fn main() -> Result<()> { match cli.command { None => { - wlink::device::check_usb_device()?; + wlink::device::check_all_devices()?; println!("No command given, use --help for help."); println!("hint: use `wlink status` to get started."); } Some(ModeSwitch { rv, dap }) => { - wlink::device::check_usb_device()?; // list all connected devices + wlink::device::check_all_devices()?; // list all connected devices log::warn!("This is an experimental feature, better use the WCH-LinkUtility!"); if !(rv ^ dap) { println!("Please choose one mode to switch, either --rv or --dap"); diff --git a/src/usb_device.rs b/src/usb_device.rs index 9a4c9ef..2a10913 100644 --- a/src/usb_device.rs +++ b/src/usb_device.rs @@ -15,6 +15,18 @@ pub trait USBDeviceBackend { fn write_endpoint(&mut self, ep: u8, buf: &[u8]) -> Result<()>; } +pub fn open_nth(vid: u16, pid: u16, nth: usize) -> Result> { + #[cfg(all(target_os = "windows", target_arch = "x86"))] + { + ch375_driver::USBDevice::open_nth(vid, pid, nth) + .or_else(|_| libusb::USBDevice::open_nth(vid, pid, nth)) + } + #[cfg(not(all(target_os = "windows", target_arch = "x86")))] + { + libusb::USBDevice::open_nth(vid, pid, nth) + } +} + pub fn list_devices(vid: u16, pid: u16) -> Result> { let mut ret = vec![]; ret.extend( @@ -23,12 +35,20 @@ pub fn list_devices(vid: u16, pid: u16) -> Result> { .map(|s| s.to_string()), ); + #[cfg(all(target_os = "windows", target_arch = "x86"))] + { + ret.extend( + ch375_driver::list_devices(vid, pid)? + .into_iter() + .map(|s| s.to_string()), + ); + } + Ok(ret) } -// pub use libusb::USBDevice; - -pub use ch375_driver::USBDevice; +pub use libusb::USBDevice; +// pub use ch375_driver::USBDevice; mod libusb { use super::*; @@ -126,6 +146,7 @@ mod libusb { } } +#[cfg(all(target_os = "windows", target_arch = "x86"))] mod ch375_driver { use libloading::os::windows::*; @@ -179,6 +200,38 @@ mod ch375_driver { bNumConfigurations: u8, } + pub fn list_devices(vid: u16, pid: u16) -> Result> { + let lib = ensure_library_load()?; + let mut ret: Vec = vec![]; + + let open_device: Symbol u32> = + unsafe { lib.get(b"CH375OpenDevice").unwrap() }; + let close_device: Symbol = + unsafe { lib.get(b"CH375CloseDevice").unwrap() }; + let get_device_descriptor: Symbol< + unsafe extern "stdcall" fn(u32, *mut UsbDeviceDescriptor, *mut u32) -> bool, + > = unsafe { lib.get(b"CH375GetDeviceDescr").unwrap() }; + + const INVALID_HANDLE: u32 = 0xffffffff; + + for i in 0..8 { + let h = unsafe { open_device(i) }; + if h != INVALID_HANDLE { + let mut descr = unsafe { core::mem::zeroed() }; + let mut len = core::mem::size_of::() as u32; + let _ = unsafe { get_device_descriptor(i, &mut descr, &mut len) }; + let vid = descr.idVendor; + let pid = descr.idProduct; + + log::debug!("Device #{}: {:04x}:{:04x}", i, vid, pid); + if vid == vid && pid == pid { + ret.push(format!(" {:04x}:{:04x}", i, vid, pid)); + } + unsafe { close_device(i) }; + } + } + } + pub struct USBDevice { index: u32, }