IOFireWireLibIsochPort.cpp [plain text]
#import "IOFireWireLibIsochPort.h"
#import "IOFireWireLibDevice.h"
#import "IOFireWireLibNuDCLPool.h"
#import "IOFireWireLibNuDCL.h"
#import "IOFireWireLibCoalesceTree.h"
#import <IOKit/iokitmig.h>
#import <mach/mach.h>
#define IOFIREWIREISOCHPORTIMP_INTERFACE \
& IsochPortCOM::SGetSupported, \
& IsochPortCOM::SAllocatePort, \
& IsochPortCOM::SReleasePort, \
& IsochPortCOM::SStart, \
& IsochPortCOM::SStop, \
& IsochPortCOM::SSetRefCon, \
& IsochPortCOM::SGetRefCon
namespace IOFireWireLib {
RemoteIsochPort::Interface RemoteIsochPortCOM::sInterface =
{
INTERFACEIMP_INTERFACE,
1, 0,
IOFIREWIREISOCHPORTIMP_INTERFACE,
& RemoteIsochPortCOM::SSetGetSupportedHandler,
& RemoteIsochPortCOM::SSetAllocatePortHandler,
& RemoteIsochPortCOM::SSetReleasePortHandler,
& RemoteIsochPortCOM::SSetStartHandler,
& RemoteIsochPortCOM::SSetStopHandler,
} ;
Boolean
GetDCLDataBuffer(
DCLCommand* dcl,
IOVirtualAddress* outDataBuffer,
IOByteCount* outDataLength)
{
Boolean result = false ;
switch(dcl->opcode & ~kFWDCLOpFlagMask)
{
case kDCLSendPacketStartOp:
case kDCLSendPacketWithHeaderStartOp:
case kDCLSendPacketOp:
case kDCLReceivePacketStartOp:
case kDCLReceivePacketOp:
*outDataBuffer = (IOVirtualAddress)((DCLTransferPacket*)dcl)->buffer ;
*outDataLength = ((DCLTransferPacket*)dcl)->size ;
result = true ;
break ;
case kDCLSendBufferOp:
case kDCLReceiveBufferOp:
break ;
case kDCLPtrTimeStampOp:
*outDataBuffer = (IOVirtualAddress)((DCLPtrTimeStamp*)dcl)->timeStampPtr ;
*outDataLength = sizeof( *( ((DCLPtrTimeStamp*)dcl)->timeStampPtr) ) ;
result = true ;
break ;
default:
break ;
}
return result ;
}
IOByteCount
GetDCLSize(
DCLCommand* dcl)
{
IOByteCount result = 0 ;
switch(dcl->opcode & ~kFWDCLOpFlagMask)
{
case kDCLSendPacketStartOp:
case kDCLSendPacketWithHeaderStartOp:
case kDCLSendPacketOp:
case kDCLReceivePacketStartOp:
case kDCLReceivePacketOp:
result = sizeof(DCLTransferPacket) ;
break ;
case kDCLSendBufferOp:
case kDCLReceiveBufferOp:
result = sizeof(DCLTransferBuffer) ;
break ;
case kDCLCallProcOp:
result = sizeof(DCLCallProc) ;
break ;
case kDCLLabelOp:
result = sizeof(DCLLabel) ;
break ;
case kDCLJumpOp:
result = sizeof(DCLJump) ;
break ;
case kDCLSetTagSyncBitsOp:
result = sizeof(DCLSetTagSyncBits) ;
break ;
case kDCLUpdateDCLListOp:
result = sizeof(DCLUpdateDCLList) ;
break ;
case kDCLPtrTimeStampOp:
result = sizeof(DCLPtrTimeStamp) ;
case kDCLSkipCycleOp:
result = sizeof(DCLCommand) ;
}
return result ;
}
#pragma mark -
IsochPort::IsochPort( const IUnknownVTbl & interface, Device & device, bool talking, bool allocateKernPort )
: IOFireWireIUnknown( interface ),
mDevice( device ),
mKernPortRef( 0 ),
mTalking( talking )
{
mDevice.AddRef() ;
}
IsochPort::~IsochPort()
{
if ( mKernPortRef )
{
IOReturn error = kIOReturnSuccess;
error = IOConnectMethodScalarIScalarO( mDevice.GetUserClientConnection(),
kReleaseUserObject, 1, 0, mKernPortRef ) ;
DebugLogCond( error, "Couldn't release kernel port" ) ;
}
mDevice.Release() ;
}
IOReturn
IsochPort::GetSupported(
IOFWSpeed& maxSpeed,
UInt64& chanSupported )
{
return ::IOConnectMethodScalarIScalarO( mDevice.GetUserClientConnection(), kIsochPort_GetSupported,
1, 3, mKernPortRef, & maxSpeed, (UInt32*)&chanSupported, (UInt32*)&chanSupported + 1) ;
}
IOReturn
IsochPort::AllocatePort( IOFWSpeed speed, UInt32 chan )
{
return ::IOConnectMethodScalarIScalarO( mDevice.GetUserClientConnection(),
mDevice.MakeSelectorWithObject( kIsochPort_AllocatePort_d, mKernPortRef ),
2, 0, speed, chan ) ;
}
IOReturn
IsochPort::ReleasePort()
{
return ::IOConnectMethodScalarIScalarO( mDevice.GetUserClientConnection(),
mDevice.MakeSelectorWithObject( kIsochPort_ReleasePort_d, mKernPortRef ),
0, 0 ) ;
}
IOReturn
IsochPort::Start()
{
return ::IOConnectMethodScalarIScalarO( mDevice.GetUserClientConnection(),
mDevice.MakeSelectorWithObject( kIsochPort_Start_d, mKernPortRef ),
0, 0 ) ;
}
IOReturn
IsochPort::Stop()
{
return ::IOConnectMethodScalarIScalarO( mDevice.GetUserClientConnection(),
mDevice.MakeSelectorWithObject( kIsochPort_Stop_d, mKernPortRef ),
0, 0 ) ;
}
#pragma mark -
IsochPortCOM::IsochPortCOM( const IUnknownVTbl & interface, Device& userclient, bool talking, bool allocateKernPort )
: IsochPort( interface, userclient, talking, allocateKernPort )
{
}
IsochPortCOM::~IsochPortCOM()
{
}
IOReturn
IsochPortCOM::SGetSupported(
IOFireWireLibIsochPortRef self,
IOFWSpeed* maxSpeed,
UInt64* chanSupported )
{
return IOFireWireIUnknown::InterfaceMap<IsochPortCOM>::GetThis(self)->GetSupported(*maxSpeed, *chanSupported) ;
}
IOReturn
IsochPortCOM::SAllocatePort(
IOFireWireLibIsochPortRef self,
IOFWSpeed speed,
UInt32 chan )
{
return IOFireWireIUnknown::InterfaceMap<IsochPortCOM>::GetThis(self)->AllocatePort(speed, chan) ;
}
IOReturn
IsochPortCOM::SReleasePort(
IOFireWireLibIsochPortRef self)
{
return IOFireWireIUnknown::InterfaceMap<IsochPortCOM>::GetThis(self)->ReleasePort() ;
}
IOReturn
IsochPortCOM::SStart(
IOFireWireLibIsochPortRef self)
{
return IOFireWireIUnknown::InterfaceMap<IsochPortCOM>::GetThis(self)->Start() ;
}
IOReturn
IsochPortCOM::SStop(
IOFireWireLibIsochPortRef self)
{
return IOFireWireIUnknown::InterfaceMap<IsochPortCOM>::GetThis(self)->Stop() ;
}
void
IsochPortCOM::SSetRefCon(
IOFireWireLibIsochPortRef self,
void* inRefCon)
{
IOFireWireIUnknown::InterfaceMap<IsochPortCOM>::GetThis(self)->SetRefCon(inRefCon) ;
}
void*
IsochPortCOM::SGetRefCon(
IOFireWireLibIsochPortRef self)
{
return IOFireWireIUnknown::InterfaceMap<IsochPortCOM>::GetThis(self)->GetRefCon() ;
}
Boolean
IsochPortCOM::SGetTalking(
IOFireWireLibIsochPortRef self)
{
return IOFireWireIUnknown::InterfaceMap<IsochPortCOM>::GetThis(self)->GetTalking() ;
}
#pragma mark -
RemoteIsochPort::RemoteIsochPort( const IUnknownVTbl & interface, Device& userclient, bool talking )
: IsochPortCOM( interface, userclient, talking ),
mGetSupportedHandler(0),
mAllocatePortHandler(0),
mReleasePortHandler(0),
mStartHandler(0),
mStopHandler(0),
mRefInterface( reinterpret_cast<IOFireWireIsochPortInterface**>(& GetInterface()) )
{
}
IOReturn
RemoteIsochPort::GetSupported(
IOFWSpeed& maxSpeed,
UInt64& chanSupported)
{
if (mGetSupportedHandler)
return (*mGetSupportedHandler)(mRefInterface, & maxSpeed, & chanSupported) ;
else
return kIOReturnUnsupported ; }
IOReturn
RemoteIsochPort::AllocatePort(
IOFWSpeed speed,
UInt32 chan )
{
if (mAllocatePortHandler)
return (*mAllocatePortHandler)(mRefInterface, speed, chan) ;
else
return kIOReturnSuccess ;
}
IOReturn
RemoteIsochPort::ReleasePort()
{
if (mReleasePortHandler)
return (*mReleasePortHandler)(mRefInterface) ;
else
return kIOReturnSuccess ;
}
IOReturn
RemoteIsochPort::Start()
{
if (mStartHandler)
return (*mStartHandler)(mRefInterface) ;
else
return kIOReturnSuccess ;
}
IOReturn
RemoteIsochPort::Stop()
{
if (mStopHandler)
return (*mStopHandler)(mRefInterface) ;
else
return kIOReturnSuccess ;
}
IOFireWireLibIsochPortGetSupportedCallback
RemoteIsochPort::SetGetSupportedHandler(
IOFireWireLibIsochPortGetSupportedCallback inHandler)
{
IOFireWireLibIsochPortGetSupportedCallback oldHandler = mGetSupportedHandler ;
mGetSupportedHandler = inHandler ;
return oldHandler ;
}
IOFireWireLibIsochPortAllocateCallback
RemoteIsochPort::SetAllocatePortHandler(
IOFireWireLibIsochPortAllocateCallback inHandler)
{
IOFireWireLibIsochPortAllocateCallback oldHandler = mAllocatePortHandler ;
mAllocatePortHandler = inHandler ;
return oldHandler ;
}
IOFireWireLibIsochPortCallback
RemoteIsochPort::SetReleasePortHandler(
IOFireWireLibIsochPortCallback inHandler)
{
IOFireWireLibIsochPortCallback oldHandler = mReleasePortHandler ;
mReleasePortHandler = inHandler ;
return oldHandler ;
}
IOFireWireLibIsochPortCallback
RemoteIsochPort::SetStartHandler(
IOFireWireLibIsochPortCallback inHandler)
{
IOFireWireLibIsochPortCallback oldHandler = mStartHandler ;
mStartHandler = inHandler ;
return oldHandler ;
}
IOFireWireLibIsochPortCallback
RemoteIsochPort::SetStopHandler(
IOFireWireLibIsochPortCallback inHandler)
{
IOFireWireLibIsochPortCallback oldHandler = mStopHandler ;
mStopHandler = inHandler ;
return oldHandler ;
}
#pragma mark -
RemoteIsochPortCOM::RemoteIsochPortCOM( Device& userclient, bool talking )
: RemoteIsochPort( reinterpret_cast<const IUnknownVTbl &>( sInterface ), userclient, talking )
{
}
RemoteIsochPortCOM::~RemoteIsochPortCOM()
{
}
IUnknownVTbl**
RemoteIsochPortCOM::Alloc( Device& userclient, bool talking )
{
RemoteIsochPortCOM* me = nil ;
try {
me = new RemoteIsochPortCOM( userclient, talking ) ;
} catch(...) {
}
return (nil==me) ? nil : reinterpret_cast<IUnknownVTbl**>(& me->GetInterface()) ;
}
HRESULT
RemoteIsochPortCOM::QueryInterface(REFIID iid, void ** ppv )
{
HRESULT result = S_OK ;
*ppv = nil ;
CFUUIDRef interfaceID = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, iid) ;
if ( CFEqual(interfaceID, IUnknownUUID) || CFEqual(interfaceID, kIOFireWireRemoteIsochPortInterfaceID) )
{
*ppv = & GetInterface() ;
AddRef() ;
}
else
{
*ppv = nil ;
result = E_NOINTERFACE ;
}
CFRelease(interfaceID) ;
return result ;
}
IOFireWireLibIsochPortGetSupportedCallback
RemoteIsochPortCOM::SSetGetSupportedHandler(
PortRef self,
IOFireWireLibIsochPortGetSupportedCallback inHandler)
{
return IOFireWireIUnknown::InterfaceMap<RemoteIsochPortCOM>::GetThis(self)->SetGetSupportedHandler(inHandler) ;
}
IOFireWireLibIsochPortAllocateCallback
RemoteIsochPortCOM::SSetAllocatePortHandler(
PortRef self,
IOFireWireLibIsochPortAllocateCallback inHandler)
{
return IOFireWireIUnknown::InterfaceMap<RemoteIsochPortCOM>::GetThis(self)->SetAllocatePortHandler(inHandler) ;
}
IOFireWireLibIsochPortCallback
RemoteIsochPortCOM::SSetReleasePortHandler(
PortRef self,
IOFireWireLibIsochPortCallback inHandler)
{
return IOFireWireIUnknown::InterfaceMap<RemoteIsochPortCOM>::GetThis(self)->SetReleasePortHandler(inHandler) ;
}
IOFireWireLibIsochPortCallback
RemoteIsochPortCOM::SSetStartHandler(
PortRef self,
IOFireWireLibIsochPortCallback inHandler)
{
return IOFireWireIUnknown::InterfaceMap<RemoteIsochPortCOM>::GetThis(self)->SetStartHandler(inHandler) ;
}
IOFireWireLibIsochPortCallback
RemoteIsochPortCOM::SSetStopHandler(
PortRef self,
IOFireWireLibIsochPortCallback inHandler)
{
return IOFireWireIUnknown::InterfaceMap<RemoteIsochPortCOM>::GetThis(self)->SetStopHandler(inHandler) ;
}
#pragma mark -
LocalIsochPortCOM::Interface LocalIsochPortCOM::sInterface =
{
INTERFACEIMP_INTERFACE
,4,0
,IOFIREWIREISOCHPORTIMP_INTERFACE
,& LocalIsochPortCOM::SModifyJumpDCL
,& LocalIsochPortCOM::SPrintDCLProgram
,& LocalIsochPortCOM::SModifyTransferPacketDCLSize
,& LocalIsochPortCOM::SModifyTransferPacketDCLBuffer
,& LocalIsochPortCOM::SModifyTransferPacketDCL
,& LocalIsochPortCOM::S_SetFinalizeCallback
, & LocalIsochPortCOM::S_SetResourceUsageFlags
, & LocalIsochPortCOM::S_Notify
} ;
LocalIsochPort::LocalIsochPort( const IUnknownVTbl & interface, Device & userclient, bool talking,
DCLCommand* program, UInt32 startEvent, UInt32 startState, UInt32 startMask,
IOVirtualRange userProgramRanges[], UInt32 userProgramRangeCount,
IOVirtualRange userBufferRanges[], UInt32 userBufferRangeCount )
: IsochPortCOM( interface, userclient, talking, false )
, mDCLProgram( program )
, mExpectedStopTokens(0)
, mDeferredReleaseCount(0)
, mFinalizeCallback(nil)
, mBufferRanges( nil )
{
if ( !program )
{
DebugLog( "no DCL program!\n" ) ;
throw kIOReturnBadArgument ;
}
IOReturn error = kIOReturnSuccess ;
CoalesceTree bufferTree ;
if ( userBufferRanges )
{
for( unsigned index=0; index < userBufferRangeCount; ++index )
bufferTree.CoalesceRange( userBufferRanges[index]) ;
}
LocalIsochPortAllocateParams params ;
{
params.programExportBytes = 0 ;
params.programData = NULL ;
}
if ( program->opcode == kDCLNuDCLLeaderOp )
{
NuDCLPool* pool = reinterpret_cast<NuDCLPool*>( reinterpret_cast< DCLNuDCLLeader* >( program )->program ) ;
params.version = 1 ;
pool->CoalesceBuffers( bufferTree ) ;
mBufferRangeCount = bufferTree.GetCount() ;
mBufferRanges = new IOVirtualRange[ mBufferRangeCount ] ;
if ( !mBufferRanges )
{
error = kIOReturnNoMemory ;
}
else
{
bufferTree.GetCoalesceList( mBufferRanges ) ;
params.programExportBytes = pool->Export( & params.programData, mBufferRanges, mBufferRangeCount ) ;
}
}
else
{
unsigned programCount = 0 ;
params.version = 0 ;
for( DCLCommand * dcl = mDCLProgram; dcl != nil; dcl = dcl->pNextDCLCommand )
{
IOVirtualRange tempRange ;
if ( GetDCLDataBuffer ( dcl, & tempRange.address, & tempRange.length ) )
{
bufferTree.CoalesceRange ( tempRange ) ;
}
++programCount ;
}
InfoLog("program count is %d\n", programCount) ;
if ( !error )
{
error = ExportDCLs( & params.programData, & params.programExportBytes ) ;
}
if ( !error )
{
mBufferRangeCount = bufferTree.GetCount() ;
mBufferRanges = new IOVirtualRange[ mBufferRangeCount ] ;
if ( !mBufferRanges )
{
error = kIOReturnNoMemory ;
}
else
{
bufferTree.GetCoalesceList( mBufferRanges ) ;
}
}
}
if ( error )
{
throw error ;
}
params.bufferRanges = mBufferRanges ;
params.bufferRangeCount = mBufferRangeCount ;
params.talking = mTalking ;
params.startEvent = startEvent ;
params.startState = startState ;
params.startMask = startMask ;
params.userObj = this ;
InfoLog("startEvent=%x, startState=%x, startMask=%x\n", params.startEvent, params.startState, params.startMask) ;
IOByteCount outputSize = sizeof( UserObjectHandle ) ;
error = :: IOConnectMethodStructureIStructureO ( mDevice.GetUserClientConnection(),
kLocalIsochPort_Allocate, sizeof ( params ),
& outputSize, & params, & mKernPortRef ) ;
if (error)
{
DebugLog ( "Couldn't create local isoch port (error=%x)\nCheck your buffers!\n", error ) ;
DebugLog ( "Found buffers:\n" ) ;
#if IOFIREWIRELIBDEBUG
for( unsigned index=0; index < mBufferRangeCount; ++index )
{
DebugLog ( "\%u: <0x%x>-<0x%lx>\n", index, mBufferRanges[index].address,
(unsigned)mBufferRanges[index].address + mBufferRanges[index].length ) ;
}
#endif
throw error ;
}
{
mach_msg_type_number_t outputSize = 0 ;
io_scalar_inband_t params = { (int) mKernPortRef } ;
OSAsyncReference asyncRef ;
asyncRef[ kIOAsyncCalloutFuncIndex ] = (natural_t) (void (*)(IOReturn)) & LocalIsochPort::DCLStopTokenCallProcHandler ;
asyncRef[ kIOAsyncCalloutRefconIndex ] = (natural_t) this ;
error = :: io_async_method_scalarI_scalarO ( mDevice.GetUserClientConnection(),
mDevice.GetIsochAsyncPort(),
asyncRef, kOSAsyncRefCount, kSetAsyncRef_DCLCallProc,
params, 1, nil, & outputSize) ;
if( error )
{
throw error ;
}
}
if ( params.programData )
vm_deallocate( mach_task_self (), (vm_address_t) params.programData, params.programExportBytes ) ;
pthread_mutex_init ( & mMutex, nil ) ;
}
LocalIsochPort :: ~LocalIsochPort ()
{
delete[] mBufferRanges ;
pthread_mutex_destroy( & mMutex ) ;
}
ULONG
LocalIsochPort :: Release ()
{
Lock () ;
if ( mExpectedStopTokens > 0 )
{
Unlock () ;
++ mDeferredReleaseCount ;
return mRefCount ;
}
Unlock () ;
return IsochPortCOM::Release() ;
}
IOReturn
LocalIsochPort :: Stop ()
{
Lock() ;
++mExpectedStopTokens ;
InfoLog("waiting for %lu stop tokens\n", mExpectedStopTokens) ;
Unlock() ;
return IsochPortCOM::Stop() ; }
IOReturn
LocalIsochPort :: ModifyJumpDCL ( DCLJump* inJump, DCLLabel* inLabel )
{
inJump->pJumpDCLLabel = inLabel ;
IOReturn result = ::IOConnectMethodScalarIScalarO( mDevice.GetUserClientConnection(),
mDevice.MakeSelectorWithObject( kLocalIsochPort_ModifyJumpDCL_d,
mKernPortRef ),
2, 0, inJump->compilerData,
inLabel->compilerData ) ;
return result ;
}
IOReturn
LocalIsochPort :: ModifyTransferPacketDCLSize ( DCLTransferPacket* dcl, IOByteCount newSize )
{
return kIOReturnUnsupported ;
}
void
LocalIsochPort :: DCLStopTokenCallProcHandler( IOReturn )
{
if ( mExpectedStopTokens > 0 )
{
Lock() ;
mExpectedStopTokens-- ;
Unlock() ;
if ( mExpectedStopTokens == 0 )
{
if ( mFinalizeCallback )
(*mFinalizeCallback)(mRefCon) ;
while ( mDeferredReleaseCount > 0 )
{
Release() ;
--mDeferredReleaseCount ;
}
}
}
}
#if 0
void
LocalIsochPort :: S_DCLKernelCallout( DCLCallProc * dcl )
{
(*dcl->proc)(dcl->procData) ;
::IOConnectMethodScalarIScalarO( port->mDevice.GetUserClientConnection(),
Device::MakeSelectorWithObject( kLocalIsochPort_RunDCLUpdateList_d, port->mKernPortRef ), 1, 0, dcl->compilerData ) ;
}
void
LocalIsochPort :: S_NuDCLKernelCallout ( NuDCL * dcl )
{
(*dcl->fData.callback)(dcl->fData.refcon, (NuDCLRef)dcl) ;
::IOConnectMethodScalarIScalarO(
mDevice.GetUserClientConnection(),
Device::MakeSelectorWithObject( kLocalIsochPort_RunNuDCLUpdateList_d, mKernPortRef ), 1, 0, dcl->fExportIndex ) ;
}
#endif
IOReturn
LocalIsochPort :: SetResourceUsageFlags (
IOFWIsochResourceFlags flags )
{
return ::IOConnectMethodScalarIScalarO( mDevice.GetUserClientConnection(),
mDevice.MakeSelectorWithObject( kIsochPort_SetIsochResourceFlags_d, mKernPortRef ),
1, 0, flags ) ;
}
IOReturn
LocalIsochPort :: ExportDCLs( IOVirtualAddress * exportBuffer, IOByteCount * exportBytes )
{
IOReturn error = kIOReturnSuccess ;
*exportBytes = 0 ;
for( DCLCommand * dcl = mDCLProgram; dcl != NULL; dcl = dcl->pNextDCLCommand )
{
*exportBytes += GetDCLSize( dcl ) ;
switch ( dcl->opcode & ~kFWDCLOpFlagMask )
{
case kDCLUpdateDCLListOp :
{
*exportBytes += sizeof( DCLCommand* ) * ((DCLUpdateDCLList*)dcl)->numDCLCommands ;
break ;
}
case kDCLCallProcOp :
{
*exportBytes += sizeof( OSAsyncReference ) ;
break ;
}
}
}
error = vm_allocate( mach_task_self (), exportBuffer, *exportBytes, true ) ;
if ( !*exportBuffer && !error )
{
error = kIOReturnNoMemory ;
}
{
unsigned offset = 0 ;
IOVirtualAddress buffer = *exportBuffer ;
InfoLog("exporting DCLs, pass 1...\n") ;
for( DCLCommand * dcl = mDCLProgram; dcl != NULL ; dcl = dcl->pNextDCLCommand )
{
unsigned size = GetDCLSize( dcl ) ;
bcopy( dcl, (void*)buffer, size ) ;
dcl->compilerData = offset ;
switch ( dcl->opcode & ~kFWDCLOpFlagMask )
{
case kDCLUpdateDCLListOp :
size += ( sizeof( DCLCommand* ) * ((DCLUpdateDCLList*)dcl)->numDCLCommands ) ;
break ;
case kDCLCallProcOp :
((DCLCallProc*)buffer)->procData = (UInt32)dcl ;
size += sizeof( OSAsyncReference ) ;
break ;
default :
break ;
}
buffer += size ;
offset += size ;
}
InfoLog("...done\n") ;
}
{
unsigned offset = 0 ;
InfoLog("exporting DCLs, pass 2... export size=%d bytes\n", (int)*exportBytes ) ;
while( offset < *exportBytes )
{
DCLCommand * dcl = (DCLCommand*)(*exportBuffer + offset ) ;
{
unsigned opcode = dcl->opcode & ~kFWDCLOpFlagMask ;
assert( opcode <= 15 || opcode == 20 ) ;
}
unsigned size = GetDCLSize( dcl ) ;
switch ( dcl->opcode & ~kFWDCLOpFlagMask )
{
case kDCLUpdateDCLListOp :
{
DCLCommand ** list = (DCLCommand**)( ((DCLUpdateDCLList*)dcl) + 1 ) ;
for( unsigned index=0; index < ((DCLUpdateDCLList*)dcl)->numDCLCommands; ++index )
{
list[ index ] = (DCLCommand*) ((DCLUpdateDCLList*)dcl)->dclCommandList[ index ]->compilerData ;
}
size += sizeof( DCLCommand* ) * ((DCLUpdateDCLList*)dcl)->numDCLCommands ;
break ;
}
case kDCLJumpOp :
{
((DCLJump*)dcl)->pJumpDCLLabel = (DCLLabel*) ((DCLJump*)dcl)->pJumpDCLLabel->compilerData ;
break ;
}
case kDCLCallProcOp :
{
size += sizeof( OSAsyncReference ) ;
break ;
}
default :
break ;
}
offset += size ;
}
InfoLog("...done\n") ;
}
{
unsigned count = 0 ;
for( DCLCommand * dcl = mDCLProgram; dcl != nil; dcl = dcl->pNextDCLCommand )
{
dcl->compilerData = ++count ; }
}
return error ;
}
IOReturn
LocalIsochPort :: Notify (
IOFWDCLNotificationType notificationType,
void ** inDCLList,
UInt32 numDCLs )
{
IOReturn error = kIOReturnSuccess ;
switch( notificationType )
{
case kFWNuDCLModifyNotification:
{
IOByteCount dataSize = 0 ;
for( unsigned index=0; index < numDCLs; ++index )
{
dataSize += 4 + ((NuDCL**)inDCLList)[ index ]->Export( NULL, NULL, NULL ) ;
}
UInt8 data[ dataSize ] ;
{
UInt8 * exportCursor = data ;
for( unsigned index=0; index < numDCLs; ++index )
{
NuDCL * dcl = ((NuDCL**)inDCLList)[ index ] ;
*(UInt32*)exportCursor = dcl->GetExportIndex() ;
exportCursor += sizeof( UInt32 ) ;
dcl->Export( (IOVirtualAddress*) & exportCursor, mBufferRanges, mBufferRangeCount ) ;
}
}
error = ::IOConnectMethodScalarIStructureI(
mDevice.GetUserClientConnection(),
Device::MakeSelectorWithObject( kLocalIsochPort_Notify_d, mKernPortRef ),
2, dataSize, (UInt32)notificationType, numDCLs, data ) ;
break ;
}
case kFWNuDCLModifyJumpNotification:
{
unsigned pairCount = numDCLs << 1 ;
unsigned dcls[ pairCount ] ;
{
unsigned index = 0 ;
unsigned pairIndex=0;
while( pairIndex < pairCount )
{
NuDCL * theDCL = ((NuDCL**)inDCLList)[ index++ ] ;
dcls[ pairIndex++ ] = theDCL->GetExportIndex() ;
dcls[ pairIndex++ ] = theDCL->GetBranch()->GetExportIndex() ;
}
}
error = ::IOConnectMethodScalarIStructureI(
mDevice.GetUserClientConnection(),
Device::MakeSelectorWithObject( kLocalIsochPort_Notify_d, mKernPortRef ),
2, sizeof( dcls ), (UInt32)notificationType, numDCLs, dcls ) ;
break ;
}
case kFWNuDCLUpdateNotification:
{
unsigned dcls[ numDCLs ] ;
for( unsigned index=0; index < numDCLs; ++index )
{
dcls[ index ] = ((NuDCL*)inDCLList[ index ])->GetExportIndex() ;
}
error = ::IOConnectMethodScalarIStructureI(
mDevice.GetUserClientConnection(),
Device::MakeSelectorWithObject( kLocalIsochPort_Notify_d, mKernPortRef ),
2, sizeof( dcls ), (UInt32)notificationType, numDCLs, dcls ) ;
break ;
}
case kFWDCLUpdateNotification:
case kFWDCLModifyNotification:
{
error = kIOReturnUnsupported ;
}
default:
error = kIOReturnBadArgument ;
}
return error ;
}
#pragma mark -
LocalIsochPortCOM::LocalIsochPortCOM( Device& userclient, bool talking, DCLCommand* program, UInt32 startEvent,
UInt32 startState, UInt32 startMask, IOVirtualRange programRanges[], UInt32 programRangeCount,
IOVirtualRange bufferRanges[], UInt32 bufferRangeCount)
: LocalIsochPort( reinterpret_cast<const IUnknownVTbl &>( sInterface ), userclient, talking, program,
startEvent, startState, startMask, programRanges,
programRangeCount, bufferRanges, bufferRangeCount )
{
}
LocalIsochPortCOM::~LocalIsochPortCOM()
{
}
IUnknownVTbl**
LocalIsochPortCOM::Alloc( Device & userclient, Boolean talking, DCLCommand * program,
UInt32 startEvent, UInt32 startState, UInt32 startMask,
IOVirtualRange programRanges[], UInt32 programRangeCount,
IOVirtualRange bufferRanges[], UInt32 bufferRangeCount )
{
LocalIsochPortCOM* me = nil ;
try
{
me = new LocalIsochPortCOM ( userclient, (bool)talking, program, startEvent, startState, startMask,
programRanges, programRangeCount, bufferRanges, bufferRangeCount ) ;
}
catch(...)
{
}
return ( nil == me ) ? nil : reinterpret_cast < IUnknownVTbl ** > ( & me->GetInterface () ) ;
}
HRESULT
LocalIsochPortCOM :: QueryInterface ( REFIID iid, void ** ppv )
{
HRESULT result = S_OK ;
CFUUIDRef interfaceID = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, iid) ;
*ppv = nil ;
if ( CFEqual(interfaceID, IUnknownUUID)
|| CFEqual(interfaceID, kIOFireWireLocalIsochPortInterfaceID )
|| CFEqual( interfaceID, kIOFireWireLocalIsochPortInterfaceID_v2 )
#if 0
|| CFEqual( interfaceID, kIOFireWireLocalIsochPortInterfaceID_v3 ) #endif
|| CFEqual( interfaceID, kIOFireWireLocalIsochPortInterfaceID_v4 )
|| CFEqual( interfaceID, kIOFireWireLocalIsochPortInterfaceID_v5 )
)
{
* ppv = & GetInterface () ;
AddRef () ;
}
else
{
* ppv = nil ;
result = E_NOINTERFACE ;
}
:: CFRelease ( interfaceID ) ;
return result ;
}
IOReturn
LocalIsochPortCOM :: SModifyJumpDCL(
IOFireWireLibLocalIsochPortRef self,
DCLJump * jump,
DCLLabel * label)
{
return IOFireWireIUnknown :: InterfaceMap< LocalIsochPortCOM > :: GetThis ( self )->ModifyJumpDCL ( jump, label ) ;
}
void
LocalIsochPortCOM :: SPrintDCLProgram (
IOFireWireLibLocalIsochPortRef self ,
const DCLCommand * program ,
UInt32 length )
{
DeviceCOM :: SPrintDCLProgram ( nil, program, length ) ;
}
IOReturn
LocalIsochPortCOM :: SModifyTransferPacketDCLSize (
PortRef self,
DCLTransferPacket * dcl,
IOByteCount newSize )
{
IOReturn error = kIOReturnBadArgument ;
switch ( dcl->opcode )
{
case kDCLSendPacketStartOp:
case kDCLSendPacketWithHeaderStartOp:
case kDCLSendPacketOp:
case kDCLReceivePacketStartOp:
case kDCLReceivePacketOp:
case kDCLReceiveBufferOp:
error = IOFireWireIUnknown::InterfaceMap<LocalIsochPortCOM>::GetThis( self )->ModifyTransferPacketDCLSize( dcl, newSize ) ;
}
return error ;
}
IOReturn
LocalIsochPortCOM :: SModifyTransferPacketDCLBuffer (
PortRef self,
DCLTransferPacket * dcl,
void * newBuffer )
{
return kIOReturnUnsupported ;
}
IOReturn
LocalIsochPortCOM :: SModifyTransferPacketDCL ( PortRef self, DCLTransferPacket * dcl, void * newBuffer, IOByteCount newSize )
{
return kIOReturnUnsupported ;
}
IOReturn
LocalIsochPortCOM :: S_SetFinalizeCallback(
IOFireWireLibLocalIsochPortRef self,
IOFireWireLibIsochPortFinalizeCallback finalizeCallback )
{
LocalIsochPortCOM * me = IOFireWireIUnknown :: InterfaceMap< LocalIsochPortCOM > :: GetThis( self ) ;
me->mFinalizeCallback = finalizeCallback ;
return kIOReturnSuccess ;
}
IOReturn
LocalIsochPortCOM :: S_SetResourceUsageFlags (
IOFireWireLibLocalIsochPortRef self,
IOFWIsochResourceFlags flags )
{
return IOFireWireIUnknown::InterfaceMap< LocalIsochPortCOM >::GetThis( self )->SetResourceUsageFlags( flags ) ;
}
IOReturn
LocalIsochPortCOM :: S_Notify(
IOFireWireLibLocalIsochPortRef self,
IOFWDCLNotificationType notificationType,
void ** inDCLList,
UInt32 numDCLs )
{
return IOFireWireIUnknown::InterfaceMap< LocalIsochPortCOM >::GetThis( self )->Notify( notificationType, inDCLList, numDCLs ) ;
}
}