Move report descriptor parsing into usbhid
This commit is contained in:
@@ -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" }
|
||||
|
||||
@@ -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"));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user