Windows CE显示驱动分析

      Windows CE中显示驱动不是流接口驱动,它属于本机驱动,本机驱动的注册表信息在注册表中一般是以[HKEY_LOCAL_MACHINE\SYSTEM\]开始的路径的信息,而流驱动的注册表信息一般是以[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\]开始的路径的信息。

显示驱动由图形、窗口、事件子系统(Gwes)直接加载,而不是设备管理器,驱动加载过程如下:

GWES.dll被加载后,GWES将根据注册表键HKEY_LOCAL_MACHINE\System\GDI\DisplayCandidates下面的项来找显示驱动,在Platform.reg中可以看到如下代码:

; GWES will pass this value to the Display driver; the driver will open the
; key to which it points to read its configuration.
[HKEY_LOCAL_MACHINE\System\GDI\DisplayCandidates]
	"Candidate10"="Drivers\\Display\\s3c6410\\Config"

 

[HKEY_LOCAL_MACHINE\Drivers\Display\s3c6410\Config]
	"DisplayDll"="My_s3c6410_disp.dll"

[HKEY_LOCAL_MACHINE\System\GDI\Drivers]
	"Display"="My_s3c6410_disp.dll"

; Settings to rotate the screen by 0 degrees clockwise upon download
[HKEY_LOCAL_MACHINE\System\GDI\Rotation]
	"Angle"=dword:0

      GWES就能找到s3c6410_disp.dll并且加载,并且把s3c6410_disp.dll作为一项写到HKEY_LOCAL_MACHINE\System\GDI\Driver键下面:

“Display”=“s3c6410_disp.dll

因为显示要实现独立于硬件的操作,驱动程序使用了分层的体系结构(可以看做为MDD层和PDD层)。

1、显示驱动的MDD

提到显示驱动的MDD层就需要知道GPE类,GPE类就相当于显示驱动的MDD层,GPE的标准定义是图形原语引擎(Graphics Primitive Engine),GPE是一个抽象类,是对显示设备的抽象,可以看做是显示驱动的通用的实现,其中包含很多纯虚函数,所以用户不能直接定义GPE类型的变量,只能以它为基类构造自己的GPE继承类,然后才能定义实例。我们也正是利用它的继承类来实现对于具体硬件的抽象,即实现我们的PDD层,同时完成基类中对应函数的实现。GPE类在gpe.h文件中定义,gpe.h在%_WINCEROOTMON\OAK\INC下。

    说到显示驱动不得不提到的就是DDI,DDI是Display Driver Interface 的缩写,如果看过串口函数的都知道,串口的MDD与PDD层的通信是通过一系列的接口函数实现的。而这里的DDI也是作为借口函数将GWES与设备驱动(PDD)联系起来的,逻辑上DDI函数的实现代码是构造生成任何一个显示设备驱动程序动态链接库的必不可少的内容。它并不需要驱动开发人员实现,微软已经帮我们实现了其中的代码。DDI的接口函数在ddi_if.cpp中实现的,源文件在%_WINCEROOT%PUBLIC\COMMON\OAK\DRIVERS\DISPLAY\GPE下;那这些函数是怎么被调用的呢?其实开发者需要设计一个GPE类的继承类,并定义一个该类的实例将其指针传递给DDI个函数供他们自身的实现,这个GPE继承类的实例就是目标硬件平台的显示设备的软件抽象,它必须正确反应特定显示设备的特性。

2、显示驱动的PDD

        显示设备的PDD层是与具体硬件相关的,它是GPE类的一个继承类,就拿6410的显示驱动来举例,准确的说,S3C6410Disp类的父类还不是GPE,而是DDGPE,DDGPE的父类才是GPE,之所以中间加了一个DDGPE类,是因为当前讨论的显示驱动程序既要支持DDI,又要支持DirectDraw。DDGPE类在文件Ddgpe.h中定义, 源文件在%_WINCEROOT%\PUBLIC\COMMON\OAK\INC下。一个GPE继承类实例对应一个显示设备硬件,所以GPE类型的所有数据成员都对应一个显示设备的某一方面的属性数据。用户可以并尽可能的根据具体的硬件设备所支持的功能实现GPE中的数据成员及函数。

3、那么具体上GWES子系统是如何获得DDI函数呢?
      Windows CE系统的设备驱动要实现自身的功能,不外乎导出函数和启动运行IST线程,但显示驱动只会向屏幕输出显示数据,不会启动IST线程。一下为6410显示驱动动态链接库导出函数:

LIBRARY DDI

EXPORTS
    DrvEnableDriver
    HALInit

     表面上只有两个导出函数,然而仅DrvEnableDriver一个函数又向Windows CE操作系统的GWES子系统提供了27个DDI函数指针。DrvEnableDriver函数是任何一个Windows CE的显示设备驱动程序都必不可少需要向GWES导出的,它是驱动程序的入口函数,他负责向GDI提供DDI指针。DrvEnableDriver()调用了GPEEnableDriver()函数,此函数在Ddi_if.cpp中实现,在此函数中可以看到,通过memcpy(pded, &pDrvFn, cj);代码将DDI的函数接口指针赋给pded提供给GWES,pDrvFn是一个DRVENABLEDATA类型的数组,DRVENABLEDATA数据结构组织了DDI的函数指针。

4、DDI函数又是如何与显示设备硬件打交道的呢?

    在ddi_id.cpp中我们可以看到有一个函数SafeGetGPE(),其实现代码如下:

GPE *
SafeGetGPE(
    HANDLE hDriver
    )
{
    GPE * pGPE = NULL;

    __try                                 
    {
        if ((hDriver != (HANDLE)SINGLE_DRIVER_HANDLE) && (pfnGetGPEPerCard != NULL))
        {
            pGPE = (*pfnGetGPEPerCard)((int)hDriver);
        }
        else
        {	
            pGPE = GetGPE();    //此函数在S3c6410_disp.cpp中定义
          
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        pGPE = NULL;
    }

    return pGPE;
}

      考虑了多个显是控制器在系统中并存的问题,所以SafeGetGPE函数才会显得那么复杂。实际上多数嵌入式设备只有一个显示控制器。这里只调用了GetGPE函数,具体函数内容如下:

GPE *
GetGPE()
{
    if (!gGPE)
    {
        gGPE = new S3C6410Disp();
    }

    return gGPE;
}

     这里的gGPE是一个GPE指针类型的全局变量,但是在GetGPE函数的实现代码直接将一个新生成S3C6410Disp类实例的指针赋值给它,S3C6410Disp类是GPE的继承类,父类的指针可以引用继承类的变量,并且对数据成员和成员函数的引用以继承类的实现或定义优先,所以使用gGPE所指向的数据或函数时,得到的是S3C6410Disp类型变量的成员数据或函数实现,只有在S3C6410Disp未定义的部分,才使用父类的数据成员和数据。这样一来,DDI函数就可以使用指向我们所创建的实例指针来访问我们具体的驱动程序了。

开发Display驱动的大致步骤如下:
(1)  继承GPE类并定义一个该类的实例。

(2)  实现GetGPE()函数,把该类的实例返回给上层的DDI接口。
(3)  实现DrvEnableDriver(..)函数并导出这个接口。

(4)  实现GPE类中的函数。

    

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值