IRP_MN_QUERY_DEVICE_RELATIONS

PnP 管理器发送此请求以确定设备之间的某些关系。 以下类型的驱动程序处理此请求:

  • 总线驱动程序必须处理其适配器或控制器的 BusRelations 请求, (总线 FDO) 。 筛选器驱动程序可以处理 BusRelations 请求。

  • 总线驱动程序必须处理其子设备的 TargetDeviceRelation 请求 (子 PDO) 。

  • 函数和筛选器驱动程序可以处理 RemovalRelationsPowerRelations 请求。

  • 总线驱动程序可以处理其子设备的 弹出关系 请求 (子 PDO) 。

0x07

主代码

IRP_MJ_PNP

发送时

PnP 管理器发送此 IRP,以收集有关与指定设备有关系的设备的信息。

PnP 管理器在枚举设备时查询设备的 BusRelations (子设备) ,并在设备处于活动状态时查询其他时间(例如驱动程序调用 IoInvalidateDeviceRelations 例程以指示子设备已到达或离开)。

PnP 管理器在删除设备的驱动程序之前查询设备的 RemoveRelations 。 PnP 管理器在弹出设备之前查询 RemovalRelations弹出Relations

当驱动程序或用户模式应用程序在设备上注册 EventCategoryTargetDeviceChange 的 PnP 通知时,PnP 管理器会查询设备的 TargetDeviceRelation。 PnP 管理器查询与特定文件对象关联的设备。 IRP_MN_QUERY_DEVICE_RELATIONS 是唯一具有有效文件对象参数的 PnP IRP。 驱动程序可以查询 TargetDeviceRelation 的设备堆栈。 驱动程序在发送 TargetDeviceRelation 查询时不需要提供文件对象。

当设备的驱动程序调用 IoInvalidateDeviceRelations 时,PnP 管理器查询设备的 PowerRelations,以指示此设备具有隐式电源管理关系的设备集已更改。 从 Windows 7 开始支持 PowerRelations 请求。

对于 BusRelationsRemovalRelations弹出关系PowerRelations 请求,PnP 管理器在系统线程上下文中的 IRQL = PASSIVE_LEVEL 发送 IRP_MN_QUERY_DEVICE_RELATIONS

对于 TargetDeviceRelation 请求,PnP 管理器在任意线程上下文中的 IRQL = PASSIVE_LEVEL 发送此 IRP。

输入参数

IO_STACK_LOCATION 结构的 Parameters.QueryDeviceRelations.Type 成员指定要查询的关系类型。 可能的值包括 BusRelations弹出关系RemovalRelationsTargetDeviceRelationPowerRelations

仅当 Parameters.QueryDeviceRelations.Type 为 TargetDeviceRelation 时,当前 IO_STACK_LOCATION 结构的 FileObject 成员才会指向有效的文件对象。

输出参数

在 I/O 状态块中返回。

I/O 状态块

驱动程序将 Irp-IoStatus.Status> 设置为STATUS_SUCCESS或故障状态(例如STATUS_INSUFFICIENT_RESOURCES)。

成功后,驱动程序会将 Irp-IoStatus.Information> 设置为指向所请求关系信息的PDEVICE_RELATIONS指针。 DEVICE_RELATIONS结构定义如下:

typedef struct _DEVICE_RELATIONS {
  ULONG  Count;
  PDEVICE_OBJECT  Objects[1];  // variable length
} DEVICE_RELATIONS, *PDEVICE_RELATIONS;

Operation

如果驱动程序返回关系以响应此 IRP_MN_QUERY_DEVICE_RELATIONS,驱动程序将从包含计数和适当数量的设备对象指针的分页内存中分配 DEVICE_RELATIONS 结构。 PnP 管理器在不再需要结构时释放该结构。 如果驱动程序替换了另一个驱动程序分配 的 DEVICE_RELATIONS 结构,则驱动程序必须释放以前的结构。

驱动程序必须引用它在此 IRP (ObReferenceObject) 报告的任何设备的 PDO。 PnP 管理器在适当时删除引用。

函数或筛选器驱动程序应准备好在设备 完成 AddDevice 例程后随时为设备处理此 IRP。 总线驱动程序应准备好在枚举设备后立即处理 BusRelations 的 查询。

有关处理即插即用次要 IRP 的一般规则,请参阅即插即用

以下小节介绍了处理各种查询的具体操作。

BusRelations 请求

当 PnP 管理器查询 (适配器或控制器) 子设备的总线关系时,总线驱动程序必须返回指向总线上实际存在的任何设备的 PDO 的指针列表。 总线驱动程序报告所有设备,无论设备是否已启动。 总线驱动程序可能需要启动其总线设备,以确定存在哪些子级。

