xref: /linux/samples/rust/rust_driver_auxiliary.rs (revision 46f651d88662ef931555cd135f09382af206295a)
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