Skip to content

Commit 0476f6b

Browse files
committed
usb: add support for custom string descriptors.
1 parent 7c6a88f commit 0476f6b

File tree

3 files changed

+59
-17
lines changed

3 files changed

+59
-17
lines changed

embassy-usb/src/builder.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use heapless::Vec;
22

3-
use crate::Interface;
3+
use crate::{Interface, STRING_INDEX_CUSTOM_START};
44

55
use super::control::ControlHandler;
66
use super::descriptor::{BosWriter, DescriptorWriter};
@@ -181,7 +181,7 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
181181
config,
182182
interfaces: Vec::new(),
183183
control_buf,
184-
next_string_index: 4,
184+
next_string_index: STRING_INDEX_CUSTOM_START,
185185

186186
device_descriptor,
187187
config_descriptor,
@@ -212,14 +212,6 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
212212
self.control_buf.len()
213213
}
214214

215-
/// Allocates a new string index.
216-
pub fn alloc_string(&mut self) -> StringIndex {
217-
let index = self.next_string_index;
218-
self.next_string_index += 1;
219-
220-
StringIndex::new(index)
221-
}
222-
223215
/// Add an USB function.
224216
///
225217
/// 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> {
277269
handler: None,
278270
current_alt_setting: 0,
279271
num_alt_settings: 0,
272+
num_strings: 0,
280273
};
281274

282275
if self.builder.interfaces.push(iface).is_err() {
@@ -308,6 +301,15 @@ impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> {
308301
self.builder.interfaces[self.interface_number.0 as usize].handler = Some(handler);
309302
}
310303

304+
/// Allocates a new string index.
305+
pub fn string(&mut self) -> StringIndex {
306+
let index = self.builder.next_string_index;
307+
self.builder.next_string_index += 1;
308+
self.builder.interfaces[self.interface_number.0 as usize].num_strings += 1;
309+
310+
StringIndex::new(index)
311+
}
312+
311313
/// Add an alternate setting to the interface and write its descriptor.
312314
///
313315
/// Alternate setting numbers are guaranteed to be allocated consecutively, starting from 0.

embassy-usb/src/control.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,20 @@ pub trait ControlHandler {
189189
let _ = (req, buf);
190190
InResponse::Rejected
191191
}
192+
193+
/// Called when a GET_DESCRIPTOR STRING control request is received.
194+
///
195+
/// Write the response string somewhere (usually to `buf`, but you may use another buffer
196+
/// owned by yourself, or a static buffer), then return it.
197+
fn get_string<'a>(
198+
&'a mut self,
199+
index: StringIndex,
200+
lang_id: u16,
201+
buf: &'a mut [u8],
202+
) -> Option<&'a str> {
203+
let _ = (index, lang_id, buf);
204+
None
205+
}
192206
}
193207

194208
/// Typestate representing a ControlPipe in the DATA IN stage

embassy-usb/src/lib.rs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ pub const CONFIGURATION_VALUE: u8 = 1;
6666

6767
pub const MAX_INTERFACE_COUNT: usize = 4;
6868

69+
const STRING_INDEX_MANUFACTURER: u8 = 1;
70+
const STRING_INDEX_PRODUCT: u8 = 2;
71+
const STRING_INDEX_SERIAL_NUMBER: u8 = 3;
72+
const STRING_INDEX_CUSTOM_START: u8 = 4;
73+
6974
/// A handler trait for changes in the device state of the [UsbDevice].
7075
pub trait DeviceStateHandler {
7176
/// Called when the USB device has been enabled or disabled.
@@ -91,6 +96,7 @@ struct Interface<'d> {
9196
handler: Option<&'d mut dyn ControlHandler>,
9297
current_alt_setting: u8,
9398
num_alt_settings: u8,
99+
num_strings: u8,
94100
}
95101

96102
pub struct UsbDevice<'d, D: Driver<'d>> {
@@ -540,14 +546,34 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
540546
.await
541547
} else {
542548
let s = match index {
543-
1 => self.config.manufacturer,
544-
2 => self.config.product,
545-
3 => self.config.serial_number,
549+
STRING_INDEX_MANUFACTURER => self.config.manufacturer,
550+
STRING_INDEX_PRODUCT => self.config.product,
551+
STRING_INDEX_SERIAL_NUMBER => self.config.serial_number,
546552
_ => {
547-
let _index = StringIndex::new(index);
548-
let _lang_id = req.index;
549-
// TODO
550-
None
553+
// Find out which iface owns this string index.
554+
let mut index_left = index - STRING_INDEX_CUSTOM_START;
555+
let mut the_iface = None;
556+
for iface in &mut self.interfaces {
557+
if index_left < iface.num_strings {
558+
the_iface = Some(iface);
559+
break;
560+
}
561+
index_left -= iface.num_strings;
562+
}
563+
564+
if let Some(iface) = the_iface {
565+
if let Some(handler) = &mut iface.handler {
566+
let index = StringIndex::new(index);
567+
let lang_id = req.index;
568+
handler.get_string(index, lang_id, self.control_buf)
569+
} else {
570+
warn!("String requested to an interface with no handler.");
571+
None
572+
}
573+
} else {
574+
warn!("String requested but didn't match to an interface.");
575+
None
576+
}
551577
}
552578
};
553579

0 commit comments

Comments
 (0)