Convert MS OS descriptor builder to a writer API

This brings it inline with the other embassy-usb descriptor APIs and allows it to integrate well with the Builder to allow class constructors to add MS OS descriptors.

Also adds a `usb_serial_winusb` example to demonstrate how to use the API.
This commit is contained in:
alexmoon
2023-02-02 16:13:16 -05:00
parent b9ecdb72bb
commit 9f9230ae7a
6 changed files with 461 additions and 273 deletions

View File

@ -3,6 +3,8 @@ use heapless::Vec;
use crate::control::ControlHandler;
use crate::descriptor::{BosWriter, DescriptorWriter};
use crate::driver::{Driver, Endpoint, EndpointType};
#[cfg(feature = "msos-descriptor")]
use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter};
use crate::types::*;
use crate::{DeviceStateHandler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START};
@ -130,7 +132,9 @@ pub struct Builder<'d, D: Driver<'d>> {
device_descriptor: DescriptorWriter<'d>,
config_descriptor: DescriptorWriter<'d>,
bos_descriptor: BosWriter<'d>,
msos_descriptor: Option<crate::msos::MsOsDescriptorSet<'d>>,
#[cfg(feature = "msos-descriptor")]
msos_descriptor: MsOsDescriptorWriter<'d>,
}
impl<'d, D: Driver<'d>> Builder<'d, D> {
@ -145,6 +149,7 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
device_descriptor_buf: &'d mut [u8],
config_descriptor_buf: &'d mut [u8],
bos_descriptor_buf: &'d mut [u8],
#[cfg(feature = "msos-descriptor")] msos_descriptor_buf: &'d mut [u8],
control_buf: &'d mut [u8],
handler: Option<&'d dyn DeviceStateHandler>,
) -> Self {
@ -183,12 +188,17 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
device_descriptor,
config_descriptor,
bos_descriptor,
msos_descriptor: None,
#[cfg(feature = "msos-descriptor")]
msos_descriptor: MsOsDescriptorWriter::new(msos_descriptor_buf),
}
}
/// Creates the [`UsbDevice`] instance with the configuration in this builder.
pub fn build(mut self) -> UsbDevice<'d, D> {
#[cfg(feature = "msos-descriptor")]
let msos_descriptor = self.msos_descriptor.build(&mut self.bos_descriptor);
self.config_descriptor.end_configuration();
self.bos_descriptor.end_bos();
@ -201,7 +211,8 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
self.bos_descriptor.writer.into_buf(),
self.interfaces,
self.control_buf,
self.msos_descriptor,
#[cfg(feature = "msos-descriptor")]
msos_descriptor,
)
}
@ -218,14 +229,10 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
///
/// If it's not set, no IAD descriptor is added.
pub fn function(&mut self, class: u8, subclass: u8, protocol: u8) -> FunctionBuilder<'_, 'd, D> {
let first_interface = InterfaceNumber::new(self.interfaces.len() as u8);
let iface_count_index = if self.config.composite_with_iads {
self.config_descriptor.iad(
InterfaceNumber::new(self.interfaces.len() as _),
0,
class,
subclass,
protocol,
);
self.config_descriptor
.iad(first_interface, 0, class, subclass, protocol);
Some(self.config_descriptor.position() - 5)
} else {
@ -235,19 +242,31 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
FunctionBuilder {
builder: self,
iface_count_index,
#[cfg(feature = "msos-descriptor")]
first_interface,
}
}
#[cfg(feature = "msos-descriptor")]
/// Add an MS OS 2.0 Descriptor Set.
///
/// Panics if called more than once.
pub fn msos_descriptor(&mut self, msos_descriptor: crate::msos::MsOsDescriptorSet<'d>) {
if self.msos_descriptor.is_some() {
panic!("msos_descriptor already set");
}
self.msos_descriptor
.insert(msos_descriptor)
.write_bos_capability(&mut self.bos_descriptor);
pub fn msos_descriptor(&mut self, windows_version: u32, vendor_code: u8) {
self.msos_descriptor.header(windows_version, vendor_code);
}
#[cfg(feature = "msos-descriptor")]
/// Add an MS OS 2.0 Device Level Feature Descriptor.
pub fn msos_feature<T: DeviceLevelDescriptor>(&mut self, desc: T) {
self.msos_descriptor.device_feature(desc);
}
#[cfg(feature = "msos-descriptor")]
/// Gets the underlying [`MsOsDescriptorWriter`] to allow adding subsets and features for classes that
/// do not add their own.
pub fn msos_writer(&mut self) -> &mut MsOsDescriptorWriter<'d> {
&mut self.msos_descriptor
}
}
@ -259,6 +278,16 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
pub struct FunctionBuilder<'a, 'd, D: Driver<'d>> {
builder: &'a mut Builder<'d, D>,
iface_count_index: Option<usize>,
#[cfg(feature = "msos-descriptor")]
first_interface: InterfaceNumber,
}
impl<'a, 'd, D: Driver<'d>> Drop for FunctionBuilder<'a, 'd, D> {
fn drop(&mut self) {
#[cfg(feature = "msos-descriptor")]
self.builder.msos_descriptor.end_function();
}
}
impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
@ -288,6 +317,21 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
next_alt_setting_number: 0,
}
}
#[cfg(feature = "msos-descriptor")]
/// Add an MS OS 2.0 Function Level Feature Descriptor.
pub fn msos_feature<T: FunctionLevelDescriptor>(&mut self, desc: T) {
if !self.builder.msos_descriptor.is_in_config_subset() {
self.builder.msos_descriptor.configuration(0);
}
if !self.builder.msos_descriptor.is_in_function_subset() {
self.builder.msos_descriptor.function(self.first_interface.0);
}
#[cfg(feature = "msos-descriptor")]
self.builder.msos_descriptor.function_feature(desc);
}
}
/// Interface builder.