Windows CE驱动开发

rel="File-List" href="file:///C:%5CDOCUME%7E1%5Czzx%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"> rel="Edit-Time-Data" href="file:///C:%5CDOCUME%7E1%5Czzx%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_editdata.mso">


1. Windows CE驱动简介

1.0. 概述

设备驱动程序是操作系统内核和硬件的接口,操作系统定义了一组标准的接口,编写驱动的过程也就是实现这些接口。从应用程序到具体硬件间要经过如下步骤:应用程序调用OS函数-操作系统-驱动接口-驱动程序-硬件操作函数-硬件。在wince里驱动都以用户态的 DLL存在,需要通过进程加载到slot里。共有三类系统进程用来加载:Device.exeGWES.exeFileSys.exe。绝大多数设备驱动都是通过Device.exe加载的。不同的OS保留的设备驱动接口是不一样的,如桌面windowswince就不同。

wince下设备的初始化分为两个阶段:Device.exe的初始化;外设的枚举和加载。其流程是:上电-启动bootloader-启动NK-启动注册表init键(Device.exe启动)-初始化数据结构、I/O、电源等-加载 BusEnum.dll(总线枚举器)-枚举注册表下Driver/buildin的所有子键。这里的枚举过程就是循环调用 ActivateDeviceEx()函数加载驱动的过程。在OS启动完毕后,我们可以用PBRemote Registry Tool查看H_L_M/drivers/active包含的子键,看哪些驱动随启动而加载

1.1. 驱动开发工具

Windows CE驱动可以采用Platform BuilderVS开发。BSP开发人员和IHVs(Independent Hardware Vendors)一般采用Platform Builer开发驱动,应用程序开发人员较多采用VS开发驱动。

下表对PBVS作了一个比较:

                工具

比较项

PB

VS

调试

采用内核调试工具调试,可实现真正的内核级调试

只能通过打印信息实现应用程序级别的调试

可开发的驱动类型

全部

仅限网络和PC卡驱动

是否支行PPC设备调试

发布方式

CAB

CAB

1.2. 驱动程序分类

按加载方式和接口类型(驱动与系统其它模块(调用者)的接口形式)可分为本机驱动(Built-In Drivers)、流驱动(Stream Drivers)和混合型驱动。

n         本地驱动

通常由GWES(图形对象事件子系统)加载,驱动对外的接口一般都是定制的。调用本地驱动的模块给了它确定的要实现的接口,比如电源驱动和通用LED驱动,操作系统有专门的接口。

n         流驱动

流驱动通常由Device Manager加载,驱动对外的接口为标准的流式驱动接口,如串口,网卡驱动。最终的dll文件中应该可以导出各种标准流式接口函数。它把外设抽象成一个文件,应用程序使用文件API(CreateFileDeviceIoControl ReadFile WriteFileCloseHandle)对设备进行访问,OS接受文件API调用FileSys.exe,转到device.exe,调用对应的流接口函数,与硬件交互。流驱动与OS和硬件的关系如下所示:



n         混合型驱动

既有定制的接口也有标准的流式驱动接口,和系统交互时只使用流式驱动接口,如PC卡操驱动。

 

按驱动的层次(实现方式)分为层次型驱动(Layered Driver)和独立型驱动(Monolithic Driver)。

n         层次型驱动

分层驱动分PDDMDD两层:

MDDModel Device Driver

与硬件无关,面向上层应用程序,一般由微软建立统一框架。具有如下特点:

*         包含给定类型的所有驱动程序所共有的代码

*         调用 PDD 函数以访问硬件

*         链接到 PDD 层,并且定义MDD 期望在该层中调用的设备驱动程序服务提供程序接口 (DDSI) 函数

*         向操作系统 (OS) 公开设备驱动程序接口 (DDI) 函数

*         OS 的其他部分可以调用这些函数,相关设备可以共享相同的 DDI,整体式驱动程序还公开 DDI 函数

*         处理中断处理

*         可供开发人员重用

*         可以链接到多个PDD

*         通常不需要进行更改

*         如果进行了更改,则在将驱动程序迁移到将来的版本时可能会遇到麻烦

