usb: unify ControlHandler+DeviceStateHandler, route all control requests to all handlers.

- Allows classes to handle vendor requests.
- Allows classes to use a single handler for multiple interfaces.
- Allows classes to access the other events (previously only `reset` was available).
This commit is contained in:
Dario Nieuwenhuis 2023-02-07 22:49:14 +01:00
parent 1d841cc8ac
commit 3af991ab63
31 changed files with 381 additions and 338 deletions

View File

@ -74,7 +74,6 @@ impl<const N: usize> UsbLogger<N> {
&mut state.config_descriptor, &mut state.config_descriptor,
&mut state.bos_descriptor, &mut state.bos_descriptor,
&mut state.control_buf, &mut state.control_buf,
None,
); );
// Create classes on the builder. // Create classes on the builder.

View File

@ -27,6 +27,15 @@ max-interface-count-6 = []
max-interface-count-7 = [] max-interface-count-7 = []
max-interface-count-8 = [] max-interface-count-8 = []
max-handler-count-1 = []
max-handler-count-2 = []
max-handler-count-3 = []
max-handler-count-4 = [] # Default
max-handler-count-5 = []
max-handler-count-6 = []
max-handler-count-7 = []
max-handler-count-8 = []
# END AUTOGENERATED CONFIG FEATURES # END AUTOGENERATED CONFIG FEATURES
[dependencies] [dependencies]

View File

@ -7,6 +7,7 @@ static CONFIGS: &[(&str, usize)] = &[
// BEGIN AUTOGENERATED CONFIG FEATURES // BEGIN AUTOGENERATED CONFIG FEATURES
// Generated by gen_config.py. DO NOT EDIT. // Generated by gen_config.py. DO NOT EDIT.
("MAX_INTERFACE_COUNT", 4), ("MAX_INTERFACE_COUNT", 4),
("MAX_HANDLER_COUNT", 4),
// END AUTOGENERATED CONFIG FEATURES // END AUTOGENERATED CONFIG FEATURES
]; ];

View File

@ -28,6 +28,7 @@ def feature(name, default, min, max, pow2=None):
feature("max_interface_count", default=4, min=1, max=8) feature("max_interface_count", default=4, min=1, max=8)
feature("max_handler_count", default=4, min=1, max=8)
# ========= Update Cargo.toml # ========= Update Cargo.toml

View File

