IOFireWirePCRSpace.cpp [plain text]
#include <IOKit/IOLib.h>
#include <IOKit/firewire/IOFireWireController.h>
#include <IOKit/firewire/IOFireWireLocalNode.h>
#include <IOKit/avc/IOFireWireAVCConsts.h>
#include <IOKit/avc/IOFireWirePCRSpace.h>
OSDefineMetaClassAndStructors(IOFireWirePCRSpace, IOFWPseudoAddressSpace)
OSMetaClassDefineReservedUnused(IOFireWirePCRSpace, 0);
OSMetaClassDefineReservedUnused(IOFireWirePCRSpace, 1);
OSMetaClassDefineReservedUnused(IOFireWirePCRSpace, 2);
OSMetaClassDefineReservedUnused(IOFireWirePCRSpace, 3);
static IOReturn MyServiceInterestHandler( void * target,
void * refCon,
UInt32 messageType,
IOService * provider,
void * messageArgument,
vm_size_t argSize )
{
IOReturn res = kIOReturnUnsupported;
IOFireWirePCRSpace *pPCRSpace = (IOFireWirePCRSpace*) target;
switch (messageType)
{
case kIOMessageServiceIsTerminated:
case kIOMessageServiceIsRequestingClose:
case kIOMessageServiceIsResumed:
res = kIOReturnSuccess;
break;
case kIOMessageServiceIsSuspended:
res = kIOReturnSuccess;
if (pPCRSpace)
pPCRSpace->clearAllP2PConnections();
break;
default:
break;
}
return res;
}
bool IOFireWirePCRSpace::init(IOFireWireBus *bus)
{
if(!IOFWPseudoAddressSpace::initFixed(bus,
FWAddress(kCSRRegisterSpaceBaseAddressHi, kPCRBaseAddress),
sizeof(fBuf), simpleReader, NULL, this))
return false;
fDesc = IOMemoryDescriptor::withAddress(fBuf, sizeof(fBuf), kIODirectionOutIn);
if (fDesc == NULL) {
return false;
}
IOReturn status = fDesc->prepare();
if( status != kIOReturnSuccess )
{
fDesc->release();
fDesc = NULL;
return false;
}
fBuf[0] = OSSwapHostToBigInt32((2 << kIOFWPCRDataRatePhase) |
(63 << kIOFWPCRBroadcastBasePhase) |
(0xff << kIOFWPCRExtensionPhase) |
(31 << kIOFWPCRNumPlugsPhase));
fBuf[32] = OSSwapHostToBigInt32((2 << kIOFWPCRDataRatePhase) |
(0xff << kIOFWPCRExtensionPhase) |
(31 << kIOFWPCRNumPlugsPhase));
fAVCTargetSpace = NULL;
IOFireWireController *pFireWireController = OSDynamicCast(IOFireWireController, bus);
if (pFireWireController)
{
IOFireWireLocalNode *pFireWireLocalNode = (pFireWireController)->getLocalNode(pFireWireController);
if (pFireWireLocalNode)
{
fNotifier = pFireWireLocalNode->registerInterest(gIOGeneralInterest,MyServiceInterestHandler,this,this);
}
}
fAVCTargetSpace = IOFireWireAVCTargetSpace::getAVCTargetSpace((IOFireWireController*)bus);
if(fAVCTargetSpace)
fAVCTargetSpace->activateWithUserClient((IOFireWireAVCProtocolUserClient*)0xFFFFFFFF);
return true;
}
IOFireWirePCRSpace * IOFireWirePCRSpace::getPCRAddressSpace(IOFireWireBus *bus)
{
IOFWAddressSpace *existing;
IOFireWirePCRSpace *space;
existing = bus->getAddressSpace(FWAddress(kCSRRegisterSpaceBaseAddressHi, kPCRBaseAddress));
if(existing && OSDynamicCast(IOFireWirePCRSpace, existing)) {
existing->retain();
return OSDynamicCast(IOFireWirePCRSpace, existing);
}
space = new IOFireWirePCRSpace;
if(space) {
if(!space->init(bus)) {
space->release();
space = NULL;
}
}
return space;
}
UInt32 IOFireWirePCRSpace::doWrite(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
const void *buf, IOFWRequestRefCon refcon)
{
if(addr.addressHi != kCSRRegisterSpaceBaseAddressHi)
return kFWResponseAddressError;
if((addr.addressLo < kPCRBaseAddress) || (addr.addressLo + len > kPCRBaseAddress + 64*4))
return kFWResponseAddressError;
if(!fControl->isLockRequest(refcon))
return kFWResponseTypeError;
if(len != 4 || (addr.addressLo & 3))
return kFWResponseTypeError;
UInt32 newVal = *(const UInt32 *)buf;
UInt32 offset = (addr.addressLo - kPCRBaseAddress)/4;
UInt32 oldVal = OSSwapBigToHostInt32(fBuf[offset]);
fBuf[offset] = newVal;
if(fClients[offset].func)
(fClients[offset].func)(fClients[offset].refcon, nodeID, (offset-1) & 31, oldVal, OSSwapBigToHostInt32(newVal));
if ((fAVCTargetSpace) && (offset > 0) && (offset < 32))
fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochOutputType,(offset-1),OSSwapBigToHostInt32(newVal));
else if ((fAVCTargetSpace) && (offset > 32) && (offset < 64))
fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochInputType,(offset-33),OSSwapBigToHostInt32(newVal));
return kFWResponseComplete;
}
IOReturn IOFireWirePCRSpace::activate()
{
IOReturn res = kIOReturnSuccess;
if(!fActivations++)
res = IOFWAddressSpace::activate();
return res;
}
void IOFireWirePCRSpace::deactivate()
{
if(!--fActivations)
{
IOFWAddressSpace::deactivate();
if (fNotifier)
fNotifier->remove();
fNotifier = NULL;
}
}
IOReturn IOFireWirePCRSpace::allocatePlug(void *refcon, IOFireWirePCRCallback func, UInt32 &plug, Client* head)
{
UInt32 i;
IOReturn res = kIOReturnNoResources;
fControl->closeGate();
for(i=0; i<32; i++) {
if(!head[i].func) {
head[i].func = func;
head[i].refcon = refcon;
plug = i;
res = kIOReturnSuccess;
break;
}
}
fControl->openGate();
return res;
}
void IOFireWirePCRSpace::freePlug(UInt32 plug, Client* client)
{
fControl->closeGate();
client->func = NULL;
fBuf[plug] = 0;
fControl->openGate();
}
UInt32 IOFireWirePCRSpace::readPlug(UInt32 plug)
{
UInt32 val;
fControl->closeGate();
val = OSSwapBigToHostInt32(fBuf[plug]);
fControl->openGate();
return val;
}
IOReturn IOFireWirePCRSpace::updatePlug(UInt32 plug, UInt32 oldVal, UInt32 newVal)
{
IOReturn res;
fControl->closeGate();
if(oldVal == OSSwapBigToHostInt32(fBuf[plug])) {
fBuf[plug] = OSSwapHostToBigInt32(newVal);
res = kIOReturnSuccess;
if ((fAVCTargetSpace) && (plug > 0) && (plug < 32))
fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochOutputType,(plug-1),newVal);
else if ((fAVCTargetSpace) && (plug > 32) && (plug < 64))
fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochInputType,(plug-33),newVal);
}
else
res = kIOReturnCannotLock;
fControl->openGate();
return res;
}
IOReturn IOFireWirePCRSpace::allocateInputPlug(void *refcon, IOFireWirePCRCallback func, UInt32 &plug)
{
return allocatePlug(refcon, func, plug, fClients+33);
}
void IOFireWirePCRSpace::freeInputPlug(UInt32 plug)
{
freePlug(plug+33, fClients+plug+33);
}
UInt32 IOFireWirePCRSpace::readInputPlug(UInt32 plug)
{
return readPlug(plug+33);
}
IOReturn IOFireWirePCRSpace::updateInputPlug(UInt32 plug, UInt32 oldVal, UInt32 newVal)
{
return updatePlug(plug+33, oldVal, newVal);
}
IOReturn IOFireWirePCRSpace::allocateOutputPlug(void *refcon, IOFireWirePCRCallback func, UInt32 &plug)
{
IOReturn result;
result = allocatePlug(refcon, func, plug, fClients+1);
return result;
}
void IOFireWirePCRSpace::freeOutputPlug(UInt32 plug)
{
freePlug(plug+1, fClients+plug+1);
}
UInt32 IOFireWirePCRSpace::readOutputPlug(UInt32 plug)
{
return readPlug(plug+1);
}
IOReturn IOFireWirePCRSpace::updateOutputPlug(UInt32 plug, UInt32 oldVal, UInt32 newVal)
{
return updatePlug(plug+1, oldVal, newVal);
}
UInt32 IOFireWirePCRSpace::readOutputMasterPlug()
{
return readPlug(0);
}
IOReturn IOFireWirePCRSpace::updateOutputMasterPlug(UInt32 oldVal, UInt32 newVal)
{
return updatePlug(0, oldVal, newVal);
}
UInt32 IOFireWirePCRSpace::readInputMasterPlug()
{
return readPlug(32);
}
IOReturn IOFireWirePCRSpace::updateInputMasterPlug(UInt32 oldVal, UInt32 newVal)
{
return updatePlug(32, oldVal, newVal);
}
void IOFireWirePCRSpace::setAVCTargetSpacePointer(IOFireWireAVCTargetSpace *pAVCTargetSpace)
{
return;
}
void IOFireWirePCRSpace::clearAllP2PConnections(void)
{
int i;
UInt32 oldVal;
for(i=0; i<32; i++)
{
fControl->closeGate();
oldVal = OSSwapBigToHostInt32(fBuf[i+1]);
if ((oldVal & 0x3F000000) != 0)
{
fBuf[i+1] &= OSSwapHostToBigInt32(0xC0FFFFFF);
if(fClients[i+1].func)
(fClients[i+1].func)(fClients[i+1].refcon, 0xFFFF, i, oldVal, OSSwapBigToHostInt32(fBuf[i+1]));
if (fAVCTargetSpace)
fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochOutputType,i,OSSwapBigToHostInt32(fBuf[i+1]));
}
fControl->openGate();
}
for(i=0; i<32; i++)
{
fControl->closeGate();
oldVal = OSSwapBigToHostInt32(fBuf[i+33]);
if ((oldVal & 0x3F000000) != 0)
{
fBuf[i+33] &= OSSwapHostToBigInt32(0xC0FFFFFF);
if(fClients[i+33].func)
(fClients[i+33].func)(fClients[i+33].refcon, 0xFFFF, i, oldVal, OSSwapBigToHostInt32(fBuf[i+33]));
if (fAVCTargetSpace)
fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochInputType,i,OSSwapBigToHostInt32(fBuf[i+33]));
}
fControl->openGate();
}
return;
}