所以您決定啟動新的主面板。在開始編寫程式之前,請先回答下列問題,確認您具備所有必要功能:
我該如何瞭解裝置及其註冊的運作方式?
- 這通常稱為「作業理論」。製造商通常會提供規格書,其中含有登錄定義,但這些參考資料可能無法說明裝置的實際使用方式。
是否有其他類似白板的驅動程式庫?
- 在實際可行情況下,請透過重構該程式碼並修正驅動程式庫的繫結規則,為類似的主面板重複使用程式碼。
裝置是否有固定的螢幕?
- 部分顯示控制器和麵板 (輸出畫面) 彼此緊耦合。如果這是新主面板的運作,您將需要在顯示驅動程式庫中新增 GPIO、I2C 和其他控制項的支援功能。
必要條件
本指南假設您熟悉一或多個作業系統的驅動程式庫開發。也假設您熟悉 Fuchsia DDK-TL。
程式語言
新驅動程式必須以 C++ 編寫。Rust 支援已規劃,但目前仍在高度實驗階段。
如果已有適當授權的驅動程式以 C 編寫,我們建議將其移植至 Fuchsia,而不要在 C++ 中實作新版本。在做出這項決定前,請與 graphics-dev@fuchsia.dev 聯絡。
踏出第一步
如果平台沒有 ACPI 或 PCI 匯流排,第一個步驟就是修改主機板驅動程式。本指南假設主面板驅動程式庫已準備就緒,螢幕驅動程式庫為 fancy
。新驅動程式庫的所有程式碼都會存放在 src/graphics/display/drivers/fancy-display/
中。
首先,請建立:
- 以最低限度導入 DisplayControllerImpl
- 一組繫結規則
DisplayControllerImpl
和繫結規則的建構方案
將驅動程式庫新增至版本
- 在名為
BUILD.gn
的檔案中建立建構方案
# Copyright 2021 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/bind/bind.gni")
import("//build/drivers.gni")
driver_bind_rules("fancy-display-bind") {
rules = "fancy-display.bind"
bind_output = "fancy-display.bindbc"
tests = "bind_tests.json"
deps = [
"//src/devices/bind/board_maker_company.platform",
]
}
# Factored out so that it can be used in tests.
source_set("common") {
public_deps = [
":fancy-display-bind",
]
sources = [
"fancy-display.cc",
]
}
fuchsia_driver("fancy-display") {
sources = []
deps = [
":common",
"//src/devices/lib/driver",
]
}
- 將
//src/graphics/display/drivers/fancy-display
新增為用於測試產品的面板依附元件。舉例來說,如果您的裝置屬於 Khadas VIM3 主面板,請將驅動程式新增至_common_bootfs_deps
清單,藉此修改//boards/vim3.gni
。
選擇要開車的裝置
現在您已擁有建構方案,接下來可以繼續建立「繫結規則」,讓驅動程式管理器用來判斷裝置是否可以搭配驅動程式使用。
- 在
src/graphics/display/drivers/fancy-display
中建立fancy-display.bind
:
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
using fuchsia.pci;
fuchsia.BIND_PROTOCOL == fuchsia.pci.BIND_PROTOCOL.DEVICE;
fuchsia.BIND_PCI_VID == fuchsia.pci.BIND_PCI_VID.PLANK_HW_INC;
accept fuchsia.BIND_PCI_DID {
// Fancy
0x0100,
// Fancy+ series
0x0120,
0x0121,
}
如為電腦裝置,則可使用 intel-i915 繫結規則。針對固定硬體 SoC,請參閱 Amlogic 顯示規則。
最小驅動程式庫
最後,請新增裸機驅動程式庫,以便在每次成功繫結至裝置時建構新物件。之後,您可以使用規格書 讓裝置執行實際操作。
在 src/graphics/display/drivers/fancy-display
中建立 fancy-display.cc
:
#include <ddktl/device.h>
#include <fuchsia/hardware/display/controller/cpp/banjo.h>
namespace fancy_display {
class Device;
using DeviceType = ddk::Device<Device>
// A Device exposes a single display controller for use by the display
// coordinator driver in src/graphics/display/drivers/coordinator.
//
// This object is constructed once for each device that matches this
// driver's bind rules.
class Device : public DeviceType {
public:
explicit Device(zx_device_t* parent) : DeviceType(parent) {}
// If Bind() returns an error, the driver won't claim the device.
zx_status_t Bind() { return ZX_OK };
// Functionality needed by the common display driver core.
void DisplayControllerImplSetDisplayControllerInterface(
const display_controller_interface_protocol* interface) {}
zx_status_t DisplayControllerImplImportBufferCollection(
uint64_t collection_id, zx::channel collection_token) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t DisplayControllerImplReleaseBufferCollection(
uint64_t collection_id) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t DisplayControllerImplImportImage(const image_metadata_t* image_metadata,
uint64_t collection_id, uint32_t index,
uint64_t* out_image_handle) {
return ZX_ERR_NOT_SUPPORTED;
}
void DisplayControllerImplReleaseImage(image_t* image) {}
config_check_result_t DisplayControllerImplCheckConfiguration(
const display_config_t** display_configs, size_t display_count,
client_composition_opcode_t* out_client_composition_opcodes_list, size_t client_composition_opcodes_count,
size_t* out_client_composition_opcodes_actual);
void DisplayControllerImplApplyConfiguration(
const display_config_t** display_config, size_t display_count) {}
void DisplayControllerImplSetEld(
uint64_t display_id,
const uint8_t* raw_eld_list,
size_t raw_eld_count) {}
zx_status_t DisplayControllerImplSetBufferCollectionConstraints(
const image_buffer_usage_t* usage, uint64_t collection_id) {
return ZX_ERR_NOT_SUPPORTED;
}
};
} // namespace fancy_display
// Main bind function called from dev manager.
zx_status_t fancy_display_bind(void* ctx, zx_device_t* parent) {
fbl::AllocChecker alloc_checker;
auto dev = fbl::make_unique_checked<fancy_display::Device>(
&alloc_checker, parent);
if (!alloc_checker.check()) {
return ZX_ERR_NO_MEMORY;
}
auto status = dev->Bind();
if (status == ZX_OK) {
// The driver/device manager now owns this memory.
[[maybe_unused]] auto ptr = dev.release();
}
return status;
}
// zx_driver_ops_t is the ABI between driver modules and the device manager.
// This lambda is used so that drivers can be rebuilt without compiler
// warnings if/when new fields are added to the struct.
static zx_driver_ops_t fancy_display_ops = [](){
zx_driver_ops_t ops;
ops.version = DRIVER_OPS_VERSION;
ops.bind = fancy_display_bind;
return ops;
}();
// ZIRCON_DRIVER marks the compiled driver as compatible with the zircon
// 0.1 driver ABI.
ZIRCON_DRIVER(fancy_display, fancy_display_ops, "zircon", "0.1");
顯示驅動程式必須實作 DisplayControllerImpl
通訊協定,這會公開硬體層並實作 vsync 通知。系統上所有裝置專用驅動程式和顯示驅動程式庫堆疊用戶端 (即系統合成器和 Virtcon) 之間的「螢幕協調器」驅動程式庫多工器。
導入提示
傳遞至 ApplyConfiguration
的設定驅動程式庫決定何時和方式生效。為了避免發生撕裂,驅動程式應在 vsync 後套用新設定。
大多數裝置都會為 vsync 事件產生中斷情形。如要確保即時顯示 vsync 通知,最簡單的方法就是建立另一個執行緒,藉此處理中斷情形。即使未顯示圖片,您的驅動程式庫必須針對每個 vsync 呼叫 OnDisplayVsync
。
支援系統啟動載入程式的控制器
如果螢幕在啟動時處於啟用狀態 (例如面板開啟且顯示圖片),您就可以快速在驅動程式庫中使用基本功能。讀取系統啟動載入程式記錄和/或原始碼,即可找到:
- framebuffer 的實際位址
- 用於規劃該位址的收銀機
- 圖片的像素尺寸,例如 800x600
- 圖片的像素格式,例如 RGB888、NV12 或 BGRA8888
然後執行下列操作:
- 請修改驅動程式庫,以回報具有格式限制的螢幕。
- 錄製
image->handle
中所有已匯入圖片的實際地址。 - 呼叫
ApplyConfig
時,重新編寫註冊的程式。
如果您不知道如何觀察 vsync,可以使用在 60Hz 呼叫 OnDisplayVsync
的執行緒中假裝。
啟動「深色」的控制器
即使顯示缺乏基本系統啟動載入程式驅動程式庫的顯示控制器,也沒有辦法開啟。在大多數情況下,您的發展藍圖如下: