PCI/PCIe介面卡Windows驅動程式(3)- 驅動程式代碼(標頭檔)

來源:互聯網
上載者:User

標籤:

在WDF的PCIe驅動程式中,共有四個.h檔案(Public.h  Driver.h  Device.h  Trace.h)。本文將分別對四個檔案原始碼進行詳細的解釋。

 Public.h

 1 #ifndef _USER_H 2 #define _USER_H 3 // 4 // Define an Interface Guid so that app can find the device and talk to it. 5 // 6 #include <initguid.h> 7 // {49FA63A7-C525-4409-8DD5-EFF37A7375F8} 8 DEFINE_GUID(GUID_DEVINTERFACE_Spw_PCIe, 9     0x49fa63a7, 0xc525, 0x4409, 0x8d, 0xd5, 0xef, 0xf3, 0x7a, 0x73, 0x75, 0xf8);10 #define Spw_PCIe_IOCTL_IN_BUFFERED CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)//the least value is 0x80011 #define Spw_PCIe_IOCTL_OUT_BUFFERED CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)12 #define Spw_PCIe_IOCTL_READ_PADDRESS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)13 #define Spw_PCIe_IOCTL_WRITE_OFFSETADDRESS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)14 #endif

代碼檔案名稱為Public,是因為這個檔案要被驅動程式和應用程式共同使用的。在第4行的注釋裡,寫明了本檔案的主要作用是為驅動程式和應用程式的通訊提供GUID介面。在Windows平台下實現對硬體裝置的控制,需要應用程式能夠與底層驅動進行通訊,應用程式與驅動通訊的設計過程中有兩個重要的概念,即GUID值和CTL_CODE宏。

GUID(Globally Unique Identifier)是微軟推出的通用唯一識別碼,通過使用某個特定的演算法(比如根據時間或地點等資訊)產生一組128位位元,來標識某一個實體,比如硬碟上的一張圖片。GUID廣泛應用於微軟的產品中,用於識別介面、檔案等對象。開發人員可以使用VS2013下的工具GUIDGen.exe產生GUID值,該GUID標識驅動程式,應用程式根據這個GUID值來找到對應的驅動程式。注意使用DEFINE_GUID宏,要包含initguid.h檔案,否則會報出無法識別的error。

I/O處理常式DeviceIoControl(這個常式將在下一篇文章中詳細介紹)的第二個參數dwIoControlCode就是由CTL_CODE宏定義的。CTL_CODE是一個用於建立一個唯一的32位系統I/O控制碼的宏,這個控制碼包括4部分組成:DeviceType(裝置類型,高16位(16-31位)),Access(訪問限制,14-15位),Function(功能2-13 位),Method(I/O訪問記憶體使用量方式)。CTL_CODE定義中有一個Method域,該域定義了驅動程式中擷取應用程式資料緩衝區地址的方式。

10-13行代碼為使用者自訂的4個I/O控制命令,分別為讀資料、寫資料、讀映射的BAR0的物理起始地址、寫位移地址(用來讀寫資料)。

第一個參數為裝置類型,通常為自訂的板卡選擇FILE_DEVICE_UNKNOWN;

注意,第二個數字要從0x800開始取值,之前的已經被微軟佔用;

第三個參數有四種選擇(METHOD_BUFFERED、METHOD_IN_DIRECT、METHOD_OUT_DIRECT、METHOD_NEITHER),buffered方式:I/O管理器會建立與應用程式資料緩衝區完全相同的系統緩衝區,驅動程式在這個緩衝區工作,由I/O管理器完成複製資料任務;direct方式:I/O管理器鎖定應用程式緩衝區的實體記憶體頁,並建立一個MDL(記憶體描述符表)來描述該頁,驅動程式將使用MDL工作;neither方式:I/O管理器把應用程式緩衝區的虛擬位址傳遞給驅動程式,一般不採用這種方式。

第四個參數用來設定檔案讀寫權限,有三種選擇(FILE_ANY_ACCESS、FILE_READ_ACCESS、FILE_WRITE_ACCESS),微軟官方的說法是“The FILE_ACCESS_ANY is generally the correct value.”,所以我們還是老實的選用FILE_ACCESS吧。

Driver.h

 1 #define INITGUID 2 #pragma warning(disable:4200)  // 3 #pragma warning(disable:4201)  // nameless struct/union 4 #pragma warning(disable:4214)  // bit field types other than int 5  6 #include <ntddk.h> 7 #include <wdf.h> 8  9 #include "Public.h"10 #include "device.h"11 #include "trace.h"

這個檔案將基於WDF的PCIe驅動程式所需要的標頭檔都包含在了一起,並且disable了一些警告,由於驅動程式的開發非常注意warnning的處理,VS2013下是預設有warnning的時候不通過編譯的,需要開發人員手動設定一下。對於一些無關痛癢的warnning,我們也可以通過預先處理的方式來disable它。

Device.h

 1 #include "public.h" 2  3 #define PCIE_WRITE_MEMORY_OFFSET 0x20000//memory1‘s offset address to BAR0 in FPGA  4 #define PCIE_READ_MEMORY_OFFSET 0x22000//memory2‘s offset address to BAR0 in FPGA 5  6 #define MAXNLEN   1024 //define the largest length 7 // 8 //device context is same as device extension in WDM 9 //10 typedef struct _DEVICE_CONTEXT11 {12     ULONG                Counter_i;//counter for WdfCmResourceListGetCount(ResourceListTranslated)13     PVOID                MemBaseAddress;//when i == 5,it gets BAR2 start virtual address14     PVOID                BAR0_VirtualAddress;//BAR0 start virtual address15     ULONG            PhysicalAddressRegister;//store the BAR0 start physical address16     ULONG                MemLength;//it records the length of menmory on hardware17     ULONG                OffsetAddressFromApp;//get offset address that is given by application18 } DEVICE_CONTEXT, *PDEVICE_CONTEXT;19 20 //21 // This macro will generate an inline function called DeviceGetContext22 // which will be used to get a pointer to the device context memory23 // in a type safe manner.24 //25 //WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, DeviceGetContext)26 WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext)//very important!27 28 //29 // WDFDRIVER Events including "EVT"30 //31 DRIVER_INITIALIZE DriverEntry;32 EVT_WDF_DRIVER_DEVICE_ADD Spw_PCIeEvtDeviceAdd;33 EVT_WDF_OBJECT_CONTEXT_CLEANUP Spw_PCIeEvtDriverContextCleanup;34 35 EVT_WDF_DEVICE_D0_ENTRY Spw_PCIeEvtDeviceD0Entry;36 EVT_WDF_DEVICE_D0_EXIT Spw_PCIeEvtDeviceD0Exit;37 EVT_WDF_DEVICE_PREPARE_HARDWARE Spw_PCIeEvtDevicePrepareHardware;38 EVT_WDF_DEVICE_RELEASE_HARDWARE Spw_PCIeEvtDeviceReleaseHardware;39 40 EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL Spw_PCIeEvtIoDeviceControl;

這個檔案定義了與裝置和驅動程式密切相關的一些東西,非常重要。

3-4行定義了兩個宏,即設定了兩塊記憶體在BAR0映射的位移地址0x20000和0x22000,這兩個值與PCIe硬體板卡有關。在讀寫操作時,BAR0的物理地址一定要加上位移地址,否則會因為寫到未知記憶體單元而造成藍屏等後果。

6行定義了最大傳輸的大小,在以後DMA操作中會用到。

