wince6.0串口驱动相关

来源:互联网 发布:php 7 编辑:程序博客网 时间:2024/06/04 19:34
之前看了李大为编写的windows ce 工程实践完全解析关于串口驱动的章节,完后脑子里进行了一定的梳理和总结。一段时间后,偶然同事和我讨论时才发现,之前感觉良好的总结基本又乱了,这里体现了讨论的重要。同时提醒我好脑子不如坏笔杆。赶紧再记下。当然可能有理解错误的地方,欢迎大神们指正。
串口时典型的流驱动方式,系统给我们留了 xxx_init,xxx_open,。。等系列函数让我们填写实现,应用程序就通过他们来实现对串口的访问。
串口驱动的加载过程如下:1,系统启动后,总线枚举器完成自身初始化后,开始枚举自己对应的注册表键的各个子键,找出合法的设备驱动程序。
2,总线枚举器,从【HKEY_LOCAL_MACHINE\Drivers\Builtin】注册表键的各个子键中寻找名位dll的键值,就是要加载的可执行文件。
3,总线枚举器调用ActivaeDeviceEx函数,加载2中的设备驱动的动态链接库到自己所在的内核进程中,
4,总线枚举器要在【HKEY_LOCAL-MACHNE\Drive\Active】下位刚才的驱动程序生成一个子键。(理解:经过和同事讨论,驱动程序直接访问这个地方的数据好像就能得到[HKEY_LOCAL_MACHINE\Drivers\Builtin]中的信息)。
5,总线枚举器调用INIT函数(理解:对于串口就是COM_init(),而且这个初始化函数带入的参数就是从步骤4中的键值信息中取得的。)。
下面说说初始化过程:上面调用了COM_INIT函数,整个过程就是对结构体HW_INDEP_INFO赋值。该结构体中成员挺多。个人认为有2个成员比较有分析价值。

第一个是PHWOBJ pHWObj;他也是个结构体含有3个成员,第一个是确定IST线程的启动位置,第二个是串口端口序号,第三个是比较重点的。他是一个结构体,他的成员全是函数指针。串口驱动程序MDD层就要使用这些函数。比如COM_READ 他就是通过调用该结构体里的serXmitComChar函数实现,具体为:

pHWObj->pFuncTbl->HWXmitComChar(pSerialHead->pHWHead,pSerialHead->DCB.XonChar);         pHWObj 中第三个成员对应的这些函数 应该是定位在MDD和pdd中的过度层,为后面方便叙述 本文定义为a层,  怎么理解呢,这样:MDD要操作串口就调用a层中的函数。而a层中的函数又会调用PDD层中那些串口类中定义的虚函数。(wince为什么要这么设计呢?为了使多个串口能共用这些函数。这些函数全固定,但是他们中除都有一个参数是不定的要根据注册表子键的DeviceArrayIndex的取值而定。这样不同的串口都能用到a层,只需更改注册表的子键值即可访问不同的串口。)

接着上面的讲,a层中还有个不同的函数SerInit,他的调用如下:pSerialHead->pHWOBj->pFuncTbl->HWInit(Identifier,pSerialHead,pSERIALhEAD->pHWObj);他通过判断端口号将生成对应端口的pdd对象。 这个对象作为返回值赋值给HW_INDEP_INFO的第二个重要参数PVOID pHWHead,

好,下面讲第二个参数,上面说到第二个参数的赋值,知道了pHWHead这个参数就是串口类对象,这是个继承类,他的父类也是继承类;他们赋予不同的能力,比如注册表操作,线程操作等。类的具体内容我就不细说了,主要有初始化,设备操作,电源管理,中断,发送接收,modem,线路功能,配置,ir特殊处理,错误处理等部分。这些留下的虚函数接口就是我们需要编写的pdd层了。上面讲到的a层函数的实现就要调用调用的就是这些虚函数。

讲到有点乱。总体流程简单的说就是:系统启动,总线枚举器查看注册表,取得信息,调用COM_INIT,调用serinit创建类对象 B。类对象B的构造函数以及其父类的构造函数不断调用实现部分初始化功能,然后类B自己的init函数中实现功能(I/O端口地址到系统物理地址的转换,物理地址到虚拟地址的转换,查找中断优先号记录到注册表active下)。然后调用器父类的init函数实现功能(初始化中断,将中断号与ist关联起来,再进行地址的一些操作,最后根据虚拟地址创建类实例。该实例功能是为部分寄存器写入初始值,及其至于一个可工作的状态。)最后调用postinit使能线程等操作。到此整个串口就工作了。


原创粉丝点击