将 PnP 设备添加到正在运行的系统

本部分介绍系统配置用户已添加到正在运行的计算机的 PnP 设备时发生的事件序列。 本讨论重点介绍 PnP 管理器、总线驱动程序以及函数和筛选器驱动程序在枚举和配置新设备方面的角色。

大部分讨论还与配置启动计算机时存在的 PnP 设备相关。 具体而言,在 INF 文件中将驱动程序标记为SERVICE_DEMAND_START的设备的配置方式基本上与设备是动态添加的,还是在启动时存在,其配置方式基本相同。

下图显示了配置设备的第一步,从用户将硬件插入计算机开始。

说明枚举和报告即插即用设备的示意图。

以下注释对应于上图中带圆圈的数字:

  1. 用户将 PnP 设备插入 PnP 总线上的可用槽。

    在此示例中,用户将 PnP USB 游戏杆插入 USB 主机控制器上的集线器。 USB 集线器是 PnP 总线设备,因为子设备可以连接到它。

  2. 总线设备的函数驱动程序确定新设备在其总线上。

    驱动程序如何确定这一点取决于总线体系结构。 对于某些总线,总线函数驱动程序会收到新设备的热插拔通知。 如果总线不支持热插拔通知,则用户必须在控制面板中采取适当的操作,以枚举总线。

    在此示例中,USB 总线支持热插拔通知,因此 USB 总线的函数驱动程序会收到其子级已更改的通知。

  3. 总线设备的函数驱动程序通知 PnP 管理器其子设备集已更改。

    函数驱动程序使用 BusRelations 类型调用 IoInvalidateDeviceRelations 来通知 PnP 管理器。

  4. PnP 管理器查询总线的驱动程序,以获取总线上的当前设备列表。

    PnP 管理器将 IRP_MN_QUERY_DEVICE_RELATIONS 请求发送到总线的设备堆栈。 Parameters.QueryDeviceRelations.Type 值为 BusRelations,表示 PnP 管理器正在请求总线上存在的当前设备列表, (总线关系) 。

    PnP 管理器将 IRP 发送到总线的设备堆栈中的顶部驱动程序。 根据 PnP IRP 的规则,堆栈中的每个驱动程序处理 IRP(如果适用),并将 IRP 向下传递到下一个驱动程序。

  5. 总线设备的函数驱动程序处理 IRP。

    有关处理此 IRP 的详细信息,请参阅 IRP_MN_QUERY_DEVICE_RELATIONS 参考页。

    在此示例中,USB 集线器驱动程序处理中心 FDO 的此 IRP。 中心驱动程序为游戏杆设备创建 PDO ,并在使用 IRP 返回的子设备列表中包括指向游戏杆 PDO 的引用指针。

    当 USB 中心的父总线驱动程序 (USB 主机控制器类/微型类驱动程序对) 完成 IRP 时,IRP 将通过中心驱动程序注册的任何 IoCompletion 例程来备份设备堆栈。

请注意,总线函数驱动程序通过请求 PnP 管理器查询其子设备列表来报告其子设备列表中的更改。 总线设备的所有驱动程序都可以看到生成的 IRP_MN_QUERY_DEVICE_RELATIONS 请求。 通常,总线函数驱动程序是处理 IRP 和报表子级的唯一驱动程序。 在某些设备堆栈中,存在总线筛选器驱动程序,并参与构建总线关系列表。 一个示例是 ACPI,它附加为 ACPI 设备的总线筛选器驱动程序。 在某些设备堆栈中,非总线筛选器驱动程序处理 IRP_MN_QUERY_DEVICE_RELATIONS 请求,但这并不典型。

此时,PnP 管理器在总线上具有当前设备列表。 然后,PnP 管理器确定任何设备是新到达设备还是已删除设备。 在此示例中,有一个新设备。 下图显示了为新设备创建开发节点并开始配置设备的 PnP 管理器。

说明为新即插即用设备创建开发节点的示意图。

