aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb/src/class
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-02-07 22:49:14 +0100
committerDario Nieuwenhuis <[email protected]>2023-02-08 00:17:08 +0100
commit3af991ab63d14cfad6f50d28bfb944d1895d1c70 (patch)
tree575fecf6f47fbfd7116070aff2ffd5f4e84c7cf1 /embassy-usb/src/class
parent1d841cc8ac74feacc4d231958ce2c46419ae3bda (diff)
usb: unify ControlHandler+DeviceStateHandler, route all control requests to all handlers.
- Allows classes to handle vendor requests. - Allows classes to use a single handler for multiple interfaces. - Allows classes to access the other events (previously only `reset` was available).
Diffstat (limited to 'embassy-usb/src/class')
-rw-r--r--embassy-usb/src/class/cdc_acm.rs50
-rw-r--r--embassy-usb/src/class/cdc_ncm/mod.rs83
-rw-r--r--embassy-usb/src/class/hid.rs170
3 files changed, 179 insertions, 124 deletions
diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs
index fb9eaeca7..ff82ad40d 100644
--- a/embassy-usb/src/class/cdc_acm.rs
+++ b/embassy-usb/src/class/cdc_acm.rs
@@ -6,10 +6,10 @@ use core::sync::atomic::{AtomicBool, Ordering};
6 6
7use embassy_sync::blocking_mutex::CriticalSectionMutex; 7use embassy_sync::blocking_mutex::CriticalSectionMutex;
8 8
9use crate::control::{self, ControlHandler, InResponse, OutResponse, Request}; 9use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType};
10use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; 10use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
11use crate::types::*; 11use crate::types::*;
12use crate::Builder; 12use crate::{Builder, Handler};
13 13
14/// This should be used as `device_class` when building the `UsbDevice`. 14/// This should be used as `device_class` when building the `UsbDevice`.
15pub const USB_CLASS_CDC: u8 = 0x02; 15pub const USB_CLASS_CDC: u8 = 0x02;
@@ -67,6 +67,7 @@ pub struct CdcAcmClass<'d, D: Driver<'d>> {
67} 67}
68 68
69struct Control<'a> { 69struct Control<'a> {
70 comm_if: InterfaceNumber,
70 shared: &'a ControlShared, 71 shared: &'a ControlShared,
71} 72}
72 73
@@ -98,7 +99,7 @@ impl<'a> Control<'a> {
98 } 99 }
99} 100}
100 101
101impl<'d> ControlHandler for Control<'d> { 102impl<'d> Handler for Control<'d> {
102 fn reset(&mut self) { 103 fn reset(&mut self) {
103 let shared = self.shared(); 104 let shared = self.shared();
104 shared.line_coding.lock(|x| x.set(LineCoding::default())); 105 shared.line_coding.lock(|x| x.set(LineCoding::default()));
@@ -106,12 +107,18 @@ impl<'d> ControlHandler for Control<'d> {
106 shared.rts.store(false, Ordering::Relaxed); 107 shared.rts.store(false, Ordering::Relaxed);
107 } 108 }
108 109
109 fn control_out(&mut self, req: control::Request, data: &[u8]) -> OutResponse { 110 fn control_out(&mut self, req: control::Request, data: &[u8]) -> Option<OutResponse> {
111 if (req.request_type, req.recipient, req.index)
112 != (RequestType::Class, Recipient::Interface, self.comm_if.0 as u16)
113 {
114 return None;
115 }
116
110 match req.request { 117 match req.request {
111 REQ_SEND_ENCAPSULATED_COMMAND => { 118 REQ_SEND_ENCAPSULATED_COMMAND => {
112 // We don't actually support encapsulated commands but pretend we do for standards 119 // We don't actually support encapsulated commands but pretend we do for standards
113 // compatibility. 120 // compatibility.
114 OutResponse::Accepted 121 Some(OutResponse::Accepted)
115 } 122 }
116 REQ_SET_LINE_CODING if data.len() >= 7 => { 123 REQ_SET_LINE_CODING if data.len() >= 7 => {
117 let coding = LineCoding { 124 let coding = LineCoding {
@@ -123,7 +130,7 @@ impl<'d> ControlHandler for Control<'d> {
123 self.shared().line_coding.lock(|x| x.set(coding)); 130 self.shared().line_coding.lock(|x| x.set(coding));
124 debug!("Set line coding to: {:?}", coding); 131 debug!("Set line coding to: {:?}", coding);
125 132
126 OutResponse::Accepted 133 Some(OutResponse::Accepted)
127 } 134 }
128 REQ_SET_CONTROL_LINE_STATE => { 135 REQ_SET_CONTROL_LINE_STATE => {
129 let dtr = (req.value & 0x0001) != 0; 136 let dtr = (req.value & 0x0001) != 0;
@@ -134,13 +141,19 @@ impl<'d> ControlHandler for Control<'d> {
134 shared.rts.store(rts, Ordering::Relaxed); 141 shared.rts.store(rts, Ordering::Relaxed);
135 debug!("Set dtr {}, rts {}", dtr, rts); 142 debug!("Set dtr {}, rts {}", dtr, rts);
136 143
137 OutResponse::Accepted 144 Some(OutResponse::Accepted)
138 } 145 }
139 _ => OutResponse::Rejected, 146 _ => Some(OutResponse::Rejected),
140 } 147 }
141 } 148 }
142 149
143 fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> { 150 fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option<InResponse<'a>> {
151 if (req.request_type, req.recipient, req.index)
152 != (RequestType::Class, Recipient::Interface, self.comm_if.0 as u16)
153 {
154 return None;
155 }
156
144 match req.request { 157 match req.request {
145 // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below. 158 // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below.
146 REQ_GET_LINE_CODING if req.length == 7 => { 159 REQ_GET_LINE_CODING if req.length == 7 => {
@@ -151,9 +164,9 @@ impl<'d> ControlHandler for Control<'d> {
151 buf[4] = coding.stop_bits as u8; 164 buf[4] = coding.stop_bits as u8;
152 buf[5] = coding.parity_type as u8; 165 buf[5] = coding.parity_type as u8;
153 buf[6] = coding.data_bits; 166 buf[6] = coding.data_bits;
154 InResponse::Accepted(&buf[0..7]) 167 Some(InResponse::Accepted(&buf[0..7]))
155 } 168 }
156 _ => InResponse::Rejected, 169 _ => Some(InResponse::Rejected),
157 } 170 }
158 } 171 }
159} 172}
@@ -162,17 +175,12 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
162 /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For 175 /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For
163 /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64. 176 /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64.
164 pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, max_packet_size: u16) -> Self { 177 pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, max_packet_size: u16) -> Self {
165 let control = state.control.write(Control { shared: &state.shared });
166
167 let control_shared = &state.shared;
168
169 assert!(builder.control_buf_len() >= 7); 178 assert!(builder.control_buf_len() >= 7);
170 179
171 let mut func = builder.function(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE); 180 let mut func = builder.function(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE);
172 181
173 // Control interface 182 // Control interface
174 let mut iface = func.interface(); 183 let mut iface = func.interface();
175 iface.handler(control);
176 let comm_if = iface.interface_number(); 184 let comm_if = iface.interface_number();
177 let data_if = u8::from(comm_if) + 1; 185 let data_if = u8::from(comm_if) + 1;
178 let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE, None); 186 let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE, None);
@@ -213,6 +221,16 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
213 let read_ep = alt.endpoint_bulk_out(max_packet_size); 221 let read_ep = alt.endpoint_bulk_out(max_packet_size);
214 let write_ep = alt.endpoint_bulk_in(max_packet_size); 222 let write_ep = alt.endpoint_bulk_in(max_packet_size);
215 223
224 drop(func);
225
226 let control = state.control.write(Control {
227 shared: &state.shared,
228 comm_if,
229 });
230 builder.handler(control);
231
232 let control_shared = &state.shared;
233
216 CdcAcmClass { 234 CdcAcmClass {
217 _comm_ep: comm_ep, 235 _comm_ep: comm_ep,
218 _data_if: data_if, 236 _data_if: data_if,
diff --git a/embassy-usb/src/class/cdc_ncm/mod.rs b/embassy-usb/src/class/cdc_ncm/mod.rs
index d6c7d37e6..262499ccb 100644
--- a/embassy-usb/src/class/cdc_ncm/mod.rs
+++ b/embassy-usb/src/class/cdc_ncm/mod.rs
@@ -17,10 +17,10 @@
17use core::intrinsics::copy_nonoverlapping; 17use core::intrinsics::copy_nonoverlapping;
18use core::mem::{size_of, MaybeUninit}; 18use core::mem::{size_of, MaybeUninit};
19 19
20use crate::control::{self, ControlHandler, InResponse, OutResponse, Request}; 20use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType};
21use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; 21use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
22use crate::types::*; 22use crate::types::*;
23use crate::Builder; 23use crate::{Builder, Handler};
24 24
25pub mod embassy_net; 25pub mod embassy_net;
26 26
@@ -117,8 +117,7 @@ fn byteify<T>(buf: &mut [u8], data: T) -> &[u8] {
117 117
118/// Internal state for the CDC-NCM class. 118/// Internal state for the CDC-NCM class.
119pub struct State<'a> { 119pub struct State<'a> {
120 comm_control: MaybeUninit<CommControl<'a>>, 120 control: MaybeUninit<Control<'a>>,
121 data_control: MaybeUninit<DataControl>,
122 shared: ControlShared, 121 shared: ControlShared,
123} 122}
124 123
@@ -126,8 +125,7 @@ impl<'a> State<'a> {
126 /// Create a new `State`. 125 /// Create a new `State`.
127 pub fn new() -> Self { 126 pub fn new() -> Self {
128 Self { 127 Self {
129 comm_control: MaybeUninit::uninit(), 128 control: MaybeUninit::uninit(),
130 data_control: MaybeUninit::uninit(),
131 shared: Default::default(), 129 shared: Default::default(),
132 } 130 }
133 } 131 }
@@ -144,29 +142,55 @@ impl Default for ControlShared {
144 } 142 }
145} 143}
146 144
147struct CommControl<'a> { 145struct Control<'a> {
148 mac_addr_string: StringIndex, 146 mac_addr_string: StringIndex,
149 shared: &'a ControlShared, 147 shared: &'a ControlShared,
150 mac_addr_str: [u8; 12], 148 mac_addr_str: [u8; 12],
149 comm_if: InterfaceNumber,
150 data_if: InterfaceNumber,
151} 151}
152 152
153impl<'d> ControlHandler for CommControl<'d> { 153impl<'d> Handler for Control<'d> {
154 fn control_out(&mut self, req: control::Request, _data: &[u8]) -> OutResponse { 154 fn set_alternate_setting(&mut self, iface: InterfaceNumber, alternate_setting: u8) {
155 if iface != self.data_if {
156 return;
157 }
158
159 match alternate_setting {
160 ALTERNATE_SETTING_ENABLED => info!("ncm: interface enabled"),
161 ALTERNATE_SETTING_DISABLED => info!("ncm: interface disabled"),
162 _ => unreachable!(),
163 }
164 }
165
166 fn control_out(&mut self, req: control::Request, _data: &[u8]) -> Option<OutResponse> {
167 if (req.request_type, req.recipient, req.index)
168 != (RequestType::Class, Recipient::Interface, self.comm_if.0 as u16)
169 {
170 return None;
171 }
172
155 match req.request { 173 match req.request {
156 REQ_SEND_ENCAPSULATED_COMMAND => { 174 REQ_SEND_ENCAPSULATED_COMMAND => {
157 // We don't actually support encapsulated commands but pretend we do for standards 175 // We don't actually support encapsulated commands but pretend we do for standards
158 // compatibility. 176 // compatibility.
159 OutResponse::Accepted 177 Some(OutResponse::Accepted)
160 } 178 }
161 REQ_SET_NTB_INPUT_SIZE => { 179 REQ_SET_NTB_INPUT_SIZE => {
162 // TODO 180 // TODO
163 OutResponse::Accepted 181 Some(OutResponse::Accepted)
164 } 182 }
165 _ => OutResponse::Rejected, 183 _ => Some(OutResponse::Rejected),
166 } 184 }
167 } 185 }
168 186
169 fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> { 187 fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option<InResponse<'a>> {
188 if (req.request_type, req.recipient, req.index)
189 != (RequestType::Class, Recipient::Interface, self.comm_if.0 as u16)
190 {
191 return None;
192 }
193
170 match req.request { 194 match req.request {
171 REQ_GET_NTB_PARAMETERS => { 195 REQ_GET_NTB_PARAMETERS => {
172 let res = NtbParameters { 196 let res = NtbParameters {
@@ -187,9 +211,9 @@ impl<'d> ControlHandler for CommControl<'d> {
187 max_datagram_count: 1, // We only decode 1 packet per NTB 211 max_datagram_count: 1, // We only decode 1 packet per NTB
188 }, 212 },
189 }; 213 };
190 InResponse::Accepted(byteify(buf, res)) 214 Some(InResponse::Accepted(byteify(buf, res)))
191 } 215 }
192 _ => InResponse::Rejected, 216 _ => Some(InResponse::Rejected),
193 } 217 }
194 } 218 }
195 219
@@ -214,18 +238,6 @@ impl<'d> ControlHandler for CommControl<'d> {
214 } 238 }
215} 239}
216 240
217struct DataControl {}
218
219impl ControlHandler for DataControl {
220 fn set_alternate_setting(&mut self, alternate_setting: u8) {
221 match alternate_setting {
222 ALTERNATE_SETTING_ENABLED => info!("ncm: interface enabled"),
223 ALTERNATE_SETTING_DISABLED => info!("ncm: interface disabled"),
224 _ => unreachable!(),
225 }
226 }
227}
228
229/// CDC-NCM class 241/// CDC-NCM class
230pub struct CdcNcmClass<'d, D: Driver<'d>> { 242pub struct CdcNcmClass<'d, D: Driver<'d>> {
231 _comm_if: InterfaceNumber, 243 _comm_if: InterfaceNumber,
@@ -253,11 +265,6 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
253 // Control interface 265 // Control interface
254 let mut iface = func.interface(); 266 let mut iface = func.interface();
255 let mac_addr_string = iface.string(); 267 let mac_addr_string = iface.string();
256 iface.handler(state.comm_control.write(CommControl {
257 mac_addr_string,
258 shared: &state.shared,
259 mac_addr_str: [0; 12],
260 }));
261 let comm_if = iface.interface_number(); 268 let comm_if = iface.interface_number();
262 let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_NCM, CDC_PROTOCOL_NONE, None); 269 let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_NCM, CDC_PROTOCOL_NONE, None);
263 270
@@ -307,13 +314,23 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
307 314
308 // Data interface 315 // Data interface
309 let mut iface = func.interface(); 316 let mut iface = func.interface();
310 iface.handler(state.data_control.write(DataControl {}));
311 let data_if = iface.interface_number(); 317 let data_if = iface.interface_number();
312 let _alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None); 318 let _alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None);
313 let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None); 319 let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None);
314 let read_ep = alt.endpoint_bulk_out(max_packet_size); 320 let read_ep = alt.endpoint_bulk_out(max_packet_size);
315 let write_ep = alt.endpoint_bulk_in(max_packet_size); 321 let write_ep = alt.endpoint_bulk_in(max_packet_size);
316 322
323 drop(func);
324
325 let control = state.control.write(Control {
326 mac_addr_string,
327 shared: &state.shared,
328 mac_addr_str: [0; 12],
329 comm_if,
330 data_if,
331 });
332 builder.handler(control);
333
317 CdcNcmClass { 334 CdcNcmClass {
318 _comm_if: comm_if, 335 _comm_if: comm_if,
319 comm_ep, 336 comm_ep,
diff --git a/embassy-usb/src/class/hid.rs b/embassy-usb/src/class/hid.rs
index 0283c1124..974268c62 100644
--- a/embassy-usb/src/class/hid.rs
+++ b/embassy-usb/src/class/hid.rs
@@ -9,9 +9,10 @@ use ssmarshal::serialize;
9#[cfg(feature = "usbd-hid")] 9#[cfg(feature = "usbd-hid")]
10use usbd_hid::descriptor::AsInputReport; 10use usbd_hid::descriptor::AsInputReport;
11 11
12use crate::control::{ControlHandler, InResponse, OutResponse, Request, RequestType}; 12use crate::control::{InResponse, OutResponse, Recipient, Request, RequestType};
13use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; 13use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
14use crate::Builder; 14use crate::types::InterfaceNumber;
15use crate::{Builder, Handler};
15 16
16const USB_CLASS_HID: u8 = 0x03; 17const USB_CLASS_HID: u8 = 0x03;
17const USB_SUBCLASS_NONE: u8 = 0x00; 18const USB_SUBCLASS_NONE: u8 = 0x00;
@@ -100,17 +101,11 @@ fn build<'d, D: Driver<'d>>(
100 config: Config<'d>, 101 config: Config<'d>,
101 with_out_endpoint: bool, 102 with_out_endpoint: bool,
102) -> (Option<D::EndpointOut>, D::EndpointIn, &'d AtomicUsize) { 103) -> (Option<D::EndpointOut>, D::EndpointIn, &'d AtomicUsize) {
103 let control = state.control.write(Control::new(
104 config.report_descriptor,
105 config.request_handler,
106 &state.out_report_offset,
107 ));
108
109 let len = config.report_descriptor.len(); 104 let len = config.report_descriptor.len();
110 105
111 let mut func = builder.function(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE); 106 let mut func = builder.function(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE);
112 let mut iface = func.interface(); 107 let mut iface = func.interface();
113 iface.handler(control); 108 let if_num = iface.interface_number();
114 let mut alt = iface.alt_setting(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE, None); 109 let mut alt = iface.alt_setting(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE, None);
115 110
116 // HID descriptor 111 // HID descriptor
@@ -139,6 +134,16 @@ fn build<'d, D: Driver<'d>>(
139 None 134 None
140 }; 135 };
141 136
137 drop(func);
138
139 let control = state.control.write(Control::new(
140 if_num,
141 config.report_descriptor,
142 config.request_handler,
143 &state.out_report_offset,
144 ));
145 builder.handler(control);
146
142 (ep_out, ep_in, &state.out_report_offset) 147 (ep_out, ep_in, &state.out_report_offset)
143} 148}
144 149
@@ -400,6 +405,7 @@ pub trait RequestHandler {
400} 405}
401 406
402struct Control<'d> { 407struct Control<'d> {
408 if_num: InterfaceNumber,
403 report_descriptor: &'d [u8], 409 report_descriptor: &'d [u8],
404 request_handler: Option<&'d dyn RequestHandler>, 410 request_handler: Option<&'d dyn RequestHandler>,
405 out_report_offset: &'d AtomicUsize, 411 out_report_offset: &'d AtomicUsize,
@@ -408,11 +414,13 @@ struct Control<'d> {
408 414
409impl<'d> Control<'d> { 415impl<'d> Control<'d> {
410 fn new( 416 fn new(
417 if_num: InterfaceNumber,
411 report_descriptor: &'d [u8], 418 report_descriptor: &'d [u8],
412 request_handler: Option<&'d dyn RequestHandler>, 419 request_handler: Option<&'d dyn RequestHandler>,
413 out_report_offset: &'d AtomicUsize, 420 out_report_offset: &'d AtomicUsize,
414 ) -> Self { 421 ) -> Self {
415 Control { 422 Control {
423 if_num,
416 report_descriptor, 424 report_descriptor,
417 request_handler, 425 request_handler,
418 out_report_offset, 426 out_report_offset,
@@ -438,88 +446,100 @@ impl<'d> Control<'d> {
438 } 446 }
439} 447}
440 448
441impl<'d> ControlHandler for Control<'d> { 449impl<'d> Handler for Control<'d> {
442 fn reset(&mut self) { 450 fn reset(&mut self) {
443 self.out_report_offset.store(0, Ordering::Release); 451 self.out_report_offset.store(0, Ordering::Release);
444 } 452 }
445 453
446 fn get_descriptor<'a>(&'a mut self, req: Request, _buf: &'a mut [u8]) -> InResponse<'a> { 454 fn control_out(&mut self, req: Request, data: &[u8]) -> Option<OutResponse> {
447 match (req.value >> 8) as u8 { 455 if (req.request_type, req.recipient, req.index)
448 HID_DESC_DESCTYPE_HID_REPORT => InResponse::Accepted(self.report_descriptor), 456 != (RequestType::Class, Recipient::Interface, self.if_num.0 as u16)
449 HID_DESC_DESCTYPE_HID => InResponse::Accepted(&self.hid_descriptor), 457 {
450 _ => InResponse::Rejected, 458 return None;
451 } 459 }
452 }
453 460
454 fn control_out(&mut self, req: Request, data: &[u8]) -> OutResponse {
455 trace!("HID control_out {:?} {=[u8]:x}", req, data); 461 trace!("HID control_out {:?} {=[u8]:x}", req, data);
456 if let RequestType::Class = req.request_type { 462 match req.request {
457 match req.request { 463 HID_REQ_SET_IDLE => {
458 HID_REQ_SET_IDLE => { 464 if let Some(handler) = self.request_handler {
459 if let Some(handler) = self.request_handler { 465 let id = req.value as u8;
460 let id = req.value as u8; 466 let id = (id != 0).then(|| ReportId::In(id));
461 let id = (id != 0).then(|| ReportId::In(id)); 467 let dur = u32::from(req.value >> 8);
462 let dur = u32::from(req.value >> 8); 468 let dur = if dur == 0 { u32::MAX } else { 4 * dur };
463 let dur = if dur == 0 { u32::MAX } else { 4 * dur }; 469 handler.set_idle_ms(id, dur);
464 handler.set_idle_ms(id, dur);
465 }
466 OutResponse::Accepted
467 } 470 }
468 HID_REQ_SET_REPORT => match (ReportId::try_from(req.value), self.request_handler) { 471 Some(OutResponse::Accepted)
469 (Ok(id), Some(handler)) => handler.set_report(id, data), 472 }
470 _ => OutResponse::Rejected, 473 HID_REQ_SET_REPORT => match (ReportId::try_from(req.value), self.request_handler) {
471 }, 474 (Ok(id), Some(handler)) => Some(handler.set_report(id, data)),
472 HID_REQ_SET_PROTOCOL => { 475 _ => Some(OutResponse::Rejected),
473 if req.value == 1 { 476 },
474 OutResponse::Accepted 477 HID_REQ_SET_PROTOCOL => {
475 } else { 478 if req.value == 1 {
476 warn!("HID Boot Protocol is unsupported."); 479 Some(OutResponse::Accepted)
477 OutResponse::Rejected // UNSUPPORTED: Boot Protocol 480 } else {
478 } 481 warn!("HID Boot Protocol is unsupported.");
482 Some(OutResponse::Rejected) // UNSUPPORTED: Boot Protocol
479 } 483 }
480 _ => OutResponse::Rejected,
481 } 484 }
482 } else { 485 _ => Some(OutResponse::Rejected),
483 OutResponse::Rejected // UNSUPPORTED: SET_DESCRIPTOR
484 } 486 }
485 } 487 }
486 488
487 fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> { 489 fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option<InResponse<'a>> {
488 trace!("HID control_in {:?}", req); 490 if req.index != self.if_num.0 as u16 {
489 match req.request { 491 return None;
490 HID_REQ_GET_REPORT => { 492 }
491 let size = match ReportId::try_from(req.value) { 493
492 Ok(id) => self.request_handler.and_then(|x| x.get_report(id, buf)), 494 match (req.request_type, req.recipient) {
493 Err(_) => None, 495 (RequestType::Standard, Recipient::Interface) => match req.request {
494 }; 496 Request::GET_DESCRIPTOR => match (req.value >> 8) as u8 {
495 497 HID_DESC_DESCTYPE_HID_REPORT => Some(InResponse::Accepted(self.report_descriptor)),
496 if let Some(size) = size { 498 HID_DESC_DESCTYPE_HID => Some(InResponse::Accepted(&self.hid_descriptor)),
497 InResponse::Accepted(&buf[0..size]) 499 _ => Some(InResponse::Rejected),
498 } else { 500 },
499 InResponse::Rejected 501
500 } 502 _ => Some(InResponse::Rejected),
501 } 503 },
502 HID_REQ_GET_IDLE => { 504 (RequestType::Class, Recipient::Interface) => {
503 if let Some(handler) = self.request_handler { 505 trace!("HID control_in {:?}", req);
504 let id = req.value as u8; 506 match req.request {
505 let id = (id != 0).then(|| ReportId::In(id)); 507 HID_REQ_GET_REPORT => {
506 if let Some(dur) = handler.get_idle_ms(id) { 508 let size = match ReportId::try_from(req.value) {
507 let dur = u8::try_from(dur / 4).unwrap_or(0); 509 Ok(id) => self.request_handler.and_then(|x| x.get_report(id, buf)),
508 buf[0] = dur; 510 Err(_) => None,
509 InResponse::Accepted(&buf[0..1]) 511 };
510 } else { 512
511 InResponse::Rejected 513 if let Some(size) = size {
514 Some(InResponse::Accepted(&buf[0..size]))
515 } else {
516 Some(InResponse::Rejected)
517 }
512 } 518 }
513 } else { 519 HID_REQ_GET_IDLE => {
514 InResponse::Rejected 520 if let Some(handler) = self.request_handler {
521 let id = req.value as u8;
522 let id = (id != 0).then(|| ReportId::In(id));
523 if let Some(dur) = handler.get_idle_ms(id) {
524 let dur = u8::try_from(dur / 4).unwrap_or(0);
525 buf[0] = dur;
526 Some(InResponse::Accepted(&buf[0..1]))
527 } else {
528 Some(InResponse::Rejected)
529 }
530 } else {
531 Some(InResponse::Rejected)
532 }
533 }
534 HID_REQ_GET_PROTOCOL => {
535 // UNSUPPORTED: Boot Protocol
536 buf[0] = 1;
537 Some(InResponse::Accepted(&buf[0..1]))
538 }
539 _ => Some(InResponse::Rejected),
515 } 540 }
516 } 541 }
517 HID_REQ_GET_PROTOCOL => { 542 _ => None,
518 // UNSUPPORTED: Boot Protocol
519 buf[0] = 1;
520 InResponse::Accepted(&buf[0..1])
521 }
522 _ => InResponse::Rejected,
523 } 543 }
524 } 544 }
525} 545}