diff options
| author | elagil <[email protected]> | 2024-09-05 21:29:24 +0200 |
|---|---|---|
| committer | elagil <[email protected]> | 2024-09-05 21:29:24 +0200 |
| commit | a8ca6713e6e9b7ad5dd53f9b46bcf5e893adda1e (patch) | |
| tree | 6d8a1eeae8d5b30239ccb1e17be8da19821eb96d /embassy-usb/src/descriptor.rs | |
| parent | d37c482e2179c95740bb4284f4df30637551199b (diff) | |
feat(usb): make use of ISO endpoint support
Diffstat (limited to 'embassy-usb/src/descriptor.rs')
| -rw-r--r-- | embassy-usb/src/descriptor.rs | 91 |
1 files changed, 81 insertions, 10 deletions
diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index f1773fa8a..0f2931c38 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. |
| 2 | use embassy_usb_driver::EndpointType; | ||
| 2 | 3 | ||
| 3 | use crate::builder::Config; | 4 | use crate::builder::Config; |
| 4 | use crate::driver::EndpointInfo; | 5 | use 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))] | ||
| 48 | pub 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))] | ||
| 65 | pub 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. |
| 42 | pub(crate) struct DescriptorWriter<'a> { | 77 | pub(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 | ||
| @@ -315,6 +385,7 @@ impl<'a> BosWriter<'a> { | |||
| 315 | 0x00, 0x00, // wTotalLength | 385 | 0x00, 0x00, // wTotalLength |
| 316 | 0x00, // bNumDeviceCaps | 386 | 0x00, // bNumDeviceCaps |
| 317 | ], | 387 | ], |
| 388 | &[], | ||
| 318 | ); | 389 | ); |
| 319 | 390 | ||
| 320 | self.capability(capability_type::USB_2_0_EXTENSION, &[0; 4]); | 391 | self.capability(capability_type::USB_2_0_EXTENSION, &[0; 4]); |