10-18行定義了與裝置相關的變數,把這些變數參數封裝在一個結構體中,體現WDF中的一種“對象封裝”的思想。幾個參數分別表示資源計數器(記錄WDF架構分配給裝置的資源個數)、記錄BAR2的起始地址(當資源計數器 i == 0 時)、BAR0經過轉換後的虛擬位址(可被應用程式使用)、BAR0映射的起始地址(物理地址,與裝置管理員中所獲得結果相同)、記憶體大小、位移地址(由應用程式傳遞過來,供I/O讀取使用)。在WDF中這個結構體被叫做裝置上下文(DEVICE_CONTEXT),在WDM中叫做DEVICE_EXTENSION

26行的宏非常重要,具體作用將在下一篇介紹源檔案中詳細說明。

31-40行聲明了一些WDF事件回調常式,聲明後,我們可以直接使用自訂的回呼函數名,這些聲明的作用只起到開發人員方便編寫程式的作用。

DriverEntry為驅動程式入口函數;

Spw_PCIeEvtDeviceAdd為裝置添加函數,非常重要,要自己說三遍;

Spw_PCIeEvtDriverContextCleanup為資源清理函數,由於作業系統越來越智能,當裝置被拔出後,作業系統會自動回收一些資源,所以這個函數貌似在PCIe驅動裡並沒什麼卵用,即使我在這做了聲明,在下一篇介紹原始碼中,我們也會發現,它的函數定義也只“打了一個醬油”;

Spw_PCIeEvtDeviceD0Entry和Spw_PCIeEvtDeviceD0Exit是與電源管理相關的兩個函數,WDF已經將電源管理做了很好的封裝,一般不需要驅動程式開發人員在作處理,所以它們兩個也是“打醬油”的;

Spw_PCIeEvtDevicePrepareHardware和Spw_PCIeEvtDeviceReleaseHardware非常重要!!!自己說三遍,分別為裝置擷取資源和釋放資源;

Spw_PCIeEvtIoDeviceControl是實現應用程式與驅動程式通訊的函數,裡面規定了不同的控制碼實現不同的操作。

在這一部分,先對這幾個常式做簡要概述,詳細的解釋將會在下一篇給出。

還有最後一個標頭檔,用來調試和跟蹤,由於我也沒用到調試和跟蹤驅動程式,所以直接給出VS2013+WDK8.1自動產生的程式碼檔案,不做解釋了。

trace.h

 1 /*++ 2  3 Module Name: 4  5     Trace.h 6  7 Abstract: 8  9     Header file for the debug tracing related function defintions and macros.10 11 Environment:12 13     Kernel mode14 15 --*/16 17 //18 // Define the tracing flags.19 //20 // Tracing GUID - ad7b826c-e901-457e-a559-a221404519c621 //22 23 #define WPP_CONTROL_GUIDS                                              24     WPP_DEFINE_CONTROL_GUID(                                           25         Spw_PCIeTraceGuid, (ad7b826c,e901,457e,a559,a221404519c6), 26                                                                             27         WPP_DEFINE_BIT(MYDRIVER_ALL_INFO)                              28         WPP_DEFINE_BIT(TRACE_DRIVER)                                   29         WPP_DEFINE_BIT(TRACE_DEVICE)                                   30         WPP_DEFINE_BIT(TRACE_QUEUE)                                    31         )                             32 33 #define WPP_FLAG_LEVEL_LOGGER(flag, level)                                  34     WPP_LEVEL_LOGGER(flag)35 36 #define WPP_FLAG_LEVEL_ENABLED(flag, level)                                 37     (WPP_LEVEL_ENABLED(flag) &&                                             38      WPP_CONTROL(WPP_BIT_ ## flag).Level >= level)39 40 #define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) 41            WPP_LEVEL_LOGGER(flags)42                43 #define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) 44            (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)45 46 //47 // This comment block is scanned by the trace preprocessor to define our48 // Trace function.49 //50 // begin_wpp config51 // FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...);52 // FUNC TraceEvents(LEVEL, FLAGS, MSG, ...);53 // end_wpp54 //

 

PCI/PCIe介面卡Windows驅動程式(3)- 驅動程式代碼(標頭檔)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.