Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
7use 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
18use core::any::TypeId;
19use pin_init::PinInit;
20
21const MODULE_NAME: &CStr = <LocalModule as kernel::ModuleMetadata>::NAME;
22const AUXILIARY_NAME: &CStr = c_str!("auxiliary");
23
24struct AuxiliaryDriver;
25
26kernel::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
33impl 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]
52struct ParentDriver {
53 private: TypeId,
54 #[pin]
55 _reg0: Devres<auxiliary::Registration>,
56 #[pin]
57 _reg1: Devres<auxiliary::Registration>,
58}
59
60kernel::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
67impl 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
81impl 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]
106struct SampleModule {
107 #[pin]
108 _pci_driver: driver::Registration<pci::Adapter<ParentDriver>>,
109 #[pin]
110 _aux_driver: driver::Registration<auxiliary::Adapter<AuxiliaryDriver>>,
111}
112
113impl 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
122module! {
123 type: SampleModule,
124 name: "rust_driver_auxiliary",
125 authors: ["Danilo Krummrich"],
126 description: "Rust auxiliary driver",
127 license: "GPL v2",
128}