From: Mario Six Date: Tue, 10 Jul 2018 06:40:17 +0000 (+0200) Subject: doc: Replace DocBook with sphinx-based docs X-Git-Url: http://git.dujemihanovic.xyz/login.html?a=commitdiff_plain;h=78a88f7930becb78afef09c1237a8e4edc1b01e1;p=u-boot.git doc: Replace DocBook with sphinx-based docs The Linux kernel moved to sphinx-based documentation and got rid of the DocBook based documentation quite a while ago. Hence, the DocBook documentation for U-Boot should be converted as well. To achieve this, import the necessary files from Linux v4.17, and convert the current DocBook documentation (three files altogether) to sphinx/reStructuredText. For now, all old DocBook documentation was merged into a single handbook, tentatively named "U-Boot Hacker Manual". For some source files, the documentation style was changed to comply with kernel-doc; no functional changes were applied. Signed-off-by: Mario Six --- diff --git a/Documentation/.gitignore b/Documentation/.gitignore new file mode 100644 index 0000000000..e74fec8693 --- /dev/null +++ b/Documentation/.gitignore @@ -0,0 +1,2 @@ +output +*.pyc diff --git a/Documentation/Makefile b/Documentation/Makefile new file mode 100644 index 0000000000..2ca77ad0f2 --- /dev/null +++ b/Documentation/Makefile @@ -0,0 +1,124 @@ +# -*- makefile -*- +# Makefile for Sphinx documentation +# + +subdir-y := + +# You can set these variables from the command line. +SPHINXBUILD = sphinx-build +SPHINXOPTS = +SPHINXDIRS = . +_SPHINXDIRS = $(patsubst $(srctree)/Documentation/%/conf.py,%,$(wildcard $(srctree)/Documentation/*/conf.py)) +SPHINX_CONF = conf.py +PAPER = +BUILDDIR = $(obj)/output +PDFLATEX = xelatex +LATEXOPTS = -interaction=batchmode + +# User-friendly check for sphinx-build +HAVE_SPHINX := $(shell if which $(SPHINXBUILD) >/dev/null 2>&1; then echo 1; else echo 0; fi) + +ifeq ($(HAVE_SPHINX),0) + +.DEFAULT: + $(warning The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed and in PATH, or set the SPHINXBUILD make variable to point to the full path of the '$(SPHINXBUILD)' executable.) + @echo + @./scripts/sphinx-pre-install + @echo " SKIP Sphinx $@ target." + +else # HAVE_SPHINX + +# User-friendly check for pdflatex +HAVE_PDFLATEX := $(shell if which $(PDFLATEX) >/dev/null 2>&1; then echo 1; else echo 0; fi) + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +KERNELDOC = $(srctree)/scripts/kernel-doc +KERNELDOC_CONF = -D kerneldoc_srctree=$(srctree) -D kerneldoc_bin=$(KERNELDOC) +ALLSPHINXOPTS = $(KERNELDOC_CONF) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +# commands; the 'cmd' from scripts/Kbuild.include is not *loopable* +loop_cmd = $(echo-cmd) $(cmd_$(1)) || exit; + +# $2 sphinx builder e.g. "html" +# $3 name of the build subfolder / e.g. "media", used as: +# * dest folder relative to $(BUILDDIR) and +# * cache folder relative to $(BUILDDIR)/.doctrees +# $4 dest subfolder e.g. "man" for man pages at media/man +# $5 reST source folder relative to $(srctree)/$(src), +# e.g. "media" for the linux-tv book-set at ./Documentation/media + +quiet_cmd_sphinx = SPHINX $@ --> file://$(abspath $(BUILDDIR)/$3/$4) + cmd_sphinx = $(MAKE) BUILDDIR=$(abspath $(BUILDDIR)) $(build)=Documentation/media $2 && \ + PYTHONDONTWRITEBYTECODE=1 \ + BUILDDIR=$(abspath $(BUILDDIR)) SPHINX_CONF=$(abspath $(srctree)/$(src)/$5/$(SPHINX_CONF)) \ + $(SPHINXBUILD) \ + -b $2 \ + -c $(abspath $(srctree)/$(src)) \ + -d $(abspath $(BUILDDIR)/.doctrees/$3) \ + -D version=$(KERNELVERSION) -D release=$(KERNELRELEASE) \ + $(ALLSPHINXOPTS) \ + $(abspath $(srctree)/$(src)/$5) \ + $(abspath $(BUILDDIR)/$3/$4) + +htmldocs: + @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,html,$(var),,$(var))) + +linkcheckdocs: + @$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,linkcheck,$(var),,$(var))) + +latexdocs: + @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,latex,$(var),latex,$(var))) + +ifeq ($(HAVE_PDFLATEX),0) + +pdfdocs: + $(warning The '$(PDFLATEX)' command was not found. Make sure you have it installed and in PATH to produce PDF output.) + @echo " SKIP Sphinx $@ target." + +else # HAVE_PDFLATEX + +pdfdocs: latexdocs + $(foreach var,$(SPHINXDIRS), $(MAKE) PDFLATEX=$(PDFLATEX) LATEXOPTS="$(LATEXOPTS)" -C $(BUILDDIR)/$(var)/latex || exit;) + +endif # HAVE_PDFLATEX + +epubdocs: + @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,epub,$(var),epub,$(var))) + +xmldocs: + @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,xml,$(var),xml,$(var))) + +endif # HAVE_SPHINX + +# The following targets are independent of HAVE_SPHINX, and the rules should +# work or silently pass without Sphinx. + +refcheckdocs: + $(Q)cd $(srctree);scripts/documentation-file-ref-check + +cleandocs: + $(Q)rm -rf $(BUILDDIR) + $(Q)$(MAKE) BUILDDIR=$(abspath $(BUILDDIR)) $(build)=Documentation/media clean + +dochelp: + @echo ' Linux kernel internal documentation in different formats from ReST:' + @echo ' htmldocs - HTML' + @echo ' latexdocs - LaTeX' + @echo ' pdfdocs - PDF' + @echo ' epubdocs - EPUB' + @echo ' xmldocs - XML' + @echo ' linkcheckdocs - check for broken external links (will connect to external hosts)' + @echo ' refcheckdocs - check for references to non-existing files under Documentation' + @echo ' cleandocs - clean all generated files' + @echo + @echo ' make SPHINXDIRS="s1 s2" [target] Generate only docs of folder s1, s2' + @echo ' valid values for SPHINXDIRS are: $(_SPHINXDIRS)' + @echo + @echo ' make SPHINX_CONF={conf-file} [target] use *additional* sphinx-build' + @echo ' configuration. This is e.g. useful to build with nit-picking config.' + @echo + @echo ' Default location for the generated documents is Documentation/output' diff --git a/Documentation/conf.py b/Documentation/conf.py new file mode 100644 index 0000000000..168c31346b --- /dev/null +++ b/Documentation/conf.py @@ -0,0 +1,528 @@ +# -*- coding: utf-8 -*- +# +# The U-Boot documentation build configuration file, created by +# sphinx-quickstart on Fri Feb 12 13:51:46 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import sphinx + +# Get Sphinx version +major, minor, patch = sphinx.version_info[:3] + + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('sphinx')) +from load_config import loadConfig + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = '1.3' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain', 'kfigure'] + +# The name of the math extension changed on Sphinx 1.4 +if major == 1 and minor > 3: + extensions.append("sphinx.ext.imgmath") +else: + extensions.append("sphinx.ext.pngmath") + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'Das U-Boot' +copyright = 'The U-Boot development community' +author = 'The U-Boot development community' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# In a normal build, version and release are are set to KERNELVERSION and +# KERNELRELEASE, respectively, from the Makefile via Sphinx command line +# arguments. +# +# The following code tries to extract the information by reading the Makefile, +# when Sphinx is run directly (e.g. by Read the Docs). +try: + makefile_version = None + makefile_patchlevel = None + for line in open('../Makefile'): + key, val = [x.strip() for x in line.split('=', 2)] + if key == 'VERSION': + makefile_version = val + elif key == 'PATCHLEVEL': + makefile_patchlevel = val + if makefile_version and makefile_patchlevel: + break +except: + pass +finally: + if makefile_version and makefile_patchlevel: + version = release = makefile_version + '.' + makefile_patchlevel + else: + version = release = "unknown version" + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['output'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + +primary_domain = 'c' +highlight_language = 'none' + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. + +# The Read the Docs theme is available from +# - https://github.com/snide/sphinx_rtd_theme +# - https://pypi.python.org/pypi/sphinx_rtd_theme +# - python-sphinx-rtd-theme package (on Debian) +try: + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +except ImportError: + sys.stderr.write('Warning: The Sphinx \'sphinx_rtd_theme\' HTML theme was not found. Make sure you have the theme installed to produce pretty HTML output. Falling back to the default theme.\n') + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". + +html_static_path = ['sphinx-static'] + +html_context = { + 'css_files': [ + '_static/theme_overrides.css', + ], +} + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'TheUBootdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +'papersize': 'a4paper', + +# The font size ('10pt', '11pt' or '12pt'). +'pointsize': '8pt', + +# Latex figure (float) alignment +#'figure_align': 'htbp', + +# Don't mangle with UTF-8 chars +'inputenc': '', +'utf8extra': '', + +# Additional stuff for the LaTeX preamble. + 'preamble': ''' + % Use some font with UTF-8 support with XeLaTeX + \\usepackage{fontspec} + \\setsansfont{DejaVu Serif} + \\setromanfont{DejaVu Sans} + \\setmonofont{DejaVu Sans Mono} + + ''' +} + +# Fix reference escape troubles with Sphinx 1.4.x +if major == 1 and minor > 3: + latex_elements['preamble'] += '\\renewcommand*{\\DUrole}[2]{ #2 }\n' + +if major == 1 and minor <= 4: + latex_elements['preamble'] += '\\usepackage[margin=0.5in, top=1in, bottom=1in]{geometry}' +elif major == 1 and (minor > 5 or (minor == 5 and patch >= 3)): + latex_elements['sphinxsetup'] = 'hmargin=0.5in, vmargin=1in' + latex_elements['preamble'] += '\\fvset{fontsize=auto}\n' + +# Customize notice background colors on Sphinx < 1.6: +if major == 1 and minor < 6: + latex_elements['preamble'] += ''' + \\usepackage{ifthen} + + % Put notes in color and let them be inside a table + \\definecolor{NoteColor}{RGB}{204,255,255} + \\definecolor{WarningColor}{RGB}{255,204,204} + \\definecolor{AttentionColor}{RGB}{255,255,204} + \\definecolor{ImportantColor}{RGB}{192,255,204} + \\definecolor{OtherColor}{RGB}{204,204,204} + \\newlength{\\mynoticelength} + \\makeatletter\\newenvironment{coloredbox}[1]{% + \\setlength{\\fboxrule}{1pt} + \\setlength{\\fboxsep}{7pt} + \\setlength{\\mynoticelength}{\\linewidth} + \\addtolength{\\mynoticelength}{-2\\fboxsep} + \\addtolength{\\mynoticelength}{-2\\fboxrule} + \\begin{lrbox}{\\@tempboxa}\\begin{minipage}{\\mynoticelength}}{\\end{minipage}\\end{lrbox}% + \\ifthenelse% + {\\equal{\\py@noticetype}{note}}% + {\\colorbox{NoteColor}{\\usebox{\\@tempboxa}}}% + {% + \\ifthenelse% + {\\equal{\\py@noticetype}{warning}}% + {\\colorbox{WarningColor}{\\usebox{\\@tempboxa}}}% + {% + \\ifthenelse% + {\\equal{\\py@noticetype}{attention}}% + {\\colorbox{AttentionColor}{\\usebox{\\@tempboxa}}}% + {% + \\ifthenelse% + {\\equal{\\py@noticetype}{important}}% + {\\colorbox{ImportantColor}{\\usebox{\\@tempboxa}}}% + {\\colorbox{OtherColor}{\\usebox{\\@tempboxa}}}% + }% + }% + }% + }\\makeatother + + \\makeatletter + \\renewenvironment{notice}[2]{% + \\def\\py@noticetype{#1} + \\begin{coloredbox}{#1} + \\bf\\it + \\par\\strong{#2} + \\csname py@noticestart@#1\\endcsname + } + { + \\csname py@noticeend@\\py@noticetype\\endcsname + \\end{coloredbox} + } + \\makeatother + + ''' + +# With Sphinx 1.6, it is possible to change the Bg color directly +# by using: +# \definecolor{sphinxnoteBgColor}{RGB}{204,255,255} +# \definecolor{sphinxwarningBgColor}{RGB}{255,204,204} +# \definecolor{sphinxattentionBgColor}{RGB}{255,255,204} +# \definecolor{sphinximportantBgColor}{RGB}{192,255,204} +# +# However, it require to use sphinx heavy box with: +# +# \renewenvironment{sphinxlightbox} {% +# \\begin{sphinxheavybox} +# } +# \\end{sphinxheavybox} +# } +# +# Unfortunately, the implementation is buggy: if a note is inside a +# table, it isn't displayed well. So, for now, let's use boring +# black and white notes. + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +# Sorted in alphabetical order +latex_documents = [ + ('index', 'u-boot-hacker-manual.tex', 'U-Boot Hacker Manual', + 'The U-Boot development community', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'dasuboot', 'The U-Boot Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'DasUBoot', 'The U-Boot Documentation', + author, 'DasUBoot', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project +epub_author = author +epub_publisher = author +epub_copyright = copyright + +# The basename for the epub file. It defaults to the project name. +#epub_basename = project + +# The HTML theme for the epub output. Since the default themes are not +# optimized for small screen space, using the same theme for HTML and epub +# output is usually not wise. This defaults to 'epub', a theme designed to save +# visual space. +#epub_theme = 'epub' + +# The language of the text. It defaults to the language option +# or 'en' if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# A sequence of (type, uri, title) tuples for the guide element of content.opf. +#epub_guide = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files that should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True + +# Choose between 'default' and 'includehidden'. +#epub_tocscope = 'default' + +# Fix unsupported image types using the Pillow. +#epub_fix_images = False + +# Scale large images. +#epub_max_image_width = 0 + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#epub_show_urls = 'inline' + +# If false, no index is generated. +#epub_use_index = True + +#======= +# rst2pdf +# +# Grouping the document tree into PDF files. List of tuples +# (source start file, target name, title, author, options). +# +# See the Sphinx chapter of http://ralsina.me/static/manual.pdf +# +# FIXME: Do not add the index file here; the result will be too big. Adding +# multiple PDF files here actually tries to get the cross-referencing right +# *between* PDF files. +pdf_documents = [ + ('uboot-documentation', u'U-Boot', u'U-Boot', u'J. Random Bozo'), +] + +# kernel-doc extension configuration for running Sphinx directly (e.g. by Read +# the Docs). In a normal build, these are supplied from the Makefile via command +# line arguments. +kerneldoc_bin = '../scripts/kernel-doc' +kerneldoc_srctree = '..' + +# ------------------------------------------------------------------------------ +# Since loadConfig overwrites settings from the global namespace, it has to be +# the last statement in the conf.py file +# ------------------------------------------------------------------------------ +loadConfig(globals()) diff --git a/Documentation/index.rst b/Documentation/index.rst new file mode 100644 index 0000000000..a7b0ee4e87 --- /dev/null +++ b/Documentation/index.rst @@ -0,0 +1,117 @@ +==================== +U-Boot Hacker Manual +==================== + +Linker-Generated Arrays +======================= + +A linker list is constructed by grouping together linker input +sections, each containing one entry of the list. Each input section +contains a constant initialized variable which holds the entry's +content. Linker list input sections are constructed from the list +and entry names, plus a prefix which allows grouping all lists +together. Assuming _list and _entry are the list and entry names, +then the corresponding input section name is + +:: + + .u_boot_list_ + 2_ + @_list + _2_ + @_entry + +and the C variable name is + +:: + + _u_boot_list + _2_ + @_list + _2_ + @_entry + +This ensures uniqueness for both input section and C variable name. + +Note that the names differ only in the first character, "." for the +section and "_" for the variable, so that the linker cannot confuse +section and symbol names. From now on, both names will be referred +to as + +:: + + %u_boot_list_ + 2_ + @_list + _2_ + @_entry + +Entry variables need never be referred to directly. + +The naming scheme for input sections allows grouping all linker lists +into a single linker output section and grouping all entries for a +single list. + +Note the two '_2_' constant components in the names: their presence +allows putting a start and end symbols around a list, by mapping +these symbols to sections names with components "1" (before) and +"3" (after) instead of "2" (within). +Start and end symbols for a list can generally be defined as + +:: + + %u_boot_list_2_ + @_list + _1_... + %u_boot_list_2_ + @_list + _3_... + +Start and end symbols for the whole of the linker lists area can be +defined as + +:: + + %u_boot_list_1_... + %u_boot_list_3_... + +Here is an example of the sorted sections which result from a list +"array" made up of three entries : "first", "second" and "third", +iterated at least once. + +:: + + .u_boot_list_2_array_1 + .u_boot_list_2_array_2_first + .u_boot_list_2_array_2_second + .u_boot_list_2_array_2_third + .u_boot_list_2_array_3 + +If lists must be divided into sublists (e.g. for iterating only on +part of a list), one can simply give the list a name of the form +'outer_2_inner', where 'outer' is the global list name and 'inner' +is the sub-list name. Iterators for the whole list should use the +global list name ("outer"); iterators for only a sub-list should use +the full sub-list name ("outer_2_inner"). + +Here is an example of the sections generated from a global list +named "drivers", two sub-lists named "i2c" and "pci", and iterators +defined for the whole list and each sub-list: + +:: + + %u_boot_list_2_drivers_1 + %u_boot_list_2_drivers_2_i2c_1 + %u_boot_list_2_drivers_2_i2c_2_first + %u_boot_list_2_drivers_2_i2c_2_first + %u_boot_list_2_drivers_2_i2c_2_second + %u_boot_list_2_drivers_2_i2c_2_third + %u_boot_list_2_drivers_2_i2c_3 + %u_boot_list_2_drivers_2_pci_1 + %u_boot_list_2_drivers_2_pci_2_first + %u_boot_list_2_drivers_2_pci_2_second + %u_boot_list_2_drivers_2_pci_2_third + %u_boot_list_2_drivers_2_pci_3 + %u_boot_list_2_drivers_3 + +.. kernel-doc:: include/linker_lists.h + :internal: + +Serial system +============= + +.. kernel-doc:: drivers/serial/serial.c + :internal: + +The U-Boot EFI subsystem +======================== + +Boot services +------------- + +.. kernel-doc:: lib/efi_loader/efi_boottime.c + :internal: diff --git a/Documentation/media/Makefile b/Documentation/media/Makefile new file mode 100644 index 0000000000..0efd18ab4d --- /dev/null +++ b/Documentation/media/Makefile @@ -0,0 +1,38 @@ +# Rules to convert a .h file to inline RST documentation + +SRC_DIR=$(srctree)/Documentation/media +PARSER = $(srctree)/Documentation/sphinx/parse-headers.pl +API = $(srctree)/include + +FILES = linker_lists.h.rst + +TARGETS := $(addprefix $(BUILDDIR)/, $(FILES)) + +gen_rst = \ + echo ${PARSER} $< $@ $(SRC_DIR)/$(notdir $@).exceptions; \ + ${PARSER} $< $@ $(SRC_DIR)/$(notdir $@).exceptions + +quiet_gen_rst = echo ' PARSE $(patsubst $(srctree)/%,%,$<)'; \ + ${PARSER} $< $@ $(SRC_DIR)/$(notdir $@).exceptions + +silent_gen_rst = ${gen_rst} + +$(BUILDDIR)/linker_lists.h.rst: ${API}/linker_lists.h ${PARSER} $(SRC_DIR)/linker_lists.h.rst.exceptions + @$($(quiet)gen_rst) + +# Media build rules + +.PHONY: all html epub xml latex + +all: $(IMGDOT) $(BUILDDIR) ${TARGETS} +html: all +epub: all +xml: all +latex: $(IMGPDF) all +linkcheck: + +clean: + -rm -f $(DOTTGT) $(IMGTGT) ${TARGETS} 2>/dev/null + +$(BUILDDIR): + $(Q)mkdir -p $@ diff --git a/Documentation/media/linker_lists.h.rst.exceptions b/Documentation/media/linker_lists.h.rst.exceptions new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Documentation/sphinx-static/theme_overrides.css b/Documentation/sphinx-static/theme_overrides.css new file mode 100644 index 0000000000..522b6d4c49 --- /dev/null +++ b/Documentation/sphinx-static/theme_overrides.css @@ -0,0 +1,89 @@ +/* -*- coding: utf-8; mode: css -*- + * + * Sphinx HTML theme customization: read the doc + * + */ + +/* Interim: Code-blocks with line nos - lines and line numbers don't line up. + * see: https://github.com/rtfd/sphinx_rtd_theme/issues/419 + */ + +div[class^="highlight"] pre { + line-height: normal; +} +.rst-content .highlight > pre { + line-height: normal; +} + +@media screen { + + /* content column + * + * RTD theme's default is 800px as max width for the content, but we have + * tables with tons of columns, which need the full width of the view-port. + */ + + .wy-nav-content{max-width: none; } + + /* table: + * + * - Sequences of whitespace should collapse into a single whitespace. + * - make the overflow auto (scrollbar if needed) + * - align caption "left" ("center" is unsuitable on vast tables) + */ + + .wy-table-responsive table td { white-space: normal; } + .wy-table-responsive { overflow: auto; } + .rst-content table.docutils caption { text-align: left; font-size: 100%; } + + /* captions: + * + * - captions should have 100% (not 85%) font size + * - hide the permalink symbol as long as link is not hovered + */ + + .toc-title { + font-size: 150%; + font-weight: bold; + } + + caption, .wy-table caption, .rst-content table.field-list caption { + font-size: 100%; + } + caption a.headerlink { opacity: 0; } + caption a.headerlink:hover { opacity: 1; } + + /* Menu selection and keystrokes */ + + span.menuselection { + color: blue; + font-family: "Courier New", Courier, monospace + } + + code.kbd, code.kbd span { + color: white; + background-color: darkblue; + font-weight: bold; + font-family: "Courier New", Courier, monospace + } + + /* fix bottom margin of lists items */ + + .rst-content .section ul li:last-child, .rst-content .section ul li p:last-child { + margin-bottom: 12px; + } + + /* inline literal: drop the borderbox, padding and red color */ + + code, .rst-content tt, .rst-content code { + color: inherit; + border: none; + padding: unset; + background: inherit; + font-size: 85%; + } + + .rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal { + color: inherit; + } +} diff --git a/Documentation/sphinx/cdomain.py b/Documentation/sphinx/cdomain.py new file mode 100644 index 0000000000..cf13ff3a65 --- /dev/null +++ b/Documentation/sphinx/cdomain.py @@ -0,0 +1,165 @@ +# -*- coding: utf-8; mode: python -*- +# pylint: disable=W0141,C0113,C0103,C0325 +u""" + cdomain + ~~~~~~~ + + Replacement for the sphinx c-domain. + + :copyright: Copyright (C) 2016 Markus Heiser + :license: GPL Version 2, June 1991 see Linux/COPYING for details. + + List of customizations: + + * Moved the *duplicate C object description* warnings for function + declarations in the nitpicky mode. See Sphinx documentation for + the config values for ``nitpick`` and ``nitpick_ignore``. + + * Add option 'name' to the "c:function:" directive. With option 'name' the + ref-name of a function can be modified. E.g.:: + + .. c:function:: int ioctl( int fd, int request ) + :name: VIDIOC_LOG_STATUS + + The func-name (e.g. ioctl) remains in the output but the ref-name changed + from 'ioctl' to 'VIDIOC_LOG_STATUS'. The function is referenced by:: + + * :c:func:`VIDIOC_LOG_STATUS` or + * :any:`VIDIOC_LOG_STATUS` (``:any:`` needs sphinx 1.3) + + * Handle signatures of function-like macros well. Don't try to deduce + arguments types of function-like macros. + +""" + +from docutils import nodes +from docutils.parsers.rst import directives + +import sphinx +from sphinx import addnodes +from sphinx.domains.c import c_funcptr_sig_re, c_sig_re +from sphinx.domains.c import CObject as Base_CObject +from sphinx.domains.c import CDomain as Base_CDomain + +__version__ = '1.0' + +# Get Sphinx version +major, minor, patch = sphinx.version_info[:3] + +def setup(app): + + app.override_domain(CDomain) + + return dict( + version = __version__, + parallel_read_safe = True, + parallel_write_safe = True + ) + +class CObject(Base_CObject): + + """ + Description of a C language object. + """ + option_spec = { + "name" : directives.unchanged + } + + def handle_func_like_macro(self, sig, signode): + u"""Handles signatures of function-like macros. + + If the objtype is 'function' and the the signature ``sig`` is a + function-like macro, the name of the macro is returned. Otherwise + ``False`` is returned. """ + + if not self.objtype == 'function': + return False + + m = c_funcptr_sig_re.match(sig) + if m is None: + m = c_sig_re.match(sig) + if m is None: + raise ValueError('no match') + + rettype, fullname, arglist, _const = m.groups() + arglist = arglist.strip() + if rettype or not arglist: + return False + + arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup + arglist = [a.strip() for a in arglist.split(",")] + + # has the first argument a type? + if len(arglist[0].split(" ")) > 1: + return False + + # This is a function-like macro, it's arguments are typeless! + signode += addnodes.desc_name(fullname, fullname) + paramlist = addnodes.desc_parameterlist() + signode += paramlist + + for argname in arglist: + param = addnodes.desc_parameter('', '', noemph=True) + # separate by non-breaking space in the output + param += nodes.emphasis(argname, argname) + paramlist += param + + return fullname + + def handle_signature(self, sig, signode): + """Transform a C signature into RST nodes.""" + + fullname = self.handle_func_like_macro(sig, signode) + if not fullname: + fullname = super(CObject, self).handle_signature(sig, signode) + + if "name" in self.options: + if self.objtype == 'function': + fullname = self.options["name"] + else: + # FIXME: handle :name: value of other declaration types? + pass + return fullname + + def add_target_and_index(self, name, sig, signode): + # for C API items we add a prefix since names are usually not qualified + # by a module name and so easily clash with e.g. section titles + targetname = 'c.' + name + if targetname not in self.state.document.ids: + signode['names'].append(targetname) + signode['ids'].append(targetname) + signode['first'] = (not self.names) + self.state.document.note_explicit_target(signode) + inv = self.env.domaindata['c']['objects'] + if (name in inv and self.env.config.nitpicky): + if self.objtype == 'function': + if ('c:func', name) not in self.env.config.nitpick_ignore: + self.state_machine.reporter.warning( + 'duplicate C object description of %s, ' % name + + 'other instance in ' + self.env.doc2path(inv[name][0]), + line=self.lineno) + inv[name] = (self.env.docname, self.objtype) + + indextext = self.get_index_text(name) + if indextext: + if major == 1 and minor < 4: + # indexnode's tuple changed in 1.4 + # https://github.com/sphinx-doc/sphinx/commit/e6a5a3a92e938fcd75866b4227db9e0524d58f7c + self.indexnode['entries'].append( + ('single', indextext, targetname, '')) + else: + self.indexnode['entries'].append( + ('single', indextext, targetname, '', None)) + +class CDomain(Base_CDomain): + + """C language domain.""" + name = 'c' + label = 'C' + directives = { + 'function': CObject, + 'member': CObject, + 'macro': CObject, + 'type': CObject, + 'var': CObject, + } diff --git a/Documentation/sphinx/kernel_include.py b/Documentation/sphinx/kernel_include.py new file mode 100755 index 0000000000..f523aa68a3 --- /dev/null +++ b/Documentation/sphinx/kernel_include.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8; mode: python -*- +# pylint: disable=R0903, C0330, R0914, R0912, E0401 + +u""" + kernel-include + ~~~~~~~~~~~~~~ + + Implementation of the ``kernel-include`` reST-directive. + + :copyright: Copyright (C) 2016 Markus Heiser + :license: GPL Version 2, June 1991 see linux/COPYING for details. + + The ``kernel-include`` reST-directive is a replacement for the ``include`` + directive. The ``kernel-include`` directive expand environment variables in + the path name and allows to include files from arbitrary locations. + + .. hint:: + + Including files from arbitrary locations (e.g. from ``/etc``) is a + security risk for builders. This is why the ``include`` directive from + docutils *prohibit* pathnames pointing to locations *above* the filesystem + tree where the reST document with the include directive is placed. + + Substrings of the form $name or ${name} are replaced by the value of + environment variable name. Malformed variable names and references to + non-existing variables are left unchanged. +""" + +# ============================================================================== +# imports +# ============================================================================== + +import os.path + +from docutils import io, nodes, statemachine +from docutils.utils.error_reporting import SafeString, ErrorString +from docutils.parsers.rst import directives +from docutils.parsers.rst.directives.body import CodeBlock, NumberLines +from docutils.parsers.rst.directives.misc import Include + +__version__ = '1.0' + +# ============================================================================== +def setup(app): +# ============================================================================== + + app.add_directive("kernel-include", KernelInclude) + return dict( + version = __version__, + parallel_read_safe = True, + parallel_write_safe = True + ) + +# ============================================================================== +class KernelInclude(Include): +# ============================================================================== + + u"""KernelInclude (``kernel-include``) directive""" + + def run(self): + path = os.path.realpath( + os.path.expandvars(self.arguments[0])) + + # to get a bit security back, prohibit /etc: + if path.startswith(os.sep + "etc"): + raise self.severe( + 'Problems with "%s" directive, prohibited path: %s' + % (self.name, path)) + + self.arguments[0] = path + + #return super(KernelInclude, self).run() # won't work, see HINTs in _run() + return self._run() + + def _run(self): + """Include a file as part of the content of this reST file.""" + + # HINT: I had to copy&paste the whole Include.run method. I'am not happy + # with this, but due to security reasons, the Include.run method does + # not allow absolute or relative pathnames pointing to locations *above* + # the filesystem tree where the reST document is placed. + + if not self.state.document.settings.file_insertion_enabled: + raise self.warning('"%s" directive disabled.' % self.name) + source = self.state_machine.input_lines.source( + self.lineno - self.state_machine.input_offset - 1) + source_dir = os.path.dirname(os.path.abspath(source)) + path = directives.path(self.arguments[0]) + if path.startswith('<') and path.endswith('>'): + path = os.path.join(self.standard_include_path, path[1:-1]) + path = os.path.normpath(os.path.join(source_dir, path)) + + # HINT: this is the only line I had to change / commented out: + #path = utils.relative_path(None, path) + + path = nodes.reprunicode(path) + encoding = self.options.get( + 'encoding', self.state.document.settings.input_encoding) + e_handler=self.state.document.settings.input_encoding_error_handler + tab_width = self.options.get( + 'tab-width', self.state.document.settings.tab_width) + try: + self.state.document.settings.record_dependencies.add(path) + include_file = io.FileInput(source_path=path, + encoding=encoding, + error_handler=e_handler) + except UnicodeEncodeError as error: + raise self.severe('Problems with "%s" directive path:\n' + 'Cannot encode input file path "%s" ' + '(wrong locale?).' % + (self.name, SafeString(path))) + except IOError as error: + raise self.severe('Problems with "%s" directive path:\n%s.' % + (self.name, ErrorString(error))) + startline = self.options.get('start-line', None) + endline = self.options.get('end-line', None) + try: + if startline or (endline is not None): + lines = include_file.readlines() + rawtext = ''.join(lines[startline:endline]) + else: + rawtext = include_file.read() + except UnicodeError as error: + raise self.severe('Problem with "%s" directive:\n%s' % + (self.name, ErrorString(error))) + # start-after/end-before: no restrictions on newlines in match-text, + # and no restrictions on matching inside lines vs. line boundaries + after_text = self.options.get('start-after', None) + if after_text: + # skip content in rawtext before *and incl.* a matching text + after_index = rawtext.find(after_text) + if after_index < 0: + raise self.severe('Problem with "start-after" option of "%s" ' + 'directive:\nText not found.' % self.name) + rawtext = rawtext[after_index + len(after_text):] + before_text = self.options.get('end-before', None) + if before_text: + # skip content in rawtext after *and incl.* a matching text + before_index = rawtext.find(before_text) + if before_index < 0: + raise self.severe('Problem with "end-before" option of "%s" ' + 'directive:\nText not found.' % self.name) + rawtext = rawtext[:before_index] + + include_lines = statemachine.string2lines(rawtext, tab_width, + convert_whitespace=True) + if 'literal' in self.options: + # Convert tabs to spaces, if `tab_width` is positive. + if tab_width >= 0: + text = rawtext.expandtabs(tab_width) + else: + text = rawtext + literal_block = nodes.literal_block(rawtext, source=path, + classes=self.options.get('class', [])) + literal_block.line = 1 + self.add_name(literal_block) + if 'number-lines' in self.options: + try: + startline = int(self.options['number-lines'] or 1) + except ValueError: + raise self.error(':number-lines: with non-integer ' + 'start value') + endline = startline + len(include_lines) + if text.endswith('\n'): + text = text[:-1] + tokens = NumberLines([([], text)], startline, endline) + for classes, value in tokens: + if classes: + literal_block += nodes.inline(value, value, + classes=classes) + else: + literal_block += nodes.Text(value, value) + else: + literal_block += nodes.Text(text, text) + return [literal_block] + if 'code' in self.options: + self.options['source'] = path + codeblock = CodeBlock(self.name, + [self.options.pop('code')], # arguments + self.options, + include_lines, # content + self.lineno, + self.content_offset, + self.block_text, + self.state, + self.state_machine) + return codeblock.run() + self.state_machine.insert_input(include_lines, path) + return [] diff --git a/Documentation/sphinx/kerneldoc.py b/Documentation/sphinx/kerneldoc.py new file mode 100644 index 0000000000..fbedcc3946 --- /dev/null +++ b/Documentation/sphinx/kerneldoc.py @@ -0,0 +1,146 @@ +# coding=utf-8 +# +# Copyright © 2016 Intel Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# +# Authors: +# Jani Nikula +# +# Please make sure this works on both python2 and python3. +# + +import codecs +import os +import subprocess +import sys +import re +import glob + +from docutils import nodes, statemachine +from docutils.statemachine import ViewList +from docutils.parsers.rst import directives, Directive +from sphinx.ext.autodoc import AutodocReporter + +__version__ = '1.0' + +class KernelDocDirective(Directive): + """Extract kernel-doc comments from the specified file""" + required_argument = 1 + optional_arguments = 4 + option_spec = { + 'doc': directives.unchanged_required, + 'functions': directives.unchanged_required, + 'export': directives.unchanged, + 'internal': directives.unchanged, + } + has_content = False + + def run(self): + env = self.state.document.settings.env + cmd = [env.config.kerneldoc_bin, '-rst', '-enable-lineno'] + + filename = env.config.kerneldoc_srctree + '/' + self.arguments[0] + export_file_patterns = [] + + # Tell sphinx of the dependency + env.note_dependency(os.path.abspath(filename)) + + tab_width = self.options.get('tab-width', self.state.document.settings.tab_width) + + # FIXME: make this nicer and more robust against errors + if 'export' in self.options: + cmd += ['-export'] + export_file_patterns = str(self.options.get('export')).split() + elif 'internal' in self.options: + cmd += ['-internal'] + export_file_patterns = str(self.options.get('internal')).split() + elif 'doc' in self.options: + cmd += ['-function', str(self.options.get('doc'))] + elif 'functions' in self.options: + for f in str(self.options.get('functions')).split(): + cmd += ['-function', f] + + for pattern in export_file_patterns: + for f in glob.glob(env.config.kerneldoc_srctree + '/' + pattern): + env.note_dependency(os.path.abspath(f)) + cmd += ['-export-file', f] + + cmd += [filename] + + try: + env.app.verbose('calling kernel-doc \'%s\'' % (" ".join(cmd))) + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = p.communicate() + + out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8') + + if p.returncode != 0: + sys.stderr.write(err) + + env.app.warn('kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode)) + return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))] + elif env.config.kerneldoc_verbosity > 0: + sys.stderr.write(err) + + lines = statemachine.string2lines(out, tab_width, convert_whitespace=True) + result = ViewList() + + lineoffset = 0; + line_regex = re.compile("^#define LINENO ([0-9]+)$") + for line in lines: + match = line_regex.search(line) + if match: + # sphinx counts lines from 0 + lineoffset = int(match.group(1)) - 1 + # we must eat our comments since the upset the markup + else: + result.append(line, filename, lineoffset) + lineoffset += 1 + + node = nodes.section() + buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter + self.state.memo.reporter = AutodocReporter(result, self.state.memo.reporter) + self.state.memo.title_styles, self.state.memo.section_level = [], 0 + try: + self.state.nested_parse(result, 0, node, match_titles=1) + finally: + self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter = buf + + return node.children + + except Exception as e: # pylint: disable=W0703 + env.app.warn('kernel-doc \'%s\' processing failed with: %s' % + (" ".join(cmd), str(e))) + return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))] + +def setup(app): + app.add_config_value('kerneldoc_bin', None, 'env') + app.add_config_value('kerneldoc_srctree', None, 'env') + app.add_config_value('kerneldoc_verbosity', 1, 'env') + + app.add_directive('kernel-doc', KernelDocDirective) + + return dict( + version = __version__, + parallel_read_safe = True, + parallel_write_safe = True + ) diff --git a/Documentation/sphinx/kfigure.py b/Documentation/sphinx/kfigure.py new file mode 100644 index 0000000000..b97228d2cc --- /dev/null +++ b/Documentation/sphinx/kfigure.py @@ -0,0 +1,551 @@ +# -*- coding: utf-8; mode: python -*- +# pylint: disable=C0103, R0903, R0912, R0915 +u""" + scalable figure and image handling + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Sphinx extension which implements scalable image handling. + + :copyright: Copyright (C) 2016 Markus Heiser + :license: GPL Version 2, June 1991 see Linux/COPYING for details. + + The build for image formats depend on image's source format and output's + destination format. This extension implement methods to simplify image + handling from the author's POV. Directives like ``kernel-figure`` implement + methods *to* always get the best output-format even if some tools are not + installed. For more details take a look at ``convert_image(...)`` which is + the core of all conversions. + + * ``.. kernel-image``: for image handling / a ``.. image::`` replacement + + * ``.. kernel-figure``: for figure handling / a ``.. figure::`` replacement + + * ``.. kernel-render``: for render markup / a concept to embed *render* + markups (or languages). Supported markups (see ``RENDER_MARKUP_EXT``) + + - ``DOT``: render embedded Graphviz's **DOC** + - ``SVG``: render embedded Scalable Vector Graphics (**SVG**) + - ... *developable* + + Used tools: + + * ``dot(1)``: Graphviz (http://www.graphviz.org). If Graphviz is not + available, the DOT language is inserted as literal-block. + + * SVG to PDF: To generate PDF, you need at least one of this tools: + + - ``convert(1)``: ImageMagick (https://www.imagemagick.org) + + List of customizations: + + * generate PDF from SVG / used by PDF (LaTeX) builder + + * generate SVG (html-builder) and PDF (latex-builder) from DOT files. + DOT: see http://www.graphviz.org/content/dot-language + + """ + +import os +from os import path +import subprocess +from hashlib import sha1 +import sys + +from docutils import nodes +from docutils.statemachine import ViewList +from docutils.parsers.rst import directives +from docutils.parsers.rst.directives import images +import sphinx + +from sphinx.util.nodes import clean_astext +from six import iteritems + +PY3 = sys.version_info[0] == 3 + +if PY3: + _unicode = str +else: + _unicode = unicode + +# Get Sphinx version +major, minor, patch = sphinx.version_info[:3] +if major == 1 and minor > 3: + # patches.Figure only landed in Sphinx 1.4 + from sphinx.directives.patches import Figure # pylint: disable=C0413 +else: + Figure = images.Figure + +__version__ = '1.0.0' + +# simple helper +# ------------- + +def which(cmd): + """Searches the ``cmd`` in the ``PATH`` environment. + + This *which* searches the PATH for executable ``cmd`` . First match is + returned, if nothing is found, ``None` is returned. + """ + envpath = os.environ.get('PATH', None) or os.defpath + for folder in envpath.split(os.pathsep): + fname = folder + os.sep + cmd + if path.isfile(fname): + return fname + +def mkdir(folder, mode=0o775): + if not path.isdir(folder): + os.makedirs(folder, mode) + +def file2literal(fname): + with open(fname, "r") as src: + data = src.read() + node = nodes.literal_block(data, data) + return node + +def isNewer(path1, path2): + """Returns True if ``path1`` is newer than ``path2`` + + If ``path1`` exists and is newer than ``path2`` the function returns + ``True`` is returned otherwise ``False`` + """ + return (path.exists(path1) + and os.stat(path1).st_ctime > os.stat(path2).st_ctime) + +def pass_handle(self, node): # pylint: disable=W0613 + pass + +# setup conversion tools and sphinx extension +# ------------------------------------------- + +# Graphviz's dot(1) support +dot_cmd = None + +# ImageMagick' convert(1) support +convert_cmd = None + + +def setup(app): + # check toolchain first + app.connect('builder-inited', setupTools) + + # image handling + app.add_directive("kernel-image", KernelImage) + app.add_node(kernel_image, + html = (visit_kernel_image, pass_handle), + latex = (visit_kernel_image, pass_handle), + texinfo = (visit_kernel_image, pass_handle), + text = (visit_kernel_image, pass_handle), + man = (visit_kernel_image, pass_handle), ) + + # figure handling + app.add_directive("kernel-figure", KernelFigure) + app.add_node(kernel_figure, + html = (visit_kernel_figure, pass_handle), + latex = (visit_kernel_figure, pass_handle), + texinfo = (visit_kernel_figure, pass_handle), + text = (visit_kernel_figure, pass_handle), + man = (visit_kernel_figure, pass_handle), ) + + # render handling + app.add_directive('kernel-render', KernelRender) + app.add_node(kernel_render, + html = (visit_kernel_render, pass_handle), + latex = (visit_kernel_render, pass_handle), + texinfo = (visit_kernel_render, pass_handle), + text = (visit_kernel_render, pass_handle), + man = (visit_kernel_render, pass_handle), ) + + app.connect('doctree-read', add_kernel_figure_to_std_domain) + + return dict( + version = __version__, + parallel_read_safe = True, + parallel_write_safe = True + ) + + +def setupTools(app): + u""" + Check available build tools and log some *verbose* messages. + + This function is called once, when the builder is initiated. + """ + global dot_cmd, convert_cmd # pylint: disable=W0603 + app.verbose("kfigure: check installed tools ...") + + dot_cmd = which('dot') + convert_cmd = which('convert') + + if dot_cmd: + app.verbose("use dot(1) from: " + dot_cmd) + else: + app.warn("dot(1) not found, for better output quality install " + "graphviz from http://www.graphviz.org") + if convert_cmd: + app.verbose("use convert(1) from: " + convert_cmd) + else: + app.warn( + "convert(1) not found, for SVG to PDF conversion install " + "ImageMagick (https://www.imagemagick.org)") + + +# integrate conversion tools +# -------------------------- + +RENDER_MARKUP_EXT = { + # The '.ext' must be handled by convert_image(..) function's *in_ext* input. + # : <.ext> + 'DOT' : '.dot', + 'SVG' : '.svg' +} + +def convert_image(img_node, translator, src_fname=None): + """Convert a image node for the builder. + + Different builder prefer different image formats, e.g. *latex* builder + prefer PDF while *html* builder prefer SVG format for images. + + This function handles output image formats in dependence of source the + format (of the image) and the translator's output format. + """ + app = translator.builder.app + + fname, in_ext = path.splitext(path.basename(img_node['uri'])) + if src_fname is None: + src_fname = path.join(translator.builder.srcdir, img_node['uri']) + if not path.exists(src_fname): + src_fname = path.join(translator.builder.outdir, img_node['uri']) + + dst_fname = None + + # in kernel builds, use 'make SPHINXOPTS=-v' to see verbose messages + + app.verbose('assert best format for: ' + img_node['uri']) + + if in_ext == '.dot': + + if not dot_cmd: + app.verbose("dot from graphviz not available / include DOT raw.") + img_node.replace_self(file2literal(src_fname)) + + elif translator.builder.format == 'latex': + dst_fname = path.join(translator.builder.outdir, fname + '.pdf') + img_node['uri'] = fname + '.pdf' + img_node['candidates'] = {'*': fname + '.pdf'} + + + elif translator.builder.format == 'html': + dst_fname = path.join( + translator.builder.outdir, + translator.builder.imagedir, + fname + '.svg') + img_node['uri'] = path.join( + translator.builder.imgpath, fname + '.svg') + img_node['candidates'] = { + '*': path.join(translator.builder.imgpath, fname + '.svg')} + + else: + # all other builder formats will include DOT as raw + img_node.replace_self(file2literal(src_fname)) + + elif in_ext == '.svg': + + if translator.builder.format == 'latex': + if convert_cmd is None: + app.verbose("no SVG to PDF conversion available / include SVG raw.") + img_node.replace_self(file2literal(src_fname)) + else: + dst_fname = path.join(translator.builder.outdir, fname + '.pdf') + img_node['uri'] = fname + '.pdf' + img_node['candidates'] = {'*': fname + '.pdf'} + + if dst_fname: + # the builder needs not to copy one more time, so pop it if exists. + translator.builder.images.pop(img_node['uri'], None) + _name = dst_fname[len(translator.builder.outdir) + 1:] + + if isNewer(dst_fname, src_fname): + app.verbose("convert: {out}/%s already exists and is newer" % _name) + + else: + ok = False + mkdir(path.dirname(dst_fname)) + + if in_ext == '.dot': + app.verbose('convert DOT to: {out}/' + _name) + ok = dot2format(app, src_fname, dst_fname) + + elif in_ext == '.svg': + app.verbose('convert SVG to: {out}/' + _name) + ok = svg2pdf(app, src_fname, dst_fname) + + if not ok: + img_node.replace_self(file2literal(src_fname)) + + +def dot2format(app, dot_fname, out_fname): + """Converts DOT file to ``out_fname`` using ``dot(1)``. + + * ``dot_fname`` pathname of the input DOT file, including extension ``.dot`` + * ``out_fname`` pathname of the output file, including format extension + + The *format extension* depends on the ``dot`` command (see ``man dot`` + option ``-Txxx``). Normally you will use one of the following extensions: + + - ``.ps`` for PostScript, + - ``.svg`` or ``svgz`` for Structured Vector Graphics, + - ``.fig`` for XFIG graphics and + - ``.png`` or ``gif`` for common bitmap graphics. + + """ + out_format = path.splitext(out_fname)[1][1:] + cmd = [dot_cmd, '-T%s' % out_format, dot_fname] + exit_code = 42 + + with open(out_fname, "w") as out: + exit_code = subprocess.call(cmd, stdout = out) + if exit_code != 0: + app.warn("Error #%d when calling: %s" % (exit_code, " ".join(cmd))) + return bool(exit_code == 0) + +def svg2pdf(app, svg_fname, pdf_fname): + """Converts SVG to PDF with ``convert(1)`` command. + + Uses ``convert(1)`` from ImageMagick (https://www.imagemagick.org) for + conversion. Returns ``True`` on success and ``False`` if an error occurred. + + * ``svg_fname`` pathname of the input SVG file with extension (``.svg``) + * ``pdf_name`` pathname of the output PDF file with extension (``.pdf``) + + """ + cmd = [convert_cmd, svg_fname, pdf_fname] + # use stdout and stderr from parent + exit_code = subprocess.call(cmd) + if exit_code != 0: + app.warn("Error #%d when calling: %s" % (exit_code, " ".join(cmd))) + return bool(exit_code == 0) + + +# image handling +# --------------------- + +def visit_kernel_image(self, node): # pylint: disable=W0613 + """Visitor of the ``kernel_image`` Node. + + Handles the ``image`` child-node with the ``convert_image(...)``. + """ + img_node = node[0] + convert_image(img_node, self) + +class kernel_image(nodes.image): + """Node for ``kernel-image`` directive.""" + pass + +class KernelImage(images.Image): + u"""KernelImage directive + + Earns everything from ``.. image::`` directive, except *remote URI* and + *glob* pattern. The KernelImage wraps a image node into a + kernel_image node. See ``visit_kernel_image``. + """ + + def run(self): + uri = self.arguments[0] + if uri.endswith('.*') or uri.find('://') != -1: + raise self.severe( + 'Error in "%s: %s": glob pattern and remote images are not allowed' + % (self.name, uri)) + result = images.Image.run(self) + if len(result) == 2 or isinstance(result[0], nodes.system_message): + return result + (image_node,) = result + # wrap image node into a kernel_image node / see visitors + node = kernel_image('', image_node) + return [node] + +# figure handling +# --------------------- + +def visit_kernel_figure(self, node): # pylint: disable=W0613 + """Visitor of the ``kernel_figure`` Node. + + Handles the ``image`` child-node with the ``convert_image(...)``. + """ + img_node = node[0][0] + convert_image(img_node, self) + +class kernel_figure(nodes.figure): + """Node for ``kernel-figure`` directive.""" + +class KernelFigure(Figure): + u"""KernelImage directive + + Earns everything from ``.. figure::`` directive, except *remote URI* and + *glob* pattern. The KernelFigure wraps a figure node into a kernel_figure + node. See ``visit_kernel_figure``. + """ + + def run(self): + uri = self.arguments[0] + if uri.endswith('.*') or uri.find('://') != -1: + raise self.severe( + 'Error in "%s: %s":' + ' glob pattern and remote images are not allowed' + % (self.name, uri)) + result = Figure.run(self) + if len(result) == 2 or isinstance(result[0], nodes.system_message): + return result + (figure_node,) = result + # wrap figure node into a kernel_figure node / see visitors + node = kernel_figure('', figure_node) + return [node] + + +# render handling +# --------------------- + +def visit_kernel_render(self, node): + """Visitor of the ``kernel_render`` Node. + + If rendering tools available, save the markup of the ``literal_block`` child + node into a file and replace the ``literal_block`` node with a new created + ``image`` node, pointing to the saved markup file. Afterwards, handle the + image child-node with the ``convert_image(...)``. + """ + app = self.builder.app + srclang = node.get('srclang') + + app.verbose('visit kernel-render node lang: "%s"' % (srclang)) + + tmp_ext = RENDER_MARKUP_EXT.get(srclang, None) + if tmp_ext is None: + app.warn('kernel-render: "%s" unknown / include raw.' % (srclang)) + return + + if not dot_cmd and tmp_ext == '.dot': + app.verbose("dot from graphviz not available / include raw.") + return + + literal_block = node[0] + + code = literal_block.astext() + hashobj = code.encode('utf-8') # str(node.attributes) + fname = path.join('%s-%s' % (srclang, sha1(hashobj).hexdigest())) + + tmp_fname = path.join( + self.builder.outdir, self.builder.imagedir, fname + tmp_ext) + + if not path.isfile(tmp_fname): + mkdir(path.dirname(tmp_fname)) + with open(tmp_fname, "w") as out: + out.write(code) + + img_node = nodes.image(node.rawsource, **node.attributes) + img_node['uri'] = path.join(self.builder.imgpath, fname + tmp_ext) + img_node['candidates'] = { + '*': path.join(self.builder.imgpath, fname + tmp_ext)} + + literal_block.replace_self(img_node) + convert_image(img_node, self, tmp_fname) + + +class kernel_render(nodes.General, nodes.Inline, nodes.Element): + """Node for ``kernel-render`` directive.""" + pass + +class KernelRender(Figure): + u"""KernelRender directive + + Render content by external tool. Has all the options known from the + *figure* directive, plus option ``caption``. If ``caption`` has a + value, a figure node with the *caption* is inserted. If not, a image node is + inserted. + + The KernelRender directive wraps the text of the directive into a + literal_block node and wraps it into a kernel_render node. See + ``visit_kernel_render``. + """ + has_content = True + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = False + + # earn options from 'figure' + option_spec = Figure.option_spec.copy() + option_spec['caption'] = directives.unchanged + + def run(self): + return [self.build_node()] + + def build_node(self): + + srclang = self.arguments[0].strip() + if srclang not in RENDER_MARKUP_EXT.keys(): + return [self.state_machine.reporter.warning( + 'Unknown source language "%s", use one of: %s.' % ( + srclang, ",".join(RENDER_MARKUP_EXT.keys())), + line=self.lineno)] + + code = '\n'.join(self.content) + if not code.strip(): + return [self.state_machine.reporter.warning( + 'Ignoring "%s" directive without content.' % ( + self.name), + line=self.lineno)] + + node = kernel_render() + node['alt'] = self.options.get('alt','') + node['srclang'] = srclang + literal_node = nodes.literal_block(code, code) + node += literal_node + + caption = self.options.get('caption') + if caption: + # parse caption's content + parsed = nodes.Element() + self.state.nested_parse( + ViewList([caption], source=''), self.content_offset, parsed) + caption_node = nodes.caption( + parsed[0].rawsource, '', *parsed[0].children) + caption_node.source = parsed[0].source + caption_node.line = parsed[0].line + + figure_node = nodes.figure('', node) + for k,v in self.options.items(): + figure_node[k] = v + figure_node += caption_node + + node = figure_node + + return node + +def add_kernel_figure_to_std_domain(app, doctree): + """Add kernel-figure anchors to 'std' domain. + + The ``StandardDomain.process_doc(..)`` method does not know how to resolve + the caption (label) of ``kernel-figure`` directive (it only knows about + standard nodes, e.g. table, figure etc.). Without any additional handling + this will result in a 'undefined label' for kernel-figures. + + This handle adds labels of kernel-figure to the 'std' domain labels. + """ + + std = app.env.domains["std"] + docname = app.env.docname + labels = std.data["labels"] + + for name, explicit in iteritems(doctree.nametypes): + if not explicit: + continue + labelid = doctree.nameids[name] + if labelid is None: + continue + node = doctree.ids[labelid] + + if node.tagname == 'kernel_figure': + for n in node.next_node(): + if n.tagname == 'caption': + sectname = clean_astext(n) + # add label to std domain + labels[name] = docname, labelid, sectname + break diff --git a/Documentation/sphinx/load_config.py b/Documentation/sphinx/load_config.py new file mode 100644 index 0000000000..301a21aa4f --- /dev/null +++ b/Documentation/sphinx/load_config.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8; mode: python -*- +# pylint: disable=R0903, C0330, R0914, R0912, E0401 + +import os +import sys +from sphinx.util.pycompat import execfile_ + +# ------------------------------------------------------------------------------ +def loadConfig(namespace): +# ------------------------------------------------------------------------------ + + u"""Load an additional configuration file into *namespace*. + + The name of the configuration file is taken from the environment + ``SPHINX_CONF``. The external configuration file extends (or overwrites) the + configuration values from the origin ``conf.py``. With this you are able to + maintain *build themes*. """ + + config_file = os.environ.get("SPHINX_CONF", None) + if (config_file is not None + and os.path.normpath(namespace["__file__"]) != os.path.normpath(config_file) ): + config_file = os.path.abspath(config_file) + + if os.path.isfile(config_file): + sys.stdout.write("load additional sphinx-config: %s\n" % config_file) + config = namespace.copy() + config['__file__'] = config_file + execfile_(config_file, config) + del config['__file__'] + namespace.update(config) + else: + sys.stderr.write("WARNING: additional sphinx-config not found: %s\n" % config_file) diff --git a/Documentation/sphinx/parse-headers.pl b/Documentation/sphinx/parse-headers.pl new file mode 100755 index 0000000000..d410f47567 --- /dev/null +++ b/Documentation/sphinx/parse-headers.pl @@ -0,0 +1,401 @@ +#!/usr/bin/perl +use strict; +use Text::Tabs; +use Getopt::Long; +use Pod::Usage; + +my $debug; +my $help; +my $man; + +GetOptions( + "debug" => \$debug, + 'usage|?' => \$help, + 'help' => \$man +) or pod2usage(2); + +pod2usage(1) if $help; +pod2usage(-exitstatus => 0, -verbose => 2) if $man; +pod2usage(2) if (scalar @ARGV < 2 || scalar @ARGV > 3); + +my ($file_in, $file_out, $file_exceptions) = @ARGV; + +my $data; +my %ioctls; +my %defines; +my %typedefs; +my %enums; +my %enum_symbols; +my %structs; + +require Data::Dumper if ($debug); + +# +# read the file and get identifiers +# + +my $is_enum = 0; +my $is_comment = 0; +open IN, $file_in or die "Can't open $file_in"; +while () { + $data .= $_; + + my $ln = $_; + if (!$is_comment) { + $ln =~ s,/\*.*(\*/),,g; + + $is_comment = 1 if ($ln =~ s,/\*.*,,); + } else { + if ($ln =~ s,^(.*\*/),,) { + $is_comment = 0; + } else { + next; + } + } + + if ($is_enum && $ln =~ m/^\s*([_\w][\w\d_]+)\s*[\,=]?/) { + my $s = $1; + my $n = $1; + $n =~ tr/A-Z/a-z/; + $n =~ tr/_/-/; + + $enum_symbols{$s} = "\\ :ref:`$s <$n>`\\ "; + + $is_enum = 0 if ($is_enum && m/\}/); + next; + } + $is_enum = 0 if ($is_enum && m/\}/); + + if ($ln =~ m/^\s*#\s*define\s+([_\w][\w\d_]+)\s+_IO/) { + my $s = $1; + my $n = $1; + $n =~ tr/A-Z/a-z/; + + $ioctls{$s} = "\\ :ref:`$s <$n>`\\ "; + next; + } + + if ($ln =~ m/^\s*#\s*define\s+([_\w][\w\d_]+)\s+/) { + my $s = $1; + my $n = $1; + $n =~ tr/A-Z/a-z/; + $n =~ tr/_/-/; + + $defines{$s} = "\\ :ref:`$s <$n>`\\ "; + next; + } + + if ($ln =~ m/^\s*typedef\s+([_\w][\w\d_]+)\s+(.*)\s+([_\w][\w\d_]+);/) { + my $s = $2; + my $n = $3; + + $typedefs{$n} = "\\ :c:type:`$n <$s>`\\ "; + next; + } + if ($ln =~ m/^\s*enum\s+([_\w][\w\d_]+)\s+\{/ + || $ln =~ m/^\s*enum\s+([_\w][\w\d_]+)$/ + || $ln =~ m/^\s*typedef\s*enum\s+([_\w][\w\d_]+)\s+\{/ + || $ln =~ m/^\s*typedef\s*enum\s+([_\w][\w\d_]+)$/) { + my $s = $1; + + $enums{$s} = "enum :c:type:`$s`\\ "; + + $is_enum = $1; + next; + } + if ($ln =~ m/^\s*struct\s+([_\w][\w\d_]+)\s+\{/ + || $ln =~ m/^\s*struct\s+([[_\w][\w\d_]+)$/ + || $ln =~ m/^\s*typedef\s*struct\s+([_\w][\w\d_]+)\s+\{/ + || $ln =~ m/^\s*typedef\s*struct\s+([[_\w][\w\d_]+)$/ + ) { + my $s = $1; + + $structs{$s} = "struct :c:type:`$s`\\ "; + next; + } +} +close IN; + +# +# Handle multi-line typedefs +# + +my @matches = ($data =~ m/typedef\s+struct\s+\S+?\s*\{[^\}]+\}\s*(\S+)\s*\;/g, + $data =~ m/typedef\s+enum\s+\S+?\s*\{[^\}]+\}\s*(\S+)\s*\;/g,); +foreach my $m (@matches) { + my $s = $m; + + $typedefs{$s} = "\\ :c:type:`$s`\\ "; + next; +} + +# +# Handle exceptions, if any +# + +my %def_reftype = ( + "ioctl" => ":ref", + "define" => ":ref", + "symbol" => ":ref", + "typedef" => ":c:type", + "enum" => ":c:type", + "struct" => ":c:type", +); + +if ($file_exceptions) { + open IN, $file_exceptions or die "Can't read $file_exceptions"; + while () { + next if (m/^\s*$/ || m/^\s*#/); + + # Parsers to ignore a symbol + + if (m/^ignore\s+ioctl\s+(\S+)/) { + delete $ioctls{$1} if (exists($ioctls{$1})); + next; + } + if (m/^ignore\s+define\s+(\S+)/) { + delete $defines{$1} if (exists($defines{$1})); + next; + } + if (m/^ignore\s+typedef\s+(\S+)/) { + delete $typedefs{$1} if (exists($typedefs{$1})); + next; + } + if (m/^ignore\s+enum\s+(\S+)/) { + delete $enums{$1} if (exists($enums{$1})); + next; + } + if (m/^ignore\s+struct\s+(\S+)/) { + delete $structs{$1} if (exists($structs{$1})); + next; + } + if (m/^ignore\s+symbol\s+(\S+)/) { + delete $enum_symbols{$1} if (exists($enum_symbols{$1})); + next; + } + + # Parsers to replace a symbol + my ($type, $old, $new, $reftype); + + if (m/^replace\s+(\S+)\s+(\S+)\s+(\S+)/) { + $type = $1; + $old = $2; + $new = $3; + } else { + die "Can't parse $file_exceptions: $_"; + } + + if ($new =~ m/^\:c\:(data|func|macro|type)\:\`(.+)\`/) { + $reftype = ":c:$1"; + $new = $2; + } elsif ($new =~ m/\:ref\:\`(.+)\`/) { + $reftype = ":ref"; + $new = $1; + } else { + $reftype = $def_reftype{$type}; + } + $new = "$reftype:`$old <$new>`"; + + if ($type eq "ioctl") { + $ioctls{$old} = $new if (exists($ioctls{$old})); + next; + } + if ($type eq "define") { + $defines{$old} = $new if (exists($defines{$old})); + next; + } + if ($type eq "symbol") { + $enum_symbols{$old} = $new if (exists($enum_symbols{$old})); + next; + } + if ($type eq "typedef") { + $typedefs{$old} = $new if (exists($typedefs{$old})); + next; + } + if ($type eq "enum") { + $enums{$old} = $new if (exists($enums{$old})); + next; + } + if ($type eq "struct") { + $structs{$old} = $new if (exists($structs{$old})); + next; + } + + die "Can't parse $file_exceptions: $_"; + } +} + +if ($debug) { + print Data::Dumper->Dump([\%ioctls], [qw(*ioctls)]) if (%ioctls); + print Data::Dumper->Dump([\%typedefs], [qw(*typedefs)]) if (%typedefs); + print Data::Dumper->Dump([\%enums], [qw(*enums)]) if (%enums); + print Data::Dumper->Dump([\%structs], [qw(*structs)]) if (%structs); + print Data::Dumper->Dump([\%defines], [qw(*defines)]) if (%defines); + print Data::Dumper->Dump([\%enum_symbols], [qw(*enum_symbols)]) if (%enum_symbols); +} + +# +# Align block +# +$data = expand($data); +$data = " " . $data; +$data =~ s/\n/\n /g; +$data =~ s/\n\s+$/\n/g; +$data =~ s/\n\s+\n/\n\n/g; + +# +# Add escape codes for special characters +# +$data =~ s,([\_\`\*\<\>\&\\\\:\/\|\%\$\#\{\}\~\^]),\\$1,g; + +$data =~ s,DEPRECATED,**DEPRECATED**,g; + +# +# Add references +# + +my $start_delim = "[ \n\t\(\=\*\@]"; +my $end_delim = "(\\s|,|\\\\=|\\\\:|\\;|\\\)|\\}|\\{)"; + +foreach my $r (keys %ioctls) { + my $s = $ioctls{$r}; + + $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; + + print "$r -> $s\n" if ($debug); + + $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g; +} + +foreach my $r (keys %defines) { + my $s = $defines{$r}; + + $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; + + print "$r -> $s\n" if ($debug); + + $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g; +} + +foreach my $r (keys %enum_symbols) { + my $s = $enum_symbols{$r}; + + $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; + + print "$r -> $s\n" if ($debug); + + $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g; +} + +foreach my $r (keys %enums) { + my $s = $enums{$r}; + + $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; + + print "$r -> $s\n" if ($debug); + + $data =~ s/enum\s+($r)$end_delim/$s$2/g; +} + +foreach my $r (keys %structs) { + my $s = $structs{$r}; + + $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; + + print "$r -> $s\n" if ($debug); + + $data =~ s/struct\s+($r)$end_delim/$s$2/g; +} + +foreach my $r (keys %typedefs) { + my $s = $typedefs{$r}; + + $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; + + print "$r -> $s\n" if ($debug); + $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g; +} + +$data =~ s/\\ ([\n\s])/\1/g; + +# +# Generate output file +# + +my $title = $file_in; +$title =~ s,.*/,,; + +open OUT, "> $file_out" or die "Can't open $file_out"; +print OUT ".. -*- coding: utf-8; mode: rst -*-\n\n"; +print OUT "$title\n"; +print OUT "=" x length($title); +print OUT "\n\n.. parsed-literal::\n\n"; +print OUT $data; +close OUT; + +__END__ + +=head1 NAME + +parse_headers.pl - parse a C file, in order to identify functions, structs, +enums and defines and create cross-references to a Sphinx book. + +=head1 SYNOPSIS + +B [] [] + +Where can be: --debug, --help or --man. + +=head1 OPTIONS + +=over 8 + +=item B<--debug> + +Put the script in verbose mode, useful for debugging. + +=item B<--usage> + +Prints a brief help message and exits. + +=item B<--help> + +Prints a more detailed help message and exits. + +=back + +=head1 DESCRIPTION + +Convert a C header or source file (C_FILE), into a ReStructured Text +included via ..parsed-literal block with cross-references for the +documentation files that describe the API. It accepts an optional +EXCEPTIONS_FILE with describes what elements will be either ignored or +be pointed to a non-default reference. + +The output is written at the (OUT_FILE). + +It is capable of identifying defines, functions, structs, typedefs, +enums and enum symbols and create cross-references for all of them. +It is also capable of distinguish #define used for specifying a Linux +ioctl. + +The EXCEPTIONS_FILE contain two rules to allow ignoring a symbol or +to replace the default references by a custom one. + +Please read Documentation/doc-guide/parse-headers.rst at the Kernel's +tree for more details. + +=head1 BUGS + +Report bugs to Mauro Carvalho Chehab + +=head1 COPYRIGHT + +Copyright (c) 2016 by Mauro Carvalho Chehab . + +License GPLv2: GNU GPL version 2 . + +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. + +=cut diff --git a/Documentation/sphinx/requirements.txt b/Documentation/sphinx/requirements.txt new file mode 100644 index 0000000000..742be3e126 --- /dev/null +++ b/Documentation/sphinx/requirements.txt @@ -0,0 +1,3 @@ +docutils==0.12 +Sphinx==1.4.9 +sphinx_rtd_theme diff --git a/Documentation/sphinx/rstFlatTable.py b/Documentation/sphinx/rstFlatTable.py new file mode 100755 index 0000000000..25feb0d35e --- /dev/null +++ b/Documentation/sphinx/rstFlatTable.py @@ -0,0 +1,376 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8; mode: python -*- +# pylint: disable=C0330, R0903, R0912 + +u""" + flat-table + ~~~~~~~~~~ + + Implementation of the ``flat-table`` reST-directive. + + :copyright: Copyright (C) 2016 Markus Heiser + :license: GPL Version 2, June 1991 see linux/COPYING for details. + + The ``flat-table`` (:py:class:`FlatTable`) is a double-stage list similar to + the ``list-table`` with some additional features: + + * *column-span*: with the role ``cspan`` a cell can be extended through + additional columns + + * *row-span*: with the role ``rspan`` a cell can be extended through + additional rows + + * *auto span* rightmost cell of a table row over the missing cells on the + right side of that table-row. With Option ``:fill-cells:`` this behavior + can changed from *auto span* to *auto fill*, which automaticly inserts + (empty) cells instead of spanning the last cell. + + Options: + + * header-rows: [int] count of header rows + * stub-columns: [int] count of stub columns + * widths: [[int] [int] ... ] widths of columns + * fill-cells: instead of autospann missing cells, insert missing cells + + roles: + + * cspan: [int] additionale columns (*morecols*) + * rspan: [int] additionale rows (*morerows*) +""" + +# ============================================================================== +# imports +# ============================================================================== + +import sys + +from docutils import nodes +from docutils.parsers.rst import directives, roles +from docutils.parsers.rst.directives.tables import Table +from docutils.utils import SystemMessagePropagation + +# ============================================================================== +# common globals +# ============================================================================== + +# The version numbering follows numbering of the specification +# (Documentation/books/kernel-doc-HOWTO). +__version__ = '1.0' + +PY3 = sys.version_info[0] == 3 +PY2 = sys.version_info[0] == 2 + +if PY3: + # pylint: disable=C0103, W0622 + unicode = str + basestring = str + +# ============================================================================== +def setup(app): +# ============================================================================== + + app.add_directive("flat-table", FlatTable) + roles.register_local_role('cspan', c_span) + roles.register_local_role('rspan', r_span) + + return dict( + version = __version__, + parallel_read_safe = True, + parallel_write_safe = True + ) + +# ============================================================================== +def c_span(name, rawtext, text, lineno, inliner, options=None, content=None): +# ============================================================================== + # pylint: disable=W0613 + + options = options if options is not None else {} + content = content if content is not None else [] + nodelist = [colSpan(span=int(text))] + msglist = [] + return nodelist, msglist + +# ============================================================================== +def r_span(name, rawtext, text, lineno, inliner, options=None, content=None): +# ============================================================================== + # pylint: disable=W0613 + + options = options if options is not None else {} + content = content if content is not None else [] + nodelist = [rowSpan(span=int(text))] + msglist = [] + return nodelist, msglist + + +# ============================================================================== +class rowSpan(nodes.General, nodes.Element): pass # pylint: disable=C0103,C0321 +class colSpan(nodes.General, nodes.Element): pass # pylint: disable=C0103,C0321 +# ============================================================================== + +# ============================================================================== +class FlatTable(Table): +# ============================================================================== + + u"""FlatTable (``flat-table``) directive""" + + option_spec = { + 'name': directives.unchanged + , 'class': directives.class_option + , 'header-rows': directives.nonnegative_int + , 'stub-columns': directives.nonnegative_int + , 'widths': directives.positive_int_list + , 'fill-cells' : directives.flag } + + def run(self): + + if not self.content: + error = self.state_machine.reporter.error( + 'The "%s" directive is empty; content required.' % self.name, + nodes.literal_block(self.block_text, self.block_text), + line=self.lineno) + return [error] + + title, messages = self.make_title() + node = nodes.Element() # anonymous container for parsing + self.state.nested_parse(self.content, self.content_offset, node) + + tableBuilder = ListTableBuilder(self) + tableBuilder.parseFlatTableNode(node) + tableNode = tableBuilder.buildTableNode() + # SDK.CONSOLE() # print --> tableNode.asdom().toprettyxml() + if title: + tableNode.insert(0, title) + return [tableNode] + messages + + +# ============================================================================== +class ListTableBuilder(object): +# ============================================================================== + + u"""Builds a table from a double-stage list""" + + def __init__(self, directive): + self.directive = directive + self.rows = [] + self.max_cols = 0 + + def buildTableNode(self): + + colwidths = self.directive.get_column_widths(self.max_cols) + if isinstance(colwidths, tuple): + # Since docutils 0.13, get_column_widths returns a (widths, + # colwidths) tuple, where widths is a string (i.e. 'auto'). + # See https://sourceforge.net/p/docutils/patches/120/. + colwidths = colwidths[1] + stub_columns = self.directive.options.get('stub-columns', 0) + header_rows = self.directive.options.get('header-rows', 0) + + table = nodes.table() + tgroup = nodes.tgroup(cols=len(colwidths)) + table += tgroup + + + for colwidth in colwidths: + colspec = nodes.colspec(colwidth=colwidth) + # FIXME: It seems, that the stub method only works well in the + # absence of rowspan (observed by the html buidler, the docutils-xml + # build seems OK). This is not extraordinary, because there exists + # no table directive (except *this* flat-table) which allows to + # define coexistent of rowspan and stubs (there was no use-case + # before flat-table). This should be reviewed (later). + if stub_columns: + colspec.attributes['stub'] = 1 + stub_columns -= 1 + tgroup += colspec + stub_columns = self.directive.options.get('stub-columns', 0) + + if header_rows: + thead = nodes.thead() + tgroup += thead + for row in self.rows[:header_rows]: + thead += self.buildTableRowNode(row) + + tbody = nodes.tbody() + tgroup += tbody + + for row in self.rows[header_rows:]: + tbody += self.buildTableRowNode(row) + return table + + def buildTableRowNode(self, row_data, classes=None): + classes = [] if classes is None else classes + row = nodes.row() + for cell in row_data: + if cell is None: + continue + cspan, rspan, cellElements = cell + + attributes = {"classes" : classes} + if rspan: + attributes['morerows'] = rspan + if cspan: + attributes['morecols'] = cspan + entry = nodes.entry(**attributes) + entry.extend(cellElements) + row += entry + return row + + def raiseError(self, msg): + error = self.directive.state_machine.reporter.error( + msg + , nodes.literal_block(self.directive.block_text + , self.directive.block_text) + , line = self.directive.lineno ) + raise SystemMessagePropagation(error) + + def parseFlatTableNode(self, node): + u"""parses the node from a :py:class:`FlatTable` directive's body""" + + if len(node) != 1 or not isinstance(node[0], nodes.bullet_list): + self.raiseError( + 'Error parsing content block for the "%s" directive: ' + 'exactly one bullet list expected.' % self.directive.name ) + + for rowNum, rowItem in enumerate(node[0]): + row = self.parseRowItem(rowItem, rowNum) + self.rows.append(row) + self.roundOffTableDefinition() + + def roundOffTableDefinition(self): + u"""Round off the table definition. + + This method rounds off the table definition in :py:member:`rows`. + + * This method inserts the needed ``None`` values for the missing cells + arising from spanning cells over rows and/or columns. + + * recount the :py:member:`max_cols` + + * Autospan or fill (option ``fill-cells``) missing cells on the right + side of the table-row + """ + + y = 0 + while y < len(self.rows): + x = 0 + + while x < len(self.rows[y]): + cell = self.rows[y][x] + if cell is None: + x += 1 + continue + cspan, rspan = cell[:2] + # handle colspan in current row + for c in range(cspan): + try: + self.rows[y].insert(x+c+1, None) + except: # pylint: disable=W0702 + # the user sets ambiguous rowspans + pass # SDK.CONSOLE() + # handle colspan in spanned rows + for r in range(rspan): + for c in range(cspan + 1): + try: + self.rows[y+r+1].insert(x+c, None) + except: # pylint: disable=W0702 + # the user sets ambiguous rowspans + pass # SDK.CONSOLE() + x += 1 + y += 1 + + # Insert the missing cells on the right side. For this, first + # re-calculate the max columns. + + for row in self.rows: + if self.max_cols < len(row): + self.max_cols = len(row) + + # fill with empty cells or cellspan? + + fill_cells = False + if 'fill-cells' in self.directive.options: + fill_cells = True + + for row in self.rows: + x = self.max_cols - len(row) + if x and not fill_cells: + if row[-1] is None: + row.append( ( x - 1, 0, []) ) + else: + cspan, rspan, content = row[-1] + row[-1] = (cspan + x, rspan, content) + elif x and fill_cells: + for i in range(x): + row.append( (0, 0, nodes.comment()) ) + + def pprint(self): + # for debugging + retVal = "[ " + for row in self.rows: + retVal += "[ " + for col in row: + if col is None: + retVal += ('%r' % col) + retVal += "\n , " + else: + content = col[2][0].astext() + if len (content) > 30: + content = content[:30] + "..." + retVal += ('(cspan=%s, rspan=%s, %r)' + % (col[0], col[1], content)) + retVal += "]\n , " + retVal = retVal[:-2] + retVal += "]\n , " + retVal = retVal[:-2] + return retVal + "]" + + def parseRowItem(self, rowItem, rowNum): + row = [] + childNo = 0 + error = False + cell = None + target = None + + for child in rowItem: + if (isinstance(child , nodes.comment) + or isinstance(child, nodes.system_message)): + pass + elif isinstance(child , nodes.target): + target = child + elif isinstance(child, nodes.bullet_list): + childNo += 1 + cell = child + else: + error = True + break + + if childNo != 1 or error: + self.raiseError( + 'Error parsing content block for the "%s" directive: ' + 'two-level bullet list expected, but row %s does not ' + 'contain a second-level bullet list.' + % (self.directive.name, rowNum + 1)) + + for cellItem in cell: + cspan, rspan, cellElements = self.parseCellItem(cellItem) + if target is not None: + cellElements.insert(0, target) + row.append( (cspan, rspan, cellElements) ) + return row + + def parseCellItem(self, cellItem): + # search and remove cspan, rspan colspec from the first element in + # this listItem (field). + cspan = rspan = 0 + if not len(cellItem): + return cspan, rspan, [] + for elem in cellItem[0]: + if isinstance(elem, colSpan): + cspan = elem.get("span") + elem.parent.remove(elem) + continue + if isinstance(elem, rowSpan): + rspan = elem.get("span") + elem.parent.remove(elem) + continue + return cspan, rspan, cellItem[:] diff --git a/Makefile b/Makefile index 4b3023b259..d1246e063f 100644 --- a/Makefile +++ b/Makefile @@ -1707,9 +1707,11 @@ tests: # Documentation targets # --------------------------------------------------------------------------- -%docs: scripts_basic FORCE - $(Q)$(MAKE) $(build)=scripts build_docproc - $(Q)$(MAKE) $(build)=doc/DocBook $@ +DOC_TARGETS := xmldocs latexdocs pdfdocs htmldocs epubdocs cleandocs \ + linkcheckdocs dochelp refcheckdocs +PHONY += $(DOC_TARGETS) +$(DOC_TARGETS): scripts_basic FORCE + $(Q)$(MAKE) $(build)=Documentation $@ endif #ifeq ($(config-targets),1) endif #ifeq ($(mixed-targets),1) diff --git a/doc/DocBook/.gitignore b/doc/DocBook/.gitignore deleted file mode 100644 index 7ebd5465d9..0000000000 --- a/doc/DocBook/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -*.xml -*.ps -*.pdf -*.html -*.9.gz -*.9 -*.aux -*.dvi -*.log -*.out -*.png -*.gif -*.svg -media-indices.tmpl -media-entities.tmpl diff --git a/doc/DocBook/Makefile b/doc/DocBook/Makefile deleted file mode 100644 index 5257613513..0000000000 --- a/doc/DocBook/Makefile +++ /dev/null @@ -1,222 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -### -# This makefile is used to generate the kernel documentation, -# primarily based on in-line comments in various source files. -# See Documentation/kernel-doc-nano-HOWTO.txt for instruction in how -# to document the SRC - and how to read it. -# To add a new book the only step required is to add the book to the -# list of DOCBOOKS. - -DOCBOOKS := efi.xml linker_lists.xml stdio.xml - -### -# The build process is as follows (targets): -# (xmldocs) [by docproc] -# file.tmpl --> file.xml +--> file.ps (psdocs) [by db2ps or xmlto] -# +--> file.pdf (pdfdocs) [by db2pdf or xmlto] -# +--> DIR=file (htmldocs) [by xmlto] -# +--> man/ (mandocs) [by xmlto] - - -# for PDF and PS output you can choose between xmlto and docbook-utils tools -PDF_METHOD = $(prefer-db2x) -PS_METHOD = $(prefer-db2x) - - -### -# The targets that may be used. -PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs - -targets += $(DOCBOOKS) -BOOKS := $(addprefix $(obj)/,$(DOCBOOKS)) -xmldocs: $(BOOKS) -sgmldocs: xmldocs - -PS := $(patsubst %.xml, %.ps, $(BOOKS)) -psdocs: $(PS) - -PDF := $(patsubst %.xml, %.pdf, $(BOOKS)) -pdfdocs: $(PDF) - -HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS))) -htmldocs: $(HTML) - $(call build_main_index) - $(call build_images) - $(call install_media_images) - -MAN := $(patsubst %.xml, %.9, $(BOOKS)) -mandocs: $(MAN) - $(if $(wildcard $(obj)/man/*.9),gzip -f $(obj)/man/*.9) - -installmandocs: mandocs - mkdir -p /usr/local/man/man9/ - install $(obj)/man/*.9.gz /usr/local/man/man9/ - -### -#External programs used -KERNELDOC = $(srctree)/scripts/kernel-doc -DOCPROC = $(objtree)/scripts/docproc - -XMLTOFLAGS = -m $(srctree)/$(src)/stylesheet.xsl -XMLTOFLAGS += --skip-validation - -### -# DOCPROC is used for two purposes: -# 1) To generate a dependency list for a .tmpl file -# 2) To preprocess a .tmpl file and call kernel-doc with -# appropriate parameters. -# The following rules are used to generate the .xml documentation -# required to generate the final targets. (ps, pdf, html). -quiet_cmd_docproc = DOCPROC $@ - cmd_docproc = SRCTREE=$(srctree)/ $(DOCPROC) doc $< >$@ -define rule_docproc - set -e; \ - $(if $($(quiet)cmd_$(1)),echo ' $($(quiet)cmd_$(1))';) \ - $(cmd_$(1)); \ - ( \ - echo 'cmd_$@ := $(cmd_$(1))'; \ - echo $@: `SRCTREE=$(srctree) $(DOCPROC) depend $<`; \ - ) > $(dir $@).$(notdir $@).cmd -endef - -%.xml: %.tmpl $(KERNELDOC) $(DOCPROC) FORCE - $(call if_changed_rule,docproc) - -# Tell kbuild to always build the programs -always := $(hostprogs-y) - -notfoundtemplate = echo "*** You have to install docbook-utils or xmlto ***"; \ - exit 1 -db2xtemplate = db2TYPE -o $(dir $@) $< -xmltotemplate = xmlto TYPE $(XMLTOFLAGS) -o $(dir $@) $< - -# determine which methods are available -ifeq ($(shell which db2ps >/dev/null 2>&1 && echo found),found) - use-db2x = db2x - prefer-db2x = db2x -else - use-db2x = notfound - prefer-db2x = $(use-xmlto) -endif -ifeq ($(shell which xmlto >/dev/null 2>&1 && echo found),found) - use-xmlto = xmlto - prefer-xmlto = xmlto -else - use-xmlto = notfound - prefer-xmlto = $(use-db2x) -endif - -# the commands, generated from the chosen template -quiet_cmd_db2ps = PS $@ - cmd_db2ps = $(subst TYPE,ps, $($(PS_METHOD)template)) -%.ps : %.xml - $(call cmd,db2ps) - -quiet_cmd_db2pdf = PDF $@ - cmd_db2pdf = $(subst TYPE,pdf, $($(PDF_METHOD)template)) -%.pdf : %.xml - $(call cmd,db2pdf) - - -index = index.html -main_idx = $(obj)/$(index) -build_main_index = rm -rf $(main_idx); \ - echo '

