diff --git a/advanced/common/usb/src/get-descriptor-configuration.rs b/advanced/common/usb/src/get-descriptor-configuration.rs index 388de88..3d531b6 100644 --- a/advanced/common/usb/src/get-descriptor-configuration.rs +++ b/advanced/common/usb/src/get-descriptor-configuration.rs @@ -1,13 +1,15 @@ //! Some USB 2.0 data types -// NOTE this is a solution to exercise `usb-2` +// NOTE this is a solution to exercise `usb-3` #![deny(missing_docs)] #![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,7 +51,8 @@ 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 { @@ -75,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(()) } @@ -97,7 +111,6 @@ pub enum Descriptor { #[cfg(test)] mod tests { - #[cfg(TODO)] use core::num::NonZeroU8; use crate::{Descriptor, Request}; @@ -122,23 +135,6 @@ mod tests { // ^^^^ } - #[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 @@ -168,6 +164,22 @@ mod tests { // ^ } + #[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() { diff --git a/advanced/firmware/src/bin/usb-3-solution.rs b/advanced/firmware/src/bin/usb-3-solution.rs index fbc405f..2afd70f 100644 --- a/advanced/firmware/src/bin/usb-3-solution.rs +++ b/advanced/firmware/src/bin/usb-3-solution.rs @@ -64,35 +64,41 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { wvalue ); - if let Ok(Request::GetDescriptor { descriptor, length }) = - Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) - { - match descriptor { - Descriptor::Device => { - log::info!("GET_DESCRIPTOR Device [length={}]", length); + let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) + .expect("Error parsing request"); + match request { + Request::GetDescriptor { descriptor, length } + if descriptor == Descriptor::Device => + { + log::info!("GET_DESCRIPTOR Device [length={}]", length); - let desc = usb2::device::Descriptor { - bDeviceClass: 0, - bDeviceProtocol: 0, - bDeviceSubClass: 0, - bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64, - bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(), - bcdDevice: 0x01_00, // 1.00 - iManufacturer: None, - iProduct: None, - iSerialNumber: None, - idProduct: consts::PID, - idVendor: consts::VID, - }; - let desc_bytes = desc.bytes(); - let resp = - &desc_bytes[..core::cmp::min(desc_bytes.len(), usize::from(length))]; - ep0in.start(&resp, usbd); - } + let desc = usb2::device::Descriptor { + bDeviceClass: 0, + bDeviceProtocol: 0, + bDeviceSubClass: 0, + bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64, + bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(), + bcdDevice: 0x01_00, // 1.00 + iManufacturer: None, + iProduct: None, + iSerialNumber: None, + idProduct: consts::PID, + idVendor: consts::VID, + }; + let desc_bytes = desc.bytes(); + let resp = + &desc_bytes[..core::cmp::min(desc_bytes.len(), usize::from(length))]; + ep0in.start(&resp, usbd); + } + Request::SetAddress { .. } => { + // On Mac OS you'll get this request before the GET_DESCRIPTOR request so we + // need to catch it here. We'll properly handle this request later + // but for now it's OK to do nothing. + }, + _ => { + log::error!("unknown request (goal achieved if GET_DESCRIPTOR Device was handled)"); + dk::exit() } - } else { - log::error!("unknown request (goal achieved if GET_DESCRIPTOR Device was handled)"); - dk::exit() } } } diff --git a/advanced/firmware/src/bin/usb-3.rs b/advanced/firmware/src/bin/usb-3.rs index a68b0bc..f2f0471 100644 --- a/advanced/firmware/src/bin/usb-3.rs +++ b/advanced/firmware/src/bin/usb-3.rs @@ -64,22 +64,28 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { wvalue ); - if let Ok(Request::GetDescriptor { descriptor, length }) = - Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) - { - match descriptor { - Descriptor::Device => { - log::info!("GET_DESCRIPTOR Device [length={}]", length); + let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) + .expect("Error parsing request"); + match request { + Request::GetDescriptor { descriptor, length } + if descriptor == Descriptor::Device => + { + log::info!("GET_DESCRIPTOR Device [length={}]", length); - // FIXME send back a valid device descriptor, truncated to `length` bytes - // let desc = usb2::device::Descriptor { .. }; - let resp = []; - ep0in.start(&resp, usbd); - } + // TODO send back a valid device descriptor, truncated to `length` bytes + // let desc = usb2::device::Descriptor { .. }; + let resp = []; + ep0in.start(&resp, usbd); + } + Request::SetAddress { .. } => { + // On Mac OS you'll get this request before the GET_DESCRIPTOR request so we + // need to catch it here. We'll properly handle this request later + // but for now it's OK to do nothing. + }, + _ => { + log::error!("unknown request (goal achieved if GET_DESCRIPTOR Device was handled)"); + dk::exit() } - } else { - log::error!("unknown request (goal achieved if GET_DESCRIPTOR Device was handled)"); - dk::exit() } } }