aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb/src
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-usb/src')
-rw-r--r--embassy-usb/src/class/hid.rs134
1 files changed, 39 insertions, 95 deletions
diff --git a/embassy-usb/src/class/hid.rs b/embassy-usb/src/class/hid.rs
index b9830baeb..6723afbbc 100644
--- a/embassy-usb/src/class/hid.rs
+++ b/embassy-usb/src/class/hid.rs
@@ -8,8 +8,6 @@ use core::sync::atomic::{AtomicUsize, Ordering};
8use ssmarshal::serialize; 8use ssmarshal::serialize;
9#[cfg(feature = "usbd-hid")] 9#[cfg(feature = "usbd-hid")]
10use usbd_hid::descriptor::AsInputReport; 10use usbd_hid::descriptor::AsInputReport;
11#[cfg(feature = "usbd-hid")]
12use usbd_hid::hid_class::HidProtocolMode;
13 11
14use crate::control::{InResponse, OutResponse, Recipient, Request, RequestType}; 12use crate::control::{InResponse, OutResponse, Recipient, Request, RequestType};
15use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; 13use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
@@ -18,13 +16,6 @@ use crate::{Builder, Handler};
18 16
19const USB_CLASS_HID: u8 = 0x03; 17const USB_CLASS_HID: u8 = 0x03;
20 18
21const USB_SUBCLASS_REPORT_ONLY: u8 = 0x00;
22const USB_SUBCLASS_BOOT_OR_REPORT: u8 = 0x01;
23
24const USB_PROTOCOL_NONE: u8 = 0x00;
25const USB_PROTOCOL_KEYBOARD: u8 = 0x01;
26const USB_PROTOCOL_MOUSE: u8 = 0x02;
27
28// HID 19// HID
29const HID_DESC_DESCTYPE_HID: u8 = 0x21; 20const HID_DESC_DESCTYPE_HID: u8 = 0x21;
30const HID_DESC_DESCTYPE_HID_REPORT: u8 = 0x22; 21const HID_DESC_DESCTYPE_HID_REPORT: u8 = 0x22;
@@ -40,7 +31,6 @@ const HID_REQ_SET_PROTOCOL: u8 = 0x0b;
40 31
41/// Get/Set Protocol mapping 32/// Get/Set Protocol mapping
42/// See (7.2.5 and 7.2.6): <https://www.usb.org/sites/default/files/hid1_11.pdf> 33/// See (7.2.5 and 7.2.6): <https://www.usb.org/sites/default/files/hid1_11.pdf>
43#[cfg(not(feature = "usbd-hid"))]
44#[derive(Copy, Clone, Debug, PartialEq, Eq)] 34#[derive(Copy, Clone, Debug, PartialEq, Eq)]
45#[cfg_attr(feature = "defmt", derive(defmt::Format))] 35#[cfg_attr(feature = "defmt", derive(defmt::Format))]
46#[repr(u8)] 36#[repr(u8)]
@@ -51,7 +41,6 @@ pub enum HidProtocolMode {
51 Report = 1, 41 Report = 1,
52} 42}
53 43
54#[cfg(not(feature = "usbd-hid"))]
55impl From<u8> for HidProtocolMode { 44impl From<u8> for HidProtocolMode {
56 fn from(mode: u8) -> HidProtocolMode { 45 fn from(mode: u8) -> HidProtocolMode {
57 if mode == HidProtocolMode::Boot as u8 { 46 if mode == HidProtocolMode::Boot as u8 {
@@ -62,6 +51,30 @@ impl From<u8> for HidProtocolMode {
62 } 51 }
63} 52}
64 53
54/// USB HID interface subclass values.
55#[derive(Copy, Clone, Debug, PartialEq, Eq)]
56#[cfg_attr(feature = "defmt", derive(defmt::Format))]
57#[repr(u8)]
58pub enum HidSubclass {
59 /// Only report mode is supported.
60 ReportOnly = 0,
61 /// Both boot and report mode are supported.
62 ReportOrBoot = 1,
63}
64
65/// USB HID protocol values.
66#[derive(Copy, Clone, Debug, PartialEq, Eq)]
67#[cfg_attr(feature = "defmt", derive(defmt::Format))]
68#[repr(u8)]
69pub enum HidBootProtocol {
70 /// No specific boot protocol.
71 None = 0,
72 /// Boot protocol keyboard.
73 Keyboard = 1,
74 /// Boot protocol mouse.
75 Mouse = 2,
76}
77
65/// Configuration for the HID class. 78/// Configuration for the HID class.
66pub struct Config<'d> { 79pub struct Config<'d> {
67 /// HID report descriptor. 80 /// HID report descriptor.
@@ -79,6 +92,12 @@ pub struct Config<'d> {
79 92
80 /// Max packet size for both the IN and OUT endpoints. 93 /// Max packet size for both the IN and OUT endpoints.
81 pub max_packet_size: u16, 94 pub max_packet_size: u16,
95
96 /// The HID subclass of this interface
97 pub hid_subclass: HidSubclass,
98
99 /// The HID boot protocol of this interface
100 pub hid_boot_protocol: HidBootProtocol,
82} 101}
83 102
84/// Report ID 103/// Report ID
@@ -137,15 +156,18 @@ fn build<'d, D: Driver<'d>>(
137 state: &'d mut State<'d>, 156 state: &'d mut State<'d>,
138 config: Config<'d>, 157 config: Config<'d>,
139 with_out_endpoint: bool, 158 with_out_endpoint: bool,
140 usb_subclass: u8,
141 usb_protocol: u8,
142) -> (Option<D::EndpointOut>, D::EndpointIn, &'d AtomicUsize) { 159) -> (Option<D::EndpointOut>, D::EndpointIn, &'d AtomicUsize) {
143 let len = config.report_descriptor.len(); 160 let len = config.report_descriptor.len();
144 161
145 let mut func = builder.function(USB_CLASS_HID, usb_subclass, usb_protocol); 162 let mut func = builder.function(USB_CLASS_HID, config.hid_subclass as u8, config.hid_boot_protocol as u8);
146 let mut iface = func.interface(); 163 let mut iface = func.interface();
147 let if_num = iface.interface_number(); 164 let if_num = iface.interface_number();
148 let mut alt = iface.alt_setting(USB_CLASS_HID, usb_subclass, usb_protocol, None); 165 let mut alt = iface.alt_setting(
166 USB_CLASS_HID,
167 config.hid_subclass as u8,
168 config.hid_boot_protocol as u8,
169 None,
170 );
149 171
150 // HID descriptor 172 // HID descriptor
151 alt.descriptor( 173 alt.descriptor(
@@ -193,42 +215,7 @@ impl<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N: usize> HidReaderWrit
193 /// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only. 215 /// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only.
194 /// 216 ///
195 pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { 217 pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self {
196 HidReaderWriter::_new(builder, state, config, USB_SUBCLASS_REPORT_ONLY, USB_PROTOCOL_NONE) 218 let (ep_out, ep_in, offset) = build(builder, state, config, true);
197 }
198
199 /// Creates a new `HidReaderWriter` for a HID Mouse, with support for the BOOT protocol mode.
200 ///
201 /// This will allocate one IN and one OUT endpoints. If you only need writing (sending)
202 /// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only.
203 ///
204 pub fn new_mouse(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self {
205 HidReaderWriter::_new(builder, state, config, USB_SUBCLASS_BOOT_OR_REPORT, USB_PROTOCOL_MOUSE)
206 }
207
208 /// Creates a new `HidReaderWriter` for a HID Keyboard, with support for the BOOT protocol mode.
209 ///
210 /// This will allocate one IN and one OUT endpoints. If you only need writing (sending)
211 /// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only.
212 ///
213 pub fn new_keyboard(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self {
214 HidReaderWriter::_new(
215 builder,
216 state,
217 config,
218 USB_SUBCLASS_BOOT_OR_REPORT,
219 USB_PROTOCOL_KEYBOARD,
220 )
221 }
222
223 /// Private helper function to create a new `HidReaderWriter`.
224 fn _new(
225 builder: &mut Builder<'d, D>,
226 state: &'d mut State<'d>,
227 config: Config<'d>,
228 usb_subclass: u8,
229 usb_protocol: u8,
230 ) -> Self {
231 let (ep_out, ep_in, offset) = build(builder, state, config, true, usb_subclass, usb_protocol);
232 219
233 Self { 220 Self {
234 reader: HidReader { 221 reader: HidReader {
@@ -317,50 +304,7 @@ impl<'d, D: Driver<'d>, const N: usize> HidWriter<'d, D, N> {
317 /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for 304 /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for
318 /// high performance uses, and a value of 255 is good for best-effort usecases. 305 /// high performance uses, and a value of 255 is good for best-effort usecases.
319 pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { 306 pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self {
320 HidWriter::_new(builder, state, config, USB_SUBCLASS_REPORT_ONLY, USB_PROTOCOL_NONE) 307 let (ep_out, ep_in, _offset) = build(builder, state, config, false);
321 }
322
323 /// Creates a new `HidWriter` for a HID Mouse, with support for the BOOT protocol mode.
324 ///
325 /// This will allocate one IN endpoint only, so the host won't be able to send
326 /// reports to us. If you need that, consider using [`HidReaderWriter::new`] instead.
327 ///
328 /// poll_ms configures how frequently the host should poll for reading/writing
329 /// HID reports. A lower value means better throughput & latency, at the expense
330 /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for
331 /// high performance uses, and a value of 255 is good for best-effort usecases.
332 pub fn new_mouse(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self {
333 HidWriter::_new(builder, state, config, USB_SUBCLASS_BOOT_OR_REPORT, USB_PROTOCOL_MOUSE)
334 }
335
336 /// Creates a new `HidWriter` for a HID Keyboard, with support for the BOOT protocol mode.
337 ///
338 /// This will allocate one IN endpoint only, so the host won't be able to send
339 /// reports to us. If you need that, consider using [`HidReaderWriter::new`] instead.
340 ///
341 /// poll_ms configures how frequently the host should poll for reading/writing
342 /// HID reports. A lower value means better throughput & latency, at the expense
343 /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for
344 /// high performance uses, and a value of 255 is good for best-effort usecases.
345 pub fn new_keyboard(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self {
346 HidWriter::_new(
347 builder,
348 state,
349 config,
350 USB_SUBCLASS_BOOT_OR_REPORT,
351 USB_PROTOCOL_KEYBOARD,
352 )
353 }
354
355 /// Private helper function to create a new `HidWriter`.
356 pub fn _new(
357 builder: &mut Builder<'d, D>,
358 state: &'d mut State<'d>,
359 config: Config<'d>,
360 usb_subclass: u8,
361 usb_protocol: u8,
362 ) -> Self {
363 let (ep_out, ep_in, _offset) = build(builder, state, config, false, usb_subclass, usb_protocol);
364 308
365 assert!(ep_out.is_none()); 309 assert!(ep_out.is_none());
366 310