📄 e100bexphy.cpp
字号:
// E100bexPhy.cpp: implementation of the E100bexPhy class.
//
//=============================================================================
//
// Compuware Corporation
// NuMega Lab
// 9 Townsend West
// Nashua, NH 03060 USA
//
// Copyright (c) 2000 Compuware Corporation. All Rights Reserved.
// Unpublished - rights reserved under the Copyright laws of the
// United States.
//
//=============================================================================
//
// Portions copied from Microsoft Windows 2000 DDK sample driver containing the
// following copyright
//
/****************************************************************************
** COPYRIGHT (C) 1994-1997 INTEL CORPORATION **
** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON **
** HTTP://WWW.INTEL.COM/ **
** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND **
** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER **
****************************************************************************/
#include <kndis.h>
#include "E100bexInc.h"
////////////////////////////////////////////////////////////////////
// E100bexPhy::Detect
//
// This routine will detect what phy we are using, set the line
// speed, FDX or HDX, and configure the phy if necessary.
//
// The following combinations are supported:
// - TX or T4 PHY alone at PHY address 1
// - T4 or TX PHY at address 1 and MII PHY at address 0
// - 82503 alone (10Base-T mode, no full duplex support)
// - 82503 and MII PHY (TX or T4) at address 0
//
// The sequence / priority of detection is as follows:
// If there is a PHY Address override use that address.
// else scan based on the 'Connector' setting.
// Switch Connector
// 0 = AutoScan
// 1 = Onboard TPE only
// 2 = MII connector only
//
// Each of the above cases is explained below.
//
// AutoScan means:
// Look for link on addresses 1, 0, 2..31 (in that order). Use the first
// address found that has link.
// If link is not found then use the first valid PHY found in the same scan
// order 1,0,2..31. NOTE: this means that NO LINK or Multi-link cases will
// default to the onboard PHY (address 1).
//
// Onboard TPE only:
// Phy address is set to 1 (No Scanning).
//
// MII connector only means:
// Look for link on addresses 0, 2..31 (again in that order, Note address 1 is
// NOT scanned). Use the first address found that has link.
// If link is not found then use the first valid Phy found in the same scan
// order 0, 2..31.
// In the AutoScan case above we should always find a valid PHY at address 1,
// there is no such guarantee here, so, If NO Phy is found then the driver
// should default to address 0 and continue to load. Note: External
// transceivers should be at address 0 but our early Nitro3 testing found
// transceivers at several non-zero addresses (6,10,14).
//
// NWAY
// Additionally auto-negotiation capable (NWAY) and parallel
// detection PHYs are supported. The flow-chart is described in
// the 82557 software writer's manual.
//
// NOTE: 1. All PHY MDI registers are read in polled mode.
// 2. The routines assume that the 82557 has been RESET and we have
// obtained the virtual memory address of the CSR.
// 3. PhyDetect will not RESET the PHY.
// 4. If FORCEFDX is set, SPEED should also be set. The driver will
// check the values for inconsistency with the detected PHY
// technology.
// 5. PHY 1 (the PHY on the adapter) MUST be at address 1.
// 6. Driver ignores FORCEFDX and SPEED overrides if a 503 interface
// is detected.
//
// Returns:
// TRUE - If a Phy was detected, and configured correctly.
// FALSE - If a valid phy could not be detected and configured.
//
BOOLEAN E100bexPhy::Detect(void)
{
TRACE("E100bexPhy::Detect entered\n");
USHORT MdiControlReg, MdiStatusReg;
UCHAR FoundPhyAt = 0xff;
// Check for a phy address over-ride of 32 which indicates a 503
if (32 == m_PhyAddress)
{
// 503 interface over-ride
TRACE(" 503 serial component over-ride\n");
m_PhyAddress = 32;
// Record the current speed and duplex. We will be in half duplex
// mode unless the user used the force full duplex over-ride.
m_AiLineSpeedCur = 10;
m_AiDuplexCur = (USHORT) m_AiForceDpx;
if (!m_AiDuplexCur)
{
m_AiDuplexCur = 1;
}
return TRUE;
}
// Check for other phy address over-rides.
// If the Phy Address is between 0-31 then there is an over-ride.
// Or the connector was set to 1
if ( (m_PhyAddress < 32) || (m_Connector == CONNECTOR_TPE) )
{ // User Override nothing to do but setup Phy and leave
if ( (m_PhyAddress > 32) && (m_Connector == CONNECTOR_TPE) )
{
m_PhyAddress = 1; // Connector was forced
// Isolate all other PHYs and unisolate this one
Select( m_PhyAddress, FALSE);
}
TRACE(" Phy address Override to address %d\n", m_PhyAddress);
#if DBG
// Read the MDI control register at override address.
MdiControlReg = MdiRead( MDI_CONTROL_REG, m_PhyAddress);
// Read the status register at override address.
MdiStatusReg = MdiRead( MDI_STATUS_REG, m_PhyAddress);
// Read the status register again because of sticky bits
MdiStatusReg = MdiRead( MDI_STATUS_REG, m_PhyAddress);
// check if we found a valid phy
if (!((MdiControlReg == 0xffff) || ((MdiStatusReg == 0) && (MdiControlReg == 0))))
{
// we have a valid phy1
TRACE(" Over-ride address %d has a valid Phy.\n", m_PhyAddress);
// Read the status register again
MdiStatusReg = MdiRead( MDI_STATUS_REG, m_PhyAddress);
// If there is a valid link then use this Phy.
if (MdiStatusReg & MDI_SR_LINK_STATUS)
{
TRACE(" Phy at address %d has link\n", m_PhyAddress);
}
}
else
{
// no PHY at over-ride address
TRACE(" Over-ride address %d has no Phy!!!!\n", m_PhyAddress);
}
#endif
return Setup();
}
else // Need to scan - No address over-ride and Connector is AUTO or MII
{
for (char LookForLink=1; LookForLink>=0 ;LookForLink-- )
{
// For each PhyAddress 0 - 31
for (UCHAR i = 0; i < 32; i++)
{
if (LookForLink)
{
// Phy Addresses must be tested in the order 1,0,2..31.
switch (i)
{
case 0:
m_PhyAddress = 1;
break;
case 1:
m_PhyAddress = 0;
break;
default:
m_PhyAddress = i;
break;
}
// Skip OnBoard for MII only case
if ( (m_PhyAddress == 1) && (m_Connector == CONNECTOR_MII) ) continue;
TRACE(" Scanning Phy address %d for link\n", m_PhyAddress);
// Read the MDI control register
MdiControlReg = MdiRead( MDI_CONTROL_REG, m_PhyAddress);
// Read the status register
MdiStatusReg = MdiRead( MDI_STATUS_REG, m_PhyAddress);
MdiStatusReg = MdiRead( MDI_STATUS_REG, m_PhyAddress); // Sticky Bits
}
else
{ // Not looking for link
if (FoundPhyAt < 32)
{
m_PhyAddress = FoundPhyAt;
}
else
{
// No valid PHYs were found last time so just default
if (m_Connector == CONNECTOR_MII)
{
m_PhyAddress = 0; // Default for MII
}
else // assume a 503 interface
{
m_PhyAddress = 32;
// Record the current speed and duplex. We will be in half duplex
// mode unless the user used the force full duplex over-ride.
m_AiLineSpeedCur = 10;
m_AiDuplexCur = (USHORT) m_AiForceDpx;
if (!m_AiDuplexCur)
{
m_AiDuplexCur = 1;
}
return TRUE;
}
TRACE(" No Links Found!!\n");
}
}
// check if we found a valid phy or on !LookForLink pass
if ( !( (MdiControlReg == 0xffff) || ((MdiStatusReg == 0) && (MdiControlReg == 0))
) || (!LookForLink)
)
{ // Valid phy or Not looking for Link
#if DBG
if (!( (MdiControlReg == 0xffff) || ((MdiStatusReg == 0) && (MdiControlReg == 0)) ) )
{
TRACE(" Found a Phy at address %d\n", m_PhyAddress);
}
#endif
// Store highest priority phy found for NO link case
if (i < FoundPhyAt && FoundPhyAt != 1)
{
// this phy is higher priority
FoundPhyAt = (UCHAR) m_PhyAddress;
}
// Select Phy before checking link status
// NOTE: may take up to 3.5 Sec if LookForLink == TRUE
Select( m_PhyAddress, (BOOLEAN)LookForLink);
// Read the MDI control register
MdiControlReg = MdiRead( MDI_CONTROL_REG, m_PhyAddress);
// Read the status register
MdiStatusReg = MdiRead( MDI_STATUS_REG, m_PhyAddress);
MdiStatusReg = MdiRead( MDI_STATUS_REG, m_PhyAddress);
// If there is a valid link or we alreadry tried once then use this Phy.
if ((MdiStatusReg & MDI_SR_LINK_STATUS) || (!LookForLink))
{
#if DBG
if (MdiStatusReg & MDI_SR_LINK_STATUS)
{
TRACE(" Using Phy at address %d with link\n", m_PhyAddress);
}
else
{
TRACE(" Using Phy at address %d WITHOUT link!!!\n", m_PhyAddress);
}
#endif
return Setup(); // Exit with Link Path
}
} // End if valid PHY
} // End for each PHY address
} // End LookForLink
} // End else scan
return FALSE;
}
////////////////////////////////////////////////////////////////////
// E100bexPhy::Setup
//
// This routine will setup phy 1 or phy 0 so that it is configured
// to match a speed and duplex over-ride option. If speed or
// duplex mode is not explicitly specified in the registry, the
// driver will skip the speed and duplex over-ride code, and
// assume the adapter is automatically setting the line speed, and
// the duplex mode. At the end of this routine, any truly Phy
// specific code will be executed (each Phy has its own quirks,
// and some require that certain special bits are set).
//
// NOTE: The driver assumes that SPEED and FORCEFDX are specified at the
// same time. If FORCEDPX is set without speed being set, the driver
// will encouter a fatal error.
//
// Parameters:
// none
// 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
//
BOOLEAN E100bexPhy::Setup(void)
{
USHORT MdiControlReg, MdiStatusReg, MdiIdLowReg, MdiIdHighReg;
USHORT MdiMiscReg;
BOOLEAN ForcePhySetting = FALSE;
TRACE("E100bexPhy::Setup\n");
// If we are NOT forcing a setting for line speed or full duplex, then
// we won't force a link setting, and we'll jump down to the phy
// specific code.
if (m_AiTempSpeed || m_AiForceDpx)
{
// Find out what kind of technology this Phy is capable of.
MdiStatusReg = MdiRead( MDI_STATUS_REG, m_PhyAddress);
// Read the MDI control register at our phy
MdiControlReg = MdiRead( MDI_CONTROL_REG, m_PhyAddress);
// Now check the validity of our forced option. If the force option is
// valid, then force the setting. If the force option is not valid,
// we'll set a flag indicating that we should error out.
// If speed is forced to 10mb
if ( m_AiTempSpeed == 10)
{
// If half duplex is forced
if (m_AiForceDpx == 1)
{
if (MdiStatusReg & MDI_SR_10T_HALF_DPX)
{
TRACE("Forcing 10mb 1/2 duplex\n");
MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
ForcePhySetting = TRUE;
}
}
// If full duplex is forced
else if (m_AiForceDpx == 2)
{
if (MdiStatusReg & MDI_SR_10T_FULL_DPX)
{
TRACE("Forcing 10mb full duplex\n");
MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT);
MdiControlReg |= MDI_CR_FULL_HALF;
ForcePhySetting = TRUE;
}
}
// If auto duplex (we actually set phy to 1/2)
else
{
if (MdiStatusReg & (MDI_SR_10T_FULL_DPX | MDI_SR_10T_HALF_DPX))
{
TRACE("Forcing 10mb auto duplex\n");
MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
ForcePhySetting = TRUE;
m_AiForceDpx = 1;
}
}
}
// If speed is forced to 100mb
else if (m_AiTempSpeed == 100)
{
// If half duplex is forced
if (m_AiForceDpx == 1)
{
if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE))
{
TRACE("Forcing 100mb half duplex\n");
MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
MdiControlReg |= MDI_CR_10_100;
ForcePhySetting = TRUE;
}
}
// If full duplex is forced
else if (m_AiForceDpx == 2)
{
if (MdiStatusReg & MDI_SR_TX_FULL_DPX)
{
TRACE("Forcing 100mb full duplex\n");
MdiControlReg &= ~MDI_CR_AUTO_SELECT;
MdiControlReg |= (MDI_CR_10_100 | MDI_CR_FULL_HALF);
ForcePhySetting = TRUE;
}
}
// If auto duplex (we set phy to 1/2)
else
{
if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE))
{
TRACE("Forcing 100mb auto duplex\n");
MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
MdiControlReg |= MDI_CR_10_100;
ForcePhySetting = TRUE;
m_AiForceDpx = 1;
}
}
}
if (ForcePhySetting == FALSE)
{
TRACE("Can't force speed=%d, duplex=%d\n",m_AiTempSpeed, m_AiForceDpx);
return FALSE;
}
// Write the MDI control register with our new Phy configuration
MdiWrite( MDI_CONTROL_REG, m_PhyAddress, MdiControlReg);
// wait 100 milliseconds for auto-negotiation to complete
StallExecution(100);
}
// Find out specifically what Phy this is. We do this because for certain
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -