Add initial nusb support for #54

This commit is contained in:
Jiajie Chen 2024-10-26 10:16:04 +08:00
parent af17fc2243
commit 9c1efa1dd3
3 changed files with 148 additions and 12 deletions

View file

@ -16,6 +16,7 @@ num-traits = "0.2.15"
num-derive = "0.3.3"
rusb = "0.9.3"
serde = { version = "1.0", features = ["derive"], optional = true }
nusb = "0.1.10"
[dev-dependencies]
tokio = { version = "1.22.0", features = ["full"] }

View file

@ -1,19 +1,19 @@
//! Host USB
use super::*;
/// A handler to pass requests to a USB device of the host
/// A handler to pass requests to a rusb USB device of the host
#[derive(Clone)]
pub struct UsbHostInterfaceHandler {
pub struct RusbUsbHostInterfaceHandler {
handle: Arc<Mutex<DeviceHandle<GlobalContext>>>,
}
impl UsbHostInterfaceHandler {
impl RusbUsbHostInterfaceHandler {
pub fn new(handle: Arc<Mutex<DeviceHandle<GlobalContext>>>) -> Self {
Self { handle }
}
}
impl UsbInterfaceHandler for UsbHostInterfaceHandler {
impl UsbInterfaceHandler for RusbUsbHostInterfaceHandler {
fn handle_urb(
&mut self,
_interface: &UsbInterface,
@ -94,17 +94,17 @@ impl UsbInterfaceHandler for UsbHostInterfaceHandler {
/// A handler to pass requests to a USB device of the host
#[derive(Clone)]
pub struct UsbHostDeviceHandler {
pub struct RusbUsbHostDeviceHandler {
handle: Arc<Mutex<DeviceHandle<GlobalContext>>>,
}
impl UsbHostDeviceHandler {
impl RusbUsbHostDeviceHandler {
pub fn new(handle: Arc<Mutex<DeviceHandle<GlobalContext>>>) -> Self {
Self { handle }
}
}
impl UsbDeviceHandler for UsbHostDeviceHandler {
impl UsbDeviceHandler for RusbUsbHostDeviceHandler {
fn handle_urb(
&mut self,
transfer_buffer_length: u32,
@ -148,3 +148,138 @@ impl UsbDeviceHandler for UsbHostDeviceHandler {
self
}
}
/// A handler to pass requests to a rusb USB device of the host
#[derive(Clone)]
pub struct NusbUsbHostInterfaceHandler {
handle: Arc<Mutex<nusb::Interface>>,
}
impl NusbUsbHostInterfaceHandler {
pub fn new(handle: Arc<Mutex<nusb::Interface>>) -> Self {
Self { handle }
}
}
impl UsbInterfaceHandler for NusbUsbHostInterfaceHandler {
fn handle_urb(
&mut self,
_interface: &UsbInterface,
ep: UsbEndpoint,
transfer_buffer_length: u32,
setup: SetupPacket,
req: &[u8],
) -> Result<Vec<u8>> {
debug!(
"To host device: ep={:?} setup={:?} req={:?}",
ep, setup, 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();
let control = nusb::transfer::Control {
control_type: match (setup.request_type >> 5) & 0b11 {
0 => nusb::transfer::ControlType::Standard,
1 => nusb::transfer::ControlType::Class,
2 => nusb::transfer::ControlType::Vendor,
_ => unimplemented!(),
},
recipient: match setup.request_type & 0b11111 {
0 => nusb::transfer::Recipient::Device,
1 => nusb::transfer::Recipient::Interface,
2 => nusb::transfer::Recipient::Endpoint,
3 => nusb::transfer::Recipient::Other,
_ => unimplemented!(),
},
request: setup.request,
value: setup.value,
index: setup.index,
};
if ep.attributes == EndpointAttributes::Control as u8 {
// control
if let Direction::In = ep.direction() {
// control in
if let Ok(len) = handle.control_in_blocking(control, &mut buffer, timeout) {
return Ok(Vec::from(&buffer[..len]));
}
} else {
// control out
handle.control_out_blocking(control, req, timeout).ok();
}
} else if ep.attributes == EndpointAttributes::Interrupt as u8 {
// interrupt
todo!("Missing blocking api for interrupt transfer in nusb")
} else if ep.attributes == EndpointAttributes::Bulk as u8 {
// bulk
todo!("Missing blocking api for bulk transfer in nusb")
}
Ok(vec![])
}
fn get_class_specific_descriptor(&self) -> Vec<u8> {
vec![]
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
}
/// A handler to pass requests to a USB device of the host
#[derive(Clone)]
pub struct NusbUsbHostDeviceHandler {
handle: Arc<Mutex<nusb::Device>>,
}
impl NusbUsbHostDeviceHandler {
pub fn new(handle: Arc<Mutex<nusb::Device>>) -> Self {
Self { handle }
}
}
impl UsbDeviceHandler for NusbUsbHostDeviceHandler {
fn handle_urb(
&mut self,
transfer_buffer_length: u32,
setup: SetupPacket,
req: &[u8],
) -> Result<Vec<u8>> {
debug!("To host device: setup={:?} req={:?}", setup, 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();
let control = nusb::transfer::Control {
control_type: match (setup.request_type >> 5) & 0b11 {
0 => nusb::transfer::ControlType::Standard,
1 => nusb::transfer::ControlType::Class,
2 => nusb::transfer::ControlType::Vendor,
_ => unimplemented!(),
},
recipient: match setup.request_type & 0b11111 {
0 => nusb::transfer::Recipient::Device,
1 => nusb::transfer::Recipient::Interface,
2 => nusb::transfer::Recipient::Endpoint,
3 => nusb::transfer::Recipient::Other,
_ => unimplemented!(),
},
request: setup.request,
value: setup.value,
index: setup.index,
};
// control
if setup.request_type & 0x80 == 0 {
// control out
handle.control_out_blocking(control, req, timeout).ok();
} else {
// control in
if let Ok(len) = handle.control_in_blocking(control, &mut buffer, timeout) {
return Ok(Vec::from(&buffer[..len]));
}
}
Ok(vec![])
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
}

View file

@ -54,7 +54,7 @@ impl UsbIpServer {
}
}
/// Create a [UsbIpServer] with Vec<[rusb::DeviceHandle]>
/// Create a [UsbIpServer] with Vec<[rusb::DeviceHandle]> for sharing host devices
pub fn with_device_handles(device_handles: Vec<DeviceHandle<GlobalContext>>) -> Vec<UsbDevice> {
let mut devices = vec![];
for open_device in device_handles {
@ -106,7 +106,7 @@ impl UsbIpServer {
});
}
let handler = Arc::new(Mutex::new(Box::new(UsbHostInterfaceHandler::new(
let handler = Arc::new(Mutex::new(Box::new(RusbUsbHostInterfaceHandler::new(
handle.clone(),
))
as Box<dyn UsbInterfaceHandler + Send>));
@ -157,9 +157,9 @@ impl UsbIpServer {
interval: 0,
},
interfaces,
device_handler: Some(Arc::new(Mutex::new(Box::new(UsbHostDeviceHandler::new(
handle.clone(),
))))),
device_handler: Some(Arc::new(Mutex::new(Box::new(
RusbUsbHostDeviceHandler::new(handle.clone()),
)))),
usb_version: desc.usb_version().into(),
..UsbDevice::default()
};