1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3pub enum RegWidth {
4 U8,
5 U16,
6 U32,
7 U64,
8}
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum MemoryBarrierType {
13 Read,
14 Write,
15 Full,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum HubRequest {
23 GetHubDescriptor,
24 GetHubStatus,
25 SetHubFeature,
26 ClearHubFeature,
27 GetPortStatus,
28 SetPortFeature,
29 ClearPortFeature,
30 GetHubDescriptor16, }
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum PortFeature {
38 Connection = 0,
39 Enable = 1,
40 Suspend = 2,
41 OverCurrent = 3,
42 Reset = 4,
43 Power = 8,
44 LowSpeed = 9,
45 CConnection = 16, CEnable = 17, CSuspend = 18, COverCurrent = 19, CReset = 20, }
51
52const USB_MAXCHILDREN: usize = 8;
53const DEVICE_BITMAP_BYTES: usize = (USB_MAXCHILDREN + 1 + 7).div_ceil(8);
54
55#[derive(Clone, Copy)]
56#[allow(non_snake_case)]
57#[repr(C, packed)]
58pub struct HubDescriptor {
59 pub bDescLength: u8,
60 pub bDescriptorType: u8,
61 pub bNbrPorts: u8,
62 wHubCharacteristics: u16,
63 pub bPwrOn2PwrGood: u8,
64 pub bHubContrCurrent: u8,
65 pub u: HubDescriptorVariant,
66}
67
68impl HubDescriptor {
69 pub fn hub_characteristics(&self) -> u16 {
70 u16::from_le(self.wHubCharacteristics)
71 }
72
73 pub fn from_bytes(data: &[u8]) -> Option<&Self> {
77 if data.is_empty() {
78 return None;
79 }
80
81 let length = data[0] as usize;
82 if data.len() < length {
83 return None;
84 }
85
86 if data.len() < 2 || data[1] != 0x29 {
88 return None;
89 }
90
91 Some(unsafe { &*(data.as_ptr() as *const HubDescriptor) })
93 }
94}
95
96#[derive(Clone, Copy)]
97#[repr(C, packed)]
98pub union HubDescriptorVariant {
99 pub hs: HighSpeedHubDescriptorTail,
100 pub ss: SuperSpeedHubDescriptorTail,
101}
102
103#[derive(Debug, Clone, Copy)]
104#[repr(C, packed)]
105pub struct HighSpeedHubDescriptorTail {
106 pub device_removable: [u8; DEVICE_BITMAP_BYTES],
107 pub port_pwr_ctrl_mask: [u8; DEVICE_BITMAP_BYTES],
108}
109
110#[allow(non_snake_case)]
111#[derive(Debug, Clone, Copy)]
112#[repr(C, packed)]
113pub struct SuperSpeedHubDescriptorTail {
114 pub bHubHdrDecLat: u8,
115 wHubDelay: u16,
116 device_removable: u16,
117}
118
119impl SuperSpeedHubDescriptorTail {
120 pub fn hub_delay(&self) -> u16 {
121 u16::from_le(self.wHubDelay)
122 }
123 pub fn device_removable(&self) -> u16 {
124 u16::from_le(self.device_removable)
125 }
126}
127
128#[derive(Debug, Clone, Copy)]
132pub struct TtInfo {
133 pub think_time: u8,
135
136 pub multi_tt: bool,
138
139 pub num_ports: u8,
141}
142
143#[derive(Debug, Clone, Copy, PartialEq, Eq)]
147pub struct HubCharacteristics {
148 pub power_switching: PowerSwitchingMode,
150
151 pub compound_device: bool,
153
154 pub over_current_mode: OverCurrentMode,
156
157 pub port_indicators: bool,
159}
160
161#[derive(Debug, Clone, Copy, PartialEq, Eq)]
163pub enum PowerSwitchingMode {
164 Ganged,
166
167 Individual,
169
170 AlwaysPower,
172}
173
174#[derive(Debug, Clone, Copy, PartialEq, Eq)]
176pub enum OverCurrentMode {
177 Global,
179
180 Individual,
182}
183
184#[derive(Debug, Clone, Copy)]
188pub struct PortStatus {
189 pub connected: bool,
191
192 pub enabled: bool,
194
195 pub suspended: bool,
197
198 pub over_current: bool,
200
201 pub resetting: bool,
203
204 pub powered: bool,
206
207 pub low_speed: bool,
209
210 pub high_speed: bool,
212
213 pub speed: Speed,
215
216 pub change: PortStatusChange,
218}
219
220#[derive(Debug, Clone, Copy, PartialEq, Eq)]
222pub struct PortStatusChange {
223 pub connection_changed: bool,
225
226 pub enabled_changed: bool,
228
229 pub reset_complete: bool,
231
232 pub suspend_changed: bool,
234
235 pub over_current_changed: bool,
237}
238
239#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
241#[repr(u8)]
242pub enum Speed {
243 Low = 0,
244 #[default]
245 Full = 1,
246 High = 2,
247 Wireless = 3,
248 SuperSpeed = 4,
249 SuperSpeedPlus = 5,
250}
251
252impl From<u8> for Speed {
253 fn from(value: u8) -> Self {
254 match value {
255 0 => Speed::Low,
256 1 => Speed::Full,
257 2 => Speed::High,
258 3 => Speed::Wireless,
259 4 => Speed::SuperSpeed,
260 5 => Speed::SuperSpeedPlus,
261 _ => Speed::Full,
262 }
263 }
264}
265
266impl Speed {
267 pub fn from_usb2_hub_status(raw: u16) -> Self {
275 if (raw & 0x0200) != 0 {
276 Speed::Low
277 } else if (raw & 0x0400) != 0 {
278 Speed::High
279 } else if (raw & 0x0600) != 0 {
280 Speed::SuperSpeed
281 } else {
282 Speed::Full
283 }
284 }
285
286 pub fn from_xhci_portsc(speed_value: u8) -> Self {
295 match speed_value {
296 1 => Speed::Full,
297 2 => Speed::Low,
298 3 => Speed::High,
299 4 => Speed::SuperSpeed,
300 5 => Speed::SuperSpeedPlus,
301 _ => Speed::Full, }
303 }
304
305 pub fn to_xhci_slot_value(&self) -> u8 {
313 match self {
314 Speed::Full => 1,
315 Speed::Low => 2,
316 Speed::High => 3,
317 Speed::SuperSpeed => 4,
318 Speed::SuperSpeedPlus => 5,
319 Speed::Wireless => 3,
320 }
321 }
322
323 pub fn to_xhci_portsc_value(&self) -> u8 {
327 match self {
328 Speed::Full => 1,
329 Speed::Low => 2,
330 Speed::High => 3,
331 Speed::SuperSpeed => 4,
332 Speed::SuperSpeedPlus => 5,
333 Speed::Wireless => 3,
334 }
335 }
336
337 pub fn requires_tt(&self, hub_speed: Self) -> bool {
342 matches!(self, Self::Low | Self::Full) && matches!(hub_speed, Self::High)
344 }
345
346 pub fn is_low_or_full_speed(&self) -> bool {
348 matches!(self, Self::Low | Self::Full)
349 }
350}
351
352impl HubCharacteristics {
357 pub fn from_descriptor(value: u16) -> Self {
361 let power_switching = match value & 0x03 {
362 0x01 => PowerSwitchingMode::Ganged,
363 0x02 => PowerSwitchingMode::Individual,
364 _ => PowerSwitchingMode::AlwaysPower,
365 };
366
367 let compound_device = (value & 0x04) != 0;
368 let over_current_mode = if (value & 0x08) != 0 {
369 OverCurrentMode::Individual
370 } else {
371 OverCurrentMode::Global
372 };
373 let port_indicators = (value & 0x10) != 0;
374
375 Self {
376 power_switching,
377 compound_device,
378 over_current_mode,
379 port_indicators,
380 }
381 }
382
383 pub fn to_descriptor(&self) -> u16 {
385 let mut value = 0u16;
386
387 value |= match self.power_switching {
388 PowerSwitchingMode::Ganged => 0x01,
389 PowerSwitchingMode::Individual => 0x02,
390 PowerSwitchingMode::AlwaysPower => 0x00,
391 };
392
393 if self.compound_device {
394 value |= 0x04;
395 }
396
397 if matches!(self.over_current_mode, OverCurrentMode::Individual) {
398 value |= 0x08;
399 }
400
401 if self.port_indicators {
402 value |= 0x10;
403 }
404
405 value
406 }
407}
408
409#[cfg(test)]
410mod tests {
411 use super::*;
412
413 #[test]
414 fn test_hub_characteristics_roundtrip() {
415 let original = HubCharacteristics {
416 power_switching: PowerSwitchingMode::Individual,
417 compound_device: true,
418 over_current_mode: OverCurrentMode::Global,
419 port_indicators: true,
420 };
421
422 let descriptor = original.to_descriptor();
423 let decoded = HubCharacteristics::from_descriptor(descriptor);
424
425 assert_eq!(original.power_switching, decoded.power_switching);
426 assert_eq!(original.compound_device, decoded.compound_device);
427 assert_eq!(original.over_current_mode, decoded.over_current_mode);
428 assert_eq!(original.port_indicators, decoded.port_indicators);
429 }
430
431 #[test]
432 fn test_hub_descriptor_from_bytes() {
433 let data = [
435 0x09, 0x29, 0x04, 0x12, 0x00, 0x32, 0x64, 0x00, 0x00, ];
448
449 let desc = HubDescriptor::from_bytes(&data).expect("Failed to parse");
450
451 assert_eq!(desc.bNbrPorts, 4);
452 assert_eq!(desc.bPwrOn2PwrGood, 50);
453 assert_eq!(desc.bHubContrCurrent, 100);
454
455 assert_eq!(desc.hub_characteristics(), 0x0012);
460 }
461
462 #[test]
463 fn test_hub_descriptor_invalid_length() {
464 let data = [0x09, 0x29]; assert!(HubDescriptor::from_bytes(&data).is_none());
466 }
467
468 #[test]
469 fn test_hub_descriptor_invalid_type() {
470 let mut data = [0x09u8; 7];
471 data[1] = 0x01; assert!(HubDescriptor::from_bytes(&data).is_none());
473 }
474}