samples: rust: add Rust auxiliary driver sample
authorDanilo Krummrich <dakr@kernel.org>
Mon, 14 Apr 2025 13:18:08 +0000 (15:18 +0200)
committerDanilo Krummrich <dakr@kernel.org>
Sat, 19 Apr 2025 12:24:05 +0000 (14:24 +0200)
Add a sample Rust auxiliary driver based on a PCI driver for QEMU's
"pci-testdev" device.

The PCI driver only registers an auxiliary device, in order to make the
corresponding auxiliary driver probe.

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://lore.kernel.org/r/20250414131934.28418-6-dakr@kernel.org
[ Use `ok_or()` when accessing auxiliary::Device::parent(). - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
MAINTAINERS
samples/rust/Kconfig
samples/rust/Makefile
samples/rust/rust_driver_auxiliary.rs [new file with mode: 0644]

index 5a19522931192fe368f15c7b77490cd26b0fd8ec..34757b8641c33f43857ab2fe765e569ffe308229 100644 (file)
@@ -3874,6 +3874,7 @@ F:        drivers/base/auxiliary.c
 F:     include/linux/auxiliary_bus.h
 F:     rust/helpers/auxiliary.c
 F:     rust/kernel/auxiliary.rs
+F:     samples/rust/rust_driver_auxiliary.rs
 
 AUXILIARY DISPLAY DRIVERS
 M:     Andy Shevchenko <andy@kernel.org>
index cad52b7120b5143e85d737234be4ff27d2c7f99f..43cb72d72631bb2d6e06185e1d88778edff6ee13 100644 (file)
@@ -82,6 +82,18 @@ config SAMPLE_RUST_DRIVER_FAUX
 
          If unsure, say N.
 
+config SAMPLE_RUST_DRIVER_AUXILIARY
+       tristate "Auxiliary Driver"
+       depends on AUXILIARY_BUS
+       depends on PCI
+       help
+         This option builds the Rust auxiliary driver sample.
+
+         To compile this as a module, choose M here:
+         the module will be called rust_driver_auxiliary.
+
+         If unsure, say N.
+
 config SAMPLE_RUST_HOSTPROGS
        bool "Host programs"
        help
index c6a2479f7d9cf3a8695fa08b33b71d0df077eb59..6a466afd2a21eba84a3b7b2be29f25dce44e9053 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_SAMPLE_RUST_DMA)                   += rust_dma.o
 obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI)           += rust_driver_pci.o
 obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM)      += rust_driver_platform.o
 obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX)          += rust_driver_faux.o
+obj-$(CONFIG_SAMPLE_RUST_DRIVER_AUXILIARY)     += rust_driver_auxiliary.o
 
 rust_print-y := rust_print_main.o rust_print_events.o
 
diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs
new file mode 100644 (file)
index 0000000..3e15e6d
--- /dev/null
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust auxiliary driver sample (based on a PCI driver for QEMU's `pci-testdev`).
+//!
+//! To make this driver probe, QEMU must be run with `-device pci-testdev`.
+
+use kernel::{
+    auxiliary, bindings, c_str, device::Core, driver, error::Error, pci, prelude::*, str::CStr,
+    InPlaceModule,
+};
+
+use pin_init::PinInit;
+
+const MODULE_NAME: &CStr = <LocalModule as kernel::ModuleMetadata>::NAME;
+const AUXILIARY_NAME: &CStr = c_str!("auxiliary");
+
+struct AuxiliaryDriver;
+
+kernel::auxiliary_device_table!(
+    AUX_TABLE,
+    MODULE_AUX_TABLE,
+    <AuxiliaryDriver as auxiliary::Driver>::IdInfo,
+    [(auxiliary::DeviceId::new(MODULE_NAME, AUXILIARY_NAME), ())]
+);
+
+impl auxiliary::Driver for AuxiliaryDriver {
+    type IdInfo = ();
+
+    const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE;
+
+    fn probe(adev: &auxiliary::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
+        dev_info!(
+            adev.as_ref(),
+            "Probing auxiliary driver for auxiliary device with id={}\n",
+            adev.id()
+        );
+
+        ParentDriver::connect(adev)?;
+
+        let this = KBox::new(Self, GFP_KERNEL)?;
+
+        Ok(this.into())
+    }
+}
+
+struct ParentDriver {
+    _reg: [auxiliary::Registration; 2],
+}
+
+kernel::pci_device_table!(
+    PCI_TABLE,
+    MODULE_PCI_TABLE,
+    <ParentDriver as pci::Driver>::IdInfo,
+    [(
+        pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5),
+        ()
+    )]
+);
+
+impl pci::Driver for ParentDriver {
+    type IdInfo = ();
+
+    const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
+
+    fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
+        let this = KBox::new(
+            Self {
+                _reg: [
+                    auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 0, MODULE_NAME)?,
+                    auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 1, MODULE_NAME)?,
+                ],
+            },
+            GFP_KERNEL,
+        )?;
+
+        Ok(this.into())
+    }
+}
+
+impl ParentDriver {
+    fn connect(adev: &auxiliary::Device) -> Result<()> {
+        let parent = adev.parent().ok_or(EINVAL)?;
+        let pdev: &pci::Device = parent.try_into()?;
+
+        dev_info!(
+            adev.as_ref(),
+            "Connect auxiliary {} with parent: VendorID={:#x}, DeviceID={:#x}\n",
+            adev.id(),
+            pdev.vendor_id(),
+            pdev.device_id()
+        );
+
+        Ok(())
+    }
+}
+
+#[pin_data]
+struct SampleModule {
+    #[pin]
+    _pci_driver: driver::Registration<pci::Adapter<ParentDriver>>,
+    #[pin]
+    _aux_driver: driver::Registration<auxiliary::Adapter<AuxiliaryDriver>>,
+}
+
+impl InPlaceModule for SampleModule {
+    fn init(module: &'static kernel::ThisModule) -> impl PinInit<Self, Error> {
+        try_pin_init!(Self {
+            _pci_driver <- driver::Registration::new(MODULE_NAME, module),
+            _aux_driver <- driver::Registration::new(MODULE_NAME, module),
+        })
+    }
+}
+
+module! {
+    type: SampleModule,
+    name: "rust_driver_auxiliary",
+    author: "Danilo Krummrich",
+    description: "Rust auxiliary driver",
+    license: "GPL v2",
+}