基于DM6446的Windows CE顯示驅(qū)動設(shè)計實現(xiàn)
WINCE 的顯示驅(qū)動程序如圖3 所示,由DDI(Display Device Interface) 和HAL(Hardware Abstraction Layer)兩部分組成。
HAL 主要為DirectDraw 服務(wù),只需要在驅(qū)動中向GDI 導(dǎo)出HALinit()即可,因此本文研究的重點是DDI 部分,即通常的顯示驅(qū)動部分。由于在顯示中存在大量硬件無關(guān)操作,顯示驅(qū)動通常采用分層結(jié)構(gòu),采用分層結(jié)構(gòu)有助于降低代碼復(fù)雜度提高代碼效率,其中MDD 層實現(xiàn)缺省的繪圖功能,由微軟提供的圖形原語引擎模塊(GPE , GraphicsPrimitive Engine)組成,如果要支持Directdraw,則要使用DDGPE模塊;而PDD層與硬件具體相關(guān),則是顯示驅(qū)動的主要內(nèi)容,一般由OEM 廠商或獨立硬件商實現(xiàn)。
WINCE 上層程序通過一組(約20 多個)顯示驅(qū)動接口函數(shù)同顯示驅(qū)動打交道,因此顯示設(shè)備驅(qū)動程序必須實現(xiàn)這些顯示驅(qū)動接口函數(shù),GDI 通過調(diào)用這組函數(shù)初始化顯示設(shè)備驅(qū)動程序和將圖形輸出到顯示設(shè)備上。由于采用分層結(jié)構(gòu),顯示驅(qū)動由MDD 層負責(zé)對上層的GWES模塊提供函數(shù)接口,但是這些函數(shù)并不是直接提供出來的,實際上只是通過一個DrvEnabLEDriver( )函數(shù)來完成的。作為DDI部分的一個導(dǎo)出函數(shù),DrvEnableDriver會在GDI初始化時被調(diào)用。
DrvEnableDriver 在MDD 層中沒有實現(xiàn),所以需要在PDD層中定義,主要代碼如下:
BOOL APIENTRY DrvEnableDriver
?。║LONG engineVersion,ULONG cj,DRVENABLEDATA *data,PENGCALLBACKS engineCallbacks)
{
BOOL fOk = FALSE;
if(gszBaseInstance[0] != 0)
{
fOk =
GPEEnableDriver(engineVersion, cj, data,engineCallbacks);
}
return fOk;
}
這里GPEEnableDriver 是微軟預(yù)先編寫的一個MDD層函數(shù)。該函數(shù)位于源文件ddi_if.cpp里, 因此我們只需簡單調(diào)用就可以了。
GPEEnableDriver 函數(shù)通過執(zhí)行語句memcpy(pded, pDrvFn, cj) 將一個預(yù)先定義好的DRVENABLEDATA 結(jié)構(gòu)體變量pDrvFn 的地址傳給一個上層結(jié)構(gòu)體指針pded.而在結(jié)構(gòu)體變量pDrvFn 中預(yù)先已包含了20 多個底層顯示驅(qū)動函數(shù)指針,這樣GWES 就可以通過這些指針操縱底層顯示硬件了。例如應(yīng)用程序想創(chuàng)建一個到圖形設(shè)備的連接時可以通過GWES.exe 調(diào)用CreateDC(),而該函數(shù)會調(diào)用DrvEnablePDEV()函數(shù),當(dāng)應(yīng)用程序需要從顯示設(shè)備上斷開時則會調(diào)用DeleteDC() , DeleteDC() 則會調(diào)用DrvDisablePDEV() .DrvEnablePDEV() 和DrvDisablePDEV()就屬于這20 多個被GWES 調(diào)用的底層顯示驅(qū)動函數(shù)。
以上這些底層顯示驅(qū)動函數(shù)大部分跟硬件密切相關(guān),因此需要進一步調(diào)用PDD層函數(shù)。由于不同的顯示硬件特點都不盡相同,因此勢必造成PDD層暴露給MDD層的接口函數(shù)各不相同,這樣勢必會增加代碼的復(fù)雜性。為此微軟設(shè)計了一個GPE類,一個GPE類實例代表一個顯示設(shè)備硬件,其所有數(shù)據(jù)成員都對應(yīng)于一個顯示設(shè)備的屬性數(shù)據(jù),并設(shè)計了多個成員函數(shù)用以操縱這些數(shù)據(jù)成員??紤]到硬件的多樣性,GPE 類的有些函數(shù)并為全部實現(xiàn),或為空函數(shù)或者虛函數(shù),需要其子類實現(xiàn)或者覆蓋。因此不能直接定義GPE類型的變量,只能以先構(gòu)造GPE類為父類的繼承類,然后才能定義實例。
MDD 層的底層顯示驅(qū)動函數(shù)通過實例化一個GPE 繼承類的實例就可以直接調(diào)用PDD 層代碼了,這一般是通過SafeGetGPE 函數(shù)來實現(xiàn)的。
SafeGetGPE 由微軟設(shè)計實現(xiàn),位于MDD 層的ddi_if.cpp,一般無須改動。在SafeGetGPE 函數(shù)中調(diào)用了GetGPE 函數(shù),這個函數(shù)MDD 層沒有,需要我們在PDD 層實現(xiàn)。GetGPE 函數(shù)可以簡單實現(xiàn)如下:
這里代碼利用了C++的多態(tài)性和繼承性。在C++中父類或更上一級的類的指針可以引用繼承類中相同的變量,并且對數(shù)據(jù)成員和成員函數(shù)的引用以繼承類的實現(xiàn)或定義優(yōu)先。這樣在MDD 中使用指針gGPE 所指向的數(shù)據(jù)或函數(shù)時得到的都是類DM6446VPBE 的成員變量和成員函數(shù)。由此可以看出GetGPE 函數(shù)是顯示驅(qū)動中聯(lián)系MDD和PDD 的橋梁,通過它MDD 可以直接調(diào)用PDD的代碼。
3.3 GPE繼承類的實現(xiàn)
通過上面的分析可以看出,WINCE 的顯示驅(qū)動主要部分在于PDD 層,而PDD 層除了向MDD導(dǎo)出一些接口函數(shù)外如DrvEnableDriver,其余主要是構(gòu)建一個GPE 或是DDGPE 的子類(如果要實現(xiàn)DirectDraw)。由于DDGPE 的父類是GPE,因此無論是DDGPE 還是GPE 的子類差別并不大。
構(gòu)建一個GPE 的子類其實就是實現(xiàn)一個有具體數(shù)據(jù)和函數(shù)并且具體準(zhǔn)確的反映了特定顯示設(shè)備硬件屬性的GPE 類的子類,并通過該子類去實例化一個對象。
一個GPE 子類通常需要重載GPE 類中的同名函數(shù)和實現(xiàn)GPE中的虛函數(shù)以及子類獨有的一些函數(shù)如初始化構(gòu)造函數(shù)[3].子類構(gòu)造函數(shù)主要是初始化硬件和子類成員變量,譬如視頻處理時鐘寄存器設(shè)置,OSD Window 的大小和坐標(biāo),VENC 的輸出模式,以及子類的成員變量如顯示寬度m_nScreenWidth 和顯示高度m_nScreenHeight 等等。子類要GPE 類中的函數(shù)包括GPE 的空函數(shù)和虛函數(shù),這些函數(shù)實際上就是MDD 調(diào)用PDD 層驅(qū)動中需要實現(xiàn)的函數(shù),主要函數(shù)包括:SetMode(),用于設(shè)置一個顯示設(shè)備能夠支持的顯示模式;GetPhysicalVideoMemory(),用于獲取顯示設(shè)備內(nèi)存的系統(tǒng)基地址和內(nèi)存大??; 以及AllocSurface() SetPointerShape()BltComplete() SetPalette()等。這些函數(shù)具體可以參考微軟提供的驅(qū)動示例代碼,它們位于Public CommonOAKDriversDisplay 目錄下[ 1].除了這些函數(shù)外PDD 還需實現(xiàn)一個MDD 層函數(shù)DrvGetMask,但比較簡單,只需要定義一個全局數(shù)組gBitMasks,該數(shù)組內(nèi)容是代表RGB 的所占的位域,與具體的顯示硬件有關(guān)。
3.4 驅(qū)動程序與應(yīng)用程序的通信
不同于其他流式驅(qū)動可以由應(yīng)用程序直接調(diào)用,顯示驅(qū)動由操作系統(tǒng)調(diào)用,應(yīng)用程序不能直接訪問。具體來說,應(yīng)用程序不是通過CreateFile等這些文件系統(tǒng)API接口來訪問,而是通過GDI接口間接訪問。對于GDI調(diào)用而言,對應(yīng)的后臺服務(wù)進程是GWES.exe,然后GWES.exe再進一步調(diào)用MDD和PDD函數(shù),即WINCE底層顯示驅(qū)動。例如如果要畫一個矩形,則可以調(diào)用SetRect、GetDC和FillRect等函數(shù)在圖形界面上面進行顯示,而要在圖形界面上輸出一段文字只需調(diào)用DrawText函數(shù)就可以了,至于顯示驅(qū)動調(diào)用就可以交給GDI就可以了。
4 結(jié)束語
本文闡述和分析了DM6446 顯示硬件原理和Windows CE驅(qū)動模型,剖析了顯示驅(qū)動程序的工作原理和顯示工作流程。本文的創(chuàng)新點在于完整的闡述了WINCE顯示驅(qū)動程序在DM6446上的設(shè)計實現(xiàn),而以往WINCE 的顯示驅(qū)動都是基于LCD,因此本文對編寫同類驅(qū)動程序的開發(fā)人員將有一定的參考價值。WINCE啟動運行后,圖形界面運行穩(wěn)定,并可支持Windows CE下的應(yīng)用軟件運行,表明驅(qū)動程序設(shè)計良好。
評論