WDF驱动开发-WDF总线枚举

支持在总线驱动程序中进行 PnP 和电源管理

某些设备永久插入系统,而其他设备可以在系统运行时插入和拔出电源。 总线驱动 必须识别并报告连接到其总线的设备,并且他们必须发现并报告系统中设备的到达和离开情况。

总线驱动程序标识和报告的设备称为总线的 子设备。 标识和报告子设备的过程称为 总线枚举。 在总线枚举期间,总线驱动程序会为其子 设备创建设备对象 。 

总线驱动程序本质上是同时处理总线枚举的功能驱动程序,或者很少是Filter驱动程序。 总线驱动程序通常是总线适配器的功能驱动程序,但它不是连接到总线的子设备的功能驱动程序。

总线驱动程序还具有与功能驱动程序相同的 PnP 和电源管理职责。

枚举总线上的设备

总线枚举 是确定哪些子设备连接到父设备的行为。 父设备通常是总线适配器,但它也可以是支持多种功能(例如声音卡)的设备,每个功能需要一组单独的驱动程序。

Kernel-Mode 驱动程序框架 (KMDF) 支持两种类型的总线枚举:

  • 静态枚举易于实现,如果子设备的数量和类型不是特定于系统的,并且硬件接通后不会更改,则静态枚举是理想的;
  • 当子设备的数量或类型从一台计算机更改为另一台计算机时,应使用动态枚举;

总线驱动程序可以使用或两种类型的总线枚举。

静态枚举

静态枚举 是驱动程序在系统初始化期间检测和报告设备是否存在的功能,并且报告系统配置的后续更改的能力有限。

如果设备或功能子单元的数量和类型是预先确定的和永久的,并且不依赖于运行驱动程序的系统的配置,则总线驱动程序可以使用静态枚举。

例如,声音卡的驱动程序可以充当总线驱动程序, PDO为卡的每个功能(例如 MIDI、音频和游戏杆)创建单独的物理设备对象。

静态子列表

框架通过提供静态子列表,使驱动程序能够支持静态枚举。 每个静态子列表表示连接到父设备的子设备列表。 父设备的总线驱动程序必须标识父设备的子设备,将它们添加到父设备的静态子设备列表中,并为每个子设备创建 PDO。

创建静态子列表

每次驱动程序创建一个框架设备对象,该框架对象表示 (设备的 FDO) 功能设备对象时,框架都会为设备创建一个空的静态子列表。

1. 当框架调用总线驱动程序的 EvtDriverDeviceAdd 回调函数时,回调函数必须调用 WdfDeviceCreate 为父设备创建 FDO。 

2. 然后,驱动程序必须枚举父设备的子级,为子级创建 PDO,并将子级添加到子级列表。

3. (可选)驱动程序可以调用 WdfDeviceSetBusInformationForChildren ,为框架提供有关总线的信息。 建议这样做,因为这样可以更轻松地让子设备和应用识别总线。

若要为检测到的子设备创建 PDO,总线驱动程序必须:

  • 调用 WdfPdoInitAllocate 以获取 WDFDEVICE_INIT 结构;
  • 初始化WDFDEVICE_INIT结构;
  • 调用 WdfDeviceCreate 以创建表示 PDO 的框架设备对象;

调用 WdfDeviceCreate 后,驱动程序必须调用 WdfFdoAddStaticChild 以将子设备添加到子列表。

修改静态子列表

由于驱动程序应仅对预先确定的永久性设备配置使用静态子列表,因此驱动程序在创建静态子列表后几乎不需要修改它。 如果驱动程序确定子设备变得不可访问,驱动程序可以调用 WdfPdoMarkMissing。 如果子设备仍可访问,但变得无响应且不可用,则驱动程序应将 WDF_DEVICE_STATE 结构的 Failed 成员设置为 WdfTrue,然后调用 WdfDeviceSetDeviceState。

遍历静态子列表

如果需要检索静态子列表的内容,驱动程序可以通过执行以下操作遍历该列表:

  • 调用 WdfFdoLockStaticChildListForIteration;
  • 根据需要多次调用 WdfFdoRetrieveNextStaticChild ;
  • 调用 WdfFdoUnlockStaticChildListFromIteration;
动态枚举

动态枚举 是驱动程序能够检测和报告在系统运行时连接到系统的设备的数量和类型的更改。

如果连接到父设备的设备数量或类型取决于系统的配置,则总线驱动程序必须使用动态枚举。 其中一些设备可能始终连接到系统,有些设备可能在系统运行时接通电源并拔下电源。

例如,插入系统 PCI 总线的设备的数量和类型取决于系统,但它们是永久性的,除非用户关闭电源、打开外壳,并使用螺丝刀添加或删除设备。 另一方面,用户可以通过在系统运行时插入或拔下电缆来添加或删除 USB 设备。

动态子列表

框架通过提供框架子列表对象,使驱动程序能够支持动态枚举。 每个子列表对象表示连接到父设备的子设备的列表。 父设备的总线驱动程序必须标识父设备的子设备,将它们添加到父设备的子列表中,并为每个子设备创建物理设备对象 (PDO) 。

每次驱动程序创建表示设备的 FDO 的框架设备对象时,框架都会为设备创建一个空的默认子列表。 驱动程序可以通过调用 WdfFdoGetDefaultChildList 来获取设备默认子列表的句柄。 通常,如果要编写枚举设备子级的总线驱动程序,驱动程序可以将子级添加到默认子列表。 如果需要创建其他子列表,驱动程序可以调用 WdfChildListCreate。

在驱动程序可以使用子列表之前,它必须通过初始化 WDF_CHILD_LIST_CONFIG 结构并将结构传递给 WdfFdoInitSetDefaultChildListConfig对于默认子列表或 WdfChildListCreate对于其他子列表来配置子列表对象。

动态子级说明

每次总线驱动程序标识子设备时,都必须将子设备的说明添加到子列表中。 子说明由必需的标识说明和可选的地址说明组成。

标识说明 是一种结构,它包含唯一标识驱动程序枚举的每个设备的信息。 驱动程序定义此结构,但其第一个成员必须是 WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER 结构。

通常,标识说明包含设备的 设备标识字符串(可能是序列号)以及有关设备在总线上的位置的信息,例如槽号。

驱动程序可以提供以下一组回调函数,这些函数允许框架操作标识说明中的信息:

  • EvtChildListIdentificationDescriptionCompare,用于比较两个标识描述结构的内容;
  • EvtChildListIdentificationDescriptionCopy,将一个标识说明结构的内容复制到另一个标识说明结构;
  • EvtChildListIdentificationDescriptionDuplicate,它通过复制现有标识说明结构并在必要时分配其他缓冲区来创建新的标识说明;
  • EvtChildListIdentificationDescriptionCleanup,它解除分配由 EvtChildListIdentificationDescriptionDuplicate 回调函数分配的缓冲区;

通常,如果驱动程序的标识说明结构包含指向动态分配的缓冲区的指针,则需要提供这些回调函数。 

地址说明 地址说明是一种结构,它包含驱动程序所需的信息,以便它可以访问其总线上的设备,如果信息可以在设备接通电源时发生更改。 驱动程序定义此结构,但其第一个成员必须是 WDF_CHILD_ADDRESS_DESCRIPTION_HEADER 结构。

地址说明是可选的。 如果设备地址信息在设备接通电源和拔出电源之间无法更改,则设备的所有地址信息都可以存储在标识说明中。 例如,USB 控制器在设备接通电源时将地址分配给设备,并且这些地址不会更改。

另一方面,一些总线使用可能会更改的寻址信息。 例如,IEEE 1394 总线使用“代数”,即已发生的总线重置次数。 向 IEEE 1394 设备发送的每个异步 I/O 请求都必须包含生成计数。 由于此地址信息可能会更改,因此驱动程序必须将其存储在地址说明中。

驱动程序可以提供以下回调函数集来操作地址说明中的信息:

  • EvtChildListAddressDescriptionCopy,将一个地址说明结构的内容复制到另一个地址说明结构;
  • EvtChildListAddressDescriptionDuplicate,它通过复制现有地址说明结构并在必要时分配其他缓冲区来创建新的地址说明;
  • EvtChildListAddressDescriptionCleanup,可解除分配由 EvtChildListAddressDescriptionDuplicate 回调函数分配的缓冲区;

通常,如果驱动程序的地址描述结构包含指向动态分配的缓冲区的指针,则需要提供这些回调函数。 

将设备添加到动态子列表

当框架调用总线驱动程序的 EvtDriverDeviceAdd 回调函数时,回调函数必须调用 WdfDeviceCreate 为父设备(通常是总线适配器)创建 FDO。 然后,驱动程序必须枚举父设备的子级,并将子级添加到子列表中。

