在 DFv2 驱动程序中连接和传送 Banjo 协议

本指南详细介绍了在 DFv2 驱动程序中提供 Banjo 协议的任务 以及从 DFv1 子驱动程序连接到其 Banjo 服务器

Banjo 协议主要用于 DFv1 驱动程序,在 FIDL 库中定义 带有 @transport("Banjo")@banjo_layout("ddk-protocol") 注解 行,例如:

/// 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 协议 并为子驾驶员提供协议本演示基于 请参阅 Banjo Transport 示例,该示例实现了 gizmo.test FIDL 库中的 Misc Banjo 协议。

具体步骤如下:

  1. 设置 Banjo 协议
  2. 实现 Banjo 协议
  3. 提供 Banjo 协议

1. 设置 Banjo 协议

如需在 DFv2 驱动程序中设置 Misc Banjo 协议,请执行以下操作:

  1. 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",
         ...
      ]
    }
    
  2. 在驱动程序的 C++ 头文件中,添加 Banjo 库的 C++ 头文件,以便 示例:

    #include <fuchsia/examples/gizmo/cpp/banjo.h>
    ...
    
    namespace banjo_transport {
    ...
    

    (来源:parent-driver.h

  3. 如需从 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 函数如下所示:

zx_status_t ProtocolNameFunctionName(response_1_type* response_1, response_2_type* response_2);

您还可以找到现有 Banjo 协议的 C++ 绑定 在 Fuchsia 源结账的以下路径中:

<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 传输示例中的以下实现:

  • 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. 提供 Banjo 协议

在 DFv2 驱动程序中实施 Banjo 协议后,您需要 使用兼容型设备服务器将协议传送到 DFv1 子节点

为此,请完成以下任务 在 DFv2 驱动程序中设置兼容型设备服务器 指南:

  1. 设置兼容型设备服务器
  2. 为 DFv1 后代驱动程序提供 Banjo 服务

通过 DFv2 驱动程序连接到 Banjo 服务器

本部分使用 Banjo 传输示例 逐步完成将 DFv2 子驱动程序连接到父驱动程序的任务 提供 Banjo 协议的驱动程序。

具体步骤如下:

  1. 将子驱动程序连接到父驱动程序
  2. 使用 Banjo 协议

1. 将子驱动程序连接到父驱动程序

为了能够为使用 Banjo 的子女司机牵线搭桥 子协议必须与父进程位于同一驱动程序主机中 并且两个驱动程序都需要使用 compat banjo_client 库。

如需将子驱动程序连接到父驱动程序,请执行以下操作:

  1. 在子驱动程序的组件清单 (.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

  2. 在子驱动程序的 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

  3. 在子驱动程序的 C++ 头文件中,添加 Banjo 库的 C++ 头文件,例如:

    #include <fuchsia/examples/gizmo/cpp/banjo.h>
    ...
    
    namespace banjo_transport {
    ...
    

    (来源:child-driver.h

  4. 在子驱动程序的 BUILD.gn 文件中,添加兼容型 banjo_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

  5. 在子驱动程序的 C++ 源文件中,添加兼容型 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

  6. 在子驱动程序的 C++ 源文件中,使用 compat::ConnectBanjo() 函数,例如:

    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 函数。

例如,以下示例展示了一个名为 Banjo 协议, ProtocolName:

@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 函数如下所示:

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