windows USB 设备驱动开发-USB电源管理(二)

USB KMDF 功能驱动程序中的选择性挂起

如果 USB 驱动程序需要用户模式下不可用的功能或资源,则应提供 KMDF 函数驱动程序。 KMDF 驱动程序通过在 KMDF 初始化结构中设置相关值,然后提供适当的回调函数来实现选择性挂起。 KMDF 处理与较低驱动程序通信以挂起和恢复设备的详细信息。

KMDF 驱动程序中的选择性挂起指南

支持选择性挂起的 KMDF 驱动程序必须遵循以下准则:

  • KMDF 函数驱动程序必须是其设备堆栈的 PPO。 默认情况下,KMDF 函数驱动程序是 PPO。
  • 支持选择性挂起的 KMDF 函数驱动程序可以使用电源管理的队列或不受电源管理的队列。 默认情况下,PDO 的队列对象受电源管理。
电源策略所有权和 KMDF USB 驱动程序

默认情况下,USB 设备的 KMDF 函数驱动程序是设备堆栈的 PPO。 KMDF 代表此驱动程序管理选择性挂起和恢复。

KMDF 驱动程序中的 I/O 队列配置

支持选择性挂起的 KMDF 函数驱动程序可以使用电源管理的队列或不受电源管理的队列。 通常,驱动程序将非电源管理的队列配置为接收传入的设备 I/O 控制请求,并将一个或多个电源管理的队列配置为接收读取、写入和其他电源依赖请求。 当请求到达电源管理的队列时,KMDF 确保设备处于 D0 状态,然后再向驱动程序提出请求。

如果要编写在设备堆栈中 PPO 之上分层的 KMDF 筛选器驱动程序,则不得使用电源管理的队列。 原因与 UMDF 驱动程序相同。 当设备暂停时,框架不会显示来自电源管理的队列的请求,因此使用此类队列可能会停止设备堆栈。

KMDF 函数驱动程序的选择性挂起机制

KMDF 处理支持 USB 选择性挂起所需的大部分工作。 它跟踪 I/O 活动,管理空闲计时器,并发送导致父驱动程序 (Usbhub.sys 或 Usbccgp.sys) 挂起和恢复设备的设备 I/O 控制请求。

如果 KMDF 函数驱动程序支持选择性挂起,则 KMDF 跟踪每个设备对象拥有的所有电源托管队列上的 I/O 活动。 每当 I/O 计数达到零时,框架就会启动空闲计时器。 默认超时值为 5 秒。

如果在空闲超时期限到期之前,I/O 请求到达属于设备对象的电源托管队列,框架将取消空闲计时器,并且不会暂停设备。

空闲计时器过期时,KMDF 会发出将 USB 设备置于挂起状态所需的请求。 如果函数驱动程序在 USB 端点 上使用连续读取器,则读取器的重复轮询不会算作 KMDF 空闲计时器的活动。 但是,在 EvtDeviceD0Exit 回调函数中,USB 驱动程序必须手动停止连续读取器和由不受电源管理的队列提供的任何其他 I/O 目标,以确保驱动程序在设备未处于工作状态时不会发送 I/O 请求。 若要停止目标,驱动程序调用 WdfIoTargetStop 并将 WdfIoTargetWaitForSentIoToComplete 指定为目标操作。 作为响应,框架仅在目标 I/O 队列中的所有 I/O 请求都已完成且任何关联的 I/O 完成回调运行后,才会停止 I/O 目标。

默认情况下,KMDF 将设备从 D0 转换为驱动程序在空闲设置中指定的设备电源状态。 作为转换的一部分,KMDF 调用驱动程序的电源回调函数的方式与任何其他关机序列的调用方式相同。

设备挂起后,当发生以下任何事件时,框架会自动恢复设备:

  • 任何驱动程序的电源托管队列的 I/O 请求都到达。
  • 用户通过使用设备管理器禁用 USB 选择性挂起。
  • 驱动程序调用 WdfDeviceStopIdle,如 防止 USB 设备挂起中所述。

为了恢复设备,KMDF 在设备堆栈中向下发送一个通电请求,然后调用驱动程序的回调函数,其方式与任何其他启动序列的调用方式相同。

在 KMDF 函数驱动程序中支持 USB 选择性挂起

若要在 KMDF 函数驱动程序中实现 USB 选择性挂起,请执行以下操作:

  • 初始化与空闲相关的电源策略设置,包括空闲超时。
  • (可选)包括逻辑,以在驱动程序确定不应由于打开的句柄或与设备的 I/O 队列无关的其他原因而暂停设备时暂时阻止挂起或恢复操作。
  • 在人机接口设备的 USB 驱动程序 (HID) 中,在 INF 中指示它支持选择性挂起。
在 KMDF 函数驱动程序中初始化电源策略设置

为了配置对 USB 选择性挂起的支持,KMDF 驱动程序使用 WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS 结构。 驱动程序必须首先初始化结构,然后才能设置字段来提供有关驱动程序及其设备功能的详细信息。 通常,驱动程序在其 EvtDriverDeviceAdd 或 EvtDevicePrepareHardware 函数中填充此结构。

1. 初始化WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS结构
驱动程序创建设备对象后,驱动程序使用 WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT 函数初始化结构。 此函数采用两个参数:

  • 指向要初始化 的WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS 结构的指针。
  • 一个枚举值,指示支持选择性挂起。 驱动程序应指定 IdleUsbSelectiveSuspend。

如果驱动程序指定 IdleUsbSelectiveSuspend,则函数初始化结构的成员,如下所示:

  • IdleTimeout 设置为 IdleTimeoutDefaultValue (当前为 5000 毫秒或 5 秒) 。
  • UserControlOfIdleSettings 设置为 IdleAllowUserControl 。
  • Enabled 设置为 WdfUseDefault,这表示选择性挂起已启用,但如果 UserControlOfIdleSettings 成员允许,用户可以禁用它。
  • DxState 设置为 PowerDeviceMaximum,这将使用设备报告的电源功能来确定要转换空闲设备的状态。

2. 配置 USB 选择性挂起
驱动程序初始化 WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS 结构后,驱动程序可以在结构中设置其他字段,然后调用 WdfDeviceAssignS0IdleSettings 将这些设置传递给框架。 以下字段适用于 USB 函数驱动程序:

  • IdleTimeout - 在框架认为设备处于空闲状态之前,必须在不收到 I/O 请求的情况下经过的间隔(以毫秒为单位)。 驱动程序可以指定 ULONG 值,也可以接受默认值。
  • UserControlOfIdleSettings - 用户是否可以修改设备的空闲设置。 可能的值为 IdleDoNotAllowUserControl 和 IdleAllowUserControl。
  • DxState - 框架将设备挂起的设备电源状态。 可能的值为 PowerDeviceD1、PowerDeviceD2 和 PowerDeviceD3。

USB 驱动程序不应更改此值的初始设置。 WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT 函数将此值设置为 PowerDeviceMaximum,这可确保框架根据设备功能选择正确的值。

以下代码片段来自 Osrusbfx2 示例驱动程序的 Device.c 文件:

WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings;
NTSTATUS    status = STATUS_SUCCESS;
//
// Initialize the idle policy structure.
//
WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleUsbSelectiveSuspend);
idleSettings.IdleTimeout = 10000; // 10 secstatus = WdfDeviceAssignS0IdleSettings(Device, &idleSettings);
if ( !NT_SUCCESS(status)) {TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,"WdfDeviceSetPowerPolicyS0IdlePolicy failed %x\n", status);return status;
}

