为驱动程序编写绑定规则

本指南逐步介绍了如何使用 i2c_temperature 示例驱动程序。

要让驱动程序绑定到节点(代表硬件 或虚拟设备),驱动程序的绑定规则必须与 节点。在本指南中,我们将为 i2c_temperature 示例编写绑定规则。 驱动程序,使其与 i2c-child 节点的节点属性相匹配。

i2c_controller 驱动程序会创建一个名为 i2c-child 的子节点用于测试 i2c_temperature 示例驱动程序。我们可以使用此 i2c_controller 驱动程序来 确定 i2c-child 节点的节点属性,并将匹配的 i2c_temperature 的绑定规则。

在开始之前,编写绑定规则要求熟悉相关概念 (在驱动程序绑定中)。

具体步骤如下:

  1. 确定节点属性
  2. 编写绑定规则
  3. 为绑定规则添加 Bazel 构建目标

1. 确定节点属性

您可以通过以下任一方式确定目标节点的节点属性:

使用 ffxDriver 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
  • 属性键“fuchsia.BIND_I2C_ADDRESS”,整数值为 0xFF

在驱动程序源代码中查找节点属性

添加子节点时,驱动程序可以为节点提供节点属性。 查看将目标节点创建为子节点的驱动程序的源代码 节点可帮助您确定要包含在绑定规则中的节点属性。

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
  • 属性键“fuchsia.BIND_I2C_ADDRESS”,整数值为 0xFF

2. 编写绑定规则

知道要匹配的节点属性后,您就可以使用 来为驱动程序编写绑定规则。

在上一部分中,我们已确定 i2c-child 节点具有 以下节点属性:

  • 属性键 fuchsia.hardware.i2c,枚举值为 fuchsia.hardware.i2c.Service.ZirconTransport
  • 属性键“fuchsia.BIND_I2C_ADDRESS”,整数值为 0xFF

为了匹配这些属性,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 库,因此构建目标包含绑定库 作为 build 依赖项。

如需确定绑定规则中使用了哪些绑定库,您可以查看 驱动程序源代码在 i2c-child 节点的节点属性中, 第一个属性键“fuchsia.hardware.i2c.Service”来自生成的绑定 库:

// 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>

这些绑定库在驱动程序的 build 中具有相应的依赖项 规则。请在 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 结构体

节点属性由 NodeProperty 结构体表示, fuchsia.driver.framework FIDL 库:

/// 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 将节点属性传递给子节点 struct:

/// 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;
};