aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-02-07 23:31:24 +0000
committerGitHub <[email protected]>2023-02-07 23:31:24 +0000
commit9d637070a516a9ed24c3e12a20082ffdf54f72fb (patch)
treed5051ead9e65ea0a51f315a4302c867d07cb2449
parent4a224efe75c7986f5b3d8c5d6083fa17cb774f12 (diff)
parent86487db5d1773d2a764ab340051d70cfa40e4714 (diff)
Merge #1203
1203: usb: unify ControlHandler+DeviceStateHandler, route all control requests to all handlers. r=Dirbaio a=Dirbaio depends on #1202 - Allows classes to handle vendor requests. (fixes #1078) - Allows classes to use a single handler for multiple interfaces. - Allows classes to access the other events (previously only `reset` was available). Co-authored-by: Dario Nieuwenhuis <[email protected]>
-rw-r--r--embassy-usb-logger/src/lib.rs1
-rw-r--r--embassy-usb/Cargo.toml22
-rw-r--r--embassy-usb/README.md24
-rw-r--r--embassy-usb/build.rs94
-rw-r--r--embassy-usb/gen_config.py74
-rw-r--r--embassy-usb/src/builder.rs52
-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.rs252
-rw-r--r--embassy-usb/src/msos.rs7
-rw-r--r--embassy-usb/src/types.rs8
-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.rs4
-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
33 files changed, 601 insertions, 347 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 eb9ba36f4..ae3f3ac37 100644
--- a/embassy-usb/Cargo.toml
+++ b/embassy-usb/Cargo.toml
@@ -16,6 +16,28 @@ usbd-hid = ["dep:usbd-hid", "dep:ssmarshal"]
16msos-descriptor = [] 16msos-descriptor = []
17default = ["usbd-hid"] 17default = ["usbd-hid"]
18 18
19# BEGIN AUTOGENERATED CONFIG FEATURES
20# Generated by gen_config.py. DO NOT EDIT.
21max-interface-count-1 = []
22max-interface-count-2 = []
23max-interface-count-3 = []
24max-interface-count-4 = [] # Default
25max-interface-count-5 = []
26max-interface-count-6 = []
27max-interface-count-7 = []
28max-interface-count-8 = []
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
39# END AUTOGENERATED CONFIG FEATURES
40
19[dependencies] 41[dependencies]
20embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 42embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
21embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } 43embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
diff --git a/embassy-usb/README.md b/embassy-usb/README.md
index 581c3290f..a3d45b561 100644
--- a/embassy-usb/README.md
+++ b/embassy-usb/README.md
@@ -1,6 +1,28 @@
1# embassy-usb 1# embassy-usb
2 2
3TODO crate description/ 3TODO crate description
4
5## Configuration
6
7`embassy-usb` has some configuration settings that are set at compile time, affecting sizes
8and counts of buffers.
9
10They can be set in two ways:
11
12- Via Cargo features: enable a feature like `<name>-<value>`. `name` must be in lowercase and
13use dashes instead of underscores. For example. `max-interface-count-3`. Only a selection of values
14is available, check `Cargo.toml` for the list.
15- Via environment variables at build time: set the variable named `EMBASSY_USB_<value>`. For example
16`EMBASSY_USB_MAX_INTERFACE_COUNT=3 cargo build`. You can also set them in the `[env]` section of `.cargo/config.toml`.
17Any value can be set, unlike with Cargo features.
18
19Environment variables take precedence over Cargo features. If two Cargo features are enabled for the same setting
20with different values, compilation fails.
21
22### `MAX_INTERFACE_COUNT`
23
24Max amount of interfaces that can be created in one device. Default: 4.
25
4 26
5## Interoperability 27## Interoperability
6 28
diff --git a/embassy-usb/build.rs b/embassy-usb/build.rs
new file mode 100644
index 000000000..33d32f7d3
--- /dev/null
+++ b/embassy-usb/build.rs
@@ -0,0 +1,94 @@
1use std::collections::HashMap;
2use std::fmt::Write;
3use std::path::PathBuf;
4use std::{env, fs};
5
6static CONFIGS: &[(&str, usize)] = &[
7 // BEGIN AUTOGENERATED CONFIG FEATURES
8 // Generated by gen_config.py. DO NOT EDIT.
9 ("MAX_INTERFACE_COUNT", 4),
10 ("MAX_HANDLER_COUNT", 4),
11 // END AUTOGENERATED CONFIG FEATURES
12];
13
14struct ConfigState {
15 value: usize,
16 seen_feature: bool,
17 seen_env: bool,
18}
19
20fn main() {
21 let crate_name = env::var("CARGO_PKG_NAME")
22 .unwrap()
23 .to_ascii_uppercase()
24 .replace('-', "_");
25
26 // only rebuild if build.rs changed. Otherwise Cargo will rebuild if any
27 // other file changed.
28 println!("cargo:rerun-if-changed=build.rs");
29
30 // Rebuild if config envvar changed.
31 for (name, _) in CONFIGS {
32 println!("cargo:rerun-if-env-changed={crate_name}_{name}");
33 }
34
35 let mut configs = HashMap::new();
36 for (name, default) in CONFIGS {
37 configs.insert(
38 *name,
39 ConfigState {
40 value: *default,
41 seen_env: false,
42 seen_feature: false,
43 },
44 );
45 }
46
47 let prefix = format!("{crate_name}_");
48 for (var, value) in env::vars() {
49 if let Some(name) = var.strip_prefix(&prefix) {
50 let Some(cfg) = configs.get_mut(name) else {
51 panic!("Unknown env var {name}")
52 };
53
54 let Ok(value) = value.parse::<usize>() else {
55 panic!("Invalid value for env var {name}: {value}")
56 };
57
58 cfg.value = value;
59 cfg.seen_env = true;
60 }
61
62 if let Some(feature) = var.strip_prefix("CARGO_FEATURE_") {
63 if let Some(i) = feature.rfind('_') {
64 let name = &feature[..i];
65 let value = &feature[i + 1..];
66 if let Some(cfg) = configs.get_mut(name) {
67 let Ok(value) = value.parse::<usize>() else {
68 panic!("Invalid value for feature {name}: {value}")
69 };
70
71 // envvars take priority.
72 if !cfg.seen_env {
73 if cfg.seen_feature {
74 panic!("multiple values set for feature {}: {} and {}", name, cfg.value, value);
75 }
76
77 cfg.value = value;
78 cfg.seen_feature = true;
79 }
80 }
81 }
82 }
83 }
84
85 let mut data = String::new();
86
87 for (name, cfg) in &configs {
88 writeln!(&mut data, "pub const {}: usize = {};", name, cfg.value).unwrap();
89 }
90
91 let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
92 let out_file = out_dir.join("config.rs").to_string_lossy().to_string();
93 fs::write(out_file, data).unwrap();
94}
diff --git a/embassy-usb/gen_config.py b/embassy-usb/gen_config.py
new file mode 100644
index 000000000..67ce359cd
--- /dev/null
+++ b/embassy-usb/gen_config.py
@@ -0,0 +1,74 @@
1import os
2
3abspath = os.path.abspath(__file__)
4dname = os.path.dirname(abspath)
5os.chdir(dname)
6
7features = []
8
9
10def feature(name, default, min, max, pow2=None):
11 vals = set()
12 val = min
13 while val <= max:
14 vals.add(val)
15 if pow2 == True or (isinstance(pow2, int) and val >= pow2):
16 val *= 2
17 else:
18 val += 1
19 vals.add(default)
20
21 features.append(
22 {
23 "name": name,
24 "default": default,
25 "vals": sorted(list(vals)),
26 }
27 )
28
29
30feature("max_interface_count", default=4, min=1, max=8)
31feature("max_handler_count", default=4, min=1, max=8)
32
33# ========= Update Cargo.toml
34
35things = ""
36for f in features:
37 name = f["name"].replace("_", "-")
38 for val in f["vals"]:
39 things += f"{name}-{val} = []"
40 if val == f["default"]:
41 things += " # Default"
42 things += "\n"
43 things += "\n"
44
45SEPARATOR_START = "# BEGIN AUTOGENERATED CONFIG FEATURES\n"
46SEPARATOR_END = "# END AUTOGENERATED CONFIG FEATURES\n"
47HELP = "# Generated by gen_config.py. DO NOT EDIT.\n"
48with open("Cargo.toml", "r") as f:
49 data = f.read()
50before, data = data.split(SEPARATOR_START, maxsplit=1)
51_, after = data.split(SEPARATOR_END, maxsplit=1)
52data = before + SEPARATOR_START + HELP + things + SEPARATOR_END + after
53with open("Cargo.toml", "w") as f:
54 f.write(data)
55
56
57# ========= Update build.rs
58
59things = ""
60for f in features:
61 name = f["name"].upper()
62 things += f' ("{name}", {f["default"]}),\n'
63
64SEPARATOR_START = "// BEGIN AUTOGENERATED CONFIG FEATURES\n"
65SEPARATOR_END = "// END AUTOGENERATED CONFIG FEATURES\n"
66HELP = " // Generated by gen_config.py. DO NOT EDIT.\n"
67with open("build.rs", "r") as f:
68 data = f.read()
69before, data = data.split(SEPARATOR_START, maxsplit=1)
70_, after = data.split(SEPARATOR_END, maxsplit=1)
71data = before + SEPARATOR_START + HELP + \
72 things + " " + SEPARATOR_END + after
73with open("build.rs", "w") as f:
74 f.write(data)
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index d1cbf674b..305dfa02e 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,14 +320,15 @@ 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() {
311 panic!("max interface count reached") 328 panic!(
329 "embassy-usb: interface list full. Increase the `max_interface_count` compile-time setting. Current value: {}",
330 MAX_INTERFACE_COUNT
331 )
312 } 332 }
313 333
314 InterfaceBuilder { 334 InterfaceBuilder {
@@ -326,7 +346,7 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
326 } 346 }
327 347
328 if !self.builder.msos_descriptor.is_in_function_subset() { 348 if !self.builder.msos_descriptor.is_in_function_subset() {
329 self.builder.msos_descriptor.function(self.first_interface.0); 349 self.builder.msos_descriptor.function(self.first_interface);
330 } 350 }
331 351
332 #[cfg(feature = "msos-descriptor")] 352 #[cfg(feature = "msos-descriptor")]
@@ -347,17 +367,9 @@ impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> {
347 self.interface_number 367 self.interface_number
348 } 368 }
349 369
350 pub fn handler(&mut self, handler: &'d mut dyn ControlHandler) {
351 self.builder.interfaces[self.interface_number.0 as usize].handler = Some(handler);
352 }
353
354 /// Allocates a new string index. 370 /// Allocates a new string index.
355 pub fn string(&mut self) -> StringIndex { 371 pub fn string(&mut self) -> StringIndex {
356 let index = self.builder.next_string_index; 372 self.builder.string()
357 self.builder.next_string_index += 1;
358 self.builder.interfaces[self.interface_number.0 as usize].num_strings += 1;
359
360 StringIndex::new(index)
361 } 373 }
362 374
363 /// 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 aec18524b..bfeccd5fe 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -16,10 +16,16 @@ mod descriptor_reader;
16pub mod msos; 16pub mod msos;
17pub mod types; 17pub mod types;
18 18
19mod config {
20 #![allow(unused)]
21 include!(concat!(env!("OUT_DIR"), "/config.rs"));
22}
23
19use embassy_futures::select::{select, Either}; 24use embassy_futures::select::{select, Either};
20use heapless::Vec; 25use heapless::Vec;
21 26
22pub use crate::builder::{Builder, Config}; 27pub use crate::builder::{Builder, Config};
28use crate::config::*;
23use crate::control::*; 29use crate::control::*;
24use crate::descriptor::*; 30use crate::descriptor::*;
25use crate::descriptor_reader::foreach_endpoint; 31use crate::descriptor_reader::foreach_endpoint;
@@ -71,40 +77,92 @@ pub const CONFIGURATION_NONE: u8 = 0;
71/// The bConfiguration value for the single configuration supported by this device. 77/// The bConfiguration value for the single configuration supported by this device.
72pub const CONFIGURATION_VALUE: u8 = 1; 78pub const CONFIGURATION_VALUE: u8 = 1;
73 79
74/// Maximum interface count, configured at compile time.
75pub const MAX_INTERFACE_COUNT: usize = 4;
76
77const STRING_INDEX_MANUFACTURER: u8 = 1; 80const STRING_INDEX_MANUFACTURER: u8 = 1;
78const STRING_INDEX_PRODUCT: u8 = 2; 81const STRING_INDEX_PRODUCT: u8 = 2;
79const STRING_INDEX_SERIAL_NUMBER: u8 = 3; 82const STRING_INDEX_SERIAL_NUMBER: u8 = 3;
80const STRING_INDEX_CUSTOM_START: u8 = 4; 83const STRING_INDEX_CUSTOM_START: u8 = 4;
81 84
82/// A handler trait for changes in the device state of the [UsbDevice]. 85/// Handler for device events and control requests.
83pub trait DeviceStateHandler { 86///
87/// All methods are optional callbacks that will be called by
88/// [`UsbDevice::run()`](crate::UsbDevice::run)
89pub trait Handler {
84 /// Called when the USB device has been enabled or disabled. 90 /// Called when the USB device has been enabled or disabled.
85 fn enabled(&self, _enabled: bool) {} 91 fn enabled(&mut self, _enabled: bool) {}
86 92
87 /// Called when the host resets the device. 93 /// Called after a USB reset after the bus reset sequence is complete.
88 fn reset(&self) {} 94 fn reset(&mut self) {}
89 95
90 /// 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`.
91 fn addressed(&self, _addr: u8) {} 97 fn addressed(&mut self, _addr: u8) {}
92 98
93 /// 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.
94 fn configured(&self, _configured: bool) {} 100 fn configured(&mut self, _configured: bool) {}
95 101
96 /// Called when the bus has entered or exited the suspend state. 102 /// Called when the bus has entered or exited the suspend state.
97 fn suspended(&self, _suspended: bool) {} 103 fn suspended(&mut self, _suspended: bool) {}
98 104
99 /// Called when remote wakeup feature is enabled or disabled. 105 /// Called when remote wakeup feature is enabled or disabled.
100 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 }
101} 161}
102 162
103struct Interface<'d> { 163struct Interface {
104 handler: Option<&'d mut dyn ControlHandler>,
105 current_alt_setting: u8, 164 current_alt_setting: u8,
106 num_alt_settings: u8, 165 num_alt_settings: u8,
107 num_strings: u8,
108} 166}
109 167
110/// Main struct for the USB device stack. 168/// Main struct for the USB device stack.
@@ -116,7 +174,6 @@ pub struct UsbDevice<'d, D: Driver<'d>> {
116 174
117struct Inner<'d, D: Driver<'d>> { 175struct Inner<'d, D: Driver<'d>> {
118 bus: D::Bus, 176 bus: D::Bus,
119 handler: Option<&'d dyn DeviceStateHandler>,
120 177
121 config: Config<'d>, 178 config: Config<'d>,
122 device_descriptor: &'d [u8], 179 device_descriptor: &'d [u8],
@@ -135,7 +192,9 @@ struct Inner<'d, D: Driver<'d>> {
135 /// instead of regular `accept()`. 192 /// instead of regular `accept()`.
136 set_address_pending: bool, 193 set_address_pending: bool,
137 194
138 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
139 #[cfg(feature = "msos-descriptor")] 198 #[cfg(feature = "msos-descriptor")]
140 msos_descriptor: crate::msos::MsOsDescriptorSet<'d>, 199 msos_descriptor: crate::msos::MsOsDescriptorSet<'d>,
141} 200}
@@ -144,11 +203,11 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
144 pub(crate) fn build( 203 pub(crate) fn build(
145 driver: D, 204 driver: D,
146 config: Config<'d>, 205 config: Config<'d>,
147 handler: Option<&'d dyn DeviceStateHandler>, 206 handlers: Vec<&'d mut dyn Handler, MAX_HANDLER_COUNT>,
148 device_descriptor: &'d [u8], 207 device_descriptor: &'d [u8],
149 config_descriptor: &'d [u8], 208 config_descriptor: &'d [u8],
150 bos_descriptor: &'d [u8], 209 bos_descriptor: &'d [u8],
151 interfaces: Vec<Interface<'d>, MAX_INTERFACE_COUNT>, 210 interfaces: Vec<Interface, MAX_INTERFACE_COUNT>,
152 control_buf: &'d mut [u8], 211 control_buf: &'d mut [u8],
153 #[cfg(feature = "msos-descriptor")] msos_descriptor: crate::msos::MsOsDescriptorSet<'d>, 212 #[cfg(feature = "msos-descriptor")] msos_descriptor: crate::msos::MsOsDescriptorSet<'d>,
154 ) -> UsbDevice<'d, D> { 213 ) -> UsbDevice<'d, D> {
@@ -162,7 +221,6 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
162 inner: Inner { 221 inner: Inner {
163 bus, 222 bus,
164 config, 223 config,
165 handler,
166 device_descriptor, 224 device_descriptor,
167 config_descriptor, 225 config_descriptor,
168 bos_descriptor, 226 bos_descriptor,
@@ -174,6 +232,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
174 address: 0, 232 address: 0,
175 set_address_pending: false, 233 set_address_pending: false,
176 interfaces, 234 interfaces,
235 handlers,
177 #[cfg(feature = "msos-descriptor")] 236 #[cfg(feature = "msos-descriptor")]
178 msos_descriptor, 237 msos_descriptor,
179 }, 238 },
@@ -218,7 +277,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
218 self.inner.suspended = false; 277 self.inner.suspended = false;
219 self.inner.remote_wakeup_enabled = false; 278 self.inner.remote_wakeup_enabled = false;
220 279
221 if let Some(h) = &self.inner.handler { 280 for h in &mut self.inner.handlers {
222 h.enabled(false); 281 h.enabled(false);
223 } 282 }
224 } 283 }
@@ -247,7 +306,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
247 self.inner.bus.remote_wakeup().await?; 306 self.inner.bus.remote_wakeup().await?;
248 self.inner.suspended = false; 307 self.inner.suspended = false;
249 308
250 if let Some(h) = &self.inner.handler { 309 for h in &mut self.inner.handlers {
251 h.suspended(false); 310 h.suspended(false);
252 } 311 }
253 312
@@ -358,29 +417,29 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
358 self.remote_wakeup_enabled = false; 417 self.remote_wakeup_enabled = false;
359 self.address = 0; 418 self.address = 0;
360 419
361 for iface in self.interfaces.iter_mut() { 420 for h in &mut self.handlers {
362 iface.current_alt_setting = 0; 421 h.reset();
363 if let Some(h) = &mut iface.handler {
364 h.reset();
365 h.set_alternate_setting(0);
366 }
367 } 422 }
368 423
369 if let Some(h) = &self.handler { 424 for (i, iface) in self.interfaces.iter_mut().enumerate() {
370 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 }
371 } 430 }
372 } 431 }
373 Event::Resume => { 432 Event::Resume => {
374 trace!("usb: resume"); 433 trace!("usb: resume");
375 self.suspended = false; 434 self.suspended = false;
376 if let Some(h) = &self.handler { 435 for h in &mut self.handlers {
377 h.suspended(false); 436 h.suspended(false);
378 } 437 }
379 } 438 }
380 Event::Suspend => { 439 Event::Suspend => {
381 trace!("usb: suspend"); 440 trace!("usb: suspend");
382 self.suspended = true; 441 self.suspended = true;
383 if let Some(h) = &self.handler { 442 for h in &mut self.handlers {
384 h.suspended(true); 443 h.suspended(true);
385 } 444 }
386 } 445 }
@@ -389,7 +448,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
389 self.bus.enable().await; 448 self.bus.enable().await;
390 self.device_state = UsbDeviceState::Default; 449 self.device_state = UsbDeviceState::Default;
391 450
392 if let Some(h) = &self.handler { 451 for h in &mut self.handlers {
393 h.enabled(true); 452 h.enabled(true);
394 } 453 }
395 } 454 }
@@ -398,7 +457,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
398 self.bus.disable().await; 457 self.bus.disable().await;
399 self.device_state = UsbDeviceState::Unpowered; 458 self.device_state = UsbDeviceState::Unpowered;
400 459
401 if let Some(h) = &self.handler { 460 for h in &mut self.handlers {
402 h.enabled(false); 461 h.enabled(false);
403 } 462 }
404 } 463 }
@@ -413,14 +472,14 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
413 (RequestType::Standard, Recipient::Device) => match (req.request, req.value) { 472 (RequestType::Standard, Recipient::Device) => match (req.request, req.value) {
414 (Request::CLEAR_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => { 473 (Request::CLEAR_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => {
415 self.remote_wakeup_enabled = false; 474 self.remote_wakeup_enabled = false;
416 if let Some(h) = &self.handler { 475 for h in &mut self.handlers {
417 h.remote_wakeup_enabled(false); 476 h.remote_wakeup_enabled(false);
418 } 477 }
419 OutResponse::Accepted 478 OutResponse::Accepted
420 } 479 }
421 (Request::SET_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => { 480 (Request::SET_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => {
422 self.remote_wakeup_enabled = true; 481 self.remote_wakeup_enabled = true;
423 if let Some(h) = &self.handler { 482 for h in &mut self.handlers {
424 h.remote_wakeup_enabled(true); 483 h.remote_wakeup_enabled(true);
425 } 484 }
426 OutResponse::Accepted 485 OutResponse::Accepted
@@ -429,7 +488,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
429 self.address = addr as u8; 488 self.address = addr as u8;
430 self.set_address_pending = true; 489 self.set_address_pending = true;
431 self.device_state = UsbDeviceState::Addressed; 490 self.device_state = UsbDeviceState::Addressed;
432 if let Some(h) = &self.handler { 491 for h in &mut self.handlers {
433 h.addressed(self.address); 492 h.addressed(self.address);
434 } 493 }
435 OutResponse::Accepted 494 OutResponse::Accepted
@@ -440,14 +499,14 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
440 499
441 // Enable all endpoints of selected alt settings. 500 // Enable all endpoints of selected alt settings.
442 foreach_endpoint(self.config_descriptor, |ep| { 501 foreach_endpoint(self.config_descriptor, |ep| {
443 let iface = &self.interfaces[ep.interface as usize]; 502 let iface = &self.interfaces[ep.interface.0 as usize];
444 self.bus 503 self.bus
445 .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);
446 }) 505 })
447 .unwrap(); 506 .unwrap();
448 507
449 // Notify handler. 508 // Notify handlers.
450 if let Some(h) = &self.handler { 509 for h in &mut self.handlers {
451 h.configured(true); 510 h.configured(true);
452 } 511 }
453 512
@@ -465,8 +524,8 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
465 }) 524 })
466 .unwrap(); 525 .unwrap();
467 526
468 // Notify handler. 527 // Notify handlers.
469 if let Some(h) = &self.handler { 528 for h in &mut self.handlers {
470 h.configured(false); 529 h.configured(false);
471 } 530 }
472 531
@@ -476,7 +535,8 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
476 _ => OutResponse::Rejected, 535 _ => OutResponse::Rejected,
477 }, 536 },
478 (RequestType::Standard, Recipient::Interface) => { 537 (RequestType::Standard, Recipient::Interface) => {
479 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) {
480 Some(iface) => iface, 540 Some(iface) => iface,
481 None => return OutResponse::Rejected, 541 None => return OutResponse::Rejected,
482 }; 542 };
@@ -494,7 +554,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
494 554
495 // Enable/disable EPs of this interface as needed. 555 // Enable/disable EPs of this interface as needed.
496 foreach_endpoint(self.config_descriptor, |ep| { 556 foreach_endpoint(self.config_descriptor, |ep| {
497 if ep.interface == req.index as u8 { 557 if ep.interface == iface_num {
498 self.bus 558 self.bus
499 .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);
500 } 560 }
@@ -503,8 +563,8 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
503 563
504 // TODO check it is valid (not out of range) 564 // TODO check it is valid (not out of range)
505 565
506 if let Some(handler) = &mut iface.handler { 566 for h in &mut self.handlers {
507 handler.set_alternate_setting(new_altsetting); 567 h.set_alternate_setting(iface_num, new_altsetting);
508 } 568 }
509 OutResponse::Accepted 569 OutResponse::Accepted
510 } 570 }
@@ -524,17 +584,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
524 } 584 }
525 _ => OutResponse::Rejected, 585 _ => OutResponse::Rejected,
526 }, 586 },
527 (RequestType::Class, Recipient::Interface) => { 587 _ => self.handle_control_out_delegated(req, data),
528 let iface = match self.interfaces.get_mut(req.index as usize) {
529 Some(iface) => iface,
530 None => return OutResponse::Rejected,
531 };
532 match &mut iface.handler {
533 Some(handler) => handler.control_out(req, data),
534 None => OutResponse::Rejected,
535 }
536 }
537 _ => OutResponse::Rejected,
538 } 588 }
539 } 589 }
540 590
@@ -579,11 +629,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
579 buf[0] = iface.current_alt_setting; 629 buf[0] = iface.current_alt_setting;
580 InResponse::Accepted(&buf[..1]) 630 InResponse::Accepted(&buf[..1])
581 } 631 }
582 Request::GET_DESCRIPTOR => match &mut iface.handler { 632 _ => self.handle_control_in_delegated(req, buf),
583 Some(handler) => handler.get_descriptor(req, buf),
584 None => InResponse::Rejected,
585 },
586 _ => InResponse::Rejected,
587 } 633 }
588 } 634 }
589 (RequestType::Standard, Recipient::Endpoint) => match req.request { 635 (RequestType::Standard, Recipient::Endpoint) => match req.request {
@@ -598,32 +644,46 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
598 } 644 }
599 _ => InResponse::Rejected, 645 _ => InResponse::Rejected,
600 }, 646 },
601 (RequestType::Class, Recipient::Interface) => {
602 let iface = match self.interfaces.get_mut(req.index as usize) {
603 Some(iface) => iface,
604 None => return InResponse::Rejected,
605 };
606
607 match &mut iface.handler {
608 Some(handler) => handler.control_in(req, buf),
609 None => InResponse::Rejected,
610 }
611 }
612 #[cfg(feature = "msos-descriptor")] 647 #[cfg(feature = "msos-descriptor")]
613 (RequestType::Vendor, Recipient::Device) => { 648 (RequestType::Vendor, Recipient::Device) => {
614 if !self.msos_descriptor.is_empty() { 649 if !self.msos_descriptor.is_empty()
615 if req.request == self.msos_descriptor.vendor_code() && req.index == 7 { 650 && req.request == self.msos_descriptor.vendor_code()
616 // Index 7 retrieves the MS OS Descriptor Set 651 && req.index == 7
617 InResponse::Accepted(self.msos_descriptor.descriptor()) 652 {
618 } else { 653 // Index 7 retrieves the MS OS Descriptor Set
619 InResponse::Rejected 654 InResponse::Accepted(self.msos_descriptor.descriptor())
620 }
621 } else { 655 } else {
622 InResponse::Rejected 656 self.handle_control_in_delegated(req, buf)
623 } 657 }
624 } 658 }
625 _ => 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 }
626 } 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
627 } 687 }
628 688
629 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> {
@@ -646,30 +706,16 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
646 STRING_INDEX_PRODUCT => self.config.product, 706 STRING_INDEX_PRODUCT => self.config.product,
647 STRING_INDEX_SERIAL_NUMBER => self.config.serial_number, 707 STRING_INDEX_SERIAL_NUMBER => self.config.serial_number,
648 _ => { 708 _ => {
649 // Find out which iface owns this string index. 709 let mut s = None;
650 let mut index_left = index - STRING_INDEX_CUSTOM_START; 710 for handler in &mut self.handlers {
651 let mut the_iface = None; 711 let index = StringIndex::new(index);
652 for iface in &mut self.interfaces { 712 let lang_id = req.index;
653 if index_left < iface.num_strings { 713 if let Some(res) = handler.get_string(index, lang_id) {
654 the_iface = Some(iface); 714 s = Some(res);
655 break; 715 break;
656 } 716 }
657 index_left -= iface.num_strings;
658 }
659
660 if let Some(iface) = the_iface {
661 if let Some(handler) = &mut iface.handler {
662 let index = StringIndex::new(index);
663 let lang_id = req.index;
664 handler.get_string(index, lang_id)
665 } else {
666 warn!("String requested to an interface with no handler.");
667 None
668 }
669 } else {
670 warn!("String requested but didn't match to an interface.");
671 None
672 } 717 }
718 s
673 } 719 }
674 }; 720 };
675 721
diff --git a/embassy-usb/src/msos.rs b/embassy-usb/src/msos.rs
index 19ed34979..b1e0335ee 100644
--- a/embassy-usb/src/msos.rs
+++ b/embassy-usb/src/msos.rs
@@ -7,6 +7,7 @@
7use core::mem::size_of; 7use core::mem::size_of;
8 8
9use super::{capability_type, BosWriter}; 9use super::{capability_type, BosWriter};
10use crate::types::InterfaceNumber;
10 11
11/// A serialized Microsoft OS 2.0 Descriptor set. 12/// A serialized Microsoft OS 2.0 Descriptor set.
12/// 13///
@@ -125,7 +126,7 @@ impl<'d> MsOsDescriptorWriter<'d> {
125 } 126 }
126 127
127 /// Add a function subset. 128 /// Add a function subset.
128 pub fn function(&mut self, first_interface: u8) { 129 pub fn function(&mut self, first_interface: InterfaceNumber) {
129 assert!( 130 assert!(
130 self.config_mark.is_some(), 131 self.config_mark.is_some(),
131 "MsOsDescriptorWriter: function subset requires a configuration subset" 132 "MsOsDescriptorWriter: function subset requires a configuration subset"
@@ -376,14 +377,14 @@ impl DescriptorSet for ConfigurationSubsetHeader {
376pub struct FunctionSubsetHeader { 377pub struct FunctionSubsetHeader {
377 wLength: u16, 378 wLength: u16,
378 wDescriptorType: u16, 379 wDescriptorType: u16,
379 bFirstInterface: u8, 380 bFirstInterface: InterfaceNumber,
380 bReserved: u8, 381 bReserved: u8,
381 wSubsetLength: u16, 382 wSubsetLength: u16,
382} 383}
383 384
384impl FunctionSubsetHeader { 385impl FunctionSubsetHeader {
385 /// Creates a function subset header 386 /// Creates a function subset header
386 pub fn new(first_interface: u8) -> Self { 387 pub fn new(first_interface: InterfaceNumber) -> Self {
387 FunctionSubsetHeader { 388 FunctionSubsetHeader {
388 wLength: (size_of::<Self>() as u16).to_le(), 389 wLength: (size_of::<Self>() as u16).to_le(),
389 wDescriptorType: (Self::TYPE as u16).to_le(), 390 wDescriptorType: (Self::TYPE as u16).to_le(),
diff --git a/embassy-usb/src/types.rs b/embassy-usb/src/types.rs
index 1743e61ff..c7a47f7e4 100644
--- a/embassy-usb/src/types.rs
+++ b/embassy-usb/src/types.rs
@@ -1,9 +1,10 @@
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); 6#[repr(transparent)]
7pub struct InterfaceNumber(pub u8);
7 8
8impl InterfaceNumber { 9impl InterfaceNumber {
9 pub(crate) fn new(index: u8) -> InterfaceNumber { 10 pub(crate) fn new(index: u8) -> InterfaceNumber {
@@ -20,7 +21,8 @@ impl From<InterfaceNumber> for u8 {
20/// A handle for a USB string descriptor that contains its index. 21/// A handle for a USB string descriptor that contains its index.
21#[derive(Copy, Clone, Eq, PartialEq)] 22#[derive(Copy, Clone, Eq, PartialEq)]
22#[cfg_attr(feature = "defmt", derive(defmt::Format))] 23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23pub struct StringIndex(u8); 24#[repr(transparent)]
25pub struct StringIndex(pub u8);
24 26
25impl StringIndex { 27impl StringIndex {
26 pub(crate) fn new(index: u8) -> StringIndex { 28 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..6561fc3b4 100644
--- a/examples/nrf52840/src/bin/usb_serial_winusb.rs
+++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs
@@ -12,6 +12,7 @@ use embassy_nrf::{interrupt, pac};
12use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 12use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
13use embassy_usb::driver::EndpointError; 13use embassy_usb::driver::EndpointError;
14use embassy_usb::msos::{self, windows_version}; 14use embassy_usb::msos::{self, windows_version};
15use embassy_usb::types::InterfaceNumber;
15use embassy_usb::{Builder, Config}; 16use embassy_usb::{Builder, Config};
16use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
17 18
@@ -65,7 +66,6 @@ async fn main(_spawner: Spawner) {
65 &mut bos_descriptor, 66 &mut bos_descriptor,
66 &mut msos_descriptor, 67 &mut msos_descriptor,
67 &mut control_buf, 68 &mut control_buf,
68 None,
69 ); 69 );
70 70
71 builder.msos_descriptor(windows_version::WIN8_1, 2); 71 builder.msos_descriptor(windows_version::WIN8_1, 2);
@@ -78,7 +78,7 @@ async fn main(_spawner: Spawner) {
78 // Inside a class constructor, you would just need to call `FunctionBuilder::msos_feature` instead. 78 // Inside a class constructor, you would just need to call `FunctionBuilder::msos_feature` instead.
79 let msos_writer = builder.msos_writer(); 79 let msos_writer = builder.msos_writer();
80 msos_writer.configuration(0); 80 msos_writer.configuration(0);
81 msos_writer.function(0); 81 msos_writer.function(InterfaceNumber(0));
82 msos_writer.function_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); 82 msos_writer.function_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
83 msos_writer.function_feature(msos::RegistryPropertyFeatureDescriptor::new( 83 msos_writer.function_feature(msos::RegistryPropertyFeatureDescriptor::new(
84 "DeviceInterfaceGUIDs", 84 "DeviceInterfaceGUIDs",
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.