aboutsummaryrefslogtreecommitdiff
path: root/src/hid.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/hid.rs')
-rw-r--r--src/hid.rs65
1 files changed, 63 insertions, 2 deletions
diff --git a/src/hid.rs b/src/hid.rs
index 0bb8a11..a2adeb3 100644
--- a/src/hid.rs
+++ b/src/hid.rs
@@ -3,10 +3,12 @@
use usb_device::bus::{InterfaceNumber, StringIndex, UsbBus, UsbBusAllocator};
use usb_device::class::{ControlIn, ControlOut, UsbClass};
+use usb_device::control::{Recipient, Request, RequestType};
use usb_device::descriptor::DescriptorWriter;
use usb_device::endpoint::{EndpointAddress, EndpointIn};
-use usb_device::Result;
+use usb_device::{Result, UsbError};
+const SPECIFICATION_RELEASE: u16 = 0x111;
const INTERFACE_CLASS_HID: u8 = 0x03;
enum_u8! {
@@ -26,10 +28,21 @@ enum_u8! {
}
}
+enum_u8! {
+ #[derive(Debug, Clone, Copy)]
+ pub enum DescriptorType {
+ Hid = 0x21,
+ Report = 0x22,
+ Physical = 0x23,
+ }
+}
+
pub trait HidDevice {
fn subclass(&self) -> Subclass;
fn protocol(&self) -> Protocol;
+
+ fn report_descriptor(&self) -> &[u8];
}
pub struct HidClass<'a, B: UsbBus, D: HidDevice> {
@@ -48,6 +61,21 @@ impl<B: UsbBus, D: HidDevice> HidClass<'_, B, D> {
expect_interrupt_in_complete: false,
}
}
+
+ fn get_report_descriptor(&self, index: u8, buf: &mut [u8]) -> Result<usize> {
+ if index == 0 {
+ let report_descriptor = self.device.report_descriptor();
+ let len = report_descriptor.len();
+ if len > buf.len() {
+ Err(UsbError::BufferOverflow)
+ } else {
+ buf[0..len].copy_from_slice(report_descriptor);
+ Ok(len)
+ }
+ } else {
+ Err(UsbError::InvalidState)
+ }
+ }
}
impl<B: UsbBus, D: HidDevice> UsbClass<B> for HidClass<'_, B, D> {
@@ -64,6 +92,27 @@ impl<B: UsbBus, D: HidDevice> UsbClass<B> for HidClass<'_, B, D> {
self.device.subclass().into(),
self.device.protocol().into(),
)?;
+
+ let report_descriptor = self.device.report_descriptor();
+ let descriptor_len = report_descriptor.len();
+ if descriptor_len > u16::max_value() as usize {
+ return Err(UsbError::InvalidState);
+ }
+ let descriptor_len = (descriptor_len as u16).to_le_bytes();
+ let specification_release = SPECIFICATION_RELEASE.to_le_bytes();
+ writer.write(
+ DescriptorType::Hid.into(),
+ &[
+ specification_release[0], // bcdHID.lower
+ specification_release[1], // bcdHID.upper
+ 0, // bCountryCode: 0 = not supported
+ 1, // bNumDescriptors
+ DescriptorType::Report.into(), // bDescriptorType
+ descriptor_len[0], // bDescriptorLength.lower
+ descriptor_len[1], // bDescriptorLength.upper
+ ],
+ )?;
+
writer.endpoint(&self.endpoint_interrupt_in)?;
Ok(())
@@ -85,7 +134,19 @@ impl<B: UsbBus, D: HidDevice> UsbClass<B> for HidClass<'_, B, D> {
fn endpoint_out(&mut self, _addr: EndpointAddress) {}
- fn control_in(&mut self, _xfer: ControlIn<B>) {}
+ fn control_in(&mut self, xfer: ControlIn<B>) {
+ let req = xfer.request();
+ if req.request_type == RequestType::Standard
+ && req.recipient == Recipient::Interface
+ && req.request == Request::GET_DESCRIPTOR
+ {
+ let (dtype, index) = req.descriptor_type_index();
+ if dtype == DescriptorType::Report.into() {
+ xfer.accept(|mut buf| self.get_report_descriptor(index, &mut buf))
+ .ok();
+ }
+ }
+ }
fn control_out(&mut self, _xfer: ControlOut<B>) {}
}