| # Copyright 2017 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Chrome OS Configuration access library (FDT). |
| |
| Chrome OS Configuration access library for a master configuration using flat |
| device tree. |
| """ |
| |
| from __future__ import print_function |
| |
| from collections import OrderedDict |
| |
| from . import fdt |
| import libcros_config_host |
| |
| class CrosConfigFdt(libcros_config_host.CrosConfigImpl): |
| """Flat Device Tree implementation of CrosConfig. |
| |
| This uses a device-tree file to hold this config. This provides efficient |
| run-time access since there is no need to parse the whole file. It also |
| supports links from one node to another, reducing redundancy in the config. |
| |
| Properties: |
| phandle_to_node: Map of phandles to the assocated CrosConfigImpl.Node: |
| key: Integer phandle value (>= 1) |
| value: Associated CrosConfigImpl.Node object |
| family: Family node (CrosConigImpl.Node object) |
| """ |
| def __init__(self, infile): |
| super(CrosConfigFdt, self).__init__(infile) |
| self._fdt = fdt.Fdt(self.infile) |
| self._fdt.Scan() |
| self.phandle_to_node = {} |
| self.root = CrosConfigFdt.MakeNode(self, self._fdt.GetRoot()) |
| self.family = self.root.subnodes['chromeos'].subnodes['family'] |
| |
| @staticmethod |
| def MakeNode(cros_config, fdt_node): |
| """Make a new Node in the tree |
| |
| This create a new Node or Model object in the tree and recursively adds all |
| subnodes to it. Any phandles found update the phandle_to_node map. |
| |
| Args: |
| cros_config: CrosConfig object |
| fdt_node: fdt.Node object containing the device-tree node |
| """ |
| node = CrosConfigFdt.Node(cros_config, fdt_node) |
| if fdt_node.parent and fdt_node.parent.name == 'models': |
| cros_config.models[node.name] = node |
| if 'phandle' in node.properties: |
| phandle = fdt_node.props['phandle'].GetPhandle() |
| cros_config.phandle_to_node[phandle] = node |
| node.default = node.FollowPhandle('default') |
| for subnode in fdt_node.subnodes.values(): |
| node.subnodes[subnode.name] = CrosConfigFdt.MakeNode(cros_config, subnode) |
| node.ScanSubnodes() |
| return node |
| |
| class Node(libcros_config_host.CrosConfigImpl.Node): |
| """FDT implementation of a node""" |
| def __init__(self, cros_config, fdt_node): |
| super(CrosConfigFdt.Node, self).__init__(cros_config) |
| self._fdt_node = fdt_node |
| self.name = fdt_node.name |
| # Subnodes are set up in Model.ScanSubnodes() |
| self.properties = OrderedDict((n, CrosConfigFdt.Property(p)) |
| for n, p in fdt_node.props.iteritems()) |
| |
| def GetPath(self): |
| """Get the full path to a node. |
| |
| Returns: |
| path to node as a string |
| """ |
| return self._fdt_node.path |
| |
| def FollowPhandle(self, prop_name): |
| """Follow a property's phandle |
| |
| Args: |
| prop_name: Property name to check |
| |
| Returns: |
| Node that the property's phandle points to, or None if none |
| """ |
| prop = self.properties.get(prop_name) |
| if not prop: |
| return None |
| return self.cros_config.phandle_to_node[prop.GetPhandle()] |
| |
| class Property(libcros_config_host.CrosConfigImpl.Property): |
| """FDT implementation of a property |
| |
| Properties: |
| name: The name of the property. |
| value: The value of the property. |
| type: The Python type of the property. |
| """ |
| def __init__(self, fdt_prop): |
| super(CrosConfigFdt.Property, self).__init__() |
| self._fdt_prop = fdt_prop |
| self.name = fdt_prop.name |
| self.value = fdt_prop.value |
| self.type = fdt_prop.type |
| |
| def GetPhandle(self): |
| """Get the value of a property as a phandle |
| |
| Returns: |
| Property's phandle as an integer (> 0) |
| """ |
| return self._fdt_prop.GetPhandle() |