//! A collection of structures for use in setting up devices during //! enumeration. //! //! These types are all defined in ยง9.3 of the USB 2.0 specification. //! //! The structures defined herein are `repr(C)` and `repr(packed)` //! when necessary to ensure that they are able to be directly //! marshalled to the bus. use core::convert::{TryFrom, TryInto}; #[derive(Clone, Copy, Debug, PartialEq)] #[repr(C)] pub struct RequestType(u8); impl RequestType { pub fn recipient(self) -> Result { const POS: u8 = 0; const MASK: u8 = 0x1f; (self.0 & (MASK << POS)).try_into() } pub fn set_recipient(&mut self, v: RequestRecipient) { const POS: u8 = 0; const MASK: u8 = 0x1f; self.0 &= !(MASK << POS); self.0 |= v as u8 & MASK; } pub fn kind(self) -> Result { const POS: u8 = 5; const MASK: u8 = 0x3; (self.0 & (MASK << POS)).try_into() } pub fn set_kind(&mut self, v: RequestKind) { const POS: u8 = 5; const MASK: u8 = 0x3; self.0 &= !(MASK << POS); self.0 |= v as u8 & MASK; } pub fn direction(self) -> Result { const POS: u8 = 7; const MASK: u8 = 0x1; (self.0 & (MASK << POS)).try_into() } pub fn set_direction(&mut self, v: RequestDirection) { const POS: u8 = 7; const MASK: u8 = 0x1; self.0 &= !(MASK << POS); self.0 |= v as u8 & MASK; } } impl From<(RequestDirection, RequestKind, RequestRecipient)> for RequestType { fn from(v: (RequestDirection, RequestKind, RequestRecipient)) -> Self { Self(v.0 as u8 | v.1 as u8 | v.2 as u8) } } #[derive(Copy, Clone, Debug, PartialEq)] pub enum RequestDirection { HostToDevice = 0x00, DeviceToHost = 0x80, } impl TryFrom for RequestDirection { type Error = &'static str; fn try_from(v: u8) -> Result { match v { 0x00 => Ok(Self::HostToDevice), 0x80 => Ok(Self::DeviceToHost), _ => Err("direction can only be 0x00 or 0x80"), } } } #[derive(Copy, Clone, Debug, PartialEq)] pub enum RequestKind { Standard = 0x00, Class = 0x20, Vendor = 0x40, } impl TryFrom for RequestKind { type Error = &'static str; fn try_from(v: u8) -> Result { match v { 0x00 => Ok(Self::Standard), 0x20 => Ok(Self::Class), 0x40 => Ok(Self::Vendor), _ => Err("type can only be 0x00, 0x20, or 0x40"), } } } #[derive(Copy, Clone, Debug, PartialEq)] pub enum RequestRecipient { Device = 0x00, Interface = 0x01, Endpoint = 0x02, Other = 0x03, } impl TryFrom for RequestRecipient { type Error = &'static str; fn try_from(v: u8) -> Result { match v { 0x00 => Ok(Self::Device), 0x01 => Ok(Self::Interface), 0x02 => Ok(Self::Endpoint), 0x03 => Ok(Self::Other), _ => Err("recipient can only be between 0 and 3"), } } } #[derive(Clone, Copy, Debug, Default, PartialEq)] #[repr(C)] pub struct WValue(u16); impl WValue { pub fn w_value_lo(self) -> u8 { const POS: u8 = 0; const MASK: u16 = 0xff; ((self.0 >> POS) & MASK) as u8 } pub fn set_w_value_lo(&mut self, v: u8) { const POS: u8 = 0; const MASK: u8 = 0xff; self.0 &= !(u16::from(MASK) << POS); self.0 |= u16::from(v & MASK) << POS; } pub fn w_value_hi(self) -> u8 { const POS: u8 = 8; const MASK: u16 = 0xff; ((self.0 >> POS) & MASK) as u8 } pub fn set_w_value_hi(&mut self, v: u8) { const POS: u8 = 8; const MASK: u8 = 0xff; self.0 &= !(u16::from(MASK) << POS); self.0 |= u16::from(v & MASK) << POS; } } impl From<(u8, u8)> for WValue { fn from(v: (u8, u8)) -> Self { let mut rc = Self(0); rc.set_w_value_lo(v.0); rc.set_w_value_hi(v.1); rc } } #[derive(Clone, Copy, Debug, PartialEq)] pub enum RequestCode { GetStatus = 0, ClearFeature = 1, SetFeature = 3, SetAddress = 5, GetDescriptor = 6, SetDescriptor = 7, GetConfiguration = 8, SetConfiguration = 9, GetInterface = 10, SetInterface = 11, SynchFrame = 12, } impl TryFrom for RequestCode { type Error = &'static str; fn try_from(v: u8) -> Result { match v { 0 => Ok(Self::GetStatus), 1 => Ok(Self::ClearFeature), 3 => Ok(Self::SetFeature), 5 => Ok(Self::SetAddress), 6 => Ok(Self::GetDescriptor), 7 => Ok(Self::SetDescriptor), 8 => Ok(Self::GetConfiguration), 9 => Ok(Self::SetConfiguration), 10 => Ok(Self::GetInterface), 11 => Ok(Self::SetInterface), 12 => Ok(Self::SynchFrame), _ => Err("invalid request value"), } } } impl Default for RequestCode { fn default() -> Self { Self::GetStatus } } #[derive(Copy, Clone, Debug)] #[repr(C, packed)] pub struct SetupPacket { pub bm_request_type: RequestType, pub b_request: RequestCode, pub w_value: WValue, pub w_index: u16, pub w_length: u16, } #[cfg(test)] mod test { use super::*; use core::mem; use core::slice; #[test] fn setup_packet_layout() { let len = mem::size_of::(); assert_eq!(len, 8); let sp = SetupPacket { bm_request_type: RequestType::from(( RequestDirection::HostToDevice, RequestKind::Class, RequestRecipient::Endpoint, )), b_request: RequestCode::GetInterface, w_value: WValue::from((0xf0, 0x0d)), w_index: 0xadde, w_length: 0xefbe, }; let base = &sp as *const _ as usize; assert_offset("bm_request_type", &sp.bm_request_type, base, 0x00); assert_offset("b_request", &sp.b_request, base, 0x01); assert_offset("w_value", &sp.w_value, base, 0x02); assert_offset("w_index", &sp.w_index, base, 0x04); assert_offset("w_length", &sp.w_length, base, 0x06); let got = unsafe { slice::from_raw_parts(&sp as *const _ as *const u8, len) }; let want = &[0x22, 0x0a, 0xf0, 0x0d, 0xde, 0xad, 0xbe, 0xef]; assert_eq!(got, want); } fn assert_offset(name: &str, field: &T, base: usize, offset: usize) { let ptr = field as *const _ as usize; assert_eq!(ptr - base, offset, "{} register offset.", name); } }