WinCE系统在驱动设计上有一个很方便的功能,就是原始设备制造商(OEMs)和独立硬件开发商(IHVs)可以自主开发设备驱动程序来支持他们的硬件。因此,在动手进行触摸屏驱动程序开发之前,深入了解WinCE系统驱动方式是非常有必要的。
(1)从驱动加载方式上的分类
要编写WinCE驱动程序首先要确定它是属于哪类驱动。一般来说,WinCE平台上使用的设备可分为两类:内建设备和可安装设备。因此,从驱动加载方式上WinCE可分为内建设备驱动(Built-In Driver)和可加载驱动(Loadable Driver)。
WinCE系统可直接使用内建设备,因为内建设备驱动程序是与WinCE的组件紧密相连的,也就是内建设备驱动程序是被静态地链接到GWES(Graphics Windowing and Events Subsystem)的。这些驱动对应的设备通常在系统启动时,在GWES的进程空间内被加载,主要是与显示和输入有关的驱动。
因为它们不是以独立的DLL形式存在,所以要求每一个内建驱动程序都必须与设备驱动程序接口(DDI)的特定接口保持一致。内建设备包括显示、触摸屏、音频、串行埠、LED、电池和PC卡插座等。内建驱动程序一般设计为动态链接库,但有两个例外:电池和LED驱动程序由于小而设计为静态库。它们一般储存在ROM或闪存内。
可加载设备是指可与平台连接和分离的第三方接口设备,可由用户随时安装和卸载。这种外围设备的驱动也被称为流驱动,这些驱动可以在系统启动时、或者启动后的任何时候由设备管理器动态加载。通常这类驱动是以DLL动态链接库的形式存在,加载后的这些驱动程序也只能以用户态的角色运行。在WinCE中典型的可加载驱动有:PCMCIA driver(PCMCIA.dll)、Serial driver(SERIAL.dll)、ATAFLASH driver(ATA.dll)、Ethernet driver(NE2000.dll,SMSC100FD.dll)。
与内建驱动程序不同的是,所有可加载流驱动程序都共享一个公用接口,而且功能也与应用程序所用的文件API中的功能匹配。因此,控制可加载设备的流接口驱动程序一般由应用程序存取。也就是说,流接口驱动程序是由一个特殊文件来将设备功能展现给应用程序的,该文件可被打开、读取、写入和关闭。通常只有OEMs才会对内建设备驱动程序进行修改,其它自由设备生产商由于只提供附加的硬件设备,对内建设备驱动程序不会有过多涉及。
(2)从驱动程序层次上分类
WinCE的好处是具有可定制性,当它自带的驱动程序不能满足用户的要求时,用户可以自己编写相应的驱动程序。因此按照结构分,WinCE驱动程序又可分为分层的驱动程序和不分层的驱动程序。分层的驱动程序由两个设置好的层组成:上层是模型设备驱动程序(Model Device Driver, MDD),下层是依赖平台的驱动程序(Platform Dependent Driver, PDD)。
分层的驱动程序中的MDD通常是无需修改可直接使用,MDD的作用是链接PDD层并定义它希望调用的函数接口:设备驱动程序提供器接口(Device Driver Service Provider Interface, DDSI)。同时MDD又把不同的函数集提供给WinCE内核,这些函数叫做设备驱动程序接口(Device Driver Interface, DDI)。不分层的驱动程序是把PDD与MDD写在一起,没有做严格的区分,通常这种驱动比较简单,比如ATADISK。简单的说,内建驱动和加载式流驱动是从驱动与系统其它模块(调用者)的接口形式上做的分类;而不分层和分层是从驱动实现方式上的分类。
在开发过程中,MDD层驱动是不需要被修改的。但和MDD层驱动不同的是,PDD层驱动必须被修改成和特定硬件相匹配的代码。程序员可以自己开发一个PDD程序,但多数情况下建议开发者在Platform Builder提供的样例驱动程序上进行修改。在Win CE系统中触摸屏驱动是一种分层驱动。
然而问题总是无处不在的,近有人问我驱动调试助手到底能动态加载哪些驱动,为什么在加载USB设备驱动时总是失败。要解释这个问题,首先得弄清楚WinCE中驱动的相关概念。本文将主要介绍WinCE下驱动程序的分类,但是有些概念性还是要了解的。
(3) WinCE中驱动的相关概念
驱动程序是介于操作系统和设备之间的一个代码层,它的主要作用是为操作系统提供一个接口,以操作不同的硬件,包括物理的和虚拟的设备。虽然驱动程序有很多种,但从编程的角度来看,无非是往一个 固定的框架中添加相应的代码。这里的框架指的是一个接口,面向操作系统。代码实现的宗旨是,在正确的时间往正确的寄存器中写正确的值。
驱动程序的分类,从不同的角度有不同的 分法。拿串口驱动来说,你可以说它是一个分层驱动,你也可以说它是一个流驱动,你还可以说它是开机时自动加载的驱动……这似乎有点乱。如果你也这么认为, 那建议往下看。如果这些你都了如指掌,那就不浪费时间了,当然,您愿意找茬,我会很感谢!
先说本地驱动(Native Drivers)和流驱动(Stream Drivers)。WinCE下的驱动都可以归类到这两个里面,二者必居其一。这是从驱动程序提供给操作系统的接口来区分的。流驱动为操作系统提供了流接口函数,如XXX_Init()、XXX_Open()、XXX_Read()、XXX_Write()、XXX_Close()等等。这一类的驱动由Device Manager来管理,它调用ActivateDeviceEx()函数来加载流驱动。ActivateDeviceEx()的参数是注册表中相应的键,用来设定加载流驱动的属性,如Index、Order、Prefix等等。流驱动的注册表配置信息一般存放在[HKEY_LOCAL_MACHINE\Drivers\BuiltIn]下。流驱动加载成功后,应用程序通过调用CreateFile()、ReadFile()、WirteFile()等来访问流驱动的设备。流驱动可以动态管理,驱动调试助手就是用来帮助调试这一类驱动的。
与流驱动相反,本地驱动提供给操作系统的不是标准的流接口,而是事先约定好的特定接口。不同的设备,接口也不一样。WinCE中,常见的本地驱动有LCD显示驱动、触摸屏驱动、鼠标和键盘驱动及打印机驱动等。可以看到,本地驱动主要是人机界面相关的驱动。它们由GWES管理,在系统启动时加载。他们在注册表中也有各自相应的配置信息。如键鼠的注册表配置如下:
[HKEY_LOCAL_MACHINE"System"CurrentControlSet"Control"Layouts"00000409]
"Layout File"="kbdmouse.dll"
"Layout Text"="US"
"PS2_AT"="kbdmouse.dll"
"Matrix"="kbdmouse.dll"
本地驱动由操作系统调用,应用程序不能访问。对于这类驱动,驱动调试助手是无能为力的,只能老老实实的编译、、验证。
WinCE驱动中经常会听到MDD(Model Device Driver)和PDD(Platform Dependent Driver)的概念,这是从驱动代码实现的结构来区分的。WinCE的驱动可以是单层的,也可以是PDD+MDD。这没有硬性规定,一个驱动程序可以采用分层结构,也可以采用单层结构。一般来说,单层结构的驱动执行效率更高,而分层结构的驱动方便代码维护和移植。拿串口驱动来说,完全可以采用单层结构。而把它分为PDD和MDD,作为一般的开发者,我们只需实现PDD层就可以了,MDD层由微软实现。这样,驱动开发的工作量少很多,而代码的可靠性则有了更好的保证。至于采用哪一种结构的驱动,主要看你的需求。
WinCE 6.0引入了内核态驱动和用户态驱动的概念。在WinCE5.0及先前的版本中,驱动工作在用户态。从代码方面看,内核态驱动和用户态驱动没太大差别。如果驱动中没有采用什么特别的技术,内核态驱动和用户态驱动甚至是二进制兼容的。我曾经试过将一个DLL分 别加载到内核态和用户态,都工作得很好。内核态驱动被加载到内核空间,用户态驱动被加载到特定的用户进程空间中。从执行效率来看,内核态的驱动效率比用户 态的驱动高。从稳定性方面考虑,用户态的驱动不会对系统产生致命影响,而内核态的驱动相对危险。同样,采用哪一种类型的驱动,也是看你的需求。
从驱动加载的时间来看,可分为两种:系统启动时加载和需要时加载。一般来说本地驱动都是在启动时加载的,所以这里说的主要是流驱动。如果想要驱动在系统启动时加载,只需将它的注册表配置信息放到[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\]下,如[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Battery],系统启动时,Device Manager会自动加载它。需要时加载,顾名思义,就是想加载就加载,想卸载就卸载,很灵活。这里很有必要说一下USB设备的驱动加载,如USB摄像头驱动,它也属于需要时加载的驱动。从驱动的接口来看,它属于流驱动,但相对普通的流驱动,它增加了几个函数:USBDeviceAttach()、USBInstallDriver()、USBUnInstallDriver()等。USB摄像头驱动的加载在USBDeviceAttach()中完成。所以,它无须,也不能,用驱动调试助手加载。需要时加载的驱动还有一个作用,在无法修改系统的情况下,应用程序中动态加载该驱动,以完成对硬件的操作。
综上所述,WinCE驱动的分类,主要有以下几种分法:
按驱动接口分,可分为本地驱动和流驱动;
按驱动结构分,可分为单层驱动和分层驱动;
按驱动加载的空间分,可分为内核态驱动和用户态驱动;
按驱动加载的时间分,可分为启动时加载和需要时加载两种。
驱动调试助手,是用来动态管理流驱动。本地驱动和USB驱动不再它的控制范围之内,各位在使用时注意这一点。
免责声明: 凡注明来源本网的所有作品,均为本网合法拥有版权或有权使用的作品,欢迎转载,注明出处。非本网作品均来自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。