aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb/src/descriptor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-usb/src/descriptor.rs')
-rw-r--r--embassy-usb/src/descriptor.rs91
1 files changed, 81 insertions, 10 deletions
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]);