Skip to content

Commit 136b00e

Browse files
committed
Implement alternate setting selection
1 parent b6037b0 commit 136b00e

File tree

4 files changed

+64
-9
lines changed

4 files changed

+64
-9
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "usb-device"
33
description = "Experimental device-side USB stack for embedded devices."
4-
version = "0.2.8"
4+
version = "0.2.9"
55
edition = "2018"
66
readme = "README.md"
77
keywords = ["no-std", "embedded", "usb"]

src/bus.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ impl<B: UsbBus> UsbBusAllocator<B> {
281281

282282
/// A handle for a USB interface that contains its number.
283283
#[derive(Copy, Clone, Eq, PartialEq)]
284-
pub struct InterfaceNumber(u8);
284+
pub struct InterfaceNumber(pub(crate) u8);
285285

286286
impl From<InterfaceNumber> for u8 {
287287
fn from(n: InterfaceNumber) -> u8 {

src/class.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::bus::{StringIndex, UsbBus};
1+
use crate::bus::{InterfaceNumber, StringIndex, UsbBus};
22
use crate::control;
33
use crate::control_pipe::ControlPipe;
44
use crate::descriptor::{BosWriter, DescriptorWriter};
@@ -116,6 +116,24 @@ pub trait UsbClass<B: UsbBus> {
116116
fn endpoint_in_complete(&mut self, addr: EndpointAddress) {
117117
let _ = addr;
118118
}
119+
120+
/// Called when the interfaces alternate setting state is requested.
121+
///
122+
/// Note: This method may be called on interfaces, that are not relevant to this class.
123+
/// You should return `None, if `interface` belongs to an interface you don't know.
124+
fn get_alt_setting(&mut self, interface: InterfaceNumber) -> Option<u8> {
125+
let _ = interface;
126+
None
127+
}
128+
129+
/// Called when the interfaces alternate setting state is altered.
130+
///
131+
/// Note: This method may be called on interfaces, that are not relevant to this class.
132+
/// You should return `false`, if `interface` belongs to an interface you don't know.
133+
fn set_alt_setting(&mut self, interface: InterfaceNumber, alternative: u8) -> bool {
134+
let _ = (interface, alternative);
135+
false
136+
}
119137
}
120138

121139
/// Handle for a control IN transfer. When implementing a class, use the methods of this object to

src/device.rs

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::bus::{PollResult, StringIndex, UsbBus, UsbBusAllocator};
1+
use crate::bus::{InterfaceNumber, PollResult, StringIndex, UsbBus, UsbBusAllocator};
22
use crate::class::{ControlIn, ControlOut, UsbClass};
33
use crate::control;
44
use crate::control_pipe::ControlPipe;
@@ -338,7 +338,25 @@ impl<B: UsbBus> UsbDevice<'_, B> {
338338
}
339339

340340
(Recipient::Interface, Request::GET_INTERFACE) => {
341-
// TODO: change when alternate settings are implemented
341+
// Reject interface numbers bigger than 255
342+
if req.index > core::u8::MAX.into() {
343+
xfer.reject().ok();
344+
return;
345+
}
346+
347+
// Ask class implementations, whether they know the alternate setting
348+
// of the interface in question
349+
for cls in classes {
350+
match cls.get_alt_setting(InterfaceNumber(req.index as u8)) {
351+
Some(setting) => {
352+
xfer.accept_with(&setting.to_le_bytes()).ok();
353+
return;
354+
}
355+
None => (),
356+
}
357+
}
358+
359+
// If no class returned an alternate setting, return the default value
342360
xfer.accept_with(&DEFAULT_ALTERNATE_SETTING.to_le_bytes())
343361
.ok();
344362
}
@@ -355,7 +373,7 @@ impl<B: UsbBus> UsbDevice<'_, B> {
355373
fn control_out(&mut self, classes: &mut ClassList<'_, B>, req: control::Request) {
356374
use crate::control::{Recipient, Request};
357375

358-
for cls in classes {
376+
for cls in classes.iter_mut() {
359377
cls.control_out(ControlOut::new(&mut self.control, &req));
360378

361379
if !self.control.waiting_for_response() {
@@ -428,9 +446,28 @@ impl<B: UsbBus> UsbDevice<'_, B> {
428446
}
429447
}
430448

431-
(Recipient::Interface, Request::SET_INTERFACE, DEFAULT_ALTERNATE_SETTING_U16) => {
432-
// TODO: do something when alternate settings are implemented
433-
xfer.accept().ok();
449+
(Recipient::Interface, Request::SET_INTERFACE, alt_setting) => {
450+
// Reject interface numbers and alt settings bigger than 255
451+
if req.index > core::u8::MAX.into() || alt_setting > core::u8::MAX.into() {
452+
xfer.reject().ok();
453+
return;
454+
}
455+
456+
// Ask class implementations, whether they accept the alternate interface setting.
457+
for cls in classes {
458+
if cls.set_alt_setting(InterfaceNumber(req.index as u8), alt_setting as u8)
459+
{
460+
xfer.accept().ok();
461+
return;
462+
}
463+
}
464+
465+
// Default behaviour, if no class implementation accepted the alternate setting.
466+
if alt_setting == DEFAULT_ALTERNATE_SETTING_U16 {
467+
xfer.accept().ok();
468+
} else {
469+
xfer.reject().ok();
470+
}
434471
}
435472

436473
_ => {

0 commit comments

Comments
 (0)