IOFWAddressSpace.cpp [plain text]
#include <IOKit/firewire/IOFWAddressSpace.h>
#include <IOKit/firewire/IOFireWireController.h>
OSData *IOFWPseudoAddressSpace::allocatedAddresses = NULL;
OSDefineMetaClass( IOFWAddressSpace, OSObject )
OSDefineAbstractStructors(IOFWAddressSpace, OSObject)
OSMetaClassDefineReservedUnused(IOFWAddressSpace, 1);
bool IOFWAddressSpace::init(IOFireWireBus *bus)
{
if(!OSObject::init())
return false;
fControl = OSDynamicCast(IOFireWireController, bus);
return fControl != NULL;
}
UInt32 IOFWAddressSpace::doLock(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 inLen,
const UInt32 *newVal, UInt32 &outLen, UInt32 *oldVal, UInt32 type,
IOFWRequestRefCon refcon)
{
UInt32 ret = kFWResponseAddressError;
bool ok;
int size;
int i;
IOMemoryDescriptor *desc = NULL;
IOByteCount offset;
size = inLen/8; outLen = inLen/2; ret = doRead(nodeID, speed, addr, size*4, &desc, &offset, refcon);
if(ret != kFWResponseComplete)
return ret;
desc->readBytes(offset, oldVal, size*4);
switch (type) {
case kFWExtendedTCodeCompareSwap:
ok = true;
for(i=0; i<size; i++)
ok = ok && oldVal[i] == newVal[i];
if(ok)
ret = doWrite(nodeID, speed, addr, size*4, newVal+size, refcon);
break;
default:
ret = kFWResponseTypeError;
}
return ret;
}
IOReturn IOFWAddressSpace::activate()
{
return fControl->allocAddress(this);
}
void IOFWAddressSpace::deactivate()
{
fControl->freeAddress(this);
}
UInt32 IOFWAddressSpace::contains(FWAddress addr)
{
return 0;
}
OSDefineMetaClassAndStructors(IOFWPhysicalAddressSpace, IOFWAddressSpace)
bool IOFWPhysicalAddressSpace::initWithDesc(IOFireWireBus *control,
IOMemoryDescriptor *mem)
{
if(!IOFWAddressSpace::init(control))
return false;
fMem = mem;
fMem->retain();
fLen = mem->getLength();
return true;
}
void IOFWPhysicalAddressSpace::free()
{
if(fMem)
fMem->release();
IOFWAddressSpace::free();
}
UInt32 IOFWPhysicalAddressSpace::doRead(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
IOMemoryDescriptor **buf, IOByteCount * offset, IOFWRequestRefCon refcon)
{
UInt32 res = kFWResponseAddressError;
vm_size_t pos;
IOPhysicalAddress phys;
if(addr.addressHi != 0)
return kFWResponseAddressError;
pos = 0;
while(pos < fLen) {
IOPhysicalLength lengthOfSegment;
phys = fMem->getPhysicalSegment(pos, &lengthOfSegment);
if(addr.addressLo >= phys && addr.addressLo+len <= phys+lengthOfSegment) {
*offset = pos + addr.addressLo - phys;
*buf = fMem;
res = kFWResponseComplete;
break;
}
pos += lengthOfSegment;
}
return res;
}
UInt32 IOFWPhysicalAddressSpace::doWrite(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
const void *buf, IOFWRequestRefCon refcon)
{
UInt32 res = kFWResponseAddressError;
vm_size_t pos;
IOPhysicalAddress phys;
if(addr.addressHi != 0)
return kFWResponseAddressError;
pos = 0;
while(pos < fLen) {
IOPhysicalLength lengthOfSegment;
phys = fMem->getPhysicalSegment(pos, &lengthOfSegment);
if(addr.addressLo >= phys && addr.addressLo+len <= phys+lengthOfSegment) {
fMem->writeBytes(pos + addr.addressLo - phys, buf, len);
res = kFWResponseComplete;
break;
}
pos += lengthOfSegment;
}
return res;
}
OSDefineMetaClassAndStructors(IOFWPseudoAddressSpace, IOFWAddressSpace)
OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpace, 0);
OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpace, 1);
IOReturn IOFWPseudoAddressSpace::allocateAddress(FWAddress *addr, UInt32 lenDummy)
{
unsigned int i, len;
UInt8 * data;
UInt8 used = 1;
if(allocatedAddresses == NULL) {
allocatedAddresses = OSData::withCapacity(4); allocatedAddresses->appendBytes(&used, 1); }
if(!allocatedAddresses)
return kIOReturnNoMemory;
len = allocatedAddresses->getLength();
data = (UInt8*)allocatedAddresses->getBytesNoCopy();
for(i=0; i<len; i++) {
if(data[i] == 0) {
data[i] = 1;
addr->addressHi = i;
addr->addressLo = 0;
return kIOReturnSuccess;
}
}
if(len >= 0xfffe)
return kIOReturnNoMemory;
if(allocatedAddresses->appendBytes(&used, 1)) {
addr->addressHi = len;
addr->addressLo = 0;
return kIOReturnSuccess;
}
return kIOReturnNoMemory;
}
void IOFWPseudoAddressSpace::freeAddress(FWAddress addr, UInt32 lenDummy)
{
unsigned int len;
UInt8 * data;
assert(allocatedAddresses != NULL);
len = allocatedAddresses->getLength();
assert(addr.addressHi < len);
data = (UInt8*)allocatedAddresses->getBytesNoCopy();
assert(data[addr.addressHi]);
data[addr.addressHi] = 0;
}
UInt32 IOFWPseudoAddressSpace::simpleReader(void *refcon, UInt16 nodeID, IOFWSpeed &speed,
FWAddress addr, UInt32 len, IOMemoryDescriptor **buf,
IOByteCount * offset, IOFWRequestRefCon reqrefcon)
{
IOFWPseudoAddressSpace * space = (IOFWPseudoAddressSpace *)refcon;
*buf = space->fDesc;
*offset = addr.addressLo - space->fBase.addressLo;
return kFWResponseComplete;
}
UInt32 IOFWPseudoAddressSpace::simpleWriter(void *refcon, UInt16 nodeID, IOFWSpeed &speed,
FWAddress addr, UInt32 len, const void *buf, IOFWRequestRefCon reqrefcon)
{
IOFWPseudoAddressSpace * space = (IOFWPseudoAddressSpace *)refcon;
space->fDesc->writeBytes(addr.addressLo - space->fBase.addressLo, buf, len);
return kFWResponseComplete;
}
IOFWPseudoAddressSpace *
IOFWPseudoAddressSpace::simpleRead(IOFireWireBus *control,
FWAddress *addr, UInt32 len, const void *data)
{
IOFWPseudoAddressSpace * me;
me = new IOFWPseudoAddressSpace;
do {
if(!me)
break;
if(!me->initAll(control, addr, len, simpleReader, NULL, (void *)me)) {
me->release();
me = NULL;
break;
}
me->fDesc = IOMemoryDescriptor::withAddress((void *)data, len, kIODirectionOut);
if(!me->fDesc) {
me->release();
me = NULL;
}
} while(false);
return me;
}
IOFWPseudoAddressSpace *
IOFWPseudoAddressSpace::simpleReadFixed(IOFireWireBus *control,
FWAddress addr, UInt32 len, const void *data)
{
IOFWPseudoAddressSpace * me;
me = new IOFWPseudoAddressSpace;
do {
if(!me)
break;
if(!me->initFixed(control, addr, len, simpleReader, NULL, (void *)me)) {
me->release();
me = NULL;
break;
}
me->fDesc = IOMemoryDescriptor::withAddress((void *)data, len, kIODirectionOut);
if(!me->fDesc) {
me->release();
me = NULL;
}
} while(false);
return me;
}
IOFWPseudoAddressSpace *IOFWPseudoAddressSpace::simpleRW(IOFireWireBus *control,
FWAddress *addr, UInt32 len, void *data)
{
IOFWPseudoAddressSpace * me;
me = new IOFWPseudoAddressSpace;
do {
if(!me)
break;
if(!me->initAll(control, addr, len, simpleReader, simpleWriter, (void *)me)) {
me->release();
me = NULL;
break;
}
me->fDesc = IOMemoryDescriptor::withAddress(data, len, kIODirectionOut);
if(!me->fDesc) {
me->release();
me = NULL;
}
} while(false);
return me;
}
IOFWPseudoAddressSpace *IOFWPseudoAddressSpace::simpleRW(IOFireWireBus *control,
FWAddress *addr, IOMemoryDescriptor * data)
{
IOFWPseudoAddressSpace * me;
me = new IOFWPseudoAddressSpace;
do {
if(!me)
break;
if(!me->initAll(control, addr, data->getLength(), simpleReader, simpleWriter, (void *)me)) {
me->release();
me = NULL;
break;
}
data->retain();
me->fDesc = data;
} while(false);
return me;
}
bool IOFWPseudoAddressSpace::initAll(IOFireWireBus *control,
FWAddress *addr, UInt32 len,
FWReadCallback reader, FWWriteCallback writer, void *refCon)
{
if(!IOFWAddressSpace::init(control))
return false;
if(allocateAddress(addr, len) != kIOReturnSuccess)
return false;
fBase = *addr;
fBase.addressHi &= 0xFFFF; fLen = len;
fDesc = NULL; fRefCon = refCon;
fReader = reader;
fWriter = writer;
return true;
}
bool IOFWPseudoAddressSpace::initFixed(IOFireWireBus *control,
FWAddress addr, UInt32 len,
FWReadCallback reader, FWWriteCallback writer, void *refCon)
{
if(!IOFWAddressSpace::init(control))
return false;
if(addr.addressHi != kCSRRegisterSpaceBaseAddressHi)
return false;
fBase = addr;
fLen = len;
fDesc = NULL; fRefCon = refCon;
fReader = reader;
fWriter = writer;
return true;
}
void IOFWPseudoAddressSpace::free()
{
if(fDesc)
fDesc->release();
if(fBase.addressHi != kCSRRegisterSpaceBaseAddressHi)
freeAddress(fBase, fLen);
IOFWAddressSpace::free();
}
UInt32 IOFWPseudoAddressSpace::doRead(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
IOMemoryDescriptor **buf, IOByteCount * offset, IOFWRequestRefCon refcon)
{
if(addr.addressHi != fBase.addressHi)
return kFWResponseAddressError;
if(addr.addressLo < fBase.addressLo)
return kFWResponseAddressError;
if(addr.addressLo + len > fBase.addressLo+fLen)
return kFWResponseAddressError;
if(!fReader)
return kFWResponseTypeError;
return fReader(fRefCon, nodeID, speed, addr, len, buf, offset, refcon);
}
UInt32 IOFWPseudoAddressSpace::doWrite(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
const void *buf, IOFWRequestRefCon refcon)
{
if(addr.addressHi != fBase.addressHi)
return kFWResponseAddressError;
if(addr.addressLo < fBase.addressLo)
return kFWResponseAddressError;
if(addr.addressLo + len > fBase.addressLo+fLen)
return kFWResponseAddressError;
if(!fWriter)
return kFWResponseTypeError;
return fWriter(fRefCon, nodeID, speed, addr, len, buf, refcon);
}
UInt32 IOFWPseudoAddressSpace::contains(FWAddress addr)
{
UInt32 offset;
if(addr.addressHi != fBase.addressHi)
return 0;
if(addr.addressLo < fBase.addressLo)
return 0;
offset = addr.addressLo - fBase.addressLo;
if(offset > fLen)
return 0;
return fLen - offset;
}