code:
.. SPDX-License-Identifier: GPL-2.0

.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/license-rules.rst <kernel_licensing>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
             Hu Haowen <src.res@email.cn>

.. _tw_kernel_licensing:

Linux內核許可規則
=================

Linux內核根據LICENSES/preferred/GPL-2.0中提供的GNU通用公共許可證版本2
（GPL-2.0）的條款提供，並在LICENSES/exceptions/Linux-syscall-note中顯式
描述了例外的系統調用，如COPYING文件中所述。

此文檔文件提供了如何對每個源文件進行注釋以使其許可證清晰明確的說明。
它不會取代內核的許可證。

內核原始碼作爲一個整體適用於COPYING文件中描述的許可證，但是單個源文件可以
具有不同的與GPL-20兼容的許可證::

    GPL-1.0+ : GNU通用公共許可證v1.0或更高版本
    GPL-2.0+ : GNU通用公共許可證v2.0或更高版本
    LGPL-2.0 : 僅限GNU庫通用公共許可證v2
    LGPL-2.0+: GNU 庫通用公共許可證v2或更高版本
    LGPL-2.1 : 僅限GNU寬通用公共許可證v2.1
    LGPL-2.1+: GNU寬通用公共許可證v2.1或更高版本

除此之外，個人文件可以在雙重許可下提供，例如一個兼容的GPL變體，或者BSD，
MIT等許可。

用戶空間API（UAPI）頭文件描述了用戶空間程序與內核的接口，這是一種特殊情況。
根據內核COPYING文件中的注釋，syscall接口是一個明確的邊界，它不會將GPL要求
擴展到任何使用它與內核通信的軟體。由於UAPI頭文件必須包含在創建在Linux內核
上運行的可執行文件的任何源文件中，因此此例外必須記錄在特別的許可證表述中。

表達源文件許可證的常用方法是將匹配的樣板文本添加到文件的頂部注釋中。由於
格式，拼寫錯誤等，這些「樣板」很難通過那些在上下文中使用的驗證許可證合規性
的工具。

樣板文本的替代方法是在每個源文件中使用軟體包數據交換（SPDX）許可證標識符。
SPDX許可證標識符是機器可解析的，並且是用於提供文件內容的許可證的精確縮寫。
SPDX許可證標識符由Linux 基金會的SPDX 工作組管理，並得到了整個行業，工具
供應商和法律團隊的合作夥伴的一致同意。有關詳細信息，請參閱
https://spdx.org/

Linux內核需要所有源文件中的精確SPDX標識符。內核中使用的有效標識符在
`許可標識符`_ 一節中進行了解釋，並且已可以在
https://spdx.org/licenses/ 上的官方SPDX許可證列表中檢索，並附帶許可證
文本。

許可標識符語法
--------------

1.安置:

   內核文件中的SPDX許可證標識符應添加到可包含注釋的文件中的第一行。對於大多
   數文件，這是第一行，除了那些在第一行中需要'#!PATH_TO_INTERPRETER'的腳本。
   對於這些腳本，SPDX標識符進入第二行。

|

2. 風格:

   SPDX許可證標識符以注釋的形式添加。注釋樣式取決於文件類型::

      C source:	// SPDX-License-Identifier: <SPDX License Expression>
      C header:	/* SPDX-License-Identifier: <SPDX License Expression> */
      ASM:	/* SPDX-License-Identifier: <SPDX License Expression> */
      scripts:	# SPDX-License-Identifier: <SPDX License Expression>
      .rst:	.. SPDX-License-Identifier: <SPDX License Expression>
      .dts{i}:	// SPDX-License-Identifier: <SPDX License Expression>

   如果特定工具無法處理標準注釋樣式，則應使用工具接受的相應注釋機制。這是在
   C 頭文件中使用「/\*\*/」樣式注釋的原因。過去在使用生成的.lds文件中觀察到
   構建被破壞，其中'ld'無法解析C++注釋。現在已經解決了這個問題，但仍然有較
   舊的彙編程序工具無法處理C++樣式的注釋。

|

3. 句法:

   <SPDX許可證表達式>是SPDX許可證列表中的SPDX短格式許可證標識符，或者在許可
   證例外適用時由「WITH」分隔的兩個SPDX短格式許可證標識符的組合。當應用多個許
   可證時，表達式由分隔子表達式的關鍵字「AND」，「OR」組成，並由「（」，「）」包圍。

   帶有「或更高」選項的[L]GPL等許可證的許可證標識符通過使用「+」來表示「或更高」
   選項來構建。::

      // SPDX-License-Identifier: GPL-2.0+
      // SPDX-License-Identifier: LGPL-2.1+

   當需要修正的許可證時，應使用WITH。 例如，linux內核UAPI文件使用表達式::

      // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
      // SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note

   其它在內核中使用WITH例外的事例如下::

      // SPDX-License-Identifier: GPL-2.0 WITH mif-exception
      // SPDX-License-Identifier: GPL-2.0+ WITH GCC-exception-2.0

   例外只能與特定的許可證標識符一起使用。有效的許可證標識符列在異常文本文件
   的標記中。有關詳細信息，請參閱 `許可標識符`_ 一章中的 `例外`_ 。

   如果文件是雙重許可且只選擇一個許可證，則應使用OR。例如，一些dtsi文件在雙
   許可下可用::

      // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause

   內核中雙許可文件中許可表達式的示例::

      // SPDX-License-Identifier: GPL-2.0 OR MIT
      // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
      // SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
      // SPDX-License-Identifier: GPL-2.0 OR MPL-1.1
      // SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT
      // SPDX-License-Identifier: GPL-1.0+ OR BSD-3-Clause OR OpenSSL

   如果文件具有多個許可證，其條款全部適用於使用該文件，則應使用AND。例如，
   如果代碼是從另一個項目繼承的，並且已經授予了將其放入內核的權限，但原始
   許可條款需要保持有效::

      // SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) AND MIT

   另一個需要遵守兩套許可條款的例子是::

      // SPDX-License-Identifier: GPL-1.0+ AND LGPL-2.1+

許可標識符
----------

當前使用的許可證以及添加到內核的代碼許可證可以分解爲：

1. _`優先許可`:

   應儘可能使用這些許可證，因爲它們已知完全兼容並廣泛使用。這些許可證在內核
   目錄::

      LICENSES/preferred/

   此目錄中的文件包含完整的許可證文本和 `元標記`_ 。文件名與SPDX許可證標識
   符相同，後者應用於源文件中的許可證。

   例如::

      LICENSES/preferred/GPL-2.0

   包含GPLv2許可證文本和所需的元標籤::

      LICENSES/preferred/MIT

   包含MIT許可證文本和所需的元標記

   _`元標記`:

   許可證文件中必須包含以下元標記：

   - Valid-License-Identifier:

     一行或多行, 聲明那些許可標識符在項目內有效, 以引用此特定許可的文本。通
     常這是一個有效的標識符，但是例如對於帶有'或更高'選項的許可證，兩個標識
     符都有效。

   - SPDX-URL:

     SPDX頁面的URL，其中包含與許可證相關的其他信息.

   - Usage-Guidance:

     使用建議的自由格式文本。該文本必須包含SPDX許可證標識符的正確示例，因爲
     它們應根據 `許可標識符語法`_ 指南放入源文件中。

   - License-Text:

     此標記之後的所有文本都被視爲原始許可文本

   文件格式示例::

      Valid-License-Identifier: GPL-2.0
      Valid-License-Identifier: GPL-2.0+
      SPDX-URL: https://spdx.org/licenses/GPL-2.0.html
      Usage-Guide:
        To use this license in source code, put one of the following SPDX
	tag/value pairs into a comment according to the placement
	guidelines in the licensing rules documentation.
	For 'GNU General Public License (GPL) version 2 only' use:
	  SPDX-License-Identifier: GPL-2.0
	For 'GNU General Public License (GPL) version 2 or any later version' use:
	  SPDX-License-Identifier: GPL-2.0+
      License-Text:
        Full license text

   ::

      SPDX-License-Identifier: MIT
      SPDX-URL: https://spdx.org/licenses/MIT.html
      Usage-Guide:
	To use this license in source code, put the following SPDX
	tag/value pair into a comment according to the placement
	guidelines in the licensing rules documentation.
	  SPDX-License-Identifier: MIT
      License-Text:
        Full license text

|

2. 不推薦的許可證:

   這些許可證只應用於現有代碼或從其他項目導入代碼。這些許可證在內核目錄::

      LICENSES/other/

   此目錄中的文件包含完整的許可證文本和 `元標記`_ 。文件名與SPDX許可證標識
   符相同，後者應用於源文件中的許可證。

   例如::

      LICENSES/other/ISC

   包含國際系統聯合許可文本和所需的元標籤::

      LICENSES/other/ZLib

   包含ZLIB許可文本和所需的元標籤.

   元標籤:

   「其他」許可證的元標籤要求與 `優先許可`_ 的要求相同。

   文件格式示例::

      Valid-License-Identifier: ISC
      SPDX-URL: https://spdx.org/licenses/ISC.html
      Usage-Guide:
        Usage of this license in the kernel for new code is discouraged
	and it should solely be used for importing code from an already
	existing project.
        To use this license in source code, put the following SPDX
	tag/value pair into a comment according to the placement
	guidelines in the licensing rules documentation.
	  SPDX-License-Identifier: ISC
      License-Text:
        Full license text

|

3. _`例外`:

   某些許可證可以修改，並允許原始許可證不具有的某些例外權利。這些例外在
   內核目錄::

      LICENSES/exceptions/

   此目錄中的文件包含完整的例外文本和所需的 `例外元標記`_ 。

   例如::

      LICENSES/exceptions/Linux-syscall-note

   包含Linux內核的COPYING文件中記錄的Linux系統調用例外，該文件用於UAPI
   頭文件。例如::

      LICENSES/exceptions/GCC-exception-2.0

   包含GCC'連結例外'，它允許獨立於其許可證的任何二進位文件與標記有此例外的
   文件的編譯版本連結。這是從GPL不兼容原始碼創建可運行的可執行文件所必需的。

   _`例外元標記`:

   以下元標記必須在例外文件中可用：

   - SPDX-Exception-Identifier:

     一個可與SPDX許可證標識符一起使用的例外標識符。

   - SPDX-URL:

     SPDX頁面的URL，其中包含與例外相關的其他信息。

   - SPDX-Licenses:

     以逗號分隔的例外可用的SPDX許可證標識符列表。

   - Usage-Guidance:

     使用建議的自由格式文本。必須在文本後面加上SPDX許可證標識符的正確示例，
     因爲它們應根據 `許可標識符語法`_ 指南放入源文件中。

   - Exception-Text:

     此標記之後的所有文本都被視爲原始異常文本

   文件格式示例::

      SPDX-Exception-Identifier: Linux-syscall-note
      SPDX-URL: https://spdx.org/licenses/Linux-syscall-note.html
      SPDX-Licenses: GPL-2.0, GPL-2.0+, GPL-1.0+, LGPL-2.0, LGPL-2.0+, LGPL-2.1, LGPL-2.1+
      Usage-Guidance:
        This exception is used together with one of the above SPDX-Licenses
	to mark user-space API (uapi) header files so they can be included
	into non GPL compliant user-space application code.
        To use this exception add it with the keyword WITH to one of the
	identifiers in the SPDX-Licenses tag:
	  SPDX-License-Identifier: <SPDX-License> WITH Linux-syscall-note
      Exception-Text:
        Full exception text

   ::

      SPDX-Exception-Identifier: GCC-exception-2.0
      SPDX-URL: https://spdx.org/licenses/GCC-exception-2.0.html
      SPDX-Licenses: GPL-2.0, GPL-2.0+
      Usage-Guidance:
        The "GCC Runtime Library exception 2.0" is used together with one
	of the above SPDX-Licenses for code imported from the GCC runtime
	library.
        To use this exception add it with the keyword WITH to one of the
	identifiers in the SPDX-Licenses tag:
	  SPDX-License-Identifier: <SPDX-License> WITH GCC-exception-2.0
      Exception-Text:
        Full exception text

所有SPDX許可證標識符和例外都必須在LICENSES子目錄中具有相應的文件。這是允許
工具驗證（例如checkpatch.pl）以及準備好從源讀取和提取許可證所必需的, 這是
各種FOSS組織推薦的，例如 `FSFE REUSE initiative <https://reuse.software/>`_.

_`模塊許可`
-----------------

   可加載內核模塊還需要MODULE_LICENSE（）標記。此標記既不替代正確的原始碼
   許可證信息（SPDX-License-Identifier），也不以任何方式表示或確定提供模塊
   原始碼的確切許可證。

   此標記的唯一目的是提供足夠的信息，該模塊是否是自由軟體或者是內核模塊加
   載器和用戶空間工具的專有模塊。

   MODULE_LICENSE（）的有效許可證字符串是:

    ============================= =============================================
    "GPL"			  模塊是根據GPL版本2許可的。這並不表示僅限於
                                  GPL-2.0或GPL-2.0或更高版本之間的任何區別。
                                  最正確許可證信息只能通過相應源文件中的許可證
                                  信息來確定

    "GPL v2"			  和"GPL"相同，它的存在是因爲歷史原因。

    "GPL and additional rights"   表示模塊源在GPL v2變體和MIT許可下雙重許可的
                                  歷史變體。請不要在新代碼中使用。

    "Dual MIT/GPL"		  表達該模塊在GPL v2變體或MIT許可證選擇下雙重
                                  許可的正確方式。

    "Dual BSD/GPL"		  該模塊根據GPL v2變體或BSD許可證選擇進行雙重
                                  許可。 BSD許可證的確切變體只能通過相應源文件
                                  中的許可證信息來確定。

    "Dual MPL/GPL"		  該模塊根據GPL v2變體或Mozilla Public License
                                  （MPL）選項進行雙重許可。 MPL許可證的確切變體
                                  只能通過相應的源文件中的許可證信息來確定。

    "Proprietary"		  該模塊屬於專有許可。此字符串僅用於專有的第三
                                  方模塊，不能用於在內核樹中具有原始碼的模塊。
                                  以這種方式標記的模塊在加載時會使用'P'標記汙
                                  染內核，並且內核模塊加載器拒絕將這些模塊連結
                                  到使用EXPORT_SYMBOL_GPL（）導出的符號。
    ============================= =============================================


code:
.. SPDX-License-Identifier: GPL-2.0

