📄 halrtl8019as.c
字号:
* @param[in] vMultiMacChain 指向一个组播地址链,该链上的组播地址应该都被设置进入该网卡.该链的结构是 * typedef struct ether_multi{ * char haddr[6]; //组播地址 * unsigned short emc_users; //该组播地址的用户数,对于驱动,不需要关心该参数 * struct ether_multi * next; //指向下一节点 * }ETHER_MULTI; * * typedef struct macforhash{ * unsigned char macaddr[6]; //要操作的组播MAC地址 * ETHER_MULTI * chainpointer; //该设备需要设置的组播地址链 * }T_MACHASH; * multiMacChian为 T_MACHASH 指针类型,该参数的使用是可选的. * 即,HAL中,增加组播地址的实现既可仅根据macaddr参数进行操作, * 也可以根据multiMacChain来全部重新设定网卡组播地址 * * @return * FALSE 失败 * TRUE 成功 */T_BOOL RTL8019AS_AddMultiAddr( T_VOID *vpHalDevData, T_CHAR *bMacAddr, T_VOID *vMultiMacChain){ return TRUE;}/** * @brief * 删除该网卡的一个组播地址 * * @param[in] vpHalDevData 设备数据块指针,该结构的类型由HAL定义 * * @param[in] bMacAddr 指向一个6字节的存储空间,内容为需要删除的组播MAC地址 * * @param[in] vMultiMacChain 指向一个组播地址链,该链上的组播地址应该都被设置进入该网卡.该链的结构是 * typedef struct ether_multi{ * char haddr[6]; //组播地址 * unsigned short emc_users; //该组播地址的用户数,对于驱动,不需要关心该参数 * struct ether_multi * next; //指向下一节点 * }ETHER_MULTI; * * typedef struct macforhash{ * unsigned char macaddr[6]; //要操作的组播MAC地址 * ETHER_MULTI * chainpointer; //该设备需要设置的组播地址链 * }T_MACHASH; * multiMacChian为 T_MACHASH 指针类型,该参数的使用是可选的. * 即,HAL中,删除组播地址的实现既可仅根据macaddr参数进行操作, * 也可以根据multiMacChain来全部重新设定网卡组播地址 * * @return * FALSE 失败 * TRUE 成功 */T_BOOL RTL8019AS_DelMultiAddr( T_VOID *vpHalDevData, T_CHAR *bMacAddr, T_VOID * vMultiMacChain){ return TRUE;}/** * @brief * 从网卡缓存(芯片RAM)中将数据读取到用户自定义BUF中,远端DMA读。 * * @param[in] wCount:要读取的字符个数 * @param[in] uwRingOffset:起始地址 * @param[out] bpBuf:用户自定义的BUF指针 * * @return * 0 :DMA读失败。 * >0 :DMA读成功。 */T_MODULE T_WORD RTL8019AS_BlockInput(T_WORD wCount,T_BYTE* bpBuf,T_UWORD uwRingOffset,T_HAL_RTL8019AS_DEV_DATA *pDevData){ T_WORD wait = 0; T_BYTE isr; BSP_OutByte(pDevData->IoBaseAddr + EN_CMD, ENCMD_NODMA + ENCMD_PAGE0 + ENCMD_START);//设置命令寄存器:无DMA,寄存器页为0页,打开包接收/发送。 BSP_OutByte(pDevData->IoBaseAddr + EN0_RCNTLO, wCount & 0xff); //设置远端DMA读出数据字节数。 BSP_OutByte(pDevData->IoBaseAddr + EN0_RCNTHI, wCount >> 8); //设置远端DMA读出数据字节数。 BSP_OutByte(pDevData->IoBaseAddr + EN0_RSARLO, uwRingOffset & 0xff); //设置远端DMA开始地址(低8位)。 BSP_OutByte(pDevData->IoBaseAddr + EN0_RSARHI, uwRingOffset >> 8); //设置远端DMA开始地址(高8位)。 BSP_OutByte(pDevData->IoBaseAddr + EN_CMD, ENCMD_RREAD + ENCMD_START); //设置命令寄存器:远端DMA读,启动。 BSP_InHWords(pDevData->IoBaseAddr + EN_DATAPORT,(short *)bpBuf,wCount>>1); //CPU从网卡芯片RAM读取数据到buf。 if (wCount & 0x01) { BSP_InByte(pDevData->IoBaseAddr + EN_DATAPORT,bpBuf[wCount-1]); } BSP_InByte(pDevData->IoBaseAddr + EN0_ISR,isr); while((!(isr && ENISR_RDC)) && (wait < 5000)) //等待远端DMA读完成(通过获取远端DMA操作完成中断状态实现)。 { BSP_InByte(pDevData->IoBaseAddr + EN0_ISR,isr); wait++; } BSP_InByte(pDevData->IoBaseAddr + EN0_ISR,isr); if (!(isr && ENISR_RDC)) //远端DMA读失败。 { return 0; } return (wCount);}/** * @brief * 计算和调整页面位置 * * @param[in] pDevData:设备数据块指针,该结构的类型由HAL定义 * @param[in] wPositionValue:位置状态值,判断现在位置指针是否已经循环 * * @return temp:当前指针位置 */T_MODULE T_WORD RTL8019AS_RingIndex(T_HAL_RTL8019AS_DEV_DATA* pDevData, T_WORD wPositionValue){ T_WORD temp ; temp = wPositionValue - pDevData->rxStartPage; if (temp < 0) { temp = -temp; } temp = temp % (pDevData->stopPage - pDevData->rxStartPage);//设定循环。 temp = pDevData->rxStartPage + temp ; //确定指针位置。 return temp ;}/** * @brief * 本地DMA发送,将数据由网卡缓存(芯片RAM)发送到网络。 * * @param[in] pDevData: 设备数据块指针,该结构的类型由HAL定义 * @param[in] uwLength 将要发送的数据长度 * * @return * 0 成功 * -1 失败 */T_MODULE T_WORD RTL8019AS_TriggerSend(T_HAL_RTL8019AS_DEV_DATA *pDevData, T_UWORD uwLength){ T_WORD wait = 0; T_UBYTE keepCmd; T_UBYTE cmd; BSP_InByte(pDevData->IoBaseAddr,keepCmd); //读出命令寄存器的值并保存。 BSP_OutByte(pDevData->IoBaseAddr + EN_CMD, ENCMD_NODMA + ENCMD_PAGE0); //设置命令寄存器:无DMA,寄存器页为0页。 BSP_InByte(pDevData->IoBaseAddr + EN_CMD,cmd); while((cmd & ENCMD_TXP) && (wait <= 5000)) //等待上一次发送操作结束。 { BSP_InByte(pDevData->IoBaseAddr + EN_CMD,cmd); wait++; } BSP_InByte(pDevData->IoBaseAddr + EN_CMD,cmd); if(cmd & ENCMD_TXP) //上一次发送操作未结束。 { BSP_OutByte(pDevData->IoBaseAddr, keepCmd); //恢复先前保存的命令寄存器的值。 return -1; //退出,发送失败。 } BSP_OutByte(pDevData->IoBaseAddr + EN0_TCNTLO, uwLength & 0xff); //设置数据包长度。 BSP_OutByte(pDevData->IoBaseAddr + EN0_TCNTHI, uwLength >> 8); //设置数据包长度。 BSP_OutByte(pDevData->IoBaseAddr + EN0_TPSR, pDevData->txStartPage); //设置发送数据包在网卡缓存(芯片RAM)中的起始地址(发送缓冲区首地址)。 BSP_OutByte(pDevData->IoBaseAddr + EN_CMD, ENCMD_NODMA + ENCMD_TXP + ENCMD_START); //设置命令寄存器:无DMA,发送,启动。 BSP_OutByte(pDevData->IoBaseAddr, keepCmd); //恢复先前保存的命令寄存器的值。 return 0;}/** * @brief * CPU写数据到网卡缓存(芯片RAM)中,远端DMA写。 * * @param[in] wCount:要写入的字符个数。 * @param[in] wStartOffset:起始地址。 * @param[in] bpBuf:用户自定义的BUF指针。 * @param[in] pDevData:设备数据块指针,该结构的类型由HAL定义 * @return * -1 :DMA写失败。 * 0 :DMA写成功。 */T_MODULE T_WORD RTL8019AS_BlockOutput(T_HAL_RTL8019AS_DEV_DATA *pDevData,T_WORD wCount,T_BYTE *bpBuf,T_WORD wStartOffset){ T_WORD i; T_UBYTE keepCmd; T_UBYTE isr; if (pDevData->word16 && (wCount & 0x01)) { wCount++; } BSP_InByte(pDevData->IoBaseAddr,keepCmd); //读出命令寄存器的值并保存。 BSP_OutByte(pDevData->IoBaseAddr + EN_CMD, ENCMD_PAGE0 + ENCMD_START + ENCMD_NODMA);//设置命令寄存器:寄存器页为0页,启动,无DMA。 BSP_OutByte(pDevData->IoBaseAddr + EN0_RCNTLO, wCount & 0xff); //设置远端DMA写入数据字节数。 BSP_OutByte(pDevData->IoBaseAddr + EN0_RCNTHI, wCount >> 8); //设置远端DMA写入数据字节数。 BSP_OutByte(pDevData->IoBaseAddr + EN0_RSARLO, wStartOffset & 0xff); //设置远端DMA开始地址(低8位)。 BSP_OutByte(pDevData->IoBaseAddr + EN0_RSARHI, wStartOffset >> 8); //设置远端DMA开始地址(高8位)。 BSP_OutByte(pDevData->IoBaseAddr + EN_CMD, ENCMD_RWRITE + ENCMD_START); //设置命令寄存器:远端DMA写,启动。 if (pDevData->word16) { BSP_OutHWords(pDevData->IoBaseAddr + EN_DATAPORT,(T_BYTE *)bpBuf, wCount >> 1);//CPU将buf中的数据写入网卡芯片RAM。 } else { BSP_OutBytes(pDevData->IoBaseAddr + EN_DATAPORT ,(T_BYTE *)bpBuf, wCount); } for(i=0;i<5000;i++) { BSP_InByte(pDevData->IoBaseAddr + EN0_ISR,isr); if(isr && ENISR_RDC) //等待远端DMA写完成(通过获取远端DMA操作完成中断状态实现)。 { break; } } BSP_OutByte(pDevData->IoBaseAddr, keepCmd); //恢复先前保存的命令寄存器的值。 if(i>=5000) { return -1; //远端DMA写失败。 } return 0;}/** * @brief * 网卡接收缓冲区溢出中断处理。 * * @param[in] pDevData:指针,指向HAL数据表(T_HAL_RTL8019AS_DEV_DATA)。 * @return 无。 */T_MODULE T_VOID RTL8019AS_HandlerOverflow(T_HAL_RTL8019AS_DEV_DATA *pDevData){ T_WORD i; T_WORD j; T_UBYTE wasTxing; T_UBYTE mustResend = 0; T_UBYTE txCompleted; T_UWORD rxingPage; T_UBYTE isr; T_UBYTE cmd; BSP_InByte(pDevData->IoBaseAddr + EN_CMD,cmd); wasTxing = (cmd & ENCMD_TXP); //判断网卡是否在DMA传送。 BSP_OutByte(pDevData->IoBaseAddr + EN_CMD, ENCMD_NODMA + ENCMD_PAGE0 + ENCMD_STOP); //设置命令寄存器:无DMA,寄存器页为0页,停止包接收/发送。 for(i=0;i<1000;i++) { j = i+1; //等待,标准为1.6ms。 } BSP_OutByte(pDevData->IoBaseAddr + EN0_RCNTLO, 0x00); //清远端DMA数据长度寄存器。 BSP_OutByte(pDevData->IoBaseAddr + EN0_RCNTHI, 0x00); //清远端DMA数据长度寄存器。 if (wasTxing) //网卡在DMA传送。 { BSP_InByte(pDevData->IoBaseAddr + EN0_ISR,isr); txCompleted = (isr & (ENISR_PTX + ENISR_TXE));//判断发送是否完成 if (!txCompleted) { mustResend = 1; } } BSP_OutByte(pDevData->IoBaseAddr + EN0_TXCR, ENTXCR_TXLOOKL); //设置传输配置寄存器:内部lookback。 BSP_OutByte(pDevData->IoBaseAddr + EN_CMD, ENCMD_NODMA + ENCMD_PAGE0 + ENCMD_START); //设置命令寄存器:无DMA,寄存器页为0页,打开包接收/发送。 BSP_OutByte(pDevData->IoBaseAddr + EN_CMD, ENCMD_NODMA + ENCMD_PAGE1); //设置命令寄存器:无DMA,寄存器页为1页。 BSP_InByte(pDevData->IoBaseAddr + EN1_CURPAG,rxingPage); //重新获取接收页面。 BSP_OutByte(pDevData->IoBaseAddr + EN_CMD, ENCMD_NODMA + ENCMD_PAGE0); BSP_OutByte(pDevData->IoBaseAddr + EN0_BOUNDARY, rxingPage - 1); //设置接收缓冲读指针。 BSP_OutByte(pDevData->IoBaseAddr + EN0_ISR, ENISR_OVW); //清中断状态寄存器。 BSP_OutByte(pDevData->IoBaseAddr + EN0_TXCR, ENTXCR_TXCONFIG); //设置传输配置寄存器:使能冲突补偿。 if (mustResend) //发送未完成,重发数据包。 { BSP_OutByte(pDevData->IoBaseAddr + EN_CMD, ENCMD_NODMA + ENCMD_PAGE0 + ENCMD_START + ENCMD_TXP); }}/** * @brief * 检查接收到的数据包是否为好包。 * * @param[in] pDevData:指针,指向HAL数据表(T_HAL_RTL8019AS_DEV_DATA)。 * @param[in] uwCurrFrame:接收到的数据包的起始地址。 * @param[in] tpRcvFrame:包头。 * @return TRUE:好包。 * FALSE:坏包。 */T_MODULE T_WORD RTL8019AS_CheckFrame(T_HAL_RTL8019AS_DEV_DATA *pDevData,T_UWORD uwCurrFrame,EN_PKTHEADER_T *tpRcvFrame){ T_WORD tmp ; if(tpRcvFrame->count > 1518 || tpRcvFrame->count < 64)//数据包长度不符合标准。 { return FALSE; //坏包。 } if((tpRcvFrame->next > pDevData->stopPage) || (tpRcvFrame->next < pDevData->rxStartPage)) //数据包的下一页地址大于缓冲区停止页或小于开始页。 { return FALSE ; //坏包。 } tmp = ((tpRcvFrame->count-1) & 0x0ff00)>>8; tmp = RTL8019AS_RingIndex(pDevData, uwCurrFrame + tmp + 1); if (tpRcvFrame->next != tmp) { tmp++; tmp = RTL8019AS_RingIndex(pDevData, tmp) ; if (tpRcvFrame->next != tmp ) return FALSE; } return TRUE;}/** * @brief * 刷新网络记数器。 * * @return 无。 */T_MODULE T_VOID RTL8019AS_UpdateCounters(T_HAL_RTL8019AS_DEV_DATA *pDevData){ T_UBYTE keepCmd; T_WORD a; T_WORD b; T_WORD c; T_WORD d; T_UBYTE cnt; a = 0; b = 0; c = 0; d = 0; BSP_InByte(pDevData->IoBaseAddr,keepCmd); //读出命令寄存器的值并保存。 BSP_OutByte(pDevData->IoBaseAddr + EN_CMD, ENCMD_NODMA + ENCMD_PAGE0);//设置命令寄存器:无DMA,寄存器页为0页。 BSP_InByte(pDevData->IoBaseAddr + EN0_COUNTER0,cnt); //读记录接收错误队列计数器。 a += cnt; BSP_InByte(pDevData->IoBaseAddr + EN0_COUNTER1,cnt); //读接收的CRC 错误计数器。 b += cnt; BSP_InByte(pDevData->IoBaseAddr + EN0_COUNTER2,cnt); //读接收丢失计数器。 c += cnt; d++; BSP_OutByte(pDevData->IoBaseAddr + EN0_ISR,ENISR_CNT); //清中断状态寄存器。 BSP_OutByte(pDevData->IoBaseAddr, keepCmd); //恢复先前保存的命令寄存器的值。}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -