From 136b00ea3228ec8b8045698688ac7a52bcc3471d Mon Sep 17 00:00:00 2001 From: Leon Tan Date: Mon, 29 Mar 2021 13:58:20 +0200 Subject: [PATCH] Implement alternate setting selection --- Cargo.toml | 2 +- src/bus.rs | 2 +- src/class.rs | 20 +++++++++++++++++++- src/device.rs | 49 +++++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d582a0f..9009be6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "usb-device" description = "Experimental device-side USB stack for embedded devices." -version = "0.2.8" +version = "0.2.9" edition = "2018" readme = "README.md" keywords = ["no-std", "embedded", "usb"] diff --git a/src/bus.rs b/src/bus.rs index cd176d3..7604d17 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -281,7 +281,7 @@ impl UsbBusAllocator { /// A handle for a USB interface that contains its number. #[derive(Copy, Clone, Eq, PartialEq)] -pub struct InterfaceNumber(u8); +pub struct InterfaceNumber(pub(crate) u8); impl From for u8 { fn from(n: InterfaceNumber) -> u8 { diff --git a/src/class.rs b/src/class.rs index 5337e97..9e94484 100644 --- a/src/class.rs +++ b/src/class.rs @@ -1,4 +1,4 @@ -use crate::bus::{StringIndex, UsbBus}; +use crate::bus::{InterfaceNumber, StringIndex, UsbBus}; use crate::control; use crate::control_pipe::ControlPipe; use crate::descriptor::{BosWriter, DescriptorWriter}; @@ -116,6 +116,24 @@ pub trait UsbClass { fn endpoint_in_complete(&mut self, addr: EndpointAddress) { let _ = addr; } + + /// Called when the interfaces alternate setting state is requested. + /// + /// Note: This method may be called on interfaces, that are not relevant to this class. + /// You should return `None, if `interface` belongs to an interface you don't know. + fn get_alt_setting(&mut self, interface: InterfaceNumber) -> Option { + let _ = interface; + None + } + + /// Called when the interfaces alternate setting state is altered. + /// + /// Note: This method may be called on interfaces, that are not relevant to this class. + /// You should return `false`, if `interface` belongs to an interface you don't know. + fn set_alt_setting(&mut self, interface: InterfaceNumber, alternative: u8) -> bool { + let _ = (interface, alternative); + false + } } /// Handle for a control IN transfer. When implementing a class, use the methods of this object to diff --git a/src/device.rs b/src/device.rs index defc49c..fc102e1 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,4 +1,4 @@ -use crate::bus::{PollResult, StringIndex, UsbBus, UsbBusAllocator}; +use crate::bus::{InterfaceNumber, PollResult, StringIndex, UsbBus, UsbBusAllocator}; use crate::class::{ControlIn, ControlOut, UsbClass}; use crate::control; use crate::control_pipe::ControlPipe; @@ -338,7 +338,25 @@ impl UsbDevice<'_, B> { } (Recipient::Interface, Request::GET_INTERFACE) => { - // TODO: change when alternate settings are implemented + // Reject interface numbers bigger than 255 + if req.index > core::u8::MAX.into() { + xfer.reject().ok(); + return; + } + + // Ask class implementations, whether they know the alternate setting + // of the interface in question + for cls in classes { + match cls.get_alt_setting(InterfaceNumber(req.index as u8)) { + Some(setting) => { + xfer.accept_with(&setting.to_le_bytes()).ok(); + return; + } + None => (), + } + } + + // If no class returned an alternate setting, return the default value xfer.accept_with(&DEFAULT_ALTERNATE_SETTING.to_le_bytes()) .ok(); } @@ -355,7 +373,7 @@ impl UsbDevice<'_, B> { fn control_out(&mut self, classes: &mut ClassList<'_, B>, req: control::Request) { use crate::control::{Recipient, Request}; - for cls in classes { + for cls in classes.iter_mut() { cls.control_out(ControlOut::new(&mut self.control, &req)); if !self.control.waiting_for_response() { @@ -428,9 +446,28 @@ impl UsbDevice<'_, B> { } } - (Recipient::Interface, Request::SET_INTERFACE, DEFAULT_ALTERNATE_SETTING_U16) => { - // TODO: do something when alternate settings are implemented - xfer.accept().ok(); + (Recipient::Interface, Request::SET_INTERFACE, alt_setting) => { + // Reject interface numbers and alt settings bigger than 255 + if req.index > core::u8::MAX.into() || alt_setting > core::u8::MAX.into() { + xfer.reject().ok(); + return; + } + + // Ask class implementations, whether they accept the alternate interface setting. + for cls in classes { + if cls.set_alt_setting(InterfaceNumber(req.index as u8), alt_setting as u8) + { + xfer.accept().ok(); + return; + } + } + + // Default behaviour, if no class implementation accepted the alternate setting. + if alt_setting == DEFAULT_ALTERNATE_SETTING_U16 { + xfer.accept().ok(); + } else { + xfer.reject().ok(); + } } _ => {