寫入驅動程式的繫結規則

本指南將逐步說明如何使用 i2c_temperature 範例驅動程式編寫繫結規則。

驅動程式庫的繫結規則必須與節點的節點屬性相符,才能繫結至「節點」 (代表硬體或虛擬裝置)。在本指南中,我們會為 i2c_temperature 範例驅動程式編寫繫結規則,使其與 i2c-child 節點的節點屬性相符。

i2c_controller 驅動程式庫會建立一個名為 i2c-child 的子節點,用於測試 i2c_temperature 範例驅動程式庫。我們可以使用此 i2c_controller 驅動程式庫來識別 i2c-child 節點的節點屬性,並寫入 i2c_temperature 相符的繫結規則。

開始編寫繫結規則之前,您需要熟悉驅動程式繫結中的概念。

步驟如下:

  1. 識別節點屬性
  2. 編寫繫結規則
  3. 為繫結規則新增 Bazel 建構目標

1. 識別節點屬性

您可以透過下列任一方式識別目標節點的節點屬性:

使用 ffx 驅動程式庫 list-devices 指令

如要列印 Fuchsia 系統中每個節點的屬性,請執行下列指令:

ffx driver list-devices -v

這個指令會輸出下列格式的節點屬性:

Name     : i2c-child
Moniker  : root.sys.platform.pt.acpi.FWCF.i2c-child
Driver   : None
3 Properties
[ 1/  3] : Key "fuchsia.hardware.i2c.Service"  Value Enum(fuchsia.hardware.i2c.Service.ZirconTransport)
[ 2/  3] : Key fuchsia.BIND_I2C_ADDRESS        Value 0x0000ff
[ 3/  3] : Key "fuchsia.platform.DRIVER_FRAMEWORK_VERSION" Value 0x000002

上方的輸出結果顯示 i2c-child 節點具有下列節點屬性:

  • 屬性鍵 fuchsia.hardware.i2c.Service 且列舉值為 fuchsia.hardware.i2c.Service.ZirconTransport
  • 屬性值為 0xFF 的屬性索引鍵 fuchsia.BIND_I2C_ADDRESS

查詢驅動程式庫原始碼中的節點屬性

新增子節點時,驅動程式可以提供節點屬性。查看建立目標節點做為子節點的驅動程式庫原始碼,可協助您找出要納入繫結規則的節點屬性。

i2c_controller 驅動程式庫會建立一個名為 i2c-child 的子節點,i2c_temperature 範例驅動程式庫會繫結至該節點。檢查 i2c_controller 驅動程式庫的原始碼,找出傳送至這個子節點的節點屬性:

// Set the properties of the node for drivers to target.
auto properties = fidl::VectorView<fuchsia_driver_framework::wire::NodeProperty>(arena, 2);
properties[0] = fdf::MakeProperty(arena, bind_fuchsia_hardware_i2c::SERVICE,
                                  bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT);
properties[1] = fdf::MakeProperty(arena, 0x0A02 /* BIND_I2C_ADDRESS */, 0xff);

此程式碼顯示 i2c-child 節點使用下列繫結屬性建立:

  • 屬性鍵 fuchsia.hardware.i2c.Service 且列舉值為 fuchsia.hardware.i2c.Service.ZirconTransport
  • 屬性值為 0xFF 的屬性索引鍵 fuchsia.BIND_I2C_ADDRESS

2. 寫入繫結規則

知道要比對的節點屬性後,即可使用繫結語言撰寫驅動程式的繫結規則。

在上一節中,我們發現 i2c-child 節點具有下列節點屬性:

  • 屬性鍵 fuchsia.hardware.i2c 且列舉值為 fuchsia.hardware.i2c.Service.ZirconTransport
  • 屬性值為 0xFF 的屬性索引鍵 fuchsia.BIND_I2C_ADDRESS

為了與這些屬性相符,i2c_temperature 驅動程式庫會宣告下列繫結規則:

using fuchsia.hardware.i2c;

fuchsia.hardware.i2c.Service == fuchsia.hardware.i2c.Service.ZirconTransport;
fuchsia.BIND_I2C_ADDRESS == 0xFF;

