usb: add support for custom string descriptors.

This commit is contained in:
Dario Nieuwenhuis 2022-04-23 04:40:57 +02:00
parent 7c6a88f3dd
commit 0476f6b55b
3 changed files with 59 additions and 17 deletions

View File

@ -1,6 +1,6 @@
use heapless::Vec; use heapless::Vec;
use crate::Interface; use crate::{Interface, STRING_INDEX_CUSTOM_START};
use super::control::ControlHandler; use super::control::ControlHandler;
use super::descriptor::{BosWriter, DescriptorWriter}; use super::descriptor::{BosWriter, DescriptorWriter};
@ -181,7 +181,7 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
config, config,
interfaces: Vec::new(), interfaces: Vec::new(),
control_buf, control_buf,
next_string_index: 4, next_string_index: STRING_INDEX_CUSTOM_START,
device_descriptor, device_descriptor,
config_descriptor, config_descriptor,
@ -212,14 +212,6 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
self.control_buf.len() self.control_buf.len()
} }
/// Allocates a new string index.
pub fn alloc_string(&mut self) -> StringIndex {
let index = self.next_string_index;
self.next_string_index += 1;
StringIndex::new(index)
}
/// Add an USB function. /// Add an USB function.
/// ///
/// If [`Config::composite_with_iads`] is set, this will add an IAD descriptor /// If [`Config::composite_with_iads`] is set, this will add an IAD descriptor
@ -277,6 +269,7 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
handler: None, handler: None,
current_alt_setting: 0, current_alt_setting: 0,
num_alt_settings: 0, num_alt_settings: 0,
num_strings: 0,
}; };
if self.builder.interfaces.push(iface).is_err() { if self.builder.interfaces.push(iface).is_err() {
@ -308,6 +301,15 @@ impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> {
self.builder.interfaces[self.interface_number.0 as usize].handler = Some(handler); self.builder.interfaces[self.interface_number.0 as usize].handler = Some(handler);
} }
/// Allocates a new string index.
pub fn string(&mut self) -> StringIndex {
let index = self.builder.next_string_index;
self.builder.next_string_index += 1;
self.builder.interfaces[self.interface_number.0 as usize].num_strings += 1;
StringIndex::new(index)
}
/// Add an alternate setting to the interface and write its descriptor. /// Add an alternate setting to the interface and write its descriptor.
/// ///
/// Alternate setting numbers are guaranteed to be allocated consecutively, starting from 0. /// Alternate setting numbers are guaranteed to be allocated consecutively, starting from 0.

View File

@ -189,6 +189,20 @@ pub trait ControlHandler {
let _ = (req, buf); let _ = (req, buf);
InResponse::Rejected InResponse::Rejected
} }
/// Called when a GET_DESCRIPTOR STRING control request is received.
///
/// Write the response string somewhere (usually to `buf`, but you may use another buffer
/// owned by yourself, or a static buffer), then return it.
fn get_string<'a>(
&'a mut self,
index: StringIndex,
lang_id: u16,
buf: &'a mut [u8],
) -> Option<&'a str> {
let _ = (index, lang_id, buf);
None
}
} }
/// Typestate representing a ControlPipe in the DATA IN stage /// Typestate representing a ControlPipe in the DATA IN stage

View File

@ -66,6 +66,11 @@ pub const CONFIGURATION_VALUE: u8 = 1;
pub const MAX_INTERFACE_COUNT: usize = 4; pub const MAX_INTERFACE_COUNT: usize = 4;
const STRING_INDEX_MANUFACTURER: u8 = 1;
const STRING_INDEX_PRODUCT: u8 = 2;
const STRING_INDEX_SERIAL_NUMBER: u8 = 3;
const STRING_INDEX_CUSTOM_START: u8 = 4;
/// A handler trait for changes in the device state of the [UsbDevice]. /// A handler trait for changes in the device state of the [UsbDevice].
pub trait DeviceStateHandler { pub trait DeviceStateHandler {
/// Called when the USB device has been enabled or disabled. /// Called when the USB device has been enabled or disabled.
@ -91,6 +96,7 @@ struct Interface<'d> {
handler: Option<&'d mut dyn ControlHandler>, handler: Option<&'d mut dyn ControlHandler>,
current_alt_setting: u8, current_alt_setting: u8,
num_alt_settings: u8, num_alt_settings: u8,
num_strings: u8,
} }
pub struct UsbDevice<'d, D: Driver<'d>> { pub struct UsbDevice<'d, D: Driver<'d>> {
@ -540,15 +546,35 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
.await .await
} else { } else {
let s = match index { let s = match index {
1 => self.config.manufacturer, STRING_INDEX_MANUFACTURER => self.config.manufacturer,
2 => self.config.product, STRING_INDEX_PRODUCT => self.config.product,
3 => self.config.serial_number, STRING_INDEX_SERIAL_NUMBER => self.config.serial_number,
_ => { _ => {
let _index = StringIndex::new(index); // Find out which iface owns this string index.
let _lang_id = req.index; let mut index_left = index - STRING_INDEX_CUSTOM_START;
// TODO let mut the_iface = None;
for iface in &mut self.interfaces {
if index_left < iface.num_strings {
the_iface = Some(iface);
break;
}
index_left -= iface.num_strings;
}
if let Some(iface) = the_iface {
if let Some(handler) = &mut iface.handler {
let index = StringIndex::new(index);
let lang_id = req.index;
handler.get_string(index, lang_id, self.control_buf)
} else {
warn!("String requested to an interface with no handler.");
None None
} }
} else {
warn!("String requested but didn't match to an interface.");
None
}
}
}; };
if let Some(s) = s { if let Some(s) = s {