Dma

  • Uploaded by: topin
  • 0
  • 0
  • November 2019
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Dma as PDF for free.

More details

  • Words: 923
  • Pages: 12
DEVICE_DESCRIPTION dd; RtlZeroMemory(&dd, sizeof(dd)); dd.Version = DEVICE_DESCRIPTION_VERSION; dd.Master = TRUE; dd.InterfaceType = InterfaceTypeUndefined; dd.MaximumLength = MAXTRANSFER; dd.Dma32BitAddresses = TRUE; pdx->AdapterObject = IoGetDmaAdapter(pdx->Pdo, &dd, &pdx->nMapRegisters); DEVICE_DESCRIPTION 结构如下页:

VOID StopDevice(...) {

if (pdx->AdapterObject) (*pdx->AdapterObject->DmaOperations->PutDmaAdapter) (pdx->AdapterObject); pdx->AdapterObject = NULL;

}

Field Name Version

Description

Version number of structure—initialize to DEVICE_DESCRIPTION_VERSION Master Bus-master device—set based on your knowledge of device ScatterGather Device supports scatter/gather list—set based on your knowledge of device DemandMode Use system DMA controller’s demand mode —set based on your knowledge of device AutoInitialize Use system DMA controller’s autoinitialize mode—set based on your knowledge of device Dma32BitAddresses Can use 32-bit physical addresses IgnoreCount Controller doesn’t maintain an accurate transfer count—set based on your knowledge of device Reserved1 Reserved—must be FALSE Dma64BitAddresses Can use 64-bit physical addresses DoNotUse2 Reserved—must be 0 DmaChannel DMA channel number—initialize from Channel attribute of resource descriptor InterfaceType Bus type—initialize to InterfaceTypeUndefined DmaWidth Width of transfers—set based on your knowledge of device to Width8Bits, Width16Bits, or Width32Bits DmaSpeed Speed of transfers—set based on your knowledge of device to Compatible, TypeA, TypeB, TypeC, or TypeF MaximumLength Maximum length of a single transfer—set based on your knowledge of device (and round up to a multiple of PAGE_SIZE) DmaPort Microchannel-type bus port number—initialize from Port attribute of resource descriptor

Relevant to Device All All All Slave Slave

All Slave

All Slave All Slave

Slave

All

Slave

typedef struct _DEVICE_EXTENSION { PADAPTER_OBJECT AdapterObject; // device's adapter object ULONG nMapRegisters; // max # map registers ULONG nMapRegistersAllocated; // # allocated for this xfer ULONG numxfer; // # bytes transferred so far ULONG xfer; // # bytes to transfer during this stage ULONG nbytes; // # bytes remaining to transfer PVOID vaddr; // virtual address for current stage PVOID regbase; // map register base for this stage

} DEVICE_EXTENSION, *PDEVICE_EXTENSION; VOID StartIo(PDEVICE_OBJECT fdo, PIRP Irp) { PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

PMDL mdl = Irp->MdlAddress; pdx->numxfer = 0; pdx->xfer = pdx->nbytes = MmGetMdlByteCount(mdl); pdx->vaddr = MmGetMdlVirtualAddress(mdl);

ULONG nregs = ADDRESS_AND_SIZE_TO_SPAN_PAGES(pdx->vaddr, pdx->nbytes); if (nregs > pdx->nMapRegisters) { nregs = pdx->nMapRegisters; pdx->xfer = nregs * PAGE_SIZE - MmGetMdlByteOffset(mdl); } pdx->nMapRegistersAllocated = nregs;

NTSTATUS status = (*pdx->AdapterObject->DmaOperations ->AllocateAdapterChannel)(pdx->AdapterObject, fdo, nregs, (PDRIVER_CONTROL) AdapterControl, pdx); if (!NT_SUCCESS(status)) { CompleteRequest(Irp, status, 0); StartNextPacket(&pdx->dqReadWrite, fdo); }

}

IO_ALLOCATION_ACTION AdapterControl(PDEVICE_OBJECT fdo, PIRP junk, PVOID regbase, PDEVICE_EXTENSION pdx) { PIRP Irp = GetCurrentIrp(&pdx->dqReadWrite);//这里如何取得 IRP 要看 排队机制 PMDL mdl = Irp->MdlAddress; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); BOOLEAN isread = stack->MajorFunction == IRP_MJ_READ; pdx->regbase = regbase; KeFlushIoBuffers(mdl, isread, TRUE); PHYSICAL_ADDRESS address = (*pdx->AdapterObject->DmaOperations->MapTransfer) (pdx->AdapterObject, mdl, regbase, pdx->vaddr, pdx->xfer, !isread);

……

return DeallocateObjectKeepRegisters; }

