IOConfigDirectory.cpp [plain text]
#import <IOKit/firewire/IOConfigDirectory.h>
#import <IOKit/firewire/IORemoteConfigDirectory.h>
#import <IOKit/firewire/IOFireWireDevice.h>
#import "FWDebugging.h"
#include "IOConfigDirectoryIterator.h"
#import <libkern/c++/OSIterator.h>
#import <libkern/c++/OSData.h>
#import <libkern/OSByteOrder.h>
static int findIndex(const UInt32* base, int size, int key,
UInt32 type = kInvalidConfigROMEntryType);
int findIndex(const UInt32* base, int size, int key, UInt32 type)
{
int i;
UInt32 mask, test;
test = (UInt32)key << kConfigEntryKeyValuePhase;
mask = kConfigEntryKeyValue;
if(type != kInvalidConfigROMEntryType) {
test |= type << kConfigEntryKeyTypePhase;
mask |= kConfigEntryKeyType;
}
mask |= test;
for(i=0; i<size; i++) {
if( (OSSwapBigToHostInt32(base[i]) & mask) == test )
break;
}
if(i >= size)
i = -1;
return i;
}
OSDefineMetaClass( IOConfigDirectory, OSObject )
OSDefineAbstractStructors(IOConfigDirectory, OSObject)
OSMetaClassDefineReservedUnused(IOConfigDirectory, 0);
OSMetaClassDefineReservedUnused(IOConfigDirectory, 1);
OSMetaClassDefineReservedUnused(IOConfigDirectory, 2);
OSMetaClassDefineReservedUnused(IOConfigDirectory, 3);
OSMetaClassDefineReservedUnused(IOConfigDirectory, 4);
OSMetaClassDefineReservedUnused(IOConfigDirectory, 5);
OSMetaClassDefineReservedUnused(IOConfigDirectory, 6);
OSMetaClassDefineReservedUnused(IOConfigDirectory, 7);
OSMetaClassDefineReservedUnused(IOConfigDirectory, 8);
bool IOConfigDirectory::initWithOffset(int start, int type)
{
IOReturn status = kIOReturnSuccess;
const UInt32 *data;
if( !OSObject::init() )
{
status = kIOReturnError;
}
if( status == kIOReturnSuccess )
{
fStart = start;
fType = type;
status = updateROMCache( start, 1 );
}
if( status == kIOReturnSuccess )
{
data = lockData();
fNumEntries = (OSSwapBigToHostInt32(data[start]) & kConfigLeafDirLength) >> kConfigLeafDirLengthPhase;
unlockData();
status = updateROMCache(start + 1, fNumEntries);
}
if( status != kIOReturnSuccess )
{
fNumEntries = 0;
}
return true;
}
IOReturn IOConfigDirectory::createIterator(UInt32 testVal, UInt32 testMask, OSIterator *&iterator)
{
IOReturn status = kIOReturnSuccess;
IOConfigDirectoryIterator *iter = NULL;
status = checkROMState();
if( status == kIOReturnSuccess )
{
iter = new IOConfigDirectoryIterator;
if( iter == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = iter->init( this, testVal, testMask );
if( status == kIOReturnSuccess )
{
iterator = iter;
}
else
{
iter->release();
iter = NULL;
}
}
return status;
}
IOReturn IOConfigDirectory::getKeyType(int key, IOConfigKeyType &type)
{
IOReturn status = kIOReturnSuccess;
int index = 0;
status = checkROMState();
if( status == kIOReturnSuccess )
{
const UInt32 * data = lockData() + fStart + 1;
index = findIndex(data, fNumEntries, key);
unlockData();
if( index < 0 )
status = kIOConfigNoEntry;
}
if( status == kIOReturnSuccess )
{
status = getIndexType(index, type);
}
return status;
}
IOReturn IOConfigDirectory::getKeyValue(int key, UInt32 &value, OSString** text)
{
IOReturn status = kIOReturnSuccess;
int index = 0;
status = checkROMState();
if( status == kIOReturnSuccess )
{
const UInt32 * data = lockData() + fStart + 1;
index = findIndex(data, fNumEntries, key);
unlockData();
if( index < 0 )
status = kIOConfigNoEntry;
}
if( status == kIOReturnSuccess )
{
status = getIndexValue(index, value);
}
if( status == kIOReturnSuccess && text )
{
*text = NULL;
status = getIndexValue(index+1, *text);
if( status != kIOFireWireConfigROMInvalid )
status = kIOReturnSuccess;
}
return status;
}
IOReturn IOConfigDirectory::getKeyValue(int key, OSData *&value, OSString** text)
{
IOReturn status = kIOReturnSuccess;
int index = 0;
status = checkROMState();
if( status == kIOReturnSuccess )
{
const UInt32 * data = lockData() + fStart + 1;
index = findIndex(data, fNumEntries, key, kConfigLeafKeyType);
unlockData();
if( index < 0 )
{
status = kIOConfigNoEntry;
}
}
if( status == kIOReturnSuccess )
{
status = getIndexValue(index, value);
}
if( status == kIOReturnSuccess && text )
{
*text = NULL;
status = getIndexValue(index+1, *text);
if( status != kIOFireWireConfigROMInvalid )
status = kIOReturnSuccess;
}
return status;
}
IOReturn IOConfigDirectory::getKeyValue(int key, IOConfigDirectory *&value,
OSString** text)
{
IOReturn status = kIOReturnSuccess;
int index = 0;
status = checkROMState();
if( status == kIOReturnSuccess )
{
const UInt32 * data = lockData() + fStart + 1;
index = findIndex(data, fNumEntries, key, kConfigDirectoryKeyType);
unlockData();
if( index < 0 )
{
status = kIOConfigNoEntry;
}
}
if( status == kIOReturnSuccess )
{
status = getIndexValue(index, value);
}
if( status == kIOReturnSuccess && text )
{
*text = NULL;
status = getIndexValue(index+1, *text);
if( status != kIOFireWireConfigROMInvalid )
status = kIOReturnSuccess;
}
return status;
}
IOReturn IOConfigDirectory::getKeyOffset(int key, FWAddress &value, OSString** text)
{
IOReturn status = kIOReturnSuccess;
int index = 0;
status = checkROMState();
if( status == kIOReturnSuccess )
{
const UInt32 * data = lockData() + fStart + 1;
index = findIndex(data, fNumEntries, key, kConfigOffsetKeyType);
unlockData();
if( index < 0 )
status = kIOConfigNoEntry;
}
if( status == kIOReturnSuccess )
{
status = getIndexOffset(index, value);
}
if( status == kIOReturnSuccess && text)
{
*text = NULL;
status = getIndexValue(index+1, *text);
if( status != kIOFireWireConfigROMInvalid )
status = kIOReturnSuccess;
}
return status;
}
IOReturn IOConfigDirectory::getKeySubdirectories(int key, OSIterator *&iterator)
{
IOReturn status = createIterator((key << kConfigEntryKeyValuePhase) |
(kConfigDirectoryKeyType << kConfigEntryKeyTypePhase),
kConfigEntryKeyType | kConfigEntryKeyValue, iterator);
return status;
}
int IOConfigDirectory::getType() const
{
return fType;
}
int IOConfigDirectory::getNumEntries() const
{
return fNumEntries;
}
IOReturn IOConfigDirectory::getIndexType(int index, IOConfigKeyType &type)
{
IOReturn status = kIOReturnSuccess;
UInt32 entry;
status = checkROMState();
if( status == kIOReturnSuccess )
{
if( index < 0 || index >= fNumEntries )
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
const UInt32 * data = lockData();
entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
unlockData();
type = (IOConfigKeyType)((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase);
}
return status;
}
IOReturn IOConfigDirectory::getIndexKey(int index, int &key)
{
IOReturn status = kIOReturnSuccess;
UInt32 entry;
status = checkROMState();
if( status == kIOReturnSuccess )
{
if( index < 0 || index >= fNumEntries )
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
const UInt32 * data = lockData();
entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
unlockData();
key = (IOConfigKeyType)((entry & kConfigEntryKeyValue) >> kConfigEntryKeyValuePhase);
}
return status;
}
IOReturn IOConfigDirectory::getIndexValue(int index, UInt32 &value)
{
IOReturn status = kIOReturnSuccess;
UInt32 entry;
status = checkROMState();
if( status == kIOReturnSuccess )
{
if( index < 0 || index >= fNumEntries )
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
const UInt32 * data = lockData();
entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
unlockData();
value = entry & kConfigEntryValue;
}
return status;
}
IOReturn IOConfigDirectory::getIndexValue(int index, OSData *&value)
{
IOReturn status = kIOReturnSuccess;
UInt32 entry;
const UInt32 *data;
UInt32 offset;
int len = 0;
status = checkROMState();
if( status == kIOReturnSuccess )
{
if( index < 0 || index >= fNumEntries )
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
data = lockData();
entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
unlockData();
if( ((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) != kConfigLeafKeyType)
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
status = getIndexOffset( index, offset );
}
if( status == kIOReturnSuccess )
{
status = updateROMCache( offset, 1 );
}
if( status == kIOReturnSuccess )
{
data = lockData();
len = ((OSSwapBigToHostInt32(data[offset]) & kConfigLeafDirLength) >> kConfigLeafDirLengthPhase);
unlockData();
status = updateROMCache( offset + 1, len );
}
if( status == kIOReturnSuccess )
{
data = lockData();
value = OSData::withBytes(data+offset+1, len*sizeof(UInt32));
unlockData();
if( value == NULL)
status = kIOReturnNoMemory;
}
return status;
}
IOReturn IOConfigDirectory::getIndexValue(int index, OSString *&value)
{
IOReturn status = kIOReturnSuccess;
UInt32 entry = 0;
const UInt32 *data;
UInt32 offset;
int len = 0;
status = checkROMState();
if( status == kIOReturnSuccess )
{
if( index < 0 || index >= fNumEntries )
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
data = lockData();
entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
unlockData();
if( ((entry & kConfigEntryKeyValue) >> kConfigEntryKeyValuePhase) != kConfigTextualDescriptorKey )
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
if( ((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) != kConfigLeafKeyType )
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
status = getIndexOffset(index, offset);
}
if( status == kIOReturnSuccess )
{
status = updateROMCache(offset, 1);
}
if( status == kIOReturnSuccess )
{
data = lockData();
len = (OSSwapBigToHostInt32(data[offset]) & kConfigLeafDirLength) >> kConfigLeafDirLengthPhase;
unlockData();
if( (len * 4) > 256 )
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
FWKLOG(( "IOConfigDirectory::getIndexValue(OSString) updateROMCache( %ld, %d )\n", offset, len ));
status = updateROMCache(offset + 1,len);
}
if( status == kIOReturnSuccess )
{
data = lockData();
char *text = (char *)(&data[offset+3]);
len -= 2; len *= sizeof(UInt32);
while(len && !*text) {
len--;
text++;
}
if(len) {
char saved = text[len];
text[len] = 0;
value = OSString::withCString(text);
text[len] = saved;
}
else
value = OSString::withCString("");
unlockData();
if( value == NULL )
status = kIOReturnNoMemory;
}
return status;
}
IOReturn IOConfigDirectory::getIndexValue(int index, IOConfigDirectory *&value)
{
IOReturn status = kIOReturnSuccess;
UInt32 entry = 0;
UInt32 offset;
status = checkROMState();
if( status == kIOReturnSuccess )
{
if( index < 0 || index >= fNumEntries )
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
const UInt32 * data = lockData();
entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
unlockData();
if( ((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) != kConfigDirectoryKeyType)
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
status = getIndexOffset(index, offset);
}
if( status == kIOReturnSuccess )
{
value = getSubDir( offset, (entry & kConfigEntryKeyValue) >> kConfigEntryKeyValuePhase );
if( value == NULL )
status = kIOReturnNoMemory;
}
return status;
}
IOReturn IOConfigDirectory::getIndexOffset(int index, FWAddress &value)
{
IOReturn status = kIOReturnSuccess;
UInt32 entry = 0;
UInt32 offset;
status = checkROMState();
if( status == kIOReturnSuccess )
{
if( index < 0 || index >= fNumEntries )
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
const UInt32 * data = lockData();
entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
unlockData();
if(((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) == kConfigImmediateKeyType)
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
value.addressHi = kCSRRegisterSpaceBaseAddressHi;
offset = entry & kConfigEntryValue;
if(((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) == kConfigOffsetKeyType)
{
value.addressLo = kCSRRegisterSpaceBaseAddressLo + offset*sizeof(UInt32);
}
else
{
offset += fStart + 1 + index;
value.addressLo = kConfigROMBaseAddress + offset*sizeof(UInt32);
}
}
return status;
}
IOReturn IOConfigDirectory::getIndexOffset(int index, UInt32 &value)
{
IOReturn status = kIOReturnSuccess;
UInt32 entry = 0;
status = checkROMState();
if( status == kIOReturnSuccess )
{
if( index < 0 || index >= fNumEntries )
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
const UInt32 * data = lockData();
entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
unlockData();
if(((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) == kConfigImmediateKeyType)
{
status = kIOReturnBadArgument;
}
else if(((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) == kConfigOffsetKeyType)
{
status = kIOReturnBadArgument;
}
}
if( status == kIOReturnSuccess )
{
value = entry & kConfigEntryValue;
value += fStart + 1 + index;
}
return status;
}
IOReturn IOConfigDirectory::getIndexEntry(int index, UInt32 &value)
{
IOReturn status = kIOReturnSuccess;
status = checkROMState();
if( status == kIOReturnSuccess )
{
if( index < 0 || index >= fNumEntries )
status = kIOReturnBadArgument;
}
if( status == kIOReturnSuccess )
{
const UInt32 * data = lockData();
value = OSSwapBigToHostInt32(data[fStart + 1 + index]);
unlockData();
}
return status;
}
IOReturn IOConfigDirectory::getSubdirectories(OSIterator *&iterator)
{
return createIterator(kConfigDirectoryKeyType << kConfigEntryKeyTypePhase,
kConfigEntryKeyType, iterator);
}