在此示例中,驱动程序调用 WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT,指定 IdleUsbSelectiveSuspend。 驱动程序将 IdleTimeout 设置为 10,000 毫秒 (10 秒) ,并接受 DxState 和 UserControlOfIdleSettings 的框架默认值。 因此,框架会在设备处于空闲状态时将其转换为 D3 状态,并创建一个设备管理器属性页,允许具有管理员特权的用户启用或禁用设备空闲支持。 然后,驱动程序调用 WdfDeviceAssignS0IdleSettings 来启用空闲支持,并在框架中注册这些设置。

驱动程序可以在创建设备对象后随时调用 WdfDeviceAssignS0IdleSettings 。 尽管大多数驱动程序最初从 EvtDriverDeviceAdd 回调调用此方法,但这并非始终可行,甚至不可取。 如果驱动程序支持多个设备或设备版本,则在查询硬件之前,驱动程序可能不知道所有设备功能。 此类驱动程序可以推迟调用 WdfDeviceAssignS0IdleSettings ,直到 EvtDevicePrepareHardware 回调。

在最初调用 WdfDeviceAssignS0IdleSettings 后,驱动程序可以随时更改空闲超时值和设备空闲的设备状态。 若要更改一个或多个设置,驱动程序只需初始化前面所述的另一 个WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS 结构,然后再次调用 WdfDeviceAssignS0IdleSettings 。

阻止 USB 设备挂起

有时,即使超时期间没有 I/O 请求存在,也不应关闭 USB 设备,这通常是在向设备打开句柄或设备正在充电时。 在这种情况下,USB 驱动程序可以通过调用 WdfDeviceStopIdle 并调用 WdfDeviceResumeIdle 来阻止框架挂起空闲设备。如果设备被暂停,则它再次可以接受。

WdfDeviceStopIdle 停止空闲计时器。 如果 IdleTimeout 期限尚未过期且设备尚未暂停,则框架将取消空闲计时器,并且不会暂停设备。 如果设备已挂起,框架会将设备返回到工作状态。 WdfDeviceStopIdle不会阻止框架在系统更改为 Sx 睡眠状态时挂起设备。 它的唯一效果是在系统处于 S0 工作状态时防止设备挂起。 WdfDeviceResumeIdle 重启空闲计时器。 这两种方法管理设备上的引用计数,因此,如果驱动程序多次调用 WdfDeviceStopIdle ,框架不会暂停设备,直到驱动程序调用 WdfDeviceResumeIdle 的次数相同。 驱动程序在未首先调用 WdfDeviceStopIdle的情况下不得调用 WdfDeviceResumeIdle。

HID 驱动程序包含注册表项

USB HID 设备的 KMDF 上层筛选器驱动程序必须在 INF 中指示它们支持选择性挂起,以便 Microsoft 提供的 HIDClass.sys 端口驱动程序可以为 HID 堆栈启用选择性挂起。 INF 应包含 AddReg 指令,该指令添加 SelectiveSuspendEnabled 键并将其值设置为 1,如以下字符串所示:

HKR,,"SelectiveSuspendEnabled",0x00000001,0x1

有关示例,请参阅 WDK 中 %WinDDK%\BuildNumber\Src\Hid\ Hidusbfx2\sys 中的 Hidusbfx2.inx。

KMDF 驱动程序的远程唤醒支持

与选择性暂停一样,KMDF 包含对唤醒的支持,以便 USB 设备可以在设备空闲且系统处于工作状态 (S0) 或处于睡眠状态 (S1-S4) 时触发唤醒信号。 在 KMDF 术语中,这两个功能分别称为“从 S0 唤醒”和“从 Sx 唤醒”。

对于 USB 设备,唤醒仅指示设备本身可以启动从低功耗状态到工作状态的转换。 因此,在 USB 术语中,从 S0 唤醒和从 Sx 唤醒是相同的,称为“远程唤醒”。