@ -1,12 +1,12 @@
use heapless::Vec; use heapless::Vec;
use crate::control::ControlHandler; use crate::config::*;
use crate::descriptor::{BosWriter, DescriptorWriter}; use crate::descriptor::{BosWriter, DescriptorWriter};
use crate::driver::{Driver, Endpoint, EndpointType}; use crate::driver::{Driver, Endpoint, EndpointType};
#[cfg(feature = "msos-descriptor")] #[cfg(feature = "msos-descriptor")]
use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter}; use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter};
use crate::types::*; use crate::types::*;
use crate::{DeviceStateHandler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START};
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -122,8 +122,8 @@ impl<'a> Config<'a> {
/// [`UsbDevice`] builder. /// [`UsbDevice`] builder.
pub struct Builder<'d, D: Driver<'d>> { pub struct Builder<'d, D: Driver<'d>> {
config: Config<'d>, config: Config<'d>,
handler: Option<&'d dyn DeviceStateHandler>, handlers: Vec<&'d mut dyn Handler, MAX_HANDLER_COUNT>,
interfaces: Vec<Interface<'d>, MAX_INTERFACE_COUNT>, interfaces: Vec<Interface, MAX_INTERFACE_COUNT>,
control_buf: &'d mut [u8], control_buf: &'d mut [u8],
driver: D, driver: D,
@ -151,7 +151,6 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
bos_descriptor_buf: &'d mut [u8], bos_descriptor_buf: &'d mut [u8],
#[cfg(feature = "msos-descriptor")] msos_descriptor_buf: &'d mut [u8], #[cfg(feature = "msos-descriptor")] msos_descriptor_buf: &'d mut [u8],
control_buf: &'d mut [u8], control_buf: &'d mut [u8],
handler: Option<&'d dyn DeviceStateHandler>,
) -> Self { ) -> Self {
// Magic values specified in USB-IF ECN on IADs. // Magic values specified in USB-IF ECN on IADs.
if config.composite_with_iads if config.composite_with_iads
@ -179,9 +178,9 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
Builder { Builder {
driver, driver,
handler,
config, config,
interfaces: Vec::new(), interfaces: Vec::new(),
handlers: Vec::new(),
control_buf, control_buf,
next_string_index: STRING_INDEX_CUSTOM_START, next_string_index: STRING_INDEX_CUSTOM_START,
@ -205,7 +204,7 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
UsbDevice::build( UsbDevice::build(
self.driver, self.driver,
self.config, self.config,
self.handler, self.handlers,
self.device_descriptor.into_buf(), self.device_descriptor.into_buf(),
self.config_descriptor.into_buf(), self.config_descriptor.into_buf(),
self.bos_descriptor.writer.into_buf(), self.bos_descriptor.writer.into_buf(),
@ -248,6 +247,26 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
} }
} }
/// Add a Handler.
///
/// The Handler is called on some USB bus events, and to handle all control requests not already
/// handled by the USB stack.
pub fn handler(&mut self, handler: &'d mut dyn Handler) {
if self.handlers.push(handler).is_err() {
panic!(
"embassy-usb: handler list full. Increase the `max_handler_count` compile-time setting. Current value: {}",
MAX_HANDLER_COUNT
)
}
}
/// Allocates a new string index.
pub fn string(&mut self) -> StringIndex {
let index = self.next_string_index;
self.next_string_index += 1;
StringIndex::new(index)
}
#[cfg(feature = "msos-descriptor")] #[cfg(feature = "msos-descriptor")]
/// Add an MS OS 2.0 Descriptor Set. /// Add an MS OS 2.0 Descriptor Set.
/// ///
@ -301,10 +320,8 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
let number = self.builder.interfaces.len() as _; let number = self.builder.interfaces.len() as _;
let iface = Interface { let iface = Interface {
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() {
@ -350,17 +367,9 @@ impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> {
self.interface_number self.interface_number
} }
pub fn handler(&mut self, handler: &'d mut dyn ControlHandler) {
self.builder.interfaces[self.interface_number.0 as usize].handler = Some(handler);
}
/// Allocates a new string index. /// Allocates a new string index.
pub fn string(&mut self) -> StringIndex { pub fn string(&mut self) -> StringIndex {
let index = self.builder.next_string_index; self.builder.string()
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.

View File

@ -6,10 +6,10 @@ use core::sync::atomic::{AtomicBool, Ordering};
use embassy_sync::blocking_mutex::CriticalSectionMutex; use embassy_sync::blocking_mutex::CriticalSectionMutex;
use crate::control::{self, ControlHandler, InResponse, OutResponse, Request}; use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType};
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
use crate::types::*; use crate::types::*;
use crate::Builder; use crate::{Builder, Handler};
/// This should be used as `device_class` when building the `UsbDevice`. /// This should be used as `device_class` when building the `UsbDevice`.
pub const USB_CLASS_CDC: u8 = 0x02; pub const USB_CLASS_CDC: u8 = 0x02;
@ -67,6 +67,7 @@ pub struct CdcAcmClass<'d, D: Driver<'d>> {
} }
struct Control<'a> { struct Control<'a> {
comm_if: InterfaceNumber,
shared: &'a ControlShared, shared: &'a ControlShared,
} }
@ -98,7 +99,7 @@ impl<'a> Control<'a> {
} }
} }
impl<'d> ControlHandler for Control<'d> { impl<'d> Handler for Control<'d> {
fn reset(&mut self) { fn reset(&mut self) {
let shared = self.shared(); let shared = self.shared();
shared.line_coding.lock(|x| x.set(LineCoding::default())); shared.line_coding.lock(|x| x.set(LineCoding::default()));
@ -106,12 +107,18 @@ impl<'d> ControlHandler for Control<'d> {
shared.rts.store(false, Ordering::Relaxed); shared.rts.store(false, Ordering::Relaxed);
} }
fn control_out(&mut self, req: control::Request, data: &[u8]) -> OutResponse { fn control_out(&mut self, req: control::Request, data: &[u8]) -> Option<OutResponse> {
if (req.request_type, req.recipient, req.index)
!= (RequestType::Class, Recipient::Interface, self.comm_if.0 as u16)
{
return None;
}
match req.request { match req.request {
REQ_SEND_ENCAPSULATED_COMMAND => { REQ_SEND_ENCAPSULATED_COMMAND => {
// We don't actually support encapsulated commands but pretend we do for standards // We don't actually support encapsulated commands but pretend we do for standards
// compatibility. // compatibility.
OutResponse::Accepted Some(OutResponse::Accepted)
} }
REQ_SET_LINE_CODING if data.len() >= 7 => { REQ_SET_LINE_CODING if data.len() >= 7 => {
let coding = LineCoding { let coding = LineCoding {
@ -123,7 +130,7 @@ impl<'d> ControlHandler for Control<'d> {
self.shared().line_coding.lock(|x| x.set(coding)); self.shared().line_coding.lock(|x| x.set(coding));
debug!("Set line coding to: {:?}", coding); debug!("Set line coding to: {:?}", coding);
OutResponse::Accepted Some(OutResponse::Accepted)
} }
REQ_SET_CONTROL_LINE_STATE => { REQ_SET_CONTROL_LINE_STATE => {
let dtr = (req.value & 0x0001) != 0; let dtr = (req.value & 0x0001) != 0;
@ -134,13 +141,19 @@ impl<'d> ControlHandler for Control<'d> {
shared.rts.store(rts, Ordering::Relaxed); shared.rts.store(rts, Ordering::Relaxed);
debug!("Set dtr {}, rts {}", dtr, rts); debug!("Set dtr {}, rts {}", dtr, rts);
OutResponse::Accepted Some(OutResponse::Accepted)
} }
_ => OutResponse::Rejected, _ => Some(OutResponse::Rejected),
} }
} }
fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> { fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option<InResponse<'a>> {
if (req.request_type, req.recipient, req.index)
!= (RequestType::Class, Recipient::Interface, self.comm_if.0 as u16)
{
return None;
}
match req.request { match req.request {
// REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below. // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below.
REQ_GET_LINE_CODING if req.length == 7 => { REQ_GET_LINE_CODING if req.length == 7 => {
@ -151,9 +164,9 @@ impl<'d> ControlHandler for Control<'d> {
buf[4] = coding.stop_bits as u8; buf[4] = coding.stop_bits as u8;
buf[5] = coding.parity_type as u8; buf[5] = coding.parity_type as u8;
buf[6] = coding.data_bits; buf[6] = coding.data_bits;
InResponse::Accepted(&buf[0..7]) Some(InResponse::Accepted(&buf[0..7]))
} }
_ => InResponse::Rejected, _ => Some(InResponse::Rejected),
} }
} }
} }
@ -162,17 +175,12 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
/// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For
/// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64. /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64.
pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, max_packet_size: u16) -> Self { pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, max_packet_size: u16) -> Self {
let control = state.control.write(Control { shared: &state.shared });
let control_shared = &state.shared;
assert!(builder.control_buf_len() >= 7); assert!(builder.control_buf_len() >= 7);
let mut func = builder.function(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE); let mut func = builder.function(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE);
// Control interface // Control interface
let mut iface = func.interface(); let mut iface = func.interface();
iface.handler(control);
let comm_if = iface.interface_number(); let comm_if = iface.interface_number();
let data_if = u8::from(comm_if) + 1; let data_if = u8::from(comm_if) + 1;
let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE, None); let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE, None);
@ -213,6 +221,16 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
let read_ep = alt.endpoint_bulk_out(max_packet_size); let read_ep = alt.endpoint_bulk_out(max_packet_size);
let write_ep = alt.endpoint_bulk_in(max_packet_size); let write_ep = alt.endpoint_bulk_in(max_packet_size);
drop(func);
let control = state.control.write(Control {
shared: &state.shared,
comm_if,
});
builder.handler(control);
let control_shared = &state.shared;
CdcAcmClass { CdcAcmClass {
_comm_ep: comm_ep, _comm_ep: comm_ep,
_data_if: data_if, _data_if: data_if,

View File

@ -17,10 +17,10 @@
use core::intrinsics::copy_nonoverlapping; use core::intrinsics::copy_nonoverlapping;
use core::mem::{size_of, MaybeUninit}; use core::mem::{size_of, MaybeUninit};
use crate::control::{self, ControlHandler, InResponse, OutResponse, Request}; use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType};
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
use crate::types::*; use crate::types::*;
use crate::Builder; use crate::{Builder, Handler};
pub mod embassy_net; pub mod embassy_net;
@ -117,8 +117,7 @@ fn byteify<T>(buf: &mut [u8], data: T) -> &[u8] {
/// Internal state for the CDC-NCM class. /// Internal state for the CDC-NCM class.
pub struct State<'a> { pub struct State<'a> {
comm_control: MaybeUninit<CommControl<'a>>, control: MaybeUninit<Control<'a>>,
data_control: MaybeUninit<DataControl>,
shared: ControlShared, shared: ControlShared,
} }
@ -126,8 +125,7 @@ impl<'a> State<'a> {
/// Create a new `State`. /// Create a new `State`.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
comm_control: MaybeUninit::uninit(), control: MaybeUninit::uninit(),
data_control: MaybeUninit::uninit(),
shared: Default::default(), shared: Default::default(),
} }
} }
@ -144,29 +142,55 @@ impl Default for ControlShared {
} }
} }
struct CommControl<'a> { struct Control<'a> {
mac_addr_string: StringIndex, mac_addr_string: StringIndex,
shared: &'a ControlShared, shared: &'a ControlShared,
mac_addr_str: [u8; 12], mac_addr_str: [u8; 12],
comm_if: InterfaceNumber,
data_if: InterfaceNumber,
} }
impl<'d> ControlHandler for CommControl<'d> { impl<'d> Handler for Control<'d> {
fn control_out(&mut self, req: control::Request, _data: &[u8]) -> OutResponse { fn set_alternate_setting(&mut self, iface: InterfaceNumber, alternate_setting: u8) {
if iface != self.data_if {
return;
}
match alternate_setting {
ALTERNATE_SETTING_ENABLED => info!("ncm: interface enabled"),
ALTERNATE_SETTING_DISABLED => info!("ncm: interface disabled"),
_ => unreachable!(),
}
}
fn control_out(&mut self, req: control::Request, _data: &[u8]) -> Option<OutResponse> {
if (req.request_type, req.recipient, req.index)
!= (RequestType::Class, Recipient::Interface, self.comm_if.0 as u16)
{
return None;
}
match req.request { match req.request {
REQ_SEND_ENCAPSULATED_COMMAND => { REQ_SEND_ENCAPSULATED_COMMAND => {
// We don't actually support encapsulated commands but pretend we do for standards // We don't actually support encapsulated commands but pretend we do for standards
// compatibility. // compatibility.
OutResponse::Accepted Some(OutResponse::Accepted)
} }
REQ_SET_NTB_INPUT_SIZE => { REQ_SET_NTB_INPUT_SIZE => {
// TODO // TODO
OutResponse::Accepted Some(OutResponse::Accepted)
} }
_ => OutResponse::Rejected, _ => Some(OutResponse::Rejected),
} }
} }
fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> { fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option<InResponse<'a>> {
if (req.request_type, req.recipient, req.index)
!= (RequestType::Class, Recipient::Interface, self.comm_if.0 as u16)
{
return None;
}
match req.request { match req.request {
REQ_GET_NTB_PARAMETERS => { REQ_GET_NTB_PARAMETERS => {
let res = NtbParameters { let res = NtbParameters {
@ -187,9 +211,9 @@ impl<'d> ControlHandler for CommControl<'d> {
max_datagram_count: 1, // We only decode 1 packet per NTB max_datagram_count: 1, // We only decode 1 packet per NTB
}, },
}; };
InResponse::Accepted(byteify(buf, res)) Some(InResponse::Accepted(byteify(buf, res)))
} }
_ => InResponse::Rejected, _ => Some(InResponse::Rejected),
} }
} }
@ -214,18 +238,6 @@ impl<'d> ControlHandler for CommControl<'d> {
} }
} }
struct DataControl {}
impl ControlHandler for DataControl {
fn set_alternate_setting(&mut self, alternate_setting: u8) {
match alternate_setting {
ALTERNATE_SETTING_ENABLED => info!("ncm: interface enabled"),
ALTERNATE_SETTING_DISABLED => info!("ncm: interface disabled"),
_ => unreachable!(),
}
}
}
/// CDC-NCM class /// CDC-NCM class
pub struct CdcNcmClass<'d, D: Driver<'d>> { pub struct CdcNcmClass<'d, D: Driver<'d>> {
_comm_if: InterfaceNumber, _comm_if: InterfaceNumber,
@ -253,11 +265,6 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
// Control interface // Control interface
let mut iface = func.interface(); let mut iface = func.interface();
let mac_addr_string = iface.string(); let mac_addr_string = iface.string();
iface.handler(state.comm_control.write(CommControl {
mac_addr_string,
shared: &state.shared,
mac_addr_str: [0; 12],
}));
let comm_if = iface.interface_number(); let comm_if = iface.interface_number();
let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_NCM, CDC_PROTOCOL_NONE, None); let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_NCM, CDC_PROTOCOL_NONE, None);
@ -307,13 +314,23 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
// Data interface // Data interface
let mut iface = func.interface(); let mut iface = func.interface();
iface.handler(state.data_control.write(DataControl {}));
let data_if = iface.interface_number(); let data_if = iface.interface_number();
let _alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None); let _alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None);
let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None); let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None);
let read_ep = alt.endpoint_bulk_out(max_packet_size); let read_ep = alt.endpoint_bulk_out(max_packet_size);
let write_ep = alt.endpoint_bulk_in(max_packet_size); let write_ep = alt.endpoint_bulk_in(max_packet_size);
drop(func);
let control = state.control.write(Control {
mac_addr_string,
shared: &state.shared,
mac_addr_str: [0; 12],
comm_if,
data_if,
});
builder.handler(control);
CdcNcmClass { CdcNcmClass {
_comm_if: comm_if, _comm_if: comm_if,
comm_ep, comm_ep,

View File

@ -9,9 +9,10 @@ use ssmarshal::serialize;
#[cfg(feature = "usbd-hid")] #[cfg(feature = "usbd-hid")]
use usbd_hid::descriptor::AsInputReport; use usbd_hid::descriptor::AsInputReport;
use crate::control::{ControlHandler, InResponse, OutResponse, Request, RequestType}; use crate::control::{InResponse, OutResponse, Recipient, Request, RequestType};
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
use crate::Builder; use crate::types::InterfaceNumber;
use crate::{Builder, Handler};
const USB_CLASS_HID: u8 = 0x03; const USB_CLASS_HID: u8 = 0x03;
const USB_SUBCLASS_NONE: u8 = 0x00; const USB_SUBCLASS_NONE: u8 = 0x00;
@ -100,17 +101,11 @@ fn build<'d, D: Driver<'d>>(
config: Config<'d>, config: Config<'d>,
with_out_endpoint: bool, with_out_endpoint: bool,
) -> (Option<D::EndpointOut>, D::EndpointIn, &'d AtomicUsize) { ) -> (Option<D::EndpointOut>, D::EndpointIn, &'d AtomicUsize) {
let control = state.control.write(Control::new(
config.report_descriptor,
config.request_handler,
&state.out_report_offset,
));
let len = config.report_descriptor.len(); let len = config.report_descriptor.len();
let mut func = builder.function(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE); let mut func = builder.function(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE);
let mut iface = func.interface(); let mut iface = func.interface();
iface.handler(control); let if_num = iface.interface_number();
let mut alt = iface.alt_setting(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE, None); let mut alt = iface.alt_setting(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE, None);
// HID descriptor // HID descriptor
@ -139,6 +134,16 @@ fn build<'d, D: Driver<'d>>(
None None
}; };
drop(func);
let control = state.control.write(Control::new(
if_num,
config.report_descriptor,
config.request_handler,
&state.out_report_offset,
));
builder.handler(control);
(ep_out, ep_in, &state.out_report_offset) (ep_out, ep_in, &state.out_report_offset)
} }
@ -400,6 +405,7 @@ pub trait RequestHandler {
} }
struct Control<'d> { struct Control<'d> {
if_num: InterfaceNumber,
report_descriptor: &'d [u8], report_descriptor: &'d [u8],
request_handler: Option<&'d dyn RequestHandler>, request_handler: Option<&'d dyn RequestHandler>,
out_report_offset: &'d AtomicUsize, out_report_offset: &'d AtomicUsize,
@ -408,11 +414,13 @@ struct Control<'d> {
impl<'d> Control<'d> { impl<'d> Control<'d> {
fn new( fn new(
if_num: InterfaceNumber,
report_descriptor: &'d [u8], report_descriptor: &'d [u8],
request_handler: Option<&'d dyn RequestHandler>, request_handler: Option<&'d dyn RequestHandler>,
out_report_offset: &'d AtomicUsize, out_report_offset: &'d AtomicUsize,
) -> Self { ) -> Self {
Control { Control {
if_num,
report_descriptor, report_descriptor,
request_handler, request_handler,
out_report_offset, out_report_offset,
@ -438,88 +446,100 @@ impl<'d> Control<'d> {
} }
} }
impl<'d> ControlHandler for Control<'d> { impl<'d> Handler for Control<'d> {
fn reset(&mut self) { fn reset(&mut self) {
self.out_report_offset.store(0, Ordering::Release); self.out_report_offset.store(0, Ordering::Release);
} }
fn get_descriptor<'a>(&'a mut self, req: Request, _buf: &'a mut [u8]) -> InResponse<'a> { fn control_out(&mut self, req: Request, data: &[u8]) -> Option<OutResponse> {
match (req.value >> 8) as u8 { if (req.request_type, req.recipient, req.index)
HID_DESC_DESCTYPE_HID_REPORT => InResponse::Accepted(self.report_descriptor), != (RequestType::Class, Recipient::Interface, self.if_num.0 as u16)
HID_DESC_DESCTYPE_HID => InResponse::Accepted(&self.hid_descriptor), {
_ => InResponse::Rejected, return None;
} }
}
fn control_out(&mut self, req: Request, data: &[u8]) -> OutResponse {
trace!("HID control_out {:?} {=[u8]:x}", req, data); trace!("HID control_out {:?} {=[u8]:x}", req, data);
if let RequestType::Class = req.request_type {
match req.request {
HID_REQ_SET_IDLE => {
if let Some(handler) = self.request_handler {
let id = req.value as u8;
let id = (id != 0).then(|| ReportId::In(id));
let dur = u32::from(req.value >> 8);
let dur = if dur == 0 { u32::MAX } else { 4 * dur };
handler.set_idle_ms(id, dur);
}
OutResponse::Accepted
}
HID_REQ_SET_REPORT => match (ReportId::try_from(req.value), self.request_handler) {
(Ok(id), Some(handler)) => handler.set_report(id, data),
_ => OutResponse::Rejected,
},
HID_REQ_SET_PROTOCOL => {
if req.value == 1 {
OutResponse::Accepted
} else {
warn!("HID Boot Protocol is unsupported.");
OutResponse::Rejected // UNSUPPORTED: Boot Protocol
}
}
_ => OutResponse::Rejected,
}
} else {
OutResponse::Rejected // UNSUPPORTED: SET_DESCRIPTOR
}
}
fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
trace!("HID control_in {:?}", req);
match req.request { match req.request {
HID_REQ_GET_REPORT => { HID_REQ_SET_IDLE => {
let size = match ReportId::try_from(req.value) {
Ok(id) => self.request_handler.and_then(|x| x.get_report(id, buf)),
Err(_) => None,
};
if let Some(size) = size {
InResponse::Accepted(&buf[0..size])
} else {
InResponse::Rejected
}
}
HID_REQ_GET_IDLE => {
if let Some(handler) = self.request_handler { if let Some(handler) = self.request_handler {
let id = req.value as u8; let id = req.value as u8;
let id = (id != 0).then(|| ReportId::In(id)); let id = (id != 0).then(|| ReportId::In(id));
if let Some(dur) = handler.get_idle_ms(id) { let dur = u32::from(req.value >> 8);
let dur = u8::try_from(dur / 4).unwrap_or(0); let dur = if dur == 0 { u32::MAX } else { 4 * dur };
buf[0] = dur; handler.set_idle_ms(id, dur);
InResponse::Accepted(&buf[0..1]) }
} else { Some(OutResponse::Accepted)
InResponse::Rejected }
} HID_REQ_SET_REPORT => match (ReportId::try_from(req.value), self.request_handler) {
(Ok(id), Some(handler)) => Some(handler.set_report(id, data)),
_ => Some(OutResponse::Rejected),
},
HID_REQ_SET_PROTOCOL => {
if req.value == 1 {
Some(OutResponse::Accepted)
} else { } else {
InResponse::Rejected warn!("HID Boot Protocol is unsupported.");
Some(OutResponse::Rejected) // UNSUPPORTED: Boot Protocol
} }
} }
HID_REQ_GET_PROTOCOL => { _ => Some(OutResponse::Rejected),
// UNSUPPORTED: Boot Protocol }
buf[0] = 1; }
InResponse::Accepted(&buf[0..1])
fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option<InResponse<'a>> {
if req.index != self.if_num.0 as u16 {
return None;
}
match (req.request_type, req.recipient) {
(RequestType::Standard, Recipient::Interface) => match req.request {
Request::GET_DESCRIPTOR => match (req.value >> 8) as u8 {
HID_DESC_DESCTYPE_HID_REPORT => Some(InResponse::Accepted(self.report_descriptor)),
HID_DESC_DESCTYPE_HID => Some(InResponse::Accepted(&self.hid_descriptor)),
_ => Some(InResponse::Rejected),
},
_ => Some(InResponse::Rejected),
},
(RequestType::Class, Recipient::Interface) => {
trace!("HID control_in {:?}", req);
match req.request {
HID_REQ_GET_REPORT => {
let size = match ReportId::try_from(req.value) {
Ok(id) => self.request_handler.and_then(|x| x.get_report(id, buf)),
Err(_) => None,
};
if let Some(size) = size {
Some(InResponse::Accepted(&buf[0..size]))
} else {
Some(InResponse::Rejected)
}
}
HID_REQ_GET_IDLE => {
if let Some(handler) = self.request_handler {
let id = req.value as u8;
let id = (id != 0).then(|| ReportId::In(id));
if let Some(dur) = handler.get_idle_ms(id) {
let dur = u8::try_from(dur / 4).unwrap_or(0);
buf[0] = dur;
Some(InResponse::Accepted(&buf[0..1]))
} else {
Some(InResponse::Rejected)
}
} else {
Some(InResponse::Rejected)
}
}
HID_REQ_GET_PROTOCOL => {
// UNSUPPORTED: Boot Protocol
buf[0] = 1;
Some(InResponse::Accepted(&buf[0..1]))
}
_ => Some(InResponse::Rejected),
}
} }
_ => InResponse::Rejected, _ => None,
} }
} }
} }

View File

@ -2,7 +2,6 @@
use core::mem; use core::mem;
use crate::driver::Direction; use crate::driver::Direction;
use crate::types::StringIndex;
/// Control request type. /// Control request type.
#[repr(u8)] #[repr(u8)]
@ -145,60 +144,3 @@ pub enum InResponse<'a> {
/// The request was rejected. /// The request was rejected.
Rejected, Rejected,
} }
/// Handler for control requests.
///
/// All methods are optional callbacks that will be called by
/// [`UsbDevice::run()`](crate::UsbDevice::run)
pub trait ControlHandler {
/// Called after a USB reset after the bus reset sequence is complete.
fn reset(&mut self) {}
/// Called when a "set alternate setting" control request is done on the interface.
fn set_alternate_setting(&mut self, alternate_setting: u8) {
let _ = alternate_setting;
}
/// Called when a control request is received with direction HostToDevice.
///
/// # Arguments
///
/// * `req` - The request from the SETUP packet.
/// * `data` - The data from the request.
fn control_out(&mut self, req: Request, data: &[u8]) -> OutResponse {
let _ = (req, data);
OutResponse::Rejected
}
/// Called when a control request is received with direction DeviceToHost.
///
/// You should write the response somewhere (usually to `buf`, but you may use another buffer
/// owned by yourself, or a static buffer), then return `InResponse::Accepted(data)`.
///
/// # Arguments
///
/// * `req` - The request from the SETUP packet.
fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
let _ = (req, buf);
InResponse::Rejected
}
/// Called when a GET DESCRIPTOR control request is received on the interface.
///
/// You should write the response somewhere (usually to `buf`, but you may use another buffer
/// owned by yourself, or a static buffer), then return `InResponse::Accepted(data)`.
///
/// # Arguments
///
/// * `req` - The request from the SETUP packet.
fn get_descriptor<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
let _ = (req, buf);
InResponse::Rejected
}
/// Called when a GET_DESCRIPTOR STRING control request is received.
fn get_string(&mut self, index: StringIndex, lang_id: u16) -> Option<&str> {
let _ = (index, lang_id);
None
}
}

View File

@ -1,5 +1,6 @@
use crate::descriptor::descriptor_type; use crate::descriptor::descriptor_type;
use crate::driver::EndpointAddress; use crate::driver::EndpointAddress;
use crate::types::InterfaceNumber;
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -75,7 +76,7 @@ impl<'a, 'b> Iterator for DescriptorIter<'a, 'b> {
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct EndpointInfo { pub struct EndpointInfo {
pub configuration: u8, pub configuration: u8,
pub interface: u8, pub interface: InterfaceNumber,
pub interface_alt: u8, pub interface_alt: u8,
pub ep_address: EndpointAddress, pub ep_address: EndpointAddress,
} }
@ -83,7 +84,7 @@ pub struct EndpointInfo {
pub fn foreach_endpoint(data: &[u8], mut f: impl FnMut(EndpointInfo)) -> Result<(), ReadError> { pub fn foreach_endpoint(data: &[u8], mut f: impl FnMut(EndpointInfo)) -> Result<(), ReadError> {
let mut ep = EndpointInfo { let mut ep = EndpointInfo {
configuration: 0, configuration: 0,
interface: 0, interface: InterfaceNumber(0),
interface_alt: 0, interface_alt: 0,
ep_address: EndpointAddress::from(0), ep_address: EndpointAddress::from(0),
}; };
@ -96,7 +97,7 @@ pub fn foreach_endpoint(data: &[u8], mut f: impl FnMut(EndpointInfo)) -> Result<
ep.configuration = r.read_u8()?; ep.configuration = r.read_u8()?;
} }
descriptor_type::INTERFACE => { descriptor_type::INTERFACE => {
ep.interface = r.read_u8()?; ep.interface = InterfaceNumber(r.read_u8()?);
ep.interface_alt = r.read_u8()?; ep.interface_alt = r.read_u8()?;
} }
descriptor_type::ENDPOINT => { descriptor_type::ENDPOINT => {

View File

@ -82,32 +82,87 @@ const STRING_INDEX_PRODUCT: u8 = 2;
const STRING_INDEX_SERIAL_NUMBER: u8 = 3; const STRING_INDEX_SERIAL_NUMBER: u8 = 3;
const STRING_INDEX_CUSTOM_START: u8 = 4; const STRING_INDEX_CUSTOM_START: u8 = 4;
/// A handler trait for changes in the device state of the [UsbDevice]. /// Handler for device events and control requests.
pub trait DeviceStateHandler { ///
/// All methods are optional callbacks that will be called by
/// [`UsbDevice::run()`](crate::UsbDevice::run)
pub trait Handler {
/// Called when the USB device has been enabled or disabled. /// Called when the USB device has been enabled or disabled.
fn enabled(&self, _enabled: bool) {} fn enabled(&mut self, _enabled: bool) {}
/// Called when the host resets the device. /// Called after a USB reset after the bus reset sequence is complete.
fn reset(&self) {} fn reset(&mut self) {}
/// Called when the host has set the address of the device to `addr`. /// Called when the host has set the address of the device to `addr`.
fn addressed(&self, _addr: u8) {} fn addressed(&mut self, _addr: u8) {}
/// Called when the host has enabled or disabled the configuration of the device. /// Called when the host has enabled or disabled the configuration of the device.
fn configured(&self, _configured: bool) {} fn configured(&mut self, _configured: bool) {}
/// Called when the bus has entered or exited the suspend state. /// Called when the bus has entered or exited the suspend state.
fn suspended(&self, _suspended: bool) {} fn suspended(&mut self, _suspended: bool) {}
/// Called when remote wakeup feature is enabled or disabled. /// Called when remote wakeup feature is enabled or disabled.
fn remote_wakeup_enabled(&self, _enabled: bool) {} fn remote_wakeup_enabled(&mut self, _enabled: bool) {}
/// Called when a "set alternate setting" control request is done on the interface.
fn set_alternate_setting(&mut self, iface: InterfaceNumber, alternate_setting: u8) {
let _ = iface;
let _ = alternate_setting;
}
/// Called when a control request is received with direction HostToDevice.
///
/// # Arguments
///
/// * `req` - The request from the SETUP packet.
/// * `data` - The data from the request.
///
/// # Returns
///
/// If you didn't handle this request (for example if it's for the wrong interface), return
/// `None`. In this case, the the USB stack will continue calling the other handlers, to see
/// if another handles it.
///
/// If you did, return `Some` with either `Accepted` or `Rejected`. This will make the USB stack
/// respond to the control request, and stop calling other handlers.
fn control_out(&mut self, req: Request, data: &[u8]) -> Option<OutResponse> {
let _ = (req, data);
None
}
/// Called when a control request is received with direction DeviceToHost.
///
/// You should write the response somewhere (usually to `buf`, but you may use another buffer
/// owned by yourself, or a static buffer), then return `InResponse::Accepted(data)`.
///
/// # Arguments
///
/// * `req` - The request from the SETUP packet.
///
/// # Returns
///
/// If you didn't handle this request (for example if it's for the wrong interface), return
/// `None`. In this case, the the USB stack will continue calling the other handlers, to see
/// if another handles it.
///
/// If you did, return `Some` with either `Accepted` or `Rejected`. This will make the USB stack
/// respond to the control request, and stop calling other handlers.
fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option<InResponse<'a>> {
let _ = (req, buf);
None
}
/// Called when a GET_DESCRIPTOR STRING control request is received.
fn get_string(&mut self, index: StringIndex, lang_id: u16) -> Option<&str> {
let _ = (index, lang_id);
None
}
} }
struct Interface<'d> { struct Interface {
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,
} }
/// Main struct for the USB device stack. /// Main struct for the USB device stack.
@ -119,7 +174,6 @@ pub struct UsbDevice<'d, D: Driver<'d>> {
struct Inner<'d, D: Driver<'d>> { struct Inner<'d, D: Driver<'d>> {
bus: D::Bus, bus: D::Bus,
handler: Option<&'d dyn DeviceStateHandler>,
config: Config<'d>, config: Config<'d>,
device_descriptor: &'d [u8], device_descriptor: &'d [u8],
@ -138,7 +192,9 @@ struct Inner<'d, D: Driver<'d>> {
/// instead of regular `accept()`. /// instead of regular `accept()`.
set_address_pending: bool, set_address_pending: bool,
interfaces: Vec<Interface<'d>, MAX_INTERFACE_COUNT>, interfaces: Vec<Interface, MAX_INTERFACE_COUNT>,
handlers: Vec<&'d mut dyn Handler, MAX_HANDLER_COUNT>,
#[cfg(feature = "msos-descriptor")] #[cfg(feature = "msos-descriptor")]
msos_descriptor: crate::msos::MsOsDescriptorSet<'d>, msos_descriptor: crate::msos::MsOsDescriptorSet<'d>,
} }
@ -147,11 +203,11 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
pub(crate) fn build( pub(crate) fn build(
driver: D, driver: D,
config: Config<'d>, config: Config<'d>,
handler: Option<&'d dyn DeviceStateHandler>, handlers: Vec<&'d mut dyn Handler, MAX_HANDLER_COUNT>,
device_descriptor: &'d [u8], device_descriptor: &'d [u8],
config_descriptor: &'d [u8], config_descriptor: &'d [u8],
bos_descriptor: &'d [u8], bos_descriptor: &'d [u8],
interfaces: Vec<Interface<'d>, MAX_INTERFACE_COUNT>, interfaces: Vec<Interface, MAX_INTERFACE_COUNT>,
control_buf: &'d mut [u8], control_buf: &'d mut [u8],
#[cfg(feature = "msos-descriptor")] msos_descriptor: crate::msos::MsOsDescriptorSet<'d>, #[cfg(feature = "msos-descriptor")] msos_descriptor: crate::msos::MsOsDescriptorSet<'d>,
) -> UsbDevice<'d, D> { ) -> UsbDevice<'d, D> {
@ -165,7 +221,6 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
inner: Inner { inner: Inner {
bus, bus,
config, config,
handler,
device_descriptor, device_descriptor,
config_descriptor, config_descriptor,
bos_descriptor, bos_descriptor,
@ -177,6 +232,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
address: 0, address: 0,
set_address_pending: false, set_address_pending: false,
interfaces, interfaces,
handlers,
#[cfg(feature = "msos-descriptor")] #[cfg(feature = "msos-descriptor")]
msos_descriptor, msos_descriptor,
}, },
@ -221,7 +277,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
self.inner.suspended = false; self.inner.suspended = false;
self.inner.remote_wakeup_enabled = false; self.inner.remote_wakeup_enabled = false;
if let Some(h) = &self.inner.handler { for h in &mut self.inner.handlers {
h.enabled(false); h.enabled(false);
} }
} }
@ -250,7 +306,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
self.inner.bus.remote_wakeup().await?; self.inner.bus.remote_wakeup().await?;
self.inner.suspended = false; self.inner.suspended = false;
if let Some(h) = &self.inner.handler { for h in &mut self.inner.handlers {
h.suspended(false); h.suspended(false);
} }
@ -361,29 +417,29 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
self.remote_wakeup_enabled = false; self.remote_wakeup_enabled = false;
self.address = 0; self.address = 0;
for iface in self.interfaces.iter_mut() { for h in &mut self.handlers {
iface.current_alt_setting = 0; h.reset();
if let Some(h) = &mut iface.handler {
h.reset();
h.set_alternate_setting(0);
}
} }
if let Some(h) = &self.handler { for (i, iface) in self.interfaces.iter_mut().enumerate() {
h.reset(); iface.current_alt_setting = 0;
for h in &mut self.handlers {
h.set_alternate_setting(InterfaceNumber::new(i as _), 0);
}
} }
} }
Event::Resume => { Event::Resume => {
trace!("usb: resume"); trace!("usb: resume");
self.suspended = false; self.suspended = false;
if let Some(h) = &self.handler { for h in &mut self.handlers {
h.suspended(false); h.suspended(false);
} }
} }
Event::Suspend => { Event::Suspend => {
trace!("usb: suspend"); trace!("usb: suspend");
self.suspended = true; self.suspended = true;
if let Some(h) = &self.handler { for h in &mut self.handlers {
h.suspended(true); h.suspended(true);
} }
} }
@ -392,7 +448,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
self.bus.enable().await; self.bus.enable().await;
self.device_state = UsbDeviceState::Default; self.device_state = UsbDeviceState::Default;
if let Some(h) = &self.handler { for h in &mut self.handlers {
h.enabled(true); h.enabled(true);
} }
} }
@ -401,7 +457,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
self.bus.disable().await; self.bus.disable().await;
self.device_state = UsbDeviceState::Unpowered; self.device_state = UsbDeviceState::Unpowered;
if let Some(h) = &self.handler { for h in &mut self.handlers {
h.enabled(false); h.enabled(false);
} }
} }
@ -416,14 +472,14 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
(RequestType::Standard, Recipient::Device) => match (req.request, req.value) { (RequestType::Standard, Recipient::Device) => match (req.request, req.value) {
(Request::CLEAR_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => { (Request::CLEAR_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => {
self.remote_wakeup_enabled = false; self.remote_wakeup_enabled = false;
if let Some(h) = &self.handler { for h in &mut self.handlers {
h.remote_wakeup_enabled(false); h.remote_wakeup_enabled(false);
} }
OutResponse::Accepted OutResponse::Accepted
} }
(Request::SET_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => { (Request::SET_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => {
self.remote_wakeup_enabled = true; self.remote_wakeup_enabled = true;
if let Some(h) = &self.handler { for h in &mut self.handlers {
h.remote_wakeup_enabled(true); h.remote_wakeup_enabled(true);
} }
OutResponse::Accepted OutResponse::Accepted
@ -432,7 +488,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
self.address = addr as u8; self.address = addr as u8;
self.set_address_pending = true; self.set_address_pending = true;
self.device_state = UsbDeviceState::Addressed; self.device_state = UsbDeviceState::Addressed;
if let Some(h) = &self.handler { for h in &mut self.handlers {
h.addressed(self.address); h.addressed(self.address);
} }
OutResponse::Accepted OutResponse::Accepted
@ -443,14 +499,14 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
// Enable all endpoints of selected alt settings. // Enable all endpoints of selected alt settings.
foreach_endpoint(self.config_descriptor, |ep| { foreach_endpoint(self.config_descriptor, |ep| {
let iface = &self.interfaces[ep.interface as usize]; let iface = &self.interfaces[ep.interface.0 as usize];
self.bus self.bus
.endpoint_set_enabled(ep.ep_address, iface.current_alt_setting == ep.interface_alt); .endpoint_set_enabled(ep.ep_address, iface.current_alt_setting == ep.interface_alt);
}) })
.unwrap(); .unwrap();
// Notify handler. // Notify handlers.
if let Some(h) = &self.handler { for h in &mut self.handlers {
h.configured(true); h.configured(true);
} }
@ -468,8 +524,8 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
}) })
.unwrap(); .unwrap();
// Notify handler. // Notify handlers.
if let Some(h) = &self.handler { for h in &mut self.handlers {
h.configured(false); h.configured(false);
} }
@ -479,7 +535,8 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
_ => OutResponse::Rejected, _ => OutResponse::Rejected,
}, },
(RequestType::Standard, Recipient::Interface) => { (RequestType::Standard, Recipient::Interface) => {
let iface = match self.interfaces.get_mut(req.index as usize) { let iface_num = InterfaceNumber::new(req.index as _);
let iface = match self.interfaces.get_mut(iface_num.0 as usize) {
Some(iface) => iface, Some(iface) => iface,
None => return OutResponse::Rejected, None => return OutResponse::Rejected,
}; };
@ -497,7 +554,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
// Enable/disable EPs of this interface as needed. // Enable/disable EPs of this interface as needed.
foreach_endpoint(self.config_descriptor, |ep| { foreach_endpoint(self.config_descriptor, |ep| {
if ep.interface == req.index as u8 { if ep.interface == iface_num {
self.bus self.bus
.endpoint_set_enabled(ep.ep_address, iface.current_alt_setting == ep.interface_alt); .endpoint_set_enabled(ep.ep_address, iface.current_alt_setting == ep.interface_alt);
} }
@ -506,8 +563,8 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
// TODO check it is valid (not out of range) // TODO check it is valid (not out of range)
if let Some(handler) = &mut iface.handler { for h in &mut self.handlers {
handler.set_alternate_setting(new_altsetting); h.set_alternate_setting(iface_num, new_altsetting);
} }
OutResponse::Accepted OutResponse::Accepted
} }
@ -527,17 +584,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
} }
_ => OutResponse::Rejected, _ => OutResponse::Rejected,
}, },
(RequestType::Class, Recipient::Interface) => { _ => self.handle_control_out_delegated(req, data),
let iface = match self.interfaces.get_mut(req.index as usize) {
Some(iface) => iface,
None => return OutResponse::Rejected,
};
match &mut iface.handler {
Some(handler) => handler.control_out(req, data),
None => OutResponse::Rejected,
}
}
_ => OutResponse::Rejected,
} }
} }
@ -582,11 +629,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
buf[0] = iface.current_alt_setting; buf[0] = iface.current_alt_setting;
InResponse::Accepted(&buf[..1]) InResponse::Accepted(&buf[..1])
} }
Request::GET_DESCRIPTOR => match &mut iface.handler { _ => self.handle_control_in_delegated(req, buf),
Some(handler) => handler.get_descriptor(req, buf),
None => InResponse::Rejected,
},
_ => InResponse::Rejected,
} }
} }
(RequestType::Standard, Recipient::Endpoint) => match req.request { (RequestType::Standard, Recipient::Endpoint) => match req.request {
@ -601,34 +644,48 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
} }
_ => InResponse::Rejected, _ => InResponse::Rejected,
}, },
(RequestType::Class, Recipient::Interface) => {
let iface = match self.interfaces.get_mut(req.index as usize) {
Some(iface) => iface,
None => return InResponse::Rejected,
};
match &mut iface.handler {
Some(handler) => handler.control_in(req, buf),
None => InResponse::Rejected,
}
}
#[cfg(feature = "msos-descriptor")] #[cfg(feature = "msos-descriptor")]
(RequestType::Vendor, Recipient::Device) => { (RequestType::Vendor, Recipient::Device) => {
if !self.msos_descriptor.is_empty() { if !self.msos_descriptor.is_empty()
if req.request == self.msos_descriptor.vendor_code() && req.index == 7 { && req.request == self.msos_descriptor.vendor_code()
// Index 7 retrieves the MS OS Descriptor Set && req.index == 7
InResponse::Accepted(self.msos_descriptor.descriptor()) {
} else { // Index 7 retrieves the MS OS Descriptor Set
InResponse::Rejected InResponse::Accepted(self.msos_descriptor.descriptor())
}
} else { } else {
InResponse::Rejected self.handle_control_in_delegated(req, buf)
} }
} }
_ => InResponse::Rejected, _ => self.handle_control_in_delegated(req, buf),
} }
} }
fn handle_control_out_delegated(&mut self, req: Request, data: &[u8]) -> OutResponse {
for h in &mut self.handlers {
if let Some(res) = h.control_out(req, data) {
return res;
}
}
OutResponse::Rejected
}
fn handle_control_in_delegated<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
unsafe fn extend_lifetime<'x, 'y>(r: InResponse<'x>) -> InResponse<'y> {
core::mem::transmute(r)
}
for h in &mut self.handlers {
if let Some(res) = h.control_in(req, buf) {
// safety: the borrow checker isn't smart enough to know this pattern (returning a
// borrowed value from inside the loop) is sound. Workaround by unsafely extending lifetime.
// Also, Polonius (the WIP new borrow checker) does accept it.
return unsafe { extend_lifetime(res) };
}
}
InResponse::Rejected
}
fn handle_get_descriptor<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> { fn handle_get_descriptor<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
let (dtype, index) = req.descriptor_type_index(); let (dtype, index) = req.descriptor_type_index();
@ -649,30 +706,16 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
STRING_INDEX_PRODUCT => self.config.product, STRING_INDEX_PRODUCT => self.config.product,
STRING_INDEX_SERIAL_NUMBER => self.config.serial_number, STRING_INDEX_SERIAL_NUMBER => self.config.serial_number,
_ => { _ => {
// Find out which iface owns this string index. let mut s = None;
let mut index_left = index - STRING_INDEX_CUSTOM_START; for handler in &mut self.handlers {
let mut the_iface = None; let index = StringIndex::new(index);
for iface in &mut self.interfaces { let lang_id = req.index;
if index_left < iface.num_strings { if let Some(res) = handler.get_string(index, lang_id) {
the_iface = Some(iface); s = Some(res);
break; 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)
} else {
warn!("String requested to an interface with no handler.");
None
}
} else {
warn!("String requested but didn't match to an interface.");
None
} }
s
} }
}; };

