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, 0, & 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 ;
IOByteCount outputSize = sizeof( info ) ;
error = ::IOConnectMethodScalarIStructureO( mUserClient.GetUserClientConnection(), kPseudoAddrSpace_GetFWAddrInfo, 1, & outputSize, mKernAddrSpaceRef, &info ) ;
if (error)
{
throw error ;
}
ROSETTA_ONLY(
{
info.address.nodeID = OSSwapInt16( info.address.nodeID );
info.address.addressHi = OSSwapInt16( info.address.addressHi );
info.address.addressLo = OSSwapInt32( info.address.addressLo );
}
);
mFWAddress = info.address ;
}
PseudoAddressSpace::~PseudoAddressSpace()
{
#if IOFIREWIREUSERCLIENTDEBUG > 0
IOReturn error =
#endif
IOConnectMethodScalarIScalarO( mUserClient.GetUserClientConnection(),
kReleaseUserObject, 1, 0, mKernAddrSpaceRef ) ;
DebugLogCond( error, "PseudoAddressSpace::~PseudoAddressSpace: error %x releasing address space!\n", error ) ;
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() ;
io_scalar_inband_t params ;
io_scalar_inband_t output ;
mach_msg_type_number_t size = 0 ;
if (mNotifyIsOn)
return true ;
if (!connection)
err = kIOReturnNoDevice ;
if ( kIOReturnSuccess == err )
{
params[0] = (UInt32)mKernAddrSpaceRef ;
params[1] = (UInt32)(IOAsyncCallback) & PseudoAddressSpace::Writer ;
params[2] = (UInt32) callBackRefCon;
err = io_async_method_scalarI_scalarO(
connection,
mUserClient.GetAsyncPort(),
mPacketAsyncRef,
1,
kSetAsyncRef_Packet,
params,
3,
output,
& size) ;
}
if ( kIOReturnSuccess == err)
{
size=0 ;
params[0] = (UInt32) mKernAddrSpaceRef ;
params[1] = (UInt32)(IOAsyncCallback2) & SkippedPacket ;
params[2] = (UInt32) callBackRefCon;
err = io_async_method_scalarI_scalarO( connection, mUserClient.GetAsyncPort(), mSkippedPacketAsyncRef, 1,
kSetAsyncRef_SkippedPacket, params, 3, output, & size) ;
}
if ( kIOReturnSuccess == err)
{
params[0] = (UInt32) mKernAddrSpaceRef ;
params[1] = (UInt32)(IOAsyncCallback) & Reader ;
params[2] = (UInt32) callBackRefCon ;
err = io_async_method_scalarI_scalarO( connection, mUserClient.GetAsyncPort(), mReadPacketAsyncRef, 1,
kSetAsyncRef_Read, params, 3, params, & size ) ;
}
if ( kIOReturnSuccess == err )
mNotifyIsOn = true ;
return ( kIOReturnSuccess == err ) ;
}
void
PseudoAddressSpace::TurnOffNotification()
{
IOReturn err = kIOReturnSuccess ;
io_connect_t connection = mUserClient.GetUserClientConnection() ;
io_scalar_inband_t params ;
mach_msg_type_number_t size = 0 ;
if (!mNotifyIsOn)
return ;
if (!connection)
err = kIOReturnNoDevice ;
if ( kIOReturnSuccess == err )
{
params[0] = (UInt32) mKernAddrSpaceRef ;
params[1] = (UInt32)(IOAsyncCallback) 0 ;
params[2] = (UInt32) this ;
err = ::io_async_method_scalarI_scalarO( connection, mUserClient.GetAsyncPort(), mPacketAsyncRef,
1, kSetAsyncRef_Packet, params, 3, params, & size) ;
params[0] = (UInt32) mKernAddrSpaceRef ;
params[1] = (UInt32)(IOAsyncCallback) 0 ;
params[2] = (UInt32) this ;
err = io_async_method_scalarI_scalarO( connection, mUserClient.GetAsyncPort(), mSkippedPacketAsyncRef,
1, kSetAsyncRef_SkippedPacket, params, 3, params, & size) ;
params[0] = (UInt32) mKernAddrSpaceRef ;
params[1] = (UInt32)(IOAsyncCallback) 0 ;
params[2] = (UInt32) this ;
err = io_async_method_scalarI_scalarO( connection, mUserClient.GetAsyncPort(),
mReadPacketAsyncRef, 1, kSetAsyncRef_Read, params, 3, params, & size) ;
}
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 = (UInt32)args[6] ;
if ( (UInt32) args[1] == 8 )
equal = *(UInt32*)((char*)mBackingStore + offset) == *(UInt32*)(mBuffer + (UInt32)args[2]) ;
else
equal = *(UInt64*)((char*)mBackingStore + offset) == *(UInt64*)(mBuffer + (UInt32)args[2]) ;
if ( equal )
{
mWriter(
addressSpaceRef,
(FWClientCommandID)(args[0]), (UInt32)(args[1]) >> 1, mBuffer + (UInt32)args[2] + ( (UInt32) args[1] == 8 ? 4 : 8), (UInt16)(UInt32)args[3], (UInt32)(args[5]), (UInt32)(args[6]),
(UInt32) mRefCon) ; }
else
status = kFWResponseAddressError ;
delete[] (args-1) ;
}
#if IOFIREWIREUSERCLIENTDEBUG > 0
OSStatus err =
#endif
::IOConnectMethodScalarIScalarO( mUserClient.GetUserClientConnection(), kPseudoAddrSpace_ClientCommandIsComplete,
3, 0, mKernAddrSpaceRef, commandID, status) ;
DebugLogCond( err, "PseudoAddressSpace::ClientCommandIsComplete: err=0x%08lX\n", err ) ;
}
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 = (UInt32)args[6] ;
(me->mReader)( (AddressSpaceRef) refcon,
(FWClientCommandID)(args[0]), (UInt32)(args[1]), offset, (UInt16)(UInt32)(args[3]), (UInt32)(args[5]), (UInt32)(args[6]), (UInt32) me->mRefCon) ;
}
else
{
(me->mWriter)(
(AddressSpaceRef) refcon,
(FWClientCommandID) args[0], (UInt32)(args[1]), me->mBuffer + (UInt32)(args[2]), (UInt16)(UInt32)(args[3]), (UInt32)(args[5]), (UInt32)(args[6]),
(UInt32) 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], (UInt32)(args[1]), (UInt32)(args[2]), (UInt16)(UInt32)(args[3]), (UInt32)(args[5]), (UInt32)(args[6]),
(UInt32) 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 ;
}
}