KMDF USB 函数驱动程序不需要任何代码来支持从 S0 唤醒,因为 KMDF 将此功能作为选择性挂起机制的一部分提供。 但是,若要在系统处于 Sx 中时支持远程唤醒,函数驱动程序必须:

  • 通过调用 WdfUsbTargetDeviceRetrieveInformation 检查设备是否支持远程唤醒。
  • 通过初始化唤醒设置并调用 WdfDeviceAssignSxWakeSettings 来启用远程唤醒。

KMDF 驱动程序通常在配置对 EvtDriverDeviceAdd 或 EvtDevicePrepareHardware 函数中的 USB 选择性挂起的支持的同时配置唤醒支持。

检查设备功能

在 KMDF USB 函数驱动程序初始化其电源策略设置以用于空闲和唤醒之前,它应验证设备是否支持远程唤醒。 为了获取有关设备硬件功能的信息,驱动程序初始化 WDF_USB_DEVICE_INFORMATION 结构并调用 WdfUsbTargetDeviceRetrieveInformation,通常在其 EvtDriverDeviceAdd 或 EvtDevicePrepareHardware 回调中。

在调用 WdfUsbTargetDeviceRetrieveInformation 时,驱动程序将句柄传递给设备对象,并将指针传递给初始化 的 WDF_USB_DEVICE_INFORMATION 结构。 从函数成功返回后,结构的“特征”字段包含标志,这些标志指示设备是否为自供电、是否可以高速运行并支持远程唤醒。

来自 Osrusbfx2 KMDF 示例的以下示例演示如何调用此方法来确定设备是否支持远程唤醒。 运行这些代码行后,如果设备支持远程唤醒,则 waitWakeEnable 变量包含 TRUE;如果不支持,则为 FALSE:

WDF_USB_DEVICE_INFORMATION          deviceInfo;
// Retrieve USBD version information, port driver capabilities and device
// capabilities such as speed, power, etc.
//WDF_USB_DEVICE_INFORMATION_INIT(&deviceInfo);status = WdfUsbTargetDeviceRetrieveInformation(pDeviceContext->UsbDevice,&deviceInfo);
waitWakeEnable = deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE;

启用远程唤醒

在 USB 术语中,当设置 USB 设备DEVICE_REMOTE_WAKEUP功能时,会启用远程唤醒。 根据 USB 规范,主机软件必须在“仅在将设备置于睡眠状态之前”设备上设置远程唤醒功能。 仅初始化唤醒设置时,才需要 KMDF 函数驱动程序。 KMDF 和 Microsoft 提供的 USB 总线驱动程序发出 I/O 请求,并处理启用远程唤醒所需的硬件操作。

初始化远程唤醒:

1.调用 WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT 以初始化 WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS 结构。 此函数将结构的 Enabled 成员设置为 WdfUseDefault,将 DxState 成员设置为 PowerDeviceMaximum,并将 UserControlOfWakeSettings 成员设置为 WakeAllowUserControl。
2.使用初始化的结构调用 WdfDeviceAssignSxWakeSettings 。 因此,设备能够从 D3 状态唤醒,用户可以在 设备管理器 中的设备属性页启用或禁用唤醒信号。
Osrusbfx2 示例中的以下代码片段演示如何将唤醒设置初始化为其默认值:

WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings;WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings);
status = WdfDeviceAssignSxWakeSettings(Device, &wakeSettings);
if (!NT_SUCCESS(status)) {return status;
}


对于支持选择性挂起的 USB 设备,基础总线驱动程序准备要唤醒的设备硬件。 因此,USB 函数驱动程序很少需要 EvtDeviceArmWakeFromS0 回调。 当空闲超时过期时,框架会向 USB 总线驱动程序发送选择性挂起请求。

出于同一原因,USB 函数驱动程序很少需要 EvtDeviceWakeFromS0Triggered 或 EvtDeviceWakeFromSxTriggered 回调。 相反,框架和基础总线驱动程序会处理将设备返回到工作状态的所有要求。

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

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

相关文章

无缝阅读体验:使用iCloud跨设备同步阅读进度的终极指南

