WDF驱动开发-DMA(一)

在 Windows 7 及更早版本上,Kernel-Mode Driver Framework (KMDF) 仅支持 (DMA) 设备的总线-主直接内存访问。 此类设备包含其自己的 DMA 控制器。

在片上系统 (SoC) 上运行Windows 8及更高版本的平台上,该框架还支持系统模式 DMA,其中多个设备共享单个多通道 DMA 控制器。

框架的 DMA 支持包括:

  • 一组框架 DMA 对象和方法,驱动程序使用这些对象和方法将 I/O 请求转换为 DMA 操作;
  • 一组驱动程序提供的事件回调函数,这些函数在发生不同事件时配置设备的 DMA 行为;

框架支持单数据包和 scatter/gather DMA 传输。 它还支持使用通用缓冲区。

在运行 Windows 8 及更高版本的基于 SoC 的平台上,框架支持单数据包系统模式 DMA 传输。

为了在基于框架的驱动程序中处理总线主机和系统模式 DMA 操作,框架提供了三个对象:

  • DMA 启用程序对象框架的 DMA 启用程序对象使驱动程序能够对特定设备使用框架的 DMA 支持。 驱动程序必须为支持 DMA 操作的每个设备创建 DMA 启用程序对象;
  • DMA 任务对象(事务对象)框架的 DMA 任务对象表示单个 DMA I/O 操作。 如果设备使用 DMA 执行请求的操作,基于框架的驱动程序通常会为其接收的每个 I/O 请求创建 DMA 事务对象;
  • 公共缓冲区对象框架的公共缓冲区对象表示计算机内存的一个区域,该区域映射供驱动程序和设备同时访问。 某些驱动程序在为 DMA 设备设置 I/O 操作时 使用通用缓冲区 ;

下面是一些术语的解释: 

DMA 任务(事务):DMA 任务是一个完整的 I/O 操作,例如来自应用程序的单个读取或写入请求;

DMA 传输:DMA 传输是单个硬件操作,用于将数据从计算机内存传输到设备或从设备传输到计算机内存;

单个 DMA 任务始终包含至少一个 DMA 传输,但一个任务可以包含多个传输。

当基于框架的驱动程序收到 I/O 请求时,驱动程序通常会创建一个 DMA 任务对象来表示请求。 当框架开始为任务提供服务时,它会确定设备是否可以在单个传输中处理整个任务。 如果任务太大,框架会将任务分解为多个传输。

在适用于总线主控 DMA 设备的 KMDF 驱动程序中处理 I/O 请求

处理总线主 DMA 设备的 KMDF 驱动程序中的 I/O 请求需要多个驱动程序的事件回调函数中的代码,如下图所示:

如上所示,与 DMA 相关的处理分四个阶段进行:

  1. 驱动程序的 EvtDriverDeviceAdd 或 EvtDevicePrepareHardware 回调函数必须为设备 启用 DMA 事务 ,以便驱动程序可以使用框架的 DMA 功能。 如果设备和驱动程序需要访问共享内存缓冲区,则相同的回调函数还必须 创建一个公共 缓冲区;
  2. 当驱动程序收到需要设备执行 DMA 操作的 I/O 请求时,驱动程序 的请求处理程序 之一必须 创建并初始化新的 DMA 事务。 请注意,如果驱动程序 重用 DMA 事务对象,驱动程序的 EvtDriverDeviceAdd 回调函数可以创建事务对象。然后,请求处理程序必须 启动 DMA 事务 ,以便框架可以根据需要开始将事务分解为较小的 DMA 传输,并调用驱动程序的 EvtProgramDma 回调函数;
  3. 驱动程序的 EvtProgramDma 回调函数针对单个 DMA 传输对 DMA 硬件进行编程 ,并启用设备中断;
  4. 设备中断时,框架会调用驱动程序的 EvtInterruptIsr 回调函数,这将保存易失设备信息并计划驱动程序的 EvtInterruptDpc 回调函数的执行。驱动程序的 EvtInterruptDpc 回调函数在硬件 完成处理后完成每个 DMA 传输 。 DMA 事务的最终传输完成后, EvtInterruptDpc 回调函数 完成 DMA 事务;

驱动程序可能会 重复使用其 DMA 事务对象 ,以确保它们在内存资源不足时可以运行。

驱动程序可以提供一组回调函数,用于处理 特定于 DMA 的电源管理操作。

某些驱动程序使用设备和驱动程序都可以访问的通用缓冲区 。

启用 DMA 事务

如果基于框架的驱动程序处理 DMA 设备的 I/O 操作,则驱动程序必须为每个 DMA 设备启用框架的 DMA 功能。 若要启用这些功能,驱动程序的 EvtDriverDeviceAdd 或 EvtDevicePrepareHardware 回调函数必须:

