xhcid: ensure max packet size is set correctly before reading descriptors

This commit is contained in:
Jeremy Soller
2024-04-15 12:54:05 -06:00
parent 12bc7273bf
commit 64fcd0a323
4 changed files with 72 additions and 7 deletions
+25 -2
View File
@@ -20,10 +20,33 @@ pub struct DeviceDescriptor {
unsafe impl plain::Plain for DeviceDescriptor {}
impl DeviceDescriptor {
fn minor_usb_vers(&self) -> u8 {
pub fn minor_usb_vers(&self) -> u8 {
(self.usb & 0xFF) as u8
}
fn major_usb_vers(&self) -> u8 {
pub fn major_usb_vers(&self) -> u8 {
((self.usb >> 8) & 0xFF) as u8
}
}
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct DeviceDescriptor8Byte {
pub length: u8,
pub kind: u8,
pub usb: u16,
pub class: u8,
pub sub_class: u8,
pub protocol: u8,
pub packet_size: u8,
}
unsafe impl plain::Plain for DeviceDescriptor8Byte {}
impl DeviceDescriptor8Byte {
pub fn minor_usb_vers(&self) -> u8 {
(self.usb & 0xFF) as u8
}
pub fn major_usb_vers(&self) -> u8 {
((self.usb >> 8) & 0xFF) as u8
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
pub use self::bos::{bos_capability_descs, BosAnyDevDesc, BosDescriptor, BosSuperSpeedDesc};
pub use self::config::ConfigDescriptor;
pub use self::device::DeviceDescriptor;
pub use self::device::{DeviceDescriptor, DeviceDescriptor8Byte};
pub use self::endpoint::{
EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor,
SuperSpeedPlusIsochCmpDescriptor, ENDP_ATTR_TY_MASK,
+43 -2
View File
@@ -129,6 +129,12 @@ impl Xhci {
Ok(())
}
async fn fetch_dev_desc_8_byte(&self, port: usize, slot: u8) -> Result<usb::DeviceDescriptor8Byte> {
let mut desc = unsafe { self.alloc_dma_zeroed::<usb::DeviceDescriptor8Byte>()? };
self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc).await?;
Ok(*desc)
}
async fn fetch_dev_desc(&self, port: usize, slot: u8) -> Result<usb::DeviceDescriptor> {
let mut desc = unsafe { self.alloc_dma_zeroed::<usb::DeviceDescriptor>()? };
self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc).await?;
@@ -552,6 +558,16 @@ impl Xhci {
};
self.port_states.insert(i, port_state);
// Ensure correct packet size is used
let dev_desc_8_byte = self.fetch_dev_desc_8_byte(i, slot).await?;
{
let mut port_state = self.port_states.get_mut(&i).unwrap();
let mut input = port_state.input_context.lock().unwrap();
self.update_max_packet_size(&mut *input, slot, dev_desc_8_byte).await?;
}
let dev_desc = self.get_desc(i, slot).await?;
self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc);
@@ -574,6 +590,33 @@ impl Xhci {
Ok(())
}
pub async fn update_max_packet_size(
&self,
input_context: &mut Dma<InputContext>,
slot_id: u8,
dev_desc: usb::DeviceDescriptor8Byte
) -> Result<()> {
let new_max_packet_size = if dev_desc.major_usb_vers() == 2 {
u32::from(dev_desc.packet_size)
} else {
1u32 << dev_desc.packet_size
};
let endp_ctx = &mut input_context.device.endpoints[0];
let mut b = endp_ctx.b.read();
b &= 0x0000_FFFF;
b |= (new_max_packet_size) << 16;
endp_ctx.b.write(b);
let (event_trb, command_trb) = self.execute_command(|trb, cycle| {
trb.evaluate_context(slot_id, input_context.physical(), false, cycle)
}).await;
self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?;
self.event_handler_finished();
Ok(())
}
pub async fn update_default_control_pipe(
&self,
input_context: &mut Dma<InputContext>,
@@ -594,14 +637,12 @@ impl Xhci {
b |= (new_max_packet_size) << 16;
endp_ctx.b.write(b);
/*TODO: this causes issues on real hardware, maybe it should only be used on USB 2?
let (event_trb, command_trb) = self.execute_command(|trb, cycle| {
trb.evaluate_context(slot_id, input_context.physical(), false, cycle)
}).await;
self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?;
self.event_handler_finished();
*/
Ok(())
}
+3 -2
View File
@@ -1036,7 +1036,7 @@ impl Xhci {
}
let raw_dd = self.fetch_dev_desc(port_id, slot).await?;
log::debug!("port {}, slot {}, desc {:?}", port_id, slot, raw_dd);
log::debug!("port {} slot {} desc {:X?}", port_id, slot, raw_dd);
let (manufacturer_str, product_str, serial_str) = (
if raw_dd.manufacturer_str > 0 {
@@ -1055,6 +1055,7 @@ impl Xhci {
None
},
);
log::debug!("manufacturer {:?} product {:?} serial {:?}", manufacturer_str, product_str, serial_str);
//TODO let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot).await?;
@@ -1067,7 +1068,7 @@ impl Xhci {
for index in 0..raw_dd.configurations {
let (desc, data) = self.fetch_config_desc(port_id, slot, index).await?;
log::debug!("port {}, slot {}, config {}, desc {:?}", port_id, slot, index, desc);
log::debug!("port {} slot {} config {} desc {:X?}", port_id, slot, index, desc);
let extra_length = desc.total_length as usize - mem::size_of_val(&desc);
let data = &data[..extra_length];