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

在您開始執行 DFv1 至 DFv2 遷移作業之前,以下常見問題可協助您找出可能適用於驅動程式的特殊狀況或極端情況。

什麼是相容性填充碼?何時必須使用?

DFv1 和 DFv2 驅動程式存在於節點拓撲樹狀結構的單一分支版本下 (也就是直到所有驅動程式都遷移到 DFv2),且它們需要能夠相互通訊。為協助遷移程序,Fuchsia 的驅動程式庫程式架構團隊建立了相容性輔助程式,讓 DFv1 驅動程式能在 DFv2 中運作。

如果您的目標驅動程式庫與其他仍然使用 Banjo 的 DFv1 驅動程式通訊,且這些驅動程式不會一次全部遷移至 DFv2,您必須使用這個相容性填充碼 (手動建立 compat::DeviceServer),讓不同架構版本的驅動程式能彼此通訊。

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

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 的一項重大變更是驅動程式會控制驅動程式建立的子項節點 (或裝置) 生命週期。這與 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 系統中如何公開?

Fuchsia 擁有一個稱為 devfs 的檔案系統,其裝置的全域樹狀結構,該系統會轉送至大多數元件為 /dev。驅動程式庫新增裝置節點時,可以選擇在 devfs 中新增「檔案」。然後,devfs 中的這個檔案可讓系統中的其他元件與驅動程式庫通訊。例如,音訊驅動程式庫可能會新增喇叭裝置節點,而音訊驅動程式庫想確認其他元件可以使用這個節點將音訊輸出至揚聲器。為此,音訊驅動程式庫程式會為喇叭新增 (或公開) devfs 節點,使其在系統中顯示為 /dev/class/audio/<random_number>

DFv1 中提供的 DFv2 未實作哪些項目?

如果 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 檔案會產生用戶端與伺服器組合適用的範本和資料類型。在這些用戶端和伺服器端之間是一個管道,而每個端的調度人員會從管道擷取資料。如要進一步瞭解調度工具,請參閱「驅動程式調度器和執行緒」。

將 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 Wi-Fi 驅動程式庫遷移作業的 Gerrit 變更 (pcie-iwlwifi-driver.cc 檔案包含大部分新的 API)。