IOFWAsyncCommand.cpp [plain text]
#include <IOKit/firewire/IOFWCommand.h>
#include <IOKit/firewire/IOFireWireController.h>
#include <IOKit/firewire/IOFireWireNub.h>
#include <IOKit/firewire/IOLocalConfigDirectory.h>
#include <IOKit/assert.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOCommand.h>
#import "FWDebugging.h"
#include <IOKit/firewire/IOFWUtils.h>
#define kIOFWAsyncCommandMaxExecutionTime 30000 // try to get the command out for up to 30 seconds
#pragma mark -
OSDefineMetaClass( IOFWAsyncCommand, IOFWCommand )
OSDefineAbstractStructors(IOFWAsyncCommand, IOFWCommand)
OSMetaClassDefineReservedUnused(IOFWAsyncCommand, 0);
OSMetaClassDefineReservedUnused(IOFWAsyncCommand, 1);
OSMetaClassDefineReservedUnused(IOFWAsyncCommand, 2);
OSMetaClassDefineReservedUnused(IOFWAsyncCommand, 3);
#pragma mark -
bool IOFWAsyncCommand::initWithController(IOFireWireController *control)
{
bool success = true;
success = IOFWCommand::initWithController(control);
if( success && fMembers == NULL )
{
success = createMemberVariables();
}
return success;
}
bool IOFWAsyncCommand::initAll(IOFireWireNub *device, FWAddress devAddress,
IOMemoryDescriptor *hostMem, FWDeviceCallback completion,
void *refcon, bool failOnReset)
{
bool success = true;
success = IOFWCommand::initWithController(device->getController());
if( success && fMembers == NULL )
{
success = createMemberVariables();
}
if( success )
{
fMaxRetries = kFWCmdDefaultRetries;
fCurRetries = fMaxRetries;
fMemDesc = hostMem;
fComplete = completion;
fSync = completion == NULL;
fRefCon = refcon;
fTimeout = 1000*125; if(hostMem)
fSize = hostMem->getLength();
fBytesTransferred = 0;
fDevice = device;
device->getNodeIDGeneration(fGeneration, fNodeID);
fAddressHi = devAddress.addressHi;
fAddressLo = devAddress.addressLo;
fMaxPack = 1 << device->maxPackLog(fWrite, devAddress);
fSpeed = fControl->FWSpeed(fNodeID);
if( fMembers->fMaxSpeed < fSpeed )
{
fSpeed = fMembers->fMaxSpeed;
}
fFailOnReset = failOnReset;
fMembers->fAckCode = 0;
fMembers->fResponseCode = 0xff;
fMembers->fResponseSpeed = 0xff;
}
return success;
}
bool IOFWAsyncCommand::initAll(IOFireWireController *control,
UInt32 generation, FWAddress devAddress,
IOMemoryDescriptor *hostMem, FWDeviceCallback completion,
void *refcon)
{
bool success = true;
success = IOFWCommand::initWithController(control);
if( success && fMembers == NULL )
{
success = createMemberVariables();
}
if( success )
{
fMaxRetries = kFWCmdDefaultRetries;
fCurRetries = fMaxRetries;
fMemDesc = hostMem;
fComplete = completion;
fSync = completion == NULL;
fRefCon = refcon;
fTimeout = 1000*125; if(hostMem)
fSize = hostMem->getLength();
fBytesTransferred = 0;
fDevice = NULL;
fGeneration = generation;
fNodeID = devAddress.nodeID;
fAddressHi = devAddress.addressHi;
fAddressLo = devAddress.addressLo;
fMaxPack = 1 << fControl->maxPackLog(fWrite, fNodeID);
fSpeed = fControl->FWSpeed(fNodeID);
if( fMembers->fMaxSpeed < fSpeed )
{
fSpeed = fMembers->fMaxSpeed;
}
fFailOnReset = true;
fMembers->fAckCode = 0;
fMembers->fResponseCode = 0xff;
fMembers->fResponseSpeed = 0xff;
}
return success;
}
bool IOFWAsyncCommand::createMemberVariables( void )
{
bool success = true;
if( fMembers == NULL )
{
if( success )
{
fMembers = (MemberVariables*)IOMalloc( sizeof(MemberVariables) );
if( fMembers == NULL )
success = false;
}
if( success )
{
bzero( fMembers, sizeof(MemberVariables) );
fMembers->fMaxSpeed = kFWSpeedMaximum;
}
if( !success )
{
destroyMemberVariables();
}
}
return success;
}
void IOFWAsyncCommand::destroyMemberVariables( void )
{
if( fMembers != NULL )
{
IOFree( fMembers, sizeof(MemberVariables) );
fMembers = NULL;
}
}
void IOFWAsyncCommand::free()
{
destroyMemberVariables();
IOFWCommand::free();
}
IOReturn IOFWAsyncCommand::reinit(FWAddress devAddress, IOMemoryDescriptor *hostMem,
FWDeviceCallback completion, void *refcon, bool failOnReset)
{
if(fStatus == kIOReturnBusy || fStatus == kIOFireWirePending || fStatus == kIOFireWireCompleting)
return fStatus;
fComplete = completion;
fRefCon = refcon;
fMemDesc=hostMem;
if(fMemDesc)
fSize=fMemDesc->getLength();
fBytesTransferred = 0;
fSync = completion == NULL;
fTrans = NULL;
fCurRetries = fMaxRetries;
if(fDevice) {
fDevice->getNodeIDGeneration(fGeneration, fNodeID);
fMaxPack = 1 << fDevice->maxPackLog(fWrite, devAddress);
}
fAddressHi = devAddress.addressHi;
fAddressLo = devAddress.addressLo;
fSpeed = fControl->FWSpeed(fNodeID);
if( fMembers->fMaxSpeed < fSpeed )
{
fSpeed = fMembers->fMaxSpeed;
}
fFailOnReset = failOnReset;
fMembers->fAckCode = 0;
fMembers->fResponseCode = 0xff;
fMembers->fResponseSpeed = 0xff;
return fStatus = kIOReturnSuccess;
}
IOReturn IOFWAsyncCommand::reinit(UInt32 generation, FWAddress devAddress, IOMemoryDescriptor *hostMem,
FWDeviceCallback completion, void *refcon)
{
if(fStatus == kIOReturnBusy || fStatus == kIOFireWirePending || fStatus == kIOFireWireCompleting)
return fStatus;
if(fDevice)
return kIOReturnBadArgument;
fComplete = completion;
fRefCon = refcon;
fMemDesc=hostMem;
if(fMemDesc)
fSize=fMemDesc->getLength();
fBytesTransferred = 0;
fSync = completion == NULL;
fTrans = NULL;
fCurRetries = fMaxRetries;
fGeneration = generation;
fNodeID = devAddress.nodeID;
fAddressHi = devAddress.addressHi;
fAddressLo = devAddress.addressLo;
fMaxPack = 1 << fControl->maxPackLog(fWrite, fNodeID);
fSpeed = fControl->FWSpeed(fNodeID);
if( fMembers->fMaxSpeed < fSpeed )
{
fSpeed = fMembers->fMaxSpeed;
}
fMembers->fAckCode = 0;
fMembers->fResponseCode = 0xff;
fMembers->fResponseSpeed = 0xff;
return fStatus = kIOReturnSuccess;
}
IOReturn IOFWAsyncCommand::updateGeneration()
{
if(!fDevice)
return kIOReturnBadArgument;
fDevice->getNodeIDGeneration(fGeneration, fNodeID);
if(fStatus == kIOFireWireBusReset)
fStatus = kIOReturnSuccess;
return fStatus;
}
IOReturn IOFWAsyncCommand::updateNodeID(UInt32 generation, UInt16 nodeID)
{
fGeneration = generation;
fNodeID = nodeID;
if(fStatus == kIOFireWireBusReset)
fStatus = kIOReturnSuccess;
return fStatus;
}
IOReturn IOFWAsyncCommand::checkProgress( void )
{
IOReturn status = kIOReturnSuccess;
AbsoluteTime now;
UInt32 milliDelta;
UInt64 nanoDelta;
IOFWGetAbsoluteTime( &now );
SUB_ABSOLUTETIME( &now, &IOFWCommand::fMembers->fSubmitTime );
absolutetime_to_nanoseconds( now, &nanoDelta );
milliDelta = nanoDelta / 1000000;
if( milliDelta > kIOFWAsyncCommandMaxExecutionTime )
{
status = kIOReturnTimeout;
}
return status;
}
IOReturn IOFWAsyncCommand::complete(IOReturn status)
{
IOFWCommand::fMembers->fCompletionStatus = status;
if( fStatus == kIOFireWireCompleting )
{
return kIOReturnSuccess;
}
fStatus = kIOFireWireCompleting;
fControl->handleAsyncCompletion( this, status );
IOReturn completion_status = IOFWCommand::fMembers->fCompletionStatus;
removeFromQ(); if(fTrans)
{
fControl->freeTrans(fTrans);
fTrans = NULL;
}
if( (completion_status == kIOFireWireBusReset) && !fFailOnReset )
{
IOReturn progress_status = checkProgress();
if( progress_status != kIOReturnSuccess )
{
status = progress_status;
}
else
{
if(fControl->scanningBus())
{
setHead(fControl->getAfterResetHandledQ());
return fStatus = kIOFireWirePending; }
else if(fDevice)
{
DebugLog( "FireWire: Command for device %p that's gone away\n", fDevice );
completion_status = kIOReturnOffline; }
}
}
else if(completion_status == kIOReturnTimeout)
{
if(fCurRetries--)
{
bool tryAgain = false;
int ack = getAckCode();
if( (ack == kFWAckBusyX) || (ack == kFWAckBusyA) || (ack == kFWAckBusyB) )
{
tryAgain = true;
}
if(!tryAgain)
{
if( fMaxPack > 4 &&
fAddressHi == kCSRRegisterSpaceBaseAddressHi &&
fAddressLo >= kConfigROMBaseAddress &&
fAddressLo < kConfigROMBaseAddress + 1024)
{
fMaxPack = 4;
tryAgain = true;
}
else
tryAgain = kIOReturnSuccess == fControl->handleAsyncTimeout(this);
}
if( fNodeID == 0x4242 )
{
tryAgain = false;
}
if(tryAgain)
{
IOReturn result;
retain();
fStatus = startExecution();
result = fStatus;
release();
return result;
}
}
}
fStatus = completion_status;
if(fSync)
fSyncWakeup->signal(completion_status);
else if(fComplete)
(*fComplete)(fRefCon, completion_status, fDevice, this);
return completion_status;
}
void IOFWAsyncCommand::gotAck(int ackCode)
{
int rcode;
setAckCode( ackCode );
switch( ackCode )
{
case kFWAckPending:
return;
case kFWAckComplete:
rcode = kFWResponseComplete;
break;
case kFWAckBusyX:
case kFWAckBusyA:
case kFWAckBusyB:
return;
case kFWAckTimeout:
return;
default:
rcode = kFWResponseTypeError; }
gotPacket(rcode, NULL, 0);
}
void IOFWAsyncCommand::setAckCode( int ack )
{
fMembers->fAckCode = ack;
}
int IOFWAsyncCommand::getAckCode( void )
{
return fMembers->fAckCode;
}
void IOFWAsyncCommand::setMaxSpeed( int speed )
{
fMembers->fMaxSpeed = speed;
if( fMembers->fMaxSpeed < fSpeed )
{
fSpeed = fMembers->fMaxSpeed;
}
};
void IOFWAsyncCommand::setRetries( int retries )
{
fMaxRetries = retries;
fCurRetries = fMaxRetries;
};
int IOFWAsyncCommand::getMaxRetries( void )
{
return fMaxRetries;
};
void IOFWAsyncCommand::setResponseCode( UInt32 rcode )
{
fMembers->fResponseCode = rcode;
}
UInt32 IOFWAsyncCommand::getResponseCode( void ) const
{
return fMembers->fResponseCode;
}