IORegistryEntry.cpp [plain text]
#include <IOKit/IORegistryEntry.h>
#include <libkern/c++/OSContainers.h>
#include <IOKit/IOService.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/IOLib.h>
#include <IOKit/assert.h>
#define super OSObject
OSDefineMetaClassAndStructors(IORegistryEntry, OSObject)
#define kIORegPlaneParentSuffix "ParentLinks"
#define kIORegPlaneChildSuffix "ChildLinks"
#define kIORegPlaneNameSuffix "Name"
#define kIORegPlaneLocationSuffix "Location"
#define kIORegPlaneParentSuffixLen (sizeof(kIORegPlaneParentSuffix) - 1)
static IORegistryEntry * gRegistryRoot;
static OSDictionary * gIORegistryPlanes;
const OSSymbol * gIONameKey;
const OSSymbol * gIOLocationKey;
enum {
kParentSetIndex = 0,
kChildSetIndex = 1,
kNumSetIndex
};
enum {
kIOMaxPlaneName = 32
};
class IORegistryPlane : public OSObject {
friend class IORegistryEntry;
OSDeclareAbstractStructors(IORegistryPlane)
const OSSymbol * nameKey;
const OSSymbol * keys[ kNumSetIndex ];
const OSSymbol * pathNameKey;
const OSSymbol * pathLocationKey;
int reserved[2];
public:
virtual bool serialize(OSSerialize *s) const;
};
OSDefineMetaClassAndStructors(IORegistryPlane, OSObject)
static IORecursiveLock * gPropertiesLock;
static SInt32 gIORegistryGenerationCount;
#define UNLOCK s_lock_done( &gIORegistryLock )
#define RLOCK s_lock_read( &gIORegistryLock )
#define WLOCK s_lock_write( &gIORegistryLock ); \
gIORegistryGenerationCount++
#define PUNLOCK IORecursiveLockUnlock( gPropertiesLock )
#define PLOCK IORecursiveLockLock( gPropertiesLock )
#define IOREGSPLITTABLES
#ifdef IOREGSPLITTABLES
#define registryTable() fRegistryTable
#else
#define registryTable() fPropertyTable
#endif
#define DEBUG_FREE 1
struct s_lock_t {
lck_spin_t interlock;
volatile unsigned int
read_count:16,
want_upgrade:1,
want_write:1,
waiting:1,
can_sleep:1;
};
static struct s_lock_t gIORegistryLock;
static unsigned int lock_wait_time[2] = { (unsigned int)-1, 100 } ;
static void
s_lock_init(
s_lock_t *l,
boolean_t can_sleep)
{
(void) memset((void *) l, 0, sizeof(s_lock_t));
lck_spin_init(&l->interlock, IOLockGroup, LCK_ATTR_NULL);
l->want_write = FALSE;
l->want_upgrade = FALSE;
l->read_count = 0;
l->can_sleep = can_sleep;
}
static void
s_lock_write(
register s_lock_t * l)
{
register int i;
lck_spin_lock(&l->interlock);
while (l->want_write) {
i = lock_wait_time[l->can_sleep ? 1 : 0];
if (i != 0) {
lck_spin_unlock(&l->interlock);
while (--i != 0 && l->want_write)
continue;
lck_spin_lock(&l->interlock);
}
if (l->can_sleep && l->want_write) {
l->waiting = TRUE;
lck_spin_sleep( &l->interlock, LCK_SLEEP_DEFAULT,
(event_t) l, THREAD_UNINT);
}
}
l->want_write = TRUE;
while ((l->read_count != 0) || l->want_upgrade) {
i = lock_wait_time[l->can_sleep ? 1 : 0];
if (i != 0) {
lck_spin_unlock(&l->interlock);
while (--i != 0 && (l->read_count != 0 ||
l->want_upgrade))
continue;
lck_spin_lock(&l->interlock);
}
if (l->can_sleep && (l->read_count != 0 || l->want_upgrade)) {
l->waiting = TRUE;
lck_spin_sleep( &l->interlock, LCK_SLEEP_DEFAULT,
(event_t) l, THREAD_UNINT);
}
}
lck_spin_unlock(&l->interlock);
}
static void
s_lock_done(
register s_lock_t * l)
{
boolean_t do_wakeup = FALSE;
lck_spin_lock(&l->interlock);
if (l->read_count != 0) {
l->read_count -= 1;
}
else {
if (l->want_upgrade) {
l->want_upgrade = FALSE;
}
else {
l->want_write = FALSE;
}
}
if (l->waiting && (l->read_count == 0)) {
l->waiting = FALSE;
do_wakeup = TRUE;
}
lck_spin_unlock(&l->interlock);
if (do_wakeup)
thread_wakeup((event_t) l);
}
static void
s_lock_read(
register s_lock_t * l)
{
register int i;
lck_spin_lock(&l->interlock);
while ( l->want_upgrade || ((0 == l->read_count) && l->want_write )) {
i = lock_wait_time[l->can_sleep ? 1 : 0];
if (i != 0) {
lck_spin_unlock(&l->interlock);
while (--i != 0 &&
(l->want_upgrade || ((0 == l->read_count) && l->want_write )))
continue;
lck_spin_lock(&l->interlock);
}
if (l->can_sleep &&
(l->want_upgrade || ((0 == l->read_count) && l->want_write ))) {
l->waiting = TRUE;
lck_spin_sleep( &l->interlock, LCK_SLEEP_DEFAULT,
(event_t) l, THREAD_UNINT);
}
}
l->read_count += 1;
lck_spin_unlock(&l->interlock);
}
IORegistryEntry * IORegistryEntry::initialize( void )
{
bool ok;
if( !gRegistryRoot) {
s_lock_init( &gIORegistryLock, true );
gRegistryRoot = new IORegistryEntry;
gPropertiesLock = IORecursiveLockAlloc();
gIORegistryPlanes = OSDictionary::withCapacity( 1 );
assert( gRegistryRoot && gPropertiesLock
&& gIORegistryPlanes );
ok = gRegistryRoot->init();
gIONameKey = OSSymbol::withCStringNoCopy( "IOName" );
gIOLocationKey = OSSymbol::withCStringNoCopy( "IOLocation" );
assert( ok && gIONameKey && gIOLocationKey );
gRegistryRoot->setName( "Root" );
gRegistryRoot->setProperty( kIORegistryPlanesKey, gIORegistryPlanes );
}
return( gRegistryRoot );
}
IORegistryEntry * IORegistryEntry::getRegistryRoot( void )
{
return( gRegistryRoot );
}
SInt32 IORegistryEntry::getGenerationCount( void )
{
return( gIORegistryGenerationCount );
}
const IORegistryPlane * IORegistryEntry::makePlane( const char * name )
{
IORegistryPlane * plane;
const OSSymbol * nameKey;
const OSSymbol * parentKey;
const OSSymbol * childKey;
const OSSymbol * pathNameKey;
const OSSymbol * pathLocationKey;
char key[ kIOMaxPlaneName + 16 ];
char * end;
strncpy( key, name, kIOMaxPlaneName );
key[ kIOMaxPlaneName ] = 0;
end = key + strlen( name );
nameKey = OSSymbol::withCString( key);
strcpy( end, kIORegPlaneParentSuffix );
parentKey = OSSymbol::withCString( key);
strcpy( end, kIORegPlaneChildSuffix );
childKey = OSSymbol::withCString( key);
strcpy( end, kIORegPlaneNameSuffix );
pathNameKey = OSSymbol::withCString( key);
strcpy( end, kIORegPlaneLocationSuffix );
pathLocationKey = OSSymbol::withCString( key);
plane = new IORegistryPlane;
if( plane && plane->init()
&& nameKey && parentKey && childKey
&& pathNameKey && pathLocationKey ) {
plane->nameKey = nameKey;
plane->keys[ kParentSetIndex ] = parentKey;
plane->keys[ kChildSetIndex ] = childKey;
plane->pathNameKey = pathNameKey;
plane->pathLocationKey = pathLocationKey;
WLOCK;
gIORegistryPlanes->setObject( nameKey, plane );
UNLOCK;
} else {
if( plane)
plane->release();
if( pathLocationKey)
pathLocationKey->release();
if( pathNameKey)
pathNameKey->release();
if( parentKey)
parentKey->release();
if( childKey)
childKey->release();
if( nameKey)
nameKey->release();
plane = 0;
}
return( plane);
}
const IORegistryPlane * IORegistryEntry::getPlane( const char * name )
{
const IORegistryPlane * plane;
RLOCK;
plane = (const IORegistryPlane *) gIORegistryPlanes->getObject( name );
UNLOCK;
return( plane );
}
bool IORegistryPlane::serialize(OSSerialize *s) const
{
return( nameKey->serialize(s) );
}
enum { kIORegCapacityIncrement = 4 };
bool IORegistryEntry::init( OSDictionary * dict )
{
OSString * prop;
if( !super::init())
return( false);
if( dict) {
dict->retain();
if( fPropertyTable)
fPropertyTable->release();
fPropertyTable = dict;
} else if( !fPropertyTable) {
fPropertyTable = OSDictionary::withCapacity( kIORegCapacityIncrement );
if( fPropertyTable)
fPropertyTable->setCapacityIncrement( kIORegCapacityIncrement );
}
if( !fPropertyTable)
return( false);
#ifdef IOREGSPLITTABLES
if( !fRegistryTable) {
fRegistryTable = OSDictionary::withCapacity( kIORegCapacityIncrement );
if( fRegistryTable)
fRegistryTable->setCapacityIncrement( kIORegCapacityIncrement );
}
if( (prop = OSDynamicCast( OSString, getProperty( gIONameKey)))) {
OSSymbol * sym = (OSSymbol *)OSSymbol::withString( prop);
setName( sym);
sym->release();
}
#endif
return( true);
}
bool IORegistryEntry::init( IORegistryEntry * old,
const IORegistryPlane * plane )
{
OSArray * all;
IORegistryEntry * next;
unsigned int index;
if( !super::init())
return( false);
WLOCK;
fPropertyTable = old->getPropertyTable();
fPropertyTable->retain();
#ifdef IOREGSPLITTABLES
fRegistryTable = old->fRegistryTable;
old->fRegistryTable = OSDictionary::withDictionary( fRegistryTable );
#endif
old->registryTable()->removeObject( plane->keys[ kParentSetIndex ] );
old->registryTable()->removeObject( plane->keys[ kChildSetIndex ] );
all = getParentSetReference( plane );
if( all) for( index = 0;
(next = (IORegistryEntry *) all->getObject(index));
index++ ) {
next->makeLink( this, kChildSetIndex, plane );
next->breakLink( old, kChildSetIndex, plane );
}
all = getChildSetReference( plane );
if( all) for( index = 0;
(next = (IORegistryEntry *) all->getObject(index));
index++ ) {
next->makeLink( this, kParentSetIndex, plane );
next->breakLink( old, kParentSetIndex, plane );
}
UNLOCK;
return( true );
}
void IORegistryEntry::free( void )
{
#if DEBUG_FREE
#define msg ": attached at free()"
char buf[ strlen(msg) + 40 ];
if( registryTable() && gIOServicePlane) {
if( getParentSetReference( gIOServicePlane )
|| getChildSetReference( gIOServicePlane )) {
strncpy( buf, getName(), 32);
buf[32] = 0;
strcat( buf, msg );
IOPanic( buf );
}
}
#endif
if( getPropertyTable())
getPropertyTable()->release();
#ifdef IOREGSPLITTABLES
if( registryTable())
registryTable()->release();
#endif
super::free();
}
void IORegistryEntry::setPropertyTable( OSDictionary * dict )
{
if( fPropertyTable)
fPropertyTable->release();
if( dict)
dict->retain();
fPropertyTable = dict;
}
#define wrap2(type, constant) \
OSObject * \
IORegistryEntry::copyProperty( type * aKey) constant \
{ \
OSObject * obj; \
\
PLOCK; \
obj = getProperty( aKey ); \
if( obj) \
obj->retain(); \
PUNLOCK; \
\
return( obj ); \
}
#define wrap4(type,constant) \
OSObject * \
IORegistryEntry::getProperty( type * aKey, \
const IORegistryPlane * plane, \
IOOptionBits options ) constant \
{ \
OSObject * obj = getProperty( aKey ); \
\
if ( (0 == obj) && plane && (options & kIORegistryIterateRecursively) ) { \
IORegistryEntry * entry = (IORegistryEntry *) this; \
IORegistryIterator * iter; \
iter = IORegistryIterator::iterateOver( entry, plane, options ); \
\
if(iter) { \
while ( (0 == obj) && (entry = iter->getNextObject()) ) { \
obj = entry->getProperty( aKey ); \
} \
iter->release(); \
} \
} \
\
return( obj ); \
}
#define wrap5(type,constant) \
OSObject * \
IORegistryEntry::copyProperty( type * aKey, \
const IORegistryPlane * plane, \
IOOptionBits options ) constant \
{ \
OSObject * obj = copyProperty( aKey ); \
\
if ( (0 == obj) && plane && (options & kIORegistryIterateRecursively) ) { \
IORegistryEntry * entry = (IORegistryEntry *) this; \
IORegistryIterator * iter; \
iter = IORegistryIterator::iterateOver( entry, plane, options ); \
\
if(iter) { \
while ( (0 == obj) && (entry = iter->getNextObject()) ) { \
obj = entry->copyProperty( aKey ); \
} \
iter->release(); \
} \
} \
\
return( obj ); \
}
bool IORegistryEntry::serializeProperties( OSSerialize * s ) const
{
PLOCK;
OSCollection *snapshotProperties = getPropertyTable()->copyCollection();
PUNLOCK;
bool ok = snapshotProperties->serialize( s );
snapshotProperties->release();
return( ok );
}
OSDictionary * IORegistryEntry::dictionaryWithProperties( void ) const
{
OSDictionary * dict;
PLOCK;
dict = OSDictionary::withDictionary( getPropertyTable(),
getPropertyTable()->getCapacity() );
PUNLOCK;
return( dict );
}
IOReturn IORegistryEntry::setProperties( OSObject * properties )
{
return( kIOReturnUnsupported );
}
wrap2(const OSSymbol, const) wrap2(const OSString, const) wrap2(const char, const)
wrap4(const OSSymbol, const) wrap4(const OSString, const) wrap4(const char, const)
wrap5(const OSSymbol, const) wrap5(const OSString, const) wrap5(const char, const)
OSObject *
IORegistryEntry::getProperty( const OSSymbol * aKey) const
{
OSObject * obj;
PLOCK;
obj = getPropertyTable()->getObject( aKey );
PUNLOCK;
return( obj );
}
void
IORegistryEntry::removeProperty( const OSSymbol * aKey)
{
PLOCK;
getPropertyTable()->removeObject( aKey );
PUNLOCK;
}
bool
IORegistryEntry::setProperty( const OSSymbol * aKey, OSObject * anObject)
{
bool ret = false;
OSCollection *coll = OSDynamicCast(OSCollection, anObject);
bool makeImmutable = (coll && inPlane());
PLOCK;
if( makeImmutable )
coll->setOptions( OSCollection::kMASK, OSCollection::kImmutable );
ret = getPropertyTable()->setObject( aKey, anObject );
PUNLOCK;
return ret;
}
IOReturn IORegistryEntry::
runPropertyAction(Action inAction, OSObject *target,
void *arg0, void *arg1, void *arg2, void *arg3)
{
IOReturn res;
PLOCK;
res = (*inAction)(target, arg0, arg1, arg2, arg3);
PUNLOCK;
return res;
}
OSObject *
IORegistryEntry::getProperty( const OSString * aKey) const
{
const OSSymbol * tmpKey = OSSymbol::withString( aKey );
OSObject * obj = getProperty( tmpKey );
tmpKey->release();
return( obj );
}
OSObject *
IORegistryEntry::getProperty( const char * aKey) const
{
const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
OSObject * obj = getProperty( tmpKey );
tmpKey->release();
return( obj );
}
void
IORegistryEntry::removeProperty( const OSString * aKey)
{
const OSSymbol * tmpKey = OSSymbol::withString( aKey );
removeProperty( tmpKey );
tmpKey->release();
}
void
IORegistryEntry::removeProperty( const char * aKey)
{
const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
removeProperty( tmpKey );
tmpKey->release();
}
bool
IORegistryEntry::setProperty( const OSString * aKey, OSObject * anObject)
{
const OSSymbol * tmpKey = OSSymbol::withString( aKey );
bool ret = setProperty( tmpKey, anObject );
tmpKey->release();
return ret;
}
bool
IORegistryEntry::setProperty( const char * aKey, OSObject * anObject)
{
const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
bool ret = setProperty( tmpKey, anObject );
tmpKey->release();
return ret;
}
bool
IORegistryEntry::setProperty(const char * aKey, const char * aString)
{
bool ret = false;
OSSymbol * aSymbol = (OSSymbol *) OSSymbol::withCString( aString );
if( aSymbol) {
const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
ret = setProperty( tmpKey, aSymbol );
tmpKey->release();
aSymbol->release();
}
return( ret );
}
bool
IORegistryEntry::setProperty(const char * aKey, bool aBoolean)
{
bool ret = false;
OSBoolean * aBooleanObj = OSBoolean::withBoolean( aBoolean );
if( aBooleanObj) {
const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
ret = setProperty( tmpKey, aBooleanObj );
tmpKey->release();
aBooleanObj->release();
}
return( ret );
}
bool
IORegistryEntry::setProperty( const char * aKey,
unsigned long long aValue,
unsigned int aNumberOfBits)
{
bool ret = false;
OSNumber * anOffset = OSNumber::withNumber( aValue, aNumberOfBits );
if( anOffset) {
const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
ret = setProperty( tmpKey, anOffset );
tmpKey->release();
anOffset->release();
}
return( ret );
}
bool
IORegistryEntry::setProperty( const char * aKey,
void * bytes,
unsigned int length)
{
bool ret = false;
OSData * data = OSData::withBytes( bytes, length );
if( data) {
const OSSymbol * tmpKey = OSSymbol::withCString( aKey );
ret = setProperty( tmpKey, data );
tmpKey->release();
data->release();
}
return( ret );
}
const char * IORegistryEntry::getName( const IORegistryPlane * plane ) const
{
OSSymbol * sym = 0;
RLOCK;
if( plane)
sym = (OSSymbol *) registryTable()->getObject( plane->pathNameKey );
if( !sym)
sym = (OSSymbol *) registryTable()->getObject( gIONameKey );
UNLOCK;
if( sym)
return( sym->getCStringNoCopy());
else
return( (getMetaClass())->getClassName());
}
const OSSymbol * IORegistryEntry::copyName(
const IORegistryPlane * plane ) const
{
OSSymbol * sym = 0;
RLOCK;
if( plane)
sym = (OSSymbol *) registryTable()->getObject( plane->pathNameKey );
if( !sym)
sym = (OSSymbol *) registryTable()->getObject( gIONameKey );
if( sym)
sym->retain();
UNLOCK;
if( sym)
return( sym );
else
return( OSSymbol::withCString((getMetaClass())->getClassName()) );
}
const OSSymbol * IORegistryEntry::copyLocation(
const IORegistryPlane * plane ) const
{
OSSymbol * sym = 0;
RLOCK;
if( plane)
sym = (OSSymbol *) registryTable()->getObject( plane->pathLocationKey );
if( !sym)
sym = (OSSymbol *) registryTable()->getObject( gIOLocationKey );
if( sym)
sym->retain();
UNLOCK;
return( sym );
}
const char * IORegistryEntry::getLocation( const IORegistryPlane * plane ) const
{
const OSSymbol * sym = copyLocation( plane );
const char * result = 0;
if( sym) {
result = sym->getCStringNoCopy();
sym->release();
}
return( result );
}
void IORegistryEntry::setName( const OSSymbol * name,
const IORegistryPlane * plane )
{
const OSSymbol * key;
if( name) {
if( plane)
key = plane->pathNameKey;
else
key = gIONameKey;
WLOCK;
registryTable()->setObject( key, (OSObject *) name);
UNLOCK;
}
}
void IORegistryEntry::setName( const char * name,
const IORegistryPlane * plane )
{
OSSymbol * sym = (OSSymbol *)OSSymbol::withCString( name );
if ( sym ) {
setName( sym, plane );
sym->release();
}
}
void IORegistryEntry::setLocation( const OSSymbol * location,
const IORegistryPlane * plane )
{
const OSSymbol * key;
if( location) {
if( plane)
key = plane->pathLocationKey;
else
key = gIOLocationKey;
WLOCK;
registryTable()->setObject( key, (OSObject *) location);
UNLOCK;
}
}
void IORegistryEntry::setLocation( const char * location,
const IORegistryPlane * plane )
{
OSSymbol * sym = (OSSymbol *)OSSymbol::withCString( location );
if ( sym ) {
setLocation( sym, plane );
sym->release();
}
}
bool
IORegistryEntry::compareName( OSString * name, OSString ** matched ) const
{
const OSSymbol * sym = copyName();
bool isEqual;
isEqual = sym->isEqualTo( name );
if( isEqual && matched) {
name->retain();
*matched = name;
}
if( sym)
sym->release();
return( isEqual );
}
bool
IORegistryEntry::compareNames( OSObject * names, OSString ** matched ) const
{
OSString * string;
OSCollection * collection;
OSIterator * iter = 0;
bool result = false;
if( (collection = OSDynamicCast( OSCollection, names))) {
iter = OSCollectionIterator::withCollection( collection );
string = 0;
} else
string = OSDynamicCast( OSString, names);
do {
if( string)
result = compareName( string, matched );
} while( (false == result)
&& iter && (string = OSDynamicCast( OSString, iter->getNextObject())));
if( iter)
iter->release();
return( result);
}
bool IORegistryEntry::getPath( char * path, int * length,
const IORegistryPlane * plane ) const
{
OSArray * stack;
IORegistryEntry * root;
const IORegistryEntry * entry;
IORegistryEntry * parent;
const OSSymbol * alias;
int index;
int len, maxLength, compLen;
char * nextComp;
bool ok;
if( !path || !length || !plane)
return( false);
len = 0;
maxLength = *length - 2;
nextComp = path;
len = plane->nameKey->getLength();
if( len >= maxLength)
return( false);
strcpy( nextComp, plane->nameKey->getCStringNoCopy());
nextComp[ len++ ] = ':';
nextComp += len;
if( (alias = hasAlias( plane ))) {
len += alias->getLength();
ok = (maxLength > len);
*length = len;
if( ok)
strcpy( nextComp, alias->getCStringNoCopy());
return( ok );
}
entry = this;
parent = entry->getParentEntry( plane );
if( !parent)
return( false);
stack = OSArray::withCapacity( getDepth( plane ));
if( !stack)
return( false);
RLOCK;
root = gRegistryRoot->getChildEntry( plane );
while( parent && (entry != root)) {
stack->setObject( (OSObject *) entry );
entry = parent;
parent = entry->getParentEntry( plane );
}
index = stack->getCount();
ok = true;
if( 0 == index) {
*nextComp++ = '/';
*nextComp = 0;
len++;
} else while( ok && ((--index) >= 0)) {
entry = (IORegistryEntry *) stack->getObject((unsigned int) index );
assert( entry );
if( (alias = entry->hasAlias( plane ))) {
len = plane->nameKey->getLength() + 1;
nextComp = path + len;
compLen = alias->getLength();
ok = (maxLength > len + compLen);
if( ok)
strcpy( nextComp, alias->getCStringNoCopy());
} else {
compLen = maxLength - len;
ok = entry->getPathComponent( nextComp + 1, &compLen, plane );
if( ok && compLen) {
compLen++;
*nextComp = '/';
}
}
if( ok) {
len += compLen;
nextComp += compLen;
}
}
*length = len;
UNLOCK;
stack->release();
return( ok );
}
bool IORegistryEntry::getPathComponent( char * path, int * length,
const IORegistryPlane * plane ) const
{
int len, locLen, maxLength;
const char * compName;
const char * loc;
bool ok;
maxLength = *length;
compName = getName( plane );
len = strlen( compName );
if( (loc = getLocation( plane )))
locLen = 1 + strlen( loc );
else
locLen = 0;
ok = ((len + locLen) < maxLength);
if( ok) {
strcpy( path, compName );
if( loc) {
path += len;
len += locLen;
*path++ = '@';
strcpy( path, loc );
}
*length = len;
}
return( ok );
}
const char * IORegistryEntry::matchPathLocation( const char * cmp,
const IORegistryPlane * plane )
{
const char * str;
const char * result = 0;
u_quad_t num1, num2;
char lastPathChar, lastLocationChar;
str = getLocation( plane );
if( str) {
lastPathChar = cmp[0];
lastLocationChar = str[0];
do {
if( lastPathChar) {
num1 = strtouq( cmp, (char **) &cmp, 16 );
lastPathChar = *cmp++;
} else
num1 = 0;
if( lastLocationChar) {
num2 = strtouq( str, (char **) &str, 16 );
lastLocationChar = *str++;
} else
num2 = 0;
if( num1 != num2)
break;
if (!lastPathChar && !lastLocationChar) {
result = cmp - 1;
break;
}
if( (',' != lastPathChar) && (':' != lastPathChar))
lastPathChar = 0;
if (lastPathChar && lastLocationChar && (lastPathChar != lastLocationChar))
break;
} while( true);
}
return( result );
}
IORegistryEntry * IORegistryEntry::getChildFromComponent( const char ** opath,
const IORegistryPlane * plane )
{
IORegistryEntry * entry = 0;
OSArray * set;
unsigned int index;
const char * path;
const char * cmp = 0;
char c;
size_t len;
const char * str;
set = getChildSetReference( plane );
if( set) {
path = *opath;
for( index = 0;
(entry = (IORegistryEntry *) set->getObject(index));
index++ ) {
cmp = path;
if( *cmp != '@') {
str = entry->getName( plane );
len = strlen( str );
if( strncmp( str, cmp, len ))
continue;
cmp += len;
c = *cmp;
if( (c == 0) || (c == '/') || (c == ':'))
break;
if( c != '@')
continue;
}
cmp++;
if( (cmp = entry->matchPathLocation( cmp, plane )))
break;
}
if( entry)
*opath = cmp;
}
return( entry );
}
const OSSymbol * IORegistryEntry::hasAlias( const IORegistryPlane * plane,
char * opath, int * length ) const
{
IORegistryEntry * entry;
IORegistryEntry * entry2;
const OSSymbol * key;
const OSSymbol * bestKey = 0;
OSIterator * iter;
OSData * data;
const char * path = "/aliases";
entry = IORegistryEntry::fromPath( path, plane );
if( entry) {
RLOCK;
if( (iter = OSCollectionIterator::withCollection(
entry->getPropertyTable() ))) {
while( (key = (OSSymbol *) iter->getNextObject())) {
data = (OSData *) entry->getProperty( key );
path = (const char *) data->getBytesNoCopy();
if( (entry2 = IORegistryEntry::fromPath( path, plane,
opath, length ))) {
if( this == entry2) {
if( !bestKey
|| (bestKey->getLength() > key->getLength()))
bestKey = key;
}
entry2->release();
}
}
iter->release();
}
entry->release();
UNLOCK;
}
return( bestKey );
}
const char * IORegistryEntry::dealiasPath(
const char ** opath,
const IORegistryPlane * plane )
{
IORegistryEntry * entry;
OSData * data;
const char * path = *opath;
const char * rpath = 0;
const char * end;
char c;
char temp[ kIOMaxPlaneName + 1 ];
if( path[0] == '/')
return( rpath );
end = path;
while( (c = *end++) && (c != '/') && (c != ':'))
{}
end--;
if( (end - path) < kIOMaxPlaneName) {
strncpy( temp, path, end - path );
temp[ end - path ] = 0;
RLOCK;
entry = IORegistryEntry::fromPath( "/aliases", plane );
if( entry) {
data = (OSData *) entry->getProperty( temp );
if( data ) {
rpath = (const char *) data->getBytesNoCopy();
if( rpath)
*opath = end;
}
entry->release();
}
UNLOCK;
}
return( rpath );
}
IORegistryEntry * IORegistryEntry::fromPath(
const char * path,
const IORegistryPlane * plane,
char * opath,
int * length,
IORegistryEntry * fromEntry )
{
IORegistryEntry * where = 0;
IORegistryEntry * aliasEntry = 0;
IORegistryEntry * next;
const char * alias;
const char * end;
int len = 0;
int len2;
char c;
char temp[ kIOMaxPlaneName + 1 ];
if( 0 == path)
return( 0 );
if( 0 == plane) {
end = strchr( path, ':' );
if( end && ((end - path) < kIOMaxPlaneName)) {
strncpy( temp, path, end - path );
temp[ end - path ] = 0;
plane = getPlane( temp );
path = end + 1;
}
}
if( 0 == plane)
return( 0 );
end = path;
if( (alias = dealiasPath( &end, plane))) {
if( length)
len = *length;
aliasEntry = IORegistryEntry::fromPath( alias, plane,
opath, &len, fromEntry );
where = aliasEntry;
if( where)
path = end;
else
len = 0;
}
RLOCK;
do {
if( 0 == where) {
if( (0 == fromEntry) && (*path++ == '/'))
fromEntry = gRegistryRoot->getChildEntry( plane );
where = fromEntry;
if( 0 == where)
break;
} else {
c = *path++;
if( c != '/') {
if( c && (c != ':')) where = 0;
break;
}
}
next = where->getChildFromComponent( &path, plane );
if( next)
where = next;
} while( next );
if( where) {
if( where != fromEntry)
path--;
if( opath && length) {
len2 = len + strlen( path );
if( len2 < *length)
strcpy( opath + len, path );
*length = len2;
} else if( path[0])
where = 0;
}
if( where)
where->retain();
if( aliasEntry)
aliasEntry->release();
UNLOCK;
return( where );
}
IORegistryEntry * IORegistryEntry::childFromPath(
const char * path,
const IORegistryPlane * plane,
char * opath,
int * len )
{
return( IORegistryEntry::fromPath( path, plane, opath, len, this ));
}
#define IOLinkIterator OSCollectionIterator
#undef super
#define super OSObject
inline bool IORegistryEntry::arrayMember( OSArray * set,
const IORegistryEntry * member,
unsigned int * index ) const
{
int i;
OSObject * probeObject;
for( i = 0; (probeObject = set->getObject(i)); i++) {
if (probeObject == (OSObject *) member) {
if( index)
*index = i;
return( true );
}
}
return( false );
}
bool IORegistryEntry::makeLink( IORegistryEntry * to,
unsigned int relation,
const IORegistryPlane * plane ) const
{
OSArray * links;
bool result = false;
if( (links = (OSArray *)
registryTable()->getObject( plane->keys[ relation ] ))) {
result = arrayMember( links, to );
if( !result)
result = links->setObject( to );
} else {
links = OSArray::withObjects( (const OSObject **) &to, 1, 1 );
result = (links != 0);
if( result) {
result = registryTable()->setObject( plane->keys[ relation ],
links );
links->release();
}
}
return( result);
}
void IORegistryEntry::breakLink( IORegistryEntry * to,
unsigned int relation,
const IORegistryPlane * plane ) const
{
OSArray * links;
unsigned int index;
if( (links = (OSArray *)
registryTable()->getObject( plane->keys[ relation ]))) {
if( arrayMember( links, to, &index )) {
links->removeObject( index );
if( 0 == links->getCount())
registryTable()->removeObject( plane->keys[ relation ]);
}
}
}
OSArray * IORegistryEntry::getParentSetReference(
const IORegistryPlane * plane ) const
{
if( plane)
return( (OSArray *) registryTable()->getObject(
plane->keys[ kParentSetIndex ]));
else
return( 0 );
}
OSIterator * IORegistryEntry::getParentIterator(
const IORegistryPlane * plane ) const
{
OSArray * links;
OSIterator * iter;
if( !plane)
return( 0 );
RLOCK;
links = getParentSetReference( plane );
if( 0 == links)
links = OSArray::withCapacity( 1 );
else
links = OSArray::withArray( links, links->getCount() );
UNLOCK;
iter = IOLinkIterator::withCollection( links );
if( links)
links->release();
return( iter );
}
IORegistryEntry * IORegistryEntry::copyParentEntry( const IORegistryPlane * plane ) const
{
IORegistryEntry * entry = 0;
OSArray * links;
RLOCK;
if( (links = getParentSetReference( plane ))) {
entry = (IORegistryEntry *) links->getObject( 0 );
entry->retain();
}
UNLOCK;
return( entry);
}
IORegistryEntry * IORegistryEntry::getParentEntry( const IORegistryPlane * plane ) const
{
IORegistryEntry * entry;
entry = copyParentEntry( plane );
if( entry)
entry->release();
return( entry );
}
OSArray * IORegistryEntry::getChildSetReference( const IORegistryPlane * plane ) const
{
if( plane)
return( (OSArray *) registryTable()->getObject(
plane->keys[ kChildSetIndex ]));
else
return( 0 );
}
OSIterator * IORegistryEntry::getChildIterator( const IORegistryPlane * plane ) const
{
OSArray * links;
OSIterator * iter;
if( !plane)
return( 0 );
RLOCK;
links = getChildSetReference( plane );
if( 0 == links)
links = OSArray::withCapacity( 1 );
else
links = OSArray::withArray( links, links->getCount() );
UNLOCK;
iter = IOLinkIterator::withCollection( links );
if( links)
links->release();
return( iter );
}
IORegistryEntry * IORegistryEntry::copyChildEntry(
const IORegistryPlane * plane ) const
{
IORegistryEntry * entry = 0;
OSArray * links;
RLOCK;
if( (links = getChildSetReference( plane ))) {
entry = (IORegistryEntry *) links->getObject( 0 );
entry->retain();
}
UNLOCK;
return( entry);
}
IORegistryEntry * IORegistryEntry::getChildEntry(
const IORegistryPlane * plane ) const
{
IORegistryEntry * entry;
entry = copyChildEntry( plane );
if( entry)
entry->release();
return( entry );
}
void IORegistryEntry::applyToChildren( IORegistryEntryApplierFunction applier,
void * context,
const IORegistryPlane * plane ) const
{
OSArray * array;
unsigned int index;
IORegistryEntry * next;
if( !plane)
return;
RLOCK;
array = OSArray::withArray( getChildSetReference( plane ));
UNLOCK;
if( array) {
for( index = 0;
(next = (IORegistryEntry *) array->getObject( index ));
index++)
(*applier)(next, context);
array->release();
}
}
void IORegistryEntry::applyToParents( IORegistryEntryApplierFunction applier,
void * context,
const IORegistryPlane * plane ) const
{
OSArray * array;
unsigned int index;
IORegistryEntry * next;
if( !plane)
return;
RLOCK;
array = OSArray::withArray( getParentSetReference( plane ));
UNLOCK;
if( array) {
for( index = 0;
(next = (IORegistryEntry *) array->getObject( index ));
index++)
(*applier)(next, context);
array->release();
}
}
bool IORegistryEntry::isChild( IORegistryEntry * child,
const IORegistryPlane * plane,
bool onlyChild ) const
{
OSArray * links;
bool ret = false;
RLOCK;
if( (links = getChildSetReference( plane ))) {
if( (!onlyChild) || (1 == links->getCount()))
ret = arrayMember( links, child );
}
if( ret && (links = child->getParentSetReference( plane )))
ret = arrayMember( links, this );
UNLOCK;
return( ret);
}
bool IORegistryEntry::isParent( IORegistryEntry * parent,
const IORegistryPlane * plane,
bool onlyParent ) const
{
OSArray * links;
bool ret = false;
RLOCK;
if( (links = getParentSetReference( plane ))) {
if( (!onlyParent) || (1 == links->getCount()))
ret = arrayMember( links, parent );
}
if( ret && (links = parent->getChildSetReference( plane )))
ret = arrayMember( links, this );
UNLOCK;
return( ret);
}
bool IORegistryEntry::inPlane( const IORegistryPlane * plane ) const
{
bool ret;
RLOCK;
if( plane)
ret = (0 != getParentSetReference( plane ));
else {
ret = false;
OSCollectionIterator *iter =
OSCollectionIterator::withCollection( registryTable());
if( iter) {
const OSSymbol *key;
while( (key = (OSSymbol *) iter->getNextObject()) ) {
const char *keysuffix;
keysuffix = key->getCStringNoCopy()
+ key->getLength() - kIORegPlaneParentSuffixLen;
if( !strcmp(keysuffix, kIORegPlaneParentSuffix) ) {
ret = true;
break;
}
}
iter->release();
}
}
UNLOCK;
return( ret );
}
bool IORegistryEntry::attachToParent( IORegistryEntry * parent,
const IORegistryPlane * plane )
{
OSArray * links;
bool ret;
bool needParent;
if( this == parent)
return( false );
WLOCK;
ret = makeLink( parent, kParentSetIndex, plane );
if( (links = parent->getChildSetReference( plane )))
needParent = (false == arrayMember( links, this ));
else
needParent = true;
UNLOCK;
PLOCK;
OSDictionary *ptable = getPropertyTable();
OSCollectionIterator *iter =
OSCollectionIterator::withCollection( ptable );
if( iter) {
const OSSymbol *key;
while( (key = (OSSymbol *) iter->getNextObject( ))) {
OSCollection *coll =
OSDynamicCast( OSCollection, ptable->getObject( key ));
if( coll) {
coll->setOptions( OSCollection::kMASK,
OSCollection::kImmutable );
}
}
iter->release();
}
PUNLOCK;
if( needParent)
ret &= parent->attachToChild( this, plane );
return( ret );
}
bool IORegistryEntry::attachToChild( IORegistryEntry * child,
const IORegistryPlane * plane )
{
OSArray * links;
bool ret;
bool needChild;
if( this == child)
return( false );
WLOCK;
ret = makeLink( child, kChildSetIndex, plane );
if( (links = child->getParentSetReference( plane )))
needChild = (false == arrayMember( links, this ));
else
needChild = true;
UNLOCK;
if( needChild)
ret &= child->attachToParent( this, plane );
return( ret );
}
void IORegistryEntry::detachFromParent( IORegistryEntry * parent,
const IORegistryPlane * plane )
{
OSArray * links;
bool needParent;
WLOCK;
parent->retain();
breakLink( parent, kParentSetIndex, plane );
if( (links = parent->getChildSetReference( plane )))
needParent = arrayMember( links, this );
else
needParent = false;
UNLOCK;
if( needParent)
parent->detachFromChild( this, plane );
parent->release();
}
void IORegistryEntry::detachFromChild( IORegistryEntry * child,
const IORegistryPlane * plane )
{
OSArray * links;
bool needChild;
WLOCK;
child->retain();
breakLink( child, kChildSetIndex, plane );
if( (links = child->getParentSetReference( plane )))
needChild = arrayMember( links, this );
else
needChild = false;
UNLOCK;
if( needChild)
child->detachFromParent( this, plane );
child->release();
}
void IORegistryEntry::detachAbove( const IORegistryPlane * plane )
{
IORegistryEntry * parent;
retain();
while( (parent = getParentEntry( plane )))
detachFromParent( parent, plane );
release();
}
void IORegistryEntry::detachAll( const IORegistryPlane * plane )
{
OSOrderedSet * all;
IORegistryEntry * next;
IORegistryIterator * regIter;
regIter = IORegistryIterator::iterateOver( this, plane, true );
if( 0 == regIter)
return;
all = regIter->iterateAll();
regIter->release();
detachAbove( plane );
if( all) {
while( (next = (IORegistryEntry *) all->getLastObject())) {
next->retain();
all->removeObject(next);
next->detachAbove( plane );
next->release();
}
all->release();
}
}
unsigned int IORegistryEntry::getDepth( const IORegistryPlane * plane ) const
{
unsigned int depth = 1;
OSArray * parents;
unsigned int oneDepth, maxParentDepth, count;
IORegistryEntry * one;
const IORegistryEntry * next;
unsigned int index;
RLOCK;
next = this;
while( (parents = next->getParentSetReference( plane ))) {
count = parents->getCount();
if( 0 == count)
break;
if( 1 == count) {
depth++;
next = (IORegistryEntry *) parents->getObject( 0 );
} else {
maxParentDepth = 0;
for( index = 0;
(one = (IORegistryEntry *) parents->getObject( index ));
index++ ) {
oneDepth = one->getDepth( plane );
if( oneDepth > maxParentDepth)
maxParentDepth = oneDepth;
}
depth += maxParentDepth;
break;
}
}
UNLOCK;
return( depth);
}
#undef super
#define super OSIterator
OSDefineMetaClassAndStructors(IORegistryIterator, OSIterator)
enum { kIORegistryIteratorInvalidFlag = 0x80000000 };
IORegistryIterator *
IORegistryIterator::iterateOver( IORegistryEntry * root,
const IORegistryPlane * plane,
IOOptionBits options )
{
IORegistryIterator * create;
if( 0 == root)
return( 0);
if( 0 == plane)
return( 0);
create = new IORegistryIterator;
if( create) {
if( create->init()) {
root->retain();
create->root = root;
create->where = &create->start;
create->start.current = root;
create->plane = plane;
create->options = options & ~kIORegistryIteratorInvalidFlag;
} else {
create->release();
create = 0;
}
}
return( create);
}
IORegistryIterator *
IORegistryIterator::iterateOver( const IORegistryPlane * plane,
IOOptionBits options )
{
return( iterateOver( gRegistryRoot, plane, options ));
}
bool IORegistryIterator::isValid( void )
{
bool ok;
IORegCursor * next;
next = where;
RLOCK;
ok = (0 == (kIORegistryIteratorInvalidFlag & options));
while( ok && next) {
if( where->iter)
ok = where->iter->isValid();
next = next->next;
}
UNLOCK;
return( ok);
}
void IORegistryIterator::enterEntry( const IORegistryPlane * enterPlane )
{
IORegCursor * prev;
prev = where;
where = (IORegCursor *) IOMalloc( sizeof( IORegCursor));
assert( where);
if( where) {
where->iter = 0;
where->next = prev;
where->current = prev->current;
plane = enterPlane;
}
}
void IORegistryIterator::enterEntry( void )
{
enterEntry( plane );
}
bool IORegistryIterator::exitEntry( void )
{
IORegCursor * gone;
if( where->iter) {
where->iter->release();
where->iter = 0;
if( where->current) where->current->release();
}
if( where != &start) {
gone = where;
where = gone->next;
IOFree( gone, sizeof( IORegCursor));
return( true);
} else
return( false);
}
void IORegistryIterator::reset( void )
{
while( exitEntry())
{}
if( done) {
done->release();
done = 0;
}
where->current = root;
options &= ~kIORegistryIteratorInvalidFlag;
}
void IORegistryIterator::free( void )
{
reset();
if( root)
root->release();
super::free();
}
IORegistryEntry * IORegistryIterator::getNextObjectFlat( void )
{
IORegistryEntry * next = 0;
OSArray * links = 0;
RLOCK;
if( (0 == where->iter)) {
if( isValid()
&& where->current
&& (links = ( (options & kIORegistryIterateParents) ?
where->current->getParentSetReference( plane ) :
where->current->getChildSetReference( plane ) )) )
where->iter = OSCollectionIterator::withCollection( links );
} else
if( where->current)
where->current->release();
if( where->iter) {
next = (IORegistryEntry *) where->iter->getNextObject();
if( next)
next->retain();
else if( !where->iter->isValid())
options |= kIORegistryIteratorInvalidFlag;
}
where->current = next;
UNLOCK;
return( next);
}
IORegistryEntry * IORegistryIterator::getNextObjectRecursive( void )
{
IORegistryEntry * next;
do
next = getNextObjectFlat();
while( (0 == next) && exitEntry());
if( next) {
if( 0 == done)
done = OSOrderedSet::withCapacity( 10 );
if( done->setObject((OSObject *) next)) {
enterEntry();
}
}
return( next);
}
IORegistryEntry * IORegistryIterator::getNextObject( void )
{
if( options & kIORegistryIterateRecursively)
return( getNextObjectRecursive());
else
return( getNextObjectFlat());
}
IORegistryEntry * IORegistryIterator::getCurrentEntry( void )
{
if( isValid())
return( where->current);
else
return( 0);
}
OSOrderedSet * IORegistryIterator::iterateAll( void )
{
reset();
while( getNextObjectRecursive())
{}
if( done)
done->retain();
return( done);
}
OSMetaClassDefineReservedUsed(IORegistryEntry, 0);
OSMetaClassDefineReservedUsed(IORegistryEntry, 1);
OSMetaClassDefineReservedUsed(IORegistryEntry, 2);
OSMetaClassDefineReservedUsed(IORegistryEntry, 3);
OSMetaClassDefineReservedUsed(IORegistryEntry, 4);
OSMetaClassDefineReservedUsed(IORegistryEntry, 5);
OSMetaClassDefineReservedUnused(IORegistryEntry, 6);
OSMetaClassDefineReservedUnused(IORegistryEntry, 7);
OSMetaClassDefineReservedUnused(IORegistryEntry, 8);
OSMetaClassDefineReservedUnused(IORegistryEntry, 9);
OSMetaClassDefineReservedUnused(IORegistryEntry, 10);
OSMetaClassDefineReservedUnused(IORegistryEntry, 11);
OSMetaClassDefineReservedUnused(IORegistryEntry, 12);
OSMetaClassDefineReservedUnused(IORegistryEntry, 13);
OSMetaClassDefineReservedUnused(IORegistryEntry, 14);
OSMetaClassDefineReservedUnused(IORegistryEntry, 15);
OSMetaClassDefineReservedUnused(IORegistryEntry, 16);
OSMetaClassDefineReservedUnused(IORegistryEntry, 17);
OSMetaClassDefineReservedUnused(IORegistryEntry, 18);
OSMetaClassDefineReservedUnused(IORegistryEntry, 19);
OSMetaClassDefineReservedUnused(IORegistryEntry, 20);
OSMetaClassDefineReservedUnused(IORegistryEntry, 21);
OSMetaClassDefineReservedUnused(IORegistryEntry, 22);
OSMetaClassDefineReservedUnused(IORegistryEntry, 23);
OSMetaClassDefineReservedUnused(IORegistryEntry, 24);
OSMetaClassDefineReservedUnused(IORegistryEntry, 25);
OSMetaClassDefineReservedUnused(IORegistryEntry, 26);
OSMetaClassDefineReservedUnused(IORegistryEntry, 27);
OSMetaClassDefineReservedUnused(IORegistryEntry, 28);
OSMetaClassDefineReservedUnused(IORegistryEntry, 29);
OSMetaClassDefineReservedUnused(IORegistryEntry, 30);
OSMetaClassDefineReservedUnused(IORegistryEntry, 31);
OSDictionary * IORegistryEntry::getPropertyTable( void ) const
{ return(fPropertyTable); }