Skip to content

Commit 9d199a7

Browse files
senekorjannau
authored andcommitted
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>
1 parent 8acbde0 commit 9d199a7

1 file changed

Lines changed: 76 additions & 0 deletions

File tree

rust/kernel/device/property.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,32 @@ impl FwNode {
5757
self.0.get()
5858
}
5959

60+
/// Returns an object that implements [`Display`](core::fmt::Display) for
61+
/// printing the name of a node.
62+
///
63+
/// This is an alternative to the default `Display` implementation, which
64+
/// prints the full path.
65+
pub fn display_name(&self) -> impl core::fmt::Display + '_ {
66+
struct FwNodeDisplayName<'a>(&'a FwNode);
67+
68+
impl core::fmt::Display for FwNodeDisplayName<'_> {
69+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
70+
// SAFETY: `self` is valid by its type invariant.
71+
let name = unsafe { bindings::fwnode_get_name(self.0.as_raw()) };
72+
if name.is_null() {
73+
return Ok(());
74+
}
75+
// SAFETY:
76+
// - `fwnode_get_name` returns null or a valid C string.
77+
// - `name` was checked to be non-null.
78+
let name = unsafe { CStr::from_char_ptr(name) };
79+
write!(f, "{name}")
80+
}
81+
}
82+
83+
FwNodeDisplayName(self)
84+
}
85+
6086
/// Checks if property is present or not.
6187
pub fn property_present(&self, name: &CStr) -> bool {
6288
// SAFETY: By the invariant of `CStr`, `name` is null-terminated.
@@ -78,3 +104,53 @@ unsafe impl crate::types::AlwaysRefCounted for FwNode {
78104
unsafe { bindings::fwnode_handle_put(obj.cast().as_ptr()) }
79105
}
80106
}
107+
108+
enum Node<'a> {
109+
Borrowed(&'a FwNode),
110+
Owned(ARef<FwNode>),
111+
}
112+
113+
impl core::fmt::Display for FwNode {
114+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115+
// The logic here is the same as the one in lib/vsprintf.c
116+
// (fwnode_full_name_string).
117+
118+
// SAFETY: `self.as_raw()` is valid by its type invariant.
119+
let num_parents = unsafe { bindings::fwnode_count_parents(self.as_raw()) };
120+
121+
for depth in (0..=num_parents).rev() {
122+
let fwnode = if depth == 0 {
123+
Node::Borrowed(self)
124+
} else {
125+
// SAFETY: `self.as_raw()` is valid.
126+
let ptr = unsafe { bindings::fwnode_get_nth_parent(self.as_raw(), depth) };
127+
// SAFETY:
128+
// - The depth passed to `fwnode_get_nth_parent` is
129+
// within the valid range, so the returned pointer is
130+
// not null.
131+
// - The reference count was incremented by
132+
// `fwnode_get_nth_parent`.
133+
// - That increment is relinquished to
134+
// `FwNode::from_raw`.
135+
Node::Owned(unsafe { FwNode::from_raw(ptr) })
136+
};
137+
// Take a reference to the owned or borrowed `FwNode`.
138+
let fwnode: &FwNode = match &fwnode {
139+
Node::Borrowed(f) => f,
140+
Node::Owned(f) => f,
141+
};
142+
143+
// SAFETY: `fwnode` is valid by its type invariant.
144+
let prefix = unsafe { bindings::fwnode_get_name_prefix(fwnode.as_raw()) };
145+
if !prefix.is_null() {
146+
// SAFETY: `fwnode_get_name_prefix` returns null or a
147+
// valid C string.
148+
let prefix = unsafe { CStr::from_char_ptr(prefix) };
149+
write!(f, "{prefix}")?;
150+
}
151+
write!(f, "{}", fwnode.display_name())?;
152+
}
153+
154+
Ok(())
155+
}
156+
}

0 commit comments

Comments
 (0)