VOID DpcForIsr(PKDPC Dpc, PDEVICE_OBJECT fdo, PIRP junk, PDEVICE_EXTENSION pdx) { PIRP Irp = GetCurrentIrp(&pdx->dqReadWrite); PMDL mdl = Irp->MdlAddress; BOOLEAN isread = IoGetCurrentIrpStackLocation(Irp) ->MajorFunction == IRP_MJ_READ; (*pdx->AdapterObject->DmaOperations->FlushAdapterBuffers) (pdx->AdapterObject, mdl, pdx->regbase, pdx->vaddr, pdx->xfer, !isread); pdx->nbytes -= pdx->xfer; pdx->numxfer += pdx->xfer; NTSTATUS status = STATUS_SUCCESS; ……判断是否读写正确的完成了

if (pdx->nbytes && NT_SUCCESS(status)) {

pdx->vaddr = (PVOID) ((PUCHAR) pdx->vaddr + pdx->xfer); pdx->xfer = pdx->nbytes;

ULONG nregs = ADDRESS_AND_SIZE_TO_SPAN_PAGES(pdx->vaddr, pdx->nbytes); if (nregs > pdx->nMapRegistersAllocated) { nregs = pdx->nMapRegistersAllocated; pdx->xfer = nregs * PAGE_SIZE; } PHYSICAL_ADDRESS address = (*pdx->AdapterObject->DmaOperations->MapTransfer) (pdx->AdapterObject, mdl, pdx->regbase, pdx->vaddr, pdx->xfer, !isread); //这里是硬件特有的开始 DMA 传输的操作 ……

}

//如果出错了或者传输完成了 else { ULONG numxfer = pdx->numxfer; (*pdx->AdapterObject->DmaOperations->FreeMapRegisters) (pdx->AdapterObject, pdx->regbase, pdx->nMapRegistersAllocated); StartNextPacket(&pdx->dqReadWrite, fdo);//开始下一次传输,这于依 赖于排队机制 CompleteRequest(Irp, status, numxfer); } }

//两个数据结构 typedef struct _SCATTER_GATHER_ELEMENT { PHYSICAL_ADDRESS Address; ULONG Length; ULONG_PTR Reserved; } SCATTER_GATHER_ELEMENT, *PSCATTER_GATHER_ELEMENT; typedef struct _SCATTER_GATHER_LIST { ULONG NumberOfElements; ULONG_PTR Reserved; SCATTER_GATHER_ELEMENT Elements[]; } SCATTER_GATHER_LIST, *PSCATTER_GATHER_LIST; //AddDevice 中申请资源 pdx->sglist = (PSCATTER_GATHER_LIST) ExAllocatePool(NonPagedPool, sizeof(SCATTER_GATHER_LIST) + MAXSG * sizeof(SCATTER_GATHER_ELEMENT)); //adapterControl 中如下;

IO_ALLOCATION_ACTION AdapterControl(PDEVICE_OBJECT fdo, PIRP junk, PVOID regbase, PDEVICE_EXTENSION pdx) { PIRP Irp = GetCurrentIrp(&pdx->dqReadWrite); PMDL mdl = Irp->MdlAddress; BOOLEAN isread = IoGetCurrentIrpStackLocation(Irp) ->MajorFunction == IRP_MJ_READ; pdx->regbase = regbase; KeFlushIoBuffers(mdl, isread, TRUE); PSCATTER_GATHER_LIST sglist = pdx->sglist;

ULONG xfer = pdx->xfer; PVOID vaddr = pdx->vaddr; pdx->xfer = 0; ULONG isg = 0; //主要的不同在这里 while (xfer && isg < MAXSG) { ULONG elen = xfer; sglist->Elements[isg].Address = (*pdx->AdapterObject->DmaOperations->MapTransfer) (pdx->AdapterObject, mdl, regbase, pdx->vaddr, &elen, !isread);

sglist->Elements[isg].Length xfer -= elen; pdx->xfer += elen; vaddr = (PVOID) ((PUCHAR) ++isg; } sglist->NumberOfElements

= elen;

vaddr

= isg;

//这里开始设置特定的硬件,进行传输 return DeallocateObjectKeepRegisters; }

+ elen);

VOID StartIo(PDEVICE_OBJECT fdo, PIRP Irp) { PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status; PMDL mdl = Irp->MdlAddress; ULONG nbytes = MmGetMdlByteCount(mdl); PVOID vaddr = MmGetMdlVirtualAddress(mdl); BOOLEAN isread = stack->MajorFunction == IRP_MJ_READ; pdx->numxfer = 0; pdx->nbytes = nbytes; status = (*pdx->AdapterObject->DmaOperations->GetScatterGatherList) (pdx->AdapterObject, fdo, mdl, vaddr, nbytes, (PDRIVER_LIST_CONTROL) DmaExecutionRoutine, pdx, !isread); if (!NT_SUCCESS(status)) { CompleteRequest(Irp, status, 0); StartNextPacket(&pdx->dqReadWrite, fdo); } } //当条件满足时,调用这个例程

VOID DmaExecutionRoutine(PDEVICE_OBJECT fdo, PIRP junk, PSCATTER_GATHER_LIST sglist, PDEVICE_EXTENSION pdx) { PIRP Irp = GetCurrentIrp(&pdx->dqReadWrite); //保存以便这个地址被 PutScatterGatherList 用于释放列表。 pdx->sglist = sglist; //这里开始设置特定的硬件,开始 dma 传输。如果列表中的元素个数超过设备一 次能处理的能力,需要分阶段执行整个传输。如果能相当快速地编程一个阶段, 建议在 ISR 中加入初始化下一阶段的逻辑。 }

当传输完成时,我们调用适配器对象的 PutScatterGatherList 函数释放列表和适配器:

VOID DpcForIsr(PKDPC Dpc, PDEVICE_OBJECT fdo, PIRP junk, PVOID Context) {

(*pdx->AdapterObject->DmaOperations->PutScatterGatherList)

(pdx->AdapterObject, pdx->sglist, !isread);

}

//使用系统 DMA 通道 NTSTATUS StartDevice(...) { ULONG dmachannel; // system DMA channel # ULONG dmaport; // MCA bus port number

for (ULONG i = 0; i < nres; ++i, ++resource) { switch (resource->Type) { case CmResourceTypeDma:

dmachannel = resource->u.Dma.Channel; dmaport = resource->u.Dma.Port; break; } }

DEVICE_DESCRIPTION dd; RtlZeroMemory(&dd, sizeof(dd)); dd.Version = DEVICE_DESCRIPTION_VERSION; dd.InterfaceType = InterfaceTypeUndefined; dd.MaximumLength = MAXTRANSFER;

dd.DmaChannel = dmachannel; dd.DmaPort = dmaport; dd.DemandMode = ??; dd.AutoInitialize = ??; dd.IgnoreCount = ??; dd.DmaWidth = ??; dd.DmaSpeed = ??;

pdx->AdapterObject = IoGetDmaAdapter(...); }

IO_ALLOCATION_ACTION AdapterControl(...) { return KeepObject;// } 返回值 KeepObject 指出希望保留映射寄存器和 DMA 通道的控制。第二,因为 我们在 AdapterControl 返回时没有释放适配器对象,所以我们必须在 DPC 例程 中做,调用 FreeAdapterChannel 替代 FreeMapRegisters : VOID DpcForIsr(...) { (*pdx->AdapterObject->DmaOperations->FreeAdapterChannel) (pdx->AdapterObject); } //使用公用缓冲区

typedef struct _DEVICE_EXTENSION { PVOID vaCommonBuffer; PHYSICAL_ADDRESS paCommonBuffer; } DEVICE_EXTENSION, *PDEVICE_EXTENSION; dd.Dma32BitAddresses = ??; dd.Dma64BitAddresses = ??; pdx->AdapterObject = IoGetDmaAdapter(...); pdx->vaCommonBuffer = (*pdx->AdapterObject->DmaOperations->AllocateCommonBuffer) (pdx->AdapterObject, , &pdx->paCommonBuffer, FALSE);

在调用 AllocateCommonBuffer 时,第二个参数是要分配缓冲区的字节长度。 第四个参数是布尔值,它表明是否需要使分配的内存进入 CPU 高速缓冲。 AllocateCommonBuffer 返回一个虚拟地址。它就是在驱动程序中用于访问已分 配缓冲区的地址。AllocateCommonBuffer 还通过其第三个参数设置了 PHYSICAL_ADDRESS 为设备使用的逻辑地址。

Related Documents

Dma
April 2020 8
Dma
October 2019 19
Dma
November 2019 30
Dma And Dma Controlled Io
November 2019 15
Dma Zone.docx
November 2019 22
Dma W-9 Instructions
December 2019 10

More Documents from "Mark Cheney"

Dma
November 2019 30