无缝阅读体验:使用iCloud跨设备同步阅读进度的终极指南 在数字化时代,我们经常在多个设备上阅读电子书籍、文章和网页。无论是在通勤途中使用手机,在家中使用平板电脑,还是在工作中使用笔记本电脑,能够无缝地在设备之…

手撸俄罗斯方块(三)——游戏核心模块设计

手撸俄罗斯方块——游戏核心模块设计 开始游戏 按照之前的设计,我们需要游戏的必要元素之后即可开始游戏,下面以控制台上运行俄罗斯方块为例进行展开讲解。 import { ConsoleCanvas, ConsoleController, ConsoleColorTheme, Color } from shushanfx/t…

CSS技巧专栏:一日一例 3.纯CSS实现炫酷多彩按钮特效

大家好,今天是 CSS技巧专栏:一日一例 第三篇《纯CSS实现炫酷多彩按钮特效》 先看图: 开工前的准备工作 正如昨日所讲,为了案例的表现,也处于书写的习惯,在今天的案例开工前,先把昨天的准备工作重做一遍。 清除浏览器的默认样式定义页面基本颜色设定body的样式清除butt…

云视频监控中的高效视频转码策略:视频汇聚EasyCVR平台H.265自动转码H.264能力解析

随着科技的快速发展,视频监控技术已经广泛应用于各个领域,如公共安全、商业管理、教育医疗等。与此同时,视频转码技术作为视频处理的关键环节,也在不断提高视频的质量和传输效率。 一、视频监控技术的演进 视频监控技术的发展历…

SEO之网站结构优化(一)

初创企业搭建网站的朋友看1号文章;想学习云计算,怎么入门看2号文章谢谢支持: 1、我给不会敲代码又想搭建网站的人建议 2、新手上云 网站内的优化大致可以分为两部分,一是网站结构调整,二是页面上针对关键词的相关性优化…

前端八股文 闭包的理解

什么是闭包 闭包是指有权访问另一个函数作用域中的变量的函数 ——《JavaScript高级程序设计》 (闭包 内层函数 引用的外层函数的变量) 下面就是一个简单的闭包 闭包不一定必须有 return 闭包不一定有内存泄漏 闭包 什么时候用到 return 就是 外部…

真实工作项目Java使用apache.poi生成word

加油,新时代打工人! 将实体类利用poi转成Word文件 demo示例 package com.fqpais.util;import com.fqpais.business.domain.TestReportTemplate; import com.fqpais.common.utils.StringUtils; import org.apache.poi.xwpf.usermodel.*; import org.slf4…

apache python使用

修改httpd.conf文件。 AddHandler cgi-script .cgi .py 代码 #!自己的python.exe #-*- coding:UTF-8 -*- print ("Content-type:text/html") print () print (<html>) print (<head>) print (<meta charset"gb2312">) print (<tit…

【排序 - 直接选择排序】

选择排序&#xff08;Selection Sort&#xff09;是一种简单直观的排序算法&#xff0c;虽然不如快速排序或归并排序高效&#xff0c;但它易于理解和实现&#xff0c;适用于小型数据集合。 选择排序原理 选择排序的基本思想是每次从未排序的数据中选出最小&#xff08;或最大…

mvcc 速读

MVCC&#xff08;Multi-Version Concurrency Control&#xff0c;多版本并发控制&#xff09;是MySQL中一种用于实现数据库并发控制的方法&#xff0c;尤其在InnoDB存储引擎中得到了广泛应用。它的主要作用是提高数据库在高并发场景下的性能&#xff0c;并确保数据的一致性。 …

QGroundControl连接运行在Docker中的PX4固件模拟器

1.通过docker启动PX4无人机 docker run --rm -it jonasvautherin/px4-gazebo-headless:1.14.3 启动成功&#xff1a; PX4完全启动OK如下&#xff1a; 会看到pxh> INFO [commander] Ready for takeoff! 执行takeoff指令 查看运行docker容器与QGC客户端的主机IP&#xff1a; …

