Windows CE LCD Driver

来源:互联网 发布:大数据专业网站有哪些 编辑:程序博客网 时间:2024/05/14 05:28

     wince的显示驱动和普通的设备驱动不一样.普通的设备驱动是由设备管理器device.exe加载和管理的;而显示驱动是由GWES.exe加载和管理的,类似的由GWES加载管理的还有键盘鼠标,触摸屏,打印机等驱动,这些叫本地驱动(内置驱动).所以,显示驱动ddi就不是常见设备驱动的ddi(流接口ddi).更具体说,它不是通过CreateFile这些文件系统api接口来访问.而是通过GDI接口,熟悉win32应用编程的会记起,GDI就是CreateDC,ReleaseDC等等这些api,可以在wingdi.h中找到这些接口.

 

      一般的,显示驱动是分层实现的,mdd层一般会使用微软提供的GPE模块.如果要支持旋转,使用GPErotate,如果要支持ddraw,使用DDGPE模块.事实上,对wince5,GPErotate已经合并到GPE里面了,typedef GPE GPErotate.而DDGPE也是从GPE继承过来的类.在一些驱动中ddraw和rotate是不能同时使用的

 

    GPE是一个简单的图形引擎.首先这是一个类,其次从显示驱动分层上说,使用GPE作为上层mdd,可以节省工作,因为它处理了和上层的接口,并且软件方式模拟了一些图形功能.上层GDI接口,提供给GWES调用的接口一共大概20几个函数.GWES通过以下DDI和显示驱动交互,并向上提供GDI接口.
 
DrvAnyBlt                 有扩展或透明位块传送(bit block transfers)
DrvBitBlt                 有剪切和屏蔽的通常位块传送
DrvConstrostControl       允许软件、硬件对照调整
DrvCopyBits               发送GDI设计的打印段到打印驱动程序
DrvCreateDeviceBitmap     设计和管理位图

DrvDeleteDeviceBitmap     删除设计位图
DrvDisableDriver          通知驱动程序GDI不再需要它,并准备卸载它
DrvDisablePDEV            通知驱动程序GDI不再需要特殊打印或显示设备
DrvDisableSurface         通知驱动程序GDI不再需要特殊绘制表面
DrvEnableDriver           由驱动程序输出初始记录,为GDI的DDI函数返回指针
DrvEnablePDEV             为GDI返回一个PDEV,它是一个物理显示设备的逻辑表示
DrvEnableSurface          设计一个绘制界面,并把它与PDEV相连
DrvEndDoc                 发送任何所需的完成打印文件控制信息
DrvFillPath               用毛刷填充路径
DrvGetMasks               为目前显示设备模式获取颜色屏蔽
DrvGetModes               列举、显示设备支持的显示模式
DrvMovePointer            移动指针,保证GDI不干涉
DrvPaint                  用毛刷漆出一个特定区
DrvPowerHandler           调用处理、上电、掉电通知
DrvAweryFont              获得字体公制信息
DrvRealizeBrush           创建由GDI指定参数毛刷
DrvRealizeColor           把一个RGB颜色,映射到由设备支持最可能获得颜色
DrvSetPalette             设置显示设备调色盘
DrvSetPointershape        对光标设置新形状并更新显示
DrvStareDoc               发送任意的开始打印文件信息
DrvStartPage              发送任意的打印新页的信息
DrvStrokePath             删除路径
DrvTransparentBlt         透明位块传送
DrvUnrealizeColor         将显示设备制式的颜色映成RGB值


但事实上,以上接口并非直接由显示驱动公开给GWES的.显示驱动只公开了一个接口DrvEnableDriver(),在这个接口中导出其他接口,具体的做法如下.
BOOL
APIENTRY
GPEEnableDriver(
    ULONG           iEngineVersion,
    ULONG           cj,
    DRVENABLEDATA * pded,
    PENGCALLBACKS   pEngCallbacks)


GWES调用DrvEnableDriver(),而DrvEnableDriver()函数调用上面的GPEEnableDriver函数,其中第三个参数就是返回的其他接口的函数指针.在ddi_if.c中同时定义了全局函数指针数组如下:
const DRVENABLEDATA pDrvFn = {
    {   DrvEnablePDEV           },
    {   DrvDisablePDEV          },
     省略
    {   NULL /* DrvEndDoc    */ },
    {   NULL /* DrvStartDoc  */ },
    {   NULL /* DrvStartPage */ },
    {   DrvEscape               }
};