以下注释对应于上图中带圆圈的数字:

  1. PnP 管理器为总线上的任何新子设备创建开发节点。

    PnP 管理器将 IRP_MN_QUERY_DEVICE_RELATIONS IRP 中返回的总线关系列表与当前记录在 PnP 设备树中的总线的子级列表进行比较。 PnP 管理器为每个新设备创建一个开发节点,并为已删除的任何设备启动删除处理。

    在此示例中,有一个新设备 (游戏杆) ,因此 PnP 管理器为游戏杆创建开发节点。 此时,为游戏杆配置的唯一驱动程序是父 USB 集线器总线驱动程序,该驱动程序创建了游戏杆的 PDO。 设备堆栈中也会存在任何可选的总线筛选器驱动程序,但为简单起见,本示例省略了总线筛选器驱动程序。

    上图中两个开发节点之间的宽箭头指示游戏杆开发节点是 USB 集线器开发节点的子级。

  2. PnP 管理器收集有关新设备的信息,并开始配置设备。

    PnP 管理器将一系列 IRP 发送到设备堆栈,以收集有关设备的信息。 此时,设备堆栈仅包含设备的父总线驱动程序创建的 PDO,以及任何可选总线筛选器驱动程序的筛选 DO。 因此,总线驱动程序和总线筛选器驱动程序是唯一响应这些 IRP 的驱动程序。 在此示例中,游戏杆设备堆栈中唯一的驱动程序是父总线驱动程序,即 USB 集线器驱动程序。

    PnP 管理器通过向设备堆栈发送 IRP 来收集有关新设备的信息。 这些 IRP 包括以下内容:

    在处理新 PnP 设备的这一阶段,PnP 管理器发送上面列出的 IRP,但不一定按列出的顺序发送,因此不应假设 IRP 的发送顺序。 此外,不应假定 PnP 管理器仅发送上面列出的 IRP。

    PnP 管理器检查注册表以确定设备以前是否已安装在此计算机上。 PnP 管理器在 Enum 分支下检查<设备的枚举器>\<deviceID> 子项。 在此示例中,该设备是新设备,必须“从头开始”进行配置。

  3. PnP 管理器将有关设备的信息存储在注册表中。

    注册表的 枚举 分支保留供操作系统组件使用,其布局可能会更改。 驱动程序编写器必须使用系统例程来提取与驱动程序相关的信息。 请勿直接从驱动程序访问 枚举 分支。 列出的以下 枚举 信息仅用于调试目的。

    • PnP 管理器在设备的枚举器的键下为设备创建子项。

      PnP 管理器创建名为 HKLM\System\CurrentControlSet\Enum\<enumeratordeviceID> 的>\<子项。 如果枚举器>子项尚不存在,则创建<该子项。

      枚举器是基于 PnP 硬件标准发现 PnP 设备的组件。 枚举器的任务由 PnP 总线驱动程序与 PnP 管理器合作执行。 设备通常由其父总线驱动程序(例如 PCI 或 PCMCIA)枚举。 某些设备由总线筛选器驱动程序(如 ACPI)枚举。

    • PnP 管理器为设备的此实例创建子项。

      如果 Capabilities.UniqueIDIRP_MN_QUERY_CAPABILITIES 返回为 TRUE,则设备的唯一 ID 在系统中是唯一的。 如果没有,PnP 管理器会修改 ID,使其在系统范围内是唯一的。

      PnP 管理器创建名为 HKLM\System\CurrentControlSet\Enum\<enumerator><\deviceID>\<instanceID> 的子项。

    • PnP 管理器将有关设备的信息写入设备实例的子项。

      PnP 管理器存储信息(包括以下内容)(如果为设备提供):

      DeviceDesc — 来自 IRP_MN_QUERY_DEVICE_TEXT

      位置来自 IRP_MN_QUERY_DEVICE_TEXT

      功能 - 来自 IRP_MN_QUERY_CAPABILITIES 的标志

      UINumber — 来自 IRP_MN_QUERY_CAPABILITIES

      HardwareID — 来自 IRP_MN_QUERY_ID

      CompatibleIDs - 来自 IRP_MN_QUERY_ID

      ContainerID — 来自 IRP_MN_QUERY_ID

      LogConf\BootConfig — 来自 IRP_MN_QUERY_RESOURCES

      LogConf\BasicConfigVector — 来自 IRP_MN_QUERY_RESOURCE_REQUIREMENTS

此时,PnP 管理器已准备好查找设备的函数驱动程序和筛选器驱动程序(如果有)。 (请参阅下图。)

说明查找函数和筛选器驱动程序的示意图。

以下注释对应于上图中的编号圆圈:

  1. 内核模式 PnP 管理器与用户模式 PnP 管理器和用户模式安装程序组件进行协调,以查找设备的函数和筛选器驱动程序(如果有)。

    内核模式 PnP 管理器将事件排队到用户模式 PnP 管理器,标识需要安装的设备。 特权用户登录后,用户模式组件将继续查找驱动程序。 有关安装组件及其在安装设备中的作用的信息,请参阅设备安装 概述

  2. 用户模式安装程序组件指示内核模式 PnP 管理器加载函数和筛选器驱动程序。

    用户模式组件调用回内核模式以加载驱动程序,从而导致调用其 AddDevice 例程。

下图显示了 PnP 管理器加载驱动程序(如果适用) () ,调用其 AddDevice 例程,并指示驱动程序启动设备。

