??很多寫Windows Device Driver的開發人員基本上都是使用Windows DDK進行開發的。但是,現在也有不少人都開始借助一些輔助工具。筆者去年開始接觸到riverStudio,發現它真的是一個不錯的開發工具,不僅寫代碼的時候思路清晰,而且和DDK的結合很好。
????當然,也有很多人覺得用DriverStudio不夠正宗,或者說不能很好的理解Windows Device Driver的架構。我感覺這就有點像MFC和SDK的關系,關于這個問題在很多地方都有爭論,比如在萬千新聞組上,就討論了將近2個月。每個人都有自己的最愛,都有自己的習慣,只要你能把事情做好,我想用什么方法應該都是一樣的。如果你已經習慣了用DDK開發,那完全還可以繼續用下去;如果你覺得DriverStudio不錯,那嘗試用一個可以給你按照OOP概念來編程的工具有什么不好呢?
在驅動開發網上,經常看到有人詢問一些關于DriverStudio的使用的問題。我正好很有幸用它作了幾個驅動程序,包括VXD, KMD和WDM,稍微有點心得,因此想寫下來給大家作一個小小的參考。如果其中有錯誤,歡迎大家給我指出,謝謝。
下面我就介紹一下用DriverStudio開發一個USB驅動程序的過程。這個USB設備有3個雙向端點,每個端點的配置如下:
EP 類型 地址 buffer(Bytes)
0 IN/OUT Control 0x80/0x00 16/16
1 IN/OUT Bulk 0x81/0x01 16/16
2 IN/OUT Bulk 0x82/0x02 64/64
我們的驅動程序需要實現的功能就是控制設備上的LED燈的亮和滅,以及通過Endpoint 2對設備進行讀寫。
由于DriveStudio由幾個部分組成,我們寫這個驅動程序只要用到DriverWorks,因此下面我們就簡稱它為DW。在這里,我們假定讀者已經正確的安裝了DW,并且已經編譯好了各個庫文件。
1. 首先,我們通過快捷方式“Setup DDK and Start MSVC“來啟動VC IDE。這個快捷方式所指向的程序,會進行一些必要的設置,然后再啟動VC IDE,這樣我們的程序就可以使用DDK和DW的頭文件和庫了。
2. 從VC IDE的菜單"DriverStudio"中選擇"DriverWizard", 在如圖1所示的對話框中, 寫上項目名稱. 在這里, 我們將這個項目稱為: TEST, 所在的目錄為D:\TEST. 然后點按鈕"Next >".

圖1
3. 在接下來的這個對話框中(如圖2), 我們需要選擇驅動程序的類型. 由于USB設備驅動程序是WDM類型的, 所以我們選擇第二項并且點按鈕"Next >".
 圖2
4. 在第3個對話框中(如圖3), 選擇我們的驅動程序所操作的總線類型. 這里, 我們選擇USB. 在USB Vendor ID和USB Product ID中填入USB設備的VID和PID. 假定我們的USB設備的VID和PID分別是16進制的0471和1801. 然后點按鈕"Next >". 關于VID和PID的規定請參考USB-IF的規范.

圖3
5. 在接下來的對話框中(如圖4), 我們需要加入Endpoint 1和Endpoint 2的定義. 由于在USB中規定Endpoint 0是必須存在的, 所以我們不需要對Endpoint 0進行定義. 點"Add..."按鈕, 彈出一個如圖5所示的對話框. 我們將它修改成如圖6所示. 其中, 按照USB的規定, 對于端點, 它的地址是1; 按照前面說明的設備的特點, Endpoint 1的最大的包大小為16字節, 因此在"Max Transer Size"中填入16; Endpoint Name可以通過"Suggest Name"得到. 按照這些原則, 繼續設置其他的配置, 以使對話框4變成如圖7所示. 接下來, 繼續按"Next >"按鈕.
 圖4
 圖5

圖6
 圖7
6. 在如圖8所示的對話框中, 可以填入我們需要的Driver Class的名字和文件名. 一般我們不需要更改. 繼續按"Next >"按鈕.
 圖8
7. 在如圖9所示的對話框中, 因為不需要給其他的驅動程序提供接口, 也不需要提供Flush功能, 所以不需要任何修改, 直接按"Next >"按鈕.

圖9
8. 在如圖10所示的對話框中, 我們選擇給端點2產生BULK Read的代碼, 并且按"Next >"按鈕. DW會給我們產生一套對端點2進行讀的代碼, 不用修改, 就可以直接使用.
 圖10
9. 在如圖11所示的對話框中, 我們選擇給端點2產生BULK Write的代碼, 并且按"Next "按鈕. 這樣, DW也會給我們產生一套對端點2進行寫的代碼, 不用修改, 就可以直接使用.
 圖11
10. 對于如圖12的對話框, 我們直接按"Next >"按鈕. 這里是設置是否要將I/O請求排隊, 在這里, 我們不需要排隊.
 圖12
11. 在如圖13所示的對話框中, 我們不需要創建任何注冊表項, 所以直接按"Next >"按鈕.

圖13
12. 如圖14所示的對話框, 是讓我們設置一些驅動程序的屬性, 比如接口, 緩沖區之類的. 一般的都可以使用缺省設置. 繼續按"Next >"按鈕.

圖14
13. 在如圖15所示的對話框中, 是讓我們給驅動程序增加一些IOCTL接口. 我們只增加一個如圖16所示的IOCTL來控制USB設備的LED燈. 然后按"Next >"按鈕.
 圖15

圖16
14. 在最后一個如圖17所示的對話框中, 可以設置一些驅動程序的屬性, 產生一個console測試程序. 按下"Finish"按鈕, 就結束了Wizard.
 圖17
這樣, 我們就創建好了一個基本的驅動程序, 下面來看看還要做哪些工作才可以和我們的設備以及上層的應用程序通訊.
把函數NTSTATUS TESTDevice::TEST_IOCTL_LED_Handler(KIrp I)改成如下面的樣子:
NTSTATUS TESTDevice::TEST_IOCTL_LED_Handler(KIrp I)
{
NTSTATUS status = STATUS_INVALID_PARAMETER;
t << "Entering TESTDevice::TEST_IOCTL_LED_Handler, " << I << EOL;
__try
{
// TODO: Verify that the input parameters are correct
// If not, return STATUS_INVALID_PARAMETER
if(I.IoctlOutputBufferSize() || !I.IoctlBuffer() ||
(I.IoctlInputBufferSize() != sizeof(UCHAR)))
__leave;
// TODO: Handle the the ZBUARD_IOCTL_LED_ON request, or
// defer the processing of the IRP (i.e. by queuing) and set
// status to STATUS_PENDING.
PURB pUrb = m_Lower.BuildVendorRequest(
NULL, // transfer buffer
0, // transfer buffer size
0, // request reserved bits
(UCHAR)(*(PUCHAR)I.IoctlBuffer()), // request. 1 = LED_ON, 0 = LED_OFF
0 // Value
);
// transmit
status = m_Lower.SubmitUrb(pUrb, NULL, NULL, 5000L);
}
__finally
{
// TODO: Assuming that the request was handled here. Set I.Information
// to indicate how much data to copy back to the user.
I.Information() = 0;
I.Status() = status;
}
return status;
}
這個函數是控制LED燈的,它是通過USB Vendor Request來向設備傳送的。其中,request=1的時候表示讓LED亮,request=0的時候讓LED滅。它是通過DeviceIoControl由上層應用程序傳下來。
再看看讀寫部分,經過檢查NTSTATUS TESTDevice::Read(KIrp I)和NTSTATUS TESTDevice::Write(KIrp I)可以發現,DW已經給我們寫好了讀寫的代碼,我們可以直接使用了。這些代碼就是在上面的第8和第9步中產生的代碼。
最后,修改編譯一下DriverStudio產生的測試程序Test_TEST程序,我們就可以通過命令行來測試我們的驅動程序了。對于LED的控制,我們可以直觀的在設備上看到,但對于讀寫的操作就需要和firmware程序配合,這已經超出了本文的范圍,不在這里討論了。
通過上面的講解,我們可以看到有了DriverStudio,就可以快速的產生一個驅動程序,然后在里面作一些小的改動就可以使用了。即使是寫一個比較復雜的USB驅動程序,我們也可以不用管一些系統的IRP處理,只要專注于我們自己的特定應用就可以了。而且它把一個驅動程序概括成幾個類的概念,并且DW還附帶有一些很有用的STL類,在VC IDE里面有了一個很清晰直觀的表示。這樣,對一些從上層應用轉向驅動程序的開發人員,或者一些對C++/OOP很熟悉但不太了解系統內核的開發人員,都比較容易上手。即使對于推崇直接用DDK編程的人來說,通過閱讀DriverStudio附帶的源代碼,也可以對驅動程序的開發有一個更加深入的了解。 |