summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-01-05 22:34:43 -0500
committerTom Rini <trini@konsulko.com>2021-01-05 22:34:43 -0500
commitb11f634b1c1be6ab419758c6596c673445e5ac70 (patch)
tree2329e1ff53c6c543e01d84b7901c53621ad8b7f9 /tools
parent720620e6916ba40b9a173bb07706d2c73f3c23e7 (diff)
parent970349a96dac3ad46c33851b1a773bfe3f1d4b33 (diff)
downloadu-boot-b11f634b1c1be6ab419758c6596c673445e5ac70.tar.gz
u-boot-b11f634b1c1be6ab419758c6596c673445e5ac70.tar.xz
u-boot-b11f634b1c1be6ab419758c6596c673445e5ac70.zip
Merge tag 'dm-pull-5jan21' of git://git.denx.de/u-boot-dm into next
Driver model: make some udevice fields private Driver model: Rename U_BOOT_DEVICE et al. dtoc: Tidy up and add more tests ns16550 code clean-up x86 and sandbox minor fixes for of-platdata dtoc prepration for adding build-time instantiation
Diffstat (limited to 'tools')
-rw-r--r--tools/concurrencytest/concurrencytest.py4
-rw-r--r--tools/dtoc/dtb_platdata.py518
-rw-r--r--tools/dtoc/dtoc_test_scan_drivers.cxx2
-rw-r--r--tools/dtoc/dtoc_test_simple.dts5
-rwxr-xr-xtools/dtoc/main.py49
-rw-r--r--tools/dtoc/src_scan.py185
-rwxr-xr-xtools/dtoc/test_dtoc.py413
-rw-r--r--tools/dtoc/test_src_scan.py107
-rw-r--r--tools/patman/tools.py8
9 files changed, 779 insertions, 512 deletions
diff --git a/tools/concurrencytest/concurrencytest.py b/tools/concurrencytest/concurrencytest.py
index 418d7eed21..5e88b94f41 100644
--- a/tools/concurrencytest/concurrencytest.py
+++ b/tools/concurrencytest/concurrencytest.py
@@ -68,7 +68,7 @@ def fork_for_tests(concurrency_num=CPU_COUNT):
pid = os.fork()
if pid == 0:
try:
- stream = os.fdopen(c2pwrite, 'wb', 1)
+ stream = os.fdopen(c2pwrite, 'wb')
os.close(c2pread)
# Leave stderr and stdout open so we can see test noise
# Close stdin so that the child goes away if it decides to
@@ -92,7 +92,7 @@ def fork_for_tests(concurrency_num=CPU_COUNT):
os._exit(0)
else:
os.close(c2pwrite)
- stream = os.fdopen(c2pread, 'rb', 1)
+ stream = os.fdopen(c2pread, 'rb')
test = ProtocolTestCase(stream)
result.append(test)
return result
diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index 82671138a9..b7abaed67a 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -15,12 +15,15 @@ See doc/driver-model/of-plat.rst for more informaiton
import collections
import copy
+from enum import IntEnum
import os
import re
import sys
from dtoc import fdt
from dtoc import fdt_util
+from dtoc import src_scan
+from dtoc.src_scan import conv_name_to_c
# When we see these properties we ignore them - i.e. do not create a structure
# member
@@ -49,6 +52,17 @@ TYPE_NAMES = {
STRUCT_PREFIX = 'dtd_'
VAL_PREFIX = 'dtv_'
+class Ftype(IntEnum):
+ SOURCE, HEADER = range(2)
+
+
+# This holds information about each type of output file dtoc can create
+# type: Type of file (Ftype)
+# fname: Filename excluding directory, e.g. 'dt-plat.c'
+# hdr_comment: Comment explaining the purpose of the file
+OutputFile = collections.namedtuple('OutputFile',
+ ['ftype', 'fname', 'method', 'hdr_comment'])
+
# This holds information about a property which includes phandles.
#
# max_args: integer: Maximum number or arguments that any phandle uses (int).
@@ -64,23 +78,6 @@ PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
PhandleLink = collections.namedtuple('PhandleLink', ['var_node', 'dev_name'])
-def conv_name_to_c(name):
- """Convert a device-tree name to a C identifier
-
- This uses multiple replace() calls instead of re.sub() since it is faster
- (400ms for 1m calls versus 1000ms for the 're' version).
-
- Args:
- name (str): Name to convert
- Return:
- str: String containing the C version of this name
- """
- new = name.replace('@', '_at_')
- new = new.replace('-', '_')
- new = new.replace(',', '_')
- new = new.replace('.', '_')
- return new
-
def tab_to(num_tabs, line):
"""Append tabs to a line of text to reach a tab stop.
@@ -112,34 +109,22 @@ def get_value(ftype, value):
str: String representation of the value
"""
if ftype == fdt.Type.INT:
- return '%#x' % fdt_util.fdt32_to_cpu(value)
+ val = '%#x' % fdt_util.fdt32_to_cpu(value)
elif ftype == fdt.Type.BYTE:
char = value[0]
- return '%#x' % (ord(char) if isinstance(char, str) else char)
+ val = '%#x' % (ord(char) if isinstance(char, str) else char)
elif ftype == fdt.Type.STRING:
# Handle evil ACPI backslashes by adding another backslash before them.
# So "\\_SB.GPO0" in the device tree effectively stays like that in C
- return '"%s"' % value.replace('\\', '\\\\')
+ val = '"%s"' % value.replace('\\', '\\\\')
elif ftype == fdt.Type.BOOL:
- return 'true'
+ val = 'true'
else: # ftype == fdt.Type.INT64:
- return '%#x' % value
-
-def get_compat_name(node):
- """Get the node's list of compatible string as a C identifiers
-
- Args:
- node (fdt.Node): Node object to check
- Return:
- List of C identifiers for all the compatible strings
- """
- compat = node.props['compatible'].value
- if not isinstance(compat, list):
- compat = [compat]
- return [conv_name_to_c(c) for c in compat]
+ val = '%#x' % value
+ return val
-class DtbPlatdata(object):
+class DtbPlatdata():
"""Provide a means to convert device tree binary data to platform data
The output of this process is C structures which can be used in space-
@@ -147,83 +132,97 @@ class DtbPlatdata(object):
code is not affordable.
Properties:
+ _scan: Scan object, for scanning and reporting on useful information
+ from the U-Boot source code
_fdt: Fdt object, referencing the device tree
_dtb_fname: Filename of the input device tree binary file
_valid_nodes: A list of Node object with compatible strings. The list
is ordered by conv_name_to_c(node.name)
_include_disabled: true to include nodes marked status = "disabled"
_outfile: The current output file (sys.stdout or a real file)
- _warning_disabled: true to disable warnings about driver names not found
_lines: Stashed list of output lines for outputting in the future
- _drivers: List of valid driver names found in drivers/
- _driver_aliases: Dict that holds aliases for driver names
- key: Driver alias declared with
- U_BOOT_DRIVER_ALIAS(driver_alias, driver_name)
- value: Driver name declared with U_BOOT_DRIVER(driver_name)
- _drivers_additional: List of additional drivers to use during scanning
+ _dirname: Directory to hold output files, or None for none (all files
+ go to stdout)
+ _struct_data (dict): OrderedDict of dtplat structures to output
+ key (str): Node name, as a C identifier
+ value: dict containing structure fields:
+ key (str): Field name
+ value: Prop object with field information
+ _basedir (str): Base directory of source tree
"""
- def __init__(self, dtb_fname, include_disabled, warning_disabled,
- drivers_additional=None):
+ def __init__(self, scan, dtb_fname, include_disabled):
+ self._scan = scan
self._fdt = None
self._dtb_fname = dtb_fname
self._valid_nodes = None
self._include_disabled = include_disabled
self._outfile = None
- self._warning_disabled = warning_disabled
self._lines = []
- self._drivers = []
- self._driver_aliases = {}
- self._drivers_additional = drivers_additional or []
+ self._dirnames = [None] * len(Ftype)
+ self._struct_data = collections.OrderedDict()
+ self._basedir = None
- def get_normalized_compat_name(self, node):
- """Get a node's normalized compat name
+ def setup_output_dirs(self, output_dirs):
+ """Set up the output directories
- Returns a valid driver name by retrieving node's list of compatible
- string as a C identifier and performing a check against _drivers
- and a lookup in driver_aliases printing a warning in case of failure.
+ This should be done before setup_output() is called
Args:
- node: Node object to check
- Return:
- Tuple:
- Driver name associated with the first compatible string
- List of C identifiers for all the other compatible strings
- (possibly empty)
- In case of no match found, the return will be the same as
- get_compat_name()
+ output_dirs (tuple of str):
+ Directory to use for C output files.
+ Use None to write files relative current directory
+ Directory to use for H output files.
+ Defaults to the C output dir
"""
- compat_list_c = get_compat_name(node)
-
- for compat_c in compat_list_c:
- if not compat_c in self._drivers:
- compat_c = self._driver_aliases.get(compat_c)
- if not compat_c:
- continue
-
- aliases_c = compat_list_c
- if compat_c in aliases_c:
- aliases_c.remove(compat_c)
- return compat_c, aliases_c
-
- if not self._warning_disabled:
- print('WARNING: the driver %s was not found in the driver list'
- % (compat_list_c[0]))
-
- return compat_list_c[0], compat_list_c[1:]
-
- def setup_output(self, fname):
+ def process_dir(ftype, dirname):
+ if dirname:
+ os.makedirs(dirname, exist_ok=True)
+ self._dirnames[ftype] = dirname
+
+ if output_dirs:
+ c_dirname = output_dirs[0]
+ h_dirname = output_dirs[1] if len(output_dirs) > 1 else c_dirname
+ process_dir(Ftype.SOURCE, c_dirname)
+ process_dir(Ftype.HEADER, h_dirname)
+
+ def setup_output(self, ftype, fname):
"""Set up the output destination
Once this is done, future calls to self.out() will output to this
- file.
+ file. The file used is as follows:
+
+ self._dirnames[ftype] is None: output to fname, or stdout if None
+ self._dirnames[ftype] is not None: output to fname in that directory
+
+ Calling this function multiple times will close the old file and open
+ the new one. If they are the same file, nothing happens and output will
+ continue to the same file.
Args:
- fname (str): Filename to send output to, or '-' for stdout
+ ftype (str): Type of file to create ('c' or 'h')
+ fname (str): Filename to send output to. If there is a directory in
+ self._dirnames for this file type, it will be put in that
+ directory
"""
- if fname == '-':
- self._outfile = sys.stdout
+ dirname = self._dirnames[ftype]
+ if dirname:
+ pathname = os.path.join(dirname, fname)
+ if self._outfile:
+ self._outfile.close()
+ self._outfile = open(pathname, 'w')
+ elif fname:
+ if not self._outfile:
+ self._outfile = open(fname, 'w')
else:
- self._outfile = open(fname, 'w')
+ self._outfile = sys.stdout
+
+ def finish_output(self):
+ """Finish outputing to a file
+
+ This closes the output file, if one is in use
+ """
+ if self._outfile != sys.stdout:
+ self._outfile.close()
def out(self, line):
"""Output a string to the output file
@@ -251,15 +250,20 @@ class DtbPlatdata(object):
self._lines = []
return lines
- def out_header(self):
- """Output a message indicating that this is an auto-generated file"""
+ def out_header(self, outfile):
+ """Output a message indicating that this is an auto-generated file
+
+ Args:
+ outfile: OutputFile describing the file being generated
+ """
self.out('''/*
* DO NOT MODIFY
*
- * This file was generated by dtoc from a .dtb (device tree binary) file.
+ * %s.
+ * This was generated by dtoc from a .dtb (device tree binary) file.
*/
-''')
+''' % outfile.hdr_comment)
def get_phandle_argc(self, prop, node_name):
"""Check if a node contains phandles
@@ -312,63 +316,6 @@ class DtbPlatdata(object):
return PhandleInfo(max_args, args)
return None
- def scan_driver(self, fname):
- """Scan a driver file to build a list of driver names and aliases
-
- This procedure will populate self._drivers and self._driver_aliases
-
- Args
- fname: Driver filename to scan
- """
- with open(fname, encoding='utf-8') as inf:
- try:
- buff = inf.read()
- except UnicodeDecodeError:
- # This seems to happen on older Python versions
- print("Skipping file '%s' due to unicode error" % fname)
- return
-
- # The following re will search for driver names declared as
- # U_BOOT_DRIVER(driver_name)
- drivers = re.findall('U_BOOT_DRIVER\((.*)\)', buff)
-
- for driver in drivers:
- self._drivers.append(driver)
-
- # The following re will search for driver aliases declared as
- # U_BOOT_DRIVER_ALIAS(alias, driver_name)
- driver_aliases = re.findall(
- 'U_BOOT_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)',
- buff)
-
- for alias in driver_aliases: # pragma: no cover
- if len(alias) != 2:
- continue
- self._driver_aliases[alias[1]] = alias[0]
-
- def scan_drivers(self):
- """Scan the driver folders to build a list of driver names and aliases
-
- This procedure will populate self._drivers and self._driver_aliases
-
- """
- basedir = sys.argv[0].replace('tools/dtoc/dtoc', '')
- if basedir == '':
- basedir = './'
- for (dirpath, _, filenames) in os.walk(basedir):
- for fname in filenames:
- if not fname.endswith('.c'):
- continue
- self.scan_driver(dirpath + '/' + fname)
-
- for fname in self._drivers_additional:
- if not isinstance(fname, str) or len(fname) == 0:
- continue
- if fname[0] == '/':
- self.scan_driver(fname)
- else:
- self.scan_driver(basedir + '/' + fname)
-
def scan_dtb(self):
"""Scan the device tree to obtain a tree of nodes and properties
@@ -383,8 +330,8 @@ class DtbPlatdata(object):
This adds each node to self._valid_nodes.
Args:
- root: Root node for scan
- valid_nodes: List of Node objects to add to
+ root (Node): Root node for scan
+ valid_nodes (list of Node): List of Node objects to add to
"""
for node in root.subnodes:
if 'compatible' in node.props:
@@ -483,16 +430,11 @@ class DtbPlatdata(object):
Once the widest property is determined, all other properties are
updated to match that width.
- Returns:
- dict containing structures:
- key (str): Node name, as a C identifier
- value: dict containing structure fields:
- key (str): Field name
- value: Prop object with field information
+ The results are written to self._struct_data
"""
- structs = collections.OrderedDict()
+ structs = self._struct_data
for node in self._valid_nodes:
- node_name, _ = self.get_normalized_compat_name(node)
+ node_name, _ = self._scan.get_normalized_compat_name(node)
fields = {}
# Get a list of all the valid properties in this node.
@@ -515,14 +457,12 @@ class DtbPlatdata(object):
structs[node_name] = fields
for node in self._valid_nodes:
- node_name, _ = self.get_normalized_compat_name(node)
+ node_name, _ = self._scan.get_normalized_compat_name(node)
struct = structs[node_name]
for name, prop in node.props.items():
if name not in PROP_IGNORE_LIST and name[0] != '#':
prop.Widen(struct[name])
- return structs
-
def scan_phandles(self):
"""Figure out what phandles each node uses
@@ -551,22 +491,14 @@ class DtbPlatdata(object):
pos += 1 + args
- def generate_structs(self, structs):
+ def generate_structs(self):
"""Generate struct defintions for the platform data
This writes out the body of a header file consisting of structure
definitions for node in self._valid_nodes. See the documentation in
doc/driver-model/of-plat.rst for more information.
-
- Args:
- structs: dict containing structures:
- key (str): Node name, as a C identifier
- value: dict containing structure fields:
- key (str): Field name
- value: Prop object with field information
-
"""
- self.out_header()
+ structs = self._struct_data
self.out('#include <stdbool.h>\n')
self.out('#include <linux/libfdt.h>\n')
@@ -591,158 +523,198 @@ class DtbPlatdata(object):
self.out(';\n')
self.out('};\n')
- def output_node(self, node):
- """Output the C code for a node
+ def _output_list(self, node, prop):
+ """Output the C code for a devicetree property that holds a list
Args:
- node (fdt.Node): node to output
+ node (fdt.Node): Node to output
+ prop (fdt.Prop): Prop to output
"""
- def _output_list(node, prop):
- """Output the C code for a devicetree property that holds a list
-
- Args:
- node (fdt.Node): Node to output
- prop (fdt.Prop): Prop to output
- """
- self.buf('{')
- vals = []
- # For phandles, output a reference to the platform data
- # of the target node.
- info = self.get_phandle_argc(prop, node.name)
- if info:
- # Process the list as pairs of (phandle, id)
- pos = 0
- for args in info.args:
- phandle_cell = prop.value[pos]
- phandle = fdt_util.fdt32_to_cpu(phandle_cell)
- target_node = self._fdt.phandle_to_node[phandle]
- arg_values = []
- for i in range(args):
- arg_values.append(
- str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
- pos += 1 + args
- vals.append('\t{%d, {%s}}' % (target_node.idx,
- ', '.join(arg_values)))
- for val in vals:
- self.buf('\n\t\t%s,' % val)
- else:
- for val in prop.value:
- vals.append(get_value(prop.type, val))
+ self.buf('{')
+ vals = []
+ # For phandles, output a reference to the platform data
+ # of the target node.
+ info = self.get_phandle_argc(prop, node.name)
+ if info:
+ # Process the list as pairs of (phandle, id)
+ pos = 0
+ for args in info.args:
+ phandle_cell = prop.value[pos]
+ phandle = fdt_util.fdt32_to_cpu(phandle_cell)
+ target_node = self._fdt.phandle_to_node[phandle]
+ arg_values = []
+ for i in range(args):
+ arg_values.append(
+ str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
+ pos += 1 + args
+ vals.append('\t{%d, {%s}}' % (target_node.idx,
+ ', '.join(arg_values)))
+ for val in vals:
+ self.buf('\n\t\t%s,' % val)
+ else:
+ for val in prop.value:
+ vals.append(get_value(prop.type, val))
- # Put 8 values per line to avoid very long lines.
- for i in range(0, len(vals), 8):
- if i:
- self.buf(',\n\t\t')
- self.buf(', '.join(vals[i:i + 8]))
- self.buf('}')
+ # Put 8 values per line to avoid very long lines.
+ for i in range(0, len(vals), 8):
+ if i:
+ self.buf(',\n\t\t')
+ self.buf(', '.join(vals[i:i + 8]))
+ self.buf('}')
- struct_name, _ = self.get_normalized_compat_name(node)
- var_name = conv_name_to_c(node.name)
- self.buf('/* Node %s index %d */\n' % (node.path, node.idx))
- self.buf('static struct %s%s %s%s = {\n' %
- (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
- for pname in sorted(node.props):
- prop = node.props[pname]
- if pname in PROP_IGNORE_LIST or pname[0] == '#':
- continue
- member_name = conv_name_to_c(prop.name)
- self.buf('\t%s= ' % tab_to(3, '.' + member_name))
+ def _declare_device(self, var_name, struct_name, node_parent):
+ """Add a device declaration to the output
- # Special handling for lists
- if isinstance(prop.value, list):
- _output_list(node, prop)
- else:
- self.buf(get_value(prop.type, prop.value))
- self.buf(',\n')
- self.buf('};\n')
+ This declares a U_BOOT_DRVINFO() for the device being processed
- # Add a device declaration
- self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name)
+ Args:
+ var_name (str): C name for the node
+ struct_name (str): Name for the dt struct associated with the node
+ node_parent (Node): Parent of the node (or None if none)
+ """
+ self.buf('U_BOOT_DRVINFO(%s) = {\n' % var_name)
self.buf('\t.name\t\t= "%s",\n' % struct_name)
self.buf('\t.plat\t= &%s%s,\n' % (VAL_PREFIX, var_name))
self.buf('\t.plat_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
idx = -1
- if node.parent and node.parent in self._valid_nodes:
- idx = node.parent.idx
+ if node_parent and node_parent in self._valid_nodes:
+ idx = node_parent.idx
self.buf('\t.parent_idx\t= %d,\n' % idx)
self.buf('};\n')
self.buf('\n')
+ def _output_prop(self, node, prop):
+ """Output a line containing the value of a struct member
+
+ Args:
+ node (Node): Node being output
+ prop (Prop): Prop object to output
+ """
+ if prop.name in PROP_IGNORE_LIST or prop.name[0] == '#':
+ return
+ member_name = conv_name_to_c(prop.name)
+ self.buf('\t%s= ' % tab_to(3, '.' + member_name))
+
+ # Special handling for lists
+ if isinstance(prop.value, list):
+ self._output_list(node, prop)
+ else:
+ self.buf(get_value(prop.type, prop.value))
+ self.buf(',\n')
+
+ def _output_values(self, var_name, struct_name, node):
+ """Output the definition of a device's struct values
+
+ Args:
+ var_name (str): C name for the node
+ struct_name (str): Name for the dt struct associated with the node
+ node (Node): Node being output
+ """
+ self.buf('static struct %s%s %s%s = {\n' %
+ (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
+ for pname in sorted(node.props):
+ self._output_prop(node, node.props[pname])
+ self.buf('};\n')
+
+ def output_node(self, node):
+ """Output the C code for a node
+
+ Args:
+ node (fdt.Node): node to output
+ """
+ struct_name, _ = self._scan.get_normalized_compat_name(node)
+ var_name = conv_name_to_c(node.name)
+ self.buf('/* Node %s index %d */\n' % (node.path, node.idx))
+
+ self._output_values(var_name, struct_name, node)
+ self._declare_device(var_name, struct_name, node.parent)
+
self.out(''.join(self.get_buf()))
- def generate_tables(self):
+ def generate_plat(self):
"""Generate device defintions for the platform data
This writes out C platform data initialisation data and
- U_BOOT_DEVICE() declarations for each valid node. Where a node has
+ U_BOOT_DRVINFO() declarations for each valid node. Where a node has
multiple compatible strings, a #define is used to make them equivalent.
See the documentation in doc/driver-model/of-plat.rst for more
information.
"""
- self.out_header()
- self.out('/* Allow use of U_BOOT_DEVICE() in this file */\n')
- self.out('#define DT_PLATDATA_C\n')
+ self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
+ self.out('#define DT_PLAT_C\n')
self.out('\n')
self.out('#include <common.h>\n')
self.out('#include <dm.h>\n')
self.out('#include <dt-structs.h>\n')
self.out('\n')
- nodes_to_output = list(self._valid_nodes)
-
- # Keep outputing nodes until there is none left
- while nodes_to_output:
- node = nodes_to_output[0]
- # Output all the node's dependencies first
- for req_node in node.phandles:
- if req_node in nodes_to_output:
- self.output_node(req_node)
- nodes_to_output.remove(req_node)
- self.output_node(node)
- nodes_to_output.remove(node)
- # Define dm_populate_phandle_data() which will add the linking between
- # nodes using DM_GET_DEVICE
- # dtv_dmc_at_xxx.clocks[0].node = DM_GET_DEVICE(clock_controller_at_xxx)
- self.buf('void dm_populate_phandle_data(void) {\n')
- self.buf('}\n')
+ for node in self._valid_nodes:
+ self.output_node(node)
self.out(''.join(self.get_buf()))
-def run_steps(args, dtb_file, include_disabled, output, warning_disabled=False,
- drivers_additional=None):
+
+# Types of output file we understand
+# key: Command used to generate this file
+# value: OutputFile for this command
+OUTPUT_FILES = {
+ 'struct':
+ OutputFile(Ftype.HEADER, 'dt-structs-gen.h',
+ DtbPlatdata.generate_structs,
+ 'Defines the structs used to hold devicetree data'),
+ 'platdata':
+ OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat,
+ 'Declares the U_BOOT_DRIVER() records and platform data'),
+ }
+
+
+def run_steps(args, dtb_file, include_disabled, output, output_dirs,
+ warning_disabled=False, drivers_additional=None, basedir=None):
"""Run all the steps of the dtoc tool
Args:
args (list): List of non-option arguments provided to the problem
dtb_file (str): Filename of dtb file to process
include_disabled (bool): True to include disabled nodes
- output (str): Name of output file
+ output (str): Name of output file (None for stdout)
+ output_dirs (tuple of str):
+ Directory to put C output files
+ Directory to put H output files
warning_disabled (bool): True to avoid showing warnings about missing
drivers
- _drivers_additional (list): List of additional drivers to use during
+ drivers_additional (list): List of additional drivers to use during
scanning
+ basedir (str): Base directory of U-Boot source code. Defaults to the
+ grandparent of this file's directory
Raises:
ValueError: if args has no command, or an unknown command
"""
if not args:
- raise ValueError('Please specify a command: struct, platdata')
+ raise ValueError('Please specify a command: struct, platdata, all')
+ if output and output_dirs and any(output_dirs):
+ raise ValueError('Must specify either output or output_dirs, not both')
- plat = DtbPlatdata(dtb_file, include_disabled, warning_disabled,
- drivers_additional)
- plat.scan_drivers()
+ scan = src_scan.Scanner(basedir, warning_disabled, drivers_additional)
+ plat = DtbPlatdata(scan, dtb_file, include_disabled)
+ scan.scan_drivers()
plat.scan_dtb()
plat.scan_tree()
plat.scan_reg_sizes()
- plat.setup_output(output)
- structs = plat.scan_structs()
+ plat.setup_output_dirs(output_dirs)
+ plat.scan_structs()
plat.scan_phandles()
- for cmd in args[0].split(','):
- if cmd == 'struct':
- plat.generate_structs(structs)
- elif cmd == 'platdata':
- plat.generate_tables()
- else:
- raise ValueError("Unknown command '%s': (use: struct, platdata)" %
- cmd)
+ cmds = args[0].split(',')
+ if 'all' in cmds:
+ cmds = sorted(OUTPUT_FILES.keys())
+ for cmd in cmds:
+ outfile = OUTPUT_FILES.get(cmd)
+ if not outfile:
+ raise ValueError("Unknown command '%s': (use: %s)" %
+ (cmd, ', '.join(sorted(OUTPUT_FILES.keys()))))
+ plat.setup_output(outfile.ftype,
+ outfile.fname if output_dirs else output)
+ plat.out_header(outfile)
+ outfile.method(plat)
+ plat.finish_output()
diff --git a/tools/dtoc/dtoc_test_scan_drivers.cxx b/tools/dtoc/dtoc_test_scan_drivers.cxx
index 557c692ba2..f448767670 100644
--- a/tools/dtoc/dtoc_test_scan_drivers.cxx
+++ b/tools/dtoc/dtoc_test_scan_drivers.cxx
@@ -1 +1 @@
-U_BOOT_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias2)
+DM_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias2)
diff --git a/tools/dtoc/dtoc_test_simple.dts b/tools/dtoc/dtoc_test_simple.dts
index fd168cb593..1c87b89192 100644
--- a/tools/dtoc/dtoc_test_simple.dts
+++ b/tools/dtoc/dtoc_test_simple.dts
@@ -44,11 +44,6 @@
longbytearray = [09 0a 0b 0c 0d 0e 0f 10];
};
- spl-test4 {
- u-boot,dm-pre-reloc;
- compatible = "sandbox,spl-test.2";
- };
-
i2c@0 {
compatible = "sandbox,i2c-test";
u-boot,dm-pre-reloc;
diff --git a/tools/dtoc/main.py b/tools/dtoc/main.py
index b94d9c301f..b0ad0f3952 100755
--- a/tools/dtoc/main.py
+++ b/tools/dtoc/main.py
@@ -13,11 +13,7 @@ having to link against libfdt. By putting the data from the device tree into
C structures, normal C code can be used. This helps to reduce the size of the
compiled program.
-Dtoc produces two output files:
-
- dt-structs.h - contains struct definitions
- dt-platdata.c - contains data from the device tree using the struct
- definitions, as well as U-Boot driver definitions.
+Dtoc produces several output files - see OUTPUT_FILES in dtb_platdata.py
This tool is used in U-Boot to provide device tree data to SPL without
increasing the code size of SPL. This supports the CONFIG_SPL_OF_PLATDATA
@@ -42,37 +38,27 @@ sys.path.insert(0, os.path.join(our_path,
from dtoc import dtb_platdata
from patman import test_util
-def run_tests(args):
+def run_tests(processes, args):
"""Run all the test we have for dtoc
Args:
+ processes: Number of processes to use to run tests (None=same as #CPUs)
args: List of positional args provided to dtoc. This can hold a test
name to execute (as in 'dtoc -t test_empty_file', for example)
"""
- import test_dtoc
+ from dtoc import test_src_scan
+ from dtoc import test_dtoc
result = unittest.TestResult()
sys.argv = [sys.argv[0]]
test_name = args and args[0] or None
- for module in (test_dtoc.TestDtoc,):
- if test_name:
- try:
- suite = unittest.TestLoader().loadTestsFromName(test_name, module)
- except AttributeError:
- continue
- else:
- suite = unittest.TestLoader().loadTestsFromTestCase(module)
- suite.run(result)
-
- print(result)
- for _, err in result.errors:
- print(err)
- for _, err in result.failures:
- print(err)
- if result.errors or result.failures:
- print('dtoc tests FAILED')
- return 1
- return 0
+
+ test_util.RunTestSuites(
+ result, debug=True, verbosity=1, test_preserve_dirs=False,
+ processes=processes, test_name=test_name, toolpath=[],
+ test_class_list=[test_dtoc.TestDtoc,test_src_scan.TestSrcScan])
+
+ return test_util.ReportResult('binman', test_name, result)
def RunTestCoverage():
"""Run the tests and check that we get 100% coverage"""
@@ -87,11 +73,15 @@ if __name__ != '__main__':
parser = OptionParser()
parser.add_option('-B', '--build-dir', type='string', default='b',
help='Directory containing the build output')
+parser.add_option('-c', '--c-output-dir', action='store',
+ help='Select output directory for C files')
+parser.add_option('-C', '--h-output-dir', action='store',
+ help='Select output directory for H files (defaults to --c-output-di)')
parser.add_option('-d', '--dtb-file', action='store',
help='Specify the .dtb input file')
parser.add_option('--include-disabled', action='store_true',
help='Include disabled nodes')
-parser.add_option('-o', '--output', action='store', default='-',
+parser.add_option('-o', '--output', action='store',
help='Select output filename')
parser.add_option('-P', '--processes', type=int,
help='set number of processes to use for running tests')
@@ -103,7 +93,7 @@ parser.add_option('-T', '--test-coverage', action='store_true',
# Run our meagre tests
if options.test:
- ret_code = run_tests(args)
+ ret_code = run_tests(options.processes, args)
sys.exit(ret_code)
elif options.test_coverage:
@@ -111,4 +101,5 @@ elif options.test_coverage:
else:
dtb_platdata.run_steps(args, options.dtb_file, options.include_disabled,
- options.output)
+ options.output,
+ [options.c_output_dir, options.h_output_dir])
diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
new file mode 100644
index 0000000000..f63c9fc166
--- /dev/null
+++ b/tools/dtoc/src_scan.py
@@ -0,0 +1,185 @@
+#!/usr/bin/python
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2017 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+
+"""Scanning of U-Boot source for drivers and structs
+
+This scans the source tree to find out things about all instances of
+U_BOOT_DRIVER(), UCLASS_DRIVER and all struct declarations in header files.
+
+See doc/driver-model/of-plat.rst for more informaiton
+"""
+
+import os
+import re
+import sys
+
+
+def conv_name_to_c(name):
+ """Convert a device-tree name to a C identifier
+
+ This uses multiple replace() calls instead of re.sub() since it is faster
+ (400ms for 1m calls versus 1000ms for the 're' version).
+
+ Args:
+ name (str): Name to convert
+ Return:
+ str: String containing the C version of this name
+ """
+ new = name.replace('@', '_at_')
+ new = new.replace('-', '_')
+ new = new.replace(',', '_')
+ new = new.replace('.', '_')
+ return new
+
+def get_compat_name(node):
+ """Get the node's list of compatible string as a C identifiers
+
+ Args:
+ node (fdt.Node): Node object to check
+ Return:
+ list of str: List of C identifiers for all the compatible strings
+ """
+ compat = node.props['compatible'].value
+ if not isinstance(compat, list):
+ compat = [compat]
+ return [conv_name_to_c(c) for c in compat]
+
+
+class Driver:
+ """Information about a driver in U-Boot
+
+ Attributes:
+ name: Name of driver. For U_BOOT_DRIVER(x) this is 'x'
+ """
+ def __init__(self, name):
+ self.name = name
+
+ def __eq__(self, other):
+ return self.name == other.name
+
+ def __repr__(self):
+ return "Driver(name='%s')" % self.name
+
+
+class Scanner:
+ """Scanning of the U-Boot source tree
+
+ Properties:
+ _basedir (str): Base directory of U-Boot source code. Defaults to the
+ grandparent of this file's directory
+ _drivers: Dict of valid driver names found in drivers/
+ key: Driver name
+ value: Driver for that driver
+ _driver_aliases: Dict that holds aliases for driver names
+ key: Driver alias declared with
+ DM_DRIVER_ALIAS(driver_alias, driver_name)
+ value: Driver name declared with U_BOOT_DRIVER(driver_name)
+ _warning_disabled: true to disable warnings about driver names not found
+ _drivers_additional (list or str): List of additional drivers to use
+ during scanning
+ """
+ def __init__(self, basedir, warning_disabled, drivers_additional):
+ """Set up a new Scanner
+ """
+ if not basedir:
+ basedir = sys.argv[0].replace('tools/dtoc/dtoc', '')
+ if basedir == '':
+ basedir = './'
+ self._basedir = basedir
+ self._drivers = {}
+ self._driver_aliases = {}
+ self._drivers_additional = drivers_additional or []
+ self._warning_disabled = warning_disabled
+
+ def get_normalized_compat_name(self, node):
+ """Get a node's normalized compat name
+
+ Returns a valid driver name by retrieving node's list of compatible
+ string as a C identifier and performing a check against _drivers
+ and a lookup in driver_aliases printing a warning in case of failure.
+
+ Args:
+ node (Node): Node object to check
+ Return:
+ Tuple:
+ Driver name associated with the first compatible string
+ List of C identifiers for all the other compatible strings
+ (possibly empty)
+ In case of no match found, the return will be the same as
+ get_compat_name()
+ """
+ compat_list_c = get_compat_name(node)
+
+ for compat_c in compat_list_c:
+ if not compat_c in self._drivers.keys():
+ compat_c = self._driver_aliases.get(compat_c)
+ if not compat_c:
+ continue
+
+ aliases_c = compat_list_c
+ if compat_c in aliases_c:
+ aliases_c.remove(compat_c)
+ return compat_c, aliases_c
+
+ if not self._warning_disabled:
+ print('WARNING: the driver %s was not found in the driver list'
+ % (compat_list_c[0]))
+
+ return compat_list_c[0], compat_list_c[1:]
+
+ def scan_driver(self, fname):
+ """Scan a driver file to build a list of driver names and aliases
+
+ This procedure will populate self._drivers and self._driver_aliases
+
+ Args
+ fname: Driver filename to scan
+ """
+ with open(fname, encoding='utf-8') as inf:
+ try:
+ buff = inf.read()
+ except UnicodeDecodeError:
+ # This seems to happen on older Python versions
+ print("Skipping file '%s' due to unicode error" % fname)
+ return
+
+ # The following re will search for driver names declared as
+ # U_BOOT_DRIVER(driver_name)
+ drivers = re.findall(r'U_BOOT_DRIVER\((.*)\)', buff)
+
+ for driver in drivers:
+ self._drivers[driver] = Driver(driver)
+
+ # The following re will search for driver aliases declared as
+ # DM_DRIVER_ALIAS(alias, driver_name)
+ driver_aliases = re.findall(
+ r'DM_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)',
+ buff)
+
+ for alias in driver_aliases: # pragma: no cover
+ if len(alias) != 2:
+ continue
+ self._driver_aliases[alias[1]] = alias[0]
+
+ def scan_drivers(self):
+ """Scan the driver folders to build a list of driver names and aliases
+
+ This procedure will populate self._drivers and self._driver_aliases
+ """
+ for (dirpath, _, filenames) in os.walk(self._basedir):
+ for fname in filenames:
+ if not fname.endswith('.c'):
+ continue
+ self.scan_driver(dirpath + '/' + fname)
+
+ for fname in self._drivers_additional:
+ if not isinstance(fname, str) or len(fname) == 0:
+ continue
+ if fname[0] == '/':
+ self.scan_driver(fname)
+ else:
+ self.scan_driver(self._basedir + '/' + fname)
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index 4913d95021..d961d67b8f 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -10,29 +10,29 @@ tool.
"""
import collections
+import glob
import os
import struct
-import sys
-import tempfile
import unittest
-from dtoc import dtb_platdata
-from dtb_platdata import conv_name_to_c
-from dtb_platdata import get_compat_name
from dtb_platdata import get_value
from dtb_platdata import tab_to
+from dtoc import dtb_platdata
from dtoc import fdt
from dtoc import fdt_util
+from dtoc.src_scan import conv_name_to_c
+from dtoc.src_scan import get_compat_name
from patman import test_util
from patman import tools
-our_path = os.path.dirname(os.path.realpath(__file__))
+OUR_PATH = os.path.dirname(os.path.realpath(__file__))
HEADER = '''/*
* DO NOT MODIFY
*
- * This file was generated by dtoc from a .dtb (device tree binary) file.
+ * Defines the structs used to hold devicetree data.
+ * This was generated by dtoc from a .dtb (device tree binary) file.
*/
#include <stdbool.h>
@@ -41,33 +41,33 @@ HEADER = '''/*
C_HEADER = '''/*
* DO NOT MODIFY
*
- * This file was generated by dtoc from a .dtb (device tree binary) file.
+ * Declares the U_BOOT_DRIVER() records and platform data.
+ * This was generated by dtoc from a .dtb (device tree binary) file.
*/
-/* Allow use of U_BOOT_DEVICE() in this file */
-#define DT_PLATDATA_C
+/* Allow use of U_BOOT_DRVINFO() in this file */
+#define DT_PLAT_C
#include <common.h>
#include <dm.h>
#include <dt-structs.h>
'''
-C_EMPTY_POPULATE_PHANDLE_DATA = '''void dm_populate_phandle_data(void) {
-}
-'''
-
+# This is a test so is allowed to access private things in the module it is
+# testing
+# pylint: disable=W0212
def get_dtb_file(dts_fname, capture_stderr=False):
"""Compile a .dts file to a .dtb
Args:
- dts_fname: Filename of .dts file in the current directory
- capture_stderr: True to capture and discard stderr output
+ dts_fname (str): Filename of .dts file in the current directory
+ capture_stderr (bool): True to capture and discard stderr output
Returns:
- Filename of compiled file in output directory
+ str: Filename of compiled file in output directory
"""
- return fdt_util.EnsureCompiled(os.path.join(our_path, dts_fname),
+ return fdt_util.EnsureCompiled(os.path.join(OUR_PATH, dts_fname),
capture_stderr=capture_stderr)
@@ -80,20 +80,21 @@ class TestDtoc(unittest.TestCase):
@classmethod
def tearDownClass(cls):
- tools._RemoveOutputDir()
+ tools.FinaliseOutputDir()
- def _WritePythonString(self, fname, data):
+ @staticmethod
+ def _write_python_string(fname, data):
"""Write a string with tabs expanded as done in this Python file
Args:
- fname: Filename to write to
- data: Raw string to convert
+ fname (str): Filename to write to
+ data (str): Raw string to convert
"""
data = data.replace('\t', '\\t')
- with open(fname, 'w') as fd:
- fd.write(data)
+ with open(fname, 'w') as fout:
+ fout.write(data)
- def _CheckStrings(self, expected, actual):
+ def _check_strings(self, expected, actual):
"""Check that a string matches its expected value
If the strings do not match, they are written to the /tmp directory in
@@ -101,18 +102,25 @@ class TestDtoc(unittest.TestCase):
easy comparison and update of the tests.
Args:
- expected: Expected string
- actual: Actual string
+ expected (str): Expected string
+ actual (str): Actual string
"""
if expected != actual:
- self._WritePythonString('/tmp/binman.expected', expected)
- self._WritePythonString('/tmp/binman.actual', actual)
+ self._write_python_string('/tmp/binman.expected', expected)
+ self._write_python_string('/tmp/binman.actual', actual)
print('Failures written to /tmp/binman.{expected,actual}')
- self.assertEquals(expected, actual)
+ self.assertEqual(expected, actual)
+ @staticmethod
+ def run_test(args, dtb_file, output):
+ """Run a test using dtoc
- def run_test(self, args, dtb_file, output):
- dtb_platdata.run_steps(args, dtb_file, False, output, True)
+ Args:
+ args (list of str): List of arguments for dtoc
+ dtb_file (str): Filename of .dtb file
+ output (str): Filename of output file
+ """
+ dtb_platdata.run_steps(args, dtb_file, False, output, [], True)
def test_name(self):
"""Test conversion of device tree names to C identifiers"""
@@ -160,7 +168,7 @@ class TestDtoc(unittest.TestCase):
prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1', 'third'])
node = Node({'compatible': prop})
self.assertEqual((['rockchip_rk3399_sdhci_5_1',
- 'arasan_sdhci_5_1', 'third']),
+ 'arasan_sdhci_5_1', 'third']),
get_compat_name(node))
def test_empty_file(self):
@@ -175,17 +183,9 @@ class TestDtoc(unittest.TestCase):
self.run_test(['platdata'], dtb_file, output)
with open(output) as infile:
lines = infile.read().splitlines()
- self.assertEqual(C_HEADER.splitlines() + [''] +
- C_EMPTY_POPULATE_PHANDLE_DATA.splitlines(), lines)
+ self.assertEqual(C_HEADER.splitlines() + [''], lines)
- def test_simple(self):
- """Test output from some simple nodes with various types of data"""
- dtb_file = get_dtb_file('dtoc_test_simple.dts')
- output = tools.GetOutputFilename('output')
- self.run_test(['struct'], dtb_file, output)
- with open(output) as infile:
- data = infile.read()
- self._CheckStrings(HEADER + '''
+ struct_text = HEADER + '''
struct dtd_sandbox_i2c_test {
};
struct dtd_sandbox_pmic_test {
@@ -204,18 +204,13 @@ struct dtd_sandbox_spl_test {
\tconst char *\tstringarray[3];
\tconst char *\tstringval;
};
-struct dtd_sandbox_spl_test_2 {
-};
-''', data)
+'''
- self.run_test(['platdata'], dtb_file, output)
- with open(output) as infile:
- data = infile.read()
- self._CheckStrings(C_HEADER + '''
+ platdata_text = C_HEADER + '''
/* Node /i2c@0 index 0 */
static struct dtd_sandbox_i2c_test dtv_i2c_at_0 = {
};
-U_BOOT_DEVICE(i2c_at_0) = {
+U_BOOT_DRVINFO(i2c_at_0) = {
\t.name\t\t= "sandbox_i2c_test",
\t.plat\t= &dtv_i2c_at_0,
\t.plat_size\t= sizeof(dtv_i2c_at_0),
@@ -227,7 +222,7 @@ static struct dtd_sandbox_pmic_test dtv_pmic_at_9 = {
\t.low_power\t\t= true,
\t.reg\t\t\t= {0x9, 0x0},
};
-U_BOOT_DEVICE(pmic_at_9) = {
+U_BOOT_DRVINFO(pmic_at_9) = {
\t.name\t\t= "sandbox_pmic_test",
\t.plat\t= &dtv_pmic_at_9,
\t.plat_size\t= sizeof(dtv_pmic_at_9),
@@ -247,7 +242,7 @@ static struct dtd_sandbox_spl_test dtv_spl_test = {
\t.stringarray\t\t= {"multi-word", "message", ""},
\t.stringval\t\t= "message",
};
-U_BOOT_DEVICE(spl_test) = {
+U_BOOT_DRVINFO(spl_test) = {
\t.name\t\t= "sandbox_spl_test",
\t.plat\t= &dtv_spl_test,
\t.plat_size\t= sizeof(dtv_spl_test),
@@ -266,7 +261,7 @@ static struct dtd_sandbox_spl_test dtv_spl_test2 = {
\t.stringarray\t\t= {"another", "multi-word", "message"},
\t.stringval\t\t= "message2",
};
-U_BOOT_DEVICE(spl_test2) = {
+U_BOOT_DRVINFO(spl_test2) = {
\t.name\t\t= "sandbox_spl_test",
\t.plat\t= &dtv_spl_test2,
\t.plat_size\t= sizeof(dtv_spl_test2),
@@ -279,24 +274,35 @@ static struct dtd_sandbox_spl_test dtv_spl_test3 = {
\t\t0x0},
\t.stringarray\t\t= {"one", "", ""},
};
-U_BOOT_DEVICE(spl_test3) = {
+U_BOOT_DRVINFO(spl_test3) = {
\t.name\t\t= "sandbox_spl_test",
\t.plat\t= &dtv_spl_test3,
\t.plat_size\t= sizeof(dtv_spl_test3),
\t.parent_idx\t= -1,
};
-/* Node /spl-test4 index 5 */
-static struct dtd_sandbox_spl_test_2 dtv_spl_test4 = {
-};
-U_BOOT_DEVICE(spl_test4) = {
-\t.name\t\t= "sandbox_spl_test_2",
-\t.plat\t= &dtv_spl_test4,
-\t.plat_size\t= sizeof(dtv_spl_test4),
-\t.parent_idx\t= -1,
-};
+'''
-''' + C_EMPTY_POPULATE_PHANDLE_DATA, data)
+ def test_simple(self):
+ """Test output from some simple nodes with various types of data"""
+ dtb_file = get_dtb_file('dtoc_test_simple.dts')
+ output = tools.GetOutputFilename('output')
+ self.run_test(['struct'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+
+ self._check_strings(self.struct_text, data)
+
+ self.run_test(['platdata'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+
+ self._check_strings(self.platdata_text, data)
+
+ # Try the 'all' command
+ self.run_test(['all'], dtb_file, output)
+ data = tools.ReadFile(output, binary=False)
+ self._check_strings(self.platdata_text + self.struct_text, data)
def test_driver_alias(self):
"""Test output from a device tree file with a driver alias"""
@@ -305,7 +311,7 @@ U_BOOT_DEVICE(spl_test4) = {
self.run_test(['struct'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(HEADER + '''
+ self._check_strings(HEADER + '''
struct dtd_sandbox_gpio {
\tconst char *\tgpio_bank_name;
\tbool\t\tgpio_controller;
@@ -316,54 +322,50 @@ struct dtd_sandbox_gpio {
self.run_test(['platdata'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(C_HEADER + '''
+ self._check_strings(C_HEADER + '''
/* Node /gpios@0 index 0 */
static struct dtd_sandbox_gpio dtv_gpios_at_0 = {
\t.gpio_bank_name\t\t= "a",
\t.gpio_controller\t= true,
\t.sandbox_gpio_count\t= 0x14,
};
-U_BOOT_DEVICE(gpios_at_0) = {
+U_BOOT_DRVINFO(gpios_at_0) = {
\t.name\t\t= "sandbox_gpio",
\t.plat\t= &dtv_gpios_at_0,
\t.plat_size\t= sizeof(dtv_gpios_at_0),
\t.parent_idx\t= -1,
};
-void dm_populate_phandle_data(void) {
-}
''', data)
def test_invalid_driver(self):
"""Test output from a device tree file with an invalid driver"""
dtb_file = get_dtb_file('dtoc_test_invalid_driver.dts')
output = tools.GetOutputFilename('output')
- with test_util.capture_sys_output() as (stdout, stderr):
- dtb_platdata.run_steps(['struct'], dtb_file, False, output)
+ with test_util.capture_sys_output() as _:
+ dtb_platdata.run_steps(['struct'], dtb_file, False, output, [])
with open(output) as infile:
data = infile.read()
- self._CheckStrings(HEADER + '''
+ self._check_strings(HEADER + '''
struct dtd_invalid {
};
''', data)
- with test_util.capture_sys_output() as (stdout, stderr):
- dtb_platdata.run_steps(['platdata'], dtb_file, False, output)
+ with test_util.capture_sys_output() as _:
+ dtb_platdata.run_steps(['platdata'], dtb_file, False, output, [])
with open(output) as infile:
data = infile.read()
- self._CheckStrings(C_HEADER + '''
+ self._check_strings(C_HEADER + '''
/* Node /spl-test index 0 */
static struct dtd_invalid dtv_spl_test = {
};
-U_BOOT_DEVICE(spl_test) = {
+U_BOOT_DRVINFO(spl_test) = {
\t.name\t\t= "invalid",
\t.plat\t= &dtv_spl_test,
\t.plat_size\t= sizeof(dtv_spl_test),
\t.parent_idx\t= -1,
};
-void dm_populate_phandle_data(void) {
-}
''', data)
def test_phandle(self):
@@ -373,7 +375,7 @@ void dm_populate_phandle_data(void) {
self.run_test(['struct'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(HEADER + '''
+ self._check_strings(HEADER + '''
struct dtd_source {
\tstruct phandle_2_arg clocks[4];
};
@@ -385,12 +387,12 @@ struct dtd_target {
self.run_test(['platdata'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(C_HEADER + '''
+ self._check_strings(C_HEADER + '''
/* Node /phandle2-target index 0 */
static struct dtd_target dtv_phandle2_target = {
\t.intval\t\t\t= 0x1,
};
-U_BOOT_DEVICE(phandle2_target) = {
+U_BOOT_DRVINFO(phandle2_target) = {
\t.name\t\t= "target",
\t.plat\t= &dtv_phandle2_target,
\t.plat_size\t= sizeof(dtv_phandle2_target),
@@ -401,24 +403,13 @@ U_BOOT_DEVICE(phandle2_target) = {
static struct dtd_target dtv_phandle3_target = {
\t.intval\t\t\t= 0x2,
};
-U_BOOT_DEVICE(phandle3_target) = {
+U_BOOT_DRVINFO(phandle3_target) = {
\t.name\t\t= "target",
\t.plat\t= &dtv_phandle3_target,
\t.plat_size\t= sizeof(dtv_phandle3_target),
\t.parent_idx\t= -1,
};
-/* Node /phandle-target index 4 */
-static struct dtd_target dtv_phandle_target = {
-\t.intval\t\t\t= 0x0,
-};
-U_BOOT_DEVICE(phandle_target) = {
-\t.name\t\t= "target",
-\t.plat\t= &dtv_phandle_target,
-\t.plat_size\t= sizeof(dtv_phandle_target),
-\t.parent_idx\t= -1,
-};
-
/* Node /phandle-source index 2 */
static struct dtd_source dtv_phandle_source = {
\t.clocks\t\t\t= {
@@ -427,7 +418,7 @@ static struct dtd_source dtv_phandle_source = {
\t\t\t{1, {12, 13}},
\t\t\t{4, {}},},
};
-U_BOOT_DEVICE(phandle_source) = {
+U_BOOT_DRVINFO(phandle_source) = {
\t.name\t\t= "source",
\t.plat\t= &dtv_phandle_source,
\t.plat_size\t= sizeof(dtv_phandle_source),
@@ -439,15 +430,24 @@ static struct dtd_source dtv_phandle_source2 = {
\t.clocks\t\t\t= {
\t\t\t{4, {}},},
};
-U_BOOT_DEVICE(phandle_source2) = {
+U_BOOT_DRVINFO(phandle_source2) = {
\t.name\t\t= "source",
\t.plat\t= &dtv_phandle_source2,
\t.plat_size\t= sizeof(dtv_phandle_source2),
\t.parent_idx\t= -1,
};
-void dm_populate_phandle_data(void) {
-}
+/* Node /phandle-target index 4 */
+static struct dtd_target dtv_phandle_target = {
+\t.intval\t\t\t= 0x0,
+};
+U_BOOT_DRVINFO(phandle_target) = {
+\t.name\t\t= "target",
+\t.plat\t= &dtv_phandle_target,
+\t.plat_size\t= sizeof(dtv_phandle_target),
+\t.parent_idx\t= -1,
+};
+
''', data)
def test_phandle_single(self):
@@ -457,7 +457,7 @@ void dm_populate_phandle_data(void) {
self.run_test(['struct'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(HEADER + '''
+ self._check_strings(HEADER + '''
struct dtd_source {
\tstruct phandle_0_arg clocks[1];
};
@@ -473,46 +473,44 @@ struct dtd_target {
self.run_test(['platdata'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(C_HEADER + '''
-/* Node /phandle-target index 1 */
-static struct dtd_target dtv_phandle_target = {
-};
-U_BOOT_DEVICE(phandle_target) = {
-\t.name\t\t= "target",
-\t.plat\t= &dtv_phandle_target,
-\t.plat_size\t= sizeof(dtv_phandle_target),
-\t.parent_idx\t= -1,
-};
-
+ self._check_strings(C_HEADER + '''
/* Node /phandle-source2 index 0 */
static struct dtd_source dtv_phandle_source2 = {
\t.clocks\t\t\t= {
\t\t\t{1, {}},},
};
-U_BOOT_DEVICE(phandle_source2) = {
+U_BOOT_DRVINFO(phandle_source2) = {
\t.name\t\t= "source",
\t.plat\t= &dtv_phandle_source2,
\t.plat_size\t= sizeof(dtv_phandle_source2),
\t.parent_idx\t= -1,
};
-void dm_populate_phandle_data(void) {
-}
+/* Node /phandle-target index 1 */
+static struct dtd_target dtv_phandle_target = {
+};
+U_BOOT_DRVINFO(phandle_target) = {
+\t.name\t\t= "target",
+\t.plat\t= &dtv_phandle_target,
+\t.plat_size\t= sizeof(dtv_phandle_target),
+\t.parent_idx\t= -1,
+};
+
''', data)
def test_phandle_cd_gpio(self):
"""Test that phandle targets are generated when unsing cd-gpios"""
dtb_file = get_dtb_file('dtoc_test_phandle_cd_gpios.dts')
output = tools.GetOutputFilename('output')
- dtb_platdata.run_steps(['platdata'], dtb_file, False, output, True)
+ dtb_platdata.run_steps(['platdata'], dtb_file, False, output, [], True)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(C_HEADER + '''
+ self._check_strings(C_HEADER + '''
/* Node /phandle2-target index 0 */
static struct dtd_target dtv_phandle2_target = {
\t.intval\t\t\t= 0x1,
};
-U_BOOT_DEVICE(phandle2_target) = {
+U_BOOT_DRVINFO(phandle2_target) = {
\t.name\t\t= "target",
\t.plat\t= &dtv_phandle2_target,
\t.plat_size\t= sizeof(dtv_phandle2_target),
@@ -523,24 +521,13 @@ U_BOOT_DEVICE(phandle2_target) = {
static struct dtd_target dtv_phandle3_target = {
\t.intval\t\t\t= 0x2,
};
-U_BOOT_DEVICE(phandle3_target) = {
+U_BOOT_DRVINFO(phandle3_target) = {
\t.name\t\t= "target",
\t.plat\t= &dtv_phandle3_target,
\t.plat_size\t= sizeof(dtv_phandle3_target),
\t.parent_idx\t= -1,
};
-/* Node /phandle-target index 4 */
-static struct dtd_target dtv_phandle_target = {
-\t.intval\t\t\t= 0x0,
-};
-U_BOOT_DEVICE(phandle_target) = {
-\t.name\t\t= "target",
-\t.plat\t= &dtv_phandle_target,
-\t.plat_size\t= sizeof(dtv_phandle_target),
-\t.parent_idx\t= -1,
-};
-
/* Node /phandle-source index 2 */
static struct dtd_source dtv_phandle_source = {
\t.cd_gpios\t\t= {
@@ -549,7 +536,7 @@ static struct dtd_source dtv_phandle_source = {
\t\t\t{1, {12, 13}},
\t\t\t{4, {}},},
};
-U_BOOT_DEVICE(phandle_source) = {
+U_BOOT_DRVINFO(phandle_source) = {
\t.name\t\t= "source",
\t.plat\t= &dtv_phandle_source,
\t.plat_size\t= sizeof(dtv_phandle_source),
@@ -561,15 +548,24 @@ static struct dtd_source dtv_phandle_source2 = {
\t.cd_gpios\t\t= {
\t\t\t{4, {}},},
};
-U_BOOT_DEVICE(phandle_source2) = {
+U_BOOT_DRVINFO(phandle_source2) = {
\t.name\t\t= "source",
\t.plat\t= &dtv_phandle_source2,
\t.plat_size\t= sizeof(dtv_phandle_source2),
\t.parent_idx\t= -1,
};
-void dm_populate_phandle_data(void) {
-}
+/* Node /phandle-target index 4 */
+static struct dtd_target dtv_phandle_target = {
+\t.intval\t\t\t= 0x0,
+};
+U_BOOT_DRVINFO(phandle_target) = {
+\t.name\t\t= "target",
+\t.plat\t= &dtv_phandle_target,
+\t.plat_size\t= sizeof(dtv_phandle_target),
+\t.parent_idx\t= -1,
+};
+
''', data)
def test_phandle_bad(self):
@@ -577,20 +573,20 @@ void dm_populate_phandle_data(void) {
dtb_file = get_dtb_file('dtoc_test_phandle_bad.dts',
capture_stderr=True)
output = tools.GetOutputFilename('output')
- with self.assertRaises(ValueError) as e:
+ with self.assertRaises(ValueError) as exc:
self.run_test(['struct'], dtb_file, output)
self.assertIn("Cannot parse 'clocks' in node 'phandle-source'",
- str(e.exception))
+ str(exc.exception))
def test_phandle_bad2(self):
"""Test a phandle target missing its #*-cells property"""
dtb_file = get_dtb_file('dtoc_test_phandle_bad2.dts',
capture_stderr=True)
output = tools.GetOutputFilename('output')
- with self.assertRaises(ValueError) as e:
+ with self.assertRaises(ValueError) as exc:
self.run_test(['struct'], dtb_file, output)
self.assertIn("Node 'phandle-target' has no cells property",
- str(e.exception))
+ str(exc.exception))
def test_addresses64(self):
"""Test output from a node with a 'reg' property with na=2, ns=2"""
@@ -599,7 +595,7 @@ void dm_populate_phandle_data(void) {
self.run_test(['struct'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(HEADER + '''
+ self._check_strings(HEADER + '''
struct dtd_test1 {
\tfdt64_t\t\treg[2];
};
@@ -614,12 +610,12 @@ struct dtd_test3 {
self.run_test(['platdata'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(C_HEADER + '''
+ self._check_strings(C_HEADER + '''
/* Node /test1 index 0 */
static struct dtd_test1 dtv_test1 = {
\t.reg\t\t\t= {0x1234, 0x5678},
};
-U_BOOT_DEVICE(test1) = {
+U_BOOT_DRVINFO(test1) = {
\t.name\t\t= "test1",
\t.plat\t= &dtv_test1,
\t.plat_size\t= sizeof(dtv_test1),
@@ -630,7 +626,7 @@ U_BOOT_DEVICE(test1) = {
static struct dtd_test2 dtv_test2 = {
\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654},
};
-U_BOOT_DEVICE(test2) = {
+U_BOOT_DRVINFO(test2) = {
\t.name\t\t= "test2",
\t.plat\t= &dtv_test2,
\t.plat_size\t= sizeof(dtv_test2),
@@ -641,14 +637,14 @@ U_BOOT_DEVICE(test2) = {
static struct dtd_test3 dtv_test3 = {
\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654, 0x2, 0x3},
};
-U_BOOT_DEVICE(test3) = {
+U_BOOT_DRVINFO(test3) = {
\t.name\t\t= "test3",
\t.plat\t= &dtv_test3,
\t.plat_size\t= sizeof(dtv_test3),
\t.parent_idx\t= -1,
};
-''' + C_EMPTY_POPULATE_PHANDLE_DATA, data)
+''', data)
def test_addresses32(self):
"""Test output from a node with a 'reg' property with na=1, ns=1"""
@@ -657,7 +653,7 @@ U_BOOT_DEVICE(test3) = {
self.run_test(['struct'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(HEADER + '''
+ self._check_strings(HEADER + '''
struct dtd_test1 {
\tfdt32_t\t\treg[2];
};
@@ -669,12 +665,12 @@ struct dtd_test2 {
self.run_test(['platdata'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(C_HEADER + '''
+ self._check_strings(C_HEADER + '''
/* Node /test1 index 0 */
static struct dtd_test1 dtv_test1 = {
\t.reg\t\t\t= {0x1234, 0x5678},
};
-U_BOOT_DEVICE(test1) = {
+U_BOOT_DRVINFO(test1) = {
\t.name\t\t= "test1",
\t.plat\t= &dtv_test1,
\t.plat_size\t= sizeof(dtv_test1),
@@ -685,14 +681,14 @@ U_BOOT_DEVICE(test1) = {
static struct dtd_test2 dtv_test2 = {
\t.reg\t\t\t= {0x12345678, 0x98765432, 0x2, 0x3},
};
-U_BOOT_DEVICE(test2) = {
+U_BOOT_DRVINFO(test2) = {
\t.name\t\t= "test2",
\t.plat\t= &dtv_test2,
\t.plat_size\t= sizeof(dtv_test2),
\t.parent_idx\t= -1,
};
-''' + C_EMPTY_POPULATE_PHANDLE_DATA, data)
+''', data)
def test_addresses64_32(self):
"""Test output from a node with a 'reg' property with na=2, ns=1"""
@@ -701,7 +697,7 @@ U_BOOT_DEVICE(test2) = {
self.run_test(['struct'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(HEADER + '''
+ self._check_strings(HEADER + '''
struct dtd_test1 {
\tfdt64_t\t\treg[2];
};
@@ -716,12 +712,12 @@ struct dtd_test3 {
self.run_test(['platdata'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(C_HEADER + '''
+ self._check_strings(C_HEADER + '''
/* Node /test1 index 0 */
static struct dtd_test1 dtv_test1 = {
\t.reg\t\t\t= {0x123400000000, 0x5678},
};
-U_BOOT_DEVICE(test1) = {
+U_BOOT_DRVINFO(test1) = {
\t.name\t\t= "test1",
\t.plat\t= &dtv_test1,
\t.plat_size\t= sizeof(dtv_test1),
@@ -732,7 +728,7 @@ U_BOOT_DEVICE(test1) = {
static struct dtd_test2 dtv_test2 = {
\t.reg\t\t\t= {0x1234567890123456, 0x98765432},
};
-U_BOOT_DEVICE(test2) = {
+U_BOOT_DRVINFO(test2) = {
\t.name\t\t= "test2",
\t.plat\t= &dtv_test2,
\t.plat_size\t= sizeof(dtv_test2),
@@ -743,14 +739,14 @@ U_BOOT_DEVICE(test2) = {
static struct dtd_test3 dtv_test3 = {
\t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3},
};
-U_BOOT_DEVICE(test3) = {
+U_BOOT_DRVINFO(test3) = {
\t.name\t\t= "test3",
\t.plat\t= &dtv_test3,
\t.plat_size\t= sizeof(dtv_test3),
\t.parent_idx\t= -1,
};
-''' + C_EMPTY_POPULATE_PHANDLE_DATA, data)
+''', data)
def test_addresses32_64(self):
"""Test output from a node with a 'reg' property with na=1, ns=2"""
@@ -759,7 +755,7 @@ U_BOOT_DEVICE(test3) = {
self.run_test(['struct'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(HEADER + '''
+ self._check_strings(HEADER + '''
struct dtd_test1 {
\tfdt64_t\t\treg[2];
};
@@ -774,12 +770,12 @@ struct dtd_test3 {
self.run_test(['platdata'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(C_HEADER + '''
+ self._check_strings(C_HEADER + '''
/* Node /test1 index 0 */
static struct dtd_test1 dtv_test1 = {
\t.reg\t\t\t= {0x1234, 0x567800000000},
};
-U_BOOT_DEVICE(test1) = {
+U_BOOT_DRVINFO(test1) = {
\t.name\t\t= "test1",
\t.plat\t= &dtv_test1,
\t.plat_size\t= sizeof(dtv_test1),
@@ -790,7 +786,7 @@ U_BOOT_DEVICE(test1) = {
static struct dtd_test2 dtv_test2 = {
\t.reg\t\t\t= {0x12345678, 0x9876543210987654},
};
-U_BOOT_DEVICE(test2) = {
+U_BOOT_DRVINFO(test2) = {
\t.name\t\t= "test2",
\t.plat\t= &dtv_test2,
\t.plat_size\t= sizeof(dtv_test2),
@@ -801,34 +797,35 @@ U_BOOT_DEVICE(test2) = {
static struct dtd_test3 dtv_test3 = {
\t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3},
};
-U_BOOT_DEVICE(test3) = {
+U_BOOT_DRVINFO(test3) = {
\t.name\t\t= "test3",
\t.plat\t= &dtv_test3,
\t.plat_size\t= sizeof(dtv_test3),
\t.parent_idx\t= -1,
};
-''' + C_EMPTY_POPULATE_PHANDLE_DATA, data)
+''', data)
def test_bad_reg(self):
"""Test that a reg property with an invalid type generates an error"""
# Capture stderr since dtc will emit warnings for this file
dtb_file = get_dtb_file('dtoc_test_bad_reg.dts', capture_stderr=True)
output = tools.GetOutputFilename('output')
- with self.assertRaises(ValueError) as e:
+ with self.assertRaises(ValueError) as exc:
self.run_test(['struct'], dtb_file, output)
self.assertIn("Node 'spl-test' reg property is not an int",
- str(e.exception))
+ str(exc.exception))
def test_bad_reg2(self):
"""Test that a reg property with an invalid cell count is detected"""
# Capture stderr since dtc will emit warnings for this file
dtb_file = get_dtb_file('dtoc_test_bad_reg2.dts', capture_stderr=True)
output = tools.GetOutputFilename('output')
- with self.assertRaises(ValueError) as e:
+ with self.assertRaises(ValueError) as exc:
self.run_test(['struct'], dtb_file, output)
- self.assertIn("Node 'spl-test' reg property has 3 cells which is not a multiple of na + ns = 1 + 1)",
- str(e.exception))
+ self.assertIn(
+ "Node 'spl-test' reg property has 3 cells which is not a multiple of na + ns = 1 + 1)",
+ str(exc.exception))
def test_add_prop(self):
"""Test that a subequent node can add a new property to a struct"""
@@ -837,7 +834,7 @@ U_BOOT_DEVICE(test3) = {
self.run_test(['struct'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(HEADER + '''
+ self._check_strings(HEADER + '''
struct dtd_sandbox_spl_test {
\tfdt32_t\t\tintarray;
\tfdt32_t\t\tintval;
@@ -847,12 +844,12 @@ struct dtd_sandbox_spl_test {
self.run_test(['platdata'], dtb_file, output)
with open(output) as infile:
data = infile.read()
- self._CheckStrings(C_HEADER + '''
+ self._check_strings(C_HEADER + '''
/* Node /spl-test index 0 */
static struct dtd_sandbox_spl_test dtv_spl_test = {
\t.intval\t\t\t= 0x1,
};
-U_BOOT_DEVICE(spl_test) = {
+U_BOOT_DRVINFO(spl_test) = {
\t.name\t\t= "sandbox_spl_test",
\t.plat\t= &dtv_spl_test,
\t.plat_size\t= sizeof(dtv_spl_test),
@@ -863,58 +860,70 @@ U_BOOT_DEVICE(spl_test) = {
static struct dtd_sandbox_spl_test dtv_spl_test2 = {
\t.intarray\t\t= 0x5,
};
-U_BOOT_DEVICE(spl_test2) = {
+U_BOOT_DRVINFO(spl_test2) = {
\t.name\t\t= "sandbox_spl_test",
\t.plat\t= &dtv_spl_test2,
\t.plat_size\t= sizeof(dtv_spl_test2),
\t.parent_idx\t= -1,
};
-''' + C_EMPTY_POPULATE_PHANDLE_DATA, data)
+''', data)
- def testStdout(self):
+ def test_stdout(self):
"""Test output to stdout"""
dtb_file = get_dtb_file('dtoc_test_simple.dts')
- with test_util.capture_sys_output() as (stdout, stderr):
- self.run_test(['struct'], dtb_file, '-')
+ with test_util.capture_sys_output() as (stdout, _):
+ self.run_test(['struct'], dtb_file, None)
+ self._check_strings(self.struct_text, stdout.getvalue())
- def testNoCommand(self):
+ def test_multi_to_file(self):
+ """Test output of multiple pieces to a single file"""
+ dtb_file = get_dtb_file('dtoc_test_simple.dts')
+ output = tools.GetOutputFilename('output')
+ self.run_test(['all'], dtb_file, output)
+ data = tools.ReadFile(output, binary=False)
+ self._check_strings(self.platdata_text + self.struct_text, data)
+
+ def test_no_command(self):
"""Test running dtoc without a command"""
- with self.assertRaises(ValueError) as e:
+ with self.assertRaises(ValueError) as exc:
self.run_test([], '', '')
self.assertIn("Please specify a command: struct, platdata",
- str(e.exception))
+ str(exc.exception))
- def testBadCommand(self):
+ def test_bad_command(self):
"""Test running dtoc with an invalid command"""
dtb_file = get_dtb_file('dtoc_test_simple.dts')
output = tools.GetOutputFilename('output')
- with self.assertRaises(ValueError) as e:
+ with self.assertRaises(ValueError) as exc:
self.run_test(['invalid-cmd'], dtb_file, output)
- self.assertIn("Unknown command 'invalid-cmd': (use: struct, platdata)",
- str(e.exception))
-
- def testScanDrivers(self):
- """Test running dtoc with additional drivers to scan"""
- dtb_file = get_dtb_file('dtoc_test_simple.dts')
- output = tools.GetOutputFilename('output')
- with test_util.capture_sys_output() as (stdout, stderr):
- dtb_platdata.run_steps(['struct'], dtb_file, False, output, True,
- [None, '', 'tools/dtoc/dtoc_test_scan_drivers.cxx'])
-
- def testUnicodeError(self):
- """Test running dtoc with an invalid unicode file
+ self.assertIn("Unknown command 'invalid-cmd': (use: platdata, struct)",
+ str(exc.exception))
+
+ def test_output_conflict(self):
+ """Test a conflict between and output dirs and output file"""
+ with self.assertRaises(ValueError) as exc:
+ dtb_platdata.run_steps(['all'], None, False, 'out', ['cdir'], True)
+ self.assertIn("Must specify either output or output_dirs, not both",
+ str(exc.exception))
+
+ def test_output_dirs(self):
+ """Test outputting files to a directory"""
+ # Remove the directory so that files from other tests are not there
+ tools._RemoveOutputDir()
+ tools.PrepareOutputDir(None)
- To be able to perform this test without adding a weird text file which
- would produce issues when using checkpatch.pl or patman, generate the
- file at runtime and then process it.
- """
+ # This should create the .dts and .dtb in the output directory
dtb_file = get_dtb_file('dtoc_test_simple.dts')
- output = tools.GetOutputFilename('output')
- driver_fn = '/tmp/' + next(tempfile._get_candidate_names())
- with open(driver_fn, 'wb+') as df:
- df.write(b'\x81')
-
- with test_util.capture_sys_output() as (stdout, stderr):
- dtb_platdata.run_steps(['struct'], dtb_file, False, output, True,
- [driver_fn])
+ outdir = tools.GetOutputDir()
+ fnames = glob.glob(outdir + '/*')
+ self.assertEqual(2, len(fnames))
+
+ dtb_platdata.run_steps(['all'], dtb_file, False, None, [outdir], True)
+ fnames = glob.glob(outdir + '/*')
+ self.assertEqual(4, len(fnames))
+
+ leafs = set(os.path.basename(fname) for fname in fnames)
+ self.assertEqual(
+ {'dt-structs-gen.h', 'source.dts', 'dt-plat.c', 'source.dtb'},
+ leafs)
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
new file mode 100644
index 0000000000..7d686530d6
--- /dev/null
+++ b/tools/dtoc/test_src_scan.py
@@ -0,0 +1,107 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2020 Google LLC
+#
+
+"""Tests for the src_scan module
+
+This includes unit tests for scanning of the source code
+"""
+
+import os
+import shutil
+import tempfile
+import unittest
+from unittest import mock
+
+from dtoc import src_scan
+from patman import test_util
+from patman import tools
+
+# This is a test so is allowed to access private things in the module it is
+# testing
+# pylint: disable=W0212
+
+class TestSrcScan(unittest.TestCase):
+ """Tests for src_scan"""
+ @classmethod
+ def setUpClass(cls):
+ tools.PrepareOutputDir(None)
+
+ @classmethod
+ def tearDownClass(cls):
+ tools.FinaliseOutputDir()
+
+ def test_simple(self):
+ """Simple test of scanning drivers"""
+ scan = src_scan.Scanner(None, True, None)
+ scan.scan_drivers()
+ self.assertIn('sandbox_gpio', scan._drivers)
+ self.assertIn('sandbox_gpio_alias', scan._driver_aliases)
+ self.assertEqual('sandbox_gpio',
+ scan._driver_aliases['sandbox_gpio_alias'])
+ self.assertNotIn('sandbox_gpio_alias2', scan._driver_aliases)
+
+ def test_additional(self):
+ """Test with additional drivers to scan"""
+ scan = src_scan.Scanner(
+ None, True, [None, '', 'tools/dtoc/dtoc_test_scan_drivers.cxx'])
+ scan.scan_drivers()
+ self.assertIn('sandbox_gpio_alias2', scan._driver_aliases)
+ self.assertEqual('sandbox_gpio',
+ scan._driver_aliases['sandbox_gpio_alias2'])
+
+ def test_unicode_error(self):
+ """Test running dtoc with an invalid unicode file
+
+ To be able to perform this test without adding a weird text file which
+ would produce issues when using checkpatch.pl or patman, generate the
+ file at runtime and then process it.
+ """
+ driver_fn = '/tmp/' + next(tempfile._get_candidate_names())
+ with open(driver_fn, 'wb+') as fout:
+ fout.write(b'\x81')
+
+ scan = src_scan.Scanner(None, True, [driver_fn])
+ with test_util.capture_sys_output() as (stdout, _):
+ scan.scan_drivers()
+ self.assertRegex(stdout.getvalue(),
+ r"Skipping file '.*' due to unicode error\s*")
+
+ def test_driver(self):
+ """Test the Driver class"""
+ drv1 = src_scan.Driver('fred')
+ drv2 = src_scan.Driver('mary')
+ drv3 = src_scan.Driver('fred')
+ self.assertEqual("Driver(name='fred')", str(drv1))
+ self.assertEqual(drv1, drv3)
+ self.assertNotEqual(drv1, drv2)
+ self.assertNotEqual(drv2, drv3)
+
+ def test_scan_dirs(self):
+ """Test scanning of source directories"""
+ def add_file(fname):
+ pathname = os.path.join(indir, fname)
+ dirname = os.path.dirname(pathname)
+ os.makedirs(dirname, exist_ok=True)
+ tools.WriteFile(pathname, '', binary=False)
+ fname_list.append(pathname)
+
+ try:
+ indir = tempfile.mkdtemp(prefix='dtoc.')
+
+ fname_list = []
+ add_file('fname.c')
+ add_file('dir/fname2.c')
+
+ # Mock out scan_driver and check that it is called with the
+ # expected files
+ with mock.patch.object(src_scan.Scanner, "scan_driver") as mocked:
+ scan = src_scan.Scanner(indir, True, None)
+ scan.scan_drivers()
+ self.assertEqual(2, len(mocked.mock_calls))
+ self.assertEqual(mock.call(fname_list[0]),
+ mocked.mock_calls[0])
+ self.assertEqual(mock.call(fname_list[1]),
+ mocked.mock_calls[1])
+ finally:
+ shutil.rmtree(indir)
diff --git a/tools/patman/tools.py b/tools/patman/tools.py
index fca3d9e604..d8e01a3e60 100644
--- a/tools/patman/tools.py
+++ b/tools/patman/tools.py
@@ -94,6 +94,14 @@ def GetOutputFilename(fname):
"""
return os.path.join(outdir, fname)
+def GetOutputDir():
+ """Return the current output directory
+
+ Returns:
+ str: The output directory
+ """
+ return outdir
+
def _FinaliseForTest():
"""Remove the output directory (for use by tests)"""
global outdir