*         包含任何中断服务线程(IST)

PDD(Platform Dependent Driver)

针对具体硬件平台的操作代码,一般由驱动开发商实现,具有如下特点:

*         由硬件平台特有的代码组成

*         可能需要修改硬件平台

*         专门用于使用特定的 MDD 实现

*         公开 MDD 调用的 DDSI 函数

*         整体式驱动程序不公开 DDSI 函数

 

MDDPDD之间通过标准的设备驱动服务供应商接口DDSI连接。

MDDPDDDDSI间关系如下图所示:



一般微软已经实现了MDD,可能也实现了PDD,我们只需要对PDD做些修改就能使用,比如音频的驱动,显示的驱动。

n         整体式驱动

整体式驱动程序包含了MDDPDD两方面的代码,适用于操作不复杂的驱动,其优点是减少了MDDPDD传递之间传递信息的开销,实时性更强。

 

 

在分层驱动和整体驱动间选择时考虑如下原则:

*         分层驱动程序可能只需要修改 PDD

*         分层驱动程序增加了设备驱动程序中的函数调用的系统开销,因为 MDD 调用到 PDD

*         整体式驱动程序改进了驱动程序性能,因为它将 MDD PDD 到组合一个层之中,这消除了 MDD PDD 进行的函数调用

*         整体式驱动程序更难以迁移到将来版本的 Windows CE,因为 Windows CE 所包含的大多数设备驱动程序都被划分为一个 PDD 和一个 MDD

*         如果设备的功能与 MDD 层中的函数执行的任务很好地匹配,则整体式驱动程序可以更简单、更有效

 


2. 流驱动开发

2.1. 流驱动(开发)的特点

Ø         必须实现一套标准接口

Ø         I/O操作非常适用

Ø         应用程序可通过操作文件的接口操作流驱动

2.2. 实现流驱动

2.2.1. 选择代表设备的文件名前缀

代表设备的文件名前缀将会在流驱动的标准接口函数中体现,必须依照以下规则选取:

Ø         必须是三个字母,系统中存在多个同类时接后接一位阿拉伯数字区分

Ø         必须唯一


2.2.2. 实现流设备驱动的标准接口函数

rel="File-List" href="file:///C:%5CDOCUME%7E1%5Czzx%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml">

1)        XXX_Init:通知设备管理器为设备初始化分配资源

DWORD XXX_Init( DWORD dwContext )

Ø         参数dwContext指向一个描述设备接口的字符串,通常为流接口驱动在注册表中的对应项下的Prefix

Ø         函数返回设备上下文句柄

Ø         描述:当用户开始使用一个设备的时候,例如,当PC卡初始化的时候,设备管理器调用这个函数来初始化PC卡设备。这个函数并不是由应用程序直接调用的,而是通过设备管理器提供的ActivateDeviceEx()函数来调用的。函数执行后如果成功则返回一个设备的句柄。

2)        XXX_Deinit:通知设备管理器回收设备初始化时分配的资源

BOOL XXX_Deinit(DWORD hDeviceContext)

Ø         参数hDeviceContext指向设备上下文句柄,由XXX_Init创建时生成的设备句柄

Ø         函数返回是否卸载成功

Ø         描述:当一个用户需要卸载一个驱动程序的时候,设备管理器调用这个函数来卸载这个驱动程序,应用程序不能够直接调用这个函数设备管理器,通过DeactivateDevice()函数调用这个函数。

3)        XXX_Open:应用程序调用CreateFile时通过文件系统映射为XXX_Open打开硬件设备

DWORD XXX_Open(   DWORD hDeviceContext,

DWORD AccessCode

DWORD ShareMode

Ø         hDeviceContext是设备上下文句柄,由XXX_Init函数创建的时候返回

Ø         AccessCode是打开设备的权限描述符

Ø         ShareMode是设备的文件共享模式

Ø         函数返回设备打开后的上下文句柄

Ø         描述:这个函数用于打开一个设备驱动程序,当应用程序准备对某一个设备进行读或写操作时,系统必须先执行CreateFile()这个函数用于打开这个设备,CreateFile 会映射到XXX_Open,这个函数执行了以后系统才能够执行读和写操作。

4)        XXX_Close:应用程序调用CloseFile时通过文件系统映射为XXX_Close关闭硬件设备