.. _tw_magicnumbers:

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/magic-number.rst <magicnumbers>`

如果想評論或更新本文的內容，請直接發信到LKML。如果你使用英文交流有困難的話，也可
以向中文版維護者求助。如果本翻譯更新不及時或者翻譯存在問題，請聯繫中文版維護者::

        中文版維護者： 賈威威 Jia Wei Wei <harryxiyou@gmail.com>
        中文版翻譯者： 賈威威 Jia Wei Wei <harryxiyou@gmail.com>
        中文版校譯者： 賈威威 Jia Wei Wei <harryxiyou@gmail.com>
                      胡皓文 Hu Haowen <src.res@email.cn>

Linux 魔術數
============

這個文件是有關當前使用的魔術值註冊表。當你給一個結構添加了一個魔術值，你也應該把這個魔術值添加到這個文件，因爲我們最好把用於各種結構的魔術值統一起來。

使用魔術值來保護內核數據結構是一個非常好的主意。這就允許你在運行期檢查(a)一個結構是否已經被攻擊，或者(b)你已經給一個例行程序通過了一個錯誤的結構。後一種情況特別地有用---特別是當你通過一個空指針指向結構體的時候。tty源碼，例如，經常通過特定驅動使用這種方法並且反覆地排列特定方面的結構。

使用魔術值的方法是在結構的開始處聲明的，如下::

        struct tty_ldisc {
	        int	magic;
        	...
        };

當你以後給內核添加增強功能的時候，請遵守這條規則！這樣就會節省數不清的調試時間，特別是一些古怪的情況，例如，數組超出範圍並且重新寫了超出部分。遵守這個規則，這些情況可以被快速地，安全地避免。

		Theodore Ts'o
		  31 Mar 94

給當前的Linux 2.1.55添加魔術表。

		Michael Chastain
		<mailto:mec@shout.net>
		22 Sep 1997

現在應該最新的Linux 2.1.112.因爲在特性凍結期間，不能在2.2.x前改變任何東西。這些條目被數域所排序。

		Krzysztof G.Baranowski
	        <mailto: kgb@knm.org.pl>
		29 Jul 1998

更新魔術表到Linux 2.5.45。剛好越過特性凍結，但是有可能還會有一些新的魔術值在2.6.x之前融入到內核中。

		Petr Baudis
		<pasky@ucw.cz>
		03 Nov 2002

更新魔術表到Linux 2.5.74。

		Fabian Frederick
                <ffrederick@users.sourceforge.net>
		09 Jul 2003

===================== ================ ======================== ==========================================
魔術數名              數字             結構                     文件
===================== ================ ======================== ==========================================
PG_MAGIC              'P'              pg_{read,write}_hdr      ``include/linux/pg.h``
APM_BIOS_MAGIC        0x4101           apm_user                 ``arch/x86/kernel/apm_32.c``
FASYNC_MAGIC          0x4601           fasync_struct            ``include/linux/fs.h``
SLIP_MAGIC            0x5302           slip                     ``drivers/net/slip.h``
MGSLPC_MAGIC          0x5402           mgslpc_info              ``drivers/char/pcmcia/synclink_cs.c``
BAYCOM_MAGIC          0x19730510       baycom_state             ``drivers/net/baycom_epp.c``
HDLCDRV_MAGIC         0x5ac6e778       hdlcdrv_state            ``include/linux/hdlcdrv.h``
KV_MAGIC              0x5f4b565f       kernel_vars_s            ``arch/mips/include/asm/sn/klkernvars.h``
CODA_MAGIC            0xC0DAC0DA       coda_file_info           ``fs/coda/coda_fs_i.h``
YAM_MAGIC             0xF10A7654       yam_port                 ``drivers/net/hamradio/yam.c``
CCB_MAGIC             0xf2691ad2       ccb                      ``drivers/scsi/ncr53c8xx.c``
QUEUE_MAGIC_FREE      0xf7e1c9a3       queue_entry              ``drivers/scsi/arm/queue.c``
QUEUE_MAGIC_USED      0xf7e1cc33       queue_entry              ``drivers/scsi/arm/queue.c``
NMI_MAGIC             0x48414d4d455201 nmi_s                    ``arch/mips/include/asm/sn/nmi.h``
===================== ================ ======================== ==========================================

repo_name: angery/linux


code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/management-style.rst <managementstyle>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
             Hu Haowen <src.res@email.cn>

.. _tw_managementstyle:

Linux內核管理風格
=================

這是一個簡短的文檔，描述了Linux內核首選的（或胡編的，取決於您問誰）管理風格。
它的目的是在某種程度上參照 :ref:`process/coding-style.rst <codingstyle>`
主要是爲了避免反覆回答 [#cnf1]_ 相同（或類似）的問題。

管理風格是非常個人化的，比簡單的編碼風格規則更難以量化，因此本文檔可能與實
際情況有關，也可能與實際情況無關。起初它是一個玩笑，但這並不意味著它可能不
是真的。你得自己決定。

順便說一句，在談到「核心管理者」時，主要是技術負責人，而不是在公司內部進行傳
統管理的人。如果你簽署了採購訂單或者對你的團隊的預算有任何了解，你幾乎肯定
不是一個核心管理者。這些建議可能適用於您，也可能不適用於您。

首先，我建議你購買「高效人的七個習慣」，而不是閱讀它。燒了它，這是一個偉大的
象徵性姿態。

.. [#cnf1] 本文件並不是通過回答問題，而是通過讓提問者痛苦地明白，我們不知道
   答案是什麼。

不管怎樣，這裡是：

.. _tw_decisions:

1）決策
-------

每個人都認爲管理者做決定，而且決策很重要。決定越大越痛苦，管理者就必須越高級。
這很明顯，但事實並非如此。

遊戲的名字是 **避免** 做出決定。尤其是，如果有人告訴你「選擇（a）或（b），
我們真的需要你來做決定」，你就是陷入麻煩的管理者。你管理的人比你更了解細節，
所以如果他們來找你做技術決策，你完蛋了。你顯然沒有能力爲他們做這個決定。

（推論：如果你管理的人不比你更了解細節，你也會被搞砸，儘管原因完全不同。
也就是說，你的工作是錯的，他們應該管理你的才智）

所以遊戲的名字是 **避免** 做出決定，至少是那些大而痛苦的決定。做一些小的
和非結果性的決定是很好的，並且使您看起來好像知道自己在做什麼，所以內核管理者
需要做的是將那些大的和痛苦的決定變成那些沒有人真正關心的小事情。

這有助於認識到一個大的決定和一個小的決定之間的關鍵區別是你是否可以在事後修正
你的決定。任何決定都可以通過始終確保如果你錯了（而且你一定會錯），你以後總是
可以通過回溯來彌補損失。突然間，你就要做兩個無關緊要的決定，一個是錯誤的，另
一個是正確的。

人們甚至會認爲這是真正的領導能力（咳，胡說，咳）。

因此，避免重大決策的關鍵在於避免做那些無法挽回的事情。不要被引導到一個你無法
逃離的角落。走投無路的老鼠可能很危險——走投無路的管理者真可憐。

事實證明，由於沒有人會愚蠢到讓內核管理者承擔巨大的財政責任，所以通常很容易
回溯。既然你不可能浪費掉你無法償還的巨額資金，你唯一可以回溯的就是技術決策，
而回溯很容易：只要告訴大家你是個不稱職的傻瓜，說對不起，然後撤銷你去年讓別
人所做的毫無價值的工作。突然間，你一年前做的決定不在是一個重大的決定，因爲
它很容易被推翻。

事實證明，有些人對接受這種方法有困難，原因有兩個：

 - 承認你是個白癡比看起來更難。我們都喜歡保持形象，在公共場合說你錯了有時
   確實很難。
 - 如果有人告訴你，你去年所做的工作終究是不值得的，那麼對那些可憐的低級工
   程師來說也是很困難的，雖然實際的 **工作** 很容易刪除，但你可能已經不可
   挽回地失去了工程師的信任。記住：「不可撤銷」是我們一開始就試圖避免的，
   而你的決定終究是一個重大的決定。

令人欣慰的是，這兩個原因都可以通過預先承認你沒有任何線索，提前告訴人們你的
決定完全是初步的，而且可能是錯誤的事情來有效地緩解。你應該始終保留改變主意
的權利，並讓人們 **意識** 到這一點。當你 **還沒有** 做過真正愚蠢的事情的時
候，承認自己是愚蠢的要容易得多。

然後，當它真的被證明是愚蠢的時候，人們就轉動他們的眼珠說「哎呀，下次不要了」。

這種對不稱職的先發制人的承認，也可能使真正做這項工作的人也會三思是否值得做。
畢竟，如果他們不確定這是否是一個好主意，你肯定不應該通過向他們保證他們所做
的工作將會進入（內核）鼓勵他們。在他們開始一項巨大的努力之前，至少讓他們三
思而後行。

記住：他們最好比你更了解細節，而且他們通常認爲他們對每件事都有答案。作爲一
個管理者，你能做的最好的事情不是灌輸自信，而是對他們所做的事情進行健康的批
判性思考。

順便說一句，另一種避免做出決定的方法是看起來很可憐的抱怨 「我們不能兩者兼
得嗎？」 相信我，它是有效的。如果不清楚哪種方法更好，他們最終會弄清楚的。
最終的答案可能是兩個團隊都會因爲這種情況而感到沮喪，以至於他們放棄了。

這聽起來像是一個失敗，但這通常是一個跡象，表明兩個項目都有問題，而參與其中
的人不能做決定的原因是他們都是錯誤的。你最終會聞到玫瑰的味道，你避免了另一
個你本可以搞砸的決定。

2）人
-----

大多數人都是白癡，做一名管理者意味著你必須處理好這件事，也許更重要的是,
**他們** 必須處理好你。

事實證明，雖然很容易糾正技術錯誤，但不容易糾正人格障礙。你只能和他們的和
你的（人格障礙）共處。

但是，爲了做好作爲內核管理者的準備，最好記住不要燒掉任何橋樑，不要轟炸任何
無辜的村民，也不要疏遠太多的內核開發人員。事實證明，疏遠人是相當容易的，而
親近一個疏遠的人是很難的。因此，「疏遠」立即屬於「不可逆」的範疇，並根據
:ref:`tw_decisions` 成爲絕不可以做的事情。

這裡只有幾個簡單的規則：

 (1) 不要叫人笨蛋（至少不要在公共場合）
 (2) 學習如何在忘記規則(1)時道歉

問題在於 #1 很容易去做，因爲你可以用數百萬種不同的方式說「你是一個笨蛋」 [#cnf2]_
有時甚至沒有意識到，而且幾乎總是帶著一種白熱化的信念，認爲你是對的。

你越確信自己是對的（讓我們面對現實吧，你可以把幾乎所有人都稱爲壞人，而且你
經常是對的），事後道歉就越難。

要解決此問題，您實際上只有兩個選項：

 - 非常擅長道歉
 - 把「愛」均勻地散開，沒有人會真正感覺到自己被不公平地瞄準了。讓它有足夠的
   創造性，他們甚至可能會覺得好笑。

選擇永遠保持禮貌是不存在的。沒有人會相信一個如此明顯地隱藏了他們真實性格的人。

.. [#cnf2] 保羅·西蒙演唱了「離開愛人的50種方法」，因爲坦率地說，「告訴開發者
   他們是D*CKHEAD" 的100萬種方法都無法確認。但我確信他已經這麼想了。

3）人2 - 好人
-------------

雖然大多數人都是白癡，但不幸的是，據此推論你也是白癡，儘管我們都自我感覺良
好，我們比普通人更好（讓我們面對現實吧，沒有人相信他們是普通人或低於普通人），
我們也應該承認我們不是最鋒利的刀，而且會有其他人比你更不像白癡。

有些人對聰明人反應不好。其他人利用它們。

作爲內核維護人員，確保您在第二組中。接受他們，因爲他們會讓你的工作更容易。
特別是，他們能夠爲你做決定，這就是遊戲的全部內容。

所以當你發現一個比你聰明的人時，就順其自然吧。你的管理職責在很大程度上變成
了「聽起來像是個好主意——去嘗試吧」，或者「聽起來不錯，但是XXX呢？」「。第二個版
本尤其是一個很好的方法，要麼學習一些關於「XXX」的新東西，要麼通過指出一些聰明
人沒有想到的東西來顯得更具管理性。無論哪種情況，你都會贏。

要注意的一件事是認識到一個領域的偉大不一定會轉化爲其他領域。所以你可能會向
特定的方向刺激人們，但讓我們面對現實吧，他們可能擅長他們所做的事情，而且對
其他事情都很差勁。好消息是，人們往往會自然而然地重拾他們擅長的東西，所以當
你向某個方向刺激他們時，你並不是在做不可逆轉的事情，只是不要用力推。

4）責備
-------

事情會出問題的，人們希望去責備人。貼標籤，你就是受責備的人。

事實上，接受責備並不難，尤其是當人們意識到這不 **全是** 你的過錯時。這讓我
們找到了承擔責任的最佳方式：爲別人承擔這件事。你會感覺很好，他們會感覺很好，
沒有受到指責. 那誰，失去了他們的全部36GB色情收藏的人，因爲你的無能將勉強承
認，你至少沒有試圖逃避責任。

然後讓真正搞砸了的開發人員（如果你能找到他們）私下知道他們搞砸了。不僅是爲
了將來可以避免，而且爲了讓他們知道他們欠你一個人情。而且，也許更重要的是，
他們也可能是能夠解決問題的人。因爲，讓我們面對現實吧，肯定不是你。

承擔責任也是你首先成爲管理者的原因。這是讓人們信任你，讓你獲得潛在的榮耀的
一部分，因爲你就是那個會說「我搞砸了」的人。如果你已經遵循了以前的規則，你現
在已經很擅長說了。

5）應避免的事情
---------------

有一件事人們甚至比被稱爲「笨蛋」更討厭，那就是在一個神聖的聲音中被稱爲「笨蛋」。
第一個你可以道歉，第二個你不會真正得到機會。即使你做得很好，他們也可能不再
傾聽。

我們都認爲自己比別人強，這意味著當別人裝腔作勢時，這會讓我們很惱火。你也許
在道德和智力上比你周圍的每個人都優越，但不要試圖太明顯，除非你真的打算激怒
某人 [#cnf3]_

同樣，不要對事情太客氣或太微妙。禮貌很容易落得落花流水，把問題隱藏起來，
正如他們所說，「在網際網路上，沒人能聽到你的含蓄。」用一個鈍器把這一點錘進去，
因爲你不能真的依靠別人來獲得你的觀點。

一些幽默可以幫助緩和直率和道德化。過度到荒謬的地步，可以灌輸一個觀點，而不
會讓接受者感到痛苦，他們只是認爲你是愚蠢的。因此，它可以幫助我們擺脫對批評
的個人心理障礙。

.. [#cnf3] 提示：與你的工作沒有直接關係的網絡新聞組是消除你對他人不滿的好
   方法。偶爾寫些侮辱性的帖子，打個噴嚏，讓你的情緒得到淨化。別把牢騷帶回家

6）爲什麼是我？
---------------

既然你的主要責任似乎是爲別人的錯誤承擔責任，並且讓別人痛苦地明白你是不稱職
的，那麼顯而易見的問題之一就變成了爲什麼首先要這樣做。

首先，雖然你可能會或可能不會聽到十幾歲女孩（或男孩，讓我們不要在這裡評判或
性別歧視）敲你的更衣室門，你會得到一個巨大的個人成就感爲「負責」。別介意你真
的在領導別人，你要跟上別人，儘可能快地追趕他們。每個人都會認爲你是負責人。

如果你可以做到這個， 這是個偉大的工作！


code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/programming-language.rst <programming_language>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
             Hu Haowen <src.res@email.cn>

.. _tw_programming_language:

程序設計語言
============

內核是用C語言 :ref:`c-language <tw_c-language>` 編寫的。更準確地說，內核通常是用 :ref:`gcc <tw_gcc>`
在 ``-std=gnu11`` :ref:`gcc-c-dialect-options <tw_gcc-c-dialect-options>` 下編譯的：ISO C11的 GNU 方言

這種方言包含對語言 :ref:`gnu-extensions <tw_gnu-extensions>` 的許多擴展，當然，它們許多都在內核中使用。

對於一些體系結構，有一些使用 :ref:`clang <tw_clang>` 和 :ref:`icc <tw_icc>` 編譯內核
的支持，儘管在編寫此文檔時還沒有完成，仍需要第三方補丁。

屬性
----

在整個內核中使用的一個常見擴展是屬性（attributes） :ref:`gcc-attribute-syntax <tw_gcc-attribute-syntax>`
屬性允許將實現定義的語義引入語言實體（如變量、函數或類型），而無需對語言進行
重大的語法更改（例如添加新關鍵字） :ref:`n2049 <tw_n2049>`

在某些情況下，屬性是可選的（即不支持這些屬性的編譯器仍然應該生成正確的代碼，
即使其速度較慢或執行的編譯時檢查/診斷次數不夠）

內核定義了僞關鍵字（例如， ``pure`` ），而不是直接使用GNU屬性語法（例如,
``__attribute__((__pure__))`` ），以檢測可以使用哪些關鍵字和/或縮短代碼, 具體
請參閱 ``include/linux/compiler_attributes.h``

.. _tw_c-language:

c-language
   http://www.open-std.org/jtc1/sc22/wg14/www/standards

.. _tw_gcc:

gcc
   https://gcc.gnu.org

.. _tw_clang:

clang
   https://clang.llvm.org

.. _tw_icc:

icc
   https://software.intel.com/en-us/c-compilers

.. _tw_gcc-c-dialect-options:

c-dialect-options
   https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html

.. _tw_gnu-extensions:

gnu-extensions
   https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html

.. _tw_gcc-attribute-syntax:

gcc-attribute-syntax
   https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html

.. _tw_n2049:

n2049
   http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2049.pdf


code:
.. SPDX-License-Identifier: GPL-2.0

.. _tw_stable_api_nonsense:

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/stable-api-nonsense.rst
           <stable_api_nonsense>`

譯者::

        中文版維護者： 鍾宇  TripleX Chung <xxx.phy@gmail.com>
        中文版翻譯者： 鍾宇  TripleX Chung <xxx.phy@gmail.com>
        中文版校譯者： 李陽  Li Yang <leoyang.li@nxp.com>
                      胡皓文 Hu Haowen <src.res@email.cn>

Linux 內核驅動接口
==================

寫作本文檔的目的，是爲了解釋爲什麼Linux既沒有二進位內核接口，也沒有穩定
的內核接口。這裡所說的內核接口，是指內核里的接口，而不是內核和用戶空間
的接口。內核到用戶空間的接口，是提供給應用程式使用的系統調用，系統調用
在歷史上幾乎沒有過變化，將來也不會有變化。我有一些老應用程式是在0.9版本
或者更早版本的內核上編譯的，在使用2.6版本內核的Linux發布上依然用得很好
。用戶和應用程式作者可以將這個接口看成是穩定的。

執行綱要
--------

你也許以爲自己想要穩定的內核接口，但是你不清楚你要的實際上不是它。你需
要的其實是穩定的驅動程序，而你只有將驅動程序放到公版內核的原始碼樹里，
才有可能達到這個目的。而且這樣做還有很多其它好處，正是因爲這些好處使得
Linux能成爲強壯，穩定，成熟的作業系統，這也是你最開始選擇Linux的原因。

入門
-----

只有那些寫驅動程序的「怪人」才會擔心內核接口的改變，對廣大用戶來說，既
看不到內核接口，也不需要去關心它。

首先，我不打算討論關於任何非GPL許可的內核驅動的法律問題，這些非GPL許可
的驅動程序包括不公開原始碼，隱藏原始碼，二進位或者是用原始碼包裝，或者
是其它任何形式的不能以GPL許可公開原始碼的驅動程序。如果有法律問題，請咨
詢律師，我只是一個程式設計師，所以我只打算探討技術問題（不是小看法律問題，
法律問題很實際，並且需要一直關注）。

既然只談技術問題，我們就有了下面兩個主題：二進位內核接口和穩定的內核源
代碼接口。這兩個問題是互相關聯的，讓我們先解決掉二進位接口的問題。

二進位內核接口
--------------
假如我們有一個穩定的內核原始碼接口，那麼自然而然的，我們就擁有了穩定的
二進位接口，是這樣的嗎？錯。讓我們看看關於Linux內核的幾點事實：

    - 取決於所用的C編譯器的版本，不同的內核數據結構里的結構體的對齊方
      式會有差別，代碼中不同函數的表現形式也不一樣（函數是不是被inline
      編譯取決於編譯器行爲）。不同的函數的表現形式並不重要，但是數據
      結構內部的對齊方式很關鍵。

    - 取決於內核的配置選項，不同的選項會讓內核的很多東西發生改變：

      - 同一個結構體可能包含不同的成員變量
      - 有的函數可能根本不會被實現（比如編譯的時候沒有選擇SMP支持
        一些鎖函數就會被定義成空函數）。
      - 內核使用的內存會以不同的方式對齊，這取決於不同的內核配置選
        項。

    - Linux可以在很多的不同體系結構的處理器上運行。在某個體系結構上編
      譯好的二進位驅動程序，不可能在另外一個體系結構上正確的運行。

對於一個特定的內核，滿足這些條件並不難，使用同一個C編譯器和同樣的內核配
置選項來編譯驅動程序模塊就可以了。這對於給一個特定Linux發布的特定版本提
供驅動程序，是完全可以滿足需求的。但是如果你要給不同發布的不同版本都發
布一個驅動程序，就需要在每個發布上用不同的內核設置參數都編譯一次內核，
這簡直跟噩夢一樣。而且還要注意到，每個Linux發布還提供不同的Linux內核，
這些內核都針對不同的硬體類型進行了優化（有很多種不同的處理器，還有不同
的內核設置選項）。所以每發布一次驅動程序，都需要提供很多不同版本的內核
模塊。

相信我，如果你真的要採取這種發布方式，一定會慢慢瘋掉，我很久以前就有過
深刻的教訓...

穩定的內核原始碼接口
--------------------

如果有人不將他的內核驅動程序，放入公版內核的原始碼樹，而又想讓驅動程序
一直保持在最新的內核中可用，那麼這個話題將會變得沒完沒了。
內核開發是持續而且快節奏的，從來都不會慢下來。內核開發人員在當前接口中
找到bug，或者找到更好的實現方式。一旦發現這些，他們就很快會去修改當前的
接口。修改接口意味著，函數名可能會改變，結構體可能被擴充或者刪減，函數
的參數也可能發生改變。一旦接口被修改，內核中使用這些接口的地方需要同時
修正，這樣才能保證所有的東西繼續工作。

舉一個例子，內核的USB驅動程序接口在USB子系統的整個生命周期中，至少經歷
了三次重寫。這些重寫解決以下問題：

    - 把數據流從同步模式改成非同步模式，這個改動減少了一些驅動程序的
      複雜度，提高了所有USB驅動程序的吞吐率，這樣幾乎所有的USB設備都
      能以最大速率工作了。
    - 修改了USB核心代碼中爲USB驅動分配數據包內存的方式，所有的驅動都
      需要提供更多的參數給USB核心，以修正了很多已經被記錄在案的死鎖。

這和一些封閉原始碼的作業系統形成鮮明的對比，在那些作業系統上，不得不額
外的維護舊的USB接口。這導致了一個可能性，新的開發者依然會不小心使用舊的
接口，以不恰當的方式編寫代碼，進而影響到作業系統的穩定性。
在上面的例子中，所有的開發者都同意這些重要的改動，在這樣的情況下修改代
價很低。如果Linux保持一個穩定的內核原始碼接口，那麼就得創建一個新的接口
；舊的，有問題的接口必須一直維護，給Linux USB開發者帶來額外的工作。既然
所有的Linux USB驅動的作者都是利用自己的時間工作，那麼要求他們去做毫無意
義的免費額外工作，是不可能的。
安全問題對Linux來說十分重要。一個安全問題被發現，就會在短時間內得到修
正。在很多情況下，這將導致Linux內核中的一些接口被重寫，以從根本上避免安
全問題。一旦接口被重寫，所有使用這些接口的驅動程序，必須同時得到修正，
以確定安全問題已經得到修復並且不可能在未來還有同樣的安全問題。如果內核
內部接口不允許改變，那麼就不可能修復這樣的安全問題，也不可能確認這樣的
安全問題以後不會發生。
開發者一直在清理內核接口。如果一個接口沒有人在使用了，它就會被刪除。這
樣可以確保內核儘可能的小，而且所有潛在的接口都會得到儘可能完整的測試
（沒有人使用的接口是不可能得到良好的測試的）。

要做什麼
--------

如果你寫了一個Linux內核驅動，但是它還不在Linux原始碼樹里，作爲一個開發
者，你應該怎麼做？爲每個發布的每個版本提供一個二進位驅動，那簡直是一個
噩夢，要跟上永遠處於變化之中的內核接口，也是一件辛苦活。
很簡單，讓你的驅動進入內核原始碼樹（要記得我們在談論的是以GPL許可發行
的驅動，如果你的代碼不符合GPL，那麼祝你好運，你只能自己解決這個問題了，
你這個吸血鬼<把Andrew和Linus對吸血鬼的定義連結到這裡>）。當你的代碼加入
公版內核原始碼樹之後，如果一個內核接口改變，你的驅動會直接被修改接口的
那個人修改。保證你的驅動永遠都可以編譯通過，並且一直工作，你幾乎不需要
做什麼事情。

把驅動放到內核原始碼樹里會有很多的好處：

    - 驅動的質量會提升，而維護成本（對原始作者來說）會下降。
    - 其他人會給驅動添加新特性。
    - 其他人會找到驅動中的bug並修復。
    - 其他人會在驅動中找到性能優化的機會。
    - 當外部的接口的改變需要修改驅動程序的時候，其他人會修改驅動程序
    - 不需要聯繫任何發行商，這個驅動會自動的隨著所有的Linux發布一起發
      布。

和別的作業系統相比，Linux爲更多不同的設備提供現成的驅動，而且能在更多不
同體系結構的處理器上支持這些設備。這個經過考驗的開發模式，必然是錯不了
的 :)

感謝
----
感謝 Randy Dunlap, Andrew Morton, David Brownell, Hanna Linder,
Robert Love, and Nishanth Aravamudan 對於本文檔早期版本的評審和建議。

英文版維護者： Greg Kroah-Hartman <greg@kroah.com>


code:
.. SPDX-License-Identifier: GPL-2.0

.. _tw_stable_kernel_rules:

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`

如果想評論或更新本文的內容，請直接聯繫原文檔的維護者。如果你使用英文
交流有困難的話，也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
譯存在問題，請聯繫中文版維護者::

        中文版維護者： 鍾宇  TripleX Chung <xxx.phy@gmail.com>
        中文版翻譯者： 鍾宇  TripleX Chung <xxx.phy@gmail.com>
        中文版校譯者：
            - 李陽  Li Yang <leoyang.li@nxp.com>
            - Kangkai Yin <e12051@motorola.com>
            - 胡皓文 Hu Haowen <src.res@email.cn>

所有你想知道的事情 - 關於linux穩定版發布
========================================

關於Linux 2.6穩定版發布，所有你想知道的事情。

關於哪些類型的補丁可以被接收進入穩定版代碼樹，哪些不可以的規則：
----------------------------------------------------------------

  - 必須是顯而易見的正確，並且經過測試的。
  - 連同上下文，不能大於100行。
  - 必須只修正一件事情。
  - 必須修正了一個給大家帶來麻煩的真正的bug（不是「這也許是一個問題...」
    那樣的東西）。
  - 必須修正帶來如下後果的問題：編譯錯誤（對被標記爲CONFIG_BROKEN的例外），
    內核崩潰，掛起，數據損壞，真正的安全問題，或者一些類似「哦，這不
    好」的問題。簡短的說，就是一些致命的問題。
  - 沒有「理論上的競爭條件」，除非能給出競爭條件如何被利用的解釋。
  - 不能存在任何的「瑣碎的」修正（拼寫修正，去掉多餘空格之類的）。
  - 必須被相關子系統的維護者接受。
  - 必須遵循Documentation/translations/zh_TW/process/submitting-patches.rst里的規則。

向穩定版代碼樹提交補丁的過程：
------------------------------

  - 在確認了補丁符合以上的規則後，將補丁發送到stable@vger.kernel.org。
  - 如果補丁被接受到隊列里，發送者會收到一個ACK回復，如果沒有被接受，收
    到的是NAK回復。回復需要幾天的時間，這取決於開發者的時間安排。
  - 被接受的補丁會被加到穩定版本隊列里，等待其他開發者的審查。
  - 安全方面的補丁不要發到這個列表，應該發送到security@kernel.org。

審查周期：
----------

  - 當穩定版的維護者決定開始一個審查周期，補丁將被發送到審查委員會，以
    及被補丁影響的領域的維護者（除非提交者就是該領域的維護者）並且抄送
    到linux-kernel郵件列表。
  - 審查委員會有48小時的時間，用來決定給該補丁回復ACK還是NAK。
  - 如果委員會中有成員拒絕這個補丁，或者linux-kernel列表上有人反對這個
    補丁，並提出維護者和審查委員會之前沒有意識到的問題，補丁會從隊列中
    丟棄。
  - 在審查周期結束的時候，那些得到ACK回應的補丁將會被加入到最新的穩定版
    發布中，一個新的穩定版發布就此產生。
  - 安全性補丁將從內核安全小組那裡直接接收到穩定版代碼樹中，而不是通過
    通常的審查周期。請聯繫內核安全小組以獲得關於這個過程的更多細節。

審查委員會：
------------
  - 由一些自願承擔這項任務的內核開發者，和幾個非志願的組成。


code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/submit-checklist.rst <submitchecklist>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
             Hu Haowen <src.res@email.cn>

.. _tw_submitchecklist:

Linux內核補丁提交清單
~~~~~~~~~~~~~~~~~~~~~

如果開發人員希望看到他們的內核補丁提交更快地被接受，那麼他們應該做一些基本
的事情。

這些都是在
:ref:`Documentation/translations/zh_TW/process/submitting-patches.rst <tw_submittingpatches>`
和其他有關提交Linux內核補丁的文檔中提供的。

1) 如果使用工具，則包括定義/聲明該工具的文件。不要依賴於其他頭文件拉入您使用
   的頭文件。

2) 乾淨的編譯：

   a) 使用適用或修改的 ``CONFIG`` 選項 ``=y``、``=m`` 和 ``=n`` 。沒有GCC
      警告/錯誤，沒有連結器警告/錯誤。

   b) 通過allnoconfig、allmodconfig

   c) 使用 ``O=builddir`` 時可以成功編譯

3) 通過使用本地交叉編譯工具或其他一些構建場在多個CPU體系結構上構建。

4) PPC64是一種很好的交叉編譯檢查體系結構，因爲它傾向於對64位的數使用無符號
   長整型。

5) 如下所述 :ref:`Documentation/translations/zh_TW/process/coding-style.rst <tw_codingstyle>`.
   檢查您的補丁是否爲常規樣式。在提交（ ``scripts/check patch.pl`` ）之前，
   使用補丁樣式檢查器檢查是否有輕微的衝突。您應該能夠處理您的補丁中存在的所有
   違規行爲。

6) 任何新的或修改過的 ``CONFIG`` 選項都不會弄髒配置菜單，並默認爲關閉，除非
   它們符合 ``Documentation/kbuild/kconfig-language.rst`` 中記錄的異常條件,
   菜單屬性：默認值.

7) 所有新的 ``kconfig`` 選項都有幫助文本。

8) 已仔細審查了相關的 ``Kconfig`` 組合。這很難用測試來糾正——腦力在這裡是有
   回報的。

9) 用 sparse 檢查乾淨。

10) 使用 ``make checkstack`` 和 ``make namespacecheck`` 並修復他們發現的任何
    問題。

    .. note::

        ``checkstack`` 並沒有明確指出問題，但是任何一個在堆棧上使用超過512
        字節的函數都可以進行更改。

11) 包括 :ref:`kernel-doc <kernel_doc>` 內核文檔以記錄全局內核API。（靜態函數
    不需要，但也可以。）使用 ``make htmldocs`` 或 ``make pdfdocs`` 檢查
    :ref:`kernel-doc <kernel_doc>` 並修復任何問題。

12) 通過以下選項同時啓用的測試 ``CONFIG_PREEMPT``, ``CONFIG_DEBUG_PREEMPT``,
    ``CONFIG_DEBUG_SLAB``, ``CONFIG_DEBUG_PAGEALLOC``, ``CONFIG_DEBUG_MUTEXES``,
    ``CONFIG_DEBUG_SPINLOCK``, ``CONFIG_DEBUG_ATOMIC_SLEEP``,
    ``CONFIG_PROVE_RCU`` and ``CONFIG_DEBUG_OBJECTS_RCU_HEAD``

13) 已經過構建和運行時測試，包括有或沒有 ``CONFIG_SMP``, ``CONFIG_PREEMPT``.

14) 如果補丁程序影響IO/磁碟等：使用或不使用 ``CONFIG_LBDAF`` 進行測試。

15) 所有代碼路徑都已在啓用所有lockdep功能的情況下運行。

16) 所有新的/proc條目都記錄在 ``Documentation/``

17) 所有新的內核引導參數都記錄在
    Documentation/admin-guide/kernel-parameters.rst 中。

18) 所有新的模塊參數都記錄在 ``MODULE_PARM_DESC()``

19) 所有新的用戶空間接口都記錄在 ``Documentation/ABI/`` 中。有關詳細信息，
    請參閱 ``Documentation/ABI/README`` 。更改用戶空間接口的補丁應該抄送
    linux-api@vger.kernel.org。

20) 已通過至少注入slab和page分配失敗進行檢查。請參閱 ``Documentation/fault-injection/``
    如果新代碼是實質性的，那麼添加子系統特定的故障注入可能是合適的。

21) 新添加的代碼已經用 ``gcc -W`` 編譯（使用 ``make EXTRA-CFLAGS=-W`` ）。這
    將產生大量噪聲，但對於查找諸如「警告：有符號和無符號之間的比較」之類的錯誤
    很有用。

22) 在它被合併到-mm補丁集中之後進行測試，以確保它仍然與所有其他排隊的補丁以
    及VM、VFS和其他子系統中的各種更改一起工作。

23) 所有內存屏障例如 ``barrier()``, ``rmb()``, ``wmb()`` 都需要原始碼中的注
    釋來解釋它們正在執行的操作及其原因的邏輯。

24) 如果補丁添加了任何ioctl，那麼也要更新 ``Documentation/userspace-api/ioctl/ioctl-number.rst``

25) 如果修改後的原始碼依賴或使用與以下 ``Kconfig`` 符號相關的任何內核API或
    功能，則在禁用相關 ``Kconfig`` 符號和/或 ``=m`` （如果該選項可用）的情況
    下測試以下多個構建[並非所有這些都同時存在，只是它們的各種/隨機組合]：

    ``CONFIG_SMP``, ``CONFIG_SYSFS``, ``CONFIG_PROC_FS``, ``CONFIG_INPUT``, ``CONFIG_PCI``, ``CONFIG_BLOCK``, ``CONFIG_PM``, ``CONFIG_MAGIC_SYSRQ``,
    ``CONFIG_NET``, ``CONFIG_INET=n`` (但是後者伴隨 ``CONFIG_NET=y``).


code:
.. SPDX-License-Identifier: GPL-2.0

.. _tw_submittingpatches:

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`

