使用 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 通訊協定,並將通訊協定提供給 DFv1 子項驅動程式庫程式。本逐步操作說明是以 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 函式的 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. 提供 Banjo 通訊協定

在 DFv2 驅動程式中實作 Banjo 通訊協定後,您需要使用以 Banjo 設定的相容裝置伺服器,將通訊協定提供給 DFv1 子節點。

如要這麼做,請完成「在 DFv2 驅動程式中設定 compat 裝置伺服器」指南中的工作:

  1. 設定 compat 裝置伺服器
  2. 為子系 DFv1 驅動程式提供 Banjo 服務

從 DFv1 驅動程式庫連線至 Banjo 伺服器

本節使用 Banjo 傳輸範例,逐步說明如何將 DFv1 子項驅動程式庫連線至提供 Banjo 通訊協定的 DFv2 父項驅動程式庫。

步驟如下:

  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 檔案中,將 Compat 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++ 來源檔案中,加入 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)

  6. 在驅動程式庫的 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)