mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-03-03 18:28:01 +01:00
The driver model defines the lifetime of the private data stored in (and owned by) a bus device to be valid from when the driver is bound to a device (i.e. from successful probe()) until the driver is unbound from the device. This is already taken care of by the Rust implementation of the driver model. However, we still ask drivers to return a Result<Pin<KBox<Self>>> from probe(). Unlike in C, where we do not have the concept of initializers, but rather deal with uninitialized memory, drivers can just return an impl PinInit<Self, Error> instead. This contributes to more clarity to the fact that a driver returns it's device private data in probe() and the Rust driver model owns the data, manages the lifetime and - considering the lifetime - provides (safe) accessors for the driver. Hence, let probe() functions return an impl PinInit<Self, Error> instead of Result<Pin<KBox<Self>>>. Reviewed-by: Alice Ryhl <aliceryhl@google.com> Acked-by: Viresh Kumar <viresh.kumar@linaro.org> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
111 lines
2.9 KiB
Rust
111 lines
2.9 KiB
Rust
// 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, c_str, device::Core, driver, error::Error, pci, prelude::*, 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) -> impl PinInit<Self, Error> {
|
|
dev_info!(
|
|
adev.as_ref(),
|
|
"Probing auxiliary driver for auxiliary device with id={}\n",
|
|
adev.id()
|
|
);
|
|
|
|
ParentDriver::connect(adev)?;
|
|
|
|
Ok(Self)
|
|
}
|
|
}
|
|
|
|
struct ParentDriver {
|
|
_reg: [auxiliary::Registration; 2],
|
|
}
|
|
|
|
kernel::pci_device_table!(
|
|
PCI_TABLE,
|
|
MODULE_PCI_TABLE,
|
|
<ParentDriver as pci::Driver>::IdInfo,
|
|
[(pci::DeviceId::from_id(pci::Vendor::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) -> impl PinInit<Self, Error> {
|
|
Ok(Self {
|
|
_reg: [
|
|
auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 0, MODULE_NAME)?,
|
|
auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 1, MODULE_NAME)?,
|
|
],
|
|
})
|
|
}
|
|
}
|
|
|
|
impl ParentDriver {
|
|
fn connect(adev: &auxiliary::Device) -> Result<()> {
|
|
let parent = adev.parent().ok_or(EINVAL)?;
|
|
let pdev: &pci::Device = parent.try_into()?;
|
|
|
|
let vendor = pdev.vendor_id();
|
|
dev_info!(
|
|
adev.as_ref(),
|
|
"Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n",
|
|
adev.id(),
|
|
vendor,
|
|
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",
|
|
authors: ["Danilo Krummrich"],
|
|
description: "Rust auxiliary driver",
|
|
license: "GPL v2",
|
|
}
|