1b6acf807SRob Herring#!/usr/bin/env python3 2b6acf807SRob Herring# SPDX-License-Identifier: GPL-2.0-only 3b6acf807SRob Herring 4*8f51593cSNícolas F. R. A. Pradoimport fnmatch 5b6acf807SRob Herringimport os 6b6acf807SRob Herringimport re 7b6acf807SRob Herringimport argparse 8b6acf807SRob Herring 9b6acf807SRob Herring 10365ba0c7SNícolas F. R. A. Pradodef parse_of_declare_macros(data, include_driver_macros=True): 11b6acf807SRob Herring """ Find all compatible strings in OF_DECLARE() style macros """ 12b6acf807SRob Herring compat_list = [] 13b6acf807SRob Herring # CPU_METHOD_OF_DECLARE does not have a compatible string 14365ba0c7SNícolas F. R. A. Prado if include_driver_macros: 15365ba0c7SNícolas F. R. A. Prado re_macros = r'(?<!CPU_METHOD_)(IRQCHIP|OF)_(DECLARE|MATCH)(_DRIVER)?\(.*?\)' 16365ba0c7SNícolas F. R. A. Prado else: 17365ba0c7SNícolas F. R. A. Prado re_macros = r'(?<!CPU_METHOD_)(IRQCHIP|OF)_(DECLARE|MATCH)\(.*?\)' 18365ba0c7SNícolas F. R. A. Prado for m in re.finditer(re_macros, data): 19b6acf807SRob Herring try: 20b6acf807SRob Herring compat = re.search(r'"(.*?)"', m[0])[1] 21b6acf807SRob Herring except: 22b6acf807SRob Herring # Fails on compatible strings in #define, so just skip 23b6acf807SRob Herring continue 24b6acf807SRob Herring compat_list += [compat] 25b6acf807SRob Herring 26b6acf807SRob Herring return compat_list 27b6acf807SRob Herring 28b6acf807SRob Herring 29365ba0c7SNícolas F. R. A. Pradodef parse_of_device_id(data, match_table_list=None): 30b6acf807SRob Herring """ Find all compatible strings in of_device_id structs """ 31b6acf807SRob Herring compat_list = [] 32365ba0c7SNícolas F. R. A. Prado for m in re.finditer(r'of_device_id(\s+\S+)?\s+(\S+)\[\](\s+\S+)?\s*=\s*({.*?);', data): 33365ba0c7SNícolas F. R. A. Prado if match_table_list is not None and m[2] not in match_table_list: 34365ba0c7SNícolas F. R. A. Prado continue 35365ba0c7SNícolas F. R. A. Prado compat_list += re.findall(r'\.compatible\s+=\s+"(\S+)"', m[4]) 36b6acf807SRob Herring 37b6acf807SRob Herring return compat_list 38b6acf807SRob Herring 39b6acf807SRob Herring 40365ba0c7SNícolas F. R. A. Pradodef parse_of_match_table(data): 41365ba0c7SNícolas F. R. A. Prado """ Find all driver's of_match_table """ 42365ba0c7SNícolas F. R. A. Prado match_table_list = [] 43365ba0c7SNícolas F. R. A. Prado for m in re.finditer(r'\.of_match_table\s+=\s+(of_match_ptr\()?([a-zA-Z0-9_-]+)', data): 44365ba0c7SNícolas F. R. A. Prado match_table_list.append(m[2]) 45365ba0c7SNícolas F. R. A. Prado 46365ba0c7SNícolas F. R. A. Prado return match_table_list 47365ba0c7SNícolas F. R. A. Prado 48365ba0c7SNícolas F. R. A. Prado 49365ba0c7SNícolas F. R. A. Pradodef parse_compatibles(file, compat_ignore_list): 50b6acf807SRob Herring with open(file, 'r', encoding='utf-8') as f: 51b6acf807SRob Herring data = f.read().replace('\n', '') 52b6acf807SRob Herring 53365ba0c7SNícolas F. R. A. Prado if compat_ignore_list is not None: 54365ba0c7SNícolas F. R. A. Prado # For a compatible in the DT to be matched to a driver it needs to show 55365ba0c7SNícolas F. R. A. Prado # up in a driver's of_match_table 56365ba0c7SNícolas F. R. A. Prado match_table_list = parse_of_match_table(data) 57365ba0c7SNícolas F. R. A. Prado compat_list = parse_of_device_id(data, match_table_list) 58365ba0c7SNícolas F. R. A. Prado 59365ba0c7SNícolas F. R. A. Prado compat_list = [compat for compat in compat_list if compat not in compat_ignore_list] 60365ba0c7SNícolas F. R. A. Prado else: 61b6acf807SRob Herring compat_list = parse_of_declare_macros(data) 62b6acf807SRob Herring compat_list += parse_of_device_id(data) 63b6acf807SRob Herring 64b6acf807SRob Herring return compat_list 65b6acf807SRob Herring 66365ba0c7SNícolas F. R. A. Pradodef parse_compatibles_to_ignore(file): 67365ba0c7SNícolas F. R. A. Prado with open(file, 'r', encoding='utf-8') as f: 68365ba0c7SNícolas F. R. A. Prado data = f.read().replace('\n', '') 69365ba0c7SNícolas F. R. A. Prado 70365ba0c7SNícolas F. R. A. Prado # Compatibles that show up in OF_DECLARE macros can't be expected to 71365ba0c7SNícolas F. R. A. Prado # match a driver, except for the _DRIVER ones. 72365ba0c7SNícolas F. R. A. Prado return parse_of_declare_macros(data, include_driver_macros=False) 73365ba0c7SNícolas F. R. A. Prado 74365ba0c7SNícolas F. R. A. Prado 75b6acf807SRob Herringdef print_compat(filename, compatibles): 76b6acf807SRob Herring if not compatibles: 77b6acf807SRob Herring return 78b6acf807SRob Herring if show_filename: 79b6acf807SRob Herring compat_str = ' '.join(compatibles) 80b6acf807SRob Herring print(filename + ": compatible(s): " + compat_str) 81b6acf807SRob Herring else: 82b6acf807SRob Herring print(*compatibles, sep='\n') 83b6acf807SRob Herring 84*8f51593cSNícolas F. R. A. Pradodef glob_without_symlinks(root, glob): 85*8f51593cSNícolas F. R. A. Prado for path, dirs, files in os.walk(root): 86*8f51593cSNícolas F. R. A. Prado # Ignore hidden directories 87*8f51593cSNícolas F. R. A. Prado for d in dirs: 88*8f51593cSNícolas F. R. A. Prado if fnmatch.fnmatch(d, ".*"): 89*8f51593cSNícolas F. R. A. Prado dirs.remove(d) 90*8f51593cSNícolas F. R. A. Prado for f in files: 91*8f51593cSNícolas F. R. A. Prado if fnmatch.fnmatch(f, glob): 92*8f51593cSNícolas F. R. A. Prado yield os.path.join(path, f) 93*8f51593cSNícolas F. R. A. Prado 94eb2139fcSNícolas F. R. A. Pradodef files_to_parse(path_args): 95eb2139fcSNícolas F. R. A. Prado for f in path_args: 96eb2139fcSNícolas F. R. A. Prado if os.path.isdir(f): 97*8f51593cSNícolas F. R. A. Prado for filename in glob_without_symlinks(f, "*.c"): 98eb2139fcSNícolas F. R. A. Prado yield filename 99eb2139fcSNícolas F. R. A. Prado else: 100eb2139fcSNícolas F. R. A. Prado yield f 101eb2139fcSNícolas F. R. A. Prado 102b6acf807SRob Herringshow_filename = False 103b6acf807SRob Herring 104b6acf807SRob Herringif __name__ == "__main__": 105b6acf807SRob Herring ap = argparse.ArgumentParser() 106b6acf807SRob Herring ap.add_argument("cfile", type=str, nargs='*', help="C source files or directories to parse") 107b6acf807SRob Herring ap.add_argument('-H', '--with-filename', help="Print filename with compatibles", action="store_true") 108365ba0c7SNícolas F. R. A. Prado ap.add_argument('-d', '--driver-match', help="Only print compatibles that should match to a driver", action="store_true") 109b6acf807SRob Herring args = ap.parse_args() 110b6acf807SRob Herring 111b6acf807SRob Herring show_filename = args.with_filename 112365ba0c7SNícolas F. R. A. Prado compat_ignore_list = None 113365ba0c7SNícolas F. R. A. Prado 114365ba0c7SNícolas F. R. A. Prado if args.driver_match: 115365ba0c7SNícolas F. R. A. Prado compat_ignore_list = [] 116365ba0c7SNícolas F. R. A. Prado for f in files_to_parse(args.cfile): 117365ba0c7SNícolas F. R. A. Prado compat_ignore_list.extend(parse_compatibles_to_ignore(f)) 118b6acf807SRob Herring 119eb2139fcSNícolas F. R. A. Prado for f in files_to_parse(args.cfile): 120365ba0c7SNícolas F. R. A. Prado compat_list = parse_compatibles(f, compat_ignore_list) 121b6acf807SRob Herring print_compat(f, compat_list) 122