aboutsummaryrefslogtreecommitdiff
path: root/src/hid.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/hid.rs')
-rw-r--r--src/hid.rs106
1 files changed, 93 insertions, 13 deletions
diff --git a/src/hid.rs b/src/hid.rs
index a2adeb3..79ba7f0 100644
--- a/src/hid.rs
+++ b/src/hid.rs
@@ -3,10 +3,13 @@
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::control;
+use usb_device::control::{Recipient, RequestType};
use usb_device::descriptor::DescriptorWriter;
use usb_device::endpoint::{EndpointAddress, EndpointIn};
-use usb_device::{Result, UsbError};
+use usb_device::UsbError;
+
+use crate::util::TryFrom;
const SPECIFICATION_RELEASE: u16 = 0x111;
const INTERFACE_CLASS_HID: u8 = 0x03;
@@ -37,12 +40,48 @@ enum_u8! {
}
}
+enum_u8! {
+ #[derive(Debug, Clone, Copy, PartialEq)]
+ pub enum Request {
+ GetReport = 0x01,
+ GetIdle = 0x02,
+ GetProtocol = 0x03,
+ SetReport = 0x09,
+ SetIdle = 0x0a,
+ SetProtocol = 0x0b,
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum ReportType {
+ Input,
+ Output,
+ Feature,
+ Reserved(u8),
+}
+
+impl From<u8> for ReportType {
+ fn from(val: u8) -> Self {
+ match val {
+ 1 => ReportType::Input,
+ 2 => ReportType::Output,
+ 3 => ReportType::Feature,
+ _ => ReportType::Reserved(val),
+ }
+ }
+}
+
pub trait HidDevice {
fn subclass(&self) -> Subclass;
fn protocol(&self) -> Protocol;
fn report_descriptor(&self) -> &[u8];
+
+ fn set_report(&mut self, report_type: ReportType, report_id: u8, data: &[u8])
+ -> Result<(), ()>;
+
+ fn get_report(&mut self, report_type: ReportType, report_id: u8) -> Result<&[u8], ()>;
}
pub struct HidClass<'a, B: UsbBus, D: HidDevice> {
@@ -62,7 +101,7 @@ impl<B: UsbBus, D: HidDevice> HidClass<'_, B, D> {
}
}
- fn get_report_descriptor(&self, index: u8, buf: &mut [u8]) -> Result<usize> {
+ fn get_report_descriptor(&self, index: u8, buf: &mut [u8]) -> usb_device::Result<usize> {
if index == 0 {
let report_descriptor = self.device.report_descriptor();
let len = report_descriptor.len();
@@ -76,6 +115,26 @@ impl<B: UsbBus, D: HidDevice> HidClass<'_, B, D> {
Err(UsbError::InvalidState)
}
}
+
+ fn get_report(&mut self, xfer: ControlIn<B>) {
+ let req = xfer.request();
+ let [report_type, report_id] = req.value.to_be_bytes();
+ let report_type = ReportType::from(report_type);
+ match self.device.get_report(report_type, report_id) {
+ Ok(data) => xfer.accept_with(data).ok(),
+ Err(()) => xfer.reject().ok(),
+ };
+ }
+
+ fn set_report(&mut self, xfer: ControlOut<B>) {
+ let req = xfer.request();
+ let [report_type, report_id] = req.value.to_be_bytes();
+ let report_type = ReportType::from(report_type);
+ match self.device.set_report(report_type, report_id, xfer.data()) {
+ Ok(()) => xfer.accept().ok(),
+ Err(()) => xfer.reject().ok(),
+ };
+ }
}
impl<B: UsbBus, D: HidDevice> UsbClass<B> for HidClass<'_, B, D> {
@@ -85,7 +144,10 @@ impl<B: UsbBus, D: HidDevice> UsbClass<B> for HidClass<'_, B, D> {
self.expect_interrupt_in_complete = false;
}
- fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
+ fn get_configuration_descriptors(
+ &self,
+ writer: &mut DescriptorWriter,
+ ) -> usb_device::Result<()> {
writer.interface(
self.interface,
INTERFACE_CLASS_HID,
@@ -136,17 +198,35 @@ impl<B: UsbBus, D: HidDevice> UsbClass<B> for HidClass<'_, B, D> {
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();
+ match (req.request_type, req.recipient) {
+ (RequestType::Standard, Recipient::Interface) => {
+ if req.request == control::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();
+ }
+ }
+ }
+ (RequestType::Class, Recipient::Interface) => {
+ if let Ok(request) = Request::try_from(req.request) {
+ if request == Request::GetReport {
+ self.get_report(xfer);
+ }
+ }
}
+ _ => {}
}
}
- fn control_out(&mut self, _xfer: ControlOut<B>) {}
+ fn control_out(&mut self, xfer: ControlOut<B>) {
+ let req = xfer.request();
+ if req.request_type == RequestType::Class && req.recipient == Recipient::Interface {
+ if let Ok(request) = Request::try_from(req.request) {
+ if request == Request::SetReport {
+ self.set_report(xfer);
+ }
+ }
+ }
+ }
}