用户拔出设备

在系统运行时,用户可以通过以下两种方式之一删除设备:有序 删除,这意味着用户通知系统设备即将删除(例如,使用“拔出”或“弹出硬件”程序):或 意外删除,这意味着用户拔下设备而不通知系统。 如果总线支持意外删除(例如 USB),设备的驱动程序必须能够处理设备的突然消失。

有序删除

用户可通过系统的“拔出或弹出硬件”程序、通过设备管理器禁用设备,或按下 可弹出设备的弹出 按钮,来请求移除设备。 框架允许删除或禁用设备,除非驱动程序具有以下功能:

对于支持设备的每个函数和筛选器驱动程序,框架一次按顺序执行以下作,从驱动程序堆栈中最高的驱动程序开始:

  1. 如果驱动程序使用的是自托管 I/O,框架将调用驱动程序的 EvtDeviceSelfManagedIoSuspend 回调函数。

  2. 框架会停止驱动程序的所有电源管理的 I/O 队列。

  3. 如果硬件和驱动程序支持 DMA,则框架将调用驱动程序的 EvtDmaEnablerSelfManagedIoStopEvtDmaEnablerFlushEvtDmaEnablerDisable 回调函数(如果存在),用于创建的每个 DMA 通道。

  4. 框架调用驱动程序的 EvtDeviceD0ExitPreInterruptsDisabled 回调函数(如果存在),然后针对每个中断调用驱动程序的 EvtInterruptDisable 回调函数(如果存在),以便驱动程序可以禁用设备中断。

  5. 框架调用驱动程序的 EvtDeviceD0Exit 回调函数(如果存在)。

  6. 框架调用驱动程序的 EvtDeviceReleaseHardware 回调函数(如果存在),并向其传递 PnP 管理器分配给设备的硬件资源列表。

  7. 如果驱动程序使用的是自管理 I/O,框架将调用驱动程序的 EvtDeviceSelfManagedIoFlush 回调函数。

  8. 如果驱动程序使用的是自管理 I/O,框架将调用驱动程序的 EvtDeviceSelfManagedIoCleanup 回调函数。

总线驱动程序是堆栈中最后调用的驱动程序。 当框架调用总线驱动程序的 EvtDeviceD0Exit 回调函数时,回调函数会将设备(总线的子设备)的电源状态设置为 D3。 总线驱动程序可以通过调用 WdfDeviceInitSetReleaseHardwareOrderOnFailure 来控制框架何时调用其 EvtDeviceReleaseHardware 回调函数。

意外删除

用户意外地拔出设备。 设备总线的驱动程序发现设备缺失,并调用 WdfChildListUpdateChildDescriptionAsMissing

对于支持设备的每个函数和筛选器驱动程序,框架一次按顺序执行以下作,从驱动程序堆栈中最高的驱动程序开始:

  1. 框架调用驱动程序的 EvtDeviceSurpriseRemoval 回调函数(如果存在)。
  2. 如果设备在拔出时处于工作状态(D0),则:
    1. 框架会停止驱动程序的所有电源管理的 I/O 队列。
    2. 如果驱动程序使用的是自托管 I/O,框架将调用驱动程序的 EvtDeviceSelfManagedIoSuspend 回调函数。
    3. 如果硬件和驱动程序支持 DMA,则框架将调用驱动程序的 EvtDmaEnablerSelfManagedIoStopEvtDmaEnablerFlushEvtDmaEnablerDisable 回调函数(如果存在),用于创建的每个 DMA 通道。
    4. 框架调用驱动程序的 EvtDeviceD0ExitPreInterruptsDisabledEvtInterruptDisable 回调函数(如果存在),以便驱动程序可以禁用设备中断。
    5. 框架调用驱动程序的 EvtDeviceD0Exit 回调函数(如果存在)。
  3. 框架调用驱动程序的 EvtDeviceReleaseHardware 回调函数(如果存在),并传递 PnP 管理器分配给设备的硬件资源列表。
  4. 如果驱动程序使用的是自管理 I/O,框架将调用驱动程序的 EvtDeviceSelfManagedIoFlush 回调函数。
  5. 如果驱动程序使用的是自管理 I/O,框架将调用驱动程序的 EvtDeviceSelfManagedIoCleanup 回调函数。

请注意,可以随时意外删除设备。 因此,框架可能会在与前面步骤中显示的时间不同的时间调用驱动程序的 EvtDeviceSurpriseRemoval 回调函数。 例如,如果用户在进入低功率状态时意外拔出设备,则框架可能会在调用 EvtDeviceReleaseHardware 回调函数后调用 EvtDeviceSurpriseRemoval 回调函数。 不得以假定它和其他回调函数在特定序列中调用的方式编写 EvtDeviceSurpriseRemoval 回调函数的代码。

此外,框架不会将设备的 EvtDeviceSurpriseRemoval 回调函数与该设备前面步骤中列出的任何回调函数同步。 因此, EvtDeviceSurpriseRemoval 回调函数可能会运行,而之前列出的另一个回调函数也在运行。