IOFireWireAVCTargetSpace.cpp [plain text]
#include <IOKit/IOLib.h>
#include <IOKit/firewire/IOFireWireController.h>
#include <IOKit/firewire/IOLocalConfigDirectory.h>
#include <IOKit/avc/IOFireWireAVCConsts.h>
#include <IOKit/avc/IOFireWireAVCTargetSpace.h>
#define AVCTARGETMUTEX_LOCK fController->closeGate()
#define AVCTARGETMUTEX_UNLOCK fController->openGate()
static void AVCTargetSendAVCResponseComplete(void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd);
OSDefineMetaClassAndStructors(AVCCommandHandlerInfo, OSObject)
OSDefineMetaClassAndStructors(AVCSubunitInfo, OSObject)
OSDefineMetaClassAndStructors(UCInfo, OSObject)
OSDefineMetaClassAndStructors(AVCConnectionRecord, OSObject)
AVCSubunitInfo *AVCSubunitInfo::create()
{
AVCSubunitInfo * subUnitInfo;
subUnitInfo = new AVCSubunitInfo;
if( subUnitInfo != NULL && !subUnitInfo->init())
{
subUnitInfo->release();
subUnitInfo = NULL;
}
return subUnitInfo;
}
bool AVCSubunitInfo::init()
{
bool success = true;
if( !OSObject::init() )
success = false;
if( success )
{
}
return success;
}
void AVCSubunitInfo::free()
{
if (sourcePlugRecords)
delete[] sourcePlugRecords;
if (destPlugRecords)
delete[] destPlugRecords;
OSObject::free();
}
OSDefineMetaClassAndStructors(IOFireWireAVCTargetSpace, IOFWPseudoAddressSpace)
OSMetaClassDefineReservedUnused(IOFireWireAVCTargetSpace, 0);
OSMetaClassDefineReservedUnused(IOFireWireAVCTargetSpace, 1);
OSMetaClassDefineReservedUnused(IOFireWireAVCTargetSpace, 2);
OSMetaClassDefineReservedUnused(IOFireWireAVCTargetSpace, 3);
void AVCTargetSendAVCResponseComplete(void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd)
{
IOBufferMemoryDescriptor *pBufMemDesc = (IOBufferMemoryDescriptor*) refcon;
if(fwCmd)
fwCmd->release();
if(pBufMemDesc)
pBufMemDesc->release();
}
bool IOFireWireAVCTargetSpace::init(IOFireWireController *controller)
{
if(!IOFWPseudoAddressSpace::initFixed(controller,
FWAddress(kCSRRegisterSpaceBaseAddressHi, kFCPCommandAddress),
512, NULL, NULL, this))
return false;
fController = controller;
return true;
}
IOFireWireAVCTargetSpace * IOFireWireAVCTargetSpace::getAVCTargetSpace(IOFireWireController *controller)
{
IOFWAddressSpace *existing;
IOFireWireAVCTargetSpace *space;
existing = controller->getAddressSpace(FWAddress(kCSRRegisterSpaceBaseAddressHi, kFCPCommandAddress));
if(existing && OSDynamicCast(IOFireWireAVCTargetSpace, existing)) {
existing->retain();
return OSDynamicCast(IOFireWireAVCTargetSpace, existing);
}
space = new IOFireWireAVCTargetSpace;
if(space) {
if(!space->init(controller)) {
space->release();
space = NULL;
}
}
return space;
}
UInt32 IOFireWireAVCTargetSpace::doWrite(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
const void *buf, IOFWRequestRefCon refcon)
{
UInt32 generation = fController->getGeneration();
UInt8 cts;
UInt8 *pBuf = (UInt8*) buf;
if(addr.addressHi != kCSRRegisterSpaceBaseAddressHi)
return kFWResponseAddressError;
if(addr.addressLo != kFCPCommandAddress)
return kFWResponseAddressError;
cts = ((pBuf[0] & 0xF0) >> 4);
if (cts != 0)
return kFWResponseAddressError;
findAVCRequestHandler(NULL,generation,nodeID,speed,0xFFFFFFFF,(const char *) pBuf,len);
return kFWResponseComplete;
}
IOReturn IOFireWireAVCTargetSpace::findAVCRequestHandler(IOFireWireAVCProtocolUserClient *userClient,
UInt32 generation,
UInt16 nodeID,
IOFWSpeed speed,
UInt32 handlerSearchIndex,
const char *pCmdBuf,
UInt32 cmdLen)
{
UInt32 currentGeneration = fController->getGeneration();
UInt8 subUnit;
UInt8 opCode;
UInt8 *pResponse;
bool handled = false;
IOBufferMemoryDescriptor *pBufMemDesc = NULL;
int i;
int firstIndex;
if( (pCmdBuf == NULL) || (cmdLen < 3) )
{
return kIOReturnBadArgument;
}
subUnit = pCmdBuf[1];
opCode = pCmdBuf[2];
if (currentGeneration != generation)
return kIOFireWireBusReset;
AVCTARGETMUTEX_LOCK;
if (handlerSearchIndex == 0xFFFFFFFF)
firstIndex = (fCommandHandlers->getCount()-1);
else
{
firstIndex = handlerSearchIndex - 1;
if (firstIndex >= (int) fCommandHandlers->getCount())
firstIndex = (fCommandHandlers->getCount()-1);
}
for (i=firstIndex;i>=0;i--)
{
AVCCommandHandlerInfo *cmdInfo;
cmdInfo = (AVCCommandHandlerInfo*) fCommandHandlers->getObject(i);
if ( ((cmdInfo->subUnitTypeAndID == subUnit) && (cmdInfo->opCode == opCode)) ||
((cmdInfo->subUnitTypeAndID == subUnit) && (cmdInfo->opCode == kAVCAllOpcodes)) ||
((cmdInfo->subUnitTypeAndID == kAVCAllSubunitsAndUnit) && (cmdInfo->opCode == opCode)) ||
((cmdInfo->subUnitTypeAndID == kAVCAllSubunitsAndUnit) && (cmdInfo->opCode == kAVCAllOpcodes)))
{
cmdInfo->callBack(cmdInfo,generation,nodeID,pCmdBuf,cmdLen,speed,i);
handled = true;
break;
}
}
if ((!handled) && (subUnit == 0xFF))
{
switch (opCode)
{
case kAVCUnitInfoOpcode:
if (handleUnitInfoCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
handled = true;
break;
case kAVCSubunitInfoOpcode:
if (handleSubUnitInfoCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
handled = true;
break;
case kAVCPowerOpcode:
if (handlePowerCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
handled = true;
break;
case kAVCConnectOpcode:
if (handleConnectCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
handled = true;
break;
case kAVCDisconnectOpcode:
if (handleDisconnectCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
handled = true;
break;
case kAVCInputPlugSignalFormatOpcode:
if (handleInputPlugSignalFormatCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
handled = true;
break;
case kAVCOutputPlugSignalFormatOpcode:
if (handleOutputPlugSignalFormatCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
handled = true;
break;
case kAVCConnectionsOpcode:
if (handleConnectionsCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
handled = true;
break;
case kAVCSignalSourceOpcode:
if (handleSignalSourceCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
handled = true;
break;
default:
break;
};
}
if ((!handled) && (opCode == kAVCPlugInfoOpcode))
{
if (handlePlugInfoCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
handled = true;
}
if (!handled)
{
pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(cmdLen, kIODirectionOutIn);
if(!pBufMemDesc)
{
AVCTARGETMUTEX_UNLOCK;
return kFWResponseDataError;
}
pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
bcopy(pCmdBuf,pResponse,cmdLen);
pResponse[kAVCCommandResponse] = kAVCNotImplementedStatus; targetSendAVCResponse(generation, nodeID, pBufMemDesc, cmdLen);
}
AVCTARGETMUTEX_UNLOCK;
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCTargetSpace::activateWithUserClient(IOFireWireAVCProtocolUserClient *userClient)
{
IOReturn res = kIOReturnSuccess;
UCInfo *uc;
UInt32 i;
if(!fActivations++)
{
fUserClients = OSArray::withCapacity(1);
fCommandHandlers = OSArray::withCapacity(1);
fSubunits = OSArray::withCapacity(1);
fConnectionRecords = OSArray::withCapacity(1);
fUnitPlugs.numIsochInPlugs = kAVCMaxNumPlugs;
fUnitPlugs.numIsochOutPlugs = kAVCMaxNumPlugs;
fUnitPlugs.numExternalInPlugs = kAVCMaxNumPlugs;
fUnitPlugs.numExternalOutPlugs = kAVCMaxNumPlugs;
for (i=0;i<kAVCMaxNumPlugs;i++)
{
fUnitPlugs.isochInPlugRecord[i].connectionCount = 0;
fUnitPlugs.isochOutPlugRecord[i].connectionCount = 0;
fUnitPlugs.externalInPlugRecord[i].connectionCount = 0;
fUnitPlugs.externalOutPlugRecord[i].connectionCount = 0;
}
#if 0
fLock = IORecursiveLockAlloc();
#endif
res = IOFWAddressSpace::activate();
}
uc = new UCInfo;
if(!uc)
return kIOReturnNoMemory;
uc->fUserClient = userClient;
if(!fUserClients->setObject(uc))
return kIOReturnNoMemory;
uc->release();
return res;
}
void IOFireWireAVCTargetSpace::deactivateWithUserClient(IOFireWireAVCProtocolUserClient *userClient)
{
IOReturn res = kIOReturnSuccess;
int i,j;
UCInfo *uc;
AVCConnectionRecord *connection;
AVCSubunitInfo *subUnitInfo;
AVCSubunitInfo *connectedSubUnitInfo;
bool avcResourcesFreed = false;
UInt32 subunitTypeAndID;
AVCTARGETMUTEX_LOCK;
for (i=(fCommandHandlers->getCount()-1);i>=0;i--)
{
AVCCommandHandlerInfo *cmdInfo;
cmdInfo = (AVCCommandHandlerInfo*) fCommandHandlers->getObject(i);
if(cmdInfo->userClient == userClient)
{
fCommandHandlers->removeObject(i);
}
}
for (i=(fSubunits->getCount()-1);i>=0;i--)
{
subUnitInfo = (AVCSubunitInfo*) fSubunits->getObject(i);
if(subUnitInfo->userClient == userClient)
{
subunitTypeAndID = subUnitInfo->subunitTypeAndID;
for (j=(fConnectionRecords->getCount()-1);j>=0;j--)
{
connection = (AVCConnectionRecord*) fConnectionRecords->getObject(j);
if ((connection->sourceSubunitTypeAndID == subunitTypeAndID) ||
(connection->destSubunitTypeAndID == subunitTypeAndID))
{
if (connection->sourceSubunitTypeAndID != subunitTypeAndID)
{
switch (connection->sourcePlugType)
{
case IOFWAVCPlugIsochInputType:
fUnitPlugs.isochInPlugRecord[connection->sourcePlugNum].connectionCount--;
break;
case IOFWAVCPlugExternalInputType:
fUnitPlugs.externalInPlugRecord[connection->sourcePlugNum - 0x80].connectionCount--;
break;
case IOFWAVCPlugSubunitSourceType:
connectedSubUnitInfo = getSubunitInfo(connection->sourceSubunitTypeAndID);
if (connectedSubUnitInfo)
{
connectedSubUnitInfo->sourcePlugRecords[connection->sourcePlugNum].connectionCount--;
if (connectedSubUnitInfo->userClient != userClient)
connectedSubUnitInfo->callBack(connectedSubUnitInfo,
kIOFWAVCSubunitPlugMsgDisconnected,
connection->sourcePlugType,
connection->sourcePlugNum,
((connection->destSubunitTypeAndID << 16) + (connection->destPlugType << 8) + connection->destPlugNum),
0,0);
}
break;
default:
break;
};
}
if (connection->destSubunitTypeAndID != subunitTypeAndID)
{
switch (connection->destPlugType)
{
case IOFWAVCPlugIsochOutputType:
fUnitPlugs.isochOutPlugRecord[connection->destPlugNum].connectionCount--;
break;
case IOFWAVCPlugExternalOutputType:
fUnitPlugs.externalOutPlugRecord[connection->destPlugNum - 0x80].connectionCount--;
break;
case IOFWAVCPlugSubunitDestType:
connectedSubUnitInfo = getSubunitInfo(connection->destSubunitTypeAndID);
if (connectedSubUnitInfo)
{
connectedSubUnitInfo->destPlugRecords[connection->destPlugNum].connectionCount--;
if (connectedSubUnitInfo->userClient != userClient)
connectedSubUnitInfo->callBack(connectedSubUnitInfo,
kIOFWAVCSubunitPlugMsgDisconnected,
connection->destPlugType,
connection->destPlugNum,
((connection->sourceSubunitTypeAndID << 16) + (connection->sourcePlugType << 8) + connection->sourcePlugNum),
0,0);
}
break;
default:
break;
};
}
fConnectionRecords->removeObject(j);
}
}
fSubunits->removeObject(i);
avcResourcesFreed = true;
}
}
for (i=(fUserClients->getCount()-1);i>=0;i--)
{
uc = (UCInfo *)fUserClients->getObject(i);
if(uc->fUserClient == userClient)
{
fUserClients->removeObject(i);
}
}
fActivations -= 1;
if (fActivations == 1)
uc = (UCInfo *)fUserClients->getObject(0);
AVCTARGETMUTEX_UNLOCK;
if ((fActivations == 0) || ((fActivations == 1) && (uc->fUserClient == (IOFireWireAVCProtocolUserClient*)0xFFFFFFFF)))
{
if (fAVCLocalConfigDirectory)
{
res = fController->RemoveUnitDirectory(fAVCLocalConfigDirectory) ;
fAVCLocalConfigDirectory->release();
fAVCLocalConfigDirectory = NULL;
}
}
else if (avcResourcesFreed == true)
fController->resetBus();
if (fActivations == 0)
{
#if 0
if (fLock)
IORecursiveLockFree(fLock);
#endif
fUserClients->release();
fCommandHandlers->release();
fSubunits->release();
fConnectionRecords->release();
IOFWAddressSpace::deactivate();
}
}
IOReturn IOFireWireAVCTargetSpace::publishAVCUnitDirectory(void)
{
IOReturn res = kIOReturnSuccess;
AVCTARGETMUTEX_LOCK;
if (!fAVCLocalConfigDirectory)
{
fAVCLocalConfigDirectory = IOLocalConfigDirectory::create();
if (!fAVCLocalConfigDirectory)
{
res = kIOReturnError;
}
AVCTARGETMUTEX_UNLOCK;
if(res == kIOReturnSuccess)
res = fAVCLocalConfigDirectory->addEntry(0x12,0xA02D) ;
if(res == kIOReturnSuccess)
res = fAVCLocalConfigDirectory->addEntry(0x13,0x10001) ;
if(res == kIOReturnSuccess)
res = fController->AddUnitDirectory(fAVCLocalConfigDirectory) ;
}
else
{
AVCTARGETMUTEX_UNLOCK;
fController->resetBus();
}
return res;
}
IOReturn
IOFireWireAVCTargetSpace::targetSendAVCResponse(UInt32 generation, UInt16 nodeID, IOBufferMemoryDescriptor *pBufMemDesc, UInt32 size)
{
IOFWWriteCommand *cmd = NULL;
IOReturn status;
do {
cmd = new IOFWWriteCommand;
if(!cmd) {
status = kIOReturnNoMemory;
break;
}
if(!cmd->initAll(fController, generation,
FWAddress(kCSRRegisterSpaceBaseAddressHi, kFCPResponseAddress, nodeID),
pBufMemDesc, AVCTargetSendAVCResponseComplete, pBufMemDesc)) {
status = kIOReturnNoMemory;
break;
}
status = cmd->submit(true);
} while (false);
return status;
}
IOReturn IOFireWireAVCTargetSpace::installAVCCommandHandler(IOFireWireAVCProtocolUserClient *userClient,
IOFireWireAVCTargetCommandHandlerCallback callBack,
OSAsyncReference64 asyncRef,
UInt32 subUnitTypeAndID,
UInt32 opCode,
uint64_t userCallBack,
uint64_t userRefCon)
{
IOReturn res = kIOReturnSuccess;
AVCCommandHandlerInfo *cmdInfo;
cmdInfo = new AVCCommandHandlerInfo;
if(!cmdInfo)
return kIOReturnNoMemory;
cmdInfo->userClient = userClient;
cmdInfo->callBack = callBack;
bcopy(asyncRef, cmdInfo->asyncRef, sizeof(OSAsyncReference64));
cmdInfo->subUnitTypeAndID = subUnitTypeAndID;
cmdInfo->opCode = opCode;
cmdInfo->userCallBack = userCallBack;
cmdInfo->userRefCon = userRefCon;
AVCTARGETMUTEX_LOCK;
if(!fCommandHandlers->setObject(cmdInfo))
res = kIOReturnNoMemory;
else
{
}
AVCTARGETMUTEX_UNLOCK;
cmdInfo->release();
return res;
}
IOReturn IOFireWireAVCTargetSpace::addSubunit(IOFireWireAVCProtocolUserClient *userClient,
IOFireWireAVCSubunitPlugHandlerCallback callBack,
OSAsyncReference64 asyncRef,
UInt32 subunitType,
UInt32 numSourcePlugs,
UInt32 numDestPlugs,
uint64_t userCallBack,
uint64_t userRefCon,
UInt32 *subUnitID)
{
IOReturn res = kIOReturnSuccess;
AVCSubunitInfo *subUnitInfo;
UInt32 count;
UInt32 i;
AVCTARGETMUTEX_LOCK;
if (fSubunits->getCount() >= 32)
res = kIOReturnNoResources;
count = subUnitOfTypeCount(subunitType);
if (count >= 4)
res = kIOReturnNoResources;
if (res == kIOReturnSuccess)
{
subUnitInfo = AVCSubunitInfo::create();
if(!subUnitInfo)
res = kIOReturnNoMemory;
else
{
subUnitInfo->userClient = userClient;
subUnitInfo->callBack = callBack;
bcopy(asyncRef, subUnitInfo->asyncRef, sizeof(OSAsyncReference64));
subUnitInfo->numSourcePlugs = numSourcePlugs;
subUnitInfo->numDestPlugs = numDestPlugs;
subUnitInfo->userCallBack = userCallBack;
subUnitInfo->userRefCon = userRefCon;
if (numSourcePlugs)
{
subUnitInfo->sourcePlugRecords = new AVCSubunitPlugRecord[numSourcePlugs];
for (i=0;i<numSourcePlugs;i++)
{
subUnitInfo->sourcePlugRecords[i].connectionCount = 0;
subUnitInfo->sourcePlugRecords[i].plugSignalFormat = kAVCPlugSignalFormatNTSCDV;
}
}
else
subUnitInfo->sourcePlugRecords = NULL;
if (numDestPlugs)
{
subUnitInfo->destPlugRecords = new AVCSubunitPlugRecord[numDestPlugs];
for (i=0;i<numDestPlugs;i++)
{
subUnitInfo->destPlugRecords[i].connectionCount = 0;
subUnitInfo->destPlugRecords[i].plugSignalFormat = kAVCPlugSignalFormatNTSCDV;
}
}
else
subUnitInfo->destPlugRecords = NULL;
subUnitInfo->subunitTypeAndID = (subunitType << 3) + count;
if(!fSubunits->setObject(subUnitInfo))
res = kIOReturnNoMemory;
else
{
}
}
*subUnitID = subUnitInfo->subunitTypeAndID;
subUnitInfo->release();
}
AVCTARGETMUTEX_UNLOCK;
return res;
}
IOReturn IOFireWireAVCTargetSpace::setSubunitPlugSignalFormat(IOFireWireAVCProtocolUserClient *userClient,
UInt32 subunitTypeAndID,
IOFWAVCPlugTypes plugType,
UInt32 plugNum,
UInt32 signalFormat)
{
IOReturn res = kIOReturnBadArgument; AVCSubunitInfo *subUnitInfo;
AVCTARGETMUTEX_LOCK;
subUnitInfo = getSubunitInfo(subunitTypeAndID);
if (subUnitInfo)
res = kIOReturnSuccess;
if ((res == kIOReturnSuccess) && (userClient != subUnitInfo->userClient))
res = kIOReturnBadArgument;
if (res == kIOReturnSuccess)
{
if ((plugType == IOFWAVCPlugSubunitSourceType) && (plugNum < subUnitInfo->numSourcePlugs))
subUnitInfo->sourcePlugRecords[plugNum].plugSignalFormat = signalFormat;
else if ((plugType == IOFWAVCPlugSubunitDestType) && (plugNum < subUnitInfo->numDestPlugs))
subUnitInfo->destPlugRecords[plugNum].plugSignalFormat = signalFormat;
else
res = kIOReturnBadArgument;
}
AVCTARGETMUTEX_UNLOCK;
return res;
}
IOReturn IOFireWireAVCTargetSpace::getSubunitPlugSignalFormat(IOFireWireAVCProtocolUserClient *userClient,
UInt32 subunitTypeAndID,
IOFWAVCPlugTypes plugType,
UInt32 plugNum,
UInt32 *pSignalFormat)
{
IOReturn res = kIOReturnBadArgument; AVCSubunitInfo *subUnitInfo;
AVCTARGETMUTEX_LOCK;
if (subunitTypeAndID == kAVCUnitAddress)
{
res = kIOReturnBadArgument;
}
else
{
subUnitInfo = getSubunitInfo(subunitTypeAndID);
if (subUnitInfo)
res = kIOReturnSuccess;
if (res == kIOReturnSuccess)
{
if ((plugType == IOFWAVCPlugSubunitSourceType) && (plugNum < subUnitInfo->numSourcePlugs))
*pSignalFormat = subUnitInfo->sourcePlugRecords[plugNum].plugSignalFormat;
else if ((plugType == IOFWAVCPlugSubunitDestType) && (plugNum < subUnitInfo->numDestPlugs))
*pSignalFormat = subUnitInfo->destPlugRecords[plugNum].plugSignalFormat;
else
res = kIOReturnBadArgument;
}
}
AVCTARGETMUTEX_UNLOCK;
return res;
}
IOReturn IOFireWireAVCTargetSpace::connectTargetPlugs(IOFireWireAVCProtocolUserClient *userClient,
AVCConnectTargetPlugsInParams *inParams,
AVCConnectTargetPlugsOutParams *outParams)
{
IOReturn res = kIOReturnSuccess;
AVCSubunitInfo *sourceSubUnitInfo = NULL;
AVCSubunitInfo *destSubUnitInfo = NULL;
UInt32 sourcePlugIndex;
UInt32 destPlugIndex;
UInt32 sourcePlugNum;
UInt32 destPlugNum;
int i;
bool found;
bool plugFound;
AVCConnectionRecord *connection;
UInt32 actualPlug;
AVCTARGETMUTEX_LOCK;
for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
{
connection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
if ((inParams->sourceSubunitTypeAndID == connection->sourceSubunitTypeAndID) &&
(inParams->sourcePlugType == connection->sourcePlugType) &&
(inParams->sourcePlugNum == connection->sourcePlugNum) &&
(inParams->destSubunitTypeAndID == connection->destSubunitTypeAndID) &&
(inParams->destPlugType == connection->destPlugType) &&
(inParams->destPlugNum == connection->destPlugNum))
{
if (inParams->lockConnection == true)
connection->lockConnection = true;
if (inParams->permConnection == true)
connection->permConnection = true;
outParams->sourcePlugNum = connection->sourcePlugNum;
outParams->destPlugNum = connection->destPlugNum;
AVCTARGETMUTEX_UNLOCK;
return res;
}
}
if (inParams->sourceSubunitTypeAndID == kAVCUnitAddress)
{
switch (inParams->sourcePlugType)
{
case IOFWAVCPlugIsochInputType:
if (inParams->sourcePlugNum == kAVCAnyAvailableIsochPlug)
{
plugFound = false;
for (i=0;i<kAVCMaxNumPlugs;i++)
{
if (fUnitPlugs.isochInPlugRecord[i].connectionCount == 0)
{
sourcePlugIndex=i;
sourcePlugNum=i;
plugFound = true;
break;
}
}
if (!plugFound)
{
sourcePlugIndex=0;
sourcePlugNum=0;
}
}
else if (inParams->sourcePlugNum < kAVCMaxNumPlugs)
{
sourcePlugIndex = inParams->sourcePlugNum;
sourcePlugNum = sourcePlugIndex;
}
else
res = kIOReturnBadArgument;
break;
case IOFWAVCPlugExternalInputType:
if (inParams->sourcePlugNum == kAVCAnyAvailableExternalPlug)
{
plugFound = false;
for (i=0;i<kAVCMaxNumPlugs;i++)
{
if (fUnitPlugs.externalInPlugRecord[i].connectionCount == 0)
{
sourcePlugIndex=i;
sourcePlugNum= 0x80 + i;
plugFound = true;
break;
}
}
if (!plugFound)
{
sourcePlugIndex=0;
sourcePlugNum = 0x80;
}
}
else if ((inParams->sourcePlugNum >= 0x80) && (inParams->sourcePlugNum < 0x9F))
{
sourcePlugIndex = inParams->sourcePlugNum - 0x80;
sourcePlugNum = inParams->sourcePlugNum;
}
else
res = kIOReturnBadArgument;
break;
default:
res = kIOReturnBadArgument;
break;
};
}
else
{
found = false;
for (i=(fSubunits->getCount()-1);i>=0;i--)
{
sourceSubUnitInfo = (AVCSubunitInfo *) fSubunits->getObject(i);
if (inParams->sourceSubunitTypeAndID == sourceSubUnitInfo->subunitTypeAndID)
{
found = true;
break;
}
}
if (found == false)
res = kIOReturnBadArgument;
if ((res == kIOReturnSuccess) && (userClient != NULL) && (sourceSubUnitInfo->userClient != userClient))
res = kIOReturnBadArgument;
if (res == kIOReturnSuccess)
{
switch (inParams->sourcePlugType)
{
case IOFWAVCPlugSubunitSourceType:
if ((inParams->sourcePlugNum == kAVCAnyAvailableSubunitPlug) && (sourceSubUnitInfo->numSourcePlugs > 0))
{
plugFound = false;
for (i=0;i<(int)sourceSubUnitInfo->numSourcePlugs;i++)
{
if (sourceSubUnitInfo->sourcePlugRecords[i].connectionCount == 0)
{
sourcePlugIndex=i;
sourcePlugNum=i;
plugFound = true;
break;
}
}
if (!plugFound)
{
sourcePlugIndex=0;
sourcePlugNum=0;
}
}
else if (inParams->sourcePlugNum < sourceSubUnitInfo->numSourcePlugs)
{
sourcePlugIndex = inParams->sourcePlugNum;
sourcePlugNum = sourcePlugIndex;
}
else
res = kIOReturnBadArgument;
break;
default:
res = kIOReturnBadArgument;
break;
};
}
}
if (res == kIOReturnSuccess)
{
if (inParams->destSubunitTypeAndID == kAVCUnitAddress)
{
switch (inParams->destPlugType)
{
case IOFWAVCPlugIsochOutputType:
if (inParams->destPlugNum == kAVCAnyAvailableIsochPlug)
{
plugFound = false;
for (i=0;i<kAVCMaxNumPlugs;i++)
{
if (fUnitPlugs.isochOutPlugRecord[i].connectionCount == 0)
{
destPlugIndex=i;
destPlugNum=i;
plugFound = true;
break;
}
}
if (!plugFound)
{
actualPlug = kAVCInvalidPlug;
if (canConnectDestPlug(kAVCUnitAddress,
IOFWAVCPlugIsochOutputType,
&actualPlug))
{
destPlugIndex = actualPlug;
destPlugNum = destPlugIndex;
}
else
res = kIOReturnBadArgument;
}
}
else if (inParams->destPlugNum < kAVCMaxNumPlugs)
{
if (canConnectDestPlug(kAVCUnitAddress,
IOFWAVCPlugIsochOutputType,
&inParams->destPlugNum))
{
destPlugIndex = inParams->destPlugNum;
destPlugNum = destPlugIndex;
}
else
res = kIOReturnBadArgument;
}
else
res = kIOReturnBadArgument;
break;
case IOFWAVCPlugExternalOutputType:
if (inParams->destPlugNum == kAVCAnyAvailableExternalPlug)
{
plugFound = false;
for (i=0;i<kAVCMaxNumPlugs;i++)
{
if (fUnitPlugs.externalOutPlugRecord[i].connectionCount == 0)
{
destPlugIndex=i;
destPlugNum= 0x80 + i;
plugFound = true;
break;
}
}
if (!plugFound)
{
actualPlug = kAVCInvalidPlug;
if (canConnectDestPlug(kAVCUnitAddress,
IOFWAVCPlugExternalOutputType,
&actualPlug))
{
destPlugIndex = actualPlug - 0x80;
destPlugNum = actualPlug;
}
else
res = kIOReturnBadArgument;
}
}
else if ((inParams->destPlugNum >= 0x80) && (inParams->destPlugNum < 0x9F))
{
if (canConnectDestPlug(kAVCUnitAddress,
IOFWAVCPlugExternalOutputType,
&inParams->destPlugNum))
{
destPlugIndex = inParams->destPlugNum - 0x80;
destPlugNum = inParams->destPlugNum;
}
else
res = kIOReturnBadArgument;
}
else
res = kIOReturnBadArgument;
break;
default:
res = kIOReturnBadArgument;
break;
};
}
else
{
found = false;
for (i=(fSubunits->getCount()-1);i>=0;i--)
{
destSubUnitInfo = (AVCSubunitInfo *) fSubunits->getObject(i);
if (inParams->destSubunitTypeAndID == destSubUnitInfo->subunitTypeAndID)
{
found = true;
break;
}
}
if (found == false)
res = kIOReturnBadArgument;
if ((res == kIOReturnSuccess) && (userClient != NULL) && (destSubUnitInfo->userClient != userClient))
res = kIOReturnBadArgument;
if (res == kIOReturnSuccess)
{
switch (inParams->destPlugType)
{
case IOFWAVCPlugSubunitDestType:
if ((inParams->destPlugNum == kAVCAnyAvailableSubunitPlug) && (destSubUnitInfo->numDestPlugs > 0))
{
plugFound = false;
for (i=0;i<(int)destSubUnitInfo->numDestPlugs;i++)
{
if (destSubUnitInfo->destPlugRecords[i].connectionCount == 0)
{
destPlugIndex =i;
destPlugNum =i;
plugFound = true;
break;
}
}
if (!plugFound)
{
actualPlug = kAVCInvalidPlug;
if (canConnectDestPlug(destSubUnitInfo->subunitTypeAndID,
IOFWAVCPlugSubunitDestType,
&actualPlug))
{
destPlugIndex = actualPlug;
destPlugNum = destPlugIndex;
}
else
res = kIOReturnBadArgument;
}
}
else if (inParams->destPlugNum < destSubUnitInfo->numDestPlugs)
{
if (canConnectDestPlug(destSubUnitInfo->subunitTypeAndID,
IOFWAVCPlugSubunitDestType,
&inParams->destPlugNum))
{
destPlugIndex = inParams->destPlugNum;
destPlugNum = destPlugIndex;
}
else
res = kIOReturnBadArgument;
}
else
res = kIOReturnBadArgument;
break;
default:
res = kIOReturnBadArgument;
break;
};
}
}
}
if (res == kIOReturnSuccess)
{
connection = new AVCConnectionRecord;
if(!connection)
res = kIOReturnNoMemory;
if (res == kIOReturnSuccess)
{
connection->sourceSubunitTypeAndID = inParams->sourceSubunitTypeAndID;
connection->sourcePlugType = inParams->sourcePlugType;
connection->sourcePlugNum = sourcePlugNum;
connection->destSubunitTypeAndID = inParams->destSubunitTypeAndID;
connection->destPlugType = inParams->destPlugType;
connection->destPlugNum = destPlugNum;
connection->lockConnection = inParams->lockConnection;
connection->permConnection = inParams->permConnection;
if(!fConnectionRecords->setObject(connection))
res = kIOReturnNoMemory;
connection->release();
if (res == kIOReturnSuccess)
{
switch (inParams->sourcePlugType)
{
case IOFWAVCPlugIsochInputType:
fUnitPlugs.isochInPlugRecord[sourcePlugIndex].connectionCount++;
break;
case IOFWAVCPlugExternalInputType:
fUnitPlugs.externalInPlugRecord[sourcePlugIndex].connectionCount++;
break;
case IOFWAVCPlugSubunitSourceType:
sourceSubUnitInfo->sourcePlugRecords[sourcePlugIndex].connectionCount++;
break;
default:
break;
};
switch (inParams->destPlugType)
{
case IOFWAVCPlugIsochOutputType:
fUnitPlugs.isochOutPlugRecord[destPlugIndex].connectionCount++;
break;
case IOFWAVCPlugExternalOutputType:
fUnitPlugs.externalOutPlugRecord[destPlugIndex].connectionCount++;
break;
case IOFWAVCPlugSubunitDestType:
destSubUnitInfo->destPlugRecords[destPlugIndex].connectionCount++;
break;
default:
break;
};
}
if ((res == kIOReturnSuccess) && (sourceSubUnitInfo))
sourceSubUnitInfo->callBack(sourceSubUnitInfo,
kIOFWAVCSubunitPlugMsgConnected,
inParams->sourcePlugType,
sourcePlugNum,
((inParams->destSubunitTypeAndID << 16) + (inParams->destPlugType << 8) + destPlugNum),
0,0);
if ((res == kIOReturnSuccess) && (destSubUnitInfo))
destSubUnitInfo->callBack(destSubUnitInfo,
kIOFWAVCSubunitPlugMsgConnected,
inParams->destPlugType,
destPlugNum,
((inParams->sourceSubunitTypeAndID << 16) + (inParams->sourcePlugType << 8) + sourcePlugNum),
0,0);
if (res == kIOReturnSuccess)
{
outParams->sourcePlugNum = sourcePlugNum;
outParams->destPlugNum = destPlugNum;
}
}
}
AVCTARGETMUTEX_UNLOCK;
return res;
}
IOReturn IOFireWireAVCTargetSpace::disconnectTargetPlugs(IOFireWireAVCProtocolUserClient *userClient,
UInt32 sourceSubunitTypeAndID,
IOFWAVCPlugTypes sourcePlugType,
UInt32 sourcePlugNum,
UInt32 destSubunitTypeAndID,
IOFWAVCPlugTypes destPlugType,
UInt32 destPlugNum)
{
int i;
AVCConnectionRecord *connection;
AVCSubunitInfo *sourceSubUnitInfo = NULL;
AVCSubunitInfo *destSubUnitInfo = NULL;
bool found = false;
AVCTARGETMUTEX_LOCK;
for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
{
connection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
if ((sourceSubunitTypeAndID == connection->sourceSubunitTypeAndID) &&
(sourcePlugType == connection->sourcePlugType) &&
(sourcePlugNum == connection->sourcePlugNum) &&
(connection->permConnection == false))
{
if (connection->sourceSubunitTypeAndID != kAVCUnitAddress)
sourceSubUnitInfo = getSubunitInfo(connection->sourceSubunitTypeAndID);
if (connection->destSubunitTypeAndID != kAVCUnitAddress)
destSubUnitInfo = getSubunitInfo(connection->destSubunitTypeAndID);
switch (connection->sourcePlugType)
{
case IOFWAVCPlugIsochInputType:
fUnitPlugs.isochInPlugRecord[connection->sourcePlugNum].connectionCount--;
break;
case IOFWAVCPlugExternalInputType:
fUnitPlugs.externalInPlugRecord[connection->sourcePlugNum - 0x80].connectionCount--;
break;
case IOFWAVCPlugSubunitSourceType:
if (sourceSubUnitInfo)
sourceSubUnitInfo->sourcePlugRecords[connection->sourcePlugNum].connectionCount--;
break;
default:
break;
};
switch (connection->destPlugType)
{
case IOFWAVCPlugIsochOutputType:
fUnitPlugs.isochOutPlugRecord[connection->destPlugNum].connectionCount--;
break;
case IOFWAVCPlugExternalOutputType:
fUnitPlugs.externalOutPlugRecord[connection->destPlugNum - 0x80].connectionCount--;
break;
case IOFWAVCPlugSubunitDestType:
if (destSubUnitInfo)
destSubUnitInfo->destPlugRecords[connection->destPlugNum].connectionCount--;
break;
default:
break;
};
if (sourceSubUnitInfo)
sourceSubUnitInfo->callBack(sourceSubUnitInfo,
kIOFWAVCSubunitPlugMsgDisconnected,
connection->sourcePlugType,
connection->sourcePlugNum,
((connection->destSubunitTypeAndID << 16) + (connection->destPlugType << 8) + connection->destPlugNum),
0,0);
if (destSubUnitInfo)
destSubUnitInfo->callBack(destSubUnitInfo,
kIOFWAVCSubunitPlugMsgDisconnected,
connection->destPlugType,
connection->destPlugNum,
((connection->sourceSubunitTypeAndID << 16) + (connection->sourcePlugType << 8) + connection->sourcePlugNum),
0,0);
fConnectionRecords->removeObject(i);
found = true;
}
}
AVCTARGETMUTEX_UNLOCK;
if (found)
return kIOReturnSuccess;
else
return kIOReturnBadArgument;
}
IOReturn IOFireWireAVCTargetSpace::getTargetPlugConnection(IOFireWireAVCProtocolUserClient *userClient,
AVCGetTargetPlugConnectionInParams *inParams,
AVCGetTargetPlugConnectionOutParams *outParams)
{
IOReturn res;
int i;
AVCConnectionRecord *connection;
UInt32 count = 0;
AVCTARGETMUTEX_LOCK;
for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
{
connection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
switch (inParams->plugType)
{
case IOFWAVCPlugSubunitSourceType:
case IOFWAVCPlugIsochOutputType:
case IOFWAVCPlugExternalOutputType:
if ((inParams->subunitTypeAndID == connection->sourceSubunitTypeAndID) &&
(inParams->plugType == connection->sourcePlugType) &&
(inParams->plugNum == connection->sourcePlugNum))
{
outParams->connectedSubunitTypeAndID = connection->destSubunitTypeAndID;
outParams->connectedPlugType = connection->destPlugType;
outParams->connectedPlugNum = connection->destPlugNum;
outParams->lockConnection = connection->lockConnection;
outParams->permConnection = connection->permConnection;
count += 1;
}
break;
case IOFWAVCPlugSubunitDestType:
case IOFWAVCPlugIsochInputType:
case IOFWAVCPlugExternalInputType:
if ((inParams->subunitTypeAndID == connection->destSubunitTypeAndID) &&
(inParams->plugType == connection->destPlugType) &&
(inParams->plugNum == connection->destPlugNum))
{
outParams->connectedSubunitTypeAndID = connection->sourceSubunitTypeAndID;
outParams->connectedPlugType = connection->sourcePlugType;
outParams->connectedPlugNum = connection->sourcePlugNum;
outParams->lockConnection = connection->lockConnection;
outParams->permConnection = connection->permConnection;
count += 1;
}
break;
default:
break;
};
}
if (count == 0)
res = kIOReturnBadArgument;
else
{
res = kIOReturnSuccess;
if (count > 1)
outParams->connectedPlugNum = kAVCMultiplePlugs;
}
AVCTARGETMUTEX_UNLOCK;
return res;
}
IOReturn IOFireWireAVCTargetSpace::handleUnitInfoCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
{
UInt8 *pResponse;
UInt8 *pBuf = (UInt8*) buf;
UInt8 cType;
IOBufferMemoryDescriptor *pBufMemDesc = NULL;
AVCSubunitInfo *subUnitInfo;
if (len != 8)
return kIOReturnError;
cType = pBuf[0] & 0x0F;
if (cType != kAVCStatusInquiryCommand)
return kIOReturnError;
if ((pBuf[kAVCOperand0] != 0xFF) ||
(pBuf[kAVCOperand1] != 0xFF) ||
(pBuf[kAVCOperand2] != 0xFF) ||
(pBuf[kAVCOperand3] != 0xFF) ||
(pBuf[kAVCOperand4] != 0xFF))
return kIOReturnError;
pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
if(!pBufMemDesc)
return kFWResponseDataError;
pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
pResponse[kAVCAddress] = pBuf[kAVCAddress];
pResponse[kAVCOpcode] = pBuf[kAVCOpcode];
pResponse[kAVCOperand0] = 0x07;
AVCTARGETMUTEX_LOCK;
if (fSubunits->getCount() > 0)
{
subUnitInfo = (AVCSubunitInfo*) fSubunits->getObject(0);
pResponse[kAVCOperand1] = subUnitInfo->subunitTypeAndID;
}
else
pResponse[kAVCOperand1] = 0xFF;
pResponse[kAVCOperand2] = 0x00;
pResponse[kAVCOperand3] = 0x03;
pResponse[kAVCOperand4] = 0x93;
targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
AVCTARGETMUTEX_UNLOCK;
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCTargetSpace::handleSubUnitInfoCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
{
UInt8 *pResponse;
UInt8 *pBuf = (UInt8*) buf;
UInt8 cType;
UInt8 page;
IOBufferMemoryDescriptor *pBufMemDesc = NULL;
int i;
AVCSubunitInfo *subUnitInfo;
UInt32 subUnitType;
UInt8 count[32];
UInt32 uniqueSubUnitCount = 0;
UInt32 countArrayIndex;
int skipped;
if (len != 8)
return kIOReturnError;
cType = pBuf[0] & 0x0F;
if (cType != kAVCStatusInquiryCommand)
return kIOReturnError;
if (((pBuf[kAVCOperand0] & 0x8F) != 0x07) ||
(pBuf[kAVCOperand1] != 0xFF) ||
(pBuf[kAVCOperand2] != 0xFF) ||
(pBuf[kAVCOperand3] != 0xFF) ||
(pBuf[kAVCOperand4] != 0xFF))
return kIOReturnError;
AVCTARGETMUTEX_LOCK;
for (i=0;i<32;i++)
count[i] = 0;
for (i=(fSubunits->getCount()-1);i>=0;i--)
{
subUnitInfo = (AVCSubunitInfo *) fSubunits->getObject(i);
subUnitType = ((subUnitInfo->subunitTypeAndID & 0xF8) >> 3);
if (count[subUnitType] == 0)
uniqueSubUnitCount += 1;
count[subUnitType] += 1;
}
page = ((pBuf[kAVCOperand0] & 0x70) >> 4);
if (page > uniqueSubUnitCount/4)
{
AVCTARGETMUTEX_UNLOCK;
return kIOReturnError; }
pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
if(!pBufMemDesc)
{
AVCTARGETMUTEX_UNLOCK;
return kFWResponseDataError;
}
pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
pResponse[kAVCAddress] = pBuf[kAVCAddress];
pResponse[kAVCOpcode] = pBuf[kAVCOpcode];
pResponse[kAVCOperand0] = pBuf[kAVCOperand0];
for (i=0;i<4;i++)
{
if (((page*4)+i) < (int) uniqueSubUnitCount)
{
skipped = 0;
for (countArrayIndex = 0; countArrayIndex < 32; countArrayIndex++)
{
if (count[countArrayIndex] != 0)
{
if (skipped != ((page*4)+i))
{
skipped += 1;
}
else
{
pResponse[kAVCOperand1+i] = ((countArrayIndex << 3) | (count[countArrayIndex] > 8 ? 7 : (count[countArrayIndex]-1)));
break;
}
}
}
}
else
pResponse[kAVCOperand1+i] = 0xFF;
}
targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
AVCTARGETMUTEX_UNLOCK;
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCTargetSpace::handlePlugInfoCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
{
UInt8 *pResponse;
UInt8 *pBuf = (UInt8*) buf;
UInt8 cType;
IOBufferMemoryDescriptor *pBufMemDesc = NULL;
int i;
AVCSubunitInfo *subUnitInfo;
bool found = false;
if (len != 8)
return kIOReturnError;
cType = pBuf[0] & 0x0F;
if (cType != kAVCStatusInquiryCommand)
return kIOReturnError;
if ((pBuf[kAVCOperand1] != 0xFF) ||
(pBuf[kAVCOperand2] != 0xFF) ||
(pBuf[kAVCOperand3] != 0xFF) ||
(pBuf[kAVCOperand4] != 0xFF))
return kIOReturnError;
if (pBuf[kAVCOperand0] != 0x00)
return kIOReturnError;
pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
if(!pBufMemDesc)
return kFWResponseDataError;
pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
bcopy(buf,pResponse,len);
if (pBuf[kAVCAddress] == kAVCUnitAddress)
{
pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
pResponse[kAVCOperand1] = 31; pResponse[kAVCOperand2] = 31; }
else
{
AVCTARGETMUTEX_LOCK;
for (i=(fSubunits->getCount()-1);i>=0;i--)
{
subUnitInfo = (AVCSubunitInfo *) fSubunits->getObject(i);
if (subUnitInfo->subunitTypeAndID == pBuf[kAVCAddress])
{
pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
pResponse[kAVCOperand1] = subUnitInfo->numDestPlugs;
pResponse[kAVCOperand2] = subUnitInfo->numSourcePlugs;
found = true;
break;
}
}
if (!found)
{
pResponse[kAVCCommandResponse] = kAVCNotImplementedStatus;
}
AVCTARGETMUTEX_UNLOCK;
}
targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCTargetSpace::handlePowerCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
{
UInt8 *pResponse;
UInt8 *pBuf = (UInt8*) buf;
UInt8 cType;
IOBufferMemoryDescriptor *pBufMemDesc = NULL;
if (len != 4)
return kIOReturnError;
cType = pBuf[0] & 0x0F;
switch (cType)
{
case kAVCStatusInquiryCommand:
if (pBuf[kAVCOperand0] != 0x7F)
return kIOReturnError;
break;
case kAVCControlCommand:
if ((pBuf[kAVCOperand0] != 0x60) && (pBuf[kAVCOperand0] != 0x70))
return kIOReturnError;
break;
default:
return kIOReturnError;
};
pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
if(!pBufMemDesc)
return kFWResponseDataError;
pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
bcopy(buf,pResponse,len);
pResponse[kAVCCommandResponse] = (cType == kAVCStatusInquiryCommand) ? kAVCImplementedStatus : kAVCAcceptedStatus;
pResponse[kAVCOperand0] = (cType == kAVCStatusInquiryCommand) ? 0x70 : pBuf[kAVCOperand0];
targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCTargetSpace::handleConnectCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
{
UInt8 *pResponse;
UInt8 *pBuf = (UInt8*) buf;
UInt8 cType;
IOBufferMemoryDescriptor *pBufMemDesc = NULL;
int i;
AVCConnectTargetPlugsInParams inParams;
AVCConnectTargetPlugsOutParams outParams;
AVCConnectionRecord *pConnection;
UInt32 connCount = 0;
if (len != 8)
return kIOReturnError;
cType = pBuf[0] & 0x0F;
switch (cType)
{
case kAVCStatusInquiryCommand:
if ((pBuf[kAVCOperand0] & 0xFF) != 0xFF)
return kIOReturnError;
break;
case kAVCControlCommand:
if ((pBuf[kAVCOperand0] & 0xFC) != 0xFC)
return kIOReturnError;
break;
default:
return kIOReturnError;
};
inParams.sourceSubunitTypeAndID = pBuf[kAVCOperand1];
inParams.sourcePlugNum = pBuf[kAVCOperand2];
inParams.destSubunitTypeAndID = pBuf[kAVCOperand3];
inParams.destPlugNum = pBuf[kAVCOperand4];
inParams.lockConnection = ((pBuf[kAVCOperand0] & 0x02) == 0x02) ? true : false;
inParams.permConnection = false;
if (inParams.sourceSubunitTypeAndID == kAVCUnitAddress)
{
if ((inParams.sourcePlugNum < kAVCMaxNumPlugs) || (inParams.sourcePlugNum == kAVCAnyAvailableIsochPlug))
inParams.sourcePlugType = IOFWAVCPlugIsochInputType;
else if (((inParams.sourcePlugNum >= 0x80) && (inParams.sourcePlugNum <= 0x9E)) || (inParams.sourcePlugNum == kAVCAnyAvailableExternalPlug))
inParams.sourcePlugType = IOFWAVCPlugExternalInputType;
else if ((cType == kAVCStatusInquiryCommand) && (inParams.sourcePlugNum = kAVCInvalidPlug))
inParams.sourcePlugType = IOFWAVCPlugIsochInputType;
else
return kIOReturnError;
}
else
inParams.sourcePlugType = IOFWAVCPlugSubunitSourceType;
if (inParams.destSubunitTypeAndID == kAVCUnitAddress)
{
if ((inParams.destPlugNum < kAVCMaxNumPlugs) || (inParams.destPlugNum == kAVCAnyAvailableIsochPlug))
inParams.destPlugType = IOFWAVCPlugIsochOutputType;
else if (((inParams.destPlugNum >= 0x80) && (inParams.destPlugNum <= 0x9E)) || (inParams.destPlugNum == kAVCAnyAvailableExternalPlug))
inParams.destPlugType = IOFWAVCPlugExternalOutputType;
else if ((cType == kAVCStatusInquiryCommand) && (inParams.destPlugNum = kAVCInvalidPlug))
inParams.destPlugType = IOFWAVCPlugIsochOutputType;
else
return kIOReturnError;
}
else
inParams.destPlugType = IOFWAVCPlugSubunitDestType;
pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
if(!pBufMemDesc)
return kFWResponseDataError;
pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
bcopy(buf,pResponse,len);
if (cType == kAVCStatusInquiryCommand)
{
AVCTARGETMUTEX_LOCK;
pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
if ((inParams.sourceSubunitTypeAndID == 0xFF) && (inParams.sourcePlugNum == 0xFE))
{
for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
{
pConnection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
if ((pConnection->destSubunitTypeAndID == inParams.destSubunitTypeAndID) &&
(pConnection->destPlugNum == inParams.destPlugNum))
{
connCount++;
pResponse[kAVCOperand1] = pConnection->sourceSubunitTypeAndID;
pResponse[kAVCOperand2] = pConnection->sourcePlugNum;
if (pConnection->lockConnection == false)
{
pResponse[kAVCOperand0] &= 0xFD; }
if (pConnection->permConnection == false)
{
pResponse[kAVCOperand0] &= 0xFE; }
}
}
if (connCount == 0)
{
pResponse[kAVCOperand2] = kAVCInvalidPlug;
}
else if (connCount > 1)
{
pResponse[kAVCOperand1] = kAVCUnitAddress;
pResponse[kAVCOperand2] = kAVCMultiplePlugs;
pResponse[kAVCOperand0] |= 0x03;
}
}
else if ((inParams.destSubunitTypeAndID == 0xFF) && (inParams.destPlugNum == 0xFE))
{
for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
{
pConnection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
if ((pConnection->sourceSubunitTypeAndID == inParams.sourceSubunitTypeAndID) &&
(pConnection->sourcePlugNum == inParams.sourcePlugNum))
{
connCount++;
pResponse[kAVCOperand3] = pConnection->destSubunitTypeAndID;
pResponse[kAVCOperand4] = pConnection->destPlugNum;
if (pConnection->lockConnection == false)
{
pResponse[kAVCOperand0] &= 0xFD; }
if (pConnection->permConnection == false)
{
pResponse[kAVCOperand0] &= 0xFE; }
}
}
if (connCount == 0)
{
pResponse[kAVCOperand4] = kAVCInvalidPlug;
}
else if (connCount > 1)
{
pResponse[kAVCOperand3] = kAVCUnitAddress;
pResponse[kAVCOperand4] = kAVCMultiplePlugs;
pResponse[kAVCOperand0] |= 0x03; }
}
else
{
pResponse[kAVCCommandResponse] = kAVCNotImplementedStatus;
}
AVCTARGETMUTEX_UNLOCK;
}
else
{
pResponse[kAVCCommandResponse] = kAVCAcceptedStatus;
if (connectTargetPlugs(NULL,&inParams,&outParams) == kIOReturnSuccess)
{
pResponse[kAVCOperand2] = outParams.sourcePlugNum;
pResponse[kAVCOperand4] = outParams.destPlugNum;
}
else
{
pResponse[kAVCCommandResponse] = kAVCRejectedStatus;
}
}
targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCTargetSpace::handleDisconnectCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
{
UInt8 *pResponse;
UInt8 *pBuf = (UInt8*) buf;
UInt8 cType;
IOBufferMemoryDescriptor *pBufMemDesc = NULL;
IOReturn res;
IOFWAVCPlugTypes sourcePlugType;
IOFWAVCPlugTypes destPlugType;
if (len != 8)
return kIOReturnError;
cType = pBuf[kAVCCommandResponse] & 0x0F;
if (cType != kAVCControlCommand)
return kIOReturnError;
if (pBuf[kAVCOperand0] != 0xFF)
return kIOReturnError;
if (pBuf[kAVCOperand1] != kAVCUnitAddress)
{
if (pBuf[kAVCOperand2] < kAVCMaxNumPlugs)
sourcePlugType = IOFWAVCPlugSubunitSourceType;
else
return kIOReturnError;
}
else
{
if (pBuf[kAVCOperand2] < kAVCMaxNumPlugs)
sourcePlugType = IOFWAVCPlugIsochInputType;
else if ((pBuf[kAVCOperand2] >= 0x80) && (pBuf[kAVCOperand2] <= 0x9E))
sourcePlugType = IOFWAVCPlugExternalInputType;
else
return kIOReturnError;
}
if (pBuf[kAVCOperand3] != kAVCUnitAddress)
{
if ((pBuf[kAVCOperand4] < kAVCMaxNumPlugs) || (pBuf[kAVCOperand4] == kAVCAnyAvailableSubunitPlug))
destPlugType = IOFWAVCPlugSubunitDestType;
else
return kIOReturnError;
}
else
{
if ((pBuf[kAVCOperand4] < kAVCMaxNumPlugs) || (pBuf[kAVCOperand4] == kAVCAnyAvailableIsochPlug))
destPlugType = IOFWAVCPlugIsochOutputType;
else if (((pBuf[kAVCOperand4] >= 0x80) && (pBuf[kAVCOperand4] <= 0x9E)) || (pBuf[kAVCOperand4] == kAVCAnyAvailableExternalPlug))
destPlugType = IOFWAVCPlugExternalOutputType;
else
return kIOReturnError;
}
pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
if(!pBufMemDesc)
return kFWResponseDataError;
pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
bcopy(buf,pResponse,len);
AVCTARGETMUTEX_LOCK;
res = disconnectTargetPlugs(NULL,
pBuf[kAVCOperand1],
sourcePlugType,
pBuf[kAVCOperand2],
pBuf[kAVCOperand3],
destPlugType,
pBuf[kAVCOperand4]);
if (res == kIOReturnSuccess)
pResponse[kAVCCommandResponse] = kAVCAcceptedStatus;
else
pResponse[kAVCCommandResponse] = kAVCRejectedStatus;
AVCTARGETMUTEX_UNLOCK;
targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCTargetSpace::handleInputPlugSignalFormatCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
{
UInt8 *pResponse;
IOBufferMemoryDescriptor *pBufMemDesc = NULL;
UInt8 *pBuf = (UInt8*) buf;
UInt8 cType;
UInt32 plug;
int i;
AVCConnectionRecord *pConnection;
bool found = false;
AVCSubunitInfo *subUnitInfo;
UInt32 signalFormat;
if (len != 8)
return kIOReturnError;
cType = pBuf[0] & 0x0F;
plug = pBuf[kAVCOperand0];
signalFormat = (((UInt32)pBuf[kAVCOperand1] << 24) +
((UInt32)pBuf[kAVCOperand2] << 16) +
((UInt32)pBuf[kAVCOperand3] << 8) +
(UInt32)pBuf[kAVCOperand4]);
if (plug > (kAVCMaxNumPlugs-1))
return kIOReturnError;
switch (cType)
{
case kAVCStatusInquiryCommand:
if ((pBuf[kAVCOperand1] != 0xFF) ||
(pBuf[kAVCOperand2] != 0xFF) ||
(pBuf[kAVCOperand3] != 0xFF) ||
(pBuf[kAVCOperand4] != 0xFF))
return kIOReturnError;
break;
case kAVCControlCommand:
if ((pBuf[kAVCOperand1] & 0xC0) != 0x80)
return kIOReturnError;
break;
default:
return kIOReturnError;
};
AVCTARGETMUTEX_LOCK;
for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
{
pConnection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
if ((pConnection->sourceSubunitTypeAndID == kAVCUnitAddress) &&
(pConnection->sourcePlugNum == plug) &&
(pConnection->destSubunitTypeAndID != kAVCUnitAddress))
{
subUnitInfo = getSubunitInfo(pConnection->destSubunitTypeAndID);
if (subUnitInfo)
{
found = true;
break;
}
}
}
if ((found == true) && (cType == kAVCControlCommand))
{
subUnitInfo->callBack(subUnitInfo,
kIOFWAVCSubunitPlugMsgSignalFormatModified,
IOFWAVCPlugSubunitDestType,
pConnection->destPlugNum,
signalFormat,
generation,
nodeID);
AVCTARGETMUTEX_UNLOCK;
return kIOReturnSuccess;
}
pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
if(!pBufMemDesc)
{
AVCTARGETMUTEX_UNLOCK;
return kFWResponseDataError;
}
pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
bcopy(buf,pResponse,len);
if (cType == kAVCStatusInquiryCommand)
{
pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
if (found == true)
{
signalFormat = subUnitInfo->destPlugRecords[pConnection->destPlugNum].plugSignalFormat;
pResponse[kAVCOperand1] = ((signalFormat & 0xFF000000) >> 24);
pResponse[kAVCOperand2] = ((signalFormat & 0x00FF0000) >> 16);
pResponse[kAVCOperand3] = ((signalFormat & 0x0000FF00) >> 8);
pResponse[kAVCOperand4] = (signalFormat & 0x000000FF);
}
else
{
pResponse[kAVCOperand1] = ((kAVCPlugSignalFormatNTSCDV & 0xFF000000) >> 24);
pResponse[kAVCOperand2] = ((kAVCPlugSignalFormatNTSCDV & 0x00FF0000) >> 16);
pResponse[kAVCOperand3] = ((kAVCPlugSignalFormatNTSCDV & 0x0000FF00) >> 8);
pResponse[kAVCOperand4] = (kAVCPlugSignalFormatNTSCDV & 0x000000FF);
}
}
else
{
pResponse[kAVCCommandResponse] = kAVCAcceptedStatus;
}
AVCTARGETMUTEX_UNLOCK;
targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCTargetSpace::handleOutputPlugSignalFormatCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
{
UInt8 *pResponse;
IOBufferMemoryDescriptor *pBufMemDesc = NULL;
UInt8 *pBuf = (UInt8*) buf;
UInt8 cType;
UInt32 plug;
int i;
AVCConnectionRecord *pConnection;
bool found = false;
AVCSubunitInfo *subUnitInfo;
UInt32 signalFormat;
if (len != 8)
return kIOReturnError;
cType = pBuf[0] & 0x0F;
plug = pBuf[kAVCOperand0];
signalFormat = (((UInt32)pBuf[kAVCOperand1] << 24) +
((UInt32)pBuf[kAVCOperand2] << 16) +
((UInt32)pBuf[kAVCOperand3] << 8) +
(UInt32)pBuf[kAVCOperand4]);
if (plug > (kAVCMaxNumPlugs-1))
return kIOReturnError;
switch (cType)
{
case kAVCStatusInquiryCommand:
if ((pBuf[kAVCOperand1] != 0xFF) ||
(pBuf[kAVCOperand2] != 0xFF) ||
(pBuf[kAVCOperand3] != 0xFF) ||
(pBuf[kAVCOperand4] != 0xFF))
return kIOReturnError;
break;
case kAVCControlCommand:
if ((pBuf[kAVCOperand1] & 0xC0) != 0x80)
return kIOReturnError;
break;
default:
return kIOReturnError;
};
AVCTARGETMUTEX_LOCK;
for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
{
pConnection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
if ((pConnection->destSubunitTypeAndID == kAVCUnitAddress) &&
(pConnection->destPlugNum == plug) &&
(pConnection->sourceSubunitTypeAndID != kAVCUnitAddress))
{
subUnitInfo = getSubunitInfo(pConnection->sourceSubunitTypeAndID);
if (subUnitInfo)
{
found = true;
break;
}
}
}
if ((found == true) && (cType == kAVCControlCommand))
{
subUnitInfo->callBack(subUnitInfo,
kIOFWAVCSubunitPlugMsgSignalFormatModified,
IOFWAVCPlugSubunitSourceType,
pConnection->sourcePlugNum,
signalFormat,
generation,
nodeID);
AVCTARGETMUTEX_UNLOCK;
return kIOReturnSuccess;
}
pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
if(!pBufMemDesc)
{
AVCTARGETMUTEX_UNLOCK;
return kFWResponseDataError;
}
pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
bcopy(buf,pResponse,len);
if (cType == kAVCStatusInquiryCommand)
{
pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
if (found == true)
{
signalFormat = subUnitInfo->sourcePlugRecords[pConnection->sourcePlugNum].plugSignalFormat;
pResponse[kAVCOperand1] = ((signalFormat & 0xFF000000) >> 24);
pResponse[kAVCOperand2] = ((signalFormat & 0x00FF0000) >> 16);
pResponse[kAVCOperand3] = ((signalFormat & 0x0000FF00) >> 8);
pResponse[kAVCOperand4] = (signalFormat & 0x000000FF);
}
else
{
pResponse[kAVCOperand1] = ((kAVCPlugSignalFormatNTSCDV & 0xFF000000) >> 24);
pResponse[kAVCOperand2] = ((kAVCPlugSignalFormatNTSCDV & 0x00FF0000) >> 16);
pResponse[kAVCOperand3] = ((kAVCPlugSignalFormatNTSCDV & 0x0000FF00) >> 8);
pResponse[kAVCOperand4] = (kAVCPlugSignalFormatNTSCDV & 0x000000FF);
}
}
else
{
pResponse[kAVCCommandResponse] = kAVCAcceptedStatus;
}
AVCTARGETMUTEX_UNLOCK;
targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCTargetSpace::handleConnectionsCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
{
UInt8 cType;
UInt8 connectionCount;
UInt32 responseLen;
UInt8 *pBuf = (UInt8*) buf;
UInt8 *pResponse;
IOBufferMemoryDescriptor *pBufMemDesc = NULL;
int i;
AVCConnectionRecord *pConnection;
UInt8 respIndex;
UInt8 connectionType;
if (len != 4)
return kIOReturnError;
cType = pBuf[0] & 0x0F;
if (cType != kAVCStatusInquiryCommand)
return kIOReturnError;
if (pBuf[kAVCOperand0] != 0xFF)
return kIOReturnError;
AVCTARGETMUTEX_LOCK;
connectionCount = (UInt8) (fConnectionRecords->getCount() & 0x000000FF);
if (connectionCount > 100)
connectionCount = 100;
responseLen = 4 + (connectionCount*5);
pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(responseLen, kIODirectionOutIn);
if(!pBufMemDesc)
{
AVCTARGETMUTEX_UNLOCK;
return kFWResponseDataError;
}
pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
pResponse[kAVCAddress] = 0xFF;
pResponse[kAVCOpcode] = 0x22;
pResponse[kAVCOperand0] = connectionCount;
respIndex = 4;
for (i=(connectionCount-1);i>=0;i--)
{
pConnection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
connectionType = 0xFC;
if (pConnection->lockConnection)
connectionType += 2;
if (pConnection->permConnection)
connectionType += 1;
pResponse[respIndex++] = connectionType;
pResponse[respIndex++] = pConnection->sourceSubunitTypeAndID;
pResponse[respIndex++] = pConnection->sourcePlugNum;
pResponse[respIndex++] = pConnection->destSubunitTypeAndID;
pResponse[respIndex++] = pConnection->destPlugNum;
}
AVCTARGETMUTEX_UNLOCK;
targetSendAVCResponse(generation, nodeID, pBufMemDesc, responseLen);
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCTargetSpace::handleSignalSourceCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
{
return kIOReturnError;
}
void IOFireWireAVCTargetSpace::pcrModified(IOFWAVCPlugTypes plugType,
UInt32 plugNum,
UInt32 newValue)
{
AVCConnectionRecord *pConnection;
AVCSubunitInfo *subUnitInfo;
int i;
AVCTARGETMUTEX_LOCK;
for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
{
pConnection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
switch (plugType)
{
case IOFWAVCPlugIsochInputType:
if ((pConnection->sourceSubunitTypeAndID == kAVCUnitAddress) &&
(pConnection->sourcePlugNum == plugNum) &&
(pConnection->destSubunitTypeAndID != kAVCUnitAddress) )
{
subUnitInfo = getSubunitInfo(pConnection->destSubunitTypeAndID);
if (subUnitInfo)
subUnitInfo->callBack(subUnitInfo,
kIOFWAVCSubunitPlugMsgConnectedPlugModified,
IOFWAVCPlugSubunitDestType,
pConnection->destPlugNum,
newValue,
0,0);
}
break;
case IOFWAVCPlugIsochOutputType:
if ((pConnection->destSubunitTypeAndID == kAVCUnitAddress) &&
(pConnection->destPlugNum == plugNum) &&
(pConnection->sourceSubunitTypeAndID != kAVCUnitAddress))
{
subUnitInfo = getSubunitInfo(pConnection->sourceSubunitTypeAndID);
if (subUnitInfo)
subUnitInfo->callBack(subUnitInfo,
kIOFWAVCSubunitPlugMsgConnectedPlugModified,
IOFWAVCPlugSubunitSourceType,
pConnection->sourcePlugNum,
newValue,
0,0);
}
break;
default:
break;
};
}
AVCTARGETMUTEX_UNLOCK;
return;
}
AVCSubunitInfo *IOFireWireAVCTargetSpace::getSubunitInfo(UInt32 subunitTypeAndID)
{
AVCSubunitInfo *subunitInfo = NULL;
int i;
bool found = false;
AVCTARGETMUTEX_LOCK;
for (i=(fSubunits->getCount()-1);i>=0;i--)
{
subunitInfo = (AVCSubunitInfo *) fSubunits->getObject(i);
if (subunitInfo->subunitTypeAndID == subunitTypeAndID)
{
found = true;
break;
}
}
AVCTARGETMUTEX_UNLOCK;
if (found == true)
return subunitInfo;
else
return NULL;
}
UInt32 IOFireWireAVCTargetSpace::subUnitOfTypeCount(UInt32 type)
{
UInt32 cnt = 0;
UInt32 subUnitType;
AVCSubunitInfo *subUnitInfo;
int i;
AVCTARGETMUTEX_LOCK;
for (i=(fSubunits->getCount()-1);i>=0;i--)
{
subUnitInfo = (AVCSubunitInfo *) fSubunits->getObject(i);
subUnitType = ((subUnitInfo->subunitTypeAndID & 0xF8) >> 3);
if (subUnitType == type)
cnt+= 1;
}
AVCTARGETMUTEX_UNLOCK;
return cnt;
}
bool IOFireWireAVCTargetSpace::canConnectDestPlug(UInt32 destSubunitTypeAndID,
IOFWAVCPlugTypes destPlugType,
UInt32 *destPlugNum)
{
bool res=true;
int i;
AVCConnectionRecord *connection;
UInt32 actualPlugNumber = *destPlugNum;
for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
{
connection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
if ((connection->destSubunitTypeAndID == destSubunitTypeAndID) &&
(connection->destPlugType == destPlugType))
{
if ((actualPlugNumber == kAVCInvalidPlug) || (connection->destPlugNum == *destPlugNum))
{
if ((connection->lockConnection == false) && (connection->permConnection == false))
{
actualPlugNumber = connection->destPlugNum;
disconnectTargetPlugs(NULL,
connection->sourceSubunitTypeAndID,
connection->sourcePlugType,
connection->sourcePlugNum,
connection->destSubunitTypeAndID,
connection->destPlugType,
connection->destPlugNum);
break; }
else if (connection->destPlugNum == *destPlugNum)
{
res = false;
break; }
}
}
}
if (actualPlugNumber == kAVCInvalidPlug)
{
res = false;
}
else
{
*destPlugNum = actualPlugNumber;
}
return res;
}