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