IOFireWireAVCLibConsumer.cpp [plain text]
#include "IOFireWireAVCLibUnit.h"
#include "IOFireWireAVCConsts.h"
#include "IOFireWireAVCLibConsumer.h"
#include <IOKit/IOMessage.h>
#include <unistd.h>
#define FWLOGGING 0
#define FWASSERTING 0
#if FWLOGGING
#define FWLOG(x) printf x
#else
#define FWLOG(x) do {} while (0)
#endif
#if FWASSERTING
#define FWLOGASSERT(a) { if(!(a)) { printf( "File "__FILE__", line %d: assertion '%s' failed.\n", __LINE__, #a); } }
#else
#define FWLOGASSERT(a) do {} while (0)
#endif
#define kProducerHeartbeatTime 5.0 // 5.0 seconds
#define kConsumerHeartbeatTime 3.0 // 3.0 seconds
#define kReconnectTime 10.0 // 10.0 seconds
enum
{
kFWAVCStatePrivBusSuspended = 0,
kFWAVCStatePrivBusResumed = 1,
kFWAVCStatePrivPlugSuspended = 3,
kFWAVCStatePrivPlugConnected = 4
};
enum
{
kFWAVCConsumerPlugCountMask = 0x00ffffff,
kFWAVCConsumerPlugCountPhase = 0,
kFWAVCConsumerPlugSCMask = 0x01000000,
kFWAVCConsumerPlugSCPhase = 24,
kFWAVCConsumerPlugModeMask = 0x0E000000,
kFWAVCConsumerPlugModePhase = 25,
kFWAVCConsumerPlugHBMask = 0x10000000,
kFWAVCConsumerPlugHBPhase = 28
};
enum
{
kFWAVCConsumerMode_FREE = 0,
kFWAVCConsumerMode_SUSPENDED = 2
};
enum
{
kFWAVCProducerMode_FREE = 0,
kFWAVCProducerMode_SUSPEND = 2,
kFWAVCProducerMode_RESUME = 4
};
enum
{
kAVCConcurrentWrites = 0x1,
kAVCMulticast = 0x2
};
enum
{
ASYNCHRONOUS_CONNECTION = 0x26,
ALLOCATE_ATTACH = 0x03,
DETACH_RELEASE = 0x07,
RESTORE_PORT = 0x40
};
#define AddressHi(poa) ((poa) & 0x0000ffff)
#define AddressLo_PortBits(poa,pbits) ( ((poa) & 0xfffffffc) | ((pbits) & 0x00000003) )
#define AddressLoToMaskedPortID(a) (0xffffffc3 | ((a) & 0x0000003c))
#define Ex_ConnectionCount(ex,con) (((ex) << 7) | ((con) & 0x3f))
#define WriteInterval_RetryCount(wi,rc) (((wi) << 4) | ((rc) & 0x0000000f))
enum
{
kAVCProducerRunBit = 0x00000020,
kAVCProducerHBBit = 0x10000000,
kAVCProducerSCBit = 0x01000000
};
#define oAPR(mode,count,flags,max) ( (flags) | (((mode) & 0x00000007) << 25) | \
((count) & 0x00ffffc0) | ((max) & 0x0000000f) )
typedef struct
{
UInt8 command_type;
UInt8 header_address;
UInt8 opcode;
UInt8 subfunction;
UInt8 status;
UInt8 plug_id;
UInt16 plug_offset_hi;
UInt32 plug_offset_lo;
UInt16 connected_node_id;
UInt16 connected_plug_offset_hi;
UInt32 connected_plug_offset_lo;
UInt8 connected_plug_id;
UInt8 connection_count;
UInt8 write_interval_retry_count;
UInt8 reserved;
} ACAVCCommand;
IOFireWireAVCLibConsumerInterface
IOFireWireAVCLibConsumer::sIOFireWireAVCLibConsumerInterface =
{
0,
&IOFireWireAVCLibConsumer::queryInterface,
&IOFireWireAVCLibConsumer::comAddRef,
&IOFireWireAVCLibConsumer::comRelease,
1, 0, &IOFireWireAVCLibConsumer::setSubunit,
&IOFireWireAVCLibConsumer::setRemotePlug,
&IOFireWireAVCLibConsumer::connectToRemotePlug,
&IOFireWireAVCLibConsumer::disconnectFromRemotePlug,
&IOFireWireAVCLibConsumer::setFrameStatusHandler,
&IOFireWireAVCLibConsumer::frameProcessed,
&IOFireWireAVCLibConsumer::setMaxPayloadSize,
&IOFireWireAVCLibConsumer::setSegmentSize,
&IOFireWireAVCLibConsumer::getSegmentSize,
&IOFireWireAVCLibConsumer::getSegmentBuffer,
&IOFireWireAVCLibConsumer::setPortStateHandler,
&IOFireWireAVCLibConsumer::setPortFlags,
&IOFireWireAVCLibConsumer::clearPortFlags,
&IOFireWireAVCLibConsumer::getPortFlags
};
CFArrayCallBacks IOFireWireAVCLibConsumer::sArrayCallbacks =
{
0, &IOFireWireAVCLibConsumer::cfAddRef, &IOFireWireAVCLibConsumer::cfRelease, NULL, NULL, };
IOFireWireAVCLibConsumer::IOFireWireAVCLibConsumer( void )
{
fIOFireWireAVCLibConsumerInterface.pseudoVTable = (IUnknownVTbl *) &sIOFireWireAVCLibConsumerInterface;
fIOFireWireAVCLibConsumerInterface.obj = this;
fRefCount = 0;
fAVCUnit = NULL;
fFWUnit = NULL;
fCFRunLoop = NULL;
fService = NULL;
fGeneration = 0;
fHeartbeatResponseSource = NULL;
fHeartbeatResponseSourceInfo = this;
fHeartbeatResponseScheduled = false;
fConsumerHeartbeatTimer = NULL;
fProducerHeartbeatTimer = NULL;
fReconnectTimer = NULL;
fFlags = 0;
fSubunit = 0;
fLocalPlugNumber = 0;
fRemotePlugNumber = 0;
fRemotePlugAddress = 0;
fRemotePlugOptions = 0;
fMaxPayloadLog = 0x5; fSegmentBitState = true;
fHeartbeatBitState = false;
fMode = 0;
fInputPlugRegisterBuffer = 0x00000000;
fOutputPlugRegisterBuffer = 0x00000000;
fState = 0;
fStateHandlerRefcon = 0;
fStateHandler = 0;
fSegmentSize = 0;
fSegmentBuffer = NULL;
fPlugAddressSpace = NULL;
fFrameStatusSource = NULL;
fFrameStatusSourceInfo = this;
fFrameStatusSourceScheduled = false;
fFrameStatusHandler = NULL;
fFrameStatusHandlerRefcon = 0;
fDisconnectResponseSource = NULL;
fDisconnectResponseSourceInfo = this;
fDisconnectResponseScheduled = false;
}
void IOFireWireAVCLibConsumer::finalize( void )
{
stopReconnectTimer();
stopProducerHeartbeatTimer();
stopConsumerHeartbeatTimer();
releaseSegment();
if( fHeartbeatResponseSource != NULL )
{
CFRunLoopSourceInvalidate( fHeartbeatResponseSource );
CFRelease( fHeartbeatResponseSource );
fHeartbeatResponseSource = NULL;
}
if( fFrameStatusSource != NULL )
{
CFRunLoopSourceInvalidate( fFrameStatusSource );
CFRelease( fFrameStatusSource );
fFrameStatusSource = NULL;
}
if( fDisconnectResponseSource != NULL )
{
CFRunLoopSourceInvalidate( fDisconnectResponseSource );
CFRelease( fDisconnectResponseSource );
fDisconnectResponseSource = NULL;
}
pthread_mutex_destroy( &fLock );
if( fFWUnit )
{
(*fFWUnit)->RemoveCallbackDispatcherFromRunLoop( fFWUnit );
(*fFWUnit)->Close( fFWUnit );
(*fFWUnit)->Release( fFWUnit );
fFWUnit = NULL;
}
}
IOFireWireAVCLibConsumer::~IOFireWireAVCLibConsumer()
{
if( fAVCUnit )
{
(*fAVCUnit)->Release( fAVCUnit );
fAVCUnit = NULL;
}
}
IUnknownVTbl ** IOFireWireAVCLibConsumer::alloc( IOFireWireAVCLibUnitInterface ** avcUnit,
CFRunLoopRef cfRunLoop,
UInt8 plugNumber )
{
IOReturn status = kIOReturnSuccess;
IOFireWireAVCLibConsumer * me;
IUnknownVTbl ** interface = NULL;
if( status == kIOReturnSuccess )
{
me = new IOFireWireAVCLibConsumer();
if( me == NULL )
status = kIOReturnError;
}
if( status == kIOReturnSuccess )
{
status = me->init( avcUnit, cfRunLoop, plugNumber );
}
if( status != kIOReturnSuccess )
delete me;
if( status == kIOReturnSuccess )
{
IOFireWireAVCLibConsumer::addRef(me);
interface = (IUnknownVTbl **) &me->fIOFireWireAVCLibConsumerInterface.pseudoVTable;
}
return interface;
}
IOReturn IOFireWireAVCLibConsumer::init( IOFireWireAVCLibUnitInterface ** avcUnit,
CFRunLoopRef cfRunLoop,
UInt8 plugNumber )
{
IOReturn status = kIOReturnSuccess;
if( avcUnit == NULL || cfRunLoop == NULL ||
plugNumber < kFWAVCAsyncPlug0 || plugNumber > kFWAVCAsyncPlug30 )
{
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
fAVCUnit = avcUnit;
(*fAVCUnit)->AddRef( fAVCUnit );
fCFRunLoop = cfRunLoop;
fLocalPlugNumber = plugNumber;
pthread_mutex_init( &fLock, NULL );
}
if( status == kIOReturnSuccess )
{
CFRunLoopSourceContext context = { 0, &fDisconnectResponseSourceInfo, nil, nil, nil, nil, nil, nil, nil, sendDisconnectResponse };
fDisconnectResponseSource = CFRunLoopSourceCreate( kCFAllocatorDefault, 0, &context );
if( fDisconnectResponseSource == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
CFRunLoopAddSource( fCFRunLoop, fDisconnectResponseSource, kCFRunLoopDefaultMode );
}
if( status == kIOReturnSuccess )
{
CFRunLoopSourceContext context = { 0, &fFrameStatusSourceInfo, nil, nil, nil, nil, nil, nil, nil, sendFrameStatusNotification };
fFrameStatusSource = CFRunLoopSourceCreate( kCFAllocatorDefault, 0, &context );
if( fFrameStatusSource == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
CFRunLoopAddSource( fCFRunLoop, fFrameStatusSource, kCFRunLoopDefaultMode );
}
if( status == kIOReturnSuccess )
{
CFRunLoopSourceContext context = { 0, &fHeartbeatResponseSourceInfo, nil, nil, nil, nil, nil, nil, nil, sendHeartbeatResponse };
fHeartbeatResponseSource = CFRunLoopSourceCreate( kCFAllocatorDefault, 0, &context );
if( fHeartbeatResponseSource == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
CFRunLoopAddSource( fCFRunLoop, fHeartbeatResponseSource, kCFRunLoopDefaultMode );
}
if( status == kIOReturnSuccess )
{
fFWUnit = (IOFireWireDeviceInterface**)(*fAVCUnit)->getAncestorInterface( fAVCUnit,
"IOFireWireUnit",
CFUUIDGetUUIDBytes(kIOFireWireLibTypeID),
CFUUIDGetUUIDBytes(kIOFireWireDeviceInterfaceID) );
if( fFWUnit == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
(*fFWUnit)->AddRef( fFWUnit );
}
IOFireWireSessionRef sessionRef = 0;
if( status == kIOReturnSuccess )
{
sessionRef = (*fAVCUnit)->getSessionRef( fAVCUnit );
if( sessionRef == 0 )
status = kIOReturnError;
}
if( status == kIOReturnSuccess )
{
status = (*fFWUnit)->OpenWithSessionRef( fFWUnit, sessionRef );
}
FWLOG(( "IOFireWireAVCLibConsumer::init OpenWithSessionRef return status = 0x%08x\n", status ));
if( status == kIOReturnSuccess )
{
status = (*fFWUnit)->AddCallbackDispatcherToRunLoop( fFWUnit, fCFRunLoop );
}
if( status == kIOReturnSuccess )
{
fService = (*fFWUnit)->GetDevice( fFWUnit );
if( fService == NULL )
status = kIOReturnError;
}
if( status == kIOReturnSuccess )
{
if( isDeviceSuspended( fAVCUnit ) )
{
fState = kFWAVCStatePrivBusSuspended;
}
else
{
fState = kFWAVCStatePrivBusResumed;
}
}
FWLOG(( "IOFireWireAVCLibConsumer::init return status = 0x%08lx\n", (UInt32)status ));
return status;
}
HRESULT IOFireWireAVCLibConsumer::queryInterface( void * self, REFIID iid, void **ppv )
{
CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid);
HRESULT result = S_OK;
IOFireWireAVCLibConsumer * me = getThis(self);
if( CFEqual(uuid, IUnknownUUID) || CFEqual(uuid, kIOFireWireAVCLibConsumerInterfaceID) )
{
*ppv = &me->fIOFireWireAVCLibConsumerInterface;
comAddRef(self);
}
else
*ppv = 0;
if( !*ppv )
result = E_NOINTERFACE;
CFRelease( uuid );
return result;
}
const void * IOFireWireAVCLibConsumer::cfAddRef( CFAllocatorRef allocator, const void *value )
{
IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)value;
IOFireWireAVCLibConsumer::addRef( me );
return value;
}
UInt32 IOFireWireAVCLibConsumer::comAddRef( void * self )
{
IOFireWireAVCLibConsumer * me = getThis(self);
return IOFireWireAVCLibConsumer::addRef( me );
}
UInt32 IOFireWireAVCLibConsumer::addRef( IOFireWireAVCLibConsumer * me )
{
me->fRefCount++;
return me->fRefCount;
}
void IOFireWireAVCLibConsumer::cfRelease( CFAllocatorRef allocator, const void *value )
{
IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)value;
IOFireWireAVCLibConsumer::release( me );
}
UInt32 IOFireWireAVCLibConsumer::comRelease( void * self )
{
IOFireWireAVCLibConsumer * me = getThis(self);
return IOFireWireAVCLibConsumer::release( me );
}
UInt32 IOFireWireAVCLibConsumer::release( IOFireWireAVCLibConsumer * me )
{
UInt32 retVal = me->fRefCount;
me->fRefCount--;
if( 0 == me->fRefCount )
{
delete me;
}
else if( 1 == me->fRefCount )
{
me->finalize();
consumerPlugDestroyed( me->fAVCUnit, me );
}
else if( me->fRefCount < 0 )
{
me->fRefCount = 0;
}
return retVal;
}
IOReturn IOFireWireAVCLibConsumer::getNodeIDsAndGeneration( UInt16 * local, UInt16 * remote, UInt32 * gen )
{
IOReturn status = kIOReturnSuccess;
UInt16 localNodeID;
UInt16 remoteNodeID;
UInt32 firstGen, secondGen;
do
{
if( status == kIOReturnSuccess )
{
status = (*fFWUnit)->GetGenerationAndNodeID( fFWUnit, &firstGen, &remoteNodeID );
}
if( status == kIOReturnSuccess )
{
status = (*fFWUnit)->GetLocalNodeID( fFWUnit, &localNodeID );
}
if( status == kIOReturnSuccess )
{
status = (*fFWUnit)->GetGenerationAndNodeID( fFWUnit, &secondGen, &remoteNodeID );
}
} while( firstGen != secondGen && status == kIOReturnSuccess );
if( status == kIOReturnSuccess )
{
*remote = remoteNodeID;
*local = localNodeID;
*gen = firstGen;
}
return status;
}
void IOFireWireAVCLibConsumer::setSubunit( void * self, UInt8 subunit )
{
IOFireWireAVCLibConsumer * me = getThis(self);
me->fSubunit = subunit;
}
void IOFireWireAVCLibConsumer::setRemotePlug( void * self, UInt8 plugNumber )
{
IOFireWireAVCLibConsumer * me = getThis(self);
me->fRemotePlugNumber = plugNumber;
}
void IOFireWireAVCLibConsumer::setMaxPayloadSize( void * self, UInt32 size )
{
IOFireWireAVCLibConsumer * me = getThis(self);
UInt32 sizeBytes = size;
me->fMaxPayloadLog = 0x0;
while( (sizeBytes >= 0x4) && (me->fMaxPayloadLog < 0xa) )
{
sizeBytes >>= 1;
me->fMaxPayloadLog++;
}
if( me->fMaxPayloadLog < 0x5 )
me->fMaxPayloadLog = 0x5;
}
IOReturn IOFireWireAVCLibConsumer::connectToRemotePlug( void * self )
{
IOFireWireAVCLibConsumer * me = getThis(self);
IOReturn status = kIOReturnSuccess;
pthread_mutex_lock( &me->fLock );
FWLOG(( "IOFireWireAVCLibConsumer::connectToRemotePlug\n" ));
if( me->fState != kFWAVCStatePrivBusResumed )
{
status = kIOReturnNotReady;
}
if( me->fRemotePlugNumber < kFWAVCAsyncPlug0 || me->fRemotePlugNumber > kFWAVCAsyncPlugAny )
{
status = kIOReturnNoResources;
}
if( me->fPlugAddressSpace == NULL )
{
status = kIOReturnNoResources;
}
if( status == kIOReturnSuccess )
{
FWLOG(( "IOFireWireAVCLibConsumer::connectToRemotePlug attempt to connect to device...\n" ));
UInt32 tries = 11; do
{
status = me->doConnectToRemotePlug();
if( status != kIOReturnSuccess )
{
FWLOG(( "IOFireWireLibAVCConsumer::connectToRemotePlug connect to device failed with status = 0x%08lx\n", (UInt32)status ));
if( tries > 1 )
{
usleep( 1 * 1000000 );
FWLOG(( "IOFireWireLibAVCConsumer::connectToRemotePlug retrying connect to device...\n" ));
}
}
}
while( status != kIOReturnSuccess && --tries );
}
FWLOG(( "IOFireWireLibAVCConsumer::connectToRemotePlug return status = 0x%08lx\n", (UInt32)status ));
pthread_mutex_unlock( &me->fLock );
return status;
}
IOReturn IOFireWireAVCLibConsumer::doConnectToRemotePlug( void )
{
IOReturn status = kIOReturnSuccess;
FWLOG(( "IOFireWireAVCLibConsumer::doConnectToRemotePlug\n" ));
FWAddress address;
if( status == kIOReturnSuccess )
{
(*fPlugAddressSpace)->GetFWAddress( fPlugAddressSpace, &address );
}
UInt16 localNodeID;
UInt16 remoteNodeID;
UInt32 generation;
if( status == kIOReturnSuccess )
{
status = getNodeIDsAndGeneration( &localNodeID, &remoteNodeID, &generation );
}
ACAVCCommand cmd;
ACAVCCommand response;
if( status == kIOReturnSuccess )
{
cmd.command_type = 0x00; cmd.header_address = kAVCUnitAddress; cmd.opcode = ASYNCHRONOUS_CONNECTION; cmd.subfunction = ALLOCATE_ATTACH; cmd.status = 0xff; cmd.plug_id = fRemotePlugNumber; cmd.plug_offset_hi = 0xffff;
cmd.plug_offset_lo = 0xffffffff; cmd.connected_node_id = 0xffc0 | localNodeID;
cmd.connected_plug_offset_hi = AddressHi(address.addressHi);
cmd.connected_plug_offset_lo = AddressLo_PortBits(address.addressLo, kAVCConcurrentWrites | kAVCMulticast );
cmd.connected_plug_id = fLocalPlugNumber;
cmd.connection_count = Ex_ConnectionCount(0x1,0x3f);
cmd.write_interval_retry_count = WriteInterval_RetryCount(0x00,0x00);
cmd.reserved = 0x00;
}
FWLOG(( "IOFireWireAVCLibConsumer::doConnectToRemotePlug avc command\n" ));
UInt32 responseLength = sizeof(response);
if( status == kIOReturnSuccess )
{
status = (*fAVCUnit)->AVCCommandInGeneration( fAVCUnit, generation, (UInt8*)&cmd, sizeof(cmd), (UInt8*)&response, &responseLength );
}
if( status == kIOReturnSuccess )
{
if( response.status != 0x03 )
status = kIOReturnDeviceError;
}
if( status == kIOReturnSuccess )
{
fRemotePlugNumber = response.plug_id;
fRemotePlugAddress.addressHi = response.plug_offset_hi;
fRemotePlugAddress.addressLo = response.plug_offset_lo & 0xfffffffc;
fRemotePlugOptions = response.plug_offset_lo & 0x00000003;
}
UInt32 newVal = 0;
if( status == kIOReturnSuccess )
{
fOutputPlugRegisterBuffer = 0x00000000;
fInputPlugRegisterBuffer = 0x00000000;
fSegmentBitState = true;
fHeartbeatBitState = false;
}
if( status == kIOReturnSuccess )
{
FWLOG(( "IOFireWireAVCLibConsumer::doConnectToRemotePlug run bit\n" ));
UInt32 flags = kAVCProducerRunBit |
(fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) |
(fSegmentBitState ? kAVCProducerSCBit : 0x00000000);
newVal = oAPR( kFWAVCProducerMode_SEND, fSegmentSize, flags, fMaxPayloadLog );
status = updateProducerRegister( newVal, generation );
}
if( status == kIOReturnSuccess )
{
fState = kFWAVCStatePrivPlugConnected;
fGeneration = generation;
fMode = kFWAVCProducerMode_SEND;
startProducerHeartbeatTimer();
}
FWLOG(( "IOFireWireAVCLibConsumer::doConnectToRemotePlug status = 0x%08lx\n", (UInt32)status ));
return status;
}
IOReturn IOFireWireAVCLibConsumer::disconnectFromRemotePlug( void * self )
{
IOFireWireAVCLibConsumer * me = getThis(self);
IOReturn status = kIOReturnSuccess;
pthread_mutex_lock( &me->fLock );
switch( me->fState )
{
case kFWAVCStatePrivPlugSuspended:
me->stopReconnectTimer();
if( me->fProducerHeartbeatTimer != NULL || me->fConsumerHeartbeatTimer != NULL )
{
printf( "IOFireWireAVCLibConsumer::disconnectFromRemotePlug heartbeat timers set while plug is suspended!\n" );
}
me->fState = kFWAVCStatePrivBusSuspended;
break;
case kFWAVCStatePrivPlugConnected:
ACAVCCommand cmd;
ACAVCCommand response;
UInt32 responseLength;
if( me->fReconnectTimer != NULL )
{
printf( "IOFireWireAVCLibConsumer::disconnectFromRemotePlug reconnect timer set while plug is resumed!\n" );
}
me->stopProducerHeartbeatTimer();
me->stopConsumerHeartbeatTimer();
if( status == kIOReturnSuccess )
{
cmd.command_type = 0x00; cmd.header_address = kAVCUnitAddress; cmd.opcode = ASYNCHRONOUS_CONNECTION; cmd.subfunction = DETACH_RELEASE; cmd.status = 0xff; cmd.plug_id = me->fRemotePlugNumber; cmd.plug_offset_hi = 0xffff;
cmd.plug_offset_lo = AddressLoToMaskedPortID(me->fRemotePlugAddress.addressLo);
cmd.connected_node_id = 0xffff;
cmd.connected_plug_offset_hi = 0xffff;
cmd.connected_plug_offset_lo = 0xffffffff;
cmd.connected_plug_id = 0xff;
cmd.connection_count = Ex_ConnectionCount(0x1,0x3f);
cmd.write_interval_retry_count = WriteInterval_RetryCount(0xf,0xf);
cmd.reserved = 0x00;
}
if( status == kIOReturnSuccess )
{
responseLength = sizeof(response);
status = (*me->fAVCUnit)->AVCCommandInGeneration( me->fAVCUnit, me->fGeneration, (UInt8*)&cmd, sizeof(cmd), (UInt8*)&response, &responseLength );
}
if( status == kIOFireWireBusReset )
{
status = kIOReturnSuccess;
}
else if( status == kIOReturnSuccess )
{
if( response.status != 0x01 )
{
FWLOG(( "IOFireWireAVCLibConsumer::disconnectFromRemotePlug disconnect AVCCommand returned response.status = 0x%02x\n", response.status ));
}
}
else
{
FWLOG(( "IOFireWireAVCLibConsumer::disconnectFromRemotePlug disconnect AVCCommand status = 0x%08lx\n", (UInt32)status ));
status = kIOReturnSuccess;
}
if( status == kIOReturnSuccess )
{
me->fState = kFWAVCStatePrivBusResumed;
me->fInputPlugRegisterBuffer = 0x00000000;
}
break;
default:
status = kIOReturnNotPermitted;
break;
}
FWLOG(( "IOFireWireAVCLibConsumer::disconnectFromRemotePlug status = 0x%08lx\n", (UInt32)status ));
pthread_mutex_unlock( &me->fLock );
return status;
}
void IOFireWireAVCLibConsumer::forciblyDisconnected( void )
{
fInputPlugRegisterBuffer = 0x00000000;
switch( fState )
{
case kFWAVCStatePrivPlugSuspended:
fState = kFWAVCStatePrivBusSuspended;
pthread_mutex_unlock( &fLock );
if( fStateHandler )
{
(fStateHandler)(fStateHandlerRefcon, kFWAVCStatePlugDisconnected );
}
break;
case kFWAVCStatePrivPlugConnected:
fState = kFWAVCStatePrivBusResumed;
pthread_mutex_unlock( &fLock );
if( fStateHandler )
{
(fStateHandler)(fStateHandlerRefcon, kFWAVCStatePlugDisconnected );
}
break;
default:
pthread_mutex_unlock( &fLock );
FWLOG(( "IOFireWireAVCLibConsumer::forciblyDisconnected we're in an unexpected state = 0x%08lx.\n", fState ));
break;
}
}
void IOFireWireAVCLibConsumer::setPortStateHandler( void * self, void * refcon, IOFireWireAVCPortStateHandler handler )
{
IOFireWireAVCLibConsumer * me = getThis(self);
me->fStateHandlerRefcon = refcon;
me->fStateHandler = handler;
}
void IOFireWireAVCLibConsumer::deviceInterestCallback( natural_t type, void * arg )
{
IOReturn status = kIOReturnSuccess;
switch( type )
{
case kIOMessageServiceIsSuspended:
FWLOG(( "IOFireWireAVCLibConsumer::kIOMessageServiceIsSuspended bus reset start\n" ));
pthread_mutex_lock( &fLock );
switch ( fState )
{
case kFWAVCStatePrivBusResumed:
fState = kFWAVCStatePrivBusSuspended;
pthread_mutex_unlock( &fLock );
if( fStateHandler )
{
(fStateHandler)( fStateHandlerRefcon, kFWAVCStateBusSuspended );
}
break;
case kFWAVCStatePrivPlugSuspended:
startReconnectTimer();
pthread_mutex_unlock( &fLock );
break;
case kFWAVCStatePrivPlugConnected:
fState = kFWAVCStatePrivPlugSuspended;
fOutputPlugRegisterBuffer &= ~(kAVCProducerRunBit | kAVCProducerHBBit);
fInputPlugRegisterBuffer &= ~kFWAVCConsumerPlugHBMask;
fHeartbeatBitState = false;
stopProducerHeartbeatTimer();
stopConsumerHeartbeatTimer();
startReconnectTimer();
pthread_mutex_unlock( &fLock );
if( fStateHandler )
{
(fStateHandler)( fStateHandlerRefcon, kFWAVCStateBusSuspended );
}
break;
case kFWAVCStatePrivBusSuspended:
default:
pthread_mutex_unlock( &fLock );
break;
}
break;
case kIOMessageServiceIsResumed:
FWLOG(( "IOFireWireAVCLibConsumer::kIOMessageServiceIsResumed bus reset complete\n" ));
pthread_mutex_lock( &fLock );
switch ( fState )
{
case kFWAVCStatePrivBusSuspended:
fState = kFWAVCStatePrivBusResumed;
pthread_mutex_unlock( &fLock );
if( fStateHandler )
{
(fStateHandler)( fStateHandlerRefcon, kFWAVCStateBusResumed );
}
break;
case kFWAVCStatePrivPlugSuspended:
pthread_mutex_unlock( &fLock );
if( fStateHandler )
{
(fStateHandler)( fStateHandlerRefcon, kFWAVCStateBusResumed );
}
pthread_mutex_lock( &fLock );
stopReconnectTimer();
UInt16 localNodeID;
UInt16 remoteNodeID;
UInt32 generation;
if( status == kIOReturnSuccess )
{
status = getNodeIDsAndGeneration( &localNodeID, &remoteNodeID, &generation );
}
if( status == kIOReturnSuccess )
{
if( generation == fGeneration )
{
}
else
{
ACAVCCommand cmd;
ACAVCCommand response;
if( status == kIOReturnSuccess )
{
cmd.command_type = 0x00; cmd.header_address = kAVCUnitAddress; cmd.opcode = ASYNCHRONOUS_CONNECTION; cmd.subfunction = RESTORE_PORT; cmd.status = 0xff; cmd.plug_id = fRemotePlugNumber; cmd.plug_offset_hi = 0xffff;
cmd.plug_offset_lo = AddressLoToMaskedPortID(fRemotePlugAddress.addressLo);
cmd.connected_node_id = 0xffc0 | localNodeID;
cmd.connected_plug_offset_hi = 0xffff;
cmd.connected_plug_offset_lo = AddressLoToMaskedPortID(0x00000000);
cmd.connected_plug_id = 0xff;
cmd.connection_count = Ex_ConnectionCount(0x1,0x3f);
cmd.write_interval_retry_count = WriteInterval_RetryCount(0xf,0xf);
cmd.reserved = 0x00;
}
UInt32 responseLength = sizeof(response);
if( status == kIOReturnSuccess )
{
status = (*fAVCUnit)->AVCCommandInGeneration( fAVCUnit, generation, (UInt8*)&cmd, sizeof(cmd), (UInt8*)&response, &responseLength );
}
if( status == kIOReturnSuccess )
{
if( response.status != 0x03 )
status = kIOReturnDeviceError;
}
if( status == kIOReturnSuccess )
{
fRemotePlugNumber = response.plug_id;
fRemotePlugAddress.addressHi = response.plug_offset_hi;
fRemotePlugAddress.addressLo = response.plug_offset_lo & 0xfffffffc;
fRemotePlugOptions = response.plug_offset_lo & 0x00000003;
}
if( fHeartbeatBitState ||
(fOutputPlugRegisterBuffer & (kAVCProducerRunBit | kAVCProducerHBBit)) ||
(fInputPlugRegisterBuffer & kFWAVCConsumerPlugHBMask) )
{
printf( "IOFireWireAVCLibConsumer::deviceInterestCallback register values not reset!\n" );
}
UInt32 newVal = 0;
if( status == kIOReturnSuccess )
{
UInt32 flags = kAVCProducerRunBit |
(fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) |
(fSegmentBitState ? kAVCProducerSCBit : 0x00000000);
newVal = oAPR( kFWAVCProducerMode_SEND, fSegmentSize, flags, fMaxPayloadLog );
status = updateProducerRegister( newVal, generation );
}
if( status == kIOReturnSuccess )
{
fMode = kFWAVCProducerMode_SEND;
startProducerHeartbeatTimer();
}
}
}
if( status == kIOReturnSuccess )
{
fState = kFWAVCStatePrivPlugConnected;
fGeneration = generation;
}
if( status == kIOReturnSuccess )
{
pthread_mutex_unlock( &fLock );
if( fStateHandler )
{
(fStateHandler)( fStateHandlerRefcon, kFWAVCStatePlugReconnected );
}
}
else if( status == kIOFireWireBusReset )
{
pthread_mutex_unlock( &fLock );
}
else
{
FWLOG(( "IOFireWireAVCLibConsumer::deviceInterestCallback failed to reconnect - forciblyDisconnecting\n" ));
forciblyDisconnected();
}
break;
case kIOFWMessageServiceIsRequestingClose:
FWLOG(( "IOFireWireAVCLibConsumer::kIOFWMessageServiceIsRequestingClose (device removed)\n" ));
pthread_mutex_lock( &fLock );
switch ( fState )
{
case kFWAVCStatePrivBusSuspended:
pthread_mutex_unlock( &fLock );
if( fStateHandler )
{
(fStateHandler)( fStateHandlerRefcon, kFWAVCStateDeviceRemoved );
}
break;
case kFWAVCStatePrivPlugSuspended:
FWLOG(( "IOFireWireAVCLibConsumer::deviceInterestCallback device unplugged - forciblyDisconnecting\n" ));
forciblyDisconnected();
if( fStateHandler )
{
(fStateHandler)( fStateHandlerRefcon, kFWAVCStateDeviceRemoved );
}
break;
default:
FWLOG(( "IOFireWireAVCLibConsumer::deviceInterestCallback kIOFWMessageServiceIsRequestingClose in odd state, fState = 0x%08lx/n", fState ));
break;
}
break;
case kIOMessageServiceIsTerminated:
FWLOG(( "IOFireWireAVCLibConsumer::kIOMessageServiceIsTerminated (device removed)\n" ));
break;
default:
FWLOG(( "IOFireWireAVCLibConsumer::deviceInterestCallback kIOMessageServiceIsResumed in odd state, fState = 0x%08lx/n", fState ));
break;
}
break;
default:
break;
}
}
void IOFireWireAVCLibConsumer::startReconnectTimer( void )
{
CFRunLoopTimerContext context;
CFAbsoluteTime time;
stopReconnectTimer();
context.version = 0;
context.info = this;
context.retain = NULL;
context.release = NULL;
context.copyDescription = NULL;
time = CFAbsoluteTimeGetCurrent() + kReconnectTime;
fReconnectTimer = CFRunLoopTimerCreate(NULL, time,
0,
0,
0,
(CFRunLoopTimerCallBack)&IOFireWireAVCLibConsumer::reconnectTimeoutProc,
&context);
if ( fReconnectTimer )
{
CFRunLoopAddTimer( fCFRunLoop, fReconnectTimer, kCFRunLoopDefaultMode );
}
}
void IOFireWireAVCLibConsumer::reconnectTimeoutProc( CFRunLoopTimerRef timer, void *data )
{
IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)data;
pthread_mutex_lock( &me->fLock );
me->stopReconnectTimer();
FWLOG(( "IOFireWireAVCLibConsumer::reconnectTimeoutProc reconnect timed out - forciblyDisconnecting\n" ));
me->forciblyDisconnected();
}
void IOFireWireAVCLibConsumer::stopReconnectTimer( void )
{
if ( fReconnectTimer )
{
CFRunLoopTimerInvalidate( fReconnectTimer );
CFRelease( fReconnectTimer );
fReconnectTimer = NULL;
}
}
IOReturn IOFireWireAVCLibConsumer::setSegmentSize( void * self, UInt32 size )
{
IOFireWireAVCLibConsumer * me = getThis(self);
IOReturn status = kIOReturnSuccess;
if( size > 0x00ffffff || (size & 0x0000003f) != 0 )
{
return kIOReturnBadArgument;
}
me->releaseSegment();
me->fSegmentBuffer = (char*)malloc( size + 64 );
if( me->fSegmentBuffer == NULL )
status = kIOReturnNoMemory;
if( status == kIOReturnSuccess )
{
me->fSegmentSize = size;
me->fPlugAddressSpace = (*me->fFWUnit)->CreatePseudoAddressSpace( me->fFWUnit, me->fSegmentSize + 64,
me, (me->fSegmentSize + 64) * 2,
me->fSegmentBuffer,
kFWAddressSpaceNoFlags,
CFUUIDGetUUIDBytes(kIOFireWirePseudoAddressSpaceInterfaceID));
if( me->fPlugAddressSpace == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
FWAddress address;
(*me->fPlugAddressSpace)->GetFWAddress(me->fPlugAddressSpace, &address);
FWLOG(("IOFireWireAVCLibConsumer::allocated address space at %04X:%08lX\n", address.addressHi, address.addressLo));
(*me->fPlugAddressSpace)->SetWriteHandler( me->fPlugAddressSpace,
&IOFireWireAVCLibConsumer::packetWriteHandler );
(*me->fPlugAddressSpace)->SetSkippedPacketHandler( me->fPlugAddressSpace,
&IOFireWireAVCLibConsumer::skippedPacketHandler );
(*me->fPlugAddressSpace)->SetReadHandler( me->fPlugAddressSpace, &IOFireWireAVCLibConsumer::packetReadHandler );
if( !(*me->fPlugAddressSpace)->TurnOnNotification( me->fPlugAddressSpace ) )
status = kIOReturnError ;
}
return status;
}
void IOFireWireAVCLibConsumer::releaseSegment( void )
{
if( fPlugAddressSpace != NULL )
{
(*fPlugAddressSpace)->TurnOffNotification( fPlugAddressSpace );
(*fPlugAddressSpace)->Release( fPlugAddressSpace );
fPlugAddressSpace = NULL;
}
if( fSegmentBuffer != NULL )
{
free( fSegmentBuffer );
fSegmentBuffer= NULL;
}
}
UInt32 IOFireWireAVCLibConsumer::getSegmentSize( void * self )
{
IOFireWireAVCLibConsumer * me = getThis(self);
return me->fSegmentSize;
}
char * IOFireWireAVCLibConsumer::getSegmentBuffer( void * self )
{
IOFireWireAVCLibConsumer * me = getThis(self);
return (me->fSegmentBuffer + 64);
}
void IOFireWireAVCLibConsumer::setFrameStatusHandler( void * self,
void * refcon, IOFireWireAVCFrameStatusHandler handler )
{
IOFireWireAVCLibConsumer * me = getThis(self);
me->fFrameStatusHandler = handler;
me->fFrameStatusHandlerRefcon = refcon;
}
IOReturn IOFireWireAVCLibConsumer::updateProducerRegister( UInt32 newVal, UInt32 generation )
{
IOReturn status = kIOReturnSuccess;
UInt32 tries = 6;
bool done = false;
do
{
FWLOG(( "IOFireWireAVCLibConsumer::updateProducerRegister sending CompareAndSwap(0x%08lx,0x%08lx) to producer\n", fOutputPlugRegisterBuffer, newVal ));
status = (*fFWUnit)->CompareSwap( fFWUnit, fService, &fRemotePlugAddress, fOutputPlugRegisterBuffer, newVal, true, generation );
if( status == kIOFireWireBusReset || status == kIOReturnSuccess)
{
done = true;
}
else
{
FWLOG(( "IOFireWireLibAVCConsumer::updateProducerRegister register update failed with status = 0x%08lx\n", (UInt32)status ));
if( tries > 1 )
{
usleep( 25 * 1000 );
UInt32 producerRegister = 0;
status = (*fFWUnit)->ReadQuadlet( fFWUnit, fService, &fRemotePlugAddress, &producerRegister, true, generation );
if( status == kIOReturnSuccess )
{
fOutputPlugRegisterBuffer = producerRegister;
}
else if( status == kIOFireWireBusReset )
{
done = true;
}
if( !done )
{
usleep( 25 * 1000 );
FWLOG(( "IOFireWireLibAVCConsumer::updateProducerRegister retrying register update.\n" ));
}
}
}
}
while( !done && --tries );
if( status == kIOReturnSuccess )
{
fOutputPlugRegisterBuffer = newVal;
}
return status;
}
UInt32
IOFireWireAVCLibConsumer::packetReadHandler(
IOFireWireLibPseudoAddressSpaceRef addressSpace,
FWClientCommandID commandID,
UInt32 packetLen,
UInt32 packetOffset,
UInt16 nodeID, UInt32 destAddressHi, UInt32 destAddressLo,
UInt32 refcon)
{
IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)refcon;
FWLOG(( "IOFireWireAVCLibConsumer::packetReadHandler called - destAddressLo = 0x%08lx\n", destAddressLo ));
UInt8 * buffer = (UInt8 *)(*addressSpace)->GetBuffer( addressSpace );
if( packetOffset < 4 )
{
bcopy( (void*)&me->fInputPlugRegisterBuffer, buffer + packetOffset, sizeof(UInt32));
}
else if( packetOffset < 64 )
{
bzero( buffer + packetOffset, packetLen );
}
else
{
bcopy( me->fSegmentBuffer + packetOffset - 64, buffer + packetOffset, packetLen);
}
(*addressSpace)->ClientCommandIsComplete( addressSpace, commandID, kFWResponseComplete ) ;
return 0;
}
UInt32 IOFireWireAVCLibConsumer::packetWriteHandler(
IOFireWireLibPseudoAddressSpaceRef addressSpace,
FWClientCommandID commandID,
UInt32 packetLen,
void* packet,
UInt16 srcNodeID, UInt32 destAddressHi, UInt32 destAddressLo,
UInt32 refcon)
{
IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)refcon;
IOReturn status = kIOReturnSuccess;
FWAddress plugAddress;
(*addressSpace)->GetFWAddress(addressSpace, &plugAddress);
FWAddress offsetAddress;
offsetAddress.addressHi = destAddressHi;
offsetAddress.addressLo = destAddressLo;
UInt32 offset = (UInt32)subtractFWAddressFromFWAddress( plugAddress, offsetAddress );
if( offset < 64 )
{
if( packetLen > 4 )
{
FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler wrote to register > 4 bytes\n" ));
status = kIOReturnError;
}
if( !((offsetAddress.addressHi == plugAddress.addressHi) &&
(offsetAddress.addressLo == plugAddress.addressLo)) )
{
FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler offsetAddress != plugAddress\n" ));
status = kIOReturnError;
}
pthread_mutex_lock( &me->fLock );
bool workScheduled = false;
if( status == kIOReturnSuccess )
{
me->fInputPlugRegisterBuffer = *((UInt32*)packet);
FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler received packet = 0x%08lx\n", me->fInputPlugRegisterBuffer ));
}
if( status == kIOReturnSuccess && me->fState == kFWAVCStatePrivPlugConnected )
{
me->stopProducerHeartbeatTimer();
UInt32 count = (me->fInputPlugRegisterBuffer & kFWAVCConsumerPlugCountMask) >> kFWAVCConsumerPlugCountPhase;
UInt32 mode = (me->fInputPlugRegisterBuffer & kFWAVCConsumerPlugModeMask) >> kFWAVCConsumerPlugModePhase;
bool newHeartbeatState = (me->fInputPlugRegisterBuffer & kFWAVCConsumerPlugHBMask) >> kFWAVCConsumerPlugHBPhase;
if( me->fHeartbeatBitState != newHeartbeatState )
{
if( !me->fHeartbeatResponseScheduled )
{
FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler schedule heartbeat response\n" ));
me->fHeartbeatResponseScheduled = true;
workScheduled = true;
CFRunLoopSourceSignal( me->fHeartbeatResponseSource );
CFRunLoopWakeUp( me->fCFRunLoop );
}
else
{
FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler frame heartbeat response already scheduled!\n" ));
}
}
else
{
switch( mode )
{
case kFWAVCConsumerMode_FREE:
switch( me->fState )
{
case kFWAVCStatePrivPlugConnected:
if( !me->fDisconnectResponseScheduled )
{
FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler schedule disconnect response\n" ));
me->fDisconnectResponseScheduled = true;
workScheduled = true;
CFRunLoopSourceSignal( me->fDisconnectResponseSource );
CFRunLoopWakeUp( me->fCFRunLoop );
}
else
{
FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler disconnect response already scheduled!\n" ));
}
break;
default:
FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler FREE received, but we're in an unexpected state = 0x%08lx.\n", me->fState ));
break;
}
break;
case kFWAVCConsumerMode_MORE:
case kFWAVCConsumerMode_LAST:
case kFWAVCConsumerMode_LESS:
case kFWAVCConsumerMode_JUNK:
case kFWAVCConsumerMode_LOST:
me->startConsumerHeartbeatTimer();
me->fFrameStatusMode = mode;
me->fFrameStatusCount = count;
if( !me->fFrameStatusSourceScheduled )
{
FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler schedule frame status handler\n" ));
me->fFrameStatusSourceScheduled = true;
workScheduled = true;
CFRunLoopSourceSignal( me->fFrameStatusSource );
CFRunLoopWakeUp( me->fCFRunLoop );
}
else
{
FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler frame heartbeat response already scheduled!\n" ));
}
break;
default:
break;
}
}
}
if( !workScheduled )
{
pthread_mutex_unlock( &me->fLock );
}
}
else
{
if( offset + packetLen - 64 > me->fSegmentSize )
{
FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler written packet size > than segment size\n" ));
status = kIOReturnError;
}
if( status == kIOReturnSuccess )
{
bcopy( packet, me->fSegmentBuffer + offset, packetLen );
}
}
(*addressSpace)->ClientCommandIsComplete(addressSpace, commandID, kIOReturnSuccess) ;
return 0;
}
void IOFireWireAVCLibConsumer::skippedPacketHandler(
IOFireWireLibPseudoAddressSpaceRef addressSpace,
FWClientCommandID commandID,
UInt32 skippedPacketCount)
{
FWLOG(("IOFireWireAVCLibConsumer::skippedPacketHandler skippedPacketCount = %ld\n", skippedPacketCount));
(*addressSpace)->ClientCommandIsComplete(addressSpace, commandID, kIOReturnSuccess);
}
void IOFireWireAVCLibConsumer::sendDisconnectResponse( IOFireWireAVCLibConsumer ** info )
{
IOReturn status = kIOReturnSuccess;
IOFireWireAVCLibConsumer * me = *info;
UInt32 newVal = 0;
me->fDisconnectResponseScheduled = false;
FWLOG(( "IOFireWireLibAVCConsumer::sendDisconnectResponse disconnect response handler called\n" ));
UInt32 flags = kAVCProducerRunBit |
(me->fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) |
(!me->fSegmentBitState ? kAVCProducerSCBit : 0x00000000);
newVal = oAPR( kFWAVCProducerMode_FREE, me->fSegmentSize, flags, me->fMaxPayloadLog );
status = me->updateProducerRegister( newVal, me->fGeneration );
if( status == kIOReturnSuccess )
{
me->fMode = kFWAVCProducerMode_FREE;
me->fState = kFWAVCStatePrivBusResumed;
me->fSegmentBitState = !me->fSegmentBitState;
FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler FREE received - forciblyDisconnecting\n" ));
me->forciblyDisconnected();
}
else
{
pthread_mutex_unlock( &me->fLock );
}
}
void IOFireWireAVCLibConsumer::sendHeartbeatResponse( IOFireWireAVCLibConsumer ** info )
{
IOReturn status = kIOReturnSuccess;
IOFireWireAVCLibConsumer * me = *info;
UInt32 newVal = 0;
me->fHeartbeatResponseScheduled = false;
FWLOG(( "IOFireWireLibAVCConsumer::sendHeartbeatResponse heartbeat response handler called\n" ));
UInt32 flags = kAVCProducerRunBit |
(!me->fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) |
(me->fSegmentBitState ? kAVCProducerSCBit : 0x00000000);
newVal = oAPR( kFWAVCProducerMode_SEND, me->fSegmentSize, flags, me->fMaxPayloadLog );
status = me->updateProducerRegister( newVal, me->fGeneration );
if( status == kIOReturnSuccess )
{
me->fHeartbeatBitState = !me->fHeartbeatBitState;
me->startProducerHeartbeatTimer();
pthread_mutex_unlock( &me->fLock );
}
else if( status != kIOFireWireBusReset )
{
FWLOG(( "IOFireWireLibAVCConsumer::sendHeartbeatResponse heartbeat handshake failed with status = 0x%08lx\n", (UInt32)status ));
me->forciblyDisconnected();
}
else
{
pthread_mutex_unlock( &me->fLock );
}
}
void IOFireWireAVCLibConsumer::startConsumerHeartbeatTimer( void )
{
CFRunLoopTimerContext context;
CFAbsoluteTime time;
stopConsumerHeartbeatTimer();
context.version = 0;
context.info = this;
context.retain = NULL;
context.release = NULL;
context.copyDescription = NULL;
time = CFAbsoluteTimeGetCurrent() + kConsumerHeartbeatTime;
fConsumerHeartbeatTimer = CFRunLoopTimerCreate(NULL, time,
kConsumerHeartbeatTime,
0,
0,
(CFRunLoopTimerCallBack)&IOFireWireAVCLibConsumer::consumerHeartbeatProc,
&context);
if ( fConsumerHeartbeatTimer )
{
CFRunLoopAddTimer( fCFRunLoop, fConsumerHeartbeatTimer, kCFRunLoopDefaultMode );
}
}
void IOFireWireAVCLibConsumer::consumerHeartbeatProc( CFRunLoopTimerRef timer, void *data )
{
IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)data;
IOReturn status = kIOReturnSuccess;
UInt32 newVal = 0;
pthread_mutex_lock( &me->fLock );
me->stopConsumerHeartbeatTimer();
UInt32 flags = kAVCProducerRunBit |
(!me->fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) |
(me->fSegmentBitState ? kAVCProducerSCBit : 0x00000000);
newVal = oAPR( me->fMode, me->fSegmentSize, flags, me->fMaxPayloadLog );
status = me->updateProducerRegister( newVal, me->fGeneration );
if( status == kIOReturnSuccess )
{
me->fHeartbeatBitState = !me->fHeartbeatBitState;
}
pthread_mutex_unlock( &me->fLock );
}
void IOFireWireAVCLibConsumer::stopConsumerHeartbeatTimer( void )
{
if ( fConsumerHeartbeatTimer )
{
CFRunLoopTimerInvalidate( fConsumerHeartbeatTimer );
CFRelease( fConsumerHeartbeatTimer );
fConsumerHeartbeatTimer = NULL;
}
}
void IOFireWireAVCLibConsumer::sendFrameStatusNotification( IOFireWireAVCLibConsumer ** info )
{
IOFireWireAVCLibConsumer * me = *info;
me->fFrameStatusSourceScheduled = false;
FWLOG(( "IOFireWireLibAVCConsumer::sendFrameStatusNotification frame status handler called\n" ));
pthread_mutex_unlock( &me->fLock );
if( me->fFrameStatusHandler )
{
(me->fFrameStatusHandler)(me->fFrameStatusHandlerRefcon, me->fFrameStatusMode, me->fFrameStatusCount);
}
}
void IOFireWireAVCLibConsumer::frameProcessed( void * self, UInt32 mode )
{
IOFireWireAVCLibConsumer * me = getThis(self);
IOReturn status = kIOReturnSuccess;
pthread_mutex_lock( &me->fLock );
me->stopConsumerHeartbeatTimer();
UInt32 flags = kAVCProducerRunBit |
(me->fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) |
(!me->fSegmentBitState ? kAVCProducerSCBit : 0x00000000);
UInt32 newVal = oAPR( mode, me->fSegmentSize, flags, me->fMaxPayloadLog );
status = me->updateProducerRegister( newVal, me->fGeneration );
if( status == kIOReturnSuccess )
{
me->fMode = mode;
me->fSegmentBitState = !me->fSegmentBitState;
me->startProducerHeartbeatTimer();
}
pthread_mutex_unlock( &me->fLock );
}
void IOFireWireAVCLibConsumer::startProducerHeartbeatTimer( void )
{
CFRunLoopTimerContext context;
CFAbsoluteTime time;
stopProducerHeartbeatTimer();
context.version = 0;
context.info = this;
context.retain = NULL;
context.release = NULL;
context.copyDescription = NULL;
time = CFAbsoluteTimeGetCurrent() + kProducerHeartbeatTime;
fProducerHeartbeatTimer = CFRunLoopTimerCreate( NULL, time,
0,
0,
0,
(CFRunLoopTimerCallBack)&IOFireWireAVCLibConsumer::producerHeartbeatProc,
&context);
if ( fProducerHeartbeatTimer )
{
CFRunLoopAddTimer( fCFRunLoop, fProducerHeartbeatTimer, kCFRunLoopDefaultMode );
}
}
void IOFireWireAVCLibConsumer::producerHeartbeatProc( CFRunLoopTimerRef timer, void *data )
{
IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)data;
pthread_mutex_lock( &me->fLock );
me->stopProducerHeartbeatTimer();
FWLOG(( "IOFireWireAVCLibConsumer::producerHeartbeatProc producer heatbeat timeout - forciblyDisconnecting\n" ));
me->forciblyDisconnected();
}
void IOFireWireAVCLibConsumer::stopProducerHeartbeatTimer( void )
{
if( fProducerHeartbeatTimer )
{
CFRunLoopTimerInvalidate( fProducerHeartbeatTimer );
CFRelease( fProducerHeartbeatTimer );
fProducerHeartbeatTimer = NULL;
}
}
void IOFireWireAVCLibConsumer::setPortFlags( void * self, UInt32 flags )
{
IOFireWireAVCLibConsumer * me = getThis(self);
me->fFlags |= flags;
}
void IOFireWireAVCLibConsumer::clearPortFlags( void * self, UInt32 flags )
{
IOFireWireAVCLibConsumer * me = getThis(self);
me->fFlags &= !flags;
}
UInt32 IOFireWireAVCLibConsumer::getPortFlags( void * self )
{
IOFireWireAVCLibConsumer * me = getThis(self);
return me->fFlags;
}