驅動程序(3) WDF下DMA傳輸的驅動程序代碼詳細說明之頭文件

之前提到根據KMDF模板生成的程序裏主要有5個頭文件和3個源文件,接下來的幾篇文章則會對這些文件詳細說明,一個驅動程序是怎樣寫成的。這一篇主要說明幾個頭文件。

1. device.h

/*++
Module Name:
	device.h
Abstract:
	This file contains the device definitions.
Environment:
	Kernel-mode Driver Framework
--*/
#include "Public.h"
#define LED_MEMORY_OFFSET 0xC0000000
#define DataTransferedStored_Address 0x100;
#define DataTransfered_Bytes 0x10;          //定義一些後續程序需求的參數

typedef struct _INTERRUPT_CONTEXT INTERRUPT_CONTEXT, *PINTERRUPT_CONTEXT;//中斷上下文的機構提
typedef struct _DEVICE_CONTEXT DEVICE_CONTEXT, *PDEVICE_CONTEXT;//設備上下文的結構體

struct _INTERRUPT_CONTEXT
{
	BOOLEAN State;
	PDEVICE_CONTEXT DeviceContext;
};

struct _DEVICE_CONTEXT
{
	//設備資源相關參數
	ULONG Counter_i;
	PVOID MemBaseAddress0;  //when i=0, it gets BAR0 start virtual address   內存映射地址
	PVOID MemBaseAddress1;  //when i=2, it gets BAR1 start virtual address 
	PVOID MemBaseAddress2;  //when i=4, it gets BAR2 start virtual address 
	PVOID IoBaseAddress;    //I/O映射地址
	ULONG PhysicalAddressRegister0;  //store the BAR0 start physical address
	ULONG PhysicalAddressRegister1;  //store the BAR1 start physical address
	ULONG PhysicalAddressRegister2;  //store the BAR2 start physical address
	ULONG MemLength0;               //映射後BAR的長度
	ULONG MemLength1;
	ULONG MemLength2;
	ULONG OffsetAddressFromApp; //get offset address that is given by application
	
	//中斷相關參數
	PKINTERRUPT Interrupt;
	INTERRUPT_CONTEXT InterruptContext;
	PDEVICE_OBJECT PhysicalDeviceObject;
	KSPIN_LOCK SpinLock;
	BOOLEAN State;
	
	//DMA和申請buffer相關參數
	WDFDMAENABLER DmaEnabler;
	WDFCOMMONBUFFER CommonBuffer;
	PVOID CommonBufferBase;
	PHYSICAL_ADDRESS CommonBufferBaseLA;
	WDFDMATRANSACTION DmaTransaction;
	WDFREQUEST Request;
	PMDL Mdl;
	ULONG BufferLength;

	PVOID virtualAddress;
	PHYSICAL_ADDRESS virtualAddressLA;
	PVOID UserModeVirtualAddress;
	PVOID KernelModeVirtualAddress;
};
//
// This macro will generate an inline function called DeviceGetContext
// which will be used to get a pointer to the device context memory
// in a type safe manner.
//
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext)
DRIVER_INITIALIZE DriverEntry;
EVT_WDF_DRIVER_DEVICE_ADD PCIe_EvtDeviceAdd;
EVT_WDF_OBJECT_CONTEXT_CLEANUP PCIe_EvtDriverContextCleanup;
EVT_WDF_DEVICE_D0_ENTRY PCIe_EvtDeviceD0Entry;
EVT_WDF_DEVICE_D0_EXIT PCIe_EvtDeviceD0Exit;
EVT_WDF_DEVICE_PREPARE_HARDWARE PCIe_EvtDevicePrepareHardware;
EVT_WDF_DEVICE_RELEASE_HARDWARE PCIe_EvtDeviceReleaseHardware;
EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL PCIe_EvtIoDeviceControl;

KMESSAGE_SERVICE_ROUTINE PCIe_InterruptMessageService;
IO_DPC_ROUTINE PCIe_InterruptDpc;
EVT_WDF_PROGRAM_DMA EvtProgramDMA;

device.h頭文件在內核態下使用,主要聲明瞭兩部分內容:第一部分是interrupt和device上下文的結構體,這也可以看作整個程序的全局變量,通過interrupt或者device句柄就可以訪問到這兩個結構體的內容。第二部分是聲明瞭一些後續使用到的函數,例如EvtDeviceAdd、EvtIoDeviceControl等,可以根據自己代碼需求來選擇聲明哪些函數,我這裏所聲明的不一定都會使用到的。

2. public.h

/*++
Module Name:
	public.h
Abstract:
    This module contains the common declarations shared by driver
    and user applications.
Environment:
    user and kernel
--*/
//
// Define an Interface Guid so that apps can find the device and talk to it.
//
#include <initguid.h>

//GUID接口
DEFINE_GUID (GUID_DEVINTERFACE_PCIe,
    0x1789131a,0x3099,0x4ffc,0x8b,0x69,0x0a,0x88,0x0c,0x7c,0x5c,0xa6);
// {1789131a-3099-4ffc-8b69-0a880c7c5ca6}

//DeviceIoControl控制關鍵字
#define WDF_DMA CTL_CODE (FILE_DEVICE_UNKNOWN, 0x812, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)

public.h聲明瞭兩部分內容,它既提供給用戶態使用,也可以給內核態使用,第一部分是設備的GUID接口,在驅動程序裏創建接口後就可以給應用程序來打開設備,這個GUID號是利用模板創建驅動程序時自動生成的,後續我們不需要改,直接使用即可。
第二部分是DeviceIoControl控制關鍵字,應用程序可以通過DeviceIoControl函數來與KMDF通信,如何識別就是通過這個關鍵字來進行的,這裏我們示範了關鍵字的格式:關鍵字名稱爲WDF_DMA,CTL_CODE表明這是一個控制命令。後面括號內第一個參數爲設備類型,通常選擇默認的FILE_DEVICE_UNKNOWN;第二個參數從0x800開始,每多定義一個關鍵字可以加1;第三個參數爲驅動程序獲取應用程序數據緩衝區地址的方式,共有四種方式可以選擇,METHOD_BUFFERED、METHOD_IN_DIRECT、METHOD_OUT_DIRECT和MTETHOD_NEITHER,詳情可以查詢MSDN內的介紹 ;第四個參數用來設置文件讀寫權限,我們設置爲默認的FILE_ANY_ACCESSS即可。

3. queue.h

/*++
Module Name: queue.h
Abstract: This file contains the queue definitions.
Environment: Kernel-mode Driver Framework
--*/
EXTERN_C_START
//
// This is the context that can be placed per queue
// and would contain per queue information.
//
typedef struct _QUEUE_CONTEXT {
    ULONG PrivateDeviceData;  // just a placeholder
} QUEUE_CONTEXT, *PQUEUE_CONTEXT;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, QueueGetContext)
EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL PCIe_EvtIoDeviceControl;
EVT_WDF_IO_QUEUE_IO_STOP PCIe_EvtIoStop;

EXTERN_C_END

queue.h這一部分主要聲明下關於消息隊列相關的內容,主要申明下EvtIoDeviceControl和EvtIoStop函數,當然你也可以在device.h函數裏聲明,或者把這兩者合二爲一都行,或者就按默認值來不改動也可以。

4. driver.h

/*++

Module Name:
    driver.h
Abstract:
    This file contains the driver definitions.
Environment:
    Kernel-mode Driver Framework
--*/
#define INITGUID
//#pragma warning(disable:4200)
//#pragma warning(disable:4201)
//#pragma warning(disable:4214)
#include <ntddk.h>
#include <wdf.h>
#include <initguid.h>

#include "device.h"
#include "queue.h"
#include "trace.h"

5. trace.h

/*++
Module Name:
    Trace.h
Abstract:
    Header file for the debug tracing related function defintions and macros.
Environment:
    Kernel mode
--*/
//
// Define the tracing flags.
//
// Tracing GUID - 3d00abd6-9fbf-4eb2-9261-f51d58a3f2e8
//
#define WPP_CONTROL_GUIDS                                              \
    WPP_DEFINE_CONTROL_GUID(                                           \
        PCIeTraceGuid, (3d00abd6,9fbf,4eb2,9261,f51d58a3f2e8), \
                                                                            \
        WPP_DEFINE_BIT(MYDRIVER_ALL_INFO)                              \
        WPP_DEFINE_BIT(TRACE_DRIVER)                                   \
        WPP_DEFINE_BIT(TRACE_DEVICE)                                   \
        WPP_DEFINE_BIT(TRACE_QUEUE)                                    \
        )                             

#define WPP_FLAG_LEVEL_LOGGER(flag, level)                                  \
    WPP_LEVEL_LOGGER(flag)

#define WPP_FLAG_LEVEL_ENABLED(flag, level)                                 \
    (WPP_LEVEL_ENABLED(flag) &&                                             \
     WPP_CONTROL(WPP_BIT_ ## flag).Level >= level)

#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \
           WPP_LEVEL_LOGGER(flags)
               
#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \
           (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)
//           
// WPP orders static parameters before dynamic parameters. To support the Trace function
// defined below which sets FLAGS=MYDRIVER_ALL_INFO, a custom macro must be defined to
// reorder the arguments to what the .tpl configuration file expects.
//
#define WPP_RECORDER_FLAGS_LEVEL_ARGS(flags, lvl) WPP_RECORDER_LEVEL_FLAGS_ARGS(lvl, flags)
#define WPP_RECORDER_FLAGS_LEVEL_FILTER(flags, lvl) WPP_RECORDER_LEVEL_FLAGS_FILTER(lvl, flags)
//
// This comment block is scanned by the trace preprocessor to define our
// Trace function.
//
// begin_wpp config
// FUNC Trace{FLAGS=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...);
// FUNC TraceEvents(LEVEL, FLAGS, MSG, ...);
// end_wpp
//

driver.h就引用了一些其他頭文件,當然你可以將它和device.h等合併一起;trace.h用來做調試跟蹤問題的,保持默認狀態不改動就可以了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章