Skip to content

Commit 4ad3f72

Browse files
authored
Merge pull request #114 from rust-embedded-community/feature/alternate-settings
Feature/alternate settings
2 parents c9e28ff + b7cf238 commit 4ad3f72

File tree

4 files changed

+64
-8
lines changed

4 files changed

+64
-8
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1010
### Added
1111
* New enums and allocators for Isochronous endpoints ([#60](https://github.com/rust-embedded-community/usb-device/pull/60)).
1212
* Ability to select USB revision ([#116](https://github.com/rust-embedded-community/usb-device/pull/116)).
13+
* Added support for alternate settings on interfaces ([#114](https://github.com/rust-embedded-community/usb-device/pull/114)).
1314

1415
### Changed
1516
* `EndpointType` enum now has fields for isochronous synchronization and usage ([#60](https://github.com/rust-embedded-community/usb-device/pull/60)).

src/bus.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ impl<B: UsbBus> UsbBusAllocator<B> {
321321
/// A handle for a USB interface that contains its number.
322322
#[derive(Copy, Clone, Eq, PartialEq)]
323323
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
324-
pub struct InterfaceNumber(u8);
324+
pub struct InterfaceNumber(pub(crate) u8);
325325

326326
impl From<InterfaceNumber> for u8 {
327327
fn from(n: InterfaceNumber) -> u8 {

src/class.rs

+19-1
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

+43-6
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;
@@ -357,7 +357,25 @@ impl<B: UsbBus> UsbDevice<'_, B> {
357357
}
358358

359359
(Recipient::Interface, Request::GET_INTERFACE) => {
360-
// TODO: change when alternate settings are implemented
360+
// Reject interface numbers bigger than 255
361+
if req.index > core::u8::MAX.into() {
362+
xfer.reject().ok();
363+
return;
364+
}
365+
366+
// Ask class implementations, whether they know the alternate setting
367+
// of the interface in question
368+
for cls in classes {
369+
match cls.get_alt_setting(InterfaceNumber(req.index as u8)) {
370+
Some(setting) => {
371+
xfer.accept_with(&setting.to_le_bytes()).ok();
372+
return;
373+
}
374+
None => (),
375+
}
376+
}
377+
378+
// If no class returned an alternate setting, return the default value
361379
xfer.accept_with(&DEFAULT_ALTERNATE_SETTING.to_le_bytes())
362380
.ok();
363381
}
@@ -374,7 +392,7 @@ impl<B: UsbBus> UsbDevice<'_, B> {
374392
fn control_out(&mut self, classes: &mut ClassList<'_, B>, req: control::Request) {
375393
use crate::control::{Recipient, Request};
376394

377-
for cls in classes {
395+
for cls in classes.iter_mut() {
378396
cls.control_out(ControlOut::new(&mut self.control, &req));
379397

380398
if !self.control.waiting_for_response() {
@@ -447,9 +465,28 @@ impl<B: UsbBus> UsbDevice<'_, B> {
447465
}
448466
}
449467

450-
(Recipient::Interface, Request::SET_INTERFACE, DEFAULT_ALTERNATE_SETTING_U16) => {
451-
// TODO: do something when alternate settings are implemented
452-
xfer.accept().ok();
468+
(Recipient::Interface, Request::SET_INTERFACE, alt_setting) => {
469+
// Reject interface numbers and alt settings bigger than 255
470+
if req.index > core::u8::MAX.into() || alt_setting > core::u8::MAX.into() {
471+
xfer.reject().ok();
472+
return;
473+
}
474+
475+
// Ask class implementations, whether they accept the alternate interface setting.
476+
for cls in classes {
477+
if cls.set_alt_setting(InterfaceNumber(req.index as u8), alt_setting as u8)
478+
{
479+
xfer.accept().ok();
480+
return;
481+
}
482+
}
483+
484+
// Default behaviour, if no class implementation accepted the alternate setting.
485+
if alt_setting == DEFAULT_ALTERNATE_SETTING_U16 {
486+
xfer.accept().ok();
487+
} else {
488+
xfer.reject().ok();
489+
}
453490
}
454491

455492
_ => {

0 commit comments

Comments
 (0)