警告 设备对象不能传递到任何采用 PDO 作为参数的例程,直到 PnP 管理器为该对象创建设备节点 (devnode) 。 (如果驱动程序确实传递了设备对象,系统将 bug 检查检查0xCA:PNP_DETECTED_FATAL_ERROR.) PnP 管理器创建开发节点以响应IRP_MN_QUERY_DEVICE_RELATIONS请求。 驱动程序可以安全地假定 PDO 的开发节点在收到 IRP_MN_QUERY_RESOURCE_REQUIREMENTS 请求时已创建。

响应此 IRP 的总线驱动程序是总线适配器或控制器的功能驱动程序,而不是适配器或控制器连接到的总线的父总线驱动程序。 非总线设备的函数驱动程序不处理此查询。 此类驱动程序只是将 IRP 传递给下一个较低的驱动程序。 (请参阅下图。) 筛选器驱动程序通常不处理此查询。

在 Windows Vista 和更高版本的操作系统上,我们建议驱动程序始终将 IRP IRP_MN_QUERY_DEVICE_RELATIONS 并稍后完成其处理。 此顺序使系统能够异步处理总线关系查询。 (在 Windows Vista 之前的操作系统上,驱动程序可以从其调度例程中安全地返回STATUS_PENDING,但 PnP 管理器不会将总线关系查询与其他任何操作重叠。)

下图显示了驱动程序如何处理总线关系的查询。

说明处理总线关系的查询的驱动程序的关系图。