View File

@ -1,9 +1,9 @@
//! USB types. //! USB types.
/// A handle for a USB interface that contains its number. /// A handle for a USB interface that contains its number.
#[derive(Copy, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InterfaceNumber(pub(crate) u8); pub struct InterfaceNumber(pub u8);
impl InterfaceNumber { impl InterfaceNumber {
pub(crate) fn new(index: u8) -> InterfaceNumber { pub(crate) fn new(index: u8) -> InterfaceNumber {
@ -20,7 +20,7 @@ impl From<InterfaceNumber> for u8 {
/// A handle for a USB string descriptor that contains its index. /// A handle for a USB string descriptor that contains its index.
#[derive(Copy, Clone, Eq, PartialEq)] #[derive(Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct StringIndex(u8); pub struct StringIndex(pub u8);
impl StringIndex { impl StringIndex {
pub(crate) fn new(index: u8) -> StringIndex { pub(crate) fn new(index: u8) -> StringIndex {

View File

@ -82,7 +82,6 @@ async fn main(spawner: Spawner) {
&mut singleton!([0; 256])[..], &mut singleton!([0; 256])[..],
&mut singleton!([0; 256])[..], &mut singleton!([0; 256])[..],
&mut singleton!([0; 128])[..], &mut singleton!([0; 128])[..],
None,
); );
// Our MAC addr. // Our MAC addr.

View File

@ -16,7 +16,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::signal::Signal; use embassy_sync::signal::Signal;
use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
use embassy_usb::control::OutResponse; use embassy_usb::control::OutResponse;
use embassy_usb::{Builder, Config, DeviceStateHandler}; use embassy_usb::{Builder, Config, Handler};
use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -52,7 +52,7 @@ async fn main(_spawner: Spawner) {
let mut bos_descriptor = [0; 256]; let mut bos_descriptor = [0; 256];
let mut control_buf = [0; 64]; let mut control_buf = [0; 64];
let request_handler = MyRequestHandler {}; let request_handler = MyRequestHandler {};
let device_state_handler = MyDeviceStateHandler::new(); let mut device_handler = MyDeviceHandler::new();
let mut state = State::new(); let mut state = State::new();
@ -63,9 +63,10 @@ async fn main(_spawner: Spawner) {
&mut config_descriptor, &mut config_descriptor,
&mut bos_descriptor, &mut bos_descriptor,
&mut control_buf, &mut control_buf,
Some(&device_state_handler),
); );
builder.handler(&mut device_handler);
// Create classes on the builder. // Create classes on the builder.
let config = embassy_usb::class::hid::Config { let config = embassy_usb::class::hid::Config {
report_descriptor: KeyboardReport::desc(), report_descriptor: KeyboardReport::desc(),
@ -164,20 +165,20 @@ impl RequestHandler for MyRequestHandler {
} }
} }
struct MyDeviceStateHandler { struct MyDeviceHandler {
configured: AtomicBool, configured: AtomicBool,
} }
impl MyDeviceStateHandler { impl MyDeviceHandler {
fn new() -> Self { fn new() -> Self {
MyDeviceStateHandler { MyDeviceHandler {
configured: AtomicBool::new(false), configured: AtomicBool::new(false),
} }
} }
} }
impl DeviceStateHandler for MyDeviceStateHandler { impl Handler for MyDeviceHandler {
fn enabled(&self, enabled: bool) { fn enabled(&mut self, enabled: bool) {
self.configured.store(false, Ordering::Relaxed); self.configured.store(false, Ordering::Relaxed);
SUSPENDED.store(false, Ordering::Release); SUSPENDED.store(false, Ordering::Release);
if enabled { if enabled {
@ -187,17 +188,17 @@ impl DeviceStateHandler for MyDeviceStateHandler {
} }
} }
fn reset(&self) { fn reset(&mut self) {
self.configured.store(false, Ordering::Relaxed); self.configured.store(false, Ordering::Relaxed);
info!("Bus reset, the Vbus current limit is 100mA"); info!("Bus reset, the Vbus current limit is 100mA");
} }
fn addressed(&self, addr: u8) { fn addressed(&mut self, addr: u8) {
self.configured.store(false, Ordering::Relaxed); self.configured.store(false, Ordering::Relaxed);
info!("USB address set to: {}", addr); info!("USB address set to: {}", addr);
} }
fn configured(&self, configured: bool) { fn configured(&mut self, configured: bool) {
self.configured.store(configured, Ordering::Relaxed); self.configured.store(configured, Ordering::Relaxed);
if configured { if configured {
info!("Device configured, it may now draw up to the configured current limit from Vbus.") info!("Device configured, it may now draw up to the configured current limit from Vbus.")
@ -206,7 +207,7 @@ impl DeviceStateHandler for MyDeviceStateHandler {
} }
} }
fn suspended(&self, suspended: bool) { fn suspended(&mut self, suspended: bool) {
if suspended { if suspended {
info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled)."); info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled).");
SUSPENDED.store(true, Ordering::Release); SUSPENDED.store(true, Ordering::Release);

View File

@ -55,7 +55,6 @@ async fn main(_spawner: Spawner) {
&mut config_descriptor, &mut config_descriptor,
&mut bos_descriptor, &mut bos_descriptor,
&mut control_buf, &mut control_buf,
None,
); );
// Create classes on the builder. // Create classes on the builder.

View File

@ -59,7 +59,6 @@ async fn main(_spawner: Spawner) {
&mut config_descriptor, &mut config_descriptor,
&mut bos_descriptor, &mut bos_descriptor,
&mut control_buf, &mut control_buf,
None,
); );
// Create classes on the builder. // Create classes on the builder.

View File

@ -83,7 +83,6 @@ async fn main(spawner: Spawner) {
&mut res.config_descriptor, &mut res.config_descriptor,
&mut res.bos_descriptor, &mut res.bos_descriptor,
&mut res.control_buf, &mut res.control_buf,
None,
); );
// Create classes on the builder. // Create classes on the builder.

View File

@ -65,7 +65,6 @@ async fn main(_spawner: Spawner) {
&mut bos_descriptor, &mut bos_descriptor,
&mut msos_descriptor, &mut msos_descriptor,
&mut control_buf, &mut control_buf,
None,
); );
builder.msos_descriptor(windows_version::WIN8_1, 2); builder.msos_descriptor(windows_version::WIN8_1, 2);

View File

@ -73,7 +73,6 @@ async fn main(spawner: Spawner) {
&mut singleton!([0; 256])[..], &mut singleton!([0; 256])[..],
&mut singleton!([0; 256])[..], &mut singleton!([0; 256])[..],
&mut singleton!([0; 128])[..], &mut singleton!([0; 128])[..],
None,
); );
// Our MAC addr. // Our MAC addr.

View File

@ -53,7 +53,6 @@ async fn main(_spawner: Spawner) {
&mut config_descriptor, &mut config_descriptor,
&mut bos_descriptor, &mut bos_descriptor,
&mut control_buf, &mut control_buf,
None,
); );
// Create classes on the builder. // Create classes on the builder.

View File

@ -58,7 +58,6 @@ async fn main(_spawner: Spawner) {
&mut config_descriptor, &mut config_descriptor,
&mut bos_descriptor, &mut bos_descriptor,
&mut control_buf, &mut control_buf,
None,
); );
// Create classes on the builder. // Create classes on the builder.

View File

@ -55,7 +55,6 @@ async fn main(_spawner: Spawner) {
&mut config_descriptor, &mut config_descriptor,
&mut bos_descriptor, &mut bos_descriptor,
&mut control_buf, &mut control_buf,
None,
); );
// Create classes on the builder. // Create classes on the builder.

View File

@ -82,7 +82,6 @@ async fn main(spawner: Spawner) {
&mut singleton!([0; 256])[..], &mut singleton!([0; 256])[..],
&mut singleton!([0; 256])[..], &mut singleton!([0; 256])[..],
&mut singleton!([0; 128])[..], &mut singleton!([0; 128])[..],
None,
); );
// Our MAC addr. // Our MAC addr.

View File

@ -57,7 +57,6 @@ async fn main(_spawner: Spawner) {
&mut config_descriptor, &mut config_descriptor,
&mut bos_descriptor, &mut bos_descriptor,
&mut control_buf, &mut control_buf,
None,
); );
// Create classes on the builder. // Create classes on the builder.

View File

@ -58,7 +58,6 @@ async fn main(_spawner: Spawner) {
&mut config_descriptor, &mut config_descriptor,
&mut bos_descriptor, &mut bos_descriptor,
&mut control_buf, &mut control_buf,
None,
); );
// Create classes on the builder. // Create classes on the builder.

View File

@ -57,7 +57,6 @@ async fn main(_spawner: Spawner) {
&mut config_descriptor, &mut config_descriptor,
&mut bos_descriptor, &mut bos_descriptor,
&mut control_buf, &mut control_buf,
None,
); );
// Create classes on the builder. // Create classes on the builder.

View File

@ -59,7 +59,6 @@ async fn main(_spawner: Spawner) {
&mut config_descriptor, &mut config_descriptor,
&mut bos_descriptor, &mut bos_descriptor,
&mut control_buf, &mut control_buf,
None,
); );
// Create classes on the builder. // Create classes on the builder.

View File

@ -79,7 +79,6 @@ async fn main(spawner: Spawner) {
&mut singleton!([0; 256])[..], &mut singleton!([0; 256])[..],
&mut singleton!([0; 256])[..], &mut singleton!([0; 256])[..],
&mut singleton!([0; 128])[..], &mut singleton!([0; 128])[..],
None,
); );
// Our MAC addr. // Our MAC addr.

View File

@ -51,7 +51,6 @@ async fn main(_spawner: Spawner) {
&mut config_descriptor, &mut config_descriptor,
&mut bos_descriptor, &mut bos_descriptor,
&mut control_buf, &mut control_buf,
None,
); );
// Create classes on the builder. // Create classes on the builder.

View File

@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) {
&mut config_descriptor, &mut config_descriptor,
&mut bos_descriptor, &mut bos_descriptor,
&mut control_buf, &mut control_buf,
None,
); );
// Create classes on the builder. // Create classes on the builder.

View File

@ -59,7 +59,6 @@ async fn main(_spawner: Spawner) {
&mut config_descriptor, &mut config_descriptor,
&mut bos_descriptor, &mut bos_descriptor,
&mut control_buf, &mut control_buf,
None,
); );
// Create classes on the builder. // Create classes on the builder.