AppleIntelPIIXATARoot.cpp [plain text]
#include <IOKit/IOLib.h>
#include <IOKit/IODeviceTreeSupport.h>
#include "AppleIntelPIIXATARoot.h"
#include "AppleIntelPIIXATAChannel.h"
#include "AppleIntelPIIXATAKeys.h"
#include "AppleIntelPIIXATAHW.h"
#define super IOService
OSDefineMetaClassAndStructors( AppleIntelPIIXATARoot, IOService )
static const UInt8 gChannelModeMap[8 ][2 ] =
{
{ kChannelModeSATAPort0, kChannelModeSATAPort1 },
{ kChannelModeSATAPort1, kChannelModeSATAPort0 },
{ kChannelModePATA, kChannelModePATA },
{ kChannelModePATA, kChannelModePATA },
{ kChannelModeSATAPort01, kChannelModePATA },
{ kChannelModeSATAPort10, kChannelModePATA },
{ kChannelModePATA, kChannelModeSATAPort01 },
{ kChannelModePATA, kChannelModeSATAPort10 }
};
IOService * AppleIntelPIIXATARoot::probe( IOService * provider,
SInt32 * score )
{
IOPCIDevice * pciDevice;
if ( super::probe( provider, score ) == 0 )
{
return 0;
}
pciDevice = OSDynamicCast( IOPCIDevice, provider );
if ( pciDevice == 0 )
{
return 0;
}
if ( (pciDevice->configRead16( kIOPCIConfigCommand ) &
kIOPCICommandIOSpace) == 0 )
{
return 0;
}
return this;
}
static void registerClientApplier( IOService * service, void * context )
{
if ( service ) service->registerService();
}
bool AppleIntelPIIXATARoot::start( IOService * provider )
{
if ( super::start(provider) != true )
return false;
_pciConfigLock = IOLockAlloc();
if ( _pciConfigLock == 0 )
return false;
_provider = OSDynamicCast( IOPCIDevice, provider );
if ( _provider == 0 )
return false;
_provider->retain();
_nubs = createATAChannelNubs();
if ( _nubs == 0 )
return false;
_openNubs = OSSet::withCapacity( _nubs->getCount() );
if ( _openNubs == 0 )
return false;
applyToClients( registerClientApplier, 0 );
return true;
}
void AppleIntelPIIXATARoot::free( void )
{
if ( _nubs )
{
_nubs->release();
_nubs = 0;
}
if ( _openNubs )
{
_openNubs->release();
_openNubs = 0;
}
if ( _provider )
{
_provider->release();
_provider = 0;
}
if ( _pciConfigLock )
{
IOLockFree( _pciConfigLock );
_pciConfigLock = 0;
}
super::free();
}
IORegistryEntry * AppleIntelPIIXATARoot::getDTChannelEntry( int channelID )
{
IORegistryEntry * entry = 0;
const char * location;
OSIterator * iter = _provider->getChildIterator( gIODTPlane );
if (iter == 0) return 0;
while (( entry = (IORegistryEntry *) iter->getNextObject() ))
{
location = entry->getLocation();
if ( location && strtol(location, 0, 10) == channelID )
{
entry->retain();
break;
}
}
iter->release();
return entry; }
OSSet * AppleIntelPIIXATARoot::createATAChannelNubs( void )
{
OSSet * nubSet;
OSDictionary * channelInfo;
UInt8 mapValue;
IORegistryEntry * dtEntry;
do {
nubSet = OSSet::withCapacity(2);
if ( nubSet == 0 )
break;
if ( _provider->open( this ) != true )
break;
if ( getProperty( kSerialATAKey ) == kOSBooleanTrue )
{
mapValue = _provider->configRead8( kPIIX_PCI_MAP ) & 0x7;
if ( mapValue == 2 || mapValue == 3 )
IOLog("%s: bad value (%x) in Port Mapping register",
getName(), mapValue);
}
else
mapValue = 2;
setProperty( kPortMappingKey, mapValue, 8 );
for ( UInt32 channelID = 0; channelID < 2; channelID++ )
{
channelInfo = createNativeModeChannelInfo( channelID, mapValue );
if (channelInfo == 0)
channelInfo = createLegacyModeChannelInfo( channelID, mapValue );
if (channelInfo == 0)
continue;
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();
}
nub->release();
}
channelInfo->release();
}
_provider->close( this );
}
while ( false );
if ( nubSet && (nubSet->getCount() == 0) )
{
nubSet->release();
nubSet = 0;
}
return nubSet;
}
OSDictionary *
AppleIntelPIIXATARoot::createNativeModeChannelInfo( UInt32 ataChannel,
UInt8 mapValue )
{
UInt8 pi = _provider->configRead8( kPIIX_PCI_PI );
UInt16 cmdPort = 0;
UInt16 ctrPort = 0;
switch ( ataChannel )
{
case kPIIX_CHANNEL_PRIMARY:
if ( pi & 0x3 )
{
cmdPort = _provider->configRead16( kIOPCIConfigBaseAddress0 );
ctrPort = _provider->configRead16( kIOPCIConfigBaseAddress1 );
cmdPort &= ~0x1; ctrPort &= ~0x1;
if ( cmdPort == kPIIX_P_CMD_ADDR &&
ctrPort == kPIIX_P_CTL_ADDR )
{
cmdPort = ctrPort = 0;
}
}
break;
case kPIIX_CHANNEL_SECONDARY:
if ( pi & 0xc0 )
{
cmdPort = _provider->configRead16( kIOPCIConfigBaseAddress2 );
ctrPort = _provider->configRead16( kIOPCIConfigBaseAddress3 );
cmdPort &= ~0x1; ctrPort &= ~0x1;
if ( cmdPort == kPIIX_S_CMD_ADDR &&
ctrPort == kPIIX_S_CTL_ADDR )
{
cmdPort = ctrPort = 0;
}
}
break;
}
if ( cmdPort && ctrPort )
return createChannelInfo( ataChannel, mapValue, cmdPort, ctrPort,
_provider->configRead8( kIOPCIConfigInterruptLine ) );
else
return 0;
}
OSDictionary *
AppleIntelPIIXATARoot::createLegacyModeChannelInfo( UInt32 ataChannel,
UInt8 mapValue )
{
UInt16 cmdPort = 0;
UInt16 ctrPort = 0;
UInt8 irq = 0;
switch ( ataChannel )
{
case kPIIX_CHANNEL_PRIMARY:
cmdPort = kPIIX_P_CMD_ADDR;
ctrPort = kPIIX_P_CTL_ADDR;
irq = kPIIX_P_IRQ;
break;
case kPIIX_CHANNEL_SECONDARY:
cmdPort = kPIIX_S_CMD_ADDR;
ctrPort = kPIIX_S_CTL_ADDR;
irq = kPIIX_S_IRQ;
break;
}
return createChannelInfo( ataChannel, mapValue,
cmdPort, ctrPort, irq );
}
OSDictionary *
AppleIntelPIIXATARoot::createChannelInfo( UInt32 ataChannel,
UInt8 mapValue,
UInt16 commandPort,
UInt16 controlPort,
UInt8 interruptVector )
{
OSDictionary * dict = OSDictionary::withCapacity( 4 );
OSNumber * num;
if ( dict == 0 || commandPort == 0 || controlPort == 0 ||
interruptVector == 0 || interruptVector == 0xFF )
{
if ( dict ) dict->release();
return 0;
}
num = OSNumber::withNumber( ataChannel, 32 );
if (num)
{
dict->setObject( kChannelNumberKey, num );
num->release();
}
num = OSNumber::withNumber( commandPort, 16 );
if (num)
{
dict->setObject( kCommandBlockAddressKey, num );
num->release();
}
num = OSNumber::withNumber( controlPort, 16 );
if (num)
{
dict->setObject( kControlBlockAddressKey, num );
num->release();
}
num = OSNumber::withNumber( interruptVector, 8 );
if (num)
{
dict->setObject( kInterruptVectorKey, num );
num->release();
}
num = OSNumber::withNumber( gChannelModeMap[mapValue][ataChannel], 32 );
if (num)
{
dict->setObject( kChannelModeKey, num );
num->release();
}
return dict;
}
bool AppleIntelPIIXATARoot::handleOpen( IOService * client,
IOOptionBits options,
void * arg )
{
bool ret = true;
if ( ( _nubs->containsObject( client ) == false ) ||
( _openNubs->containsObject( client ) == true ) )
return false;
if ( _openNubs->getCount() == 0 )
ret = _provider->open( this );
if ( ret )
{
_openNubs->setObject( client );
if ( arg ) *((IOService **) arg) = _provider;
}
return ret;
}
void AppleIntelPIIXATARoot::handleClose( IOService * client,
IOOptionBits options )
{
if ( _openNubs->containsObject( client ) == false ) return;
_openNubs->removeObject( client );
if ( _openNubs->getCount() == 0 )
_provider->close( this );
}
bool AppleIntelPIIXATARoot::handleIsOpen( const IOService * client ) const
{
if ( client )
return _openNubs->containsObject( client );
else
return ( _openNubs->getCount() != 0 );
}
void AppleIntelPIIXATARoot::pciConfigWrite8( UInt8 offset,
UInt8 data,
UInt8 mask )
{
UInt8 u8;
IOLockLock( _pciConfigLock );
u8 = _provider->configRead8( offset );
u8 &= ~mask;
u8 |= (mask & data);
_provider->configWrite8( offset, u8 );
IOLockUnlock( _pciConfigLock );
}
void AppleIntelPIIXATARoot::pciConfigWrite16( UInt8 offset,
UInt16 data,
UInt16 mask )
{
UInt16 u16;
IOLockLock( _pciConfigLock );
u16 = _provider->configRead16( offset );
u16 &= ~mask;
u16 |= (mask & data);
_provider->configWrite16( offset, u16 );
IOLockUnlock( _pciConfigLock );
}
bool AppleIntelPIIXATARoot::serializeProperties( OSSerialize * s ) const
{
AppleIntelPIIXATARoot * self;
char timingString[80];
if ( _provider )
{
sprintf( timingString, "0x40=%08lx 0x44=%08lx 0x48=%08lx 0x54=%04x",
_provider->configRead32( 0x40 ),
_provider->configRead32( 0x44 ),
_provider->configRead32( 0x48 ),
_provider->configRead16( 0x54 ) );
self = (AppleIntelPIIXATARoot *) this;
self->setProperty( "PCI Timing Registers", timingString );
}
return super::serializeProperties(s);
}