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