/* * Copyright (c) 1998-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * IOFireWireLibIsochPort.cpp * IOFireWireFamily * * Created on Mon Mar 12 2001. * Copyright (c) 2001-2002 Apple Computer, Inc. All rights reserved. * * $Log: IOFireWireLibIsochPort.cpp,v $ * Revision 1.58 2009/01/16 02:53:19 collin * and finally put TOT back... * * Revision 1.54 2009/01/15 01:40:02 collin * BRB-VERIFY: 10A222: Trying to record a movie through QT X, getting error message. * * Revision 1.53 2008/05/06 00:14:48 collin * more k64 changes * * Revision 1.52 2007/03/14 01:01:14 collin * *** empty log message *** * * Revision 1.51 2007/02/15 19:42:08 ayanowit * For 4369537, eliminated support for legacy DCL SendPacketWithHeader, since it didn't work anyway, and NuDCL does support it. * * Revision 1.50 2007/02/15 17:18:54 ayanowit * Fixed a panic found with ProIO DCL program in FCP. Related to recent changes for 64-bit app support. * * Revision 1.49 2007/02/07 06:35:22 collin * *** empty log message *** * * Revision 1.48 2007/01/26 20:52:31 ayanowit * changes to user-space isoch stuff to support 64-bit apps. * * Revision 1.47 2007/01/11 04:28:05 collin * *** empty log message *** * * Revision 1.46 2007/01/08 18:47:20 ayanowit * More 64-bit changes for isoch. * * Revision 1.45 2007/01/02 18:14:12 ayanowit * Enabled building the plug-in lib 4-way FAT. Also, fixed compile problems for 64-bit. * * Revision 1.44 2006/12/21 21:17:46 ayanowit * More changes necessary to eventually get support for 64-bit apps working (4222965). * * Revision 1.43 2006/12/16 00:07:48 ayanowit * fixed some of the leopard user-lib changes. was failing on ppc systems. * * Revision 1.42 2006/12/13 21:34:24 ayanowit * For 4222965, replaced all io async method calls with new Leopard API version. * * Revision 1.41 2006/12/13 01:11:23 ayanowit * For 4222969, replaced the remaining calls to IOConnectMethod... struct variants. * * Revision 1.40 2006/12/12 22:39:05 ayanowit * For radar 4222965, changed all scalar in, scalar out calls to IOConnectMethod... to use new Leopard IOConnectCall... API. * * Revision 1.39 2006/08/21 22:41:11 collin * *** empty log message *** * * Revision 1.38 2006/02/09 00:21:55 niels * merge chardonnay branch to tot * * Revision 1.37 2005/04/02 02:43:46 niels * exporter works outside IOFireWireFamily * * Revision 1.36.4.6 2006/01/31 04:49:57 collin * *** empty log message *** * * Revision 1.36.4.4 2006/01/17 00:35:00 niels * FireWire NuDCL APIs need Rosetta support * * Revision 1.36.4.3 2006/01/04 00:45:54 collin * *** empty log message *** * * Revision 1.36.4.2 2005/08/06 01:31:31 collin * *** empty log message *** * * Revision 1.36.4.1 2005/07/23 00:30:46 collin * *** empty log message *** * * Revision 1.36 2005/03/12 03:27:52 collin * *** empty log message *** * * Revision 1.35 2005/02/18 03:19:05 niels * fix isight * * Revision 1.34 2004/05/04 22:52:20 niels * *** empty log message *** * * Revision 1.33 2004/02/17 23:13:23 niels * *** empty log message *** * * Revision 1.32 2004/02/17 23:12:27 niels * *** empty log message *** * * Revision 1.31 2004/02/17 20:23:58 niels * keep track if local isoch port has started or not to avoid leaking when stop is called on an unstarted port * * Revision 1.30 2003/12/19 22:07:46 niels * send force stop when channel dies/system sleeps * * Revision 1.29 2003/08/25 08:39:17 niels * *** empty log message *** * * Revision 1.28 2003/08/20 23:33:37 niels * *** empty log message *** * * Revision 1.27 2003/08/20 18:48:45 niels * *** empty log message *** * * Revision 1.26 2003/08/18 23:18:15 niels * *** empty log message *** * * Revision 1.25 2003/08/14 17:47:33 niels * *** empty log message *** * * Revision 1.24 2003/07/29 22:49:25 niels * *** empty log message *** * * Revision 1.23 2003/07/24 20:49:50 collin * *** empty log message *** * * Revision 1.22 2003/07/24 06:30:59 collin * *** empty log message *** * * Revision 1.21 2003/07/21 06:53:10 niels * merge isoch to TOT * * Revision 1.20.6.6 2003/07/21 06:44:48 niels * *** empty log message *** * * Revision 1.20.6.5 2003/07/18 00:17:47 niels * *** empty log message *** * * Revision 1.20.6.4 2003/07/10 00:11:58 niels * *** empty log message *** * * Revision 1.20.6.3 2003/07/09 21:24:07 niels * *** empty log message *** * * Revision 1.20.6.2 2003/07/03 22:10:26 niels * fix iidc/dv rcv * * Revision 1.20.6.1 2003/07/01 20:54:24 niels * isoch merge * */ #import "IOFireWireLibIsochPort.h" #import "IOFireWireLibDevice.h" #import "IOFireWireLibNuDCLPool.h" #import "IOFireWireLibNuDCL.h" #import "IOFireWireLibCoalesceTree.h" #import #import #import #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, } ; // ============================================================ // utility functions // ============================================================ 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: //zzz what should I do here? 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(UserExportDCLTransferPacket) ; break ; case kDCLSendBufferOp: case kDCLReceiveBufferOp: result = sizeof(UserExportDCLTransferBuffer) ; break ; case kDCLCallProcOp: result = sizeof(UserExportDCLCallProc) ; break ; case kDCLLabelOp: result = sizeof(UserExportDCLLabel) ; break ; case kDCLJumpOp: result = sizeof(UserExportDCLJump) ; break ; case kDCLSetTagSyncBitsOp: result = sizeof(UserExportDCLSetTagSyncBits) ; break ; case kDCLUpdateDCLListOp: result = sizeof(UserExportDCLUpdateDCLList) ; break ; case kDCLPtrTimeStampOp: result = sizeof(UserExportDCLPtrTimeStamp) ; break; case kDCLSkipCycleOp: result = sizeof(UserExportDCLCommand) ; break; } return result ; } #pragma mark - // ============================================================ // // IsochPort // // ============================================================ 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; uint32_t outputCnt = 0; const uint64_t inputs[1]={(const uint64_t)mKernPortRef}; error = IOConnectCallScalarMethod(mDevice.GetUserClientConnection(), kReleaseUserObject, inputs,1,NULL,&outputCnt); DebugLogCond( error, "Couldn't release kernel port" ) ; } mDevice.Release() ; } IOReturn IsochPort::GetSupported( IOFWSpeed& maxSpeed, UInt64& chanSupported ) { uint32_t outputCnt = 3; uint64_t outputVal[3]; const uint64_t inputs[1]={(const uint64_t)mKernPortRef}; IOReturn result = IOConnectCallScalarMethod(mDevice.GetUserClientConnection(), kIsochPort_GetSupported, inputs,1, outputVal,&outputCnt); maxSpeed = (IOFWSpeed)(outputVal[0] & 0xFFFFFFFF); chanSupported = ((outputVal[1] & 0xFFFFFFFF)<<32)+(outputVal[2] & 0xFFFFFFFF); return result; } IOReturn IsochPort::AllocatePort( IOFWSpeed speed, UInt32 chan ) { uint32_t outputCnt = 0; const uint64_t inputs[2] = {speed, chan}; return IOConnectCallScalarMethod(mDevice.GetUserClientConnection(), mDevice.MakeSelectorWithObject( kIsochPort_AllocatePort_d, mKernPortRef ), inputs,2, NULL,&outputCnt); } IOReturn IsochPort::ReleasePort() { uint32_t outputCnt = 0; return IOConnectCallScalarMethod(mDevice.GetUserClientConnection(), mDevice.MakeSelectorWithObject( kIsochPort_ReleasePort_d, mKernPortRef ), NULL,0, NULL,&outputCnt); } IOReturn IsochPort::Start() { uint32_t outputCnt = 0; return IOConnectCallScalarMethod(mDevice.GetUserClientConnection(), mDevice.MakeSelectorWithObject( kIsochPort_Start_d, mKernPortRef ), NULL,0, NULL,&outputCnt); } IOReturn IsochPort::Stop() { uint32_t outputCnt = 0; return IOConnectCallScalarMethod(mDevice.GetUserClientConnection(), mDevice.MakeSelectorWithObject( kIsochPort_Stop_d, mKernPortRef ), NULL,0, NULL,&outputCnt); } #pragma mark - // ============================================================ // // IsochPortCOM // // ============================================================ 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::GetThis(self)->GetSupported(*maxSpeed, *chanSupported) ; } IOReturn IsochPortCOM::SAllocatePort( IOFireWireLibIsochPortRef self, IOFWSpeed speed, UInt32 chan ) { return IOFireWireIUnknown::InterfaceMap::GetThis(self)->AllocatePort(speed, chan) ; } IOReturn IsochPortCOM::SReleasePort( IOFireWireLibIsochPortRef self) { return IOFireWireIUnknown::InterfaceMap::GetThis(self)->ReleasePort() ; } IOReturn IsochPortCOM::SStart( IOFireWireLibIsochPortRef self) { return IOFireWireIUnknown::InterfaceMap::GetThis(self)->Start() ; } IOReturn IsochPortCOM::SStop( IOFireWireLibIsochPortRef self) { return IOFireWireIUnknown::InterfaceMap::GetThis(self)->Stop() ; } void IsochPortCOM::SSetRefCon( IOFireWireLibIsochPortRef self, void* inRefCon) { IOFireWireIUnknown::InterfaceMap::GetThis(self)->SetRefCon(inRefCon) ; } void* IsochPortCOM::SGetRefCon( IOFireWireLibIsochPortRef self) { return IOFireWireIUnknown::InterfaceMap::GetThis(self)->GetRefCon() ; } Boolean IsochPortCOM::SGetTalking( IOFireWireLibIsochPortRef self) { return IOFireWireIUnknown::InterfaceMap::GetThis(self)->GetTalking() ; } #pragma mark - // ============================================================ // // RemoteIsochPort // // ============================================================ 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(& GetInterface()) ) { } IOReturn RemoteIsochPort::GetSupported( IOFWSpeed& maxSpeed, UInt64& chanSupported) { if (mGetSupportedHandler) return (*mGetSupportedHandler)(mRefInterface, & maxSpeed, & chanSupported) ; else return kIOReturnUnsupported ; // should we return unsupported if user proc doesn't answer? } 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::RemoteIsochPortCOM( Device& userclient, bool talking ) : RemoteIsochPort( reinterpret_cast( 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(& 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::GetThis(self)->SetGetSupportedHandler(inHandler) ; } IOFireWireLibIsochPortAllocateCallback RemoteIsochPortCOM::SSetAllocatePortHandler( PortRef self, IOFireWireLibIsochPortAllocateCallback inHandler) { return IOFireWireIUnknown::InterfaceMap::GetThis(self)->SetAllocatePortHandler(inHandler) ; } IOFireWireLibIsochPortCallback RemoteIsochPortCOM::SSetReleasePortHandler( PortRef self, IOFireWireLibIsochPortCallback inHandler) { return IOFireWireIUnknown::InterfaceMap::GetThis(self)->SetReleasePortHandler(inHandler) ; } IOFireWireLibIsochPortCallback RemoteIsochPortCOM::SSetStartHandler( PortRef self, IOFireWireLibIsochPortCallback inHandler) { return IOFireWireIUnknown::InterfaceMap::GetThis(self)->SetStartHandler(inHandler) ; } IOFireWireLibIsochPortCallback RemoteIsochPortCOM::SSetStopHandler( PortRef self, IOFireWireLibIsochPortCallback inHandler) { return IOFireWireIUnknown::InterfaceMap::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 ) , mBufferAddressRanges( nil ) , mStarted( false ) { // sorry about the spaghetti.. hope you're hungry: if ( !program ) { DebugLog( "no DCL program!\n" ) ; throw kIOReturnBadArgument ; } // DeviceCOM::SPrintDCLProgram ( nil, program, 0 ) ; IOReturn error = kIOReturnSuccess ; // trees used to coalesce program/data ranges CoalesceTree bufferTree ; // check if user passed in any virtual memory ranges to start with... 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( reinterpret_cast< DCLNuDCLLeader* >( program )->program ) ; params.version = kDCLExportDataNuDCLRosettaVersion ; // new-style DCL program pool->CoalesceBuffers( bufferTree ) ; mBufferRangeCount = bufferTree.GetCount() ; mBufferRanges = new IOVirtualRange[ mBufferRangeCount ] ; if ( !mBufferRanges ) { error = kIOReturnNoMemory ; } else { bufferTree.GetCoalesceList( mBufferRanges ) ; mBufferAddressRanges = new FWVirtualAddressRange[ mBufferRangeCount ] ; if ( !mBufferAddressRanges ) { error = kIOReturnNoMemory ; } else for (unsigned int i=0;iExport( &programData, mBufferRanges, mBufferRangeCount ) ; params.programExportBytes = programExportBytes ; params.programData = programData; } } } else { unsigned programCount = 0 ; params.version = kDCLExportDataLegacyVersion ; // old-style DCL program // count DCLs in program and coalesce buffers: 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 ) ; mBufferAddressRanges = new FWVirtualAddressRange[ mBufferRangeCount ] ; if ( !mBufferAddressRanges ) { error = kIOReturnNoMemory ; } else for (unsigned int i=0;iaddress = OSSwapInt64( pAddressRange->address ); pAddressRange->length = OSSwapInt64( pAddressRange->length ); } params.bufferRangeCount = OSSwapInt32( params.bufferRangeCount ); params.bufferRanges = OSSwapInt64(params.bufferRanges ); params.options = (IOFWIsochPortOptions)OSSwapInt32( params.options | kFWIsochBigEndianUpdates ); params.userObj = (mach_vm_address_t)OSSwapInt64((mach_vm_address_t)params.userObj ); } ); #endif uint32_t outputCnt = 0; size_t outputStructSize = sizeof( UserObjectHandle ) ; error = IOConnectCallMethod(mDevice.GetUserClientConnection(), kLocalIsochPort_Allocate, NULL,0, & params,sizeof (params), NULL,&outputCnt, &mKernPortRef,&outputStructSize); #ifndef __LP64__ ROSETTA_ONLY( { mKernPortRef = (UserObjectHandle)OSSwapInt32( (UInt32)mKernPortRef ); } ); #endif 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 ) { #ifdef __LP64__ DebugLog ( "\%u: <0x%x>-<0x%x>\n", index, (unsigned)mBufferRanges[index].address, (unsigned)mBufferRanges[index].address + mBufferRanges[index].length ) ; #else DebugLog ( "\%u: <0x%x>-<0x%lx>\n", index, (unsigned)mBufferRanges[index].address, (unsigned)mBufferRanges[index].address + mBufferRanges[index].length ) ; #endif } #endif throw error ; } { uint64_t refrncData[kOSAsyncRef64Count]; refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t) & LocalIsochPort::s_DCLStopTokenCallProcHandler; refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long)this; uint32_t outputCnt = 0; const uint64_t inputs[1]={(const uint64_t)mKernPortRef}; error = IOConnectCallAsyncScalarMethod(mDevice.GetUserClientConnection(), kSetAsyncRef_DCLCallProc, mDevice.GetIsochAsyncPort(), refrncData,kOSAsyncRef64Count, inputs,1, NULL,&outputCnt); if( error ) { throw error ; } } if ( params.programData ) { vm_deallocate( mach_task_self (), (vm_address_t) programData, programExportBytes ) ; // this is temporary storage } // make our mutex pthread_mutex_init ( & mMutex, nil ) ; } LocalIsochPort::~LocalIsochPort () { delete[] mBufferRanges ; delete[] mBufferAddressRanges; pthread_mutex_destroy( & mMutex ) ; } ULONG LocalIsochPort::Release () { Lock () ; if ( mExpectedStopTokens > 0 ) { Unlock () ; ++ mDeferredReleaseCount ; return mRefCount ; } Unlock () ; // while( true ) // { // Lock() ; // bool run = ( mExpectedStopTokens > 0 ) ; // Unlock() ; // // if ( !run ) // { // break ; // } // // ::CFRunLoopRunInMode( kCFRunLoopDefaultMode, 1, true ) ; // } 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() ; // call superclass Stop() } IOReturn LocalIsochPort::ModifyJumpDCL ( DCLJump* inJump, DCLLabel* inLabel ) { inJump->pJumpDCLLabel = inLabel ; uint32_t outputCnt = 0; const uint64_t inputs[2] = {inJump->compilerData, inLabel->compilerData}; IOReturn result = IOConnectCallScalarMethod(mDevice.GetUserClientConnection(), mDevice.MakeSelectorWithObject( kLocalIsochPort_ModifyJumpDCL_d, mKernPortRef ), inputs,2, NULL,&outputCnt); return result ; } IOReturn LocalIsochPort::ModifyTransferPacketDCLSize ( DCLTransferPacket* dcl, IOByteCount newSize ) { //kLocalIsochPort_ModifyTransferPacketDCLSize, 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) ; // use a local so we don't touch "this" after release UInt32 release_count = mDeferredReleaseCount; while ( release_count > 0 ) { --release_count ; Release() ; } } } } #if 0 void LocalIsochPort::S_DCLKernelCallout( DCLCallProc * dcl ) { (*dcl->proc)(dcl->procData) ; uint32_t outputCnt = 0; const uint64_t inputs[1]={(const uint64_t)dcl->compilerData}; IOReturn result = IOConnectCallScalarMethod(mDevice.GetUserClientConnection(), Device::MakeSelectorWithObject( kLocalIsochPort_RunDCLUpdateList_d, port->mKernPortRef ), inputs,1, NULL,&outputCnt); } void LocalIsochPort::S_NuDCLKernelCallout ( NuDCL * dcl ) { (*dcl->fData.callback)(dcl->fData.refcon, (NuDCLRef)dcl) ; uint32_t outputCnt = 0; const uint64_t inputs[1]={(const uint64_t)dcl->fExportIndex}; IOReturn result = IOConnectCallScalarMethod(mDevice.GetUserClientConnection(), Device::MakeSelectorWithObject( kLocalIsochPort_RunNuDCLUpdateList_d, mKernPortRef ), inputs,1, NULL,&outputCnt); } #endif IOReturn LocalIsochPort::SetResourceUsageFlags ( IOFWIsochResourceFlags flags ) { uint32_t outputCnt = 0; const uint64_t inputs[1]={(const uint64_t)flags}; return IOConnectCallScalarMethod(mDevice.GetUserClientConnection(), mDevice.MakeSelectorWithObject( kIsochPort_SetIsochResourceFlags_d, mKernPortRef ), inputs,1, NULL,&outputCnt); } IOReturn LocalIsochPort::ExportDCLs( IOVirtualAddress * exportBuffer, IOByteCount * exportBytes ) { IOReturn error = kIOReturnSuccess ; // see how much space we need for serialization... // unsigned byteCount = 0 ; *exportBytes = 0 ; for( DCLCommand * dcl = mDCLProgram; dcl != NULL; dcl = dcl->pNextDCLCommand ) { *exportBytes += GetDCLSize( dcl ) ; switch ( dcl->opcode & ~kFWDCLOpFlagMask ) { case kDCLUpdateDCLListOp : { // update DCLs store a copy of their update list in the export buffer *exportBytes += sizeof( mach_vm_address_t ) * ((DCLUpdateDCLList*)dcl)->numDCLCommands ; break ; } case kDCLCallProcOp : { *exportBytes += sizeof( uint64_t[kOSAsyncRef64Count]) ; break ; } } } // buffer to hold copy of DCLs in program error = vm_allocate( mach_task_self (), (vm_address_t*)exportBuffer, *exportBytes, true /*anywhere*/ ) ; if ( !*exportBuffer && !error ) { error = kIOReturnNoMemory ; } // start from beginning { 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 ) ; dcl->compilerData = offset ; // save for later. // Copy the DCLs into the buffer using the ExportDCL structs switch(dcl->opcode & ~kFWDCLOpFlagMask) { case kDCLSendPacketStartOp: //case kDCLSendPacketWithHeaderStartOp: case kDCLSendPacketOp: case kDCLReceivePacketStartOp: case kDCLReceivePacketOp: { UserExportDCLTransferPacket *pUserExportDCLTransferPacket = (UserExportDCLTransferPacket*) buffer; pUserExportDCLTransferPacket->pClientDCLStruct = (mach_vm_address_t) dcl; pUserExportDCLTransferPacket->pNextDCLCommand = (mach_vm_address_t) ((DCLTransferPacket*)dcl)->pNextDCLCommand; pUserExportDCLTransferPacket->compilerData = ((DCLTransferPacket*)dcl)->compilerData; pUserExportDCLTransferPacket->opcode = ((DCLTransferPacket*)dcl)->opcode; pUserExportDCLTransferPacket->buffer = (mach_vm_address_t) ((DCLTransferPacket*)dcl)->buffer; pUserExportDCLTransferPacket->size = ((DCLTransferPacket*)dcl)->size; } break ; case kDCLSendBufferOp: case kDCLReceiveBufferOp: { UserExportDCLTransferBuffer *pUserExportDCLTransferBuffer = (UserExportDCLTransferBuffer*) buffer; pUserExportDCLTransferBuffer->pClientDCLStruct = (mach_vm_address_t) dcl; pUserExportDCLTransferBuffer->pNextDCLCommand = (mach_vm_address_t) ((DCLTransferBuffer*)dcl)->pNextDCLCommand; pUserExportDCLTransferBuffer->compilerData = ((DCLTransferBuffer*)dcl)->compilerData; pUserExportDCLTransferBuffer->opcode = ((DCLTransferBuffer*)dcl)->opcode; pUserExportDCLTransferBuffer->buffer = (mach_vm_address_t) ((DCLTransferBuffer*)dcl)->buffer; pUserExportDCLTransferBuffer->size = ((DCLTransferBuffer*)dcl)->size; pUserExportDCLTransferBuffer->packetSize = ((DCLTransferBuffer*)dcl)->packetSize; pUserExportDCLTransferBuffer->reserved = ((DCLTransferBuffer*)dcl)->reserved; pUserExportDCLTransferBuffer->bufferOffset = ((DCLTransferBuffer*)dcl)->bufferOffset; } break ; case kDCLCallProcOp: { UserExportDCLCallProc *pUserExportDCLCallProc = (UserExportDCLCallProc*) buffer; pUserExportDCLCallProc->pClientDCLStruct = (mach_vm_address_t) dcl; pUserExportDCLCallProc->pNextDCLCommand = (mach_vm_address_t) ((DCLCallProc*)dcl)->pNextDCLCommand; pUserExportDCLCallProc->compilerData = ((DCLCallProc*)dcl)->compilerData; pUserExportDCLCallProc->opcode = ((DCLCallProc*)dcl)->opcode; pUserExportDCLCallProc->proc = (mach_vm_address_t) ((DCLCallProc*)dcl)->proc; //pUserExportDCLCallProc->procData = (uint64_t) ((DCLCallProc*)dcl)->procData; pUserExportDCLCallProc->procData = (uint64_t)dcl ; size += sizeof( uint64_t[kOSAsyncRef64Count]) ; } break ; case kDCLLabelOp: { UserExportDCLLabel *pUserExportDCLLabel = (UserExportDCLLabel*) buffer; pUserExportDCLLabel->pClientDCLStruct = (mach_vm_address_t) dcl; pUserExportDCLLabel->pNextDCLCommand = (mach_vm_address_t) ((DCLLabel*)dcl)->pNextDCLCommand; pUserExportDCLLabel->compilerData = ((DCLLabel*)dcl)->compilerData; pUserExportDCLLabel->opcode = ((DCLLabel*)dcl)->opcode; } break ; case kDCLJumpOp: { UserExportDCLJump *pUserExportDCLJump = (UserExportDCLJump*) buffer; pUserExportDCLJump->pClientDCLStruct = (mach_vm_address_t) dcl; pUserExportDCLJump->pNextDCLCommand = (mach_vm_address_t) ((DCLJump*)dcl)->pNextDCLCommand; pUserExportDCLJump->compilerData = ((DCLJump*)dcl)->compilerData; pUserExportDCLJump->opcode = ((DCLJump*)dcl)->opcode; pUserExportDCLJump->pJumpDCLLabel = (mach_vm_address_t) ((DCLJump*)dcl)->pJumpDCLLabel; } break ; case kDCLSetTagSyncBitsOp: { UserExportDCLSetTagSyncBits *pUserExportDCLSetTagSyncBits = (UserExportDCLSetTagSyncBits*) buffer; pUserExportDCLSetTagSyncBits->pClientDCLStruct = (mach_vm_address_t) dcl; pUserExportDCLSetTagSyncBits->pNextDCLCommand = (mach_vm_address_t) ((DCLSetTagSyncBits*)dcl)->pNextDCLCommand; pUserExportDCLSetTagSyncBits->compilerData = ((DCLSetTagSyncBits*)dcl)->compilerData; pUserExportDCLSetTagSyncBits->opcode = ((DCLSetTagSyncBits*)dcl)->opcode; pUserExportDCLSetTagSyncBits->tagBits = ((DCLSetTagSyncBits*)dcl)->tagBits; pUserExportDCLSetTagSyncBits->syncBits = ((DCLSetTagSyncBits*)dcl)->syncBits; } break ; case kDCLUpdateDCLListOp: { UserExportDCLUpdateDCLList *pUserExportDCLUpdateDCLList = (UserExportDCLUpdateDCLList*) buffer; pUserExportDCLUpdateDCLList->pClientDCLStruct = (mach_vm_address_t) dcl; pUserExportDCLUpdateDCLList->pNextDCLCommand = (mach_vm_address_t) ((DCLUpdateDCLList*)dcl)->pNextDCLCommand; pUserExportDCLUpdateDCLList->compilerData = ((DCLUpdateDCLList*)dcl)->compilerData; pUserExportDCLUpdateDCLList->opcode = ((DCLUpdateDCLList*)dcl)->opcode; pUserExportDCLUpdateDCLList->dclCommandList = (mach_vm_address_t) ((DCLUpdateDCLList*)dcl)->dclCommandList; pUserExportDCLUpdateDCLList->numDCLCommands = ((DCLUpdateDCLList*)dcl)->numDCLCommands; size += ( sizeof( mach_vm_address_t ) * ((DCLUpdateDCLList*)dcl)->numDCLCommands ) ; } break ; case kDCLPtrTimeStampOp: { UserExportDCLPtrTimeStamp *pUserExportDCLPtrTimeStamp = (UserExportDCLPtrTimeStamp*) buffer; pUserExportDCLPtrTimeStamp->pClientDCLStruct = (mach_vm_address_t) dcl; pUserExportDCLPtrTimeStamp->pNextDCLCommand = (mach_vm_address_t) ((DCLPtrTimeStamp*)dcl)->pNextDCLCommand; pUserExportDCLPtrTimeStamp->compilerData = ((DCLPtrTimeStamp*)dcl)->compilerData; pUserExportDCLPtrTimeStamp->opcode = ((DCLPtrTimeStamp*)dcl)->opcode; pUserExportDCLPtrTimeStamp->timeStampPtr = (mach_vm_address_t) ((DCLPtrTimeStamp*)dcl)->timeStampPtr; } break ; case kDCLSkipCycleOp: { UserExportDCLCommand *pUserExportDCLCommand = (UserExportDCLCommand*) buffer; pUserExportDCLCommand->pClientDCLStruct = (mach_vm_address_t) dcl; pUserExportDCLCommand->pNextDCLCommand = (mach_vm_address_t) ((DCLCommand*)dcl)->pNextDCLCommand; pUserExportDCLCommand->compilerData = ((DCLCommand*)dcl)->compilerData; pUserExportDCLCommand->opcode = ((DCLCommand*)dcl)->opcode; pUserExportDCLCommand->operands[0] = ((DCLCommand*)dcl)->operands[0]; } break ; } // Account for this DCL's exported bytes buffer += size ; offset += size ; } InfoLog("...done\n") ; } // some DCLs (jumps and update list DCLs) refer to other DCLs with // user space pointers which makes translation a bit harder. // The 'compilerData' field of all the DCLs in our export data block // contain an offset in bytes from the beginning of the exported data // block.. // We now replace any user space pointers with offsets for kernel use.. { unsigned offset = 0 ; InfoLog("exporting DCLs, pass 2... export size=%d bytes\n", (int)*exportBytes ) ; while( offset < *exportBytes ) { UserExportDCLCommand * dcl = (UserExportDCLCommand*)(*exportBuffer + offset ) ; DCLCommand *pClientDCL = (DCLCommand *) dcl->pClientDCLStruct; // DebugLog("DCL=%p, offset=%x, opcode=%x\n", dcl, offset, dcl->opcode) ; { unsigned opcode = dcl->opcode & ~kFWDCLOpFlagMask ; assert( opcode <= 15 || opcode == 20 ) ; } unsigned size = GetDCLSize( pClientDCL ) ; switch ( dcl->opcode & ~kFWDCLOpFlagMask ) { case kDCLUpdateDCLListOp : { // make list of offsets from list of user space DCL pointers // List starts after DCL in question on export buffer mach_vm_address_t* list = (mach_vm_address_t*)( ((UserExportDCLUpdateDCLList*)dcl) + 1 ) ; for( unsigned index=0; index < ((UserExportDCLUpdateDCLList*)dcl)->numDCLCommands; ++index ) { list[ index ] = (mach_vm_address_t) ((DCLUpdateDCLList*)pClientDCL)->dclCommandList[ index ]->compilerData ; } size += sizeof( mach_vm_address_t ) * ((DCLUpdateDCLList*)pClientDCL)->numDCLCommands ; break ; } case kDCLJumpOp : { ((UserExportDCLJump*)dcl)->pJumpDCLLabel = (mach_vm_address_t) ((DCLJump*)pClientDCL)->pJumpDCLLabel->compilerData ; break ; } case kDCLCallProcOp : { size += sizeof( uint64_t[kOSAsyncRef64Count]) ; break ; } default : break ; } #ifndef __LP64__ ROSETTA_ONLY( { switch(dcl->opcode & ~kFWDCLOpFlagMask) { case kDCLSendPacketStartOp: //case kDCLSendPacketWithHeaderStartOp: case kDCLSendPacketOp: case kDCLReceivePacketStartOp: case kDCLReceivePacketOp: ((UserExportDCLTransferPacket*)dcl)->pNextDCLCommand = (mach_vm_address_t)OSSwapInt64(((UserExportDCLTransferPacket*)dcl)->pNextDCLCommand ); ((UserExportDCLTransferPacket*)dcl)->compilerData = OSSwapInt32( ((UserExportDCLTransferPacket*)dcl)->compilerData ); ((UserExportDCLTransferPacket*)dcl)->opcode = OSSwapInt32( ((UserExportDCLTransferPacket*)dcl)->opcode ); ((UserExportDCLTransferPacket*)dcl)->buffer = (mach_vm_address_t)OSSwapInt64( ((UserExportDCLTransferPacket*)dcl)->buffer ); ((UserExportDCLTransferPacket*)dcl)->size = OSSwapInt32( ((UserExportDCLTransferPacket*)dcl)->size ); break ; case kDCLSendBufferOp: case kDCLReceiveBufferOp: ((UserExportDCLTransferBuffer*)dcl)->pNextDCLCommand = (mach_vm_address_t)OSSwapInt64(((UserExportDCLTransferBuffer*)dcl)->pNextDCLCommand ); ((UserExportDCLTransferBuffer*)dcl)->compilerData = OSSwapInt32( ((UserExportDCLTransferBuffer*)dcl)->compilerData ); ((UserExportDCLTransferBuffer*)dcl)->opcode = OSSwapInt32( ((UserExportDCLTransferBuffer*)dcl)->opcode ); ((UserExportDCLTransferBuffer*)dcl)->buffer = (mach_vm_address_t)OSSwapInt64(((UserExportDCLTransferBuffer*)dcl)->buffer ); ((UserExportDCLTransferBuffer*)dcl)->size = OSSwapInt32( ((UserExportDCLTransferBuffer*)dcl)->size ); ((UserExportDCLTransferBuffer*)dcl)->packetSize = OSSwapInt16( ((UserExportDCLTransferBuffer*)dcl)->packetSize ); ((UserExportDCLTransferBuffer*)dcl)->reserved = OSSwapInt16( ((UserExportDCLTransferBuffer*)dcl)->reserved ); ((UserExportDCLTransferBuffer*)dcl)->bufferOffset = OSSwapInt32( ((UserExportDCLTransferBuffer*)dcl)->bufferOffset ); break ; case kDCLCallProcOp: ((UserExportDCLCallProc*)dcl)->pNextDCLCommand = (mach_vm_address_t)OSSwapInt64(((UserExportDCLCallProc*)dcl)->pNextDCLCommand ); ((UserExportDCLCallProc*)dcl)->compilerData = OSSwapInt32( ((UserExportDCLCallProc*)dcl)->compilerData ); ((UserExportDCLCallProc*)dcl)->opcode = OSSwapInt32( ((UserExportDCLCallProc*)dcl)->opcode ); ((UserExportDCLCallProc*)dcl)->proc = (mach_vm_address_t)OSSwapInt64(((UserExportDCLCallProc*)dcl)->proc ); ((UserExportDCLCallProc*)dcl)->procData = OSSwapInt64( ((UserExportDCLCallProc*)dcl)->procData ); break ; case kDCLLabelOp: ((UserExportDCLLabel*)dcl)->pNextDCLCommand = (mach_vm_address_t)OSSwapInt64(((UserExportDCLLabel*)dcl)->pNextDCLCommand ); ((UserExportDCLLabel*)dcl)->compilerData = OSSwapInt32( ((UserExportDCLLabel*)dcl)->compilerData ); ((UserExportDCLLabel*)dcl)->opcode = OSSwapInt32( ((UserExportDCLLabel*)dcl)->opcode ); break ; case kDCLJumpOp: ((UserExportDCLJump*)dcl)->pNextDCLCommand = (mach_vm_address_t)OSSwapInt64( ((UserExportDCLJump*)dcl)->pNextDCLCommand ); ((UserExportDCLJump*)dcl)->compilerData = OSSwapInt32( ((UserExportDCLJump*)dcl)->compilerData ); ((UserExportDCLJump*)dcl)->opcode = OSSwapInt32( ((UserExportDCLJump*)dcl)->opcode ); ((UserExportDCLJump*)dcl)->pJumpDCLLabel = (mach_vm_address_t)OSSwapInt64(((UserExportDCLJump*)dcl)->pJumpDCLLabel ); break ; case kDCLSetTagSyncBitsOp: ((UserExportDCLSetTagSyncBits*)dcl)->pNextDCLCommand = (mach_vm_address_t)OSSwapInt64(((UserExportDCLSetTagSyncBits*)dcl)->pNextDCLCommand ); ((UserExportDCLSetTagSyncBits*)dcl)->compilerData = OSSwapInt32( ((UserExportDCLSetTagSyncBits*)dcl)->compilerData ); ((UserExportDCLSetTagSyncBits*)dcl)->opcode = OSSwapInt32( ((UserExportDCLSetTagSyncBits*)dcl)->opcode ); ((UserExportDCLSetTagSyncBits*)dcl)->tagBits = OSSwapInt16( ((UserExportDCLSetTagSyncBits*)dcl)->tagBits ); ((UserExportDCLSetTagSyncBits*)dcl)->syncBits = OSSwapInt16( ((UserExportDCLSetTagSyncBits*)dcl)->syncBits ); break ; case kDCLUpdateDCLListOp: ((UserExportDCLUpdateDCLList*)dcl)->pNextDCLCommand = (mach_vm_address_t)OSSwapInt64(((UserExportDCLUpdateDCLList*)dcl)->pNextDCLCommand ); ((UserExportDCLUpdateDCLList*)dcl)->compilerData = OSSwapInt32( ((UserExportDCLUpdateDCLList*)dcl)->compilerData ); ((UserExportDCLUpdateDCLList*)dcl)->opcode = OSSwapInt32( ((UserExportDCLUpdateDCLList*)dcl)->opcode ); { mach_vm_address_t * list = (mach_vm_address_t *)( ((UserExportDCLUpdateDCLList*)dcl) + 1 ) ; for( unsigned index=0; index < ((UserExportDCLUpdateDCLList*)dcl)->numDCLCommands; ++index ) { list[ index ] = (mach_vm_address_t)OSSwapInt64(list[ index ] ); } } ((UserExportDCLUpdateDCLList*)dcl)->dclCommandList = (mach_vm_address_t)OSSwapInt64(((UserExportDCLUpdateDCLList*)dcl)->dclCommandList ); ((UserExportDCLUpdateDCLList*)dcl)->numDCLCommands = OSSwapInt32( ((UserExportDCLUpdateDCLList*)dcl)->numDCLCommands ); break ; case kDCLPtrTimeStampOp: ((UserExportDCLPtrTimeStamp*)dcl)->pNextDCLCommand = (mach_vm_address_t)OSSwapInt64(((UserExportDCLPtrTimeStamp*)dcl)->pNextDCLCommand ); ((UserExportDCLPtrTimeStamp*)dcl)->compilerData = OSSwapInt32( ((UserExportDCLPtrTimeStamp*)dcl)->compilerData ); ((UserExportDCLPtrTimeStamp*)dcl)->opcode = OSSwapInt32( ((UserExportDCLPtrTimeStamp*)dcl)->opcode ); ((UserExportDCLPtrTimeStamp*)dcl)->timeStampPtr = (mach_vm_address_t)OSSwapInt64(((UserExportDCLPtrTimeStamp*)dcl)->timeStampPtr ); break; case kDCLSkipCycleOp: ((UserExportDCLCommand*)dcl)->pNextDCLCommand = (mach_vm_address_t)OSSwapInt64(((UserExportDCLCommand*)dcl)->pNextDCLCommand ); ((UserExportDCLCommand*)dcl)->compilerData = OSSwapInt32( ((UserExportDCLCommand*)dcl)->compilerData ); ((UserExportDCLCommand*)dcl)->opcode = OSSwapInt32( ((UserExportDCLCommand*)dcl)->opcode ); ((UserExportDCLCommand*)dcl)->operands[0] = OSSwapInt32( ((UserExportDCLCommand*)dcl)->operands[0] ); break; } } ); #endif offset += size ; } InfoLog("...done\n") ; } // fill in DCL compiler data fields with ( program index + 1 ) ; { unsigned count = 0 ; for( DCLCommand * dcl = mDCLProgram; dcl != nil; dcl = dcl->pNextDCLCommand ) { dcl->compilerData = ++count ; // index incremented here.. // compiler data for DCL should be index + 1 } } 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; error = vm_allocate ( mach_task_self (), (vm_address_t *) &data, dataSize, true /*anywhere*/ ) ; if (error) break; { UInt8 * exportCursor = data ; for( unsigned index=0; index < numDCLs; ++index ) { NuDCL * dcl = ((NuDCL**)inDCLList)[ index ] ; *(UInt32*)exportCursor = dcl->GetExportIndex() ; #ifndef __LP64__ ROSETTA_ONLY( { *(UInt32*)exportCursor = OSSwapInt32(*(UInt32*)exportCursor); } ); #endif exportCursor += sizeof( UInt32 ) ; dcl->Export( (IOVirtualAddress*) & exportCursor, mBufferRanges, mBufferRangeCount ) ; } } uint32_t outputCnt = 0; const uint64_t inputs[4] = {notificationType, numDCLs, (uint64_t) data, dataSize}; error = IOConnectCallScalarMethod(mDevice.GetUserClientConnection(), Device::MakeSelectorWithObject( kLocalIsochPort_Notify_d, mKernPortRef ), inputs,4,NULL,&outputCnt); vm_deallocate( mach_task_self (), (vm_address_t) data, dataSize ) ; 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() ; #ifndef __LP64__ ROSETTA_ONLY( { dcls[ pairIndex ] = OSSwapInt32(dcls[ pairIndex ]); } ); #endif pairIndex += 1; if (theDCL->GetBranch()) dcls[ pairIndex ] = theDCL->GetBranch()->GetExportIndex() ; else dcls[ pairIndex ] = 0; #ifndef __LP64__ ROSETTA_ONLY( { dcls[ pairIndex ] = OSSwapInt32(dcls[ pairIndex ]); } ); #endif pairIndex += 1; } } uint32_t outputCnt = 0; size_t outputStructSize = 0 ; const uint64_t inputs[2] = {notificationType, numDCLs}; error = IOConnectCallMethod(mDevice.GetUserClientConnection(), Device::MakeSelectorWithObject( kLocalIsochPort_Notify_d, mKernPortRef ), inputs,2, dcls,sizeof( dcls ), NULL,&outputCnt, NULL,&outputStructSize); break ; } case kFWNuDCLUpdateNotification: { unsigned dcls[ numDCLs ] ; for( unsigned index=0; index < numDCLs; ++index ) { dcls[ index ] = ((NuDCL*)inDCLList[ index ])->GetExportIndex() ; #ifndef __LP64__ ROSETTA_ONLY( { dcls[ index ] = OSSwapInt32(dcls[ index ]); } ); #endif } uint32_t outputCnt = 0; size_t outputStructSize = 0 ; const uint64_t inputs[2] = {notificationType, numDCLs}; error = IOConnectCallMethod(mDevice.GetUserClientConnection(), Device::MakeSelectorWithObject( kLocalIsochPort_Notify_d, mKernPortRef ), inputs,2, dcls,sizeof( dcls ), NULL,&outputCnt, NULL,&outputStructSize); break ; } case kFWDCLUpdateNotification: case kFWDCLModifyNotification: { error = kIOReturnUnsupported ; } default: error = kIOReturnBadArgument ; } return error ; } #pragma mark - // ============================================================ // // LocalIsochPortCOM // // ============================================================ 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( 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 ) // don't support this yet... #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 ) ; } // // utility functions // 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::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 ; } // // v4 // IOReturn LocalIsochPortCOM::S_SetFinalizeCallback( IOFireWireLibLocalIsochPortRef self, IOFireWireLibIsochPortFinalizeCallback finalizeCallback ) { LocalIsochPortCOM * me = IOFireWireIUnknown::InterfaceMap< LocalIsochPortCOM >::GetThis( self ) ; me->mFinalizeCallback = finalizeCallback ; return kIOReturnSuccess ; } // // v5 (panther) // 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 ) ; } }