From 5f5f71efd09266eccb0ab7e4048994f244eed5ae Mon Sep 17 00:00:00 2001 From: matteo Date: Sun, 21 Sep 2025 17:52:14 +0200 Subject: Add support for changing hid protocol mode --- embassy-usb/CHANGELOG.md | 4 ++++ embassy-usb/Cargo.toml | 2 +- embassy-usb/src/class/hid.rs | 39 ++++++++++++++++++++++++++++++++------- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/embassy-usb/CHANGELOG.md b/embassy-usb/CHANGELOG.md index 0a30bc24b..891388122 100644 --- a/embassy-usb/CHANGELOG.md +++ b/embassy-usb/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +## 0.5.2 - Unreleased + +- `hid`: Add USB HID Boot Protocol Mode support + ## 0.5.1 - 2025-08-26 ## 0.5.0 - 2025-07-16 diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index e309eec93..fde603df0 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-usb" -version = "0.5.1" +version = "0.5.2" edition = "2021" license = "MIT OR Apache-2.0" description = "Async USB device stack for embedded devices in Rust." diff --git a/embassy-usb/src/class/hid.rs b/embassy-usb/src/class/hid.rs index 182e1f83f..8df23b384 100644 --- a/embassy-usb/src/class/hid.rs +++ b/embassy-usb/src/class/hid.rs @@ -8,6 +8,7 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use ssmarshal::serialize; #[cfg(feature = "usbd-hid")] use usbd_hid::descriptor::AsInputReport; +use usbd_hid::hid_class::HidProtocolMode; use crate::control::{InResponse, OutResponse, Recipient, Request, RequestType}; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; @@ -389,6 +390,23 @@ pub trait RequestHandler { OutResponse::Rejected } + /// Gets the current hid protocol. + /// + /// Returns `Report` protocol by default. + fn get_protocol(&self) -> HidProtocolMode { + HidProtocolMode::Report + } + + /// Sets the current hid protocol to `protocol`. + /// + /// Accepts only `Report` protocol by default. + fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse { + match protocol { + HidProtocolMode::Report => OutResponse::Accepted, + HidProtocolMode::Boot => OutResponse::Rejected, + } + } + /// Get the idle rate for `id`. /// /// If `id` is `None`, get the idle rate for all reports. Returning `None` @@ -482,11 +500,14 @@ impl<'d> Handler for Control<'d> { _ => Some(OutResponse::Rejected), }, HID_REQ_SET_PROTOCOL => { - if req.value == 1 { - Some(OutResponse::Accepted) - } else { - warn!("HID Boot Protocol is unsupported."); - Some(OutResponse::Rejected) // UNSUPPORTED: Boot Protocol + let hid_protocol = HidProtocolMode::from(req.value as u8); + match (self.request_handler.as_mut(), hid_protocol) { + (Some(request_handler), hid_protocol) => Some(request_handler.set_protocol(hid_protocol)), + (None, HidProtocolMode::Report) => Some(OutResponse::Accepted), + (None, HidProtocolMode::Boot) => { + warn!("HID Boot Protocol is unsupported."); + Some(OutResponse::Rejected) // UNSUPPORTED: Boot Protocol + } } } _ => Some(OutResponse::Rejected), @@ -539,8 +560,12 @@ impl<'d> Handler for Control<'d> { } } HID_REQ_GET_PROTOCOL => { - // UNSUPPORTED: Boot Protocol - buf[0] = 1; + if let Some(request_handler) = self.request_handler.as_mut() { + buf[0] = request_handler.get_protocol() as u8; + } else { + // Return `Report` protocol by default + buf[0] = HidProtocolMode::Report as u8; + } Some(InResponse::Accepted(&buf[0..1])) } _ => Some(InResponse::Rejected), -- cgit