?? lan9118.c
字號:
/*****************************************************************************
Copyright (c) 2004-2005, SMSC
This code and information is provided as is without warranty of any kind,
either expressed or implied, including but not limited to the implied
warranties of merchantability and/or fitness for a particular purpose.
File name : lan9118.c
Description : st driver for the ethernet chip SMSC LAN9118.
Date Modification Name
---- ------------ -------
18/02/05 Initial release V1.16 Phong Le
*****************************************************************************/
#ifndef LAN9118_SOURCE
#error LAN9118_SOURCE NOT DEFINED
#endif
#include "LAN9118.h"
static const NGubyte _date_code[]="021805";
/* global variables */
static const char driver_version [] = "SMSC Lan9118 Driver Version 1.16\n";
/* prototypes of local functions */
static void lan9118Isr(void *data);
static int lan9118Open(NGifnet * netp);
static void lan9118Start(NGifnet * netp);
static int lan9118Close(NGifnet* netp);
#ifdef _lint
static void lan9118SetMulti(const NGifnet * const netp);
#else
static void lan9118SetMulti(NGifnet * netp);
#endif
static BOOLEAN Lan_MacNotBusy(const DWORD dwLanBase);
/*
* WriteFifo (dwBase, dwOffset, pdwBuf, dwDwordCount)
* Writes 'dwDwordCount' 4-byte integers starting at address 'pdwBuf'
* into TX fifo at address (dwBase + dwOffset)
*/
void WriteFifo(
const DWORD dwBase,
const DWORD dwOffset,
const DWORD *pdwBuf,
DWORD dwDwordCount)
{
volatile DWORD * pdwReg;
pdwReg = (volatile DWORD *)(dwBase + dwOffset);
while (dwDwordCount >= 16UL)
{
*pdwReg = *pdwBuf++;
*pdwReg = *pdwBuf++;
*pdwReg = *pdwBuf++;
*pdwReg = *pdwBuf++;
*pdwReg = *pdwBuf++;
*pdwReg = *pdwBuf++;
*pdwReg = *pdwBuf++;
*pdwReg = *pdwBuf++;
*pdwReg = *pdwBuf++;
*pdwReg = *pdwBuf++;
*pdwReg = *pdwBuf++;
*pdwReg = *pdwBuf++;
*pdwReg = *pdwBuf++;
*pdwReg = *pdwBuf++;
*pdwReg = *pdwBuf++;
*pdwReg = *pdwBuf++;
dwDwordCount -= 16UL;
}
while (dwDwordCount)
{
*pdwReg = *pdwBuf++;
dwDwordCount--;
}
}
/*
* ReadFifo (dwBase, dwOffset, pdwBuf, dwDwordCount)
* Reads 'dwDwordCount' 4-byte integers from RX fifo at address
* (dwBase + dwOffset) and stores in memory buffer at address
* pdwBuf
*/
void ReadFifo(
const DWORD dwBase,
const DWORD dwOffset,
DWORD *pdwBuf,
DWORD dwDwordCount)
{
DWORD dummy;
const volatile DWORD * const pdwReg =
(const volatile DWORD * const)(dwBase + dwOffset);
dwDwordCount--; /* do not store CRC on OS20 buffer */
while (dwDwordCount >= 16UL)
{
*pdwBuf++ = *pdwReg;
*pdwBuf++ = *pdwReg;
*pdwBuf++ = *pdwReg;
*pdwBuf++ = *pdwReg;
*pdwBuf++ = *pdwReg;
*pdwBuf++ = *pdwReg;
*pdwBuf++ = *pdwReg;
*pdwBuf++ = *pdwReg;
*pdwBuf++ = *pdwReg;
*pdwBuf++ = *pdwReg;
*pdwBuf++ = *pdwReg;
*pdwBuf++ = *pdwReg;
*pdwBuf++ = *pdwReg;
*pdwBuf++ = *pdwReg;
*pdwBuf++ = *pdwReg;
*pdwBuf++ = *pdwReg;
dwDwordCount -= 16UL;
}
while (dwDwordCount)
{
*pdwBuf++ = *pdwReg;
dwDwordCount--;
}
dummy = *pdwReg;
dummy = dummy;
}
/*
* LanDetectChipId () returns the ID of the Concord Ethernet chip.
* Possible valid values are 0x115, 0x116, 0x117, 0x118
*/
DWORD LanDetectChipId (const DWORD dwLanBase)
{
DWORD dwIdRev;
dwIdRev = GetRegDW (dwLanBase, ID_REV);
dwIdRev = (dwIdRev >> 16) & 0xffffUL;
if ((dwIdRev != 0x0118UL) && (dwIdRev != 0x0117UL) &&
(dwIdRev != 0x0116UL) && (dwIdRev != 0x0115UL))
{
dwIdRev = 0xffffffffUL;
}
return dwIdRev;
}
/*
* LanDelayUS (dwLanBase, dwUS) delays 'dwUS' microseconds in this
* function.
*/
void LanDelayUS(const DWORD dwLanBase, const DWORD dwUS)
{
DWORD dwStartTick, dwEndTick, dwCurrentTick;
// get starting timestamp
dwStartTick = GetRegDW(dwLanBase, FREE_RUN);
// Calculate ending tick. Make sure we always wait at least 1 uS.
// Note that this could wrap-around (handled later).
if (dwUS == 0UL)
{
dwEndTick = dwStartTick + 25UL;
}
else
{
dwEndTick = dwStartTick + (dwUS*25UL);
}
// 4 possible cases:
// 1. could start on 0's
// 2. could end on ff's
// 3. could have a wrap-around before end
// 4. normal case (none of the above)
if (dwStartTick == 0UL) // case 1 above -- started on 0's
{
do {
dwCurrentTick = GetRegDW(dwLanBase, FREE_RUN);
} while (dwCurrentTick <= dwEndTick);
}
else if (dwEndTick == 0xFFFFFFFFUL) // case 2 above -- ended on ff's
{
do {
dwCurrentTick = GetRegDW(dwLanBase, FREE_RUN);
} while (dwCurrentTick >= dwStartTick);
}
else if (dwEndTick < dwStartTick) // case 3 above -- wrap-around before end
{
do {
dwCurrentTick = GetRegDW(dwLanBase, FREE_RUN);
} while ((dwCurrentTick >= dwStartTick) || (dwCurrentTick <= dwEndTick));
}
else // case 4 above -- the "normal" case
{
do {
dwCurrentTick = GetRegDW(dwLanBase, FREE_RUN);
} while ((dwCurrentTick >= dwStartTick) && (dwCurrentTick <= dwEndTick));
}
}
/*
FUNCTION: Lan_WriteTxFifo
This function is used to write a buffer to the
Tx Fifo in PIO mode.
This function is only intended to be called
from with in other Lan_xxx functions.
*/
void Lan_WriteTxFifo(
const DWORD dwLanBase,
const DWORD * const pdwBuf,
DWORD dwDwordCount)
{
WriteFifo(
dwLanBase,
TX_DATA_FIFO_PORT,
pdwBuf,dwDwordCount);
}
/*
FUNCTION: Lan_ReadRxFifo
This function is used to read a buffer to the
Rx Fifo in PIO mode.
This function is only intended to be called
from with in other Lan_xxx functions.
*/
void Lan_ReadRxFifo(
const DWORD dwLanBase,
DWORD * pdwBuf,
DWORD dwDwordCount)
{
ReadFifo(
dwLanBase,
RX_FIFO_PORT,
pdwBuf,dwDwordCount);
}
/*
FUNCTION: update_tx_counters
This function pops tx status and update statistics.
*/
void Lan_UpdateTxCounters(NGifnet *netp)
{
DWORD dwLanBase;
DWORD dwTxStatus=0UL;
dwLanBase = (DWORD) NG_ETHIF_DATA(((void *) netp), eif_base);
while((dwTxStatus=Lan_CompleteTx(dwLanBase))!=0UL)
{
if(dwTxStatus&0x80000000UL) {
} else {
if(dwTxStatus&0x00008000UL) {
netp->if_oerrors++;
} else {
netp->if_opackets++;
netp->if_obytes += (dwTxStatus>>16);
}
}
}
}
/*
FUNCTION: Lan_MacLoad
initialze MAC address.
return TRUE on success, FALSE on failure
*/
BOOLEAN Lan_MacLoad(NGifnet * netp)
{
int i;
DWORD dwHigh16, dwLow32;
DWORD dwLanBase;
dwLanBase = (DWORD) NG_ETHIF_DATA(((void *) netp), eif_base);
for (i = 0; i < 6; i++)
{
if (NG_ETHIF_DATA(((void *) netp), eif_addr[i]) != 0)
{
break;
}
}
if (i < 6)
{
/* use application-defined MAC address */
dwHigh16 = ((DWORD)NG_ETHIF_DATA(((void *) netp), eif_addr[4])) |
(((DWORD)NG_ETHIF_DATA(((void *) netp), eif_addr[5])) << 8);
dwLow32 = ((DWORD)NG_ETHIF_DATA(((void *) netp), eif_addr [0])) |
(((DWORD)NG_ETHIF_DATA(((void *) netp), eif_addr[1])) << 8) |
(((DWORD)NG_ETHIF_DATA(((void *) netp), eif_addr[2])) << 16) |
(((DWORD)NG_ETHIF_DATA(((void *) netp), eif_addr[3])) << 24);
/* set MAC address into lan9118 */
Lan_SetMacAddress (dwLanBase, dwHigh16, dwLow32);
}
else
{
/* get MAC address from lan9118 */
Lan_GetMacAddress (dwLanBase, &dwHigh16, &dwLow32);
{
return FALSE;
}
/* update MAC address into NexGen structure */
NG_ETHIF_DATA(((void *) netp), eif_addr[4]) = (NGubyte) (dwHigh16 & 0xffUL);
NG_ETHIF_DATA(((void *) netp), eif_addr[5]) = (NGubyte) ((dwHigh16 >> 8) & 0xffUL);
NG_ETHIF_DATA(((void *) netp), eif_addr[0]) = (NGubyte) (dwLow32 & 0xffUL);
NG_ETHIF_DATA(((void *) netp), eif_addr[1]) = (NGubyte) ((dwLow32 >> 8) & 0xffUL);
NG_ETHIF_DATA(((void *) netp), eif_addr[2]) = (NGubyte) ((dwLow32 >> 16) & 0xffUL);
NG_ETHIF_DATA(((void *) netp), eif_addr[3]) = (NGubyte) ((dwLow32 >> 24) & 0xffUL);
}
return TRUE;
}
/*
****************************************************************************
* Indirect (MAC) Registers and Reader/Writers
****************************************************************************
*/
static BOOLEAN Lan_MacNotBusy(const DWORD dwLanBase)
{
NGuint i=0U;
#ifdef SMC_DEBUG
char buf [256];
#endif
/* wait for MAC not busy, w/ timeout */
for(i = 0U; i < 40U; i++)
{
if((GetRegDW(dwLanBase, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY_)==(0UL))
{
return TRUE;
}
}
#ifdef SMC_DEBUG
sprintf (buf, "timeout waiting for MAC not BUSY. MAC_CSR_CMD = 0x%08lX\n", (DWORD)(*(volatile DWORD *)(dwLanBase + MAC_CSR_CMD)));
OS_TEXT_OUT (buf);
#endif
return FALSE;
}
/*
FUNCTION: Lan_GetMacRegDW
This function is used to read a Mac Register.
This function is only intended to be called
from with in other Lan_xxx functions.
*/
DWORD Lan_GetMacRegDW(
const DWORD dwLanBase,
const DWORD dwOffset)
{
DWORD dwTemp;
/* wait until not busy, w/ timeout */
if (GetRegDW(dwLanBase, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY_)
{
#ifdef SMC_DEBUG
OS_TEXT_OUT ("LanGetMacRegDW() failed MAC already busy at entry\n");
#endif
return 0xFFFFFFFFUL;
}
/* send the MAC Cmd w/ offset */
SetRegDW(dwLanBase, MAC_CSR_CMD,
((dwOffset & 0x000000FFUL) | MAC_CSR_CMD_CSR_BUSY_ | MAC_CSR_CMD_R_NOT_W_));
/* force flush of previous write */
dwTemp = GetRegDW(dwLanBase, BYTE_TEST);
dwTemp = dwTemp;
/* wait for the read to happen, w/ timeout */
if (!Lan_MacNotBusy(dwLanBase))
{
#ifdef SMC_DEBUG
OS_TEXT_OUT ("LanGetMacRegDW() failed waiting for MAC not busy after read\n");
#endif
return 0xFFFFFFFFUL;
}
else
{
/* finally, return the read data */
return GetRegDW(dwLanBase, MAC_CSR_DATA);
}
}
/*
FUNCTION: Lan_SetMacRegDW
This function is used to write a Mac register.
This function is only intended to be called
from with in other Lan_xxx functions.
*/
void Lan_SetMacRegDW(
const DWORD dwLanBase,
const DWORD dwOffset,
const DWORD dwVal)
{
DWORD dwTemp;
if (GetRegDW(dwLanBase, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY_)
{
#ifdef SMC_DEBUG
OS_TEXT_OUT ("LanSetMacRegDW() failed MAC already busy at entry\n");
#endif
return;
}
/* send the data to write */
SetRegDW(dwLanBase, MAC_CSR_DATA, dwVal);
/* do the actual write */
SetRegDW(dwLanBase, MAC_CSR_CMD,
((dwOffset & 0x000000FFUL) | MAC_CSR_CMD_CSR_BUSY_));
/* force flush of previous write */
dwTemp = GetRegDW(dwLanBase, BYTE_TEST);
dwTemp = dwTemp;
/* wait for the write to complete, w/ timeout */
if (!Lan_MacNotBusy(dwLanBase))
{
#ifdef SMC_DEBUG
OS_TEXT_OUT ("LanSetMacRegDW() failed waiting for MAC not busy after write\n");
#endif
}
}
/* Phy_GetRegW () reads a 16-bit phy register values */
NGushort Phy_GetRegW(
const NGifnet * const netp,
const DWORD dwRegIndex)
{
const LAN9118_DATA *pLan9118Data;
DWORD dwLanBase;
int ictrl; /* save previous interrupt state */
DWORD dwAddr=0UL;
NGuint i=0U;
NGushort result= (NGushort) 0xFFFF;
dwLanBase = (DWORD) NG_ETHIF_DATA(((void *) netp), eif_base);
pLan9118Data = (PLAN9118_DATA) netp->if_devptr1;
ictrl = ngOSIntrCtl(NG_INTRCTL_DISABLE);
/* confirm MII not busy
*/
if ((Lan_GetMacRegDW(dwLanBase, MII_ACC) & MII_ACC_MII_BUSY_) != 0UL)
{
#ifdef SMC_DEBUG
OS_TEXT_OUT("MII is busy in Phy_GetRegW???\n");
#endif
result = (NGushort) 0;
goto DONE;
}
/* set the address, index & direction (read from PHY)
*/
dwAddr = ((pLan9118Data->dwPhyAddress&0x1FUL)<<11) | ((dwRegIndex & 0x1FUL)<<6);
Lan_SetMacRegDW(dwLanBase,MII_ACC,dwAddr);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -