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 driver i2c command line utility. For example:
driver i2c 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
API
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.
TODO(https://fxbug.dev/42122211): Add inspect usage description.
Discovery
The Fuchsia driver model defines a devfs
filesystem (see
Device Model, which 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/i2c-0/aml-i2c/i2c/i2c-2-44
Creating new driver utilities
Discovery
You can discover existing drivers with devfs
. New devices become discoverable
when their driver performs a DdkAdd()
(for C++ drivers) operation.
API
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:
- Make the device messagable by deriving from
ddk::Messageable
. - Add methods for the FIDL protocol methods of the given FIDL API.
For instance for SPI:
using SpiChildType =
ddk::Device<SpiChild, ddk::Messageable<fuchsia_hardware_spi::Device>::Mixin>;
class SpiChild : public SpiChildType,
public ddk::SpiProtocol<SpiChild, ddk::base_protocol> {
...
// FIDL methods.
void Transmit(fidl::VectorView<uint8_t> data, TransmitCompleter::Sync completer) override;
...
Utility
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 the new C++ bindings we have:
fidl::WireSyncClient<fuchsia_hardware_i2c::Device2> client(zx::channel(channel));
auto read = client.Transfer(...);
This calls the Transfer()
method to write and read from an I2C device.