Expose a handle to the config descriptor writer
This commit is contained in:
parent
7b91597e9c
commit
847e5a7a75
@ -295,6 +295,13 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
|
||||
pub fn msos_writer(&mut self) -> &mut MsOsDescriptorWriter<'d> {
|
||||
&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.
|
||||
@ -360,6 +367,13 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
|
||||
#[cfg(feature = "msos-descriptor")]
|
||||
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.
|
||||
@ -411,6 +425,13 @@ impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> {
|
||||
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.
|
||||
@ -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
|
||||
/// 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)
|
||||
}
|
||||
|
||||
/// Add a custom descriptor to this alternate setting,
|
||||
/// 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.
|
||||
/// Returns a handle to the inner config descriptor writer owned by the [`UsbDevice`] builder.
|
||||
///
|
||||
/// Descriptors are written in the order builder functions are called. Note that some
|
||||
/// classes care about the order.
|
||||
///
|
||||
/// # 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);
|
||||
/// 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()
|
||||
}
|
||||
|
||||
fn endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn {
|
||||
|
@ -182,7 +182,6 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
|
||||
// Control interface
|
||||
let mut iface = func.interface();
|
||||
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);
|
||||
|
||||
alt.descriptor(
|
||||
@ -208,19 +207,29 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
|
||||
&[
|
||||
CDC_TYPE_UNION, // bDescriptorSubtype
|
||||
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);
|
||||
|
||||
// Data interface
|
||||
let mut iface = func.interface();
|
||||
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 read_ep = alt.endpoint_bulk_out(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);
|
||||
|
||||
let control = state.control.write(Control {
|
||||
|
@ -37,7 +37,8 @@ pub mod capability_type {
|
||||
}
|
||||
|
||||
/// 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],
|
||||
position: usize,
|
||||
num_interfaces_mark: Option<usize>,
|
||||
|
Loading…
Reference in New Issue
Block a user