usb_host/
descriptor.rs

1//! A collection of structures defining descriptors in the USB.
2//!
3//! These types are defined in ยง9.5 and 9.6 of the USB 2.0
4//! 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;
11
12#[derive(Clone, Copy, Debug, PartialEq)]
13pub enum DescriptorType {
14    Device = 1,
15    Configuration = 2,
16    String = 3,
17    Interface = 4,
18    Endpoint = 5,
19    DeviceQualifier = 6,
20    OtherSpeed = 7,
21    InterfacePower = 8,
22}
23
24impl TryFrom<u8> for DescriptorType {
25    type Error = &'static str;
26
27    fn try_from(v: u8) -> Result<Self, Self::Error> {
28        match v {
29            1 => Ok(Self::Device),
30            2 => Ok(Self::Configuration),
31            3 => Ok(Self::String),
32            4 => Ok(Self::Interface),
33            5 => Ok(Self::Endpoint),
34            6 => Ok(Self::DeviceQualifier),
35            7 => Ok(Self::OtherSpeed),
36            8 => Ok(Self::InterfacePower),
37            _ => Err("invalid descriptor"),
38        }
39    }
40}
41
42#[derive(Copy, Clone, Debug, PartialEq)]
43#[repr(C, packed)]
44pub struct DeviceDescriptor {
45    pub b_length: u8,
46    pub b_descriptor_type: DescriptorType,
47    pub bcd_usb: u16,
48    pub b_device_class: u8,
49    pub b_device_sub_class: u8,
50    pub b_device_protocol: u8,
51    pub b_max_packet_size: u8,
52    pub id_vendor: u16,
53    pub id_product: u16,
54    pub bcd_device: u16,
55    pub i_manufacturer: u8,
56    pub i_product: u8,
57    pub i_serial_number: u8,
58    pub b_num_configurations: u8,
59}
60
61#[derive(Copy, Clone, Debug, PartialEq)]
62#[repr(C, packed)]
63pub struct ConfigurationDescriptor {
64    pub b_length: u8,
65    pub b_descriptor_type: DescriptorType,
66    pub w_total_length: u16,
67    pub b_num_interfaces: u8,
68    pub b_configuration_value: u8,
69    pub i_configuration: u8,
70    pub bm_attributes: u8,
71    pub b_max_power: u8,
72}
73
74#[derive(Copy, Clone, Debug, PartialEq)]
75#[repr(C, packed)]
76pub struct InterfaceDescriptor {
77    pub b_length: u8,
78    pub b_descriptor_type: DescriptorType,
79    pub b_interface_number: u8,
80    pub b_alternate_setting: u8,
81    pub b_num_endpoints: u8,
82    pub b_interface_class: u8,
83    pub b_interface_sub_class: u8,
84    pub b_interface_protocol: u8,
85    pub i_interface: u8,
86}
87
88#[derive(Copy, Clone, Debug, PartialEq)]
89#[repr(C, packed)]
90pub struct EndpointDescriptor {
91    pub b_length: u8,
92    pub b_descriptor_type: DescriptorType,
93    pub b_endpoint_address: u8,
94    pub bm_attributes: u8,
95    pub w_max_packet_size: u16,
96    pub b_interval: u8,
97}
98
99#[cfg(test)]
100mod test {
101    use super::*;
102
103    use core::mem;
104    use core::slice;
105
106    #[test]
107    fn device_descriptor_layout() {
108        let len = mem::size_of::<DeviceDescriptor>();
109        assert_eq!(len, 18);
110        let desc = DeviceDescriptor {
111            b_length: len as u8,
112            b_descriptor_type: DescriptorType::Device,
113            bcd_usb: 0x1001,
114            b_device_class: 0xaa,
115            b_device_sub_class: 0xbb,
116            b_device_protocol: 0xcc,
117            b_max_packet_size: 0xdd,
118            id_vendor: 0xdead,
119            id_product: 0xbeef,
120            bcd_device: 0xf00d,
121            i_manufacturer: 0x11,
122            i_product: 0x22,
123            i_serial_number: 0x33,
124            b_num_configurations: 0x44,
125        };
126        let base = &desc as *const _ as usize;
127        assert_offset("b_length", &desc.b_length, base, 0x00);
128        assert_offset("b_descriptor_type", &desc.b_descriptor_type, base, 0x01);
129        assert_offset("bcd_usb", &desc.bcd_usb, base, 0x02);
130        assert_offset("b_device_class", &desc.b_device_class, base, 0x04);
131        assert_offset("b_device_sub_class", &desc.b_device_sub_class, base, 0x05);
132        assert_offset("b_device_protocol", &desc.b_device_protocol, base, 0x06);
133        assert_offset("b_max_packet_size", &desc.b_max_packet_size, base, 0x07);
134        assert_offset("id_vendor", &desc.id_vendor, base, 0x08);
135        assert_offset("id_product", &desc.id_product, base, 0x0a);
136        assert_offset("bcd_device", &desc.bcd_device, base, 0x0c);
137        assert_offset("i_manufacturer", &desc.i_manufacturer, base, 0x0e);
138        assert_offset("i_product", &desc.i_product, base, 0x0f);
139        assert_offset("i_serial_number", &desc.i_serial_number, base, 0x10);
140        assert_offset(
141            "b_num_configurations",
142            &desc.b_num_configurations,
143            base,
144            0x011,
145        );
146
147        let got = unsafe { slice::from_raw_parts(&desc as *const _ as *const u8, len) };
148        let want = &[
149            0x12, 0x01, 0x01, 0x10, 0xaa, 0xbb, 0xcc, 0xdd, 0xad, 0xde, 0xef, 0xbe, 0x0d, 0xf0,
150            0x11, 0x22, 0x33, 0x44,
151        ];
152        assert_eq!(got, want);
153    }
154
155    #[test]
156    fn configuration_descriptor_layout() {
157        let len = mem::size_of::<ConfigurationDescriptor>();
158        assert_eq!(len, 9);
159        let desc = ConfigurationDescriptor {
160            b_length: len as u8,
161            b_descriptor_type: DescriptorType::Configuration,
162            w_total_length: 0xdead,
163            b_num_interfaces: 0x22,
164            b_configuration_value: 0x33,
165            i_configuration: 0x44,
166            bm_attributes: 0x55,
167            b_max_power: 0x66,
168        };
169        let base = &desc as *const _ as usize;
170        assert_offset("b_length", &desc.b_length, base, 0x00);
171        assert_offset("b_descriptor_type", &desc.b_descriptor_type, base, 0x01);
172        assert_offset("w_total_length", &desc.w_total_length, base, 0x02);
173        assert_offset("b_num_interfaces", &desc.b_num_interfaces, base, 0x04);
174        assert_offset(
175            "b_configuration_value",
176            &desc.b_configuration_value,
177            base,
178            0x05,
179        );
180        assert_offset("i_configuration", &desc.i_configuration, base, 0x06);
181        assert_offset("bm_attributes", &desc.bm_attributes, base, 0x07);
182        assert_offset("b_max_power", &desc.b_max_power, base, 0x08);
183
184        let got = unsafe { slice::from_raw_parts(&desc as *const _ as *const u8, len) };
185        let want = &[0x09, 0x02, 0xad, 0xde, 0x22, 0x33, 0x44, 0x55, 0x66];
186        assert_eq!(got, want);
187    }
188
189    #[test]
190    fn interface_descriptor_layout() {
191        let len = mem::size_of::<InterfaceDescriptor>();
192        assert_eq!(len, 9);
193        let desc = InterfaceDescriptor {
194            b_length: len as u8,
195            b_descriptor_type: DescriptorType::Interface,
196            b_interface_number: 0xee,
197            b_alternate_setting: 0xaa,
198            b_num_endpoints: 0xf7,
199            b_interface_class: 0x11,
200            b_interface_sub_class: 0x22,
201            b_interface_protocol: 0x33,
202            i_interface: 0x44,
203        };
204        let base = &desc as *const _ as usize;
205        assert_offset("b_length", &desc.b_length, base, 0x00);
206        assert_offset("b_descriptor_type", &desc.b_descriptor_type, base, 0x01);
207        assert_offset("b_interface_number", &desc.b_interface_number, base, 0x02);
208        assert_offset("b_alternate_setting", &desc.b_alternate_setting, base, 0x03);
209        assert_offset("b_num_endpoints", &desc.b_num_endpoints, base, 0x04);
210        assert_offset("b_interface_class", &desc.b_interface_class, base, 0x05);
211        assert_offset(
212            "b_interface_sub_class",
213            &desc.b_interface_sub_class,
214            base,
215            0x06,
216        );
217        assert_offset(
218            "b_interface_protocol",
219            &desc.b_interface_protocol,
220            base,
221            0x07,
222        );
223        assert_offset("i_interface", &desc.i_interface, base, 0x08);
224
225        let got = unsafe { slice::from_raw_parts(&desc as *const _ as *const u8, len) };
226        let want = &[0x09, 0x04, 0xee, 0xaa, 0xf7, 0x11, 0x22, 0x33, 0x44];
227        assert_eq!(got, want);
228    }
229
230    #[test]
231    fn endpoint_descriptor_layout() {
232        let len = mem::size_of::<EndpointDescriptor>();
233        assert_eq!(len, 7);
234        let desc = EndpointDescriptor {
235            b_length: len as u8,
236            b_descriptor_type: DescriptorType::Endpoint,
237            b_endpoint_address: 2,
238            bm_attributes: 0xae,
239            w_max_packet_size: 0xdead,
240            b_interval: 0x7a,
241        };
242        let base = &desc as *const _ as usize;
243        assert_offset("b_length", &desc.b_length, base, 0x00);
244        assert_offset("b_descriptor_type", &desc.b_descriptor_type, base, 0x01);
245        assert_offset("b_endpoint_address", &desc.b_endpoint_address, base, 0x02);
246        assert_offset("bm_attributes", &desc.bm_attributes, base, 0x03);
247        assert_offset("w_max_packet_size", &desc.w_max_packet_size, base, 0x04);
248        assert_offset("b_interval", &desc.b_interval, base, 0x06);
249
250        let got = unsafe { slice::from_raw_parts(&desc as *const _ as *const u8, len) };
251        let want = &[0x07, 0x05, 0x02, 0xae, 0xad, 0xde, 0x7a];
252        assert_eq!(got, want);
253    }
254
255    fn assert_offset<T>(name: &str, field: &T, base: usize, offset: usize) {
256        let ptr = field as *const _ as usize;
257        assert_eq!(ptr - base, offset, "{} register offset.", name);
258    }
259}