diff --git a/advanced/common/usb/src/get-descriptor-device.rs b/advanced/common/usb/src/get-descriptor-device.rs index 36fb245..fd1c210 100644 --- a/advanced/common/usb/src/get-descriptor-device.rs +++ b/advanced/common/usb/src/get-descriptor-device.rs @@ -5,9 +5,11 @@ #![deny(warnings)] #![no_std] -#[cfg(TODO)] use core::num::NonZeroU8; +/// Device address assigned by the host; will be in the range 1..=127 +pub type Address = NonZeroU8; + /// Standard USB request #[derive(Clone, Copy, Debug, PartialEq)] pub enum Request { @@ -22,10 +24,9 @@ pub enum Request { /// SET_ADDRESS // see section 9.4.6 of the USB specification - #[cfg(TODO)] SetAddress { /// New device address, in the range `1..=127` - address: Option, + address: Option
, }, /// SET_CONFIGURATION @@ -50,17 +51,24 @@ impl Request { windex: u16, wlength: u16, ) -> Result { - // see table 9-4 + // see table 9-4 (USB specification) + const SET_ADDRESS: u8 = 5; const GET_DESCRIPTOR: u8 = 6; + if bmrequesttype == 0b10000000 && brequest == GET_DESCRIPTOR { // see table 9-5 const DEVICE: u8 = 1; + // 1. get descriptor type and descriptor index from wValue let desc_ty = (wvalue >> 8) as u8; let desc_index = wvalue as u8; let langid = windex; + // 2. confirm that the descriptor + // - is of type DEVICE and + // - has descriptor index 0 (i.e. it is the first implemented descriptor for this type) and + // - has wIndex 0 (i.e. no language ID since it's not a string descriptor) if desc_ty == DEVICE && desc_index == 0 && langid == 0 { Ok(Request::GetDescriptor { descriptor: Descriptor::Device, @@ -69,6 +77,18 @@ impl Request { } else { Err(()) } + } else if bmrequesttype == 0b00000000 && brequest == SET_ADDRESS { + // Set the device address for all future accesses. + // (Needed to successfully init when conected to Apple devices) + // Section 9.4.6 Set Address of the USB specification explains which values for wvalue, + // windex and wlength are valid. + if wvalue < 128 && windex == 0 && wlength == 0 { + Ok(Request::SetAddress { + address: NonZeroU8::new(wvalue as u8), + }) + } else { + Err(()) + } } else { Err(()) } @@ -92,7 +112,6 @@ pub enum Descriptor { #[cfg(test)] mod tests { - #[cfg(TODO)] use core::num::NonZeroU8; use crate::{Descriptor, Request}; @@ -117,24 +136,6 @@ mod tests { // ^^^^ } - #[cfg(TODO)] - #[test] - fn get_descriptor_configuration() { - // OK: GET_DESCRIPTOR Configuration 0 [length=9] - assert_eq!( - Request::parse(0b1000_0000, 0x06, 0x02_00, 0, 9), - Ok(Request::GetDescriptor { - descriptor: Descriptor::Configuration { index: 0 }, - length: 9 - }) - ); - - // has language ID but shouldn't - assert!(Request::parse(0b1000_0000, 0x06, 0x02_00, 1033, 9).is_err()); - // ^^^^ - } - - #[cfg(TODO)] #[test] fn set_address() { // OK: SET_ADDRESS 16 @@ -164,6 +165,23 @@ mod tests { // ^ } + #[cfg(TODO)] + #[test] + fn get_descriptor_configuration() { + // OK: GET_DESCRIPTOR Configuration 0 [length=9] + assert_eq!( + Request::parse(0b1000_0000, 0x06, 0x02_00, 0, 9), + Ok(Request::GetDescriptor { + descriptor: Descriptor::Configuration { index: 0 }, + length: 9 + }) + ); + + // has language ID but shouldn't + assert!(Request::parse(0b1000_0000, 0x06, 0x02_00, 1033, 9).is_err()); + // ^^^^ + } + #[cfg(TODO)] #[test] fn set_configuration() {