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

📄 e100bexphy.cpp

📁 nmE100bex网卡驱动程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    // phys there are specific bits that must be set so that the phy and the
    // 82557 work together properly.

    MdiIdLowReg = MdiRead( PHY_ID_REG_1, m_PhyAddress);
    MdiIdHighReg = MdiRead( PHY_ID_REG_2, m_PhyAddress);

    UINT PhyId = ((UINT) MdiIdLowReg | ((UINT) MdiIdHighReg << 16));
    m_PhyId = PhyId;

    TRACE("Phy ID is %x\n", PhyId);

    // And out the revsion field of the Phy ID so that we'll be able to detect
    // future revs of the same Phy.
    PhyId &= PHY_MODEL_REV_ID_MASK;

    // Handle the National TX
    if (PhyId == PHY_NSC_TX)
    {
        TRACE("Found a NSC TX Phy\n");

        MdiMiscReg = MdiRead( NSC_CONG_CONTROL_REG, m_PhyAddress);

        MdiMiscReg |= (NSC_TX_CONG_TXREADY | NSC_TX_CONG_F_CONNECT);

        // If we are configured to do congestion control, then enable the
        // congestion control bit in the National Phy
        if (m_Congest)
		{
            MdiMiscReg |= NSC_TX_CONG_ENABLE;
		}
        else
		{
            MdiMiscReg &= ~NSC_TX_CONG_ENABLE;
		}

        MdiWrite( NSC_CONG_CONTROL_REG, m_PhyAddress, MdiMiscReg);
    }

    FindSpeedAndDpx(PhyId);

    TRACE("Current speed=%d, Current Duplex=%d\n",m_AiLineSpeedCur, m_AiDuplexCur);

    return TRUE;
}

////////////////////////////////////////////////////////////////////
// E100bexPhy::FindSpeedAndDpx
//
// This routine will figure out what line speed and duplex mode
//              the PHY is currently using.
//
// Parameters:
//      PhyId - The ID of the PHY in question.
// IRQL: 
//		
// Return Mode:
//		Synchronous
// Returns:
//      TRUE - If the phy could be configured correctly
//      FALSE - If the phy couldn't be configured correctly, because an
//              unsupported over-ride option was used
//      	
VOID E100bexPhy::FindSpeedAndDpx(UINT PhyId)
{
    USHORT MdiMiscReg, MdiOwnAdReg;

    TRACE("E100bexPhy::FindSpeedAndDpx\n");

    // If there was a speed and/or duplex override, then set our current
    // value accordingly
    m_AiLineSpeedCur = m_AiTempSpeed;
    m_AiDuplexCur = (USHORT)  m_AiForceDpx;

    // If speed and duplex were forced, then we know our current settings, so
    // we'll just return.  Otherwise, we'll need to figure out what NWAY set
    // us to.
    if (m_AiLineSpeedCur && m_AiDuplexCur)
	{
        return;
	}

    // If we didn't have a valid link, then we'll assume that our current
    // speed is 10mb half-duplex.

    // Read the status register twice because of sticky bits
    USHORT MdiStatusReg = MdiRead( MDI_STATUS_REG, m_PhyAddress);
    MdiStatusReg = MdiRead( MDI_STATUS_REG, m_PhyAddress);

    // If there wasn't a valid link then use default speed & duplex
    if (!(MdiStatusReg & MDI_SR_LINK_STATUS))
    {
        TRACE("Link Not found for speed detection!!!  Using defaults.\n");

        m_AiLineSpeedCur = 10;
        m_AiDuplexCur = 1;

        return;
    }

    // If this is an Intel PHY (a T4 PHY_100 or a TX PHY_TX), then read bits
    // 1 and 0 of extended register 0, to get the current speed and duplex
    // settings.
    if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) || (PhyId == PHY_TX_ID))
    {
        TRACE("Detecting Speed/Dpx for an Intel PHY\n");

        // Read extended register 0
        MdiMiscReg = MdiRead( EXTENDED_REG_0, m_PhyAddress);
        // Get current speed setting
        if (MdiMiscReg & PHY_100_ER0_SPEED_INDIC)
		{
            m_AiLineSpeedCur = 100;
		}
        else
		{
            m_AiLineSpeedCur = 10;
		}

        // Get current duplex setting -- if bit is set then FDX is enabled
        if (MdiMiscReg & PHY_100_ER0_FDX_INDIC)
		{
            m_AiDuplexCur = 2;
		}
        else
		{
            m_AiDuplexCur = 1;
		}

        return;
    }

    // Read our link partner's advertisement register
    USHORT MdiLinkPartnerAdReg = MdiRead( AUTO_NEG_LINK_PARTNER_REG, m_PhyAddress);
    // See if Auto-Negotiation was complete (bit 5, reg 1)
    MdiStatusReg = MdiRead( MDI_STATUS_REG, m_PhyAddress);

    // If a True NWAY connection was made, then we can detect speed/duplex by
    // ANDing our adapter's advertised abilities with our link partner's
    // advertised ablilities, and then assuming that the highest common
    // denominator was chosed by NWAY.
    if ((MdiLinkPartnerAdReg & NWAY_LP_ABILITY) &&
        (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE))
    {
        TRACE("Detecting Speed/Dpx from NWAY connection\n");

        // Read our advertisement register
        MdiOwnAdReg = MdiRead( AUTO_NEG_ADVERTISE_REG, m_PhyAddress);

        // AND the two advertisement registers together, and get rid of any
        // extraneous bits.
        MdiOwnAdReg &= (MdiLinkPartnerAdReg & NWAY_LP_ABILITY);

        // Get speed setting
        if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX | NWAY_AD_TX_FULL_DPX | NWAY_AD_T4_CAPABLE))
		{
            m_AiLineSpeedCur = 100;
		}
        else
		{
            m_AiLineSpeedCur = 10;
		}

        // Get duplex setting -- use priority resolution algorithm
        if (MdiOwnAdReg & (NWAY_AD_T4_CAPABLE))
        {
            m_AiDuplexCur = 1;
            return;
        }
        else if (MdiOwnAdReg & (NWAY_AD_TX_FULL_DPX))
        {
            m_AiDuplexCur = 2;
            return;
        }
        else if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX))
        {
            m_AiDuplexCur = 1;
            return;
        }
        else if (MdiOwnAdReg & (NWAY_AD_10T_FULL_DPX))
        {
            m_AiDuplexCur = 2;
            return;
        }
        else
        {
            m_AiDuplexCur = 1;
            return;
        }
    }

    // If we are connected to a non-NWAY repeater or hub, and the line
    // speed was determined automatically by parallel detection, then we have
    // no way of knowing exactly what speed the PHY is set to unless that PHY
    // has a propietary register which indicates speed in this situation.  The
    // NSC TX PHY does have such a register.  Also, since NWAY didn't establish
    // the connection, the duplex setting should HALF duplex.

    m_AiDuplexCur = 1;

    if (PhyId == PHY_NSC_TX)
    {
        TRACE("Detecting Speed/Dpx from non-NWAY NSC connection\n");

        // Read register 25 to get the SPEED_10 bit
        MdiMiscReg = MdiRead(NSC_SPEED_IND_REG, m_PhyAddress);

        // If bit 6 was set then we're at 10mb
        if (MdiMiscReg & NSC_TX_SPD_INDC_SPEED)
		{
            m_AiLineSpeedCur = 10;
		}
        else
		{
            m_AiLineSpeedCur = 100;
		}
    }
    else
	{
		// If we don't know what line speed we are set at, then we'll default to
		// 10mbs
        m_AiLineSpeedCur = 10;
	}
}

