驅動程式繫結

如要編寫繫結規則,請參閱繫結規則教學課程

在 Fuchsia 中,驅動程式庫架構會維護系統中的驅動程式和裝置樹狀結構。在本 樹狀結構,裝置是指存取 OS 可用的部分硬體。駕駛人包括 繫結至裝置。舉例來說,USB 驅動程式庫可能會繫結至 PCI 裝置 (其父項),然後發布 乙太網路裝置 (其子項)。以便決定驅動程式庫能夠繫結的裝置,每個驅動程式庫都會 都有繫結規則,而每部裝置都有一組屬性。繫結規則定義了一項條件 指定其對應的屬性。

繫結規則及其參照的條件是由特定網域語言所定義。繫結 編譯器會使用這種語言,並產生繫結規則的位元碼。語言共有兩種 包括規則和程式庫程式庫可用來共用屬性定義 相同的驅動程式和繫結規則編譯器也會從繫結的程式庫產生 FIDL 檔案, 驅動程式可能會參照程式碼中的裝置屬性

關於遷移階段,請注意,這個階段不支援定義裝置 屬性鍵 (參閱下方說明)。而是使用舊版驅動程式庫繫結系統的按鍵 (lib/ddk/binding.h) 尚可擴充。 這些金鑰會以硬式編碼的方式寫入繫結編譯器,並可在 fuchsia 命名空間下使用。 例如 PCI 供應商 ID 金鑰為 fuchsia.BIND_PCI_VID。經過硬式編碼的鍵最終會 會從這個命名空間中移除,並在繫結程式庫中定義所有節點屬性鍵。

編譯器

編譯器會採用程式庫來源清單和一個規則來源。例如:

fx bindc compile \
  --include src/devices/bind/fuchsia.usb/fuchsia.usb.bind \
  --output tools/bindc/examples/gizmo.h \
  tools/bindc/examples/gizmo.bind

目前,它會產生 C 標頭檔案,可由驅動程式庫包含。標頭檔案會定義 巨集:

ZIRCON_DRIVER(Driver, Ops, VendorName, Version);
  • Driver 是驅動程式庫的名稱。
  • Opszx_driver_ops,這是驅動程式庫作業掛鉤
  • VendorName 是代表驅動程式庫供應商名稱的字串。
  • Version 是代表驅動程式庫版本的字串。

詳情請參閱 驅動程式庫開發說明文件

繫結規則

繫結規則定義了呼叫驅動程式庫 bind() 掛鉤的條件。繫結中每個陳述式 規則是指裝置屬性必須符合的條件, 驅動程式庫進行繫結。如果繫結規則執行完畢,且所有條件都符合,則裝置 協調器會呼叫驅動程式庫 bind() 掛鉤。

繫結規則應視為宣告式規則的 驅動程式庫應繫結。因此,條件運算式的執行順序與 以及最終評估結果建議將繫結規則視為布林公式。

陳述式分為四種類型:

  • 條件陳述式是形式的等式 (或不相等) 運算式 <key> == <value> (或 <key> != <value>)。
  • 接受陳述式是指特定鍵允許的值清單。
  • 「If statement」提供簡單的分支版本。
  • True 和 false 陳述式可用來明確評估繫結規則。

範例

您可以在 //tools/bindc/examples/gizmo.bind 中找到這個繫結規則範例。

using fuchsia.usb;

// The device must be a USB device.
fuchsia.BIND_PROTOCOL == fuchsia.usb.BIND_PROTOCOL.INTERFACE;

if fuchsia.BIND_USB_VID == fuchsia.usb.BIND_USB_VID.INTEL {
  // If the device's vendor is Intel, the device class must be audio.
  fuchsia.BIND_USB_CLASS == fuchsia.usb.BIND_USB_CLASS.AUDIO;
} else if fuchsia.BIND_USB_VID == fuchsia.usb.BIND_USB_VID.REALTEK {
  // If the device's vendor is Realtek, the device class must be one of the following values:
  accept fuchsia.BIND_USB_CLASS {
    fuchsia.usb.BIND_USB_CLASS.COMM,
    fuchsia.usb.BIND_USB_CLASS.VIDEO,
  }
} else {
  // If the vendor is neither Intel or Realtek, do not bind.
  false;
}

語言限制

為提升可讀性, 繫結規則是驅動程式庫所繫結條件的簡單示意圖。

  • 不允許空白區塊。 空一個區塊是否代表驅動程式庫會繫結或取消,這點不明確。 作者應使用明確的 truefalse 陳述式。

  • 如果陳述式必須有其他區塊,且為終端機, 這項限制會明確地做出執行作業分支,藉此提高可讀性。因為沒有 陳述式可能會遵循 if 陳述式,因此可以透過繫結規則輕鬆追蹤路徑。

  • 真陽性和偽陳述必須是相關範圍內的唯一陳述。 繫結規則並非強制性的計畫,且評估順序並不重要。攪拌 具有其他條件的布林陳述式 (尤其是 true) 可能導致下列情況 不是清楚的。

