This guide walks through the steps for writing bind rules using the
[`i2c_temperature`](https://fuchsia.googlesource.com/sdk-samples/drivers/+/refs/heads/main/src/i2c_temperature/) sample driver.

For a driver to bind to a [node](https://fuchsia.dev/docs/concepts/drivers/drivers_and_nodes) (which represents a hardware
or virtual device), the driver's bind rules must match the node properties of the
node. In this guide, we'll write bind rules for the `i2c_temperature` sample
driver so that they match the node properties of the `i2c-child` node.

The `i2c_controller` driver creates a child node named `i2c-child` for testing
the `i2c_temperature` sample driver. We can use this `i2c_controller` driver to
identify the node properties of the `i2c-child` node and write the matching
bind rules for `i2c_temperature`.

Before you begin, writing bind rules requires familiarity with the concepts
in [Driver binding](https://fuchsia.dev/docs/concepts/drivers/driver_binding).

The steps are:

1. [Identify the node properties](https://fuchsia.dev/fuchsia-src/development/sdk/write-bind-rules-for-driver#identify-bind-properties).
2. [Write the bind rules](https://fuchsia.dev/fuchsia-src/development/sdk/write-bind-rules-for-driver#write-bind-rules).
3. [Add a Bazel build target for the bind rules](https://fuchsia.dev/fuchsia-src/development/sdk/write-bind-rules-for-driver#add-a-bazel-build-target).

## 1. Identify the node properties

You can identify the node properties of your target node in one of the following ways:

- [Use the ffx driver list-devices command](https://fuchsia.dev/fuchsia-src/development/sdk/write-bind-rules-for-driver#use-ffx-driver-list-devices)
- [Look up the node properties in the driver source code](https://fuchsia.dev/fuchsia-src/development/sdk/write-bind-rules-for-driver#look-up-the-driver-source-code)

### Use the ffx driver list-devices command

To print the properties of every node in the Fuchsia system, run the following command:

    ffx driver list-devices -v

This command prints the properties of a node in the following format:

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

The output above shows that the `i2c-child` node has the following node properties:

- Property key `fuchsia.Service` with a string value of `"fuchsia.hardware.i2c.Service"`.
- Property key `fuchsia.BIND_I2C_ADDRESS` with an integer value of `0xFF`.

### Look up the node properties in the driver source code

When adding a child node, drivers can provide node properties to the node.
Reviewing the source code of the driver that creates your target node as a child
node helps you identify the node properties to include in your bind rules.

The `i2c_controller` driver creates a child node named `i2c-child` to which the
`i2c_temperature` sample driver binds. Examine the source code of the
`i2c_controller` driver to identify which node properties are passed to this
child node:

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

This code shows that the `i2c-child` node is created with the following bind
properties:

- Property key `fuchsia.Service` with a string value of `"fuchsia.hardware.i2c.Service"`.
- Property key `fuchsia.BIND_I2C_ADDRESS` with an integer value of `0xFF`.

> [!NOTE]
> **Note:** For more information on the `NodeAddArgs` struct used to pass the bind properties to a child node, see [NodeProperty and NodeAddArgs structs](https://fuchsia.dev/fuchsia-src/development/sdk/write-bind-rules-for-driver#nodeproperty-and-nodeaddargs-structs).

## 2. Write the bind rules

Once you know the node properties you want to match, you can use the bind
language to write the bind rules for your driver.

In the previous section, we've identified that the `i2c-child` node has the
following node properties:

- Property key `fuchsia.Service` with a string value of `"fuchsia.hardware.i2c.Service"`.
- Property key `fuchsia.BIND_I2C_ADDRESS` with an integer value of `0xFF`.

To match these properties, the `i2c_temperature` driver declares the following
bind rules:

    using fuchsia.hardware.i2c;

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

Integer-based node property keys that start with `BIND_` (defined in
[`binding_priv.h`](https://cs.opensource.google/fuchsia/fuchsia/+/main:/src/lib/ddk/include/lib/ddk/binding_priv.h) in the Fuchsia source tree) are old property
keys currently hardcoded in the bind compiler. See the following definition for
`BIND_I2C_ADDRESS` from `binding_priv.h`:

    #define BIND_I2C_ADDRESS 0x0A02

When these keys are used in bind rules, they are prefixed with `fuchsia.`.

## 3. Add a Bazel build target for the bind rules

Once you have written the bind rules for your driver, you need to update the
`BUILD.bazel` file to add a build target for the bind rules bytecode using the
`fuchsia_driver_bytecode_bind_rules()` template:

    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",
        ],
    )

For each library used in your bind rules, add the library as a dependency to the
build target. For example, the `i2c_temperature` sample driver's bind rules use
the `fuchsia.hardware.i2c` library, so the build target includes the bind library
as a build dependency.

To determine which bind libraries are used in the bind rules, you can examine
the driver source code. In the node properties of the `i2c-child` node, the
first property key `fuchsia.hardware.i2c.Service` is from a generated bind
library from the FIDL protocol:

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

The prefix `fuchsia_hardware_i2c` implies that this node property's key and
value are defined in the following header:

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

These bind libraries will have corresponding dependencies in the driver's build
rules. See the following `fuchsia.hardware.i2c` dependency in the `i2c_controller`
binary target:

    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",
        ],
    )

> [!NOTE]
> **Note:** For more information on the generated bind library, see [Create a new bind library for a driver](https://fuchsia.dev/docs/development/sdk/create-new-bind-library-for-driver).

## Appendices

### NodeProperty and NodeAddArgs structs

Node properties are represented by the `NodeProperty` struct in the
`fuchsia.driver.framework` FIDL library:

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

Then the node properties are passed to a child node using the `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;
    };

[](https://issues.fuchsia.dev/issues/new?component=1439230&template=1881640&description=Issue+on:+https://fuchsia.dev/docs/development/sdk/write-bind-rules-for-driver.md "Report a bug or suggest improvements on this page") [](https://cs.opensource.google/fuchsia/fuchsia/+/main:docs/development/sdk/write-bind-rules-for-driver.md "View the source code of this page") [](https://ci.android.com/edit?repo=fuchsia/fuchsia/main&file=docs/development/sdk/write-bind-rules-for-driver.md&cloneRepo=fuchsia/fuchsia:refs/heads/main&fullPath=fuchsia/docs/development/sdk/write-bind-rules-for-driver.md "Edit the source code of this page")