WDF驱动开发-中断处理(三)

使用中断唤醒设备

当设备转换为低功耗状态时,框架会断开连接 (或报告为非活动) 用于 I/O 处理的中断。 从在 Windows 8.1 上运行的 KMDF 1.13 和 UMDF 2.0 开始,WDF 驱动程序可以创建一个框架中断对象,该对象在设备转换为低功耗状态时保持活动状态,然后可用于唤醒设备并将其还原到完全处于 D0 状态。

如果要为芯片上的系统开发 WDF 驱动程序 (SoC) 平台,则可以使用此类中断唤醒不提供传统唤醒信号机制的设备。 若要使用此功能,设备必须具有通过 ACPI 公开的唤醒中断的硬件支持。 创建中断的驱动程序必须是设备的电源策略所有者。

当设备转换为低功耗状态时,框架不会断开已标识为支持唤醒的中断。 当设备中断时,框架在 IRQL = PASSIVE_LEVEL调用驱动程序的 EvtDeviceD0Entry 和 EvtInterruptIsr 回调例程。

如果驱动程序已创建被动 级中断对象 用于 I/O 处理,我们建议共享同一个中断对象以用于唤醒功能。 在此方案中,驱动程序的 EvtInterruptIsr 回调例程实现条件逻辑以执行 I/O 相关中断的处理以及唤醒处理。

但是,如果驱动程序使用的中断需要在设备的 IRQL (DIRQL) 进行处理,我们建议创建额外的框架中断对象以提供唤醒功能。

按照以下步骤在 KMDF 或 UMDF 驱动程序中创建支持唤醒的中断对象:

1. 调用 WdfDeviceAssignS0IdleSettings,通常来自 EvtDriverDeviceAdd,并在 IdleCaps 参数中指定 IdleCanWakeFromS0;

2. (可选)调用 WdfDeviceInitSetPowerPolicyEventCallbacks 以注册 支持系统唤醒中所述的事件回调函数;

3. 调用 WDF_INTERRUPT_CONFIG_INIT 以初始化 WDF_INTERRUPT_CONFIG 结构。 提供在被动级别调用的 EvtInterruptIsr 回调函数。 在配置结构中,将 PassiveHandling 和 CanWakeDevice 设置为 TRUE。 然后从驱动程序的 EvtDevicePrepareHardware 回调函数调用 WdfInterruptCreate 以创建框架中断对象;

4. 调用 WdfDeviceAssignSxWakeSettings 将设备配置为将系统从低功耗状态唤醒;

WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings);
wakeSettings.DxState = PowerDeviceD3;
wakeSettings.UserControlOfWakeSettings = WakeDoNotAllowUserControl;
wakeSettings.Enabled = WdfTrue;status = WdfDeviceAssignSxWakeSettings(Device, &wakeSettings);
if (!NT_SUCCESS(status)) {Trace(TRACE_LEVEL_ERROR,"WdfDeviceAssignSxWakeSettings failed %x\n", status);return status;
}

5. 当设备转换为低功耗状态时,框架不会为支持唤醒的中断调用 EvtInterruptDisable 。 如果驱动程序提供了 EvtDeviceArmWakeFromS0 ,框架会调用该框架;

6. 当设备发出唤醒中断信号时,框架会调用驱动程序的 EvtDeviceD0Entry 回调例程;

7. 如果驱动程序的 EvtDeviceD0Entry 回调返回成功,框架将在被动级别调用驱动程序的 EvtInterruptIsr 回调。 在中断处理程序返回之前,它必须在中断控制器中静音中断。 如果驱动程序从 EvtDeviceD0Entry 返回失败代码,框架将断开中断,并调用驱动程序的 EvtInterruptDisable 回调,如果驱动程序已提供;

8. 如果驱动程序提供了以下唤醒事件回调例程,则框架会调用以下唤醒事件回调例程:

EvtDeviceDisarmWakeFromS0
EvtDeviceDisarmWakeFromSx
EvtDeviceWakeFromS0Triggered
EvtDeviceWakeFromSxTriggered
9. 框架继续执行正常的通电回调序列;

可以在windbg中使用 !wdfkd.wdfinterrupt 调试器扩展来显示特定中断是否已配置为支持唤醒。

注意: 唤醒中断功能不能与 USB 选择性挂起结合使用。

处理同时处于活动状态的中断

注意仅适用于 Kernel-Mode Driver Framework (KMDF) 版本 1.13 及更早版本。

许多设备都有控制中断生成和屏蔽的硬件寄存器。 通常,此类设备的 KMDF 和 UMDF 驱动程序使用框架的内置中断支持。

但是,芯片上的系统上的简单设备 (SoC) 硬件平台可能没有用于中断的硬件寄存器。 因此,此类设备的驱动程序可能无法控制何时生成中断,也无法在硬件中屏蔽中断。 如果设备在连接后立即中断,并且驱动程序正在使用框架的中断支持,则有可能在框架完全初始化框架中断对象之前触发中断。 因此,KMDF 驱动程序必须直接调用 WDM 例程才能连接和断开中断。 由于 UMDF 驱动程序无法调用这些方法,因此不能为此类设备编写 UMDF 驱动程序。

在 SoC 硬件平台上,主动两个中断通常用于非常简单的设备,如硬件按钮。 当用户按下一键时,设备的中断信号线将从低到高或从高转换为低。 当用户松开一键时,中断线会向相反的方向转换。 配置为双活动中断输入的 GPIO 引脚在从低到高和高到低转换时生成中断,导致系统在这两种情况下调用外围设备驱动程序的中断服务例程 ISR。 但是,驱动程序不会收到转换是低到高还是高到低转换的指示。

若要区分从低到高以及从高到低的转换,驱动程序必须跟踪每个中断的状态。 为此,驱动程序可能会维护布尔中断状态值,当中断行状态较低时为 FALSE ,当行状态较高时为 TRUE 。

假设系统启动时行状态默认为低。 驱动程序在其 EvtDevicePrepareHardware 回调函数中将状态值初始化为 FALSE。 然后,每次调用驱动程序的 ISR指示状态发生更改时,驱动程序都会反转其 ISR 中的状态值。

如果系统启动时线路状态较高,则启用中断后会立即触发。 由于驱动程序直接调用 IoConnectInterruptEx 例程,而不是调用 WdfInterruptCreate,因此可确保它收到可能的即时中断。

此解决方案要求 GPIO 控制器支持硬件中的双主动中断,或者 GPIO 控制器的驱动程序在软件中模拟双主动中断。  

下面的代码示例演示外围设备的 KMDF 驱动程序如何跟踪中断极性。

