WDF驱动开发-DMA(三)

重复使用 DMA 事务对象

在驱动程序处理与 DMA 事务关联的所有 DMA 传输后,驱动程序可以删除或重用事务对象。 通常,驱动程序的 EvtInterruptDpc 回调函数通过调用 WdfObjectDelete 删除 事务对象。 随后,当驱动程序创建新的 DMA 事务时,它会调用 WdfDmaTransactionCreate 来创建新的事务对象。

但是,有时,驱动程序重用事务对象是有益的。 在这种情况下,驱动程序调用 WdfDmaTransactionRelease 而不是 WdfObjectDelete。

例如,假设驱动程序和设备必须在计算机内存资源不足时运行。 若要处理此内存问题,驱动程序可以使用以下过程:

驱动程序的 EvtDriverDeviceAdd 回调函数可以调用 WdfDmaTransactionCreate 来创建一个或多个事务对象。 驱动程序将句柄保存到这些事务对象。

每次驱动程序准备好创建和初始化新事务时,它都会调用 WdfDmaTransactionCreate。 如果此方法返回STATUS_INSUFFICIENT_RESOURCES,驱动程序可以使用其中一个存储的事务对象。

如果驱动程序使用其中一个存储的事务对象,则应在事务完成时重用事务对象,而不是删除它。 驱动程序通过调用 WdfDmaTransactionRelease 而不是 WdfObjectDelete 来设置事务对象以供重复使用。

支持适用于 DMA 设备的电源管理

DMA 启用程序对象定义一组可选的事件回调函数,DMA 设备的驱动程序可以使用这些函数来管理进入和传出设备工作 (D0) 状态的转换。

每次 DMA 设备进入其工作状态,并在框架调用驱动程序的 EvtDeviceD0Entry 回调函数后,框架将按照其列出的顺序调用以下 DMA 回调函数:

  • EvtDmaEnablerFil: 分配设备的 DMA 缓冲区;
  • EvtDmaEnablerEnabl: 在设备进入其工作 (D0) 状态后启用设备的 DMA 功能;
  • EvtDmaEnablerSelfManagedIoStar: 启动 DMA 设备的自我管理 I/O 操作;

每次 DMA 设备离开其工作状态时,在框架调用驱动程序的 EvtDeviceD0Exit 回调函数之前,框架会按照列出的顺序调用以下 DMA 回调函数:

  • EvtDmaEnablerSelfManagedIoSto: 停止 DMA 设备的自托管 I/O 操作;
  • EvtDmaEnablerDisabl: 禁用设备的 DMA 功能,然后设备离开其工作 (D0) 状态;
  • EvtDmaEnablerFlus: 解除分配设备的 DMA 缓冲区;
使用常用缓冲区

DMA 设备的驱动程序有时必须分配设备和驱动程序都可以访问的缓冲区空间。 例如,设备可能会将传输信息(如字节计数)写入此缓冲区空间,驱动程序可以读取它以确定传输的字节数。 这种类型的缓冲区空间称为 通用缓冲区。

若要分配公共缓冲区,驱动程序的 EvtDriverDeviceAdd 回调函数:

  • 调用 WdfDmaEnablerCreate 来创建 DMA 启用程序对象;
  • 调用 WdfCommonBufferCreate 或 WdfCommonBufferCreateWithConfig 来创建缓冲区;
  • 调用 WdfCommonBufferGetAlignedLogicalAddress 以获取设备可以访问的缓冲区的逻辑地址;
  • 调用 WdfCommonBufferGetAlignedVirtualAddress 以获取缓冲区的虚拟地址,驱动程序可以访问该地址;

以下代码示例演示 KMDF 驱动程序如何分配公共缓冲区空间:

复制代码
// Allocate common buffer for building writes
DevExt->WriteCommonBufferSize = 
         sizeof( DMA_TRANSFER_ELEMENT) * DevExt->WriteTransferElements;
status = WdfCommonBufferCreate( DevExt->DmaEnabler,
                                DevExt->WriteCommonBufferSize,
                                WDF_NO_OBJECT_ATTRIBUTES, 
                                &DevExt->WriteCommonBuffer );
if (!NT_SUCCESS(status)) {
    . . . //Error-handling code omitted 
    }
DevExt->WriteCommonBufferBase = 
             WdfCommonBufferGetAlignedVirtualAddress(
                      DevExt->WriteCommonBuffer);
DevExt->WriteCommonBufferBaseLA = 
             WdfCommonBufferGetAlignedLogicalAddress(
                      DevExt->WriteCommonBuffer);
RtlZeroMemory( DevExt->WriteCommonBufferBase, DevExt->WriteCommonBufferSize);

如果驱动程序在调用 WdfDmaEnablerCreate 之前调用 WdfDeviceSetAlignmentRequirement,则 WdfDmaEnablerCreate 创建的缓冲区与驱动程序指定给 WdfDeviceSetAlignmentRequirement 的内存地址边界对齐。 否则,通用缓冲区与字地址边界对齐。 或者,驱动程序可以调用 WdfCommonBufferCreateWithConfig 来指定单个缓冲区的对齐方式。

若要获取驱动程序已分配的公共缓冲区的长度,驱动程序可以调用 WdfCommonBufferGetLength。

当驱动程序使用完公共缓冲区时,驱动程序将调用 WdfObjectDelete。

在 KMDF 驱动程序中调试DMA

以下命令在windbg工具可帮助调试支持 DMA 的基于框架的驱动程序:

驱动程序验证程序:包括特定的验证测试,用于检测各种 DMA 操作的不当使用;

!dma 内核调试器扩展显示有关由驱动程序验证程序验证的 DMA 子系统和 DMA 设备驱动程序的信息。;

内核模式驱动程序框架扩展包含以下特定于 DMA 的命令:

!wdfcommonbuffer:转储有关给定公共缓冲区对象的信息;

!wdfdmaenabler:转储有关特定 DMA 启用程序对象及其事务和常见缓冲区对象的信息;

!wdfdmaenablers:列出所有 DMA 启用程序及其事务和常见缓冲区对象;

!wdfdmatransaction:转储有关给定事务对象的信息;

相关推荐
铜豌豆_Y2 小时前
【实用】GDB调试保姆级教程|常用操作|附笔记
linux·c语言·驱动开发·笔记·嵌入式
光芒Shine8 小时前
【开源飞控PX4架构】
驱动开发
DeeplyMind9 小时前
linux drm子系统技术分析目录表
linux·驱动开发·drm
张较瘦_10 小时前
[论文阅读] AI + 硬件开发 | 硬件设计新范式:LLM赋能行为驱动开发,解决验证痛点的实战方案
论文阅读·人工智能·驱动开发
DeeplyMind11 小时前
AMD KFD的BO设计分析系列7-2:GPU GART 实现深度解析--绑定机制与性能优化
驱动开发·amdgpu·kfd·gart
Zeku1 天前
20251130 - 详细解析Framebuffer应用编程中涉及到的API函数
linux·驱动开发·嵌入式软件·linux应用开发
LUCIFER1 天前
[驱动之路(七)——Pinctrl子系统]学习总结,万字长篇,一文彻底搞懂Pinctrl子系统(含Pin Controller驱动框架解析)
linux·驱动开发
Zeku2 天前
20251129 - 详细解析Linux的mmap(内存映射)
linux·驱动开发·嵌入式软件·linux应用开发
少年、潜行2 天前
F1C100/200S学习笔记(1)-- 核心板和验证板硬件设计
linux·驱动开发·f1c200s
Molesidy2 天前
【Linux】基于Imx6ull Pro开发板和platform_device+platform_driver框架的LED驱动设计以及上机测试
linux·驱动开发