AppleVIAATARoot.cpp [plain text]
#include <IOKit/IOLib.h>
#include <IOKit/IODeviceTreeSupport.h>
#include "AppleVIAATARoot.h"
#include "AppleVIAATAChannel.h"
#include "AppleVIAATAHardware.h"
#define super IOService
OSDefineMetaClassAndStructors( AppleVIAATARoot, IOService )
IOService * AppleVIAATARoot::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 AppleVIAATARoot::start( IOService * provider )
{
OSDictionary * match;
if (super::start(provider) != true)
return false;
fProvider = OSDynamicCast( IOPCIDevice, provider );
if (fProvider == 0)
return false;
fProvider->retain();
fProvider->setBusMasterEnable( true );
fPCILock = IOLockAlloc();
if (fPCILock == 0)
return false;
fIsSATA = (getProperty(kSerialATAKey) == kOSBooleanTrue);
fChannels = createATAChannels();
if (fChannels == 0)
return false;
fOpenChannels = OSSet::withCapacity( fChannels->getCount() );
if (fOpenChannels == 0)
return false;
if (fIsSATA)
{
fHardwareType = VIA_HW_SATA;
fHardwareFlags = 0;
applyToClients( registerClientApplier, 0 );
}
else if ((match = OSDynamicCast(OSDictionary,
getProperty(kISABridgeMatchingKey))))
{
match->retain();
fISABridgeNotifier = addNotification(
gIOFirstPublishNotification,
match,
isaBridgePublished,
this,
0 );
if (fISABridgeNotifier == 0)
{
match->release();
return false;
}
}
else
{
return false;
}
return true;
}
void AppleVIAATARoot::free( void )
{
if (fISABridgeNotifier)
{
fISABridgeNotifier->remove();
fISABridgeNotifier = 0;
}
if (fChannels)
{
fChannels->release();
fChannels = 0;
}
if (fOpenChannels)
{
fOpenChannels->release();
fOpenChannels = 0;
}
if (fProvider)
{
fProvider->release();
fProvider = 0;
}
if (fPCILock)
{
IOLockFree( fPCILock );
fPCILock = 0;
}
super::free();
}
static const struct ISABridgeInfo {
UInt16 deviceID;
UInt8 minRevID;
UInt8 hwType;
UInt8 hwFlags;
const char * name;
} gISABridges[] =
{
{ PCI_VIA_82C586, 0x02, VIA_HW_UDMA_33, 0x00, "82C586B" },
{ PCI_VIA_82C586, 0x00, VIA_HW_UDMA_33, 0x00, "82C586" },
{ PCI_VIA_82C596, 0x12, VIA_HW_UDMA_66, 0x00, "82C596B" },
{ PCI_VIA_82C596, 0x00, VIA_HW_UDMA_33, 0x00, "82C596" },
{ PCI_VIA_82C686, 0x40, VIA_HW_UDMA_100, 0x00, "82C686B" },
{ PCI_VIA_82C686, 0x10, VIA_HW_UDMA_66, 0x00, "82C686A" },
{ PCI_VIA_82C686, 0x00, VIA_HW_UDMA_33, 0x00, "82C686" },
{ PCI_VIA_8231, 0x00, VIA_HW_UDMA_100, 0x00, "8231" },
{ PCI_VIA_8233, 0x00, VIA_HW_UDMA_100, 0x00, "8233" },
{ PCI_VIA_8233_C, 0x00, VIA_HW_UDMA_100, 0x00, "8233C" },
{ PCI_VIA_8233_A, 0x00, VIA_HW_UDMA_133, 0x00, "8233A" },
{ PCI_VIA_8235, 0x00, VIA_HW_UDMA_133, 0x00, "8235" },
{ PCI_VIA_8237, 0x00, VIA_HW_UDMA_133, 0x00, "8237" },
{ 0, 0x00, VIA_HW_UDMA_NONE, 0x00, "UNKNOWN" },
};
bool AppleVIAATARoot::isaBridgePublished( void * target,
void * param,
IOService * service )
{
IOPCIDevice * bridge;
AppleVIAATARoot * root = (AppleVIAATARoot *) target;
const ISABridgeInfo * info;
UInt16 bridgeDID;
UInt8 bridgeRev;
if (root == 0)
return false;
bridge = OSDynamicCast( IOPCIDevice, service );
if (bridge == 0)
return false;
bridgeDID = bridge->configRead16(kIOPCIConfigDeviceID);
bridgeRev = bridge->configRead8(kIOPCIConfigRevisionID);
info = &gISABridges[0];
while (info->deviceID)
{
if ((bridgeDID == info->deviceID) &&
(bridgeRev >= info->minRevID))
break;
info++;
}
root->setProperty(kHardwareNameKey, info->name);
root->fHardwareType = info->hwType;
root->fHardwareFlags = info->hwFlags;
root->applyToClients( registerClientApplier, 0 );
if (root->fISABridgeNotifier)
root->fISABridgeNotifier->disable();
return false;
}
IORegistryEntry * AppleVIAATARoot::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 * AppleVIAATARoot::createATAChannels( void )
{
OSSet * nubSet;
OSDictionary * channelInfo;
IORegistryEntry * dtEntry;
do {
nubSet = OSSet::withCapacity(2);
if (nubSet == 0)
break;
if (fProvider->open(this) != true)
break;
for ( UInt32 channelID = 0; channelID < 2; channelID++ )
{
channelInfo = createNativeModeChannelInfo( channelID );
if (channelInfo == 0)
channelInfo = createLegacyModeChannelInfo( channelID );
if (channelInfo == 0)
continue;
AppleVIAATAChannel * nub = new AppleVIAATAChannel;
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'};
channelName[3] = '0' + channelID;
nub->setName( channelName );
if (fProvider->inPlane(gIODTPlane))
{
nub->attachToParent( fProvider, gIODTPlane );
}
}
nub->release();
}
channelInfo->release();
}
fProvider->close( this );
}
while ( false );
if (nubSet && (nubSet->getCount() == 0))
{
nubSet->release();
nubSet = 0;
}
return nubSet;
}
OSDictionary *
AppleVIAATARoot::createNativeModeChannelInfo( UInt32 ataChannel )
{
UInt8 pi = fProvider->configRead8( PCI_PI );
UInt16 cmdPort = 0;
UInt16 ctrPort = 0;
if (fIsSATA) pi = 0xFF;
switch ( ataChannel )
{
case PRI_CHANNEL_ID:
if ( pi & 0x3 )
{
cmdPort = fProvider->configRead16( kIOPCIConfigBaseAddress0 );
ctrPort = fProvider->configRead16( kIOPCIConfigBaseAddress1 );
cmdPort &= ~0x1; ctrPort &= ~0x1;
if ( cmdPort == PRI_CMD_ADDR &&
ctrPort == PRI_CTR_ADDR )
{
cmdPort = ctrPort = 0;
}
}
break;
case SEC_CHANNEL_ID:
if ( pi & 0xc )
{
cmdPort = fProvider->configRead16( kIOPCIConfigBaseAddress2 );
ctrPort = fProvider->configRead16( kIOPCIConfigBaseAddress3 );
cmdPort &= ~0x1; ctrPort &= ~0x1;
if ( cmdPort == SEC_CMD_ADDR &&
ctrPort == SEC_CTR_ADDR )
{
cmdPort = ctrPort = 0;
}
}
break;
}
if (cmdPort && ctrPort)
return createChannelInfo( ataChannel, cmdPort, ctrPort,
fProvider->configRead8(kIOPCIConfigInterruptLine) );
else
return 0;
}
OSDictionary *
AppleVIAATARoot::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 *
AppleVIAATARoot::createChannelInfo( UInt32 ataChannel,
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, 32 );
if (num)
{
dict->setObject( kInterruptVectorKey, num );
num->release();
}
return dict;
}
bool AppleVIAATARoot::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 == true)
{
fOpenChannels->setObject(client);
if ( arg ) *((IOService **) arg) = fProvider;
}
return ret;
}
void AppleVIAATARoot::handleClose( IOService * client,
IOOptionBits options )
{
if (fOpenChannels->containsObject(client) == false) return;
fOpenChannels->removeObject(client);
if (fOpenChannels->getCount() == 0)
fProvider->close(this);
}
bool AppleVIAATARoot::handleIsOpen( const IOService * client ) const
{
if (client)
return fOpenChannels->containsObject(client);
else
return (fOpenChannels->getCount() != 0);
}
UInt32 AppleVIAATARoot::getHardwareType( void ) const
{
return fHardwareType;
}
UInt32 AppleVIAATARoot::getHardwareFlags( void ) const
{
return fHardwareFlags;
}
UInt32 AppleVIAATARoot::getUltraDMAModeMask( void ) const
{
static const UInt8 HardwareTypeToUDMAModeMask[ VIA_HW_COUNT ] =
{
0x00,
0x07,
0x1F,
0x3F,
0x7F,
0x7F
};
if (fHardwareType < VIA_HW_COUNT)
return HardwareTypeToUDMAModeMask[ fHardwareType ];
else
return HardwareTypeToUDMAModeMask[ VIA_HW_UDMA_133 ];
}
void AppleVIAATARoot::pciConfigWrite8( UInt8 offset, UInt8 data, UInt8 mask )
{
UInt8 u8;
IOLockLock( fPCILock );
u8 = fProvider->configRead8( offset );
u8 &= ~mask;
u8 |= (mask & data);
fProvider->configWrite8( offset, u8 );
IOLockUnlock( fPCILock );
}
void AppleVIAATARoot::pciConfigWrite32( UInt8 offset, UInt32 data, UInt32 mask )
{
UInt8 u32;
IOLockLock( fPCILock );
u32 = fProvider->configRead32( offset );
u32 &= ~mask;
u32 |= (mask & data);
fProvider->configWrite32( offset, u32 );
IOLockUnlock( fPCILock );
}
UInt8 AppleVIAATARoot::pciConfigRead8( UInt8 offset )
{
return fProvider->configRead8( offset );
}
UInt16 AppleVIAATARoot::pciConfigRead16( UInt8 offset )
{
return fProvider->configRead16( offset );
}
UInt32 AppleVIAATARoot::pciConfigRead32( UInt8 offset )
{
return fProvider->configRead32( offset );
}