blob: 2699153016c0308b33469d54823a517be6175dcf [file] [log] [blame]
Simon Glass9065bc92020-12-28 20:35:06 -07001#!/usr/bin/python
2# SPDX-License-Identifier: GPL-2.0+
3#
4# Copyright (C) 2017 Google, Inc
5# Written by Simon Glass <sjg@chromium.org>
6#
7
8"""Scanning of U-Boot source for drivers and structs
9
10This scans the source tree to find out things about all instances of
11U_BOOT_DRIVER(), UCLASS_DRIVER and all struct declarations in header files.
12
13See doc/driver-model/of-plat.rst for more informaiton
14"""
15
16import os
17import re
18import sys
19
20
21def conv_name_to_c(name):
22 """Convert a device-tree name to a C identifier
23
24 This uses multiple replace() calls instead of re.sub() since it is faster
25 (400ms for 1m calls versus 1000ms for the 're' version).
26
27 Args:
28 name (str): Name to convert
29 Return:
30 str: String containing the C version of this name
31 """
32 new = name.replace('@', '_at_')
33 new = new.replace('-', '_')
34 new = new.replace(',', '_')
35 new = new.replace('.', '_')
36 return new
37
38def get_compat_name(node):
39 """Get the node's list of compatible string as a C identifiers
40
41 Args:
42 node (fdt.Node): Node object to check
43 Return:
44 list of str: List of C identifiers for all the compatible strings
45 """
46 compat = node.props['compatible'].value
47 if not isinstance(compat, list):
48 compat = [compat]
49 return [conv_name_to_c(c) for c in compat]
50
51
52class Driver:
53 """Information about a driver in U-Boot
54
55 Attributes:
56 name: Name of driver. For U_BOOT_DRIVER(x) this is 'x'
Simon Glass78933b72021-02-03 06:00:50 -070057 fname: Filename where the driver was found
58 uclass_id: Name of uclass, e.g. 'UCLASS_I2C'
59 compat: Driver data for each compatible string:
60 key: Compatible string, e.g. 'rockchip,rk3288-grf'
61 value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
62 fname: Filename where the driver was found
63 priv (str): struct name of the priv_auto member, e.g. 'serial_priv'
Simon Glass0f3b1412021-02-03 06:00:53 -070064 plat (str): struct name of the plat_auto member, e.g. 'serial_plat'
65 child_priv (str): struct name of the per_child_auto member,
66 e.g. 'pci_child_priv'
67 child_plat (str): struct name of the per_child_plat_auto member,
68 e.g. 'pci_child_plat'
Simon Glasseb3c2492021-02-03 06:01:01 -070069 used (bool): True if the driver is used by the structs being output
Simon Glassf303ee72021-02-03 06:01:02 -070070 phase (str): Which phase of U-Boot to use this driver
Simon Glass9065bc92020-12-28 20:35:06 -070071 """
Simon Glass78933b72021-02-03 06:00:50 -070072 def __init__(self, name, fname):
Simon Glass9065bc92020-12-28 20:35:06 -070073 self.name = name
Simon Glass78933b72021-02-03 06:00:50 -070074 self.fname = fname
75 self.uclass_id = None
76 self.compat = None
77 self.priv = ''
Simon Glass0f3b1412021-02-03 06:00:53 -070078 self.plat = ''
79 self.child_priv = ''
80 self.child_plat = ''
Simon Glasseb3c2492021-02-03 06:01:01 -070081 self.used = False
Simon Glassf303ee72021-02-03 06:01:02 -070082 self.phase = ''
Simon Glass9065bc92020-12-28 20:35:06 -070083
84 def __eq__(self, other):
Simon Glass78933b72021-02-03 06:00:50 -070085 return (self.name == other.name and
86 self.uclass_id == other.uclass_id and
87 self.compat == other.compat and
Simon Glass0f3b1412021-02-03 06:00:53 -070088 self.priv == other.priv and
Simon Glasseb3c2492021-02-03 06:01:01 -070089 self.plat == other.plat and
90 self.used == other.used)
Simon Glass9065bc92020-12-28 20:35:06 -070091
92 def __repr__(self):
Simon Glasseb3c2492021-02-03 06:01:01 -070093 return ("Driver(name='%s', used=%s, uclass_id='%s', compat=%s, priv=%s)" %
94 (self.name, self.used, self.uclass_id, self.compat, self.priv))
Simon Glass9065bc92020-12-28 20:35:06 -070095
96
Simon Glass2e199ab2021-02-03 06:00:54 -070097class UclassDriver:
98 """Holds information about a uclass driver
99
100 Attributes:
101 name: Uclass name, e.g. 'i2c' if the driver is for UCLASS_I2C
102 uclass_id: Uclass ID, e.g. 'UCLASS_I2C'
103 priv: struct name of the private data, e.g. 'i2c_priv'
104 per_dev_priv (str): struct name of the priv_auto member, e.g. 'spi_info'
105 per_dev_plat (str): struct name of the plat_auto member, e.g. 'i2c_chip'
106 per_child_priv (str): struct name of the per_child_auto member,
107 e.g. 'pci_child_priv'
108 per_child_plat (str): struct name of the per_child_plat_auto member,
109 e.g. 'pci_child_plat'
110 """
111 def __init__(self, name):
112 self.name = name
113 self.uclass_id = None
114 self.priv = ''
115 self.per_dev_priv = ''
116 self.per_dev_plat = ''
117 self.per_child_priv = ''
118 self.per_child_plat = ''
119
120 def __eq__(self, other):
121 return (self.name == other.name and
122 self.uclass_id == other.uclass_id and
123 self.priv == other.priv)
124
125 def __repr__(self):
126 return ("UclassDriver(name='%s', uclass_id='%s')" %
127 (self.name, self.uclass_id))
128
129 def __hash__(self):
130 # We can use the uclass ID since it is unique among uclasses
131 return hash(self.uclass_id)
132
133
Simon Glass88bd5382021-02-03 06:00:55 -0700134class Struct:
135 """Holds information about a struct definition
136
137 Attributes:
138 name: Struct name, e.g. 'fred' if the struct is 'struct fred'
139 fname: Filename containing the struct, in a format that C files can
140 include, e.g. 'asm/clk.h'
141 """
142 def __init__(self, name, fname):
143 self.name = name
144 self.fname =fname
145
146 def __repr__(self):
147 return ("Struct(name='%s', fname='%s')" % (self.name, self.fname))
148
149
Simon Glass9065bc92020-12-28 20:35:06 -0700150class Scanner:
151 """Scanning of the U-Boot source tree
152
153 Properties:
154 _basedir (str): Base directory of U-Boot source code. Defaults to the
155 grandparent of this file's directory
156 _drivers: Dict of valid driver names found in drivers/
157 key: Driver name
158 value: Driver for that driver
159 _driver_aliases: Dict that holds aliases for driver names
160 key: Driver alias declared with
161 DM_DRIVER_ALIAS(driver_alias, driver_name)
162 value: Driver name declared with U_BOOT_DRIVER(driver_name)
Simon Glassdf692c32020-12-28 20:35:07 -0700163 _warning_disabled: true to disable warnings about driver names not found
Simon Glass9065bc92020-12-28 20:35:06 -0700164 _drivers_additional (list or str): List of additional drivers to use
165 during scanning
Simon Glass78933b72021-02-03 06:00:50 -0700166 _of_match: Dict holding information about compatible strings
167 key: Name of struct udevice_id variable
168 value: Dict of compatible info in that variable:
169 key: Compatible string, e.g. 'rockchip,rk3288-grf'
170 value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
171 _compat_to_driver: Maps compatible strings to Driver
Simon Glass2e199ab2021-02-03 06:00:54 -0700172 _uclass: Dict of uclass information
173 key: uclass name, e.g. 'UCLASS_I2C'
174 value: UClassDriver
Simon Glass88bd5382021-02-03 06:00:55 -0700175 _structs: Dict of all structs found in U-Boot:
176 key: Name of struct
177 value: Struct object
Simon Glassf303ee72021-02-03 06:01:02 -0700178 _phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
179 or 'tpl'. None if not known
Simon Glass9065bc92020-12-28 20:35:06 -0700180 """
Simon Glassf303ee72021-02-03 06:01:02 -0700181 def __init__(self, basedir, warning_disabled, drivers_additional, phase=''):
Simon Glass9065bc92020-12-28 20:35:06 -0700182 """Set up a new Scanner
183 """
184 if not basedir:
185 basedir = sys.argv[0].replace('tools/dtoc/dtoc', '')
186 if basedir == '':
187 basedir = './'
188 self._basedir = basedir
189 self._drivers = {}
190 self._driver_aliases = {}
191 self._drivers_additional = drivers_additional or []
192 self._warning_disabled = warning_disabled
Simon Glass78933b72021-02-03 06:00:50 -0700193 self._of_match = {}
194 self._compat_to_driver = {}
Simon Glass2e199ab2021-02-03 06:00:54 -0700195 self._uclass = {}
Simon Glass88bd5382021-02-03 06:00:55 -0700196 self._structs = {}
Simon Glassf303ee72021-02-03 06:01:02 -0700197 self._phase = phase
Simon Glass9065bc92020-12-28 20:35:06 -0700198
Simon Glass047a4802021-02-03 06:01:00 -0700199 def get_driver(self, name):
200 """Get a driver given its name
201
202 Args:
203 name (str): Driver name
204
205 Returns:
206 Driver: Driver or None if not found
207 """
208 return self._drivers.get(name)
209
Simon Glass9065bc92020-12-28 20:35:06 -0700210 def get_normalized_compat_name(self, node):
211 """Get a node's normalized compat name
212
213 Returns a valid driver name by retrieving node's list of compatible
214 string as a C identifier and performing a check against _drivers
215 and a lookup in driver_aliases printing a warning in case of failure.
216
217 Args:
218 node (Node): Node object to check
219 Return:
220 Tuple:
221 Driver name associated with the first compatible string
222 List of C identifiers for all the other compatible strings
223 (possibly empty)
224 In case of no match found, the return will be the same as
225 get_compat_name()
226 """
227 compat_list_c = get_compat_name(node)
228
229 for compat_c in compat_list_c:
230 if not compat_c in self._drivers.keys():
231 compat_c = self._driver_aliases.get(compat_c)
232 if not compat_c:
233 continue
234
235 aliases_c = compat_list_c
236 if compat_c in aliases_c:
237 aliases_c.remove(compat_c)
238 return compat_c, aliases_c
239
240 if not self._warning_disabled:
241 print('WARNING: the driver %s was not found in the driver list'
242 % (compat_list_c[0]))
243
244 return compat_list_c[0], compat_list_c[1:]
245
Simon Glass88bd5382021-02-03 06:00:55 -0700246 def _parse_structs(self, fname, buff):
247 """Parse a H file to extract struct definitions contained within
248
249 This parses 'struct xx {' definitions to figure out what structs this
250 header defines.
251
252 Args:
253 buff (str): Contents of file
254 fname (str): Filename (to use when printing errors)
255 """
256 structs = {}
257
258 re_struct = re.compile('^struct ([a-z0-9_]+) {$')
259 re_asm = re.compile('../arch/[a-z0-9]+/include/asm/(.*)')
260 prefix = ''
261 for line in buff.splitlines():
262 # Handle line continuation
263 if prefix:
264 line = prefix + line
265 prefix = ''
266 if line.endswith('\\'):
267 prefix = line[:-1]
268 continue
269
270 m_struct = re_struct.match(line)
271 if m_struct:
272 name = m_struct.group(1)
273 include_dir = os.path.join(self._basedir, 'include')
274 rel_fname = os.path.relpath(fname, include_dir)
275 m_asm = re_asm.match(rel_fname)
276 if m_asm:
277 rel_fname = 'asm/' + m_asm.group(1)
278 structs[name] = Struct(name, rel_fname)
279 self._structs.update(structs)
280
Simon Glass78933b72021-02-03 06:00:50 -0700281 @classmethod
282 def _get_re_for_member(cls, member):
283 """_get_re_for_member: Get a compiled regular expression
284
285 Args:
286 member (str): Struct member name, e.g. 'priv_auto'
287
288 Returns:
289 re.Pattern: Compiled regular expression that parses:
290
291 .member = sizeof(struct fred),
292
293 and returns "fred" as group 1
294 """
295 return re.compile(r'^\s*.%s\s*=\s*sizeof\(struct\s+(.*)\),$' % member)
296
Simon Glass2e199ab2021-02-03 06:00:54 -0700297 def _parse_uclass_driver(self, fname, buff):
298 """Parse a C file to extract uclass driver information contained within
299
300 This parses UCLASS_DRIVER() structs to obtain various pieces of useful
301 information.
302
303 It updates the following member:
304 _uclass: Dict of uclass information
305 key: uclass name, e.g. 'UCLASS_I2C'
306 value: UClassDriver
307
308 Args:
309 fname (str): Filename being parsed (used for warnings)
310 buff (str): Contents of file
311 """
312 uc_drivers = {}
313
314 # Collect the driver name and associated Driver
315 driver = None
316 re_driver = re.compile(r'UCLASS_DRIVER\((.*)\)')
317
318 # Collect the uclass ID, e.g. 'UCLASS_SPI'
319 re_id = re.compile(r'\s*\.id\s*=\s*(UCLASS_[A-Z0-9_]+)')
320
321 # Matches the header/size information for uclass-private data
322 re_priv = self._get_re_for_member('priv_auto')
323
324 # Set up parsing for the auto members
325 re_per_device_priv = self._get_re_for_member('per_device_auto')
326 re_per_device_plat = self._get_re_for_member('per_device_plat_auto')
327 re_per_child_priv = self._get_re_for_member('per_child_auto')
328 re_per_child_plat = self._get_re_for_member('per_child_plat_auto')
329
330 prefix = ''
331 for line in buff.splitlines():
332 # Handle line continuation
333 if prefix:
334 line = prefix + line
335 prefix = ''
336 if line.endswith('\\'):
337 prefix = line[:-1]
338 continue
339
340 driver_match = re_driver.search(line)
341
342 # If we have seen UCLASS_DRIVER()...
343 if driver:
344 m_id = re_id.search(line)
345 m_priv = re_priv.match(line)
346 m_per_dev_priv = re_per_device_priv.match(line)
347 m_per_dev_plat = re_per_device_plat.match(line)
348 m_per_child_priv = re_per_child_priv.match(line)
349 m_per_child_plat = re_per_child_plat.match(line)
350 if m_id:
351 driver.uclass_id = m_id.group(1)
352 elif m_priv:
353 driver.priv = m_priv.group(1)
354 elif m_per_dev_priv:
355 driver.per_dev_priv = m_per_dev_priv.group(1)
356 elif m_per_dev_plat:
357 driver.per_dev_plat = m_per_dev_plat.group(1)
358 elif m_per_child_priv:
359 driver.per_child_priv = m_per_child_priv.group(1)
360 elif m_per_child_plat:
361 driver.per_child_plat = m_per_child_plat.group(1)
362 elif '};' in line:
363 if not driver.uclass_id:
364 raise ValueError(
365 "%s: Cannot parse uclass ID in driver '%s'" %
366 (fname, driver.name))
367 uc_drivers[driver.uclass_id] = driver
368 driver = None
369
370 elif driver_match:
371 driver_name = driver_match.group(1)
372 driver = UclassDriver(driver_name)
373
374 self._uclass.update(uc_drivers)
375
Simon Glass78933b72021-02-03 06:00:50 -0700376 def _parse_driver(self, fname, buff):
377 """Parse a C file to extract driver information contained within
378
379 This parses U_BOOT_DRIVER() structs to obtain various pieces of useful
380 information.
381
382 It updates the following members:
383 _drivers - updated with new Driver records for each driver found
384 in the file
385 _of_match - updated with each compatible string found in the file
386 _compat_to_driver - Maps compatible string to Driver
387
388 Args:
389 fname (str): Filename being parsed (used for warnings)
390 buff (str): Contents of file
391
392 Raises:
393 ValueError: Compatible variable is mentioned in .of_match in
394 U_BOOT_DRIVER() but not found in the file
395 """
396 # Dict holding information about compatible strings collected in this
397 # function so far
398 # key: Name of struct udevice_id variable
399 # value: Dict of compatible info in that variable:
400 # key: Compatible string, e.g. 'rockchip,rk3288-grf'
401 # value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
402 of_match = {}
403
404 # Dict holding driver information collected in this function so far
405 # key: Driver name (C name as in U_BOOT_DRIVER(xxx))
406 # value: Driver
407 drivers = {}
408
409 # Collect the driver info
410 driver = None
411 re_driver = re.compile(r'U_BOOT_DRIVER\((.*)\)')
412
413 # Collect the uclass ID, e.g. 'UCLASS_SPI'
414 re_id = re.compile(r'\s*\.id\s*=\s*(UCLASS_[A-Z0-9_]+)')
415
416 # Collect the compatible string, e.g. 'rockchip,rk3288-grf'
417 compat = None
418 re_compat = re.compile(r'{\s*.compatible\s*=\s*"(.*)"\s*'
419 r'(,\s*.data\s*=\s*(\S*))?\s*},')
420
421 # This is a dict of compatible strings that were found:
422 # key: Compatible string, e.g. 'rockchip,rk3288-grf'
423 # value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
424 compat_dict = {}
425
426 # Holds the var nane of the udevice_id list, e.g.
427 # 'rk3288_syscon_ids_noc' in
428 # static const struct udevice_id rk3288_syscon_ids_noc[] = {
429 ids_name = None
430 re_ids = re.compile(r'struct udevice_id (.*)\[\]\s*=')
431
432 # Matches the references to the udevice_id list
433 re_of_match = re.compile(
434 r'\.of_match\s*=\s*(of_match_ptr\()?([a-z0-9_]+)(\))?,')
435
Simon Glassf303ee72021-02-03 06:01:02 -0700436 re_phase = re.compile('^\s*DM_PHASE\((.*)\).*$')
437
Simon Glass0f3b1412021-02-03 06:00:53 -0700438 # Matches the struct name for priv, plat
Simon Glass78933b72021-02-03 06:00:50 -0700439 re_priv = self._get_re_for_member('priv_auto')
Simon Glass0f3b1412021-02-03 06:00:53 -0700440 re_plat = self._get_re_for_member('plat_auto')
441 re_child_priv = self._get_re_for_member('per_child_auto')
442 re_child_plat = self._get_re_for_member('per_child_plat_auto')
Simon Glass78933b72021-02-03 06:00:50 -0700443
444 prefix = ''
445 for line in buff.splitlines():
446 # Handle line continuation
447 if prefix:
448 line = prefix + line
449 prefix = ''
450 if line.endswith('\\'):
451 prefix = line[:-1]
452 continue
453
454 driver_match = re_driver.search(line)
455
456 # If this line contains U_BOOT_DRIVER()...
457 if driver:
458 m_id = re_id.search(line)
459 m_of_match = re_of_match.search(line)
460 m_priv = re_priv.match(line)
Simon Glass0f3b1412021-02-03 06:00:53 -0700461 m_plat = re_plat.match(line)
462 m_cplat = re_child_plat.match(line)
463 m_cpriv = re_child_priv.match(line)
Simon Glassf303ee72021-02-03 06:01:02 -0700464 m_phase = re_phase.match(line)
Simon Glass78933b72021-02-03 06:00:50 -0700465 if m_priv:
466 driver.priv = m_priv.group(1)
Simon Glass0f3b1412021-02-03 06:00:53 -0700467 elif m_plat:
468 driver.plat = m_plat.group(1)
469 elif m_cplat:
470 driver.child_plat = m_cplat.group(1)
471 elif m_cpriv:
472 driver.child_priv = m_cpriv.group(1)
Simon Glass78933b72021-02-03 06:00:50 -0700473 elif m_id:
474 driver.uclass_id = m_id.group(1)
475 elif m_of_match:
476 compat = m_of_match.group(2)
Simon Glassf303ee72021-02-03 06:01:02 -0700477 elif m_phase:
478 driver.phase = m_phase.group(1)
Simon Glass78933b72021-02-03 06:00:50 -0700479 elif '};' in line:
480 if driver.uclass_id and compat:
481 if compat not in of_match:
482 raise ValueError(
483 "%s: Unknown compatible var '%s' (found: %s)" %
484 (fname, compat, ','.join(of_match.keys())))
485 driver.compat = of_match[compat]
486
487 # This needs to be deterministic, since a driver may
488 # have multiple compatible strings pointing to it.
489 # We record the one earliest in the alphabet so it
490 # will produce the same result on all machines.
491 for compat_id in of_match[compat]:
492 old = self._compat_to_driver.get(compat_id)
493 if not old or driver.name < old.name:
494 self._compat_to_driver[compat_id] = driver
495 drivers[driver.name] = driver
496 else:
497 # The driver does not have a uclass or compat string.
498 # The first is required but the second is not, so just
499 # ignore this.
500 pass
501 driver = None
502 ids_name = None
503 compat = None
504 compat_dict = {}
505
506 elif ids_name:
507 compat_m = re_compat.search(line)
508 if compat_m:
509 compat_dict[compat_m.group(1)] = compat_m.group(3)
510 elif '};' in line:
511 of_match[ids_name] = compat_dict
512 ids_name = None
513 elif driver_match:
514 driver_name = driver_match.group(1)
515 driver = Driver(driver_name, fname)
516 else:
517 ids_m = re_ids.search(line)
518 if ids_m:
519 ids_name = ids_m.group(1)
520
521 # Make the updates based on what we found
522 self._drivers.update(drivers)
523 self._of_match.update(of_match)
524
Simon Glass9065bc92020-12-28 20:35:06 -0700525 def scan_driver(self, fname):
526 """Scan a driver file to build a list of driver names and aliases
527
Simon Glass78933b72021-02-03 06:00:50 -0700528 It updates the following members:
529 _drivers - updated with new Driver records for each driver found
530 in the file
531 _of_match - updated with each compatible string found in the file
532 _compat_to_driver - Maps compatible string to Driver
533 _driver_aliases - Maps alias names to driver name
Simon Glass9065bc92020-12-28 20:35:06 -0700534
535 Args
536 fname: Driver filename to scan
537 """
538 with open(fname, encoding='utf-8') as inf:
539 try:
540 buff = inf.read()
541 except UnicodeDecodeError:
542 # This seems to happen on older Python versions
543 print("Skipping file '%s' due to unicode error" % fname)
544 return
545
Simon Glass78933b72021-02-03 06:00:50 -0700546 # If this file has any U_BOOT_DRIVER() declarations, process it to
547 # obtain driver information
548 if 'U_BOOT_DRIVER' in buff:
549 self._parse_driver(fname, buff)
Simon Glass2e199ab2021-02-03 06:00:54 -0700550 if 'UCLASS_DRIVER' in buff:
551 self._parse_uclass_driver(fname, buff)
Simon Glass9065bc92020-12-28 20:35:06 -0700552
553 # The following re will search for driver aliases declared as
554 # DM_DRIVER_ALIAS(alias, driver_name)
555 driver_aliases = re.findall(
556 r'DM_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)',
557 buff)
558
559 for alias in driver_aliases: # pragma: no cover
560 if len(alias) != 2:
561 continue
562 self._driver_aliases[alias[1]] = alias[0]
563
Simon Glass88bd5382021-02-03 06:00:55 -0700564 def scan_header(self, fname):
565 """Scan a header file to build a list of struct definitions
566
567 It updates the following members:
568 _structs - updated with new Struct records for each struct found
569 in the file
570
571 Args
572 fname: header filename to scan
573 """
574 with open(fname, encoding='utf-8') as inf:
575 try:
576 buff = inf.read()
577 except UnicodeDecodeError:
578 # This seems to happen on older Python versions
579 print("Skipping file '%s' due to unicode error" % fname)
580 return
581
582 # If this file has any U_BOOT_DRIVER() declarations, process it to
583 # obtain driver information
584 if 'struct' in buff:
585 self._parse_structs(fname, buff)
586
Simon Glass9065bc92020-12-28 20:35:06 -0700587 def scan_drivers(self):
588 """Scan the driver folders to build a list of driver names and aliases
589
590 This procedure will populate self._drivers and self._driver_aliases
591 """
592 for (dirpath, _, filenames) in os.walk(self._basedir):
Simon Glassdc37c812021-02-03 06:00:52 -0700593 rel_path = dirpath[len(self._basedir):]
594 if rel_path.startswith('/'):
595 rel_path = rel_path[1:]
596 if rel_path.startswith('build') or rel_path.startswith('.git'):
597 continue
Simon Glass9065bc92020-12-28 20:35:06 -0700598 for fname in filenames:
Simon Glass88bd5382021-02-03 06:00:55 -0700599 pathname = dirpath + '/' + fname
600 if fname.endswith('.c'):
601 self.scan_driver(pathname)
602 elif fname.endswith('.h'):
603 self.scan_header(pathname)
Simon Glass9065bc92020-12-28 20:35:06 -0700604
605 for fname in self._drivers_additional:
606 if not isinstance(fname, str) or len(fname) == 0:
607 continue
608 if fname[0] == '/':
609 self.scan_driver(fname)
610 else:
611 self.scan_driver(self._basedir + '/' + fname)
Simon Glasseb3c2492021-02-03 06:01:01 -0700612
613 def mark_used(self, nodes):
614 """Mark the drivers associated with a list of nodes as 'used'
615
616 This takes a list of nodes, finds the driver for each one and marks it
617 as used.
618
619 Args:
620 nodes (list of None): Nodes that are in use
621 """
622 # Figure out which drivers we actually use
623 for node in nodes:
624 struct_name, _ = self.get_normalized_compat_name(node)
625 driver = self._drivers.get(struct_name)
626 if driver:
627 driver.used = True