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