📄 halrtl8139.c
字号:
/*
* 修改记录:
* 20060110 创建该文件。
*
*/
/**
* @file halRtl8139.c
* @brief
* <li>功能:实现RTL8139设备的HAL,该HAL目前仅支持网络组件的DLL。 </li>
* @date 20060110
*/
/**************************** 引用部分 *****************************************/
#include "sysDM.h"
#include "sysDR.h"
#include "halx86pci.h"
#include "halRtl8139.h"
/*************************** 前向声明部分 ****************************************/
T_MODULE T_BOOL rtl8139_Probe( T_HAL_RTL8139_DEV_DATA * pEtherDevDataTable, T_WORD index );
T_MODULE void Rtl8139_TxTmo( T_HAL_RTL8139_DEV_DATA * pEtherDevDataTable );
T_MODULE int Rtl8139_Tx( T_HAL_RTL8139_DEV_DATA * pEtherDevDataTable );
T_MODULE void Rtl8139_InitRing( T_HAL_RTL8139_DEV_DATA * pEtherDevDataTable );
T_MODULE void Rtl8139_mCastAddrAdd(T_HAL_RTL8139_DEV_DATA * pEtherDevDataTable, char *buf );
T_MODULE void Rtl8139_mCastAddrDel(T_HAL_RTL8139_DEV_DATA * pEtherDevDataTable, void *buf );
/**************************** 实现部分 *****************************************/
/**
* @brief
* 确认设备的存在,对于需要动态获得系统参数的设备
* 需要在此处把系统资源占用信息更新,如PCI设备的中断
* 号和基地址。
*
* @param[in] pEtherDevData:设备数据块指针,该结构的类型由HAL定义。
*
* @return 成功返回TRUE;否则,返回FALSE。
*/
T_BOOL rtl8139_Find( T_VOID *pEtherDevData )
{
T_HAL_RTL8139_DEV_DATA *pEtherDevDataTable = (T_HAL_RTL8139_DEV_DATA *)pEtherDevData;
T_WORD retval;
int i;
// 确认In82559的存在,更新配置表项
retval = rtl8139_Probe( pEtherDevDataTable, pEtherDevDataTable->devIndex );
for(i = 0; i < 6; i++)
{
BSP_InByte( pEtherDevDataTable->IoBaseAddr + R8139_IDR0 + i, pEtherDevDataTable->macaddr[i] );
}
if ( retval != TRUE )
{
return FALSE;
}
return TRUE;
}
/**
* @brief
* 该接口用来获取HAL管理该设备需要的资源(主要指内存)
* HAL不应该再再别的地方进行资源的获取工作,该接口获得的资源将都被传给HAL中其他接口使用。
*
* @param[in] pEtherDevData:设备数据块指针,该结构的类型由HAL定义。
*
* @return 成功返回TRUE;否则,返回FALSE。
*/
T_BOOL rtl8139_GetResource( T_VOID *pEtherDevData )
{
T_HAL_RTL8139_DEV_DATA *pEtherDevDataTable = (T_HAL_RTL8139_DEV_DATA *)pEtherDevData;
T_WORD Status = 0;
/*
* 申请发送以及接收缓存
*/
Status = fnDM_SemaphoreCreate (
"RTL8139ETHER",
1,
DM_SIMPLE_BINARY_SEMAPHORE,
DM_NO_PRIORITY,
&pEtherDevDataTable->outbufmutex);
if (Status != DM_SUCCESSFUL)
return FALSE;
pEtherDevDataTable->rxBufLen = (8192 << pEtherDevDataTable->rxBufSize);
pEtherDevDataTable->tx_bufs = (unsigned char *)malloc(pEtherDevDataTable->txBufSize * NUM_TX_DESC);
pEtherDevDataTable->rx_ring = (unsigned char *)malloc(pEtherDevDataTable->rxBufLen + 16); /*1536 for don't wrap option*/
return TRUE;
}
/**
* @brief
* 释放HAL占用的资源(主要指在GetResource中获取到的资源)
*
* @param[in] pEtherDevData:设备数据块指针,该结构的类型由HAL定义。
*
* @return 成功返回TRUE;否则,返回FALSE。
*/
T_BOOL rtl8139_ReleaseResource( T_VOID *pEtherDevData )
{
T_HAL_RTL8139_DEV_DATA *pEtherDevDataTable = (T_HAL_RTL8139_DEV_DATA *)pEtherDevData;
free(pEtherDevDataTable->rx_ring);
free(pEtherDevDataTable->tx_bufs);
return TRUE;
}
/**
* @brief
* 启动设备的运行,对设备进行基本初始化工作.主要工作包括:
* 1.获取HAL为了驱动该设备所需要的系统资源,一般指内存空间
* 2.设置设备寄存器,让设备工作在正常状态下
* 3.注意该接口不要关心设备的中断开关状态。
*
* @param[in] pEtherDevData 设备数据块指针,该结构的类型由HAL定义。
*
* @return 成功返回TRUE;否则,返回FALSE。
*/
T_BOOL rtl8139_Start( T_VOID *pEtherDevData )
{
T_HAL_RTL8139_DEV_DATA *pEtherDevDataTable = (T_HAL_RTL8139_DEV_DATA *)pEtherDevData;
T_UHWORD i = 0 ;
T_WORD full_duplex = 0 ;
T_UHWORD lpar = 0;
T_BYTE ioInVar;
T_UHWORD ioInUHword;
BSP_OutByte( pEtherDevDataTable->IoBaseAddr + R8139_CR, 0x10 );
// 初始化设备运行状态参数,注意,在此不应该涉及资源申请
Rtl8139_InitRing( pEtherDevDataTable );
// 检查设备是否已经完全复位
for (i = 5000; i > 0; i--)
{
BSP_InByte( pEtherDevDataTable->IoBaseAddr + R8139_CR, ioInVar);
if (( ioInVar & 0x10) == 0)
{
break;
}
}
if(i<=0)
{
return FALSE;
}
BSP_InHWord( pEtherDevDataTable->IoBaseAddr + R8139_BMCR, ioInUHword);
BSP_OutHWord( pEtherDevDataTable->IoBaseAddr + R8139_BMCR, ioInUHword | 0x1300);
// 初始化MAC寄存器
for (i = 0; i < 6; i++)
{
BSP_OutByte( pEtherDevDataTable->IoBaseAddr + R8139_IDR0+i, pEtherDevDataTable->macaddr[i]);
}
do
{
BSP_InHWord( pEtherDevDataTable->IoBaseAddr + R8139_BMSR, ioInUHword);
}
while (( ioInUHword & 0x20 ) == 0);
// Must enable Tx/Rx before setting transfer thresholds!
BSP_OutByte( pEtherDevDataTable->IoBaseAddr + R8139_CR,0x0c);/*enable tx and rx*/
BSP_OutLong( pEtherDevDataTable->IoBaseAddr + R8139_RCR,
(RX_FIFO_THRESH << 13) | (pEtherDevDataTable->rxBufSize << 11) | (RX_DMA_BURST<<8)|RX_OPTION);
BSP_OutLong( pEtherDevDataTable->IoBaseAddr + R8139_TCR,(TX_DMA_BURST<<8)|0x03000000);
full_duplex = 1;
BSP_InHWord( pEtherDevDataTable->IoBaseAddr + R8139_ANLPAR, lpar);
if ((lpar & 0x0100) == 0x0100 || (lpar & 0x00C0) == 0x0040)
{
full_duplex = 1;
}
else
{
full_duplex = 0;
}
BSP_OutByte( pEtherDevDataTable->IoBaseAddr + R8139_9346CR,0xC0);
BSP_OutByte( pEtherDevDataTable->IoBaseAddr + R8139_CONFIG1,full_duplex ? 0x60 : 0x20);
BSP_OutByte( pEtherDevDataTable->IoBaseAddr + R8139_9346CR,0x00);
BSP_OutLong( pEtherDevDataTable->IoBaseAddr + R8139_RBSTART,(unsigned long)pEtherDevDataTable->rx_ring);
// Start the chip's Tx and Rx process.
BSP_OutLong( pEtherDevDataTable->IoBaseAddr + R8139_MPC,0);
BSP_OutByte( pEtherDevDataTable->IoBaseAddr + R8139_CR,0x0c);/*enable rx and tx*/
pEtherDevDataTable->interrupt = 0;
// clear interrupt status register.if not done,receive buf will remain empty
BSP_OutHWord( pEtherDevDataTable->IoBaseAddr + R8139_IMR,0x0000);
BSP_OutHWord( pEtherDevDataTable->IoBaseAddr + R8139_ISR,0xffff);
// Enable all known interrupts by setting the interrupt mask.
BSP_OutHWord( pEtherDevDataTable->IoBaseAddr + R8139_IMR,
PCIErr|PCSTimeout|RxUnderrun|RxOverflow|RxFIFOOver|TxErr|TxOK|RxErr|RxOK);
// 延迟2秒,等待网卡和HUB或主机协商过程完成
delta_task_wake_after(2000);
return TRUE;
}
/**
* @brief
* 停止(或暂停)设备的运行,就是让该IO设备不能(正常)输入输出。
* 该函数一般就是要设置DISABLE位,或者把该设备
* 设置为内循环模式等。
*
* @param[in] pEtherDevData:设备数据块指针,该结构的类型由HAL定义。
*
* @return 成功返回TRUE;否则,返回FALSE。
*/
T_BOOL rtl8139_Stop( T_VOID *pEtherDevData )
{
T_HAL_RTL8139_DEV_DATA *pEtherDevDataTable = (T_HAL_RTL8139_DEV_DATA *)pEtherDevData;
T_WORD rxerr = 0;
// Disable interrupts by clearing the interrupt mask.
BSP_OutHWord( pEtherDevDataTable->IoBaseAddr +R8139_IMR,0x0000);
// Stop the chip's Tx and Rx DMA processes.
BSP_OutByte( pEtherDevDataTable->IoBaseAddr +R8139_CR,0x00);
// Update the error counts.
BSP_InLong( pEtherDevDataTable->IoBaseAddr + R8139_MPC, rxerr);
BSP_OutLong( pEtherDevDataTable->IoBaseAddr +R8139_MPC,0);
//Put the chip in low-power mode.
BSP_OutByte( pEtherDevDataTable->IoBaseAddr +R8139_9346CR,0xC0);
BSP_OutByte( pEtherDevDataTable->IoBaseAddr +R8139_CONFIG1,0x03);
return TRUE;
}
/**
* @brief
* 增加一个组播地址到该网卡
*
* @param[in] pEtherDevData: 设备数据块指针,该结构的类型由HAL定义。
*
* @param[in] macAddr:指向一个6字节的存储空间,内容为需要增加的组播MAC地址。
*
* @param[in] multiMacChian 指向一个组播地址链,该链上的组播地址应该都被设置进入该网卡.该链的结构是
* 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 成功返回TRUE;否则,返回FALSE。
*/
T_BOOL rtl8139_AddMultiAddr( T_VOID * pEtherDevData, T_CHAR *macAddr, T_VOID * multiMacChain)
{
T_HAL_RTL8139_DEV_DATA *pEtherDevDataTable = (T_HAL_RTL8139_DEV_DATA *)pEtherDevData;
Rtl8139_mCastAddrAdd(pEtherDevDataTable,macAddr);
return TRUE;
}
/**
* @brief
* 删除该网卡的一个组播地址
*
* @param[in] pEtherDevData: 设备数据块指针,该结构的类型由HAL定义。
*
* @param[in] macAddr:指向一个6字节的存储空间,内容为需要删除的组播MAC地址。
*
* @param[in] multiMacChian 指向一个组播地址链,该链上的组播地址应该都被设置进入该网卡.该链的结构是
* 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 成功返回TRUE;否则,返回FALSE。
*/
T_BOOL rtl8139_DelMultiAddr( T_VOID * pEtherDevData, T_CHAR *macAddr, T_VOID * multiMacChain)
{
T_HAL_RTL8139_DEV_DATA *pEtherDevDataTable = (T_HAL_RTL8139_DEV_DATA *)pEtherDevData;
Rtl8139_mCastAddrDel(pEtherDevDataTable,multiMacChain);
return TRUE;
}
/**
* @brief
* 发送数据包,把从DLL传来的数据包发送出去。
*
* @param[in] pEtherDevData: 设备数据块指针,该结构的类型由HAL定义。
* @param[in] pktBuf:数据包所在的缓存指针。
* @param[in] pktLen:数据包大小。
*
* @return 成功返回TRUE;否则,返回FALSE。
*/
T_BOOL rtl8139_SendPkt( T_VOID *pEtherDevData, T_CHAR * pktBuf, T_WORD pktLen )
{
T_HAL_RTL8139_DEV_DATA *pEtherDevDataTable = (T_HAL_RTL8139_DEV_DATA *)pEtherDevData;
unsigned int i = 0;
int j = 0;
int txbusy = pEtherDevDataTable->txbusy;
int txentry = pEtherDevDataTable->txentry;
// 用tbusy做互斥
if( pEtherDevDataTable->tx_full )
{
if(fnDM_SemaphoreObtain (pEtherDevDataTable->outbufmutex, DM_WAIT, 8000) != DM_SUCCESSFUL )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -