+ def GetFdt(self):
+ """Get the Fdt object for this node
+
+ Returns:
+ Fdt object
+ """
+ return self._fdt
+
+ def FindNode(self, name):
+ """Find a node given its name
+
+ Args:
+ name: Node name to look for
+ Returns:
+ Node object if found, else None
+ """
+ for subnode in self.subnodes:
+ if subnode.name == name:
+ return subnode
+ return None
+
+ 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.
+ """
+ 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 = fdt_obj.first_subnode(self.Offset(), QUIET_NOTFOUND)
+ while offset >= 0:
+ sep = '' if self.path[-1] == '/' else '/'
+ name = fdt_obj.get_name(offset)
+ path = self.path + sep + name
+ node = Node(self._fdt, self, offset, name, path)
+ self.subnodes.append(node)
+
+ node.Scan()
+ 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:
+ self._offset = my_offset
+ offset = fdt_obj.first_subnode(self._offset, QUIET_NOTFOUND)
+ for subnode in self.subnodes:
+ if subnode.name != fdt_obj.get_name(offset):
+ raise ValueError('Internal error, node name mismatch %s != %s' %
+ (subnode.name, fdt_obj.get_name(offset)))
+ subnode.Refresh(offset)
+ offset = fdt_obj.next_subnode(offset, QUIET_NOTFOUND)
+ if offset != -libfdt.FDT_ERR_NOTFOUND:
+ raise ValueError('Internal error, offset == %d' % offset)
+
+ poffset = fdt_obj.first_property_offset(self._offset, QUIET_NOTFOUND)
+ while poffset >= 0:
+ p = fdt_obj.get_property_by_offset(poffset)
+ prop = self.props.get(p.name)
+ if not prop:
+ raise ValueError("Internal error, property '%s' missing, "
+ 'offset %d' % (p.name, poffset))
+ prop.RefreshOffset(poffset)
+ poffset = fdt_obj.next_property_offset(poffset, QUIET_NOTFOUND)
+
+ 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(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 AddZeroProp(self, prop_name):
+ """Add a new property to the device tree with an integer value of 0.
+
+ Args:
+ prop_name: Name of property
+ """
+ self.props[prop_name] = Prop(self, None, prop_name,
+ tools.GetBytes(0, 4))
+
+ def AddEmptyProp(self, prop_name, len):
+ """Add a property with a fixed data size, for filling in later
+
+ The device tree is marked dirty so that the value will be written to
+ the blob on the next sync.
+
+ Args:
+ prop_name: Name of property
+ len: Length of data in property
+ """
+ value = tools.GetBytes(0, len)
+ self.props[prop_name] = Prop(self, None, prop_name, value)
+
+ def _CheckProp(self, prop_name):
+ """Check if a property is present
+
+ Args:
+ prop_name: Name of property
+
+ Returns:
+ self
+
+ Raises:
+ ValueError if the property is missing
+ """
+ if prop_name not in self.props:
+ raise ValueError("Fdt '%s', node '%s': Missing property '%s'" %
+ (self._fdt._fname, self.path, prop_name))
+ return self
+
+ def SetInt(self, prop_name, val):
+ """Update an integer property int the device tree.
+
+ This is not allowed to change the size of the FDT.
+
+ The device tree is marked dirty so that the value will be written to
+ the blob on the next sync.
+
+ Args:
+ prop_name: Name of property
+ val: Value to set
+ """
+ self._CheckProp(prop_name).props[prop_name].SetInt(val)
+
+ def SetData(self, prop_name, val):
+ """Set the data value of a property
+
+ The device tree is marked dirty so that the value will be written to
+ the blob on the next sync.
+
+ Args:
+ prop_name: Name of property to set
+ val: Data value to set
+ """
+ self._CheckProp(prop_name).props[prop_name].SetData(val)
+
+ def SetString(self, prop_name, val):
+ """Set the string value of a property
+
+ The device tree is marked dirty so that the value will be written to
+ the blob on the next sync.
+
+ Args:
+ prop_name: Name of property to set
+ val: String value to set (will be \0-terminated in DT)
+ """
+ if sys.version_info[0] >= 3: # pragma: no cover
+ val = bytes(val, 'utf-8')
+ self._CheckProp(prop_name).props[prop_name].SetData(val + b'\0')
+
+ def AddString(self, prop_name, val):
+ """Add a new string property to a node
+
+ The device tree is marked dirty so that the value will be written to
+ the blob on the next sync.
+
+ Args:
+ prop_name: Name of property to add
+ val: String value of property
+ """
+ if sys.version_info[0] >= 3: # pragma: no cover
+ val = bytes(val, 'utf-8')
+ self.props[prop_name] = Prop(self, None, prop_name, val + b'\0')
+
+ def AddSubnode(self, name):
+ """Add a new subnode to the node
+
+ Args:
+ name: name of node to add
+
+ Returns:
+ New subnode that was created
+ """
+ path = self.path + '/' + name
+ subnode = Node(self._fdt, self, None, name, path)
+ self.subnodes.append(subnode)
+ return subnode
+
+ def Sync(self, auto_resize=False):
+ """Sync node changes back to the device tree
+
+ This updates the device tree blob with any changes to this node and its
+ subnodes since the last sync.
+
+ Args:
+ auto_resize: Resize the device tree automatically if it does not
+ have enough space for the update
+
+ Raises:
+ FdtException if auto_resize is False and there is not enough space
+ """
+ if self._offset is None:
+ # The subnode doesn't exist yet, so add it
+ fdt_obj = self._fdt._fdt_obj
+ if auto_resize:
+ while True:
+ offset = fdt_obj.add_subnode(self.parent._offset, self.name,
+ (libfdt.NOSPACE,))
+ if offset != -libfdt.NOSPACE:
+ break
+ fdt_obj.resize(fdt_obj.totalsize() + 1024)
+ else:
+ offset = fdt_obj.add_subnode(self.parent._offset, self.name)
+ self._offset = offset
+
+ # Sync subnodes in reverse so that we don't disturb node offsets for
+ # nodes that are earlier in the DT. This avoids an O(n^2) rescan of
+ # node offsets.
+ for node in reversed(self.subnodes):
+ node.Sync(auto_resize)
+
+ # Sync properties now, whose offsets should not have been disturbed.
+ # We do this after subnodes, since this disturbs the offsets of these
+ # properties. Note that new properties will have an offset of None here,
+ # which Python 3 cannot sort against int. So use a large value instead
+ # to ensure that the new properties are added first.
+ prop_list = sorted(self.props.values(),
+ key=lambda prop: prop._offset or 1 << 31,
+ reverse=True)
+ for prop in prop_list:
+ prop.Sync(auto_resize)
+
+