譯者::

        中文版維護者： 鍾宇 TripleX Chung <xxx.phy@gmail.com>
        中文版翻譯者： 鍾宇 TripleX Chung <xxx.phy@gmail.com>
                       時奎亮 Alex Shi <alex.shi@linux.alibaba.com>
        中文版校譯者： 李陽 Li Yang <leoyang.li@nxp.com>
                       王聰 Wang Cong <xiyou.wangcong@gmail.com>
                       胡皓文 Hu Haowen <src.res@email.cn>

如何讓你的改動進入內核
======================

對於想要將改動提交到 Linux 內核的個人或者公司來說，如果不熟悉「規矩」，
提交的流程會讓人畏懼。本文檔收集了一系列建議，這些建議可以大大的提高你
的改動被接受的機會.

以下文檔含有大量簡潔的建議， 具體請見：
:ref:`Documentation/process <development_process_main>`
同樣，:ref:`Documentation/translations/zh_TW/process/submit-checklist.rst <tw_submitchecklist>`
給出在提交代碼前需要檢查的項目的列表。

其中許多步驟描述了Git版本控制系統的默認行爲；如果您使用Git來準備補丁，
您將發現它爲您完成的大部分機械工作，儘管您仍然需要準備和記錄一組合理的
補丁。一般來說，使用git將使您作爲內核開發人員的生活更輕鬆。

0) 獲取當前源碼樹
-----------------

如果您沒有一個可以使用當前內核原始碼的存儲庫，請使用git獲取一個。您將要
從主線存儲庫開始，它可以通過以下方式獲取::

        git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

但是，請注意，您可能不希望直接針對主線樹進行開發。大多數子系統維護人員運
行自己的樹，並希望看到針對這些樹準備的補丁。請參見MAINTAINERS文件中子系
統的 **T:** 項以查找該樹，或者簡單地詢問維護者該樹是否未在其中列出。

仍然可以通過tarballs下載內核版本（如下一節所述），但這是進行內核開發的
一種困難的方式。

1) "diff -up"
-------------

使用 "diff -up" 或者 "diff -uprN" 來創建補丁。

所有內核的改動，都是以補丁的形式呈現的，補丁由 diff(1) 生成。創建補丁的
時候，要確認它是以 "unified diff" 格式創建的，這種格式由 diff(1) 的 '-u'
參數生成。而且，請使用 '-p' 參數，那樣會顯示每個改動所在的C函數，使得
產生的補丁容易讀得多。補丁應該基於內核原始碼樹的根目錄，而不是裡邊的任
何子目錄。

爲一個單獨的文件創建補丁，一般來說這樣做就夠了::

        SRCTREE=linux
        MYFILE=drivers/net/mydriver.c

        cd $SRCTREE
        cp $MYFILE $MYFILE.orig
        vi $MYFILE      # make your change
        cd ..
        diff -up $SRCTREE/$MYFILE{.orig,} > /tmp/patch

爲多個文件創建補丁，你可以解開一個沒有修改過的內核原始碼樹，然後和你自
己的代碼樹之間做 diff 。例如::

        MYSRC=/devel/linux

        tar xvfz linux-3.19.tar.gz
        mv linux-3.19 linux-3.19-vanilla
        diff -uprN -X linux-3.19-vanilla/Documentation/dontdiff \
                linux-3.19-vanilla $MYSRC > /tmp/patch

"dontdiff" 是內核在編譯的時候產生的文件的列表，列表中的文件在 diff(1)
產生的補丁里會被跳過。

確定你的補丁里沒有包含任何不屬於這次補丁提交的額外文件。記得在用diff(1)
生成補丁之後，審閱一次補丁，以確保準確。

如果你的改動很散亂，你應該研究一下如何將補丁分割成獨立的部分，將改動分
割成一系列合乎邏輯的步驟。這樣更容易讓其他內核開發者審核，如果你想你的
補丁被接受，這是很重要的。請參閱：
:ref:`tw_split_changes`

如果你用 ``git`` , ``git rebase -i`` 可以幫助你這一點。如果你不用 ``git``,
``quilt`` <https://savannah.nongnu.org/projects/quilt> 另外一個流行的選擇。

.. _tw_describe_changes:

2) 描述你的改動
---------------

描述你的問題。無論您的補丁是一行錯誤修復還是5000行新功能，都必須有一個潛在
的問題激勵您完成這項工作。讓審稿人相信有一個問題值得解決，讓他們讀完第一段
是有意義的。

描述用戶可見的影響。直接崩潰和鎖定是相當有說服力的，但並不是所有的錯誤都那麼
明目張胆。即使在代碼審查期間發現了這個問題，也要描述一下您認爲它可能對用戶產
生的影響。請記住，大多數Linux安裝運行的內核來自二級穩定樹或特定於供應商/產品
的樹，只從上游精選特定的補丁，因此請包含任何可以幫助您將更改定位到下游的內容：
觸發的場景、DMESG的摘錄、崩潰描述、性能回歸、延遲尖峯、鎖定等。

量化優化和權衡。如果您聲稱在性能、內存消耗、堆棧占用空間或二進位大小方面有所
改進，請包括支持它們的數字。但也要描述不明顯的成本。優化通常不是免費的，而是
在CPU、內存和可讀性之間進行權衡；或者，探索性的工作，在不同的工作負載之間進
行權衡。請描述優化的預期缺點，以便審閱者可以權衡成本和收益。

一旦問題建立起來，就要詳細地描述一下您實際在做什麼。對於審閱者來說，用簡單的
英語描述代碼的變化是很重要的，以驗證代碼的行爲是否符合您的意願。

如果您將補丁描述寫在一個表單中，這個表單可以很容易地作爲「提交日誌」放入Linux
的原始碼管理系統git中，那麼維護人員將非常感謝您。見 :ref:`tw_explicit_in_reply_to`.

每個補丁只解決一個問題。如果你的描述開始變長，這就表明你可能需要拆分你的補丁。
請見 :ref:`tw_split_changes`

提交或重新提交修補程序或修補程序系列時，請包括完整的修補程序說明和理由。不要
只說這是補丁（系列）的第幾版。不要期望子系統維護人員引用更早的補丁版本或引用
URL來查找補丁描述並將其放入補丁中。也就是說，補丁（系列）及其描述應該是獨立的。
這對維護人員和審查人員都有好處。一些評審者可能甚至沒有收到補丁的早期版本。

描述你在命令語氣中的變化，例如「make xyzzy do frotz」而不是「[這個補丁]make
xyzzy do frotz」或「[我]changed xyzzy to do frotz」，就好像你在命令代碼庫改變
它的行爲一樣。

如果修補程序修復了一個記錄的bug條目，請按編號和URL引用該bug條目。如果補丁來
自郵件列表討論，請給出郵件列表存檔的URL；使用帶有 ``Message-ID`` 的
https://lore.kernel.org/ 重定向，以確保連結不會過時。

但是，在沒有外部資源的情況下，儘量讓你的解釋可理解。除了提供郵件列表存檔或
bug的URL之外，還要總結需要提交補丁的相關討論要點。

如果您想要引用一個特定的提交，不要只引用提交的 SHA-1 ID。還請包括提交的一行
摘要，以便於審閱者了解它是關於什麼的。例如::

        Commit e21d2170f36602ae2708 ("video: remove unnecessary
        platform_set_drvdata()") removed the unnecessary
        platform_set_drvdata(), but left the variable "dev" unused,
        delete it.

您還應該確保至少使用前12位 SHA-1 ID. 內核存儲庫包含*許多*對象，使與較短的ID
發生衝突的可能性很大。記住，即使現在不會與您的六個字符ID發生衝突，這種情況
可能五年後改變。

如果修補程序修復了特定提交中的錯誤，例如，使用 ``git bisct`` ，請使用帶有前
12個字符SHA-1 ID 的"Fixes:"標記和單行摘要。爲了簡化不要將標記拆分爲多個，
行、標記不受分析腳本「75列換行」規則的限制。例如::

        Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed")

下列 ``git config`` 設置可以添加讓 ``git log``, ``git show`` 漂亮的顯示格式::

	[core]
		abbrev = 12
	[pretty]
		fixes = Fixes: %h (\"%s\")

.. _tw_split_changes:

3) 拆分你的改動
---------------

將每個邏輯更改分隔成一個單獨的補丁。

例如，如果你的改動里同時有bug修正和性能優化，那麼把這些改動拆分到兩個或
者更多的補丁文件中。如果你的改動包含對API的修改，並且修改了驅動程序來適
應這些新的API，那麼把這些修改分成兩個補丁。

另一方面，如果你將一個單獨的改動做成多個補丁文件，那麼將它們合併成一個
單獨的補丁文件。這樣一個邏輯上單獨的改動只被包含在一個補丁文件里。

如果有一個補丁依賴另外一個補丁來完成它的改動，那沒問題。簡單的在你的補
丁描述里指出「這個補丁依賴某補丁」就好了。

在將您的更改劃分爲一系列補丁時，要特別注意確保內核在系列中的每個補丁之後
都能正常構建和運行。使用 ``git bisect`` 來追蹤問題的開發者可能會在任何時
候分割你的補丁系列；如果你在中間引入錯誤，他們不會感謝你。

如果你不能將補丁濃縮成更少的文件，那麼每次大約發送出15個，然後等待審查
和集成。

4) 檢查你的更改風格
-------------------

檢查您的補丁是否存在基本樣式衝突，詳細信息可在
:ref:`Documentation/translations/zh_TW/process/coding-style.rst <tw_codingstyle>`
中找到。如果不這樣做，只會浪費審稿人的時間，並且會導致你的補丁被拒絕，甚至
可能沒有被閱讀。

一個重要的例外是在將代碼從一個文件移動到另一個文件時——在這種情況下，您不應
該在移動代碼的同一個補丁中修改移動的代碼。這清楚地描述了移動代碼和您的更改
的行爲。這大大有助於審查實際差異，並允許工具更好地跟蹤代碼本身的歷史。

在提交之前，使用補丁樣式檢查程序檢查補丁（scripts/check patch.pl）。不過，
請注意，樣式檢查程序應該被視爲一個指南，而不是作爲人類判斷的替代品。如果您
的代碼看起來更好，但有違規行爲，那麼最好不要使用它。

檢查者報告三個級別：

 - ERROR：很可能出錯的事情
 - WARNING：需要仔細審查的事項
 - CHECK：需要思考的事情

您應該能夠判斷您的補丁中存在的所有違規行爲。

5) 選擇補丁收件人
-----------------

您應該總是在任何補丁上複製相應的子系統維護人員，以獲得他們維護的代碼；查看
維護人員文件和原始碼修訂歷史記錄，以了解這些維護人員是誰。腳本
scripts/get_Maintainer.pl在這個步驟中非常有用。如果您找不到正在工作的子系統
的維護人員，那麼Andrew Morton（akpm@linux-foundation.org）將充當最後的維護
人員。

您通常還應該選擇至少一個郵件列表來接收補丁集的。linux-kernel@vger.kernel.org
作爲最後一個解決辦法的列表，但是這個列表上的體積已經引起了許多開發人員的拒絕。
在MAINTAINERS文件中查找子系統特定的列表；您的補丁可能會在那裡得到更多的關注。
不過，請不要發送垃圾郵件到無關的列表。

許多與內核相關的列表託管在vger.kernel.org上；您可以在
http://vger.kernel.org/vger-lists.html 上找到它們的列表。不過，也有與內核相關
的列表託管在其他地方。

不要一次發送超過15個補丁到vger郵件列表！！！！

Linus Torvalds 是決定改動能否進入 Linux 內核的最終裁決者。他的 e-mail
地址是 <torvalds@linux-foundation.org> 。他收到的 e-mail 很多，所以一般
的說，最好別給他發 e-mail。

如果您有修復可利用安全漏洞的補丁，請將該補丁發送到 security@kernel.org。對於
嚴重的bug，可以考慮短期暫停以允許分銷商向用戶發布補丁；在這種情況下，顯然不應
將補丁發送到任何公共列表。

