当前位置:首页 > 嵌入式 > 嵌入式软件
[导读]与非网(EEFOCUS)电子产业社区平台为中国电子行业首家采用强大技术平台,由专业的电子技术编辑服务,为全球3000家知名半导体厂家及电子技术系统厂商提供技术信息发布、厂商网站、技术社区建设服务,并以电子术语词典,集成电路数据手册查询,电子产品新闻访谈资讯信息以及互动技术交流社区为上百万电子技术工程师以及高校师生提供最完整的电子技术信息查询和交流服务。

文/付林林

这是我从1月6日开始主持天极网论坛嵌入式开发版以来第一次发表文章,加上以前琐碎的文章共计30篇。研究的越多就越感觉自己懂的太少,其实在驱动开发方面我还是个菜鸟,我是想再次抛砖引玉,让做驱动有N年经验的人奉献一点出来,让大家减少一些研究驱动源码而又缺少注释所带来的痛苦。

我想即使读者看过微软的关于驱动开发的培训教材和CE帮助文档中的驱动部分,头脑中仍然一片茫然。要想真正了解驱动程序必须结合一些驱动程序源码,在此我以串口驱动程序(COM16550)中初始化过程为线索简单讲一讲驱动开发的基础知识。

Windows CE下的串口驱动程序能够处理所有I/O行为类似串口的设备,包括基于16450、16550 UART(通用异步收发芯片)的设备和一些采用DMA的设备,常见的有9针串口、红外I/O口、Modem等。在%_WINCEROOT%PublicCommonOAKDriversSerial目录下,COM_MDD2子目录包含新的串口驱动MDD层函数代码。COM16550子目录包含串口驱动PDD层代码。SER16550子目录包含的一系列函数专用于控制与16550兼容的UART,这样PDD层的主要工作就是调用SER16550中的函数。还有一个ISR16550子目录包含的是串口驱动程序专用的可安装ISR(中断服务例程),而很多硬件设备驱动程序采用CE默认的可安装ISR giisr.dll。一般串口设备相应的注册表设置例子及意义如下:

[HKEY_LOCAL_MACHINEDriversBuiltInSerial_1]

键意义"SysIntr"=dword:13串口1的中断ID为十进制13"IoBase"=dword:02F8串口1的IO空间首地址为十六进制2F8"IoLen"=dword:8串口1的IO空间长度为8个字节"DeviceArrayIndex"=dword:0串口1的索引,是1的由来"Order"=dword:0串口1驱动的加载顺序"DeviceType"=dword:0串口1的设备类型"DevConfig"=hex: 10,00 ....串口1在与Modem设备通讯时的配置,如波特率、奇偶校检等"FriendlyName"="COM1:"串口1在拨号程序中显示的名字"Tsp"="Unimodem.dll"串口1 被用于与Modem设备通讯的时候要加载的TSP(TAPI Service provider)DLL"Prefix"="COM"串口1的流接口的前缀"Dll"="com16550.Dll"串口1的驱动程序DLL

SysIntr由CE在文件Nkintr.h中预定义,用于唯一标识中断设备。OEM可以在文件Oalintr.h中定义自己的SysIntr。常见的预定义SysIntr有SYSINTR_NOP(中断只由ISR处理,IST不再处理),SYSINTR_RESCHED(重新调度线程),SYSINTR_DEVICES(由CE预定义的设备中断ID的基值),SYSINTR_PROFILE、SYSINTR_TIMING、SYSINTR_FIRMWARE等都是基于SYSINTR_DEVICES定义的。IoBase是串口1的IO地址空间的首地址,IoLen是IO空间的大小。IO地址空间只存在于x86平台,如果在其它平台硬件寄存器必须映射到物理地址空间,那子键的名称为MemBase和MemLen。在x86平台更多硬件的寄存器由于IO空间的局限也映射到物理地址空间。DeviceArrayIndex是设备的索引,用于区分同类型的设备。Prefix是流驱动程序的前缀,当应用程序调用CreateFile函数传递COM1:参数时,文件系统负责与串口驱动程序通信,串口驱动程序是在CE启动时由device.exe加载的。

