上層和驅動通訊
用deviceiocontrol函式,這是乙個win32 api,在sdk中定義。這個函式都會產生乙個irp_mj_device_control包,如果驅動中註冊過相應的例程,那麼這個包就會引發該例程的工作。如果是驅動和驅動間的通訊,那麼用iobuilddevicecontrolrequest函式,該函式在ddk中定義,會產生乙個irp_internal_device_control包,並引發相應的例程。這兩個irp包中都有乙個非常重要的結構叫ioctl(io control code),用於指定通訊中的各類細節。該資料結構是乙個32位元的資料塊,有6個區域,每個區域包含一類資訊。ioctl的結構如下圖所示
ddk中有乙個ctl_code巨集,用這個巨集我們可以很方便的定義ioctl。不管是irp_mj_device_control還是irp_internal_device_control包,ioctl都用如下形式定義:
#define ioctl_device_function ctl_code(devicetype, function, method, access)
devicetype:裝置型別,和device_object結構中的devicetype必須一致。注意:0x8000以下的數字被微軟占用了。
function code:功能**,可以自定義,用來區分操作型別。注意:0x800以下的數字被微軟占用了。
method:io緩衝型別,有method_buffered,method_in_direct,method_out_direct,method_neither四種型別。
method_buffered表明輸入輸出都用系統緩衝,這種策略下輸入輸出指向的是同乙個記憶體塊,該記憶體塊有io manager管理。輸入的時候把資料拷貝到緩衝中,然後緩衝再拷貝到驅動;輸出的時候資料拷貝到緩衝中,然後緩衝拷貝到使用者空間。由於用的是同一塊緩衝,所以呼叫者自己得管理好裡面的資料,防止弄混。緩衝區位址存放在irp.associatedirp.systembuffer中,輸入資料大小為parameter.deviceiocontrol.inputbufferlength,輸出資料大小為parameter.deviceiocontrol.outputbufferlength,兩者都在io_stack_location結構中。
method_in_direct表明輸出用緩衝,輸入用直接io。這種策略下輸出和上面的方法一致,而輸入則是直接訪問指定的記憶體區域,不通過緩衝。iomanager先把輸入資料的記憶體塊鎖定,然後把位址存放在irp.mdladdress中。輸入輸出資料塊的大小和上面一致。
method_out_direct表明輸入用緩衝,輸出直接io。io manager把輸出資料的記憶體快鎖定,存放在irp.mdladdress中,驅動直接通過該位址訪問資料,輸入資料通過系統緩衝,存放在irp.associatedirp.systembuffer中。輸入輸出資料塊的大小和上面一致。
method_neither表明輸入輸出都不用緩衝,i/o manager把呼叫者的輸入緩衝區的位址放到irp當前i/o堆疊單元的parameters.devi ceiocontrol.typeinputbuffer域中,把輸出緩衝 區的位址存放到irp的userbuffer域中。這兩個位址都是使用者空間地 址。
從上面的說明可以看出,在執行緩衝i/o時,i/o管理器將在非份頁池 中分配記憶體,如果呼叫者的緩衝區比較大時,分配的非份頁池也將 比較大。非份頁池是系統比較寶貴的資源,因此,如果呼叫者的緩 沖區比較大時,我們一般採用直接i/o的方式(例如磁碟讀寫請求等), 這樣不僅節省系統資源,另一方面由於省去了i/o管理器在系統緩衝 區和呼叫者緩衝區之間的資料拷貝,也提高了效率,這對存在大量 資料傳送的驅動程式尤其明顯。不過需要注意的是,直接io要求驅動和ioctl的發起者執行在同乙個執行緒裡。
access:指明呼叫者的訪問許可權,有file_any_access,file_read_data,file_write_data三個選項可選。file_any_access表明使用者擁有所有的許可權,file_read_data表明許可權為唯讀,file_write_data表明許可權為可寫。file_write_data | file_read_data表明許可權為可讀可寫,但還沒達到file_any_access的許可權。
使用者定義ioctl時要注意以下幾條原則:
1. functioncode總是定義成0x800以上的數字,因為0x800以下的數字被微軟占用了。
2. 仔細考慮訪問許可權,如果指定了你不具備的許可權,那麼io manager會忽略ioctl
3. 仔細考慮要訪問的記憶體區域,如果去讀寫乙個關鍵記憶體,那麼系統會重啟
驅動內部執行ioctl時要注意以下幾條原則:
1. 接收到ioctl時,要先檢查整個32位元的資料完整性
2. 用iovalidatedeviceiocontrolaccess檢查訪問許可權是否有效
3. 嚴格遵照parameter.deviceiocontrol.inputbufferlength和parameter.deviceiocontrol.outputbufferlength指定的大小訪問輸入輸出區域,否則系統會重啟
4. 驅動中申請一塊記憶體後,總是先用rtlzeromemory清空區域
5. 直接io策略中,用mmgetsystemaddressformdlsafe獲取相應記憶體區域時,要判斷是否為null
6. 直接io中,用probeforread 和probeforwrite檢查記憶體是否可以訪問。
windows nt 4.0 ddk (可通過 msdn professional 成員) 說明如何執行此對映中沒有示例 (mapmem)。 下面是大綱方法是:
1.獲取轉換實體地址的介面卡記憶體 (haltranslatebusaddress)。
2.開啟到物理記憶體裝置 device\physicalmemory 控制代碼 (zwopensection) 部分。
3.引用物件控制代碼 (obreferenceobjectbyhandle) 以防止它被刪除。
4.對映 (zwmapviewofsection) 記憶體。
僅從 zwmapviewofsection 得到虛擬位址對映其程序的上下文中有效。 如果要訪問您駕駛延遲過程呼叫 (dpc) 中記憶體或中斷服務例程 (isr), 在任意程序上下文, 執行您應該還對映記憶體系統位址空間 (使用下方法) 中。 取消對映 (zwunmapviewofsection) 在同一記憶體程序上下文, 對映之前退出。
//此方法說明如何對映記憶體程序使用者位址空間和系統程序位址空間中。
1.獲取轉換實體地址的介面卡記憶體 (haltranslatebusaddress)。
2.
systemvirtualaddress = mmmapiospace(physicaladdress, sizeofmemory,3.分配乙個 mdl:cacheenable);
mdl = ioallocatemdl(systemvirtualaddress, sizeofmemory, false, false,4.生成 mdl 來描述記憶體頁:null);
mmbuildmdlfornonpagedpool(mdl);5.對映到程序記憶體空間使用者是使用 mmmaplockedpages。 因為有處於一致之間此函式返回值是 windows nt sp 4 以前版本 sp 和釋放, 使用下列語句以使此**與所有版本的 windowsnt 相容:
uservirtualaddress = (pvoid)(((ulong)page_align(mmmaplockedpages(mdl,mode))) + mmge***lbyteoffset(mdl));
mmunmapiospace(systemvirtualaddress, sizeofmemory);
mmunmaplockedpages(uservirtualaddress, mdl);finally, free the mdl by calling:
iofreemdl(mdl);
WinCE 控制面板和驅動通訊
2.在驅動執行緒內部的死迴圈體呼叫waitforsingleobject 函式進行等待 dword winapi soclcd mybacklightchangethreadproc pvoid parg closehandle hevent return 0 3.接下來,我們來看看控制面板如何傳送...
WinCE 控制面板和驅動通訊
驅動初始化函式 mydriver myinit 2.在驅動執行緒內部的死迴圈體呼叫waitforsingleobject 函式進行等待 dword winapi soclcd mybacklightchangethreadproc pvoid parg closehandle hevent retu...
WDF驅動和3環通訊
ifndef ctl code h 89749 9961731 define ctl code h 89749 9961731 define ctl buffered ctl code file device unknown,0x850,method buffered,file any access...