IOFireWireAVCProtocolUserClient.cpp [plain text]
#include "IOFireWireAVCProtocolUserClient.h"
#include <IOKit/avc/IOFireWireAVCConsts.h>
#include <IOKit/firewire/IOFireWireNub.h>
#include <IOKit/firewire/IOFireWireBus.h>
#include <IOKit/firewire/IOFWAddressSpace.h>
#include <IOKit/avc/IOFireWirePCRSpace.h>
#include <IOKit/avc/IOFireWireAVCTargetSpace.h>
struct PlugInfo {
IOFireWireAVCProtocolUserClient *fClient;
UInt32 fPlug;
OSAsyncReference fCallbackInfo;
void *fUserRefcon; };
OSDefineMetaClassAndStructors(IOFireWireAVCProtocolUserClient, IOUserClient)
IOExternalMethod IOFireWireAVCProtocolUserClient::sMethods[kIOFWAVCProtocolUserClientNumCommands] =
{
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::sendAVCResponse,
kIOUCScalarIStructI,
2,
0xFFFFFFFF },
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::freeInputPlug,
kIOUCScalarIScalarO,
1,
0
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::readInputPlug,
kIOUCScalarIScalarO,
1,
1
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::updateInputPlug,
kIOUCScalarIScalarO,
3,
0
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::freeOutputPlug,
kIOUCScalarIScalarO,
1,
0
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::readOutputPlug,
kIOUCScalarIScalarO,
1,
1
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::updateOutputPlug,
kIOUCScalarIScalarO,
3,
0
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::readOutputMasterPlug,
kIOUCScalarIScalarO,
0,
1
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::updateOutputMasterPlug,
kIOUCScalarIScalarO,
2,
0
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::readInputMasterPlug,
kIOUCScalarIScalarO,
0,
1
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::updateInputMasterPlug,
kIOUCScalarIScalarO,
2,
0
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::publishAVCUnitDirectory,
kIOUCScalarIScalarO,
0,
0
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::setSubunitPlugSignalFormat,
kIOUCScalarIScalarO,
4,
0
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::getSubunitPlugSignalFormat,
kIOUCScalarIScalarO,
3,
1
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::connectTargetPlugs,
kIOUCStructIStructO,
sizeof(AVCConnectTargetPlugsInParams),
sizeof(AVCConnectTargetPlugsOutParams)
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::disconnectTargetPlugs,
kIOUCScalarIScalarO,
6,
0
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::getTargetPlugConnection,
kIOUCStructIStructO,
sizeof(AVCGetTargetPlugConnectionInParams),
sizeof(AVCGetTargetPlugConnectionOutParams)
},
{ 0,
(IOMethod) &IOFireWireAVCProtocolUserClient::AVCRequestNotHandled,
kIOUCScalarIStructI,
4,
0xFFFFFFFF }
};
IOExternalAsyncMethod IOFireWireAVCProtocolUserClient::sAsyncMethods[kIOFWAVCProtocolUserClientNumAsyncCommands] =
{
{ 0,
(IOAsyncMethod) &IOFireWireAVCProtocolUserClient::setAVCRequestCallback,
kIOUCScalarIScalarO,
2,
0
},
{ 0,
(IOAsyncMethod) &IOFireWireAVCProtocolUserClient::allocateInputPlug,
kIOUCScalarIScalarO,
1,
1
},
{ 0,
(IOAsyncMethod) &IOFireWireAVCProtocolUserClient::allocateOutputPlug,
kIOUCScalarIScalarO,
1,
1
},
{
0,
(IOAsyncMethod) &IOFireWireAVCProtocolUserClient::installAVCCommandHandler,
kIOUCScalarIScalarO,
4,
0
},
{
0,
(IOAsyncMethod) &IOFireWireAVCProtocolUserClient::addSubunit,
kIOUCScalarIScalarO,
5,
1
}
};
void IOFireWireAVCProtocolUserClient::forwardPlugWrite(void *refcon, UInt16 nodeID, UInt32 plug, UInt32 oldVal, UInt32 newVal)
{
OSData *data = (OSData *)refcon;
const PlugInfo *info = (const PlugInfo *)(data->getBytesNoCopy());
void * args[kMaxAsyncArgs];
UInt32 generation;
UInt16 localID;
info->fClient->fDevice->getNodeIDGeneration(generation, localID);
args[0] = info->fUserRefcon;
args[1] = (void*)generation;
args[2] = (void*)((UInt32)nodeID);
args[3] = (void*)plug;
args[4] = (void*)oldVal;
args[5] = (void*)newVal;
info->fClient->sendAsyncResult( ((PlugInfo *)info)->fCallbackInfo, kIOReturnSuccess, args, 6 );
}
void IOFireWireAVCProtocolUserClient::avcTargetCommandHandler(const AVCCommandHandlerInfo *pCmdInfo,
UInt32 generation,
UInt16 nodeID,
const void *command,
UInt32 cmdLen,
IOFWSpeed &speed,
UInt32 handlerSearchIndex)
{
void * args[kMaxAsyncArgs];
OSAsyncReference asyncRef;
const UInt8 *src;
UInt8 *dst;
UInt32 copyLen;
bcopy(pCmdInfo->asyncRef, asyncRef, sizeof(OSAsyncReference));
args[0] = 0; args[2] = (void*)generation;
args[3] = (void*)((UInt32)nodeID);
args[4] = (void*)cmdLen;
args[5] = (void*)pCmdInfo->userCallBack;
args[6] = (void*)pCmdInfo->userRefCon;
args[7] = (void*)speed;
args[8] = (void*)handlerSearchIndex;
src = (const UInt8*)command;
dst = (UInt8 *)(args+9);
copyLen = cmdLen;
if(copyLen > (kMaxAsyncArgs - 9)*sizeof(void *))
copyLen = (kMaxAsyncArgs - 9)*sizeof(void *);
bcopy(src, dst, copyLen);
args[1] = (void*)copyLen;
pCmdInfo->userClient->sendAsyncResult( asyncRef, kIOReturnSuccess,
args, 9+(copyLen+sizeof(void *)-1)/sizeof(void *) );
cmdLen -= copyLen;
src += copyLen;
while(cmdLen) {
copyLen = cmdLen;
dst = (UInt8 *)(args+2);
if(copyLen > (kMaxAsyncArgs - 2)*sizeof(void *))
copyLen = (kMaxAsyncArgs - 2)*sizeof(void *);
bcopy(src, dst, copyLen);
args[0] = (void *)(src - (const UInt8*)command); args[1] = (void*)copyLen;
pCmdInfo->userClient->sendAsyncResult( asyncRef, kIOReturnSuccess,
args, 2+(copyLen+sizeof(void *)-1)/sizeof(void *) );
cmdLen -= copyLen;
src += copyLen;
}
}
void IOFireWireAVCProtocolUserClient::avcSubunitPlugHandler(const AVCSubunitInfo *pSubunitInfo,
IOFWAVCSubunitPlugMessages plugMessage,
IOFWAVCPlugTypes plugType,
UInt32 plugNum,
UInt32 messageParams,
UInt32 generation,
UInt16 nodeID)
{
void * args[kMaxAsyncArgs];
OSAsyncReference asyncRef;
bcopy(pSubunitInfo->asyncRef, asyncRef, sizeof(OSAsyncReference));
args[0] = (void*) pSubunitInfo->subunitTypeAndID;
args[1] = (void*) plugType;
args[2] = (void*) plugNum;
args[3] = (void*) plugMessage;
args[4] = (void*) messageParams;
args[5] = (void*)pSubunitInfo->userCallBack;
args[6] = (void*)pSubunitInfo->userRefCon;
args[7] = (void*)generation;
args[8] = (void*)((UInt32)nodeID);
pSubunitInfo->userClient->sendAsyncResult( asyncRef, kIOReturnSuccess,
args, 9);
}
void IOFireWireAVCProtocolUserClient::free()
{
if(fInputPlugs) {
OSData *data;
while(data = OSDynamicCast(OSData, fInputPlugs->getAnyObject())) {
const PlugInfo *info = (const PlugInfo *)(data->getBytesNoCopy());
fPCRSpace->freeInputPlug(info->fPlug);
fInputPlugs->removeObject(data);
}
fInputPlugs->release();
}
if(fOutputPlugs) {
OSData *data;
while(data = OSDynamicCast(OSData, fOutputPlugs->getAnyObject())) {
const PlugInfo *info = (const PlugInfo *)(data->getBytesNoCopy());
fPCRSpace->freeOutputPlug(info->fPlug);
fOutputPlugs->removeObject(data);
}
fOutputPlugs->release();
}
if(fPCRSpace) {
fPCRSpace->deactivate();
fPCRSpace->release();
}
if(fAVCTargetSpace) {
fAVCTargetSpace->deactivateWithUserClient(this);
fAVCTargetSpace->release();
}
IOUserClient::free();
}
bool IOFireWireAVCProtocolUserClient::start(IOService *provider)
{
OSObject *prop;
IOFireWireNub *device;
device = OSDynamicCast(IOFireWireNub, provider->getProvider());
if(!device)
return false;
fBus = device->getBus();
fDevice = device;
prop = device->getProperty(gFireWire_GUID);
if(prop)
setProperty(gFireWire_GUID, prop);
fInputPlugs = OSSet::withCapacity(1);
fOutputPlugs = OSSet::withCapacity(1);
if(!fInputPlugs || !fOutputPlugs)
return false;
fPCRSpace = IOFireWirePCRSpace::getPCRAddressSpace(fDevice->getBus());
if(!fPCRSpace)
return false;
fPCRSpace->activate();
fAVCTargetSpace = IOFireWireAVCTargetSpace::getAVCTargetSpace(fDevice->getController());
if(!fAVCTargetSpace)
return false;
fAVCTargetSpace->activateWithUserClient(this);
fPCRSpace->setAVCTargetSpacePointer(fAVCTargetSpace);
registerService();
return true;
}
IOReturn IOFireWireAVCProtocolUserClient::newUserClient( task_t owningTask, void * securityID,
UInt32 type, OSDictionary * properties,
IOUserClient ** handler )
{
if(fStarted)
return kIOReturnStillOpen;
retain();
*handler = this;
fStarted = true;
fTask = owningTask;
if (properties)
{
properties->setObject("IOUserClientCrossEndianCompatible", kOSBooleanTrue);
setProperty("IOUserClientCrossEndianCompatible", kOSBooleanTrue);
}
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCProtocolUserClient::clientClose( void )
{
fStarted = false;
getProvider()->terminate( kIOServiceRequired );
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCProtocolUserClient::clientDied( void )
{
return clientClose();
}
bool IOFireWireAVCProtocolUserClient::matchPropertyTable(OSDictionary * table)
{
if (!IOService::matchPropertyTable(table)) return false;
bool res = compareProperty(table, gFireWire_GUID);
return res;
}
IOExternalMethod* IOFireWireAVCProtocolUserClient::getTargetAndMethodForIndex(IOService **target, UInt32 index)
{
if( index >= kIOFWAVCProtocolUserClientNumCommands )
return NULL;
else
{
*target = this;
return &sMethods[index];
}
}
IOExternalAsyncMethod*
IOFireWireAVCProtocolUserClient::getAsyncTargetAndMethodForIndex(IOService **target, UInt32 index)
{
if( index >= kIOFWAVCProtocolUserClientNumAsyncCommands )
return NULL;
else
{
*target = this;
return &sAsyncMethods[index];
}
return NULL;
}
IOReturn IOFireWireAVCProtocolUserClient::setAVCRequestCallback
( OSAsyncReference asyncRef, UInt32 subUnitType, UInt32 subUnitID)
{
return kIOReturnUnsupported;
}
IOReturn
IOFireWireAVCProtocolUserClient::sendAVCResponse(UInt32 generation, UInt16 nodeID, const char *buffer, UInt32 size)
{
IOMemoryDescriptor *desc = NULL;
IOFWWriteCommand *cmd = NULL;
IOReturn status;
do {
desc = IOMemoryDescriptor::withAddress((void *)buffer,size, kIODirectionOutIn);
if(!desc) {
status = kIOReturnNoMemory;
break;
}
status = desc->prepare();
if( status != kIOReturnSuccess )
{
break;
}
cmd = new IOFWWriteCommand;
if(!cmd) {
status = kIOReturnNoMemory;
break;
}
if(!cmd->initAll(fDevice->getController(), generation,
FWAddress(kCSRRegisterSpaceBaseAddressHi, kFCPResponseAddress, nodeID),
desc, NULL, NULL)) {
status = kIOReturnNoMemory;
break;
}
status = cmd->submit();
} while (false);
if(cmd)
cmd->release();
if(desc)
desc->release();
return status;
}
IOReturn
IOFireWireAVCProtocolUserClient::allocateInputPlug(OSAsyncReference asyncRef, void *userRefcon, UInt32 *plugPtr)
{
IOReturn status;
PlugInfo info;
OSData *data;
data = OSData::withCapacity(sizeof(info));
if(!data)
return kIOReturnNoMemory;
do {
info.fPlug = 0x1234; status = fPCRSpace->allocateInputPlug(data, forwardPlugWrite, info.fPlug);
if(status != kIOReturnSuccess)
break;
bcopy(asyncRef, info.fCallbackInfo, sizeof(OSAsyncReference));
info.fUserRefcon = userRefcon;
info.fClient = this;
if(!data->appendBytes(&info, sizeof(info))) {
status = kIOReturnNoMemory;
break;
}
if(!fInputPlugs->setObject(data)) {
status = kIOReturnNoMemory;
break;
}
*plugPtr = info.fPlug;
status = kIOReturnSuccess;
} while (false);
data->release(); if(status != kIOReturnSuccess && info.fPlug != 0x1234)
fPCRSpace->freeInputPlug(info.fPlug);
return status;
}
IOReturn
IOFireWireAVCProtocolUserClient::allocateOutputPlug(OSAsyncReference asyncRef, void *userRefcon, UInt32 *plugPtr)
{
IOReturn status;
PlugInfo info;
OSData *data;
data = OSData::withCapacity(sizeof(info));
if(!data)
return kIOReturnNoMemory;
do {
info.fPlug = 0x1234; status = fPCRSpace->allocateOutputPlug(data, forwardPlugWrite, info.fPlug);
if(status != kIOReturnSuccess)
break;
bcopy(asyncRef, info.fCallbackInfo, sizeof(OSAsyncReference));
info.fUserRefcon = userRefcon;
info.fClient = this;
if(!data->appendBytes(&info, sizeof(info))) {
status = kIOReturnNoMemory;
break;
}
if(!fOutputPlugs->setObject(data)) {
status = kIOReturnNoMemory;
break;
}
*plugPtr = info.fPlug;
status = kIOReturnSuccess;
} while (false);
data->release(); if(status != kIOReturnSuccess && info.fPlug != 0x1234)
fPCRSpace->freeOutputPlug(info.fPlug);
return status;
}
IOReturn IOFireWireAVCProtocolUserClient::freeInputPlug(UInt32 plug)
{
OSIterator *plugIterator;
plugIterator = OSCollectionIterator::withCollection(fInputPlugs);
if( plugIterator) {
OSData * data;
while( (data = (OSData *)plugIterator->getNextObject())) {
const PlugInfo *info = (const PlugInfo *)(data->getBytesNoCopy());
if(info->fPlug == plug) {
fPCRSpace->freeInputPlug(info->fPlug);
fInputPlugs->removeObject(data);
}
}
plugIterator->release();
}
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCProtocolUserClient::freeOutputPlug(UInt32 plug)
{
OSIterator *plugIterator;
plugIterator = OSCollectionIterator::withCollection(fOutputPlugs);
if( plugIterator) {
OSData * data;
while( (data = (OSData *)plugIterator->getNextObject())) {
const PlugInfo *info = (const PlugInfo *)(data->getBytesNoCopy());
if(info->fPlug == plug) {
fPCRSpace->freeOutputPlug(info->fPlug);
fInputPlugs->removeObject(data);
}
}
plugIterator->release();
}
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCProtocolUserClient::readInputPlug(UInt32 plug, UInt32 *valPtr)
{
if(plug > 30)
return kIOReturnBadArgument;
*valPtr = fPCRSpace->readInputPlug(plug);
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCProtocolUserClient::updateInputPlug(UInt32 plug, UInt32 oldVal, UInt32 newVal)
{
if(plug > 30)
return kIOReturnBadArgument;
return fPCRSpace->updateInputPlug(plug, oldVal, newVal);
}
IOReturn IOFireWireAVCProtocolUserClient::readOutputPlug(UInt32 plug, UInt32 *valPtr)
{
if(plug > 30)
return kIOReturnBadArgument;
*valPtr = fPCRSpace->readOutputPlug(plug);
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCProtocolUserClient::updateOutputPlug(UInt32 plug, UInt32 oldVal, UInt32 newVal)
{
if(plug > 30)
return kIOReturnBadArgument;
return fPCRSpace->updateOutputPlug(plug, oldVal, newVal);
}
IOReturn IOFireWireAVCProtocolUserClient::readOutputMasterPlug(UInt32 *valPtr)
{
*valPtr = fPCRSpace->readOutputMasterPlug();
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCProtocolUserClient::updateOutputMasterPlug(UInt32 oldVal, UInt32 newVal)
{
return fPCRSpace->updateOutputMasterPlug(oldVal, newVal);
}
IOReturn IOFireWireAVCProtocolUserClient::readInputMasterPlug(UInt32 *valPtr)
{
*valPtr = fPCRSpace->readInputMasterPlug();
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCProtocolUserClient::updateInputMasterPlug(UInt32 oldVal, UInt32 newVal)
{
return fPCRSpace->updateInputMasterPlug(oldVal, newVal);
}
IOReturn IOFireWireAVCProtocolUserClient::publishAVCUnitDirectory(void)
{
return fAVCTargetSpace->publishAVCUnitDirectory();
}
IOReturn IOFireWireAVCProtocolUserClient::installAVCCommandHandler(OSAsyncReference asyncRef, UInt32 subUnitTypeAndID, UInt32 opCode, UInt32 callback, UInt32 refCon)
{
return fAVCTargetSpace->installAVCCommandHandler(this, avcTargetCommandHandler, asyncRef, subUnitTypeAndID, opCode, callback, refCon);
}
IOReturn IOFireWireAVCProtocolUserClient::addSubunit(OSAsyncReference asyncRef,
UInt32 subunitType,
UInt32 numSourcePlugs,
UInt32 numDestPlugs,
UInt32 callBack,
UInt32 refCon,
UInt32 *subUnitTypeAndID)
{
IOReturn res = kIOReturnSuccess;
UInt32 subUnitID = 0x00;
res = fAVCTargetSpace->addSubunit(this,
avcSubunitPlugHandler,
asyncRef,
subunitType,
numSourcePlugs,
numDestPlugs,
callBack,
refCon,
&subUnitID);
if (res == kIOReturnSuccess)
*subUnitTypeAndID = subUnitID;
return res;
}
IOReturn IOFireWireAVCProtocolUserClient::setSubunitPlugSignalFormat(UInt32 subunitTypeAndID,
IOFWAVCPlugTypes plugType,
UInt32 plugNum,
UInt32 signalFormat)
{
return fAVCTargetSpace->setSubunitPlugSignalFormat(this,subunitTypeAndID, plugType, plugNum, signalFormat);
}
IOReturn IOFireWireAVCProtocolUserClient::getSubunitPlugSignalFormat(UInt32 subunitTypeAndID,
IOFWAVCPlugTypes plugType,
UInt32 plugNum,
UInt32 *pSignalFormat)
{
return fAVCTargetSpace->getSubunitPlugSignalFormat(this,subunitTypeAndID, plugType, plugNum, pSignalFormat);
}
IOReturn IOFireWireAVCProtocolUserClient::connectTargetPlugs(AVCConnectTargetPlugsInParams *inParams,
AVCConnectTargetPlugsOutParams *outParams)
{
return fAVCTargetSpace->connectTargetPlugs(this,inParams,outParams);
}
IOReturn IOFireWireAVCProtocolUserClient::disconnectTargetPlugs(UInt32 sourceSubunitTypeAndID,
IOFWAVCPlugTypes sourcePlugType,
UInt32 sourcePlugNum,
UInt32 destSubunitTypeAndID,
IOFWAVCPlugTypes destPlugType,
UInt32 destPlugNum)
{
return fAVCTargetSpace->disconnectTargetPlugs(this,
sourceSubunitTypeAndID,
sourcePlugType,
sourcePlugNum,
destSubunitTypeAndID,
destPlugType,
destPlugNum);
}
IOReturn IOFireWireAVCProtocolUserClient::getTargetPlugConnection(AVCGetTargetPlugConnectionInParams *inParams,
AVCGetTargetPlugConnectionOutParams *outParams)
{
return fAVCTargetSpace->getTargetPlugConnection(this,inParams,outParams);
}
IOReturn IOFireWireAVCProtocolUserClient::AVCRequestNotHandled(UInt32 generation,
UInt16 nodeID,
IOFWSpeed speed,
UInt32 handlerSearchIndex,
const char *pCmdBuf,
UInt32 cmdLen)
{
fAVCTargetSpace->findAVCRequestHandler(this,
generation,
nodeID,
speed,
handlerSearchIndex,
pCmdBuf,
cmdLen);
return kIOReturnSuccess;
}