]> git.proxmox.com Git - mirror_qemu.git/blobdiff - scripts/kernel-doc
hw/arm/aspeed: Init CPU defaults in a common helper
[mirror_qemu.git] / scripts / kernel-doc
index 40ad782e3420f34f78e5bf5af53d8e7a5aca4bf9..240923d509a6fcdf2a53b7e458739867174f637b 100755 (executable)
@@ -56,6 +56,13 @@ Output format selection (mutually exclusive):
   -rst                 Output reStructuredText format.
   -none                        Do not output documentation, only warnings.
 
+Output format selection modifier (affects only ReST output):
+
+  -sphinx-version      Use the ReST C domain dialect compatible with an
+                       specific Sphinx Version.
+                       If not specified, kernel-doc will auto-detect using
+                       the sphinx-build version found on PATH.
+
 Output selection (mutually exclusive):
   -export              Only output documentation for symbols that have been
                        exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL()
@@ -66,13 +73,10 @@ Output selection (mutually exclusive):
   -function NAME       Only output documentation for the given function(s)
                        or DOC: section title(s). All other functions and DOC:
                        sections are ignored. May be specified multiple times.
-  -nofunction NAME     Do NOT output documentation for the given function(s);
-                       only output documentation for the other functions and
-                       DOC: sections. May be specified multiple times.
+  -nosymbol NAME       Exclude the specified symbols from the output
+                       documentation. May be specified multiple times.
 
 Output selection modifiers:
-  -sphinx-version VER   Generate rST syntax for the specified Sphinx version.
-                        Only works with reStructuredTextFormat.
   -no-doc-sections     Do not output DOC: sections.
   -enable-lineno        Enable output of #define LINENO lines. Only works with
                         reStructuredText format.
@@ -83,6 +87,7 @@ Output selection modifiers:
 Other parameters:
   -v                   Verbose output, more warnings and other information.
   -h                   Print this help.
+  -Werror              Treat warnings as errors.
 
 EOF
     print $message;
@@ -215,7 +220,9 @@ my $type_constant = '\b``([^\`]+)``\b';
 my $type_constant2 = '\%([-_\w]+)';
 my $type_func = '(\w+)\(\)';
 my $type_param = '\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)';
+my $type_param_ref = '([\!]?)\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)';
 my $type_fp_param = '\@(\w+)\(\)';  # Special RST handling for func ptr params
+my $type_fp_param2 = '\@(\w+->\S+)\(\)';  # Special RST handling for structs with func ptr params
 my $type_env = '(\$\w+)';
 my $type_enum = '#(enum\s*([_\w]+))';
 my $type_struct = '#(struct\s*([_\w]+))';
@@ -238,6 +245,7 @@ my @highlights_man = (
                       [$type_typedef, "\\\\fI\$1\\\\fP"],
                       [$type_union, "\\\\fI\$1\\\\fP"],
                       [$type_param, "\\\\fI\$1\\\\fP"],
+                      [$type_param_ref, "\\\\fI\$1\$2\\\\fP"],
                       [$type_member, "\\\\fI\$1\$2\$3\\\\fP"],
                       [$type_fallback, "\\\\fI\$1\\\\fP"]
                     );
