diff options
| -rw-r--r-- | embassy-usb/src/builder.rs | 140 | ||||
| -rw-r--r-- | embassy-usb/src/descriptor.rs | 91 |
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 @@ | |||
| 1 | use heapless::Vec; | 1 | use heapless::Vec; |
| 2 | 2 | ||
| 3 | use crate::config::MAX_HANDLER_COUNT; | 3 | use crate::config::MAX_HANDLER_COUNT; |
| 4 | use crate::descriptor::{BosWriter, DescriptorWriter}; | 4 | use crate::descriptor::{BosWriter, DescriptorWriter, SynchronizationType, UsageType}; |
| 5 | use crate::driver::{Driver, Endpoint, EndpointType}; | 5 | use crate::driver::{Driver, Endpoint, EndpointInfo, EndpointType}; |
| 6 | use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter}; | 6 | use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter}; |
| 7 | use crate::types::{InterfaceNumber, StringIndex}; | 7 | use crate::types::{InterfaceNumber, StringIndex}; |
| 8 | use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; | 8 | use 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 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]); |
