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

📄 nicmiiwork.c

📁 3com3c905网卡驱动程序
💻 C
字号:
/*******************************************************************************
*** Note: Copy rights resevered to Beijing Pacific Linkair Communications Co. 
***
*** File Name: NICMii.c
*** Purpose  : Operations about MII 
***
*** Author   : Guangzhao Tian
*** Modified : By Guangzhao Tian at 2000/9/11
***
**/

#include "NICMacro.h"
#include "NICWinReg.h"
#include "NICCommand.h"
#include "NICEeprom.h"
#include "NICData.h"
#include "NICHelper.h"
#include "NICMii.h"
#include "NICExport.h"

/***********************************************************************
*** Used to detect if 10Base-T, 100Base-TX, or external MII is available. 
**/
BOOLEAN NIC_MIITryIt(IN PNIC_INFORMATION pAdapter,IN USHORT MediaOptions ) 
{
    BOOLEAN bHandles100Mbit = FALSE;
	USHORT  wPhyStatus=0;

    /* First see if there's anything connected to the MII */
    if (!NIC_MIIFindPhy(pAdapter) )
	{
		DebugMsg("Cannot find MII!\n");
		pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
		return FALSE;
    }
  
    DebugMsg(" We find the MII available ! \n");
    /* Nowhere is it written that the register must be latched, and since  reset is the last bit out,
          the contents might not be valid.  read it one more time.*/

    /* Now we can read the status and try to figure out what's out there. */
    if (! NIC_MIIReadPhy(pAdapter, MII_PHY_STATUS, &wPhyStatus) ) 
	{
    	DebugMsg("Error: PHY not responding when getting status ! \n");
	   	pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;  
		return FALSE;
    }
    
   if ( (wPhyStatus & MII_STATUS_AUTO) &&  (wPhyStatus & MII_STATUS_EXTENDED) ) 
	{
		/*  If it is capable of auto negotiation, see if it has been done already. */
			DebugMsg("  MII Capable of Autonegotiation ! \n"); 

		/* Check the current MII auto-negotiation state and see if we need to start auto-neg over.  */
		if ( !NIC_MIICheckConfg(pAdapter, MediaOptions) )
        {
            DebugMsg(" We cannot config the MII Phy ! \n");
        	return FALSE;
        }
			DebugMsg("  MII auto-negotiation state -- OK ! \n"); 

		/* See if link is up... */
		if (! NIC_MIIReadPhy(pAdapter, MII_PHY_STATUS, &wPhyStatus) ) 
		{
     		DebugMsg("Error: PHY not responding when getting status ! \n");
		 	pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;  
			return FALSE;
		}

		if (wPhyStatus  & MII_STATUS_LINK_UP) 
		{  
			if (!NIC_MIILinkSpeedGet(pAdapter, &bHandles100Mbit))
			{
				DebugMsg(" Unknown link speed! \n");
				pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
				return FALSE;
			} 

			if (bHandles100Mbit) 
			{ 	pAdapter->LinkInfo.LinkSpeed = LINK_SPEED_100;	} 
			else
			{	pAdapter->LinkInfo.LinkSpeed = LINK_SPEED_10;	}
			  
			return TRUE;
		} 
		else 
		{ 
			DebugMsg(" Auto Negotiations not completed, or even not be executed at all, use default! \n");
           /* Assume 10Mbit if no link*/
			if (wPhyStatus & MII_STATUS_100MB_MASK)
			{	pAdapter->LinkInfo.LinkSpeed = LINK_SPEED_100;	}
			else 
			{	pAdapter->LinkInfo.LinkSpeed = LINK_SPEED_10;	}

			return TRUE;
		} 
	} 

    return FALSE;
}

