1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Rust auxiliary driver sample (based on a PCI driver for QEMU's `pci-testdev`). 4 //! 5 //! To make this driver probe, QEMU must be run with `-device pci-testdev`. 6 7 use kernel::{ 8 auxiliary, 9 device::{ 10 Bound, 11 Core, // 12 }, 13 devres::Devres, 14 driver, 15 pci, 16 prelude::*, 17 InPlaceModule, // 18 }; 19 20 const MODULE_NAME: &CStr = <LocalModule as kernel::ModuleMetadata>::NAME; 21 const AUXILIARY_NAME: &CStr = c"auxiliary"; 22 23 struct AuxiliaryDriver; 24 25 kernel::auxiliary_device_table!( 26 AUX_TABLE, 27 MODULE_AUX_TABLE, 28 <AuxiliaryDriver as auxiliary::Driver>::IdInfo, 29 [(auxiliary::DeviceId::new(MODULE_NAME, AUXILIARY_NAME), ())] 30 ); 31 32 impl auxiliary::Driver for AuxiliaryDriver { 33 type IdInfo = (); 34 type Data = Self; 35 36 const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE; 37 38 fn probe( 39 adev: &auxiliary::Device<Core<'_>>, 40 _info: &Self::IdInfo, 41 ) -> impl PinInit<Self, Error> { 42 dev_info!( 43 adev, 44 "Probing auxiliary driver for auxiliary device with id={}\n", 45 adev.id() 46 ); 47 48 ParentDriver::connect(adev)?; 49 50 Ok(Self) 51 } 52 } 53 54 struct Data { 55 index: u32, 56 } 57 58 struct ParentDriver { 59 _reg0: Devres<auxiliary::Registration<Data>>, 60 _reg1: Devres<auxiliary::Registration<Data>>, 61 } 62 63 kernel::pci_device_table!( 64 PCI_TABLE, 65 MODULE_PCI_TABLE, 66 <ParentDriver as pci::Driver>::IdInfo, 67 [(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())] 68 ); 69 70 impl pci::Driver for ParentDriver { 71 type IdInfo = (); 72 type Data = Self; 73 74 const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; 75 76 fn probe(pdev: &pci::Device<Core<'_>>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { 77 Ok(Self { 78 _reg0: auxiliary::Registration::new( 79 pdev.as_ref(), 80 AUXILIARY_NAME, 81 0, 82 MODULE_NAME, 83 Data { index: 0 }, 84 )?, 85 _reg1: auxiliary::Registration::new( 86 pdev.as_ref(), 87 AUXILIARY_NAME, 88 1, 89 MODULE_NAME, 90 Data { index: 1 }, 91 )?, 92 }) 93 } 94 } 95 96 impl ParentDriver { 97 fn connect(adev: &auxiliary::Device<Bound>) -> Result { 98 let dev = adev.parent(); 99 let pdev: &pci::Device<Bound> = dev.try_into()?; 100 101 let data = adev.registration_data::<Data>()?; 102 103 dev_info!( 104 dev, 105 "Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n", 106 adev.id(), 107 pdev.vendor_id(), 108 pdev.device_id() 109 ); 110 111 dev_info!( 112 dev, 113 "Connected to auxiliary device with index {}.\n", 114 data.index 115 ); 116 117 Ok(()) 118 } 119 } 120 121 #[pin_data] 122 struct SampleModule { 123 #[pin] 124 _pci_driver: driver::Registration<pci::Adapter<ParentDriver>>, 125 #[pin] 126 _aux_driver: driver::Registration<auxiliary::Adapter<AuxiliaryDriver>>, 127 } 128 129 impl InPlaceModule for SampleModule { 130 fn init(module: &'static kernel::ThisModule) -> impl PinInit<Self, Error> { 131 try_pin_init!(Self { 132 _pci_driver <- driver::Registration::new(MODULE_NAME, module), 133 _aux_driver <- driver::Registration::new(MODULE_NAME, module), 134 }) 135 } 136 } 137 138 module! { 139 type: SampleModule, 140 name: "rust_driver_auxiliary", 141 authors: ["Danilo Krummrich"], 142 description: "Rust auxiliary driver", 143 license: "GPL v2", 144 } 145