IOFireWireDevice.cpp [plain text]
#import "FWDebugging.h"
#define DEBUGGING_LEVEL 0 // 1 = low; 2 = high; 3 = extreme
#ifndef DEBUGLOG
#define DEBUGLOG kprintf
#endif
#import <IOKit/assert.h>
#import <IOKit/IOMessage.h>
#import <IOKit/IODeviceTreeSupport.h>
#import <IOKit/firewire/IOFireWireLink.h>
#import <IOKit/firewire/IOFireWireDevice.h>
#import <IOKit/firewire/IOFireWireUnit.h>
#import <IOKit/firewire/IOFireWireController.h>
#import <IOKit/firewire/IOConfigDirectory.h>
#import "IORemoteConfigDirectory.h"
#import "IOFireWireROMCache.h"
#import <IOKit/firewire/IOFWSimpleContiguousPhysicalAddressSpace.h>
#include <IOKit/firewire/IOFWUtils.h>
OSDefineMetaClassAndStructors(IOFireWireDeviceAux, IOFireWireNubAux);
OSMetaClassDefineReservedUnused(IOFireWireDeviceAux, 0);
OSMetaClassDefineReservedUnused(IOFireWireDeviceAux, 1);
OSMetaClassDefineReservedUnused(IOFireWireDeviceAux, 2);
OSMetaClassDefineReservedUnused(IOFireWireDeviceAux, 3);
#pragma mark -
bool IOFireWireDeviceAux::init( IOFireWireDevice * primary )
{
bool success = true;
if( !IOFireWireNubAux::init( primary ) )
success = false;
if( success )
{
fUnitCount = 0;
fMaxSpeed = kFWSpeedMaximum;
fOpenUnitSet = OSSet::withCapacity( 2 );
}
return success;
}
bool IOFireWireDeviceAux::isTerminated( void )
{
return ((fTerminationState == kTerminated) || fPrimary->isInactive());
}
void IOFireWireDeviceAux::setTerminationState( TerminationState state )
{
IOReturn status = kIOReturnSuccess;
IOFireWireNubAux::setTerminationState( state );
if( fTerminationState == kTerminated )
{
OSIterator * clientIterator = NULL;
OSObject * client = NULL;
if( status == kIOReturnSuccess )
{
clientIterator = fPrimary->getClientIterator();
if( clientIterator == NULL )
status = kIOReturnError;
}
if( status == kIOReturnSuccess )
{
clientIterator->reset();
while( (client = clientIterator->getNextObject()) )
{
IOFireWireUnit * unit;
unit = OSDynamicCast( IOFireWireUnit, client );
if( unit )
{
unit->setTerminationState( kTerminated );
}
}
}
if( clientIterator != NULL )
{
clientIterator->release();
}
}
FWKLOGASSERT( status == kIOReturnSuccess );
}
void IOFireWireDeviceAux::setMaxSpeed( IOFWSpeed speed )
{
fPrimary->fControl->closeGate();
fMaxSpeed = speed;
((IOFireWireDevice*)fPrimary)->configureNode();
fPrimary->fControl->openGate();
}
void IOFireWireDeviceAux::setUnitCount( UInt32 count )
{
fUnitCount = count;
}
UInt32 IOFireWireDeviceAux::getUnitCount( void )
{
return fUnitCount;
}
bool IOFireWireDeviceAux::isPhysicalAccessEnabled( void )
{
IOFireWireDevice * device = (IOFireWireDevice*)fPrimary;
bool enabled = false;
if( device->fNodeID != kFWBadNodeID )
{
enabled = device->fControl->isPhysicalAccessEnabledForNodeID( device->fNodeID & 0x3f );
}
return enabled;
}
IOFWSimpleContiguousPhysicalAddressSpace * IOFireWireDeviceAux::createSimpleContiguousPhysicalAddressSpace( vm_size_t size, IODirection direction )
{
IOFWSimpleContiguousPhysicalAddressSpace * space = IOFireWireNubAux::createSimpleContiguousPhysicalAddressSpace( size, direction );
if( space != NULL )
{
space->addTrustedNode( (IOFireWireDevice*)fPrimary );
}
return space;
}
IOFWSimplePhysicalAddressSpace * IOFireWireDeviceAux::createSimplePhysicalAddressSpace( vm_size_t size, IODirection direction )
{
IOFWSimplePhysicalAddressSpace * space = IOFireWireNubAux::createSimplePhysicalAddressSpace( size, direction );
if( space != NULL )
{
space->addTrustedNode( (IOFireWireDevice*)fPrimary );
}
return space;
}
void IOFireWireDeviceAux::free()
{
if( fOpenUnitSet )
{
fOpenUnitSet->release();
fOpenUnitSet = NULL;
}
IOFireWireNubAux::free();
}
OSSet * IOFireWireDeviceAux::getOpenUnitSet() const
{
return fOpenUnitSet;
}
void IOFireWireDeviceAux::latchResumeTime()
{
IOFWGetAbsoluteTime( &fResumeTime ); }
AbsoluteTime IOFireWireDeviceAux::getResumeTime( void )
{
return fResumeTime;
}
#pragma mark -
OSDefineMetaClassAndStructors(IOFireWireDevice, IOFireWireNub)
OSMetaClassDefineReservedUnused(IOFireWireDevice, 0);
OSMetaClassDefineReservedUnused(IOFireWireDevice, 1);
struct RomScan
{
IOFireWireDevice * fDevice;
UInt32 fROMGeneration;
};
class IOFireWireUnitInfo : public OSObject
{
OSDeclareDefaultStructors(IOFireWireUnitInfo);
private:
OSDictionary * fPropTable;
IOConfigDirectory * fDirectory;
UInt32 fSBP2LUN;
UInt32 fSBP2MAO;
UInt32 fSBP2Revision;
protected:
virtual void free();
public:
static IOFireWireUnitInfo * create( void );
void setPropTable( OSDictionary * propTable );
OSDictionary * getPropTable( void );
void setDirectory( IOConfigDirectory * directory );
IOConfigDirectory * getDirectory( void );
void setSBP2LUN( UInt32 sbp2_lun );
UInt32 getSBP2LUN( void );
void setSBP2MAO( UInt32 sbp2_mao );
UInt32 getSBP2MAO( void );
void setSBP2Revision( UInt32 sbp2_revision );
UInt32 getSBP2Revision( void );
};
OSDefineMetaClassAndStructors(IOFireWireUnitInfo, OSObject);
IOFireWireUnitInfo * IOFireWireUnitInfo::create( void )
{
IOFireWireUnitInfo * me;
me = OSTypeAlloc( IOFireWireUnitInfo );
return me;
}
void IOFireWireUnitInfo::free()
{
if( fPropTable != NULL )
{
fPropTable->release();
fPropTable = NULL;
}
if( fDirectory != NULL )
{
fDirectory->release();
fDirectory = NULL;
}
OSObject::free();
}
void IOFireWireUnitInfo::setPropTable( OSDictionary * propTable )
{
OSDictionary * oldPropTable = fPropTable;
propTable->retain();
fPropTable = propTable;
if( oldPropTable )
oldPropTable->release();
}
OSDictionary * IOFireWireUnitInfo::getPropTable( void )
{
return fPropTable;
}
void IOFireWireUnitInfo::setDirectory( IOConfigDirectory * directory )
{
IOConfigDirectory * oldDirectory = fDirectory;
directory->retain();
fDirectory = directory;
if( oldDirectory )
oldDirectory->release();
}
IOConfigDirectory * IOFireWireUnitInfo::getDirectory( void )
{
return fDirectory;
}
void IOFireWireUnitInfo::setSBP2LUN( UInt32 sbp2_lun )
{
fSBP2LUN = sbp2_lun;
}
UInt32 IOFireWireUnitInfo::getSBP2LUN( void )
{
return fSBP2LUN;
}
void IOFireWireUnitInfo::setSBP2MAO( UInt32 sbp2_mao )
{
fSBP2MAO = sbp2_mao;
}
UInt32 IOFireWireUnitInfo::getSBP2MAO( void )
{
return fSBP2MAO;
}
void IOFireWireUnitInfo::setSBP2Revision( UInt32 sbp2_revision )
{
fSBP2Revision = sbp2_revision;
}
UInt32 IOFireWireUnitInfo::getSBP2Revision( void )
{
return fSBP2Revision;
}
#pragma mark -
bool IOFireWireDevice::init(OSDictionary *propTable, const IOFWNodeScan *info)
{
if(!IOFireWireNub::init(propTable))
return false;
fROMReadRetry = 4;
if(info->fROMSize > 8)
{
UInt32 bib_quad = OSSwapBigToHostInt32( info->fBuf[2] );
UInt32 maxPackLog = ((bib_quad & kFWBIBMaxRec) >> kFWBIBMaxRecPhase) + 1;
if( maxPackLog == 1 )
{
IOLog("Illegal maxrec, using 512 bytes\n");
maxPackLog = 9;
}
if( bib_quad & kFWBIBGeneration )
{
if(((bib_quad & kFWBIBMaxROM) >> kFWBIBMaxROMPhase) == 2)
fMaxReadROMPackLog = 10; else
fMaxReadROMPackLog = 2; }
else
fMaxReadROMPackLog = maxPackLog;
fMaxReadPackLog = maxPackLog;
fMaxWritePackLog = maxPackLog;
}
else {
fMaxReadROMPackLog = 2;
fMaxReadPackLog = 2;
fMaxWritePackLog = 2;
}
fROMLock = IORecursiveLockAlloc();
return fROMLock != NULL;
}
IOFireWireNubAux * IOFireWireDevice::createAuxiliary( void )
{
IOFireWireDeviceAux * auxiliary;
auxiliary = OSTypeAlloc( IOFireWireDeviceAux );
if( auxiliary != NULL && !auxiliary->init(this) )
{
auxiliary->release();
auxiliary = NULL;
}
return auxiliary;
}
void IOFireWireDevice::terminateDevice(void *refcon)
{
IOFireWireDevice *me = (IOFireWireDevice *)refcon;
me->fControl->closeGate();
me->lockForArbitration();
if( me->fNodeID == kFWBadNodeID && !me->isInactive() && !me->isOpen() )
{
if( me->fDeviceROM )
{
me->fDeviceROM->setROMState( IOFireWireROMCache::kROMStateInvalid );
}
me->unlockForArbitration();
me->terminate();
}
else
{
me->unlockForArbitration();
}
me->fControl->openGate();
}
void IOFireWireDevice::free()
{
FWKLOG(( "IOFireWireDevice@%p::free()\n", this ));
if( fDeviceROM )
{
fDeviceROM->setROMState( IOFireWireROMCache::kROMStateInvalid );
fDeviceROM->release();
fDeviceROM = NULL;
}
if(fROMLock)
{
IORecursiveLockFree(fROMLock);
}
if ( fControl )
{
fControl->release();
fControl = NULL;
}
IOFireWireNub::free();
}
bool IOFireWireDevice::attach(IOService *provider)
{
char location[17];
assert(OSDynamicCast(IOFireWireController, provider));
if( !IOFireWireNub::attach(provider))
return (false);
fControl = (IOFireWireController *)provider;
fControl->retain();
snprintf(location, sizeof(location), "%x%08x", (uint32_t)(fUniqueID >> 32), (uint32_t)(fUniqueID & 0xffffffff));
setLocation(location);
IOService *parent = provider;
while(parent) {
if(parent->inPlane(gIODTPlane))
break;
parent = parent->getProvider();
}
if(parent) {
attachToParent(parent, gIODTPlane);
setName("node", gIODTPlane);
}
return(true);
}
bool IOFireWireDevice::finalize( IOOptionBits options )
{
if(fDeviceROM)
fDeviceROM->setROMState( IOFireWireROMCache::kROMStateInvalid );
if(fDirectory) {
fDirectory->release();
fDirectory = NULL;
}
detachAll(gIODTPlane);
return IOFireWireNub::finalize(options);
}
#pragma mark -
void IOFireWireDevice::setNodeROM(UInt32 gen, UInt16 localID, const IOFWNodeScan *info)
{
FWTrace( kFWTDevice, kTPDeviceSetNodeROM, (uintptr_t)(fControl->getLink()), localID, 0, 0);
OSObject *prop;
IOFireWireROMCache * rom;
fLocalNodeID = localID;
fGeneration = gen;
if( info )
{
fNodeID = info->fAddr.nodeID;
}
else
{
if( fNodeID != kFWBadNodeID )
{
latchResumeTime();
}
fNodeID = kFWBadNodeID;
}
FWKLOG(( "IOFireWireDevice@%p::setNodeROM entered with nodeID = 0x%04x\n", this, fNodeID ));
prop = OSNumber::withNumber( fNodeID, 16 );
setProperty( gFireWireNodeID, prop );
prop->release();
if( fNodeID != kFWBadNodeID )
{
configureNode(); }
if( !info )
{
fDeviceROM->setROMState( IOFireWireROMCache::kROMStateSuspended );
FWTrace( kFWTDevice, kTPDeviceSetNodeROM, (uintptr_t)(fControl->getLink()), localID, 0, 1);
messageClients( kIOMessageServiceIsSuspended );
return; }
prop = OSData::withBytes( info->fSelfIDs, info->fNumSelfIDs*sizeof(UInt32) );
setProperty( gFireWireSelfIDs, prop );
prop->release();
UInt32 newROMSize = info->fROMSize;
bool rom_changed = true;
if( fDeviceROM != NULL )
{
rom_changed = fDeviceROM->hasROMChanged( info->fBuf, newROMSize );
}
if( !rom_changed )
{
FWTrace( kFWTDevice, kTPDeviceSetNodeROM, (uintptr_t)(fControl->getLink()), localID, 0, 2);
fDeviceROM->setROMState( IOFireWireROMCache::kROMStateResumed, fGeneration );
messageClients( kIOMessageServiceIsResumed );
#if IOFIREWIREDEBUG > 0
IOLog("IOFireWireDevice, ROM unchanged 0x%p\n", this);
#endif
FWKLOG(( "IOFireWireDevice@%p::setNodeROM exited - ROM unchanged\n", this ));
return; }
fROMGeneration++;
if( fRegistrationState == kDeviceNotRegistered )
{
setRegistrationState( kDeviceNeedsRegisterService );
adjustBusy( 1 );
}
if( newROMSize > 12 )
{
UInt32 bib_quad = OSSwapBigToHostInt32( info->fBuf[3] );
UInt32 vendorID = bib_quad >> 8;
prop = OSNumber::withNumber( vendorID, 32 );
setProperty( gFireWireVendor_ID, prop );
prop->release();
}
rom = IOFireWireROMCache::withOwnerAndBytes( this, info->fBuf, newROMSize, fGeneration );
setProperty( gFireWireROM, rom );
if( fDeviceROM )
{
fDeviceROM->setROMState( IOFireWireROMCache::kROMStateInvalid );
fDeviceROM->release();
}
fDeviceROM = rom;
if( newROMSize == 20 )
{
RomScan *romScan = (RomScan *)IOMalloc( sizeof(RomScan) );
if( romScan )
{
romScan->fROMGeneration = fROMGeneration;
romScan->fDevice = this;
retain();
thread_t thread;
FWTrace( kFWTDevice, kTPDeviceSetNodeROM, (uintptr_t)(fControl->getLink()), localID, (uintptr_t)thread, 3);
if( kernel_thread_start((thread_continue_t)readROMThreadFunc, romScan, &thread) == KERN_SUCCESS )
{
thread_deallocate(thread);
}
}
}
else
{
if( fRegistrationState == kDeviceNeedsRegisterService )
{
setRegistrationState( kDeviceNotRegistered );
adjustBusy( -1 );
}
}
FWKLOG(( "IOFireWireDevice@%p::setNodeROM exited\n", this ));
}
void IOFireWireDevice::readROMDirGlue(void *refcon, IOReturn status,
IOFireWireNub *nub, IOFWCommand *fwCmd)
{
}
void IOFireWireDevice::readROMThreadFunc( void *refcon )
{
RomScan * romScan = (RomScan *)refcon;
IOFireWireDevice * device = romScan->fDevice;
IORecursiveLockLock(device->fROMLock);
device->processROM( romScan );
IORecursiveLockUnlock(device->fROMLock);
IOFree(romScan, sizeof(RomScan));
device->release();
}
void IOFireWireDevice::processROM( RomScan *romScan )
{
FWTrace( kFWTDevice, kTPDeviceProcessROM, (uintptr_t)(fControl->getLink()), (uintptr_t)this, 0, 1);
IOReturn status = kIOReturnSuccess;
IOConfigDirectory * directory = NULL;
IOFireWireROMCache * rom = NULL;
OSSet * unitSet = NULL;
OSDictionary * rootPropTable = NULL;
fControl->closeGate();
rom = fDeviceROM;
rom->retain();
UInt32 generation = fROMGeneration;
fControl->openGate();
FWKLOG(( "IOFireWireDevice@%p::processROM generation %ld entered\n", this, generation ));
if( romScan->fROMGeneration != generation )
{
FWKLOG(( "IOFireWireDevice@%p::processROM generation %ld != romScan->fROMGeneration\n", this, generation ));
status = kIOReturnError;
}
if( status == kIOReturnSuccess )
{
directory = IORemoteConfigDirectory::withOwnerOffset( rom, 5, kConfigRootDirectoryKey );
if( directory == NULL )
{
#if IOFIREWIREDEBUG > 0
IOLog("whoops, no root directory!!\n");
#endif
status = kIOReturnNoMemory;
}
}
if( status == kIOReturnSuccess )
{
rootPropTable = OSDictionary::withCapacity(7);
if( rootPropTable == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = readRootDirectory( directory, rootPropTable );
}
if( status == kIOReturnSuccess )
{
unitSet = OSSet::withCapacity(2);
if( unitSet == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = readUnitDirectories( directory, unitSet );
}
if( status == kIOReturnSuccess )
{
preprocessDirectories( rootPropTable, unitSet );
}
if( status == kIOReturnSuccess )
{
fControl->closeGate();
RegistrationState registrationState = fRegistrationState;
status = setConfigDirectory( directory );
FWKLOGASSERT( status == kIOReturnSuccess );
status = processRootDirectory( rootPropTable );
FWKLOGASSERT( status == kIOReturnSuccess );
status = processUnitDirectories( unitSet );
FWKLOGASSERT( status == kIOReturnSuccess );
if( registrationState == kDeviceNeedsRegisterService )
{
adjustBusy( -1 );
}
messageClients( kIOMessageServiceIsResumed );
fControl->openGate();
}
if( (status != kIOReturnSuccess) && (status != kIOFireWireBusReset) )
{
fControl->closeGate();
if( fROMReadRetry > 0 )
{
fROMReadRetry--;
FWTrace( kFWTDevice, kTPDeviceProcessROM, (uintptr_t)(fControl->getLink()), (uintptr_t)this, 0, 2);
fControl->resetBus();
}
else
{
if( fRegistrationState == kDeviceNeedsRegisterService )
{
setRegistrationState( kDeviceNotRegistered );
adjustBusy( -1 );
}
}
fControl->openGate();
}
if( unitSet != NULL )
{
unitSet->release();
}
if( rootPropTable != NULL )
{
rootPropTable->release();
}
if( directory != NULL )
{
directory->release();
}
if( rom != NULL )
{
rom->release();
}
FWKLOG(( "IOFireWireDevice@%p::processROM generation %ld exited\n", this, generation ));
}
void IOFireWireDevice::preprocessDirectories( OSDictionary * rootPropTable, OSSet * unitSet )
{
OSObject * modelNameProperty = rootPropTable->getObject( gFireWireProduct_Name );
OSObject * vendorNameProperty = rootPropTable->getObject( gFireWireVendor_Name );
OSObject * modelIDProperty = rootPropTable->getObject( gFireWireModel_ID );
OSIterator * iterator = OSCollectionIterator::withCollection( unitSet );
iterator->reset();
IOFireWireUnitInfo * info = NULL;
while( (info = (IOFireWireUnitInfo *) iterator->getNextObject()) )
{
OSDictionary * propTable = info->getPropTable();
OSObject * unitModelNameProperty = propTable->getObject( gFireWireProduct_Name );
if( unitModelNameProperty == NULL && modelNameProperty != NULL )
{
propTable->setObject( gFireWireProduct_Name, modelNameProperty );
}
OSObject * unitModelIDProperty = propTable->getObject( gFireWireModel_ID );
if( unitModelIDProperty == NULL && modelIDProperty != NULL )
{
propTable->setObject( gFireWireModel_ID, modelIDProperty );
}
if( vendorNameProperty )
{
propTable->setObject( gFireWireVendor_Name, vendorNameProperty );
}
if ( vendorNameProperty == NULL || modelIDProperty == NULL )
{
IOConfigDirectory * unit = info->getDirectory();
IOReturn error = kIOReturnSuccess;
UInt32 unitSpecID = 0;
UInt32 unitSWVers = 0;
IOConfigDirectory * unitdep;
error = unit->getKeyValue( kConfigUnitSpecIdKey, unitSpecID );
error |= unit->getKeyValue( kConfigUnitSwVersionKey, unitSWVers );
error |= unit->getKeyValue( kConfigUnitDependentInfoKey, unitdep );
if( error == kIOReturnSuccess && unitSpecID == kConfigUnitSpec1394TA1 )
{
if ( unitSWVers == kConfigUnitSWVersIIDC100
|| unitSWVers == kConfigUnitSWVersIIDC101
|| unitSWVers == kConfigUnitSWVersIIDC102 )
{
if ( vendorNameProperty == NULL )
{
OSData * iidcVendorData = NULL;
error = unitdep->getKeyValue( 1, iidcVendorData, NULL);
OSString * iidcVendorString = NULL;
if ( !error && iidcVendorData )
{
iidcVendorData->appendBytes( 0, 1 );
UInt32 * leaf = (UInt32 *)(iidcVendorData->getBytesNoCopy());
UInt32 len = iidcVendorData->getLength() - 8;
if ( len <= 256 && leaf ) {
char * text = (char *)(&leaf[2]);
while( len && !*text)
{
len--;
text++;
}
if ( len > 0 && text[len] == 0 )
iidcVendorString = OSString::withCString( text );
}
if( iidcVendorString )
{
rootPropTable->setObject( gFireWireVendor_Name, iidcVendorString );
iidcVendorString->release();
}
iidcVendorData->release();
}
}
if ( modelIDProperty == NULL )
{
OSData * iidcModelData = NULL;
error = unitdep->getKeyValue( 2, iidcModelData, NULL);
OSString * iidcModelString = NULL;
if ( !error && iidcModelData )
{
iidcModelData->appendBytes( 0, 1 );
UInt32 * leaf = (UInt32 *)(iidcModelData->getBytesNoCopy());
UInt32 len = iidcModelData->getLength() - 8;
if ( len <= 256 ) {
char * text = (char *)(&leaf[2]);
while( len && !*text)
{
len--;
text++;
}
if ( len > 0 && text[len] == 0 )
iidcModelString = OSString::withCString( text );
}
if( iidcModelString )
{
rootPropTable->setObject( gFireWireProduct_Name, iidcModelString );
iidcModelString->release();
}
iidcModelData->release();
}
}
}
}
}
UInt32 modelID = 0;
UInt32 modelVendorID = 0;
{
OSNumber * prop = (OSNumber*)rootPropTable->getObject( gFireWireModel_ID );
if( prop )
{
modelID = prop->unsigned32BitValue();
}
}
{
OSNumber * prop = (OSNumber*)rootPropTable->getObject( gFireWireVendor_ID );
if( prop )
{
modelVendorID = prop->unsigned32BitValue();
}
}
UInt32 sbp2_revision = info->getSBP2Revision();
UInt32 sbp2_lun = info->getSBP2LUN();
UInt32 sbp2_mao = info->getSBP2MAO();
if( (modelVendorID == 0x000a27) && (modelID == 0x54444d) )
{
if( ((sbp2_lun & 0x0000ffff) == 0) && (sbp2_revision == 0xffffffff) &&
((sbp2_mao == 0x004000) || (sbp2_mao == 0x00c000)) )
{
rootPropTable->setObject( gFireWireTDM, OSString::withCString("PPC") );
}
}
}
iterator->release();
}
IOReturn IOFireWireDevice::readRootDirectory( IOConfigDirectory * directory, OSDictionary * propTable )
{
IOReturn status = kIOReturnSuccess;
UInt32 modelID = 0;
bool modelIDPresent = false;
OSString * modelName = NULL;
OSString * vendorName = NULL;
FWKLOG(( "IOFireWireDevice@%p::readRootDirectory entered\n", this ));
if( status == kIOReturnSuccess )
{
IOReturn result = kIOReturnSuccess;
UInt32 vendorID = 0;
result = directory->getKeyValue( kConfigModuleVendorIdKey, vendorID, &vendorName );
if( result == kIOFireWireConfigROMInvalid )
status = result;
if(result == kIOReturnSuccess) {
OSNumber *num = OSNumber::withNumber(vendorID, 32);
if(num) {
propTable->setObject( gFireWireVendor_ID, num);
num->release();
}
}
}
if( status == kIOReturnSuccess )
{
IOReturn result = kIOReturnSuccess;
result = directory->getKeyValue( kConfigModelIdKey, modelID, &modelName );
if( result == kIOFireWireConfigROMInvalid )
status = result;
if( result == kIOReturnSuccess )
modelIDPresent = true;
}
if( status == kIOReturnSuccess )
{
IOReturn result = kIOReturnSuccess;
OSString * t = NULL;
IOConfigDirectory * unit = NULL;
result = directory->getKeyValue( kConfigModuleVendorIdKey, unit, &t );
if( result == kIOFireWireConfigROMInvalid )
status = result;
if( result == kIOReturnSuccess && t != NULL )
{
if( vendorName )
vendorName->release();
vendorName = t;
t = NULL;
}
if( result == kIOReturnSuccess )
{
result = unit->getKeyValue( kConfigModelIdKey, modelID, &t );
if( result == kIOFireWireConfigROMInvalid )
status = result;
if( result == kIOReturnSuccess )
modelIDPresent = true;
if( result == kIOReturnSuccess && t != NULL )
{
if( modelName )
modelName->release();
modelName = t;
t = NULL;
}
unit->release();
}
}
if( modelName != NULL )
{
if( status == kIOReturnSuccess )
propTable->setObject( gFireWireProduct_Name, modelName );
modelName->release();
}
if( modelIDPresent )
{
if( status == kIOReturnSuccess )
{
OSObject *prop = OSNumber::withNumber(modelID, 32);
propTable->setObject(gFireWireModel_ID, prop);
prop->release();
}
}
if( vendorName != NULL )
{
if( status == kIOReturnSuccess )
propTable->setObject( gFireWireVendor_Name, vendorName );
vendorName->release();
}
FWKLOG(( "IOFireWireDevice@%p::readRootDirectory returned status = 0x%08lx\n", this, (UInt32)status ));
return status;
}
IOReturn IOFireWireDevice::processRootDirectory( OSDictionary * propTable )
{
IOReturn status = kIOReturnSuccess;
OSSymbol * key = NULL;
OSObject * property = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( propTable );
while( NULL != (key = OSDynamicCast(OSSymbol, iterator->getNextObject())) )
{
property = propTable->getObject( key );
setProperty( key, property );
}
iterator->release();
if( fRegistrationState == kDeviceNeedsRegisterService )
{
setRegistrationState( kDeviceRegistered );
registerService();
}
return status;
}
IOReturn IOFireWireDevice::readUnitDirectories( IOConfigDirectory * directory, OSSet * unitInfo )
{
IOReturn status = kIOReturnSuccess;
OSIterator * unitDirs = NULL;
OSString * modelName = NULL;
FWKLOG(( "IOFireWireDevice@%p::readUnitDirectory entered\n", this ));
if( status == kIOReturnSuccess )
{
IOReturn result = kIOReturnSuccess;
result = directory->getKeySubdirectories( kConfigUnitDirectoryKey, unitDirs );
if( result == kIOFireWireConfigROMInvalid )
status = result;
if( result == kIOReturnSuccess )
{
IOConfigDirectory * unit = NULL;
while( (unit = OSDynamicCast(IOConfigDirectory, unitDirs->getNextObject())) )
{
UInt32 unitSpecID = 0;
UInt32 unitSoftwareVersion = 0;
UInt32 modelID = 0;
bool modelIDPresent = false;
OSString * t = NULL;
UInt32 sbp2_revision = 0xffffffff;
UInt32 sbp2_lun = 0xffffffff;
UInt32 sbp2_mao = 0xffffffff;
result = unit->getKeyValue(kConfigUnitSpecIdKey, unitSpecID);
if( result == kIOReturnSuccess )
result = unit->getKeyValue(kConfigUnitSwVersionKey, unitSoftwareVersion);
if( result == kIOReturnSuccess )
result = unit->getKeyValue(kConfigModelIdKey, modelID, &t);
if( result == kIOReturnSuccess )
modelIDPresent = true;
if( result == kIOFireWireConfigROMInvalid )
status = result;
if( result == kIOReturnSuccess && t != NULL )
{
if( modelName )
modelName->release();
modelName = t;
t = NULL;
}
if( status == kIOReturnSuccess )
{
result = unit->getKeyValue( kConfigSBP2LUN, sbp2_lun );
if( result == kIOFireWireConfigROMInvalid )
status = result;
}
if( status == kIOReturnSuccess )
{
result = unit->getKeyValue( kConfigSBP2Revision, sbp2_revision );
if( result == kIOFireWireConfigROMInvalid )
status = result;
}
if( status == kIOReturnSuccess )
{
result = unit->getKeyValue( kConfigSBP2MAO, sbp2_mao );
if( result == kIOFireWireConfigROMInvalid )
status = result;
}
if( status == kIOReturnSuccess )
{
OSDictionary * propTable = 0;
do
{
OSObject * prop;
propTable = OSDictionary::withCapacity(7);
if( !propTable )
continue;
prop = OSString::withCString("FireWire Unit");
propTable->setObject(gIOMatchCategoryKey, prop);
prop->release();
if( modelName )
propTable->setObject(gFireWireProduct_Name, modelName);
if( modelIDPresent )
{
prop = OSNumber::withNumber(modelID, 32);
propTable->setObject(gFireWireModel_ID, prop);
prop->release();
}
prop = OSNumber::withNumber(unitSpecID, 32);
propTable->setObject(gFireWireUnit_Spec_ID, prop);
prop->release();
prop = OSNumber::withNumber(unitSoftwareVersion, 32);
propTable->setObject(gFireWireUnit_SW_Version, prop);
prop->release();
prop = getProperty(gFireWireVendor_ID);
if( prop )
propTable->setObject(gFireWireVendor_ID, prop);
prop = getProperty(gFireWire_GUID);
if( prop )
propTable->setObject(gFireWire_GUID, prop);
IOFireWireUnitInfo * info = IOFireWireUnitInfo::create();
info->setDirectory( unit );
info->setPropTable( propTable );
info->setSBP2Revision( sbp2_revision );
info->setSBP2LUN( sbp2_lun );
info->setSBP2MAO( sbp2_mao );
unitInfo->setObject( info );
info->release();
} while( false );
if( propTable != NULL )
propTable->release();
}
if( modelName != NULL )
{
modelName->release();
modelName = NULL;
}
}
unitDirs->release();
}
}
FWKLOG(( "IOFireWireDevice@%p::readUnitDirectory returned status = 0x%08lx\n", this, (UInt32)status ));
return status;
}
IOReturn IOFireWireDevice::processUnitDirectories( OSSet * unitSet )
{
IOReturn status = kIOReturnSuccess;
OSIterator * iterator = NULL;
OSIterator * clientIterator = NULL;
OSSet * clientSet = NULL;
OSObject * client = NULL;
if( status == kIOReturnSuccess )
{
clientSet = OSSet::withCapacity(2);
if( clientSet == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
clientIterator = getClientIterator();
if( clientIterator == NULL )
status = kIOReturnError;
}
if( status == kIOReturnSuccess )
{
clientIterator->reset();
while( (client = clientIterator->getNextObject()) )
{
clientSet->setObject( client );
}
clientIterator->release();
}
if( status == kIOReturnSuccess )
{
clientIterator = OSCollectionIterator::withCollection( clientSet );
if( clientIterator == NULL )
status = kIOReturnError;
}
if( status == kIOReturnSuccess )
{
UInt32 count = unitSet->getCount();
setUnitCount( count );
iterator = OSCollectionIterator::withCollection( unitSet );
iterator->reset();
IOFireWireUnitInfo * info = NULL;
while( (info = (IOFireWireUnitInfo *) iterator->getNextObject()) )
{
IOFireWireUnit * newDevice = 0;
OSDictionary * propTable = info->getPropTable();
IOConfigDirectory * unit = info->getDirectory();
do
{
IOFireWireUnit * found = NULL;
clientIterator->reset();
while( (client = clientIterator->getNextObject()) )
{
found = OSDynamicCast(IOFireWireUnit, client);
if( found )
{
found->lockForArbitration();
if( (found->getTerminationState() != kTerminated) && found->matchPropertyTable(propTable) )
{
break;
}
else
{
found->unlockForArbitration();
found = NULL;
}
}
}
if( found )
{
if( found->getTerminationState() == kNeedsTermination )
{
found->setTerminationState( kNotTerminated );
}
found->unlockForArbitration();
FWTrace( kFWTDevice, kTPDeviceProcessUnitDirectories, (uintptr_t)(fControl->getLink()), (uintptr_t)this, (uintptr_t)found, 1 );
found->setConfigDirectory( unit );
clientSet->removeObject( found );
break;
}
newDevice = OSTypeAlloc( IOFireWireUnit );
if (!newDevice || !newDevice->init(propTable, unit))
break;
newDevice->setMaxPackLog(true, false, fMaxWritePackLog);
newDevice->setMaxPackLog(false, false, fMaxReadPackLog);
newDevice->setMaxPackLog(false, true, fMaxReadROMPackLog);
FWTrace( kFWTDevice, kTPDeviceProcessUnitDirectories, (uintptr_t)(fControl->getLink()), (uintptr_t)this, (uintptr_t)newDevice, 2 );
if (!newDevice->attach(this))
break;
newDevice->registerService();
}
while( false );
if( newDevice != NULL )
{
newDevice->release();
newDevice = NULL;
}
}
}
if( iterator != NULL )
{
iterator->release();
}
if( status == kIOReturnSuccess )
{
clientIterator->reset();
while( (client = clientIterator->getNextObject()) )
{
IOFireWireUnit * unit;
unit = OSDynamicCast(IOFireWireUnit, client);
if( unit )
{
FWTrace( kFWTDevice, kTPDeviceProcessUnitDirectories, (uintptr_t)(fControl->getLink()), (uintptr_t)this, (uintptr_t)unit, 3 );
unit->terminateUnit();
}
}
}
if( clientIterator != NULL )
{
clientIterator->release();
}
if( clientSet != NULL )
{
clientSet->release();
}
return status;
}
IOReturn IOFireWireDevice::cacheROM(OSData *rom, UInt32 offset, const UInt32 *&romBase)
{
return kIOReturnError;
}
const UInt32 * IOFireWireDevice::getROMBase()
{
return (const UInt32 *)fDeviceROM->getBytesNoCopy();
}
void IOFireWireDevice::setRegistrationState( RegistrationState state )
{
fRegistrationState = state;
}
bool IOFireWireDevice::matchPropertyTable(OSDictionary * table)
{
if (!IOFireWireNub::matchPropertyTable(table)) return false;
return compareProperty(table, gFireWireVendor_ID) &&
compareProperty(table, gFireWire_GUID);
}
#pragma mark -
IOReturn IOFireWireDevice::message( UInt32 mess, IOService * provider,
void * argument )
{
if( kIOFWMessageServiceIsRequestingClose == mess )
{
fDeviceROM->setROMState( IOFireWireROMCache::kROMStateInvalid ) ;
messageClients( mess );
return kIOReturnSuccess;
}
if( kIOFWMessagePowerStateChanged == mess )
{
messageClients( mess );
return kIOReturnSuccess;
}
if( kIOFWMessageTopologyChanged == mess )
{
messageClients( mess );
return kIOReturnSuccess;
}
return IOService::message(mess, provider, argument );
}
#pragma mark -
bool IOFireWireDevice::handleOpen( IOService * forClient, IOOptionBits options, void * arg )
{
bool ok = true;
IOFireWireUnit * unitClient = OSDynamicCast( IOFireWireUnit, forClient );
if( unitClient != NULL )
{
if( fOpenFromDevice )
return false;
OSSet * open_set = getOpenUnitSet();
if( !open_set->containsObject( forClient ) )
{
if( open_set->getCount() == 0 )
{
ok = IOService::handleOpen( this, options, arg );
}
if( ok )
{
open_set->setObject( forClient );
}
}
}
else
{
OSSet * open_set = getOpenUnitSet();
if( open_set->getCount() != 0 )
return false;
if( !fOpenFromDevice ) {
ok = IOService::handleOpen( forClient, options, arg );
if( ok )
{
fOpenFromDevice = true;
}
}
else
{
ok = false; }
}
return ok;
}
void IOFireWireDevice::handleClose( IOService * forClient, IOOptionBits options )
{
IOFireWireUnit * unitClient = OSDynamicCast( IOFireWireUnit, forClient );
if( unitClient != NULL )
{
OSSet * open_set = getOpenUnitSet();
if( open_set->containsObject( forClient ) )
{
open_set->removeObject( forClient );
if( open_set->getCount() == 0 )
{
IOService::handleClose( this, options );
if( getTerminationState() == kNeedsTermination )
{
setTerminationState( kTerminated );
thread_t thread;
if( kernel_thread_start((thread_continue_t)terminateDevice, this, &thread) == KERN_SUCCESS )
{
thread_deallocate(thread);
}
}
}
}
}
else
{
if( fOpenFromDevice )
{
fOpenFromDevice = false;
IOService::handleClose( forClient, options );
if( getTerminationState() == kNeedsTermination )
{
setTerminationState( kTerminated );
thread_t thread;
if( kernel_thread_start((thread_continue_t)terminateDevice, this, &thread) == KERN_SUCCESS )
{
thread_deallocate(thread);
}
}
}
}
}
bool IOFireWireDevice::handleIsOpen( const IOService * forClient ) const
{
OSSet * open_set = getOpenUnitSet();
if( forClient == NULL )
{
return ((open_set->getCount() != 0) || fOpenFromDevice);
}
if( open_set->getCount() != 0 )
{
return open_set->containsObject( forClient );
}
if( fOpenFromDevice )
{
return IOService::handleIsOpen( forClient );
}
return false;
}
#pragma mark -
void IOFireWireDevice::setNodeFlags( UInt32 flags )
{
fControl->closeGate();
fNodeFlags |= flags;
configureNode();
fControl->openGate();
}
void IOFireWireDevice::clearNodeFlags( UInt32 flags )
{
fControl->closeGate();
fNodeFlags &= ~flags;
configureNode();
fControl->openGate();
}
UInt32 IOFireWireDevice::getNodeFlags( void )
{
return fNodeFlags;
}
IOReturn IOFireWireDevice::configureNode( void )
{
fControl->closeGate();
if( fNodeID != kFWBadNodeID )
{
configurePhysicalFilter();
if( fNodeFlags & kIOFWEnableRetryOnAckD )
{
IOFireWireLink * fwim = fControl->getLink();
fwim->setNodeFlags( fNodeID & 0x3f, kIOFWNodeFlagRetryOnAckD );
}
IOFWSpeed currentSpeed = FWSpeed();
IOFWSpeed maxSpeed = ((IOFireWireDeviceAux*)fAuxiliary)->fMaxSpeed;
if( currentSpeed > maxSpeed )
{
fControl->setNodeSpeed( fNodeID, maxSpeed );
}
if( fNodeFlags & kIOFWLimitAsyncPacketSize )
{
fControl->useHalfSizePackets();
}
if( fNodeFlags & kIOFWMustBeRoot )
{
fControl->nodeMustBeRoot( fNodeID );
}
if( fNodeFlags & kIOFWMustNotBeRoot )
{
fControl->nodeMustNotBeRoot( fNodeID );
}
if( fNodeFlags & kIOFWMustHaveGap63 )
{
fControl->setGapCount(63);
}
if( fNodeFlags & kIOFWDisablePhyOnSleep && (hopCount() == 1) )
{
fControl->disablePhyPortOnSleepForNodeID( fNodeID & 0x3f );
}
}
fControl->openGate();
return kIOReturnSuccess;
}
void IOFireWireDevice::configurePhysicalFilter( void )
{
if( fNodeID != kFWBadNodeID )
{
if( fNodeFlags & kIOFWDisableAllPhysicalAccess )
{
fControl->setPhysicalAccessMode( kIOFWPhysicalAccessDisabledForGeneration );
}
if( (fNodeFlags & kIOFWDisablePhysicalAccess) )
{
fControl->setNodeIDPhysicalFilter( fNodeID & 0x3f, false );
}
else
{
fControl->setNodeIDPhysicalFilter( fNodeID & 0x3f, true );
}
}
}
#pragma mark -
IOFWPhysicalAddressSpace * IOFireWireDevice::createPhysicalAddressSpace(IOMemoryDescriptor *mem)
{
IOFWPhysicalAddressSpace * space = fControl->createPhysicalAddressSpace(mem);
if( space != NULL )
{
space->addTrustedNode( this );
}
return space;
}
IOFWPseudoAddressSpace * IOFireWireDevice::createPseudoAddressSpace(FWAddress *addr, UInt32 len,
FWReadCallback reader, FWWriteCallback writer, void *refcon)
{
IOFWPseudoAddressSpace * space = fControl->createPseudoAddressSpace(addr, len, reader, writer, refcon);
if( space != NULL )
{
space->addTrustedNode( this );
}
return space;
}