Skip to content

Commit 30cae17

Browse files
ZR233claude
andcommitted
♻️ refactor(device): introduce ProbedDevice enum to distinguish hubs from devices
Add `ProbedDevice` enum with `Device` and `Hub` variants so that callers of `probe_devices()` can tell apart USB hubs from regular devices without inspecting descriptors manually. - Backend: add `ProbedDeviceInfoOp` enum in `ty/mod.rs`, update kmod and umod backends to classify devices at probe time - Public API: expose `ProbedDevice`, `HubDeviceInfo` from `host.rs` - Tests/examples: use `into_device_info()` to filter out hubs Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 9f8f18d commit 30cae17

12 files changed

Lines changed: 187 additions & 30 deletions

File tree

test_crates/test_hub/tests/test.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,11 @@ mod tests {
6868
sleep(Duration::from_millis(100)).await;
6969
}
7070

71-
for info in ls {
72-
info!("{info:#x?}");
71+
for probed in ls {
72+
info!("{probed:#x?}");
73+
let Some(info) = probed.into_device_info() else {
74+
continue;
75+
};
7376

7477
let mut interface_desc = None;
7578
let mut config_desc: Option<ConfigurationDescriptor> = None;

test_crates/test_hub/tests/test_dwc.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,11 @@ mod tests {
8383
sleep(Duration::from_millis(1000)).await;
8484
}
8585

86-
for info in ls {
87-
info!("{info:#x?}");
86+
for probed in ls {
87+
info!("{probed:#x?}");
88+
let Some(info) = probed.into_device_info() else {
89+
continue;
90+
};
8891

8992
let mut interface_desc = None;
9093
let mut config_desc: Option<ConfigurationDescriptor> = None;

test_crates/test_libusb/tests/test.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ async fn test() {
1616

1717
let mut info: Option<DeviceInfo> = None;
1818

19-
for device in ls {
20-
println!("{device:?}");
19+
'devices: for probed in ls {
20+
println!("{probed:?}");
21+
let Some(device) = probed.into_device_info() else {
22+
continue;
23+
};
2124

2225
for iface in device.interface_descriptors().cloned().collect::<Vec<_>>() {
2326
println!(" Interface: {:?}", iface.class());
@@ -30,7 +33,7 @@ async fn test() {
3033
if matches!(iface.class(), Class::Video | Class::AudioVideo(_)) {
3134
info!("Found video interface: {iface:?}");
3235
info = Some(device);
33-
break;
36+
break 'devices;
3437
}
3538
}
3639
}

test_crates/test_libusb_uvc/src/main.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
2626

2727
// 查找 UVC 设备
2828
let mut uvc_device = None;
29-
for device_info in devices {
29+
for probed in devices {
30+
let Some(device_info) = probed.into_device_info() else {
31+
continue;
32+
};
3033
info!(
3134
"Checking device: VID={:04x}, PID={:04x}",
3235
device_info.vendor_id(),

test_crates/test_xhci_uvc/tests/test.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ mod tests {
5252
let ls2 = host.probe_devices().await.unwrap();
5353
if !ls2.is_empty() {
5454
info!("found {} devices", ls2.len());
55-
devices = ls2;
55+
devices = ls2
56+
.into_iter()
57+
.filter_map(|device| device.into_device_info())
58+
.collect();
5659
break;
5760
}
5861
spin_delay(Duration::from_millis(100));

usb-device/hid/keyboard/examples/keyboard.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,19 @@ async fn main() {
1313

1414
let mut info: Option<DeviceInfo> = None;
1515

16-
for device in ls {
17-
println!("{device}");
16+
'devices: for probed in ls {
17+
println!("{probed}");
18+
let Some(device) = probed.into_device_info() else {
19+
continue;
20+
};
1821

1922
for iface in device.interface_descriptors().cloned().collect::<Vec<_>>() {
2023
println!(" Interface: {:?}", iface.class());
2124

2225
if KeyBoard::check(&device) {
2326
info!("Found video interface: {iface:?}");
2427
info = Some(device);
25-
break;
28+
break 'devices;
2629
}
2730
}
2831
}

usb-host/src/backend/kmod/kcore.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::{
1616
backend::{
1717
BackendOp,
1818
kmod::hub::{Hub, HubDevice, HubInfo, HubOp, PortChangeInfo},
19-
ty::{DeviceInfoOp, DeviceOp, EventHandlerOp},
19+
ty::{DeviceInfoOp, DeviceOp, EventHandlerOp, ProbedDeviceInfoOp},
2020
},
2121
};
2222

@@ -62,7 +62,7 @@ impl Core {
6262
out
6363
}
6464

65-
async fn _probe_devices(&mut self) -> Result<(bool, Vec<Box<dyn DeviceInfoOp>>), USBError> {
65+
async fn _probe_devices(&mut self) -> Result<(bool, Vec<ProbedDeviceInfoOp>), USBError> {
6666
let mut is_have_new_hub = false;
6767
let mut out = Vec::new();
6868

@@ -87,6 +87,8 @@ impl Core {
8787
if let Some(hub_settings) =
8888
HubDevice::is_hub(device.descriptor(), device.configuration_descriptors())
8989
{
90+
let desc = device.descriptor().clone();
91+
let configs = device.configuration_descriptors().to_vec();
9092
let device_inner: Device = device.into();
9193

9294
let hub_device = HubDevice::new(
@@ -109,6 +111,10 @@ impl Core {
109111
let hub_id = self.hubs.alloc(hub);
110112
is_have_new_hub = true;
111113

114+
let hub_info = Box::new(DeviceInfo::new(device_id, desc, &configs))
115+
as Box<dyn DeviceInfoOp>;
116+
out.push(ProbedDeviceInfoOp::Hub(hub_info));
117+
112118
info!("Added new hub with id {:?}", hub_id);
113119
} else {
114120
let desc = device.descriptor().clone();
@@ -119,7 +125,7 @@ impl Core {
119125
let device_info = Box::new(DeviceInfo::new(device_id, desc, &configs))
120126
as Box<dyn DeviceInfoOp>;
121127

122-
out.push(device_info);
128+
out.push(ProbedDeviceInfoOp::Device(device_info));
123129
}
124130
}
125131
}
@@ -135,7 +141,7 @@ impl Core {
135141
hub.backend.changed_ports().await
136142
}
137143

138-
async fn probe_devices(&mut self) -> Result<Vec<Box<dyn DeviceInfoOp>>, USBError> {
144+
async fn probe_devices(&mut self) -> Result<Vec<ProbedDeviceInfoOp>, USBError> {
139145
let mut result = Vec::new();
140146

141147
loop {
@@ -164,9 +170,7 @@ impl BackendOp for Core {
164170
.boxed()
165171
}
166172

167-
fn device_list<'a>(
168-
&'a mut self,
169-
) -> BoxFuture<'a, Result<Vec<Box<dyn DeviceInfoOp>>, USBError>> {
173+
fn device_list<'a>(&'a mut self) -> BoxFuture<'a, Result<Vec<ProbedDeviceInfoOp>, USBError>> {
170174
self.probe_devices().boxed()
171175
}
172176

usb-host/src/backend/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use alloc::{boxed::Box, vec::Vec};
55
use futures::future::{BoxFuture, LocalBoxFuture};
66
use usb_if::err::USBError;
77

8-
use crate::backend::ty::{DeviceInfoOp, DeviceOp};
8+
use crate::backend::ty::{DeviceInfoOp, DeviceOp, ProbedDeviceInfoOp};
99

1010
#[cfg(umod)]
1111
pub mod umod;
@@ -36,8 +36,7 @@ pub(crate) trait BackendOp: Send + Any + 'static {
3636
fn init<'a>(&'a mut self) -> BoxFuture<'a, Result<(), USBError>>;
3737

3838
/// 探测已连接的设备
39-
fn device_list<'a>(&'a mut self)
40-
-> BoxFuture<'a, Result<Vec<Box<dyn DeviceInfoOp>>, USBError>>;
39+
fn device_list<'a>(&'a mut self) -> BoxFuture<'a, Result<Vec<ProbedDeviceInfoOp>, USBError>>;
4140

4241
fn open_device<'a>(
4342
&'a mut self,

usb-host/src/backend/ty/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use alloc::boxed::Box;
12
use core::any::Any;
23
use core::fmt::Debug;
34

@@ -28,6 +29,11 @@ pub(crate) trait DeviceInfoOp: Send + Sync + Any + Debug + 'static {
2829
fn configuration_descriptors(&self) -> &[ConfigurationDescriptor];
2930
}
3031

32+
pub(crate) enum ProbedDeviceInfoOp {
33+
Device(Box<dyn DeviceInfoOp>),
34+
Hub(Box<dyn DeviceInfoOp>),
35+
}
36+
3137
/// USB 设备特征(高层抽象)
3238
pub(crate) trait DeviceOp: Send + Any + 'static {
3339
fn id(&self) -> usize;

usb-host/src/backend/umod/mod.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ use std::{sync::Arc, thread};
33
use futures::FutureExt;
44
use usb_if::err::USBError;
55

6-
use crate::{USBHost, backend::BackendOp};
6+
use crate::{
7+
USBHost,
8+
backend::{
9+
BackendOp,
10+
ty::{DeviceInfoOp, ProbedDeviceInfoOp},
11+
},
12+
};
713

814
#[macro_use]
915
mod err;
@@ -44,13 +50,20 @@ impl Libusb {
4450
Self { ctx }
4551
}
4652

47-
async fn device_list(&mut self) -> Result<Vec<Box<dyn super::ty::DeviceInfoOp>>, USBError> {
53+
async fn device_list(&mut self) -> Result<Vec<ProbedDeviceInfoOp>, USBError> {
4854
let ctx = self.ctx.clone();
4955
let devices = ctx.device_list()?;
5056
let mut infos = Vec::new();
5157
for dev in devices {
5258
let info = device::DeviceInfo::new(dev)?;
53-
infos.push(Box::new(info) as Box<dyn super::ty::DeviceInfoOp>);
59+
let is_hub = info.descriptor().class == 0x09;
60+
let info = Box::new(info) as Box<dyn super::ty::DeviceInfoOp>;
61+
let info = if is_hub {
62+
ProbedDeviceInfoOp::Hub(info)
63+
} else {
64+
ProbedDeviceInfoOp::Device(info)
65+
};
66+
infos.push(info);
5467
}
5568
Ok(infos)
5669
}
@@ -81,8 +94,7 @@ impl BackendOp for Libusb {
8194

8295
fn device_list<'a>(
8396
&'a mut self,
84-
) -> futures::future::BoxFuture<'a, Result<Vec<Box<dyn super::ty::DeviceInfoOp>>, USBError>>
85-
{
97+
) -> futures::future::BoxFuture<'a, Result<Vec<ProbedDeviceInfoOp>, USBError>> {
8698
self.device_list().boxed()
8799
}
88100

0 commit comments

Comments
 (0)