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

📄 lan9118.c

📁 wince 6.0下SMSC9118 100M网卡驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	/* reset the PHY */
	Lan_SetPhyRegW(pLan9118Data->dwLanBase, (DWORD)bPhyAddress, PHY_BCR, PHY_BCR_RESET_);
	dwLoopCount = 100000UL;
	do {
		SMSC_MICRO_DELAY(10U);
		dwTemp = (DWORD)Lan_GetPhyRegW(pLan9118Data->dwLanBase, (DWORD)bPhyAddress, PHY_BCR);
		dwLoopCount--;
	} while ((dwLoopCount>0UL) && (dwTemp & (DWORD)PHY_BCR_RESET_));
	if (dwTemp & (DWORD)PHY_BCR_RESET_) {
		SMSC_WARNING0("PHY reset failed to complete.\r\n");
		goto DONE;
	}
#ifdef USE_PHY_WORK_AROUND	// on internal PHY use only
	if (ExtPhy == FALSE) 	// 031305 WH
	{
		// workaround for 118/117/116/115 family
		if (((pLan9118Data->dwIdRev & 0xFFF0FFFFUL) == 0x01100001UL) ||
			((pLan9118Data->dwIdRev & 0xFFF0FFFFUL) == 0x01100002UL))
		{
			if(!Phy_LoopBackTest(pLan9118Data) && (pLan9118Data->bPhyAddress==(BYTE)1)) {
				SMSC_WARNING1("Failed Loop Back Test, reset %d times\n\r",
					pLan9118Data->dwResetCount);
				goto DONE;
			} else {
				SMSC_WARNING1("Passed Loop Back Test, reset %d times\n\r",
					pLan9118Data->dwResetCount);
			}	
		}
	}
#endif //USE_PHY_WORK_AROUND	// on internal PHY use only


if (ExtPhy == FALSE) 
{
	if (((pLan9118Data->dwIdRev & 0x000F0000UL) == 0x000A0000UL) | 
		((pLan9118Data->dwIdRev & 0xFFF00000UL) == 0x92100000UL))
	{
		Lan_SetAutoMdixSts(pLan9118Data);
	}
	else
	{
		RETAILMSG(1, (TEXT("This chip doesn't support Auto Mdix!!!\r\n")));
	}
}

	pLan9118Data->PhyInitialized = (BOOLEAN)TRUE;

	result = TRUE;
DONE:
	SMSC_TRACE1(DBG_INIT,"-Lan_InitializePhy, result=%s\r\n",result?TEXT("TRUE"):TEXT("FALSE"));
	return result;
}

/*
FUNCTION: Lan_AutoNegotiate
RETURN VALUE:
	returns TRUE on success.
	returns FALSE on failure.
*/
BOOLEAN Lan_AutoNegotiate(const LAN9118_DATA * const pLan9118Data)
{
	DWORD dwTimeout=0UL;
	WORD  wTemp, wBreaknow=(WORD)0;

	SMSC_TRACE0(DBG_INIT, "+Lan_AutoNegotiate(...)\n");

	wTemp = (WORD)(PHY_BCR_AUTO_NEG_ENABLE_ | PHY_BCR_RESTART_AUTO_NEG_);
	LanWritePhy(PHY_BCR, wTemp);

Restart_AutoNegotiation:
	wBreaknow++;
	dwTimeout = 100000UL;
	// Check for the completion and the remote fault
	do {
		wTemp = LanReadPhy(PHY_BSR);
	} while((dwTimeout-- > 0UL) && 
			!((wTemp & (WORD)PHY_BSR_REMOTE_FAULT_) || 
			 (wTemp & (WORD)PHY_BSR_AUTO_NEG_COMP_)));

	if(wTemp & (WORD)PHY_BSR_REMOTE_FAULT_) {
		SMSC_TRACE0(DBG_INIT,"Autonegotiation Remote Fault\n");
		if(wBreaknow < 10)
		{
			goto Restart_AutoNegotiation;
		}
	}

	SMSC_TRACE0(DBG_INIT, "-Lan_AutoNegotiate(...)\n");
	return (BOOLEAN)FALSE;
}

