From 604813cda77834e1cbb17bb74ace57d7233a8ae6 Mon Sep 17 00:00:00 2001 From: Christophe Dufaza Date: Sun, 8 Sep 2024 21:02:43 +0200 Subject: [PATCH] edtlib: auto-format Python source file Apply the black/autopep config we use verywhere, will produce more valuable "git diff" if we were to work on edtlib (issues, experiments, etc). --- src/devicetree/edtlib.py | 1415 ++++++++++++++++++++++++-------------- 1 file changed, 881 insertions(+), 534 deletions(-) diff --git a/src/devicetree/edtlib.py b/src/devicetree/edtlib.py index 088ef6e..b7d5366 100644 --- a/src/devicetree/edtlib.py +++ b/src/devicetree/edtlib.py @@ -70,19 +70,31 @@ from collections import defaultdict from copy import deepcopy from dataclasses import dataclass -from typing import Any, Callable, Dict, Iterable, List, NoReturn, \ - Optional, Set, TYPE_CHECKING, Tuple, Union +from typing import ( + Any, + Callable, + Dict, + Iterable, + List, + NoReturn, + Optional, + Set, + TYPE_CHECKING, + Tuple, + Union, +) import logging import os import re import yaml + try: # Use the C LibYAML parser if available, rather than the Python parser. # This makes e.g. gen_defines.py more than twice as fast. from yaml import CLoader as Loader except ImportError: - from yaml import Loader # type: ignore + from yaml import Loader # type: ignore from devicetree.dtlib import DT, DTError, to_num, to_nums, Type from devicetree.dtlib import Node as dtlib_Node @@ -161,11 +173,16 @@ class Binding: are multiple levels of 'child-binding' descriptions in the binding. """ - def __init__(self, path: Optional[str], fname2path: Dict[str, str], - raw: Any = None, require_compatible: bool = True, - require_description: bool = True, - inc_allowlist: Optional[List[str]] = None, - inc_blocklist: Optional[List[str]] = None): + def __init__( + self, + path: Optional[str], + fname2path: Dict[str, str], + raw: Any = None, + require_compatible: bool = True, + require_description: bool = True, + inc_allowlist: Optional[List[str]] = None, + inc_blocklist: Optional[List[str]] = None, + ): """ Binding constructor. @@ -221,7 +238,7 @@ def __init__(self, path: Optional[str], fname2path: Dict[str, str], # the properties specified by the included bindings # - eventually, we'll update prop2specs with the properties # this binding itself defines or modifies - self.prop2specs: Dict[str, 'PropertySpec'] = {} + self.prop2specs: Dict[str, "PropertySpec"] = {} # Merge any included files into self.raw. This also pulls in # inherited child binding definitions, so it has to be done @@ -233,13 +250,17 @@ def __init__(self, path: Optional[str], fname2path: Dict[str, str], # but they must be dicts. if "child-binding" in raw: if not isinstance(raw["child-binding"], dict): - _err(f"malformed 'child-binding:' in {self.path}, " - "expected a binding (dictionary with keys/values)") - self.child_binding: Optional['Binding'] = Binding( - path, fname2path, + _err( + f"malformed 'child-binding:' in {self.path}, " + "expected a binding (dictionary with keys/values)" + ) + self.child_binding: Optional["Binding"] = Binding( + path, + fname2path, raw=raw["child-binding"], require_compatible=False, - require_description=False) + require_description=False, + ) else: self.child_binding = None @@ -254,7 +275,7 @@ def __init__(self, path: Optional[str], fname2path: Dict[str, str], self.specifier2cells: Dict[str, List[str]] = {} for key, val in self.raw.items(): if key.endswith("-cells"): - self.specifier2cells[key[:-len("-cells")]] = val + self.specifier2cells[key[: -len("-cells")]] = val def __repr__(self) -> str: if self.compatible: @@ -267,22 +288,22 @@ def __repr__(self) -> str: @property def description(self) -> Optional[str]: "See the class docstring" - return self.raw.get('description') + return self.raw.get("description") @property def compatible(self) -> Optional[str]: "See the class docstring" - return self.raw.get('compatible') + return self.raw.get("compatible") @property def bus(self) -> Union[None, str, List[str]]: "See the class docstring" - return self.raw.get('bus') + return self.raw.get("bus") @property def buses(self) -> List[str]: "See the class docstring" - if self.raw.get('bus') is not None: + if self.raw.get("bus") is not None: return self._buses else: return [] @@ -290,7 +311,7 @@ def buses(self) -> List[str]: @property def on_bus(self) -> Optional[str]: "See the class docstring" - return self.raw.get('on-bus') + return self.raw.get("on-bus") def _merge_includes(self, raw: dict, binding_path: Optional[str]) -> dict: # Constructor helper. Merges included files in @@ -315,25 +336,27 @@ def _merge_includes(self, raw: dict, binding_path: Optional[str]) -> dict: if isinstance(include, str): # Simple scalar string case # Load YAML file and register property specs into prop2specs. - inc_raw = self._load_raw(include, self._inc_allowlist, - self._inc_blocklist) + inc_raw = self._load_raw( + include, self._inc_allowlist, self._inc_blocklist + ) - _merge_props(merged, inc_raw, None, binding_path, False) + _merge_props(merged, inc_raw, None, binding_path, False) elif isinstance(include, list): # List of strings and maps. These types may be intermixed. for elem in include: if isinstance(elem, str): # Load YAML file and register property specs into prop2specs. - inc_raw = self._load_raw(elem, self._inc_allowlist, - self._inc_blocklist) + inc_raw = self._load_raw( + elem, self._inc_allowlist, self._inc_blocklist + ) _merge_props(merged, inc_raw, None, binding_path, False) elif isinstance(elem, dict): - name = elem.pop('name', None) + name = elem.pop("name", None) # Merge this include property-allowlist filter # with filters from including bindings. - allowlist = elem.pop('property-allowlist', None) + allowlist = elem.pop("property-allowlist", None) if allowlist is not None: if self._inc_allowlist: allowlist.extend(self._inc_allowlist) @@ -342,39 +365,46 @@ def _merge_includes(self, raw: dict, binding_path: Optional[str]) -> dict: # Merge this include property-blocklist filter # with filters from including bindings. - blocklist = elem.pop('property-blocklist', None) + blocklist = elem.pop("property-blocklist", None) if blocklist is not None: if self._inc_blocklist: blocklist.extend(self._inc_blocklist) else: blocklist = self._inc_blocklist - child_filter = elem.pop('child-binding', None) + child_filter = elem.pop("child-binding", None) if elem: # We've popped out all the valid keys. - _err(f"'include:' in {binding_path} should not have " - f"these unexpected contents: {elem}") + _err( + f"'include:' in {binding_path} should not have " + f"these unexpected contents: {elem}" + ) - _check_include_dict(name, allowlist, blocklist, - child_filter, binding_path) + _check_include_dict( + name, allowlist, blocklist, child_filter, binding_path + ) # Load YAML file, and register (filtered) property specs # into prop2specs. - contents = self._load_raw(name, - allowlist, blocklist, - child_filter) + contents = self._load_raw( + name, allowlist, blocklist, child_filter + ) _merge_props(merged, contents, None, binding_path, False) else: - _err(f"all elements in 'include:' in {binding_path} " - "should be either strings or maps with a 'name' key " - "and optional 'property-allowlist' or " - f"'property-blocklist' keys, but got: {elem}") + _err( + f"all elements in 'include:' in {binding_path} " + "should be either strings or maps with a 'name' key " + "and optional 'property-allowlist' or " + f"'property-blocklist' keys, but got: {elem}" + ) else: # Invalid item. - _err(f"'include:' in {binding_path} " - f"should be a string or list, but has type {type(include)}") + _err( + f"'include:' in {binding_path} " + f"should be a string or list, but has type {type(include)}" + ) # Next, merge the merged included files into 'raw'. Error out if # 'raw' has 'required: false' while the merged included files have @@ -384,11 +414,13 @@ def _merge_includes(self, raw: dict, binding_path: Optional[str]) -> dict: return raw - - def _load_raw(self, fname: str, - allowlist: Optional[List[str]] = None, - blocklist: Optional[List[str]] = None, - child_filter: Optional[dict] = None) -> dict: + def _load_raw( + self, + fname: str, + allowlist: Optional[List[str]] = None, + blocklist: Optional[List[str]] = None, + child_filter: Optional[dict] = None, + ) -> dict: # Returns the contents of the binding given by 'fname' after merging # any bindings it lists in 'include:' into it, according to the given # property filters. @@ -404,21 +436,25 @@ def _load_raw(self, fname: str, with open(path, encoding="utf-8") as f: contents = yaml.load(f, Loader=_BindingLoader) if not isinstance(contents, dict): - _err(f'{path}: invalid contents, expected a mapping') + _err(f"{path}: invalid contents, expected a mapping") # Apply constraints to included YAML contents. - _filter_properties(contents, - allowlist, blocklist, - child_filter, self.path) + _filter_properties( + contents, allowlist, blocklist, child_filter, self.path + ) # Register included property specs. self._add_included_prop2specs(fname, contents, allowlist, blocklist) return self._merge_includes(contents, path) - def _add_included_prop2specs(self, fname: str, contents: dict, - allowlist: Optional[List[str]] = None, - blocklist: Optional[List[str]] = None) -> None: + def _add_included_prop2specs( + self, + fname: str, + contents: dict, + allowlist: Optional[List[str]] = None, + blocklist: Optional[List[str]] = None, + ) -> None: # Registers the properties specified by an included binding file # into the properties this binding supports/requires (aka prop2specs). # @@ -463,9 +499,11 @@ def _check(self, require_compatible: bool, require_description: bool): if "compatible" in raw: compatible = raw["compatible"] if not isinstance(compatible, str): - _err(f"malformed 'compatible: {compatible}' " - f"field in {self.path} - " - f"should be a string, not {type(compatible).__name__}") + _err( + f"malformed 'compatible: {compatible}' " + f"field in {self.path} - " + f"should be a string, not {type(compatible).__name__}" + ) elif require_compatible: _err(f"missing 'compatible' in {self.path}") @@ -478,8 +516,14 @@ def _check(self, require_compatible: bool, require_description: bool): # Allowed top-level keys. The 'include' key should have been # removed by _load_raw() already. - ok_top = {"description", "compatible", "bus", "on-bus", - "properties", "child-binding"} + ok_top = { + "description", + "compatible", + "bus", + "on-bus", + "properties", + "child-binding", + } # Descriptive errors for legacy bindings. legacy_errors = { @@ -497,16 +541,21 @@ def _check(self, require_compatible: bool, require_description: bool): _err(f"legacy '{key}:' in {self.path}, {legacy_errors[key]}") if key not in ok_top and not key.endswith("-cells"): - _err(f"unknown key '{key}' in {self.path}, " - "expected one of {', '.join(ok_top)}, or *-cells") + _err( + f"unknown key '{key}' in {self.path}, " + "expected one of {', '.join(ok_top)}, or *-cells" + ) if "bus" in raw: bus = raw["bus"] - if not isinstance(bus, str) and \ - (not isinstance(bus, list) and \ - not all(isinstance(elem, str) for elem in bus)): - _err(f"malformed 'bus:' value in {self.path}, " - "expected string or list of strings") + if not isinstance(bus, str) and ( + not isinstance(bus, list) + and not all(isinstance(elem, str) for elem in bus) + ): + _err( + f"malformed 'bus:' value in {self.path}, " + "expected string or list of strings" + ) if isinstance(bus, list): self._buses = bus @@ -514,19 +563,22 @@ def _check(self, require_compatible: bool, require_description: bool): # Convert bus into a list self._buses = [bus] - if "on-bus" in raw and \ - not isinstance(raw["on-bus"], str): - _err(f"malformed 'on-bus:' value in {self.path}, " - "expected string") + if "on-bus" in raw and not isinstance(raw["on-bus"], str): + _err( + f"malformed 'on-bus:' value in {self.path}, " "expected string" + ) self._check_properties() for key, val in raw.items(): if key.endswith("-cells"): - if not isinstance(val, list) or \ - not all(isinstance(elem, str) for elem in val): - _err(f"malformed '{key}:' in {self.path}, " - "expected a list of strings") + if not isinstance(val, list) or not all( + isinstance(elem, str) for elem in val + ): + _err( + f"malformed '{key}:' in {self.path}, " + "expected a list of strings" + ) def _check_properties(self) -> None: # _check() helper for checking the contents of 'properties:'. @@ -536,16 +588,25 @@ def _check_properties(self) -> None: if "properties" not in raw: return - ok_prop_keys = {"description", "type", "required", - "enum", "const", "default", "deprecated", - "specifier-space"} + ok_prop_keys = { + "description", + "type", + "required", + "enum", + "const", + "default", + "deprecated", + "specifier-space", + } for prop_name, options in raw["properties"].items(): for key in options: if key not in ok_prop_keys: - _err(f"unknown setting '{key}' in " - f"'properties: {prop_name}: ...' in {self.path}, " - f"expected one of {', '.join(ok_prop_keys)}") + _err( + f"unknown setting '{key}' in " + f"'properties: {prop_name}: ...' in {self.path}, " + f"expected one of {', '.join(ok_prop_keys)}" + ) _check_prop_by_type(prop_name, options, self.path) @@ -553,22 +614,31 @@ def _check_properties(self) -> None: if true_false_opt in options: option = options[true_false_opt] if not isinstance(option, bool): - _err(f"malformed '{true_false_opt}:' setting '{option}' " - f"for '{prop_name}' in 'properties' in {self.path}, " - "expected true/false") + _err( + f"malformed '{true_false_opt}:' setting '{option}' " + f"for '{prop_name}' in 'properties' in {self.path}, " + "expected true/false" + ) if options.get("deprecated") and options.get("required"): - _err(f"'{prop_name}' in 'properties' in {self.path} should not " - "have both 'deprecated' and 'required' set") + _err( + f"'{prop_name}' in 'properties' in {self.path} should not " + "have both 'deprecated' and 'required' set" + ) - if "description" in options and \ - not isinstance(options["description"], str): - _err("missing, malformed, or empty 'description' for " - f"'{prop_name}' in 'properties' in {self.path}") + if "description" in options and not isinstance( + options["description"], str + ): + _err( + "missing, malformed, or empty 'description' for " + f"'{prop_name}' in 'properties' in {self.path}" + ) if "enum" in options and not isinstance(options["enum"], list): - _err(f"enum in {self.path} for property '{prop_name}' " - "is not a list") + _err( + f"enum in {self.path} for property '{prop_name}' " + "is not a list" + ) class PropertySpec: @@ -658,30 +728,32 @@ def enum(self) -> Optional[list]: @property def enum_tokenizable(self) -> bool: "See the class docstring" - if not hasattr(self, '_enum_tokenizable'): - if self.type != 'string' or self.enum is None: + if not hasattr(self, "_enum_tokenizable"): + if self.type != "string" or self.enum is None: self._enum_tokenizable = False else: # Saving _as_tokens here lets us reuse it in # enum_upper_tokenizable. - self._as_tokens = [re.sub(_NOT_ALPHANUM_OR_UNDERSCORE, - '_', value) - for value in self.enum] - self._enum_tokenizable = (len(self._as_tokens) == - len(set(self._as_tokens))) + self._as_tokens = [ + re.sub(_NOT_ALPHANUM_OR_UNDERSCORE, "_", value) + for value in self.enum + ] + self._enum_tokenizable = len(self._as_tokens) == len( + set(self._as_tokens) + ) return self._enum_tokenizable @property def enum_upper_tokenizable(self) -> bool: "See the class docstring" - if not hasattr(self, '_enum_upper_tokenizable'): + if not hasattr(self, "_enum_upper_tokenizable"): if not self.enum_tokenizable: self._enum_upper_tokenizable = False else: - self._enum_upper_tokenizable = \ - (len(self._as_tokens) == - len(set(x.upper() for x in self._as_tokens))) + self._enum_upper_tokenizable = len(self._as_tokens) == len( + set(x.upper() for x in self._as_tokens) + ) return self._enum_upper_tokenizable @property @@ -709,11 +781,18 @@ def specifier_space(self) -> Optional[str]: "See the class docstring" return self._raw.get("specifier-space") -PropertyValType = Union[int, str, - List[int], List[str], - 'Node', List['Node'], - List[Optional['ControllerAndData']], - bytes, None] + +PropertyValType = Union[ + int, + str, + List[int], + List[str], + "Node", + List["Node"], + List[Optional["ControllerAndData"]], + bytes, + None, +] @dataclass @@ -776,7 +855,7 @@ class Property: spec: PropertySpec val: PropertyValType - node: 'Node' + node: "Node" @property def name(self) -> str: @@ -828,7 +907,7 @@ class Register: The length of the register in bytes """ - node: 'Node' + node: "Node" name: Optional[str] addr: Optional[int] size: Optional[int] @@ -866,7 +945,8 @@ class Range: The size of the range in the child address space, or None if the child's #size-cells equals 0. """ - node: 'Node' + + node: "Node" child_bus_cells: int child_bus_addr: Optional[int] parent_bus_cells: int @@ -907,8 +987,9 @@ class ControllerAndData: basename: Basename for the controller when supporting named cells """ - node: 'Node' - controller: 'Node' + + node: "Node" + controller: "Node" data: dict name: Optional[str] basename: Optional[str] @@ -939,9 +1020,9 @@ class PinCtrl: pinctrl-0 = <&state_1 &state_2>; """ - node: 'Node' + node: "Node" name: Optional[str] - conf_nodes: List['Node'] + conf_nodes: List["Node"] @property def name_as_token(self): @@ -1090,15 +1171,12 @@ class Node: True if the node is a PCI device. """ - def __init__(self, - dt_node: dtlib_Node, - edt: 'EDT', - compats: List[str]): - ''' + def __init__(self, dt_node: dtlib_Node, edt: "EDT", compats: List[str]): + """ For internal use only; not meant to be used outside edtlib itself. - ''' + """ # Public, some of which are initialized properly later: - self.edt: 'EDT' = edt + self.edt: "EDT" = edt self.dep_ordinal: int = -1 self.matching_compat: Optional[str] = None self.binding_path: Optional[str] = None @@ -1108,7 +1186,7 @@ def __init__(self, self.props: Dict[str, Property] = {} self.interrupts: List[ControllerAndData] = [] self.pinctrls: List[PinCtrl] = [] - self.bus_node: Optional['Node'] = None + self.bus_node: Optional["Node"] = None # Private, don't touch outside the class: self._node: dtlib_Node = dt_node @@ -1144,7 +1222,7 @@ def description(self) -> Optional[str]: return None @property - def path(self) -> str: + def path(self) -> str: "See the class docstring" return self._node.path @@ -1161,42 +1239,45 @@ def labels(self) -> List[str]: return self._node.labels @property - def parent(self) -> Optional['Node']: + def parent(self) -> Optional["Node"]: "See the class docstring" - return self.edt._node2enode.get(self._node.parent) # type: ignore + return self.edt._node2enode.get(self._node.parent) # type: ignore @property - def children(self) -> Dict[str, 'Node']: + def children(self) -> Dict[str, "Node"]: "See the class docstring" # Could be initialized statically too to preserve identity, but not # sure if needed. Parent nodes being initialized before their children # would need to be kept in mind. - return {name: self.edt._node2enode[node] - for name, node in self._node.nodes.items()} + return { + name: self.edt._node2enode[node] + for name, node in self._node.nodes.items() + } def child_index(self, node) -> int: """Get the index of *node* in self.children. Raises KeyError if the argument is not a child of this node. """ - if not hasattr(self, '_child2index'): + if not hasattr(self, "_child2index"): # Defer initialization of this lookup table until this # method is callable to handle parents needing to be # initialized before their chidlren. By the time we # return from __init__, 'self.children' is callable. self._child2index: Dict[str, int] = {} - for index, child_path in enumerate(child.path for child in - self.children.values()): + for index, child_path in enumerate( + child.path for child in self.children.values() + ): self._child2index[child_path] = index return self._child2index[node.path] @property - def required_by(self) -> List['Node']: + def required_by(self) -> List["Node"]: "See the class docstring" return self.edt._graph.required_by(self) @property - def depends_on(self) -> List['Node']: + def depends_on(self) -> List["Node"]: "See the class docstring" return self.edt._graph.depends_on(self) @@ -1223,8 +1304,11 @@ def read_only(self) -> bool: @property def aliases(self) -> List[str]: "See the class docstring" - return [alias for alias, node in self._node.dt.alias2node.items() - if node is self._node] + return [ + alias + for alias, node in self._node.dt.alias2node.items() + if node is self._node + ] @property def buses(self) -> List[str]: @@ -1240,7 +1324,7 @@ def on_buses(self) -> List[str]: return bus_node.buses if bus_node else [] @property - def flash_controller(self) -> 'Node': + def flash_controller(self) -> "Node": "See the class docstring" # The node path might be something like @@ -1256,7 +1340,9 @@ def flash_controller(self) -> 'Node': controller = self.parent.parent if controller.matching_compat == "soc-nv-flash": if controller.parent is None: - _err(f"flash controller '{controller.path}' cannot be the root node") + _err( + f"flash controller '{controller.path}' cannot be the root node" + ) return controller.parent return controller @@ -1264,14 +1350,18 @@ def flash_controller(self) -> 'Node': def spi_cs_gpio(self) -> Optional[ControllerAndData]: "See the class docstring" - if not ("spi" in self.on_buses - and self.bus_node - and "cs-gpios" in self.bus_node.props): + if not ( + "spi" in self.on_buses + and self.bus_node + and "cs-gpios" in self.bus_node.props + ): return None if not self.regs: - _err(f"{self!r} needs a 'reg' property, to look up the " - "chip select index for SPI") + _err( + f"{self!r} needs a 'reg' property, to look up the " + "chip select index for SPI" + ) parent_cs_lst = self.bus_node.props["cs-gpios"].val if TYPE_CHECKING: @@ -1283,9 +1373,11 @@ def spi_cs_gpio(self) -> Optional[ControllerAndData]: assert isinstance(cs_index, int) if cs_index >= len(parent_cs_lst): - _err(f"index from 'regs' in {self!r} ({cs_index}) " - "is >= number of cs-gpios in " - f"{self.bus_node!r} ({len(parent_cs_lst)})") + _err( + f"index from 'regs' in {self!r} ({cs_index}) " + "is >= number of cs-gpios in " + f"{self.bus_node!r} ({len(parent_cs_lst)})" + ) ret = parent_cs_lst[cs_index] if TYPE_CHECKING: @@ -1308,20 +1400,26 @@ def gpio_hogs(self) -> List[ControllerAndData]: n_cells = self.parent._node.props["#gpio-cells"].to_num() res = [] - for item in _slice(self._node, "gpios", 4*n_cells, - f"4*(<#gpio-cells> (= {n_cells})"): + for item in _slice( + self._node, "gpios", 4 * n_cells, f"4*(<#gpio-cells> (= {n_cells})" + ): controller = self.parent - res.append(ControllerAndData( - node=self, controller=controller, - data=self._named_cells(controller, item, "gpio"), - name=None, basename="gpio")) + res.append( + ControllerAndData( + node=self, + controller=controller, + data=self._named_cells(controller, item, "gpio"), + name=None, + basename="gpio", + ) + ) return res @property def is_pci_device(self) -> bool: "See the class docstring" - return 'pcie' in self.on_buses + return "pcie" in self.on_buses def __repr__(self) -> str: if self.binding_path: @@ -1396,8 +1494,8 @@ def _binding_from_properties(self) -> None: # Synthesize a 'raw' binding as if it had been parsed from YAML. raw: Dict[str, Any] = { - 'description': 'Inferred binding from properties, via edtlib.', - 'properties': {}, + "description": "Inferred binding from properties, via edtlib.", + "properties": {}, } for name, prop in self._node.props.items(): pp: Dict[str, str] = {} @@ -1422,9 +1520,11 @@ def _binding_from_properties(self) -> None: elif prop.type == Type.PATH: pp["type"] = "path" else: - _err(f"cannot infer binding from property: {prop} " - f"with type {prop.type!r}") - raw['properties'][name] = pp + _err( + f"cannot infer binding from property: {prop} " + f"with type {prop.type!r}" + ) + raw["properties"][name] = pp # Set up Node state. self.binding_path = None @@ -1448,8 +1548,9 @@ def _binding_from_parent(self) -> Optional[Binding]: return None - def _bus_node(self, support_fixed_partitions_on_any_bus: bool = True - ) -> Optional['Node']: + def _bus_node( + self, support_fixed_partitions_on_any_bus: bool = True + ) -> Optional["Node"]: # Returns the value for self.bus_node. Relies on parent nodes being # initialized before their children. @@ -1462,7 +1563,10 @@ def _bus_node(self, support_fixed_partitions_on_any_bus: bool = True # bus be None means we'll always match the binding for fixed-partitions # also this means want processing the fixed-partitions node we wouldn't # try to do anything bus specific with it. - if support_fixed_partitions_on_any_bus and "fixed-partitions" in self.compats: + if ( + support_fixed_partitions_on_any_bus + and "fixed-partitions" in self.compats + ): return None if self.parent.buses: @@ -1472,8 +1576,9 @@ def _bus_node(self, support_fixed_partitions_on_any_bus: bool = True # Same bus node as parent (possibly None) return self.parent.bus_node - def _init_props(self, default_prop_types: bool = False, - err_on_deprecated: bool = False) -> None: + def _init_props( + self, default_prop_types: bool = False, err_on_deprecated: bool = False + ) -> None: # Creates self.props. See the class docstring. Also checks that all # properties on the node are declared in its binding. @@ -1495,12 +1600,20 @@ def _init_props(self, default_prop_types: bool = False, if name not in _DEFAULT_PROP_SPECS: continue prop_spec = _DEFAULT_PROP_SPECS[name] - val = self._prop_val(name, prop_spec.type, False, False, None, - None, err_on_deprecated) + val = self._prop_val( + name, + prop_spec.type, + False, + False, + None, + None, + err_on_deprecated, + ) self.props[name] = Property(prop_spec, val, self) - def _init_prop(self, prop_spec: PropertySpec, - err_on_deprecated: bool) -> None: + def _init_prop( + self, prop_spec: PropertySpec, err_on_deprecated: bool + ) -> None: # _init_props() helper for initializing a single property. # 'prop_spec' is a PropertySpec object from the node's binding. @@ -1509,9 +1622,15 @@ def _init_prop(self, prop_spec: PropertySpec, if not prop_type: _err(f"'{name}' in {self.binding_path} lacks 'type'") - val = self._prop_val(name, prop_type, prop_spec.deprecated, - prop_spec.required, prop_spec.default, - prop_spec.specifier_space, err_on_deprecated) + val = self._prop_val( + name, + prop_type, + prop_spec.deprecated, + prop_spec.required, + prop_spec.default, + prop_spec.specifier_space, + err_on_deprecated, + ) if val is None: # 'required: false' property that wasn't there, or a property type @@ -1520,16 +1639,20 @@ def _init_prop(self, prop_spec: PropertySpec, enum = prop_spec.enum if enum and val not in enum: - _err(f"value of property '{name}' on {self.path} in " - f"{self.edt.dts_path} ({val!r}) is not in 'enum' list in " - f"{self.binding_path} ({enum!r})") + _err( + f"value of property '{name}' on {self.path} in " + f"{self.edt.dts_path} ({val!r}) is not in 'enum' list in " + f"{self.binding_path} ({enum!r})" + ) const = prop_spec.const if const is not None and val != const: - _err(f"value of property '{name}' on {self.path} in " - f"{self.edt.dts_path} ({val!r}) " - "is different from the 'const' value specified in " - f"{self.binding_path} ({const!r})") + _err( + f"value of property '{name}' on {self.path} in " + f"{self.edt.dts_path} ({val!r}) " + "is different from the 'const' value specified in " + f"{self.binding_path} ({const!r})" + ) # Skip properties that start with '#', like '#size-cells', and mapping # properties like 'gpio-map'/'interrupt-map' @@ -1538,11 +1661,16 @@ def _init_prop(self, prop_spec: PropertySpec, self.props[name] = Property(prop_spec, val, self) - def _prop_val(self, name: str, prop_type: str, - deprecated: bool, required: bool, - default: PropertyValType, - specifier_space: Optional[str], - err_on_deprecated: bool) -> PropertyValType: + def _prop_val( + self, + name: str, + prop_type: str, + deprecated: bool, + required: bool, + default: PropertyValType, + specifier_space: Optional[str], + err_on_deprecated: bool, + ) -> PropertyValType: # _init_prop() helper for getting the property's value # # name: @@ -1571,8 +1699,10 @@ def _prop_val(self, name: str, prop_type: str, prop = node.props.get(name) if prop and deprecated: - msg = (f"'{name}' is marked as deprecated in 'properties:' " - f"in {self.binding_path} for node {node.path}.") + msg = ( + f"'{name}' is marked as deprecated in 'properties:' " + f"in {self.binding_path} for node {node.path}." + ) if err_on_deprecated: _err(msg) else: @@ -1580,8 +1710,10 @@ def _prop_val(self, name: str, prop_type: str, if not prop: if required and self.status == "okay": - _err(f"'{name}' is marked as required in 'properties:' in " - f"{self.binding_path}, but does not appear in {node!r}") + _err( + f"'{name}' is marked as required in 'properties:' in " + f"{self.binding_path}, but does not appear in {node!r}" + ) if default is not None: # YAML doesn't have a native format for byte arrays. We need to @@ -1589,16 +1721,18 @@ def _prop_val(self, name: str, prop_type: str, # format has already been checked in # _check_prop_by_type(). if prop_type == "uint8-array": - return bytes(default) # type: ignore + return bytes(default) # type: ignore return default return False if prop_type == "boolean" else None if prop_type == "boolean": if prop.type != Type.EMPTY: - _err("'{0}' in {1!r} is defined with 'type: boolean' in {2}, " - "but is assigned a value ('{3}') instead of being empty " - "('{0};')".format(name, node, self.binding_path, prop)) + _err( + "'{0}' in {1!r} is defined with 'type: boolean' in {2}, " + "but is assigned a value ('{3}') instead of being empty " + "('{0};')".format(name, node, self.binding_path, prop) + ) return True if prop_type == "int": @@ -1626,11 +1760,17 @@ def _prop_val(self, name: str, prop_type: str, # This type is a bit high-level for dtlib as it involves # information from bindings and *-names properties, so there's no # to_phandle_array() in dtlib. Do the type check ourselves. - if prop.type not in (Type.PHANDLE, Type.PHANDLES, Type.PHANDLES_AND_NUMS): - _err(f"expected property '{name}' in {node.path} in " - f"{node.dt.filename} to be assigned " - f"with '{name} = < &foo ... &bar 1 ... &baz 2 3 >' " - f"(a mix of phandles and numbers), not '{prop}'") + if prop.type not in ( + Type.PHANDLE, + Type.PHANDLES, + Type.PHANDLES_AND_NUMS, + ): + _err( + f"expected property '{name}' in {node.path} in " + f"{node.dt.filename} to be assigned " + f"with '{name} = < &foo ... &bar 1 ... &baz 2 3 >' " + f"(a mix of phandles and numbers), not '{prop}'" + ) return self._standard_phandle_val_list(prop, specifier_space) @@ -1650,20 +1790,31 @@ def _check_undeclared_props(self) -> None: for prop_name in self._node.props: # Allow a few special properties to not be declared in the binding - if prop_name.endswith("-controller") or \ - prop_name.startswith("#") or \ - prop_name in { - "compatible", "status", "ranges", "phandle", - "interrupt-parent", "interrupts-extended", "device_type"}: + if ( + prop_name.endswith("-controller") + or prop_name.startswith("#") + or prop_name + in { + "compatible", + "status", + "ranges", + "phandle", + "interrupt-parent", + "interrupts-extended", + "device_type", + } + ): continue if TYPE_CHECKING: assert self._binding if prop_name not in self._binding.prop2specs: - _err(f"'{prop_name}' appears in {self._node.path} in " - f"{self.edt.dts_path}, but is not declared in " - f"'properties:' in {self.binding_path}") + _err( + f"'{prop_name}' appears in {self._node.path} in " + f"{self.edt.dts_path}, but is not declared in " + f"'properties:' in {self.binding_path}" + ) def _init_ranges(self) -> None: # Initializes self.ranges @@ -1677,55 +1828,77 @@ def _init_ranges(self) -> None: raw_child_address_cells = node.props.get("#address-cells") parent_address_cells = _address_cells(node) if raw_child_address_cells is None: - child_address_cells = 2 # Default value per DT spec. + child_address_cells = 2 # Default value per DT spec. else: child_address_cells = raw_child_address_cells.to_num() raw_child_size_cells = node.props.get("#size-cells") if raw_child_size_cells is None: - child_size_cells = 1 # Default value per DT spec. + child_size_cells = 1 # Default value per DT spec. else: child_size_cells = raw_child_size_cells.to_num() # Number of cells for one translation 3-tuple in 'ranges' - entry_cells = child_address_cells + parent_address_cells + child_size_cells + entry_cells = ( + child_address_cells + parent_address_cells + child_size_cells + ) if entry_cells == 0: if len(node.props["ranges"].value) == 0: return else: - _err(f"'ranges' should be empty in {self._node.path} since " - f"<#address-cells> = {child_address_cells}, " - f"<#address-cells for parent> = {parent_address_cells} and " - f"<#size-cells> = {child_size_cells}") - - for raw_range in _slice(node, "ranges", 4*entry_cells, - f"4*(<#address-cells> (= {child_address_cells}) + " - "<#address-cells for parent> " - f"(= {parent_address_cells}) + " - f"<#size-cells> (= {child_size_cells}))"): - + _err( + f"'ranges' should be empty in {self._node.path} since " + f"<#address-cells> = {child_address_cells}, " + f"<#address-cells for parent> = {parent_address_cells} and " + f"<#size-cells> = {child_size_cells}" + ) + + for raw_range in _slice( + node, + "ranges", + 4 * entry_cells, + f"4*(<#address-cells> (= {child_address_cells}) + " + "<#address-cells for parent> " + f"(= {parent_address_cells}) + " + f"<#size-cells> (= {child_size_cells}))", + ): child_bus_cells = child_address_cells if child_address_cells == 0: child_bus_addr = None else: - child_bus_addr = to_num(raw_range[:4*child_address_cells]) + child_bus_addr = to_num(raw_range[: 4 * child_address_cells]) parent_bus_cells = parent_address_cells if parent_address_cells == 0: parent_bus_addr = None else: parent_bus_addr = to_num( - raw_range[(4*child_address_cells): - (4*child_address_cells + 4*parent_address_cells)]) + raw_range[ + (4 * child_address_cells) : ( + 4 * child_address_cells + 4 * parent_address_cells + ) + ] + ) length_cells = child_size_cells if child_size_cells == 0: length = None else: length = to_num( - raw_range[(4*child_address_cells + 4*parent_address_cells):]) - - self.ranges.append(Range(self, child_bus_cells, child_bus_addr, - parent_bus_cells, parent_bus_addr, - length_cells, length)) + raw_range[ + (4 * child_address_cells + 4 * parent_address_cells) : + ] + ) + + self.ranges.append( + Range( + self, + child_bus_cells, + child_bus_addr, + parent_bus_cells, + parent_bus_addr, + length_cells, + length, + ) + ) def _init_regs(self) -> None: # Initializes self.regs @@ -1740,22 +1913,28 @@ def _init_regs(self) -> None: address_cells = _address_cells(node) size_cells = _size_cells(node) - for raw_reg in _slice(node, "reg", 4*(address_cells + size_cells), - f"4*(<#address-cells> (= {address_cells}) + " - f"<#size-cells> (= {size_cells}))"): + for raw_reg in _slice( + node, + "reg", + 4 * (address_cells + size_cells), + f"4*(<#address-cells> (= {address_cells}) + " + f"<#size-cells> (= {size_cells}))", + ): if address_cells == 0: addr = None else: - addr = _translate(to_num(raw_reg[:4*address_cells]), node) + addr = _translate(to_num(raw_reg[: 4 * address_cells]), node) if size_cells == 0: size = None else: - size = to_num(raw_reg[4*address_cells:]) + size = to_num(raw_reg[4 * address_cells :]) # Size zero is ok for PCI devices if size_cells != 0 and size == 0 and not self.is_pci_device: - _err(f"zero-sized 'reg' in {self._node!r} seems meaningless " - "(maybe you want a size of one or #size-cells = 0 " - "instead)") + _err( + f"zero-sized 'reg' in {self._node!r} seems meaningless " + "(maybe you want a size of one or #size-cells = 0 " + "instead)" + ) # We'll fix up the name when we're done. self.regs.append(Register(self, None, addr, size)) @@ -1768,25 +1947,34 @@ def _init_pinctrls(self) -> None: node = self._node # pinctrl- properties - pinctrl_props = [prop for name, prop in node.props.items() - if re.match("pinctrl-[0-9]+", name)] + pinctrl_props = [ + prop + for name, prop in node.props.items() + if re.match("pinctrl-[0-9]+", name) + ] # Sort by index pinctrl_props.sort(key=lambda prop: prop.name) # Check indices for i, prop in enumerate(pinctrl_props): if prop.name != "pinctrl-" + str(i): - _err(f"missing 'pinctrl-{i}' property on {node!r} " - "- indices should be contiguous and start from zero") + _err( + f"missing 'pinctrl-{i}' property on {node!r} " + "- indices should be contiguous and start from zero" + ) self.pinctrls = [] for prop in pinctrl_props: # We'll fix up the names below. - self.pinctrls.append(PinCtrl( - node=self, - name=None, - conf_nodes=[self.edt._node2enode[node] - for node in prop.to_nodes()])) + self.pinctrls.append( + PinCtrl( + node=self, + name=None, + conf_nodes=[ + self.edt._node2enode[node] for node in prop.to_nodes() + ], + ) + ) _add_names(node, "pinctrl", self.pinctrls) @@ -1800,17 +1988,20 @@ def _init_interrupts(self) -> None: for controller_node, data in _interrupts(node): # We'll fix up the names below. controller = self.edt._node2enode[controller_node] - self.interrupts.append(ControllerAndData( - node=self, controller=controller, - data=self._named_cells(controller, data, "interrupt"), - name=None, basename=None)) + self.interrupts.append( + ControllerAndData( + node=self, + controller=controller, + data=self._named_cells(controller, data, "interrupt"), + name=None, + basename=None, + ) + ) _add_names(node, "interrupt", self.interrupts) def _standard_phandle_val_list( - self, - prop: dtlib_Property, - specifier_space: Optional[str] + self, prop: dtlib_Property, specifier_space: Optional[str] ) -> List[Optional[ControllerAndData]]: # Parses a property like # @@ -1869,38 +2060,45 @@ def _standard_phandle_val_list( continue controller_node, data = item - mapped_controller, mapped_data = \ - _map_phandle_array_entry(prop.node, controller_node, data, - specifier_space) + mapped_controller, mapped_data = _map_phandle_array_entry( + prop.node, controller_node, data, specifier_space + ) controller = self.edt._node2enode[mapped_controller] # We'll fix up the names below. - res.append(ControllerAndData( - node=self, controller=controller, - data=self._named_cells(controller, mapped_data, - specifier_space), - name=None, basename=specifier_space)) + res.append( + ControllerAndData( + node=self, + controller=controller, + data=self._named_cells( + controller, mapped_data, specifier_space + ), + name=None, + basename=specifier_space, + ) + ) _add_names(self._node, specifier_space, res) return res def _named_cells( - self, - controller: 'Node', - data: bytes, - basename: str + self, controller: "Node", data: bytes, basename: str ) -> Dict[str, int]: # Returns a dictionary that maps -cells names given in the # binding for 'controller' to cell values. 'data' is the raw data, as a # byte array. if not controller._binding: - _err(f"{basename} controller {controller._node!r} " - f"for {self._node!r} lacks binding") + _err( + f"{basename} controller {controller._node!r} " + f"for {self._node!r} lacks binding" + ) if basename in controller._binding.specifier2cells: - cell_names: List[str] = controller._binding.specifier2cells[basename] + cell_names: List[str] = controller._binding.specifier2cells[ + basename + ] else: # Treat no *-cells in the binding the same as an empty *-cells, so # that bindings don't have to have e.g. an empty 'clock-cells:' for @@ -1909,9 +2107,11 @@ def _named_cells( data_list = to_nums(data) if len(data_list) != len(cell_names): - _err(f"unexpected '{basename}-cells:' length in binding for " - f"{controller._node!r} - {len(cell_names)} " - f"instead of {len(data_list)}") + _err( + f"unexpected '{basename}-cells:' length in binding for " + f"{controller._node!r} - {len(cell_names)} " + f"instead of {len(data_list)}" + ) return dict(zip(cell_names, data_list)) @@ -1977,15 +2177,17 @@ class EDT: unmarshal EDT objects. """ - def __init__(self, - dts: Optional[str], - bindings_dirs: List[str], - warn_reg_unit_address_mismatch: bool = True, - default_prop_types: bool = True, - support_fixed_partitions_on_any_bus: bool = True, - infer_binding_for_paths: Optional[Iterable[str]] = None, - vendor_prefixes: Optional[Dict[str, str]] = None, - werror: bool = False): + def __init__( + self, + dts: Optional[str], + bindings_dirs: List[str], + warn_reg_unit_address_mismatch: bool = True, + default_prop_types: bool = True, + support_fixed_partitions_on_any_bus: bool = True, + infer_binding_for_paths: Optional[Iterable[str]] = None, + vendor_prefixes: Optional[Dict[str, str]] = None, + werror: bool = False, + ): """EDT constructor. dts: @@ -2037,17 +2239,23 @@ def __init__(self, self.compat2nodes: Dict[str, List[Node]] = defaultdict(list) self.compat2okay: Dict[str, List[Node]] = defaultdict(list) self.compat2vendor: Dict[str, str] = defaultdict(str) - self.compat2model: Dict[str, str] = defaultdict(str) + self.compat2model: Dict[str, str] = defaultdict(str) self.label2node: Dict[str, Node] = {} self.dep_ord2node: Dict[int, Node] = {} - self.dts_path: str = dts # type: ignore + self.dts_path: str = dts # type: ignore self.bindings_dirs: List[str] = list(bindings_dirs) # Saved kwarg values for internal use - self._warn_reg_unit_address_mismatch: bool = warn_reg_unit_address_mismatch + self._warn_reg_unit_address_mismatch: bool = ( + warn_reg_unit_address_mismatch + ) self._default_prop_types: bool = default_prop_types - self._fixed_partitions_no_bus: bool = support_fixed_partitions_on_any_bus - self._infer_binding_for_paths: Set[str] = set(infer_binding_for_paths or []) + self._fixed_partitions_no_bus: bool = ( + support_fixed_partitions_on_any_bus + ) + self._infer_binding_for_paths: Set[str] = set( + infer_binding_for_paths or [] + ) self._vendor_prefixes: Dict[str, str] = vendor_prefixes or {} self._werror: bool = bool(werror) @@ -2056,8 +2264,7 @@ def __init__(self, self._graph: Graph = Graph() self._binding_paths: List[str] = _binding_paths(self.bindings_dirs) self._binding_fname2path: Dict[str, str] = { - os.path.basename(path): path - for path in self._binding_paths + os.path.basename(path): path for path in self._binding_paths } self._node2enode: Dict[dtlib_Node, Node] = {} @@ -2122,10 +2329,12 @@ def dts_source(self) -> str: return f"{self._dt}" def __repr__(self) -> str: - return f"" + ) - def __deepcopy__(self, memo) -> 'EDT': + def __deepcopy__(self, memo) -> "EDT": """ Implements support for the standard library copy.deepcopy() function on EDT instances. @@ -2139,7 +2348,7 @@ def __deepcopy__(self, memo) -> 'EDT': support_fixed_partitions_on_any_bus=self._fixed_partitions_no_bus, infer_binding_for_paths=set(self._infer_binding_for_paths), vendor_prefixes=dict(self._vendor_prefixes), - werror=self._werror + werror=self._werror, ) ret.dts_path = self.dts_path ret._dt = deepcopy(self._dt, memo) @@ -2165,14 +2374,14 @@ def _process_properties_r(self, root_node, props_node): # A Node depends on any Nodes present in 'phandle', # 'phandles', or 'phandle-array' property values. for prop in props_node.props.values(): - if prop.type == 'phandle': + if prop.type == "phandle": self._graph.add_edge(root_node, prop.val) - elif prop.type == 'phandles': + elif prop.type == "phandles": if TYPE_CHECKING: assert isinstance(prop.val, list) for phandle_node in prop.val: self._graph.add_edge(root_node, phandle_node) - elif prop.type == 'phandle-array': + elif prop.type == "phandle-array": if TYPE_CHECKING: assert isinstance(prop.val, list) for cd in prop.val: @@ -2265,8 +2474,9 @@ def _init_compat2binding(self) -> None: raw = yaml.load(contents, Loader=_BindingLoader) except yaml.YAMLError as e: _err( - f"'{binding_path}' appears in binding directories " - f"but isn't valid YAML: {e}") + f"'{binding_path}' appears in binding directories " + f"but isn't valid YAML: {e}" + ) continue # Convert the raw data to a Binding object, erroring out @@ -2280,10 +2490,9 @@ def _init_compat2binding(self) -> None: self._register_binding(binding) binding = binding.child_binding - def _binding(self, - raw: Optional[dict], - binding_path: str, - dt_compats: Set[str]) -> Optional[Binding]: + def _binding( + self, raw: Optional[dict], binding_path: str, dt_compats: Set[str] + ) -> Optional[Binding]: # Convert a 'raw' binding from YAML to a Binding object and return it. # # Error out if the raw data looks like an invalid binding. @@ -2310,11 +2519,14 @@ def _register_binding(self, binding: Binding) -> None: # 'compatible:'/'on-bus:' combo if TYPE_CHECKING: assert binding.compatible - old_binding = self._compat2binding.get((binding.compatible, - binding.on_bus)) + old_binding = self._compat2binding.get( + (binding.compatible, binding.on_bus) + ) if old_binding: - msg = (f"both {old_binding.path} and {binding.path} have " - f"'compatible: {binding.compatible}'") + msg = ( + f"both {old_binding.path} and {binding.path} have " + f"'compatible: {binding.compatible}'" + ) if binding.on_bus is not None: msg += f" and 'on-bus: {binding.on_bus}'" _err(msg) @@ -2346,8 +2558,10 @@ def _init_nodes(self) -> None: # These depend on all Node objects having been created, because # they (either always or sometimes) reference other nodes, so we # run them separately - node._init_props(default_prop_types=self._default_prop_types, - err_on_deprecated=self._werror) + node._init_props( + default_prop_types=self._default_prop_types, + err_on_deprecated=self._werror, + ) node._init_interrupts() node._init_pinctrls() @@ -2355,11 +2569,16 @@ def _init_nodes(self) -> None: # This warning matches the simple_bus_reg warning in dtc for node in self.nodes: # Address mismatch is ok for PCI devices - if (node.regs and node.regs[0].addr != node.unit_addr and - not node.is_pci_device): - _LOG.warning("unit address and first address in 'reg' " - f"(0x{node.regs[0].addr:x}) don't match for " - f"{node.path}") + if ( + node.regs + and node.regs[0].addr != node.unit_addr + and not node.is_pci_device + ): + _LOG.warning( + "unit address and first address in 'reg' " + f"(0x{node.regs[0].addr:x}) don't match for " + f"{node.path}" + ) def _init_luts(self) -> None: # Initialize node lookup tables (LUTs). @@ -2378,29 +2597,33 @@ def _init_luts(self) -> None: continue # The regular expression comes from dt-schema. - compat_re = r'^[a-zA-Z][a-zA-Z0-9,+\-._]+$' + compat_re = r"^[a-zA-Z][a-zA-Z0-9,+\-._]+$" if not re.match(compat_re, compat): - _err(f"node '{node.path}' compatible '{compat}' " - 'must match this regular expression: ' - f"'{compat_re}'") - - if ',' in compat and self._vendor_prefixes: - vendor, model = compat.split(',', 1) + _err( + f"node '{node.path}' compatible '{compat}' " + "must match this regular expression: " + f"'{compat_re}'" + ) + + if "," in compat and self._vendor_prefixes: + vendor, model = compat.split(",", 1) if vendor in self._vendor_prefixes: - self.compat2vendor[compat] = self._vendor_prefixes[vendor] + self.compat2vendor[compat] = self._vendor_prefixes[ + vendor + ] self.compat2model[compat] = model # As an exception, the root node can have whatever # compatibles it wants. Other nodes get checked. - elif node.path != '/': + elif node.path != "/": if self._werror: handler_fn: Any = _err else: handler_fn = _LOG.warning handler_fn( f"node '{node.path}' compatible '{compat}' " - f"has unknown vendor prefix '{vendor}'") - + f"has unknown vendor prefix '{vendor}'" + ) for nodeset in self.scc_order: node = nodeset[0] @@ -2411,29 +2634,30 @@ def _check(self) -> None: for binding in self._compat2binding.values(): for spec in binding.prop2specs.values(): - if not spec.enum or spec.type != 'string': + if not spec.enum or spec.type != "string": continue if not spec.enum_tokenizable: _LOG.warning( f"compatible '{binding.compatible}' " f"in binding '{binding.path}' has non-tokenizable enum " - f"for property '{spec.name}': " + - ', '.join(repr(x) for x in spec.enum)) + f"for property '{spec.name}': " + + ", ".join(repr(x) for x in spec.enum) + ) elif not spec.enum_upper_tokenizable: _LOG.warning( f"compatible '{binding.compatible}' " f"in binding '{binding.path}' has enum for property " f"'{spec.name}' that is only tokenizable " - 'in lowercase: ' + - ', '.join(repr(x) for x in spec.enum)) + "in lowercase: " + ", ".join(repr(x) for x in spec.enum) + ) # Validate the contents of compatible properties. for node in self.nodes: - if 'compatible' not in node.props: + if "compatible" not in node.props: continue - compatibles = node.props['compatible'].val + compatibles = node.props["compatible"].val # _check() runs after _init_compat2binding() has called # _dt_compats(), which already converted every compatible @@ -2446,8 +2670,9 @@ def _check(self) -> None: assert isinstance(compat, str) -def bindings_from_paths(yaml_paths: List[str], - ignore_errors: bool = False) -> List[Binding]: +def bindings_from_paths( + yaml_paths: List[str], ignore_errors: bool = False +) -> List[Binding]: """ Get a list of Binding objects from the yaml files 'yaml_paths'. @@ -2471,6 +2696,7 @@ def bindings_from_paths(yaml_paths: List[str], class EDTError(Exception): "Exception raised for devicetree- and binding-related errors" + # # Public global functions # @@ -2481,22 +2707,23 @@ def load_vendor_prefixes_txt(vendor_prefixes: str) -> Dict[str, str]: representation mapping a vendor prefix to the vendor name. """ vnd2vendor: Dict[str, str] = {} - with open(vendor_prefixes, 'r', encoding='utf-8') as f: + with open(vendor_prefixes, "r", encoding="utf-8") as f: for line in f: line = line.strip() - if not line or line.startswith('#'): + if not line or line.startswith("#"): # Comment or empty line. continue # Other lines should be in this form: # # - vnd_vendor = line.split('\t', 1) + vnd_vendor = line.split("\t", 1) assert len(vnd_vendor) == 2, line vnd2vendor[vnd_vendor[0]] = vnd_vendor[1] return vnd2vendor + # # Private global functions # @@ -2506,10 +2733,12 @@ def _dt_compats(dt: DT) -> Set[str]: # Returns a set() with all 'compatible' strings in the devicetree # represented by dt (a dtlib.DT instance) - return {compat - for node in dt.node_iter() - if "compatible" in node.props - for compat in node.props["compatible"].to_strings()} + return { + compat + for node in dt.node_iter() + if "compatible" in node.props + for compat in node.props["compatible"].to_strings() + } def _binding_paths(bindings_dirs: List[str]) -> List[str]: @@ -2533,78 +2762,96 @@ def _binding_inc_error(msg): raise yaml.constructor.ConstructorError(None, None, "error: " + msg) -def _check_include_dict(name: Optional[str], - allowlist: Optional[List[str]], - blocklist: Optional[List[str]], - child_filter: Optional[dict], - binding_path: Optional[str]) -> None: +def _check_include_dict( + name: Optional[str], + allowlist: Optional[List[str]], + blocklist: Optional[List[str]], + child_filter: Optional[dict], + binding_path: Optional[str], +) -> None: # Check that an 'include:' named 'name' with property-allowlist # 'allowlist', property-blocklist 'blocklist', and # child-binding filter 'child_filter' has valid structure. if name is None: - _err(f"'include:' element in {binding_path} " - "should have a 'name' key") + _err( + f"'include:' element in {binding_path} " "should have a 'name' key" + ) if allowlist is not None and blocklist is not None: - _err(f"'include:' of file '{name}' in {binding_path} " - "should not specify both 'property-allowlist:' " - "and 'property-blocklist:'") + _err( + f"'include:' of file '{name}' in {binding_path} " + "should not specify both 'property-allowlist:' " + "and 'property-blocklist:'" + ) while child_filter is not None: child_copy = deepcopy(child_filter) - child_allowlist: Optional[List[str]] = \ - child_copy.pop('property-allowlist', None) - child_blocklist: Optional[List[str]] = \ - child_copy.pop('property-blocklist', None) - next_child_filter: Optional[dict] = \ - child_copy.pop('child-binding', None) + child_allowlist: Optional[List[str]] = child_copy.pop( + "property-allowlist", None + ) + child_blocklist: Optional[List[str]] = child_copy.pop( + "property-blocklist", None + ) + next_child_filter: Optional[dict] = child_copy.pop( + "child-binding", None + ) if child_copy: # We've popped out all the valid keys. - _err(f"'include:' of file '{name}' in {binding_path} " - "should not have these unexpected contents in a " - f"'child-binding': {child_copy}") + _err( + f"'include:' of file '{name}' in {binding_path} " + "should not have these unexpected contents in a " + f"'child-binding': {child_copy}" + ) if child_allowlist is not None and child_blocklist is not None: - _err(f"'include:' of file '{name}' in {binding_path} " - "should not specify both 'property-allowlist:' and " - "'property-blocklist:' in a 'child-binding:'") + _err( + f"'include:' of file '{name}' in {binding_path} " + "should not specify both 'property-allowlist:' and " + "'property-blocklist:' in a 'child-binding:'" + ) child_filter = next_child_filter -def _filter_properties(raw: dict, - allowlist: Optional[List[str]], - blocklist: Optional[List[str]], - child_filter: Optional[dict], - binding_path: Optional[str]) -> None: +def _filter_properties( + raw: dict, + allowlist: Optional[List[str]], + blocklist: Optional[List[str]], + child_filter: Optional[dict], + binding_path: Optional[str], +) -> None: # Destructively modifies 'raw["properties"]' and # 'raw["child-binding"]', if they exist, according to # 'allowlist', 'blocklist', and 'child_filter'. - props = raw.get('properties') + props = raw.get("properties") _filter_properties_helper(props, allowlist, blocklist, binding_path) - child_binding = raw.get('child-binding') + child_binding = raw.get("child-binding") while child_filter is not None and child_binding is not None: - _filter_properties_helper(child_binding.get('properties'), - child_filter.get('property-allowlist'), - child_filter.get('property-blocklist'), - binding_path) - child_filter = child_filter.get('child-binding') - child_binding = child_binding.get('child-binding') - - -def _filter_properties_helper(props: Optional[dict], - allowlist: Optional[List[str]], - blocklist: Optional[List[str]], - binding_path: Optional[str]) -> None: + _filter_properties_helper( + child_binding.get("properties"), + child_filter.get("property-allowlist"), + child_filter.get("property-blocklist"), + binding_path, + ) + child_filter = child_filter.get("child-binding") + child_binding = child_binding.get("child-binding") + + +def _filter_properties_helper( + props: Optional[dict], + allowlist: Optional[List[str]], + blocklist: Optional[List[str]], + binding_path: Optional[str], +) -> None: if props is None or (allowlist is None and blocklist is None): return - _check_prop_filter('property-allowlist', allowlist, binding_path) - _check_prop_filter('property-blocklist', blocklist, binding_path) + _check_prop_filter("property-allowlist", allowlist, binding_path) + _check_prop_filter("property-blocklist", blocklist, binding_path) if allowlist is not None: allowset = set(allowlist) @@ -2619,8 +2866,9 @@ def _filter_properties_helper(props: Optional[dict], del props[prop] -def _check_prop_filter(name: str, value: Optional[List[str]], - binding_path: Optional[str]) -> None: +def _check_prop_filter( + name: str, value: Optional[List[str]], binding_path: Optional[str] +) -> None: # Ensure an include: ... property-allowlist or property-blocklist # is a list. @@ -2631,11 +2879,13 @@ def _check_prop_filter(name: str, value: Optional[List[str]], _err(f"'{name}' value {value} in {binding_path} should be a list") -def _merge_props(to_dict: dict, - from_dict: dict, - parent: Optional[str], - binding_path: Optional[str], - check_required: bool = False): +def _merge_props( + to_dict: dict, + from_dict: dict, + parent: Optional[str], + binding_path: Optional[str], + check_required: bool = False, +): # Recursively merges 'from_dict' into 'to_dict', to implement 'include:'. # # If 'from_dict' and 'to_dict' contain a 'required:' key for the same @@ -2655,30 +2905,43 @@ def _merge_props(to_dict: dict, # These are used to generate errors for sketchy property overwrites. for prop in from_dict: - if isinstance(to_dict.get(prop), dict) and \ - isinstance(from_dict[prop], dict): - _merge_props(to_dict[prop], from_dict[prop], prop, binding_path, - check_required) + if isinstance(to_dict.get(prop), dict) and isinstance( + from_dict[prop], dict + ): + _merge_props( + to_dict[prop], + from_dict[prop], + prop, + binding_path, + check_required, + ) elif prop not in to_dict: to_dict[prop] = from_dict[prop] elif _bad_overwrite(to_dict, from_dict, prop, check_required): - _err(f"{binding_path} (in '{parent}'): '{prop}' " - f"from included file overwritten ('{from_dict[prop]}' " - f"replaced with '{to_dict[prop]}')") + _err( + f"{binding_path} (in '{parent}'): '{prop}' " + f"from included file overwritten ('{from_dict[prop]}' " + f"replaced with '{to_dict[prop]}')" + ) elif prop == "required": # Need a separate check here, because this code runs before # Binding._check() - if not (isinstance(from_dict["required"], bool) and - isinstance(to_dict["required"], bool)): - _err(f"malformed 'required:' setting for '{parent}' in " - f"'properties' in {binding_path}, expected true/false") + if not ( + isinstance(from_dict["required"], bool) + and isinstance(to_dict["required"], bool) + ): + _err( + f"malformed 'required:' setting for '{parent}' in " + f"'properties' in {binding_path}, expected true/false" + ) # 'required: true' takes precedence to_dict["required"] = to_dict["required"] or from_dict["required"] -def _bad_overwrite(to_dict: dict, from_dict: dict, prop: str, - check_required: bool) -> bool: +def _bad_overwrite( + to_dict: dict, from_dict: dict, prop: str, check_required: bool +) -> bool: # _merge_props() helper. Returns True in cases where it's bad that # to_dict[prop] takes precedence over from_dict[prop]. @@ -2712,9 +2975,9 @@ def _binding_include(loader, node): _binding_inc_error("unrecognised node type in !include statement") -def _check_prop_by_type(prop_name: str, - options: dict, - binding_path: Optional[str]) -> None: +def _check_prop_by_type( + prop_name: str, options: dict, binding_path: Optional[str] +) -> None: # Binding._check_properties() helper. Checks 'type:', 'default:', # 'const:' and # 'specifier-space:' for the property named 'prop_name' @@ -2723,54 +2986,85 @@ def _check_prop_by_type(prop_name: str, const = options.get("const") if prop_type is None: - _err(f"missing 'type:' for '{prop_name}' in 'properties' in " - f"{binding_path}") + _err( + f"missing 'type:' for '{prop_name}' in 'properties' in " + f"{binding_path}" + ) - ok_types = {"boolean", "int", "array", "uint8-array", "string", - "string-array", "phandle", "phandles", "phandle-array", - "path", "compound"} + ok_types = { + "boolean", + "int", + "array", + "uint8-array", + "string", + "string-array", + "phandle", + "phandles", + "phandle-array", + "path", + "compound", + } if prop_type not in ok_types: - _err(f"'{prop_name}' in 'properties:' in {binding_path} " - f"has unknown type '{prop_type}', expected one of " + - ", ".join(ok_types)) + _err( + f"'{prop_name}' in 'properties:' in {binding_path} " + f"has unknown type '{prop_type}', expected one of " + + ", ".join(ok_types) + ) if "specifier-space" in options and prop_type != "phandle-array": - _err(f"'specifier-space' in 'properties: {prop_name}' " - f"has type '{prop_type}', expected 'phandle-array'") + _err( + f"'specifier-space' in 'properties: {prop_name}' " + f"has type '{prop_type}', expected 'phandle-array'" + ) if prop_type == "phandle-array": if not prop_name.endswith("s") and not "specifier-space" in options: - _err(f"'{prop_name}' in 'properties:' in {binding_path} " - f"has type 'phandle-array' and its name does not end in 's', " - f"but no 'specifier-space' was provided.") + _err( + f"'{prop_name}' in 'properties:' in {binding_path} " + f"has type 'phandle-array' and its name does not end in 's', " + f"but no 'specifier-space' was provided." + ) # If you change const_types, be sure to update the type annotation # for PropertySpec.const. const_types = {"int", "array", "uint8-array", "string", "string-array"} if const and prop_type not in const_types: - _err(f"const in {binding_path} for property '{prop_name}' " - f"has type '{prop_type}', expected one of " + - ", ".join(const_types)) + _err( + f"const in {binding_path} for property '{prop_name}' " + f"has type '{prop_type}', expected one of " + ", ".join(const_types) + ) # Check default if default is None: return - if prop_type in {"boolean", "compound", "phandle", "phandles", - "phandle-array", "path"}: - _err("'default:' can't be combined with " - f"'type: {prop_type}' for '{prop_name}' in " - f"'properties:' in {binding_path}") + if prop_type in { + "boolean", + "compound", + "phandle", + "phandles", + "phandle-array", + "path", + }: + _err( + "'default:' can't be combined with " + f"'type: {prop_type}' for '{prop_name}' in " + f"'properties:' in {binding_path}" + ) def ok_default() -> bool: # Returns True if 'default' is an okay default for the property's type. # If you change this, be sure to update the type annotation for # PropertySpec.default. - if prop_type == "int" and isinstance(default, int) or \ - prop_type == "string" and isinstance(default, str): + if ( + prop_type == "int" + and isinstance(default, int) + or prop_type == "string" + and isinstance(default, str) + ): return True # array, uint8-array, or string-array @@ -2778,21 +3072,25 @@ def ok_default() -> bool: if not isinstance(default, list): return False - if prop_type == "array" and \ - all(isinstance(val, int) for val in default): + if prop_type == "array" and all( + isinstance(val, int) for val in default + ): return True - if prop_type == "uint8-array" and \ - all(isinstance(val, int) and 0 <= val <= 255 for val in default): + if prop_type == "uint8-array" and all( + isinstance(val, int) and 0 <= val <= 255 for val in default + ): return True # string-array return all(isinstance(val, str) for val in default) if not ok_default(): - _err(f"'default: {default}' is invalid for '{prop_name}' " - f"in 'properties:' in {binding_path}, " - f"which has type {prop_type}") + _err( + f"'default: {default}' is invalid for '{prop_name}' " + f"in 'properties:' in {binding_path}, " + f"which has type {prop_type}" + ) def _translate(addr: int, node: dtlib_Node) -> int: @@ -2821,16 +3119,20 @@ def _translate(addr: int, node: dtlib_Node) -> int: # Number of cells for one translation 3-tuple in 'ranges' entry_cells = child_address_cells + parent_address_cells + child_size_cells - for raw_range in _slice(node.parent, "ranges", 4*entry_cells, - f"4*(<#address-cells> (= {child_address_cells}) + " - "<#address-cells for parent> " - f"(= {parent_address_cells}) + " - f"<#size-cells> (= {child_size_cells}))"): - child_addr = to_num(raw_range[:4*child_address_cells]) - raw_range = raw_range[4*child_address_cells:] - - parent_addr = to_num(raw_range[:4*parent_address_cells]) - raw_range = raw_range[4*parent_address_cells:] + for raw_range in _slice( + node.parent, + "ranges", + 4 * entry_cells, + f"4*(<#address-cells> (= {child_address_cells}) + " + "<#address-cells for parent> " + f"(= {parent_address_cells}) + " + f"<#size-cells> (= {child_size_cells}))", + ): + child_addr = to_num(raw_range[: 4 * child_address_cells]) + raw_range = raw_range[4 * child_address_cells :] + + parent_addr = to_num(raw_range[: 4 * parent_address_cells]) + raw_range = raw_range[4 * parent_address_cells :] child_len = to_num(raw_range) @@ -2860,9 +3162,11 @@ def _add_names(node: dtlib_Node, names_ident: str, objs: Any) -> None: if full_names_ident in node.props: names = node.props[full_names_ident].to_strings() if len(names) != len(objs): - _err(f"{full_names_ident} property in {node.path} " - f"in {node.dt.filename} has {len(names)} strings, " - f"expected {len(objs)} strings") + _err( + f"{full_names_ident} property in {node.path} " + f"in {node.dt.filename} has {len(names)} strings, " + f"expected {len(objs)} strings" + ) for obj, name in zip(objs, names): if obj is None: @@ -2886,8 +3190,10 @@ def _interrupt_parent(start_node: dtlib_Node) -> dtlib_Node: return node.props["interrupt-parent"].to_node() node = node.parent - _err(f"{start_node!r} has an 'interrupts' property, but neither the node " - f"nor any of its parents has an 'interrupt-parent' property") + _err( + f"{start_node!r} has an 'interrupts' property, but neither the node " + f"nor any of its parents has an 'interrupt-parent' property" + ) def _interrupts(node: dtlib_Node) -> List[Tuple[dtlib_Node, bytes]]: @@ -2903,8 +3209,10 @@ def _interrupts(node: dtlib_Node) -> List[Tuple[dtlib_Node, bytes]]: ret: List[Tuple[dtlib_Node, bytes]] = [] for entry in _phandle_val_list(prop, "interrupt"): if entry is None: - _err(f"node '{node.path}' interrupts-extended property " - "has an empty element") + _err( + f"node '{node.path}' interrupts-extended property " + "has an empty element" + ) iparent, spec = entry ret.append(_map_interrupt(node, iparent, spec)) return ret @@ -2916,17 +3224,18 @@ def _interrupts(node: dtlib_Node) -> List[Tuple[dtlib_Node, bytes]]: iparent = _interrupt_parent(node) interrupt_cells = _interrupt_cells(iparent) - return [_map_interrupt(node, iparent, raw) - for raw in _slice(node, "interrupts", 4*interrupt_cells, - "4*<#interrupt-cells>")] + return [ + _map_interrupt(node, iparent, raw) + for raw in _slice( + node, "interrupts", 4 * interrupt_cells, "4*<#interrupt-cells>" + ) + ] return [] def _map_interrupt( - child: dtlib_Node, - parent: dtlib_Node, - child_spec: bytes + child: dtlib_Node, parent: dtlib_Node, child_spec: bytes ) -> Tuple[dtlib_Node, bytes]: # Translates an interrupt headed from 'child' to 'parent' with data # 'child_spec' through any 'interrupt-map' properties. Returns a @@ -2942,8 +3251,10 @@ def own_address_cells(node): address_cells = node.props.get("#address-cells") if not address_cells: - _err(f"missing #address-cells on {node!r} " - "(while handling interrupt-map)") + _err( + f"missing #address-cells on {node!r} " + "(while handling interrupt-map)" + ) return address_cells.to_num() def spec_len_fn(node): @@ -2952,18 +3263,20 @@ def spec_len_fn(node): return own_address_cells(node) + _interrupt_cells(node) parent, raw_spec = _map( - "interrupt", child, parent, _raw_unit_addr(child) + child_spec, - spec_len_fn, require_controller=True) + "interrupt", + child, + parent, + _raw_unit_addr(child) + child_spec, + spec_len_fn, + require_controller=True, + ) # Strip the parent unit address part, if any - return (parent, raw_spec[4*own_address_cells(parent):]) + return (parent, raw_spec[4 * own_address_cells(parent) :]) def _map_phandle_array_entry( - child: dtlib_Node, - parent: dtlib_Node, - child_spec: bytes, - basename: str + child: dtlib_Node, parent: dtlib_Node, child_spec: bytes, basename: str ) -> Tuple[dtlib_Node, bytes]: # Returns a (, ) tuple with the final destination after # mapping through any '-map' (e.g. gpio-map) properties. See @@ -2972,22 +3285,30 @@ def _map_phandle_array_entry( def spec_len_fn(node): prop_name = f"#{basename}-cells" if prop_name not in node.props: - _err(f"expected '{prop_name}' property on {node!r} " - f"(referenced by {child!r})") + _err( + f"expected '{prop_name}' property on {node!r} " + f"(referenced by {child!r})" + ) return node.props[prop_name].to_num() # Do not require -controller for anything but interrupts for now - return _map(basename, child, parent, child_spec, spec_len_fn, - require_controller=False) + return _map( + basename, + child, + parent, + child_spec, + spec_len_fn, + require_controller=False, + ) def _map( - prefix: str, - child: dtlib_Node, - parent: dtlib_Node, - child_spec: bytes, - spec_len_fn: Callable[[dtlib_Node], int], - require_controller: bool + prefix: str, + child: dtlib_Node, + parent: dtlib_Node, + child_spec: bytes, + spec_len_fn: Callable[[dtlib_Node], int], + require_controller: bool, ) -> Tuple[dtlib_Node, bytes]: # Common code for mapping through -map properties, e.g. # interrupt-map and gpio-map. @@ -3017,8 +3338,10 @@ def _map( map_prop = parent.props.get(prefix + "-map") if not map_prop: if require_controller and prefix + "-controller" not in parent.props: - _err(f"expected '{prefix}-controller' property on {parent!r} " - f"(referenced by {child!r})") + _err( + f"expected '{prefix}-controller' property on {parent!r} " + f"(referenced by {child!r})" + ) # No mapping return (parent, child_spec) @@ -3029,8 +3352,8 @@ def _map( while raw: if len(raw) < len(child_spec): _err(f"bad value for {map_prop!r}, missing/truncated child data") - child_spec_entry = raw[:len(child_spec)] - raw = raw[len(child_spec):] + child_spec_entry = raw[: len(child_spec)] + raw = raw[len(child_spec) :] if len(raw) < 4: _err(f"bad value for {map_prop!r}, missing/truncated phandle") @@ -3042,7 +3365,7 @@ def _map( if not map_parent: _err(f"bad phandle ({phandle}) in {map_prop!r}") - map_parent_spec_len = 4*spec_len_fn(map_parent) + map_parent_spec_len = 4 * spec_len_fn(map_parent) if len(raw) < map_parent_spec_len: _err(f"bad value for {map_prop!r}, missing/truncated parent data") parent_spec = raw[:map_parent_spec_len] @@ -3052,21 +3375,27 @@ def _map( if child_spec_entry == masked_child_spec: # Handle *-map-pass-thru parent_spec = _pass_thru( - prefix, child, parent, child_spec, parent_spec) + prefix, child, parent, child_spec, parent_spec + ) # Found match. Recursively map and return it. - return _map(prefix, parent, map_parent, parent_spec, spec_len_fn, - require_controller) + return _map( + prefix, + parent, + map_parent, + parent_spec, + spec_len_fn, + require_controller, + ) - _err(f"child specifier for {child!r} ({child_spec!r}) " - f"does not appear in {map_prop!r}") + _err( + f"child specifier for {child!r} ({child_spec!r}) " + f"does not appear in {map_prop!r}" + ) def _mask( - prefix: str, - child: dtlib_Node, - parent: dtlib_Node, - child_spec: bytes + prefix: str, child: dtlib_Node, parent: dtlib_Node, child_spec: bytes ) -> bytes: # Common code for handling -mask properties, e.g. interrupt-mask. # See _map() for the parameters. @@ -3078,18 +3407,20 @@ def _mask( mask = mask_prop.value if len(mask) != len(child_spec): - _err(f"{child!r}: expected '{prefix}-mask' in {parent!r} " - f"to be {len(child_spec)} bytes, is {len(mask)} bytes") + _err( + f"{child!r}: expected '{prefix}-mask' in {parent!r} " + f"to be {len(child_spec)} bytes, is {len(mask)} bytes" + ) return _and(child_spec, mask) def _pass_thru( - prefix: str, - child: dtlib_Node, - parent: dtlib_Node, - child_spec: bytes, - parent_spec: bytes + prefix: str, + child: dtlib_Node, + parent: dtlib_Node, + child_spec: bytes, + parent_spec: bytes, ) -> bytes: # Common code for handling -map-thru properties, e.g. # interrupt-pass-thru. @@ -3106,31 +3437,36 @@ def _pass_thru( pass_thru = pass_thru_prop.value if len(pass_thru) != len(child_spec): - _err(f"{child!r}: expected '{prefix}-map-pass-thru' in {parent!r} " - f"to be {len(child_spec)} bytes, is {len(pass_thru)} bytes") + _err( + f"{child!r}: expected '{prefix}-map-pass-thru' in {parent!r} " + f"to be {len(child_spec)} bytes, is {len(pass_thru)} bytes" + ) - res = _or(_and(child_spec, pass_thru), - _and(parent_spec, _not(pass_thru))) + res = _or(_and(child_spec, pass_thru), _and(parent_spec, _not(pass_thru))) # Truncate to length of parent spec. - return res[-len(parent_spec):] + return res[-len(parent_spec) :] def _raw_unit_addr(node: dtlib_Node) -> bytes: # _map_interrupt() helper. Returns the unit address (derived from 'reg' and # #address-cells) as a raw 'bytes' - if 'reg' not in node.props: - _err(f"{node!r} lacks 'reg' property " - "(needed for 'interrupt-map' unit address lookup)") + if "reg" not in node.props: + _err( + f"{node!r} lacks 'reg' property " + "(needed for 'interrupt-map' unit address lookup)" + ) - addr_len = 4*_address_cells(node) + addr_len = 4 * _address_cells(node) - if len(node.props['reg'].value) < addr_len: - _err(f"{node!r} has too short 'reg' property " - "(while doing 'interrupt-map' unit address lookup)") + if len(node.props["reg"].value) < addr_len: + _err( + f"{node!r} has too short 'reg' property " + "(while doing 'interrupt-map' unit address lookup)" + ) - return node.props['reg'].value[:addr_len] + return node.props["reg"].value[:addr_len] def _and(b1: bytes, b2: bytes) -> bytes: @@ -3139,8 +3475,10 @@ def _and(b1: bytes, b2: bytes) -> bytes: # Pad on the left, to equal length maxlen = max(len(b1), len(b2)) - return bytes(x & y for x, y in zip(b1.rjust(maxlen, b'\xff'), - b2.rjust(maxlen, b'\xff'))) + return bytes( + x & y + for x, y in zip(b1.rjust(maxlen, b"\xff"), b2.rjust(maxlen, b"\xff")) + ) def _or(b1: bytes, b2: bytes) -> bytes: @@ -3149,8 +3487,10 @@ def _or(b1: bytes, b2: bytes) -> bytes: # Pad on the left, to equal length maxlen = max(len(b1), len(b2)) - return bytes(x | y for x, y in zip(b1.rjust(maxlen, b'\x00'), - b2.rjust(maxlen, b'\x00'))) + return bytes( + x | y + for x, y in zip(b1.rjust(maxlen, b"\x00"), b2.rjust(maxlen, b"\x00")) + ) def _not(b: bytes) -> bytes: @@ -3161,8 +3501,7 @@ def _not(b: bytes) -> bytes: def _phandle_val_list( - prop: dtlib_Property, - n_cells_name: str + prop: dtlib_Property, n_cells_name: str ) -> List[Optional[Tuple[dtlib_Node, bytes]]]: # Parses a ' ...' value. The number of # cells that make up each is derived from the node pointed at by @@ -3202,11 +3541,11 @@ def _phandle_val_list( _err(f"{node!r} lacks {full_n_cells_name}") n_cells = node.props[full_n_cells_name].to_num() - if len(raw) < 4*n_cells: + if len(raw) < 4 * n_cells: _err("missing data after phandle in " + repr(prop)) - res.append((node, raw[:4*n_cells])) - raw = raw[4*n_cells:] + res.append((node, raw[: 4 * n_cells])) + raw = raw[4 * n_cells :] return res @@ -3242,10 +3581,9 @@ def _interrupt_cells(node: dtlib_Node) -> int: return node.props["#interrupt-cells"].to_num() -def _slice(node: dtlib_Node, - prop_name: str, - size: int, - size_hint: str) -> List[bytes]: +def _slice( + node: dtlib_Node, prop_name: str, size: int, size_hint: str +) -> List[bytes]: return _slice_helper(node, prop_name, size, size_hint, EDTError) @@ -3268,27 +3606,32 @@ def _check_dt(dt: DT) -> None: _err(str(e)) if status_val not in ok_status: - _err(f"unknown 'status' value \"{status_val}\" in {node.path} " - f"in {node.dt.filename}, expected one of " + - ", ".join(ok_status) + - " (see the devicetree specification)") + _err( + f"unknown 'status' value \"{status_val}\" in {node.path} " + f"in {node.dt.filename}, expected one of " + + ", ".join(ok_status) + + " (see the devicetree specification)" + ) ranges_prop = node.props.get("ranges") if ranges_prop: if ranges_prop.type not in (Type.EMPTY, Type.NUMS): - _err(f"expected 'ranges = < ... >;' in {node.path} in " - f"{node.dt.filename}, not '{ranges_prop}' " - "(see the devicetree specification)") + _err( + f"expected 'ranges = < ... >;' in {node.path} in " + f"{node.dt.filename}, not '{ranges_prop}' " + "(see the devicetree specification)" + ) def _err(msg) -> NoReturn: raise EDTError(msg) + # Logging object _LOG = logging.getLogger(__name__) # Regular expression for non-alphanumeric-or-underscore characters. -_NOT_ALPHANUM_OR_UNDERSCORE = re.compile(r'\W', re.ASCII) +_NOT_ALPHANUM_OR_UNDERSCORE = re.compile(r"\W", re.ASCII) def str_as_token(val: str) -> str: @@ -3297,7 +3640,7 @@ def str_as_token(val: str) -> str: This converts special characters in 'val' to underscores, and returns the result.""" - return re.sub(_NOT_ALPHANUM_OR_UNDERSCORE, '_', val) + return re.sub(_NOT_ALPHANUM_OR_UNDERSCORE, "_", val) # Custom PyYAML binding loader class to avoid modifying yaml.Loader directly, @@ -3332,26 +3675,30 @@ class _BindingLoader(Loader): _STATUS_ENUM: List[str] = "ok okay disabled reserved fail fail-sss".split() + def _raw_default_property_for( - name: str + name: str, ) -> Dict[str, Union[str, bool, List[str]]]: ret: Dict[str, Union[str, bool, List[str]]] = { - 'type': _DEFAULT_PROP_TYPES[name], - 'required': False, + "type": _DEFAULT_PROP_TYPES[name], + "required": False, } - if name == 'status': - ret['enum'] = _STATUS_ENUM + if name == "status": + ret["enum"] = _STATUS_ENUM return ret + _DEFAULT_PROP_BINDING: Binding = Binding( - None, {}, + None, + {}, raw={ - 'properties': { + "properties": { name: _raw_default_property_for(name) for name in _DEFAULT_PROP_TYPES }, }, - require_compatible=False, require_description=False, + require_compatible=False, + require_description=False, ) _DEFAULT_PROP_SPECS: Dict[str, PropertySpec] = {