#!/usr/bin/python
+# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2016 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
#
-# SPDX-License-Identifier: GPL-2.0+
-#
import struct
import sys
import fdt_util
import libfdt
+from libfdt import QUIET_NOTFOUND
# This deals with a device tree, presenting it as an assortment of Node and
# Prop objects, representing nodes and properties, respectively. This file
-# contains the base classes and defines the high-level API. See fdt_select.py
-# for how to create an Fdt object.
+# contains the base classes and defines the high-level API. You can use
+# FdtScan() as a convenience function to create and scan an Fdt.
# This implementation uses a libfdt Python library to access the device tree,
# so it is fairly efficient.
# A list of types we support
-(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL) = range(4)
+(TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL, TYPE_INT64) = range(5)
def CheckErr(errnum, msg):
if errnum:
else:
return TYPE_INT, val
+ @classmethod
def GetEmpty(self, type):
"""Get an empty / zero value of the given type
props: A dict of properties for this node, each a Prop object.
Keyed by property name
"""
- def __init__(self, fdt, offset, name, path):
+ def __init__(self, fdt, parent, offset, name, path):
self._fdt = fdt
+ self.parent = parent
self._offset = offset
self.name = name
self.path = path
This fills in the props and subnodes properties, recursively
searching into subnodes so that the entire tree is built.
"""
+ fdt_obj = self._fdt._fdt_obj
self.props = self._fdt.GetProps(self)
+ phandle = fdt_obj.get_phandle(self.Offset())
+ if phandle:
+ self._fdt.phandle_to_node[phandle] = self
- offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.Offset())
+ offset = fdt_obj.first_subnode(self.Offset(), QUIET_NOTFOUND)
while offset >= 0:
sep = '' if self.path[-1] == '/' else '/'
- name = self._fdt._fdt_obj.get_name(offset)
+ name = fdt_obj.get_name(offset)
path = self.path + sep + name
- node = Node(self._fdt, offset, name, path)
+ node = Node(self._fdt, self, offset, name, path)
self.subnodes.append(node)
node.Scan()
- offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
+ offset = fdt_obj.next_subnode(offset, QUIET_NOTFOUND)
def Refresh(self, my_offset):
"""Fix up the _offset for each node, recursively
Note: This does not take account of property offsets - these will not
be updated.
"""
+ fdt_obj = self._fdt._fdt_obj
if self._offset != my_offset:
- #print '%s: %d -> %d\n' % (self.path, self._offset, my_offset)
self._offset = my_offset
- offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self._offset)
+ offset = fdt_obj.first_subnode(self._offset, QUIET_NOTFOUND)
for subnode in self.subnodes:
subnode.Refresh(offset)
- offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
+ offset = fdt_obj.next_subnode(offset, QUIET_NOTFOUND)
def DeleteProp(self, prop_name):
"""Delete a property of a node
Raises:
ValueError if the property does not exist
"""
- CheckErr(libfdt.fdt_delprop(self._fdt.GetFdt(), self.Offset(), prop_name),
+ CheckErr(self._fdt._fdt_obj.delprop(self.Offset(), prop_name),
"Node '%s': delete property: '%s'" % (self.path, prop_name))
del self.props[prop_name]
self._fdt.Invalidate()
def __init__(self, fname):
self._fname = fname
self._cached_offsets = False
+ self.phandle_to_node = {}
if self._fname:
self._fname = fdt_util.EnsureCompiled(self._fname)
with open(self._fname) as fd:
- self._fdt = bytearray(fd.read())
- self._fdt_obj = libfdt.Fdt(self._fdt)
+ self._fdt_obj = libfdt.Fdt(fd.read())
def Scan(self, root='/'):
"""Scan a device tree, building up a tree of Node objects
TODO(sjg@chromium.org): Implement the 'root' parameter
"""
- self._root = self.Node(self, 0, '/', '/')
+ self._root = self.Node(self, None, 0, '/', '/')
self._root.Scan()
def GetRoot(self):
If the device tree has changed in memory, write it back to the file.
"""
with open(self._fname, 'wb') as fd:
- fd.write(self._fdt)
+ fd.write(self._fdt_obj.as_bytearray())
def Pack(self):
"""Pack the device tree down to its minimum size
When nodes and properties shrink or are deleted, wasted space can
build up in the device tree binary.
"""
- CheckErr(libfdt.fdt_pack(self._fdt), 'pack')
- fdt_len = libfdt.fdt_totalsize(self._fdt)
- del self._fdt[fdt_len:]
+ CheckErr(self._fdt_obj.pack(), 'pack')
+ self.Invalidate()
- def GetFdt(self):
+ def GetContents(self):
"""Get the contents of the FDT
Returns:
The FDT contents as a string of bytes
"""
- return self._fdt
+ return self._fdt_obj.as_bytearray()
- def CheckErr(errnum, msg):
+ def GetFdtObj(self):
+ """Get the contents of the FDT
+
+ Returns:
+ The FDT contents as a libfdt.Fdt object
+ """
+ return self._fdt_obj
+
+ def CheckErr(self, errnum, msg):
if errnum:
raise ValueError('Error %d: %s: %s' %
(errnum, libfdt.fdt_strerror(errnum), msg))
-
def GetProps(self, node):
"""Get all properties from a node.
ValueError: if the node does not exist.
"""
props_dict = {}
- poffset = libfdt.fdt_first_property_offset(self._fdt, node._offset)
+ poffset = self._fdt_obj.first_property_offset(node._offset,
+ QUIET_NOTFOUND)
while poffset >= 0:
p = self._fdt_obj.get_property_by_offset(poffset)
- prop = Prop(node, poffset, p.name, p.value)
+ prop = Prop(node, poffset, p.name, p)
props_dict[prop.name] = prop
- poffset = libfdt.fdt_next_property_offset(self._fdt, poffset)
+ poffset = self._fdt_obj.next_property_offset(poffset,
+ QUIET_NOTFOUND)
return props_dict
def Invalidate(self):
Returns:
Position of @offset within the device tree binary
"""
- return libfdt.fdt_off_dt_struct(self._fdt) + offset
+ return self._fdt_obj.off_dt_struct() + offset
@classmethod
- def Node(self, fdt, offset, name, path):
+ def Node(self, fdt, parent, offset, name, path):
"""Create a new node
This is used by Fdt.Scan() to create a new node using the correct
Args:
fdt: Fdt object
+ parent: Parent node, or None if this is the root node
offset: Offset of node
name: Node name
path: Full path to node
"""
- node = Node(fdt, offset, name, path)
+ node = Node(fdt, parent, offset, name, path)
return node
+
+def FdtScan(fname):
+ """Returns a new Fdt object from the implementation we are using"""
+ dtb = Fdt(fname)
+ dtb.Scan()
+ return dtb