AppleGenericPCATARoot.cpp [plain text]
#include <IOKit/IOLib.h>
#include <IOKit/pci/IOPCIDevice.h>
#include <IOKit/IODeviceTreeSupport.h>
#include "AppleGenericPCATARoot.h"
#include "AppleGenericPCATAChannel.h"
#include "AppleGenericPCATAKeys.h"
#define super IOService
OSDefineMetaClassAndStructors( AppleGenericPCATARoot, IOService )
static void registerClientApplier( IOService * service, void * context )
{
if ( service ) service->registerService();
}
bool AppleGenericPCATARoot::start( IOService * provider )
{
if ( super::start(provider) != true )
{
return false;
}
fProvider = provider;
fProvider->retain();
fChannels = createATAChannels();
if (fChannels == 0)
{
return false;
}
fOpenChannels = OSSet::withCapacity( fChannels->getCount() );
if ( fOpenChannels == 0 )
{
return false;
}
applyToClients( registerClientApplier, 0 );
return true;
}
void AppleGenericPCATARoot::free( void )
{
if ( fChannels )
{
fChannels->release();
fChannels = 0;
}
if ( fOpenChannels )
{
fOpenChannels->release();
fOpenChannels = 0;
}
if ( fProvider )
{
fProvider->release();
fProvider = 0;
}
super::free();
}
IORegistryEntry * AppleGenericPCATARoot::getDTChannelEntry( int channelID )
{
IORegistryEntry * entry = 0;
const char * location;
OSIterator * iter = fProvider->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 * AppleGenericPCATARoot::createATAChannels( void )
{
OSSet * nubSet;
OSDictionary * channelInfo;
IORegistryEntry * dtEntry;
do {
nubSet = OSSet::withCapacity(4);
if ( nubSet == 0 )
break;
if (fProvider->open(this) != true)
break;
for ( UInt32 channelID = 0; channelID < 2; channelID++ )
{
channelInfo = createNativeModeChannelInfo( channelID );
if (channelInfo)
{
channelInfo->release();
channelInfo = 0;
break;
}
channelInfo = createLegacyModeChannelInfo( channelID );
if (channelInfo == 0)
continue;
AppleGenericPCATAChannel * nub = new AppleGenericPCATAChannel;
if ( nub )
{
dtEntry = getDTChannelEntry( channelID );
if (nub->init( this, channelInfo, dtEntry ) &&
nub->attach( this ))
{
nubSet->setObject( nub );
}
if ( dtEntry )
{
dtEntry->release();
}
else
{
char channelName[5] = {'C','H','N','_','\0'};
IOService * dtRoot;
channelName[3] = '0' + channelID;
nub->setName( channelName );
dtRoot = fProvider;
while (dtRoot && dtRoot->inPlane(gIODTPlane) == false)
{
dtRoot = dtRoot->getProvider();
}
if (dtRoot)
nub->attachToParent( dtRoot, gIODTPlane );
}
nub->release();
}
channelInfo->release();
}
fProvider->close( this );
}
while ( false );
if ( nubSet && (nubSet->getCount() == 0) )
{
nubSet->release();
nubSet = 0;
}
return nubSet;
}
OSDictionary *
AppleGenericPCATARoot::createNativeModeChannelInfo( UInt32 ataChannel )
{
IOPCIDevice * pciDevice;
UInt16 cmdPort = 0;
UInt16 ctrPort = 0;
pciDevice = OSDynamicCast(IOPCIDevice, fProvider);
if (pciDevice == 0)
return 0;
switch ( ataChannel )
{
case PRI_CHANNEL_ID:
cmdPort = pciDevice->configRead16( kIOPCIConfigBaseAddress0 );
ctrPort = pciDevice->configRead16( kIOPCIConfigBaseAddress1 );
if (((cmdPort & 0x1) == 0) || ((ctrPort & 0x1) == 0))
{
cmdPort = ctrPort = 0;
break;
}
cmdPort &= ~0x1; ctrPort &= ~0x1;
if ((cmdPort > 0xFFF8) || (ctrPort > 0xFFF8) ||
(cmdPort < 0x100) || (ctrPort < 0x100) ||
((cmdPort == PRI_CMD_ADDR) && (ctrPort == PRI_CTR_ADDR)))
{
cmdPort = ctrPort = 0;
}
break;
case SEC_CHANNEL_ID:
cmdPort = pciDevice->configRead16( kIOPCIConfigBaseAddress2 );
ctrPort = pciDevice->configRead16( kIOPCIConfigBaseAddress3 );
if (((cmdPort & 0x1) == 0) || ((ctrPort & 0x1) == 0))
{
cmdPort = ctrPort = 0;
break;
}
if ((cmdPort > 0xFFF8) || (ctrPort > 0xFFF8) ||
(cmdPort < 0x100) || (ctrPort < 0x100) ||
((cmdPort == SEC_CMD_ADDR) && (ctrPort == SEC_CTR_ADDR)))
{
cmdPort = ctrPort = 0;
}
break;
}
if (cmdPort && ctrPort)
return createChannelInfo( ataChannel, cmdPort, ctrPort,
pciDevice->configRead8(kIOPCIConfigInterruptLine) );
else
return 0;
}
OSDictionary *
AppleGenericPCATARoot::createLegacyModeChannelInfo( UInt32 ataChannel )
{
UInt16 cmdPort = 0;
UInt16 ctrPort = 0;
UInt8 isaIrq = 0;
switch ( ataChannel )
{
case PRI_CHANNEL_ID:
cmdPort = PRI_CMD_ADDR;
ctrPort = PRI_CTR_ADDR;
isaIrq = PRI_ISA_IRQ;
break;
case SEC_CHANNEL_ID:
cmdPort = SEC_CMD_ADDR;
ctrPort = SEC_CTR_ADDR;
isaIrq = SEC_ISA_IRQ;
break;
}
return createChannelInfo( ataChannel, cmdPort, ctrPort, isaIrq );
}
OSDictionary *
AppleGenericPCATARoot::createChannelInfo( UInt32 ataChannel,
UInt16 commandPort,
UInt16 controlPort,
UInt8 interruptVector )
{
OSDictionary * dict = OSDictionary::withCapacity( 5 );
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, 32 );
if (num)
{
dict->setObject( kInterruptVectorKey, num );
num->release();
}
dict->setObject( kPIOModeKey, getProperty(kPIOModeKey) );
return dict;
}
bool AppleGenericPCATARoot::handleOpen( IOService * client,
IOOptionBits options,
void * arg )
{
bool ret = true;
if ( ( fChannels->containsObject( client ) == false ) ||
( fOpenChannels->containsObject( client ) == true ) )
return false;
if ( fOpenChannels->getCount() == 0 )
ret = fProvider->open( this );
if ( ret )
{
fOpenChannels->setObject( client );
if ( arg ) *((IOService **) arg) = fProvider;
}
return ret;
}
void AppleGenericPCATARoot::handleClose( IOService * client,
IOOptionBits options )
{
if ( fOpenChannels->containsObject( client ) == false ) return;
fOpenChannels->removeObject( client );
if ( fOpenChannels->getCount() == 0 )
fProvider->close( this );
}
bool AppleGenericPCATARoot::handleIsOpen( const IOService * client ) const
{
if ( client )
return fOpenChannels->containsObject( client );
else
return ( fOpenChannels->getCount() != 0 );
}
#undef super
#define super AppleGenericPCATARoot
OSDefineMetaClassAndStructors( AppleGenericPCATAPCIRoot,
AppleGenericPCATARoot )
IOService * AppleGenericPCATAPCIRoot::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;
}