【HarmonyOS NEXT】鸿蒙 代码混淆

代码混淆简介 针对工程源码的混淆可以降低工程被破解攻击的风险&#xff0c;缩短代码的类与成员的名称&#xff0c;减小应用的大小。 DevEco Studio提供代码混淆的能力并默认开启&#xff0c;API 10及以上版本的Stage模型、编译模式为release时自动进行代码混淆。 使用约束 …

【企业级监控】Docker部署Zabbix与监控主机

基于Docker部署Zabbix6.2 文章目录 基于Docker部署Zabbix6.2资源列表基础环境一、首先安装Docker1.1、部署Docker1.2、配置Docker加速器 二、部署Zabbix组件介绍三、部署Zabbix3.1、安装数据库容器3.2、安装zabbix-java-gateway3.3、安装zabbix-server3.4、安装zabbix-web界面3…

从零开始实现大语言模型(四):简单自注意力机制

1. 前言 理解大语言模型结构的关键在于理解自注意力机制(self-attention)。自注意力机制可以判断输入文本序列中各个token与序列中所有token之间的相关性&#xff0c;并生成包含这种相关性信息的context向量。 本文介绍一种不包含训练参数的简化版自注意力机制——简单自注意…

java synchronized关键字介绍

Java 中的 synchronized 关键字用于实现线程安全&#xff0c;防止多个线程同时访问共享资源时出现数据不一致的问题。它可以用来修饰方法或者代码块&#xff0c;确保在同一时刻最多只有一个线程执行被 synchronized 修饰的代码。 使用场景 同步实例方法&#xff1a;确保同一实…

JMH324-免费【最后一战LOL】MOBA竞技版本+单机一键端+视频教程+文本教程

资源介绍&#xff1a; 修改前打开【D:\ZHServer】文件夹里的【[1]一键启动.bat】&#xff0c;游戏不要打开&#xff0c;否则修改失败。 修改完以后重启架设程序才会生效。 fball_gamedb1数据库——gameuser数据表 obj_name 角色名 obj_lv 等级 obj_diamond 钻石 obj_gold 8…

嵌入式驱动源代码(9):Linux内核移植

目录 环境平台介绍 修改编译内核 1. 解压linux-3.0.8.tar.bz2源码包 2. 修改内核根目录下Makefile文件 3. 修改链接地址和运行地址 4. 修改机器类型ID号(mach-type) 5. 修改默认配置文件 6. 修改支持NAND FLASH及MTD分区 7. 支持yaffs文件系统 8. make zImage 9. 内…

ZFT9-7VE8043-Z同期脉冲发送装置100V JOSEF约瑟 柜内安装

ZFT9(PIG)同期脉冲发送装置 系列型号 ZFT9(PIG) 7VE8033同期脉冲发送装置; ZFT9(PIG) 7VE8043同期脉冲发送装置; ZFT9 7VE8033同期脉冲发送装置; ZFT9 7VE8043同期脉冲发送装置; 用途&#xff1a; ZFT9同期脉冲发送装置用于船舶的三相系统&#xff0c;根据发电机和电力系…

为什么要考国际人力资源证书?HR不能不知道!

在人力资源领域中&#xff0c;持有专业的人力资源证书并非铁律般的必需。但不容忽视的是&#xff0c;随着时代的进步和行业的不断演进&#xff0c;越来越多的人力资源专业人员开始重视并追求人力资源资格认证。 一张高含金量的证书让HR在求职市场上更具竞争力&#xff0c;更能…

JavaScript中的执行上下文和原型链

目录 一、执行上下文 1.执行上下文 2.执行上下文栈 3.闭包 1&#xff09;定义 2&#xff09;形成条件 3&#xff09;例子 &#xff08;1&#xff09;例子1&#xff1a;简单闭包 &#xff08;2&#xff09;例子2&#xff1a;闭包与循环 &#xff08;3&#xff09;例子…