Beruflich Dokumente
Kultur Dokumente
RtlZeroMemory(&dd, sizeof(dd));
dd.Version = DEVICE_DESCRIPTION_VERSION;
dd.Master = TRUE;
dd.InterfaceType = InterfaceTypeUndefined;
dd.MaximumLength = MAXTRANSFER;
dd.Dma32BitAddresses = TRUE;
DEVICE_DESCRIPTION 结构如下页:
VOID StopDevice(...)
{
if (pdx->AdapterObject)
(*pdx->AdapterObject->DmaOperations->PutDmaAdapter)
(pdx->AdapterObject);
pdx->AdapterObject = NULL;
}
Field Name Description Relevant
to Device
Version Version number of structure—initialize All
to DEVICE_DESCRIPTION_VERSION
Master Bus-master device—set based on your All
knowledge of device
ScatterGather Device supports scatter/gather list—set All
based on your knowledge of device
DemandMode Use system DMA controller’s demand mode Slave
—set based on your knowledge of device
AutoInitialize Use system DMA controller’s Slave
autoinitialize mode—set based on your
knowledge of device
Dma32BitAddresses Can use 32-bit physical addresses All
IgnoreCount Controller doesn’t maintain an accurate Slave
transfer count—set based on your
knowledge of device
Reserved1 Reserved—must be FALSE
Dma64BitAddresses Can use 64-bit physical addresses All
DoNotUse2 Reserved—must be 0
DmaChannel DMA channel number—initialize from - Slave
Channel attribute of resource descriptor
InterfaceType Bus type—initialize to InterfaceType- All
Undefined
DmaWidth Width of transfers—set based on your Slave
knowledge of device to Width8Bits,
Width16Bits, or Width32Bits
DmaSpeed Speed of transfers—set based on your Slave
knowledge of device to Compatible, TypeA,
TypeB, TypeC, or TypeF
MaximumLength Maximum length of a single transfer—set All
based on your knowledge of device (and
round up to a multiple of PAGE_SIZE)
DmaPort Microchannel-type bus port number—- Slave
initialize from Port attribute of
resource descriptor
typedef struct _DEVICE_EXTENSION {
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
pdx->regbase = regbase;
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)
{
(*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;
……判断是否读写正确的完成了
}
//如果出错了或者传输完成了
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;
//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)
{
sglist->Elements[isg].Address =
(*pdx->AdapterObject->DmaOperations->MapTransfer)
(pdx->AdapterObject, mdl, regbase, pdx->vaddr,
&elen, !isread);
sglist->Elements[isg].Length = elen;
xfer -= elen;
pdx->xfer += elen;
vaddr = (PVOID) ((PUCHAR) vaddr + elen);
++isg;
}
sglist->NumberOfElements = isg;
//这里开始设置特定的硬件,进行传输
return DeallocateObjectKeepRegisters;
}
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 中加入初始化下一阶段的逻辑。
}
(*pdx->AdapterObject->DmaOperations->PutScatterGatherList)
(pdx->AdapterObject, pdx->sglist, !isread);
//使用系统 DMA 通道
NTSTATUS StartDevice(...)
{
ULONG dmachannel; // system DMA channel #
ULONG dmaport; // MCA bus port number
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;//
}
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, <length>, &pdx->paCommonBuffer, FALSE);
AllocateCommonBuffer 返回一个虚拟地址。它就是在驱动程序中用于访问已分
配缓冲区的地址。AllocateCommonBuffer 还通过其第三个参数设置了
PHYSICAL_ADDRESS 为设备使用的逻辑地址。