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