Skip to content

Commit 00df97d

Browse files
committed
Support finding nodes by name without address.
Many device tree nodes have names containing both a node-name and a unit-address component, like memory@40000000. It should be possible to find them by just the node-name.
1 parent 9d8fee9 commit 00df97d

5 files changed

Lines changed: 46 additions & 12 deletions

File tree

src/fdt/mod.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -403,10 +403,15 @@ impl<'a> Fdt<'a> {
403403
return Some(Ok(current_node));
404404
}
405405
for component in path.split('/').filter(|s| !s.is_empty()) {
406+
let include_address = component.contains('@');
406407
match current_node.children().find(|child| {
407-
child
408-
.as_ref()
409-
.is_ok_and(|c| c.name().is_ok_and(|n| n == component))
408+
child.as_ref().is_ok_and(|c| {
409+
if include_address {
410+
c.name().is_ok_and(|n| n == component)
411+
} else {
412+
c.name_without_address().is_ok_and(|n| n == component)
413+
}
414+
})
410415
}) {
411416
Some(Ok(node)) => current_node = node,
412417
Some(Err(e)) => return Some(Err(e)),

src/fdt/node.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ pub struct FdtNode<'a> {
2424
impl<'a> FdtNode<'a> {
2525
/// Returns the name of this node.
2626
///
27-
/// # Examples
28-
///
2927
/// # Errors
3028
///
3129
/// Returns an
@@ -49,6 +47,24 @@ impl<'a> FdtNode<'a> {
4947
self.fdt.string_at_offset(name_offset, None)
5048
}
5149

50+
/// Returns the name of this node without the unit address, if any.
51+
///
52+
/// # Errors
53+
///
54+
/// Returns an
55+
/// [`FdtErrorKind::InvalidOffset`](crate::error::FdtErrorKind::InvalidOffset)
56+
/// if the name offset is invalid or an
57+
/// [`FdtErrorKind::InvalidString`](crate::error::FdtErrorKind::InvalidString) if the string at the offset is not null-terminated
58+
/// or contains invalid UTF-8.
59+
pub fn name_without_address(&self) -> Result<&'a str, FdtError> {
60+
let name = self.name()?;
61+
if let Some((name, _)) = name.split_once('@') {
62+
Ok(name)
63+
} else {
64+
Ok(name)
65+
}
66+
}
67+
5268
/// Returns a property by its name.
5369
///
5470
/// # Performance
@@ -126,9 +142,14 @@ impl<'a> FdtNode<'a> {
126142
/// assert_eq!(child.name().unwrap(), "child1");
127143
/// ```
128144
pub fn child(&self, name: &str) -> Result<Option<FdtNode<'a>>, FdtError> {
145+
let include_address = name.contains('@');
129146
for child in self.children() {
130147
let child = child?;
131-
if child.name()? == name {
148+
if if include_address {
149+
child.name()? == name
150+
} else {
151+
child.name_without_address()? == name
152+
} {
132153
return Ok(Some(child));
133154
}
134155
}
@@ -146,7 +167,7 @@ impl<'a> FdtNode<'a> {
146167
/// let root = fdt.root().unwrap();
147168
/// let mut children = root.children();
148169
/// assert_eq!(children.next().unwrap().unwrap().name().unwrap(), "child1");
149-
/// assert_eq!(children.next().unwrap().unwrap().name().unwrap(), "child2");
170+
/// assert_eq!(children.next().unwrap().unwrap().name().unwrap(), "child2@42");
150171
/// assert!(children.next().is_none());
151172
/// ```
152173
pub fn children(&self) -> impl Iterator<Item = Result<FdtNode<'a>, FdtError>> + use<'a> {

tests/dtb/test_children.dtb

57 Bytes
Binary file not shown.

tests/dts/test_children.dts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
/dts-v1/;
22

33
/ {
4+
#address-cells = <0x01>;
5+
#size-cells = <0x00>;
6+
47
child1 {
58
prop1 = <0x12345678>;
69
};
710

8-
child2 {
9-
prop2 = "hello";
11+
child2@42 {
12+
reg = <0x00>;
1013
};
1114
};

tests/fdt.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ fn read_child_nodes() {
1717

1818
let child1 = children.next().unwrap().unwrap();
1919
assert_eq!(child1.name().unwrap(), "child1");
20+
assert_eq!(child1.name_without_address().unwrap(), "child1");
2021

21-
let child2 = children.next().unwrap().unwrap();
22-
assert_eq!(child2.name().unwrap(), "child2");
22+
let child3 = children.next().unwrap().unwrap();
23+
assert_eq!(child3.name().unwrap(), "child2@42");
24+
assert_eq!(child3.name_without_address().unwrap(), "child2");
2325

2426
assert!(children.next().is_none());
2527
}
@@ -86,7 +88,10 @@ fn get_child_by_name() {
8688
assert_eq!(child1.name().unwrap(), "child1");
8789

8890
let child2 = root.child("child2").unwrap().unwrap();
89-
assert_eq!(child2.name().unwrap(), "child2");
91+
assert_eq!(child2.name().unwrap(), "child2@42");
92+
93+
let child2_with_address = root.child("child2@42").unwrap().unwrap();
94+
assert_eq!(child2_with_address.name().unwrap(), "child2@42");
9095

9196
assert!(root.child("non-existent-child").unwrap().is_none());
9297
}

0 commit comments

Comments
 (0)