IOFireWireLibVectorCommand.cpp [plain text]
#import <IOKit/firewire/IOFireWireLib.h>
#include "IOFireWireLibVectorCommand.h"
#include "IOFireWireLibCommand.h"
#import "IOFireWireLibDevice.h"
#import "IOFireWireLibPriv.h"
namespace IOFireWireLib
{
IOFireWireLibVectorCommandInterface VectorCommand::sInterface =
{
INTERFACEIMP_INTERFACE,
1, 1,
&VectorCommand::SSubmit,
&VectorCommand::SSubmitWithRefconAndCallback,
&VectorCommand::SIsExecuting,
&VectorCommand::SSetCallback,
&VectorCommand::SSetRefCon,
&VectorCommand::SGetRefCon,
&VectorCommand::SSetFlags,
&VectorCommand::SGetFlags,
&VectorCommand::SEnsureCapacity,
&VectorCommand::SAddCommand,
&VectorCommand::SRemoveCommand,
&VectorCommand::SInsertCommandAtIndex,
&VectorCommand::SGetCommandAtIndex,
&VectorCommand::SGetIndexOfCommand,
&VectorCommand::SRemoveCommandAtIndex,
&VectorCommand::SRemoveAllCommands,
&VectorCommand::SGetCommandCount
};
CFArrayCallBacks VectorCommand::sArrayCallbacks =
{
0, &VectorCommand::SRetainCallback, &VectorCommand::SReleaseCallback, NULL, NULL, };
IUnknownVTbl** VectorCommand::Alloc( Device& userclient,
IOFireWireLibCommandCallback callback,
void* inRefCon )
{
VectorCommand * me = new VectorCommand( userclient, callback, inRefCon );
if( !me )
return nil;
return reinterpret_cast<IUnknownVTbl**>(&me->GetInterface());
}
VectorCommand::VectorCommand( Device & userClient,
IOFireWireLibCommandCallback inCallback, void* inRefCon )
: IOFireWireIUnknown( reinterpret_cast<const IUnknownVTbl &>( sInterface ) ),
mUserClient( userClient ),
mKernCommandRef( 0 ),
mRefCon( inRefCon ),
mCallback( inCallback ),
mFlags( 0 ),
mInflightCount( 0 ),
mSubmitBuffer( NULL ),
mSubmitBufferSize( 0 ),
mResultBuffer( NULL ),
mResultBufferSize( 0 )
{
mUserClient.AddRef();
mCommandArray = CFArrayCreateMutable( kCFAllocatorDefault,
0, &sArrayCallbacks );
if( mCommandArray == NULL )
{
throw kIOReturnNoMemory;
}
UserObjectHandle kernel_ref = 0;
size_t outputStructCnt = sizeof(kernel_ref);
IOReturn status = IOConnectCallStructMethod( mUserClient.GetUserClientConnection(),
kVectorCommandCreate,
NULL, 0,
&kernel_ref, &outputStructCnt );
if( status != kIOReturnSuccess )
{
throw status;
}
mKernCommandRef = kernel_ref;
}
VectorCommand::~VectorCommand()
{
if( mKernCommandRef )
{
IOReturn result = kIOReturnSuccess;
uint32_t outputCnt = 0;
const uint64_t inputs[1]={ (const uint64_t)mKernCommandRef };
result = IOConnectCallScalarMethod( mUserClient.GetUserClientConnection(),
kReleaseUserObject,
inputs, 1,
NULL, &outputCnt);
DebugLogCond( result, "VectorCommand::~VectorCommand: command release returned 0x%08x\n", result );
}
if( mSubmitBuffer != NULL )
{
vm_deallocate( mach_task_self(), (vm_address_t)mSubmitBuffer, mSubmitBufferSize );
mSubmitBuffer = NULL;
mSubmitBufferSize = 0;
}
if( mResultBuffer != NULL )
{
vm_deallocate( mach_task_self(), (vm_address_t)mResultBuffer, mResultBufferSize );
mResultBuffer = NULL;
mResultBufferSize = 0;
}
if( mCommandArray )
{
CFRelease( mCommandArray );
mCommandArray = NULL;
}
mUserClient.Release();
}
HRESULT
VectorCommand::QueryInterface( REFIID iid, LPVOID* ppv )
{
HRESULT result = S_OK;
*ppv = nil;
CFUUIDRef interfaceID = CFUUIDCreateFromUUIDBytes( kCFAllocatorDefault, iid );
if( CFEqual(interfaceID, IUnknownUUID) || CFEqual(interfaceID, kIOFireWireVectorCommandInterfaceID) )
{
*ppv = &GetInterface();
AddRef();
}
else
{
*ppv = nil;
result = E_NOINTERFACE;
}
CFRelease( interfaceID );
return result;
}
IOReturn VectorCommand::SEnsureCapacity( IOFireWireLibVectorCommandRef self, UInt32 capacity )
{
return IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self)->EnsureCapacity( capacity );
}
IOReturn VectorCommand::EnsureCapacity( UInt32 capacity )
{
IOReturn status = kIOReturnSuccess;
mach_vm_size_t required_submit_size = capacity * sizeof(CommandSubmitParams);
mach_vm_size_t required_result_size = capacity * sizeof(CommandSubmitResult);
if( (mSubmitBufferSize < required_submit_size) ||
(mResultBufferSize < required_result_size) )
{
vm_address_t submit_buffer = NULL;
status = vm_allocate( mach_task_self(), &submit_buffer, required_submit_size, true ) ;
if ( !submit_buffer && (status == kIOReturnSuccess) )
{
status = kIOReturnNoMemory;
}
vm_address_t result_buffer = NULL;
status = vm_allocate( mach_task_self(), &result_buffer, required_result_size, true ) ;
if ( !result_buffer && (status == kIOReturnSuccess) )
{
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
const uint64_t inputs[4] = { (const uint64_t)submit_buffer,
(const uint64_t)required_submit_size,
(const uint64_t)result_buffer,
(const uint64_t)required_result_size };
uint32_t output_count = 0;
status = IOConnectCallScalarMethod( mUserClient.GetUserClientConnection(),
mUserClient.MakeSelectorWithObject( kVectorCommandSetBuffers, mKernCommandRef ),
inputs, 4,
NULL, &output_count);
}
if( status == kIOReturnSuccess )
{
if( mSubmitBuffer != NULL )
{
vm_deallocate( mach_task_self(), (vm_address_t)mSubmitBuffer, mSubmitBufferSize );
mSubmitBuffer = NULL;
mSubmitBufferSize = 0;
}
if( mResultBuffer != NULL )
{
vm_deallocate( mach_task_self(), (vm_address_t)mResultBuffer, mResultBufferSize );
mResultBuffer = NULL;
mResultBufferSize = 0;
}
}
if( status == kIOReturnSuccess )
{
mSubmitBuffer = (CommandSubmitParams*)submit_buffer;
mSubmitBufferSize = required_submit_size;
mResultBuffer = (CommandSubmitResult*)result_buffer;
mResultBufferSize = required_result_size;
}
}
return status;
}
IOReturn
VectorCommand::SSubmit( IOFireWireLibVectorCommandRef self )
{
return IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self)->Submit();
}
IOReturn
VectorCommand::Submit()
{
IOReturn status = kIOReturnSuccess;
if( mInflightCount != 0 )
{
status = kIOReturnNotReady;
}
CFIndex count = 0;
if( status == kIOReturnSuccess )
{
count = CFArrayGetCount( mCommandArray );
status = EnsureCapacity( count );
}
if( status == kIOReturnSuccess )
{
mStatus = kIOReturnSuccess;
for( CFIndex index = 0; (status == kIOReturnSuccess) && (index < count); index++ )
{
IOFireWireLibCommandRef command = (IOFireWireLibCommandRef)CFArrayGetValueAtIndex( mCommandArray, index );
Cmd * cmd = IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(command);
status = cmd->PrepareForVectorSubmit( &mSubmitBuffer[index] );
}
}
if( status == kIOReturnSuccess )
{
uint64_t async_ref[kOSAsyncRef64Count];
async_ref[kIOAsyncCalloutFuncIndex] = (uint64_t) 0;
async_ref[kIOAsyncCalloutRefconIndex] = (unsigned long) 0;
const uint64_t inputs[2] = { (const uint64_t)&SVectorCompletionHandler,
(const uint64_t)this };
uint32_t output_count = 0;
status = IOConnectCallAsyncScalarMethod( mUserClient.GetUserClientConnection(),
mUserClient.MakeSelectorWithObject( kVectorCommandSubmit, mKernCommandRef ),
mUserClient.GetAsyncPort(),
async_ref, kOSAsyncRef64Count,
inputs, 2,
NULL, &output_count);
mInflightCount = count;
}
if( status == kIOReturnSuccess )
{
for( CFIndex index = 0; (status == kIOReturnSuccess) && (index < count); index++ )
{
IOFireWireLibCommandRef command = (IOFireWireLibCommandRef)CFArrayGetValueAtIndex( mCommandArray, index );
Cmd * cmd = IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(command);
cmd->VectorIsExecuting();
}
}
#if 0
if( status == kIOReturnSuccess )
{
mStatus = kIOReturnSuccess;
for( CFIndex index = 0; index < count; index++ )
{
IOFireWireLibCommandRef command = (IOFireWireLibCommandRef)CFArrayGetValueAtIndex( mCommandArray, index );
mInflightCount++;
(*command)->Submit( command );
}
}
#endif
return status;
}
IOReturn VectorCommand::SSubmitWithRefconAndCallback( IOFireWireLibVectorCommandRef self, void* refCon, IOFireWireLibCommandCallback inCallback )
{
(*self)->SetRefCon( self, refCon );
(*self)->SetCallback( self, inCallback );
return (*self)->Submit( self );
}
Boolean VectorCommand::SIsExecuting( IOFireWireLibVectorCommandRef self )
{
VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self);
return (me->mInflightCount != 0);
}
void
VectorCommand::SVectorCompletionHandler(
void* refcon,
IOReturn result,
void* quads[],
UInt32 numQuads )
{
VectorCommand * me = (VectorCommand*)refcon;
me->VectorCompletionHandler( result, quads, numQuads );
}
void
VectorCommand::VectorCompletionHandler(
IOReturn result,
void* quads[],
UInt32 numQuads )
{
CFIndex count = CFArrayGetCount( mCommandArray );
for( CFIndex index = 0; (index < count); index++ )
{
Cmd * cmd = (Cmd*)mResultBuffer[index].refCon;
IOReturn status = mResultBuffer[index].result;
void * args[3];
args[0] = (void*)mResultBuffer[index].bytesTransferred;
args[1] = (void*)mResultBuffer[index].ackCode;
args[2] = (void*)mResultBuffer[index].responseCode;
cmd->CommandCompletionHandler( cmd, status, args, 3 );
if( mInflightCount > 0 )
{
mInflightCount--;
}
}
(*mCallback)( mRefCon, mStatus );
}
void VectorCommand::SSetCallback( IOFireWireLibVectorCommandRef self, IOFireWireLibCommandCallback inCallback )
{
VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self);
me->mCallback = inCallback;
}
void VectorCommand::SSetRefCon( IOFireWireLibVectorCommandRef self, void* refCon )
{
VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self);
me->mRefCon = refCon;
}
void * VectorCommand::SGetRefCon( IOFireWireLibVectorCommandRef self )
{
VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self);
return me->mRefCon;
}
void VectorCommand::SSetFlags( IOFireWireLibVectorCommandRef self, UInt32 inFlags )
{
VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self);
me->mFlags = inFlags;
}
UInt32 VectorCommand::SGetFlags( IOFireWireLibVectorCommandRef self )
{
VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self);
return me->mFlags;
}
void VectorCommand::SAddCommand( IOFireWireLibVectorCommandRef self, IOFireWireLibCommandRef command )
{
VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self);
CFArrayAppendValue( me->mCommandArray, command );
}
void VectorCommand::SRemoveCommand( IOFireWireLibVectorCommandRef self, IOFireWireLibCommandRef command )
{
VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self);
CFMutableArrayRef array = me->mCommandArray;
CFRange search_range = CFRangeMake( 0, CFArrayGetCount( array ) );
CFIndex index = kCFNotFound;
while( (index = CFArrayGetFirstIndexOfValue( array, search_range, command)) != kCFNotFound )
{
CFArrayRemoveValueAtIndex( array, index );
search_range = CFRangeMake( 0, CFArrayGetCount( array ) );
}
}
void VectorCommand::SInsertCommandAtIndex( IOFireWireLibVectorCommandRef self, IOFireWireLibCommandRef command, UInt32 index )
{
VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self);
CFArrayInsertValueAtIndex( me->mCommandArray, index, command );
}
IOFireWireLibCommandRef VectorCommand::SGetCommandAtIndex( IOFireWireLibVectorCommandRef self, UInt32 index )
{
VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self);
return (IOFireWireLibCommandRef)CFArrayGetValueAtIndex( me->mCommandArray, index );
}
UInt32 VectorCommand::SGetIndexOfCommand( IOFireWireLibVectorCommandRef self, IOFireWireLibCommandRef command )
{
VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self);
CFRange search_range = CFRangeMake( 0, CFArrayGetCount( me->mCommandArray ) );
return CFArrayGetFirstIndexOfValue( me->mCommandArray, search_range, command );
}
void VectorCommand::SRemoveCommandAtIndex( IOFireWireLibVectorCommandRef self, UInt32 index )
{
VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self);
CFArrayRemoveValueAtIndex( me->mCommandArray, index );
}
void VectorCommand::SRemoveAllCommands( IOFireWireLibVectorCommandRef self )
{
VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self);
CFArrayRemoveAllValues( me->mCommandArray );
}
UInt32 VectorCommand::SGetCommandCount( IOFireWireLibVectorCommandRef self )
{
VectorCommand * me = IOFireWireIUnknown::InterfaceMap<VectorCommand>::GetThis(self);
return CFArrayGetCount( me->mCommandArray );
}
const void * VectorCommand::SRetainCallback( CFAllocatorRef allocator, const void * value )
{
IUnknownVTbl** iUnknown = (IUnknownVTbl**)value;
(*iUnknown)->AddRef( iUnknown );
return value;
}
void VectorCommand::SReleaseCallback( CFAllocatorRef allocator, const void * value )
{
IUnknownVTbl** iUnknown = (IUnknownVTbl**)value;
(*iUnknown)->Release( iUnknown );
}
}