blob: b844b063ee38399b43caffd772bd5e417068daf0 [file] [log] [blame] [view]
# Connect and serve Banjo protocols in a DFv2 driver
This guide walks through the tasks of serving Banjo protocols in a DFv2 driver
and connecting to its Banjo server from a DFv1 child driver.
Banjo protocols, primarily used in DFv1 drivers, are defined in FIDL library
annotated with the `@transport("Banjo")` and `@banjo_layout("ddk-protocol")`
lines, for example:
```cpp {:.devsite-disable-click-to-copy}
/// The protocol provides access to functions of the driver.
{{"<strong>"}}@transport("Banjo"){{"</strong>"}}
{{"<strong>"}}@banjo_layout("ddk-protocol"){{"</strong>"}}
closed protocol Misc {
/// Returns a unique identifier for this device.
strict GetHardwareId() -> (struct {
status zx.Status;
response uint32;
});
/// Returns the current device firmware version
strict GetFirmwareVersion() -> (struct {
status zx.Status;
major uint32;
minor uint32;
});
};
```
(Source: [`gizmo.test.fidl`][gizmo-test-fidl])
To enable a DFv2 driver to use Banjo protocols, see the tasks below:
- [Serve a Banjo protocol from a DFv2 driver](#serve-a-bano-protocol-from-a-dfv2-driver):
Implement and serve Banjo protocols in a DFv2 driver, which sets up
the driver to communicate with child drivers using Banjo protocols.
- [Connect to a Banjo server from a DFv2 driver](#connect-to-a-banjo-server-from-a-DFv2-driver):
Connect to a parent driver's Banjo server from a DFv2 child driver
and start using Banjo protocols.
## Serve a Banjo protocol from a DFv2 driver {:#serve-a-bano-protocol-from-a-dfv2-driver}
This section walks through implementing a Banjo protocol in a DFv2 driver
and serving the protocol to child drivers. This walkthrough is based
on the [Banjo Transport example][banjo-transport-example], which implements
the `Misc` Banjo protocol in the [`gizmo.test`][gizmo-test-fidl] FIDL library.
The steps are:
1. [Set up the Banjo protocol](#set-up-the-banjo-protocol).
2. [Implement the Banjo protocol](#implement-the-banjo-protocol).
3. [Serve the Banjo protocol](#serve-the-banjo-protocol).
### 1. Set up the Banjo protocol {:#set-up-the-banjo-protocol}
To set up the `Misc` Banjo protocol in a DFv2 driver, do the following:
1. In the `BUILD.gn` file, add the Banjo library as a dependency in the
`fuchsia_driver` target, for example:
```gn {:.devsite-disable-click-to-copy}
fuchsia_cc_driver("parent_driver") {
output_name = "banjo_transport_parent"
sources = [ "parent-driver.cc" ]
deps = [
"//examples/drivers/bind_library:gizmo.example_cpp",
{{"<strong>"}}"//examples/drivers/transport/banjo:fuchsia.examples.gizmo_banjo_cpp",{{"</strong>"}}
...
]
}
```
1. In the driver's C++ header file, include the Banjo library's C++ header, for
example:
```cpp {:.devsite-disable-click-to-copy}
{{"<strong>"}}#include <fuchsia/examples/gizmo/cpp/banjo.h>{{"</strong>"}}
...
namespace banjo_transport {
...
```
(Source: [`parent-driver.h`][parent-driver-h])
1. To inherit from the Banjo protocol bindings, update the driver class using
the following format:
```cpp
ddk::<PROTOCOL_NAME>Protocol<<YOUR_DRIVER_CLASS>>
```
Replace `PROTOCOL_NAME` with the name of the Banjo protocol and
`YOUR_DRIVER_CLASS` is the class of your driver, both in camel case,
for example:
```cpp {:.devsite-disable-click-to-copy}
class ParentBanjoTransportDriver : public fdf::DriverBase,
{{"<strong>"}}public ddk::MiscProtocol<ParentBanjoTransportDriver>{{"</strong>"}} {
...
};
```
(Source: [`parent-driver.h`][parent-driver-h])
### 2. Implement the Banjo protocol {:#implement-the-banjo-protocol}
In the driver class, define and implement each function in the Banjo
protocol.
For instance, the example below shows a Banjo protocol named `ProtocolName`:
```cpp {:.devsite-disable-click-to-copy}
@transport("Banjo")
@banjo_layout("ddk-protocol")
closed protocol ProtocolName {
/// Returns a unique identifier for this device.
strict FunctionName() -> (struct {
status zx.Status;
response_1 response_1_type;
response_2 response_2_type;
});
};
```
For this `ProtocolName` Banjo protocol, the C++ binding for the
`FunctionName` function looks like below:
```cpp {:.devsite-disable-click-to-copy}
zx_status_t ProtocolNameFunctionName(response_1_type* response_1, response_2_type* response_2);
```
And you can find the C++ bindings of the existing Banjo protocols
in the following path of the Fuchsia source checkout:
```none {:.devsite-disable-click-to-copy}
<OUT_DIRECTORY>/fidling/gen/<PATH_TO_THE_FIDL_LIBRARY>/banjo
```
For instance, if your `out` directory is `out/default` and the FIDL
library is located in the `examples/drivers/transport` directory,
then the C++ bindings are located in the following directory:
```none {:.devsite-disable-click-to-copy}
out/default/fidling/gen/examples/drivers/transport/banjo
```
See the following implementation in the [Banjo Transport example][banjo-transport-example]:
- The `Misc` protocol contains the functions below:
```cpp {:.devsite-disable-click-to-copy}
/// Returns a unique identifier for this device.
strict GetHardwareId() -> (struct {
status zx.Status;
response uint32;
});
/// Returns the current device firmware version
strict GetFirmwareVersion() -> (struct {
status zx.Status;
major uint32;
minor uint32;
});
```
- The `ParentBanjoTransportDriver` class defines these functions as
below:
```cpp {:.devsite-disable-click-to-copy}
class ParentBanjoTransportDriver : public fdf::DriverBase,
public ddk::MiscProtocol<ParentBanjoTransportDriver> {
public:
...
// MiscProtocol implementation.
zx_status_t MiscGetHardwareId(uint32_t* out_response);
zx_status_t MiscGetFirmwareVersion(uint32_t* out_major, uint32_t* out_minor);
...
};
```
(Source: [`parent-driver.h`][parent-driver-h])
- The functions are implemented as below:
```cpp {:.devsite-disable-click-to-copy}
zx_status_t ParentBanjoTransportDriver::MiscGetHardwareId(uint32_t* out_response) {
*out_response = 0x1234ABCD;
return ZX_OK;
}
zx_status_t ParentBanjoTransportDriver::MiscGetFirmwareVersion(uint32_t* out_major,
uint32_t* out_minor) {
*out_major = 0x0;
*out_minor = 0x1;
return ZX_OK;
}
```
(Source: [`parent-driver.cc`][parent-driver-cc])
### 3. Serve the Banjo protocol {:#serve-the-banjo-protocol}
Once the Banjo protocol is implemented in a DFv2 driver, you need to
serve the protocol to a DFv1 child node using a compat device server
configured with Banjo.
To do so, complete the following tasks in the
[Set up the compat device server in a DFv2 driver][set-up-the-compat-device-server-in-a-dfv2-driver]
guide:
1. [Set up the compat device server][set-up-the-compat-device-server].
2. [Provide Banjo services to descendant DFv1 drivers][provide-banjo-services].
## Connect to a Banjo server from a DFv2 driver {:#connect-to-a-banjo-server-from-a-DFv2-driver}
This section uses the [Banjo transport example][banjo-transport-example]
to walk through the task of connecting a DFv2 child driver to a parent
driver that serves a Banjo protocol.
The steps are:
1. [Connect the child driver to the parent driver](#connect-the-child-driver-to-the-parent-driver).
2. [Use the Banjo protocol](#use-the-banjo-protocol).
### 1. Connect the child driver to the parent driver {:#connect-the-child-driver-to-the-parent-driver}
To be able to connect a child driver to a parent driver for using Banjo
protocols, the child must be co-located in the same driver host as the parent
and both drivers need to use the compat [`banjo_client`][banjo-client] library.
To connect the child driver to the parent driver, do the following:
1. In the child driver's component manifest (`.cml`), set the `colocate`
field to `true`, for example:
```cml {:.devsite-disable-click-to-copy}
{
include: [ 'syslog/client.shard.cml' ],
program: {
runner: 'driver',
binary: 'driver/banjo_transport_child.so',
bind: 'meta/bind/child-driver.bindbc',
// Run in the same driver host as the parent driver
{{"<strong>"}}colocate: 'true',{{"</strong>"}}
},
use: [
{ service: 'fuchsia.driver.compat.Service' },
],
}
```
(Source: [`child-driver.cml`][child-driver-cml])
1. In the child driver's `BUILD.gn` file, add the Banjo library as
a dependency in the `fuchsia_driver` target, for example:
```gn {:.devsite-disable-click-to-copy}
fuchsia_cc_driver("child_driver") {
output_name = "banjo_transport_child"
sources = [ "child-driver.cc" ]
deps = [
{{"<strong>"}}"//examples/drivers/transport/banjo:fuchsia.examples.gizmo_banjo_cpp",{{"</strong>"}}
"//sdk/lib/driver/component/cpp:cpp",
"//src/devices/lib/driver:driver_runtime",
]
}
```
(Source: [`BUILD.gn`][build-gn])
1. In the child driver's C++ header file, include the Banjo library's
C++ header, for example:
```
{{"<strong>"}}#include <fuchsia/examples/gizmo/cpp/banjo.h>{{"</strong>"}}
...
namespace banjo_transport {
...
```
(Source: [`child-driver.h`][child-driver-h])
1. In the child driver's `BUILD.gn` file, add the compat `banjo_client`
library as a dependency in the `fuchsia_driver` target, for example:
```gn {:.devsite-disable-click-to-copy}
fuchsia_cc_driver("child_driver") {
output_name = "banjo_transport_child"
sources = [ "child-driver.cc" ]
deps = [
"//examples/drivers/transport/banjo:fuchsia.examples.gizmo_banjo_cpp",
{{"<strong>"}}"//sdk/lib/driver/compat/cpp",{{"</strong>"}}
"//sdk/lib/driver/component/cpp:cpp",
"//src/devices/lib/driver:driver_runtime",
]
}
```
(Source: [`BUILD.gn`][build-gn])
1. In the child driver's C++ source file, include the compat `banjo_client`
library's C++ header, for example:
```cpp {:.devsite-disable-click-to-copy}
#include "examples/drivers/transport/banjo/v2/child-driver.h"
{{"<strong>"}}#include <lib/driver/compat/cpp/compat.h>{{"</strong>"}}
#include <lib/driver/component/cpp/driver_export.h>
#include <lib/driver/logging/cpp/structured_logger.h>
namespace banjo_transport {
zx::result<> ChildBanjoTransportDriver::Start() {
...
```
(Source: [`child-driver.cc`][child-driver-cc])
1. In the child driver's C++ source file, set up a Banjo client with the
`compat::ConnectBanjo()` function, for example:
```cpp
zx::result<Client> ConnectBanjo(const std::shared_ptr<fdf::Namespace>& incoming,
std::string_view parent_name = "default") {
```
In the [Banjo Transport example][banjo-transport-example], the child
driver does the following to connect to the `Misc` protocol:
```cpp {:.devsite-disable-click-to-copy}
zx::result<ddk::MiscProtocolClient> client =
compat::ConnectBanjo<ddk::MiscProtocolClient>(incoming());
if (client.is_error()) {
FDF_SLOG(ERROR, "Failed to connect client", KV("status",
client.status_string()));
return client.take_error();
}
```
(Source: [`child-driver.cc`][child-driver-cc])
### 2. Use the Banjo protocol {:#use-the-banjo-protocol}
In the child driver, use the protocol client to invoke the Banjo functions.
For instance, the example below shows a Banjo protocol named
`ProtocolName`:
```cpp {:.devsite-disable-click-to-copy}
@transport("Banjo")
@banjo_layout("ddk-protocol")
closed protocol ProtocolName {
/// Returns a unique identifier for this device.
strict FunctionName() -> (struct {
status zx.Status;
response_1 response_1_type;
response_2 response_2_type;
});
};
```
For this `ProtocolName` Banjo protocol, the C++ binding for the
`FunctionName` function looks like below:
```cpp {:.devsite-disable-click-to-copy}
zx_status_t ProtocolNameFunctionName(response_1_type* response_1, response_2_type* response_2);
```
In the [Banjo Transport example][banjo-transport-example],
the `GetHardwareId()` function is defined as below:
```cpp {:.devsite-disable-click-to-copy}
/// Returns a unique identifier for this device.
strict GetHardwareId() -> (struct {
status zx.Status;
response uint32;
});
```
(Source: [`gizmo.test.fidl`][gizmo-test-fidl])
With the Banjo client stored in the `client_` object
and the `hardware_id_` variable defined as
a `uint32_t`, you can call the `GetHardwareId()` function
in the following way:
```cpp {:.devsite-disable-click-to-copy}
zx_status_t status = client_.GetHardwareId(&hardware_id_);
if (status != ZX_OK) {
return status;
}
```
(Source: [`child-driver.cc`][child-driver-cc])
<!-- Reference links -->
[banjo-transport-example]: https://cs.opensource.google/fuchsia/fuchsia/+/main:examples/drivers/transport/banjo/v2/
[gizmo-test-fidl]: https://cs.opensource.google/fuchsia/fuchsia/+/main:examples/drivers/transport/banjo/gizmo.test.fidl
[parent-driver-h]: https://cs.opensource.google/fuchsia/fuchsia/+/main:examples/drivers/transport/banjo/v2/parent-driver.h
[parent-driver-cc]: https://cs.opensource.google/fuchsia/fuchsia/+/main:examples/drivers/transport/banjo/v2/parent-driver.cc
[set-up-the-compat-device-server-in-a-dfv2-driver]: /docs/development/drivers/migration/set-up-compat-device-server.md
[set-up-the-compat-device-server]: /docs/development/drivers/migration/set-up-compat-device-server.md#set-up-the-compat-device-server
[child-driver-cml]: https://cs.opensource.google/fuchsia/fuchsia/+/main:examples/drivers/transport/banjo/v2/meta/child-driver.cml
[build-gn]: https://cs.opensource.google/fuchsia/fuchsia/+/main:examples/drivers/transport/banjo/v2/BUILD.gn
[child-driver-h]: https://cs.opensource.google/fuchsia/fuchsia/+/main:examples/drivers/transport/banjo/v2/child-driver.h
[child-driver-cc]: https://cs.opensource.google/fuchsia/fuchsia/+/main:examples/drivers/transport/banjo/v2/child-driver.cc
[provide-banjo-services]: /docs/development/drivers/migration/set-up-compat-device-server.md#provide-banjo-services-to-descendant-dfv1-drivers
[banjo-client]: https://cs.opensource.google/fuchsia/fuchsia/+/main:sdk/lib/driver/compat/cpp/banjo_client.h