#include <IOKit/firewire/IOFWCommand.h>
#include <IOKit/firewire/IOFireWireController.h>
#include <IOKit/firewire/IOFireWireNub.h>
#include <IOKit/firewire/IOLocalConfigDirectory.h>
#include <IOKit/firewire/IOFireWireLink.h>
#include <IOKit/assert.h>
#include <IOKit/IOSyncer.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOCommand.h>
OSDefineMetaClass( IOFWCommand, IOCommand )
OSDefineAbstractStructors(IOFWCommand, IOCommand)
OSMetaClassDefineReservedUnused(IOFWCommand, 0);
OSMetaClassDefineReservedUnused(IOFWCommand, 1);
#pragma mark -
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;
}
retain();
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();
#if 0
if (res) IOLog("%s %u: fSyncWakeup->wait returned %x\n", __FILE__, __LINE__, res) ;
#endif
}
else
{
fSyncWakeup->release();
fSyncWakeup = NULL;
}
}
fControl->closeGate();
fControl->fFWIM->flushWaitingPackets();
fControl->openGate();
release();
return res;
}
IOReturn IOFWCommand::startExecution()
{
updateTimer();
return execute();
}
IOReturn IOFWCommand::complete(IOReturn status)
{
removeFromQ();
return fStatus = status;
}
IOReturn IOFWCommand::cancel(IOReturn reason)
{
IOReturn result = kIOReturnSuccess;
retain();
fControl->closeGate();
result = complete(reason);
fControl->openGate();
release();
return result;
}
#pragma mark -
void IOFWCommand::setHead( IOFWCmdQ &queue )
{
IOFWCommand *oldHead;
assert(fQueue == NULL);
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;
assert(fQueue == NULL);
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);
}
}
}
void IOFWCommand::updateTimer()
{
if(fTimeout)
{
AbsoluteTime delta;
clock_interval_to_absolutetime_interval(fTimeout, kMicrosecondScale, &delta);
clock_get_uptime(&fDeadline);
ADD_ABSOLUTETIME(&fDeadline, &delta);
if(fQueue)
{
IOFWCommand *oldHead = fQueue->fHead;
IOFWCommand *next;
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);
}
}
else
{
IOFWCommand *prev;
IOFWCmdQ &timeoutQ = fControl->getTimeoutQ();
prev = timeoutQ.fTail;
while(prev)
{
if(CMP_ABSOLUTETIME(&prev->getDeadline(), &fDeadline) != 1)
break; prev = prev->getPrevious();
}
if(!prev)
{
setHead(timeoutQ);
}
else
{
insertAfter(*prev);
#if 0
{
AbsoluteTime now, dead;
clock_get_uptime(&now);
IOLog("%s: insertAfter %s, time is %lx:%lx\n",
getMetaClass()->getClassName(), prev->getMetaClass()->getClassName(), now.hi, now.lo);
{
IOFWCommand *t = timeoutQ.fHead;
while(t)
{
AbsoluteTime d = t->getDeadline();
IOLog("%s:%p deadline %lx:%lx\n",
t->getMetaClass()->getClassName(), t, d.hi, d.lo);
t = t->getNext();
}
}
}
#endif
}
}
}
}