summaryrefslogtreecommitdiff
path: root/embassy-usb
diff options
context:
space:
mode:
authorDario Nieuwenhuis <dirbaio@dirbaio.net>2022-04-23 04:40:57 +0200
committerDario Nieuwenhuis <dirbaio@dirbaio.net>2022-04-23 04:40:57 +0200
commit0476f6b55beb38ec504449d38d634c98bf0f21e3 (patch)
tree9b336dc62427762e3952a695c21834ca292735e5 /embassy-usb
parent7c6a88f3dd59b0780a9f1ac7b5c3993ddfe0a265 (diff)
downloadembassy-0476f6b55beb38ec504449d38d634c98bf0f21e3.zip
usb: add support for custom string descriptors.
Diffstat (limited to 'embassy-usb')
-rw-r--r--embassy-usb/src/builder.rs22
-rw-r--r--embassy-usb/src/control.rs14
-rw-r--r--embassy-usb/src/lib.rs40
3 files changed, 59 insertions, 17 deletions
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index 07b6c79d..8cf9c82a 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -1,6 +1,6 @@
use heapless::Vec;
-use crate::Interface;
+use crate::{Interface, STRING_INDEX_CUSTOM_START};
use super::control::ControlHandler;
use super::descriptor::{BosWriter, DescriptorWriter};
@@ -181,7 +181,7 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
config,
interfaces: Vec::new(),
control_buf,
- next_string_index: 4,
+ next_string_index: STRING_INDEX_CUSTOM_START,
device_descriptor,
config_descriptor,
@@ -212,14 +212,6 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
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.
///
/// 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,
current_alt_setting: 0,
num_alt_settings: 0,
+ num_strings: 0,
};
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);
}
+ /// 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.
///
/// Alternate setting numbers are guaranteed to be allocated consecutively, starting from 0.
diff --git a/embassy-usb/src/control.rs b/embassy-usb/src/control.rs
index 0b59451d..ff42f9d7 100644
--- a/embassy-usb/src/control.rs
+++ b/embassy-usb/src/control.rs
@@ -189,6 +189,20 @@ pub trait ControlHandler {
let _ = (req, buf);
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
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index acb26c60..3bfedc04 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -66,6 +66,11 @@ pub const CONFIGURATION_VALUE: u8 = 1;
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].
pub trait DeviceStateHandler {
/// Called when the USB device has been enabled or disabled.
@@ -91,6 +96,7 @@ struct Interface<'d> {
handler: Option<&'d mut dyn ControlHandler>,
current_alt_setting: u8,
num_alt_settings: u8,
+ num_strings: u8,
}
pub struct UsbDevice<'d, D: Driver<'d>> {
@@ -540,14 +546,34 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
.await
} else {
let s = match index {
- 1 => self.config.manufacturer,
- 2 => self.config.product,
- 3 => self.config.serial_number,
+ STRING_INDEX_MANUFACTURER => self.config.manufacturer,
+ STRING_INDEX_PRODUCT => self.config.product,
+ STRING_INDEX_SERIAL_NUMBER => self.config.serial_number,
_ => {
- let _index = StringIndex::new(index);
- let _lang_id = req.index;
- // TODO
- None
+ // Find out which iface owns this string index.
+ let mut index_left = index - STRING_INDEX_CUSTOM_START;
+ 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
+ }
+ } else {
+ warn!("String requested but didn't match to an interface.");
+ None
+ }
}
};