From 136b00ea3228ec8b8045698688ac7a52bcc3471d Mon Sep 17 00:00:00 2001 From: Leon Tan Date: Mon, 29 Mar 2021 13:58:20 +0200 Subject: [PATCH 1/4] 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(); + } } _ => { From e5fb4a9766b0d6fea5d0e713304c8537c3184f00 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Wed, 19 Apr 2023 13:19:53 +0100 Subject: [PATCH 2/4] Remove redundant imports --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index b3befbf..97e2f96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -198,7 +198,7 @@ pub mod class_prelude { } fn _ensure_sync() { - use crate::bus::{PollResult, UsbBus, UsbBusAllocator}; + use crate::bus::PollResult; use crate::class_prelude::*; struct DummyBus<'a> { From 6deff28ee7f8f07be9b7c8c2342d7a8c1481aacd Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Wed, 19 Apr 2023 13:21:05 +0100 Subject: [PATCH 3/4] =?UTF-8?q?Add=20the=20ability=20to=20select=20USB?= =?UTF-8?q?=C2=A0revision?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/descriptor.rs | 12 ++++++------ src/device.rs | 15 ++++++++++++++- src/device_builder.rs | 8 +++++++- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/descriptor.rs b/src/descriptor.rs index e946f71..8d596e0 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -110,12 +110,12 @@ impl DescriptorWriter<'_> { self.write( descriptor_type::DEVICE, &[ - 0x10, - 0x02, // bcdUSB 2.1 - config.device_class, // bDeviceClass - config.device_sub_class, // bDeviceSubClass - config.device_protocol, // bDeviceProtocol - config.max_packet_size_0, // bMaxPacketSize0 + (config.usb_rev as u16) as u8, + (config.usb_rev as u16 >> 8) as u8, // bcdUSB + config.device_class, // bDeviceClass + config.device_sub_class, // bDeviceSubClass + config.device_protocol, // bDeviceProtocol + config.max_packet_size_0, // bMaxPacketSize0 config.vendor_id as u8, (config.vendor_id >> 8) as u8, // idVendor config.product_id as u8, diff --git a/src/device.rs b/src/device.rs index b1eb203..09f25d2 100644 --- a/src/device.rs +++ b/src/device.rs @@ -30,6 +30,18 @@ pub enum UsbDeviceState { // Maximum number of endpoints in one direction. Specified by the USB specification. const MAX_ENDPOINTS: usize = 16; +/// Usb spec revision. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[repr(u16)] +pub enum UsbRev { + /// USB 2.0 compliance + Usb200 = 0x200, + /// USB 2.1 compliance. + /// + /// Typically adds support for BOS requests. + Usb210 = 0x210, +} + /// A USB device consisting of one or more device classes. pub struct UsbDevice<'a, B: UsbBus> { bus: &'a B, @@ -49,6 +61,7 @@ pub(crate) struct Config<'a> { pub max_packet_size_0: u8, pub vendor_id: u16, pub product_id: u16, + pub usb_rev: UsbRev, pub device_release: u16, pub manufacturer: Option<&'a str>, pub product: Option<&'a str>, @@ -469,7 +482,7 @@ impl UsbDevice<'_, B> { } match dtype { - descriptor_type::BOS => accept_writer(xfer, |w| { + descriptor_type::BOS if config.usb_rev > UsbRev::Usb200 => accept_writer(xfer, |w| { let mut bw = BosWriter::new(w); bw.bos()?; diff --git a/src/device_builder.rs b/src/device_builder.rs index 944a45f..ec6c4a4 100644 --- a/src/device_builder.rs +++ b/src/device_builder.rs @@ -1,5 +1,5 @@ use crate::bus::{UsbBus, UsbBusAllocator}; -use crate::device::{Config, UsbDevice}; +use crate::device::{Config, UsbDevice, UsbRev}; /// A USB vendor ID and product ID pair. pub struct UsbVidPid(pub u16, pub u16); @@ -34,6 +34,7 @@ impl<'a, B: UsbBus> UsbDeviceBuilder<'a, B> { max_packet_size_0: 8, vendor_id: vid_pid.0, product_id: vid_pid.1, + usb_rev: UsbRev::Usb210, device_release: 0x0010, manufacturer: None, product: None, @@ -87,6 +88,11 @@ impl<'a, B: UsbBus> UsbDeviceBuilder<'a, B> { /// /// Default: `false` supports_remote_wakeup: bool, + + /// Sets which Usb 2 revision to comply to. + /// + /// Default: `UsbRev::Usb210` + usb_rev: UsbRev, } /// Configures the device as a composite device with interface association descriptors. From 823a05325ae514cad92b5f665c4c4fbd70cee8f0 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 20 Apr 2023 07:25:44 +0300 Subject: [PATCH 4/4] Update changelog --- CHANGELOG.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00935c7..271677e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,17 +6,21 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] + ### Added -* New enums and allocators for Isochronous endpoints +* New enums and allocators for Isochronous endpoints ([#60](https://github.com/rust-embedded-community/usb-device/pull/60)). +* Ability to select USB revision ([#116](https://github.com/rust-embedded-community/usb-device/pull/116)). ### Changed -* `EndpointType` enum now has fields for isochronous synchronization and usage. +* `EndpointType` enum now has fields for isochronous synchronization and usage ([#60](https://github.com/rust-embedded-community/usb-device/pull/60)). ## [0.2.9] - 2022-08-02 +### Added +* Optional support for defmt ([#76](https://github.com/rust-embedded-community/usb-device/pull/76)). + ### Fixed * Fixed an issue where USB devices were not enumerating on Windows ([#32](https://github.com/rust-embedded-community/usb-device/issues/82)) -* Add optional support for defmt ([#76](https://github.com/rust-embedded-community/usb-device/pull/76)) * Fixed Suspend state transition so it goes back to the previous state, not just Default ([#97](https://github.com/rust-embedded-community/usb-device/pull/97)) ## [0.2.8] - 2021-03-13