@@ -251,6 +259,7 @@ my @highlights_rst = (
                        [$type_member_func, "\\:c\\:type\\:`\$1\$2\$3\\\\(\\\\) <\$1>`"],
                        [$type_member, "\\:c\\:type\\:`\$1\$2\$3 <\$1>`"],
                       [$type_fp_param, "**\$1\\\\(\\\\)**"],
+                      [$type_fp_param2, "**\$1\\\\(\\\\)**"],
                        [$type_func, "\$1()"],
                        [$type_enum, "\\:c\\:type\\:`\$1 <\$2>`"],
                        [$type_struct, "\\:c\\:type\\:`\$1 <\$2>`"],
@@ -258,7 +267,7 @@ my @highlights_rst = (
                        [$type_union, "\\:c\\:type\\:`\$1 <\$2>`"],
                        # in rst this can refer to any type
                        [$type_fallback, "\\:c\\:type\\:`\$1`"],
-                       [$type_param, "**\$1**"]
+                       [$type_param_ref, "**\$1\$2**"]
                      );
 my $blankline_rst = "\n";
 
@@ -268,9 +277,12 @@ if ($#ARGV == -1) {
 }
 
 my $kernelversion;
+my ($sphinx_major, $sphinx_minor, $sphinx_patch);
+
 my $dohighlight = "";
 
 my $verbose = 0;
+my $Werror = 0;
 my $output_mode = "rst";
 my $output_preformatted = 0;
 my $no_doc_sections = 0;
@@ -282,13 +294,11 @@ my $modulename = "Kernel API";
 use constant {
     OUTPUT_ALL          => 0, # output all symbols and doc sections
     OUTPUT_INCLUDE      => 1, # output only specified symbols
-    OUTPUT_EXCLUDE      => 2, # output everything except specified symbols
-    OUTPUT_EXPORTED     => 3, # output exported symbols
-    OUTPUT_INTERNAL     => 4, # output non-exported symbols
+    OUTPUT_EXPORTED     => 2, # output exported symbols
+    OUTPUT_INTERNAL     => 3, # output non-exported symbols
 };
 my $output_selection = OUTPUT_ALL;
 my $show_not_found = 0;        # No longer used
-my $sphinx_version = "0.0"; # if not specified, assume old
 
 my @export_file_list;
 
@@ -310,6 +320,7 @@ my $man_date = ('January', 'February', 'March', 'April', 'May', 'June',
 # CAVEAT EMPTOR!  Some of the others I localised may not want to be, which
 # could cause "use of undefined value" or other bugs.
 my ($function, %function_table, %parametertypes, $declaration_purpose);
+my %nosymbol_table = ();
 my $declaration_start_line;
 my ($type, $declaration_name, $return_type);
 my ($newsection, $newcontents, $prototype, $brcount, %source_map);
@@ -318,9 +329,21 @@ if (defined($ENV{'KBUILD_VERBOSE'})) {
        $verbose = "$ENV{'KBUILD_VERBOSE'}";
 }
 
+if (defined($ENV{'KDOC_WERROR'})) {
+       $Werror = "$ENV{'KDOC_WERROR'}";
+}
+
+if (defined($ENV{'KCFLAGS'})) {
+       my $kcflags = "$ENV{'KCFLAGS'}";
+
+       if ($kcflags =~ /Werror/) {
+               $Werror = 1;
+       }
+}
+
 # Generated docbook code is inserted in a template at a point where
 # docbook v3.1 requires a non-zero sequence of RefEntry's; see:
-# http://www.oasis-open.org/docbook/documentation/reference/html/refentry.html
+# https://www.oasis-open.org/docbook/documentation/reference/html/refentry.html
 # We keep track of number of generated entries and generate a dummy
 # if needs be to ensure the expanded template can be postprocessed
 # into html.
@@ -330,13 +353,14 @@ my $lineprefix="";
 
 # Parser states
 use constant {
-    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_PROTO         => 4, # scanning prototype
-    STATE_DOCBLOCK      => 5, # documentation block
-    STATE_INLINE        => 6, # gathering documentation outside main block
+    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
 };
 my $state;
 my $in_doc_sect;
@@ -416,10 +440,9 @@ while ($ARGV[0] =~ m/^--?(.*)/) {
        $output_selection = OUTPUT_INCLUDE;
        $function = shift @ARGV;
        $function_table{$function} = 1;
-    } elsif ($cmd eq "nofunction") { # output all except specific functions
-       $output_selection = OUTPUT_EXCLUDE;
-       $function = shift @ARGV;
-       $function_table{$function} = 1;
+    } elsif ($cmd eq "nosymbol") { # Exclude specific symbols
+       my $symbol = shift @ARGV;
+       $nosymbol_table{$symbol} = 1;
     } elsif ($cmd eq "export") { # only exported symbols
        $output_selection = OUTPUT_EXPORTED;
        %function_table = ();
@@ -431,6 +454,8 @@ while ($ARGV[0] =~ m/^--?(.*)/) {
        push(@export_file_list, $file);
     } elsif ($cmd eq "v") {
        $verbose = 1;
+    } elsif ($cmd eq "Werror") {
+       $Werror = 1;
     } elsif (($cmd eq "h") || ($cmd eq "help")) {
        usage();
     } elsif ($cmd eq 'no-doc-sections') {
@@ -439,8 +464,23 @@ while ($ARGV[0] =~ m/^--?(.*)/) {
            $enable_lineno = 1;
     } elsif ($cmd eq 'show-not-found') {
        $show_not_found = 1;  # A no-op but don't fail
-    } elsif ($cmd eq 'sphinx-version') {
-        $sphinx_version = shift @ARGV;
+    } elsif ($cmd eq "sphinx-version") {
+       my $ver_string = shift @ARGV;
+       if ($ver_string =~ m/^(\d+)(\.\d+)?(\.\d+)?/) {
+           $sphinx_major = $1;
+           if (defined($2)) {
+               $sphinx_minor = substr($2,1);
+           } else {
+               $sphinx_minor = 0;
+           }
+           if (defined($3)) {
+               $sphinx_patch = substr($3,1)
+           } else {
+               $sphinx_patch = 0;
+           }
+       } else {
+           die "Sphinx version should either major.minor or major.minor.patch format\n";
+       }
     } else {
        # Unknown argument
         usage();
@@ -449,6 +489,51 @@ while ($ARGV[0] =~ m/^--?(.*)/) {
 
 # continue execution near EOF;
 
+# The C domain dialect changed on Sphinx 3. So, we need to check the
+# version in order to produce the right tags.
+sub findprog($)
+{
+       foreach(split(/:/, $ENV{PATH})) {
+               return "$_/$_[0]" if(-x "$_/$_[0]");
+       }
+}
+
+sub get_sphinx_version()
+{
+       my $ver;
+
+       my $cmd = "sphinx-build";
+       if (!findprog($cmd)) {
+               my $cmd = "sphinx-build3";
+               if (!findprog($cmd)) {
+                       $sphinx_major = 1;
+                       $sphinx_minor = 2;
+                       $sphinx_patch = 0;
+                       printf STDERR "Warning: Sphinx version not found. Using default (Sphinx version %d.%d.%d)\n",
+                              $sphinx_major, $sphinx_minor, $sphinx_patch;
+                       return;
+               }
+       }
+
+       open IN, "$cmd --version 2>&1 |";
+       while (<IN>) {
+               if (m/^\s*sphinx-build\s+([\d]+)\.([\d\.]+)(\+\/[\da-f]+)?$/) {
+                       $sphinx_major = $1;
+                       $sphinx_minor = $2;
+                       $sphinx_patch = $3;
+                       last;
+               }
+               # Sphinx 1.2.x uses a different format
+               if (m/^\s*Sphinx.*\s+([\d]+)\.([\d\.]+)$/) {
+                       $sphinx_major = $1;
+                       $sphinx_minor = $2;
+                       $sphinx_patch = $3;
+                       last;
+               }
+       }
+       close IN;
+}
+
 # get kernel version from env
 sub get_kernel_version() {
     my $version = 'unknown kernel version';
@@ -515,11 +600,11 @@ sub dump_doc_section {
         return;
     }
 
+    return if (defined($nosymbol_table{$name}));
+
     if (($output_selection == OUTPUT_ALL) ||
-       ($output_selection == OUTPUT_INCLUDE &&
-        defined($function_table{$name})) ||
-       ($output_selection == OUTPUT_EXCLUDE &&
-        !defined($function_table{$name})))
+       (($output_selection == OUTPUT_INCLUDE) &&
+        defined($function_table{$name})))
     {
        dump_section($file, $name, $contents);
        output_blockhead({'sectionlist' => \@sectionlist,
@@ -602,10 +687,10 @@ sub output_function_man(%) {
        $type = $args{'parametertypes'}{$parameter};
        if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
            # pointer-to-function
-           print ".BI \"" . $parenth . $1 . "\" " . $parameter . " \") (" . $2 . ")" . $post . "\"\n";
+           print ".BI \"" . $parenth . $1 . "\" " . " \") (" . $2 . ")" . $post . "\"\n";
        } else {
            $type =~ s/([^\*])$/$1 /;
-           print ".BI \"" . $parenth . $type . "\" " . $parameter . " \"" . $post . "\"\n";
+           print ".BI \"" . $parenth . $type . "\" " . " \"" . $post . "\"\n";
        }
        $count++;
        $parenth = "";
@@ -745,6 +830,8 @@ sub output_blockhead_rst(%) {
     my ($parameter, $section);
 
     foreach $section (@{$args{'sectionlist'}}) {
+       next if (defined($nosymbol_table{$section}));
+
        if ($output_selection != OUTPUT_INCLUDE) {
            print "**$section**\n\n";
        }
@@ -830,16 +917,37 @@ sub output_function_rst(%) {
     my ($parameter, $section);
     my $oldprefix = $lineprefix;
     my $start = "";
-
-    if ($args{'typedef'}) {
-       print ".. c:type:: ". $args{'function'} . "\n\n";
-       print_lineno($declaration_start_line);
-       print "   **Typedef**: ";
-       $lineprefix = "";
-       output_highlight_rst($args{'purpose'});
-       $start = "\n\n**Syntax**\n\n  ``";
+    my $is_macro = 0;
+
+    if ($sphinx_major < 3) {
+       if ($args{'typedef'}) {
+           print ".. c:type:: ". $args{'function'} . "\n\n";
+           print_lineno($declaration_start_line);
+           print "   **Typedef**: ";
+           $lineprefix = "";
+           output_highlight_rst($args{'purpose'});
+           $start = "\n\n**Syntax**\n\n  ``";
+           $is_macro = 1;
+       } else {
+           print ".. c:function:: ";
+       }
     } else {
-       print ".. c:function:: ";
+       if ($args{'typedef'} || $args{'functiontype'} eq "") {
+           $is_macro = 1;
+           print ".. c:macro:: ". $args{'function'} . "\n\n";
+       } else {
+           print ".. c:function:: ";
+       }
+
+       if ($args{'typedef'}) {
+           print_lineno($declaration_start_line);
+           print "   **Typedef**: ";
+           $lineprefix = "";
+           output_highlight_rst($args{'purpose'});
+           $start = "\n\n**Syntax**\n\n  ``";
+       } else {
+           print "``" if ($is_macro);
+       }
     }
     if ($args{'functiontype'} ne "") {
        $start .= $args{'functiontype'} . " " . $args{'function'} . " (";
@@ -860,13 +968,15 @@ sub output_function_rst(%) {
            # pointer-to-function
            print $1 . $parameter . ") (" . $2 . ")";
        } else {
-           print $type . " " . $parameter;
+           print $type;
        }
     }
-    if ($args{'typedef'}) {
-       print ");``\n\n";
+    if ($is_macro) {
+       print ")``\n\n";
     } else {
        print ")\n\n";
+    }
+    if (!$args{'typedef'}) {
        print_lineno($declaration_start_line);
        $lineprefix = "   ";
        output_highlight_rst($args{'purpose'});
@@ -881,7 +991,7 @@ sub output_function_rst(%) {
        $type = $args{'parametertypes'}{$parameter};
 
        if ($type ne "") {
-           print "``$type $parameter``\n";
+           print "``$type``\n";
        } else {
            print "``$parameter``\n";
        }
@@ -922,9 +1032,14 @@ sub output_enum_rst(%) {
     my ($parameter);
     my $oldprefix = $lineprefix;
     my $count;
-    my $name = "enum " . $args{'enum'};
 
-    print "\n\n.. c:type:: " . $name . "\n\n";
+    if ($sphinx_major < 3) {
+       my $name = "enum " . $args{'enum'};
+       print "\n\n.. c:type:: " . $name . "\n\n";
+    } else {
+       my $name = $args{'enum'};
+       print "\n\n.. c:enum:: " . $name . "\n\n";
+    }
     print_lineno($declaration_start_line);
     $lineprefix = "   ";
     output_highlight_rst($args{'purpose'});
@@ -950,8 +1065,13 @@ sub output_typedef_rst(%) {
     my %args = %{$_[0]};
     my ($parameter);
     my $oldprefix = $lineprefix;
-    my $name = "typedef " . $args{'typedef'};
+    my $name;
 
+    if ($sphinx_major < 3) {
+       $name = "typedef " . $args{'typedef'};
+    } else {
+       $name = $args{'typedef'};
+    }
     print "\n\n.. c:type:: " . $name . "\n\n";
     print_lineno($declaration_start_line);
     $lineprefix = "   ";
@@ -966,17 +1086,17 @@ sub output_struct_rst(%) {
     my %args = %{$_[0]};
     my ($parameter);
     my $oldprefix = $lineprefix;
-    my $name = $args{'type'} . " " . $args{'struct'};
-
-    # Sphinx 3.0 and up will emit warnings for "c:type:: struct Foo".
-    # It wants to see "c:struct:: Foo" (and will add the word 'struct' in
-    # the rendered output).
-    if ((split(/\./, $sphinx_version))[0] >= 3) {
-        my $sname = $name;
-        $sname =~ s/^struct //;
-        print "\n\n.. c:struct:: " . $sname . "\n\n";
+
+    if ($sphinx_major < 3) {
+       my $name = $args{'type'} . " " . $args{'struct'};
+       print "\n\n.. c:type:: " . $name . "\n\n";
     } else {
-        print "\n\n.. c:type:: " . $name . "\n\n";
+       my $name = $args{'struct'};
+       if ($args{'type'} eq 'union') {
+           print "\n\n.. c:union:: " . $name . "\n\n";
+       } else {
+           print "\n\n.. c:struct:: " . $name . "\n\n";
+       }
     }
     print_lineno($declaration_start_line);
     $lineprefix = "   ";
@@ -1036,12 +1156,14 @@ sub output_declaration {
     my $name = shift;
     my $functype = shift;
     my $func = "output_${functype}_$output_mode";
+
+    return if (defined($nosymbol_table{$name}));
+
     if (($output_selection == OUTPUT_ALL) ||
        (($output_selection == OUTPUT_INCLUDE ||
          $output_selection == OUTPUT_EXPORTED) &&
         defined($function_table{$name})) ||
-       (($output_selection == OUTPUT_EXCLUDE ||
-         $output_selection == OUTPUT_INTERNAL) &&
+       ($output_selection == OUTPUT_INTERNAL &&
         !($functype eq "function" && defined($function_table{$name}))))
     {
        &$func(@_);
@@ -1064,14 +1186,6 @@ sub output_blockhead {
 sub dump_declaration($$) {
     no strict 'refs';
     my ($prototype, $file) = @_;
-    if ($decl_type eq 'type name') {
-       if ($prototype =~ /^(enum|struct|union)\s+/) {
-          $decl_type = $1;
-       } else {
-          return;
-       }
-    }
-
     my $func = "dump_" . $decl_type;
     &$func(@_);
 }
@@ -1084,7 +1198,7 @@ sub dump_struct($$) {
     my $x = shift;
     my $file = shift;
 
-    if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|__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\(\)]*\)\)))*/) {
        my $decl_type = $1;
        $declaration_name = $2;
        my $members = $3;
@@ -1095,11 +1209,15 @@ sub dump_struct($$) {
        # strip comments:
        $members =~ s/\/\*.*?\*\///gos;
        # strip attributes
-       $members =~ s/\s*__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)//gi;
-       $members =~ s/\s*__aligned\s*\([^;]*\)//gos;
-       $members =~ s/\s*__packed\s*//gos;
-       $members =~ s/\s*CRYPTO_MINALIGN_ATTR//gos;
+       $members =~ s/\s*__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)/ /gi;
+       $members =~ s/\s*__aligned\s*\([^;]*\)/ /gos;
+       $members =~ s/\s*__packed\s*/ /gos;
+       $members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos;
+       $members =~ s/\s*____cacheline_aligned_in_smp/ /gos;
+       $members =~ s/\s*____cacheline_aligned/ /gos;
+
        # replace DECLARE_BITMAP
+       $members =~ s/__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, __ETHTOOL_LINK_MODE_MASK_NBITS)/gos;
        $members =~ s/DECLARE_BITMAP\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos;
        # replace DECLARE_HASHTABLE
        $members =~ s/DECLARE_HASHTABLE\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[1 << (($2) - 1)\]/gos;
@@ -1226,6 +1344,8 @@ sub show_warnings($$) {
        my $functype = shift;
        my $name = shift;
 
+       return 0 if (defined($nosymbol_table{$name}));
+
        return 1 if ($output_selection == OUTPUT_ALL);
 
        if ($output_selection == OUTPUT_EXPORTED) {
@@ -1249,27 +1369,28 @@ sub show_warnings($$) {
                        return 0;
                }
        }
-       if ($output_selection == OUTPUT_EXCLUDE) {
-               if (!defined($function_table{$name})) {
-                       return 1;
-               } else {
-                       return 0;
-               }
-       }
        die("Please add the new output type at show_warnings()");
 }
 
 sub dump_enum($$) {
     my $x = shift;
     my $file = shift;
+    my $members;
+
 
     $x =~ s@/\*.*?\*/@@gos;    # strip comments.
     # strip #define macros inside enums
     $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos;
 
-    if ($x =~ /enum\s+(\w*)\s*\{(.*)\}/) {
+    if ($x =~ /typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;/) {
+       $declaration_name = $2;
+       $members = $1;
+    } elsif ($x =~ /enum\s+(\w*)\s*\{(.*)\}/) {
        $declaration_name = $1;
-       my $members = $2;
+       $members = $2;
+    }
+
+    if ($declaration_name) {
        my %_members;
 
        $members =~ s/\s+$//;
@@ -1304,27 +1425,31 @@ sub dump_enum($$) {
                            'sections' => \%sections,
                            'purpose' => $declaration_purpose
                           });
-    }
-    else {
+    } else {
        print STDERR "${file}:$.: error: Cannot parse enum!\n";
        ++$errors;
     }
 }
 
+my $typedef_type = qr { ((?:\s+[\w\*]+){1,8})\s* }x;
+my $typedef_ident = qr { \*?\s*(\w\S+)\s* }x;
+my $typedef_args = qr { \s*\((.*)\); }x;
+
+my $typedef1 = qr { typedef$typedef_type\($typedef_ident\)$typedef_args }x;
+my $typedef2 = qr { typedef$typedef_type$typedef_ident$typedef_args }x;
+
 sub dump_typedef($$) {
     my $x = shift;
     my $file = shift;
 
     $x =~ s@/\*.*?\*/@@gos;    # strip comments.
 
-    # Parse function prototypes
-    if ($x =~ /typedef\s+(\w+)\s*\(\*\s*(\w\S+)\s*\)\s*\((.*)\);/ ||
-       $x =~ /typedef\s+(\w+)\s*(\w\S+)\s*\s*\((.*)\);/) {
-
-       # Function typedefs
+    # Parse function typedef prototypes
+    if ($x =~ $typedef1 || $x =~ $typedef2) {
        $return_type = $1;
        $declaration_name = $2;
        my $args = $3;
+       $return_type =~ s/^\s+//;
 
        create_parameterlist($args, ',', $file, $declaration_name);
 
@@ -1400,7 +1525,7 @@ sub create_parameterlist($$$$) {
            # Treat preprocessor directive as a typeless variable just to fill
            # corresponding data structures "correctly". Catch it later in
            # output_* subs.
-           push_parameter($arg, "", $file);
+           push_parameter($arg, "", "", $file);
        } elsif ($arg =~ m/\(.+\)\s*\(/) {
            # pointer-to-function
            $arg =~ tr/#/,/;
@@ -1409,7 +1534,7 @@ sub create_parameterlist($$$$) {
            $type = $arg;
            $type =~ s/([^\(]+\(\*?)\s*$param/$1/;
            save_struct_actual($param);
-           push_parameter($param, $type, $file, $declaration_name);
+           push_parameter($param, $type, $arg, $file, $declaration_name);
        } elsif ($arg) {
            $arg =~ s/\s*:\s*/:/g;
            $arg =~ s/\s*\[/\[/g;
@@ -1434,26 +1559,28 @@ sub create_parameterlist($$$$) {
            foreach $param (@args) {
                if ($param =~ m/^(\*+)\s*(.*)/) {
                    save_struct_actual($2);
-                   push_parameter($2, "$type $1", $file, $declaration_name);
+
+                   push_parameter($2, "$type $1", $arg, $file, $declaration_name);
                }
                elsif ($param =~ m/(.*?):(\d+)/) {
                    if ($type ne "") { # skip unnamed bit-fields
                        save_struct_actual($1);
-                       push_parameter($1, "$type:$2", $file, $declaration_name)
+                       push_parameter($1, "$type:$2", $arg, $file, $declaration_name)
                    }
                }
                else {
                    save_struct_actual($param);
-                   push_parameter($param, $type, $file, $declaration_name);
+                   push_parameter($param, $type, $arg, $file, $declaration_name);
                }
            }
        }
     }
 }
 
-sub push_parameter($$$$) {
+sub push_parameter($$$$$) {
        my $param = shift;
        my $type = shift;
+       my $org_arg = shift;
        my $file = shift;
        my $declaration_name = shift;
 
@@ -1471,6 +1598,10 @@ sub push_parameter($$$$) {
              # handles unnamed variable parameters
              $param = "...";
            }
+           elsif ($param =~ /\w\.\.\.$/) {
+             # for named variable parameters of the form `x...`, remove the dots
+             $param =~ s/\.\.\.$//;
+           }
            if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") {
                $parameterdescs{$param} = "variable arguments";
            }
@@ -1513,8 +1644,8 @@ sub push_parameter($$$$) {
        # "[blah" in a parameter string;
        ###$param =~ s/\s*//g;
        push @parameterlist, $param;
-       $type =~ s/\s\s+/ /g;
-       $parametertypes{$param} = $type;
+       $org_arg =~ s/\s\s+/ /g;
+       $parametertypes{$param} = $org_arg;
 }
 
 sub check_sections($$$$$) {
@@ -1588,6 +1719,8 @@ sub dump_function($$) {
     my $file = shift;
     my $noret = 0;
 
+    print_lineno($new_start_line);
+
     $prototype =~ s/^static +//;
     $prototype =~ s/^extern +//;
     $prototype =~ s/^asmlinkage +//;
@@ -1612,6 +1745,9 @@ sub dump_function($$) {
             )+
           \)\)\s+//x;
 
+    # Strip QEMU specific compiler annotations
+    $prototype =~ s/QEMU_[A-Z_]+ +//;
+
     # 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
@@ -1625,7 +1761,7 @@ sub dump_function($$) {
     # 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)
-    # - qatomic_set (macro)
+    # - atomic_set (macro)
     # - pci_match_device, __copy_to_user (long return type)
 
     if ($define && $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s+/) {
@@ -1663,30 +1799,48 @@ sub dump_function($$) {
        return;
     }
 
-       my $prms = join " ", @parameterlist;
-       check_sections($file, $declaration_name, "function", $sectcheck, $prms);
+    my $prms = join " ", @parameterlist;
+    check_sections($file, $declaration_name, "function", $sectcheck, $prms);
 
-        # This check emits a lot of warnings at the moment, because many
-        # functions don't have a 'Return' doc section. So until the number
-        # of warnings goes sufficiently down, the check is only performed in
-        # verbose mode.
-        # TODO: always perform the check.
-        if ($verbose && !$noret) {
-                check_return_section($file, $declaration_name, $return_type);
-        }
+    # This check emits a lot of warnings at the moment, because many
+    # functions don't have a 'Return' doc section. So until the number
+    # of warnings goes sufficiently down, the check is only performed in
+    # verbose mode.
+    # TODO: always perform the check.
+    if ($verbose && !$noret) {
+           check_return_section($file, $declaration_name, $return_type);
+    }
 
-    output_declaration($declaration_name,
-                      'function',
-                      {'function' => $declaration_name,
-                       'module' => $modulename,
-                       'functiontype' => $return_type,
-                       'parameterlist' => \@parameterlist,
-                       'parameterdescs' => \%parameterdescs,
-                       'parametertypes' => \%parametertypes,
-                       'sectionlist' => \@sectionlist,
-                       'sections' => \%sections,
-                       'purpose' => $declaration_purpose
-                      });
+    # The function parser can be called with a typedef parameter.
+    # Handle it.
+    if ($return_type =~ /typedef/) {
+       output_declaration($declaration_name,
+                          'function',
+                          {'function' => $declaration_name,
+                           'typedef' => 1,
+                           'module' => $modulename,
+                           'functiontype' => $return_type,
+                           'parameterlist' => \@parameterlist,
+                           'parameterdescs' => \%parameterdescs,
+                           'parametertypes' => \%parametertypes,
+                           'sectionlist' => \@sectionlist,
+                           'sections' => \%sections,
+                           'purpose' => $declaration_purpose
+                          });
+    } else {
+       output_declaration($declaration_name,
+                          'function',
+                          {'function' => $declaration_name,
+                           'module' => $modulename,
+                           'functiontype' => $return_type,
+                           'parameterlist' => \@parameterlist,
+                           'parameterdescs' => \%parameterdescs,
+                           'parametertypes' => \%parametertypes,
+                           'sectionlist' => \@sectionlist,
+                           'sections' => \%sections,
+                           'purpose' => $declaration_purpose
+                          });
+    }
 }
 
 sub reset_state {
@@ -1781,6 +1935,11 @@ sub process_proto_function($$) {
        $prototype =~ s@/\*.*?\*/@@gos; # strip comments.
        $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
        $prototype =~ s@^\s+@@gos; # strip leading spaces
+
+        # Handle prototypes for function pointers like:
+        # int (*pcs_config)(struct foo)
+       $prototype =~ s@^(\S+\s+)\(\s*\*(\S+)\)@$1$2@gos;
+
        if ($prototype =~ /SYSCALL_DEFINE/) {
                syscall_munge();
        }
@@ -1859,6 +2018,7 @@ sub process_export_file($) {
 
     while (<IN>) {
        if (/$export_symbol/) {
+           next if (defined($nosymbol_table{$2}));
            $function_table{$2} = 1;
        }
     }
@@ -1890,7 +2050,7 @@ sub process_name($$) {
     if (/$doc_block/o) {
        $state = STATE_DOCBLOCK;
        $contents = "";
-       $new_start_line = $. + 1;
+       $new_start_line = $.;
 
        if ( $1 eq "" ) {
            $section = $section_intro;
@@ -1928,9 +2088,7 @@ sub process_name($$) {
            ++$warnings;
        }
 
-       if ($identifier =~ m/^[A-Z]/) {
-           $decl_type = 'type name';
-       } elsif ($identifier =~ m/^struct\b/) {
+       if ($identifier =~ m/^struct\b/) {
            $decl_type = 'struct';
        } elsif ($identifier =~ m/^union\b/) {
            $decl_type = 'union';
@@ -1960,6 +2118,25 @@ sub process_name($$) {
 sub process_body($$) {
     my $file = shift;
 
+    # Until all named variable macro parameters are
+    # documented using the bare name (`x`) rather than with
+    # dots (`x...`), strip the dots:
+    if ($section =~ /\w\.\.\.$/) {
+       $section =~ s/\.\.\.$//;
+
+       if ($verbose) {
+           print STDERR "${file}:$.: warning: Variable macro arguments should be documented without dots\n";
+           ++$warnings;
+       }
+    }
+
+    if ($state == STATE_BODY_WITH_BLANK_LINE && /^\s*\*\s?\S/) {
+       dump_section($file, $section, $contents);
+       $section = $section_default;
+       $new_start_line = $.;
+       $contents = "";
+    }
+
     if (/$doc_sect/i) { # case insensitive for supported section names
        $newsection = $1;
        $newcontents = $2;
@@ -2012,19 +2189,23 @@ sub process_body($$) {
        $prototype = "";
        $state = STATE_PROTO;
        $brcount = 0;
+        $new_start_line = $. + 1;
     } elsif (/$doc_content/) {
-       # miguel-style comment kludge, look for blank lines after
-       # @parameter line to signify start of description
        if ($1 eq "") {
-           if ($section =~ m/^@/ || $section eq $section_context) {
+           if ($section eq $section_context) {
                dump_section($file, $section, $contents);
                $section = $section_default;
                $contents = "";
                $new_start_line = $.;
+               $state = STATE_BODY;
            } else {
+               if ($section ne $section_default) {
+                   $state = STATE_BODY_WITH_BLANK_LINE;
+               } else {
+                   $state = STATE_BODY;
+               }
                $contents .= "\n";
            }
-           $state = STATE_BODY;
        } elsif ($state == STATE_BODY_MAYBE) {
            # Continued declaration purpose
            chomp($declaration_purpose);
@@ -2156,7 +2337,7 @@ sub process_file($) {
 
     $file = map_filename($orig_file);
 
-    if (!open(IN,"<$file")) {
+    if (!open(IN_FILE,"<$file")) {
        print STDERR "Error: Cannot open file $file\n";
        ++$errors;
        return;
@@ -2165,9 +2346,9 @@ sub process_file($) {
     $. = 1;
 
     $section_counter = 0;
-    while (<IN>) {
+    while (<IN_FILE>) {
        while (s/\\\s*$//) {
-           $_ .= <IN>;
+           $_ .= <IN_FILE>;
        }
        # Replace tabs by spaces
         while ($_ =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {};
@@ -2176,7 +2357,8 @@ sub process_file($) {
            process_normal();
        } elsif ($state == STATE_NAME) {
            process_name($file, $_);
-       } elsif ($state == STATE_BODY || $state == STATE_BODY_MAYBE) {
+       } elsif ($state == STATE_BODY || $state == STATE_BODY_MAYBE ||
+                $state == STATE_BODY_WITH_BLANK_LINE) {
            process_body($file, $_);
        } elsif ($state == STATE_INLINE) { # scanning for inline parameters
            process_inline($file, $_);
@@ -2198,9 +2380,14 @@ sub process_file($) {
            print STDERR "${file}:1: warning: no structured comments found\n";
        }
     }
+    close IN_FILE;
 }
 
 
+if ($output_mode eq "rst") {
+       get_sphinx_version() if (!$sphinx_major);
+}
+
 $kernelversion = get_kernel_version();
 
 # generate a sequence of code that will splice in highlighting information
@@ -2247,4 +2434,9 @@ if ($verbose && $warnings) {
   print STDERR "$warnings warnings\n";
 }
 
-exit($output_mode eq "none" ? 0 : $errors);
+if ($Werror && $warnings) {
+    print STDERR "$warnings warnings as Errors\n";
+    exit($warnings);
+} else {
+    exit($output_mode eq "none" ? 0 : $errors)
+}