複合節點

總覽

本指南說明如何使用以下程式碼,將複合節點新增至驅動程式架構: 複合節點規格本文假設您熟悉下列項目:

建立複合式節點

複合節點節點 。如要建立 您需要執行以下動作:

  • 在驅動程式庫中定義複合節點規格
  • 使用符合規格的繫結規則建立複合驅動程式庫

如果 駕駛 會定義規格 程序如下:

  1. 駕駛管理員 詢問 驅動程式庫索引,找出符合規格的複合驅動程式庫
  2. 找到相符的複合驅動程式庫後,驅動程式管理器會尋找節點 找到符合每個父項規格的拓撲每個相符的節點 成為複合節點的父項
  3. 所有父項規格都相符後,驅動程式管理器會建立 這些複合節點和節點做為父項,然後將複合驅動程式庫繫結至 基礎架構主要節點和節點名稱由複合式驅動程式庫提供。

composite-node-spec-bind-diagram

定義複合節點規格

複合節點規格是一組父項規格, 會將複合節點設為父項節點每個父項規格都包含 包括:

  • 繫結規則 - 繫結規則 的 會將父項規格與節點進行比對
  • 屬性 - 用於比對的父項規格中的屬性 是否符合複合驅動程式庫的繫結規則這些執行個體採用的格式與節點相同 資源。

繫結規則

繫結規則可用來尋找節點,並比對節點與父項規格。 系統會依據繫結規則評估節點屬性,如果兩者相符,系統就會評估節點屬性 會成為複合的父項

父項規格的繫結規則由 以及遭拒的屬性值如要比對繫結規則,節點屬性 必須包含所有已接受的節點屬性值,但不得使用任何遭拒的節點屬性值 服務。

舉例來說,如果父項規格包含繫結規則:

  • 接受 fuchsia.BIND_PROTOCOL 值:15 和 17
  • 拒絕 fuchsia.BIND_PLATFORM_DEV_VID 值「Intel」

接著,如果裝置包含 15 或 17 的 fuchsia.BIND_PROTOCOL 屬性,不含「Intel」值 fuchsia.BIND_PLATFORM_DEV_VID 屬性。

判斷繫結規則

判斷繫結規則應具備的程序 繫結語言中的規則。 為判斷繫結規則,您必須先找出節點的屬性 清單,以便建立繫結

您可以使用 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"

轉儲作業中的節點屬性為:

  • fuchsia.I2C_BUS_ID = 0x01
  • fuchsia.I2C_ADDRESS = 0x38
  • fuchsia.hardware.i2c.Service = fuchsia.hardware.i2c.Service.ZirconTransport

您可以透過繫結程式庫搜尋屬性值 (例如 在 src/devices/bind 中繫結程式庫)。在本例中。自 節點為 I2C 節點,屬性值位於 fuchsia.i2c.bind

fuchsia.i2c.bind

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

我們也會從 FIDL 程式庫產生繫結程式庫, fuchsia.hardware.i2c.Service,其值 fuchsia.hardware.i2c.Service.ZirconTransport 成本來源詳情請見 generated-bind-libraries 瞭解詳情。

如此一來,我們就能將節點屬性重新對應到:

  • 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

您可以在驅動程式庫原始碼中,透過 產生的程式庫詳情請參閱 繫結程式庫 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 }

編寫驅動程式架構 v1 (DFv1)

在 DFv1 中,複合節點規格是以 DDK 編寫。函式 寫入繫結規則 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),
};

編寫驅動程式架構 v2 (DFv2)

在 DFv2 中,系統會以 composite_node_spec.fidl敬上 fuchsia.driver.framework FIDL 程式庫。 composite_node_spec.h敬上 sdk/lib/driver/component/cpp 中的程式庫可簡化定義 繫結規則。

使用該程式庫並繫結程式庫 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),
};

屬性

屬性是鍵/值組合,用來比對 複合驅動程式的繫結規則的父項規格。 這些項目與節點屬性相同,因此格式相同。 屬性鍵可以是整數或字串式,而屬性值則可以 是整數、布林值、字串或列舉類型。

編寫驅動程式架構 v1 (DFv1)

在 DFv1 中,複合節點規格是以 DDK 編寫,並使用函式 寫入繫結規則 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),
};

編寫驅動程式架構 v2 (DFv2)

在 DFv2 中,系統會以 composite_node_spec.fidl敬上 儲存在 fuchsia.driver.framework FIDL 程式庫中。 node_add_args.h 圖書館位於 //sdk/lib/driver/component/cpp 可用於簡化定義繫結機制 不過,編寫這類演算法並不容易 因為我們無法寫出所有可能的規則

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

新增複合節點規格

如要建立複合節點規格,必須定義並新增一組 套用至驅動程式管理器。

平台公車複合資料

如果複合節點需要來自 月台公車 那麼 桌遊駕駛 可將複合式節點 透過 kubectl 指令 platform_bus.fidl 也能使用 Google Cloud CLI 或 Compute Engine 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;

平台 Bus API 使用在CompositeNodeSpec composite_node_spec.fidl。 詳情請見 使用 FIDL 定義複合式節點規格 一文。

舉例來說,假設我們定義了以下複合節點規格:

