fix: align bulk IN buffers and forward unknown string descriptors
Two fixes for mass storage passthrough: 1. Bulk IN buffer allocation now rounds up to the endpoint's max_packet_size. nusb (and the USB spec) require IN transfers to be multiples of max_packet_size. Without this, SCSI INQUIRY (36 bytes on a 512-byte max_packet_size endpoint) was rejected, causing the kernel to repeatedly reset the device. 2. String descriptor requests for indices not in the local string pool are now forwarded to the device handler. This fixes interface and configuration string descriptors (e.g., iInterface=5) that exist on the real device but weren't populated in the synthetic string pool. Tested: USB mass storage gadget via dummy_hcd successfully enumerates, mounts, reads, and writes through the USBIP passthrough. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
889017be3b
commit
63e9faf82d
2 changed files with 17 additions and 2 deletions
|
|
@ -507,6 +507,18 @@ impl UsbDevice {
|
|||
desc.resize(setup_packet.length as usize, 0);
|
||||
}
|
||||
Ok(UrbResponse { data: desc, ..Default::default() })
|
||||
} else if self.device_handler.is_some() {
|
||||
// Forward unknown string indices to the device handler
|
||||
// (host passthrough: the real device knows its own strings)
|
||||
let lock = self.device_handler.as_ref().unwrap();
|
||||
let mut handler = lock.lock().unwrap();
|
||||
handler.handle_urb(UrbRequest {
|
||||
ep,
|
||||
transfer_buffer_length,
|
||||
setup: setup_packet,
|
||||
data: out_data,
|
||||
..Default::default()
|
||||
})
|
||||
} else {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
|
|
|
|||
|
|
@ -334,17 +334,20 @@ impl UsbInterfaceHandler for NusbUsbHostInterfaceHandler {
|
|||
} else if ep.attributes == EndpointAttributes::Bulk as u8 {
|
||||
// bulk
|
||||
if let Direction::In = ep.direction() {
|
||||
// bulk in
|
||||
// bulk in - round up to max_packet_size as required by USB spec
|
||||
let mps = ep.max_packet_size.max(1) as usize;
|
||||
let alloc_len = ((transfer_buffer_length as usize) + mps - 1) / mps * mps;
|
||||
let mut endpoint = handle
|
||||
.endpoint::<nusb::transfer::Bulk, nusb::transfer::In>(ep.address)
|
||||
.map_err(|e| {
|
||||
std::io::Error::other(format!("Failed to open bulk endpoint: {}", e))
|
||||
})?;
|
||||
let buffer = endpoint.allocate(transfer_buffer_length as usize);
|
||||
let buffer = endpoint.allocate(alloc_len);
|
||||
let completion = endpoint.transfer_blocking(buffer, timeout);
|
||||
completion.status.map_err(|e| {
|
||||
std::io::Error::new(std::io::ErrorKind::Other, format!("USB bulk IN failed: {e}"))
|
||||
})?;
|
||||
// Return only the actual bytes received (may be less than alloc_len)
|
||||
return Ok(UrbResponse { data: completion.buffer.to_vec(), ..Default::default() });
|
||||
} else {
|
||||
// bulk out
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue