IOFireWireLibPseudoAddressSpace.cpp [plain text]
#import "IOFireWireLibPseudoAddressSpace.h"
#import "IOFireWireLibDevice.h"
#import <IOKit/iokitmig.h>
#import <System/libkern/OSCrossEndian.h>
namespace IOFireWireLib {
PseudoAddressSpace::Interface PseudoAddressSpace::sInterface =
{
INTERFACEIMP_INTERFACE,
1, 1, & PseudoAddressSpace::SSetWriteHandler,
& PseudoAddressSpace::SSetReadHandler,
& PseudoAddressSpace::SSetSkippedPacketHandler,
& PseudoAddressSpace::SNotificationIsOn,
& PseudoAddressSpace::STurnOnNotification,
& PseudoAddressSpace::STurnOffNotification,
& PseudoAddressSpace::SClientCommandIsComplete,
& PseudoAddressSpace::SGetFWAddress,
& PseudoAddressSpace::SGetBuffer,
& PseudoAddressSpace::SGetBufferSize,
& PseudoAddressSpace::SGetRefCon
} ;
IUnknownVTbl**
PseudoAddressSpace::Alloc( Device& userclient, UserObjectHandle inKernAddrSpaceRef, void* inBuffer, UInt32 inBufferSize,
void* inBackingStore, void* inRefCon )
{
PseudoAddressSpace* me = nil ;
try {
me = new PseudoAddressSpace(userclient, inKernAddrSpaceRef, inBuffer, inBufferSize, inBackingStore, inRefCon) ;
} catch (...) {
}
return (nil == me) ? nil : reinterpret_cast<IUnknownVTbl**>(& me->GetInterface()) ;
}
HRESULT STDMETHODCALLTYPE
PseudoAddressSpace::QueryInterface(REFIID iid, LPVOID* ppv)
{
HRESULT result = S_OK ;
*ppv = nil ;
CFUUIDRef interfaceID = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, iid) ;
if ( CFEqual(interfaceID, IUnknownUUID) || CFEqual(interfaceID, kIOFireWirePseudoAddressSpaceInterfaceID) )
{
*ppv = & GetInterface() ;
AddRef() ;
}
else
{
*ppv = nil ;
result = E_NOINTERFACE ;
}
CFRelease(interfaceID) ;
return result ;
}
const PseudoAddressSpace::WriteHandler
PseudoAddressSpace::SSetWriteHandler( AddressSpaceRef self, WriteHandler inWriter )
{
return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->SetWriteHandler(inWriter);
}
const PseudoAddressSpace::ReadHandler
PseudoAddressSpace::SSetReadHandler(AddressSpaceRef self, ReadHandler inReader)
{
return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->SetReadHandler(inReader);
}
const PseudoAddressSpace::SkippedPacketHandler
PseudoAddressSpace::SSetSkippedPacketHandler(AddressSpaceRef self, SkippedPacketHandler inHandler)
{
return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->SetSkippedPacketHandler(inHandler);
}
Boolean
PseudoAddressSpace::SNotificationIsOn(AddressSpaceRef self)
{
return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->mNotifyIsOn;
}
Boolean
PseudoAddressSpace::STurnOnNotification(AddressSpaceRef self)
{
return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->TurnOnNotification(self);
}
void
PseudoAddressSpace::STurnOffNotification(AddressSpaceRef self)
{
IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->TurnOffNotification();
}
void
PseudoAddressSpace::SClientCommandIsComplete(AddressSpaceRef self, FWClientCommandID commandID, IOReturn status)
{
IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->ClientCommandIsComplete(commandID, status);
}
void
PseudoAddressSpace::SGetFWAddress(AddressSpaceRef self, FWAddress* outAddr)
{
bcopy (&IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->mFWAddress, outAddr, sizeof(FWAddress));
}
void*
PseudoAddressSpace::SGetBuffer(AddressSpaceRef self)
{
return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->GetBuffer() ;
}
const UInt32
PseudoAddressSpace::SGetBufferSize(AddressSpaceRef self)
{
return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->mBufferSize;
}
void*
PseudoAddressSpace::SGetRefCon(AddressSpaceRef self)
{
return IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(self)->mRefCon;
}
#pragma mark -
PseudoAddressSpace::PseudoAddressSpace( Device& userclient, UserObjectHandle inKernAddrSpaceRef,
void* inBuffer, UInt32 inBufferSize, void* inBackingStore, void* inRefCon)
: IOFireWireIUnknown( reinterpret_cast<const IUnknownVTbl &>( sInterface ) ),
mNotifyIsOn(false),
mWriter( nil ),
mReader( nil ),
mSkippedPacketHandler( nil ),
mUserClient(userclient),
mKernAddrSpaceRef(inKernAddrSpaceRef),
mBuffer((char*)inBuffer),
mBufferSize(inBufferSize),
mBackingStore(inBackingStore),
mRefCon(inRefCon)
{
userclient.AddRef() ;
mPendingLocks = ::CFDictionaryCreateMutable( kCFAllocatorDefault, 0, NULL, NULL ) ;
if (!mPendingLocks)
throw kIOReturnNoMemory ;
AddressSpaceInfo info ;
IOReturn error ;
uint32_t outputCnt = 0;
size_t outputStructSize = sizeof( info ) ;
const uint64_t inputs[1]={(const uint64_t)mKernAddrSpaceRef};
error = IOConnectCallMethod(mUserClient.GetUserClientConnection(),
kPseudoAddrSpace_GetFWAddrInfo,
inputs,1,
NULL,0,
NULL,&outputCnt,
&info,&outputStructSize);
if (error)
{
throw error ;
}
#ifndef __LP64__
ROSETTA_ONLY(
{
info.address.nodeID = OSSwapInt16( info.address.nodeID );
info.address.addressHi = OSSwapInt16( info.address.addressHi );
info.address.addressLo = OSSwapInt32( info.address.addressLo );
}
);
#endif
mFWAddress = info.address ;
}
PseudoAddressSpace::~PseudoAddressSpace()
{
uint32_t outputCnt = 0;
const uint64_t inputs[1]={(const uint64_t)mKernAddrSpaceRef};
#if IOFIREWIREUSERCLIENTDEBUG > 0
IOReturn error =
#endif
IOConnectCallScalarMethod(mUserClient.GetUserClientConnection(),
kReleaseUserObject,
inputs,1,NULL,&outputCnt);
DebugLogCond( error, "PseudoAddressSpace::~PseudoAddressSpace: error %x releasing address space!\n", error ) ;
if( mPendingLocks )
{
::CFDictionaryRemoveAllValues( mPendingLocks );
::CFRelease( mPendingLocks );
mPendingLocks = 0;
}
if( mBuffer and mBufferSize > 0 )
{
delete[] mBuffer;
mBuffer = 0;
mBufferSize = 0;
}
mUserClient.Release() ;
}
#pragma mark -
#pragma mark --callback management
const PseudoAddressSpace::WriteHandler
PseudoAddressSpace::SetWriteHandler( WriteHandler inWriter )
{
WriteHandler oldWriter = mWriter ;
mWriter = inWriter ;
return oldWriter ;
}
const PseudoAddressSpace::ReadHandler
PseudoAddressSpace::SetReadHandler(
ReadHandler inReader)
{
ReadHandler oldReader = mReader ;
mReader = inReader ;
return oldReader ;
}
const PseudoAddressSpace::SkippedPacketHandler
PseudoAddressSpace::SetSkippedPacketHandler(
SkippedPacketHandler inHandler)
{
SkippedPacketHandler result = mSkippedPacketHandler ;
mSkippedPacketHandler = inHandler ;
return result ;
}
Boolean
PseudoAddressSpace::TurnOnNotification( void* callBackRefCon )
{
IOReturn err = kIOReturnSuccess ;
io_connect_t connection = mUserClient.GetUserClientConnection() ;
if (mNotifyIsOn)
return true ;
if (!connection)
err = kIOReturnNoDevice ;
if ( kIOReturnSuccess == err )
{
uint64_t refrncData[kOSAsyncRef64Count];
refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t) 0;
refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long)0;
const uint64_t inputs[3] = {(const uint64_t)mKernAddrSpaceRef, (const uint64_t)&PseudoAddressSpace::Writer, (const uint64_t)callBackRefCon};
uint32_t outputCnt = 0;
err = IOConnectCallAsyncScalarMethod(connection,
kSetAsyncRef_Packet,
mUserClient.GetAsyncPort(),
refrncData,kOSAsyncRef64Count,
inputs,3,
NULL,&outputCnt);
}
if ( kIOReturnSuccess == err)
{
uint64_t refrncData[kOSAsyncRef64Count];
refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t) 0;
refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long)0;
const uint64_t inputs[3] = {(const uint64_t)mKernAddrSpaceRef, (const uint64_t)& SkippedPacket, (const uint64_t)callBackRefCon};
uint32_t outputCnt = 0;
err = IOConnectCallAsyncScalarMethod(connection,
kSetAsyncRef_SkippedPacket,
mUserClient.GetAsyncPort(),
refrncData,kOSAsyncRef64Count,
inputs,3,
NULL,&outputCnt);
}
if ( kIOReturnSuccess == err)
{
uint64_t refrncData[kOSAsyncRef64Count];
refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t) 0;
refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long)0;
const uint64_t inputs[3] = {(const uint64_t)mKernAddrSpaceRef, (const uint64_t)& Reader, (const uint64_t)callBackRefCon};
uint32_t outputCnt = 0;
err = IOConnectCallAsyncScalarMethod(connection,
kSetAsyncRef_Read,
mUserClient.GetAsyncPort(),
refrncData,kOSAsyncRef64Count,
inputs,3,
NULL,&outputCnt);
}
if ( kIOReturnSuccess == err )
mNotifyIsOn = true ;
return ( kIOReturnSuccess == err ) ;
}
void
PseudoAddressSpace::TurnOffNotification()
{
IOReturn err = kIOReturnSuccess ;
io_connect_t connection = mUserClient.GetUserClientConnection() ;
if (!mNotifyIsOn)
return ;
if (!connection)
err = kIOReturnNoDevice ;
if ( kIOReturnSuccess == err )
{
uint64_t refrncData[kOSAsyncRef64Count];
refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t) 0;
refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long)0;
const uint64_t inputs[3] = {(const uint64_t)mKernAddrSpaceRef, (const uint64_t)0, (const uint64_t)this};
uint32_t outputCnt = 0;
err = IOConnectCallAsyncScalarMethod(connection,
kSetAsyncRef_Packet,
mUserClient.GetAsyncPort(),
refrncData,kOSAsyncRef64Count,
inputs,3,
NULL,&outputCnt);
outputCnt = 0;
err = IOConnectCallAsyncScalarMethod(connection,
kSetAsyncRef_SkippedPacket,
mUserClient.GetAsyncPort(),
refrncData,kOSAsyncRef64Count,
inputs,3,
NULL,&outputCnt);
outputCnt = 0;
err = IOConnectCallAsyncScalarMethod(connection,
kSetAsyncRef_Read,
mUserClient.GetAsyncPort(),
refrncData,kOSAsyncRef64Count,
inputs,3,
NULL,&outputCnt);
}
mNotifyIsOn = false ;
}
void
PseudoAddressSpace::ClientCommandIsComplete(
FWClientCommandID commandID,
IOReturn status)
{
void** args ;
if (::CFDictionaryGetValueIfPresent( mPendingLocks, commandID, (const void**) &args ) && (status == kIOReturnSuccess) )
{
::CFDictionaryRemoveValue( mPendingLocks, commandID ) ;
AddressSpaceRef addressSpaceRef = (AddressSpaceRef) args[0] ;
++args ;
bool equal ;
UInt32 offset = (unsigned long)args[6] ;
if ( (unsigned long) args[1] == 8 )
equal = *(UInt32*)((char*)mBackingStore + offset) == *(UInt32*)(mBuffer + (unsigned long)args[2]) ;
else
equal = *(UInt64*)((char*)mBackingStore + offset) == *(UInt64*)(mBuffer + (unsigned long)args[2]) ;
if ( equal )
{
mWriter(
addressSpaceRef,
(FWClientCommandID)(args[0]), (unsigned long)(args[1]) >> 1, mBuffer + (unsigned long)args[2] + ( (unsigned long) args[1] == 8 ? 4 : 8), (UInt16)(unsigned long)args[3], (unsigned long)(args[5]), (unsigned long)(args[6]),
(void*) mRefCon) ; }
else
status = kFWResponseAddressError ;
delete[] (args-1) ;
}
uint32_t outputCnt = 0;
const uint64_t inputs[3] = {(const uint64_t)mKernAddrSpaceRef, (const uint64_t)commandID, status};
#if IOFIREWIREUSERCLIENTDEBUG > 0
OSStatus err =
#endif
IOConnectCallScalarMethod(mUserClient.GetUserClientConnection(),
kPseudoAddrSpace_ClientCommandIsComplete,
inputs,3,
NULL,&outputCnt);
#ifdef __LP64__
DebugLogCond( err, "PseudoAddressSpace::ClientCommandIsComplete: err=0x%08X\n", (UInt32)err ) ;
#else
DebugLogCond( err, "PseudoAddressSpace::ClientCommandIsComplete: err=0x%08lX\n", (UInt32)err ) ;
#endif
}
void
PseudoAddressSpace::Writer( AddressSpaceRef refcon, IOReturn result, void** args, int numArgs)
{
PseudoAddressSpace* me = IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(refcon) ;
if ( !me->mWriter || ( (bool)args[7] && !me->mReader) )
{
me->ClientCommandIsComplete( args[0], kFWResponseTypeError) ;
return ;
}
else if ( (bool)args[7] )
{
void** lockValues = (void**) new UInt32 *[numArgs+1] ;
bcopy( args, & lockValues[1], sizeof(void*) * numArgs ) ;
lockValues[0] = refcon ;
::CFDictionaryAddValue( me->mPendingLocks, args[0], lockValues ) ;
UInt32 offset = (unsigned long)args[6] ;
(me->mReader)( (AddressSpaceRef) refcon,
(FWClientCommandID)(args[0]), (unsigned long)(args[1]), offset, (UInt16)(unsigned long)(args[3]), (unsigned long)(args[5]), (unsigned long)(args[6]), (void*) me->mRefCon) ;
}
else
{
(me->mWriter)(
(AddressSpaceRef) refcon,
(FWClientCommandID) args[0], (unsigned long)(args[1]), me->mBuffer + (unsigned long)(args[2]), (UInt16)(unsigned long)(args[3]), (unsigned long)(args[5]), (unsigned long)(args[6]),
(void*) me->mRefCon) ;
}
}
void
PseudoAddressSpace::SkippedPacket( AddressSpaceRef refcon, IOReturn result, FWClientCommandID commandID, UInt32 packetCount)
{
PseudoAddressSpace* me = IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(refcon) ;
if (me->mSkippedPacketHandler)
(me->mSkippedPacketHandler)( refcon, commandID, packetCount) ;
}
void
PseudoAddressSpace::Reader( AddressSpaceRef refcon, IOReturn result, void** args, int numArgs )
{
PseudoAddressSpace* me = IOFireWireIUnknown::InterfaceMap<PseudoAddressSpace>::GetThis(refcon) ;
if (me->mReader)
{
(me->mReader)( (AddressSpaceRef) refcon,
(FWClientCommandID) args[0], (unsigned long)(args[1]), (unsigned long)(args[2]), (UInt16)(unsigned long)(args[3]), (unsigned long)(args[5]), (unsigned long)(args[6]),
(void*) me->mRefCon) ; }
else
me->ClientCommandIsComplete( args[0], kFWResponseTypeError) ;
}
#pragma mark -
#pragma mark --accessors
const FWAddress&
PseudoAddressSpace::GetFWAddress()
{
return mFWAddress ;
}
void*
PseudoAddressSpace::GetBuffer()
{
return mBackingStore ; }
const UInt32
PseudoAddressSpace::GetBufferSize()
{
return mBufferSize ;
}
void*
PseudoAddressSpace::GetRefCon()
{
return mRefCon ;
}
}