本指南逐步介绍了如何在 DFv2 驱动程序中提供 Banjo 协议,以及如何从 DFv1 子驱动程序连接到其 Banjo 服务器。
Banjo 协议(主要用于 DFv1 驱动程序)在带有 @transport("Banjo")
和 @banjo_layout("ddk-protocol")
行注解的 FIDL 库中定义,例如:
/// The protocol provides access to functions of the driver.
@transport("Banjo")
@banjo_layout("ddk-protocol")
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;
});
};
(来源:gizmo.test.fidl
)
要使 DFv2 驱动程序能够使用 Banjo 协议,请参阅以下任务:
从 DFv2 驱动程序提供 Banjo 协议:在 DFv2 驱动程序中实现和提供 Banjo 协议,该驱动程序可设置驱动程序以与 DFv1 子驱动程序进行通信。
从 DFv1 驱动程序连接到 Banjo 服务器:从 DFv1 子驱动程序连接到 DFv2 父级驱动程序的 Banjo 服务器,然后开始使用 Banjo 协议。
从 DFv2 驱动程序提供 Banjo 协议
本部分逐步介绍了如何在 DFv2 驱动程序中实现 Banjo 协议,以及如何将该协议提供给 DFv1 子驱动程序。本演示基于 Banjo Transport 示例,该示例在 gizmo.test
FIDL 库中实现了 Misc
Banjo 协议。
相关步骤如下:
1. 设置 Banjo 协议
如需在 DFv2 驱动程序中设置 Misc
Banjo 协议,请执行以下操作:
在
BUILD.gn
文件中,将 Banjo 库作为依赖项添加到fuchsia_driver
目标中,例如:fuchsia_driver("parent_driver") { output_name = "banjo_transport_parent" sources = [ "parent-driver.cc" ] deps = [ "//examples/drivers/bind_library:gizmo.example_cpp", "//examples/drivers/transport/banjo:fuchsia.examples.gizmo_banjo_cpp", ... ] }
在驱动程序的 C++ 头文件中,添加 Banjo 库的 C++ 头文件,例如:
#include <fuchsia/examples/gizmo/cpp/banjo.h> ... namespace banjo_transport { ...
(来源:
parent-driver.h
)如需从 Banjo 协议绑定继承,请使用以下格式更新驱动程序类:
ddk::<PROTOCOL_NAME>Protocol<<YOUR_DRIVER_CLASS>>
将
PROTOCOL_NAME
替换为 Banjo 协议的名称,YOUR_DRIVER_CLASS
是驱动程序的类(两者均采用驼峰命名法),例如:class ParentBanjoTransportDriver : public fdf::DriverBase, public ddk::MiscProtocol<ParentBanjoTransportDriver> { ... };
(来源:
parent-driver.h
)
2. 实现 Banjo 协议
在驱动程序类中,定义和实现 Banjo 协议中的每个函数。
例如,以下示例展示了名为 ProtocolName
的 Banjo 协议:
@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;
});
};
对于此 ProtocolName
Banjo 协议,FunctionName
函数的 C++ 绑定如下所示:
zx_status_t ProtocolNameFunctionName(response_1_type* response_1, response_2_type* response_2);
您可以在 Fuchsia 源代码检出的以下路径中找到现有 Banjo 协议的 C++ 绑定:
<OUT_DIRECTORY>/fidling/gen/<PATH_TO_THE_FIDL_LIBRARY>/banjo
例如,如果您的 out
目录为 out/default
且 FIDL 库位于 examples/drivers/transport
目录中,则 C++ 绑定位于以下目录中:
out/default/fidling/gen/examples/drivers/transport/banjo
请参阅 Banjo Transport 示例中的以下实现:
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; });
ParentBanjoTransportDriver
类定义这些函数,如下所示: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); ... };
(来源:
parent-driver.h
)这些函数的实现方式如下:
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; }
(来源:
parent-driver.cc
)
3. 遵循班卓琴的协议
在 DFv2 驱动程序中实现 Banjo 协议后,您需要使用配置了 Banjo 的兼容型设备服务器将该协议提供给 DFv1 子节点。
为此,请完成在 DFv2 驱动程序中设置兼容型设备服务器指南中的以下任务:
从 DFv1 驱动程序连接到 Banjo 服务器
本部分使用 Banjo 传输示例来演示将 DFv1 子驱动程序连接到提供 Banjo 协议的 DFv2 父驱动程序的任务。
相关步骤如下:
1. 将子驱动程序连接到父驱动程序
为了能够将子驱动程序连接到父驱动程序以使用 Banjo 协议,子驱动程序必须与父驱动程序位于同一驱动程序主机中,并且两个驱动程序都需要使用兼容型 banjo_client
库。
如需将子驱动程序连接到父驱动程序,请执行以下操作:
在子驱动程序的组件清单 (
.cml
) 中,将colocate
字段设置为true
,例如:{ 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 colocate: 'true', }, use: [ { service: 'fuchsia.driver.compat.Service' }, ], }
(来源:
child-driver.cml
)在驱动程序的
BUILD.gn
文件中,将 Banjo 库作为依赖项添加到fuchsia_driver
目标中,例如:fuchsia_driver("child_driver") { output_name = "banjo_transport_child" sources = [ "child-driver.cc" ] deps = [ "//examples/drivers/transport/banjo:fuchsia.examples.gizmo_banjo_cpp", "//sdk/lib/driver/component/cpp:cpp", "//src/devices/lib/driver:driver_runtime", ] }
(来源:
BUILD.gn
)在驱动程序的 C++ 头文件中,添加 Banjo 库的 C++ 头文件,例如:
#include <fuchsia/examples/gizmo/cpp/banjo.h> ... namespace banjo_transport { ...
(来源:
child-driver.h
)在驱动程序的
BUILD.gn
文件中,将 compatbanjo_client
库作为依赖项添加到fuchsia_driver
目标中,例如:fuchsia_driver("child_driver") { output_name = "banjo_transport_child" sources = [ "child-driver.cc" ] deps = [ "//examples/drivers/transport/banjo:fuchsia.examples.gizmo_banjo_cpp", "//sdk/lib/driver/compat/cpp", "//sdk/lib/driver/component/cpp:cpp", "//src/devices/lib/driver:driver_runtime", ] }
(来源:
BUILD.gn
)在驱动程序的 C++ 源文件中,添加 compat
banjo_client
库的 C++ 头文件,例如:#include "examples/drivers/transport/banjo/v2/child-driver.h" #include <lib/driver/compat/cpp/compat.h> #include <lib/driver/component/cpp/driver_export.h> #include <lib/driver/logging/cpp/structured_logger.h> namespace banjo_transport { zx::result<> ChildBanjoTransportDriver::Start() { ...
(来源:
child-driver.cc
)在驱动程序的 C++ 源文件中,使用
compat::ConnectBanjo()
函数设置 Banjo 客户端,例如:zx::result<Client> ConnectBanjo(const std::shared_ptr<fdf::Namespace>& incoming, std::string_view parent_name = "default") {
在 Banjo Transport 示例中,子级驱动程序会执行以下操作来连接到
Misc
协议: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(); }
(来源:
child-driver.cc
)
2. 使用 Banjo 协议
在子驱动程序中,使用协议客户端调用 Banjo 函数。
例如,以下示例展示了名为 ProtocolName
的 Banjo 协议:
@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;
});
};
对于此 ProtocolName
Banjo 协议,FunctionName
函数的 C++ 绑定如下所示:
zx_status_t ProtocolNameFunctionName(response_1_type* response_1, response_2_type* response_2);
在 Banjo Transport 示例中,GetHardwareId()
函数的定义如下所示:
/// Returns a unique identifier for this device.
strict GetHardwareId() -> (struct {
status zx.Status;
response uint32;
});
(来源:gizmo.test.fidl
)
将 Banjo 客户端存储在 client_
对象中并将 hardware_id_
变量定义为 uint32_t
后,您可以通过以下方式调用 GetHardwareId()
函数:
zx_status_t status = client_.GetHardwareId(&hardware_id_);
if (status != ZX_OK) {
return status;
}
(来源:child-driver.cc
)