概览
本指南介绍了如何使用以下代码将复合节点添加到驱动程序框架中 复合节点规范本文档假定您熟悉以下内容:
创建复合节点
复合节点 是 节点 和多个家长一起玩要创建 复合节点,您需要执行以下操作:
- 在驱动程序中定义复合节点规范
- 创建绑定规则与规范匹配的复合驱动程序
当 driver 定义了一个规范, 过程如下:
- 通过 驾驶管理器 问 驱动程序索引,用于查找符合规范的复合驱动程序
- 找到匹配的复合驱动程序后,驱动程序管理器会查找 在与每个父级规范匹配的拓扑中每个匹配的节点 会成为复合节点的父节点。
- 在所有父级规范匹配后,驱动程序管理器会创建一个 以这些节点作为父项的复合节点,并将复合驱动程序绑定到 。主节点和节点名称由复合驱动程序提供。
定义复合节点规范
复合节点规范是一组父规范, 将作为复合节点的父级节点每个父规范包含 以下:
- 绑定规则 - 绑定规则 用于 将父规范与节点进行匹配。
- 属性 - 父级规范中用于匹配的属性 并违反复合驱动程序的绑定规则。它们的格式与节点格式 属性。
绑定规则
绑定规则用于查找节点并将其与父规范进行匹配。通过 根据绑定规则评估节点属性,如果匹配,则 会成为该组合的父级。
父级规范的绑定规则由接受的一系列 和遭拒的属性值。为了匹配绑定规则 必须包含所有已接受的节点属性值,而不是任何被拒绝的节点属性值 。
例如,如果父规范包含绑定规则:
- 接受
fuchsia.BIND_PROTOCOL
值 15 和 17 - 拒绝
fuchsia.BIND_PLATFORM_DEV_VID
个值“Intel”
然后,如果设备的
fuchsia.BIND_PROTOCOL
属性,并且不包含“Intel”值
fuchsia.BIND_PLATFORM_DEV_VID
属性。
确定绑定规则
确定绑定规则的操作过程与 绑定语言中的绑定规则。 要确定绑定规则,您首先需要找到 要绑定的目标对象
您可以使用命令 ffx driver list-devices -v
来输出
节点拓扑中的每个节点:
Name : i2c-1-56
Topo Path: sys/platform/i2c-0/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 库和绑定库代码生成值,我们可以编写
以下:
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),
};
在驱动程序框架 v2 (DFv2) 中编写
在 DFv2 中,复合节点规范是
composite_node_spec.fidl
在 fuchsia.driver.framework
FIDL 库中。通过
composite_node_spec.h
sdk/lib/driver/component/cpp
中的库可用于简化定义
绑定规则
使用该库并绑定库代码生成值,我们可以编写 以下:
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 库和绑定库代码生成值,我们可以编写
以下:
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),
};
在驱动程序框架 v2 (DFv2) 中编写
在 DFv2 中,复合节点规范是
composite_node_spec.fidl
(位于 fuchsia.driver.framework FIDL 库中)。通过
node_add_args.h
库
//sdk/lib/driver/component/cpp
可用于简化绑定定义
规则。
auto i2c_properties[] = std::vector {
ddk::MakeProperty(bind_fuchsia::I2C_ADDRESS,
bind_fuchsia_focaltech_platform::BIND_I2C_ADDRESS_TOUCH),
};
添加复合节点规范
创建复合节点规范涉及定义和添加一组 父规范传递给驱动程序管理器。
平台总线复合型
如果复合节点需要
平台总线
然后
板驱动程序
可以添加复合节点
请参阅
platform_bus.fidl
API。这适用于 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 使用在CompositeNodeSpec
composite_node_spec.fidl
。
请参阅
使用 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()
插入,
平台设备,其中包含来自 VID、PID、
以及在 fpbus::Node dev
中提供的 DID。其余父级规范为
。
驱动程序框架 v1 (DFv1)
在 DFv1 中,驱动程序可以通过 DDK 库添加复合节点规范
通过 DdkAddCompositeNodeSpec()
函数实现。
驱动程序必须先在 spec.h 库中定义 CompositeNodeSpec
。使用
上述绑定规则和属性,就可以定义 CompositeNodeSpec
I2C 父规范:
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
中的 CompositeNodeManager
FIDL API,用于添加复合节点规范。
@discoverable
protocol CompositeNodeManager {
/// Add the given spec to the driver manager.
AddSpec(CompositeNodeSpec) -> () error CompositeNodeSpecError;
};
使用 FIDL 定义复合节点规范
CompositeNodeSpec
结构体在
composite_node_spec.fidl
。
您可以使用 spec.h
和 node_add_args.h
函数
在 sdk/lib/driver/component/cpp
库中定义绑定规则
属性。
使用该库,我们可以定义一个具有父节点规范的复合节点规范。 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