Skip to content

Commit 885cba8

Browse files
senekorjannau
authored andcommitted
rust: device: Add child accessor and iterator
Allow Rust drivers to access children of a fwnode either by name or by iterating over all of them. In C, there is the function `fwnode_get_next_child_node` for iteration and the macro `fwnode_for_each_child_node` that helps with handling the pointers. Instead of a macro, a native iterator is used in Rust such that regular for-loops can be used. Tested-by: Dirk Behme <dirk.behme@de.bosch.com> Signed-off-by: Remo Senekowitsch <remo@buenzli.dev>
1 parent 1e5dfb5 commit 885cba8

1 file changed

Lines changed: 56 additions & 0 deletions

File tree

rust/kernel/device/property.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,62 @@ impl FwNode {
190190
name,
191191
}
192192
}
193+
194+
/// Returns first matching named child node handle.
195+
pub fn get_child_by_name(&self, name: &CStr) -> Option<ARef<Self>> {
196+
// SAFETY: `self` and `name` are valid by their type invariants.
197+
let child =
198+
unsafe { bindings::fwnode_get_named_child_node(self.as_raw(), name.as_char_ptr()) };
199+
if child.is_null() {
200+
return None;
201+
}
202+
// SAFETY:
203+
// - `fwnode_get_named_child_node` returns a pointer with its refcount
204+
// incremented.
205+
// - That increment is relinquished, i.e. the underlying object is not
206+
// used anymore except via the newly created `ARef`.
207+
Some(unsafe { Self::from_raw(child) })
208+
}
209+
210+
/// Returns an iterator over a node's children.
211+
pub fn children<'a>(&'a self) -> impl Iterator<Item = ARef<FwNode>> + 'a {
212+
let mut prev: Option<ARef<FwNode>> = None;
213+
214+
core::iter::from_fn(move || {
215+
let prev_ptr = match prev.take() {
216+
None => ptr::null_mut(),
217+
Some(prev) => {
218+
// We will pass `prev` to `fwnode_get_next_child_node`,
219+
// which decrements its refcount, so we use
220+
// `ARef::into_raw` to avoid decrementing the refcount
221+
// twice.
222+
let prev = ARef::into_raw(prev);
223+
prev.as_ptr().cast()
224+
}
225+
};
226+
// SAFETY:
227+
// - `self.as_raw()` is valid by its type invariant.
228+
// - `prev_ptr` may be null, which is allowed and corresponds to
229+
// getting the first child. Otherwise, `prev_ptr` is valid, as it
230+
// is the stored return value from the previous invocation.
231+
// - `prev_ptr` has its refount incremented.
232+
// - The increment of `prev_ptr` is relinquished, i.e. the
233+
// underlying object won't be used anymore.
234+
let next = unsafe { bindings::fwnode_get_next_child_node(self.as_raw(), prev_ptr) };
235+
if next.is_null() {
236+
return None;
237+
}
238+
// SAFETY:
239+
// - `next` is valid because `fwnode_get_next_child_node` returns a
240+
// pointer with its refcount incremented.
241+
// - That increment is relinquished, i.e. the underlying object
242+
// won't be used anymore, except via the newly created
243+
// `ARef<Self>`.
244+
let next = unsafe { FwNode::from_raw(next) };
245+
prev = Some(next.clone());
246+
Some(next)
247+
})
248+
}
193249
}
194250

195251
// SAFETY: Instances of `FwNode` are always reference-counted.

0 commit comments

Comments
 (0)