修復已發布內核中嚴重錯誤的補丁程序應該指向穩定版維護人員，方法是放這樣的一行::

        Cc: stable@vger.kernel.org

進入補丁的簽准區（注意，不是電子郵件收件人）。除了這個文件之外，您還應該閱讀
:ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`

但是，請注意，一些子系統維護人員希望得出他們自己的結論，即哪些補丁應該被放到
穩定的樹上。尤其是網絡維護人員，不希望看到單個開發人員在補丁中添加像上面這樣
的行。

如果更改影響到用戶和內核接口，請向手冊頁維護人員（如維護人員文件中所列）發送
手冊頁補丁，或至少發送更改通知，以便一些信息進入手冊頁。還應將用戶空間API
更改複製到 linux-api@vger.kernel.org。

6) 沒有 MIME 編碼，沒有連結，沒有壓縮，沒有附件，只有純文本
-----------------------------------------------------------

Linus 和其他的內核開發者需要閱讀和評論你提交的改動。對於內核開發者來說
，可以「引用」你的改動很重要，使用一般的 e-mail 工具，他們就可以在你的
代碼的任何位置添加評論。

因爲這個原因，所有的提交的補丁都是 e-mail 中「內嵌」的。

.. warning::
   如果你使用剪切-粘貼你的補丁，小心你的編輯器的自動換行功能破壞你的補丁

不要將補丁作爲 MIME 編碼的附件，不管是否壓縮。很多流行的 e-mail 軟體不
是任何時候都將 MIME 編碼的附件當作純文本發送的，這會使得別人無法在你的
代碼中加評論。另外，MIME 編碼的附件會讓 Linus 多花一點時間來處理，這就
降低了你的改動被接受的可能性。

例外：如果你的郵遞員弄壞了補丁，那麼有人可能會要求你使用mime重新發送補丁

請參閱 :ref:`Documentation/translations/zh_TW/process/email-clients.rst <tw_email_clients>`
以獲取有關配置電子郵件客戶端以使其不受影響地發送修補程序的提示。

7) e-mail 的大小
----------------

大的改動對郵件列表不合適，對某些維護者也不合適。如果你的補丁，在不壓縮
的情況下，超過了300kB，那麼你最好將補丁放在一個能通過 internet 訪問的服
務器上，然後用指向你的補丁的 URL 替代。但是請注意，如果您的補丁超過了
300kb，那麼它幾乎肯定需要被破壞。

8）回複評審意見
---------------

你的補丁幾乎肯定會得到評審者對補丁改進方法的評論。您必須對這些評論作出
回應；讓補丁被忽略的一個好辦法就是忽略審閱者的意見。不會導致代碼更改的
意見或問題幾乎肯定會帶來注釋或變更日誌的改變，以便下一個評審者更好地了解
正在發生的事情。

一定要告訴審稿人你在做什麼改變，並感謝他們的時間。代碼審查是一個累人且
耗時的過程，審查人員有時會變得暴躁。即使在這種情況下，也要禮貌地回應並
解決他們指出的問題。

9）不要洩氣或不耐煩
-------------------

提交更改後，請耐心等待。審閱者是忙碌的人，可能無法立即訪問您的修補程序。

曾幾何時，補丁曾在沒有評論的情況下消失在空白中，但開發過程比現在更加順利。
您應該在一周左右的時間內收到評論；如果沒有收到評論，請確保您已將補丁發送
到正確的位置。在重新提交或聯繫審閱者之前至少等待一周-在諸如合併窗口之類的
繁忙時間可能更長。

10）主題中包含 PATCH
--------------------

由於到linus和linux內核的電子郵件流量很高，通常會在主題行前面加上[PATCH]
前綴. 這使Linus和其他內核開發人員更容易將補丁與其他電子郵件討論區分開。

11）簽署你的作品-開發者原始認證
-------------------------------

爲了加強對誰做了何事的追蹤，尤其是對那些透過好幾層的維護者的補丁，我們
建議在發送出去的補丁上加一個 「sign-off」 的過程。

"sign-off" 是在補丁的注釋的最後的簡單的一行文字，認證你編寫了它或者其他
人有權力將它作爲開放原始碼的補丁傳遞。規則很簡單：如果你能認證如下信息:

開發者來源證書 1.1
^^^^^^^^^^^^^^^^^^

對於本項目的貢獻，我認證如下信息：

      （a）這些貢獻是完全或者部分的由我創建，我有權利以文件中指出
           的開放原始碼許可證提交它；或者
      （b）這些貢獻基於以前的工作，據我所知，這些以前的工作受恰當的開放
           原始碼許可證保護，而且，根據許可證，我有權提交修改後的貢獻，
           無論是完全還是部分由我創造，這些貢獻都使用同一個開放原始碼許可證
           （除非我被允許用其它的許可證），正如文件中指出的；或者
      （c）這些貢獻由認證（a），（b）或者（c）的人直接提供給我，而
           且我沒有修改它。
      （d）我理解並同意這個項目和貢獻是公開的，貢獻的記錄（包括我
           一起提交的個人記錄，包括 sign-off ）被永久維護並且可以和這個項目
           或者開放原始碼的許可證同步地再發行。

那麼加入這樣一行::

       Signed-off-by: Random J Developer <random@developer.example.org>

使用你的真名（抱歉，不能使用假名或者匿名。）

有人在最後加上標籤。現在這些東西會被忽略，但是你可以這樣做，來標記公司
內部的過程，或者只是指出關於 sign-off 的一些特殊細節。

如果您是子系統或分支維護人員，有時需要稍微修改收到的補丁，以便合併它們，
因爲樹和提交者中的代碼不完全相同。如果你嚴格遵守規則（c），你應該要求提交者
重新發布，但這完全是在浪費時間和精力。規則（b）允許您調整代碼，但是更改一個
提交者的代碼並讓他認可您的錯誤是非常不禮貌的。要解決此問題，建議在最後一個
由簽名行和您的行之間添加一行，指示更改的性質。雖然這並不是強制性的，但似乎
在描述前加上您的郵件和/或姓名（全部用方括號括起來），這足以讓人注意到您對最
後一分鐘的更改負有責任。例如::

	Signed-off-by: Random J Developer <random@developer.example.org>
	[lucky@maintainer.example.org: struct foo moved from foo.c to foo.h]
	Signed-off-by: Lucky K Maintainer <lucky@maintainer.example.org>

如果您維護一個穩定的分支機構，同時希望對作者進行致謝、跟蹤更改、合併修復並
保護提交者不受投訴，那麼這種做法尤其有用。請注意，在任何情況下都不能更改作者
的ID（From 頭），因爲它是出現在更改日誌中的標識。

對回合（back-porters）的特別說明：在提交消息的頂部（主題行之後）插入一個補丁
的起源指示似乎是一種常見且有用的實踐，以便於跟蹤。例如，下面是我們在3.x穩定
版本中看到的內容::

  Date:   Tue Oct 7 07:26:38 2014 -0400

    libata: Un-break ATA blacklist

    commit 1c40279960bcd7d52dbdf1d466b20d24b99176c8 upstream.

還有， 這裡是一個舊版內核中的一個回合補丁::

    Date:   Tue May 13 22:12:27 2008 +0200

        wireless, airo: waitbusy() won't delay

        [backport of 2.6 commit b7acbdfbd1f277c1eb23f344f899cfa4cd0bf36a]

12）何時使用Acked-by:，CC:，和Co-Developed by:
----------------------------------------------

Singed-off-by: 標記表示簽名者參與了補丁的開發，或者他/她在補丁的傳遞路徑中。

如果一個人沒有直接參與補丁的準備或處理，但希望表示並記錄他們對補丁的批准，
那麼他們可以要求在補丁的變更日誌中添加一個 Acked-by:

Acked-by：通常由受影響代碼的維護者使用，當該維護者既沒有貢獻也沒有轉發補丁時。

Acked-by: 不像簽字人那樣正式。這是一個記錄，確認人至少審查了補丁，並表示接受。
因此，補丁合併有時會手動將Acker的「Yep，looks good to me」轉換爲 Acked-By：（但
請注意，通常最好要求一個明確的Ack）。

Acked-by：不一定表示對整個補丁的確認。例如，如果一個補丁影響多個子系統，並且
有一個：來自一個子系統維護者，那麼這通常表示只確認影響維護者代碼的部分。這裡
應該仔細判斷。如有疑問，應參考郵件列表檔案中的原始討論。

如果某人有機會對補丁進行評論，但沒有提供此類評論，您可以選擇在補丁中添加 ``Cc:``
這是唯一一個標籤，它可以在沒有被它命名的人顯式操作的情況下添加，但它應該表明
這個人是在補丁上抄送的。討論中包含了潛在利益相關方。

Co-developed-by: 聲明補丁是由多個開發人員共同創建的；當幾個人在一個補丁上工
作時，它用於將屬性賦予共同作者（除了 From: 所賦予的作者之外）。因爲
Co-developed-by: 表示作者身份，所以每個共同開發人：必須緊跟在相關合作作者的
簽名之後。標準的簽核程序要求：標記的簽核順序應儘可能反映補丁的時間歷史，而不
管作者是通過 From ：還是由 Co-developed-by: 共同開發的。值得注意的是，最後一
個簽字人：必須始終是提交補丁的開發人員。

注意，當作者也是電子郵件標題「發件人：」行中列出的人時，「From: 」 標記是可選的。

作者提交的補丁程序示例::

	<changelog>

	Co-developed-by: First Co-Author <first@coauthor.example.org>
	Signed-off-by: First Co-Author <first@coauthor.example.org>
	Co-developed-by: Second Co-Author <second@coauthor.example.org>
	Signed-off-by: Second Co-Author <second@coauthor.example.org>
	Signed-off-by: From Author <from@author.example.org>

合作開發者提交的補丁示例::

	From: From Author <from@author.example.org>

	<changelog>

	Co-developed-by: Random Co-Author <random@coauthor.example.org>
	Signed-off-by: Random Co-Author <random@coauthor.example.org>
	Signed-off-by: From Author <from@author.example.org>
	Co-developed-by: Submitting Co-Author <sub@coauthor.example.org>
	Signed-off-by: Submitting Co-Author <sub@coauthor.example.org>

13）使用報告人：、測試人：、審核人：、建議人：、修復人：
--------------------------------------------------------

Reported-by: 給那些發現錯誤並報告錯誤的人致謝，它希望激勵他們在將來再次幫助
我們。請注意，如果bug是以私有方式報告的，那麼在使用Reported-by標記之前，請
先請求權限。

Tested-by: 標記表示補丁已由指定的人（在某些環境中）成功測試。這個標籤通知
維護人員已經執行了一些測試，爲將來的補丁提供了一種定位測試人員的方法，並確
保測試人員的信譽。

Reviewed-by：相反，根據審查人的聲明，表明該補丁已被審查並被認爲是可接受的：

審查人的監督聲明
^^^^^^^^^^^^^^^^

通過提供我的 Reviewed-by，我聲明：

        (a) 我已經對這個補丁進行了一次技術審查，以評估它是否適合被包含到
            主線內核中。

        (b) 與補丁相關的任何問題、顧慮或問題都已反饋給提交者。我對提交者對
            我的評論的回應感到滿意。

        (c) 雖然這一提交可能會改進一些東西，但我相信，此時，（1）對內核
            進行了有價值的修改，（2）沒有包含爭論中涉及的已知問題。

        (d) 雖然我已經審查了補丁並認爲它是健全的，但我不會（除非另有明確
            說明）作出任何保證或保證它將在任何給定情況下實現其規定的目的
            或正常運行。

Reviewed-by 是一種觀點聲明，即補丁是對內核的適當修改，沒有任何遺留的嚴重技術
問題。任何感興趣的審閱者（完成工作的人）都可以爲一個補丁提供一個 Review-by
標籤。此標籤用於向審閱者提供致謝，並通知維護者已在修補程序上完成的審閱程度。
Reviewed-by: 當由已知了解主題區域並執行徹底檢查的審閱者提供時，通常會增加
補丁進入內核的可能性。

Suggested-by: 表示補丁的想法是由指定的人提出的，並確保將此想法歸功於指定的
人。請注意，未經許可，不得添加此標籤，特別是如果該想法未在公共論壇上發布。
這就是說，如果我們勤快地致謝我們的創意者，他們很有希望在未來得到鼓舞，再次
幫助我們。

Fixes: 指示補丁在以前的提交中修復了一個問題。它可以很容易地確定錯誤的來源，
這有助於檢查錯誤修復。這個標記還幫助穩定內核團隊確定應該接收修復的穩定內核
版本。這是指示補丁修復的錯誤的首選方法。請參閱 :ref:`tw_describe_changes`
描述您的更改以了解更多詳細信息。

.. _tw_the_canonical_patch_format:

12）標準補丁格式
----------------

本節描述如何格式化補丁本身。請注意，如果您的補丁存儲在 ``Git`` 存儲庫中，則
可以使用 ``git format-patch`` 進行正確的補丁格式設置。但是，這些工具無法創建
必要的文本，因此請務必閱讀下面的說明。

標準的補丁，標題行是::

    Subject: [PATCH 001/123] 子系統:一句話概述

標準補丁的信體存在如下部分：

  - 一個 "from" 行指出補丁作者。後跟空行（僅當發送修補程序的人不是作者時才需要）。

  - 解釋的正文，行以75列包裝，這將被複製到永久變更日誌來描述這個補丁。

  - 一個空行

  - 上面描述的「Signed-off-by」 行，也將出現在更改日誌中。

  - 只包含 ``---`` 的標記線。

  - 任何其他不適合放在變更日誌的注釋。

  - 實際補丁（ ``diff`` 輸出）。

標題行的格式，使得對標題行按字母序排序非常的容易 - 很多 e-mail 客戶端都
可以支持 - 因爲序列號是用零填充的，所以按數字排序和按字母排序是一樣的。

e-mail 標題中的「子系統」標識哪個內核子系統將被打補丁。

e-mail 標題中的「一句話概述」扼要的描述 e-mail 中的補丁。「一句話概述」
不應該是一個文件名。對於一個補丁系列（「補丁系列」指一系列的多個相關補
丁），不要對每個補丁都使用同樣的「一句話概述」。

記住 e-mail 的「一句話概述」會成爲該補丁的全局唯一標識。它會蔓延到 git
的改動記錄里。然後「一句話概述」會被用在開發者的討論里，用來指代這個補
丁。用戶將希望通過 google 來搜索"一句話概述"來找到那些討論這個補丁的文
章。當人們在兩三個月後使用諸如 ``gitk`` 或 ``git log --oneline`` 之類
的工具查看數千個補丁時，也會很快看到它。

出於這些原因，概述必須不超過70-75個字符，並且必須描述補丁的更改以及爲
什麼需要補丁。既要簡潔又要描述性很有挑戰性，但寫得好的概述應該這樣做。

概述的前綴可以用方括號括起來：「Subject: [PATCH <tag>...] <概述>」。標記
不被視爲概述的一部分，而是描述應該如何處理補丁。如果補丁的多個版本已發
送出來以響應評審（即「v1，v2，v3」）或「rfc」，以指示評審請求，那麼通用標記
可能包括版本描述符。如果一個補丁系列中有四個補丁，那麼各個補丁可以這樣
編號：1/4、2/4、3/4、4/4。這可以確保開發人員了解補丁應用的順序，並且他們
已經查看或應用了補丁系列中的所有補丁。

一些標題的例子::

    Subject: [patch 2/5] ext2: improve scalability of bitmap searching
    Subject: [PATCHv2 001/207] x86: fix eflags tracking

"From" 行是信體裡的最上面一行，具有如下格式：
        From: Patch Author <author@example.com>

"From" 行指明在永久改動日誌里，誰會被確認爲作者。如果沒有 "From" 行，那
麼郵件頭裡的 "From: " 行會被用來決定改動日誌中的作者。

說明的主題將會被提交到永久的原始碼改動日誌里，因此對那些早已經不記得和
這個補丁相關的討論細節的有能力的讀者來說，是有意義的。包括補丁程序定位
錯誤的（內核日誌消息、OOPS消息等）症狀，對於搜索提交日誌以尋找適用補丁的人
尤其有用。如果一個補丁修復了一個編譯失敗，那麼可能不需要包含所有編譯失敗；
只要足夠讓搜索補丁的人能夠找到它就行了。與概述一樣，既要簡潔又要描述性。

"---" 標記行對於補丁處理工具要找到哪裡是改動日誌信息的結束，是不可缺少
的。

對於 "---" 標記之後的額外註解，一個好的用途就是用來寫 diffstat，用來顯
示修改了什麼文件和每個文件都增加和刪除了多少行。diffstat 對於比較大的補
丁特別有用。其餘那些只是和時刻或者開發者相關的註解，不合適放到永久的改
動日誌里的，也應該放這裡。
使用 diffstat的選項 "-p 1 -w 70" 這樣文件名就會從內核原始碼樹的目錄開始
，不會占用太寬的空間（很容易適合80列的寬度，也許會有一些縮進。）

在後面的參考資料中能看到適當的補丁格式的更多細節。

.. _tw_explicit_in_reply_to:

15) 明確回覆郵件頭(In-Reply-To)
-------------------------------

手動添加回復補丁的的標題頭(In-Reply_To:) 是有幫助的（例如，使用 ``git send-email`` ）
將補丁與以前的相關討論關聯起來，例如，將bug修復程序連結到電子郵件和bug報告。
但是，對於多補丁系列，最好避免在回復時使用連結到該系列的舊版本。這樣，
補丁的多個版本就不會成爲電子郵件客戶端中無法管理的引用序列。如果連結有用，
可以使用 https://lore.kernel.org/ 重定向器（例如，在封面電子郵件文本中）
連結到補丁系列的早期版本。

16) 發送git pull請求
--------------------

如果您有一系列補丁，那麼讓維護人員通過git pull操作將它們直接拉入子系統存儲
庫可能是最方便的。但是，請注意，從開發人員那裡獲取補丁比從郵件列表中獲取補
丁需要更高的信任度。因此，許多子系統維護人員不願意接受請求，特別是來自新的
未知開發人員的請求。如果有疑問，您可以在封面郵件中使用pull 請求作爲補丁系列
正常發布的一個選項，讓維護人員可以選擇使用其中之一。

pull 請求的主題行中應該有[Git Pull]。請求本身應該在一行中包含存儲庫名稱和
感興趣的分支；它應該看起來像::

  Please pull from

      git://jdelvare.pck.nerim.net/jdelvare-2.6 i2c-for-linus

  to get these changes:

pull 請求還應該包含一條整體消息，說明請求中將包含什麼，一個補丁本身的 ``Git shortlog``
以及一個顯示補丁系列整體效果的 ``diffstat`` 。當然，將所有這些信息收集在一起
的最簡單方法是讓 ``git`` 使用 ``git request-pull`` 命令爲您完成這些工作。

一些維護人員（包括Linus）希望看到來自已簽名提交的請求；這增加了他們對你的
請求信心。特別是，在沒有簽名標籤的情況下，Linus 不會從像 Github 這樣的公共
託管站點拉請求。

創建此類簽名的第一步是生成一個 GNRPG 密鑰，並由一個或多個核心內核開發人員對
其進行簽名。這一步對新開發人員來說可能很困難，但沒有辦法繞過它。參加會議是
找到可以簽署您的密鑰的開發人員的好方法。

一旦您在Git 中準備了一個您希望有人拉的補丁系列，就用 ``git tag -s`` 創建一
個簽名標記。這將創建一個新標記，標識該系列中的最後一次提交，並包含用您的私
鑰創建的簽名。您還可以將changelog樣式的消息添加到標記中；這是一個描述拉請求
整體效果的理想位置。

如果維護人員將要從中提取的樹不是您正在使用的存儲庫，請不要忘記將已簽名的標記
顯式推送到公共樹。

生成拉請求時，請使用已簽名的標記作爲目標。這樣的命令可以實現::

  git request-pull master git://my.public.tree/linux.git my-signed-tag

參考文獻
--------

Andrew Morton, "The perfect patch" (tpp).
  <https://www.ozlabs.org/~akpm/stuff/tpp.txt>

Jeff Garzik, "Linux kernel patch submission format".
  <https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html>

Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
  <http://www.kroah.com/log/linux/maintainer.html>

  <http://www.kroah.com/log/linux/maintainer-02.html>

  <http://www.kroah.com/log/linux/maintainer-03.html>

  <http://www.kroah.com/log/linux/maintainer-04.html>

  <http://www.kroah.com/log/linux/maintainer-05.html>

  <http://www.kroah.com/log/linux/maintainer-06.html>

NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
  <https://lore.kernel.org/r/20050711.125305.08322243.davem@davemloft.net>

Kernel Documentation/process/coding-style.rst:
  :ref:`Documentation/translations/zh_TW/process/coding-style.rst <tw_codingstyle>`

Linus Torvalds's mail on the canonical patch format:
  <https://lore.kernel.org/r/Pine.LNX.4.58.0504071023190.28951@ppc970.osdl.org>

Andi Kleen, "On submitting kernel patches"
  Some strategies to get difficult or controversial changes in.

  http://halobates.de/on-submitting-patches.pdf


code:
.. SPDX-License-Identifier: GPL-2.0

.. _tw_volatile_considered_harmful:

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/volatile-considered-harmful.rst
           <volatile_considered_harmful>`

如果想評論或更新本文的內容，請直接聯繫原文檔的維護者。如果你使用英文
交流有困難的話，也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
譯存在問題，請聯繫中文版維護者::

        英文版維護者： Jonathan Corbet <corbet@lwn.net>
        中文版維護者： 伍鵬  Bryan Wu <bryan.wu@analog.com>
        中文版翻譯者： 伍鵬  Bryan Wu <bryan.wu@analog.com>
        中文版校譯者： 張漢輝  Eugene Teo <eugeneteo@kernel.sg>
                       楊瑞  Dave Young <hidave.darkstar@gmail.com>
                       時奎亮 Alex Shi <alex.shi@linux.alibaba.com>
                       胡皓文 Hu Haowen <src.res@email.cn>

爲什麼不應該使用「volatile」類型
================================

C程式設計師通常認爲volatile表示某個變量可以在當前執行的線程之外被改變；因此，在內核
中用到共享數據結構時，常常會有C程式設計師喜歡使用volatile這類變量。換句話說，他們經
常會把volatile類型看成某種簡易的原子變量，當然它們不是。在內核中使用volatile幾
乎總是錯誤的；本文檔將解釋爲什麼這樣。

理解volatile的關鍵是知道它的目的是用來消除優化，實際上很少有人真正需要這樣的應
用。在內核中，程式設計師必須防止意外的並發訪問破壞共享的數據結構，這其實是一個完全
不同的任務。用來防止意外並發訪問的保護措施，可以更加高效的避免大多數優化相關的
問題。

像volatile一樣，內核提供了很多原語來保證並發訪問時的數據安全（自旋鎖, 互斥量,內
存屏障等等），同樣可以防止意外的優化。如果可以正確使用這些內核原語，那麼就沒有
必要再使用volatile。如果仍然必須使用volatile，那麼幾乎可以肯定在代碼的某處有一
個bug。在正確設計的內核代碼中，volatile能帶來的僅僅是使事情變慢。

思考一下這段典型的內核代碼::

    spin_lock(&the_lock);
    do_something_on(&shared_data);
    do_something_else_with(&shared_data);
    spin_unlock(&the_lock);

如果所有的代碼都遵循加鎖規則，當持有the_lock的時候，不可能意外的改變shared_data的
值。任何可能訪問該數據的其他代碼都會在這個鎖上等待。自旋鎖原語跟內存屏障一樣—— 它
們顯式的用來書寫成這樣 —— 意味著數據訪問不會跨越它們而被優化。所以本來編譯器認爲
它知道在shared_data裡面將有什麼，但是因爲spin_lock()調用跟內存屏障一樣，會強制編
譯器忘記它所知道的一切。那麼在訪問這些數據時不會有優化的問題。

如果shared_data被聲名爲volatile，鎖操作將仍然是必須的。就算我們知道沒有其他人正在
使用它，編譯器也將被阻止優化對臨界區內shared_data的訪問。在鎖有效的同時，
shared_data不是volatile的。在處理共享數據的時候，適當的鎖操作可以不再需要
volatile —— 並且是有潛在危害的。

volatile的存儲類型最初是爲那些內存映射的I/O寄存器而定義。在內核里，寄存器訪問也應
該被鎖保護，但是人們也不希望編譯器「優化」臨界區內的寄存器訪問。內核里I/O的內存訪問
是通過訪問函數完成的；不贊成通過指針對I/O內存的直接訪問，並且不是在所有體系架構上
都能工作。那些訪問函數正是爲了防止意外優化而寫的，因此，再說一次，volatile類型不
是必需的。

另一種引起用戶可能使用volatile的情況是當處理器正忙著等待一個變量的值。正確執行一
個忙等待的方法是::

    while (my_variable != what_i_want)
        cpu_relax();

cpu_relax()調用會降低CPU的能量消耗或者讓位於超線程雙處理器；它也作爲內存屏障一樣出
現，所以，再一次，volatile不是必需的。當然，忙等待一開始就是一種反常規的做法。

在內核中，一些稀少的情況下volatile仍然是有意義的：

  - 在一些體系架構的系統上，允許直接的I/0內存訪問，那麼前面提到的訪問函數可以使用
    volatile。基本上，每一個訪問函數調用它自己都是一個小的臨界區域並且保證了按照
    程式設計師期望的那樣發生訪問操作。

  - 某些會改變內存的內聯彙編代碼雖然沒有什麼其他明顯的附作用，但是有被GCC刪除的可
    能性。在彙編聲明中加上volatile關鍵字可以防止這種刪除操作。

  - Jiffies變量是一種特殊情況，雖然每次引用它的時候都可以有不同的值，但讀jiffies
    變量時不需要任何特殊的加鎖保護。所以jiffies變量可以使用volatile，但是不贊成
    其他跟jiffies相同類型變量使用volatile。Jiffies被認爲是一種「愚蠢的遺留物"
    （Linus的話）因爲解決這個問題比保持現狀要麻煩的多。

  - 由於某些I/0設備可能會修改連續一致的內存,所以有時,指向連續一致內存的數據結構
    的指針需要正確的使用volatile。網絡適配器使用的環狀緩存區正是這類情形的一個例
    子，其中適配器用改變指針來表示哪些描述符已經處理過了。

對於大多代碼，上述幾種可以使用volatile的情況都不適用。所以，使用volatile是一種
bug並且需要對這樣的代碼額外仔細檢查。那些試圖使用volatile的開發人員需要退一步想想
他們真正想實現的是什麼。

非常歡迎刪除volatile變量的補丁 － 只要證明這些補丁完整的考慮了並發問題。

注釋
----

[1] https://lwn.net/Articles/233481/
[2] https://lwn.net/Articles/233482/

致謝
----

最初由Randy Dunlap推動並作初步研究
由Jonathan Corbet撰寫
參考Satyam Sharma，Johannes Stezenbach，Jesper Juhl，Heikki Orsila，
H. Peter Anvin，Philipp Hahn和Stefan Richter的意見改善了本檔。


code:
Chinese translated version of Documentation/dev-tools/sparse.rst

If you have any comment or update to the content, please contact the
original document maintainer directly.  However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help.  Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.

Traditional Chinese maintainer: Hu Haowen <src.res@email.cn>
---------------------------------------------------------------------
Documentation/dev-tools/sparse.rst 的繁體中文翻譯

如果想評論或更新本文的內容，請直接聯繫原文檔的維護者。如果你使用英文
交流有困難的話，也可以向繁體中文版維護者求助。如果本翻譯更新不及時或
者翻譯存在問題，請聯繫繁體中文版維護者。

繁體中文版維護者： 胡皓文 Hu Haowen <src.res@email.cn>
繁體中文版翻譯者： 胡皓文 Hu Haowen <src.res@email.cn>

以下爲正文
---------------------------------------------------------------------

Copyright 2004 Linus Torvalds
Copyright 2004 Pavel Machek <pavel@ucw.cz>
Copyright 2006 Bob Copeland <me@bobcopeland.com>

使用 sparse 工具做類型檢查
~~~~~~~~~~~~~~~~~~~~~~~~~~

"__bitwise" 是一種類型屬性，所以你應該這樣使用它：

        typedef int __bitwise pm_request_t;

        enum pm_request {
                PM_SUSPEND = (__force pm_request_t) 1,
                PM_RESUME = (__force pm_request_t) 2
        };

這樣會使 PM_SUSPEND 和 PM_RESUME 成爲位方式(bitwise)整數（使用"__force"
是因爲 sparse 會抱怨改變位方式的類型轉換，但是這裡我們確實需要強制進行轉
換）。而且因爲所有枚舉值都使用了相同的類型，這裡的"enum pm_request"也將
會使用那個類型做爲底層實現。

而且使用 gcc 編譯的時候，所有的 __bitwise/__force 都會消失，最後在 gcc
看來它們只不過是普通的整數。

坦白來說，你並不需要使用枚舉類型。上面那些實際都可以濃縮成一個特殊的"int
__bitwise"類型。

所以更簡單的辦法只要這樣做：

	typedef int __bitwise pm_request_t;

	#define PM_SUSPEND ((__force pm_request_t) 1)
	#define PM_RESUME ((__force pm_request_t) 2)

現在你就有了嚴格的類型檢查所需要的所有基礎架構。

一個小提醒：常數整數"0"是特殊的。你可以直接把常數零當作位方式整數使用而
不用擔心 sparse 會抱怨。這是因爲"bitwise"（恰如其名）是用來確保不同位方
式類型不會被弄混（小尾模式，大尾模式，cpu尾模式，或者其他），對他們來說
常數"0"確實是特殊的。

獲取 sparse 工具
~~~~~~~~~~~~~~~~

你可以從 Sparse 的主頁獲取最新的發布版本：

	http://www.kernel.org/pub/linux/kernel/people/josh/sparse/

或者，你也可以使用 git 克隆最新的 sparse 開發版本：

	git://git.kernel.org/pub/scm/linux/kernel/git/josh/sparse.git

一旦你下載了源碼，只要以普通用戶身份運行：

	make
	make install

它將會被自動安裝到你的 ~/bin 目錄下。

使用 sparse 工具
~~~~~~~~~~~~~~~~

用"make C=1"命令來編譯內核，會對所有重新編譯的 C 文件使用 sparse 工具。
或者使用"make C=2"命令，無論文件是否被重新編譯都會對其使用 sparse 工具。
如果你已經編譯了內核，用後一種方式可以很快地檢查整個源碼樹。

make 的可選變量 CHECKFLAGS 可以用來向 sparse 工具傳遞參數。編譯系統會自
動向 sparse 工具傳遞 -Wbitwise 參數。


code:
Credits for the Simple Linux USB Driver:

The following people have contributed to this code (in alphabetical
order by last name).  I'm sure this list should be longer, it's
difficult to maintain, add yourself with a patch if desired.

  Georg Acher <acher@informatik.tu-muenchen.de>
  David Brownell <dbrownell@users.sourceforge.net>
  Alan Cox <alan@lxorguk.ukuu.org.uk>
  Randy Dunlap <randy.dunlap@intel.com>
  Johannes Erdfelt <johannes@erdfelt.com>
  Deti Fliegl <deti@fliegl.de>
  ham <ham@unsuave.com>
  Bradley M Keryan <keryan@andrew.cmu.edu>
  Greg Kroah-Hartman <greg@kroah.com>
  Pavel Machek <pavel@suse.cz>
  Paul Mackerras <paulus@cs.anu.edu.au>
  Petko Manlolov <petkan@dce.bg>
  David E. Nelson <dnelson@jump.net>
  Vojtech Pavlik <vojtech@suse.cz>
  Bill Ryder <bryder@sgi.com>
  Thomas Sailer <sailer@ife.ee.ethz.ch>
  Gregory P. Smith <greg@electricrain.com>
  Linus Torvalds <torvalds@linux-foundation.org>
  Roman Weissgaerber <weissg@vienna.at>
  <Kazuki.Yasumatsu@fujixerox.co.jp>

Special thanks to:

  Inaky Perez Gonzalez <inaky@peloncho.fis.ucm.es> for starting the
  Linux USB driver effort and writing much of the larger uusbd driver.
  Much has been learned from that effort.

  The NetBSD & FreeBSD USB developers.  For being on the Linux USB list
  and offering suggestions and sharing implementation experiences.

Additional thanks to the following companies and people for donations
of hardware, support, time and development (this is from the original
THANKS file in Inaky's driver):

        The following corporations have helped us in the development
        of Linux USB / UUSBD:

	- 3Com GmbH for donating a ISDN Pro TA and supporting me
	  in technical questions and with test equipment. I'd never
	  expect such a great help.

        - USAR Systems provided us with one of their excellent USB
          Evaluation Kits. It allows us to test the Linux-USB driver
          for compliance with the latest USB specification. USAR
          Systems recognized the importance of an up-to-date open
          Operating System and supports this project with
          Hardware. Thanks!.

        - Thanks to Intel Corporation for their precious help.

        - We teamed up with Cherry to make Linux the first OS with
          built-in USB support. Cherry is one of the biggest keyboard
          makers in the world.

        - CMD Technology, Inc. sponsored us kindly donating a CSA-6700
          PCI-to-USB Controller Board to test the OHCI implementation.

        - Due to their support to us, Keytronic can be sure that they
          will sell keyboards to some of the 3 million (at least)
          Linux users.

        - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
          It was almost impossible to get a PC backplate USB connector
          for the motherboard here at Europe (mine, home-made, was
          quite lousy :). Now I know where to acquire nice USB stuff!

        - Genius Germany donated a USB mouse to test the mouse boot
          protocol. They've also donated a F-23 digital joystick and a
          NetMouse Pro. Thanks!

        - AVM GmbH Berlin is supporting the development of the Linux
          USB driver for the AVM ISDN Controller B1 USB. AVM is a
          leading manufacturer for active and passive ISDN Controllers
          and CAPI 2.0-based software. The active design of the AVM B1
          is open for all OS platforms, including Linux.

        - Thanks to Y-E Data, Inc. for donating their FlashBuster-U
          USB Floppy Disk Drive, so we could test the bulk transfer
          code.

        - Many thanks to Logitech for contributing a three axis USB
          mouse.

          Logitech designs, manufactures and markets
          Human Interface Devices, having a long history and
          experience in making devices such as keyboards, mice,
          trackballs, cameras, loudspeakers and control devices for
          gaming and professional use.

          Being a recognized vendor and seller for all these devices,
          they have donated USB mice, a joystick and a scanner, as a
          way to acknowledge the importance of Linux and to allow
          Logitech customers to enjoy support in their favorite
          operating systems and all Linux users to use Logitech and
          other USB hardware.

          Logitech is official sponsor of the Linux Conference on
          Feb. 11th 1999 in Vienna, where we'll will present the
          current state of the Linux USB effort.

        - CATC has provided means to uncover dark corners of the UHCI
          inner workings with a USB Inspector.

        - Thanks to Entrega for providing PCI to USB cards, hubs and
          converter products for development.

	- Thanks to ConnectTech for providing a WhiteHEAT usb to
	  serial converter, and the documentation for the device to
	  allow a driver to be written.

	- Thanks to ADMtek for providing Pegasus and Pegasus II
	  evaluation boards, specs and valuable advices during
	  the driver development.

        And thanks go to (hey! in no particular order :)

        - Oren Tirosh <orenti@hishome.net>, for standing so patiently
          all my doubts'bout USB and giving lots of cool ideas.

        - Jochen Karrer <karrer@wpfd25.physik.uni-wuerzburg.de>, for
          pointing out mortal bugs and giving advice.

        - Edmund Humemberger <ed@atnet.at>, for his great work on
          public relationships and general management stuff for the
          Linux-USB effort.

        - Alberto Menegazzi <flash@flash.iol.it> is starting the
          documentation for the UUSBD. Go for it!

        - Ric Klaren <ia_ric@cs.utwente.nl> for doing nice
          introductory documents (competing with Alberto's :).

        - Christian Groessler <cpg@aladdin.de>, for his help on those
          itchy bits ... :)

        - Paul MacKerras for polishing OHCI and pushing me harder for
          the iMac support, giving improvements and enhancements.

        - Fernando Herrera <fherrera@eurielec.etsit.upm.es> has taken
          charge of composing, maintaining and feeding the
          long-awaited, unique and marvelous UUSBD FAQ! Tadaaaa!!!

        - Rasca Gmelch <thron@gmx.de> has revived the raw driver and
          pointed bugs, as well as started the uusbd-utils package.

        - Peter Dettori <dettori@ozy.dec.com> is uncovering bugs like
          crazy, as well as making cool suggestions, great :)

        - All the Free Software and Linux community, the FSF & the GNU
          project, the MIT X consortium, the TeX people ... everyone!
          You know who you are!

        - Big thanks to Richard Stallman for creating Emacs!

        - The people at the linux-usb mailing list, for reading so
          many messages :) Ok, no more kidding; for all your advises!

        - All the people at the USB Implementors Forum for their
          help and assistance.

        - Nathan Myers <ncm@cantrip.org>, for his advice! (hope you
          liked Cibeles' party).

        - Linus Torvalds, for starting, developing and managing Linux.

        - Mike Smith, Craig Keithley, Thierry Giron and Janet Schank
          for convincing me USB Standard hubs are not that standard
          and that's good to allow for vendor specific quirks on the
          standard hub driver.

path: Documentation/usb/CREDITS


code:
======================
Linux ACM driver v0.16
======================

Copyright (c) 1999 Vojtech Pavlik <vojtech@suse.cz>

Sponsored by SuSE

0. Disclaimer
~~~~~~~~~~~~~
This program 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

Should you need to contact me, the author, you can do so either by e-mail -
mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
Ucitelska 1576, Prague 8, 182 00 Czech Republic

For your convenience, the GNU General Public License version 2 is included
in the package: See the file COPYING.

1. Usage
~~~~~~~~
The drivers/usb/class/cdc-acm.c drivers works with USB modems and USB ISDN terminal
adapters that conform to the Universal Serial Bus Communication Device Class
Abstract Control Model (USB CDC ACM) specification.

Many modems do, here is a list of those I know of:

	- 3Com OfficeConnect 56k
	- 3Com Voice FaxModem Pro
	- 3Com Sportster
	- MultiTech MultiModem 56k
	- Zoom 2986L FaxModem
	- Compaq 56k FaxModem
	- ELSA Microlink 56k

I know of one ISDN TA that does work with the acm driver:

	- 3Com USR ISDN Pro TA

Some cell phones also connect via USB. I know the following phones work:

	- SonyEricsson K800i

Unfortunately many modems and most ISDN TAs use proprietary interfaces and
thus won't work with this drivers. Check for ACM compliance before buying.

To use the modems you need these modules loaded::

	usbcore.ko
	uhci-hcd.ko ohci-hcd.ko or ehci-hcd.ko
	cdc-acm.ko

After that, the modem[s] should be accessible. You should be able to use
minicom, ppp and mgetty with them.

2. Verifying that it works
~~~~~~~~~~~~~~~~~~~~~~~~~~

The first step would be to check /sys/kernel/debug/usb/devices, it should look
like this::

  T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2
  B:  Alloc=  0/900 us ( 0%), #Int=  0, #Iso=  0
  D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
  P:  Vendor=0000 ProdID=0000 Rev= 0.00
  S:  Product=USB UHCI Root Hub
  S:  SerialNumber=6800
  C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=  0mA
  I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
  E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl=255ms
  T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
  D:  Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs=  2
  P:  Vendor=04c1 ProdID=008f Rev= 2.07
  S:  Manufacturer=3Com Inc.
  S:  Product=3Com U.S. Robotics Pro ISDN TA
  S:  SerialNumber=UFT53A49BVT7
  C:  #Ifs= 1 Cfg#= 1 Atr=60 MxPwr=  0mA
  I:  If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=acm
  E:  Ad=85(I) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
  E:  Ad=04(O) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
  E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=128ms
  C:* #Ifs= 2 Cfg#= 2 Atr=60 MxPwr=  0mA
  I:  If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm
  E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=128ms
  I:  If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm
  E:  Ad=85(I) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
  E:  Ad=04(O) Atr=02(Bulk) MxPS=  64 Ivl=  0ms

The presence of these three lines (and the Cls= 'comm' and 'data' classes)
is important, it means it's an ACM device. The Driver=acm means the acm
driver is used for the device. If you see only Cls=ff(vend.) then you're out
of luck, you have a device with vendor specific-interface::

  D:  Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs=  2
  I:  If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm
  I:  If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm

In the system log you should see::

  usb.c: USB new device connect, assigned device number 2
  usb.c: kmalloc IF c7691fa0, numif 1
  usb.c: kmalloc IF c7b5f3e0, numif 2
  usb.c: skipped 4 class/vendor specific interface descriptors
  usb.c: new device strings: Mfr=1, Product=2, SerialNumber=3
  usb.c: USB device number 2 default language ID 0x409
  Manufacturer: 3Com Inc.
  Product: 3Com U.S. Robotics Pro ISDN TA
  SerialNumber: UFT53A49BVT7
  acm.c: probing config 1
  acm.c: probing config 2
  ttyACM0: USB ACM device
  acm.c: acm_control_msg: rq: 0x22 val: 0x0 len: 0x0 result: 0
  acm.c: acm_control_msg: rq: 0x20 val: 0x0 len: 0x7 result: 7
  usb.c: acm driver claimed interface c7b5f3e0
  usb.c: acm driver claimed interface c7b5f3f8
  usb.c: acm driver claimed interface c7691fa0

If all this seems to be OK, fire up minicom and set it to talk to the ttyACM
device and try typing 'at'. If it responds with 'OK', then everything is
working.


code:
==============================================================
Authorizing (or not) your USB devices to connect to the system
==============================================================

Copyright (C) 2007 Inaky Perez-Gonzalez <inaky@linux.intel.com> Intel Corporation

This feature allows you to control if a USB device can be used (or
not) in a system. This feature will allow you to implement a lock-down
of USB devices, fully controlled by user space.

As of now, when a USB device is connected it is configured and
its interfaces are immediately made available to the users.  With this
modification, only if root authorizes the device to be configured will
then it be possible to use it.

Usage
=====

Authorize a device to connect::

	$ echo 1 > /sys/bus/usb/devices/DEVICE/authorized

De-authorize a device::

	$ echo 0 > /sys/bus/usb/devices/DEVICE/authorized

Set new devices connected to hostX to be deauthorized by default (ie:
lock down)::

	$ echo 0 > /sys/bus/usb/devices/usbX/authorized_default

Remove the lock down::

	$ echo 1 > /sys/bus/usb/devices/usbX/authorized_default

By default, Wired USB devices are authorized by default to
connect. Wireless USB hosts deauthorize by default all new connected
devices (this is so because we need to do an authentication phase
before authorizing). Writing "2" to the authorized_default attribute
causes kernel to only authorize by default devices connected to internal
USB ports.

Example system lockdown (lame)
------------------------------

Imagine you want to implement a lockdown so only devices of type XYZ
can be connected (for example, it is a kiosk machine with a visible
USB port)::

  boot up
  rc.local ->

   for host in /sys/bus/usb/devices/usb*
   do
      echo 0 > $host/authorized_default
   done

Hookup an script to udev, for new USB devices::

 if device_is_my_type $DEV
 then
   echo 1 > $device_path/authorized
 done

Now, device_is_my_type() is where the juice for a lockdown is. Just
checking if the class, type and protocol match something is the worse
security verification you can make (or the best, for someone willing
to break it). If you need something secure, use crypto and Certificate
Authentication or stuff like that. Something simple for an storage key
could be::

 function device_is_my_type()
 {
   echo 1 > authorized		# temporarily authorize it
                                # FIXME: make sure none can mount it
   mount DEVICENODE /mntpoint
   sum=$(md5sum /mntpoint/.signature)
   if [ $sum = $(cat /etc/lockdown/keysum) ]
   then
        echo "We are good, connected"
        umount /mntpoint
        # Other stuff so others can use it
   else
        echo 0 > authorized
   fi
 }

Of course, this is lame, you'd want to do a real certificate
verification stuff with PKI, so you don't depend on a shared secret,
etc, but you get the idea. Anybody with access to a device gadget kit
can fake descriptors and device info. Don't trust that. You are
welcome.

Interface authorization
-----------------------

There is a similar approach to allow or deny specific USB interfaces.
That allows to block only a subset of an USB device.

Authorize an interface::

	$ echo 1 > /sys/bus/usb/devices/INTERFACE/authorized

Deauthorize an interface::

	$ echo 0 > /sys/bus/usb/devices/INTERFACE/authorized

The default value for new interfaces
on a particular USB bus can be changed, too.

Allow interfaces per default::

	$ echo 1 > /sys/bus/usb/devices/usbX/interface_authorized_default

Deny interfaces per default::

	$ echo 0 > /sys/bus/usb/devices/usbX/interface_authorized_default

Per default the interface_authorized_default bit is 1.
So all interfaces would authorized per default.

Note:
  If a deauthorized interface will be authorized so the driver probing must
  be triggered manually by writing INTERFACE to /sys/bus/usb/drivers_probe

For drivers that need multiple interfaces all needed interfaces should be
authorized first. After that the drivers should be probed.
This avoids side effects.


code:
==============================================
ChipIdea Highspeed Dual Role Controller Driver
==============================================

1. How to test OTG FSM(HNP and SRP)
-----------------------------------

To show how to demo OTG HNP and SRP functions via sys input files
with 2 Freescale i.MX6Q sabre SD boards.

1.1 How to enable OTG FSM
-------------------------

1.1.1 Select CONFIG_USB_OTG_FSM in menuconfig, rebuild kernel
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Image and modules. If you want to check some internal
variables for otg fsm, mount debugfs, there are 2 files
which can show otg fsm variables and some controller registers value::

	cat /sys/kernel/debug/ci_hdrc.0/otg
	cat /sys/kernel/debug/ci_hdrc.0/registers

1.1.2 Add below entries in your dts file for your controller node
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

::

	otg-rev = <0x0200>;
	adp-disable;

1.2 Test operations
-------------------

1) Power up 2 Freescale i.MX6Q sabre SD boards with gadget class driver loaded
   (e.g. g_mass_storage).

