驅動程式繫結

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

在 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