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 接口恢复特定子设备的请求。

 

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

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

相关文章

OpenCV颜色检测

OpenCV颜色检测 前言策略分析根据颜色检测目标对象相关链接 前言 绿幕技术是一种经典的视频编辑技术,可以用于将人物置于不同的背景中。例如在电影制作中,技术的关键在于演员不能身着特定颜色的衣服(比如绿色),站在只有绿色的背景前。然后&a…

异地组网如何OEM?

在现代信息社会中,企业越来越需要跨地域进行数据传输与共享。面临的挑战却是如何在不暴露在公网的情况下,实现异地组网并保障数据的安全性。本文将介绍一种名为“异地组网OEM”的解决方案,该方案能够通过私有通道传输数据并对数据进行安全加密…

大数据平台之Flink

Apache Flink是一款开源的流处理框架,用于处理实时数据流和批处理数据。它由Apache Software Foundation开发和维护,提供了丰富的功能和特性,适用于各种复杂的数据处理任务。下面是对Flink的详细介绍: 1. 基本概念 流处理&#…

我的大学生活-人面不知何处去(大三篇)

我的大学生活(大三篇) 前言推荐大三(人面不知何处去)2022年8月2022年9月2022年10月2022年11月2022年12月 寒假2023年1月 大三(人面不知何处去)2023年2月2023年3月2023年4月2023年5月2023年6月 暑假2023年7月…

(十三)、MQTT3.1.1-MQTT服务端数据结构设计

为进一步实现一个简易的MQTT服务端,做如下服务端数据结构设计。 1、服务端协议相关的函数 连接 rx_connect() 接收连接请求 Socket中监听,通过第一个字节switch,根据数据创建client对象 tx_connectack() 回复连接响应 处理完成rx_conn…

【LeedCode】二分查找算法(一)

二分查找算法的时间复杂度是O(logN) ,更优于传统的遍历数组算法值得我们学习。 注意二分查找一般使用的前提是:待操作的数组的元素有某种规律也就是要有二阶性,二段性就是在数组中选取一点根据该数组元素某种规律可以把数组分为两部分&#x…

国企:2024年6月中国移动相关招聘信息 三

中国移动卓望公司-卓望信息 卓望公司成立于2000年6月,是中国移动的控股子公司,积极拓展互联网、IT、ICT领域,提供平台及应用开发、运营运维等服务。  成立二十余年来,卓望公司逐渐形成包括业务合作管理、内容渠道运营、网络集中运维、企业服务、安全服务、行业DICT服务等…

笔记-python的with用法

一、With语句是什么? 在编程中,有些任务需要在执行前进行设置,并在完成后进行清理。针对这种情况,Python的with语句提供了一种非常方便的处理方式。一个典型的例子是文件处理:需要打开一个文件句柄,从中读…

LDR6500U,让设备爱上“被骗”的充电速度!

在数字设备日新月异的今天,兼容性和充电效率已成为用户关注的核心焦点。尤其是随着电子设备市场的全球化发展,标准化的需求日益凸显。近期,欧洲联盟(简称“欧盟”)就电子设备充电接口问题做出了重要决策,要…

高校新生如何选择最优手机流量卡?

一年一度的高考已经结束了,愿广大学子金榜题名,家长们都给孩子准备好了手机,那么手机流量卡应该如何选择呢? 高校新生在选择手机流量卡时,需要综合考量流量套餐、费用、网络覆盖、售后服务等多方面因素,以下…

办理河南建筑工程乙级设计资质的流程与要点

办理河南建筑工程乙级设计资质的流程与要点 办理河南建筑工程乙级设计资质的流程与要点主要包括以下几个方面: 流程: 工商注册与资质规划:确保企业具有独立法人资格,完成工商注册,并明确乙级设计资质的具体要求&…

Java开发-实际工作经验和技巧-0001-PostgreSQL数据库存储磁盘满了重启以及应急措施

Java开发-实际工作经验和技巧-0001-PostgreSQL数据库存储磁盘满了重启以及应急措施 更多内容欢迎关注我(持续更新中,欢迎Star✨) Github:CodeZeng1998/Java-Developer-Work-Note 技术公众号:CodeZeng1998&#xff0…

【Unity Shader】片段着色器(Fragment Shader)的概念及其使用方法

在Unity和图形编程中,片段着色器(Fragment Shader)是渲染管线中的一个阶段,负责计算屏幕上每个像素(片段)的颜色和特性。片段着色器通常在顶点着色器和任何几何处理之后运行,是决定最终像素颜色…

用于射频功率应用的氮化铝电阻元件

EAK推出了新的厚膜氮化铝 (AlN) 电阻器和端接系列,以补充公司现有的产品。传统上,射频功率电阻元件采用氧化铍(BeO)陶瓷材料作为陶瓷基板;然而,由于国际上要求从产品中去除BeO的压力&#xff0c…

[HBM] HBM 国产进程, 国产HBM首次研发成功 (202406)

依公知及经验整理,原创保护,禁止转载。 专栏 《深入理解DDR》 AI 的火热浪潮带火了高带宽内存的需求,HBM已是存储市场耀眼的明星。目前市场上还没有国产HBM, 什么时候可以看到国产希望呢? 或许现在可以看到曙光了。 1. 设计端 1…

免费内网穿透工具 ,快解析内网穿透解决方案

在IPv4公网IP严重不足的环境下,内网穿透技术越来越多的被人们所使用,使用内网穿透技术的好处有很多。 1:无需公网ip 物以稀为贵,由于可用的公网IP地址越来越少,价格也是水涨船高,一个固定公网IP一年的成本…

全面讲解数字化采购:整体技术架构与最佳实践

在全球化和数字化浪潮的推动下,企业的采购流程正经历深刻变革。数字化采购通过引入先进的信息技术,优化供应链管理,提高采购效率,降低成本。本文将详细介绍数字化采购的整体技术架构,并分享最佳实践经验,帮…

Java中的大数据处理与分析架构

Java中的大数据处理与分析架构 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们来讨论Java中的大数据处理与分析架构。随着大数据时代的到来&#xff0c…

JupyterLab使用指南(十): JupyterLab安全性与配置教程

文章目录 1. 生成详细的配置2. 安全策略2.1 使用 HTTPS 加密通信2.2 设置访问密码2.3 禁用 root 用户启动3. 修改配置文件4. 将 JupyterLab 作为后台进程运行4.1 使用 `nohup`4.2 使用 `systemd`1. 生成详细的配置 JupyterLab 的配置文件用于管理和定制 JupyterLab 的各种行为…