typedef struct _INTERRUPT_CONTEXT INTERRUPT_CONTEXT, *PINTERRUPT_CONTEXT;
typedef struct _DEVICE_CONTEXT DEVICE_CONTEXT, *PDEVICE_CONTEXT;struct _INTERRUPT_CONTEXT
{BOOLEAN State;PDEVICE_CONTEXT DeviceContext;
};struct _DEVICE_CONTEXT
{PKINTERRUPT Interrupt;INTERRUPT_CONTEXT InterruptContext;PDEVICE_OBJECT PhysicalDeviceObject;KSPIN_LOCK SpinLock;
};...BOOLEAN
YourInterruptIsr(__in PKINTERRUPT Interrupt,__in PVOID ServiceContext)
{PINTERRUPT_CONTEXT InterruptContext = (PINTERRUPT_CONTEXT)ServiceContext;PDEVICE_CONTEXT DeviceContext = InterruptContext->DeviceContext;//// Flip the state.//InterruptContext->State = !InterruptContext->State;IoRequestDpc(DeviceContext->PhysicalDeviceObject, DeviceContext->PhysicalDeviceObject->CurrentIrp, InterruptContext);
}VOID
YourInterruptDpc(__in PKDPC Dpc,__in PDEVICE_OBJECT DeviceObject,__inout PIRP Irp,__in_opt PVOID ContextPointer)
{PINTERRUPT_CONTEXT InterruptContext = (PINTERRUPT_CONTEXT)ContextPointer;...
}NTSTATUS
EvtDriverDeviceAdd(__in  WDFDRIVER Driver,__in  PWDFDEVICE_INIT DeviceInit)
{WDFDEVICE Device;PDEVICE_CONTEXT DeviceContext;...DeviceContext->Interrupt = NULL;DeviceContext->PhysicalDeviceObject = WdfDeviceWdmGetPhysicalDevice(Device);KeInitializeSpinLock(&DeviceContext->SpinLock);IoInitializeDpcRequest(DeviceContext->PhysicalDeviceObject, YourInterruptDpc);
}NTSTATUS
EvtDevicePrepareHardware(__in  WDFDEVICE Device,__in  WDFCMRESLIST ResourcesRaw,__in  WDFCMRESLIST ResourcesTranslated)
{PDEVICE_CONTEXT DeviceContext = YourGetDeviceContext(Device);for (ULONG i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++){PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i);if (descriptor->Type == CmResourceTypeInterrupt){IO_CONNECT_INTERRUPT_PARAMETERS params;RtlZeroMemory(&params, sizeof(params));params.Version = CONNECT_FULLY_SPECIFIED;params.FullySpecified.PhysicalDeviceObject = DeviceContext->PhysicalDeviceObject;params.FullySpecified.InterruptObject = &DeviceContext->Interrupt;params.FullySpecified.ServiceRoutine = YourInterruptIsr;params.FullySpecified.ServiceContext = (PVOID)&DeviceContext->InterruptContext;params.FullySpecified.SpinLock = &DeviceContext->SpinLock;params.FullySpecified.Vector = descriptor->u.Interrupt.Vector;params.FullySpecified.Irql = (KIRQL)descriptor->u.Interrupt.Level;params.FullySpecified.SynchronizeIrql = (KIRQL)descriptor->u.Interrupt.Level;params.FullySpecified.InterruptMode = (descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;params.FullySpecified.ProcessorEnableMask = descriptor->u.Interrupt.Affinity;params.FullySpecified.ShareVector = descriptor->ShareDisposition;//// Default state is low.//DeviceContext->InterruptContext.State = 0;DeviceContext->InterruptContext.DeviceContext = DeviceContext;return IoConnectInterruptEx(&params);}}return STATUS_SUCCESS;
}NTSTATUS
EvtDeviceReleaseHardware(__in  WDFDEVICE Device,__in  WDFCMRESLIST ResourcesTranslated
)
{PDEVICE_CONTEXT DeviceContext = YourGetDeviceContext(Device);if (NULL != DeviceContext->Interrupt){IO_DISCONNECT_INTERRUPT_PARAMETERS params;params.Version = CONNECT_FULLY_SPECIFIED;params.ConnectionContext.InterruptObject = DeviceContext->Interrupt;IoDisconnectInterruptEx(&params);}return STATUS_SUCCESS;
}

 

在前面的代码示例中,驱动程序的 EvtDriverDeviceAdd 回调函数配置设备上下文,然后调用 IoInitializeDpcRequest 来注册 DpcForIsr 例程。

驱动程序的 InterruptService 例程反转中断状态值,然后调用 IoRequestDpc 将 DPC 排队。

在其 EvtDevicePrepareHardware 回调函数中,驱动程序将状态值初始化为 FALSE ,然后调用 IoConnectInterruptEx。 在其 EvtDeviceReleaseHardware 回调函数中,驱动程序调用 IoDisconnectInterruptEx 以取消注册其 ISR。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/856651.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【QT】实现无边框窗口+可拖动+可调整大小

QT无边框 // 在widget构造中添加如下即可实现无边框 setWindowFlags(Qt::FramelessWindowHint); //设置无边框可拖动 当实现无边框之后&#xff0c;你会发现无法拖动了。 或许我们需要了解下窗口是怎么被拖动的 通过标题栏拖动窗口move窗口位置 因此有两种方案可以解决无法…

Redis—String数据类型及其常用命令详解

文章目录 Redis概述1.Redis-String数据类型概述2.常用命令2.1 SET&#xff1a;添加或者修改已经存在的一个String类型的键值对2.2 GET&#xff1a;根据key获取String类型的value2.3 MSET&#xff1a;批量添加多个String类型的键值对2.4 MGET&#xff1a;根据多个key获取多个Str…

CDN缓存命中率较低可能的原因

背景&#xff1a; 网站使用CDN加速以后&#xff0c;大部分静态文件都将会被离用户较近的CDN边缘节点缓存&#xff0c;由此起到访问加速效果。如果用户访问的文件由CDN节点直接响应&#xff0c;无需回源&#xff0c;则称之为缓存命中。CDN缓存命中率越高&#xff0c;也就意味着…

腾讯云开端口

轻量服务器 由于开发者计划&#xff0c;这些腾讯云 阿里云什么的小vps&#xff0c;是非常之便宜&#xff0c;甚至到了白送的地步&#xff08;小阿&#xff09;&#xff0c;但是作为一个web安全学习者必要的vps操作还是要会的 开启端口 腾讯云的轻量服务器是没有安全组的&…

【服务器02】之阿里云平台

百度一下阿里云官网 点击注册直接使用支付宝注册可以跳过认证 成功登录后&#xff0c;点击产品 点击免费试用 点击勾选 选一个距离最近的 点满GB 注意&#xff1a;一般试用的时用的是【阿里云】&#xff0c;真正做项目时用的是【腾讯云】 现在开始学习使用&#xff1a; 首先…

排序方法——《归并排序》

P. S.&#xff1a;以下代码均在VS2019环境下测试&#xff0c;不代表所有编译器均可通过。 P. S.&#xff1a;测试代码均未展示头文件stdio.h的声明&#xff0c;使用时请自行添加。 博主主页&#xff1a;Yan. yan.                        …

如何使用LangChain自定义agent的制作(1) - 自定义一个可以执行 SQL 查询的 Agent

文章目录 前言一、准备工作梳理一、 安装依赖包二、 设置数据库连接三、 自定义 Agent四、 运行示例五、 完整代码六、使用agent的好处1. **模块化和可重用性**2. **扩展性**3. **简化复杂性**4. **增强可维护性**5. **集成大语言模型的能力**6. **易于扩展到其他任务** 继续思…

Web前端期末项目报告:探索、实践与反思

Web前端期末项目报告&#xff1a;探索、实践与反思 随着Web技术的不断发展&#xff0c;前端开发在软件开发中扮演着越来越重要的角色。本次期末项目&#xff0c;我们致力于构建一个功能完善、用户体验优良的Web应用&#xff0c;以实践所学知识&#xff0c;提升技能水平。接下来…

算法体系-23 第二十三节:暴力递归到动态规划(五)

一 求K次打击之后&#xff0c;英雄把怪兽砍死的概率 1.1 描述 给定3个参数&#xff0c;N&#xff0c;M&#xff0c;K 怪兽有N滴血&#xff0c;等着英雄来砍自己 英雄每一次打击&#xff0c;都会让怪兽流失[0~M]的血量 到底流失多少&#xff1f;每一次在[0~M]上等概率的获得一个…

搭建预约咨询小程序,高效便捷新选择

一、预约咨询小程序是什么&#xff1f; 预约咨询小程序是一款适用于各种生活场景包括医疗、保洁、宠物护理、法律等方面的预约咨询类小程序。 二、这款小程序有什么亮点优势&#xff1f; 预约咨询小程序适用场景广泛&#xff0c;无论是心理咨询、法律咨询&#xff0c;还是宠物…

让图片开口说话的模型Hallo: 基于音频驱动的肖像图像动画,精准唇形同步,支持多种语言和风格

前言 让静态的图片“开口说话”&#xff0c;一直是人们对人工智能的期待。近年来&#xff0c;随着深度学习技术的发展&#xff0c;音频驱动的肖像图像动画技术取得了长足的进步。各种模型涌现&#xff0c;但如何实现精准的唇形同步、保持视频的真实感和流畅性&#xff0c;以及…

变长的时间戳设计

以前的时间戳有32位&#xff0c;以秒为单位&#xff0c;231秒≈68年&#xff0c;从1970年开始&#xff0c;到2038年会出问题。 后来出现的时间戳有64位&#xff0c;以纳秒为单位&#xff0c;263纳秒≈292年。 本次设计的变长时间戳&#xff0c;以32比特为单位&#xff0c;总共…

mysql8.0找不到my.ini

报错问题解释&#xff1a; MySQL 8.0 在Windows系统中通常不需要 my.ini 文件&#xff0c;因为安装程序会在 %PROGRAMDATA%\MySQL\MySQL Server 8.0\ &#xff08;通常是 C:\ProgramData\MySQL\MySQL Server 8.0\&#xff09;创建默认的配置文件。如果你的系统中找不到 my.ini…

Qt中利用QTextBrowser控件设计日志窗口

我们一般使用Qt开发应用程序时&#xff0c;都有将控制台窗口去掉。但是&#xff0c;有时候又需要查看一些调试信息&#xff0c;一般的处理方式是把log写到一个文件中。本文介绍一下日志窗口&#xff0c;可以更方便的查看日志信息。 UI设计 推拽UI控件&#xff0c;修改默认背景…

FFmpeg+SDL2实现音视频播放器项目

一、FFmpeg视频解码器 1.视频解码知识 1).纯净的视频解码流程 压缩编码数据->像素数据。 例如解码H.264&#xff0c;就是“H.264码流->YUV”。 2).一般的视频解码流程 视频码流一般存储在一定的封装格式&#xff08;例如MP4、AVI等&#xff09;中。封装格式中通常还…

反转链表(java精简版)

反转一个单向链表。 public class ReversingLinkedList {static class Node {int val;Node next;public Node(int val) {this.val val;}public boolean hasNext() {return next ! null;}}public static void main(String[] args) {//构造Node head null;Node shift null;for…

高效电商数据分析:电商爬虫API与大数据技术的融合应用

一、引言 随着电子商务的迅猛发展和数据量的爆炸式增长&#xff0c;电商数据分析已成为企业决策的关键依据。在竞争激烈的电商市场中&#xff0c;如何高效、准确地获取并分析数据&#xff0c;以洞察市场趋势、优化运营策略、提升用户体验&#xff0c;成为电商企业面临的重要挑…

期货止损口诀需牢记

实战操作难免错&#xff0c;心中不必一团火&#xff1b; 出错认输是常事&#xff0c;亏损不止闯大祸。 止损纪律要定死&#xff0c;价格不能差豪丝&#xff1b; 触及止损要出局&#xff0c;管它价格怎放肆。 强势多空价放宽&#xff0c;价格波动要空间&#xff1b; 大势不改…

【数学】什么是傅里叶级数与傅里叶变换?

傅里叶级数与傅里叶变换 背景 傅里叶级数和傅里叶变换是数学和工程领域中的重要工具&#xff0c;特别是在信号处理、图像处理和物理学中。傅里叶级数用于将周期函数表示为正弦和余弦函数的和&#xff0c;而傅里叶变换用于将任意函数表示为频率的函数。 公式 傅里叶级数&…

深度学习(十四)——优化器

前言 反向传播可以求出神经网路中每个需要调节参数的梯度(grad)&#xff0c;优化器可以根据梯度进行调整&#xff0c;达到降低整体误差的作用。下面我们对优化器进行介绍。 1. 如何使用优化器 官方文档:torch.optim — PyTorch 2.0 documentation &#xff08;1&#xff09;构…