1
0

rust: device: Enable printing fwnode name and path

Add two new public methods `display_name` and `display_path` to
`FwNode`. They can be used by driver authors for logging purposes. In
addition, they will be used by core property abstractions for automatic
logging, for example when a driver attempts to read a required but
missing property.

Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
Signed-off-by: Remo Senekowitsch <remo@buenzli.dev>
Link: https://lore.kernel.org/r/20250611102908.212514-5-remo@buenzli.dev
[ Remove #[expect(dead_code)] from FwNode::from_raw(). - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
This commit is contained in:
Remo Senekowitsch
2025-06-11 12:29:03 +02:00
committed by Danilo Krummrich
parent d3393e8450
commit ecea245981

View File

@@ -38,7 +38,6 @@ impl FwNode {
/// - They relinquish that increment. That is, if there is only one
/// increment, callers must not use the underlying object anymore -- it is
/// only safe to do so via the newly created `ARef<FwNode>`.
#[expect(dead_code)]
unsafe fn from_raw(raw: *mut bindings::fwnode_handle) -> ARef<Self> {
// SAFETY: As per the safety requirements of this function:
// - `NonNull::new_unchecked`:
@@ -58,6 +57,32 @@ impl FwNode {
self.0.get()
}
/// Returns an object that implements [`Display`](core::fmt::Display) for
/// printing the name of a node.
///
/// This is an alternative to the default `Display` implementation, which
/// prints the full path.
pub fn display_name(&self) -> impl core::fmt::Display + '_ {
struct FwNodeDisplayName<'a>(&'a FwNode);
impl core::fmt::Display for FwNodeDisplayName<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
// SAFETY: `self` is valid by its type invariant.
let name = unsafe { bindings::fwnode_get_name(self.0.as_raw()) };
if name.is_null() {
return Ok(());
}
// SAFETY:
// - `fwnode_get_name` returns null or a valid C string.
// - `name` was checked to be non-null.
let name = unsafe { CStr::from_char_ptr(name) };
write!(f, "{name}")
}
}
FwNodeDisplayName(self)
}
/// Checks if property is present or not.
pub fn property_present(&self, name: &CStr) -> bool {
// SAFETY: By the invariant of `CStr`, `name` is null-terminated.
@@ -79,3 +104,53 @@ unsafe impl crate::types::AlwaysRefCounted for FwNode {
unsafe { bindings::fwnode_handle_put(obj.cast().as_ptr()) }
}
}
enum Node<'a> {
Borrowed(&'a FwNode),
Owned(ARef<FwNode>),
}
impl core::fmt::Display for FwNode {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
// The logic here is the same as the one in lib/vsprintf.c
// (fwnode_full_name_string).
// SAFETY: `self.as_raw()` is valid by its type invariant.
let num_parents = unsafe { bindings::fwnode_count_parents(self.as_raw()) };
for depth in (0..=num_parents).rev() {
let fwnode = if depth == 0 {
Node::Borrowed(self)
} else {
// SAFETY: `self.as_raw()` is valid.
let ptr = unsafe { bindings::fwnode_get_nth_parent(self.as_raw(), depth) };
// SAFETY:
// - The depth passed to `fwnode_get_nth_parent` is
// within the valid range, so the returned pointer is
// not null.
// - The reference count was incremented by
// `fwnode_get_nth_parent`.
// - That increment is relinquished to
// `FwNode::from_raw`.
Node::Owned(unsafe { FwNode::from_raw(ptr) })
};
// Take a reference to the owned or borrowed `FwNode`.
let fwnode: &FwNode = match &fwnode {
Node::Borrowed(f) => f,
Node::Owned(f) => f,
};
// SAFETY: `fwnode` is valid by its type invariant.
let prefix = unsafe { bindings::fwnode_get_name_prefix(fwnode.as_raw()) };
if !prefix.is_null() {
// SAFETY: `fwnode_get_name_prefix` returns null or a
// valid C string.
let prefix = unsafe { CStr::from_char_ptr(prefix) };
write!(f, "{prefix}")?;
}
write!(f, "{}", fwnode.display_name())?;
}
Ok(())
}
}