IOFireWireLibIsochPort.cpp [plain text]
#import "IOFireWireLibIsochPort.h"
#import <IOKit/iokitmig.h>
#import <unistd.h>
#import <pthread.h>
#import <exception>
#ifndef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
#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(
DCLCommandStruct* inDCL,
IOVirtualAddress* outDataBuffer,
IOByteCount* outDataLength)
{
Boolean result = false ;
switch(inDCL->opcode & ~kFWDCLOpFlagMask)
{
case kDCLSendPacketStartOp:
case kDCLSendPacketWithHeaderStartOp:
case kDCLSendPacketOp:
case kDCLReceivePacketStartOp:
case kDCLReceivePacketOp:
*outDataBuffer = (IOVirtualAddress)((DCLTransferPacketStruct*)inDCL)->buffer ;
*outDataLength = ((DCLTransferPacketStruct*)inDCL)->size ;
result = true ;
break ;
case kDCLSendBufferOp:
case kDCLReceiveBufferOp:
break ;
case kDCLPtrTimeStampOp:
*outDataBuffer = (IOVirtualAddress)((DCLPtrTimeStampStruct*)inDCL)->timeStampPtr ;
*outDataLength = sizeof( *( ((DCLPtrTimeStampStruct*)inDCL)->timeStampPtr) ) ;
result = true ;
break ;
default:
break ;
}
return result ;
}
IOByteCount
GetDCLSize(
DCLCommandStruct* inDCL)
{
IOByteCount result = 0 ;
switch(inDCL->opcode & ~kFWDCLOpFlagMask)
{
case kDCLSendPacketStartOp:
case kDCLSendPacketWithHeaderStartOp:
case kDCLSendPacketOp:
case kDCLReceivePacketStartOp:
case kDCLReceivePacketOp:
result = sizeof(DCLTransferPacketStruct) ;
break ;
case kDCLSendBufferOp:
case kDCLReceiveBufferOp:
result = sizeof(DCLTransferBufferStruct) ;
break ;
case kDCLCallProcOp:
result = sizeof(DCLCallProcStruct) ;
break ;
case kDCLLabelOp:
result = sizeof(DCLLabelStruct) ;
break ;
case kDCLJumpOp:
result = sizeof(DCLJumpStruct) ;
break ;
case kDCLSetTagSyncBitsOp:
result = sizeof(DCLSetTagSyncBitsStruct) ;
break ;
case kDCLUpdateDCLListOp:
result = sizeof(DCLUpdateDCLListStruct) ;
break ;
case kDCLPtrTimeStampOp:
result = sizeof(DCLPtrTimeStampStruct) ;
}
return result ;
}
#pragma mark -
CoalesceTree::CoalesceTree()
{
mTop = nil ;
}
CoalesceTree::~CoalesceTree()
{
DeleteNode(mTop) ;
}
void
CoalesceTree::DeleteNode(Node* inNode)
{
if (inNode)
{
DeleteNode(inNode->left) ;
DeleteNode(inNode->right) ;
delete inNode ;
}
}
void
CoalesceTree::CoalesceRange(const IOVirtualRange& inRange)
{
if ( inRange.address == NULL or inRange.length == 0)
return ;
IOVirtualRange range = { trunc_page(inRange.address), round_page( (inRange.address & getpagesize() - 1) + inRange.length - 1) } ;
if (mTop)
CoalesceRange(range, mTop) ;
else
{
mTop = new Node ;
mTop->left = nil ;
mTop->right = nil ;
mTop->range.address = range.address ;
mTop->range.length = range.length ;
}
}
void
CoalesceTree::CoalesceRange(const IOVirtualRange& inRange, Node* inNode)
{
if (inRange.address > inNode->range.address)
{
if ( (inRange.address - inNode->range.address) <= inNode->range.length)
{
inNode->range.length = MAX(inNode->range.length, inRange.address + inRange.length - inNode->range.address) ;
}
else
if (inNode->right)
CoalesceRange(inRange, inNode->right) ;
else
{
inNode->right = new Node ;
inNode->right->left = nil ;
inNode->right->right = nil ;
inNode->right->range.address = inRange.address ;
inNode->right->range.length = inRange.length ;
}
}
else
{
if ((inNode->range.address - inRange.address) <= inRange.length)
{
inNode->range.length = MAX(inRange.length, inNode->range.address + inNode->range.length - inRange.address) ;
inNode->range.address = inRange.address ;
}
else
if (inNode->left)
CoalesceRange(inRange, inNode->left) ;
else
{
inNode->left = new Node ;
inNode->left->left = nil ;
inNode->left->right = nil ;
inNode->left->range.address = inRange.address ;
inNode->left->range.length = inRange.length ;
}
}
}
const UInt32
CoalesceTree::GetCount() const
{
return GetCount(mTop) ;
}
const UInt32
CoalesceTree::GetCount(Node* inNode) const
{
if (inNode)
return 1 + GetCount(inNode->left) + GetCount(inNode->right) ;
else
return 0 ;
}
void
CoalesceTree::GetCoalesceList(IOVirtualRange* outRanges) const
{
UInt32 index = 0 ;
GetCoalesceList(outRanges, mTop, & index) ;
}
void
CoalesceTree::GetCoalesceList(IOVirtualRange* outRanges, Node* inNode, UInt32* pIndex) const
{
if (inNode)
{
GetCoalesceList(outRanges, inNode->left, pIndex) ;
outRanges[*pIndex].address = inNode->range.address ;
outRanges[*pIndex].length = inNode->range.length ;
++(*pIndex) ;
GetCoalesceList(outRanges, inNode->right, pIndex) ;
}
}
#pragma mark -
IsochPort::IsochPort( IUnknownVTbl* interface, Device& userclient, bool talking, bool allocateKernPort )
: IOFireWireIUnknown( interface ),
mUserClient( userclient ),
mKernPortRef( 0 ),
mTalking( talking )
{
mUserClient.AddRef() ;
if (allocateKernPort)
{
FWIsochPortAllocateParams params ;
IOByteCount outputSize = sizeof(FWKernIsochPortRef) ;
IOReturn err = IOConnectMethodStructureIStructureO( mUserClient.GetUserClientConnection(), kFWIsochPort_Allocate, sizeof(FWIsochPortAllocateParams),
& outputSize, & params, & mKernPortRef) ;
if(err)
throw std::exception() ;
}
}
IsochPort::~IsochPort()
{
if ( mKernPortRef )
{
IOReturn err = IOConnectMethodScalarIScalarO( mUserClient.GetUserClientConnection(),
kFWIsochPort_Release,
1,
0,
mKernPortRef ) ;
IOFireWireLibLogIfErr_( err, "%s %u: Couldn't release kernel port", __FILE__, __LINE__) ;
}
mUserClient.Release() ;
}
#if 0
IOReturn
IsochPort::Init(
Boolean inTalking)
{
mTalking = inTalking ;
FWIsochPortAllocateParams params ;
IOByteCount outputSize = sizeof(FWKernIsochPortRef) ;
IOReturn result = IOConnectMethodStructureIStructureO( mUserClient.GetUserClientConnection(),
kFWIsochPort_Allocate,
sizeof(FWIsochPortAllocateParams),
& outputSize,
& params,
& mKernPortRef) ;
IOFireWireLibLogIfErr_( result, "IsochPort::Init: result=0x%08X\n", result ) ;
return result ;
}
#endif
IOReturn
IsochPort::GetSupported(
IOFWSpeed& maxSpeed,
UInt64& chanSupported )
{
return IOConnectMethodScalarIScalarO(
mUserClient.GetUserClientConnection(),
kFWIsochPort_GetSupported,
1,
3,
mKernPortRef,
& maxSpeed,
(UInt32*)&chanSupported,
(UInt32*)&chanSupported + 1) ;
}
IOReturn
IsochPort::AllocatePort(
IOFWSpeed speed,
UInt32 chan )
{
return IOConnectMethodScalarIScalarO(
mUserClient.GetUserClientConnection(),
kFWIsochPort_AllocatePort,
3,
0,
mKernPortRef,
speed,
chan) ;
}
IOReturn
IsochPort::ReleasePort()
{
return IOConnectMethodScalarIScalarO(
mUserClient.GetUserClientConnection(),
kFWIsochPort_ReleasePort,
1,
0,
mKernPortRef) ;
}
IOReturn
IsochPort::Start()
{
return IOConnectMethodScalarIScalarO(
mUserClient.GetUserClientConnection(),
kFWIsochPort_Start,
1,
0,
mKernPortRef) ;
}
IOReturn
IsochPort::Stop()
{
return IOConnectMethodScalarIScalarO( mUserClient.GetUserClientConnection(), kFWIsochPort_Stop, 1, 0, mKernPortRef ) ;
}
#pragma mark -
IsochPortCOM::IsochPortCOM( IUnknownVTbl* interface, Device& inUserClient, bool talking, bool allocateKernPort )
: IsochPort( interface, inUserClient, 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( 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<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,
1, 0,
IOFIREWIREISOCHPORTIMP_INTERFACE,
& LocalIsochPortCOM::SModifyJumpDCL,
& LocalIsochPortCOM::SPrintDCLProgram,
& LocalIsochPortCOM::SModifyTransferPacketDCLSize,
& LocalIsochPortCOM::SModifyTransferPacketDCLBuffer,
& LocalIsochPortCOM::SModifyTransferPacketDCL
} ;
LocalIsochPort::LocalIsochPort( IUnknownVTbl* interface, Device& userclient, bool talking, DCLCommand* inDCLProgram,
UInt32 inStartEvent, UInt32 inStartState, UInt32 inStartMask, IOVirtualRange inDCLProgramRanges[],
UInt32 inDCLProgramRangeCount, IOVirtualRange inBufferRanges[], UInt32 inBufferRangeCount )
: IsochPortCOM( interface, userclient, talking, false ),
mDCLProgram(inDCLProgram),
mStartEvent(inStartEvent),
mStartState(inStartState),
mStartMask(inStartMask),
mExpectedStopTokens(0),
mDeferredRelease(false)
{
if ( !inDCLProgram )
{
IOFireWireLibLog_("%s %u:no DCL program!\n", __FILE__, __LINE__) ;
throw; }
CoalesceTree programTree ;
CoalesceTree bufferTree ;
if (inDCLProgramRanges)
for(UInt32 index=0; index < inDCLProgramRangeCount; ++index)
programTree.CoalesceRange(inDCLProgramRanges[index]) ;
if (inBufferRanges)
for(UInt32 index=0; index < inBufferRangeCount; ++index)
bufferTree.CoalesceRange(inBufferRanges[index]) ;
DCLCommand* pCurrentDCLStruct = mDCLProgram ;
IOVirtualRange tempRange ;
FWLocalIsochPortAllocateParams params ;
params.userDCLProgramDCLCount = 0 ;
while (pCurrentDCLStruct)
{
++params.userDCLProgramDCLCount ;
tempRange.address = (IOVirtualAddress) pCurrentDCLStruct ;
tempRange.length = GetDCLSize(pCurrentDCLStruct) ;
programTree.CoalesceRange(tempRange) ;
if ( GetDCLDataBuffer(pCurrentDCLStruct, & tempRange.address, & tempRange.length) )
{
bufferTree.CoalesceRange(tempRange) ;
}
pCurrentDCLStruct = pCurrentDCLStruct->pNextDCLCommand ;
}
IOVirtualRange* programRanges = nil ;
IOVirtualRange* bufferRanges = nil ;
UInt32 programRangeCount = programTree.GetCount() ;
UInt32 bufferRangeCount = bufferTree.GetCount() ;
if ( nil == (programRanges = new IOVirtualRange[programRangeCount] ))
throw; else
programTree.GetCoalesceList(programRanges) ;
if ( bufferRangeCount > 0)
{
if (nil == (bufferRanges = new IOVirtualRange[bufferRangeCount] ))
throw; else
bufferTree.GetCoalesceList(bufferRanges) ;
}
params.userDCLProgram = mDCLProgram ;
params.userDCLProgramRanges = programRanges ;
params.userDCLProgramRangeCount = programRangeCount ;
params.userDCLBufferRanges = bufferRanges ;
params.userDCLBufferRangeCount = bufferRangeCount ;
params.talking = mTalking ;
params.startEvent = mStartEvent ;
params.startState = mStartState ;
params.startMask = mStartMask ;
params.userObj = this ;
IOByteCount outputSize = sizeof(FWKernIsochPortRef) ;
IOReturn err = IOConnectMethodStructureIStructureO( mUserClient.GetUserClientConnection(), kFWLocalIsochPort_Allocate, sizeof(params),
& outputSize, & params, & mKernPortRef) ;
if (err)
throw std::exception() ;
delete[] programRanges ;
delete[] bufferRanges ;
{
mach_msg_type_number_t outputSize = 0 ;
io_scalar_inband_t params = { (int)mKernPortRef, (int)& DCLCallProcHandler, (int)this } ;
err = io_async_method_scalarI_scalarO( mUserClient.GetUserClientConnection(), mUserClient.GetIsochAsyncPort(), mAsyncRef, 1,
kFWSetAsyncRef_DCLCallProc, params, 2, NULL, & outputSize) ;
if(err)
throw std::exception() ;
}
pthread_mutex_init( & mMutex, nil ) ;
}
LocalIsochPort::~LocalIsochPort()
{
pthread_mutex_destroy( & mMutex ) ;
}
ULONG
LocalIsochPort::Release()
{
Lock() ;
if ( mExpectedStopTokens > 0 )
{
Unlock() ;
mDeferredRelease = true ;
return mRefCount ;
}
Unlock() ;
return IsochPortCOM::Release() ;
}
#if 0
IOReturn
LocalIsochPort::Init(
Boolean inTalking,
DCLCommandStruct* inDCLProgram,
UInt32 inStartEvent,
UInt32 inStartState,
UInt32 inStartMask,
IOVirtualRange inDCLProgramRanges[], UInt32 inDCLProgramRangeCount,
IOVirtualRange inBufferRanges[],
UInt32 inBufferRangeCount)
{
if ( !inDCLProgram )
{
IOFireWireLibLog_("%s %u:no DCL program!\n", __FILE__, __LINE__) ;
return kIOReturnBadArgument ;
}
pthread_mutex_init( & mMutex, nil ) ;
mTalking = inTalking ;
mDCLProgram = inDCLProgram ;
mStartEvent = inStartEvent ;
mStartState = inStartState ;
mStartMask = inStartMask ;
mExpectedStopTokens = 0 ;
mDeferredRelease = false ;
CoalesceTree programTree ;
CoalesceTree bufferTree ;
if (inDCLProgramRanges)
for(UInt32 index=0; index < inDCLProgramRangeCount; ++index)
programTree.CoalesceRange(inDCLProgramRanges[index]) ;
if (inBufferRanges)
for(UInt32 index=0; index < inBufferRangeCount; ++index)
bufferTree.CoalesceRange(inBufferRanges[index]) ;
DCLCommandStruct* pCurrentDCLStruct = mDCLProgram ;
IOVirtualRange tempRange ;
FWLocalIsochPortAllocateParams params ;
params.userDCLProgramDCLCount = 0 ;
while (pCurrentDCLStruct)
{
++params.userDCLProgramDCLCount ;
tempRange.address = (IOVirtualAddress) pCurrentDCLStruct ;
tempRange.length = GetDCLSize(pCurrentDCLStruct) ;
programTree.CoalesceRange(tempRange) ;
if ( GetDCLDataBuffer(pCurrentDCLStruct, & tempRange.address, & tempRange.length) )
{
bufferTree.CoalesceRange(tempRange) ;
}
pCurrentDCLStruct = pCurrentDCLStruct->pNextDCLCommand ;
}
IOVirtualRange* programRanges = nil ;
IOVirtualRange* bufferRanges = nil ;
UInt32 programRangeCount = programTree.GetCount() ;
UInt32 bufferRangeCount = bufferTree.GetCount() ;
IOReturn result = kIOReturnSuccess ;
if ( nil == (programRanges = new IOVirtualRange[programRangeCount] ))
result = kIOReturnNoMemory ;
else
programTree.GetCoalesceList(programRanges) ;
if ( kIOReturnSuccess == result && bufferRangeCount > 0)
{
if (nil == (bufferRanges = new IOVirtualRange[bufferRangeCount] ))
result = kIOReturnNoMemory ;
else
bufferTree.GetCoalesceList(bufferRanges) ;
}
if ( kIOReturnSuccess == result )
{
params.userDCLProgram = mDCLProgram ;
params.userDCLProgramRanges = programRanges ;
params.userDCLProgramRangeCount = programRangeCount ;
params.userDCLBufferRanges = bufferRanges ;
params.userDCLBufferRangeCount = bufferRangeCount ;
params.talking = mTalking ;
params.startEvent = mStartEvent ;
params.startState = mStartState ;
params.startMask = mStartMask ;
params.userObj = this ;
IOByteCount outputSize = sizeof(FWKernIsochPortRef) ;
result = IOConnectMethodStructureIStructureO(
mUserClient.GetUserClientConnection(),
kFWLocalIsochPort_Allocate,
sizeof(params),
& outputSize,
& params,
& mKernPortRef) ;
}
if (programRanges)
delete[] programRanges ;
if (bufferRanges)
delete[] bufferRanges ;
if (kIOReturnSuccess == result)
{
mach_msg_type_number_t outputSize = 0 ;
io_scalar_inband_t params ;
params[0] = (UInt32) mKernPortRef ;
params[1] = (UInt32) & DCLCallProcHandler ;
params[2] = (UInt32) this ;
result = io_async_method_scalarI_scalarO( mUserClient.GetUserClientConnection(),
mUserClient.GetIsochAsyncPort(),
mAsyncRef,
1,
kFWSetAsyncRef_DCLCallProc,
params,
2,
NULL,
& outputSize) ;
}
return result ;
}
#endif
IOReturn
LocalIsochPort::Stop()
{
Lock() ;
++mExpectedStopTokens ;
IOFireWireLibLog_("waiting for %lu stop tokens\n", mExpectedStopTokens) ;
Unlock() ;
return IsochPortCOM::Stop() ; }
IOReturn
LocalIsochPort::ModifyJumpDCL(
DCLJumpStruct* inJump,
DCLLabelStruct* inLabel)
{
inJump->pJumpDCLLabel = inLabel ;
return IOConnectMethodScalarIScalarO( mUserClient.GetUserClientConnection(), kFWLocalIsochPort_ModifyJumpDCL, 3, 0,
mKernPortRef, inJump->compilerData, inLabel->compilerData ) ;
}
IOReturn
LocalIsochPort::ModifyTransferPacketDCLSize( DCLTransferPacket* dcl, IOByteCount newSize )
{
return ::IOConnectMethodScalarIScalarO( mUserClient.GetUserClientConnection(), kFWLocalIsochPort_ModifyTransferPacketDCLSize, 3, 0,
mKernPortRef, dcl->compilerData, newSize ) ;
}
void
LocalIsochPort::DCLCallProcHandler(
void* inRefCon,
IOReturn result,
LocalIsochPort* me )
{
if ( me->mExpectedStopTokens > 0 )
{
if ( result == kIOFireWireLastDCLToken && inRefCon==(void*)0xFFFFFFFF )
{
me->Lock() ;
me->mExpectedStopTokens-- ;
me->Unlock() ;
if ( me->mExpectedStopTokens == 0 && me->mDeferredRelease )
me->Release() ;
}
return ;
}
if ( result == kIOReturnSuccess )
{
DCLCallProcStruct* callProcDCL = (DCLCallProcStruct*)inRefCon ;
(*callProcDCL->proc)((DCLCommandStruct*)inRefCon) ;
}
}
void
LocalIsochPort::Lock()
{
pthread_mutex_lock( & mMutex ) ;
}
void
LocalIsochPort::Unlock()
{
pthread_mutex_unlock( & mMutex ) ;
}
void
LocalIsochPort::PrintDCLProgram(
const DCLCommandStruct* inDCL,
UInt32 inDCLCount)
{
mUserClient.PrintDCLProgram(inDCL, inDCLCount) ;
}
#pragma mark -
LocalIsochPortCOM::LocalIsochPortCOM( Device& userclient, bool inTalking, DCLCommandStruct* inDCLProgram, UInt32 inStartEvent,
UInt32 inStartState, UInt32 inStartMask, IOVirtualRange inDCLProgramRanges[], UInt32 inDCLProgramRangeCount,
IOVirtualRange inBufferRanges[], UInt32 inBufferRangeCount)
: LocalIsochPort( reinterpret_cast<IUnknownVTbl*>(& sInterface), userclient, inTalking, inDCLProgram, inStartEvent,
inStartState, inStartMask, inDCLProgramRanges, inDCLProgramRangeCount, inBufferRanges, inBufferRangeCount )
{
}
LocalIsochPortCOM::~LocalIsochPortCOM()
{
}
IUnknownVTbl**
LocalIsochPortCOM::Alloc(
Device& inUserClient,
Boolean inTalking,
DCLCommandStruct* inDCLProgram,
UInt32 inStartEvent,
UInt32 inStartState,
UInt32 inStartMask,
IOVirtualRange inDCLProgramRanges[], UInt32 inDCLProgramRangeCount,
IOVirtualRange inBufferRanges[],
UInt32 inBufferRangeCount)
{
LocalIsochPortCOM* me = nil ;
try {
me = new LocalIsochPortCOM(inUserClient, inTalking, inDCLProgram, inStartEvent, inStartState, inStartMask,
inDCLProgramRanges, inDCLProgramRangeCount, inBufferRanges, inBufferRangeCount ) ;
} catch(...) {
}
return (nil == me) ? nil : reinterpret_cast<IUnknownVTbl**>(& me->GetInterface()) ;
}
HRESULT
LocalIsochPortCOM::QueryInterface(REFIID iid, void ** ppv )
{
HRESULT result = S_OK ;
*ppv = nil ;
CFUUIDRef interfaceID = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, iid) ;
if ( CFEqual(interfaceID, IUnknownUUID)
|| CFEqual(interfaceID, kIOFireWireLocalIsochPortInterfaceID )
|| CFEqual( interfaceID, kIOFireWireLocalIsochPortInterfaceID_v2 )
#if 0
|| CFEqual( interfaceID, kIOFireWireLocalIsochPortInterfaceID_v3 ) #endif
)
{
*ppv = & GetInterface() ;
AddRef() ;
}
else
{
*ppv = nil ;
result = E_NOINTERFACE ;
}
CFRelease(interfaceID) ;
return result ;
}
IOReturn
LocalIsochPortCOM::SModifyJumpDCL(
IOFireWireLibLocalIsochPortRef self,
DCLJumpStruct* inJump,
DCLLabelStruct* inLabel)
{
return IOFireWireIUnknown::InterfaceMap<LocalIsochPortCOM>::GetThis(self)->ModifyJumpDCL(inJump, inLabel) ;
}
void
LocalIsochPortCOM::SPrintDCLProgram(
IOFireWireLibLocalIsochPortRef self,
const DCLCommandStruct* inProgram,
UInt32 inLength)
{
IOFireWireIUnknown::InterfaceMap<LocalIsochPortCOM>::GetThis(self)->PrintDCLProgram(inProgram, inLength) ;
}
IOReturn
LocalIsochPortCOM::SModifyTransferPacketDCLSize( PortRef self, DCLTransferPacket* dcl, IOByteCount newSize )
{
IOReturn err = kIOReturnBadArgument ;
switch(dcl->opcode)
{
case kDCLSendPacketStartOp:
case kDCLSendPacketWithHeaderStartOp:
case kDCLSendPacketOp:
case kDCLReceivePacketStartOp:
case kDCLReceivePacketOp:
case kDCLReceiveBufferOp:
err = IOFireWireIUnknown::InterfaceMap<LocalIsochPortCOM>::GetThis(self)->ModifyTransferPacketDCLSize(dcl, newSize) ;
}
return err ;
}
IOReturn
LocalIsochPortCOM::SModifyTransferPacketDCLBuffer( PortRef self, DCLTransferPacket* dcl, void* newBuffer )
{
return kIOReturnUnsupported ;
}
IOReturn
LocalIsochPortCOM::SModifyTransferPacketDCL( PortRef self, DCLTransferPacket* dcl, void* newBuffer, IOByteCount newSize )
{
return kIOReturnUnsupported ;
}
}