From e0aa6bfbf686a7c4a2fb496da06cd9c7960ff9fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dav=C3=AD=C3=B0=20Steinn=20Geirsson?= Date: Wed, 25 Mar 2026 15:19:51 +0000 Subject: [PATCH] refactor: remove rusb backend, keep only nusb - Delete lib/examples/ (unused upstream leftovers) - Remove rusb crate dependency - Define local Direction enum in consts.rs (Out=0x00, In=0x80) - Remove RusbUsbHostInterfaceHandler and RusbUsbHostDeviceHandler - Replace rusb device enumeration with nusb in new_from_host* - Update flake.nix cargoHash and Cargo.lock Co-Authored-By: Claude Opus 4.6 (1M context) --- Cargo.lock | 58 ---------- flake.nix | 2 +- lib/Cargo.toml | 3 +- lib/examples/cdc_acm_serial.rs | 32 ------ lib/examples/hid_keyboard.rs | 45 -------- lib/examples/host.rs | 16 --- lib/src/consts.rs | 10 +- lib/src/device.rs | 18 --- lib/src/host.rs | 174 ---------------------------- lib/src/lib.rs | 202 +-------------------------------- lib/src/usbip_protocol.rs | 2 +- 11 files changed, 16 insertions(+), 546 deletions(-) delete mode 100644 lib/examples/cdc_acm_serial.rs delete mode 100644 lib/examples/hid_keyboard.rs delete mode 100644 lib/examples/host.rs diff --git a/Cargo.lock b/Cargo.lock index c72cab5..a500935 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,16 +103,6 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" -[[package]] -name = "cc" -version = "1.2.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" -dependencies = [ - "find-msvc-tools", - "shlex", -] - [[package]] name = "cfg-if" version = "1.0.4" @@ -220,12 +210,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - [[package]] name = "futures" version = "0.3.32" @@ -366,18 +350,6 @@ version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" -[[package]] -name = "libusb1-sys" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da050ade7ac4ff1ba5379af847a10a10a8e284181e060105bf8d86960ce9ce0f" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -525,12 +497,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - [[package]] name = "portable-atomic" version = "1.13.1" @@ -602,17 +568,6 @@ version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" -[[package]] -name = "rusb" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab9f9ff05b63a786553a4c02943b74b34a988448671001e9a27e2f0565cc05a4" -dependencies = [ - "libc", - "libusb1-sys", - "serde", -] - [[package]] name = "rustix" version = "1.1.4" @@ -662,12 +617,6 @@ dependencies = [ "syn", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -787,7 +736,6 @@ dependencies = [ "num-derive", "num-traits", "nusb", - "rusb", "serde", "tokio", "tokio-util", @@ -812,12 +760,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "vsock" version = "0.5.3" diff --git a/flake.nix b/flake.nix index fcbb8b5..24a7bf0 100644 --- a/flake.nix +++ b/flake.nix @@ -31,7 +31,7 @@ src = self; - cargoHash = "sha256-ol61Q+2IYDZ4ZvJiLYJdfqaN23thuZ1QHDOSvNXHhvY="; + cargoHash = "sha256-i2dRJ7n7J9K2PfjEUnIPS9pRXs61WUYYXAfJUmFxt/M="; inherit nativeBuildInputs buildInputs; diff --git a/lib/Cargo.toml b/lib/Cargo.toml index bd5cf2e..c507083 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -12,7 +12,6 @@ tokio = { version = "1.22.0", features = ["rt", "net", "io-util", "sync", "time" log = "0.4.17" num-traits = "0.2.15" num-derive = "0.4.2" -rusb = "0.9.3" serde = { version = "1.0", features = ["derive"], optional = true } nusb = { git = "https://git.dsg.is/dsg/nusb.git", rev = "c1380673" } tokio-util = { version = "0.7", features = ["rt"] } @@ -23,4 +22,4 @@ env_logger = "0.11.7" [features] default = [] -serde = ["dep:serde", "rusb/serde"] +serde = ["dep:serde"] diff --git a/lib/examples/cdc_acm_serial.rs b/lib/examples/cdc_acm_serial.rs deleted file mode 100644 index f3cea52..0000000 --- a/lib/examples/cdc_acm_serial.rs +++ /dev/null @@ -1,32 +0,0 @@ -use log::*; -use std::net::*; -use std::sync::Arc; -use std::time::Duration; - -#[tokio::main] -async fn main() { - env_logger::init(); - let handler = Arc::new(usbip_rs::cdc::UsbCdcAcmHandler::new()); - let server = Arc::new(usbip_rs::UsbIpServer::new_simulated(vec![ - usbip_rs::UsbDevice::new(0) - .expect("create device") - .with_interface( - usbip_rs::ClassCode::CDC as u8, - usbip_rs::cdc::CDC_ACM_SUBCLASS, - 0x00, - Some("Test CDC ACM"), - usbip_rs::cdc::UsbCdcAcmHandler::endpoints(), - handler.clone() as Arc, - ) - .expect("add interface"), - ])); - let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 3240); - tokio::spawn(usbip_rs::server(addr, server)); - - loop { - // sleep 1s - tokio::time::sleep(Duration::new(1, 0)).await; - handler.tx_buffer.lock().unwrap().push(b'a'); - info!("Simulate a char input"); - } -} diff --git a/lib/examples/hid_keyboard.rs b/lib/examples/hid_keyboard.rs deleted file mode 100644 index bc25682..0000000 --- a/lib/examples/hid_keyboard.rs +++ /dev/null @@ -1,45 +0,0 @@ -use log::*; -use std::net::*; -use std::sync::Arc; -use std::time::Duration; - -#[tokio::main] -async fn main() { - env_logger::init(); - let handler = Arc::new(usbip_rs::hid::UsbHidKeyboardHandler::new_keyboard()); - let server = Arc::new(usbip_rs::UsbIpServer::new_simulated(vec![ - usbip_rs::UsbDevice::new(0) - .expect("create device") - .with_interface( - usbip_rs::ClassCode::HID as u8, - 0x00, - 0x00, - Some("Test HID"), - vec![usbip_rs::UsbEndpoint { - address: 0x81, // IN - attributes: 0x03, // Interrupt - max_packet_size: 0x08, // 8 bytes - interval: 10, - ..Default::default() - }], - handler.clone() as Arc, - ) - .expect("add interface"), - ])); - let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 3240); - tokio::spawn(usbip_rs::server(addr, server)); - - loop { - // sleep 1s - tokio::time::sleep(Duration::new(1, 0)).await; - match usbip_rs::hid::UsbHidKeyboardReport::from_ascii(b'1') { - Ok(report) => { - handler.pending_key_events.lock().unwrap().push_back(report); - info!("Simulate a key event"); - } - Err(e) => { - error!("Failed to create key report: {}", e); - } - } - } -} diff --git a/lib/examples/host.rs b/lib/examples/host.rs deleted file mode 100644 index ef407e1..0000000 --- a/lib/examples/host.rs +++ /dev/null @@ -1,16 +0,0 @@ -use std::net::*; -use std::sync::Arc; -use std::time::Duration; - -#[tokio::main] -async fn main() { - env_logger::init(); - let server = Arc::new(usbip_rs::UsbIpServer::new_from_host()); - let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 3240); - tokio::spawn(usbip_rs::server(addr, server)); - - loop { - // sleep 1s - tokio::time::sleep(Duration::new(1, 0)).await; - } -} diff --git a/lib/src/consts.rs b/lib/src/consts.rs index d101e74..a3ca03d 100644 --- a/lib/src/consts.rs +++ b/lib/src/consts.rs @@ -52,9 +52,13 @@ pub enum EndpointAttributes { Interrupt, } -/// USB endpoint direction: IN or OUT -/// Already exists in rusb crate -pub use rusb::Direction; +/// USB endpoint direction (bit 7 of endpoint address) +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum Direction { + Out = 0x00, + In = 0x80, +} /// Emulated max packet size of EP0 pub const EP0_MAX_PACKET_SIZE: u16 = 64; diff --git a/lib/src/device.rs b/lib/src/device.rs index 001e42d..7b14dd8 100644 --- a/lib/src/device.rs +++ b/lib/src/device.rs @@ -1,6 +1,4 @@ use super::*; -use rusb::Version as rusbVersion; - #[derive(Clone, Default, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Version { @@ -9,22 +7,6 @@ pub struct Version { pub patch: u8, } -impl From for Version { - fn from(value: rusbVersion) -> Self { - Self { - major: value.major(), - minor: value.minor(), - patch: value.sub_minor(), - } - } -} - -impl From for rusbVersion { - fn from(val: Version) -> Self { - rusbVersion(val.major, val.minor, val.patch) - } -} - /// bcdDevice impl From for Version { fn from(value: u16) -> Self { diff --git a/lib/src/host.rs b/lib/src/host.rs index a58986f..9c21d77 100644 --- a/lib/src/host.rs +++ b/lib/src/host.rs @@ -17,180 +17,6 @@ pub fn nusb_speed_to_linux(speed: nusb::Speed) -> u32 { } } -/// A handler to pass requests to interface of a rusb USB device of the host -#[derive(Clone, Debug)] -pub struct RusbUsbHostInterfaceHandler { - handle: Arc>>, -} - -impl RusbUsbHostInterfaceHandler { - pub fn new(handle: Arc>>) -> Self { - Self { handle } - } -} - -impl UsbInterfaceHandler for RusbUsbHostInterfaceHandler { - fn handle_urb( - &self, - _interface: &UsbInterface, - request: UrbRequest, - ) -> Result { - let ep = request.ep.clone(); - let transfer_buffer_length = request.transfer_buffer_length; - let setup = request.setup; - let req = &request.data; - debug!("To host device: ep={ep:?} setup={setup:?} req={req:?}",); - let mut buffer = vec![0u8; transfer_buffer_length as usize]; - let timeout = std::time::Duration::new(1, 0); - let handle = self.handle.lock().unwrap_or_else(|e| e.into_inner()); - if ep.transfer_type() == Some(EndpointAttributes::Control) { - // control - if let Direction::In = ep.direction() { - // control in - if let Ok(len) = handle.read_control( - setup.request_type, - setup.request, - setup.value, - setup.index, - &mut buffer, - timeout, - ) { - return Ok(UrbResponse { data: Vec::from(&buffer[..len]), ..Default::default() }); - } - } else { - // control out - handle - .write_control( - setup.request_type, - setup.request, - setup.value, - setup.index, - req, - timeout, - ) - .map_err(|e| { - std::io::Error::new( - std::io::ErrorKind::Other, - format!("USB control OUT failed: {e}"), - ) - })?; - } - } else if ep.transfer_type() == Some(EndpointAttributes::Interrupt) { - // interrupt - if let Direction::In = ep.direction() { - // interrupt in - if let Ok(len) = handle.read_interrupt(ep.address, &mut buffer, timeout) { - info!("intr in {:?}", &buffer[..len]); - return Ok(UrbResponse { data: Vec::from(&buffer[..len]), ..Default::default() }); - } - } else { - // interrupt out - handle - .write_interrupt(ep.address, req, timeout) - .map_err(|e| { - std::io::Error::new( - std::io::ErrorKind::Other, - format!("USB interrupt OUT failed: {e}"), - ) - })?; - } - } else if ep.transfer_type() == Some(EndpointAttributes::Bulk) { - // bulk - if let Direction::In = ep.direction() { - // bulk in - if let Ok(len) = handle.read_bulk(ep.address, &mut buffer, timeout) { - return Ok(UrbResponse { data: Vec::from(&buffer[..len]), ..Default::default() }); - } - } else { - // bulk out - handle.write_bulk(ep.address, req, timeout).map_err(|e| { - std::io::Error::new( - std::io::ErrorKind::Other, - format!("USB bulk OUT failed: {e}"), - ) - })?; - } - } else if ep.transfer_type() == Some(EndpointAttributes::Isochronous) { - return Err(std::io::Error::new( - std::io::ErrorKind::Unsupported, - "isochronous transfers not supported on rusb handler", - )); - } - Ok(UrbResponse::default()) - } - - fn get_class_specific_descriptor(&self) -> Vec { - vec![] - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -/// A handler to pass requests to device of a rusb USB device of the host -#[derive(Clone, Debug)] -pub struct RusbUsbHostDeviceHandler { - handle: Arc>>, -} - -impl RusbUsbHostDeviceHandler { - pub fn new(handle: Arc>>) -> Self { - Self { handle } - } -} - -impl UsbDeviceHandler for RusbUsbHostDeviceHandler { - fn handle_urb( - &mut self, - request: UrbRequest, - ) -> Result { - let transfer_buffer_length = request.transfer_buffer_length; - let setup = request.setup; - let req = &request.data; - debug!("To host device: setup={setup:?} req={req:?}"); - let mut buffer = vec![0u8; transfer_buffer_length as usize]; - let timeout = std::time::Duration::new(1, 0); - let handle = self.handle.lock().unwrap_or_else(|e| e.into_inner()); - // control - if setup.request_type & 0x80 == 0 { - // control out - handle - .write_control( - setup.request_type, - setup.request, - setup.value, - setup.index, - req, - timeout, - ) - .map_err(|e| { - std::io::Error::new( - std::io::ErrorKind::Other, - format!("USB control OUT failed: {e}"), - ) - })?; - } else { - // control in - if let Ok(len) = handle.read_control( - setup.request_type, - setup.request, - setup.value, - setup.index, - &mut buffer, - timeout, - ) { - return Ok(UrbResponse { data: Vec::from(&buffer[..len]), ..Default::default() }); - } - } - Ok(UrbResponse::default()) - } - - fn as_any(&self) -> &dyn Any { - self - } -} - /// A handler to pass requests to interface of a nusb USB device of the host #[derive(Clone)] pub struct NusbUsbHostInterfaceHandler { diff --git a/lib/src/lib.rs b/lib/src/lib.rs index a1cf5e5..7875d88 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -4,7 +4,6 @@ use log::*; use num_derive::FromPrimitive; use num_traits::FromPrimitive; use nusb::MaybeFuture; -use rusb::*; use std::any::Any; use std::collections::{HashMap, VecDeque}; use std::io::{ErrorKind, Result}; @@ -187,210 +186,21 @@ impl UsbIpServer { devices } - /// Create a [UsbIpServer] with Vec<[rusb::DeviceHandle]> for sharing host devices - pub fn with_rusb_device_handles( - device_handles: Vec>, - ) -> Vec { - let mut devices = vec![]; - for open_device in device_handles { - let dev = open_device.device(); - let desc = match dev.device_descriptor() { - Ok(desc) => desc, - Err(err) => { - warn!( - "Impossible to get device descriptor for {dev:?}: {err}, ignoring device", - ); - continue; - } - }; - let cfg = match dev.active_config_descriptor() { - Ok(desc) => desc, - Err(err) => { - warn!( - "Impossible to get config descriptor for {dev:?}: {err}, ignoring device", - ); - continue; - } - }; - - let handle = Arc::new(Mutex::new(open_device)); - let mut interface_states = vec![]; - handle - .lock() - .unwrap() - .set_auto_detach_kernel_driver(true) - .ok(); - for intf in cfg.interfaces() { - // ignore alternate settings - let intf_desc = intf.descriptors().next().unwrap(); - handle - .lock() - .unwrap() - .set_auto_detach_kernel_driver(true) - .ok(); - let mut endpoints = vec![]; - - for ep_desc in intf_desc.endpoint_descriptors() { - endpoints.push(UsbEndpoint { - address: ep_desc.address(), - attributes: ep_desc.transfer_type() as u8, - max_packet_size: ep_desc.max_packet_size(), - interval: ep_desc.interval(), - ..Default::default() - }); - } - - let handler: Arc = Arc::new( - RusbUsbHostInterfaceHandler::new(handle.clone()), - ); - interface_states.push(InterfaceState::new(UsbInterface { - interface_class: intf_desc.class_code(), - interface_subclass: intf_desc.sub_class_code(), - interface_protocol: intf_desc.protocol_code(), - endpoints, - string_interface: intf_desc.description_string_index().unwrap_or(0), - class_specific_descriptor: Vec::from(intf_desc.extra()), - handler, - })); - } - let mut device = UsbDevice { - path: format!( - "/sys/bus/{}/{}/{}", - dev.bus_number(), - dev.address(), - dev.port_number() - ), - bus_id: format!( - "{}-{}-{}", - dev.bus_number(), - dev.address(), - dev.port_number() - ), - bus_num: dev.bus_number() as u32, - dev_num: dev.port_number() as u32, - speed: dev.speed() as u32, - vendor_id: desc.vendor_id(), - product_id: desc.product_id(), - device_class: desc.class_code(), - device_subclass: desc.sub_class_code(), - device_protocol: desc.protocol_code(), - device_bcd: desc.device_version().into(), - configuration_value: cfg.number(), - num_configurations: desc.num_configurations(), - ep0_in: UsbEndpoint { - address: 0x80, - attributes: EndpointAttributes::Control as u8, - max_packet_size: desc.max_packet_size() as u16, - ..Default::default() - }, - ep0_out: UsbEndpoint { - address: 0x00, - attributes: EndpointAttributes::Control as u8, - max_packet_size: desc.max_packet_size() as u16, - ..Default::default() - }, - interface_states, - device_handler: Some(Arc::new(Mutex::new(Box::new( - RusbUsbHostDeviceHandler::new(handle.clone()), - )))), - usb_version: desc.usb_version().into(), - ..UsbDevice::default() - }; - - // set strings - if let Some(index) = desc.manufacturer_string_index() { - match handle - .lock() - .unwrap() - .read_string_descriptor_ascii(index) - { - Ok(s) => match device.new_string(&s) { - Ok(idx) => device.string_manufacturer = idx, - Err(err) => { - warn!("Failed to set manufacturer string: {err}"); - continue; - } - }, - Err(err) => { - warn!("Failed to read manufacturer string: {err}"); - } - } - } - if let Some(index) = desc.product_string_index() { - match handle - .lock() - .unwrap() - .read_string_descriptor_ascii(index) - { - Ok(s) => match device.new_string(&s) { - Ok(idx) => device.string_product = idx, - Err(err) => { - warn!("Failed to set product string: {err}"); - continue; - } - }, - Err(err) => { - warn!("Failed to read product string: {err}"); - } - } - } - if let Some(index) = desc.serial_number_string_index() { - match handle - .lock() - .unwrap() - .read_string_descriptor_ascii(index) - { - Ok(s) => match device.new_string(&s) { - Ok(idx) => device.string_serial = idx, - Err(err) => { - warn!("Failed to set serial string: {err}"); - continue; - } - }, - Err(err) => { - warn!("Failed to read serial string: {err}"); - } - } - } - devices.push(device); - } - devices - } - - fn with_rusb_devices(device_list: Vec>) -> Vec { - let mut device_handles = vec![]; - - for dev in device_list { - let open_device = match dev.open() { - Ok(dev) => dev, - Err(err) => { - warn!("Impossible to share {dev:?}: {err}, ignoring device"); - continue; - } - }; - device_handles.push(open_device); - } - Self::with_rusb_device_handles(device_handles) - } - - /// Create a [UsbIpServer] exposing devices in the host, and redirect all USB transfers to them using libusb + /// Create a [UsbIpServer] exposing devices in the host using nusb pub fn new_from_host() -> Self { Self::new_from_host_with_filter(|_| true) } - /// Create a [UsbIpServer] exposing filtered devices in the host, and redirect all USB transfers to them using libusb + /// Create a [UsbIpServer] exposing filtered devices in the host using nusb pub fn new_from_host_with_filter(filter: F) -> Self where - F: FnMut(&Device) -> bool, + F: FnMut(&nusb::DeviceInfo) -> bool, { - match rusb::devices() { + match nusb::list_devices().wait() { Ok(list) => { - let mut devs = vec![]; - for d in list.iter().filter(filter) { - devs.push(d) - } + let devs: Vec<_> = list.filter(filter).collect(); Self { - available_devices: RwLock::new(Self::with_rusb_devices(devs)), + available_devices: RwLock::new(Self::with_nusb_devices(devs)), ..Default::default() } } diff --git a/lib/src/usbip_protocol.rs b/lib/src/usbip_protocol.rs index be8142a..9f2cc94 100644 --- a/lib/src/usbip_protocol.rs +++ b/lib/src/usbip_protocol.rs @@ -46,7 +46,7 @@ pub const USBIP_RET_UNLINK: u16 = 0x0004; /// USB/IP direction /// -/// NOTE: Must not be confused with rusb::Direction, +/// NOTE: Must not be confused with the public Direction enum in consts.rs, /// which has the opposite enum values. This is only for /// internal use in the USB/IP protocol. #[derive(Debug, Clone, Copy, PartialEq, Eq)]