分类: 嵌入式
2013-07-17 22:30:38
上一节分析了网卡驱动的数据结构与系统中不同的层次数据结构的相互关系,作为驱动程序的主要目的,就是要建立一个符合系统要求的数据结构关联,只有建成了完整的数据结构关联,系统才能够使用网卡驱动。本节从网卡驱动相关的数据结构的动态创建过程出发,了解驱动程序的配置安装过程。
对网卡来说,该安装过程首先分为两部步:第一步,对各个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调用相应的网络层接收程序进行接收。