[RFC PATCH v2 1/2] acpi: Add script to extract ACPI device ids in the kernel

Laura Nao <[email protected]>
Newsgroups dev.linux.lists.kernelci,org.kernel.vger.linux-acpi,org.kernel.vger.linux-kernel,org.kernel.vger.linux-kselftest
Message-ID <[email protected]>
Add a script to extract all the supported acpi device ids
from kernel sources.

The script looks for IDs defined in acpi_device_id structs within both
.c and .h files and prints them. If the -d option is used, the script
only shows the IDs that are matched by a driver, identified through
either an ACPI match table or a list of supported IDs provided by the
driver.

The list of IDs returned by the script can be used as a
reference to determine if a device declared in the ACPI namespace
with certain _HID/_CID is supported by the kernel or not.

Note: this script cannot identify IDs defined via macros.

Signed-off-by: Laura Nao <[email protected]>
---
 MAINTAINERS                   |  1 +
 scripts/acpi/acpi-extract-ids | 99 +++++++++++++++++++++++++++++++++++
 2 files changed, 100 insertions(+)
 create mode 100755 scripts/acpi/acpi-extract-ids

diff --git a/MAINTAINERS b/MAINTAINERS
index 375d34363777..8333ead448c4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -293,6 +293,7 @@ F:	include/linux/acpi.h
 F:	include/linux/fwnode.h
 F:	include/linux/fw_table.h
 F:	lib/fw_table.c
+F:	scripts/acpi/acpi-extract-ids
 F:	tools/power/acpi/
 
 ACPI APEI
diff --git a/scripts/acpi/acpi-extract-ids b/scripts/acpi/acpi-extract-ids
new file mode 100755
index 000000000000..4c492d384a35
--- /dev/null
+++ b/scripts/acpi/acpi-extract-ids
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Heavily inspired by the scripts/dtc/dt-extract-compatibles script,
+# adapted for the ACPI use case.
+#
+
+import fnmatch
+import os
+import glob
+import re
+import argparse
+
+
+def parse_acpi_device_id(data, match_list=None):
+    """ Find all device ids in acpi_device_id structs """
+    acpi_device_id_list = []
+
+    for m in re.finditer(r'acpi_device_id(\s+\S+)?\s+(\S+)\[\](\s+\S+)?\s*=\s*({.*?);', data):
+        if match_list is not None and m[2] not in match_list:
+            continue
+        acpi_device_id_list += re.findall(r'\"(\S+)\"', m[4])
+
+    return acpi_device_id_list
+
+def parse_acpi_match_table(data):
+    """ Find all driver's acpi_match_table """
+    match_table_list = []
+    for m in re.finditer(r'\.acpi_match_table\s+=\s+(ACPI_PTR\()?([a-zA-Z0-9_-]+)', data):
+        match_table_list.append(m[2])
+
+    return match_table_list
+
+def parse_acpi_driver_ids(data):
+    """ Find all driver's ids """
+    id_list = []
+    for m in re.finditer(r'\.ids\s+=\s+([a-zA-Z0-9_-]+)', data):
+        id_list.append(m[1])
+
+    return id_list
+
+def is_header_file(file):
+    _, extension = os.path.splitext(file)
+    return extension.lower() == ".h"
+
+def parse_ids(file, driver_match=False):
+    with open(file, 'r', encoding='utf-8') as f:
+        data = f.read().replace('\n', '')
+
+    if is_header_file(file) or not driver_match:
+        return parse_acpi_device_id(data)
+    else:
+        match_list = parse_acpi_match_table(data) + parse_acpi_driver_ids(data)
+        return parse_acpi_device_id(data, match_list)
+
+def print_ids(filename, id_list):
+    if not id_list:
+        return
+    if show_filename:
+        compat_str = ' '.join(id_list)
+        print(filename + ": ID(s): " + compat_str)
+    else:
+        print(*id_list, sep='\n')
+
+def glob_without_symlinks(root, glob):
+    for path, dirs, files in os.walk(root):
+        # Ignore hidden directories
+        for d in dirs:
+            if fnmatch.fnmatch(d, ".*"):
+                dirs.remove(d)
+        for f in files:
+            if fnmatch.fnmatch(f, glob):
+                yield os.path.join(path, f)
+
+def files_to_parse(path_args):
+    for f in path_args:
+        if os.path.isdir(f):
+            for filename in glob_without_symlinks(f, "*.[ch]"):
+                yield filename
+        else:
+            yield f
+
+
+show_filename = False
+
+if __name__ == "__main__":
+    ap = argparse.ArgumentParser()
+    ap.add_argument("cfile", type=str, nargs='*',
+                    help="C source files or directories to parse")
+    ap.add_argument('-H', '--with-filename',
+                    help="Print filename with device ids", action="store_true")
+    ap.add_argument('-d', '--driver-match', help="Only print ids that should match to a driver", action="store_true")
+    args = ap.parse_args()
+
+    show_filename = args.with_filename
+
+    for f in files_to_parse(args.cfile):
+        id_list = parse_ids(f, args.driver_match)
+        print_ids(f, id_list)
-- 
2.30.2
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.