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 use core::any::TypeId; 21 22 const MODULE_NAME: &CStr = <LocalModule as kernel::ModuleMetadata>::NAME; 23 const AUXILIARY_NAME: &CStr = c"auxiliary"; 24 25 struct AuxiliaryDriver; 26 27 kernel::auxiliary_device_table!( 28 AUX_TABLE, 29 MODULE_AUX_TABLE, 30 <AuxiliaryDriver as auxiliary::Driver>::IdInfo, 31 [(auxiliary::DeviceId::new(MODULE_NAME, AUXILIARY_NAME), ())] 32 ); 33 34 impl auxiliary::Driver for AuxiliaryDriver { 35 type IdInfo = (); 36 37 const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE; 38 39 fn probe(adev: &auxiliary::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { 40 dev_info!( 41 adev, 42 "Probing auxiliary driver for auxiliary device with id={}\n", 43 adev.id() 44 ); 45 46 ParentDriver::connect(adev)?; 47 48 Ok(Self) 49 } 50 } 51 52 #[pin_data] 53 struct ParentDriver { 54 private: TypeId, 55 #[pin] 56 _reg0: Devres<auxiliary::Registration>, 57 #[pin] 58 _reg1: Devres<auxiliary::Registration>, 59 } 60 61 kernel::pci_device_table!( 62 PCI_TABLE, 63 MODULE_PCI_TABLE, 64 <ParentDriver as pci::Driver>::IdInfo, 65 [(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())] 66 ); 67 68 impl pci::Driver for ParentDriver { 69 type IdInfo = (); 70 71 const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; 72 73 fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> { 74 try_pin_init!(Self { 75 private: TypeId::of::<Self>(), 76 _reg0 <- auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 0, MODULE_NAME), 77 _reg1 <- auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 1, MODULE_NAME), 78 }) 79 } 80 } 81 82 impl ParentDriver { 83 fn connect(adev: &auxiliary::Device<Bound>) -> Result { 84 let dev = adev.parent(); 85 let pdev: &pci::Device<Bound> = dev.try_into()?; 86 let drvdata = dev.drvdata::<Self>()?; 87 88 dev_info!( 89 dev, 90 "Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n", 91 adev.id(), 92 pdev.vendor_id(), 93 pdev.device_id() 94 ); 95 96 dev_info!( 97 dev, 98 "We have access to the private data of {:?}.\n", 99 drvdata.private 100 ); 101 102 Ok(()) 103 } 104 } 105 106 #[pin_data] 107 struct SampleModule { 108 #[pin] 109 _pci_driver: driver::Registration<pci::Adapter<ParentDriver>>, 110 #[pin] 111 _aux_driver: driver::Registration<auxiliary::Adapter<AuxiliaryDriver>>, 112 } 113 114 impl InPlaceModule for SampleModule { 115 fn init(module: &'static kernel::ThisModule) -> impl PinInit<Self, Error> { 116 try_pin_init!(Self { 117 _pci_driver <- driver::Registration::new(MODULE_NAME, module), 118 _aux_driver <- driver::Registration::new(MODULE_NAME, module), 119 }) 120 } 121 } 122 123 module! { 124 type: SampleModule, 125 name: "rust_driver_auxiliary", 126 authors: ["Danilo Krummrich"], 127 description: "Rust auxiliary driver", 128 license: "GPL v2", 129 } 130