Skip to content

Commit 092c2b7

Browse files
committed
usb: builtin handling of interface alternate settings
The stack reads its own descriptors to figure out which endpoints are used in which alt settings, and enables/disables them as needed. The ControlHandler has a callback so it can get notified of alternate setting changes, which is purely informative (it doesn't have to do anything).
1 parent ea0a701 commit 092c2b7

File tree

9 files changed

+358
-147
lines changed

9 files changed

+358
-147
lines changed

embassy-nrf/src/usb.rs

Lines changed: 67 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -194,16 +194,12 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
194194
fn into_bus(self) -> Self::Bus {
195195
Bus {
196196
phantom: PhantomData,
197-
alloc_in: self.alloc_in,
198-
alloc_out: self.alloc_out,
199197
}
200198
}
201199
}
202200

203201
pub struct Bus<'d, T: Instance> {
204202
phantom: PhantomData<&'d mut T>,
205-
alloc_in: Allocator,
206-
alloc_out: Allocator,
207203
}
208204

209205
impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
@@ -264,7 +260,16 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
264260
if regs.events_usbreset.read().bits() != 0 {
265261
regs.events_usbreset.reset();
266262
regs.intenset.write(|w| w.usbreset().set());
267-
self.set_configured(false);
263+
264+
// Disable all endpoints except EP0
265+
regs.epinen.write(|w| unsafe { w.bits(0x01) });
266+
regs.epouten.write(|w| unsafe { w.bits(0x01) });
267+
READY_ENDPOINTS.store(In::mask(0), Ordering::Release);
268+
for i in 1..=7 {
269+
In::waker(i).wake();
270+
Out::waker(i).wake();
271+
}
272+
268273
return Poll::Ready(Event::Reset);
269274
}
270275

@@ -297,57 +302,76 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
297302
}
298303

