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/IOSyncer.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOCommand.h>
#define kDefaultRetries 3
#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 = kDefaultRetries;
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;
}
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 = kDefaultRetries;
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;
}
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)
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;
return fStatus = kIOReturnSuccess;
}
IOReturn IOFWAsyncCommand::reinit(UInt32 generation, FWAddress devAddress, IOMemoryDescriptor *hostMem,
FWDeviceCallback completion, void *refcon)
{
if(fStatus == kIOReturnBusy || fStatus == kIOFireWirePending)
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;
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::complete(IOReturn status)
{
removeFromQ(); if(fTrans) {
fControl->freeTrans(fTrans);
fTrans = NULL;
}
if((status == kIOFireWireBusReset) && !fFailOnReset) {
if(fControl->scanningBus()) {
setHead(fControl->getAfterResetHandledQ());
return fStatus = kIOFireWirePending; }
else if(fDevice) {
IOLog("Command for device %p that's gone away\n", fDevice);
status = kIOReturnOffline; }
}
if(status == kIOReturnTimeout) {
if(fCurRetries--) {
bool tryAgain = kIOFireWireResponseBase+kFWResponseConflictError == fStatus;
if(!tryAgain) {
if(fMaxPack > 4 && fAddressHi == kCSRRegisterSpaceBaseAddressHi &&
fAddressLo >= kConfigROMBaseAddress && fAddressLo < kConfigROMBaseAddress + 1024) {
fMaxPack = 4;
tryAgain = true;
}
else
tryAgain = kIOReturnSuccess == fControl->handleAsyncTimeout(this);
}
if(tryAgain) {
IOReturn result;
retain();
fStatus = startExecution();
result = fStatus;
release();
return result;
}
}
}
fStatus = status;
if(fSync)
fSyncWakeup->signal(status);
else if(fComplete)
(*fComplete)(fRefCon, status, fDevice, this);
return status;
}
void IOFWAsyncCommand::gotAck(int ackCode)
{
int rcode;
setAckCode( ackCode );
switch( ackCode )
{
case kFWAckPending:
IOLog("Command 0x%p received Ack code %d\n", this, ackCode);
return;
case kFWAckComplete:
rcode = kFWResponseComplete;
break;
case kFWAckBusyX:
case kFWAckBusyA:
case kFWAckBusyB:
fStatus = kIOFireWireResponseBase+kFWResponseConflictError;
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;
}
};