IOFireWireAVCCommand.cpp [plain text]
#include <IOKit/avc/IOFireWireAVCCommand.h>
#include <IOKit/avc/IOFireWireAVCConsts.h>
#include <IOKit/firewire/IOFireWireNub.h>
#include <IOKit/firewire/IOFireWireController.h>
#include <IOKit/IOSyncer.h>
#define kInterimTimeout 10000000
class IOFireWireAVCCommandInGen : public IOFireWireAVCCommand
{
OSDeclareDefaultStructors(IOFireWireAVCCommandInGen)
protected:
UInt32 fDummy;
virtual IOReturn complete(IOReturn status);
public:
virtual bool init(IOFireWireNub *device, UInt32 generation, const UInt8 * command, UInt32 cmdLen,
UInt8 * response, UInt32 * responseLen);
virtual IOReturn reinit(IOFireWireNub *device, UInt32 generation, const UInt8 * command, UInt32 cmdLen,
UInt8 * response, UInt32 * responseLen);
private:
OSMetaClassDeclareReservedUnused(IOFireWireAVCCommandInGen, 0);
OSMetaClassDeclareReservedUnused(IOFireWireAVCCommandInGen, 1);
OSMetaClassDeclareReservedUnused(IOFireWireAVCCommandInGen, 2);
OSMetaClassDeclareReservedUnused(IOFireWireAVCCommandInGen, 3);
};
OSDefineMetaClassAndStructors(IOFireWireAVCCommand, IOFWCommand)
OSMetaClassDefineReservedUnused(IOFireWireAVCCommand, 1);
OSMetaClassDefineReservedUnused(IOFireWireAVCCommand, 2);
OSMetaClassDefineReservedUnused(IOFireWireAVCCommand, 3);
void IOFireWireAVCCommand::writeDone(void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd)
{
IOFireWireAVCCommand *me = (IOFireWireAVCCommand *)refcon;
if(status == kIOReturnSuccess) {
if(device)
device->getNodeIDGeneration(me->fWriteGen, me->fWriteNodeID);
me->fTimeout = 250000;
me->updateTimer();
}
else {
IOLog("Write for %p done, status %x\n", refcon, status);
me->complete(status);
}
}
UInt32 IOFireWireAVCCommand::handleResponse(UInt16 nodeID, UInt32 len, const void *buf)
{
const UInt8 *p;
UInt32 i;
UInt32 res = kFWResponseAddressError;
if(fTimeout && nodeID == fWriteNodeID) {
p = (const UInt8 *)buf;
if(p[kAVCCommandResponse] == kAVCInterimStatus) {
fTimeout = kInterimTimeout; updateTimer();
}
else {
if(len > *fResponseLen)
len = *fResponseLen;
for (i = 0 ; i < len ; i++)
fResponse[i] = *p++;
*fResponseLen = len;
fTimeout = 0;
complete(kIOReturnSuccess);
}
res = kFWResponseComplete;
}
else {
IOLog("%p: ------ Write not for me ----------\n", this);
IOLog("nodeID: %d-%d\n", nodeID, fWriteNodeID);
IOLog("Data: %x len %d\n", (unsigned int) *(const UInt32 *)buf, (int)len);
}
return res;
}
void IOFireWireAVCCommand::free()
{
if (fWriteCmd) {
fWriteCmd->release();
}
if(fMem)
fMem->release();
IOFWCommand::free();
}
IOReturn IOFireWireAVCCommand::complete(IOReturn state)
{
if(state == kIOFireWireBusReset && fWriteNodeID == kFWBadNodeID)
state = kIOReturnOffline;
state = IOFWCommand::complete(state);
if( (state == kIOReturnTimeout && fTimeout != 0 && fCurRetries--) ||
(state == kIOFireWireBusReset)) {
FWAddress addr;
addr.addressHi = kCSRRegisterSpaceBaseAddressHi;
addr.addressLo = kFCPCommandAddress;
if(fMem)
((IOFWWriteCommand *)fWriteCmd)->reinit(addr, fMem, writeDone, this);
else
((IOFWWriteQuadCommand *)fWriteCmd)->reinit(addr,(UInt32 *)fCommand, fCmdLen/4, writeDone, this);
fTimeout = 0;
return fStatus = startExecution();
}
if(fSync)
fSyncWakeup->signal(state);
return state;
}
IOReturn IOFireWireAVCCommand::execute()
{
fStatus = kIOReturnBusy;
fWriteCmd->submit();
return fStatus;
}
IOReturn IOFireWireAVCCommand::resetInterimTimeout()
{
fControl->closeGate();
if(fTimeout == kInterimTimeout && fStatus == kIOReturnBusy)
updateTimer();
fControl->openGate();
return kIOReturnSuccess;
}
bool IOFireWireAVCCommand::init(IOFireWireNub *device, const UInt8 * command, UInt32 cmdLen,
UInt8 * response, UInt32 * responseLen)
{
FWAddress addr;
addr.addressHi = kCSRRegisterSpaceBaseAddressHi;
addr.addressLo = kFCPCommandAddress;
IOFWCommand::initWithController(device->getController());
fTimeout = 0;
fSync = true;
fCancelOnReset = true;
fResponse = response;
fResponseLen = responseLen;
fWriteNodeID = kFWBadNodeID;
fMaxRetries = 4;
fCurRetries = fMaxRetries;
fCmdLen = cmdLen;
if(cmdLen == 4 || cmdLen == 8) {
fMem = NULL;
fCommand = command;
fWriteCmd = device->createWriteQuadCommand(addr,(UInt32 *)command, cmdLen/4, writeDone, this);
if(!fWriteCmd) {
return false;
}
}
else {
fCommand = NULL;
fMem = IOMemoryDescriptor::withAddress((void *)command, cmdLen,
kIODirectionOutIn);
if(!fMem) {
return false;
}
IOReturn err = fMem->prepare();
if( err != kIOReturnSuccess )
{
fMem->release();
return false;
}
fWriteCmd = device->createWriteCommand(addr, fMem, writeDone, this);
if(!fWriteCmd) {
return false;
}
}
return true;
}
IOReturn IOFireWireAVCCommand::reinit(IOFireWireNub *device, const UInt8 * command, UInt32 cmdLen,
UInt8 * response, UInt32 * responseLen)
{
if(Busy())
return fStatus;
if(fMem) {
fMem->release();
fMem = NULL;
}
if(fWriteCmd) {
fWriteCmd->release();
fWriteCmd = NULL;
}
if(init(device, command, cmdLen, response, responseLen))
return kIOReturnSuccess;
else
return kIOReturnNoMemory;
}
IOFireWireAVCCommand *
IOFireWireAVCCommand::withNub(IOFireWireNub *device, const UInt8 * command, UInt32 cmdLen,
UInt8 * response, UInt32 * responseLen)
{
IOFireWireAVCCommand *me = new IOFireWireAVCCommand;
if(me) {
if(!me->init(device, command, cmdLen, response, responseLen)) {
me->release();
me = NULL;
}
}
return me;
}
IOFireWireAVCCommand *
IOFireWireAVCCommand::withNub(IOFireWireNub *device, UInt32 generation,
const UInt8 * command, UInt32 cmdLen, UInt8 * response, UInt32 * responseLen)
{
IOFireWireAVCCommandInGen *me = new IOFireWireAVCCommandInGen;
if(me) {
if(!me->init(device, generation, command, cmdLen, response, responseLen)) {
me->release();
me = NULL;
}
}
return me;
}
OSDefineMetaClassAndStructors(IOFireWireAVCCommandInGen, IOFireWireAVCCommand)
OSMetaClassDefineReservedUnused(IOFireWireAVCCommandInGen, 0);
OSMetaClassDefineReservedUnused(IOFireWireAVCCommandInGen, 1);
OSMetaClassDefineReservedUnused(IOFireWireAVCCommandInGen, 2);
OSMetaClassDefineReservedUnused(IOFireWireAVCCommandInGen, 3);
IOReturn IOFireWireAVCCommandInGen::complete(IOReturn state)
{
state = IOFWCommand::complete(state);
if(state == kIOReturnTimeout && fTimeout != 0 && fCurRetries--) {
FWAddress addr;
addr.nodeID = fWriteNodeID;
addr.addressHi = kCSRRegisterSpaceBaseAddressHi;
addr.addressLo = kFCPCommandAddress;
if(fMem)
((IOFWWriteCommand *)fWriteCmd)->reinit(fWriteGen, addr, fMem, writeDone, this);
else
((IOFWWriteQuadCommand *)fWriteCmd)->reinit(fWriteGen, addr,
(UInt32 *)fCommand, fCmdLen/4, writeDone, this);
fTimeout = 0;
return fStatus = startExecution();
}
if(fSync)
fSyncWakeup->signal(state);
return state;
}
bool IOFireWireAVCCommandInGen::init(IOFireWireNub *device, UInt32 generation,
const UInt8 * command, UInt32 cmdLen, UInt8 * response, UInt32 * responseLen)
{
FWAddress addr;
UInt32 dummyGen;
IOFireWireController *control;
device->getNodeIDGeneration(dummyGen, fWriteNodeID);
fWriteGen = generation;
addr.nodeID = fWriteNodeID;
addr.addressHi = kCSRRegisterSpaceBaseAddressHi;
addr.addressLo = kFCPCommandAddress;
control = device->getController();
IOFWCommand::initWithController(control);
fTimeout = 0;
fSync = true;
fCancelOnReset = true;
fResponse = response;
fResponseLen = responseLen;
fMaxRetries = 4;
fCurRetries = fMaxRetries;
fCmdLen = cmdLen;
if(cmdLen == 4 || cmdLen == 8) {
fMem = NULL;
fCommand = command;
fWriteCmd = new IOFWWriteQuadCommand;
if(!fWriteCmd) {
return false;
}
((IOFWWriteQuadCommand *)fWriteCmd)->initAll(control, generation, addr,
(UInt32 *)command, cmdLen/4, writeDone, this);
}
else {
fCommand = NULL;
fMem = IOMemoryDescriptor::withAddress((void *)command, cmdLen,
kIODirectionOutIn);
if(!fMem) {
return false;
}
IOReturn err = fMem->prepare();
if( err != kIOReturnSuccess )
{
fMem->release();
return false;
}
fWriteCmd = new IOFWWriteCommand;
if(!fWriteCmd) {
return false;
}
((IOFWWriteCommand *)fWriteCmd)->initAll(control, generation, addr, fMem, writeDone, this);
}
return true;
}
IOReturn IOFireWireAVCCommandInGen::reinit(IOFireWireNub *device, UInt32 generation,
const UInt8 * command, UInt32 cmdLen, UInt8 * response, UInt32 * responseLen)
{
if(Busy())
return fStatus;
if(fMem) {
fMem->release();
fMem = NULL;
}
if(fWriteCmd) {
fWriteCmd->release();
fWriteCmd = NULL;
}
if(init(device, generation, command, cmdLen, response, responseLen))
return kIOReturnSuccess;
else
return kIOReturnNoMemory;
}