#include <ppc/proc_reg.h>
#include "AppleKiwiRoot.h"
#include <IOKit/assert.h>
#include <IOKit/IOTypes.h>
#include <IOKit/IOLib.h>
#include <IOKit/pci/IOPCIDevice.h>
#include <libkern/OSByteOrder.h>
#include <libkern/OSAtomic.h>
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/pwr_mgt/IOPM.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include <IOKit/ata/IOATATypes.h>
#include <kern/clock.h>
#ifdef DLOG
#undef DLOG
#endif
#ifdef KIWI_ROOT_DEBUG
#define DLOG(fmt, args...) IOLog(fmt, ## args)
#else
#define DLOG(fmt, args...)
#endif
#define kDeviceTypeString "pci-ide"
#define kDevicetypeKey "device_type"
#define kNameKey "name"
#define kNameString "AppleKiwi"
#define kPCIInlineKey "pci_inline"
#define kMode6Key "mode6"
#define k100mhz_pll 0x0d2b
#define k133mhz_pll 0x0826
#define kTrayPresentStatusKey "platform-drivePresent"
#define kBayInUseStatusKey "platform-driveInUse"
#define kBayPowerStatusKey "platform-drivePower"
#define kBayOpenSwitchStatusKey "platform-driveSwitch"
#define kBaySetActiveLEDKey "platform-setDriveInUse"
#define kBaySetFailLEDKey "platform-setDriveFail"
#define kBaySetPowerKey "platform-setDrivePower"
#define kEnableInsertEvent "enable-drivePresent"
#define kEnableSwitchEvent "enable-driveSwitch"
#define kDisableInsertEvent "disable-drivePresent"
#define kDisableSwitchEvent "disable-driveSwitch"
#define kRegisterForInsertEvent "register-drivePresent"
#define kRegisterForSwitchEvent "register-driveSwitch"
#define kInsertEvent 'Inst'
#define kSwitchEvent 'Swch'
#define super IOService
OSDefineMetaClassAndStructors ( AppleKiwiRoot, IOService )
bool
AppleKiwiRoot::init(OSDictionary* properties)
{
DLOG("AppleKiwiRoot init start\n");
baseZeroMap = baseOneMap = baseTwoMap = baseThreeMap = baseFourMap = baseFiveMap = 0;
baseAddrZero = baseAddrOne = baseAddrTwo = baseAddrThree = baseAddrFour = baseAddrFive = 0;
pmRootDomain = 0;
systemIsSleeping = false;
chiplockOnBus = true;
pdc271 = false;
masterpllF = k100mhz_pll;
if (super::init(properties) == false)
{
DLOG("AppleKiwiRoot: super::init() failed\n");
return false;
}
DLOG("AppleKiwiRoot init done\n");
return true;
}
IOService*
AppleKiwiRoot::probe(IOService* provider, SInt32* score)
{
OSData *compatibleEntry;
DLOG("AppleKiwiRoot starting probe\n");
compatibleEntry = OSDynamicCast( OSData, provider->getProperty( "name" ) );
if ( compatibleEntry == 0 )
{
DLOG("AppleKiwiRoot failed getting compatible property\n");
return 0;
}
if ( compatibleEntry->isEqualTo( kNameString, sizeof(kNameString)-1 ) == false )
{
DLOG("AppleKiwiRoot compatible property doesn't match\n");
return 0;
}
return this;
}
bool
AppleKiwiRoot::start( IOService * provider )
{
DLOG("AppleKiwiRoot: starting\n");
static const IOPMPowerState powerStates[ 2 ] = {
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, IOPMPowerOn, IOPMPowerOn, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 }
};
IOPCIDevice *pciNub = (IOPCIDevice *)provider;
if( !super::start( provider))
return( false);
if(pciNub->configRead8( kIOPCIConfigRevisionID) < 0x03)
{
chiplockOnBus = true;
kiwiChipLock = IORecursiveLockAlloc();
if( !kiwiChipLock )
return false;
DLOG("AppleKiwiRoot: pci inline not detected\n");
} else {
DLOG("AppleKiwiRoot: pci inline available\n");
chiplockOnBus = false;
conf40Val = pciNub->configRead8( 0x40);
conf40Val |= 0x01;
pciNub->configWrite8( 0x40, conf40Val);
}
if(pciNub->configRead16( kIOPCIConfigDeviceID) == 0x6269)
{
pdc271 = true;
masterpllF = k133mhz_pll;
DLOG("AppleKiwiRoot: pdc271 detected\n");
}
pciNub->setIOEnable(true);
pciNub->setBusMasterEnable( true );
pciNub->setMemoryEnable(true);
setupPDC270(provider);
AppleKiwiIC* kiwiIC = new AppleKiwiIC;
if( !kiwiIC )
{
DLOG("AppleKiwiRoot: failed to create KiwiIC\n");
return false;
}
if( !kiwiIC->init(NULL) )
{
DLOG("AppleKiwiRoot: failed to init KiwiIC\n");
return false;
}
if( !kiwiIC->start(provider,baseAddrFive) )
{
DLOG("AppleKiwiRoot: failed to start KiwiIC\n");
return false;
}
pmRootDomain = getPMRootDomain();
if (pmRootDomain != 0) {
pmRootDomain->registerInterestedDriver(this);
}
systemIsSleeping = false;
PMinit();
registerPowerDriver(this,(IOPMPowerState *)powerStates,2);
joinPMtree(this);
publishBelow(provider);
DLOG("AppleKiwiRoot: started\n");
return( true);
}
void
AppleKiwiRoot::free()
{
if( baseZeroMap )
{
baseZeroMap->release();
}
if( baseOneMap )
{
baseOneMap->release();
}
if( baseTwoMap )
{
baseTwoMap->release();
}
if( baseThreeMap)
{
baseThreeMap->release();
}
if( baseFourMap )
{
baseFourMap->release();
}
if( baseFiveMap )
{
baseFiveMap->release();
}
if( kiwiChipLock )
{
IORecursiveLockFree( kiwiChipLock);
kiwiChipLock = 0;
}
super::free();
}
AppleKiwiDevice *
AppleKiwiRoot::createNub( IORegistryEntry * from )
{
AppleKiwiDevice * nub;
nub = new AppleKiwiDevice;
if( nub && !nub->init( from, gIODTPlane ))
{
nub->free();
nub = 0;
}
return( nub);
}
void
AppleKiwiRoot::processNub(AppleKiwiDevice * nub)
{
if(!chiplockOnBus)
{
nub->setProperty(kPCIInlineKey, true );
}
if( pdc271 )
{
nub->setProperty(kMode6Key, true );
}
nub->setDeviceMemory( getProvider()->getDeviceMemory());
nub->initProperties();
}
void
AppleKiwiRoot::publishBelow( IORegistryEntry * root )
{
DLOG("AppleKiwiRoot publish below\n");
OSCollectionIterator * kids = 0;
IORegistryEntry * next;
AppleKiwiDevice * nub;
kids = IODTFindMatchingEntries( root, kIODTRecursive | kIODTExclusive, "('ata-disk','atapi-disk','disk')");
if( kids) {
DLOG("AppleKiwiRoot found kids\n");
while( (next = (IORegistryEntry *)kids->getNextObject())) {
if( 0 == (nub = createNub( next )))
continue;
nub->attach( this );
processNub(nub);
if( !nub->deviceIsPresent() )
{
int busNum = 0;
UInt32* gcrReg = (UInt32*) ( baseAddrFive + 0x1108 );
OSString* locationCompare = OSString::withCString( "1" );
if( locationCompare->isEqualTo( nub->getLocation() ))
{
gcrReg = (UInt32*) ( baseAddrFive + 0x1208 );
busNum = 1;
}
locationCompare->release();
*gcrReg |= 0x00000800; OSSynchronizeIO();
DLOG("AppleKiwiRoot - turning off empty bus %d\n", busNum);
}
}
kids->release();
}
}
bool
AppleKiwiRoot::compareNubName( const IOService * nub,
OSString * name, OSString ** matched ) const
{
return( IODTCompareNubName( nub, name, matched )
|| nub->IORegistryEntry::compareName( name, matched ) );
}
IOReturn
AppleKiwiRoot::getNubResources( IOService * nub )
{
if( nub->getDeviceMemory())
return( kIOReturnSuccess );
IODTResolveAddressing( nub, "reg", getProvider()->getDeviceMemoryWithIndex(0) );
return( kIOReturnSuccess);
}
void
AppleKiwiRoot::setupPDC270(IOService* provider)
{
IOPCIDevice *pciNub = (IOPCIDevice *)provider;
baseFiveMap = pciNub->mapDeviceMemoryWithRegister( kIOPCIConfigBaseAddress5 );
if( baseFiveMap == 0 )
{
DLOG("Failed to get base address maps\n");
return;
}
baseAddrFive = (UInt8*) baseFiveMap->getVirtualAddress();
DLOG("baseAddrFive = %lx \n", (UInt32) baseAddrFive);
OSWriteLittleInt16((void*) baseAddrFive, 0x1202, masterpllF);
IOSleep( 10 );
return;
}
void
AppleKiwiRoot::getLock(bool lock)
{
if(!chiplockOnBus)
return;
if( lock )
{
IORecursiveLockLock( kiwiChipLock);
} else {
IORecursiveLockUnlock( kiwiChipLock);
}
}
IOReturn
AppleKiwiRoot::powerStateWillChangeTo (IOPMPowerFlags theFlags, unsigned long, IOService* whichDevice)
{
if ( (whichDevice == pmRootDomain)
&& systemIsSleeping )
{
if ((theFlags & IOPMPowerOn) || (theFlags & IOPMSoftSleep) )
{
DLOG("KiwiRoot::powerStateWillChangeTo waking up\n");
systemIsSleeping = false;
}
}
return IOPMAckImplied;
}
IOReturn
AppleKiwiRoot::powerStateDidChangeTo (IOPMPowerFlags theFlags, unsigned long, IOService* whichDevice)
{
if ( ( whichDevice == pmRootDomain)
&& !systemIsSleeping )
{
if (!(theFlags & IOPMPowerOn) && !(theFlags & IOPMSoftSleep) )
{
DLOG("KiwiRoot::powerStateDidChangeTo going to sleep\n");
getLock(true);
systemIsSleeping = true;
}
}
return IOPMAckImplied;
}
IOReturn
AppleKiwiRoot::setPowerState ( unsigned long powerStateOrdinal, IOService* whatDevice )
{
if( powerStateOrdinal == 0
&& systemIsSleeping )
{
DLOG("AppleKiwiRoot power ordinal 0\n");
}
if( powerStateOrdinal == 1
&& !(systemIsSleeping) )
{
DLOG("AppleKiwiRoot power ordinal 1\n");
IOPCIDevice *pciNub = (IOPCIDevice *)getProvider();
if(!chiplockOnBus)
{
pciNub->configWrite8( 0x40, conf40Val);
}
OSWriteLittleInt16((void*) baseAddrFive, 0x1202, masterpllF);
IODelay( 250 ); getLock(false);
}
return IOPMAckImplied;
}
#pragma mark -
#ifdef DLOG
#undef DLOG
#endif
#ifdef KIWI_BAY_DEBUG
#define DLOG(fmt, args...) IOLog(fmt, ## args)
#else
#define DLOG(fmt, args...)
#endif
#undef super
#define super IOService
OSDefineMetaClassAndStructors(AppleKiwiDevice, IOService);
enum {
kKiwiDevCPowerStateCount = 2
};
bool
AppleKiwiDevice::init( IORegistryEntry * from,
const IORegistryPlane * inPlane )
{
bool result = super::init(from, inPlane);
bayPHandle = 0;
bayState = kBayInitialState;
eventGate = kEventsOff;
childBusState = kChildBusNone;
currPwrState = 1; return result;
}
void
AppleKiwiDevice::initProperties(void)
{
OSData* registryData = 0;
IOReturn retval;
static const IOPMPowerState powerStates[ kKiwiDevCPowerStateCount ] = {
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, IOPMPowerOn, IOPMPowerOn, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 }
};
registryData = OSDynamicCast( OSData, getProperty("AAPL,phandle") );
if( registryData )
{
bayPHandle = * ((UInt32*) registryData->getBytesNoCopy(0,4) );
DLOG("Kiwi Device found %s with data %lx\n", kTrayPresentStatusKey, bayPHandle);
}
char callName[255];
if( bayPHandle )
{
sprintf(callName,"%s-%8lx", kRegisterForInsertEvent, bayPHandle);
retval = callPlatformFunction(callName, true, (void*) &sBayEventOccured, (void*)this,
(void*)kInsertEvent, 0 );
DLOG("AppleKiwiDevice registering handler %s returned %x\n", callName, retval);
} else {
DLOG( "AppleKiwiDevice bayPHandle not found, handler not registerd\n" );
}
if( bayPHandle )
{
sprintf(callName,"%s-%8lx", kRegisterForSwitchEvent, bayPHandle);
retval = callPlatformFunction(callName, true, (void*) &sBayEventOccured, (void*) this, (void*)kSwitchEvent, 0 );
DLOG("AppleKiwiDevice registering handler %s returned %x\n", callName, retval);
} else {
DLOG( "AppleKiwiDevice bayPHandle not found, handler not registerd\n" );
}
pmRootDomain = getPMRootDomain();
if (pmRootDomain != 0) {
pmRootDomain->registerInterestedDriver(this);
}
systemIsSleeping = false;
PMinit();
registerPowerDriver( this, (IOPMPowerState *) powerStates,
kKiwiDevCPowerStateCount);
getProvider()->joinPMtree( this);
enableBayEvents();
}
IOService*
AppleKiwiDevice::matchLocation( IOService * )
{
return( this );
}
IOReturn
AppleKiwiDevice::getResources( void )
{
return( ((AppleKiwiRoot *)getProvider())->getNubResources( this ));
}
IOReturn
AppleKiwiDevice::message (UInt32 type, IOService* provider, void* argument)
{
if( provider == 0 )
{
switch( type )
{
case 'onli':
childBusState = kChildBusOnline;
setLEDColor( kLEDGreen );
break;
case 'fail':
childBusState = kChildBusNone;
setLEDColor( kLEDRed );
break;
case 'ofln':
setBayPower( kBayPowerOff);
IOSleep(3000);
setLEDColor( kLEDOff );
break;
default:
break;
}
} else {
return super::message(type, provider, argument);
}
return kATANoErr;
}
bool
AppleKiwiDevice::deviceIsPresent(void)
{
UInt32 isPresent = 0;
IOReturn retval = 0;
char callName[255];
if( bayPHandle )
{
sprintf(callName,"%s-%8lx", kTrayPresentStatusKey, bayPHandle );
retval = callPlatformFunction(callName, false, (void *)&isPresent, 0, 0, 0);
DLOG("AppleKiwiDevice call platform %s returned %d, isPresent = %lu\n", callName, retval, isPresent);
} else {
DLOG( "AppleKiwiDevice bayPHandle not found isPresent\n" );
}
if(isPresent)
{
bayState = kBayDriveNotLocked;
sprintf(callName,"%s-%8lx", kBayOpenSwitchStatusKey, bayPHandle );
retval = callPlatformFunction(callName, false, (void *)&isPresent, 0, 0, 0);
DLOG("AppleKiwiDevice call platform %s returned %d, isPresent = %lu\n", callName, retval, isPresent);
if(isPresent)
{
bayState = kBayDriveLocked;
makeBayReady(0);
registerService();
} else {
handleBayRemoved();
}
} else {
handleBayRemoved();
bayState = kBayEmpty;
}
OSCompareAndSwap(kEventsOff, kEventsOn, &eventGate );
return isPresent;
}
void
AppleKiwiDevice::makeBayReady(UInt32 delayMS)
{
setBayPower( kBayPowerOn);
switch( childBusState )
{
case kChildBusNone:
case kChildBusStarting: break;
case kChildBusOnline:
setLEDColor( kLEDGreen );
break;
case kChildBusFail:
setLEDColor(kLEDRed);
break;
}
}
void
AppleKiwiDevice::handleBayRemoved(void)
{
setLEDColor( kLEDRed );
IORegistryEntry *myTempchild = getChildEntry(gIOServicePlane);
IOService *ioServiceChild = OSDynamicCast(IOService, myTempchild);
if (ioServiceChild != NULL)
{
DLOG("AppleKiwi Sending removal message\n");
messageClient(kATARemovedEvent, ioServiceChild, (void*)OSString::withCString( kNameString ), 0);
} else {
DLOG("AppleKiwi removal event but no ioService child to message\n");
setBayPower( kBayPowerOff);
setLEDColor( kLEDOff );
}
childBusState = kChildBusNone;
}
void
AppleKiwiDevice::enableBayEvents(void)
{
IOReturn retval;
char callName[256];
sprintf(callName,"%s-%8lx", kEnableInsertEvent, bayPHandle);
retval = callPlatformFunction(callName, true, (void*) &sBayEventOccured, (void*)this, (void*)kInsertEvent, 0 );
sprintf(callName,"%s-%8lx", kEnableSwitchEvent, bayPHandle);
retval = callPlatformFunction(callName, true, (void*) &sBayEventOccured, (void*) this,(void*)kSwitchEvent, 0 );
DLOG("AppleKiwiDevice enable handler %s returned %x\n", callName, retval);
}
void
AppleKiwiDevice::disableBayEvents(void)
{
IOReturn retval;
char callName[256];
sprintf(callName,"%s-%8lx", kDisableInsertEvent, bayPHandle);
retval = callPlatformFunction(callName, true, (void*) &sBayEventOccured, (void*)this, (void*)kInsertEvent, 0 );
sprintf(callName,"%s-%8lx", kDisableSwitchEvent, bayPHandle);
retval = callPlatformFunction(callName, true, (void*) &sBayEventOccured, (void*) this,(void*)kSwitchEvent, 0 );
DLOG("AppleKiwiDevice disable handler %s returned %x\n", callName, retval);
}
void
AppleKiwiDevice::handleBayEvent(UInt32 event, UInt32 newData)
{
if( childBusState == kChildBusStarting )
{
DLOG("Kiwi bus is still starting - handle bay event ignored.\n");
return;
}
if( (event == kInsertEvent) && (newData == 0) && (bayState == kBayDriveLocked ) ) {
DLOG("AppleKiwi drive was removed while bay in locked state!!!!\n");
handleBayRemoved();
bayState = kBayEmpty;
return;
}
switch( bayState )
{
case kBayInitialState: DLOG("AppleKiwi handleBay event status unknown!\n");
break;
case kBayEmpty: if( (event == kInsertEvent) && (newData != 0) )
{
bayState = kBayDriveNotLocked;
DLOG( "AppleKiwi drive inserted\n");
UInt32 bayBits = getBayStatus();
if( bayBits & 0x02)
{
handleBayEvent( kSwitchEvent, 1);
}
} else {
DLOG("AppleKiwi bay empty but got some other event!\n");
}
break;
case kBayDriveNotLocked: if( ( event == kInsertEvent ) && (newData == 0) )
{
bayState = kBayEmpty;
DLOG("AppleKiwi bay empty\n");
} else if( (event == kSwitchEvent) && (newData != 0) ) {
childBusState = kChildBusStarting;
setBayPower( kBayPowerOn);
setLEDColor( kLEDOrange ); DLOG("AppleKiwi bay latching. Data = %x\n", (unsigned int)newData);
IOSleep( 1000 );
registerService();
bayState = kBayDriveLocked;
DLOG("AppleKiwi handle locked, starting disk.\n");
} else {
DLOG("AppleKiwi kBayDriveNotLocked got unexpected event\n");
}
break;
case kBayDriveLocked : if( event == kSwitchEvent && newData == 0)
{
DLOG("AppleKiwi handle is being unlocked, stopping disk. Data = %x\n", (unsigned int) newData);
handleBayRemoved();
bayState = kBayDrivePendRemoval;
} else {
DLOG("AppleKiwi kBayDriveLocked got unexpected event\n");
}
break;
case kBayDrivePendRemoval: if( (event == kInsertEvent) && (newData == 0) ) {
bayState = kBayEmpty;
DLOG("AppleKiwi bay empty from pend-removal\n");
} else {
DLOG("AppleKiwi event while in pend-removal state\n");
;
}
break;
default:
DLOG("AppleKiwi handled unexpected default event\n");
break;
}
}
void
AppleKiwiDevice::sBayEventOccured( void* p1, void* p2, void* p3, void* p4)
{
AppleKiwiDevice* me = (AppleKiwiDevice*) p1;
if( OSCompareAndSwap( kEventsOn, kEventsOff, &(me->eventGate) ) )
{
me->handleBayEvent( (UInt32)p2, (UInt32)p4 );
OSCompareAndSwap( kEventsOff, kEventsOn, &(me->eventGate) );
}
}
void
AppleKiwiDevice::setLEDColor( UInt32 color)
{
char callGreen[255];
char callRed[255];
if( bayPHandle )
{
sprintf(callGreen,"%s-%8lx", kBaySetActiveLEDKey, bayPHandle );
sprintf(callRed,"%s-%8lx", kBaySetFailLEDKey, bayPHandle );
switch( color )
{
case kLEDOff:
callPlatformFunction(callGreen, false, (void *)0, 0, 0, 0);
callPlatformFunction(callRed, false, (void *)0, 0, 0, 0);
break;
case kLEDGreen:
callPlatformFunction(callGreen, false, (void *)1, 0, 0, 0);
callPlatformFunction(callRed, false, (void *)0, 0, 0, 0);
break;
case kLEDOrange:
callPlatformFunction(callGreen, false, (void *)1, 0, 0, 0);
callPlatformFunction(callRed, false, (void *)1, 0, 0, 0);
break;
case kLEDRed:
callPlatformFunction(callGreen, false, (void *)0, 0, 0, 0);
callPlatformFunction(callRed, false, (void *)1, 0, 0, 0);
break;
default:
break;
}
}
}
void
AppleKiwiDevice::setBayPower( UInt32 powerState )
{
char callName[255];
if( bayPHandle )
{
sprintf(callName,"%s-%8lx", kBaySetPowerKey, bayPHandle );
switch( powerState )
{
case kBayPowerOn:
callPlatformFunction(callName, false, (void*)1, 0, 0, 0); break;
case kBayPowerOff:
callPlatformFunction(callName, false, 0, 0, 0, 0); break;
default:
break;
}
}
}
UInt32
AppleKiwiDevice::getBayStatus( void )
{
IOReturn errVal = 0;
UInt32 platformStatus = 0;
UInt32 bayBits = 0; char callName[255];
sprintf(callName,"%s-%8lx", kTrayPresentStatusKey, bayPHandle );
errVal = callPlatformFunction(callName, false, (void *)&platformStatus, 0, 0, 0);
if( platformStatus )
{
bayBits |= 0x01;
}
platformStatus = 0;
sprintf(callName,"%s-%8lx", kBayOpenSwitchStatusKey, bayPHandle );
errVal = callPlatformFunction(callName, false, (void *)&platformStatus, 0, 0, 0);
if( platformStatus )
{
bayBits |= (0x02);
}
if(bayBits == 0x02 )
{
DLOG("Kiwidevice - bay handles in invalid state!!!\n");
;
}
return bayBits;
}
IOReturn
AppleKiwiDevice::setPowerState ( unsigned long powerStateOrdinal, IOService* whatDevice )
{
if( powerStateOrdinal == 0
&& systemIsSleeping )
{
DLOG("KiwiDevice power ordinal 0\n");
currPwrState = 0;
}
UInt32 states[4] = { kBayEmpty, kBayDriveNotLocked, 0xffffffff, kBayDriveLocked};
if( powerStateOrdinal == 1
&& (currPwrState == 0)
&& !(systemIsSleeping) )
{
DLOG("KiwiDevice power ordinal 1\n");
if( bayState == kBayDrivePendRemoval )
{
bayState = kBayDriveNotLocked;
}
UInt32 bayBits = getBayStatus();
UInt32 bayStatNow = states[bayBits];
if( bayBits == 0x02 )
{
bayStatNow = kBayEmpty;
}
if( bayStatNow == bayState )
{
if( bayState == kBayDriveLocked)
{
makeBayReady( 0 );
} else {
setLEDColor( kLEDOff );
setBayPower( kBayPowerOff );
}
}
switch( bayState )
{
case kBayEmpty:
if( bayBits & 0x01 )
{
handleBayEvent( kInsertEvent, 1);
}
if( bayBits & 0x02)
{
handleBayEvent( kSwitchEvent, 1);
}
break;
case kBayDriveNotLocked:
if( !(bayBits & 0x01) )
{
handleBayEvent( kInsertEvent, 0);
} else if( bayBits & 0x02){
handleBayEvent( kSwitchEvent, 1);
}
break;
case kBayDriveLocked:
if( !(bayBits & 0x02))
{
handleBayEvent( kSwitchEvent, 0);
}
if( !(bayBits & 0x01) )
{
handleBayEvent( kInsertEvent, 0);
}
break;
default:
break;
}
}
return IOPMAckImplied;
}
IOReturn
AppleKiwiDevice::powerStateWillChangeTo (IOPMPowerFlags theFlags, unsigned long, IOService* whichDevice)
{
if ( ( whichDevice == pmRootDomain)
&& !systemIsSleeping )
{
if (!(theFlags & IOPMPowerOn) && !(theFlags & IOPMSoftSleep) )
{
DLOG("AppleKiwiDevice::powerStateWillChangeTo going to sleep\n");
systemIsSleeping = true;
}
}
return IOPMAckImplied;
}
IOReturn
AppleKiwiDevice::powerStateDidChangeTo (IOPMPowerFlags theFlags, unsigned long, IOService* whichDevice)
{
if ( (whichDevice == pmRootDomain)
&& systemIsSleeping )
{
if ((theFlags & IOPMPowerOn) || (theFlags & IOPMSoftSleep) )
{
DLOG("AppleKiwiDevice::powerStateDidChangeTo waking up\n");
systemIsSleeping = false;
}
}
return IOPMAckImplied;
}
#pragma mark -
#ifdef DLOG
#undef DLOG
#endif
#ifdef KIWI_IC_DEBUG
#define DLOG(fmt, args...) IOLog(fmt, ## args)
#else
#define DLOG(fmt, args...)
#endif
#undef super
#define super IOService
#undef super
#define super IOInterruptController
OSDefineMetaClassAndStructors(AppleKiwiIC, IOInterruptController);
enum {
kIOSLICPowerStateCount = 2
};
bool
AppleKiwiIC::start(IOService *provider, UInt8* inBar5)
{
if( !provider || !inBar5 )
return false;
gcr0 = (volatile UInt32*) (inBar5 + 0x1108);
gcr1 = (volatile UInt32*) (inBar5 + 0x1208);
if (!super::start(provider))
{
DLOG ("AppleKiwiIC::start - super::start(provider) returned false\n");
return false;
}
myProvider = provider;
interruptControllerName = (OSSymbol *)IODTInterruptControllerName( provider );
if (interruptControllerName == 0) {
DLOG ("AppleKiwiIC::start - interruptControllerName is NULL\n");
return false;
}
UInt32 numVectors = 2;
UInt32 sizeofVectors = numVectors * sizeof(IOInterruptVector);
vectors = (IOInterruptVector *)IOMalloc(sizeofVectors);
if (vectors == NULL) {
DLOG ("AppleKiwiIC::start - cannot allocate vectors\n");
return false;
}
bzero(vectors, sizeofVectors);
for (unsigned int cnt = 0; cnt < numVectors ; cnt++) {
vectors[cnt].interruptLock = IOLockAlloc();
if (vectors[cnt].interruptLock == NULL) {
for (cnt = 0; cnt < numVectors; cnt++) {
if (vectors[cnt].interruptLock != NULL)
IOLockFree(vectors[cnt].interruptLock);
}
DLOG ("AppleKiwiIC::start - cannot allocate lock for vectors[%d]\n", cnt);
return false;
}
}
*gcr0 &= (~ 0x00000200); *gcr1 &= (~ 0x00000400);
provider->registerInterrupt(0, this, getInterruptHandlerAddress(), 0);
getPlatform()->registerInterruptController(interruptControllerName, this);
provider->enableInterrupt(0);
DLOG ("AppleKiwiIC::start - finished\n");
return true;
}
IOReturn
AppleKiwiIC::getInterruptType(IOService *nub, int source,
int *interruptType)
{
if (interruptType == 0) return kIOReturnBadArgument;
*interruptType = kIOInterruptTypeLevel;
return kIOReturnSuccess;
}
IOInterruptAction
AppleKiwiIC::getInterruptHandlerAddress(void)
{
return OSMemberFunctionCast(IOInterruptAction, this, &AppleKiwiIC::handleInterrupt) ;
}
IOReturn
AppleKiwiIC::handleInterrupt( void* ,
IOService* ,
int )
{
long vectorNumber = 0;
IOInterruptVector *vector;
for(int i = 0; i < 2; i++)
{
vectorNumber = i;
vector = &vectors[vectorNumber];
vector->interruptActive = 1;
sync();
isync();
if (!vector->interruptDisabledSoft) {
isync();
if (vector->interruptRegistered) {
vector->handler(vector->target, vector->refCon, vector->nub, vector->source);
if (vector->interruptDisabledSoft) {
vector->interruptDisabledHard = 1;
disableVectorHard(vectorNumber, vector);
}
}
} else {
vector->interruptDisabledHard = 1;
disableVectorHard(vectorNumber, vector);
}
vector->interruptActive = 0;
}
return kIOReturnSuccess;
}
bool
AppleKiwiIC::vectorCanBeShared(long vectorNumber, IOInterruptVector *vector)
{
return false;
}
void
AppleKiwiIC::initVector(long vectorNumber, IOInterruptVector *vector)
{
return;
}
void
AppleKiwiIC::disableVectorHard(long vectorNumber, IOInterruptVector *vector)
{
myProvider->disableInterrupt( 0 );
#if 0
switch( vectorNumber )
{
case 0:
OSSynchronizeIO();
break;
case 1:
OSSynchronizeIO();
break;
default:
break; }
}
#endif
}
void
AppleKiwiIC::enableVector(long vectorNumber, IOInterruptVector *vector)
{
myProvider->enableInterrupt( 0 );
#if 0
switch( vectorNumber )
{
case 0:
OSSynchronizeIO();
break;
case 1:
OSSynchronizeIO();
break;
default:
break; }
#endif
}
IOReturn
AppleKiwiIC::setPowerState ( unsigned long powerStateOrdinal, IOService* whatDevice )
{
return IOPMAckImplied;
}