2) Connect 2 boards with usb cable with one end is micro A plug, the other end
   is micro B plug.

   The A-device(with micro A plug inserted) should enumerate B-device.

3) Role switch

   On B-device::

	echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req

   B-device should take host role and enumerate A-device.

4) A-device switch back to host.

   On B-device::

	echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req

   or, by introducing HNP polling, B-Host can know when A-peripheral wish
   to be host role, so this role switch also can be trigged in A-peripheral
   side by answering the polling from B-Host, this can be done on A-device::

	echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req

   A-device should switch back to host and enumerate B-device.

5) Remove B-device(unplug micro B plug) and insert again in 10 seconds,
   A-device should enumerate B-device again.

6) Remove B-device(unplug micro B plug) and insert again after 10 seconds,
   A-device should NOT enumerate B-device.

   if A-device wants to use bus:

   On A-device::

	echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop
	echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req

   if B-device wants to use bus:

   On B-device::

	echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req

7) A-device power down the bus.

   On A-device::

	echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop

   A-device should disconnect with B-device and power down the bus.

8) B-device does data pulse for SRP.

   On B-device::

	echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req

   A-device should resume usb bus and enumerate B-device.

1.3 Reference document
----------------------
"On-The-Go and Embedded Host Supplement to the USB Revision 2.0 Specification
July 27, 2012 Revision 2.0 version 1.1a"

2. How to enable USB as system wakeup source
--------------------------------------------
Below is the example for how to enable USB as system wakeup source
at imx6 platform.

2.1 Enable core's wakeup::

	echo enabled > /sys/bus/platform/devices/ci_hdrc.0/power/wakeup

2.2 Enable glue layer's wakeup::

	echo enabled > /sys/bus/platform/devices/2184000.usb/power/wakeup

2.3 Enable PHY's wakeup (optional)::

	echo enabled > /sys/bus/platform/devices/20c9000.usbphy/power/wakeup

2.4 Enable roothub's wakeup::

	echo enabled > /sys/bus/usb/devices/usb1/power/wakeup

2.5 Enable related device's wakeup::

	echo enabled > /sys/bus/usb/devices/1-1/power/wakeup

If the system has only one usb port, and you want usb wakeup at this port, you
can use below script to enable usb wakeup::

	for i in $(find /sys -name wakeup | grep usb);do echo enabled > $i;done;


code:
===========
DWC3 driver
===========

TODO
~~~~

Please pick something while reading :)

- Convert interrupt handler to per-ep-thread-irq

  As it turns out some DWC3-commands ~1ms to complete. Currently we spin
  until the command completes which is bad.

  Implementation idea:

  - dwc core implements a demultiplexing irq chip for interrupts per
    endpoint. The interrupt numbers are allocated during probe and belong
    to the device. If MSI provides per-endpoint interrupt this dummy
    interrupt chip can be replaced with "real" interrupts.
  - interrupts are requested / allocated on usb_ep_enable() and removed on
    usb_ep_disable(). Worst case are 32 interrupts, the lower limit is two
    for ep0/1.
  - dwc3_send_gadget_ep_cmd() will sleep in wait_for_completion_timeout()
    until the command completes.
  - the interrupt handler is split into the following pieces:

    - primary handler of the device
      goes through every event and calls generic_handle_irq() for event
      it. On return from generic_handle_irq() in acknowledges the event
      counter so interrupt goes away (eventually).

    - threaded handler of the device
      none

    - primary handler of the EP-interrupt
      reads the event and tries to process it. Everything that requires
      sleeping is handed over to the Thread. The event is saved in an
      per-endpoint data-structure.
      We probably have to pay attention not to process events once we
      handed something to thread so we don't process event X prio Y
      where X > Y.

    - threaded handler of the EP-interrupt
      handles the remaining EP work which might sleep such as waiting
      for command completion.

  Latency:

   There should be no increase in latency since the interrupt-thread has a
   high priority and will be run before an average task in user land
   (except the user changed priorities).


code:
===========
EHCI driver
===========

27-Dec-2002

The EHCI driver is used to talk to high speed USB 2.0 devices using
USB 2.0-capable host controller hardware.  The USB 2.0 standard is
compatible with the USB 1.1 standard. It defines three transfer speeds:

    - "High Speed" 480 Mbit/sec (60 MByte/sec)
    - "Full Speed" 12 Mbit/sec (1.5 MByte/sec)
    - "Low Speed" 1.5 Mbit/sec

USB 1.1 only addressed full speed and low speed.  High speed devices
can be used on USB 1.1 systems, but they slow down to USB 1.1 speeds.

USB 1.1 devices may also be used on USB 2.0 systems.  When plugged
into an EHCI controller, they are given to a USB 1.1 "companion"
controller, which is a OHCI or UHCI controller as normally used with
such devices.  When USB 1.1 devices plug into USB 2.0 hubs, they
interact with the EHCI controller through a "Transaction Translator"
(TT) in the hub, which turns low or full speed transactions into
high speed "split transactions" that don't waste transfer bandwidth.

At this writing, this driver has been seen to work with implementations
of EHCI from (in alphabetical order):  Intel, NEC, Philips, and VIA.
Other EHCI implementations are becoming available from other vendors;
you should expect this driver to work with them too.

While usb-storage devices have been available since mid-2001 (working
quite speedily on the 2.4 version of this driver), hubs have only
been available since late 2001, and other kinds of high speed devices
appear to be on hold until more systems come with USB 2.0 built-in.
Such new systems have been available since early 2002, and became much
more typical in the second half of 2002.

Note that USB 2.0 support involves more than just EHCI.  It requires
other changes to the Linux-USB core APIs, including the hub driver,
but those changes haven't needed to really change the basic "usbcore"
APIs exposed to USB device drivers.

- David Brownell
  <dbrownell@users.sourceforge.net>

Functionality
=============

This driver is regularly tested on x86 hardware, and has also been
used on PPC hardware so big/little endianness issues should be gone.
It's believed to do all the right PCI magic so that I/O works even on
systems with interesting DMA mapping issues.

Transfer Types
--------------

At this writing the driver should comfortably handle all control, bulk,
and interrupt transfers, including requests to USB 1.1 devices through
transaction translators (TTs) in USB 2.0 hubs.  But you may find bugs.

High Speed Isochronous (ISO) transfer support is also functional, but
at this writing no Linux drivers have been using that support.

Full Speed Isochronous transfer support, through transaction translators,
is not yet available.  Note that split transaction support for ISO
transfers can't share much code with the code for high speed ISO transfers,
since EHCI represents these with a different data structure.  So for now,
most USB audio and video devices can't be connected to high speed buses.

Driver Behavior
---------------

Transfers of all types can be queued.  This means that control transfers
from a driver on one interface (or through usbfs) won't interfere with
ones from another driver, and that interrupt transfers can use periods
of one frame without risking data loss due to interrupt processing costs.

The EHCI root hub code hands off USB 1.1 devices to its companion
controller.  This driver doesn't need to know anything about those
drivers; a OHCI or UHCI driver that works already doesn't need to change
just because the EHCI driver is also present.

There are some issues with power management; suspend/resume doesn't
behave quite right at the moment.

Also, some shortcuts have been taken with the scheduling periodic
transactions (interrupt and isochronous transfers).  These place some
limits on the number of periodic transactions that can be scheduled,
and prevent use of polling intervals of less than one frame.

Use by
======

Assuming you have an EHCI controller (on a PCI card or motherboard)
and have compiled this driver as a module, load this like::

    # modprobe ehci-hcd

and remove it by::

    # rmmod ehci-hcd

You should also have a driver for a "companion controller", such as
"ohci-hcd"  or "uhci-hcd".  In case of any trouble with the EHCI driver,
remove its module and then the driver for that companion controller will
take over (at lower speed) all the devices that were previously handled
by the EHCI driver.

Module parameters (pass to "modprobe") include:

    log2_irq_thresh (default 0):
	Log2 of default interrupt delay, in microframes.  The default
	value is 0, indicating 1 microframe (125 usec).  Maximum value
	is 6, indicating 2^6 = 64 microframes.  This controls how often
	the EHCI controller can issue interrupts.

If you're using this driver on a 2.5 kernel, and you've enabled USB
debugging support, you'll see three files in the "sysfs" directory for
any EHCI controller:

	"async"
		dumps the asynchronous schedule, used for control
		and bulk transfers.  Shows each active qh and the qtds
		pending, usually one qtd per urb.  (Look at it with
		usb-storage doing disk I/O; watch the request queues!)
	"periodic"
		dumps the periodic schedule, used for interrupt
		and isochronous transfers.  Doesn't show qtds.
	"registers"
		show controller register state, and

The contents of those files can help identify driver problems.

Device drivers shouldn't care whether they're running over EHCI or not,
but they may want to check for "usb_device->speed == USB_SPEED_HIGH".
High speed devices can do things that full speed (or low speed) ones
can't, such as "high bandwidth" periodic (interrupt or ISO) transfers.
Also, some values in device descriptors (such as polling intervals for
periodic transfers) use different encodings when operating at high speed.

However, do make a point of testing device drivers through USB 2.0 hubs.
Those hubs report some failures, such as disconnections, differently when
transaction translators are in use; some drivers have been seen to behave
badly when they see different faults than OHCI or UHCI report.

Performance
===========

USB 2.0 throughput is gated by two main factors:  how fast the host
controller can process requests, and how fast devices can respond to
them.  The 480 Mbit/sec "raw transfer rate" is obeyed by all devices,
but aggregate throughput is also affected by issues like delays between
individual high speed packets, driver intelligence, and of course the
overall system load.  Latency is also a performance concern.

Bulk transfers are most often used where throughput is an issue.  It's
good to keep in mind that bulk transfers are always in 512 byte packets,
and at most 13 of those fit into one USB 2.0 microframe.  Eight USB 2.0
microframes fit in a USB 1.1 frame; a microframe is 1 msec/8 = 125 usec.

So more than 50 MByte/sec is available for bulk transfers, when both
hardware and device driver software allow it.  Periodic transfer modes
(isochronous and interrupt) allow the larger packet sizes which let you
approach the quoted 480 MBit/sec transfer rate.

Hardware Performance
--------------------

At this writing, individual USB 2.0 devices tend to max out at around
20 MByte/sec transfer rates.  This is of course subject to change;
and some devices now go faster, while others go slower.

The first NEC implementation of EHCI seems to have a hardware bottleneck
at around 28 MByte/sec aggregate transfer rate.  While this is clearly
enough for a single device at 20 MByte/sec, putting three such devices
onto one bus does not get you 60 MByte/sec.  The issue appears to be
that the controller hardware won't do concurrent USB and PCI access,
so that it's only trying six (or maybe seven) USB transactions each
microframe rather than thirteen.  (Seems like a reasonable trade off
for a product that beat all the others to market by over a year!)

It's expected that newer implementations will better this, throwing
more silicon real estate at the problem so that new motherboard chip
sets will get closer to that 60 MByte/sec target.  That includes an
updated implementation from NEC, as well as other vendors' silicon.

There's a minimum latency of one microframe (125 usec) for the host
to receive interrupts from the EHCI controller indicating completion
of requests.  That latency is tunable; there's a module option.  By
default ehci-hcd driver uses the minimum latency, which means that if
you issue a control or bulk request you can often expect to learn that
it completed in less than 250 usec (depending on transfer size).

Software Performance
--------------------

To get even 20 MByte/sec transfer rates, Linux-USB device drivers will
need to keep the EHCI queue full.  That means issuing large requests,
or using bulk queuing if a series of small requests needs to be issued.
When drivers don't do that, their performance results will show it.

In typical situations, a usb_bulk_msg() loop writing out 4 KB chunks is
going to waste more than half the USB 2.0 bandwidth.  Delays between the
I/O completion and the driver issuing the next request will take longer
than the I/O.  If that same loop used 16 KB chunks, it'd be better; a
sequence of 128 KB chunks would waste a lot less.

But rather than depending on such large I/O buffers to make synchronous
I/O be efficient, it's better to just queue up several (bulk) requests
to the HC, and wait for them all to complete (or be canceled on error).
Such URB queuing should work with all the USB 1.1 HC drivers too.

In the Linux 2.5 kernels, new usb_sg_*() api calls have been defined; they
queue all the buffers from a scatterlist.  They also use scatterlist DMA
mapping (which might apply an IOMMU) and IRQ reduction, all of which will
help make high speed transfers run as fast as they can.

TBD:
   Interrupt and ISO transfer performance issues.  Those periodic
   transfers are fully scheduled, so the main issue is likely to be how
   to trigger "high bandwidth" modes.

TBD:
   More than standard 80% periodic bandwidth allocation is possible
   through sysfs uframe_periodic_max parameter. Describe that.


code:
====================
How FunctionFS works
====================

From kernel point of view it is just a composite function with some
unique behaviour.  It may be added to an USB configuration only after
the user space driver has registered by writing descriptors and
strings (the user space program has to provide the same information
that kernel level composite functions provide when they are added to
the configuration).

This in particular means that the composite initialisation functions
may not be in init section (ie. may not use the __init tag).

From user space point of view it is a file system which when
mounted provides an "ep0" file.  User space driver need to
write descriptors and strings to that file.  It does not need
to worry about endpoints, interfaces or strings numbers but
simply provide descriptors such as if the function was the
only one (endpoints and strings numbers starting from one and
interface numbers starting from zero).  The FunctionFS changes
them as needed also handling situation when numbers differ in
different configurations.

When descriptors and strings are written "ep#" files appear
(one for each declared endpoint) which handle communication on
a single endpoint.  Again, FunctionFS takes care of the real
numbers and changing of the configuration (which means that
"ep1" file may be really mapped to (say) endpoint 3 (and when
configuration changes to (say) endpoint 2)).  "ep0" is used
for receiving events and handling setup requests.

When all files are closed the function disables itself.

What I also want to mention is that the FunctionFS is designed in such
a way that it is possible to mount it several times so in the end
a gadget could use several FunctionFS functions. The idea is that
each FunctionFS instance is identified by the device name used
when mounting.

One can imagine a gadget that has an Ethernet, MTP and HID interfaces
where the last two are implemented via FunctionFS.  On user space
level it would look like this::

  $ insmod g_ffs.ko idVendor=<ID> iSerialNumber=<string> functions=mtp,hid
  $ mkdir /dev/ffs-mtp && mount -t functionfs mtp /dev/ffs-mtp
  $ ( cd /dev/ffs-mtp && mtp-daemon ) &
  $ mkdir /dev/ffs-hid && mount -t functionfs hid /dev/ffs-hid
  $ ( cd /dev/ffs-hid && hid-daemon ) &

On kernel level the gadget checks ffs_data->dev_name to identify
whether its FunctionFS is designed for MTP ("mtp") or HID ("hid").

If no "functions" module parameters is supplied, the driver accepts
just one function with any name.

When "functions" module parameter is supplied, only functions
with listed names are accepted. In particular, if the "functions"
parameter's value is just a one-element list, then the behaviour
is similar to when there is no "functions" at all; however,
only a function with the specified name is accepted.

The gadget is registered only after all the declared function
filesystems have been mounted and USB descriptors of all functions
have been written to their ep0's.

Conversely, the gadget is unregistered after the first USB function
closes its endpoints.