# This implementation uses a libfdt Python library to access the device tree,
# so it is fairly efficient.
+def CheckErr(errnum, msg):
+ if errnum:
+ raise ValueError('Error %d: %s: %s' %
+ (errnum, libfdt.fdt_strerror(errnum), msg))
+
class Prop(PropBase):
"""A device tree property
PropBase.__init__(self, node, offset, name)
self.bytes = bytes
if not bytes:
- self.type = fdt_util.TYPE_BOOL
+ self.type = fdt.TYPE_BOOL
self.value = True
return
- self.type, self.value = fdt_util.BytesToValue(bytes)
+ self.type, self.value = self.BytesToValue(bytes)
- def GetPhandle(self):
- """Get a (single) phandle value from a property
+ def GetOffset(self):
+ """Get the offset of a property
- Gets the phandle valuie from a property and returns it as an integer
- """
- return fdt_util.fdt32_to_cpu(self.value[:4])
-
- def Widen(self, newprop):
- """Figure out which property type is more general
-
- Given a current property and a new property, this function returns the
- one that is less specific as to type. The less specific property will
- be ble to represent the data in the more specific property. This is
- used for things like:
-
- node1 {
- compatible = "fred";
- value = <1>;
- };
- node1 {
- compatible = "fred";
- value = <1 2>;
- };
-
- He we want to use an int array for 'value'. The first property
- suggests that a single int is enough, but the second one shows that
- it is not. Calling this function with these two propertes would
- update the current property to be like the second, since it is less
- specific.
+ Returns:
+ The offset of the property (struct fdt_property) within the file
"""
- if newprop.type < self.type:
- self.type = newprop.type
-
- if type(newprop.value) == list and type(self.value) != list:
- self.value = [self.value]
-
- if type(self.value) == list and len(newprop.value) > len(self.value):
- val = fdt_util.GetEmpty(self.type)
- while len(self.value) < len(newprop.value):
- self.value.append(val)
-
+ return self._node._fdt.GetStructOffset(self._offset)
class Node(NodeBase):
"""A device tree node
def __init__(self, fdt, offset, name, path):
NodeBase.__init__(self, fdt, offset, name, path)
+ def Offset(self):
+ """Returns the offset of a node, after checking the cache
+
+ This should be used instead of self._offset directly, to ensure that
+ the cache does not contain invalid offsets.
+ """
+ self._fdt.CheckCache()
+ return self._offset
+
def Scan(self):
"""Scan a node's properties and subnodes
This fills in the props and subnodes properties, recursively
searching into subnodes so that the entire tree is built.
"""
- self.props = self._fdt.GetProps(self.path)
+ self.props = self._fdt.GetProps(self)
- offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self._offset)
+ offset = libfdt.fdt_first_subnode(self._fdt.GetFdt(), self.Offset())
while offset >= 0:
sep = '' if self.path[-1] == '/' else '/'
name = libfdt.Name(self._fdt.GetFdt(), offset)
node.Scan()
offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
+ 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.
+ """
+ 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)
+ for subnode in self.subnodes:
+ subnode.Refresh(offset)
+ offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset)
+
+ def DeleteProp(self, prop_name):
+ """Delete a property of a node
+
+ The property is deleted and the offset cache is invalidated.
+
+ Args:
+ prop_name: Name of the property to delete
+ Raises:
+ ValueError if the property does not exist
+ """
+ CheckErr(libfdt.fdt_delprop(self._fdt.GetFdt(), self.Offset(), prop_name),
+ "Node '%s': delete property: '%s'" % (self.path, prop_name))
+ del self.props[prop_name]
+ self._fdt.Invalidate()
class FdtNormal(Fdt):
"""Provides simple access to a flat device tree blob using libfdt.
"""
def __init__(self, fname):
Fdt.__init__(self, fname)
- with open(self._fname) as fd:
- self._fdt = fd.read()
+ self._cached_offsets = False
+ if self._fname:
+ self._fname = fdt_util.EnsureCompiled(self._fname)
+
+ with open(self._fname) as fd:
+ self._fdt = bytearray(fd.read())
def GetFdt(self):
"""Get the contents of the FDT
"""
return self._fdt
- def Scan(self):
- """Scan a device tree, building up a tree of Node objects
+ def Flush(self):
+ """Flush device tree changes back to the file"""
+ with open(self._fname, 'wb') as fd:
+ fd.write(self._fdt)
- This fills in the self._root property
- """
- self._root = Node(self, 0, '/', '/')
- self._root.Scan()
-
- def GetRoot(self):
- """Get the root Node of the device tree
-
- Returns:
- The root Node object
- """
- return self._root
+ def Pack(self):
+ """Pack the device tree down to its minimum size"""
+ CheckErr(libfdt.fdt_pack(self._fdt), 'pack')
+ fdt_len = libfdt.fdt_totalsize(self._fdt)
+ del self._fdt[fdt_len:]
def GetProps(self, node):
"""Get all properties from a node.
Raises:
ValueError: if the node does not exist.
"""
- offset = libfdt.fdt_path_offset(self._fdt, node)
- if offset < 0:
- libfdt.Raise(offset)
props_dict = {}
- poffset = libfdt.fdt_first_property_offset(self._fdt, offset)
+ poffset = libfdt.fdt_first_property_offset(self._fdt, node._offset)
while poffset >= 0:
dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset)
prop = Prop(node, poffset, libfdt.String(self._fdt, dprop.nameoff),
poffset = libfdt.fdt_next_property_offset(self._fdt, poffset)
return props_dict
+ def Invalidate(self):
+ """Mark our offset cache as invalid"""
+ self._cached_offsets = False
+
+ def CheckCache(self):
+ """Refresh the offset cache if needed"""
+ if self._cached_offsets:
+ return
+ self.Refresh()
+ self._cached_offsets = True
+
+ def Refresh(self):
+ """Refresh the offset cache"""
+ self._root.Refresh(0)
+
+ def GetStructOffset(self, offset):
+ """Get the file offset of a given struct offset
+
+ Args:
+ offset: Offset within the 'struct' region of the device tree
+ Returns:
+ Position of @offset within the device tree binary
+ """
+ return libfdt.fdt_off_dt_struct(self._fdt) + offset
+
@classmethod
def Node(self, fdt, offset, name, path):
"""Create a new node