驱动程序的结构包括三个部分:初始化部分,函数功能部分和中断服务程序ISR。初始化部分初始化硬件,分配设备所需的资源,完成所有与系统相关的设置。如果是字符设备,首先调用iosDrvlnstall()来安装驱动程序,把中断向量和ISR挂上,然后调用iosDevAdd()来把驱动程序加到IO系统中:如果是块设备,首先把中断向量和ISR挂上,在内存中分配一个设备结构,然后初始化该结构。用户要使用该设备时,先调用设备初始化部分myInit()(一般放在sysLib.C中),再调用设备创建函数myDevCreate()返回一个BLK_DEV结构的指针,供文件系统初始化函数如
dosFsDevInit()使用。以下为块设备的初始化示例代码:

struct MyDevice{ //自定义的设备结构 

BLK_DEV dev; 必须在结构的开始 

Int interrupt;设备使用的中断号 

.... 

} 

int mylnit(){ //初始化函数 

MyDevicelnit();//硬件初始化函数 

MyDevice* Device =(MyDevice*)malloc(sizeof(MyDevice)); 

//为设备结构分配内存 

Device->dev.bd_blkRd = Read;//初始化设备结构 

Device->dev_blkWrt= Write; 

intConnect(imToVec(9),my_ISR);//连接中断向量和中断服务程序ISR 

)


  ISR处理硬件中断,管理具体的硬件输入输出,同时和驱动程序的其它部分通信。ISR中第一条指令用来读APIC的中断服务寄存器,以通知CPU已经接到中断请求。

my_ISR(int va1)//中断断服务函数 

sysOutByte(0xa0,0x02);//中断响应 

..... 

semGive(my_sem);//通知其它程序中断处理完毕 

}


   函数功能部分完成系统指定的功能,对于字符设备,这些函数就是指定的7个标准函数;对于块设备,则是在BLK_DEV或SEQ_DEV结构中指定的功能函数。应当注意的是,系统在调用块标准函数时,传递的设备结构指针是设备结构中BLK_DEV结构的指针,由于BLK_DEV定义在设备结构的开始处,该指针实际上也就是设备结构的指针。


STATUS Read (MyDevice* pDev,int startBlk,int numBlk,char*pBuf) 

{ 

........ 

SemTake(my sem,WAI1 OREVER);//等待设备IO执行完成 
)


Vxworks内核驱动基本结构:


三张表:1. 系统设备表  2. 系统驱动表 3. 文件描述符表



    Vxworks 内部对每个设备使用DEV_HDR 数据结构进行表示:


Typedef struct 

 

  { 

 

     DL_NODE    node; 

 

     Short      drvnum; 

 

     Char       *name; 

 

  }


    该结构中给出了链接指针(用以将该结构串入队列中)、驱动索引号、设备节点名称。内核提供这个结构较为简单,只存储了一些设备的关键信息。底层驱动对其驱动的设备都有一个自定义数据结构表示,其中包含了驱动设备寄存器基地址,中断号,可能的数据缓冲区,保存内核回调函数的指针,以及一些标志位。最关键的一点是DEV_HDR必须是自定义数据结构的第一个成员变量,因为这个用户自定义结构最后需要添加到系统设备队列中,必须能够在用户定义结构与DEV_HDR结构之间进行转换,而将DEV_HDR结构设置为用户自定义结构的第一个成员变量就可以达到目的。


typedef struct 

 

  { 

 

         DEV_HDR     pFCcardHdr; 

 

         BOOL        created; 

 

         char *      buf_virts; 

 

         UINT32      iobase; 

 

         UINT32      membase; 

 

         char        irq; 

 

         UINT32      irqvec; 

 

         UINT32      Bus; 

 

         UINT32      Device; 

 

         UINT32      Func; 

 

  }DRV_CTRL;


    系统提供了iosDevAdd(DEV_HDR *pDevHdr, char *name, int drvnum)用于驱动程序调用注册一个设备。第三个参数是设备对应的驱动程序索引号。这个驱动号是iosDrvInstall函数的返回值,在设备初始化函数中,我们首先调用iosDrvInstall注册驱动,然后使用iosDrvInstall 函数返回的驱动号调用 iosDevAdd添加设备到系统中通过这两步设备就可以被用户程序使用了。


    用户调用open函数打开一个设备文件时,系统将以传入的文件路径名匹配系统设备的设备节点名,匹配方式是最佳匹配。


 


系统驱动表:


    系统驱动表包含了当前注册到I/O子系统下的所有驱动。这些驱动可以直接驱动硬件工作的驱动层。系统驱动表底层实现是一个数组,数组元素数目在内核初始化过程中指定。I/O子系统提供iosDrvInstall供驱动程序注册,iosDrvInstall原型如下:


Int iosDrvInstall 

 

  ( 

 

    FUNCPTR  pCreate,   FUNCPTR  pDelete,   

 

    FUNCPTR  pOpen,    FUNCPTR  pClose,   

 

    FUNCPTR  pRead,   FUNCPTR  pWrite,  FUNCPTR  pIoctl /*pointer to driver ioctl function*/ 

 

  )



    一个设备驱动在初始化过程中一方面完成硬件设备寄存器配置,另一方面就是向I/O子系统注册驱动和设备。一个驱动并不需要实现上述所有函数,无须实现的函数直接传递NULL指针就可以了。iosDrvInstall 函数的基本实现即遍历drvTable数组,查询一个空闲表项,用传入的函数地址对各成员变量进行初始化。


 


系统文件描述符表


    文件描述符表表项索引被用做文件描述符ID,即open函数返回值。对于文件描述符,需要注意:标准输入、标准输出、标准错误输出虽然使用0,1,2三个文件描述符,但是可能在系统文件描述符表中只占用一个表项,即都使用同一个表项。Vxworks内核将0,1,2三个标准文件描述符与系统文件描述符表中的内容分开进行管理。


    系统文件描述符中的内容主要是针对硬件设备,使用一次open函数调用就占用一个表项:


int fd = open(DevName, 2,0);



    应用程序每调用一次open函数,系统文件描述符表中就增加一个有效表项,直到数组满为止。此时open函数调用将以失败返回,因此注意如果需要反复打开设备的话,一定要在设备不用的时候调用close函数关闭该描述符指向的设备,并在每次调用open函数之后检查返回的文件描述符是否合法。