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, bindings, c_str, device::Core, driver, error::Error, pci, prelude::*, str::CStr,
9 InPlaceModule,
10};
11
12use pin_init::PinInit;
13
14const MODULE_NAME: &CStr = <LocalModule as kernel::ModuleMetadata>::NAME;
15const AUXILIARY_NAME: &CStr = c_str!("auxiliary");
16
17struct AuxiliaryDriver;
18
19kernel::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
26impl 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) -> Result<Pin<KBox<Self>>> {
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 let this = KBox::new(Self, GFP_KERNEL)?;
41
42 Ok(this.into())
43 }
44}
45
46struct ParentDriver {
47 _reg: [auxiliary::Registration; 2],
48}
49
50kernel::pci_device_table!(
51 PCI_TABLE,
52 MODULE_PCI_TABLE,
53 <ParentDriver as pci::Driver>::IdInfo,
54 [(
55 pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5),
56 ()
57 )]
58);
59
60impl pci::Driver for ParentDriver {
61 type IdInfo = ();
62
63 const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
64
65 fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
66 let this = KBox::new(
67 Self {
68 _reg: [
69 auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 0, MODULE_NAME)?,
70 auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 1, MODULE_NAME)?,
71 ],
72 },
73 GFP_KERNEL,
74 )?;
75
76 Ok(this.into())
77 }
78}
79
80impl ParentDriver {
81 fn connect(adev: &auxiliary::Device) -> Result<()> {
82 let parent = adev.parent().ok_or(EINVAL)?;
83 let pdev: &pci::Device = parent.try_into()?;
84
85 dev_info!(
86 adev.as_ref(),
87 "Connect auxiliary {} with parent: VendorID={:#x}, DeviceID={:#x}\n",
88 adev.id(),
89 pdev.vendor_id(),
90 pdev.device_id()
91 );
92
93 Ok(())
94 }
95}
96
97#[pin_data]
98struct SampleModule {
99 #[pin]
100 _pci_driver: driver::Registration<pci::Adapter<ParentDriver>>,
101 #[pin]
102 _aux_driver: driver::Registration<auxiliary::Adapter<AuxiliaryDriver>>,
103}
104
105impl InPlaceModule for SampleModule {
106 fn init(module: &'static kernel::ThisModule) -> impl PinInit<Self, Error> {
107 try_pin_init!(Self {
108 _pci_driver <- driver::Registration::new(MODULE_NAME, module),
109 _aux_driver <- driver::Registration::new(MODULE_NAME, module),
110 })
111 }
112}
113
114module! {
115 type: SampleModule,
116 name: "rust_driver_auxiliary",
117 author: "Danilo Krummrich",
118 description: "Rust auxiliary driver",
119 license: "GPL v2",
120}