U-Boot Bootloader HTML Documentation

' >> $(main_idx) && \ - echo '

U-Boot Version: $(UBOOTVERSION)

' >> $(main_idx) && \ - cat $(HTML) >> $(main_idx) - -quiet_cmd_db2html = HTML $@ - cmd_db2html = xmlto html $(XMLTOFLAGS) -o $(patsubst %.html,%,$@) $< && \ - echo ' \ - $(patsubst %.html,%,$(notdir $@))

' > $@ - -%.html: %.xml - @(which xmlto > /dev/null 2>&1) || \ - (echo "*** You need to install xmlto ***"; \ - exit 1) - @rm -rf $@ $(patsubst %.html,%,$@) - $(call cmd,db2html) - @if [ ! -z "$(PNG-$(basename $(notdir $@)))" ]; then \ - cp $(PNG-$(basename $(notdir $@))) $(patsubst %.html,%,$@); fi - -quiet_cmd_db2man = MAN $@ - cmd_db2man = if grep -q refentry $<; then xmlto man $(XMLTOFLAGS) -o $(obj)/man $< ; fi -%.9 : %.xml - @(which xmlto > /dev/null 2>&1) || \ - (echo "*** You need to install xmlto ***"; \ - exit 1) - $(Q)mkdir -p $(obj)/man - $(call cmd,db2man) - @touch $@ - -### -# Rules to generate postscripts and PNG images from .fig format files -quiet_cmd_fig2eps = FIG2EPS $@ - cmd_fig2eps = fig2dev -Leps $< $@ - -%.eps: %.fig - @(which fig2dev > /dev/null 2>&1) || \ - (echo "*** You need to install transfig ***"; \ - exit 1) - $(call cmd,fig2eps) - -quiet_cmd_fig2png = FIG2PNG $@ - cmd_fig2png = fig2dev -Lpng $< $@ - -%.png: %.fig - @(which fig2dev > /dev/null 2>&1) || \ - (echo "*** You need to install transfig ***"; \ - exit 1) - $(call cmd,fig2png) - -### -# Rule to convert a .c file to inline XML documentation - gen_xml = : - quiet_gen_xml = echo ' GEN $@' -silent_gen_xml = : -%.xml: %.c - @$($(quiet)gen_xml) - @( \ - echo ""; \ - expand --tabs=8 < $< | \ - sed -e "s/&/\\&/g" \ - -e "s//\\>/g"; \ - echo "") > $@ - -### -# Help targets as used by the top-level makefile -dochelp: - @echo ' U-Boot bootloader internal documentation in different formats:' - @echo ' htmldocs - HTML' - @echo ' pdfdocs - PDF' - @echo ' psdocs - Postscript' - @echo ' xmldocs - XML DocBook' - @echo ' mandocs - man pages' - @echo ' installmandocs - install man pages generated by mandocs' - @echo ' cleandocs - clean all generated DocBook files' - -### -# Temporary files left by various tools -clean-files := $(DOCBOOKS) \ - $(patsubst %.xml, %.dvi, $(DOCBOOKS)) \ - $(patsubst %.xml, %.aux, $(DOCBOOKS)) \ - $(patsubst %.xml, %.tex, $(DOCBOOKS)) \ - $(patsubst %.xml, %.log, $(DOCBOOKS)) \ - $(patsubst %.xml, %.out, $(DOCBOOKS)) \ - $(patsubst %.xml, %.ps, $(DOCBOOKS)) \ - $(patsubst %.xml, %.pdf, $(DOCBOOKS)) \ - $(patsubst %.xml, %.html, $(DOCBOOKS)) \ - $(patsubst %.xml, %.9, $(DOCBOOKS)) \ - $(index) - -clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) man - -cleandocs: - $(Q)rm -f $(call objectify, $(clean-files)) - $(Q)rm -rf $(call objectify, $(clean-dirs)) - -# Declare the contents of the .PHONY variable as phony. We keep that -# information in a variable se we can use it in if_changed and friends. - -.PHONY: $(PHONY) diff --git a/doc/DocBook/docbook.css b/doc/DocBook/docbook.css deleted file mode 100644 index 7a79ec54bd..0000000000 --- a/doc/DocBook/docbook.css +++ /dev/null @@ -1,16 +0,0 @@ -body { - font-family: sans-serif; -} - -.programlisting { - font-family: monospace; - font-size: 1em; - display: block; - padding: 10px; - border: 1px solid #aaa; - color: #000; - background-color: #eee; - overflow: auto; - margin: 1em 0em; - border-radius: 6px; -} diff --git a/doc/DocBook/efi.tmpl b/doc/DocBook/efi.tmpl deleted file mode 100644 index 5daaae382b..0000000000 --- a/doc/DocBook/efi.tmpl +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - The U-Boot EFI subsystem - - - - - - Boot services -!Ilib/efi_loader/efi_boottime.c - - - diff --git a/doc/DocBook/linker_lists.tmpl b/doc/DocBook/linker_lists.tmpl deleted file mode 100644 index f1975165d6..0000000000 --- a/doc/DocBook/linker_lists.tmpl +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - The U-Boot Linker-Generated Arrays - - - - This documentation is free software; you can redistribute - it and/or modify it under the terms of the GNU General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later - version. - - - - This program is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied - warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. - - - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, - MA 02111-1307 USA - - - - For more details see the file COPYING in the source - distribution of U-Boot Bootloader. - - - - - - - - Linker-Generated Arrays -!Iinclude/linker_lists.h - - - diff --git a/doc/DocBook/stdio.tmpl b/doc/DocBook/stdio.tmpl deleted file mode 100644 index 4783abb0a0..0000000000 --- a/doc/DocBook/stdio.tmpl +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - The U-Boot STDIO subsystem - - - - This documentation is free software; you can redistribute - it and/or modify it under the terms of the GNU General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later - version. - - - - This program is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY; without even the implied - warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. - - - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, - MA 02111-1307 USA - - - - For more details see the file COPYING in the source - distribution of U-Boot Bootloader. - - - - - - - - U-Boot Serial subsystem -!Idrivers/serial/serial.c - - - diff --git a/doc/DocBook/stylesheet.xsl b/doc/DocBook/stylesheet.xsl deleted file mode 100644 index 85b2527519..0000000000 --- a/doc/DocBook/stylesheet.xsl +++ /dev/null @@ -1,10 +0,0 @@ - - -1 -ansi -80 -0 - -2 -1 - diff --git a/include/linker_lists.h b/include/linker_lists.h index e0759d446f..d775d041e0 100644 --- a/include/linker_lists.h +++ b/include/linker_lists.h @@ -19,87 +19,6 @@ #if !defined(__ASSEMBLY__) -/** - * A linker list is constructed by grouping together linker input - * sections, each containing one entry of the list. Each input section - * contains a constant initialized variable which holds the entry's - * content. Linker list input sections are constructed from the list - * and entry names, plus a prefix which allows grouping all lists - * together. Assuming _list and _entry are the list and entry names, - * then the corresponding input section name is - * - * .u_boot_list_ + 2_ + @_list + _2_ + @_entry - * - * and the C variable name is - * - * _u_boot_list + _2_ + @_list + _2_ + @_entry - * - * This ensures uniqueness for both input section and C variable name. - * - * Note that the names differ only in the first character, "." for the - * section and "_" for the variable, so that the linker cannot confuse - * section and symbol names. From now on, both names will be referred - * to as - * - * %u_boot_list_ + 2_ + @_list + _2_ + @_entry - * - * Entry variables need never be referred to directly. - * - * The naming scheme for input sections allows grouping all linker lists - * into a single linker output section and grouping all entries for a - * single list. - * - * Note the two '_2_' constant components in the names: their presence - * allows putting a start and end symbols around a list, by mapping - * these symbols to sections names with components "1" (before) and - * "3" (after) instead of "2" (within). - * Start and end symbols for a list can generally be defined as - * - * %u_boot_list_2_ + @_list + _1_... - * %u_boot_list_2_ + @_list + _3_... - * - * Start and end symbols for the whole of the linker lists area can be - * defined as - * - * %u_boot_list_1_... - * %u_boot_list_3_... - * - * Here is an example of the sorted sections which result from a list - * "array" made up of three entries : "first", "second" and "third", - * iterated at least once. - * - * .u_boot_list_2_array_1 - * .u_boot_list_2_array_2_first - * .u_boot_list_2_array_2_second - * .u_boot_list_2_array_2_third - * .u_boot_list_2_array_3 - * - * If lists must be divided into sublists (e.g. for iterating only on - * part of a list), one can simply give the list a name of the form - * 'outer_2_inner', where 'outer' is the global list name and 'inner' - * is the sub-list name. Iterators for the whole list should use the - * global list name ("outer"); iterators for only a sub-list should use - * the full sub-list name ("outer_2_inner"). - * - * Here is an example of the sections generated from a global list - * named "drivers", two sub-lists named "i2c" and "pci", and iterators - * defined for the whole list and each sub-list: - * - * %u_boot_list_2_drivers_1 - * %u_boot_list_2_drivers_2_i2c_1 - * %u_boot_list_2_drivers_2_i2c_2_first - * %u_boot_list_2_drivers_2_i2c_2_first - * %u_boot_list_2_drivers_2_i2c_2_second - * %u_boot_list_2_drivers_2_i2c_2_third - * %u_boot_list_2_drivers_2_i2c_3 - * %u_boot_list_2_drivers_2_pci_1 - * %u_boot_list_2_drivers_2_pci_2_first - * %u_boot_list_2_drivers_2_pci_2_second - * %u_boot_list_2_drivers_2_pci_2_third - * %u_boot_list_2_drivers_2_pci_3 - * %u_boot_list_2_drivers_3 - */ - /** * llsym() - Access a linker-generated array entry * @_type: Data type of the entry @@ -134,16 +53,19 @@ * a subsection of this section is declared and contains some elements, * it is imperative that the elements are of the same type. * - * 4) In case an outer section is declared that contains some array elements + * 3) In case an outer section is declared that contains some array elements * AND an inner subsection of this section is declared and contains some * elements, then when traversing the outer section, even the elements of * the inner sections are present in the array. * * Example: - * ll_entry_declare(struct my_sub_cmd, my_sub_cmd, cmd_sub) = { - * .x = 3, - * .y = 4, - * }; + * + * :: + * + * ll_entry_declare(struct my_sub_cmd, my_sub_cmd, cmd_sub) = { + * .x = 3, + * .y = 4, + * }; */ #define ll_entry_declare(_type, _name, _list) \ _type _u_boot_list_2_##_list##_2_##_name __aligned(4) \ @@ -160,18 +82,20 @@ * This is like ll_entry_declare() but creates multiple entries. It should * be assigned to an array. * - * ll_entry_declare_list(struct my_sub_cmd, my_sub_cmd, cmd_sub) = { - * { .x = 3, .y = 4 }, - * { .x = 8, .y = 2 }, - * { .x = 1, .y = 7 } - * }; + * :: + * + * ll_entry_declare_list(struct my_sub_cmd, my_sub_cmd, cmd_sub) = { + * { .x = 3, .y = 4 }, + * { .x = 8, .y = 2 }, + * { .x = 1, .y = 7 } + * }; */ #define ll_entry_declare_list(_type, _name, _list) \ _type _u_boot_list_2_##_list##_2_##_name[] __aligned(4) \ __attribute__((unused, \ section(".u_boot_list_2_"#_list"_2_"#_name))) -/** +/* * We need a 0-byte-size type for iterator symbols, and the compiler * does not allow defining objects of C type 'void'. Using an empty * struct is allowed by the compiler, but causes gcc versions 4.4 and @@ -185,7 +109,7 @@ * @_type: Data type of the entry * @_list: Name of the list in which this entry is placed * - * This function returns (_type *) pointer to the very first entry of a + * This function returns ``(_type *)`` pointer to the very first entry of a * linker-generated array placed into subsection of .u_boot_list section * specified by _list argument. * @@ -193,7 +117,10 @@ * must be 2 and its rightmost index must be 1. * * Example: - * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub); + * + * :: + * + * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub); */ #define ll_entry_start(_type, _list) \ ({ \ @@ -208,7 +135,7 @@ * @_list: Name of the list in which this entry is placed * (with underscores instead of dots) * - * This function returns (_type *) pointer after the very last entry of + * This function returns ``(_type *)`` pointer after the very last entry of * a linker-generated array placed into subsection of .u_boot_list * section specified by _list argument. * @@ -216,7 +143,10 @@ * must be 2 and its rightmost index must be 3. * * Example: - * struct my_sub_cmd *msc = ll_entry_end(struct my_sub_cmd, cmd_sub); + * + * :: + * + * struct my_sub_cmd *msc = ll_entry_end(struct my_sub_cmd, cmd_sub); */ #define ll_entry_end(_type, _list) \ ({ \ @@ -234,11 +164,14 @@ * argument. The result is of an unsigned int type. * * Example: - * int i; - * const unsigned int count = ll_entry_count(struct my_sub_cmd, cmd_sub); - * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub); - * for (i = 0; i < count; i++, msc++) - * printf("Entry %i, x=%i y=%i\n", i, msc->x, msc->y); + * + * :: + * + * int i; + * const unsigned int count = ll_entry_count(struct my_sub_cmd, cmd_sub); + * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub); + * for (i = 0; i < count; i++, msc++) + * printf("Entry %i, x=%i y=%i\n", i, msc->x, msc->y); */ #define ll_entry_count(_type, _list) \ ({ \ @@ -259,12 +192,15 @@ * and it's name. * * Example: - * ll_entry_declare(struct my_sub_cmd, my_sub_cmd, cmd_sub) = { - * .x = 3, - * .y = 4, - * }; - * ... - * struct my_sub_cmd *c = ll_entry_get(struct my_sub_cmd, my_sub_cmd, cmd_sub); + * + * :: + * + * ll_entry_declare(struct my_sub_cmd, my_sub_cmd, cmd_sub) = { + * .x = 3, + * .y = 4, + * }; + * ... + * struct my_sub_cmd *c = ll_entry_get(struct my_sub_cmd, my_sub_cmd, cmd_sub); */ #define ll_entry_get(_type, _name, _list) \ ({ \ @@ -278,14 +214,17 @@ * ll_start() - Point to first entry of first linker-generated array * @_type: Data type of the entry * - * This function returns (_type *) pointer to the very first entry of + * This function returns ``(_type *)`` pointer to the very first entry of * the very first linker-generated array. * * Since this macro defines the start of the linker-generated arrays, * its leftmost index must be 1. * * Example: - * struct my_sub_cmd *msc = ll_start(struct my_sub_cmd); + * + * :: + * + * struct my_sub_cmd *msc = ll_start(struct my_sub_cmd); */ #define ll_start(_type) \ ({ \ @@ -298,14 +237,17 @@ * ll_end() - Point after last entry of last linker-generated array * @_type: Data type of the entry * - * This function returns (_type *) pointer after the very last entry of + * This function returns ``(_type *)`` pointer after the very last entry of * the very last linker-generated array. * * Since this macro defines the end of the linker-generated arrays, * its leftmost index must be 3. * * Example: - * struct my_sub_cmd *msc = ll_end(struct my_sub_cmd); + * + * :: + * + * struct my_sub_cmd *msc = ll_end(struct my_sub_cmd); */ #define ll_end(_type) \ ({ \ diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 261d66d97f..eeefe0bdfe 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -115,9 +115,9 @@ void efi_save_gd(void) } /* - * Special case handler for error/abort that just forces things back - * to u-boot world so we can dump out an abort msg, without any care - * about returning back to UEFI world. + * Special case handler for error/abort that just forces things back to u-boot + * world so we can dump out an abort msg, without any care about returning back + * to UEFI world. */ void efi_restore_gd(void) { @@ -130,14 +130,14 @@ void efi_restore_gd(void) } /** - * indent_string - returns a string for indenting with two spaces per level + * indent_string() - returns a string for indenting with two spaces per level + * @level: indent level * * A maximum of ten indent levels is supported. Higher indent levels will be * truncated. * - * @level: indent level - * Return Value: A string for indenting with two spaces per level is - * returned. + * Return: A string for indenting with two spaces per level is + * returned. */ static const char *indent_string(int level) { @@ -164,18 +164,18 @@ const char *__efi_nesting_dec(void) } /** - * efi_queue_event - queue an EFI event + * efi_queue_event() - queue an EFI event + * @event: event to signal + * @check_tpl: check the TPL level * * This function queues the notification function of the event for future * execution. * - * The notification function is called if the task priority level of the - * event is higher than the current task priority level. + * The notification function is called if the task priority level of the event + * is higher than the current task priority level. * * For the SignalEvent service see efi_signal_event_ext. * - * @event: event to signal - * @check_tpl: check the TPL level */ static void efi_queue_event(struct efi_event *event, bool check_tpl) { @@ -191,16 +191,15 @@ static void efi_queue_event(struct efi_event *event, bool check_tpl) } /** - * efi_signal_event - signal an EFI event + * efi_signal_event() - signal an EFI event + * @event: event to signal + * @check_tpl: check the TPL level * - * This function signals an event. If the event belongs to an event group - * all events of the group are signaled. If they are of type EVT_NOTIFY_SIGNAL + * This function signals an event. If the event belongs to an event group all + * events of the group are signaled. If they are of type EVT_NOTIFY_SIGNAL * their notification function is queued. * * For the SignalEvent service see efi_signal_event_ext. - * - * @event: event to signal - * @check_tpl: check the TPL level */ void efi_signal_event(struct efi_event *event, bool check_tpl) { @@ -235,14 +234,15 @@ void efi_signal_event(struct efi_event *event, bool check_tpl) } /** - * efi_raise_tpl - raise the task priority level + * efi_raise_tpl() - raise the task priority level + * @new_tpl: new value of the task priority level * * This function implements the RaiseTpl service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @new_tpl: new value of the task priority level - * Return Value: old value of the task priority level + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: old value of the task priority level */ static unsigned long EFIAPI efi_raise_tpl(efi_uintn_t new_tpl) { @@ -261,13 +261,13 @@ static unsigned long EFIAPI efi_raise_tpl(efi_uintn_t new_tpl) } /** - * efi_restore_tpl - lower the task priority level + * efi_restore_tpl() - lower the task priority level + * @old_tpl: value of the task priority level to be restored * * This function implements the RestoreTpl service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @old_tpl: value of the task priority level to be restored + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. */ static void EFIAPI efi_restore_tpl(efi_uintn_t old_tpl) { @@ -288,17 +288,18 @@ static void EFIAPI efi_restore_tpl(efi_uintn_t old_tpl) } /** - * efi_allocate_pages_ext - allocate memory pages + * efi_allocate_pages_ext() - allocate memory pages + * @type: type of allocation to be performed + * @memory_type: usage type of the allocated memory + * @pages: number of pages to be allocated + * @memory: allocated memory * * This function implements the AllocatePages service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @type: type of allocation to be performed - * @memory_type: usage type of the allocated memory - * @pages: number of pages to be allocated - * @memory: allocated memory - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_allocate_pages_ext(int type, int memory_type, efi_uintn_t pages, @@ -312,15 +313,16 @@ static efi_status_t EFIAPI efi_allocate_pages_ext(int type, int memory_type, } /** - * efi_free_pages_ext - Free memory pages. + * efi_free_pages_ext() - Free memory pages. + * @memory: start of the memory area to be freed + * @pages: number of pages to be freed * * This function implements the FreePages service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @memory: start of the memory area to be freed - * @pages: number of pages to be freed - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_free_pages_ext(uint64_t memory, efi_uintn_t pages) @@ -333,19 +335,20 @@ static efi_status_t EFIAPI efi_free_pages_ext(uint64_t memory, } /** - * efi_get_memory_map_ext - get map describing memory usage + * efi_get_memory_map_ext() - get map describing memory usage + * @memory_map_size: on entry the size, in bytes, of the memory map buffer, + * on exit the size of the copied memory map + * @memory_map: buffer to which the memory map is written + * @map_key: key for the memory map + * @descriptor_size: size of an individual memory descriptor + * @descriptor_version: version number of the memory descriptor structure * * This function implements the GetMemoryMap service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @memory_map_size: on entry the size, in bytes, of the memory map buffer, - * on exit the size of the copied memory map - * @memory_map: buffer to which the memory map is written - * @map_key: key for the memory map - * @descriptor_size: size of an individual memory descriptor - * @descriptor_version: version number of the memory descriptor structure - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_get_memory_map_ext( efi_uintn_t *memory_map_size, @@ -364,16 +367,17 @@ static efi_status_t EFIAPI efi_get_memory_map_ext( } /** - * efi_allocate_pool_ext - allocate memory from pool + * efi_allocate_pool_ext() - allocate memory from pool + * @pool_type: type of the pool from which memory is to be allocated + * @size: number of bytes to be allocated + * @buffer: allocated memory * * This function implements the AllocatePool service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @pool_type: type of the pool from which memory is to be allocated - * @size: number of bytes to be allocated - * @buffer: allocated memory - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_allocate_pool_ext(int pool_type, efi_uintn_t size, @@ -387,14 +391,15 @@ static efi_status_t EFIAPI efi_allocate_pool_ext(int pool_type, } /** - * efi_free_pool_ext - free memory from pool + * efi_free_pool_ext() - free memory from pool + * @buffer: start of memory to be freed * * This function implements the FreePool service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @buffer: start of memory to be freed - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) { @@ -406,12 +411,10 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) } /** - * efi_add_handle - add a new object to the object list - * - * The protocols list is initialized. - * The object handle is set. + * efi_add_handle() - add a new object to the object list + * @obj: object to be added * - * @obj: object to be added + * The protocols list is initialized. The object handle is set. */ void efi_add_handle(struct efi_object *obj) { @@ -423,10 +426,10 @@ void efi_add_handle(struct efi_object *obj) } /** - * efi_create_handle - create handle + * efi_create_handle() - create handle + * @handle: new handle * - * @handle: new handle - * Return Value: status code + * Return: status code */ efi_status_t efi_create_handle(efi_handle_t *handle) { @@ -443,12 +446,12 @@ efi_status_t efi_create_handle(efi_handle_t *handle) } /** - * efi_search_protocol - find a protocol on a handle. + * efi_search_protocol() - find a protocol on a handle. + * @handle: handle + * @protocol_guid: GUID of the protocol + * @handler: reference to the protocol * - * @handle: handle - * @protocol_guid: GUID of the protocol - * @handler: reference to the protocol - * Return Value: status code + * Return: status code */ efi_status_t efi_search_protocol(const efi_handle_t handle, const efi_guid_t *protocol_guid, @@ -476,12 +479,12 @@ efi_status_t efi_search_protocol(const efi_handle_t handle, } /** - * efi_remove_protocol - delete protocol from a handle + * efi_remove_protocol() - delete protocol from a handle + * @handle: handle from which the protocol shall be deleted + * @protocol: GUID of the protocol to be deleted + * @protocol_interface: interface of the protocol implementation * - * @handle: handle from which the protocol shall be deleted - * @protocol: GUID of the protocol to be deleted - * @protocol_interface: interface of the protocol implementation - * Return Value: status code + * Return: status code */ efi_status_t efi_remove_protocol(const efi_handle_t handle, const efi_guid_t *protocol, @@ -503,10 +506,10 @@ efi_status_t efi_remove_protocol(const efi_handle_t handle, } /** - * efi_remove_all_protocols - delete all protocols from a handle + * efi_remove_all_protocols() - delete all protocols from a handle + * @handle: handle from which the protocols shall be deleted * - * @handle: handle from which the protocols shall be deleted - * Return Value: status code + * Return: status code */ efi_status_t efi_remove_all_protocols(const efi_handle_t handle) { @@ -529,9 +532,9 @@ efi_status_t efi_remove_all_protocols(const efi_handle_t handle) } /** - * efi_delete_handle - delete handle + * efi_delete_handle() - delete handle * - * @obj: handle to delete + * @obj: handle to delete */ void efi_delete_handle(struct efi_object *obj) { @@ -543,10 +546,10 @@ void efi_delete_handle(struct efi_object *obj) } /** - * efi_is_event - check if a pointer is a valid event + * efi_is_event() - check if a pointer is a valid event + * @event: pointer to check * - * @event: pointer to check - * Return Value: status code + * Return: status code */ static efi_status_t efi_is_event(const struct efi_event *event) { @@ -562,20 +565,20 @@ static efi_status_t efi_is_event(const struct efi_event *event) } /** - * efi_create_event - create an event + * efi_create_event() - create an event + * @type: type of the event to create + * @notify_tpl: task priority level of the event + * @notify_function: notification function of the event + * @notify_context: pointer passed to the notification function + * @group: event group + * @event: created event * * This function is used inside U-Boot code to create an event. * * For the API function implementing the CreateEvent service see * efi_create_event_ext. * - * @type: type of the event to create - * @notify_tpl: task priority level of the event - * @notify_function: notification function of the event - * @notify_context: pointer passed to the notification function - * @group: event group - * @event: created event - * Return Value: status code + * Return: status code */ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl, void (EFIAPI *notify_function) ( @@ -614,19 +617,20 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl, } /* - * efi_create_event_ex - create an event in a group + * efi_create_event_ex() - create an event in a group + * @type: type of the event to create + * @notify_tpl: task priority level of the event + * @notify_function: notification function of the event + * @notify_context: pointer passed to the notification function + * @event: created event + * @event_group: event group * * This function implements the CreateEventEx service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @type: type of the event to create - * @notify_tpl: task priority level of the event - * @notify_function: notification function of the event - * @notify_context: pointer passed to the notification function - * @event: created event - * @event_group: event group - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ efi_status_t EFIAPI efi_create_event_ex(uint32_t type, efi_uintn_t notify_tpl, void (EFIAPI *notify_function) ( @@ -643,18 +647,19 @@ efi_status_t EFIAPI efi_create_event_ex(uint32_t type, efi_uintn_t notify_tpl, } /** - * efi_create_event_ext - create an event + * efi_create_event_ext() - create an event + * @type: type of the event to create + * @notify_tpl: task priority level of the event + * @notify_function: notification function of the event + * @notify_context: pointer passed to the notification function + * @event: created event * * This function implements the CreateEvent service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @type: type of the event to create - * @notify_tpl: task priority level of the event - * @notify_function: notification function of the event - * @notify_context: pointer passed to the notification function - * @event: created event - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_create_event_ext( uint32_t type, efi_uintn_t notify_tpl, @@ -670,7 +675,7 @@ static efi_status_t EFIAPI efi_create_event_ext( } /** - * efi_timer_check - check if a timer event has occurred + * efi_timer_check() - check if a timer event has occurred * * Check if a timer event has occurred or a queued notification function should * be called. @@ -705,15 +710,15 @@ void efi_timer_check(void) } /** - * efi_set_timer - set the trigger time for a timer event or stop the event + * efi_set_timer() - set the trigger time for a timer event or stop the event + * @event: event for which the timer is set + * @type: type of the timer + * @trigger_time: trigger period in multiples of 100ns * * This is the function for internal usage in U-Boot. For the API function * implementing the SetTimer service see efi_set_timer_ext. * - * @event: event for which the timer is set - * @type: type of the timer - * @trigger_time: trigger period in multiples of 100ns - * Return Value: status code + * Return: status code */ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, uint64_t trigger_time) @@ -746,16 +751,19 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, } /** - * efi_set_timer_ext - Set the trigger time for a timer event or stop the event + * efi_set_timer_ext() - Set the trigger time for a timer event or stop the + * event + * @event: event for which the timer is set + * @type: type of the timer + * @trigger_time: trigger period in multiples of 100ns * * This function implements the SetTimer service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @event: event for which the timer is set - * @type: type of the timer - * @trigger_time: trigger period in multiples of 100ns - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * + * Return: status code */ static efi_status_t EFIAPI efi_set_timer_ext(struct efi_event *event, enum efi_timer_delay type, @@ -766,16 +774,17 @@ static efi_status_t EFIAPI efi_set_timer_ext(struct efi_event *event, } /** - * efi_wait_for_event - wait for events to be signaled + * efi_wait_for_event() - wait for events to be signaled + * @num_events: number of events to be waited for + * @event: events to be waited for + * @index: index of the event that was signaled * * This function implements the WaitForEvent service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @num_events: number of events to be waited for - * @event: events to be waited for - * @index: index of the event that was signaled - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_wait_for_event(efi_uintn_t num_events, struct efi_event **event, @@ -823,17 +832,18 @@ out: } /** - * efi_signal_event_ext - signal an EFI event + * efi_signal_event_ext() - signal an EFI event + * @event: event to signal * * This function implements the SignalEvent service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. * * This functions sets the signaled state of the event and queues the * notification function for execution. * - * @event: event to signal - * Return Value: status code + * Return: status code */ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) { @@ -845,14 +855,15 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) } /** - * efi_close_event - close an EFI event + * efi_close_event() - close an EFI event + * @event: event to close * * This function implements the CloseEvent service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @event: event to close - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_close_event(struct efi_event *event) { @@ -865,17 +876,18 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event) } /** - * efi_check_event - check if an event is signaled + * efi_check_event() - check if an event is signaled + * @event: event to check * * This function implements the CheckEvent service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * If an event is not signaled yet, the notification function is queued. - * The signaled state is cleared. + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * If an event is not signaled yet, the notification function is queued. The + * signaled state is cleared. * - * @event: event to check - * Return Value: status code + * Return: status code */ static efi_status_t EFIAPI efi_check_event(struct efi_event *event) { @@ -894,10 +906,10 @@ static efi_status_t EFIAPI efi_check_event(struct efi_event *event) } /** - * efi_search_obj - find the internal EFI object for a handle + * efi_search_obj() - find the internal EFI object for a handle + * @handle: handle to find * - * @handle: handle to find - * Return Value: EFI object + * Return: EFI object */ struct efi_object *efi_search_obj(const efi_handle_t handle) { @@ -912,11 +924,11 @@ struct efi_object *efi_search_obj(const efi_handle_t handle) } /** - * efi_open_protocol_info_entry - create open protocol info entry and add it - * to a protocol + * efi_open_protocol_info_entry() - create open protocol info entry and add it + * to a protocol + * @handler: handler of a protocol * - * @handler: handler of a protocol - * Return Value: open protocol info entry + * Return: open protocol info entry */ static struct efi_open_protocol_info_entry *efi_create_open_info( struct efi_handler *handler) @@ -933,10 +945,10 @@ static struct efi_open_protocol_info_entry *efi_create_open_info( } /** - * efi_delete_open_info - remove an open protocol info entry from a protocol + * efi_delete_open_info() - remove an open protocol info entry from a protocol + * @item: open protocol info entry to delete * - * @item: open protocol info entry to delete - * Return Value: status code + * Return: status code */ static efi_status_t efi_delete_open_info( struct efi_open_protocol_info_item *item) @@ -947,12 +959,12 @@ static efi_status_t efi_delete_open_info( } /** - * efi_add_protocol - install new protocol on a handle + * efi_add_protocol() - install new protocol on a handle + * @handle: handle on which the protocol shall be installed + * @protocol: GUID of the protocol to be installed + * @protocol_interface: interface of the protocol implementation * - * @handle: handle on which the protocol shall be installed - * @protocol: GUID of the protocol to be installed - * @protocol_interface: interface of the protocol implementation - * Return Value: status code + * Return: status code */ efi_status_t efi_add_protocol(const efi_handle_t handle, const efi_guid_t *protocol, @@ -981,18 +993,19 @@ efi_status_t efi_add_protocol(const efi_handle_t handle, } /** - * efi_install_protocol_interface - install protocol interface + * efi_install_protocol_interface() - install protocol interface + * @handle: handle on which the protocol shall be installed + * @protocol: GUID of the protocol to be installed + * @protocol_interface_type: type of the interface to be installed, + * always EFI_NATIVE_INTERFACE + * @protocol_interface: interface of the protocol implementation * * This function implements the InstallProtocolInterface service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @handle: handle on which the protocol shall be installed - * @protocol: GUID of the protocol to be installed - * @protocol_interface_type: type of the interface to be installed, - * always EFI_NATIVE_INTERFACE - * @protocol_interface: interface of the protocol implementation - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_install_protocol_interface( void **handle, const efi_guid_t *protocol, @@ -1027,15 +1040,15 @@ out: } /** - * efi_get_drivers - get all drivers associated to a controller + * efi_get_drivers() - get all drivers associated to a controller + * @efiobj: handle of the controller + * @protocol: protocol guid (optional) + * @number_of_drivers: number of child controllers + * @driver_handle_buffer: handles of the the drivers * * The allocated buffer has to be freed with free(). * - * @efiobj: handle of the controller - * @protocol: protocol guid (optional) - * @number_of_drivers: number of child controllers - * @driver_handle_buffer: handles of the the drivers - * Return Value: status code + * Return: status code */ static efi_status_t efi_get_drivers(struct efi_object *efiobj, const efi_guid_t *protocol, @@ -1092,16 +1105,17 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj, } /** - * efi_disconnect_all_drivers - disconnect all drivers from a controller + * efi_disconnect_all_drivers() - disconnect all drivers from a controller + * @efiobj: handle of the controller + * @protocol: protocol guid (optional) + * @child_handle: handle of the child to destroy * * This function implements the DisconnectController service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @efiobj: handle of the controller - * @protocol: protocol guid (optional) - * @child_handle: handle of the child to destroy - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t efi_disconnect_all_drivers( struct efi_object *efiobj, @@ -1131,16 +1145,17 @@ static efi_status_t efi_disconnect_all_drivers( } /** - * efi_uninstall_protocol_interface - uninstall protocol interface + * efi_uninstall_protocol_interface() - uninstall protocol interface + * @handle: handle from which the protocol shall be removed + * @protocol: GUID of the protocol to be removed + * @protocol_interface: interface to be removed * * This function implements the UninstallProtocolInterface service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @handle: handle from which the protocol shall be removed - * @protocol: GUID of the protocol to be removed - * @protocol_interface: interface to be removed - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_uninstall_protocol_interface( efi_handle_t handle, const efi_guid_t *protocol, @@ -1188,18 +1203,17 @@ out: } /** - * efi_register_protocol_notify - register an event for notification when a - * protocol is installed. + * efi_register_protocol_notify() - register an event for notification when a + * protocol is installed. + * @protocol: GUID of the protocol whose installation shall be notified + * @event: event to be signaled upon installation of the protocol + * @registration: key for retrieving the registration information * * This function implements the RegisterProtocolNotify service. * See the Unified Extensible Firmware Interface (UEFI) specification * for details. * - * @protocol: GUID of the protocol whose installation shall be - * notified - * @event: event to be signaled upon installation of the protocol - * @registration: key for retrieving the registration information - * Return Value: status code + * Return: status code */ static efi_status_t EFIAPI efi_register_protocol_notify( const efi_guid_t *protocol, @@ -1211,15 +1225,15 @@ static efi_status_t EFIAPI efi_register_protocol_notify( } /** - * efi_search - determine if an EFI handle implements a protocol + * efi_search() - determine if an EFI handle implements a protocol + * @search_type: selection criterion + * @protocol: GUID of the protocol + * @search_key: registration key + * @efiobj: handle * * See the documentation of the LocateHandle service in the UEFI specification. * - * @search_type: selection criterion - * @protocol: GUID of the protocol - * @search_key: registration key - * @efiobj: handle - * Return Value: 0 if the handle implements the protocol + * Return: 0 if the handle implements the protocol */ static int efi_search(enum efi_locate_search_type search_type, const efi_guid_t *protocol, void *search_key, @@ -1243,17 +1257,17 @@ static int efi_search(enum efi_locate_search_type search_type, } /** - * efi_locate_handle - locate handles implementing a protocol + * efi_locate_handle() - locate handles implementing a protocol + * @search_type: selection criterion + * @protocol: GUID of the protocol + * @search_key: registration key + * @buffer_size: size of the buffer to receive the handles in bytes + * @buffer: buffer to receive the relevant handles * * This function is meant for U-Boot internal calls. For the API implementation * of the LocateHandle service see efi_locate_handle_ext. * - * @search_type: selection criterion - * @protocol: GUID of the protocol - * @search_key: registration key - * @buffer_size: size of the buffer to receive the handles in bytes - * @buffer: buffer to receive the relevant handles - * Return Value: status code + * Return: status code */ static efi_status_t efi_locate_handle( enum efi_locate_search_type search_type, @@ -1313,18 +1327,19 @@ static efi_status_t efi_locate_handle( } /** - * efi_locate_handle_ext - locate handles implementing a protocol. + * efi_locate_handle_ext() - locate handles implementing a protocol. + * @search_type: selection criterion + * @protocol: GUID of the protocol + * @search_key: registration key + * @buffer_size: size of the buffer to receive the handles in bytes + * @buffer: buffer to receive the relevant handles * * This function implements the LocateHandle service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @search_type: selection criterion - * @protocol: GUID of the protocol - * @search_key: registration key - * @buffer_size: size of the buffer to receive the handles in bytes - * @buffer: buffer to receive the relevant handles - * Return Value: 0 if the handle implements the protocol + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: 0 if the handle implements the protocol */ static efi_status_t EFIAPI efi_locate_handle_ext( enum efi_locate_search_type search_type, @@ -1339,10 +1354,10 @@ static efi_status_t EFIAPI efi_locate_handle_ext( } /** - * efi_remove_configuration_table - collapses configuration table entries, - * removing index i + * efi_remove_configuration_table() - collapses configuration table entries, + * removing index i * - * @i: index of the table entry to be removed + * @i: index of the table entry to be removed */ static void efi_remove_configuration_table(int i) { @@ -1355,15 +1370,15 @@ static void efi_remove_configuration_table(int i) } /** - * efi_install_configuration_table - adds, updates, or removes a configuration - * table + * efi_install_configuration_table() - adds, updates, or removes a + * configuration table + * @guid: GUID of the installed table + * @table: table to be installed * * This function is used for internal calls. For the API implementation of the * InstallConfigurationTable service see efi_install_configuration_table_ext. * - * @guid: GUID of the installed table - * @table: table to be installed - * Return Value: status code + * Return: status code */ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table) @@ -1410,16 +1425,17 @@ out: } /** - * efi_install_configuration_table_ex - Adds, updates, or removes a - * configuration table. + * efi_install_configuration_table_ex() - Adds, updates, or removes a + * configuration table. + * @guid: GUID of the installed table + * @table: table to be installed * * This function implements the InstallConfigurationTable service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @guid: GUID of the installed table - * @table: table to be installed - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid, void *table) @@ -1429,17 +1445,16 @@ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid, } /** - * efi_setup_loaded_image - initialize a loaded image + * efi_setup_loaded_image() - initialize a loaded image + * @info: loaded image info to be passed to the entry point of the image + * @obj: internal object associated with the loaded image + * @device_path: device path of the loaded image + * @file_path: file path of the loaded image * * Initialize a loaded_image_info and loaded_image_info object with correct * protocols, boot-device, etc. * - * @info: loaded image info to be passed to the entry point of the - * image - * @obj: internal object associated with the loaded image - * @device_path: device path of the loaded image - * @file_path: file path of the loaded image - * Return Value: status code + * Return: status code */ efi_status_t efi_setup_loaded_image( struct efi_loaded_image *info, struct efi_object *obj, @@ -1494,11 +1509,11 @@ failure: } /** - * efi_load_image_from_path - load an image using a file path + * efi_load_image_from_path() - load an image using a file path + * @file_path: the path of the image to load + * @buffer: buffer containing the loaded image * - * @file_path: the path of the image to load - * @buffer: buffer containing the loaded image - * Return Value: status code + * Return: status code */ efi_status_t efi_load_image_from_path(struct efi_device_path *file_path, void **buffer) @@ -1543,20 +1558,20 @@ error: } /** - * efi_load_image - load an EFI image into memory + * efi_load_image() - load an EFI image into memory + * @boot_policy: true for request originating from the boot manager + * @parent_image: the caller's image handle + * @file_path: the path of the image to load + * @source_buffer: memory location from which the image is installed + * @source_size: size of the memory area from which the image is installed + * @image_handle: handle for the newly installed image * * This function implements the LoadImage service. + * * See the Unified Extensible Firmware Interface (UEFI) specification * for details. * - * @boot_policy: true for request originating from the boot manager - * @parent_image: the caller's image handle - * @file_path: the path of the image to load - * @source_buffer: memory location from which the image is installed - * @source_size: size of the memory area from which the image is - * installed - * @image_handle: handle for the newly installed image - * Return Value: status code + * Return: status code */ static efi_status_t EFIAPI efi_load_image(bool boot_policy, efi_handle_t parent_image, @@ -1633,16 +1648,17 @@ error: } /** - * efi_start_image - dall the entry point of an image + * efi_start_image() - dall the entry point of an image + * @image_handle: handle of the image + * @exit_data_size: size of the buffer + * @exit_data: buffer to receive the exit data of the called image * * This function implements the StartImage service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @image_handle: handle of the image - * @exit_data_size: size of the buffer - * @exit_data: buffer to receive the exit data of the called image - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, unsigned long *exit_data_size, @@ -1699,17 +1715,18 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, } /** - * efi_exit - leave an EFI application or driver + * efi_exit() - leave an EFI application or driver + * @image_handle: handle of the application or driver that is exiting + * @exit_status: status code + * @exit_data_size: size of the buffer in bytes + * @exit_data: buffer with data describing an error * * This function implements the Exit service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @image_handle: handle of the application or driver that is exiting - * @exit_status: status code - * @exit_data_size: size of the buffer in bytes - * @exit_data: buffer with data describing an error - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, efi_status_t exit_status, @@ -1748,14 +1765,15 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, } /** - * efi_unload_image - unload an EFI image + * efi_unload_image() - unload an EFI image + * @image_handle: handle of the image to be unloaded * * This function implements the UnloadImage service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @image_handle: handle of the image to be unloaded - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle) { @@ -1770,7 +1788,7 @@ static efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle) } /** - * efi_exit_caches - fix up caches for EFI payloads if necessary + * efi_exit_caches() - fix up caches for EFI payloads if necessary */ static void efi_exit_caches(void) { @@ -1785,19 +1803,20 @@ static void efi_exit_caches(void) } /** - * efi_exit_boot_services - stop all boot services + * efi_exit_boot_services() - stop all boot services + * @image_handle: handle of the loaded image + * @map_key: key of the memory map * * This function implements the ExitBootServices service. + * * See the Unified Extensible Firmware Interface (UEFI) specification * for details. * - * All timer events are disabled. - * For exit boot services events the notification function is called. - * The boot services are disabled in the system table. + * All timer events are disabled. For exit boot services events the + * notification function is called. The boot services are disabled in the + * system table. * - * @image_handle: handle of the loaded image - * @map_key: key of the memory map - * Return Value: status code + * Return: status code */ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, unsigned long map_key) @@ -1860,14 +1879,15 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, } /** - * efi_get_next_monotonic_count - get next value of the counter + * efi_get_next_monotonic_count() - get next value of the counter + * @count: returned value of the counter * * This function implements the NextMonotonicCount service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @count: returned value of the counter - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_get_next_monotonic_count(uint64_t *count) { @@ -1879,14 +1899,15 @@ static efi_status_t EFIAPI efi_get_next_monotonic_count(uint64_t *count) } /** - * efi_stall - sleep + * efi_stall() - sleep + * @microseconds: period to sleep in microseconds * - * This function implements the Stall sercive. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. + * This function implements the Stall service. * - * @microseconds: period to sleep in microseconds - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_stall(unsigned long microseconds) { @@ -1896,17 +1917,18 @@ static efi_status_t EFIAPI efi_stall(unsigned long microseconds) } /** - * efi_set_watchdog_timer - reset the watchdog timer + * efi_set_watchdog_timer() - reset the watchdog timer + * @timeout: seconds before reset by watchdog + * @watchdog_code: code to be logged when resetting + * @data_size: size of buffer in bytes + * @watchdog_data: buffer with data describing the reset reason * * This function implements the SetWatchdogTimer service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @timeout: seconds before reset by watchdog - * @watchdog_code: code to be logged when resetting - * @data_size: size of buffer in bytes - * @watchdog_data: buffer with data describing the reset reason - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout, uint64_t watchdog_code, @@ -1919,17 +1941,18 @@ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout, } /** - * efi_close_protocol - close a protocol + * efi_close_protocol() - close a protocol + * @handle: handle on which the protocol shall be closed + * @protocol: GUID of the protocol to close + * @agent_handle: handle of the driver + * @controller_handle: handle of the controller * * This function implements the CloseProtocol service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @handle: handle on which the protocol shall be closed - * @protocol: GUID of the protocol to close - * @agent_handle: handle of the driver - * @controller_handle: handle of the controller - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_close_protocol(efi_handle_t handle, const efi_guid_t *protocol, @@ -1966,18 +1989,19 @@ out: } /** - * efi_open_protocol_information - provide information about then open status - * of a protocol on a handle + * efi_open_protocol_information() - provide information about then open status + * of a protocol on a handle + * @handle: handle for which the information shall be retrieved + * @protocol: GUID of the protocol + * @entry_buffer: buffer to receive the open protocol information + * @entry_count: number of entries available in the buffer * * This function implements the OpenProtocolInformation service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @handle: handle for which the information shall be retrieved - * @protocol: GUID of the protocol - * @entry_buffer: buffer to receive the open protocol information - * @entry_count: number of entries available in the buffer - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_open_protocol_information( efi_handle_t handle, const efi_guid_t *protocol, @@ -2030,16 +2054,17 @@ out: } /** - * efi_protocols_per_handle - get protocols installed on a handle + * efi_protocols_per_handle() - get protocols installed on a handle + * @handle: handle for which the information is retrieved + * @protocol_buffer: buffer with protocol GUIDs + * @protocol_buffer_count: number of entries in the buffer * * This function implements the ProtocolsPerHandleService. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @handle: handle for which the information is retrieved - * @protocol_buffer: buffer with protocol GUIDs - * @protocol_buffer_count: number of entries in the buffer - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_protocols_per_handle( efi_handle_t handle, efi_guid_t ***protocol_buffer, @@ -2091,18 +2116,19 @@ static efi_status_t EFIAPI efi_protocols_per_handle( } /** - * efi_locate_handle_buffer - locate handles implementing a protocol + * efi_locate_handle_buffer() - locate handles implementing a protocol + * @search_type: selection criterion + * @protocol: GUID of the protocol + * @search_key: registration key + * @no_handles: number of returned handles + * @buffer: buffer with the returned handles * * This function implements the LocateHandleBuffer service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @search_type: selection criterion - * @protocol: GUID of the protocol - * @search_key: registration key - * @no_handles: number of returned handles - * @buffer: buffer with the returned handles - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_locate_handle_buffer( enum efi_locate_search_type search_type, @@ -2138,16 +2164,17 @@ out: } /** - * efi_locate_protocol - find an interface implementing a protocol + * efi_locate_protocol() - find an interface implementing a protocol + * @protocol: GUID of the protocol + * @registration: registration key passed to the notification function + * @protocol_interface: interface implementing the protocol * * This function implements the LocateProtocol service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @protocol: GUID of the protocol - * @registration: registration key passed to the notification function - * @protocol_interface: interface implementing the protocol - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol, void *registration, @@ -2179,17 +2206,18 @@ static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol, } /** - * efi_locate_device_path - Get the device path and handle of an device - * implementing a protocol + * efi_locate_device_path() - Get the device path and handle of an device + * implementing a protocol + * @protocol: GUID of the protocol + * @device_path: device path + * @device: handle of the device * * This function implements the LocateDevicePath service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @protocol: GUID of the protocol - * @device_path: device path - * @device: handle of the device - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_locate_device_path( const efi_guid_t *protocol, @@ -2256,17 +2284,18 @@ out: } /** - * Install multiple protocol interfaces. + * efi_install_multiple_protocol_interfaces() - Install multiple protocol + * interfaces + * @handle: handle on which the protocol interfaces shall be installed + * @...: NULL terminated argument list with pairs of protocol GUIDS and + * interfaces * * This function implements the MultipleProtocolInterfaces service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @handle: handle on which the protocol interfaces shall be - * installed - * @...: NULL terminated argument list with pairs of protocol - * GUIDS and interfaces - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( void **handle, ...) @@ -2314,18 +2343,18 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( } /** - * efi_uninstall_multiple_protocol_interfaces - uninstall multiple protocol - * interfaces + * efi_uninstall_multiple_protocol_interfaces() - uninstall multiple protocol + * interfaces + * @handle: handle from which the protocol interfaces shall be removed + * @...: NULL terminated argument list with pairs of protocol GUIDS and + * interfaces * * This function implements the UninstallMultipleProtocolInterfaces service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @handle: handle from which the protocol interfaces shall be - * removed - * @...: NULL terminated argument list with pairs of protocol - * GUIDS and interfaces - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( void *handle, ...) @@ -2373,16 +2402,17 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( } /** - * efi_calculate_crc32 - calculate cyclic redundancy code + * efi_calculate_crc32() - calculate cyclic redundancy code + * @data: buffer with data + * @data_size: size of buffer in bytes + * @crc32_p: cyclic redundancy code * * This function implements the CalculateCrc32 service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @data: buffer with data - * @data_size: size of buffer in bytes - * @crc32_p: cyclic redundancy code - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_calculate_crc32(void *data, unsigned long data_size, @@ -2394,15 +2424,15 @@ static efi_status_t EFIAPI efi_calculate_crc32(void *data, } /** - * efi_copy_mem - copy memory + * efi_copy_mem() - copy memory + * @destination: destination of the copy operation + * @source: source of the copy operation + * @length: number of bytes to copy * * This function implements the CopyMem service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @destination: destination of the copy operation - * @source: source of the copy operation - * @length: number of bytes to copy + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. */ static void EFIAPI efi_copy_mem(void *destination, const void *source, size_t length) @@ -2413,15 +2443,15 @@ static void EFIAPI efi_copy_mem(void *destination, const void *source, } /** - * efi_set_mem - Fill memory with a byte value. + * efi_set_mem() - Fill memory with a byte value. + * @buffer: buffer to fill + * @size: size of buffer in bytes + * @value: byte to copy to the buffer * * This function implements the SetMem service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @buffer: buffer to fill - * @size: size of buffer in bytes - * @value: byte to copy to the buffer + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. */ static void EFIAPI efi_set_mem(void *buffer, size_t size, uint8_t value) { @@ -2431,14 +2461,14 @@ static void EFIAPI efi_set_mem(void *buffer, size_t size, uint8_t value) } /** - * efi_protocol_open - open protocol interface on a handle + * efi_protocol_open() - open protocol interface on a handle + * @handler: handler of a protocol + * @protocol_interface: interface implementing the protocol + * @agent_handle: handle of the driver + * @controller_handle: handle of the controller + * @attributes: attributes indicating how to open the protocol * - * @handler: handler of a protocol - * @protocol_interface: interface implementing the protocol - * @agent_handle: handle of the driver - * @controller_handle: handle of the controller - * @attributes: attributes indicating how to open the protocol - * Return Value: status code + * Return: status code */ static efi_status_t efi_protocol_open( struct efi_handler *handler, @@ -2526,19 +2556,20 @@ out: } /** - * efi_open_protocol - open protocol interface on a handle + * efi_open_protocol() - open protocol interface on a handle + * @handle: handle on which the protocol shall be opened + * @protocol: GUID of the protocol + * @protocol_interface: interface implementing the protocol + * @agent_handle: handle of the driver + * @controller_handle: handle of the controller + * @attributes: attributes indicating how to open the protocol * * This function implements the OpenProtocol interface. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @handle: handle on which the protocol shall be opened - * @protocol: GUID of the protocol - * @protocol_interface: interface implementing the protocol - * @agent_handle: handle of the driver - * @controller_handle: handle of the controller - * @attributes: attributes indicating how to open the protocol - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_open_protocol( void *handle, const efi_guid_t *protocol, @@ -2593,16 +2624,17 @@ out: } /** - * efi_handle_protocol - get interface of a protocol on a handle + * efi_handle_protocol() - get interface of a protocol on a handle + * @handle: handle on which the protocol shall be opened + * @protocol: GUID of the protocol + * @protocol_interface: interface implementing the protocol * * This function implements the HandleProtocol service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @handle: handle on which the protocol shall be opened - * @protocol: GUID of the protocol - * @protocol_interface: interface implementing the protocol - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_handle_protocol(efi_handle_t handle, const efi_guid_t *protocol, @@ -2613,12 +2645,12 @@ static efi_status_t EFIAPI efi_handle_protocol(efi_handle_t handle, } /** - * efi_bind_controller - bind a single driver to a controller + * efi_bind_controller() - bind a single driver to a controller + * @controller_handle: controller handle + * @driver_image_handle: driver handle + * @remain_device_path: remaining path * - * @controller_handle: controller handle - * @driver_image_handle: driver handle - * @remain_device_path: remaining path - * Return Value: status code + * Return: status code */ static efi_status_t efi_bind_controller( efi_handle_t controller_handle, @@ -2649,12 +2681,12 @@ static efi_status_t efi_bind_controller( } /** - * efi_connect_single_controller - connect a single driver to a controller + * efi_connect_single_controller() - connect a single driver to a controller + * @controller_handle: controller + * @driver_image_handle: driver + * @remain_device_path: remainting path * - * @controller_handle: controller - * @driver_image_handle: driver - * @remain_device_path: remainting path - * Return Value: status code + * Return: status code */ static efi_status_t efi_connect_single_controller( efi_handle_t controller_handle, @@ -2721,21 +2753,22 @@ static efi_status_t efi_connect_single_controller( } /** - * efi_connect_controller - connect a controller to a driver + * efi_connect_controller() - connect a controller to a driver + * @controller_handle: handle of the controller + * @driver_image_handle: handle of the driver + * @remain_device_path: device path of a child controller + * @recursive: true to connect all child controllers * * This function implements the ConnectController service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. * * First all driver binding protocol handles are tried for binding drivers. * Afterwards all handles that have openened a protocol of the controller * with EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER are connected to drivers. * - * @controller_handle: handle of the controller - * @driver_image_handle: handle of the driver - * @remain_device_path: device path of a child controller - * @recursive: true to connect all child controllers - * Return Value: status code + * Return: status code */ static efi_status_t EFIAPI efi_connect_controller( efi_handle_t controller_handle, @@ -2789,21 +2822,21 @@ out: } /** - * efi_reinstall_protocol_interface - reinstall protocol interface + * efi_reinstall_protocol_interface() - reinstall protocol interface + * @handle: handle on which the protocol shall be reinstalled + * @protocol: GUID of the protocol to be installed + * @old_interface: interface to be removed + * @new_interface: interface to be installed * * This function implements the ReinstallProtocolInterface service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. * * The old interface is uninstalled. The new interface is installed. * Drivers are connected. * - * @handle: handle on which the protocol shall be - * reinstalled - * @protocol: GUID of the protocol to be installed - * @old_interface: interface to be removed - * @new_interface: interface to be installed - * Return Value: status code + * Return: status code */ static efi_status_t EFIAPI efi_reinstall_protocol_interface( efi_handle_t handle, const efi_guid_t *protocol, @@ -2832,15 +2865,15 @@ out: } /** - * efi_get_child_controllers - get all child controllers associated to a driver + * efi_get_child_controllers() - get all child controllers associated to a driver + * @efiobj: handle of the controller + * @driver_handle: handle of the driver + * @number_of_children: number of child controllers + * @child_handle_buffer: handles of the the child controllers * * The allocated buffer has to be freed with free(). * - * @efiobj: handle of the controller - * @driver_handle: handle of the driver - * @number_of_children: number of child controllers - * @child_handle_buffer: handles of the the child controllers - * Return Value: status code + * Return: status code */ static efi_status_t efi_get_child_controllers( struct efi_object *efiobj, @@ -2896,16 +2929,17 @@ static efi_status_t efi_get_child_controllers( } /** - * efi_disconnect_controller - disconnect a controller from a driver + * efi_disconnect_controller() - disconnect a controller from a driver + * @controller_handle: handle of the controller + * @driver_image_handle: handle of the driver + * @child_handle: handle of the child to destroy * * This function implements the DisconnectController service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. * - * @controller_handle: handle of the controller - * @driver_image_handle: handle of the driver - * @child_handle: handle of the child to destroy - * Return Value: status code + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code */ static efi_status_t EFIAPI efi_disconnect_controller( efi_handle_t controller_handle, diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 08a6c76845..3cb6259182 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1,5 +1,7 @@ -#!/usr/bin/perl -w +#!/usr/bin/env perl +# SPDX-License-Identifier: GPL-2.0 +use warnings; use strict; ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ## @@ -39,41 +41,51 @@ use strict; # 25/07/2012 - Added support for HTML5 # -- Dan Luedtke -# -# This will read a 'c' file and scan for embedded comments in the -# style of gnome comments (+minor extensions - see below). -# - -# Note: This only supports 'c'. - -# usage: -# kernel-doc [ -docbook | -html | -html5 | -text | -man | -list ] -# [ -no-doc-sections ] -# [ -function funcname [ -function funcname ...] ] -# c file(s)s > outputfile -# or -# [ -nofunction funcname [ -function funcname ...] ] -# c file(s)s > outputfile -# -# Set output format using one of -docbook -html -html5 -text or -man. -# Default is man. -# The -list format is for internal use by docproc. -# -# -no-doc-sections -# Do not output DOC: sections -# -# -function funcname -# If set, then only generate documentation for the given function(s) or -# DOC: section titles. All other functions and DOC: sections are ignored. -# -# -nofunction funcname -# If set, then only generate documentation for the other function(s)/DOC: -# sections. Cannot be used together with -function (yes, that's a bug -- -# perl hackers can fix it 8)) -# -# c files - list of 'c' files to process -# -# All output goes to stdout, with errors to stderr. +sub usage { + my $message = <<"EOF"; +Usage: $0 [OPTION ...] FILE ... + +Read C language source or header FILEs, extract embedded documentation comments, +and print formatted documentation to standard output. + +The documentation comments are identified by "/**" opening comment mark. See +Documentation/doc-guide/kernel-doc.rst for the documentation comment syntax. + +Output format selection (mutually exclusive): + -man Output troff manual page format. This is the default. + -rst Output reStructuredText format. + -none Do not output documentation, only warnings. + +Output selection (mutually exclusive): + -export Only output documentation for symbols that have been + exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL() + in any input FILE or -export-file FILE. + -internal Only output documentation for symbols that have NOT been + exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL() + in any input FILE or -export-file FILE. + -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. + +Output selection modifiers: + -no-doc-sections Do not output DOC: sections. + -enable-lineno Enable output of #define LINENO lines. Only works with + reStructuredText format. + -export-file FILE Specify an additional FILE in which to look for + EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL(). To be used with + -export or -internal. May be specified multiple times. + +Other parameters: + -v Verbose output, more warnings and other information. + -h Print this help. + +EOF + print $message; + exit 1; +} # # format of comments. @@ -133,6 +145,30 @@ use strict; # # All descriptions can be multiline, except the short function description. # +# For really longs structs, you can also describe arguments inside the +# body of the struct. +# eg. +# /** +# * struct my_struct - short description +# * @a: first member +# * @b: second member +# * +# * Longer description +# */ +# struct my_struct { +# int a; +# int b; +# /** +# * @c: This is longer description of C +# * +# * You can use paragraphs to describe arguments +# * using this method. +# */ +# int c; +# }; +# +# This should be use only for struct/enum members. +# # You can also add additional sections. When documenting kernel functions you # should document the "Context:" of the function, e.g. whether the functions # can be called form interrupts. Unlike other sections you can end it with an @@ -161,8 +197,10 @@ use strict; # 'funcname()' - function # '$ENVVAR' - environmental variable # '&struct_name' - name of a structure (up to two words including 'struct') +# '&struct_name.member' - name of a structure member # '@parameter' - name of a parameter # '%CONST' - name of a constant. +# '``LITERAL``' - literal string without any spaces on it. ## init lots of data @@ -171,71 +209,56 @@ my $warnings = 0; my $anon_struct_union = 0; # match expressions used to find embedded type information -my $type_constant = '\%([-_\w]+)'; +my $type_constant = '\b``([^\`]+)``\b'; +my $type_constant2 = '\%([-_\w]+)'; my $type_func = '(\w+)\(\)'; -my $type_param = '\@(\w+)'; -my $type_struct = '\&((struct\s*)*[_\w]+)'; -my $type_struct_xml = '\\&((struct\s*)*[_\w]+)'; +my $type_param = '\@(\w*(\.\w+)*(\.\.\.)?)'; +my $type_fp_param = '\@(\w+)\(\)'; # Special RST handling for func ptr params my $type_env = '(\$\w+)'; +my $type_enum = '\&(enum\s*([_\w]+))'; +my $type_struct = '\&(struct\s*([_\w]+))'; +my $type_typedef = '\&(typedef\s*([_\w]+))'; +my $type_union = '\&(union\s*([_\w]+))'; +my $type_member = '\&([_\w]+)(\.|->)([_\w]+)'; +my $type_fallback = '\&([_\w]+)'; +my $type_member_func = $type_member . '\(\)'; # Output conversion substitutions. # One for each output format -# these work fairly well -my %highlights_html = ( $type_constant, "\$1", - $type_func, "\$1", - $type_struct_xml, "\$1", - $type_env, "\$1", - $type_param, "\$1" ); -my $local_lt = "\\\\\\\\lt:"; -my $local_gt = "\\\\\\\\gt:"; -my $blankline_html = $local_lt . "p" . $local_gt; # was "

