Skip to content

Commit 2a5bfd5

Browse files
committed
[otlib,qemu,usbdev] Make minihost configure the device
The minihost was previously only retrieve the device descriptor, which insufficient for most tests. Now the minihost performs a full enumeration sequence, retrieving all configurations, assigning an address to the device and configuring the device. Signed-off-by: Amaury Pouly <[email protected]>
1 parent 409ddb0 commit 2a5bfd5

File tree

1 file changed

+114
-8
lines changed
  • sw/host/opentitanlib/src/transport/qemu

1 file changed

+114
-8
lines changed

sw/host/opentitanlib/src/transport/qemu/usbdev.rs

Lines changed: 114 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -293,10 +293,12 @@ impl<T> UsbContext<T, UsbError> for UsbResult<T> {
293293

294294
/// This structure represents an enumerated and configured device.
295295
#[derive(Clone, Debug)]
296+
// Temporary until we have a more complete stack that uses this field.
297+
#[allow(dead_code)]
296298
struct DeviceInfo {
297-
// Temporary until we have a more complete stack that uses this field.
298-
#[allow(dead_code)]
299299
dev_desc: Vec<u8>,
300+
address: u8,
301+
configurations: Vec<Vec<u8>>,
300302
}
301303

302304
struct ControlIn {
@@ -344,20 +346,27 @@ impl QemuHostThread {
344346
const USB_FS_SAFE_PACKET_SIZE: u16 = 8;
345347

346348
// Some standard request types.
349+
const USB_REQ_TYPE_OUT: u8 = 0;
347350
const USB_REQ_TYPE_IN: u8 = 0x80;
348351
const USB_REQ_TYPE_STANDARD: u8 = 0;
349352
const USB_REQ_TYPE_DEVICE: u8 = 0;
350353

351354
// Some standard USB requests.
355+
const USB_SET_ADDRESS: u8 = 5;
352356
const USB_GET_DESCRIPTOR: u8 = 6;
357+
const USB_SET_CONFIGURATION: u8 = 9;
353358

354359
// Some standard descriptor types.
355360
const USB_DEVICE_DESCRIPTOR: u8 = 1;
356-
const USB_DEVICE_DESCRIPTOR_LENGTH: usize = 18;
361+
const USB_CONFIG_DESCRIPTOR: u8 = 2;
357362

358363
// Location of the bMaxPacketSize field in the device descriptor.
359364
const USB_DEV_DESC_MAX_PACKET_SIZE_OFFSET: usize = 7;
360365

366+
// How much time to wait after a SET_ADDRESS before moving on
367+
// to the rest of the enumeration sequence.
368+
const SET_ADDRESS_WAIT_DELAY_MS: u64 = 10;
369+
361370
fn new(
362371
usbdev: TTYPort,
363372
channel_send: mpsc::Sender<HostChannelEvent>,
@@ -752,31 +761,125 @@ impl QemuHostThread {
752761
req: Self::USB_GET_DESCRIPTOR,
753762
value: (Self::USB_DEVICE_DESCRIPTOR as u16) << 8,
754763
index: 0,
755-
length: Self::USB_FS_SAFE_PACKET_SIZE.into(), // length
764+
length: Self::USB_FS_SAFE_PACKET_SIZE.into(),
756765
max_pkt_size: Self::USB_FS_SAFE_PACKET_SIZE,
757766
})
758767
.maybe_context("Failed to send GET_DESC(device, 8 bytes)")?;
759768
let max_packet_size = trunc_dev_desc[Self::USB_DEV_DESC_MAX_PACKET_SIZE_OFFSET] as u16;
760769
log::info!("USB Host: device report a maximum packet size of {max_packet_size} on EP0");
761770
// TODO sanity check max packet size
762771

772+
// Assign an address to the device.
773+
// TODO randomize address or assign them by increasing numbers?
774+
let address = 42; // Arbitrary number.
775+
self.send_and_wait_control_out(&ControlOut {
776+
addr: 0,
777+
ep: 0,
778+
req_type: Self::USB_REQ_TYPE_OUT
779+
| Self::USB_REQ_TYPE_STANDARD
780+
| Self::USB_REQ_TYPE_DEVICE,
781+
req: Self::USB_SET_ADDRESS,
782+
value: address as u16,
783+
index: 0,
784+
max_pkt_size: max_packet_size,
785+
data: &[],
786+
})
787+
.maybe_context("Failed to send SET_ADDRESS")?;
788+
log::info!("USB Host: device accepted address {address:?}");
789+
790+
// Give time to the device to update its address.
791+
std::thread::sleep(Duration::from_millis(Self::SET_ADDRESS_WAIT_DELAY_MS));
792+
763793
// Retrieve the full device descriptor.
764794
let dev_desc = self
765795
.send_and_wait_control_in(&ControlIn {
766-
addr: 0,
796+
addr: address,
767797
ep: 0,
768798
req_type: Self::USB_REQ_TYPE_IN
769799
| Self::USB_REQ_TYPE_STANDARD
770800
| Self::USB_REQ_TYPE_DEVICE,
771801
req: Self::USB_GET_DESCRIPTOR,
772802
value: (Self::USB_DEVICE_DESCRIPTOR as u16) << 8,
773803
index: 0,
774-
length: Self::USB_DEVICE_DESCRIPTOR_LENGTH,
804+
length: size_of::<desc::DeviceDescriptor>(),
775805
max_pkt_size: max_packet_size,
776806
})
777807
.maybe_context("Failed to send GET_DESC(device, all bytes)")?;
808+
// Extract number of configurations.
809+
let num_config = desc::DeviceDescriptor::ref_from_bytes(&dev_desc)
810+
.map_err(|_err| anyhow!("Cannot parse device descriptor"))?
811+
.num_config;
812+
813+
// Retrieve all configurations descriptors.
814+
let mut configurations = Vec::new();
815+
let mut first_config_val = None;
816+
for config_idx in 0..num_config {
817+
// Retrieve just the configuration descriptor first.
818+
let config_desc = self
819+
.send_and_wait_control_in(&ControlIn {
820+
addr: address,
821+
ep: 0,
822+
req_type: Self::USB_REQ_TYPE_IN
823+
| Self::USB_REQ_TYPE_STANDARD
824+
| Self::USB_REQ_TYPE_DEVICE,
825+
req: Self::USB_GET_DESCRIPTOR,
826+
value: (Self::USB_CONFIG_DESCRIPTOR as u16) << 8 | config_idx as u16,
827+
index: 0,
828+
length: size_of::<desc::ConfigurationDescriptor>(),
829+
max_pkt_size: max_packet_size,
830+
})
831+
.maybe_context("Failed to send GET_DESC(config desc)")?;
832+
// Parse and extract the size of the full configuration.
833+
let parsed_desc = desc::ConfigurationDescriptor::ref_from_bytes(&config_desc)
834+
.map_err(|_err| anyhow!("Cannot parse config descriptor"))?;
835+
let tot_len = parsed_desc.tot_length;
836+
// Remember the configuration value for later.
837+
if first_config_val.is_none() {
838+
first_config_val = Some(parsed_desc.config_val);
839+
}
840+
// Retrieve full configuration.
841+
let full_config = self
842+
.send_and_wait_control_in(&ControlIn {
843+
addr: address,
844+
ep: 0,
845+
req_type: Self::USB_REQ_TYPE_IN
846+
| Self::USB_REQ_TYPE_STANDARD
847+
| Self::USB_REQ_TYPE_DEVICE,
848+
req: Self::USB_GET_DESCRIPTOR,
849+
value: (Self::USB_CONFIG_DESCRIPTOR as u16) << 8 | config_idx as u16,
850+
index: 0,
851+
length: tot_len.into(),
852+
max_pkt_size: max_packet_size,
853+
})
854+
.maybe_context("Failed to send GET_DESC(full config)")?;
855+
configurations.push(full_config);
856+
}
778857

779-
Ok(DeviceInfo { dev_desc })
858+
// Set the first available configuration.
859+
if let Some(first_config_val) = first_config_val {
860+
self.send_and_wait_control_out(&ControlOut {
861+
addr: address,
862+
ep: 0,
863+
req_type: Self::USB_REQ_TYPE_OUT
864+
| Self::USB_REQ_TYPE_STANDARD
865+
| Self::USB_REQ_TYPE_DEVICE,
866+
req: Self::USB_SET_CONFIGURATION,
867+
value: first_config_val as u16,
868+
index: 0,
869+
max_pkt_size: max_packet_size,
870+
data: &[],
871+
})
872+
.maybe_context("Failed to send SET_CONFIGURATION")?;
873+
} else {
874+
log::error!("USB host: device has no configurations")
875+
}
876+
log::info!("USB Host: device configured");
877+
878+
Ok(DeviceInfo {
879+
dev_desc,
880+
address,
881+
configurations,
882+
})
780883
}
781884

782885
/// This thread simulates a USB host. It can react to events sent by otlib
@@ -834,7 +937,10 @@ impl QemuHostThread {
834937
log::info!("USB Host: device disconnected");
835938
continue;
836939
}
837-
Err(err) => return Err(err).maybe_context("Failed to enumerate device"),
940+
Err(err) => {
941+
log::error!("USB host: failed to enumerate device: {err:?}");
942+
continue;
943+
}
838944
Ok(dev_info) => dev_info,
839945
};
840946
log::info!("USB Host: device configured: {dev_info:?}");

0 commit comments

Comments
 (0)