Expose a handle to the config descriptor writer

This commit is contained in:
Ali Somay 2023-08-15 21:36:21 +02:00
parent 7b91597e9c
commit 847e5a7a75
3 changed files with 41 additions and 43 deletions

View File

@ -295,6 +295,13 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
pub fn msos_writer(&mut self) -> &mut MsOsDescriptorWriter<'d> { pub fn msos_writer(&mut self) -> &mut MsOsDescriptorWriter<'d> {
&mut self.msos_descriptor &mut self.msos_descriptor
} }
/// Returns a handle to the inner config descriptor writer owned by the [`UsbDevice`] builder.
///
/// This can be used to overwrite parts of the descriptor buffer or other granular controls over the buffer.
pub fn config_descriptor_writer(&mut self) -> &mut DescriptorWriter<'d> {
&mut self.config_descriptor
}
} }
/// Function builder. /// Function builder.
@ -360,6 +367,13 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
#[cfg(feature = "msos-descriptor")] #[cfg(feature = "msos-descriptor")]
self.builder.msos_descriptor.function_feature(desc); self.builder.msos_descriptor.function_feature(desc);
} }
/// Returns a handle to the inner config descriptor writer owned by the [`UsbDevice`] builder.
///
/// This can be used to overwrite parts of the descriptor buffer or other granular controls over the buffer.
pub fn config_descriptor_writer(&mut self) -> &mut DescriptorWriter<'d> {
self.builder.config_descriptor_writer()
}
} }
/// Interface builder. /// Interface builder.
@ -411,6 +425,13 @@ impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> {
alt_setting_number: number, alt_setting_number: number,
} }
} }
/// Returns a handle to the inner config descriptor writer owned by the [`UsbDevice`] builder.
///
/// This can be used to overwrite parts of the descriptor buffer or other granular controls over the buffer.
pub fn config_descriptor_writer(&mut self) -> &mut DescriptorWriter<'d> {
self.builder.config_descriptor_writer()
}
} }
/// Interface alternate setting builder. /// Interface alternate setting builder.
@ -435,50 +456,17 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
/// ///
/// Descriptors are written in the order builder functions are called. Note that some /// Descriptors are written in the order builder functions are called. Note that some
/// classes care about the order. /// classes care about the order.
pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) { ///
/// Returns the byte length of the descriptor which has been written.
pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) -> usize {
self.builder.config_descriptor.write(descriptor_type, descriptor) self.builder.config_descriptor.write(descriptor_type, descriptor)
} }
/// Add a custom descriptor to this alternate setting, /// Returns a handle to the inner config descriptor writer owned by the [`UsbDevice`] builder.
/// assuming that the descriptor is the initial one which will be followed by variable number
/// of descriptors of the same type forming a compound descriptor set.
/// ///
/// Descriptors are written in the order builder functions are called. Note that some /// This can be used to overwrite parts of the descriptor buffer or other granular controls over the buffer.
/// classes care about the order. pub fn config_descriptor_writer(&mut self) -> &mut DescriptorWriter<'d> {
/// self.builder.config_descriptor_writer()
/// # Details
///
/// In the USB specification, when it comes to class-specific descriptors, the presence of a "total length" field is not universally common across all classes.
/// However, it is found in several class specifications, particularly in those where a variable number of descriptors or a variable configuration might follow.
///
/// For instance:
///
/// - **Audio Class:** The class-specific header descriptor in the Audio class contains a "Total Length" field, which indicates the entire length of the class-specific AudioControl interface descriptor. This is useful because the AudioControl interface can have a variable configuration depending on the number and type of audio channels, terminal interfaces, etc.
///
/// - **Video Class:** The Video class's class-specific header descriptor also contains a "Total Length" field.
///
/// The purpose behind the "Total Length" (or equivalent) field in these class-specific descriptors is to provide a straightforward way to determine the full length of a compound descriptor set.
/// This can be especially helpful for parsing or skipping over the entirety of the descriptor set if needed.
///
/// While it's common in certain classes like Audio and Video,
/// it's not a universal feature of all USB class-specific descriptors.
pub fn start_writing_compound_set_tracking_total_length(&mut self, descriptor_type: u8, descriptor: &[u8]) {
let descriptor_writer = &mut self.builder.config_descriptor;
// Start tracking the total length of the compound descriptor set.
descriptor_writer.start_tracking_total_length_of_compound_descriptor_set(descriptor_writer.position());
// Write the initial descriptor of that particular set.
self.builder.config_descriptor.write(descriptor_type, descriptor);
}
/// End writing a compound descriptor set updating the total length area in the initial descriptor.
///
/// The offset of the total length bytes should be provided.
/// This number may change depending on the class, please derive it from the specification.
pub fn end_writing_compound_set_updating_total_length(&mut self, offset: usize) {
// End tracking the total length of the compound descriptor set and write it to the initial descriptor of that set on provided offset.
self.builder
.config_descriptor
.end_tracking_total_length_of_compound_descriptor_set_and_update_the_initial_descriptor(offset);
} }
fn endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { fn endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn {

View File

@ -182,7 +182,6 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
// Control interface // Control interface
let mut iface = func.interface(); let mut iface = func.interface();
let comm_if = iface.interface_number(); let comm_if = iface.interface_number();
let data_if = u8::from(comm_if) + 1;
let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE, None); let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE, None);
alt.descriptor( alt.descriptor(
@ -208,19 +207,29 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
&[ &[
CDC_TYPE_UNION, // bDescriptorSubtype CDC_TYPE_UNION, // bDescriptorSubtype
comm_if.into(), // bControlInterface comm_if.into(), // bControlInterface
data_if.into(), // bSubordinateInterface // Padding, bSubordinateInterface byte will be written later.
0x0, // bSubordinateInterface
], ],
); );
// Keep the position of the subordinate interface byte so we can fill it in later
let subordinate_interface_position = alt.config_descriptor_writer().position() - 1;
let comm_ep = alt.endpoint_interrupt_in(8, 255); let comm_ep = alt.endpoint_interrupt_in(8, 255);
// Data interface // Data interface
let mut iface = func.interface(); let mut iface = func.interface();
let data_if = iface.interface_number(); let data_if = iface.interface_number();
let data_if_number_byte = data_if.0;
let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NONE, None); let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NONE, None);
let read_ep = alt.endpoint_bulk_out(max_packet_size); let read_ep = alt.endpoint_bulk_out(max_packet_size);
let write_ep = alt.endpoint_bulk_in(max_packet_size); let write_ep = alt.endpoint_bulk_in(max_packet_size);
// Fill in the subordinate interface byte with the right interface number.
alt.config_descriptor_writer()
.overwrite(subordinate_interface_position, &[data_if_number_byte]);
drop(func); drop(func);
let control = state.control.write(Control { let control = state.control.write(Control {

View File

@ -37,7 +37,8 @@ pub mod capability_type {
} }
/// A writer for USB descriptors. /// A writer for USB descriptors.
pub(crate) struct DescriptorWriter<'a> { pub struct DescriptorWriter<'a> {
/// The inner buffer of the descriptor writer.
pub buf: &'a mut [u8], pub buf: &'a mut [u8],
position: usize, position: usize,
num_interfaces_mark: Option<usize>, num_interfaces_mark: Option<usize>,