xhcid: ensure max packet size is set correctly before reading descriptors
This commit is contained in:
+25
-2
@@ -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,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
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user