/*
FUNCTION: Lan_EstablishLink
  This function similar to Lan_RequestLink except that it is
  not interrupt driven. This function will not return until 
  either the link is established or link can not be established.
RETURN VALUE:
	returns TRUE on success.
	returns FALSE on failure.
*/
BOOL Lan_EstablishLink(PLAN9118_DATA pLan9118Data, const DWORD dwLinkRequest)
{
	WORD	wTemp, wRegVal = (WORD)0;
	DWORD	dwRegVal = 0UL;
	BOOL	result = TRUE;

	SMSC_TRACE2(DBG_INIT, "+Lan_EstablishLink(pLan9118Data==0x%08lX,dwLinkRequest==%ld)\r\n", (DWORD)pLan9118Data,dwLinkRequest);

	if (dwLinkRequest & LINKMODE_ANEG) {
		// Enable ANEG
		wTemp = LanReadPhy(PHY_BCR);
		wTemp = (WORD)(wTemp | PHY_BCR_AUTO_NEG_ENABLE_);
		LanWritePhy(PHY_BCR, wTemp);
		// Set ANEG Advertise
		wTemp = LanReadPhy(PHY_ANEG_ADV);
		wTemp = (WORD)(wTemp & ~(PHY_ANEG_ADV_PAUSE_OP_ | PHY_ANEG_ADV_SPEED_));
		if (dwLinkRequest & LINKMODE_ASYM_PAUSE)
		{
			wTemp = (WORD)(wTemp | PHY_ANEG_ADV_ASYM_PAUSE_);
		}
		if (dwLinkRequest & LINKMODE_SYM_PAUSE)
		{
			wTemp = (WORD)(wTemp | PHY_ANEG_ADV_SYM_PAUSE_);
		}
		if (dwLinkRequest & LINKMODE_100_FD)
		{
			wTemp = (WORD)(wTemp | PHY_ANEG_ADV_100F_);
		}
		if (dwLinkRequest & LINKMODE_100_HD)
		{
			wTemp = (WORD)(wTemp | PHY_ANEG_ADV_100H_);
		}
		if (dwLinkRequest & LINKMODE_10_FD)
		{
			wTemp = (WORD)(wTemp | PHY_ANEG_ADV_10F_);
		}
		if (dwLinkRequest & LINKMODE_10_HD)
		{
			wTemp = (WORD)(wTemp | PHY_ANEG_ADV_10H_);
		}
		LanWritePhy(PHY_ANEG_ADV, wTemp);

		if(!Lan_AutoNegotiate(pLan9118Data))
		{
			pLan9118Data->dwLinkMode = LINK_NO_LINK;
			SMSC_TRACE0(DBG_INIT,"Auto Negotiation Failed !\r\n");
			result = FALSE;
		} 
		else 
		{
			SMSC_TRACE0(DBG_INIT,"Auto Negotiation Complete\r\n");
		}

		//Clear any pending interrupts
		wRegVal = LanReadPhy(PHY_INT_SRC);
		// avoid lint error
		wRegVal = wRegVal;

		//CheckForLink
		pLan9118Data->dwLinkMode = Lan_GetLinkMode(pLan9118Data);

		dwRegVal = Lan_GetMacRegDW(pLan9118Data->dwLanBase, MAC_CR);
		dwRegVal &= ~(MAC_CR_FDPX_|MAC_CR_RCVOWN_);

		switch(pLan9118Data->dwLinkMode) 
		{
			case LINK_NO_LINK:
				SMSC_TRACE0(DBG_INIT,"There is no Link\r\n");
				//TODO: consider auto linking to a specified link state.
				break;

			case LINK_10MPS_HALF:
				SMSC_TRACE0(DBG_INIT,"Link is 10Mbps Half Duplex\r\n");
				dwRegVal|=MAC_CR_RCVOWN_;
				break;

			case LINK_10MPS_FULL:
				SMSC_TRACE0(DBG_INIT,"Link is 10Mbps Full Duplex\r\n");
				dwRegVal|=MAC_CR_FDPX_;
				break;

			case LINK_100MPS_HALF:
				SMSC_TRACE0(DBG_INIT,"Link is 100Mbps Half Duplex\r\n");
				dwRegVal|=MAC_CR_RCVOWN_;
				break;

			case LINK_100MPS_FULL:
				SMSC_TRACE0(DBG_INIT,"Link is 100Mbps Full Duplex\r\n");
				dwRegVal|=MAC_CR_FDPX_;
				break;

			default:
				SMSC_TRACE0(DBG_INIT,"Unknown LinkMode\r\n");
				break;
		}

		Lan_SetMacRegDW(pLan9118Data->dwLanBase, MAC_CR, dwRegVal);

	}
	else {
		// Non-ANEG
		// If multiple mode bits were set, it uses following priority,
		//	 100FD->100HD->10FD->10HD
		wTemp = LanReadPhy(PHY_BCR);
		if (dwLinkRequest & LINKMODE_100_FD) {
			wTemp = (WORD)(wTemp & ~(PHY_BCR_AUTO_NEG_ENABLE_ | PHY_BCR_RESTART_AUTO_NEG_));
			wTemp = (WORD)(wTemp | (PHY_BCR_SPEED_SELECT_ | PHY_BCR_DUPLEX_MODE_));
		}
		else if (dwLinkRequest & LINKMODE_100_HD) {
			wTemp = (WORD)(wTemp & ~(PHY_BCR_AUTO_NEG_ENABLE_ | PHY_BCR_RESTART_AUTO_NEG_));
			wTemp = (WORD)(wTemp | PHY_BCR_SPEED_SELECT_);
			wTemp = (WORD)(wTemp & ~PHY_BCR_DUPLEX_MODE_);
		}
		else if (dwLinkRequest & LINKMODE_10_FD) {
			wTemp = (WORD)(wTemp & ~(PHY_BCR_AUTO_NEG_ENABLE_ | PHY_BCR_RESTART_AUTO_NEG_));
			wTemp = (WORD)(wTemp & ~PHY_BCR_SPEED_SELECT_);
			wTemp = (WORD)(wTemp | PHY_BCR_DUPLEX_MODE_);
		}
		else if (dwLinkRequest & LINKMODE_10_HD) {
			wTemp = (WORD)(wTemp & ~(PHY_BCR_AUTO_NEG_ENABLE_ | PHY_BCR_RESTART_AUTO_NEG_));
			wTemp = (WORD)(wTemp & ~(PHY_BCR_SPEED_SELECT_ | PHY_BCR_DUPLEX_MODE_));
		}
		else {
			RETAILMSG(1, (TEXT("Error! No Link Mode was Set.\r\n")));
			return FALSE;
		}
		LanWritePhy(PHY_BCR, wTemp);

		//Clear any pending interrupts
		wRegVal = LanReadPhy(PHY_INT_SRC);
		// avoid lint error
		wRegVal = wRegVal;

		//CheckForLink
		dwRegVal = Lan_GetMacRegDW(pLan9118Data->dwLanBase, MAC_CR);
		dwRegVal &= ~(MAC_CR_FDPX_|MAC_CR_RCVOWN_);

		if (dwLinkRequest & LINKMODE_100_FD) {
				dwRegVal|=MAC_CR_FDPX_;
		}
		else if (dwLinkRequest & LINKMODE_100_HD) {
				dwRegVal|=MAC_CR_RCVOWN_;
		}
		else if (dwLinkRequest & LINKMODE_10_FD) {
				dwRegVal|=MAC_CR_FDPX_;
		}
		else if (dwLinkRequest & LINKMODE_10_HD) {
				dwRegVal|=MAC_CR_RCVOWN_;
		}
		else 
		{
			// do nothing except making lint happy
		}

		Lan_SetMacRegDW(pLan9118Data->dwLanBase, MAC_CR, dwRegVal);
	}
	SMSC_TRACE1(DBG_INIT,"-Lan_EstablishLink, result=%s\r\n",result?TEXT("TRUE"):TEXT("FALSE"));
	return result;
}


