#include "RTL8139.h"
bool RTL8139::phyAddMediumType( IOMediumType type,
UInt32 bps,
MediumIndex index )
{
IONetworkMedium * medium;
bool ret = false;
medium = IONetworkMedium::medium( type, bps, 0, index );
if ( medium )
{
ret = IONetworkMedium::addMedium( mediumDict, medium );
if (ret) mediumTable[index] = medium;
medium->release();
}
return ret;
}
#define kMbScale 1000000
void RTL8139::phyProbeMediaCapability( void )
{
reg_bms = csrRead16( RTL_BMS );
phyAddMediumType( kIOMediumEthernetAuto,
0, MEDIUM_INDEX_AUTO );
if ( reg_bms & MII_STATUS_10_HD )
{
phyAddMediumType( kIOMediumEthernet10BaseT |
kIOMediumOptionHalfDuplex,
10 * kMbScale, MEDIUM_INDEX_10_HD );
}
if ( reg_bms & MII_STATUS_10_FD )
{
phyAddMediumType( kIOMediumEthernet10BaseT |
kIOMediumOptionFullDuplex,
10 * kMbScale, MEDIUM_INDEX_10_FD );
}
if ( reg_bms & MII_STATUS_TX_HD )
{
phyAddMediumType( kIOMediumEthernet100BaseTX |
kIOMediumOptionHalfDuplex,
100 * kMbScale, MEDIUM_INDEX_TX_HD);
}
if ( reg_bms & MII_STATUS_TX_FD )
{
phyAddMediumType( kIOMediumEthernet100BaseTX |
kIOMediumOptionFullDuplex,
100 * kMbScale, MEDIUM_INDEX_TX_FD );
}
}
bool RTL8139::phyReset( void )
{
return true;
}
bool RTL8139::phyWaitForAutoNegotiation( void )
{
for ( SInt32 timeout = 5000; timeout > 0; timeout -= 20 )
{
if ( csrRead16( RTL_BMS ) & MII_STATUS_AUTONEG_COMPLETE )
{
return true;
}
IOSleep( 20 );
}
return false;
}
bool RTL8139::phySetMedium( MediumIndex mediumIndex )
{
UInt16 supportMask;
UInt16 control;
bool success = false;
if ( mediumIndex == currentMediumIndex )
{
return true; }
switch ( mediumIndex )
{
case MEDIUM_INDEX_AUTO:
csrWrite16( RTL_BMC, MII_CONTROL_AUTONEG_ENABLE |
MII_CONTROL_RESTART_AUTONEG );
phyWaitForAutoNegotiation();
success = true;
break;
case MEDIUM_INDEX_10_HD:
case MEDIUM_INDEX_10_FD:
case MEDIUM_INDEX_TX_HD:
case MEDIUM_INDEX_TX_FD:
case MEDIUM_INDEX_T4:
supportMask = (reg_bms >> 11) & 0x1f;
if ( (supportMask & (1 << mediumIndex)) == 0 )
{
break; }
control = 0;
if (( mediumIndex == MEDIUM_INDEX_TX_HD ) ||
( mediumIndex == MEDIUM_INDEX_TX_FD ) ||
( mediumIndex == MEDIUM_INDEX_T4 ))
{
control |= MII_CONTROL_100;
}
if (( mediumIndex == MEDIUM_INDEX_10_FD ) ||
( mediumIndex == MEDIUM_INDEX_TX_FD ))
{
control |= MII_CONTROL_FULL_DUPLEX;
}
csrWrite16( RTL_BMC, control );
success = true;
break;
case MEDIUM_INDEX_NONE:
phyReset();
success = true;
break;
default:
break;
}
if ( success ) currentMediumIndex = mediumIndex;
return success;
}
bool RTL8139::phySetMedium( const IONetworkMedium * medium )
{
return phySetMedium( medium->getIndex() );
}
void RTL8139::phyReportLinkStatus( bool forceStatusReport )
{
UInt16 phyStatus;
UInt16 linkChanged;
MediumIndex activeMediumIndex;
phyStatus = csrRead16( RTL_BMS );
linkChanged = ( phyStatus ^ phyStatusLast ) &
( MII_STATUS_LINK_STATUS |
MII_STATUS_AUTONEG_COMPLETE );
if ( linkChanged || forceStatusReport )
{
if ( phyStatus & MII_STATUS_LINK_STATUS )
{
UInt8 mediaStatus = csrRead8( RTL_MEDIA_STATUS );
UInt16 modeControl = csrRead16( RTL_BMC );
if ( mediaStatus & R_MEDIA_STATUS_SPEED_10 )
{
if ( modeControl & R_BMC_DUPLEXMODE )
activeMediumIndex = MEDIUM_INDEX_10_FD;
else
activeMediumIndex = MEDIUM_INDEX_10_HD;
}
else
{
if ( modeControl & R_BMC_DUPLEXMODE )
activeMediumIndex = MEDIUM_INDEX_TX_FD;
else
activeMediumIndex = MEDIUM_INDEX_TX_HD;
}
setLinkStatus( kIONetworkLinkValid | kIONetworkLinkActive,
phyGetMediumWithIndex( activeMediumIndex ) );
}
else
{
setLinkStatus( kIONetworkLinkValid );
}
phyStatusLast = phyStatus;
}
}
const IONetworkMedium * RTL8139::phyGetMediumWithIndex( MediumIndex index ) const
{
if ( index < MEDIUM_INDEX_COUNT )
return mediumTable[index];
else
return 0;
}