/*************************************************************************************************
*** Sets up the tranceiver through MII registers. This will first check on the current connection
***	state as shown by the MII registers. If the current state matches what the media options support,
***	then the link is kept. If not, the registers will be configured in the proper manner and auto-negotiation
***	will be restarted.
***	Since this function is called for forced xcvr configurations, it assumes that the xcvr type has
***	been verified as supported by the NIC.
**/
BOOLEAN NIC_MIICheckConfg(IN PNIC_INFORMATION pAdapter, IN USHORT pMediaOptions	) 
{
	BOOLEAN PhyResponding;
	USHORT PhyControl;
	USHORT PhyStatus;
	USHORT PhyAnar;
	USHORT tempAnar;

	/* Check to see if auto-negotiation has completed. Check the results in the control and status registers. */
	PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_CONTROL, &PhyControl);
	if (!PhyResponding) 
	{		
		DebugMsg(" Error: Phy not responding ! \n");
		pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
		return FALSE;
	}

	PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_STATUS, &PhyStatus);
	if (!PhyResponding) 
	{
		DebugMsg(" Error: Phy not responding ! \n");
		pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
		return FALSE;
	}

	if ( ! ( (PhyControl & MII_CONTROL_ENABLE_AUTO) && (PhyStatus & MII_STATUS_AUTO_DONE) ) )
	{
		/* Auto-negotiation did not complete, so start it over using the new settings. */
		if ( !NIC_MIIConfig(pAdapter,pMediaOptions) )	return FALSE;
	}

	/* Auto-negotiation has completed. Check the results against the ANAR and ANLPAR
	    registers to see if we need to restart auto-neg. */
	PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_ANAR, &PhyAnar);
	if (!PhyResponding) 
	{		
		DebugMsg(" Error: Phy not responding ! \n");
		pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
		return FALSE;
	}

	/*  Check to see what we negotiated with the link partner. First, let's make
	    sure that the ANAR is set properly based on the media options defined. */
	tempAnar = 0;
	if (pMediaOptions & MEDIA_OPTIONS_100BASETX_AVAILABLE)
	{
		if (pAdapter->LinkInfo.AutoSelect) 	tempAnar |= MII_ANAR_100TXFD | MII_ANAR_100TX;
		else
		{
			if (pAdapter->LinkInfo.FullDuplexEnable)	tempAnar |= MII_ANAR_100TXFD;
			else										tempAnar |= MII_ANAR_100TX;
		}
	}

	if (pMediaOptions & MEDIA_OPTIONS_10BASET_AVAILABLE)
	{
		if (pAdapter->LinkInfo.AutoSelect)		tempAnar |= MII_ANAR_10TFD | MII_ANAR_10T;
		else 
		{
			if (pAdapter->LinkInfo.FullDuplexEnable)	tempAnar |= MII_ANAR_10TFD;
			else								    	tempAnar |= MII_ANAR_10T;
		}
	}

	if ( pAdapter->LinkInfo.FullDuplexEnable &&	pAdapter->LinkInfo.FlowControlSupported )
		tempAnar |= MII_ANAR_FLOWCONTROL;

	if ( (PhyAnar & MII_ANAR_MEDIA_MASK) == tempAnar) 
	{
		/*The negotiated configuration hasn't changed. So, return and don't restart auto-negotiation.*/
		return TRUE;
	}
	
	/* Check the media settings. */
	if (pMediaOptions & MEDIA_OPTIONS_100BASETX_AVAILABLE) 
	{
		/* Check 100BaseTX settings. */
		if ( (PhyAnar & MII_ANAR_MEDIA_100_MASK) != (tempAnar & MII_ANAR_MEDIA_100_MASK) )
		{
	    	DebugMsg("  Now We Re-Initiating autonegotiation...\n") ; 
			return NIC_MIIConfig(pAdapter,pMediaOptions);
		}
	}

	if (pMediaOptions & MEDIA_OPTIONS_10BASET_AVAILABLE)
	{
		/* Check 10BaseT settings. */
		if ( (PhyAnar & MII_ANAR_MEDIA_10_MASK) != (tempAnar & MII_ANAR_MEDIA_10_MASK) ) 
		{
	    	DebugMsg("  Now We Re-Initiating autonegotiation...\n") ; 
			return NIC_MIIConfig(pAdapter,pMediaOptions);
		}
	}        

	return TRUE;
}


/**************************************************************************************************
*** Used to setup the configuration for 10Base-T and 100Base-TX.
**/
BOOLEAN NIC_MIIConfig(IN PNIC_INFORMATION pAdapter,IN USHORT MediaOptions) 
{
	BOOLEAN PhyResponding;
    USHORT PhyControl;
	USHORT PhyAnar;
    USHORT PhyStatusReset;

	ULONG TimeOutCount;
        
    /* Nowhere is it written that the register must be latched, and since reset is 
		the last bit out, the contents might not be valid.  read it one more time.*/
    PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_CONTROL, &PhyControl);
    if (!PhyResponding) 
	{
		DebugMsg(" Error: PHY not responding ! \n");
		pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
		return FALSE;
	} 

	/* Also, read the ANAR register and clear out it's current settings. */
    PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_ANAR, &PhyAnar);
    if (!PhyResponding) 
	{	
		DebugMsg(" Error: PHY not responding ! \n");
		pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
		return FALSE;
	}
	/* Set up speed and duplex settings in MII Control and ANAR register. */
	PhyAnar &= ~( MII_ANAR_100TXFD|	MII_ANAR_100TX	|MII_ANAR_10TFD	|MII_ANAR_10T);

	/* Set up duplex. */
	if (pAdapter->LinkInfo.FullDuplexEnable)  PhyControl |= MII_CONTROL_FULL_DUPLEX;
	else									  PhyControl &= ~(MII_CONTROL_FULL_DUPLEX);

	/* Set up flow control.
	     NOTE: On some NICs, such as Tornado, this will be hardwired to be set.
	     Clearing it will have no effect. */
	if (pAdapter->LinkInfo.FlowControlSupported) 	PhyAnar |= MII_ANAR_FLOWCONTROL;
	else											PhyAnar &= ~(MII_ANAR_FLOWCONTROL);

	/* Set up the media options. For duplex settings, if we're set to auto-select 
	   then enable both half and full-duplex settings. Otherwise, go by what's 
	   been enabled for duplex mode. */
	if (MediaOptions & MEDIA_OPTIONS_100BASETX_AVAILABLE)
	{
		if (pAdapter->LinkInfo.AutoSelect)	PhyAnar |= (MII_ANAR_100TXFD | MII_ANAR_100TX);
		else
		{ 
			if (pAdapter->LinkInfo.FullDuplexEnable)	PhyAnar |= MII_ANAR_100TXFD;
			else										PhyAnar |= MII_ANAR_100TX;
		}
	}

	if (MediaOptions & MEDIA_OPTIONS_10BASET_AVAILABLE)
	{
		if (pAdapter->LinkInfo.AutoSelect)	PhyAnar |= (MII_ANAR_10TFD | MII_ANAR_10T);
		else 
		{
			if (pAdapter->LinkInfo.FullDuplexEnable)	PhyAnar |= MII_ANAR_10TFD;
			else									    PhyAnar |= MII_ANAR_10T;
		}
	}

	/* Enable and start auto-negotiation */
	PhyControl |= (MII_CONTROL_ENABLE_AUTO | MII_CONTROL_START_AUTO);

	/* Write the MII registers back. */
	NIC_MIIWritePhy(pAdapter, MII_PHY_ANAR, PhyAnar);
	NIC_MIIWritePhy(pAdapter, MII_PHY_CONTROL, PhyControl);

	/* Wait for auto-negotiation to finish. */
	NIC_DELAY(MII_RESETWAITTIMEs);

	PhyResponding = NIC_MIIReadPhy(pAdapter,MII_PHY_STATUS, &PhyStatusReset);
	if (!PhyResponding)
	{
		DebugMsg(" Error: PHY not responding ! \n");
		pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
		return FALSE;
	}

	if (! (PhyStatusReset & MII_STATUS_AUTO_DONE) )
	{	
        DebugMsg(" Error: Auto Negotionation not done ! \n");
		pAdapter->LinkInfo.LinkState = LINK_DOWN_AT_INIT;
		return FALSE;
	}

	pAdapter->LinkInfo.LinkState = LINK_UP;
	return TRUE;
}

