#include "RTL8139.h"
#define super IOEthernetController
OSDefineMetaClassAndStructors( RTL8139, IOEthernetController ) ;
#pragma mark -
#pragma mark еее Event Logging еее
#pragma mark -
#if USE_ELG
void RTL8139::AllocateEventLog( UInt32 size )
{
mach_timespec_t time;
IOByteCount length;
fpELGMemDesc = IOBufferMemoryDescriptor::withOptions( kIOMemoryPhysicallyContiguous,
kEvLogSize,
PAGE_SIZE );
if ( !fpELGMemDesc )
{
kprintf( "AllocateEventLog - RTL8139 evLog allocation failed " );
return;
}
fpELGMemDesc->prepare( kIODirectionNone );
fpELG = (elg*)fpELGMemDesc->getBytesNoCopy();
bzero( fpELG, kEvLogSize );
fpELG->physAddr = fpELGMemDesc->getPhysicalSegment64( 0, &length );
fpELG->evLogBuf = (UInt8*)fpELG + sizeof( struct elg );
fpELG->evLogBufe = (UInt8*)fpELG + kEvLogSize - 0x20; fpELG->evLogBufp = fpELG->evLogBuf;
fpELG->evLogFlag = 0x03330333;
IOGetTime( &time );
fpELG->startTimeSecs = time.tv_sec;
IOLog( "\033[32mRTL8139::AllocateEventLog - buffer=%8x phys=%16llx \033[0m \n",
(unsigned int)fpELG, fpELG->physAddr );
return;
}
void RTL8139::EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str )
{
register UInt32 *lp;
register elg *pe = fpELG;
mach_timespec_t time;
UInt32 lefty;
if ( pe->evLogFlag == 0 )
{
pe->lostEvents++;
return;
}
IOGetTime( &time );
if ( pe->evLogFlag <= kEvLogSize / 0x10 )
--pe->evLogFlag;
else if ( pe->evLogFlag == 0xDebeefed ) {
for ( lp = (UInt32*)pe->evLogBuf; lp < (UInt32*)pe->evLogBufe; lp++ )
*lp = 0xDebeefed;
pe->evLogBufp = pe->evLogBuf; pe->evLogFlag = 0x03330333; }
if ( pe->evLogBufp >= pe->evLogBufe )
{
pe->evLogBufp = pe->evLogBuf;
pe->wrapCount++;
if ( pe->evLogFlag != 0xFeedBeef ) {
pe->evLogFlag = 0;
return;
}
pe->startTimeSecs = time.tv_sec;
}
lp = (UInt32*)pe->evLogBufp;
pe->evLogBufp += 0x10;
lefty = time.tv_sec << 24; *lp++ = lefty | (time.tv_nsec >> 10); *lp++ = a;
*lp++ = b;
*lp = ascii;
return;
}
UInt32 RTL8139::Alrt( UInt32 a, UInt32 b, UInt32 ascii, char* str )
{
char work [ 256 ];
char *bp = work;
UInt8 x;
int i;
EvLog( a, b, ascii, str );
EvLog( '****', '****', 'Alrt', "*** Alrt" );
*bp++ = '{'; for ( i = 7; i >= 0; --i )
{
x = a & 0x0F;
if ( x < 10 )
x += '0';
else x += 'A' - 10;
bp[ i ] = x;
a >>= 4;
}
bp += 8;
*bp++ = ' ';
for ( i = 7; i >= 0; --i )
{
x = b & 0x0F;
if ( x < 10 )
x += '0';
else x += 'A' - 10;
bp[ i ] = x;
b >>= 4;
}
bp += 8;
*bp++ = '}';
*bp++ = ' ';
for ( i = sizeof( work ) - (int)(bp - work) - 1; i && (*bp++ = *str++); --i ) ;
bp[ -1 ] = '\n'; *bp = 0;
fpELG->alertCount++; fpELG->lastAlrt = ascii;
return 0xDeadBeef;
}
#endif // USE_ELG
#pragma mark -
#pragma mark еее Override methods еее
#pragma mark -
bool RTL8139::init( OSDictionary *properties )
{
#if USE_ELG
AllocateEventLog( kEvLogSize );
ELG( this, fpELG, 'Rltk', "RTL8139::init - event logging set up." );
#endif
if ( false == super::init( properties ) )
return false;
forceLinkChange = true;
phyStatusLast = 0;
fSpeed100 = false;
currentLevel = kActivationLevel0;
currentMediumIndex = MEDIUM_INDEX_NONE;
fLoopback = false;
fLoopbackMode = kSelectLoopbackPHY;
fTSD_ERTXTH = R_TSD_ERTXTH;
return true;
}
bool RTL8139::start( IOService *provider )
{
OSObject *builtinProperty;
bool success = false;
ELG( IOThreadSelf(), provider, 'Strt', "RTL8139::start - this, provider." );
DEBUG_LOG( "start() ===>\n" );
do
{
if ( false == super::start( provider ) ) break;
pciNub = OSDynamicCast( IOPCIDevice, provider );
if ( 0 == pciNub )
break;
pciNub->retain();
if ( false == pciNub->open( this ) ) break;
fBuiltin = false;
builtinProperty = provider->getProperty( "built-in" );
if ( builtinProperty )
{
fBuiltin = true;
ELG( 0, 0, 'b-in', "RTL8139::start - found built-in property." );
}
if ( false == initEventSources( provider ) )
break;
if ( false == allocateDescriptorMemory() )
break;
csrMap = pciNub->mapDeviceMemoryWithRegister( kIOPCIConfigBaseAddress1 );
if ( 0 == csrMap )
break;
csrBase = (volatile void*)csrMap->getVirtualAddress();
if ( false == initPCIConfigSpace( pciNub ) )
break;
if ( initAdapter( kResetChip ) == false )
{
IOLog( "%s: initAdapter() failed\n", getName() );
break;
}
registerEEPROM();
phyProbeMediaCapability();
if ( false == publishMediumDictionary( mediumDict ) )
break;
success = true;
} while ( false );
if ( pciNub )
pciNub->close( this );
do
{
if ( false == success )
break;
success = false;
if ( false == attachInterface( (IONetworkInterface**)&netif, false) )
break;
attachDebuggerClient( &debugger );
netif->registerService();
success = true;
}
while ( false );
DEBUG_LOG( "start() <===\n" );
return success;
}
void RTL8139::stop( IOService *provider )
{
ELG( 0, provider, 'stop', "RTL8139::stop" );
DEBUG_LOG( "stop() ===>\n" );
super::stop( provider );
DEBUG_LOG( "stop() <===\n" );
return;
}
bool RTL8139::initEventSources( IOService *provider )
{
ELG( 0, 0, 'InES', "RTL8139::initEventSources - " );
DEBUG_LOG( "initEventSources() ===>\n" );
IOWorkLoop *wl = getWorkLoop();
if ( 0 == wl )
return false;
fTransmitQueue = getOutputQueue();
if ( 0 == fTransmitQueue )
return false;
fTransmitQueue->setCapacity( kTransmitQueueCapacity );
interruptSrc = IOInterruptEventSource::interruptEventSource(
this,
OSMemberFunctionCast( IOInterruptEventAction,
this,
&RTL8139::interruptOccurred ),
provider );
if ( !interruptSrc || (wl->addEventSource( interruptSrc ) != kIOReturnSuccess) )
return false;
interruptSrc->enable();
timerSrc = IOTimerEventSource::timerEventSource(
this,
OSMemberFunctionCast( IOTimerEventSource::Action,
this,
&RTL8139::timeoutOccurred ) );
if ( !timerSrc || (wl->addEventSource( timerSrc ) != kIOReturnSuccess) )
return false;
mediumDict = OSDictionary::withCapacity( 5 );
if ( 0 == mediumDict )
return false;
DEBUG_LOG( "initEventSources() <===\n" );
return true;
}
bool RTL8139::initPCIConfigSpace( IOPCIDevice *provider )
{
UInt16 reg16;
ELG( 0, provider, 'iPCI', "RTL8139::initPCIConfigSpace" );
DEBUG_LOG( "pciConfigInit() ===>\n" );
reg16 = provider->configRead16( kIOPCIConfigCommand );
reg16 &= ~kIOPCICommandIOSpace;
reg16 |= ( kIOPCICommandBusMaster
| kIOPCICommandMemorySpace
| kIOPCICommandMemWrInvalidate );
provider->configWrite16( kIOPCIConfigCommand, reg16 );
provider->configWrite8( kIOPCIConfigCacheLineSize, 64 / sizeof( UInt32 ) );
provider->configWrite8( kIOPCIConfigLatencyTimer, 0xF8 );
DEBUG_LOG( "pciConfigInit() <===\n" );
return true;
}
bool RTL8139::createWorkLoop()
{
DEBUG_LOG( "createWorkLoop() ===>\n" );
workLoop = IOWorkLoop::workLoop();
DEBUG_LOG( "createWorkLoop() <===\n" );
return (workLoop != 0);
}
IOWorkLoop* RTL8139::getWorkLoop( void ) const
{
DEBUG_LOG( "getWorkLoop() ===>\n" );
DEBUG_LOG( "getWorkLoop() <===\n" );
return workLoop;
}
bool RTL8139::configureInterface( IONetworkInterface *netif )
{
IONetworkData *data;
ELG( this, netif, 'cfgI', "RTL8139::configureInterface " );
DEBUG_LOG( "configureInterface() ===>\n" );
if ( false == super::configureInterface( netif ) )
return false;
data = netif->getParameter( kIONetworkStatsKey );
if ( !data || !(netStats = (IONetworkStats*)data->getBuffer()) )
return false;
data = netif->getParameter( kIOEthernetStatsKey );
if ( !data || !(etherStats = (IOEthernetStats*)data->getBuffer()) )
return false;
DEBUG_LOG( "configureInterface() <===\n" );
return true;
}
void RTL8139::free()
{
#define RELEASE(x) do { if(x) { (x)->release(); (x) = 0; } } while(0)
ELG( 0, 0, 'free', "RTL8139::free" );
DEBUG_LOG( "free() ===>\n" );
if ( interruptSrc && workLoop )
workLoop->removeEventSource( interruptSrc );
RELEASE( netif );
RELEASE( debugger );
RELEASE( interruptSrc );
RELEASE( timerSrc );
RELEASE( csrMap );
RELEASE( mediumDict );
RELEASE( pciNub );
RELEASE( workLoop );
if ( fpTxRxMD )
{
fpTxRxMD->complete();
fpTxRxMD->release();
fpTxRxMD = 0;
}
super::free();
DEBUG_LOG( "free() <===\n" );
return;
}
bool RTL8139::enableAdapter( UInt32 level )
{
UInt16 isr;
bool success = false;
ELG( 0, level, 'enbA', "RTL8139::enableAdapter - level" );
DEBUG_LOG( "enableAdapter() ===>\n" );
DEBUG_LOG( "enable level %ld\n", level);
switch ( level )
{
case kActivationLevel1:
if ( (0 == pciNub) || (false == pciNub->open( this )) )
break;
if ( initAdapter( kFullInitialization ) != true )
break;
if ( selectMedium( getSelectedMedium() ) != kIOReturnSuccess )
break;
timerSrc->setTimeoutMS( kWatchdogTimerPeriod );
for ( int i = 0; i < 100; i++ )
{
isr = csrRead16( RTL_ISR );
if ( isr & R_ISR_PUN )
{
csrWrite16( RTL_ISR, R_ISR_PUN );
ELG( i, isr, 'enbA', "RTL8139::enableAdapter - cleared PUN interrupt" );
DEBUG_LOG( "cleared PUN interrupt %x in %d\n", isr, i );
break;
}
IOSleep( 10 );
}
success = true;
break;
case kActivationLevel2:
workLoop->enableAllInterrupts();
success = true;
break;
}
if ( false == success )
IOLog( "enable level %ld failed\n", level );
DEBUG_LOG( "enableAdapter() <===\n" );
return success;
}
bool RTL8139::disableAdapter( UInt32 currentLevel )
{
bool success = false;
ELG( 0, currentLevel, 'disA', "RTL8139::disableAdapter" );
DEBUG_LOG( "disableAdapter() ===>\n" );
DEBUG_LOG( "disable currentLevel %ld\n", currentLevel );
switch ( currentLevel )
{
case kActivationLevel1:
timerSrc->cancelTimeout(); initAdapter( kResetChip );
phySetMedium( MEDIUM_INDEX_NONE );
if ( pciNub )
pciNub->close( this );
success = true;
break;
case kActivationLevel2:
disableHardwareInterrupts(); workLoop->disableAllInterrupts();
fTransmitQueue->stop();
fTransmitQueue->flush();
setLinkStatus( kIONetworkLinkValid ); success = true;
break;
}
if ( false == success )
IOLog( "disable currentLevel %ld failed\n", currentLevel );
DEBUG_LOG( "disableAdapter() <===\n" );
return success;
}
bool RTL8139::setActivationLevel( UInt32 level )
{
bool success = false;
UInt32 nextLevel;
ELG( 0, level, 'sLvl', "RTL8139::setActivationLevel" );
DEBUG_LOG( "setActivationLevel() ===>\n" );
DEBUG_LOG( "---> CURRENT LEVEL: %ld DESIRED LEVEL: %ld\n", currentLevel, level );
if ( currentLevel == level )
return true;
for ( ; currentLevel > level; currentLevel-- )
{
if ( (success = disableAdapter( currentLevel )) == false )
break;
}
for ( nextLevel = currentLevel + 1; currentLevel < level;
currentLevel++, nextLevel++ )
{
if ( (success = enableAdapter( nextLevel )) == false )
break;
}
DEBUG_LOG( "---> PRESENT LEVEL: %ld\n\n", currentLevel);
DEBUG_LOG( "setActivationLevel() <===\n" );
return success;
}
IOReturn RTL8139::enable( IONetworkInterface *netif )
{
ELG( 0, enabledByBSD, 'enbN', "RTL8139::enable - netif" );
DEBUG_LOG( "enable(netif) ===>\n" );
if ( true == enabledByBSD )
{
DEBUG_LOG( "enable() <===\n" );
return kIOReturnSuccess;
}
enabledByBSD = setActivationLevel( kActivationLevel2 );
DEBUG_LOG( "enable(netif) <===\n" );
return enabledByBSD ? kIOReturnSuccess : kIOReturnIOError;
}
IOReturn RTL8139::disable( IONetworkInterface* )
{
ELG( enabledByKDP, enabledByBSD, 'disN', "RTL8139::disable - netif" );
DEBUG_LOG( "disable(netif) ===>\n" );
enabledByBSD = false;
setActivationLevel( enabledByKDP ? kActivationLevel1 : kActivationLevel0 );
DEBUG_LOG( "disable(netif) <===\n" );
return kIOReturnSuccess;
}
IOReturn RTL8139::enable( IOKernelDebugger* )
{
ELG( enabledByKDP, enabledByBSD, 'enbD', "RTL8139::enable - debugger" );
if ( enabledByKDP || enabledByBSD )
{
enabledByKDP = true;
return kIOReturnSuccess;
}
enabledByKDP = setActivationLevel( kActivationLevel1 );
return enabledByKDP ? kIOReturnSuccess : kIOReturnIOError;
}
IOReturn RTL8139::disable( IOKernelDebugger* )
{
ELG( 0, 0, 'disD', "RTL8139::disable - debugger" );
enabledByKDP = false;
if ( enabledByBSD == false )
setActivationLevel( kActivationLevel0 );
return kIOReturnSuccess;
}
bool RTL8139::setLinkStatus( UInt32 status,
const IONetworkMedium *activeMedium,
UInt64 speed,
OSData *data )
{
ELG( speed / 1000000, status, ' SLS', "setLinkStatus" );
return super::setLinkStatus( status, activeMedium, speed, data );
}
void RTL8139::timeoutOccurred( IOTimerEventSource *timer )
{
UInt32 u32;
timerSrc->setTimeoutMS( kWatchdogTimerPeriod );
ELG( 0, 0, 'time', "RTL8139::timeoutOccurred" );
u32 = csrRead32( RTL_MPC ); if ( u32 )
{
etherStats->dot3StatsEntry.missedFrames += u32;
csrWrite32( RTL_MPC, 0 );
}
phyReportLinkStatus();
return;
}
IOReturn RTL8139::setPromiscuousMode( bool enabled )
{
ELG( 0, enabled, 'setP', "RTL8139::setPromiscuousMode" );
DEBUG_LOG( "setPromiscuousMode() ===>\n" );
if ( enabled )
{
reg_rcr |= R_RCR_AAP;
csrWrite32( RTL_MAR0, 0xffffffff ); csrWrite32( RTL_MAR4, 0xffffffff );
}
else
{
reg_rcr &= ~R_RCR_AAP;
csrWrite32( RTL_MAR0, reg_mar0 ); csrWrite32( RTL_MAR4, reg_mar4 );
}
csrWrite32( RTL_RCR, reg_rcr );
DEBUG_LOG( "setPromiscuousMode RTL_RCR = 0x%lx\n", reg_rcr );
DEBUG_LOG( "setPromiscuousMode() <===\n" );
return kIOReturnSuccess;
}
IOReturn RTL8139::setMulticastMode( bool enabled )
{
ELG( 0, enabled, 'setM', "RTL8139::setMulticastMode" );
DEBUG_LOG( "setMulticastMode() ===>\n" );
DEBUG_LOG( "setMulticastMode RTL_RCR = 0x%lx\n", reg_rcr );
DEBUG_LOG( "setMulticastMode() <===\n" );
return kIOReturnSuccess;
}
static inline UInt32 rtl_ether_crc( int length, const unsigned char *data )
{
static unsigned const ethernet_polynomial = 0x04c11db7U;
unsigned char current_octet;
int crc = -1;
while ( --length >= 0 )
{
current_octet = *data++;
for ( int bit = 0; bit < 8; bit++, current_octet >>= 1 )
crc = (crc << 1) ^
((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
}
return crc;
}
IOReturn RTL8139::setMulticastList( IOEthernetAddress *addrs, UInt32 count )
{
ELG( addrs, count, 'setL', "RTL8139::setMulticastList" );
DEBUG_LOG( "setMulticastList() ===>\n" );
for ( UInt32 i = 0; i < count; i++, addrs++ )
{
int bit = rtl_ether_crc( 6, (const UInt8*)addrs ) >> 26;
if ( bit < 32 )
reg_mar0 |= (1 << bit);
else reg_mar4 |= (1 << (bit - 32));
}
csrWrite32( RTL_MAR0, reg_mar0 );
csrWrite32( RTL_MAR4, reg_mar4 );
DEBUG_LOG( "setMulticastList() <===\n" );
return kIOReturnSuccess;
}
void RTL8139::getPacketBufferConstraints(
IOPacketBufferConstraints *constraints ) const
{
DEBUG_LOG( "getPacketBufferConstraints() ===>\n" );
constraints->alignStart = kIOPacketBufferAlign1; constraints->alignLength = kIOPacketBufferAlign1;
DEBUG_LOG( "getPacketBufferConstraints() <===\n" );
return;
}
IOReturn RTL8139::getHardwareAddress( IOEthernetAddress *address )
{
union
{
UInt8 bytes[4];
UInt32 int32;
} idr;
DEBUG_LOG( "getHardwareAddress() ===>\n" );
idr.int32 = OSSwapLittleToHostInt32( csrRead32( RTL_IDR0 ) );
address->bytes[0] = idr.bytes[0];
address->bytes[1] = idr.bytes[1];
address->bytes[2] = idr.bytes[2];
address->bytes[3] = idr.bytes[3];
idr.int32 = OSSwapLittleToHostInt32( csrRead32( RTL_IDR4 ) );
address->bytes[4] = idr.bytes[0];
address->bytes[5] = idr.bytes[1];
ELG( *(UInt16*)address->bytes, *(UInt32*)&address->bytes[2], 'gHWA', "RTL8139::getHardwareAddress" );
DEBUG_LOG( "getHardwareAddress() <===\n" );
return kIOReturnSuccess;
}
IOOutputQueue* RTL8139::createOutputQueue()
{
ELG( 0, 0, 'crOQ', "RTL8139::createOutputQueue" );
DEBUG_LOG( "createOutputQueue() ===>\n" );
DEBUG_LOG( "createOutputQueue() <===\n" );
return IOGatedOutputQueue::withTarget( this, getWorkLoop() );
}
IOReturn RTL8139::selectMedium( const IONetworkMedium *medium )
{
bool success;
ELG( 0, medium, 'sMed', "RTL8139::selectMedium" );
if ( medium == 0 )
medium = phyGetMediumWithIndex( MEDIUM_INDEX_AUTO );
if ( medium == 0 )
return kIOReturnUnsupported;
success = phySetMedium( medium );
if ( success )
{
setCurrentMedium( medium );
forceLinkChange = true; phyReportLinkStatus();
}
return success ? kIOReturnSuccess : kIOReturnIOError;
}
const OSString* RTL8139::newVendorString() const
{
DEBUG_LOG( "newVendorString() ===>\n" );
DEBUG_LOG( "newVendorString() <===\n" );
return OSString::withCString( "Realtek" );
}
const OSString* RTL8139::newModelString() const
{
const char *model = "8139";
DEBUG_LOG( "newModelString() ===>\n" );
DEBUG_LOG( "newModelString() <===\n" );
return OSString::withCString(model);
}
IOReturn RTL8139::registerWithPolicyMaker( IOService *policyMaker )
{
enum
{
kPowerStateOff = 0,
kPowerStateOn,
kPowerStateCount
};
static IOPMPowerState powerStateArray[ kPowerStateCount ] =
{
{ 1,0,0,0,0,0,0,0,0,0,0,0 },
{ 1, IOPMDeviceUsable, IOPMPowerOn, IOPMPowerOn, 0,0,0,0,0,0,0,0 }
};
IOReturn ret;
ELG( 0, 0, 'RwPM', "RTL8139::registerWithPolicyMaker" );
ret = policyMaker->registerPowerDriver( this, powerStateArray,
kPowerStateCount );
return ret;
}
IOReturn RTL8139::setPowerState( unsigned long powerStateOrdinal,
IOService *policyMaker )
{
ELG( 0, powerStateOrdinal, 's PS', "RTL8139::setPowerState" );
DEBUG_LOG( "setPowerState state %d\n", powerStateOrdinal);
return IOPMAckImplied;
}
IOReturn RTL8139::newUserClient( task_t owningTask,
void*, UInt32 type, IOUserClient **handler ) {
IOReturn ior = kIOReturnSuccess;
RTL8139UserClient *client = NULL;
bool privileged;
ELG( type, type, 'Usr+', "RTL8139::newUserClient" );
privileged = IOUserClient::clientHasPrivilege( current_task(), kIOClientPrivilegeAdministrator ) == kIOReturnSuccess;
if ( !privileged )
{
ELG( 0, 0, 'nuc-', "RTL8139::newUserClient - task is not privileged." );
return kIOReturnNotPrivileged;
}
if ( type != 'Rltk' )
{ ELG( 0, type, 'Usr-', "RTL8139::newUserClient - unlucky." );
return kIOReturnError;
}
client = RTL8139UserClient::withTask( owningTask );
if ( !client )
{
ELG( 0, 0, 'usr-', "Realtek::newUserClient: Can't create user client" );
return kIOReturnError;
}
if ( ior == kIOReturnSuccess )
{ if ( client->attach( this ) == false )
{
ior = kIOReturnError;
ELG( 0, 0, 'USR-', "Realtek::newUserClient: Can't attach user client" );
}
}
if ( ior == kIOReturnSuccess )
{ if ( client->start( this ) == false )
{
ior = kIOReturnError;
ELG( 0, 0, 'USR-', "Realtek::newUserClient: Can't start user client" );
}
}
if ( client && (ior != kIOReturnSuccess) )
{
client->detach( this );
client->release();
client = 0;
}
*handler = client;
return ior;
}
#pragma mark -
#pragma mark еее User Client еее
#pragma mark -
#undef super
#define super IOUserClient
OSDefineMetaClassAndStructors( RTL8139UserClient, IOUserClient ) ;
RTL8139UserClient* RTL8139UserClient::withTask( task_t owningTask )
{
RTL8139UserClient* me = new RTL8139UserClient;
if ( me && me->init() == false )
{
me->release();
return 0;
}
me->fTask = owningTask;
return me;
}
bool RTL8139UserClient::start( IOService *provider )
{
if ( super::start( provider ) == false ) return false;
if ( provider->open( this ) == false ) return false;
fProvider = (RTL8139*)provider;
fMethods[0].object = this;
fMethods[0].func = (IOMethod)&RTL8139UserClient::doRequest;
fMethods[0].count0 = 0xFFFFFFFF;
fMethods[0].count1 = 0xFFFFFFFF;
fMethods[0].flags = kIOUCStructIStructO;
return true;
}
IOReturn RTL8139UserClient::clientClose()
{
if ( fProvider )
{
if ( fProvider->isOpen( this ) )
fProvider->close( this );
detach( fProvider );
fProvider = 0;
}
return kIOReturnSuccess;
}
IOReturn RTL8139UserClient::clientDied()
{
return clientClose();
}
IOReturn RTL8139UserClient::connectClient( IOUserClient *client )
{
return kIOReturnSuccess;
}
IOReturn RTL8139UserClient::registerNotificationPort( mach_port_t port, UInt32 type )
{
return kIOReturnUnsupported;
}
IOExternalMethod* RTL8139UserClient::getExternalMethodForIndex( UInt32 index )
{
IOExternalMethod *result = NULL;
if ( index == 0 )
result = &fMethods[0];
return result;
}
IOReturn RTL8139UserClient::doRequest( void *pIn, void *pOut,
IOByteCount inputSize, IOByteCount *pOutPutSize )
{
UInt32 reqID;
bool privileged;
IOReturn ior = kIOReturnSuccess;
privileged = (IOUserClient::clientHasPrivilege(
current_task(), kIOClientPrivilegeAdministrator ) == kIOReturnSuccess);
if ( !privileged )
return kIOReturnNotPrivileged;
if ( !pIn || (inputSize < sizeof( UCRequest )) )
{
IOLog( "RTL8139UserClient::doRequest - bad argument(s) - pIn = %lx, inputSize = %ld.\n",
(UInt32)pIn, inputSize );
return kIOReturnBadArgument;
}
reqID = *(UInt32*)pIn;
switch ( reqID )
{
case kSelectLoopbackMAC:
case kSelectLoopbackPHY:
fProvider->fLoopbackMode = reqID;
break;
case kRltkUserCmd_GetLog: ior = getRltkLog( pIn, pOut, inputSize, pOutPutSize ); break;
case kRltkUserCmd_GetRegs: ior = getRltkRegs( pIn, pOut, inputSize, pOutPutSize ); break;
case kRltkUserCmd_WriteOneReg: ior = writeOneRltkReg( pIn, pOut, inputSize, pOutPutSize ); break;
default:
IOLog( "RTL8139UserClient::doRequest - Bad command, %lx\n", reqID );
ior = kIOReturnBadArgument;
break;
}
return ior;
}
#if USE_ELG
IOReturn RTL8139UserClient::getRltkLog( void *pIn, void *pOut,
IOByteCount inputSize, IOByteCount *pOutPutSize )
{
UCRequest *req = (UCRequest*)pIn;
IOVirtualAddress clientAddr;
UC_ELG( (UInt32)pIn, inputSize, 'UgLg', "RTL8139UserClient::getRltkLog" );
fMap = fProvider->fpELGMemDesc->map( fTask, 0, kIOMapAnywhere );
clientAddr = fMap->getVirtualAddress();
req->pLogBuffer = (UInt8*)clientAddr;
req->bufSize = (fProvider->fpELG->evLogBufe - fProvider->fpELG->evLogBuf + PAGE_SIZE) & ~(PAGE_SIZE - 1);
bcopy( req, pOut, sizeof( UCRequest ) );
*pOutPutSize = sizeof( UCRequest );
return kIOReturnSuccess;
}
#else // Production driver - no event logging buffer:
IOReturn RTL8139UserClient::getRltkLog( void*, void*, IOByteCount, IOByteCount* )
{
return kIOReturnBadArgument;
}
#endif // USE_ELG
IOReturn RTL8139UserClient::getRltkRegs( void *pIn, void *pOut,
IOByteCount inputSize, IOByteCount *pOutPutSize )
{
UInt8 *dest = (UInt8*)pOut;
UInt32 i;
if ( !pOut || (*pOutPutSize < PAGE_SIZE) ) {
IOLog( "RTL8139UserClient::getRltkRegs - bad argument(s) - pOut = %lx, *pOutPutSize = %ld.\n",
(UInt32)pOut, (UInt32)*pOutPutSize );
return kIOReturnBadArgument;
}
for ( i = 0; i < 0x80; i++ )
*dest++ = fProvider->csrRead8( i );
*pOutPutSize = 0x80;
UC_ELG( 0, *pOutPutSize, 'gReg', "RTL8139UserClient::getRltkRegs - done" );
return kIOReturnSuccess;
}
static UInt8 regSize[ 0x80 ] =
{
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 2, 0, 1, 1, 2, 0, 2, 0, 2, 0, 2, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
1, 1, 1, 0, 4, 0, 0, 0, 1, 1, 1, 1, 2, 0, 0, 0,
2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0,
2, 0, 2, 0, 2, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0
};
IOReturn RTL8139UserClient::writeOneRltkReg(
void *pIn, void *pOut,
IOByteCount inputSize, IOByteCount *pOutPutSize )
{
UCRequest *req = (UCRequest*)pIn;
UInt32 reg, value;
UInt8 size = 0;
UC_ELG( (UInt32)pIn, inputSize, 'UgWR', "RTL8139UserClient::writeOneRltkReg" );
*pOutPutSize = 0;
reg = (UInt32)req->pLogBuffer;
value = req->bufSize;
if ( reg == 0x100 ) {
fProvider->fTSD_ERTXTH = (value & 0x3F) << 16;
return kIOReturnSuccess;
}
if ( reg < 0x80 )
size = regSize[ reg ];
if ( size == 0 )
{
IOLog( "RTL8139UserClient::writeOneRltkReg - bad argument(s) - reg = %lx; size = %d.\n", reg, size );
return kIOReturnBadArgument;
}
switch ( size )
{
case 1:
if ( value >= 256 ) { size = 0; break; }
fProvider->csrWrite8( reg, (UInt8)value );
case 2:
if ( value >= 0x10000 ) { size = 0; break; }
fProvider->csrWrite16( reg, (UInt16)value );
case 4:
fProvider->csrWrite32( reg, (UInt32)value );
}
if ( size == 0 )
{
IOLog( "RTL8139UserClient::writeOneRltkReg - value too large for register - reg = %lx; value = %lx.\n", reg, value );
return kIOReturnBadArgument;
}
return kIOReturnSuccess;
}