文法

rule = using-list , ( statement )+ ;

using-list = ( using , ";" )* ;

using = "using" , compound-identifier , ( "as" , IDENTIFIER ) ;

statement = condition , ";" | accept | if-statement | true | false ;

condition = compound-identifier , condition-op , value ;

condition-op = "==" | "!=" ;

accept = "accept" , compound-identifier , "{" ( value , "," )+ "}" ;

if-statement = "if" , condition , "{" , ( statement )+ , "}" ,
                ( "else if" , "{" , ( statement )+ , "}" )* ,
                "else" , "{" , ( statement )+ , "}" ;

true = "true" , ";" ;

false = "false" , ";" ;

compound-identifier = IDENTIFIER ( "." , IDENTIFIER )* ;

value = compound-identifier | STRING-LITERAL | NUMERIC-LITERAL | "true" | "false" ;

ID 與規則運算式 [a-zA-Z]([a-zA-Z0-9_]*[a-zA-Z0-9])? 相符,但不得與任何 ID 相符 字詞。關鍵字清單如下:

accept
as
else
false
if
true
using

字串常值與規則運算式 ”[^”]*” 相符,且數值常值與規則運算式 [0-9]+ 相符,或 0x[0-9A-F]+

繫結編譯器會忽略任何以 // 開頭的行 (以空白字元表示), 以 /**/ 分隔的線條。

複合繫結

除了將驅動程式與裝置繫結外,Fchsia 的驅動程式也能使用繫結規則。 從節點建立複合裝置繫結規則會依循相同語言 視為非複合繫結,但會分離包含 名稱和陳述式集合

繫結規則中只能有一個主要節點。複合驅動程式庫會 啟動與主要節點相同的驅動程式代管程序。

如需複合繫結規則檔案的範例,請前往 //tools/bindc/examples/composite-gizmo.bind.

composite gizmo_pci;

using fuchsia.pci;
using fuchsia.platform;
using fuchsia.tee;

primary node "pci" {
  fuchsia.BIND_PROTOCOL == fuchsia.pci.BIND_PROTOCOL.DEVICE;
}

node "tee" {
  if fuchsia.BIND_PROTOCOL == fuchsia.tee.BIND_PROTOCOL.DEVICE {
    fuchsia.BIND_PLATFORM_DEV_VID == fuchsia.platform.BIND_PLATFORM_DEV_VID.GENERIC;
  } else {
    fuchsia.BIND_PLATFORM_DEV_VID == fuchsia.platform.BIND_PLATFORM_DEV_VID.QEMU;
  }
}

複合繫結的文法如下:

composite-bind-rules = [composite-device], using-list , ( node )+ ;

composite-device = “composite” , IDENTIFIER;

node = [ "primary" ], "node" , STRING-LITERAL , "{" , ( statement )+ , "}"

建立目標

如要在 Fuchsia 建構系統中宣告繫結規則,請使用下列建構目標:

driver_bind_rules("bind") {
  rules = <bind rules filename>
  bind_output = <generated bind binary filename>
  deps = [ <list of bind library targets> ]
}

詳情請參閱 //build/繫結/bind.gni

測試

繫結編譯器支援適用於繫結規則的資料導向單元測試架構,可讓您 獨立測試您的繫結規則。繫結規則的測試案例包含 裝置規格和預期結果,即繫結或中止。測試案例會傳遞到繫結狀態 而編譯器會以 JSON 規格檔案的形式,執行每個測試案例。 執行偵錯工具

JSON 規格必須是測試案例物件清單,其中每個物件都包含以下內容:

  • name 測試案例名稱的字串。
  • expected 預期的結果。必須為 “match”“abort”
  • device 字串鍵/值組合清單,用於說明裝置屬性。這是 與偵錯工具的裝置規格類似 (請參閱 這個例子)。

如果測試是針對複合裝置,則裝置中的每個節點都可以 測試案例物件清單。單元測試的 JSON 規格會是 列出節點物件每個節點物件都包含:

  • node 節點名稱的字串。必須與繫結規則中的節點相符 測試。
  • tests 測試案例物件清單。

範例

這是測試案例範例,完整的測試位於 //tools/bindc/examples/test.json。這個 保護殼會檢查繫結規則是否符合所列屬性的裝置,例如 Intel USB 音訊 裝置。

[
  {
    "name": "Intel",
    "expected": "match",
    "device": {
      "fuchsia.BIND_PROTOCOL": "fuchsia.usb.BIND_PROTOCOL.INTERFACE",
      "fuchsia.BIND_USB_VID": "fuchsia.usb.BIND_USB_VID.INTEL",
      "fuchsia.BIND_USB_CLASS": "fuchsia.usb.BIND_USB_CLASS.AUDIO"
    }
  }
]

