⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lan9118.c

📁 SMSC9118网卡驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
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 + -