之前提到根據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用來做調試跟蹤問題的,保持默認狀態不改動就可以了。