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>
#import <System/libkern/OSCrossEndian.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, IOFWIsochPortOptions options )
: IsochPortCOM( interface, userclient, talking, false )
, mDCLProgram( program )
, mExpectedStopTokens(0)
, mDeferredReleaseCount(0)
, mFinalizeCallback(nil)
, mBufferRanges( nil )
, mStarted( false )
{
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]) ;
}
IOByteCount programExportBytes = 0 ;
IOVirtualAddress programData = 0 ;
LocalIsochPortAllocateParams params ;
{
params.programExportBytes = 0 ;
params.programData = 0 ;
}
if ( program->opcode == kDCLNuDCLLeaderOp )
{
if( !error )
{
NuDCLPool* pool = reinterpret_cast<NuDCLPool*>( reinterpret_cast< DCLNuDCLLeader* >( program )->program ) ;
params.version = kDCLExportDataNuDCLRosettaVersion ;
pool->CoalesceBuffers( bufferTree ) ;
mBufferRangeCount = bufferTree.GetCount() ;
mBufferRanges = new IOVirtualRange[ mBufferRangeCount ] ;
if ( !mBufferRanges )
{
error = kIOReturnNoMemory ;
}
else
{
bufferTree.GetCoalesceList( mBufferRanges ) ;
programExportBytes = pool->Export( &programData, mBufferRanges, mBufferRangeCount ) ;
params.programExportBytes = programExportBytes ;
params.programData = programData;
}
}
}
else
{
unsigned programCount = 0 ;
params.version = kDCLExportDataLegacyVersion ;
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( &programData, &programExportBytes ) ;
params.programData = programData;
params.programExportBytes = 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 ;
params.options = options ;
#if 0
params.options |= kFWIsochEnableRobustness;
#endif
InfoLog("startEvent=%x, startState=%x, startMask=%x\n", params.startEvent, params.startState, params.startMask) ;
ROSETTA_ONLY(
{
params.version = OSSwapInt32( params.version );
params.talking = params.talking; params.startEvent = OSSwapInt32( params.startEvent );
params.startState = OSSwapInt32( params.startState );
params.startMask = OSSwapInt32( params.startMask );
params.programExportBytes = OSSwapInt32( params.programExportBytes );
params.programData = OSSwapInt32( params.programData );
for( UInt32 i = 0; i < params.bufferRangeCount; i++ )
{
params.bufferRanges[i].address = OSSwapInt32( params.bufferRanges[i].address );
params.bufferRanges[i].length = OSSwapInt32( params.bufferRanges[i].length );
}
params.bufferRangeCount = OSSwapInt32( params.bufferRangeCount );
params.bufferRanges = (IOVirtualRange*)OSSwapInt32( (UInt32)params.bufferRanges );
params.options = (IOFWIsochPortOptions)OSSwapInt32( params.options | kFWIsochBigEndianUpdates );
params.userObj = (void*)OSSwapInt32( (UInt32)params.userObj );
}
);
IOByteCount outputSize = sizeof( UserObjectHandle ) ;
error = :: IOConnectMethodStructureIStructureO ( mDevice.GetUserClientConnection(),
kLocalIsochPort_Allocate, sizeof ( params ),
& outputSize, & params, & mKernPortRef ) ;
ROSETTA_ONLY(
{
mKernPortRef = (UserObjectHandle)OSSwapInt32( (UInt32)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) & LocalIsochPort::s_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) programData, 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 :: Start()
{
IOReturn error = IsochPort::Start() ;
if ( !error )
{
Lock() ;
mStarted = true ;
Unlock() ;
}
return error ;
}
IOReturn
LocalIsochPort :: Stop ()
{
Lock() ;
if ( mStarted )
{
mStarted = false ;
++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::s_DCLStopTokenCallProcHandler ( void * self, IOReturn e )
{
((LocalIsochPort*)self)->DCLStopTokenCallProcHandler(e) ;
}
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 ;
}
ROSETTA_ONLY(
{
switch(dcl->opcode & ~kFWDCLOpFlagMask)
{
case kDCLSendPacketStartOp:
case kDCLSendPacketWithHeaderStartOp:
case kDCLSendPacketOp:
case kDCLReceivePacketStartOp:
case kDCLReceivePacketOp:
((DCLTransferPacket*)dcl)->pNextDCLCommand = (DCLCommand*)OSSwapInt32( (UInt32)((DCLTransferPacket*)dcl)->pNextDCLCommand );
((DCLTransferPacket*)dcl)->compilerData = OSSwapInt32( ((DCLTransferPacket*)dcl)->compilerData );
((DCLTransferPacket*)dcl)->opcode = OSSwapInt32( ((DCLTransferPacket*)dcl)->opcode );
((DCLTransferPacket*)dcl)->buffer = (void*)OSSwapInt32( (UInt32)((DCLTransferPacket*)dcl)->buffer );
((DCLTransferPacket*)dcl)->size = OSSwapInt32( ((DCLTransferPacket*)dcl)->size );
break ;
case kDCLSendBufferOp:
case kDCLReceiveBufferOp:
((DCLTransferPacket*)dcl)->pNextDCLCommand = (DCLCommand*)OSSwapInt32( (UInt32)((DCLTransferPacket*)dcl)->pNextDCLCommand );
((DCLTransferBuffer*)dcl)->compilerData = OSSwapInt32( ((DCLTransferBuffer*)dcl)->compilerData );
((DCLTransferBuffer*)dcl)->opcode = OSSwapInt32( ((DCLTransferBuffer*)dcl)->opcode );
((DCLTransferBuffer*)dcl)->buffer = (void*)OSSwapInt32( (UInt32)((DCLTransferBuffer*)dcl)->buffer );
((DCLTransferBuffer*)dcl)->size = OSSwapInt32( ((DCLTransferBuffer*)dcl)->size );
((DCLTransferBuffer*)dcl)->packetSize = OSSwapInt16( ((DCLTransferBuffer*)dcl)->packetSize );
((DCLTransferBuffer*)dcl)->reserved = OSSwapInt16( ((DCLTransferBuffer*)dcl)->reserved );
((DCLTransferBuffer*)dcl)->bufferOffset = OSSwapInt32( ((DCLTransferBuffer*)dcl)->bufferOffset );
break ;
case kDCLCallProcOp:
((DCLTransferPacket*)dcl)->pNextDCLCommand = (DCLCommand*)OSSwapInt32( (UInt32)((DCLTransferPacket*)dcl)->pNextDCLCommand );
((DCLCallProc*)dcl)->compilerData = OSSwapInt32( ((DCLCallProc*)dcl)->compilerData );
((DCLCallProc*)dcl)->opcode = OSSwapInt32( ((DCLCallProc*)dcl)->opcode );
((DCLCallProc*)dcl)->proc = (DCLCallCommandProc *)OSSwapInt32( (UInt32)((DCLCallProc*)dcl)->proc );
((DCLCallProc*)dcl)->procData = OSSwapInt32( ((DCLCallProc*)dcl)->procData );
break ;
case kDCLLabelOp:
((DCLTransferPacket*)dcl)->pNextDCLCommand = (DCLCommand*)OSSwapInt32( (UInt32)((DCLTransferPacket*)dcl)->pNextDCLCommand );
((DCLLabel*)dcl)->compilerData = OSSwapInt32( ((DCLLabel*)dcl)->compilerData );
((DCLLabel*)dcl)->opcode = OSSwapInt32( ((DCLLabel*)dcl)->opcode );
break ;
case kDCLJumpOp:
((DCLTransferPacket*)dcl)->pNextDCLCommand = (DCLCommand*)OSSwapInt32( (UInt32)((DCLTransferPacket*)dcl)->pNextDCLCommand );
((DCLJump*)dcl)->compilerData = OSSwapInt32( ((DCLJump*)dcl)->compilerData );
((DCLJump*)dcl)->opcode = OSSwapInt32( ((DCLJump*)dcl)->opcode );
((DCLJump*)dcl)->pJumpDCLLabel = (DCLLabel*)OSSwapInt32( (UInt32)((DCLJump*)dcl)->pJumpDCLLabel );
break ;
case kDCLSetTagSyncBitsOp:
((DCLTransferPacket*)dcl)->pNextDCLCommand = (DCLCommand*)OSSwapInt32( (UInt32)((DCLTransferPacket*)dcl)->pNextDCLCommand );
((DCLSetTagSyncBits*)dcl)->compilerData = OSSwapInt32( ((DCLSetTagSyncBits*)dcl)->compilerData );
((DCLSetTagSyncBits*)dcl)->opcode = OSSwapInt32( ((DCLSetTagSyncBits*)dcl)->opcode );
((DCLSetTagSyncBits*)dcl)->tagBits = OSSwapInt16( ((DCLSetTagSyncBits*)dcl)->tagBits );
((DCLSetTagSyncBits*)dcl)->syncBits = OSSwapInt16( ((DCLSetTagSyncBits*)dcl)->syncBits );
break ;
case kDCLUpdateDCLListOp:
((DCLTransferPacket*)dcl)->pNextDCLCommand = (DCLCommand*)OSSwapInt32( (UInt32)((DCLTransferPacket*)dcl)->pNextDCLCommand );
((DCLUpdateDCLList*)dcl)->compilerData = OSSwapInt32( ((DCLUpdateDCLList*)dcl)->compilerData );
((DCLUpdateDCLList*)dcl)->opcode = OSSwapInt32( ((DCLUpdateDCLList*)dcl)->opcode );
{
DCLCommand ** list = (DCLCommand**)( ((DCLUpdateDCLList*)dcl) + 1 ) ;
for( unsigned index=0; index < ((DCLUpdateDCLList*)dcl)->numDCLCommands; ++index )
{
list[ index ] = (DCLCommand*)OSSwapInt32( (UInt32)list[ index ] );
}
}
((DCLUpdateDCLList*)dcl)->dclCommandList = (DCLCommand**)OSSwapInt32( (UInt32)((DCLUpdateDCLList*)dcl)->dclCommandList );
((DCLUpdateDCLList*)dcl)->numDCLCommands = OSSwapInt32( ((DCLUpdateDCLList*)dcl)->numDCLCommands );
break ;
case kDCLPtrTimeStampOp:
((DCLTransferPacket*)dcl)->pNextDCLCommand = (DCLCommand*)OSSwapInt32( (UInt32)((DCLTransferPacket*)dcl)->pNextDCLCommand );
((DCLPtrTimeStamp*)dcl)->compilerData = OSSwapInt32( ((DCLPtrTimeStamp*)dcl)->compilerData );
((DCLPtrTimeStamp*)dcl)->opcode = OSSwapInt32( ((DCLPtrTimeStamp*)dcl)->opcode );
((DCLPtrTimeStamp*)dcl)->timeStampPtr = (UInt32 *)OSSwapInt32( (UInt32)((DCLPtrTimeStamp*)dcl)->timeStampPtr );
break;
case kDCLSkipCycleOp:
((DCLTransferPacket*)dcl)->pNextDCLCommand = (DCLCommand*)OSSwapInt32( (UInt32)((DCLTransferPacket*)dcl)->pNextDCLCommand );
((DCLCommand*)dcl)->compilerData = OSSwapInt32( ((DCLCommand*)dcl)->compilerData );
((DCLCommand*)dcl)->opcode = OSSwapInt32( ((DCLCommand*)dcl)->opcode );
((DCLCommand*)dcl)->operands[1] = OSSwapInt32( ((DCLCommand*)dcl)->operands[1] );
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, 0 ) ;
}
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, IOFWIsochPortOptions options )
: LocalIsochPort( reinterpret_cast<const IUnknownVTbl &>( sInterface ), userclient, talking, program,
startEvent, startState, startMask, programRanges,
programRangeCount, bufferRanges, bufferRangeCount, options )
{
}
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,
IOFWIsochPortOptions options )
{
LocalIsochPortCOM* me = nil ;
try
{
me = new LocalIsochPortCOM ( userclient, (bool)talking, program, startEvent, startState, startMask,
programRanges, programRangeCount, bufferRanges, bufferRangeCount, options ) ;
}
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
{
DebugLog("unknown local isoch port interface UUID\n") ;
* 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 ) ;
}
}