/**********************************************************************************************
**** Since this function is called for forced xcvr configurations, it assumes that the xcvr type has
**** been verified as supported by the NIC.
**/
VOID NIC_MIICheckErrorReason( IN PNIC_INFORMATION pAdapter	) 
{
	BOOLEAN PhyResponding;
	USHORT PhyStatus;
	USHORT PhyAnar;
	USHORT PhyAnlpar;

	/* Check to see if auto-negotiation has completed. Check the results in the status registers. */
	PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_STATUS, &PhyStatus);
	if (!PhyResponding) 
	{		
	    DebugMsg(" Error: the MII Phy not responding ! \n ");
		pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
		return;
	}

	if (PhyStatus & MII_STATUS_LINK_UP)		return; /*We have a valid link, so get out! */

	/* Check to see why auto-negotiation or parallel detection has failed. We'll do this
	   by comparing the advertisement registers between the NIC and the link partner. */
	PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_ANAR, &PhyAnar);
	if (!PhyResponding)
	{
	    DebugMsg(" Error: the MII Phy not responding ! \n ");
		pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
		return;
	}

	PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_ANLPAR, &PhyAnlpar);
	if (!PhyResponding) 
	{		
	    DebugMsg(" Error: the MII Phy not responding ! \n ");
		pAdapter->Hardware.Status = HARDWARE_STATUS_FAILURE;
		return;
	}

	/* Now, compare what was advertised between the NIC and it's link partner.
	   If the media bits don't match, then write an error log entry. */
	if ( (PhyAnar & MII_ANAR_MEDIA_MASK) != (PhyAnlpar & MII_ANAR_MEDIA_MASK) )
		DebugMsg(" Error Reason: Incompatible configuration between Link peer !\n" );
	else
		DebugMsg(" Error Reason: Unknown ! \n ");
	
	return;
}

/************************************************************************************
***	Determine from the MII AutoNegotiationAdvertisement and AutoNegotiationPartnerAbility 
*** registers whether the current linkspeed is 10Mbits or 100Mbits.
**/
BOOLEAN NIC_MIILinkSpeedGet(IN PNIC_INFORMATION pAdapter,OUT BOOLEAN * handles100Mbitptr	) 
{
  	BOOLEAN PhyResponding;
	USHORT PhyAnlpar;
    USHORT PhyAner;
    USHORT PhyAnar;
	USHORT PhyStatus;
      
    PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_ANER, &PhyAner);
    if (!PhyResponding)	return FALSE;
  
    PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_ANLPAR, &PhyAnlpar);
    if (!PhyResponding)	return FALSE;

    PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_ANAR, &PhyAnar);
    if (!PhyResponding)	return FALSE;

	PhyResponding = NIC_MIIReadPhy(pAdapter, MII_PHY_STATUS, &PhyStatus);
	if (!PhyResponding)	return FALSE;

	/* Check to see if we've completed auto-negotiation.*/
	if (!(PhyStatus & MII_STATUS_AUTO_DONE))  return FALSE;

	if ((PhyAnar & MII_ANAR_100TXFD) && (PhyAnlpar & MII_ANLPAR_100TXFD) )
    {
		pAdapter->LinkInfo.MIIPhyUsed = MII_100TXFD;
		*handles100Mbitptr = TRUE;
		pAdapter->LinkInfo.FullDuplexEnable = TRUE;

	} 
    else if ((PhyAnar & MII_ANAR_100TX) && (PhyAnlpar & MII_ANLPAR_100TX))
    {
		pAdapter->LinkInfo.MIIPhyUsed = MII_100TX ;
		*handles100Mbitptr = TRUE;
		pAdapter->LinkInfo.FullDuplexEnable = FALSE;
    } 
    else if ((PhyAnar & MII_ANAR_10TFD) && (PhyAnlpar & MII_ANLPAR_10TFD))
   {
		pAdapter->LinkInfo.MIIPhyUsed = MII_10TFD ;
		pAdapter->LinkInfo.FullDuplexEnable = TRUE;
    	*handles100Mbitptr = FALSE;
	} 
   	else if ((PhyAnar & MII_ANAR_10T) && (PhyAnlpar & MII_ANLPAR_10T))
    {
		pAdapter->LinkInfo.MIIPhyUsed = MII_10T ;
		pAdapter->LinkInfo.FullDuplexEnable = FALSE;
		*handles100Mbitptr = FALSE;	
    }
	else if (!(PhyAner & MII_ANER_LPANABLE)) 
   {
	/* Link partner is not capable of auto-negotiation. Fall back to 10HD. */
		pAdapter->LinkInfo.MIIPhyUsed = MII_10T ;
		pAdapter->LinkInfo.FullDuplexEnable = FALSE;
		*handles100Mbitptr = FALSE;	
	}
	else 
		return FALSE;

    return TRUE;
}


/** Above are routines about MII
***  End of NICMII.c
*****************************************************************************************/

⌨️ 快捷键说明

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