和PNP相关的IRP非常多,遗憾的是,它们并非都是必需的,所以这里仅仅给出一些常规实现功能的相关讲解,在那之前我们先看一下所有相关的IRP:
注意不会关注基于FDO的子总线的情况,这个最可能得应用是指的是UDE,但是老实说UDE的应用范围其实非常狭窄,我们先讨论设备生命周期,然后分别从功能驱动、过滤驱动、总线驱动三个方面来讨论设备的生命周期。
PNP设备启动
PnP 管理器向驱动程序发送 IRP_MN_START_DEVICE 请求,以启动新枚举的设备或重启已停止的现有设备以重新平衡资源。
功能驱动和Filter驱动程序必须设置 IoCompletion 例程,将 IRP_MN_START_DEVICE 请求向下传递设备堆栈,并推迟其启动操作,直到所有较低的驱动程序完成 IRP。 父总线驱动程序(设备堆栈中的底部驱动程序)必须是第一个在设备上执行启动操作的驱动程序,然后其他驱动程序才能访问该设备。
为了确保启动操作的正确排序,Windows 2000 以上的PnP 管理器会推迟公开设备接口,并阻止为设备创建请求,直到启动IRP成功。
如果设备的驱动程序未通过 IRP_MN_START_DEVICE 请求,PnP 管理器会将 IRP_MN_REMOVE_DEVICE 请求发送到Windows 2000 以上的设备堆栈 。 为了响应此 IRP,如果设备驱动程序未能成功启动 IRP、撤消 AddDevice 操作并从设备堆栈分离,则 撤消其启动操作,PnP 管理器将此类设备标记为“启动失败”。
下面是总线驱动的设计原则:
- 在 IRP_MN_START_DEVICE IRP 完成之前,PnP 管理器无法为设备创建请求,指示设备的所有驱动程序都已执行其启动操作。
- 由于 DispatchPnP 例程在 IRQL PASSIVE_LEVEL 的系统线程上下文中运行,因此,只要驱动程序不控制保存系统页文件的设备,使用 ExAllocatePoolWithTag 分配的任何内存在初始化期间专用于分页池即可。 在 DispatchPnP 例程返回控件之前,必须使用 ExFreePool 释放此类内存分配。
- WDM 设备驱动程序的 ISR 应该能够确定是否在设备启动期间使用虚假中断调用它。 从处理IRP_MN_START_DEVICE的代码路径中调用 IoConnectInterrupt 返回时,如果设备上启用了中断,可以立即调用 ISR。
PNP设备停止
下图显示了停止和重启设备以重新平衡资源所涉及的 IRP 序列:
以下注释对应于上图中带圆圈的数字:
1. PnP 管理器发出 IRP_MN_QUERY_STOP_DEVICE ,询问设备的驱动程序是否可以停止设备并释放其硬件资源。
如果设备堆栈中的所有驱动程序都返回STATUS_SUCCESS,则驱动程序会将设备置于停止挂起状态 (停止挂起) ,可从中快速停止设备。
如果设备堆栈返回除STATUS_SUCCESS以外的任何内容,它将不参与重新平衡过程。 由于资源重新平衡是一项尽力而为的操作,在这种情况下,系统仍会尝试重新平衡操作以满足系统中设备的资源要求。 但是,如果设备失败查询停止,可能无法获得所需的结果,例如,如果枚举新设备并触发重新平衡,则它可能无法接收其所需的资源,因此最终无法启动) 。
查询停止操作失败的设备将继续处于运行状态,即使查询停止失败。
PnP 管理器根据需要查询尽可能多的设备堆栈,以重新平衡所需的资源。
2. PnP 管理器发出 IRP_MN_STOP_DEVICE 来停止设备。
在 Windows 2000 及更高版本的 Windows 上,仅当设备的上一个查询停止IRP成功完成时,PnP 管理器才会发送停止 IRP。 为了响应停止 IRP,驱动程序释放设备的硬件资源 ,例如其 I/O 端口) 并保留需要访问设备的任何 IRP。
3. 成功重新平衡资源后,PnP 管理器 会发出IRP_MN_START_DEVICE 请求,以重启在重新平衡期间停止的任何设备。
4. 否则,PnP 管理器通过发送 IRP_MN_CANCEL_STOP_DEVICE来取消查询停止 IRP。
为了响应 IRP_MN_CANCEL_STOP_DEVICE,设备的驱动程序将设备返回到启动状态并恢复处理设备的 I/O 请求。
如果堆栈中的一个驱动程序使请求失败,或者整体重新平衡操作失败,并且正在取消其所有查询停止请求,则PnP 管理器将取消设备堆栈的查询停止。 当PnP 管理器仅取消一个设备堆栈上的查询停止时,它会发送 IRP_MN_CANCEL_STOP_DEVICE 请求,因为查询失败的驱动程序上方附加的任何驱动程序都使设备处于停止挂起状态。 当IRP_MN_CANCEL_STOP_DEVICE成功时,驱动程序已将设备返回到启动状态。
5. 如果驱动程序在重新平衡资源后无法重启设备,PnP 管理器会将删除IRP发送到 Windows 2000 及更高版本的 Windows上的设备堆栈 。
PnP 管理器首先发送 IRP_MN_SURPRISE_REMOVAL 请求。 然后,它发送 IRP_MN_REMOVE_DEVICE 请求,但仅在关闭设备的所有打开句柄之后。
重新平衡PnP 设备的硬件资源必须对应用程序和最终用户透明, 用户可能会遇到暂时的操作延迟,但数据不得丢失。 处理停止IRP时,必须考虑到这一点。
PNP设备删除
下图显示了删除设备驱动程序时涉及的典型 IRP 序列:
以下注释对应于上图中带圆圈的数字:
1. 查询删除:PnP 管理器发出 IRP_MN_QUERY_REMOVE_DEVICE ,询问是否可以在不中断计算机的情况下删除设备。 当用户请求更新设备的驱动程序,并在 Windows 2000 及更高版本上 () 设备管理器禁用设备时,它还会发送此 IRP。
如果设备堆栈中的所有驱动程序都返回STATUS_SUCCESS,则驱动程序会将设备置于待删除状态。 在此状态下,驱动程序不得启动阻止删除设备的任何操作。
在此“干净”删除案例中,PnP 管理器会在发送删除IRP之前发送查询删除 IRP。
尽管上图中未显示,但总线驱动程序可能会收到未启动设备的 IRP_MN_QUERY_REMOVE_DEVICE 。 如果用户请求动态删除计算机上实际存在但已禁用的设备,则可能会发生这种情况。
2. 查询成功后删除:PnP 管理器发出 IRP_MN_REMOVE_DEVICE 来删除设备的驱动程序。
驱动程序必须成功执行此请求。 设备的驱动程序执行任何必要的清理,从设备堆栈中分离,并删除 FDO 和任何筛选器DO。 父总线驱动程序会保留 PDO,直到用户以物理方式从计算机中删除设备。
请注意,驱动程序可能会在删除IRP之前收到 IRP_MN_STOP_DEVICE ,但这不是必需的。 在 Windows 2000 及更高版本中, IRP_MN_STOP_DEVICE 仅用于暂停设备以重新平衡资源;这不是删除的一步。 如果用户在设备停止时移除了设备硬件,则PnP 管理器会在停止IRP之后的某个时间点发送删除 IRP,但停止不是删除的先决条件。
3. 恢复设备:如果在驱动程序删除其设备对象后恢复设备,PnP 管理器会调用驱动程序的 AddDevice 例程并发出 IRP_MN_START_DEVICE 以恢复设备。
4. 取消查询删除:PnP 管理器发出 IRP_MN_CANCEL_REMOVE_DEVICE 来取消查询删除请求。
为了响应 IRP_MN_CANCEL_REMOVE_DEVICE,驱动程序将设备返回到其启动状态。
5. 意外删除:在 Windows 2000 及更高系统上,如果用户在不使用拔出或弹出硬件程序的情况下从计算机拔出设备,PnP 管理器会发送 IRP_MN_SURPRISE_REMOVAL IRP。
这种情况称为“意外”删除,因为驱动程序不会收到任何提前警告。
为了响应 IRP_MN_SURPRISE_REMOVAL IRP,设备的驱动程序会使任何未完成的 I/O 失败,并释放设备使用的硬件资源。 驱动程序必须确保没有组件尝试访问设备,因为它不再存在。
所有驱动程序都必须处理 IRP_MN_SURPRISE_REMOVAL IRP,并且必须将状态设置为STATUS_SUCCESS。
无法取消IRP_MN_SURPRISE_REMOVAL。
6. 意外删除后删除:关闭设备的所有打开句柄后,PnP 管理器会向设备的驱动程序发送 IRP_MN_REMOVE_DEVICE 请求。 每个驱动程序从设备堆栈中分离并删除其设备对象。
7. windows 2000 及更高版本启动失败后删除:如果设备的某个驱动程序 在IRP_MN_START_DEVICE失败,PnP 管理器会向设备堆栈发送 IRP_MN_REMOVE_DEVICE 请求。 这种删除IRP可确保设备的所有驱动程序都会收到设备未成功启动的通知。 为了响应 IRP_MN_REMOVE_DEVICE IRP,如果设备的驱动程序成功启动 IRP) 并撤消其 AddDevice 操作,则 撤消其启动操作。PnP 管理器将此类设备标记为“启动失败”。
与图中演示典型删除IRP转换的情况相比,PnP 设备的驱动程序可以接收 IRP_MN_SURPRISE_REMOVAL 。 例如,用户可以将电脑卡插入计算机,然后在启动设备之前将其移除。 在这种情况下,在调用驱动程序的 AddDevice 例程之后,但在发出 IRP_MN_START_DEVICE 请求之前,PnP 管理器会发出意外删除 IRP。 调用驱动程序的 AddDevice 例程后,必须准备好PnP 设备的驱动程序,以便随时处理删除 IRP。