lsusb/
descriptors.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use num_traits::FromPrimitive;
6use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref};
7
8#[repr(u8)]
9#[derive(num_derive::FromPrimitive)]
10pub enum DescriptorType {
11    Device = 0x01,
12    Config = 0x02,
13    r#String = 0x03,
14    Interface = 0x04,
15    Endpoint = 0x05,
16    DeviceQualifier = 0x06,
17    OtherSpeedConfig = 0x07,
18    InterfacePower = 0x08,
19    InterfaceAssociation = 0x0b,
20    Hid = 0x21,
21    Hidreport = 0x22,
22    Hidphysical = 0x23,
23    CsInterface = 0x24,
24    CsEndpoint = 0x25,
25    SsEpCompanion = 0x30,
26    SsIsochEpCompanion = 0x31,
27}
28
29#[repr(C, packed)]
30#[derive(IntoBytes, KnownLayout, FromBytes, Immutable)]
31pub struct DeviceDescriptor {
32    pub b_length: u8,
33    pub b_descriptor_type: u8,
34    pub bcd_usb: u16,
35    pub b_device_class: u8,
36    pub b_device_sub_class: u8,
37    pub b_device_protocol: u8,
38    pub b_max_packet_size0: u8,
39    pub id_vendor: u16,
40    pub id_product: u16,
41    pub bcd_device: u16,
42    pub i_manufacturer: u8,
43    pub i_product: u8,
44    pub i_serial_number: u8,
45    pub b_num_configurations: u8,
46}
47
48#[repr(C, packed)]
49#[derive(IntoBytes, KnownLayout, FromBytes, Immutable)]
50pub struct ConfigurationDescriptor {
51    pub b_length: u8,
52    pub b_descriptor_type: u8,
53    pub w_total_length: u16,
54    pub b_num_interfaces: u8,
55    pub b_configuration_value: u8,
56    pub i_configuration: u8,
57    pub bm_attributes: u8,
58    pub b_max_power: u8,
59}
60
61#[repr(C, packed)]
62#[derive(IntoBytes, KnownLayout, FromBytes, Immutable)]
63pub struct InterfaceInfoDescriptor {
64    pub b_length: u8,
65    pub b_descriptor_type: u8,
66    pub b_interface_number: u8,
67    pub b_alternate_setting: u8,
68    pub b_num_endpoints: u8,
69    pub b_interface_class: u8,
70    pub b_interface_sub_class: u8,
71    pub b_interface_protocol: u8,
72    pub i_interface: u8,
73}
74
75#[repr(C, packed)]
76#[derive(IntoBytes, KnownLayout, FromBytes, Immutable)]
77pub struct EndpointInfoDescriptor {
78    pub b_length: u8,
79    pub b_descriptor_type: u8,
80    pub b_endpoint_address: u8,
81    pub bm_attributes: u8,
82    pub w_max_packet_size: u16,
83    pub b_interval: u8,
84}
85
86#[repr(C, packed)]
87#[derive(IntoBytes, KnownLayout, FromBytes, Immutable)]
88pub struct HidDescriptor {
89    pub b_length: u8,
90    pub b_descriptor_type: u8,
91    pub bcd_hid: u16,
92    pub b_country_code: u8,
93    pub b_num_descriptors: u8,
94}
95
96#[repr(C, packed)]
97#[derive(IntoBytes, KnownLayout, FromBytes, Immutable)]
98pub struct SsEpCompDescriptorInfo {
99    pub b_length: u8,
100    pub b_descriptor_type: u8,
101    pub b_max_burst: u8,
102    pub bm_attributes: u8,
103    pub w_bytes_per_interval: u8,
104}
105
106#[repr(C, packed)]
107#[derive(IntoBytes, KnownLayout, FromBytes, Immutable)]
108pub struct SsIsochEpCompDescriptor {
109    pub b_length: u8,
110    pub b_descriptor_type: u8,
111    pub w_reserved: u16,
112    pub dw_bytes_per_interval: u32,
113}
114
115#[repr(C, packed)]
116#[derive(IntoBytes, KnownLayout, FromBytes, Immutable)]
117pub struct InterfaceAssocDescriptor {
118    pub b_length: u8,
119    pub b_descriptor_type: u8,
120    pub b_first_interface: u8,
121    pub b_interface_count: u8,
122    pub b_function_class: u8,
123    pub b_function_sub_class: u8,
124    pub b_function_protocol: u8,
125    pub i_function: u8,
126}
127
128#[repr(C, packed)]
129#[derive(IntoBytes, KnownLayout, FromBytes, Immutable)]
130pub struct HidDescriptorEntry {
131    pub b_descriptor_type: u8,
132    pub w_descriptor_length: u16,
133}
134
135pub struct DescriptorIterator<'a> {
136    offset: usize,
137    buffer: &'a [u8],
138}
139
140impl<'a> DescriptorIterator<'a> {
141    pub fn new(buffer: &'a [u8]) -> DescriptorIterator<'a> {
142        DescriptorIterator { offset: 0, buffer }
143    }
144}
145
146pub struct HidDescriptorIter<'a> {
147    offset: usize,
148    buffer: &'a [u8],
149}
150
151impl<'a> HidDescriptorIter<'a> {
152    fn new(buffer: &'a [u8]) -> HidDescriptorIter<'a> {
153        HidDescriptorIter { offset: std::mem::size_of::<HidDescriptor>(), buffer }
154    }
155
156    pub fn get(&self) -> Ref<&[u8], HidDescriptor> {
157        Ref::from_bytes(&self.buffer[0..(std::mem::size_of::<HidDescriptor>())]).unwrap()
158    }
159}
160
161impl<'a> Iterator for HidDescriptorIter<'a> {
162    type Item = Ref<&'a [u8], HidDescriptorEntry>;
163
164    fn next(&mut self) -> Option<Self::Item> {
165        let len = std::mem::size_of::<HidDescriptorEntry>();
166        if self.offset + len > self.buffer.len() {
167            return None;
168        }
169        let slice = &self.buffer[self.offset..self.offset + len];
170        self.offset += len;
171
172        Ref::from_bytes(slice).ok()
173    }
174}
175
176pub enum Descriptor<'a> {
177    Config(Ref<&'a [u8], ConfigurationDescriptor>),
178    Interface(Ref<&'a [u8], InterfaceInfoDescriptor>),
179    InterfaceAssociation(Ref<&'a [u8], InterfaceAssocDescriptor>),
180    Endpoint(Ref<&'a [u8], EndpointInfoDescriptor>),
181    Hid(HidDescriptorIter<'a>),
182    SsEpCompanion(Ref<&'a [u8], SsEpCompDescriptorInfo>),
183    SsIsochEpCompanion(Ref<&'a [u8], SsIsochEpCompDescriptor>),
184    Unknown(&'a [u8]),
185}
186
187impl<'a> Iterator for DescriptorIterator<'a> {
188    type Item = Descriptor<'a>;
189
190    fn next(&mut self) -> Option<Self::Item> {
191        if self.offset + 2 > self.buffer.len() {
192            return None;
193        }
194
195        let length = self.buffer[self.offset] as usize;
196        let desc_type = self.buffer[self.offset + 1];
197
198        if length == 0 || length > self.buffer.len() {
199            return None;
200        }
201
202        let slice = &self.buffer[self.offset..self.offset + length];
203
204        let desc = match DescriptorType::from_u8(desc_type) {
205            Some(DescriptorType::Config) => {
206                Ref::from_bytes(slice).map(|d| Descriptor::Config(d)).ok()
207            }
208            Some(DescriptorType::Interface) => {
209                Ref::from_bytes(slice).map(|d| Descriptor::Interface(d)).ok()
210            }
211            Some(DescriptorType::Endpoint) => {
212                Ref::from_bytes(slice).map(|d| Descriptor::Endpoint(d)).ok()
213            }
214            Some(DescriptorType::Hid) => {
215                if length < std::mem::size_of::<HidDescriptor>() {
216                    None
217                } else {
218                    Some(Descriptor::Hid(HidDescriptorIter::new(
219                        &self.buffer[self.offset..self.offset + length],
220                    )))
221                }
222            }
223            Some(DescriptorType::SsEpCompanion) => {
224                Ref::from_bytes(slice).map(|d| Descriptor::SsEpCompanion(d)).ok()
225            }
226            Some(DescriptorType::SsIsochEpCompanion) => {
227                Ref::from_bytes(slice).map(|d| Descriptor::SsIsochEpCompanion(d)).ok()
228            }
229            Some(DescriptorType::InterfaceAssociation) => {
230                Ref::from_bytes(slice).map(|d| Descriptor::InterfaceAssociation(d)).ok()
231            }
232            _ => Some(Descriptor::Unknown(slice)),
233        };
234
235        self.offset += length;
236        desc
237    }
238}
239
240pub struct UsbSpeed(pub u32);
241
242impl std::fmt::Display for UsbSpeed {
243    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244        match self.0 {
245            1 => write!(f, "FULL"),
246            2 => write!(f, "LOW"),
247            3 => write!(f, "HIGH"),
248            4 => write!(f, "SUPER"),
249            _ => write!(f, "<unknown>"),
250        }
251    }
252}
253
254pub const EN_US: u16 = 0x0409;