1#![recursion_limit = "256"]
6
7pub(crate) mod device;
8pub(crate) mod sysfs;
9
10use crate::device::{
11 USB_SPEED_FULL, USB_SPEED_HIGH, USB_SPEED_LOW, USB_SPEED_SUPER, USB_SPEED_SUPER_PLUS,
12 USB_SPEED_UNKNOWN, UsbDevice, UsbDeviceFile,
13};
14use crate::sysfs::build_usb_device_directory;
15use fidl::endpoints::Proxy;
16use fidl_fuchsia_hardware_usb as fhardware_usb;
17use fidl_fuchsia_hardware_usb_descriptor as fusb_descriptor;
18use fuchsia_component::client::Service;
19use futures::TryStreamExt;
20use starnix_core::device::DeviceMode;
21use starnix_core::device::kobject::{Bus, Device, DeviceMetadata};
22use starnix_core::task::dynamic_thread_spawner::SpawnRequestBuilder;
23use starnix_core::task::{CurrentTask, Kernel};
24use starnix_core::vfs::NamespaceNode;
25use starnix_logging::{log_error, log_info};
26use starnix_sync::Mutex;
27use starnix_uapi::device_id::{DeviceId, USB_DEVICE_MAJOR};
28use starnix_uapi::errors::Errno;
29use starnix_uapi::open_flags::OpenFlags;
30use starnix_uapi::{errno, usb_device_descriptor};
31use std::collections::{BTreeMap, HashSet};
32use std::sync::Arc;
33use std::sync::atomic::Ordering;
34
35pub(crate) fn fuchsia_speed_to_linux_speed(speed: fusb_descriptor::UsbSpeed) -> u32 {
36 match speed {
37 fusb_descriptor::UsbSpeed::Full => USB_SPEED_FULL,
38 fusb_descriptor::UsbSpeed::Low => USB_SPEED_LOW,
39 fusb_descriptor::UsbSpeed::High => USB_SPEED_HIGH,
40 fusb_descriptor::UsbSpeed::Super => USB_SPEED_SUPER,
41 fusb_descriptor::UsbSpeed::EnhancedSuper => USB_SPEED_SUPER_PLUS,
42 fusb_descriptor::UsbSpeed::Undefined => USB_SPEED_UNKNOWN,
43 }
44}
45
46pub(crate) fn fidl_device_descriptor_to_linux(
47 desc: &fusb_descriptor::UsbDeviceDescriptor,
48) -> usb_device_descriptor {
49 usb_device_descriptor {
50 bLength: desc.b_length,
51 bDescriptorType: desc.b_descriptor_type,
52 bcdUSB: desc.bcd_usb.to_le(),
53 bDeviceClass: desc.b_device_class,
54 bDeviceSubClass: desc.b_device_sub_class,
55 bDeviceProtocol: desc.b_device_protocol,
56 bMaxPacketSize0: desc.b_max_packet_size0,
57 idVendor: desc.id_vendor.to_le(),
58 idProduct: desc.id_product.to_le(),
59 bcdDevice: desc.bcd_device.to_le(),
60 iManufacturer: desc.i_manufacturer,
61 iProduct: desc.i_product,
62 iSerialNumber: desc.i_serial_number,
63 bNumConfigurations: desc.b_num_configurations,
64 }
65}
66
67struct DevNumAllocator {
68 allocated: HashSet<u16>,
69 next: u16,
70}
71
72impl DevNumAllocator {
73 fn new() -> Self {
74 Self { allocated: HashSet::new(), next: 2 }
75 }
76
77 fn allocate(&mut self) -> Option<u16> {
78 let start = self.next;
79 for i in 0..126 {
80 let num = ((start - 2 + i) % 126) + 2;
81 if self.allocated.insert(num) {
82 self.next = if num >= 127 { 2 } else { num + 1 };
83 return Some(num);
84 }
85 }
86 None
87 }
88
89 fn release(&mut self, dev_num: u16) {
90 self.allocated.remove(&dev_num);
91 }
92}
93
94#[derive(Clone)]
95pub struct UsbDeviceManager {
96 pub(crate) bus: Bus,
97 pub(crate) devices: Arc<Mutex<BTreeMap<DeviceId, Arc<UsbDevice>>>>,
98 pub(crate) allocator: Arc<Mutex<DevNumAllocator>>,
99}
100
101impl UsbDeviceManager {
102 pub(crate) fn new(bus: Bus) -> Self {
103 Self {
104 bus,
105 devices: Arc::new(Mutex::new(BTreeMap::new())),
106 allocator: Arc::new(Mutex::new(DevNumAllocator::new())),
107 }
108 }
109
110 pub(crate) fn allocate_dev_num(&self) -> Option<u16> {
111 self.allocator.lock().allocate()
112 }
113
114 pub(crate) fn release_dev_num(&self, dev_num: u16) {
115 self.allocator.lock().release(dev_num);
116 }
117
118 pub(crate) fn get_device(&self, id: DeviceId) -> Option<Arc<UsbDevice>> {
119 self.devices.lock().get(&id).cloned()
120 }
121
122 pub(crate) fn add_device(
123 &self,
124 kernel: &Kernel,
125 device: Arc<UsbDevice>,
126 ) -> Result<Device, Errno> {
127 let bus_str = format!("{:03}", device.bus_num);
128 let dev_str = format!("{:03}", device.dev_num);
129 let devname = format!("bus/usb/{}/{}", bus_str, dev_str);
130 let sysname = format!("{}-{}", device.bus_num, device.dev_num);
131
132 let devt = DeviceId::new(USB_DEVICE_MAJOR, device.minor());
133
134 let desc = &device.device_descriptor;
135 let id_vendor = u16::from_le(desc.idVendor);
136 let id_product = u16::from_le(desc.idProduct);
137 let bcd_device = u16::from_le(desc.bcdDevice);
138 let b_device_class = desc.bDeviceClass;
139 let b_device_sub_class = desc.bDeviceSubClass;
140 let b_device_protocol = desc.bDeviceProtocol;
141
142 let metadata =
143 DeviceMetadata::new(devname.into(), devt, DeviceMode::Char).with_devtype("usb_device");
144
145 metadata.properties.insert(
146 b"PRODUCT".into(),
147 format!("{:x}/{:x}/{:x}", id_vendor, id_product, bcd_device).into(),
148 );
149 metadata.properties.insert(
150 b"TYPE".into(),
151 format!("{}/{}/{}", b_device_class, b_device_sub_class, b_device_protocol).into(),
152 );
153 metadata.properties.insert(b"BUSNUM".into(), format!("{:03}", device.bus_num).into());
154 metadata.properties.insert(b"DEVNUM".into(), format!("{:03}", device.dev_num).into());
155
156 self.devices.lock().insert(devt, device.clone());
157
158 let device_clone = device.clone();
159 let registered_device = kernel.device_registry.add_major_device(
160 kernel,
161 sysname.as_bytes().into(),
162 metadata,
163 None,
164 self.bus.clone(),
165 move |device_obj, dir| {
166 build_usb_device_directory(device_obj, dir, &device_clone);
167 },
168 );
169
170 Ok(registered_device)
171 }
172
173 pub(crate) fn remove_device(
174 &self,
175 current_task: &CurrentTask,
176 registered_device: Device,
177 ) -> Result<(), Errno> {
178 if let Some(metadata) = registered_device.metadata() {
179 if let Some(device) = self.devices.lock().remove(&metadata.devt) {
180 self.release_dev_num(device.dev_num);
181 device.on_disconnect();
182 }
183 }
184 current_task.kernel().device_registry.remove_device(current_task, registered_device);
185 Ok(())
186 }
187}
188
189async fn run_in_kernel_task_async<F, R>(
190 kernel: &Kernel,
191 debug_name: &'static str,
192 f: F,
193) -> Result<R, Errno>
194where
195 F: FnOnce(&CurrentTask) -> R + Send + 'static,
196 R: Send + 'static,
197{
198 let closure = move |current_task: &CurrentTask| {
199 current_task.override_creds(
200 starnix_core::security::creds_start_internal_operation(current_task),
201 || f(current_task),
202 )
203 };
204 let (result_fut, req) = SpawnRequestBuilder::new()
205 .with_debug_name(debug_name)
206 .with_sync_closure(closure)
207 .build_with_async_result();
208 kernel.kthreads.spawner().spawn_from_request(req);
209 result_fut.await
210}
211
212pub fn usbfs_init(kernel: &Arc<Kernel>) -> Result<UsbDeviceManager, Errno> {
213 let registry = &kernel.device_registry;
214
215 let usb_bus = registry.objects.get_or_create_bus("usb".into());
216 let manager = UsbDeviceManager::new(usb_bus);
217 let manager_clone = manager.clone();
218
219 registry.register_major(
220 "usb".into(),
221 DeviceMode::Char,
222 USB_DEVICE_MAJOR,
223 move |_current_task: &CurrentTask,
224 id: DeviceId,
225 _node: &NamespaceNode,
226 _flags: OpenFlags|
227 -> Result<Box<dyn starnix_core::vfs::FileOps>, Errno> {
228 let device = manager_clone.get_device(id).ok_or_else(|| errno!(ENODEV))?;
229 Ok(Box::new(UsbDeviceFile::new(device)))
230 },
231 )?;
232
233 let kernel_clone = Arc::clone(kernel);
234 let manager_for_watcher = manager.clone();
235 kernel.kthreads.spawn_future(
236 move || async move {
237 watch_usb_devices(kernel_clone, manager_for_watcher).await;
238 },
239 "usbfs_watcher",
240 );
241
242 Ok(manager)
243}
244
245async fn watch_usb_devices(kernel: Arc<Kernel>, manager: UsbDeviceManager) {
246 log_info!("Starting Starnix usbfs USB device watcher.");
247
248 let service = match Service::open(fhardware_usb::UsbServiceMarker) {
249 Ok(service) => service,
250 Err(e) => {
251 log_info!("Physical USB service not available: {:?}", e);
252 return;
253 }
254 };
255 watch_usb_devices_from_service(kernel, manager, service).await;
256}
257
258async fn watch_usb_devices_from_service(
259 kernel: Arc<Kernel>,
260 manager: UsbDeviceManager,
261 service: Service<fhardware_usb::UsbServiceMarker>,
262) {
263 let mut watcher = match service.watch().await {
264 Ok(watcher) => watcher,
265 Err(e) => {
266 log_info!("Failed to create USB service watcher: {:?}", e);
267 return;
268 }
269 };
270
271 let active_hw_ids = Arc::new(Mutex::new(HashSet::<u32>::new()));
272 while let Ok(Some(instance)) = watcher.try_next().await {
273 let device_proxy = match instance.connect_to_device() {
274 Ok(proxy) => proxy,
275 Err(e) => {
276 log_error!("Failed to connect to USB device: {:?}", e);
277 continue;
278 }
279 };
280
281 let first_config_desc = match device_proxy.get_configuration_descriptor(1).await {
282 Err(fidl::Error::ClientChannelClosed { .. }) => continue,
283 Ok(Err(zx::sys::ZX_ERR_NOT_SUPPORTED)) => {
284 continue;
286 }
287 Ok(Ok(desc)) if !desc.is_empty() => Some(desc),
288 _ => None,
289 };
290
291 let hw_device_id = match device_proxy.get_device_id().await {
292 Ok(id) => id,
293 Err(e) => {
294 log_error!("Failed to get device ID: {:?}", e);
295 continue;
296 }
297 };
298 if !active_hw_ids.lock().insert(hw_device_id) {
299 continue;
300 }
301
302 let fidl_desc = match device_proxy.get_device_descriptor().await {
303 Ok(desc) => desc,
304 Err(e) => {
305 active_hw_ids.lock().remove(&hw_device_id);
306 log_error!("Failed to get device descriptor: {:?}", e);
307 continue;
308 }
309 };
310
311 let device_descriptor = fidl_device_descriptor_to_linux(&fidl_desc);
312
313 let mut config_descriptors = Vec::new();
314 if let Some(desc) = first_config_desc {
315 config_descriptors.extend_from_slice(&desc);
316 }
317 for cfg in 2..=device_descriptor.bNumConfigurations {
318 match device_proxy.get_configuration_descriptor(cfg).await {
319 Ok(Ok(desc)) if !desc.is_empty() => {
320 config_descriptors.extend_from_slice(&desc);
321 }
322 _ => {}
323 }
324 }
325
326 let speed = match device_proxy.get_device_speed().await {
327 Ok(s) => fuchsia_speed_to_linux_speed(s),
328 Err(_) => USB_SPEED_FULL,
329 };
330
331 let active_config = device_proxy.get_configuration().await.unwrap_or(1);
332
333 let assigned_dev_num = match manager.allocate_dev_num() {
334 Some(n) => n,
335 None => {
336 active_hw_ids.lock().remove(&hw_device_id);
337 log_error!("Exhausted USB device numbers (2..127) for incoming device.");
338 continue;
339 }
340 };
341
342 let sync_proxy = match instance.connect_to_device() {
343 Ok(client_proxy) => {
344 let client_end = client_proxy.into_client_end().ok();
345 client_end
346 .map(|c| Arc::new(fhardware_usb::UsbSynchronousProxy::new(c.into_channel())))
347 }
348 Err(_) => None,
349 };
350
351 let mut usb_device =
352 UsbDevice::new(1, assigned_dev_num, speed, device_descriptor, config_descriptors);
353 usb_device.active_config.store(active_config, Ordering::Relaxed);
354 usb_device.sync_proxy = sync_proxy;
355 let usb_device = Arc::new(usb_device);
356
357 let add_res = manager.add_device(&kernel, Arc::clone(&usb_device));
358
359 match add_res {
360 Ok(registered_device) => {
361 log_info!(
362 "Registered USB device in Starnix usbfs (/dev/bus/usb/001/{:03}) with speed {}",
363 assigned_dev_num,
364 speed
365 );
366
367 let kernel_for_close = Arc::clone(&kernel);
368 let manager_for_close = manager.clone();
369 let active_hw_ids_for_close = Arc::clone(&active_hw_ids);
370 let proxy_for_close = device_proxy.clone();
371 kernel.kthreads.spawn_future(
372 move || async move {
373 let mut event_stream = proxy_for_close.take_event_stream();
374 let _ = event_stream.try_next().await;
375 active_hw_ids_for_close.lock().remove(&hw_device_id);
376 let _ = run_in_kernel_task_async(
377 &kernel_for_close,
378 "usbfs-device-disconnect",
379 move |current_task| {
380 if manager_for_close
381 .remove_device(current_task, registered_device)
382 .is_ok()
383 {
384 log_info!(
385 "Removed disconnected USB device from Starnix usbfs (/dev/bus/usb/001/{:03})",
386 assigned_dev_num
387 );
388 }
389 },
390 )
391 .await;
392 },
393 "usbfs-device-lifecycle",
394 );
395 }
396 Err(e) => {
397 manager.release_dev_num(assigned_dev_num);
398 active_hw_ids.lock().remove(&hw_device_id);
399 log_error!("Failed to register USB device in Starnix usbfs: {:?}", e);
400 }
401 }
402 }
403}
404
405#[cfg(test)]
406mod tests {
407 use super::*;
408 use starnix_core::device::DeviceListener;
409 use starnix_core::device::kobject::{UEventAction, UEventContext};
410 use starnix_core::task::KernelFeatures;
411 use starnix_core::testing::{spawn_kernel_and_run, spawn_kernel_with_features_and_run};
412 use starnix_core::vfs::{FsStr, FsString};
413 use starnix_uapi::{
414 error, usb_config_descriptor, usb_endpoint_descriptor, usb_interface_descriptor,
415 };
416 use std::sync::atomic::{AtomicUsize, Ordering};
417 use zerocopy::IntoBytes as _;
418
419 fn create_mock_hid_descriptors() -> (usb_device_descriptor, Vec<u8>) {
420 let device_desc = usb_device_descriptor {
421 bLength: 18,
422 bDescriptorType: 1,
423 bcdUSB: 0x0210u16.to_le(),
424 bDeviceClass: 0,
425 bDeviceSubClass: 0,
426 bDeviceProtocol: 0,
427 bMaxPacketSize0: 64,
428 idVendor: 0x1234u16.to_le(),
429 idProduct: 0x5678u16.to_le(),
430 bcdDevice: 0x0543u16.to_le(),
431 iManufacturer: 1,
432 iProduct: 2,
433 iSerialNumber: 3,
434 bNumConfigurations: 1,
435 };
436
437 let config_desc = usb_config_descriptor {
438 bLength: 9,
439 bDescriptorType: 2,
440 wTotalLength: ((9 + 9 + 7 + 7) as u16).to_le(),
441 bNumInterfaces: 1,
442 bConfigurationValue: 1,
443 iConfiguration: 0,
444 bmAttributes: 0x80, bMaxPower: 50, };
447
448 let if_desc = usb_interface_descriptor {
449 bLength: 9,
450 bDescriptorType: 4,
451 bInterfaceNumber: 0,
452 bAlternateSetting: 0,
453 bNumEndpoints: 2,
454 bInterfaceClass: 3, bInterfaceSubClass: 0,
456 bInterfaceProtocol: 0,
457 iInterface: 0,
458 };
459
460 let ep_in_desc = usb_endpoint_descriptor {
461 bLength: 7,
462 bDescriptorType: 5,
463 bEndpointAddress: 0x81, bmAttributes: 3, wMaxPacketSize: 64u16.to_le(),
466 bInterval: 5,
467 bRefresh: 0,
468 bSynchAddress: 0,
469 };
470
471 let ep_out_desc = usb_endpoint_descriptor {
472 bLength: 7,
473 bDescriptorType: 5,
474 bEndpointAddress: 0x01, bmAttributes: 3, wMaxPacketSize: 64u16.to_le(),
477 bInterval: 5,
478 bRefresh: 0,
479 bSynchAddress: 0,
480 };
481
482 let mut config_bytes = Vec::new();
483 config_bytes.extend_from_slice(config_desc.as_bytes());
484 config_bytes.extend_from_slice(if_desc.as_bytes());
485 config_bytes.extend_from_slice(&ep_in_desc.as_bytes()[..7]);
486 config_bytes.extend_from_slice(&ep_out_desc.as_bytes()[..7]);
487
488 (device_desc, config_bytes)
489 }
490
491 fn open_dev_node(
492 current_task: &CurrentTask,
493 path: &FsStr,
494 flags: OpenFlags,
495 ) -> Result<starnix_core::vfs::FileHandle, Errno> {
496 let dev_root = NamespaceNode::new_anonymous(
497 starnix_core::fs::devtmpfs::DevTmpFs::from_kernel(current_task.kernel()).root().clone(),
498 );
499 let mut context = starnix_core::vfs::LookupContext::default();
500 let node = current_task.lookup_path(&mut context, dev_root, path)?;
501 node.open(current_task, flags)
502 }
503
504 #[::fuchsia::test]
505 async fn test_usb_device_descriptor_layout() {
506 assert_eq!(std::mem::size_of::<usb_device_descriptor>(), 18);
507 assert_eq!(std::mem::size_of::<usb_config_descriptor>(), 9);
508 assert_eq!(std::mem::size_of::<usb_interface_descriptor>(), 9);
509 assert_eq!(std::mem::size_of::<usb_endpoint_descriptor>(), 9);
510
511 let (device_desc, config_bytes) = create_mock_hid_descriptors();
512 let device = UsbDevice::new(1, 2, USB_SPEED_HIGH, device_desc, config_bytes);
513
514 assert_eq!(device.bus_num, 1);
515 assert_eq!(device.dev_num, 2);
516 assert_eq!(device.minor(), 1);
517 assert_eq!(device.speed, USB_SPEED_HIGH);
518 assert_eq!(device.raw_descriptors.len(), 18 + 9 + 9 + 7 + 7);
519 }
520
521 #[::fuchsia::test]
522 async fn test_usbfs_registration_and_devtmpfs() {
523 spawn_kernel_with_features_and_run(
524 async |current_task| {
525 let kernel = current_task.kernel();
526 let manager = usbfs_init(kernel).expect("usbfs_init failed");
527
528 let (device_desc, config_bytes) = create_mock_hid_descriptors();
529 let usb_dev =
530 Arc::new(UsbDevice::new(1, 2, USB_SPEED_HIGH, device_desc, config_bytes));
531
532 let registered = manager.add_device(kernel, usb_dev).expect("add_device failed");
533 let metadata = registered.metadata().expect("metadata present");
534 assert_eq!(metadata.devname.as_slice(), b"bus/usb/001/002");
535 assert_eq!(metadata.devt.major(), USB_DEVICE_MAJOR);
536 assert_eq!(metadata.devt.minor(), 1);
537
538 let node = open_dev_node(current_task, b"bus/usb/001/002".into(), OpenFlags::RDWR)
539 .expect("open_dev_node failed");
540 assert!(node.ops().is_seekable());
541
542 assert!(
544 kernel
545 .device_registry
546 .objects
547 .root
548 .lookup("bus/usb/devices/1-2".into())
549 .is_some()
550 );
551
552 manager.remove_device(current_task, registered).expect("remove_device failed");
553
554 assert!(
556 kernel
557 .device_registry
558 .objects
559 .root
560 .lookup("bus/usb/devices/1-2".into())
561 .is_none()
562 );
563 },
564 KernelFeatures { devtmpfs: true, ..Default::default() },
565 )
566 .await;
567 }
568
569 #[::fuchsia::test]
570 async fn test_usbfs_read_descriptors() {
571 spawn_kernel_with_features_and_run(
572 async |current_task| {
573 let kernel = current_task.kernel();
574 let manager = usbfs_init(kernel).expect("usbfs_init failed");
575
576 let (device_desc, config_bytes) = create_mock_hid_descriptors();
577 let mut expected_raw = Vec::new();
578 expected_raw.extend_from_slice(device_desc.as_bytes());
579 expected_raw.extend_from_slice(&config_bytes);
580
581 let usb_dev = Arc::new(UsbDevice::new(
582 1,
583 3,
584 USB_SPEED_FULL,
585 device_desc,
586 config_bytes.clone(),
587 ));
588 let registered = manager.add_device(kernel, usb_dev).unwrap();
589
590 let file =
591 open_dev_node(current_task, b"bus/usb/001/003".into(), OpenFlags::RDONLY)
592 .expect("open_dev_node failed");
593
594 let mut output_buf = starnix_core::vfs::buffers::VecOutputBuffer::new(128);
595 let bytes_read = file.ops().read(&file, current_task, 0, &mut output_buf).unwrap();
596
597 assert_eq!(bytes_read, expected_raw.len());
598 assert_eq!(Vec::from(output_buf), expected_raw);
599
600 manager.remove_device(current_task, registered).unwrap();
601 },
602 KernelFeatures { devtmpfs: true, ..Default::default() },
603 )
604 .await;
605 }
606
607 struct MockUEventListener {
608 add_count: Arc<AtomicUsize>,
609 remove_count: Arc<AtomicUsize>,
610 }
611
612 impl DeviceListener for MockUEventListener {
613 fn on_device_event(&self, action: UEventAction, device: Device, _context: UEventContext) {
614 if let Some(metadata) = device.metadata() {
615 if metadata.devname.as_slice() == b"bus/usb/001/005" {
616 match action {
617 UEventAction::Add => {
618 self.add_count.fetch_add(1, Ordering::SeqCst);
619 }
620 UEventAction::Remove => {
621 self.remove_count.fetch_add(1, Ordering::SeqCst);
622 }
623 _ => {}
624 }
625 }
626 }
627 }
628 }
629
630 #[::fuchsia::test]
631 async fn test_usbfs_uevent_emission() {
632 spawn_kernel_and_run(async |current_task| {
633 let kernel = current_task.kernel();
634 let manager = usbfs_init(kernel).expect("usbfs_init failed");
635
636 let add_count = Arc::new(AtomicUsize::new(0));
637 let remove_count = Arc::new(AtomicUsize::new(0));
638 let listener = MockUEventListener {
639 add_count: add_count.clone(),
640 remove_count: remove_count.clone(),
641 };
642
643 let _listener_key = kernel.device_registry.register_listener(listener);
644
645 let (device_desc, config_bytes) = create_mock_hid_descriptors();
646 let usb_dev = Arc::new(UsbDevice::new(1, 5, USB_SPEED_HIGH, device_desc, config_bytes));
647 let registered = manager.add_device(kernel, usb_dev).unwrap();
648
649 let props: std::collections::HashMap<FsString, FsString> =
650 registered.get_uevent_properties_list().into_iter().collect();
651 assert_eq!(props.get(&FsString::from(b"SUBSYSTEM")).unwrap().as_slice(), b"usb");
652 assert_eq!(props.get(&FsString::from(b"DEVTYPE")).unwrap().as_slice(), b"usb_device");
653 assert_eq!(props.get(&FsString::from(b"BUSNUM")).unwrap().as_slice(), b"001");
654 assert_eq!(props.get(&FsString::from(b"DEVNUM")).unwrap().as_slice(), b"005");
655 assert_eq!(
656 props.get(&FsString::from(b"PRODUCT")).unwrap().as_slice(),
657 b"1234/5678/543"
658 );
659
660 assert_eq!(add_count.load(Ordering::SeqCst), 1);
661 assert_eq!(remove_count.load(Ordering::SeqCst), 0);
662
663 manager.remove_device(current_task, registered).unwrap();
664 assert_eq!(remove_count.load(Ordering::SeqCst), 1);
665 })
666 .await;
667 }
668
669 #[::fuchsia::test]
670 async fn test_multidevice_minor_allocation_and_cleanup() {
671 spawn_kernel_and_run(async |current_task| {
672 let kernel = current_task.kernel();
673 let manager = usbfs_init(kernel).expect("usbfs_init failed");
674
675 let dev1 = manager.allocate_dev_num().expect("alloc 1");
676 let dev2 = manager.allocate_dev_num().expect("alloc 2");
677 assert_eq!(dev1, 2);
678 assert_eq!(dev2, 3);
679
680 manager.release_dev_num(dev1);
681 let dev3 = manager.allocate_dev_num().expect("alloc 3");
682 assert_eq!(dev3, 4, "Monotonic device number allocation must increment");
683
684 manager.release_dev_num(dev3);
685 manager.release_dev_num(dev2);
686 })
687 .await;
688 }
689
690 #[::fuchsia::test]
691 async fn test_watch_usb_devices_missing_service_handled_gracefully() {
692 spawn_kernel_and_run(async |current_task| {
693 let kernel = current_task.kernel();
694 let manager = usbfs_init(kernel).expect("usbfs_init failed");
695 assert!(manager.allocate_dev_num().is_some());
696 })
697 .await;
698 }
699
700 #[::fuchsia::test]
701 async fn test_barebones_ioctl_returns_enotty() {
702 spawn_kernel_with_features_and_run(
703 async |current_task| {
704 let kernel = current_task.kernel();
705 let manager = usbfs_init(kernel).expect("usbfs_init failed");
706
707 let (device_desc, config_bytes) = create_mock_hid_descriptors();
708 let usb_dev =
709 Arc::new(UsbDevice::new(1, 2, USB_SPEED_HIGH, device_desc, config_bytes));
710 let registered = manager.add_device(kernel, usb_dev.clone()).unwrap();
711
712 let file = open_dev_node(current_task, b"bus/usb/001/002".into(), OpenFlags::RDWR)
713 .expect("open_dev_node failed");
714
715 let res = file.ops().ioctl(&file, current_task, 0x1234, 0u64.into());
717 assert_eq!(res, error!(ENOTTY));
718
719 usb_dev.on_disconnect();
721 let res_disconn = file.ops().ioctl(&file, current_task, 0x1234, 0u64.into());
722 assert_eq!(res_disconn, error!(ENODEV));
723
724 manager.remove_device(current_task, registered).unwrap();
725 },
726 KernelFeatures { devtmpfs: true, ..Default::default() },
727 )
728 .await;
729 }
730}