~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/scripts/dtc/dt-extract-compatibles

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 #!/usr/bin/env python3
  2 # SPDX-License-Identifier: GPL-2.0-only
  3 
  4 import fnmatch
  5 import os
  6 import re
  7 import argparse
  8 
  9 
 10 def parse_of_declare_macros(data, include_driver_macros=True):
 11         """ Find all compatible strings in OF_DECLARE() style macros """
 12         compat_list = []
 13         # CPU_METHOD_OF_DECLARE does not have a compatible string
 14         if include_driver_macros:
 15                 re_macros = r'(?<!CPU_METHOD_)(IRQCHIP|OF)_(DECLARE|MATCH)(_DRIVER)?\(.*?\)'
 16         else:
 17                 re_macros = r'(?<!CPU_METHOD_)(IRQCHIP|OF)_(DECLARE|MATCH)\(.*?\)'
 18         for m in re.finditer(re_macros, data):
 19                 try:
 20                         compat = re.search(r'"(.*?)"', m[0])[1]
 21                 except:
 22                         # Fails on compatible strings in #define, so just skip
 23                         continue
 24                 compat_list += [compat]
 25 
 26         return compat_list
 27 
 28 
 29 def parse_of_device_id(data, match_table_list=None):
 30         """ Find all compatible strings in of_device_id structs """
 31         compat_list = []
 32         for m in re.finditer(r'of_device_id(\s+\S+)?\s+(\S+)\[\](\s+\S+)?\s*=\s*({.*?);', data):
 33                 if match_table_list is not None and m[2] not in match_table_list:
 34                         continue
 35                 compat_list += re.findall(r'\.compatible\s+=\s+"(\S+)"', m[4])
 36 
 37         return compat_list
 38 
 39 
 40 def parse_of_match_table(data):
 41         """ Find all driver's of_match_table """
 42         match_table_list = []
 43         for m in re.finditer(r'\.of_match_table\s+=\s+(of_match_ptr\()?([a-zA-Z0-9_-]+)', data):
 44                 match_table_list.append(m[2])
 45 
 46         return match_table_list
 47 
 48 
 49 def parse_of_functions(data, func_name):
 50         """ Find all compatibles in the last argument of a given function """
 51         compat_list = []
 52         for m in re.finditer(rf'{func_name}\(([a-zA-Z0-9_>\(\)"\-]+,\s)*"([a-zA-Z0-9_,-]+)"\)', data):
 53                 compat_list.append(m[2])
 54 
 55         return compat_list
 56 
 57 
 58 def parse_compatibles(file, compat_ignore_list):
 59         with open(file, 'r', encoding='utf-8') as f:
 60                 data = f.read().replace('\n', '')
 61 
 62         if compat_ignore_list is not None:
 63                 # For a compatible in the DT to be matched to a driver it needs to show
 64                 # up in a driver's of_match_table
 65                 match_table_list = parse_of_match_table(data)
 66                 compat_list = parse_of_device_id(data, match_table_list)
 67 
 68                 compat_list = [compat for compat in compat_list if compat not in compat_ignore_list]
 69         else:
 70                 compat_list = parse_of_declare_macros(data)
 71                 compat_list += parse_of_device_id(data)
 72                 compat_list += parse_of_functions(data, "_is_compatible")
 73                 compat_list += parse_of_functions(data, "of_find_compatible_node")
 74                 compat_list += parse_of_functions(data, "for_each_compatible_node")
 75                 compat_list += parse_of_functions(data, "of_get_compatible_child")
 76 
 77         return compat_list
 78 
 79 def parse_compatibles_to_ignore(file):
 80         with open(file, 'r', encoding='utf-8') as f:
 81                 data = f.read().replace('\n', '')
 82 
 83         # Compatibles that show up in OF_DECLARE macros can't be expected to
 84         # match a driver, except for the _DRIVER ones.
 85         return parse_of_declare_macros(data, include_driver_macros=False)
 86 
 87 
 88 def print_compat(filename, compatibles):
 89         if not compatibles:
 90                 return
 91         if show_filename:
 92                 compat_str = ' '.join(compatibles)
 93                 print(filename + ": compatible(s): " + compat_str)
 94         else:
 95                 print(*compatibles, sep='\n')
 96 
 97 def glob_without_symlinks(root, glob):
 98         for path, dirs, files in os.walk(root):
 99                 # Ignore hidden directories
100                 for d in dirs:
101                         if fnmatch.fnmatch(d, ".*"):
102                                 dirs.remove(d)
103                 for f in files:
104                         if fnmatch.fnmatch(f, glob):
105                                 yield os.path.join(path, f)
106 
107 def files_to_parse(path_args):
108         for f in path_args:
109                 if os.path.isdir(f):
110                         for filename in glob_without_symlinks(f, "*.c"):
111                                 yield filename
112                 else:
113                         yield f
114 
115 show_filename = False
116 
117 if __name__ == "__main__":
118         ap = argparse.ArgumentParser()
119         ap.add_argument("cfile", type=str, nargs='*', help="C source files or directories to parse")
120         ap.add_argument('-H', '--with-filename', help="Print filename with compatibles", action="store_true")
121         ap.add_argument('-d', '--driver-match', help="Only print compatibles that should match to a driver", action="store_true")
122         args = ap.parse_args()
123 
124         show_filename = args.with_filename
125         compat_ignore_list = None
126 
127         if args.driver_match:
128                 compat_ignore_list = []
129                 for f in files_to_parse(args.cfile):
130                         compat_ignore_list.extend(parse_compatibles_to_ignore(f))
131 
132         for f in files_to_parse(args.cfile):
133                 compat_list = parse_compatibles(f, compat_ignore_list)
134                 print_compat(f, compat_list)

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php