auto bind_rules = std::vector{
    driver::MakeAcceptBindRule(bind_fuchsia_hardware_i2c::SERVICE,
        bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
    driver::MakeAcceptBindRule(bind_fuchsia::I2C_ADDRESS,
        bind_fuchsia_i2c::BIND_I2C_ADDRESS_BACKLIGHT),
};

auto properties = std::vector{
    driver::MakeProperty(bind_fuchsia_hardware_i2c::SERVICE,
        bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
    driver::MakeProperty(bind_fuchsia::I2C_ADDRESS,
        bind_fuchsia_i2c::BIND_I2C_ADDRESS_BACKLIGHT),
};

auto spec = std::vector{
    fuchsia_driver_framework::ParentSpecification{
        .bind_rules = bind_rules,
        .properties = properties,
    },
};

定義複合節點規格後,主機板驅動程式庫就能 透過 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()) {
    zxlogf(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
}

第一個父項規格是由 AddCompositeSpec() 插入,且相符 平台裝置,其中包含來自 VID、PID、 和 DIDfpbus::Node dev。其餘的父項規格 傳入的複合式節點規格中。

驅動程式架構 v1 (DFv1)

在 DFv1 中,驅動程式庫可透過 DDK 程式庫新增複合節點規格 透過 DdkAddCompositeNodeSpec() 函式呼叫 API。

驅動程式必須先在 spec.h 程式庫中定義 CompositeNodeSpec。使用 上述繫結的規則和屬性,我們就可以定義 CompositeNodeSpec,並使用 I2C 父項規格:

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);

中繼資料可以透過多種方式傳遞至複合節點規格的複合資料 set_metadata() 函式。

CompositeNodeSpec 準備就緒後,您就能加入 DdkAddCompositeNodeSpec():

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

由於 CompositeNodeSpec 遵循建構工具模式,因此這可以簡化為:

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

驅動程式架構 v2 (DFv2)

在 DFv2 中,我們使用 fuchsia.driver.framework 中的 CompositeNodeManager FIDL API,用於新增複合節點規格。

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

使用 FIDL 定義複合節點規格

CompositeNodeSpec 結構已定義於 composite_node_spec.fidl。 您可以使用 spec.hnode_add_args.h 函式 sdk/lib/driver/component/cpp程式庫中,定義繫結規則和 父項規格的屬性。

我們可以透過程式庫,使用父項定義複合節點規格 I2C 節點和 gpio-繼續執行節點的規格:

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),
};

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


auto gpio_interrupt_bind_rules = std::vector {
    MakeAcceptBindRule(bind_fuchsia::BIND_PROTOCOL,
                       bind_fuchsia_gpio::BIND_PROTOCOL_DEVICE),
    MakeAcceptBindRule(bind_fuchsia::GPIO_PIN,
                       bind_fuchsia_amlogic_platform_s905d2::GPIOZ_PIN_ID_PIN_4),
};

auto gpio_interrupt_properties[] = std::vector {
    ddk::MakeProperty(bind_fuchsia::BIND_PROTOCOL,
                      bind_fuchsia_gpio::FUNCTION_TOUCH_INTERRUPT),
};

auto nodes = std::vector{
      fdf::ParentSpec{
          .bind_rules = i2c_bind_rules,
          .properties = i2c_properties,
      },
      fdf::ParentSpec{
          .bind_rules = gpio_interrupt_bind_rules,
          .properties = gpio_interrupt_properties,
      },
  };

auto spec = fdf::CompositeNodeSpec {.name = "fo", .nodes = nodes};

新增複合式節點規格

如要將複合節點規格新增至 CompositeNodeManager,您需要 連線至服務:

auto client = incoming()->Connect<fdf::CompositeNodeManager>();

if (client.is_error()) {
  FDF_LOG(ERROR, "Failed to connect to CompositeNodeManager: %s",
      zx_status_get_string(client.error_value()));
  return client.take_error();
}

fidl::SharedClient<fdf::CompositeNodeManager> composite_node_manager;
composite_node_manager.Bind(std::move(client.value()), dispatcher());

然後呼叫 API:

composite_node_manager->AddSpec(std::move(spec))
    .Then([this](
        fidl::Result<fdf::CompositeNodeManager::AddSpec>& create_result) {
            if (create_result.is_error()) {
              FDF_LOG(ERROR, "AddSpec failed: %s",
                  create_result.error_value().FormatDescription().c_str());
              return;
            }
            FDF_LOG(INFO, "Succeeded adding spec");
        });

定義複合驅動程式庫繫結規則

複合驅動程式庫是只會繫結至複合節點的驅動程式庫。驅動因素 透過繫結規則定義詳情請見 複合繫結規則 瞭解詳情

比對程序

比對程序會透過將複合驅動程式的繫結規則套用至 父項規格資源。符合下列條件時即成功比對 已完成:

  • 所有父項規格都必須與複合式繫結規則中的節點相符
  • 所有非選擇性的複合繫結規則節點都必須與父項相符 規格。

比對不會模稜兩可:

  • 每個父項規格只能與一項複合繫結規則對應 節點
  • 每個複合繫結規則節點都必須與最多一個父項相符 規格。選用繫結規則可能符合零個父項規格。
  • 節點不需要依序比對
  • 如果發生不明確的情況,系統會顯示警告訊息。

composite-node-spec-bind-diagram

寫入繫結規則

以上述範例為例,假設我們想繫結至複合節點規格 其父項規格中具有下列屬性:

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