////////////////////////////////////////////////////////////////////
// E100bexPhy::Select 
//
// This routine will Isolate all Phy addresses on the MII
//                  Bus except for the one address to be 'selected'.  This
//                  Phy address will be un-isolated and auto-negotiation will
//                  be enabled, started, and completed.  The Phy will NOT be
//                  reset and the speed will NOT be set to any value (that is
//                  done in SetupPhy).
//
// Parameters:       
//		SelectPhyAddress - PhyAddress to select
//      WaitAutoNeg      - TRUE = Wait for Auto Negociation to complete.
//                         FALSE = don't wait. Good for 'No Link' case.
// IRQL: 
//		
// Return Mode:
//		Synchronous
//      
VOID E100bexPhy::Select( UINT SelectPhyAddress, BOOLEAN WaitAutoNeg)
{
    // Isolate all other phys and unisolate the one to query
    for (UCHAR i = 0; i < 32; i++ )
    {
        if (i != SelectPhyAddress)
        {
            // isolate this phy
            MdiWrite( MDI_CONTROL_REG, i, MDI_CR_ISOLATE);
            // wait 100 microseconds for the phy to isolate.
            NdisStallExecution(100);
        }
    }

    // unisolate the phy to query

    // Read the MDI control register
    USHORT MdiControlReg = MdiRead( MDI_CONTROL_REG, SelectPhyAddress);
    // Set/Clear bit unisolate this phy
    MdiControlReg &= ~MDI_CR_ISOLATE;             // Clear the Isolate Bit
    // issue the command to unisolate this Phy
    MdiWrite(MDI_CONTROL_REG, SelectPhyAddress, MdiControlReg);
    // sticky bits on link
    USHORT MdiStatusReg = MdiRead(MDI_STATUS_REG, SelectPhyAddress);
    MdiStatusReg = MdiRead(MDI_STATUS_REG, SelectPhyAddress);
    // if we have link, don't mess with the phy
    if (MdiStatusReg & MDI_SR_LINK_STATUS)
	{
        return;
	}

    // Read the MDI control register
    MdiControlReg = MdiRead(MDI_CONTROL_REG, SelectPhyAddress);
    // set Restart auto-negotiation
    MdiControlReg |= MDI_CR_AUTO_SELECT;          // Set Auto Neg Enable
    MdiControlReg |= MDI_CR_RESTART_AUTO_NEG;     // Restart Auto Neg
    // restart the auto-negotion process
    MdiWrite(MDI_CONTROL_REG, SelectPhyAddress, MdiControlReg);
    // wait 200 microseconds for the phy to unisolate.
    NdisStallExecution(200);

    if (WaitAutoNeg)
    {
        // wait for auto-negotiation to complete (up to 3.5 seconds)
        for (i = RENEGOTIATE_TIME; i != 0; i-- )
        {
            // Read the status register twice because of sticky bits
            MdiStatusReg = MdiRead(MDI_STATUS_REG, SelectPhyAddress);
            MdiStatusReg = MdiRead(MDI_STATUS_REG, SelectPhyAddress);

            if (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE)
			{
                break;
			}

            StallExecution(100);
        }
    }
}

