#include <IOKit/firewire/IOFireWireFamilyCommon.h>
#include "IOFireWireIRM.h"
#include "FWDebugging.h"
#define kChannel31Mask 0x00000001
OSDefineMetaClassAndStructors( IOFireWireIRM, OSObject )
IOFireWireIRM * IOFireWireIRM::create( IOFireWireController * controller )
{
IOReturn status = kIOReturnSuccess;
IOFireWireIRM * me;
if( status == kIOReturnSuccess )
{
me = new IOFireWireIRM;
if( me == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
bool success = me->initWithController( controller );
if( !success )
{
status = kIOReturnError;
}
}
if( status != kIOReturnSuccess )
{
me = NULL;
}
FWLOCALKLOG(( "IOFireWireIRM::create() - created new IRM 0x%08lx\n", (UInt32)me ));
return me;
}
bool IOFireWireIRM::initWithController(IOFireWireController * control)
{
IOReturn status = kIOReturnSuccess;
bool success = OSObject::init();
FWPANICASSERT( success == true );
fControl = control;
fIRMNodeID = kFWBadNodeID;
fOurNodeID = kFWBadNodeID;
fGeneration = 0;
fBroadcastChannelBuffer = kBroadcastChannelInitialValues;
fBroadcastChannelAddressSpace = IOFWPseudoAddressSpace::simpleRWFixed( fControl, FWAddress(kCSRRegisterSpaceBaseAddressHi, kCSRBroadcastChannel),
sizeof(fBroadcastChannelBuffer), &fBroadcastChannelBuffer );
FWPANICASSERT( fBroadcastChannelAddressSpace != NULL );
status = fBroadcastChannelAddressSpace->activate();
FWPANICASSERT( status == kIOReturnSuccess );
fLockCmdInUse = false;
fLockCmd = new IOFWCompareAndSwapCommand;
FWPANICASSERT( fLockCmd != NULL );
fLockCmd->initAll( fControl, 0, FWAddress(), NULL, NULL, 0, IOFireWireIRM::lockCompleteStatic, this );
FWLOCALKLOG(( "IOFireWireIRM::initWithController() - IRM intialized\n" ));
return true;
}
void IOFireWireIRM::free()
{
FWLOCALKLOG(( "IOFireWireIRM::free() - freeing IRM 0x%08lx\n", (UInt32)this ));
if( fLockCmd != NULL )
{
if( fLockCmdInUse )
{
fLockCmd->cancel( kIOFireWireBusReset );
}
fLockCmd->release();
fLockCmd = NULL;
}
if( fBroadcastChannelAddressSpace != NULL)
{
fBroadcastChannelAddressSpace->deactivate();
fBroadcastChannelAddressSpace->release();
fBroadcastChannelAddressSpace = NULL;
}
OSObject::free();
}
bool IOFireWireIRM::isIRMActive( void )
{
return (fOurNodeID == fIRMNodeID && (fOurNodeID & 0x3f) != 0);
}
void IOFireWireIRM::processBusReset( UInt16 ourNodeID, UInt16 irmNodeID, UInt32 generation )
{
FWLOCALKLOG(( "IOFireWireIRM::processBusReset() - bus reset occurred\n" ));
FWLOCALKLOG(( "IOFireWireIRM::processBusReset() - ourNodeID = 0x%04x, irmNodeID = 0x%04x, generation = %d\n", ourNodeID, irmNodeID, generation ));
fIRMNodeID = irmNodeID;
fOurNodeID = ourNodeID;
fGeneration = generation;
if( isIRMActive() )
{
if( fLockCmdInUse )
{
fLockCmd->cancel( kIOFireWireBusReset );
}
fLockRetries = 8;
fOldChannels = 0;
allocateBroadcastChannel();
}
else
{
FWLOCALKLOG(( "IOFireWireIRM::processBusReset() - clear valid bit in BROADCAST_CHANNEL register\n" ));
fBroadcastChannelBuffer = kBroadcastChannelInitialValues;
}
}
void IOFireWireIRM::allocateBroadcastChannel( void )
{
IOReturn status = kIOReturnSuccess;
FWLOCALKLOG(( "IOFireWireIRM::allocateBroadcastChannel() - attempting to allocate broadcast channel\n" ));
FWAddress address( kCSRRegisterSpaceBaseAddressHi, kCSRChannelsAvailable31_0 );
address.nodeID = fIRMNodeID;
fNewChannels = fOldChannels | kChannel31Mask;
fLockCmd->reinit( fGeneration, address, &fOldChannels, &fNewChannels, 1, IOFireWireIRM::lockCompleteStatic, this );
fLockCmdInUse = true;
status = fLockCmd->submit();
}
void IOFireWireIRM::lockCompleteStatic( void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd )
{
IOFireWireIRM * me = (IOFireWireIRM*)refcon;
me->lockComplete( status );
}
void IOFireWireIRM::lockComplete( IOReturn status )
{
bool done = true;
fLockCmdInUse = false;
if( status == kIOReturnSuccess )
{
bool tryAgain = !fLockCmd->locked( &fOldChannels );
if( tryAgain && fLockRetries-- )
{
FWLOCALKLOG(( "IOFireWireIRM::lockComplete() - allocation attempt failed, will retry\n" ));
allocateBroadcastChannel();
done = false;
}
}
if( done )
{
#if FWLOCALLOGGING
if( status == kIOReturnSuccess )
{
FWLOCALKLOG(( "IOFireWireIRM::lockComplete() - successfully allocated broadcast channel\n" ));
}
else
{
FWLOCALKLOG(( "IOFireWireIRM::lockComplete() - failed to allocate broadcast channel\n" ));
}
#endif
if( status != kIOFireWireBusReset )
{
FWLOCALKLOG(( "IOFireWireIRM::lockComplete() - set valid bit in BROADCAST_CHANNEL register\n" ));
fBroadcastChannelBuffer = kBroadcastChannelInitialValues | kBroadcastChannelValidMask;
}
}
}