IOFireWireController.cpp [plain text]
#include <IOKit/assert.h>
#define DEBUGGING_LEVEL 0 // 1 = low; 2 = high; 3 = extreme
#define DEBUGLOG IOLog
#include "FWDebugging.h"
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IOMessage.h>
#include <IOKit/firewire/IOFireWireController.h>
#include <IOKit/firewire/IOFWCommand.h>
#include <IOKit/firewire/IOFireWireDevice.h>
#include <IOKit/firewire/IOFWDCLProgram.h>
#include <IOKit/firewire/IOFWLocalIsochPort.h>
#include <IOKit/firewire/IOFWAddressSpace.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/firewire/IOLocalConfigDirectory.h>
#include <IOKit/firewire/IOFireWireLink.h>
#include "IOFireLogPriv.h"
#define kScanBusDelay 100
#define kDevicePruneDelay 1000
#define kRepeatResetDelay 2000
#define FWAddressToID(addr) (addr & 63)
enum requestRefConBits {
kRequestLabel = kFWAsynchTTotal-1,
kRequestExtTCodeShift = 6,
kRequestExtTCodeMask = 0x3fffc0, 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 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}
};
class IOFireWireMagicMatchingNub : public IOService
{
OSDeclareDefaultStructors(IOFireWireMagicMatchingNub)
public:
virtual bool matchPropertyTable( OSDictionary * table );
};
OSDefineMetaClassAndStructors(IOFireWireMagicMatchingNub, IOService)
bool IOFireWireMagicMatchingNub::matchPropertyTable( OSDictionary * table )
{
OSObject *clientClass;
clientClass = table->getObject("IOClass");
if(!clientClass)
return false;
return clientClass->isEqualTo( getProperty( "IODesiredChild" ) );
}
class IOFireWireLocalNode : public IOFireWireNub
{
OSDeclareDefaultStructors(IOFireWireLocalNode)
protected:
public:
virtual void setNodeProperties(UInt32 generation, UInt16 nodeID, UInt32 *selfIDs, int numIDs);
virtual bool init(OSDictionary * propTable);
virtual bool attach(IOService * provider );
virtual void handleClose( IOService * forClient,
IOOptionBits options ) ;
virtual bool handleOpen( IOService * forClient,
IOOptionBits options,
void * arg ) ;
virtual bool handleIsOpen( const IOService * forClient ) const;
virtual IOReturn setProperties( OSObject * properties );
protected:
UInt32 fOpenCount ;
};
OSDefineMetaClassAndStructors(IOFireWireLocalNode, IOFireWireNub)
bool IOFireWireLocalNode::init(OSDictionary * propTable)
{
if(!IOFireWireNub::init(propTable))
return false;
fMaxReadROMPackLog = 11;
fMaxReadPackLog = 11;
fMaxWritePackLog = 11;
return true;
}
bool IOFireWireLocalNode::attach(IOService * provider )
{
assert(OSDynamicCast(IOFireWireController, provider));
if( !IOFireWireNub::attach(provider))
return (false);
fControl = (IOFireWireController *)provider;
return(true);
}
void IOFireWireLocalNode::setNodeProperties(UInt32 gen, UInt16 nodeID,
UInt32 *selfIDs, int numSelfIDs)
{
OSObject *prop;
fLocalNodeID = fNodeID = nodeID;
fGeneration = gen;
prop = OSNumber::withNumber(nodeID, 16);
setProperty(gFireWireNodeID, prop);
prop->release();
prop = OSData::withBytes(selfIDs, numSelfIDs*sizeof(UInt32));
setProperty(gFireWireSelfIDs, prop);
prop->release();
prop = OSNumber::withNumber((selfIDs[0] & kFWSelfID0SP) >> kFWSelfID0SPPhase, 32);
setProperty(gFireWireSpeed, prop);
prop->release();
}
bool IOFireWireLocalNode::handleOpen( IOService * forClient,
IOOptionBits options,
void * arg )
{
bool ok = true ;
if ( fOpenCount == 0)
ok = IOFireWireNub::handleOpen( this, 0, NULL ) ;
if ( ok )
fOpenCount++ ;
return ok;
}
void IOFireWireLocalNode::handleClose( IOService * forClient,
IOOptionBits options )
{
if ( fOpenCount )
{
fOpenCount-- ;
if ( fOpenCount == 0)
IOFireWireNub::handleClose( this, 0 );
}
}
bool IOFireWireLocalNode::handleIsOpen( const IOService * forClient ) const
{
return (fOpenCount > 0 ) ;
}
IOReturn IOFireWireLocalNode::setProperties( OSObject * properties )
{
OSDictionary *dict = OSDynamicCast(OSDictionary, properties);
OSDictionary *summon;
if(!dict)
return kIOReturnUnsupported;
summon = OSDynamicCast(OSDictionary, dict->getObject("SummonNub"));
if(!summon) {
return kIOReturnBadArgument;
}
IOFireWireMagicMatchingNub *nub = NULL;
IOReturn ret = kIOReturnBadArgument;
do {
nub = new IOFireWireMagicMatchingNub;
if(!nub->init(summon))
break;
if (!nub->attach(this))
break;
nub->registerService(kIOServiceSynchronous);
if(!nub->getClient()) {
nub->detach(this);
}
ret = kIOReturnSuccess;
} while (0);
if(nub)
nub->release();
return ret;
}
class IOFWQEventSource : public IOEventSource
{
OSDeclareDefaultStructors(IOFWQEventSource)
protected:
IOFWCmdQ *fQueue;
virtual bool checkForWork();
public:
bool init(IOFireWireController *owner);
inline void signalWorkAvailable() {IOEventSource::signalWorkAvailable();};
inline void openGate() {IOEventSource::openGate();};
inline void closeGate() {IOEventSource::closeGate();};
inline bool inGate( void ) {return workLoop->inGate();};
};
OSDefineMetaClassAndStructors(IOFWQEventSource, IOEventSource)
bool IOFWQEventSource::checkForWork()
{
return fQueue->executeQueue(false);
}
bool IOFWQEventSource::init(IOFireWireController *owner)
{
fQueue = &owner->getPendingQ();
return IOEventSource::init(owner);
}
IOFireWireLocalNode *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;
}
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);
void IOFireWireController::readROMGlue(void *refcon, IOReturn status,
IOFireWireNub *device, IOFWCommand *fwCmd)
{
IOFWNodeScan *scan = (IOFWNodeScan *)refcon;
scan->fControl->readDeviceROM(scan, status);
}
void IOFireWireController::clockTick(OSObject *obj, IOTimerEventSource *src)
{
IOFireWireController *me = (IOFireWireController *)obj;
me->processTimeout(src);
}
void IOFireWireController::delayedStateChange(void *refcon, IOReturn status,
IOFireWireBus *bus, IOFWBusCommand *fwCmd)
{
IOFireWireController *me = (IOFireWireController *)bus;
if(status == kIOReturnTimeout) {
switch (me->fBusState) {
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;
}
}
}
void IOFireWireController::processTimeout(IOTimerEventSource *src)
{
while (fTimeoutQ.fHead) {
AbsoluteTime now, dead;
clock_get_uptime(&now);
#if 0
IOLog("processTimeout, time is %lx:%lx\n", now.hi, now.lo);
{
IOFWCommand *t = fTimeoutQ.fHead;
while(t) {
AbsoluteTime d = t->getDeadline();
IOLog("%s:%p deadline %lx:%lx\n",
t->getMetaClass()->getClassName(), t, d.hi, d.lo);
t = t->getNext();
}
}
#endif
dead = fTimeoutQ.fHead->getDeadline();
if(CMP_ABSOLUTETIME(&dead, &now) == 1)
break; fFWIM->handleInterrupts(1);
if(!fTimeoutQ.fHead)
break;
if(CMP_ABSOLUTETIME(&dead, &fTimeoutQ.fHead->getDeadline()) != 0)
continue;
fTimeoutQ.fHead->cancel(kIOReturnTimeout);
};
if(fTimeoutQ.fHead) {
src->wakeAtTime(fTimeoutQ.fHead->getDeadline());
}
else {
src->cancelTimeout();
}
}
void IOFireWireController::timeoutQ::headChanged(IOFWCommand *oldHead)
{
#if 0
{
IOFWCommand *t = fHead;
if(oldHead)
IOLog("IOFireWireController::timeoutQ::headChanged(%s:%p)\n",
oldHead->getMetaClass()->getClassName(), oldHead);
else
IOLog("IOFireWireController::timeoutQ::headChanged(0)\n");
while(t) {
AbsoluteTime d = t->getDeadline();
IOLog("%s:%p deadline %lx:%lx\n",
t->getMetaClass()->getClassName(), t, d.hi, d.lo);
t = t->getNext();
}
}
#endif
if(!fHead) {
fTimer->cancelTimeout();
}
else {
fTimer->wakeAtTime(fHead->getDeadline());
}
}
void IOFireWireController::timeoutQ::busReset()
{
#if 0
{
IOFWCommand *t = fHead;
if(oldHead)
IOLog("IOFireWireController::timeoutQ::headChanged(%s:%p)\n",
oldHead->getMetaClass()->getClassName(), oldHead);
else
IOLog("IOFireWireController::timeoutQ::headChanged(0)\n");
while(t) {
AbsoluteTime d = t->getDeadline();
IOLog("%s:%p deadline %lx:%lx\n",
t->getMetaClass()->getClassName(), t, d.hi, d.lo);
t = t->getNext();
}
}
#endif
IOFWCommand *cmd;
cmd = fHead;
while(cmd) {
IOFWCommand *next;
next = cmd->getNext();
if(cmd->cancelOnReset()) {
cmd->cancel(kIOFireWireBusReset);
}
cmd = next;
}
}
void IOFireWireController::pendingQ::headChanged(IOFWCommand *oldHead)
{
if(fHead) {
fSource->signalWorkAvailable();
}
}
bool IOFireWireController::init(IOFireWireLink *fwim)
{
if(!IOFireWireBus::init())
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");
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;
UInt32 bad = 0xdeadbabe;
fBadReadResponse = IOBufferMemoryDescriptor::withBytes(&bad, sizeof(bad), kIODirectionOutIn);
fDelayedStateChangeCmdNeedAbort = false;
fDelayedStateChangeCmd = createDelayedCmd(1000 * kScanBusDelay, delayedStateChange, NULL);
fBusResetStateChangeCmd = createDelayedCmd(1000 * kRepeatResetDelay, resetStateChange, NULL);
return (gFireWireROM != NULL && gFireWireNodeID != NULL &&
gFireWireUnit_Spec_ID != NULL && gFireWireUnit_SW_Version != NULL &&
fLocalAddresses != NULL && fSpaceIterator != NULL &&
fAllocatedChannels != NULL && fAllocChannelIterator != NULL &&
fBadReadResponse != NULL);
}
void IOFireWireController::free()
{
if(fROMAddrSpace) {
fROMAddrSpace->release();
}
if(fRootDir)
fRootDir->release();
if(fBadReadResponse)
fBadReadResponse->release();
if(fDelayedStateChangeCmd)
fDelayedStateChangeCmd->release();
if(fBusResetStateChangeCmd)
fBusResetStateChangeCmd->release();
if(fSpaceIterator) {
fSpaceIterator->release();
}
if(fLocalAddresses)
fLocalAddresses->release();
if(fAllocChannelIterator) {
fAllocChannelIterator->release();
}
if(fAllocatedChannels)
fAllocatedChannels->release();
fWorkLoop->removeEventSource(fTimer);
fTimer->release();
fWorkLoop->removeEventSource(fPendingQ.fSource);
fPendingQ.fSource->release();
IOFireWireBus::free();
}
IOReturn IOFireWireController::setPowerState( unsigned long powerStateOrdinal,
IOService* whatDevice )
{
IOReturn res;
IOReturn sleepRes;
if(fBusState != kAsleep || fROMHeader[1] != kFWBIBBusName) {
fPendingQ.fSource->closeGate();
}
else {
sleepRes = fWorkLoop->wake(&fBusState);
if(sleepRes != kIOReturnSuccess) {
IOLog("Can't wake FireWire workloop, error 0x%x\n", sleepRes);
}
}
if(powerStateOrdinal != 0)
{
fBusState = kRunning; if( fDelayedStateChangeCmdNeedAbort )
{
fDelayedStateChangeCmdNeedAbort = false;
fDelayedStateChangeCmd->cancel(kIOReturnAborted);
}
}
if(powerStateOrdinal == 0)
fFWIM->resetBus();
res = fFWIM->setLinkPowerState(powerStateOrdinal);
if(powerStateOrdinal == 1 && res == IOPMAckImplied && fROMHeader[1] == kFWBIBBusName)
{
if ( kIOReturnSuccess != UpdateROM() )
IOLog(" %s %u: UpdateROM() got error\n", __FILE__, __LINE__ ) ;
fFWIM->resetBus(); }
if(powerStateOrdinal == 0) {
if( fBusState == kWaitingPrune || fBusState == kWaitingScan )
{
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 {
fPendingQ.fSource->openGate();
}
return res;
}
bool IOFireWireController::start(IOService *provider)
{
UInt16 crc16;
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();
}
}
fTimer = IOTimerEventSource::timerEventSource(this, clockTick);
if(!fTimer)
return false;
fTimeoutQ.fTimer = fTimer;
IOFWQEventSource *q;
q = new IOFWQEventSource;
fPendingQ.fSource = q;
q->init(this);
fWorkLoop = fFWIM->getFireWireWorkLoop();
fWorkLoop->addEventSource(fTimer);
fWorkLoop->addEventSource(fPendingQ.fSource);
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));
fROMHeader[1] = kFWBIBBusName;
fROMHeader[2] = fFWIM->getBusCharacteristics();
fMaxRecvLog = ((fROMHeader[2] & kFWBIBMaxRec) >> kFWBIBMaxRecPhase)+1;
fMaxSendLog = fFWIM->getMaxSendLog();
fROMHeader[3] = guid >> 32;
fROMHeader[4] = guid & 0xffffffff;
crc16 = FWComputeCRC16 (&fROMHeader[1], 4);
fROMHeader[0] = 0x04040000 | crc16;
fRootDir = IOLocalConfigDirectory::create();
if(!fRootDir)
return false;
fRootDir->addEntry(kConfigGenerationKey, (UInt32)0);
fRootDir->addEntry(kConfigModuleVendorIdKey, 0x00A040);
fRootDir->addEntry(kConfigNodeCapabilitiesKey, 0x000083C0);
OSData *t = OSData::withBytes(&guid, sizeof(guid));
fRootDir->addEntry(kConfigNodeUniqueIdKey, t);
fTimer->enable();
IOFireWireLocalNode *localNode = new IOFireWireLocalNode;
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 FIRELOG
fFireLogPublisher = IOFireLogPublisher::create( this );
#endif
res = UpdateROM();
if(res == kIOReturnSuccess)
res = fFWIM->resetBus();
fWorkLoop->enableAllInterrupts();
registerService();
return res == kIOReturnSuccess;
}
void IOFireWireController::stop( IOService * provider )
{
processBusReset();
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);
}
fPendingQ.fSource->openGate();
}
IOService::stop(provider);
}
bool IOFireWireController::finalize( IOOptionBits options )
{
bool res;
#if FIRELOG
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->isInactive() && found->isOpen())
{
messageClient( kIOFWMessageServiceIsRequestingClose, found );
}
}
childIterator->release();
}
IOFireWireLocalNode *localNode = getLocalNode(this);
if(localNode) {
localNode->release();
}
return IOService::requestTerminate(provider, options);
}
IOWorkLoop *IOFireWireController::getWorkLoop() const
{
return fWorkLoop;
}
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 codes!\n");
return NULL;
}
void IOFireWireController::freeTrans(AsyncPendingTrans *trans)
{
trans->fHandler = NULL;
trans->fInUse = false;
}
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;
}
OSDictionary *propTable;
UInt32 nodeID = FWAddressToID(scan->fAddr.nodeID);
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;
}
}
fNodes[nodeID] = newPhy;
if(propTable)
propTable->release();
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->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->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];
childIterator = getClientIterator();
if( childIterator) {
OSObject *child;
while( (child = childIterator->getNextObject())) {
IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
if(found && found->fUniqueID == guid && !found->isInactive()) {
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" ));
}
void IOFireWireController::processBusReset()
{
FWKLOG(( "IOFireWireController::processBusReset\n" ));
clock_get_uptime(&fResetTime);
fBusResetScheduled = false;
if( fBusResetState == kResetStateDisabled )
fBusResetStateChangeCmd->cancel( kIOReturnAborted );
fBusResetState = kResetStateDisabled;
fBusResetStateChangeCmd->reinit( 1000 * kRepeatResetDelay, resetStateChange, NULL );
fBusResetStateChangeCmd->submit();
if(fBusState != kWaitingSelfIDs) {
if(fBusState == kWaitingPrune || fBusState == kWaitingScan )
fDelayedStateChangeCmd->cancel(kIOReturnAborted);
fBusState = kWaitingSelfIDs;
unsigned int i;
UInt32 oldgen = fBusGeneration;
fBusGeneration++;
OSIterator *childIterator;
childIterator = getClientIterator();
if( childIterator) {
OSObject * child;
while( (child = childIterator->getNextObject())) {
IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
if(found && !found->isInactive())
found->setNodeROM(oldgen, kFWBadNodeID, NULL);
else if(OSDynamicCast(IOFireWireLocalNode, child)) {
((IOFireWireLocalNode *)child)->messageClients(kIOMessageServiceIsSuspended);
}
}
childIterator->release();
}
bzero(fSpeedCodes, sizeof(fSpeedCodes));
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();
}
}
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();
fBusState = kWaitingScan;
fRootNodeID = ourID = (*ownIDs & kFWPhyPacketPhyID) >> kFWPhyPacketPhyIDPhase;
fLocalNodeID = ourID | (kFWLocalBusAddress>>kCSRNodeIDPhase);
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 );
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, (fRootNodeID+1) * 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;
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" ));
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->fCmd = new IOFWReadQuadCommand;
scan->fCmd->initAll(this, fBusGeneration, scan->fAddr, scan->fBuf, 1,
&readROMGlue, scan);
scan->fCmd->submit();
}
}
if(fNumROMReads == 0) {
finishedBusScan();
}
FWKLOG(( "IOFireWireController::startBusScan exited\n" ));
}
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)
{
fBusState = kWaitingPrune; fDelayedStateChangeCmd->reinit(1000 * kDevicePruneDelay, 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" ));
}
void IOFireWireController::buildTopology(bool doFWPlane)
{
int i, maxDepth;
IORegistryEntry *root;
struct FWNodeScan
{
int nodeID;
int childrenRemaining;
IORegistryEntry *node;
};
FWNodeScan scanList[kFWMaxNodeHops];
FWNodeScan *level;
maxDepth = 0;
root = fNodes[fRootNodeID];
level = scanList;
for(i=fRootNodeID; i>=0; i--) {
UInt32 id0, idn;
UInt32 *idPtr;
UInt8 speedCode;
IORegistryEntry *node = fNodes[i];
int children = 0;
int ports;
UInt32 port;
int mask, shift;
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;
}
}
}
level->nodeID = i;
level->childrenRemaining = children;
level->node = node;
speedCode = (id0 & kFWSelfID0SP) >> kFWSelfID0SPPhase;
fSpeedCodes[(kFWMaxNodesPerBus + 1)*i + i] = speedCode;
if (i != fRootNodeID) {
int parentNodeNum, scanNodeNum;
parentNodeNum = (level-1)->nodeID;
if(doFWPlane)
node->attachToParent((level-1)->node, gIOFireWirePlane);
for (scanNodeNum = i + 1; scanNodeNum <= fRootNodeID; scanNodeNum++) {
UInt8 scanSpeedCode;
scanSpeedCode =
fSpeedCodes[(kFWMaxNodesPerBus + 1)*parentNodeNum + scanNodeNum];
if (speedCode < scanSpeedCode)
scanSpeedCode = speedCode;
fSpeedCodes[(kFWMaxNodesPerBus + 1)*i + scanNodeNum] = scanSpeedCode;
fSpeedCodes[(kFWMaxNodesPerBus + 1)*scanNodeNum + i] = scanSpeedCode;
}
}
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(doFWPlane)
root->attachToParent(IORegistryEntry::getRegistryRoot(), gIOFireWirePlane);
}
void IOFireWireController::updatePlane()
{
OSIterator *childIterator;
childIterator = getClientIterator();
if( childIterator) {
OSObject *child;
while( (child = childIterator->getNextObject())) {
IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
if(found && !found->isInactive() && found->fNodeID == kFWBadNodeID) {
if( found->isOpen() )
{
messageClient( kIOFWMessageServiceIsRequestingClose, found );
}
else
{
IOFireWireDevice::terminateDevice( found );
}
}
}
childIterator->release();
}
buildTopology(true);
}
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;
}
fFWIM->asyncWriteResponse(sourceID, speed, tLabel, ret, addr.addressHi);
}
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)
{
fFWIM->asyncLockResponse(sourceID, speed, tLabel, ret, type, oldVal, outLen);
}
}
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::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;
quad0 = *data;
tCode = (quad0 & kFWPacketTCode) >> kFWPacketTCodePhase;
tLabel = (quad0 & kFWAsynchTLabel) >> kFWAsynchTLabelPhase;
sourceID = (data[1] & kFWAsynchSourceID) >> kFWAsynchSourceIDPhase;
switch (tCode)
{
case kFWTCodeWriteQuadlet :
#if (DEBUGGING_LEVEL > 0)
DEBUGLOG("WriteQuadlet: addr 0x%x:0x%x\n",
(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\n",
(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\n",
(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) {
IOByteCount lengthOfSegment;
fFWIM->asyncReadQuadResponse(sourceID, speed, tLabel, ret,
*(UInt32 *)buf->getVirtualSegment(offset, &lengthOfSegment));
}
else {
fFWIM->asyncReadQuadResponse(sourceID, speed, tLabel, ret, 0xdeadbeef);
}
}
break;
case kFWTCodeReadBlock :
#if (DEBUGGING_LEVEL > 0)
DEBUGLOG("ReadBlock: addr 0x%x:0x%x len %d\n",
(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) {
fFWIM->asyncReadResponse(sourceID, speed,
tLabel, ret, buf, offset, length);
}
else {
fFWIM->asyncReadResponse(sourceID, speed,
tLabel, ret, fBadReadResponse, 0, 4);
}
}
break;
case kFWTCodeReadQuadletResponse :
if(fTrans[tLabel].fHandler) {
IOFWAsyncCommand * cmd = fTrans[tLabel].fHandler;
cmd->gotPacket((data[1] & kFWAsynchRCode)>>kFWAsynchRCodePhase,
(const void*)(data+3), 4);
}
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;
cmd->gotPacket((data[1] & kFWAsynchRCode)>>kFWAsynchRCodePhase,
(const void*)(data+4), (data[3] & kFWAsynchDataLength)>>kFWAsynchDataLengthPhase);
}
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\n",
(data[3] & kFWAsynchExtendedTCode) >> kFWAsynchExtendedTCodePhase,
(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;
}
}
IOReturn IOFireWireController::getCycleTime(UInt32 &cycleTime)
{
IOReturn res;
fPendingQ.fSource->closeGate();
res = fFWIM->getCycleTime(cycleTime);
fPendingQ.fSource->openGate();
return res;
}
IOReturn IOFireWireController::getBusCycleTime(UInt32 &busTime, UInt32 &cycleTime)
{
IOReturn res;
UInt32 cycleSecs;
fPendingQ.fSource->closeGate();
res = fFWIM->getBusCycleTime(busTime, cycleTime);
fPendingQ.fSource->openGate();
if(res == kIOReturnSuccess) {
cycleSecs = cycleTime >> 25;
if((busTime & 0x7F) > cycleSecs) {
cycleSecs += 0x80;
}
busTime = (busTime & ~0x7F) + cycleSecs;
}
return res;
}
IOReturn IOFireWireController::allocAddress(IOFWAddressSpace *space)
{
IOReturn res;
fPendingQ.fSource->closeGate();
if(!fLocalAddresses->setObject(space))
res = kIOReturnNoMemory;
else
res = kIOReturnSuccess;
fPendingQ.fSource->openGate();
return res;
}
void IOFireWireController::freeAddress(IOFWAddressSpace *space)
{
fPendingQ.fSource->closeGate();
fLocalAddresses->removeObject(space);
fPendingQ.fSource->openGate();
}
void IOFireWireController::addAllocatedChannel(IOFWIsochChannel *channel)
{
fPendingQ.fSource->closeGate();
fAllocatedChannels->setObject(channel);
fPendingQ.fSource->openGate();
}
void IOFireWireController::removeAllocatedChannel(IOFWIsochChannel *channel)
{
fPendingQ.fSource->closeGate();
fAllocatedChannels->removeObject(channel);
fPendingQ.fSource->openGate();
}
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->isInactive() && found->fNodeID == nodeID)
break;
}
childIterator->release();
}
return found;
}
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,
DCLCommandStruct *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;
}
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;
}
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)
{
fPendingQ.fSource->closeGate();
IOFWAddressSpace * found;
fSpaceIterator->reset();
while( (found = (IOFWAddressSpace *) fSpaceIterator->getNextObject())) {
if(found->contains(address))
break;
}
fPendingQ.fSource->openGate();
return found;
}
IOReturn IOFireWireController::AddUnitDirectory(IOLocalConfigDirectory *unitDir)
{
IOReturn res;
fPendingQ.fSource->closeGate();
getRootDir()->addEntry(kConfigUnitDirectoryKey, unitDir);
res = UpdateROM();
if(res == kIOReturnSuccess)
res = resetBus();
fPendingQ.fSource->openGate();
return res;
}
IOReturn IOFireWireController::RemoveUnitDirectory(IOLocalConfigDirectory *unitDir)
{
IOReturn res;
fPendingQ.fSource->closeGate();
getRootDir()->removeSubDir(unitDir);
res = UpdateROM();
if(res == kIOReturnSuccess)
res = resetBus();
fPendingQ.fSource->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);
}
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, lengthOfSegment;
IOFWSpeed temp = (IOFWSpeed)speed;
rcode = doReadSpace(nodeID, temp, FWAddress(addrHi, addrLo), size,
&buf, &offset, (IOFWRequestRefCon)label);
if(rcode == kFWResponseComplete)
cmd->gotPacket(rcode, buf->getVirtualSegment(offset, &lengthOfSegment), size);
else
cmd->gotPacket(rcode, NULL, 0);
return kIOReturnSuccess;
}
else
return fFWIM->asyncRead(nodeID, addrHi, addrLo, speed, label, size, cmd);
}
IOReturn IOFireWireController::asyncWrite(UInt32 generation, UInt16 nodeID, UInt16 addrHi, UInt32 addrLo,
int speed, int label, IOMemoryDescriptor *buf, IOByteCount offset,
int size, IOFWAsyncCommand *cmd)
{
if(!checkGeneration(generation)) {
return (kIOFireWireBusReset);
}
if(nodeID == fLocalNodeID) {
UInt32 rcode;
IOByteCount lengthOfSegment;
IOFWSpeed temp = (IOFWSpeed)speed;
rcode = doWriteSpace(nodeID, temp, FWAddress(addrHi, addrLo), size,
buf->getVirtualSegment(offset, &lengthOfSegment), (IOFWRequestRefCon)label);
cmd->gotPacket(rcode, NULL, 0);
return kIOReturnSuccess;
}
else
return fFWIM->asyncWrite(nodeID, addrHi, addrLo, speed, label, buf, offset, size, cmd);
}
IOReturn IOFireWireController::asyncWrite(UInt32 generation, UInt16 nodeID, UInt16 addrHi, UInt32 addrLo,
int speed, int label, void *data, int size, IOFWAsyncCommand *cmd)
{
if(!checkGeneration(generation)) {
return (kIOFireWireBusReset);
}
if(nodeID == fLocalNodeID) {
UInt32 rcode;
IOFWSpeed temp = (IOFWSpeed)speed;
rcode = doWriteSpace(nodeID, temp, FWAddress(addrHi, addrLo), size,
data, (IOFWRequestRefCon)label);
cmd->gotPacket(rcode, NULL, 0);
return kIOReturnSuccess;
}
else
return fFWIM->asyncWrite(nodeID, addrHi, addrLo, speed, label, data, size, cmd);
}
IOReturn IOFireWireController::asyncLock(UInt32 generation, UInt16 nodeID, UInt16 addrHi, UInt32 addrLo,
int speed, int label, int type, void *data, 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));
rcode = doLockSpace(nodeID, temp, FWAddress(addrHi, addrLo), size,
(const UInt32 *)data, retSize, retVals, type, refcon);
cmd->gotPacket(rcode, retVals, retSize);
return kIOReturnSuccess;
}
else
return fFWIM->asyncLock(nodeID, addrHi, addrLo, speed, label, type, data, size, cmd);
}
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;
IOByteCount lengthOfSegment;
fPendingQ.fSource->closeGate();
if(!checkGeneration(generation))
result = kIOFireWireBusReset;
else if(params & kRequestIsQuad)
result = fFWIM->asyncReadQuadResponse(nodeID, speed, label, kFWResponseComplete,
*(UInt32 *)buf->getVirtualSegment(offset, &lengthOfSegment));
else
result = fFWIM->asyncReadResponse(nodeID, speed, label, kFWResponseComplete, buf, offset, size);
fPendingQ.fSource->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;
fPendingQ.fSource->closeGate();
if(!checkGeneration(generation))
result = kIOFireWireBusReset;
else
{
IOByteCount dataSize = size ;
void* data = buf->getVirtualSegment( offset, & dataSize ) ;
result = fFWIM->asyncLockResponse(nodeID, speed, label, kFWResponseComplete, getExtendedTCode(refcon), data, size);
}
fPendingQ.fSource->openGate();
return result;
}
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;
return log;
}
int IOFireWireController::maxPackLog(UInt16 nodeA, UInt16 nodeB) const
{
return 9+FWSpeed(nodeA, nodeB);
}
IOReturn IOFireWireController::handleAsyncTimeout(IOFWAsyncCommand *cmd)
{
return fFWIM->handleAsyncTimeout(cmd);
}
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::openGate()
{
fPendingQ.fSource->openGate();
}
void IOFireWireController::closeGate()
{
fPendingQ.fSource->closeGate();
}
bool IOFireWireController::inGate()
{
return fPendingQ.fSource->inGate();
}
void IOFireWireController::doBusReset( void )
{
IOReturn status = kIOReturnSuccess;
if( fDelayedPhyPacket )
{
fFWIM->sendPHYPacket( fDelayedPhyPacket );
fDelayedPhyPacket = 0x00000000;
}
FWKLOG(( "IOFireWireController::doBusReset\n" ));
fBusResetState = kResetStateResetting;
status = fFWIM->resetBus();
}
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();
}
IOReturn IOFireWireController::makeRoot(UInt32 generation, UInt16 nodeID)
{
IOReturn res = kIOReturnSuccess;
nodeID &= 63;
fPendingQ.fSource->closeGate();
if(!checkGeneration(generation))
res = kIOFireWireBusReset;
else if( fRootNodeID != nodeID ) {
res = fFWIM->sendPHYPacket((kFWConfigurationPacketID << kFWPhyPacketIDPhase) |
(nodeID << kFWPhyPacketPhyIDPhase) | kFWPhyConfigurationR);
if(kIOReturnSuccess == res)
{
res = resetBus();
}
}
fPendingQ.fSource->openGate();
return res;
}
bool IOFireWireController::isLockRequest(IOFWRequestRefCon refcon)
{
return ((UInt32)refcon) & kRequestIsLock;
}
bool IOFireWireController::isQuadRequest(IOFWRequestRefCon refcon)
{
return ((UInt32)refcon) & kRequestIsQuad;
}
UInt32 IOFireWireController::getExtendedTCode(IOFWRequestRefCon refcon)
{
return((UInt32)refcon & kRequestExtTCodeMask) >> kRequestExtTCodeShift;
}
IOFWCmdQ& IOFireWireController::getTimeoutQ()
{
return fTimeoutQ;
}
IOFWCmdQ& IOFireWireController::getPendingQ()
{
return fPendingQ;
}
IOFWCmdQ &IOFireWireController::getAfterResetHandledQ()
{
return fAfterResetHandledQ;
}
IOFireWireLink * IOFireWireController::getLink() const
{
return fFWIM;
}
IOLocalConfigDirectory * IOFireWireController::getRootDir() const
{
return fRootDir;
}
bool IOFireWireController::checkGeneration(UInt32 gen) const
{
return gen == fBusGeneration;
}
UInt32 IOFireWireController::getGeneration() const
{
return fBusGeneration;
}
UInt16 IOFireWireController::getLocalNodeID() const
{
return fLocalNodeID;
}
IOReturn IOFireWireController::getIRMNodeID(UInt32 &generation, UInt16 &id) const
{
generation = fBusGeneration;
id = fIRMNodeID;
return kIOReturnSuccess;
}
const AbsoluteTime * IOFireWireController::getResetTime() const
{
return &fResetTime;
}
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)];
}
bool IOFireWireController::scanningBus() const
{
return fBusState == kWaitingSelfIDs || fBusState == kWaitingScan || fBusState == kScanning;
}
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();
}