60人参与 • 2024-08-06 • 驱动开发
在 windows 7 及更早版本上,kernel-mode driver framework (kmdf) 仅支持 (dma) 设备的总线-主直接内存访问。 此类设备包含其自己的 dma 控制器。
在片上系统 (soc) 上运行windows 8及更高版本的平台上,该框架还支持系统模式 dma,其中多个设备共享单个多通道 dma 控制器。
框架的 dma 支持包括:
框架支持单数据包和 scatter/gather dma 传输。 它还支持使用通用缓冲区。
在运行 windows 8 及更高版本的基于 soc 的平台上,框架支持单数据包系统模式 dma 传输。
为了在基于框架的驱动程序中处理总线主机和系统模式 dma 操作,框架提供了三个对象:
下面是一些术语的解释:
dma 任务(事务):dma 任务是一个完整的 i/o 操作,例如来自应用程序的单个读取或写入请求;
dma 传输:dma 传输是单个硬件操作,用于将数据从计算机内存传输到设备或从设备传输到计算机内存;
单个 dma 任务始终包含至少一个 dma 传输,但一个任务可以包含多个传输。
当基于框架的驱动程序收到 i/o 请求时,驱动程序通常会创建一个 dma 任务对象来表示请求。 当框架开始为任务提供服务时,它会确定设备是否可以在单个传输中处理整个任务。 如果任务太大,框架会将任务分解为多个传输。
处理总线主 dma 设备的 kmdf 驱动程序中的 i/o 请求需要多个驱动程序的事件回调函数中的代码,如下图所示:
如上所示,与 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 结构的指针。 但是,大多数基于框架的驱动程序不需要访问这些结构。
在驱动程序可以将 i/o 请求发送到 dma 设备之前,驱动程序必须:
通常,驱动程序会创建 dma 事务 ,因为 请求处理程序 已收到 框架请求对象 ,并且必须将请求传递给硬件。 在这种情况下,驱动程序应调用 wdfdmatransactioninitializeusingrequest,后者接受请求对象句柄作为输入,并从请求对象中提取请求的地址参数。
如果驱动程序必须创建 不 基于驱动程序收到的框架请求对象的 dma 事务,则驱动程序可以调用 wdfdmatransactioninitialize 或 wdfdmatransactioninitializeusingoffset。 这两种方法都接受驱动程序提供的地址参数。
所有三种初始化方法都需要 evtprogramdma 事件回调函数的地址作为输入参数。 此回调函数对设备进行程序,并且每次 dma 传输 可用时,框架都会调用回调函数。
当驱动程序调用 wdfdmaenablercreate 来创建 dma 启用程序对象时,驱动程序将提供包含设备最大传输长度的 wdf_dma_enabler_config 结构。 框架使用此值作为所有 dma 传输的默认最大长度。
对于某些类型的 dma 事务,可能需要指定与设备的默认最大长度不同的最大传输长度。 可以使用 wdfdmatransactionsetmaximumlength 设置单个事务的最大传输长度。 框架仅在处理指定的事务时使用指定的最大传输长度。
请注意,最大传输长度受操作系统提供给 dma 启用程序对象的 映射寄存器 数的限制。 若要确定可用的最大传输长度,驱动程序可以调用 wdfdmaenablergetfragmentlength。 如果 wdfdmaenablergetfragmentlength 返回的值小于驱动程序提供给 wdfdmaenablercreate 的最大传输长度,则框架使用较小的值。
在驱动程序创建并初始化 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 handle
devext = 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 omitted
break;
}
// execute this dmatransaction.
status = wdfdmatransactionexecute( devext->readdmatransaction,
wdf_no_context);
if(!nt_success(status)) {
. . . //error-handling code omitted
break;
}
// 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;
}
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论