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