WDF
+ -

自拖管IO

2026-06-17 3 0

自拖管IO主要是一些电源的回调

typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS {
    //
    // Size of this structure in bytes
    //
    ULONG Size;

    PFN_WDF_DEVICE_D0_ENTRY                 EvtDeviceD0Entry;
    PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED EvtDeviceD0EntryPostInterruptsEnabled;
    PFN_WDF_DEVICE_D0_EXIT                  EvtDeviceD0Exit;
    PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED EvtDeviceD0ExitPreInterruptsDisabled;
    PFN_WDF_DEVICE_PREPARE_HARDWARE         EvtDevicePrepareHardware;
    PFN_WDF_DEVICE_RELEASE_HARDWARE         EvtDeviceReleaseHardware;

    //自拖管IO的回调
    PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP  EvtDeviceSelfManagedIoCleanup;
    PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH    EvtDeviceSelfManagedIoFlush;
    PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT     EvtDeviceSelfManagedIoInit;
    PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND  EvtDeviceSelfManagedIoSuspend;

    PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART  EvtDeviceSelfManagedIoRestart;
    PFN_WDF_DEVICE_SURPRISE_REMOVAL         EvtDeviceSurpriseRemoval;
    PFN_WDF_DEVICE_QUERY_REMOVE             EvtDeviceQueryRemove;
    PFN_WDF_DEVICE_QUERY_STOP               EvtDeviceQueryStop;
    PFN_WDF_DEVICE_USAGE_NOTIFICATION       EvtDeviceUsageNotification;
    PFN_WDF_DEVICE_RELATIONS_QUERY          EvtDeviceRelationsQuery;
    PFN_WDF_DEVICE_USAGE_NOTIFICATION_EX    EvtDeviceUsageNotificationEx;
} WDF_PNPPOWER_EVENT_CALLBACKS, *PWDF_PNPPOWER_EVENT_CALLBACKS;

自拖管IO是对电源状态管理变化时相对应的调用,这组回调函数正是 WDF 框架为了让你能优雅地管理“自托管 I/O”与电源状态之间的同步而专门设计的。它们精确地映射到了设备电源状态(D状态)变化的关键节点上。

可以把它们理解为 “自托管 I/O 的电源状态机”。框架会在设备电源状态转换时,自动调用对应的回调,让你有机会暂停、重启或清理这些后台活动。

调用时机

设备插入 / 系统启动
    ↓
[ 第一阶段:设备启动 ]
    ↓
EvtDevicePrepareHardware  (分配硬件资源)
    ↓
EvtDeviceD0Entry         (设备进入 D0 工作状态)
    ↓
EvtDeviceSelfManagedIoInit  ★ 启动你的后台活动 (定时器/线程)
    ↓
设备正常运行 (自托管 I/O 活动进行中)
    ↓
[ 第二阶段:设备进入睡眠 (S3) ]
    ↓
EvtDeviceSelfManagedIoSuspend  ★ 暂停你的后台活动
    ↓
EvtDeviceD0Exit          (设备离开 D0,进入低功耗状态)
    ↓
[ 系统进入睡眠... ]
    ↓
[ 第三阶段:设备从睡眠唤醒 ]
    ↓
EvtDeviceD0Entry         (设备回到 D0 工作状态)
    ↓
EvtDeviceSelfManagedIoRestart  ★ 重启你的后台活动
    ↓
设备正常运行
    ↓
[ 第四阶段:设备被移除 (物理拔出 / 禁用) ]
    ↓
EvtDeviceSelfManagedIoSuspend  ★ 暂停活动 (为移除做准备)
    ↓
EvtDeviceSelfManagedIoFlush     ★ 清空所有待处理的操作
    ↓
EvtDeviceD0Exit          (设备进入 D0 冷移除或低功耗状态)
    ↓
EvtDeviceReleaseHardware (释放硬件资源)
    ↓
EvtDeviceSelfManagedIoCleanup   ★ 释放所有自托管 I/O 资源 (最后的清理)
回调函数 调用时机 (电源状态变化) 对应的 PnP/电源事件 你通常在这里做什么?
EvtDeviceSelfManagedIoInit 设备首次从 D0(工作状态)启动时。 (只调用一次) EvtDeviceD0Entry 之后调用。 启动所有后台活动。例如:创建并启动定时器、启动后台线程、初始化自托管的 I/O 队列。
EvtDeviceSelfManagedIoSuspend 设备将要离开 D0 状态,进入低功耗状态(D1/D2/D3)之前。 EvtDeviceD0Exit 之前调用。 暂停所有后台活动。例如:停止定时器、挂起后台线程、等待正在进行的 I/O 完成。目的是让设备能安全地进入低功耗状态。
EvtDeviceSelfManagedIoRestart 设备低功耗状态(D1/D2/D3)回到 D0 状态之后。 EvtDeviceD0Entry 之后调用。 重启被暂停的后台活动。例如:重新启动定时器、恢复后台线程。它恢复的是 Suspend 时暂停的工作。
EvtDeviceSelfManagedIoFlush 设备即将被移除被重新配置(如 PnP 重新平衡资源)时。 EvtDeviceSelfManagedIoSuspend 之后,设备移除前调用。 清空所有待处理的自托管 I/O。例如:取消所有未完成的内部请求、清空队列。确保设备移除时没有“悬空”的 I/O 操作。
EvtDeviceSelfManagedIoCleanup 设备对象正在被删除时。这是自托管 I/O 生命周期的最后一步 在设备移除流程的最末尾调用。 释放所有自托管 I/O 使用的资源。例如:删除定时器对象、等待线程结束。这是最后的“打扫卫生”工作。

虚拟驱动或者过滤驱动的使用示例

    WDF_PNPPOWER_EVENT_CALLBACKS    wdfPnpPowerCallbacks;
    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&wdfPnpPowerCallbacks);
    wdfPnpPowerCallbacks.EvtDeviceSelfManagedIoInit = HIDINJECTOR_EvtDeviceSelfManagedIoInit;
    wdfPnpPowerCallbacks.EvtDeviceSelfManagedIoCleanup = HIDINJECTOR_EvtDeviceSelfManagedIoCleanup;
    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &wdfPnpPowerCallbacks);

对应函籹

NTSTATUS
HIDINJECTOR_EvtDeviceSelfManagedIoInit(
    WDFDEVICE WdfDevice
    )
{
    PHID_DEVICE_CONTEXT    deviceContext;
    NTSTATUS        status;
    PAGED_CODE();
    deviceContext = GetHidDeviceContext(WdfDevice);
    status = VhfStart(deviceContext->VhfHandle);
    if (!NT_SUCCESS(status)) 
    {
        // TODO; seach all KDPrint Calls to make sure parameters match format specifiers
        KdPrint(("VhfStart failed %d\n", status));
    }
    return status;
}

VOID
HIDINJECTOR_EvtDeviceSelfManagedIoCleanup(
    WDFDEVICE WdfDevice
    )
{
    PHID_DEVICE_CONTEXT    deviceContext;
    PAGED_CODE();

    deviceContext = GetHidDeviceContext(WdfDevice);
    VhfDelete(deviceContext->VhfHandle, TRUE);
    return;
}

0 篇笔记 写笔记

作者信息
我爱内核
Windows驱动开发,网站开发
好好学习,天天向上。
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!