From patchwork Tue Jul 26 00:59:04 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 652514 X-Patchwork-Delegate: sjg@chromium.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 3rz0F51TSFz9s4q for ; Tue, 26 Jul 2016 11:01:29 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.b=ds1gF2ib; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 8352BA78A9; Tue, 26 Jul 2016 03:01:01 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id O6QZHRBlcwBr; Tue, 26 Jul 2016 03:01:01 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 8459FA7879; Tue, 26 Jul 2016 03:00:28 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id A59A7A7853 for ; Tue, 26 Jul 2016 03:00:14 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id uRLOcQfYo_4Q for ; Tue, 26 Jul 2016 03:00:14 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-it0-f42.google.com (mail-it0-f42.google.com [209.85.214.42]) by theia.denx.de (Postfix) with ESMTPS id 55C90A786D for ; Tue, 26 Jul 2016 03:00:08 +0200 (CEST) Received: by mail-it0-f42.google.com with SMTP id u186so99391452ita.0 for ; Mon, 25 Jul 2016 18:00:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=6QzV9xxce3nac1ij0srsLCFsMzFRkwGFbCVm8IDEXR8=; b=ds1gF2ibNdselpFXX/5D6uLmnlElfsEQYTxcl1f284tWYjB6Ei60X489jFfu3xWuCK omEtnSR3mpxqlZ0dC3VLPQ183E3WMdOB4pYEVAYJwwnFi7+uBoqERsfnDgrhHxqvks7W 75eaiafcQO5/8UbqlGM4U9IZumBaNIWRftrlc+YpUcqEepBQGIGGwR0negoqC6Z9d8Q+ 24YNvBH3/S9G984K0Hw44Ej9Tj+KekRq3ZaBj9OcIZXZchkK97eEInTlEY+oCP/uvNjh BO0NlySiHEK0IyAxcMmLVZ0CE/dbQjxgmaabH28rgZ9UEmckHXDflUQHQqjfq7j04lJc vagQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=6QzV9xxce3nac1ij0srsLCFsMzFRkwGFbCVm8IDEXR8=; b=cfjnqqAINlnNXC58J8eZfZQCZBEaklj7aPrucVKMXAdmHXRYdB+OXcaRwMlNf6JhmJ 0xF6lj3og1U9WLBtOdfcWdyKV5wflC/jEWC0O2z2+sx6HTjRkFJxY/bUADO6DWnGg1aj wE1/JO77iQwc2ti4DL6bgiXzbL2X66FjfhPLQlbqULLT4WSSuZaLWLSSsC90vqvXJrjP wO0QUw/nDI9yqSeX3z4bymuRhPsBrwoIWJ1thsZCzbqzfscMeo225ao68WyEH2r4TCcE U9AYsmSXzNkdM6xwgd9Ui5vOaZYn/KrLZ/cqa2TSh4iI1eKB7ZeEndVIjaZlkF4X0/Pe 8V6Q== X-Gm-Message-State: AEkoouv5QE22Vnrb0J0AH93zbU6tiMJF9/OF+AjZ5U3M1oNrrtQNVlJu0MJSMNnxplLSKOUf X-Received: by 10.36.152.5 with SMTP id n5mr9655477itd.79.1469494806656; Mon, 25 Jul 2016 18:00:06 -0700 (PDT) Received: from kaki.bld.corp.google.com ([2620:0:1005:12:544b:64e8:bc3:7489]) by smtp.gmail.com with ESMTPSA id y42sm10346764ita.9.2016.07.25.18.00.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 25 Jul 2016 18:00:06 -0700 (PDT) Received: by kaki.bld.corp.google.com (Postfix, from userid 121222) id A4851220F90; Mon, 25 Jul 2016 19:00:05 -0600 (MDT) From: Simon Glass To: U-Boot Mailing List Date: Mon, 25 Jul 2016 18:59:04 -0600 Message-Id: <1469494766-26601-9-git-send-email-sjg@chromium.org> X-Mailer: git-send-email 2.8.0.rc3.226.g39d4020 In-Reply-To: <1469494766-26601-1-git-send-email-sjg@chromium.org> References: <1469494766-26601-1-git-send-email-sjg@chromium.org> Cc: Tom Rini Subject: [U-Boot] [PATCH 08/30] dtoc: Create a base class for Fdt X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" At present we have two separate implementations of the Fdt library, one which uses fdtget/fdtput and one which uses libfdt (via swig). Before adding more functionality it makes sense to create a base class for these. This will allow common functions to be shared, and make the Fdt API a little clearer. Create a new fdt.py file with the base class, and adjust fdt_normal.py and fdt_fallback.py to use it. Signed-off-by: Simon Glass --- tools/dtoc/fdt.py | 68 ++++++++++++++++++++++++++++++++++++++++++++++ tools/dtoc/fdt_fallback.py | 61 +++++++++++++++++++++++++---------------- tools/dtoc/fdt_normal.py | 58 +++++++++++++++++++++++++-------------- tools/dtoc/fdt_select.py | 9 ++++-- 4 files changed, 148 insertions(+), 48 deletions(-) create mode 100644 tools/dtoc/fdt.py diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py new file mode 100644 index 0000000..413d45d --- /dev/null +++ b/tools/dtoc/fdt.py @@ -0,0 +1,68 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 Google, Inc +# Written by Simon Glass +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import struct +import sys + +import fdt_util + +# 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. Most of the +# implementation is in the FdtFallback and FdtNormal subclasses. See +# fdt_select.py for how to create an Fdt object. + +def CheckErr(errnum, msg): + if errnum: + raise ValueError('Error %d: %s: %s' % + (errnum, libfdt.fdt_strerror(errnum), msg)) + +class PropBase: + """A device tree property + + Properties: + name: Property name (as per the device tree) + value: Property value as a string of bytes, or a list of strings of + bytes + type: Value type + """ + def __init__(self, node, offset, name): + self._node = node + self._offset = offset + self.name = name + self.value = None + +class NodeBase: + """A device tree node + + Properties: + offset: Integer offset in the device tree + name: Device tree node tname + path: Full path to node, along with the node name itself + _fdt: Device tree object + subnodes: A list of subnodes for this node, each a Node object + props: A dict of properties for this node, each a Prop object. + Keyed by property name + """ + def __init__(self, fdt, offset, name, path): + self._fdt = fdt + self._offset = offset + self.name = name + self.path = path + self.subnodes = [] + self.props = {} + +class Fdt: + """Provides simple access to a flat device tree blob. + + Properties: + fname: Filename of fdt + _root: Root of device tree (a Node object) + """ + def __init__(self, fname): + self._fname = fname diff --git a/tools/dtoc/fdt_fallback.py b/tools/dtoc/fdt_fallback.py index 14decf3..7d912e2 100644 --- a/tools/dtoc/fdt_fallback.py +++ b/tools/dtoc/fdt_fallback.py @@ -7,6 +7,8 @@ # import command +import fdt +from fdt import Fdt, NodeBase, PropBase import fdt_util import sys @@ -17,7 +19,7 @@ import sys # is not very efficient for larger trees. The tool is called once for each # node and property in the tree. -class Prop: +class Prop(PropBase): """A device tree property Properties: @@ -26,14 +28,14 @@ class Prop: bytes type: Value type """ - def __init__(self, name, byte_list_str): - self.name = name - self.value = None + def __init__(self, node, name, byte_list_str): + PropBase.__init__(self, node, 0, name) if not byte_list_str.strip(): self.type = fdt_util.TYPE_BOOL return - bytes = [chr(int(byte, 16)) for byte in byte_list_str.strip().split(' ')] - self.type, self.value = fdt_util.BytesToValue(''.join(bytes)) + self.bytes = [chr(int(byte, 16)) + for byte in byte_list_str.strip().split(' ')] + self.type, self.value = fdt_util.BytesToValue(''.join(self.bytes)) def GetPhandle(self): """Get a (single) phandle value from a property @@ -71,7 +73,7 @@ class Prop: if type(newprop.value) == list and type(self.value) != list: self.value = newprop.value -class Node: +class Node(NodeBase): """A device tree node Properties: @@ -82,12 +84,8 @@ class Node: props: A dict of properties for this node, each a Prop object. Keyed by property name """ - def __init__(self, fdt, name, path): - self.name = name - self.path = path - self._fdt = fdt - self.subnodes = [] - self.props = {} + def __init__(self, fdt, offset, name, path): + NodeBase.__init__(self, fdt, offset, name, path) def Scan(self): """Scan a node's properties and subnodes @@ -96,35 +94,34 @@ class Node: searching into subnodes so that the entire tree is built. """ for name, byte_list_str in self._fdt.GetProps(self.path).iteritems(): - prop = Prop(name, byte_list_str) + prop = Prop(self, name, byte_list_str) self.props[name] = prop for name in self._fdt.GetSubNodes(self.path): sep = '' if self.path[-1] == '/' else '/' path = self.path + sep + name - node = Node(self._fdt, name, path) + node = Node(self._fdt, 0, name, path) self.subnodes.append(node) node.Scan() -class Fdt: - """Provides simple access to a flat device tree blob. +class FdtFallback(Fdt): + """Provides simple access to a flat device tree blob using fdtget/fdtput Properties: - fname: Filename of fdt - _root: Root of device tree (a Node object) + See superclass """ def __init__(self, fname): - self.fname = fname + Fdt.__init__(self, fname) def Scan(self): """Scan a device tree, building up a tree of Node objects This fills in the self._root property """ - self._root = Node(self, '/', '/') + self._root = Node(self, 0, '/', '/') self._root.Scan() def GetRoot(self): @@ -147,7 +144,7 @@ class Fdt: Raises: CmdError: if the node does not exist. """ - out = command.Output('fdtget', self.fname, '-l', node) + out = command.Output('fdtget', self._fname, '-l', node) return out.strip().splitlines() def GetProps(self, node, convert_dashes=False): @@ -165,7 +162,7 @@ class Fdt: Raises: CmdError: if the node does not exist. """ - out = command.Output('fdtget', self.fname, node, '-p') + out = command.Output('fdtget', self._fname, node, '-p') props = out.strip().splitlines() props_dict = {} for prop in props: @@ -198,10 +195,26 @@ class Fdt: Raises: CmdError: if the property does not exist and no default is provided. """ - args = [self.fname, node, prop, '-t', 'bx'] + args = [self._fname, node, prop, '-t', 'bx'] if default is not None: args += ['-d', str(default)] if typespec is not None: args += ['-t%s' % typespec] out = command.Output('fdtget', *args) return out.strip() + + @classmethod + def Node(self, fdt, offset, name, path): + """Create a new node + + This is used by Fdt.Scan() to create a new node using the correct + class. + + Args: + fdt: Fdt object + offset: Offset of node + name: Node name + path: Full path to node + """ + node = Node(fdt, offset, name, path) + return node diff --git a/tools/dtoc/fdt_normal.py b/tools/dtoc/fdt_normal.py index 1d913a9..ca5335b 100644 --- a/tools/dtoc/fdt_normal.py +++ b/tools/dtoc/fdt_normal.py @@ -6,9 +6,13 @@ # SPDX-License-Identifier: GPL-2.0+ # +import struct +import sys + +import fdt +from fdt import Fdt, NodeBase, PropBase import fdt_util import libfdt -import sys # This deals with a device tree, presenting it as a list of Node and Prop # objects, representing nodes and properties, respectively. @@ -16,7 +20,7 @@ import sys # This implementation uses a libfdt Python library to access the device tree, # so it is fairly efficient. -class Prop: +class Prop(PropBase): """A device tree property Properties: @@ -25,9 +29,9 @@ class Prop: bytes type: Value type """ - def __init__(self, name, bytes): - self.name = name - self.value = None + def __init__(self, node, offset, name, bytes): + PropBase.__init__(self, node, offset, name) + self.bytes = bytes if not bytes: self.type = fdt_util.TYPE_BOOL self.value = True @@ -76,7 +80,7 @@ class Prop: self.value.append(val) -class Node: +class Node(NodeBase): """A device tree node Properties: @@ -89,12 +93,7 @@ class Node: Keyed by property name """ def __init__(self, fdt, offset, name, path): - self.offset = offset - self.name = name - self.path = path - self._fdt = fdt - self.subnodes = [] - self.props = {} + NodeBase.__init__(self, fdt, offset, name, path) def Scan(self): """Scan a node's properties and subnodes @@ -104,7 +103,7 @@ class Node: """ self.props = self._fdt.GetProps(self.path) - 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) @@ -116,17 +115,17 @@ class Node: offset = libfdt.fdt_next_subnode(self._fdt.GetFdt(), offset) -class Fdt: - """Provides simple access to a flat device tree blob. +class FdtNormal(Fdt): + """Provides simple access to a flat device tree blob using libfdt. Properties: - fname: Filename of fdt - _root: Root of device tree (a Node object) + _fdt: Device tree contents (bytearray) + _cached_offsets: True if all the nodes have a valid _offset property, + False if something has changed to invalidate the offsets """ - def __init__(self, fname): - self.fname = fname - with open(fname) as fd: + Fdt.__init__(self, fname) + with open(self._fname) as fd: self._fdt = fd.read() def GetFdt(self): @@ -173,8 +172,25 @@ class Fdt: poffset = libfdt.fdt_first_property_offset(self._fdt, offset) while poffset >= 0: dprop, plen = libfdt.fdt_get_property_by_offset(self._fdt, poffset) - prop = Prop(libfdt.String(self._fdt, dprop.nameoff), libfdt.Data(dprop)) + prop = Prop(node, poffset, libfdt.String(self._fdt, dprop.nameoff), + libfdt.Data(dprop)) props_dict[prop.name] = prop poffset = libfdt.fdt_next_property_offset(self._fdt, poffset) return props_dict + + @classmethod + def Node(self, fdt, offset, name, path): + """Create a new node + + This is used by Fdt.Scan() to create a new node using the correct + class. + + Args: + fdt: Fdt object + offset: Offset of node + name: Node name + path: Full path to node + """ + node = Node(fdt, offset, name, path) + return node diff --git a/tools/dtoc/fdt_select.py b/tools/dtoc/fdt_select.py index 681dfbf..18a36d8 100644 --- a/tools/dtoc/fdt_select.py +++ b/tools/dtoc/fdt_select.py @@ -10,14 +10,17 @@ # fallback one (which uses fdtget and is slower). Both provide the same # interface for this file to use. try: - import fdt_normal as fdt + import fdt_normal have_libfdt = True except ImportError: have_libfdt = False - import fdt_fallback as fdt + import fdt_fallback def FdtScan(fname): """Returns a new Fdt object from the implementation we are using""" - dtb = fdt.Fdt(fname) + if have_libfdt: + dtb = fdt_normal.FdtNormal(fname) + else: + dtb = fdt_fallback.FdtFallback(fname) dtb.Scan() return dtb