为了实现应用层程序的平台无关性,操作系统为应用层提供了一套标准的接口函数,这些接口函数在所有的平台上都保持一致,只是随着平台的变化,底层驱动或接近驱动部分操作系统中间层可能会随着调整。这样可以使用户程序独立于具体的硬件平台,增加了应用层开发的效率,避免了重复编码。通用操作系统GPOS(General Purpose Operating System)比如Unix,Linux,将这套提供给应用层的标准接口函数从操作系统中独立出来,专门以标准库的形式存在,增加了应用程序的平台无关性,平台之间的差别完全被操作系统屏蔽。
本文介绍了VxWorks Workbench开发环境相关的快速教程
可以按照如下步骤来启动Wind River Workbench IDE(Integrated Develoment Environment),从菜单选择,Applications men -> Development -> Wind River Workbenche, 或者从命令行运行/opt/WindRiver/workbench-4/startWorkbench.sh,下面的窗口将会询问并让我们选择工作空间workspace。
这儿的Workspace是你的项目存放的地方,建议将workspace放置到你的Home目录下(/home.nfs/)。
本章将通过AM79C97X网络通信芯片的例子来说明网卡的驱动原理。该通信芯片不仅具有网络通信功能,而且还建有PCI接口控制管理功能。在操作系统通过对AM79C97X的PCI接口的自动配置为该设备分配内存资源和IO资源,这些内存资源和IO资源将是CPU控制AM79C97X网络通信芯片的主要的主要通道。
表4.1列出了AM79C97X芯片的PCI配置寄存器。在配置寄存器的10h地址记录了该PCI设备对IO资源的要求:32字节;在配置寄存器的14h地址记录了该PCI设备对内存资源的需求:32字节。其实这两个地址所映射的内容是一样的,即CPU控制AM79C97X芯片的主要接口。一般来说既有IO接口又有内存接口的情况下,首先选用内存接口,因为内存接口访问速度要远高于IO接口。
上一节分析了网卡驱动的数据结构与系统中不同的层次数据结构的相互关系,作为驱动程序的主要目的,就是要建立一个符合系统要求的数据结构关联,只有建成了完整的数据结构关联,系统才能够使用网卡驱动。本节从网卡驱动相关的数据结构的动态创建过程出发,了解驱动程序的配置安装过程。
对网卡来说,该安装过程首先分为两部步:第一步,对各个PCI设备挨个进行检查,发现其中的AM79C97X网络芯片设备,其过程如图5.15所示。
图5.15 根据PCI配置信息识别网卡类型并记录基本信息
函数sysHwInit()调用了函数pciConfigForeachFunc (0, TRUE, (PCI_FOREACH_FUNC) sysNetPciInit, NULL),对所有PCI设备执行sysNetPciInit函数。 sysNetPciInit函数的作用是对所有PCI设备识别,如果能够识别则从中读取必要的信息并启动网卡的PCI功能。在函数库sysNet中定义了一个数据结构
LOCAL VEND_ID_DESC vendorIdEnet [] =
{
#if defined(INCLUDE_DEC21X40_END)
{DEC_PCI_VENDOR_ID, sysDec21x40PciInit},
#endif /* INCLUDE_DEC21X40_END */
#if defined(INCLUDE_LN_97X_END)
{AMD_PCI_VENDOR_ID, sysLan97xPciInit},
#endif /* INCLUDE_LN_97X_END */
#if defined(INCLUDE_EL_3C90X_END)
{THREECOM_PCI_VENDOR_ID, sysEl3c90xPciInit},
#endif /* INCLUDE_EL_3C90X_END */
#if defined(INCLUDE_GEI8254X_END)
{INTEL_PCI_VENDOR_ID, sys543PciInit},
#endif /* INCLUDE_GEI8254X_END */
#if defined(INCLUDE_FEI_END)
{INTEL_PCI_VENDOR_ID, sys557PciInit},
#endif /* INCLUDE_FEI_END */
{0xffffffff, NULL} /* last entry */
};
这个结构包括了对不同类型PCI网卡的信息读取及PCI功能初始化。sysNetPciInit函数利用vendorIdEnet数组中各个元素的PCI初始化函数逐个进行试探,当网卡和对应的初始化函数匹配后读取必要的信息并将读取的内容记录结构PCI_BOARD_RESOURCE ln97xPciResources中,记录的信息包括VendorId、deviceId、映射的IO地址及memory地址。有了这些信息之后系统就可以控制该网卡设备。
不过到目前为止系统还没有真正开始硬件的初始化设置。此时还需要做的一部是打开该设备的PCI功能以确保后面的硬件配置能够顺利进行。
配置安装的第二步,就是完成am79c97x控制芯片的网络功能的配置,主要包括相关变量的初始化以及数据结构联系的构建。图5.16给出了am79c97x控制芯片的网络功能配置流程。
图5.16 网卡驱动的动态配置安装过程
图5.16仅仅给出了与网卡驱动直接相关的部分,并没有对网络层及以上层的初始化函数机型分析。
首先是函数muxLibInit()主要完成函数库muxLib内部变量(muxLibState、addrResList[]、endList)的初始化。
endDevTbl数组中保留了系统支持的所有的设备的Load函数,函数usrEndLibInit()对每个设备的Load函数,调用函数muxDevLoad驱动各个Load函数完成对设备的Load。如果Load成功则建立建立完整的数据结构联系,最后调用函数。
endDevTbl数组的定义如下:
END_TBL_ENTRY endDevTbl [] =
{
#ifdef INCLUDE_EL_3C90X_END
{0, EL_3C90X_LOAD_FUNC, EL_3C90X_LOAD_STR, EL_3C90X_BUFF_LOAN, NULL, FALSE},
#endif /* INCLUDE_EL_3C90X_END */
#ifdef INCLUDE_LN_97X_END
{0, LN_97X_LOAD_FUNC, LN_97X_LOAD_STR, LN_97X_BUFF_LOAN, NULL, FALSE},
#endif /* INCLUDE_LN_97X_END */
#ifdef INCLUDE_FEI_END
{0, FEI82557_LOAD_FUNC, FEI82557_LOAD_STRING, FEI82557_BUFF_LOAN, NULL, FALSE},
#endif /* INCLUDE_FEI_END */
#ifdef INCLUDE_DEC21X40_END
{0, END_DC_LOAD_FUNC, END_DC_LOAD_STRING, END_DC_BUFF_LOAN, NULL, FALSE},
#endif /* INCLUDE_DEC21X40_END */
#ifdef INCLUDE_ELT_3C509_END
{0, END_3C509_LOAD_FUNC, END_3C509_LOAD_STRING, END_3C509_BUFF_LOAN, NULL, FALSE},
#endif /* INCLUDE_ELT_3C509_END */
#ifdef INCLUDE_ULTRA_END
{0, END_ULTRA_LOAD_FUNC, END_ULTRA_LOAD_STRING, END_ULTRA_BUFF_LOAN, NULL, FALSE},
#endif /* INCLUDE_ULTRA_END */
#ifdef INCLUDE_ENE_END
{0, END_ENE_LOAD_FUNC, END_ENE_LOAD_STRING, END_ENE_BUFF_LOAN, NULL, FALSE},
#endif /* INCLUDE_ENE_END */
#ifdef INCLUDE_GEI8254X_END
{0, GEI8254X_LOAD_FUNC, GEI8254X_LOAD_STR, GEI8254X_BUFF_LOAN, NULL, FALSE},
#endif /* INCLUDE_GEI8254X_END */
{0, END_TBL_END, NULL, 0, NULL, FALSE}
};
在函数usrEndLibInit()通过函数muxDevLoad()驱动各个设备的Load函数的过程分为四步,第一步根据endDevTbl数组各元素指定的参数检查endList表,看是否已经安装相应设备的驱动,如果已经安装则直接退出,否则进入第二步;第二步,调用相应的endLoad函数(这里是sysLn97xEndLoad函数)建立图5.7、图5.8、图5.9以及图5.17的数据结构,其核心为数据结构LN_97X_DRV_CTRL;第三步,将结构LN_97X_DRV_CTRL中的endObj元素装载到endList链表,形成图5.4所示的数据结构;第四步,调用函数muxDevStart安装中断服务程序。
图5.17 函数sysLn97xEndLoad形成的顶层结构
在驱动程序安装之后,就可以使用网络层就可以使用muxLib提供的通用函数接口,首先网络层调用muxBind绑定一个网络服务形成如图5.14所示的结构图,然后就可以通过调用muxSend发送数据,如果网卡接收到数据,则自动通过中断的方式调用回调函数muxReceive调用相应的网络层接收程序进行接收。
在库文件src\dev\pci\pciIntLib.c中描述了PCI设备的中断处理方法。这个函数库并不是在PCI自动配置的时候调用,因为这时候各PCI设备的中断处理函数还不明确,只能是作为具体PCI设备初始化的时候调用该函数库从而完成该中断向量初始化功能。
根据PCI规范,PCI设备function的中断可以连接到4个IRQ中断的一个,对系统的PCI总线来说,所有设备中断都将连接在这4根IRQ上,因此当一个PCI中断IRQ信号到来时,系统并不知道具体是那个PCI function发生了中断,它必须调用系统中所有中断号为IRQ的function,这也就是中断处理函数pciInt要做的工作。
当CPU发现了一个PCI总线上的中断,它并不知道到底是那个设备中断的,为了处理的方便,系统构造了一个数组pciIntList,这个数组中一共有4个元素,分别对应于IRQ的4个中断。每个元素就是一个链表头,该链表中链接的是系统中所有中断IRQ号为function的中断处理函数。图4.9表示pciIntList[0]链表对应的数据结构。
© 2023 VxWorks Club