" - -# html version 5 -my %highlights_html5 = ( $type_constant, "\$1", - $type_func, "\$1", - $type_struct_xml, "\$1", - $type_env, "\$1", - $type_param, "\$1" ); -my $blankline_html5 = $local_lt . "br /" . $local_gt; - -# XML, docbook format -my %highlights_xml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1\$2", - $type_constant, "\$1", - $type_func, "\$1", - $type_struct_xml, "\$1", - $type_env, "\$1", - $type_param, "\$1" ); -my $blankline_xml = $local_lt . "/para" . $local_gt . $local_lt . "para" . $local_gt . "\n"; - -# gnome, docbook format -my %highlights_gnome = ( $type_constant, "\$1", - $type_func, "\$1", - $type_struct, "\$1", - $type_env, "\$1", - $type_param, "\$1" ); -my $blankline_gnome = "\n"; - # these are pretty rough -my %highlights_man = ( $type_constant, "\$1", - $type_func, "\\\\fB\$1\\\\fP", - $type_struct, "\\\\fI\$1\\\\fP", - $type_param, "\\\\fI\$1\\\\fP" ); +my @highlights_man = ( + [$type_constant, "\$1"], + [$type_constant2, "\$1"], + [$type_func, "\\\\fB\$1\\\\fP"], + [$type_enum, "\\\\fI\$1\\\\fP"], + [$type_struct, "\\\\fI\$1\\\\fP"], + [$type_typedef, "\\\\fI\$1\\\\fP"], + [$type_union, "\\\\fI\$1\\\\fP"], + [$type_param, "\\\\fI\$1\\\\fP"], + [$type_member, "\\\\fI\$1\$2\$3\\\\fP"], + [$type_fallback, "\\\\fI\$1\\\\fP"] + ); my $blankline_man = ""; -# text-mode -my %highlights_text = ( $type_constant, "\$1", - $type_func, "\$1", - $type_struct, "\$1", - $type_param, "\$1" ); -my $blankline_text = ""; - -# list mode -my %highlights_list = ( $type_constant, "\$1", - $type_func, "\$1", - $type_struct, "\$1", - $type_param, "\$1" ); -my $blankline_list = ""; +# rst-mode +my @highlights_rst = ( + [$type_constant, "``\$1``"], + [$type_constant2, "``\$1``"], + # Note: need to escape () to avoid func matching later + [$type_member_func, "\\:c\\:type\\:`\$1\$2\$3\\\\(\\\\) <\$1>`"], + [$type_member, "\\:c\\:type\\:`\$1\$2\$3 <\$1>`"], + [$type_fp_param, "**\$1\\\\(\\\\)**"], + [$type_func, "\\:c\\:func\\:`\$1()`"], + [$type_enum, "\\:c\\:type\\:`\$1 <\$2>`"], + [$type_struct, "\\:c\\:type\\:`\$1 <\$2>`"], + [$type_typedef, "\\:c\\:type\\:`\$1 <\$2>`"], + [$type_union, "\\:c\\:type\\:`\$1 <\$2>`"], + # in rst this can refer to any type + [$type_fallback, "\\:c\\:type\\:`\$1`"], + [$type_param, "**\$1**"] + ); +my $blankline_rst = "\n"; # read arguments if ($#ARGV == -1) { @@ -246,24 +269,45 @@ my $kernelversion; my $dohighlight = ""; my $verbose = 0; -my $output_mode = "man"; +my $output_mode = "rst"; my $output_preformatted = 0; my $no_doc_sections = 0; -my %highlights = %highlights_man; -my $blankline = $blankline_man; -my $modulename = "Bootloader API"; -my $function_only = 0; +my $enable_lineno = 0; +my @highlights = @highlights_rst; +my $blankline = $blankline_rst; +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 +}; +my $output_selection = OUTPUT_ALL; +my $show_not_found = 0; + +my @export_file_list; + +my @build_time; +if (defined($ENV{'KBUILD_BUILD_TIMESTAMP'}) && + (my $seconds = `date -d"${ENV{'KBUILD_BUILD_TIMESTAMP'}}" +%s`) ne '') { + @build_time = gmtime($seconds); +} else { + @build_time = localtime; +} + my $man_date = ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', - 'November', 'December')[(localtime)[4]] . - " " . ((localtime)[5]+1900); -my $show_not_found = 0; + 'November', 'December')[$build_time[4]] . + " " . ($build_time[5]+1900); # Essentially these are globals. # They probably want to be tidied up, made more localised or something. # 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 $declaration_start_line; my ($type, $declaration_name, $return_type); my ($newsection, $newcontents, $prototype, $brcount, %source_map); @@ -281,39 +325,65 @@ my $section_counter = 0; my $lineprefix=""; -# states -# 0 - normal code -# 1 - looking for function name -# 2 - scanning field start. -# 3 - scanning prototype. -# 4 - documentation block +# 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 +}; my $state; my $in_doc_sect; +my $leading_space; + +# Inline documentation state +use constant { + 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. +}; +my $inline_doc_state; #declaration types: can be # 'function', 'struct', 'union', 'enum', 'typedef' my $decl_type; -my $doc_special = "\@\%\$\&"; - my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start. my $doc_end = '\*/'; my $doc_com = '\s*\*\s*'; my $doc_com_body = '\s*\* ?'; my $doc_decl = $doc_com . '(\w+)'; -my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)'; +# @params and a strictly limited set of supported section names +my $doc_sect = $doc_com . + '\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:(.*)'; my $doc_content = $doc_com_body . '(.*)'; my $doc_block = $doc_com . 'DOC:\s*(.*)?'; +my $doc_inline_start = '^\s*/\*\*\s*$'; +my $doc_inline_sect = '\s*\*\s*(@\s*[\w][\w\.]*\s*):(.*)'; +my $doc_inline_end = '^\s*\*/\s*$'; +my $doc_inline_oneline = '^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$'; +my $export_symbol = '^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*;'; -my %constants; my %parameterdescs; +my %parameterdesc_start_lines; my @parameterlist; my %sections; my @sectionlist; +my %section_start_lines; my $sectcheck; my $struct_actual; my $contents = ""; +my $new_start_line = 0; + +# the canonical section names. see also $doc_sect above. my $section_default = "Description"; # default section my $section_intro = "Introduction"; my $section = $section_default; @@ -324,80 +394,73 @@ my $undescribed = "-- undescribed --"; reset_state(); -while ($ARGV[0] =~ m/^-(.*)/) { - my $cmd = shift @ARGV; - if ($cmd eq "-html") { - $output_mode = "html"; - %highlights = %highlights_html; - $blankline = $blankline_html; - } elsif ($cmd eq "-html5") { - $output_mode = "html5"; - %highlights = %highlights_html5; - $blankline = $blankline_html5; - } elsif ($cmd eq "-man") { +while ($ARGV[0] =~ m/^--?(.*)/) { + my $cmd = $1; + shift @ARGV; + if ($cmd eq "man") { $output_mode = "man"; - %highlights = %highlights_man; + @highlights = @highlights_man; $blankline = $blankline_man; - } elsif ($cmd eq "-text") { - $output_mode = "text"; - %highlights = %highlights_text; - $blankline = $blankline_text; - } elsif ($cmd eq "-docbook") { - $output_mode = "xml"; - %highlights = %highlights_xml; - $blankline = $blankline_xml; - } elsif ($cmd eq "-list") { - $output_mode = "list"; - %highlights = %highlights_list; - $blankline = $blankline_list; - } elsif ($cmd eq "-gnome") { - $output_mode = "gnome"; - %highlights = %highlights_gnome; - $blankline = $blankline_gnome; - } elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document + } elsif ($cmd eq "rst") { + $output_mode = "rst"; + @highlights = @highlights_rst; + $blankline = $blankline_rst; + } elsif ($cmd eq "none") { + $output_mode = "none"; + } elsif ($cmd eq "module") { # not needed for XML, inherits from calling document $modulename = shift @ARGV; - } elsif ($cmd eq "-function") { # to only output specific functions - $function_only = 1; + } elsif ($cmd eq "function") { # to only output specific functions + $output_selection = OUTPUT_INCLUDE; $function = shift @ARGV; $function_table{$function} = 1; - } elsif ($cmd eq "-nofunction") { # to only output specific functions - $function_only = 2; + } elsif ($cmd eq "nofunction") { # output all except specific functions + $output_selection = OUTPUT_EXCLUDE; $function = shift @ARGV; $function_table{$function} = 1; - } elsif ($cmd eq "-v") { + } elsif ($cmd eq "export") { # only exported symbols + $output_selection = OUTPUT_EXPORTED; + %function_table = (); + } elsif ($cmd eq "internal") { # only non-exported symbols + $output_selection = OUTPUT_INTERNAL; + %function_table = (); + } elsif ($cmd eq "export-file") { + my $file = shift @ARGV; + push(@export_file_list, $file); + } elsif ($cmd eq "v") { $verbose = 1; - } elsif (($cmd eq "-h") || ($cmd eq "--help")) { + } elsif (($cmd eq "h") || ($cmd eq "help")) { usage(); - } elsif ($cmd eq '-no-doc-sections') { + } elsif ($cmd eq 'no-doc-sections') { $no_doc_sections = 1; - } elsif ($cmd eq '-show-not-found') { + } elsif ($cmd eq 'enable-lineno') { + $enable_lineno = 1; + } elsif ($cmd eq 'show-not-found') { $show_not_found = 1; + } else { + # Unknown argument + usage(); } } # continue execution near EOF; -sub usage { - print "Usage: $0 [ -docbook | -html | -html5 | -text | -man | -list ]\n"; - print " [ -no-doc-sections ]\n"; - print " [ -function funcname [ -function funcname ...] ]\n"; - print " [ -nofunction funcname [ -nofunction funcname ...] ]\n"; - print " [ -v ]\n"; - print " c source file(s) > outputfile\n"; - print " -v : verbose output, more warnings & other info listed\n"; - exit 1; -} - # get kernel version from env sub get_kernel_version() { my $version = 'unknown kernel version'; - if (defined($ENV{'UBOOTVERSION'})) { - $version = $ENV{'UBOOTVERSION'}; + if (defined($ENV{'KERNELVERSION'})) { + $version = $ENV{'KERNELVERSION'}; } return $version; } +# +sub print_lineno { + my $lineno = shift; + if ($enable_lineno && defined($lineno)) { + print "#define LINENO " . $lineno . "\n"; + } +} ## # dumps section contents to arrays/hashes intended for that purpose. # @@ -406,28 +469,32 @@ sub dump_section { my $name = shift; my $contents = join "\n", @_; - if ($name =~ m/$type_constant/) { - $name = $1; -# print STDERR "constant section '$1' = '$contents'\n"; - $constants{$name} = $contents; - } elsif ($name =~ m/$type_param/) { -# print STDERR "parameter def '$1' = '$contents'\n"; + if ($name =~ m/$type_param/) { $name = $1; $parameterdescs{$name} = $contents; $sectcheck = $sectcheck . $name . " "; + $parameterdesc_start_lines{$name} = $new_start_line; + $new_start_line = 0; } elsif ($name eq "@\.\.\.") { -# print STDERR "parameter def '...' = '$contents'\n"; $name = "..."; $parameterdescs{$name} = $contents; $sectcheck = $sectcheck . $name . " "; + $parameterdesc_start_lines{$name} = $new_start_line; + $new_start_line = 0; } else { -# print STDERR "other section '$name' = '$contents'\n"; if (defined($sections{$name}) && ($sections{$name} ne "")) { - print STDERR "Error(${file}:$.): duplicate section name '$name'\n"; - ++$errors; + # Only warn on user specified duplicate section names. + if ($name ne $section_default) { + print STDERR "${file}:$.: warning: duplicate section name '$name'\n"; + ++$warnings; + } + $sections{$name} .= $contents; + } else { + $sections{$name} = $contents; + push @sectionlist, $name; + $section_start_lines{$name} = $new_start_line; + $new_start_line = 0; } - $sections{$name} = $contents; - push @sectionlist, $name; } } @@ -443,15 +510,17 @@ sub dump_doc_section { return; } - if (($function_only == 0) || - ( $function_only == 1 && defined($function_table{$name})) || - ( $function_only == 2 && !defined($function_table{$name}))) + if (($output_selection == OUTPUT_ALL) || + ($output_selection == OUTPUT_INCLUDE && + defined($function_table{$name})) || + ($output_selection == OUTPUT_EXCLUDE && + !defined($function_table{$name}))) { dump_section($file, $name, $contents); output_blockhead({'sectionlist' => \@sectionlist, 'sections' => \%sections, 'module' => $modulename, - 'content-only' => ($function_only != 0), }); + 'content-only' => ($output_selection != OUTPUT_ALL), }); } } @@ -476,32 +545,20 @@ sub output_highlight { # confess "output_highlight got called with no args?\n"; # } - if ($output_mode eq "html" || $output_mode eq "html5" || - $output_mode eq "xml") { - $contents = local_unescape($contents); - # convert data read & converted thru xml_escape() into &xyz; format: - $contents =~ s/\\\\\\/\&/g; - } # print STDERR "contents b4:$contents\n"; eval $dohighlight; die $@ if $@; # print STDERR "contents af:$contents\n"; -# strip whitespaces when generating html5 - if ($output_mode eq "html5") { - $contents =~ s/^\s+//; - $contents =~ s/\s+$//; - } foreach $line (split "\n", $contents) { if (! $output_preformatted) { $line =~ s/^\s*//; } if ($line eq ""){ if (! $output_preformatted) { - print $lineprefix, local_unescape($blankline); + print $lineprefix, $blankline; } } else { - $line =~ s/\\\\\\/\&/g; if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { print "\\&$line"; } else { @@ -512,815 +569,6 @@ sub output_highlight { } } -# output sections in html -sub output_section_html(%) { - my %args = %{$_[0]}; - my $section; - - foreach $section (@{$args{'sectionlist'}}) { - print "

$section

\n"; - print "
\n"; - output_highlight($args{'sections'}{$section}); - print "
\n"; - } -} - -# output enum in html -sub output_enum_html(%) { - my %args = %{$_[0]}; - my ($parameter); - my $count; - print "

enum " . $args{'enum'} . "

\n"; - - print "enum " . $args{'enum'} . " {
\n"; - $count = 0; - foreach $parameter (@{$args{'parameterlist'}}) { - print " " . $parameter . ""; - if ($count != $#{$args{'parameterlist'}}) { - $count++; - print ",\n"; - } - print "
"; - } - print "};
\n"; - - print "

Constants

\n"; - print "
\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - print "
" . $parameter . "\n"; - print "
"; - output_highlight($args{'parameterdescs'}{$parameter}); - } - print "
\n"; - output_section_html(@_); - print "
\n"; -} - -# output typedef in html -sub output_typedef_html(%) { - my %args = %{$_[0]}; - my ($parameter); - my $count; - print "

typedef " . $args{'typedef'} . "

\n"; - - print "typedef " . $args{'typedef'} . "\n"; - output_section_html(@_); - print "
\n"; -} - -# output struct in html -sub output_struct_html(%) { - my %args = %{$_[0]}; - my ($parameter); - - print "

" . $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "

\n"; - print "" . $args{'type'} . " " . $args{'struct'} . " {
\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - if ($parameter =~ /^#/) { - print "$parameter
\n"; - next; - } - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - $type = $args{'parametertypes'}{$parameter}; - if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { - # pointer-to-function - print "    $1$parameter) ($2);
\n"; - } elsif ($type =~ m/^(.*?)\s*(:.*)/) { - # bitfield - print "    $1 $parameter$2;
\n"; - } else { - print "    $type $parameter;
\n"; - } - } - print "};
\n"; - - print "

