1use crate::debug;
2
3#[repr(C)]
48#[cfg_attr(feature = "defmt", derive(defmt::Format))]
49#[cfg_attr(feature = "std", derive(Debug))]
50#[allow(non_snake_case)] pub struct SetupPacket {
52 pub bmRequestType: u8,
54 pub bRequest: u8,
56 pub wValue: u16,
58 pub wIndex: u16,
60 pub wLength: u16,
64}
65
66#[repr(C)]
68#[cfg_attr(feature = "defmt", derive(defmt::Format))]
69#[cfg_attr(feature = "std", derive(Debug))]
70#[allow(non_snake_case)] #[allow(missing_docs)]
72pub struct DeviceDescriptor {
73 pub bLength: u8,
74 pub bDescriptorType: u8,
75 pub bcdUSB: [u8; 2],
76 pub bDeviceClass: u8,
77 pub bDeviceSubClass: u8,
78 pub bDeviceProtocol: u8,
79 pub bMaxPacketSize0: u8,
80
81 pub idVendor: [u8; 2],
82 pub idProduct: [u8; 2],
83 pub bcdDevice: [u8; 2],
84 pub iManufacturer: u8,
85 pub iProduct: u8,
86 pub iSerialNumber: u8,
87 pub bNumConfigurations: u8,
88}
89
90#[repr(C)]
92#[cfg_attr(feature = "defmt", derive(defmt::Format))]
93#[cfg_attr(feature = "std", derive(Debug))]
94#[derive(Copy, Clone)]
95#[allow(non_snake_case)] #[allow(missing_docs)]
97pub struct ConfigurationDescriptor {
98 pub bLength: u8,
99 pub bDescriptorType: u8,
100 pub wTotalLength: [u8; 2],
101 pub bNumInterfaces: u8,
102 pub bConfigurationValue: u8,
103 pub iConfiguration: u8,
104 pub bmAttributes: u8,
105 pub bMaxPower: u8,
106}
107
108unsafe impl bytemuck::Zeroable for ConfigurationDescriptor {}
110unsafe impl bytemuck::Pod for ConfigurationDescriptor {}
112
113#[repr(C)]
115#[cfg_attr(feature = "defmt", derive(defmt::Format))]
116#[cfg_attr(feature = "std", derive(Debug))]
117#[derive(Copy, Clone)]
118#[allow(non_snake_case)] #[allow(missing_docs)]
120pub struct InterfaceDescriptor {
121 pub bLength: u8,
122 pub bDescriptorType: u8,
123 pub bInterfaceNumber: u8,
124 pub bAlternateSetting: u8,
125 pub bNumEndpoints: u8,
126 pub bInterfaceClass: u8,
127 pub bInterfaceSubClass: u8,
128 pub bInterfaceProtocol: u8,
129 pub iInterface: u8,
130}
131
132unsafe impl bytemuck::Zeroable for InterfaceDescriptor {}
134unsafe impl bytemuck::Pod for InterfaceDescriptor {}
136
137#[repr(C)]
139#[cfg_attr(feature = "defmt", derive(defmt::Format))]
140#[cfg_attr(feature = "std", derive(Debug))]
141#[derive(Copy, Clone)]
142#[allow(non_snake_case)] #[allow(missing_docs)]
144pub struct EndpointDescriptor {
145 pub bLength: u8,
146 pub bDescriptorType: u8,
147 pub bEndpointAddress: u8,
148 pub bmAttributes: u8,
149 pub wMaxPacketSize: [u8; 2],
150 pub bInterval: u8,
151}
152
153unsafe impl bytemuck::Zeroable for EndpointDescriptor {}
155unsafe impl bytemuck::Pod for EndpointDescriptor {}
157
158#[repr(C)]
160#[cfg_attr(feature = "defmt", derive(defmt::Format))]
161#[cfg_attr(feature = "std", derive(Debug))]
162#[derive(Copy, Clone)]
163#[allow(non_snake_case)] #[allow(missing_docs)]
165pub struct HubDescriptor {
166 bDescLength: u8,
167 bDescriptorType: u8,
168 bNbrPorts: u8,
169 wHubCharacteristics: [u8; 2],
170 bPwrOn2PwrGood: u8,
171 bHubContrCurrent: u8,
172 DeviceRemovable: u8, PortPwrCtrlMask: u8, }
175
176unsafe impl bytemuck::Zeroable for HubDescriptor {}
178unsafe impl bytemuck::Pod for HubDescriptor {}
180
181pub const DEVICE_TO_HOST: u8 = 0x80;
185
186pub const HOST_TO_DEVICE: u8 = 0;
188
189pub const STANDARD_REQUEST: u8 = 0;
191
192pub const CLASS_REQUEST: u8 = 0x20;
194
195pub const VENDOR_REQUEST: u8 = 0x40;
197
198pub const RECIPIENT_DEVICE: u8 = 0;
200
201pub const RECIPIENT_INTERFACE: u8 = 1;
203
204pub const RECIPIENT_ENDPOINT: u8 = 2;
206
207pub const RECIPIENT_OTHER: u8 = 3;
209
210pub const GET_STATUS: u8 = 0;
214
215pub const CLEAR_FEATURE: u8 = 1;
217
218pub const SET_FEATURE: u8 = 3;
220
221pub const SET_ADDRESS: u8 = 5;
223
224pub const GET_DESCRIPTOR: u8 = 6;
226
227pub const SET_DESCRIPTOR: u8 = 7;
229
230pub const SET_CONFIGURATION: u8 = 9;
232
233pub const DEVICE_DESCRIPTOR: u8 = 1;
237
238pub const CONFIGURATION_DESCRIPTOR: u8 = 2;
240
241pub const STRING_DESCRIPTOR: u8 = 3;
243
244pub const INTERFACE_DESCRIPTOR: u8 = 4;
246
247pub const ENDPOINT_DESCRIPTOR: u8 = 5;
249
250pub const HUB_DESCRIPTOR: u8 = 0x29;
252
253pub const HUB_CLASSCODE: u8 = 9;
257
258pub const PORT_RESET: u16 = 4;
262
263pub const PORT_POWER: u16 = 8;
265
266#[cfg_attr(feature = "defmt", derive(defmt::Format))]
268#[cfg_attr(feature = "std", derive(Debug))]
269#[derive(Copy, Clone, PartialEq, Eq)]
270#[allow(missing_docs)]
271pub enum EndpointType {
272 Control = 0,
273 Isochronous = 1,
274 Bulk = 2,
275 Interrupt = 3,
276}
277
278#[cfg_attr(feature = "defmt", derive(defmt::Format))]
280#[cfg_attr(feature = "std", derive(Debug))]
281#[derive(Copy, Clone, PartialEq, Eq)]
282pub enum Direction {
283 In,
285 Out,
287}
288
289pub trait DescriptorVisitor {
293 fn on_configuration(&mut self, _c: &ConfigurationDescriptor) {}
295
296 fn on_interface(&mut self, _i: &InterfaceDescriptor) {}
298
299 fn on_endpoint(&mut self, _e: &EndpointDescriptor) {}
301
302 fn on_other(&mut self, _d: &[u8]) {}
304}
305
306pub struct ShowDescriptors;
308
309impl DescriptorVisitor for ShowDescriptors {
310 fn on_configuration(&mut self, c: &ConfigurationDescriptor) {
311 debug::println!("{:?}", c);
312 }
313 fn on_interface(&mut self, i: &InterfaceDescriptor) {
314 debug::println!(" {:?}", i);
315 }
316 fn on_endpoint(&mut self, e: &EndpointDescriptor) {
317 debug::println!(" {:?}", e);
318 }
319 fn on_other(&mut self, d: &[u8]) {
320 let dlen = d[0];
321 let dtype = d[1];
322 let domain = match dtype & 0x60 {
323 0x00 => "standard",
324 0x20 => "class",
325 0x40 => "vendor",
326 _ => "reserved",
327 };
328 debug::println!(" {} type {} len {} skipped", domain, dtype, dlen);
329 }
330}
331
332pub fn parse_descriptors(buf: &[u8], v: &mut impl DescriptorVisitor) {
340 let mut index = 0;
341
342 while buf.len() > index + 2 {
343 let dlen = buf[index] as usize;
344 let dtype = buf[index + 1];
345
346 if dlen < 2 || buf.len() < index + dlen {
347 return;
348 }
349
350 match dtype {
351 CONFIGURATION_DESCRIPTOR => {
352 let min_dlen =
353 Ord::min(dlen, size_of::<ConfigurationDescriptor>());
354
355 if let Ok(c) =
356 bytemuck::try_from_bytes(&buf[index..index + min_dlen])
357 {
358 v.on_configuration(c);
359 }
360 }
361 INTERFACE_DESCRIPTOR => {
362 let min_dlen =
363 Ord::min(dlen, size_of::<InterfaceDescriptor>());
364
365 if let Ok(i) =
366 bytemuck::try_from_bytes(&buf[index..index + min_dlen])
367 {
368 v.on_interface(i);
369 }
370 }
371 ENDPOINT_DESCRIPTOR => {
372 let min_dlen = Ord::min(dlen, size_of::<EndpointDescriptor>());
373
374 if let Ok(e) =
375 bytemuck::try_from_bytes(&buf[index..index + min_dlen])
376 {
377 v.on_endpoint(e);
378 }
379 }
380 _ => {
381 v.on_other(&buf[index..(index + dlen)]);
382 }
383 }
384
385 index += dlen;
386 }
387}
388
389#[cfg(all(test, feature = "std"))]
390#[path = "tests/wire.rs"]
391mod tests;