📄 e100bexphy.cpp
字号:
// 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 + -