xref: /linux/samples/rust/rust_driver_auxiliary.rs (revision 99676aed1fec109d62822e21a06760eb098dc5f4)
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     driver,
14     pci,
15     prelude::*,
16     types::ForLt,
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<'bound> {
55     index: u32,
56     parent: &'bound pci::Device<Bound>,
57 }
58 
59 struct ParentDriver;
60 
61 #[allow(clippy::type_complexity)]
62 struct ParentData<'bound> {
63     _reg0: auxiliary::Registration<'bound, ForLt!(Data<'_>)>,
64     _reg1: auxiliary::Registration<'bound, ForLt!(Data<'_>)>,
65 }
66 
67 kernel::pci_device_table!(
68     PCI_TABLE,
69     MODULE_PCI_TABLE,
70     <ParentDriver as pci::Driver>::IdInfo,
71     [(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())]
72 );
73 
74 impl pci::Driver for ParentDriver {
75     type IdInfo = ();
76     type Data<'bound> = ParentData<'bound>;
77 
78     const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
79 
80     fn probe<'bound>(
81         pdev: &'bound pci::Device<Core<'_>>,
82         _info: &'bound Self::IdInfo,
83     ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
84         Ok(ParentData {
85             // SAFETY: `ParentData` is the driver's private data, which is dropped when the
86             // device is unbound; i.e. `mem::forget()` is never called on it.
87             _reg0: unsafe {
88                 auxiliary::Registration::new_with_lt(
89                     pdev.as_ref(),
90                     AUXILIARY_NAME,
91                     0,
92                     MODULE_NAME,
93                     Data {
94                         index: 0,
95                         parent: pdev,
96                     },
97                 )?
98             },
99             // SAFETY: See `_reg0` above.
100             _reg1: unsafe {
101                 auxiliary::Registration::new_with_lt(
102                     pdev.as_ref(),
103                     AUXILIARY_NAME,
104                     1,
105                     MODULE_NAME,
106                     Data {
107                         index: 1,
108                         parent: pdev,
109                     },
110                 )?
111             },
112         })
113     }
114 }
115 
116 impl ParentDriver {
117     fn connect(adev: &auxiliary::Device<Bound>) -> Result {
118         let data = adev.registration_data::<ForLt!(Data<'_>)>()?;
119         let pdev = data.parent;
120 
121         dev_info!(
122             pdev,
123             "Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n",
124             adev.id(),
125             pdev.vendor_id(),
126             pdev.device_id()
127         );
128 
129         dev_info!(
130             pdev,
131             "Connected to auxiliary device with index {}.\n",
132             data.index
133         );
134 
135         Ok(())
136     }
137 }
138 
139 #[pin_data]
140 struct SampleModule {
141     #[pin]
142     _pci_driver: driver::Registration<pci::Adapter<ParentDriver>>,
143     #[pin]
144     _aux_driver: driver::Registration<auxiliary::Adapter<AuxiliaryDriver>>,
145 }
146 
147 impl InPlaceModule for SampleModule {
148     fn init(module: &'static kernel::ThisModule) -> impl PinInit<Self, Error> {
149         try_pin_init!(Self {
150             _pci_driver <- driver::Registration::new(MODULE_NAME, module),
151             _aux_driver <- driver::Registration::new(MODULE_NAME, module),
152         })
153     }
154 }
155 
156 module! {
157     type: SampleModule,
158     name: "rust_driver_auxiliary",
159     authors: ["Danilo Krummrich"],
160     description: "Rust auxiliary driver",
161     license: "GPL v2",
162 }
163