IOFWUserIsochPort.cpp [plain text]
#import <IOKit/firewire/IOFireWireDevice.h>
#import <IOKit/firewire/IOFireWireController.h>
#import <IOKit/firewire/IOFWLocalIsochPort.h>
#import <IOKit/firewire/IOFWDCLTranslator.h>
#import <IOKit/firewire/IOFWDCLPool.h>
#import <IOKit/firewire/IOFWDCL.h>
#import <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IOKitKeysPrivate.h>
#include <IOKit/IODMACommand.h>
#import <IOKit/firewire/IOFireWireLink.h>
#import "IOFireWireUserClient.h"
#import "IOFWUserIsochPort.h"
#if 0
class DebugThing
{
public :
natural_t * asyncRef ;
IOFWUserLocalIsochPort * port;
} ;
#endif
extern bool findOffsetInRanges ( IOVirtualAddress address, unsigned rangeCount, IOVirtualRange ranges[], IOByteCount & outOffset ) ;
static bool
getDCLDataBuffer(
const 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 kDCLPtrTimeStampOp:
outDataBuffer = (IOVirtualAddress)( (DCLPtrTimeStamp *) dcl )->timeStampPtr ;
outDataLength = sizeof ( *( ( (DCLPtrTimeStamp *)dcl )->timeStampPtr) ) ;
result = true ;
break ;
default:
break ;
}
return result ;
}
static void
setDCLDataBuffer (
DCLCommand* inDCL,
IOVirtualAddress inDataBuffer,
IOByteCount inDataLength )
{
switch(inDCL->opcode & ~kFWDCLOpFlagMask)
{
case kDCLSendPacketStartOp:
case kDCLSendPacketWithHeaderStartOp:
case kDCLSendPacketOp:
case kDCLReceivePacketStartOp:
case kDCLReceivePacketOp:
((DCLTransferPacket*)inDCL)->buffer = (void*) inDataBuffer ;
((DCLTransferPacket*)inDCL)->size = inDataLength ;
break ;
case kDCLSendBufferOp:
case kDCLReceiveBufferOp:
break ;
case kDCLPtrTimeStampOp:
((DCLPtrTimeStamp*)inDCL)->timeStampPtr = (UInt32*)inDataBuffer ;
break ;
default:
break ;
}
}
static 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 ;
}
#if 0
static bool
findOffsetIndexInRanges (
IOVirtualAddress address,
unsigned rangeCount,
IOVirtualRange ranges[],
unsigned & outIndex,
unsigned & hint )
{
if ( hint > 0 )
--hint ;
unsigned index = hint ;
do
{
if ( ( ranges[ index ].address <= address ) && ( ( ranges[ index ].address + ranges[ index ].length ) > address ) )
{
outIndex = index ;
hint = index ;
return true ;
}
index = ( index + 1 ) % rangeCount ;
} while ( index != hint ) ;
return false ;
}
#endif
#pragma mark -
#undef super
#define super IOFWLocalIsochPort
OSDefineMetaClassAndStructors ( IOFWUserLocalIsochPort, super )
#if 0
{}
#endif
#if IOFIREWIREDEBUG > 0
bool
IOFWUserLocalIsochPort :: serialize( OSSerialize * s ) const
{
const OSString * keys[ 1 ] =
{
OSString::withCString( "program" )
} ;
const OSObject * objects[ 1 ] =
{
fProgram ? (const OSObject*)fProgram : (const OSObject*)OSString::withCString( "(null)" )
} ;
OSDictionary * dict = OSDictionary::withObjects( objects, keys, sizeof( keys )/sizeof( OSObject* ) ) ;
if ( !dict )
return false ;
bool result = dict->serialize( s ) ;
dict->release() ;
return result ;
}
#endif // IOFIREWIREDEBUG > 0
void
IOFWUserLocalIsochPort :: free()
{
if ( fDCLPool )
{
fDCLPool->release() ;
fDCLPool = NULL ;
}
delete [] (UInt8*)fProgramBuffer ;
fProgramBuffer = NULL ;
if ( fLock )
{
IORecursiveLockFree( fLock ) ;
}
delete[] fDCLTable ;
fDCLTable = NULL ;
super :: free() ;
}
#if 0
IOReturn checkMemoryInRange( IOMemoryDescriptor * memory, UInt64 mask )
{
IOReturn status = kIOReturnSuccess;
if( memory == NULL )
{
status = kIOReturnBadArgument;
}
bool memory_prepared = false;
if( status == kIOReturnSuccess )
{
status = memory->prepare( kIODirectionInOut );
}
if( status == kIOReturnSuccess )
{
memory_prepared = true;
}
UInt64 length = 0;
IODMACommand * dma_command = NULL;
if( status == kIOReturnSuccess )
{
length = memory->getLength();
dma_command = IODMACommand::withSpecification(
kIODMACommandOutputHost64, 64, length, IODMACommand::kMapped | IODMACommand::kIterateOnly, length, 0, NULL, NULL ); if( dma_command == NULL )
status = kIOReturnError;
}
if( status == kIOReturnSuccess )
{
status = dma_command->setMemoryDescriptor( memory, false );
}
bool dma_command_prepared = false;
if( status == kIOReturnSuccess )
{
status = dma_command->prepare( 0, length, true );
}
if( status == kIOReturnSuccess )
{
dma_command_prepared = true;
}
if( status == kIOReturnSuccess )
{
UInt64 offset = 0;
while( (offset < length) && (status == kIOReturnSuccess) )
{
IODMACommand::Segment64 segments[10];
UInt32 num_segments = 10;
status = dma_command->gen64IOVMSegments( &offset, segments, &num_segments );
if( status == kIOReturnSuccess )
{
for( UInt32 i = 0; i < num_segments; i++ )
{
if( (segments[i].fIOVMAddr & (~mask)) )
{
IOLog( "checkSegmentsFailed - 0x%016llx & 0x%016llx\n", segments[i].fIOVMAddr, mask );
status = kIOReturnNotPermitted;
break;
}
}
}
}
}
if( dma_command_prepared )
{
dma_command->complete();
dma_command_prepared = false;
}
if( dma_command )
{
dma_command->release();
dma_command = NULL;
}
if( memory_prepared )
{
memory->complete();
memory_prepared = false;
}
return status;
}
#endif
bool
IOFWUserLocalIsochPort :: initWithUserDCLProgram (
AllocateParams * params,
IOFireWireUserClient & userclient,
IOFireWireController & controller )
{
if ( params->programExportBytes == 0 )
{
ErrorLog ( "No program!" ) ;
return false ;
}
fLock = IORecursiveLockAlloc () ;
if ( ! fLock )
{
ErrorLog ( "Couldn't allocate recursive lock\n" ) ;
return false ;
}
fUserObj = params->userObj ;
fUserClient = & userclient ;
fDCLPool = NULL ;
fProgramCount = 0;
fStarted = false ;
IOReturn error = kIOReturnSuccess ;
IOVirtualRange * bufferRanges = new IOVirtualRange[ params->bufferRangeCount ] ;
if ( !bufferRanges )
{
error = kIOReturnNoMemory ;
}
if ( !error )
{
error = fUserClient->copyUserData( (IOVirtualAddress)params->bufferRanges, (IOVirtualAddress)bufferRanges,
sizeof ( IOVirtualRange ) * params->bufferRangeCount ) ;
}
IOMemoryDescriptor * bufferDesc = NULL ;
if ( ! error )
{
{
IOByteCount length = 0 ;
for ( unsigned index = 0; index < params->bufferRangeCount; ++index )
{
length += bufferRanges[ index ].length ;
}
}
bufferDesc = IOMemoryDescriptor :: withRanges ( bufferRanges, params->bufferRangeCount, kIODirectionOutIn,
fUserClient->getOwningTask() ) ;
if ( ! bufferDesc )
error = kIOReturnNoMemory ;
else
{
error = bufferDesc->prepare( kIODirectionPrepareToPhys32 ) ;
}
}
IOMemoryMap * bufferMap = NULL ;
if ( !error )
{
bufferMap = bufferDesc->map() ;
if ( !bufferMap )
{
DebugLog( "Couldn't map program buffers\n" ) ;
error = kIOReturnVMError ;
}
bufferDesc->release() ;
}
IOMemoryDescriptor * userProgramExportDesc = NULL ;
if ( !error )
{
userProgramExportDesc = IOMemoryDescriptor::withAddress(
params->programData,
params->programExportBytes,
kIODirectionOut,
fUserClient->getOwningTask() ) ;
}
if ( userProgramExportDesc )
{
error = userProgramExportDesc->prepare() ;
}
if ( !error )
{
DCLCommand * opcodes = NULL ;
switch ( params->version )
{
case kDCLExportDataLegacyVersion :
error = importUserProgram( userProgramExportDesc, params->bufferRangeCount, bufferRanges, bufferMap ) ;
ErrorLogCond( error, "importUserProgram returned %x\n", error ) ;
if ( ! error )
{
opcodes = (DCLCommand*)fProgramBuffer ;
}
break ;
case kDCLExportDataNuDCLRosettaVersion :
fDCLPool = fUserClient->getOwner()->getBus()->createDCLPool() ;
if ( ! fDCLPool )
{
error = kIOReturnNoMemory ;
}
if ( !error )
{
error = fDCLPool->importUserProgram( userProgramExportDesc, params->bufferRangeCount, bufferRanges, bufferMap ) ;
}
fProgramBuffer = new UInt8[ sizeof( DCLNuDCLLeader ) ] ;
{
DCLNuDCLLeader * leader = (DCLNuDCLLeader*)fProgramBuffer ;
{
leader->pNextDCLCommand = NULL ; leader->opcode = kDCLNuDCLLeaderOp ;
leader->program = fDCLPool ;
}
opcodes = (DCLCommand*)leader ;
}
break ;
default :
ErrorLog ( "unsupported DCL program type\n" ) ;
error = kIOReturnBadArgument ;
break ;
}
ErrorLogCond( !opcodes, "Couldn't get opcodes\n" ) ;
IODCLProgram * program = NULL ;
if ( opcodes )
{
IOFireWireBus::DCLTaskInfoAux infoAux ;
{
infoAux.version = 2 ;
infoAux.u.v2.bufferMemoryMap = bufferMap ;
infoAux.u.v2.workloop = params->options & kFWIsochPortUseSeparateKernelThread ? createRealtimeThread() : NULL ;
infoAux.u.v2.options = params->options ;
}
IOFireWireBus::DCLTaskInfo info = { 0, 0, 0, 0, 0, 0, & infoAux } ;
program = fUserClient->getOwner()->getController()->getLink()->createDCLProgram( params->talking,
opcodes,
& info,
params->startEvent,
params->startState,
params->startMask ) ;
bufferMap->release() ; bufferMap = NULL ;
if ( infoAux.u.v2.workloop )
{
infoAux.u.v2.workloop->release() ;
}
DebugLogCond( !program, "createDCLProgram returned nil\n" ) ;
}
if ( program )
{
if ( ! super::init( program, & controller ) )
{
ErrorLog ( "IOFWUserIsochPort :: init failed\n" ) ;
error = kIOReturnError ;
}
program->setForceStopProc( IOFireWireUserClient::s_IsochChannel_ForceStopHandler, 0, NULL ) ;
}
else
{
DebugLog ( "Couldn't create DCL program\n" ) ;
error = kIOReturnNoMemory ;
}
userProgramExportDesc->complete() ;
userProgramExportDesc->release() ;
userProgramExportDesc = NULL ;
}
delete [] bufferRanges ;
InfoLog( "-IOFWUserLocalIsochPort :: initWithUserDCLProgram error=%x (build date "__TIME__" "__DATE__")\n", error ) ;
return ( ! error ) ;
}
IOReturn
IOFWUserLocalIsochPort :: importUserProgram (
IOMemoryDescriptor * userExportDesc,
unsigned userBufferRangeCount,
IOVirtualRange userBufferRanges[],
IOMemoryMap * bufferMap )
{
IOReturn error = kIOReturnSuccess ;
if ( ! error )
{
fProgramBuffer = new UInt8[ userExportDesc->getLength() ] ;
if ( !fProgramBuffer )
{
error = kIOReturnNoMemory ;
}
}
if ( !error )
{
unsigned byteCount = userExportDesc->readBytes( 0, (void*)fProgramBuffer, userExportDesc->getLength() ) ;
if ( byteCount < userExportDesc->getLength() )
{
error = kIOReturnVMError ;
}
}
if ( ! error )
{
for( DCLCommand * dcl = (DCLCommand*)fProgramBuffer; dcl != NULL && !error; dcl = dcl->pNextDCLCommand )
{
{
unsigned opcode = dcl->opcode & ~kFWDCLOpFlagMask ;
if ( opcode > 15 && opcode != 20 )
{
ErrorLog("found invalid DCL in export data\n") ;
error = kIOFireWireBogusDCLProgram ;
break ;
}
}
unsigned size = getDCLSize( dcl ) ;
{
IOVirtualRange tempRange ;
if ( getDCLDataBuffer ( dcl, tempRange.address, tempRange.length ) )
{
if ( tempRange.address != NULL && tempRange.length > 0 )
{
IOByteCount offset ;
if ( ! findOffsetInRanges ( tempRange.address, userBufferRangeCount, userBufferRanges, offset ) )
{
DebugLog( "IOFWUserLocalIsochPort::initWithUserDCLProgram: couldn't find DCL data buffer in buffer ranges") ;
}
setDCLDataBuffer ( dcl, bufferMap->getVirtualAddress() + offset, tempRange.length ) ;
}
}
}
switch( dcl->opcode & ~kFWDCLOpFlagMask )
{
case kDCLUpdateDCLListOp:
size += sizeof( DCLCommand * ) * ((DCLUpdateDCLList*)dcl)->numDCLCommands ;
error = convertToKernelDCL( ( DCLUpdateDCLList * ) dcl ) ;
break ;
case kDCLCallProcOp :
size += sizeof( OSAsyncReference ) ;
error = convertToKernelDCL ( (DCLCallProc*) dcl ) ;
break ;
case kDCLJumpOp:
error = convertToKernelDCL( ( DCLJump * ) dcl ) ;
break ;
}
if ( dcl->pNextDCLCommand )
dcl->pNextDCLCommand = (DCLCommand*)( ((UInt8*)dcl) + size ) ;
++fProgramCount ;
}
fDCLTable = new DCLCommand*[ fProgramCount ] ;
InfoLog( "made DCL table, %d entries\n", fProgramCount ) ;
if ( !fDCLTable )
error = kIOReturnNoMemory ;
if ( !error )
{
unsigned index = 0 ;
for( DCLCommand * dcl = (DCLCommand*)fProgramBuffer; dcl != NULL; dcl = dcl->pNextDCLCommand )
{
if ( index >= fProgramCount )
panic("dcl table out of bounds\n") ;
fDCLTable[ index++ ] = dcl ;
}
}
}
return error ;
}
#if 0
IOReturn
IOFWUserLocalIsochPort :: releasePort ()
{
return super :: releasePort () ;
}
#endif
IOReturn
IOFWUserLocalIsochPort::start()
{
IOReturn error = super::start() ;
fStarted = (!error) ;
return error ;
}
IOReturn
IOFWUserLocalIsochPort :: stop ()
{
IOReturn error ;
error = super :: stop() ;
if ( fStarted )
{
error = IOFireWireUserClient::sendAsyncResult( fStopTokenAsyncRef, kIOFireWireLastDCLToken, NULL, 0 ) ;
fStarted = false ;
}
return error ;
}
void
IOFWUserLocalIsochPort :: s_dclCallProcHandler( DCLCallProc * dcl )
{
#if 0
#if IOFIREWIREUSERCLIENTDEBUG > 0
IOFWUserLocalIsochPort * me = (IOFWUserLocalIsochPort *) holder->obj ;
DebugLog("+IOFWUserLocalIsochPort :: s_dclCallProcHandler, holder=%p, (holder->asyncRef)[0]=0x%x\n", holder, (holder->asyncRef)[0]) ;
me->fUserClient->getStatistics()->getIsochCallbackCounter()->addValue( 1 ) ;
#endif
#endif
if ( dcl->procData )
{
#if 0
DebugThing * debugThing = (DebugThing*)dcl->procData ;
IOFireWireUserClient::sendAsyncResult( (natural_t*)debugThing->asyncRef, kIOReturnSuccess, NULL, 0 ) ;
DebugLog("send callback port=%p\n", debugThing->port ) ;
#else
IOFireWireUserClient::sendAsyncResult( (natural_t*)dcl->procData, kIOReturnSuccess, NULL, 0 ) ;
#endif
}
}
void
IOFWUserLocalIsochPort :: s_nuDCLCallout( void * refcon )
{
natural_t * asyncRef = (natural_t *)refcon ;
IOFireWireUserClient :: sendAsyncResult( asyncRef, kIOReturnSuccess, NULL, 0 ) ;
}
IOReturn
IOFWUserLocalIsochPort::setAsyncRef_DCLCallProc( OSAsyncReference asyncRef )
{
bcopy( asyncRef, fStopTokenAsyncRef, sizeof( OSAsyncReference ) ) ;
if ( fDCLPool )
{
const OSArray * program = fDCLPool->getProgramRef() ;
for( unsigned index = 0, count = program->getCount(); index < count; ++index )
{
IOFWDCL * dcl = reinterpret_cast< IOFWDCL * >( program->getObject( index ) ) ;
if ( dcl->getCallback() )
{
natural_t * dclAsyncRef = (natural_t*)dcl->getRefcon() ;
if ( asyncRef )
{
bcopy( asyncRef, dclAsyncRef, sizeof( natural_t ) * kIOAsyncReservedCount ) ;
}
}
}
program->release() ;
}
else
{
for( unsigned index=0; index < fProgramCount; ++index )
{
DCLCommand * dcl = fDCLTable[ index ] ;
if ( ( dcl->opcode & ~kFWDCLOpFlagMask ) == kDCLCallProcOp )
{
#if 0
if ( ((DCLCallProc*)dcl)->proc && ((DCLCallProc*)dcl)->procData )
{
((DebugThing*)((DCLCallProc*)dcl)->procData)->asyncRef[0] = asyncRef[0] ;
}
#else
{
((natural_t*)((DCLCallProc*)dcl)->procData)[ 0 ] = asyncRef[ 0 ] ;
}
#endif
}
dcl = dcl->pNextDCLCommand ;
}
}
return kIOReturnSuccess ;
}
IOReturn
IOFWUserLocalIsochPort :: modifyJumpDCL ( UInt32 inJumpDCLCompilerData, UInt32 inLabelDCLCompilerData)
{
if ( !fProgram )
{
ErrorLog("no program!\n") ;
return kIOReturnError ;
}
--inJumpDCLCompilerData ;
--inLabelDCLCompilerData ;
if ( inJumpDCLCompilerData > fProgramCount || inLabelDCLCompilerData > fProgramCount )
{
DebugLog( "IOFWUserLocalIsochPort::modifyJumpDCL: DCL index (inJumpDCLCompilerData=%lu, inLabelDCLCompilerData=%lu) past end of lookup table (length=%u)\n",
inJumpDCLCompilerData,
inLabelDCLCompilerData,
fProgramCount ) ;
return kIOReturnBadArgument ;
}
DCLJump * jumpDCL = (DCLJump *) fDCLTable[ inJumpDCLCompilerData ] ;
DCLLabel * labelDCL = (DCLLabel *) fDCLTable[ inLabelDCLCompilerData ] ;
if ( ( jumpDCL->opcode & ~kFWDCLOpFlagMask ) != kDCLJumpOp || ( labelDCL->opcode & ~kFWDCLOpFlagMask ) != kDCLLabelOp )
{
DebugLog("IOFWUserLocalIsochPort::modifyJumpDCL: modifying non-jump (%p, %d) or pointing jump to non-label (%p, %d)\n", jumpDCL, (int)inJumpDCLCompilerData, jumpDCL->pJumpDCLLabel, (int)inLabelDCLCompilerData ) ;
return kIOReturnBadArgument ;
}
jumpDCL->pJumpDCLLabel = labelDCL ;
fProgram->closeGate() ;
IOReturn error = notify ( kFWDCLModifyNotification, (DCLCommand**) & jumpDCL, 1 ) ;
fProgram->openGate() ;
return error ;
}
IOReturn
IOFWUserLocalIsochPort :: modifyDCLSize ( UInt32 dclCompilerData, IOByteCount newSize )
{
return kIOReturnUnsupported ;
#if 0
--dclCompilerData ;
if ( dclCompilerData > fUserToKernelDCLLookupTableLength )
{
DebugLog("IOFWUserLocalIsochPort::modifyJumpDCLSize: DCL index (dclCompilerData=%lu) past end of lookup table (length=%lu)\n",
dclCompilerData, fUserToKernelDCLLookupTableLength ) ;
return kIOReturnBadArgument ;
}
DCLTransferPacket* dcl = (DCLTransferPacket*)( fUserToKernelDCLLookupTable[ dclCompilerData ] ) ;
IOReturn result = kIOReturnSuccess ;
lock() ;
if (fPort)
result = ((IOFWLocalIsochPort*)fPort)->notify(kFWDCLModifyNotification, (DCLCommand**)&dcl, 1) ;
unlock() ;
return result ;
#endif
}
IOReturn
IOFWUserLocalIsochPort :: convertToKernelDCL (
DCLUpdateDCLList * dcl )
{
dcl->dclCommandList = (DCLCommand**)(dcl + 1) ;
for( unsigned index = 0 ; index < dcl->numDCLCommands; ++index )
{
dcl->dclCommandList[ index ] = (DCLCommand*)( fProgramBuffer + (UInt32)dcl->dclCommandList[ index ] ) ;
{
unsigned opcode = dcl->dclCommandList[ index ]->opcode & ~kFWDCLOpFlagMask ;
if ( opcode > 15 && opcode != 20 )
{
panic("invalid opcode\n") ;
}
}
}
return kIOReturnSuccess ;
}
IOReturn
IOFWUserLocalIsochPort :: convertToKernelDCL (
DCLJump * dcl )
{
dcl->pJumpDCLLabel = (DCLLabel*)( fProgramBuffer + (UInt32)dcl->pJumpDCLLabel ) ;
if ( ( dcl->pJumpDCLLabel->opcode & ~kFWDCLOpFlagMask ) != kDCLLabelOp )
{
dcl->pJumpDCLLabel = NULL ;
DebugLog( "Jump %p pointing to non-label %p\n", dcl, dcl->pJumpDCLLabel ) ;
}
return kIOReturnSuccess ;
}
IOReturn
IOFWUserLocalIsochPort :: convertToKernelDCL (
DCLCallProc * dcl)
{
if ( !dcl->proc )
return NULL ;
natural_t * asyncRef = (natural_t *)(dcl + 1 ) ;
asyncRef[0] = 0 ;
asyncRef[ kIOAsyncCalloutFuncIndex ] = (natural_t)dcl->proc ;
asyncRef[ kIOAsyncCalloutRefconIndex ] = (natural_t)dcl->procData ;
dcl->proc = (DCLCallCommandProc*) & s_dclCallProcHandler ;
#if 0
DebugThing * debugThing = new DebugThing ;
dcl->procData = debugThing ;
debugThing->asyncRef = asyncRef ;
debugThing->port = this ;
#else
dcl->procData = (UInt32) asyncRef ;
#endif
return kIOReturnSuccess ;
}
void
IOFWUserLocalIsochPort :: exporterCleanup ()
{
stop() ;
releasePort() ;
}
IOReturn
IOFWUserLocalIsochPort :: userNotify (
UInt32 notificationType,
UInt32 numDCLs,
void * data,
IOByteCount dataSize )
{
InfoLog("+IOFWUserLocalIsochPort :: userNotify, numDCLs=%ld\n", numDCLs ) ;
if ( __builtin_expect( numDCLs > 64, false ) )
{
return kIOReturnBadArgument ;
}
IOFWDCL * dcls[ numDCLs ] ;
const OSArray * program = fDCLPool->getProgramRef() ;
unsigned programLength = program->getCount() ;
IOReturn error = kIOReturnSuccess ;
switch( (IOFWDCLNotificationType)notificationType )
{
case kFWNuDCLModifyNotification :
{
IOMemoryMap * bufferMap = fProgram->getBufferMap() ;
for( unsigned index=0; index < numDCLs; ++index )
{
unsigned dclIndex = *(unsigned*)data - 1 ;
if ( dclIndex >= programLength )
{
DebugLog("out of range DCL dclIndex=%d, programLength=%d\n", dclIndex, programLength ) ;
error = kIOReturnBadArgument ;
}
else
{
dcls[ index ] = (IOFWDCL*)program->getObject( dclIndex ) ;
data = (UInt8*)data + sizeof( unsigned ) ;
IOByteCount dataSize ;
error = dcls[ index ]->importUserDCL( (UInt8*)data, dataSize, bufferMap, program ) ;
if ( dclIndex + 1 < programLength && !dcls[ index ]->getBranch() )
{
dcls[ index ]->setBranch( (IOFWDCL*)program->getObject( dclIndex + 1 ) ) ;
}
data = (UInt8*)data + dataSize ;
}
if ( error )
{
break ;
}
}
break ;
}
case kFWNuDCLModifyJumpNotification :
{
unsigned * dclIndexTable = (unsigned*)data ;
{
unsigned index = 0 ;
unsigned pairIndex = 0 ;
while( pairIndex < numDCLs )
{
--dclIndexTable[ index ] ;
if ( dclIndexTable[ index ] >= programLength )
{
DebugLog("out of range DCL index=%d, dclIndices[ index ]=%d, programLength=%d\n", index, dclIndexTable[ index ], programLength ) ;
error = kIOReturnBadArgument ;
break ;
}
dcls[ pairIndex ] = (IOFWDCL*)program->getObject( dclIndexTable[ index ] ) ;
++index ;
--dclIndexTable[ index ] ;
if ( dclIndexTable[ index ] >= programLength )
{
DebugLog("out of range DCL index=%d, dclIndices[ index ]=%d, programLength=%d\n", index, dclIndexTable[ index ], programLength ) ;
error = kIOReturnBadArgument ;
break ;
}
dcls[ pairIndex ]->setBranch( (IOFWDCL*)program->getObject( dclIndexTable[ index ] ) ) ;
++index ;
++pairIndex ;
}
}
break ;
}
case kFWNuDCLUpdateNotification :
{
unsigned index = 0 ;
while ( index < numDCLs )
{
unsigned * dclIndices = (unsigned*)data ;
--dclIndices[ index ] ;
if ( __builtin_expect( dclIndices[ index ] >= programLength, false ) )
{
DebugLog("out of range DCL index=%d, dclIndices[ index ]=%d, programLength=%d\n", index, dclIndices[ index ], programLength ) ;
error = kIOReturnBadArgument ;
break ;
}
dcls[ index ] = (IOFWDCL*)program->getObject( dclIndices[ index ] ) ;
++index ;
}
break ;
}
default:
{
error = kIOReturnBadArgument ;
DebugLog("unsupported notification type 0x%08lx\n", notificationType) ;
break ;
}
}
program->release() ;
return error ? error : notify( (IOFWDCLNotificationType)notificationType, (DCLCommand**)dcls, numDCLs ) ;
}
IOWorkLoop *
IOFWUserLocalIsochPort :: createRealtimeThread()
{
IOWorkLoop * workloop = IOWorkLoop::workLoop() ;
if ( workloop )
{
thread_time_constraint_policy_data_t constraints;
AbsoluteTime time;
nanoseconds_to_absolutetime(625000, &time);
constraints.period = AbsoluteTime_to_scalar(&time);
nanoseconds_to_absolutetime(60000, &time);
constraints.computation = AbsoluteTime_to_scalar(&time);
nanoseconds_to_absolutetime(1250000, &time);
constraints.constraint = AbsoluteTime_to_scalar(&time);
constraints.preemptible = TRUE;
{
IOThread thread;
thread = workloop->getThread();
thread_policy_set( thread, THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t) & constraints, THREAD_TIME_CONSTRAINT_POLICY_COUNT );
}
}
return workloop ;
}