(可选)驱动程序可以调用 WdfDeviceSetBusInformationForChildren ,为框架提供有关总线的信息。 建议这样做,因为它使子设备和应用更容易识别总线。

若要将子级添加到子列表,驱动程序必须为找到的每个子设备调用 WdfChildListAddOrUpdateChildDescriptionAsPresent 。 此调用通知框架驱动程序已发现连接到父设备的子设备。 当驱动程序调用 WdfChildListAddOrUpdateChildDescriptionAsPresent 时,它会提供标识说明和地址说明(可选)。

在驱动程序调用 WdfChildListAddOrUpdateChildDescriptionAsPresent 来报告新设备后,框架会通知 PnP 管理器新设备存在。 然后,PnP 管理器为新设备生成设备堆栈和驱动程序堆栈。 在此过程中,框架调用总线驱动程序的 EvtChildListCreateDevice 回调函数。 此回调函数必须调用 WdfDeviceCreate 才能为新设备创建 PDO。

通常,多个子设备连接到父设备,因此总线驱动程序需要多次调用 WdfChildListAddOrUpdateChildDescriptionAsPresent 。 执行此操作的最有效方法是:

  • 调用 WdfChildListBeginScan;
  • 为每个子设备调用 WdfChildListAddOrUpdateChildDescriptionAsPresent ;
  • 调用 WdfChildListEndScan;

如果使用对 WdfChildListBeginScan 和 WdfChildListEndScan 的调用包围驱动程序的动态枚举,框架会将所有更改存储到子列表,并在驱动程序调用 WdfChildListEndScan 时通知 PnP 管理器所做的更改。 稍后,框架会为子列表中的每台设备调用总线驱动程序的 EvtChildListCreateDevice 回调函数。 此回调函数调用 WdfDeviceCreate 为每个新设备创建 PDO。

当驱动程序调用 WdfChildListBeginScan 时,框架会将以前报告的所有设备标记为不再存在。 因此,驱动程序必须为驱动程序可以检测的所有子级,而不仅仅是新发现的子级调用 WdfChildListAddOrUpdateChildDescriptionAsPresent 。 若要将单个子级添加到子列表,驱动程序可以调用 WdfChildListUpdateAllChildDescriptionsAsPresent ,而无需先调用 WdfChildListBeginScan。

更新动态子列表

有两种常见方法来更新动态子列表中的信息:

  • 当父设备收到指示子项到达或删除的中断时,如果设备已接通电源,则驱动程序的 EvtInterruptDpc 回调函数将调用 WdfChildListAddOrUpdateChildDescriptionAsPresent ;如果设备已拔出电源,则 调用 WdfChildListUpdDescriptionAsMissing ;
  • 驱动程序可以提供 EvtChildListScanForChildren 回调函数,每次父设备进入其工作 (D0) 状态时,框架都会调用该函数。 此回调函数应通过调用 WdfChildListBeginScan、 WdfChildListAddOrUpdateChildDescriptionAsPresent (或 WdfChildListUpdateAllChildDescriptionsAsPresent) 和 WdfChildListEndScan 来枚举所有子设备;

可以在驱动程序中使用其中一种或两种技术。

遍历动态子列表

如果希望驱动程序检查子列表的内容,它可以使用以下方法之一遍历列表:

1. 若要获取每个子设备说明的内容(一次一个),驱动程序可以:

调用 WdfChildListBeginIteration。
根据需要多次调用 WdfChildListRetrieveNextDevice。
调用 WdfChildListEndIteration。
调用 WdfChildListBeginIteration 时,驱动程序指定 WDF_RETRIEVE_CHILD_FLAGS类型的标志,该标志指示框架是应检索所有设备说明还是仅检索子集。 当 WdfChildListRetrieveNextDevice 找到匹配项时,它将检索子设备的标识和地址说明,以及其设备对象的句柄。

2. 如果需要获取当前包含在子设备说明中的地址说明,驱动程序可以调用 WdfChildListRetrieveAddressDescription,并指定标识说明。 框架遍历子列表,直到找到具有匹配标识说明的子设备,然后检索地址说明。

3. 如果需要获取与特定子设备关联的框架设备对象的句柄,驱动程序可以调用 WdfChildListRetrievePdo。 框架遍历子列表,直到找到具有匹配标识说明的子设备,然后返回设备对象句柄。 请务必使用 WdfChildListBeginIteration 和 WdfChildListEndIteration 包装调用,以防止调用方在另一个线程上突然删除 PDO。

访问 PDO 的标识和地址说明

驱动程序可以调用以下方法来访问 PDO 的标识说明或地址说明:

  • WdfPdoRetrieveIdentificationDescription,用于检索与 PDO 关联的标识说明;
  • WdfPdoRetrieveAddressDescription,用于检索与 PDO 关联的地址说明;
  • WdfPdoUpdateAddressDescription,用于更新与 PDO 关联的地址说明;
处理重新枚举请求

支持动态枚举的基于框架的总线驱动程序可以接收通过 REENUMERATE_SELF_INTERFACE_STANDARD 接口恢复特定子设备的请求。

处理枚举请求

PnP 管理器可以随时请求总线驱动程序枚举其子级。 (如果熟悉 WDM 接口,则枚举请求 IRP_MN_QUERY_DEVICE_RELATIONS 关系类型为 BusRelations.) Framework 驱动程序的请求看不到这些请求。 相反,框架使用存储在设备的子列表中的信息来处理请求。 驱动程序负责使子列表保持最新状态,以便框架可以在 PnP 管理器请求枚举时提供正确的信息。

支持动态枚举的基于框架的总线驱动程序可以接收请求,要求恢复特定子设备。 在驱动程序检测到设备故障后,子设备的功能驱动程序可能会发送此类请求。 框架通过实现 REENUMERATE_SELF_INTERFACE_STANDARD 接口来支持这种类型的请求,该接口是在 wdm.h.

支持动态枚举的基于框架的总线驱动程序可以提供 EvtChildListDeviceReenumerated 回调函数,框架在收到来自子设备的驱动程序的恢复请求时调用该函数。 如果此回调函数返回 TRUE 或不存在,框架会将子设备标记为不再存在,并通知 PnP 管理器总线驱动程序的子列表已更改。 因此,PnP 管理器请求恢复,框架调用驱动程序的 EvtChildListCreateDevice 回调函数,该函数为子设备创建新的 PDO。

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

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

相关文章

TEMU半托管模式引领跨境电商新风尚

TEMU半托管模式作为2024年的热门话题,正吸引着越来越多卖家的目光。继全托管模式取得巨大成功之后,半托管模式的推出无疑为跨境电商行业注入了新的活力。 在选品方向上,TEMU半托管模式强调商品的聚焦与精选。卖家在选择上架商品时&#xff0c…

python AI全栈工程师

python AI全栈工程师 前端:Streamlit Streamlit是一个开源的Python库,专为数据科学家和机器学习工程师设计,用于快速构建交互式用户界面。Streamlit功能强大、易于使用,特别适合数据科学家和机器学习工程师快速构建和部署交互式数…

在项目中使用 VitePress 作为文档常见问题:样式丢失,图标丢失,打包错误,中文配置修改等

本文总结和记录自己在使用 vitepress 作为 Vue 项目文档时遇到的问题,以及解决方法。直接进入正题: md 文档中引入组件部分样式丢失 默认你导入的 vue 文件的 style 标签里的样式会生效,但是样式之外的样式不会生效,需要手动引入…

nodejs国内源下载

nodejs的官网下载太慢了 可以尝试网盘下载快一点 夸克网盘分享夸克网盘是夸克推出的一款云服务产品,功能包括云存储、高清看剧、文件在线解压、PDF一键转换等。通过夸克网盘可随时随地管理和使用照片、文档、手机资料,目前支持Android、iOS、PC、iPad。…

AI产品经理如何快速接手一个新产品?

我们到一家新的公司,往往都有现成的产品需要你熟悉,这个对你来说就是一个新产品。 又或者说,公司要搭建一个新的项目,让你负责,需要你从0开始去接手,最终去上线,去推广,去盈利&…

【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【14】缓存与分布式锁

持续学习&持续更新中… 守破离 【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【14】缓存与分布式锁 缓存本地缓存分布式缓存-本地模式在分布式下的问题分布式缓存整合 redis 作为缓存JMeter测试出OutOfDirectMemoryError【堆外内存溢出】 高并发读下缓存失效问题缓存…

基于YOLOv5+PyQT5的吸烟行为检测(含pyqt页面、模型、数据集)

简介 吸烟不仅对个人健康有害,也可能在某些特定场合带来安全隐患。为了有效地监控公共场所和工作环境中的吸烟行为,我们开发了一种基于YOLOv5目标检测模型的吸烟检测系统。本报告将详细介绍该系统的实际应用与实现,包括系统架构、功能实现、使用说明、检测示例、数据集获取…

UDS - 10.2 DiagnosticSessionControl (10) service

10.3 诊断会话控制(10)服务 来自:ISO 14229-1-2020.pdf 10.2.1 服务说明 DiagnosticsSessionControl服务用于在服务器中启用不同的诊断会话。 诊断会话启用服务器中的一组特定诊断服务和/或功能。该服务提供了服务器可以报告对启用的诊断会话有效的数据链路层特定参数值(…

ZAP安全扫描工具

下载地址: 去官网下载:https://www.zaproxy.org/download/ 1.主动扫描 需要登录的网站建议使用主动扫描 也可以绕过登录进行手动扫描 再选择手动扫描后 获取到对应的token 2.自动扫描 3.查看报告 4.扫描策略的使用

.gitignore git添加忽略文件

在项目的根目录下创建一个名为 .gitignore 的文件。在这个文件中,列出您希望Git忽略的文件和文件夹的名称或模式。 下面是一些基本的步骤和规则: 创建 .gitignore 文件:在项目根目录下创建一个名为 .gitignore 的文件。如果没有这个文件&…

如何设计一门编程语言?

一、设计流程 步骤说明 确定语言目标和用途: 目标受众:确定是面向初学者、专业开发者还是特定领域专家。 主要用途:明确语言的主要用途,如系统编程、Web 开发、数据分析、科学计算等。 独特卖点:确定语言的独特优势…

如何使用 Python 交互式解释器?

1. 什么是Python交互式解释器? Python交互式解释器是一种REPL(Read-Eval-Print Loop)环境。它会读取用户输入的代码,执行代码,并输出结果,随后等待下一个用户输入。这种交互方式使得Python非常适合快速原型…

【Day03】0基础微信小程序入门-学习笔记

文章目录 视图与逻辑学习目标页面导航1. 声明式导航2. 编程式导航3. 导航传参 页面事件1. 下拉刷新2. 上拉触底3.扩展-自定义编译模式 生命周期1. 简介2. 生命周期函数3. 应用的生命周期函数4. 页面生命周期函数 WXS脚本1. 概述2. 基础语法3. WXS的特点4. 使用WXS处理手机号 总…

Multisim详细安装过程

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、Multisim是什么?二、下载安装步骤1.下载安装包2.安装 总结 前言 对于很多学习电路,数电,模电的朋友,我们在…

富格林:可信经验曝光有效出金

富格林认为,在现货黄金当中,曝光可信的交易技巧可以帮助投资者有效地盈利出金。现货黄金市场就像一把双刃剑,投资者利用得好就能成为赢家,利用得不好便是损失钱财。事实上,要想成为赢家还是要掌握必须的可信经验。以下…

volcengine 库装不上 #25

https://github.com/volcengine/volc-sdk-python/issues/25 解决了, 就是解决方案比较蠢 在 Docker python3.10-slim 中 volcengine 安装时报错, 其依赖 pycryptodome 显示 gcc 相关错误 调研发现 pycryptodome3.19.0 不会报错, volcengine 依赖的 pycryptodome3.9.9 会报错 …

php中strict_types使用详解

在PHP中,strict_types是一个声明性的指令,用于在文件级别控制类型声明的严格性。当你在脚本的最顶部使用declare语句启用strict_types时,PHP将在该文件中对类型声明执行严格的类型检查。这意味着函数参数、返回值等必须精确匹配指定的类型&am…

05-Mysql备份与恢复

物理备份:对数据库操作系统的物理文件(如数据库文件,日志文件等)的备份 物理备份方法: 冷备份(防脱备份):是在关闭数据库的时候进行的 热备份(联机备份)&am…

入门JavaWeb之 Session 篇

Session: 服务器会给每个用户(浏览器)创建一个 Session 对象 一个 Session 独占一个浏览器,只要浏览器没有关闭,这个 Session 就存在 代码如下: package com.demo.cookie;import javax.servlet.Servlet…

WPF/C#:如何实现拖拉元素

前言 在Canvas中放置了一些元素&#xff0c;需要能够拖拉这些元素&#xff0c;在WPF Samples中的DragDropObjects项目中告诉了我们如何实现这种效果。 效果如下所示&#xff1a; 拖拉过程中的效果如下所示&#xff1a; 具体实现 xaml页面 我们先来看看xaml&#xff1a; <…