在如图所示的示例中,PnP 管理器将 BusRelations的IRP_MN_QUERY_DEVICE_RELATIONS发送到 USB 集线器设备的驱动程序。 PnP 管理器正在请求中心设备的子级列表。

  1. 与所有 PnP IRP 一样,PnP 管理器会将 IRP 发送到设备堆栈中的顶部驱动程序。

  2. 可选的筛选器驱动程序可能是堆栈中的顶级驱动程序。 筛选器驱动程序通常不处理此 IRP;它将 IRP 向下传递堆栈。 例如,如果驱动程序在总线上公开了不可枚举的设备,则筛选器驱动程序可能会处理此 IRP。

  3. USB 中心总线驱动程序处理 IRP。

    USB 集线器总线驱动程序:

    • 为没有 PDO 的任何子设备创建 PDO。

    • 将总线上不再存在的任何设备的 PDO 标记为非活动状态。 总线驱动程序不会删除此类 PDO。有关何时删除 PDO 的详细信息,请参阅 删除设备

    • 报告总线上存在的任何子设备。

      对于每个子设备,总线驱动程序引用 PDO,并将指向 PDO 的指针置于DEVICE_RELATIONS结构中。

      此示例中有两个 PDO:一个用于游戏杆设备,一个用于键盘设备。

      总线驱动程序应检查另一个驱动程序是否已为此 IRP 创建了DEVICE_RELATIONS结构。 如果是这样,则总线驱动程序必须添加到现有信息。

      如果总线上没有子设备,驱动程序在DEVICE_RELATIONS结构中将计数设置为零,并返回成功。

    • 在 I/O 状态块中设置适当的值,并将 IRP 传递给下一个较低的驱动程序。 适配器或控制器的总线驱动程序未完成 IRP。

  4. 可选的较低筛选器(如果存在)通常不会处理此 IRP。 此类筛选器驱动程序将 IRP 向下传递堆栈。 如果低筛选器驱动程序处理此 IRP,它可以将 PDO () 添加到子设备列表,但不得删除其他驱动程序创建的任何 PDO。

  5. 父总线驱动程序不会处理此 IRP,除非它是设备堆栈中唯一的驱动程序, (设备处于原始模式) 。 与所有 PnP IRP 一样,父总线驱动程序使用 IoCompleteRequest 完成 IRP。

    如果设备堆栈中存在一个或多个总线筛选器驱动程序,则如果存在 IoCompletion 例程) ,此类驱动程序可能会在 IRP 下到总线驱动程序和/或在 IRP 的备份设备堆栈 (处理 IRP。 根据 PnP IRP 规则,此类驱动程序可以在 IoCompletion 例程) IoCompletion 例程中,将 PDO 添加到 IRP 上,并/或修改 I (RP 上的关系列表。

弹出关系请求

驱动程序返回指向任何设备的 PDO 的指针,这些设备可能会在弹出指定设备时从系统中实际删除。 不报告设备子级的 PDO;PnP 管理器始终请求在其父设备之前删除子设备。

PnP 管理器将 IRP_MN_EJECT IRP 发送到正在弹出的设备。 此类设备的驱动程序还会收到删除 IRP。 设备的弹出关系接收 IRP_MN_REMOVE_DEVICE IRP (而不是 IRP_MN_EJECT IRP) 。

只有父总线驱动程序可以响应其子设备之一的 弹出 关系查询。 函数和筛选器驱动程序必须将其传递给设备堆栈中的下一个较低驱动程序。 如果总线驱动程序接收此 IRP 作为其适配器或控制器的函数驱动程序,则总线驱动程序正在执行函数驱动程序的任务,必须将 IRP 传递给下一个较低的驱动程序。

PowerRelations 请求

从 Windows 7 开始, PowerRelations 查询使驱动程序能够指定支持 PnP 枚举的父总线与总线上枚举子设备之间的传统关系之外的电源管理关系。 例如,如果总线驱动程序无法枚举总线上的子设备,或者设备是多个总线的子设备, 则 PowerRelations 查询可以描述子设备与总线或总线的电源关系。

当设备的驱动程序调用 IoInvalidateDeviceRelations 例程并指定 PowerRelations的 Type 参数值时,PnP 管理器会为设备发出 PowerRelations 查询。

为了响应此查询,目标设备的驱动程序 (即,作为查询) 目标的设备提供 一个DEVICE_RELATIONS 结构,该结构包含指向任何其他设备的 PDO 的指针,这些设备必须在目标设备打开之前由电源管理器打开。 相反,只有在目标设备关闭后,这些其他设备才必须关闭。 电源管理器使用查询中的信息来保证以正确的顺序打开和关闭这些设备。

此排序保证仅适用于全局系统睡眠状态转换,包括从 S1、S2、S3 (睡眠) 转换、S4 (休眠) 以及 S5 (关闭) 系统电源状态。 当系统保持 S0 (运行) 系统状态时,PowerRelations 排序保证不适用于 Dx 设备电源状态转换,但定向运行时电源管理 (DFx) 转换的情况除外。

如果目标设备位于特殊文件 (的设备路径上,例如分页文件、休眠文件或故障转储文件) ,则目标设备的驱动程序在处理 InPathTRUE的IRP_MN_DEVICE_USAGE_NOTIFICATION IRP 时必须执行附加步骤。 此驱动程序必须确保为 PowerRelations 查询提供 PDO 的设备也可以支持在特殊文件的设备路径中。 若要确认此支持,目标设备的驱动程序必须先将 IRP_MN_DEVICE_USAGE_NOTIFICATION IRP 发送到其中每个设备,并且此 IRP 必须指定与目标设备相同的 UsageNotification.Type 。 仅当接收此 IRP 的所有设备使用成功状态代码完成 IRP 时,目标设备的驱动程序才能成功完成 其IRP_MN_DEVICE_USAGE_NOTIFICATION IRP。 否则,此驱动程序必须使用失败状态代码完成此 IRP。

当此驱动程序处理 InPathFALSEIRP_MN_DEVICE_USAGE_NOTIFICATION IRP 时,驱动程序必须将IRP_MN_DEVICE_USAGE_NOTIFICATION IRP 发送到与 InPathTRUE 的同一组依赖设备。 但是, 当 InPathFALSE 时,驱动程序不应使用失败状态代码完成此 IRP。

响应 PowerRelations 查询的驱动程序应在为 PowerRelations 查询提供 PDO 的所有设备上注册目标设备更改通知。 若要注册这些通知,驱动程序可以调用 IoRegisterPlugPlayNotification 例程,并指定 EventCategoryTargetDeviceChange 的 EventCategory 参数值。

RemovalRelations 请求

驱动程序返回指向在删除指定设备的驱动程序时必须删除其驱动程序的任何设备的 PDO 的指针。 不报告设备子级的 PDO;在删除设备之前,PnP 管理器已请求删除子设备。

删除关系的顺序未定义。

设备堆栈中的任何驱动程序都可以处理这种类型的关系查询。 函数或筛选器驱动程序先处理 IRP,然后再将其传递到下一个较低的驱动程序。 总线驱动程序处理 IRP,然后完成它。

TargetDeviceRelation 请求

TargetDeviceRelation 查询使 PnP 管理器能够查询控制硬件的 PnP 设备堆栈中的 PDO 的非 PnP 设备堆栈。

通常,驱动程序将 IRP_MN_QUERY_DEVICE_RELATIONS IRP 向下转发其堆栈,直到 IRP 到达特定设备堆栈的底部。 然后,非 PnP 堆栈底部的驱动程序将 IRP 转发或重新颁发到相关的 PnP 堆栈。 例如,PnP 管理器可能会将 TargetDeviceRelation 查询发送到文件系统堆栈顶部的设备对象,这是非 PnP 堆栈。 文件系统堆栈中的每个设备对象都会将查询传递到它下面的设备对象,直到查询到达堆栈底部的设备对象。 堆栈中最低的设备对象会将 TargetDeviceRelation 查询转发或重新发出到 PnP 存储卷堆栈顶部的设备对象,然后将查询向下传递到存储卷堆栈底部的 PDO。

以下列表总结了可以安全地获取指向 PnP 设备堆栈底部 PDO 的指针的情况:

  • PnP 中的设备对象

    调用设备的 AddDevice 例程时,PnP 设备堆栈中的设备对象将了解堆栈的 PDO。 如果使用删除锁例程将指针与传入IRP_MN_REMOVE_DEVICE消息正确同步,驱动程序可以安全地缓存指向 PDO 的指针。

  • 非 PnP 堆栈中的设备对象,而不是堆栈底部的设备对象

    对于不在非 PnP 堆栈底部的设备对象,驱动程序可以发送 TargetDeviceRelation 查询以获取指向相应 PnP 设备堆栈底部的 PDO 的指针。

  • 设备的文件对象

    给定设备的文件对象,驱动程序可以调用 IoGetRelatedDeviceObject 来获取设备对象,然后按照前面的列表项中的说明进行操作。

  • 设备对象的句柄

    给定设备对象的句柄,驱动程序可以调用 ObReferenceObjectByHandle 来获取设备的文件对象,然后按照前面的列表项中的说明进行操作。

父总线驱动程序必须为其子设备处理 TargetDeviceRelation 关系查询。 总线驱动程序使用 ObReferenceObject 引用子设备的 PDO,并在 DEVICE_RELATIONS 结构中返回指向 PDO 的指针。 此关系类型的结构中只有一个 PDO 指针。 当驱动程序或应用程序在设备上注销通知时,PnP 管理器会删除对 PDO 的引用。

只有父总线驱动程序响应 TargetDeviceRelation 查询。 函数和筛选器驱动程序必须将其传递给设备堆栈中的下一个较低驱动程序。 如果总线驱动程序接收此 IRP 作为其适配器或控制器的函数驱动程序,则总线驱动程序正在执行函数驱动程序的任务,必须将 IRP 传递给下一个较低的驱动程序。

如果驱动程序不在基于 PDO 的堆栈中,则驱动程序会将新的目标设备关系查询 IRP 发送到与驱动程序执行 I/O 的文件句柄关联的设备对象。

发送此 IRP

驱动程序不得发送请求 BusRelations的IRP_MN_QUERY_DEVICE_RELATIONS。 驱动程序不限制发送此 IRP for RemovalRelations弹出关系,但驱动程序不太可能发送此 IRP。

驱动程序可以查询 TargetDeviceRelation 的设备堆栈。 有关发送 IRP 的信息,请参阅处理 IRP。 以下步骤专门适用于此 IRP:

  • 设置 IRP 的下一个 I/O 堆栈位置中的值:将 MajorFunction 设置为 IRP_MJ_PNP,将 MinorFunction 设置为 IRP_MN_QUERY_DEVICE_RELATIONS,将 Parameters.QueryDeviceRelations.Type 设置为 TargetDeviceRelation,并将 Irp-FileObject> 设置为有效的文件对象。

  • 初始化 IoStatus.Status 以STATUS_NOT_SUPPORTED。

如果驱动程序发送此 IRP 以让 PDO 报告以响应驱动程序收到的 TargetDeviceRelationIRP_MN_QUERY_DEVICE_RELATIONS,则驱动程序将报告 PDO 并在 IRP 完成后释放返回的关系结构。 如果驱动程序出于其他原因启动了此 IRP,则驱动程序在 IRP 完成时释放关系结构,并在不再需要 PDO 时取消引用。

要求

标头

Wdm.h(包括 Wdm.h、Ntddk.h 或 Ntifs.h)

另请参阅

AddDevice

IoCompleteRequest

IoGetRelatedDeviceObject

IoInvalidateDeviceRelations

IoRegisterPlugPlayNotification

IRP_MJ_PNP

IRP_MN_DEVICE_USAGE_NOTIFICATION

IRP_MN_EJECT

IRP_MN_QUERY_RESOURCE_REQUIREMENTS

IRP_MN_REMOVE_DEVICE

IO_STACK_LOCATION

ObReferenceObject

ObReferenceObjectByHandle