aboutsummaryrefslogtreecommitdiff
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
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).
-rw-r--r--embassy-usb-logger/src/lib.rs1
-rw-r--r--embassy-usb/Cargo.toml9
-rw-r--r--embassy-usb/build.rs1
-rw-r--r--embassy-usb/gen_config.py1
-rw-r--r--embassy-usb/src/builder.rs45
-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
-rw-r--r--embassy-usb/src/control.rs58
-rw-r--r--embassy-usb/src/descriptor_reader.rs7
-rw-r--r--embassy-usb/src/lib.rs243
-rw-r--r--embassy-usb/src/types.rs6
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs1
-rw-r--r--examples/nrf52840/src/bin/usb_hid_keyboard.rs25
-rw-r--r--examples/nrf52840/src/bin/usb_hid_mouse.rs1
-rw-r--r--examples/nrf52840/src/bin/usb_serial.rs1
-rw-r--r--examples/nrf52840/src/bin/usb_serial_multitask.rs1
-rw-r--r--examples/nrf52840/src/bin/usb_serial_winusb.rs1
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs1
-rw-r--r--examples/rp/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32f1/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32f3/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs1
-rw-r--r--examples/stm32f4/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32f7/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32h7/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32l4/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs1
-rw-r--r--examples/stm32l5/src/bin/usb_hid_mouse.rs1
-rw-r--r--examples/stm32l5/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32u5/src/bin/usb_serial.rs1
31 files changed, 380 insertions, 337 deletions
diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs
index 6386e2096..1d8dd13ce 100644
--- a/embassy-usb-logger/src/lib.rs
+++ b/embassy-usb-logger/src/lib.rs
@@ -74,7 +74,6 @@ impl<const N: usize> UsbLogger<N> {
74 &mut state.config_descriptor, 74 &mut state.config_descriptor,
75 &mut state.bos_descriptor, 75 &mut state.bos_descriptor,
76 &mut state.control_buf, 76 &mut state.control_buf,
77 None,
78 ); 77 );
79 78
80 // Create classes on the builder. 79 // Create classes on the builder.
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml
index 463e1268c..ae3f3ac37 100644
--- a/embassy-usb/Cargo.toml
+++ b/embassy-usb/Cargo.toml
@@ -27,6 +27,15 @@ max-interface-count-6 = []
27max-interface-count-7 = [] 27max-interface-count-7 = []
28max-interface-count-8 = [] 28max-interface-count-8 = []
29 29
30max-handler-count-1 = []
31max-handler-count-2 = []
32max-handler-count-3 = []
33max-handler-count-4 = [] # Default
34max-handler-count-5 = []
35max-handler-count-6 = []
36max-handler-count-7 = []
37max-handler-count-8 = []
38
30# END AUTOGENERATED CONFIG FEATURES 39# END AUTOGENERATED CONFIG FEATURES
31 40
32[dependencies] 41[dependencies]
diff --git a/embassy-usb/build.rs b/embassy-usb/build.rs
index 524bdc2f6..33d32f7d3 100644
--- a/embassy-usb/build.rs
+++ b/embassy-usb/build.rs
@@ -7,6 +7,7 @@ static CONFIGS: &[(&str, usize)] = &[
7 // BEGIN AUTOGENERATED CONFIG FEATURES 7 // BEGIN AUTOGENERATED CONFIG FEATURES
8 // Generated by gen_config.py. DO NOT EDIT. 8 // Generated by gen_config.py. DO NOT EDIT.
9 ("MAX_INTERFACE_COUNT", 4), 9 ("MAX_INTERFACE_COUNT", 4),
10 ("MAX_HANDLER_COUNT", 4),
10 // END AUTOGENERATED CONFIG FEATURES 11 // END AUTOGENERATED CONFIG FEATURES
11]; 12];
12 13
diff --git a/embassy-usb/gen_config.py b/embassy-usb/gen_config.py
index 55a7fa3c0..67ce359cd 100644
--- a/embassy-usb/gen_config.py
+++ b/embassy-usb/gen_config.py
@@ -28,6 +28,7 @@ def feature(name, default, min, max, pow2=None):
28 28
29 29
30feature("max_interface_count", default=4, min=1, max=8) 30feature("max_interface_count", default=4, min=1, max=8)
31feature("max_handler_count", default=4, min=1, max=8)
31 32
32# ========= Update Cargo.toml 33# ========= Update Cargo.toml
33 34
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index d89fc4017..07b2a177c 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -1,12 +1,12 @@
1use heapless::Vec; 1use heapless::Vec;
2 2
3use crate::control::ControlHandler; 3use crate::config::*;
4use crate::descriptor::{BosWriter, DescriptorWriter}; 4use crate::descriptor::{BosWriter, DescriptorWriter};
5use crate::driver::{Driver, Endpoint, EndpointType}; 5use crate::driver::{Driver, Endpoint, EndpointType};
6#[cfg(feature = "msos-descriptor")] 6#[cfg(feature = "msos-descriptor")]
7use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter}; 7use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter};
8use crate::types::*; 8use crate::types::*;
9use crate::{DeviceStateHandler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; 9use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START};
10 10
11#[derive(Debug, Copy, Clone)] 11#[derive(Debug, Copy, Clone)]
12#[cfg_attr(feature = "defmt", derive(defmt::Format))] 12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -122,8 +122,8 @@ impl<'a> Config<'a> {
122/// [`UsbDevice`] builder. 122/// [`UsbDevice`] builder.
123pub struct Builder<'d, D: Driver<'d>> { 123pub struct Builder<'d, D: Driver<'d>> {
124 config: Config<'d>, 124 config: Config<'d>,
125 handler: Option<&'d dyn DeviceStateHandler>, 125 handlers: Vec<&'d mut dyn Handler, MAX_HANDLER_COUNT>,
126 interfaces: Vec<Interface<'d>, MAX_INTERFACE_COUNT>, 126 interfaces: Vec<Interface, MAX_INTERFACE_COUNT>,
127 control_buf: &'d mut [u8], 127 control_buf: &'d mut [u8],
128 128
129 driver: D, 129 driver: D,
@@ -151,7 +151,6 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
151 bos_descriptor_buf: &'d mut [u8], 151 bos_descriptor_buf: &'d mut [u8],
152 #[cfg(feature = "msos-descriptor")] msos_descriptor_buf: &'d mut [u8], 152 #[cfg(feature = "msos-descriptor")] msos_descriptor_buf: &'d mut [u8],
153 control_buf: &'d mut [u8], 153 control_buf: &'d mut [u8],
154 handler: Option<&'d dyn DeviceStateHandler>,
155 ) -> Self { 154 ) -> Self {
156 // Magic values specified in USB-IF ECN on IADs. 155 // Magic values specified in USB-IF ECN on IADs.
157 if config.composite_with_iads 156 if config.composite_with_iads
@@ -179,9 +178,9 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
179 178
180 Builder { 179 Builder {
181 driver, 180 driver,
182 handler,
183 config, 181 config,
184 interfaces: Vec::new(), 182 interfaces: Vec::new(),
183 handlers: Vec::new(),
185 control_buf, 184 control_buf,
186 next_string_index: STRING_INDEX_CUSTOM_START, 185 next_string_index: STRING_INDEX_CUSTOM_START,
187 186
@@ -205,7 +204,7 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
205 UsbDevice::build( 204 UsbDevice::build(
206 self.driver, 205 self.driver,
207 self.config, 206 self.config,
208 self.handler, 207 self.handlers,
209 self.device_descriptor.into_buf(), 208 self.device_descriptor.into_buf(),
210 self.config_descriptor.into_buf(), 209 self.config_descriptor.into_buf(),
211 self.bos_descriptor.writer.into_buf(), 210 self.bos_descriptor.writer.into_buf(),
@@ -248,6 +247,26 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
248 } 247 }
249 } 248 }
250 249
250 /// Add a Handler.
251 ///
252 /// The Handler is called on some USB bus events, and to handle all control requests not already
253 /// handled by the USB stack.
254 pub fn handler(&mut self, handler: &'d mut dyn Handler) {
255 if self.handlers.push(handler).is_err() {
256 panic!(
257 "embassy-usb: handler list full. Increase the `max_handler_count` compile-time setting. Current value: {}",
258 MAX_HANDLER_COUNT
259 )
260 }
261 }
262
263 /// Allocates a new string index.
264 pub fn string(&mut self) -> StringIndex {
265 let index = self.next_string_index;
266 self.next_string_index += 1;
267 StringIndex::new(index)
268 }
269
251 #[cfg(feature = "msos-descriptor")] 270 #[cfg(feature = "msos-descriptor")]
252 /// Add an MS OS 2.0 Descriptor Set. 271 /// Add an MS OS 2.0 Descriptor Set.
253 /// 272 ///
@@ -301,10 +320,8 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
301 320
302 let number = self.builder.interfaces.len() as _; 321 let number = self.builder.interfaces.len() as _;
303 let iface = Interface { 322 let iface = Interface {
304 handler: None,
305 current_alt_setting: 0, 323 current_alt_setting: 0,
306 num_alt_settings: 0, 324 num_alt_settings: 0,
307 num_strings: 0,
308 }; 325 };
309 326
310 if self.builder.interfaces.push(iface).is_err() { 327 if self.builder.interfaces.push(iface).is_err() {
@@ -350,17 +367,9 @@ impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> {
350 self.interface_number 367 self.interface_number
351 } 368 }
352 369
353 pub fn handler(&mut self, handler: &'d mut dyn ControlHandler) {
354 self.builder.interfaces[self.interface_number.0 as usize].handler = Some(handler);
355 }
356
357 /// Allocates a new string index. 370 /// Allocates a new string index.
358 pub fn string(&mut self) -> StringIndex { 371 pub fn string(&mut self) -> StringIndex {
359 let index = self.builder.next_string_index; 372 self.builder.string()
360 self.builder.next_string_index += 1;
361 self.builder.interfaces[self.interface_number.0 as usize].num_strings += 1;
362
363 StringIndex::new(index)
364 } 373 }
365 374
366 /// Add an alternate setting to the interface and write its descriptor. 375 /// Add an alternate setting to the interface and write its descriptor.
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}
diff --git a/embassy-usb/src/control.rs b/embassy-usb/src/control.rs
index 39b499f03..ceccfd85b 100644
--- a/embassy-usb/src/control.rs
+++ b/embassy-usb/src/control.rs
@@ -2,7 +2,6 @@
2use core::mem; 2use core::mem;
3 3
4use crate::driver::Direction; 4use crate::driver::Direction;
5use crate::types::StringIndex;
6 5
7/// Control request type. 6/// Control request type.
8#[repr(u8)] 7#[repr(u8)]
@@ -145,60 +144,3 @@ pub enum InResponse<'a> {
145 /// The request was rejected. 144 /// The request was rejected.
146 Rejected, 145 Rejected,
147} 146}
148
149/// Handler for control requests.
150///
151/// All methods are optional callbacks that will be called by
152/// [`UsbDevice::run()`](crate::UsbDevice::run)
153pub trait ControlHandler {
154 /// Called after a USB reset after the bus reset sequence is complete.
155 fn reset(&mut self) {}
156
157 /// Called when a "set alternate setting" control request is done on the interface.
158 fn set_alternate_setting(&mut self, alternate_setting: u8) {
159 let _ = alternate_setting;
160 }
161
162 /// Called when a control request is received with direction HostToDevice.
163 ///
164 /// # Arguments
165 ///
166 /// * `req` - The request from the SETUP packet.
167 /// * `data` - The data from the request.
168 fn control_out(&mut self, req: Request, data: &[u8]) -> OutResponse {
169 let _ = (req, data);
170 OutResponse::Rejected
171 }
172
173 /// Called when a control request is received with direction DeviceToHost.
174 ///
175 /// You should write the response somewhere (usually to `buf`, but you may use another buffer
176 /// owned by yourself, or a static buffer), then return `InResponse::Accepted(data)`.
177 ///
178 /// # Arguments
179 ///
180 /// * `req` - The request from the SETUP packet.
181 fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
182 let _ = (req, buf);
183 InResponse::Rejected
184 }
185
186 /// Called when a GET DESCRIPTOR control request is received on the interface.
187 ///
188 /// You should write the response somewhere (usually to `buf`, but you may use another buffer
189 /// owned by yourself, or a static buffer), then return `InResponse::Accepted(data)`.
190 ///
191 /// # Arguments
192 ///
193 /// * `req` - The request from the SETUP packet.
194 fn get_descriptor<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
195 let _ = (req, buf);
196 InResponse::Rejected
197 }
198
199 /// Called when a GET_DESCRIPTOR STRING control request is received.
200 fn get_string(&mut self, index: StringIndex, lang_id: u16) -> Option<&str> {
201 let _ = (index, lang_id);
202 None
203 }
204}
diff --git a/embassy-usb/src/descriptor_reader.rs b/embassy-usb/src/descriptor_reader.rs
index d64bcb73b..05adcce60 100644
--- a/embassy-usb/src/descriptor_reader.rs
+++ b/embassy-usb/src/descriptor_reader.rs
@@ -1,5 +1,6 @@
1use crate::descriptor::descriptor_type; 1use crate::descriptor::descriptor_type;
2use crate::driver::EndpointAddress; 2use crate::driver::EndpointAddress;
3use crate::types::InterfaceNumber;
3 4
4#[derive(Copy, Clone, PartialEq, Eq, Debug)] 5#[derive(Copy, Clone, PartialEq, Eq, Debug)]
5#[cfg_attr(feature = "defmt", derive(defmt::Format))] 6#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -75,7 +76,7 @@ impl<'a, 'b> Iterator for DescriptorIter<'a, 'b> {
75#[cfg_attr(feature = "defmt", derive(defmt::Format))] 76#[cfg_attr(feature = "defmt", derive(defmt::Format))]
76pub struct EndpointInfo { 77pub struct EndpointInfo {
77 pub configuration: u8, 78 pub configuration: u8,
78 pub interface: u8, 79 pub interface: InterfaceNumber,
79 pub interface_alt: u8, 80 pub interface_alt: u8,
80 pub ep_address: EndpointAddress, 81 pub ep_address: EndpointAddress,
81} 82}
@@ -83,7 +84,7 @@ pub struct EndpointInfo {
83pub fn foreach_endpoint(data: &[u8], mut f: impl FnMut(EndpointInfo)) -> Result<(), ReadError> { 84pub fn foreach_endpoint(data: &[u8], mut f: impl FnMut(EndpointInfo)) -> Result<(), ReadError> {
84 let mut ep = EndpointInfo { 85 let mut ep = EndpointInfo {
85 configuration: 0, 86 configuration: 0,
86 interface: 0, 87 interface: InterfaceNumber(0),
87 interface_alt: 0, 88 interface_alt: 0,
88 ep_address: EndpointAddress::from(0), 89 ep_address: EndpointAddress::from(0),
89 }; 90 };
@@ -96,7 +97,7 @@ pub fn foreach_endpoint(data: &[u8], mut f: impl FnMut(EndpointInfo)) -> Result<
96 ep.configuration = r.read_u8()?; 97 ep.configuration = r.read_u8()?;
97 } 98 }
98 descriptor_type::INTERFACE => { 99 descriptor_type::INTERFACE => {
99 ep.interface = r.read_u8()?; 100 ep.interface = InterfaceNumber(r.read_u8()?);
100 ep.interface_alt = r.read_u8()?; 101 ep.interface_alt = r.read_u8()?;
101 } 102 }
102 descriptor_type::ENDPOINT => { 103 descriptor_type::ENDPOINT => {
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index f8983318e..bfeccd5fe 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -82,32 +82,87 @@ const STRING_INDEX_PRODUCT: u8 = 2;
82const STRING_INDEX_SERIAL_NUMBER: u8 = 3; 82const STRING_INDEX_SERIAL_NUMBER: u8 = 3;
83const STRING_INDEX_CUSTOM_START: u8 = 4; 83const STRING_INDEX_CUSTOM_START: u8 = 4;
84 84
85/// A handler trait for changes in the device state of the [UsbDevice]. 85/// Handler for device events and control requests.
86pub trait DeviceStateHandler { 86///
87/// All methods are optional callbacks that will be called by
88/// [`UsbDevice::run()`](crate::UsbDevice::run)
89pub trait Handler {
87 /// Called when the USB device has been enabled or disabled. 90 /// Called when the USB device has been enabled or disabled.
88 fn enabled(&self, _enabled: bool) {} 91 fn enabled(&mut self, _enabled: bool) {}
89 92
90 /// Called when the host resets the device. 93 /// Called after a USB reset after the bus reset sequence is complete.
91 fn reset(&self) {} 94 fn reset(&mut self) {}
92 95
93 /// Called when the host has set the address of the device to `addr`. 96 /// Called when the host has set the address of the device to `addr`.
94 fn addressed(&self, _addr: u8) {} 97 fn addressed(&mut self, _addr: u8) {}
95 98
96 /// Called when the host has enabled or disabled the configuration of the device. 99 /// Called when the host has enabled or disabled the configuration of the device.
97 fn configured(&self, _configured: bool) {} 100 fn configured(&mut self, _configured: bool) {}
98 101
99 /// Called when the bus has entered or exited the suspend state. 102 /// Called when the bus has entered or exited the suspend state.
100 fn suspended(&self, _suspended: bool) {} 103 fn suspended(&mut self, _suspended: bool) {}
101 104
102 /// Called when remote wakeup feature is enabled or disabled. 105 /// Called when remote wakeup feature is enabled or disabled.
103 fn remote_wakeup_enabled(&self, _enabled: bool) {} 106 fn remote_wakeup_enabled(&mut self, _enabled: bool) {}
107
108 /// Called when a "set alternate setting" control request is done on the interface.
109 fn set_alternate_setting(&mut self, iface: InterfaceNumber, alternate_setting: u8) {
110 let _ = iface;
111 let _ = alternate_setting;
112 }
113
114 /// Called when a control request is received with direction HostToDevice.
115 ///
116 /// # Arguments
117 ///
118 /// * `req` - The request from the SETUP packet.
119 /// * `data` - The data from the request.
120 ///
121 /// # Returns
122 ///
123 /// If you didn't handle this request (for example if it's for the wrong interface), return
124 /// `None`. In this case, the the USB stack will continue calling the other handlers, to see
125 /// if another handles it.
126 ///
127 /// If you did, return `Some` with either `Accepted` or `Rejected`. This will make the USB stack
128 /// respond to the control request, and stop calling other handlers.
129 fn control_out(&mut self, req: Request, data: &[u8]) -> Option<OutResponse> {
130 let _ = (req, data);
131 None
132 }
133
134 /// Called when a control request is received with direction DeviceToHost.
135 ///
136 /// You should write the response somewhere (usually to `buf`, but you may use another buffer
137 /// owned by yourself, or a static buffer), then return `InResponse::Accepted(data)`.
138 ///
139 /// # Arguments
140 ///
141 /// * `req` - The request from the SETUP packet.
142 ///
143 /// # Returns
144 ///
145 /// If you didn't handle this request (for example if it's for the wrong interface), return
146 /// `None`. In this case, the the USB stack will continue calling the other handlers, to see
147 /// if another handles it.
148 ///
149 /// If you did, return `Some` with either `Accepted` or `Rejected`. This will make the USB stack
150 /// respond to the control request, and stop calling other handlers.
151 fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option<InResponse<'a>> {
152 let _ = (req, buf);
153 None
154 }
155
156 /// Called when a GET_DESCRIPTOR STRING control request is received.
157 fn get_string(&mut self, index: StringIndex, lang_id: u16) -> Option<&str> {
158 let _ = (index, lang_id);
159 None
160 }
104} 161}
105 162
106struct Interface<'d> { 163struct Interface {
107 handler: Option<&'d mut dyn ControlHandler>,
108 current_alt_setting: u8, 164 current_alt_setting: u8,
109 num_alt_settings: u8, 165 num_alt_settings: u8,
110 num_strings: u8,
111} 166}
112 167
113/// Main struct for the USB device stack. 168/// Main struct for the USB device stack.
@@ -119,7 +174,6 @@ pub struct UsbDevice<'d, D: Driver<'d>> {
119 174
120struct Inner<'d, D: Driver<'d>> { 175struct Inner<'d, D: Driver<'d>> {
121 bus: D::Bus, 176 bus: D::Bus,
122 handler: Option<&'d dyn DeviceStateHandler>,
123 177
124 config: Config<'d>, 178 config: Config<'d>,
125 device_descriptor: &'d [u8], 179 device_descriptor: &'d [u8],
@@ -138,7 +192,9 @@ struct Inner<'d, D: Driver<'d>> {
138 /// instead of regular `accept()`. 192 /// instead of regular `accept()`.
139 set_address_pending: bool, 193 set_address_pending: bool,
140 194
141 interfaces: Vec<Interface<'d>, MAX_INTERFACE_COUNT>, 195 interfaces: Vec<Interface, MAX_INTERFACE_COUNT>,
196 handlers: Vec<&'d mut dyn Handler, MAX_HANDLER_COUNT>,
197
142 #[cfg(feature = "msos-descriptor")] 198 #[cfg(feature = "msos-descriptor")]
143 msos_descriptor: crate::msos::MsOsDescriptorSet<'d>, 199 msos_descriptor: crate::msos::MsOsDescriptorSet<'d>,
144} 200}
@@ -147,11 +203,11 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
147 pub(crate) fn build( 203 pub(crate) fn build(
148 driver: D, 204 driver: D,
149 config: Config<'d>, 205 config: Config<'d>,
150 handler: Option<&'d dyn DeviceStateHandler>, 206 handlers: Vec<&'d mut dyn Handler, MAX_HANDLER_COUNT>,
151 device_descriptor: &'d [u8], 207 device_descriptor: &'d [u8],
152 config_descriptor: &'d [u8], 208 config_descriptor: &'d [u8],
153 bos_descriptor: &'d [u8], 209 bos_descriptor: &'d [u8],
154 interfaces: Vec<Interface<'d>, MAX_INTERFACE_COUNT>, 210 interfaces: Vec<Interface, MAX_INTERFACE_COUNT>,
155 control_buf: &'d mut [u8], 211 control_buf: &'d mut [u8],
156 #[cfg(feature = "msos-descriptor")] msos_descriptor: crate::msos::MsOsDescriptorSet<'d>, 212 #[cfg(feature = "msos-descriptor")] msos_descriptor: crate::msos::MsOsDescriptorSet<'d>,
157 ) -> UsbDevice<'d, D> { 213 ) -> UsbDevice<'d, D> {
@@ -165,7 +221,6 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
165 inner: Inner { 221 inner: Inner {
166 bus, 222 bus,
167 config, 223 config,
168 handler,
169 device_descriptor, 224 device_descriptor,
170 config_descriptor, 225 config_descriptor,
171 bos_descriptor, 226 bos_descriptor,
@@ -177,6 +232,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
177 address: 0, 232 address: 0,
178 set_address_pending: false, 233 set_address_pending: false,
179 interfaces, 234 interfaces,
235 handlers,
180 #[cfg(feature = "msos-descriptor")] 236 #[cfg(feature = "msos-descriptor")]
181 msos_descriptor, 237 msos_descriptor,
182 }, 238 },
@@ -221,7 +277,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
221 self.inner.suspended = false; 277 self.inner.suspended = false;
222 self.inner.remote_wakeup_enabled = false; 278 self.inner.remote_wakeup_enabled = false;
223 279
224 if let Some(h) = &self.inner.handler { 280 for h in &mut self.inner.handlers {
225 h.enabled(false); 281 h.enabled(false);
226 } 282 }
227 } 283 }
@@ -250,7 +306,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
250 self.inner.bus.remote_wakeup().await?; 306 self.inner.bus.remote_wakeup().await?;
251 self.inner.suspended = false; 307 self.inner.suspended = false;
252 308
253 if let Some(h) = &self.inner.handler { 309 for h in &mut self.inner.handlers {
254 h.suspended(false); 310 h.suspended(false);
255 } 311 }
256 312
@@ -361,29 +417,29 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
361 self.remote_wakeup_enabled = false; 417 self.remote_wakeup_enabled = false;
362 self.address = 0; 418 self.address = 0;
363 419
364 for iface in self.interfaces.iter_mut() { 420 for h in &mut self.handlers {
365 iface.current_alt_setting = 0; 421 h.reset();
366 if let Some(h) = &mut iface.handler {
367 h.reset();
368 h.set_alternate_setting(0);
369 }
370 } 422 }
371 423
372 if let Some(h) = &self.handler { 424 for (i, iface) in self.interfaces.iter_mut().enumerate() {
373 h.reset(); 425 iface.current_alt_setting = 0;
426
427 for h in &mut self.handlers {
428 h.set_alternate_setting(InterfaceNumber::new(i as _), 0);
429 }
374 } 430 }
375 } 431 }
376 Event::Resume => { 432 Event::Resume => {
377 trace!("usb: resume"); 433 trace!("usb: resume");
378 self.suspended = false; 434 self.suspended = false;
379 if let Some(h) = &self.handler { 435 for h in &mut self.handlers {
380 h.suspended(false); 436 h.suspended(false);
381 } 437 }
382 } 438 }
383 Event::Suspend => { 439 Event::Suspend => {
384 trace!("usb: suspend"); 440 trace!("usb: suspend");
385 self.suspended = true; 441 self.suspended = true;
386 if let Some(h) = &self.handler { 442 for h in &mut self.handlers {
387 h.suspended(true); 443 h.suspended(true);
388 } 444 }
389 } 445 }
@@ -392,7 +448,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
392 self.bus.enable().await; 448 self.bus.enable().await;
393 self.device_state = UsbDeviceState::Default; 449 self.device_state = UsbDeviceState::Default;
394 450
395 if let Some(h) = &self.handler { 451 for h in &mut self.handlers {
396 h.enabled(true); 452 h.enabled(true);
397 } 453 }
398 } 454 }
@@ -401,7 +457,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
401 self.bus.disable().await; 457 self.bus.disable().await;
402 self.device_state = UsbDeviceState::Unpowered; 458 self.device_state = UsbDeviceState::Unpowered;
403 459
404 if let Some(h) = &self.handler { 460 for h in &mut self.handlers {
405 h.enabled(false); 461 h.enabled(false);
406 } 462 }
407 } 463 }
@@ -416,14 +472,14 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
416 (RequestType::Standard, Recipient::Device) => match (req.request, req.value) { 472 (RequestType::Standard, Recipient::Device) => match (req.request, req.value) {
417 (Request::CLEAR_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => { 473 (Request::CLEAR_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => {
418 self.remote_wakeup_enabled = false; 474 self.remote_wakeup_enabled = false;
419 if let Some(h) = &self.handler { 475 for h in &mut self.handlers {
420 h.remote_wakeup_enabled(false); 476 h.remote_wakeup_enabled(false);
421 } 477 }
422 OutResponse::Accepted 478 OutResponse::Accepted
423 } 479 }
424 (Request::SET_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => { 480 (Request::SET_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => {
425 self.remote_wakeup_enabled = true; 481 self.remote_wakeup_enabled = true;
426 if let Some(h) = &self.handler { 482 for h in &mut self.handlers {
427 h.remote_wakeup_enabled(true); 483 h.remote_wakeup_enabled(true);
428 } 484 }
429 OutResponse::Accepted 485 OutResponse::Accepted
@@ -432,7 +488,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
432 self.address = addr as u8; 488 self.address = addr as u8;
433 self.set_address_pending = true; 489 self.set_address_pending = true;
434 self.device_state = UsbDeviceState::Addressed; 490 self.device_state = UsbDeviceState::Addressed;
435 if let Some(h) = &self.handler { 491 for h in &mut self.handlers {
436 h.addressed(self.address); 492 h.addressed(self.address);
437 } 493 }
438 OutResponse::Accepted 494 OutResponse::Accepted
@@ -443,14 +499,14 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
443 499
444 // Enable all endpoints of selected alt settings. 500 // Enable all endpoints of selected alt settings.
445 foreach_endpoint(self.config_descriptor, |ep| { 501 foreach_endpoint(self.config_descriptor, |ep| {
446 let iface = &self.interfaces[ep.interface as usize]; 502 let iface = &self.interfaces[ep.interface.0 as usize];
447 self.bus 503 self.bus
448 .endpoint_set_enabled(ep.ep_address, iface.current_alt_setting == ep.interface_alt); 504 .endpoint_set_enabled(ep.ep_address, iface.current_alt_setting == ep.interface_alt);
449 }) 505 })
450 .unwrap(); 506 .unwrap();
451 507
452 // Notify handler. 508 // Notify handlers.
453 if let Some(h) = &self.handler { 509 for h in &mut self.handlers {
454 h.configured(true); 510 h.configured(true);
455 } 511 }
456 512
@@ -468,8 +524,8 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
468 }) 524 })
469 .unwrap(); 525 .unwrap();
470 526
471 // Notify handler. 527 // Notify handlers.
472 if let Some(h) = &self.handler { 528 for h in &mut self.handlers {
473 h.configured(false); 529 h.configured(false);
474 } 530 }
475 531
@@ -479,7 +535,8 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
479 _ => OutResponse::Rejected, 535 _ => OutResponse::Rejected,
480 }, 536 },
481 (RequestType::Standard, Recipient::Interface) => { 537 (RequestType::Standard, Recipient::Interface) => {
482 let iface = match self.interfaces.get_mut(req.index as usize) { 538 let iface_num = InterfaceNumber::new(req.index as _);
539 let iface = match self.interfaces.get_mut(iface_num.0 as usize) {
483 Some(iface) => iface, 540 Some(iface) => iface,
484 None => return OutResponse::Rejected, 541 None => return OutResponse::Rejected,
485 }; 542 };
@@ -497,7 +554,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
497 554
498 // Enable/disable EPs of this interface as needed. 555 // Enable/disable EPs of this interface as needed.
499 foreach_endpoint(self.config_descriptor, |ep| { 556 foreach_endpoint(self.config_descriptor, |ep| {
500 if ep.interface == req.index as u8 { 557 if ep.interface == iface_num {
501 self.bus 558 self.bus
502 .endpoint_set_enabled(ep.ep_address, iface.current_alt_setting == ep.interface_alt); 559 .endpoint_set_enabled(ep.ep_address, iface.current_alt_setting == ep.interface_alt);
503 } 560 }
@@ -506,8 +563,8 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
506 563
507 // TODO check it is valid (not out of range) 564 // TODO check it is valid (not out of range)
508 565
509 if let Some(handler) = &mut iface.handler { 566 for h in &mut self.handlers {
510 handler.set_alternate_setting(new_altsetting); 567 h.set_alternate_setting(iface_num, new_altsetting);
511 } 568 }
512 OutResponse::Accepted 569 OutResponse::Accepted
513 } 570 }
@@ -527,17 +584,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
527 } 584 }
528 _ => OutResponse::Rejected, 585 _ => OutResponse::Rejected,
529 }, 586 },
530 (RequestType::Class, Recipient::Interface) => { 587 _ => self.handle_control_out_delegated(req, data),
531 let iface = match self.interfaces.get_mut(req.index as usize) {
532 Some(iface) => iface,
533 None => return OutResponse::Rejected,
534 };
535 match &mut iface.handler {
536 Some(handler) => handler.control_out(req, data),
537 None => OutResponse::Rejected,
538 }
539 }
540 _ => OutResponse::Rejected,
541 } 588 }
542 } 589 }
543 590
@@ -582,11 +629,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
582 buf[0] = iface.current_alt_setting; 629 buf[0] = iface.current_alt_setting;
583 InResponse::Accepted(&buf[..1]) 630 InResponse::Accepted(&buf[..1])
584 } 631 }
585 Request::GET_DESCRIPTOR => match &mut iface.handler { 632 _ => self.handle_control_in_delegated(req, buf),
586 Some(handler) => handler.get_descriptor(req, buf),
587 None => InResponse::Rejected,
588 },
589 _ => InResponse::Rejected,
590 } 633 }
591 } 634 }
592 (RequestType::Standard, Recipient::Endpoint) => match req.request { 635 (RequestType::Standard, Recipient::Endpoint) => match req.request {
@@ -601,32 +644,46 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
601 } 644 }
602 _ => InResponse::Rejected, 645 _ => InResponse::Rejected,
603 }, 646 },
604 (RequestType::Class, Recipient::Interface) => {
605 let iface = match self.interfaces.get_mut(req.index as usize) {
606 Some(iface) => iface,
607 None => return InResponse::Rejected,
608 };
609
610 match &mut iface.handler {
611 Some(handler) => handler.control_in(req, buf),
612 None => InResponse::Rejected,
613 }
614 }
615 #[cfg(feature = "msos-descriptor")] 647 #[cfg(feature = "msos-descriptor")]
616 (RequestType::Vendor, Recipient::Device) => { 648 (RequestType::Vendor, Recipient::Device) => {
617 if !self.msos_descriptor.is_empty() { 649 if !self.msos_descriptor.is_empty()
618 if req.request == self.msos_descriptor.vendor_code() && req.index == 7 { 650 && req.request == self.msos_descriptor.vendor_code()
619 // Index 7 retrieves the MS OS Descriptor Set 651 && req.index == 7
620 InResponse::Accepted(self.msos_descriptor.descriptor()) 652 {
621 } else { 653 // Index 7 retrieves the MS OS Descriptor Set
622 InResponse::Rejected 654 InResponse::Accepted(self.msos_descriptor.descriptor())
623 }
624 } else { 655 } else {
625 InResponse::Rejected 656 self.handle_control_in_delegated(req, buf)
626 } 657 }
627 } 658 }
628 _ => InResponse::Rejected, 659 _ => self.handle_control_in_delegated(req, buf),
660 }
661 }
662
663 fn handle_control_out_delegated(&mut self, req: Request, data: &[u8]) -> OutResponse {
664 for h in &mut self.handlers {
665 if let Some(res) = h.control_out(req, data) {
666 return res;
667 }
629 } 668 }
669 OutResponse::Rejected
670 }
671
672 fn handle_control_in_delegated<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
673 unsafe fn extend_lifetime<'x, 'y>(r: InResponse<'x>) -> InResponse<'y> {
674 core::mem::transmute(r)
675 }
676
677 for h in &mut self.handlers {
678 if let Some(res) = h.control_in(req, buf) {
679 // safety: the borrow checker isn't smart enough to know this pattern (returning a
680 // borrowed value from inside the loop) is sound. Workaround by unsafely extending lifetime.
681 // Also, Polonius (the WIP new borrow checker) does accept it.
682
683 return unsafe { extend_lifetime(res) };
684 }
685 }
686 InResponse::Rejected
630 } 687 }
631 688
632 fn handle_get_descriptor<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> { 689 fn handle_get_descriptor<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
@@ -649,30 +706,16 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
649 STRING_INDEX_PRODUCT => self.config.product, 706 STRING_INDEX_PRODUCT => self.config.product,
650 STRING_INDEX_SERIAL_NUMBER => self.config.serial_number, 707 STRING_INDEX_SERIAL_NUMBER => self.config.serial_number,
651 _ => { 708 _ => {
652 // Find out which iface owns this string index. 709 let mut s = None;
653 let mut index_left = index - STRING_INDEX_CUSTOM_START; 710 for handler in &mut self.handlers {
654 let mut the_iface = None; 711 let index = StringIndex::new(index);
655 for iface in &mut self.interfaces { 712 let lang_id = req.index;
656 if index_left < iface.num_strings { 713 if let Some(res) = handler.get_string(index, lang_id) {
657 the_iface = Some(iface); 714 s = Some(res);
658 break; 715 break;
659 } 716 }
660 index_left -= iface.num_strings;
661 }
662
663 if let Some(iface) = the_iface {
664 if let Some(handler) = &mut iface.handler {
665 let index = StringIndex::new(index);
666 let lang_id = req.index;
667 handler.get_string(index, lang_id)
668 } else {
669 warn!("String requested to an interface with no handler.");
670 None
671 }
672 } else {
673 warn!("String requested but didn't match to an interface.");
674 None
675 } 717 }
718 s
676 } 719 }
677 }; 720 };
678 721
diff --git a/embassy-usb/src/types.rs b/embassy-usb/src/types.rs
index 1743e61ff..15d195002 100644
--- a/embassy-usb/src/types.rs
+++ b/embassy-usb/src/types.rs
@@ -1,9 +1,9 @@
1//! USB types. 1//! USB types.
2 2
3/// A handle for a USB interface that contains its number. 3/// A handle for a USB interface that contains its number.
4#[derive(Copy, Clone, Eq, PartialEq)] 4#[derive(Debug, Copy, Clone, Eq, PartialEq)]
5#[cfg_attr(feature = "defmt", derive(defmt::Format))] 5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
6pub struct InterfaceNumber(pub(crate) u8); 6pub struct InterfaceNumber(pub u8);
7 7
8impl InterfaceNumber { 8impl InterfaceNumber {
9 pub(crate) fn new(index: u8) -> InterfaceNumber { 9 pub(crate) fn new(index: u8) -> InterfaceNumber {
@@ -20,7 +20,7 @@ impl From<InterfaceNumber> for u8 {
20/// A handle for a USB string descriptor that contains its index. 20/// A handle for a USB string descriptor that contains its index.
21#[derive(Copy, Clone, Eq, PartialEq)] 21#[derive(Copy, Clone, Eq, PartialEq)]
22#[cfg_attr(feature = "defmt", derive(defmt::Format))] 22#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23pub struct StringIndex(u8); 23pub struct StringIndex(pub u8);
24 24
25impl StringIndex { 25impl StringIndex {
26 pub(crate) fn new(index: u8) -> StringIndex { 26 pub(crate) fn new(index: u8) -> StringIndex {
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs
index 699666cee..979780896 100644
--- a/examples/nrf52840/src/bin/usb_ethernet.rs
+++ b/examples/nrf52840/src/bin/usb_ethernet.rs
@@ -82,7 +82,6 @@ async fn main(spawner: Spawner) {
82 &mut singleton!([0; 256])[..], 82 &mut singleton!([0; 256])[..],
83 &mut singleton!([0; 256])[..], 83 &mut singleton!([0; 256])[..],
84 &mut singleton!([0; 128])[..], 84 &mut singleton!([0; 128])[..],
85 None,
86 ); 85 );
87 86
88 // Our MAC addr. 87 // Our MAC addr.
diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
index 017cac197..3d8a114cd 100644
--- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
@@ -16,7 +16,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
16use embassy_sync::signal::Signal; 16use embassy_sync::signal::Signal;
17use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; 17use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
18use embassy_usb::control::OutResponse; 18use embassy_usb::control::OutResponse;
19use embassy_usb::{Builder, Config, DeviceStateHandler}; 19use embassy_usb::{Builder, Config, Handler};
20use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 20use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
21use {defmt_rtt as _, panic_probe as _}; 21use {defmt_rtt as _, panic_probe as _};
22 22
@@ -52,7 +52,7 @@ async fn main(_spawner: Spawner) {
52 let mut bos_descriptor = [0; 256]; 52 let mut bos_descriptor = [0; 256];
53 let mut control_buf = [0; 64]; 53 let mut control_buf = [0; 64];
54 let request_handler = MyRequestHandler {}; 54 let request_handler = MyRequestHandler {};
55 let device_state_handler = MyDeviceStateHandler::new(); 55 let mut device_handler = MyDeviceHandler::new();
56 56
57 let mut state = State::new(); 57 let mut state = State::new();
58 58
@@ -63,9 +63,10 @@ async fn main(_spawner: Spawner) {
63 &mut config_descriptor, 63 &mut config_descriptor,
64 &mut bos_descriptor, 64 &mut bos_descriptor,
65 &mut control_buf, 65 &mut control_buf,
66 Some(&device_state_handler),
67 ); 66 );
68 67
68 builder.handler(&mut device_handler);
69
69 // Create classes on the builder. 70 // Create classes on the builder.
70 let config = embassy_usb::class::hid::Config { 71 let config = embassy_usb::class::hid::Config {
71 report_descriptor: KeyboardReport::desc(), 72 report_descriptor: KeyboardReport::desc(),
@@ -164,20 +165,20 @@ impl RequestHandler for MyRequestHandler {
164 } 165 }
165} 166}
166 167
167struct MyDeviceStateHandler { 168struct MyDeviceHandler {
168 configured: AtomicBool, 169 configured: AtomicBool,
169} 170}
170 171
171impl MyDeviceStateHandler { 172impl MyDeviceHandler {
172 fn new() -> Self { 173 fn new() -> Self {
173 MyDeviceStateHandler { 174 MyDeviceHandler {
174 configured: AtomicBool::new(false), 175 configured: AtomicBool::new(false),
175 } 176 }
176 } 177 }
177} 178}
178 179
179impl DeviceStateHandler for MyDeviceStateHandler { 180impl Handler for MyDeviceHandler {
180 fn enabled(&self, enabled: bool) { 181 fn enabled(&mut self, enabled: bool) {
181 self.configured.store(false, Ordering::Relaxed); 182 self.configured.store(false, Ordering::Relaxed);
182 SUSPENDED.store(false, Ordering::Release); 183 SUSPENDED.store(false, Ordering::Release);
183 if enabled { 184 if enabled {
@@ -187,17 +188,17 @@ impl DeviceStateHandler for MyDeviceStateHandler {
187 } 188 }
188 } 189 }
189 190
190 fn reset(&self) { 191 fn reset(&mut self) {
191 self.configured.store(false, Ordering::Relaxed); 192 self.configured.store(false, Ordering::Relaxed);
192 info!("Bus reset, the Vbus current limit is 100mA"); 193 info!("Bus reset, the Vbus current limit is 100mA");
193 } 194 }
194 195
195 fn addressed(&self, addr: u8) { 196 fn addressed(&mut self, addr: u8) {
196 self.configured.store(false, Ordering::Relaxed); 197 self.configured.store(false, Ordering::Relaxed);
197 info!("USB address set to: {}", addr); 198 info!("USB address set to: {}", addr);
198 } 199 }
199 200
200 fn configured(&self, configured: bool) { 201 fn configured(&mut self, configured: bool) {
201 self.configured.store(configured, Ordering::Relaxed); 202 self.configured.store(configured, Ordering::Relaxed);
202 if configured { 203 if configured {
203 info!("Device configured, it may now draw up to the configured current limit from Vbus.") 204 info!("Device configured, it may now draw up to the configured current limit from Vbus.")
@@ -206,7 +207,7 @@ impl DeviceStateHandler for MyDeviceStateHandler {
206 } 207 }
207 } 208 }
208 209
209 fn suspended(&self, suspended: bool) { 210 fn suspended(&mut self, suspended: bool) {
210 if suspended { 211 if suspended {
211 info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled)."); 212 info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled).");
212 SUSPENDED.store(true, Ordering::Release); 213 SUSPENDED.store(true, Ordering::Release);
diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs
index a5849129a..d7c9d55b7 100644
--- a/examples/nrf52840/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs
@@ -55,7 +55,6 @@ async fn main(_spawner: Spawner) {
55 &mut config_descriptor, 55 &mut config_descriptor,
56 &mut bos_descriptor, 56 &mut bos_descriptor,
57 &mut control_buf, 57 &mut control_buf,
58 None,
59 ); 58 );
60 59
61 // Create classes on the builder. 60 // Create classes on the builder.
diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs
index 18b6f25b9..102d7ea60 100644
--- a/examples/nrf52840/src/bin/usb_serial.rs
+++ b/examples/nrf52840/src/bin/usb_serial.rs
@@ -59,7 +59,6 @@ async fn main(_spawner: Spawner) {
59 &mut config_descriptor, 59 &mut config_descriptor,
60 &mut bos_descriptor, 60 &mut bos_descriptor,
61 &mut control_buf, 61 &mut control_buf,
62 None,
63 ); 62 );
64 63
65 // Create classes on the builder. 64 // Create classes on the builder.
diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs
index 3532d3f82..558d4ba60 100644
--- a/examples/nrf52840/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs
@@ -83,7 +83,6 @@ async fn main(spawner: Spawner) {
83 &mut res.config_descriptor, 83 &mut res.config_descriptor,
84 &mut res.bos_descriptor, 84 &mut res.bos_descriptor,
85 &mut res.control_buf, 85 &mut res.control_buf,
86 None,
87 ); 86 );
88 87
89 // Create classes on the builder. 88 // Create classes on the builder.
diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs
index f4b828de6..ade6af527 100644
--- a/examples/nrf52840/src/bin/usb_serial_winusb.rs
+++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs
@@ -65,7 +65,6 @@ async fn main(_spawner: Spawner) {
65 &mut bos_descriptor, 65 &mut bos_descriptor,
66 &mut msos_descriptor, 66 &mut msos_descriptor,
67 &mut control_buf, 67 &mut control_buf,
68 None,
69 ); 68 );
70 69
71 builder.msos_descriptor(windows_version::WIN8_1, 2); 70 builder.msos_descriptor(windows_version::WIN8_1, 2);
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
index 104b25d39..66a6ed4d0 100644
--- a/examples/rp/src/bin/usb_ethernet.rs
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -73,7 +73,6 @@ async fn main(spawner: Spawner) {
73 &mut singleton!([0; 256])[..], 73 &mut singleton!([0; 256])[..],
74 &mut singleton!([0; 256])[..], 74 &mut singleton!([0; 256])[..],
75 &mut singleton!([0; 128])[..], 75 &mut singleton!([0; 128])[..],
76 None,
77 ); 76 );
78 77
79 // Our MAC addr. 78 // Our MAC addr.
diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs
index b7d6493b4..a991082ee 100644
--- a/examples/rp/src/bin/usb_serial.rs
+++ b/examples/rp/src/bin/usb_serial.rs
@@ -53,7 +53,6 @@ async fn main(_spawner: Spawner) {
53 &mut config_descriptor, 53 &mut config_descriptor,
54 &mut bos_descriptor, 54 &mut bos_descriptor,
55 &mut control_buf, 55 &mut control_buf,
56 None,
57 ); 56 );
58 57
59 // Create classes on the builder. 58 // Create classes on the builder.
diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs
index ad92cdeb2..07cad84ef 100644
--- a/examples/stm32f1/src/bin/usb_serial.rs
+++ b/examples/stm32f1/src/bin/usb_serial.rs
@@ -58,7 +58,6 @@ async fn main(_spawner: Spawner) {
58 &mut config_descriptor, 58 &mut config_descriptor,
59 &mut bos_descriptor, 59 &mut bos_descriptor,
60 &mut control_buf, 60 &mut control_buf,
61 None,
62 ); 61 );
63 62
64 // Create classes on the builder. 63 // Create classes on the builder.
diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs
index f6d27c860..5b4e0a91a 100644
--- a/examples/stm32f3/src/bin/usb_serial.rs
+++ b/examples/stm32f3/src/bin/usb_serial.rs
@@ -55,7 +55,6 @@ async fn main(_spawner: Spawner) {
55 &mut config_descriptor, 55 &mut config_descriptor,
56 &mut bos_descriptor, 56 &mut bos_descriptor,
57 &mut control_buf, 57 &mut control_buf,
58 None,
59 ); 58 );
60 59
61 // Create classes on the builder. 60 // Create classes on the builder.
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index cf2885ae5..4a16aac07 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -82,7 +82,6 @@ async fn main(spawner: Spawner) {
82 &mut singleton!([0; 256])[..], 82 &mut singleton!([0; 256])[..],
83 &mut singleton!([0; 256])[..], 83 &mut singleton!([0; 256])[..],
84 &mut singleton!([0; 128])[..], 84 &mut singleton!([0; 128])[..],
85 None,
86 ); 85 );
87 86
88 // Our MAC addr. 87 // Our MAC addr.
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs
index 014647762..baabc1a2d 100644
--- a/examples/stm32f4/src/bin/usb_serial.rs
+++ b/examples/stm32f4/src/bin/usb_serial.rs
@@ -57,7 +57,6 @@ async fn main(_spawner: Spawner) {
57 &mut config_descriptor, 57 &mut config_descriptor,
58 &mut bos_descriptor, 58 &mut bos_descriptor,
59 &mut control_buf, 59 &mut control_buf,
60 None,
61 ); 60 );
62 61
63 // Create classes on the builder. 62 // Create classes on the builder.
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs
index 688bd0dab..5fd9d2ec9 100644
--- a/examples/stm32f7/src/bin/usb_serial.rs
+++ b/examples/stm32f7/src/bin/usb_serial.rs
@@ -58,7 +58,6 @@ async fn main(_spawner: Spawner) {
58 &mut config_descriptor, 58 &mut config_descriptor,
59 &mut bos_descriptor, 59 &mut bos_descriptor,
60 &mut control_buf, 60 &mut control_buf,
61 None,
62 ); 61 );
63 62
64 // Create classes on the builder. 63 // Create classes on the builder.
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs
index b319d12c3..9ef520ae2 100644
--- a/examples/stm32h7/src/bin/usb_serial.rs
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -57,7 +57,6 @@ async fn main(_spawner: Spawner) {
57 &mut config_descriptor, 57 &mut config_descriptor,
58 &mut bos_descriptor, 58 &mut bos_descriptor,
59 &mut control_buf, 59 &mut control_buf,
60 None,
61 ); 60 );
62 61
63 // Create classes on the builder. 62 // Create classes on the builder.
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs
index 3e38b10a3..663f60d52 100644
--- a/examples/stm32l4/src/bin/usb_serial.rs
+++ b/examples/stm32l4/src/bin/usb_serial.rs
@@ -59,7 +59,6 @@ async fn main(_spawner: Spawner) {
59 &mut config_descriptor, 59 &mut config_descriptor,
60 &mut bos_descriptor, 60 &mut bos_descriptor,
61 &mut control_buf, 61 &mut control_buf,
62 None,
63 ); 62 );
64 63
65 // Create classes on the builder. 64 // Create classes on the builder.
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index e5a46b064..98ec0e836 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -79,7 +79,6 @@ async fn main(spawner: Spawner) {
79 &mut singleton!([0; 256])[..], 79 &mut singleton!([0; 256])[..],
80 &mut singleton!([0; 256])[..], 80 &mut singleton!([0; 256])[..],
81 &mut singleton!([0; 128])[..], 81 &mut singleton!([0; 128])[..],
82 None,
83 ); 82 );
84 83
85 // Our MAC addr. 84 // Our MAC addr.
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs
index d38ed7496..e3bbe9d09 100644
--- a/examples/stm32l5/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs
@@ -51,7 +51,6 @@ async fn main(_spawner: Spawner) {
51 &mut config_descriptor, 51 &mut config_descriptor,
52 &mut bos_descriptor, 52 &mut bos_descriptor,
53 &mut control_buf, 53 &mut control_buf,
54 None,
55 ); 54 );
56 55
57 // Create classes on the builder. 56 // Create classes on the builder.
diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs
index 7562a4e96..66ccacb73 100644
--- a/examples/stm32l5/src/bin/usb_serial.rs
+++ b/examples/stm32l5/src/bin/usb_serial.rs
@@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) {
46 &mut config_descriptor, 46 &mut config_descriptor,
47 &mut bos_descriptor, 47 &mut bos_descriptor,
48 &mut control_buf, 48 &mut control_buf,
49 None,
50 ); 49 );
51 50
52 // Create classes on the builder. 51 // Create classes on the builder.
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
index c846836b0..8cd3bf2f4 100644
--- a/examples/stm32u5/src/bin/usb_serial.rs
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -59,7 +59,6 @@ async fn main(_spawner: Spawner) {
59 &mut config_descriptor, 59 &mut config_descriptor,
60 &mut bos_descriptor, 60 &mut bos_descriptor,
61 &mut control_buf, 61 &mut control_buf,
62 None,
63 ); 62 );
64 63
65 // Create classes on the builder. 64 // Create classes on the builder.