IOFireWireAVCProtocolUserClient.cpp [plain text]
#include "IOFireWireAVCProtocolUserClient.h"
#include "IOFireWireAVCConsts.h"
#include <IOKit/firewire/IOFireWireNub.h>
#include <IOKit/firewire/IOFireWireBus.h>
#include <IOKit/firewire/IOFWAddressSpace.h>
#include "IOFireWirePCRSpace.h"
#include "IOFireWireAVCRequestSpace.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
}
};
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
}
};
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*)nodeID;
args[3] = (void*)plug;
args[4] = (void*)oldVal;
args[5] = (void*)newVal;
info->fClient->sendAsyncResult( ((PlugInfo *)info)->fCallbackInfo, kIOReturnSuccess, args, 6 );
}
UInt32 IOFireWireAVCProtocolUserClient::avcRequestHandler(void *refcon, UInt16 nodeID, IOFWSpeed &speed,
FWAddress addr, UInt32 len, const void *buf, IOFWRequestRefCon requestRefcon)
{
IOFireWireAVCProtocolUserClient * me = (IOFireWireAVCProtocolUserClient *)refcon;
if( me->fAVCRequestCallbackAsyncRef[0] != 0 ) {
void * args[kMaxAsyncArgs];
UInt32 generation;
UInt16 localID;
const UInt8 *src;
UInt8 *dst;
UInt32 copyLen;
me->fDevice->getNodeIDGeneration(generation, localID);
args[0] = 0; args[2] = (void*)generation;
args[3] = (void*)nodeID;
args[4] = (void*)len;
src = (const UInt8*)buf;
dst = (UInt8 *)(args+5);
copyLen = len;
if(copyLen > (kMaxAsyncArgs - 5)*sizeof(void *))
copyLen = (kMaxAsyncArgs - 5)*sizeof(void *);
bcopy(src, dst, copyLen);
args[1] = (void*)copyLen;
me->sendAsyncResult( me->fAVCRequestCallbackAsyncRef, kIOReturnSuccess,
args, 5+(copyLen+sizeof(void *)-1)/sizeof(void *) );
len -= copyLen;
src += copyLen;
while(len) {
copyLen = len;
if(copyLen > (kMaxAsyncArgs - 2)*sizeof(void *))
copyLen = (kMaxAsyncArgs - 2)*sizeof(void *);
bcopy(src, dst, copyLen);
args[0] = (void *)(src - (const UInt8*)buf); args[1] = (void*)copyLen;
me->sendAsyncResult( me->fAVCRequestCallbackAsyncRef, kIOReturnSuccess,
args, 2+(copyLen+sizeof(void *)-1)/sizeof(void *) );
len -= copyLen;
src += copyLen;
}
}
return kFWResponseComplete;
}
void IOFireWireAVCProtocolUserClient::free()
{
if(fAVCSpace) {
fAVCSpace->deactivate();
fAVCSpace->release();
}
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();
}
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;
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;
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCProtocolUserClient::clientClose( void )
{
IOLog( "IOFireWireAVCProtocolUserClient : clientClose\n" );
fStarted = false;
getProvider()->terminate( kIOServiceRequired );
return kIOReturnSuccess;
}
IOReturn IOFireWireAVCProtocolUserClient::clientDied( void )
{
IOLog( "IOFireWireAVCProtocolUserClient : clientDied\n" );
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)
{
bcopy( asyncRef, fAVCRequestCallbackAsyncRef, sizeof(OSAsyncReference) );
if(fAVCSpace) {
fAVCSpace->deactivate();
fAVCSpace->release();
}
fAVCSpace = IOFireWireAVCRequestSpace::withSubUnit(fBus,
subUnitType, subUnitID, avcRequestHandler, this);
if(fAVCSpace)
fAVCSpace->activate();
return kIOReturnSuccess;
}
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;
}
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;
if(!fPCRSpace) {
fPCRSpace = IOFireWirePCRSpace::getPCRAddressSpace(fDevice->getBus());
if(!fPCRSpace)
return kIOReturnNoMemory;
fPCRSpace->activate();
}
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;
if(!fPCRSpace) {
fPCRSpace = IOFireWirePCRSpace::getPCRAddressSpace(fDevice->getBus());
if(!fPCRSpace)
return kIOReturnNoMemory;
fPCRSpace->activate();
}
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);
}