如此,上层获得下层的函数指针pded.即获得了所有接口函数的指针.此外,第4个参数pEngCallbacks是一个回调函数的指针入口,是上层提供给下层的回调函数.是系统提供给显示驱动调用的.它具体包括下面这些:
BRVSHOBJ 代表一个执行用实线或网格删除填充操作的毛刷
BRVSHOBJ_pvAllocRbrush 为毛刷分配内存
BRUSHOBJ_pvGetRbrush 为特定毛刷返回指针
CLIPOBJ 代表剪切区结构
CLIPOBJ-bEnum 从剪切区,列举剪切矩形的函数
CLIPOBJ-cEnumStart 为列举剪切区的剪切矩形设置参数
EngcreateDericeBitmap 使GDI对设备位图进行处理
EngCreateDeviceBitmap 请求GDI创建一个位图,并返回句柄.
EngCreateDeviceSurFace 通过GDI创建一个显示驱动程序管理的设备界面
EngCreatePalette 请求GDI创建一个调色板.
EngDeleteSurface 通知GDI显示驱动程序不再需要设备界面
PALOBJ-cGetColors 将颜色复制到调色板上
PATHDAT 存储部分绘制路径的结构
PATHOBJ-bEenum 由绘制路径中列举PATHDATA记录
PATHOBJ-vEnumStart 一个绘制路径列举它的线性部分
PATHOBJ-vGetBounds 返回绘制路径的有限制矩形区
(XLATEOBJ 用来在调色板之间传送色彩)
XLATEOBJ-cGetPalette 由指定的调色盘返回颜色.

 

用户使用GDI, 如CreateDC, ReleaseDC这样的api和WinCE的图形系统交互. GDI并不是显示驱动, GDI位于显示驱动上层, 它和显示驱动通过DDI接口交互.DDI既是设备驱动接口Device Driver Interface, 也是显示驱动接口Display Driver Interface.以前分析过, DDI一共20几个函数.但不是全部公开函数指针给GDI, 而是透过唯一公开的DrvEnableDriver()来传递这所有的DDI函数指针,并且从GDI获得回调接口.写个伪代码会是这样的:
BOOL DrvEnableDriver(ULONG iEngineVersion,
ULONG cj,
DRVENABLEDATA *pded, //
PENGCALLBACKS pEngCAllbacks) // gdi提供的回调函数
{
    保存回调函数指针,供以后使用.
    把DDI的函数指针数组赋值给第三个参数pded. 这样GDI就得到了DDI接口;
}

GDI已经获得了和显示驱动的接口, 此后会透过DDI接口传递下来,所以显示驱动要做的就是实现这所有的DDI接口函数. 在public/common/oak/drivers/display/gpe下面有一个ddi_if.cpp的源码文件, 就是实现DDI接口. 但在这里没有DrvEnableDriver, 所以设计显示驱动, 必须完成并公开一个DrvEnableDriver接口函数, 并链接这个ddi_if.cpp, 把里面其他ddi接口指针传递给GDI, 实际上. 只要直接调用ddi_if.cpp中的GPEEnableDriver函数, 它替你完成了这个. 因此在你的显示驱动将会见到如下代码:
BOOL APIENTRY DrvEnableDriver(
ULONG engineVersion,
ULONG cj,
DRVENABLEDATA * data,
PENGCALLBACKS engineCallbacks
)
{
    return GPEEnableDriver(engineVersion, cj, data, engineCallbacks);
}
 
使用ddi_if.cpp来完成一个显示驱动. 还需要给ddi_if.cpp提供这些接口:
AllocConverters
FreeConverters
GetGammaValue
SetGammaValue
GetGPE
DrvGetMask


GetGammaValue和SetGammaValue是读写伽马值的接口. DDI接到上层读写伽马值的请求后直接调用这2个外部函数.

GetGPE这个函数返回一个GPE的指针.使用ddi_if构造一个显示驱动需要基于GPE.意思是你需要实例化new一个GPE, 然后实现GetGPE返回这个GPE的指针.因此你要提供下面的接口给ddi_if.cpp:
GPE * gGPE = (GPE *)NULL;
GPE* GetGPE() {gGPE=new GPE(); return gGPE;}
GPE是一个类,DDGPE是继承自GPE的类,扩展了directdraw功能.GPE里面成员函数大部分是virtual函数.因此你可以从GPE继承,也可以从DDGPE继承, 可以定义同名函数,c++的多态.我有限的C++知识差点不够用了.


DrvGetMask是返回RGB位域的. 前面说了ddi_if.cpp透过DrvEnableDisplay到处所有其他接口, 并且在ddi_if.cpp中实现了这些接口. 但DrvGetMask除外.因此你要实现DrvGetMask这个函数, 返回一个数组,如下
ULONG gBitMasks[] = {0xf800, 0x7e0, 0x1f};
ULONG * APIENTRY DrvGetMasks(DHPDEV dhpdev){return gBitMasks;}
上面这个数组的值是RGB565的配置. 三个值分别代表R,G,B的所占的位域.多说几句,16bit色深有RGB565, RGB555, 常见的是RGB565. 24bit的一般RGB888了数字代表所占的位.比如RGB565, R占5bit, G占6bit, B占5bit.


另外, WinCE提供了一个AABLT的库, 这个是抗锯齿功能的, 在初始化时候调用AATextBltInit(AAGetMaskBits)把RGB位域也要告诉这个库.当然, 你也可以不使用这个库, 写一个AATEXTBltInit函数, 返回FALSE即可.
总结一下, 使用微软的MDD来完成一个显示驱动需要的基本工作:
1. 你需要继承一个GPE类并实例化gGPE=new GPE, 然后实现GetGPE函数,把这个gGPE指针交给ddi_if.
2. 需要实现DrvEnableDriver.
3. 你需要定义一个全局数组gBitMasks, 透过DrvGetMask把这个数组指针返回给ddi_if.