pSoSystem下的通用网络驱动模型设计与分析
发布时间:2010-7-31 19:59
发布者:lavida
pSoSystem操作系统简介 pSoSystem是一种专门用以嵌入式处理器的高性能的、模块化的操作系统.基于开放操作系统标准,它提供了一种复杂的多任务运行环境.同时,它也提供了一系列的集成开发工具,这些开发工具可用于Unix系统,也可用于Windows系统.另外,由于pSoSystem是一种模块化的操作系统,所以,开发人员可以根据需要,选用不同的操作系统模块.这样,就使得我们没有必要把一个庞大的操作系统全部加载到嵌入式系统设备上.比如说,如果我们的应用系统不需要支持文件功能,则可以不用加载文件系统.这样,就可以大大缩减操作系统的尺寸.pSoSystem的整个系统结构如图1所示. ![]() 图1pSOS系统框图 pSoSystem网络设备驱动程序概述 网络驱动在pSoSystem里有作专门的处理,它不是直接和pSOS+内核模块的I/Osupervisor打交道,而是和pNA+网络模块打交道.和I/O监管层一样,为了屏蔽具体硬件之间的差异,pNA+也为网络驱动程序提供了一个中间层,称之为NI(NetworkInterface)层.在NI层,它为上层提供了一系列的标准网络接口函数(如网卡初始化,网络包发送等),这些接口函数是在网络驱动程序里实现,而由pNA+模块里的其它网络层调用.要编写网络驱程,就是要具体实现这几个接口函数.图2是网络驱动程序在pSoSystem中的模型图. ![]() 图2网络驱动模型 通用网络驱动模型的设计 通用网络驱动模型的整体设计思想,就是将独立于具体硬件的操作抽象出来,以形成一个通用的代码框架.具体来说,主要包括以下几个部分: a) 底层驱动和上层应用的分离层次模型设计; b) 由上述分离层次所得到的相应接口函数的设计; c) 网卡数据包接收、发送的抽象代码框架的设计; 下面,本文将就上述3个方面的设计作一个较为全面的分析. 底层驱动和上层应用的分离层次模型设计 显然,这一块的设计是整个驱动模型设计的首要部分.只有将底层驱动和上层应用有效地分离出来,才能保证代码的独立性与重用性,从而也使得驱动程序的开发者不用过多地关心上层应用,符合现代软件的设计思想.关于这一部分的设计,pSoSys2tem已经帮助我们完成,其所提供的网络驱动模型就是一个典型的软件分层设计实例.详情请看图2. 接口函数的设计 一般来说,根据上述所设计的驱动程序分层模型,都会为上下两层的沟通提供一些标准的接口函数.显然,这些接口函数的实现,大部分是和底层硬件具体相关的,但其操作步骤却是大同小异的.因此,在我们的通用驱动模型框架里,就是要抽象出独立于具体硬件的一般操作,以形成一个通用的代码框架,在这里,我们一般就以伪C代码形式来给出各个接口函数的一般实现. (1)NiLan接口函数的设计与分析 NiLan是pNA+层和网络驱动挂接的一个最为重要的接口函数.实际上,早在pNA+模块的加载过程中,pNA+就安装了此函数,其相应的伪C代码如下: UCHAR *SetUpNI(UCHAR *FreeMemPtr) {InstallNi((int(*)()) Nilan, IPaddr, BSP-LAN1-MTU,BSP-LAN1-HWALEN,BSP-LAN1-FLAGS,SysVars.Lan1SubnetMask,0); /*通过这个函数的调用,将NiLan函数安装到了pNA+模块中去了*/ FreeMemPtr=SetupLanParams(BSP-LAN1-PKB,FreeMemPtr); /*在pNA+模块里为网卡要用到的接收与发送等缓存分配空间*/ } 代码1 通过这个函数,pNA+层可以完成所有有关网络应用的调用.其具体做法就是:由pNA+层传入不同的功能号,以达到调用相应具体功能函数的目的,其相应的伪C代码如下: longNiLan(ULONGfunction, union nientry*p) { if(function= =NI-INIT) { return ni-init(); }else { /*根据功能号,调用相应的功能函数*/ switch(function) caseNI-SEND:调用ni-send();break; case其它功能号:调用其它功能函数;break; } } 代码2 (2)ni-init函数的设计与分析 此函数主要是用来配置和初始化网卡的各种硬件和软件资源,具体功能如下所述: a)初始化buffers,主要是将其链成链表,以方便操作; b)初始化网卡相关的寄存器,最重要的就是收发寄存器的首址RxDesc和TxDesc; c)初始化收发寄存器,主要是将其链成队列,以方便内存的循环使用; staticlongni-init(void) { InitBuffers();/*初始化buffer,主要是将 其链成链表*/ InstallIsr();/*安装中断服务程序,最重要 的就是网络数据接收中断*/ InitDescps()/*将收发寄存器链成队列*/ lanInit();/*初始化网卡的各个寄存器*/ } 代码3 网卡数据包收发代码框架的设计与分析 设计通用网卡驱动模型,显然,数据包的收发是最为重要的与具体硬件有关的操作,如何去除具体硬件的相关性,而抽象出独立于各种硬件的一般的收发代码,则显得非常重要.下面,将就网卡收发过程的一般步骤进行分析. (1)网卡数据包的发送过程其具体步骤如下所示 a)应用程序为了发送数据,调用相应的套接字; b)套接字的调用引发pNA+的系统调用,pNA+层则调用NiLan函数将上层的数据传给NI层;NiLan的具体实现参看代码2,这里,主要解释一下其传入的参数;function:功能号,NiLan将根据不同的功能号调用合适的NI层的函数;p:NI层的入口点,即上层和下层交换数据的地方,发送数据时,由这个入口点将相应的数据由pNA+层传入NI层,同样,接收数据时,也是由这个入口点将NI层收到的数据上传给pNA+层. c)NI层收到pNA+层传入的数据之后,则将待发送数据组装成数据帧,以便接下来移 入网卡的发送寄存器发送出去,其相应的实现代码如下所示: staticvoidni-send(char*hwa-ptr,char*pkbpt r,USHORTtype) { tx-hdr=InitMblk();/3初始化三元组,一个三元组里存放一个数据帧*/ FillFrameHead();/*填充帧头*/ TxFillDesc();/*调用TxFillDesc()填充相 应的寄存器以把数据发送出去*/ } 代码4 (2)网卡数据包的接收过程 网卡接收数据的过程不同于发送数据的过程,发送数据时,有一个独立的发送数据的函数,而在网卡的接收数据的过程中,并不存在这样一个独立的函数,网卡数据的接收是通过中断服务程序来完成的,其具体步骤如下: a)网卡产生接收数据的中断; b)中断导致ni-isr()中断服务程序的调用,而在ni-isr()中,调用真正的中断响应程序 ni-poll(),ni-poll()则根据不同的中断事件,调用具体的中断服务程序; static voidni-isr(void) { ienter(); AppModel-run-on-sstack((Pointer)nipoll, Null); ireturn(); } static voidni-poll(void) { for(;;) { if(接收数据中断)RxBufRcv(); if(发送数据中断)TxFillDesc(); if(其它中断)...... } } 代码5 c)对于接收数据的中断而言,在ni-poll()函数里调用的中断响应函数就是RxBufRev(),这个函数是真正负责网卡数据接收的地方,其工作原理就是读取网卡相应的接收寄存器,并通知pNA+层将数据取走; staticvoidRxBufRcv(void) { for(;;) { good=CheckFrame()/*判断接收的数据包是否出错*/ if(good==TRUE)/*如果数据包没有出错,则将它交给pNA+层*/ { /*建立三元组,并通知pNA+层*/ msgBlk=NiFuncs.esballoc((void3)&pktAddr->type,dataLen,0,&frtn); Announce(type,msgBlk,dataLen,IfNum); } } } 代码6 d)通过RxBufRec()函数将数据从网卡中收下后,它最后还要再调用Announce()函数 通知pNA+模块将数据取走.至此,一个数据包的接收过程全部完成;注:Announce是一个回调函数,即在pNA+模块中定义的,由NI层调用的函数; 驱动程序的安装 在pSOS中,一般的驱动程序安装是通过修改drv-conf.c(pSoSystem操作系统里的一个系统配置文件)中的InstallDriver来完成.而网络驱动程序在pSoSystem里有作专门的处理,它是通过调用drvconf.c中的SetUpNi函数来实现的,而SetUpNi则会调用pSoSystem所提供的InstallDriver来最后完成网络驱动程序的安装.当然,最后还需要重新编译pSoSystem的内核,从而将我们的驱动程序模块加载到pSoSystem系统模块中.具体实现可以参看前面的代码1. 结束语 本文只给出了通用网络驱动模型的最重要部分的设计与分析,至于其它一些细节函数,限于篇幅,本文未做详述.有兴趣的读者,可以进一步参看文末所附的参考文献.最后,希望本文能对有心开发类似应用的工程技术人员有所帮助. |
网友评论