aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb/src/builder.rs
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-04-15 23:17:50 +0200
committerDario Nieuwenhuis <[email protected]>2022-04-16 04:30:31 +0200
commit50d257cc7cb6f80118fc47a8c601db958775105c (patch)
tree0c1c6c54c60a5cf41ecd2353b92587d454e551f5 /embassy-usb/src/builder.rs
parent1bf7b4d6c3baceeee0b64f3844fd31928d029917 (diff)
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.
Diffstat (limited to 'embassy-usb/src/builder.rs')
-rw-r--r--embassy-usb/src/builder.rs325
1 files changed, 183 insertions, 142 deletions
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index 41cbfa940..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,7 +117,7 @@ impl<'a> Config<'a> {
117 } 117 }
118} 118}
119 119
120/// Used to build new [`UsbDevice`]s. 120/// [`UsbDevice`] builder.
121pub struct Builder<'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>,
@@ -128,10 +128,9 @@ pub struct Builder<'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>> Builder<'d, D> { 136impl<'d, D: Driver<'d>> Builder<'d, D> {
@@ -207,36 +206,12 @@ impl<'d, D: Driver<'d>> Builder<'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>> Builder<'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}