diff --git a/drivers/input/usbhidd/Cargo.toml b/drivers/input/usbhidd/Cargo.toml index 2c0cda1915..05bef7d12d 100644 --- a/drivers/input/usbhidd/Cargo.toml +++ b/drivers/input/usbhidd/Cargo.toml @@ -13,8 +13,10 @@ anyhow.workspace = true bitflags.workspace = true log.workspace = true orbclient.workspace = true +plain.workspace = true redox_syscall.workspace = true rehid = { git = "https://gitlab.redox-os.org/redox-os/rehid.git" } +smallvec.workspace = true xhcid = { path = "../../usb/xhcid" } common = { path = "../../common" } diff --git a/drivers/input/usbhidd/src/descs.rs b/drivers/input/usbhidd/src/descs.rs new file mode 100644 index 0000000000..23742fcd14 --- /dev/null +++ b/drivers/input/usbhidd/src/descs.rs @@ -0,0 +1,92 @@ +use anyhow::{anyhow, Result}; +use plain::Plain; +use smallvec::SmallVec; +use std::convert::TryInto; + +#[repr(u8)] +#[derive(Clone, Copy, Debug, Default)] +pub enum HidClassType { + #[default] + HID = 0x21, + Report, + Physical, +} + +#[repr(C, packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct HidClassDescriptor { + pub desc_type: HidClassType, + pub desc_len: u16, +} + +unsafe impl Plain for HidClassDescriptor {} + +#[derive(Clone, Debug, Default)] +pub struct HidDescriptor { + pub length: u8, + pub kind: u8, + pub hid_spec_release: u16, + pub country_code: u8, + pub num_descriptors: u8, + pub descriptors: SmallVec<[HidClassDescriptor; 1]>, +} + +impl HidDescriptor { + // Size of the fixed part of HidDescriptor + const HID_DESC_FIXED_SIZE: u8 = 6; + const HID_CLASS_DESC_SIZE: u8 = 3; + + pub fn from_bytes(bytes: &[u8]) -> Result { + let length = bytes[0]; + let kind = bytes[1]; + + // A valid descriptor has at least one class descriptor + if (length < Self::HID_DESC_FIXED_SIZE + Self::HID_CLASS_DESC_SIZE) { + return Err(anyhow!("Invalid length")); + } + + if (kind != HidClassType::HID as u8) { + return Err(anyhow!("This is not a hid descriptor")); + } + + let num_descriptors = bytes[5]; + + if (length != Self::HID_DESC_FIXED_SIZE + num_descriptors * Self::HID_CLASS_DESC_SIZE) { + return Err(anyhow!( + "Len doesn't match the given number of descriptors ({num_descriptors})" + )); + } + + let mut descriptors = + SmallVec::<[HidClassDescriptor; 1]>::with_capacity(num_descriptors as usize); + + for i in 0..num_descriptors { + match HidClassDescriptor::from_bytes( + &bytes[(Self::HID_DESC_FIXED_SIZE + i * Self::HID_CLASS_DESC_SIZE) as usize + ..(Self::HID_DESC_FIXED_SIZE + (i + 1) * Self::HID_CLASS_DESC_SIZE) as usize], + ) { + Ok(desc) => descriptors.push(*desc), + Err(e) => return Err(anyhow!("{e:?}")), + } + } + + Ok(Self { + length, + kind, + hid_spec_release: u16::from_ne_bytes(bytes[2..4].try_into()?), + country_code: bytes[4], + num_descriptors, + descriptors, + }) + } + + pub fn get_report_desc(&self) -> Result { + for desc in self.descriptors.iter() { + match desc.desc_type { + HidClassType::Report => return Ok(*desc), + _ => (), + } + } + return Err(anyhow!("No Report descriptor found")); + } +} diff --git a/drivers/input/usbhidd/src/main.rs b/drivers/input/usbhidd/src/main.rs index 15c5b77820..d49f1c1111 100644 --- a/drivers/input/usbhidd/src/main.rs +++ b/drivers/input/usbhidd/src/main.rs @@ -1,4 +1,4 @@ -use anyhow::{Context, Result}; +use anyhow::{anyhow, Context, Result}; use std::{env, thread, time}; use inputd::ProducerHandle; @@ -13,6 +13,9 @@ use xhcid_interface::{ XhciClientHandle, }; +use crate::descs::HidDescriptor; + +mod descs; mod reqs; fn send_key_event(display: &mut ProducerHandle, usage_page: u16, usage: u16, pressed: bool) { @@ -217,9 +220,9 @@ fn main() -> Result<()> { None } }); - let hid_desc = if_desc.hid_descs.iter().find_map(|hid_desc| { + let hid_desc = if_desc.unknown_descs.iter().find_map(|unknown_desc| { //TODO: should we do any filtering? - Some(hid_desc) + HidDescriptor::from_bytes(&unknown_desc.all_bytes).ok() })?; Some((if_desc.clone(), endp_desc_opt, hid_desc)) } else { @@ -246,8 +249,7 @@ fn main() -> Result<()> { // This sets all reports to a duration of 4ms reqs::set_idle(&handle, 1, 0, interface_num as u16).context("Failed to set idle")?; - let report_desc_len = hid_desc.desc_len; - assert_eq!(hid_desc.desc_ty, REPORT_DESC_TY); + let report_desc_len = hid_desc.get_report_desc()?.desc_len; let mut report_desc_bytes = vec![0u8; report_desc_len as usize]; handle 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..30ee55a5b2 100644 --- a/drivers/usb/xhcid/src/xhci/scheme.rs +++ b/drivers/usb/xhcid/src/xhci/scheme.rs @@ -477,21 +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 { Self { @@ -519,9 +504,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 +519,7 @@ impl AnyDescriptor { let kind = bytes[1]; if bytes.len() < len.into() { + error!("Parsed length is bigger than buffer len"); return None; } @@ -543,13 +529,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 +545,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 +564,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,53 +1521,105 @@ 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(); + debug!("Processing descriptor {item:?}"); - 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(); + 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); } } @@ -1603,6 +1637,7 @@ impl Xhci { attributes: desc.attributes, max_power: desc.max_power, interface_descs, + unknown_descs, }); }