Extend the Rust sample platform driver to probe using device/driver name
matching, OF ID table matching, or ACPI ID table matching.
Signed-off-by: Igor Korotin <igor.korotin.linux@gmail.com>
---
samples/rust/rust_driver_platform.rs | 71 +++++++++++++++++++++++++++-
1 file changed, 70 insertions(+), 1 deletion(-)
diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs
index 8b42b3cfb363..35d5067aa023 100644
--- a/samples/rust/rust_driver_platform.rs
+++ b/samples/rust/rust_driver_platform.rs
@@ -2,7 +2,7 @@
//! Rust Platform driver sample.
-use kernel::{c_str, device::Core, of, platform, prelude::*, types::ARef};
+use kernel::{acpi, c_str, device::Core, of, platform, prelude::*, types::ARef};
struct SampleDriver {
pdev: ARef<platform::Device>,
@@ -17,9 +17,78 @@ struct SampleDriver {
[(of::DeviceId::new(c_str!("test,rust-device")), Info(42))]
);
+// ACPI match table test
+//
+// This demonstrates how to test an ACPI-based Rust platform driver using QEMU
+// with a custom SSDT.
+//
+// Steps:
+//
+// 1. **Create an SSDT source file** (`ssdt.dsl`) with the following content:
+//
+// ```asl
+// DefinitionBlock ("", "SSDT", 2, "TEST", "VIRTACPI", 0x00000001)
+// {
+// Scope (\_SB)
+// {
+// Device (T432)
+// {
+// Name (_HID, "TEST4321") // ACPI hardware ID to match
+// Name (_UID, 1)
+// Name (_STA, 0x0F) // Device present, enabled
+// Name (_CRS, ResourceTemplate ()
+// {
+// Memory32Fixed (ReadWrite, 0xFED00000, 0x1000)
+// })
+// }
+// }
+// }
+// ```
+//
+// 2. **Compile the table**:
+//
+// ```sh
+// iasl -tc ssdt.dsl
+// ```
+//
+// This generates `ssdt.aml`
+//
+// 3. **Run QEMU** with the compiled AML file:
+//
+// ```sh
+// qemu-system-x86_64 -m 512M \
+// -enable-kvm \
+// -kernel path/to/bzImage \
+// -append "root=/dev/sda console=ttyS0" \
+// -hda rootfs.img \
+// -serial stdio \
+// -acpitable file=ssdt.aml
+// ```
+//
+// Requirements:
+// - The `rust_driver_platform` must be present either:
+// - built directly into the kernel (`bzImage`), or
+// - available as a `.ko` file and loadable from `rootfs.img`
+//
+// 4. **Verify it worked** by checking `dmesg`:
+//
+// ```
+// rust_driver_platform TEST4321:00: Probed with info: '0'.
+// ```
+//
+// This demonstrates ACPI table matching using a custom ID in QEMU with a minimal SSDT
+
+kernel::acpi_device_table!(
+ ACPI_TABLE,
+ MODULE_ACPI_TABLE,
+ <SampleDriver as platform::Driver>::IdInfo,
+ [(acpi::DeviceId::new(c_str!("TEST4321")), Info(0))]
+);
+
impl platform::Driver for SampleDriver {
type IdInfo = Info;
const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
+ const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE);
fn probe(
pdev: &platform::Device<Core>,
--
2.43.0
On Fri, Jun 13, 2025 at 02:54:07PM +0100, Igor Korotin wrote:
> Extend the Rust sample platform driver to probe using device/driver name
> matching, OF ID table matching, or ACPI ID table matching.
Can you please rebase onto driver-core-next? You may also want to add the three
patches I sent as a reply to this one to your series.
> Signed-off-by: Igor Korotin <igor.korotin.linux@gmail.com>
> ---
> samples/rust/rust_driver_platform.rs | 71 +++++++++++++++++++++++++++-
> 1 file changed, 70 insertions(+), 1 deletion(-)
>
> diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs
> index 8b42b3cfb363..35d5067aa023 100644
> --- a/samples/rust/rust_driver_platform.rs
> +++ b/samples/rust/rust_driver_platform.rs
> @@ -2,7 +2,7 @@
>
> //! Rust Platform driver sample.
>
> -use kernel::{c_str, device::Core, of, platform, prelude::*, types::ARef};
> +use kernel::{acpi, c_str, device::Core, of, platform, prelude::*, types::ARef};
>
> struct SampleDriver {
> pdev: ARef<platform::Device>,
> @@ -17,9 +17,78 @@ struct SampleDriver {
> [(of::DeviceId::new(c_str!("test,rust-device")), Info(42))]
> );
>
> +// ACPI match table test
> +//
> +// This demonstrates how to test an ACPI-based Rust platform driver using QEMU
> +// with a custom SSDT.
> +//
> +// Steps:
> +//
> +// 1. **Create an SSDT source file** (`ssdt.dsl`) with the following content:
> +//
> +// ```asl
> +// DefinitionBlock ("", "SSDT", 2, "TEST", "VIRTACPI", 0x00000001)
> +// {
> +// Scope (\_SB)
> +// {
> +// Device (T432)
> +// {
> +// Name (_HID, "TEST4321") // ACPI hardware ID to match
> +// Name (_UID, 1)
> +// Name (_STA, 0x0F) // Device present, enabled
> +// Name (_CRS, ResourceTemplate ()
> +// {
> +// Memory32Fixed (ReadWrite, 0xFED00000, 0x1000)
> +// })
> +// }
> +// }
> +// }
> +// ```
> +//
> +// 2. **Compile the table**:
> +//
> +// ```sh
> +// iasl -tc ssdt.dsl
> +// ```
> +//
> +// This generates `ssdt.aml`
> +//
> +// 3. **Run QEMU** with the compiled AML file:
> +//
> +// ```sh
> +// qemu-system-x86_64 -m 512M \
> +// -enable-kvm \
> +// -kernel path/to/bzImage \
> +// -append "root=/dev/sda console=ttyS0" \
> +// -hda rootfs.img \
> +// -serial stdio \
> +// -acpitable file=ssdt.aml
> +// ```
> +//
> +// Requirements:
> +// - The `rust_driver_platform` must be present either:
> +// - built directly into the kernel (`bzImage`), or
> +// - available as a `.ko` file and loadable from `rootfs.img`
> +//
> +// 4. **Verify it worked** by checking `dmesg`:
> +//
> +// ```
> +// rust_driver_platform TEST4321:00: Probed with info: '0'.
> +// ```
> +//
> +// This demonstrates ACPI table matching using a custom ID in QEMU with a minimal SSDT
Can you please move this up into the module-level documentation?
> +kernel::acpi_device_table!(
> + ACPI_TABLE,
> + MODULE_ACPI_TABLE,
> + <SampleDriver as platform::Driver>::IdInfo,
> + [(acpi::DeviceId::new(c_str!("TEST4321")), Info(0))]
Let's use something like "SAMPLE_DRV0" instead.
> +);
> +
> impl platform::Driver for SampleDriver {
> type IdInfo = Info;
> const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
> + const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE);
>
> fn probe(
> pdev: &platform::Device<Core>,
> --
> 2.43.0
>
On 6/16/25 20:52, Danilo Krummrich wrote:
>> +kernel::acpi_device_table!(
>> + ACPI_TABLE,
>> + MODULE_ACPI_TABLE,
>> + <SampleDriver as platform::Driver>::IdInfo,
>> + [(acpi::DeviceId::new(c_str!("TEST4321")), Info(0))]
>
> Let's use something like "SAMPLE_DRV0" instead.
Nope, that's prohibited by ACPI HID naming rules. A brief description
can be found here:
https://uefi.org/specs/ACPI/6.5/06_Device_Configuration.html.
According to section 6.1.5, ACPI IDs must be 7 or 8 characters long and
follow the format "AAA####" or "AAAA####", where A is an uppercase
letter [A–Z] and # is an uppercase letter or digit [A–Z, 0–9]. No
underscores or special characters are allowed.
The `iasl` utility throws an error if an invalid HID string is used in a
dsl file.
I could suggest on of the following:
DRV0001
DRVR0001
PDRV0001
TEST0001
TST0001
Let me know which one you'd prefer for the code and documentation.
Best Regards
Igor
On Tue, Jun 17, 2025 at 05:39:07PM +0100, Igor Korotin wrote: > I could suggest on of the following: > DRV0001 > DRVR0001 > PDRV0001 This one looks reasonable to me. > TEST0001 > TST0001
On Tue, Jun 17, 2025 at 7:15 PM Danilo Krummrich <dakr@kernel.org> wrote: > > On Tue, Jun 17, 2025 at 05:39:07PM +0100, Igor Korotin wrote: > > I could suggest on of the following: > > DRV0001 > > DRVR0001 > > PDRV0001 > > This one looks reasonable to me. > > > TEST0001 > > TST0001 Can we please avoid using made up device IDs in the code, even if it is just sample code? It is way better to use a real one that's been reserved already as "never use in real ACPI tables" for some reason. I think I can find a few of these for you if need be. Thanks!
On Wed, Jun 25, 2025 at 11:17:33AM +0200, Rafael J. Wysocki wrote: > On Tue, Jun 17, 2025 at 7:15 PM Danilo Krummrich <dakr@kernel.org> wrote: > > > > On Tue, Jun 17, 2025 at 05:39:07PM +0100, Igor Korotin wrote: > > > I could suggest on of the following: > > > DRV0001 > > > DRVR0001 > > > PDRV0001 > > > > This one looks reasonable to me. > > > > > TEST0001 > > > TST0001 > > Can we please avoid using made up device IDs in the code, even if it > is just sample code? > > It is way better to use a real one that's been reserved already as > "never use in real ACPI tables" for some reason. I think I can find a > few of these for you if need be. > > Thanks! Sure! Please let me know which one you think fits best and I'll use it instead of "TST0001" when I apply the series. - Danilo
Implement FwNode::is_compatible() to check whether a given match string
is compatible with a FwNode.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
rust/helpers/property.c | 6 ++++++
rust/kernel/device/property.rs | 9 +++++++++
2 files changed, 15 insertions(+)
diff --git a/rust/helpers/property.c b/rust/helpers/property.c
index 08f68e2dac4a..177b9ffd7ba4 100644
--- a/rust/helpers/property.c
+++ b/rust/helpers/property.c
@@ -6,3 +6,9 @@ void rust_helper_fwnode_handle_put(struct fwnode_handle *fwnode)
{
fwnode_handle_put(fwnode);
}
+
+bool rust_helper_fwnode_device_is_compatible(const struct fwnode_handle *fwnode,
+ const char *match)
+{
+ return fwnode_device_is_compatible(fwnode, match);
+}
diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs
index 838509111e57..a946bf8d5571 100644
--- a/rust/kernel/device/property.rs
+++ b/rust/kernel/device/property.rs
@@ -93,6 +93,15 @@ pub fn property_present(&self, name: &CStr) -> bool {
unsafe { bindings::fwnode_property_present(self.as_raw().cast_const(), name.as_char_ptr()) }
}
+ /// Return `true` if this [`FwNode`] is compatible with `match_str`, `false` otherwise.
+ pub fn is_compatible(&self, match_str: &CStr) -> bool {
+ // SAFETY:
+ // - By the invariant of `CStr`, `name.as_char_ptr()` is valid and null-terminated.
+ // - The type invariant of `Self` guarantees that `self.as_raw() is a pointer to a valid
+ // `struct fwnode_handle`.
+ unsafe { bindings::fwnode_device_is_compatible(self.as_raw(), match_str.as_char_ptr()) }
+ }
+
/// Returns firmware property `name` boolean value.
pub fn property_read_bool(&self, name: &CStr) -> bool {
// SAFETY:
base-commit: 2a1ea59de83bf367215e2a4dd9bf8bbd061349b3
--
2.49.0
In SampleDriver::probe() don't call pdev.as_ref() repeatedly, instead
introduce a dedicated &Device.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
samples/rust/rust_driver_platform.rs | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs
index c0abf78d0683..000bb915af60 100644
--- a/samples/rust/rust_driver_platform.rs
+++ b/samples/rust/rust_driver_platform.rs
@@ -32,13 +32,15 @@ fn probe(
pdev: &platform::Device<Core>,
info: Option<&Self::IdInfo>,
) -> Result<Pin<KBox<Self>>> {
- dev_dbg!(pdev.as_ref(), "Probe Rust Platform driver sample.\n");
+ let dev = pdev.as_ref();
+
+ dev_dbg!(dev, "Probe Rust Platform driver sample.\n");
if let Some(info) = info {
- dev_info!(pdev.as_ref(), "Probed with info: '{}'.\n", info.0);
+ dev_info!(dev, "Probed with info: '{}'.\n", info.0);
}
- Self::properties_parse(pdev.as_ref())?;
+ Self::properties_parse(dev)?;
let drvdata = KBox::new(Self { pdev: pdev.into() }, GFP_KERNEL)?;
--
2.49.0
On 16/06/2025 21:40, Danilo Krummrich wrote:
> In SampleDriver::probe() don't call pdev.as_ref() repeatedly, instead
> introduce a dedicated &Device.
>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
> samples/rust/rust_driver_platform.rs | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs
> index c0abf78d0683..000bb915af60 100644
> --- a/samples/rust/rust_driver_platform.rs
> +++ b/samples/rust/rust_driver_platform.rs
> @@ -32,13 +32,15 @@ fn probe(
> pdev: &platform::Device<Core>,
> info: Option<&Self::IdInfo>,
> ) -> Result<Pin<KBox<Self>>> {
> - dev_dbg!(pdev.as_ref(), "Probe Rust Platform driver sample.\n");
> + let dev = pdev.as_ref();
> +
> + dev_dbg!(dev, "Probe Rust Platform driver sample.\n");
>
> if let Some(info) = info {
> - dev_info!(pdev.as_ref(), "Probed with info: '{}'.\n", info.0);
> + dev_info!(dev, "Probed with info: '{}'.\n", info.0);
> }
>
> - Self::properties_parse(pdev.as_ref())?;
> + Self::properties_parse(dev)?;
>
> let drvdata = KBox::new(Self { pdev: pdev.into() }, GFP_KERNEL)?;
Yes!
Reviewed-by: Dirk Behme <dirk.behme@de.bosch.com>
Thanks,
Dirk
Only call Self::properties_parse() when the device is compatible with
"test,rust-device".
Once we add ACPI support, we don't want the ACPI device to fail probing
in Self::properties_parse().
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
samples/rust/rust_driver_platform.rs | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs
index 000bb915af60..036dd0b899b0 100644
--- a/samples/rust/rust_driver_platform.rs
+++ b/samples/rust/rust_driver_platform.rs
@@ -40,7 +40,12 @@ fn probe(
dev_info!(dev, "Probed with info: '{}'.\n", info.0);
}
- Self::properties_parse(dev)?;
+ if dev
+ .fwnode()
+ .is_some_and(|node| node.is_compatible(c_str!("test,rust-device")))
+ {
+ Self::properties_parse(dev)?;
+ }
let drvdata = KBox::new(Self { pdev: pdev.into() }, GFP_KERNEL)?;
--
2.49.0
© 2016 - 2026 Red Hat, Inc.