aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb/src
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-09-16 19:51:52 +0000
committerGitHub <[email protected]>2024-09-16 19:51:52 +0000
commitae8caf3f55d91579234f199458c369536fd39bb1 (patch)
tree43e2180b0292cece5d4f590f06f4717cc97c9b09 /embassy-usb/src
parente90b3bc4494682ae23d5839328ab950e34ca7cfe (diff)
parenta8ca6713e6e9b7ad5dd53f9b46bcf5e893adda1e (diff)
Merge pull request #3314 from elagil/add_iso_endpoint_support
Add ISO endpoint support
Diffstat (limited to 'embassy-usb/src')
-rw-r--r--embassy-usb/src/builder.rs140
-rw-r--r--embassy-usb/src/descriptor.rs91
2 files changed, 206 insertions, 25 deletions
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index 7168e077c..e1bf8041f 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -1,8 +1,8 @@
1use heapless::Vec; 1use heapless::Vec;
2 2
3use crate::config::MAX_HANDLER_COUNT; 3use crate::config::MAX_HANDLER_COUNT;
4use crate::descriptor::{BosWriter, DescriptorWriter}; 4use crate::descriptor::{BosWriter, DescriptorWriter, SynchronizationType, UsageType};
5use crate::driver::{Driver, Endpoint, EndpointType}; 5use crate::driver::{Driver, Endpoint, EndpointInfo, EndpointType};
6use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter}; 6use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter};
7use crate::types::{InterfaceNumber, StringIndex}; 7use crate::types::{InterfaceNumber, StringIndex};
8use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; 8use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START};
@@ -414,7 +414,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
414 /// Descriptors are written in the order builder functions are called. Note that some 414 /// Descriptors are written in the order builder functions are called. Note that some
415 /// classes care about the order. 415 /// classes care about the order.
416 pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) { 416 pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) {
417 self.builder.config_descriptor.write(descriptor_type, descriptor); 417 self.builder.config_descriptor.write(descriptor_type, descriptor, &[]);
418 } 418 }
419 419
420 /// Add a custom Binary Object Store (BOS) descriptor to this alternate setting. 420 /// Add a custom Binary Object Store (BOS) descriptor to this alternate setting.
@@ -422,26 +422,80 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
422 self.builder.bos_descriptor.capability(capability_type, capability); 422 self.builder.bos_descriptor.capability(capability_type, capability);
423 } 423 }
424 424
425 fn endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { 425 /// Write a custom endpoint descriptor for a certain endpoint.
426 ///
427 /// This can be necessary, if the endpoint descriptors can only be written
428 /// after the endpoint was created. As an example, an endpoint descriptor
429 /// may contain the address of an endpoint that was allocated earlier.
430 pub fn endpoint_descriptor(
431 &mut self,
432 endpoint: &EndpointInfo,
433 synchronization_type: SynchronizationType,
434 usage_type: UsageType,
435 extra_fields: &[u8],
436 ) {
437 self.builder
438 .config_descriptor
439 .endpoint(endpoint, synchronization_type, usage_type, extra_fields);
440 }
441
442 /// Allocate an IN endpoint, without writing its descriptor.
443 ///
444 /// Used for granular control over the order of endpoint and descriptor creation.
445 pub fn alloc_endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn {
426 let ep = self 446 let ep = self
427 .builder 447 .builder
428 .driver 448 .driver
429 .alloc_endpoint_in(ep_type, max_packet_size, interval_ms) 449 .alloc_endpoint_in(ep_type, max_packet_size, interval_ms)
430 .expect("alloc_endpoint_in failed"); 450 .expect("alloc_endpoint_in failed");
431 451
432 self.builder.config_descriptor.endpoint(ep.info()); 452 ep
453 }
454
455 fn endpoint_in(
456 &mut self,
457 ep_type: EndpointType,
458 max_packet_size: u16,
459 interval_ms: u8,
460 synchronization_type: SynchronizationType,
461 usage_type: UsageType,
462 extra_fields: &[u8],
463 ) -> D::EndpointIn {
464 let ep = self.alloc_endpoint_in(ep_type, max_packet_size, interval_ms);
465 self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields);
433 466
434 ep 467 ep
435 } 468 }
436 469
437 fn endpoint_out(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { 470 /// Allocate an OUT endpoint, without writing its descriptor.
471 ///
472 /// Use for granular control over the order of endpoint and descriptor creation.
473 pub fn alloc_endpoint_out(
474 &mut self,
475 ep_type: EndpointType,
476 max_packet_size: u16,
477 interval_ms: u8,
478 ) -> D::EndpointOut {
438 let ep = self 479 let ep = self
439 .builder 480 .builder
440 .driver 481 .driver
441 .alloc_endpoint_out(ep_type, max_packet_size, interval_ms) 482 .alloc_endpoint_out(ep_type, max_packet_size, interval_ms)
442 .expect("alloc_endpoint_out failed"); 483 .expect("alloc_endpoint_out failed");
443 484
444 self.builder.config_descriptor.endpoint(ep.info()); 485 ep
486 }
487
488 fn endpoint_out(
489 &mut self,
490 ep_type: EndpointType,
491 max_packet_size: u16,
492 interval_ms: u8,
493 synchronization_type: SynchronizationType,
494 usage_type: UsageType,
495 extra_fields: &[u8],
496 ) -> D::EndpointOut {
497 let ep = self.alloc_endpoint_out(ep_type, max_packet_size, interval_ms);
498 self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields);
445 499
446 ep 500 ep
447 } 501 }
@@ -451,7 +505,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
451 /// Descriptors are written in the order builder functions are called. Note that some 505 /// Descriptors are written in the order builder functions are called. Note that some
452 /// classes care about the order. 506 /// classes care about the order.
453 pub fn endpoint_bulk_in(&mut self, max_packet_size: u16) -> D::EndpointIn { 507 pub fn endpoint_bulk_in(&mut self, max_packet_size: u16) -> D::EndpointIn {
454 self.endpoint_in(EndpointType::Bulk, max_packet_size, 0) 508 self.endpoint_in(
509 EndpointType::Bulk,
510 max_packet_size,
511 0,
512 SynchronizationType::NoSynchronization,
513 UsageType::DataEndpoint,
514 &[],
515 )
455 } 516 }
456 517
457 /// Allocate a BULK OUT endpoint and write its descriptor. 518 /// Allocate a BULK OUT endpoint and write its descriptor.
@@ -459,7 +520,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
459 /// Descriptors are written in the order builder functions are called. Note that some 520 /// Descriptors are written in the order builder functions are called. Note that some
460 /// classes care about the order. 521 /// classes care about the order.
461 pub fn endpoint_bulk_out(&mut self, max_packet_size: u16) -> D::EndpointOut { 522 pub fn endpoint_bulk_out(&mut self, max_packet_size: u16) -> D::EndpointOut {
462 self.endpoint_out(EndpointType::Bulk, max_packet_size, 0) 523 self.endpoint_out(
524 EndpointType::Bulk,
525 max_packet_size,
526 0,
527 SynchronizationType::NoSynchronization,
528 UsageType::DataEndpoint,
529 &[],
530 )
463 } 531 }
464 532
465 /// Allocate a INTERRUPT IN endpoint and write its descriptor. 533 /// Allocate a INTERRUPT IN endpoint and write its descriptor.
@@ -467,24 +535,66 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
467 /// Descriptors are written in the order builder functions are called. Note that some 535 /// Descriptors are written in the order builder functions are called. Note that some
468 /// classes care about the order. 536 /// classes care about the order.
469 pub fn endpoint_interrupt_in(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { 537 pub fn endpoint_interrupt_in(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn {
470 self.endpoint_in(EndpointType::Interrupt, max_packet_size, interval_ms) 538 self.endpoint_in(
539 EndpointType::Interrupt,
540 max_packet_size,
541 interval_ms,
542 SynchronizationType::NoSynchronization,
543 UsageType::DataEndpoint,
544 &[],
545 )
471 } 546 }
472 547
473 /// Allocate a INTERRUPT OUT endpoint and write its descriptor. 548 /// Allocate a INTERRUPT OUT endpoint and write its descriptor.
474 pub fn endpoint_interrupt_out(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { 549 pub fn endpoint_interrupt_out(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut {
475 self.endpoint_out(EndpointType::Interrupt, max_packet_size, interval_ms) 550 self.endpoint_out(
551 EndpointType::Interrupt,
552 max_packet_size,
553 interval_ms,
554 SynchronizationType::NoSynchronization,
555 UsageType::DataEndpoint,
556 &[],
557 )
476 } 558 }
477 559
478 /// Allocate a ISOCHRONOUS IN endpoint and write its descriptor. 560 /// Allocate a ISOCHRONOUS IN endpoint and write its descriptor.
479 /// 561 ///
480 /// Descriptors are written in the order builder functions are called. Note that some 562 /// Descriptors are written in the order builder functions are called. Note that some
481 /// classes care about the order. 563 /// classes care about the order.
482 pub fn endpoint_isochronous_in(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { 564 pub fn endpoint_isochronous_in(
483 self.endpoint_in(EndpointType::Isochronous, max_packet_size, interval_ms) 565 &mut self,
566 max_packet_size: u16,
567 interval_ms: u8,
568 synchronization_type: SynchronizationType,
569 usage_type: UsageType,
570 extra_fields: &[u8],
571 ) -> D::EndpointIn {
572 self.endpoint_in(
573 EndpointType::Isochronous,
574 max_packet_size,
575 interval_ms,
576 synchronization_type,
577 usage_type,
578 extra_fields,
579 )
484 } 580 }
485 581
486 /// Allocate a ISOCHRONOUS OUT endpoint and write its descriptor. 582 /// Allocate a ISOCHRONOUS OUT endpoint and write its descriptor.
487 pub fn endpoint_isochronous_out(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { 583 pub fn endpoint_isochronous_out(
488 self.endpoint_out(EndpointType::Isochronous, max_packet_size, interval_ms) 584 &mut self,
585 max_packet_size: u16,
586 interval_ms: u8,
587 synchronization_type: SynchronizationType,
588 usage_type: UsageType,
589 extra_fields: &[u8],
590 ) -> D::EndpointOut {
591 self.endpoint_out(
592 EndpointType::Isochronous,
593 max_packet_size,
594 interval_ms,
595 synchronization_type,
596 usage_type,
597 extra_fields,
598 )
489 } 599 }
490} 600}
diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs
index c4d79e39f..06ebe0481 100644
--- a/embassy-usb/src/descriptor.rs
+++ b/embassy-usb/src/descriptor.rs
@@ -1,4 +1,5 @@
1//! Utilities for writing USB descriptors. 1//! Utilities for writing USB descriptors.
2use embassy_usb_driver::EndpointType;
2 3
3use crate::builder::Config; 4use crate::builder::Config;
4use crate::driver::EndpointInfo; 5use crate::driver::EndpointInfo;
@@ -38,6 +39,40 @@ pub mod capability_type {
38 pub const PLATFORM: u8 = 5; 39 pub const PLATFORM: u8 = 5;
39} 40}
40 41
42/// USB endpoint synchronization type. The values of this enum can be directly
43/// cast into `u8` to get the bmAttributes synchronization type bits.
44/// Values other than `NoSynchronization` are only allowed on isochronous endpoints.
45#[repr(u8)]
46#[derive(Copy, Clone, Eq, PartialEq, Debug)]
47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
48pub enum SynchronizationType {
49 /// No synchronization is used.
50 NoSynchronization = 0b00,
51 /// Unsynchronized, although sinks provide data rate feedback.
52 Asynchronous = 0b01,
53 /// Synchronized using feedback or feedforward data rate information.
54 Adaptive = 0b10,
55 /// Synchronized to the USB’s SOF.
56 Synchronous = 0b11,
57}
58
59/// USB endpoint usage type. The values of this enum can be directly cast into
60/// `u8` to get the bmAttributes usage type bits.
61/// Values other than `DataEndpoint` are only allowed on isochronous endpoints.
62#[repr(u8)]
63#[derive(Copy, Clone, Eq, PartialEq, Debug)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65pub enum UsageType {
66 /// Use the endpoint for regular data transfer.
67 DataEndpoint = 0b00,
68 /// Endpoint conveys explicit feedback information for one or more data endpoints.
69 FeedbackEndpoint = 0b01,
70 /// A data endpoint that also serves as an implicit feedback endpoint for one or more data endpoints.
71 ImplicitFeedbackDataEndpoint = 0b10,
72 /// Reserved usage type.
73 Reserved = 0b11,
74}
75
41/// A writer for USB descriptors. 76/// A writer for USB descriptors.
42pub(crate) struct DescriptorWriter<'a> { 77pub(crate) struct DescriptorWriter<'a> {
43 pub buf: &'a mut [u8], 78 pub buf: &'a mut [u8],
@@ -65,23 +100,26 @@ impl<'a> DescriptorWriter<'a> {
65 self.position 100 self.position
66 } 101 }
67 102
68 /// Writes an arbitrary (usually class-specific) descriptor. 103 /// Writes an arbitrary (usually class-specific) descriptor with optional extra fields.
69 pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8]) { 104 pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8], extra_fields: &[u8]) {
70 let length = descriptor.len(); 105 let descriptor_length = descriptor.len();
106 let extra_fields_length = extra_fields.len();
107 let total_length = descriptor_length + extra_fields_length;
71 108
72 assert!( 109 assert!(
73 (self.position + 2 + length) <= self.buf.len() && (length + 2) <= 255, 110 (self.position + 2 + total_length) <= self.buf.len() && (total_length + 2) <= 255,
74 "Descriptor buffer full" 111 "Descriptor buffer full"
75 ); 112 );
76 113
77 self.buf[self.position] = (length + 2) as u8; 114 self.buf[self.position] = (total_length + 2) as u8;
78 self.buf[self.position + 1] = descriptor_type; 115 self.buf[self.position + 1] = descriptor_type;
79 116
80 let start = self.position + 2; 117 let start = self.position + 2;
81 118
82 self.buf[start..start + length].copy_from_slice(descriptor); 119 self.buf[start..start + descriptor_length].copy_from_slice(descriptor);
120 self.buf[start + descriptor_length..start + total_length].copy_from_slice(extra_fields);
83 121
84 self.position = start + length; 122 self.position = start + total_length;
85 } 123 }
86 124
87 pub(crate) fn configuration(&mut self, config: &Config) { 125 pub(crate) fn configuration(&mut self, config: &Config) {
@@ -99,6 +137,7 @@ impl<'a> DescriptorWriter<'a> {
99 | if config.supports_remote_wakeup { 0x20 } else { 0x00 }, // bmAttributes 137 | if config.supports_remote_wakeup { 0x20 } else { 0x00 }, // bmAttributes
100 (config.max_power / 2) as u8, // bMaxPower 138 (config.max_power / 2) as u8, // bMaxPower
101 ], 139 ],
140 &[],
102 ); 141 );
103 } 142 }
104 143
@@ -145,6 +184,7 @@ impl<'a> DescriptorWriter<'a> {
145 function_protocol, 184 function_protocol,
146 0, 185 0,
147 ], 186 ],
187 &[],
148 ); 188 );
149 } 189 }
150 190
@@ -195,6 +235,7 @@ impl<'a> DescriptorWriter<'a> {
195 interface_protocol, // bInterfaceProtocol 235 interface_protocol, // bInterfaceProtocol
196 str_index, // iInterface 236 str_index, // iInterface
197 ], 237 ],
238 &[],
198 ); 239 );
199 } 240 }
200 241
@@ -204,21 +245,50 @@ impl<'a> DescriptorWriter<'a> {
204 /// 245 ///
205 /// * `endpoint` - Endpoint previously allocated with 246 /// * `endpoint` - Endpoint previously allocated with
206 /// [`UsbDeviceBuilder`](crate::bus::UsbDeviceBuilder). 247 /// [`UsbDeviceBuilder`](crate::bus::UsbDeviceBuilder).
207 pub fn endpoint(&mut self, endpoint: &EndpointInfo) { 248 /// * `synchronization_type` - The synchronization type of the endpoint.
249 /// * `usage_type` - The usage type of the endpoint.
250 /// * `extra_fields` - Additional, class-specific entries at the end of the endpoint descriptor.
251 pub fn endpoint(
252 &mut self,
253 endpoint: &EndpointInfo,
254 synchronization_type: SynchronizationType,
255 usage_type: UsageType,
256 extra_fields: &[u8],
257 ) {
208 match self.num_endpoints_mark { 258 match self.num_endpoints_mark {
209 Some(mark) => self.buf[mark] += 1, 259 Some(mark) => self.buf[mark] += 1,
210 None => panic!("you can only call `endpoint` after `interface/interface_alt`."), 260 None => panic!("you can only call `endpoint` after `interface/interface_alt`."),
211 }; 261 };
212 262
263 let mut bm_attributes = endpoint.ep_type as u8;
264
265 // Synchronization types other than `NoSynchronization`,
266 // and usage types other than `DataEndpoint`
267 // are only allowed for isochronous endpoints.
268 if endpoint.ep_type != EndpointType::Isochronous {
269 assert_eq!(synchronization_type, SynchronizationType::NoSynchronization);
270 assert_eq!(usage_type, UsageType::DataEndpoint);
271 } else {
272 if usage_type == UsageType::FeedbackEndpoint {
273 assert_eq!(synchronization_type, SynchronizationType::NoSynchronization)
274 }
275
276 let synchronization_bm_attibutes: u8 = (synchronization_type as u8) << 2;
277 let usage_bm_attibutes: u8 = (usage_type as u8) << 4;
278
279 bm_attributes |= usage_bm_attibutes | synchronization_bm_attibutes;
280 }
281
213 self.write( 282 self.write(
214 descriptor_type::ENDPOINT, 283 descriptor_type::ENDPOINT,
215 &[ 284 &[
216 endpoint.addr.into(), // bEndpointAddress 285 endpoint.addr.into(), // bEndpointAddress
217 endpoint.ep_type as u8, // bmAttributes 286 bm_attributes, // bmAttributes
218 endpoint.max_packet_size as u8, 287 endpoint.max_packet_size as u8,
219 (endpoint.max_packet_size >> 8) as u8, // wMaxPacketSize 288 (endpoint.max_packet_size >> 8) as u8, // wMaxPacketSize
220 endpoint.interval_ms, // bInterval 289 endpoint.interval_ms, // bInterval
221 ], 290 ],
291 extra_fields,
222 ); 292 );
223 } 293 }
224 294
@@ -318,6 +388,7 @@ impl<'a> BosWriter<'a> {
318 0x00, 0x00, // wTotalLength 388 0x00, 0x00, // wTotalLength
319 0x00, // bNumDeviceCaps 389 0x00, // bNumDeviceCaps
320 ], 390 ],
391 &[],
321 ); 392 );
322 393
323 self.capability(capability_type::USB_2_0_EXTENSION, &[0; 4]); 394 self.capability(capability_type::USB_2_0_EXTENSION, &[0; 4]);