1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! Some useful interfaces for device tree.

#![no_std]
use fdt_rs::{
    base::{DevTree, DevTreeNode, DevTreeProp},
    prelude::{FallibleIterator, PropReader},
};
use lazy_init::LazyInit;

/// The device Tree.
static TREE: LazyInit<DevTree> = LazyInit::new();

/// Init device tree from given address.
/// # Safety
///
/// Callers of this method the must guarantee the following:
///
/// - The passed address is 32-bit aligned.
pub unsafe fn init(dtb: *const u8) {
    TREE.init_by(DevTree::from_raw_pointer(dtb).unwrap());
}

/// A node on the device tree.
pub struct DeviceNode<'a>(DevTreeNode<'a, 'static>);

/// A prop of a node.
pub struct DeviceProp<'a>(DevTreeProp<'a, 'static>);

impl<'a> DeviceNode<'a> {
    /// Find a node's prop with given name(may not exist).
    pub fn find_prop(&'a self, name: &str) -> Option<DeviceProp<'a>> {
        self.0
            .props()
            .filter(|p| p.name().map(|s| s == name))
            .next()
            .unwrap()
            .map(DeviceProp)
    }

    /// Find a node's prop with given name(must exist).
    pub fn prop(&'a self, name: &str) -> DeviceProp<'a> {
        self.find_prop(name).unwrap()
    }
}

impl<'a> DeviceProp<'a> {
    /// Assume the prop is a u32 array. Get an element.
    pub fn u32(&self, index: usize) -> u32 {
        self.0.u32(index).unwrap()
    }

    /// Assume the prop is a u64 array. Get an element.
    pub fn u64(&self, index: usize) -> u64 {
        self.0.u64(index).unwrap()
    }

    /// Assume the prop is a str. Get the whole str.
    pub fn str(&self) -> &'static str {
        self.0.str().unwrap()
    }
}

/// Find the first node with given compatible(may not exist).
pub fn compatible_node(compatible: &str) -> Option<DeviceNode> {
    TREE.compatible_nodes(compatible)
        .next()
        .unwrap()
        .map(DeviceNode)
}

/// Find the first node with given name(may not exist).
pub fn get_node(name: &str) -> Option<DeviceNode> {
    TREE.nodes()
        .filter(|n| n.name().map(|s| s == name))
        .next()
        .unwrap()
        .map(DeviceNode)
}

/// Do something for all devices with given type.
pub fn devices<F>(device_type: &str, f: F)
where
    F: Fn(DeviceNode),
{
    TREE.nodes()
        .filter_map(|n| {
            let n = DeviceNode(n);
            Ok(
                if n.find_prop("device_type").map(|p| p.str()) == Some(device_type) {
                    Some(n)
                } else {
                    None
                },
            )
        })
        .for_each(|n| {
            f(n);
            Ok(())
        })
        .unwrap();
}

/// Do something for all nodes with given compatible.
pub fn compatible_nodes<F>(compatible: &str, mut f: F)
where
    F: FnMut(DeviceNode),
{
    TREE.compatible_nodes(compatible)
        .for_each(|n| {
            f(DeviceNode(n));
            Ok(())
        })
        .unwrap();
}