本指南將逐步說明建立最小 DFv2 驅動程式庫的相關步驟。
本指南中的指示是以 架構驅動程式,其中提供基本實作 ,在 Fuchsia 系統中建構、載入及註冊新的 DFv2 驅動程式庫。
步驟如下:
如需更多 DFv2 相關功能,請參閱其他工作。
建立驅動程式庫標頭檔案
如要建立 DFv2 驅動程式庫的標頭檔案,請按照下列步驟操作:
為驅動程式庫建立新的標頭檔案 (
.h
),例如skeleton_driver.h
)。在標頭檔案中加入下列介面:
#include <lib/driver/component/cpp/driver_base.h>
為
DriverBase
類別新增介面。 例如:#include <lib/driver/component/cpp/driver_base.h> namespace skeleton { class SkeletonDriver : public fdf::DriverBase { public: SkeletonDriver(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher driver_dispatcher); // Called by the driver framework to initialize the driver instance. zx::result<> SkeletonDriver::Start() override; }; } // namespace skeleton
(資料來源:
skeleton_driver.h
)
建立驅動程式庫來源檔案
如要實作 DriverBase
類別的基本方法,
:
建立驅動程式庫的新來源檔案 (
.cc
),例如skeleton_driver.cc
)。納入為驅動程式庫建立的標頭檔案,例如:
#include "skeleton_driver.h"
實作類別的基本方法,例如:
#include "skeleton_driver.h" namespace skeleton { SkeletonDriver::SkeletonDriver(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher driver_dispatcher) : DriverBase("skeleton_driver", std::move(start_args), std::move(driver_dispatcher)) { } zx::result<> SkeletonDriver::Start() { return zx::ok(); } } // namespace skeleton
(資料來源:
skeleton_driver.cc
)此驅動程式庫建構函式必須傳遞驅動程式庫名稱 (例如
"skeleton_driver"
、start_args
和driver_dispatcher
都移至DriverBase
類別。
新增驅動程式庫匯出巨集
如要新增驅動程式庫匯出巨集,請按照下列步驟操作:
在驅動程式庫來源檔案中,納入下列標頭檔案:
#include <lib/driver/component/cpp/driver_export.h>
在 驅動程式庫來源檔案的底部:
FUCHSIA_DRIVER_EXPORT(skeleton::SkeletonDriver);
例如:
#include <lib/driver/component/cpp/driver_base.h> #include <lib/driver/component/cpp/driver_export.h> #include "skeleton_driver.h" namespace skeleton { SkeletonDriver::SkeletonDriver(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher driver_dispatcher) : DriverBase("skeleton_driver", std::move(start_args), std::move(driver_dispatcher)) { } zx::result<> SkeletonDriver::Start() { return zx::ok(); } } // namespace skeleton FUCHSIA_DRIVER_EXPORT(skeleton::SkeletonDriver);
(資料來源:
skeleton_driver.cc
)
建立建構檔案
如要為驅動程式庫建立建構檔案,請按照下列步驟操作:
- 建立新的
BUILD.gn
檔案。 加入下列程式碼以匯入驅動程式庫建構規則:
import("//build/drivers.gni")
為驅動程式庫新增目標,例如:
fuchsia_driver("driver") { output_name = "skeleton_driver" sources = [ "skeleton_driver.cc" ] deps = [ "//sdk/lib/driver/component/cpp", "//src/devices/lib/driver:driver_runtime", ] }
(資料來源:
BUILD.gn
)所有驅動程式的
output_name
欄位均不得重複。
寫入繫結規則
如要編寫驅動程式的繫結規則,請按照下列步驟操作:
為驅動程式庫建立新的繫結規則檔案 (
.bind
) (例如skeleton_driver.bind
)。meta
新增基本繫結規則,例如:
using gizmo.example; gizmo.example.TEST_NODE_ID == "skeleton_driver";
(資料來源:
skeleton_driver.bind
)在
BUILD.gn
檔案中,加入下列程式碼以匯入 繫結建構規則:import("//build/bind/bind.gni")
在
BUILD.gn
檔案中,為驅動程式庫的繫結規則新增目標。 例如:driver_bind_rules("bind") { rules = "meta/skeleton.bind" bind_output = "skeleton_driver.bindbc" deps = [ "//examples/drivers/bind_library:gizmo.example" ] }
(資料來源:
BUILD.gn
)所有驅動程式的
bind_output
欄位均不得重複。
建立驅動程式庫元件
如要為驅動程式庫建立 Fuchsia 元件,請按照下列步驟操作:
在
meta
中建立新的元件資訊清單檔案 (.cml
) 目錄內 (例如skeleton_driver.cml
)。必須包含下列元件資料分割:
{ include: [ "inspect/client.shard.cml", "syslog/client.shard.cml", ], }
請使用下列格式新增驅動程式庫
program
資訊:{ program: { runner: "driver", binary: "driver/<OUTPUT_NAME>.so", bind: "meta/bind/<BIND_OUTPUT>", }, }
binary
欄位必須與output_name
BUILD.gn
檔案的fuchsia_driver
目標,以及bind
欄位必須與driver_bind_rules
目標中的bind_output
相符, 例如:{ include: [ "inspect/client.shard.cml", "syslog/client.shard.cml", ], program: { runner: "driver", binary: "driver/skeleton_driver.so", bind: "meta/bind/skeleton.bindbc", }, }
(資料來源:
skeleton_driver.cml
)建立新的 JSON 檔案,提供元件資訊 (例如
component-info.json
)。meta
以 JSON 格式新增驅動程式庫元件資訊,例如:
{ "short_description": "Driver Framework example for a skeleton DFv2 driver", "manufacturer": "", "families": [], "models": [], "areas": [ "DriverFramework" ] }
(資料來源:
component-info.json
)在
BUILD.gn
檔案中,加入下列程式碼以匯入元件 建構規則:import("//build/components.gni")
在
BUILD.gn
檔案中,為驅動程式庫元件新增目標,例如:fuchsia_driver_component("component") { component_name = "skeleton" manifest = "meta/skeleton.cml" deps = [ ":bind", ":driver" ] info = "component-info.json" }
(資料來源:
BUILD.gn
)請參閱下列欄位規則:
- 將
manifest
欄位設為驅動程式庫.cml
檔案的位置。 - 將
info
欄位設為驅動程式庫元件的位置 資訊 JSON 檔案 - 將
deps
陣列設為包含fuchsia_driver
和BUILD.gn
檔案中的driver_bind_rules
目標。
- 將
您現在可以在 Fuchsia 系統中建構、載入及註冊這個 DFv2 驅動程式庫
其他工作
本節提供您可在最小 DFv2 中加入的其他功能 驅動程式庫:
新增記錄檔
根據預設,如要列印 DFv2 驅動程式庫的記錄,請使用 FDF_LOG
巨集。
範例:
FDF_LOG(INFO, "Starting SimpleDriver")
除了使用 FDF_LOG
巨集之外,您也可以使用
Fuchsia 的結構化 Logger 程式庫
(structured_logger.h
),後者會使用
FDF_SLOG
巨集。
如要使用 DFv2 驅動程式的結構化記錄,請按照下列步驟操作:
加入下列標頭:
#include <lib/driver/logging/cpp/structured_logger.h>
使用
FDF_SLOG
巨集輸出記錄,例如:FDF_SLOG(ERROR, "Failed to add child", KV("status", result.status_string()));
新增子節點
DFv2 驅動程式可使用以下 Node
通訊協定新增子節點:
fuchsia.driver.framework
FIDL 程式庫:
open protocol Node {
flexible AddChild(resource struct {
args NodeAddArgs;
controller server_end:NodeController;
node server_end:<Node, optional>;
}) -> () error NodeError;
};
為了方便起見,在啟動期間,驅動程式庫架構會提供
透過 DriverBase
繫結節點的 Node
通訊協定至 DFv2 驅動程式。
驅動程式隨時可以存取節點用戶端,在其上建立子節點。
不過,直接使用這個 FIDL 程式庫需要設定包含
建立 FIDL 管道組合,並建構 NodeAddArgs
資料表。
因此 DriverBase
類別會提供一組輔助函式,以建立
新增子節點(若要瞭解這些輔助工具,請參閱
driver_base.h
file.)
DFv2 驅動程式庫可新增的節點類型有兩種:「非擁有」和「擁有」。 非擁有節點和自有節點之間的主要差異在於 決定是否要參與駕駛人比對程序。
驅動程式庫程式架構會嘗試找出與 非自有節點,以便將驅動程式庫繫結至節點。一旦成功找到驅動程式庫成功 繫結至節點,繫結的驅動程式庫就會成為節點的擁有者。 另一方面,擁有的節點不會參與比對,因為驅動程式庫 建立節點的 Pod 已經是擁有者
DriverBase 輔助函式
驅動程式目前繫結節點的用戶端儲存在
DriverBase
物件。如此一來,驅動程式庫就能使用 DriverBase
類別的
使用 AddChild()
和 AddOwnedChild()
函式將子節點新增至這個節點。
不過,如要使用這些 DriverBase
輔助函式,節點不得
。如果節點被移出,或您的目標節點不是
驅動程式庫目前繫結的節點 (亦即大子項節點);
您需要使用
add_child.h
檔案。這些方法與
DriverBase
輔助函式,但可用來將子項新增至節點
而不只是 DriverBase
物件所能觸及的地方,而是提供正確的父項
做為目標
最後,如果記錄錯誤發生,這些輔助函式會負責處理記錄錯誤。 因此驅動程式庫不需要記錄
建立非擁有的節點
如要建立非自有節點,驅動程式庫可以使用 DriverBase::AddChild()
輔助程式
函式。這些函式有兩種:一種可讓您提供
DevfsAddArgs
和其他不需要。使用這些函式
並用於尋找相符節點之上空屬性
驅動程式。兩者的傳回結果都是 NodeController
通訊協定的用戶端。
這些物件可由驅動程式庫保留,或安全捨棄。
下列程式碼範例會在驅動程式庫繫結節點下建立非從屬節點:
// Add a child node.
auto properties = std::vector{fdf::MakeProperty(bind_fuchsia_test::TEST_CHILD, "simple")};
zx::result child_result = AddChild(child_name, properties, compat_server_.CreateOffers2());
if (child_result.is_error()) {
return child_result.take_error();
}
child_controller_.Bind(std::move(child_result.value()));
(資料來源:simple_driver.cc
)
建立自有節點
如要建立自有節點,驅動程式庫可以使用 DriverBase::AddOwnedChild()
輔助程式
函式。又有兩種類型:一種允許 DevfsAddArgs
,另一種類型允許
但它不會顯示這些函式不提供屬性引數,因為
節點不會參與驅動程式庫比對。兩者的傳回結果都是
OwnedChildNode
物件,內含為 NodeController
的用戶端 (該
安全捨棄) 以及用戶端的 Node
通訊協定
捨棄安全。駕駛必須在 Node
用戶端保持連線狀態,
希望擁有的節點留在系統中捨棄這個用戶端會導致驅動程式庫
移除節點
下列程式碼範例會使用 devfs
引數建立自有節點:
fuchsia_driver_framework::DevfsAddArgs devfs_args{{.connector = std::move(connector.value())}};
zx::result owned_child = AddOwnedChild("retriever", devfs_args);
if (owned_child.is_error()) {
return owned_child.error_value();
}
child_node_.emplace(std::move(owned_child.value()));
(資料來源:retriever.cc
)
清潔驅動程式庫
如果 DFv2 驅動程式庫需要在停止前執行拆解 (例如
停止執行緒),您就必須覆寫並實作
DriverBase
方法:PrepareStop()
和 Stop()
系統會先呼叫 PrepareStop()
函式,再呼叫驅動程式庫的 fdf
調度工具
並撤離驅動程式庫位置因此,驅動程式
實作 PrepareStop()if
時,必須先執行特定作業
驅動程式庫的調度器關閉,例如:
void SimpleDriver::PrepareStop(fdf::PrepareStopCompleter completer) {
// Teardown threads
FDF_LOG(INFO, "Preparing to stop SimpleDriver");
completer(zx::ok());
}
在這個驅動程式庫的所有調度器之後,會呼叫 Stop()
函式
例如:
void SimpleDriver::Stop() {
FDF_LOG(INFO, "Stopping SimpleDriver");
}
新增相容裝置伺服器
如果 DFv2 驅動程式庫具有尚未遷移的 DFv1 驅動程式 DFv2 後,您必須使用相容性盾牌才能讓 DFv2 驅動程式庫進行通訊 與系統中的其他 DFv1 驅動程式整合詳情請參閱 在 DFv2 驅動程式中設定 Compat 裝置伺服器 指南。