📄 lan9118.c
字号:
/*
FUNCTION: Lan_GetLinkMode
Gets the link mode from the PHY,
Stores it in LAN9118_DATA and also returns it.
RETURN VALUE:
one of the following link modes
LINK_NO_LINK
LINK_10MPS_HALF
LINK_10MPS_FULL
LINK_100MPS_HALF
LINK_100MPS_FULL
*/
DWORD Lan_GetLinkMode(const LAN9118_DATA * const pLan9118Data)
{
DWORD result = LINK_NO_LINK;
WORD wRegVal;
const WORD wRegBSR = LanReadPhy(PHY_BSR);
wRegVal = LanReadPhy(PHY_BCR);
if (wRegVal & PHY_BCR_AUTO_NEG_ENABLE_)
{
if(wRegBSR & PHY_BSR_LINK_STATUS_)
{
WORD wTemp;
const WORD wRegADV = LanReadPhy(PHY_ANEG_ADV);
const WORD wRegLPA = LanReadPhy(PHY_ANEG_LPA);
wTemp = (WORD)(wRegLPA & wRegADV);
if(wTemp & PHY_ANEG_LPA_100FDX_)
{
result = LINK_100MPS_FULL;
}
else if(wTemp & PHY_ANEG_LPA_100HDX_)
{
result = LINK_100MPS_HALF;
}
else if(wTemp & PHY_ANEG_LPA_10FDX_)
{
result = LINK_10MPS_FULL;
}
else if(wTemp & PHY_ANEG_LPA_10HDX_)
{
result = LINK_10MPS_HALF;
}
else
{
// do nothing except making lint happy
}
// check Flow Control
if (wTemp & (WORD) (PHY_ANEG_LPA_100FDX_ | PHY_ANEG_LPA_10FDX_)) {
DWORD dwTemp;
if (wTemp & (WORD)0x0400U) {
// both support Symmetric Flow Control
dwTemp = LanReadMac(FLOW);
LanWriteMac(FLOW, dwTemp | FLOW_FCEN_);
dwTemp = GetRegDW(pLan9118Data->dwLanBase, AFC_CFG);
SetRegDW(pLan9118Data->dwLanBase, AFC_CFG, dwTemp | AFC_CFG_FCANY_);
}
else if (((wRegADV & 0x0C00) == 0x0C00) &&
((wRegLPA & 0x0C00) == 0x0800)) {
// Partner is Asymmetric Flow Control
// Enable Rx Only (Enable FC on MAC, Disable at AFC_CFG)
dwTemp = LanReadMac(FLOW);
LanWriteMac(FLOW, dwTemp | FLOW_FCEN_);
dwTemp = GetRegDW(pLan9118Data->dwLanBase, AFC_CFG);
SetRegDW(pLan9118Data->dwLanBase, AFC_CFG, dwTemp & ~AFC_CFG_FCANY_);
}
else {
// Disable Flow Control
dwTemp = LanReadMac(FLOW);
LanWriteMac(FLOW, dwTemp & ~FLOW_FCEN_);
dwTemp = GetRegDW(pLan9118Data->dwLanBase, AFC_CFG);
SetRegDW(pLan9118Data->dwLanBase, AFC_CFG, dwTemp & ~AFC_CFG_FCANY_);
}
}
else {
// Half-Duplex
// Disable Flow Control
DWORD dwTemp;
dwTemp = LanReadMac(FLOW);
LanWriteMac(FLOW, dwTemp & ~FLOW_FCEN_);
dwTemp = GetRegDW(pLan9118Data->dwLanBase, AFC_CFG);
SetRegDW(pLan9118Data->dwLanBase, AFC_CFG, dwTemp & ~AFC_CFG_FCANY_);
}
}
}
else
{
if (wRegBSR & PHY_BSR_LINK_STATUS_)
{
if (wRegVal & PHY_BCR_SPEED_SELECT_)
{
if (wRegVal & PHY_BCR_DUPLEX_MODE_)
{
result = LINK_100MPS_FULL;
}
else
{
result = LINK_100MPS_HALF;
}
}
else
{
if (wRegVal & PHY_BCR_DUPLEX_MODE_)
{
result = LINK_10MPS_FULL;
}
else
{
result = LINK_10MPS_HALF;
}
}
}
}
return result;
}
/*
FUNCTION: Lan_EnableInterrupt
Enables bits in INT_EN according to the set bits in dwMask
WARNING this has thread synchronization issues. Use with caution.
*/
void Lan_EnableInterrupt(const LAN9118_DATA * const pLan9118Data, const DWORD dwMask)
{
DWORD dwTemp;
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
dwTemp = GetRegDW(pLan9118Data->dwLanBase, INT_EN);
dwTemp |= dwMask;
SetRegDW(pLan9118Data->dwLanBase, INT_EN, dwTemp);
}
}
/*
FUNCTION: Lan_DisableInterrupt
Disables bits in INT_EN according to the set bits in dwMask
WARNING this has thread synchronization issues. Use with caution.
*/
void Lan_DisableInterrupt(const LAN9118_DATA * const pLan9118Data, const DWORD dwMask)
{
DWORD dwTemp;
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
dwTemp = GetRegDW(pLan9118Data->dwLanBase, INT_EN);
dwTemp &= (~dwMask);
SetRegDW(pLan9118Data->dwLanBase, INT_EN, dwTemp);
}
}
/*
FUNCTION: Lan_GetInterruptStatus
Reads and returns the value in the INT_STS register.
*/
DWORD Lan_GetInterruptStatus(const LAN9118_DATA * const pLan9118Data)
{
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
return GetRegDW(pLan9118Data->dwLanBase, INT_STS);
}
return 0xFFFFFFFFUL;
}
/*
FUNCTION: Lan_EnableIRQ
Sets IRQ_EN in the INT_CFG registers.
WARNING this has thread synchronization issues. Use with caution.
*/
void Lan_EnableIRQ(const LAN9118_DATA * const pLan9118Data)
{
DWORD dwRegVal = 0UL;
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
dwRegVal = GetRegDW(pLan9118Data->dwLanBase, INT_CFG);
dwRegVal |= INT_CFG_IRQ_EN_;
SetRegDW(pLan9118Data->dwLanBase, INT_CFG, dwRegVal);
}
}
/*
FUNCTION: Lan_DisableIRQ
Clears IRQ_EN in the INT_CFG registers.
WARNING this has thread sychronization issues. Use with caution.
*/
void Lan_DisableIRQ(const LAN9118_DATA * const pLan9118Data)
{
DWORD dwRegVal = 0UL;
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
dwRegVal = GetRegDW(pLan9118Data->dwLanBase, INT_CFG);
dwRegVal &= ~(INT_CFG_IRQ_EN_);
SetRegDW(pLan9118Data->dwLanBase, INT_CFG, dwRegVal);
}
}
/*
FUNCTION: Lan_ClearInterruptStatus
Clears the bits in INT_STS according to the bits set in dwMask
*/
void Lan_ClearInterruptStatus(const LAN9118_DATA * const pLan9118Data, const DWORD dwMask)
{
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
SetRegDW(pLan9118Data->dwLanBase, INT_STS, dwMask);
}
}
/*
FUNCTION: Lan_InitializeInterrupts
Should be called after Lan_Initialize
Should be called before the ISR is registered.
*/
void Lan_InitializeInterrupts(LAN9118_DATA * const pLan9118Data, DWORD dwIntCfg)
{
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
SMSC_ASSERT(pLan9118Data->LanInitialized == TRUE);
SetRegDW(pLan9118Data->dwLanBase, INT_EN, 0UL);
SetRegDW(pLan9118Data->dwLanBase, INT_STS, 0xFFFFFFFFUL);
dwIntCfg |= INT_CFG_IRQ_EN_;
SetRegDW(pLan9118Data->dwLanBase, INT_CFG, dwIntCfg);
pLan9118Data->InterruptsInitialized = (BOOLEAN)TRUE;
}
}
/*
FUNCTION: Lan_EnableSoftwareInterrupt
Clears a flag in the LAN9118_DATA structure
Sets the SW_INT_EN bit of the INT_EN register
WARNING this has thread sychronization issues. Use with caution.
*/
void Lan_EnableSoftwareInterrupt(PLAN9118_DATA pLan9118Data)
{
DWORD dwTemp = 0UL;
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
pLan9118Data->SoftwareInterruptSignal = (BOOLEAN)FALSE;
dwTemp = GetRegDW(pLan9118Data->dwLanBase, INT_EN);
dwTemp |= INT_EN_SW_INT_EN_;
SetRegDW(pLan9118Data->dwLanBase, INT_EN, dwTemp);
}
}
/*
FUNCTION: Lan_HandleSoftwareInterrupt
Disables the SW_INT_EN bit of the INT_EN register,
Clears the SW_INT in the INT_STS,
Sets a flag in the LAN9118_DATA structure
*/
void Lan_HandleSoftwareInterrupt(PLAN9118_DATA pLan9118Data)
{
DWORD dwTemp = 0UL;
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
dwTemp = GetRegDW(pLan9118Data->dwLanBase, INT_EN);
dwTemp &= ~(INT_EN_SW_INT_EN_);
SetRegDW(pLan9118Data->dwLanBase, INT_EN, dwTemp);
SetRegDW(pLan9118Data->dwLanBase, INT_STS, INT_STS_SW_INT_);
pLan9118Data->SoftwareInterruptSignal = (BOOLEAN)TRUE;
}
}
/*
FUNCTION: Lan_IsSoftwareInterruptSignaled
returns the set/cleared state of the flag used in
Lan_EnableSoftwareInterrupt
Lan_HandleSoftwareInterrupt
*/
BOOLEAN Lan_IsSoftwareInterruptSignaled(const LAN9118_DATA * const pLan9118Data)
{
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
return pLan9118Data->SoftwareInterruptSignal;
}
else
{
return (BOOLEAN)FALSE;
}
}
void Lan_SetMacAddress(PLAN9118_DATA const pLan9118Data, const DWORD dwHigh16, const DWORD dwLow32)
{
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
Lan_SetMacRegDW(pLan9118Data->dwLanBase, ADDRH, dwHigh16);
Lan_SetMacRegDW(pLan9118Data->dwLanBase, ADDRL, dwLow32);
pLan9118Data->dwMacAddrHigh16 = dwHigh16;
pLan9118Data->dwMacAddrLow32 = dwLow32;
}
}
void Lan_GetMacAddress(PLAN9118_DATA const pLan9118Data, DWORD * const dwHigh16,DWORD * const dwLow32)
{
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
*dwHigh16 = pLan9118Data->dwMacAddrHigh16=
Lan_GetMacRegDW(pLan9118Data->dwLanBase, ADDRH);
*dwLow32 = pLan9118Data->dwMacAddrLow32=
Lan_GetMacRegDW(pLan9118Data->dwLanBase, ADDRL);
}
}
void Lan_InitializeTx(PLAN9118_DATA const pLan9118Data)
{
DWORD dwRegVal = 0UL;
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
SMSC_ASSERT(pLan9118Data->InterruptsInitialized == TRUE);
SMSC_ASSERT(pLan9118Data->PhyInitialized == TRUE);
// setup MAC for TX
dwRegVal = Lan_GetMacRegDW(pLan9118Data->dwLanBase, MAC_CR);
dwRegVal |= (MAC_CR_TXEN_ | MAC_CR_HBDIS_);
Lan_SetMacRegDW(pLan9118Data->dwLanBase, MAC_CR, dwRegVal);
//setup TLI store-and-forward, and preserve TxFifo size
dwRegVal = GetRegDW(pLan9118Data->dwLanBase, HW_CFG);
// some chips (may) use bit 11~0
dwRegVal &= (HW_CFG_TX_FIF_SZ_ | 0xFFFUL);
dwRegVal |= HW_CFG_SF_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwRegVal);
SetRegDW(pLan9118Data->dwLanBase, TX_CFG, TX_CFG_TX_ON_);
SetRegDW(pLan9118Data->dwLanBase, FIFO_INT, 0xFF000000UL);
Lan_EnableInterrupt(pLan9118Data,
INT_EN_TDFU_EN_ | INT_EN_TDFO_EN_ | INT_EN_TDFA_EN_);
pLan9118Data->TxInitialized = (BOOLEAN)TRUE;
}
}
void Lan_StartTx(const LAN9118_DATA * const pLan9118Data, const DWORD dwTxCmdA, const DWORD dwTxCmdB)
{
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
SMSC_ASSERT(pLan9118Data->TxInitialized == TRUE);
SetRegDW(pLan9118Data->dwLanBase, TX_DATA_FIFO_PORT ,dwTxCmdA);
SetRegDW(pLan9118Data->dwLanBase, TX_DATA_FIFO_PORT, dwTxCmdB);
}
}
void Lan_SendPacketPIO(const LAN9118_DATA * const pLan9118Data, const WORD wPacketTag, const WORD wPacketLength, BYTE * pbPacketData)
{
DWORD dwTxCmdA;
DWORD dwTxCmdB;
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
SMSC_ASSERT(pLan9118Data->TxInitialized == TRUE);
if(wPacketTag == 0)
{
SMSC_WARNING0("Lan_SendPacketPIO(wPacketTag==0) Zero is reserved\n");
}
dwTxCmdA=(
((((DWORD)pbPacketData)&0x03UL)<<16) | //DWORD alignment adjustment
TX_CMD_A_INT_FIRST_SEG_ | TX_CMD_A_INT_LAST_SEG_ |
((DWORD)wPacketLength));
dwTxCmdB=
(((DWORD)wPacketTag)<<16) |
((DWORD)wPacketLength);
SetRegDW(pLan9118Data->dwLanBase,TX_DATA_FIFO_PORT,dwTxCmdA);
SetRegDW(pLan9118Data->dwLanBase,TX_DATA_FIFO_PORT,dwTxCmdB);
Lan_WriteTxFifo(
pLan9118Data->dwLanBase,
(DWORD *)(((DWORD)pbPacketData)&0xFFFFFFFCUL),
((DWORD)wPacketLength+3UL+
(((DWORD)pbPacketData)&0x03UL))>>2);
}
}
DWORD Lan_CompleteTx(const LAN9118_DATA * const pLan9118Data)
{
DWORD result = 0UL;
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase!=0UL);
SMSC_ASSERT(pLan9118Data->TxInitialized==TRUE);
result = GetRegDW(pLan9118Data->dwLanBase,TX_FIFO_INF);
result &= TX_FIFO_INF_TSUSED_;
if(result != 0x00000000UL) {
result = GetRegDW(pLan9118Data->dwLanBase,TX_STATUS_FIFO_PORT);
} else {
result = 0UL;
}
}
return result;
}
DWORD Lan_GetTxDataFreeSpace(const LAN9118_DATA * const pLan9118Data)
{
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
return GetRegDW(pLan9118Data->dwLanBase,TX_FIFO_INF) & TX_FIFO_INF_TDFREE_;
}
else
{
return 0x0UL;
}
}
DWORD Lan_GetTxStatusCount(const LAN9118_DATA * const pLan9118Data)
{
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
return ((GetRegDW(pLan9118Data->dwLanBase,TX_FIFO_INF) & (TX_FIFO_INF_TSUSED_)) >> 16) & 0xFFFFUL;
}
else
{
return 0x0UL;
}
}
void Lan_InitializeRx(CPCLAN9118_DATA pLan9118Data, const DWORD dwRxCfg, const DWORD dw)
{
DWORD dwRegVal = 0UL;
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
SMSC_ASSERT(pLan9118Data->InterruptsInitialized == TRUE);
SMSC_ASSERT(pLan9118Data->PhyInitialized == TRUE);
//set receive configuration
SetRegDW(pLan9118Data->dwLanBase, RX_CFG, dwRxCfg);
//set the interrupt levels to zero
dwRegVal = GetRegDW(pLan9118Data->dwLanBase, FIFO_INT);
dwRegVal &= 0xFFFF0000UL;
dwRegVal |= (dw & 0x0000FFFFUL);
SetRegDW(pLan9118Data->dwLanBase, FIFO_INT, dwRegVal);
//enable interrupt
Lan_EnableInterrupt(pLan9118Data, INT_EN_RSFL_EN_);
}
}
DWORD Lan_PopRxStatus(CPCLAN9118_DATA pLan9118Data)
{
DWORD result = 0UL;
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data)
{
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
result = GetRegDW(pLan9118Data->dwLanBase, RX_FIFO_INF);
if(result & 0x00FF0000UL) {
//Rx status is available, read it
result = GetRegDW(pLan9118Data->dwLanBase,RX_STATUS_FIFO_PORT);
} else {
result = 0UL;
}
}
return result;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -