aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-04-16 02:32:35 +0000
committerGitHub <[email protected]>2022-04-16 02:32:35 +0000
commit0f1a364cd91148ab59773bf7aa43980f0ce6f04e (patch)
tree0c1c6c54c60a5cf41ecd2353b92587d454e551f5
parent1c9adec3c59da48f8084c29b4ece083100a703e3 (diff)
parent50d257cc7cb6f80118fc47a8c601db958775105c (diff)
Merge #720
720: USB: New builder API r=Dirbaio a=Dirbaio usb: improved descriptor building API The same API call allocates interfaces/endpoints/etc and writes their descriptors. This means less API calls, and less possibility to screw things up. DescriptorWriter is now private. Co-authored-by: Dario Nieuwenhuis <[email protected]>
-rw-r--r--embassy-usb-hid/src/lib.rs44
-rw-r--r--embassy-usb-serial/src/lib.rs53
-rw-r--r--embassy-usb/src/builder.rs331
-rw-r--r--embassy-usb/src/descriptor.rs39
-rw-r--r--embassy-usb/src/lib.rs2
-rw-r--r--examples/nrf/src/bin/usb_hid_keyboard.rs4
-rw-r--r--examples/nrf/src/bin/usb_hid_mouse.rs4
-rw-r--r--examples/nrf/src/bin/usb_serial.rs4
-rw-r--r--examples/nrf/src/bin/usb_serial_multitask.rs4
9 files changed, 233 insertions, 252 deletions
diff --git a/embassy-usb-hid/src/lib.rs b/embassy-usb-hid/src/lib.rs
index abcd6b5d9..48e15e86a 100644
--- a/embassy-usb-hid/src/lib.rs
+++ b/embassy-usb-hid/src/lib.rs
@@ -16,7 +16,7 @@ use embassy_usb::driver::EndpointOut;
16use embassy_usb::{ 16use embassy_usb::{
17 control::{ControlHandler, InResponse, OutResponse, Request, RequestType}, 17 control::{ControlHandler, InResponse, OutResponse, Request, RequestType},
18 driver::{Driver, Endpoint, EndpointError, EndpointIn}, 18 driver::{Driver, Endpoint, EndpointError, EndpointIn},
19 UsbDeviceBuilder, 19 Builder,
20}; 20};
21 21
22#[cfg(feature = "usbd-hid")] 22#[cfg(feature = "usbd-hid")]
@@ -98,7 +98,7 @@ pub struct HidReaderWriter<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N
98} 98}
99 99
100fn build<'d, D: Driver<'d>>( 100fn build<'d, D: Driver<'d>>(
101 builder: &mut UsbDeviceBuilder<'d, D>, 101 builder: &mut Builder<'d, D>,
102 state: &'d mut State<'d>, 102 state: &'d mut State<'d>,
103 config: Config<'d>, 103 config: Config<'d>,
104 with_out_endpoint: bool, 104 with_out_endpoint: bool,
@@ -110,23 +110,13 @@ fn build<'d, D: Driver<'d>>(
110 )); 110 ));
111 111
112 let len = config.report_descriptor.len(); 112 let len = config.report_descriptor.len();
113 let if_num = builder.alloc_interface_with_handler(control);
114 let ep_in = builder.alloc_interrupt_endpoint_in(config.max_packet_size, config.poll_ms);
115 let ep_out = if with_out_endpoint {
116 Some(builder.alloc_interrupt_endpoint_out(config.max_packet_size, config.poll_ms))
117 } else {
118 None
119 };
120 113
121 builder.config_descriptor.interface( 114 let mut func = builder.function(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE);
122 if_num, 115 let mut iface = func.interface(Some(control));
123 USB_CLASS_HID, 116 let mut alt = iface.alt_setting(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE);
124 USB_SUBCLASS_NONE,
125 USB_PROTOCOL_NONE,
126 );
127 117
128 // HID descriptor 118 // HID descriptor
129 builder.config_descriptor.write( 119 alt.descriptor(
130 HID_DESC_DESCTYPE_HID, 120 HID_DESC_DESCTYPE_HID,
131 &[ 121 &[
132 // HID Class spec version 122 // HID Class spec version
@@ -144,10 +134,12 @@ fn build<'d, D: Driver<'d>>(
144 ], 134 ],
145 ); 135 );
146 136
147 builder.config_descriptor.endpoint(ep_in.info()); 137 let ep_in = alt.endpoint_interrupt_in(config.max_packet_size, config.poll_ms);
148 if let Some(ep_out) = &ep_out { 138 let ep_out = if with_out_endpoint {
149 builder.config_descriptor.endpoint(ep_out.info()); 139 Some(alt.endpoint_interrupt_out(config.max_packet_size, config.poll_ms))
150 } 140 } else {
141 None
142 };
151 143
152 (ep_out, ep_in, &state.out_report_offset) 144 (ep_out, ep_in, &state.out_report_offset)
153} 145}
@@ -160,11 +152,7 @@ impl<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N: usize>
160 /// This will allocate one IN and one OUT endpoints. If you only need writing (sending) 152 /// This will allocate one IN and one OUT endpoints. If you only need writing (sending)
161 /// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only. 153 /// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only.
162 /// 154 ///
163 pub fn new( 155 pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self {
164 builder: &mut UsbDeviceBuilder<'d, D>,
165 state: &'d mut State<'d>,
166 config: Config<'d>,
167 ) -> Self {
168 let (ep_out, ep_in, offset) = build(builder, state, config, true); 156 let (ep_out, ep_in, offset) = build(builder, state, config, true);
169 157
170 Self { 158 Self {
@@ -246,11 +234,7 @@ impl<'d, D: Driver<'d>, const N: usize> HidWriter<'d, D, N> {
246 /// HID reports. A lower value means better throughput & latency, at the expense 234 /// HID reports. A lower value means better throughput & latency, at the expense
247 /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for 235 /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for
248 /// high performance uses, and a value of 255 is good for best-effort usecases. 236 /// high performance uses, and a value of 255 is good for best-effort usecases.
249 pub fn new( 237 pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self {
250 builder: &mut UsbDeviceBuilder<'d, D>,
251 state: &'d mut State<'d>,
252 config: Config<'d>,
253 ) -> Self {
254 let (ep_out, ep_in, _offset) = build(builder, state, config, false); 238 let (ep_out, ep_in, _offset) = build(builder, state, config, false);
255 239
256 assert!(ep_out.is_none()); 240 assert!(ep_out.is_none());
diff --git a/embassy-usb-serial/src/lib.rs b/embassy-usb-serial/src/lib.rs
index 7b25398d0..4bddc31af 100644
--- a/embassy-usb-serial/src/lib.rs
+++ b/embassy-usb-serial/src/lib.rs
@@ -11,7 +11,7 @@ use core::sync::atomic::{AtomicBool, Ordering};
11use embassy::blocking_mutex::CriticalSectionMutex; 11use embassy::blocking_mutex::CriticalSectionMutex;
12use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request}; 12use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request};
13use embassy_usb::driver::{Endpoint, EndpointError, EndpointIn, EndpointOut}; 13use embassy_usb::driver::{Endpoint, EndpointError, EndpointIn, EndpointOut};
14use embassy_usb::{driver::Driver, types::*, UsbDeviceBuilder}; 14use embassy_usb::{driver::Driver, types::*, Builder};
15 15
16/// This should be used as `device_class` when building the `UsbDevice`. 16/// This should be used as `device_class` when building the `UsbDevice`.
17pub const USB_CLASS_CDC: u8 = 0x02; 17pub const USB_CLASS_CDC: u8 = 0x02;
@@ -163,7 +163,7 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
163 /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For 163 /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For
164 /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64. 164 /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64.
165 pub fn new( 165 pub fn new(
166 builder: &mut UsbDeviceBuilder<'d, D>, 166 builder: &mut Builder<'d, D>,
167 state: &'d mut State<'d>, 167 state: &'d mut State<'d>,
168 max_packet_size: u16, 168 max_packet_size: u16,
169 ) -> Self { 169 ) -> Self {
@@ -175,26 +175,15 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
175 175
176 assert!(builder.control_buf_len() >= 7); 176 assert!(builder.control_buf_len() >= 7);
177 177
178 let comm_if = builder.alloc_interface_with_handler(control); 178 let mut func = builder.function(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE);
179 let comm_ep = builder.alloc_interrupt_endpoint_in(8, 255); 179
180 let data_if = builder.alloc_interface(); 180 // Control interface
181 let read_ep = builder.alloc_bulk_endpoint_out(max_packet_size); 181 let mut iface = func.interface(Some(control));
182 let write_ep = builder.alloc_bulk_endpoint_in(max_packet_size); 182 let comm_if = iface.interface_number();
183 183 let data_if = u8::from(comm_if) + 1;
184 builder.config_descriptor.iad( 184 let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE);
185 comm_if, 185
186 2, 186 alt.descriptor(
187 USB_CLASS_CDC,
188 CDC_SUBCLASS_ACM,
189 CDC_PROTOCOL_NONE,
190 );
191 builder.config_descriptor.interface(
192 comm_if,
193 USB_CLASS_CDC,
194 CDC_SUBCLASS_ACM,
195 CDC_PROTOCOL_NONE,
196 );
197 builder.config_descriptor.write(
198 CS_INTERFACE, 187 CS_INTERFACE,
199 &[ 188 &[
200 CDC_TYPE_HEADER, // bDescriptorSubtype 189 CDC_TYPE_HEADER, // bDescriptorSubtype
@@ -202,14 +191,14 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
202 0x01, // bcdCDC (1.10) 191 0x01, // bcdCDC (1.10)
203 ], 192 ],
204 ); 193 );
205 builder.config_descriptor.write( 194 alt.descriptor(
206 CS_INTERFACE, 195 CS_INTERFACE,
207 &[ 196 &[
208 CDC_TYPE_ACM, // bDescriptorSubtype 197 CDC_TYPE_ACM, // bDescriptorSubtype
209 0x00, // bmCapabilities 198 0x00, // bmCapabilities
210 ], 199 ],
211 ); 200 );
212 builder.config_descriptor.write( 201 alt.descriptor(
213 CS_INTERFACE, 202 CS_INTERFACE,
214 &[ 203 &[
215 CDC_TYPE_UNION, // bDescriptorSubtype 204 CDC_TYPE_UNION, // bDescriptorSubtype
@@ -217,7 +206,7 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
217 data_if.into(), // bSubordinateInterface 206 data_if.into(), // bSubordinateInterface
218 ], 207 ],
219 ); 208 );
220 builder.config_descriptor.write( 209 alt.descriptor(
221 CS_INTERFACE, 210 CS_INTERFACE,
222 &[ 211 &[
223 CDC_TYPE_CALL_MANAGEMENT, // bDescriptorSubtype 212 CDC_TYPE_CALL_MANAGEMENT, // bDescriptorSubtype
@@ -225,13 +214,15 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
225 data_if.into(), // bDataInterface 214 data_if.into(), // bDataInterface
226 ], 215 ],
227 ); 216 );
228 builder.config_descriptor.endpoint(comm_ep.info());
229 217
230 builder 218 let comm_ep = alt.endpoint_interrupt_in(8, 255);
231 .config_descriptor 219
232 .interface(data_if, USB_CLASS_CDC_DATA, 0x00, 0x00); 220 // Data interface
233 builder.config_descriptor.endpoint(write_ep.info()); 221 let mut iface = func.interface(None);
234 builder.config_descriptor.endpoint(read_ep.info()); 222 let data_if = iface.interface_number();
223 let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NONE);
224 let read_ep = alt.endpoint_bulk_out(max_packet_size);
225 let write_ep = alt.endpoint_bulk_in(max_packet_size);
235 226
236 CdcAcmClass { 227 CdcAcmClass {
237 _comm_ep: comm_ep, 228 _comm_ep: comm_ep,
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index 486672055..7e67b4ae6 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -2,7 +2,7 @@ use heapless::Vec;
2 2
3use super::control::ControlHandler; 3use super::control::ControlHandler;
4use super::descriptor::{BosWriter, DescriptorWriter}; 4use super::descriptor::{BosWriter, DescriptorWriter};
5use super::driver::{Driver, EndpointAllocError}; 5use super::driver::{Driver, Endpoint};
6use super::types::*; 6use super::types::*;
7use super::DeviceStateHandler; 7use super::DeviceStateHandler;
8use super::UsbDevice; 8use super::UsbDevice;
@@ -117,8 +117,8 @@ impl<'a> Config<'a> {
117 } 117 }
118} 118}
119 119
120/// Used to build new [`UsbDevice`]s. 120/// [`UsbDevice`] builder.
121pub struct UsbDeviceBuilder<'d, D: Driver<'d>> { 121pub struct Builder<'d, D: Driver<'d>> {
122 config: Config<'d>, 122 config: Config<'d>,
123 handler: Option<&'d dyn DeviceStateHandler>, 123 handler: Option<&'d dyn DeviceStateHandler>,
124 interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>, 124 interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>,
@@ -128,13 +128,12 @@ pub struct UsbDeviceBuilder<'d, D: Driver<'d>> {
128 next_interface_number: u8, 128 next_interface_number: u8,
129 next_string_index: u8, 129 next_string_index: u8,
130 130
131 // TODO make not pub? 131 device_descriptor: DescriptorWriter<'d>,
132 pub device_descriptor: DescriptorWriter<'d>, 132 config_descriptor: DescriptorWriter<'d>,
133 pub config_descriptor: DescriptorWriter<'d>, 133 bos_descriptor: BosWriter<'d>,
134 pub bos_descriptor: BosWriter<'d>,
135} 134}
136 135
137impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> { 136impl<'d, D: Driver<'d>> Builder<'d, D> {
138 /// Creates a builder for constructing a new [`UsbDevice`]. 137 /// Creates a builder for constructing a new [`UsbDevice`].
139 /// 138 ///
140 /// `control_buf` is a buffer used for USB control request data. It should be sized 139 /// `control_buf` is a buffer used for USB control request data. It should be sized
@@ -175,7 +174,7 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
175 config_descriptor.configuration(&config); 174 config_descriptor.configuration(&config);
176 bos_descriptor.bos(); 175 bos_descriptor.bos();
177 176
178 UsbDeviceBuilder { 177 Builder {
179 driver, 178 driver,
180 handler, 179 handler,
181 config, 180 config,
@@ -207,36 +206,12 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
207 ) 206 )
208 } 207 }
209 208
210 /// Allocates a new interface number.
211 pub fn alloc_interface(&mut self) -> InterfaceNumber {
212 let number = self.next_interface_number;
213 self.next_interface_number += 1;
214
215 InterfaceNumber::new(number)
216 }
217
218 /// Returns the size of the control request data buffer. Can be used by 209 /// Returns the size of the control request data buffer. Can be used by
219 /// classes to validate the buffer is large enough for their needs. 210 /// classes to validate the buffer is large enough for their needs.
220 pub fn control_buf_len(&self) -> usize { 211 pub fn control_buf_len(&self) -> usize {
221 self.control_buf.len() 212 self.control_buf.len()
222 } 213 }
223 214
224 /// Allocates a new interface number, with a handler that will be called
225 /// for all the control requests directed to it.
226 pub fn alloc_interface_with_handler(
227 &mut self,
228 handler: &'d mut dyn ControlHandler,
229 ) -> InterfaceNumber {
230 let number = self.next_interface_number;
231 self.next_interface_number += 1;
232
233 if self.interfaces.push((number, handler)).is_err() {
234 panic!("max class count reached")
235 }
236
237 InterfaceNumber::new(number)
238 }
239
240 /// Allocates a new string index. 215 /// Allocates a new string index.
241 pub fn alloc_string(&mut self) -> StringIndex { 216 pub fn alloc_string(&mut self) -> StringIndex {
242 let index = self.next_string_index; 217 let index = self.next_string_index;
@@ -245,146 +220,212 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
245 StringIndex::new(index) 220 StringIndex::new(index)
246 } 221 }
247 222
248 /// Allocates an in endpoint. 223 /// Add an USB function.
249 /// 224 ///
250 /// This directly delegates to [`Driver::alloc_endpoint_in`], so see that method for details. In most 225 /// If [`Config::composite_with_iads`] is set, this will add an IAD descriptor
251 /// cases classes should call the endpoint type specific methods instead. 226 /// with the given class/subclass/protocol, associating all the child interfaces.
252 pub fn alloc_endpoint_in( 227 ///
228 /// If it's not set, no IAD descriptor is added.
229 pub fn function(
253 &mut self, 230 &mut self,
254 ep_addr: Option<EndpointAddress>, 231 class: u8,
255 ep_type: EndpointType, 232 subclass: u8,
256 max_packet_size: u16, 233 protocol: u8,
257 interval: u8, 234 ) -> FunctionBuilder<'_, 'd, D> {
258 ) -> Result<D::EndpointIn, EndpointAllocError> { 235 let iface_count_index = if self.config.composite_with_iads {
259 self.driver 236 self.config_descriptor.iad(
260 .alloc_endpoint_in(ep_addr, ep_type, max_packet_size, interval) 237 InterfaceNumber::new(self.next_interface_number),
238 0,
239 class,
240 subclass,
241 protocol,
242 );
243
244 Some(self.config_descriptor.position() - 5)
245 } else {
246 None
247 };
248
249 FunctionBuilder {
250 builder: self,
251 iface_count_index,
252 }
261 } 253 }
254}
255
256/// Function builder.
257///
258/// A function is a logical grouping of interfaces that perform a given USB function.
259/// If [`Config::composite_with_iads`] is set, each function will have an IAD descriptor.
260/// If not, functions will not be visible as descriptors.
261pub struct FunctionBuilder<'a, 'd, D: Driver<'d>> {
262 builder: &'a mut Builder<'d, D>,
263 iface_count_index: Option<usize>,
264}
262 265
263 /// Allocates an out endpoint. 266impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
267 /// Add an interface to the function.
264 /// 268 ///
265 /// This directly delegates to [`Driver::alloc_endpoint_out`], so see that method for details. In most 269 /// Interface numbers are guaranteed to be allocated consecutively, starting from 0.
266 /// cases classes should call the endpoint type specific methods instead. 270 pub fn interface(
267 pub fn alloc_endpoint_out(
268 &mut self, 271 &mut self,
269 ep_addr: Option<EndpointAddress>, 272 handler: Option<&'d mut dyn ControlHandler>,
270 ep_type: EndpointType, 273 ) -> InterfaceBuilder<'_, 'd, D> {
271 max_packet_size: u16, 274 if let Some(i) = self.iface_count_index {
272 interval: u8, 275 self.builder.config_descriptor.buf[i] += 1;
273 ) -> Result<D::EndpointOut, EndpointAllocError> { 276 }
274 self.driver 277
275 .alloc_endpoint_out(ep_addr, ep_type, max_packet_size, interval) 278 let number = self.builder.next_interface_number;
279 self.builder.next_interface_number += 1;
280
281 if let Some(handler) = handler {
282 if self.builder.interfaces.push((number, handler)).is_err() {
283 panic!("max interface count reached")
284 }
285 }
286
287 InterfaceBuilder {
288 builder: self.builder,
289 interface_number: InterfaceNumber::new(number),
290 next_alt_setting_number: 0,
291 }
276 } 292 }
293}
277 294
278 /// Allocates a control in endpoint. 295/// Interface builder.
279 /// 296pub struct InterfaceBuilder<'a, 'd, D: Driver<'d>> {
280 /// This crate implements the control state machine only for endpoint 0. If classes want to 297 builder: &'a mut Builder<'d, D>,
281 /// support control requests in other endpoints, the state machine must be implemented manually. 298 interface_number: InterfaceNumber,
282 /// This should rarely be needed by classes. 299 next_alt_setting_number: u8,
283 /// 300}
284 /// # Arguments 301
285 /// 302impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> {
286 /// * `max_packet_size` - Maximum packet size in bytes. Must be one of 8, 16, 32 or 64. 303 /// Get the interface number.
287 /// 304 pub fn interface_number(&self) -> InterfaceNumber {
288 /// # Panics 305 self.interface_number
289 ///
290 /// Panics if endpoint allocation fails, because running out of endpoints or memory is not
291 /// feasibly recoverable.
292 #[inline]
293 pub fn alloc_control_endpoint_in(&mut self, max_packet_size: u16) -> D::EndpointIn {
294 self.alloc_endpoint_in(None, EndpointType::Control, max_packet_size, 0)
295 .expect("alloc_ep failed")
296 } 306 }
297 307
298 /// Allocates a control out endpoint. 308 /// Add an alternate setting to the interface and write its descriptor.
299 ///
300 /// This crate implements the control state machine only for endpoint 0. If classes want to
301 /// support control requests in other endpoints, the state machine must be implemented manually.
302 /// This should rarely be needed by classes.
303 ///
304 /// # Arguments
305 /// 309 ///
306 /// * `max_packet_size` - Maximum packet size in bytes. Must be one of 8, 16, 32 or 64. 310 /// Alternate setting numbers are guaranteed to be allocated consecutively, starting from 0.
307 /// 311 ///
308 /// # Panics 312 /// The first alternate setting, with number 0, is the default one.
309 /// 313 pub fn alt_setting(
310 /// Panics if endpoint allocation fails, because running out of endpoints or memory is not 314 &mut self,
311 /// feasibly recoverable. 315 class: u8,
312 #[inline] 316 subclass: u8,
313 pub fn alloc_control_pipe(&mut self, max_packet_size: u16) -> D::ControlPipe { 317 protocol: u8,
314 self.driver 318 ) -> InterfaceAltBuilder<'_, 'd, D> {
315 .alloc_control_pipe(max_packet_size) 319 let number = self.next_alt_setting_number;
316 .expect("alloc_control_pipe failed") 320 self.next_alt_setting_number += 1;
321
322 self.builder.config_descriptor.interface_alt(
323 self.interface_number,
324 number,
325 class,
326 subclass,
327 protocol,
328 None,
329 );
330
331 InterfaceAltBuilder {
332 builder: self.builder,
333 interface_number: self.interface_number,
334 alt_setting_number: number,
335 }
317 } 336 }
337}
318 338
319 /// Allocates a bulk in endpoint. 339/// Interface alternate setting builder.
320 /// 340pub struct InterfaceAltBuilder<'a, 'd, D: Driver<'d>> {
321 /// # Arguments 341 builder: &'a mut Builder<'d, D>,
322 /// 342 interface_number: InterfaceNumber,
323 /// * `max_packet_size` - Maximum packet size in bytes. Must be one of 8, 16, 32 or 64. 343 alt_setting_number: u8,
324 /// 344}
325 /// # Panics 345
326 /// 346impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
327 /// Panics if endpoint allocation fails, because running out of endpoints or memory is not 347 /// Get the interface number.
328 /// feasibly recoverable. 348 pub fn interface_number(&self) -> InterfaceNumber {
329 #[inline] 349 self.interface_number
330 pub fn alloc_bulk_endpoint_in(&mut self, max_packet_size: u16) -> D::EndpointIn {
331 self.alloc_endpoint_in(None, EndpointType::Bulk, max_packet_size, 0)
332 .expect("alloc_ep failed")
333 } 350 }
334 351
335 /// Allocates a bulk out endpoint. 352 /// Get the alternate setting number.
336 /// 353 pub fn alt_setting_number(&self) -> u8 {
337 /// # Arguments 354 self.alt_setting_number
338 ///
339 /// * `max_packet_size` - Maximum packet size in bytes. Must be one of 8, 16, 32 or 64.
340 ///
341 /// # Panics
342 ///
343 /// Panics if endpoint allocation fails, because running out of endpoints or memory is not
344 /// feasibly recoverable.
345 #[inline]
346 pub fn alloc_bulk_endpoint_out(&mut self, max_packet_size: u16) -> D::EndpointOut {
347 self.alloc_endpoint_out(None, EndpointType::Bulk, max_packet_size, 0)
348 .expect("alloc_ep failed")
349 } 355 }
350 356
351 /// Allocates a bulk in endpoint. 357 /// Add a custom descriptor to this alternate setting.
352 ///
353 /// # Arguments
354 ///
355 /// * `max_packet_size` - Maximum packet size in bytes. Cannot exceed 64 bytes.
356 /// 358 ///
357 /// # Panics 359 /// Descriptors are written in the order builder functions are called. Note that some
358 /// 360 /// classes care about the order.
359 /// Panics if endpoint allocation fails, because running out of endpoints or memory is not 361 pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) {
360 /// feasibly recoverable. 362 self.builder
361 #[inline] 363 .config_descriptor
362 pub fn alloc_interrupt_endpoint_in( 364 .write(descriptor_type, descriptor)
365 }
366
367 fn endpoint_in(
363 &mut self, 368 &mut self,
369 ep_addr: Option<EndpointAddress>,
370 ep_type: EndpointType,
364 max_packet_size: u16, 371 max_packet_size: u16,
365 interval: u8, 372 interval: u8,
366 ) -> D::EndpointIn { 373 ) -> D::EndpointIn {
367 self.alloc_endpoint_in(None, EndpointType::Interrupt, max_packet_size, interval) 374 let ep = self
368 .expect("alloc_ep failed") 375 .builder
376 .driver
377 .alloc_endpoint_in(ep_addr, ep_type, max_packet_size, interval)
378 .expect("alloc_endpoint_in failed");
379
380 self.builder.config_descriptor.endpoint(ep.info());
381
382 ep
369 } 383 }
370 384
371 /// Allocates a bulk in endpoint. 385 fn endpoint_out(
372 ///
373 /// # Arguments
374 ///
375 /// * `max_packet_size` - Maximum packet size in bytes. Cannot exceed 64 bytes.
376 ///
377 /// # Panics
378 ///
379 /// Panics if endpoint allocation fails, because running out of endpoints or memory is not
380 /// feasibly recoverable.
381 #[inline]
382 pub fn alloc_interrupt_endpoint_out(
383 &mut self, 386 &mut self,
387 ep_addr: Option<EndpointAddress>,
388 ep_type: EndpointType,
384 max_packet_size: u16, 389 max_packet_size: u16,
385 interval: u8, 390 interval: u8,
386 ) -> D::EndpointOut { 391 ) -> D::EndpointOut {
387 self.alloc_endpoint_out(None, EndpointType::Interrupt, max_packet_size, interval) 392 let ep = self
388 .expect("alloc_ep failed") 393 .builder
394 .driver
395 .alloc_endpoint_out(ep_addr, ep_type, max_packet_size, interval)
396 .expect("alloc_endpoint_out failed");
397
398 self.builder.config_descriptor.endpoint(ep.info());
399
400 ep
401 }
402
403 /// Allocate a BULK IN endpoint and write its descriptor.
404 ///
405 /// Descriptors are written in the order builder functions are called. Note that some
406 /// classes care about the order.
407 pub fn endpoint_bulk_in(&mut self, max_packet_size: u16) -> D::EndpointIn {
408 self.endpoint_in(None, EndpointType::Bulk, max_packet_size, 0)
409 }
410
411 /// Allocate a BULK OUT endpoint and write its descriptor.
412 ///
413 /// Descriptors are written in the order builder functions are called. Note that some
414 /// classes care about the order.
415 pub fn endpoint_bulk_out(&mut self, max_packet_size: u16) -> D::EndpointOut {
416 self.endpoint_out(None, EndpointType::Bulk, max_packet_size, 0)
417 }
418
419 /// Allocate a INTERRUPT IN endpoint and write its descriptor.
420 ///
421 /// Descriptors are written in the order builder functions are called. Note that some
422 /// classes care about the order.
423 pub fn endpoint_interrupt_in(&mut self, max_packet_size: u16, interval: u8) -> D::EndpointIn {
424 self.endpoint_in(None, EndpointType::Interrupt, max_packet_size, interval)
425 }
426
427 /// Allocate a INTERRUPT OUT endpoint and write its descriptor.
428 pub fn endpoint_interrupt_out(&mut self, max_packet_size: u16, interval: u8) -> D::EndpointOut {
429 self.endpoint_out(None, EndpointType::Interrupt, max_packet_size, interval)
389 } 430 }
390} 431}
diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs
index ff971e127..b61dea4b4 100644
--- a/embassy-usb/src/descriptor.rs
+++ b/embassy-usb/src/descriptor.rs
@@ -33,12 +33,11 @@ pub mod capability_type {
33} 33}
34 34
35/// A writer for USB descriptors. 35/// A writer for USB descriptors.
36pub struct DescriptorWriter<'a> { 36pub(crate) struct DescriptorWriter<'a> {
37 buf: &'a mut [u8], 37 pub buf: &'a mut [u8],
38 position: usize, 38 position: usize,
39 num_interfaces_mark: Option<usize>, 39 num_interfaces_mark: Option<usize>,
40 num_endpoints_mark: Option<usize>, 40 num_endpoints_mark: Option<usize>,
41 write_iads: bool,
42} 41}
43 42
44impl<'a> DescriptorWriter<'a> { 43impl<'a> DescriptorWriter<'a> {
@@ -48,7 +47,6 @@ impl<'a> DescriptorWriter<'a> {
48 position: 0, 47 position: 0,
49 num_interfaces_mark: None, 48 num_interfaces_mark: None,
50 num_endpoints_mark: None, 49 num_endpoints_mark: None,
51 write_iads: false,
52 } 50 }
53 } 51 }
54 52
@@ -106,8 +104,6 @@ impl<'a> DescriptorWriter<'a> {
106 pub(crate) fn configuration(&mut self, config: &Config) { 104 pub(crate) fn configuration(&mut self, config: &Config) {
107 self.num_interfaces_mark = Some(self.position + 4); 105 self.num_interfaces_mark = Some(self.position + 4);
108 106
109 self.write_iads = config.composite_with_iads;
110
111 self.write( 107 self.write(
112 descriptor_type::CONFIGURATION, 108 descriptor_type::CONFIGURATION,
113 &[ 109 &[
@@ -160,10 +156,6 @@ impl<'a> DescriptorWriter<'a> {
160 function_sub_class: u8, 156 function_sub_class: u8,
161 function_protocol: u8, 157 function_protocol: u8,
162 ) { 158 ) {
163 if !self.write_iads {
164 return;
165 }
166
167 self.write( 159 self.write(
168 descriptor_type::IAD, 160 descriptor_type::IAD,
169 &[ 161 &[
@@ -177,33 +169,6 @@ impl<'a> DescriptorWriter<'a> {
177 ); 169 );
178 } 170 }
179 171
180 /// Writes a interface descriptor.
181 ///
182 /// # Arguments
183 ///
184 /// * `number` - Interface number previously allocated with
185 /// [`UsbDeviceBuilder::interface`](crate::bus::UsbDeviceBuilder::interface).
186 /// * `interface_class` - Class code assigned by USB.org. Use `0xff` for vendor-specific devices
187 /// that do not conform to any class.
188 /// * `interface_sub_class` - Sub-class code. Depends on class.
189 /// * `interface_protocol` - Protocol code. Depends on class and sub-class.
190 pub fn interface(
191 &mut self,
192 number: InterfaceNumber,
193 interface_class: u8,
194 interface_sub_class: u8,
195 interface_protocol: u8,
196 ) {
197 self.interface_alt(
198 number,
199 DEFAULT_ALTERNATE_SETTING,
200 interface_class,
201 interface_sub_class,
202 interface_protocol,
203 None,
204 )
205 }
206
207 /// Writes a interface descriptor with a specific alternate setting and 172 /// Writes a interface descriptor with a specific alternate setting and
208 /// interface string identifier. 173 /// interface string identifier.
209 /// 174 ///
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index baeca099f..7cd00fbaf 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -19,8 +19,8 @@ use self::descriptor::*;
19use self::driver::{Bus, Driver, Event}; 19use self::driver::{Bus, Driver, Event};
20use self::types::*; 20use self::types::*;
21 21
22pub use self::builder::Builder;
22pub use self::builder::Config; 23pub use self::builder::Config;
23pub use self::builder::UsbDeviceBuilder;
24 24
25/// The global state of the USB device. 25/// The global state of the USB device.
26/// 26///
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs
index a2d78b08e..9fa7ab334 100644
--- a/examples/nrf/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf/src/bin/usb_hid_keyboard.rs
@@ -17,7 +17,7 @@ use embassy_nrf::pac;
17use embassy_nrf::usb::Driver; 17use embassy_nrf::usb::Driver;
18use embassy_nrf::Peripherals; 18use embassy_nrf::Peripherals;
19use embassy_usb::control::OutResponse; 19use embassy_usb::control::OutResponse;
20use embassy_usb::{Config, DeviceStateHandler, UsbDeviceBuilder}; 20use embassy_usb::{Builder, Config, DeviceStateHandler};
21use embassy_usb_hid::{HidReaderWriter, ReportId, RequestHandler, State}; 21use embassy_usb_hid::{HidReaderWriter, ReportId, RequestHandler, State};
22use futures::future::join; 22use futures::future::join;
23use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 23use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
@@ -77,7 +77,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
77 77
78 let mut state = State::new(); 78 let mut state = State::new();
79 79
80 let mut builder = UsbDeviceBuilder::new( 80 let mut builder = Builder::new(
81 driver, 81 driver,
82 config, 82 config,
83 &mut device_descriptor, 83 &mut device_descriptor,
diff --git a/examples/nrf/src/bin/usb_hid_mouse.rs b/examples/nrf/src/bin/usb_hid_mouse.rs
index 1e98dd1ae..92aeffda2 100644
--- a/examples/nrf/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf/src/bin/usb_hid_mouse.rs
@@ -12,7 +12,7 @@ use embassy_nrf::pac;
12use embassy_nrf::usb::Driver; 12use embassy_nrf::usb::Driver;
13use embassy_nrf::Peripherals; 13use embassy_nrf::Peripherals;
14use embassy_usb::control::OutResponse; 14use embassy_usb::control::OutResponse;
15use embassy_usb::{Config, UsbDeviceBuilder}; 15use embassy_usb::{Builder, Config};
16use embassy_usb_hid::{HidWriter, ReportId, RequestHandler, State}; 16use embassy_usb_hid::{HidWriter, ReportId, RequestHandler, State};
17use futures::future::join; 17use futures::future::join;
18use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 18use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
@@ -54,7 +54,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
54 54
55 let mut state = State::new(); 55 let mut state = State::new();
56 56
57 let mut builder = UsbDeviceBuilder::new( 57 let mut builder = Builder::new(
58 driver, 58 driver,
59 config, 59 config,
60 &mut device_descriptor, 60 &mut device_descriptor,
diff --git a/examples/nrf/src/bin/usb_serial.rs b/examples/nrf/src/bin/usb_serial.rs
index 987cc4139..6081ee917 100644
--- a/examples/nrf/src/bin/usb_serial.rs
+++ b/examples/nrf/src/bin/usb_serial.rs
@@ -11,7 +11,7 @@ use embassy_nrf::pac;
11use embassy_nrf::usb::{Driver, Instance}; 11use embassy_nrf::usb::{Driver, Instance};
12use embassy_nrf::Peripherals; 12use embassy_nrf::Peripherals;
13use embassy_usb::driver::EndpointError; 13use embassy_usb::driver::EndpointError;
14use embassy_usb::{Config, UsbDeviceBuilder}; 14use embassy_usb::{Builder, Config};
15use embassy_usb_serial::{CdcAcmClass, State}; 15use embassy_usb_serial::{CdcAcmClass, State};
16use futures::future::join; 16use futures::future::join;
17 17
@@ -47,7 +47,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
47 47
48 let mut state = State::new(); 48 let mut state = State::new();
49 49
50 let mut builder = UsbDeviceBuilder::new( 50 let mut builder = Builder::new(
51 driver, 51 driver,
52 config, 52 config,
53 &mut device_descriptor, 53 &mut device_descriptor,
diff --git a/examples/nrf/src/bin/usb_serial_multitask.rs b/examples/nrf/src/bin/usb_serial_multitask.rs
index 5fcb0e052..d4b3000e7 100644
--- a/examples/nrf/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf/src/bin/usb_serial_multitask.rs
@@ -12,7 +12,7 @@ use embassy_nrf::usb::Driver;
12use embassy_nrf::Peripherals; 12use embassy_nrf::Peripherals;
13use embassy_nrf::{interrupt, peripherals}; 13use embassy_nrf::{interrupt, peripherals};
14use embassy_usb::driver::EndpointError; 14use embassy_usb::driver::EndpointError;
15use embassy_usb::{Config, UsbDevice, UsbDeviceBuilder}; 15use embassy_usb::{Builder, Config, UsbDevice};
16use embassy_usb_serial::{CdcAcmClass, State}; 16use embassy_usb_serial::{CdcAcmClass, State};
17 17
18use defmt_rtt as _; // global logger 18use defmt_rtt as _; // global logger
@@ -72,7 +72,7 @@ async fn main(spawner: Spawner, p: Peripherals) {
72 }); 72 });
73 73
74 // Create embassy-usb DeviceBuilder using the driver and config. 74 // Create embassy-usb DeviceBuilder using the driver and config.
75 let mut builder = UsbDeviceBuilder::new( 75 let mut builder = Builder::new(
76 driver, 76 driver,
77 config, 77 config,
78 &mut res.device_descriptor, 78 &mut res.device_descriptor,