Linux Hardening
 help / color / mirror / Atom feed
* [PATCH v2 00/39] Implement kernel-doc in Python
@ 2025-02-24  9:08 Mauro Carvalho Chehab
  2025-02-24  9:08 ` [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser Mauro Carvalho Chehab
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24  9:08 UTC (permalink / raw)
  To: Linux Doc Mailing List, Jonathan Corbet
  Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel,
	Gustavo A. R. Silva, Arnd Bergmann, Bingbu Cao,
	Greg Kroah-Hartman, Kees Cook, Sakari Ailus, Takashi Sakamoto,
	Tianshu Qiu, linux-arch, linux-hardening, linux-media,
	linux-staging, linux1394-devel

Hi Jon,

This changeset contains the kernel-doc.py script to replace the verable
kernel-doc originally written in Perl. It replaces the first version and the
second series I sent on the top of it.

I tried to stay as close as possible of the original Perl implementation
on the first patch introducing kernel-doc.py, as it helps to double check
if each function was  properly translated to Python.  This have been 
helpful debugging troubles that happened during the conversion.

I worked hard to make it bug-compatible with the original one. Still, its
output has a couple of differences from the original one:

- The tab expansion works better with the Python script. With that, some
  outputs that contain tabs at kernel-doc markups are now different;

- The new script  works better stripping blank lines. So, there are a couple
  of empty new lines that are now stripped with this version;

- There is a buggy logic at kernel-doc to strip empty description and
  return sections. I was not able to replicate the exact behavior. So, I ended
  adding an extra logic to strip empty sections with a different algorithm.

Yet, on my tests, the results are compatible with the venerable script
output for all .. kernel-doc tags found in Documentation/. I double-checked
this by adding support to output the kernel-doc commands when V=1, and
then I ran a diff between kernel-doc.pl and kernel-doc.py for the same
command lines.

On version 2, kerneldoc.py Sphinx extension now uses the Python classes
if KERNELDOC  environment var ends with kernel-doc.py. It  keeps a cache
of previously-parsed files to avoid performance penalties when the same
file is added on multiple places.

This series contains:

- 4 patches fixing some kernel-doc issues. One of them is for media, but
   I prefer to have this merged via your tree, as it suppresses a warning
   that happens after the changes;

- 2 cleanup patches for Perl kernel-doc;

- 2 patches renaming kernel-doc to kernel-doc.pl and adding a symlink.
  I opted to have the symlink in separate to make easier to review, but
  feel free to merge them on a single patch if you want.

The remaining patches add the new script, converts it into a library and
addresses lots of minor compatibility issues. The last patch changes
Sphinx extension to directly use the Python classes.

The only patch that doesn't belong to this series is a patch dropping
kernel-doc.py. I opted to keep it for now, as it can help to better
test the new tools.

With such changes, if one wants to build docs with the old script,
all it is needed is to use KERNELDOC parameter, e.g.:

	$ make KERNELDOC=scripts/kernel-doc.pl htmldocs

Mauro Carvalho Chehab (39):
  include/asm-generic/io.h: fix kerneldoc markup
  drivers: media: intel-ipu3.h: fix identation on a kernel-doc markup
  drivers: firewire: firewire-cdev.h: fix identation on a kernel-doc
    markup
  docs: driver-api/infiniband.rst: fix Kerneldoc markup
  scripts/kernel-doc: don't add not needed new lines
  scripts/kernel-doc: drop dead code for Wcontents_before_sections
  scripts/kernel-doc: rename it to scripts/kernel-doc.pl
  scripts/kernel-doc: add a symlink to the Perl version of kernel-doc
  scripts/kernel-doc.py: add a Python parser
  scripts/kernel-doc.py: output warnings the same way as kerneldoc
  scripts/kernel-doc.py: better handle empty sections
  scripts/kernel-doc.py: properly handle struct_group macros
  scripts/kernel-doc.py: move regex methods to a separate file
  scripts/kernel-doc.py: move KernelDoc class to a separate file
  scripts/kernel-doc.py: move KernelFiles class to a separate file
  scripts/kernel-doc.py: move output classes to a separate file
  scripts/kernel-doc.py: convert message output to an interactor
  scripts/kernel-doc.py: move file lists to the parser function
  scripts/kernel-doc.py: implement support for -no-doc-sections
  scripts/kernel-doc.py: fix line number output
  scripts/kernel-doc.py: fix handling of doc output check
  scripts/kernel-doc.py: properly handle out_section for ReST
  scripts/kernel-doc.py: postpone warnings to the output plugin
  docs: add a .pylintrc file with sys path for docs scripts
  docs: sphinx: kerneldoc: verbose kernel-doc command if V=1
  docs: sphinx: kerneldoc: ignore "\" characters from options
  docs: sphinx: kerneldoc: use kernel-doc.py script
  scripts/kernel-doc.py: Set an output format for --none
  scripts/kernel-doc.py: adjust some coding style issues
  scripts/lib/kdoc/kdoc_parser.py: fix Python compat with < v3.13
  scripts/kernel-doc.py: move modulename to man class
  scripts/kernel-doc.py: properly handle KBUILD_BUILD_TIMESTAMP
  scripts/lib/kdoc/kdoc_parser.py: remove a python 3.9 dependency
  scripts/kernel-doc.py: Properly handle Werror and exit codes
  scripts/kernel-doc.py: some coding style cleanups
  scripts/kernel-doc: switch to use kernel-doc.py
  scripts/lib/kdoc/kdoc_files.py: allow filtering output per fname
  scripts/kernel_doc.py: better handle exported symbols
  docs: sphinx: kerneldoc: Use python class if available

 .pylintrc                                     |    2 +
 Documentation/Makefile                        |    2 +-
 Documentation/conf.py                         |    2 +-
 Documentation/driver-api/infiniband.rst       |   16 +-
 Documentation/sphinx/kerneldoc.py             |  183 +-
 .../media/ipu3/include/uapi/intel-ipu3.h      |    3 +-
 include/asm-generic/io.h                      |    6 +-
 include/uapi/linux/firewire-cdev.h            |    3 +-
 scripts/kernel-doc                            | 2447 +----------------
 scripts/kernel-doc.pl                         | 2439 ++++++++++++++++
 scripts/kernel-doc.py                         |  240 ++
 scripts/lib/kdoc/kdoc_files.py                |  281 ++
 scripts/lib/kdoc/kdoc_output.py               |  792 ++++++
 scripts/lib/kdoc/kdoc_parser.py               | 1714 ++++++++++++
 scripts/lib/kdoc/kdoc_re.py                   |  273 ++
 15 files changed, 5930 insertions(+), 2473 deletions(-)
 create mode 100644 .pylintrc
 mode change 100755 => 120000 scripts/kernel-doc
 create mode 100755 scripts/kernel-doc.pl
 create mode 100755 scripts/kernel-doc.py
 create mode 100755 scripts/lib/kdoc/kdoc_files.py
 create mode 100755 scripts/lib/kdoc/kdoc_output.py
 create mode 100755 scripts/lib/kdoc/kdoc_parser.py
 create mode 100755 scripts/lib/kdoc/kdoc_re.py

-- 
2.48.1



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser
  2025-02-24  9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
@ 2025-02-24  9:08 ` Mauro Carvalho Chehab
  2025-02-24 23:38   ` Jonathan Corbet
  2025-02-24  9:08 ` [PATCH v2 14/39] scripts/kernel-doc.py: move KernelDoc class to a separate file Mauro Carvalho Chehab
  2025-02-24 23:49 ` [PATCH v2 00/39] Implement kernel-doc in Python Jonathan Corbet
  2 siblings, 1 reply; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24  9:08 UTC (permalink / raw)
  To: Linux Doc Mailing List, Jonathan Corbet
  Cc: Mauro Carvalho Chehab, Gustavo A. R. Silva, Mauro Carvalho Chehab,
	Kees Cook, linux-hardening, linux-kernel

Maintaining kernel-doc has been a challenge, as there aren't many
perl developers among maintainers. Also, the logic there is too
complex. Having lots of global variables and using pure functions
doesn't help.

Rewrite the script in Python, placing most global variables
inside classes. This should help maintaining the script in long
term.

It also allows a better integration with kernel-doc Sphinx
extension in the future.

I opted to keep this version as close as possible to what we
have already in Perl. There are some differences though:

1. There is one regular expression that required a rewrite:

	/\bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;/

   As this one uses two features that aren't available by the native
   Python regular expression module (re):

	- recursive patterns: ?1
	- atomic grouping (?>...)

   Rewrite it to use a much simpler regular expression:

	/\bSTRUCT_GROUP\(([^\)]+)\)[^;]*;/

   Extra care should be taken when validating this script, as such
   replacement might cause some regressions.

2. The filters are now applied only during output generation.
   In particular, "nosymbol" argument is only handled there.

   It means that, if the same file is processed twice for
   different symbols, the warnings will be duplicated.

   I opted to use this behavior as it allows the Sphinx extension
   to read the file(s) only once, and apply the filtering only
   when producing the ReST output. This hopefully will help
   to speed up doc generation

3. This version can handle multiple files and multiple directories.

   So, if one just wants to produce a big output with everything
   inside a file, this could be done with

   $ time ./scripts/kernel-doc.py -man . 2>/dev/null >new
   real    0m54.592s
   user    0m53.345s
   sys     0m0.997s

4. I tried to replicate as much as possible the same arguments
   from kernel-doc, with about the same behavior, for the
   command line parameters starting with a single dash (-parameter).

   I also added one letter aliases for each parameter, and a
   --parameter (sometimes with a better name).

5. There are some sutile nuances between how Perl handles
   certain regular expressions. In special, the qr operatior,
   which compiles a regular expression also works as a
   non-capturing group. It means that some regexes like
   this one:

	my $type1 = qr{[\w\s]+};

   needs to be mapped as:

	type1 = r'(?:[\w\s]+)?'

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>

---

TODO:
- on this RFC, the man output doesn't match yet the same output of
  kernel-doc. The ReST output matches, except for some whitespaces
  and suppressed empty sectionsl
- this version lacks support for -W<filter> parameters: it will just
  output all warnings.
- all classes are at the same file. I want to split the classes on
  multiple files for the final version, but, during development time,
  it is easier to have everything on a single file, but I plan to split
  classes on different files to help maintaining the script.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 scripts/kernel-doc.py | 2757 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 2757 insertions(+)
 create mode 100755 scripts/kernel-doc.py

diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
new file mode 100755
index 000000000000..5cf5ed63f215
--- /dev/null
+++ b/scripts/kernel-doc.py
@@ -0,0 +1,2757 @@
+#!/usr/bin/env python3
+# pylint: disable=R0902,R0903,R0904,R0911,R0912,R0913,R0914,R0915,R0917,R1702
+# pylint: disable=C0302,C0103,C0301
+# pylint: disable=C0116,C0115,W0511,W0613
+# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
+# SPDX-License-Identifier: GPL-2.0
+
+# TODO: implement warning filtering
+
+"""
+kernel_doc
+==========
+
+Print formatted kernel documentation to stdout
+
+Read C language source or header FILEs, extract embedded
+documentation comments, and print formatted documentation
+to standard output.
+
+The documentation comments are identified by the "/**"
+opening comment mark.
+
+See Documentation/doc-guide/kernel-doc.rst for the
+documentation comment syntax.
+"""
+
+import argparse
+import logging
+import os
+import re
+import sys
+
+from datetime import datetime
+from pprint import pformat
+
+from dateutil import tz
+
+# Local cache for regular expressions
+re_cache = {}
+
+
+class Re:
+    """
+    Helper class to simplify regex declaration and usage,
+
+    It calls re.compile for a given pattern. It also allows adding
+    regular expressions and define sub at class init time.
+
+    Regular expressions can be cached via an argument, helping to speedup
+    searches.
+    """
+
+    def _add_regex(self, string, flags):
+        if string in re_cache:
+            self.regex = re_cache[string]
+        else:
+            self.regex = re.compile(string, flags=flags)
+
+            if self.cache:
+                re_cache[string] = self.regex
+
+    def __init__(self, string, cache=True, flags=0):
+        self.cache = cache
+        self.last_match = None
+
+        self._add_regex(string, flags)
+
+    def __str__(self):
+        return self.regex.pattern
+
+    def __add__(self, other):
+        return Re(str(self) + str(other), cache=self.cache or other.cache,
+                  flags=self.regex.flags | other.regex.flags)
+
+    def match(self, string):
+        self.last_match = self.regex.match(string)
+        return self.last_match
+
+    def search(self, string):
+        self.last_match = self.regex.search(string)
+        return self.last_match
+
+    def findall(self, string):
+        return self.regex.findall(string)
+
+    def split(self, string):
+        return self.regex.split(string)
+
+    def sub(self, sub, string, count=0):
+        return self.regex.sub(sub, string, count=count)
+
+    def group(self, num):
+        return self.last_match.group(num)
+
+#
+# Regular expressions used to parse kernel-doc markups at KernelDoc class.
+#
+# Let's declare them in lowercase outside any class to make easier to
+# convert from the python script.
+#
+# As those are evaluated at the beginning, no need to cache them
+#
+
+
+# Allow whitespace at end of comment start.
+doc_start = Re(r'^/\*\*\s*$', cache=False)
+
+doc_end = Re(r'\*/', cache=False)
+doc_com = Re(r'\s*\*\s*', cache=False)
+doc_com_body = Re(r'\s*\* ?', cache=False)
+doc_decl = doc_com + Re(r'(\w+)', cache=False)
+
+# @params and a strictly limited set of supported section names
+# Specifically:
+#   Match @word:
+#         @...:
+#         @{section-name}:
+# while trying to not match literal block starts like "example::"
+#
+doc_sect = doc_com + \
+            Re(r'\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:([^:].*)?$',
+                flags=re.I, cache=False)
+
+doc_content = doc_com_body + Re(r'(.*)', cache=False)
+doc_block = doc_com + Re(r'DOC:\s*(.*)?', cache=False)
+doc_inline_start = Re(r'^\s*/\*\*\s*$', cache=False)
+doc_inline_sect = Re(r'\s*\*\s*(@\s*[\w][\w\.]*\s*):(.*)', cache=False)
+doc_inline_end = Re(r'^\s*\*/\s*$', cache=False)
+doc_inline_oneline = Re(r'^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$', cache=False)
+function_pointer = Re(r"([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)", cache=False)
+attribute = Re(r"__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)",
+               flags=re.I | re.S, cache=False)
+
+# match expressions used to find embedded type information
+type_constant = Re(r"\b``([^\`]+)``\b", cache=False)
+type_constant2 = Re(r"\%([-_*\w]+)", cache=False)
+type_func = Re(r"(\w+)\(\)", cache=False)
+type_param = Re(r"\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False)
+type_param_ref = Re(r"([\!~\*]?)\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False)
+
+# Special RST handling for func ptr params
+type_fp_param = Re(r"\@(\w+)\(\)", cache=False)
+
+# Special RST handling for structs with func ptr params
+type_fp_param2 = Re(r"\@(\w+->\S+)\(\)", cache=False)
+
+type_env = Re(r"(\$\w+)", cache=False)
+type_enum = Re(r"\&(enum\s*([_\w]+))", cache=False)
+type_struct = Re(r"\&(struct\s*([_\w]+))", cache=False)
+type_typedef = Re(r"\&(typedef\s*([_\w]+))", cache=False)
+type_union = Re(r"\&(union\s*([_\w]+))", cache=False)
+type_member = Re(r"\&([_\w]+)(\.|->)([_\w]+)", cache=False)
+type_fallback = Re(r"\&([_\w]+)", cache=False)
+type_member_func = type_member + Re(r"\(\)", cache=False)
+
+export_symbol = Re(r'^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*', cache=False)
+export_symbol_ns = Re(r'^\s*EXPORT_SYMBOL_NS(_GPL)?\s*\(\s*(\w+)\s*,\s*"\S+"\)\s*', cache=False)
+
+class KernelDoc:
+    # Parser states
+    STATE_NORMAL        = 0        # normal code
+    STATE_NAME          = 1        # looking for function name
+    STATE_BODY_MAYBE    = 2        # body - or maybe more description
+    STATE_BODY          = 3        # the body of the comment
+    STATE_BODY_WITH_BLANK_LINE = 4 # the body which has a blank line
+    STATE_PROTO         = 5        # scanning prototype
+    STATE_DOCBLOCK      = 6        # documentation block
+    STATE_INLINE        = 7        # gathering doc outside main block
+
+    st_name = [
+        "NORMAL",
+        "NAME",
+        "BODY_MAYBE",
+        "BODY",
+        "BODY_WITH_BLANK_LINE",
+        "PROTO",
+        "DOCBLOCK",
+        "INLINE",
+    ]
+
+    # Inline documentation state
+    STATE_INLINE_NA     = 0 # not applicable ($state != STATE_INLINE)
+    STATE_INLINE_NAME   = 1 # looking for member name (@foo:)
+    STATE_INLINE_TEXT   = 2 # looking for member documentation
+    STATE_INLINE_END    = 3 # done
+    STATE_INLINE_ERROR  = 4 # error - Comment without header was found.
+                            # Spit a warning as it's not
+                            # proper kernel-doc and ignore the rest.
+
+    st_inline_name = [
+        "",
+        "_NAME",
+        "_TEXT",
+        "_END",
+        "_ERROR",
+    ]
+
+    # Section names
+
+    section_default = "Description"  # default section
+    section_intro = "Introduction"
+    section_context = "Context"
+    section_return = "Return"
+
+    undescribed = "-- undescribed --"
+
+    def __init__(self, config, fname):
+        """Initialize internal variables"""
+
+        self.fname = fname
+        self.config = config
+
+        # Initial state for the state machines
+        self.state = self.STATE_NORMAL
+        self.inline_doc_state = self.STATE_INLINE_NA
+
+        # Store entry currently being processed
+        self.entry = None
+
+        # Place all potential outputs into an array
+        self.entries = []
+
+    def show_warnings(self, dtype, declaration_name):
+        # TODO: implement it
+
+        return True
+
+    # TODO: rename to emit_message
+    def emit_warning(self, ln, msg, warning=True):
+        """Emit a message"""
+
+        if warning:
+            self.config.log.warning("%s:%d %s", self.fname, ln, msg)
+        else:
+            self.config.log.info("%s:%d %s", self.fname, ln, msg)
+
+    def dump_section(self, start_new=True):
+        """
+        Dumps section contents to arrays/hashes intended for that purpose.
+        """
+
+        name = self.entry.section
+        contents = self.entry.contents
+
+        if type_param.match(name):
+            name = type_param.group(1)
+
+            self.entry.parameterdescs[name] = contents
+            self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line
+
+            self.entry.sectcheck += name + " "
+            self.entry.new_start_line = 0
+
+        elif name == "@...":
+            name = "..."
+            self.entry.parameterdescs[name] = contents
+            self.entry.sectcheck += name + " "
+            self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line
+            self.entry.new_start_line = 0
+
+        else:
+            if name in self.entry.sections and self.entry.sections[name] != "":
+                # Only warn on user-specified duplicate section names
+                if name != self.section_default:
+                    self.emit_warning(self.entry.new_start_line,
+                                      f"duplicate section name '{name}'\n")
+                self.entry.sections[name] += contents
+            else:
+                self.entry.sections[name] = contents
+                self.entry.sectionlist.append(name)
+                self.entry.section_start_lines[name] = self.entry.new_start_line
+                self.entry.new_start_line = 0
+
+#        self.config.log.debug("Section: %s : %s", name, pformat(vars(self.entry)))
+
+        if start_new:
+            self.entry.section = self.section_default
+            self.entry.contents = ""
+
+    # TODO: rename it to store_declaration
+    def output_declaration(self, dtype, name, **args):
+        """
+        Stores the entry into an entry array.
+
+        The actual output and output filters will be handled elsewhere
+        """
+
+        # The implementation here is different than the original kernel-doc:
+        # instead of checking for output filters or actually output anything,
+        # it just stores the declaration content at self.entries, as the
+        # output will happen on a separate class.
+        #
+        # For now, we're keeping the same name of the function just to make
+        # easier to compare the source code of both scripts
+
+        if "declaration_start_line" not in args:
+            args["declaration_start_line"] = self.entry.declaration_start_line
+
+        args["type"] = dtype
+
+        self.entries.append((name, args))
+
+        self.config.log.debug("Output: %s:%s = %s", dtype, name, pformat(args))
+
+    def reset_state(self, ln):
+        """
+        Ancillary routine to create a new entry. It initializes all
+        variables used by the state machine.
+        """
+
+        self.entry = argparse.Namespace
+
+        self.entry.contents = ""
+        self.entry.function = ""
+        self.entry.sectcheck = ""
+        self.entry.struct_actual = ""
+        self.entry.prototype = ""
+
+        self.entry.parameterlist = []
+        self.entry.parameterdescs = {}
+        self.entry.parametertypes = {}
+        self.entry.parameterdesc_start_lines = {}
+
+        self.entry.section_start_lines = {}
+        self.entry.sectionlist = []
+        self.entry.sections = {}
+
+        self.entry.anon_struct_union = False
+
+        self.entry.leading_space = None
+
+        # State flags
+        self.state = self.STATE_NORMAL
+        self.inline_doc_state = self.STATE_INLINE_NA
+        self.entry.brcount = 0
+
+        self.entry.in_doc_sect = False
+        self.entry.declaration_start_line = ln
+
+    def push_parameter(self, ln, decl_type, param, dtype,
+                       org_arg, declaration_name):
+        if self.entry.anon_struct_union and dtype == "" and param == "}":
+            return  # Ignore the ending }; from anonymous struct/union
+
+        self.entry.anon_struct_union = False
+
+        param = Re(r'[\[\)].*').sub('', param, count=1)
+
+        if dtype == "" and param.endswith("..."):
+            if Re(r'\w\.\.\.$').search(param):
+                # For named variable parameters of the form `x...`,
+                # remove the dots
+                param = param[:-3]
+            else:
+                # Handles unnamed variable parameters
+                param = "..."
+
+            if param not in self.entry.parameterdescs or \
+                not self.entry.parameterdescs[param]:
+
+                self.entry.parameterdescs[param] = "variable arguments"
+
+        elif dtype == "" and (not param or param == "void"):
+            param = "void"
+            self.entry.parameterdescs[param] = "no arguments"
+
+        elif dtype == "" and param in ["struct", "union"]:
+            # Handle unnamed (anonymous) union or struct
+            dtype = param
+            param = "{unnamed_" + param + "}"
+            self.entry.parameterdescs[param] = "anonymous\n"
+            self.entry.anon_struct_union = True
+
+        # Handle cache group enforcing variables: they do not need
+        # to be described in header files
+        elif "__cacheline_group" in param:
+            # Ignore __cacheline_group_begin and __cacheline_group_end
+            return
+
+        # Warn if parameter has no description
+        # (but ignore ones starting with # as these are not parameters
+        # but inline preprocessor statements)
+        if param not in self.entry.parameterdescs and not param.startswith("#"):
+            self.entry.parameterdescs[param] = self.undescribed
+
+            if self.show_warnings(dtype, declaration_name) and "." not in param:
+                if decl_type == 'function':
+                    dname = f"{decl_type} parameter"
+                else:
+                    dname = f"{decl_type} member"
+
+                self.emit_warning(ln,
+                                  f"{dname} '{param}' not described in '{declaration_name}'")
+
+        # Strip spaces from param so that it is one continuous string on
+        # parameterlist. This fixes a problem where check_sections()
+        # cannot find a parameter like "addr[6 + 2]" because it actually
+        # appears as "addr[6", "+", "2]" on the parameter list.
+        # However, it's better to maintain the param string unchanged for
+        # output, so just weaken the string compare in check_sections()
+        # to ignore "[blah" in a parameter string.
+
+        self.entry.parameterlist.append(param)
+        org_arg = Re(r'\s\s+').sub(' ', org_arg, count=1)
+        self.entry.parametertypes[param] = org_arg
+
+    def save_struct_actual(self, actual):
+        """
+        Strip all spaces from the actual param so that it looks like
+        one string item.
+        """
+
+        actual = Re(r'\s*').sub("", actual, count=1)
+
+        self.entry.struct_actual += actual + " "
+
+    def create_parameter_list(self, ln, decl_type, args, splitter, declaration_name):
+
+        # temporarily replace all commas inside function pointer definition
+        arg_expr = Re(r'(\([^\),]+),')
+        while arg_expr.search(args):
+            args = arg_expr.sub(r"\1#", args)
+
+        for arg in args.split(splitter):
+            # Strip comments
+            arg = Re(r'\/\*.*\*\/').sub('', arg)
+
+            # Ignore argument attributes
+            arg = Re(r'\sPOS0?\s').sub(' ', arg)
+
+            # Strip leading/trailing spaces
+            arg = arg.strip()
+            arg = Re(r'\s+').sub(' ', arg, count=1)
+
+            if arg.startswith('#'):
+                # Treat preprocessor directive as a typeless variable just to fill
+                # corresponding data structures "correctly". Catch it later in
+                # output_* subs.
+
+                # Treat preprocessor directive as a typeless variable
+                self.push_parameter(ln, decl_type, arg, "",
+                                    "", declaration_name)
+
+            elif Re(r'\(.+\)\s*\(').search(arg):
+                # Pointer-to-function
+
+                arg = arg.replace('#', ',')
+
+                r = Re(r'[^\(]+\(\*?\s*([\w\[\]\.]*)\s*\)')
+                if r.match(arg):
+                    param = r.group(1)
+                else:
+                    self.emit_warning(ln, f"Invalid param: {arg}")
+                    param = arg
+
+                dtype = Re(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg)
+                self.save_struct_actual(param)
+                self.push_parameter(ln, decl_type, param, dtype,
+                                    arg, declaration_name)
+
+            elif Re(r'\(.+\)\s*\[').search(arg):
+                # Array-of-pointers
+
+                arg = arg.replace('#', ',')
+                r = Re(r'[^\(]+\(\s*\*\s*([\w\[\]\.]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)')
+                if r.match(arg):
+                    param = r.group(1)
+                else:
+                    self.emit_warning(ln, f"Invalid param: {arg}")
+                    param = arg
+
+                dtype = Re(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg)
+
+                self.save_struct_actual(param)
+                self.push_parameter(ln, decl_type, param, dtype,
+                                    arg, declaration_name)
+
+            elif arg:
+                arg = Re(r'\s*:\s*').sub(":", arg)
+                arg = Re(r'\s*\[').sub('[', arg)
+
+                args = Re(r'\s*,\s*').split(arg)
+                if args[0] and '*' in args[0]:
+                    args[0] = re.sub(r'(\*+)\s*', r' \1', args[0])
+
+                first_arg = []
+                r = Re(r'^(.*\s+)(.*?\[.*\].*)$')
+                if args[0] and r.match(args[0]):
+                    args.pop(0)
+                    first_arg.extend(r.group(1))
+                    first_arg.append(r.group(2))
+                else:
+                    first_arg = Re(r'\s+').split(args.pop(0))
+
+                args.insert(0, first_arg.pop())
+                dtype = ' '.join(first_arg)
+
+                for param in args:
+                    if Re(r'^(\*+)\s*(.*)').match(param):
+                        r = Re(r'^(\*+)\s*(.*)')
+                        if not r.match(param):
+                            self.emit_warning(ln, f"Invalid param: {param}")
+                            continue
+
+                        param = r.group(1)
+
+                        self.save_struct_actual(r.group(2))
+                        self.push_parameter(ln, decl_type, r.group(2),
+                                            f"{dtype} {r.group(1)}",
+                                            arg, declaration_name)
+
+                    elif Re(r'(.*?):(\w+)').search(param):
+                        r = Re(r'(.*?):(\w+)')
+                        if not r.match(param):
+                            self.emit_warning(ln, f"Invalid param: {param}")
+                            continue
+
+                        if dtype != "":  # Skip unnamed bit-fields
+                            self.save_struct_actual(r.group(1))
+                            self.push_parameter(ln, decl_type, r.group(1),
+                                                f"{dtype}:{r.group(2)}",
+                                                arg, declaration_name)
+                    else:
+                        self.save_struct_actual(param)
+                        self.push_parameter(ln, decl_type, param, dtype,
+                                            arg, declaration_name)
+
+    def check_sections(self, ln, decl_name, decl_type, sectcheck, prmscheck):
+        sects = sectcheck.split()
+        prms = prmscheck.split()
+        err = False
+
+        for sx in range(len(sects)):                  # pylint: disable=C0200
+            err = True
+            for px in range(len(prms)):               # pylint: disable=C0200
+                prm_clean = prms[px]
+                prm_clean = Re(r'\[.*\]').sub('', prm_clean)
+                prm_clean = attribute.sub('', prm_clean)
+
+                # ignore array size in a parameter string;
+                # however, the original param string may contain
+                # spaces, e.g.:  addr[6 + 2]
+                # and this appears in @prms as "addr[6" since the
+                # parameter list is split at spaces;
+                # hence just ignore "[..." for the sections check;
+                prm_clean = Re(r'\[.*').sub('', prm_clean)
+
+                if prm_clean == sects[sx]:
+                    err = False
+                    break
+
+            if err:
+                if decl_type == 'function':
+                    dname = f"{decl_type} parameter"
+                else:
+                    dname = f"{decl_type} member"
+
+                self.emit_warning(ln,
+                                  f"Excess {dname} '{sects[sx]}' description in '{decl_name}'")
+
+    def check_return_section(self, ln, declaration_name, return_type):
+
+        if not self.config.wreturn:
+            return
+
+        # Ignore an empty return type (It's a macro)
+        # Ignore functions with a "void" return type (but not "void *")
+        if not return_type or Re(r'void\s*\w*\s*$').search(return_type):
+            return
+
+        if not self.entry.sections.get("Return", None):
+            self.emit_warning(ln,
+                              f"No description found for return value of '{declaration_name}'")
+
+    def dump_struct(self, ln, proto):
+        """
+        Store an entry for an struct or union
+        """
+
+        type_pattern = r'(struct|union)'
+
+        qualifiers = [
+            "__attribute__",
+            "__packed",
+            "__aligned",
+            "____cacheline_aligned_in_smp",
+            "____cacheline_aligned",
+        ]
+
+        definition_body = r'\{(.*)\}\s*' + "(?:" + '|'.join(qualifiers) + ")?"
+        struct_members = Re(type_pattern + r'([^\{\};]+)(\{)([^\{\}]*)(\})([^\{\}\;]*)(\;)')
+
+        # Extract struct/union definition
+        members = None
+        declaration_name = None
+        decl_type = None
+
+        r = Re(type_pattern + r'\s+(\w+)\s*' + definition_body)
+        if r.search(proto):
+            decl_type = r.group(1)
+            declaration_name = r.group(2)
+            members = r.group(3)
+        else:
+            r = Re(r'typedef\s+' + type_pattern + r'\s*' + definition_body + r'\s*(\w+)\s*;')
+
+            if r.search(proto):
+                decl_type = r.group(1)
+                declaration_name = r.group(3)
+                members = r.group(2)
+
+        if not members:
+            self.emit_warning(ln, f"{proto} error: Cannot parse struct or union!")
+            self.config.errors += 1
+            return
+
+        if self.entry.identifier != declaration_name:
+            self.emit_warning(ln,
+                              f"expecting prototype for {decl_type} {self.entry.identifier}. Prototype was for {decl_type} {declaration_name} instead\n")
+            return
+
+        args_pattern =r'([^,)]+)'
+
+        sub_prefixes = [
+            (Re(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', re.S | re.I),  ''),
+            (Re(r'\/\*\s*private:.*', re.S| re.I),  ''),
+
+            # Strip comments
+            (Re(r'\/\*.*?\*\/', re.S),  ''),
+
+            # Strip attributes
+            (attribute, ' '),
+            (Re(r'\s*__aligned\s*\([^;]*\)', re.S),  ' '),
+            (Re(r'\s*__counted_by\s*\([^;]*\)', re.S),  ' '),
+            (Re(r'\s*__counted_by_(le|be)\s*\([^;]*\)', re.S),  ' '),
+            (Re(r'\s*__packed\s*', re.S),  ' '),
+            (Re(r'\s*CRYPTO_MINALIGN_ATTR', re.S),  ' '),
+            (Re(r'\s*____cacheline_aligned_in_smp', re.S),  ' '),
+            (Re(r'\s*____cacheline_aligned', re.S),  ' '),
+
+            # Unwrap struct_group() based on this definition:
+            # __struct_group(TAG, NAME, ATTRS, MEMBERS...)
+            # which has variants like: struct_group(NAME, MEMBERS...)
+
+            (Re(r'\bstruct_group\s*\(([^,]*,)', re.S),  r'STRUCT_GROUP('),
+            (Re(r'\bstruct_group_attr\s*\(([^,]*,){2}', re.S),  r'STRUCT_GROUP('),
+            (Re(r'\bstruct_group_tagged\s*\(([^,]*),([^,]*),', re.S),  r'struct \1 \2; STRUCT_GROUP('),
+            (Re(r'\b__struct_group\s*\(([^,]*,){3}', re.S),  r'STRUCT_GROUP('),
+
+            # This is incompatible with Python re, as it uses:
+            #  recursive patterns ((?1)) and atomic grouping ((?>...)):
+            #   '\bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;'
+            # Let's see if this works instead:
+            (Re(r'\bSTRUCT_GROUP\(([^\)]+)\)[^;]*;', re.S),  r'\1'),
+
+            # Replace macros
+            (Re(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S),  r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'),
+            (Re(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S),  r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'),
+            (Re(r'DECLARE_BITMAP\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S),  r'unsigned long \1[BITS_TO_LONGS(\2)]'),
+            (Re(r'DECLARE_HASHTABLE\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S),  r'unsigned long \1[1 << ((\2) - 1)]'),
+            (Re(r'DECLARE_KFIFO\s*\(' + args_pattern + r',\s*' + args_pattern + r',\s*' + args_pattern + r'\)', re.S),  r'\2 *\1'),
+            (Re(r'DECLARE_KFIFO_PTR\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S),  r'\2 *\1'),
+            (Re(r'(?:__)?DECLARE_FLEX_ARRAY\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S),  r'\1 \2[]'),
+            (Re(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + args_pattern + r'\)', re.S),  r'dma_addr_t \1'),
+            (Re(r'DEFINE_DMA_UNMAP_LEN\s*\(' + args_pattern + r'\)', re.S),  r'__u32 \1'),
+        ]
+
+        for search, sub in sub_prefixes:
+            members = search.sub(sub, members)
+
+        # Keeps the original declaration as-is
+        declaration = members
+
+        # Split nested struct/union elements
+        #
+        # This loop was simpler at the original kernel-doc perl version, as
+        #   while ($members =~ m/$struct_members/) { ... }
+        # reads 'members' string on each interaction.
+        #
+        # Python behavior is different: it parses 'members' only once,
+        # creating a list of tuples from the first interaction.
+        #
+        # On other words, this won't get nested structs.
+        #
+        # So, we need to have an extra loop on Python to override such
+        # re limitation.
+
+        while True:
+            tuples = struct_members.findall(members)
+            if not tuples:
+                break
+
+            for t in tuples:
+                newmember = ""
+                maintype = t[0]
+                s_ids = t[5]
+                content = t[3]
+
+                oldmember = "".join(t)
+
+                for s_id in s_ids.split(','):
+                    s_id = s_id.strip()
+
+                    newmember += f"{maintype} {s_id}; "
+                    s_id = Re(r'[:\[].*').sub('', s_id)
+                    s_id = Re(r'^\s*\**(\S+)\s*').sub(r'\1', s_id)
+
+                    for arg in content.split(';'):
+                        arg = arg.strip()
+
+                        if not arg:
+                            continue
+
+                        r = Re(r'^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)')
+                        if r.match(arg):
+                            # Pointer-to-function
+                            dtype = r.group(1)
+                            name = r.group(2)
+                            extra = r.group(3)
+
+                            if not name:
+                                continue
+
+                            if not s_id:
+                                # Anonymous struct/union
+                                newmember += f"{dtype}{name}{extra}; "
+                            else:
+                                newmember += f"{dtype}{s_id}.{name}{extra}; "
+
+                        else:
+                            arg = arg.strip()
+                            # Handle bitmaps
+                            arg = Re(r':\s*\d+\s*').sub('', arg)
+
+                            # Handle arrays
+                            arg = Re(r'\[.*\]').sub('', arg)
+
+                            # Handle multiple IDs
+                            arg = Re(r'\s*,\s*').sub(',', arg)
+
+
+                            r = Re(r'(.*)\s+([\S+,]+)')
+
+                            if r.search(arg):
+                                dtype = r.group(1)
+                                names = r.group(2)
+                            else:
+                                newmember += f"{arg}; "
+                                continue
+
+                            for name in names.split(','):
+                                name = Re(r'^\s*\**(\S+)\s*').sub(r'\1', name).strip()
+
+                                if not name:
+                                    continue
+
+                                if not s_id:
+                                    # Anonymous struct/union
+                                    newmember += f"{dtype} {name}; "
+                                else:
+                                    newmember += f"{dtype} {s_id}.{name}; "
+
+                members = members.replace(oldmember, newmember)
+
+        # Ignore other nested elements, like enums
+        members = re.sub(r'(\{[^\{\}]*\})', '', members)
+
+        self.create_parameter_list(ln, decl_type, members, ';',
+                                   declaration_name)
+        self.check_sections(ln, declaration_name, decl_type,
+                            self.entry.sectcheck, self.entry.struct_actual)
+
+        # Adjust declaration for better display
+        declaration = Re(r'([\{;])').sub(r'\1\n', declaration)
+        declaration = Re(r'\}\s+;').sub('};', declaration)
+
+        # Better handle inlined enums
+        while True:
+            r = Re(r'(enum\s+\{[^\}]+),([^\n])')
+            if not r.search(declaration):
+                break
+
+            declaration = r.sub(r'\1,\n\2', declaration)
+
+        def_args = declaration.split('\n')
+        level = 1
+        declaration = ""
+        for clause in def_args:
+
+            clause = clause.strip()
+            clause = Re(r'\s+').sub(' ', clause, count=1)
+
+            if not clause:
+                continue
+
+            if '}' in clause and level > 1:
+                level -= 1
+
+            if not Re(r'^\s*#').match(clause):
+                declaration += "\t" * level
+
+            declaration += "\t" + clause + "\n"
+            if "{" in clause and "}" not in clause:
+                level += 1
+
+        self.output_declaration(decl_type, declaration_name,
+                    struct=declaration_name,
+                    module=self.entry.modulename,
+                    definition=declaration,
+                    parameterlist=self.entry.parameterlist,
+                    parameterdescs=self.entry.parameterdescs,
+                    parametertypes=self.entry.parametertypes,
+                    sectionlist=self.entry.sectionlist,
+                    sections=self.entry.sections,
+                    purpose=self.entry.declaration_purpose)
+
+    def dump_enum(self, ln, proto):
+
+        # Ignore members marked private
+        proto = Re(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', flags=re.S).sub('', proto)
+        proto = Re(r'\/\*\s*private:.*}', flags=re.S).sub('}', proto)
+
+        # Strip comments
+        proto = Re(r'\/\*.*?\*\/', flags=re.S).sub('', proto)
+
+        # Strip #define macros inside enums
+        proto = Re(r'#\s*((define|ifdef|if)\s+|endif)[^;]*;', flags=re.S).sub('', proto)
+
+        members = None
+        declaration_name = None
+
+        r = Re(r'typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;')
+        if r.search(proto):
+            declaration_name = r.group(2)
+            members = r.group(1).rstrip()
+        else:
+            r = Re(r'enum\s+(\w*)\s*\{(.*)\}')
+            if r.match(proto):
+                declaration_name = r.group(1)
+                members = r.group(2).rstrip()
+
+        if not members:
+            self.emit_warning(ln, f"{proto}: error: Cannot parse enum!")
+            self.config.errors += 1
+            return
+
+        if self.entry.identifier != declaration_name:
+            if self.entry.identifier == "":
+                self.emit_warning(ln,
+                                  f"{proto}: wrong kernel-doc identifier on prototype")
+            else:
+                self.emit_warning(ln,
+                                  f"expecting prototype for enum {self.entry.identifier}. Prototype was for enum {declaration_name} instead")
+            return
+
+        if not declaration_name:
+            declaration_name = "(anonymous)"
+
+        member_set = set()
+
+        members = Re(r'\([^;]*?[\)]').sub('', members)
+
+        for arg in members.split(','):
+            if not arg:
+                continue
+            arg = Re(r'^\s*(\w+).*').sub(r'\1', arg)
+            self.entry.parameterlist.append(arg)
+            if arg not in self.entry.parameterdescs:
+                self.entry.parameterdescs[arg] = self.undescribed
+                if self.show_warnings("enum", declaration_name):
+                    self.emit_warning(ln,
+                                      f"Enum value '{arg}' not described in enum '{declaration_name}'")
+            member_set.add(arg)
+
+        for k in self.entry.parameterdescs:
+            if k not in member_set:
+                if self.show_warnings("enum", declaration_name):
+                    self.emit_warning(ln,
+                                      f"Excess enum value '%{k}' description in '{declaration_name}'")
+
+        self.output_declaration('enum', declaration_name,
+                   enum=declaration_name,
+                   module=self.config.modulename,
+                   parameterlist=self.entry.parameterlist,
+                   parameterdescs=self.entry.parameterdescs,
+                   sectionlist=self.entry.sectionlist,
+                   sections=self.entry.sections,
+                   purpose=self.entry.declaration_purpose)
+
+    def dump_declaration(self, ln, prototype):
+        if self.entry.decl_type == "enum":
+            self.dump_enum(ln, prototype)
+            return
+
+        if self.entry.decl_type == "typedef":
+            self.dump_typedef(ln, prototype)
+            return
+
+        if self.entry.decl_type in ["union", "struct"]:
+            self.dump_struct(ln, prototype)
+            return
+
+        # TODO: handle other types
+        self.output_declaration(self.entry.decl_type, prototype,
+                   entry=self.entry)
+
+    def dump_function(self, ln, prototype):
+
+        func_macro = False
+        return_type = ''
+        decl_type = 'function'
+
+        # Prefixes that would be removed
+        sub_prefixes = [
+            (r"^static +", "", 0),
+            (r"^extern +", "", 0),
+            (r"^asmlinkage +", "", 0),
+            (r"^inline +", "", 0),
+            (r"^__inline__ +", "", 0),
+            (r"^__inline +", "", 0),
+            (r"^__always_inline +", "", 0),
+            (r"^noinline +", "", 0),
+            (r"^__FORTIFY_INLINE +", "", 0),
+            (r"__init +", "", 0),
+            (r"__init_or_module +", "", 0),
+            (r"__deprecated +", "", 0),
+            (r"__flatten +", "", 0),
+            (r"__meminit +", "", 0),
+            (r"__must_check +", "", 0),
+            (r"__weak +", "", 0),
+            (r"__sched +", "", 0),
+            (r"_noprof", "", 0),
+            (r"__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +", "", 0),
+            (r"__(?:re)?alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) +", "", 0),
+            (r"__diagnose_as\s*\(\s*\S+\s*(?:,\s*\d+\s*)*\) +", "", 0),
+            (r"DECL_BUCKET_PARAMS\s*\(\s*(\S+)\s*,\s*(\S+)\s*\)", r"\1, \2", 0),
+            (r"__attribute_const__ +", "", 0),
+
+            # It seems that Python support for re.X is broken:
+            # At least for me (Python 3.13), this didn't work
+#            (r"""
+#              __attribute__\s*\(\(
+#                (?:
+#                    [\w\s]+          # attribute name
+#                    (?:\([^)]*\))?   # attribute arguments
+#                    \s*,?            # optional comma at the end
+#                )+
+#              \)\)\s+
+#             """, "", re.X),
+
+            # So, remove whitespaces and comments from it
+            (r"__attribute__\s*\(\((?:[\w\s]+(?:\([^)]*\))?\s*,?)+\)\)\s+", "", 0),
+        ]
+
+        for search, sub, flags in sub_prefixes:
+            prototype = Re(search, flags).sub(sub, prototype)
+
+        # Macros are a special case, as they change the prototype format
+        new_proto = Re(r"^#\s*define\s+").sub("", prototype)
+        if new_proto != prototype:
+            is_define_proto = True
+            prototype = new_proto
+        else:
+            is_define_proto = False
+
+        # Yes, this truly is vile.  We are looking for:
+        # 1. Return type (may be nothing if we're looking at a macro)
+        # 2. Function name
+        # 3. Function parameters.
+        #
+        # All the while we have to watch out for function pointer parameters
+        # (which IIRC is what the two sections are for), C types (these
+        # regexps don't even start to express all the possibilities), and
+        # so on.
+        #
+        # If you mess with these regexps, it's a good idea to check that
+        # the following functions' documentation still comes out right:
+        # - parport_register_device (function pointer parameters)
+        # - atomic_set (macro)
+        # - pci_match_device, __copy_to_user (long return type)
+
+        name = r'[a-zA-Z0-9_~:]+'
+        prototype_end1 = r'[^\(]*'
+        prototype_end2 = r'[^\{]*'
+        prototype_end = fr'\(({prototype_end1}|{prototype_end2})\)'
+
+        # Besides compiling, Perl qr{[\w\s]+} works as a non-capturing group.
+        # So, this needs to be mapped in Python with (?:...)? or (?:...)+
+
+        type1 = r'(?:[\w\s]+)?'
+        type2 = r'(?:[\w\s]+\*+)+'
+
+        found = False
+
+        if is_define_proto:
+            r = Re(r'^()(' + name + r')\s+')
+
+            if r.search(prototype):
+                return_type = ''
+                declaration_name = r.group(2)
+                func_macro = True
+
+                found = True
+
+        if not found:
+            patterns = [
+                rf'^()({name})\s*{prototype_end}',
+                rf'^({type1})\s+({name})\s*{prototype_end}',
+                rf'^({type2})\s*({name})\s*{prototype_end}',
+            ]
+
+            for p in patterns:
+                r = Re(p)
+
+                if r.match(prototype):
+
+                    return_type = r.group(1)
+                    declaration_name = r.group(2)
+                    args = r.group(3)
+
+                    self.create_parameter_list(ln, decl_type, args, ',',
+                                               declaration_name)
+
+                    found = True
+                    break
+        if not found:
+            self.emit_warning(ln,
+                              f"cannot understand function prototype: '{prototype}'")
+            return
+
+        if self.entry.identifier != declaration_name:
+            self.emit_warning(ln,
+                              f"expecting prototype for {self.entry.identifier}(). Prototype was for {declaration_name}() instead")
+            return
+
+        prms = " ".join(self.entry.parameterlist)
+        self.check_sections(ln, declaration_name, "function",
+                            self.entry.sectcheck, prms)
+
+        self.check_return_section(ln, declaration_name, return_type)
+
+        if 'typedef' in return_type:
+            self.output_declaration(decl_type, declaration_name,
+                       function=declaration_name,
+                       typedef=True,
+                       module=self.config.modulename,
+                       functiontype=return_type,
+                       parameterlist=self.entry.parameterlist,
+                       parameterdescs=self.entry.parameterdescs,
+                       parametertypes=self.entry.parametertypes,
+                       sectionlist=self.entry.sectionlist,
+                       sections=self.entry.sections,
+                       purpose=self.entry.declaration_purpose,
+                       func_macro=func_macro)
+        else:
+            self.output_declaration(decl_type, declaration_name,
+                       function=declaration_name,
+                       typedef=False,
+                       module=self.config.modulename,
+                       functiontype=return_type,
+                       parameterlist=self.entry.parameterlist,
+                       parameterdescs=self.entry.parameterdescs,
+                       parametertypes=self.entry.parametertypes,
+                       sectionlist=self.entry.sectionlist,
+                       sections=self.entry.sections,
+                       purpose=self.entry.declaration_purpose,
+                       func_macro=func_macro)
+
+    def dump_typedef(self, ln, proto):
+        typedef_type = r'((?:\s+[\w\*]+\b){1,8})\s*'
+        typedef_ident = r'\*?\s*(\w\S+)\s*'
+        typedef_args = r'\s*\((.*)\);'
+
+        typedef1 = Re(r'typedef' + typedef_type + r'\(' + typedef_ident + r'\)' + typedef_args)
+        typedef2 = Re(r'typedef' + typedef_type + typedef_ident + typedef_args)
+
+        # Strip comments
+        proto = Re(r'/\*.*?\*/', flags=re.S).sub('', proto)
+
+        # Parse function typedef prototypes
+        for r in [typedef1, typedef2]:
+            if not r.match(proto):
+                continue
+
+            return_type = r.group(1).strip()
+            declaration_name = r.group(2)
+            args = r.group(3)
+
+            if self.entry.identifier != declaration_name:
+                self.emit_warning(ln,
+                                  f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
+                return
+
+            decl_type = 'function'
+            self.create_parameter_list(ln, decl_type, args, ',', declaration_name)
+
+            self.output_declaration(decl_type, declaration_name,
+                       function=declaration_name,
+                       typedef=True,
+                       module=self.entry.modulename,
+                       functiontype=return_type,
+                       parameterlist=self.entry.parameterlist,
+                       parameterdescs=self.entry.parameterdescs,
+                       parametertypes=self.entry.parametertypes,
+                       sectionlist=self.entry.sectionlist,
+                       sections=self.entry.sections,
+                       purpose=self.entry.declaration_purpose)
+            return
+
+        # Handle nested parentheses or brackets
+        r = Re(r'(\(*.\)\s*|\[*.\]\s*);$')
+        while r.search(proto):
+            proto = r.sub('', proto)
+
+        # Parse simple typedefs
+        r = Re(r'typedef.*\s+(\w+)\s*;')
+        if r.match(proto):
+            declaration_name = r.group(1)
+
+            if self.entry.identifier != declaration_name:
+                self.emit_warning(ln, f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
+                return
+
+            self.output_declaration('typedef', declaration_name,
+                       typedef=declaration_name,
+                       module=self.entry.modulename,
+                       sectionlist=self.entry.sectionlist,
+                       sections=self.entry.sections,
+                       purpose=self.entry.declaration_purpose)
+            return
+
+        self.emit_warning(ln, "error: Cannot parse typedef!")
+        self.config.errors += 1
+
+    @staticmethod
+    def process_export(function_table, line):
+        """
+        process EXPORT_SYMBOL* tags
+
+        This method is called both internally and externally, so, it
+        doesn't use self.
+        """
+
+        if export_symbol.search(line):
+            symbol = export_symbol.group(2)
+            function_table.add(symbol)
+
+        if export_symbol_ns.search(line):
+            symbol = export_symbol_ns.group(2)
+            function_table.add(symbol)
+
+    def process_normal(self, ln, line):
+        """
+        STATE_NORMAL: looking for the /** to begin everything.
+        """
+
+        if not doc_start.match(line):
+            return
+
+        # start a new entry
+        self.reset_state(ln + 1)
+        self.entry.in_doc_sect = False
+
+        # next line is always the function name
+        self.state = self.STATE_NAME
+
+    def process_name(self, ln, line):
+        """
+        STATE_NAME: Looking for the "name - description" line
+        """
+
+        if doc_block.search(line):
+            self.entry.new_start_line = ln
+
+            if not doc_block.group(1):
+                self.entry.section = self.section_intro
+            else:
+                self.entry.section = doc_block.group(1)
+
+            self.state = self.STATE_DOCBLOCK
+            return
+
+        if doc_decl.search(line):
+            self.entry.identifier = doc_decl.group(1)
+            self.entry.is_kernel_comment = False
+
+            decl_start = str(doc_com)       # comment block asterisk
+            fn_type = r"(?:\w+\s*\*\s*)?"  # type (for non-functions)
+            parenthesis = r"(?:\(\w*\))?"   # optional parenthesis on function
+            decl_end = r"(?:[-:].*)"         # end of the name part
+
+            # test for pointer declaration type, foo * bar() - desc
+            r = Re(fr"^{decl_start}([\w\s]+?){parenthesis}?\s*{decl_end}?$")
+            if r.search(line):
+                self.entry.identifier = r.group(1)
+
+            # Test for data declaration
+            r = Re(r"^\s*\*?\s*(struct|union|enum|typedef)\b\s*(\w*)")
+            if r.search(line):
+                self.entry.decl_type = r.group(1)
+                self.entry.identifier = r.group(2)
+                self.entry.is_kernel_comment = True
+            else:
+                # Look for foo() or static void foo() - description;
+                # or misspelt identifier
+
+                r1 = Re(fr"^{decl_start}{fn_type}(\w+)\s*{parenthesis}\s*{decl_end}?$")
+                r2 = Re(fr"^{decl_start}{fn_type}(\w+[^-:]*){parenthesis}\s*{decl_end}$")
+
+                for r in [r1, r2]:
+                    if r.search(line):
+                        self.entry.identifier = r.group(1)
+                        self.entry.decl_type = "function"
+
+                        r = Re(r"define\s+")
+                        self.entry.identifier = r.sub("", self.entry.identifier)
+                        self.entry.is_kernel_comment = True
+                        break
+
+            self.entry.identifier = self.entry.identifier.strip(" ")
+
+            self.state = self.STATE_BODY
+
+            # if there's no @param blocks need to set up default section here
+            self.entry.section = self.section_default
+            self.entry.new_start_line = ln + 1
+
+            r = Re("[-:](.*)")
+            if r.search(line):
+                # strip leading/trailing/multiple spaces
+                self.entry.descr = r.group(1).strip(" ")
+
+                r = Re(r"\s+")
+                self.entry.descr = r.sub(" ", self.entry.descr)
+                self.entry.declaration_purpose = self.entry.descr
+                self.state = self.STATE_BODY_MAYBE
+            else:
+                self.entry.declaration_purpose = ""
+
+            if not self.entry.is_kernel_comment:
+                self.emit_warning(ln,
+                                  f"This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n{line}")
+                self.state = self.STATE_NORMAL
+
+            if not self.entry.declaration_purpose and self.config.wshort_desc:
+                self.emit_warning(ln,
+                                  f"missing initial short description on line:\n{line}")
+
+            if not self.entry.identifier and self.entry.decl_type != "enum":
+                self.emit_warning(ln,
+                                  f"wrong kernel-doc identifier on line:\n{line}")
+                self.state = self.STATE_NORMAL
+
+            if self.config.verbose:
+                self.emit_warning(ln,
+                                  f"Scanning doc for {self.entry.decl_type} {self.entry.identifier}",
+                             warning=False)
+
+            return
+
+        # Failed to find an identifier. Emit a warning
+        self.emit_warning(ln, f"Cannot find identifier on line:\n{line}")
+
+    def process_body(self, ln, line):
+        """
+        STATE_BODY and STATE_BODY_MAYBE: the bulk of a kerneldoc comment.
+        """
+
+        if self.state == self.STATE_BODY_WITH_BLANK_LINE:
+            r = Re(r"\s*\*\s?\S")
+            if r.match(line):
+                self.dump_section()
+                self.entry.section = self.section_default
+                self.entry.new_start_line = line
+                self.entry.contents = ""
+
+        if doc_sect.search(line):
+            self.entry.in_doc_sect = True
+            newsection = doc_sect.group(1)
+
+            if newsection.lower() in ["description", "context"]:
+                newsection = newsection.title()
+
+            # Special case: @return is a section, not a param description
+            if newsection.lower() in ["@return", "@returns",
+                                    "return", "returns"]:
+                newsection = "Return"
+
+            # Perl kernel-doc has a check here for contents before sections.
+            # the logic there is always false, as in_doc_sect variable is
+            # always true. So, just don't implement Wcontents_before_sections
+
+            # .title()
+            newcontents = doc_sect.group(2)
+            if not newcontents:
+                newcontents = ""
+
+            if self.entry.contents.strip("\n"):
+                self.dump_section()
+
+            self.entry.new_start_line = ln
+            self.entry.section = newsection
+            self.entry.leading_space = None
+
+            self.entry.contents = newcontents.lstrip()
+            if self.entry.contents:
+                self.entry.contents += "\n"
+
+            self.state = self.STATE_BODY
+            return
+
+        if doc_end.search(line):
+            if self.entry.contents.strip("\n"):
+                self.dump_section()
+
+            # Look for doc_com + <text> + doc_end:
+            r = Re(r'\s*\*\s*[a-zA-Z_0-9:\.]+\*/')
+            if r.match(line):
+                self.emit_warning(ln, f"suspicious ending line: {line}")
+
+            self.entry.prototype = ""
+            self.entry.new_start_line = ln + 1
+
+            self.state = self.STATE_PROTO
+            return
+
+        if doc_content.search(line):
+            cont = doc_content.group(1)
+
+            if cont == "":
+                if self.entry.section == self.section_context:
+                    self.dump_section()
+
+                    self.entry.new_start_line = ln
+                    self.state = self.STATE_BODY
+                else:
+                    if self.entry.section != self.section_default:
+                        self.state = self.STATE_BODY_WITH_BLANK_LINE
+                    else:
+                        self.state = self.STATE_BODY
+
+                    self.entry.contents += "\n"
+
+            elif self.state == self.STATE_BODY_MAYBE:
+
+                # Continued declaration purpose
+                self.entry.declaration_purpose = self.entry.declaration_purpose.rstrip()
+                self.entry.declaration_purpose += " " + cont
+
+                r = Re(r"\s+")
+                self.entry.declaration_purpose = r.sub(' ',
+                                                       self.entry.declaration_purpose)
+
+            else:
+                if self.entry.section.startswith('@') or        \
+                   self.entry.section == self.section_context:
+                    if self.entry.leading_space is None:
+                        r = Re(r'^(\s+)')
+                        if r.match(cont):
+                            self.entry.leading_space = len(r.group(1))
+                        else:
+                            self.entry.leading_space = 0
+
+                    # Double-check if leading space are realy spaces
+                    pos = 0
+                    for i in range(0, self.entry.leading_space):
+                        if cont[i] != " ":
+                            break
+                        pos += 1
+
+                    cont = cont[pos:]
+
+                    # NEW LOGIC:
+                    # In case it is different, update it
+                    if self.entry.leading_space != pos:
+                        self.entry.leading_space = pos
+
+                self.entry.contents += cont + "\n"
+            return
+
+        # Unknown line, ignore
+        self.emit_warning(ln, f"bad line: {line}")
+
+    def process_inline(self, ln, line):
+        """STATE_INLINE: docbook comments within a prototype."""
+
+        if self.inline_doc_state == self.STATE_INLINE_NAME and \
+           doc_inline_sect.search(line):
+            self.entry.section = doc_inline_sect.group(1)
+            self.entry.new_start_line = ln
+
+            self.entry.contents = doc_inline_sect.group(2).lstrip()
+            if self.entry.contents != "":
+                self.entry.contents += "\n"
+
+            self.inline_doc_state = self.STATE_INLINE_TEXT
+            # Documentation block end */
+            return
+
+        if doc_inline_end.search(line):
+            if self.entry.contents not in ["", "\n"]:
+                self.dump_section()
+
+            self.state = self.STATE_PROTO
+            self.inline_doc_state = self.STATE_INLINE_NA
+            return
+
+        if doc_content.search(line):
+            if self.inline_doc_state == self.STATE_INLINE_TEXT:
+                self.entry.contents += doc_content.group(1) + "\n"
+                if not self.entry.contents.strip(" ").rstrip("\n"):
+                    self.entry.contents = ""
+
+            elif self.inline_doc_state == self.STATE_INLINE_NAME:
+                self.emit_warning(ln,
+                                  f"Incorrect use of kernel-doc format: {line}")
+
+                self.inline_doc_state = self.STATE_INLINE_ERROR
+
+    def syscall_munge(self, ln, proto):
+        """
+        Handle syscall definitions
+        """
+
+        is_void = False
+
+        # Strip newlines/CR's
+        proto = re.sub(r'[\r\n]+', ' ', proto)
+
+        # Check if it's a SYSCALL_DEFINE0
+        if 'SYSCALL_DEFINE0' in proto:
+            is_void = True
+
+        # Replace SYSCALL_DEFINE with correct return type & function name
+        proto = Re(r'SYSCALL_DEFINE.*\(').sub('long sys_', proto)
+
+        r = Re(r'long\s+(sys_.*?),')
+        if r.search(proto):
+            proto = proto.replace(',', '(', count=1)
+        elif is_void:
+            proto = proto.replace(')', '(void)', count=1)
+
+        # Now delete all of the odd-numbered commas in the proto
+        # so that argument types & names don't have a comma between them
+        count = 0
+        length = len(proto)
+
+        if is_void:
+            length = 0  # skip the loop if is_void
+
+        for ix in range(length):
+            if proto[ix] == ',':
+                count += 1
+                if count % 2 == 1:
+                    proto = proto[:ix] + ' ' + proto[ix+1:]
+
+        return proto
+
+    def tracepoint_munge(self, ln, proto):
+        """
+        Handle tracepoint definitions
+        """
+
+        tracepointname = None
+        tracepointargs = None
+
+        # Match tracepoint name based on different patterns
+        r = Re(r'TRACE_EVENT\((.*?),')
+        if r.search(proto):
+            tracepointname = r.group(1)
+
+        r = Re(r'DEFINE_SINGLE_EVENT\((.*?),')
+        if r.search(proto):
+            tracepointname = r.group(1)
+
+        r = Re(r'DEFINE_EVENT\((.*?),(.*?),')
+        if r.search(proto):
+            tracepointname = r.group(2)
+
+        if tracepointname:
+            tracepointname = tracepointname.lstrip()
+
+        r = Re(r'TP_PROTO\((.*?)\)')
+        if r.search(proto):
+            tracepointargs = r.group(1)
+
+        if not tracepointname or not tracepointargs:
+            self.emit_warning(ln,
+                              f"Unrecognized tracepoint format:\n{proto}\n")
+        else:
+            proto = f"static inline void trace_{tracepointname}({tracepointargs})"
+            self.entry.identifier = f"trace_{self.entry.identifier}"
+
+        return proto
+
+    def process_proto_function(self, ln, line):
+        """Ancillary routine to process a function prototype"""
+
+        # strip C99-style comments to end of line
+        r = Re(r"\/\/.*$", re.S)
+        line = r.sub('', line)
+
+        if Re(r'\s*#\s*define').match(line):
+            self.entry.prototype = line
+        elif line.startswith('#'):
+            # Strip other macros like #ifdef/#ifndef/#endif/...
+            pass
+        else:
+            r = Re(r'([^\{]*)')
+            if r.match(line):
+                self.entry.prototype += r.group(1) + " "
+
+        if '{' in line or ';' in line or Re(r'\s*#\s*define').match(line):
+            # strip comments
+            r = Re(r'/\*.*?\*/')
+            self.entry.prototype = r.sub('', self.entry.prototype)
+
+            # strip newlines/cr's
+            r = Re(r'[\r\n]+')
+            self.entry.prototype = r.sub(' ', self.entry.prototype)
+
+            # strip leading spaces
+            r = Re(r'^\s+')
+            self.entry.prototype = r.sub('', self.entry.prototype)
+
+            # Handle self.entry.prototypes for function pointers like:
+            #       int (*pcs_config)(struct foo)
+
+            r = Re(r'^(\S+\s+)\(\s*\*(\S+)\)')
+            self.entry.prototype = r.sub(r'\1\2', self.entry.prototype)
+
+            if 'SYSCALL_DEFINE' in self.entry.prototype:
+                self.entry.prototype = self.syscall_munge(ln,
+                                                          self.entry.prototype)
+
+            r = Re(r'TRACE_EVENT|DEFINE_EVENT|DEFINE_SINGLE_EVENT')
+            if r.search(self.entry.prototype):
+                self.entry.prototype = self.tracepoint_munge(ln,
+                                                             self.entry.prototype)
+
+            self.dump_function(ln, self.entry.prototype)
+            self.reset_state(ln)
+
+    def process_proto_type(self, ln, line):
+        """Ancillary routine to process a type"""
+
+        # Strip newlines/cr's.
+        line = Re(r'[\r\n]+', re.S).sub(' ', line)
+
+        # Strip leading spaces
+        line = Re(r'^\s+', re.S).sub('', line)
+
+        # Strip trailing spaces
+        line = Re(r'\s+$', re.S).sub('', line)
+
+        # Strip C99-style comments to the end of the line
+        line = Re(r"\/\/.*$", re.S).sub('', line)
+
+        # To distinguish preprocessor directive from regular declaration later.
+        if line.startswith('#'):
+            line += ";"
+
+        r = Re(r'([^\{\};]*)([\{\};])(.*)')
+        while True:
+            if r.search(line):
+                if self.entry.prototype:
+                    self.entry.prototype += " "
+                self.entry.prototype += r.group(1) + r.group(2)
+
+                self.entry.brcount += r.group(2).count('{')
+                self.entry.brcount -= r.group(2).count('}')
+
+                self.entry.brcount = max(self.entry.brcount, 0)
+
+                if r.group(2) == ';' and self.entry.brcount == 0:
+                    self.dump_declaration(ln, self.entry.prototype)
+                    self.reset_state(ln)
+                    break
+
+                line = r.group(3)
+            else:
+                self.entry.prototype += line
+                break
+
+    def process_proto(self, ln, line):
+        """STATE_PROTO: reading a function/whatever prototype."""
+
+        if doc_inline_oneline.search(line):
+            self.entry.section = doc_inline_oneline.group(1)
+            self.entry.contents = doc_inline_oneline.group(2)
+
+            if self.entry.contents != "":
+                self.entry.contents += "\n"
+                self.dump_section(start_new=False)
+
+        elif doc_inline_start.search(line):
+            self.state = self.STATE_INLINE
+            self.inline_doc_state = self.STATE_INLINE_NAME
+
+        elif self.entry.decl_type == 'function':
+            self.process_proto_function(ln, line)
+
+        else:
+            self.process_proto_type(ln, line)
+
+    def process_docblock(self, ln, line):
+        """STATE_DOCBLOCK: within a DOC: block."""
+
+        if doc_end.search(line):
+            self.dump_section()
+            self.output_declaration("doc", None,
+                       sectionlist=self.entry.sectionlist,
+                       sections=self.entry.sections,                    module=self.config.modulename)
+            self.reset_state(ln)
+
+        elif doc_content.search(line):
+            self.entry.contents += doc_content.group(1) + "\n"
+
+    def run(self):
+        """
+        Open and process each line of a C source file.
+        he parsing is controlled via a state machine, and the line is passed
+        to a different process function depending on the state. The process
+        function may update the state as needed.
+        """
+
+        cont = False
+        prev = ""
+        prev_ln = None
+
+        try:
+            with open(self.fname, "r", encoding="utf8",
+                      errors="backslashreplace") as fp:
+                for ln, line in enumerate(fp):
+
+                    line = line.expandtabs().strip("\n")
+
+                    # Group continuation lines on prototypes
+                    if self.state == self.STATE_PROTO:
+                        if line.endswith("\\"):
+                            prev += line.removesuffix("\\")
+                            cont = True
+
+                            if not prev_ln:
+                                prev_ln = ln
+
+                            continue
+
+                        if cont:
+                            ln = prev_ln
+                            line = prev + line
+                            prev = ""
+                            cont = False
+                            prev_ln = None
+
+                    self.config.log.debug("%d %s%s: %s",
+                                          ln, self.st_name[self.state],
+                                          self.st_inline_name[self.inline_doc_state],
+                                          line)
+
+                    # TODO: not all states allow EXPORT_SYMBOL*, so this
+                    # can be optimized later on to speedup parsing
+                    self.process_export(self.config.function_table, line)
+
+                    # Hand this line to the appropriate state handler
+                    if self.state == self.STATE_NORMAL:
+                        self.process_normal(ln, line)
+                    elif self.state == self.STATE_NAME:
+                        self.process_name(ln, line)
+                    elif self.state in [self.STATE_BODY, self.STATE_BODY_MAYBE,
+                                        self.STATE_BODY_WITH_BLANK_LINE]:
+                        self.process_body(ln, line)
+                    elif self.state == self.STATE_INLINE:  # scanning for inline parameters
+                        self.process_inline(ln, line)
+                    elif self.state == self.STATE_PROTO:
+                        self.process_proto(ln, line)
+                    elif self.state == self.STATE_DOCBLOCK:
+                        self.process_docblock(ln, line)
+        except OSError:
+            self.config.log.error(f"Error: Cannot open file {self.fname}")
+            self.config.errors += 1
+
+
+class GlobSourceFiles:
+    """
+    Parse C source code file names and directories via an Interactor.
+
+    """
+
+    def __init__(self, srctree=None, valid_extensions=None):
+        """
+        Initialize valid extensions with a tuple.
+
+        If not defined, assume default C extensions (.c and .h)
+
+        It would be possible to use python's glob function, but it is
+        very slow, and it is not interactive. So, it would wait to read all
+        directories before actually do something.
+
+        So, let's use our own implementation.
+        """
+
+        if not valid_extensions:
+            self.extensions = (".c", ".h")
+        else:
+            self.extensions = valid_extensions
+
+        self.srctree = srctree
+
+    def _parse_dir(self, dirname):
+        """Internal function to parse files recursively"""
+
+        with os.scandir(dirname) as obj:
+            for entry in obj:
+                name = os.path.join(dirname, entry.name)
+
+                if entry.is_dir():
+                    yield from self._parse_dir(name)
+
+                if not entry.is_file():
+                    continue
+
+                basename = os.path.basename(name)
+
+                if not basename.endswith(self.extensions):
+                    continue
+
+                yield name
+
+    def parse_files(self, file_list, file_not_found_cb):
+        for fname in file_list:
+            if self.srctree:
+                f = os.path.join(self.srctree, fname)
+            else:
+                f = fname
+
+            if os.path.isdir(f):
+                yield from self._parse_dir(f)
+            elif os.path.isfile(f):
+                yield f
+            elif file_not_found_cb:
+                file_not_found_cb(fname)
+
+
+class KernelFiles():
+
+    def parse_file(self, fname):
+
+        doc = KernelDoc(self.config, fname)
+        doc.run()
+
+        return doc
+
+    def process_export_file(self, fname):
+        try:
+            with open(fname, "r", encoding="utf8",
+                      errors="backslashreplace") as fp:
+                for line in fp:
+                    KernelDoc.process_export(self.config.function_table, line)
+
+        except IOError:
+            print(f"Error: Cannot open fname {fname}", fname=sys.stderr)
+            self.config.errors += 1
+
+    def file_not_found_cb(self, fname):
+        self.config.log.error("Cannot find file %s", fname)
+        self.config.errors += 1
+
+    def __init__(self, files=None, verbose=False, out_style=None,
+                 werror=False, wreturn=False, wshort_desc=False,
+                 wcontents_before_sections=False,
+                 logger=None, modulename=None, export_file=None):
+        """Initialize startup variables and parse all files"""
+
+
+        if not verbose:
+            verbose = bool(os.environ.get("KBUILD_VERBOSE", 0))
+
+        if not modulename:
+            modulename = "Kernel API"
+
+        dt = datetime.now()
+        if os.environ.get("KBUILD_BUILD_TIMESTAMP", None):
+            # use UTC TZ
+            to_zone = tz.gettz('UTC')
+            dt = dt.astimezone(to_zone)
+
+        if not werror:
+            kcflags = os.environ.get("KCFLAGS", None)
+            if kcflags:
+                match = re.search(r"(\s|^)-Werror(\s|$)/", kcflags)
+                if match:
+                    werror = True
+
+            # reading this variable is for backwards compat just in case
+            # someone was calling it with the variable from outside the
+            # kernel's build system
+            kdoc_werror = os.environ.get("KDOC_WERROR", None)
+            if kdoc_werror:
+                werror = kdoc_werror
+
+        # Set global config data used on all files
+        self.config = argparse.Namespace
+
+        self.config.verbose = verbose
+        self.config.werror = werror
+        self.config.wreturn = wreturn
+        self.config.wshort_desc = wshort_desc
+        self.config.wcontents_before_sections = wcontents_before_sections
+        self.config.modulename = modulename
+
+        self.config.function_table = set()
+        self.config.source_map = {}
+
+        if not logger:
+            self.config.log = logging.getLogger("kernel-doc")
+        else:
+            self.config.log = logger
+
+        self.config.kernel_version = os.environ.get("KERNELVERSION",
+                                                    "unknown kernel version'")
+        self.config.src_tree = os.environ.get("SRCTREE", None)
+
+        self.out_style = out_style
+        self.export_file = export_file
+
+        # Initialize internal variables
+
+        self.config.errors = 0
+        self.results = []
+
+        self.file_list = files
+        self.files = set()
+
+    def parse(self):
+        """
+        Parse all files
+        """
+
+        glob = GlobSourceFiles(srctree=self.config.src_tree)
+
+        # Let's use a set here to avoid duplicating files
+
+        for fname in glob.parse_files(self.file_list, self.file_not_found_cb):
+            if fname in self.files:
+                continue
+
+            self.files.add(fname)
+
+            res = self.parse_file(fname)
+            self.results.append((res.fname, res.entries))
+
+        if not self.files:
+            sys.exit(1)
+
+        # If a list of export files was provided, parse EXPORT_SYMBOL*
+        # from the ones not already parsed
+
+        if self.export_file:
+            files = self.files
+
+            glob = GlobSourceFiles(srctree=self.config.src_tree)
+
+            for fname in glob.parse_files(self.export_file,
+                                          self.file_not_found_cb):
+                if fname not in files:
+                    files.add(fname)
+
+                    self.process_export_file(fname)
+
+    def out_msg(self, fname, name, arg):
+        # TODO: filter out unwanted parts
+
+        return self.out_style.msg(fname, name, arg)
+
+    def msg(self, enable_lineno=False, export=False, internal=False,
+            symbol=None, nosymbol=None):
+
+        function_table = self.config.function_table
+
+        if symbol:
+            for s in symbol:
+                function_table.add(s)
+
+        # Output none mode: only warnings will be shown
+        if not self.out_style:
+            return
+
+        self.out_style.set_config(self.config)
+
+        self.out_style.set_filter(export, internal, symbol, nosymbol,
+                                  function_table, enable_lineno)
+
+        for fname, arg_tuple in self.results:
+            for name, arg in arg_tuple:
+                if self.out_msg(fname, name, arg):
+                    ln = arg.get("ln", 0)
+                    dtype = arg.get('type', "")
+
+                    self.config.log.warning("%s:%d Can't handle %s",
+                                            fname, ln, dtype)
+
+
+class OutputFormat:
+    # output mode.
+    OUTPUT_ALL          = 0 # output all symbols and doc sections
+    OUTPUT_INCLUDE      = 1 # output only specified symbols
+    OUTPUT_EXPORTED     = 2 # output exported symbols
+    OUTPUT_INTERNAL     = 3 # output non-exported symbols
+
+    # Virtual member to be overriden at the  inherited classes
+    highlights = []
+
+    def __init__(self):
+        """Declare internal vars and set mode to OUTPUT_ALL"""
+
+        self.out_mode = self.OUTPUT_ALL
+        self.enable_lineno = None
+        self.nosymbol = {}
+        self.symbol = None
+        self.function_table = set()
+        self.config = None
+
+    def set_config(self, config):
+        self.config = config
+
+    def set_filter(self, export, internal, symbol, nosymbol, function_table,
+                   enable_lineno):
+        """
+        Initialize filter variables according with the requested mode.
+
+        Only one choice is valid between export, internal and symbol.
+
+        The nosymbol filter can be used on all modes.
+        """
+
+        self.enable_lineno = enable_lineno
+
+        if symbol:
+            self.out_mode = self.OUTPUT_INCLUDE
+            function_table = symbol
+        elif export:
+            self.out_mode = self.OUTPUT_EXPORTED
+        elif internal:
+            self.out_mode = self.OUTPUT_INTERNAL
+        else:
+            self.out_mode = self.OUTPUT_ALL
+
+        if nosymbol:
+            self.nosymbol = set(nosymbol)
+
+        if function_table:
+            self.function_table = function_table
+
+    def highlight_block(self, block):
+        """
+        Apply the RST highlights to a sub-block of text.
+        """
+
+        for r, sub in self.highlights:
+            block = r.sub(sub, block)
+
+        return block
+
+    def check_doc(self, name):
+        """Check if DOC should be output"""
+
+        if self.out_mode == self.OUTPUT_ALL:
+            return True
+
+        if self.out_mode == self.OUTPUT_INCLUDE:
+            if name in self.nosymbol:
+                return False
+
+            if name in self.function_table:
+                return True
+
+        return False
+
+    def check_declaration(self, dtype, name):
+        if name in self.nosymbol:
+            return False
+
+        if self.out_mode == self.OUTPUT_ALL:
+            return True
+
+        if self.out_mode in [ self.OUTPUT_INCLUDE, self.OUTPUT_EXPORTED ]:
+            if name in self.function_table:
+                return True
+
+        if self.out_mode == self.OUTPUT_INTERNAL:
+            if dtype != "function":
+                return True
+
+            if name not in self.function_table:
+                return True
+
+        return False
+
+    def check_function(self, fname, name, args):
+        return True
+
+    def check_enum(self, fname, name, args):
+        return True
+
+    def check_typedef(self, fname, name, args):
+        return True
+
+    def msg(self, fname, name, args):
+
+        dtype = args.get('type', "")
+
+        if dtype == "doc":
+            self.out_doc(fname, name, args)
+            return False
+
+        if not self.check_declaration(dtype, name):
+            return False
+
+        if dtype == "function":
+            self.out_function(fname, name, args)
+            return False
+
+        if dtype == "enum":
+            self.out_enum(fname, name, args)
+            return False
+
+        if dtype == "typedef":
+            self.out_typedef(fname, name, args)
+            return False
+
+        if dtype in ["struct", "union"]:
+            self.out_struct(fname, name, args)
+            return False
+
+        # Warn if some type requires an output logic
+        self.config.log.warning("doesn't now how to output '%s' block",
+                                dtype)
+
+        return True
+
+    # Virtual methods to be overridden by inherited classes
+    def out_doc(self, fname, name, args):
+        pass
+
+    def out_function(self, fname, name, args):
+        pass
+
+    def out_enum(self, fname, name, args):
+        pass
+
+    def out_typedef(self, fname, name, args):
+        pass
+
+    def out_struct(self, fname, name, args):
+        pass
+
+
+class RestFormat(OutputFormat):
+    # """Consts and functions used by ReST output"""
+
+    highlights = [
+        (type_constant, r"``\1``"),
+        (type_constant2, r"``\1``"),
+
+        # Note: need to escape () to avoid func matching later
+        (type_member_func, r":c:type:`\1\2\3\\(\\) <\1>`"),
+        (type_member, r":c:type:`\1\2\3 <\1>`"),
+        (type_fp_param, r"**\1\\(\\)**"),
+        (type_fp_param2, r"**\1\\(\\)**"),
+        (type_func, r"\1()"),
+        (type_enum, r":c:type:`\1 <\2>`"),
+        (type_struct, r":c:type:`\1 <\2>`"),
+        (type_typedef, r":c:type:`\1 <\2>`"),
+        (type_union, r":c:type:`\1 <\2>`"),
+
+        # in rst this can refer to any type
+        (type_fallback, r":c:type:`\1`"),
+        (type_param_ref, r"**\1\2**")
+    ]
+    blankline = "\n"
+
+    sphinx_literal = Re(r'^[^.].*::$', cache=False)
+    sphinx_cblock = Re(r'^\.\.\ +code-block::', cache=False)
+
+    def __init__(self):
+        """
+        Creates class variables.
+
+        Not really mandatory, but it is a good coding style and makes
+        pylint happy.
+        """
+
+        super().__init__()
+        self.lineprefix = ""
+
+    def print_lineno (self, ln):
+        """Outputs a line number"""
+
+        if self.enable_lineno and ln:
+            print(f".. LINENO {ln}")
+
+    def output_highlight(self, args):
+        input_text = args
+        output = ""
+        in_literal = False
+        litprefix = ""
+        block = ""
+
+        for line in input_text.strip("\n").split("\n"):
+
+            # If we're in a literal block, see if we should drop out of it.
+            # Otherwise, pass the line straight through unmunged.
+            if in_literal:
+                if line.strip():  # If the line is not blank
+                    # If this is the first non-blank line in a literal block,
+                    # figure out the proper indent.
+                    if not litprefix:
+                        r = Re(r'^(\s*)')
+                        if r.match(line):
+                            litprefix = '^' + r.group(1)
+                        else:
+                            litprefix = ""
+
+                        output += line + "\n"
+                    elif not Re(litprefix).match(line):
+                        in_literal = False
+                    else:
+                        output += line + "\n"
+                else:
+                    output += line + "\n"
+
+            # Not in a literal block (or just dropped out)
+            if not in_literal:
+                block += line + "\n"
+                if self.sphinx_literal.match(line) or self.sphinx_cblock.match(line):
+                    in_literal = True
+                    litprefix = ""
+                    output += self.highlight_block(block)
+                    block = ""
+
+        # Handle any remaining block
+        if block:
+            output += self.highlight_block(block)
+
+        # Print the output with the line prefix
+        for line in output.strip("\n").split("\n"):
+            print(self.lineprefix + line)
+
+    def out_section(self, args, out_reference=False):
+        """
+        Outputs a block section.
+
+        This could use some work; it's used to output the DOC: sections, and
+        starts by putting out the name of the doc section itself, but that
+        tends to duplicate a header already in the template file.
+        """
+
+        sectionlist = args.get('sectionlist', [])
+        sections = args.get('sections', {})
+        section_start_lines = args.get('section_start_lines', {})
+
+        for section in sectionlist:
+            # Skip sections that are in the nosymbol_table
+            if section in self.nosymbol:
+                continue
+
+            if not self.out_mode == self.OUTPUT_INCLUDE:
+                if out_reference:
+                    print(f".. _{section}:\n")
+
+                if not self.symbol:
+                    print(f'{self.lineprefix}**{section}**\n')
+
+            self.print_lineno(section_start_lines.get(section, 0))
+            self.output_highlight(sections[section])
+            print()
+        print()
+
+    def out_doc(self, fname, name, args):
+        if not self.check_doc(name):
+            return
+
+        self.out_section(args, out_reference=True)
+
+    def out_function(self, fname, name, args):
+
+        oldprefix = self.lineprefix
+        signature = ""
+
+        func_macro = args.get('func_macro', False)
+        if func_macro:
+            signature = args['function']
+        else:
+            if args.get('functiontype'):
+                signature = args['functiontype'] + " "
+            signature += args['function'] + " ("
+
+        parameterlist = args.get('parameterlist', [])
+        parameterdescs = args.get('parameterdescs', {})
+        parameterdesc_start_lines = args.get('parameterdesc_start_lines', {})
+
+        ln = args.get('ln', 0)
+
+        count = 0
+        for parameter in parameterlist:
+            if count != 0:
+                signature += ", "
+            count += 1
+            dtype = args['parametertypes'].get(parameter, "")
+
+            if function_pointer.search(dtype):
+                signature += function_pointer.group(1) + parameter + function_pointer.group(3)
+            else:
+                signature += dtype
+
+        if not func_macro:
+            signature += ")"
+
+        if args.get('typedef') or not args.get('functiontype'):
+            print(f".. c:macro:: {args['function']}\n")
+
+            if args.get('typedef'):
+                self.print_lineno(ln)
+                print("   **Typedef**: ", end="")
+                self.lineprefix = ""
+                self.output_highlight(args.get('purpose', ""))
+                print("\n\n**Syntax**\n")
+                print(f"  ``{signature}``\n")
+            else:
+                print(f"``{signature}``\n")
+        else:
+            print(f".. c:function:: {signature}\n")
+
+        if not args.get('typedef'):
+            self.print_lineno(ln)
+            self.lineprefix = "   "
+            self.output_highlight(args.get('purpose', ""))
+            print()
+
+        # Put descriptive text into a container (HTML <div>) to help set
+        # function prototypes apart
+        self.lineprefix = "  "
+
+        if parameterlist:
+            print(".. container:: kernelindent\n")
+            print(f"{self.lineprefix}**Parameters**\n")
+
+        for parameter in parameterlist:
+            parameter_name = Re(r'\[.*').sub('', parameter)
+            dtype = args['parametertypes'].get(parameter, "")
+
+            if dtype:
+                print(f"{self.lineprefix}``{dtype}``")
+            else:
+                print(f"{self.lineprefix}``{parameter}``")
+
+            self.print_lineno(parameterdesc_start_lines.get(parameter_name, 0))
+
+            self.lineprefix = "    "
+            if parameter_name in parameterdescs and \
+               parameterdescs[parameter_name] != KernelDoc.undescribed:
+
+                self.output_highlight(parameterdescs[parameter_name])
+                print()
+            else:
+                print(f"{self.lineprefix}*undescribed*\n")
+            self.lineprefix = "  "
+
+        self.out_section(args)
+        self.lineprefix = oldprefix
+
+    def out_enum(self, fname, name, args):
+
+        oldprefix = self.lineprefix
+        name = args.get('enum', '')
+        parameterlist = args.get('parameterlist', [])
+        parameterdescs = args.get('parameterdescs', {})
+        ln = args.get('ln', 0)
+
+        print(f"\n\n.. c:enum:: {name}\n")
+
+        self.print_lineno(ln)
+        self.lineprefix = "  "
+        self.output_highlight(args.get('purpose', ''))
+        print()
+
+        print(".. container:: kernelindent\n")
+        outer = self.lineprefix + "  "
+        self.lineprefix = outer + "  "
+        print(f"{outer}**Constants**\n")
+
+        for parameter in parameterlist:
+            print(f"{outer}``{parameter}``")
+
+            if parameterdescs.get(parameter, '') != KernelDoc.undescribed:
+                self.output_highlight(parameterdescs[parameter])
+            else:
+                print(f"{self.lineprefix}*undescribed*\n")
+            print()
+
+        self.lineprefix = oldprefix
+        self.out_section(args)
+
+    def out_typedef(self, fname, name, args):
+
+        oldprefix = self.lineprefix
+        name = args.get('typedef', '')
+        ln = args.get('ln', 0)
+
+        print(f"\n\n.. c:type:: {name}\n")
+
+        self.print_lineno(ln)
+        self.lineprefix = "   "
+
+        self.output_highlight(args.get('purpose', ''))
+
+        print()
+
+        self.lineprefix = oldprefix
+        self.out_section(args)
+
+    def out_struct(self, fname, name, args):
+
+        name = args.get('struct', "")
+        purpose = args.get('purpose', "")
+        declaration = args.get('definition', "")
+        dtype = args.get('type', "struct")
+        ln = args.get('ln', 0)
+
+        parameterlist = args.get('parameterlist', [])
+        parameterdescs = args.get('parameterdescs', {})
+        parameterdesc_start_lines = args.get('parameterdesc_start_lines', {})
+
+        print(f"\n\n.. c:{dtype}:: {name}\n")
+
+        self.print_lineno(ln)
+
+        oldprefix = self.lineprefix
+        self.lineprefix += "  "
+
+        self.output_highlight(purpose)
+        print()
+
+        print(".. container:: kernelindent\n")
+        print(f"{self.lineprefix}**Definition**::\n")
+
+        self.lineprefix = self.lineprefix + "  "
+
+        declaration = declaration.replace("\t", self.lineprefix)
+
+        print(f"{self.lineprefix}{dtype} {name}" + ' {')
+        print(f"{declaration}{self.lineprefix}" + "};\n")
+
+        self.lineprefix = "  "
+        print(f"{self.lineprefix}**Members**\n")
+        for parameter in parameterlist:
+            if not parameter or parameter.startswith("#"):
+                continue
+
+            parameter_name = parameter.split("[", maxsplit=1)[0]
+
+            if parameterdescs.get(parameter_name) == KernelDoc.undescribed:
+                continue
+
+            self.print_lineno(parameterdesc_start_lines.get(parameter_name, 0))
+
+            print(f"{self.lineprefix}``{parameter}``")
+
+            self.lineprefix = "    "
+            self.output_highlight(parameterdescs[parameter_name])
+            self.lineprefix = "  "
+
+            print()
+
+        print()
+
+        self.lineprefix = oldprefix
+        self.out_section(args)
+
+
+class ManFormat(OutputFormat):
+    """Consts and functions used by man pages output"""
+
+    highlights = (
+        (type_constant, r"\1"),
+        (type_constant2, r"\1"),
+        (type_func, r"\\fB\1\\fP"),
+        (type_enum, r"\\fI\1\\fP"),
+        (type_struct, r"\\fI\1\\fP"),
+        (type_typedef, r"\\fI\1\\fP"),
+        (type_union, r"\\fI\1\\fP"),
+        (type_param, r"\\fI\1\\fP"),
+        (type_param_ref, r"\\fI\1\2\\fP"),
+        (type_member, r"\\fI\1\2\3\\fP"),
+        (type_fallback, r"\\fI\1\\fP")
+    )
+    blankline = ""
+
+    def __init__(self):
+        """
+        Creates class variables.
+
+        Not really mandatory, but it is a good coding style and makes
+        pylint happy.
+        """
+
+        super().__init__()
+
+        dt = datetime.now()
+        if os.environ.get("KBUILD_BUILD_TIMESTAMP", None):
+            # use UTC TZ
+            to_zone = tz.gettz('UTC')
+            dt = dt.astimezone(to_zone)
+
+        self.man_date = dt.strftime("%B %Y")
+
+    def output_highlight(self, block):
+
+        contents = self.highlight_block(block)
+
+        if isinstance(contents, list):
+            contents = "\n".join(contents)
+
+        for line in contents.strip("\n").split("\n"):
+            line = Re(r"^\s*").sub("", line)
+
+            if line and line[0] == ".":
+                print("\\&" + line)
+            else:
+                print(line)
+
+    def out_doc(self, fname, name, args):
+        module = args.get('module')
+        sectionlist = args.get('sectionlist', [])
+        sections = args.get('sections', {})
+
+        print(f'.TH "{module}" 9 "{module}" "{self.man_date}" "API Manual" LINUX')
+
+        for section in sectionlist:
+            print(f'.SH "{section}"')
+            self.output_highlight(sections.get(section))
+
+    def out_function(self, fname, name, args):
+        """output function in man"""
+
+        parameterlist = args.get('parameterlist', [])
+        parameterdescs = args.get('parameterdescs', {})
+        sectionlist = args.get('sectionlist', [])
+        sections = args.get('sections', {})
+
+        print(f'.TH "{args['function']}" 9 "{args['function']}" "{self.man_date}" "Kernel Hacker\'s Manual" LINUX')
+
+        print(".SH NAME")
+        print(f"{args['function']} \\- {args['purpose']}")
+
+        print(".SH SYNOPSIS")
+        if args.get('functiontype', ''):
+            print(f'.B "{args['functiontype']}" {args['function']}')
+        else:
+            print(f'.B "{args['function']}')
+
+        count = 0
+        parenth = "("
+        post = ","
+
+        for parameter in parameterlist:
+            if count == len(parameterlist) - 1:
+                post = ");"
+
+            dtype = args['parametertypes'].get(parameter, "")
+            if function_pointer.match(dtype):
+                # Pointer-to-function
+                print(f'".BI "{parenth}{function_pointer.group(1)}" " ") ({function_pointer.group(2)}){post}"')
+            else:
+                dtype = Re(r'([^\*])$').sub(r'\1 ', dtype)
+
+                print(f'.BI "{parenth}{dtype}"  "{post}"')
+            count += 1
+            parenth = ""
+
+        if parameterlist:
+            print(".SH ARGUMENTS")
+
+        for parameter in parameterlist:
+            parameter_name = re.sub(r'\[.*', '', parameter)
+
+            print(f'.IP "{parameter}" 12')
+            self.output_highlight(parameterdescs.get(parameter_name, ""))
+
+        for section in sectionlist:
+            print(f'.SH "{section.upper()}"')
+            self.output_highlight(sections[section])
+
+    def out_enum(self, fname, name, args):
+
+        name = args.get('enum', '')
+        parameterlist = args.get('parameterlist', [])
+        sectionlist = args.get('sectionlist', [])
+        sections = args.get('sections', {})
+
+        print(f'.TH "{args['module']}" 9 "enum {args['enum']}" "{self.man_date}" "API Manual" LINUX')
+
+        print(".SH NAME")
+        print(f"enum {args['enum']} \\- {args['purpose']}")
+
+        print(".SH SYNOPSIS")
+        print(f"enum {args['enum']}" + " {")
+
+        count = 0
+        for parameter in parameterlist:
+            print(f'.br\n.BI "    {parameter}"')
+            if count == len(parameterlist) - 1:
+                print("\n};")
+            else:
+                print(", \n.br")
+
+            count += 1
+
+        print(".SH Constants")
+
+        for parameter in parameterlist:
+            parameter_name = Re(r'\[.*').sub('', parameter)
+            print(f'.IP "{parameter}" 12')
+            self.output_highlight(args['parameterdescs'].get(parameter_name, ""))
+
+        for section in sectionlist:
+            print(f'.SH "{section}"')
+            self.output_highlight(sections[section])
+
+    def out_typedef(self, fname, name, args):
+        module = args.get('module')
+        typedef = args.get('typedef')
+        purpose = args.get('purpose')
+        sectionlist = args.get('sectionlist', [])
+        sections = args.get('sections', {})
+
+        print(f'.TH "{module}" 9 "{typedef}" "{self.man_date}" "API Manual" LINUX')
+
+        print(".SH NAME")
+        print(f"typedef {typedef} \\- {purpose}")
+
+        for section in sectionlist:
+            print(f'.SH "{section}"')
+            self.output_highlight(sections.get(section))
+
+    def out_struct(self, fname, name, args):
+        module = args.get('module')
+        struct_type = args.get('type')
+        struct_name = args.get('struct')
+        purpose = args.get('purpose')
+        definition = args.get('definition')
+        sectionlist = args.get('sectionlist', [])
+        parameterlist = args.get('parameterlist', [])
+        sections = args.get('sections', {})
+        parameterdescs = args.get('parameterdescs', {})
+
+        print(f'.TH "{module}" 9 "{struct_type} {struct_name}" "{self.man_date}" "API Manual" LINUX')
+
+        print(".SH NAME")
+        print(f"{struct_type} {struct_name} \\- {purpose}")
+
+        # Replace tabs with two spaces and handle newlines
+        declaration = definition.replace("\t", "  ")
+        declaration = Re(r"\n").sub('"\n.br\n.BI "', declaration)
+
+        print(".SH SYNOPSIS")
+        print(f"{struct_type} {struct_name} " + "{" +"\n.br")
+        print(f'.BI "{declaration}\n' + "};\n.br\n")
+
+        print(".SH Members")
+        for parameter in parameterlist:
+            if parameter.startswith("#"):
+                continue
+
+            parameter_name = re.sub(r"\[.*", "", parameter)
+
+            if parameterdescs.get(parameter_name) == KernelDoc.undescribed:
+                continue
+
+            print(f'.IP "{parameter}" 12')
+            self.output_highlight(parameterdescs.get(parameter_name))
+
+        for section in sectionlist:
+            print(f'.SH "{section}"')
+            self.output_highlight(sections.get(section))
+
+
+# Command line interface
+
+
+DESC = """
+Read C language source or header FILEs, extract embedded documentation comments,
+and print formatted documentation to standard output.
+
+The documentation comments are identified by the "/**" opening comment mark.
+
+See Documentation/doc-guide/kernel-doc.rst for the documentation comment syntax.
+"""
+
+EXPORT_FILE_DESC = """
+Specify an additional FILE in which to look for EXPORT_SYMBOL information.
+
+May be used multiple times.
+"""
+
+EXPORT_DESC = """
+Only output documentation for the symbols that have been
+exported using EXPORT_SYMBOL() and related macros in any input
+FILE or -export-file FILE.
+"""
+
+INTERNAL_DESC = """
+Only output documentation for the symbols that have NOT been
+exported using EXPORT_SYMBOL() and related macros in any input
+FILE or -export-file FILE.
+"""
+
+FUNCTION_DESC = """
+Only output documentation for the given function or DOC: section
+title. All other functions and DOC: sections are ignored.
+
+May be used multiple times.
+"""
+
+NOSYMBOL_DESC = """
+Exclude the specified symbol from the output documentation.
+
+May be used multiple times.
+"""
+
+FILES_DESC = """
+Header and C source files to be parsed.
+"""
+
+WARN_CONTENTS_BEFORE_SECTIONS_DESC = """
+Warns if there are contents before sections (deprecated).
+
+This option is kept just for backward-compatibility, but it does nothing,
+neither here nor at the original Perl script.
+"""
+
+
+def main():
+    """Main program"""
+
+    parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
+                                     description=DESC)
+
+    # Normal arguments
+
+    parser.add_argument("-v", "-verbose", "--verbose", action="store_true",
+                        help="Verbose output, more warnings and other information.")
+
+    parser.add_argument("-d", "-debug", "--debug", action="store_true",
+                        help="Enable debug messages")
+
+    parser.add_argument("-M", "-modulename", "--modulename",
+                        help="Allow setting a module name at the output.")
+
+    parser.add_argument("-l", "-enable-lineno", "--enable_lineno",
+                        action="store_true",
+                        help="Enable line number output (only in ReST mode)")
+
+    # Arguments to control the warning behavior
+
+    parser.add_argument("-Wreturn", "--wreturn", action="store_true",
+                        help="Warns about the lack of a return markup on functions.")
+
+    parser.add_argument("-Wshort-desc", "-Wshort-description", "--wshort-desc",
+                        action="store_true",
+                        help="Warns if initial short description is missing")
+
+    parser.add_argument("-Wcontents-before-sections",
+                        "--wcontents-before-sections", action="store_true",
+                        help=WARN_CONTENTS_BEFORE_SECTIONS_DESC)
+
+    parser.add_argument("-Wall", "--wall", action="store_true",
+                        help="Enable all types of warnings")
+
+    parser.add_argument("-Werror", "--werror", action="store_true",
+                        help="Treat warnings as errors.")
+
+    parser.add_argument("-export-file", "--export-file", action='append',
+                        help=EXPORT_FILE_DESC)
+
+    # Output format mutually-exclusive group
+
+    out_group = parser.add_argument_group("Output format selection (mutually exclusive)")
+
+    out_fmt = out_group.add_mutually_exclusive_group()
+
+    out_fmt.add_argument("-m", "-man", "--man", action="store_true",
+                         help="Output troff manual page format.")
+    out_fmt.add_argument("-r", "-rst", "--rst", action="store_true",
+                         help="Output reStructuredText format (default).")
+    out_fmt.add_argument("-N", "-none", "--none", action="store_true",
+                         help="Do not output documentation, only warnings.")
+
+    # Output selection mutually-exclusive group
+
+    sel_group = parser.add_argument_group("Output selection (mutually exclusive)")
+    sel_mut = sel_group.add_mutually_exclusive_group()
+
+    sel_mut.add_argument("-e", "-export", "--export", action='store_true',
+                         help=EXPORT_DESC)
+
+    sel_mut.add_argument("-i", "-internal", "--internal", action='store_true',
+                         help=INTERNAL_DESC)
+
+    sel_mut.add_argument("-s", "-function", "--symbol", action='append',
+                         help=FUNCTION_DESC)
+
+    # This one is valid for all 3 types of filter
+    parser.add_argument("-n", "-nosymbol", "--nosymbol", action='append',
+                         help=NOSYMBOL_DESC)
+
+    parser.add_argument("files", metavar="FILE",
+                        nargs="+", help=FILES_DESC)
+
+    args = parser.parse_args()
+
+    if args.wall:
+        args.wreturn = True
+        args.wshort_desc = True
+        args.wcontents_before_sections = True
+
+    if not args.debug:
+        level = logging.INFO
+    else:
+        level = logging.DEBUG
+
+    if args.man:
+        out_style = ManFormat()
+    elif args.none:
+        out_style = None
+    else:
+        out_style = RestFormat()
+
+    logging.basicConfig(level=level, format="%(levelname)s: %(message)s")
+
+    kfiles = KernelFiles(files=args.files, verbose=args.verbose,
+                         out_style=out_style, werror=args.werror,
+                         wreturn=args.wreturn, wshort_desc=args.wshort_desc,
+                         wcontents_before_sections=args.wcontents_before_sections,
+                         modulename=args.modulename,
+                         export_file=args.export_file)
+
+    kfiles.parse()
+
+    kfiles.msg(enable_lineno=args.enable_lineno, export=args.export,
+               internal=args.internal, symbol=args.symbol,
+               nosymbol=args.nosymbol)
+
+
+# Call main method
+if __name__ == "__main__":
+    main()
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 14/39] scripts/kernel-doc.py: move KernelDoc class to a separate file
  2025-02-24  9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
  2025-02-24  9:08 ` [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser Mauro Carvalho Chehab
@ 2025-02-24  9:08 ` Mauro Carvalho Chehab
  2025-02-24 23:49 ` [PATCH v2 00/39] Implement kernel-doc in Python Jonathan Corbet
  2 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-24  9:08 UTC (permalink / raw)
  To: Linux Doc Mailing List, Jonathan Corbet
  Cc: Mauro Carvalho Chehab, Gustavo A. R. Silva, Mauro Carvalho Chehab,
	Kees Cook, linux-hardening, linux-kernel

In preparation for letting kerneldoc Sphinx extension to import
Python libraries, move regex ancillary classes to a separate
file.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 scripts/kernel-doc.py           | 1634 +-----------------------------
 scripts/lib/kdoc/kdoc_parser.py | 1689 +++++++++++++++++++++++++++++++
 2 files changed, 1691 insertions(+), 1632 deletions(-)
 create mode 100755 scripts/lib/kdoc/kdoc_parser.py

diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
index faae66aa6ead..193a30fcfb7c 100755
--- a/scripts/kernel-doc.py
+++ b/scripts/kernel-doc.py
@@ -42,53 +42,15 @@ SRC_DIR = os.path.dirname(os.path.realpath(__file__))
 
 sys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR))
 
-from kdoc_re import Re, NestedMatch
+from kdoc_parser import KernelDoc, type_param
+from kdoc_re import Re
 
-
-#
-# Regular expressions used to parse kernel-doc markups at KernelDoc class.
-#
-# Let's declare them in lowercase outside any class to make easier to
-# convert from the python script.
-#
-# As those are evaluated at the beginning, no need to cache them
-#
-
-
-# Allow whitespace at end of comment start.
-doc_start = Re(r'^/\*\*\s*$', cache=False)
-
-doc_end = Re(r'\*/', cache=False)
-doc_com = Re(r'\s*\*\s*', cache=False)
-doc_com_body = Re(r'\s*\* ?', cache=False)
-doc_decl = doc_com + Re(r'(\w+)', cache=False)
-
-# @params and a strictly limited set of supported section names
-# Specifically:
-#   Match @word:
-#         @...:
-#         @{section-name}:
-# while trying to not match literal block starts like "example::"
-#
-doc_sect = doc_com + \
-            Re(r'\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:([^:].*)?$',
-                flags=re.I, cache=False)
-
-doc_content = doc_com_body + Re(r'(.*)', cache=False)
-doc_block = doc_com + Re(r'DOC:\s*(.*)?', cache=False)
-doc_inline_start = Re(r'^\s*/\*\*\s*$', cache=False)
-doc_inline_sect = Re(r'\s*\*\s*(@\s*[\w][\w\.]*\s*):(.*)', cache=False)
-doc_inline_end = Re(r'^\s*\*/\s*$', cache=False)
-doc_inline_oneline = Re(r'^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$', cache=False)
 function_pointer = Re(r"([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)", cache=False)
-attribute = Re(r"__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)",
-               flags=re.I | re.S, cache=False)
 
 # match expressions used to find embedded type information
 type_constant = Re(r"\b``([^\`]+)``\b", cache=False)
 type_constant2 = Re(r"\%([-_*\w]+)", cache=False)
 type_func = Re(r"(\w+)\(\)", cache=False)
-type_param = Re(r"\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False)
 type_param_ref = Re(r"([\!~\*]?)\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False)
 
 # Special RST handling for func ptr params
@@ -106,1598 +68,6 @@ type_member = Re(r"\&([_\w]+)(\.|->)([_\w]+)", cache=False)
 type_fallback = Re(r"\&([_\w]+)", cache=False)
 type_member_func = type_member + Re(r"\(\)", cache=False)
 
-export_symbol = Re(r'^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*', cache=False)
-export_symbol_ns = Re(r'^\s*EXPORT_SYMBOL_NS(_GPL)?\s*\(\s*(\w+)\s*,\s*"\S+"\)\s*', cache=False)
-
-class KernelDoc:
-    # Parser states
-    STATE_NORMAL        = 0        # normal code
-    STATE_NAME          = 1        # looking for function name
-    STATE_BODY_MAYBE    = 2        # body - or maybe more description
-    STATE_BODY          = 3        # the body of the comment
-    STATE_BODY_WITH_BLANK_LINE = 4 # the body which has a blank line
-    STATE_PROTO         = 5        # scanning prototype
-    STATE_DOCBLOCK      = 6        # documentation block
-    STATE_INLINE        = 7        # gathering doc outside main block
-
-    st_name = [
-        "NORMAL",
-        "NAME",
-        "BODY_MAYBE",
-        "BODY",
-        "BODY_WITH_BLANK_LINE",
-        "PROTO",
-        "DOCBLOCK",
-        "INLINE",
-    ]
-
-    # Inline documentation state
-    STATE_INLINE_NA     = 0 # not applicable ($state != STATE_INLINE)
-    STATE_INLINE_NAME   = 1 # looking for member name (@foo:)
-    STATE_INLINE_TEXT   = 2 # looking for member documentation
-    STATE_INLINE_END    = 3 # done
-    STATE_INLINE_ERROR  = 4 # error - Comment without header was found.
-                            # Spit a warning as it's not
-                            # proper kernel-doc and ignore the rest.
-
-    st_inline_name = [
-        "",
-        "_NAME",
-        "_TEXT",
-        "_END",
-        "_ERROR",
-    ]
-
-    # Section names
-
-    section_default = "Description"  # default section
-    section_intro = "Introduction"
-    section_context = "Context"
-    section_return = "Return"
-
-    undescribed = "-- undescribed --"
-
-    def __init__(self, config, fname):
-        """Initialize internal variables"""
-
-        self.fname = fname
-        self.config = config
-
-        # Initial state for the state machines
-        self.state = self.STATE_NORMAL
-        self.inline_doc_state = self.STATE_INLINE_NA
-
-        # Store entry currently being processed
-        self.entry = None
-
-        # Place all potential outputs into an array
-        self.entries = []
-
-    def show_warnings(self, dtype, declaration_name):
-        # TODO: implement it
-
-        return True
-
-    # TODO: rename to emit_message
-    def emit_warning(self, ln, msg, warning=True):
-        """Emit a message"""
-
-        if warning:
-            self.config.log.warning("%s:%d %s", self.fname, ln, msg)
-        else:
-            self.config.log.info("%s:%d %s", self.fname, ln, msg)
-
-    def dump_section(self, start_new=True):
-        """
-        Dumps section contents to arrays/hashes intended for that purpose.
-        """
-
-        name = self.entry.section
-        contents = self.entry.contents
-
-        # TODO: we can prevent dumping empty sections here with:
-        #
-        #    if self.entry.contents.strip("\n"):
-        #       if start_new:
-        #           self.entry.section = self.section_default
-        #           self.entry.contents = ""
-        #
-        #        return
-        #
-        # But, as we want to be producing the same output of the
-        # venerable kernel-doc Perl tool, let's just output everything,
-        # at least for now
-
-        if type_param.match(name):
-            name = type_param.group(1)
-
-            self.entry.parameterdescs[name] = contents
-            self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line
-
-            self.entry.sectcheck += name + " "
-            self.entry.new_start_line = 0
-
-        elif name == "@...":
-            name = "..."
-            self.entry.parameterdescs[name] = contents
-            self.entry.sectcheck += name + " "
-            self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line
-            self.entry.new_start_line = 0
-
-        else:
-            if name in self.entry.sections and self.entry.sections[name] != "":
-                # Only warn on user-specified duplicate section names
-                if name != self.section_default:
-                    self.emit_warning(self.entry.new_start_line,
-                                      f"duplicate section name '{name}'\n")
-                self.entry.sections[name] += contents
-            else:
-                self.entry.sections[name] = contents
-                self.entry.sectionlist.append(name)
-                self.entry.section_start_lines[name] = self.entry.new_start_line
-                self.entry.new_start_line = 0
-
-#        self.config.log.debug("Section: %s : %s", name, pformat(vars(self.entry)))
-
-        if start_new:
-            self.entry.section = self.section_default
-            self.entry.contents = ""
-
-    # TODO: rename it to store_declaration
-    def output_declaration(self, dtype, name, **args):
-        """
-        Stores the entry into an entry array.
-
-        The actual output and output filters will be handled elsewhere
-        """
-
-        # The implementation here is different than the original kernel-doc:
-        # instead of checking for output filters or actually output anything,
-        # it just stores the declaration content at self.entries, as the
-        # output will happen on a separate class.
-        #
-        # For now, we're keeping the same name of the function just to make
-        # easier to compare the source code of both scripts
-
-        if "declaration_start_line" not in args:
-            args["declaration_start_line"] = self.entry.declaration_start_line
-
-        args["type"] = dtype
-
-        # TODO: use colletions.OrderedDict
-
-        sections = args.get('sections', {})
-        sectionlist = args.get('sectionlist', [])
-
-        # Drop empty sections
-        # TODO: improve it to emit warnings
-        for section in [ "Description", "Return" ]:
-            if section in sectionlist:
-                if not sections[section].rstrip():
-                    del sections[section]
-                    sectionlist.remove(section)
-
-        self.entries.append((name, args))
-
-        self.config.log.debug("Output: %s:%s = %s", dtype, name, pformat(args))
-
-    def reset_state(self, ln):
-        """
-        Ancillary routine to create a new entry. It initializes all
-        variables used by the state machine.
-        """
-
-        self.entry = argparse.Namespace
-
-        self.entry.contents = ""
-        self.entry.function = ""
-        self.entry.sectcheck = ""
-        self.entry.struct_actual = ""
-        self.entry.prototype = ""
-
-        self.entry.parameterlist = []
-        self.entry.parameterdescs = {}
-        self.entry.parametertypes = {}
-        self.entry.parameterdesc_start_lines = {}
-
-        self.entry.section_start_lines = {}
-        self.entry.sectionlist = []
-        self.entry.sections = {}
-
-        self.entry.anon_struct_union = False
-
-        self.entry.leading_space = None
-
-        # State flags
-        self.state = self.STATE_NORMAL
-        self.inline_doc_state = self.STATE_INLINE_NA
-        self.entry.brcount = 0
-
-        self.entry.in_doc_sect = False
-        self.entry.declaration_start_line = ln
-
-    def push_parameter(self, ln, decl_type, param, dtype,
-                       org_arg, declaration_name):
-        if self.entry.anon_struct_union and dtype == "" and param == "}":
-            return  # Ignore the ending }; from anonymous struct/union
-
-        self.entry.anon_struct_union = False
-
-        param = Re(r'[\[\)].*').sub('', param, count=1)
-
-        if dtype == "" and param.endswith("..."):
-            if Re(r'\w\.\.\.$').search(param):
-                # For named variable parameters of the form `x...`,
-                # remove the dots
-                param = param[:-3]
-            else:
-                # Handles unnamed variable parameters
-                param = "..."
-
-            if param not in self.entry.parameterdescs or \
-                not self.entry.parameterdescs[param]:
-
-                self.entry.parameterdescs[param] = "variable arguments"
-
-        elif dtype == "" and (not param or param == "void"):
-            param = "void"
-            self.entry.parameterdescs[param] = "no arguments"
-
-        elif dtype == "" and param in ["struct", "union"]:
-            # Handle unnamed (anonymous) union or struct
-            dtype = param
-            param = "{unnamed_" + param + "}"
-            self.entry.parameterdescs[param] = "anonymous\n"
-            self.entry.anon_struct_union = True
-
-        # Handle cache group enforcing variables: they do not need
-        # to be described in header files
-        elif "__cacheline_group" in param:
-            # Ignore __cacheline_group_begin and __cacheline_group_end
-            return
-
-        # Warn if parameter has no description
-        # (but ignore ones starting with # as these are not parameters
-        # but inline preprocessor statements)
-        if param not in self.entry.parameterdescs and not param.startswith("#"):
-            self.entry.parameterdescs[param] = self.undescribed
-
-            if self.show_warnings(dtype, declaration_name) and "." not in param:
-                if decl_type == 'function':
-                    dname = f"{decl_type} parameter"
-                else:
-                    dname = f"{decl_type} member"
-
-                self.emit_warning(ln,
-                                  f"{dname} '{param}' not described in '{declaration_name}'")
-
-        # Strip spaces from param so that it is one continuous string on
-        # parameterlist. This fixes a problem where check_sections()
-        # cannot find a parameter like "addr[6 + 2]" because it actually
-        # appears as "addr[6", "+", "2]" on the parameter list.
-        # However, it's better to maintain the param string unchanged for
-        # output, so just weaken the string compare in check_sections()
-        # to ignore "[blah" in a parameter string.
-
-        self.entry.parameterlist.append(param)
-        org_arg = Re(r'\s\s+').sub(' ', org_arg)
-        self.entry.parametertypes[param] = org_arg
-
-    def save_struct_actual(self, actual):
-        """
-        Strip all spaces from the actual param so that it looks like
-        one string item.
-        """
-
-        actual = Re(r'\s*').sub("", actual, count=1)
-
-        self.entry.struct_actual += actual + " "
-
-    def create_parameter_list(self, ln, decl_type, args, splitter, declaration_name):
-
-        # temporarily replace all commas inside function pointer definition
-        arg_expr = Re(r'(\([^\),]+),')
-        while arg_expr.search(args):
-            args = arg_expr.sub(r"\1#", args)
-
-        for arg in args.split(splitter):
-            # Strip comments
-            arg = Re(r'\/\*.*\*\/').sub('', arg)
-
-            # Ignore argument attributes
-            arg = Re(r'\sPOS0?\s').sub(' ', arg)
-
-            # Strip leading/trailing spaces
-            arg = arg.strip()
-            arg = Re(r'\s+').sub(' ', arg, count=1)
-
-            if arg.startswith('#'):
-                # Treat preprocessor directive as a typeless variable just to fill
-                # corresponding data structures "correctly". Catch it later in
-                # output_* subs.
-
-                # Treat preprocessor directive as a typeless variable
-                self.push_parameter(ln, decl_type, arg, "",
-                                    "", declaration_name)
-
-            elif Re(r'\(.+\)\s*\(').search(arg):
-                # Pointer-to-function
-
-                arg = arg.replace('#', ',')
-
-                r = Re(r'[^\(]+\(\*?\s*([\w\[\]\.]*)\s*\)')
-                if r.match(arg):
-                    param = r.group(1)
-                else:
-                    self.emit_warning(ln, f"Invalid param: {arg}")
-                    param = arg
-
-                dtype = Re(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg)
-                self.save_struct_actual(param)
-                self.push_parameter(ln, decl_type, param, dtype,
-                                    arg, declaration_name)
-
-            elif Re(r'\(.+\)\s*\[').search(arg):
-                # Array-of-pointers
-
-                arg = arg.replace('#', ',')
-                r = Re(r'[^\(]+\(\s*\*\s*([\w\[\]\.]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)')
-                if r.match(arg):
-                    param = r.group(1)
-                else:
-                    self.emit_warning(ln, f"Invalid param: {arg}")
-                    param = arg
-
-                dtype = Re(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg)
-
-                self.save_struct_actual(param)
-                self.push_parameter(ln, decl_type, param, dtype,
-                                    arg, declaration_name)
-
-            elif arg:
-                arg = Re(r'\s*:\s*').sub(":", arg)
-                arg = Re(r'\s*\[').sub('[', arg)
-
-                args = Re(r'\s*,\s*').split(arg)
-                if args[0] and '*' in args[0]:
-                    args[0] = re.sub(r'(\*+)\s*', r' \1', args[0])
-
-                first_arg = []
-                r = Re(r'^(.*\s+)(.*?\[.*\].*)$')
-                if args[0] and r.match(args[0]):
-                    args.pop(0)
-                    first_arg.extend(r.group(1))
-                    first_arg.append(r.group(2))
-                else:
-                    first_arg = Re(r'\s+').split(args.pop(0))
-
-                args.insert(0, first_arg.pop())
-                dtype = ' '.join(first_arg)
-
-                for param in args:
-                    if Re(r'^(\*+)\s*(.*)').match(param):
-                        r = Re(r'^(\*+)\s*(.*)')
-                        if not r.match(param):
-                            self.emit_warning(ln, f"Invalid param: {param}")
-                            continue
-
-                        param = r.group(1)
-
-                        self.save_struct_actual(r.group(2))
-                        self.push_parameter(ln, decl_type, r.group(2),
-                                            f"{dtype} {r.group(1)}",
-                                            arg, declaration_name)
-
-                    elif Re(r'(.*?):(\w+)').search(param):
-                        r = Re(r'(.*?):(\w+)')
-                        if not r.match(param):
-                            self.emit_warning(ln, f"Invalid param: {param}")
-                            continue
-
-                        if dtype != "":  # Skip unnamed bit-fields
-                            self.save_struct_actual(r.group(1))
-                            self.push_parameter(ln, decl_type, r.group(1),
-                                                f"{dtype}:{r.group(2)}",
-                                                arg, declaration_name)
-                    else:
-                        self.save_struct_actual(param)
-                        self.push_parameter(ln, decl_type, param, dtype,
-                                            arg, declaration_name)
-
-    def check_sections(self, ln, decl_name, decl_type, sectcheck, prmscheck):
-        sects = sectcheck.split()
-        prms = prmscheck.split()
-        err = False
-
-        for sx in range(len(sects)):                  # pylint: disable=C0200
-            err = True
-            for px in range(len(prms)):               # pylint: disable=C0200
-                prm_clean = prms[px]
-                prm_clean = Re(r'\[.*\]').sub('', prm_clean)
-                prm_clean = attribute.sub('', prm_clean)
-
-                # ignore array size in a parameter string;
-                # however, the original param string may contain
-                # spaces, e.g.:  addr[6 + 2]
-                # and this appears in @prms as "addr[6" since the
-                # parameter list is split at spaces;
-                # hence just ignore "[..." for the sections check;
-                prm_clean = Re(r'\[.*').sub('', prm_clean)
-
-                if prm_clean == sects[sx]:
-                    err = False
-                    break
-
-            if err:
-                if decl_type == 'function':
-                    dname = f"{decl_type} parameter"
-                else:
-                    dname = f"{decl_type} member"
-
-                self.emit_warning(ln,
-                                  f"Excess {dname} '{sects[sx]}' description in '{decl_name}'")
-
-    def check_return_section(self, ln, declaration_name, return_type):
-
-        if not self.config.wreturn:
-            return
-
-        # Ignore an empty return type (It's a macro)
-        # Ignore functions with a "void" return type (but not "void *")
-        if not return_type or Re(r'void\s*\w*\s*$').search(return_type):
-            return
-
-        if not self.entry.sections.get("Return", None):
-            self.emit_warning(ln,
-                              f"No description found for return value of '{declaration_name}'")
-
-    def dump_struct(self, ln, proto):
-        """
-        Store an entry for an struct or union
-        """
-
-        type_pattern = r'(struct|union)'
-
-        qualifiers = [
-            "__attribute__",
-            "__packed",
-            "__aligned",
-            "____cacheline_aligned_in_smp",
-            "____cacheline_aligned",
-        ]
-
-        definition_body = r'\{(.*)\}\s*' + "(?:" + '|'.join(qualifiers) + ")?"
-        struct_members = Re(type_pattern + r'([^\{\};]+)(\{)([^\{\}]*)(\})([^\{\}\;]*)(\;)')
-
-        # Extract struct/union definition
-        members = None
-        declaration_name = None
-        decl_type = None
-
-        r = Re(type_pattern + r'\s+(\w+)\s*' + definition_body)
-        if r.search(proto):
-            decl_type = r.group(1)
-            declaration_name = r.group(2)
-            members = r.group(3)
-        else:
-            r = Re(r'typedef\s+' + type_pattern + r'\s*' + definition_body + r'\s*(\w+)\s*;')
-
-            if r.search(proto):
-                decl_type = r.group(1)
-                declaration_name = r.group(3)
-                members = r.group(2)
-
-        if not members:
-            self.emit_warning(ln, f"{proto} error: Cannot parse struct or union!")
-            self.config.errors += 1
-            return
-
-        if self.entry.identifier != declaration_name:
-            self.emit_warning(ln,
-                              f"expecting prototype for {decl_type} {self.entry.identifier}. Prototype was for {decl_type} {declaration_name} instead\n")
-            return
-
-        args_pattern =r'([^,)]+)'
-
-        sub_prefixes = [
-            (Re(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', re.S | re.I),  ''),
-            (Re(r'\/\*\s*private:.*', re.S| re.I),  ''),
-
-            # Strip comments
-            (Re(r'\/\*.*?\*\/', re.S),  ''),
-
-            # Strip attributes
-            (attribute, ' '),
-            (Re(r'\s*__aligned\s*\([^;]*\)', re.S),  ' '),
-            (Re(r'\s*__counted_by\s*\([^;]*\)', re.S),  ' '),
-            (Re(r'\s*__counted_by_(le|be)\s*\([^;]*\)', re.S),  ' '),
-            (Re(r'\s*__packed\s*', re.S),  ' '),
-            (Re(r'\s*CRYPTO_MINALIGN_ATTR', re.S),  ' '),
-            (Re(r'\s*____cacheline_aligned_in_smp', re.S),  ' '),
-            (Re(r'\s*____cacheline_aligned', re.S),  ' '),
-
-            # Unwrap struct_group macros based on this definition:
-            # __struct_group(TAG, NAME, ATTRS, MEMBERS...)
-            # which has variants like: struct_group(NAME, MEMBERS...)
-            # Only MEMBERS arguments require documentation.
-            #
-            # Parsing them happens on two steps:
-            #
-            # 1. drop struct group arguments that aren't at MEMBERS,
-            #    storing them as STRUCT_GROUP(MEMBERS)
-            #
-            # 2. remove STRUCT_GROUP() ancillary macro.
-            #
-            # The original logic used to remove STRUCT_GROUP() using an
-            # advanced regex:
-            #
-            #   \bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;
-            #
-            # with two patterns that are incompatible with
-            # Python re module, as it has:
-            #
-            #   - a recursive pattern: (?1)
-            #   - an atomic grouping: (?>...)
-            #
-            # I tried a simpler version: but it didn't work either:
-            #   \bSTRUCT_GROUP\(([^\)]+)\)[^;]*;
-            #
-            # As it doesn't properly match the end parenthesis on some cases.
-            #
-            # So, a better solution was crafted: there's now a NestedMatch
-            # class that ensures that delimiters after a search are properly
-            # matched. So, the implementation to drop STRUCT_GROUP() will be
-            # handled in separate.
-
-            (Re(r'\bstruct_group\s*\(([^,]*,)', re.S),  r'STRUCT_GROUP('),
-            (Re(r'\bstruct_group_attr\s*\(([^,]*,){2}', re.S),  r'STRUCT_GROUP('),
-            (Re(r'\bstruct_group_tagged\s*\(([^,]*),([^,]*),', re.S),  r'struct \1 \2; STRUCT_GROUP('),
-            (Re(r'\b__struct_group\s*\(([^,]*,){3}', re.S),  r'STRUCT_GROUP('),
-
-            # Replace macros
-            #
-            # TODO: it is better to also move those to the NestedMatch logic,
-            # to ensure that parenthesis will be properly matched.
-
-            (Re(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S),  r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'),
-            (Re(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S),  r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'),
-            (Re(r'DECLARE_BITMAP\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S),  r'unsigned long \1[BITS_TO_LONGS(\2)]'),
-            (Re(r'DECLARE_HASHTABLE\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S),  r'unsigned long \1[1 << ((\2) - 1)]'),
-            (Re(r'DECLARE_KFIFO\s*\(' + args_pattern + r',\s*' + args_pattern + r',\s*' + args_pattern + r'\)', re.S),  r'\2 *\1'),
-            (Re(r'DECLARE_KFIFO_PTR\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S),  r'\2 *\1'),
-            (Re(r'(?:__)?DECLARE_FLEX_ARRAY\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S),  r'\1 \2[]'),
-            (Re(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + args_pattern + r'\)', re.S),  r'dma_addr_t \1'),
-            (Re(r'DEFINE_DMA_UNMAP_LEN\s*\(' + args_pattern + r'\)', re.S),  r'__u32 \1'),
-        ]
-
-        # Regexes here are guaranteed to have the end limiter matching
-        # the start delimiter. Yet, right now, only one replace group
-        # is allowed.
-
-        sub_nested_prefixes = [
-            (re.compile(r'\bSTRUCT_GROUP\('),  r'\1'),
-        ]
-
-        for search, sub in sub_prefixes:
-            members = search.sub(sub, members)
-
-        nested = NestedMatch()
-
-        for search, sub in sub_nested_prefixes:
-            members = nested.sub(search, sub, members)
-
-        # Keeps the original declaration as-is
-        declaration = members
-
-        # Split nested struct/union elements
-        #
-        # This loop was simpler at the original kernel-doc perl version, as
-        #   while ($members =~ m/$struct_members/) { ... }
-        # reads 'members' string on each interaction.
-        #
-        # Python behavior is different: it parses 'members' only once,
-        # creating a list of tuples from the first interaction.
-        #
-        # On other words, this won't get nested structs.
-        #
-        # So, we need to have an extra loop on Python to override such
-        # re limitation.
-
-        while True:
-            tuples = struct_members.findall(members)
-            if not tuples:
-                break
-
-            for t in tuples:
-                newmember = ""
-                maintype = t[0]
-                s_ids = t[5]
-                content = t[3]
-
-                oldmember = "".join(t)
-
-                for s_id in s_ids.split(','):
-                    s_id = s_id.strip()
-
-                    newmember += f"{maintype} {s_id}; "
-                    s_id = Re(r'[:\[].*').sub('', s_id)
-                    s_id = Re(r'^\s*\**(\S+)\s*').sub(r'\1', s_id)
-
-                    for arg in content.split(';'):
-                        arg = arg.strip()
-
-                        if not arg:
-                            continue
-
-                        r = Re(r'^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)')
-                        if r.match(arg):
-                            # Pointer-to-function
-                            dtype = r.group(1)
-                            name = r.group(2)
-                            extra = r.group(3)
-
-                            if not name:
-                                continue
-
-                            if not s_id:
-                                # Anonymous struct/union
-                                newmember += f"{dtype}{name}{extra}; "
-                            else:
-                                newmember += f"{dtype}{s_id}.{name}{extra}; "
-
-                        else:
-                            arg = arg.strip()
-                            # Handle bitmaps
-                            arg = Re(r':\s*\d+\s*').sub('', arg)
-
-                            # Handle arrays
-                            arg = Re(r'\[.*\]').sub('', arg)
-
-                            # Handle multiple IDs
-                            arg = Re(r'\s*,\s*').sub(',', arg)
-
-
-                            r = Re(r'(.*)\s+([\S+,]+)')
-
-                            if r.search(arg):
-                                dtype = r.group(1)
-                                names = r.group(2)
-                            else:
-                                newmember += f"{arg}; "
-                                continue
-
-                            for name in names.split(','):
-                                name = Re(r'^\s*\**(\S+)\s*').sub(r'\1', name).strip()
-
-                                if not name:
-                                    continue
-
-                                if not s_id:
-                                    # Anonymous struct/union
-                                    newmember += f"{dtype} {name}; "
-                                else:
-                                    newmember += f"{dtype} {s_id}.{name}; "
-
-                members = members.replace(oldmember, newmember)
-
-        # Ignore other nested elements, like enums
-        members = re.sub(r'(\{[^\{\}]*\})', '', members)
-
-        self.create_parameter_list(ln, decl_type, members, ';',
-                                   declaration_name)
-        self.check_sections(ln, declaration_name, decl_type,
-                            self.entry.sectcheck, self.entry.struct_actual)
-
-        # Adjust declaration for better display
-        declaration = Re(r'([\{;])').sub(r'\1\n', declaration)
-        declaration = Re(r'\}\s+;').sub('};', declaration)
-
-        # Better handle inlined enums
-        while True:
-            r = Re(r'(enum\s+\{[^\}]+),([^\n])')
-            if not r.search(declaration):
-                break
-
-            declaration = r.sub(r'\1,\n\2', declaration)
-
-        def_args = declaration.split('\n')
-        level = 1
-        declaration = ""
-        for clause in def_args:
-
-            clause = clause.strip()
-            clause = Re(r'\s+').sub(' ', clause, count=1)
-
-            if not clause:
-                continue
-
-            if '}' in clause and level > 1:
-                level -= 1
-
-            if not Re(r'^\s*#').match(clause):
-                declaration += "\t" * level
-
-            declaration += "\t" + clause + "\n"
-            if "{" in clause and "}" not in clause:
-                level += 1
-
-        self.output_declaration(decl_type, declaration_name,
-                    struct=declaration_name,
-                    module=self.entry.modulename,
-                    definition=declaration,
-                    parameterlist=self.entry.parameterlist,
-                    parameterdescs=self.entry.parameterdescs,
-                    parametertypes=self.entry.parametertypes,
-                    sectionlist=self.entry.sectionlist,
-                    sections=self.entry.sections,
-                    purpose=self.entry.declaration_purpose)
-
-    def dump_enum(self, ln, proto):
-
-        # Ignore members marked private
-        proto = Re(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', flags=re.S).sub('', proto)
-        proto = Re(r'\/\*\s*private:.*}', flags=re.S).sub('}', proto)
-
-        # Strip comments
-        proto = Re(r'\/\*.*?\*\/', flags=re.S).sub('', proto)
-
-        # Strip #define macros inside enums
-        proto = Re(r'#\s*((define|ifdef|if)\s+|endif)[^;]*;', flags=re.S).sub('', proto)
-
-        members = None
-        declaration_name = None
-
-        r = Re(r'typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;')
-        if r.search(proto):
-            declaration_name = r.group(2)
-            members = r.group(1).rstrip()
-        else:
-            r = Re(r'enum\s+(\w*)\s*\{(.*)\}')
-            if r.match(proto):
-                declaration_name = r.group(1)
-                members = r.group(2).rstrip()
-
-        if not members:
-            self.emit_warning(ln, f"{proto}: error: Cannot parse enum!")
-            self.config.errors += 1
-            return
-
-        if self.entry.identifier != declaration_name:
-            if self.entry.identifier == "":
-                self.emit_warning(ln,
-                                  f"{proto}: wrong kernel-doc identifier on prototype")
-            else:
-                self.emit_warning(ln,
-                                  f"expecting prototype for enum {self.entry.identifier}. Prototype was for enum {declaration_name} instead")
-            return
-
-        if not declaration_name:
-            declaration_name = "(anonymous)"
-
-        member_set = set()
-
-        members = Re(r'\([^;]*?[\)]').sub('', members)
-
-        for arg in members.split(','):
-            if not arg:
-                continue
-            arg = Re(r'^\s*(\w+).*').sub(r'\1', arg)
-            self.entry.parameterlist.append(arg)
-            if arg not in self.entry.parameterdescs:
-                self.entry.parameterdescs[arg] = self.undescribed
-                if self.show_warnings("enum", declaration_name):
-                    self.emit_warning(ln,
-                                      f"Enum value '{arg}' not described in enum '{declaration_name}'")
-            member_set.add(arg)
-
-        for k in self.entry.parameterdescs:
-            if k not in member_set:
-                if self.show_warnings("enum", declaration_name):
-                    self.emit_warning(ln,
-                                      f"Excess enum value '%{k}' description in '{declaration_name}'")
-
-        self.output_declaration('enum', declaration_name,
-                   enum=declaration_name,
-                   module=self.config.modulename,
-                   parameterlist=self.entry.parameterlist,
-                   parameterdescs=self.entry.parameterdescs,
-                   sectionlist=self.entry.sectionlist,
-                   sections=self.entry.sections,
-                   purpose=self.entry.declaration_purpose)
-
-    def dump_declaration(self, ln, prototype):
-        if self.entry.decl_type == "enum":
-            self.dump_enum(ln, prototype)
-            return
-
-        if self.entry.decl_type == "typedef":
-            self.dump_typedef(ln, prototype)
-            return
-
-        if self.entry.decl_type in ["union", "struct"]:
-            self.dump_struct(ln, prototype)
-            return
-
-        # TODO: handle other types
-        self.output_declaration(self.entry.decl_type, prototype,
-                   entry=self.entry)
-
-    def dump_function(self, ln, prototype):
-
-        func_macro = False
-        return_type = ''
-        decl_type = 'function'
-
-        # Prefixes that would be removed
-        sub_prefixes = [
-            (r"^static +", "", 0),
-            (r"^extern +", "", 0),
-            (r"^asmlinkage +", "", 0),
-            (r"^inline +", "", 0),
-            (r"^__inline__ +", "", 0),
-            (r"^__inline +", "", 0),
-            (r"^__always_inline +", "", 0),
-            (r"^noinline +", "", 0),
-            (r"^__FORTIFY_INLINE +", "", 0),
-            (r"__init +", "", 0),
-            (r"__init_or_module +", "", 0),
-            (r"__deprecated +", "", 0),
-            (r"__flatten +", "", 0),
-            (r"__meminit +", "", 0),
-            (r"__must_check +", "", 0),
-            (r"__weak +", "", 0),
-            (r"__sched +", "", 0),
-            (r"_noprof", "", 0),
-            (r"__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +", "", 0),
-            (r"__(?:re)?alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) +", "", 0),
-            (r"__diagnose_as\s*\(\s*\S+\s*(?:,\s*\d+\s*)*\) +", "", 0),
-            (r"DECL_BUCKET_PARAMS\s*\(\s*(\S+)\s*,\s*(\S+)\s*\)", r"\1, \2", 0),
-            (r"__attribute_const__ +", "", 0),
-
-            # It seems that Python support for re.X is broken:
-            # At least for me (Python 3.13), this didn't work
-#            (r"""
-#              __attribute__\s*\(\(
-#                (?:
-#                    [\w\s]+          # attribute name
-#                    (?:\([^)]*\))?   # attribute arguments
-#                    \s*,?            # optional comma at the end
-#                )+
-#              \)\)\s+
-#             """, "", re.X),
-
-            # So, remove whitespaces and comments from it
-            (r"__attribute__\s*\(\((?:[\w\s]+(?:\([^)]*\))?\s*,?)+\)\)\s+", "", 0),
-        ]
-
-        for search, sub, flags in sub_prefixes:
-            prototype = Re(search, flags).sub(sub, prototype)
-
-        # Macros are a special case, as they change the prototype format
-        new_proto = Re(r"^#\s*define\s+").sub("", prototype)
-        if new_proto != prototype:
-            is_define_proto = True
-            prototype = new_proto
-        else:
-            is_define_proto = False
-
-        # Yes, this truly is vile.  We are looking for:
-        # 1. Return type (may be nothing if we're looking at a macro)
-        # 2. Function name
-        # 3. Function parameters.
-        #
-        # All the while we have to watch out for function pointer parameters
-        # (which IIRC is what the two sections are for), C types (these
-        # regexps don't even start to express all the possibilities), and
-        # so on.
-        #
-        # If you mess with these regexps, it's a good idea to check that
-        # the following functions' documentation still comes out right:
-        # - parport_register_device (function pointer parameters)
-        # - atomic_set (macro)
-        # - pci_match_device, __copy_to_user (long return type)
-
-        name = r'[a-zA-Z0-9_~:]+'
-        prototype_end1 = r'[^\(]*'
-        prototype_end2 = r'[^\{]*'
-        prototype_end = fr'\(({prototype_end1}|{prototype_end2})\)'
-
-        # Besides compiling, Perl qr{[\w\s]+} works as a non-capturing group.
-        # So, this needs to be mapped in Python with (?:...)? or (?:...)+
-
-        type1 = r'(?:[\w\s]+)?'
-        type2 = r'(?:[\w\s]+\*+)+'
-
-        found = False
-
-        if is_define_proto:
-            r = Re(r'^()(' + name + r')\s+')
-
-            if r.search(prototype):
-                return_type = ''
-                declaration_name = r.group(2)
-                func_macro = True
-
-                found = True
-
-        if not found:
-            patterns = [
-                rf'^()({name})\s*{prototype_end}',
-                rf'^({type1})\s+({name})\s*{prototype_end}',
-                rf'^({type2})\s*({name})\s*{prototype_end}',
-            ]
-
-            for p in patterns:
-                r = Re(p)
-
-                if r.match(prototype):
-
-                    return_type = r.group(1)
-                    declaration_name = r.group(2)
-                    args = r.group(3)
-
-                    self.create_parameter_list(ln, decl_type, args, ',',
-                                               declaration_name)
-
-                    found = True
-                    break
-        if not found:
-            self.emit_warning(ln,
-                              f"cannot understand function prototype: '{prototype}'")
-            return
-
-        if self.entry.identifier != declaration_name:
-            self.emit_warning(ln,
-                              f"expecting prototype for {self.entry.identifier}(). Prototype was for {declaration_name}() instead")
-            return
-
-        prms = " ".join(self.entry.parameterlist)
-        self.check_sections(ln, declaration_name, "function",
-                            self.entry.sectcheck, prms)
-
-        self.check_return_section(ln, declaration_name, return_type)
-
-        if 'typedef' in return_type:
-            self.output_declaration(decl_type, declaration_name,
-                       function=declaration_name,
-                       typedef=True,
-                       module=self.config.modulename,
-                       functiontype=return_type,
-                       parameterlist=self.entry.parameterlist,
-                       parameterdescs=self.entry.parameterdescs,
-                       parametertypes=self.entry.parametertypes,
-                       sectionlist=self.entry.sectionlist,
-                       sections=self.entry.sections,
-                       purpose=self.entry.declaration_purpose,
-                       func_macro=func_macro)
-        else:
-            self.output_declaration(decl_type, declaration_name,
-                       function=declaration_name,
-                       typedef=False,
-                       module=self.config.modulename,
-                       functiontype=return_type,
-                       parameterlist=self.entry.parameterlist,
-                       parameterdescs=self.entry.parameterdescs,
-                       parametertypes=self.entry.parametertypes,
-                       sectionlist=self.entry.sectionlist,
-                       sections=self.entry.sections,
-                       purpose=self.entry.declaration_purpose,
-                       func_macro=func_macro)
-
-    def dump_typedef(self, ln, proto):
-        typedef_type = r'((?:\s+[\w\*]+\b){1,8})\s*'
-        typedef_ident = r'\*?\s*(\w\S+)\s*'
-        typedef_args = r'\s*\((.*)\);'
-
-        typedef1 = Re(r'typedef' + typedef_type + r'\(' + typedef_ident + r'\)' + typedef_args)
-        typedef2 = Re(r'typedef' + typedef_type + typedef_ident + typedef_args)
-
-        # Strip comments
-        proto = Re(r'/\*.*?\*/', flags=re.S).sub('', proto)
-
-        # Parse function typedef prototypes
-        for r in [typedef1, typedef2]:
-            if not r.match(proto):
-                continue
-
-            return_type = r.group(1).strip()
-            declaration_name = r.group(2)
-            args = r.group(3)
-
-            if self.entry.identifier != declaration_name:
-                self.emit_warning(ln,
-                                  f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
-                return
-
-            decl_type = 'function'
-            self.create_parameter_list(ln, decl_type, args, ',', declaration_name)
-
-            self.output_declaration(decl_type, declaration_name,
-                       function=declaration_name,
-                       typedef=True,
-                       module=self.entry.modulename,
-                       functiontype=return_type,
-                       parameterlist=self.entry.parameterlist,
-                       parameterdescs=self.entry.parameterdescs,
-                       parametertypes=self.entry.parametertypes,
-                       sectionlist=self.entry.sectionlist,
-                       sections=self.entry.sections,
-                       purpose=self.entry.declaration_purpose)
-            return
-
-        # Handle nested parentheses or brackets
-        r = Re(r'(\(*.\)\s*|\[*.\]\s*);$')
-        while r.search(proto):
-            proto = r.sub('', proto)
-
-        # Parse simple typedefs
-        r = Re(r'typedef.*\s+(\w+)\s*;')
-        if r.match(proto):
-            declaration_name = r.group(1)
-
-            if self.entry.identifier != declaration_name:
-                self.emit_warning(ln, f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
-                return
-
-            self.output_declaration('typedef', declaration_name,
-                       typedef=declaration_name,
-                       module=self.entry.modulename,
-                       sectionlist=self.entry.sectionlist,
-                       sections=self.entry.sections,
-                       purpose=self.entry.declaration_purpose)
-            return
-
-        self.emit_warning(ln, "error: Cannot parse typedef!")
-        self.config.errors += 1
-
-    @staticmethod
-    def process_export(function_table, line):
-        """
-        process EXPORT_SYMBOL* tags
-
-        This method is called both internally and externally, so, it
-        doesn't use self.
-        """
-
-        if export_symbol.search(line):
-            symbol = export_symbol.group(2)
-            function_table.add(symbol)
-
-        if export_symbol_ns.search(line):
-            symbol = export_symbol_ns.group(2)
-            function_table.add(symbol)
-
-    def process_normal(self, ln, line):
-        """
-        STATE_NORMAL: looking for the /** to begin everything.
-        """
-
-        if not doc_start.match(line):
-            return
-
-        # start a new entry
-        self.reset_state(ln + 1)
-        self.entry.in_doc_sect = False
-
-        # next line is always the function name
-        self.state = self.STATE_NAME
-
-    def process_name(self, ln, line):
-        """
-        STATE_NAME: Looking for the "name - description" line
-        """
-
-        if doc_block.search(line):
-            self.entry.new_start_line = ln
-
-            if not doc_block.group(1):
-                self.entry.section = self.section_intro
-            else:
-                self.entry.section = doc_block.group(1)
-
-            self.state = self.STATE_DOCBLOCK
-            return
-
-        if doc_decl.search(line):
-            self.entry.identifier = doc_decl.group(1)
-            self.entry.is_kernel_comment = False
-
-            decl_start = str(doc_com)       # comment block asterisk
-            fn_type = r"(?:\w+\s*\*\s*)?"  # type (for non-functions)
-            parenthesis = r"(?:\(\w*\))?"   # optional parenthesis on function
-            decl_end = r"(?:[-:].*)"         # end of the name part
-
-            # test for pointer declaration type, foo * bar() - desc
-            r = Re(fr"^{decl_start}([\w\s]+?){parenthesis}?\s*{decl_end}?$")
-            if r.search(line):
-                self.entry.identifier = r.group(1)
-
-            # Test for data declaration
-            r = Re(r"^\s*\*?\s*(struct|union|enum|typedef)\b\s*(\w*)")
-            if r.search(line):
-                self.entry.decl_type = r.group(1)
-                self.entry.identifier = r.group(2)
-                self.entry.is_kernel_comment = True
-            else:
-                # Look for foo() or static void foo() - description;
-                # or misspelt identifier
-
-                r1 = Re(fr"^{decl_start}{fn_type}(\w+)\s*{parenthesis}\s*{decl_end}?$")
-                r2 = Re(fr"^{decl_start}{fn_type}(\w+[^-:]*){parenthesis}\s*{decl_end}$")
-
-                for r in [r1, r2]:
-                    if r.search(line):
-                        self.entry.identifier = r.group(1)
-                        self.entry.decl_type = "function"
-
-                        r = Re(r"define\s+")
-                        self.entry.identifier = r.sub("", self.entry.identifier)
-                        self.entry.is_kernel_comment = True
-                        break
-
-            self.entry.identifier = self.entry.identifier.strip(" ")
-
-            self.state = self.STATE_BODY
-
-            # if there's no @param blocks need to set up default section here
-            self.entry.section = self.section_default
-            self.entry.new_start_line = ln + 1
-
-            r = Re("[-:](.*)")
-            if r.search(line):
-                # strip leading/trailing/multiple spaces
-                self.entry.descr = r.group(1).strip(" ")
-
-                r = Re(r"\s+")
-                self.entry.descr = r.sub(" ", self.entry.descr)
-                self.entry.declaration_purpose = self.entry.descr
-                self.state = self.STATE_BODY_MAYBE
-            else:
-                self.entry.declaration_purpose = ""
-
-            if not self.entry.is_kernel_comment:
-                self.emit_warning(ln,
-                                  f"This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n{line}")
-                self.state = self.STATE_NORMAL
-
-            if not self.entry.declaration_purpose and self.config.wshort_desc:
-                self.emit_warning(ln,
-                                  f"missing initial short description on line:\n{line}")
-
-            if not self.entry.identifier and self.entry.decl_type != "enum":
-                self.emit_warning(ln,
-                                  f"wrong kernel-doc identifier on line:\n{line}")
-                self.state = self.STATE_NORMAL
-
-            if self.config.verbose:
-                self.emit_warning(ln,
-                                  f"Scanning doc for {self.entry.decl_type} {self.entry.identifier}",
-                             warning=False)
-
-            return
-
-        # Failed to find an identifier. Emit a warning
-        self.emit_warning(ln, f"Cannot find identifier on line:\n{line}")
-
-    def process_body(self, ln, line):
-        """
-        STATE_BODY and STATE_BODY_MAYBE: the bulk of a kerneldoc comment.
-        """
-
-        if self.state == self.STATE_BODY_WITH_BLANK_LINE:
-            r = Re(r"\s*\*\s?\S")
-            if r.match(line):
-                self.dump_section()
-                self.entry.section = self.section_default
-                self.entry.new_start_line = line
-                self.entry.contents = ""
-
-        if doc_sect.search(line):
-            self.entry.in_doc_sect = True
-            newsection = doc_sect.group(1)
-
-            if newsection.lower() in ["description", "context"]:
-                newsection = newsection.title()
-
-            # Special case: @return is a section, not a param description
-            if newsection.lower() in ["@return", "@returns",
-                                    "return", "returns"]:
-                newsection = "Return"
-
-            # Perl kernel-doc has a check here for contents before sections.
-            # the logic there is always false, as in_doc_sect variable is
-            # always true. So, just don't implement Wcontents_before_sections
-
-            # .title()
-            newcontents = doc_sect.group(2)
-            if not newcontents:
-                newcontents = ""
-
-            if self.entry.contents.strip("\n"):
-                self.dump_section()
-
-            self.entry.new_start_line = ln
-            self.entry.section = newsection
-            self.entry.leading_space = None
-
-            self.entry.contents = newcontents.lstrip()
-            if self.entry.contents:
-                self.entry.contents += "\n"
-
-            self.state = self.STATE_BODY
-            return
-
-        if doc_end.search(line):
-            self.dump_section()
-
-            # Look for doc_com + <text> + doc_end:
-            r = Re(r'\s*\*\s*[a-zA-Z_0-9:\.]+\*/')
-            if r.match(line):
-                self.emit_warning(ln, f"suspicious ending line: {line}")
-
-            self.entry.prototype = ""
-            self.entry.new_start_line = ln + 1
-
-            self.state = self.STATE_PROTO
-            return
-
-        if doc_content.search(line):
-            cont = doc_content.group(1)
-
-            if cont == "":
-                if self.entry.section == self.section_context:
-                    self.dump_section()
-
-                    self.entry.new_start_line = ln
-                    self.state = self.STATE_BODY
-                else:
-                    if self.entry.section != self.section_default:
-                        self.state = self.STATE_BODY_WITH_BLANK_LINE
-                    else:
-                        self.state = self.STATE_BODY
-
-                    self.entry.contents += "\n"
-
-            elif self.state == self.STATE_BODY_MAYBE:
-
-                # Continued declaration purpose
-                self.entry.declaration_purpose = self.entry.declaration_purpose.rstrip()
-                self.entry.declaration_purpose += " " + cont
-
-                r = Re(r"\s+")
-                self.entry.declaration_purpose = r.sub(' ',
-                                                       self.entry.declaration_purpose)
-
-            else:
-                if self.entry.section.startswith('@') or        \
-                   self.entry.section == self.section_context:
-                    if self.entry.leading_space is None:
-                        r = Re(r'^(\s+)')
-                        if r.match(cont):
-                            self.entry.leading_space = len(r.group(1))
-                        else:
-                            self.entry.leading_space = 0
-
-                    # Double-check if leading space are realy spaces
-                    pos = 0
-                    for i in range(0, self.entry.leading_space):
-                        if cont[i] != " ":
-                            break
-                        pos += 1
-
-                    cont = cont[pos:]
-
-                    # NEW LOGIC:
-                    # In case it is different, update it
-                    if self.entry.leading_space != pos:
-                        self.entry.leading_space = pos
-
-                self.entry.contents += cont + "\n"
-            return
-
-        # Unknown line, ignore
-        self.emit_warning(ln, f"bad line: {line}")
-
-    def process_inline(self, ln, line):
-        """STATE_INLINE: docbook comments within a prototype."""
-
-        if self.inline_doc_state == self.STATE_INLINE_NAME and \
-           doc_inline_sect.search(line):
-            self.entry.section = doc_inline_sect.group(1)
-            self.entry.new_start_line = ln
-
-            self.entry.contents = doc_inline_sect.group(2).lstrip()
-            if self.entry.contents != "":
-                self.entry.contents += "\n"
-
-            self.inline_doc_state = self.STATE_INLINE_TEXT
-            # Documentation block end */
-            return
-
-        if doc_inline_end.search(line):
-            if self.entry.contents not in ["", "\n"]:
-                self.dump_section()
-
-            self.state = self.STATE_PROTO
-            self.inline_doc_state = self.STATE_INLINE_NA
-            return
-
-        if doc_content.search(line):
-            if self.inline_doc_state == self.STATE_INLINE_TEXT:
-                self.entry.contents += doc_content.group(1) + "\n"
-                if not self.entry.contents.strip(" ").rstrip("\n"):
-                    self.entry.contents = ""
-
-            elif self.inline_doc_state == self.STATE_INLINE_NAME:
-                self.emit_warning(ln,
-                                  f"Incorrect use of kernel-doc format: {line}")
-
-                self.inline_doc_state = self.STATE_INLINE_ERROR
-
-    def syscall_munge(self, ln, proto):
-        """
-        Handle syscall definitions
-        """
-
-        is_void = False
-
-        # Strip newlines/CR's
-        proto = re.sub(r'[\r\n]+', ' ', proto)
-
-        # Check if it's a SYSCALL_DEFINE0
-        if 'SYSCALL_DEFINE0' in proto:
-            is_void = True
-
-        # Replace SYSCALL_DEFINE with correct return type & function name
-        proto = Re(r'SYSCALL_DEFINE.*\(').sub('long sys_', proto)
-
-        r = Re(r'long\s+(sys_.*?),')
-        if r.search(proto):
-            proto = proto.replace(',', '(', count=1)
-        elif is_void:
-            proto = proto.replace(')', '(void)', count=1)
-
-        # Now delete all of the odd-numbered commas in the proto
-        # so that argument types & names don't have a comma between them
-        count = 0
-        length = len(proto)
-
-        if is_void:
-            length = 0  # skip the loop if is_void
-
-        for ix in range(length):
-            if proto[ix] == ',':
-                count += 1
-                if count % 2 == 1:
-                    proto = proto[:ix] + ' ' + proto[ix+1:]
-
-        return proto
-
-    def tracepoint_munge(self, ln, proto):
-        """
-        Handle tracepoint definitions
-        """
-
-        tracepointname = None
-        tracepointargs = None
-
-        # Match tracepoint name based on different patterns
-        r = Re(r'TRACE_EVENT\((.*?),')
-        if r.search(proto):
-            tracepointname = r.group(1)
-
-        r = Re(r'DEFINE_SINGLE_EVENT\((.*?),')
-        if r.search(proto):
-            tracepointname = r.group(1)
-
-        r = Re(r'DEFINE_EVENT\((.*?),(.*?),')
-        if r.search(proto):
-            tracepointname = r.group(2)
-
-        if tracepointname:
-            tracepointname = tracepointname.lstrip()
-
-        r = Re(r'TP_PROTO\((.*?)\)')
-        if r.search(proto):
-            tracepointargs = r.group(1)
-
-        if not tracepointname or not tracepointargs:
-            self.emit_warning(ln,
-                              f"Unrecognized tracepoint format:\n{proto}\n")
-        else:
-            proto = f"static inline void trace_{tracepointname}({tracepointargs})"
-            self.entry.identifier = f"trace_{self.entry.identifier}"
-
-        return proto
-
-    def process_proto_function(self, ln, line):
-        """Ancillary routine to process a function prototype"""
-
-        # strip C99-style comments to end of line
-        r = Re(r"\/\/.*$", re.S)
-        line = r.sub('', line)
-
-        if Re(r'\s*#\s*define').match(line):
-            self.entry.prototype = line
-        elif line.startswith('#'):
-            # Strip other macros like #ifdef/#ifndef/#endif/...
-            pass
-        else:
-            r = Re(r'([^\{]*)')
-            if r.match(line):
-                self.entry.prototype += r.group(1) + " "
-
-        if '{' in line or ';' in line or Re(r'\s*#\s*define').match(line):
-            # strip comments
-            r = Re(r'/\*.*?\*/')
-            self.entry.prototype = r.sub('', self.entry.prototype)
-
-            # strip newlines/cr's
-            r = Re(r'[\r\n]+')
-            self.entry.prototype = r.sub(' ', self.entry.prototype)
-
-            # strip leading spaces
-            r = Re(r'^\s+')
-            self.entry.prototype = r.sub('', self.entry.prototype)
-
-            # Handle self.entry.prototypes for function pointers like:
-            #       int (*pcs_config)(struct foo)
-
-            r = Re(r'^(\S+\s+)\(\s*\*(\S+)\)')
-            self.entry.prototype = r.sub(r'\1\2', self.entry.prototype)
-
-            if 'SYSCALL_DEFINE' in self.entry.prototype:
-                self.entry.prototype = self.syscall_munge(ln,
-                                                          self.entry.prototype)
-
-            r = Re(r'TRACE_EVENT|DEFINE_EVENT|DEFINE_SINGLE_EVENT')
-            if r.search(self.entry.prototype):
-                self.entry.prototype = self.tracepoint_munge(ln,
-                                                             self.entry.prototype)
-
-            self.dump_function(ln, self.entry.prototype)
-            self.reset_state(ln)
-
-    def process_proto_type(self, ln, line):
-        """Ancillary routine to process a type"""
-
-        # Strip newlines/cr's.
-        line = Re(r'[\r\n]+', re.S).sub(' ', line)
-
-        # Strip leading spaces
-        line = Re(r'^\s+', re.S).sub('', line)
-
-        # Strip trailing spaces
-        line = Re(r'\s+$', re.S).sub('', line)
-
-        # Strip C99-style comments to the end of the line
-        line = Re(r"\/\/.*$", re.S).sub('', line)
-
-        # To distinguish preprocessor directive from regular declaration later.
-        if line.startswith('#'):
-            line += ";"
-
-        r = Re(r'([^\{\};]*)([\{\};])(.*)')
-        while True:
-            if r.search(line):
-                if self.entry.prototype:
-                    self.entry.prototype += " "
-                self.entry.prototype += r.group(1) + r.group(2)
-
-                self.entry.brcount += r.group(2).count('{')
-                self.entry.brcount -= r.group(2).count('}')
-
-                self.entry.brcount = max(self.entry.brcount, 0)
-
-                if r.group(2) == ';' and self.entry.brcount == 0:
-                    self.dump_declaration(ln, self.entry.prototype)
-                    self.reset_state(ln)
-                    break
-
-                line = r.group(3)
-            else:
-                self.entry.prototype += line
-                break
-
-    def process_proto(self, ln, line):
-        """STATE_PROTO: reading a function/whatever prototype."""
-
-        if doc_inline_oneline.search(line):
-            self.entry.section = doc_inline_oneline.group(1)
-            self.entry.contents = doc_inline_oneline.group(2)
-
-            if self.entry.contents != "":
-                self.entry.contents += "\n"
-                self.dump_section(start_new=False)
-
-        elif doc_inline_start.search(line):
-            self.state = self.STATE_INLINE
-            self.inline_doc_state = self.STATE_INLINE_NAME
-
-        elif self.entry.decl_type == 'function':
-            self.process_proto_function(ln, line)
-
-        else:
-            self.process_proto_type(ln, line)
-
-    def process_docblock(self, ln, line):
-        """STATE_DOCBLOCK: within a DOC: block."""
-
-        if doc_end.search(line):
-            self.dump_section()
-            self.output_declaration("doc", None,
-                       sectionlist=self.entry.sectionlist,
-                       sections=self.entry.sections,                    module=self.config.modulename)
-            self.reset_state(ln)
-
-        elif doc_content.search(line):
-            self.entry.contents += doc_content.group(1) + "\n"
-
-    def run(self):
-        """
-        Open and process each line of a C source file.
-        he parsing is controlled via a state machine, and the line is passed
-        to a different process function depending on the state. The process
-        function may update the state as needed.
-        """
-
-        cont = False
-        prev = ""
-        prev_ln = None
-
-        try:
-            with open(self.fname, "r", encoding="utf8",
-                      errors="backslashreplace") as fp:
-                for ln, line in enumerate(fp):
-
-                    line = line.expandtabs().strip("\n")
-
-                    # Group continuation lines on prototypes
-                    if self.state == self.STATE_PROTO:
-                        if line.endswith("\\"):
-                            prev += line.removesuffix("\\")
-                            cont = True
-
-                            if not prev_ln:
-                                prev_ln = ln
-
-                            continue
-
-                        if cont:
-                            ln = prev_ln
-                            line = prev + line
-                            prev = ""
-                            cont = False
-                            prev_ln = None
-
-                    self.config.log.debug("%d %s%s: %s",
-                                          ln, self.st_name[self.state],
-                                          self.st_inline_name[self.inline_doc_state],
-                                          line)
-
-                    # TODO: not all states allow EXPORT_SYMBOL*, so this
-                    # can be optimized later on to speedup parsing
-                    self.process_export(self.config.function_table, line)
-
-                    # Hand this line to the appropriate state handler
-                    if self.state == self.STATE_NORMAL:
-                        self.process_normal(ln, line)
-                    elif self.state == self.STATE_NAME:
-                        self.process_name(ln, line)
-                    elif self.state in [self.STATE_BODY, self.STATE_BODY_MAYBE,
-                                        self.STATE_BODY_WITH_BLANK_LINE]:
-                        self.process_body(ln, line)
-                    elif self.state == self.STATE_INLINE:  # scanning for inline parameters
-                        self.process_inline(ln, line)
-                    elif self.state == self.STATE_PROTO:
-                        self.process_proto(ln, line)
-                    elif self.state == self.STATE_DOCBLOCK:
-                        self.process_docblock(ln, line)
-        except OSError:
-            self.config.log.error(f"Error: Cannot open file {self.fname}")
-            self.config.errors += 1
-
-
 class GlobSourceFiles:
     """
     Parse C source code file names and directories via an Interactor.
diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py
new file mode 100755
index 000000000000..6d6395e32093
--- /dev/null
+++ b/scripts/lib/kdoc/kdoc_parser.py
@@ -0,0 +1,1689 @@
+#!/usr/bin/env python3
+# pylint: disable=C0301,C0302,R0904,R0912,R0913,R0914,R0915,R0917,R1702
+# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
+# SPDX-License-Identifier: GPL-2.0
+
+"""
+kdoc_parser
+===========
+
+Read a C language source or header FILE and extract embedded
+documentation comments
+"""
+
+import argparse
+import re
+from pprint import pformat
+
+from kdoc_re import NestedMatch, Re
+
+
+#
+# Regular expressions used to parse kernel-doc markups at KernelDoc class.
+#
+# Let's declare them in lowercase outside any class to make easier to
+# convert from the python script.
+#
+# As those are evaluated at the beginning, no need to cache them
+#
+
+# Allow whitespace at end of comment start.
+doc_start = Re(r'^/\*\*\s*$', cache=False)
+
+doc_end = Re(r'\*/', cache=False)
+doc_com = Re(r'\s*\*\s*', cache=False)
+doc_com_body = Re(r'\s*\* ?', cache=False)
+doc_decl = doc_com + Re(r'(\w+)', cache=False)
+
+# @params and a strictly limited set of supported section names
+# Specifically:
+#   Match @word:
+#         @...:
+#         @{section-name}:
+# while trying to not match literal block starts like "example::"
+#
+doc_sect = doc_com + \
+            Re(r'\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:([^:].*)?$',
+                flags=re.I, cache=False)
+
+doc_content = doc_com_body + Re(r'(.*)', cache=False)
+doc_block = doc_com + Re(r'DOC:\s*(.*)?', cache=False)
+doc_inline_start = Re(r'^\s*/\*\*\s*$', cache=False)
+doc_inline_sect = Re(r'\s*\*\s*(@\s*[\w][\w\.]*\s*):(.*)', cache=False)
+doc_inline_end = Re(r'^\s*\*/\s*$', cache=False)
+doc_inline_oneline = Re(r'^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$', cache=False)
+attribute = Re(r"__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)",
+               flags=re.I | re.S, cache=False)
+
+export_symbol = Re(r'^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*', cache=False)
+export_symbol_ns = Re(r'^\s*EXPORT_SYMBOL_NS(_GPL)?\s*\(\s*(\w+)\s*,\s*"\S+"\)\s*', cache=False)
+
+type_param = Re(r"\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False)
+
+
+class KernelDoc:
+    """
+    Read a C language source or header FILE and extract embedded
+    documentation comments.
+    """
+
+    # Parser states
+    STATE_NORMAL        = 0        # normal code
+    STATE_NAME          = 1        # looking for function name
+    STATE_BODY_MAYBE    = 2        # body - or maybe more description
+    STATE_BODY          = 3        # the body of the comment
+    STATE_BODY_WITH_BLANK_LINE = 4 # the body which has a blank line
+    STATE_PROTO         = 5        # scanning prototype
+    STATE_DOCBLOCK      = 6        # documentation block
+    STATE_INLINE        = 7        # gathering doc outside main block
+
+    st_name = [
+        "NORMAL",
+        "NAME",
+        "BODY_MAYBE",
+        "BODY",
+        "BODY_WITH_BLANK_LINE",
+        "PROTO",
+        "DOCBLOCK",
+        "INLINE",
+    ]
+
+    # Inline documentation state
+    STATE_INLINE_NA     = 0 # not applicable ($state != STATE_INLINE)
+    STATE_INLINE_NAME   = 1 # looking for member name (@foo:)
+    STATE_INLINE_TEXT   = 2 # looking for member documentation
+    STATE_INLINE_END    = 3 # done
+    STATE_INLINE_ERROR  = 4 # error - Comment without header was found.
+                            # Spit a warning as it's not
+                            # proper kernel-doc and ignore the rest.
+
+    st_inline_name = [
+        "",
+        "_NAME",
+        "_TEXT",
+        "_END",
+        "_ERROR",
+    ]
+
+    # Section names
+
+    section_default = "Description"  # default section
+    section_intro = "Introduction"
+    section_context = "Context"
+    section_return = "Return"
+
+    undescribed = "-- undescribed --"
+
+    def __init__(self, config, fname):
+        """Initialize internal variables"""
+
+        self.fname = fname
+        self.config = config
+
+        # Initial state for the state machines
+        self.state = self.STATE_NORMAL
+        self.inline_doc_state = self.STATE_INLINE_NA
+
+        # Store entry currently being processed
+        self.entry = None
+
+        # Place all potential outputs into an array
+        self.entries = []
+
+    def show_warnings(self, dtype, declaration_name):  # pylint: disable=W0613
+        """
+        Allow filtering out warnings
+        """
+
+        # TODO: implement it
+
+        return True
+
+    # TODO: rename to emit_message
+    def emit_warning(self, ln, msg, warning=True):
+        """Emit a message"""
+
+        if warning:
+            self.config.log.warning("%s:%d %s", self.fname, ln, msg)
+        else:
+            self.config.log.info("%s:%d %s", self.fname, ln, msg)
+
+    def dump_section(self, start_new=True):
+        """
+        Dumps section contents to arrays/hashes intended for that purpose.
+        """
+
+        name = self.entry.section
+        contents = self.entry.contents
+
+        # TODO: we can prevent dumping empty sections here with:
+        #
+        #    if self.entry.contents.strip("\n"):
+        #       if start_new:
+        #           self.entry.section = self.section_default
+        #           self.entry.contents = ""
+        #
+        #        return
+        #
+        # But, as we want to be producing the same output of the
+        # venerable kernel-doc Perl tool, let's just output everything,
+        # at least for now
+
+        if type_param.match(name):
+            name = type_param.group(1)
+
+            self.entry.parameterdescs[name] = contents
+            self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line
+
+            self.entry.sectcheck += name + " "
+            self.entry.new_start_line = 0
+
+        elif name == "@...":
+            name = "..."
+            self.entry.parameterdescs[name] = contents
+            self.entry.sectcheck += name + " "
+            self.entry.parameterdesc_start_lines[name] = self.entry.new_start_line
+            self.entry.new_start_line = 0
+
+        else:
+            if name in self.entry.sections and self.entry.sections[name] != "":
+                # Only warn on user-specified duplicate section names
+                if name != self.section_default:
+                    self.emit_warning(self.entry.new_start_line,
+                                      f"duplicate section name '{name}'\n")
+                self.entry.sections[name] += contents
+            else:
+                self.entry.sections[name] = contents
+                self.entry.sectionlist.append(name)
+                self.entry.section_start_lines[name] = self.entry.new_start_line
+                self.entry.new_start_line = 0
+
+#        self.config.log.debug("Section: %s : %s", name, pformat(vars(self.entry)))
+
+        if start_new:
+            self.entry.section = self.section_default
+            self.entry.contents = ""
+
+    # TODO: rename it to store_declaration
+    def output_declaration(self, dtype, name, **args):
+        """
+        Stores the entry into an entry array.
+
+        The actual output and output filters will be handled elsewhere
+        """
+
+        # The implementation here is different than the original kernel-doc:
+        # instead of checking for output filters or actually output anything,
+        # it just stores the declaration content at self.entries, as the
+        # output will happen on a separate class.
+        #
+        # For now, we're keeping the same name of the function just to make
+        # easier to compare the source code of both scripts
+
+        if "declaration_start_line" not in args:
+            args["declaration_start_line"] = self.entry.declaration_start_line
+
+        args["type"] = dtype
+
+        # TODO: use colletions.OrderedDict
+
+        sections = args.get('sections', {})
+        sectionlist = args.get('sectionlist', [])
+
+        # Drop empty sections
+        # TODO: improve it to emit warnings
+        for section in ["Description", "Return"]:
+            if section in sectionlist:
+                if not sections[section].rstrip():
+                    del sections[section]
+                    sectionlist.remove(section)
+
+        self.entries.append((name, args))
+
+        self.config.log.debug("Output: %s:%s = %s", dtype, name, pformat(args))
+
+    def reset_state(self, ln):
+        """
+        Ancillary routine to create a new entry. It initializes all
+        variables used by the state machine.
+        """
+
+        self.entry = argparse.Namespace
+
+        self.entry.contents = ""
+        self.entry.function = ""
+        self.entry.sectcheck = ""
+        self.entry.struct_actual = ""
+        self.entry.prototype = ""
+
+        self.entry.parameterlist = []
+        self.entry.parameterdescs = {}
+        self.entry.parametertypes = {}
+        self.entry.parameterdesc_start_lines = {}
+
+        self.entry.section_start_lines = {}
+        self.entry.sectionlist = []
+        self.entry.sections = {}
+
+        self.entry.anon_struct_union = False
+
+        self.entry.leading_space = None
+
+        # State flags
+        self.state = self.STATE_NORMAL
+        self.inline_doc_state = self.STATE_INLINE_NA
+        self.entry.brcount = 0
+
+        self.entry.in_doc_sect = False
+        self.entry.declaration_start_line = ln
+
+    def push_parameter(self, ln, decl_type, param, dtype,
+                       org_arg, declaration_name):
+        """
+        Store parameters and their descriptions at self.entry.
+        """
+
+        if self.entry.anon_struct_union and dtype == "" and param == "}":
+            return  # Ignore the ending }; from anonymous struct/union
+
+        self.entry.anon_struct_union = False
+
+        param = Re(r'[\[\)].*').sub('', param, count=1)
+
+        if dtype == "" and param.endswith("..."):
+            if Re(r'\w\.\.\.$').search(param):
+                # For named variable parameters of the form `x...`,
+                # remove the dots
+                param = param[:-3]
+            else:
+                # Handles unnamed variable parameters
+                param = "..."
+
+            if param not in self.entry.parameterdescs or \
+                not self.entry.parameterdescs[param]:
+
+                self.entry.parameterdescs[param] = "variable arguments"
+
+        elif dtype == "" and (not param or param == "void"):
+            param = "void"
+            self.entry.parameterdescs[param] = "no arguments"
+
+        elif dtype == "" and param in ["struct", "union"]:
+            # Handle unnamed (anonymous) union or struct
+            dtype = param
+            param = "{unnamed_" + param + "}"
+            self.entry.parameterdescs[param] = "anonymous\n"
+            self.entry.anon_struct_union = True
+
+        # Handle cache group enforcing variables: they do not need
+        # to be described in header files
+        elif "__cacheline_group" in param:
+            # Ignore __cacheline_group_begin and __cacheline_group_end
+            return
+
+        # Warn if parameter has no description
+        # (but ignore ones starting with # as these are not parameters
+        # but inline preprocessor statements)
+        if param not in self.entry.parameterdescs and not param.startswith("#"):
+            self.entry.parameterdescs[param] = self.undescribed
+
+            if self.show_warnings(dtype, declaration_name) and "." not in param:
+                if decl_type == 'function':
+                    dname = f"{decl_type} parameter"
+                else:
+                    dname = f"{decl_type} member"
+
+                self.emit_warning(ln,
+                                  f"{dname} '{param}' not described in '{declaration_name}'")
+
+        # Strip spaces from param so that it is one continuous string on
+        # parameterlist. This fixes a problem where check_sections()
+        # cannot find a parameter like "addr[6 + 2]" because it actually
+        # appears as "addr[6", "+", "2]" on the parameter list.
+        # However, it's better to maintain the param string unchanged for
+        # output, so just weaken the string compare in check_sections()
+        # to ignore "[blah" in a parameter string.
+
+        self.entry.parameterlist.append(param)
+        org_arg = Re(r'\s\s+').sub(' ', org_arg)
+        self.entry.parametertypes[param] = org_arg
+
+    def save_struct_actual(self, actual):
+        """
+        Strip all spaces from the actual param so that it looks like
+        one string item.
+        """
+
+        actual = Re(r'\s*').sub("", actual, count=1)
+
+        self.entry.struct_actual += actual + " "
+
+    def create_parameter_list(self, ln, decl_type, args,
+                              splitter, declaration_name):
+        """
+        Creates a list of parameters, storing them at self.entry.
+        """
+
+        # temporarily replace all commas inside function pointer definition
+        arg_expr = Re(r'(\([^\),]+),')
+        while arg_expr.search(args):
+            args = arg_expr.sub(r"\1#", args)
+
+        for arg in args.split(splitter):
+            # Strip comments
+            arg = Re(r'\/\*.*\*\/').sub('', arg)
+
+            # Ignore argument attributes
+            arg = Re(r'\sPOS0?\s').sub(' ', arg)
+
+            # Strip leading/trailing spaces
+            arg = arg.strip()
+            arg = Re(r'\s+').sub(' ', arg, count=1)
+
+            if arg.startswith('#'):
+                # Treat preprocessor directive as a typeless variable just to fill
+                # corresponding data structures "correctly". Catch it later in
+                # output_* subs.
+
+                # Treat preprocessor directive as a typeless variable
+                self.push_parameter(ln, decl_type, arg, "",
+                                    "", declaration_name)
+
+            elif Re(r'\(.+\)\s*\(').search(arg):
+                # Pointer-to-function
+
+                arg = arg.replace('#', ',')
+
+                r = Re(r'[^\(]+\(\*?\s*([\w\[\]\.]*)\s*\)')
+                if r.match(arg):
+                    param = r.group(1)
+                else:
+                    self.emit_warning(ln, f"Invalid param: {arg}")
+                    param = arg
+
+                dtype = Re(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg)
+                self.save_struct_actual(param)
+                self.push_parameter(ln, decl_type, param, dtype,
+                                    arg, declaration_name)
+
+            elif Re(r'\(.+\)\s*\[').search(arg):
+                # Array-of-pointers
+
+                arg = arg.replace('#', ',')
+                r = Re(r'[^\(]+\(\s*\*\s*([\w\[\]\.]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)')
+                if r.match(arg):
+                    param = r.group(1)
+                else:
+                    self.emit_warning(ln, f"Invalid param: {arg}")
+                    param = arg
+
+                dtype = Re(r'([^\(]+\(\*?)\s*' + re.escape(param)).sub(r'\1', arg)
+
+                self.save_struct_actual(param)
+                self.push_parameter(ln, decl_type, param, dtype,
+                                    arg, declaration_name)
+
+            elif arg:
+                arg = Re(r'\s*:\s*').sub(":", arg)
+                arg = Re(r'\s*\[').sub('[', arg)
+
+                args = Re(r'\s*,\s*').split(arg)
+                if args[0] and '*' in args[0]:
+                    args[0] = re.sub(r'(\*+)\s*', r' \1', args[0])
+
+                first_arg = []
+                r = Re(r'^(.*\s+)(.*?\[.*\].*)$')
+                if args[0] and r.match(args[0]):
+                    args.pop(0)
+                    first_arg.extend(r.group(1))
+                    first_arg.append(r.group(2))
+                else:
+                    first_arg = Re(r'\s+').split(args.pop(0))
+
+                args.insert(0, first_arg.pop())
+                dtype = ' '.join(first_arg)
+
+                for param in args:
+                    if Re(r'^(\*+)\s*(.*)').match(param):
+                        r = Re(r'^(\*+)\s*(.*)')
+                        if not r.match(param):
+                            self.emit_warning(ln, f"Invalid param: {param}")
+                            continue
+
+                        param = r.group(1)
+
+                        self.save_struct_actual(r.group(2))
+                        self.push_parameter(ln, decl_type, r.group(2),
+                                            f"{dtype} {r.group(1)}",
+                                            arg, declaration_name)
+
+                    elif Re(r'(.*?):(\w+)').search(param):
+                        r = Re(r'(.*?):(\w+)')
+                        if not r.match(param):
+                            self.emit_warning(ln, f"Invalid param: {param}")
+                            continue
+
+                        if dtype != "":  # Skip unnamed bit-fields
+                            self.save_struct_actual(r.group(1))
+                            self.push_parameter(ln, decl_type, r.group(1),
+                                                f"{dtype}:{r.group(2)}",
+                                                arg, declaration_name)
+                    else:
+                        self.save_struct_actual(param)
+                        self.push_parameter(ln, decl_type, param, dtype,
+                                            arg, declaration_name)
+
+    def check_sections(self, ln, decl_name, decl_type, sectcheck, prmscheck):
+        """
+        Check for errors inside sections, emitting warnings if not found
+        parameters are described.
+        """
+
+        sects = sectcheck.split()
+        prms = prmscheck.split()
+        err = False
+
+        for sx in range(len(sects)):                  # pylint: disable=C0200
+            err = True
+            for px in range(len(prms)):               # pylint: disable=C0200
+                prm_clean = prms[px]
+                prm_clean = Re(r'\[.*\]').sub('', prm_clean)
+                prm_clean = attribute.sub('', prm_clean)
+
+                # ignore array size in a parameter string;
+                # however, the original param string may contain
+                # spaces, e.g.:  addr[6 + 2]
+                # and this appears in @prms as "addr[6" since the
+                # parameter list is split at spaces;
+                # hence just ignore "[..." for the sections check;
+                prm_clean = Re(r'\[.*').sub('', prm_clean)
+
+                if prm_clean == sects[sx]:
+                    err = False
+                    break
+
+            if err:
+                if decl_type == 'function':
+                    dname = f"{decl_type} parameter"
+                else:
+                    dname = f"{decl_type} member"
+
+                self.emit_warning(ln,
+                                  f"Excess {dname} '{sects[sx]}' description in '{decl_name}'")
+
+    def check_return_section(self, ln, declaration_name, return_type):
+        """
+        If the function doesn't return void, warns about the lack of a
+        return description.
+        """
+
+        if not self.config.wreturn:
+            return
+
+        # Ignore an empty return type (It's a macro)
+        # Ignore functions with a "void" return type (but not "void *")
+        if not return_type or Re(r'void\s*\w*\s*$').search(return_type):
+            return
+
+        if not self.entry.sections.get("Return", None):
+            self.emit_warning(ln,
+                              f"No description found for return value of '{declaration_name}'")
+
+    def dump_struct(self, ln, proto):
+        """
+        Store an entry for an struct or union
+        """
+
+        type_pattern = r'(struct|union)'
+
+        qualifiers = [
+            "__attribute__",
+            "__packed",
+            "__aligned",
+            "____cacheline_aligned_in_smp",
+            "____cacheline_aligned",
+        ]
+
+        definition_body = r'\{(.*)\}\s*' + "(?:" + '|'.join(qualifiers) + ")?"
+        struct_members = Re(type_pattern + r'([^\{\};]+)(\{)([^\{\}]*)(\})([^\{\}\;]*)(\;)')
+
+        # Extract struct/union definition
+        members = None
+        declaration_name = None
+        decl_type = None
+
+        r = Re(type_pattern + r'\s+(\w+)\s*' + definition_body)
+        if r.search(proto):
+            decl_type = r.group(1)
+            declaration_name = r.group(2)
+            members = r.group(3)
+        else:
+            r = Re(r'typedef\s+' + type_pattern + r'\s*' + definition_body + r'\s*(\w+)\s*;')
+
+            if r.search(proto):
+                decl_type = r.group(1)
+                declaration_name = r.group(3)
+                members = r.group(2)
+
+        if not members:
+            self.emit_warning(ln, f"{proto} error: Cannot parse struct or union!")
+            self.config.errors += 1
+            return
+
+        if self.entry.identifier != declaration_name:
+            self.emit_warning(ln,
+                              f"expecting prototype for {decl_type} {self.entry.identifier}. Prototype was for {decl_type} {declaration_name} instead\n")
+            return
+
+        args_pattern = r'([^,)]+)'
+
+        sub_prefixes = [
+            (Re(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', re.S | re.I), ''),
+            (Re(r'\/\*\s*private:.*', re.S | re.I), ''),
+
+            # Strip comments
+            (Re(r'\/\*.*?\*\/', re.S), ''),
+
+            # Strip attributes
+            (attribute, ' '),
+            (Re(r'\s*__aligned\s*\([^;]*\)', re.S), ' '),
+            (Re(r'\s*__counted_by\s*\([^;]*\)', re.S), ' '),
+            (Re(r'\s*__counted_by_(le|be)\s*\([^;]*\)', re.S), ' '),
+            (Re(r'\s*__packed\s*', re.S), ' '),
+            (Re(r'\s*CRYPTO_MINALIGN_ATTR', re.S), ' '),
+            (Re(r'\s*____cacheline_aligned_in_smp', re.S), ' '),
+            (Re(r'\s*____cacheline_aligned', re.S), ' '),
+
+            # Unwrap struct_group macros based on this definition:
+            # __struct_group(TAG, NAME, ATTRS, MEMBERS...)
+            # which has variants like: struct_group(NAME, MEMBERS...)
+            # Only MEMBERS arguments require documentation.
+            #
+            # Parsing them happens on two steps:
+            #
+            # 1. drop struct group arguments that aren't at MEMBERS,
+            #    storing them as STRUCT_GROUP(MEMBERS)
+            #
+            # 2. remove STRUCT_GROUP() ancillary macro.
+            #
+            # The original logic used to remove STRUCT_GROUP() using an
+            # advanced regex:
+            #
+            #   \bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;
+            #
+            # with two patterns that are incompatible with
+            # Python re module, as it has:
+            #
+            #   - a recursive pattern: (?1)
+            #   - an atomic grouping: (?>...)
+            #
+            # I tried a simpler version: but it didn't work either:
+            #   \bSTRUCT_GROUP\(([^\)]+)\)[^;]*;
+            #
+            # As it doesn't properly match the end parenthesis on some cases.
+            #
+            # So, a better solution was crafted: there's now a NestedMatch
+            # class that ensures that delimiters after a search are properly
+            # matched. So, the implementation to drop STRUCT_GROUP() will be
+            # handled in separate.
+
+            (Re(r'\bstruct_group\s*\(([^,]*,)', re.S), r'STRUCT_GROUP('),
+            (Re(r'\bstruct_group_attr\s*\(([^,]*,){2}', re.S), r'STRUCT_GROUP('),
+            (Re(r'\bstruct_group_tagged\s*\(([^,]*),([^,]*),', re.S), r'struct \1 \2; STRUCT_GROUP('),
+            (Re(r'\b__struct_group\s*\(([^,]*,){3}', re.S), r'STRUCT_GROUP('),
+
+            # Replace macros
+            #
+            # TODO: it is better to also move those to the NestedMatch logic,
+            # to ensure that parenthesis will be properly matched.
+
+            (Re(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'),
+            (Re(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'),
+            (Re(r'DECLARE_BITMAP\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[BITS_TO_LONGS(\2)]'),
+            (Re(r'DECLARE_HASHTABLE\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[1 << ((\2) - 1)]'),
+            (Re(r'DECLARE_KFIFO\s*\(' + args_pattern + r',\s*' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'),
+            (Re(r'DECLARE_KFIFO_PTR\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'),
+            (Re(r'(?:__)?DECLARE_FLEX_ARRAY\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\1 \2[]'),
+            (Re(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + args_pattern + r'\)', re.S), r'dma_addr_t \1'),
+            (Re(r'DEFINE_DMA_UNMAP_LEN\s*\(' + args_pattern + r'\)', re.S), r'__u32 \1'),
+        ]
+
+        # Regexes here are guaranteed to have the end limiter matching
+        # the start delimiter. Yet, right now, only one replace group
+        # is allowed.
+
+        sub_nested_prefixes = [
+            (re.compile(r'\bSTRUCT_GROUP\('), r'\1'),
+        ]
+
+        for search, sub in sub_prefixes:
+            members = search.sub(sub, members)
+
+        nested = NestedMatch()
+
+        for search, sub in sub_nested_prefixes:
+            members = nested.sub(search, sub, members)
+
+        # Keeps the original declaration as-is
+        declaration = members
+
+        # Split nested struct/union elements
+        #
+        # This loop was simpler at the original kernel-doc perl version, as
+        #   while ($members =~ m/$struct_members/) { ... }
+        # reads 'members' string on each interaction.
+        #
+        # Python behavior is different: it parses 'members' only once,
+        # creating a list of tuples from the first interaction.
+        #
+        # On other words, this won't get nested structs.
+        #
+        # So, we need to have an extra loop on Python to override such
+        # re limitation.
+
+        while True:
+            tuples = struct_members.findall(members)
+            if not tuples:
+                break
+
+            for t in tuples:
+                newmember = ""
+                maintype = t[0]
+                s_ids = t[5]
+                content = t[3]
+
+                oldmember = "".join(t)
+
+                for s_id in s_ids.split(','):
+                    s_id = s_id.strip()
+
+                    newmember += f"{maintype} {s_id}; "
+                    s_id = Re(r'[:\[].*').sub('', s_id)
+                    s_id = Re(r'^\s*\**(\S+)\s*').sub(r'\1', s_id)
+
+                    for arg in content.split(';'):
+                        arg = arg.strip()
+
+                        if not arg:
+                            continue
+
+                        r = Re(r'^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)')
+                        if r.match(arg):
+                            # Pointer-to-function
+                            dtype = r.group(1)
+                            name = r.group(2)
+                            extra = r.group(3)
+
+                            if not name:
+                                continue
+
+                            if not s_id:
+                                # Anonymous struct/union
+                                newmember += f"{dtype}{name}{extra}; "
+                            else:
+                                newmember += f"{dtype}{s_id}.{name}{extra}; "
+
+                        else:
+                            arg = arg.strip()
+                            # Handle bitmaps
+                            arg = Re(r':\s*\d+\s*').sub('', arg)
+
+                            # Handle arrays
+                            arg = Re(r'\[.*\]').sub('', arg)
+
+                            # Handle multiple IDs
+                            arg = Re(r'\s*,\s*').sub(',', arg)
+
+                            r = Re(r'(.*)\s+([\S+,]+)')
+
+                            if r.search(arg):
+                                dtype = r.group(1)
+                                names = r.group(2)
+                            else:
+                                newmember += f"{arg}; "
+                                continue
+
+                            for name in names.split(','):
+                                name = Re(r'^\s*\**(\S+)\s*').sub(r'\1', name).strip()
+
+                                if not name:
+                                    continue
+
+                                if not s_id:
+                                    # Anonymous struct/union
+                                    newmember += f"{dtype} {name}; "
+                                else:
+                                    newmember += f"{dtype} {s_id}.{name}; "
+
+                members = members.replace(oldmember, newmember)
+
+        # Ignore other nested elements, like enums
+        members = re.sub(r'(\{[^\{\}]*\})', '', members)
+
+        self.create_parameter_list(ln, decl_type, members, ';',
+                                   declaration_name)
+        self.check_sections(ln, declaration_name, decl_type,
+                            self.entry.sectcheck, self.entry.struct_actual)
+
+        # Adjust declaration for better display
+        declaration = Re(r'([\{;])').sub(r'\1\n', declaration)
+        declaration = Re(r'\}\s+;').sub('};', declaration)
+
+        # Better handle inlined enums
+        while True:
+            r = Re(r'(enum\s+\{[^\}]+),([^\n])')
+            if not r.search(declaration):
+                break
+
+            declaration = r.sub(r'\1,\n\2', declaration)
+
+        def_args = declaration.split('\n')
+        level = 1
+        declaration = ""
+        for clause in def_args:
+
+            clause = clause.strip()
+            clause = Re(r'\s+').sub(' ', clause, count=1)
+
+            if not clause:
+                continue
+
+            if '}' in clause and level > 1:
+                level -= 1
+
+            if not Re(r'^\s*#').match(clause):
+                declaration += "\t" * level
+
+            declaration += "\t" + clause + "\n"
+            if "{" in clause and "}" not in clause:
+                level += 1
+
+        self.output_declaration(decl_type, declaration_name,
+                                struct=declaration_name,
+                                module=self.entry.modulename,
+                                definition=declaration,
+                                parameterlist=self.entry.parameterlist,
+                                parameterdescs=self.entry.parameterdescs,
+                                parametertypes=self.entry.parametertypes,
+                                sectionlist=self.entry.sectionlist,
+                                sections=self.entry.sections,
+                                purpose=self.entry.declaration_purpose)
+
+    def dump_enum(self, ln, proto):
+        """
+        Stores an enum inside self.entries array.
+        """
+
+        # Ignore members marked private
+        proto = Re(r'\/\*\s*private:.*?\/\*\s*public:.*?\*\/', flags=re.S).sub('', proto)
+        proto = Re(r'\/\*\s*private:.*}', flags=re.S).sub('}', proto)
+
+        # Strip comments
+        proto = Re(r'\/\*.*?\*\/', flags=re.S).sub('', proto)
+
+        # Strip #define macros inside enums
+        proto = Re(r'#\s*((define|ifdef|if)\s+|endif)[^;]*;', flags=re.S).sub('', proto)
+
+        members = None
+        declaration_name = None
+
+        r = Re(r'typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;')
+        if r.search(proto):
+            declaration_name = r.group(2)
+            members = r.group(1).rstrip()
+        else:
+            r = Re(r'enum\s+(\w*)\s*\{(.*)\}')
+            if r.match(proto):
+                declaration_name = r.group(1)
+                members = r.group(2).rstrip()
+
+        if not members:
+            self.emit_warning(ln, f"{proto}: error: Cannot parse enum!")
+            self.config.errors += 1
+            return
+
+        if self.entry.identifier != declaration_name:
+            if self.entry.identifier == "":
+                self.emit_warning(ln,
+                                  f"{proto}: wrong kernel-doc identifier on prototype")
+            else:
+                self.emit_warning(ln,
+                                  f"expecting prototype for enum {self.entry.identifier}. Prototype was for enum {declaration_name} instead")
+            return
+
+        if not declaration_name:
+            declaration_name = "(anonymous)"
+
+        member_set = set()
+
+        members = Re(r'\([^;]*?[\)]').sub('', members)
+
+        for arg in members.split(','):
+            if not arg:
+                continue
+            arg = Re(r'^\s*(\w+).*').sub(r'\1', arg)
+            self.entry.parameterlist.append(arg)
+            if arg not in self.entry.parameterdescs:
+                self.entry.parameterdescs[arg] = self.undescribed
+                if self.show_warnings("enum", declaration_name):
+                    self.emit_warning(ln,
+                                      f"Enum value '{arg}' not described in enum '{declaration_name}'")
+            member_set.add(arg)
+
+        for k in self.entry.parameterdescs:
+            if k not in member_set:
+                if self.show_warnings("enum", declaration_name):
+                    self.emit_warning(ln,
+                                      f"Excess enum value '%{k}' description in '{declaration_name}'")
+
+        self.output_declaration('enum', declaration_name,
+                                enum=declaration_name,
+                                module=self.config.modulename,
+                                parameterlist=self.entry.parameterlist,
+                                parameterdescs=self.entry.parameterdescs,
+                                sectionlist=self.entry.sectionlist,
+                                sections=self.entry.sections,
+                                purpose=self.entry.declaration_purpose)
+
+    def dump_declaration(self, ln, prototype):
+        """
+        Stores a data declaration inside self.entries array.
+        """
+
+        if self.entry.decl_type == "enum":
+            self.dump_enum(ln, prototype)
+            return
+
+        if self.entry.decl_type == "typedef":
+            self.dump_typedef(ln, prototype)
+            return
+
+        if self.entry.decl_type in ["union", "struct"]:
+            self.dump_struct(ln, prototype)
+            return
+
+        # TODO: handle other types
+        self.output_declaration(self.entry.decl_type, prototype,
+                                entry=self.entry)
+
+    def dump_function(self, ln, prototype):
+        """
+        Stores a function of function macro inside self.entries array.
+        """
+
+        func_macro = False
+        return_type = ''
+        decl_type = 'function'
+
+        # Prefixes that would be removed
+        sub_prefixes = [
+            (r"^static +", "", 0),
+            (r"^extern +", "", 0),
+            (r"^asmlinkage +", "", 0),
+            (r"^inline +", "", 0),
+            (r"^__inline__ +", "", 0),
+            (r"^__inline +", "", 0),
+            (r"^__always_inline +", "", 0),
+            (r"^noinline +", "", 0),
+            (r"^__FORTIFY_INLINE +", "", 0),
+            (r"__init +", "", 0),
+            (r"__init_or_module +", "", 0),
+            (r"__deprecated +", "", 0),
+            (r"__flatten +", "", 0),
+            (r"__meminit +", "", 0),
+            (r"__must_check +", "", 0),
+            (r"__weak +", "", 0),
+            (r"__sched +", "", 0),
+            (r"_noprof", "", 0),
+            (r"__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +", "", 0),
+            (r"__(?:re)?alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) +", "", 0),
+            (r"__diagnose_as\s*\(\s*\S+\s*(?:,\s*\d+\s*)*\) +", "", 0),
+            (r"DECL_BUCKET_PARAMS\s*\(\s*(\S+)\s*,\s*(\S+)\s*\)", r"\1, \2", 0),
+            (r"__attribute_const__ +", "", 0),
+
+            # It seems that Python support for re.X is broken:
+            # At least for me (Python 3.13), this didn't work
+#            (r"""
+#              __attribute__\s*\(\(
+#                (?:
+#                    [\w\s]+          # attribute name
+#                    (?:\([^)]*\))?   # attribute arguments
+#                    \s*,?            # optional comma at the end
+#                )+
+#              \)\)\s+
+#             """, "", re.X),
+
+            # So, remove whitespaces and comments from it
+            (r"__attribute__\s*\(\((?:[\w\s]+(?:\([^)]*\))?\s*,?)+\)\)\s+", "", 0),
+        ]
+
+        for search, sub, flags in sub_prefixes:
+            prototype = Re(search, flags).sub(sub, prototype)
+
+        # Macros are a special case, as they change the prototype format
+        new_proto = Re(r"^#\s*define\s+").sub("", prototype)
+        if new_proto != prototype:
+            is_define_proto = True
+            prototype = new_proto
+        else:
+            is_define_proto = False
+
+        # Yes, this truly is vile.  We are looking for:
+        # 1. Return type (may be nothing if we're looking at a macro)
+        # 2. Function name
+        # 3. Function parameters.
+        #
+        # All the while we have to watch out for function pointer parameters
+        # (which IIRC is what the two sections are for), C types (these
+        # regexps don't even start to express all the possibilities), and
+        # so on.
+        #
+        # If you mess with these regexps, it's a good idea to check that
+        # the following functions' documentation still comes out right:
+        # - parport_register_device (function pointer parameters)
+        # - atomic_set (macro)
+        # - pci_match_device, __copy_to_user (long return type)
+
+        name = r'[a-zA-Z0-9_~:]+'
+        prototype_end1 = r'[^\(]*'
+        prototype_end2 = r'[^\{]*'
+        prototype_end = fr'\(({prototype_end1}|{prototype_end2})\)'
+
+        # Besides compiling, Perl qr{[\w\s]+} works as a non-capturing group.
+        # So, this needs to be mapped in Python with (?:...)? or (?:...)+
+
+        type1 = r'(?:[\w\s]+)?'
+        type2 = r'(?:[\w\s]+\*+)+'
+
+        found = False
+
+        if is_define_proto:
+            r = Re(r'^()(' + name + r')\s+')
+
+            if r.search(prototype):
+                return_type = ''
+                declaration_name = r.group(2)
+                func_macro = True
+
+                found = True
+
+        if not found:
+            patterns = [
+                rf'^()({name})\s*{prototype_end}',
+                rf'^({type1})\s+({name})\s*{prototype_end}',
+                rf'^({type2})\s*({name})\s*{prototype_end}',
+            ]
+
+            for p in patterns:
+                r = Re(p)
+
+                if r.match(prototype):
+
+                    return_type = r.group(1)
+                    declaration_name = r.group(2)
+                    args = r.group(3)
+
+                    self.create_parameter_list(ln, decl_type, args, ',',
+                                               declaration_name)
+
+                    found = True
+                    break
+        if not found:
+            self.emit_warning(ln,
+                              f"cannot understand function prototype: '{prototype}'")
+            return
+
+        if self.entry.identifier != declaration_name:
+            self.emit_warning(ln,
+                              f"expecting prototype for {self.entry.identifier}(). Prototype was for {declaration_name}() instead")
+            return
+
+        prms = " ".join(self.entry.parameterlist)
+        self.check_sections(ln, declaration_name, "function",
+                            self.entry.sectcheck, prms)
+
+        self.check_return_section(ln, declaration_name, return_type)
+
+        if 'typedef' in return_type:
+            self.output_declaration(decl_type, declaration_name,
+                                    function=declaration_name,
+                                    typedef=True,
+                                    module=self.config.modulename,
+                                    functiontype=return_type,
+                                    parameterlist=self.entry.parameterlist,
+                                    parameterdescs=self.entry.parameterdescs,
+                                    parametertypes=self.entry.parametertypes,
+                                    sectionlist=self.entry.sectionlist,
+                                    sections=self.entry.sections,
+                                    purpose=self.entry.declaration_purpose,
+                                    func_macro=func_macro)
+        else:
+            self.output_declaration(decl_type, declaration_name,
+                                    function=declaration_name,
+                                    typedef=False,
+                                    module=self.config.modulename,
+                                    functiontype=return_type,
+                                    parameterlist=self.entry.parameterlist,
+                                    parameterdescs=self.entry.parameterdescs,
+                                    parametertypes=self.entry.parametertypes,
+                                    sectionlist=self.entry.sectionlist,
+                                    sections=self.entry.sections,
+                                    purpose=self.entry.declaration_purpose,
+                                    func_macro=func_macro)
+
+    def dump_typedef(self, ln, proto):
+        """
+        Stores a typedef inside self.entries array.
+        """
+
+        typedef_type = r'((?:\s+[\w\*]+\b){1,8})\s*'
+        typedef_ident = r'\*?\s*(\w\S+)\s*'
+        typedef_args = r'\s*\((.*)\);'
+
+        typedef1 = Re(r'typedef' + typedef_type + r'\(' + typedef_ident + r'\)' + typedef_args)
+        typedef2 = Re(r'typedef' + typedef_type + typedef_ident + typedef_args)
+
+        # Strip comments
+        proto = Re(r'/\*.*?\*/', flags=re.S).sub('', proto)
+
+        # Parse function typedef prototypes
+        for r in [typedef1, typedef2]:
+            if not r.match(proto):
+                continue
+
+            return_type = r.group(1).strip()
+            declaration_name = r.group(2)
+            args = r.group(3)
+
+            if self.entry.identifier != declaration_name:
+                self.emit_warning(ln,
+                                  f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
+                return
+
+            decl_type = 'function'
+            self.create_parameter_list(ln, decl_type, args, ',', declaration_name)
+
+            self.output_declaration(decl_type, declaration_name,
+                                    function=declaration_name,
+                                    typedef=True,
+                                    module=self.entry.modulename,
+                                    functiontype=return_type,
+                                    parameterlist=self.entry.parameterlist,
+                                    parameterdescs=self.entry.parameterdescs,
+                                    parametertypes=self.entry.parametertypes,
+                                    sectionlist=self.entry.sectionlist,
+                                    sections=self.entry.sections,
+                                    purpose=self.entry.declaration_purpose)
+            return
+
+        # Handle nested parentheses or brackets
+        r = Re(r'(\(*.\)\s*|\[*.\]\s*);$')
+        while r.search(proto):
+            proto = r.sub('', proto)
+
+        # Parse simple typedefs
+        r = Re(r'typedef.*\s+(\w+)\s*;')
+        if r.match(proto):
+            declaration_name = r.group(1)
+
+            if self.entry.identifier != declaration_name:
+                self.emit_warning(ln, f"expecting prototype for typedef {self.entry.identifier}. Prototype was for typedef {declaration_name} instead\n")
+                return
+
+            self.output_declaration('typedef', declaration_name,
+                                    typedef=declaration_name,
+                                    module=self.entry.modulename,
+                                    sectionlist=self.entry.sectionlist,
+                                    sections=self.entry.sections,
+                                    purpose=self.entry.declaration_purpose)
+            return
+
+        self.emit_warning(ln, "error: Cannot parse typedef!")
+        self.config.errors += 1
+
+    @staticmethod
+    def process_export(function_table, line):
+        """
+        process EXPORT_SYMBOL* tags
+
+        This method is called both internally and externally, so, it
+        doesn't use self.
+        """
+
+        if export_symbol.search(line):
+            symbol = export_symbol.group(2)
+            function_table.add(symbol)
+
+        if export_symbol_ns.search(line):
+            symbol = export_symbol_ns.group(2)
+            function_table.add(symbol)
+
+    def process_normal(self, ln, line):
+        """
+        STATE_NORMAL: looking for the /** to begin everything.
+        """
+
+        if not doc_start.match(line):
+            return
+
+        # start a new entry
+        self.reset_state(ln + 1)
+        self.entry.in_doc_sect = False
+
+        # next line is always the function name
+        self.state = self.STATE_NAME
+
+    def process_name(self, ln, line):
+        """
+        STATE_NAME: Looking for the "name - description" line
+        """
+
+        if doc_block.search(line):
+            self.entry.new_start_line = ln
+
+            if not doc_block.group(1):
+                self.entry.section = self.section_intro
+            else:
+                self.entry.section = doc_block.group(1)
+
+            self.state = self.STATE_DOCBLOCK
+            return
+
+        if doc_decl.search(line):
+            self.entry.identifier = doc_decl.group(1)
+            self.entry.is_kernel_comment = False
+
+            decl_start = str(doc_com)       # comment block asterisk
+            fn_type = r"(?:\w+\s*\*\s*)?"  # type (for non-functions)
+            parenthesis = r"(?:\(\w*\))?"   # optional parenthesis on function
+            decl_end = r"(?:[-:].*)"         # end of the name part
+
+            # test for pointer declaration type, foo * bar() - desc
+            r = Re(fr"^{decl_start}([\w\s]+?){parenthesis}?\s*{decl_end}?$")
+            if r.search(line):
+                self.entry.identifier = r.group(1)
+
+            # Test for data declaration
+            r = Re(r"^\s*\*?\s*(struct|union|enum|typedef)\b\s*(\w*)")
+            if r.search(line):
+                self.entry.decl_type = r.group(1)
+                self.entry.identifier = r.group(2)
+                self.entry.is_kernel_comment = True
+            else:
+                # Look for foo() or static void foo() - description;
+                # or misspelt identifier
+
+                r1 = Re(fr"^{decl_start}{fn_type}(\w+)\s*{parenthesis}\s*{decl_end}?$")
+                r2 = Re(fr"^{decl_start}{fn_type}(\w+[^-:]*){parenthesis}\s*{decl_end}$")
+
+                for r in [r1, r2]:
+                    if r.search(line):
+                        self.entry.identifier = r.group(1)
+                        self.entry.decl_type = "function"
+
+                        r = Re(r"define\s+")
+                        self.entry.identifier = r.sub("", self.entry.identifier)
+                        self.entry.is_kernel_comment = True
+                        break
+
+            self.entry.identifier = self.entry.identifier.strip(" ")
+
+            self.state = self.STATE_BODY
+
+            # if there's no @param blocks need to set up default section here
+            self.entry.section = self.section_default
+            self.entry.new_start_line = ln + 1
+
+            r = Re("[-:](.*)")
+            if r.search(line):
+                # strip leading/trailing/multiple spaces
+                self.entry.descr = r.group(1).strip(" ")
+
+                r = Re(r"\s+")
+                self.entry.descr = r.sub(" ", self.entry.descr)
+                self.entry.declaration_purpose = self.entry.descr
+                self.state = self.STATE_BODY_MAYBE
+            else:
+                self.entry.declaration_purpose = ""
+
+            if not self.entry.is_kernel_comment:
+                self.emit_warning(ln,
+                                  f"This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n{line}")
+                self.state = self.STATE_NORMAL
+
+            if not self.entry.declaration_purpose and self.config.wshort_desc:
+                self.emit_warning(ln,
+                                  f"missing initial short description on line:\n{line}")
+
+            if not self.entry.identifier and self.entry.decl_type != "enum":
+                self.emit_warning(ln,
+                                  f"wrong kernel-doc identifier on line:\n{line}")
+                self.state = self.STATE_NORMAL
+
+            if self.config.verbose:
+                self.emit_warning(ln,
+                                  f"Scanning doc for {self.entry.decl_type} {self.entry.identifier}",
+                                  warning=False)
+
+            return
+
+        # Failed to find an identifier. Emit a warning
+        self.emit_warning(ln, f"Cannot find identifier on line:\n{line}")
+
+    def process_body(self, ln, line):
+        """
+        STATE_BODY and STATE_BODY_MAYBE: the bulk of a kerneldoc comment.
+        """
+
+        if self.state == self.STATE_BODY_WITH_BLANK_LINE:
+            r = Re(r"\s*\*\s?\S")
+            if r.match(line):
+                self.dump_section()
+                self.entry.section = self.section_default
+                self.entry.new_start_line = line
+                self.entry.contents = ""
+
+        if doc_sect.search(line):
+            self.entry.in_doc_sect = True
+            newsection = doc_sect.group(1)
+
+            if newsection.lower() in ["description", "context"]:
+                newsection = newsection.title()
+
+            # Special case: @return is a section, not a param description
+            if newsection.lower() in ["@return", "@returns",
+                                      "return", "returns"]:
+                newsection = "Return"
+
+            # Perl kernel-doc has a check here for contents before sections.
+            # the logic there is always false, as in_doc_sect variable is
+            # always true. So, just don't implement Wcontents_before_sections
+
+            # .title()
+            newcontents = doc_sect.group(2)
+            if not newcontents:
+                newcontents = ""
+
+            if self.entry.contents.strip("\n"):
+                self.dump_section()
+
+            self.entry.new_start_line = ln
+            self.entry.section = newsection
+            self.entry.leading_space = None
+
+            self.entry.contents = newcontents.lstrip()
+            if self.entry.contents:
+                self.entry.contents += "\n"
+
+            self.state = self.STATE_BODY
+            return
+
+        if doc_end.search(line):
+            self.dump_section()
+
+            # Look for doc_com + <text> + doc_end:
+            r = Re(r'\s*\*\s*[a-zA-Z_0-9:\.]+\*/')
+            if r.match(line):
+                self.emit_warning(ln, f"suspicious ending line: {line}")
+
+            self.entry.prototype = ""
+            self.entry.new_start_line = ln + 1
+
+            self.state = self.STATE_PROTO
+            return
+
+        if doc_content.search(line):
+            cont = doc_content.group(1)
+
+            if cont == "":
+                if self.entry.section == self.section_context:
+                    self.dump_section()
+
+                    self.entry.new_start_line = ln
+                    self.state = self.STATE_BODY
+                else:
+                    if self.entry.section != self.section_default:
+                        self.state = self.STATE_BODY_WITH_BLANK_LINE
+                    else:
+                        self.state = self.STATE_BODY
+
+                    self.entry.contents += "\n"
+
+            elif self.state == self.STATE_BODY_MAYBE:
+
+                # Continued declaration purpose
+                self.entry.declaration_purpose = self.entry.declaration_purpose.rstrip()
+                self.entry.declaration_purpose += " " + cont
+
+                r = Re(r"\s+")
+                self.entry.declaration_purpose = r.sub(' ',
+                                                       self.entry.declaration_purpose)
+
+            else:
+                if self.entry.section.startswith('@') or        \
+                   self.entry.section == self.section_context:
+                    if self.entry.leading_space is None:
+                        r = Re(r'^(\s+)')
+                        if r.match(cont):
+                            self.entry.leading_space = len(r.group(1))
+                        else:
+                            self.entry.leading_space = 0
+
+                    # Double-check if leading space are realy spaces
+                    pos = 0
+                    for i in range(0, self.entry.leading_space):
+                        if cont[i] != " ":
+                            break
+                        pos += 1
+
+                    cont = cont[pos:]
+
+                    # NEW LOGIC:
+                    # In case it is different, update it
+                    if self.entry.leading_space != pos:
+                        self.entry.leading_space = pos
+
+                self.entry.contents += cont + "\n"
+            return
+
+        # Unknown line, ignore
+        self.emit_warning(ln, f"bad line: {line}")
+
+    def process_inline(self, ln, line):
+        """STATE_INLINE: docbook comments within a prototype."""
+
+        if self.inline_doc_state == self.STATE_INLINE_NAME and \
+           doc_inline_sect.search(line):
+            self.entry.section = doc_inline_sect.group(1)
+            self.entry.new_start_line = ln
+
+            self.entry.contents = doc_inline_sect.group(2).lstrip()
+            if self.entry.contents != "":
+                self.entry.contents += "\n"
+
+            self.inline_doc_state = self.STATE_INLINE_TEXT
+            # Documentation block end */
+            return
+
+        if doc_inline_end.search(line):
+            if self.entry.contents not in ["", "\n"]:
+                self.dump_section()
+
+            self.state = self.STATE_PROTO
+            self.inline_doc_state = self.STATE_INLINE_NA
+            return
+
+        if doc_content.search(line):
+            if self.inline_doc_state == self.STATE_INLINE_TEXT:
+                self.entry.contents += doc_content.group(1) + "\n"
+                if not self.entry.contents.strip(" ").rstrip("\n"):
+                    self.entry.contents = ""
+
+            elif self.inline_doc_state == self.STATE_INLINE_NAME:
+                self.emit_warning(ln,
+                                  f"Incorrect use of kernel-doc format: {line}")
+
+                self.inline_doc_state = self.STATE_INLINE_ERROR
+
+    def syscall_munge(self, ln, proto):         # pylint: disable=W0613
+        """
+        Handle syscall definitions
+        """
+
+        is_void = False
+
+        # Strip newlines/CR's
+        proto = re.sub(r'[\r\n]+', ' ', proto)
+
+        # Check if it's a SYSCALL_DEFINE0
+        if 'SYSCALL_DEFINE0' in proto:
+            is_void = True
+
+        # Replace SYSCALL_DEFINE with correct return type & function name
+        proto = Re(r'SYSCALL_DEFINE.*\(').sub('long sys_', proto)
+
+        r = Re(r'long\s+(sys_.*?),')
+        if r.search(proto):
+            proto = proto.replace(',', '(', count=1)
+        elif is_void:
+            proto = proto.replace(')', '(void)', count=1)
+
+        # Now delete all of the odd-numbered commas in the proto
+        # so that argument types & names don't have a comma between them
+        count = 0
+        length = len(proto)
+
+        if is_void:
+            length = 0  # skip the loop if is_void
+
+        for ix in range(length):
+            if proto[ix] == ',':
+                count += 1
+                if count % 2 == 1:
+                    proto = proto[:ix] + ' ' + proto[ix + 1:]
+
+        return proto
+
+    def tracepoint_munge(self, ln, proto):
+        """
+        Handle tracepoint definitions
+        """
+
+        tracepointname = None
+        tracepointargs = None
+
+        # Match tracepoint name based on different patterns
+        r = Re(r'TRACE_EVENT\((.*?),')
+        if r.search(proto):
+            tracepointname = r.group(1)
+
+        r = Re(r'DEFINE_SINGLE_EVENT\((.*?),')
+        if r.search(proto):
+            tracepointname = r.group(1)
+
+        r = Re(r'DEFINE_EVENT\((.*?),(.*?),')
+        if r.search(proto):
+            tracepointname = r.group(2)
+
+        if tracepointname:
+            tracepointname = tracepointname.lstrip()
+
+        r = Re(r'TP_PROTO\((.*?)\)')
+        if r.search(proto):
+            tracepointargs = r.group(1)
+
+        if not tracepointname or not tracepointargs:
+            self.emit_warning(ln,
+                              f"Unrecognized tracepoint format:\n{proto}\n")
+        else:
+            proto = f"static inline void trace_{tracepointname}({tracepointargs})"
+            self.entry.identifier = f"trace_{self.entry.identifier}"
+
+        return proto
+
+    def process_proto_function(self, ln, line):
+        """Ancillary routine to process a function prototype"""
+
+        # strip C99-style comments to end of line
+        r = Re(r"\/\/.*$", re.S)
+        line = r.sub('', line)
+
+        if Re(r'\s*#\s*define').match(line):
+            self.entry.prototype = line
+        elif line.startswith('#'):
+            # Strip other macros like #ifdef/#ifndef/#endif/...
+            pass
+        else:
+            r = Re(r'([^\{]*)')
+            if r.match(line):
+                self.entry.prototype += r.group(1) + " "
+
+        if '{' in line or ';' in line or Re(r'\s*#\s*define').match(line):
+            # strip comments
+            r = Re(r'/\*.*?\*/')
+            self.entry.prototype = r.sub('', self.entry.prototype)
+
+            # strip newlines/cr's
+            r = Re(r'[\r\n]+')
+            self.entry.prototype = r.sub(' ', self.entry.prototype)
+
+            # strip leading spaces
+            r = Re(r'^\s+')
+            self.entry.prototype = r.sub('', self.entry.prototype)
+
+            # Handle self.entry.prototypes for function pointers like:
+            #       int (*pcs_config)(struct foo)
+
+            r = Re(r'^(\S+\s+)\(\s*\*(\S+)\)')
+            self.entry.prototype = r.sub(r'\1\2', self.entry.prototype)
+
+            if 'SYSCALL_DEFINE' in self.entry.prototype:
+                self.entry.prototype = self.syscall_munge(ln,
+                                                          self.entry.prototype)
+
+            r = Re(r'TRACE_EVENT|DEFINE_EVENT|DEFINE_SINGLE_EVENT')
+            if r.search(self.entry.prototype):
+                self.entry.prototype = self.tracepoint_munge(ln,
+                                                             self.entry.prototype)
+
+            self.dump_function(ln, self.entry.prototype)
+            self.reset_state(ln)
+
+    def process_proto_type(self, ln, line):
+        """Ancillary routine to process a type"""
+
+        # Strip newlines/cr's.
+        line = Re(r'[\r\n]+', re.S).sub(' ', line)
+
+        # Strip leading spaces
+        line = Re(r'^\s+', re.S).sub('', line)
+
+        # Strip trailing spaces
+        line = Re(r'\s+$', re.S).sub('', line)
+
+        # Strip C99-style comments to the end of the line
+        line = Re(r"\/\/.*$", re.S).sub('', line)
+
+        # To distinguish preprocessor directive from regular declaration later.
+        if line.startswith('#'):
+            line += ";"
+
+        r = Re(r'([^\{\};]*)([\{\};])(.*)')
+        while True:
+            if r.search(line):
+                if self.entry.prototype:
+                    self.entry.prototype += " "
+                self.entry.prototype += r.group(1) + r.group(2)
+
+                self.entry.brcount += r.group(2).count('{')
+                self.entry.brcount -= r.group(2).count('}')
+
+                self.entry.brcount = max(self.entry.brcount, 0)
+
+                if r.group(2) == ';' and self.entry.brcount == 0:
+                    self.dump_declaration(ln, self.entry.prototype)
+                    self.reset_state(ln)
+                    break
+
+                line = r.group(3)
+            else:
+                self.entry.prototype += line
+                break
+
+    def process_proto(self, ln, line):
+        """STATE_PROTO: reading a function/whatever prototype."""
+
+        if doc_inline_oneline.search(line):
+            self.entry.section = doc_inline_oneline.group(1)
+            self.entry.contents = doc_inline_oneline.group(2)
+
+            if self.entry.contents != "":
+                self.entry.contents += "\n"
+                self.dump_section(start_new=False)
+
+        elif doc_inline_start.search(line):
+            self.state = self.STATE_INLINE
+            self.inline_doc_state = self.STATE_INLINE_NAME
+
+        elif self.entry.decl_type == 'function':
+            self.process_proto_function(ln, line)
+
+        else:
+            self.process_proto_type(ln, line)
+
+    def process_docblock(self, ln, line):
+        """STATE_DOCBLOCK: within a DOC: block."""
+
+        if doc_end.search(line):
+            self.dump_section()
+            self.output_declaration("doc", None,
+                                    sectionlist=self.entry.sectionlist,
+                                    sections=self.entry.sections, module=self.config.modulename)
+            self.reset_state(ln)
+
+        elif doc_content.search(line):
+            self.entry.contents += doc_content.group(1) + "\n"
+
+    def run(self):
+        """
+        Open and process each line of a C source file.
+        he parsing is controlled via a state machine, and the line is passed
+        to a different process function depending on the state. The process
+        function may update the state as needed.
+        """
+
+        cont = False
+        prev = ""
+        prev_ln = None
+
+        try:
+            with open(self.fname, "r", encoding="utf8",
+                      errors="backslashreplace") as fp:
+                for ln, line in enumerate(fp):
+
+                    line = line.expandtabs().strip("\n")
+
+                    # Group continuation lines on prototypes
+                    if self.state == self.STATE_PROTO:
+                        if line.endswith("\\"):
+                            prev += line.removesuffix("\\")
+                            cont = True
+
+                            if not prev_ln:
+                                prev_ln = ln
+
+                            continue
+
+                        if cont:
+                            ln = prev_ln
+                            line = prev + line
+                            prev = ""
+                            cont = False
+                            prev_ln = None
+
+                    self.config.log.debug("%d %s%s: %s",
+                                          ln, self.st_name[self.state],
+                                          self.st_inline_name[self.inline_doc_state],
+                                          line)
+
+                    # TODO: not all states allow EXPORT_SYMBOL*, so this
+                    # can be optimized later on to speedup parsing
+                    self.process_export(self.config.function_table, line)
+
+                    # Hand this line to the appropriate state handler
+                    if self.state == self.STATE_NORMAL:
+                        self.process_normal(ln, line)
+                    elif self.state == self.STATE_NAME:
+                        self.process_name(ln, line)
+                    elif self.state in [self.STATE_BODY, self.STATE_BODY_MAYBE,
+                                        self.STATE_BODY_WITH_BLANK_LINE]:
+                        self.process_body(ln, line)
+                    elif self.state == self.STATE_INLINE:  # scanning for inline parameters
+                        self.process_inline(ln, line)
+                    elif self.state == self.STATE_PROTO:
+                        self.process_proto(ln, line)
+                    elif self.state == self.STATE_DOCBLOCK:
+                        self.process_docblock(ln, line)
+        except OSError:
+            self.config.log.error(f"Error: Cannot open file {self.fname}")
+            self.config.errors += 1
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser
  2025-02-24  9:08 ` [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser Mauro Carvalho Chehab
@ 2025-02-24 23:38   ` Jonathan Corbet
  2025-02-25  7:38     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 10+ messages in thread
From: Jonathan Corbet @ 2025-02-24 23:38 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Linux Doc Mailing List
  Cc: Mauro Carvalho Chehab, Gustavo A. R. Silva, Mauro Carvalho Chehab,
	Kees Cook, linux-hardening, linux-kernel

Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:

> Maintaining kernel-doc has been a challenge, as there aren't many
> perl developers among maintainers. Also, the logic there is too
> complex. Having lots of global variables and using pure functions
> doesn't help.
>
> Rewrite the script in Python, placing most global variables
> inside classes. This should help maintaining the script in long
> term.

[...]

> diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
> new file mode 100755
> index 000000000000..5cf5ed63f215
> --- /dev/null
> +++ b/scripts/kernel-doc.py
> @@ -0,0 +1,2757 @@
> +#!/usr/bin/env python3
> +# pylint: disable=R0902,R0903,R0904,R0911,R0912,R0913,R0914,R0915,R0917,R1702
> +# pylint: disable=C0302,C0103,C0301
> +# pylint: disable=C0116,C0115,W0511,W0613
> +# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
> +# SPDX-License-Identifier: GPL-2.0

The SPDX tag is supposed to be up top, right under the shebang

I also think you should give consideration to preserving the other
copyright notices in the Perl version.  A language translation doesn't
remove existing copyrights...who knows how much creativity went into
some of those regexes?

> +# TODO: implement warning filtering
> +
> +"""
> +kernel_doc
> +==========
> +
> +Print formatted kernel documentation to stdout
> +
> +Read C language source or header FILEs, extract embedded
> +documentation comments, and print formatted documentation
> +to standard output.
> +
> +The documentation comments are identified by the "/**"
> +opening comment mark.
> +
> +See Documentation/doc-guide/kernel-doc.rst for the
> +documentation comment syntax.
> +"""
> +
> +import argparse
> +import logging
> +import os
> +import re
> +import sys
> +
> +from datetime import datetime
> +from pprint import pformat
> +
> +from dateutil import tz
> +
> +# Local cache for regular expressions
> +re_cache = {}
> +
> +
> +class Re:

So I have to say this bugs me a bit ... the class is fine, but the
one-letter case-only difference from the standard "re" class is just
going to make the code harder for others to approach.  "kern_re" or
something like that?  Or even "kre" if you really want it to be as short
as possible.

> +    """
> +    Helper class to simplify regex declaration and usage,
> +
> +    It calls re.compile for a given pattern. It also allows adding
> +    regular expressions and define sub at class init time.
> +
> +    Regular expressions can be cached via an argument, helping to speedup
> +    searches.
> +    """

[...]

> +
> +class KernelDoc:
> +    # Parser states
> +    STATE_NORMAL        = 0        # normal code
> +    STATE_NAME          = 1        # looking for function name
> +    STATE_BODY_MAYBE    = 2        # body - or maybe more description
> +    STATE_BODY          = 3        # the body of the comment
> +    STATE_BODY_WITH_BLANK_LINE = 4 # the body which has a blank line
> +    STATE_PROTO         = 5        # scanning prototype
> +    STATE_DOCBLOCK      = 6        # documentation block
> +    STATE_INLINE        = 7        # gathering doc outside main block
> +
> +    st_name = [
> +        "NORMAL",
> +        "NAME",
> +        "BODY_MAYBE",
> +        "BODY",
> +        "BODY_WITH_BLANK_LINE",
> +        "PROTO",
> +        "DOCBLOCK",
> +        "INLINE",
> +    ]

So these ... kind of look like enums?

That's kind of it for nits ... I do have one wish that will kind of hard
to grant overall ... for the long-term maintenance of this code, it
would be really nice if every non-trivial regex were described by a
comment explaining what it is trying to do.  It's not reasonable to
expect that as a condition for accepting this rewrite, but it sure would
be a nice goal to be working toward.

Thanks,

jon

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 00/39] Implement kernel-doc in Python
  2025-02-24  9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
  2025-02-24  9:08 ` [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser Mauro Carvalho Chehab
  2025-02-24  9:08 ` [PATCH v2 14/39] scripts/kernel-doc.py: move KernelDoc class to a separate file Mauro Carvalho Chehab
@ 2025-02-24 23:49 ` Jonathan Corbet
  2025-02-25  7:54   ` Mauro Carvalho Chehab
  2 siblings, 1 reply; 10+ messages in thread
From: Jonathan Corbet @ 2025-02-24 23:49 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Linux Doc Mailing List
  Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel,
	Gustavo A. R. Silva, Arnd Bergmann, Bingbu Cao,
	Greg Kroah-Hartman, Kees Cook, Sakari Ailus, Takashi Sakamoto,
	Tianshu Qiu, linux-arch, linux-hardening, linux-media,
	linux-staging, linux1394-devel

Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:

> Hi Jon,
>
> This changeset contains the kernel-doc.py script to replace the verable
> kernel-doc originally written in Perl. It replaces the first version and the
> second series I sent on the top of it.

I've sent minor comments on a couple of the patches.  The new version
works for me, I can't find any real problems with it.

Here's the question: what were your thoughts on when to do this?  I can
certainly take the initial fixup patches and get them out of your queue,
but at some point there will be a need to dive into the deep end.  I'm
just a bit leery of doing that as we head toward -rc5...  what do you
think of "just after the merge window"?

I'm definitely looking forward to no longer having to bash my head
against the Perl version...

Thanks,

jon

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser
  2025-02-24 23:38   ` Jonathan Corbet
@ 2025-02-25  7:38     ` Mauro Carvalho Chehab
  2025-02-25 20:10       ` Jonathan Corbet
  0 siblings, 1 reply; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-25  7:38 UTC (permalink / raw)
  To: Jonathan Corbet; +Cc: Linux Doc Mailing List, linux-hardening, linux-kernel

Em Mon, 24 Feb 2025 16:38:58 -0700
Jonathan Corbet <corbet@lwn.net> escreveu:

> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
> 
> > Maintaining kernel-doc has been a challenge, as there aren't many
> > perl developers among maintainers. Also, the logic there is too
> > complex. Having lots of global variables and using pure functions
> > doesn't help.
> >
> > Rewrite the script in Python, placing most global variables
> > inside classes. This should help maintaining the script in long
> > term.  
> 
> [...]
> 
> > diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
> > new file mode 100755
> > index 000000000000..5cf5ed63f215
> > --- /dev/null
> > +++ b/scripts/kernel-doc.py
> > @@ -0,0 +1,2757 @@
> > +#!/usr/bin/env python3
> > +# pylint: disable=R0902,R0903,R0904,R0911,R0912,R0913,R0914,R0915,R0917,R1702
> > +# pylint: disable=C0302,C0103,C0301
> > +# pylint: disable=C0116,C0115,W0511,W0613
> > +# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
> > +# SPDX-License-Identifier: GPL-2.0  
> 
> The SPDX tag is supposed to be up top, right under the shebang

I'll move it. 

> 
> I also think you should give consideration to preserving the other
> copyright notices in the Perl version.  A language translation doesn't
> remove existing copyrights...who knows how much creativity went into
> some of those regexes?

Makes sense, but the copyrights at kernel-doc.pl:

	## Copyright (c) 1998 Michael Zucchi, All Rights Reserved        ##
	## Copyright (C) 2000, 1  Tim Waugh <twaugh@redhat.com>          ##
	## Copyright (C) 2001  Simon Huggins                             ##
	## Copyright (C) 2005-2012  Randy Dunlap                         ##
	## Copyright (C) 2012  Dan Luedtke                               ##
	##                                                               ##
	## #define enhancements by Armin Kuster <akuster@mvista.com>     ##
	## Copyright (c) 2000 MontaVista Software, Inc.                  ##
	#
	# Copyright (C) 2022 Tomasz Warniełło (POD)

Also doesn't preserve all copyrights from people that worked hard to
maintain it all over those years.

A quick check with git log shows 68 different authors touching it
(didn't check how trivial/hard were the changes):

$ git log --follow --pretty="%an" scripts/kernel-doc.pl|sort|uniq -c|sort -n
      1 Alexander A. Klimov
      1 Alexander Lobakin
      1 Anna-Maria Behnsen
      1 Bart Van Assche
      1 Chen-Yu Tsai
      1 Coco Li
      1 Dan Luedtke
      1 Donald Hunter
      1 Gabriel Krisman Bertazi
      1 Greg Kroah-Hartman
      1 Harvey Harrison
      1 Horia Geanta
      1 Jason Gunthorpe
      1 Jérémy Bobbio
      1 Johannes Weiner
      1 Jonathan Cameron
      1 Kamil Rytarowski
      1 Laurent Pinchart
      1 Levin, Alexander (Sasha Levin)
      1 Linus Torvalds
      1 Lucas De Marchi
      1 Mark Rutland
      1 Masahiro Yamada
      1 Michal Wajdeczko
      1 Niklas Söderlund
      1 Nishanth Menon
      1 Peter Maydell
      1 Pierre-Louis Bossart
      1 Randy.Dunlap
      1 Richard Kennedy
      1 Rich Walker
      1 Rolf Eike Beer
      1 Silvio Fricke
      1 Utkarsh Tripathi
      1 valdis.kletnieks@vt.edu
      1 Will Deacon
      2 Ilya Dryomov
      2 Jakub Kicinski
      2 Jason Baron
      2 Jonathan Neuschäfer
      2 Markus Heiser
      2 Pavan Kumar Linga
      2 Pavel Pisa
      2 Sakari Ailus
      2 Yacine Belkadi
      2 Yujie Liu
      3 Akira Yokosawa
      3 André Almeida
      3 Andy Shevchenko
      3 Ben Hutchings
      3 Borislav Petkov
      3 Conchúr Navid
      3 Daniel Santos
      3 Danilo Cesar Lemes de Paula
      3 Mike Rapoport
      4 Daniel Vetter
      4 Matthew Wilcox
      5 Martin Waitz
      5 Paolo Bonzini
      6 Aditya Srivastava
      6 Vegard Nossum
      7 Kees Cook
     11 Johannes Berg
     11 Tomasz Warniełło
     20 Jonathan Corbet
     32 Jani Nikula
     57 Mauro Carvalho Chehab
     65 Randy Dunlap

So, picking the latest e-mails from the above authors, maybe we can add
some credit lines like these:

# Converted from the kernel-doc script originally written in Perl
# under GPLv2, copyrighted since 1998 by the following authors:
#
#    Aditya Srivastava <yashsri421@gmail.com>
#    Akira Yokosawa <akiyks@gmail.com>
#    Alexander A. Klimov <grandmaster@al2klimov.de>
#    Alexander Lobakin <aleksander.lobakin@intel.com>
#    André Almeida <andrealmeid@igalia.com>
#    Andy Shevchenko <andriy.shevchenko@linux.intel.com>
#    Anna-Maria Behnsen <anna-maria@linutronix.de>
#    Armin Kuster <akuster@mvista.com>
#    Bart Van Assche <bart.vanassche@sandisk.com>
#    Ben Hutchings <ben@decadent.org.uk>
#    Borislav Petkov <bbpetkov@yahoo.de>
#    Chen-Yu Tsai <wenst@chromium.org>
#    Coco Li <lixiaoyan@google.com>
#    Conchúr Navid <conchur@web.de>
#    Daniel Santos <daniel.santos@pobox.com>
#    Danilo Cesar Lemes de Paula <danilo.cesar@collabora.co.uk>
#    Dan Luedtke <mail@danrl.de>
#    Donald Hunter <donald.hunter@gmail.com>
#    Gabriel Krisman Bertazi <krisman@collabora.co.uk>
#    Greg Kroah-Hartman <gregkh@linuxfoundation.org>
#    Harvey Harrison <harvey.harrison@gmail.com>
#    Horia Geanta <horia.geanta@freescale.com>
#    Ilya Dryomov <idryomov@gmail.com>
#    Jakub Kicinski <kuba@kernel.org>
#    Jani Nikula <jani.nikula@intel.com>
#    Jason Baron <jbaron@redhat.com>
#    Jason Gunthorpe <jgg@nvidia.com>
#    Jérémy Bobbio <lunar@debian.org>
#    Johannes Berg <johannes.berg@intel.com>
#    Johannes Weiner <hannes@cmpxchg.org>
#    Jonathan Cameron <Jonathan.Cameron@huawei.com>
#    Jonathan Corbet <corbet@lwn.net>
#    Jonathan Neuschäfer <j.neuschaefer@gmx.net>
#    Kamil Rytarowski <n54@gmx.com>
#    Kees Cook <kees@kernel.org>
#    Laurent Pinchart <laurent.pinchart@ideasonboard.com>
#    Levin, Alexander (Sasha Levin) <alexander.levin@verizon.com>
#    Linus Torvalds <torvalds@linux-foundation.org>
#    Lucas De Marchi <lucas.demarchi@profusion.mobi>
#    Mark Rutland <mark.rutland@arm.com>
#    Markus Heiser <markus.heiser@darmarit.de>
#    Martin Waitz <tali@admingilde.org>
#    Masahiro Yamada <masahiroy@kernel.org>
#    Matthew Wilcox <willy@infradead.org>
#    Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
#    Michal Wajdeczko <michal.wajdeczko@intel.com>
#    Michael Zucchi
#    Mike Rapoport <rppt@linux.ibm.com>
#    Niklas Söderlund <niklas.soderlund@corigine.com>
#    Nishanth Menon <nm@ti.com>
#    Paolo Bonzini <pbonzini@redhat.com>
#    Pavan Kumar Linga <pavan.kumar.linga@intel.com>
#    Pavel Pisa <pisa@cmp.felk.cvut.cz>
#    Peter Maydell <peter.maydell@linaro.org>
#    Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
#    Randy Dunlap <rdunlap@infradead.org>
#    Richard Kennedy <richard@rsk.demon.co.uk>
#    Rich Walker <rw@shadow.org.uk>
#    Rolf Eike Beer <eike-kernel@sf-tec.de>
#    Sakari Ailus <sakari.ailus@linux.intel.com>
#    Silvio Fricke <silvio.fricke@gmail.com>
#    Simon Huggins
#    Tim Waugh <twaugh@redhat.com> 
#    Tomasz Warniełło <tomasz.warniello@gmail.com>
#    Utkarsh Tripathi <utripathi2002@gmail.com>
#    valdis.kletnieks@vt.edu <valdis.kletnieks@vt.edu>
#    Vegard Nossum <vegard.nossum@oracle.com>
#    Will Deacon <will.deacon@arm.com>
#    Yacine Belkadi <yacine.belkadi.1@gmail.com>
#    Yujie Liu <yujie.liu@intel.com>

Note: unfortunately, two of the original authors didn't send any patches
with their names since when we migrated to git. So, I'm placing them
without e-mails.

On a side note, I would keep the above credits line only at the main
kernel-doc.py, as it would be really hard to distribute it along
the several kernel-doc classes.


> 
> > +# TODO: implement warning filtering
> > +
> > +"""
> > +kernel_doc
> > +==========
> > +
> > +Print formatted kernel documentation to stdout
> > +
> > +Read C language source or header FILEs, extract embedded
> > +documentation comments, and print formatted documentation
> > +to standard output.
> > +
> > +The documentation comments are identified by the "/**"
> > +opening comment mark.
> > +
> > +See Documentation/doc-guide/kernel-doc.rst for the
> > +documentation comment syntax.
> > +"""
> > +
> > +import argparse
> > +import logging
> > +import os
> > +import re
> > +import sys
> > +
> > +from datetime import datetime
> > +from pprint import pformat
> > +
> > +from dateutil import tz
> > +
> > +# Local cache for regular expressions
> > +re_cache = {}
> > +
> > +
> > +class Re:  
> 
> So I have to say this bugs me a bit ... the class is fine, but the
> one-letter case-only difference from the standard "re" class is just
> going to make the code harder for others to approach.  "kern_re" or
> something like that?  Or even "kre" if you really want it to be as short
> as possible.

A short name close to "re" made easier to convert the script ;-)

I'll rename the class to KernRe (*)

(*) I opted to follow pylint convention for class names, which
    is using camel case. As we don't have classes in C, this
    doesn't strictly conflicts with our Kernel conventions ;-)

To make easier, I'll do such change as a separate patch at the end
of the series.

> 
> > +    """
> > +    Helper class to simplify regex declaration and usage,
> > +
> > +    It calls re.compile for a given pattern. It also allows adding
> > +    regular expressions and define sub at class init time.
> > +
> > +    Regular expressions can be cached via an argument, helping to speedup
> > +    searches.
> > +    """  
> 
> [...]
> 
> > +
> > +class KernelDoc:
> > +    # Parser states
> > +    STATE_NORMAL        = 0        # normal code
> > +    STATE_NAME          = 1        # looking for function name
> > +    STATE_BODY_MAYBE    = 2        # body - or maybe more description
> > +    STATE_BODY          = 3        # the body of the comment
> > +    STATE_BODY_WITH_BLANK_LINE = 4 # the body which has a blank line
> > +    STATE_PROTO         = 5        # scanning prototype
> > +    STATE_DOCBLOCK      = 6        # documentation block
> > +    STATE_INLINE        = 7        # gathering doc outside main block
> > +
> > +    st_name = [
> > +        "NORMAL",
> > +        "NAME",
> > +        "BODY_MAYBE",
> > +        "BODY",
> > +        "BODY_WITH_BLANK_LINE",
> > +        "PROTO",
> > +        "DOCBLOCK",
> > +        "INLINE",
> > +    ]  
> 
> So these ... kind of look like enums?

Yes. I considered using Python enum there:
	https://docs.python.org/3/library/enum.html

but it would simply be:

	from enum import Enum

	class state(enum):
	    NORMAL        = 0        # normal code
	    NAME          = 1        # looking for function name
	    BODY_MAYBE    = 2        # body - or maybe more description
	    BODY          = 3        # the body of the comment
	    BODY_WITH_BLANK_LINE = 4 # the body which has a blank line
	    PROTO         = 5        # scanning prototype
	    DOCBLOCK      = 6        # documentation block
	    INLINE        = 7        # gathering doc outside main block

and we would replace:

	self.STATE_NORMAL
	...

to:
	state.NORMAL

(and a similar change for inline states as well)

Except for an ancillary number-to-string conversion with this syntax:

	Color = Enum('Color', [('RED', 1), ('GREEN', 2), ('BLUE', 3)])

I didn't see much advantage of using it. See, we only use the string
on a single line, when --debug is used to show the per-line state machine.

Yet, perhaps we can split the states on a separate class anyway.

> That's kind of it for nits ... I do have one wish that will kind of hard
> to grant overall ... for the long-term maintenance of this code, it
> would be really nice if every non-trivial regex were described by a
> comment explaining what it is trying to do.  It's not reasonable to
> expect that as a condition for accepting this rewrite, but it sure would
> be a nice goal to be working toward.

Agreed. For the future, the best would be to request a description for
every new regex added.

For the future, my plan is to split the C source parser (e.g. the code that
calls output_declaration() and/or modifies self.entry at the KernelDoc
class inside kdoc_parser to a separate file and class. We can then work
to implement some regexes to a more lexical way. For instance, all those
regexes:

            (Re(r'\bstruct_group\s*\(([^,]*,)', re.S), r'STRUCT_GROUP('),
            (Re(r'\bstruct_group_attr\s*\(([^,]*,){2}', re.S), r'STRUCT_GROUP('),
            (Re(r'\bstruct_group_tagged\s*\(([^,]*),([^,]*),', re.S), r'struct \1 \2; STRUCT_GROUP('),
            (Re(r'\b__struct_group\s*\(([^,]*,){3}', re.S), r'STRUCT_GROUP('),

            (Re(r'__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, __ETHTOOL_LINK_MODE_MASK_NBITS)'),
            (Re(r'DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)', re.S), r'DECLARE_BITMAP(\1, PHY_INTERFACE_MODE_MAX)'),
            (Re(r'DECLARE_BITMAP\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[BITS_TO_LONGS(\2)]'),
            (Re(r'DECLARE_HASHTABLE\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'unsigned long \1[1 << ((\2) - 1)]'),
            (Re(r'DECLARE_KFIFO\s*\(' + args_pattern + r',\s*' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'),
            (Re(r'DECLARE_KFIFO_PTR\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\2 *\1'),
            (Re(r'(?:__)?DECLARE_FLEX_ARRAY\s*\(' + args_pattern + r',\s*' + args_pattern + r'\)', re.S), r'\1 \2[]'),
            (Re(r'DEFINE_DMA_UNMAP_ADDR\s*\(' + args_pattern + r'\)', re.S), r'dma_addr_t \1'),
            (Re(r'DEFINE_DMA_UNMAP_LEN\s*\(' + args_pattern + r'\)', re.S), r'__u32 \1'),

could be converted on a more lexical representation where the macro
name with their arguments could be represented on a clearer expression.

Something like:

	ReplaceMatch("DECLARE_HASHTABLE($1, $2)", "unsigned long $1[1 << (($2) - 1)]")

We have already the NestedMatch class that do something similar to
that(*) could be improved to do things like that - or we can come up with
something new.

(*) NestedMatch currently miss one feature: it doesn't split the contents
    inside parenthesis on multiple match groups. I guess it won't be hard to
    add such features to it.

Thanks,
Mauro

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 00/39] Implement kernel-doc in Python
  2025-02-24 23:49 ` [PATCH v2 00/39] Implement kernel-doc in Python Jonathan Corbet
@ 2025-02-25  7:54   ` Mauro Carvalho Chehab
  2025-02-25 14:33     ` Jonathan Corbet
  0 siblings, 1 reply; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-25  7:54 UTC (permalink / raw)
  To: Jonathan Corbet
  Cc: Linux Doc Mailing List, linux-kernel, Arnd Bergmann, Bingbu Cao,
	Greg Kroah-Hartman, Sakari Ailus, Takashi Sakamoto, Tianshu Qiu,
	linux-arch, linux-hardening, linux-media, linux-staging,
	linux1394-devel

Em Mon, 24 Feb 2025 16:49:10 -0700
Jonathan Corbet <corbet@lwn.net> escreveu:

> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
> 
> > Hi Jon,
> >
> > This changeset contains the kernel-doc.py script to replace the verable
> > kernel-doc originally written in Perl. It replaces the first version and the
> > second series I sent on the top of it.  
> 
> I've sent minor comments on a couple of the patches.  The new version
> works for me, I can't find any real problems with it.

Good!

Btw, I should have sent this earlier, but what I did here to test here were
use the new V=1 output from Sphinx kerneldoc extension to get a list of
all kernel-doc commands used to build the docs. Then, I wrote an
ancillary script to do the diff, replacing kernel-doc calls to use 
the diff script. I'm enclosing the scripts I wrote with such approach,
as a patch.

Btw, I used the diff script also for the -man output, except that,
on such case, I just got all file names send them without any
arguments to -man parser.

> Here's the question: what were your thoughts on when to do this?  I can
> certainly take the initial fixup patches and get them out of your queue,
> but at some point there will be a need to dive into the deep end.  I'm
> just a bit leery of doing that as we head toward -rc5...  what do you
> think of "just after the merge window"?

There's no need to rush things there, provided that people refrain
touching the Perl version of kernel-doc. So yeah, postponing it to
the next merge window makes sense to me. Perhaps we should announce
somewhere that we're in the process of doing such replacement, asking
people to wait for 6.15-rc before sending any changes to kernel-doc.

> I'm definitely looking forward to no longer having to bash my head
> against the Perl version...

Yeah, the Perl version have too many global symbols, which makes it
hard for people to understand it. During the conversion, I also had
to bash my head a couple of times to get things right and - as you
can see from the fixup patches on this series - sometimes I just got
things wrong and had to come up with a completely different approach 
;-)

Regards,
Mauro

---

[PATCH] Test scripts to compare kernel-doc.pl with kernel-doc.py output

Those scripts are under GPLv2.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>

diff --git a/check_all.sh b/check_all.sh
new file mode 100755
index 000000000000..2cc92b3c16cf
--- /dev/null
+++ b/check_all.sh
@@ -0,0 +1,1847 @@
+./diff-doc -rst -enable-lineno ./arch/s390/include/asm/debug.h
+./diff-doc -rst -enable-lineno ./arch/s390/kernel/debug.c
+./diff-doc -rst -enable-lineno ./block/blk-mq.c
+./diff-doc -rst -enable-lineno ./Documentation/gpu/rfc/i915_vm_bind.h
+./diff-doc -rst -enable-lineno ./drivers/ata/libata-eh.c
+./diff-doc -rst -enable-lineno ./drivers/base/devcoredump.c
+./diff-doc -rst -enable-lineno ./drivers/edac/edac_device.h
+./diff-doc -rst -enable-lineno ./drivers/edac/edac_mc.h
+./diff-doc -rst -enable-lineno ./drivers/edac/edac_pci.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/gt/uc/abi/guc_communication_ctb_abi.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/gt/uc/abi/guc_communication_mmio_abi.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/gt/uc/abi/guc_messages_abi.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/gt/uc/intel_guc.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/i915/pxp/intel_pxp_types.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/xe/xe_assert.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/xlnx/zynqmp_disp.c
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/xlnx/zynqmp_disp.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/xlnx/zynqmp_dp.c
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/xlnx/zynqmp_dpsub.h
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/xlnx/zynqmp_kms.c
+./diff-doc -rst -enable-lineno ./drivers/gpu/drm/xlnx/zynqmp_kms.h
+./diff-doc -rst -enable-lineno ./drivers/i3c/device.c
+./diff-doc -rst -enable-lineno ./drivers/i3c/master.c
+./diff-doc -rst -enable-lineno ./drivers/iio/buffer/industrialio-triggered-buffer.c
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/a8293.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/af9013.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/ascot2e.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/cxd2820r.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/drxk.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/dvb-pll.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/helene.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/horus3a.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/ix2505v.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/m88ds3103.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/mb86a20s.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/mn88472.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/rtl2830.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/rtl2832.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/rtl2832_sdr.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/stb6000.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/tda10071.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/tda826x.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/zd1301_demod.h
+./diff-doc -rst -enable-lineno ./drivers/media/dvb-frontends/zl10036.h
+./diff-doc -rst -enable-lineno ./drivers/media/i2c/ccs-pll.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_bridge.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_channel.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_common.c
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_demod.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_encoder.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_mux.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_pes.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_psi.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_s302m.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_ts.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_tuner.c
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vidtv/vidtv_tuner.h
+./diff-doc -rst -enable-lineno ./drivers/media/test-drivers/vimc/vimc-streamer.c
+./diff-doc -rst -enable-lineno ./drivers/net/phy/phylink.c
+./diff-doc -rst -enable-lineno ./drivers/peci/core.c
+./diff-doc -rst -enable-lineno ./drivers/peci/cpu.c
+./diff-doc -rst -enable-lineno ./drivers/peci/internal.h
+./diff-doc -rst -enable-lineno ./drivers/peci/request.c
+./diff-doc -rst -enable-lineno ./drivers/platform/surface/aggregator/trace.h
+./diff-doc -rst -enable-lineno ./drivers/platform/x86/amd/wbrf.c
+./diff-doc -rst -enable-lineno ./drivers/platform/x86/intel/ifs/ifs.h
+./diff-doc -rst -enable-lineno ./drivers/scsi/scsi_proc.c
+./diff-doc -rst -enable-lineno ./drivers/staging/media/ipu3/include/uapi/intel-ipu3.h
+./diff-doc -rst -enable-lineno ./drivers/tty/tty_ioctl.c
+./diff-doc -rst -enable-lineno -export ./arch/sh/boards/mach-x3proto/ilsel.c
+./diff-doc -rst -enable-lineno -export ./arch/sh/kernel/cpu/sh4/sq.c
+./diff-doc -rst -enable-lineno -export ./arch/x86/kernel/cpu/mtrr/mtrr.c
+./diff-doc -rst -enable-lineno -export ./arch/x86/lib/usercopy_32.c
+./diff-doc -rst -enable-lineno -export ./block/bdev.c
+./diff-doc -rst -enable-lineno -export ./block/bio.c
+./diff-doc -rst -enable-lineno -export ./block/blk-core.c
+./diff-doc -rst -enable-lineno -export ./block/blk-flush.c
+./diff-doc -rst -enable-lineno -export ./block/blk-integrity.c
+./diff-doc -rst -enable-lineno -export ./block/blk-lib.c
+./diff-doc -rst -enable-lineno -export ./block/blk-map.c
+./diff-doc -rst -enable-lineno -export ./block/blk-settings.c
+./diff-doc -rst -enable-lineno -export ./block/genhd.c
+./diff-doc -rst -enable-lineno -export ./drivers/ata/libata-core.c
+./diff-doc -rst -enable-lineno -export ./drivers/ata/libata-scsi.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/bus.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/class.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/component.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/core.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/dd.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/devres.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/driver.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/platform.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/syscore.c
+./diff-doc -rst -enable-lineno -export ./drivers/base/transport_class.c
+./diff-doc -rst -enable-lineno -export ./drivers/char/misc.c
+./diff-doc -rst -enable-lineno -export ./drivers/clk/clk_kunit_helpers.c
+./diff-doc -rst -enable-lineno -export ./drivers/counter/counter-chrdev.c
+./diff-doc -rst -enable-lineno -export ./drivers/counter/counter-core.c
+./diff-doc -rst -enable-lineno -export ./drivers/devfreq/devfreq.c
+./diff-doc -rst -enable-lineno -export ./drivers/devfreq/devfreq-event.c
+./diff-doc -rst -enable-lineno -export ./drivers/dma-buf/dma-buf.c
+./diff-doc -rst -enable-lineno -export ./drivers/dma-buf/dma-fence-array.c
+./diff-doc -rst -enable-lineno -export ./drivers/dma-buf/dma-fence.c
+./diff-doc -rst -enable-lineno -export ./drivers/dma-buf/dma-fence-chain.c
+./diff-doc -rst -enable-lineno -export ./drivers/dma-buf/dma-resv.c
+./diff-doc -rst -enable-lineno -export ./drivers/dma-buf/sync_file.c
+./diff-doc -rst -enable-lineno -export ./drivers/firewire/core-device.c
+./diff-doc -rst -enable-lineno -export ./drivers/firewire/core-iso.c
+./diff-doc -rst -enable-lineno -export ./drivers/firewire/core-transaction.c
+./diff-doc -rst -enable-lineno -export ./drivers/firmware/dmi_scan.c
+./diff-doc -rst -enable-lineno -export ./drivers/firmware/stratix10-svc.c
+./diff-doc -rst -enable-lineno -export ./drivers/firmware/sysfb.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpio/gpiolib-acpi.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpio/gpiolib.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpio/gpiolib-devres.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpio/gpiolib-of.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpio/gpiolib-sysfs.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/bridge/panel.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_bridge_connector.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_dp_cec.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_dp_dual_mode_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_dp_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_dp_mst_topology.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_dsc_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_hdcp_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/display/drm_scdc_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_atomic.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_atomic_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_atomic_state_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_atomic_uapi.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_auth.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_blend.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_bridge.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_buddy.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_cache.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_client.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_client_event.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_client_modeset.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_color_mgmt.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_connector.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_crtc.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_crtc_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_damage_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_debugfs.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_debugfs_crc.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_drv.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_edid.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_eld.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_encoder.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_exec.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_fb_dma_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_fb_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_file.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_flip_work.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_format_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_fourcc.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_framebuffer.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gem_atomic_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gem.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gem_dma_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gem_framebuffer_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gem_shmem_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gem_ttm_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gem_vram_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_gpuvm.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_ioc32.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_ioctl.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_managed.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_mipi_dbi.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_mipi_dsi.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_mm.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_mode_config.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_mode_object.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_modes.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_modeset_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_modeset_lock.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_of.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_panel_backlight_quirks.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_panel.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_panel_orientation_quirks.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_panic.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_plane.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_plane_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_prime.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_print.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_privacy_screen.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_probe_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_property.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_rect.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_self_refresh_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_simple_kms_helper.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_syncobj.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_sysfs.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_vblank.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_vblank_work.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_vma_manager.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/drm_writeback.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/scheduler/sched_entity.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/scheduler/sched_main.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/ttm/ttm_device.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/ttm/ttm_pool.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/ttm/ttm_resource.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/drm/ttm/ttm_tt.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/host1x/bus.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/host1x/syncpt.c
+./diff-doc -rst -enable-lineno -export ./drivers/gpu/vga/vga_switcheroo.c
+./diff-doc -rst -enable-lineno -export ./drivers/hsi/hsi_core.c
+./diff-doc -rst -enable-lineno -export ./drivers/i2c/i2c-core-base.c
+./diff-doc -rst -enable-lineno -export ./drivers/i2c/i2c-core-smbus.c
+./diff-doc -rst -enable-lineno -export ./drivers/iio/buffer/industrialio-hw-consumer.c
+./diff-doc -rst -enable-lineno -export ./drivers/iio/industrialio-buffer.c
+./diff-doc -rst -enable-lineno -export ./drivers/iio/industrialio-core.c
+./diff-doc -rst -enable-lineno -export ./drivers/iio/industrialio-trigger.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/cm.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/cq.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/device.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/packer.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/rw.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/sa_query.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/ud_header.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/umem.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/umem_odp.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/core/verbs.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/sw/rdmavt/ah.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/sw/rdmavt/cq.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/sw/rdmavt/mcast.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/sw/rdmavt/mr.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/sw/rdmavt/qp.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/sw/rdmavt/rc.c
+./diff-doc -rst -enable-lineno -export ./drivers/infiniband/sw/rdmavt/vt.c
+./diff-doc -rst -enable-lineno -export ./drivers/input/ff-core.c
+./diff-doc -rst -enable-lineno -export ./drivers/input/ff-memless.c
+./diff-doc -rst -enable-lineno -export ./drivers/input/input.c
+./diff-doc -rst -enable-lineno -export ./drivers/input/input-mt.c
+./diff-doc -rst -enable-lineno -export ./drivers/input/serio/libps2.c
+./diff-doc -rst -enable-lineno -export ./drivers/input/sparse-keymap.c
+./diff-doc -rst -enable-lineno -export ./drivers/iommu/iommufd/device.c
+./diff-doc -rst -enable-lineno -export ./drivers/iommu/iommufd/main.c
+./diff-doc -rst -enable-lineno -export ./drivers/media/v4l2-core/v4l2-jpeg.c
+./diff-doc -rst -enable-lineno -export ./drivers/message/fusion/mptbase.c
+./diff-doc -rst -enable-lineno -export ./drivers/message/fusion/mptscsih.c
+./diff-doc -rst -enable-lineno -export ./drivers/mtd/nand/raw/nand_base.c
+./diff-doc -rst -enable-lineno -export ./drivers/net/phy/mdio_bus.c
+./diff-doc -rst -enable-lineno -export ./drivers/net/phy/phy.c
+./diff-doc -rst -enable-lineno -export ./drivers/net/phy/phy-c45.c
+./diff-doc -rst -enable-lineno -export ./drivers/net/phy/phy-core.c
+./diff-doc -rst -enable-lineno -export ./drivers/net/phy/phy_device.c
+./diff-doc -rst -enable-lineno -export ./drivers/net/phy/sfp-bus.c
+./diff-doc -rst -enable-lineno -export ./drivers/nvmem/core.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/address.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/base.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/device.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/dynamic.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/fdt.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/irq.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/of_kunit_helpers.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/overlay.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/platform.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/property.c
+./diff-doc -rst -enable-lineno -export ./drivers/of/resolver.c
+./diff-doc -rst -enable-lineno -export ./drivers/parport/ieee1284.c
+./diff-doc -rst -enable-lineno -export ./drivers/parport/share.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/access.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/bus.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/devres.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/hotplug/pci_hotplug_core.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/iomap.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/iov.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/irq.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/msi/api.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/msi/msi.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/p2pdma.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/pci.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/pci-driver.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/probe.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/remove.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/rom.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/search.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/slot.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/tph.c
+./diff-doc -rst -enable-lineno -export ./drivers/pci/vgaarb.c
+./diff-doc -rst -enable-lineno -export ./drivers/platform/surface/aggregator/bus.c
+./diff-doc -rst -enable-lineno -export ./drivers/platform/surface/aggregator/controller.c
+./diff-doc -rst -enable-lineno -export ./drivers/platform/surface/aggregator/core.c
+./diff-doc -rst -enable-lineno -export ./drivers/platform/surface/aggregator/ssh_packet_layer.c
+./diff-doc -rst -enable-lineno -export ./drivers/platform/surface/surface_acpi_notify.c
+./diff-doc -rst -enable-lineno -export ./drivers/platform/x86/wmi.c
+./diff-doc -rst -enable-lineno -export ./drivers/pnp/card.c
+./diff-doc -rst -enable-lineno -export ./drivers/pnp/manager.c
+./diff-doc -rst -enable-lineno -export ./drivers/pnp/support.c
+./diff-doc -rst -enable-lineno -export ./drivers/power/sequencing/core.c
+./diff-doc -rst -enable-lineno -export ./drivers/pwm/core.c
+./diff-doc -rst -enable-lineno -export ./drivers/rapidio/rio.c
+./diff-doc -rst -enable-lineno -export ./drivers/rapidio/rio-driver.c
+./diff-doc -rst -enable-lineno -export ./drivers/regulator/core.c
+./diff-doc -rst -enable-lineno -export ./drivers/s390/cio/airq.c
+./diff-doc -rst -enable-lineno -export ./drivers/s390/cio/ccwgroup.c
+./diff-doc -rst -enable-lineno -export ./drivers/s390/cio/cmf.c
+./diff-doc -rst -enable-lineno -export ./drivers/s390/cio/device.c
+./diff-doc -rst -enable-lineno -export ./drivers/s390/cio/device_ops.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/hosts.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/iscsi_boot_sysfs.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/libiscsi.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/libiscsi_tcp.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsicam.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_common.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_devinfo.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_error.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_ioctl.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_lib.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_lib_dma.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_scan.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_sysfs.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_transport_fc.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_transport_iscsi.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_transport_sas.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_transport_spi.c
+./diff-doc -rst -enable-lineno -export ./drivers/scsi/scsi_transport_srp.c
+./diff-doc -rst -enable-lineno -export ./drivers/sh/maple/maple.c
+./diff-doc -rst -enable-lineno -export ./drivers/slimbus/core.c
+./diff-doc -rst -enable-lineno -export ./drivers/slimbus/messaging.c
+./diff-doc -rst -enable-lineno -export ./drivers/slimbus/sched.c
+./diff-doc -rst -enable-lineno -export ./drivers/slimbus/stream.c
+./diff-doc -rst -enable-lineno -export ./drivers/spi/spi.c
+./diff-doc -rst -enable-lineno -export ./drivers/staging/vme_user/vme.c
+./diff-doc -rst -enable-lineno -export ./drivers/target/target_core_transport.c
+./diff-doc -rst -enable-lineno -export ./drivers/tty/n_tty.c
+./diff-doc -rst -enable-lineno -export ./drivers/tty/serial/8250/8250_core.c
+./diff-doc -rst -enable-lineno -export ./drivers/tty/vt/selection.c
+./diff-doc -rst -enable-lineno -export ./drivers/tty/vt/vt.c
+./diff-doc -rst -enable-lineno -export ./drivers/uio/uio.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/common/common.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/driver.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/file.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/hcd.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/hcd-pci.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/hub.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/message.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/urb.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/core/usb.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/gadget/composite.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/gadget/config.c
+./diff-doc -rst -enable-lineno -export ./drivers/usb/gadget/usbstring.c
+./diff-doc -rst -enable-lineno -export ./drivers/video/aperture.c
+./diff-doc -rst -enable-lineno -export ./drivers/video/backlight/backlight.c
+./diff-doc -rst -enable-lineno -export ./drivers/video/fbdev/core/fbcmap.c
+./diff-doc -rst -enable-lineno -export ./drivers/video/fbdev/core/fbmem.c
+./diff-doc -rst -enable-lineno -export ./drivers/video/fbdev/core/modedb.c
+./diff-doc -rst -enable-lineno -export ./drivers/video/fbdev/macmodes.c
+./diff-doc -rst -enable-lineno -export ./drivers/video/hdmi.c
+./diff-doc -rst -enable-lineno -export ./drivers/w1/w1_family.c
+./diff-doc -rst -enable-lineno -export ./drivers/w1/w1_int.c
+./diff-doc -rst -enable-lineno -export ./drivers/w1/w1_io.c
+./diff-doc -rst -enable-lineno -export -export-file ./drivers/misc/mei/bus.c ./drivers/misc/mei/bus.c
+./diff-doc -rst -enable-lineno -export ./fs/anon_inodes.c
+./diff-doc -rst -enable-lineno -export ./fs/attr.c
+./diff-doc -rst -enable-lineno -export ./fs/bad_inode.c
+./diff-doc -rst -enable-lineno -export ./fs/buffer.c
+./diff-doc -rst -enable-lineno -export ./fs/char_dev.c
+./diff-doc -rst -enable-lineno -export ./fs/dax.c
+./diff-doc -rst -enable-lineno -export ./fs/dcache.c
+./diff-doc -rst -enable-lineno -export ./fs/debugfs/file.c
+./diff-doc -rst -enable-lineno -export ./fs/debugfs/inode.c
+./diff-doc -rst -enable-lineno -export ./fs/d_path.c
+./diff-doc -rst -enable-lineno -export ./fs/eventfd.c
+./diff-doc -rst -enable-lineno -export ./fs/filesystems.c
+./diff-doc -rst -enable-lineno -export ./fs/fs-writeback.c
+./diff-doc -rst -enable-lineno -export ./fs/inode.c
+./diff-doc -rst -enable-lineno -export ./fs/jbd2/journal.c
+./diff-doc -rst -enable-lineno -export ./fs/libfs.c
+./diff-doc -rst -enable-lineno -export ./fs/locks.c
+./diff-doc -rst -enable-lineno -export ./fs/mpage.c
+./diff-doc -rst -enable-lineno -export ./fs/namei.c
+./diff-doc -rst -enable-lineno -export ./fs/namespace.c
+./diff-doc -rst -enable-lineno -export ./fs/posix_acl.c
+./diff-doc -rst -enable-lineno -export ./fs/pstore/blk.c
+./diff-doc -rst -enable-lineno -export ./fs/seq_file.c
+./diff-doc -rst -enable-lineno -export ./fs/stat.c
+./diff-doc -rst -enable-lineno -export ./fs/super.c
+./diff-doc -rst -enable-lineno -export ./fs/sync.c
+./diff-doc -rst -enable-lineno -export ./fs/sysfs/file.c
+./diff-doc -rst -enable-lineno -export ./fs/sysfs/symlink.c
+./diff-doc -rst -enable-lineno -export ./fs/xattr.c
+./diff-doc -rst -enable-lineno -export ./kernel/audit.c
+./diff-doc -rst -enable-lineno -export ./kernel/cgroup/dmem.c
+./diff-doc -rst -enable-lineno -export ./kernel/dma.c
+./diff-doc -rst -enable-lineno -export ./kernel/dma/mapping.c
+./diff-doc -rst -enable-lineno -export ./kernel/irq/chip.c
+./diff-doc -rst -enable-lineno -export ./kernel/irq/generic-chip.c
+./diff-doc -rst -enable-lineno -export ./kernel/kthread.c
+./diff-doc -rst -enable-lineno -export ./kernel/livepatch/core.c
+./diff-doc -rst -enable-lineno -export ./kernel/livepatch/shadow.c
+./diff-doc -rst -enable-lineno -export ./kernel/livepatch/state.c
+./diff-doc -rst -enable-lineno -export ./kernel/locking/mutex.c
+./diff-doc -rst -enable-lineno -export ./kernel/module/kmod.c
+./diff-doc -rst -enable-lineno -export ./kernel/panic.c
+./diff-doc -rst -enable-lineno -export ./kernel/power/energy_model.c
+./diff-doc -rst -enable-lineno -export ./kernel/relay.c
+./diff-doc -rst -enable-lineno -export ./kernel/resource.c
+./diff-doc -rst -enable-lineno -export ./kernel/sched/core.c
+./diff-doc -rst -enable-lineno -export ./kernel/sched/wait.c
+./diff-doc -rst -enable-lineno -export ./kernel/sysctl.c
+./diff-doc -rst -enable-lineno -export ./kernel/time/hrtimer.c
+./diff-doc -rst -enable-lineno -export ./kernel/time/time.c
+./diff-doc -rst -enable-lineno -export ./kernel/time/timer.c
+./diff-doc -rst -enable-lineno -export ./lib/bitmap.c
+./diff-doc -rst -enable-lineno -export ./lib/cmdline.c
+./diff-doc -rst -enable-lineno -export ./lib/crc16.c
+./diff-doc -rst -enable-lineno -export ./lib/crc4.c
+./diff-doc -rst -enable-lineno -export ./lib/crc7.c
+./diff-doc -rst -enable-lineno -export ./lib/crc8.c
+./diff-doc -rst -enable-lineno -export ./lib/crc-ccitt.c
+./diff-doc -rst -enable-lineno -export ./lib/crc-itu-t.c
+./diff-doc -rst -enable-lineno -export ./lib/kobject.c
+./diff-doc -rst -enable-lineno -export ./lib/kstrtox.c
+./diff-doc -rst -enable-lineno -export ./lib/kunit/platform.c
+./diff-doc -rst -enable-lineno -export ./lib/list_sort.c
+./diff-doc -rst -enable-lineno -export ./lib/math/gcd.c
+./diff-doc -rst -enable-lineno -export ./lib/math/int_pow.c
+./diff-doc -rst -enable-lineno -export ./lib/math/int_sqrt.c
+./diff-doc -rst -enable-lineno -export ./lib/parser.c
+./diff-doc -rst -enable-lineno -export ./lib/reed_solomon/reed_solomon.c
+./diff-doc -rst -enable-lineno -export ./lib/refcount.c
+./diff-doc -rst -enable-lineno -export ./lib/sort.c
+./diff-doc -rst -enable-lineno -export ./lib/string.c
+./diff-doc -rst -enable-lineno -export ./lib/string_helpers.c
+./diff-doc -rst -enable-lineno -export ./lib/textsearch.c
+./diff-doc -rst -enable-lineno -export ./lib/uuid.c
+./diff-doc -rst -enable-lineno -export ./lib/vsprintf.c
+./diff-doc -rst -enable-lineno -export ./mm/dmapool.c
+./diff-doc -rst -enable-lineno -export ./mm/filemap.c
+./diff-doc -rst -enable-lineno -export ./mm/memory.c
+./diff-doc -rst -enable-lineno -export ./mm/mempool.c
+./diff-doc -rst -enable-lineno -export ./mm/page-writeback.c
+./diff-doc -rst -enable-lineno -export ./mm/readahead.c
+./diff-doc -rst -enable-lineno -export ./mm/slab_common.c
+./diff-doc -rst -enable-lineno -export ./mm/slub.c
+./diff-doc -rst -enable-lineno -export ./mm/truncate.c
+./diff-doc -rst -enable-lineno -export ./mm/vmalloc.c
+./diff-doc -rst -enable-lineno -export ./net/core/datagram.c
+./diff-doc -rst -enable-lineno -export ./net/core/dev.c
+./diff-doc -rst -enable-lineno -export ./net/core/filter.c
+./diff-doc -rst -enable-lineno -export ./net/core/gen_estimator.c
+./diff-doc -rst -enable-lineno -export ./net/core/gen_stats.c
+./diff-doc -rst -enable-lineno -export ./net/core/skbuff.c
+./diff-doc -rst -enable-lineno -export ./net/core/sock.c
+./diff-doc -rst -enable-lineno -export ./net/core/stream.c
+./diff-doc -rst -enable-lineno -export ./net/ethernet/eth.c
+./diff-doc -rst -enable-lineno -export ./net/sched/sch_generic.c
+./diff-doc -rst -enable-lineno -export ./net/socket.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/clnt.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/rpcb_clnt.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/rpc_pipe.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/sched.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/socklib.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/stats.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/svc_xprt.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/xdr.c
+./diff-doc -rst -enable-lineno -export ./net/sunrpc/xprt.c
+./diff-doc -rst -enable-lineno -export -nosymbol printk ./kernel/printk/printk.c
+./diff-doc -rst -enable-lineno -export ./security/inode.c
+./diff-doc -rst -enable-lineno -export ./security/security.c
+./diff-doc -rst -enable-lineno ./fs/jbd2/transaction.c
+./diff-doc -rst -enable-lineno ./fs/netfs/buffered_read.c
+./diff-doc -rst -enable-lineno ./fs/pipe.c
+./diff-doc -rst -enable-lineno ./fs/splice.c
+./diff-doc -rst -enable-lineno -function acoustic_limit_rpm_threshold ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function acoustic_target_rpm_threshold ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function 'Actions and configuration' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function aead_request -function aead_alg ./include/crypto/aead.h
+./diff-doc -rst -enable-lineno -function ahash_request_set_tfm -function ahash_request_alloc -function ahash_request_free -function ahash_request_set_callback -function ahash_request_set_crypt ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function akcipher_alg -function akcipher_request ./include/crypto/akcipher.h
+./diff-doc -rst -enable-lineno -function akcipher_request_alloc -function akcipher_request_free -function akcipher_request_set_callback -function akcipher_request_set_crypt ./include/crypto/akcipher.h
+./diff-doc -rst -enable-lineno -function amdgpu_dm_atomic_check -function amdgpu_dm_atomic_commit_tail ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+./diff-doc -rst -enable-lineno -function amdgpu_object ./drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+./diff-doc -rst -enable-lineno -function 'AMDGPU RAS debugfs control interface' ./drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+./diff-doc -rst -enable-lineno -function 'AMDGPU RAS debugfs EEPROM table reset interface' ./drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+./diff-doc -rst -enable-lineno -function 'AMDGPU RAS Reboot Behavior for Unrecoverable Errors' ./drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+./diff-doc -rst -enable-lineno -function 'AMDGPU RAS sysfs Error Count Interface' ./drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+./diff-doc -rst -enable-lineno -function 'AMDGPU RAS sysfs gpu_vram_bad_pages Interface' ./drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+./diff-doc -rst -enable-lineno -function amd_ip_block_type -function amd_ip_funcs -function DC_DEBUG_MASK ./drivers/gpu/drm/amd/include/amd_shared.h
+./diff-doc -rst -enable-lineno -function 'Analog TV Connector Properties' ./drivers/gpu/drm/drm_connector.c
+./diff-doc -rst -enable-lineno -function 'AP support for powersaving clients' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'ARM PrimeCell PL110 and PL111 CLCD Driver' ./drivers/gpu/drm/pl111/pl111_drv.c
+./diff-doc -rst -enable-lineno -function ASSERT_EQ -function ASSERT_NE -function ASSERT_LT -function ASSERT_LE -function ASSERT_GT -function ASSERT_GE -function ASSERT_NULL -function ASSERT_TRUE -function ASSERT_NULL -function ASSERT_TRUE -function ASSERT_FALSE -function ASSERT_STREQ -function ASSERT_STRNE -function EXPECT_EQ -function EXPECT_NE -function EXPECT_LT -function EXPECT_LE -function EXPECT_GT -function EXPECT_GE -function EXPECT_NULL -function EXPECT_TRUE -function EXPECT_FALSE -function EXPECT_STREQ -function EXPECT_STRNE ./tools/testing/selftests/kselftest_harness.h
+./diff-doc -rst -enable-lineno -function ASSERT_EXCLUSIVE_WRITER -function ASSERT_EXCLUSIVE_WRITER_SCOPED -function ASSERT_EXCLUSIVE_ACCESS -function ASSERT_EXCLUSIVE_ACCESS_SCOPED -function ASSERT_EXCLUSIVE_BITS ./include/linux/kcsan-checks.h
+./diff-doc -rst -enable-lineno -function 'Asynchronous AEAD Request Handle' ./include/crypto/aead.h
+./diff-doc -rst -enable-lineno -function 'asynchronous flip implementation' ./drivers/gpu/drm/i915/display/intel_display.c
+./diff-doc -rst -enable-lineno -function 'Asynchronous Hash Request Handle' ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function 'Asynchronous Message Digest API' ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function atomic ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+./diff-doc -rst -enable-lineno -function 'atomic plane helpers' ./drivers/gpu/drm/i915/display/intel_atomic_plane.c
+./diff-doc -rst -enable-lineno -function 'atomic state reset and initialization' ./drivers/gpu/drm/drm_atomic_state_helper.c
+./diff-doc -rst -enable-lineno -function 'Authenticated Encryption With Associated Data (AEAD) Cipher API' ./include/crypto/aead.h
+./diff-doc -rst -enable-lineno -function auxiliary_device ./include/linux/auxiliary_bus.h
+./diff-doc -rst -enable-lineno -function auxiliary_device_init -function __auxiliary_device_add ./drivers/base/auxiliary.c
+./diff-doc -rst -enable-lineno -function auxiliary_driver -function module_auxiliary_driver ./include/linux/auxiliary_bus.h
+./diff-doc -rst -enable-lineno -function __auxiliary_driver_register -function auxiliary_driver_unregister ./drivers/base/auxiliary.c
+./diff-doc -rst -enable-lineno -function 'aux kms helpers' ./drivers/gpu/drm/drm_modeset_helper.c
+./diff-doc -rst -enable-lineno -function 'Backlight control' ./drivers/platform/x86/apple-gmux.c
+./diff-doc -rst -enable-lineno -function 'Basic sk_buff geometry' ./include/linux/skbuff.h
+./diff-doc -rst -enable-lineno -function 'batch buffer command parser' ./drivers/gpu/drm/i915/i915_cmd_parser.c
+./diff-doc -rst -enable-lineno -function 'Beacon filter support' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'bitmap bitops' ./include/linux/bitmap.h
+./diff-doc -rst -enable-lineno -function 'bitmap introduction' ./lib/bitmap.c
+./diff-doc -rst -enable-lineno -function 'bitmap overview' ./include/linux/bitmap.h
+./diff-doc -rst -enable-lineno -function 'Block Cipher Algorithm Definitions' ./include/linux/crypto.h
+./diff-doc -rst -enable-lineno -function board_info ./drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+./diff-doc -rst -enable-lineno -function bpf_cgroup_acquire -function bpf_cgroup_release ./kernel/bpf/helpers.c
+./diff-doc -rst -enable-lineno -function bpf_cgroup_ancestor ./kernel/bpf/helpers.c
+./diff-doc -rst -enable-lineno -function bpf_cgroup_from_id ./kernel/bpf/helpers.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_acquire ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_and -function bpf_cpumask_or -function bpf_cpumask_xor ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_any_distribute -function bpf_cpumask_any_and_distribute ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_copy ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_create ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_equal -function bpf_cpumask_intersects -function bpf_cpumask_subset -function bpf_cpumask_empty -function bpf_cpumask_full ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_first -function bpf_cpumask_first_zero -function bpf_cpumask_first_and -function bpf_cpumask_test_cpu -function bpf_cpumask_weight ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_release ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_setall -function bpf_cpumask_clear ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_set_cpu -function bpf_cpumask_clear_cpu ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_cpumask_test_and_set_cpu -function bpf_cpumask_test_and_clear_cpu ./kernel/bpf/cpumask.c
+./diff-doc -rst -enable-lineno -function bpf_task_acquire -function bpf_task_release ./kernel/bpf/helpers.c
+./diff-doc -rst -enable-lineno -function bpf_task_from_pid ./kernel/bpf/helpers.c
+./diff-doc -rst -enable-lineno -function bpf_xdp_metadata_rx_hash ./net/core/xdp.c
+./diff-doc -rst -enable-lineno -function bpf_xdp_metadata_rx_timestamp ./net/core/xdp.c
+./diff-doc -rst -enable-lineno -function bpf_xdp_metadata_rx_vlan_tag ./net/core/xdp.c
+./diff-doc -rst -enable-lineno -function 'Branch device and port refcounting' ./drivers/gpu/drm/display/drm_dp_mst_topology.c
+./diff-doc -rst -enable-lineno -function 'Bridge enum definition' ./include/uapi/linux/if_link.h
+./diff-doc -rst -enable-lineno -function 'bridge operations' ./drivers/gpu/drm/drm_bridge.c
+./diff-doc -rst -enable-lineno -function 'Bridge port enum definition' ./include/uapi/linux/if_link.h
+./diff-doc -rst -enable-lineno -function 'Broadcom V3D Graphics Driver' ./drivers/gpu/drm/v3d/v3d_drv.c
+./diff-doc -rst -enable-lineno -function 'Broadcom V3D MMU' ./drivers/gpu/drm/v3d/v3d_mmu.c
+./diff-doc -rst -enable-lineno -function 'Broadcom V3D scheduling' ./drivers/gpu/drm/v3d/v3d_sched.c
+./diff-doc -rst -enable-lineno -function 'Broadcom VC4 Graphics Driver' ./drivers/gpu/drm/vc4/vc4_drv.c
+./diff-doc -rst -enable-lineno -function 'Buffer Objects (BO)' ./drivers/gpu/drm/xe/xe_bo_doc.h
+./diff-doc -rst -enable-lineno -function 'buffer object tiling' ./drivers/gpu/drm/i915/gem/i915_gem_tiling.c
+./diff-doc -rst -enable-lineno -function 'Buffers allocated by the backend' ./drivers/gpu/drm/xen/xen_drm_front.h
+./diff-doc -rst -enable-lineno -function 'Buffers allocated by the frontend driver' ./drivers/gpu/drm/xen/xen_drm_front.h
+./diff-doc -rst -enable-lineno -function bus_type -function bus_notifier_event ./include/linux/device/bus.h
+./diff-doc -rst -enable-lineno -function 'Calling mac80211 from interrupts' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'CDCLK / RAWCLK' ./drivers/gpu/drm/i915/display/intel_cdclk.c
+./diff-doc -rst -enable-lineno -function cfg80211_ops -function vif_params -function key_params -function survey_info_flags -function survey_info -function cfg80211_beacon_data -function cfg80211_ap_settings -function station_parameters -function rate_info_flags -function rate_info -function station_info -function monitor_flags -function mpath_info_flags -function mpath_info -function bss_parameters -function ieee80211_txq_params -function cfg80211_crypto_settings -function cfg80211_auth_request -function cfg80211_assoc_request -function cfg80211_deauth_request -function cfg80211_disassoc_request -function cfg80211_ibss_params -function cfg80211_connect_params -function cfg80211_pmksa -function cfg80211_rx_mlme_mgmt -function cfg80211_auth_timeout -function cfg80211_rx_assoc_resp -function cfg80211_assoc_timeout -function cfg80211_tx_mlme_mgmt -function cfg80211_ibss_joined -function cfg80211_connect_resp_params -function cfg80211_connect_done -function cfg80211_connect_result -function cfg80211_connect_bss -function cfg80211_connect_timeout -function cfg80211_roamed -function cfg80211_disconnected -function cfg80211_ready_on_channel -function cfg80211_remain_on_channel_expired -function cfg80211_new_sta -function cfg80211_rx_mgmt -function cfg80211_mgmt_tx_status -function cfg80211_cqm_rssi_notify -function cfg80211_cqm_pktloss_notify -function cfg80211_michael_mic_failure ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function cfg80211_ssid -function cfg80211_scan_request -function cfg80211_scan_done -function cfg80211_bss -function cfg80211_inform_bss -function cfg80211_inform_bss_frame_data -function cfg80211_inform_bss_data -function cfg80211_unlink_bss -function cfg80211_find_ie -function ieee80211_bss_get_ie ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function cfg80211_testmode_alloc_reply_skb -function cfg80211_testmode_reply -function cfg80211_testmode_alloc_event_skb -function cfg80211_testmode_event ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function class ./include/linux/device/class.h
+./diff-doc -rst -enable-lineno -function color-management-caps ./drivers/gpu/drm/amd/display/dc/dc.h
+./diff-doc -rst -enable-lineno -function 'Command list validator for VC4.' ./drivers/gpu/drm/vc4/vc4_validate.c
+./diff-doc -rst -enable-lineno -function 'component helper usage recommendations' ./drivers/gpu/drm/drm_drv.c
+./diff-doc -rst -enable-lineno -function console -function cons_flags ./include/linux/console.h
+./diff-doc -rst -enable-lineno -function console_srcu_read_flags -function console_srcu_write_flags -function console_is_registered -function for_each_console_srcu -function for_each_console ./include/linux/console.h
+./diff-doc -rst -enable-lineno -function consw ./include/linux/console.h
+./diff-doc -rst -enable-lineno -function 'cpu access' ./drivers/dma-buf/dma-buf.c
+./diff-doc -rst -enable-lineno -function 'cpu map' ./kernel/bpf/cpumap.c
+./diff-doc -rst -enable-lineno -function 'CRC ABI' ./drivers/gpu/drm/drm_debugfs_crc.c
+./diff-doc -rst -enable-lineno -function crypto_aead_reqsize -function aead_request_set_tfm -function aead_request_alloc -function aead_request_free -function aead_request_set_callback -function aead_request_set_crypt -function aead_request_set_ad ./include/crypto/aead.h
+./diff-doc -rst -enable-lineno -function crypto_alg -function cipher_alg -function compress_alg ./include/linux/crypto.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_aead -function crypto_free_aead -function crypto_aead_ivsize -function crypto_aead_authsize -function crypto_aead_blocksize -function crypto_aead_setkey -function crypto_aead_setauthsize -function crypto_aead_encrypt -function crypto_aead_decrypt ./include/crypto/aead.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_ahash -function crypto_free_ahash -function crypto_ahash_init -function crypto_ahash_digestsize -function crypto_ahash_reqtfm -function crypto_ahash_reqsize -function crypto_ahash_statesize -function crypto_ahash_setkey -function crypto_ahash_finup -function crypto_ahash_final -function crypto_ahash_digest -function crypto_ahash_export -function crypto_ahash_import ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_akcipher -function crypto_free_akcipher -function crypto_akcipher_set_pub_key -function crypto_akcipher_set_priv_key -function crypto_akcipher_maxsize -function crypto_akcipher_encrypt -function crypto_akcipher_decrypt ./include/crypto/akcipher.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_cipher -function crypto_free_cipher -function crypto_has_cipher -function crypto_cipher_blocksize -function crypto_cipher_setkey -function crypto_cipher_encrypt_one -function crypto_cipher_decrypt_one ./include/crypto/internal/cipher.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_kpp -function crypto_free_kpp -function crypto_kpp_set_secret -function crypto_kpp_generate_public_key -function crypto_kpp_compute_shared_secret -function crypto_kpp_maxsize ./include/crypto/kpp.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_rng -function crypto_rng_alg -function crypto_free_rng -function crypto_rng_generate -function crypto_rng_get_bytes -function crypto_rng_reset -function crypto_rng_seedsize ./include/crypto/rng.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_shash -function crypto_free_shash -function crypto_shash_blocksize -function crypto_shash_digestsize -function crypto_shash_descsize -function crypto_shash_setkey -function crypto_shash_digest -function crypto_shash_export -function crypto_shash_import -function crypto_shash_init -function crypto_shash_update -function crypto_shash_final -function crypto_shash_finup ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_sig -function crypto_free_sig -function crypto_sig_set_pubkey -function crypto_sig_set_privkey -function crypto_sig_keysize -function crypto_sig_maxsize -function crypto_sig_digestsize -function crypto_sig_sign -function crypto_sig_verify ./include/crypto/sig.h
+./diff-doc -rst -enable-lineno -function crypto_alloc_skcipher -function crypto_free_skcipher -function crypto_has_skcipher -function crypto_skcipher_ivsize -function crypto_skcipher_blocksize -function crypto_skcipher_setkey -function crypto_skcipher_reqtfm -function crypto_skcipher_encrypt -function crypto_skcipher_decrypt ./include/crypto/skcipher.h
+./diff-doc -rst -enable-lineno -function crypto_skcipher_reqsize -function skcipher_request_set_tfm -function skcipher_request_alloc -function skcipher_request_free -function skcipher_request_set_callback -function skcipher_request_set_crypt ./include/crypto/skcipher.h
+./diff-doc -rst -enable-lineno -function 'CSS-based Firmware Layout' ./drivers/gpu/drm/xe/xe_uc_fw_abi.h
+./diff-doc -rst -enable-lineno -function 'cxl core' ./drivers/cxl/core/port.c
+./diff-doc -rst -enable-lineno -function 'cxl core hdm' ./drivers/cxl/core/hdm.c
+./diff-doc -rst -enable-lineno -function 'cxl core pci' ./drivers/cxl/core/pci.c
+./diff-doc -rst -enable-lineno -function 'cxl core region' ./drivers/cxl/core/region.c
+./diff-doc -rst -enable-lineno -function 'cxl mbox' ./drivers/cxl/core/mbox.c
+./diff-doc -rst -enable-lineno -function 'cxl mem' ./drivers/cxl/mem.c
+./diff-doc -rst -enable-lineno -function 'cxl objects' ./drivers/cxl/cxl.h
+./diff-doc -rst -enable-lineno -function 'cxl pci' ./drivers/cxl/pci.c
+./diff-doc -rst -enable-lineno -function 'cxl pmem' ./drivers/cxl/core/pmem.c
+./diff-doc -rst -enable-lineno -function 'cxl port' ./drivers/cxl/port.c
+./diff-doc -rst -enable-lineno -function 'cxl registers' ./drivers/cxl/core/regs.c
+./diff-doc -rst -enable-lineno -function 'damage tracking' ./drivers/gpu/drm/drm_plane.c
+./diff-doc -rst -enable-lineno -function 'Data path helpers' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function 'dataref and headerless skbs' ./include/linux/skbuff.h
+./diff-doc -rst -enable-lineno -function 'dcp blob format' ./security/keys/trusted-keys/trusted_dcp.c
+./diff-doc -rst -enable-lineno -function 'deadline hints' ./drivers/dma-buf/dma-fence.c
+./diff-doc -rst -enable-lineno -function debug_object_activate ./lib/debugobjects.c
+./diff-doc -rst -enable-lineno -function debug_object_assert_init ./lib/debugobjects.c
+./diff-doc -rst -enable-lineno -function debug_object_deactivate ./lib/debugobjects.c
+./diff-doc -rst -enable-lineno -function debug_object_destroy ./lib/debugobjects.c
+./diff-doc -rst -enable-lineno -function debug_object_free ./lib/debugobjects.c
+./diff-doc -rst -enable-lineno -function debug_object_init ./lib/debugobjects.c
+./diff-doc -rst -enable-lineno -function debug_object_init_on_stack ./lib/debugobjects.c
+./diff-doc -rst -enable-lineno -function 'declare bitmap' ./include/linux/bitmap.h
+./diff-doc -rst -enable-lineno -function descriptors ./include/uapi/linux/usb/functionfs.h
+./diff-doc -rst -enable-lineno -function DEVICE_LIFESPAN ./include/linux/auxiliary_bus.h
+./diff-doc -rst -enable-lineno -function device_link_state ./include/linux/device.h
+./diff-doc -rst -enable-lineno -function 'Device registration' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function __devm_fpga_mgr_register ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function __devm_fpga_mgr_register_full ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function devm_gen_pool_create ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function devm_hte_register_chip -function hte_push_ts_ns ./drivers/hte/hte.c
+./diff-doc -rst -enable-lineno -function dh -function crypto_dh_key_len -function crypto_dh_encode_key -function crypto_dh_decode_key ./include/crypto/dh.h
+./diff-doc -rst -enable-lineno -function 'DH Helper Functions' ./include/crypto/dh.h
+./diff-doc -rst -enable-lineno -function 'display driver integration' ./drivers/gpu/drm/drm_bridge.c
+./diff-doc -rst -enable-lineno -function 'Display PLLs' ./drivers/gpu/drm/i915/display/intel_dpll_mgr.c
+./diff-doc -rst -enable-lineno -function 'Display Refresh Rate Switching (DRRS)' ./drivers/gpu/drm/i915/display/intel_drrs.c
+./diff-doc -rst -enable-lineno -function 'dma buf device access' ./drivers/dma-buf/dma-buf.c
+./diff-doc -rst -enable-lineno -function 'DMA fences overview' ./drivers/dma-buf/dma-fence.c
+./diff-doc -rst -enable-lineno -function 'dma helpers' ./drivers/gpu/drm/drm_gem_dma_helper.c
+./diff-doc -rst -enable-lineno -function 'DMC Firmware Support' ./drivers/gpu/drm/i915/display/intel_dmc.c
+./diff-doc -rst -enable-lineno -function 'DMC wakelock support' ./drivers/gpu/drm/i915/display/intel_dmc_wl.c
+./diff-doc -rst -enable-lineno -function dm_hw_init -function dm_hw_fini ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+./diff-doc -rst -enable-lineno -function 'DM Lifecycle' ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+./diff-doc -rst -enable-lineno -function do_div ./include/asm-generic/div64.h
+./diff-doc -rst -enable-lineno -function 'dp cec helpers' ./drivers/gpu/drm/display/drm_dp_cec.c
+./diff-doc -rst -enable-lineno -function 'dp dual mode helpers' ./drivers/gpu/drm/display/drm_dp_dual_mode_helper.c
+./diff-doc -rst -enable-lineno -function 'dp helpers' ./drivers/gpu/drm/display/drm_dp_helper.c
+./diff-doc -rst -enable-lineno -function DPIO ./drivers/gpu/drm/i915/display/intel_dpio_phy.c
+./diff-doc -rst -enable-lineno -function 'dp mst helper' ./drivers/gpu/drm/display/drm_dp_mst_topology.c
+./diff-doc -rst -enable-lineno -function 'driver instance overview' ./drivers/gpu/drm/drm_drv.c
+./diff-doc -rst -enable-lineno -function 'Driver limitations' ./drivers/gpu/drm/xen/xen_drm_front.h
+./diff-doc -rst -enable-lineno -function 'Driver modes of operation in terms of display buffers used' ./drivers/gpu/drm/xen/xen_drm_front.h
+./diff-doc -rst -enable-lineno -function 'Driver power control' ./drivers/gpu/vga/vga_switcheroo.c
+./diff-doc -rst -enable-lineno -function 'driver specific ioctls' ./drivers/gpu/drm/drm_ioctl.c
+./diff-doc -rst -enable-lineno -function 'DRM Client usage stats' ./drivers/gpu/drm/xe/xe_drm_client.c
+./diff-doc -rst -enable-lineno -function drm_dp_mst_topology_try_get_mstb -function drm_dp_mst_topology_get_mstb -function drm_dp_mst_topology_put_mstb -function drm_dp_mst_topology_try_get_port -function drm_dp_mst_topology_get_port -function drm_dp_mst_topology_put_port -function drm_dp_mst_get_mstb_malloc -function drm_dp_mst_put_mstb_malloc ./drivers/gpu/drm/display/drm_dp_mst_topology.c
+./diff-doc -rst -enable-lineno -function __drm_i915_gem_create_ext ./Documentation/gpu/rfc/i915_small_bar.h
+./diff-doc -rst -enable-lineno -function __drm_i915_memory_region_info ./Documentation/gpu/rfc/i915_small_bar.h
+./diff-doc -rst -enable-lineno -function 'drm leasing' ./drivers/gpu/drm/drm_lease.c
+./diff-doc -rst -enable-lineno -function 'drm panel' ./drivers/gpu/drm/drm_panel.c
+./diff-doc -rst -enable-lineno -function drm_pvr_create_hwrt_geom_data_args -function drm_pvr_create_hwrt_rt_data_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ctx_priority -function drm_pvr_ctx_type -function drm_pvr_static_render_context_state -function drm_pvr_static_render_context_state_format -function drm_pvr_reset_framework -function drm_pvr_reset_framework_format ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_dev_query_gpu_info -function drm_pvr_dev_query_runtime_info -function drm_pvr_dev_query_hwrt_info -function drm_pvr_dev_query_quirks -function drm_pvr_dev_query_enhancements ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_dev_query ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_heap_id -function drm_pvr_heap -function drm_pvr_dev_query_heap_info ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_create_bo_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_create_context_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_create_free_list_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_create_hwrt_dataset_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_create_vm_context_args -function drm_pvr_ioctl_destroy_vm_context_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_destroy_context_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_destroy_free_list_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_destroy_hwrt_dataset_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_dev_query_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_get_bo_mmap_offset_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_submit_jobs_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_ioctl_vm_map_args -function drm_pvr_ioctl_vm_unmap_args ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_obj_array ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function DRM_PVR_OBJ_ARRAY ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_static_data_area_usage -function drm_pvr_static_data_area -function drm_pvr_dev_query_static_data_areas ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function drm_pvr_sync_op -function drm_pvr_job_type -function drm_pvr_hwrt_data_ref -function drm_pvr_job ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'drm utils' ./include/drm/drm_util.h
+./diff-doc -rst -enable-lineno -function DSB ./drivers/gpu/drm/i915/display/intel_dsb.c
+./diff-doc -rst -enable-lineno -function 'dsc helpers' ./drivers/gpu/drm/display/drm_dsc_helper.c
+./diff-doc -rst -enable-lineno -function 'dsi bridge operations' ./drivers/gpu/drm/drm_bridge.c
+./diff-doc -rst -enable-lineno -function 'dsi helpers' ./drivers/gpu/drm/drm_mipi_dsi.c
+./diff-doc -rst -enable-lineno -function 'dup_failed_modules - tracks duplicate failed modules' ./kernel/module/stats.c
+./diff-doc -rst -enable-lineno -function 'eBPF Syscall Commands' ./include/uapi/linux/bpf.h
+./diff-doc -rst -enable-lineno -function 'eBPF Syscall Preamble' ./include/uapi/linux/bpf.h
+./diff-doc -rst -enable-lineno -function ecdh -function crypto_ecdh_key_len -function crypto_ecdh_encode_key -function crypto_ecdh_decode_key ./include/crypto/ecdh.h
+./diff-doc -rst -enable-lineno -function 'ECDH Helper Functions' ./include/crypto/ecdh.h
+./diff-doc -rst -enable-lineno -function efi_embedded_fw_desc ./include/linux/efi_embedded_fw.h
+./diff-doc -rst -enable-lineno -function ethtool_c33_pse_admin_state ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_c33_pse_ext_state ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_c33_pse_ext_substate_class_num_events -function ethtool_c33_pse_ext_substate_error_condition -function ethtool_c33_pse_ext_substate_mr_pse_enable -function ethtool_c33_pse_ext_substate_option_detect_ted -function ethtool_c33_pse_ext_substate_option_vport_lim -function ethtool_c33_pse_ext_substate_ovld_detected -function ethtool_c33_pse_ext_substate_pd_dll_power_type -function ethtool_c33_pse_ext_substate_power_not_available -function ethtool_c33_pse_ext_substate_short_detected ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_c33_pse_pw_d_status ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_fec_stats ./include/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_mac_stats_src ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_mm_cfg ./include/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_mm_state ./include/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_mm_stats ./include/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_mm_verify_status ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_module_fw_flash_status ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_module_power_mode ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_module_power_mode_policy ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_pause_stats ./include/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_podl_pse_admin_state ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function ethtool_podl_pse_pw_d_status ./include/uapi/linux/ethtool.h
+./diff-doc -rst -enable-lineno -function EXAMPLE ./drivers/base/auxiliary.c
+./diff-doc -rst -enable-lineno -function Examples ./drivers/gpu/drm/drm_gpuvm.c
+./diff-doc -rst -enable-lineno -function example ./tools/testing/selftests/kselftest_harness.h
+./diff-doc -rst -enable-lineno -function 'Execbuf (User GPU command submission)' ./drivers/gpu/drm/xe/xe_exec.c
+./diff-doc -rst -enable-lineno -function 'explicit fencing properties' ./drivers/gpu/drm/drm_atomic_uapi.c
+./diff-doc -rst -enable-lineno -function extcon_get_property ./drivers/extcon/extcon.c
+./diff-doc -rst -enable-lineno -function extcon_get_state ./drivers/extcon/extcon.c
+./diff-doc -rst -enable-lineno -function extcon_set_state ./drivers/extcon/extcon.c
+./diff-doc -rst -enable-lineno -function extcon_set_state_sync ./drivers/extcon/extcon.c
+./diff-doc -rst -enable-lineno -function fan_curve ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function fan_minimum_pwm ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function fan_target_temperature ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function fan_zero_rpm_enable ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function fan_zero_rpm_stop_temperature ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function 'Faraday TV Encoder TVE200 DRM Driver' ./drivers/gpu/drm/tve200/tve200_drv.c
+./diff-doc -rst -enable-lineno -function 'fbdev helpers' ./drivers/gpu/drm/drm_fb_helper.c
+./diff-doc -rst -enable-lineno -function 'fence cross-driver contract' ./drivers/dma-buf/dma-fence.c
+./diff-doc -rst -enable-lineno -function 'fence register handling' ./drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
+./diff-doc -rst -enable-lineno -function 'fence signalling annotation' ./drivers/dma-buf/dma-fence.c
+./diff-doc -rst -enable-lineno -function fiemap_extent ./include/uapi/linux/fiemap.h
+./diff-doc -rst -enable-lineno -function fiemap_extent_info ./include/linux/fiemap.h
+./diff-doc -rst -enable-lineno -function fiemap ./include/uapi/linux/fiemap.h
+./diff-doc -rst -enable-lineno -function 'fifo underrun handling' ./drivers/gpu/drm/i915/display/intel_fifo_underrun.c
+./diff-doc -rst -enable-lineno -function 'file operations' ./drivers/gpu/drm/drm_file.c
+./diff-doc -rst -enable-lineno -function firmware_fallback_sysfs ./drivers/base/firmware_loader/fallback.c
+./diff-doc -rst -enable-lineno -function 'Firmware Layout' ./drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
+./diff-doc -rst -enable-lineno -function firmware_request_cache ./drivers/base/firmware_loader/main.c
+./diff-doc -rst -enable-lineno -function firmware_request_nowarn ./drivers/base/firmware_loader/main.c
+./diff-doc -rst -enable-lineno -function firmware_request_platform ./drivers/base/firmware_loader/main.c
+./diff-doc -rst -enable-lineno -function firmware_upload_register ./drivers/base/firmware_loader/sysfs_upload.c
+./diff-doc -rst -enable-lineno -function firmware_upload_unregister ./drivers/base/firmware_loader/sysfs_upload.c
+./diff-doc -rst -enable-lineno -function 'Flags for CREATE_BO' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'Flags for SUBMIT_JOB ioctl compute command.' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'Flags for SUBMIT_JOB ioctl fragment command.' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'Flags for SUBMIT_JOB ioctl geometry command.' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'Flags for SUBMIT_JOB ioctl transfer command.' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'Flags for the drm_pvr_sync_op object.' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'flip utils' ./include/drm/drm_flip_work.h
+./diff-doc -rst -enable-lineno -function 'Flow Control' ./drivers/gpu/drm/scheduler/sched_main.c
+./diff-doc -rst -enable-lineno -function folio_mapping ./mm/util.c
+./diff-doc -rst -enable-lineno -function fpga_bridge_get_to_list ./drivers/fpga/fpga-bridge.c
+./diff-doc -rst -enable-lineno -function fpga_bridge ./include/linux/fpga/fpga-bridge.h
+./diff-doc -rst -enable-lineno -function fpga_bridge_ops ./include/linux/fpga/fpga-bridge.h
+./diff-doc -rst -enable-lineno -function __fpga_bridge_register ./drivers/fpga/fpga-bridge.c
+./diff-doc -rst -enable-lineno -function fpga_bridges_put ./drivers/fpga/fpga-bridge.c
+./diff-doc -rst -enable-lineno -function fpga_bridge_unregister ./drivers/fpga/fpga-bridge.c
+./diff-doc -rst -enable-lineno -function fpga_image_info_alloc ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function fpga_image_info_free ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function fpga_image_info ./include/linux/fpga/fpga-mgr.h
+./diff-doc -rst -enable-lineno -function 'FPGA Manager flags' ./include/linux/fpga/fpga-mgr.h
+./diff-doc -rst -enable-lineno -function fpga_manager ./include/linux/fpga/fpga-mgr.h
+./diff-doc -rst -enable-lineno -function fpga_manager_info ./include/linux/fpga/fpga-mgr.h
+./diff-doc -rst -enable-lineno -function fpga_manager_ops ./include/linux/fpga/fpga-mgr.h
+./diff-doc -rst -enable-lineno -function fpga_mgr_get ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function fpga_mgr_put ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function __fpga_mgr_register ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function __fpga_mgr_register_full ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function fpga_mgr_states ./include/linux/fpga/fpga-mgr.h
+./diff-doc -rst -enable-lineno -function fpga_mgr_unregister ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function fpga_region ./include/linux/fpga/fpga-region.h
+./diff-doc -rst -enable-lineno -function fpga_region_info ./include/linux/fpga/fpga-region.h
+./diff-doc -rst -enable-lineno -function fpga_region_program_fpga ./drivers/fpga/fpga-region.c
+./diff-doc -rst -enable-lineno -function __fpga_region_register ./drivers/fpga/fpga-region.c
+./diff-doc -rst -enable-lineno -function __fpga_region_register_full ./drivers/fpga/fpga-region.c
+./diff-doc -rst -enable-lineno -function fpga_region_unregister ./drivers/fpga/fpga-region.c
+./diff-doc -rst -enable-lineno -function 'Frame Buffer Compression (FBC)' ./drivers/gpu/drm/i915/display/intel_fbc.c
+./diff-doc -rst -enable-lineno -function 'framebuffer dma helper functions' ./drivers/gpu/drm/drm_fb_dma_helper.c
+./diff-doc -rst -enable-lineno -function 'Frame filtering' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'Frame format' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'frontbuffer tracking' ./drivers/gpu/drm/i915/display/intel_frontbuffer.c
+./diff-doc -rst -enable-lineno -function fru_id ./drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
+./diff-doc -rst -enable-lineno -function fs_access -function net_access -function scope ./include/uapi/linux/landlock.h
+./diff-doc -rst -enable-lineno -function fw_iso_context_schedule_flush_completions ./include/linux/firewire.h
+./diff-doc -rst -enable-lineno -function fw_upload_err ./include/linux/firmware.h
+./diff-doc -rst -enable-lineno -function fw_upload_ops ./include/linux/firmware.h
+./diff-doc -rst -enable-lineno -function fw_upload_prog ./drivers/base/firmware_loader/sysfs_upload.h
+./diff-doc -rst -enable-lineno -function 'Generic Key-agreement Protocol Primitives API' ./include/crypto/kpp.h
+./diff-doc -rst -enable-lineno -function 'Generic Public Key Cipher API' ./include/crypto/akcipher.h
+./diff-doc -rst -enable-lineno -function 'Generic Public Key Signature API' ./include/crypto/sig.h
+./diff-doc -rst -enable-lineno -function 'Generic radix trees/sparse arrays' ./include/linux/generic-radix-tree.h
+./diff-doc -rst -enable-lineno -function gen_pool_add ./include/linux/genalloc.h
+./diff-doc -rst -enable-lineno -function gen_pool_add_owner ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_alloc_algo_owner ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_alloc ./include/linux/genalloc.h
+./diff-doc -rst -enable-lineno -function gen_pool_avail ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_create ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_destroy ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_dma_alloc ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_for_each_chunk ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_free_owner ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_get ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_has_addr ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_set_algo ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_size ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function gen_pool_virt_to_phys ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function 'getunique and setversion story' ./drivers/gpu/drm/drm_ioctl.c
+./diff-doc -rst -enable-lineno -function get_user_pages_fast ./mm/gup.c
+./diff-doc -rst -enable-lineno -function 'Global Graphics Translation Table (GGTT)' ./drivers/gpu/drm/xe/xe_ggtt.c
+./diff-doc -rst -enable-lineno -function 'Global GTT views' ./drivers/gpu/drm/i915/i915_vma_types.h
+./diff-doc -rst -enable-lineno -function gpioevent_data -function gpioevent_request -function gpiohandle_config -function gpiohandle_data -function gpiohandle_request -function gpioline_info -function gpioline_info_changed ./include/uapi/linux/gpio.h
+./diff-doc -rst -enable-lineno -function gpio_v2_line_attr_id -function gpio_v2_line_attribute -function gpio_v2_line_changed_type -function gpio_v2_line_config -function gpio_v2_line_config_attribute -function gpio_v2_line_event -function gpio_v2_line_event_id -function gpio_v2_line_flag -function gpio_v2_line_info -function gpio_v2_line_info_changed -function gpio_v2_line_request -function gpio_v2_line_values -function gpiochip_info ./include/uapi/linux/gpio.h
+./diff-doc -rst -enable-lineno -function gpu_busy_percent ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function gpu_metrics ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function GPUVM ./drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+./diff-doc -rst -enable-lineno -function 'Graphics mux' ./drivers/platform/x86/apple-gmux.c
+./diff-doc -rst -enable-lineno -function 'GSC-based Firmware Layout' ./drivers/gpu/drm/xe/xe_uc_fw_abi.h
+./diff-doc -rst -enable-lineno -function 'GT Multicast/Replicated (MCR) Register Support' ./drivers/gpu/drm/i915/gt/intel_gt_mcr.c
+./diff-doc -rst -enable-lineno -function 'GT Multicast/Replicated (MCR) Register Support' ./drivers/gpu/drm/xe/xe_gt_mcr.c
+./diff-doc -rst -enable-lineno -function 'GuC-based command submission' ./drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+./diff-doc -rst -enable-lineno -function 'GuC CTB Blob' ./drivers/gpu/drm/xe/xe_guc_ct.c
+./diff-doc -rst -enable-lineno -function GuC ./drivers/gpu/drm/i915/gt/uc/intel_guc.c
+./diff-doc -rst -enable-lineno -function 'GuC Memory Management' ./drivers/gpu/drm/i915/gt/uc/intel_guc.c
+./diff-doc -rst -enable-lineno -function 'GuC Power Conservation (PC)' ./drivers/gpu/drm/xe/xe_guc_pc.c
+./diff-doc -rst -enable-lineno -function 'handling driver private state' ./drivers/gpu/drm/drm_atomic.c
+./diff-doc -rst -enable-lineno -function 'Hardware crypto acceleration' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'Hardware workarounds' ./drivers/gpu/drm/i915/gt/intel_workarounds.c
+./diff-doc -rst -enable-lineno -function 'Hardware workarounds' ./drivers/gpu/drm/xe/xe_wa.c
+./diff-doc -rst -enable-lineno -function hash_alg_common -function ahash_alg -function shash_alg ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function 'HDMI connector properties' ./drivers/gpu/drm/drm_connector.c
+./diff-doc -rst -enable-lineno -function 'HDMI Output' ./drivers/gpu/drm/meson/meson_dw_hdmi.c
+./diff-doc -rst -enable-lineno -function hid_bpf_ctx ./include/linux/hid_bpf.h
+./diff-doc -rst -enable-lineno -function hid_bpf_get_data ./drivers/hid/bpf/hid_bpf_dispatch.c
+./diff-doc -rst -enable-lineno -function hid_bpf_hw_request -function hid_bpf_hw_output_report -function hid_bpf_input_report -function hid_bpf_try_input_report -function hid_bpf_allocate_context -function hid_bpf_release_context ./drivers/hid/bpf/hid_bpf_dispatch.c
+./diff-doc -rst -enable-lineno -function hid_bpf_ops ./include/linux/hid_bpf.h
+./diff-doc -rst -enable-lineno -function 'HID quirks' ./include/linux/hid.h
+./diff-doc -rst -enable-lineno -function 'High Definition Audio over HDMI and Display Port' ./drivers/gpu/drm/i915/display/intel_audio.c
+./diff-doc -rst -enable-lineno -function Hotplug ./drivers/gpu/drm/i915/display/intel_hotplug.c
+./diff-doc -rst -enable-lineno -function 'hotspot properties' ./drivers/gpu/drm/drm_plane.c
+./diff-doc -rst -enable-lineno -function hte_init_line_attr -function hte_ts_get -function hte_ts_put -function devm_hte_request_ts_ns -function hte_request_ts_ns -function hte_enable_ts -function hte_disable_ts -function of_hte_req_count -function hte_get_clk_src_info ./drivers/hte/hte.c
+./diff-doc -rst -enable-lineno -function HuC ./drivers/gpu/drm/i915/gt/uc/intel_huc.c
+./diff-doc -rst -enable-lineno -function 'HuC Memory Management' ./drivers/gpu/drm/i915/gt/uc/intel_huc.c
+./diff-doc -rst -enable-lineno -function hwmon ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function i2c_register_board_info ./drivers/i2c/i2c-boardinfo.c
+./diff-doc -rst -enable-lineno -function 'i915_context_create and i915_context_free tracepoints' ./drivers/gpu/drm/i915/i915_trace.h
+./diff-doc -rst -enable-lineno -function i915_context_engines_parallel_submit ./include/uapi/drm/i915_drm.h
+./diff-doc -rst -enable-lineno -function i915_oa_ops ./drivers/gpu/drm/i915/i915_perf_types.h
+./diff-doc -rst -enable-lineno -function i915_oa_poll_wait ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_oa_read ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_oa_stream_disable ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_oa_stream_enable ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_oa_stream_init ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_oa_wait_unlocked ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_add_config_ioctl ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_destroy_locked ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_disable_locked ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_enable_locked ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_fini ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function 'i915 Perf History and Comparison with Core Perf' ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_init ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_ioctl ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_open_ioctl ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_open_ioctl_locked ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function 'i915 Perf Overview' ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_poll ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_poll_locked ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_read ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_register ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_release ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_remove_config_ioctl ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function i915_perf_stream ./drivers/gpu/drm/i915/i915_perf_types.h
+./diff-doc -rst -enable-lineno -function i915_perf_stream_ops ./drivers/gpu/drm/i915/i915_perf_types.h
+./diff-doc -rst -enable-lineno -function i915_perf_unregister ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function 'i915_ppgtt_create and i915_ppgtt_release tracepoints' ./drivers/gpu/drm/i915/i915_trace.h
+./diff-doc -rst -enable-lineno -function i915_sched_engine ./drivers/gpu/drm/i915/i915_scheduler_types.h
+./diff-doc -rst -enable-lineno -function 'IDA description' ./lib/idr.c
+./diff-doc -rst -enable-lineno -function 'idr sync' ./include/linux/idr.h
+./diff-doc -rst -enable-lineno -function ieee80211_ampdu_mlme_action ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_beacon_loss ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_channel_flags -function ieee80211_channel -function ieee80211_rate_flags -function ieee80211_rate -function ieee80211_sta_ht_cap -function ieee80211_supported_band -function cfg80211_signal_type -function wiphy_params_flags -function wiphy_flags -function wiphy -function wireless_dev -function wiphy_new -function wiphy_read_of_freq_limits -function wiphy_register -function wiphy_unregister -function wiphy_free -function wiphy_name -function wiphy_dev -function wiphy_priv -function priv_to_wiphy -function set_wiphy_dev -function wdev_priv -function ieee80211_iface_limit -function ieee80211_iface_combination -function cfg80211_check_combinations ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_channel_to_frequency -function ieee80211_frequency_to_channel -function ieee80211_get_channel -function ieee80211_get_response_rate -function ieee80211_hdrlen -function ieee80211_get_hdrlen_from_skb -function ieee80211_radiotap_iterator ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_conf -function ieee80211_conf_flags ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_data_to_8023 -function ieee80211_amsdu_to_8023s -function cfg80211_classify8021d ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_filter_flags ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_get_buffered_bc -function ieee80211_beacon_get -function ieee80211_sta_eosp -function ieee80211_frame_release_type -function ieee80211_sta_ps_transition -function ieee80211_sta_ps_transition_ni -function ieee80211_sta_set_buffered -function ieee80211_sta_block_awake ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_get_tx_led_name -function ieee80211_get_rx_led_name -function ieee80211_get_assoc_led_name -function ieee80211_get_radio_led_name -function ieee80211_tpt_blink -function ieee80211_tpt_led_trigger_flags -function ieee80211_create_tpt_led_trigger ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_hw -function ieee80211_hw_flags -function SET_IEEE80211_DEV -function SET_IEEE80211_PERM_ADDR -function ieee80211_ops -function ieee80211_alloc_hw -function ieee80211_register_hw -function ieee80211_unregister_hw -function ieee80211_free_hw ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_iterate_active_interfaces -function ieee80211_iterate_active_interfaces_atomic ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_queue_work -function ieee80211_queue_delayed_work ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_request_smps -function ieee80211_smps_mode ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_rx_status -function mac80211_rx_encoding_flags -function mac80211_rx_flags -function mac80211_tx_info_flags -function mac80211_tx_control_flags -function mac80211_rate_control_flags -function ieee80211_tx_rate -function ieee80211_tx_info -function ieee80211_tx_info_clear_status -function ieee80211_rx -function ieee80211_rx_ni -function ieee80211_rx_irqsafe -function ieee80211_tx_status_skb -function ieee80211_tx_status_ni -function ieee80211_tx_status_irqsafe -function ieee80211_rts_get -function ieee80211_rts_duration -function ieee80211_ctstoself_get -function ieee80211_ctstoself_duration -function ieee80211_generic_frame_duration -function ieee80211_wake_queue -function ieee80211_stop_queue -function ieee80211_wake_queues -function ieee80211_stop_queues -function ieee80211_queue_stopped ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_scan_completed ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_sta -function sta_notify_cmd -function ieee80211_find_sta -function ieee80211_find_sta_by_ifaddr ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_start_tx_ba_session -function ieee80211_start_tx_ba_cb_irqsafe -function ieee80211_stop_tx_ba_session -function ieee80211_stop_tx_ba_cb_irqsafe -function ieee80211_rate_control_changed -function ieee80211_tx_rate_control ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_tx_queue_params ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function ieee80211_vif ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'implementing nonblocking commit' ./drivers/gpu/drm/drm_atomic_helper.c
+./diff-doc -rst -enable-lineno -function 'implicit fence polling' ./drivers/dma-buf/dma-buf.c
+./diff-doc -rst -enable-lineno -function intel_guc_allocate_vma ./drivers/gpu/drm/i915/gt/uc/intel_guc.c
+./diff-doc -rst -enable-lineno -function 'Intel GVT-g guest support' ./drivers/gpu/drm/i915/i915_vgpu.c
+./diff-doc -rst -enable-lineno -function 'Intel GVT-g host support' ./drivers/gpu/drm/i915/intel_gvt.c
+./diff-doc -rst -enable-lineno -function intel_huc_auth ./drivers/gpu/drm/i915/gt/uc/intel_huc.c
+./diff-doc -rst -enable-lineno -function intel_irq_init -function intel_irq_init_hw -function intel_hpd_init ./drivers/gpu/drm/i915/i915_irq.c
+./diff-doc -rst -enable-lineno -function intel_irq_resume ./drivers/gpu/drm/i915/i915_irq.c
+./diff-doc -rst -enable-lineno -function intel_irq_suspend ./drivers/gpu/drm/i915/i915_irq.c
+./diff-doc -rst -enable-lineno -function Interrupt ./drivers/platform/x86/apple-gmux.c
+./diff-doc -rst -enable-lineno -function 'Interrupt Handling' ./drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+./diff-doc -rst -enable-lineno -function 'interrupt handling' ./drivers/gpu/drm/i915/i915_irq.c
+./diff-doc -rst -enable-lineno -function 'Interrupt management for the V3D engine' ./drivers/gpu/drm/v3d/v3d_irq.c
+./diff-doc -rst -enable-lineno -function 'Interrupt management for the V3D engine' ./drivers/gpu/drm/vc4/vc4_irq.c
+./diff-doc -rst -enable-lineno -function Introduction ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function 'IOCTL validation helpers' ./drivers/gpu/drm/imagination/pvr_device.h
+./diff-doc -rst -enable-lineno -function 'IP Blocks' ./drivers/gpu/drm/amd/include/amd_shared.h
+./diff-doc -rst -enable-lineno -function iscsi_iser_pdu_alloc -function iser_initialize_task_headers -function \ -function iscsi_iser_task_init -function iscsi_iser_mtask_xmit -function iscsi_iser_task_xmit -function \ -function iscsi_iser_cleanup_task -function iscsi_iser_check_protection -function \ -function iscsi_iser_conn_create -function iscsi_iser_conn_bind -function \ -function iscsi_iser_conn_start -function iscsi_iser_conn_stop -function \ -function iscsi_iser_session_destroy -function iscsi_iser_session_create -function \ -function iscsi_iser_set_param -function iscsi_iser_ep_connect -function iscsi_iser_ep_poll -function \ -function iscsi_iser_ep_disconnect ./drivers/infiniband/ulp/iser/iscsi_iser.c
+./diff-doc -rst -enable-lineno -function is_kfence_address -function kfence_shutdown_cache -function kfence_alloc -function kfence_free -function __kfence_free -function kfence_ksize -function kfence_object_start -function kfence_handle_page_fault ./include/linux/kfence.h
+./diff-doc -rst -enable-lineno -function kernel_hwtstamp_config ./include/linux/net_tstamp.h
+./diff-doc -rst -enable-lineno -function 'Key handling basics' ./net/mac80211/key.c
+./diff-doc -rst -enable-lineno -function kfree_const -function kvmalloc_node -function kvfree ./mm/util.c
+./diff-doc -rst -enable-lineno -function klp_patch -function klp_object -function klp_func -function klp_callbacks -function klp_state ./include/linux/livepatch.h
+./diff-doc -rst -enable-lineno -function 'kms locking' ./drivers/gpu/drm/drm_modeset_lock.c
+./diff-doc -rst -enable-lineno -function kpp_request_alloc -function kpp_request_free -function kpp_request_set_callback -function kpp_request_set_input -function kpp_request_set_output ./include/crypto/kpp.h
+./diff-doc -rst -enable-lineno -function kpp_request -function crypto_kpp -function kpp_alg -function kpp_secret ./include/crypto/kpp.h
+./diff-doc -rst -enable-lineno -function kstrdup -function kstrdup_const -function kstrndup -function kmemdup -function kmemdup_nul -function memdup_user -function vmemdup_user -function strndup_user -function memdup_user_nul ./mm/util.c
+./diff-doc -rst -enable-lineno -function kstrtol -function kstrtoul ./include/linux/kstrtox.h
+./diff-doc -rst -enable-lineno -function landlock_ruleset_attr ./include/uapi/linux/landlock.h
+./diff-doc -rst -enable-lineno -function landlock_rule_type -function landlock_path_beneath_attr -function landlock_net_port_attr ./include/uapi/linux/landlock.h
+./diff-doc -rst -enable-lineno -function lirc_scancode -function rc_proto ./include/uapi/linux/lirc.h
+./diff-doc -rst -enable-lineno -function 'locking convention' ./drivers/dma-buf/dma-buf.c
+./diff-doc -rst -enable-lineno -function Locking ./drivers/gpu/drm/drm_gpuvm.c
+./diff-doc -rst -enable-lineno -function 'Lockless queue stopping / waking helpers.' ./include/net/netdev_queues.h
+./diff-doc -rst -enable-lineno -function 'Logical Rings, Logical Ring Contexts and Execlists' ./drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+./diff-doc -rst -enable-lineno -function 'LPE Audio integration for HDMI or DP playback' ./drivers/gpu/drm/i915/display/intel_lpe_audio.c
+./diff-doc -rst -enable-lineno -function 'lru scan roster' ./drivers/gpu/drm/drm_mm.c
+./diff-doc -rst -enable-lineno -function 'mac80211 workqueue' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'managed resources' ./drivers/gpu/drm/drm_managed.c
+./diff-doc -rst -enable-lineno -function 'Manual switching and manual power control' ./drivers/gpu/vga/vga_switcheroo.c
+./diff-doc -rst -enable-lineno -function manufacturer ./drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
+./diff-doc -rst -enable-lineno -function 'Map layer' ./drivers/gpu/drm/xe/xe_map.h
+./diff-doc -rst -enable-lineno -function 'master and authentication' ./drivers/gpu/drm/drm_auth.c
+./diff-doc -rst -enable-lineno -function mctrl_gpio_init -function mctrl_gpio_free -function mctrl_gpio_to_gpiod -function mctrl_gpio_set -function mctrl_gpio_get -function mctrl_gpio_enable_ms -function mctrl_gpio_disable_ms ./drivers/tty/serial/serial_mctrl_gpio.c
+./diff-doc -rst -enable-lineno -function mdelay ./include/linux/delay.h
+./diff-doc -rst -enable-lineno -function 'MEI_HDCP Client Driver' ./drivers/misc/mei/hdcp/mei_hdcp.c
+./diff-doc -rst -enable-lineno -function memalloc_nofs_save -function memalloc_nofs_restore ./include/linux/sched/mm.h
+./diff-doc -rst -enable-lineno -function memalloc_noio_save -function memalloc_noio_restore ./include/linux/sched/mm.h
+./diff-doc -rst -enable-lineno -function 'memblock overview' ./mm/memblock.c
+./diff-doc -rst -enable-lineno -function mem_busy_percent ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function mem_info_gtt_total ./drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
+./diff-doc -rst -enable-lineno -function mem_info_gtt_used ./drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
+./diff-doc -rst -enable-lineno -function mem_info_vis_vram_total ./drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+./diff-doc -rst -enable-lineno -function mem_info_vis_vram_used ./drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+./diff-doc -rst -enable-lineno -function mem_info_vram_total ./drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+./diff-doc -rst -enable-lineno -function mem_info_vram_used ./drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+./diff-doc -rst -enable-lineno -function 'memory domains' ./include/uapi/drm/amdgpu_drm.h
+./diff-doc -rst -enable-lineno -function 'Message Digest Algorithm Definitions' ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function 'Migrate Layer' ./drivers/gpu/drm/xe/xe_migrate_doc.h
+./diff-doc -rst -enable-lineno -function mm_slot -function ksm_scan -function stable_node -function rmap_item ./mm/ksm.c
+./diff-doc -rst -enable-lineno -function 'MMU Notifier' ./drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
+./diff-doc -rst -enable-lineno -function 'module debugging statistics overview' ./kernel/module/stats.c
+./diff-doc -rst -enable-lineno -function 'module statistics debugfs counters' ./kernel/module/stats.c
+./diff-doc -rst -enable-lineno -function mpcc_alpha_blend_mode ./drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
+./diff-doc -rst -enable-lineno -function mpcc_blnd_cfg ./drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
+./diff-doc -rst -enable-lineno -function msleep -function msleep_interruptible ./kernel/time/sleep_timeout.c
+./diff-doc -rst -enable-lineno -function 'Multi-tile Design' ./drivers/gpu/drm/xe/xe_tile.c
+./diff-doc -rst -enable-lineno -function nbcon_state -function nbcon_prio -function nbcon_context -function nbcon_write_context ./include/linux/console.h
+./diff-doc -rst -enable-lineno -function net_bridge_vlan ./net/bridge/br_private.h
+./diff-doc -rst -enable-lineno -function of_fpga_bridge_get_to_list ./drivers/fpga/fpga-bridge.c
+./diff-doc -rst -enable-lineno -function of_fpga_mgr_get ./drivers/fpga/fpga-mgr.c
+./diff-doc -rst -enable-lineno -function of_gen_pool_get ./lib/genalloc.c
+./diff-doc -rst -enable-lineno -function of_reset_simple_xlate -function reset_controller_register -function reset_controller_unregister -function devm_reset_controller_register -function reset_controller_add_lookup ./drivers/reset/core.c
+./diff-doc -rst -enable-lineno -function operators ./tools/testing/selftests/kselftest_harness.h
+./diff-doc -rst -enable-lineno -function 'output probing helper overview' ./drivers/gpu/drm/drm_probe_helper.c
+./diff-doc -rst -enable-lineno -function 'overview and lifetime rules' ./drivers/gpu/drm/drm_prime.c
+./diff-doc -rst -enable-lineno -function overview ./arch/x86/kernel/cpu/intel_epb.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/base/component.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/dma-buf/dma-buf-sysfs-stats.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/dc/inc/hw/opp.h
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/display/drm_bridge_connector.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_atomic_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_atomic_uapi.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_blend.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_bridge.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_client.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_color_mgmt.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_connector.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_crtc.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_crtc_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_dumb_buffers.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_encoder.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/gpu/drm/drm_exec.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_framebuffer.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_gem_atomic_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_gem_framebuffer_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_gem_shmem_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_gem_ttm_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_gem_vram_helper.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/gpu/drm/drm_gpuvm.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_mipi_dbi.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/gpu/drm/drm_mm.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_of.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_panic.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_plane.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_plane_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_privacy_screen.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_property.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_self_refresh_helper.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_simple_kms_helper.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/gpu/drm/drm_syncobj.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_sysfs.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/gpu/drm/drm_writeback.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/gpu/drm/nouveau/nouveau_exec.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/gpu/drm/scheduler/sched_main.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/gpu/vga/vga_switcheroo.c
+./diff-doc -rst -enable-lineno -function Overview ./drivers/platform/x86/apple-gmux.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/video/aperture.c
+./diff-doc -rst -enable-lineno -function overview ./drivers/video/backlight/backlight.c
+./diff-doc -rst -enable-lineno -function overview ./include/drm/drm_modeset_helper_vtables.h
+./diff-doc -rst -enable-lineno -function overview ./include/drm/drm_module.h
+./diff-doc -rst -enable-lineno -function overview ./include/linux/iosys-map.h
+./diff-doc -rst -enable-lineno -function overview ./include/uapi/drm/drm_fourcc.h
+./diff-doc -rst -enable-lineno -function overview ./include/uapi/drm/drm_mode.h
+./diff-doc -rst -enable-lineno -function Overview ./mm/ksm.c
+./diff-doc -rst -enable-lineno -function 'Packet alignment' ./net/mac80211/rx.c
+./diff-doc -rst -enable-lineno -function 'Page mobility and placement hints' ./include/linux/gfp_types.h
+./diff-doc -rst -enable-lineno -function 'page_pool allocator' ./include/net/page_pool/helpers.h
+./diff-doc -rst -enable-lineno -function page_pool_create ./net/core/page_pool.c
+./diff-doc -rst -enable-lineno -function page_pool_put_page_bulk -function page_pool_get_stats ./net/core/page_pool.c
+./diff-doc -rst -enable-lineno -function page_pool_put_page -function page_pool_put_full_page -function page_pool_recycle_direct -function page_pool_free_va -function page_pool_dev_alloc_pages -function page_pool_dev_alloc_frag -function page_pool_dev_alloc -function page_pool_dev_alloc_va -function page_pool_get_dma_addr -function page_pool_get_dma_dir ./include/net/page_pool/helpers.h
+./diff-doc -rst -enable-lineno -function 'Pagetable building' ./drivers/gpu/drm/xe/xe_pt.c
+./diff-doc -rst -enable-lineno -function 'Panel Self Refresh (PSR/SRD)' ./drivers/gpu/drm/i915/display/intel_psr.c
+./diff-doc -rst -enable-lineno -function pci_device_id ./include/linux/mod_devicetable.h
+./diff-doc -rst -enable-lineno -function pci_driver ./include/linux/pci.h
+./diff-doc -rst -enable-lineno -function pcie_bw ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function pcie_replay_count ./drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+./diff-doc -rst -enable-lineno -function PCODE ./drivers/gpu/drm/xe/xe_pcode.c
+./diff-doc -rst -enable-lineno -function pm_policy ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function 'Power control' ./drivers/platform/x86/apple-gmux.c
+./diff-doc -rst -enable-lineno -function power_dpm_force_performance_level ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function power_dpm_state ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function 'Powersave support' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL CREATE_BO interface' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL CREATE_CONTEXT and DESTROY_CONTEXT interfaces' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL CREATE_FREE_LIST and DESTROY_FREE_LIST interfaces' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL CREATE_HWRT_DATASET and DESTROY_HWRT_DATASET interfaces' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL CREATE_VM_CONTEXT and DESTROY_VM_CONTEXT interfaces' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL DEV_QUERY interface' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL GET_BO_MMAP_OFFSET interface' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL interface' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL SUBMIT_JOBS interface' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR IOCTL VM_MAP and VM_UNMAP interfaces' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'PowerVR (Series 6 and later) and IMG Graphics Driver' ./drivers/gpu/drm/imagination/pvr_drv.c
+./diff-doc -rst -enable-lineno -function 'PowerVR UAPI' ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function 'pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_fclk pp_dpm_dcefclk pp_dpm_pcie' ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function pp_od_clk_voltage ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function pp_power_profile_mode ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function pp_table ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function 'PRIME Buffer Sharing' ./drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+./diff-doc -rst -enable-lineno -function 'PRIME Helpers' ./drivers/gpu/drm/drm_prime.c
+./diff-doc -rst -enable-lineno -function print ./include/drm/drm_print.h
+./diff-doc -rst -enable-lineno -function printk -function pr_emerg -function pr_alert -function pr_crit -function pr_err -function pr_warn -function pr_notice -function pr_info -function pr_fmt -function pr_debug -function pr_devel -function pr_cont ./include/linux/printk.h
+./diff-doc -rst -enable-lineno -function probe_type -function device_driver ./include/linux/device/driver.h
+./diff-doc -rst -enable-lineno -function product_name ./drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
+./diff-doc -rst -enable-lineno -function product_number ./drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
+./diff-doc -rst -enable-lineno -function PURPOSE ./drivers/base/auxiliary.c
+./diff-doc -rst -enable-lineno -function PVR_IOCTL ./include/uapi/drm/pvr_drm.h
+./diff-doc -rst -enable-lineno -function PVR_STATIC_ASSERT_64BIT_ALIGNED -function PVR_IOCTL_UNION_PADDING_CHECK -function pvr_ioctl_union_padding_check ./drivers/gpu/drm/imagination/pvr_device.h
+./diff-doc -rst -enable-lineno -function PXP ./drivers/gpu/drm/i915/pxp/intel_pxp.c
+./diff-doc -rst -enable-lineno -function 'Random number generator API' ./include/crypto/rng.h
+./diff-doc -rst -enable-lineno -function 'Readahead Overview' ./mm/readahead.c
+./diff-doc -rst -enable-lineno -function read_properties_unlocked ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -function 'Reclaim modifiers' ./include/linux/gfp_types.h
+./diff-doc -rst -enable-lineno -function 'rect utils' ./include/drm/drm_rect.h
+./diff-doc -rst -enable-lineno -function register_hpd_handlers -function dm_crtc_high_irq -function dm_pflip_high_irq ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+./diff-doc -rst -enable-lineno -function 'Register Table Processing' ./drivers/gpu/drm/xe/xe_rtp.c
+./diff-doc -rst -enable-lineno -function 'Regulatory enforcement infrastructure' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function regulatory_hint -function wiphy_apply_custom_regulatory -function freq_reg_info ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function 'Render command list generation' ./drivers/gpu/drm/vc4/vc4_render_cl.c
+./diff-doc -rst -enable-lineno -function request_firmware_direct ./drivers/base/firmware_loader/main.c
+./diff-doc -rst -enable-lineno -function request_firmware ./drivers/base/firmware_loader/main.c
+./diff-doc -rst -enable-lineno -function request_firmware_into_buf ./drivers/base/firmware_loader/main.c
+./diff-doc -rst -enable-lineno -function request_firmware_nowait ./drivers/base/firmware_loader/main.c
+./diff-doc -rst -enable-lineno -function 'Reservation Object Overview' ./drivers/dma-buf/dma-resv.c
+./diff-doc -rst -enable-lineno -function reset_control_reset -function reset_control_assert -function reset_control_deassert -function reset_control_status -function reset_control_acquire -function reset_control_release -function reset_control_rearm -function reset_control_put -function of_reset_control_get_count -function of_reset_control_array_get -function devm_reset_control_array_get -function reset_control_get_count ./drivers/reset/core.c
+./diff-doc -rst -enable-lineno -function 'RFkill integration' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function 'Ring Design' ./include/uapi/linux/target_core_user.h
+./diff-doc -rst -enable-lineno -function riscv_set_icache_flush_ctx ./arch/riscv/mm/cacheflush.c
+./diff-doc -rst -enable-lineno -function rng_alg ./include/crypto/rng.h
+./diff-doc -rst -enable-lineno -function rtnl_link_stats64 ./include/uapi/linux/if_link.h
+./diff-doc -rst -enable-lineno -function 'runtime pm' ./drivers/gpu/drm/i915/intel_runtime_pm.c
+./diff-doc -rst -enable-lineno -function 'RX A-MPDU aggregation' ./net/mac80211/agg-rx.c
+./diff-doc -rst -enable-lineno -function 'Scanning and BSS list handling' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function 'scdc helpers' ./drivers/gpu/drm/display/drm_scdc_helper.c
+./diff-doc -rst -enable-lineno -function 'scope-based cleanup helpers' ./include/linux/cleanup.h
+./diff-doc -rst -enable-lineno -function serial_number ./drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c
+./diff-doc -rst -enable-lineno -function serial_rs485 -function uart_get_rs485_mode ./include/uapi/linux/serial.h
+./diff-doc -rst -enable-lineno -function set_key_cmd -function ieee80211_key_conf -function ieee80211_key_flags -function ieee80211_get_tkip_p1k -function ieee80211_get_tkip_p1k_iv -function ieee80211_get_tkip_p2k ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function sgx_ioc_enclave_create -function sgx_ioc_enclave_add_pages -function sgx_ioc_enclave_init -function sgx_ioc_enclave_provision ./arch/x86/kernel/cpu/sgx/ioctl.c
+./diff-doc -rst -enable-lineno -function sgx_ioc_enclave_restrict_permissions -function sgx_ioc_enclave_modify_types -function sgx_ioc_enclave_remove_pages ./arch/x86/kernel/cpu/sgx/ioctl.c
+./diff-doc -rst -enable-lineno -function 'Shader validator for VC4.' ./drivers/gpu/drm/vc4/vc4_validate_shaders.c
+./diff-doc -rst -enable-lineno -function sig_alg ./include/crypto/sig.h
+./diff-doc -rst -enable-lineno -function 'Single Block Cipher API' ./include/crypto/internal/cipher.h
+./diff-doc -rst -enable-lineno -function 'skb checksums' ./include/linux/skbuff.h
+./diff-doc -rst -enable-lineno -function smartshift_apu_power ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function smartshift_bias ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function smartshift_dgpu_power ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function snd_soc_dai_set_bclk_ratio ./sound/soc/soc-dai.c
+./diff-doc -rst -enable-lineno -function snd_soc_dai_set_clkdiv ./sound/soc/soc-dai.c
+./diff-doc -rst -enable-lineno -function snd_soc_dai_set_pll ./sound/soc/soc-dai.c
+./diff-doc -rst -enable-lineno -function snd_soc_dai_set_sysclk ./sound/soc/soc-dai.c
+./diff-doc -rst -enable-lineno -function 'Spatial multiplexing power save' ./include/net/mac80211.h
+./diff-doc -rst -enable-lineno -function 'special care dsi' ./drivers/gpu/drm/drm_bridge.c
+./diff-doc -rst -enable-lineno -function spi_register_board_info ./drivers/spi/spi.c
+./diff-doc -rst -enable-lineno -function 'Split and Merge' ./drivers/gpu/drm/drm_gpuvm.c
+./diff-doc -rst -enable-lineno -function ssleep -function fsleep ./include/linux/delay.h
+./diff-doc -rst -enable-lineno -function sta_ampdu_mlme -function tid_ampdu_tx -function tid_ampdu_rx ./net/mac80211/sta_info.h
+./diff-doc -rst -enable-lineno -function sta_info -function ieee80211_sta_info_flags ./net/mac80211/sta_info.h
+./diff-doc -rst -enable-lineno -function 'STA information lifetime rules' ./net/mac80211/sta_info.c
+./diff-doc -rst -enable-lineno -function 'standard connector properties' ./drivers/gpu/drm/drm_connector.c
+./diff-doc -rst -enable-lineno -function 'standard CRTC properties' ./drivers/gpu/drm/drm_crtc.c
+./diff-doc -rst -enable-lineno -function 'standard plane properties' ./drivers/gpu/drm/drm_plane.c
+./diff-doc -rst -enable-lineno -function start_tty -function stop_tty ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function 'ST-Ericsson MCDE Driver' ./drivers/gpu/drm/mcde/mcde_drv.c
+./diff-doc -rst -enable-lineno -function stratix10_svc_cb_data ./include/linux/firmware/intel/stratix10-svc-client.h
+./diff-doc -rst -enable-lineno -function stratix10_svc_client ./include/linux/firmware/intel/stratix10-svc-client.h
+./diff-doc -rst -enable-lineno -function stratix10_svc_client_msg ./include/linux/firmware/intel/stratix10-svc-client.h
+./diff-doc -rst -enable-lineno -function stratix10_svc_command_code ./include/linux/firmware/intel/stratix10-svc-client.h
+./diff-doc -rst -enable-lineno -function stratix10_svc_command_config_type ./include/linux/firmware/intel/stratix10-svc-client.h
+./diff-doc -rst -enable-lineno -function struct -function dcp_blob_fmt ./security/keys/trusted-keys/trusted_dcp.c
+./diff-doc -rst -enable-lineno -function struct -function page_pool_params ./include/net/page_pool/types.h
+./diff-doc -rst -enable-lineno -function struct -function page_pool_recycle_stats -function struct -function page_pool_alloc_stats -function struct -function page_pool_stats ./include/net/page_pool/types.h
+./diff-doc -rst -enable-lineno -function struct -function virtqueue ./include/linux/virtio.h
+./diff-doc -rst -enable-lineno -function struct -function vring_desc ./include/uapi/linux/virtio_ring.h
+./diff-doc -rst -enable-lineno -function 'Supported input formats and encodings' ./include/drm/bridge/dw_hdmi.h
+./diff-doc -rst -enable-lineno -function 'Symmetric Key Cipher API' ./include/crypto/skcipher.h
+./diff-doc -rst -enable-lineno -function 'Symmetric Key Cipher Request Handle' ./include/crypto/skcipher.h
+./diff-doc -rst -enable-lineno -function 'Synchronous Message Digest API' ./include/crypto/hash.h
+./diff-doc -rst -enable-lineno -function sys_landlock_add_rule ./security/landlock/syscalls.c
+./diff-doc -rst -enable-lineno -function sys_landlock_create_ruleset ./security/landlock/syscalls.c
+./diff-doc -rst -enable-lineno -function sys_landlock_restrict_self ./security/landlock/syscalls.c
+./diff-doc -rst -enable-lineno -function sys_lsm_get_self_attr ./security/lsm_syscalls.c
+./diff-doc -rst -enable-lineno -function sys_lsm_list_modules ./security/lsm_syscalls.c
+./diff-doc -rst -enable-lineno -function sys_lsm_set_self_attr ./security/lsm_syscalls.c
+./diff-doc -rst -enable-lineno -function teo-description ./drivers/cpuidle/governors/teo.c
+./diff-doc -rst -enable-lineno -function 'Test mode' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function textsearch_find -function textsearch_next -function \ -function textsearch_get_pattern -function textsearch_get_pattern_len ./include/linux/textsearch.h
+./diff-doc -rst -enable-lineno -function 'The i915 register macro definition style guide' ./drivers/gpu/drm/i915/i915_reg.h
+./diff-doc -rst -enable-lineno -function TH_LOG -function TEST -function TEST_SIGNAL -function FIXTURE -function FIXTURE_DATA -function FIXTURE_SETUP -function FIXTURE_TEARDOWN -function TEST_F -function TEST_HARNESS_MAIN -function FIXTURE_VARIANT -function FIXTURE_VARIANT_ADD ./tools/testing/selftests/kselftest_harness.h
+./diff-doc -rst -enable-lineno -function 'Tile group' ./drivers/gpu/drm/drm_connector.c
+./diff-doc -rst -enable-lineno -function 'tiling swizzling details' ./drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
+./diff-doc -rst -enable-lineno -function ts_intro ./lib/textsearch.c
+./diff-doc -rst -enable-lineno -function TTM ./drivers/gpu/drm/ttm/ttm_module.c
+./diff-doc -rst -enable-lineno -function __tty_alloc_driver -function tty_driver_kref_put ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_buffer_lock_exclusive -function tty_buffer_unlock_exclusive ./drivers/tty/tty_buffer.c
+./diff-doc -rst -enable-lineno -function tty_buffer_space_avail -function tty_buffer_set_limit ./drivers/tty/tty_buffer.c
+./diff-doc -rst -enable-lineno -function tty_do_resize ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function 'TTY Driver Flags' ./include/linux/tty_driver.h
+./diff-doc -rst -enable-lineno -function tty_driver ./include/linux/tty_driver.h
+./diff-doc -rst -enable-lineno -function tty_get_baud_rate ./include/linux/tty.h
+./diff-doc -rst -enable-lineno -function tty_hangup -function tty_vhangup -function tty_hung_up_p ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_init_termios ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_insert_flip_string_fixed_flag -function tty_insert_flip_string_flags -function tty_insert_flip_char ./include/linux/tty_flip.h
+./diff-doc -rst -enable-lineno -function tty_kopen_exclusive -function tty_kopen_shared -function tty_kclose ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_kref_get ./include/linux/tty.h
+./diff-doc -rst -enable-lineno -function tty_kref_put ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_ldisc_ops ./include/linux/tty_ldisc.h
+./diff-doc -rst -enable-lineno -function tty_ldisc_ref_wait -function tty_ldisc_ref -function tty_ldisc_deref ./drivers/tty/tty_ldisc.c
+./diff-doc -rst -enable-lineno -function tty_name ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_operations ./include/linux/tty_driver.h
+./diff-doc -rst -enable-lineno -function tty_port_carrier_raised -function tty_port_raise_dtr_rts -function tty_port_lower_dtr_rts ./drivers/tty/tty_port.c
+./diff-doc -rst -enable-lineno -function tty_port ./include/linux/tty_port.h
+./diff-doc -rst -enable-lineno -function tty_port_init -function tty_port_destroy -function tty_port_get -function tty_port_put ./drivers/tty/tty_port.c
+./diff-doc -rst -enable-lineno -function tty_port_install -function tty_port_open -function tty_port_block_til_ready -function tty_port_close -function tty_port_close_start -function tty_port_close_end -function tty_port_hangup -function tty_port_shutdown ./drivers/tty/tty_port.c
+./diff-doc -rst -enable-lineno -function tty_port_link_device -function tty_port_register_device -function tty_port_register_device_attr ./drivers/tty/tty_port.c
+./diff-doc -rst -enable-lineno -function tty_port_operations ./include/linux/tty_port.h
+./diff-doc -rst -enable-lineno -function tty_port_tty_get -function tty_port_tty_set ./drivers/tty/tty_port.c
+./diff-doc -rst -enable-lineno -function tty_port_tty_hangup -function tty_port_tty_wakeup ./drivers/tty/tty_port.c
+./diff-doc -rst -enable-lineno -function tty_prepare_flip_string -function tty_flip_buffer_push -function tty_ldisc_receive_buf ./drivers/tty/tty_buffer.c
+./diff-doc -rst -enable-lineno -function tty_put_char ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_register_device -function tty_register_device_attr -function tty_unregister_device ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_register_driver -function tty_unregister_driver ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_register_ldisc -function tty_unregister_ldisc ./drivers/tty/tty_ldisc.c
+./diff-doc -rst -enable-lineno -function tty_release_struct -function tty_dev_name_to_number -function tty_get_icount ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function tty_set_ldisc -function tty_ldisc_flush ./drivers/tty/tty_ldisc.c
+./diff-doc -rst -enable-lineno -function tty_standard_install ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function 'TTY Struct Flags' ./include/linux/tty.h
+./diff-doc -rst -enable-lineno -function tty_struct ./include/linux/tty.h
+./diff-doc -rst -enable-lineno -function tty_wakeup ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -function 'TX A-MPDU aggregation' ./net/mac80211/agg-tx.c
+./diff-doc -rst -enable-lineno -function typec_altmode_driver -function typec_altmode_ops ./include/linux/usb/typec_altmode.h
+./diff-doc -rst -enable-lineno -function typec_altmode_enter -function typec_altmode_exit -function typec_altmode_attention -function typec_altmode_vdm -function typec_altmode_notify ./drivers/usb/typec/bus.c
+./diff-doc -rst -enable-lineno -function typec_altmode_get_plug -function typec_altmode_put_plug ./drivers/usb/typec/bus.c
+./diff-doc -rst -enable-lineno -function typec_altmode_register_driver -function typec_altmode_unregister_driver ./include/linux/usb/typec_altmode.h
+./diff-doc -rst -enable-lineno -function typec_altmode_update_active ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_cable_set_identity ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_match_altmode ./drivers/usb/typec/bus.c
+./diff-doc -rst -enable-lineno -function typec_partner_register_altmode ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_partner_set_identity ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_plug_register_altmode ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_port_register_altmode ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_register_cable -function typec_unregister_cable -function typec_register_plug -function typec_unregister_plug ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_register_partner -function typec_unregister_partner ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_register_port -function typec_unregister_port ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_set_data_role -function typec_set_pwr_role -function typec_set_vconn_role -function typec_set_pwr_opmode ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_set_orientation -function typec_set_mode ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function typec_switch_register -function typec_switch_unregister -function typec_mux_register -function typec_mux_unregister ./drivers/usb/typec/mux.c
+./diff-doc -rst -enable-lineno -function typec_unregister_altmode ./drivers/usb/typec/class.c
+./diff-doc -rst -enable-lineno -function UAPI ./include/uapi/linux/cxl_mem.h
+./diff-doc -rst -enable-lineno -function uart_ops ./include/linux/serial_core.h
+./diff-doc -rst -enable-lineno -function uart_port_tx_limited -function uart_port_tx ./include/linux/serial_core.h
+./diff-doc -rst -enable-lineno -function uart_update_timeout -function uart_get_baud_rate -function uart_get_divisor -function uart_match_port -function uart_write_wakeup -function uart_register_driver -function uart_unregister_driver -function uart_suspend_port -function uart_resume_port -function uart_add_one_port -function uart_remove_one_port -function uart_console_write -function uart_parse_earlycon -function uart_parse_options -function uart_set_options -function uart_get_lsr_info -function uart_handle_dcd_change -function uart_handle_cts_change -function uart_try_toggle_sysrq -function uart_get_console ./drivers/tty/serial/serial_core.c
+./diff-doc -rst -enable-lineno -function udelay -function ndelay ./include/asm-generic/delay.h
+./diff-doc -rst -enable-lineno -function unique_id ./drivers/gpu/drm/amd/pm/amdgpu_pm.c
+./diff-doc -rst -enable-lineno -function USAGE ./drivers/base/auxiliary.c
+./diff-doc -rst -enable-lineno -function usb_dfu_functional_descriptor ./include/uapi/linux/usb/functionfs.h
+./diff-doc -rst -enable-lineno -function 'Useful GFP flag combinations' ./include/linux/gfp_types.h
+./diff-doc -rst -enable-lineno -function 'User command execution' ./drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+./diff-doc -rst -enable-lineno -function 'Userspace I/O' ./drivers/target/target_core_user.c
+./diff-doc -rst -enable-lineno -function usleep_range -function usleep_range_idle ./include/linux/delay.h
+./diff-doc -rst -enable-lineno -function usleep_range_state ./kernel/time/sleep_timeout.c
+./diff-doc -rst -enable-lineno -function 'Utility functions' ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function 'V3D GEM BO management support' ./drivers/gpu/drm/v3d/v3d_bo.c
+./diff-doc -rst -enable-lineno -function 'Variable refresh properties' ./drivers/gpu/drm/drm_connector.c
+./diff-doc -rst -enable-lineno -function 'vblank handling' ./drivers/gpu/drm/drm_vblank.c
+./diff-doc -rst -enable-lineno -function 'vblank works' ./drivers/gpu/drm/drm_vblank_work.c
+./diff-doc -rst -enable-lineno -function 'VC4 CRTC module' ./drivers/gpu/drm/vc4/vc4_crtc.c
+./diff-doc -rst -enable-lineno -function 'VC4 DPI module' ./drivers/gpu/drm/vc4/vc4_dpi.c
+./diff-doc -rst -enable-lineno -function 'VC4 DSI0/DSI1 module' ./drivers/gpu/drm/vc4/vc4_dsi.c
+./diff-doc -rst -enable-lineno -function 'VC4 Falcon HDMI module' ./drivers/gpu/drm/vc4/vc4_hdmi.c
+./diff-doc -rst -enable-lineno -function 'VC4 GEM BO management support' ./drivers/gpu/drm/vc4/vc4_bo.c
+./diff-doc -rst -enable-lineno -function 'VC4 HVS module.' ./drivers/gpu/drm/vc4/vc4_hvs.c
+./diff-doc -rst -enable-lineno -function 'VC4 plane module' ./drivers/gpu/drm/vc4/vc4_plane.c
+./diff-doc -rst -enable-lineno -function 'VC4 SDTV module' ./drivers/gpu/drm/vc4/vc4_vec.c
+./diff-doc -rst -enable-lineno -function vdso_sgx_enter_enclave_t ./arch/x86/include/uapi/asm/sgx.h
+./diff-doc -rst -enable-lineno -function vgasr_priv ./drivers/gpu/vga/vga_switcheroo.c
+./diff-doc -rst -enable-lineno -function vga_switcheroo_client ./drivers/gpu/vga/vga_switcheroo.c
+./diff-doc -rst -enable-lineno -function vga_switcheroo_client_id ./include/linux/vga_switcheroo.h
+./diff-doc -rst -enable-lineno -function vga_switcheroo_client_ops ./include/linux/vga_switcheroo.h
+./diff-doc -rst -enable-lineno -function vga_switcheroo_handler_flags_t ./include/linux/vga_switcheroo.h
+./diff-doc -rst -enable-lineno -function vga_switcheroo_handler ./include/linux/vga_switcheroo.h
+./diff-doc -rst -enable-lineno -function vga_switcheroo_state ./include/linux/vga_switcheroo.h
+./diff-doc -rst -enable-lineno -function 'Video BIOS Table (VBT)' ./drivers/gpu/drm/i915/display/intel_bios.c
+./diff-doc -rst -enable-lineno -function 'Video Clocks' ./drivers/gpu/drm/meson/meson_vclk.c
+./diff-doc -rst -enable-lineno -function 'Video Encoder' ./drivers/gpu/drm/meson/meson_venc.c
+./diff-doc -rst -enable-lineno -function 'Video Input Unit' ./drivers/gpu/drm/meson/meson_viu.c
+./diff-doc -rst -enable-lineno -function 'Video Post Processing' ./drivers/gpu/drm/meson/meson_vpp.c
+./diff-doc -rst -enable-lineno -function 'Video Processing Unit' ./drivers/gpu/drm/meson/meson_drv.c
+./diff-doc -rst -enable-lineno -function virtio_device_ready ./include/linux/virtio_config.h
+./diff-doc -rst -enable-lineno -function virtqueue_add_inbuf ./drivers/virtio/virtio_ring.c
+./diff-doc -rst -enable-lineno -function virtqueue_add_outbuf ./drivers/virtio/virtio_ring.c
+./diff-doc -rst -enable-lineno -function virtqueue_add_sgs ./drivers/virtio/virtio_ring.c
+./diff-doc -rst -enable-lineno -function virtqueue_disable_cb ./drivers/virtio/virtio_ring.c
+./diff-doc -rst -enable-lineno -function virtqueue_enable_cb ./drivers/virtio/virtio_ring.c
+./diff-doc -rst -enable-lineno -function virtqueue_get_buf_ctx ./drivers/virtio/virtio_ring.c
+./diff-doc -rst -enable-lineno -function 'Virtual Memory Address' ./drivers/gpu/drm/i915/i915_vma_types.h
+./diff-doc -rst -enable-lineno -function 'vkms (Virtual Kernel Modesetting)' ./drivers/gpu/drm/vkms/vkms_drv.c
+./diff-doc -rst -enable-lineno -function 'vma offset manager' ./drivers/gpu/drm/drm_vma_manager.c
+./diff-doc -rst -enable-lineno -function vring_interrupt ./drivers/virtio/virtio_ring.c
+./diff-doc -rst -enable-lineno -function vtpmx_ioc_new_dev ./drivers/char/tpm/tpm_vtpm_proxy.c
+./diff-doc -rst -enable-lineno -function 'Watermark modifiers' ./include/linux/gfp_types.h
+./diff-doc -rst -enable-lineno -function wiphy_rfkill_set_hw_state -function wiphy_rfkill_start_polling -function wiphy_rfkill_stop_polling ./include/net/cfg80211.h
+./diff-doc -rst -enable-lineno -function 'WOPCM Layout' ./drivers/gpu/drm/i915/gt/intel_wopcm.c
+./diff-doc -rst -enable-lineno -function 'Write Once Protected Content Memory (WOPCM) Layout' ./drivers/gpu/drm/xe/xe_wopcm.c
+./diff-doc -rst -enable-lineno -function 'xdp redirect' ./net/core/filter.c
+./diff-doc -rst -enable-lineno -function 'Xe device coredump' ./drivers/gpu/drm/xe/xe_devcoredump.c
+./diff-doc -rst -enable-lineno -function 'Xe Power Management' ./drivers/gpu/drm/xe/xe_pm.c
+./diff-doc -rst -enable-lineno -function XSDFEC_ADD_LDPC_CODE_PARAMS ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_CLEAR_STATS ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_GET_CONFIG ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_GET_STATS ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_GET_STATUS ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_IS_ACTIVE ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_SET_BYPASS ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_SET_DEFAULT_CONFIG ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_SET_IRQ ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_SET_ORDER ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_SET_TURBO ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_START_DEV ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -function XSDFEC_STOP_DEV ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno ./include/linux/bio.h
+./diff-doc -rst -enable-lineno ./include/linux/blk-mq.h
+./diff-doc -rst -enable-lineno ./include/linux/bootconfig.h
+./diff-doc -rst -enable-lineno ./include/linux/buffer_head.h
+./diff-doc -rst -enable-lineno ./include/linux/connector.h
+./diff-doc -rst -enable-lineno ./include/linux/cpuhotplug.h
+./diff-doc -rst -enable-lineno ./include/linux/damon.h
+./diff-doc -rst -enable-lineno ./include/linux/devcoredump.h
+./diff-doc -rst -enable-lineno ./include/linux/devfreq-event.h
+./diff-doc -rst -enable-lineno ./include/linux/devfreq.h
+./diff-doc -rst -enable-lineno ./include/linux/edac.h
+./diff-doc -rst -enable-lineno ./include/linux/folio_queue.h
+./diff-doc -rst -enable-lineno ./include/linux/fprobe.h
+./diff-doc -rst -enable-lineno ./include/linux/fscache-cache.h
+./diff-doc -rst -enable-lineno ./include/linux/fscache.h
+./diff-doc -rst -enable-lineno ./include/linux/highmem.h
+./diff-doc -rst -enable-lineno ./include/linux/highmem-internal.h
+./diff-doc -rst -enable-lineno ./include/linux/host1x.h
+./diff-doc -rst -enable-lineno ./include/linux/hte.h
+./diff-doc -rst -enable-lineno ./include/linux/i2c-atr.h
+./diff-doc -rst -enable-lineno ./include/linux/i3c/device.h
+./diff-doc -rst -enable-lineno ./include/linux/i3c/master.h
+./diff-doc -rst -enable-lineno ./include/linux/iio/buffer.h
+./diff-doc -rst -enable-lineno ./include/linux/iio/iio.h
+./diff-doc -rst -enable-lineno ./include/linux/iio/trigger.h
+./diff-doc -rst -enable-lineno ./include/linux/interconnect-provider.h
+./diff-doc -rst -enable-lineno ./include/linux/int_log.h
+./diff-doc -rst -enable-lineno ./include/linux/irqdomain.h
+./diff-doc -rst -enable-lineno ./include/linux/kref.h
+./diff-doc -rst -enable-lineno ./include/linux/maple_tree.h
+./diff-doc -rst -enable-lineno ./include/linux/memblock.h
+./diff-doc -rst -enable-lineno ./include/linux/migrate.h
+./diff-doc -rst -enable-lineno ./include/linux/mm_inline.h
+./diff-doc -rst -enable-lineno ./include/linux/mmzone.h
+./diff-doc -rst -enable-lineno ./include/linux/netfs.h
+./diff-doc -rst -enable-lineno ./include/linux/padata.h
+./diff-doc -rst -enable-lineno ./include/linux/page-flags.h
+./diff-doc -rst -enable-lineno ./include/linux/page_ref.h
+./diff-doc -rst -enable-lineno ./include/linux/peci.h
+./diff-doc -rst -enable-lineno ./include/linux/pm.h
+./diff-doc -rst -enable-lineno ./include/linux/rculist_bl.h
+./diff-doc -rst -enable-lineno ./include/linux/rculist.h
+./diff-doc -rst -enable-lineno ./include/linux/rculist_nulls.h
+./diff-doc -rst -enable-lineno ./include/linux/rcupdate.h
+./diff-doc -rst -enable-lineno ./include/linux/rcupdate_trace.h
+./diff-doc -rst -enable-lineno ./include/linux/rcupdate_wait.h
+./diff-doc -rst -enable-lineno ./include/linux/rcuref.h
+./diff-doc -rst -enable-lineno ./include/linux/rcu_sync.h
+./diff-doc -rst -enable-lineno ./include/linux/rcutree.h
+./diff-doc -rst -enable-lineno ./include/linux/seqlock.h
+./diff-doc -rst -enable-lineno ./include/linux/srcu.h
+./diff-doc -rst -enable-lineno ./include/linux/surface_acpi_notify.h
+./diff-doc -rst -enable-lineno ./include/linux/surface_aggregator/controller.h
+./diff-doc -rst -enable-lineno ./include/linux/surface_aggregator/device.h
+./diff-doc -rst -enable-lineno ./include/linux/surface_aggregator/serial_hub.h
+./diff-doc -rst -enable-lineno ./include/linux/workqueue.h
+./diff-doc -rst -enable-lineno ./include/linux/xarray.h
+./diff-doc -rst -enable-lineno ./include/linux/xz.h
+./diff-doc -rst -enable-lineno ./include/media/cec-notifier.h
+./diff-doc -rst -enable-lineno ./include/media/cec-pin.h
+./diff-doc -rst -enable-lineno ./include/media/demux.h
+./diff-doc -rst -enable-lineno ./include/media/dmxdev.h
+./diff-doc -rst -enable-lineno ./include/media/dvb_ca_en50221.h
+./diff-doc -rst -enable-lineno ./include/media/dvb_demux.h
+./diff-doc -rst -enable-lineno ./include/media/dvbdev.h
+./diff-doc -rst -enable-lineno ./include/media/dvb_frontend.h
+./diff-doc -rst -enable-lineno ./include/media/dvb_net.h
+./diff-doc -rst -enable-lineno ./include/media/dvb_ringbuffer.h
+./diff-doc -rst -enable-lineno ./include/media/dvb_vb2.h
+./diff-doc -rst -enable-lineno ./include/media/media-dev-allocator.h
+./diff-doc -rst -enable-lineno ./include/media/media-device.h
+./diff-doc -rst -enable-lineno ./include/media/media-devnode.h
+./diff-doc -rst -enable-lineno ./include/media/media-entity.h
+./diff-doc -rst -enable-lineno ./include/media/media-request.h
+./diff-doc -rst -enable-lineno ./include/media/rc-core.h
+./diff-doc -rst -enable-lineno ./include/media/rc-map.h
+./diff-doc -rst -enable-lineno ./include/media/tuner.h
+./diff-doc -rst -enable-lineno ./include/media/tuner-types.h
+./diff-doc -rst -enable-lineno ./include/media/tveeprom.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-async.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-cci.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-common.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-ctrls.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-dev.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-device.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-dv-timings.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-event.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-fh.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-flash-led-class.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-fwnode.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-ioctl.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-mc.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-mediabus.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-mem2mem.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-rect.h
+./diff-doc -rst -enable-lineno ./include/media/v4l2-subdev.h
+./diff-doc -rst -enable-lineno ./include/media/videobuf2-core.h
+./diff-doc -rst -enable-lineno ./include/media/videobuf2-memops.h
+./diff-doc -rst -enable-lineno ./include/media/videobuf2-v4l2.h
+./diff-doc -rst -enable-lineno ./include/sound/compress_driver.h
+./diff-doc -rst -enable-lineno ./include/sound/control.h
+./diff-doc -rst -enable-lineno ./include/sound/core.h
+./diff-doc -rst -enable-lineno ./include/sound/dmaengine_pcm.h
+./diff-doc -rst -enable-lineno ./include/sound/jack.h
+./diff-doc -rst -enable-lineno ./include/sound/pcm.h
+./diff-doc -rst -enable-lineno ./include/sound/soc.h
+./diff-doc -rst -enable-lineno ./include/uapi/drm/i915_drm.h
+./diff-doc -rst -enable-lineno ./include/uapi/drm/nouveau_drm.h
+./diff-doc -rst -enable-lineno ./include/uapi/drm/panthor_drm.h
+./diff-doc -rst -enable-lineno ./include/uapi/drm/xe_drm.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/dma-buf.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/dpll.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/dvb/ca.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/dvb/dmx.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/dvb/frontend.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/dvb/net.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/iommufd.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/media/raspberrypi/pisp_be_config.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/netlink.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/rkisp1-config.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/surface_aggregator/cdev.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/surface_aggregator/dtx.h
+./diff-doc -rst -enable-lineno ./include/uapi/linux/vtpm_proxy.h
+./diff-doc -rst -enable-lineno ./include/uapi/sound/compress_offload.h
+./diff-doc -rst -enable-lineno ./include/uapi/sound/compress_params.h
+./diff-doc -rst -enable-lineno -internal ./arch/powerpc/sysdev/fsl_rio.c
+./diff-doc -rst -enable-lineno -internal ./arch/s390/include/asm/ccwdev.h
+./diff-doc -rst -enable-lineno -internal ./arch/s390/include/asm/ccwgroup.h
+./diff-doc -rst -enable-lineno -internal ./arch/s390/include/asm/cio.h
+./diff-doc -rst -enable-lineno -internal ./arch/s390/include/uapi/asm/cmb.h
+./diff-doc -rst -enable-lineno -internal ./arch/sh/boards/mach-dreamcast/rtc.c
+./diff-doc -rst -enable-lineno -internal ./arch/x86/include/asm/io.h
+./diff-doc -rst -enable-lineno -internal ./arch/x86/include/asm/uaccess.h
+./diff-doc -rst -enable-lineno -internal ./block/blk-core.c
+./diff-doc -rst -enable-lineno -internal ./block/blk-sysfs.c
+./diff-doc -rst -enable-lineno -internal ./block/genhd.c
+./diff-doc -rst -enable-lineno -internal ./drivers/ata/ata_piix.c
+./diff-doc -rst -enable-lineno -internal ./drivers/ata/libata-core.c
+./diff-doc -rst -enable-lineno -internal ./drivers/ata/libata-scsi.c
+./diff-doc -rst -enable-lineno -internal ./drivers/ata/sata_sil.c
+./diff-doc -rst -enable-lineno -internal ./drivers/base/init.c
+./diff-doc -rst -enable-lineno -internal ./drivers/base/node.c
+./diff-doc -rst -enable-lineno -internal ./drivers/cxl/cxl.h
+./diff-doc -rst -enable-lineno -internal ./drivers/cxl/cxlmem.h
+./diff-doc -rst -enable-lineno -internal ./drivers/cxl/pci.c
+./diff-doc -rst -enable-lineno -internal ./drivers/firmware/edd.c
+./diff-doc -rst -enable-lineno -internal ./drivers/firmware/efi/libstub/mem.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/display/dc/dc.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/display/dc/inc/hw/opp.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/arm/display/komeda/komeda_dev.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/arm/display/komeda/komeda_kms.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/arm/display/komeda/komeda_plane.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_atomic_plane.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_audio.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_bios.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_cdclk.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_dmc.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_dpll_mgr.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_dpll_mgr.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_drrs.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_dsb.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_fbc.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_fifo_underrun.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_frontbuffer.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_frontbuffer.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_hotplug.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_lpe_audio.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_psr.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/display/intel_vbt_defs.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/gem/i915_gem_tiling.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/gt/intel_gt_mcr.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/i915_cmd_parser.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/i915_gem_evict.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/i915_gem_gtt.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/i915_vgpu.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/intel_gvt.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/intel_runtime_pm.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/i915/intel_uncore.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_devcoredump.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_ggtt.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_ggtt_types.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_pcode.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_pm.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_rtp.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_rtp.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_rtp_types.h
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_tile.c
+./diff-doc -rst -enable-lineno -internal ./drivers/gpu/drm/xe/xe_wa.c
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/core/iwpm_util.h
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/iser/iscsi_iser.h
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/iser/iser_initiator.c
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/iser/iser_verbs.c
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/isert/ib_isert.c
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.h
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/opa_vnic/opa_vnic_internal.h
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/opa_vnic/opa_vnic_vema_iface.c
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/srpt/ib_srpt.c
+./diff-doc -rst -enable-lineno -internal ./drivers/infiniband/ulp/srpt/ib_srpt.h
+./diff-doc -rst -enable-lineno -internal ./drivers/media/test-drivers/vimc/vimc-streamer.h
+./diff-doc -rst -enable-lineno -internal ./drivers/mtd/nand/raw/nand_base.c
+./diff-doc -rst -enable-lineno -internal ./drivers/mtd/nand/raw/nand_bbt.c
+./diff-doc -rst -enable-lineno -internal ./drivers/net/can/ctucanfd/ctucanfd_base.c
+./diff-doc -rst -enable-lineno -internal ./drivers/net/can/ctucanfd/ctucanfd.h
+./diff-doc -rst -enable-lineno -internal ./drivers/net/can/ctucanfd/ctucanfd_pci.c
+./diff-doc -rst -enable-lineno -internal ./drivers/net/can/ctucanfd/ctucanfd_platform.c
+./diff-doc -rst -enable-lineno -internal ./drivers/net/phy/mdio_bus.c
+./diff-doc -rst -enable-lineno -internal ./drivers/net/phy/phy.c
+./diff-doc -rst -enable-lineno -internal ./drivers/net/phy/phy_device.c
+./diff-doc -rst -enable-lineno -internal ./drivers/net/phy/sfp-bus.c
+./diff-doc -rst -enable-lineno -internal ./drivers/parport/daisy.c
+./diff-doc -rst -enable-lineno -internal ./drivers/pci/pci-sysfs.c
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/bus.c
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/controller.c
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/controller.h
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/core.c
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/ssh_msgb.h
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/ssh_packet_layer.c
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/ssh_packet_layer.h
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/ssh_parser.c
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/ssh_parser.h
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/ssh_request_layer.c
+./diff-doc -rst -enable-lineno -internal ./drivers/platform/surface/aggregator/ssh_request_layer.h
+./diff-doc -rst -enable-lineno -internal ./drivers/pnp/core.c
+./diff-doc -rst -enable-lineno -internal ./drivers/pnp/driver.c
+./diff-doc -rst -enable-lineno -internal ./drivers/rapidio/rio-access.c
+./diff-doc -rst -enable-lineno -internal ./drivers/rapidio/rio.c
+./diff-doc -rst -enable-lineno -internal ./drivers/rapidio/rio-driver.c
+./diff-doc -rst -enable-lineno -internal ./drivers/rapidio/rio-scan.c
+./diff-doc -rst -enable-lineno -internal ./drivers/scsi/iscsi_tcp.c
+./diff-doc -rst -enable-lineno -internal ./drivers/scsi/scsi_netlink.c
+./diff-doc -rst -enable-lineno -internal ./drivers/slimbus/slimbus.h
+./diff-doc -rst -enable-lineno -internal ./drivers/staging/vme_user/vme.h
+./diff-doc -rst -enable-lineno -internal ./drivers/tty/n_tty.c
+./diff-doc -rst -enable-lineno -internal ./drivers/tty/tty_buffer.c
+./diff-doc -rst -enable-lineno -internal ./drivers/tty/tty_io.c
+./diff-doc -rst -enable-lineno -internal ./drivers/tty/tty_ldisc.c
+./diff-doc -rst -enable-lineno -internal ./drivers/tty/vt/selection.c
+./diff-doc -rst -enable-lineno -internal ./drivers/tty/vt/vt.c
+./diff-doc -rst -enable-lineno -internal ./drivers/usb/core/buffer.c
+./diff-doc -rst -enable-lineno -internal ./drivers/usb/dwc3/core.c
+./diff-doc -rst -enable-lineno -internal ./drivers/usb/dwc3/core.h
+./diff-doc -rst -enable-lineno -internal ./drivers/usb/dwc3/gadget.c
+./diff-doc -rst -enable-lineno -internal ./drivers/usb/dwc3/gadget.h
+./diff-doc -rst -enable-lineno -internal ./drivers/video/fbdev/core/modedb.c
+./diff-doc -rst -enable-lineno -internal ./drivers/w1/w1.c
+./diff-doc -rst -enable-lineno -internal ./drivers/w1/w1_internal.h
+./diff-doc -rst -enable-lineno -internal ./drivers/w1/w1_io.c
+./diff-doc -rst -enable-lineno -internal ./drivers/w1/w1_netlink.h
+./diff-doc -rst -enable-lineno -internal ./fs/eventpoll.c
+./diff-doc -rst -enable-lineno -internal ./fs/jbd2/recovery.c
+./diff-doc -rst -enable-lineno -internal ./fs/locks.c
+./diff-doc -rst -enable-lineno -internal ./fs/proc/base.c
+./diff-doc -rst -enable-lineno -internal ./fs/pstore/zone.c
+./diff-doc -rst -enable-lineno -internal ./include/asm-generic/bitops/instrumented-atomic.h
+./diff-doc -rst -enable-lineno -internal ./include/asm-generic/bitops/instrumented-lock.h
+./diff-doc -rst -enable-lineno -internal ./include/asm-generic/bitops/instrumented-non-atomic.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/display/drm_dp_dual_mode_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/display/drm_dp.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/display/drm_dp_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/display/drm_dp_mst_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/display/drm_dsc.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/display/drm_scdc_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_atomic.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_atomic_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_auth.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_bridge.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_client.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_color_mgmt.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_connector.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_crtc.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_damage_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_debugfs.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_device.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_drv.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_edid.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_eld.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_encoder.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_exec.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_fb_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_file.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_flip_work.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_fourcc.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_framebuffer.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_gem_atomic_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_gem_dma_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_gem.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_gem_shmem_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_gem_vram_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_gpuvm.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_ioctl.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_managed.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_mipi_dbi.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_mipi_dsi.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_mm.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_mode_config.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_mode_object.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_modeset_helper_vtables.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_modeset_lock.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_modes.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_panel.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_panic.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_plane.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_prime.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_print.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_privacy_screen_driver.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_privacy_screen_machine.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_property.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_rect.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_simple_kms_helper.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_syncobj.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_util.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_vblank.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_vblank_work.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_vma_manager.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/drm_writeback.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/gpu_scheduler.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/intel/i915_component.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/ttm/ttm_caching.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/ttm/ttm_device.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/ttm/ttm_placement.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/ttm/ttm_pool.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/ttm/ttm_resource.h
+./diff-doc -rst -enable-lineno -internal ./include/drm/ttm/ttm_tt.h
+./diff-doc -rst -enable-lineno -internal ./include/kunit/device.h
+./diff-doc -rst -enable-lineno -internal ./include/kunit/of.h
+./diff-doc -rst -enable-lineno -internal ./include/kunit/resource.h
+./diff-doc -rst -enable-lineno -internal ./include/kunit/static_stub.h
+./diff-doc -rst -enable-lineno -internal ./include/kunit/test.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/aperture.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/apple-gmux.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/atomic/atomic-arch-fallback.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/atomic/atomic-instrumented.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/atomic/atomic-long.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/backlight.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/bitmap.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/clk.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/completion.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/component.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/counter.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dcache.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/debugobjects.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dim.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dma-buf.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dma-fence-array.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dma-fence-chain.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dma-fence.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dma-fence-unwrap.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/dma-resv.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/energy_model.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/err.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/etherdevice.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/fortify-string.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/fs.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/gpio/driver.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/hdmi.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/hrtimer.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/hsi/hsi.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/i2c.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/input.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/input/matrix_keypad.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/input/mt.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/input/sparse-keymap.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/interrupt.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/iosys-map.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/irq.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/jbd2.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/jiffies.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/kfifo.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/kgdb.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/kthread.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/ktime.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/libps2.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/list.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/log2.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/math64.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/mm.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/mm_types.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/module.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/mtd/rawnand.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/mutex.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/netdevice.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/net.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/of_device.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/of_graph.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/of.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/of_platform.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/overflow.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/pagemap.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/parport.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/phy.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/phylink.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/pipe_fs_i.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/platform_device.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/pstore_blk.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/pstore_zone.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/pwm.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/pwrseq/provider.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/refcount.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/regulator/consumer.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/regulator/driver.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/regulator/machine.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/reset-controller.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/reset.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/rio_drv.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/rio.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/rslib.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/sched.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/sfp.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/skbuff.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/slab.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/slimbus.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/spi/spi.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/string.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/sync_file.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/uio_driver.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/usb/composite.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/usb/gadget.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/usb.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/vgaarb.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/w1.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/wait.h
+./diff-doc -rst -enable-lineno -internal ./include/linux/wmi.h
+./diff-doc -rst -enable-lineno -internal ./include/media/v4l2-jpeg.h
+./diff-doc -rst -enable-lineno -internal ./include/net/net_shaper.h
+./diff-doc -rst -enable-lineno -internal ./include/net/sock.h
+./diff-doc -rst -enable-lineno -internal ./include/scsi/scsi_device.h
+./diff-doc -rst -enable-lineno -internal ./include/trace/events/block.h
+./diff-doc -rst -enable-lineno -internal ./include/trace/events/irq.h
+./diff-doc -rst -enable-lineno -internal ./include/trace/events/signal.h
+./diff-doc -rst -enable-lineno -internal ./include/trace/events/workqueue.h
+./diff-doc -rst -enable-lineno -internal ./include/uapi/drm/drm.h
+./diff-doc -rst -enable-lineno -internal ./include/uapi/drm/drm_mode.h
+./diff-doc -rst -enable-lineno -internal ./include/uapi/linux/cxl_mem.h
+./diff-doc -rst -enable-lineno -internal ./include/uapi/linux/firewire-cdev.h
+./diff-doc -rst -enable-lineno -internal ./include/uapi/linux/gen_stats.h
+./diff-doc -rst -enable-lineno -internal ./include/uapi/linux/sync_file.h
+./diff-doc -rst -enable-lineno -internal ./include/uapi/misc/xilinx_sdfec.h
+./diff-doc -rst -enable-lineno -internal ./ipc/util.c
+./diff-doc -rst -enable-lineno -internal ./kernel/acct.c
+./diff-doc -rst -enable-lineno -internal ./kernel/auditfilter.c
+./diff-doc -rst -enable-lineno -internal ./kernel/auditsc.c
+./diff-doc -rst -enable-lineno -internal ./kernel/exit.c
+./diff-doc -rst -enable-lineno -internal ./kernel/futex/core.c
+./diff-doc -rst -enable-lineno -internal ./kernel/futex/futex.h
+./diff-doc -rst -enable-lineno -internal ./kernel/futex/pi.c
+./diff-doc -rst -enable-lineno -internal ./kernel/futex/requeue.c
+./diff-doc -rst -enable-lineno -internal ./kernel/futex/waitwake.c
+./diff-doc -rst -enable-lineno -internal ./kernel/irq/chip.c
+./diff-doc -rst -enable-lineno -internal ./kernel/relay.c
+./diff-doc -rst -enable-lineno -internal ./kernel/resource.c
+./diff-doc -rst -enable-lineno -internal ./kernel/sched/cpupri.c
+./diff-doc -rst -enable-lineno -internal ./kernel/sched/fair.c
+./diff-doc -rst -enable-lineno -internal ./kernel/signal.c
+./diff-doc -rst -enable-lineno -internal ./kernel/trace/blktrace.c
+./diff-doc -rst -enable-lineno -internal ./lib/bitmap.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/bcast.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/bearer.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/bearer.h
+./diff-doc -rst -enable-lineno -internal ./net/tipc/crypto.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/discover.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/link.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/msg.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/name_distr.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/name_distr.h
+./diff-doc -rst -enable-lineno -internal ./net/tipc/name_table.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/name_table.h
+./diff-doc -rst -enable-lineno -internal ./net/tipc/node.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/socket.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/subscr.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/subscr.h
+./diff-doc -rst -enable-lineno -internal ./net/tipc/topsrv.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/trace.c
+./diff-doc -rst -enable-lineno -internal ./net/tipc/udp_media.c
+./diff-doc -rst -enable-lineno -internal -nosymbol device_link_state ./include/linux/device.h
+./diff-doc -rst -enable-lineno -internal -nosymbol i915_perf_init -nosymbol i915_perf_fini -nosymbol i915_perf_register -nosymbol i915_perf_unregister -nosymbol i915_perf_open_ioctl -nosymbol i915_perf_release -nosymbol i915_perf_add_config_ioctl -nosymbol i915_perf_remove_config_ioctl -nosymbol read_properties_unlocked -nosymbol i915_perf_open_ioctl_locked -nosymbol i915_perf_destroy_locked -nosymbol i915_perf_read -nosymbol i915_perf_ioctl -nosymbol i915_perf_enable_locked -nosymbol i915_perf_disable_locked -nosymbol i915_perf_poll -nosymbol i915_perf_poll_locked -nosymbol i915_oa_stream_init -nosymbol i915_oa_read -nosymbol i915_oa_stream_enable -nosymbol i915_oa_stream_disable -nosymbol i915_oa_wait_unlocked -nosymbol i915_oa_poll_wait ./drivers/gpu/drm/i915/i915_perf.c
+./diff-doc -rst -enable-lineno -internal -nosymbol kstrtol -nosymbol kstrtoul ./include/linux/kernel.h
+./diff-doc -rst -enable-lineno -internal -nosymbol mpcc_blnd_cfg -nosymbol mpcc_alpha_blend_mode ./drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
+./diff-doc -rst -enable-lineno -internal -nosymbol pci_device_id ./include/linux/mod_devicetable.h
+./diff-doc -rst -enable-lineno -internal ./security/security.c
+./diff-doc -rst -enable-lineno ./kernel/irq/handle.c
+./diff-doc -rst -enable-lineno ./kernel/irq/irqdesc.c
+./diff-doc -rst -enable-lineno ./kernel/irq/manage.c
+./diff-doc -rst -enable-lineno ./kernel/padata.c
+./diff-doc -rst -enable-lineno ./kernel/rcu/srcutree.c
+./diff-doc -rst -enable-lineno ./kernel/rcu/sync.c
+./diff-doc -rst -enable-lineno ./kernel/rcu/tasks.h
+./diff-doc -rst -enable-lineno ./kernel/rcu/tree.c
+./diff-doc -rst -enable-lineno ./kernel/rcu/tree_exp.h
+./diff-doc -rst -enable-lineno ./kernel/rcu/tree_stall.h
+./diff-doc -rst -enable-lineno ./kernel/rcu/update.c
+./diff-doc -rst -enable-lineno ./kernel/trace/fprobe.c
+./diff-doc -rst -enable-lineno ./kernel/workqueue.c
+./diff-doc -rst -enable-lineno ./lib/bootconfig.c
+./diff-doc -rst -enable-lineno ./lib/crc32.c
+./diff-doc -rst -enable-lineno ./lib/errseq.c
+./diff-doc -rst -enable-lineno ./lib/maple_tree.c
+./diff-doc -rst -enable-lineno ./lib/xarray.c
+./diff-doc -rst -enable-lineno ./mm/balloon_compaction.c
+./diff-doc -rst -enable-lineno ./mm/damon/core.c
+./diff-doc -rst -enable-lineno ./mm/highmem.c
+./diff-doc -rst -enable-lineno ./mm/huge_memory.c
+./diff-doc -rst -enable-lineno ./mm/hugetlb.c
+./diff-doc -rst -enable-lineno ./mm/io-mapping.c
+./diff-doc -rst -enable-lineno ./mm/kmemleak.c
+./diff-doc -rst -enable-lineno ./mm/maccess.c
+./diff-doc -rst -enable-lineno ./mm/mapping_dirty_helpers.c
+./diff-doc -rst -enable-lineno ./mm/memcontrol.c
+./diff-doc -rst -enable-lineno ./mm/memory_hotplug.c
+./diff-doc -rst -enable-lineno ./mm/mempolicy.c
+./diff-doc -rst -enable-lineno ./mm/memremap.c
+./diff-doc -rst -enable-lineno ./mm/migrate.c
+./diff-doc -rst -enable-lineno ./mm/migrate_device.c
+./diff-doc -rst -enable-lineno ./mm/mmap.c
+./diff-doc -rst -enable-lineno ./mm/mmu_notifier.c
+./diff-doc -rst -enable-lineno ./mm/page_alloc.c
+./diff-doc -rst -enable-lineno ./mm/percpu.c
+./diff-doc -rst -enable-lineno ./mm/rmap.c
+./diff-doc -rst -enable-lineno ./mm/shmem.c
+./diff-doc -rst -enable-lineno ./mm/swap.c
+./diff-doc -rst -enable-lineno ./mm/vmscan.c
+./diff-doc -rst -enable-lineno ./mm/zpool.c
+./diff-doc -rst -enable-lineno ./mm/zsmalloc.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./drivers/cxl/core/cdat.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./drivers/cxl/core/hdm.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./drivers/cxl/core/memdev.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./drivers/cxl/core/pci.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./drivers/cxl/core/port.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./drivers/cxl/core/region.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./drivers/misc/mei/hdcp/mei_hdcp.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./include/linux/generic-radix-tree.h
+./diff-doc -rst -enable-lineno -no-doc-sections ./include/linux/idr.h
+./diff-doc -rst -enable-lineno -no-doc-sections ./lib/idr.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./mm/memblock.c
+./diff-doc -rst -enable-lineno -no-doc-sections ./security/landlock/fs.h
+./diff-doc -rst -enable-lineno -no-doc-sections ./security/landlock/object.h
+./diff-doc -rst -enable-lineno -no-doc-sections ./security/landlock/ruleset.h
+./diff-doc -rst -enable-lineno -nosymbol bus_type -nosymbol bus_notifier_event ./include/linux/device/bus.h
+./diff-doc -rst -enable-lineno -nosymbol class ./include/linux/device/class.h
+./diff-doc -rst -enable-lineno -nosymbol probe_type -nosymbol device_driver ./include/linux/device/driver.h
+./diff-doc -rst -enable-lineno ./sound/core/compress_offload.c
+./diff-doc -rst -enable-lineno ./sound/core/control.c
+./diff-doc -rst -enable-lineno ./sound/core/device.c
+./diff-doc -rst -enable-lineno ./sound/core/hwdep.c
+./diff-doc -rst -enable-lineno ./sound/core/info.c
+./diff-doc -rst -enable-lineno ./sound/core/init.c
+./diff-doc -rst -enable-lineno ./sound/core/isadma.c
+./diff-doc -rst -enable-lineno ./sound/core/jack.c
+./diff-doc -rst -enable-lineno ./sound/core/memalloc.c
+./diff-doc -rst -enable-lineno ./sound/core/memory.c
+./diff-doc -rst -enable-lineno ./sound/core/pcm.c
+./diff-doc -rst -enable-lineno ./sound/core/pcm_dmaengine.c
+./diff-doc -rst -enable-lineno ./sound/core/pcm_lib.c
+./diff-doc -rst -enable-lineno ./sound/core/pcm_memory.c
+./diff-doc -rst -enable-lineno ./sound/core/pcm_misc.c
+./diff-doc -rst -enable-lineno ./sound/core/pcm_native.c
+./diff-doc -rst -enable-lineno ./sound/core/rawmidi.c
+./diff-doc -rst -enable-lineno ./sound/core/sound.c
+./diff-doc -rst -enable-lineno ./sound/core/vmaster.c
+./diff-doc -rst -enable-lineno ./sound/drivers/mpu401/mpu401_uart.c
+./diff-doc -rst -enable-lineno ./sound/pci/ac97/ac97_codec.c
+./diff-doc -rst -enable-lineno ./sound/pci/ac97/ac97_pcm.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-component.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-compress.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-core.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-dapm.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-devres.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-generic-dmaengine-pcm.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-jack.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-ops.c
+./diff-doc -rst -enable-lineno ./sound/soc/soc-pcm.c
+./diff-doc -rst -enable-lineno ./sound/sound_core.c
diff --git a/diff-doc b/diff-doc
new file mode 100755
index 000000000000..3cce8bb25c04
--- /dev/null
+++ b/diff-doc
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+RST=
+MAN=
+ARGS=
+
+args=()
+
+while [ "$1" != "" ]; do
+        case $1 in
+        --rst|-rst)
+                RST=1
+                ;;
+	# For now, ignore line numbers
+        --enable-lineno|-enable-lineno)
+                ;;
+        --man|-man)
+                MAN=1
+                ;;
+        *)
+		args+=(${1@Q})
+                ;;
+        esac
+        shift
+done
+
+if [ -z "$args" ]; then
+	echo "Need a filename"
+	exit 1
+fi
+
+if [ -z $RST ]; then
+	if [ -z $MAN ]; then
+		RST=1
+	fi
+fi
+
+echo >org
+echo >new
+
+echo scripts/kernel-doc ${args[@]}
+
+if [ ! -z $MAN ]; then
+	eval ./scripts/kernel-doc.pl -man ${args[@]} >>org
+fi
+
+if [ ! -z $RST ]; then
+	eval ./scripts/kernel-doc.pl -rst ${args[@]} >>org
+fi
+
+if [ ! -z $MAN ]; then
+	eval ./scripts/kernel-doc.py -man ${args[@]} >>new
+fi
+
+if [ ! -z $RST ]; then
+	eval ./scripts/kernel-doc.py -rst ${args[@]} >>new
+fi
+
+diff -u -B org new





Thanks,
Mauro

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 00/39] Implement kernel-doc in Python
  2025-02-25  7:54   ` Mauro Carvalho Chehab
@ 2025-02-25 14:33     ` Jonathan Corbet
  0 siblings, 0 replies; 10+ messages in thread
From: Jonathan Corbet @ 2025-02-25 14:33 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Linux Doc Mailing List, linux-kernel, Arnd Bergmann, Bingbu Cao,
	Greg Kroah-Hartman, Sakari Ailus, Takashi Sakamoto, Tianshu Qiu,
	linux-arch, linux-hardening, linux-media, linux-staging,
	linux1394-devel

Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:

> There's no need to rush things there, provided that people refrain
> touching the Perl version of kernel-doc. So yeah, postponing it to
> the next merge window makes sense to me. Perhaps we should announce
> somewhere that we're in the process of doing such replacement, asking
> people to wait for 6.15-rc before sending any changes to kernel-doc.

I have no problem with sending an announcement ... but I wouldn't worry
about a flood of changes to the Perl script creating more work.  There's
not a lot of people willing to dive into that thing in the first
place...

Thanks,

jon

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser
  2025-02-25  7:38     ` Mauro Carvalho Chehab
@ 2025-02-25 20:10       ` Jonathan Corbet
  2025-02-26  6:56         ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 10+ messages in thread
From: Jonathan Corbet @ 2025-02-25 20:10 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Linux Doc Mailing List, linux-hardening, linux-kernel

Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:

> Em Mon, 24 Feb 2025 16:38:58 -0700
> Jonathan Corbet <corbet@lwn.net> escreveu:
>
>> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
>> 
>> 
>> I also think you should give consideration to preserving the other
>> copyright notices in the Perl version.  A language translation doesn't
>> remove existing copyrights...who knows how much creativity went into
>> some of those regexes?
>
> Makes sense, but the copyrights at kernel-doc.pl:
>
> 	## Copyright (c) 1998 Michael Zucchi, All Rights Reserved        ##
> 	## Copyright (C) 2000, 1  Tim Waugh <twaugh@redhat.com>          ##
> 	## Copyright (C) 2001  Simon Huggins                             ##
> 	## Copyright (C) 2005-2012  Randy Dunlap                         ##
> 	## Copyright (C) 2012  Dan Luedtke                               ##
> 	##                                                               ##
> 	## #define enhancements by Armin Kuster <akuster@mvista.com>     ##
> 	## Copyright (c) 2000 MontaVista Software, Inc.                  ##
> 	#
> 	# Copyright (C) 2022 Tomasz Warniełło (POD)
>
> Also doesn't preserve all copyrights from people that worked hard to
> maintain it all over those years.

Agreed ... and I'm not sure what we can do about that.  But *removing*
existing copyright notices is a bit of a different story; that is
generally considered to be fairly bad form.

I don't have a problem with adding a longer credits area, I guess, if we
want to do that (though it's not normal for other source files).  But
I'm not sure we need to.

Thanks,

jon

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser
  2025-02-25 20:10       ` Jonathan Corbet
@ 2025-02-26  6:56         ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2025-02-26  6:56 UTC (permalink / raw)
  To: Jonathan Corbet; +Cc: Linux Doc Mailing List, linux-hardening, linux-kernel

Em Tue, 25 Feb 2025 13:10:19 -0700
Jonathan Corbet <corbet@lwn.net> escreveu:

> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
> 
> > Em Mon, 24 Feb 2025 16:38:58 -0700
> > Jonathan Corbet <corbet@lwn.net> escreveu:
> >  
> >> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:
> >> 
> >> 
> >> I also think you should give consideration to preserving the other
> >> copyright notices in the Perl version.  A language translation doesn't
> >> remove existing copyrights...who knows how much creativity went into
> >> some of those regexes?  
> >
> > Makes sense, but the copyrights at kernel-doc.pl:
> >
> > 	## Copyright (c) 1998 Michael Zucchi, All Rights Reserved        ##
> > 	## Copyright (C) 2000, 1  Tim Waugh <twaugh@redhat.com>          ##
> > 	## Copyright (C) 2001  Simon Huggins                             ##
> > 	## Copyright (C) 2005-2012  Randy Dunlap                         ##
> > 	## Copyright (C) 2012  Dan Luedtke                               ##
> > 	##                                                               ##
> > 	## #define enhancements by Armin Kuster <akuster@mvista.com>     ##
> > 	## Copyright (c) 2000 MontaVista Software, Inc.                  ##
> > 	#
> > 	# Copyright (C) 2022 Tomasz Warniełło (POD)
> >
> > Also doesn't preserve all copyrights from people that worked hard to
> > maintain it all over those years.  
> 
> Agreed ... and I'm not sure what we can do about that.  But *removing*
> existing copyright notices is a bit of a different story; that is
> generally considered to be fairly bad form.

I'm with you: we shall not remove copyrights.

Yet, copyrights were originally developed for artwork (paintings, music
and such). So I guess we can borrow an analogy from there to try 
understanding what a conversion like that would mean. At least for me,
it sounds like having two paintings of the same image: they both
reflect the same picture, but they have different brush strokes. They
also may have different painting styles that may look similar but are
different.

Using such analogy, let's say someone draws a new painting while looking
at a famous painting like Monalisa. Surely the painter should give credits
to Leonardo Da Vinci  for his brilliant artwork, but, on the other hand,
he cannot and should not sign that his painting was authored by Leonardo
Da Vinci. 

This is the same here: the Python code, while derivated from the
Perl version, doesn't have the same coding style ("brush strokes") nor
we can say that it were authored by the original writers. IMO, all we
can do is to give credits for the original authors and preserve GPLv2
license, which explicitly allows derivative work. 

That's why I think we could give such credits with some preamble
note to distinguish it from the Python copyrights. 

It could be something like:

	# Converted from the kernel-doc script originally written in Perl
	# under GPLv2, copyrighted since 1998 by the following authors:

Followed by a list of the contributors, or it could be mentioning the
original script and how people could browse to see the developers
who wrote/modified kernel-doc.

Feel free to suggest a better text if you think the above won't fit.

> I don't have a problem with adding a longer credits area, I guess, if we
> want to do that (though it's not normal for other source files).  But
> I'm not sure we need to.

I have the same doubts, but on the other hand, looking at the
copyrights written on kernel-doc.pl since 2005 (git version), I can see 
records for just 3 persons:

- Dan Luedtke: a single patch adding html5 support
  1b40c1944db4 ("scripts/kernel-doc: added support for html5")

  We didn't port html5 to Python - and html output was already removed
  from kernel-doc a long time ago. Maybe there might have some small
  pieces of his original work that could have been ported. I dunno.

- Tomasz Warniełło: basically, changes at the help/man part of the script

  2b306ecaf57b scripts: kernel-doc: Refresh the copyright lines
  258092a89085 scripts: kernel-doc: Drop obsolete comments
  252b47da9fd9 scripts: kernel-doc: Replace the usage function
  834cf6b9039e scripts: kernel-doc: Translate the "Other parameters" subsection of OPTIONS
  c15de5a19a28 scripts: kernel-doc: Translate the "Output selection modifiers" subsection of OPTIONS
  9c77f108f43a scripts: kernel-doc: Translate the "Output selection" subsection of OPTIONS
  dd803b04b0a0 scripts: kernel-doc: Translate the "Output format selection modifier" subsection of OPTIONS
  2875f7870821 scripts: kernel-doc: Translate the "Output format selection" subsection of OPTIONS
  f1583922bf93 scripts: kernel-doc: Translate the DESCRIPTION section
  43caf1a6823d scripts: kernel-doc: Relink argument parsing error handling to pod2usage
  a5cdaea525c3 scripts: kernel-doc: Add the basic POD sections

  Parts of the text used at the POD sections were preserved at the 
  Python version. I didn't check if the texts we're using were
  authored by him.

- Randy Dunlap: 64 patches fixing things and improving the script

  I'm pretty sure I ported lots of stuff from Randy to the Python
  version.

At least for me, while it sounds right to give credits for the above
3 developers and also for Michael, Simon and Armin, who collaborated
and authored it before git time, it doesn't sound right to not mention 
any but one of the several developers that have been maintaining it 
since 2005. Now, the list, ordered by the number of patches is:

     65 Randy Dunlap
     57 Mauro Carvalho Chehab
     32 Jani Nikula
     20 Jonathan Corbet
     11 Tomasz Warniełło
     11 Johannes Berg
      7 Kees Cook
      6 Vegard Nossum
      6 Aditya Srivastava
      5 Paolo Bonzini
      5 Martin Waitz
      4 Matthew Wilcox
      4 Daniel Vetter
      3 Mike Rapoport
      3 Danilo Cesar Lemes de Paula
      3 Daniel Santos
      3 Conchúr Navid
      3 Borislav Petkov
      3 Ben Hutchings
      3 Andy Shevchenko
      3 André Almeida
      3 Akira Yokosawa
      2 Yujie Liu
      2 Yacine Belkadi
      2 Sakari Ailus
      2 Pavel Pisa
      2 Pavan Kumar Linga
      2 Markus Heiser
      2 Jonathan Neuschäfer
      2 Jason Baron
      2 Jakub Kicinski
      2 Ilya Dryomov
      1 Will Deacon
      1 valdis.kletnieks@vt.edu
      1 Utkarsh Tripathi
      1 Silvio Fricke
      1 Rolf Eike Beer
      1 Rich Walker
      1 Richard Kennedy
      1 Randy.Dunlap
      1 Pierre-Louis Bossart
      1 Peter Maydell
      1 Nishanth Menon
      1 Niklas Söderlund
      1 Michal Wajdeczko
      1 Masahiro Yamada
      1 Mark Rutland
      1 Lucas De Marchi
      1 Linus Torvalds
      1 Levin, Alexander (Sasha Levin)
      1 Laurent Pinchart
      1 Kamil Rytarowski
      1 Jonathan Cameron
      1 Johannes Weiner
      1 Jérémy Bobbio
      1 Jason Gunthorpe
      1 Horia Geanta
      1 Harvey Harrison
      1 Greg Kroah-Hartman
      1 Gabriel Krisman Bertazi
      1 Donald Hunter
      1 Dan Luedtke
      1 Coco Li
      1 Chen-Yu Tsai
      1 Bart Van Assche
      1 Anna-Maria Behnsen
      1 Alexander Lobakin
      1 Alexander A. Klimov

If you think the list is too long, one option would be to draw a line
(for instance picking developers with more than 2 patches or something
like that) and add an "and others" to not forget about the others.

We might analyze each individual contribution to see what was relevant
or not, ignoring for instance single-line authors that did changes like
this one:

	diff --git a/scripts/kernel-doc b/scripts/kernel-doc
	index 28b761567815..f565536a2bef 100755
	--- a/scripts/kernel-doc
	+++ b/scripts/kernel-doc
	@@ -2082 +2081,0 @@ sub dump_function($$) {
	-    $prototype =~ s/__devinit +//;

which almost certainly doesn't affect copyrights, which doesn't add any new
code to it, while preserving credits for single-patch authors that did 
regex changes like this one:

	diff --git a/scripts/kernel-doc b/scripts/kernel-doc
	index 3982d47048a7..724528f4b7d6 100755
	--- a/scripts/kernel-doc
	+++ b/scripts/kernel-doc
	@@ -1086 +1086 @@ sub dump_struct($$) {
	-    if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|____cacheline_aligned_in_smp|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) {
	+    if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|____cacheline_aligned_in_smp|____cacheline_aligned|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) {
	@@ -1101,0 +1102 @@ sub dump_struct($$) {
	+       $members =~ s/\s*____cacheline_aligned/ /gos;


but for me it sounds a waste of our time to analyze all patches, and
we may risk of get things wrong, so I prefer to place the complete list.

Thanks,
Mauro

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2025-02-26  6:56 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-24  9:08 [PATCH v2 00/39] Implement kernel-doc in Python Mauro Carvalho Chehab
2025-02-24  9:08 ` [PATCH v2 09/39] scripts/kernel-doc.py: add a Python parser Mauro Carvalho Chehab
2025-02-24 23:38   ` Jonathan Corbet
2025-02-25  7:38     ` Mauro Carvalho Chehab
2025-02-25 20:10       ` Jonathan Corbet
2025-02-26  6:56         ` Mauro Carvalho Chehab
2025-02-24  9:08 ` [PATCH v2 14/39] scripts/kernel-doc.py: move KernelDoc class to a separate file Mauro Carvalho Chehab
2025-02-24 23:49 ` [PATCH v2 00/39] Implement kernel-doc in Python Jonathan Corbet
2025-02-25  7:54   ` Mauro Carvalho Chehab
2025-02-25 14:33     ` Jonathan Corbet

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox