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 driver, 14 pci, 15 prelude::*, 16 types::ForLt, 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<'bound> = Self; 35 36 const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE; 37 38 fn probe<'bound>( 39 adev: &'bound auxiliary::Device<Core<'_>>, 40 _info: &'bound Self::IdInfo, 41 ) -> impl PinInit<Self, Error> + 'bound { 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<'bound> { 55 index: u32, 56 parent: &'bound pci::Device<Bound>, 57 } 58 59 struct ParentDriver; 60 61 #[allow(clippy::type_complexity)] 62 struct ParentData<'bound> { 63 _reg0: auxiliary::Registration<'bound, ForLt!(Data<'_>)>, 64 _reg1: auxiliary::Registration<'bound, ForLt!(Data<'_>)>, 65 } 66 67 kernel::pci_device_table!( 68 PCI_TABLE, 69 MODULE_PCI_TABLE, 70 <ParentDriver as pci::Driver>::IdInfo, 71 [(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())] 72 ); 73 74 impl pci::Driver for ParentDriver { 75 type IdInfo = (); 76 type Data<'bound> = ParentData<'bound>; 77 78 const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; 79 80 fn probe<'bound>( 81 pdev: &'bound pci::Device<Core<'_>>, 82 _info: &'bound Self::IdInfo, 83 ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { 84 Ok(ParentData { 85 // SAFETY: `ParentData` is the driver's private data, which is dropped when the 86 // device is unbound; i.e. `mem::forget()` is never called on it. 87 _reg0: unsafe { 88 auxiliary::Registration::new_with_lt( 89 pdev.as_ref(), 90 AUXILIARY_NAME, 91 0, 92 MODULE_NAME, 93 Data { 94 index: 0, 95 parent: pdev, 96 }, 97 )? 98 }, 99 // SAFETY: See `_reg0` above. 100 _reg1: unsafe { 101 auxiliary::Registration::new_with_lt( 102 pdev.as_ref(), 103 AUXILIARY_NAME, 104 1, 105 MODULE_NAME, 106 Data { 107 index: 1, 108 parent: pdev, 109 }, 110 )? 111 }, 112 }) 113 } 114 } 115 116 impl ParentDriver { 117 fn connect(adev: &auxiliary::Device<Bound>) -> Result { 118 let data = adev.registration_data::<ForLt!(Data<'_>)>()?; 119 let pdev = data.parent; 120 121 dev_info!( 122 pdev, 123 "Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n", 124 adev.id(), 125 pdev.vendor_id(), 126 pdev.device_id() 127 ); 128 129 dev_info!( 130 pdev, 131 "Connected to auxiliary device with index {}.\n", 132 data.index 133 ); 134 135 Ok(()) 136 } 137 } 138 139 #[pin_data] 140 struct SampleModule { 141 #[pin] 142 _pci_driver: driver::Registration<pci::Adapter<ParentDriver>>, 143 #[pin] 144 _aux_driver: driver::Registration<auxiliary::Adapter<AuxiliaryDriver>>, 145 } 146 147 impl InPlaceModule for SampleModule { 148 fn init(module: &'static kernel::ThisModule) -> impl PinInit<Self, Error> { 149 try_pin_init!(Self { 150 _pci_driver <- driver::Registration::new(MODULE_NAME, module), 151 _aux_driver <- driver::Registration::new(MODULE_NAME, module), 152 }) 153 } 154 } 155 156 module! { 157 type: SampleModule, 158 name: "rust_driver_auxiliary", 159 authors: ["Danilo Krummrich"], 160 description: "Rust auxiliary driver", 161 license: "GPL v2", 162 } 163