Members

\n"; - print "
\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - ($parameter =~ /^#/) && next; - - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - print "
" . $parameter . "\n"; - print "
"; - output_highlight($args{'parameterdescs'}{$parameter_name}); - } - print "
\n"; - output_section_html(@_); - print "
\n"; -} - -# output function in html -sub output_function_html(%) { - my %args = %{$_[0]}; - my ($parameter, $section); - my $count; - - print "

" . $args{'function'} . " - " . $args{'purpose'} . "

\n"; - print "" . $args{'functiontype'} . "\n"; - print "" . $args{'function'} . "\n"; - print "("; - $count = 0; - foreach $parameter (@{$args{'parameterlist'}}) { - $type = $args{'parametertypes'}{$parameter}; - if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { - # pointer-to-function - print "$1$parameter) ($2)"; - } else { - print "" . $type . " " . $parameter . ""; - } - if ($count != $#{$args{'parameterlist'}}) { - $count++; - print ",\n"; - } - } - print ")\n"; - - print "

Arguments

\n"; - print "
\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - print "
" . $parameter . "\n"; - print "
"; - output_highlight($args{'parameterdescs'}{$parameter_name}); - } - print "
\n"; - output_section_html(@_); - print "
\n"; -} - -# output DOC: block header in html -sub output_blockhead_html(%) { - my %args = %{$_[0]}; - my ($parameter, $section); - my $count; - - foreach $section (@{$args{'sectionlist'}}) { - print "

$section

\n"; - print "
    \n"; - output_highlight($args{'sections'}{$section}); - print "
\n"; - } - print "
\n"; -} - -# output sections in html5 -sub output_section_html5(%) { - my %args = %{$_[0]}; - my $section; - - foreach $section (@{$args{'sectionlist'}}) { - print "
\n"; - print "

$section

\n"; - print "

\n"; - output_highlight($args{'sections'}{$section}); - print "

\n"; - print "
\n"; - } -} - -# output enum in html5 -sub output_enum_html5(%) { - my %args = %{$_[0]}; - my ($parameter); - my $count; - my $html5id; - - $html5id = $args{'enum'}; - $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; - print "
"; - print "

enum " . $args{'enum'} . "

\n"; - print "
    \n"; - print "
  1. "; - print "enum "; - print "" . $args{'enum'} . " {"; - print "
  2. \n"; - $count = 0; - foreach $parameter (@{$args{'parameterlist'}}) { - print "
  3. "; - print "" . $parameter . ""; - if ($count != $#{$args{'parameterlist'}}) { - $count++; - print ","; - } - print "
  4. \n"; - } - print "
  5. };
  6. \n"; - print "
\n"; - - print "
\n"; - print "

Constants

\n"; - print "
\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - print "
" . $parameter . "
\n"; - print "
"; - output_highlight($args{'parameterdescs'}{$parameter}); - print "
\n"; - } - print "
\n"; - print "
\n"; - output_section_html5(@_); - print "
\n"; -} - -# output typedef in html5 -sub output_typedef_html5(%) { - my %args = %{$_[0]}; - my ($parameter); - my $count; - my $html5id; - - $html5id = $args{'typedef'}; - $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; - print "
\n"; - print "

typedef " . $args{'typedef'} . "

\n"; - - print "
    \n"; - print "
  1. "; - print "typedef "; - print "" . $args{'typedef'} . ""; - print "
  2. \n"; - print "
\n"; - output_section_html5(@_); - print "
\n"; -} - -# output struct in html5 -sub output_struct_html5(%) { - my %args = %{$_[0]}; - my ($parameter); - my $html5id; - - $html5id = $args{'struct'}; - $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; - print "
\n"; - print "
\n"; - print "

" . $args{'type'} . " " . $args{'struct'} . "

"; - print "

". $args{'purpose'} . "

\n"; - print "
\n"; - print "
    \n"; - print "
  1. "; - print "" . $args{'type'} . " "; - print "" . $args{'struct'} . " {"; - print "
  2. \n"; - foreach $parameter (@{$args{'parameterlist'}}) { - print "
  3. "; - if ($parameter =~ /^#/) { - print "" . $parameter ."\n"; - print "
  4. \n"; - next; - } - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - $type = $args{'parametertypes'}{$parameter}; - if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { - # pointer-to-function - print "$1 "; - print "$parameter"; - print ") "; - print "($2);"; - } elsif ($type =~ m/^(.*?)\s*(:.*)/) { - # bitfield - print "$1 "; - print "$parameter"; - print "$2;"; - } else { - print "$type "; - print "$parameter;"; - } - print "\n"; - } - print "
  5. };
  6. \n"; - print "
\n"; - - print "
\n"; - print "

Members

\n"; - print "
\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - ($parameter =~ /^#/) && next; - - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - print "
" . $parameter . "
\n"; - print "
"; - output_highlight($args{'parameterdescs'}{$parameter_name}); - print "
\n"; - } - print "
\n"; - print "
\n"; - output_section_html5(@_); - print "
\n"; -} - -# output function in html5 -sub output_function_html5(%) { - my %args = %{$_[0]}; - my ($parameter, $section); - my $count; - my $html5id; - - $html5id = $args{'function'}; - $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; - print "
\n"; - print "
\n"; - print "

" . $args{'function'} . "

"; - print "

" . $args{'purpose'} . "

\n"; - print "
\n"; - print "
    \n"; - print "
  1. "; - print "" . $args{'functiontype'} . " "; - print "" . $args{'function'} . " ("; - print "
  2. "; - $count = 0; - foreach $parameter (@{$args{'parameterlist'}}) { - print "
  3. "; - $type = $args{'parametertypes'}{$parameter}; - if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { - # pointer-to-function - print "$1 "; - print "$parameter"; - print ") "; - print "($2)"; - } else { - print "$type "; - print "$parameter"; - } - if ($count != $#{$args{'parameterlist'}}) { - $count++; - print ","; - } - print "
  4. \n"; - } - print "
  5. )
  6. \n"; - print "
\n"; - - print "
\n"; - print "

Arguments

\n"; - print "

\n"; - print "

\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - print "
" . $parameter . "
\n"; - print "
"; - output_highlight($args{'parameterdescs'}{$parameter_name}); - print "
\n"; - } - print "
\n"; - print "
\n"; - output_section_html5(@_); - print "
\n"; -} - -# output DOC: block header in html5 -sub output_blockhead_html5(%) { - my %args = %{$_[0]}; - my ($parameter, $section); - my $count; - my $html5id; - - foreach $section (@{$args{'sectionlist'}}) { - $html5id = $section; - $html5id =~ s/[^a-zA-Z0-9\-]+/_/g; - print "
\n"; - print "

$section

\n"; - print "

\n"; - output_highlight($args{'sections'}{$section}); - print "