下面从MDD层函数COM_Init开始探索串口驱动的初始化过程。COM_Init是在串口设备被检测后由设备管理器device.exe调用的,主要的作用是初始化设备,它的唯一参数Identifier是由device.exe传递的,其类型是一个字符串指针,字符串的内容是HLMDriversActivexx,xx是一个十进制数(device.exe会跟踪系统中每个驱动程序,把加载的驱动程序记录在Active键下)。

COM_Init先分配一个HW_INDEP_INFO结构体,这个结构体是独立于串口硬件的头信息(MDD、PDD、SER16550都包含自己独特的结构体,具体的结构体定义请参见串口驱动源码),分配之后再初始化结构体中每个成员,初始化结构体后调用 OpenDeviceKey((LPCTSTR)Identifier)打开HLMDriversActivexxKey包含的注册表路径,在这里路径一般为HLMDriversBuiltInSerial,即串口的驱动程序信息在注册表中所处的位置。COM_Init接着在HLMDriversBuiltInSerial下查询DeviceArrayIndex、Priority256的值,Priority256指定了驱动程序的优先级,如果没有就用默认的优先级。接下来调用GetSerialObject(DeviceArrayIndex),这个函数由PDD层定义,返回HWOBJ结构体,这个结构体主要包含PDD层和SER16550定义的函数的指针。

也就是说MDD通过调用这个函数才能调用底层实现的函数。接下来的大多数工作都是调用底层函数实现初始化。第一个调用的底层函数SerInit主要设置由用户设置的硬件配置,例如线路控制、波特率。它调用Ser_GetRegistryData函数得到保存在注册表中的硬件信息,Ser_GetRegistryData在内部调用系统提供的DDKReg_GetIsrInfoDDK和DDKReg_GetWindowInfo函数得到在HLMDriversBuiltInSerial下保存的IRQ、SysIntr、IsrDll、IsrHandler、IoBase、IoLen。IRQ是逻辑中断号,IsrDll表示当前驱动程序的可安装ISR所在的DLL名称,IsrHandler 表示可安装ISR的函数名称。
在这里顺便提一下可安装ISR,读者在我以前发表的关于OAL的文章中可以了解到OEM在OEMInit函数中关联IRQ和SysIntr,当硬件设备发生中断时,ISR会禁止同级和低级中断,然后根据IRQ返回关联的SysIntr,内核根据ISR返回的SysIntr唤醒相应的IST(SysIntr与IST创建的Event关联),IST处理中断之后调用InterruptDone解除中断禁止。在OEMInit中关联的缺点是一旦编译了CE内核后就无法添加这种关联了,而一些硬件设备会随时插拔或者共享中断,要关联这样的硬件设备解决方法就是可安装ISR,可安装ISR专用于处理指定的硬件设备发出的中断,所以如果硬件设备需要可安装ISR必须在注册表中添加IsrDll、IsrHandler。多数硬件设备采用CE默认的可安装ISR giisr.dll,格式如下:

"IsrDll"="giisr.dll"

"IsrHandler"="ISRHandler"


如果一个硬件驱动程序需要可安装ISR而开发者又不想自己写一个,那么可以利用giisr.dll来实现。除了在注册表中添加如上所示外,还要在驱动程序中调用相关函数注册可安装ISR。伪代码如下:

g_IsrHandle = LoadIntChainHandler(IsrDll, IsrHandler, (BYTE)Irq);

GIISR_INFO Info;

PHYSICAL_ADDRESS PortAddress = {PhysAddr, 0};

TransBusAddrToStatic(BusType, dwBusNumber, PortAddress, dwAddrLen, &dwIOSpace, &(PVOID)PhysAddr)

Info.SysIntr = dwSysIntr;

Info.CheckPort = TRUE;

Info.PortIsIO = (dwIOSpace) ? TRUE : FALSE;

Info.UseMaskReg = TRUE;

Info.PortAddr = PhysAddr + 0x0C;

Info.PortSize = sizeof(DWORD);

Info.MaskAddr = PhysAddr + 0x10;

KernelLibIoControl(g_IsrHandle, IOCTL_GIISR_INFO, &Info, sizeof(Info), NULL, 0, NULL);


LoadIntChainHandler函数负责注册可安装ISR,参数1为DLL名称,参数2为ISR函数名称,参数3为IRQ。TransBusAddrToStatic函数在后面讲。如果要利用giisr.dll作为可安装ISR,必须先填充GIISR_INFO结构体,CheckPort=TRUE表示giisr要检测指定的寄存器来确定当前发出中断的是否是这个设备。PortIsIO表示寄存器地址属于哪个地址空间,FALSE表示是内定空间,TRUE表示IO空间。UseMaskReg=TRUE表示设备有一个掩码寄存器,专用于指定当前设备是否是中断源,也就是发出中断,而MaskAddr表示掩码寄存器的地址。如果对Info.Mask赋值,那么PortAddr表示一个特殊的寄存器地址,这个寄存器的值与Mask的值&运算的结果如果为真,则证明当前设备是中断源,否则返回SYSINTR_CHAIN(表示当前ISR没有处理中断,内核将调用ISR链中下一个ISR),如果UseMaskReg=TRUE,那么MaskReg寄存器的值与PortAddr指定的寄存器的值&运算的结果如果为真,则证明当前设备是中断源。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

双系统将是下述内容的主要介绍对象,通过这篇文章,小编希望大家可以对双系统的相关情况以及信息有所认识和了解,详细内容如下。

关键字: 双系统 Windows Linux

今天,小编将在这篇文章中为大家带来Windows 11系统的有关报道,通过阅读这篇文章,大家可以对Windows 11系统具备清晰的认识,主要内容如下。

关键字: Windows 操作系统

串行通信需要传输的数据通过调制器(Modulator)将数据转换为模拟信号,经过信号调制(Modulation)后在传输线上传输,接收端通过解调器(Demodulator)将信号解码还原成原始数据。

关键字: 串口 串行通信 并行通信

(全球TMT2023年9月8日讯)亚马逊云科技日前在一年一度的存储服务创新日上宣布推出诸多亚马逊云科技存储服务的新功能,其中重点包括为支持人工智能/机器学习、大数据分析等数据密集型工作负载进一步提升Amazon Ela...

关键字: 亚马逊 FOR IC Windows

中断机制在单片机及嵌入式系统中是重中之重,我们必须深入理解。首先我们要明白一点:CPU执行指令代码,并非一直顺序地逐条执行,而是可能突然跳到某段代码上去的。因为这段代码的优先级更高,或者说它更加紧迫,CPU必须暂时放下手...

关键字: 中断 单片机 嵌入式系统

PIC单片机是基于RISC系统结构的单片机,最初的设计是支持PDP(编程数据处理器)计算机。大量的操作可以用来控制外围设备。PIC单片机比微控制器具有更快的程序执行能力。它是由微芯片技术公司于1889年发明的,是一种8位...

关键字: PIC单片机 定时器 中断

STC单片机是一款增强型51单片机,完全兼容MCS-51,还增加了新的功能,比如新增两级中断优先级,多一个外中断,内置EEPROM,硬件看门狗,具有掉电模式,512B内存等。还支持ISP下载,不用编程器,只要一个MAX2...

关键字: 单片机 看门狗 中断

什么是PIC中断程序呢?形象的生活比喻就比如你现在这在看我的文章,突然你的朋友喊你一起去烤地瓜,这时候你就中断了看文章和朋友烤地瓜去了,烤完地瓜之后你又回来看文章。烤地瓜这件事就好比中断程序,他中断了你看文章这件事。在程...

关键字: PIC 中断 标志位

MCS—51系列单片机内部只需两个外部接中断连源输入端,当外部接连源多于两个时,就必须进行拓宽,下面介绍几种简略的拓宽办法:

关键字: 单片机 软件 中断

51 单片机内部有一个全双工串行接口。什么叫全双工串口呢?一般来说,只能接受或只能发送的称为单工串行;既可接收又可发送,但不能同时进行的称为半双工;能同时接收和发送的串行口称为全双工串行口。串行通信是指数据一位一位地按顺...

关键字: 单片机 全双工 串口
关闭
关闭