DFv1 至 DFv2 遷移作業的常見問題

開始進行 DFv1 至 DFv2 遷移作業前,請先參閱下列常見問題,瞭解可能適用於驅動程式的特殊情況或邊緣案例。

什麼是相容性墊片,何時需要使用?

DFv1 和 DFv2 驅動程式會位於節點拓樸樹狀圖的單一分支下方 (也就是在所有驅動程式遷移至 DFv2 之前),且需要能夠彼此通訊。為了協助遷移程序,Fuchsia 的驅動程式庫程式架構團隊建立了相容性墊片,讓 DFv1 驅動程式可在 DFv2 中運作。

如果目標驅動程式庫與仍使用 Banjo 的其他 DFv1 驅動程式通訊,且這些驅動程式不會一次全部遷移至 DFv2,您就需要使用這個相容性墊片 (透過手動建立 compat::DeviceServer),讓不同架構版本中的驅動程式能夠彼此通訊。

如要進一步瞭解如何在 DFv2 驅動程式庫中使用相容性墊片,請參閱「在 DFv2 驅動程式中設定相容性裝置伺服器」指南。

DFv2 驅動程式可以使用相容性墊片與 Banjo 通訊協定通訊嗎?

雖然強烈建議您將 DFv1 驅動程式庫從 Banjo 遷移至 FIDL,但如果 DFv2 驅動程式庫需要與某些現有的 Banjo 通訊協定通訊,相容性墊片會提供下列功能:

  • compat::BanjoServer 可讓您更輕鬆地放送 Banjo (請參閱 banjo_server.h)。
  • compat::ConnectBanjo 可讓您更輕鬆地連線至 Banjo (請參閱 banjo_client.h)。

如要進一步瞭解這些功能,請參閱「在 DFv2 驅動程式中提供 Banjo 通訊協定」指南。

DFv2 驅動程式可以為複合節點使用相容性墊片嗎?

複合驅動程式的遷移程序幾乎與一般驅動程式相同,但複合驅動程式與父節點連線至 Banjo 或 FIDL 通訊協定的做法略有不同。

由於複合式節點有多個父項,因此複合式驅動程式需要在連線時識別父項名稱。舉例來說,以下是一般驅動程式庫與其父項建立 Banjo 連線的情況:

zx::result client_result =
  compat::ConnectBanjo<ddk::HidDeviceProtocolClient>(incoming());

複合驅動程式的方法幾乎相同,但需要加入父項名稱:

zx::result client_result =
  compat::ConnectBanjo<ddk::HidDeviceProtocolClient>(incoming(), "gpio-int")

新版 DFv2 驅動程式庫介面有哪些變更?

DFv2 的一項重大變更是,驅動程式會控管由驅動程式建立的子 nodes (或裝置) 的生命週期。這與 DFv1 不同,在 DFv1 中,驅動程式庫架構會透過裝置樹狀結構管理裝置的生命週期,例如拆卸裝置

在 DFv1 中,裝置由 zx_protocol_device 控制,驅動程式則由 zx_driver_ops 控制。如果使用 ddktlzx_protocol_device 中的介面需要由混合器範本類別中的 Ddk*() 函式包裝。在 DFv2 中,這些介面已大幅變更。

服務探索功能在 DFv2 中如何運作?

在 DFv2 中,您必須使用 FIDL 服務才能建立通訊協定連線。父項驅動程式庫會將 FIDL 服務新增至 fdf::OutgoingDirectory 物件,並將其提供給子項節點,進而讓父項驅動程式庫程式向子項節點提供服務。

DFv1 和 DFv2 驅動程式會以以下方式執行此操作:

  • 在 DFv1 中,驅動程式庫會從 DeviceAddArgs::set_runtime_service_offers() 呼叫設定及傳遞優惠。接著,驅動程式庫會建立 fdf::OutgoingDirectory 物件,並透過 DeviceAddArgs::set_outgoing_dir() 呼叫傳遞用戶端結尾句柄。

  • 在 DFv2 中,驅動程式庫會設定並傳遞 NodeAddArgs::offers 物件的優惠。驅動程式會將服務新增至由 DriverBase 類別 (最初由 Start() 函式提供) 包裝的傳出目錄。當子驅動程式庫繫結至子節點時,驅動程式代管程序會將包含服務的傳入命名空間傳遞至子驅動程式庫的 Start() 函式。

在子驅動程式庫端,DFv1 和 DFv2 驅動程式也會以不同方式連線至提供服務的通訊協定:

  • DFv1 驅動程式庫會呼叫 DdkConnectRuntimeProtocol<ServiceInstanceName>() 方法。
  • 如果使用 DriverBase 類別,DFv2 驅動程式庫會呼叫 incoming()->Connect<ServiceInstanceName>()

    詳情請參閱「使用 DFv2 服務探索功能」。

在 DFv2 中,我的驅動程式庫節點 (或裝置) 如何在系統中公開?

驅動程式可以公開服務,並將服務路由至用戶端。此外,您可以使用 ffx component list 列出驅動程式,就像列出所有元件一樣。

DFv2 中未實作的 DFv1 功能為何?

如果 DFv1 驅動程式庫會呼叫 DDK 程式庫中的 load_firmware() 函式,您就需要實作自己的函式,因為 DFv2 中沒有等效的函式。不過,這項功能應該很容易導入

DFv2 的繫結規則有哪些變更?

DFv2 節點包含由 FIDL 服務供應項目產生的額外節點屬性

不過,將現有的 DFv1 驅動程式庫遷移至 DFv2 時,您不太可能需要修改繫結規則。

DFv2 的記錄功能有哪些變更?

DFv2 驅動程式無法使用 zxlogf() 函式,也無法使用包裝或使用此函式的任何偵錯程式庫。zxlogf() 是在 //src/lib/ddk/include/lib/ddk/debug.h 中定義,並從 DFv2 的依附元件中移除。遷移至 DFv2 的驅動程式需要停止使用這個程式庫,以及其他依附於此程式庫的程式庫。

不過,我們現在已新增一組相容性程式庫,這類程式庫僅適用於 Fuchsia 來源樹狀結構 (fuchsia.git) 環境,可讓 DFv2 驅動程式使用 DFv1 風格的記錄功能。

在 DFv2 中,檢查功能有哪些變更?

DFv1 驅動程式會使用驅動程式庫專屬檢查函式,建立及更新由驅動程式庫維護的指標。舉例來說,在 DFv1 中,系統會呼叫 DeviceAddArgs::set_inspect_vmo() 函式,指出驅動程式庫用於檢查的 VMO。不過,在 DFv2 中,我們可以直接建立 inspect::ComponentInspector 物件。

調度器在 DFv2 中的作用

FIDL 檔案會為用戶端和伺服器組合產生範本和資料類型。在這些用戶端和伺服器端之間,有一個管道,而每個端的調度器會從管道擷取資料。如要進一步瞭解調度器,請參閱「Driver 調度器和執行緒」。

將 DFv1 驅動程式庫遷移至 DFv2 時,新執行緒模型會遇到哪些問題?

DFv2 中的 FIDL 呼叫並非以單一執行緒為基礎,且設計上為非同步 (雖然您可以透過在 FIDL 呼叫中新增 .sync() 或使用 fdf::WireSyncClient 來讓呼叫變成同步)。一般來說,我們不建議驅動程式進行同步呼叫,因為這可能會阻止其他工作執行。(不過,如果需要,驅動程式庫可以使用 FDF_DISPATCHER_OPTION_ALLOW_SYNC_CALLS 選項建立調度器,但這項選項僅支援同步調度器)。

由於 Banjo (DFv1) 和 FIDL (DFv2) 的執行緒模型不同,您需要決定在遷移時要使用哪種 FIDL 呼叫 (即同步或非同步)。如果原始程式碼是根據 Banjo 的同步性設計,且難以解開並使其全部非同步,建議您一開始使用 FIDL 的同步版本 (不過,這可能會導致效能暫時降低)。日後,您可以重新查看這些呼叫,並將其最佳化為使用同步呼叫。

DFv2 的測試驅動程式有哪些變更?

在驅動程式庫單元測試中使用的 mock_ddk 程式庫是 DFv1 專屬。新測試程式庫現已開放 DFv2 驅動程式使用。

進行遷移作業時,是否應將驅動程式分支為 DFv2 版本?

分支現有驅動程式庫以便遷移,取決於驅動程式庫的複雜度。一般來說,建議您避免分叉驅動程式庫,因為這可能會導致更多工作。不過,對於較大的驅動程式,將驅動程式庫分支為 DFv2 版本可能會比較適合,這樣就能逐步在較小的修補程式中實現遷移變更。

您可以透過在 GN 引數中新增新的驅動程式庫元件,並使用標記決定使用 DFv1 或 DFv2 版本,來分支驅動程式庫。這個 範例 CL 示範如何新增 msd-arm-mali 驅動程式庫的 DFv2 分支。

fuchsia.dev 上的 DFv2 概念說明文件,以及來自先前 DFv1 Intel WiFi 驅動程式庫遷移作業的 Gerrit 變更 (pcie-iwlwifi-driver.cc 檔案包含大部分的新 API)。