驱动程序通信

在 Fuchsia 中,对于驱动程序和非驱动程序,所有通信都通过 FIDL 调用进行。不同之处在于发现驱动程序服务的方式以及如何建立连接。

对于驱动程序到驱动程序的通信,Fuchsia 使用节点拓扑将父节点的功能放置在子节点的传入 FIDL 命名空间中(即 /svc 下作为目录和文件)。此设置使驱动程序(绑定到子节点后)能够访问从父节点提供给子节点的 FIDL 服务。

不过,从非驱动程序组件到驱动程序的通信分两个阶段进行:

  1. 服务发现(使用 devfs)
  2. FIDL 通信

对于非驱动程序组件,第一个任务是发现系统中可用的驱动程序服务。这些服务由当前绑定到表示系统中的硬件或虚拟设备的节点的驱动程序提供。名为 devfs 的文件系统提供了一种发现这些服务的机制。

非驾驶员与驾驶员之间的通信会发生以下事件:

  1. 为了发现系统中的驱动程序服务,非驱动程序组件会扫描 devfs 中的目录和文件。
  2. 非驱动程序组件会在 devfs 中找到表示目标驱动程序提供的服务的文件。
  3. 非驱动程序组件会打开此文件,以与目标驱动程序建立连接。
  4. 初次接触后,非驱动程序组件和驱动程序之间会建立 FIDL 连接。
  5. 从此时开始,所有通信均通过 FIDL 通道进行。

服务发现(使用 devfs)

驱动程序管理器会托管名为 devfs 的虚拟文件系统(如在“设备文件系统中”)。此虚拟文件系统可让对 Fuchsia 系统中的所有驱动程序服务统一访问 Fuchsia 的用户空间服务(即驱动程序外部的组件)。这些非驱动程序组件通过发现 devfs 中目标驱动程序的服务与驱动程序建立初始联系。

严格来说,devfs 是驱动程序管理器公开的目录功能。因此,按照惯例,要访问驱动程序的组件会将 devfs 装载到其命名空间的 /dev 目录下(尽管并不要求 devfs 始终装载在 /dev 下)。

devfs 会托管虚拟文件,借助这些虚拟文件,Fuchsia 组件可以将消息路由到由 Fuchsia 系统中运行的驱动程序实现的接口。换言之,当客户端(即非驱动程序组件)打开 /dev 目录下的文件时,它会接收一个通道,可用于直接对映射到该文件的驱动程序进行 FIDL 调用。例如,Fuchsia 组件可以通过打开类似 /dev/class/input-report/000 的文件并写入其中来连接到输入设备。在这种情况下,客户端可能会收到使用 fuchsia.input.report FIDL 的通道。

驱动程序添加新节点时,可以使用 DevfsAddArgs 表将自己导出到 devfs

FIDL 通信

使用 devfs 在非驱动程序组件和驱动程序组件之间发生初始接触后,这些组件就可以交换 FIDL 句柄。从此时开始,这些组件就像 Fuchsia 中的其他组件一样,利用 FIDL 调用进行通信。

作为紫红色组件,驱动程序有一个传入 FIDL 命名空间,其中包含了驱动程序可使用的功能。其中一些功能可能会从其父驱动程序提供给驱动程序(例如,PCI 设备将具有来自其父节点的 fuchsia.hardware.PCI 功能)。驱动程序可以使用这些功能对其父级驱动程序进行 FIDL 调用。同样,其客户端(即非驱动程序组件)也可以使用从驱动程序接收的功能对驱动程序进行 FIDL 调用。

默认情况下,这些 FIDL 调用通过 Zircon 内核进行路由。不过,如果目标驱动程序位于同一进程中(因此也在同一个驱动程序主机中),则驱动程序运行时可以路由 FIDL 调用以保持进程状态,而无需进出 Zircon 内核。