Skip to content

Commit 5a16b90

Browse files
b0661nashif
authored andcommitted
dts: bindings: scan application dir for bindings
In addtion to zephyr/dts/bindings als scan the dts/bindings directory within the application source directory for bindings. Allows to have application specific bindings and drivers. Signed-off-by: Bobby Noelte <[email protected]>
1 parent 7976d2b commit 5a16b90

File tree

2 files changed

+89
-52
lines changed

2 files changed

+89
-52
lines changed

cmake/dts.cmake

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ set(GENERATED_DTS_BOARD_H ${PROJECT_BINARY_DIR}/include/generated/generated_d
1212
set(GENERATED_DTS_BOARD_CONF ${PROJECT_BINARY_DIR}/include/generated/generated_dts_board.conf)
1313
set_ifndef(DTS_SOURCE ${BOARD_ROOT}/boards/${ARCH}/${BOARD_FAMILY}/${BOARD}.dts)
1414
set_ifndef(DTS_COMMON_OVERLAYS ${ZEPHYR_BASE}/dts/common/common.dts)
15+
set_ifndef(DTS_APP_BINDINGS ${APPLICATION_SOURCE_DIR}/dts/bindings)
1516

1617
message(STATUS "Generating zephyr/include/generated/generated_dts_board.h")
1718

@@ -102,9 +103,13 @@ if(CONFIG_HAS_DTS)
102103
set(DTS_FIXUPS --fixup ${DTS_FIXUPS})
103104
endif()
104105

106+
if(NOT EXISTS ${DTS_APP_BINDINGS})
107+
set(DTS_APP_BINDINGS)
108+
endif()
109+
105110
set(CMD_EXTRACT_DTS_INCLUDES ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/dts/extract_dts_includes.py
106111
--dts ${BOARD}.dts_compiled
107-
--yaml ${ZEPHYR_BASE}/dts/bindings
112+
--yaml ${ZEPHYR_BASE}/dts/bindings ${DTS_APP_BINDINGS}
108113
${DTS_FIXUPS}
109114
--keyvalue ${GENERATED_DTS_BOARD_CONF}
110115
--include ${GENERATED_DTS_BOARD_H}

scripts/dts/extract_dts_includes.py

Lines changed: 83 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -27,44 +27,102 @@
2727
from extract.pinctrl import pinctrl
2828
from extract.default import default
2929

30-
class Loader(yaml.Loader):
30+
class Bindings(yaml.Loader):
31+
32+
##
33+
# List of all yaml files available for yaml loaders
34+
# of this class. Must be preset before the first
35+
# load operation.
36+
_files = []
37+
38+
##
39+
# Files that are already included.
40+
# Must be reset on the load of every new binding
41+
_included = []
42+
43+
@classmethod
44+
def bindings(cls, compatibles, yaml_dirs):
45+
# find unique set of compatibles across all active nodes
46+
s = set()
47+
for k, v in compatibles.items():
48+
if isinstance(v, list):
49+
for item in v:
50+
s.add(item)
51+
else:
52+
s.add(v)
53+
54+
# scan YAML files and find the ones we are interested in
55+
cls._files = []
56+
for yaml_dir in yaml_dirs:
57+
for root, dirnames, filenames in os.walk(yaml_dir):
58+
for filename in fnmatch.filter(filenames, '*.yaml'):
59+
cls._files.append(os.path.join(root, filename))
60+
61+
yaml_list = {}
62+
file_load_list = set()
63+
for file in cls._files:
64+
for line in open(file, 'r'):
65+
if re.search('^\s+constraint:*', line):
66+
c = line.split(':')[1].strip()
67+
c = c.strip('"')
68+
if c in s:
69+
if file not in file_load_list:
70+
file_load_list.add(file)
71+
with open(file, 'r') as yf:
72+
cls._included = []
73+
yaml_list[c] = yaml.load(yf, cls)
74+
return yaml_list
75+
3176
def __init__(self, stream):
32-
self._root = os.path.realpath(stream.name)
33-
super(Loader, self).__init__(stream)
34-
Loader.add_constructor('!include', Loader.include)
35-
Loader.add_constructor('!import', Loader.include)
77+
filepath = os.path.realpath(stream.name)
78+
if filepath in self._included:
79+
print("Error:: circular inclusion for file name '{}'".
80+
format(stream.name))
81+
raise yaml.constructor.ConstructorError
82+
self._included.append(filepath)
83+
super(Bindings, self).__init__(stream)
84+
Bindings.add_constructor('!include', Bindings._include)
85+
Bindings.add_constructor('!import', Bindings._include)
3686

37-
def include(self, node):
87+
def _include(self, node):
3888
if isinstance(node, yaml.ScalarNode):
39-
return self.extractFile(self.construct_scalar(node))
89+
return self._extract_file(self.construct_scalar(node))
4090

4191
elif isinstance(node, yaml.SequenceNode):
4292
result = []
4393
for filename in self.construct_sequence(node):
44-
result.append(self.extractFile(filename))
94+
result.append(self._extract_file(filename))
4595
return result
4696

4797
elif isinstance(node, yaml.MappingNode):
4898
result = {}
4999
for k, v in self.construct_mapping(node).iteritems():
50-
result[k] = self.extractFile(v)
100+
result[k] = self._extract_file(v)
51101
return result
52102

53103
else:
54104
print("Error:: unrecognised node type in !include statement")
55105
raise yaml.constructor.ConstructorError
56106

57-
def extractFile(self, filename):
58-
filepath = os.path.join(os.path.dirname(self._root), filename)
59-
if not os.path.isfile(filepath):
60-
# we need to look in bindings/* directories
61-
# take path and back up 1 directory and parse in '/bindings/*'
62-
filepath = os.path.dirname(os.path.dirname(self._root))
63-
for root, dirnames, file in os.walk(filepath):
64-
if fnmatch.filter(file, filename):
65-
filepath = os.path.join(root, filename)
66-
with open(filepath, 'r') as f:
67-
return yaml.load(f, Loader)
107+
def _extract_file(self, filename):
108+
filepaths = [filepath for filepath in self._files if filepath.endswith(filename)]
109+
if len(filepaths) == 0:
110+
print("Error:: unknown file name '{}' in !include statement".
111+
format(filename))
112+
raise yaml.constructor.ConstructorError
113+
elif len(filepaths) > 1:
114+
# multiple candidates for filename
115+
files = []
116+
for filepath in filepaths:
117+
if os.path.basename(filename) == os.path.basename(filepath):
118+
files.append(filepath)
119+
if len(files) > 1:
120+
print("Error:: multiple candidates for file name '{}' in !include statement".
121+
format(filename), filepaths)
122+
raise yaml.constructor.ConstructorError
123+
filepaths = files
124+
with open(filepaths[0], 'r') as f:
125+
return yaml.load(f, Bindings)
68126

69127

70128
def extract_reg_prop(node_address, names, def_label, div, post_label):
@@ -663,36 +721,10 @@ def load_and_parse_dts(dts_file):
663721
return dts
664722

665723

666-
def load_yaml_descriptions(dts, yaml_dir):
724+
def load_yaml_descriptions(dts, yaml_dirs):
667725
compatibles = get_all_compatibles(dts['/'], '/', {})
668-
# find unique set of compatibles across all active nodes
669-
s = set()
670-
for k, v in compatibles.items():
671-
if isinstance(v, list):
672-
for item in v:
673-
s.add(item)
674-
else:
675-
s.add(v)
676-
677-
# scan YAML files and find the ones we are interested in
678-
yaml_files = []
679-
for root, dirnames, filenames in os.walk(yaml_dir):
680-
for filename in fnmatch.filter(filenames, '*.yaml'):
681-
yaml_files.append(os.path.join(root, filename))
682-
683-
yaml_list = {}
684-
file_load_list = set()
685-
for file in yaml_files:
686-
for line in open(file, 'r'):
687-
if re.search('^\s+constraint:*', line):
688-
c = line.split(':')[1].strip()
689-
c = c.strip('"')
690-
if c in s:
691-
if file not in file_load_list:
692-
file_load_list.add(file)
693-
with open(file, 'r') as yf:
694-
yaml_list[c] = yaml.load(yf, Loader)
695726

727+
yaml_list = Bindings.bindings(compatibles, yaml_dirs)
696728
if yaml_list == {}:
697729
raise Exception("Missing YAML information. Check YAML sources")
698730

@@ -735,8 +767,8 @@ def parse_arguments():
735767
parser = argparse.ArgumentParser(description=__doc__, formatter_class=rdh)
736768

737769
parser.add_argument("-d", "--dts", nargs=1, required=True, help="DTS file")
738-
parser.add_argument("-y", "--yaml", nargs=1, required=True,
739-
help="YAML file")
770+
parser.add_argument("-y", "--yaml", nargs='+', required=True,
771+
help="YAML file directories, we allow multiple")
740772
parser.add_argument("-f", "--fixup", nargs='+',
741773
help="Fixup file(s), we allow multiple")
742774
parser.add_argument("-i", "--include", nargs=1, required=True,
@@ -757,7 +789,7 @@ def main():
757789
get_aliases(dts['/'])
758790
get_chosen(dts['/'])
759791

760-
yaml_list = load_yaml_descriptions(dts, args.yaml[0])
792+
yaml_list = load_yaml_descriptions(dts, args.yaml)
761793

762794
defs = generate_node_definitions(yaml_list)
763795

0 commit comments

Comments
 (0)