usb_util/
types.rs

1// Copyright 2018 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::mem::size_of;
6
7use static_assertions::const_assert;
8use zerocopy::FromBytes;
9use zerocopy::Immutable;
10use zerocopy::IntoBytes;
11use zerocopy::KnownLayout;
12
13/// Standard USB descriptor types.
14pub enum DescriptorType {
15    Device = 0x01,
16    Configuration = 0x02,
17    Interface = 0x04,
18    Endpoint = 0x05,
19}
20
21/// Trait describing USB descriptors.
22pub trait Descriptor {
23    /// Get the expected bDescriptorType value for this type of descriptor.
24    fn descriptor_type() -> DescriptorType;
25}
26
27/// Standard USB descriptor header common to all descriptor types.
28#[allow(non_snake_case)]
29#[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
30#[repr(C, packed)]
31pub struct DescriptorHeader {
32    pub bLength: u8,
33    pub bDescriptorType: u8,
34}
35
36fn _assert_descriptor_header() {
37    const_assert!(size_of::<DescriptorHeader>() == 2);
38}
39
40/// Standard USB device descriptor as defined in USB 2.0 chapter 9,
41/// not including the standard header.
42#[allow(non_snake_case)]
43#[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
44#[repr(C, packed)]
45pub struct DeviceDescriptor {
46    pub bcdUSB: u16,
47    pub bDeviceClass: u8,
48    pub bDeviceSubClass: u8,
49    pub bDeviceProtocol: u8,
50    pub bMaxPacketSize0: u8,
51    pub idVendor: u16,
52    pub idProduct: u16,
53    pub bcdDevice: u16,
54    pub iManufacturer: u8,
55    pub iProduct: u8,
56    pub iSerialNumber: u8,
57    pub bNumConfigurations: u8,
58}
59
60impl Descriptor for DeviceDescriptor {
61    fn descriptor_type() -> DescriptorType {
62        DescriptorType::Device
63    }
64}
65
66fn _assert_device_descriptor() {
67    const_assert!(size_of::<DeviceDescriptor>() == 18 - 2);
68}
69
70/// Standard USB configuration descriptor as defined in USB 2.0 chapter 9,
71/// not including the standard header.
72#[allow(non_snake_case)]
73#[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
74#[repr(C, packed)]
75pub struct ConfigDescriptor {
76    pub wTotalLength: u16,
77    pub bNumInterfaces: u8,
78    pub bConfigurationValue: u8,
79    pub iConfiguration: u8,
80    pub bmAttributes: u8,
81    pub bMaxPower: u8,
82}
83
84impl Descriptor for ConfigDescriptor {
85    fn descriptor_type() -> DescriptorType {
86        DescriptorType::Configuration
87    }
88}
89
90fn _assert_config_descriptor() {
91    const_assert!(size_of::<ConfigDescriptor>() == 9 - 2);
92}
93
94impl ConfigDescriptor {
95    pub fn num_interfaces(&self) -> u8 {
96        self.bNumInterfaces
97    }
98}
99
100/// Standard USB interface descriptor as defined in USB 2.0 chapter 9,
101/// not including the standard header.
102#[allow(non_snake_case)]
103#[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
104#[repr(C, packed)]
105pub struct InterfaceDescriptor {
106    pub bInterfaceNumber: u8,
107    pub bAlternateSetting: u8,
108    pub bNumEndpoints: u8,
109    pub bInterfaceClass: u8,
110    pub bInterfaceSubClass: u8,
111    pub bInterfaceProtocol: u8,
112    pub iInterface: u8,
113}
114
115impl Descriptor for InterfaceDescriptor {
116    fn descriptor_type() -> DescriptorType {
117        DescriptorType::Interface
118    }
119}
120
121fn _assert_interface_descriptor() {
122    const_assert!(size_of::<InterfaceDescriptor>() == 9 - 2);
123}
124
125/// Standard USB endpoint descriptor as defined in USB 2.0 chapter 9,
126/// not including the standard header.
127#[allow(non_snake_case)]
128#[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
129#[repr(C, packed)]
130pub struct EndpointDescriptor {
131    pub bEndpointAddress: u8,
132    pub bmAttributes: u8,
133    pub wMaxPacketSize: u16,
134    pub bInterval: u8,
135}
136
137impl Descriptor for EndpointDescriptor {
138    fn descriptor_type() -> DescriptorType {
139        DescriptorType::Endpoint
140    }
141}
142
143fn _assert_endpoint_descriptor() {
144    const_assert!(size_of::<EndpointDescriptor>() == 7 - 2);
145}
146
147const ENDPOINT_DESCRIPTOR_DIRECTION_MASK: u8 = 1 << 7;
148const ENDPOINT_DESCRIPTOR_NUMBER_MASK: u8 = 0xf;
149const ENDPOINT_DESCRIPTOR_ATTRIBUTES_TYPE_MASK: u8 = 0x3;
150
151/// Endpoint types.
152#[derive(PartialEq, Eq)]
153pub enum EndpointType {
154    Control,
155    Isochronous,
156    Bulk,
157    Interrupt,
158}
159
160/// Endpoint Directions.
161#[derive(PartialEq, Eq, Clone, Copy)]
162pub enum EndpointDirection {
163    HostToDevice = 0,
164    DeviceToHost = 1,
165}
166/// Endpoint direction offset.
167pub const ENDPOINT_DIRECTION_OFFSET: u8 = 7;
168
169impl EndpointDescriptor {
170    // Get direction of this endpoint.
171    pub fn get_direction(&self) -> EndpointDirection {
172        let direction = self.bEndpointAddress & ENDPOINT_DESCRIPTOR_DIRECTION_MASK;
173        if direction != 0 {
174            EndpointDirection::DeviceToHost
175        } else {
176            EndpointDirection::HostToDevice
177        }
178    }
179
180    // Get endpoint number.
181    pub fn get_endpoint_number(&self) -> u8 {
182        self.bEndpointAddress & ENDPOINT_DESCRIPTOR_NUMBER_MASK
183    }
184
185    // Get endpoint type.
186    pub fn get_endpoint_type(&self) -> Option<EndpointType> {
187        let ep_type = self.bmAttributes & ENDPOINT_DESCRIPTOR_ATTRIBUTES_TYPE_MASK;
188        match ep_type {
189            0 => Some(EndpointType::Control),
190            1 => Some(EndpointType::Isochronous),
191            2 => Some(EndpointType::Bulk),
192            3 => Some(EndpointType::Interrupt),
193            _ => None,
194        }
195    }
196}
197
198/// Offset of data phase transfer direction.
199pub const DATA_PHASE_DIRECTION_OFFSET: u8 = 7;
200/// Bit mask of data phase transfer direction.
201pub const DATA_PHASE_DIRECTION: u8 = 1u8 << DATA_PHASE_DIRECTION_OFFSET;
202// Types of data phase transfer directions.
203#[derive(Copy, Clone, PartialEq, Eq)]
204pub enum ControlRequestDataPhaseTransferDirection {
205    HostToDevice = 0,
206    DeviceToHost = 1,
207}
208
209/// Offset of control request type.
210pub const CONTROL_REQUEST_TYPE_OFFSET: u8 = 5;
211/// Bit mask of control request type.
212pub const CONTROL_REQUEST_TYPE: u8 = 0b11 << CONTROL_REQUEST_TYPE_OFFSET;
213/// Request types.
214#[derive(PartialEq, Eq)]
215pub enum ControlRequestType {
216    Standard = 0,
217    Class = 1,
218    Vendor = 2,
219    Reserved = 3,
220}
221
222/// Recipient type bits.
223pub const REQUEST_RECIPIENT_TYPE: u8 = 0b1111;
224/// Recipient type of control request.
225#[derive(PartialEq, Eq)]
226pub enum ControlRequestRecipient {
227    Device = 0,
228    Interface = 1,
229    Endpoint = 2,
230    Other = 3,
231    Reserved,
232}
233
234/// Standard request defined in usb spec.
235#[derive(PartialEq, Eq)]
236pub enum StandardControlRequest {
237    GetStatus = 0,
238    ClearFeature = 1,
239    SetFeature = 3,
240    SetAddress = 5,
241    GetDescriptor = 6,
242    SetDescriptor = 7,
243    GetConfiguration = 8,
244    SetConfiguration = 9,
245    GetInterface = 10,
246    SetInterface = 11,
247    SynchFrame = 12,
248}
249
250/// RequestSetup is first part of control transfer buffer.
251#[repr(C, packed)]
252#[derive(Copy, Clone, Debug, FromBytes, Immutable, IntoBytes, KnownLayout)]
253pub struct UsbRequestSetup {
254    // USB Device Request. USB spec. rev. 2.0 9.3
255    pub request_type: u8, // bmRequestType
256    pub request: u8,      // bRequest
257    pub value: u16,       // wValue
258    pub index: u16,       // wIndex
259    pub length: u16,      // wLength
260}
261
262fn _assert_usb_request_setup() {
263    const_assert!(size_of::<UsbRequestSetup>() == 8);
264}
265
266impl UsbRequestSetup {
267    pub fn new(
268        request_type: u8,
269        request: u8,
270        value: u16,
271        index: u16,
272        length: u16,
273    ) -> UsbRequestSetup {
274        UsbRequestSetup {
275            request_type,
276            request,
277            value,
278            index,
279            length,
280        }
281    }
282
283    /// Get type of request.
284    pub fn get_type(&self) -> ControlRequestType {
285        let ty = (self.request_type & CONTROL_REQUEST_TYPE) >> CONTROL_REQUEST_TYPE_OFFSET;
286        match ty {
287            0 => ControlRequestType::Standard,
288            1 => ControlRequestType::Class,
289            2 => ControlRequestType::Vendor,
290            _ => ControlRequestType::Reserved,
291        }
292    }
293
294    /// Get request direction.
295    pub fn get_direction(&self) -> ControlRequestDataPhaseTransferDirection {
296        let dir = (self.request_type & DATA_PHASE_DIRECTION) >> DATA_PHASE_DIRECTION_OFFSET;
297        match dir {
298            0 => ControlRequestDataPhaseTransferDirection::HostToDevice,
299            _ => ControlRequestDataPhaseTransferDirection::DeviceToHost,
300        }
301    }
302
303    /// Get recipient of this control transfer.
304    pub fn get_recipient(&self) -> ControlRequestRecipient {
305        let recipient = self.request_type & REQUEST_RECIPIENT_TYPE;
306        match recipient {
307            0 => ControlRequestRecipient::Device,
308            1 => ControlRequestRecipient::Interface,
309            2 => ControlRequestRecipient::Endpoint,
310            3 => ControlRequestRecipient::Other,
311            _ => ControlRequestRecipient::Reserved,
312        }
313    }
314
315    /// Return the type of standard control request.
316    pub fn get_standard_request(&self) -> Option<StandardControlRequest> {
317        if self.get_type() != ControlRequestType::Standard {
318            return None;
319        }
320        match self.request {
321            // Defined in USB 2.0 Specification Table 9-4
322            0 => Some(StandardControlRequest::GetStatus),
323            1 => Some(StandardControlRequest::ClearFeature),
324            3 => Some(StandardControlRequest::SetFeature),
325            5 => Some(StandardControlRequest::SetAddress),
326            6 => Some(StandardControlRequest::GetDescriptor),
327            7 => Some(StandardControlRequest::SetDescriptor),
328            8 => Some(StandardControlRequest::GetConfiguration),
329            9 => Some(StandardControlRequest::SetConfiguration),
330            10 => Some(StandardControlRequest::GetInterface),
331            11 => Some(StandardControlRequest::SetInterface),
332            12 => Some(StandardControlRequest::SynchFrame),
333            _ => None,
334        }
335    }
336}
337
338/// Construct a bmRequestType value for a control request.
339pub fn control_request_type(
340    type_: ControlRequestType,
341    dir: ControlRequestDataPhaseTransferDirection,
342    recipient: ControlRequestRecipient,
343) -> u8 {
344    ((type_ as u8) << CONTROL_REQUEST_TYPE_OFFSET)
345        | ((dir as u8) << DATA_PHASE_DIRECTION_OFFSET)
346        | (recipient as u8)
347}
348
349/// USB device speed
350pub enum DeviceSpeed {
351    Full,
352    Low,
353    High,
354    Super,
355    SuperPlus,
356}
357
358#[cfg(test)]
359#[allow(clippy::unusual_byte_groupings)]
360mod tests {
361    use super::*;
362
363    #[test]
364    fn control_request_types() {
365        assert_eq!(
366            control_request_type(
367                ControlRequestType::Standard,
368                ControlRequestDataPhaseTransferDirection::HostToDevice,
369                ControlRequestRecipient::Device
370            ),
371            0b0_00_00000
372        );
373        assert_eq!(
374            control_request_type(
375                ControlRequestType::Standard,
376                ControlRequestDataPhaseTransferDirection::DeviceToHost,
377                ControlRequestRecipient::Device
378            ),
379            0b1_00_00000
380        );
381        assert_eq!(
382            control_request_type(
383                ControlRequestType::Standard,
384                ControlRequestDataPhaseTransferDirection::HostToDevice,
385                ControlRequestRecipient::Interface
386            ),
387            0b0_00_00001
388        );
389        assert_eq!(
390            control_request_type(
391                ControlRequestType::Class,
392                ControlRequestDataPhaseTransferDirection::HostToDevice,
393                ControlRequestRecipient::Device
394            ),
395            0b0_01_00000
396        );
397    }
398}