////////////////////////////////////////////////////////////////////
// E100bexPhy::MdiRead
//
// This routine will read a value from the specified MII register
//              of an external MDI compliant device (e.g. PHY 100), and return
//              it to the calling routine.  The command will execute in polled
//              mode.
//
// Parameters:       
//      MIIRegAddress - The MII register that we are reading from
//      PhyMdiAddress - The MDI address of the Phy component.
// IRQL: 
//		
// Return Mode:
//		Synchronous
// Returns:
//      The value read from the MII register.
//      
USHORT E100bexPhy::MdiRead(ULONG MIIRegAddress, ULONG PhyMdiAddress)
{
	// Issue the read command to the MDI control register.
	m_MDIControl = ((MIIRegAddress << 16) |
		(PhyMdiAddress << 21) |
		(MDI_READ << 26));

	// wait 20usec before checking status
	NdisStallExecution(20);

	// poll for the mdi read to complete
	for (UINT counter = 100000; counter != 0; counter--)
	{
		if ( (ULONG) m_MDIControl & MDI_PHY_READY)
		{
			break;
		}

		NdisStallExecution(20);
	}

	if (!counter)
	{
		TRACE("HARDWARE_NOT_RESPONDING\n");
		return 0;
	}

	return (USHORT) (ULONG) m_MDIControl;
}

////////////////////////////////////////////////////////////////////
// E100bexPhy::MdiWrite
//
// This routine will write a value to the specified MII register
//              of an external MDI compliant device (e.g. PHY 100).  The
//              command will execute in polled mode.
//
// Parameters:       
//      MIIRegAddress - The MII register that we are writing to
//      PhyMdiAddress - The MDI address of the Phy component.
//		DataValue	  - The value to write to the MII register.
// IRQL: 
//		
// Return Mode:
//		Synchronous
//      
VOID E100bexPhy::MdiWrite(
	ULONG MIIRegAddress,
	ULONG PhyMdiAddress,
	USHORT DataValue
	)
{
    // Issue the write command to the MDI control register.
    m_MDIControl = (((ULONG) DataValue) |
        (MIIRegAddress << 16) |
        (PhyMdiAddress << 21) |
        (MDI_WRITE << 26));

    // wait 20usec before checking status
    NdisStallExecution(20);

    // poll for the mdi write to complete
    for (UINT counter = 100000; counter != 0; counter--)
    {
        if ( (ULONG) m_MDIControl & MDI_PHY_READY)
		{
            break;
		}

        NdisStallExecution(20);
    }

    if (!counter)
    {
		TRACE("HARDWARE_NOT_RESPONDING\n");
    }
}

////////////////////////////////////////////////////////////////////
// E100bexPhy::Reset
//
// This routine will reset the Phy
//
// Parameters:       
//		None
// IRQL: 
//		
// Return Mode:
//		Synchronous
//      
VOID E100bexPhy::Reset(void)
{
    TRACE("E100bexPhy::Reset\n");

    // Reset the Phy, enable auto-negotiation, and restart auto-negotiation.
    USHORT MdiControlReg = MDI_CR_AUTO_SELECT | MDI_CR_RESTART_AUTO_NEG | MDI_CR_RESET;

    // Write the MDI control register with our new Phy configuration
    MdiWrite( MDI_CONTROL_REG, m_PhyAddress, MdiControlReg);
}

⌨️ 快捷键说明

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