3.3.2 函数库intALib

函数库intALib是个汇编函数库,里面保存了与CPU结构相关的中断处理函数。这里进行简单的分析。

1.int intLevelSet (level)
x86系列的CPU并不支持中断级,因此该函数是个空函数。
2. int intLock ()

该函数返回刚intLock函数时CPU的EFLAGS寄存器中的中断允许标志位(IF),然后将中断允许位置0,表示禁止可屏蔽中断。如果需要恢复,则调用函数intUnlock(int)将中断允许标志恢复到intLock调用之前的状态。

intLock()函数既可以在中断级又可以在任务级调用,当在任务级调用时,并不能组织任务的调度,如果需要组织任务调用则需要使用函数taskLock和taskUnlock函数。

3. int intUnlock()
恢复intLock函数调用前CPU中EFLAGS寄存器的中断允许标志。
4. void intVBRSet(baseAddr)
将参数baseAddr指定的中断向量基地址保存到CPU的IDT寄存器中。
5. void intBoiExit()
直接从routineBoi函数中跳转到intExit函数且不再执行C中断函数和routineEoi函数(参见函数库i8259Intr中函数i8259IntBoi的分析)。

3.3.3 函数库i8259Intr

函数库i8259Intr中提供了对8259中断控制器的基本操作函数。分析这个函数之前,有几个问题需要注意:

中断号(IntNum)和IRQ号的关系。同一PIC上的IRQ号和中断号是线性关系,如主片上IRQ0对应中断号0x20,主片上的IRQ1对应中断号0x21等;从片上的IRQ0对应与中断号0x28,从片上的IRQ1对应中断号0x29等。

中断号(IntNum)和中断优先级没有必然的联系。这主要体现在有级联的中断上,加入从片的中断输出连接到中断的IRQ2上,那么主片上IRQ0和IRQ1的中断优先级总高于从片上的中断;而主片上IRQ3~IRQ7的中断优先级总低于从片上的中断。

表3.1给出了中断号、IRQ号与优先级的关系。主从片连接图参见图3.1。

表格 3.1 PC机对应的中断号、IRQ号与优先级的关系

3.3.1 函数库intArchLib

函数库主要为上层应用程序提供了一组与外部硬件无关的中断控制函数。其中比较常用的就是函数intConnect、intEnable、intDisable。


1. STATUS intConnect

    (

    VOIDFUNCPTR *vector,

    VOIDFUNCPTR routine,

    int parameter

    )

该函数的作用是将一个C函数与一个硬件中断连接起来,当发生了硬件中断时,自动执行该C函数。

它主要完成了三件事情,一是调用函数(* intEoiGet)(......)获取该中断的ISR处理前后需要执行的函数routineBoi、routineEoi及其参数;

二是调用函数intHandlerCreateI86填充数组intConnectCode,主要填充routineBoi、routine、routineEoi,组成完整的中断执行代码;

三是调用函数intVecSet将数组intConnectCode存放到参数vector指定的位置。

注意:代码中调用intHandlerCreate的情况属较老的vxWorks版本,对于新版本已经被intHandlerCreateI86函数所代替,因此不再过多分析。

2.4 串口驱动程序的动态分析

串口驱动程序的动态分析主要分为两部分,第一部分是串口驱动程序的初始化,第二部分则是串口驱动程序的应用。

2.4.1 串口驱动程序的初始化

串口驱动程序的初始化主要包括一下几个部分。

l 硬件地址的设置(指定)。硬件地址的指定可以通过在函数库中直接指定相关变量的数值而达到目的,不一定非要执行相关的函数。如sysSerial函数库。因此它不需要函数调用过程来实现。

l 硬件的初始化。主要是通过函数执行向硬件的控制寄存器写入特定的数值来实现,通常需要函数指定的动态过程。

l 中断处理程序的安装。需要函数执行来安装。

l 各个函数库的初始化。主要是函数库中相关数据结构的初始化,一般需要动态执行和静态指定相结合来实现。

l 串口驱动程序数据结构的搭建。主要体现在数据结构

下面从vxWorks操作系统启动的过程来分析驱动程序的安装过程。先看图2.17。

3.1 概述

中断是计算机系统中很常用的一种工作方式。在没有中断的计算机系统中,如果要求CPU在某一外设的状态发生改变时立刻进行处理,为了保证及时处理CPU就必须不断查询该外设状态是否发生改变,一旦发生改变则做出相应的处理。显然这种方式会因为CPU不断查询而浪费极大资源。中断方式的出现则解决了这个问题,它只在外设需要CPU做出处理的时候向CPU发出中断信号,CPU收到中断信号后则暂时搁置正在处理的任务转入外设请求处理,待处理完毕后则重新返回继续执行已搁置的任务。

一般来说中断可以分为两大类,硬中断和软中断。其中硬中断指的是来自CPU以外的IO设备或者电路产生的中断,又称作外部中断,硬中断则又可分为可屏蔽中断和非屏蔽中断。非屏蔽中断主要用于处理某些影响系统正常运行的外部事件,如电源故障、RAM奇偶校验错等等。非屏蔽中断不能被CPU用指令CLI来禁止。一旦出现就必须响应。而可屏蔽中断则正好相反。

软中断是由CPU内部状态或者执行中断指令引起中断。对PC机来说,软中断又可以分为微处理器专用中断和指令形式软中断两种。在执行中,如果CPU发现出现了某种状态就会转而执行专用的处理程序,这部分中断成为微处理器专用中断,如除法错、单步中断、NMI中断、断点中断、溢出错、屏幕打印等等。指令中断则是执行了INT N指令产生的中断,如DOS中断、ROM-BIOS中断。

在PC机上最常见中断控制芯片为i8259可编程中断控制器(Programmable Interrupt Controller,PIC),i8259采用两级方式,主8259和从8259一共两片,其中从8259中断输出连接到主8259的2号中断位置。如图3.1所示。

VxWorks UART Driver, Interrupt Routine

图3.1 i8259中断控制器的连接方式

3.2 中断控制器i8259概述

本节并不打算用大段的内容描述i8259中断控制器,只是重点强调几个需要注意的几个问题。关于i8259中断控制器详细的描述可以参考intel公司i8259控制器的相关资料。

2.3.5 函数库i8250Sio

从图2.13可以看出,函数库ttyDrv与底层函数库的接口形式为一个通用的结构接口SIO_CHAN,该接口中保存了一些硬件操作的函数指针,显而易见,对于底层函数库来说,实现结构SIO_CHAN中定义的几个函数指针对应的函数则是其最根本的目的。从下面即将分析的i8250Sio库来看,它也正是这么做的。

如图2.16。和图2.12相比,指针pSioChan从SIO_CHAIN的结构变成了I8250_CHAN,从SIO_CHAN和I8250_CHAN的对比来看,I8250_CHAN结构定义一开始就完全包含了SIO_CHAN结构中的元素,因此在内存中SIO_DRV_FUNCS函数对应的相对地址也都是完全一样的,因此可以用SIO_CHAN结构指针指向I8250_CHAN结构变量而不会出现混乱,这里依然采取了多态的思想,不过将I8250_CHAN结构定义成下列格式可以使多态的概念更加清晰。



    typedef struct

    {

    SIO_CHAIN    sioChain;

    STATUS      (*getTxChar) ();

    STATUS      (*putRcvChar) ();

    void *      getTxArg;

......

}I8250_CHAN;

VxWorks UART Driver

图2.16 函数ttyDrv与i8250控制器函数库的接口

这里不再详细分析硬件操作的详细内容,重点还是放在函数库的结构分析上,如有有需要了解具体的硬件操作可以参考i8250控制芯片的数据手册。