📄 haldm9000.c
字号:
/*
* 修改记录:
* 20060310 创建该文件。
* 20040518 M4修正更新。
*
*/
/**
* @file halDM9000.c
* @brief
* <li>功能: 实现DM9000设备的HAL,该HAL目前仅支持网络组件的DLL</li>
* @date 20060310
*/
/**************************** 引用部分 *****************************************/
#include <board.h>
#include <delta.h>
#include "halDM9000.h"
/*************************** 前向声明部分 ****************************************/
T_MODULE T_VOID PhyRead(T_VOID *vpEtherDevData, T_WORD wReg, T_UHWORD *uhpValue);
T_MODULE T_VOID PhyWrite(T_VOID *vpEtherDevData, T_WORD wReg, T_UHWORD uhValue);
T_MODULE T_VOID SetPHYMode(T_VOID *vpEtherDevData);
T_MODULE T_BOOL Probe(T_HAL_DM9000_DEV_DATA *vpEtherDevData);
/**************************** 定义部分 *****************************************/
#define DM9000_IOW( _port, _value) \
{ \
*( volatile char * )(tpEtherDevDataTable->vbpDM9000Addr) = _port; \
*( volatile char * )(tpEtherDevDataTable->vbpDM9000Addr+4) = _value; \
}
#define DM9000_IOR( _port, _value) \
{ \
*( volatile char * )(tpEtherDevDataTable->vbpDM9000Addr) = _port; \
_value = *( volatile char * )(tpEtherDevDataTable->vbpDM9000Addr+4); \
}
/**************************** 实现部分 *****************************************/
/**
* @brief
* 确认设备的存在,对于需要动态获得系统参数的设备
* 需要在此处把系统资源占用信息更新。
*
* @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。
*
* @return TRUE 成功 。
* FALSE 失败。
*/
T_BOOL DM9000_Find(T_VOID *vpEtherDevData)
{
T_HAL_DM9000_DEV_DATA *tpEtherDevDataTable = (T_HAL_DM9000_DEV_DATA *)vpEtherDevData;
T_WORD retval;
// 确认DM9000的存在,更新配置表项
retval = Probe(tpEtherDevDataTable);
return retval;
}
/**
* @brief
* 该接口用来获取HAL管理该设备需要的资源(主要指内存)
* HAL不应该再再别的地方进行资源的获取工作,该接口获得的资源将都被传给HAL中其他接口使用。
*
* @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。
*
* @return TRUE 成功 (始终返回该值)。
*/
T_BOOL DM9000_GetResource(T_VOID *vpEtherDevData)
{
return TRUE;
}
/**
* @brief
* 关闭设备的中断。工作就是屏蔽在ChipIntEnable中使能的中断类型。
*
* @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。
*
* @return TRUE 成功(始终返回该值)。
*/
T_BOOL DM9000_ChipIntDisable(T_VOID *vpEtherDevData)
{
T_HAL_DM9000_DEV_DATA *tpEtherDevDataTable = (T_HAL_DM9000_DEV_DATA *)vpEtherDevData;
rEXTINT &= 0xffff8fff;
rEXTINT |= 0x1000; //设置 EXINT3 为高位
DM9000_IOW(IMR, 0x80); //disable TX/RX interrupt mask
rI_ISPC = 0x400000; //清除 pending
return TRUE;
}
/**
* @brief
* 启动设备的运行,对设备进行基本初始化工作.主要工作包括:
* 1.获取HAL为了驱动该设备所需要的系统资源,一般指内存空间;
* 2.设置设备寄存器,让设备工作在正常状态下;
* 3.注意该接口不要关心设备的中断开关状态。
*
* @param[in] pEtherDevData 设备数据块指针,该结构的类型由HAL定义。
*
* @return
* FALSE 失败
* TRUE 成功
*/
T_BOOL DM9000_Start(T_VOID *vpEtherDevData)
{
T_WORD port;
T_WORD i;
T_BYTE IoMode;
T_UHWORD phyid1,phyid2;
T_HAL_DM9000_DEV_DATA *tpEtherDevDataTable = (T_HAL_DM9000_DEV_DATA *)vpEtherDevData;
/*设置MAC地址*/
tpEtherDevDataTable->tEiStatus.local_mac_address[0] = tpEtherDevDataTable->mac0;
tpEtherDevDataTable->tEiStatus.local_mac_address[1] = tpEtherDevDataTable->mac1;
tpEtherDevDataTable->tEiStatus.local_mac_address[2] = tpEtherDevDataTable->mac2;
tpEtherDevDataTable->tEiStatus.local_mac_address[3] = tpEtherDevDataTable->mac3;
tpEtherDevDataTable->tEiStatus.local_mac_address[4] = tpEtherDevDataTable->mac4;
tpEtherDevDataTable->tEiStatus.local_mac_address[5] = tpEtherDevDataTable->mac5;
//重启设备
DM9000_IOW(NCR, 1);
//延时,等待重启完毕,延时时间大约需10us
for(i = 0; i< 1000; i++)
{
;
}
//设置T_EiStatus结构
DM9000_IOR(ISR, IoMode);
tpEtherDevDataTable->tEiStatus.io_mode = IoMode >> 6;
tpEtherDevDataTable->tEiStatus.reg0 = DM9000_REG00;
tpEtherDevDataTable->tEiStatus.reg5 = DM9000_REG05;
tpEtherDevDataTable->tEiStatus.reg8 = DM9000_REG08;
tpEtherDevDataTable->tEiStatus.reg9 = DM9000_REG09;
tpEtherDevDataTable->tEiStatus.rega = DM9000_REG0A;
tpEtherDevDataTable->tEiStatus.interrupt = 0;
tpEtherDevDataTable->tEiStatus.queue_pkt_len = 0;
tpEtherDevDataTable->tEiStatus.trans_start = 0;
tpEtherDevDataTable->tEiStatus.tx_pkt_cnt = 0;
tpEtherDevDataTable->tEiStatus.tbusy = 0;
tpEtherDevDataTable->tEiStatus.start = 1;
// 初始化寄存器
DM9000_IOW(NCR, tpEtherDevDataTable->tEiStatus.reg0);
DM9000_IOW(TCR, 0); // TX Polling clear
DM9000_IOW(BPTR, 0x3f); // high water overflow threshold,Less 3Kb, 200us
DM9000_IOW(FCTR, tpEtherDevDataTable->tEiStatus.reg9); // Rx Flow Control : High/Low Water
DM9000_IOW(FCR, tpEtherDevDataTable->tEiStatus.rega); // Flow Control
DM9000_IOW(SMCR, 0); // Special Mode
DM9000_IOW(NSR, 0x2c); // clear TX status
DM9000_IOW(ISR, 0x0f); // Clear interrupt status
DM9000_IOW( PAR, tpEtherDevDataTable->tEiStatus.local_mac_address[0] );
DM9000_IOW( PAR+1, tpEtherDevDataTable->tEiStatus.local_mac_address[1] );
DM9000_IOW( PAR+2, tpEtherDevDataTable->tEiStatus.local_mac_address[2] );
DM9000_IOW( PAR+3, tpEtherDevDataTable->tEiStatus.local_mac_address[3] );
DM9000_IOW( PAR+4, tpEtherDevDataTable->tEiStatus.local_mac_address[4] );
DM9000_IOW( PAR+5, tpEtherDevDataTable->tEiStatus.local_mac_address[5] );
//清除多播地址
port = MAR;
for(i = 0; i < 7; i++)
{
DM9000_IOW(port,0x00);
port++;
}
DM9000_IOW(port,0x80);
//read internal PHY id and init PHY
PhyRead(vpEtherDevData, 0x02, &phyid1);
PhyRead(vpEtherDevData, 0x03, &phyid2);
if((phyid1 != 0x181) || (phyid2 != 0xb8c0))
{
return FALSE;
}
SetPHYMode(vpEtherDevData); // Set PHY after set op_mode
//延时,等待网卡和HUB或主机协商过程完成
for(i = 0; i< 2000000; i++)
{
;
}
return TRUE;
}
/**
* @brief
* 使能设备中断。设备也许有多种类型的中断,网络组件只关心发送和接收中断而已
* 其他中断类型的处理将由HAL本身负责解释并响应。所以此处使能的中断类型应该包括
* 发送中断和接收中断,其他类型中断由HAL自行决定。
*
* @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。
*
* @return TRUE 成功(始终返回该值)。
*/
T_BOOL DM9000_ChipIntEnable(T_VOID *vpEtherDevData)
{
T_HAL_DM9000_DEV_DATA *tpEtherDevDataTable = (T_HAL_DM9000_DEV_DATA *)vpEtherDevData;
DM9000_IOW(RCR, DM9000_REG05 | 1); //RX enable
DM9000_IOW(IMR, DM9000_REGFF); //Enable TX/RX interrupt mask
rI_ISPC = 0x400000; //clear the pending
return TRUE;
}
/**
* @brief
* 发送数据包,把从DLL传来的数据包发送出去。
*
* @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。
* @param[in] bpKtBuf 数据包所在的缓存指针。
* @param[in] wKtLen 数据包大小。
*
* @return
* FALSE 失败
* TRUE 成功
*/
T_BOOL DM9000_SendPkt(T_VOID *vpEtherDevData, T_CHAR *bpKtBuf, T_WORD wKtLen)
{
T_WORD tmplen,i;
T_WORD wait = 0;
T_WORD TCR_Status;
T_WORD ISR_STATUS;
T_UHWORD *data_ptr;
T_UDWORD jiffies;
T_UHWORD phyid1,phyid2;
T_HAL_DM9000_DEV_DATA *tpEtherDevDataTable = (T_HAL_DM9000_DEV_DATA *)vpEtherDevData;
if(tpEtherDevDataTable->tEiStatus.tx_pkt_cnt == 1)
{
do
{
DM9000_IOR(TCR, TCR_Status);
wait++;
}while((TCR_Status & 0x01) && (wait <= 500000));
if(TCR_Status & 0x01)
{
PhyRead(vpEtherDevData, 0x02, &phyid1);
PhyRead(vpEtherDevData, 0x03, &phyid2);
return FALSE;
}
}
if((tpEtherDevDataTable->tEiStatus.tbusy != 0) || (tpEtherDevDataTable->tEiStatus.tx_pkt_cnt > 1))
{
do
{
DM9000_IOR(TCR, TCR_Status);
wait++;
}while((TCR_Status & 0x01) && (wait <= 500000));
if(TCR_Status & 0x01)
{
delta_clock_get(DELTA_CLOCK_GET_TICKS_SINCE_BOOT, (void*)(&jiffies));
if (tpEtherDevDataTable->tEiStatus.trans_start && ((jiffies - tpEtherDevDataTable->tEiStatus.trans_start) > DMFE_TX_TIMEOUT))
{
tpEtherDevDataTable->tEiStatus.stat.tx_errors++;
tpEtherDevDataTable->tEiStatus.tbusy = 0;
tpEtherDevDataTable->tEiStatus.trans_start = 0;
return FALSE;
}
}
tpEtherDevDataTable->tEiStatus.tbusy = 1;
return FALSE;
}
tpEtherDevDataTable->tEiStatus.tbusy = 1;
DM9000_IOW(IMR, 0x80); //Disable all interrupt
if(wKtLen < 60)
{
wKtLen = 60;
}
data_ptr = (T_UHWORD *)bpKtBuf;
*(( T_BYTE * )(tpEtherDevDataTable->vbpDM9000Addr)) = 0xf8;
tmplen = (wKtLen + 1) / 2; //Word mode
for (i = 0; i < tmplen; i++)
{
*((T_HWORD *)(tpEtherDevDataTable->vbpDM9000Addr+4)) = data_ptr[i];
}
if (tpEtherDevDataTable->tEiStatus.tx_pkt_cnt == 0)
{
tpEtherDevDataTable->tEiStatus.tx_pkt_cnt++;
DM9000_IOW(TXPLL, wKtLen & 0xff); // Set TX length to DM9000
DM9000_IOW(TXPLH, (wKtLen >> 8) & 0xff);
DM9000_IOW(TCR, 0x1); // Cleared after TX complete
delta_clock_get(DELTA_CLOCK_GET_TICKS_SINCE_BOOT, (void*)(&jiffies));
DM9000_IOR(ISR,ISR_STATUS);
while((ISR_STATUS & 0x02) == 0)
DM9000_IOR(ISR, ISR_STATUS);
DM9000_IOW(ISR , 0x02);
tpEtherDevDataTable->tEiStatus.tx_pkt_cnt--;
tpEtherDevDataTable->tEiStatus.tbusy = 0;
tpEtherDevDataTable->tEiStatus.trans_start = jiffies;
}
else
{
tpEtherDevDataTable->tEiStatus.tx_pkt_cnt++;
tpEtherDevDataTable->tEiStatus.queue_pkt_len = wKtLen;
}
if (tpEtherDevDataTable->tEiStatus.tx_pkt_cnt == 1)
{
tpEtherDevDataTable->tEiStatus.tbusy = 0;
}
DM9000_IOW(IMR, DM9000_REGFF);
return TRUE;
}
/**
* @brief
* 获取中断类型。当设备发生中断时,该接口将被调用。
*
* @param[in] vpEtherDevData 设备数据块指针,该结构的类型由HAL定义。
* @param[in] uwVector 产生中断的中断向量。
* @param[out] *wpIntInfo 设备的中断信息,当返回的中断类型中包括"其他中断类型"
时,该参数将被传给HandleOtherIntType的HAL接口。
*
* @return 当发生多种中断类型时,把如下的返回值采用‘位或’运算后再返回。
* DEV_NO_INTERRUPT 该设备没有发生中断。
* DEV_INT_HAD_HANDLED 设备发生了中断,但已经被处理了。
* DEV_RECEIVE_INTERRUPT 设备发生了接收中断。
* DEV_SENDOVER_INTERRUPT 设备发生了发生中断。
* DEV_OHER_INTTYPE 设备发生了其他的中断类型。
*/
T_UWORD DM9000_GetIntType(T_VOID *vpEtherDevData, T_UWORD uwVector, T_WORD *wpIntInfo)
{
T_WORD IntStatus;
T_BYTE RegSave;
T_UWORD ret = 0;
T_HAL_DM9000_DEV_DATA *tpEtherDevDataTable = (T_HAL_DM9000_DEV_DATA *)vpEtherDevData;
//清除中断
rI_ISPC = 0x400000;
tpEtherDevDataTable->tEiStatus.interrupt = 1;
DM9000_IOW(IMR,0x80); // Disable all interrupt
DM9000_IOR(DM9000_REG00 ,RegSave); // Save previous register address
DM9000_IOR(ISR, IntStatus); // Got DM9000 interrupt status
DM9000_IOR(ISR, IntStatus); // Got DM9000 interrupt status
DM9000_IOW(ISR, IntStatus);
if ((IntStatus & 0x0f) == 0)
{
return DEV_NO_INTERRUPT;
}
if (IntStatus & 1)
{
ret |= DEV_RECEIVE_INTERRUPT;
}
if (IntStatus & 2)
{
ret |= DEV_INT_HAD_HANDLED;
}
if (IntStatus & 4)
{
ret |= DEV_INT_HAD_HANDLED;
}
if (IntStatus & 8)
{
ret |= DEV_INT_HAD_HANDLED;
}
tpEtherDevDataTable->tEiStatus.interrupt = 0; // release interrupt lock
DM9000_IOW(IMR, DM9000_REGFF); // Re-enable interrupt mask
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -