本文介绍了VxWorks Workbench开发环境相关的快速教程

1. 启动Wind River Workbench

可以按照如下步骤来启动Wind River Workbench IDE(Integrated Develoment Environment),从菜单选择,Applications men -> Development -> Wind River Workbenche, 或者从命令行运行/opt/WindRiver/workbench-4/startWorkbench.sh,下面的窗口将会询问并让我们选择工作空间workspace。

WRS Workspace How To

这儿的Workspace是你的项目存放的地方,建议将workspace放置到你的Home目录下(/home.nfs/)。

5.3 AM79C97X驱动的动态配置安装及使用过程

5.3.1 AM79C97X驱动的动态配置安装过程

上一节分析了网卡驱动的数据结构与系统中不同的层次数据结构的相互关系,作为驱动程序的主要目的,就是要建立一个符合系统要求的数据结构关联,只有建成了完整的数据结构关联,系统才能够使用网卡驱动。本节从网卡驱动相关的数据结构的动态创建过程出发,了解驱动程序的配置安装过程。

对网卡来说,该安装过程首先分为两部步:第一步,对各个PCI设备挨个进行检查,发现其中的AM79C97X网络芯片设备,其过程如图5.15所示。

VxWorks Network Device Driver

图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控制芯片的网络功能配置流程。

VxWorks Network Device Driver

图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安装中断服务程序。

VxWorks Network Device Driver

图5.17 函数sysLn97xEndLoad形成的顶层结构

5.3.2 AM79C97X驱动使用过程

在驱动程序安装之后,就可以使用网络层就可以使用muxLib提供的通用函数接口,首先网络层调用muxBind绑定一个网络服务形成如图5.14所示的结构图,然后就可以通过调用muxSend发送数据,如果网卡接收到数据,则自动通过中断的方式调用回调函数muxReceive调用相应的网络层接收程序进行接收。

4.2.3 PCI中断处理函数库pciIntLib

在库文件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]链表对应的数据结构。

5.1 概述

本章将通过AM79C97X网络通信芯片的例子来说明网卡的驱动原理。该通信芯片不仅具有网络通信功能,而且还建有PCI接口控制管理功能。在操作系统通过对AM79C97X的PCI接口的自动配置为该设备分配内存资源和IO资源,这些内存资源和IO资源将是CPU控制AM79C97X网络通信芯片的主要的主要通道。

表4.1列出了AM79C97X芯片的PCI配置寄存器。在配置寄存器的10h地址记录了该PCI设备对IO资源的要求:32字节;在配置寄存器的14h地址记录了该PCI设备对内存资源的需求:32字节。其实这两个地址所映射的内容是一样的,即CPU控制AM79C97X芯片的主要接口。一般来说既有IO接口又有内存接口的情况下,首先选用内存接口,因为内存接口访问速度要远高于IO接口。

4.2 PCI配置驱动程序的结构

前面已经说过,PCI设备是一种接口标准,所有PCI设备都要服从这个标准,因此对于操作系统来说,无需为每个设备都单独编写一套驱动程序,而只需要写出一套符合PCI规范的驱动程序就能够满足操作系统配置PCI接口的要求了。从这个意义上来说,PCI接口驱动程序的结构相对要简单一些。

PCI总线驱动主要为上层软件提供两方面的接口,一方面用于系统内PCI设备接口的自动配置,另一方面则是用于系统内PCI设备接口的手工配置。对自动配置来说,它提供了一个自动配置函数,通过调用该函数完成了系统内所有需要自动配置的PCI接口的自动配置,并建立一个专门的数据结构来保存系统中所有自动配置设备的必要的信息;而对于手工配置来说,它也提供了手工配置的一系列操作函数。鉴于目前大多数的设备都采用自动配置的情况,本节只分析自动配置驱动程序结构。

图4.2描述了PCI接口驱动程序的结构。

VxWorks PCI Interface Device Driver Structure

图4.2 PCI接口驱动程序的结构下面将针对图中的各个函数进行详细说明。

4.2.1 基本配置函数库pciConfigLib

该函数库主要提供了一些PCI配置空间访问的一些基本的方法,通过这些底层的访问方法,函数库pciAutoConfigLib就可以完成系统内PCI接口的自动配置。本节还是通过最基本的函数分析研究函数库peiConfigLib提供给上层的基本的访问控制方法。