在函数驱动程序中删除设备
删除设备时,函数驱动程序必须撤消为添加和启动设备而执行的任何操作。 此讨论包括外围设备的功能驱动程序和总线设备的功能驱动程序。
函数驱动程序在其 DispatchPnP 例程中使用如下过程删除设备:
这是总线设备的函数驱动程序吗?
如果是这样,可能会删除总线上设备的任何未完成子 PDO。
如果总线驱动程序处理了针对子设备的上一个 IRP_MN_SURPRISE_REMOVAL 请求,但驱动程序尚未收到后续 IRP_MN_REMOVE_DEVICE 请求,则总线驱动程序将使子 PDO 保持不变。 稍后,当关闭子设备的所有句柄时,PnP 管理器将发送子设备的删除 IRP,而总线驱动程序此时会删除子 PDO。
如果总线驱动程序处理了设备的上一 个IRP_MN_REMOVE_DEVICE 请求,并且没有后续 IRP_MN_SURPRISE_REMOVAL 请求,则总线驱动程序会删除子 PDO。 在这种情况下,PnP 管理器确保在将删除 IRP 发送到父总线设备之前,已从子设备中删除任何函数和筛选器驱动程序, (FDO 和筛选器DO 已被删除) 。 子 PDO 可能仍然存在,因此总线驱动程序必须先删除子 PDO,然后才能删除总线设备。
驱动程序是否已处理此 FDO 的先前 IRP_MN_SURPRISE_REMOVAL 请求?
如果是这样,请执行任何剩余的清理,并跳到步骤 8 IoCallDriver。
驱动程序通常在设备扩展中维护一个标志,指示驱动程序是否已处理设备的 IRP_MN_SURPRISE_REMOVAL 请求。
如果驱动程序以前为设备启用了唤醒,请取消 IRP_MN_WAIT_WAKE 请求。
确保设备处于非活动状态。
如果设备尚未处于非活动状态以响应之前的 IRP_MN_QUERY_REMOVE_DEVICE,驱动程序必须将设备标记为不接受新请求,并且必须完成此驱动程序中排队的任何请求。 驱动程序必须使需要访问设备的任何未完成请求失败。
驱动程序可以使用 IoXxxRemoveLockXxx 例程对未完成的 I/O 进行计数,并设置指示删除处理可以继续的事件。
执行任何关机操作。
设备的每个驱动程序在收到 IRP_MN_REMOVE_DEVICE 请求时执行其关机操作(如果有)。 设备的电源策略所有者(通常是函数驱动程序)不会发送单独的 IRP_MN_SET_POWER 请求,将设备电源状态设置为 D3。 父总线驱动程序通常会关闭槽,并在总线驱动程序获取删除 IRP 时使用 PoSetPowerState 通知电源管理器。 有关其他信息,请参阅 电源管理。
通过调用 IoSetDeviceInterfaceState 禁用任何设备接口。
释放驱动程序正在使用的设备的任何硬件资源。
具体操作取决于设备和驱动程序,但可能包括断开 IoDisconnectInterrupt 中断的连接、使用 MmUnmapIoSpace 释放物理地址范围以及释放 I/O 端口。
将 IRP_MN_REMOVE_DEVICE 请求向下传递到下一个驱动程序。
使用 IoSkipCurrentIrpStackLocation 为下一个较低驱动程序设置 IRP 堆栈位置,并使用 IoCallDriver 将 IRP 传递给下一个驱动程序。
驱动程序无需等待基础驱动程序完成其删除操作,然后再继续其删除活动。
使用 IoDetachDevice 从设备堆栈中删除设备对象。
将指向下一个较低设备对象的指针指定为 TargetDevice 参数。 驱动程序从调用 IoAttachDeviceToDeviceStack 在驱动程序的 AddDevice 例程中接收此类指针。
清理任何特定于设备的分配、内存、事件等。
使用 IoDeleteDevice 释放 FDO。
从 DispatchPnP 例程返回,从 IoCallDriver 传播返回状态。
函数驱动程序不会为删除 IRP 指定 IoCompletion 例程,也不会完成 IRP。 删除 IRP 由父总线驱动程序完成。