OSSet * AppleNForceATARoot::createATAChannels( void )
{
    OSSet *           nubSet;
    OSDictionary *    channelInfo;
    IORegistryEntry * dtEntry;
	char* debugInfo;

    do {
        nubSet = OSSet::withCapacity(2);
        if (nubSet == 0)
            break;

        if (fProvider->open(this) != true)
            break;

        for ( UInt32 channelID = 0; channelID < 2; channelID++ )
        {        
            // Create a dictionary for the channel info. Use native mode
            // settings if possible, else default to legacy mode.

			debugInfo = "native";
            channelInfo = createNativeModeChannelInfo( channelID );
            if (channelInfo == 0) 
			{
				debugInfo = "legacy";
                channelInfo = createLegacyModeChannelInfo( channelID );
			}
            if (channelInfo == 0)
                continue;
				
			DEBUG_LOG( "%s::%s() [this=%p] created channel %d in %s mode.\n", 
				getName(), __FUNCTION__, this, (int)channelID, debugInfo );

            // Create a nub for each ATA channel.

            AppleNForceATAChannel * nub = new AppleNForceATAChannel;
            if ( nub )
            {
                dtEntry = getDTChannelEntry( channelID );

                // Invoke special init method in channel nub.

                if (nub->init( this, channelInfo, dtEntry ) &&
                    nub->attach( this ))
                {
                    nubSet->setObject( nub );
                }

                if ( dtEntry )
                {
                    dtEntry->release();
                }
                else
                {
                    // Platform did not create a device tree entry for
                    // this ATA channel. Do it here.

                    char channelName[5] = {'C','H','N','_','\0'};

                    channelName[3] = '0' + channelID;
                    nub->setName( channelName );

                    if (fProvider->inPlane(gIODTPlane))
                    {
                        nub->attachToParent( fProvider, gIODTPlane );
                    }
                }

                nub->release();
            }

            channelInfo->release();
        }
        
        fProvider->close( this );
    }
    while ( false );

    // Release and invalidate an empty set.

    if (nubSet && (nubSet->getCount() == 0))
    {
        nubSet->release();
        nubSet = 0;
    }

    return nubSet;
}
OSSet * AppleIntelPIIXATARoot::createATAChannelNubs( void )
{
    OSSet *           nubSet;
    OSDictionary *    channelInfo;
    IORegistryEntry * dtEntry;
    UInt32            priChannelMode;
    UInt32            secChannelMode;
    UInt8             mapValue = 0;

    do {
        nubSet = OSSet::withCapacity(2);
        if ( nubSet == 0 )
            break;

        if ( _provider->open( this ) != true )
            break;

        priChannelMode = kChannelModePATA;
        secChannelMode = kChannelModePATA;

        // Determine SATA channel mode based on Port Mapping Register.

        if ( getProperty( kSerialATAKey ) == kOSBooleanTrue )
        {
            OSString * hwName;

            hwName = OSDynamicCast(OSString, getProperty(kControllerNameKey));
            mapValue = _provider->configRead8(kPIIX_PCI_MAP);
            setProperty( kPortMappingKey, mapValue, 8 );

            priChannelMode = kChannelModeDisabled;
            secChannelMode = kChannelModeDisabled;

            if (hwName)
            {
                if (hwName->isEqualTo("ICH7-M SATA"))
                {
                    mapValue &= 0x3;
                    priChannelMode = gICH7MChannelModeMap[mapValue][0];
                    secChannelMode = gICH7MChannelModeMap[mapValue][1];
                }
                else if (hwName->isEqualTo("ICH6 SATA") || hwName->isEqualTo("ESB2 SATA"))
                {
                    mapValue &= 0x3;
                    priChannelMode = gICH6ChannelModeMap[mapValue][0];
                    secChannelMode = gICH6ChannelModeMap[mapValue][1];
                }
                else if (hwName->isEqualTo("ICH6-M SATA"))
                {
                    mapValue &= 0x3;
                    priChannelMode = gICH6MChannelModeMap[mapValue][0];
                    secChannelMode = gICH6MChannelModeMap[mapValue][1];
                }
                else if (hwName->isEqualTo("ICH5 SATA"))
                {
                    mapValue &= 0x7;
                    priChannelMode = gICH5ChannelModeMap[mapValue][0];
                    secChannelMode = gICH5ChannelModeMap[mapValue][1];
                }
                else /* if (hwName->isEqualTo("ICH7 SATA")) */
                {
                    mapValue &= 0x3;
                    priChannelMode = gICH7ChannelModeMap[mapValue][0];
                    secChannelMode = gICH7ChannelModeMap[mapValue][1];
                }
            }
        }

        if ( priChannelMode == kChannelModeDisabled &&
             secChannelMode == kChannelModeDisabled )
        {
            IOLog("%s: bad value (%x) in Port Mapping register",
                  getName(), mapValue);
            _provider->close( this );
            break;
        }

        for ( UInt32 channelID = 0; channelID < 2; channelID++ )
        {
            UInt32 channelMode = (channelID ? secChannelMode : priChannelMode);

            // Create a dictionary for the channel info. Use native mode
            // settings if possible, else default to legacy mode.

            channelInfo = createNativeModeChannelInfo( channelID, channelMode );
            if (channelInfo == 0)
                channelInfo = createLegacyModeChannelInfo( channelID, channelMode );
            if (channelInfo == 0)
                continue;

            // Create a nub for each ATA channel.

            AppleIntelPIIXATAChannel * nub = new AppleIntelPIIXATAChannel;
            if ( nub )
            {
                dtEntry = getDTChannelEntry( channelID );

                if ( nub->init( this, channelInfo, dtEntry ) &&
                     nub->attach( this ) )
                {
                    nubSet->setObject( nub );
                }

                if ( dtEntry )
                {
                    dtEntry->release();
                }
                else
                {
                    // Platform did not create a device tree entry for
                    // this ATA channel. Do it here.

                    char channelName[5] = {'C','H','N','_','\0'};

                    channelName[3] = '0' + channelID;
                    nub->setName( channelName );

                    if ( _provider->inPlane(gIODTPlane) )
                    {
                        nub->attachToParent( _provider, gIODTPlane );
                    }
                }

                nub->release();
            }

            channelInfo->release();
        }
        
        _provider->close( this );
    }
    while ( false );

    // Release and invalidate an empty set.

    if ( nubSet && (nubSet->getCount() == 0) )
    {
        nubSet->release();
        nubSet = 0;
    }

    return nubSet;
}
OSSet * IOPartitionScheme::juxtaposeMediaObjects(OSSet * partitionsOld,
                                                 OSSet * partitionsNew)
{
    //
    // Updates a set of existing partitions, represented by partitionsOld,
    // with possible updates from a rescan of the disk, represented by
    // partitionsNew.  It returns a new set of partitions with the results,
    // removing partitions from partitionsOld where applicable, adding
    // partitions from partitionsNew where applicable, and folding in property
    // changes to partitions from partitionsNew into partitionsOld where
    // applicable.
    //

    OSIterator *   iterator    = 0;
    OSIterator *   iterator1   = 0;
    OSIterator *   iterator2   = 0;
    OSSymbol *     key;
    OSSet *        keys        = 0;
    IOMedia *      partition;
    IOMedia *      partition1;
    IOMedia *      partition2;
    OSSet *        partitions  = 0;
    OSOrderedSet * partitions1 = 0;
    OSOrderedSet * partitions2 = 0;
    UInt32         partitionID = 0;
    OSDictionary * properties;

    // Allocate a set to hold the set of media objects representing partitions.

    partitions = OSSet::withCapacity( partitionsNew->getCapacity( ) );
    if ( partitions == 0 ) goto juxtaposeErr;

    // Prepare the reference set of partitions.

    partitions1 = OSOrderedSet::withCapacity( partitionsOld->getCapacity( ), partitionComparison, 0 );
    if ( partitions1 == 0 ) goto juxtaposeErr;

    iterator1 = OSCollectionIterator::withCollection( partitionsOld );
    if ( iterator1 == 0 ) goto juxtaposeErr;

    while ( ( partition1 = ( IOMedia * ) iterator1->getNextObject( ) ) )
    {
        partitionID = max( partitionID, strtoul( partition1->getLocation( ), NULL, 10 ) );

        partitions1->setObject( partition1 );
    }

    iterator1->release( );
    iterator1 = 0;

    // Prepare the comparison set of partitions.

    partitions2 = OSOrderedSet::withCapacity( partitionsNew->getCapacity( ), partitionComparison, 0 );
    if ( partitions2 == 0 ) goto juxtaposeErr;

    iterator2 = OSCollectionIterator::withCollection( partitionsNew );
    if ( iterator2 == 0 ) goto juxtaposeErr;

    while ( ( partition2 = ( IOMedia * ) iterator2->getNextObject( ) ) )
    {
        partitionID = max( partitionID, strtoul( partition2->getLocation( ), NULL, 10 ) );

        partitions2->setObject( partition2 );
    }

    iterator2->release( );
    iterator2 = 0;

    // Juxtapose the partitions.

    iterator1 = OSCollectionIterator::withCollection( partitions1 );
    if ( iterator1 == 0 ) goto juxtaposeErr;

    iterator2 = OSCollectionIterator::withCollection( partitions2 );
    if ( iterator2 == 0 ) goto juxtaposeErr;

    partition1 = ( IOMedia * ) iterator1->getNextObject( );
    partition2 = ( IOMedia * ) iterator2->getNextObject( );

    while ( partition1 || partition2 )
    {
        UInt64 base1;
        UInt64 base2;

        base1 = partition1 ? partition1->getBase( ) : UINT64_MAX;
        base2 = partition2 ? partition2->getBase( ) : UINT64_MAX;

#if TARGET_OS_EMBEDDED
        if ( partition1 && partition2 )
        {
            OSString * uuid1;
            OSString * uuid2;

            uuid1 = OSDynamicCast( OSString, partition1->getProperty( kIOMediaUUIDKey ) );
            uuid2 = OSDynamicCast( OSString, partition2->getProperty( kIOMediaUUIDKey ) );

            if ( uuid1 || uuid2 )
            {
                if ( uuid1 == 0 )
                {
                   base1 = UINT64_MAX;
                }
                else if ( uuid2 == 0 )
                {
                   base2 = UINT64_MAX;
                }
                else
                {
                    int compare;

                    compare = strcmp( uuid1->getCStringNoCopy( ), uuid2->getCStringNoCopy( ) );

                    if ( compare > 0 )
                    {
                        base1 = UINT64_MAX;
                    }
                    else if ( compare < 0 )
                    {
                        base2 = UINT64_MAX;
                    }
                    else
                    {
                        base1 = base2;
                    }
                }
            }
        }
#endif /* TARGET_OS_EMBEDDED */

        if ( base1 > base2 )
        {
            // A partition was added.

            partition2->setProperty( kIOMediaLiveKey, true );

            iterator = OSCollectionIterator::withCollection( partitions1 );
            if ( iterator == 0 ) goto juxtaposeErr;

            while ( ( partition = ( IOMedia * ) iterator->getNextObject( ) ) )
            {
                if ( strcmp( partition->getLocation( ), partition2->getLocation( ) ) == 0 )
                {
                    // Set a location value for this partition.

                    char location[ 12 ];

                    partitionID++;

                    snprintf( location, sizeof( location ), "%d", ( int ) partitionID );

                    partition2->setLocation( location );

                    partition2->setProperty( kIOMediaLiveKey, false );

                    break;
                }
            }

            iterator->release( );
            iterator = 0;

            if ( partition2->attach( this ) )
            {
                attachMediaObjectToDeviceTree( partition2 );

                partition2->registerService( kIOServiceAsynchronous );
            }

            partitions->setObject( partition2 );

            partition2 = ( IOMedia * ) iterator2->getNextObject( );
        }
        else if ( base1 < base2 )
        {
            // A partition was removed.

            partition1->setProperty( kIOMediaLiveKey, false );

            if ( handleIsOpen( partition1 ) == false )
            {
                partition1->terminate( kIOServiceSynchronous );

                detachMediaObjectFromDeviceTree( partition1 );
            }
            else
            {
                partition1->removeProperty( kIOMediaPartitionIDKey );

                partitions->setObject( partition1 );
            }

            partition1 = ( IOMedia * ) iterator1->getNextObject( );
        }
        else
        {
            // A partition was matched.

            bool edit;
            bool move;

            edit = false;
            move = false;

            keys = OSSet::withCapacity( 1 );
            if ( keys == 0 ) goto juxtaposeErr;

            properties = partition2->getPropertyTable( );

            // Determine which properties were updated.

            if ( partition1->getBase( )               != partition2->getBase( )               ||
                 partition1->getSize( )               != partition2->getSize( )               ||
                 partition1->getPreferredBlockSize( ) != partition2->getPreferredBlockSize( ) ||
                 partition1->getAttributes( )         != partition2->getAttributes( )         ||
                 partition1->isWhole( )               != partition2->isWhole( )               ||
                 partition1->isWritable( )            != partition2->isWritable( )            ||
                 strcmp( partition1->getContentHint( ), partition2->getContentHint( ) )       )
            {
                edit = true;
            }

            if ( strcmp( partition1->getName( ),     partition2->getName( )     ) ||
                 strcmp( partition1->getLocation( ), partition2->getLocation( ) ) )
            {
                move = true;
            }

            iterator = OSCollectionIterator::withCollection( properties );
            if ( iterator == 0 ) goto juxtaposeErr;

            while ( ( key = ( OSSymbol * ) iterator->getNextObject( ) ) )
            {
                OSObject * value1;
                OSObject * value2;

                if ( key->isEqualTo( kIOMediaContentHintKey        ) ||
                     key->isEqualTo( kIOMediaEjectableKey          ) ||
                     key->isEqualTo( kIOMediaPreferredBlockSizeKey ) ||
                     key->isEqualTo( kIOMediaRemovableKey          ) ||
                     key->isEqualTo( kIOMediaSizeKey               ) ||
                     key->isEqualTo( kIOMediaWholeKey              ) ||
                     key->isEqualTo( kIOMediaWritableKey           ) )
                {
                    continue;
                }

                if ( key->isEqualTo( kIOMediaContentKey ) ||
                     key->isEqualTo( kIOMediaLeafKey    ) ||
                     key->isEqualTo( kIOMediaLiveKey    ) ||
                     key->isEqualTo( kIOMediaOpenKey    ) )
                {
                    continue;
                }

                value1 = partition1->getProperty( key );
                value2 = partition2->getProperty( key );

                if ( value1 == 0 || value1->isEqualTo( value2 ) == false )
                {
                    keys->setObject( key );
                }
            }

            iterator->release( );
            iterator = 0;

            // A partition was updated.

            partition1->setProperty( kIOMediaLiveKey, ( move == false ) );

            if ( edit )
            {
                partition1->init( partition2->getBase( ),
                                  partition2->getSize( ),
                                  partition2->getPreferredBlockSize( ),
                                  partition2->getAttributes( ),
                                  partition2->isWhole( ),
                                  partition2->isWritable( ),
                                  partition2->getContentHint( ) );
            }

            if ( keys->getCount( ) )
            {
                iterator = OSCollectionIterator::withCollection( keys );
                if ( iterator == 0 ) goto juxtaposeErr;

                while ( ( key = ( OSSymbol * ) iterator->getNextObject( ) ) )
                {
                    partition1->setProperty( key, partition2->getProperty( key ) );
                }

                iterator->release( );
                iterator = 0;
            }

            if ( edit || keys->getCount( ) )
            {
                partition1->messageClients( kIOMessageServicePropertyChange );

                partition1->registerService( kIOServiceAsynchronous );
            }

            keys->release( );
            keys = 0;

            partitions->setObject( partition1 );

            partition1 = ( IOMedia * ) iterator1->getNextObject( );
            partition2 = ( IOMedia * ) iterator2->getNextObject( );
        }
    }

    // Release our resources.

    iterator1->release( );
    iterator2->release( );
    partitions1->release( );
    partitions2->release( );

    return partitions;

juxtaposeErr:

    // Release our resources.

    if ( iterator    ) iterator->release( );
    if ( iterator1   ) iterator1->release( );
    if ( iterator2   ) iterator2->release( );
    if ( keys        ) keys->release( );
    if ( partitions  ) partitions->release( );
    if ( partitions1 ) partitions1->release( );
    if ( partitions2 ) partitions2->release( );

    return 0;
}