From 2bf09b5fc5f96649b3fed303a1bf6162b097941c Mon Sep 17 00:00:00 2001 From: James Devine Date: Wed, 1 Feb 2023 10:21:26 +0000 Subject: [PATCH 1/7] Add basic implementation of FtdiDeviceHandler --- src/ftdi.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 93 insertions(+) create mode 100644 src/ftdi.rs diff --git a/src/ftdi.rs b/src/ftdi.rs new file mode 100644 index 0000000..d581b60 --- /dev/null +++ b/src/ftdi.rs @@ -0,0 +1,92 @@ +use std::any::Any; +use crate::{UsbDeviceHandler, SetupPacket}; + +const FTDI_DEVICE_REQ_TYPE:u8 = 0xC0; +const FTDI_SIO_RESET: u8 = 0; /* Reset the port */ +const FTDI_SIO_MODEM_CTRL: u8 = 1; /* Set the modem control register */ +const FTDI_SIO_SET_FLOW_CTRL: u8 = 2; /* Set flow control register */ +const FTDI_SIO_SET_BAUD_RATE: u8 = 3; /* Set baud rate */ +const FTDI_SIO_SET_DATA: u8 = 4; /* Set the data characteristics ofthe port */ +const FTDI_SIO_GET_MODEM_STATUS: u8 = 5; /* Retrieve current value of modem status register */ +const FTDI_SIO_SET_EVENT_CHAR: u8 = 6; /* Set the event character */ +const FTDI_SIO_SET_ERROR_CHAR: u8 = 7; /* Set the error character */ +const FTDI_SIO_SET_LATENCY_TIMER: u8 = 9; /* Set the latency timer */ +const FTDI_SIO_GET_LATENCY_TIMER: u8 = 0x0a; /* Get the latency timer */ +const FTDI_SIO_SET_BITMODE: u8 = 0x0b; /* Set bitbang mode */ +const FTDI_SIO_READ_PINS: u8 = 0x0c; /* Read immediate value of pins */ +const FTDI_SIO_READ_EEPROM: u8 = 0x90; /* Read EEPROM */ + +enum FTDISIORequestTypes { + Reset, + ModemCtrl, + SetFlowCtrl, + SetBaudRate, + SetData, + GetModemStatus, + SetEventChar, + SetErrorChar, + SetLatencyTimer, + GetLatencyTimer, + SetBitmode, + ReadPins, + ReadEEPROM, + Unknown +} + +impl From for FTDISIORequestTypes { + fn from(orig: u8) -> Self { + match orig { + FTDI_SIO_RESET => FTDISIORequestTypes::Reset, + FTDI_SIO_MODEM_CTRL => FTDISIORequestTypes::ModemCtrl, + FTDI_SIO_SET_FLOW_CTRL => FTDISIORequestTypes::SetFlowCtrl, + FTDI_SIO_SET_BAUD_RATE => FTDISIORequestTypes::SetBaudRate, + FTDI_SIO_SET_DATA => FTDISIORequestTypes::SetData, + FTDI_SIO_GET_MODEM_STATUS => FTDISIORequestTypes::GetModemStatus, + FTDI_SIO_SET_EVENT_CHAR => FTDISIORequestTypes::SetEventChar, + FTDI_SIO_SET_ERROR_CHAR => FTDISIORequestTypes::SetErrorChar, + FTDI_SIO_SET_LATENCY_TIMER => FTDISIORequestTypes::SetLatencyTimer, + FTDI_SIO_GET_LATENCY_TIMER => FTDISIORequestTypes::GetLatencyTimer, + FTDI_SIO_SET_BITMODE => FTDISIORequestTypes::SetBitmode, + FTDI_SIO_READ_PINS => FTDISIORequestTypes::ReadPins, + FTDI_SIO_READ_EEPROM => FTDISIORequestTypes::ReadEEPROM, + _ => FTDISIORequestTypes::Unknown, + } + } +} + + +#[derive(Clone)] +pub struct FtdiDeviceHandler { +} + +impl FtdiDeviceHandler { + pub fn new() -> Self { + Self {} + } +} + +impl UsbDeviceHandler for FtdiDeviceHandler { + fn handle_urb(&mut self, setup: SetupPacket, _: &[u8]) -> Result, std::io::Error> + { + // dummy responses for now + match setup.request_type { + FTDI_DEVICE_REQ_TYPE=> { + match setup.request.into() { + FTDISIORequestTypes::GetModemStatus => { + Ok(vec![0x00,0x00,0x00,0x00]) + }, + FTDISIORequestTypes::GetLatencyTimer => { + // 1ms + Ok(vec![0x01]) + }, + _ => Ok(vec![]) + } + }, + _ => Ok(vec![]) + } + } + + fn as_any(&mut self) -> &mut dyn Any { + self + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index d1ad134..c901916 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ pub mod cdc; mod consts; mod device; mod endpoint; +pub mod ftdi; pub mod hid; mod host; mod interface; From 77270ad13a8ac6694c5452bc9848e6b7f7af91d5 Mon Sep 17 00:00:00 2001 From: James Devine Date: Fri, 3 Feb 2023 17:42:52 +0000 Subject: [PATCH 2/7] devices_with_filter --- src/lib.rs | 259 +++++++++++++++++++++++++++++------------------------ 1 file changed, 143 insertions(+), 116 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c901916..c282f44 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,134 +42,161 @@ impl UsbIpServer { Self { devices } } - /// Create a [UsbIpServer] exposing devices in the host, and redirect all USB transfers to them using libusb - pub fn new_from_host() -> Self { + fn with_devices(device_list: Vec>) -> Vec { let mut devices = vec![]; - if let Ok(list) = rusb::devices() { - for dev in list.iter() { - let open_device = match dev.open() { - Ok(dev) => dev, - Err(err) => { - println!("Impossible to share {:?}: {}", dev, err); - continue; - } - }; - let handle = Arc::new(Mutex::new(open_device)); - let desc = dev.device_descriptor().unwrap(); - let cfg = dev.active_config_descriptor().unwrap(); - let mut interfaces = vec![]; + + for dev in device_list { + let open_device = match dev.open() { + Ok(dev) => dev, + Err(err) => { + println!("Impossible to share {:?}: {}", dev, err); + continue; + } + }; + let handle = Arc::new(Mutex::new(open_device)); + let desc = dev.device_descriptor().unwrap(); + let cfg = dev.active_config_descriptor().unwrap(); + let mut interfaces = 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) + .claim_interface(intf_desc.interface_number()) .ok(); - for intf in cfg.interfaces() { - // ignore alternate settings - let intf_desc = intf.descriptors().next().unwrap(); - handle - .lock() - .unwrap() - .claim_interface(intf_desc.interface_number()) - .ok(); - let mut endpoints = vec![]; + 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(), - }); - } - - let handler = Arc::new(Mutex::new(Box::new(UsbHostInterfaceHandler::new( - handle.clone(), - )) - as Box)); - interfaces.push(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, + 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(), }); } - 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(), - 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, - interval: 0, - }, - ep0_out: UsbEndpoint { - address: 0x00, - attributes: EndpointAttributes::Control as u8, - max_packet_size: desc.max_packet_size() as u16, - interval: 0, - }, - interfaces, - device_handler: Some(Arc::new(Mutex::new(Box::new( - UsbHostDeviceHandler::new(handle.clone()), - )))), - ..UsbDevice::default() - }; - // set strings - if let Some(index) = desc.manufacturer_string_index() { - device.string_manufacturer = device.new_string( - &handle - .lock() - .unwrap() - .read_string_descriptor_ascii(index) - .unwrap(), - ) - } - if let Some(index) = desc.product_string_index() { - device.string_product = device.new_string( - &handle - .lock() - .unwrap() - .read_string_descriptor_ascii(index) - .unwrap(), - ) + let handler = Arc::new(Mutex::new(Box::new(UsbHostInterfaceHandler::new( + handle.clone(), + )) + as Box)); + interfaces.push(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(), + 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, + interval: 0, + }, + ep0_out: UsbEndpoint { + address: 0x00, + attributes: EndpointAttributes::Control as u8, + max_packet_size: desc.max_packet_size() as u16, + interval: 0, + }, + interfaces, + device_handler: Some(Arc::new(Mutex::new(Box::new( + UsbHostDeviceHandler::new(handle.clone()), + )))), + ..UsbDevice::default() + }; + + // set strings + if let Some(index) = desc.manufacturer_string_index() { + device.string_manufacturer = device.new_string( + &handle + .lock() + .unwrap() + .read_string_descriptor_ascii(index) + .unwrap(), + ) + } + if let Some(index) = desc.product_string_index() { + device.string_product = device.new_string( + &handle + .lock() + .unwrap() + .read_string_descriptor_ascii(index) + .unwrap(), + ) + } + if let Some(index) = desc.serial_number_string_index() { + device.string_serial = device.new_string( + &handle + .lock() + .unwrap() + .read_string_descriptor_ascii(index) + .unwrap(), + ) + } + devices.push(device); + } + devices + } + + /// Create a [UsbIpServer] exposing devices in the host, and redirect all USB transfers to them using libusb + pub fn new_from_host() -> Self { + match rusb::devices() { + Ok(list) => { + let mut devs = vec![]; + for d in list.iter() { + devs.push(d) } - if let Some(index) = desc.serial_number_string_index() { - device.string_serial = device.new_string( - &handle - .lock() - .unwrap() - .read_string_descriptor_ascii(index) - .unwrap(), - ) + Self {devices: Self::with_devices(devs)} + }, + Err(_) => Self { devices: vec![] } + } + } + + pub fn new_from_host_with_filter(filter: F) -> Self + where F: FnMut(&Device) -> bool { + match rusb::devices() { + Ok(list) => { + let mut devs = vec![]; + for d in list.iter().filter(filter) { + devs.push(d) } - devices.push(device); - } + Self {devices: Self::with_devices(devs) } + }, + Err(_) => Self { devices: vec![] } } - Self { devices } } } From ee51a4003b95ef54400aa6990ce2b05823f03967 Mon Sep 17 00:00:00 2001 From: James Devine Date: Fri, 3 Feb 2023 17:43:16 +0000 Subject: [PATCH 3/7] snap ep writes to maximum buffer size of endpoint --- src/host.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/host.rs b/src/host.rs index f8947e8..29268ce 100644 --- a/src/host.rs +++ b/src/host.rs @@ -25,7 +25,7 @@ impl UsbInterfaceHandler for UsbHostInterfaceHandler { "To host device: ep={:?} setup={:?} req={:?}", ep, setup, req ); - let mut buffer = [0u8; 1024]; + let mut buffer = vec![0u8; ep.max_packet_size as usize]; let timeout = std::time::Duration::new(1, 0); let handle = self.handle.lock().unwrap(); if ep.attributes == EndpointAttributes::Control as u8 { From b89607494d4fd564097943f4406d2e559f9d5955 Mon Sep 17 00:00:00 2001 From: James Devine Date: Mon, 6 Feb 2023 09:47:21 +0000 Subject: [PATCH 4/7] format code --- src/ftdi.rs | 29 ++++++++++++----------------- src/lib.rs | 29 +++++++++++++++++------------ 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/ftdi.rs b/src/ftdi.rs index d581b60..c1bb43d 100644 --- a/src/ftdi.rs +++ b/src/ftdi.rs @@ -1,7 +1,7 @@ +use crate::{SetupPacket, UsbDeviceHandler}; use std::any::Any; -use crate::{UsbDeviceHandler, SetupPacket}; -const FTDI_DEVICE_REQ_TYPE:u8 = 0xC0; +const FTDI_DEVICE_REQ_TYPE: u8 = 0xC0; const FTDI_SIO_RESET: u8 = 0; /* Reset the port */ const FTDI_SIO_MODEM_CTRL: u8 = 1; /* Set the modem control register */ const FTDI_SIO_SET_FLOW_CTRL: u8 = 2; /* Set flow control register */ @@ -30,7 +30,7 @@ enum FTDISIORequestTypes { SetBitmode, ReadPins, ReadEEPROM, - Unknown + Unknown, } impl From for FTDISIORequestTypes { @@ -54,10 +54,8 @@ impl From for FTDISIORequestTypes { } } - #[derive(Clone)] -pub struct FtdiDeviceHandler { -} +pub struct FtdiDeviceHandler {} impl FtdiDeviceHandler { pub fn new() -> Self { @@ -66,27 +64,24 @@ impl FtdiDeviceHandler { } impl UsbDeviceHandler for FtdiDeviceHandler { - fn handle_urb(&mut self, setup: SetupPacket, _: &[u8]) -> Result, std::io::Error> - { + fn handle_urb(&mut self, setup: SetupPacket, _: &[u8]) -> Result, std::io::Error> { // dummy responses for now match setup.request_type { - FTDI_DEVICE_REQ_TYPE=> { + FTDI_DEVICE_REQ_TYPE => { match setup.request.into() { - FTDISIORequestTypes::GetModemStatus => { - Ok(vec![0x00,0x00,0x00,0x00]) - }, + FTDISIORequestTypes::GetModemStatus => Ok(vec![0x00, 0x00, 0x00, 0x00]), FTDISIORequestTypes::GetLatencyTimer => { // 1ms Ok(vec![0x01]) - }, - _ => Ok(vec![]) + } + _ => Ok(vec![]), } - }, - _ => Ok(vec![]) + } + _ => Ok(vec![]), } } fn as_any(&mut self) -> &mut dyn Any { self } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index c282f44..1680de7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ impl UsbIpServer { Self { devices } } - fn with_devices(device_list: Vec>) -> Vec { + fn with_devices(device_list: Vec>) -> Vec { let mut devices = vec![]; for dev in device_list { @@ -63,7 +63,6 @@ impl UsbIpServer { .set_auto_detach_kernel_driver(true) .ok(); for intf in cfg.interfaces() { - // ignore alternate settings let intf_desc = intf.descriptors().next().unwrap(); handle @@ -132,9 +131,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(UsbHostDeviceHandler::new( + handle.clone(), + ))))), ..UsbDevice::default() }; @@ -179,23 +178,29 @@ impl UsbIpServer { for d in list.iter() { devs.push(d) } - Self {devices: Self::with_devices(devs)} - }, - Err(_) => Self { devices: vec![] } + Self { + devices: Self::with_devices(devs), + } + } + Err(_) => Self { devices: vec![] }, } } pub fn new_from_host_with_filter(filter: F) -> Self - where F: FnMut(&Device) -> bool { + where + F: FnMut(&Device) -> bool, + { match rusb::devices() { Ok(list) => { let mut devs = vec![]; for d in list.iter().filter(filter) { devs.push(d) } - Self {devices: Self::with_devices(devs) } - }, - Err(_) => Self { devices: vec![] } + Self { + devices: Self::with_devices(devs), + } + } + Err(_) => Self { devices: vec![] }, } } } From 5a838a7c3394fe539325061ed9ed39cd9cf1865b Mon Sep 17 00:00:00 2001 From: James Devine Date: Mon, 6 Feb 2023 11:59:26 +0000 Subject: [PATCH 5/7] Working FTDI example --- examples/ftdi.rs | 107 +++++++++++++++++++++++++++++++++++++++++++++++ src/ftdi.rs | 52 ++++++++++++++++++----- 2 files changed, 148 insertions(+), 11 deletions(-) create mode 100644 examples/ftdi.rs diff --git a/examples/ftdi.rs b/examples/ftdi.rs new file mode 100644 index 0000000..4c094da --- /dev/null +++ b/examples/ftdi.rs @@ -0,0 +1,107 @@ +use env_logger; +use std::any::Any; +use std::net::*; +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use usbip::{ + ftdi::FtdiDeviceHandler, Direction, EndpointAttributes, SetupPacket, UsbDevice, UsbEndpoint, + UsbInterface, UsbInterfaceHandler, +}; + +const FTDI_VID: u16 = 0x0403; +const FTDI_PID: u16 = 0x6011; + +#[derive(Clone)] +pub struct PseudoFtdiHandler { + tx_buffer: Vec, +} + +impl PseudoFtdiHandler { + pub fn new() -> Self { + Self { tx_buffer: vec![] } + } +} + +// This implemention does not +impl UsbInterfaceHandler for PseudoFtdiHandler { + fn handle_urb( + &mut self, + _interface: &UsbInterface, + ep: UsbEndpoint, + _setup: SetupPacket, + req: &[u8], + ) -> Result, std::io::Error> { + // interrupt + if ep.attributes == EndpointAttributes::Interrupt as u8 { + Ok(vec![]) + } + // bulk + else if let Direction::Out = ep.direction() { + // write to device/file here... + println!("Write endpoint {:02x}: {:?}", ep.address, req); + Ok(vec![]) + } else { + // Read from the device. + // The first two bytes are device status. + // These must always be present, otherwise the ftdi driver on the remote side will + // consume these bytes. + if self.tx_buffer.len() > 0 { + let mut ftdi_packet: Vec = vec![0x01, 0x00]; + ftdi_packet.extend(&self.tx_buffer); + self.tx_buffer = vec![]; + println!("Read endpoint {:02x}: {:?}", ep.address, ftdi_packet); + Ok(ftdi_packet) + } else { + Ok(vec![0x01, 0x00]) + } + } + } + + fn get_class_specific_descriptor(&self) -> Vec { + vec![] + } + + fn as_any(&mut self) -> &mut dyn Any { + self + } +} + +fn ftdi_device() -> ( + UsbDevice, + Arc>>, +) { + let pseudo = Arc::new(Mutex::new( + Box::new(PseudoFtdiHandler::new()) as Box + )); + let device_handler = Arc::new(Mutex::new( + Box::new(FtdiDeviceHandler::new()) as Box + )); + let endpoints = FtdiDeviceHandler::endpoints(4); + let mut device = UsbDevice::new(0) + .with_interface(255, 255, 255, "", endpoints[0..2].to_vec(), pseudo.clone()) + .with_interface(255, 255, 255, "", endpoints[2..4].to_vec(), pseudo.clone()) + .with_interface(255, 255, 255, "", endpoints[4..6].to_vec(), pseudo.clone()) + .with_interface(255, 255, 255, "", endpoints[6..8].to_vec(), pseudo.clone()) + .with_device_handler(device_handler); + + device.product_id = FTDI_PID; + device.vendor_id = FTDI_VID; + (device, pseudo) +} + +#[tokio::main] +async fn main() { + env_logger::init(); + let (device, handler) = ftdi_device(); + let server = usbip::UsbIpServer::new_simulated(vec![device]); + let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 3240); + tokio::spawn(usbip::server(addr, server)); + + loop { + tokio::time::sleep(Duration::from_secs(1)).await; + let mut handler = handler.lock().unwrap(); + if let Some(ftdi) = handler.as_any().downcast_mut::() { + ftdi.tx_buffer.extend(b"hello\0"); + } + } +} diff --git a/src/ftdi.rs b/src/ftdi.rs index c1bb43d..b3b2f58 100644 --- a/src/ftdi.rs +++ b/src/ftdi.rs @@ -1,4 +1,4 @@ -use crate::{SetupPacket, UsbDeviceHandler}; +use crate::{EndpointAttributes, SetupPacket, UsbDeviceHandler, UsbEndpoint}; use std::any::Any; const FTDI_DEVICE_REQ_TYPE: u8 = 0xC0; @@ -16,6 +16,9 @@ const FTDI_SIO_SET_BITMODE: u8 = 0x0b; /* Set bitbang mode */ const FTDI_SIO_READ_PINS: u8 = 0x0c; /* Read immediate value of pins */ const FTDI_SIO_READ_EEPROM: u8 = 0x90; /* Read EEPROM */ +const EP_MAX_PACKET_SIZE: u16 = 512; + +#[derive(Debug)] enum FTDISIORequestTypes { Reset, ModemCtrl, @@ -61,22 +64,49 @@ impl FtdiDeviceHandler { pub fn new() -> Self { Self {} } + + pub fn endpoints(interface_count: u8) -> Vec { + let mut ret_eps = vec![]; + + for i in 0..interface_count { + ret_eps.push(UsbEndpoint { + /// bEndpointAddress + address: 0x81 + (0x2 * i), + /// bmAttributes + attributes: EndpointAttributes::Bulk as u8, + /// wMaxPacketSize + max_packet_size: EP_MAX_PACKET_SIZE as u16, + /// bInterval + interval: 0, + }); + + ret_eps.push(UsbEndpoint { + /// bEndpointAddress + address: 0x2 + (0x2 * i), + /// bmAttributes + attributes: EndpointAttributes::Bulk as u8, + /// wMaxPacketSize + max_packet_size: EP_MAX_PACKET_SIZE as u16, + /// bInterval + interval: 0, + }) + } + ret_eps + } } impl UsbDeviceHandler for FtdiDeviceHandler { fn handle_urb(&mut self, setup: SetupPacket, _: &[u8]) -> Result, std::io::Error> { - // dummy responses for now match setup.request_type { - FTDI_DEVICE_REQ_TYPE => { - match setup.request.into() { - FTDISIORequestTypes::GetModemStatus => Ok(vec![0x00, 0x00, 0x00, 0x00]), - FTDISIORequestTypes::GetLatencyTimer => { - // 1ms - Ok(vec![0x01]) - } - _ => Ok(vec![]), + FTDI_DEVICE_REQ_TYPE => match setup.request.into() { + FTDISIORequestTypes::GetModemStatus => Ok(vec![0x00]), + // 1 ms + FTDISIORequestTypes::GetLatencyTimer => Ok(vec![0x01]), + request => { + println!("Unhandled: {:?}", request); + Ok(vec![]) } - } + }, _ => Ok(vec![]), } } From 79b470ba49e3adb7f0182faea19607d2bfa3f2ce Mon Sep 17 00:00:00 2001 From: James Devine Date: Mon, 6 Feb 2023 14:58:36 +0000 Subject: [PATCH 6/7] write padding in unlink response --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 1680de7..4a6c4d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -324,7 +324,8 @@ async fn handler( socket.write_u32(direction).await?; socket.write_u32(ep).await?; // status - socket.write_u32(0).await?; + socket.write_i32(0).await?; + socket.write_all(&mut padding).await?; } _ => warn!("Got unknown command {:?}", command), } From d5d0ed6410f4950c9faaffdae02d39445bb88349 Mon Sep 17 00:00:00 2001 From: James Devine Date: Mon, 6 Feb 2023 16:00:32 +0000 Subject: [PATCH 7/7] mirror device version and usb version --- src/device.rs | 62 +++++++++++++++++++++++++++++++++++++-------------- src/lib.rs | 2 ++ 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/device.rs b/src/device.rs index a37db4c..5b078f4 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,4 +1,28 @@ use super::*; +use rusb::Version as rusbVersion; + +#[derive(Clone, Default)] +pub struct Version { + pub major: u8, + pub minor: u8, + pub patch: u8, +} + +impl From for Version { + fn from(value: rusbVersion) -> Self { + Self { + major: value.major(), + minor: value.minor(), + patch: value.sub_minor(), + } + } +} + +impl Into for Version { + fn into(self) -> rusbVersion { + rusbVersion(self.major, self.minor, self.patch) + } +} /// Represent a USB device #[derive(Clone, Default)] @@ -10,7 +34,7 @@ pub struct UsbDevice { pub speed: u32, pub vendor_id: u16, pub product_id: u16, - pub device_bcd: u16, + pub device_bcd: Version, pub device_class: u8, pub device_subclass: u8, pub device_protocol: u8, @@ -18,6 +42,8 @@ pub struct UsbDevice { pub num_configurations: u8, pub interfaces: Vec, pub device_handler: Option>>>, + pub usb_version: Version, + pub(crate) ep0_in: UsbEndpoint, pub(crate) ep0_out: UsbEndpoint, // strings @@ -130,7 +156,9 @@ impl UsbDevice { socket.write_u32(self.speed).await?; socket.write_u16(self.vendor_id).await?; socket.write_u16(self.product_id).await?; - socket.write_u16(self.device_bcd).await?; + socket + .write_u16((self.device_bcd.major as u16) << 8 | self.device_bcd.minor as u16) + .await?; socket.write_u8(self.device_class).await?; socket.write_u8(self.device_subclass).await?; socket.write_u8(self.device_protocol).await?; @@ -198,18 +226,18 @@ impl UsbDevice { let mut desc = vec![ 0x12, // bLength Device as u8, // bDescriptorType: Device - 0x10, - 0x02, // bcdUSB: USB 2.1 - self.device_class, // bDeviceClass - self.device_subclass, // bDeviceSubClass - self.device_protocol, // bDeviceProtocol + self.usb_version.minor as u8, + self.usb_version.major as u8, // bcdUSB: USB 2.0 + self.device_class, // bDeviceClass + self.device_subclass, // bDeviceSubClass + self.device_protocol, // bDeviceProtocol self.ep0_in.max_packet_size as u8, // bMaxPacketSize0 - self.vendor_id as u8, // idVendor + self.vendor_id as u8, // idVendor (self.vendor_id >> 8) as u8, self.product_id as u8, // idProduct (self.product_id >> 8) as u8, - self.device_bcd as u8, // bcdDevice - (self.device_bcd >> 8) as u8, + self.device_bcd.minor as u8, // bcdDevice + self.device_bcd.major as u8, self.string_manufacturer, // iManufacturer self.string_product, // iProduct self.string_serial, // iSerial @@ -331,14 +359,14 @@ impl UsbDevice { let mut desc = vec![ 0x0A, // bLength DeviceQualifier as u8, // bDescriptorType: Device Qualifier - 0x10, - 0x02, // bcdUSB USB 2.1 - self.device_class, // bDeviceClass - self.device_subclass, // bDeviceSUbClass - self.device_protocol, // bDeviceProtocol + self.usb_version.minor as u8, + self.usb_version.major as u8, + self.device_class, // bDeviceClass + self.device_subclass, // bDeviceSUbClass + self.device_protocol, // bDeviceProtocol self.ep0_in.max_packet_size as u8, // bMaxPacketSize0 - self.num_configurations, // bNumConfigurations - 0x00, // reserved + self.num_configurations, // bNumConfigurations + 0x00, // reserved ]; // requested len too short: wLength < real length diff --git a/src/lib.rs b/src/lib.rs index 4a6c4d7..a939b1c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,6 +116,7 @@ impl UsbIpServer { device_class: desc.class_code(), device_subclass: desc.sub_class_code(), device_protocol: desc.protocol_code(), + device_bcd: device::Version::from(desc.device_version()), configuration_value: cfg.number(), num_configurations: desc.num_configurations(), ep0_in: UsbEndpoint { @@ -134,6 +135,7 @@ impl UsbIpServer { device_handler: Some(Arc::new(Mutex::new(Box::new(UsbHostDeviceHandler::new( handle.clone(), ))))), + usb_version: device::Version::from(desc.usb_version()), ..UsbDevice::default() };