设备节点和设备堆栈

在 Windows 中,设备由即插即用(PnP)设备树中的设备节点表示。 通常,当 I/O 请求发送到设备时,多个驱动程序会帮助处理请求。 其中每个驱动程序都与设备对象相关联,设备对象排列在堆栈中。 设备对象的序列及其关联的驱动程序称为设备堆栈。 每个设备节点都有自己的设备堆栈。

设备节点和即插即用设备树

Windows 在名为 即插即用设备树的树结构中组织设备,或只是 设备树。 通常,设备树中的节点表示复合设备上的设备或单个功能。 但是,某些节点表示与物理设备没有关联的软件组件。

设备树中的节点称为 设备节点。 设备树的根节点称为 根设备节点。 按照约定,根设备节点在设备树底部绘制,如下图所示。

显示设备节点的设备树的示意图。

设备树说明了 PnP 环境中固有的父/子关系。 设备树中的几个节点表示连接子设备的总线。 例如,PCI 总线节点表示主板上的物理 PCI 总线。 在启动期间,PnP 管理器要求 PCI 总线驱动程序枚举连接到 PCI 总线的设备。 这些设备由 PCI 总线节点的子节点表示。 在上图中,PCI 总线节点具有连接到 PCI 总线的多个设备的子节点,包括 USB 主机控制器、音频控制器和 PCI Express 端口。

连接到 PCI 总线的某些设备本身是总线。 PnP 管理器要求每个总线枚举其连接的设备。 在上图中,我们可以看到音频控制器是一个连接了音频设备的总线。 我们可以看到,PCI Express 端口是一条总线,连接了一个显示适配器,而显示适配器则连接到一个监视器。

无论你认为节点是表示设备还是总线,都取决于你的观点。 例如,可以将显示适配器视为在准备屏幕上显示的帧方面发挥关键作用的设备。 但是,还可以将显示适配器视为能够检测和枚举连接的监视器的总线。

设备对象和设备堆栈

设备对象DEVICE_OBJECT结构的实例。 PnP 设备树中的每个设备节点都有设备对象的有序列表,其中每个设备对象都与驱动程序相关联。 设备对象的有序列表及其关联的驱动程序称为 设备节点的设备堆栈

可以通过多种方式来考虑设备堆栈。 在最正式的意义上,设备堆栈是有序的(设备对象、驱动程序)对列表。 但是,在某些上下文中,将设备堆栈视为设备对象的有序列表可能很有用。 在其他上下文中,将设备堆栈视为驱动程序的有序列表可能很有用。

按照约定,设备堆栈具有顶部和底部。 在设备堆栈中创建的第一个设备对象位于底部,要创建并附加到设备堆栈的最后一个设备对象位于顶部。

在下图中,Proseware Gizmo 设备节点具有一个设备堆栈,其中包含三个(设备对象、驱动程序)对。 顶部设备对象与驱动程序 AfterThought.sys相关联,中间设备对象与驱动程序 Proseware.sys相关联,底部设备对象与驱动程序 Pci.sys相关联。 关系图中心内的 PCI 总线节点具有一个设备堆栈,其中包含两个(设备对象、驱动程序)对,即与 Pci.sys 关联的设备对象以及与 Acpi.sys关联的设备对象。

此图显示了在 proseware gizmo 和 pci 设备节点中的设备堆栈中排序的设备对象。

如何构造设备堆栈?

在启动期间,PnP 管理器要求驱动程序为每个总线枚举连接到总线的子设备。 例如,PnP 管理器要求 PCI 总线驱动程序(Pci.sys)枚举连接到 PCI 总线的设备。 为了响应此请求,Pci.sys 为每个连接到 PCI 总线的设备创建设备对象。 其中每个设备对象称为 物理设备对象 (PDO)。 Pci.sys 创建 PDO 集后不久,设备树将类似于下图所示的设备树。

子设备的 pci 节点和物理设备对象的示意图。

PnP 管理器将设备节点与每个新创建的 PDO 相关联,并在注册表中查找以确定哪些驱动程序需要是节点的设备堆栈的一部分。 设备堆栈必须具有一个(且只有一个) 函数驱动程序 ,并且可以选择性地具有一个或多个 筛选器驱动程序。 函数驱动程序是设备堆栈的主要驱动程序,负责处理读取、写入和设备控制请求。 筛选器驱动程序在处理读取、写入和设备控制请求时扮演辅助角色。 加载每个函数和筛选器驱动程序时,它将创建一个设备对象,并将其附加到设备堆栈。 由函数驱动程序创建的设备 对象称为功能设备对象 (FDO),筛选器驱动程序创建的设备 对象称为筛选器设备对象 (Filter DO)。 现在,设备树如下所示。

显示 proseware gizmo 设备节点中的筛选器、函数和物理设备对象的设备树图。

在关系图中,请注意,在一个节点中,筛选器驱动程序高于函数驱动程序,而在其他节点中,筛选器驱动程序位于函数驱动程序下方。 设备堆栈中函数驱动程序上方的筛选器驱动程序称为 上层筛选器驱动程序。 函数驱动程序下方的筛选器驱动程序称为 较低筛选器驱动程序

PDO 始终是设备堆栈中的底部设备对象。 这源于设备堆栈的构造方式。 首先创建 PDO,并且当其他设备对象附加到堆栈时,它们将附加到现有堆栈的顶部。

注意 安装设备的驱动程序时,安装程序使用信息(INF)文件中的信息来确定哪个驱动程序是函数驱动程序,哪些驱动程序是筛选器。 通常,INF 文件由Microsoft或硬件供应商提供。 安装设备的驱动程序后,PnP 管理器可以通过在注册表中查找来确定设备的函数和筛选器驱动程序。

总线驱动程序

在上图中,可以看到驱动程序 Pci.sys 扮演两个角色。 首先,Pci.sys 与 PCI 总线设备节点中的 FDO 相关联。 事实上,它在 PCI 总线设备节点中创建 FDO。 因此,Pci.sys 是 PCI 总线的功能驱动程序。 其次,Pci.sys 与 PCI 总线节点的每个子节点中的 PDO 相关联。 请回想一下,它为子设备创建了PDO。 为设备节点创建 PDO 的驱动程序称为节点的 总线驱动程序

如果参考点是 PCI 总线,则 Pci.sys 是函数驱动程序。 但是,如果你的参考点是 Proseware Gizmo 设备,则 Pci.sys 是总线驱动程序。 此双重角色在 PnP 设备树中很典型。 作为总线功能驱动程序的驱动程序,同时也充当该总线的子设备的总线驱动程序。

用户模式设备堆栈

到目前为止,我们一直在讨论内核模式设备堆栈。 也就是说,堆栈中的驱动程序在内核模式下运行,设备对象将映射到系统空间,这是只能在内核模式下运行的代码的地址空间。 有关内核模式与用户模式之间的差异的信息,请参阅 用户模式和内核模式

在某些情况下,除了其内核模式设备堆栈外,设备还具有用户模式设备堆栈。 用户模式驱动程序通常基于 User-Mode Driver Framework (UMDF),这是 Windows 驱动程序框架(WDF)提供的驱动程序模型之一。 在 UMDF 中,驱动程序是用户模式 DLL,设备对象是实现 IWDFDevice 接口的 COM 对象。 UMDF 设备堆栈中的设备对象被称为 WDF 设备对象(WDF DO)

下图显示了 USB-FX-2 设备的设备节点、内核模式设备堆栈和用户模式设备堆栈。 用户模式和内核模式堆栈中的驱动程序都参与定向到 USB-FX-2 设备的 I/O 请求。

显示用户模式和内核模式设备堆栈的关系图。

面向所有驱动程序开发人员的概念

驱动程序堆栈