IOFireWireROMCache.cpp [plain text]
#include "FWDebugging.h"
#include "IOFireWireROMCache.h"
#include <IOKit/firewire/IOFireWireDevice.h>
#include <IOKit/firewire/IOFireWireUnit.h>
#include <IOKit/firewire/IOFireWireController.h>
OSDefineMetaClassAndStructors(IOFireWireROMCache, OSObject)
OSMetaClassDefineReservedUnused(IOFireWireROMCache, 0);
OSMetaClassDefineReservedUnused(IOFireWireROMCache, 1);
OSMetaClassDefineReservedUnused(IOFireWireROMCache, 2);
OSMetaClassDefineReservedUnused(IOFireWireROMCache, 3);
OSMetaClassDefineReservedUnused(IOFireWireROMCache, 4);
OSMetaClassDefineReservedUnused(IOFireWireROMCache, 5);
OSMetaClassDefineReservedUnused(IOFireWireROMCache, 6);
OSMetaClassDefineReservedUnused(IOFireWireROMCache, 7);
#define kROMBIBSizeMinimal 4 // technically, this is the size of the ROM header
#define kROMBIBSizeGeneral 20 // technically, this is the size of the ROM header + the BIB
IOFireWireROMCache * IOFireWireROMCache::withOwnerAndBytes( IOFireWireDevice *owner, const void *bytes, unsigned int inLength, UInt32 generation )
{
IOFireWireROMCache *me = new IOFireWireROMCache;
if( me && !me->initWithOwnerAndBytes( owner, bytes, inLength, generation ) )
{
me->free();
return 0;
}
return me;
}
bool IOFireWireROMCache::initWithOwnerAndBytes( IOFireWireDevice *owner, const void *bytes, unsigned int inLength, UInt32 generation )
{
bool result = true;
fOwner = owner;
if( result )
{
fLock = IORecursiveLockAlloc();
if( fLock == NULL )
result = false;
}
if( result )
{
fROM = OSData::withBytes( bytes, inLength );
if( fROM == NULL )
result = false;
}
setROMState( kROMStateResumed, generation );
FWKLOG(( "IOFireWireROMCache@0x%08lx::initWithOwnerAndBytes created ROM cache\n", (UInt32)this ));
return result;
}
void IOFireWireROMCache::free()
{
FWKLOG(( "IOFireWireROMCache@0x%08lx::free()\n", (UInt32)this ));
if( fROM != NULL )
{
fROM->release();
fROM = NULL;
}
if( fLock != NULL )
{
IORecursiveLockFree( fLock );
fLock = NULL;
}
OSObject::free();
}
unsigned int IOFireWireROMCache::getLength()
{
unsigned int result;
lock();
result = fROM->getLength();
unlock();
return result;
}
unsigned int IOFireWireROMCache::ensureCapacity( unsigned int newCapacity )
{
unsigned int result;
lock();
result = fROM->ensureCapacity( newCapacity );
unlock();
return result;
}
bool IOFireWireROMCache::appendBytes( const void *bytes, unsigned int inLength )
{
bool result;
lock();
result = fROM->appendBytes( bytes, inLength );
unlock();
return result;
}
bool IOFireWireROMCache::appendBytes( const OSData *other )
{
bool result;
lock();
result = fROM->appendBytes( other );
unlock();
return result;
}
const void * IOFireWireROMCache::getBytesNoCopy()
{
const void * result;
lock();
result = fROM->getBytesNoCopy();
unlock();
return result;
}
const void * IOFireWireROMCache::getBytesNoCopy( unsigned int start, unsigned int inLength )
{
const void * result;
lock();
result = fROM->getBytesNoCopy( start, inLength );
unlock();
return result;
}
void IOFireWireROMCache::lock( void )
{
IORecursiveLockLock(fLock);
}
void IOFireWireROMCache::unlock( void )
{
IORecursiveLockUnlock(fLock);
}
bool IOFireWireROMCache::hasROMChanged( const UInt32 * newBIB, UInt32 newBIBSize )
{
bool rom_changed = false;
FWKLOG(( "IOFireWireROMCache@0x%08lx::hasROMChanged - newBIB = 0x%08lx, newBIBSize = %d\n", (UInt32)this, (UInt32)newBIB, (int)newBIBSize ));
FWPANICASSERT( newBIB != NULL );
FWPANICASSERT( newBIBSize != 0 );
FWKLOGASSERT( newBIBSize == kROMBIBSizeMinimal || newBIBSize == kROMBIBSizeGeneral );
lock();
if( newBIBSize > getLength() )
{
rom_changed = true;
}
if( newBIBSize < kROMBIBSizeGeneral &&
getLength() >= kROMBIBSizeGeneral )
{
rom_changed = true;
}
if( newBIBSize == kROMBIBSizeGeneral )
{
if( bcmp( newBIB, getBytesNoCopy(), newBIBSize) != 0 )
{
rom_changed = true;
}
UInt32 romGeneration = (newBIB[2] & kFWBIBGeneration) >> kFWBIBGenerationPhase;
if( romGeneration == 0 )
{
if( fOwner->getUnitCount() == 0 )
{
rom_changed = true;
}
}
}
if( fState == kROMStateInvalid )
{
rom_changed = true;
}
#if FWLOGGING
if( rom_changed )
{
FWKLOG(( "IOFireWireROMCache@0x%08lx::hasROMChanged - ROM changed\n", (UInt32)this ));
}
else
{
FWKLOG(( "IOFireWireROMCache@0x%08lx::hasROMChanged - ROM unchanged\n", (UInt32)this ));
}
#endif
unlock();
return rom_changed;
}
IOReturn IOFireWireROMCache::checkROMState( UInt32 &generation )
{
IOReturn status = kIOReturnSuccess;
FWKLOGASSERT( fOwner->getController()->inGate() == false );
lock();
while( fState == kROMStateSuspended )
{
FWKLOG(( "IOFireWireROMCache@0x%08lx::checkROMState fROMState == kROMStateSuspended sleep thread 0x%08lx\n",
(UInt32)this, (UInt32)IOThreadSelf() ));
IORecursiveLockSleep( fLock, &fState, THREAD_UNINT );
FWKLOG(( "IOFireWireROMCache@0x%08lx::checkROMState fROMState != kROMStateSuspended - wake thread 0x%08lx\n",
(UInt32)this, (UInt32)IOThreadSelf() ));
}
FWKLOGASSERT( fState == kROMStateInvalid || fState == kROMStateResumed );
if( fState == kROMStateInvalid )
{
status = kIOFireWireConfigROMInvalid;
}
else if( fState == kROMStateResumed )
{
status = kIOReturnSuccess;
}
generation = fGeneration;
#if 0
if( status == kROMStateInvalid )
{
FWKLOG(( "IOFireWireROMCache@0x%08lx::checkROMState(generation) return kIOFireWireConfigROMInvalid\n", (UInt32)this ));
}
else
{
FWKLOG(( "IOFireWireROMCache@0x%08lx::checkROMState(generation) return kIOReturnSuccess\n", (UInt32)this ));
}
#endif
unlock();
return status;
}
IOReturn IOFireWireROMCache::checkROMState( void )
{
IOReturn status = kIOReturnSuccess;
FWKLOGASSERT( fOwner->getController()->inGate() == false );
lock();
while( fState == kROMStateSuspended )
{
FWKLOG(( "IOFireWireROMCache@0x%08lx::checkROMState fROMState == kROMStateSuspended sleep thread 0x%08lx\n",
(UInt32)this, (UInt32)IOThreadSelf() ));
IORecursiveLockSleep( fLock, &fState, THREAD_UNINT );
FWKLOG(( "IOFireWireROMCache@0x%08lx::checkROMState fROMState != kROMStateSuspended - wake thread 0x%08lx\n",
(UInt32)this, (UInt32)IOThreadSelf() ));
}
FWKLOGASSERT( fState == kROMStateInvalid || fState == kROMStateResumed );
if( fState == kROMStateInvalid )
{
status = kIOFireWireConfigROMInvalid;
}
else if( fState == kROMStateResumed )
{
status = kIOReturnSuccess;
}
#if 0
if( status == kROMStateInvalid )
{
FWKLOG(( "IOFireWireROMCache@0x%08lx::checkROMState return kIOFireWireConfigROMInvalid\n", (UInt32)this ));
}
else
{
FWKLOG(( "IOFireWireROMCache@0x%08lx::checkROMState return kIOReturnSuccess\n", (UInt32)this ));
}
#endif
unlock();
return status;
}
void IOFireWireROMCache::setROMState( ROMState state, UInt32 generation )
{
lock();
#if 0
if( state == kROMStateResumed )
{
FWKLOG(( "IOFireWireROMCache@0x%08lx::setROMState - kROMStateResumed, gen = %ld\n", (UInt32)this, generation ));
}
else if( state == kROMStateSuspended )
{
FWKLOG(( "IOFireWireROMCache@0x%08lx::setROMState - kROMStateSuspended\n", (UInt32)this ));
}
else
{
FWKLOG(( "IOFireWireROMCache@0x%08lx::setROMState - kROMStateInvalid\n", (UInt32)this ));
}
#endif
fState = state;
if( fState == kROMStateResumed )
{
fGeneration = generation;
}
if( fState == kROMStateResumed || fState == kROMStateInvalid )
{
unlock();
IORecursiveLockWakeup( fLock, &fState, false );
}
else
{
unlock();
}
}
IOReturn IOFireWireROMCache::updateROMCache( UInt32 offset, UInt32 length )
{
IOReturn status = kIOReturnSuccess;
FWKLOG(( "IOFireWireROMCache@0x%08lx::updateROMCache entered offset = %ld, length = %ld\n", (UInt32)this, offset, length ));
FWKLOGASSERT( fOwner->getController()->inGate() == false );
UInt32 generation = 0;
status = checkROMState( generation );
if( status == kIOReturnSuccess )
{
unsigned int romLength = getLength();
UInt32 romEnd = (offset + length) * sizeof(UInt32);
while( romEnd > romLength && kIOReturnSuccess == status)
{
UInt32 * buff;
int bufLen;
IOFWReadQuadCommand * cmd;
FWKLOG(( "IOFireWireROMCache %p:Need to extend ROM cache from 0x%lx to 0x%lx quads\n",
this, romLength/sizeof(UInt32), romEnd ));
bufLen = romEnd - romLength;
buff = (UInt32 *)IOMalloc(bufLen);
cmd = fOwner->createReadQuadCommand( FWAddress(kCSRRegisterSpaceBaseAddressHi, kFWBIBHeaderAddress+romLength),
buff, bufLen/sizeof(UInt32), NULL, NULL, true );
cmd->setMaxSpeed( kFWSpeed100MBit );
cmd->setGeneration( generation );
status = cmd->submit();
cmd->release();
if( status == kIOFireWireBusReset )
{
UInt32 oldGeneration = generation;
status = checkROMState( generation );
if(status == kIOReturnSuccess && generation == oldGeneration) {
setROMState(kROMStateSuspended);
}
}
else if( status == kIOReturnSuccess )
{
unsigned int newLength;
lock();
newLength = getLength();
if( romLength == newLength )
{
appendBytes( buff, bufLen );
newLength += bufLen;
}
romLength = newLength;
unlock();
}
else
{
FWKLOG(( "%p: err 0x%x reading ROM\n", this, status ));
}
IOFree( buff, bufLen );
}
}
FWKLOG(( "IOFireWireROMCache@%08lx::updateROMCache exited status = 0x%08lx\n", (UInt32)this, (UInt32)status ));
return status;
}
bool IOFireWireROMCache::serialize( OSSerialize * s ) const
{
OSDictionary * dictionary;
bool ok;
dictionary = OSDictionary::withCapacity( 4 );
if( !dictionary )
return false;
dictionary->setObject( "Offset 0", fROM );
ok = dictionary->serialize(s);
dictionary->release();
return ok;
}