创建复合节点

本教程介绍了如何在 Fuchsia 系统中为复合驱动程序创建复合节点

复合节点规范是一种用于描述 Fuchsia 系统中的复合节点的机制。复合节点是具有多个父节点的节点。复合驱动程序是一种绑定到复合节点并使用系统中多个父节点管理的资源的驱动程序。

如需为复合驱动程序创建复合节点,您需要执行以下任务:

  • 创建复合节点规范
  • 编写复合驱动程序的绑定规则(以匹配复合节点规范)

具体步骤如下:

  1. 准备父级规范
  2. 创建复合节点规范
  3. 为复合驱动程序定义绑定规则

如需排查问题,请参阅调试复合驱动程序问题

了解复合节点概念

复合节点是具有多个父级的节点。复合节点充当多个父级节点的中央联系点,可访问这些父级节点管理的资源。将驱动程序绑定到复合节点后,复合驱动程序可以访问父级驱动程序提供的组合资源。

复合节点

图 1. 复合节点可以访问多个父节点及其资源。

在开始之前,请先熟悉以下开发概念:

主要背景概念

本教程假定您熟悉与 Fuchsia 驱动程序相关的以下概念:

  • 驱动程序绑定:将驱动程序与 Fuchsia 系统中的节点进行匹配的过程。
  • 复合节点:具有多个父节点的节点,可访问 Fuchsia 系统中的多个资源。
  • 驱动程序框架 (DFv2):用于管理 Fuchsia 中的驱动程序和节点的新框架。

什么是复合节点规范?

复合节点规范是一种用于创建复合节点的机制。它描述了可以用作复合节点的父节点,以及可以绑定到复合节点的适当复合驱动程序。

与组件清单 (.cml) 和绑定规则 (.bind) 不同,复合节点规范不是文件。它是一个对象,需要由加载到 Fuchsia 系统中的驱动程序(确切地说,由驱动程序的源代码)构建并添加(使用 CompositeNodeManager 协议)。

复合节点规范

图 2. 复合节点规范是父级规范的集合。

复合节点规范由一组父级规范组成,每个父级规范代表复合节点的父级节点的条件。一组父级规范具有以下用途:

  • 描述此复合节点的父节点。
  • 提供属性以识别复合驱动程序。

复合节点规范中的每个父级规范都包含以下内容:

  • 绑定规则:用于将此父级规范与拓扑中的节点进行匹配的绑定规则。
  • 属性:在复合节点的匹配过程中应用的键值对的一部分,用于查找复合驱动程序。(它们遵循与节点属性相同的格式。)

驱动程序框架如何在 Fuchsia 系统中创建复合节点?

