Skip to main content

usb_if/descriptor/
mod.rs

1use alloc::{string::String, vec::Vec};
2use core::num::NonZero;
3
4use crate::transfer::Direction;
5
6mod class_code;
7mod lang_id;
8mod parser;
9
10pub use class_code::*;
11pub use lang_id::*;
12pub use parser::decode_string_descriptor;
13
14#[repr(C)]
15#[derive(Debug, Clone)]
16pub struct DescriptorType(pub u8);
17
18impl DescriptorType {
19    pub const DEVICE: Self = Self(0x01);
20    pub const CONFIGURATION: Self = Self(0x02);
21    pub const STRING: Self = Self(0x03);
22    pub const INTERFACE: Self = Self(0x04);
23    pub const ENDPOINT: Self = Self(0x05);
24    // Reserved 6
25    // Reserved 7
26    pub const INTERFACE_POWER: Self = Self(0x08);
27    pub const OTG: Self = Self(0x09);
28    pub const DEBUG: Self = Self(0x0A);
29    pub const INTERFACE_ASSOCIATION: Self = Self(0x0B);
30    pub const BOS: Self = Self(0x0F);
31    pub const DEVICE_CAPABILITY: Self = Self(0x10);
32    pub const SUPERSPEED_USB_ENDPOINT_COMPANION: Self = Self(0x30);
33    pub const SUPERSPEEDPLUS_ISOCHRONOUS_ENDPOINT_COMPANION: Self = Self(0x31);
34    pub const HUB: Self = Self(0x29);
35}
36
37impl From<u8> for DescriptorType {
38    fn from(value: u8) -> Self {
39        Self(value)
40    }
41}
42
43impl From<DescriptorType> for u8 {
44    fn from(desc_type: DescriptorType) -> Self {
45        desc_type.0
46    }
47}
48
49#[derive(Debug, Clone, Copy)]
50#[repr(C)]
51pub struct DeviceDescriptorBase {
52    pub length: u8,
53    pub descriptor_type: u8,
54    pub usb_version: u16,
55    pub class: u8,
56    pub subclass: u8,
57    pub protocol: u8,
58    pub max_packet_size_0: u8,
59}
60
61impl DeviceDescriptorBase {
62    pub fn class(&self) -> Class {
63        Class::from_class_and_subclass(self.class, self.subclass, self.protocol)
64    }
65}
66
67#[derive(Debug, Clone)]
68pub struct DeviceDescriptor {
69    pub usb_version: u16,
70    pub class: u8,
71    pub subclass: u8,
72    pub protocol: u8,
73    pub max_packet_size_0: u8,
74    pub vendor_id: u16,
75    pub product_id: u16,
76    pub device_version: u16,
77    pub manufacturer_string_index: Option<NonZero<u8>>,
78    pub product_string_index: Option<NonZero<u8>>,
79    pub serial_number_string_index: Option<NonZero<u8>>,
80    pub num_configurations: u8,
81}
82
83impl DeviceDescriptor {
84    pub fn parse(data: &[u8]) -> Option<Self> {
85        parser::DeviceDescriptor::new(data).map(Into::into)
86    }
87
88    pub const LEN: usize = 18;
89
90    pub fn class(&self) -> Class {
91        Class::from_class_and_subclass(self.class, self.subclass, self.protocol)
92    }
93}
94
95#[derive(Debug, Clone)]
96pub struct InterfaceDescriptor {
97    pub interface_number: u8,
98    pub alternate_setting: u8,
99    pub class: u8,
100    pub subclass: u8,
101    pub protocol: u8,
102    pub string_index: Option<NonZero<u8>>,
103    pub string: Option<String>,
104    pub num_endpoints: u8,
105    pub endpoints: Vec<EndpointDescriptor>,
106}
107
108impl InterfaceDescriptor {
109    pub fn class(&self) -> Class {
110        Class::from_class_and_subclass(self.class, self.subclass, self.protocol)
111    }
112}
113
114/// Endpoint type.
115#[derive(Debug, Copy, Clone, PartialEq, Eq)]
116pub enum EndpointType {
117    /// Control endpoint.
118    Control     = 0,
119
120    /// Isochronous endpoint.
121    Isochronous = 1,
122
123    /// Bulk endpoint.
124    Bulk        = 2,
125
126    /// Interrupt endpoint.
127    Interrupt   = 3,
128}
129
130#[derive(Debug, Clone)]
131pub struct EndpointDescriptor {
132    pub address: u8,
133    pub max_packet_size: u16,
134    pub transfer_type: EndpointType,
135    pub direction: Direction,
136    pub packets_per_microframe: usize,
137    pub interval: u8,
138}
139
140impl EndpointDescriptor {
141    pub fn dci(&self) -> u8 {
142        // DCI = (endpoint_number * 2) + direction
143        // Control endpoint always has DCI 1
144        let endpoint_number = self.address & 0x0F; // Extract endpoint number (low 4 bits)
145        (endpoint_number * 2)
146            + match self.transfer_type {
147                EndpointType::Control => 1, // Control endpoint always has DCI 1
148                _ => {
149                    if self.direction == Direction::In {
150                        1
151                    } else {
152                        0
153                    }
154                }
155            }
156    }
157}
158
159#[derive(Debug, Clone)]
160pub struct InterfaceDescriptors {
161    pub interface_number: u8,
162    pub alt_settings: Vec<InterfaceDescriptor>,
163}
164
165impl InterfaceDescriptors {
166    pub fn first_alt_setting(&self) -> InterfaceDescriptor {
167        self.alt_settings.first().cloned().unwrap()
168    }
169}
170
171#[derive(Debug, Clone)]
172pub struct ConfigurationDescriptor {
173    pub num_interfaces: u8,
174    pub configuration_value: u8,
175    pub attributes: u8,
176    pub max_power: u8,
177    pub string_index: Option<NonZero<u8>>,
178    pub string: Option<String>,
179    pub interfaces: Vec<InterfaceDescriptors>,
180    pub raw: Vec<u8>,
181}
182
183impl ConfigurationDescriptor {
184    pub fn parse(data: &[u8]) -> Option<Self> {
185        parser::ConfigurationDescriptor::new(data).map(Into::into)
186    }
187
188    pub const LEN: usize = 9;
189}
190
191impl From<parser::DeviceDescriptor> for DeviceDescriptor {
192    fn from(desc: parser::DeviceDescriptor) -> Self {
193        DeviceDescriptor {
194            usb_version: desc.usb_version(),
195            class: desc.class(),
196            subclass: desc.subclass(),
197            protocol: desc.protocol(),
198            max_packet_size_0: desc.max_packet_size_0(),
199            vendor_id: desc.vendor_id(),
200            product_id: desc.product_id(),
201            device_version: desc.device_version(),
202            manufacturer_string_index: desc.manufacturer_string_index(),
203            product_string_index: desc.product_string_index(),
204            serial_number_string_index: desc.serial_number_string_index(),
205            num_configurations: desc.num_configurations(),
206        }
207    }
208}
209
210impl From<parser::EndpointDescriptor<'_>> for EndpointDescriptor {
211    fn from(desc: parser::EndpointDescriptor) -> Self {
212        EndpointDescriptor {
213            address: desc.address(),
214            max_packet_size: desc.max_packet_size() as _,
215            direction: desc.direction(),
216            transfer_type: desc.transfer_type(),
217            packets_per_microframe: desc.packets_per_microframe() as usize,
218            interval: desc.interval(),
219        }
220    }
221}
222
223impl From<parser::ConfigurationDescriptor<'_>> for ConfigurationDescriptor {
224    fn from(desc: parser::ConfigurationDescriptor) -> Self {
225        ConfigurationDescriptor {
226            num_interfaces: desc.num_interfaces(),
227            configuration_value: desc.configuration_value(),
228            attributes: desc.attributes(),
229            max_power: desc.max_power(),
230            string_index: desc.string_index(),
231            interfaces: desc.interfaces().map(InterfaceDescriptors::from).collect(),
232            string: None,
233            raw: desc.as_bytes().to_vec(),
234        }
235    }
236}
237
238impl From<parser::InterfaceDescriptor<'_>> for InterfaceDescriptor {
239    fn from(desc: parser::InterfaceDescriptor) -> Self {
240        InterfaceDescriptor {
241            interface_number: desc.interface_number(),
242            alternate_setting: desc.alternate_setting(),
243            class: desc.class(),
244            subclass: desc.subclass(),
245            protocol: desc.protocol(),
246            string_index: desc.string_index(),
247            num_endpoints: desc.num_endpoints(),
248            endpoints: desc.endpoints().map(EndpointDescriptor::from).collect(),
249            string: None,
250        }
251    }
252}
253
254impl From<parser::InterfaceDescriptors<'_>> for InterfaceDescriptors {
255    fn from(desc: parser::InterfaceDescriptors) -> Self {
256        InterfaceDescriptors {
257            interface_number: desc.interface_number(),
258            alt_settings: desc.alt_settings().map(InterfaceDescriptor::from).collect(),
259        }
260    }
261}