Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions rockusb/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rockusb"
version = "0.3.0"
version = "0.4.0"
edition = "2024"
authors = ["Sjoerd Simons <sjoerd@collabora.com>"]
license = "MIT OR Apache-2.0"
Expand All @@ -23,7 +23,7 @@ fastrand = "2"
num_enum = "0.7"
thiserror = "2.0.7"
rusb = { version = "0.9.4", optional = true }
nusb = { version = "0.1.10", optional = true }
nusb = { version = "0.2.1", optional = true }
futures = { version = "0.3.31", optional = true }
maybe-async-cfg = "0.2.5"

Expand Down
4 changes: 2 additions & 2 deletions rockusb/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ Printing chip info using nusb backend:
# #[cfg(feature = "nusb")] {
# #[tokio::main]
# async fn main() -> anyhow::Result<()> {
let mut devices = rockusb::nusb::devices()?;
let mut devices = rockusb::nusb::devices().await?;
let info = devices.next()
.ok_or_else(|| anyhow::anyhow!("No Device found"))?;
let mut device = rockusb::nusb::Device::from_usb_device_info(info)?;
let mut device = rockusb::nusb::Device::from_usb_device_info(info).await?;
println!("Chip Info: {:0x?}", device.chip_info().await?);
Ok(())
# }
Expand Down
16 changes: 8 additions & 8 deletions rockusb/examples/rockusb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use clap::Parser;
use common::{Command, ExampleDeviceAsync, Opts};
use rockusb::nusb::Device;

