From fcad9bbf9e1a7de6c53908954ba1b1a1ab11ef1e Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sun, 15 Jun 2025 16:55:05 -0400 Subject: rust: enable `clippy::ptr_as_ptr` lint In Rust 1.51.0, Clippy introduced the `ptr_as_ptr` lint [1]: > Though `as` casts between raw pointers are not terrible, > `pointer::cast` is safer because it cannot accidentally change the > pointer's mutability, nor cast the pointer to other types like `usize`. There are a few classes of changes required: - Modules generated by bindgen are marked `#[allow(clippy::ptr_as_ptr)]`. - Inferred casts (` as _`) are replaced with `.cast()`. - Ascribed casts (` as *... T`) are replaced with `.cast::()`. - Multistep casts from references (` as *const _ as *const T`) are replaced with `core::ptr::from_ref(&x).cast()` with or without `::` according to the previous rules. The `core::ptr::from_ref` call is required because `(x as *const _).cast::()` results in inference failure. - Native literal C strings are replaced with `c_str!().as_char_ptr()`. - `*mut *mut T as _` is replaced with `let *mut *const T = (*mut *mut T)`.cast();` since pointer to pointer can be confusing. Apply these changes and enable the lint -- no functional change intended. Link: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr [1] Reviewed-by: Benno Lossin Reviewed-by: Boqun Feng Signed-off-by: Tamir Duberstein Acked-by: Viresh Kumar Acked-by: Greg Kroah-Hartman Acked-by: Tejun Heo Acked-by: Danilo Krummrich Link: https://lore.kernel.org/r/20250615-ptr-as-ptr-v12-1-f43b024581e8@gmail.com [ Added `.cast()` for `opp`. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/platform.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'rust/kernel/platform.rs') diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 5b21fa517e55..4b06f9fbc172 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -69,7 +69,9 @@ impl Adapter { // Let the `struct platform_device` own a reference of the driver's private data. // SAFETY: By the type invariant `pdev.as_raw` returns a valid pointer to a // `struct platform_device`. - unsafe { bindings::platform_set_drvdata(pdev.as_raw(), data.into_foreign() as _) }; + unsafe { + bindings::platform_set_drvdata(pdev.as_raw(), data.into_foreign().cast()) + }; } Err(err) => return Error::to_errno(err), } -- cgit From b6985083be1deb1f5fa14d160265f57d9ccb42a1 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 10 Jun 2025 14:33:00 +0530 Subject: rust: Use consistent "# Examples" heading style in rustdoc Use a consistent `# Examples` heading in rustdoc across the codebase. Some modules previously used `## Examples` (even when they should be available as top-level headers), while others used `# Example`, which deviates from the preferred `# Examples` style. Suggested-by: Miguel Ojeda Signed-off-by: Viresh Kumar Acked-by: Benno Lossin Link: https://lore.kernel.org/r/ddd5ce0ac20c99a72a4f1e4322d3de3911056922.1749545815.git.viresh.kumar@linaro.org Signed-off-by: Miguel Ojeda --- rust/kernel/platform.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust/kernel/platform.rs') diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 4b06f9fbc172..0a6a6be732b2 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -122,7 +122,7 @@ macro_rules! module_platform_driver { /// /// Drivers must implement this trait in order to get a platform driver registered. /// -/// # Example +/// # Examples /// ///``` /// # use kernel::{bindings, c_str, device::Core, of, platform}; -- cgit From 7a5cb145a9ce844be41ca5ed26e7d8d7c41dec7d Mon Sep 17 00:00:00 2001 From: Igor Korotin Date: Fri, 20 Jun 2025 16:39:13 +0100 Subject: rust: driver: Add ACPI id table support to Adapter trait Extend the `Adapter` trait to support ACPI device identification. This mirrors the existing Open Firmware (OF) support (`of_id_table`) and enables Rust drivers to match and retrieve ACPI-specific device data when `CONFIG_ACPI` is enabled. To avoid breaking compilation, a stub implementation of `acpi_id_table()` is added to the Platform adapter; the full implementation will be provided in a subsequent patch. Signed-off-by: Igor Korotin Link: https://lore.kernel.org/r/20250620153914.295679-1-igor.korotin.linux@gmail.com [ Fix clippy warning if #[cfg(not(CONFIG_OF))]; fix checkpatch.pl line length warnings. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/platform.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'rust/kernel/platform.rs') diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 5b21fa517e55..5923d29a0511 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -5,7 +5,7 @@ //! C header: [`include/linux/platform_device.h`](srctree/include/linux/platform_device.h) use crate::{ - bindings, container_of, device, driver, + acpi, bindings, container_of, device, driver, error::{to_result, Result}, of, prelude::*, @@ -94,6 +94,10 @@ impl driver::Adapter for Adapter { fn of_id_table() -> Option> { T::OF_ID_TABLE } + + fn acpi_id_table() -> Option> { + None + } } /// Declares a kernel module that exposes a single platform driver. -- cgit From ec3ef2175e16360605c7e1b409ceaa77be6521a8 Mon Sep 17 00:00:00 2001 From: Igor Korotin Date: Fri, 20 Jun 2025 16:41:24 +0100 Subject: rust: platform: Set `OF_ID_TABLE` default to `None` in `Driver` trait Provide a default value of `None` for `Driver::OF_ID_TABLE` to simplify driver implementations. Drivers that do not require OpenFirmware matching no longer need to import the `of` module or define the constant explicitly. This reduces unnecessary boilerplate and avoids pulling in unused dependencies. Signed-off-by: Igor Korotin Link: https://lore.kernel.org/r/20250620154124.297158-1-igor.korotin.linux@gmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/platform.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust/kernel/platform.rs') diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 5923d29a0511..2436f55b579b 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -162,7 +162,7 @@ pub trait Driver: Send { type IdInfo: 'static; /// The table of OF device ids supported by the driver. - const OF_ID_TABLE: Option>; + const OF_ID_TABLE: Option> = None; /// Platform driver probe. /// -- cgit From 8411e6f06a022679a642c236724944057b90e60e Mon Sep 17 00:00:00 2001 From: Igor Korotin Date: Fri, 20 Jun 2025 16:43:34 +0100 Subject: rust: platform: Add ACPI match table support to `Driver` trait Extend the `platform::Driver` trait to support ACPI device matching by adding the `ACPI_ID_TABLE` constant. This allows Rust platform drivers to define ACPI match tables alongside their existing OF match tables. These changes mirror the existing OF support and allow Rust platform drivers to match devices based on ACPI identifiers. Signed-off-by: Igor Korotin Link: https://lore.kernel.org/r/20250620154334.298320-1-igor.korotin.linux@gmail.com [ Use 'LNUXBEEF' as ACPI ID. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/platform.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'rust/kernel/platform.rs') diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 2436f55b579b..86f9d73c64b3 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -37,12 +37,18 @@ unsafe impl driver::RegistrationOps for Adapter { None => core::ptr::null(), }; + let acpi_table = match T::ACPI_ID_TABLE { + Some(table) => table.as_ptr(), + None => core::ptr::null(), + }; + // SAFETY: It's safe to set the fields of `struct platform_driver` on initialization. unsafe { (*pdrv.get()).driver.name = name.as_char_ptr(); (*pdrv.get()).probe = Some(Self::probe_callback); (*pdrv.get()).remove = Some(Self::remove_callback); (*pdrv.get()).driver.of_match_table = of_table; + (*pdrv.get()).driver.acpi_match_table = acpi_table; } // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. @@ -96,7 +102,7 @@ impl driver::Adapter for Adapter { } fn acpi_id_table() -> Option> { - None + T::ACPI_ID_TABLE } } @@ -127,7 +133,7 @@ macro_rules! module_platform_driver { /// # Example /// ///``` -/// # use kernel::{bindings, c_str, device::Core, of, platform}; +/// # use kernel::{acpi, bindings, c_str, device::Core, of, platform}; /// /// struct MyDriver; /// @@ -140,9 +146,19 @@ macro_rules! module_platform_driver { /// ] /// ); /// +/// kernel::acpi_device_table!( +/// ACPI_TABLE, +/// MODULE_ACPI_TABLE, +/// ::IdInfo, +/// [ +/// (acpi::DeviceId::new(c_str!("LNUXBEEF")), ()) +/// ] +/// ); +/// /// impl platform::Driver for MyDriver { /// type IdInfo = (); /// const OF_ID_TABLE: Option> = Some(&OF_TABLE); +/// const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); /// /// fn probe( /// _pdev: &platform::Device, @@ -164,6 +180,9 @@ pub trait Driver: Send { /// The table of OF device ids supported by the driver. const OF_ID_TABLE: Option> = None; + /// The table of ACPI device ids supported by the driver. + const ACPI_ID_TABLE: Option> = None; + /// Platform driver probe. /// /// Called when a new platform device is added or discovered. -- cgit From 8ae33576ead8fb71505515df8c938b3e0ae5b37c Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Fri, 4 Jul 2025 15:49:54 -0400 Subject: rust: platform: remove unnecessary import `kernel::str::CStr` is included in the prelude. Signed-off-by: Tamir Duberstein Link: https://lore.kernel.org/r/20250704-cstr-include-platform-v1-1-ff7803ee7a81@gmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/platform.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'rust/kernel/platform.rs') diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 86f9d73c64b3..7484d7e5c2cf 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -9,7 +9,6 @@ use crate::{ error::{to_result, Result}, of, prelude::*, - str::CStr, types::{ForeignOwnable, Opaque}, ThisModule, }; -- cgit From f0a68a912c673d8899d863c2f01f1ef7006e0b11 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sat, 21 Jun 2025 21:43:29 +0200 Subject: rust: platform: use generic device drvdata accessors Take advantage of the generic drvdata accessors of the generic Device type. While at it, use from_result() instead of match. Link: https://lore.kernel.org/r/20250621195118.124245-4-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/platform.rs | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'rust/kernel/platform.rs') diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 7484d7e5c2cf..e9e95c5bb02b 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -6,10 +6,10 @@ use crate::{ acpi, bindings, container_of, device, driver, - error::{to_result, Result}, + error::{from_result, to_result, Result}, of, prelude::*, - types::{ForeignOwnable, Opaque}, + types::Opaque, ThisModule, }; @@ -66,30 +66,28 @@ impl Adapter { // `struct platform_device`. // // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. - let pdev = unsafe { &*pdev.cast::>() }; - + let pdev = unsafe { &*pdev.cast::>() }; let info = ::id_info(pdev.as_ref()); - match T::probe(pdev, info) { - Ok(data) => { - // Let the `struct platform_device` own a reference of the driver's private data. - // SAFETY: By the type invariant `pdev.as_raw` returns a valid pointer to a - // `struct platform_device`. - unsafe { bindings::platform_set_drvdata(pdev.as_raw(), data.into_foreign() as _) }; - } - Err(err) => return Error::to_errno(err), - } - 0 + from_result(|| { + let data = T::probe(pdev, info)?; + + pdev.as_ref().set_drvdata(data); + Ok(0) + }) } extern "C" fn remove_callback(pdev: *mut bindings::platform_device) { - // SAFETY: `pdev` is a valid pointer to a `struct platform_device`. - let ptr = unsafe { bindings::platform_get_drvdata(pdev) }.cast(); + // SAFETY: The platform bus only ever calls the remove callback with a valid pointer to a + // `struct platform_device`. + // + // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. + let pdev = unsafe { &*pdev.cast::>() }; // SAFETY: `remove_callback` is only ever called after a successful call to - // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized - // `KBox` pointer created through `KBox::into_foreign`. - let _ = unsafe { KBox::::from_foreign(ptr) }; + // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called + // and stored a `Pin>`. + let _ = unsafe { pdev.as_ref().drvdata_obtain::>>() }; } } -- cgit From 4be5f3fff151e49b0e7a82d33d4d12e91840abde Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sat, 21 Jun 2025 21:43:32 +0200 Subject: rust: platform: implement Driver::unbind() Currently, there's really only one core callback for drivers, which is probe(). Now, this isn't entirely true, since there is also the drop() callback of the driver type (serving as the driver's private data), which is returned by probe() and is dropped in remove(). On the C side remove() mainly serves two purposes: (1) Tear down the device that is operated by the driver, e.g. call bus specific functions, write I/O memory to reset the device, etc. (2) Free the resources that have been allocated by a driver for a specific device. The drop() callback mentioned above is intended to cover (2) as the Rust idiomatic way. However, it is partially insufficient and inefficient to cover (1) properly, since drop() can't be called with additional arguments, such as the reference to the corresponding device that has the correct device context, i.e. the Core device context. This makes it inefficient (but not impossible) to access device resources, e.g. to write device registers, and impossible to call device methods, which are only accessible under the Core device context. In order to solve this, add an additional callback for (1), which we call unbind(). The reason for calling it unbind() is that, unlike remove(), it is *only* meant to be used to perform teardown operations on the device (1), but *not* to release resources (2). Link: https://lore.kernel.org/r/20250621195118.124245-7-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/platform.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'rust/kernel/platform.rs') diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index e9e95c5bb02b..ced43367d900 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -87,7 +87,9 @@ impl Adapter { // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called // and stored a `Pin>`. - let _ = unsafe { pdev.as_ref().drvdata_obtain::>>() }; + let data = unsafe { pdev.as_ref().drvdata_obtain::>>() }; + + T::unbind(pdev, data.as_ref()); } } @@ -186,6 +188,20 @@ pub trait Driver: Send { /// Implementers should attempt to initialize the device here. fn probe(dev: &Device, id_info: Option<&Self::IdInfo>) -> Result>>; + + /// Platform driver unbind. + /// + /// Called when a [`Device`] is unbound from its bound [`Driver`]. Implementing this callback + /// is optional. + /// + /// This callback serves as a place for drivers to perform teardown operations that require a + /// `&Device` or `&Device` reference. For instance, drivers may try to perform I/O + /// operations to gracefully tear down the device. + /// + /// Otherwise, release operations for driver resources should be performed in `Self::drop`. + fn unbind(dev: &Device, this: Pin<&Self>) { + let _ = (dev, this); + } } /// The platform device representation. -- cgit From 12717ebeffcf3e34063dbc1e1b7f34924150c7c9 Mon Sep 17 00:00:00 2001 From: Andreas Hindborg Date: Thu, 12 Jun 2025 15:09:43 +0200 Subject: rust: types: add FOREIGN_ALIGN to ForeignOwnable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current implementation of `ForeignOwnable` is leaking the type of the opaque pointer to consumers of the API. This allows consumers of the opaque pointer to rely on the information that can be extracted from the pointer type. To prevent this, change the API to the version suggested by Maira Canal (link below): Remove `ForeignOwnable::PointedTo` in favor of a constant, which specifies the alignment of the pointers returned by `into_foreign`. With this change, `ArcInner` no longer needs `pub` visibility, so change it to private. Suggested-by: Alice Ryhl Suggested-by: MaĆ­ra Canal Link: https://lore.kernel.org/r/20240309235927.168915-3-mcanal@igalia.com Acked-by: Danilo Krummrich Reviewed-by: Benno Lossin Signed-off-by: Andreas Hindborg Reviewed-by: Alice Ryhl Link: https://lore.kernel.org/r/20250612-pointed-to-v3-1-b009006d86a1@kernel.org Signed-off-by: Miguel Ojeda --- rust/kernel/platform.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust/kernel/platform.rs') diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 0a6a6be732b2..e894790c510c 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -81,7 +81,7 @@ impl Adapter { extern "C" fn remove_callback(pdev: *mut bindings::platform_device) { // SAFETY: `pdev` is a valid pointer to a `struct platform_device`. - let ptr = unsafe { bindings::platform_get_drvdata(pdev) }.cast(); + let ptr = unsafe { bindings::platform_get_drvdata(pdev) }; // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized -- cgit From 2f5606afa4c2bcabd45cb34c92faf93ca5ffe75e Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 11 Jul 2025 08:04:37 +0000 Subject: device: rust: rename Device::as_ref() to Device::from_raw() The prefix as_* should not be used for a constructor. Constructors usually use the prefix from_* instead. Some prior art in the stdlib: Box::from_raw, CString::from_raw, Rc::from_raw, Arc::from_raw, Waker::from_raw, File::from_raw_fd. There is also prior art in the kernel crate: cpufreq::Policy::from_raw, fs::File::from_raw_file, Kuid::from_raw, ARef::from_raw, SeqFile::from_raw, VmaNew::from_raw, Io::from_raw. Link: https://lore.kernel.org/r/aCd8D5IA0RXZvtcv@pollux Signed-off-by: Alice Ryhl Reviewed-by: Benno Lossin Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250711-device-as-ref-v2-1-1b16ab6402d7@google.com Signed-off-by: Danilo Krummrich --- rust/kernel/platform.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust/kernel/platform.rs') diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index ced43367d900..3d7a532550c8 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -251,7 +251,7 @@ impl AsRef> for Device { let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) }; // SAFETY: `dev` points to a valid `struct device`. - unsafe { device::Device::as_ref(dev) } + unsafe { device::Device::from_raw(dev) } } } -- cgit From 256de48f2cad85153b271b66320a9355773db64e Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 16 Jul 2025 17:02:49 +0200 Subject: rust: platform: implement the `dma::Device` trait The platform bus is potentially capable of performing DMA, hence implement the `dma:Device` trait for `platform::Device`. Reviewed-by: Daniel Almeida Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250716150354.51081-5-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/platform.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'rust/kernel/platform.rs') diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 3d7a532550c8..3c0c507c2432 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -231,6 +231,8 @@ impl Device { kernel::impl_device_context_deref!(unsafe { Device }); kernel::impl_device_context_into_aref!(Device); +impl crate::dma::Device for Device {} + // SAFETY: Instances of `Device` are always reference-counted. unsafe impl crate::types::AlwaysRefCounted for Device { fn inc_ref(&self) { -- cgit From bc4f9045a59963abb142f6a648195ccd73ec39dd Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Thu, 17 Jul 2025 12:55:24 -0300 Subject: rust: platform: add resource accessors The previous patches have added the abstractions for Resources and the ability to map them and therefore read and write the underlying memory . The only thing missing to make this accessible for platform devices is to provide accessors that return instances of IoRequest<'a>. These ensure that the resource are valid only for the lifetime of the platform device, and that the platform device is in the Bound state. Therefore, add these accessors. Also make it possible to retrieve resources from platform devices in Rust using either a name or an index. Acked-by: Miguel Ojeda Signed-off-by: Daniel Almeida Link: https://lore.kernel.org/r/20250717-topics-tyr-platform_iomem-v15-3-beca780b77e3@collabora.com [ Remove #[expect(dead_code)] from IoRequest::new() and move SAFETY comments right on top of unsafe blocks to avoid clippy warnings for some (older) clippy versions. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/platform.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) (limited to 'rust/kernel/platform.rs') diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 3c0c507c2432..b4d3087aff52 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -5,8 +5,11 @@ //! C header: [`include/linux/platform_device.h`](srctree/include/linux/platform_device.h) use crate::{ - acpi, bindings, container_of, device, driver, + acpi, bindings, container_of, + device::{self, Bound}, + driver, error::{from_result, to_result, Result}, + io::{mem::IoRequest, Resource}, of, prelude::*, types::Opaque, @@ -224,6 +227,61 @@ impl Device { fn as_raw(&self) -> *mut bindings::platform_device { self.0.get() } + + /// Returns the resource at `index`, if any. + pub fn resource_by_index(&self, index: u32) -> Option<&Resource> { + // SAFETY: `self.as_raw()` returns a valid pointer to a `struct platform_device`. + let resource = unsafe { + bindings::platform_get_resource(self.as_raw(), bindings::IORESOURCE_MEM, index) + }; + + if resource.is_null() { + return None; + } + + // SAFETY: `resource` is a valid pointer to a `struct resource` as + // returned by `platform_get_resource`. + Some(unsafe { Resource::from_raw(resource) }) + } + + /// Returns the resource with a given `name`, if any. + pub fn resource_by_name(&self, name: &CStr) -> Option<&Resource> { + // SAFETY: `self.as_raw()` returns a valid pointer to a `struct + // platform_device` and `name` points to a valid C string. + let resource = unsafe { + bindings::platform_get_resource_byname( + self.as_raw(), + bindings::IORESOURCE_MEM, + name.as_char_ptr(), + ) + }; + + if resource.is_null() { + return None; + } + + // SAFETY: `resource` is a valid pointer to a `struct resource` as + // returned by `platform_get_resource`. + Some(unsafe { Resource::from_raw(resource) }) + } +} + +impl Device { + /// Returns an `IoRequest` for the resource at `index`, if any. + pub fn io_request_by_index(&self, index: u32) -> Option> { + self.resource_by_index(index) + // SAFETY: `resource` is a valid resource for `&self` during the + // lifetime of the `IoRequest`. + .map(|resource| unsafe { IoRequest::new(self.as_ref(), resource) }) + } + + /// Returns an `IoRequest` for the resource with a given `name`, if any. + pub fn io_request_by_name(&self, name: &CStr) -> Option> { + self.resource_by_name(name) + // SAFETY: `resource` is a valid resource for `&self` during the + // lifetime of the `IoRequest`. + .map(|resource| unsafe { IoRequest::new(self.as_ref(), resource) }) + } } // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic -- cgit