IOFireWireController.cpp [plain text]
#import <IOKit/firewire/IOFWUtils.h>
#import <IOKit/firewire/IOFireWireController.h>
#import <IOKit/firewire/IOLocalConfigDirectory.h>
#import <IOKit/firewire/IOFireWireNub.h>
#import <IOKit/firewire/IOFireWireDevice.h>
#import <IOKit/firewire/IOFWLocalIsochPort.h>
#import <IOKit/firewire/IOFWDCLProgram.h>
#import <IOKit/firewire/IOFireWirePowerManager.h>
#import <IOKit/firewire/IOFWWorkLoop.h>
#import <IOKit/firewire/IOFireWireLink.h>
#import "FWDebugging.h"
#import "IOFireWireLocalNode.h"
#import "IOFWQEventSource.h"
#import "IOFireWireIRM.h"
#if FIRELOGCORE
#import "IOFireLogPriv.h"
#endif
#import <IOKit/IOKitKeys.h>
#import <IOKit/IOBufferMemoryDescriptor.h>
#import <IOKit/IODeviceTreeSupport.h>
#import <IOKit/IOMessage.h>
#import <IOKit/IOTimerEventSource.h>
#define kScanBusDelay 100
#define kBusResetTimeout 1000
#define kSelfIDTimeout 1000
#define kNormalDevicePruneDelay 1000
#define kRepeatResetDelay 2000
#define kOnlyNodeDevicePruneDelay 3000
#define kWakeDevicePruneDelay 15000
#define kFireWireGenerationID "FireWire Generation ID"
#define kFWBusScanInProgress "-1"
#define FWAddressToID(addr) (addr & 63)
enum requestRefConBits
{
kRequestLabel = kFWAsynchTTotal-1, kRequestExtTCodeShift = 6,
kRequestExtTCodeMask = 0x3fffc0, kRequestIsComplete = 0x20000000, kRequestIsLock = 0x40000000,
kRequestIsQuad = 0x80000000
};
const OSSymbol *gFireWireROM;
const OSSymbol *gFireWireNodeID;
const OSSymbol *gFireWireSelfIDs;
const OSSymbol *gFireWireUnit_Spec_ID;
const OSSymbol *gFireWireUnit_SW_Version;
const OSSymbol *gFireWireVendor_ID;
const OSSymbol *gFireWire_GUID;
const OSSymbol *gFireWireSpeed;
const OSSymbol *gFireWireVendor_Name;
const OSSymbol *gFireWireProduct_Name;
const OSSymbol *gFireWireModel_ID;
const IORegistryPlane * IOFireWireBus::gIOFireWirePlane = NULL;
#define number_of_power_states 2
static IOPMPowerState ourPowerStates[number_of_power_states] =
{
{1,0,0,0,0,0,0,0,0,0,0,0},
{1,IOPMDeviceUsable,IOPMPowerOn,IOPMPowerOn,0,0,0,0,0,0,0,0}
};
OSDefineMetaClassAndStructors(IOFireWireControllerAux, IOFireWireBusAux);
OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 0);
OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 1);
OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 2);
OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 3);
OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 4);
OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 5);
OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 6);
OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 7);
#pragma mark -
bool IOFireWireControllerAux::init( IOFireWireController * primary )
{
bool success = true;
success = IOFireWireBusAux::init();
fPrimary = primary;
return success;
}
void IOFireWireControllerAux::free()
{
IOFireWireBusAux::free();
}
IOFWDCLPool *
IOFireWireControllerAux :: createDCLPool ( unsigned capacity ) const
{
return fPrimary->getLink()->createDCLPool( capacity ) ;
}
#pragma mark -
OSDefineMetaClassAndStructors( IOFireWireController, IOFireWireBus )
OSMetaClassDefineReservedUnused(IOFireWireController, 0);
OSMetaClassDefineReservedUnused(IOFireWireController, 1);
OSMetaClassDefineReservedUnused(IOFireWireController, 2);
OSMetaClassDefineReservedUnused(IOFireWireController, 3);
OSMetaClassDefineReservedUnused(IOFireWireController, 4);
OSMetaClassDefineReservedUnused(IOFireWireController, 5);
OSMetaClassDefineReservedUnused(IOFireWireController, 6);
OSMetaClassDefineReservedUnused(IOFireWireController, 7);
OSMetaClassDefineReservedUnused(IOFireWireController, 8);
#pragma mark -
bool IOFireWireController::init( IOFireWireLink *fwim )
{
if( !IOFireWireBus::init() )
return false;
fAuxiliary = createAuxiliary();
if( fAuxiliary == NULL )
return false;
fFWIM = fwim;
gFireWireROM = OSSymbol::withCString("FireWire Device ROM");
gFireWireNodeID = OSSymbol::withCString("FireWire Node ID");
gFireWireSelfIDs = OSSymbol::withCString("FireWire Self IDs");
gFireWireUnit_Spec_ID = OSSymbol::withCString("Unit_Spec_ID");
gFireWireUnit_SW_Version = OSSymbol::withCString("Unit_SW_Version");
gFireWireVendor_ID = OSSymbol::withCString("Vendor_ID");
gFireWire_GUID = OSSymbol::withCString("GUID");
gFireWireSpeed = OSSymbol::withCString("FireWire Speed");
gFireWireVendor_Name = OSSymbol::withCString("FireWire Vendor Name");
gFireWireProduct_Name = OSSymbol::withCString("FireWire Product Name");
gFireWireModel_ID = OSSymbol::withCString("Model_ID");
if(NULL == gIOFireWirePlane)
{
gIOFireWirePlane = IORegistryEntry::makePlane( kIOFireWirePlane );
}
fLocalAddresses = OSSet::withCapacity(5); if(fLocalAddresses)
fSpaceIterator = OSCollectionIterator::withCollection(fLocalAddresses);
fAllocatedChannels = OSSet::withCapacity(1); if(fAllocatedChannels)
fAllocChannelIterator = OSCollectionIterator::withCollection(fAllocatedChannels);
fLastTrans = kMaxPendingTransfers-1;
fDevicePruneDelay = kNormalDevicePruneDelay;
UInt32 bad = 0xdeadbabe;
fBadReadResponse = IOBufferMemoryDescriptor::withBytes(&bad, sizeof(bad), kIODirectionOutIn);
fDelayedStateChangeCmdNeedAbort = false;
fDelayedStateChangeCmd = createDelayedCmd(1000 * kScanBusDelay, delayedStateChange, NULL);
fBusResetStateChangeCmd = createDelayedCmd(1000 * kRepeatResetDelay, resetStateChange, NULL);
fBusPowerManager = IOFireWirePowerManager::createWithController( this );
if( fBusPowerManager == NULL )
{
IOLog( "IOFireWireController::start - failed to create bus power manager!\n" );
return false;
}
return (gFireWireROM != NULL && gFireWireNodeID != NULL &&
gFireWireUnit_Spec_ID != NULL && gFireWireUnit_SW_Version != NULL &&
fLocalAddresses != NULL && fSpaceIterator != NULL &&
fAllocatedChannels != NULL && fAllocChannelIterator != NULL &&
fBadReadResponse != NULL);
}
IOFireWireBusAux * IOFireWireController::createAuxiliary( void )
{
IOFireWireControllerAux * auxiliary;
auxiliary = new IOFireWireControllerAux;
if( auxiliary != NULL && !auxiliary->init(this) )
{
auxiliary->release();
auxiliary = NULL;
}
return auxiliary;
}
void IOFireWireController::free()
{
if( fIRM != NULL )
{
fIRM->release();
fIRM = NULL;
}
if( fBusPowerManager != NULL )
{
fBusPowerManager->release();
fBusPowerManager = NULL;
}
if( fROMAddrSpace != NULL )
{
fROMAddrSpace->release();
fROMAddrSpace = NULL;
}
if( fRootDir != NULL )
{
fRootDir->release();
fRootDir = NULL;
}
if( fBadReadResponse != NULL )
{
fBadReadResponse->release();
fBadReadResponse = NULL;
}
if( fDelayedStateChangeCmd != NULL )
{
fDelayedStateChangeCmd->release();
fDelayedStateChangeCmd = NULL;
}
if( fBusResetStateChangeCmd != NULL )
{
fBusResetStateChangeCmd->release();
fBusResetStateChangeCmd = NULL;
}
if( fSpaceIterator != NULL )
{
fSpaceIterator->release();
fSpaceIterator = NULL;
}
if( fLocalAddresses != NULL )
{
fLocalAddresses->release();
fLocalAddresses = NULL;
}
if( fAllocChannelIterator != NULL )
{
fAllocChannelIterator->release();
fAllocChannelIterator = NULL;
}
if( fAllocatedChannels != NULL )
{
fAllocatedChannels->release();
fAllocatedChannels = NULL;
}
destroyTimeoutQ();
destroyPendingQ();
if( fWorkLoop != NULL )
{
fWorkLoop->release();
fWorkLoop = NULL;
}
if( fAuxiliary != NULL )
{
fAuxiliary->release();
fAuxiliary = NULL;
}
IOFireWireBus::free();
}
bool IOFireWireController::start(IOService *provider)
{
IOReturn res;
if (!IOService::start(provider))
{
return false;
}
CSRNodeUniqueID guid = fFWIM->getGUID();
IOService *parent = this;
while(parent) {
if(parent->inPlane(gIODTPlane))
break;
parent = parent->getProvider();
}
if(parent) {
IORegistryEntry * child;
IORegistryIterator * children;
children = IORegistryIterator::iterateOver(parent, gIODTPlane);
if ( children != 0 ) {
OSOrderedSet * set = children->iterateAll();
if(set != 0) {
OSIterator *iter = OSCollectionIterator::withCollection(set);
if(iter != 0) {
while ( (child = (IORegistryEntry *)iter->getNextObject()) ) {
child->detachAll(gIODTPlane);
}
iter->release();
}
set->release();
}
children->release();
}
}
fWorkLoop = fFWIM->getFireWireWorkLoop();
fWorkLoop->retain();
createPendingQ();
createTimeoutQ();
initSecurity();
fROMHeader[1] = kFWBIBBusName;
fROMHeader[2] = fFWIM->getBusCharacteristics();
fROMHeader[2] &= ~kFWBIBGeneration;
fMaxRecvLog = ((fROMHeader[2] & kFWBIBMaxRec) >> kFWBIBMaxRecPhase)+1;
fMaxSendLog = fFWIM->getMaxSendLog();
fROMHeader[3] = guid >> 32;
fROMHeader[4] = guid & 0xffffffff;
fRootDir = IOLocalConfigDirectory::create();
if(!fRootDir)
{
return false;
}
fRootDir->addEntry(kConfigGenerationKey, (UInt32)1);
fRootDir->addEntry(kConfigModuleVendorIdKey, 0x000a27, OSString::withCString("Apple Computer, Inc."));
fRootDir->addEntry(kConfigModelIdKey, 10, OSString::withCString("Macintosh"));
fRootDir->addEntry(kConfigNodeCapabilitiesKey, 0x000083C0);
OSData *t = OSData::withBytes(&guid, sizeof(guid));
fRootDir->addEntry(kConfigNodeUniqueIdKey, t);
fTimer->enable();
IOFireWireLocalNode *localNode = new IOFireWireLocalNode;
localNode->setConfigDirectory( fRootDir );
OSDictionary *propTable;
do {
OSObject * prop;
propTable = OSDictionary::withCapacity(8);
if (!propTable)
continue;
prop = OSNumber::withNumber(guid, 8*sizeof(guid));
if(prop) {
propTable->setObject(gFireWire_GUID, prop);
prop->release();
}
localNode->init(propTable);
localNode->attach(this);
localNode->registerService();
} while (false);
if(propTable)
propTable->release();
#if FIRELOGCORE
fFireLogPublisher = IOFireLogPublisher::create( this );
#endif
fIRM = IOFireWireIRM::create(this);
FWPANICASSERT( fIRM != NULL );
fWorkLoop->enableAllInterrupts();
PMinit();
provider->joinPMtree(this);
registerPowerDriver(this, ourPowerStates, number_of_power_states);
res = changePowerStateTo(1);
IOLog("Local FireWire GUID = 0x%lx:0x%lx\n", (UInt32)(guid >> 32), (UInt32)(guid & 0xffffffff));
registerService();
return res == kIOReturnSuccess;
}
void IOFireWireController::stop( IOService * provider )
{
processBusReset();
freeSecurity();
PMstop();
if(fBusState == kAsleep) {
IOReturn sleepRes;
sleepRes = fWorkLoop->wake(&fBusState);
if(sleepRes != kIOReturnSuccess) {
IOLog("IOFireWireController::stop - Can't wake FireWire workloop, error 0x%x\n", sleepRes);
}
openGate();
}
IOService::stop(provider);
}
bool IOFireWireController::finalize( IOOptionBits options )
{
bool res;
#if FIRELOGCORE
if( fFireLogPublisher )
{
fFireLogPublisher->release();
fFireLogPublisher = NULL;
}
#endif
res = IOService::finalize(options);
return res;
}
bool IOFireWireController::requestTerminate( IOService * provider, IOOptionBits options )
{
OSIterator *childIterator;
childIterator = getClientIterator();
if( childIterator )
{
OSObject *child;
while( (child = childIterator->getNextObject()) )
{
IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
if(found && !found->isTerminated() && found->isOpen())
{
messageClient( kIOFWMessageServiceIsRequestingClose, found );
}
}
childIterator->release();
}
IOFireWireLocalNode *localNode = getLocalNode(this);
if(localNode) {
localNode->release();
}
return IOService::requestTerminate(provider, options);
}
IOReturn IOFireWireController::setPowerState( unsigned long powerStateOrdinal,
IOService* whatDevice )
{
IOReturn res;
IOReturn sleepRes;
if( fBusState != kAsleep )
{
closeGate();
}
else
{
sleepRes = fWorkLoop->wake(&fBusState);
if(sleepRes != kIOReturnSuccess)
{
IOLog("Can't wake FireWire workloop, error 0x%x\n", sleepRes);
}
}
if(powerStateOrdinal != 0)
{
fDevicePruneDelay = kWakeDevicePruneDelay;
fBusState = kRunning; if( fDelayedStateChangeCmdNeedAbort )
{
fDelayedStateChangeCmdNeedAbort = false;
fDelayedStateChangeCmd->cancel(kIOReturnAborted);
}
}
if(powerStateOrdinal == 0)
{
fFWIM->setContender(false);
fFWIM->setRootHoldOff(false);
fFWIM->resetBus();
IOSleep(10); }
res = fFWIM->setLinkPowerState(powerStateOrdinal);
if( powerStateOrdinal == 1 && res == IOPMAckImplied )
{
if ( kIOReturnSuccess != UpdateROM() )
IOLog(" %s %u: UpdateROM() got error\n", __FILE__, __LINE__ ) ;
fFWIM->resetBus(); }
if(powerStateOrdinal == 0) {
if( delayedStateCommandInUse() )
{
fDelayedStateChangeCmdNeedAbort = true;
}
if( fBusResetState == kResetStateDisabled )
{
fBusResetStateChangeCmd->cancel( kIOReturnAborted );
fBusResetState = kResetStateResetting;
}
fBusState = kAsleep;
}
if((fBusState == kAsleep) && (fROMHeader[1] == kFWBIBBusName)) {
sleepRes = fWorkLoop->sleep(&fBusState);
if(sleepRes != kIOReturnSuccess) {
IOLog("Can't sleep FireWire workloop, error 0x%x\n", sleepRes);
}
}
else {
openGate();
}
return res;
}
IOReturn IOFireWireController::resetBus()
{
IOReturn res = kIOReturnSuccess;
closeGate();
switch( fBusResetState )
{
case kResetStateDisabled:
fBusResetScheduled = true;
break;
case kResetStateArbitrated:
if( fBusResetDisabledCount == 0 )
{
doBusReset();
}
else if( !fBusResetScheduled )
{
fBusResetScheduled = true;
}
break;
case kResetStateResetting:
default:
break;
}
openGate();
return res;
}
void IOFireWireController::resetStateChange(void *refcon, IOReturn status,
IOFireWireBus *bus, IOFWBusCommand *fwCmd)
{
IOFireWireController *me = (IOFireWireController *)bus;
if( status == kIOReturnTimeout )
{
#ifdef FWKLOGASSERT
FWKLOGASSERT( me->fBusResetState == kResetStateDisabled );
#endif
me->fBusResetState = kResetStateArbitrated;
if( me->fBusResetScheduled && me->fBusResetDisabledCount == 0 )
{
me->doBusReset();
}
}
}
void IOFireWireController::doBusReset( void )
{
IOReturn status = kIOReturnSuccess;
bool useIBR = false;
if( fDelayedPhyPacket )
{
fFWIM->sendPHYPacket( fDelayedPhyPacket );
fDelayedPhyPacket = 0x00000000;
if( fGapCountMismatch )
{
useIBR = true;
}
}
FWKLOG(( "IOFireWireController::doBusReset\n" ));
fBusResetState = kResetStateResetting;
if( delayedStateCommandInUse() )
{
fDelayedStateChangeCmd->cancel(kIOReturnAborted);
}
fBusState = kWaitingBusReset;
fDelayedStateChangeCmd->reinit(1000 * kBusResetTimeout, delayedStateChange, NULL);
fDelayedStateChangeCmd->submit();
status = fFWIM->resetBus( useIBR );
}
void IOFireWireController::enterBusResetDisabledState( )
{
if( fBusResetState == kResetStateDisabled )
fBusResetStateChangeCmd->cancel( kIOReturnAborted );
fBusResetState = kResetStateDisabled;
fBusResetStateChangeCmd->reinit( 1000 * kRepeatResetDelay, resetStateChange, NULL );
fBusResetStateChangeCmd->submit();
}
IOReturn IOFireWireController::disableSoftwareBusResets( void )
{
IOReturn status = kIOReturnSuccess;
closeGate();
switch( fBusResetState )
{
case kResetStateDisabled:
fBusResetDisabledCount++;
break;
case kResetStateResetting:
status = kIOFireWireBusReset;
break;
case kResetStateArbitrated:
if( !fBusResetScheduled )
{
fBusResetDisabledCount++;
}
else
{
status = kIOFireWireBusReset;
}
break;
default:
break;
}
openGate();
return status;
}
void IOFireWireController::enableSoftwareBusResets( void )
{
closeGate();
#ifdef FWKLOGASSERT
FWKLOGASSERT( fBusResetDisabledCount != 0 );
#endif
if( fBusResetDisabledCount > 0 )
{
fBusResetDisabledCount--;
}
switch( fBusResetState )
{
case kResetStateArbitrated:
if( fBusResetDisabledCount == 0 && fBusResetScheduled )
{
doBusReset();
}
break;
case kResetStateResetting:
case kResetStateDisabled:
default:
break;
}
openGate();
}
void IOFireWireController::delayedStateChange(void *refcon, IOReturn status,
IOFireWireBus *bus, IOFWBusCommand *fwCmd)
{
IOFireWireController *me = (IOFireWireController *)bus;
if(status == kIOReturnTimeout) {
switch (me->fBusState) {
case kWaitingBusReset:
me->enterBusResetDisabledState();
me->fBusState = kRunning;
me->resetBus();
break;
case kWaitingSelfIDs:
me->fBusState = kRunning;
me->resetBus();
break;
case kWaitingScan:
me->fBusState = kScanning;
me->startBusScan();
break;
case kWaitingPrune:
me->fBusState = kRunning;
me->updatePlane();
break;
default:
IOLog("State change timeout, state is %d\n", me->fBusState);
break;
}
}
}
bool IOFireWireController::scanningBus() const
{
return fBusState == kWaitingSelfIDs || fBusState == kWaitingScan || fBusState == kScanning;
}
bool IOFireWireController::delayedStateCommandInUse() const
{
return (fBusState == kWaitingBusReset) || (fBusState == kWaitingSelfIDs) || (fBusState == kWaitingScan) || (fBusState == kWaitingPrune);
}
const AbsoluteTime * IOFireWireController::getResetTime() const
{
return &fResetTime;
}
void IOFireWireController::processBusReset()
{
FWKLOG(( "IOFireWireController::processBusReset\n" ));
FWKLOG(("IOFireWireController::processBusReset set generation to '%s' realGen=0x%lx\n", kFWBusScanInProgress, fBusGeneration));
setProperty( kFireWireGenerationID, kFWBusScanInProgress );
clock_get_uptime(&fResetTime);
fBusResetScheduled = false;
enterBusResetDisabledState();
if( fBusState == kWaitingSelfIDs )
{
fDelayedStateChangeCmd->cancel( kIOReturnAborted );
}
else
{
if( delayedStateCommandInUse() )
{
fDelayedStateChangeCmd->cancel(kIOReturnAborted);
}
fBusState = kWaitingSelfIDs;
fRequestedHalfSizePackets = false;
unsigned int i;
UInt32 oldgen = fBusGeneration;
fBusGeneration++;
OSIterator * childIterator = getClientIterator();
if( childIterator )
{
OSObject * child;
while( (child = childIterator->getNextObject()) )
{
IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
if( found && !found->isTerminated() )
{
found->setNodeROM( oldgen, kFWBadNodeID, NULL );
}
else if( OSDynamicCast(IOFireWireLocalNode, child) )
{
((IOFireWireLocalNode *)child)->messageClients(kIOMessageServiceIsSuspended);
}
}
childIterator->release();
}
physicalAccessProcessBusReset();
bzero( fSpeedCodes, sizeof(fSpeedCodes) );
bzero(fHopCounts, sizeof(fHopCounts) );
for( i=0; i<kMaxPendingTransfers; i++ )
{
AsyncPendingTrans *t = &fTrans[i];
if( t->fHandler )
{
IOFWAsyncCommand * cmd = t->fHandler;
cmd->gotPacket(kFWResponseBusResetError, NULL, 0);
}
}
if( fNodes[fRootNodeID] )
{
fNodes[fRootNodeID]->detachAll(gIOFireWirePlane);
}
for( i=0; i<=fRootNodeID; i++ )
{
if(fNodes[i])
{
fNodes[i]->release();
fNodes[i] = NULL;
}
}
fTimeoutQ.busReset();
}
fDelayedStateChangeCmd->reinit(1000 * kSelfIDTimeout, delayedStateChange, NULL);
fDelayedStateChangeCmd->submit();
}
void IOFireWireController::processSelfIDs(UInt32 *IDs, int numIDs, UInt32 *ownIDs, int numOwnIDs)
{
int i;
UInt32 id;
UInt32 nodeID;
UInt16 irmID;
UInt16 ourID;
IOFireWireLocalNode * localNode;
FWKLOG(( "IOFireWireController::processSelfIDs entered\n" ));
#if (DEBUGGING_LEVEL > 0)
for(i=0; i<numIDs; i++)
IOLog("ID %d: 0x%x <-> 0x%x\n", i, IDs[2*i], ~IDs[2*i+1]);
for(i=0; i<numOwnIDs; i++)
IOLog("Own ID %d: 0x%x <-> 0x%x\n", i, ownIDs[2*i], ~ownIDs[2*i+1]);
#endif
if( fBusState != kWaitingSelfIDs )
{
processBusReset();
}
if( fBusState != kWaitingSelfIDs )
{
IOLog( "IOFireWireController::processSelfIDs - fBusState != kWaitingSelfIDs\n" );
}
if( fBusState == kWaitingSelfIDs )
{
fDelayedStateChangeCmd->cancel( kIOReturnAborted );
}
fBusState = kWaitingScan;
fRootNodeID = ourID = (*ownIDs & kFWPhyPacketPhyID) >> kFWPhyPacketPhyIDPhase;
fLocalNodeID = ourID | (kFWLocalBusAddress>>kCSRNodeIDPhase);
fGapCountMismatch = false;
UInt32 gap_count = (*ownIDs & kFWSelfID0GapCnt) >> kFWSelfID0GapCntPhase;
for( i = 0; i < numIDs; i++ )
{
UInt32 current_id = IDs[2*i];
if( (current_id & kFWSelfIDPacketType) == 0 &&
((current_id & kFWSelfID0GapCnt) >> kFWSelfID0GapCntPhase) != gap_count )
{
fFWIM->sendPHYPacket( (kFWConfigurationPacketID << kFWPhyPacketIDPhase) |
(0x3f << kFWPhyConfigurationGapCntPhase) | kFWPhyConfigurationT );
fGapCountMismatch = true;
FWKLOG(( "IOFireWireController::processSelfIDs Found Gap Count Mismatch!\n" ));
break;
}
}
localNode = getLocalNode(this);
if(localNode)
{
localNode->setNodeProperties(fBusGeneration, fLocalNodeID, ownIDs, numOwnIDs);
fNodes[ourID] = localNode;
localNode->retain();
}
SInt16 prevID = -1; UInt32 *idPtr = fSelfIDs;
bzero( fNodeIDs, sizeof(fNodeIDs) ) ;
for(i=0; i<numIDs; i++)
{
UInt32 id = IDs[2*i];
UInt16 currID = (id & kFWPhyPacketPhyID) >> kFWPhyPacketPhyIDPhase;
if(id != ~IDs[2*i+1])
{
IOLog("Bad SelfID packet %d: 0x%lx != 0x%lx!\n", i, id, ~IDs[2*i+1]);
resetBus(); FWKLOG(( "IOFireWireController::processSelfIDs exited\n" ));
return;
}
if(currID != prevID)
{
if( prevID < ourID && currID > ourID )
{
int j;
fNodeIDs[ourID] = idPtr;
for(j=0; j<numOwnIDs; j++)
*idPtr++ = ownIDs[2*j];
}
fNodeIDs[currID] = idPtr;
prevID = currID;
if(fRootNodeID < currID)
fRootNodeID = currID;
}
*idPtr++ = id;
}
if(prevID < ourID)
{
int j;
fNodeIDs[ourID] = idPtr;
for(j=0; j<numOwnIDs; j++)
*idPtr++ = ownIDs[2*j];
}
fNodeIDs[fRootNodeID+1] = idPtr;
for(i = 0; i<=fRootNodeID; i++)
{
if ( NULL == fNodeIDs[i] )
{
IOLog("Missing self ID for node %d!\n", i ) ;
resetBus();
return; }
if( ((*fNodeIDs[i] & kFWPhyPacketPhyID) >> kFWPhyPacketPhyIDPhase) != (UInt32)i)
{
IOLog("No FireWire node %d (got ID packet 0x%lx)!\n", i, *fNodeIDs[i]);
resetBus();
return; }
}
OSObject * prop = OSData::withBytes( fSelfIDs, numIDs * sizeof(UInt32));
setProperty(gFireWireSelfIDs, prop);
prop->release();
buildTopology(false);
#if (DEBUGGING_LEVEL > 0)
for(i=0; i<numIDs; i++) {
id = IDs[2*i];
if(id != ~IDs[2*i+1]) {
DEBUGLOG("Bad SelfID: 0x%x <-> 0x%x\n", id, ~IDs[2*i+1]);
continue;
}
DEBUGLOG("SelfID: 0x%x\n", id);
}
DEBUGLOG("Our ID: 0x%x\n", *ownIDs);
#endif
irmID = 0;
for(i=0; i<=fRootNodeID; i++) {
id = *fNodeIDs[i];
nodeID = (id & kFWSelfIDPhyID) >> kFWSelfIDPhyIDPhase;
nodeID |= kFWLocalBusAddress>>kCSRNodeIDPhase;
if((id & (kFWSelfID0C | kFWSelfID0L)) == (kFWSelfID0C | kFWSelfID0L)) {
#if (DEBUGGING_LEVEL > 0)
IOLog("IRM contender: %lx\n", nodeID);
#endif
if(nodeID > irmID)
irmID = nodeID;
}
}
if(irmID != 0)
fIRMNodeID = irmID;
else
fIRMNodeID = kFWBadNodeID;
fBusMgr = false;
fIRM->processBusReset( fLocalNodeID, fIRMNodeID, fBusGeneration );
if(localNode) {
localNode->messageClients(kIOMessageServiceIsResumed);
}
fDelayedStateChangeCmd->reinit(1000 * kScanBusDelay, delayedStateChange, NULL);
fDelayedStateChangeCmd->submit();
FWKLOG(( "IOFireWireController::processSelfIDs exited\n" ));
}
void IOFireWireController::startBusScan()
{
int i;
FWKLOG(( "IOFireWireController::startBusScan entered\n" ));
fFWIM->sendPHYPacket(((fLocalNodeID & 0x3f) << kFWPhyPacketPhyIDPhase) | 0x003c0000);
fNumROMReads = 0;
for(i=0; i<=fRootNodeID; i++) {
UInt16 nodeID;
UInt32 id;
id = *fNodeIDs[i];
nodeID = (id & kFWSelfIDPhyID) >> kFWSelfIDPhyIDPhase;
nodeID |= kFWLocalBusAddress>>kCSRNodeIDPhase;
if(nodeID == fLocalNodeID)
continue;
if(true) { IOFWNodeScan *scan;
scan = (IOFWNodeScan *)IOMalloc(sizeof(*scan));
fNumROMReads++;
scan->fControl = this;
scan->fAddr.nodeID = nodeID;
scan->fAddr.addressHi = kCSRRegisterSpaceBaseAddressHi;
scan->fAddr.addressLo = kConfigBIBHeaderAddress;
scan->fSelfIDs = fNodeIDs[i];
scan->fNumSelfIDs = fNodeIDs[i+1] - fNodeIDs[i];
scan->fRead = 0;
scan->generation = fBusGeneration;
scan->fCmd = new IOFWReadQuadCommand;
FWKLOG(( "IOFireWireController::startBusScan node %lx speed was %lx\n",(UInt32)nodeID,(UInt32)FWSpeed( nodeID ) ));
if( FWSpeed( nodeID ) & kFWSpeedUnknownMask )
{
fSpeedCodes[(kFWMaxNodesPerBus + 1)*(scan->fAddr.nodeID & 63) + (fLocalNodeID & 63)] &= ~kFWSpeedUnknownMask;
fSpeedCodes[(kFWMaxNodesPerBus + 1)*(fLocalNodeID & 63) + (scan->fAddr.nodeID & 63)] &= ~kFWSpeedUnknownMask;
scan->fCmd->initAll(this, fBusGeneration, scan->fAddr, scan->fBuf, 1,
&readROMGlue, scan);
FWKLOG(( "IOFireWireController::startBusScan speedchecking\n" ));
scan->speedChecking = true; }
else
{
scan->fCmd->initAll(this, fBusGeneration, scan->fAddr, scan->fBuf, 1,
&readROMGlue, scan);
scan->fCmd->setMaxSpeed( kFWSpeed100MBit );
scan->speedChecking = false;
FWKLOG(( "IOFireWireController::startBusScan not speedchecking\n" ));
}
scan->fCmd->submit();
}
}
if(fNumROMReads == 0) {
finishedBusScan();
}
FWKLOG(( "IOFireWireController::startBusScan exited\n" ));
}
void IOFireWireController::readROMGlue(void *refcon, IOReturn status,
IOFireWireNub *device, IOFWCommand *fwCmd)
{
IOFWNodeScan *scan = (IOFWNodeScan *)refcon;
scan->fControl->readDeviceROM(scan, status);
}
void IOFireWireController::readDeviceROM(IOFWNodeScan *scan, IOReturn status)
{
bool done = true;
FWKLOG(( "IOFireWireController::readDeviceROM entered\n" ));
if(status != kIOReturnSuccess)
{
if(status == kIOFireWireBusReset)
{
scan->fCmd->release();
IOFree(scan, sizeof(*scan));
FWKLOG(( "IOFireWireController::readDeviceROM exited\n" ));
return;
}
FWKLOG(( "IOFireWireController::readDeviceROM speedcheck %lx ; speed %lx\n", (UInt32)scan->speedChecking, (UInt32)FWSpeed( scan->fAddr.nodeID ) ));
if( scan->speedChecking && FWSpeed( scan->fAddr.nodeID ) > kFWSpeed100MBit )
{
if( scan->generation == fBusGeneration )
{
FWKLOG(( "IOFireWireController::readDeviceROM reseting speed for node %lx from local %lx\n", (UInt32)scan->fAddr.nodeID, (UInt32)fLocalNodeID));
fSpeedCodes[(kFWMaxNodesPerBus + 1)*(scan->fAddr.nodeID & 63) + (fLocalNodeID & 63)]--;
fSpeedCodes[(kFWMaxNodesPerBus + 1)*(fLocalNodeID & 63) + (scan->fAddr.nodeID & 63)]--;
scan->fCmd->reinit(scan->fAddr, scan->fBuf, 1, &readROMGlue, scan, true);
scan->fCmd->submit();
return;
}
}
UInt32 nodeID = FWAddressToID(scan->fAddr.nodeID);
fNodes[nodeID] = createDummyRegistryEntry( scan );
fNumROMReads--;
if(fNumROMReads == 0)
{
finishedBusScan();
}
scan->fCmd->release();
IOFree(scan, sizeof(*scan));
FWKLOG(( "IOFireWireController::readDeviceROM exited\n" ));
return;
}
if(scan->fRead == 0)
{
if( ((scan->fBuf[0] & kConfigBusInfoBlockLength) >> kConfigBusInfoBlockLengthPhase) == 1)
{
scan->fROMSize = 4;
done = true;
}
else
{
scan->fROMSize = 4*((scan->fBuf[0] & kConfigROMCRCLength) >> kConfigROMCRCLengthPhase) + 4;
if(scan->fROMSize > 20)
scan->fROMSize = 20; scan->fRead = 8;
scan->fBuf[1] = kFWBIBBusName; scan->fAddr.addressLo = kConfigROMBaseAddress+8;
scan->fCmd->reinit(scan->fAddr, scan->fBuf+2, 1,
&readROMGlue, scan, true);
scan->fCmd->setMaxSpeed( kFWSpeed100MBit );
scan->fCmd->submit();
done = false;
}
}
else if(scan->fRead < 16)
{
if(scan->fROMSize > scan->fRead)
{
scan->fRead += 4;
scan->fAddr.addressLo = kConfigROMBaseAddress+scan->fRead;
scan->fCmd->reinit(scan->fAddr, scan->fBuf+scan->fRead/4, 1,
&readROMGlue, scan, true);
scan->fCmd->setMaxSpeed( kFWSpeed100MBit );
scan->fCmd->submit();
done = false;
}
else
done = true;
}
if( done )
{
if(!fBusMgr)
fBusMgr = scan->fBuf[2] & kFWBIBBmc;
#if (DEBUGGING_LEVEL > 0)
DEBUGLOG("Finished reading ROM for node 0x%x\n", scan->fAddr.nodeID);
#endif
IOFireWireDevice * newDevice = NULL;
do
{
CSRNodeUniqueID guid;
OSIterator *childIterator;
if(scan->fROMSize >= 20)
guid = *(CSRNodeUniqueID *)(scan->fBuf+3);
else
guid = scan->fBuf[0];
if( guid == 0 )
{
UInt32 nodeID = FWAddressToID(scan->fAddr.nodeID);
fNodes[nodeID] = createDummyRegistryEntry( scan );
OSObject * prop = OSNumber::withNumber( guid, 64 );
if( prop != NULL )
{
fNodes[nodeID]->setProperty( gFireWire_GUID, prop );
prop->release();
}
continue;
}
childIterator = getClientIterator();
if( childIterator)
{
OSObject *child;
while( (child = childIterator->getNextObject()))
{
IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
if(found && found->fUniqueID == guid && !found->isTerminated())
{
newDevice = found;
break;
}
}
childIterator->release();
}
if(newDevice)
{
#if IOFIREWIREDEBUG > 0
IOLog("Found old device 0x%p\n", newDevice);
#endif
newDevice->setNodeROM(fBusGeneration, fLocalNodeID, scan);
newDevice->retain(); }
else
{
newDevice = fFWIM->createDeviceNub(guid, scan);
if (!newDevice)
continue;
#if IOFIREWIREDEBUG > 0
IOLog("Creating new device 0x%p\n", newDevice);
#endif
newDevice->adjustBusy( 1 ); adjustBusy( 1 );
FWKLOG(( "IOFireWireController@0x%08lx::readDeviceROM adjustBusy(1)\n", (UInt32)this ));
if( !newDevice->attach(this) )
{
newDevice->adjustBusy( -1 ); adjustBusy( -1 ); FWKLOG(( "IOFireWireController@0x%08lx::readDeviceROM adjustBusy(-1)\n", (UInt32)this ));
continue;
}
newDevice->setRegistrationState( IOFireWireDevice::kDeviceNeedsRegisterService );
newDevice->setNodeROM( fBusGeneration, fLocalNodeID, scan );
}
UInt32 nodeID = FWAddressToID(scan->fAddr.nodeID);
fNodes[nodeID] = newDevice;
fNodes[nodeID]->retain();
} while (false);
if (newDevice)
newDevice->release();
scan->fCmd->release();
IOFree(scan, sizeof(*scan));
fNumROMReads--;
if(fNumROMReads == 0)
{
finishedBusScan();
}
}
FWKLOG(( "IOFireWireController::readDeviceROM exited\n" ));
}
IORegistryEntry * IOFireWireController::createDummyRegistryEntry( IOFWNodeScan *scan )
{
OSDictionary *propTable;
OSObject * prop;
propTable = OSDictionary::withCapacity(3);
prop = OSNumber::withNumber(scan->fAddr.nodeID, 16);
propTable->setObject(gFireWireNodeID, prop);
prop->release();
prop = OSNumber::withNumber((scan->fSelfIDs[0] & kFWSelfID0SP) >> kFWSelfID0SPPhase, 32);
propTable->setObject(gFireWireSpeed, prop);
prop->release();
prop = OSData::withBytes(scan->fSelfIDs, scan->fNumSelfIDs*sizeof(UInt32));
propTable->setObject(gFireWireSelfIDs, prop);
prop->release();
IORegistryEntry * newPhy;
newPhy = new IORegistryEntry;
if(newPhy)
{
if(!newPhy->init(propTable))
{
newPhy->release();
newPhy = NULL;
}
if(getSecurityMode() == kIOFWSecurityModeNormal) {
setNodeIDPhysicalFilter( scan->fAddr.nodeID & 0x3f, true );
}
if(propTable)
propTable->release();
}
return newPhy;
}
void IOFireWireController::finishedBusScan()
{
FWKLOG(( "IOFireWireController::finishedBusScan entered\n" ));
static UInt32 gaps[17] = {63, 5, 7, 8, 10, 13, 16, 18, 21,
24, 26, 29, 32, 35, 37, 40, 43};
if( !fBusResetScheduled && !fBusMgr && fLocalNodeID == fIRMNodeID) {
int maxHops;
int i;
maxHops = fRootNodeID;
if (maxHops > 16) maxHops = 16;
fGapCount = gaps[maxHops] << kFWPhyConfigurationGapCntPhase;
if(fRootNodeID == 0) {
fFWIM->setRootHoldOff(false);
}
else {
fFWIM->sendPHYPacket((kFWConfigurationPacketID << kFWPhyPacketIDPhase) |
((fLocalNodeID & 63) << kFWPhyPacketPhyIDPhase) | kFWPhyConfigurationR );
fFWIM->setRootHoldOff(true);
if(fRootNodeID != (fLocalNodeID & 63)) {
resetBus();
FWKLOG(( "IOFireWireController::finishedBusScan exited\n" ));
return; }
}
fFWIM->setCycleMaster(true);
if(fRootNodeID != 0) {
for( i = 0; i <= fRootNodeID; i++ ) {
if( (*fNodeIDs[i] & kFWSelfID0GapCnt) != fGapCount ) {
fDelayedPhyPacket = (kFWConfigurationPacketID << kFWPhyPacketIDPhase) |
((fLocalNodeID & 63) << kFWPhyPacketPhyIDPhase) |
kFWPhyConfigurationR | fGapCount | kFWPhyConfigurationT;
resetBus();
FWKLOG(( "IOFireWireController::finishedBusScan exited\n" ));
return; }
}
}
}
if(fBusState == kScanning)
{
bool wouldTerminateDevice = false;
OSIterator * childIterator;
childIterator = getClientIterator();
if( childIterator )
{
OSObject *child;
while( (child = childIterator->getNextObject()))
{
IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
if( found && !found->isTerminated() && found->fNodeID == kFWBadNodeID )
{
wouldTerminateDevice = true;
}
}
childIterator->release();
}
if( (fRootNodeID == 0) && (fDevicePruneDelay < kOnlyNodeDevicePruneDelay) )
{
fDevicePruneDelay = kOnlyNodeDevicePruneDelay;
}
if( !wouldTerminateDevice )
{
fDevicePruneDelay = kNormalDevicePruneDelay;
}
fBusState = kWaitingPrune; fDelayedStateChangeCmd->reinit(1000 * fDevicePruneDelay, delayedStateChange, NULL); fDelayedStateChangeCmd->submit();
}
IOFWCmdQ &resetQ(getAfterResetHandledQ());
resetQ.executeQueue(true);
IOFWIsochChannel *found;
fAllocChannelIterator->reset();
while( (found = (IOFWIsochChannel *) fAllocChannelIterator->getNextObject())) {
found->handleBusReset();
}
IOFWCommand *cmd;
while( (cmd = resetQ.fHead) )
{
cmd->cancel(kIOReturnTimeout);
}
FWKLOG(( "IOFireWireController::finishedBusScan exited\n" ));
}
UInt32 IOFireWireController::countNodeIDChildren( UInt16 nodeID )
{
UInt32 id0, idn;
UInt32 *idPtr;
int i;
int children = 0;
int ports;
UInt32 port;
int mask, shift;
i = nodeID & 63;
idPtr = fNodeIDs[i];
id0 = *idPtr++;
mask = kFWSelfID0P0;
shift = kFWSelfID0P0Phase;
for(ports=0; ports<3; ports++)
{
port = (id0 & mask) >> shift;
if(port == kFWSelfIDPortStatusChild)
children++;
mask >>= 2;
shift -= 2;
}
if(fNodeIDs[i+1] > idPtr)
{
idn = *idPtr++;
mask = kFWSelfIDNPa;
shift = kFWSelfIDNPaPhase;
for(ports=0; ports<8; ports++)
{
port = (idn & mask) >> shift;
if(port == kFWSelfIDPortStatusChild)
children++;
mask >>= 2;
shift -= 2;
}
if(fNodeIDs[i+1] > idPtr)
{
idn = *idPtr++;
mask = kFWSelfIDNPa;
shift = kFWSelfIDNPaPhase;
for(ports=0; ports<5; ports++)
{
port = (idn & mask) >> shift;
if(port == kFWSelfIDPortStatusChild)
children++;
mask >>= 2;
shift -= 2;
}
}
}
return children;
}
UInt32 IOFireWireController::getPortNumberFromIndex( UInt16 index )
{
UInt32 id0, idn;
UInt32 *idPtr;
int i;
int children = 0;
int ports;
UInt32 port;
int mask, shift;
i = fLocalNodeID & 63;
idPtr = fNodeIDs[i];
id0 = *idPtr++;
mask = kFWSelfID0P0;
shift = kFWSelfID0P0Phase;
for(ports=0; ports<3; ports++)
{
port = (id0 & mask) >> shift;
if(port == kFWSelfIDPortStatusChild)
{
if( index == children )
return ports;
children++;
}
mask >>= 2;
shift -= 2;
}
if(fNodeIDs[i+1] > idPtr)
{
idn = *idPtr++;
mask = kFWSelfIDNPa;
shift = kFWSelfIDNPaPhase;
for(ports=0; ports<8; ports++)
{
if(port == kFWSelfIDPortStatusChild)
{
if( index == children )
return ports;
children++;
}
mask >>= 2;
shift -= 2;
}
}
return 0xFFFFFFFF;
}
void IOFireWireController::buildTopology(bool doFWPlane)
{
int i, maxDepth;
IORegistryEntry *root;
struct FWNodeScan
{
int nodeID;
int childrenRemaining;
IORegistryEntry *node;
};
FWNodeScan scanList[kFWMaxNodesPerBus];
FWNodeScan *level;
maxDepth = 0;
root = fNodes[fRootNodeID];
level = scanList;
for(i=fRootNodeID; i>=0; i--)
{
UInt32 id0;
UInt8 speedCode;
IORegistryEntry *node = fNodes[i];
int children = 0;
children = countNodeIDChildren( i );
level->nodeID = i;
level->childrenRemaining = children;
level->node = node;
id0 = *fNodeIDs[i];
speedCode = (id0 & kFWSelfID0SP) >> kFWSelfID0SPPhase;
if( !doFWPlane )
{
if( speedCode == kFWSpeedReserved )
speedCode = kFWSpeed800MBit | kFWSpeedUnknownMask; }
fSpeedCodes[(kFWMaxNodesPerBus + 1)*i + i] = speedCode;
fHopCounts[(kFWMaxNodesPerBus + 1)*i + i] = 0;
if (i != fRootNodeID)
{
int parentNodeNum, scanNodeNum;
parentNodeNum = (level-1)->nodeID;
if(doFWPlane)
{
node->attachToParent((level-1)->node, gIOFireWirePlane);
}
else
{
for (scanNodeNum = i + 1; scanNodeNum <= fRootNodeID; scanNodeNum++)
{
UInt8 scanSpeedCode;
scanSpeedCode = fSpeedCodes[(kFWMaxNodesPerBus + 1)*parentNodeNum + scanNodeNum];
if ( (speedCode & ~kFWSpeedUnknownMask) < (scanSpeedCode & ~kFWSpeedUnknownMask) )
{
scanSpeedCode = speedCode;
}
if( (speedCode & kFWSpeedUnknownMask) || (scanSpeedCode & kFWSpeedUnknownMask) )
{
scanSpeedCode |= kFWSpeedUnknownMask;
}
fSpeedCodes[(kFWMaxNodesPerBus + 1)*i + scanNodeNum] = scanSpeedCode;
fSpeedCodes[(kFWMaxNodesPerBus + 1)*scanNodeNum + i] = scanSpeedCode;
UInt8 hops;
hops = fHopCounts[(kFWMaxNodesPerBus + 1)*parentNodeNum + scanNodeNum];
fHopCounts[(kFWMaxNodesPerBus + 1)*i + scanNodeNum] = hops + 1;
fHopCounts[(kFWMaxNodesPerBus + 1)*scanNodeNum + i] = hops + 1;
}
}
}
if (i > 0)
{
while (level->childrenRemaining == 0)
{
level--;
if(level < scanList)
{
IOLog("SelfIDs don't build a proper tree (missing selfIDS?)!!\n");
return;
}
level->childrenRemaining--;
}
level++;
if(level - scanList > maxDepth)
{
maxDepth = level - scanList;
}
}
}
#if (DEBUGGING_LEVEL > 0)
if(doFWPlane) {
IOLog("max FireWire tree depth is %d\n", maxDepth);
IOLog("FireWire Speed map:\n");
for(i=0; i <= fRootNodeID; i++) {
int j;
for(j=0; j <= i; j++) {
IOLog("%d ", fSpeedCodes[(kFWMaxNodesPerBus + 1)*i + j]);
}
IOLog("\n");
}
}
#endif
#if 0
if( doFWPlane )
{
IOLog( "FireWire Hop Counts:\n" );
for( i=0; i <= fRootNodeID; i++ )
{
int j;
for( j=0; j <= i; j++ )
{
IOLog( "%d ", fHopCounts[(kFWMaxNodesPerBus + 1)*i + j] );
}
IOLog( "\n" );
}
}
#endif
if(doFWPlane)
root->attachToParent(IORegistryEntry::getRegistryRoot(), gIOFireWirePlane);
}
void IOFireWireController::updatePlane()
{
OSIterator *childIterator;
fDevicePruneDelay = kNormalDevicePruneDelay;
childIterator = getClientIterator();
if( childIterator) {
OSObject *child;
while( (child = childIterator->getNextObject())) {
IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
if(found && !found->isTerminated() && found->fNodeID == kFWBadNodeID) {
if( found->isOpen() )
{
messageClient( kIOFWMessageServiceIsRequestingClose, found );
}
else
{
found->setTerminated( true );
IOFireWireDevice::terminateDevice( found );
}
}
}
childIterator->release();
}
buildTopology(true);
messageClients( kIOFWMessageTopologyChanged );
char busGenerationStr[32];
sprintf(busGenerationStr, "%lx", fBusGeneration);
setProperty( kFireWireGenerationID, busGenerationStr);
FWKLOG(("IOFireWireController::updatePlane reset generation to '%s'\n", busGenerationStr));
fUseHalfSizePackets = fRequestedHalfSizePackets;
}
#pragma mark -
void IOFireWireController::setPhysicalAccessMode( IOFWPhysicalAccessMode mode )
{
closeGate();
if( mode == kIOFWPhysicalAccessEnabled &&
getSecurityMode() == kIOFWSecurityModeNormal )
{
fPhysicalAccessMode = kIOFWPhysicalAccessEnabled;
FWKLOG(( "IOFireWireController::setPhysicalAccessMode - enable physical access\n" ));
OSIterator * iterator = getClientIterator();
OSObject * child = NULL;
while( (child = iterator->getNextObject()) )
{
IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
if( found && !found->isTerminated() )
{
found->configurePhysicalFilter();
}
}
iterator->release();
}
if( mode == kIOFWPhysicalAccessDisabled )
{
fPhysicalAccessMode = kIOFWPhysicalAccessDisabled;
FWKLOG(( "IOFireWireController::setPhysicalAccessMode - disable physical access\n" ));
fFWIM->setNodeIDPhysicalFilter( kIOFWAllPhysicalFilters, false );
}
if( mode == kIOFWPhysicalAccessDisabledForGeneration &&
fPhysicalAccessMode != kIOFWPhysicalAccessDisabled )
{
fPhysicalAccessMode = kIOFWPhysicalAccessDisabledForGeneration;
FWKLOG(( "IOFireWireController::setPhysicalAccessMode - disable physical access for this bus generation\n" ));
fFWIM->setNodeIDPhysicalFilter( kIOFWAllPhysicalFilters, false );
}
openGate();
}
IOFWPhysicalAccessMode IOFireWireController::getPhysicalAccessMode( void )
{
return fPhysicalAccessMode;
}
void IOFireWireController::physicalAccessProcessBusReset( void )
{
if( fPhysicalAccessMode == kIOFWPhysicalAccessDisabledForGeneration &&
getSecurityMode() == kIOFWSecurityModeNormal )
{
fPhysicalAccessMode = kIOFWPhysicalAccessEnabled;
FWKLOG(( "IOFireWireController::physicalAccessProcessBusReset - re-enable physical access because of bus reset\n" ));
}
}
void IOFireWireController::setNodeIDPhysicalFilter( UInt16 nodeID, bool state )
{
if( fPhysicalAccessMode == kIOFWPhysicalAccessEnabled )
{
FWKLOG(( "IOFireWireController::setNodeIDPhysicalFilter - set physical access for node 0x%x to %d\n", nodeID, state ));
fFWIM->setNodeIDPhysicalFilter( nodeID, state );
}
}
#pragma mark -
void IOFireWireController::initSecurity( void )
{
IOFWSecurityMode mode = kIOFWSecurityModeNormal;
{
IORegistryEntry * options = IORegistryEntry::fromPath( "/options", gIODTPlane );
if( options != NULL )
{
OSString * securityModeProperty = OSDynamicCast( OSString, options->getProperty("security-mode") );
if( securityModeProperty != NULL && strcmp("none", securityModeProperty->getCStringNoCopy()) != 0 )
{
mode = kIOFWSecurityModeSecurePermanent;
}
options->release();
options = NULL;
}
}
if( mode != kIOFWSecurityModeSecurePermanent )
{
OSIterator * iterator = NULL;
OSBoolean * keyswitchState = NULL;
iterator = getMatchingServices( nameMatching("AppleKeyswitch") );
if( iterator != NULL )
{
OSObject * obj = NULL;
if( (obj = iterator->getNextObject()) )
{
IOService * service = (IOService*)obj;
keyswitchState = OSDynamicCast( OSBoolean, service->getProperty( "Keyswitch" ) );
if( keyswitchState->isTrue() )
{
mode = kIOFWSecurityModeSecure;
}
}
iterator->release();
iterator = NULL;
}
fKeyswitchNotifier = addNotification( gIOMatchedNotification, nameMatching( "AppleKeyswitch" ),
(IOServiceNotificationHandler)&IOFireWireController::serverKeyswitchCallback,
this, 0 );
}
setSecurityMode( mode );
}
void IOFireWireController::freeSecurity( void )
{
if( fKeyswitchNotifier != NULL )
{
fKeyswitchNotifier->remove();
fKeyswitchNotifier = NULL;
}
}
bool IOFireWireController::serverKeyswitchCallback( void * target, void * refCon, IOService * service )
{
OSBoolean * keyswitchState = NULL;
IOFireWireController * me = NULL;
keyswitchState = OSDynamicCast( OSBoolean, service->getProperty( "Keyswitch" ) );
me = OSDynamicCast( IOFireWireController, (OSObject *)target );
if( keyswitchState != NULL && me != NULL )
{
if( keyswitchState->isFalse() )
{
me->setSecurityMode( kIOFWSecurityModeNormal );
}
else if( keyswitchState->isTrue() )
{
me->setSecurityMode( kIOFWSecurityModeSecure );
}
}
return true;
}
void IOFireWireController::setSecurityMode( IOFWSecurityMode mode )
{
closeGate();
fSecurityMode = mode;
switch( fSecurityMode )
{
case kIOFWSecurityModeNormal:
FWKLOG(( "IOFireWireController::setSecurityMode - set mode to normal\n" ));
fFWIM->setSecurityMode( mode );
setPhysicalAccessMode( kIOFWPhysicalAccessEnabled );
break;
case kIOFWSecurityModeSecure:
case kIOFWSecurityModeSecurePermanent:
FWKLOG(( "IOFireWireController::setSecurityMode - set mode to secure\n" ));
fFWIM->setSecurityMode( mode );
setPhysicalAccessMode( kIOFWPhysicalAccessDisabled );
break;
default:
IOLog( "IOFireWireController::setSecurityMode - illegal security mode = 0x%x\n", fSecurityMode );
break;
}
openGate();
}
IOFWSecurityMode IOFireWireController::getSecurityMode( void )
{
return fSecurityMode;
}
#pragma mark -
IOLocalConfigDirectory * IOFireWireController::getRootDir() const
{
return fRootDir;
}
IOReturn IOFireWireController::AddUnitDirectory(IOLocalConfigDirectory *unitDir)
{
IOReturn res;
closeGate();
getRootDir()->addEntry(kConfigUnitDirectoryKey, unitDir);
res = UpdateROM();
if(res == kIOReturnSuccess)
res = resetBus();
openGate();
return res;
}
IOReturn IOFireWireController::RemoveUnitDirectory(IOLocalConfigDirectory *unitDir)
{
IOReturn res;
closeGate();
getRootDir()->removeSubDir(unitDir);
res = UpdateROM();
if(res == kIOReturnSuccess)
res = resetBus();
openGate();
return res;
}
IOReturn IOFireWireController::UpdateROM()
{
UInt32 * hack;
UInt32 crc;
unsigned int numQuads;
OSData * rom;
IOReturn ret;
UInt32 generation;
IOFireWireLocalNode * localNode;
generation = fROMHeader[2] & kFWBIBGeneration;
generation += (1 << kFWBIBGenerationPhase);
generation &= kFWBIBGeneration;
if(generation < (2 << kFWBIBGenerationPhase))
generation = (2 << kFWBIBGenerationPhase);
fROMHeader[2] = (fROMHeader[2] & ~kFWBIBGeneration) | generation;
rom = OSData::withBytes(&fROMHeader, sizeof(fROMHeader));
fRootDir->compile(rom);
hack = (UInt32 *)rom->getBytesNoCopy();
numQuads = rom->getLength()/sizeof(UInt32) - 1;
crc = FWComputeCRC16 (hack + 1, numQuads);
*hack = (((sizeof(fROMHeader)/sizeof(UInt32)-1) <<
kConfigBusInfoBlockLengthPhase) &
kConfigBusInfoBlockLength) |
((numQuads << kConfigROMCRCLengthPhase) & kConfigROMCRCLength) |
((crc << kConfigROMCRCValuePhase) & kConfigROMCRCValue);
localNode = getLocalNode(this);
if(localNode)
localNode->setProperty(gFireWireROM, rom);
#if 0
{
unsigned int i;
IOLog("--------- FW Local ROM: --------\n");
for(i=0; i<numQuads+1; i++)
IOLog("ROM[%d] = 0x%x\n", i, hack[i]);
}
#endif
if(fROMAddrSpace)
{
freeAddress( fROMAddrSpace );
fROMAddrSpace->release();
fROMAddrSpace = NULL;
}
fROMAddrSpace = IOFWPseudoAddressSpace::simpleReadFixed( this,
FWAddress(kCSRRegisterSpaceBaseAddressHi, kConfigROMBaseAddress),
(numQuads+1)*sizeof(UInt32), rom->getBytesNoCopy());
ret = allocAddress(fROMAddrSpace);
if(kIOReturnSuccess == ret)
{
ret = fFWIM->updateROM(rom);
}
rom->release();
return ret ;
}
#pragma mark -
AsyncPendingTrans *IOFireWireController::allocTrans(IOFWAsyncCommand *cmd)
{
unsigned int i;
unsigned int tran;
tran = fLastTrans;
for(i=0; i<kMaxPendingTransfers; i++) {
AsyncPendingTrans *t;
tran++;
if(tran >= kMaxPendingTransfers)
tran = 0;
t = &fTrans[tran];
if(!t->fInUse) {
t->fHandler = cmd;
t->fInUse = true;
t->fTCode = tran;
fLastTrans = tran;
return t;
}
}
IOLog("Out of FireWire transaction labels!\n");
return NULL;
}
void IOFireWireController::freeTrans(AsyncPendingTrans *trans)
{
trans->fHandler = NULL;
trans->fInUse = false;
}
IOReturn IOFireWireController::asyncRead( UInt32 generation,
UInt16 nodeID,
UInt16 addrHi,
UInt32 addrLo,
int speed,
int label,
int size,
IOFWAsyncCommand * cmd)
{
if( !checkGeneration(generation) )
{
return kIOFireWireBusReset;
}
if( nodeID == fLocalNodeID )
{
UInt32 rcode;
IOMemoryDescriptor *buf;
IOByteCount offset;
IOFWSpeed temp = (IOFWSpeed)speed;
rcode = doReadSpace( nodeID,
temp,
FWAddress(addrHi, addrLo),
size,
&buf,
&offset,
(IOFWRequestRefCon)label );
if(rcode == kFWResponseComplete)
{
void * bytes = IOMalloc( size );
buf->readBytes( offset, bytes, size );
cmd->gotPacket( rcode, bytes, size );
IOFree( bytes, size );
}
else
{
cmd->gotPacket( rcode, NULL, 0 );
}
return kIOReturnSuccess;
}
else
{
int actual_speed = speed;
if( addrHi == kCSRRegisterSpaceBaseAddressHi )
{
if( (addrLo == kCSRBandwidthAvailable) ||
(addrLo == kCSRChannelsAvailable31_0) ||
(addrLo == kCSRChannelsAvailable63_32) ||
(addrLo == kCSRBusManagerID) )
{
actual_speed = kFWSpeed100MBit;
}
}
return fFWIM->asyncRead( nodeID, addrHi, addrLo, actual_speed, label, size, cmd );
}
}
IOReturn IOFireWireController::asyncWrite( UInt32 generation,
UInt16 nodeID,
UInt16 addrHi,
UInt32 addrLo,
int speed,
int label,
void * data,
int size,
IOFWAsyncCommand * cmd)
{
IOLog( "IOFireWireController::asyncWrite : DEPRECATED API\n" );
return kIOReturnUnsupported;
}
IOReturn IOFireWireController::asyncWrite( UInt32 generation,
UInt16 nodeID,
UInt16 addrHi,
UInt32 addrLo,
int speed,
int label,
IOMemoryDescriptor * buf,
IOByteCount offset,
int size,
IOFWAsyncCommand * cmd )
{
return asyncWrite( generation,
nodeID,
addrHi,
addrLo,
speed,
label,
buf,
offset,
size,
cmd,
kIOFWWriteFlagsNone );
}
IOReturn IOFireWireController::asyncWrite( UInt32 generation,
UInt16 nodeID,
UInt16 addrHi,
UInt32 addrLo,
int speed,
int label,
IOMemoryDescriptor * buf,
IOByteCount offset,
int size,
IOFWAsyncCommand * cmd,
IOFWWriteFlags flags )
{
if( !checkGeneration(generation) )
{
return kIOFireWireBusReset;
}
if( nodeID == fLocalNodeID )
{
UInt32 rcode;
IOFWSpeed temp = (IOFWSpeed)speed;
void * bytes = IOMalloc( size );
buf->readBytes( offset, bytes, size );
rcode = doWriteSpace( nodeID,
temp,
FWAddress( addrHi, addrLo ),
size,
bytes,
(IOFWRequestRefCon)label );
IOFree( bytes, size );
cmd->gotPacket(rcode, NULL, 0);
return kIOReturnSuccess;
}
else
{
int actual_speed = speed;
if( addrHi == kCSRRegisterSpaceBaseAddressHi )
{
if( (addrLo == kCSRBandwidthAvailable) ||
(addrLo == kCSRChannelsAvailable31_0) ||
(addrLo == kCSRChannelsAvailable63_32) ||
(addrLo == kCSRBusManagerID) )
{
actual_speed = kFWSpeed100MBit;
}
}
return fFWIM->asyncWrite( nodeID,
addrHi,
addrLo,
actual_speed,
label,
buf,
offset,
size,
cmd,
flags );
}
}
IOReturn IOFireWireController::asyncLock( UInt32 generation,
UInt16 nodeID,
UInt16 addrHi,
UInt32 addrLo,
int speed,
int label,
int type,
void * data,
int size,
IOFWAsyncCommand * cmd )
{
IOLog( "IOFireWireController::asyncLock : DEPRECATED API\n" );
return kIOReturnUnsupported;
}
IOReturn IOFireWireController::asyncLock( UInt32 generation,
UInt16 nodeID,
UInt16 addrHi,
UInt32 addrLo,
int speed,
int label,
int type,
IOMemoryDescriptor * buf,
IOByteCount offset,
int size,
IOFWAsyncCommand * cmd )
{
if( !checkGeneration(generation) )
{
return kIOFireWireBusReset;
}
if( nodeID == fLocalNodeID )
{
UInt32 rcode;
UInt32 retVals[2];
UInt32 retSize = sizeof(retVals);
IOFWSpeed temp = (IOFWSpeed)speed;
IOFWRequestRefCon refcon = (IOFWRequestRefCon)(label | kRequestIsLock | (type << kRequestExtTCodeShift));
void * bytes = IOMalloc( size );
buf->readBytes( offset, bytes, size );
rcode = doLockSpace( nodeID,
temp,
FWAddress(addrHi, addrLo),
size,
(const UInt32*)bytes,
retSize,
retVals,
type,
refcon );
IOFree( bytes, size );
cmd->gotPacket( rcode, retVals, retSize );
return kIOReturnSuccess;
}
else
{
int actual_speed = speed;
if( addrHi == kCSRRegisterSpaceBaseAddressHi )
{
if( (addrLo == kCSRBandwidthAvailable) ||
(addrLo == kCSRChannelsAvailable31_0) ||
(addrLo == kCSRChannelsAvailable63_32) ||
(addrLo == kCSRBusManagerID) )
{
actual_speed = kFWSpeed100MBit;
}
}
return fFWIM->asyncLock( nodeID,
addrHi,
addrLo,
actual_speed,
label,
type,
buf,
offset,
size,
cmd );
}
}
IOReturn IOFireWireController::handleAsyncTimeout(IOFWAsyncCommand *cmd)
{
return fFWIM->handleAsyncTimeout(cmd);
}
IOReturn IOFireWireController::asyncStreamWrite(UInt32 generation,
int speed, int tag, int sync, int channel,
IOMemoryDescriptor *buf, IOByteCount offset,
int size, IOFWAsyncStreamCommand *cmd)
{
if(!checkGeneration(generation)) {
return (kIOFireWireBusReset);
}
return fFWIM->asyncStreamTransmit((UInt32)channel, speed, (UInt32) sync, (UInt32) tag, buf, offset, size, cmd);
}
IOFWAsyncStreamCommand * IOFireWireController::createAsyncStreamCommand( UInt32 generation,
UInt32 channel, UInt32 sync, UInt32 tag, IOMemoryDescriptor *hostMem,
UInt32 size, int speed, FWAsyncStreamCallback completion, void *refcon)
{
IOFWAsyncStreamCommand * cmd;
cmd = new IOFWAsyncStreamCommand;
if(cmd) {
if(!cmd->initAll(this, generation, channel, sync, tag, hostMem,size,speed,
completion, refcon)) {
cmd->release();
cmd = NULL;
}
}
return cmd;
}
void IOFireWireController::processRcvPacket(UInt32 *data, int size)
{
#if 0
int i;
kprintf("Received packet 0x%x size %d\n", data, size);
for(i=0; i<size; i++) {
kprintf("0x%x ", data[i]);
}
kprintf("\n");
#endif
UInt32 tCode, tLabel;
UInt32 quad0;
UInt16 sourceID;
UInt16 destID;
quad0 = *data;
tCode = (quad0 & kFWPacketTCode) >> kFWPacketTCodePhase;
tLabel = (quad0 & kFWAsynchTLabel) >> kFWAsynchTLabelPhase;
sourceID = (data[1] & kFWAsynchSourceID) >> kFWAsynchSourceIDPhase;
destID = (data[0] & kFWAsynchDestinationID) >> kFWAsynchDestinationIDPhase;
switch (tCode)
{
case kFWTCodeWriteQuadlet :
#if (DEBUGGING_LEVEL > 0)
DEBUGLOG("WriteQuadlet: addr 0x%x -> 0x%x:0x%x:0x%x\n", sourceID, destID,
(data[1] & kFWAsynchDestinationOffsetHigh) >> kFWAsynchDestinationOffsetHighPhase, data[2]);
#endif
processWriteRequest(sourceID, tLabel, data, &data[3], 4);
break;
case kFWTCodeWriteBlock :
#if (DEBUGGING_LEVEL > 0)
DEBUGLOG("WriteBlock: addr 0x%x -> 0x%x:0x%x:0x%x\n", sourceID, destID,
(data[1] & kFWAsynchDestinationOffsetHigh) >> kFWAsynchDestinationOffsetHighPhase, data[2]);
#endif
processWriteRequest(sourceID, tLabel, data, &data[4],
(data[3] & kFWAsynchDataLength) >> kFWAsynchDataLengthPhase);
break;
case kFWTCodeWriteResponse :
if(fTrans[tLabel].fHandler) {
IOFWAsyncCommand * cmd = fTrans[tLabel].fHandler;
cmd->gotPacket((data[1] & kFWAsynchRCode)>>kFWAsynchRCodePhase, 0, 0);
}
else {
#if (DEBUGGING_LEVEL > 0)
DEBUGLOG("WriteResponse: label %d isn't in use!!, data1 = 0x%x\n",
tLabel, data[1]);
#endif
}
break;
case kFWTCodeReadQuadlet :
#if (DEBUGGING_LEVEL > 0)
DEBUGLOG("ReadQuadlet: addr 0x%x -> 0x%x:0x%x:0x%x\n", sourceID, destID,
(data[1] & kFWAsynchDestinationOffsetHigh) >>
kFWAsynchDestinationOffsetHighPhase, data[2]);
#endif
{
UInt32 ret;
FWAddress addr((data[1] & kFWAsynchDestinationOffsetHigh) >> kFWAsynchDestinationOffsetHighPhase, data[2]);
IOFWSpeed speed = FWSpeed(sourceID);
IOMemoryDescriptor *buf = NULL;
IOByteCount offset;
ret = doReadSpace(sourceID, speed, addr, 4,
&buf, &offset, (IOFWRequestRefCon)(tLabel | kRequestIsQuad));
if(ret == kFWResponsePending)
break;
if( NULL != buf )
{
UInt32 quad = 0xdeadbeef;
buf->readBytes( offset, &quad, 4 );
if ( destID != 0xffff ) fFWIM->asyncReadQuadResponse(sourceID, speed, tLabel, ret, quad );
else
DebugLog("Skipped asyncReadQuadResponse because destID=0x%x\n", destID);
}
else
{
if ( destID != 0xffff ) fFWIM->asyncReadQuadResponse(sourceID, speed, tLabel, ret, 0xdeadbeef);
else
DebugLog("Skipped asyncReadQuadResponse because destID=0x%x\n", destID);
}
}
break;
case kFWTCodeReadBlock :
#if (DEBUGGING_LEVEL > 0)
DEBUGLOG("ReadBlock: addr 0x%x -> 0x%x:0x%x:0x%x\n", sourceID, destID,
(data[1] & kFWAsynchDestinationOffsetHigh) >> kFWAsynchDestinationOffsetHighPhase, data[2],
(data[3] & kFWAsynchDataLength) >> kFWAsynchDataLengthPhase);
#endif
{
IOReturn ret;
int length = (data[3] & kFWAsynchDataLength) >> kFWAsynchDataLengthPhase ;
FWAddress addr((data[1] & kFWAsynchDestinationOffsetHigh) >> kFWAsynchDestinationOffsetHighPhase, data[2]);
IOFWSpeed speed = FWSpeed(sourceID);
IOMemoryDescriptor * buf = NULL;
IOByteCount offset;
ret = doReadSpace(sourceID, speed, addr, length, &buf, &offset, (IOFWRequestRefCon)(tLabel));
if(ret == kFWResponsePending)
break;
if(NULL != buf) {
if ( destID != 0xffff ) fFWIM->asyncReadResponse(sourceID, speed, tLabel, ret, buf, offset, length);
else
DebugLog("Skipped asyncReadResponse because destID=0x%x\n", destID);
}
else {
if ( destID != 0xffff ) fFWIM->asyncReadResponse(sourceID, speed, tLabel, ret, fBadReadResponse, 0, 4);
else
DebugLog("Skipped asyncReadResponse because destID=0x%x\n", destID);
}
}
break;
case kFWTCodeReadQuadletResponse :
if(fTrans[tLabel].fHandler) {
IOFWAsyncCommand * cmd = fTrans[tLabel].fHandler;
FWAddress commandAddress = cmd->getAddress();
if( sourceID == commandAddress.nodeID )
{
cmd->gotPacket((data[1] & kFWAsynchRCode)>>kFWAsynchRCodePhase,
(const void*)(data+3), 4);
}
else
{
#if (DEBUGGING_LEVEL > 0)
DEBUGLOG( "Response from wrong node ID!\n" );
#endif
}
}
else {
#if (DEBUGGING_LEVEL > 0)
DEBUGLOG("ReadQuadletResponse: label %d isn't in use!!\n", tLabel);
#endif
}
break;
case kFWTCodeReadBlockResponse :
case kFWTCodeLockResponse :
if(fTrans[tLabel].fHandler) {
IOFWAsyncCommand * cmd = fTrans[tLabel].fHandler;
FWAddress commandAddress = cmd->getAddress();
if( sourceID == commandAddress.nodeID )
{
cmd->gotPacket((data[1] & kFWAsynchRCode)>>kFWAsynchRCodePhase,
(const void*)(data+4), (data[3] & kFWAsynchDataLength)>>kFWAsynchDataLengthPhase);
}
else
{
#if (DEBUGGING_LEVEL > 0)
DEBUGLOG( "Response from wrong node ID!\n" );
#endif
}
}
else {
#if (DEBUGGING_LEVEL > 0)
DEBUGLOG("ReadBlock/LockResponse: label %d isn't in use!!\n", tLabel);
#endif
}
break;
case kFWTCodeLock :
#if (DEBUGGING_LEVEL > 0)
DEBUGLOG("Lock type %d: addr 0x%x -> 0x%x:0x%x:0x%x\n",
(data[3] & kFWAsynchExtendedTCode) >> kFWAsynchExtendedTCodePhase, sourceID, destID,
(data[1] & kFWAsynchDestinationOffsetHigh) >> kFWAsynchDestinationOffsetHighPhase,
data[2]);
#endif
processLockRequest(sourceID, tLabel, data, &data[4],
(data[3] & kFWAsynchDataLength) >> kFWAsynchDataLengthPhase);
break;
case kFWTCodeIsochronousBlock :
#if (DEBUGGING_LEVEL > 0)
DEBUGLOG("Async Stream Packet\n");
#endif
break;
default :
#if (DEBUGGING_LEVEL > 0)
DEBUGLOG("Unexpected tcode in Asyncrecv: %d\n", tCode);
#endif
break;
}
}
IOFWPhysicalAddressSpace *
IOFireWireController::createPhysicalAddressSpace(IOMemoryDescriptor *mem)
{
IOFWPhysicalAddressSpace *space;
space = new IOFWPhysicalAddressSpace;
if(!space)
return NULL;
if(!space->initWithDesc(this, mem)) {
space->release();
space = NULL;
}
return space;
}
IOFWPseudoAddressSpace *
IOFireWireController::createPseudoAddressSpace(FWAddress *addr, UInt32 len,
FWReadCallback reader, FWWriteCallback writer, void *refcon)
{
IOFWPseudoAddressSpace *space;
space = new IOFWPseudoAddressSpace;
if(!space)
return NULL;
if(!space->initAll(this, addr, len, reader, writer, refcon)) {
space->release();
space = NULL;
}
return space;
}
IOFWPseudoAddressSpace *
IOFireWireController::createInitialAddressSpace(UInt32 addressLo, UInt32 len,
FWReadCallback reader, FWWriteCallback writer, void *refcon)
{
IOFWPseudoAddressSpace *space;
space = new IOFWPseudoAddressSpace;
if(!space)
return NULL;
if(!space->initFixed(this, FWAddress(kCSRRegisterSpaceBaseAddressHi, addressLo),
len, reader, writer, refcon)) {
space->release();
space = NULL;
}
return space;
}
IOFWAddressSpace *
IOFireWireController::getAddressSpace(FWAddress address)
{
closeGate();
IOFWAddressSpace * found;
fSpaceIterator->reset();
while( (found = (IOFWAddressSpace *) fSpaceIterator->getNextObject())) {
if(found->contains(address))
break;
}
openGate();
return found;
}
IOReturn IOFireWireController::allocAddress(IOFWAddressSpace *space)
{
IOReturn res;
closeGate();
if(!fLocalAddresses->setObject(space))
res = kIOReturnNoMemory;
else
res = kIOReturnSuccess;
openGate();
return res;
}
void IOFireWireController::freeAddress(IOFWAddressSpace *space)
{
closeGate();
fLocalAddresses->removeObject(space);
openGate();
}
IOReturn IOFireWireController::allocatePseudoAddress(FWAddress *addr, UInt32 lenDummy)
{
unsigned int i, len;
UInt8 * data;
UInt8 used = 1;
closeGate();
if( fAllocatedAddresses == NULL )
{
fAllocatedAddresses = OSData::withCapacity(4); fAllocatedAddresses->appendBytes(&used, 1); }
if( !fAllocatedAddresses )
{
openGate();
return kIOReturnNoMemory;
}
len = fAllocatedAddresses->getLength();
data = (UInt8*)fAllocatedAddresses->getBytesNoCopy();
for( i=0; i<len; i++ )
{
if( data[i] == 0 )
{
data[i] = 1;
addr->addressHi = i;
addr->addressLo = 0;
openGate();
return kIOReturnSuccess;
}
}
if( len >= 0xfffe )
{
openGate();
return kIOReturnNoMemory;
}
if( fAllocatedAddresses->appendBytes(&used, 1))
{
addr->addressHi = len;
addr->addressLo = 0;
openGate();
return kIOReturnSuccess;
}
openGate();
return kIOReturnNoMemory;
}
void IOFireWireController::freePseudoAddress(FWAddress addr, UInt32 lenDummy)
{
unsigned int len;
UInt8 * data;
closeGate();
assert( fAllocatedAddresses != NULL);
len = fAllocatedAddresses->getLength();
assert(addr.addressHi < len);
data = (UInt8*)fAllocatedAddresses->getBytesNoCopy();
assert(data[addr.addressHi]);
data[addr.addressHi] = 0;
openGate();
}
void IOFireWireController::processWriteRequest(UInt16 sourceID, UInt32 tLabel,
UInt32 *hdr, void *buf, int len)
{
UInt32 ret = kFWResponseAddressError;
IOFWSpeed speed = FWSpeed(sourceID);
FWAddress addr((hdr[1] & kFWAsynchDestinationOffsetHigh) >> kFWAsynchDestinationOffsetHighPhase, hdr[2]);
IOFWAddressSpace * found;
fSpaceIterator->reset();
while( (found = (IOFWAddressSpace *) fSpaceIterator->getNextObject())) {
ret = found->doWrite(sourceID, speed, addr, len, buf, (IOFWRequestRefCon)tLabel);
if(ret != kFWResponseAddressError)
break;
}
if ( ((hdr[0] & kFWAsynchDestinationID) >> kFWAsynchDestinationIDPhase) != 0xffff ) fFWIM->asyncWriteResponse(sourceID, speed, tLabel, ret, addr.addressHi);
else
DebugLog("Skipped asyncWriteResponse because destID=0x%x\n", ((hdr[0] & kFWAsynchDestinationID) >> kFWAsynchDestinationIDPhase));
}
void IOFireWireController::processLockRequest(UInt16 sourceID, UInt32 tLabel,
UInt32 *hdr, void *buf, int len)
{
UInt32 oldVal[2];
UInt32 ret;
UInt32 outLen =sizeof(oldVal);
int type = (hdr[3] & kFWAsynchExtendedTCode) >> kFWAsynchExtendedTCodePhase;
FWAddress addr((hdr[1] & kFWAsynchDestinationOffsetHigh) >> kFWAsynchDestinationOffsetHighPhase, hdr[2]);
IOFWSpeed speed = FWSpeed(sourceID);
IOFWRequestRefCon refcon = (IOFWRequestRefCon)(tLabel | kRequestIsLock | (type << kRequestExtTCodeShift));
ret = doLockSpace(sourceID, speed, addr, len, (const UInt32 *)buf, outLen, oldVal, type, refcon);
if(ret != kFWResponsePending)
{
if ( ((hdr[0] & kFWAsynchDestinationID) >> kFWAsynchDestinationIDPhase) != 0xffff ) fFWIM->asyncLockResponse(sourceID, speed, tLabel, ret, type, oldVal, outLen);
else
DebugLog("Skipped asyncLockResponse because destID=0x%x\n", ((hdr[0] & kFWAsynchDestinationID) >> kFWAsynchDestinationIDPhase));
}
}
UInt32 IOFireWireController::doReadSpace(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
IOMemoryDescriptor **buf, IOByteCount * offset,
IOFWRequestRefCon refcon)
{
IOFWAddressSpace * found;
UInt32 ret = kFWResponseAddressError;
fSpaceIterator->reset();
while( (found = (IOFWAddressSpace *) fSpaceIterator->getNextObject())) {
ret = found->doRead(nodeID, speed, addr, len, buf, offset,
refcon);
if(ret != kFWResponseAddressError)
break;
}
return ret;
}
UInt32 IOFireWireController::doWriteSpace(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
const void *buf, IOFWRequestRefCon refcon)
{
IOFWAddressSpace * found;
UInt32 ret = kFWResponseAddressError;
fSpaceIterator->reset();
while( (found = (IOFWAddressSpace *) fSpaceIterator->getNextObject())) {
ret = found->doWrite(nodeID, speed, addr, len, buf, refcon);
if(ret != kFWResponseAddressError)
break;
}
return ret;
}
UInt32 IOFireWireController::doLockSpace(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 inLen,
const UInt32 *newVal, UInt32 &outLen, UInt32 *oldVal, UInt32 type,
IOFWRequestRefCon refcon)
{
IOFWAddressSpace * found;
UInt32 ret = kFWResponseAddressError;
fSpaceIterator->reset();
while( (found = (IOFWAddressSpace *) fSpaceIterator->getNextObject())) {
ret = found->doLock(nodeID, speed, addr, inLen, newVal, outLen, oldVal, type, refcon);
if(ret != kFWResponseAddressError)
break;
}
if(ret != kFWResponseComplete) {
oldVal[0] = 0xdeadbabe;
outLen = 4;
}
return ret;
}
void IOFireWireController::handleARxReqIntComplete( void )
{
IOFWAddressSpace * found;
fSpaceIterator->reset();
while( (found = (IOFWAddressSpace *) fSpaceIterator->getNextObject()) )
{
IOFWPseudoAddressSpace * space = OSDynamicCast( IOFWPseudoAddressSpace, found );
if( space != NULL )
{
space->handleARxReqIntComplete();
}
}
}
bool IOFireWireController::isLockRequest(IOFWRequestRefCon refcon)
{
return ((UInt32)refcon) & kRequestIsLock;
}
bool IOFireWireController::isQuadRequest(IOFWRequestRefCon refcon)
{
return ((UInt32)refcon) & kRequestIsQuad;
}
bool IOFireWireController::isCompleteRequest(IOFWRequestRefCon refcon)
{
return ((UInt32)refcon) & kRequestIsComplete;
}
UInt32 IOFireWireController::getExtendedTCode(IOFWRequestRefCon refcon)
{
return((UInt32)refcon & kRequestExtTCodeMask) >> kRequestExtTCodeShift;
}
IOReturn IOFireWireController::asyncReadResponse( UInt32 generation,
UInt16 nodeID,
int speed,
IOMemoryDescriptor * buf,
IOByteCount offset,
int size,
IOFWRequestRefCon refcon )
{
IOReturn result;
UInt32 params = (UInt32)refcon;
UInt32 label = params & kRequestLabel;
closeGate();
if( !checkGeneration(generation) )
{
result = kIOFireWireBusReset;
}
else if( params & kRequestIsQuad )
{
UInt32 quad = 0xdeadbeef;
buf->readBytes( offset, &quad, 4 );
result = fFWIM->asyncReadQuadResponse( nodeID,
speed,
label,
kFWResponseComplete,
quad );
}
else
{
result = fFWIM->asyncReadResponse( nodeID,
speed,
label,
kFWResponseComplete,
buf,
offset,
size );
}
openGate();
return result;
}
IOReturn IOFireWireController::asyncLockResponse( UInt32 generation,
UInt16 nodeID,
int speed,
IOMemoryDescriptor * buf,
IOByteCount offset,
int size,
IOFWRequestRefCon refcon )
{
IOReturn result;
UInt32 params = (UInt32)refcon;
UInt32 label = params & kRequestLabel;
closeGate();
if( !checkGeneration(generation) )
{
result = kIOFireWireBusReset;
}
else
{
void * bytes = IOMalloc( size );
buf->readBytes( offset, bytes, size );
result = fFWIM->asyncLockResponse( nodeID,
speed,
label,
kFWResponseComplete,
getExtendedTCode(refcon),
bytes,
size );
IOFree( bytes, size );
}
openGate();
return result;
}
IOFWDelayCommand * IOFireWireController::createDelayedCmd(UInt32 uSecDelay, FWBusCallback func, void *refcon)
{
IOFWDelayCommand *delay;
delay = new IOFWDelayCommand;
if(!delay)
return NULL;
if(!delay->initWithDelay(this, uSecDelay, func, refcon))
{
delay->release();
return NULL;
}
return delay;
}
#pragma mark -
IOFWIsochChannel *IOFireWireController::createIsochChannel( bool doIRM,
UInt32 bandwidth,
IOFWSpeed prefSpeed,
FWIsochChannelForceStopNotificationProc stopProc,
void * stopRefCon )
{
IOFWIsochChannel *channel;
channel = new IOFWIsochChannel;
if(!channel)
{
return NULL;
}
if( !channel->init(this, doIRM, bandwidth, prefSpeed, stopProc, stopRefCon) )
{
channel->release();
channel = NULL;
}
return channel;
}
IOFWLocalIsochPort *IOFireWireController::createLocalIsochPort( bool talking,
DCLCommand * opcodes,
DCLTaskInfo * info,
UInt32 startEvent,
UInt32 startState,
UInt32 startMask )
{
IOFWLocalIsochPort *port;
IODCLProgram *program;
program = fFWIM->createDCLProgram( talking, opcodes, info, startEvent, startState, startMask );
if(!program)
return NULL;
port = new IOFWLocalIsochPort;
if( !port )
{
program->release();
return NULL;
}
if(!port->init(program, this))
{
port->release();
port = NULL;
}
return port;
}
void IOFireWireController::addAllocatedChannel(IOFWIsochChannel *channel)
{
closeGate();
fAllocatedChannels->setObject(channel);
openGate();
}
void IOFireWireController::removeAllocatedChannel(IOFWIsochChannel *channel)
{
closeGate();
fAllocatedChannels->removeObject(channel);
openGate();
}
#pragma mark -
IOFireWireLocalNode * IOFireWireController::getLocalNode(IOFireWireController *control)
{
OSIterator *childIterator;
IOFireWireLocalNode *localNode = NULL;
childIterator = control->getClientIterator();
if( childIterator) {
OSObject * child;
while( (child = childIterator->getNextObject())) {
localNode = OSDynamicCast(IOFireWireLocalNode, child);
if(localNode) {
break;
}
}
childIterator->release();
}
return localNode;
}
IOFireWirePowerManager * IOFireWireController::getBusPowerManager( void )
{
return fBusPowerManager;
}
IOWorkLoop * IOFireWireController::getWorkLoop() const
{
return fWorkLoop;
}
IOFireWireLink * IOFireWireController::getLink() const
{
return fFWIM;
}
IOReturn IOFireWireController::getCycleTime(UInt32 &cycleTime)
{
IOReturn res;
res = fFWIM->getCycleTime(cycleTime);
return res;
}
IOReturn IOFireWireController::getBusCycleTime(UInt32 &busTime, UInt32 &cycleTime)
{
IOReturn res;
UInt32 cycleSecs;
res = fFWIM->getBusCycleTime(busTime, cycleTime);
if(res == kIOReturnSuccess) {
cycleSecs = cycleTime >> 25;
if((busTime & 0x7F) > cycleSecs) {
cycleSecs += 0x80;
}
busTime = (busTime & ~0x7F) + cycleSecs;
}
return res;
}
UInt32 IOFireWireController::hopCount(UInt16 nodeAAddress, UInt16 nodeBAddress )
{
closeGate();
UInt32 hops = fHopCounts[(kFWMaxNodesPerBus+1)*(nodeAAddress & 63)+(nodeBAddress & 63)];
openGate();
return hops;
}
UInt32 IOFireWireController::hopCount( UInt16 nodeA )
{
closeGate();
UInt32 hops = hopCount( nodeA, fLocalNodeID );
openGate();
return hops;
}
IOFWSpeed IOFireWireController::FWSpeed(UInt16 nodeAddress) const
{
return (IOFWSpeed)fSpeedCodes[(kFWMaxNodesPerBus+1)*(nodeAddress & 63)+(fLocalNodeID & 63)];
}
IOFWSpeed IOFireWireController::FWSpeed(UInt16 nodeA, UInt16 nodeB) const
{
return (IOFWSpeed)fSpeedCodes[(kFWMaxNodesPerBus+1)*(nodeA & 63)+(nodeB & 63)];
}
void IOFireWireController::setNodeSpeed( UInt16 nodeAddress, IOFWSpeed speed )
{
fSpeedCodes[(kFWMaxNodesPerBus+1)*(nodeAddress & 63)+(fLocalNodeID & 63)] = speed;
}
int IOFireWireController::maxPackLog(bool forSend, UInt16 nodeAddress) const
{
int log;
log = 9+FWSpeed(nodeAddress);
if( forSend )
{
if( log > fMaxSendLog )
{
log = fMaxSendLog;
}
}
else
{
if( log > fMaxSendLog )
{
log = fMaxRecvLog;
}
}
if( fUseHalfSizePackets )
{
if( log > 1 )
{
log--;
}
}
return log;
}
int IOFireWireController::maxPackLog(UInt16 nodeA, UInt16 nodeB) const
{
return 9+FWSpeed(nodeA, nodeB);
}
IOFireWireDevice * IOFireWireController::nodeIDtoDevice(UInt32 generation, UInt16 nodeID)
{
OSIterator *childIterator;
IOFireWireDevice * found = NULL;
if(!checkGeneration(generation))
{
return NULL;
}
childIterator = getClientIterator();
if( childIterator)
{
OSObject *child;
while( (child = childIterator->getNextObject()))
{
found = OSDynamicCast(IOFireWireDevice, child);
if( found &&
!found->isTerminated() &&
found->fNodeID == nodeID )
{
break;
}
}
childIterator->release();
}
return found;
}
UInt32 IOFireWireController::getGeneration() const
{
return fBusGeneration;
}
bool IOFireWireController::checkGeneration(UInt32 gen) const
{
return gen == fBusGeneration;
}
UInt16 IOFireWireController::getLocalNodeID() const
{
return fLocalNodeID;
}
IOReturn IOFireWireController::getIRMNodeID(UInt32 &generation, UInt16 &id) const
{
generation = fBusGeneration;
id = fIRMNodeID;
return kIOReturnSuccess;
}
IOReturn IOFireWireController::clipMaxRec2K(Boolean clipMaxRec )
{
IOReturn res;
closeGate();
res = fFWIM->clipMaxRec2K(clipMaxRec);
openGate();
return res;
}
IOReturn IOFireWireController::makeRoot(UInt32 generation, UInt16 nodeID)
{
IOReturn res = kIOReturnSuccess;
nodeID &= 63;
closeGate();
if(!checkGeneration(generation))
res = kIOFireWireBusReset;
else if( fRootNodeID != nodeID ) {
res = fFWIM->sendPHYPacket((kFWConfigurationPacketID << kFWPhyPacketIDPhase) |
(nodeID << kFWPhyPacketPhyIDPhase) | kFWPhyConfigurationR);
if(kIOReturnSuccess == res)
{
res = resetBus();
}
}
openGate();
return res;
}
void IOFireWireController::useHalfSizePackets( void )
{
fUseHalfSizePackets = true;
fRequestedHalfSizePackets = true;
}
void IOFireWireController::disablePhyPortOnSleepForNodeID( UInt32 nodeID )
{
UInt32 childNodeID;
UInt32 childNumber = 0;
UInt32 childPort;
for( childNodeID = 0; childNodeID < fLocalNodeID; childNodeID++ )
{
if( childNodeID == nodeID )
{
IOLog( "IOFireWireController::disablePhyPortOnSleepForNodeID found child %lx\n",childNodeID);
childPort = getPortNumberFromIndex( childNumber );
if( childPort != 0xFFFFFFFF ) {
IOLog( "IOFireWireController::disablePhyPortOnSleepForNodeID disable port %lx\n",childPort);
fFWIM->disablePHYPortOnSleep( 1 << childPort );
break;
}
}
if( hopCount( childNodeID, fLocalNodeID ) == 1 )
{
childNumber++;
}
}
}
#pragma mark -
void IOFireWireController::openGate()
{
fPendingQ.fSource->openGate();
}
void IOFireWireController::closeGate()
{
fPendingQ.fSource->closeGate();
}
bool IOFireWireController::inGate()
{
return fPendingQ.fSource->inGate();
}
#pragma mark -
IOFWCmdQ& IOFireWireController::getTimeoutQ()
{
return fTimeoutQ;
}
IOFWCmdQ& IOFireWireController::getPendingQ()
{
return fPendingQ;
}
IOFWCmdQ &IOFireWireController::getAfterResetHandledQ()
{
return fAfterResetHandledQ;
}