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<'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 { 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<'bound> = Self; 73 74 const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; 75 76 fn probe<'bound>( 77 pdev: &'bound pci::Device<Core<'_>>, 78 _info: &'bound Self::IdInfo, 79 ) -> impl PinInit<Self, Error> + 'bound { 80 Ok(Self { 81 _reg0: auxiliary::Registration::new( 82 pdev.as_ref(), 83 AUXILIARY_NAME, 84 0, 85 MODULE_NAME, 86 Data { index: 0 }, 87 )?, 88 _reg1: auxiliary::Registration::new( 89 pdev.as_ref(), 90 AUXILIARY_NAME, 91 1, 92 MODULE_NAME, 93 Data { index: 1 }, 94 )?, 95 }) 96 } 97 } 98 99 impl ParentDriver { 100 fn connect(adev: &auxiliary::Device<Bound>) -> Result { 101 let dev = adev.parent(); 102 let pdev: &pci::Device<Bound> = dev.try_into()?; 103 104 let data = adev.registration_data::<Data>()?; 105 106 dev_info!( 107 dev, 108 "Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n", 109 adev.id(), 110 pdev.vendor_id(), 111 pdev.device_id() 112 ); 113 114 dev_info!( 115 dev, 116 "Connected to auxiliary device with index {}.\n", 117 data.index 118 ); 119 120 Ok(()) 121 } 122 } 123 124 #[pin_data] 125 struct SampleModule { 126 #[pin] 127 _pci_driver: driver::Registration<pci::Adapter<ParentDriver>>, 128 #[pin] 129 _aux_driver: driver::Registration<auxiliary::Adapter<AuxiliaryDriver>>, 130 } 131 132 impl InPlaceModule for SampleModule { 133 fn init(module: &'static kernel::ThisModule) -> impl PinInit<Self, Error> { 134 try_pin_init!(Self { 135 _pci_driver <- driver::Registration::new(MODULE_NAME, module), 136 _aux_driver <- driver::Registration::new(MODULE_NAME, module), 137 }) 138 } 139 } 140 141 module! { 142 type: SampleModule, 143 name: "rust_driver_auxiliary", 144 authors: ["Danilo Krummrich"], 145 description: "Rust auxiliary driver", 146 license: "GPL v2", 147 } 148