#include <IOKit/assert.h>
#include <IOKit/IOSyncer.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOCommand.h>
#include <IOKit/firewire/IOFWCommand.h>
#include <IOKit/firewire/IOFireWireController.h>
#include <IOKit/firewire/IOFireWireNub.h>
#include <IOKit/firewire/IOLocalConfigDirectory.h>
#define kDefaultRetries 3
bool IOFWCmdQ::executeQueue(bool all)
{
IOFWCommand *cmd;
cmd = fHead;
while(cmd) {
IOFWCommand *newHead;
newHead = cmd->getNext();
if(newHead)
newHead->fQueuePrev = NULL;
else
fTail = NULL;
fHead = newHead;
cmd->startExecution();
if(!all)
break;
cmd = newHead;
}
return fHead != NULL; }
void IOFWCmdQ::headChanged(IOFWCommand *oldHead)
{
}
OSDefineMetaClass( IOFWCommand, IOCommand )
OSDefineAbstractStructors(IOFWCommand, IOCommand)
OSMetaClassDefineReservedUnused(IOFWCommand, 0);
OSMetaClassDefineReservedUnused(IOFWCommand, 1);
bool IOFWCommand::initWithController(IOFireWireController *control)
{
if(!IOCommand::init())
return false;
fControl = control;
return true;
}
IOReturn IOFWCommand::submit(bool queue)
{
IOReturn res;
IOWorkLoop * workLoop = fControl->getWorkLoop();
if(workLoop->onThread() && fSync) {
IOLog("Potential FireWire workloop deadlock!\n");
IOLog("Naughty cmd is a %s\n", getMetaClass()->getClassName());
}
if(fSync) {
fSyncWakeup = IOSyncer::create();
if(!fSyncWakeup)
return kIOReturnNoMemory;
}
fControl->closeGate();
if(queue) {
IOFWCmdQ &pendingQ = fControl->getPendingQ();
IOFWCommand *prev = pendingQ.fTail;
if(!prev) {
setHead(pendingQ);
}
else {
insertAfter(*prev);
}
res = fStatus = kIOFireWirePending;
}
else {
res = fStatus = startExecution();
}
fControl->openGate();
if(res == kIOReturnBusy || res == kIOFireWirePending)
res = kIOReturnSuccess;
if(fSync) {
if(res == kIOReturnSuccess)
res = fSyncWakeup->wait();
else
fSyncWakeup->release();
fSyncWakeup = NULL;
}
return res;
}
IOReturn IOFWCommand::startExecution()
{
if(fTimeout) {
AbsoluteTime delta;
IOFWCommand *prev;
IOFWCmdQ &timeoutQ = fControl->getTimeoutQ();
clock_interval_to_absolutetime_interval(fTimeout, kMicrosecondScale, &delta);
clock_get_uptime(&fDeadline);
ADD_ABSOLUTETIME(&fDeadline, &delta);
prev = timeoutQ.fTail;
while(prev) {
if(CMP_ABSOLUTETIME(&prev->getDeadline(), &fDeadline) != 1)
break; prev = prev->getPrevious();
}
if(!prev) {
setHead(timeoutQ);
}
else {
insertAfter(*prev);
}
}
return execute();
}
IOReturn IOFWCommand::complete(IOReturn status)
{
removeFromQ();
return fStatus = status;
}
void IOFWCommand::updateTimer()
{
if(fTimeout) {
AbsoluteTime delta;
IOFWCommand *oldHead = fQueue->fHead;
IOFWCommand *next;
clock_interval_to_absolutetime_interval(fTimeout, kMicrosecondScale, &delta);
clock_get_uptime(&fDeadline);
ADD_ABSOLUTETIME(&fDeadline, &delta);
next = fQueueNext;
while(next) {
if(CMP_ABSOLUTETIME(&next->fDeadline, &fDeadline) == 1)
break; next = next->fQueueNext;
}
if(next != fQueueNext) {
IOFWCommand *prev;
if(fQueuePrev) {
assert(fQueuePrev->fQueueNext == this);
fQueuePrev->fQueueNext = fQueueNext;
}
else {
assert(fQueue->fHead == this);
fQueue->fHead = fQueueNext;
}
assert(fQueueNext); assert(fQueueNext->fQueuePrev == this);
fQueueNext->fQueuePrev = fQueuePrev;
if(!next) {
prev = fQueue->fTail;
fQueue->fTail = this;
}
else {
prev = next->fQueuePrev;
next->fQueuePrev = this;
}
assert(prev); prev->fQueueNext = this;
fQueuePrev = prev;
fQueueNext = next;
}
if(oldHead == this) {
fQueue->headChanged(this);
}
}
}
IOReturn IOFWCommand::cancel(IOReturn reason)
{
IOReturn result = kIOReturnSuccess;
fControl->closeGate();
result = complete(reason);
fControl->openGate();
return result;
}
void IOFWCommand::setHead(IOFWCmdQ &queue)
{
IOFWCommand *oldHead;
oldHead = queue.fHead;
queue.fHead = this;
fQueue = &queue;
fQueuePrev = NULL;
fQueueNext = oldHead;
if(!oldHead)
queue.fTail = this;
else
oldHead->fQueuePrev = this;
queue.headChanged(oldHead); }
void IOFWCommand::insertAfter(IOFWCommand &prev)
{
IOFWCommand *next;
next = prev.fQueueNext;
fQueue = prev.fQueue;
prev.fQueueNext = this;
fQueuePrev = &prev;
fQueueNext = next;
if(!next)
fQueue->fTail = this;
else
next->fQueuePrev = this;
}
void IOFWCommand::removeFromQ()
{
if(fQueue) {
IOFWCmdQ *queue = fQueue;
IOFWCommand *oldHead = queue->fHead;
if(fQueuePrev) {
assert(fQueuePrev->fQueueNext == this);
fQueuePrev->fQueueNext = fQueueNext;
}
else {
assert(queue->fHead == this);
queue->fHead = fQueueNext;
}
if(fQueueNext) {
assert(fQueueNext->fQueuePrev == this);
fQueueNext->fQueuePrev = fQueuePrev;
}
else {
assert(queue->fTail == this);
queue->fTail = fQueuePrev;
}
fQueue = NULL;
if(oldHead == this) {
queue->headChanged(this);
}
}
}
OSDefineMetaClass( IOFWBusCommand, IOFWCommand )
OSDefineAbstractStructors(IOFWBusCommand, IOFWCommand)
OSMetaClassDefineReservedUnused(IOFWBusCommand, 0);
bool IOFWBusCommand::initWithController(IOFireWireController *control, FWBusCallback completion, void *refcon)
{
if(!IOFWCommand::initWithController(control))
return false;
fSync = completion == NULL;
fComplete = completion;
fRefCon = refcon;
return true;
}
IOReturn IOFWBusCommand::reinit(FWBusCallback completion, void *refcon)
{
if(fStatus == kIOReturnBusy || fStatus == kIOFireWirePending)
return fStatus;
fSync = completion == NULL;
fComplete = completion;
fRefCon = refcon;
return kIOReturnSuccess;
}
IOReturn IOFWBusCommand::complete(IOReturn state)
{
state = IOFWCommand::complete(state);
if(fSync)
fSyncWakeup->signal(state);
else if(fComplete)
(*fComplete)(fRefCon, state, fControl, this);
return state;
}
OSDefineMetaClassAndStructors(IOFWDelayCommand, IOFWBusCommand)
OSMetaClassDefineReservedUnused(IOFWDelayCommand, 0);
bool IOFWDelayCommand::initWithDelay(IOFireWireController *control,
UInt32 delay, FWBusCallback completion, void *refcon)
{
if(!IOFWBusCommand::initWithController(control, completion, refcon))
return false;
fTimeout = delay;
return true;
}
IOReturn IOFWDelayCommand::reinit(UInt32 delay, FWBusCallback completion, void *refcon)
{
IOReturn res;
res = IOFWBusCommand::reinit(completion, refcon);
if(res != kIOReturnSuccess)
return res;
fTimeout = delay;
return kIOReturnSuccess;
}
IOReturn IOFWDelayCommand::execute()
{
fStatus = kIOReturnBusy;
return fStatus;
}
OSDefineMetaClass( IOFWAsyncCommand, IOFWCommand )
OSDefineAbstractStructors(IOFWAsyncCommand, IOFWCommand)
OSMetaClassDefineReservedUnused(IOFWAsyncCommand, 0);
OSMetaClassDefineReservedUnused(IOFWAsyncCommand, 1);
OSMetaClassDefineReservedUnused(IOFWAsyncCommand, 2);
OSMetaClassDefineReservedUnused(IOFWAsyncCommand, 3);
bool IOFWAsyncCommand::initAll(IOFireWireNub *device, FWAddress devAddress,
IOMemoryDescriptor *hostMem, FWDeviceCallback completion,
void *refcon, bool failOnReset)
{
if(!IOFWCommand::initWithController(device->getController()))
return false;
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);
fFailOnReset = failOnReset;
return true;
}
bool IOFWAsyncCommand::initAll(IOFireWireController *control,
UInt32 generation, FWAddress devAddress,
IOMemoryDescriptor *hostMem, FWDeviceCallback completion,
void *refcon)
{
if(!IOFWCommand::initWithController(control))
return false;
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);
fFailOnReset = true;
return true;
}
IOReturn IOFWAsyncCommand::reinit(FWAddress devAddress, IOMemoryDescriptor *hostMem,
FWDeviceCallback completion, void *refcon, bool failOnReset)
{
if(fStatus == kIOReturnBusy || fStatus == kIOFireWirePending)
return fStatus;
fComplete = completion;
fRefCon = refcon;
if(hostMem)
fSize = hostMem->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);
fFailOnReset = failOnReset;
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;
if(hostMem)
fSize = hostMem->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);
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 && fControl->scanningBus()) {
setHead(fControl->getAfterResetHandledQ());
return fStatus = kIOFireWirePending; }
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) {
return fStatus = startExecution();
}
}
}
fStatus = status;
if(fSync)
fSyncWakeup->signal(status);
else if(fComplete)
(*fComplete)(fRefCon, status, fDevice, this);
return status;
}
void IOFWAsyncCommand::gotAck(int ackCode)
{
int rcode;
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);
}
OSDefineMetaClassAndStructors(IOFWReadCommand, IOFWAsyncCommand)
OSMetaClassDefineReservedUnused(IOFWReadCommand, 0);
OSMetaClassDefineReservedUnused(IOFWReadCommand, 1);
void IOFWReadCommand::gotPacket(int rcode, const void* data, int size)
{
if(rcode != kFWResponseComplete) {
if(rcode == kFWResponseTypeError && fMaxPack > 4) {
fMaxPack = 4;
size = 0;
}
else {
complete(kIOFireWireResponseBase+rcode);
return;
}
}
else {
fMemDesc->writeBytes(fBytesTransferred, data, size);
fSize -= size;
fBytesTransferred += size;
}
if(fSize > 0) {
fAddressLo += size;
fControl->freeTrans(fTrans); updateTimer();
fCurRetries = fMaxRetries;
execute();
}
else {
complete(kIOReturnSuccess);
}
}
bool IOFWReadCommand::initAll(IOFireWireNub *device, FWAddress devAddress,
IOMemoryDescriptor *hostMem, FWDeviceCallback completion,
void *refcon, bool failOnReset)
{
return IOFWAsyncCommand::initAll(device, devAddress,
hostMem, completion, refcon, failOnReset);
}
bool IOFWReadCommand::initAll(IOFireWireController *control,
UInt32 generation, FWAddress devAddress,
IOMemoryDescriptor *hostMem, FWDeviceCallback completion,
void *refcon)
{
return IOFWAsyncCommand::initAll(control, generation, devAddress,
hostMem, completion, refcon);
}
IOReturn IOFWReadCommand::reinit(FWAddress devAddress,
IOMemoryDescriptor *hostMem,
FWDeviceCallback completion, void *refcon, bool failOnReset)
{
return IOFWAsyncCommand::reinit(devAddress,
hostMem, completion, refcon, failOnReset);
}
IOReturn IOFWReadCommand::reinit(UInt32 generation, FWAddress devAddress,
IOMemoryDescriptor *hostMem,
FWDeviceCallback completion, void *refcon)
{
return IOFWAsyncCommand::reinit(generation, devAddress,
hostMem, completion, refcon);
}
IOReturn IOFWReadCommand::execute()
{
IOReturn result;
int transfer;
fStatus = kIOReturnBusy;
if(!fFailOnReset) {
fDevice->getNodeIDGeneration(fGeneration, fNodeID);
}
transfer = fSize;
if(transfer > fMaxPack)
transfer = fMaxPack;
fTrans = fControl->allocTrans(this);
if(fTrans) {
result = fControl->asyncRead(fGeneration, fNodeID, fAddressHi,
fAddressLo, fSpeed, fTrans->fTCode, transfer, this);
}
else {
IOLog("IOFWReadCommand::execute: Out of tcodes?");
result = kIOReturnInternalError;
}
if(result != kIOReturnSuccess)
complete(result);
return (fStatus);
}
OSDefineMetaClassAndStructors(IOFWReadQuadCommand, IOFWAsyncCommand)
OSMetaClassDefineReservedUnused(IOFWReadQuadCommand, 0);
OSMetaClassDefineReservedUnused(IOFWReadQuadCommand, 1);
void IOFWReadQuadCommand::gotPacket(int rcode, const void* data, int size)
{
if(rcode != kFWResponseComplete) {
if( (rcode == kFWResponseTypeError || rcode == kFWResponseAddressError) && fMaxPack > 4) {
fMaxPack = 4;
size = 0;
}
else {
complete(kIOFireWireResponseBase+rcode);
return;
}
}
else {
int i;
UInt32 *src = (UInt32 *)data;
for(i=0; i<size/4; i++)
*fQuads++ = *src++;
fSize -= size;
fBytesTransferred += size ;
}
if(fSize > 0) {
fAddressLo += size;
updateTimer();
fCurRetries = fMaxRetries;
fControl->freeTrans(fTrans);
execute();
}
else {
complete(kIOReturnSuccess);
}
}
bool IOFWReadQuadCommand::initAll(IOFireWireNub *device, FWAddress devAddress,
UInt32 *quads, int numQuads, FWDeviceCallback completion,
void *refcon, bool failOnReset)
{
if(!IOFWAsyncCommand::initAll(device, devAddress,
NULL, completion, refcon, failOnReset))
return false;
fSize = 4*numQuads;
fQuads = quads;
return true;
}
bool IOFWReadQuadCommand::initAll(IOFireWireController *control,
UInt32 generation, FWAddress devAddress,
UInt32 *quads, int numQuads, FWDeviceCallback completion,
void *refcon)
{
if(!IOFWAsyncCommand::initAll(control, generation, devAddress,
NULL, completion, refcon))
return false;
fSize = 4*numQuads;
fQuads = quads;
return true;
}
IOReturn IOFWReadQuadCommand::reinit(FWAddress devAddress,
UInt32 *quads, int numQuads, FWDeviceCallback completion,
void *refcon, bool failOnReset)
{
IOReturn res;
res = IOFWAsyncCommand::reinit(devAddress,
NULL, completion, refcon, failOnReset);
if(res != kIOReturnSuccess)
return res;
fSize = 4*numQuads;
fQuads = quads;
return res;
}
IOReturn IOFWReadQuadCommand::reinit(UInt32 generation, FWAddress devAddress,
UInt32 *quads, int numQuads, FWDeviceCallback completion, void *refcon)
{
IOReturn res;
res = IOFWAsyncCommand::reinit(generation, devAddress,
NULL, completion, refcon);
if(res != kIOReturnSuccess)
return res;
fSize = 4*numQuads;
fQuads = quads;
return res;
}
IOReturn IOFWReadQuadCommand::execute()
{
IOReturn result;
int transfer;
fStatus = kIOReturnBusy;
if(!fFailOnReset) {
fDevice->getNodeIDGeneration(fGeneration, fNodeID);
}
transfer = fSize;
if(transfer > fMaxPack)
transfer = fMaxPack;
fTrans = fControl->allocTrans(this);
if(fTrans) {
result = fControl->asyncRead(fGeneration, fNodeID, fAddressHi,
fAddressLo, fSpeed, fTrans->fTCode, transfer, this);
}
else {
IOLog("IOFWReadQuadCommand::execute: Out of tcodes?");
result = kIOReturnInternalError;
}
if(result != kIOReturnSuccess)
complete(result);
return (fStatus);
}
OSDefineMetaClassAndStructors(IOFWWriteCommand, IOFWAsyncCommand)
OSMetaClassDefineReservedUnused(IOFWWriteCommand, 0);
OSMetaClassDefineReservedUnused(IOFWWriteCommand, 1);
void IOFWWriteCommand::gotPacket(int rcode, const void* data, int size)
{
if(rcode != kFWResponseComplete) {
complete(kIOFireWireResponseBase+rcode);
return;
}
else {
fBytesTransferred += fPackSize;
fSize -= fPackSize;
}
if(fSize > 0) {
fAddressLo += fPackSize;
updateTimer();
fCurRetries = fMaxRetries;
fControl->freeTrans(fTrans); execute();
}
else {
complete(kIOReturnSuccess);
}
}
bool IOFWWriteCommand::initAll(IOFireWireNub *device, FWAddress devAddress,
IOMemoryDescriptor *hostMem, FWDeviceCallback completion,
void *refcon, bool failOnReset)
{
fWrite = true;
return IOFWAsyncCommand::initAll(device, devAddress,
hostMem, completion, refcon, failOnReset);
}
bool IOFWWriteCommand::initAll(IOFireWireController *control,
UInt32 generation, FWAddress devAddress,
IOMemoryDescriptor *hostMem, FWDeviceCallback completion, void *refcon)
{
fWrite = true;
return IOFWAsyncCommand::initAll(control, generation, devAddress,
hostMem, completion, refcon);
}
IOReturn IOFWWriteCommand::reinit(FWAddress devAddress,
IOMemoryDescriptor *hostMem,
FWDeviceCallback completion, void *refcon, bool failOnReset)
{
return IOFWAsyncCommand::reinit(devAddress,
hostMem, completion, refcon, failOnReset);
}
IOReturn IOFWWriteCommand::reinit(UInt32 generation, FWAddress devAddress,
IOMemoryDescriptor *hostMem,
FWDeviceCallback completion, void *refcon)
{
return IOFWAsyncCommand::reinit(generation, devAddress,
hostMem, completion, refcon);
}
IOReturn IOFWWriteCommand::execute()
{
IOReturn result;
fStatus = kIOReturnBusy;
if(!fFailOnReset) {
fDevice->getNodeIDGeneration(fGeneration, fNodeID);
}
fPackSize = fSize;
if(fPackSize > fMaxPack)
fPackSize = fMaxPack;
fTrans = fControl->allocTrans(this);
if(fTrans) {
result = fControl->asyncWrite(fGeneration, fNodeID, fAddressHi, fAddressLo, fSpeed,
fTrans->fTCode, fMemDesc, fBytesTransferred, fPackSize, this);
}
else {
IOLog("IOFWWriteCommand::execute: Out of tcodes?");
result = kIOReturnInternalError;
}
if(result != kIOReturnSuccess)
complete(result);
return (fStatus);
}
OSDefineMetaClassAndStructors(IOFWWriteQuadCommand, IOFWAsyncCommand)
OSMetaClassDefineReservedUnused(IOFWWriteQuadCommand, 0);
OSMetaClassDefineReservedUnused(IOFWWriteQuadCommand, 1);
void IOFWWriteQuadCommand::gotPacket(int rcode, const void* data, int size)
{
if(rcode != kFWResponseComplete) {
complete(kIOFireWireResponseBase+rcode);
return;
}
else {
fQPtr += fPackSize/4;
fSize -= fPackSize;
fBytesTransferred += fPackSize ;
}
if(fSize > 0) {
fAddressLo += fPackSize;
updateTimer();
fCurRetries = fMaxRetries;
fControl->freeTrans(fTrans);
execute();
}
else {
complete(kIOReturnSuccess);
}
}
bool IOFWWriteQuadCommand::initAll(IOFireWireNub *device, FWAddress devAddress,
UInt32 *quads, int numQuads, FWDeviceCallback completion,
void *refcon, bool failOnReset)
{
int i;
if(numQuads > kMaxWriteQuads)
return false;
fWrite = true;
if(!IOFWAsyncCommand::initAll(device, devAddress,
NULL, completion, refcon, failOnReset))
return false;
fSize = 4*numQuads;
for(i=0; i<numQuads; i++)
fQuads[i] = *quads++;
fQPtr = fQuads;
return true;
}
bool IOFWWriteQuadCommand::initAll(IOFireWireController *control,
UInt32 generation, FWAddress devAddress,
UInt32 *quads, int numQuads, FWDeviceCallback completion, void *refcon)
{
int i;
if(numQuads > kMaxWriteQuads)
return false;
fWrite = true;
if(!IOFWAsyncCommand::initAll(control, generation, devAddress,
NULL, completion, refcon))
return false;
fSize = 4*numQuads;
for(i=0; i<numQuads; i++)
fQuads[i] = *quads++;
fQPtr = fQuads;
return true;
}
IOReturn IOFWWriteQuadCommand::reinit(FWAddress devAddress,
UInt32 *quads, int numQuads, FWDeviceCallback completion,
void *refcon, bool failOnReset)
{
IOReturn res;
int i;
if(numQuads > kMaxWriteQuads)
return kIOReturnUnsupported;
res = IOFWAsyncCommand::reinit(devAddress,
NULL, completion, refcon, failOnReset);
if(res != kIOReturnSuccess)
return res;
fSize = 4*numQuads;
for(i=0; i<numQuads; i++)
fQuads[i] = *quads++;
fQPtr = fQuads;
return res;
}
IOReturn IOFWWriteQuadCommand::reinit(UInt32 generation, FWAddress devAddress,
UInt32 *quads, int numQuads, FWDeviceCallback completion, void *refcon)
{
IOReturn res;
int i;
if(numQuads > kMaxWriteQuads)
return kIOReturnUnsupported;
res = IOFWAsyncCommand::reinit(generation, devAddress, NULL, completion, refcon);
if(res != kIOReturnSuccess)
return res;
fSize = 4*numQuads;
for(i=0; i<numQuads; i++)
fQuads[i] = *quads++;
fQPtr = fQuads;
return res;
}
IOReturn IOFWWriteQuadCommand::execute()
{
IOReturn result;
fStatus = kIOReturnBusy;
if(!fFailOnReset) {
fDevice->getNodeIDGeneration(fGeneration, fNodeID);
}
fPackSize = fSize;
if(fPackSize > fMaxPack)
fPackSize = fMaxPack;
fTrans = fControl->allocTrans(this);
if(fTrans) {
result = fControl->asyncWrite(fGeneration, fNodeID, fAddressHi, fAddressLo,
fSpeed, fTrans->fTCode, fQPtr, fPackSize, this);
}
else {
IOLog("IOFWWriteQuadCommand::execute: Out of tcodes?");
result = kIOReturnInternalError;
}
if(result != kIOReturnSuccess)
complete(result);
return (fStatus);
}
OSDefineMetaClassAndStructors(IOFWCompareAndSwapCommand, IOFWAsyncCommand)
OSMetaClassDefineReservedUnused(IOFWCompareAndSwapCommand, 0);
OSMetaClassDefineReservedUnused(IOFWCompareAndSwapCommand, 1);
OSMetaClassDefineReservedUnused(IOFWCompareAndSwapCommand, 2);
OSMetaClassDefineReservedUnused(IOFWCompareAndSwapCommand, 3);
void IOFWCompareAndSwapCommand::gotPacket(int rcode, const void* data, int size)
{
int i;
if(rcode != kFWResponseComplete) {
IOLog("Received rcode %d for lock command %p, nodeID %x\n", rcode, this, fNodeID);
complete(kIOFireWireResponseBase+rcode);
return;
}
for(i=0; i<size/4; i++) {
fOldVal[i] = ((UInt32 *)data)[i];
}
complete(kIOReturnSuccess);
}
bool IOFWCompareAndSwapCommand::initAll(IOFireWireNub *device, FWAddress devAddress,
const UInt32 *cmpVal, const UInt32 *newVal, int size, FWDeviceCallback completion,
void *refcon, bool failOnReset)
{
int i;
if(!IOFWAsyncCommand::initAll(device, devAddress,
NULL, completion, refcon, failOnReset))
return false;
for(i=0; i<size; i++) {
fInputVals[i] = cmpVal[i];
fInputVals[size+i] = newVal[i];
}
fSize = 8*size;
return true;
}
bool IOFWCompareAndSwapCommand::initAll(IOFireWireController *control,
UInt32 generation, FWAddress devAddress,
const UInt32 *cmpVal, const UInt32 *newVal, int size,
FWDeviceCallback completion, void *refcon)
{
int i;
if(!IOFWAsyncCommand::initAll(control, generation, devAddress,
NULL, completion, refcon))
return false;
for(i=0; i<size; i++) {
fInputVals[i] = cmpVal[i];
fInputVals[size+i] = newVal[i];
}
fSize = 8*size;
return true;
}
IOReturn IOFWCompareAndSwapCommand::reinit(FWAddress devAddress,
const UInt32 *cmpVal, const UInt32 *newVal, int size,
FWDeviceCallback completion, void *refcon, bool failOnReset)
{
int i;
IOReturn res;
res = IOFWAsyncCommand::reinit(devAddress, NULL, completion, refcon, failOnReset);
if(res != kIOReturnSuccess)
return res;
for(i=0; i<size; i++) {
fInputVals[i] = cmpVal[i];
fInputVals[size+i] = newVal[i];
}
fSize = 8*size;
return res;
}
IOReturn IOFWCompareAndSwapCommand::reinit(UInt32 generation, FWAddress devAddress,
const UInt32 *cmpVal, const UInt32 *newVal, int size,
FWDeviceCallback completion, void *refcon)
{
int i;
IOReturn res;
res = IOFWAsyncCommand::reinit(generation, devAddress, NULL, completion, refcon);
if(res != kIOReturnSuccess)
return res;
for(i=0; i<size; i++) {
fInputVals[i] = cmpVal[i];
fInputVals[size+i] = newVal[i];
}
fSize = 8*size;
return res;
}
IOReturn IOFWCompareAndSwapCommand::execute()
{
IOReturn result;
fStatus = kIOReturnBusy;
if(!fFailOnReset) {
fDevice->getNodeIDGeneration(fGeneration, fNodeID);
}
fTrans = fControl->allocTrans(this);
if(fTrans) {
result = fControl->asyncLock(fGeneration, fNodeID, fAddressHi, fAddressLo, fSpeed,
fTrans->fTCode, kFWExtendedTCodeCompareSwap,
fInputVals, fSize, this);
}
else {
IOLog("IOFWCompareAndSwapCommand::execute: Out of tcodes?");
result = kIOReturnInternalError;
}
if(result != kIOReturnSuccess)
complete(result);
else
fBytesTransferred = fSize ;
return (fStatus);
}
bool IOFWCompareAndSwapCommand::locked(UInt32 *oldVal)
{
int i;
bool ret = true;
for(i = 0; i<fSize/8; i++) {
ret = ret && (fInputVals[i] == fOldVal[i]);
oldVal[i] = fOldVal[i];
}
return ret;
}