590 likes | 675 Views
本机设备驱动程序. www.up-tech.com 博创科技 嵌入互动. 主要内容. 本机驱动程序简介 键盘驱动与布局管理器 PDD 代码示例及分析 触摸屏代码示例及分析. 1 、本机驱动程序简介. 本机设备驱动程序的概念.
E N D
本机设备驱动程序 www.up-tech.com 博创科技 嵌入互动
主要内容 • 本机驱动程序简介 • 键盘驱动与布局管理器 • PDD代码示例及分析 • 触摸屏代码示例及分析
本机设备驱动程序的概念 • Windows CE可以在各类类平台上运行,不同的平台涉及到不同的外围设备和这些设备的驱动程序。在可以连接到WinCE系统的成千上万个设备当中,有一些设备是固定的,无论在哪种平台都会出现;有一些设备是极其重要的,例如USB和显示设备。WinCE为了驱动这些设备,定制了各种各样的接口,为每种设备都提供了量身定做的驱动模型。这类驱动程序成为本机设备驱动程序。
本机设备驱动程序的体系结构 • 为了方便研发人员开发出适合自己平台的本机设备驱动程序,微软提供了一些驱动程序样本。开发人员可以通过修改这些样本来快速实现自己的驱动程序。 • 本机设备驱动程序一般分为两种类型:整体式驱动程序和分层驱动程序。
整体驱动程序和分层驱动程序 • 整体驱动程序没有层次之分,基于单个码片,向上与操作系统之间存在一套接口函数(DDI),向下直接控制硬件。 • 分层驱动程序一般分为上下两层,上层为模型设备驱动程序(MDD),下层为依赖平台的设备驱动程序(PDD)。MDD与操作系统之间存在一套接口函数(DDI),MDD与PDD之间也存在一套接口函数(DDSI),PDD控制硬件。
整体驱动程序和分层驱动程序 • 无论是整体驱动还是分层驱动,在功能上并没有太大的不同。对于一些功能相对简单的驱动程序,整体式的结构更加小巧和快速,对于一些功能复杂,重用性要求比较高的驱动程序,分层驱动会提供更清晰的结构,代码移植也更加方便,但是会增加一部分系统开销。 • 整体式驱动程序最终会连接成为一个动态连接库,向上与操作系统接口,向下直接控制硬件;对于分层的驱动程序,一般只需要编写适合于平台的PDD部分,链接后生成动态连接库,与系统默认的MDD接口。
二者的利弊分析 • 分层驱动程序可能只需要修改 PDD。 • 分层驱动程序增加了设备驱动程序中的函数调用的系统开销,因为 MDD 调用到 PDD 中。 • 整体式驱动程序改进了驱动程序性能,因为它将 MDD 和 PDD 到组合一个层之中,这消除了 MDD 对 PDD 进行的函数调用。 • 整体式驱动程序更难以迁移到将来版本的 Windows CE,因为 Windows CE 所包含的大多数设备驱动程序都被划分为一个 PDD 和一个 MDD。 • 如果设备的功能与 MDD 层中的函数执行的任务很好地匹配,则整体式驱动程序可以更简单、更有效。
GWES 设备管理器 DDI函数 DDI函数 流接口函数 设备 驱动 程序 单片 驱动 程序 设备 驱动 程序 硬件 驱动程序结构图
分层驱动程序中的MDD • 包含给定类型的所有驱动程序所共有的代码。 • 调用 PDD 函数以访问硬件。 • 链接到 PDD 层,并且定义MDD 期望在该层中调用的设备驱动程序服务提供程序接口 (DDSI) 函数。 • 向操作系统 (OS) 公开设备驱动程序接口 (DDI) 函数。 • OS 的其他部分可以调用这些函数。相关设备可以共享相同的 DDI。
分层驱动程序中的MDD • 处理中断处理。 • 可供开发人员重用。 • 可以链接到多个 PDD。 • 通常不需要进行更改。如果进行了更改,则在将驱动程序迁移到将来的版本时可能会遇到麻烦。 • 包含任何中断服务线程 (IST)。
分层驱动中的PDD • 由硬件平台特有的代码组成。 • 可能需要修改硬件平台。 • 专门用于使用特定的 MDD 实现。 • 公开 MDD 调用的 DDSI 函数。提供DDSI函数,以供MDD或是其他驱动程序调用。
分层驱动中的PDD • 微软为各种各样的内部设备提供了几个样本的PDD层,样本音频驱动就是一个很好的分层的、中断驱动的流接口驱动程序,该驱动程序用于驱动内部音频设备,它的层就是典型的本机设备驱动程序使用的MDD层和PDD层。 • 样本驱动程序的MDD层实现单独的音频设备,该设备具有播放和录制脉冲码调音波形声音的功能。 • PDD层负责与声音硬件的通信,用于开始/停止播放和录音、初始化硬件和去除硬件的初始化。
样本音频分层驱动 • 微软为各种各样的内部设备提供了几个样本的PDD层,样本音频驱动就是一个很好的分层的、中断驱动的流接口驱动程序,该驱动程序用于驱动内部音频设备,它的层就是典型的本机设备驱动程序使用的MDD层和PDD层。 • 样本驱动程序的MDD层实现单独的音频设备,该设备具有播放和录制脉冲码调音波形声音的功能。 • PDD层负责与声音硬件的通信,用于开始/停止播放和录音、初始化硬件和去除硬件的初始化。
样本音频分层驱动 • MDD层提供的接口是标准的流接口函数,而PDD和MDD是使用一组DDSI函数通信。DDSI是PDD层提供的专门用来与上层通信的接口。 • 这个例子只是提供了一种方法,用户可以根据自己的需要来定制自己的驱动实现相应的功能。也就是说微软并不对Windows CE.NET的音频硬件活动方式有任何限制。用户可以根据自己的意愿,从头开始编写或是修改已有的驱动代码来驱动外围设备。
样本音频分层驱动 • 微软为各种各样的内部设备提供了几个样本的PDD层,样本音频驱动就是一个很好的分层的、中断驱动的流接口驱动程序,该驱动程序用于驱动内部音频设备,它的层就是典型的本机设备驱动程序使用的MDD层和PDD层。 • 样本驱动程序的MDD层实现单独的音频设备,该设备具有播放和录制脉冲码调音波形声音的功能。 • PDD层负责与声音硬件的通信,用于开始/停止播放和录音、初始化硬件和去除硬件的初始化。
对驱动程序的限制 • 设备驱动程序是用户层次上的过程,也就是说驱动程序代码可以调用Microsoft Win32 API,访问用户层次可用的任何资源。然而对大多数情况来说,设备驱动程序只需要一定数量的样本API,比如内存定位程序。驱动程序偶尔也执行比较复杂的任务,包括生成线程或视窗等。例如在一些基于Windows CE的平台上当电池电压低于临界电压时,电池驱动程序给用户提供一个对话框提示用户更换电池。
对驱动程序的限制 • 在关闭系统时限制设备驱动程序的下列动作: • 在预先定位好的空间存储设备状态 • 向与关闭系统有关的设备发出指令 • 在驱动程序中设置用来提醒其已经关闭的标志 • 当电源恢复时,驱动程序能从存储数据恢复设备的状态。 • 驱动程序也能够使用SetInterruptEvent函数来产生人工中断事件。通过调用SetlnterruptEvent驱动程序可以强行释放中断线程来继续任何必须的事件处理。驱动程序只应在电源周期变化期间调用这些函数。
键盘驱动的分层 • Windows键盘驱动属于本机驱动。一个本机驱动程序意味着这个驱动可能会使用一些特别的接口,这种接口不同于任何你所能看见的Windows驱动程序接口,它往往是与系统密切相关的,并且很多接口也被设计为可以直接被应用程序所调用。
键盘驱动的分层 • 键盘驱动程序将键盘硬件的输入转换为驱动程序传入系统的的键盘消息。驱动程序也负责从这些键盘消息中产生对应的Unicode字符。键盘驱动被分成两个组件,这种分层使得为一个国际性的键盘布局开发驱动程序变得非常便利。其中一些键盘驱动需要将一个按键映射为多个虚拟键码。对于一些比较小的不具备像桌面工作站一样齐全的键盘的小系统来说是非常有用的,其中一些键有多个功能,或者功能有所改变,或者前面两者兼具。驱动程序根据某些特殊按键的状态(SHIFT,ALT等)来生成虚拟键码。
键盘驱动的分层 • 通常,你应该把键盘驱动实现为一个分层的驱动。上层,或者称作模型设备驱动(MDD),负责将扫描码映射到虚拟键码,并且配合虚拟键码生成字符数据,然后将键盘消息打包并把它们放到系统消息队列中。下层,或者称作依赖于平台的驱动程序(PDD),主要负责从硬件获取扫描码。
布局管理器 • 布局管理器管理设备布局和PDD以及操作系统其它部分的输入语言。布局管理器实现了WINCE 4.1和更早版本的键盘驱动接口,所以,在WINCE 4.1和更早版本的键盘驱动中可以访问图形,窗口和事件(GWES)接口。
布局管理器 布局管理器按照下面的顺序处理扫描码: 1、PDD获取一个扫描码 2、发送扫描码到布局管理器 3、布局管理器根据发送此扫描码的键盘的设备布局将此扫描码转换为虚拟键码 4、布局管理器根据发送此扫描码的键盘的设备布局对其进行重新映射 5、布局管理器处理自动连击功能。所有的键盘共享自动连击设置 6、布局管理器调用Keybd_event函数发送键盘事件 如果在PDD得到键盘事件并且布局管理器处理这个事件的时候,输入所在的本地区域变化了,键盘事件将被映射到新的设备布局上。
布局管理器 • 当一个将虚拟键码转换为Unicode的请求到达的时候,布局管理器使用编辑者所对应的状态和映射表格进行转换。在此之前,布局管理器执行ALT+小键盘数字的逻辑,这个逻辑可以通过按下ALT并在小键盘上输入字符所对应的数值来输入Unicode。
布局管理器 • 布局管理器在一个全局数组中存储每个PDD的信息,这个数组的索引值是布局管理器在初始化每个PDD是分配给他们的键盘标识符。布局管理器将保存一整套的有关每个PDD的入口点,可用的设备布局和当前布局的信息。 • 当本地输入改变的时候,布局管理器将每个PDD的布局改变位于新的本地输入项匹配的布局。它同时也将输入语言切换为由本地输入的低字节描述的那一种。
布局管理器与GWES接口 • 布局管理器与GWES接口的方式与WINCE 4.1和早期的键盘驱动相同,都是通过KeybdDriverXXX函数,以及附加的LayoutMgrXXX 函数。后表列出了布局管理器与GWES接口的几种方式:
PDD层开发 • 键盘PDD是键盘驱动程序中依赖于平台的代码。 • 布局管理器能够同时处理多个键盘PDD,比如在同一台设备上的PS2键盘和矩阵键盘。 • 键盘PDD中包含初始化和电源管理的函数。 • 键盘PDD可以使用通用键盘中断服务线程(IST)或者使用自己的IST。
PDD层开发 • 当图形窗口和事件子系统初始化键盘驱动的时候,会逐个枚举每个PDD并对其进行初始化。 • 每个PDD都会拥有自己的入口函数,这个入口函数返回一个包含对PDD的描述和函数指针的机构体。 • 当设备管理器初始化PDD的时候,键盘驱动传给PDD一个唯一的标识符,PDD使用这个标识符来标识自己。这个标识符在系统中存在多个PDD的时候,比如有两个独立的PS/2控制器的时候,是非常有用的。 • 所有的PDD和布局管理器被编译到一个DLL中,不能够另行添加。
PDD层开发 • 在键盘驱动函数中必须指定需要初始化的PDD。以NULL作为最后一个元素的数组gpfnPddEntries指定了键盘驱动中所有需要被初始化的PDD。 • 如果多个控制器使用相同的PDD,那么这个入口函数可能会被多次调用。 • 在数组中的第一个入口点指向默认的PDD。MapVirtualKey函数使用默认的PDD设备层将扫描码转换为虚拟键码。 • 微软推荐将默认的PDD设置为PS/2键盘布局以便支持HID设备。如果没有PS/2口,请使用NOP PS/2 PDD。
示例代码-PDD的入口 • PDD入口定义: typedef BOOL (*PFN_KEYBD_PDD_ENTRY)( UINT uiPddId, PFN_KEYBD_EVENT pfnKeybdEvent, PKEYBD_PDD *ppKeybdPdd ); • 全局的PDD入口数组: PFN_KEYBD_PDD_ENTRY g_rgpfnPddEntries[] = { PS2Entry, MatrixEntry, NULL };
PDD层开发 • 当这个PDD的IST执行的时候,他会通过布局管理器传递下来的pfnKeybdEvent函数发送当前的键盘事件给键盘布局管理器。下面的代码说明了这个接口的使用方法。 typedef struct tagKEYBD_PDD { WORD wPddMask; // Matches the keyboard layout with its PDD LPCTSTR pszName; // Could be used to identify PDD to user PFN_KEYBD_PDD_POWER_HANDLER pfnPowerHandler; PFN_KEYBD_PDD_TOGGLE_LIGHTS pfnToggleLights; } KEYBD_PDD, *PKEYBD_PDD; typedef void (*PFN_KEYBD_EVENT)( UINT uiPddId, UINT32 uiScanCode, BOOL fKeyDown );
PDD开发 • 启动键盘IST是PDD入口函数的责任之一。如果针对PS/2控制器,PDD入口函数同样也会启动鼠标IST。键盘IST调用调用布局管理器键盘事件函数,这个函数是由布局管理器传递给PDD的入口函数来响应每个键盘事件的。可以在驱动程序中启动并使用通用的键盘IST,只要传递给他一个包含了所有需要的信息的函数。
IST的工作流程 1、当内核的中断处理函数触发hevInterrupt事件时,通用IST调用PDD的GetKeyboardEvent函数。 2、这个GetKeyboardEvent函数并不一定需要如此命名。 3、收到了对键盘事件函数的调用,布局管理器开启了自动连击逻辑。 4、IST和键盘PDD与并不参与自动连击功能的实现过程。 5、IST为每个返回的事件调用布局管理器的键盘事件响应函数。 6、IST调用InterruptDone结束对中断号为dwSystIntr_Keybd的中断的响应。
键盘LED和电源管理 • 当键盘LED状态发生变化时,布局管理器调用每个PDD的ToggleLights函数。实现这个功能的函数不一定要命名为ToggleLights。 • 另外,为了让HID键盘的LED显示状态和其他键盘保持一致,当键盘LED事件发生的时候,布局管理器会向所有的HID键盘发送一个I/O控制码IOCTL_HID_SET_MODIFIERS。这个过程发生在GWES调用布局管理器的KeybdDriverVKeyToUnicode的时候。 • 布局管理器调用每个PDD的电源处理函数KeybdDriverPowerHandler,电源关闭的时候传入的参数为TRUE,而电源开启的时候传入的参数为FALSE。
PDD需要提供的接口函数 • 传出的函数指针: • 电源处理函数指针: pfnPowerHandler • LED状态处理函数指针:pfnToggleLights • 接收的函数指针: • 键盘事件响应函数: pfnKeybdEvent
Mdd(Layout Manager) 向下调用 向上调用 uiPddId KeybdEvent PowerHandler ToggleLights 软件 Pdd 触发指示灯 向下调用 向上调用 按键事件 硬件 PS2 Keyboard 驱动程序体系结构
实现PDD的基本思想 • 从已有的代码开始。可以参考PB附带的样例驱动,或是由BSP中的键盘驱动代码开始。 • 只需要实现PDD层的修改。MDD层是被整个操作系统使用的,不仅仅是你所改写的那个键盘驱动。如果你修改了MDD(即布局管理器),很可能会出现无法预料的错误。
实现PDD的基本思想 • 修改BSP中的键盘驱动时要留意系统是否有必要或是已经挂载了另外的键盘驱动程序。一个系统中可以存在不止一个键盘驱动程序,在编写你自己的驱动的同时不要破坏其他驱动的工作。 • 永远都要有一个键盘驱动。很可能你的系统不需要键盘,但是在这种情况下还是要有一个键盘驱动。键盘驱动的MDD是GWES的重要组成部分,缺了它,GWES无法正常完成工作,所以一定要确保存在一个键盘驱动,来保证GWES的正常运行。一个框架驱动(NOP PDD)就可以很好的完成这种工作。
PDD涉及到的一些函数 • Pdd_Entry() Pdd入口函数 • ScanCodeToVKeyEx() 将扫描码转化为虚拟键码。 • 类Ps2Keybd • IsrThreadProc()。 键盘的中断服务线程 • IsrThreadStart()。 键盘中断服务线程入口 • Initialize()。 键盘类初始化函数 • KeybdPowerOn() 上电时对应的键盘电源管理函数 • KeybdPowerOff() 断电时对应的键盘电源管理函数 • KeybdPdd_PowerHandler() 暴露给上层驱动的电源管理接口 • KeybdPdd_GetEventEx2() 键盘时间响应函数 • KeybdPdd_ToggleKeyNotification()暴露给上层的键盘LED响应函数
一个典型的PDD入口函数分析 BOOL WINAPI PS2_8042_Entry( UINT uiPddId, PFN_KEYBD_EVENT pfnKeybdEvent, PKEYBD_PDD *ppKeybdPdd ) { SETFNAME(_T("PS2_8042_Entry")); 。。。 v_uiPddId = uiPddId;//保存分配给当前Pdd的标识号 v_pfnKeybdEvent = pfnKeybdEvent;//保存键盘事件响应接口函数指针 。。。 *ppKeybdPdd = &PS28042Pdd;将自己的Pdd信息结构体的指针返回给上层 。。。 return fRet;//返回一个布尔值,如果函数执行成功则返回TRUE,否则返回FALSE }
对于其他函数的更改 • 参考PB附带的PS2_8042的键盘驱动程序,大部分函数可以保留,一般只需要修改入口函数和键盘驱动IST及电源管理函数和LED响应函数。 • 键盘驱动IST位于IsrThreadProc()中,Initialize()和IsrThreadStart()函数用于加载IST并完成其他的初始化的必要过程。 • KeybdPowerOn()和KeybdPowerOff()分别对应上电和断电时的处理, KeybdPdd_PowerHandler() 是电源管理的框架,一般不需要修改。 • KeybdPdd_ToggleKeyNotification()控制LED的显示状态,修改这个函数适应你的键盘即可。
Windows CE.net触摸屏 • 隶属于GWES的本机驱动程序 • 拥有4点校屏的可视化校屏程序 • 具有良好的点触反应和准确性
Netarm2410-S的触摸屏 • 采用了4线电阻式触摸屏 • 采用了处理器自带的AD来实现,需要调整参考电压至最大(3.3V) • 数据返回xy方向的2个坐标值 • 采用了Windows CE.net集成的stylus校屏程序 • 实现了系统单击、双击、拖拽等基本鼠标操作
接口函数 • TouchDriverCalibrationPointGet获取校验点 • DdsiTouchPanelGetDeviceCaps捕捉设备点 • DdsiTouchPanelSetMode设置模式 • DdsiTouchPanelEnable使能触摸屏 • DdsiTouchPanelDisable禁止触摸屏 • DdsiTouchPanelAttach加载触摸屏 • DdsiTouchPanelDetach卸载触摸屏 • DdsiTouchPanelGetPoint获取点值 • DdsiTouchPanelPowerHandler