usb: associate ControlHandlers with interfaces, automatically route requests.

This commit is contained in:
Dario Nieuwenhuis
2022-03-28 03:19:07 +02:00
parent 3412e5dc4a
commit 15cc97d794
4 changed files with 94 additions and 109 deletions

View File

@ -3,7 +3,7 @@ use core::mem::{self, MaybeUninit};
use core::sync::atomic::{AtomicBool, Ordering};
use defmt::info;
use embassy::blocking_mutex::CriticalSectionMutex;
use embassy_usb::class::{ControlInRequestStatus, RequestStatus, UsbClass};
use embassy_usb::class::{ControlHandler, ControlInRequestStatus, RequestStatus};
use embassy_usb::control::{self, Request};
use embassy_usb::driver::{Endpoint, EndpointIn, EndpointOut, ReadError, WriteError};
use embassy_usb::{driver::Driver, types::*, UsbDeviceBuilder};
@ -64,7 +64,6 @@ pub struct CdcAcmClass<'d, D: Driver<'d>> {
}
struct Control {
comm_if: InterfaceNumber,
shared: UnsafeCell<ControlShared>,
}
@ -80,7 +79,7 @@ impl Control {
unsafe { &*(self.shared.get() as *const _) }
}
}
impl UsbClass for Control {
impl ControlHandler for Control {
fn reset(&mut self) {
let shared = self.shared();
shared.line_coding.lock(|x| x.set(LineCoding::default()));
@ -89,13 +88,6 @@ impl UsbClass for Control {
}
fn control_out(&mut self, req: control::Request, data: &[u8]) -> RequestStatus {
if !(req.request_type == control::RequestType::Class
&& req.recipient == control::Recipient::Interface
&& req.index == u8::from(self.comm_if) as u16)
{
return RequestStatus::Unhandled;
}
match req.request {
REQ_SEND_ENCAPSULATED_COMMAND => {
// We don't actually support encapsulated commands but pretend we do for standards
@ -134,13 +126,6 @@ impl UsbClass for Control {
req: Request,
control: embassy_usb::class::ControlIn<'a>,
) -> ControlInRequestStatus<'a> {
if !(req.request_type == control::RequestType::Class
&& req.recipient == control::Recipient::Interface
&& req.index == u8::from(self.comm_if) as u16)
{
return control.ignore();
}
match req.request {
// REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below.
REQ_GET_LINE_CODING if req.length == 7 => {
@ -166,7 +151,22 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
state: &'d mut State,
max_packet_size: u16,
) -> Self {
let comm_if = builder.alloc_interface();
let control = state.control.write(Control {
shared: UnsafeCell::new(ControlShared {
dtr: AtomicBool::new(false),
rts: AtomicBool::new(false),
line_coding: CriticalSectionMutex::new(Cell::new(LineCoding {
stop_bits: StopBits::One,
data_bits: 8,
parity_type: ParityType::None,
data_rate: 8_000,
})),
}),
});
let control_shared = unsafe { &*(control.shared.get() as *const _) };
let comm_if = builder.alloc_interface_with_handler(control);
let comm_ep = builder.alloc_interrupt_endpoint_in(8, 255);
let data_if = builder.alloc_interface();
let read_ep = builder.alloc_bulk_endpoint_out(max_packet_size);
@ -245,23 +245,6 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
builder.config_descriptor.endpoint(write_ep.info()).unwrap();
builder.config_descriptor.endpoint(read_ep.info()).unwrap();
let control = state.control.write(Control {
comm_if,
shared: UnsafeCell::new(ControlShared {
dtr: AtomicBool::new(false),
rts: AtomicBool::new(false),
line_coding: CriticalSectionMutex::new(Cell::new(LineCoding {
stop_bits: StopBits::One,
data_bits: 8,
parity_type: ParityType::None,
data_rate: 8_000,
})),
}),
});
let control_shared = unsafe { &*(control.shared.get() as *const _) };
builder.add_class(control);
CdcAcmClass {
comm_ep,
data_if,