A cross-platform Rust library for USB device communication on Windows, Linux, and macOS.
- Device enumeration — list connected USB devices with VID/PID, serial, manufacturer, and product strings
- Control transfers — typed
ControlSetupbuilder for IN/OUT control requests - Bulk & interrupt transfers — synchronous read/write with configurable timeout
- Isochronous transfers — enabled via the
isochronousfeature flag (Windows/WinUSB only) - Pipe management — query, reset, and abort pipes; get/set pipe policies (7 built-in policies)
- Descriptor reading — Device, Configuration, String, HID, BOS, Hub, SuperSpeed Endpoint Companion
- Async transfers — OVERLAPPED I/O backend with optional Tokio wrappers (
tokiofeature) - Hotplug detection —
CM_Register_Notificationon Windows; udev monitor on Linux; IOKit on macOS - Multi-interface support — per-interface endpoint cache via
HashMap
| Feature | Windows | Linux | macOS | Mock |
|---|---|---|---|---|
| Enumeration | ✅ WinUSB | ✅ udev | ✅ IOKit | ✅ In-memory |
| Control Transfers | ✅ | ✅ | ✅ | ✅ |
| Bulk/Interrupt | ✅ | ✅ | ✅ | ✅ |
| Isochronous | ✅ (isochronous) |
🚧 | 🚧 | ❌ |
| Hotplug | ✅ | ✅ | ✅ | ❌ |
| Async (Tokio) | ✅ (tokio) |
✅ | ✅ | ❌ |
Note
The async_transfers module (enabled via the tokio feature) requires a multi-threaded Tokio runtime because it utilizes tokio::task::block_in_place to bridge synchronous I/O.
Add to your Cargo.toml:
[dependencies]
rust-usb = "0.1"use rust_usb::UsbContext;
let ctx = UsbContext::new();
let devices = ctx.devices()?;
for device in devices {
println!("Device at {}: {:04x}:{:04x}", device.path, device.vendor_id, device.product_id);
}use std::time::Duration;
use rust_usb::UsbContext;
let ctx = UsbContext::new();
let mut handle = ctx.open("platform-specific-path")?;
// Interfaces must be claimed before performing pipe I/O
handle.claim_interface(0)?;
let mut buf = [0u8; 64];
let timeout = Duration::from_secs(1);
// Bulk Read from EP 0x81
let n = handle.bulk_read(0x81, &mut buf, timeout)?;
// Bulk Write to EP 0x01
handle.bulk_write(0x01, &buf[..n], timeout)?;use rust_usb::{UsbContext, HotplugEvent};
let ctx = UsbContext::new();
// The handle keeps the subscription alive; drop it to unregister
let _handle = ctx.register_hotplug(|event| {
match event {
HotplugEvent::DeviceArrived { path } => println!("Device arrived: {}", path),
HotplugEvent::DeviceLeft { path } => println!("Device removed: {}", path),
}
})?;Run the bundled example:
cargo run --example list_devicesSee DEVELOPMENT.md for architecture decisions, feature flag guidance, and platform-specific notes.
Contributions are welcome! Please read CONTRIBUTING.md and open an issue before submitting a PR.
Licensed under the MIT License.