撰寫基本驅動程式庫
程式碼結構應遵循 fx create 驅動程式庫 goldens
範本。
中繼目錄
每個驅動程式庫目錄都必須有 meta 子目錄,內含下列檔案:
- 定義驅動程式庫
bind規則的bind檔案 - 元件資訊清單
驅動程式原始碼
使用 Driver Component 程式庫 (sdk/lib/driver/component/) 編寫驅動程式。驅動程式應從標頭 <lib/driver/component/cpp/driver_base2.h> 中定義的 fdf::DriverBase2 類別繼承。
驅動程式提供 FUCHSIA_DRIVER_EXPORT2 巨集,用於匯出標頭 <lib/driver/component/cpp/driver_export2.h> 中定義的驅動程式庫符號。這個巨集應位於 .cc 檔案中。
初始化驅動程式庫
請勿在驅動程式庫的建構函式中放置任何邏輯。您必須覆寫 fdf::DriverBase2 提供的其中一個 Start() 方法,實作驅動程式的初始化邏輯,即使初始化邏輯為空白也一樣,而非使用建構函式。請務必只使用單一 Start() 變體。
初始化邏輯包含:
- 擷取及設定所有驅動程式庫資源。
- 建立服務連線。
- 將驅動程式庫的自有服務新增至傳出目錄。
- 新增子節點 (在資源設定完成並提供自有服務後執行)。
- 使用
zx_bti_release_quarantine()從隔離區釋出 BTI。
關閉驅動程式庫
驅動程式的解構函式應不含任何邏輯。在大多數情況下,不需要覆寫 DriverBase2::Stop() 並提供實作項目。除非驅動程式庫功能特別需要 DriverBase2::Stop(),例如執行正常硬體關機或取消固定 DMA,否則請勿實作這項功能。函式參數中的 fdf::StopCompleter 必須在函式結尾呼叫。
建構檔案
所有新驅動程式都必須使用 Bazel 進行建構程序,且必須包含下列目標:
fuchsia_driver_bind_bytecodefuchsia_cc_driverfuchsia_driver_component
與司機通訊
驅動程式會透過 FIDL 服務與父項驅動程式通訊。
提供服務
提供 FIDL 服務的驅動程式必須維護 fidl::ServerBindingGroup (使用 Zircon 傳輸時) 或 fdf::ServerBindingGroup (適用於驅動程式庫傳輸)。除非驅動程式庫必須限制為單一用戶端連線,否則請避免使用 fidl::ServerBinding 或 fdf::ServerBinding。
建立任何子節點之前,必須先將伺服器繫結新增至 Start() 函式內的驅動程式傳出目錄。此外,CML 檔案必須在能力中指定服務,並從 self 公開服務。
使用服務
如要使用服務,駕駛人應將服務納入 bind 規則,並在 CML 的 uses 區段中指定服務。
新增孩子
新增子節點的主要原因是,驅動程式庫需要為其他驅動程式庫提供服務或資源。請避免無故新增子項。
除非驅動程式庫需要動態新增子節點,否則子節點應新增為驅動程式 Start() 函式中的初始化邏輯。
應使用 DriverBase2 的 AddChild() 或 add_child 輔助程式庫 (sdk/lib/driver/node/cpp/add_child.h) 新增子節點。只有在子節點需要使用其他記錄器時,才應使用輔助程式庫。
除非用於支援已淘汰的 devfs,否則所有子節點都應為未擁有狀態。如果擁有子節點,驅動程式庫必須儲存從輔助函式收到的 fuchsia_driver_framework::Node 用戶端。
新增子節點時,請明確定義子節點的名稱,不要使用 DriverBase2 中的 name()。使用 node_offers 輔助程式庫 (sdk/lib/driver/component/cpp/node_offers.h) 建立優惠。使用 node_properties 程式庫 (sdk/lib/driver/component/cpp/node_properties.h) 建立屬性。節點屬性鍵和值應使用產生的繫結程式庫程式碼繫結。
記錄
如要記錄,驅動程式應使用格式型記錄 API,例如fdf::info() 驅動程式記錄器程式庫 (sdk/lib/driver/logging/cpp/logger.h) 中的 API。如要記錄自訂型別,請實作 std::format。
請按照 Fuchsia 記錄指南,使用 warning 或 error 記錄層級記錄 FIDL 錯誤等失敗情形。
Zircon 資源
中斷
初始化期間,應在驅動程式庫中擷取並儲存中斷。
中斷應由 async::Irq 物件 (sdk/lib/async/include/lib/async/cpp/irq.h) 包裝。
應使用 IrqMethod 物件處理中斷觸發條件。處理中斷觸發程序後,應使用 ack() 確認 Irq 物件,以便重新啟動中斷程序,並再次觸發。
DMA
如要執行記憶體作業,驅動程式應使用 MmioBuffer,位於 sdk/lib/driver/mmio/cpp/mmio-buffer.h。這個程式庫提供原始 mmio_block_t 物件的包裝函式,用於讀取和寫入。
為確保安全存取位元欄位,建議使用 hwreg/bitfields 程式庫。這個程式庫位於 zircon/system/ulib/hwreg/include/hwreg/bitfields.h。
驅動程式應控管 BTI,並停止初始化期間可能正在進行的任何 DMA。完成後,應呼叫 zx_bti_release_quarantine(),告知 BTI 已重新取得硬體控制權。如要與硬體共用 DMA 的驅動程式,必須事先釘選 BTI。硬體存取記憶體完成後,驅動程式庫會負責取消釘選記憶體。在任何情況下,都不應在解構函式中取消釘選 BTI。
時鐘
時鐘是透過 fuchsia.hardware.clock FIDL 服務控制。
驅動程式必須在所有依賴的時鐘上呼叫 Enable(),並在不再需要時鐘訊號時呼叫 Disable()。駕駛人必須先啟用時鐘,才能呼叫 Disable()。
測試
確認建構目標包含必要的驅動程式庫測試。
單元測試
單元測試應使用 gtests (third_party/googletest/src/googletest/include/gtest/gtest.h) 編寫。
測試整個驅動程式庫
如果測試整個驅動程式庫,驅動程式庫應由
ForegroundDriverTest或 BackgroundDriverTest 從
驅動程式測試程式庫
(sdk/lib/driver/testing/cpp/driver_test.h) 包裝。單元測試應在測試初始化後立即呼叫
StartDriver(),並在 Teardown() 函式中呼叫 StopDriver()。驅動程式庫所需的所有服務和資源,都應在自訂驅動程式庫測試的 Environment 類別中初始化及提供。
如果驅動程式庫需要平台裝置服務,測試應例項化 FakePlatformDevice (sdk/lib/driver/fake-platform-device/) DriverTestEnvironment 並提供服務。同樣地,如果驅動程式庫需要 FIDL 服務,則應在 DriverTestEnvironment 中例項化並提供服務的測試實作。
測試驅動程式庫的部分
如果只隔離驅動程式庫程式邏輯的子集進行測試,測試可能需要特定的驅動程式庫環境元件。
評估使用驅動程式記錄器程式庫 (sdk/lib/driver/logging/cpp/logger.h) 的邏輯時,測試必須例項化並維護 fdf_testing::ScopedGlobalLogger 例項 (sdk/lib/driver/testing/cpp/scoped_global_logger.h)。
此外,如果邏輯需要驅動程式庫調度器,測試就必須設定並保留 fdf_testing::DriverRuntime 物件 (sdk/lib/driver/testing/cpp/driver_runtime.h)。
模擬/仿冒程式庫
需要虛擬 FIDL 服務或資源的測試,應盡可能使用 sdk/lib/driver/ 中提供的虛擬和模擬程式庫。
下列程式庫適用於常見的 FIDL 服務:
- //sdk/lib/驅動程式庫/fake-clock -
fuchsia.hardware.clock服務。 - //sdk/lib/驅動程式庫/fake-gpio -
fuchsia.hardware.gpio服務。 - //sdk/lib/驅動程式庫/fake-interconnect -
fuchsia.hardware.interconnectservice. - //sdk/lib/驅動程式庫/fake-pin -
fuchsia.hardware.pin服務。 - //sdk/lib/驅動程式庫/fake-platform-device -
fuchsia.hardware.platform.device和fuchsia.hardware.power服務。 - //sdk/lib/驅動程式庫/fake-reset -
fuchsia.hardware.reset服務。 - //sdk/lib/驅動程式庫/fake-vreg -
fuchsia.hardware.vreg服務。
下列程式庫適用於常見的內部 Zircon 物件、記憶體區域或驅動程式庫執行階段資源:
- //sdk/lib/驅動程式庫/fake-bti:模擬 Zircon BTI (
zx::bti) 物件。 - //sdk/lib/驅動程式庫/fake-object:模擬一般 Zircon 核心物件 (
zx::handle)。 - //sdk/lib/驅動程式庫/fake-resource:模擬 Zircon 資源 (
zx::resource) 物件。 - //sdk/lib/驅動程式庫/fake-mmio-reg:透過記憶體結構模擬 MMIO 暫存器。
- //sdk/lib/驅動程式庫/mock-mmio:模擬 MMIO 區域,用於記憶體對應 I/O 暫存器測試。
整合測試
整合測試應使用 Driver Test Realm (sdk/lib/driver_test_realm/) 架構。首先,測試必須建立與 DriverTestRealm 服務的連線,在 RealmArgs 中執行必要設定,然後使用引數呼叫 Start()。