Move report descriptor parsing into usbhid

This commit is contained in:
Antoine Reversat
2026-05-07 14:05:13 -04:00
parent e22712d920
commit f6bb61ba18
3 changed files with 97 additions and 5 deletions
+2
View File
@@ -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" }
+88
View File
@@ -0,0 +1,88 @@
use anyhow::{Result, anyhow};
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<Self> {
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<HidClassDescriptor> {
for desc in self.descriptors.iter() {
match desc.desc_type {
HidClassType::Report => return Ok(*desc),
_ => ()
}
}
return Err(anyhow!("No Report descriptor found"));
}
}
+7 -5
View File
@@ -1,4 +1,4 @@
use anyhow::{Context, Result};
use anyhow::{anyhow, Context, Result};
use std::{env, thread, time};
use inputd::ProducerHandle;
@@ -13,7 +13,10 @@ use xhcid_interface::{
XhciClientHandle,
};
use crate::descs::HidDescriptor;
mod reqs;
mod descs;
fn send_key_event(display: &mut ProducerHandle, usage_page: u16, usage: u16, pressed: bool) {
let scancode = match usage_page {
@@ -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