usb: add support for custom string descriptors.
This commit is contained in:
parent
7c6a88f3dd
commit
0476f6b55b
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user