WDF驱动开发-WDF总线枚举(一)

2024-06-24 11:52
文章标签 开发 驱动 总线 枚举 wdf

本文主要是介绍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 接口恢复特定子设备的请求。

 

这篇关于WDF驱动开发-WDF总线枚举(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1090071

相关文章

Python通过模块化开发优化代码的技巧分享

《Python通过模块化开发优化代码的技巧分享》模块化开发就是把代码拆成一个个“零件”,该封装封装,该拆分拆分,下面小编就来和大家简单聊聊python如何用模块化开发进行代码优化吧... 目录什么是模块化开发如何拆分代码改进版:拆分成模块让模块更强大:使用 __init__.py你一定会遇到的问题模www.

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

使用Python开发一个简单的本地图片服务器

《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

利用Python开发Markdown表格结构转换为Excel工具

《利用Python开发Markdown表格结构转换为Excel工具》在数据管理和文档编写过程中,我们经常使用Markdown来记录表格数据,但它没有Excel使用方便,所以本文将使用Python编写一... 目录1.完整代码2. 项目概述3. 代码解析3.1 依赖库3.2 GUI 设计3.3 解析 Mark

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件

基于Python开发批量提取Excel图片的小工具

《基于Python开发批量提取Excel图片的小工具》这篇文章主要为大家详细介绍了如何使用Python中的openpyxl库开发一个小工具,可以实现批量提取Excel图片,有需要的小伙伴可以参考一下... 目前有一个需求,就是批量读取当前目录下所有文件夹里的Excel文件,去获取出Excel文件中的图片,并

基于Python开发PDF转PNG的可视化工具

《基于Python开发PDF转PNG的可视化工具》在数字文档处理领域,PDF到图像格式的转换是常见需求,本文介绍如何利用Python的PyMuPDF库和Tkinter框架开发一个带图形界面的PDF转P... 目录一、引言二、功能特性三、技术架构1. 技术栈组成2. 系统架构javascript设计3.效果图