Kernel Mode Driver Framework>> C/C++ (PNP) >> File
WdfDeviceIoDirect(DMA)
參考資訊:
1. Source Code
由於我們練習的驅動程式位於上層,本身並沒有觸及過多DMA的細節操作,因此,WdfDeviceIoDirect的DMA作法會跟PIO一樣,唯一的區別就是取得DMA位址的方式,必須使用特殊的API取得,這篇練習在於說明有這樣的記憶體差別,當使用者實際觸及DMA驅動程式時,必須詳細閱讀DMA的操作方式。
記憶體指標:
Event | Buffer | Length |
---|---|---|
EvtIoRead | Step 1. WdfRequestRetrieveOutputWdmMdl() Step 2. MmGetMdlVirtualAddress() |
傳入的第三個參數 |
EvtIoWrite | Step 1. WdfRequestRetrieveInputWdmMdl() Step 2. MmGetMdlVirtualAddress() |
傳入的第三個參數 |
main.c
#include <ntddk.h> #include <wdf.h> #define DEV_NAME L"\\Device\\MyDriver" #define SYM_NAME L"\\DosDevices\\MyDriver" char szBuffer[255]={0}; void IrpFileCreate(WDFDEVICE Device, WDFREQUEST Request, WDFFILEOBJECT FileObject) { DbgPrint("IrpFieCreate"); WdfRequestComplete(Request, STATUS_SUCCESS); } void IrpFileClose(WDFFILEOBJECT FileObject) { DbgPrint("IrpFieClose"); } void IrpRead(WDFQUEUE Queue, WDFREQUEST Request, size_t Length) { PMDL mdl; ULONG len; UCHAR *dst; DbgPrint("IrpRead"); len = strlen(szBuffer) + 1; WdfRequestRetrieveOutputWdmMdl(Request, &mdl); dst = MmGetMdlVirtualAddress(mdl); memcpy(dst, szBuffer, len); WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, len); } void IrpWrite(WDFQUEUE Queue, WDFREQUEST Request, size_t Length) { PMDL mdl; UCHAR *src; DbgPrint("IrpWrite"); WdfRequestRetrieveInputWdmMdl(Request, &mdl); src = MmGetMdlVirtualAddress(mdl); memcpy(szBuffer, src, Length); DbgPrint("Buffer: %s, Length:%d", szBuffer, Length); WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, Length); } NTSTATUS AddDevice(WDFDRIVER Driver, PWDFDEVICE_INIT pDeviceInit) { WDFDEVICE device; UNICODE_STRING suDevName; UNICODE_STRING szSymName; WDF_FILEOBJECT_CONFIG file_cfg; WDF_IO_QUEUE_CONFIG ioqueue_cfg; RtlInitUnicodeString(&suDevName, DEV_NAME); RtlInitUnicodeString(&szSymName, SYM_NAME); WdfDeviceInitAssignName(pDeviceInit, &suDevName); WdfDeviceInitSetIoType(pDeviceInit, WdfDeviceIoDirect); WDF_FILEOBJECT_CONFIG_INIT(&file_cfg, IrpFileCreate, IrpFileClose, NULL); WdfDeviceInitSetFileObjectConfig(pDeviceInit, &file_cfg, WDF_NO_OBJECT_ATTRIBUTES); WdfDeviceCreate(&pDeviceInit, WDF_NO_OBJECT_ATTRIBUTES, &device); WdfDeviceCreateSymbolicLink(device, &szSymName); WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioqueue_cfg, WdfIoQueueDispatchSequential); ioqueue_cfg.EvtIoRead = IrpRead; ioqueue_cfg.EvtIoWrite = IrpWrite; return WdfIoQueueCreate(device, &ioqueue_cfg, WDF_NO_OBJECT_ATTRIBUTES, WDF_NO_HANDLE); } NTSTATUS DriverEntry(PDRIVER_OBJECT pOurDriver, PUNICODE_STRING pRegistry) { WDF_DRIVER_CONFIG config; WDF_DRIVER_CONFIG_INIT(&config, AddDevice); return WdfDriverCreate(pOurDriver, pRegistry, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE); }
IrpWrite()複製User Application的資料到szBuffer
IrpRead()回填資料給User Application
app.c
#define INITGUID #include <windows.h> #include <strsafe.h> #include <setupapi.h> #include <stdio.h> #include <stdlib.h> int __cdecl main(int argc, char* argv[]) { HANDLE hFile = NULL; DWORD dwRet = 0; char szBuffer[255]={0}; hFile = CreateFile("\\\\.\\MyDriver", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if(hFile == INVALID_HANDLE_VALUE){ printf("failed to open mydriver"); return 1; } strncpy(szBuffer, "I am error", sizeof(szBuffer)); WriteFile(hFile, szBuffer, strlen(szBuffer) + 1, &dwRet, NULL); printf("WR: %s, %d\n", szBuffer, dwRet); memset(szBuffer, 0, sizeof(szBuffer)); ReadFile(hFile, szBuffer, sizeof(szBuffer), &dwRet, NULL); printf("RD: %s, %d\n", szBuffer, dwRet); CloseHandle(hFile); return 0; }
結果