Driver utilities

Driver utilities are Fuchsia applications that communicate with devices used for diagnostics and exported by drivers. For example Inter-Integrated Circuit (I2C) devices can be scanned and communicated through the i2cutil command line utility. For example:

i2cutil ping
/dev/class/i2c/000: OK
[00164.657] 04506:05266> i2c: error on bus
Error -1
/dev/class/i2c/001: ERROR
/dev/class/i2c/002: OK
/dev/class/i2c/003: OK
/dev/class/i2c/004: OK


The communication mechanism between between drivers and applications is FIDL, and hence the FIDL API exported by any given driver fully defines what diagnostics can be performed on it. For instance for I2C, from i2c.fidl, there is a Transfer() FIDL method that allows for writes and reads from I2C devices.

Note: Banjo should not be used for driver utilities application to driver communication.

TODO( Add inspect usage description.


The Fuchsia driver model defines a devfs filesystem, see Device Model, that is the mechanism through which userspace services and applications gain access to devices. As a user, you can navigate the devfs filesystem to see what devices are exported, note that there are multiple ways to access the same device, you can use the lsdev command to find relationships as in:

lsdev /dev/class/i2c/000
topological path for /dev/class/i2c/000: /dev/sys/platform/05:00:2/aml-i2c/i2c/i2c-2-44

Creating new driver utilities


You can discover existing drivers with devfs. New devices become discoverable when their driver performs a DdkAdd() (for C++ drivers) operation.


Existing utilities like spiutil make use of currently existing FIDL APIs. To extend the functionality exported by an existing driver, the FIDL API the existing driver exports can be extended/evolved by following FIDL ABI and API compatibility guide. In cases when there is no existing FIDL API, you need to add new FIDL files to a folder within /sdk/fidl.

To enable FIDL communication in C++ drivers that do not already offer a FIDL API, complete the following steps:

  1. Make the device messagable by deriving from ddk::Messageable.
  2. Add a DdkMessage method to handle incoming FIDL messages.
  3. Add methods for the FIDL protocol methods of the given FIDL API.

For instance for SPI:

using SpiChildType = ddk::Device<SpiChild, ddk::Messageable>;
class SpiChild : public SpiChildType,
                 public llcpp::fuchsia::hardware::spi::Device::Interface,
                 public ddk::SpiProtocol<SpiChild, ddk::base_protocol> {
  zx_status_t DdkMessage(fidl_incoming_msg_t* msg, fidl_txn_t* txn);
  // FIDL methods.
  void Transmit(fidl::VectorView<uint8_t> data, TransmitCompleter::Sync completer) override;


To implement the Fuchsia application that would communicate with the device, call into the FIDL API. For this utilize the FIDL bindings for your language of choice, for C++:

For example for I2C in i2cutil using LLCPP we have:

llcpp::fuchsia::hardware::i2c::Device2::SyncClient client((zx::channel(channel)));
auto read = client.Transfer(...);

This calls the Transfer() method to write and read from an I2C device.