VXWORKS系统AX88796网卡代码学习
- 格式:docx
- 大小:254.95 KB
- 文档页数:7
VXWORKS系统AX88796网卡驱动代码学习一之前学习了AX88796网卡的大体流程,这周主要针对具体代码进行分析学习。
一、初始化驱动程序和设备当设备上电后,经过系统一系列的自检操作流程后,进入END程序的加载,从源码看到,网卡驱动的加载函数是ne2000EndLoad( ),此函数的作用是初始化驱动程序和设备:首先通过调用GetNetCfgFromFlash()函数来获得目标机的MAC地址和IP地址,如果不存在则采用默认222.111.112.204作为IP1地址。
ne2000Parse (pDrvCtrl, initString)函数来解析设备初始化字符串,其中initString是指向所有的设备的具体参数指针,解析的字符串包含网卡编号地址,IP地址,中断向量,设置配置寄存器,8位或者16位访问格式等,通过strtok_r函数来分割字符串分析。
strtok_r函数原型是char *strtok_r(char *str, const char *delim, char **saveptr);其中第一个参数是待分割字符串,第二个参数是分隔符,第三个用来保存切分是的上下文,第一次调用可以为空。
如果连续调用分割字符,第一个参数可以为null,第三个参数则是上次调用的返回值。
比如tok = strtok_r (initString, ":", &holder);if (tok == NULL)return (ERROR);pDrvCtrl->unit = atoi (tok);上面的代码是通过‘:’分割字符串initString,通过atoi将字符装换成整形,也就是网口编号地址,如0x8000000,0x8200000,0x8400000。
接下来初始化一个END_OBJ结构并用参数列表中的数据进行填充,并创建和初始化信号量和协议列表。
if (END_OBJ_INIT (&pDrvCtrl->endObj, (DEV_OBJ *)pDrvCtrl, NE2000_DEV_NAME,pDrvCtrl->unit, &ne2000FuncTable,"ne2000 Enhanced Network Driver") == ERROR) /*初始化初始化一个END_OBJ结构并用参数列表中的数据进行填充,并创建和初始化信号量和协议列表。
*/if (END_MIB_INIT (&pDrvCtrl->endObj, M2_ifType_ethernet_csmacd,&pDrvCtrl->enetAddr[0], 6, ETHERMTU,END_SPEED) == ERROR)/*初始化结构的MIB2部分* if (ne2000MemInit (pDrvCtrl) == ERROR) /* 执行内存分配*/pDrvCtrl->netCtrlSem=semMCreate(SEM_Q_PRIORITY|SEM_DELETE_SAFE|SEM_INVERSION_SAF E);END_OBJ_READY (&pDrvCtrl->endObj,IFF_NOTRAILERS | IFF_MULTICAST | IFF_BROADCAST);return (&pDrvCtrl->endObj); /* 设置标志以指示就绪*/加载完以上设备后,启动设备。
二、启动设备通过ne2000Start( )实现,该函数启动设备并在中断模式下运行,需要使用SYS_INT_CONNECT (pDrvCtrl, ne2000Int, pDrvCtrl->ivec, &result)来实现与中断函数ne2000Int 关联,目的是将当前进程连接到硬件中断,中断向量与网口编号相关联,当某个网卡有数据收发是就触发ne2000Int()函数。
if(pDrvCtrl->unit == 0){if(ne0 == 0){neTaskSem0 = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);taskSpawn("neTask0", 40,0, 100000,(FUNCPTR)neProcess0,(int)pDrvCtrl,2,3,4,5,6,7,8,9,0);ne0++;}}if(pDrvCtrl->unit == 1){if(ne1 == 0){neTaskSem1 = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);taskSpawn("neTask1", 40, 0, 100000,(FUNCPTR)neProcess1,(int)pDrvCtrl,2,3,4,5,6,7,8,9,0);ne1++;}}if(pDrvCtrl->unit == 2){if(ne2 == 0){neTaskSem2 = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);taskSpawn("neTask2", 40, 0, 100000,(FUNCPTR)neProcess2,(int)pDrvCtrl,2,3,4,5,6,7,8,9,0);ne2++;}}上面的代码中:建立互斥信号量neTaskSem0,neTaskSem1,neTaskSem2,和三个任务neTask0,neTask1,neTask2,信号量采用优先级方式,哪个任务得到这个信号量,哪个任务优先被执行,互斥信号量介于semTake()和SemGive()之间,直到semGive(neTaskSem0)释放该信号量,其他任务才可以得到执行,LOCAL void neProcess0(NE2000END_DEVICE *pDrvCtrl){for(;;){semTake (neTaskSem0, WAIT_FOREVER);if( pDrvCtrl->unit == 0){neProcess(pDrvCtrl);}}}假如此时网卡1有数据通讯,上电后,neTaskSem0和neTask0会被创建,此时pDrvCtrl->unit == 0 semGive (neTaskSem0);就会执行neTask0任务,即neProcess函数,LOCAL void neProcess(NE2000END_DEVICE *pDrvCtrl){……SYS_IN_CHAR (pDrvCtrl, ENE_RSTAT, &rxStat);//得到接收寄存器SYS_IN_CHAR (pDrvCtrl, ENE_COLCNT, &val);//更新计数器……如果有接收到错误,netJobAdd ((FUNCPTR) muxError, (int) &pDrvCtrl->endObj,(int)&pDrvCtrl->lastError,0, 0, 0);通过netJobAdd将错误处理函数muxError加入任务队列;如果接收数据溢出,netJobAdd ((FUNCPTR) ne2000OverwriteRecover, (int) pDrvCtrl,cmdStat, 0, 0, 0);通过netJobAdd将溢出处理函数ne2000OverwriteRecover加入任务队列;其中溢出处理流程:1.经过短暂的延时后,清除发送寄存器计数(ENE_RBCR0和ENE_RBCR1)2.判断是否需要重新发送3. SYS_OUT_CHARA (pDrvCtrl, ENE_TCON, TCON_LB1);SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_START);对照芯片手册得知,上面一行代码是设置环回类型,第二行是发出start命令远程操作;4.删除数据包,清除溢出标志字。
5. SYS_IN_CHAR (pDrvCtrl, ENE_INTSTAT, &stat);SYS_OUT_CHARA (pDrvCtrl, ENE_INTSTAT, stat);重新设置中断状态;6.SYS_OUT_CHARA (pDrvCtrl, ENE_TCON, 0x00);退出环回7. intKey = intLock();pDrvCtrl->flags &= ~END_OVERWRITE2;pDrvCtrl->imask = NE2000_ALL_INTS;SYS_OUT_CHARA (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);intUnlock(intKey);重新启动设备中断;8.if (reSend)SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_TXP);else muxTxRestart (&pDrvCtrl->endObj);如果重新发送成功没有溢出则TXP置位发送数据,如果溢出,则调用MUX层函数muxTxRestart函数,重启发送指令。
三、接收处理在没有接收错误或溢出的情况下,进入接收处理函数ne2000HandleRcvInt(),获得当前广播点播数量(bgnTick[pDrvCtrl->unit]=tickGet();ptpbgnTick[pDrvCtrl->unit]=tickGet();)if (pDrvCtrl->nextPacket == pDrvCtrl->current)break; //如果接收到的数据与之前的一致没有变化,说明处理完毕在不满足溢出条件下,分配MBLK和替换缓冲区,调用netClusterGet函数,在指定的内存池中获取一部分空间,len = ne2000PacketGet (pDrvCtrl, pBuf + pDrvCtrl->offset);得到下个数据包的长度,ne2000PacketGet()函数中:调用系统函数ne2000DataIn( )ne2000DataIn (pDrvCtrl, (((UINT16)pDrvCtrl->nextPacket << 8) & 0x0000ffff),sizeof (NE2000_HEADER), (char *) &h)来完成输入字节到存储器(该函数具体代码实现方法不理解);packetSize = ((((UINT16)h.uppByteCnt << 8) + h.lowByteCnt) - 4)&0xffff;//计算数据包大小,除去4位校验码大小。