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:转储有关给定事务对象的信息;

相关推荐
nix.gnehc11 小时前
读懂 OpenSpec:AI 编码时代的规范驱动开发新范式
人工智能·驱动开发·sdd·openspec
嵌入式×边缘AI:打怪升级日志11 小时前
DS18B20 Linux 驱动开发实战:从时序图到温度读取的保姆级教学
linux·驱动开发
智者知已应修善业13 小时前
【proteus78进制计数器与非门】2023-7-5
驱动开发·经验分享·笔记·硬件架构·硬件工程
嵌入式×边缘AI:打怪升级日志17 小时前
从零开始学习 Linux SPI 驱动开发(基于 IMX6ULL + TLC5615 DAC)
linux·驱动开发·学习
senijusene1 天前
基于 imx6ull平台按键驱动开发:input子系统+中断子系统+platform总线
linux·驱动开发
senijusene1 天前
I2C 总线框架下LM75A 温度传感器 Linux驱动开发:
linux·运维·驱动开发
熬夜有啥好2 天前
基于IMXULL的SHT3X 温湿度传感器 I2C 驱动开发调试记录
驱动开发·imx6ull·i2c·sht3x温湿度传感器
senijusene2 天前
基于 Linux SPI 子系统的 ADXL345 加速度传感器驱动开发
linux·运维·驱动开发
快乐的划水a3 天前
单片机仿Linux驱动开发(一)
linux·驱动开发·单片机
快乐的划水a3 天前
单片机仿Linux驱动开发(三)
linux·驱动开发·单片机