Merge pull request #722 from embassy-rs/usb-altsettings
usb: builtin handling of interface alternate settings
This commit is contained in:
commit
11143a1be1
@ -17,6 +17,8 @@ flavors = [
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
||||||
|
defmt = ["dep:defmt", "embassy/defmt", "embassy-usb?/defmt"]
|
||||||
|
|
||||||
# Enable nightly-only features
|
# Enable nightly-only features
|
||||||
nightly = ["embassy/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-usb", "embedded-storage-async"]
|
nightly = ["embassy/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-usb", "embedded-storage-async"]
|
||||||
|
|
||||||
|
@ -194,16 +194,12 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
|||||||
fn into_bus(self) -> Self::Bus {
|
fn into_bus(self) -> Self::Bus {
|
||||||
Bus {
|
Bus {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
alloc_in: self.alloc_in,
|
|
||||||
alloc_out: self.alloc_out,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Bus<'d, T: Instance> {
|
pub struct Bus<'d, T: Instance> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
alloc_in: Allocator,
|
|
||||||
alloc_out: Allocator,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
||||||
@ -264,7 +260,16 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
if regs.events_usbreset.read().bits() != 0 {
|
if regs.events_usbreset.read().bits() != 0 {
|
||||||
regs.events_usbreset.reset();
|
regs.events_usbreset.reset();
|
||||||
regs.intenset.write(|w| w.usbreset().set());
|
regs.intenset.write(|w| w.usbreset().set());
|
||||||
self.set_configured(false);
|
|
||||||
|
// Disable all endpoints except EP0
|
||||||
|
regs.epinen.write(|w| unsafe { w.bits(0x01) });
|
||||||
|
regs.epouten.write(|w| unsafe { w.bits(0x01) });
|
||||||
|
READY_ENDPOINTS.store(In::mask(0), Ordering::Release);
|
||||||
|
for i in 1..=7 {
|
||||||
|
In::waker(i).wake();
|
||||||
|
Out::waker(i).wake();
|
||||||
|
}
|
||||||
|
|
||||||
return Poll::Ready(Event::Reset);
|
return Poll::Ready(Event::Reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,57 +302,76 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn set_configured(&mut self, configured: bool) {
|
fn set_address(&mut self, _addr: u8) {
|
||||||
|
// Nothing to do, the peripheral handles this.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
|
||||||
|
Driver::<T>::set_stalled(ep_addr, stalled)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
|
||||||
|
Driver::<T>::is_stalled(ep_addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
unsafe {
|
let i = ep_addr.index();
|
||||||
if configured {
|
let mask = 1 << i;
|
||||||
// TODO: Initialize ISO buffers
|
|
||||||
|
|
||||||
regs.epinen.write(|w| w.bits(self.alloc_in.used.into()));
|
debug!("endpoint_set_enabled {:?} {}", ep_addr, enabled);
|
||||||
regs.epouten.write(|w| w.bits(self.alloc_out.used.into()));
|
|
||||||
|
|
||||||
for i in 1..8 {
|
match ep_addr.direction() {
|
||||||
let out_enabled = self.alloc_out.used & (1 << i) != 0;
|
UsbDirection::In => {
|
||||||
|
let mut was_enabled = false;
|
||||||
|
regs.epinen.modify(|r, w| {
|
||||||
|
let mut bits = r.bits();
|
||||||
|
was_enabled = (bits & mask) != 0;
|
||||||
|
if enabled {
|
||||||
|
bits |= mask
|
||||||
|
} else {
|
||||||
|
bits &= !mask
|
||||||
|
}
|
||||||
|
unsafe { w.bits(bits) }
|
||||||
|
});
|
||||||
|
|
||||||
|
let ready_mask = In::mask(i);
|
||||||
|
if enabled {
|
||||||
|
if !was_enabled {
|
||||||
|
READY_ENDPOINTS.fetch_or(ready_mask, Ordering::AcqRel);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
READY_ENDPOINTS.fetch_and(!ready_mask, Ordering::AcqRel);
|
||||||
|
}
|
||||||
|
|
||||||
|
In::waker(i).wake();
|
||||||
|
}
|
||||||
|
UsbDirection::Out => {
|
||||||
|
regs.epouten.modify(|r, w| {
|
||||||
|
let mut bits = r.bits();
|
||||||
|
if enabled {
|
||||||
|
bits |= mask
|
||||||
|
} else {
|
||||||
|
bits &= !mask
|
||||||
|
}
|
||||||
|
unsafe { w.bits(bits) }
|
||||||
|
});
|
||||||
|
|
||||||
|
let ready_mask = Out::mask(i);
|
||||||
|
if enabled {
|
||||||
// when first enabled, bulk/interrupt OUT endpoints will *not* receive data (the
|
// when first enabled, bulk/interrupt OUT endpoints will *not* receive data (the
|
||||||
// peripheral will NAK all incoming packets) until we write a zero to the SIZE
|
// peripheral will NAK all incoming packets) until we write a zero to the SIZE
|
||||||
// register (see figure 203 of the 52840 manual). To avoid that we write a 0 to the
|
// register (see figure 203 of the 52840 manual). To avoid that we write a 0 to the
|
||||||
// SIZE register
|
// SIZE register
|
||||||
if out_enabled {
|
regs.size.epout[i].reset();
|
||||||
regs.size.epout[i].reset();
|
} else {
|
||||||
}
|
READY_ENDPOINTS.fetch_and(!ready_mask, Ordering::AcqRel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// IN endpoints (low bits) default to ready.
|
Out::waker(i).wake();
|
||||||
// OUT endpoints (high bits) default to NOT ready, they become ready when data comes in.
|
|
||||||
READY_ENDPOINTS.store(0x0000FFFF, Ordering::Release);
|
|
||||||
} else {
|
|
||||||
// Disable all endpoints except EP0
|
|
||||||
regs.epinen.write(|w| w.bits(0x01));
|
|
||||||
regs.epouten.write(|w| w.bits(0x01));
|
|
||||||
|
|
||||||
READY_ENDPOINTS.store(In::mask(0), Ordering::Release);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 1..=7 {
|
|
||||||
In::waker(i).wake();
|
|
||||||
Out::waker(i).wake();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn set_device_address(&mut self, _addr: u8) {
|
|
||||||
// Nothing to do, the peripheral handles this.
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
|
|
||||||
Driver::<T>::set_stalled(ep_addr, stalled)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
|
|
||||||
Driver::<T>::is_stalled(ep_addr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -112,7 +112,8 @@ fn build<'d, D: Driver<'d>>(
|
|||||||
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(Some(control));
|
let mut iface = func.interface();
|
||||||
|
iface.handler(control);
|
||||||
let mut alt = iface.alt_setting(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE);
|
let mut alt = iface.alt_setting(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE);
|
||||||
|
|
||||||
// HID descriptor
|
// HID descriptor
|
||||||
@ -438,6 +439,14 @@ impl<'d> ControlHandler for Control<'d> {
|
|||||||
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> {
|
||||||
|
match (req.value >> 8) as u8 {
|
||||||
|
HID_DESC_DESCTYPE_HID_REPORT => InResponse::Accepted(self.report_descriptor),
|
||||||
|
HID_DESC_DESCTYPE_HID => InResponse::Accepted(&self.hid_descriptor),
|
||||||
|
_ => InResponse::Rejected,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn control_out(&mut self, req: embassy_usb::control::Request, data: &[u8]) -> OutResponse {
|
fn control_out(&mut self, req: embassy_usb::control::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 {
|
if let RequestType::Class = req.request_type {
|
||||||
@ -477,13 +486,8 @@ impl<'d> ControlHandler for Control<'d> {
|
|||||||
|
|
||||||
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]) -> InResponse<'a> {
|
||||||
trace!("HID control_in {:?}", req);
|
trace!("HID control_in {:?}", req);
|
||||||
match (req.request_type, req.request) {
|
match req.request {
|
||||||
(RequestType::Standard, Request::GET_DESCRIPTOR) => match (req.value >> 8) as u8 {
|
HID_REQ_GET_REPORT => {
|
||||||
HID_DESC_DESCTYPE_HID_REPORT => InResponse::Accepted(self.report_descriptor),
|
|
||||||
HID_DESC_DESCTYPE_HID => InResponse::Accepted(&self.hid_descriptor),
|
|
||||||
_ => InResponse::Rejected,
|
|
||||||
},
|
|
||||||
(RequestType::Class, HID_REQ_GET_REPORT) => {
|
|
||||||
let size = match ReportId::try_from(req.value) {
|
let size = match ReportId::try_from(req.value) {
|
||||||
Ok(id) => self.request_handler.and_then(|x| x.get_report(id, buf)),
|
Ok(id) => self.request_handler.and_then(|x| x.get_report(id, buf)),
|
||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
@ -495,7 +499,7 @@ impl<'d> ControlHandler for Control<'d> {
|
|||||||
InResponse::Rejected
|
InResponse::Rejected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(RequestType::Class, HID_REQ_GET_IDLE) => {
|
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));
|
||||||
@ -510,7 +514,7 @@ impl<'d> ControlHandler for Control<'d> {
|
|||||||
InResponse::Rejected
|
InResponse::Rejected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(RequestType::Class, HID_REQ_GET_PROTOCOL) => {
|
HID_REQ_GET_PROTOCOL => {
|
||||||
// UNSUPPORTED: Boot Protocol
|
// UNSUPPORTED: Boot Protocol
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
InResponse::Accepted(&buf[0..1])
|
InResponse::Accepted(&buf[0..1])
|
||||||
|
@ -178,7 +178,8 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
|
|||||||
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(Some(control));
|
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);
|
let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE);
|
||||||
@ -218,7 +219,7 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
|
|||||||
let comm_ep = alt.endpoint_interrupt_in(8, 255);
|
let comm_ep = alt.endpoint_interrupt_in(8, 255);
|
||||||
|
|
||||||
// Data interface
|
// Data interface
|
||||||
let mut iface = func.interface(None);
|
let mut iface = func.interface();
|
||||||
let data_if = iface.interface_number();
|
let data_if = iface.interface_number();
|
||||||
let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NONE);
|
let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NONE);
|
||||||
let read_ep = alt.endpoint_bulk_out(max_packet_size);
|
let read_ep = alt.endpoint_bulk_out(max_packet_size);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
|
|
||||||
|
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};
|
||||||
use super::driver::{Driver, Endpoint};
|
use super::driver::{Driver, Endpoint};
|
||||||
@ -121,11 +123,10 @@ impl<'a> Config<'a> {
|
|||||||
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>,
|
handler: Option<&'d dyn DeviceStateHandler>,
|
||||||
interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>,
|
interfaces: Vec<Interface<'d>, MAX_INTERFACE_COUNT>,
|
||||||
control_buf: &'d mut [u8],
|
control_buf: &'d mut [u8],
|
||||||
|
|
||||||
driver: D,
|
driver: D,
|
||||||
next_interface_number: u8,
|
|
||||||
next_string_index: u8,
|
next_string_index: u8,
|
||||||
|
|
||||||
device_descriptor: DescriptorWriter<'d>,
|
device_descriptor: DescriptorWriter<'d>,
|
||||||
@ -180,8 +181,7 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
|
|||||||
config,
|
config,
|
||||||
interfaces: Vec::new(),
|
interfaces: Vec::new(),
|
||||||
control_buf,
|
control_buf,
|
||||||
next_interface_number: 0,
|
next_string_index: STRING_INDEX_CUSTOM_START,
|
||||||
next_string_index: 4,
|
|
||||||
|
|
||||||
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
|
||||||
@ -234,7 +226,7 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
|
|||||||
) -> FunctionBuilder<'_, 'd, D> {
|
) -> FunctionBuilder<'_, 'd, D> {
|
||||||
let iface_count_index = if self.config.composite_with_iads {
|
let iface_count_index = if self.config.composite_with_iads {
|
||||||
self.config_descriptor.iad(
|
self.config_descriptor.iad(
|
||||||
InterfaceNumber::new(self.next_interface_number),
|
InterfaceNumber::new(self.interfaces.len() as _),
|
||||||
0,
|
0,
|
||||||
class,
|
class,
|
||||||
subclass,
|
subclass,
|
||||||
@ -267,21 +259,21 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
|
|||||||
/// Add an interface to the function.
|
/// Add an interface to the function.
|
||||||
///
|
///
|
||||||
/// Interface numbers are guaranteed to be allocated consecutively, starting from 0.
|
/// Interface numbers are guaranteed to be allocated consecutively, starting from 0.
|
||||||
pub fn interface(
|
pub fn interface(&mut self) -> InterfaceBuilder<'_, 'd, D> {
|
||||||
&mut self,
|
|
||||||
handler: Option<&'d mut dyn ControlHandler>,
|
|
||||||
) -> InterfaceBuilder<'_, 'd, D> {
|
|
||||||
if let Some(i) = self.iface_count_index {
|
if let Some(i) = self.iface_count_index {
|
||||||
self.builder.config_descriptor.buf[i] += 1;
|
self.builder.config_descriptor.buf[i] += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let number = self.builder.next_interface_number;
|
let number = self.builder.interfaces.len() as _;
|
||||||
self.builder.next_interface_number += 1;
|
let iface = Interface {
|
||||||
|
handler: None,
|
||||||
|
current_alt_setting: 0,
|
||||||
|
num_alt_settings: 0,
|
||||||
|
num_strings: 0,
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(handler) = handler {
|
if self.builder.interfaces.push(iface).is_err() {
|
||||||
if self.builder.interfaces.push((number, handler)).is_err() {
|
panic!("max interface count reached")
|
||||||
panic!("max interface count reached")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InterfaceBuilder {
|
InterfaceBuilder {
|
||||||
@ -305,6 +297,19 @@ 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.
|
||||||
|
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.
|
||||||
@ -318,6 +323,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> {
|
|||||||
) -> InterfaceAltBuilder<'_, 'd, D> {
|
) -> InterfaceAltBuilder<'_, 'd, D> {
|
||||||
let number = self.next_alt_setting_number;
|
let number = self.next_alt_setting_number;
|
||||||
self.next_alt_setting_number += 1;
|
self.next_alt_setting_number += 1;
|
||||||
|
self.builder.interfaces[self.interface_number.0 as usize].num_alt_settings += 1;
|
||||||
|
|
||||||
self.builder.config_descriptor.interface_alt(
|
self.builder.config_descriptor.interface_alt(
|
||||||
self.interface_number,
|
self.interface_number,
|
||||||
|
@ -2,7 +2,6 @@ use core::mem;
|
|||||||
|
|
||||||
use crate::descriptor::DescriptorWriter;
|
use crate::descriptor::DescriptorWriter;
|
||||||
use crate::driver::{self, EndpointError};
|
use crate::driver::{self, EndpointError};
|
||||||
use crate::DEFAULT_ALTERNATE_SETTING;
|
|
||||||
|
|
||||||
use super::types::*;
|
use super::types::*;
|
||||||
|
|
||||||
@ -150,6 +149,10 @@ pub trait ControlHandler {
|
|||||||
/// Called after a USB reset after the bus reset sequence is complete.
|
/// Called after a USB reset after the bus reset sequence is complete.
|
||||||
fn reset(&mut self) {}
|
fn reset(&mut self) {}
|
||||||
|
|
||||||
|
fn set_alternate_setting(&mut self, alternate_setting: u8) {
|
||||||
|
let _ = alternate_setting;
|
||||||
|
}
|
||||||
|
|
||||||
/// Called when a control request is received with direction HostToDevice.
|
/// Called when a control request is received with direction HostToDevice.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
@ -163,8 +166,8 @@ pub trait ControlHandler {
|
|||||||
|
|
||||||
/// Called when a control request is received with direction DeviceToHost.
|
/// Called when a control request is received with direction DeviceToHost.
|
||||||
///
|
///
|
||||||
/// You should write the response to `resp`, then return `InResponse::Accepted(len)`
|
/// You should write the response somewhere (usually to `buf`, but you may use another buffer
|
||||||
/// with the length of the response.
|
/// owned by yourself, or a static buffer), then return `InResponse::Accepted(data)`.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
@ -174,23 +177,31 @@ pub trait ControlHandler {
|
|||||||
InResponse::Rejected
|
InResponse::Rejected
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_interface(&mut self, alternate_setting: u16) -> OutResponse {
|
/// Called when a GET DESCRIPTOR control request is received on the interface.
|
||||||
if alternate_setting == u16::from(DEFAULT_ALTERNATE_SETTING) {
|
///
|
||||||
OutResponse::Accepted
|
/// You should write the response somewhere (usually to `buf`, but you may use another buffer
|
||||||
} else {
|
/// owned by yourself, or a static buffer), then return `InResponse::Accepted(data)`.
|
||||||
OutResponse::Rejected
|
///
|
||||||
}
|
/// # 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
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_interface<'a>(&'a mut self, buf: &'a mut [u8]) -> InResponse<'a> {
|
/// Called when a GET_DESCRIPTOR STRING control request is received.
|
||||||
buf[0] = DEFAULT_ALTERNATE_SETTING;
|
///
|
||||||
InResponse::Accepted(&buf[0..1])
|
/// 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>(
|
||||||
fn get_status<'a>(&'a mut self, buf: &'a mut [u8]) -> InResponse {
|
&'a mut self,
|
||||||
let status: u16 = 0;
|
index: StringIndex,
|
||||||
buf[0..2].copy_from_slice(&status.to_le_bytes());
|
lang_id: u16,
|
||||||
InResponse::Accepted(&buf[0..2])
|
buf: &'a mut [u8],
|
||||||
|
) -> Option<&'a str> {
|
||||||
|
let _ = (index, lang_id, buf);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::builder::Config;
|
use super::builder::Config;
|
||||||
use super::{types::*, CONFIGURATION_VALUE, DEFAULT_ALTERNATE_SETTING};
|
use super::{types::*, CONFIGURATION_VALUE};
|
||||||
|
|
||||||
/// Standard descriptor types
|
/// Standard descriptor types
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
@ -192,7 +192,7 @@ impl<'a> DescriptorWriter<'a> {
|
|||||||
interface_protocol: u8,
|
interface_protocol: u8,
|
||||||
interface_string: Option<StringIndex>,
|
interface_string: Option<StringIndex>,
|
||||||
) {
|
) {
|
||||||
if alternate_setting == DEFAULT_ALTERNATE_SETTING {
|
if alternate_setting == 0 {
|
||||||
match self.num_interfaces_mark {
|
match self.num_interfaces_mark {
|
||||||
Some(mark) => self.buf[mark] += 1,
|
Some(mark) => self.buf[mark] += 1,
|
||||||
None => {
|
None => {
|
||||||
|
110
embassy-usb/src/descriptor_reader.rs
Normal file
110
embassy-usb/src/descriptor_reader.rs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
use crate::descriptor::descriptor_type;
|
||||||
|
use crate::types::EndpointAddress;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct ReadError;
|
||||||
|
|
||||||
|
pub struct Reader<'a> {
|
||||||
|
data: &'a [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Reader<'a> {
|
||||||
|
pub fn new(data: &'a [u8]) -> Self {
|
||||||
|
Self { data }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eof(&self) -> bool {
|
||||||
|
self.data.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read<const N: usize>(&mut self) -> Result<[u8; N], ReadError> {
|
||||||
|
let n = self.data.get(0..N).ok_or(ReadError)?;
|
||||||
|
self.data = &self.data[N..];
|
||||||
|
Ok(n.try_into().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_u8(&mut self) -> Result<u8, ReadError> {
|
||||||
|
Ok(u8::from_le_bytes(self.read()?))
|
||||||
|
}
|
||||||
|
pub fn read_u16(&mut self) -> Result<u16, ReadError> {
|
||||||
|
Ok(u16::from_le_bytes(self.read()?))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_slice(&mut self, len: usize) -> Result<&'a [u8], ReadError> {
|
||||||
|
let res = self.data.get(0..len).ok_or(ReadError)?;
|
||||||
|
self.data = &self.data[len..];
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_descriptors(&mut self) -> DescriptorIter<'_, 'a> {
|
||||||
|
DescriptorIter { r: self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DescriptorIter<'a, 'b> {
|
||||||
|
r: &'a mut Reader<'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Iterator for DescriptorIter<'a, 'b> {
|
||||||
|
type Item = Result<(u8, Reader<'a>), ReadError>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.r.eof() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let len = match self.r.read_u8() {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => return Some(Err(e)),
|
||||||
|
};
|
||||||
|
let type_ = match self.r.read_u8() {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => return Some(Err(e)),
|
||||||
|
};
|
||||||
|
let data = match self.r.read_slice(len as usize - 2) {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => return Some(Err(e)),
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(Ok((type_, Reader::new(data))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct EndpointInfo {
|
||||||
|
pub configuration: u8,
|
||||||
|
pub interface: u8,
|
||||||
|
pub interface_alt: u8,
|
||||||
|
pub ep_address: EndpointAddress,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn foreach_endpoint(data: &[u8], mut f: impl FnMut(EndpointInfo)) -> Result<(), ReadError> {
|
||||||
|
let mut ep = EndpointInfo {
|
||||||
|
configuration: 0,
|
||||||
|
interface: 0,
|
||||||
|
interface_alt: 0,
|
||||||
|
ep_address: EndpointAddress::from(0),
|
||||||
|
};
|
||||||
|
for res in Reader::new(data).read_descriptors() {
|
||||||
|
let (kind, mut r) = res?;
|
||||||
|
match kind {
|
||||||
|
descriptor_type::CONFIGURATION => {
|
||||||
|
let _total_length = r.read_u16()?;
|
||||||
|
let _total_length = r.read_u8()?;
|
||||||
|
ep.configuration = r.read_u8()?;
|
||||||
|
}
|
||||||
|
descriptor_type::INTERFACE => {
|
||||||
|
ep.interface = r.read_u8()?;
|
||||||
|
ep.interface_alt = r.read_u8()?;
|
||||||
|
}
|
||||||
|
descriptor_type::ENDPOINT => {
|
||||||
|
ep.ep_address = EndpointAddress::from(r.read_u8()?);
|
||||||
|
f(ep)
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -79,17 +79,17 @@ pub trait Bus {
|
|||||||
fn poll<'a>(&'a mut self) -> Self::PollFuture<'a>;
|
fn poll<'a>(&'a mut self) -> Self::PollFuture<'a>;
|
||||||
|
|
||||||
/// Sets the device USB address to `addr`.
|
/// Sets the device USB address to `addr`.
|
||||||
fn set_device_address(&mut self, addr: u8);
|
fn set_address(&mut self, addr: u8);
|
||||||
|
|
||||||
/// Sets the device configured state.
|
/// Enables or disables an endpoint.
|
||||||
fn set_configured(&mut self, configured: bool);
|
fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool);
|
||||||
|
|
||||||
/// Sets or clears the STALL condition for an endpoint. If the endpoint is an OUT endpoint, it
|
/// Sets or clears the STALL condition for an endpoint. If the endpoint is an OUT endpoint, it
|
||||||
/// should be prepared to receive data again. Only used during control transfers.
|
/// should be prepared to receive data again. Only used during control transfers.
|
||||||
fn set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool);
|
fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool);
|
||||||
|
|
||||||
/// Gets whether the STALL condition is set for an endpoint. Only used during control transfers.
|
/// Gets whether the STALL condition is set for an endpoint. Only used during control transfers.
|
||||||
fn is_stalled(&mut self, ep_addr: EndpointAddress) -> bool;
|
fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool;
|
||||||
|
|
||||||
/// Simulates a disconnect from the USB bus, causing the host to reset and re-enumerate the
|
/// Simulates a disconnect from the USB bus, causing the host to reset and re-enumerate the
|
||||||
/// device.
|
/// device.
|
||||||
|
@ -8,12 +8,15 @@ pub(crate) mod fmt;
|
|||||||
mod builder;
|
mod builder;
|
||||||
pub mod control;
|
pub mod control;
|
||||||
pub mod descriptor;
|
pub mod descriptor;
|
||||||
|
mod descriptor_reader;
|
||||||
pub mod driver;
|
pub mod driver;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
use embassy::util::{select, Either};
|
use embassy::util::{select, Either};
|
||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
|
|
||||||
|
use crate::descriptor_reader::foreach_endpoint;
|
||||||
|
|
||||||
use self::control::*;
|
use self::control::*;
|
||||||
use self::descriptor::*;
|
use self::descriptor::*;
|
||||||
use self::driver::{Bus, Driver, Event};
|
use self::driver::{Bus, Driver, Event};
|
||||||
@ -61,11 +64,13 @@ pub const CONFIGURATION_NONE: u8 = 0;
|
|||||||
/// The bConfiguration value for the single configuration supported by this device.
|
/// The bConfiguration value for the single configuration supported by this device.
|
||||||
pub const CONFIGURATION_VALUE: u8 = 1;
|
pub const CONFIGURATION_VALUE: u8 = 1;
|
||||||
|
|
||||||
/// The default value for bAlternateSetting for all interfaces.
|
|
||||||
pub const DEFAULT_ALTERNATE_SETTING: u8 = 0;
|
|
||||||
|
|
||||||
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.
|
||||||
@ -87,6 +92,13 @@ pub trait DeviceStateHandler {
|
|||||||
fn remote_wakeup_enabled(&self, _enabled: bool) {}
|
fn remote_wakeup_enabled(&self, _enabled: bool) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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>> {
|
pub struct UsbDevice<'d, D: Driver<'d>> {
|
||||||
bus: D::Bus,
|
bus: D::Bus,
|
||||||
handler: Option<&'d dyn DeviceStateHandler>,
|
handler: Option<&'d dyn DeviceStateHandler>,
|
||||||
@ -104,7 +116,7 @@ pub struct UsbDevice<'d, D: Driver<'d>> {
|
|||||||
self_powered: bool,
|
self_powered: bool,
|
||||||
pending_address: u8,
|
pending_address: u8,
|
||||||
|
|
||||||
interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>,
|
interfaces: Vec<Interface<'d>, MAX_INTERFACE_COUNT>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
||||||
@ -115,7 +127,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
|||||||
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<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>,
|
interfaces: Vec<Interface<'d>, MAX_INTERFACE_COUNT>,
|
||||||
control_buf: &'d mut [u8],
|
control_buf: &'d mut [u8],
|
||||||
) -> UsbDevice<'d, D> {
|
) -> UsbDevice<'d, D> {
|
||||||
let control = driver
|
let control = driver
|
||||||
@ -247,8 +259,12 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
|||||||
self.remote_wakeup_enabled = false;
|
self.remote_wakeup_enabled = false;
|
||||||
self.pending_address = 0;
|
self.pending_address = 0;
|
||||||
|
|
||||||
for (_, h) in self.interfaces.iter_mut() {
|
for iface in self.interfaces.iter_mut() {
|
||||||
h.reset();
|
iface.current_alt_setting = 0;
|
||||||
|
if let Some(h) = &mut iface.handler {
|
||||||
|
h.reset();
|
||||||
|
h.set_alternate_setting(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(h) = &self.handler {
|
if let Some(h) = &self.handler {
|
||||||
@ -302,7 +318,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
|||||||
}
|
}
|
||||||
(Request::SET_ADDRESS, addr @ 1..=127) => {
|
(Request::SET_ADDRESS, addr @ 1..=127) => {
|
||||||
self.pending_address = addr as u8;
|
self.pending_address = addr as u8;
|
||||||
self.bus.set_device_address(self.pending_address);
|
self.bus.set_address(self.pending_address);
|
||||||
self.device_state = UsbDeviceState::Addressed;
|
self.device_state = UsbDeviceState::Addressed;
|
||||||
if let Some(h) = &self.handler {
|
if let Some(h) = &self.handler {
|
||||||
h.addressed(self.pending_address);
|
h.addressed(self.pending_address);
|
||||||
@ -310,59 +326,110 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
|||||||
self.control.accept(stage)
|
self.control.accept(stage)
|
||||||
}
|
}
|
||||||
(Request::SET_CONFIGURATION, CONFIGURATION_VALUE_U16) => {
|
(Request::SET_CONFIGURATION, CONFIGURATION_VALUE_U16) => {
|
||||||
|
debug!("SET_CONFIGURATION: configured");
|
||||||
self.device_state = UsbDeviceState::Configured;
|
self.device_state = UsbDeviceState::Configured;
|
||||||
self.bus.set_configured(true);
|
|
||||||
|
// Enable all endpoints of selected alt settings.
|
||||||
|
foreach_endpoint(self.config_descriptor, |ep| {
|
||||||
|
let iface = &self.interfaces[ep.interface as usize];
|
||||||
|
self.bus.endpoint_set_enabled(
|
||||||
|
ep.ep_address,
|
||||||
|
iface.current_alt_setting == ep.interface_alt,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Notify handler.
|
||||||
if let Some(h) = &self.handler {
|
if let Some(h) = &self.handler {
|
||||||
h.configured(true);
|
h.configured(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.control.accept(stage)
|
self.control.accept(stage)
|
||||||
}
|
}
|
||||||
(Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => match self.device_state {
|
(Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => match self.device_state {
|
||||||
UsbDeviceState::Default => self.control.accept(stage),
|
UsbDeviceState::Default => self.control.accept(stage),
|
||||||
_ => {
|
_ => {
|
||||||
|
debug!("SET_CONFIGURATION: unconfigured");
|
||||||
self.device_state = UsbDeviceState::Addressed;
|
self.device_state = UsbDeviceState::Addressed;
|
||||||
self.bus.set_configured(false);
|
|
||||||
|
// Disable all endpoints.
|
||||||
|
foreach_endpoint(self.config_descriptor, |ep| {
|
||||||
|
self.bus.endpoint_set_enabled(ep.ep_address, false);
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Notify handler.
|
||||||
if let Some(h) = &self.handler {
|
if let Some(h) = &self.handler {
|
||||||
h.configured(false);
|
h.configured(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.control.accept(stage)
|
self.control.accept(stage)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => self.control.reject(),
|
_ => self.control.reject(),
|
||||||
},
|
},
|
||||||
|
(RequestType::Standard, Recipient::Interface) => {
|
||||||
|
let iface = match self.interfaces.get_mut(req.index as usize) {
|
||||||
|
Some(iface) => iface,
|
||||||
|
None => return self.control.reject(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match req.request {
|
||||||
|
Request::SET_INTERFACE => {
|
||||||
|
let new_altsetting = req.value as u8;
|
||||||
|
|
||||||
|
if new_altsetting >= iface.num_alt_settings {
|
||||||
|
warn!("SET_INTERFACE: trying to select alt setting out of range.");
|
||||||
|
return self.control.reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
iface.current_alt_setting = new_altsetting;
|
||||||
|
|
||||||
|
// Enable/disable EPs of this interface as needed.
|
||||||
|
foreach_endpoint(self.config_descriptor, |ep| {
|
||||||
|
if ep.interface == req.index as u8 {
|
||||||
|
self.bus.endpoint_set_enabled(
|
||||||
|
ep.ep_address,
|
||||||
|
iface.current_alt_setting == ep.interface_alt,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// TODO check it is valid (not out of range)
|
||||||
|
// TODO actually enable/disable endpoints.
|
||||||
|
|
||||||
|
if let Some(handler) = &mut iface.handler {
|
||||||
|
handler.set_alternate_setting(new_altsetting);
|
||||||
|
}
|
||||||
|
self.control.accept(stage)
|
||||||
|
}
|
||||||
|
_ => self.control.reject(),
|
||||||
|
}
|
||||||
|
}
|
||||||
(RequestType::Standard, Recipient::Endpoint) => match (req.request, req.value) {
|
(RequestType::Standard, Recipient::Endpoint) => match (req.request, req.value) {
|
||||||
(Request::SET_FEATURE, Request::FEATURE_ENDPOINT_HALT) => {
|
(Request::SET_FEATURE, Request::FEATURE_ENDPOINT_HALT) => {
|
||||||
let ep_addr = ((req.index as u8) & 0x8f).into();
|
let ep_addr = ((req.index as u8) & 0x8f).into();
|
||||||
self.bus.set_stalled(ep_addr, true);
|
self.bus.endpoint_set_stalled(ep_addr, true);
|
||||||
self.control.accept(stage)
|
self.control.accept(stage)
|
||||||
}
|
}
|
||||||
(Request::CLEAR_FEATURE, Request::FEATURE_ENDPOINT_HALT) => {
|
(Request::CLEAR_FEATURE, Request::FEATURE_ENDPOINT_HALT) => {
|
||||||
let ep_addr = ((req.index as u8) & 0x8f).into();
|
let ep_addr = ((req.index as u8) & 0x8f).into();
|
||||||
self.bus.set_stalled(ep_addr, false);
|
self.bus.endpoint_set_stalled(ep_addr, false);
|
||||||
self.control.accept(stage)
|
self.control.accept(stage)
|
||||||
}
|
}
|
||||||
_ => self.control.reject(),
|
_ => self.control.reject(),
|
||||||
},
|
},
|
||||||
(_, Recipient::Interface) => {
|
(RequestType::Class, Recipient::Interface) => {
|
||||||
let handler = self
|
let iface = match self.interfaces.get_mut(req.index as usize) {
|
||||||
.interfaces
|
Some(iface) => iface,
|
||||||
.iter_mut()
|
None => return self.control.reject(),
|
||||||
.find(|(i, _)| req.index == *i as _)
|
};
|
||||||
.map(|(_, h)| h);
|
match &mut iface.handler {
|
||||||
|
Some(handler) => match handler.control_out(req, data) {
|
||||||
match handler {
|
OutResponse::Accepted => self.control.accept(stage),
|
||||||
Some(handler) => {
|
OutResponse::Rejected => self.control.reject(),
|
||||||
let response = match (req.request_type, req.request) {
|
},
|
||||||
(RequestType::Standard, Request::SET_INTERFACE) => {
|
|
||||||
handler.set_interface(req.value)
|
|
||||||
}
|
|
||||||
_ => handler.control_out(req, data),
|
|
||||||
};
|
|
||||||
match response {
|
|
||||||
OutResponse::Accepted => self.control.accept(stage),
|
|
||||||
OutResponse::Rejected => self.control.reject(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => self.control.reject(),
|
None => self.control.reject(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -406,41 +473,54 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
|||||||
}
|
}
|
||||||
_ => self.control.reject(),
|
_ => self.control.reject(),
|
||||||
},
|
},
|
||||||
|
(RequestType::Standard, Recipient::Interface) => {
|
||||||
|
let iface = match self.interfaces.get_mut(req.index as usize) {
|
||||||
|
Some(iface) => iface,
|
||||||
|
None => return self.control.reject(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match req.request {
|
||||||
|
Request::GET_STATUS => {
|
||||||
|
let status: u16 = 0;
|
||||||
|
self.control.accept_in(&status.to_le_bytes(), stage).await
|
||||||
|
}
|
||||||
|
Request::GET_INTERFACE => {
|
||||||
|
self.control
|
||||||
|
.accept_in(&[iface.current_alt_setting], stage)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
Request::GET_DESCRIPTOR => match &mut iface.handler {
|
||||||
|
Some(handler) => match handler.get_descriptor(req, self.control_buf) {
|
||||||
|
InResponse::Accepted(data) => self.control.accept_in(data, stage).await,
|
||||||
|
InResponse::Rejected => self.control.reject(),
|
||||||
|
},
|
||||||
|
None => self.control.reject(),
|
||||||
|
},
|
||||||
|
_ => self.control.reject(),
|
||||||
|
}
|
||||||
|
}
|
||||||
(RequestType::Standard, Recipient::Endpoint) => match req.request {
|
(RequestType::Standard, Recipient::Endpoint) => match req.request {
|
||||||
Request::GET_STATUS => {
|
Request::GET_STATUS => {
|
||||||
let ep_addr: EndpointAddress = ((req.index as u8) & 0x8f).into();
|
let ep_addr: EndpointAddress = ((req.index as u8) & 0x8f).into();
|
||||||
let mut status: u16 = 0x0000;
|
let mut status: u16 = 0x0000;
|
||||||
if self.bus.is_stalled(ep_addr) {
|
if self.bus.endpoint_is_stalled(ep_addr) {
|
||||||
status |= 0x0001;
|
status |= 0x0001;
|
||||||
}
|
}
|
||||||
self.control.accept_in(&status.to_le_bytes(), stage).await
|
self.control.accept_in(&status.to_le_bytes(), stage).await
|
||||||
}
|
}
|
||||||
_ => self.control.reject(),
|
_ => self.control.reject(),
|
||||||
},
|
},
|
||||||
(_, Recipient::Interface) => {
|
(RequestType::Class, Recipient::Interface) => {
|
||||||
let handler = self
|
let iface = match self.interfaces.get_mut(req.index as usize) {
|
||||||
.interfaces
|
Some(iface) => iface,
|
||||||
.iter_mut()
|
None => return self.control.reject(),
|
||||||
.find(|(i, _)| req.index == *i as _)
|
};
|
||||||
.map(|(_, h)| h);
|
|
||||||
|
|
||||||
match handler {
|
match &mut iface.handler {
|
||||||
Some(handler) => {
|
Some(handler) => match handler.control_in(req, self.control_buf) {
|
||||||
let response = match (req.request_type, req.request) {
|
InResponse::Accepted(data) => self.control.accept_in(data, stage).await,
|
||||||
(RequestType::Standard, Request::GET_STATUS) => {
|
InResponse::Rejected => self.control.reject(),
|
||||||
handler.get_status(self.control_buf)
|
},
|
||||||
}
|
|
||||||
(RequestType::Standard, Request::GET_INTERFACE) => {
|
|
||||||
handler.get_interface(self.control_buf)
|
|
||||||
}
|
|
||||||
_ => handler.control_in(req, self.control_buf),
|
|
||||||
};
|
|
||||||
|
|
||||||
match response {
|
|
||||||
InResponse::Accepted(data) => self.control.accept_in(data, stage).await,
|
|
||||||
InResponse::Rejected => self.control.reject(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => self.control.reject(),
|
None => self.control.reject(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -466,14 +546,34 @@ 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;
|
||||||
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ pub struct EndpointInfo {
|
|||||||
/// 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(Copy, Clone, Eq, PartialEq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct InterfaceNumber(u8);
|
pub struct InterfaceNumber(pub(crate) u8);
|
||||||
|
|
||||||
impl InterfaceNumber {
|
impl InterfaceNumber {
|
||||||
pub(crate) fn new(index: u8) -> InterfaceNumber {
|
pub(crate) fn new(index: u8) -> InterfaceNumber {
|
||||||
|
Loading…
Reference in New Issue
Block a user