#include "UniNEnet.h"
#include "UniNEnetMII.h"
#include <libkern/OSByteOrder.h>
extern "C"
{
extern boolean_t ml_probe_read( vm_offset_t physAddr, unsigned int *val );
}
#define super IOEthernetController
OSDefineMetaClassAndStructors( UniNEnet, IOEthernetController ) ;
globals g;
#if USE_ELG
static void AllocateEventLog( UInt32 size )
{
IOPhysicalAddress phys;
if ( g.evLogBuf )
return;
g.evLogFlag = 0;
g.evLogBuf = (UInt8*)IOMallocContiguous( size, 0x1000, &phys );
if ( !g.evLogBuf )
{
kprintf( "AllocateEventLog - UniNEnet evLog allocation failed " );
return;
}
bzero( g.evLogBuf, size );
g.evLogBufp = g.evLogBuf;
g.evLogBufe = g.evLogBufp + kEvLogSize - 0x20; g.evLogFlag = 0xFEEDBEEF;
IOLog( "UniNEnet - AllocateEventLog - &globals=%8x buffer=%8x phys=%8x\n",
(unsigned int)&g, (unsigned int)g.evLogBuf, (UInt32)phys );
return;
}
void EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str )
{
register UInt32 *lp;
mach_timespec_t time;
UInt32 lefty;
if ( g.evLogFlag == 0 )
return;
IOGetTime( &time );
if ( g.evLogFlag == 0xDEBEEFED )
{
for ( lp = (UInt32*)g.evLogBuf; lp < (UInt32*)g.evLogBufe; lp++ )
*lp = 0xDEBEEFED;
g.evLogBufp = g.evLogBuf; g.evLogFlag = 0x333; }
lp = (UInt32*)g.evLogBufp;
g.evLogBufp += 0x10;
if ( g.evLogBufp >= g.evLogBufe )
{ g.evLogBufp = g.evLogBuf;
if ( g.evLogFlag != 0xFEEDBEEF ) g.evLogFlag = 0;
IOFlushProcessorCache( kernel_task, (IOVirtualAddress)g.evLogBuf, kEvLogSize );
}
if ( g.pRegs )
lefty = OSSwapInt32( ((GMAC_Registers*)g.pRegs)->RxCompletion ) << 24;
else lefty = 0xFF000000;
*lp++ = lefty | (time.tv_nsec >> 10); *lp++ = a;
*lp++ = b;
*lp = ascii;
if ( g.evLogFlag == 'step' )
{ static char code[ 5 ] = {0,0,0,0,0};
*(UInt32*)&code = ascii;
IOLog( "%8x UniNEnet: %8x %8x\t%s\n",
time.tv_nsec>>10, (unsigned int)a, (unsigned int)b, code );
IOSleep( 2 );
}
lp = (UInt32*)g.evLogBufe; *lp = (UInt32)g.evLogBufp;
return;
}
void Alert( UInt32 a, UInt32 b, UInt32 ascii, char* str )
{
char work [ 256 ];
char name[] = "UniNEnet: ";
char *bp = work;
UInt8 x;
int i;
EvLog( a, b, ascii, str );
EvLog( '****', '** A', 'lert', "*** Alert" );
bcopy( name, bp, sizeof( name ) );
bp += sizeof( name ) - 1;
*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++ = '\n';
OSSynchronizeIO();
IOFlushProcessorCache( kernel_task, (IOVirtualAddress)g.evLogBuf, kEvLogSize );
return;
}
#endif // USE_ELG
bool UniNEnet::init( OSDictionary *properties )
{
#if USE_ELG
AllocateEventLog( kEvLogSize );
fpGlobals = &g; g.UniNEnetInstance = this;
g.pRegs = 0;
ELG( &g, g.evLogBufp, 'eNet', "UniNEnet::init - event logging set up." );
#endif
if ( super::init( properties ) == false )
return false;
phyId = 0xFF;
linkStatusPrev = kLinkStatusUnknown;
return true;
}
bool UniNEnet::start( IOService *provider )
{
OSString *matchEntry;
IOWorkLoop *myWorkLoop = getWorkLoop();
ELG( IOThreadSelf(), provider, 'Strt', "UniNEnet::start - this, provider." );
matchEntry = OSDynamicCast( OSString, getProperty( gIONameMatchedKey ) );
if ( matchEntry == 0 )
{
ALERT( 0, 0, 'Mat-', "UniNEnet::start: Cannot obtain matching property." );
return false;
}
fBuiltin = matchEntry->isEqualTo( "gmac" );
nub = OSDynamicCast( IOPCIDevice, provider );
if ( !nub || !super::start( provider ) )
return false;
if ( fBuiltin )
{
keyLargo = waitForService( serviceMatching( "KeyLargo" ) );
if ( keyLargo == 0 ) return false;
keyLargo_resetUniNEthernetPhy = OSSymbol::withCString( "keyLargo_resetUniNEthernetPhy" );
ELG( IOThreadSelf(), keyLargo, 'KeyL', "UniNEnet::start - KeyLargo" );
}
else
{
keyLargo = 0;
}
transmitQueue = (IOGatedOutputQueue*)getOutputQueue();
if ( !transmitQueue )
{
IOLog( "UniNEnet::start - Output queue initialization failed\n" );
return false;
}
transmitQueue->retain();
debugQueue = IOPacketQueue::withCapacity( (UInt)-1 );
if ( !debugQueue )
return false;
mbufCursor = IOMbufBigMemoryCursor::withSpecification( NETWORK_BUFSIZE, 1 );
if ( !mbufCursor )
{
IOLog( "UniNEnet::start - IOMbufBigMemoryCursor allocation failure\n" );
return false;
}
phyId = 0xFF;
myWorkLoop = getWorkLoop();
interruptSource = IOInterruptEventSource::interruptEventSource(
(OSObject*)this,
(IOInterruptEventAction)&UniNEnet::interruptOccurred,
(IOService*)provider,
(int)0 );
if ( interruptSource == NULL )
{ IOLog( "UniNEnet::start: Couldn't allocate Interrupt event source\n" );
return false;
}
if ( myWorkLoop->addEventSource( interruptSource ) != kIOReturnSuccess )
{ IOLog( "UniNEnet::start - Couldn't add Interrupt event source\n" );
return false;
}
timerSource = IOTimerEventSource::timerEventSource(
this,
(IOTimerEventSource::Action)&UniNEnet::timeoutOccurred );
if ( timerSource == NULL )
{
IOLog( "UniNEnet::start - Couldn't allocate timer event source\n" );
return false;
}
if ( myWorkLoop->addEventSource( timerSource ) != kIOReturnSuccess )
{
IOLog( "UniNEnet::start - Couldn't add timer event source\n" );
return false;
}
MGETHDR( txDebuggerPkt, M_DONTWAIT, MT_DATA );
if ( !txDebuggerPkt )
{ IOLog( "UniNEnet::start - Couldn't allocate KDB buffer\n" );
return false;
}
if ( getHardwareAddress( &myAddress ) != kIOReturnSuccess )
{ ALERT( 0, 0, 'gha-', "UniNEnet::start - getHardwareAddress failed" );
return false;
}
if ( allocateMemory() == false )
{ ALERT( 0, 0, 'alo-', "UniNEnet::start - allocateMemory failed" );
return false;
}
ELG( IOThreadSelf(), 0, 'AttI', "UniNEnet::start - attach interface" );
if ( !attachInterface( (IONetworkInterface**)&networkInterface, false ) )
{ ALERT( 0, 0, 'Att-', "UniNEnet::start - attachInterface failed" );
return false;
}
if ( fBuiltin )
{
ELG( IOThreadSelf(), 0, 'AttD', "UniNEnet::start - attach debugger" );
attachDebuggerClient( &debugger );
}
if ( fBuiltin )
{ ELG( IOThreadSelf(), currentPowerState, 'powr', "UniNEnet::start - more power!" );
}
else
{
currentPowerState = 1; }
ELG( IOThreadSelf(), 0, 'RegS', "UniNEnet::start - networkInterface->registerService" );
networkInterface->registerService();
ELG( IOThreadSelf(), 0, 'Exit', "UniNEnet::start - exiting" );
return true;
}
bool UniNEnet::configureInterface( IONetworkInterface *netif )
{
IONetworkData *nd;
ELG( IOThreadSelf(), netif, 'cfig', "configureInterface" );
if ( super::configureInterface( netif ) == false )
return false;
nd = netif->getNetworkData( kIONetworkStatsKey );
if (!nd || !(fpNetStats = (IONetworkStats *) nd->getBuffer()))
{
IOLog("EtherNet(UniN): invalid network statistics\n");
return false;
}
nd = netif->getParameter( kIOEthernetStatsKey );
if ( !nd || !(fpEtherStats = (IOEthernetStats*)nd->getBuffer()) )
{
IOLog( "UniNEnet::configureInterface - invalid ethernet statistics\n" );
return false;
}
return true;
}
void UniNEnet::free()
{
ELG( this, 0, 'Free', "UniNEnet::free" );
putToSleep();
flushRings( true, true );
if ( debugger ) debugger->release();
if ( getWorkLoop() ) getWorkLoop()->disableAllEventSources();
if ( timerSource ) { timerSource->release(); timerSource = 0; }
if ( interruptSource ) interruptSource->release();
if ( txDebuggerPkt ) freePacket( txDebuggerPkt );
if ( transmitQueue ) transmitQueue->release();
if ( debugQueue ) debugQueue->release();
if ( networkInterface ) networkInterface->release();
if ( mbufCursor ) mbufCursor->release();
if ( mediumDict ) mediumDict->release();
if ( ioMapEnet ) ioMapEnet->release();
if ( dmaCommands ) IOFreeContiguous( (void*)dmaCommands, dmaCommandsSize );
if ( workLoop ) { workLoop->release(); workLoop = 0; }
if ( keyLargo_resetUniNEthernetPhy )
{
keyLargo_resetUniNEthernetPhy->release();
keyLargo_resetUniNEthernetPhy = 0;
}
super::free();
return;
}
bool UniNEnet::createWorkLoop()
{
workLoop = IOWorkLoop::workLoop();
return ( workLoop != 0 );
}
IOWorkLoop* UniNEnet::getWorkLoop() const
{
return workLoop;
}
void UniNEnet::interruptOccurred( IOInterruptEventSource *src, int )
{
IODebuggerLockState lockState;
UInt32 interruptStatus;
bool doFlushQueue;
bool doService;
if ( ready == false )
{
ALERT( 0, READ_REGISTER( Status ), 'int-', "interruptOccurred - not ready" );
return;
}
do
{
lockState = IODebuggerLock( this );
interruptStatus = READ_REGISTER( Status )
& ( kStatus_TX_INT_ME | kStatus_RX_DONE );
ELG( READ_REGISTER( RxCompletion ), interruptStatus, 'Int+', "interruptOccurred - got status" );
doService = false;
if ( interruptStatus & kStatus_TX_INT_ME )
{
txWDInterrupts++;
KERNEL_DEBUG(DBG_GEM_TXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 );
doService = transmitInterruptOccurred();
KERNEL_DEBUG(DBG_GEM_TXIRQ | DBG_FUNC_END, 0, 0, 0, 0, 0 );
ETHERNET_STAT_ADD( dot3TxExtraEntry.interrupts );
}
doFlushQueue = false;
if ( interruptStatus & kStatus_RX_DONE )
{
rxWDInterrupts++;
KERNEL_DEBUG(DBG_GEM_RXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 );
doFlushQueue = receiveInterruptOccurred();
KERNEL_DEBUG(DBG_GEM_RXIRQ | DBG_FUNC_END, 0, 0, 0, 0, 0 );
ETHERNET_STAT_ADD( dot3RxExtraEntry.interrupts );
}
IODebuggerUnlock( lockState );
if ( doFlushQueue )
networkInterface->flushInputQueue();
if ( doService && netifEnabled )
transmitQueue->service();
} while ( interruptStatus );
return;
}
UInt32 UniNEnet::outputPacket(struct mbuf * pkt, void * param)
{
UInt32 ret = kIOReturnOutputSuccess;
KERNEL_DEBUG( DBG_GEM_TXQUEUE | DBG_FUNC_NONE,
(int) pkt, (int) pkt->m_pkthdr.len, 0, 0, 0 );
reserveDebuggerLock();
ELG( pkt, linkStatusPrev, 'OutP', "outputPacket" );
if ( linkStatusPrev != kLinkStatusUp )
{
ELG( pkt, linkStatusPrev, 'Out-', "UniNEnet::outputPacket - link is down" );
freePacket( pkt );
}
else if ( transmitPacket(pkt) == false )
{
ret = kIOReturnOutputStall;
}
releaseDebuggerLock();
return ret;
}
void UniNEnet::putToSleep()
{
ELG( this, 0, 'Slep', "UniNEnet::putToSleep" );
reserveDebuggerLock();
ready = false;
if ( timerSource )
timerSource->cancelTimeout();
WRITE_REGISTER( InterruptMask, kInterruptMask_None );
if ( getWorkLoop() )
getWorkLoop()->disableAllInterrupts();
setLinkStatus( 0, 0 );
stopChip(); flushRings( true, false );
stopPHY();
currentPowerState = 0;
if ( fBuiltin && !fWOL )
{
ALERT( 0, 0, '-Clk', "UniNEnet::setPowerState - turning off cell clock!!!" );
OSSynchronizeIO();
callPlatformFunction( "EnableUniNEthernetClock", true, (void*)false, 0, 0, 0 );
OSSynchronizeIO();
ALERT( 0, 0, '-clk', "UniNEnet::setPowerState - turned off cell clock!!!" );
}
releaseDebuggerLock();
return;
}
bool UniNEnet::wakeUp()
{
bool rc = false;
bool regAvail;
UInt32 gemReg = 0;
ELG( this, 0, 'Wake', "UniNEnet::wakeUp" );
reserveDebuggerLock();
ready = false;
phyId = 0xFF;
if ( timerSource )
timerSource->cancelTimeout();
if ( getWorkLoop() )
getWorkLoop()->disableAllInterrupts();
setLinkStatus( 0, 0 );
if ( fBuiltin )
{
callPlatformFunction( "EnableUniNEthernetClock", true, (void*)true, 0, 0, 0 );
if ( ioMapEnet ) {
IOSleep( 10 );
regAvail = ml_probe_read( (vm_offset_t)&fpRegsPhys->Status,
&(unsigned int)gemReg );
if ( !regAvail ) {
IOLog( "UniNEnet::wakeUp - ethernet cell's clock is disabled.\n" );
callPlatformFunction( "EnableUniNEthernetClock", true, (void*)true, 0, 0, 0 );
IOSleep( 10 );
regAvail = ml_probe_read( (vm_offset_t)&fpRegsPhys->Status,
&(unsigned int)gemReg );
if ( !regAvail ) {
IOLog( "UniNEnet::wakeUp - ethernet cell's clock is still disabled.\n" );
goto wakeUp_exit;
}
}
}
}
nub->configWrite32( 0x04, 0x16 );
nub->configWrite32( 0x0C, ((2 + (kGEMBurstSize * (0+1)))<< 8) | (CACHE_LINE_SIZE >> 2) );
if ( ioMapEnet == NULL )
{
ioMapEnet = nub->mapDeviceMemoryWithRegister( 0x10 );
if ( ioMapEnet == NULL )
goto wakeUp_exit;
fpRegs = (GMAC_Registers*)ioMapEnet->getVirtualAddress();
g.pRegs = (UInt32)fpRegs;
ELG( ioMapEnet, fpRegs, 'Adrs', "start - base eNet addr" );
fpRegsPhys = (GMAC_Registers*)ioMapEnet->getPhysicalAddress();
}
if ( !initRxRing() || !initTxRing() )
goto wakeUp_exit;
currentPowerState = 1;
WRITE_REGISTER( SoftwareReset, kSoftwareReset_TX | kSoftwareReset_RX );
do
{
gemReg = READ_REGISTER( SoftwareReset );
}
while( gemReg & (kSoftwareReset_TX | kSoftwareReset_RX) );
initChip();
if ( !mediumDict && createMediumTables() == false )
{ ALERT( 0, 0, 'cmt-', "UniNEnet::start - createMediumTables failed" );
goto wakeUp_exit;
}
if ( fBuiltin )
{
hardwareResetPHY();
if ( phyId == 0xFF)
{
if ( miiFindPHY( &phyId ) == false )
goto wakeUp_exit;
}
if ( getPhyType() == false ) goto wakeUp_exit;
}
startPHY();
if ( fBuiltin )
miiInitializePHY( phyId );
timerSource->setTimeoutMS( WATCHDOG_TIMER_MS );
if ( getWorkLoop() )
getWorkLoop()->enableAllInterrupts();
ready = true;
monitorLinkStatus( true ); rc = true;
wakeUp_exit:
releaseDebuggerLock();
return rc;
}
IOReturn UniNEnet::enable(IONetworkInterface * netif)
{
ELG( this, netif, 'NetE', "UniNEnet::enable( netInterface* )" );
if ( netifEnabled )
{
IOLog("EtherNet(UniN): already enabled\n");
return kIOReturnSuccess;
}
if ( (ready == false) && !wakeUp() )
return kIOReturnIOError;
netifEnabled = true;
transmitQueue->setCapacity( TRANSMIT_QUEUE_SIZE );
transmitQueue->start();
return kIOReturnSuccess;
}
IOReturn UniNEnet::disable(IONetworkInterface * )
{
ELG( this, debugEnabled, 'NetD', "disable( IONetworkInterface* )" );
transmitQueue->stop();
transmitQueue->setCapacity(0);
transmitQueue->flush();
if ( debugEnabled == false )
putToSleep();
netifEnabled = false;
return kIOReturnSuccess;
}
IOReturn UniNEnet::enable(IOKernelDebugger * )
{
ELG( this, ready, 'DbgE', "UniNEnet::enable( IOKernelDebugger* )" );
if ( (ready == false) && !wakeUp() )
return kIOReturnIOError;
debugEnabled = true;
return kIOReturnSuccess;
}
IOReturn UniNEnet::disable(IOKernelDebugger * )
{
ELG( this, netifEnabled, 'DbgD', "UniNEnet::disable( IOKernelDebugger* )" );
debugEnabled = false;
if ( netifEnabled == false )
putToSleep();
return kIOReturnSuccess;
}
IOReturn UniNEnet::getPacketFilters( const OSSymbol *group, UInt32 *filters ) const
{
ELG( group, filters, 'G PF', "UniNEnet::getPacketFilters" );
if ( group == gIOEthernetWakeOnLANFilterGroup )
{
if ( fBuiltin )
*filters = kIOEthernetWakeOnMagicPacket;
else *filters = 0;
return kIOReturnSuccess;
}
return super::getPacketFilters( group, filters );
}
IOReturn UniNEnet::setWakeOnMagicPacket( bool active )
{
ELG( this, active, 'WoMP', "UniNEnet::setWakeOnMagicPacket" );
fWOL = active;
return kIOReturnSuccess;
}
void UniNEnet::timeoutOccurred(IOTimerEventSource * )
{
IODebuggerLockState lockState;
bool doService = false;
UInt32 txRingIndex;
UInt32 x;
if ( ready == false )
{
ALERT( txCommandHead, txCommandTail, 'TIM-', "UniNEnet::timeoutOccurred - spurious" );
return;
}
ELG( txCommandHead, txCommandTail, 'Time', "UniNEnet::timeoutOccurred" );
x = READ_REGISTER( LengthErrorCounter );
if ( x ) WRITE_REGISTER( LengthErrorCounter, 0 );
fpEtherStats->dot3StatsEntry.frameTooLongs += x;
x = READ_REGISTER( AlignmentErrorCounter );
if ( x ) WRITE_REGISTER( AlignmentErrorCounter, 0 );
fpEtherStats->dot3StatsEntry.alignmentErrors += x;
x = READ_REGISTER( FCSErrorCounter );
if ( x ) WRITE_REGISTER( FCSErrorCounter, 0 );
fpEtherStats->dot3StatsEntry.fcsErrors += x;
x = READ_REGISTER( RxCodeViolationErrorCounter );
if ( x ) WRITE_REGISTER( RxCodeViolationErrorCounter, 0 );
fpEtherStats->dot3StatsEntry.internalMacTransmitErrors += x;
x = READ_REGISTER( FirstAttemptSuccessfulCollisionCounter );
if ( x ) WRITE_REGISTER( FirstAttemptSuccessfulCollisionCounter, 0 );
fpEtherStats->dot3StatsEntry.singleCollisionFrames += x;
x = READ_REGISTER( ExcessiveCollisionCounter );
if ( x ) WRITE_REGISTER( ExcessiveCollisionCounter, 0 );
fpEtherStats->dot3StatsEntry.excessiveCollisions += x;
x = READ_REGISTER( LateCollisionCounter );
if ( x ) WRITE_REGISTER( LateCollisionCounter, 0 );
fpEtherStats->dot3StatsEntry.lateCollisions += x;
lockState = IODebuggerLock( this );
monitorLinkStatus( false );
if ( txCommandHead != txCommandTail )
{
txRingIndex = READ_REGISTER( TxCompletion );
if ( txRingIndex == txRingIndexLast )
{
txWDCount++;
}
else
{
txWDCount = 0;
txRingIndexLast = txRingIndex;
}
if ( txWDCount > 2 )
{
if ( txRingIndex != txCommandTail )
{
UInt32 interruptStatus, compReg, kickReg;
interruptStatus = READ_REGISTER( Status );
compReg = READ_REGISTER( TxCompletion );
kickReg = READ_REGISTER( TxKick );
IOLog( "Tx Int Timeout - Comp = %04x Kick = %04x Int = %08x\n\r", (int)compReg, (int)kickReg, (int)interruptStatus );
}
transmitInterruptOccurred();
doService = true;
txRingIndexLast = txRingIndex;
txWDCount = 0;
}
}
else
{
txWDCount = 0;
}
if ( rxWDInterrupts == 0 )
{
UInt32 rxMACStatus;
switch ( rxWDCount )
{
case 0:
case 1:
rxWDCount++; break;
default:
rxMACStatus = READ_REGISTER( RxMACStatus );
if ( rxMACStatus & kRX_MAC_Status_Rx_Overflow )
{
restartReceiver();
NETWORK_STAT_ADD( inputErrors );
ETHERNET_STAT_ADD( dot3RxExtraEntry.watchdogTimeouts );
}
rxWDCount = 0;
break;
}
}
else
{
rxWDCount = 0;
rxWDInterrupts = 0;
}
if ( debugTxPoll )
{
debugQueue->flush();
debugTxPoll = false;
doService = true;
}
IODebuggerUnlock( lockState );
if (doService && netifEnabled)
{
transmitQueue->service();
}
timerSource->setTimeoutMS(WATCHDOG_TIMER_MS);
return;
}
const OSString * UniNEnet::newVendorString() const
{
return OSString::withCString("Apple");
}
const OSString * UniNEnet::newModelString() const
{
return OSString::withCString("gmac+");
}
const OSString * UniNEnet::newRevisionString() const
{
return OSString::withCString("");
}
IOReturn UniNEnet::setPromiscuousMode( bool active )
{
ELG( 0, active, 'SetP', "setPromiscuousMode" );
reserveDebuggerLock();
isPromiscuous = active;
rxMacConfigReg = READ_REGISTER( RxMACConfiguration );
if ( active )
rxMacConfigReg |= kRxMACConfiguration_Promiscuous;
else rxMacConfigReg &= ~kRxMACConfiguration_Promiscuous;
WRITE_REGISTER( RxMACConfiguration, rxMacConfigReg );
releaseDebuggerLock();
return kIOReturnSuccess;
}
IOReturn UniNEnet::setMulticastMode( bool active )
{
ELG( this, active, 'SetM', "setMulticastMode" );
multicastEnabled = active;
return kIOReturnSuccess;
}
IOReturn UniNEnet::setMulticastList(IOEthernetAddress *addrs, UInt32 count)
{
ELG( addrs, count, 'SetL', "setMulticastList" );
reserveDebuggerLock();
resetHashTableMask();
for (UInt32 i = 0; i < count; i++)
{
addToHashTableMask(addrs->bytes);
addrs++;
}
updateHashTableMask();
releaseDebuggerLock();
return kIOReturnSuccess;
}
IOOutputQueue* UniNEnet::createOutputQueue()
{
return IOBasicOutputQueue::withTarget( this, TRANSMIT_QUEUE_SIZE );
}
static struct MediumTable
{
UInt32 type;
UInt32 speed;
}
mediumTable[] =
{
{ kIOMediumEthernetNone , 0 },
{ kIOMediumEthernetAuto , 0 },
{ kIOMediumEthernet10BaseT | kIOMediumOptionHalfDuplex, 10 },
{ kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex, 10 },
{ kIOMediumEthernet100BaseTX | kIOMediumOptionHalfDuplex, 100 },
{ kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex, 100 },
{ kIOMediumEthernet1000BaseSX | kIOMediumOptionFullDuplex, 1000 },
{ kIOMediumEthernet1000BaseTX | kIOMediumOptionFullDuplex, 1000 }
};
bool UniNEnet::createMediumTables()
{
IONetworkMedium *medium;
UInt64 maxSpeed;
UInt16 phyWord;
UInt32 i;
if ( fBuiltin )
{
miiReadWord( &phyWord, MII_CONTROL, phyId );
if ( phyWord & MII_CONTROL_SPEED_SELECTION_2 )
maxSpeed = 1000;
else maxSpeed = 100;
}
else
{
maxSpeed = 1000; }
mediumDict = OSDictionary::withCapacity( sizeof( mediumTable ) / sizeof( mediumTable[0] ) );
ELG( 0, mediumDict, 'MTbl', "createMediumTables" );
if ( mediumDict == 0 )
return false;
for ( i = 0; i < sizeof( mediumTable ) / sizeof( mediumTable[0] ); i++ )
{
medium = IONetworkMedium::medium( mediumTable[i].type, mediumTable[i].speed );
if ( medium && (medium->getSpeed() <= maxSpeed) )
{
IONetworkMedium::addMedium( mediumDict, medium );
medium->release();
}
}
if ( publishMediumDictionary( mediumDict ) != true )
return false;
medium = IONetworkMedium::getMediumWithType( mediumDict, kIOMediumEthernetAuto );
setCurrentMedium( medium );
return true;
}
#ifdef HDW_CHECKSUM
IOReturn UniNEnet::getChecksumSupport( UInt32 *checksumMask,
UInt32 checksumFamily,
bool )
{
if ( checksumFamily != kChecksumFamilyTCPIP )
return kIOReturnUnsupported;
*checksumMask = kChecksumTCPSum16;
return kIOReturnSuccess;
}
#endif // HDW_CHECKSUM
void UniNEnet::writeRegister( volatile UInt32 *pReg, UInt32 data )
{
if ( pReg != &fpRegs->MIFBitBangFrame_Output )
ELG( data, (UInt32)pReg - (UInt32)fpRegs, 'wReg', "writeRegister" );
OSWriteLittleInt32( pReg, 0, data );
return;
}