opentitanlib/io/usb/
desc.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use anyhow::{Result, anyhow};
6use derive_more::{TryFrom, TryInto};
7use zerocopy::byteorder::little_endian::U16;
8use zerocopy::{FromBytes, Immutable, KnownLayout, Unaligned};
9
10#[derive(Copy, Clone, Eq, PartialEq, Debug, TryFrom, TryInto)]
11#[try_from(repr)]
12#[repr(u8)]
13pub enum DescriptorType {
14    Device = 1,
15    Configuration,
16    String,
17    Interface,
18    Endpoint,
19}
20
21#[derive(Copy, Clone, Eq, PartialEq, Debug, TryFrom, TryInto)]
22#[try_from(repr)]
23#[repr(u8)]
24pub enum TransferType {
25    Control,
26    Isochronous,
27    Bulk,
28    Interrupt,
29}
30
31#[derive(Copy, Clone, Eq, PartialEq, Debug)]
32pub enum Direction {
33    In,
34    Out,
35}
36
37#[derive(Clone, FromBytes, KnownLayout, Immutable, Unaligned, Debug)]
38#[repr(C)]
39pub struct DeviceDescriptor {
40    pub length: u8,
41    pub desc_type: u8,
42    pub usb_version: U16,
43    pub class: u8,
44    pub subclass: u8,
45    pub protocol: u8,
46    pub max_pkt_size: u8,
47    pub vendor_id: U16,
48    pub product_id: U16,
49    pub dev_version: U16,
50    pub manuf_idx: u8,
51    pub product_idx: u8,
52    pub serial_idx: u8,
53    pub num_config: u8,
54}
55
56pub struct Device<'a> {
57    bytes: &'a [u8],
58}
59
60impl<'a> Device<'a> {
61    pub fn new(bytes: &'a [u8]) -> Self {
62        Device { bytes }
63    }
64
65    /// Return the entire configuration (all descriptors).
66    pub fn as_bytes(&self) -> &'a [u8] {
67        self.bytes
68    }
69
70    /// Return the configuration descriptor.
71    pub fn descriptor(&self) -> Result<&'a DeviceDescriptor> {
72        DeviceDescriptor::ref_from_prefix(self.bytes)
73            .map(|(desc, _)| desc)
74            .map_err(|_err| anyhow!("Cannot parse device descriptor"))
75    }
76}
77
78#[derive(Clone, FromBytes, KnownLayout, Immutable, Unaligned, Debug)]
79#[repr(C)]
80pub struct ConfigurationDescriptor {
81    pub length: u8,
82    pub desc_type: u8,
83    pub tot_length: U16,
84    pub num_intf: u8,
85    pub config_val: u8,
86    pub str_idx: u8,
87    pub attr: u8,
88    pub max_power: u8,
89}
90
91impl ConfigurationDescriptor {
92    pub fn string_index(&self) -> Option<u8> {
93        if self.str_idx == 0 {
94            None
95        } else {
96            Some(self.str_idx)
97        }
98    }
99}
100
101#[derive(Clone, FromBytes, KnownLayout, Immutable, Unaligned, Debug)]
102#[repr(C)]
103pub struct InterfaceDescriptor {
104    pub length: u8,
105    pub desc_type: u8,
106    pub intf_num: u8,
107    pub alt_setting: u8,
108    pub num_ep: u8,
109    pub class: u8,
110    pub subclass: u8,
111    pub protocol: u8,
112    pub str_idx: u8,
113}
114
115impl InterfaceDescriptor {
116    pub fn string_index(&self) -> Option<u8> {
117        if self.str_idx == 0 {
118            None
119        } else {
120            Some(self.str_idx)
121        }
122    }
123}
124
125#[derive(Clone, FromBytes, KnownLayout, Immutable, Unaligned, Debug)]
126#[repr(C)]
127pub struct EndpointDescriptor {
128    pub length: u8,
129    pub desc_type: u8,
130    pub addr: u8,
131    pub attr: u8,
132    pub max_pkt_size: U16,
133    pub interval: u8,
134}
135
136impl EndpointDescriptor {
137    pub fn transfer_type(&self) -> TransferType {
138        // Conversation cannot fail (all cases are covered).
139        (self.attr & 0x3).try_into().unwrap()
140    }
141
142    pub fn direction(&self) -> Direction {
143        if (self.addr & 0x80) == 0 {
144            Direction::Out
145        } else {
146            Direction::In
147        }
148    }
149}
150
151pub struct Configuration<'a> {
152    bytes: &'a [u8],
153}
154
155impl<'a> Configuration<'a> {
156    pub fn new(bytes: &'a [u8]) -> Self {
157        Configuration { bytes }
158    }
159
160    /// Return the entire configuration (all descriptors).
161    pub fn as_bytes(&self) -> &'a [u8] {
162        self.bytes
163    }
164
165    /// Return the configuration descriptor.
166    pub fn descriptor(&self) -> Result<&'a ConfigurationDescriptor> {
167        ConfigurationDescriptor::ref_from_prefix(self.bytes)
168            .map(|(desc, _)| desc)
169            .map_err(|_err| anyhow!("Cannot parse configuration descriptor"))
170    }
171
172    /// Iterate over all interfaces.
173    pub fn interface_alt_settings(&'a self) -> impl Iterator<Item = Interface<'a>> {
174        DescOffsetIter { bytes: self.bytes }.filter_map(|(_, desc_type, bytes)| {
175            if desc_type == DescriptorType::Interface as u8 {
176                Some(Interface { bytes })
177            } else {
178                None
179            }
180        })
181    }
182}
183
184struct DescOffsetIter<'a> {
185    bytes: &'a [u8],
186}
187
188impl<'a> Iterator for DescOffsetIter<'a> {
189    /// (descriptor size, descriptor type, slice)
190    type Item = (usize, u8, &'a [u8]);
191
192    fn next(&mut self) -> Option<Self::Item> {
193        // We need at least two bytes to get the type of this descriptor.
194        if self.bytes.len() < 2 {
195            None
196        } else {
197            let sz = self.bytes[0] as usize;
198            let next = Some((sz, self.bytes[1], self.bytes));
199            self.bytes = if sz < self.bytes.len() {
200                &self.bytes[sz..]
201            } else {
202                &[]
203            };
204            next
205        }
206    }
207}
208
209pub struct Interface<'a> {
210    bytes: &'a [u8],
211}
212
213impl<'a> Interface<'a> {
214    /// Return the interface's descriptor.
215    pub fn descriptor(&self) -> Result<&'a InterfaceDescriptor> {
216        InterfaceDescriptor::ref_from_prefix(self.bytes)
217            .map(|(desc, _)| desc)
218            .map_err(|_err| anyhow!("Cannot parse interface descriptor"))
219    }
220
221    fn subdescriptor_iter(&self) -> impl Iterator<Item = (usize, u8, &'a [u8])> {
222        DescOffsetIter { bytes: self.bytes }
223            .skip(1)
224            .take_while(|(_, desc_type, _)| {
225                // Stop when we reach the next interface.
226                *desc_type != DescriptorType::Interface as u8
227            })
228    }
229
230    /// Iterate over all endpoints.
231    pub fn endpoints(&self) -> impl Iterator<Item = Endpoint<'a>> {
232        self.subdescriptor_iter()
233            .filter_map(|(_, desc_type, bytes)| {
234                if desc_type == DescriptorType::Endpoint as u8 {
235                    Some(Endpoint { bytes })
236                } else {
237                    None
238                }
239            })
240    }
241
242    pub fn subdescriptors(&self) -> impl Iterator<Item = &'a [u8]> {
243        self.subdescriptor_iter().filter_map(|(sz, _, bytes)| {
244            // Ignore invalid descriptors (size would go beyond end of buffer).
245            if sz <= bytes.len() {
246                Some(&bytes[..sz])
247            } else {
248                None
249            }
250        })
251    }
252}
253
254pub struct Endpoint<'a> {
255    bytes: &'a [u8],
256}
257
258impl<'a> Endpoint<'a> {
259    pub fn descriptor(&self) -> Result<&'a EndpointDescriptor> {
260        EndpointDescriptor::ref_from_prefix(self.bytes)
261            .map(|(desc, _)| desc)
262            .map_err(|_err| anyhow!("Cannot parse endpoint descriptor"))
263    }
264}