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