299304
#[inline]
300-
fn set_configured(&mut self, configured: bool) {
305+
fn set_address(&mut self, _addr: u8) {
306+
// Nothing to do, the peripheral handles this.
307+
}
308+
309+
fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
310+
Driver::<T>::set_stalled(ep_addr, stalled)
311+
}
312+
313+
fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
314+
Driver::<T>::is_stalled(ep_addr)
315+
}
316+
317+
fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) {
301318
let regs = T::regs();
302319

303-
unsafe {
304-
if configured {
305-
// TODO: Initialize ISO buffers
320+
let i = ep_addr.index();
321+
let mask = 1 << i;
306322

307-
regs.epinen.write(|w| w.bits(self.alloc_in.used.into()));
308-
regs.epouten.write(|w| w.bits(self.alloc_out.used.into()));
323+
debug!("endpoint_set_enabled {:?} {}", ep_addr, enabled);
309324

310-
for i in 1..8 {
311-
let out_enabled = self.alloc_out.used & (1 << i) != 0;
325+
match ep_addr.direction() {
326+
UsbDirection::In => {
327+
let mut was_enabled = false;
328+
regs.epinen.modify(|r, w| {
329+
let mut bits = r.bits();
330+
was_enabled = (bits & mask) != 0;
331+
if enabled {
332+
bits |= mask
333+
} else {
334+
bits &= !mask
335+
}
336+
unsafe { w.bits(bits) }
337+
});
312338

339+
let ready_mask = In::mask(i);
340+
if enabled {
341+
if !was_enabled {
342+
READY_ENDPOINTS.fetch_or(ready_mask, Ordering::AcqRel);
343+
}
344+
} else {
345+
READY_ENDPOINTS.fetch_and(!ready_mask, Ordering::AcqRel);
346+
}
347+
348+
In::waker(i).wake();
349+
}
350+
UsbDirection::Out => {
351+
regs.epouten.modify(|r, w| {
352+
let mut bits = r.bits();
353+
if enabled {
354+
bits |= mask
355+
} else {
356+
bits &= !mask
357+
}
358+
unsafe { w.bits(bits) }
359+
});
360+
361+
let ready_mask = Out::mask(i);
362+
if enabled {
313363
// when first enabled, bulk/interrupt OUT endpoints will *not* receive data (the
314364
// peripheral will NAK all incoming packets) until we write a zero to the SIZE
315365
// register (see figure 203 of the 52840 manual). To avoid that we write a 0 to the
316366
// SIZE register
317-
if out_enabled {
318-
regs.size.epout[i].reset();
319-
}
367+
regs.size.epout[i].reset();
368+
} else {
369+
READY_ENDPOINTS.fetch_and(!ready_mask, Ordering::AcqRel);
320370
}
321371

322-
// IN endpoints (low bits) default to ready.
323-
// OUT endpoints (high bits) default to NOT ready, they become ready when data comes in.
324-
READY_ENDPOINTS.store(0x0000FFFF, Ordering::Release);
325-
} else {
326-
// Disable all endpoints except EP0
327-
regs.epinen.write(|w| w.bits(0x01));
328-
regs.epouten.write(|w| w.bits(0x01));
329-
330-
READY_ENDPOINTS.store(In::mask(0), Ordering::Release);
372+
Out::waker(i).wake();
331373
}
332374
}
333-
334-
for i in 1..=7 {
335-
In::waker(i).wake();
336-
Out::waker(i).wake();
337-
}
338-
}
339-
340-
#[inline]
341-
fn set_device_address(&mut self, _addr: u8) {
342-
// Nothing to do, the peripheral handles this.
343-
}
344-
345-
fn set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
346-
Driver::<T>::set_stalled(ep_addr, stalled)
347-
}
348-
349-
fn is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
350-
Driver::<T>::is_stalled(ep_addr)
351375
}
352376

353377
#[inline]

embassy-usb-hid/src/lib.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,14 @@ impl<'d> ControlHandler for Control<'d> {
438438
self.out_report_offset.store(0, Ordering::Release);
439439
}
440440

441+
fn get_descriptor<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
442+
match (req.value >> 8) as u8 {
443+
HID_DESC_DESCTYPE_HID_REPORT => InResponse::Accepted(self.report_descriptor),
444+
HID_DESC_DESCTYPE_HID => InResponse::Accepted(&self.hid_descriptor),
445+
_ => InResponse::Rejected,
446+
}
447+
}
448+
441449
fn control_out(&mut self, req: embassy_usb::control::Request, data: &[u8]) -> OutResponse {
442450
trace!("HID control_out {:?} {=[u8]:x}", req, data);
443451
if let RequestType::Class = req.request_type {
@@ -477,13 +485,8 @@ impl<'d> ControlHandler for Control<'d> {
477485

478486
fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
479487
trace!("HID control_in {:?}", req);
480-
match (req.request_type, req.request) {
481-
(RequestType::Standard, Request::GET_DESCRIPTOR) => match (req.value >> 8) as u8 {
482-
HID_DESC_DESCTYPE_HID_REPORT => InResponse::Accepted(self.report_descriptor),
483-
HID_DESC_DESCTYPE_HID => InResponse::Accepted(&self.hid_descriptor),
484-
_ => InResponse::Rejected,
485-
},
486-
(RequestType::Class, HID_REQ_GET_REPORT) => {
488+
match req.request {
489+
HID_REQ_GET_REPORT => {
487490
let size = match ReportId::try_from(req.value) {
488491
Ok(id) => self.request_handler.and_then(|x| x.get_report(id, buf)),
489492
Err(_) => None,
@@ -495,7 +498,7 @@ impl<'d> ControlHandler for Control<'d> {
495498
InResponse::Rejected
496499
}
497500
}
498-
(RequestType::Class, HID_REQ_GET_IDLE) => {
501+
HID_REQ_GET_IDLE => {
499502
if let Some(handler) = self.request_handler {
500503
let id = req.value as u8;
501504
let id = (id != 0).then(|| ReportId::In(id));
@@ -510,7 +513,7 @@ impl<'d> ControlHandler for Control<'d> {
510513
InResponse::Rejected
511514
}
512515
}
513-
(RequestType::Class, HID_REQ_GET_PROTOCOL) => {
516+
HID_REQ_GET_PROTOCOL => {
514517
// UNSUPPORTED: Boot Protocol
515518
buf[0] = 1;
516519
InResponse::Accepted(&buf[0..1])

embassy-usb/src/builder.rs

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

3+
use crate::Interface;
4+
35
use super::control::ControlHandler;
46
use super::descriptor::{BosWriter, DescriptorWriter};
57
use super::driver::{Driver, Endpoint};
@@ -121,11 +123,10 @@ impl<'a> Config<'a> {
121123
pub struct Builder<'d, D: Driver<'d>> {
122124
config: Config<'d>,
123125
handler: Option<&'d dyn DeviceStateHandler>,
124-
interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>,
126+
interfaces: Vec<Interface<'d>, MAX_INTERFACE_COUNT>,
125127
control_buf: &'d mut [u8],
126128

127129
driver: D,
128-
next_interface_number: u8,
129130
next_string_index: u8,
130131

131132
device_descriptor: DescriptorWriter<'d>,
@@ -180,7 +181,6 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
180181
config,
181182
interfaces: Vec::new(),
182183
control_buf,
183-
next_interface_number: 0,
184184
next_string_index: 4,
185185

186186
device_descriptor,
@@ -234,7 +234,7 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
234234
) -> FunctionBuilder<'_, 'd, D> {
235235
let iface_count_index = if self.config.composite_with_iads {
236236
self.config_descriptor.iad(
237-
InterfaceNumber::new(self.next_interface_number),
237+
InterfaceNumber::new(self.interfaces.len() as _),
238238
0,
239239
class,
240240
subclass,
@@ -275,13 +275,15 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
275275
self.builder.config_descriptor.buf[i] += 1;
276276
}
277277

278-
let number = self.builder.next_interface_number;
279-
self.builder.next_interface_number += 1;
278+
let number = self.builder.interfaces.len() as _;
279+
let iface = Interface {
280+
handler,
281+
current_alt_setting: 0,
282+
num_alt_settings: 0,
283+
};
280284

281-
if let Some(handler) = handler {
282-
if self.builder.interfaces.push((number, handler)).is_err() {
283-
panic!("max interface count reached")
284-
}
285+
if self.builder.interfaces.push(iface).is_err() {
286+
panic!("max interface count reached")
285287
}
286288

287289
InterfaceBuilder {
@@ -318,6 +320,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> {
318320
) -> InterfaceAltBuilder<'_, 'd, D> {
319321
let number = self.next_alt_setting_number;
320322
self.next_alt_setting_number += 1;
323+
self.builder.interfaces[self.interface_number.0 as usize].num_alt_settings += 1;
321324

322325
self.builder.config_descriptor.interface_alt(
323326
self.interface_number,

embassy-usb/src/control.rs

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use core::mem;
22

33
use crate::descriptor::DescriptorWriter;
44
use crate::driver::{self, EndpointError};
5-
use crate::DEFAULT_ALTERNATE_SETTING;
65

76
use super::types::*;
87

@@ -150,6 +149,10 @@ pub trait ControlHandler {
150149
/// Called after a USB reset after the bus reset sequence is complete.
151150
fn reset(&mut self) {}
152151

152+
fn set_alternate_setting(&mut self, alternate_setting: u8) {
153+
let _ = alternate_setting;
154+
}
155+
153156
/// Called when a control request is received with direction HostToDevice.
154157
///
155158
/// # Arguments
@@ -163,8 +166,8 @@ pub trait ControlHandler {
163166

164167
/// Called when a control request is received with direction DeviceToHost.
165168
///
166-
/// You should write the response to `resp`, then return `InResponse::Accepted(len)`
167-
/// with the length of the response.
169+
/// You should write the response somewhere (usually to `buf`, but you may use another buffer
170+
/// owned by yourself, or a static buffer), then return `InResponse::Accepted(data)`.
168171
///
169172
/// # Arguments
170173
///
@@ -174,23 +177,17 @@ pub trait ControlHandler {
174177
InResponse::Rejected
175178
}
176179

177-
fn set_interface(&mut self, alternate_setting: u16) -> OutResponse {
178-
if alternate_setting == u16::from(DEFAULT_ALTERNATE_SETTING) {
179-
OutResponse::Accepted
180-
} else {
181-
OutResponse::Rejected
182-
}
183-
}
184-
185-
fn get_interface<'a>(&'a mut self, buf: &'a mut [u8]) -> InResponse<'a> {
186-
buf[0] = DEFAULT_ALTERNATE_SETTING;
187-
InResponse::Accepted(&buf[0..1])
188-
}
189-
190-
fn get_status<'a>(&'a mut self, buf: &'a mut [u8]) -> InResponse {
191-
let status: u16 = 0;
192-
buf[0..2].copy_from_slice(&status.to_le_bytes());
193-
InResponse::Accepted(&buf[0..2])
180+
/// Called when a GET DESCRIPTOR control request is received on the interface.
181+
///
182+
/// You should write the response somewhere (usually to `buf`, but you may use another buffer
183+
/// owned by yourself, or a static buffer), then return `InResponse::Accepted(data)`.
184+
///
185+
/// # Arguments
186+
///
187+
/// * `req` - The request from the SETUP packet.
188+
fn get_descriptor<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
189+
let _ = (req, buf);
190+
InResponse::Rejected
194191
}
195192
}
196193

embassy-usb/src/descriptor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::builder::Config;
2-
use super::{types::*, CONFIGURATION_VALUE, DEFAULT_ALTERNATE_SETTING};
2+
use super::{types::*, CONFIGURATION_VALUE};
33

44
/// Standard descriptor types
55
#[allow(missing_docs)]
@@ -192,7 +192,7 @@ impl<'a> DescriptorWriter<'a> {
192192
interface_protocol: u8,
193193
interface_string: Option<StringIndex>,
194194
) {
195-
if alternate_setting == DEFAULT_ALTERNATE_SETTING {
195+
if alternate_setting == 0 {
196196
match self.num_interfaces_mark {
197197
Some(mark) => self.buf[mark] += 1,
198198
None => {

0 commit comments

Comments
 (0)