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