说明调用 adddevice 例程和启动新设备的示意图。

以下注释对应于上图中的编号圆圈:

  1. 低筛选器驱动程序

    在函数驱动程序附加到设备堆栈之前,PnP 管理器会处理任何低筛选器驱动程序。 对于每个低筛选器驱动程序,如果驱动程序尚未加载,PnP 管理器会调用驱动程序的 DriverEntry 例程。 然后,PnP 管理器调用驱动程序的 AddDevice 例程。 在其 AddDevice 例程中,筛选器驱动程序 (筛选器 DO) 创建筛选器设备对象,并将其附加到设备堆栈 (IoAttachDeviceToDeviceStack) 。 将设备对象附加到设备堆栈后,驱动程序将作为设备的驱动程序使用。

    在 USB 游戏杆示例中,有一个适用于设备的低筛选器驱动程序。

  2. 函数驱动程序

    附加任何较低的筛选器后,PnP 管理器将处理函数驱动程序。 如果尚未加载驱动程序,则 PnP 管理器会调用函数驱动程序的 DriverEntry 例程,并调用函数驱动程序的 AddDevice 例程。 函数驱动程序 (FDO) 创建函数设备对象,并将其附加到设备堆栈。

    在此示例中,USB 游戏杆的函数驱动程序实际上是一对驱动程序:HID 类驱动程序和 HID 微类驱动程序。 这两个驱动程序协同工作,充当函数驱动程序。 驱动程序对仅创建一个 FDO 并将其附加到设备堆栈。

  3. 上层筛选器驱动程序

    附加函数驱动程序后,PnP 管理器将处理任何上层筛选器驱动程序。

    在此示例中,有一个适用于设备的上层筛选器驱动程序。

  4. 分配资源和启动设备

    如果需要,PnP 管理器会向设备分配资源,并发出 IRP 来启动设备。

    • 分配资源

      在配置过程的早期,PnP 管理器从设备的父总线驱动程序中收集了设备的硬件资源要求。 为设备加载完整的驱动程序集后,PnP 管理器会向设备堆栈发送 IRP_MN_FILTER_RESOURCE_REQUIREMENTS 请求。 堆栈中的所有驱动程序都有机会处理此 IRP 并在必要时修改设备的资源要求列表。

      如果设备需要资源,则 PnP 管理器会根据设备的要求和当前可用的资源将资源分配给设备。

      PnP 管理器可能需要重新排列现有设备的资源分配以满足新设备的需求。 这种资源重新分配称为“重新均衡”。现有设备的驱动程序在重新平衡期间接收一系列停止和启动 IRP,但重新平衡必须对用户透明。

      在 USB 游戏杆示例中,USB 设备不需要硬件资源,因此 PnP 管理器将资源列表设置为 NULL

    • 启动设备 (IRP_MN_START_DEVICE)

      PnP 管理器将资源分配给设备后,会将 IRP_MN_START_DEVICE IRP 发送到设备堆栈,以指示驱动程序启动设备。

    启动设备后,PnP 管理器再向设备的驱动程序发送三个 IRP:

    • IRP_MN_QUERY_CAPABILITIES

      启动 IRP 成功完成后,PnP 管理器将另一 个IRP_MN_QUERY_CAPABILITIES IRP 发送到设备堆栈。 设备的所有驱动程序都可以选择处理 IRP。 PnP 管理器此时会在附加所有驱动程序并启动设备后发送此 IRP,因为函数或筛选器驱动程序可能需要访问设备来收集功能信息。

    • IRP_MN_QUERY_PNP_DEVICE_STATE

      例如,此 IRP 使驱动程序有机会报告设备不应显示在用户界面(如 设备管理器 和 Hotplug 程序)中。 这对于系统上存在但在当前配置中不可用的设备(例如,在取消停靠笔记本电脑时无法使用的笔记本电脑上的游戏端口)非常有用。

    • 总线关系的IRP_MN_QUERY_DEVICE_RELATIONS

      PnP 管理器发送此 IRP 以确定设备是否具有任何子设备。 如果是这样,PnP 管理器将配置每个子设备。

使用 GUID_PNP_LOCATION_INTERFACE

GUID_PNP_LOCATION_INTERFACE 接口为设备提供 SPDRP_LOCATION_PATHS 即插即用 (PnP) 设备属性。

若要在驱动程序中实现此接口,请处理 interfaceType = GUID_PNP_LOCATION_INTERFACE IRP_MN_QUERY_INTERFACE IRP。 驱动程序提供指向PNP_LOCATION_INTERFACE结构的指针,该结构包含指向接口的各个例程的指针。 PnpGetLocationString 例程提供设备SPDRP_LOCATION_PATHS属性中特定于设备的部分。