diff --git a/drivers/usb/xhcid/src/driver_interface.rs b/drivers/usb/xhcid/src/driver_interface.rs index 727f8d7e99..ba45d01ad5 100644 --- a/drivers/usb/xhcid/src/driver_interface.rs +++ b/drivers/usb/xhcid/src/driver_interface.rs @@ -59,9 +59,10 @@ pub struct ConfDesc { pub attributes: u8, pub max_power: u8, pub interface_descs: SmallVec<[IfDesc; 1]>, + pub unknown_descs: SmallVec<[UnknownDesc; 1]>, } -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)] pub struct EndpDesc { pub kind: u8, pub address: u8, @@ -215,7 +216,7 @@ impl EndpDesc { .unwrap_or(false) } } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct IfDesc { pub kind: u8, pub number: u8, @@ -225,31 +226,26 @@ pub struct IfDesc { pub protocol: u8, pub interface_str: Option, pub endpoints: SmallVec<[EndpDesc; 4]>, - pub hid_descs: SmallVec<[HidDesc; 1]>, + pub unknown_descs: SmallVec<[UnknownDesc; 1]>, } -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)] pub struct SuperSpeedCmp { pub kind: u8, pub max_burst: u8, pub attributes: u8, pub bytes_per_interval: u16, } -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)] pub struct SuperSpeedPlusIsochCmp { pub kind: u8, pub bytes_per_interval: u32, } -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct HidDesc { +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct UnknownDesc { + pub len: u8, pub kind: u8, - pub hid_spec_release: u16, - pub country: u8, - pub desc_count: u8, - pub desc_ty: u8, - pub desc_len: u16, - pub optional_desc_ty: u8, - pub optional_desc_len: u16, + pub all_bytes: Vec, } #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct PortReq { diff --git a/drivers/usb/xhcid/src/xhci/scheme.rs b/drivers/usb/xhcid/src/xhci/scheme.rs index ca27b3fec7..fe80d2062d 100644 --- a/drivers/usb/xhcid/src/xhci/scheme.rs +++ b/drivers/usb/xhcid/src/xhci/scheme.rs @@ -477,20 +477,6 @@ impl From for EndpDesc { } } -impl From for HidDesc { - fn from(d: usb::HidDescriptor) -> Self { - Self { - kind: d.kind, - hid_spec_release: d.hid_spec_release, - country: d.country_code, - desc_count: d.num_descriptors, - desc_ty: d.report_desc_ty, - desc_len: d.report_desc_len, - optional_desc_ty: d.optional_desc_ty, - optional_desc_len: d.optional_desc_len, - } - } -} impl From for SuperSpeedCmp { fn from(d: usb::SuperSpeedCompanionDescriptor) -> Self { @@ -519,9 +505,9 @@ pub enum AnyDescriptor { Config(usb::ConfigDescriptor), Interface(usb::InterfaceDescriptor), Endpoint(usb::EndpointDescriptor), - Hid(usb::HidDescriptor), SuperSpeedCompanion(usb::SuperSpeedCompanionDescriptor), SuperSpeedPlusCompanion(usb::SuperSpeedPlusIsochCmpDescriptor), + Unknown(Vec), } impl AnyDescriptor { @@ -534,6 +520,7 @@ impl AnyDescriptor { let kind = bytes[1]; if bytes.len() < len.into() { + error!("Parsed length is bigger than buffer len"); return None; } @@ -543,13 +530,9 @@ impl AnyDescriptor { 2 => Self::Config(*plain::from_bytes(bytes).ok()?), 4 => Self::Interface(*plain::from_bytes(bytes).ok()?), 5 => Self::Endpoint(*plain::from_bytes(bytes).ok()?), - 33 => Self::Hid(*plain::from_bytes(bytes).ok()?), 48 => Self::SuperSpeedCompanion(*plain::from_bytes(bytes).ok()?), 49 => Self::SuperSpeedPlusCompanion(*plain::from_bytes(bytes).ok()?), - _ => { - //panic!("Descriptor unknown {}: bytes {:#0x?}", kind, bytes); - return None; - } + _ => Self::Unknown(bytes[..len as usize].iter().cloned().collect()), }, len.into(), )) @@ -563,7 +546,7 @@ impl Xhci { slot: u8, desc: usb::InterfaceDescriptor, endps: impl IntoIterator, - hid_descs: impl IntoIterator, + unknown_descs: impl IntoIterator, lang_id: u16, ) -> Result { Ok(IfDesc { @@ -582,7 +565,7 @@ impl Xhci { protocol: desc.protocol, sub_class: desc.sub_class, endpoints: endps.into_iter().collect(), - hid_descs: hid_descs.into_iter().collect(), + unknown_descs: unknown_descs.into_iter().collect(), }) } /// Pushes a command TRB to the command ring, rings the doorbell, and then awaits its Command @@ -1539,56 +1522,85 @@ impl Xhci { } let mut interface_descs = SmallVec::new(); + let mut unknown_descs = SmallVec::new(); + let mut iface_unknown_descs = SmallVec::<[UnknownDesc; 1]>::new(); let mut iter = descriptors.into_iter().peekable(); + + let mut cur_iface = None; + let mut cur_endpoint = None; + let mut endpoints = SmallVec::<[EndpDesc; 4]>::new(); while let Some(item) = iter.next() { - if let AnyDescriptor::Interface(idesc) = item { - let mut endpoints = SmallVec::<[EndpDesc; 4]>::new(); - let mut hid_descs = SmallVec::<[HidDesc; 1]>::new(); - - while endpoints.len() < idesc.endpoints as usize { - let next = match iter.next() { - Some(AnyDescriptor::Endpoint(n)) => n, - Some(AnyDescriptor::Hid(h)) if idesc.class == 3 => { - hid_descs.push(h.into()); - continue; - } - Some(unexpected) => { - log::warn!("expected endpoint, got {:X?}", unexpected); - break; - } - None => break, - }; - let mut endp = EndpDesc::from(next); - - loop { - match iter.peek() { - Some(AnyDescriptor::SuperSpeedCompanion(n)) => { - endp.ssc = Some(SuperSpeedCmp::from(n.clone())); - iter.next().unwrap(); + debug!("Processing descriptor {item:?}"); + + + match item { + AnyDescriptor::Interface(idesc) => { + if let Some(cur_idesc) = cur_iface { + if let Some(endp) = cur_endpoint{ + if !endpoints.contains(&endp) { + endpoints.push(endp); } - Some(AnyDescriptor::SuperSpeedPlusCompanion(n)) => { - endp.sspc = Some(SuperSpeedPlusIsochCmp::from(n.clone())); - iter.next().unwrap(); - } - _ => break, } + interface_descs.push( + self.new_if_desc(port_id, slot, cur_idesc, endpoints, iface_unknown_descs, lang_id) + .await?, + ); } - - endpoints.push(endp); + cur_iface = Some(idesc); + endpoints = SmallVec::new(); + iface_unknown_descs = SmallVec::new(); + }, + AnyDescriptor::Endpoint(endpdesc) => { + if let Some(desc) = cur_endpoint { + endpoints.push(desc); + } + cur_endpoint = Some(EndpDesc::from(endpdesc)); + }, + AnyDescriptor::SuperSpeedCompanion(ssc) => { + if let Some(endp) = cur_endpoint.as_mut() { + endp.ssc = Some(SuperSpeedCmp::from(ssc.clone())); + } else { + error!("Found a superspeedcompanion descriptor before encountering any endpoint descriptor."); + } + }, + AnyDescriptor::SuperSpeedPlusCompanion(sscp) => { + if let Some(endp) = cur_endpoint.as_mut() { + endp.sspc = Some(SuperSpeedPlusIsochCmp::from(sscp.clone())); + } else { + error!("Found a superspeedpluscompanion descriptor before encountering any endpoint descriptor."); + } + }, + AnyDescriptor::Unknown(bytes) => { + // If we're processing an interface, add the desc to it, otherwise add it to the configuration + if cur_iface.is_none() { + unknown_descs.push(UnknownDesc {len: bytes[0], kind: bytes[1], all_bytes: bytes}); + } else { + iface_unknown_descs.push(UnknownDesc {len: bytes[0], kind: bytes[1], all_bytes: bytes}); + } + }, + _ => { + error!("Found unexpected descriptor {item:?} while parsing config descriptors, skipping"); + continue; } - - interface_descs.push( - self.new_if_desc(port_id, slot, idesc, endpoints, hid_descs, lang_id) - .await?, - ); - } else { - log::warn!("expected interface, got {:?}", item); - // TODO - //break; } } + // Push the last endpoint + if let Some(endp) = cur_endpoint{ + if !endpoints.contains(&endp) { + endpoints.push(endp); + } + } + + // Push the last interface + if let Some(idesc) = cur_iface { + let new_if_desc = self.new_if_desc(port_id, slot, idesc, endpoints, iface_unknown_descs, lang_id).await?; + if !interface_descs.contains(&new_if_desc) { + interface_descs.push(new_if_desc); + } + } + config_descs.push(ConfDesc { kind: desc.kind, configuration: if desc.configuration_str > 0 { @@ -1603,6 +1615,7 @@ impl Xhci { attributes: desc.attributes, max_power: desc.max_power, interface_descs, + unknown_descs }); }