DWORD XXX_Close(DWORD hOpenContext)

Ø         hOpenContext是要关闭的设备上下文句柄,调用XXX_Open时获得

Ø         0返回代表函数关闭失败

Ø         描述:这个函数用于关闭一个通过XXX_Open打开的驱动程序的实例。应用程序通过CloseHandle() 来调用这个函数,当执行完这个函数的时候驱动实例hOpenContext将不再有效。

5)        XXX_PowerUp:上电时(设备)OS调用此函数完成必要的上电操作

void XXX_PowerUp(DWORD hDeviceContext

Ø         hDeviceContext是设备的上下文句柄,XXX_Init生成

6)        XXX_PowerDown:掉电时(设备)OS调用此函数完成必要操作

void XXX_PowerDown(DWORD hDeviceContext

Ø         hDeviceContext是设备的上下文句柄,XXX_Init生成

Ø         描述:PowerDownPowerUp这两个函数通常都必须要硬件的支持才能够有效,也就是说相关的硬件必须支持PowerDownPowerUp这两个模式。

7)       XXX_Read:应用程序调用ReadFile映射为XXX_Read从打开的设备中读数据

DWORD XXX_Read(    DWORD hOpenContext,

LPVOID pBuffer,

DWORD count)

Ø         hOpenContext是打开设备的上下文句柄,由CreatFile()返回

Ø         pBuffer指向应用程序用于存放读取数据的缓冲区

Ø         Count指定从设备中读取多少字节的数据

Ø         函数返回实际读取的数据数量

Ø         描述:这个函数与ReadFile很相似,当一个流接口驱动程序对应的设备已经被打开后,可以使用ReadFile()函数对这个设备进行读操作,ReadFile()里面的hFile  参数就是这个设备的引用实例句柄hOpenContext

8)       XXX_Write:应用程序调用WriteFile映射为XXX_Write向打开的设备写数据

DWORD XXX_Write(   DWORD hOpenContext,

LPVOID lpBuffer,

DOWRD count)

Ø         XXX_Write的参数与XXX_Read的参数相似,方向相反

Ø         函数返回实际写入的数据数量

Ø         描述:当一个流接口驱动程序打开后,可以使用WriteFile()函数进行写操作。

9)       XXX_Seek:设备定位,是否支持视具体硬件而定

DWORD XXX_Seek(    DWORD hOpenContext,

long Amount,

WORD type)

Ø         hOpenContext是打开设备的上下文句柄

Ø         Amount指定指针要移动多少字节,正值向文件尾移动,负值向文件头移动

Ø         type描述了设备文件起始点位置

Ø         函数返回设备文件的当前指针

10)     XXX_IOControlI/O操作扩展,视具体硬件而定

BOOL XXX_IOControl     DWORD hOpenContext

DWORD dwCode,

PBYTE pBufIn

DWORD dwLenIn

PBYTE pBufOut,

DWORD dwLenOut

PDWORD pdwActualOut)

Ø         hOpenContext是打开设备的上下文句柄,由CreateFile返回

Ø         dwCode指定了IO操作的识别码,这些识别码由设备开发人员自定义

Ø         pBufIn指向输入缓冲区的地址,其中有给驱动程序使用的数据

Ø         dwLenIn指定了输入数据的长度

Ø         pBufOut指向输出缓冲区的地址,其中有驱动传给应用程序的数据

Ø         dwLenOut指定了需要输出的数据长度

Ø         pdwActualOutDWORD指针,需要知道从设备中实际读取的数据长度

Ø         函数返回操作是否成功

Ø         描述:这个函数通常用于向设备发送一个命令。应用程序使用DeviceIOControl函数来通知操作系统调用这个函数。通过参数dwCode来通知驱动程序要执行的操作。这个函数扩展了流接口驱动程序的功能。另外用户可以通过更改HKEY_LOCAL_MACHINE/Drivers/BuiltIn/YourDevice/Ioctl健来使自己的流接口驱动程序在加载的时候执行固定的操作。


2.2.3. 建立.def文件

