IOFWUserVectorCommand.cpp [plain text]
#include "IOFWUserVectorCommand.h"
#import "IOFWUserCommand.h"
#import <IOKit/firewire/IOFireWireController.h>
#import <IOKit/firewire/IOFireWireNub.h>
OSDefineMetaClassAndStructors( IOFWUserVectorCommand, OSObject );
IOFWUserVectorCommand *
IOFWUserVectorCommand::withUserClient( IOFireWireUserClient * inUserClient )
{
IOFWUserVectorCommand* result = NULL ;
result = OSTypeAlloc( IOFWUserVectorCommand );
if( result && !result->initWithUserClient( inUserClient ) )
{
result->release() ;
result = NULL ;
}
return result ;
}
bool
IOFWUserVectorCommand::initWithUserClient( IOFireWireUserClient * inUserClient )
{
bool success = true;
if( !OSObject::init() )
success = false;
if( success )
{
fUserClient = inUserClient;
fControl = fUserClient->getOwner()->getController();
}
return success;
}
void
IOFWUserVectorCommand::free( void )
{
if( fSubmitDesc )
{
fSubmitDesc->complete();
fSubmitDesc->release();
fSubmitDesc = NULL;
}
if( fResultDesc )
{
fResultDesc->complete();
fResultDesc->release();
fResultDesc = NULL;
}
OSObject::free();
}
#pragma mark -
IOReturn
IOFWUserVectorCommand::setBuffers( mach_vm_address_t submit_buffer_address, mach_vm_size_t submit_buffer_size,
mach_vm_address_t result_buffer_address, mach_vm_size_t result_buffer_size )
{
IOReturn status = kIOReturnSuccess;
if( (submit_buffer_address == 0) || (submit_buffer_size == 0) ||
(result_buffer_address == 0) || (result_buffer_size == 0) )
{
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
if( fSubmitDesc )
{
fSubmitDesc->complete();
fSubmitDesc->release();
fSubmitDesc = NULL;
}
fSubmitDesc = IOMemoryDescriptor::withAddressRange( submit_buffer_address,
submit_buffer_size,
kIODirectionOut,
fUserClient->getOwningTask() );
if( fSubmitDesc == NULL )
{
status = kIOReturnNoMemory;
}
}
if( status == kIOReturnSuccess )
{
status = fSubmitDesc->prepare();
}
if( status == kIOReturnSuccess )
{
if( fResultDesc )
{
fResultDesc->complete();
fResultDesc->release();
fResultDesc = NULL;
}
fResultDesc = IOMemoryDescriptor::withAddressRange( result_buffer_address,
result_buffer_size,
kIODirectionIn,
fUserClient->getOwningTask() );
if( fResultDesc == NULL )
{
status = kIOReturnNoMemory;
}
}
if( status == kIOReturnSuccess )
{
status = fResultDesc->prepare();
}
return status;
}
IOReturn
IOFWUserVectorCommand::submit( OSAsyncReference64 async_ref, mach_vm_address_t callback, io_user_reference_t refCon )
{
IOReturn status = kIOReturnSuccess;
if( fSubmitDesc == NULL )
{
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
IOFireWireUserClient::setAsyncReference64( fAsyncRef, (mach_port_t)async_ref[0], callback, refCon );
}
if( status == kIOReturnSuccess )
{
fControl->closeGate();
fInflightCmds = 0;
fResultOffset = 0;
fVectorStatus = kIOReturnSuccess;
mach_vm_size_t offset = 0;
mach_vm_size_t length = sizeof(CommandSubmitParams);
mach_vm_size_t size = fSubmitDesc->getLength();
while( (status == kIOReturnSuccess) && ((offset + length) <= size) )
{
CommandSubmitParams params;
fSubmitDesc->readBytes( offset, ¶ms, length );
status = submitOneCommand( ¶ms );
offset += length;
}
fControl->openGate();
}
return status;
}
IOReturn
IOFWUserVectorCommand::submitOneCommand( CommandSubmitParams * params )
{
IOReturn status = kIOReturnSuccess;
if( status == kIOReturnSuccess )
{
if( params->kernCommandRef == NULL )
{
status = kIOReturnBadArgument;
}
}
const OSObject * object = NULL;
if( status == kIOReturnSuccess )
{
IOFWUserObjectExporter * exporter = fUserClient->getExporter();
object = exporter->lookupObject( params->kernCommandRef );
if( !object )
{
status = kIOReturnBadArgument;
}
}
IOFWUserCommand * cmd = NULL;
if( status == kIOReturnSuccess )
{
cmd = OSDynamicCast( IOFWUserCommand, object );
if( !cmd )
{
object->release();
object = NULL;
status = kIOReturnBadArgument;
}
}
if( status == kIOReturnSuccess )
{
cmd->setFlush( false );
cmd->setVectorCommand( this );
status = cmd->submit( params, NULL );
fInflightCmds++;
cmd->setFlush( true );
}
if( cmd )
{
cmd->release(); cmd = NULL;
}
return status;
}
void
IOFWUserVectorCommand::asyncCompletion(
void * refcon,
IOReturn status,
IOFireWireNub * device,
IOFWCommand * fwCmd )
{
if( fInflightCmds > 0 )
{
fInflightCmds--;
IOFWUserCommand * cmd = (IOFWUserCommand*)refcon;
IOFWAsyncCommand * async_cmd = cmd->getAsyncCommand();
CommandSubmitResult result;
result.kernCommandRef = 0; result.result = status;
result.bytesTransferred = async_cmd->getBytesTransferred();
result.ackCode = async_cmd->getAckCode();
result.responseCode = async_cmd->getResponseCode();
result.refCon = cmd->getRefCon();
fResultDesc->writeBytes( fResultOffset, &result, sizeof(CommandSubmitResult) );
fResultOffset += sizeof(CommandSubmitResult);
if( status != kIOReturnSuccess )
{
fVectorStatus = status;
}
cmd->setVectorCommand( NULL );
if( fInflightCmds == 0 )
{
IOFireWireUserClient::sendAsyncResult64( fAsyncRef, fVectorStatus, NULL, 0 );
}
}
}
void
IOFWUserVectorCommand::asyncPHYCompletion(
void * refcon,
IOReturn status,
IOFireWireBus * bus,
IOFWAsyncPHYCommand * fwCmd )
{
if( fInflightCmds > 0 )
{
fInflightCmds--;
IOFWUserPHYCommand * cmd = (IOFWUserPHYCommand*)refcon;
IOFWAsyncPHYCommand * async_cmd = cmd->getAsyncPHYCommand();
CommandSubmitResult result;
result.kernCommandRef = 0; result.result = status;
result.bytesTransferred = 8;
result.ackCode = async_cmd->getAckCode();
result.responseCode = async_cmd->getResponseCode();
result.refCon = cmd->getRefCon();
fResultDesc->writeBytes( fResultOffset, &result, sizeof(CommandSubmitResult) );
fResultOffset += sizeof(CommandSubmitResult);
if( status != kIOReturnSuccess )
{
fVectorStatus = status;
}
cmd->setVectorCommand( NULL );
if( fInflightCmds == 0 )
{
IOFireWireUserClient::sendAsyncResult64( fAsyncRef, fVectorStatus, NULL, 0 );
}
}
}