\n"; - } - print "
\n"; -} - -sub output_section_xml(%) { - my %args = %{$_[0]}; - my $section; - # print out each section - $lineprefix=" "; - foreach $section (@{$args{'sectionlist'}}) { - print "\n"; - print "$section\n"; - if ($section =~ m/EXAMPLE/i) { - print "\n"; - $output_preformatted = 1; - } else { - print "\n"; - } - output_highlight($args{'sections'}{$section}); - $output_preformatted = 0; - if ($section =~ m/EXAMPLE/i) { - print "\n"; - } else { - print "\n"; - } - print "\n"; - } -} - -# output function in XML DocBook -sub output_function_xml(%) { - my %args = %{$_[0]}; - my ($parameter, $section); - my $count; - my $id; - - $id = "API-" . $args{'function'}; - $id =~ s/[^A-Za-z0-9]/-/g; - - print "\n"; - print "\n"; - print " U-BOOT\n"; - print " Bootloader Hackers Manual\n"; - print " $man_date\n"; - print "\n"; - print "\n"; - print " " . $args{'function'} . "\n"; - print " 9\n"; - print " " . $kernelversion . "\n"; - print "\n"; - print "\n"; - print " " . $args{'function'} . "\n"; - print " \n"; - print " "; - output_highlight ($args{'purpose'}); - print " \n"; - print "\n"; - - print "\n"; - print " Synopsis\n"; - print " \n"; - print " " . $args{'functiontype'} . " "; - print "" . $args{'function'} . " \n"; - - $count = 0; - if ($#{$args{'parameterlist'}} >= 0) { - foreach $parameter (@{$args{'parameterlist'}}) { - $type = $args{'parametertypes'}{$parameter}; - if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { - # pointer-to-function - print " $1$parameter)\n"; - print " $2\n"; - } else { - print " " . $type; - print " $parameter\n"; - } - } - } else { - print " \n"; - } - print " \n"; - print "\n"; - - # print parameters - print "\n Arguments\n"; - if ($#{$args{'parameterlist'}} >= 0) { - print " \n"; - foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - print " \n $parameter\n"; - print " \n \n"; - $lineprefix=" "; - output_highlight($args{'parameterdescs'}{$parameter_name}); - print " \n \n \n"; - } - print " \n"; - } else { - print " \n None\n \n"; - } - print "\n"; - - output_section_xml(@_); - print "\n\n"; -} - -# output struct in XML DocBook -sub output_struct_xml(%) { - my %args = %{$_[0]}; - my ($parameter, $section); - my $id; - - $id = "API-struct-" . $args{'struct'}; - $id =~ s/[^A-Za-z0-9]/-/g; - - print "\n"; - print "\n"; - print " U-BOOT\n"; - print " Bootloader Hackers Manual\n"; - print " $man_date\n"; - print "\n"; - print "\n"; - print " " . $args{'type'} . " " . $args{'struct'} . "\n"; - print " 9\n"; - print " " . $kernelversion . "\n"; - print "\n"; - print "\n"; - print " " . $args{'type'} . " " . $args{'struct'} . "\n"; - print " \n"; - print " "; - output_highlight ($args{'purpose'}); - print " \n"; - print "\n"; - - print "\n"; - print " Synopsis\n"; - print " \n"; - print $args{'type'} . " " . $args{'struct'} . " {\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - if ($parameter =~ /^#/) { - my $prm = $parameter; - # convert data read & converted thru xml_escape() into &xyz; format: - # This allows us to have #define macros interspersed in a struct. - $prm =~ s/\\\\\\/\&/g; - print "$prm\n"; - next; - } - - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - defined($args{'parameterdescs'}{$parameter_name}) || next; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - $type = $args{'parametertypes'}{$parameter}; - if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { - # pointer-to-function - print " $1 $parameter) ($2);\n"; - } elsif ($type =~ m/^(.*?)\s*(:.*)/) { - # bitfield - print " $1 $parameter$2;\n"; - } else { - print " " . $type . " " . $parameter . ";\n"; - } - } - print "};"; - print " \n"; - print "\n"; - - print " \n"; - print " Members\n"; - - if ($#{$args{'parameterlist'}} >= 0) { - print " \n"; - foreach $parameter (@{$args{'parameterlist'}}) { - ($parameter =~ /^#/) && next; - - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - defined($args{'parameterdescs'}{$parameter_name}) || next; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - print " "; - print " $parameter\n"; - print " \n"; - output_highlight($args{'parameterdescs'}{$parameter_name}); - print " \n"; - print " \n"; - } - print " \n"; - } else { - print " \n None\n \n"; - } - print " \n"; - - output_section_xml(@_); - - print "\n\n"; -} - -# output enum in XML DocBook -sub output_enum_xml(%) { - my %args = %{$_[0]}; - my ($parameter, $section); - my $count; - my $id; - - $id = "API-enum-" . $args{'enum'}; - $id =~ s/[^A-Za-z0-9]/-/g; - - print "\n"; - print "\n"; - print " U-BOOT\n"; - print " Bootloader Hackers Manual\n"; - print " $man_date\n"; - print "\n"; - print "\n"; - print " enum " . $args{'enum'} . "\n"; - print " 9\n"; - print " " . $kernelversion . "\n"; - print "\n"; - print "\n"; - print " enum " . $args{'enum'} . "\n"; - print " \n"; - print " "; - output_highlight ($args{'purpose'}); - print " \n"; - print "\n"; - - print "\n"; - print " Synopsis\n"; - print " \n"; - print "enum " . $args{'enum'} . " {\n"; - $count = 0; - foreach $parameter (@{$args{'parameterlist'}}) { - print " $parameter"; - if ($count != $#{$args{'parameterlist'}}) { - $count++; - print ","; - } - print "\n"; - } - print "};"; - print " \n"; - print "\n"; - - print "\n"; - print " Constants\n"; - print " \n"; - foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - print " "; - print " $parameter\n"; - print " \n"; - output_highlight($args{'parameterdescs'}{$parameter_name}); - print " \n"; - print " \n"; - } - print " \n"; - print "\n"; - - output_section_xml(@_); - - print "\n\n"; -} - -# output typedef in XML DocBook -sub output_typedef_xml(%) { - my %args = %{$_[0]}; - my ($parameter, $section); - my $id; - - $id = "API-typedef-" . $args{'typedef'}; - $id =~ s/[^A-Za-z0-9]/-/g; - - print "\n"; - print "\n"; - print " U-BOOT\n"; - print " Bootloader Hackers Manual\n"; - print " $man_date\n"; - print "\n"; - print "\n"; - print " typedef " . $args{'typedef'} . "\n"; - print " 9\n"; - print "\n"; - print "\n"; - print " typedef " . $args{'typedef'} . "\n"; - print " \n"; - print " "; - output_highlight ($args{'purpose'}); - print " \n"; - print "\n"; - - print "\n"; - print " Synopsis\n"; - print " typedef " . $args{'typedef'} . ";\n"; - print "\n"; - - output_section_xml(@_); - - print "\n\n"; -} - -# output in XML DocBook -sub output_blockhead_xml(%) { - my %args = %{$_[0]}; - my ($parameter, $section); - my $count; - - my $id = $args{'module'}; - $id =~ s/[^A-Za-z0-9]/-/g; - - # print out each section - $lineprefix=" "; - foreach $section (@{$args{'sectionlist'}}) { - if (!$args{'content-only'}) { - print "\n $section\n"; - } - if ($section =~ m/EXAMPLE/i) { - print "\n"; - $output_preformatted = 1; - } else { - print "\n"; - } - output_highlight($args{'sections'}{$section}); - $output_preformatted = 0; - if ($section =~ m/EXAMPLE/i) { - print "\n"; - } else { - print ""; - } - if (!$args{'content-only'}) { - print "\n\n"; - } - } - - print "\n\n"; -} - -# output in XML DocBook -sub output_function_gnome { - my %args = %{$_[0]}; - my ($parameter, $section); - my $count; - my $id; - - $id = $args{'module'} . "-" . $args{'function'}; - $id =~ s/[^A-Za-z0-9]/-/g; - - print "\n"; - print " " . $args{'function'} . "\n"; - - print " \n"; - print " " . $args{'functiontype'} . " "; - print "" . $args{'function'} . " "; - print "\n"; - - $count = 0; - if ($#{$args{'parameterlist'}} >= 0) { - foreach $parameter (@{$args{'parameterlist'}}) { - $type = $args{'parametertypes'}{$parameter}; - if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { - # pointer-to-function - print " $1 $parameter)\n"; - print " $2\n"; - } else { - print " " . $type; - print " $parameter\n"; - } - } - } else { - print " \n"; - } - print " \n"; - if ($#{$args{'parameterlist'}} >= 0) { - print " \n"; - print "\n"; - print "\n"; - print "\n"; - print "\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - print " $parameter\n"; - print " \n"; - $lineprefix=" "; - output_highlight($args{'parameterdescs'}{$parameter_name}); - print " \n"; - } - print " \n"; - } else { - print " \n None\n \n"; - } - - # print out each section - $lineprefix=" "; - foreach $section (@{$args{'sectionlist'}}) { - print "\n $section\n"; - if ($section =~ m/EXAMPLE/i) { - print "\n"; - $output_preformatted = 1; - } else { - } - print "\n"; - output_highlight($args{'sections'}{$section}); - $output_preformatted = 0; - print "\n"; - if ($section =~ m/EXAMPLE/i) { - print "\n"; - } else { - } - print " \n"; - } - - print "\n\n"; -} - ## # output function in man sub output_function_man(%) { @@ -1328,7 +576,7 @@ sub output_function_man(%) { my ($parameter, $section); my $count; - print ".TH \"$args{'function'}\" 9 \"$args{'function'}\" \"$man_date\" \"Bootloader Hacker's Manual\" U-BOOT\n"; + print ".TH \"$args{'function'}\" 9 \"$args{'function'}\" \"$man_date\" \"Kernel Hacker's Manual\" LINUX\n"; print ".SH NAME\n"; print $args{'function'} . " \\- " . $args{'purpose'} . "\n"; @@ -1379,7 +627,7 @@ sub output_enum_man(%) { my ($parameter, $section); my $count; - print ".TH \"$args{'module'}\" 9 \"enum $args{'enum'}\" \"$man_date\" \"API Manual\" U-BOOT\n"; + print ".TH \"$args{'module'}\" 9 \"enum $args{'enum'}\" \"$man_date\" \"API Manual\" LINUX\n"; print ".SH NAME\n"; print "enum " . $args{'enum'} . " \\- " . $args{'purpose'} . "\n"; @@ -1419,37 +667,17 @@ sub output_struct_man(%) { my %args = %{$_[0]}; my ($parameter, $section); - print ".TH \"$args{'module'}\" 9 \"" . $args{'type'} . " " . $args{'struct'} . "\" \"$man_date\" \"API Manual\" U-BOOT\n"; + print ".TH \"$args{'module'}\" 9 \"" . $args{'type'} . " " . $args{'struct'} . "\" \"$man_date\" \"API Manual\" LINUX\n"; print ".SH NAME\n"; print $args{'type'} . " " . $args{'struct'} . " \\- " . $args{'purpose'} . "\n"; + my $declaration = $args{'definition'}; + $declaration =~ s/\t/ /g; + $declaration =~ s/\n/"\n.br\n.BI \"/g; print ".SH SYNOPSIS\n"; print $args{'type'} . " " . $args{'struct'} . " {\n.br\n"; - - foreach my $parameter (@{$args{'parameterlist'}}) { - if ($parameter =~ /^#/) { - print ".BI \"$parameter\"\n.br\n"; - next; - } - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - $type = $args{'parametertypes'}{$parameter}; - if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { - # pointer-to-function - print ".BI \" " . $1 . "\" " . $parameter . " \") (" . $2 . ")" . "\"\n;\n"; - } elsif ($type =~ m/^(.*?)\s*(:.*)/) { - # bitfield - print ".BI \" " . $1 . "\ \" " . $parameter . $2 . " \"" . "\"\n;\n"; - } else { - $type =~ s/([^\*])$/$1 /; - print ".BI \" " . $type . "\" " . $parameter . " \"" . "\"\n;\n"; - } - print "\n.br\n"; - } - print "};\n.br\n"; + print ".BI \"$declaration\n};\n.br\n\n"; print ".SH Members\n"; foreach $parameter (@{$args{'parameterlist'}}) { @@ -1474,7 +702,7 @@ sub output_typedef_man(%) { my %args = %{$_[0]}; my ($parameter, $section); - print ".TH \"$args{'module'}\" 9 \"$args{'typedef'}\" \"$man_date\" \"API Manual\" U-BOOT\n"; + print ".TH \"$args{'module'}\" 9 \"$args{'typedef'}\" \"$man_date\" \"API Manual\" LINUX\n"; print ".SH NAME\n"; print "typedef " . $args{'typedef'} . " \\- " . $args{'purpose'} . "\n"; @@ -1490,7 +718,7 @@ sub output_blockhead_man(%) { my ($parameter, $section); my $count; - print ".TH \"$args{'module'}\" 9 \"$args{'module'}\" \"$man_date\" \"API Manual\" U-BOOT\n"; + print ".TH \"$args{'module'}\" 9 \"$args{'module'}\" \"$man_date\" \"API Manual\" LINUX\n"; foreach $section (@{$args{'sectionlist'}}) { print ".SH \"$section\"\n"; @@ -1499,135 +727,256 @@ sub output_blockhead_man(%) { } ## -# output in text -sub output_function_text(%) { +# output in restructured text +# + +# +# 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. +# +sub output_blockhead_rst(%) { my %args = %{$_[0]}; my ($parameter, $section); - my $start; - print "Name:\n\n"; - print $args{'function'} . " - " . $args{'purpose'} . "\n"; + foreach $section (@{$args{'sectionlist'}}) { + if ($output_selection != OUTPUT_INCLUDE) { + print "**$section**\n\n"; + } + print_lineno($section_start_lines{$section}); + output_highlight_rst($args{'sections'}{$section}); + print "\n"; + } +} + +# +# Apply the RST highlights to a sub-block of text. +# +sub highlight_block($) { + # The dohighlight kludge requires the text be called $contents + my $contents = shift; + eval $dohighlight; + die $@ if $@; + return $contents; +} + +# +# Regexes used only here. +# +my $sphinx_literal = '^[^.].*::$'; +my $sphinx_cblock = '^\.\.\ +code-block::'; + +sub output_highlight_rst { + my $input = join "\n",@_; + my $output = ""; + my $line; + my $in_literal = 0; + my $litprefix; + my $block = ""; + + foreach $line (split "\n",$input) { + # + # 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 =~ /^\s*$/)) { + # + # If this is the first non-blank line in a literal + # block we need to figure out what the proper indent is. + # + if ($litprefix eq "") { + $line =~ /^(\s*)/; + $litprefix = '^' . $1; + $output .= $line . "\n"; + } elsif (! ($line =~ /$litprefix/)) { + $in_literal = 0; + } else { + $output .= $line . "\n"; + } + } else { + $output .= $line . "\n"; + } + } + # + # Not in a literal block (or just dropped out) + # + if (! $in_literal) { + $block .= $line . "\n"; + if (($line =~ /$sphinx_literal/) || ($line =~ /$sphinx_cblock/)) { + $in_literal = 1; + $litprefix = ""; + $output .= highlight_block($block); + $block = "" + } + } + } + + if ($block) { + $output .= highlight_block($block); + } + foreach $line (split "\n", $output) { + print $lineprefix . $line . "\n"; + } +} - print "\nSynopsis:\n\n"; +sub output_function_rst(%) { + my %args = %{$_[0]}; + 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 ``"; + } else { + print ".. c:function:: "; + } if ($args{'functiontype'} ne "") { - $start = $args{'functiontype'} . " " . $args{'function'} . " ("; + $start .= $args{'functiontype'} . " " . $args{'function'} . " ("; } else { - $start = $args{'function'} . " ("; + $start .= $args{'function'} . " ("; } print $start; my $count = 0; foreach my $parameter (@{$args{'parameterlist'}}) { + if ($count ne 0) { + print ", "; + } + $count++; $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function print $1 . $parameter . ") (" . $2; } else { print $type . " " . $parameter; } - if ($count != $#{$args{'parameterlist'}}) { - $count++; - print ",\n"; - print " " x length($start); - } else { - print ");\n\n"; - } + } + if ($args{'typedef'}) { + print ");``\n\n"; + } else { + print ")\n\n"; + print_lineno($declaration_start_line); + $lineprefix = " "; + output_highlight_rst($args{'purpose'}); + print "\n"; } - print "Arguments:\n\n"; + print "**Parameters**\n\n"; + $lineprefix = " "; foreach $parameter (@{$args{'parameterlist'}}) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; + $type = $args{'parametertypes'}{$parameter}; + + if ($type ne "") { + print "``$type $parameter``\n"; + } else { + print "``$parameter``\n"; + } + + print_lineno($parameterdesc_start_lines{$parameter_name}); - print $parameter . "\n\t" . $args{'parameterdescs'}{$parameter_name} . "\n"; + if (defined($args{'parameterdescs'}{$parameter_name}) && + $args{'parameterdescs'}{$parameter_name} ne $undescribed) { + output_highlight_rst($args{'parameterdescs'}{$parameter_name}); + } else { + print " *undescribed*\n"; + } + print "\n"; } - output_section_text(@_); + + $lineprefix = $oldprefix; + output_section_rst(@_); } -#output sections in text -sub output_section_text(%) { +sub output_section_rst(%) { my %args = %{$_[0]}; my $section; + my $oldprefix = $lineprefix; + $lineprefix = ""; - print "\n"; foreach $section (@{$args{'sectionlist'}}) { - print "$section:\n\n"; - output_highlight($args{'sections'}{$section}); + print "**$section**\n\n"; + print_lineno($section_start_lines{$section}); + output_highlight_rst($args{'sections'}{$section}); + print "\n"; } - print "\n\n"; + print "\n"; + $lineprefix = $oldprefix; } -# output enum in text -sub output_enum_text(%) { +sub output_enum_rst(%) { my %args = %{$_[0]}; my ($parameter); + my $oldprefix = $lineprefix; my $count; - print "Enum:\n\n"; + my $name = "enum " . $args{'enum'}; - print "enum " . $args{'enum'} . " - " . $args{'purpose'} . "\n\n"; - print "enum " . $args{'enum'} . " {\n"; - $count = 0; + print "\n\n.. c:type:: " . $name . "\n\n"; + print_lineno($declaration_start_line); + $lineprefix = " "; + output_highlight_rst($args{'purpose'}); + print "\n"; + + print "**Constants**\n\n"; + $lineprefix = " "; foreach $parameter (@{$args{'parameterlist'}}) { - print "\t$parameter"; - if ($count != $#{$args{'parameterlist'}}) { - $count++; - print ","; + print "``$parameter``\n"; + if ($args{'parameterdescs'}{$parameter} ne $undescribed) { + output_highlight_rst($args{'parameterdescs'}{$parameter}); + } else { + print " *undescribed*\n"; } print "\n"; } - print "};\n\n"; - - print "Constants:\n\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - print "$parameter\n\t"; - print $args{'parameterdescs'}{$parameter} . "\n"; - } - output_section_text(@_); + $lineprefix = $oldprefix; + output_section_rst(@_); } -# output typedef in text -sub output_typedef_text(%) { +sub output_typedef_rst(%) { my %args = %{$_[0]}; my ($parameter); - my $count; - print "Typedef:\n\n"; + my $oldprefix = $lineprefix; + my $name = "typedef " . $args{'typedef'}; + + print "\n\n.. c:type:: " . $name . "\n\n"; + print_lineno($declaration_start_line); + $lineprefix = " "; + output_highlight_rst($args{'purpose'}); + print "\n"; - print "typedef " . $args{'typedef'} . " - " . $args{'purpose'} . "\n"; - output_section_text(@_); + $lineprefix = $oldprefix; + output_section_rst(@_); } -# output struct as text -sub output_struct_text(%) { +sub output_struct_rst(%) { my %args = %{$_[0]}; my ($parameter); + my $oldprefix = $lineprefix; + my $name = $args{'type'} . " " . $args{'struct'}; - print $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "\n\n"; - print $args{'type'} . " " . $args{'struct'} . " {\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - if ($parameter =~ /^#/) { - print "$parameter\n"; - next; - } - - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; + print "\n\n.. c:type:: " . $name . "\n\n"; + print_lineno($declaration_start_line); + $lineprefix = " "; + output_highlight_rst($args{'purpose'}); + print "\n"; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - $type = $args{'parametertypes'}{$parameter}; - if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { - # pointer-to-function - print "\t$1 $parameter) ($2);\n"; - } elsif ($type =~ m/^(.*?)\s*(:.*)/) { - # bitfield - print "\t$1 $parameter$2;\n"; - } else { - print "\t" . $type . " " . $parameter . ";\n"; - } - } - print "};\n\n"; + print "**Definition**\n\n"; + print "::\n\n"; + my $declaration = $args{'definition'}; + $declaration =~ s/\t/ /g; + print " " . $args{'type'} . " " . $args{'struct'} . " {\n$declaration };\n\n"; - print "Members:\n\n"; + print "**Members**\n\n"; + $lineprefix = " "; foreach $parameter (@{$args{'parameterlist'}}) { ($parameter =~ /^#/) && next; @@ -1635,58 +984,33 @@ sub output_struct_text(%) { $parameter_name =~ s/\[.*//; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - print "$parameter\n\t"; - print $args{'parameterdescs'}{$parameter_name} . "\n"; + $type = $args{'parametertypes'}{$parameter}; + print_lineno($parameterdesc_start_lines{$parameter_name}); + print "``" . $parameter . "``\n"; + output_highlight_rst($args{'parameterdescs'}{$parameter_name}); + print "\n"; } print "\n"; - output_section_text(@_); -} -sub output_blockhead_text(%) { - my %args = %{$_[0]}; - my ($parameter, $section); - - foreach $section (@{$args{'sectionlist'}}) { - print " $section:\n"; - print " -> "; - output_highlight($args{'sections'}{$section}); - } + $lineprefix = $oldprefix; + output_section_rst(@_); } -## list mode output functions - -sub output_function_list(%) { - my %args = %{$_[0]}; +## none mode output functions - print $args{'function'} . "\n"; +sub output_function_none(%) { } -# output enum in list -sub output_enum_list(%) { - my %args = %{$_[0]}; - print $args{'enum'} . "\n"; +sub output_enum_none(%) { } -# output typedef in list -sub output_typedef_list(%) { - my %args = %{$_[0]}; - print $args{'typedef'} . "\n"; +sub output_typedef_none(%) { } -# output struct as list -sub output_struct_list(%) { - my %args = %{$_[0]}; - - print $args{'struct'} . "\n"; +sub output_struct_none(%) { } -sub output_blockhead_list(%) { - my %args = %{$_[0]}; - my ($parameter, $section); - - foreach $section (@{$args{'sectionlist'}}) { - print "DOC: $section\n"; - } +sub output_blockhead_none(%) { } ## @@ -1698,9 +1022,13 @@ sub output_declaration { my $name = shift; my $functype = shift; my $func = "output_${functype}_$output_mode"; - if (($function_only==0) || - ( $function_only == 1 && defined($function_table{$name})) || - ( $function_only == 2 && !defined($function_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) && + !($functype eq "function" && defined($function_table{$name})))) { &$func(@_); $section_counter++; @@ -1733,35 +1061,128 @@ sub dump_union($$) { sub dump_struct($$) { my $x = shift; my $file = shift; - my $nested; if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) { - #my $decl_type = $1; + my $decl_type = $1; $declaration_name = $2; my $members = $3; - # ignore embedded structs or unions - $members =~ s/({.*})//g; - $nested = $1; - # ignore members marked private: - $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gos; - $members =~ s/\/\*\s*private:.*//gos; + $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gosi; + $members =~ s/\/\*\s*private:.*//gosi; # strip comments: $members =~ s/\/\*.*?\*\///gos; - $nested =~ s/\/\*.*?\*\///gos; - # strip kmemcheck_bitfield_{begin,end}.*; - $members =~ s/kmemcheck_bitfield_.*?;//gos; # strip attributes - $members =~ s/__aligned\s*\(.+\)//gos; - - create_parameterlist($members, ';', $file); - check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested); - + $members =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i; + $members =~ s/__aligned\s*\([^;]*\)//gos; + $members =~ s/\s*CRYPTO_MINALIGN_ATTR//gos; + # replace DECLARE_BITMAP + $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; + # replace DECLARE_KFIFO + $members =~ s/DECLARE_KFIFO\s*\(([^,)]+),\s*([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos; + # replace DECLARE_KFIFO_PTR + $members =~ s/DECLARE_KFIFO_PTR\s*\(([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos; + + my $declaration = $members; + + # Split nested struct/union elements as newer ones + while ($members =~ m/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/) { + my $newmember; + my $maintype = $1; + my $ids = $4; + my $content = $3; + foreach my $id(split /,/, $ids) { + $newmember .= "$maintype $id; "; + + $id =~ s/[:\[].*//; + $id =~ s/^\s*\**(\S+)\s*/$1/; + foreach my $arg (split /;/, $content) { + next if ($arg =~ m/^\s*$/); + if ($arg =~ m/^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)/) { + # pointer-to-function + my $type = $1; + my $name = $2; + my $extra = $3; + next if (!$name); + if ($id =~ m/^\s*$/) { + # anonymous struct/union + $newmember .= "$type$name$extra; "; + } else { + $newmember .= "$type$id.$name$extra; "; + } + } else { + my $type; + my $names; + $arg =~ s/^\s+//; + $arg =~ s/\s+$//; + # Handle bitmaps + $arg =~ s/:\s*\d+\s*//g; + # Handle arrays + $arg =~ s/\[.*\]//g; + # The type may have multiple words, + # and multiple IDs can be defined, like: + # const struct foo, *bar, foobar + # So, we remove spaces when parsing the + # names, in order to match just names + # and commas for the names + $arg =~ s/\s*,\s*/,/g; + if ($arg =~ m/(.*)\s+([\S+,]+)/) { + $type = $1; + $names = $2; + } else { + $newmember .= "$arg; "; + next; + } + foreach my $name (split /,/, $names) { + $name =~ s/^\s*\**(\S+)\s*/$1/; + next if (($name =~ m/^\s*$/)); + if ($id =~ m/^\s*$/) { + # anonymous struct/union + $newmember .= "$type $name; "; + } else { + $newmember .= "$type $id.$name; "; + } + } + } + } + } + $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)}([^\{\}\;]*)\;/$newmember/; + } + + # Ignore other nested elements, like enums + $members =~ s/({[^\{\}]*})//g; + + create_parameterlist($members, ';', $file, $declaration_name); + check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual); + + # Adjust declaration for better display + $declaration =~ s/([{;])/$1\n/g; + $declaration =~ s/}\s+;/};/g; + # Better handle inlined enums + do {} while ($declaration =~ s/(enum\s+{[^}]+),([^\n])/$1,\n$2/); + + my @def_args = split /\n/, $declaration; + my $level = 1; + $declaration = ""; + foreach my $clause (@def_args) { + $clause =~ s/^\s+//; + $clause =~ s/\s+$//; + $clause =~ s/\s+/ /; + next if (!$clause); + $level-- if ($clause =~ m/(})/ && $level > 1); + if (!($clause =~ m/^\s*#/)) { + $declaration .= "\t" x $level; + } + $declaration .= "\t" . $clause . "\n"; + $level++ if ($clause =~ m/({)/ && !($clause =~m/}/)); + } output_declaration($declaration_name, 'struct', {'struct' => $declaration_name, 'module' => $modulename, + 'definition' => $declaration, 'parameterlist' => \@parameterlist, 'parameterdescs' => \%parameterdescs, 'parametertypes' => \%parametertypes, @@ -1772,33 +1193,84 @@ sub dump_struct($$) { }); } else { - print STDERR "Error(${file}:$.): Cannot parse struct or union!\n"; + print STDERR "${file}:$.: error: Cannot parse struct or union!\n"; ++$errors; } } + +sub show_warnings($$) { + my $functype = shift; + my $name = shift; + + return 1 if ($output_selection == OUTPUT_ALL); + + if ($output_selection == OUTPUT_EXPORTED) { + if (defined($function_table{$name})) { + return 1; + } else { + return 0; + } + } + if ($output_selection == OUTPUT_INTERNAL) { + if (!($functype eq "function" && defined($function_table{$name}))) { + return 1; + } else { + return 0; + } + } + if ($output_selection == OUTPUT_INCLUDE) { + if (defined($function_table{$name})) { + return 1; + } else { + 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; $x =~ s@/\*.*?\*/@@gos; # strip comments. - $x =~ s/^#\s*define\s+.*$//; # strip #define macros inside enums + # strip #define macros inside enums + $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos; if ($x =~ /enum\s+(\w+)\s*{(.*)}/) { $declaration_name = $1; my $members = $2; + my %_members; + + $members =~ s/\s+$//; foreach my $arg (split ',', $members) { $arg =~ s/^\s*(\w+).*/$1/; push @parameterlist, $arg; if (!$parameterdescs{$arg}) { $parameterdescs{$arg} = $undescribed; - print STDERR "Warning(${file}:$.): Enum value '$arg' ". - "not described in enum '$declaration_name'\n"; + if (show_warnings("enum", $declaration_name)) { + print STDERR "${file}:$.: warning: Enum value '$arg' not described in enum '$declaration_name'\n"; + } } - + $_members{$arg} = 1; } + while (my ($k, $v) = each %parameterdescs) { + if (!exists($_members{$k})) { + if (show_warnings("enum", $declaration_name)) { + print STDERR "${file}:$.: warning: Excess enum value '$k' description in '$declaration_name'\n"; + } + } + } + output_declaration($declaration_name, 'enum', {'enum' => $declaration_name, @@ -1811,7 +1283,7 @@ sub dump_enum($$) { }); } else { - print STDERR "Error(${file}:$.): Cannot parse enum!\n"; + print STDERR "${file}:$.: error: Cannot parse enum!\n"; ++$errors; } } @@ -1821,6 +1293,34 @@ sub dump_typedef($$) { 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 + $return_type = $1; + $declaration_name = $2; + my $args = $3; + + create_parameterlist($args, ',', $file, $declaration_name); + + 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 + }); + return; + } + while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) { $x =~ s/\(*.\)\s*;$/;/; $x =~ s/\[*.\]\s*;$/;/; @@ -1839,7 +1339,7 @@ sub dump_typedef($$) { }); } else { - print STDERR "Error(${file}:$.): Cannot parse typedef!\n"; + print STDERR "${file}:$.: error: Cannot parse typedef!\n"; ++$errors; } } @@ -1852,10 +1352,11 @@ sub save_struct_actual($) { $struct_actual = $struct_actual . $actual . " "; } -sub create_parameterlist($$$) { +sub create_parameterlist($$$$) { my $args = shift; my $splitter = shift; my $file = shift; + my $declaration_name = shift; my $type; my $param; @@ -1880,12 +1381,12 @@ sub create_parameterlist($$$) { } elsif ($arg =~ m/\(.+\)\s*\(/) { # pointer-to-function $arg =~ tr/#/,/; - $arg =~ m/[^\(]+\(\*?\s*(\w*)\s*\)/; + $arg =~ m/[^\(]+\(\*?\s*([\w\.]*)\s*\)/; $param = $1; $type = $arg; $type =~ s/([^\(]+\(\*?)\s*$param/$1/; save_struct_actual($param); - push_parameter($param, $type, $file); + push_parameter($param, $type, $file, $declaration_name); } elsif ($arg) { $arg =~ s/\s*:\s*/:/g; $arg =~ s/\s*\[/\[/g; @@ -1910,27 +1411,28 @@ sub create_parameterlist($$$) { foreach $param (@args) { if ($param =~ m/^(\*+)\s*(.*)/) { save_struct_actual($2); - push_parameter($2, "$type $1", $file); + push_parameter($2, "$type $1", $file, $declaration_name); } elsif ($param =~ m/(.*?):(\d+)/) { if ($type ne "") { # skip unnamed bit-fields save_struct_actual($1); - push_parameter($1, "$type:$2", $file) + push_parameter($1, "$type:$2", $file, $declaration_name) } } else { save_struct_actual($param); - push_parameter($param, $type, $file); + push_parameter($param, $type, $file, $declaration_name); } } } } } -sub push_parameter($$$) { +sub push_parameter($$$$) { my $param = shift; my $type = shift; my $file = shift; + my $declaration_name = shift; if (($anon_struct_union == 1) && ($type eq "") && ($param eq "}")) { @@ -1938,11 +1440,14 @@ sub push_parameter($$$) { } $anon_struct_union = 0; - my $param_name = $param; - $param_name =~ s/\[.*//; + $param =~ s/[\[\)].*//; if ($type eq "" && $param =~ /\.\.\.$/) { + if (!$param =~ /\w\.\.\.$/) { + # handles unnamed variable parameters + $param = "..."; + } if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") { $parameterdescs{$param} = "variable arguments"; } @@ -1964,25 +1469,17 @@ sub push_parameter($$$) { # warn if parameter has no description # (but ignore ones starting with # as these are not parameters # but inline preprocessor statements); - # also ignore unnamed structs/unions; - if (!$anon_struct_union) { - if (!defined $parameterdescs{$param_name} && $param_name !~ /^#/) { - - $parameterdescs{$param_name} = $undescribed; + # Note: It will also ignore void params and unnamed structs/unions + if (!defined $parameterdescs{$param} && $param !~ /^#/) { + $parameterdescs{$param} = $undescribed; - if (($type eq 'function') || ($type eq 'enum')) { - print STDERR "Warning(${file}:$.): Function parameter ". - "or member '$param' not " . - "described in '$declaration_name'\n"; - } - print STDERR "Warning(${file}:$.):" . - " No description found for parameter '$param'\n"; - ++$warnings; - } + if (show_warnings($type, $declaration_name)) { + print STDERR + "${file}:$.: warning: Function parameter or member '$param' not described in '$declaration_name'\n"; + ++$warnings; + } } - $param = xml_escape($param); - # strip spaces from $param so that it is one continuous string # on @parameterlist; # this fixes a problem where check_sections() cannot find @@ -1993,11 +1490,12 @@ sub push_parameter($$$) { # "[blah" in a parameter string; ###$param =~ s/\s*//g; push @parameterlist, $param; + $type =~ s/\s\s+/ /g; $parametertypes{$param} = $type; } -sub check_sections($$$$$$) { - my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck, $nested) = @_; +sub check_sections($$$$$) { + my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck) = @_; my @sects = split ' ', $sectcheck; my @prms = split ' ', $prmscheck; my $err; @@ -2026,19 +1524,11 @@ sub check_sections($$$$$$) { } if ($err) { if ($decl_type eq "function") { - print STDERR "Warning(${file}:$.): " . + print STDERR "${file}:$.: warning: " . "Excess function parameter " . "'$sects[$sx]' " . "description in '$decl_name'\n"; ++$warnings; - } else { - if ($nested !~ m/\Q$sects[$sx]\E/) { - print STDERR "Warning(${file}:$.): " . - "Excess struct/union/enum/typedef member " . - "'$sects[$sx]' " . - "description in '$decl_name'\n"; - ++$warnings; - } } } } @@ -2059,7 +1549,7 @@ sub check_return_section { if (!defined($sections{$section_return}) || $sections{$section_return} eq "") { - print STDERR "Warning(${file}:$.): " . + print STDERR "${file}:$.: warning: " . "No description found for return value of " . "'$declaration_name'\n"; ++$warnings; @@ -2088,8 +1578,15 @@ sub dump_function($$) { $prototype =~ s/__meminit +//; $prototype =~ s/__must_check +//; $prototype =~ s/__weak +//; + $prototype =~ s/__sched +//; my $define = $prototype =~ s/^#\s*define\s+//; #ak added - $prototype =~ s/__attribute__\s*\(\([a-z,]*\)\)//; + $prototype =~ s/__attribute__\s*\(\( + (?: + [\w\s]++ # attribute name + (?:\([^)]*+\))? # attribute arguments + \s*+,? # optional comma at the end + )+ + \)\)\s+//x; # Yes, this truly is vile. We are looking for: # 1. Return type (may be nothing if we're looking at a macro) @@ -2117,33 +1614,33 @@ sub dump_function($$) { $noret = 1; } elsif ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || - $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || + $prototype =~ m/^(\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || - $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || - $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || - $prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || - $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || - $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || - $prototype =~ m/^(\w+\s+\w+\s*\*\s*\w+\s*\*\s*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/) { + $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s*\*+\s*\w+\s*\*+\s*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/) { $return_type = $1; $declaration_name = $2; my $args = $3; - create_parameterlist($args, ',', $file); + create_parameterlist($args, ',', $file, $declaration_name); } else { - print STDERR "Warning(${file}:$.): cannot understand function prototype: '$prototype'\n"; + print STDERR "${file}:$.: warning: cannot understand function prototype: '$prototype'\n"; return; } my $prms = join " ", @parameterlist; - check_sections($file, $declaration_name, "function", $sectcheck, $prms, ""); + 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 @@ -2170,7 +1667,6 @@ sub dump_function($$) { sub reset_state { $function = ""; - %constants = (); %parameterdescs = (); %parametertypes = (); @parameterlist = (); @@ -2180,7 +1676,8 @@ sub reset_state { $struct_actual = ""; $prototype = ""; - $state = 0; + $state = STATE_NORMAL; + $inline_doc_state = STATE_INLINE_NA; } sub tracepoint_munge($) { @@ -2202,7 +1699,7 @@ sub tracepoint_munge($) { $tracepointargs = $1; } if (($tracepointname eq 0) || ($tracepointargs eq 0)) { - print STDERR "Warning(${file}:$.): Unrecognized tracepoint format: \n". + print STDERR "${file}:$.: warning: Unrecognized tracepoint format: \n". "$prototype\n"; } else { $prototype = "static inline void trace_$tracepointname($tracepointargs)"; @@ -2212,7 +1709,7 @@ sub tracepoint_munge($) { sub syscall_munge() { my $void = 0; - $prototype =~ s@[\r\n\t]+@ @gos; # strip newlines/CR's/tabs + $prototype =~ s@[\r\n]+@ @gos; # strip newlines/CR's ## if ($prototype =~ m/SYSCALL_DEFINE0\s*\(\s*(a-zA-Z0-9_)*\s*\)/) { if ($prototype =~ m/SYSCALL_DEFINE0/) { $void = 1; @@ -2243,7 +1740,7 @@ sub syscall_munge() { } } -sub process_state3_function($$) { +sub process_proto_function($$) { my $x = shift; my $file = shift; @@ -2273,7 +1770,7 @@ sub process_state3_function($$) { } } -sub process_state3_type($$) { +sub process_proto_type($$) { my $x = shift; my $file = shift; @@ -2289,6 +1786,9 @@ sub process_state3_type($$) { while (1) { if ( $x =~ /([^{};]*)([{};])(.*)/ ) { + if( length $prototype ) { + $prototype .= " " + } $prototype .= $1 . $2; ($2 eq '{') && $brcount++; ($2 eq '}') && $brcount--; @@ -2305,279 +1805,369 @@ sub process_state3_type($$) { } } -# xml_escape: replace <, >, and & in the text stream; -# -# however, formatting controls that are generated internally/locally in the -# kernel-doc script are not escaped here; instead, they begin life like -# $blankline_html (4 of '\' followed by a mnemonic + ':'), then these strings -# are converted to their mnemonic-expected output, without the 4 * '\' & ':', -# just before actual output; (this is done by local_unescape()) -sub xml_escape($) { - my $text = shift; - if (($output_mode eq "text") || ($output_mode eq "man")) { - return $text; - } - $text =~ s/\&/\\\\\\amp;/g; - $text =~ s/\/\\\\\\gt;/g; - return $text; -} - -# convert local escape strings to html -# local escape strings look like: '\\\\menmonic:' (that's 4 backslashes) -sub local_unescape($) { - my $text = shift; - if (($output_mode eq "text") || ($output_mode eq "man")) { - return $text; - } - $text =~ s/\\\\\\\\lt://g; - return $text; -} -sub process_file($) { +sub map_filename($) { my $file; - my $identifier; - my $func; - my $descr; - my $in_purpose = 0; - my $initial_section_counter = $section_counter; + my ($orig_file) = @_; if (defined($ENV{'SRCTREE'})) { - $file = "$ENV{'SRCTREE'}" . "/" . "@_"; - } - else { - $file = "@_"; + $file = "$ENV{'SRCTREE'}" . "/" . $orig_file; + } else { + $file = $orig_file; } + if (defined($source_map{$file})) { $file = $source_map{$file}; } + return $file; +} + +sub process_export_file($) { + my ($orig_file) = @_; + my $file = map_filename($orig_file); + if (!open(IN,"<$file")) { print STDERR "Error: Cannot open file $file\n"; ++$errors; return; } - $. = 1; - - $section_counter = 0; while () { - while (s/\\\s*$//) { - $_ .= ; + if (/$export_symbol/) { + $function_table{$2} = 1; } - if ($state == 0) { - if (/$doc_start/o) { - $state = 1; # next line is always the function name - $in_doc_sect = 0; - } - } elsif ($state == 1) { # this line is the function name (always) - if (/$doc_block/o) { - $state = 4; - $contents = ""; - if ( $1 eq "" ) { - $section = $section_intro; - } else { - $section = $1; - } - } - elsif (/$doc_decl/o) { - $identifier = $1; - if (/\s*([\w\s]+?)\s*-/) { - $identifier = $1; - } + } - $state = 2; - if (/-(.*)/) { - # strip leading/trailing/multiple spaces - $descr= $1; - $descr =~ s/^\s*//; - $descr =~ s/\s*$//; - $descr =~ s/\s+/ /g; - $declaration_purpose = xml_escape($descr); - $in_purpose = 1; - } else { - $declaration_purpose = ""; - } + close(IN); +} - if (($declaration_purpose eq "") && $verbose) { - print STDERR "Warning(${file}:$.): missing initial short description on line:\n"; - print STDERR $_; - ++$warnings; - } +# +# Parsers for the various processing states. +# +# STATE_NORMAL: looking for the /** to begin everything. +# +sub process_normal() { + if (/$doc_start/o) { + $state = STATE_NAME; # next line is always the function name + $in_doc_sect = 0; + $declaration_start_line = $. + 1; + } +} - if ($identifier =~ m/^struct/) { - $decl_type = 'struct'; - } elsif ($identifier =~ m/^union/) { - $decl_type = 'union'; - } elsif ($identifier =~ m/^enum/) { - $decl_type = 'enum'; - } elsif ($identifier =~ m/^typedef/) { - $decl_type = 'typedef'; - } else { - $decl_type = 'function'; - } +# +# STATE_NAME: Looking for the "name - description" line +# +sub process_name($$) { + my $file = shift; + my $identifier; + my $descr; - if ($verbose) { - print STDERR "Info(${file}:$.): Scanning doc for $identifier\n"; - } - } else { - print STDERR "Warning(${file}:$.): Cannot understand $_ on line $.", - " - I thought it was a doc line\n"; + if (/$doc_block/o) { + $state = STATE_DOCBLOCK; + $contents = ""; + $new_start_line = $. + 1; + + if ( $1 eq "" ) { + $section = $section_intro; + } else { + $section = $1; + } + } + elsif (/$doc_decl/o) { + $identifier = $1; + if (/\s*([\w\s]+?)(\(\))?\s*-/) { + $identifier = $1; + } + + $state = STATE_BODY; + # if there's no @param blocks need to set up default section + # here + $contents = ""; + $section = $section_default; + $new_start_line = $. + 1; + if (/-(.*)/) { + # strip leading/trailing/multiple spaces + $descr= $1; + $descr =~ s/^\s*//; + $descr =~ s/\s*$//; + $descr =~ s/\s+/ /g; + $declaration_purpose = $descr; + $state = STATE_BODY_MAYBE; + } else { + $declaration_purpose = ""; + } + + if (($declaration_purpose eq "") && $verbose) { + print STDERR "${file}:$.: warning: missing initial short description on line:\n"; + print STDERR $_; + ++$warnings; + } + + if ($identifier =~ m/^struct/) { + $decl_type = 'struct'; + } elsif ($identifier =~ m/^union/) { + $decl_type = 'union'; + } elsif ($identifier =~ m/^enum/) { + $decl_type = 'enum'; + } elsif ($identifier =~ m/^typedef/) { + $decl_type = 'typedef'; + } else { + $decl_type = 'function'; + } + + if ($verbose) { + print STDERR "${file}:$.: info: Scanning doc for $identifier\n"; + } + } else { + print STDERR "${file}:$.: warning: Cannot understand $_ on line $.", + " - I thought it was a doc line\n"; + ++$warnings; + $state = STATE_NORMAL; + } +} + + +# +# STATE_BODY and STATE_BODY_MAYBE: the bulk of a kerneldoc comment. +# +sub process_body($$) { + my $file = shift; + + if (/$doc_sect/i) { # case insensitive for supported section names + $newsection = $1; + $newcontents = $2; + + # map the supported section names to the canonical names + if ($newsection =~ m/^description$/i) { + $newsection = $section_default; + } elsif ($newsection =~ m/^context$/i) { + $newsection = $section_context; + } elsif ($newsection =~ m/^returns?$/i) { + $newsection = $section_return; + } elsif ($newsection =~ m/^\@return$/) { + # special: @return is a section, not a param description + $newsection = $section_return; + } + + if (($contents ne "") && ($contents ne "\n")) { + if (!$in_doc_sect && $verbose) { + print STDERR "${file}:$.: warning: contents before sections\n"; ++$warnings; - $state = 0; } - } elsif ($state == 2) { # look for head: lines, and include content - if (/$doc_sect/o) { - $newsection = $1; - $newcontents = $2; - - if (($contents ne "") && ($contents ne "\n")) { - if (!$in_doc_sect && $verbose) { - print STDERR "Warning(${file}:$.): contents before sections\n"; - ++$warnings; - } - dump_section($file, $section, xml_escape($contents)); - $section = $section_default; - } + dump_section($file, $section, $contents); + $section = $section_default; + } + + $in_doc_sect = 1; + $state = STATE_BODY; + $contents = $newcontents; + $new_start_line = $.; + while (substr($contents, 0, 1) eq " ") { + $contents = substr($contents, 1); + } + if ($contents ne "") { + $contents .= "\n"; + } + $section = $newsection; + $leading_space = undef; + } elsif (/$doc_end/) { + if (($contents ne "") && ($contents ne "\n")) { + dump_section($file, $section, $contents); + $section = $section_default; + $contents = ""; + } + # look for doc_com + + doc_end: + if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { + print STDERR "${file}:$.: warning: suspicious ending line: $_"; + ++$warnings; + } - $in_doc_sect = 1; - $in_purpose = 0; - $contents = $newcontents; - if ($contents ne "") { - while ((substr($contents, 0, 1) eq " ") || - substr($contents, 0, 1) eq "\t") { - $contents = substr($contents, 1); + $prototype = ""; + $state = STATE_PROTO; + $brcount = 0; + } 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) { + dump_section($file, $section, $contents); + $section = $section_default; + $contents = ""; + $new_start_line = $.; + } else { + $contents .= "\n"; + } + $state = STATE_BODY; + } elsif ($state == STATE_BODY_MAYBE) { + # Continued declaration purpose + chomp($declaration_purpose); + $declaration_purpose .= " " . $1; + $declaration_purpose =~ s/\s+/ /g; + } else { + my $cont = $1; + if ($section =~ m/^@/ || $section eq $section_context) { + if (!defined $leading_space) { + if ($cont =~ m/^(\s+)/) { + $leading_space = $1; + } else { + $leading_space = ""; } - $contents .= "\n"; } - $section = $newsection; - } elsif (/$doc_end/) { + $cont =~ s/^$leading_space//; + } + $contents .= $cont . "\n"; + } + } else { + # i dont know - bad line? ignore. + print STDERR "${file}:$.: warning: bad line: $_"; + ++$warnings; + } +} - if (($contents ne "") && ($contents ne "\n")) { - dump_section($file, $section, xml_escape($contents)); - $section = $section_default; - $contents = ""; - } - # look for doc_com + + doc_end: - if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { - print STDERR "Warning(${file}:$.): suspicious ending line: $_"; - ++$warnings; - } - $prototype = ""; - $state = 3; - $brcount = 0; -# print STDERR "end of doc comment, looking for prototype\n"; - } 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) { - dump_section($file, $section, xml_escape($contents)); - $section = $section_default; - $contents = ""; - } else { - $contents .= "\n"; - } - $in_purpose = 0; - } elsif ($in_purpose == 1) { - # Continued declaration purpose - chomp($declaration_purpose); - $declaration_purpose .= " " . xml_escape($1); - $declaration_purpose =~ s/\s+/ /g; - } else { - $contents .= $1 . "\n"; - } - } else { - # i dont know - bad line? ignore. - print STDERR "Warning(${file}:$.): bad line: $_"; - ++$warnings; +# +# STATE_PROTO: reading a function/whatever prototype. +# +sub process_proto($$) { + my $file = shift; + + if (/$doc_inline_oneline/) { + $section = $1; + $contents = $2; + if ($contents ne "") { + $contents .= "\n"; + dump_section($file, $section, $contents); + $section = $section_default; + $contents = ""; + } + } elsif (/$doc_inline_start/) { + $state = STATE_INLINE; + $inline_doc_state = STATE_INLINE_NAME; + } elsif ($decl_type eq 'function') { + process_proto_function($_, $file); + } else { + process_proto_type($_, $file); + } +} + +# +# STATE_DOCBLOCK: within a DOC: block. +# +sub process_docblock($$) { + my $file = shift; + + if (/$doc_end/) { + dump_doc_section($file, $section, $contents); + $section = $section_default; + $contents = ""; + $function = ""; + %parameterdescs = (); + %parametertypes = (); + @parameterlist = (); + %sections = (); + @sectionlist = (); + $prototype = ""; + $state = STATE_NORMAL; + } elsif (/$doc_content/) { + if ( $1 eq "" ) { + $contents .= $blankline; + } else { + $contents .= $1 . "\n"; + } + } +} + +# +# STATE_INLINE: docbook comments within a prototype. +# +sub process_inline($$) { + my $file = shift; + + # First line (state 1) needs to be a @parameter + if ($inline_doc_state == STATE_INLINE_NAME && /$doc_inline_sect/o) { + $section = $1; + $contents = $2; + $new_start_line = $.; + if ($contents ne "") { + while (substr($contents, 0, 1) eq " ") { + $contents = substr($contents, 1); } - } elsif ($state == 3) { # scanning for function '{' (end of prototype) - if ($decl_type eq 'function') { - process_state3_function($_, $file); - } else { - process_state3_type($_, $file); + $contents .= "\n"; + } + $inline_doc_state = STATE_INLINE_TEXT; + # Documentation block end */ + } elsif (/$doc_inline_end/) { + if (($contents ne "") && ($contents ne "\n")) { + dump_section($file, $section, $contents); + $section = $section_default; + $contents = ""; + } + $state = STATE_PROTO; + $inline_doc_state = STATE_INLINE_NA; + # Regular text + } elsif (/$doc_content/) { + if ($inline_doc_state == STATE_INLINE_TEXT) { + $contents .= $1 . "\n"; + # nuke leading blank lines + if ($contents =~ /^\s*$/) { + $contents = ""; } - } elsif ($state == 4) { - # Documentation block - if (/$doc_block/) { - dump_doc_section($file, $section, xml_escape($contents)); - $contents = ""; - $function = ""; - %constants = (); - %parameterdescs = (); - %parametertypes = (); - @parameterlist = (); - %sections = (); - @sectionlist = (); - $prototype = ""; - if ( $1 eq "" ) { - $section = $section_intro; - } else { - $section = $1; - } - } - elsif (/$doc_end/) - { - dump_doc_section($file, $section, xml_escape($contents)); - $contents = ""; - $function = ""; - %constants = (); - %parameterdescs = (); - %parametertypes = (); - @parameterlist = (); - %sections = (); - @sectionlist = (); - $prototype = ""; - $state = 0; - } - elsif (/$doc_content/) - { - if ( $1 eq "" ) - { - $contents .= $blankline; - } - else - { - $contents .= $1 . "\n"; - } - } + } elsif ($inline_doc_state == STATE_INLINE_NAME) { + $inline_doc_state = STATE_INLINE_ERROR; + print STDERR "${file}:$.: warning: "; + print STDERR "Incorrect use of kernel-doc format: $_"; + ++$warnings; } } +} + + +sub process_file($) { + my $file; + my $initial_section_counter = $section_counter; + my ($orig_file) = @_; + + $file = map_filename($orig_file); + + if (!open(IN,"<$file")) { + print STDERR "Error: Cannot open file $file\n"; + ++$errors; + return; + } + + $. = 1; + + $section_counter = 0; + while () { + while (s/\\\s*$//) { + $_ .= ; + } + # Replace tabs by spaces + while ($_ =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}; + # Hand this line to the appropriate state handler + if ($state == STATE_NORMAL) { + process_normal(); + } elsif ($state == STATE_NAME) { + process_name($file, $_); + } elsif ($state == STATE_BODY || $state == STATE_BODY_MAYBE) { + process_body($file, $_); + } elsif ($state == STATE_INLINE) { # scanning for inline parameters + process_inline($file, $_); + } elsif ($state == STATE_PROTO) { + process_proto($file, $_); + } elsif ($state == STATE_DOCBLOCK) { + process_docblock($file, $_); + } + } + + # Make sure we got something interesting. if ($initial_section_counter == $section_counter) { - print STDERR "Warning(${file}): no structured comments found\n"; - if (($function_only == 1) && ($show_not_found == 1)) { - print STDERR " Was looking for '$_'.\n" for keys %function_table; + if ($output_mode ne "none") { + print STDERR "${file}:1: warning: no structured comments found\n"; } - if ($output_mode eq "xml") { - # The template wants at least one RefEntry here; make one. - print "\n"; - print " \n"; - print " \n"; - print " ${file}\n"; - print " \n"; - print " \n"; - print " Document generation inconsistency\n"; - print " \n"; - print " \n"; - print " \n"; - print " \n"; - print " Oops\n"; - print " \n"; - print " \n"; - print " \n"; - print " The template for this document tried to insert\n"; - print " the structured comment from the file\n"; - print " ${file} at this point,\n"; - print " but none was found.\n"; - print " This dummy section is inserted to allow\n"; - print " generation to continue.\n"; - print " \n"; - print " \n"; - print " \n"; - print "\n"; + if (($output_selection == OUTPUT_INCLUDE) && ($show_not_found == 1)) { + print STDERR " Was looking for '$_'.\n" for keys %function_table; } } } @@ -2587,9 +2177,11 @@ $kernelversion = get_kernel_version(); # generate a sequence of code that will splice in highlighting information # using the s// operator. -foreach my $pattern (keys %highlights) { -# print STDERR "scanning pattern:$pattern, highlight:($highlights{$pattern})\n"; - $dohighlight .= "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n"; +for (my $k = 0; $k < @highlights; $k++) { + my $pattern = $highlights[$k][0]; + my $result = $highlights[$k][1]; +# print STDERR "scanning pattern:$pattern, highlight:($result)\n"; + $dohighlight .= "\$contents =~ s:$pattern:$result:gs;\n"; } # Read the file that maps relative names to absolute names for @@ -2605,6 +2197,17 @@ if (open(SOURCE_MAP, "<.tmp_filelist.txt")) { close(SOURCE_MAP); } +if ($output_selection == OUTPUT_EXPORTED || + $output_selection == OUTPUT_INTERNAL) { + + push(@export_file_list, @ARGV); + + foreach (@export_file_list) { + chomp; + process_export_file($_); + } +} + foreach (@ARGV) { chomp; process_file($_); @@ -2616,4 +2219,4 @@ if ($verbose && $warnings) { print STDERR "$warnings warnings\n"; } -exit($errors); +exit($output_mode eq "none" ? 0 : $errors);