系统的硬件资源包括 I/O 端口、中断向量、直接内存访问 (DMA) 通道,以及其他必须分配给连接到系统的每个设备的通信路径。 本节中的主题介绍Kernel-Mode驱动程序框架如何 (KMDF) 驱动程序协商设备的硬件资源要求、查看建议的资源列表,然后接收分配的资源。 本部分还讨论 KMDF 和 User-Mode Driver Framework (UMDF) 驱动程序如何访问和映射分配的资源。
用户插入 PnP 设备后, 枚举设备的 驱动程序通常会创建一个或多个 逻辑配置,这些配置是设备可以使用的硬件资源的组合。 这些配置包括:
- 一种 启动配置 ,其中列出了设备在系统启动时所需的硬件资源。 对于 PnP 设备,此信息由 BIOS;
- 设备可以运行的其他配置。 驱动程序将这些附加配置分组到 资源要求列表中。 PnP 管理器最终将从此列表中选择要分配给设备的资源;
驱动程序创建逻辑配置后,会将这些配置发送到框架,框架会将这些配置发送到 PnP 管理器。
接下来,PnP 管理器确定设备需要哪些驱动程序,并在尚未加载时加载这些驱动程序。 PnP 管理器将设备的硬件要求列表发送到设备的驱动程序以供查看。 功能和Filter驱动程序可以修改此列表并将其发送回 PnP 管理器。
PnP 管理器检查修改后的硬件要求列表,并确定哪些指定的资源在系统上实际可用。 如果设备需要 PnP 管理器之前分配给另一台设备的资源,PnP 管理器可能会尝试在系统设备之间 重新分发资源 。
接下来,PnP 管理器创建 一个资源列表,该列表是 PnP 管理器打算分配给设备的资源列表。 PnP 管理器将此列表发送到设备的驱动程序以供查看。 此时,功能和Filter驱动程序可以从列表中删除资源,但无法向其添加资源。
最后,PnP 管理器将资源分配给设备。 框架将资源列表传递给设备的功能和Filter驱动程序,设备的功能驱动程序执行任何必要的初始化,以便设备和驱动程序可以访问资源。
以下步骤更详细地描述了该过程:
- 用户插入设备。
- 总线驱动程序检测并 枚举 设备。
- 框架调用总线驱动程序的 EvtDeviceResourcesQuery 回调函数,该函数创建描述设备启动配置 的资源列表 。
- 框架调用总线驱动程序的 EvtDeviceResourceRequirementsQuery 回调函数,该回调函数为设备 创建资源要求列表 。
- PnP 管理器确定设备需要哪些驱动程序并加载它们(如果尚未加载),以便为设备创建驱动程序堆栈。
- PnP 管理器将设备的资源要求列表发送到驱动程序堆栈以供查看。 当列表在驱动程序堆栈中向下移动时,框架会调用每个函数并筛选驱动程序的 EvtDeviceFilterRemoveResourceRequirements 回调函数。 当列表备份堆栈时,框架会调用每个函数并筛选驱动程序的 EvtDeviceFilterAddResourceRequirements 回调函数。 这两个回调函数都可以 修改资源要求列表。
- PnP 管理器为设备创建资源列表,并将其发送到驱动程序堆栈以供查看。 框架调用每个功能和Filter驱动程序的 EvtDeviceRemoveAddedResources 回调函数,这将删除驱动程序的 EvtDeviceFilterAddResourceRequirements 回调函数添加的资源,以便总线驱动程序不会尝试使用它们。
- 框架从 PnP 管理器接收最终资源列表并将其存储。
- 如果驱动程序调用 WdfInterruptCreate 来创建中断对象,框架会在资源列表中查找中断资源并将其分配给中断对象。
- 设备进入未初始化的 D0 状态后,框架会调用每个驱动程序的 EvtDevicePrepareHardware 回调函数,将设备资源列表 的原始版本和已翻译 版本作为输入参数传递。 驱动程序可以保存资源列表,该列表在框架调用驱动程序的 EvtDeviceReleaseHardware 回调函数之前有效。
硬件资源的框架对象
框架定义了以下三个对象,框架和驱动程序使用这些对象来指定设备的硬件资源:
框架 resource-requirements-list 对象
每个框架 resource-requirements-list 对象都表示 一个资源要求列表。 这些对象的句柄的类型为 WDFIORESREQLIST。 对象定义 框架 resource-requirements-list 对象方法。 资源要求列表由一组逻辑配置组成。
框架 resource-range-list 对象
每个框架 resource-range-list 对象表示一个 逻辑配置 (即设备能够在资源要求列表中使用) 的一组资源范围。 这些对象的句柄的类型为 WDFIORESLIST。 对象定义 框架 resource-range-list 对象方法。
框架资源列表对象
每个框架资源列表对象表示一个逻辑配置 (即资源列表中) 一组特定 资源。 这些对象的句柄的类型为 WDFCMRESLIST。 对象定义 框架资源列表对象方法。
创建资源要求列表
当总线驱动程序检测到子设备时,驱动程序负责为设备创建资源要求列表。 列表中的每个项都是设备的 逻辑配置 。
驱动程序在总线枚举期间报告设备后,框架将调用驱动程序的 EvtDeviceResourceRequirementsQuery 回调函数。 此回调函数接收表示空资源要求列表的 resource-requirements-list 对象的句柄。
然后,驱动程序必须执行以下操作才能将信息添加到资源要求列表:
1. 创建空的逻辑配置。对于驱动程序将指定的每个逻辑配置,驱动程序必须调用 WdfIoResourceListCreate 来创建空的逻辑配置。
2. 将资源描述符添加到逻辑配置。
若要将资源描述符添加到逻辑配置,驱动程序必须针对设备所需的每种类型的硬件资源执行以下操作:
填写驱动程序分配 的IO_RESOURCE_DESCRIPTOR 结构,该结构指定特定资源的有效值范围。
调用 WdfIoResourceListAppendDescriptor 或 WdfIoResourceListInsertDescriptor 将IO_RESOURCE_DESCRIPTOR结构的内容添加到逻辑配置中。
如果设备使用资源类型的多个实例,则堆栈中访问资源的所有驱动程序都必须知道资源的添加顺序。 例如,如果设备需要两个 I/O 端口地址范围,则访问资源描述符的所有驱动程序都必须知道这两个范围添加到逻辑配置的顺序。
3. 将逻辑配置添加到资源要求列表。
若要将逻辑配置添加到设备的资源要求列表,驱动程序调用 WdfIoResourceRequirementsListAppendIoResList 或 WdfIoResourceRequirementsListInsertIoResList。
将资源分配给设备时,PnP 管理器会尝试匹配列表中第一个逻辑配置的要求。 如果该配置所需的资源不可用,则 PnP 管理器将匹配可用的资源的列表中的下一个配置。
如果驱动程序支持非 PnP 设备,则驱动程序通常还必须调用 WdfIoResourceRequirementsListSetSlotNumber 和 WdfIoResourceRequirementsListSetInterfaceType。
驱动程序的 EvtDeviceResourceResourceRequirementsQuery 回调函数返回后,框架会将资源要求列表传递给 PnP 管理器。
修改资源要求列表
PnP 管理器确保已加载新连接设备的所有驱动程序后,会将设备的硬件要求列表发送到设备的驱动程序堆栈。
当列表在堆栈中向下移动时,框架调用每个函数和筛选器驱动程序的 EvtDeviceFilterRemoveResourceRequirements 回调函数,并将硬件要求列表作为输入参数传递。 此回调函数可以从总线驱动程序指定的硬件要求列表中删除硬件资源,但函数驱动程序确定设备运行不必要。
例如,PCI 总线驱动程序可能会根据 PCI 规范复制内存空间中的 I/O 空间资源。 如果设备可以在不使用 I/O 空间资源的情况下运行,则设备的功能驱动程序可以从硬件要求列表中删除 I/O 空间资源。
若要从要求列表中删除项,驱动程序可以执行以下操作:
1. 调用以下方法来修改资源要求列表中的逻辑配置:
WdfIoResourceRequirementsListGetCount,用于获取逻辑配置的数量。
WdfIoResourceRequirementsListGetIoResList,用于获取对逻辑配置的访问权限。
WdfIoResourceRequirementsListRemove 和 WdfIoResourceRequirementsListRemoveByIoResList,以删除逻辑配置;
2. 调用以下方法来修改逻辑配置中的资源描述符:
WdfIoResourceListGetCount,用于获取资源描述符的数量。
WdfIoResourceListGetDescriptor,用于获取对资源描述符的访问权限。
WdfIoResourceListRemove 和 WdfIoResourceListRemoveByDescriptor,用于删除资源描述符;
当列表备份驱动程序堆栈时,框架会调用每个函数并筛选驱动程序的 EvtDeviceFilterAddResourceRequirements 回调函数,并将硬件要求列表作为输入参数传递。 此回调函数可以添加函数驱动程序使设备正常运行所需的其他硬件资源。
若要将项添加到硬件要求列表,驱动程序可以执行以下操作:
1. 调用以下方法来修改资源要求列表中的逻辑配置:
WdfIoResourceRequirementsListGetCount,用于获取逻辑配置的数量。
WdfIoResourceRequirementsListGetIoResList,用于获取对逻辑配置的访问权限。
WdfIoResourceListCreate,用于创建新的逻辑配置。
WdfIoResourceRequirementsListAppendIoResList 或 WdfIoResourceRequirementsListInsertIoResList,以添加新的逻辑配置。
2. 调用以下方法来修改逻辑配置中的资源描述符:
WdfIoResourceListGetCount,用于获取资源描述符的数量。
WdfIoResourceListGetDescriptor,用于获取对资源描述符的访问权限。
WdfIoResourceListAppendDescriptor 或 WdfIoResourceListInsertDescriptor,用于添加资源描述符。