调用 WdfDeviceSetAlignmentRequirement 以指定设备的缓冲区对齐要求。

调用 WdfDmaEnablerCreate 以指定 DMA 操作的类型 (单个数据包或散点/收集) 以及设备支持的最大传输大小。 从 KMDF 版本 1.11 开始,该框架支持在操作系统的 Windows 8 或更高版本上运行的基于芯片 (SoC) 的系统上的系统模式 DMA。

调用 WdfDmaEnablerSetMaximumScatterGatherElements 以指定设备可在scatter/gather列表中支持的最大元素数,如果设备支持scatter/gather操作。

以下代码示例演示了如何启用框架的 DMA 功能:

WDF_DMA_ENABLER_CONFIG   dmaConfig;WdfDeviceSetAlignmentRequirement( DevExt->Device, PCI9656_DTE_ALIGNMENT_16 );
WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig,WdfDmaProfileScatterGather64Duplex,DevExt->MaximumTransferLength );
status = WdfDmaEnablerCreate( DevExt->Device,&dmaConfig, WDF_NO_OBJECT_ATTRIBUTES,&DevExt->DmaEnabler );

如果驱动程序需要通用缓冲区,驱动程序的 EvtDriverDeviceAdd 回调函数通常会设置它们。 

驱动程序调用 WdfDmaEnablerCreate 后,它可以调用 WdfDmaEnablerWdmGetDmaAdapter 以获取指向框架为设备的输入和输出方向创建的 WDM DMA_ADAPTER 结构的指针。 但是,大多数基于框架的驱动程序不需要访问这些结构。

创建并初始化 DMA 事务

在驱动程序可以将 I/O 请求发送到 DMA 设备之前,驱动程序必须:

  • 调用 WdfDmaTransactionCreate 为请求创建 DMA 事务对象;
  • 调用 WdfDmaTransactionInitializeUsingRequest、 WdfDmaTransactionInitialize 或 WdfDmaTransactionInitializeUsingOffset 来初始化事务对象;

通常,驱动程序会创建 DMA 事务 ,因为 请求处理程序 已收到 框架请求对象 ,并且必须将请求传递给硬件。 在这种情况下,驱动程序应调用 WdfDmaTransactionInitializeUsingRequest,后者接受请求对象句柄作为输入,并从请求对象中提取请求的地址参数。

如果驱动程序必须创建 不 基于驱动程序收到的框架请求对象的 DMA 事务,则驱动程序可以调用 WdfDmaTransactionInitialize 或 WdfDmaTransactionInitializeUsingOffset。 这两种方法都接受驱动程序提供的地址参数。

所有三种初始化方法都需要 EvtProgramDma 事件回调函数的地址作为输入参数。 此回调函数对设备进行程序,并且每次 DMA 传输 可用时,框架都会调用回调函数。

当驱动程序调用 WdfDmaEnablerCreate 来创建 DMA 启用程序对象时,驱动程序将提供包含设备最大传输长度的 WDF_DMA_ENABLER_CONFIG 结构。 框架使用此值作为所有 DMA 传输的默认最大长度。

对于某些类型的 DMA 事务,可能需要指定与设备的默认最大长度不同的最大传输长度。 可以使用 WdfDmaTransactionSetMaximumLength 设置单个事务的最大传输长度。 框架仅在处理指定的事务时使用指定的最大传输长度。

请注意,最大传输长度受操作系统提供给 DMA 启用程序对象的 映射寄存器 数的限制。 若要确定可用的最大传输长度,驱动程序可以调用 WdfDmaEnablerGetFragmentLength。 如果 WdfDmaEnablerGetFragmentLength 返回的值小于驱动程序提供给 WdfDmaEnablerCreate 的最大传输长度,则框架使用较小的值。

在驱动程序创建并初始化 DMA 事务后,驱动程序必须 启动该事务。

启动 DMA 事务

在驱动程序 创建并初始化 DMA 事务后,驱动程序可以调用 WdfDmaTransactionExecute 方法来启动该事务。 此方法为与事务关联的第一个 DMA 传输 生成散点/收集列表。 接下来, 方法调用驱动程序为事务注册的 EvtProgramDma 回调函数。 回调函数 对 DMA 硬件进行程序 以启动传输。

在驱动程序调用 WdfDmaTransactionExecute 之前,驱动程序必须存储 DMA 事务句柄,以便在驱动程序完成与事务关联的每个 DMA 传输时可以检索该句柄。 存储事务句柄的一个好位置是在框架对象的上下文内存中,通常是设备的框架设备对象。 