以下示例呈現包含測試案例的複合繫結節點。完整的測試位於 `//tools/bindc/examples/composite-tests.json。每個測試案例都會檢查節點是否 繫結規則會比對具備所列屬性的裝置。

[
    {
        "node": "pci",
        "tests": [
            {
                "name": "Match",
                "expected": "match",
                "device": {
                    "fuchsia.BIND_PROTOCOL": "fuchsia.pci.BIND_PROTOCOL.DEVICE"
                }
            },
            {
                "name": "Abort pci",
                "expected": "abort",
                "device": {
                    "fuchsia.BIND_PROTOCOL": "fuchsia.tee.BIND_PROTOCOL.DEVICE"
                }
            }
        ]
    }
]

建構

定義測試建構目標,如下所示:

bind_test("example_bind_test") {
  rules = <bind rules filename>
  tests = <test specification filename>
  deps = [ <list of bind library targets> ]
}

或者,您也可以在現有的 bind_rules 中新增 tests 引數來產生 測試目標這個名稱會是原始目標的名稱加上 _test。例如,下列 就會產生 example_bind_test

driver_bind_rules("example_bind") {
  rules = "meta/gizmo.bind"
  bind_output = “gizmo.bindbc”
  tests = "meta/tests.json"
  deps = [ "//src/devices/bind/fuchsia.usb" ]
}

執行

如果您已為測試定義建構目標,則可使用 fx 測試照常執行測試。

fx test example_bind_test

或者,您也可以直接執行繫結工具。例如:

fx bindc test \
  tools/bindc/examples/gizmo.bind \
  --test-spec tools/bindc/examples/tests.json \
  --include src/devices/bind/fuchsia.usb/fuchsia.usb.bind

繫結程式庫

繫結程式庫會定義驅動程式可指派給其子項的一組屬性。另外, 繫結規則可能是指繫結程式庫

名稱間距

繫結程式庫一開始會定義其命名空間:

library <vendor>.<library>;

每個命名空間均須以廠商開頭,且每個廠商都必須確保彼此之間不會有衝突 各自的命名空間然而,此語言可讓一個廠商 另一個例子。Google 會將 fuchsia 用於公開程式庫。

程式庫引入的任何值均為命名空間。舉例來說,下列程式庫會定義 新的 PCI 裝置 ID GIZMO_VER_1

library gizmotronics.gizmo;

using fuchsia.pci as pci;

extend uint pci.device_id {
  GIZMO_VER_1 = 0x4242,
};

如要參照這個值,驅動程式庫作者應使用完整名稱,如下所示。

using fuchsia.pci as pci;
using gizmotronics.gizmo;

pci.device_id == gizmotronics.gizmo.device_id.GIZMO_VER_1

鍵和值

裝置屬性定義類似於其他語言中的變數宣告。

<type> <name>;
Or:
<type> <name> {
  <value>,
  <value>,
  …
};

繫結程式庫也可以擴充其他程式庫的屬性。

extend <type> <name> {
  <value>,
  …
};

每個鍵都有一個類型,而對應該鍵的所有值都必須屬於該類型。語言 支援原始類型:uintstringbool 之一。和列舉 (enum)。時間 定義索引鍵時,您應該偏好使用列舉,但值會由外部提供 例如硬體

定義原始值時,請使用 <identifier> = <literal> 形式和列舉 只要提供 ID 即可使用相同的值定義多個原始值是有效的 常值。

文法

library = library-header , using-list , declaration-list ;

library-header = "library" , compound-identifier , ";" ;

using-list = ( using , ";" )* ;

using = "using" , compound-identifier , ( "as" , IDENTIFIER ) ;

compound-identifier = IDENTIFIER ( "." , IDENTIFIER )* ;

declaration-list = ( declaration , ";" )* ;

declaration = primitive-declaration | enum-declaration ;

primitive-declaration = ( "extend" ) , type , compound-identifier ,
                        ( "{" primitive-value-list "}" ) ;

type = "uint" | "string" | "bool";

primitive-value-list = ( IDENTIFIER , "=" , literal , "," )* ;

enum-declaration = ( "extend" ) , "enum" , compound-identifier ,
                   ( "{" , enum-value-list , "}" ) ;

enum-value-list = ( IDENTIFIER , "," )* ;

literal = STRING-LITERAL | NUMERIC-LITERAL | "true" | "false" ;

ID 與規則運算式 [a-zA-Z]([a-zA-Z0-9_]*[a-zA-Z0-9])? 相符,但不得與任何 ID 相符 字詞。關鍵字清單如下:

as
bool
enum
extend
library
string
uint
using

字串常值與規則運算式 ”[^”]*” 相符,且數值常值與規則運算式 [0-9]+ 相符,或 0x[0-9A-F]+

繫結編譯器會忽略任何以 // 開頭的行 (以空白字元表示), 以 /**/ 分隔的線條。

建立目標

如要在 Fuchsia 建構系統中宣告繫結程式庫,請使用下列建構目標:

bind_library(<library name>) {
  source = <bind library filename>
  public_deps = [ <list of bind library targets> ]
}

詳情請參閱 //build/繫結/bind.gni