usb_host/
setup.rs

1//! A collection of structures for use in setting up devices during
2//! enumeration.
3//!
4//! These types are all defined in ยง9.3 of the USB 2.0 specification.
5//!
6//! The structures defined herein are `repr(C)` and `repr(packed)`
7//! when necessary to ensure that they are able to be directly
8//! marshalled to the bus.
9
10use core::convert::{TryFrom, TryInto};
11
12#[derive(Clone, Copy, Debug, PartialEq)]
13#[repr(C)]
14pub struct RequestType(u8);
15impl RequestType {
16    pub fn recipient(self) -> Result<RequestRecipient, &'static str> {
17        const POS: u8 = 0;
18        const MASK: u8 = 0x1f;
19        (self.0 & (MASK << POS)).try_into()
20    }
21
22    pub fn set_recipient(&mut self, v: RequestRecipient) {
23        const POS: u8 = 0;
24        const MASK: u8 = 0x1f;
25        self.0 &= !(MASK << POS);
26        self.0 |= v as u8 & MASK;
27    }
28
29    pub fn kind(self) -> Result<RequestKind, &'static str> {
30        const POS: u8 = 5;
31        const MASK: u8 = 0x3;
32        (self.0 & (MASK << POS)).try_into()
33    }
34
35    pub fn set_kind(&mut self, v: RequestKind) {
36        const POS: u8 = 5;
37        const MASK: u8 = 0x3;
38        self.0 &= !(MASK << POS);
39        self.0 |= v as u8 & MASK;
40    }
41
42    pub fn direction(self) -> Result<RequestDirection, &'static str> {
43        const POS: u8 = 7;
44        const MASK: u8 = 0x1;
45        (self.0 & (MASK << POS)).try_into()
46    }
47
48    pub fn set_direction(&mut self, v: RequestDirection) {
49        const POS: u8 = 7;
50        const MASK: u8 = 0x1;
51        self.0 &= !(MASK << POS);
52        self.0 |= v as u8 & MASK;
53    }
54}
55impl From<(RequestDirection, RequestKind, RequestRecipient)> for RequestType {
56    fn from(v: (RequestDirection, RequestKind, RequestRecipient)) -> Self {
57        Self(v.0 as u8 | v.1 as u8 | v.2 as u8)
58    }
59}
60
61#[derive(Copy, Clone, Debug, PartialEq)]
62pub enum RequestDirection {
63    HostToDevice = 0x00,
64    DeviceToHost = 0x80,
65}
66impl TryFrom<u8> for RequestDirection {
67    type Error = &'static str;
68
69    fn try_from(v: u8) -> Result<Self, Self::Error> {
70        match v {
71            0x00 => Ok(Self::HostToDevice),
72            0x80 => Ok(Self::DeviceToHost),
73            _ => Err("direction can only be 0x00 or 0x80"),
74        }
75    }
76}
77
78#[derive(Copy, Clone, Debug, PartialEq)]
79pub enum RequestKind {
80    Standard = 0x00,
81    Class = 0x20,
82    Vendor = 0x40,
83}
84impl TryFrom<u8> for RequestKind {
85    type Error = &'static str;
86
87    fn try_from(v: u8) -> Result<Self, Self::Error> {
88        match v {
89            0x00 => Ok(Self::Standard),
90            0x20 => Ok(Self::Class),
91            0x40 => Ok(Self::Vendor),
92            _ => Err("type can only be 0x00, 0x20, or 0x40"),
93        }
94    }
95}
96
97#[derive(Copy, Clone, Debug, PartialEq)]
98pub enum RequestRecipient {
99    Device = 0x00,
100    Interface = 0x01,
101    Endpoint = 0x02,
102    Other = 0x03,
103}
104impl TryFrom<u8> for RequestRecipient {
105    type Error = &'static str;
106
107    fn try_from(v: u8) -> Result<Self, Self::Error> {
108        match v {
109            0x00 => Ok(Self::Device),
110            0x01 => Ok(Self::Interface),
111            0x02 => Ok(Self::Endpoint),
112            0x03 => Ok(Self::Other),
113            _ => Err("recipient can only be between 0 and 3"),
114        }
115    }
116}
117
118#[derive(Clone, Copy, Debug, Default, PartialEq)]
119#[repr(C)]
120pub struct WValue(u16);
121impl WValue {
122    pub fn w_value_lo(self) -> u8 {
123        const POS: u8 = 0;
124        const MASK: u16 = 0xff;
125        ((self.0 >> POS) & MASK) as u8
126    }
127
128    pub fn set_w_value_lo(&mut self, v: u8) {
129        const POS: u8 = 0;
130        const MASK: u8 = 0xff;
131        self.0 &= !(u16::from(MASK) << POS);
132        self.0 |= u16::from(v & MASK) << POS;
133    }
134
135    pub fn w_value_hi(self) -> u8 {
136        const POS: u8 = 8;
137        const MASK: u16 = 0xff;
138        ((self.0 >> POS) & MASK) as u8
139    }
140
141    pub fn set_w_value_hi(&mut self, v: u8) {
142        const POS: u8 = 8;
143        const MASK: u8 = 0xff;
144        self.0 &= !(u16::from(MASK) << POS);
145        self.0 |= u16::from(v & MASK) << POS;
146    }
147}
148impl From<(u8, u8)> for WValue {
149    fn from(v: (u8, u8)) -> Self {
150        let mut rc = Self(0);
151        rc.set_w_value_lo(v.0);
152        rc.set_w_value_hi(v.1);
153        rc
154    }
155}
156
157#[derive(Clone, Copy, Debug, PartialEq)]
158pub enum RequestCode {
159    GetStatus = 0,
160    ClearFeature = 1,
161    SetFeature = 3,
162    SetAddress = 5,
163    GetDescriptor = 6,
164    SetDescriptor = 7,
165    GetConfiguration = 8,
166    SetConfiguration = 9,
167    GetInterface = 10,
168    SetInterface = 11,
169    SynchFrame = 12,
170}
171impl TryFrom<u8> for RequestCode {
172    type Error = &'static str;
173
174    fn try_from(v: u8) -> Result<Self, Self::Error> {
175        match v {
176            0 => Ok(Self::GetStatus),
177            1 => Ok(Self::ClearFeature),
178            3 => Ok(Self::SetFeature),
179            5 => Ok(Self::SetAddress),
180            6 => Ok(Self::GetDescriptor),
181            7 => Ok(Self::SetDescriptor),
182            8 => Ok(Self::GetConfiguration),
183            9 => Ok(Self::SetConfiguration),
184            10 => Ok(Self::GetInterface),
185            11 => Ok(Self::SetInterface),
186            12 => Ok(Self::SynchFrame),
187            _ => Err("invalid request value"),
188        }
189    }
190}
191impl Default for RequestCode {
192    fn default() -> Self {
193        Self::GetStatus
194    }
195}
196
197#[derive(Copy, Clone, Debug)]
198#[repr(C, packed)]
199pub struct SetupPacket {
200    pub bm_request_type: RequestType,
201    pub b_request: RequestCode,
202    pub w_value: WValue,
203    pub w_index: u16,
204    pub w_length: u16,
205}
206
207#[cfg(test)]
208mod test {
209    use super::*;
210
211    use core::mem;
212    use core::slice;
213
214    #[test]
215    fn setup_packet_layout() {
216        let len = mem::size_of::<SetupPacket>();
217        assert_eq!(len, 8);
218        let sp = SetupPacket {
219            bm_request_type: RequestType::from((
220                RequestDirection::HostToDevice,
221                RequestKind::Class,
222                RequestRecipient::Endpoint,
223            )),
224            b_request: RequestCode::GetInterface,
225            w_value: WValue::from((0xf0, 0x0d)),
226            w_index: 0xadde,
227            w_length: 0xefbe,
228        };
229        let base = &sp as *const _ as usize;
230        assert_offset("bm_request_type", &sp.bm_request_type, base, 0x00);
231        assert_offset("b_request", &sp.b_request, base, 0x01);
232        assert_offset("w_value", &sp.w_value, base, 0x02);
233        assert_offset("w_index", &sp.w_index, base, 0x04);
234        assert_offset("w_length", &sp.w_length, base, 0x06);
235
236        let got = unsafe { slice::from_raw_parts(&sp as *const _ as *const u8, len) };
237        let want = &[0x22, 0x0a, 0xf0, 0x0d, 0xde, 0xad, 0xbe, 0xef];
238        assert_eq!(got, want);
239    }
240
241    fn assert_offset<T>(name: &str, field: &T, base: usize, offset: usize) {
242        let ptr = field as *const _ as usize;
243        assert_eq!(ptr - base, offset, "{} register offset.", name);
244    }
245}