流驱动一般以dll形式存在,通过DEF文件定义dll需要导出的接口函数,DEF文件的名称应该与设备驱动的名称相同。

以下为一个具体的DEF文件示例:

SampleDrv.DEF

LIBRARY SampleDrv

EXPORTS

SDV_Init

SDV_Deinit

SDV_Open

SDV_Close

SDV_Read

SDV_Write

SDV_Seek

SDV_IOControl

SDV_PowerUp

SDV_PowerDow

SDV_DLLEntry


2.2.4. 建立注册表项

为了加载前边的流驱动SampleDrv应该在注册表中增加流驱动的入口点,需要做以下工作:

1)        在注册表的[HKEY_LOCAL_MACHINE/Drivers/BuiltIn]下建立子项

2)        1)中建立的子项SampleDrv下建立键值对,PrefixDLL是必须的两个键

3)        建立其它子键

收下为针对SampleDrv 的注册表示例:

[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/SampleDrv]

Prefix”=”SDV                                     //设备前缀名

Dll”=SampleDrv.dll                                   //流驱动对应的dll

Order=dword2

Ioctl=dword4

2.3. 流驱动开发实例

参见http://msdn.microsoft.com/zh-cn/library/aa446913.aspx

2.4. 驱动调试

可以利用如下方法对驱动进行调试:

1)        调试区信息(Debug Zone

一般和WinCE的控制台调试工具Cesh.exe配合使用,具有以下特点:

Ø         可在不打断OS运行的情况下进行驱动的实时调试

Ø         可利用宏开关控制需要输出的调试区信息

Ø         可以得到进程、线程、和调试状态信息

Ø         可以利用IDE动态选择开关调试区信息

2)        驱动程序输出调试信息

通过调用RETAIILMSGDEBUGMSG完成,是最简单也是使用最广泛的一种驱动调试方法,具有如下特点:

Ø         必须借助至少一种外设显示调试信息

Ø         可动态输出设备状态信息

Ø         基本不影响OS运行保证了驱动程序运行的真实性

3)        核心调试工具(Kernel Debugger)

利用核心调试工具调试驱动时必须在PB下利用至少一种外设进行,具有如下特点:

Ø         禁止所有硬件中断,挂起OS

Ø         可以访问堆栈信息

Ø         可以单步调试OS或核心代码

4)        硬件辅助调试

硬件辅助调试利用硬件调试工具观察物理设备的真实状态,具有如下特点:

Ø         可以实时查看CPU的内部寄存器(利用JTAG

Ø         可以实时查看物理外设的输出输出状态(利用逻辑分析仪或示波器)

Ø         可以实时显示驱动的状态信息(利用LED

5)        VS调试

利用VS内置工具进行状态调试,单步跟踪等。

2.5. 驱动测试

Windows的驱动测试有如下方法:

Ø         写一个简单的应用程序来测试驱动程序的正确性

Ø         模拟各种可能发生的硬件输入状态来测试驱动程序的正确性

Ø         利用Windows CE自带的测试工具CETK来测试驱动程序的性能和完备性

2.6. 驱动程序的集成

在已有的BSP中集成新的驱动程序按以下步骤进行:

n         BSPDriver目录下建立新的驱动文件夹SampleDrv

n         实现SampleDrv驱动以及相关的DEF文件

n         如果需要用到硬件中断资源,修改原BSP中的相关中断处理函数OEMInterruptEnable,OEMInterruptDisable, OEMInterruptDone, OEMInterruptHandler

n         Platform.reg中,增加驱动程序相关项

n         Platform.bib中,增加驱动程序的相关注册表项

n         SampleDrv.dll $(_FLATRELEASEDIR)/SampleDrv.dll NK SH

2.6. 驱动程序的集成和发布

驱动的发布有如下两种方式:

1)利用CAB Wizard生成.cab驱动包

2)直接提供驱动程序文件夹以及相关注册表项和修改说明

参考文献

[1]. Windows CE 驱动开发基础. 陈黎.

[2]. 分层驱动程序与整体式驱动程序之比较. MSDN.

[3]. wince驱动开发学习笔记. milkyway的窝.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值