@@ -424,3 +424,320 @@ impl std::fmt::Debug for InterfaceInfo {
424
424
. finish ( )
425
425
}
426
426
}
427
+
428
+ /// PCI device information for host controllers
429
+ #[ derive( Clone ) ]
430
+ pub struct PciInfo {
431
+ #[ cfg( target_os = "linux" ) ]
432
+ pub ( crate ) path : SysfsPath ,
433
+
434
+ #[ cfg( target_os = "windows" ) ]
435
+ pub ( crate ) instance_id : OsString ,
436
+ /// PCI vendor ID
437
+ pub ( crate ) vendor_id : u16 ,
438
+ /// PCI device ID
439
+ pub ( crate ) device_id : u16 ,
440
+ /// PCI hardware revision
441
+ pub ( crate ) revision : Option < u16 > ,
442
+ /// PCI subsystem vendor ID
443
+ pub ( crate ) subsystem_vendor_id : Option < u16 > ,
444
+ /// PCI subsystem device ID
445
+ pub ( crate ) subsystem_device_id : Option < u16 > ,
446
+ }
447
+
448
+ impl PciInfo {
449
+ /// *(Linux-only)* Sysfs path for the PCI device.
450
+ #[ cfg( target_os = "linux" ) ]
451
+ pub fn sysfs_path ( & self ) -> & std:: path:: Path {
452
+ & self . path . 0
453
+ }
454
+
455
+ /// *(Windows-only)* Instance ID path of this device
456
+ #[ cfg( target_os = "windows" ) ]
457
+ pub fn instance_id ( & self ) -> & OsStr {
458
+ & self . instance_id
459
+ }
460
+
461
+ /// PCI vendor ID
462
+ pub fn vendor_id ( & self ) -> u16 {
463
+ self . vendor_id
464
+ }
465
+
466
+ /// PCI device ID
467
+ pub fn device_id ( & self ) -> u16 {
468
+ self . device_id
469
+ }
470
+
471
+ /// PCI hardware revision
472
+ pub fn revision ( & self ) -> Option < u16 > {
473
+ self . revision
474
+ }
475
+
476
+ /// PCI subsystem vendor ID
477
+ pub fn subsystem_vendor_id ( & self ) -> Option < u16 > {
478
+ self . subsystem_vendor_id
479
+ }
480
+
481
+ /// PCI subsystem device ID
482
+ pub fn subsystem_device_id ( & self ) -> Option < u16 > {
483
+ self . subsystem_device_id
484
+ }
485
+ }
486
+
487
+ impl std:: fmt:: Debug for PciInfo {
488
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
489
+ let mut s = f. debug_struct ( "PciInfo" ) ;
490
+
491
+ s. field ( "vendor_id" , & format_args ! ( "0x{:04X}" , self . vendor_id) )
492
+ . field ( "device_id" , & format_args ! ( "0x{:04X}" , self . device_id) )
493
+ . field ( "revision" , & self . revision )
494
+ . field ( "subsystem_vendor_id" , & self . subsystem_vendor_id )
495
+ . field ( "subsystem_device_id" , & self . subsystem_device_id ) ;
496
+
497
+ #[ cfg( target_os = "linux" ) ]
498
+ {
499
+ s. field ( "sysfs_path" , & self . path ) ;
500
+ }
501
+
502
+ #[ cfg( target_os = "windows" ) ]
503
+ {
504
+ s. field ( "instance_id" , & self . instance_id ) ;
505
+ }
506
+
507
+ s. finish ( )
508
+ }
509
+ }
510
+
511
+ /// USB host controller type
512
+ #[ derive( Copy , Clone , Eq , PartialOrd , Ord , PartialEq , Hash , Debug ) ]
513
+ #[ non_exhaustive]
514
+ pub enum UsbController {
515
+ /// xHCI controller (USB 3.0+)
516
+ XHCI ,
517
+
518
+ /// EHCI controller (USB 2.0)
519
+ EHCI ,
520
+
521
+ /// OHCI controller (USB 1.1)
522
+ OHCI ,
523
+
524
+ /// VHCI controller (virtual internal USB)
525
+ VHCI ,
526
+ }
527
+
528
+ impl UsbController {
529
+ #[ allow( dead_code) ] // not used on all platforms
530
+ pub ( crate ) fn from_str ( s : & str ) -> Option < Self > {
531
+ match s
532
+ . find ( "HCI" )
533
+ . filter ( |i| * i > 0 )
534
+ . and_then ( |i| s. bytes ( ) . nth ( i - 1 ) )
535
+ {
536
+ Some ( b'x' ) | Some ( b'X' ) => Some ( UsbController :: XHCI ) ,
537
+ Some ( b'e' ) | Some ( b'E' ) => Some ( UsbController :: EHCI ) ,
538
+ Some ( b'o' ) | Some ( b'O' ) => Some ( UsbController :: OHCI ) ,
539
+ Some ( b'v' ) | Some ( b'V' ) => Some ( UsbController :: VHCI ) ,
540
+ _ => None ,
541
+ }
542
+ }
543
+ }
544
+
545
+ /// Information about a system USB bus. Aims to be a more useful and portable version of the Linux root hub device.
546
+ ///
547
+ /// Platform-specific fields:
548
+ /// * Linux: `path`, `busnum`, `root_hub`
549
+ /// * Windows: `instance_id`, `location_paths`, `devinst`, `driver`
550
+ /// * macOS: `registry_id`, `location_id`, `name`, `driver`
551
+ pub struct BusInfo {
552
+ #[ cfg( target_os = "linux" ) ]
553
+ pub ( crate ) path : SysfsPath ,
554
+
555
+ /// The phony root hub device
556
+ #[ cfg( target_os = "linux" ) ]
557
+ pub ( crate ) root_hub : DeviceInfo ,
558
+
559
+ #[ cfg( target_os = "linux" ) ]
560
+ pub ( crate ) busnum : u8 ,
561
+
562
+ #[ cfg( target_os = "windows" ) ]
563
+ pub ( crate ) instance_id : OsString ,
564
+
565
+ #[ cfg( target_os = "windows" ) ]
566
+ pub ( crate ) location_paths : Vec < OsString > ,
567
+
568
+ #[ cfg( target_os = "windows" ) ]
569
+ pub ( crate ) devinst : crate :: platform:: DevInst ,
570
+
571
+ #[ cfg( any( target_os = "windows" , target_os = "macos" ) ) ]
572
+ pub ( crate ) driver : Option < String > ,
573
+
574
+ #[ cfg( target_os = "macos" ) ]
575
+ pub ( crate ) registry_id : u64 ,
576
+
577
+ #[ cfg( target_os = "macos" ) ]
578
+ pub ( crate ) location_id : u32 ,
579
+
580
+ #[ cfg( target_os = "macos" ) ]
581
+ pub ( crate ) name : Option < String > ,
582
+
583
+ /// System ID for the bus
584
+ pub ( crate ) bus_id : String ,
585
+
586
+ /// Optional PCI information if the bus is connected to a PCI Host Controller
587
+ pub ( crate ) pci_info : Option < PciInfo > ,
588
+
589
+ /// Detected USB controller type
590
+ pub ( crate ) controller : Option < UsbController > ,
591
+
592
+ /// System provider class name for the bus
593
+ pub ( crate ) provider_class : Option < String > ,
594
+ /// System class name for the bus
595
+ pub ( crate ) class_name : Option < String > ,
596
+ }
597
+
598
+ impl BusInfo {
599
+ /// Opaque identifier for the device.
600
+ pub fn id ( & self ) -> DeviceId {
601
+ #[ cfg( target_os = "windows" ) ]
602
+ {
603
+ DeviceId ( self . devinst )
604
+ }
605
+
606
+ #[ cfg( target_os = "linux" ) ]
607
+ {
608
+ self . root_hub . id ( )
609
+ }
610
+
611
+ #[ cfg( target_os = "macos" ) ]
612
+ {
613
+ DeviceId ( self . registry_id )
614
+ }
615
+ }
616
+
617
+ /// *(Linux-only)* Sysfs path for the bus.
618
+ #[ doc( hidden) ]
619
+ #[ deprecated = "use `sysfs_path()` instead" ]
620
+ #[ cfg( target_os = "linux" ) ]
621
+ pub fn path ( & self ) -> & SysfsPath {
622
+ & self . path
623
+ }
624
+
625
+ /// *(Linux-only)* Sysfs path for the bus.
626
+ #[ cfg( target_os = "linux" ) ]
627
+ pub fn sysfs_path ( & self ) -> & std:: path:: Path {
628
+ & self . path . 0
629
+ }
630
+
631
+ /// *(Linux-only)* Bus number.
632
+ ///
633
+ /// On Linux, the `bus_id` is an integer and this provides the value as `u8`.
634
+ #[ cfg( target_os = "linux" ) ]
635
+ pub fn busnum ( & self ) -> u8 {
636
+ self . busnum
637
+ }
638
+
639
+ /// *(Linux-only)* The root hub [`DeviceInfo`] representing the bus.
640
+ #[ cfg( target_os = "linux" ) ]
641
+ pub fn root_hub ( & self ) -> & DeviceInfo {
642
+ & self . root_hub
643
+ }
644
+
645
+ /// *(Windows-only)* Instance ID path of this device
646
+ #[ cfg( target_os = "windows" ) ]
647
+ pub fn instance_id ( & self ) -> & OsStr {
648
+ & self . instance_id
649
+ }
650
+
651
+ /// *(Windows-only)* Location paths property
652
+ #[ cfg( target_os = "windows" ) ]
653
+ pub fn location_paths ( & self ) -> & [ OsString ] {
654
+ & self . location_paths
655
+ }
656
+
657
+ /// *(Windows/macOS-only)* Driver associated with the device as a whole
658
+ #[ cfg( any( target_os = "windows" , target_os = "macos" ) ) ]
659
+ pub fn driver ( & self ) -> Option < & str > {
660
+ self . driver . as_deref ( )
661
+ }
662
+
663
+ /// *(macOS-only)* IOKit Location ID
664
+ #[ cfg( target_os = "macos" ) ]
665
+ pub fn location_id ( & self ) -> u32 {
666
+ self . location_id
667
+ }
668
+
669
+ /// *(macOS-only)* IOKit [Registry Entry ID](https://developer.apple.com/documentation/iokit/1514719-ioregistryentrygetregistryentryi?language=objc)
670
+ #[ cfg( target_os = "macos" ) ]
671
+ pub fn registry_entry_id ( & self ) -> u64 {
672
+ self . registry_id
673
+ }
674
+
675
+ /// Name of the bus
676
+ #[ cfg( target_os = "macos" ) ]
677
+ pub fn name ( & self ) -> Option < & str > {
678
+ self . name . as_deref ( )
679
+ }
680
+
681
+ /// Identifier for the bus
682
+ pub fn bus_id ( & self ) -> & str {
683
+ & self . bus_id
684
+ }
685
+
686
+ /// Optional PCI information if the bus is connected to a PCI Host Controller
687
+ pub fn pci_info ( & self ) -> Option < & PciInfo > {
688
+ self . pci_info . as_ref ( )
689
+ }
690
+
691
+ /// Detected USB controller type
692
+ pub fn controller ( & self ) -> Option < UsbController > {
693
+ self . controller
694
+ }
695
+
696
+ /// System provider class name for the bus
697
+ pub fn provider_class ( & self ) -> Option < & str > {
698
+ self . provider_class . as_deref ( )
699
+ }
700
+
701
+ /// System class name for the bus
702
+ pub fn class_name ( & self ) -> Option < & str > {
703
+ self . class_name . as_deref ( )
704
+ }
705
+ }
706
+
707
+ impl std:: fmt:: Debug for BusInfo {
708
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
709
+ let mut s = f. debug_struct ( "BusInfo" ) ;
710
+
711
+ #[ cfg( target_os = "linux" ) ]
712
+ {
713
+ s. field ( "sysfs_path" , & self . path ) ;
714
+ s. field ( "busnum" , & self . busnum ) ;
715
+ }
716
+
717
+ #[ cfg( target_os = "windows" ) ]
718
+ {
719
+ s. field ( "instance_id" , & self . instance_id ) ;
720
+ s. field ( "location_paths" , & self . location_paths ) ;
721
+ s. field ( "driver" , & self . driver ) ;
722
+ }
723
+
724
+ #[ cfg( target_os = "macos" ) ]
725
+ {
726
+ s. field ( "location_id" , & format_args ! ( "0x{:08X}" , self . location_id) ) ;
727
+ s. field (
728
+ "registry_entry_id" ,
729
+ & format_args ! ( "0x{:08X}" , self . registry_id) ,
730
+ ) ;
731
+ s. field ( "name" , & self . name ) ;
732
+ s. field ( "driver" , & self . driver ) ;
733
+ }
734
+
735
+ s. field ( "bus_id" , & self . bus_id )
736
+ . field ( "pci_info" , & self . pci_info )
737
+ . field ( "controller" , & self . controller )
738
+ . field ( "provider_class" , & self . provider_class )
739
+ . field ( "class_name" , & self . class_name ) ;
740
+
741
+ s. finish ( )
742
+ }
743
+ }
0 commit comments