fn list_available_devices() -> Result<()> {
let devices = rockusb::nusb::devices()?;
async fn list_available_devices() -> Result<()> {
let devices = rockusb::nusb::devices().await?;
println!("Available rockchip devices:");
for d in devices {
println!(
"* Bus {} Device {} ID {}:{}",
d.bus_number(),
d.busnum(),
d.device_address(),
d.vendor_id(),
d.product_id()
Expand All @@ -27,13 +27,13 @@ async fn main() -> Result<()> {

// Commands that don't talk a device
if matches!(opt.command, Command::List) {
return list_available_devices();
return list_available_devices().await;
}

let mut devices = rockusb::nusb::devices()?;
let mut devices = rockusb::nusb::devices().await?;
let info = if let Some(dev) = opt.device {
devices
.find(|d| d.bus_number() == dev.bus_number && d.device_address() == dev.address)
.find(|d| d.busnum() == dev.bus_number && d.device_address() == dev.address)
.ok_or_else(|| anyhow!("Specified device not found"))?
} else {
let mut devices: Vec<_> = devices.collect();
Expand All @@ -42,7 +42,7 @@ async fn main() -> Result<()> {
1 => Ok(devices.pop().unwrap()),
_ => {
drop(devices);
let _ = list_available_devices();
let _ = list_available_devices().await;
println!();
Err(anyhow!(
"Please select a specific device using the -d option"
Expand All @@ -51,7 +51,7 @@ async fn main() -> Result<()> {
}?
};

let device = Device::from_usb_device_info(info)?;
let device = Device::from_usb_device_info(info).await?;
let device = ExampleDeviceAsync::new(device);
opt.command.run_async(device).await
}
110 changes: 62 additions & 48 deletions rockusb/src/nusb.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
use std::time::Duration;

use crate::operation::{OperationSteps, UsbStep};
pub use nusb::transfer::TransferError;
use nusb::{
DeviceInfo,
transfer::{ControlOut, ControlType, Recipient, RequestBuffer},
transfer::{Buffer, Bulk, ControlOut, ControlType, In, Out, Recipient},
};
use thiserror::Error;

/// Error indicate a device is not available
#[derive(Debug, Error)]
#[error("Device is not available: {error}")]
pub struct DeviceUnavalable {
#[from]
pub error: nusb::Error,
pub enum DeviceUnavalable {
#[error("Device is not available: {0}")]
UsbError(#[from] nusb::Error),
#[error("Device not found")]
NotFound,
}

impl DeviceUnavalable {
/// Create a "not found" error
pub fn not_found() -> Self {
DeviceUnavalable::NotFound
}
}

/// List rockchip devices
pub fn devices() -> std::result::Result<impl Iterator<Item = DeviceInfo>, nusb::Error> {
Ok(nusb::list_devices()?.filter(|d| d.vendor_id() == 0x2207))
pub async fn devices() -> std::result::Result<impl Iterator<Item = DeviceInfo>, nusb::Error> {
Ok(nusb::list_devices()
.await?
.filter(|d| d.vendor_id() == 0x2207))
}

impl From<TransferError> for crate::device::Error<TransferError> {
Expand All @@ -28,8 +40,8 @@ impl From<TransferError> for crate::device::Error<TransferError> {
/// nusb based Transport for rockusb operation
pub struct Transport {
interface: nusb::Interface,
ep_in: u8,
ep_out: u8,
ep_in: nusb::Endpoint<Bulk, In>,
ep_out: nusb::Endpoint<Bulk, Out>,
}

impl crate::device::TransportAsync for Transport {
Expand All @@ -41,24 +53,28 @@ impl crate::device::TransportAsync for Transport {
where
O: OperationSteps<T>,
{
// Default timeout for USB operations
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(5);

loop {
let step = operation.step();
match step {
UsbStep::WriteBulk { data } => {
let _written = self
.interface
.bulk_out(self.ep_out, data.to_vec())
.await
.into_result()?;
let buf: Buffer = data.to_vec().into();
self.ep_out.submit(buf);
let completion = self.ep_out.next_complete().await;
completion.into_result()?;
}
UsbStep::ReadBulk { data } => {
let req = RequestBuffer::new(data.len());
let read = self
.interface
.bulk_in(self.ep_in, req)
.await
.into_result()?;
data.copy_from_slice(&read);
// For IN transfers, requested_len must be a multiple of max_packet_size
let max_packet_size = self.ep_in.max_packet_size();
let requested_len = data.len().next_multiple_of(max_packet_size);
let buf = Buffer::new(requested_len);
self.ep_in.submit(buf);
let completion = self.ep_in.next_complete().await;
let result_buf = completion.into_result()?;
let copy_len = data.len().min(result_buf.len());
data[..copy_len].copy_from_slice(&result_buf[..copy_len]);
}
UsbStep::WriteControl {
request_type,
Expand Down Expand Up @@ -90,7 +106,7 @@ impl crate::device::TransportAsync for Transport {
index,
data,
};
self.interface.control_out(data).await.into_result()?;
self.interface.control_out(data, DEFAULT_TIMEOUT).await?;
}
UsbStep::Finished(r) => break r.map_err(|e| e.into()),
}
Expand All @@ -100,55 +116,53 @@ impl crate::device::TransportAsync for Transport {

impl Transport {
fn new(
device: nusb::Device,
interface: u8,
ep_in: u8,
ep_out: u8,
) -> std::result::Result<Self, DeviceUnavalable> {
let interface = device.claim_interface(interface)?;
Ok(Self {
interface: nusb::Interface,
ep_in: nusb::Endpoint<Bulk, In>,
ep_out: nusb::Endpoint<Bulk, Out>,
) -> Self {
Self {
interface,
ep_in,
ep_out,
})
}
}
}

pub type Device = crate::device::DeviceAsync<Transport>;
impl Device {
/// Create a new transport from a device info
pub fn from_usb_device_info(
pub async fn from_usb_device_info(
info: nusb::DeviceInfo,
) -> std::result::Result<Self, DeviceUnavalable> {
let device = info.open()?;
Self::from_usb_device(device)
let device = info.open().await?;
Self::from_usb_device(device).await
}

/// Create a new transport from an existing device
pub fn from_usb_device(device: nusb::Device) -> std::result::Result<Self, DeviceUnavalable> {
pub async fn from_usb_device(
device: nusb::Device,
) -> std::result::Result<Self, DeviceUnavalable> {
for config in device.clone().configurations() {
for interface in config.interface_alt_settings() {
let output = interface.endpoints().find(|e| {
for iface_setting in config.interface_alt_settings() {
let output = iface_setting.endpoints().find(|e| {
e.direction() == nusb::transfer::Direction::Out
&& e.transfer_type() == nusb::transfer::EndpointType::Bulk
&& e.transfer_type() == nusb::descriptors::TransferType::Bulk
});
let input = interface.endpoints().find(|e| {
let input = iface_setting.endpoints().find(|e| {
e.direction() == nusb::transfer::Direction::In
&& e.transfer_type() == nusb::transfer::EndpointType::Bulk
&& e.transfer_type() == nusb::descriptors::TransferType::Bulk
});

if let (Some(input), Some(output)) = (input, output) {
return Ok(Device::new(Transport::new(
device,
interface.interface_number(),
input.address(),
output.address(),
)?));
let interface = device
.claim_interface(iface_setting.interface_number())
.await?;
let ep_in = interface.endpoint::<Bulk, In>(input.address())?;
let ep_out = interface.endpoint::<Bulk, Out>(output.address())?;
return Ok(Device::new(Transport::new(interface, ep_in, ep_out)));
}
}
}
Err(DeviceUnavalable {
error: nusb::Error::new(std::io::ErrorKind::NotFound, "Device not found"),
})
Err(DeviceUnavalable::not_found())
}
}