Hello,
I want to use Direct I/O to implement DMA on my own driver, but it seems doesn’t work. Here’s my steps(For some reasons, I can not choose the way of WDF’s Dmatransaction):
1, allocate DMA adaptor during the driver init. DEVICE_DESCRIPTION dd; RtlZeroMemory(&dd, sizeof(dd)); dd.Version = DEVICE_DESCRIPTION_VERSION2; dd.Master = TRUE; dd.ScatterGather = TRUE; dd.InterfaceType = PCIBus; dd.MaximumLength = MAXIMUM_TRANSFER_LENGTH; dd.Dma64BitAddresses = TRUE;
ULONG NumberOfMapRegisters = 100;
adapter = IoGetDmaAdapter(WdfDeviceWdmGetPhysicalDevice(DevExt->Device), &dd, &NumberOfMapRegisters);
KdPrint((“DMA Adapter can afford %d Map Registers”, NumberOfMapRegisters));
if (!adapter) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, “WdfDmaEnablerCreate failed: %!STATUS!”, status); return STATUS_NDIS_ADAPTER_NOT_FOUND; }
DevExt->DmaChannel[i].DmaAdaptor = adapter;
2, Make a DeviceIOContorl with Direct I/O #define PCIe_IOCTL_CREATE_DMA_CHANNEL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_DIRECT_FROM_HARDWARE, FILE_ANY_ACCESS)
3, In EvtIoDeviceControl routine PDEVICE_OBJECT pDevice = WdfDeviceWdmGetPhysicalDevice(DevExt->Device); status = WdfRequestRetrieveInputWdmMdl(Request, &mdl); virtualAddress = MmGetMdlVirtualAddress(mdl); length = MmGetMdlByteCount(mdl); status = adapter->DmaOperations->GetScatterGatherList( adapter, pDevice, mdl, virtualAddress, length, SGListExcution, DevExt, TRUE );4, In SGListExcution, get the SGList to my device’s DMA engine dteVA = (PDMA_TRANSFER_ELEMENT)devExt->ReadCommonBufferBase; dteLA = (devExt->ReadCommonBufferBaseLA.QuadPart + sizeof(DMA_TRANSFER_ELEMENT)); for (i = 0; i < SgList->NumberOfElements; i++) {
dteVA->LogicalAddr = SgList->Elements[i].Address.QuadPart; dteVA->Length = SgList->Elements[i].Length;
KdPrint((“[Element %d]LogicalAddr: %llx, Length:%llu”, i, dteVA->LogicalAddr, dteVA->Length));
// Reserved dteVA->Status = 0xFFFF; dteVA->VirturalAddr = 0;
offset += SgList->Elements[i].Length;
// // If at end of SgList, then set LastElement bit in final NTE. // if (i == SgList->NumberOfElements - 1) { dteVA->NextDescAddr = 0; break; } else { dteVA->NextDescAddr = dteLA; }
//Adjust the next DMA_TRANSFER_ELEMEMT
dteVA++; dteLA += sizeof(DMA_TRANSFER_ELEMENT);
KdPrint((“dteVA is %llx, dteLA is %llx”, dteVA, dteLA)); } After doing this, I enable my device to write data to the physical address. But there’s no data found after the divice finish writing. my user space buffer is still nothing.
I don’t know in which part the problem occurs?
Thank you