以下代码演示如何初始化并执行 DMA 事务:

VOID PLxEvtIoRead(IN WDFQUEUE         Queue,IN WDFREQUEST       Request,IN size_t           Length)
{NTSTATUS            status = STATUS_UNSUCCESSFUL;PDEVICE_EXTENSION   devExt;// Get the DevExt from the queue handledevExt = PLxGetDeviceContext(WdfIoQueueGetDevice(Queue));do {// Validate the Length parameter.if (Length > PCI9656_SRAM_SIZE)  {status = STATUS_INVALID_BUFFER_SIZE;break;}// Initialize the DmaTransaction.status = WdfDmaTransactionInitializeUsingRequest(devExt->ReadDmaTransaction,Request, PLxEvtProgramReadDma, WdfDmaDirectionReadFromDevice );if(!NT_SUCCESS(status)) {. . . //Error-handling code omittedbreak; }// Execute this DmaTransaction.status = WdfDmaTransactionExecute( devExt->ReadDmaTransaction, WDF_NO_CONTEXT);if(!NT_SUCCESS(status)) {. . . //Error-handling code omittedbreak; }// Indicate that the DMA transaction started successfully.// The DPC routine will complete the request when the DMA// transaction is complete.status = STATUS_SUCCESS;} while (0);// If there are errors, clean up and complete the request.if (!NT_SUCCESS(status )) {WdfDmaTransactionRelease(devExt->ReadDmaTransaction); WdfRequestComplete(Request, status);}return;
}

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

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

相关文章

视频讲解|基于模型预测算法的含储能微网双层能量管理模型【mpc】

1 主要内容 该讲解视频对应的免费程序链接为【防骗贴】基于模型预测算法的含储能微网双层能量管理模型,主要做的是一个微网双层优化调度模型,微网聚合单元包括风电、光伏、储能以及超级电容器,在微网的运行成本层面考虑了电池的退化成本&…

快捷方式(lnk)--加载HTA-CS上线

免责声明:本文仅做技术交流与学习... 目录 CS: HTA文档 文件托管 借助mshta.exe突破 本地生成lnk快捷方式: 非系统图标路径不同问题: 关于lnk的上线问题: CS: HTA文档 配置监听器 有效载荷---->HTA文档--->选择监听器--->选择powershell模式----> 默认生成一…

政务大厅引导系统:AR、VR技术革新引领政务服务体验升级

一、传统政务大厅面临的普遍痛点 随着城市的发展和政务服务需求的增长,传统的政务大厅面临着诸多挑战和痛点: 信息不对称:政务大厅内各部门信息分散,群众难以快速获取全面准确的服务信息,导致办事效率低下。 办事流…

ES6 新增Set 和 Map 两种数据结构

ES6 新增了 Set 和 Map 这两种数据结构,它们为 JavaScript 提供了更强大和灵活的数据处理能力。下面详细介绍一下 Set 和 Map 的特性和用法: Set Set 是一种类似于数组的数据结构,但是成员的值都是唯一的,没有重复的值。 特性&…

4字节十进制数 转为 IPV4点分十进制 -- C++语言实现

4字节十进制数 转为 IPV4点分十进制 – C语言实现 //IPv4表示,通过4字节整数,比如1 6777 2418(0x0A 00 01 02),表示10.0.1.2 // 4字节 4 * 1字节 4 * 8bit 32 bit // 2 ^32 1024 * 1024 *1024 * 4 42 9496 7296 0xff ff ff ff 1 //写…

计算机视觉 | 基于图像处理和边缘检测算法的黄豆计数实验

目录 一、实验原理二、实验步骤1. 图像读取与预处理2. 边缘检测3. 轮廓检测4. 标记轮廓序号 三、实验结果 Hi,大家好,我是半亩花海。 本实验旨在利用 Python 和 OpenCV 库,通过图像处理和边缘检测算法实现黄豆图像的自动识别和计数&#xff0…

ICMPV6协议

ICMPV6:intermet 控制管理协议--- 存在大量的子协议 1、PMTU---路径 MTU 发现协议 通过ICMPV6error包来获取整段路径上最小 MTU 值 2、NDP------邻居发现协议---用于取代IPV4下的 ARP协议 假设PC1和PC2 通讯 1无2的MAC地址 …

JetBrains GoLand 2024 mac/win版:高效开发,Go无止境

JetBrains GoLand 2024是一款专为Go语言开发者设计的集成开发环境(IDE),为开发者带来了更加高效、智能和便捷的编程体验。 GoLand 2024 mac/win版获取 在代码编辑方面,GoLand 2024提供了全行代码补全功能,通过利用先进的深度学习模型&#x…

C#面:C#中的析构函数是什么?

在C#中,析构函数是一种特殊的方法,用于在对象被销毁之前执行一些清理操作。它的名称与类名相同,但在名称前面加上一个波浪线(~)。析构函数没有参数,也没有返回类型。 当对象不再被使用时,垃圾回…

力扣85.最大矩形

力扣85.最大矩形 遍历所有行作为底边 做求矩形面积&#xff08;84. class Solution {public:int maximalRectangle(vector<vector<char>>& matrix) {if (matrix.empty()) return 0;int n matrix.size(),m matrix[0].size();int res0;vector<int> li…

grub引导LinuxMint

注意事项&#xff1a;文件系统必须是FAT32 安装 sudo apt install gparted -y 分区管理软件 使用gparted分区和查看设备路径 sudo apt-get install grub-efi-amd64 #/dev/sdd1 是需要制作分区引导的设备路径 sudo mount /dev/sdd1 /mnt/123 #bios sudo grub-install --targe…

适耳贴合的气传导耳机,带来智能生活体验,塞那Z50耳夹耳机上手

现在大家几乎每天都会用到各种AI产品&#xff0c;蓝牙耳机也是我们必不可少的装备&#xff0c;最近我发现一款很好用的分体式气传导蓝牙耳机&#xff0c;它还带有一个具备AI功能的APP端&#xff0c;大大方便了我们日常的使用。这款sanag塞那Z50耳夹耳机我用过一段时间以后&…

interface Ref<T = any> 这是什么写法?为什么写接口还需要加上<T = any>

问: export interface Ref<T any> { value: T [RefSymbol]: true } 这里既然是interface接口,为什么还有<T any>这是什么意思? 回答: <T any> 中的 <T> 表示这是一个泛型参数&#xff0c;它可以在接口中作为类型的占位符&#xff0c;在实际…

动手学深度学习(Pytorch版)代码实践 -卷积神经网络-19图像卷积

19图像卷积 #互相关运算 #在卷积层中&#xff0c;输入张量和核张量通过互相关运算产生输出张量。 import torch from torch import nn from d2l import torch as d2ldef corr2d(X, K):"""计算二维互相关运算"""h, w K.shapeY torch.zeros((X.…

开发指南033-数据库兼容

元芳&#xff0c;你怎么看&#xff1f; 单一数据库自身就有一些不同处理之处&#xff0c;如果一个平台要兼容所有数据库&#xff0c;就是难上加难&#xff0c;像isnull函数各数据库就不同。 对于这类问题&#xff0c;平台采用统一自定义函数解决&#xff0c;例如上面的round函…

一篇文章搞懂残差网络算法

残差网络(Residual Network,简称ResNet)是一种深度学习架构,它在2015年由微软研究院的Kaiming He等四位作者提出。ResNet的提出是为了解决深度神经网络训练中的梯度消失和梯度爆炸问题,以及随着网络层数增加而出现的性能退化问题。本文将详细介绍残差网络算法的定义、产生…

模式分解的概念(下)-无损连接分解的与保持函数依赖分解的定义和判断、损失分解

一、无损连接分解 1、定义 2、检验一个分解是否是无损连接分解的算法 输入与输出 输入&#xff1a; 关系模式R&#xff08;U&#xff0c;F&#xff09;&#xff0c;F是最小函数依赖集 R上的一个分解 输出&#xff1a; 判断分解是否为无损连接分解 &#xff08;1&#x…

【LinuxC语言】POSIX信号量

文章目录 前言一、信号量的概念信号量相关函数sem_initsem_waitsem_postsem_destroy总结前言 在并发编程中,我们经常需要对共享资源进行访问控制,以防止数据竞争和不一致性。在Linux C语言中,我们使用一种称为“信号量”的机制来实现这种控制。信号量是一种同步工具,用于保…

JAVA同城服务场馆门店预约系统支持H5小程序APP源码

&#x1f4f1;一键预约&#xff0c;畅享无忧体验&#x1f3e2; &#x1f680;一、开启预约新纪元 在繁忙的都市生活中&#xff0c;我们常常因为时间紧张而错过心仪的门店或场馆服务。然而&#xff0c;有了“门店场馆预约小程序”&#xff0c;这些问题都将迎刃而解。这款小程序…

群辉NAS中文件下载的三种方案

目录 一、迅雷套件 1、添加套件来源 2、安装套件 3、手机安装迅雷 二、qBittorrent套件 1、添加套件来源 2、改手工安装 3、更新后的问题 4、最后放弃DSM6 (1)上传文件手工安装 (2)添加套件来源 5、解决登陆报错 6、添加tracker 7、修改下载默认位置 8、手机…