xref: /OK3568_Linux_fs/u-boot/tools/dtoc/fdt.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#!/usr/bin/python
2*4882a593Smuzhiyun#
3*4882a593Smuzhiyun# Copyright (C) 2016 Google, Inc
4*4882a593Smuzhiyun# Written by Simon Glass <sjg@chromium.org>
5*4882a593Smuzhiyun#
6*4882a593Smuzhiyun# SPDX-License-Identifier:      GPL-2.0+
7*4882a593Smuzhiyun#
8*4882a593Smuzhiyun
9*4882a593Smuzhiyunimport struct
10*4882a593Smuzhiyunimport sys
11*4882a593Smuzhiyun
12*4882a593Smuzhiyunimport fdt_util
13*4882a593Smuzhiyunimport libfdt
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun# This deals with a device tree, presenting it as an assortment of Node and
16*4882a593Smuzhiyun# Prop objects, representing nodes and properties, respectively. This file
17*4882a593Smuzhiyun# contains the base classes and defines the high-level API. You can use
18*4882a593Smuzhiyun# FdtScan() as a convenience function to create and scan an Fdt.
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun# This implementation uses a libfdt Python library to access the device tree,
21*4882a593Smuzhiyun# so it is fairly efficient.
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun# A list of types we support
24*4882a593Smuzhiyun(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL, TYPE_INT64) = range(5)
25*4882a593Smuzhiyun
26*4882a593Smuzhiyundef CheckErr(errnum, msg):
27*4882a593Smuzhiyun    if errnum:
28*4882a593Smuzhiyun        raise ValueError('Error %d: %s: %s' %
29*4882a593Smuzhiyun            (errnum, libfdt.fdt_strerror(errnum), msg))
30*4882a593Smuzhiyun
31*4882a593Smuzhiyunclass Prop:
32*4882a593Smuzhiyun    """A device tree property
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun    Properties:
35*4882a593Smuzhiyun        name: Property name (as per the device tree)
36*4882a593Smuzhiyun        value: Property value as a string of bytes, or a list of strings of
37*4882a593Smuzhiyun            bytes
38*4882a593Smuzhiyun        type: Value type
39*4882a593Smuzhiyun    """
40*4882a593Smuzhiyun    def __init__(self, node, offset, name, bytes):
41*4882a593Smuzhiyun        self._node = node
42*4882a593Smuzhiyun        self._offset = offset
43*4882a593Smuzhiyun        self.name = name
44*4882a593Smuzhiyun        self.value = None
45*4882a593Smuzhiyun        self.bytes = str(bytes)
46*4882a593Smuzhiyun        if not bytes:
47*4882a593Smuzhiyun            self.type = TYPE_BOOL
48*4882a593Smuzhiyun            self.value = True
49*4882a593Smuzhiyun            return
50*4882a593Smuzhiyun        self.type, self.value = self.BytesToValue(bytes)
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun    def GetPhandle(self):
53*4882a593Smuzhiyun        """Get a (single) phandle value from a property
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun        Gets the phandle valuie from a property and returns it as an integer
56*4882a593Smuzhiyun        """
57*4882a593Smuzhiyun        return fdt_util.fdt32_to_cpu(self.value[:4])
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun    def Widen(self, newprop):
60*4882a593Smuzhiyun        """Figure out which property type is more general
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun        Given a current property and a new property, this function returns the
63*4882a593Smuzhiyun        one that is less specific as to type. The less specific property will
64*4882a593Smuzhiyun        be ble to represent the data in the more specific property. This is
65*4882a593Smuzhiyun        used for things like:
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun            node1 {
68*4882a593Smuzhiyun                compatible = "fred";
69*4882a593Smuzhiyun                value = <1>;
70*4882a593Smuzhiyun            };
71*4882a593Smuzhiyun            node1 {
72*4882a593Smuzhiyun                compatible = "fred";
73*4882a593Smuzhiyun                value = <1 2>;
74*4882a593Smuzhiyun            };
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun        He we want to use an int array for 'value'. The first property
77*4882a593Smuzhiyun        suggests that a single int is enough, but the second one shows that
78*4882a593Smuzhiyun        it is not. Calling this function with these two propertes would
79*4882a593Smuzhiyun        update the current property to be like the second, since it is less
80*4882a593Smuzhiyun        specific.
81*4882a593Smuzhiyun        """
82*4882a593Smuzhiyun        if newprop.type < self.type:
83*4882a593Smuzhiyun            self.type = newprop.type
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun        if type(newprop.value) == list and type(self.value) != list:
86*4882a593Smuzhiyun            self.value = [self.value]
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun        if type(self.value) == list and len(newprop.value) > len(self.value):
89*4882a593Smuzhiyun            val = self.GetEmpty(self.type)
90*4882a593Smuzhiyun            while len(self.value) < len(newprop.value):
91*4882a593Smuzhiyun                self.value.append(val)
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun    def BytesToValue(self, bytes):
94*4882a593Smuzhiyun        """Converts a string of bytes into a type and value
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun        Args:
97*4882a593Smuzhiyun            A string containing bytes
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun        Return:
100*4882a593Smuzhiyun            A tuple:
101*4882a593Smuzhiyun                Type of data
102*4882a593Smuzhiyun                Data, either a single element or a list of elements. Each element
103*4882a593Smuzhiyun                is one of:
104*4882a593Smuzhiyun                    TYPE_STRING: string value from the property
105*4882a593Smuzhiyun                    TYPE_INT: a byte-swapped integer stored as a 4-byte string
106*4882a593Smuzhiyun                    TYPE_BYTE: a byte stored as a single-byte string
107*4882a593Smuzhiyun        """
108*4882a593Smuzhiyun        bytes = str(bytes)
109*4882a593Smuzhiyun        size = len(bytes)
110*4882a593Smuzhiyun        strings = bytes.split('\0')
111*4882a593Smuzhiyun        is_string = True
112*4882a593Smuzhiyun        count = len(strings) - 1
113*4882a593Smuzhiyun        if count > 0 and not strings[-1]:
114*4882a593Smuzhiyun            for string in strings[:-1]:
115*4882a593Smuzhiyun                if not string:
116*4882a593Smuzhiyun                    is_string = False
117*4882a593Smuzhiyun                    break
118*4882a593Smuzhiyun                for ch in string:
119*4882a593Smuzhiyun                    if ch < ' ' or ch > '~':
120*4882a593Smuzhiyun                        is_string = False
121*4882a593Smuzhiyun                        break
122*4882a593Smuzhiyun        else:
123*4882a593Smuzhiyun            is_string = False
124*4882a593Smuzhiyun        if is_string:
125*4882a593Smuzhiyun            if count == 1:
126*4882a593Smuzhiyun                return TYPE_STRING, strings[0]
127*4882a593Smuzhiyun            else:
128*4882a593Smuzhiyun                return TYPE_STRING, strings[:-1]
129*4882a593Smuzhiyun        if size % 4:
130*4882a593Smuzhiyun            if size == 1:
131*4882a593Smuzhiyun                return TYPE_BYTE, bytes[0]
132*4882a593Smuzhiyun            else:
133*4882a593Smuzhiyun                return TYPE_BYTE, list(bytes)
134*4882a593Smuzhiyun        val = []
135*4882a593Smuzhiyun        for i in range(0, size, 4):
136*4882a593Smuzhiyun            val.append(bytes[i:i + 4])
137*4882a593Smuzhiyun        if size == 4:
138*4882a593Smuzhiyun            return TYPE_INT, val[0]
139*4882a593Smuzhiyun        else:
140*4882a593Smuzhiyun            return TYPE_INT, val
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun    def GetEmpty(self, type):
143*4882a593Smuzhiyun        """Get an empty / zero value of the given type
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun        Returns:
146*4882a593Smuzhiyun            A single value of the given type
147*4882a593Smuzhiyun        """
148*4882a593Smuzhiyun        if type == TYPE_BYTE:
149*4882a593Smuzhiyun            return chr(0)
150*4882a593Smuzhiyun        elif type == TYPE_INT:
151*4882a593Smuzhiyun            return struct.pack('<I', 0);
152*4882a593Smuzhiyun        elif type == TYPE_STRING:
153*4882a593Smuzhiyun            return ''
154*4882a593Smuzhiyun        else:
155*4882a593Smuzhiyun            return True
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun    def GetOffset(self):
158*4882a593Smuzhiyun        """Get the offset of a property
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun        Returns:
161*4882a593Smuzhiyun            The offset of the property (struct fdt_property) within the file
162*4882a593Smuzhiyun        """
163*4882a593Smuzhiyun        return self._node._fdt.GetStructOffset(self._offset)
164*4882a593Smuzhiyun
165*4882a593Smuzhiyunclass Node:
166*4882a593Smuzhiyun    """A device tree node
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun    Properties:
169*4882a593Smuzhiyun        offset: Integer offset in the device tree
170*4882a593Smuzhiyun        name: Device tree node tname
171*4882a593Smuzhiyun        path: Full path to node, along with the node name itself
172*4882a593Smuzhiyun        _fdt: Device tree object
173*4882a593Smuzhiyun        subnodes: A list of subnodes for this node, each a Node object
174*4882a593Smuzhiyun        props: A dict of properties for this node, each a Prop object.
175*4882a593Smuzhiyun            Keyed by property name
176*4882a593Smuzhiyun    """
177*4882a593Smuzhiyun    def __init__(self, fdt, parent, offset, name, path):
178*4882a593Smuzhiyun        self._fdt = fdt
179*4882a593Smuzhiyun        self.parent = parent
180*4882a593Smuzhiyun        self._offset = offset
181*4882a593Smuzhiyun        self.name = name
182*4882a593Smuzhiyun        self.path = path
183*4882a593Smuzhiyun        self.subnodes = []
184*4882a593Smuzhiyun        self.props = {}
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun    def _FindNode(self, name):
187*4882a593Smuzhiyun        """Find a node given its name
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun        Args:
190*4882a593Smuzhiyun            name: Node name to look for
191*4882a593Smuzhiyun        Returns:
192*4882a593Smuzhiyun            Node object if found, else None
193*4882a593Smuzhiyun        """
194*4882a593Smuzhiyun        for subnode in self.subnodes:
195*4882a593Smuzhiyun            if subnode.name == name:
196*4882a593Smuzhiyun                return subnode
197*4882a593Smuzhiyun        return None
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun    def Offset(self):
200*4882a593Smuzhiyun        """Returns the offset of a node, after checking the cache
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun        This should be used instead of self._offset directly, to ensure that
203*4882a593Smuzhiyun        the cache does not contain invalid offsets.
204*4882a593Smuzhiyun        """
205*4882a593Smuzhiyun        self._fdt.CheckCache()
206*4882a593Smuzhiyun        return self._offset
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun    def Scan(self):
209*4882a593Smuzhiyun        """Scan a node's properties and subnodes
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun        This fills in the props and subnodes properties, recursively
212*4882a593Smuzhiyun        searching into subnodes so that the entire tree is built.
213*4882a593Smuzhiyun        """
214*4882a593Smuzhiyun        self.props = self._fdt.GetProps(self)
215*4882a593Smuzhiyun        phandle = self.props.get('phandle')
216*4882a593Smuzhiyun        if phandle:
217*4882a593Smuzhiyun            val = fdt_util.fdt32_to_cpu(phandle.value)
218*4882a593Smuzhiyun            self._fdt.phandle_to_node[val] = self
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun        offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.Offset())
221*4882a593Smuzhiyun        while offset >= 0:
222*4882a593Smuzhiyun            sep = '' if self.path[-1] == '/' else '/'
223*4882a593Smuzhiyun            name = self._fdt._fdt_obj.get_name(offset)
224*4882a593Smuzhiyun            path = self.path + sep + name
225*4882a593Smuzhiyun            node = Node(self._fdt, self, offset, name, path)
226*4882a593Smuzhiyun            self.subnodes.append(node)
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun            node.Scan()
229*4882a593Smuzhiyun            offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun    def Refresh(self, my_offset):
232*4882a593Smuzhiyun        """Fix up the _offset for each node, recursively
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun        Note: This does not take account of property offsets - these will not
235*4882a593Smuzhiyun        be updated.
236*4882a593Smuzhiyun        """
237*4882a593Smuzhiyun        if self._offset != my_offset:
238*4882a593Smuzhiyun            #print '%s: %d -> %d\n' % (self.path, self._offset, my_offset)
239*4882a593Smuzhiyun            self._offset = my_offset
240*4882a593Smuzhiyun        offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self._offset)
241*4882a593Smuzhiyun        for subnode in self.subnodes:
242*4882a593Smuzhiyun            subnode.Refresh(offset)
243*4882a593Smuzhiyun            offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun    def DeleteProp(self, prop_name):
246*4882a593Smuzhiyun        """Delete a property of a node
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun        The property is deleted and the offset cache is invalidated.
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun        Args:
251*4882a593Smuzhiyun            prop_name: Name of the property to delete
252*4882a593Smuzhiyun        Raises:
253*4882a593Smuzhiyun            ValueError if the property does not exist
254*4882a593Smuzhiyun        """
255*4882a593Smuzhiyun        CheckErr(libfdt.fdt_delprop(self._fdt.GetFdt(), self.Offset(), prop_name),
256*4882a593Smuzhiyun                 "Node '%s': delete property: '%s'" % (self.path, prop_name))
257*4882a593Smuzhiyun        del self.props[prop_name]
258*4882a593Smuzhiyun        self._fdt.Invalidate()
259*4882a593Smuzhiyun
260*4882a593Smuzhiyunclass Fdt:
261*4882a593Smuzhiyun    """Provides simple access to a flat device tree blob using libfdts.
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun    Properties:
264*4882a593Smuzhiyun      fname: Filename of fdt
265*4882a593Smuzhiyun      _root: Root of device tree (a Node object)
266*4882a593Smuzhiyun    """
267*4882a593Smuzhiyun    def __init__(self, fname):
268*4882a593Smuzhiyun        self._fname = fname
269*4882a593Smuzhiyun        self._cached_offsets = False
270*4882a593Smuzhiyun        self.phandle_to_node = {}
271*4882a593Smuzhiyun        if self._fname:
272*4882a593Smuzhiyun            self._fname = fdt_util.EnsureCompiled(self._fname)
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun            with open(self._fname) as fd:
275*4882a593Smuzhiyun                self._fdt = bytearray(fd.read())
276*4882a593Smuzhiyun                self._fdt_obj = libfdt.Fdt(self._fdt)
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun    def Scan(self, root='/'):
279*4882a593Smuzhiyun        """Scan a device tree, building up a tree of Node objects
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun        This fills in the self._root property
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun        Args:
284*4882a593Smuzhiyun            root: Ignored
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun        TODO(sjg@chromium.org): Implement the 'root' parameter
287*4882a593Smuzhiyun        """
288*4882a593Smuzhiyun        self._root = self.Node(self, None, 0, '/', '/')
289*4882a593Smuzhiyun        self._root.Scan()
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun    def GetRoot(self):
292*4882a593Smuzhiyun        """Get the root Node of the device tree
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun        Returns:
295*4882a593Smuzhiyun            The root Node object
296*4882a593Smuzhiyun        """
297*4882a593Smuzhiyun        return self._root
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun    def GetNode(self, path):
300*4882a593Smuzhiyun        """Look up a node from its path
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun        Args:
303*4882a593Smuzhiyun            path: Path to look up, e.g. '/microcode/update@0'
304*4882a593Smuzhiyun        Returns:
305*4882a593Smuzhiyun            Node object, or None if not found
306*4882a593Smuzhiyun        """
307*4882a593Smuzhiyun        node = self._root
308*4882a593Smuzhiyun        for part in path.split('/')[1:]:
309*4882a593Smuzhiyun            node = node._FindNode(part)
310*4882a593Smuzhiyun            if not node:
311*4882a593Smuzhiyun                return None
312*4882a593Smuzhiyun        return node
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun    def Flush(self):
315*4882a593Smuzhiyun        """Flush device tree changes back to the file
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun        If the device tree has changed in memory, write it back to the file.
318*4882a593Smuzhiyun        """
319*4882a593Smuzhiyun        with open(self._fname, 'wb') as fd:
320*4882a593Smuzhiyun            fd.write(self._fdt)
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun    def Pack(self):
323*4882a593Smuzhiyun        """Pack the device tree down to its minimum size
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun        When nodes and properties shrink or are deleted, wasted space can
326*4882a593Smuzhiyun        build up in the device tree binary.
327*4882a593Smuzhiyun        """
328*4882a593Smuzhiyun        CheckErr(libfdt.fdt_pack(self._fdt), 'pack')
329*4882a593Smuzhiyun        fdt_len = libfdt.fdt_totalsize(self._fdt)
330*4882a593Smuzhiyun        del self._fdt[fdt_len:]
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun    def GetFdt(self):
333*4882a593Smuzhiyun        """Get the contents of the FDT
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun        Returns:
336*4882a593Smuzhiyun            The FDT contents as a string of bytes
337*4882a593Smuzhiyun        """
338*4882a593Smuzhiyun        return self._fdt
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun    def CheckErr(errnum, msg):
341*4882a593Smuzhiyun        if errnum:
342*4882a593Smuzhiyun            raise ValueError('Error %d: %s: %s' %
343*4882a593Smuzhiyun                (errnum, libfdt.fdt_strerror(errnum), msg))
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun    def GetProps(self, node):
347*4882a593Smuzhiyun        """Get all properties from a node.
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun        Args:
350*4882a593Smuzhiyun            node: Full path to node name to look in.
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun        Returns:
353*4882a593Smuzhiyun            A dictionary containing all the properties, indexed by node name.
354*4882a593Smuzhiyun            The entries are Prop objects.
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun        Raises:
357*4882a593Smuzhiyun            ValueError: if the node does not exist.
358*4882a593Smuzhiyun        """
359*4882a593Smuzhiyun        props_dict = {}
360*4882a593Smuzhiyun        poffset = libfdt.fdt_first_property_offset(self._fdt, node._offset)
361*4882a593Smuzhiyun        while poffset >= 0:
362*4882a593Smuzhiyun            p = self._fdt_obj.get_property_by_offset(poffset)
363*4882a593Smuzhiyun            prop = Prop(node, poffset, p.name, p.value)
364*4882a593Smuzhiyun            props_dict[prop.name] = prop
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun            poffset = libfdt.fdt_next_property_offset(self._fdt, poffset)
367*4882a593Smuzhiyun        return props_dict
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun    def Invalidate(self):
370*4882a593Smuzhiyun        """Mark our offset cache as invalid"""
371*4882a593Smuzhiyun        self._cached_offsets = False
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun    def CheckCache(self):
374*4882a593Smuzhiyun        """Refresh the offset cache if needed"""
375*4882a593Smuzhiyun        if self._cached_offsets:
376*4882a593Smuzhiyun            return
377*4882a593Smuzhiyun        self.Refresh()
378*4882a593Smuzhiyun        self._cached_offsets = True
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun    def Refresh(self):
381*4882a593Smuzhiyun        """Refresh the offset cache"""
382*4882a593Smuzhiyun        self._root.Refresh(0)
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun    def GetStructOffset(self, offset):
385*4882a593Smuzhiyun        """Get the file offset of a given struct offset
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun        Args:
388*4882a593Smuzhiyun            offset: Offset within the 'struct' region of the device tree
389*4882a593Smuzhiyun        Returns:
390*4882a593Smuzhiyun            Position of @offset within the device tree binary
391*4882a593Smuzhiyun        """
392*4882a593Smuzhiyun        return libfdt.fdt_off_dt_struct(self._fdt) + offset
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun    @classmethod
395*4882a593Smuzhiyun    def Node(self, fdt, parent, offset, name, path):
396*4882a593Smuzhiyun        """Create a new node
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun        This is used by Fdt.Scan() to create a new node using the correct
399*4882a593Smuzhiyun        class.
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun        Args:
402*4882a593Smuzhiyun            fdt: Fdt object
403*4882a593Smuzhiyun            parent: Parent node, or None if this is the root node
404*4882a593Smuzhiyun            offset: Offset of node
405*4882a593Smuzhiyun            name: Node name
406*4882a593Smuzhiyun            path: Full path to node
407*4882a593Smuzhiyun        """
408*4882a593Smuzhiyun        node = Node(fdt, parent, offset, name, path)
409*4882a593Smuzhiyun        return node
410*4882a593Smuzhiyun
411*4882a593Smuzhiyundef FdtScan(fname):
412*4882a593Smuzhiyun    """Returns a new Fdt object from the implementation we are using"""
413*4882a593Smuzhiyun    dtb = Fdt(fname)
414*4882a593Smuzhiyun    dtb.Scan()
415*4882a593Smuzhiyun    return dtb
416