開頭為 BIND_ 的整數型節點屬性鍵 (如 Fuchsia 來源樹狀結構中的 binding_priv.h 所定義) 是目前在繫結編譯器中以硬式編碼方式寫入的舊屬性金鑰。請參閱下列 binding_priv.hBIND_I2C_ADDRESS 定義:

#define BIND_I2C_ADDRESS 0x0A02

在繫結規則中使用這些金鑰時,前置字串會加上 fuchsia.

3. 為繫結規則新增 Bazel 建構目標

編寫驅動程式的繫結規則後,您必須更新 BUILD.bazel 檔案,使用 fuchsia_driver_bytecode_bind_rules() 範本為繫結規則位元碼新增建構目標:

fuchsia_driver_bind_bytecode(
    name = "bind_bytecode",
    output = "i2c_temperature.bindbc",
    rules = "i2c_temperature.bind",
    deps = [
        "@fuchsia_sdk//fidl/fuchsia.hardware.i2c:fuchsia.hardware.i2c_bindlib",
    ],
)

針對繫結規則中使用的每個程式庫,請將程式庫新增為建構目標的依附元件。舉例來說,i2c_temperature 範例驅動程式庫的繫結規則使用 fuchsia.hardware.i2c 程式庫,因此建構目標會包含繫結程式庫做為建構依附元件。

如要判斷在繫結規則中使用哪些繫結程式庫,您可以查看驅動程式庫原始碼。在 i2c-child 節點的節點屬性中,第一個屬性金鑰 fuchsia.hardware.i2c.Service 來自於 FIDL 通訊協定中產生的繫結程式庫:

// Set the properties of the node for drivers to target.
auto properties = fidl::VectorView<fuchsia_driver_framework::wire::NodeProperty>(arena, 2);
properties[0] = fdf::MakeProperty(arena, bind_fuchsia_hardware_i2c::SERVICE,
                                  bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT);
properties[1] = fdf::MakeProperty(arena, 0x0A02 /* BIND_I2C_ADDRESS */, 0xff);

前置字串 fuchsia_hardware_i2c 表示這個節點屬性的鍵和值是在以下標頭定義:

#include <bind/fuchsia/hardware/i2c/cpp/bind.h>

這些繫結程式庫會在驅動程式庫的建構規則中擁有對應的依附元件。請參閱 i2c_controller 二進位檔目標中的下列 fuchsia.hardware.i2c 依附元件:

fuchsia_cc_driver(
    name = "i2c_controller",
    srcs = [
        "i2c_controller.cc",
        "i2c_controller.h",
        "i2c_server.cc",
        "i2c_server.h",
    ],
    deps = [
        "//src/i2c_temperature/lib",
        "@fuchsia_sdk//fidl/fuchsia.hardware.i2c:fuchsia.hardware.i2c_bindlib_cc",
        "@fuchsia_sdk//fidl/fuchsia.hardware.i2c:fuchsia.hardware.i2c_llcpp_cc",
        "@fuchsia_sdk//pkg/driver_component_cpp",
    ],
)

附錄

NodeProperty 和 NodeAddArgs 結構體

節點屬性是以 fuchsia.driver.framework FIDL 程式庫中的 NodeProperty 結構表示:

/// Definition of a property for a node. A property is commonly used to match a
/// node to a driver for driver binding.
type NodeProperty = table {
    /// Key for the property.
    1: key NodePropertyKey;

    /// Value for the property.
    2: value NodePropertyValue;
};

接著,節點屬性會使用 NodeAddArgs 結構傳遞至子節點:

/// Arguments for adding a node.
type NodeAddArgs = table {
    /// Name of the node.
    1: name string:MAX_NODE_NAME_LENGTH;

    /// Capabilities to offer to the driver that is bound to this node.
    2: offers vector<fuchsia.component.decl.Offer>:MAX_OFFER_COUNT;

    /// Functions to provide to the driver that is bound to this node.
    3: symbols vector<NodeSymbol>:MAX_SYMBOL_COUNT;

    /// Properties of the node.
    4: properties vector<NodeProperty>:MAX_PROPERTY_COUNT;
};