如需为 Fuchsia 系统中的设备提供服务,驱动程序必须绑定到设备节点。驱动程序管理器会维护节点的拓扑结构,其中每个节点代表对系统中硬件或虚拟设备的访问权限。绑定到设备节点后,驱动程序便可以开始为节点代表的设备提供服务。
该框架通过将每个节点的节点属性与驱动程序提供的一组绑定规则相关联,将驱动程序与设备节点进行匹配。绑定规则是一组逻辑规则,用于描述驱动程序支持哪些节点属性。
在本部分中,您将创建一个绑定到 edu
设备并实现裸驱动程序框架钩子的框架驱动程序。
创建新的驱动程序组件
首先,在 Bazel 工作区中为名为 qemu_edu
的驱动程序组件创建一个新的项目目录:
mkdir -p fuchsia-codelab/qemu_edu/drivers
完成本部分后,项目应具有以下目录结构:
//fuchsia-codelab/qemu_edu/drivers
|- BUILD.bazel
|- meta
| |- qemu_edu.cml
|- qemu_edu.bind
|- qemu_edu.cc
|- qemu_edu.h
创建 qemu_edu/drivers/BUILD.bazel
文件并添加以下语句,以包含 Fuchsia SDK 中的必要构建规则:
qemu_edu/drivers/BUILD.bazel
:
load(
"@rules_fuchsia//fuchsia:defs.bzl",
"fuchsia_cc_driver",
"fuchsia_component_manifest",
"fuchsia_driver_bind_bytecode",
"fuchsia_driver_component",
"fuchsia_package",
)
添加组件清单
组件清单文件定义了组件可执行文件的属性,包括绑定规则和组件的功能。驱动程序使用 driver
运行程序加载为共享库 (.so
)。
创建 qemu_edu/drivers/meta/qemu_edu.cml
文件并添加以下内容:
qemu_edu/drivers/meta/qemu_edu.cml
:
{
include: [
"syslog/client.shard.cml",
],
program: {
runner: 'driver',
binary: 'driver/libqemu_edu.so',
bind: 'meta/bind/qemu_edu.bindbc',
// Identifies the device categories, for compatibility tests. This
// example driver uses the 'misc' category; real drivers should
// select a more specific category.
device_categories: [
{ category: 'misc', subcategory: '' },
],
},
}
将以下 build 规则添加到 qemu_edu/drivers/BUILD.bazel
文件底部,以编译组件清单:
fuchsia_component_manifest()
:描述用于编译驱动程序的组件清单的源文件和依赖项。
qemu_edu/drivers/BUILD.bazel
:
fuchsia_component_manifest(
name = "manifest",
src = "meta/qemu_edu.cml",
includes = [
"@fuchsia_sdk//pkg/syslog:client",
],
)
配置绑定规则
绑定规则描述了此驱动程序可以支持哪些设备节点。这些条件列为一组,以引用设备节点属性中的键值对的条件语句的形式显示。为了将驱动程序视为匹配,对于给定的设备节点,所有规则都必须评估为 true。
创建 qemu_edu/drivers/qemu_edu.bind
并添加以下绑定规则,以声明驱动程序支持 VID 和 DID 与 edu
设备匹配的 PCI 设备:
qemu_edu/drivers/qemu_edu.bind
:
using fuchsia.pci;
fuchsia.BIND_FIDL_PROTOCOL == fuchsia.pci.BIND_PROTOCOL.DEVICE;
// PCI VID/DID pair defined in the QEMU edu device specification:
fuchsia.BIND_PCI_VID == 0x1234;
fuchsia.BIND_PCI_DID == 0x11e8;
将以下 build 规则添加到 qemu_edu/drivers/BUILD.bazel
文件底部,以编译绑定规则:
fuchsia_driver_bytecode_bind_rules()
:描述驱动程序的绑定规则的具体信息。rules
属性用于指定包含此驱动程序绑定规则的文件。deps
属性用于指定要与 rules 中指定的绑定规则一起使用的绑定库。
qemu_edu/drivers/BUILD.bazel
:
fuchsia_driver_bind_bytecode(
name = "bind_bytecode",
output = "qemu_edu.bindbc",
rules = "qemu_edu.bind",
deps = [
"@fuchsia_sdk//bind/fuchsia.pci",
],
)
实现驱动程序钩子
绑定驱动程序后,框架会加载组件二进制文件,并构建使用 FUCHSIA_DRIVER_EXPORT()
宏注册的驱动程序类的实例。驱动程序会替换 Start()
方法以执行任何初始化任务。
创建 qemu_edu/drivers/qemu_edu.h
和 qemu_edu/drivers/qemu_edu.cc
,并添加以下样板代码以创建驱动程序类并配置初始 Start()
钩子:
qemu_edu/drivers/qemu_edu.h
:
#ifndef FUCHSIA_CODELAB_CC_QEMU_EDU_H_
#define FUCHSIA_CODELAB_CC_QEMU_EDU_H_
#include <fidl/examples.qemuedu/cpp/wire.h>
#include <lib/driver/component/cpp/driver_base.h>
#include <lib/driver/devfs/cpp/connector.h>
namespace qemu_edu {
class QemuEduDriver : public fdf::DriverBase {
public:
QemuEduDriver(fdf::DriverStartArgs start_args,
fdf::UnownedSynchronizedDispatcher driver_dispatcher)
: fdf::DriverBase("qemu-edu", std::move(start_args), std::move(driver_dispatcher)),
devfs_connector_(fit::bind_member<&QemuEduDriver::Serve>(this)) {}
virtual ~QemuEduDriver() = default;
// Start hook called by the driver factory.
zx::result<> Start() override;
private:
zx::result<> ExportToDevfs();
void Serve(fidl::ServerEnd<examples_qemuedu::Device> request);
fidl::WireSyncClient<fuchsia_driver_framework::Node> node_;
fidl::WireSyncClient<fuchsia_driver_framework::NodeController> controller_;
driver_devfs::Connector<examples_qemuedu::Device> devfs_connector_;
};
} // namespace qemu_edu
#endif // FUCHSIA_CODELAB_CC_QEMU_EDU_H_
qemu_edu/drivers/qemu_edu.cc
:
#include "qemu_edu.h"
#include <lib/driver/component/cpp/driver_export.h>
namespace qemu_edu {
// Initialize this driver instance
zx::result<> QemuEduDriver::Start() {
FDF_SLOG(INFO, "edu driver loaded successfully");
return zx::ok();
}
} // namespace qemu_edu
// Register driver hooks with the framework
FUCHSIA_DRIVER_EXPORT(qemu_edu::QemuEduDriver);
将以下 build 规则添加到 qemu_edu/drivers/BUILD.bazel
文件的底部,以将驱动程序代码编译为共享库二进制文件:
fuchsia_cc_driver()
:指定用于为 Fuchsia 构建 C++ 驱动程序的源文件和头文件(例如qemu_edu.cc
和qemu_edu.h
)。
qemu_edu/drivers/BUILD.bazel
:
fuchsia_cc_driver(
name = "qemu_edu",
srcs = [
"qemu_edu.cc",
"qemu_edu.h",
],
deps = [
"@fuchsia_sdk//pkg/driver_component_cpp",
"@fuchsia_sdk//pkg/driver_devfs_cpp",
"@fuchsia_sdk//pkg/hwreg",
"@fuchsia_sdk//pkg/mmio",
],
)
加载驱动程序
初始框架就绪后,您可以将驱动程序发布到本地软件包仓库,并验证它是否已成功绑定到 edu
设备。
将以下规则添加到 qemu_edu/drivers/BUILD.bazel
文件的底部,以将驱动程序组件构建为 Fuchsia 软件包:
fuchsia_driver_component()
:描述qemu_edu
驱动程序组件的二进制文件和工件。fuchsia_package()
:将驱动程序组件构建为 Fuchsia 软件包。
qemu_edu/drivers/BUILD.bazel
:
fuchsia_driver_component(
name = "component",
bind_bytecode = ":bind_bytecode",
driver_lib = ":qemu_edu",
manifest = ":manifest",
)
fuchsia_package(
name = "pkg",
package_name = "qemu_edu",
components = [
":component",
],
visibility = ["//visibility:public"],
)
使用 bazel run
命令构建和执行组件目标:
bazel run //fuchsia-codelab/qemu_edu/drivers:pkg.component
bazel run
命令会执行以下步骤:
- 构建组件并打包。
- 将软件包发布到本地软件包代码库。
- 向目标设备注册软件包仓库。
- 使用
ffx driver register
加载驱动程序组件。
您应该会看到驱动程序框架自动检测到匹配项,并将驱动程序绑定到 edu
设备节点:
INFO: Build completed successfully, 1 total action
added repository bazel.pkg.component
Registering fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm
Successfully bound:
Node 'root.sys.platform.pt.PCI0.bus.00_06_0_.pci-00_06.0-fidl', Driver 'fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm'.
检查系统日志,并验证在驱动程序成功绑定后,您是否可以从驱动程序代码中看到 FDF_SLOG()
消息:
ffx log --filter qemu_edu
[driver_index][driver_index,driver][I] Registered driver successfully: fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm.
[driver_manager][driver_manager.cm][I]: [driver_runner.cc:959] Binding fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm to 00_06_0_
[full-drivers:root.sys.platform.pt.PCI0.bus.00_06_0_][qemu-edu,driver][I]: [fuchsia-codelab/qemu_edu/qemu_edu.cc:28] edu driver loaded successfully
[driver-hosts:driver-host-3][][I]: [../../src/devices/bin/driver_host/driver_host.cc:349] Started driver url=fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm
探索更新后的设备节点
现在,驱动程序已成功绑定到设备节点,ffx driver list
会报告驱动程序已加载:
ffx driver list --loaded
fuchsia-boot:///#meta/block.core.cm
fuchsia-boot:///#meta/bus-pci.cm
fuchsia-boot:///#meta/cpu-trace.cm
fuchsia-boot:///#meta/fvm.cm
fuchsia-boot:///#meta/hid.cm
fuchsia-boot:///#meta/intel-rtc.cm
fuchsia-boot:///#meta/netdevice-migration.cm
fuchsia-boot:///#meta/network-device.cm
fuchsia-boot:///#meta/pc-ps2.cm
fuchsia-boot:///#meta/platform-bus-x86.cm
fuchsia-boot:///#meta/platform-bus.cm
fuchsia-boot:///#meta/ramdisk.cm
fuchsia-boot:///#meta/sysmem.cm
fuchsia-boot:///#meta/virtio_block.cm
fuchsia-boot:///#meta/virtio_ethernet.cm
fuchsia-pkg://fuchsia.com/virtual_audio#meta/virtual_audio_driver.cm
fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm
使用 ffx driver list-devices
再次检查设备节点,并验证您的驱动程序现在是否列为已附加到 edu
设备节点:
ffx driver list-devices root.sys.platform.pt.PCI0.bus.00_06_0_.pci-00_06.0-fidl --verbose
Name : 0-fidl
Moniker : root.sys.platform.pt.PCI0.bus.00_06_0_.pci-00_06.0-fidl
Driver : fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm
11 Properties
[ 1/ 11] : Key fuchsia.BIND_FIDL_PROTOCOL Value 0x000004
[ 2/ 11] : Key fuchsia.BIND_PCI_VID Value 0x001234
[ 3/ 11] : Key fuchsia.BIND_PCI_DID Value 0x0011e8
[ 4/ 11] : Key fuchsia.BIND_PCI_CLASS Value 0x000000
[ 5/ 11] : Key fuchsia.BIND_PCI_SUBCLASS Value 0x0000ff
[ 6/ 11] : Key fuchsia.BIND_PCI_INTERFACE Value 0x000000
[ 7/ 11] : Key fuchsia.BIND_PCI_REVISION Value 0x000010
[ 8/ 11] : Key fuchsia.BIND_PCI_TOPO Value 0x000030
[ 9/ 11] : Key "fuchsia.hardware.pci.Device" Value true
[10/ 11] : Key fuchsia.BIND_PROTOCOL Value 0x000000
[11/ 11] : Key "fuchsia.platform.DRIVER_FRAMEWORK_VERSION" Value 0x000002
恭喜!您已成功将驱动程序组件绑定到 Fuchsia 上的设备节点。