向系统引入复合节点规范后,会发生以下事件:

  1. 复合节点规范由 Fuchsia 系统中加载的驱动程序(通常是板级驱动程序)添加到驱动程序框架。

    复合节点规范第 1 步

  2. 驱动程序管理器会请求驱动程序索引根据复合节点规范搜索匹配的复合驱动程序。

    系统会匹配绑定规则可满足此复合节点规范中父级规范的所有属性的复合驱动程序。(请参阅驱动程序框架如何将复合驱动程序与复合节点进行匹配?

    复合节点规范第 2 步

  3. 找到复合驱动程序后,驱动程序管理器会请求驱动程序索引根据复合节点规范在系统中搜索节点。

    系统会匹配节点属性能够满足复合节点规范中父级规范提供的绑定规则的节点。每个匹配的节点都会成为第 3 步中新创建的复合节点的父节点。

    复合节点规范第 3 步

  4. 所有父级规范都匹配后,驱动程序管理器会使用匹配的节点作为父级创建复合节点,最后将复合驱动程序(在第 1 步中匹配)绑定到新创建的复合节点。(复合节点提供主节点和节点名称。)

    复合节点规范第 4 步

驱动程序框架如何将复合驱动程序与复合节点进行匹配?

复合驱动程序的匹配过程是通过将复合驱动程序的绑定规则应用于复合节点规范中父级规范提供的属性来完成的。(请注意,这与应用父级规范的绑定规则来匹配拓扑中的节点不同。)

例如,以下绑定规则来自复合驱动程序:

composite focaltech_touch;

using fuchsia.gpio;
using fuchsia.hardware.i2c;
using fuchsia.i2c;

primary node "i2c" {
  fuchsia.hardware.i2c.Service == fuchsia.hardware.i2c.Service.ZirconTransport;
  fuchsia.BIND_I2C_ADDRESS == fuchsia.i2c.BIND_I2C_ADDRESS.FOCALTECH_TOUCH;
}

node "gpio-int" {
  fuchsia.BIND_PROTOCOL == fuchsia.gpio.BIND_PROTOCOL.DEVICE;
  fuchsia.gpio.FUNCTION == fuchsia.gpio.FUNCTION.TOUCH_INTERRUPT;
}

根据这些绑定规则,匹配的复合节点规范需要一个属性与 i2c 匹配的父规范,以及另一个属性与 gpio-int 匹配的父规范。

如果满足以下条件,复合驱动程序与复合节点(规范)之间的匹配将成功:

  • 所有父级规范都必须与复合驱动程序的绑定规则中的节点匹配。

  • 复合驱动程序绑定规则中的所有非可选节点都必须与父级规范匹配。

    例如,复合驱动程序中的以下绑定规则包含一个可选节点:

    composite virtio_input;
    
    using fuchsia.acpi;
    using fuchsia.hardware.pci;
    using fuchsia.pci;
    
    primary node "pci" {
        fuchsia.hardware.pci.Service == fuchsia.hardware.pci.Service.ZirconTransport;
        fuchsia.BIND_PCI_VID == fuchsia.pci.BIND_PCI_VID.VIRTIO;
        fuchsia.BIND_PCI_DID == fuchsia.pci.BIND_PCI_DID.VIRTIO_DEV_TYPE_INPUT;
    }
    
    optional node "acpi" {
        fuchsia.BIND_PROTOCOL == fuchsia.acpi.BIND_PROTOCOL.DEVICE;
    }
    

    来源virtio_input.bind

节点的匹配顺序无需与复合驱动程序的绑定规则中列出的顺序一致。

不过,匹配不能含糊不清,即:

  • 每个父级规范都只能与复合驱动程序的绑定规则中的一个节点相对应。
  • 复合绑定规则中的每个节点最多只能与一个父级规范匹配。(可选节点可能与任何父级规范都不匹配。)

如果发生模糊情况,驱动程序管理器会在日志中输出警告消息。(目前,系统仍会进行匹配,但日后将禁止进行匹配。请参阅此相关工单。)

父级规范绑定规则

图 3. 每个父级规范的绑定规则都用于查找复合节点的父级节点。

复合节点绑定规则

图 4. 复合驱动程序的绑定规则会与复合节点的属性进行匹配,这些属性由复合节点规范中的父规范共同提供。

绑定规则如何运作?

父级规范中的绑定规则提供了接受拒绝的属性值的列表。为了满足绑定规则,节点的节点属性必须包含所有接受的节点属性值,且不包含任何被拒绝的节点属性值。

例如,父级规范可以包含以下绑定规则:

  • 接受 fuchsia.BIND_PROTOCOL1517
  • 拒绝 fuchsia.BIND_PLATFORM_DEV_VIDIntel

使用这些绑定规则时,只有当节点的 fuchsia.BIND_PROTOCOL 属性值为 1517,且 fuchsia.BIND_PLATFORM_DEV_VID 属性没有 Intel 值时,才会匹配该节点。

1. 准备父级规范

您首先需要准备构成复合节点规范的父规范。

如需准备父级规范,请按以下步骤操作:

  1. 在父级规范中定义绑定规则
  2. 在父级规范中定义属性

1. 在父级规范中定义绑定规则

绑定规则用于根据父级规范查找和匹配拓扑中的节点。系统会根据父级规范中的绑定规则评估节点的属性。如果匹配,该节点将成为复合节点的父节点。

编写绑定规则的过程

为复合节点的父节点编写绑定规则的过程与绑定规则教程中所述的过程类似。如需确定绑定规则,您首先需要确定要绑定的每个父级节点的属性。

如需查看节点拓扑中的每个节点的属性,您可以使用以下 ffx 命令:

ffx driver list-devices -v

此命令会输出类似以下内容的条目:

Name     : i2c-1-56
Topo Path: sys/platform/i2c-0/aml-i2c/i2c/i2c-1-56
Driver   : fuchsia-boot:///#driver/i2c.so
Flags    : MUST_ISOLATE | BOUND
Proto    : ZX_PROTOCOL_I2C (24)
3 Properties
[ 1/  3] : Key fuchsia.BIND_I2C_BUS_ID        Value 0x000001
[ 2/  3] : Key fuchsia.BIND_I2C_ADDRESS       Value 0x000038
[ 3/  3] : Key "fuchsia.hardware.i2c.Service" Value "fuchsia.hardware.i2c.Service.ZirconTransport"

上面的示例条目显示了 i2c-1-56 节点的以下节点属性:

  • fuchsia.I2C_BUS_ID = 0x000001undefined
  • fuchsia.I2C_ADDRESS = 0x000038
  • fuchsia.hardware.i2c.Service = fuchsia.hardware.i2c.Service.ZirconTransport

如需查看哪些属性值是可接受的,您可以在 Fuchsia 代码库中查找绑定库(例如,在 src/devices/bind 目录中)。在此示例中,由于节点是 I2C 节点,因此属性值位于 fuchsia.i2c 绑定库中,如下所示:

extend uint fuchsia.BIND_I2C_BUS_ID {
  I2C_A0_0 = 0,
  I2C_2 = 1,
  I2C_3 = 2,
};

extend uint fuchsia.BIND_I2C_ADDRESS {
  BACKLIGHT = 0x2C,
  ETH = 0x18,
  FOCALTECH_TOUCH = 0x38,
  AMBIENTLIGHT = 0x39,
  AUDIO_CODEC = 0x48,
  GOODIX_TOUCH = 0x5d,
  TI_INA231_MLB = 0x49,
  TI_INA231_SPEAKERS = 0x40,
  TI_INA231_MLB_PROTO = 0x46,
};

除了 Fuchsia 代码库中的绑定库之外,您还可以从 FIDL 库生成绑定库。在上面的示例中,fuchsia.hardware.i2c.Service 键及其值 fuchsia.hardware.i2c.Service.ZirconTransport 的属性就来自此处。(如需了解详情,请参阅生成的绑定库。)

使用绑定库中找到的属性值,您可以重新映射节点属性,如下所示:

  • fuchsia.BIND_I2C_BUS_ID = fuchsia.i2c.BIND_I2C_BUS_ID.I2C_2
  • fuchsia.BIND_I2C_ADDRESS = fuchsia.i2c.BIND_I2C_ADDRESS.FOCALTECH_TOUCH
  • fuchsia.hardware.i2c.Service = fuchsia.hardware.i2c.Service.ZirconTransport

您可以通过驱动程序源代码中的生成的库访问这些绑定库值。(如需了解详情,请参阅绑定库 codegen 教程。)

与这些属性匹配的绑定规则的定义如下所示:

accept fuchsia.hardware.i2c.Service { fuchsia.hardware.i2c.Service.ZirconTransport }
accept BIND_I2C_BUS_ID { fuchsia.i2c.BIND_I2C_BUS_ID.I2C_2 }
accept BIND_I2C_ADDRESS { fuchsia.i2c.BIND_I2C_ADDRESS.FOCALTECH_TOUCH }

在 DFv1 中定义绑定规则

在 DFv1 中,复合节点规范是使用 DDKTL(设备驱动程序套件模板库)编写的。用于编写绑定规则的函数位于 composite-node-spec.h 中。

使用 DDK 库和绑定库 codegen 值,我们可以编写以下代码:

const ddk::BindRule kI2cBindRules[] = {
    ddk::MakeAcceptBindRule(bind_fuchsia_hardware_i2c::SERVICE,
                            bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
    ddk::MakeAcceptBindRule(bind_fuchsia::I2C_BUS_ID,
                            bind_fuchsia_i2c::BIND_I2C_BUS_ID_I2C_2),
    ddk::MakeAcceptBindRule(bind_fuchsia::I2C_ADDRESS,
                            bind_fuchsia_focaltech_platform::BIND_I2C_ADDRESS_TOUCH),
};

在 DFv2 中定义绑定规则

在 DFv2 中,复合节点规范由 fuchsia.driver.framework FIDL 库中的 composite_node_spec.fidl 中的 CompositeNodeSpec 协议定义。sdk/lib/driver/component/cpp 目录中的 composite_node_spec.h 库可用于简化绑定规则的定义。

使用 CompositeNodeSpec 库和绑定库 codegen 值,我们可以编写以下代码:

auto i2c_bind_rules = std::vector {
    MakeAcceptBindRule(bind_fuchsia_hardware_i2c::SERVICE,
                       bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
    MakeAcceptBindRule(bind_fuchsia::I2C_BUS_ID,
                       bind_fuchsia_i2c::BIND_I2C_BUS_ID_I2C_2),
    MakeAcceptBindRule(bind_fuchsia::I2C_ADDRESS,
                       bind_fuchsia_focaltech_platform::BIND_I2C_ADDRESS_TOUCH),
};

2. 在父级规范中定义属性

除了为节点定义绑定规则之外,您还需要在父级规范中定义用于查找复合驱动程序的属性。

这些属性是键值对,用于将父级规范与复合驱动程序的绑定规则进行匹配。它们与节点属性相同,采用相同的格式。属性键可以基于整数或基于字符串,而属性值可以是整数、布尔值、字符串或枚举类型。

在 DFv1 中定义媒体资源

在 DFv1 中,复合节点规范使用 DDKTL 编写,用于编写绑定规则的函数位于 composite-node-spec.h 中。您可以使用 DDK 库定义属性,并绑定库 codegen 值,如下所示:

const device_bind_prop_t kI2cProperties[] = {
    ddk::MakeProperty(bind_fuchsia_hardware_i2c::SERVICE,
                      bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
    ddk::MakeProperty(bind_fuchsia::I2C_ADDRESS,
                      bind_fuchsia_focaltech_platform::BIND_I2C_ADDRESS_TOUCH),
};

在 DFv2 中定义媒体资源

在 DFv2 中,系统会为 fuchsia.driver.framework FIDL 库中的 composite_node_spec.fidl 编写复合节点规范。//sdk/lib/driver/component/cpp 中的 node_add_args.h 库可用于简化属性定义。您可以使用 CompositeNodeSpec 库定义属性,并绑定库 codegen 值,如下所示:

auto i2c_properties[] = std::vector {
    ddk::MakeProperty(bind_fuchsia::I2C_ADDRESS,
                      bind_fuchsia_focaltech_platform::BIND_I2C_ADDRESS_TOUCH),
};

2. 创建复合节点规范

创建复合节点规范涉及定义并将一组父级规范添加到驱动程序管理器。

复合节点规范由 Fuchsia 系统中加载的驱动程序(通常是板级驱动程序)添加到驱动程序框架。(如需详细了解此过程,请参阅驱动程序框架如何在 Fuchsia 系统中创建复合节点?

在 DFv1 中添加复合节点规范

在 DFv1 中,驱动程序可以使用 DdkAddCompositeNodeSpec() 函数通过 DDKTL 添加复合节点规范。

驱动程序必须先在 composite-node-spec.h 库中定义 CompositeNodeSpec 对象。使用上一部分中的示例绑定规则和属性,您可以定义具有 I2C 父级规范的 CompositeNodeSpec 对象,如下所示:

const ddk::BindRule kI2cBindRules[] = {
    ddk::MakeAcceptBindRule(bind_fuchsia_hardware_i2c::SERVICE,
                            bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
    ddk::MakeAcceptBindRule(bind_fuchsia::I2C_BUS_ID,
                            bind_fuchsia_i2c::BIND_I2C_BUS_ID_I2C_2),
    ddk::MakeAcceptBindRule(bind_fuchsia::I2C_ADDRESS,
                            bind_fuchsia_focaltech_platform::BIND_I2C_ADDRESS_TOUCH),
};

const device_bind_prop_t kI2cProperties[] = {
    ddk::MakeProperty(bind_fuchsia_hardware_i2c::SERVICE,
                      bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
    ddk::MakeProperty(bind_fuchsia::I2C_ADDRESS,
                      bind_fuchsia_focaltech_platform::BIND_I2C_ADDRESS_TOUCH),
};

auto spec = ddk::CompositeNodeSpec(kI2cBindRules, kI2cProperties);

您可以使用 AddParentSpec() 函数添加任何其他节点。例如,如果我们想为 GPIO 解释引脚添加父级规范,可以编写以下代码:

const ddk::BindRule kGpioInterruptRules[] = {
    ddk::MakeAcceptBindRule(bind_fuchsia::PROTOCOL,
                            bind_fuchsia_gpio::BIND_PROTOCOL_DEVICE),
    ddk::MakeAcceptBindRule(bind_fuchsia::GPIO_PIN,
                bind_fuchsia_amlogic_platform_s905d2::GPIOZ_PIN_ID_PIN_4),
};

const device_bind_prop_t kGpioInterruptProperties[] = {
    ddk::MakeProperty(bind_fuchsia::PROTOCOL,
                      bind_fuchsia_gpio::BIND_PROTOCOL_DEVICE),
    ddk::MakeProperty(bind_fuchsia_gpio::FUNCTION,
                      bind_fuchsia_gpio::FUNCTION_TOUCH_INTERRUPT)};

desc.AddParentSpec(kGpioInterruptRules, kGpioInterruptProperties);

CompositeNodeSpec 对象准备就绪后,您可以使用 DdkAddCompositeNodeSpec() 添加该对象,其中 spec 是包含复合节点规范的对象,例如:

auto status = DdkAddCompositeNodeSpec("ft3x27_touch", spec);

由于 CompositeNodeSpec 对象遵循构建器模式,因此可以简化为:

auto status =
     DdkAddCompositeNodeSpec("ft3x27_touch",
          ddk::CompositeNodeSpec(kFocaltechI2cRules, kFocaltechI2cProperties)
              .AddParentSpec(kGpioInterruptRules, kGpioInterruptProperties)
              .set_metadata(metadata);

在 DFv2 中添加复合节点规范

在 DFv2 中,我们使用 fuchsia.driver.framework FIDL API 中的 CompositeNodeManager 协议添加复合节点规范:

@discoverable
protocol CompositeNodeManager {
    /// Add the given spec to the driver manager.
    AddSpec(CompositeNodeSpec) -> () error CompositeNodeSpecError;
};

向平台总线添加复合节点规范

如果复合节点需要平台总线上的节点作为父级,则开发板驱动程序可以通过 platform_bus.fidl API 添加复合节点规范。这适用于 DFv1 和 DFv2。

/// Adds a composite node specification to the bus. This will add a platform device specified
/// by |node| and insert a node into the composite node specification that matches the device.
AddCompositeNodeSpec(struct {
    node Node;
    spec fuchsia.driver.framework.CompositeNodeSpec;
}) -> () error zx.Status;

平台总线 API 使用 composite_node_spec.fidl 中定义的相同 CompositeNodeSpec 结构体。

例如,假设我们定义了以下复合节点规范:

std::vector<fuchsia_driver_framework::BindRule> bind_rules = {
    fdf::MakeAcceptBindRule(bind_fuchsia_hardware_i2c::SERVICE,
        bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
    fdf::MakeAcceptBindRule(bind_fuchsia::I2C_ADDRESS,
        bind_fuchsia_i2c::BIND_I2C_ADDRESS_BACKLIGHT),
};

std::vector<fuchsia_driver_frameowork::Node> properties = {
    fdf::MakeProperty(bind_fuchsia_hardware_i2c::SERVICE,
        bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
    fdf::MakeProperty(bind_fuchsia::I2C_ADDRESS,
        bind_fuchsia_i2c::BIND_I2C_ADDRESS_BACKLIGHT),
};

std::vector<fuchsia_driver_framework::ParentSpec> spec = {
    {{bind_rules, properties}}
};

(如需详细了解上述示例中使用的库,请参阅在 DFv2 中定义属性在 DFv2 中定义绑定规则。)

复合节点规范定义完毕后,开发板驱动程序便可通过 PlatformBus FIDL 协议连接到平台总线,并使用客户端端调用 AddCompositeNodeSpec()

AddCompositeNodeSpec() 调用会将平台设备的父级规范(根据节点字段中的数据创建)插入给定的复合节点规范,并将此经过修改的复合节点规范添加到驱动程序框架中。然后,它会创建并添加平台设备,例如:

fpbus::Node dev;
dev.name() = "backlight";
dev.vid() = PDEV_VID_TI;  // 0x10
dev.pid() = PDEV_PID_TI_LP8556; // 0x01
dev.did() = PDEV_DID_TI_BACKLIGHT;  // 0x01

auto endpoints =
    fdf::CreateEndpoints<fuchsia_hardware_platform_bus::PlatformBus>();
if (endpoints.is_error()) {
    return endpoints.error_value();
}

fdf::WireSyncClient<fuchsia_hardware_platform_bus::PlatformBus> pbus =
    endpoints->client;
auto result = pbus.buffer(arena)->AddCompositeNodeSpec(
fidl::ToWire(fidl_arena, dev),
fidl::ToWire(fidl_arena, spec), false);

if (!result.ok()) {
    FDF_LOG(ERROR, "AddCompositeNodeSpec request failed: %s",
               result.FormatDescription().data());
    return result.status();
}

调用 AddCompositeNodeSpec() 后,系统会将以下复合节点规范添加到驱动程序框架中:

Name      : backlight
Driver    : fuchsia-boot:///#meta/ti-lp8556.cm
Nodes     : 2
Node 0    : None
  3 Bind Rules
  [ 1/ 3] : Accept "fuchsia.BIND_PLATFORM_DEV_VID" { 0x000010 }
  [ 2/ 3] : Accept "fuchsia.BIND_PLATFORM_DEV_PID" { 0x000001 }
  [ 2/ 3] : Accept "fuchsia.BIND_PLATFORM_DEV_DID" { 0x000001 }
  3 Properties
  [ 1/ 3] : Key "fuchsia.BIND_PLATFORM_DEV_VID"   Value 0x000010
  [ 2/ 3] : Key "fuchsia.BIND_PLATFORM_DEV_PID"   Value 0x000001
  [ 3/ 3] : Key "fuchsia.BIND_PLATFORM_DEV_DID"   Value 0x000001
Node 1    : None
  2 Bind Rules
  [ 1/ 2] : Accept "fuchsia.hardware.i2c.Service" { "fuchsia.hardware.i2c.Service.ZirconTransport" }
  [ 2/ 2] : Accept "fuchsia.BIND_I2C_ADDRESS"     { 0x00002C }
  2 Properties
  [ 1/ 2] : Key "fuchsia.hardware.i2c.Service" Value "fuchsia.hardware.i2c.Service.ZirconTransport"
  [ 2/ 2] : Key "fuchsia.BIND_I2C_ADDRESS"     Value 0x00002C
}

上面复合节点规范示例中显示的第一个节点 (Node 0) 与通过 AddCompositeNodeSpec() 创建的平台设备匹配。第一个父级规范由 AddCompositeSpec() 插入,旨在与平台设备匹配,其中包含 VID, PID 中的绑定规则和属性,以及 fpbus::Node dev 中提供的 DID。其余父级规范来自传入的复合节点规范。

3. 为复合驱动程序定义绑定规则

定义复合节点规范后,您就可以开始为复合驱动程序编写绑定规则,这些规则将与根据复合节点规范创建的复合节点匹配。

为复合驱动程序编写绑定规则的过程与为驱动程序编写绑定规则类似。

前面部分中的示例在其父级规范中包含以下属性:

i2c parent specification properties {
     fuchsia.hardware.i2c.Service: fuchsia.hardware.i2c.Service.ZirconTransport,
     fuchsia.BIND_I2C_ADDRESS: fuchsia.focaltech.platform.BIND_I2C_ADDRESS_TOUCH,
}

gpio-interrupt parent specification properties {
     fuchsia.BIND_PROTOCOL: fuchsia.gpio.BIND_PROTOCOL_DEVICE,
     fuchsia.gpio.FUNCTION: fuchsia.gpio.FUNCTION.TOUCH_INTERRUPT,
}

如果您想将上述属性绑定到复合节点规范,可以编写以下复合绑定规则,以匹配目标父级规范:

composite focaltech_touch;

using fuchsia.gpio;
using fuchsia.hardware.i2c;
using fuchsia.i2c;

primary node "i2c" {
  fuchsia.hardware.i2c.Service == fuchsia.hardware.i2c.Service.ZirconTransport;
  fuchsia.BIND_I2C_ADDRESS == fuchsia.i2c.BIND_I2C_ADDRESS.FOCALTECH_TOUCH;
}

node "gpio-int" {
  fuchsia.BIND_PROTOCOL == fuchsia.gpio.BIND_PROTOCOL.DEVICE;
  fuchsia.gpio.FUNCTION == fuchsia.gpio.FUNCTION.TOUCH_INTERRUPT;
}

附录

调试复合驱动程序问题

如需验证复合节点是否已成功创建并尝试绑定复合驱动程序,您可以检查日志并查找类似于以下行语句的语句:

Binding driver fuchsia-boot:///#meta/focaltech.cm

如需验证复合节点规范是否已成功添加并与复合驱动程序匹配,请运行以下命令:

ffx driver list-composite-node-specs -v

此命令会输出类似于以下内容的输出:

Name      : ft3x27_touch
Driver    : fuchsia-boot:///#meta/focaltech.cm
Nodes     : 2
Node 0    : "i2c" (Primary)
  3 Bind Rules
  [ 1/ 3] : Accept "fuchsia.hardware.i2c.Service" { "fuchsia.hardware.i2c.Service.ZirconTransport" }
  [ 2/ 3] : Accept "fuchsia.BIND_I2C_BUS_ID" { 0x000001 }
  [ 3/ 3] : Accept "fuchsia.BIND_I2C_ADDRESS" { 0x000038 }
  2 Properties
  [ 1/ 2] : Key "fuchsia.hardware.i2c.Service" Value "fuchsia.hardware.i2c.Service.ZirconTransport"
  [ 2/ 2] : Key "fuchsia.BIND_I2C_ADDRESS"     Value 0x000038
Node 1    : "gpio-int"
  2 Bind Rules
  [ 1/ 2] : Accept "fuchsia.BIND_PROTOCOL" { 0x000014 }
  [ 2/ 2] : Accept "fuchsia.BIND_GPIO_PIN" { 0x000004 }
  2 Properties
  [ 1/ 2] : Key "fuchsia.BIND_PROTOCOL"        Value 0x000014
  [ 2/ 2] : Key "fuchsia.gpio.FUNCTION"        Value "fuchsia.gpio.FUNCTION.TOUCH_INTERRUPT"

如果没有与复合节点规范匹配的复合驱动程序,该命令将输出类似于以下内容的输出:

Name      : focaltech_touch
Driver    : None
Nodes     : 2
Node 0    : None
  3 Bind Rules
  [ 1/ 3] : Accept "fuchsia.hardware.i2c.Service" { "fuchsia.hardware.i2c.Service.ZirconTransport" }
  [ 2/ 3] : Accept "fuchsia.BIND_I2C_BUS_ID" { 0x000001 }
  [ 3/ 3] : Accept "fuchsia.BIND_I2C_ADDRESS" { 0x000038 }
  1 Properties
  [ 1/ 2] : Key "fuchsia.hardware.i2c.Service" Value "fuchsia.hardware.i2c.Service.ZirconTransport"
  [ 2/ 2] : Key "fuchsia.BIND_I2C_ADDRESS"     Value 0x000038
Node 1    : None
  2 Bind Rules
  [ 1/ 2] : Accept "fuchsia.BIND_PROTOCOL" { 0x000014 }
  [ 2/ 2] : Accept "fuchsia.BIND_GPIO_PIN" { 0x000004 }
  2 Properties
  [ 1/ 2] : Key "fuchsia.BIND_PROTOCOL"        Value 0x000014
  [ 2/ 2] : Key "fuchsia.gpio.FUNCTION"        Value "fuchsia.gpio.FUNCTION.TOUCH_INTERRUPT

如需详细了解 ffx driver 命令,请参阅查看驱动程序信息