總覽
本指南說明如何使用複合式節點規格將複合節點新增至驅動程式架構。本文假設您已熟悉下列項目:
建立複合式節點
- 在驅動程式庫中定義複合式節點規格
- 使用符合規格的繫結規則建立複合驅動程式庫
- 找到相符的複合驅動程式庫後,驅動程式管理器會在符合每個父項規格的拓撲中找到節點。每個相符的節點都會成為複合式節點的父項。
- 所有父項規格都相符之後,驅動程式管理器會建立含有節點做為父項的複合式節點,並將複合驅動程式庫繫結至該節點。主要節點和節點名稱是由複合驅動程式庫提供。
定義複合式節點規格
複合式節點規格是一組父項規格,用於定義將上層節點設為父項的節點。每個父項規格都包含下列項目:
繫結規則
繫結規則可用來尋找節點並與父項規格進行比對。系統會根據繫結規則評估節點屬性,如果兩者相符,節點就會成為複合式的父項。
父項規格的繫結規則包含可接受和遭拒屬性值的清單。如要與繫結規則相符,節點屬性必須包含所有可接受的節點屬性值,而非任何遭拒的規則。
舉例來說,假設父項規格包含繫結規則:
- 接受
fuchsia.BIND_PROTOCOL
值 15 和 17 - 拒絕
fuchsia.BIND_PLATFORM_DEV_VID
個值「Intel」
接著,如果裝置包含 fuchsia.BIND_PROTOCOL
屬性值為 15 或 17,且 fuchsia.BIND_PLATFORM_DEV_VID
屬性的值不包含「Intel」值,就會繫結至節點。
決定繫結規則
定義繫結規則的程序與繫結語言中的繫結規則程序相同。如要決定繫結規則,首先必須找出要繫結的節點屬性。
您可以使用 ffx driver list-devices -v
指令,列印節點拓撲中每個節點的屬性:
Name : i2c-1-56
Topo Path: sys/platform/05:00:2/aml-i2c/i2c/i2c-1-56
Driver : fuchsia-boot:///#driver/i2c.so
Flags : MUST_ISOLATE | BOUND
Proto : ZX_PROTOCOL_I2C (24)
3 Properties
[ 1/ 3] : Key fuchsia.BIND_I2C_BUS_ID Value 0x000001
[ 2/ 3] : Key fuchsia.BIND_I2C_ADDRESS Value 0x000038
[ 3/ 3] : Key "fuchsia.hardware.i2c.Service" Value "fuchsia.hardware.i2c.Service.ZirconTransport"
在傾印中,節點屬性如下:
fuchsia.I2C_BUS_ID
= 0x01fuchsia.I2C_ADDRESS
= 0x38fuchsia.hardware.i2c.Service
= fuchsia.hardware.i2c.Service.ZirconTransport
您可以透過繫結程式庫搜尋屬性值 (例如 src/devices/bind 中的繫結程式庫)。在此範例中,由於節點是 I2C 節點,因此屬性值可在 fuchsia.i2c.bind 中找到。
fuchsia.i2c.bind
extend uint fuchsia.BIND_I2C_BUS_ID {
I2C_A0_0 = 0,
I2C_2 = 1,
I2C_3 = 2,
};
extend uint fuchsia.BIND_I2C_ADDRESS {
BACKLIGHT = 0x2C,
ETH = 0x18,
FOCALTECH_TOUCH = 0x38,
AMBIENTLIGHT = 0x39,
AUDIO_CODEC = 0x48,
GOODIX_TOUCH = 0x5d,
TI_INA231_MLB = 0x49,
TI_INA231_SPEAKERS = 0x40,
TI_INA231_MLB_PROTO = 0x46,
};
我們也會從 FIDL 程式庫產生繫結程式庫,這是 fuchsia.hardware.i2c.Service
及其值 fuchsia.hardware.i2c.Service.ZirconTransport
的項目來源。詳情請參閱generated-bind-libraries。
如此一來,我們就能將節點屬性重新對應到下列位置:
fuchsia.hardware.i2c.Service
=fuchsia.hardware.i2c.Service.ZirconTransport
fuchsia.BIND_I2C_BUS_ID
=fuchsia.i2c.BIND_I2C_BUS_ID.I2C_2
fuchsia.BIND_I2C_ADDRESS
=fuchsia.i2c.BIND_I2C_ADDRESS.FOCALTECH_TOUCH
透過驅動程式產生的程式庫,可在驅動程式庫原始碼中存取繫結程式庫值。詳情請參閱繫結程式庫程式碼產生教學課程。
我們可以定義下列繫結規則,比對這些屬性:
accept fuchsia.hardware.i2c.Service { fuchsia.hardware.i2c.Service.ZirconTransport }
accept BIND_I2C_BUS_ID { fuchsia.i2c.BIND_I2C_BUS_ID.I2C_2 }
accept BIND_I2C_ADDRESS { fuchsia.i2c.BIND_I2C_ADDRESS.FOCALTECH_TOUCH }
使用驅動程式架構 v1 (DFv1) 寫入
在 DFv1 中,複合式節點規格是以 DDK 編寫。用於編寫繫結規則的函式位於 composite-node-spec.h
中。使用 DDK 程式庫和繫結程式庫的 Codegen 值時,我們可以編寫以下內容:
const ddk::BindRule kI2cBindRules[] = {
ddk::MakeAcceptBindRule(bind_fuchsia_hardware_i2c::SERVICE,
bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
ddk::MakeAcceptBindRule(bind_fuchsia::I2C_BUS_ID,
bind_fuchsia_i2c::BIND_I2C_BUS_ID_I2C_2),
ddk::MakeAcceptBindRule(bind_fuchsia::I2C_ADDRESS,
bind_fuchsia_focaltech_platform::BIND_I2C_ADDRESS_TOUCH),
};
使用驅動程式架構第 2 版 (DFv2) 寫入
在 DFv2 中,針對 fuchsia.driver.framework
FIDL 程式庫中的 composite_node_spec.fidl
編寫複合式節點規格。sdk/lib/driver/component/cpp
中的 composite_node_spec.h
程式庫可用於簡化繫結規則的定義程序。
使用該程式庫和繫結程式庫的 Codegen 值,我們就能編寫以下內容:
auto i2c_bind_rules = std::vector {
MakeAcceptBindRule(bind_fuchsia_hardware_i2c::SERVICE,
bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
MakeAcceptBindRule(bind_fuchsia::I2C_BUS_ID,
bind_fuchsia_i2c::BIND_I2C_BUS_ID_I2C_2),
MakeAcceptBindRule(bind_fuchsia::I2C_ADDRESS,
bind_fuchsia_focaltech_platform::BIND_I2C_ADDRESS_TOUCH),
};
屬性
屬性為鍵/值組合,用於比對父項規格和複合驅動程式的繫結規則。它們與節點屬性相同,因此格式相同。屬性金鑰可以是整數或字串型,而屬性值可以是整數、布林值、字串或列舉類型。
使用驅動程式架構 v1 (DFv1) 寫入
在 DFv1 中,複合節點規格是以 DDK 編寫,而用於編寫繫結規則的函式則位於 composite-node-spec.h
。使用 DDK 程式庫和繫結程式庫的 Codegen 值時,我們可以編寫以下內容:
const device_bind_prop_t kI2cProperties[] = {
ddk::MakeProperty(bind_fuchsia_hardware_i2c::SERVICE,
bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
ddk::MakeProperty(bind_fuchsia::I2C_ADDRESS,
bind_fuchsia_focaltech_platform::BIND_I2C_ADDRESS_TOUCH),
};
使用驅動程式架構第 2 版 (DFv2) 寫入
在 DFv2 中,複合節點規格是針對 fuchsia.driver.framework FIDL 程式庫中的 composite_node_spec.fidl
。//sdk/lib/driver/component/cpp
中的 node_add_args.h
程式庫可用於簡化繫結規則的定義。
auto i2c_properties[] = std::vector {
ddk::MakeProperty(bind_fuchsia::I2C_ADDRESS,
bind_fuchsia_focaltech_platform::BIND_I2C_ADDRESS_TOUCH),
};
新增複合式節點規格
建立複合式節點規格需要定義一組父項規格並新增至驅動程式管理器。
平台匯流排複合
platform_bus.fidl
這適用於 DFv1 和 DFv2。
/// Adds a composite node specification to the bus. This will add a platform device specified
/// by |node| and insert a node into the composite node specification that matches the device.
AddCompositeNodeSpec(struct {
node Node;
spec fuchsia.driver.framework.CompositeNodeSpec;
}) -> () error zx.Status;
平台匯流排 API 會使用 composite_node_spec.fidl
中定義的相同 CompositeNodeSpec
結構。如需操作說明,請參閱使用 FIDL 定義複合式節點規格。
舉例來說,假設我們定義了下列複合式節點規格:
auto bind_rules = std::vector{
driver::MakeAcceptBindRule(bind_fuchsia_hardware_i2c::SERVICE,
bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
driver::MakeAcceptBindRule(bind_fuchsia::I2C_ADDRESS,
bind_fuchsia_i2c::BIND_I2C_ADDRESS_BACKLIGHT),
};
auto properties = std::vector{
driver::MakeProperty(bind_fuchsia_hardware_i2c::SERVICE,
bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
driver::MakeProperty(bind_fuchsia::I2C_ADDRESS,
bind_fuchsia_i2c::BIND_I2C_ADDRESS_BACKLIGHT),
};
auto spec = std::vector{
fuchsia_driver_framework::ParentSpecification{
.bind_rules = bind_rules,
.properties = properties,
},
};
定義複合式節點規格後,板型驅動程式庫即可透過 PlatformBus
FIDL 通訊協定連線至平台匯流排,並使用用戶端端對端呼叫 AddCompositeNodeSpec()
。
AddCompositeNodeSpec()
呼叫會針對節點欄位資料建立的平台裝置,將父項規格插入指定複合式節點規格,然後將修改後的複合式節點規格新增至驅動程式架構。然後建立並新增平台裝置。
fpbus::Node dev;
dev.name() = "backlight";
dev.vid() = PDEV_VID_TI; // 0x10
dev.pid() = PDEV_PID_TI_LP8556; // 0x01
dev.did() = PDEV_DID_TI_BACKLIGHT; // 0x01
auto endpoints =
fdf::CreateEndpoints<fuchsia_hardware_platform_bus::PlatformBus>();
if (endpoints.is_error()) {
return endpoints.error_value();
}
fdf::WireSyncClient<fuchsia_hardware_platform_bus::PlatformBus> pbus =
endpoints->client;
auto result = pbus.buffer(arena)->AddCompositeNodeSpec(
fidl::ToWire(fidl_arena, dev),
fidl::ToWire(fidl_arena, spec), false);
if (!result.ok()) {
zxlogf(ERROR, "AddCompositeNodeSpec request failed: %s",
result.FormatDescription().data());
return result.status();
}
呼叫 AddCompositeNodeSpec()
後,下列複合式節點規格會新增至驅動程式架構:
Name : backlight
Driver : fuchsia-boot:///#meta/ti-lp8556.cm
Nodes : 2
Node 0 : None
3 Bind Rules
[ 1/ 3] : Accept "fuchsia.BIND_PLATFORM_DEV_VID" { 0x000010 }
[ 2/ 3] : Accept "fuchsia.BIND_PLATFORM_DEV_PID" { 0x000001 }
[ 2/ 3] : Accept "fuchsia.BIND_PLATFORM_DEV_DID" { 0x000001 }
3 Properties
[ 1/ 3] : Key "fuchsia.BIND_PLATFORM_DEV_VID" Value 0x000010
[ 2/ 3] : Key "fuchsia.BIND_PLATFORM_DEV_PID" Value 0x000001
[ 3/ 3] : Key "fuchsia.BIND_PLATFORM_DEV_DID" Value 0x000001
Node 1 : None
2 Bind Rules
[ 1/ 2] : Accept "fuchsia.hardware.i2c.Service" { "fuchsia.hardware.i2c.Service.ZirconTransport" }
[ 2/ 2] : Accept "fuchsia.BIND_I2C_ADDRESS" { 0x00002C }
2 Properties
[ 1/ 2] : Key "fuchsia.hardware.i2c.Service" Value "fuchsia.hardware.i2c.Service.ZirconTransport"
[ 2/ 2] : Key "fuchsia.BIND_I2C_ADDRESS" Value 0x00002C
}
第一個父項規格是由 AddCompositeSpec()
插入,且與平台裝置相符,其中包含 fpbus::Node dev
中提供的 VID、PID 和 DID 繫結規則和屬性。其餘父項規格來自複合式節點規格傳遞。
驅動程式架構 v1 (DFv1)
在 DFv1 中,驅動程式庫可透過 DdkAddCompositeNodeSpec()
函式透過 DDK 程式庫新增複合式節點規格。
驅動程式必須先在 spec.h 程式庫中定義 CompositeNodeSpec
。使用上述繫結規則和屬性,即可定義包含 I2C 父項規格的 CompositeNodeSpec
:
const ddk::BindRule kI2cBindRules[] = {
ddk::MakeAcceptBindRule(bind_fuchsia_hardware_i2c::SERVICE,
bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
ddk::MakeAcceptBindRule(bind_fuchsia::I2C_BUS_ID,
bind_fuchsia_i2c::BIND_I2C_BUS_ID_I2C_2),
ddk::MakeAcceptBindRule(bind_fuchsia::I2C_ADDRESS,
bind_fuchsia_focaltech_platform::BIND_I2C_ADDRESS_TOUCH),
};
const device_bind_prop_t kI2cProperties[] = {
ddk::MakeProperty(bind_fuchsia_hardware_i2c::SERVICE,
bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
ddk::MakeProperty(bind_fuchsia::I2C_ADDRESS,
bind_fuchsia_focaltech_platform::BIND_I2C_ADDRESS_TOUCH),
};
auto spec = ddk::CompositeNodeSpec(kI2cBindRules, kI2cProperties);
您可使用 AddParentSpec()
新增任何額外的節點。例如,如要為 GPIO 解譯圖釘加入父項規格,可以編寫以下內容:
const ddk::BindRule kGpioInterruptRules[] = {
ddk::MakeAcceptBindRule(bind_fuchsia::PROTOCOL,
bind_fuchsia_gpio::BIND_PROTOCOL_DEVICE),
ddk::MakeAcceptBindRule(bind_fuchsia::GPIO_PIN,
bind_fuchsia_amlogic_platform_s905d2::GPIOZ_PIN_ID_PIN_4),
};
const device_bind_prop_t kGpioInterruptProperties[] = {
ddk::MakeProperty(bind_fuchsia::PROTOCOL,
bind_fuchsia_gpio::BIND_PROTOCOL_DEVICE),
ddk::MakeProperty(bind_fuchsia_gpio::FUNCTION,
bind_fuchsia_gpio::FUNCTION_TOUCH_INTERRUPT)};
desc.AddParentSpec(kGpioInterruptRules, kGpioInterruptProperties);
您可以利用 set_metadata()
函式將中繼資料傳遞至複合式節點規格的複合。
CompositeNodeSpec
準備就緒後,您就可以使用 DdkAddCompositeNodeSpec()
新增:
auto status = DdkAddCompositeNodeSpec("ft3x27_touch", spec);
由於 CompositeNodeSpec
遵循建構工具模式,因此這可以簡化:
auto status =
DdkAddCompositeNodeSpec("ft3x27_touch",
ddk::CompositeNodeSpec(kFocaltechI2cRules, kFocaltechI2cProperties)
.AddParentSpec(kGpioInterruptRules, kGpioInterruptProperties)
.set_metadata(metadata);
驅動程式架構 v2 (DFv2)
在 DFv2 中,我們使用 fuchsia.driver.framework
FIDL API 中的 CompositeNodeManager
新增複合式節點規格。
@discoverable
protocol CompositeNodeManager {
/// Add the given spec to the driver manager.
AddSpec(CompositeNodeSpec) -> () error CompositeNodeSpecError;
};
使用 FIDL 定義複合式節點規格
CompositeNodeSpec
結構是在 composite_node_spec.fidl
中定義。您可以使用 sdk/lib/driver/component/cpp
程式庫中的 spec.h
和 node_add_args.h
函式,定義父項規格的繫結規則和屬性。
透過這個程式庫,我們可以定義 I2C 節點和 gpio-中斷節點的父項規格的複合節點規格:
auto i2c_bind_rules = std::vector {
MakeAcceptBindRule(bind_fuchsia_hardware_i2c::SERVICE,
bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
MakeAcceptBindRule(bind_fuchsia::I2C_BUS_ID,
bind_fuchsia_i2c::BIND_I2C_BUS_ID_I2C_2),
MakeAcceptBindRule(bind_fuchsia::I2C_ADDRESS,
bind_fuchsia_focaltech_platform::BIND_I2C_ADDRESS_TOUCH),
};
auto i2c_properties[] = std::vector {
ddk::MakeProperty(bind_fuchsia::I2C_ADDRESS,
bind_fuchsia_focaltech_platform::BIND_I2C_ADDRESS_TOUCH),
};
auto gpio_interrupt_bind_rules = std::vector {
MakeAcceptBindRule(bind_fuchsia::BIND_PROTOCOL,
bind_fuchsia_gpio::BIND_PROTOCOL_DEVICE),
MakeAcceptBindRule(bind_fuchsia::GPIO_PIN,
bind_fuchsia_amlogic_platform_s905d2::GPIOZ_PIN_ID_PIN_4),
};
auto gpio_interrupt_properties[] = std::vector {
ddk::MakeProperty(bind_fuchsia::BIND_PROTOCOL,
bind_fuchsia_gpio::FUNCTION_TOUCH_INTERRUPT),
};
auto nodes = std::vector{
fdf::ParentSpec{
.bind_rules = i2c_bind_rules,
.properties = i2c_properties,
},
fdf::ParentSpec{
.bind_rules = gpio_interrupt_bind_rules,
.properties = gpio_interrupt_properties,
},
};
auto spec = fdf::CompositeNodeSpec {.name = "fo", .nodes = nodes};
新增複合式節點規格
如要將複合式節點規格新增至 CompositeNodeManager
,您必須連線至服務:
auto client = incoming()->Connect<fdf::CompositeNodeManager>();
if (client.is_error()) {
FDF_LOG(ERROR, "Failed to connect to CompositeNodeManager: %s",
zx_status_get_string(client.error_value()));
return client.take_error();
}
fidl::SharedClient<fdf::CompositeNodeManager> composite_node_manager;
composite_node_manager.Bind(std::move(client.value()), dispatcher());
接著呼叫 API:
composite_node_manager->AddSpec(std::move(spec))
.Then([this](
fidl::Result<fdf::CompositeNodeManager::AddSpec>& create_result) {
if (create_result.is_error()) {
FDF_LOG(ERROR, "AddSpec failed: %s",
create_result.error_value().FormatDescription().c_str());
return;
}
FDF_LOG(INFO, "Succeeded adding spec");
});
定義複合式驅動程式庫繫結規則
複合驅動程式庫是一種只繫結至複合式節點的驅動程式庫。驅動程式是透過其繫結規則來定義。詳情請參閱複合式繫結規則。
比對程序
比對程序方法是將複合驅動程式庫繫結規則套用至父項規格的屬性。符合下列條件時即視為比對成功:
- 所有父項規格都必須與複合式繫結規則中的節點相符
- 所有非選用的複合式繫結規則節點都必須符合父項規格。
比對作業不得重複:
- 每個父項規格只能對應一個複合式繫結規則節點
- 每個複合式繫結規則節點最多只能符合一個父項規格。選用的繫結規則可能與零父項規格相符。
- 節點不必依序比對
- 如果發生不明確情況,系統會顯示警告訊息。
編寫繫結規則
以上述範例為例,假設我們想要繫結至複合式節點規格,並在其父項規格中包含下列屬性:
i2c parent specification properties {
fuchsia.hardware.i2c.Service: fuchsia.hardware.i2c.Service.ZirconTransport,
fuchsia.BIND_I2C_ADDRESS: fuchsia.focaltech.platform.BIND_I2C_ADDRESS_TOUCH,
}
gpio-interrupt parent specification properties {
fuchsia.BIND_PROTOCOL: fuchsia.gpio.BIND_PROTOCOL_DEVICE,
fuchsia.gpio.FUNCTION: fuchsia.gpio.FUNCTION.TOUCH_INTERRUPT,
}
我們可以編寫複合式繫結規則,使其符合父項規格:
composite focaltech_touch;
using fuchsia.gpio;
using fuchsia.hardware.i2c;
using fuchsia.i2c;
primary node "i2c" {
fuchsia.hardware.i2c.Service == fuchsia.hardware.i2c.Service.ZirconTransport;
fuchsia.BIND_I2C_ADDRESS == fuchsia.i2c.BIND_I2C_ADDRESS.FOCALTECH_TOUCH;
}
node "gpio-int" {
fuchsia.BIND_PROTOCOL == fuchsia.gpio.BIND_PROTOCOL.DEVICE;
fuchsia.gpio.FUNCTION == fuchsia.gpio.FUNCTION.TOUCH_INTERRUPT;
}
偵錯
如要驗證複合式節點是否已成功建立,並嘗試繫結複合式驅動程式庫,您可以在記錄檔中查看與下列內容相似的陳述式:
Binding driver fuchsia-boot:///#meta/focaltech.cm
如要確認複合式節點規格已成功新增,並且與複合式驅動程式庫進行比對,請執行下列指令:
ffx driver list-composite-node-specs -v
這會輸出類似以下的內容:
Name : ft3x27_touch
Driver : fuchsia-boot:///#meta/focaltech.cm
Nodes : 2
Node 0 : "i2c" (Primary)
3 Bind Rules
[ 1/ 3] : Accept "fuchsia.hardware.i2c.Service" { "fuchsia.hardware.i2c.Service.ZirconTransport" }
[ 2/ 3] : Accept "fuchsia.BIND_I2C_BUS_ID" { 0x000001 }
[ 3/ 3] : Accept "fuchsia.BIND_I2C_ADDRESS" { 0x000038 }
2 Properties
[ 1/ 2] : Key "fuchsia.hardware.i2c.Service" Value "fuchsia.hardware.i2c.Service.ZirconTransport"
[ 2/ 2] : Key "fuchsia.BIND_I2C_ADDRESS" Value 0x000038
Node 1 : "gpio-int"
2 Bind Rules
[ 1/ 2] : Accept "fuchsia.BIND_PROTOCOL" { 0x000014 }
[ 2/ 2] : Accept "fuchsia.BIND_GPIO_PIN" { 0x000004 }
2 Properties
[ 1/ 2] : Key "fuchsia.BIND_PROTOCOL" Value 0x000014
[ 2/ 2] : Key "fuchsia.gpio.FUNCTION" Value "fuchsia.gpio.FUNCTION.TOUCH_INTERRUPT"
如果複合節點規格沒有相符的複合驅動程式庫,輸出內容將如下所示:
Name : focaltech_touch
Driver : None
Nodes : 2
Node 0 : None
3 Bind Rules
[ 1/ 3] : Accept "fuchsia.hardware.i2c.Service" { "fuchsia.hardware.i2c.Service.ZirconTransport" }
[ 2/ 3] : Accept "fuchsia.BIND_I2C_BUS_ID" { 0x000001 }
[ 3/ 3] : Accept "fuchsia.BIND_I2C_ADDRESS" { 0x000038 }
1 Properties
[ 1/ 2] : Key "fuchsia.hardware.i2c.Service" Value "fuchsia.hardware.i2c.Service.ZirconTransport"
[ 2/ 2] : Key "fuchsia.BIND_I2C_ADDRESS" Value 0x000038
Node 1 : None
2 Bind Rules
[ 1/ 2] : Accept "fuchsia.BIND_PROTOCOL" { 0x000014 }
[ 2/ 2] : Accept "fuchsia.BIND_GPIO_PIN" { 0x000004 }
2 Properties
[ 1/ 2] : Key "fuchsia.BIND_PROTOCOL" Value 0x000014
[ 2/ 2] : Key "fuchsia.gpio.FUNCTION" Value "fuchsia.gpio.FUNCTION.TOUCH_INTERRUPT