/*
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;
}




void Lan_SetAutoMdixSts(PLAN9118_DATA pLan9118Data)
{
	WORD wAutoMdixSts = pLan9118Data->wAutoMdix;
	WORD SpecialCtrlSts=0U;

		if (wAutoMdixSts > 2)
		{

			SpecialCtrlSts=LanReadPhy(SPECIAL_CTRL_STS);
			SpecialCtrlSts = (SpecialCtrlSts&0x1FFF);
			LanWritePhy(SPECIAL_CTRL_STS,SpecialCtrlSts);

			if (GetRegDW(pLan9118Data->dwLanBase, HW_CFG) & HW_CFG_AMDIX_EN_STRAP_STS_)
			{
				RETAILMSG(1, (TEXT("Auto-MDIX Enable by default!!!\r\n")));
			}
			else {
				RETAILMSG(1, (TEXT("Auto-MDIX Disable by default!!!\r\n")));
			}
			pLan9118Data->wAutoMdix=3;
        }
		else 
		{

			SpecialCtrlSts=LanReadPhy(SPECIAL_CTRL_STS);
			SpecialCtrlSts = (((wAutoMdixSts+4) << 13) | (SpecialCtrlSts&0x1FFF));
			LanWritePhy(SPECIAL_CTRL_STS,SpecialCtrlSts);

			if (wAutoMdixSts & AMDIX_ENABLE) {
				RETAILMSG(1, (TEXT("Override Strap, Enable Auto-MDIX\r\n")));
			} else if (wAutoMdixSts & AMDIX_DISABLE_CROSSOVER) {
				RETAILMSG(1, (TEXT("Override Strap, Disable Auto-MDIX, CrossOver Cable\r\n")));		
			} else {
				RETAILMSG(1, (TEXT("Override Strap, Disable Auto-MDIX, Straight Cable\r\n")));	
			}
			pLan9118Data->wAutoMdix=wAutoMdixSts;
			
		}
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -