AppleKeyswitch.cpp [plain text]
#include "AppleKeyswitch.h"
#define super IOService
OSDefineMetaClassAndStructors(AppleKeyswitch, IOService);
bool AppleKeyswitch::start( IOService * provider )
{
UInt8 val = 0;
#if defined( __ppc__ ) // ********************** PowerPC -- Start
OSData *tempOSData;
IOReturn status;
#endif // ********************** PowerPC -- End
DLOG("AppleKeyswitch::start entered.\n");
if ( ! super::start(provider) )
{
DLOG( "AppleKeyswitch::start - super::start() failed\n" );
return false;
}
#if defined( __i386__ ) || defined( __x86_64__ ) // ********************** Intel -- Start
myProvider = (IOACPIPlatformDevice *) provider->metaCast( "IOACPIPlatformDevice" );
if ( ! myProvider )
{
DLOG( "AppleKeyswitch::start - metaCast( 'IOACPIPlatformDevice' ) failed\n" );
return false;
}
if ( ! myProvider->open(this) )
{
IOLog( "AppleKeyswitch::start - open() failed\n" );
return false;
}
#endif // ********************** Intel -- End
myWorkLoop = (IOWorkLoop *)getWorkLoop();
if(myWorkLoop == NULL)
{
IOLog("AppleKeyswitch::start failed to get WorkLoop.\n" );
return false;
}
#if defined( __ppc__ ) // ********************** PowerPC -- Start
DLOG( "AppleKeyswitch::start - PPC-specific initialization entered.\n" );
interruptSource = IOInterruptEventSource::interruptEventSource(this, (IOInterruptEventAction)&AppleKeyswitch::interruptOccurred, provider, 0);
if (interruptSource == NULL)
{
IOLog("AppleKeyswitch::start failed to create interrupt event source.\n");
return false;
}
status = myWorkLoop->addEventSource(interruptSource);
if (status != kIOReturnSuccess)
{
IOLog("AppleKeyswitch::start failed to add interrupt event source to work loop.\n");
return false;
}
keyLargo_safeWriteRegUInt8 = OSSymbol::withCString("keyLargo_safeWriteRegUInt8");
keyLargo_safeReadRegUInt8 = OSSymbol::withCString("keyLargo_safeReadRegUInt8");
tempOSData = OSDynamicCast(OSData, provider->getProperty("reg"));
if (tempOSData == NULL)
{
IOLog("AppleKeyswitch::start - failed to get GPIO offset value.\n");
return false;
}
extIntGPIO = (UInt32*)tempOSData->getBytesNoCopy();
callPlatformFunction(keyLargo_safeWriteRegUInt8, false, (void *)(kKeyLargoGPIOBaseAddr + *extIntGPIO), (void *)0xFF, (void *)0x80, (void *)0);
IOSleep(100);
getKeyswitchState( &val );
interruptSource->enable();
#elif defined( __i386__ ) || defined( __x86_64__ ) // ********************** Intel -- Start
DLOG( "AppleKeyswitch::start - Intel-specific initialization entered.\n" );
switchEventNotify = myProvider->registerInterest( gIOGeneralInterest, keyswitchNotification, this, 0 );
if ( ! switchEventNotify )
{
IOLog( "AppleKeyswitch::start - Unable to register interest in getting keyswitch notifications\n" );
stop( provider );
return false;
}
getKeyswitchState( &val );
#endif // ********************** Intel -- End
DLOG( "AppleKeyswitch::start - Initial keyswitch value: 0x%02X (%s)\n", val, ( val == KEYSWITCH_VALUE_UNLOCKED )? "UNLOCKED" : "LOCKED" );
if( val == KEYSWITCH_VALUE_UNLOCKED )
{
DLOG( "AppleKeyswitch::start - Initial keyswitch state is UNLOCKED\n" );
state = kSWITCH_STATE_IS_UNLOCKED;
setProperty("Keyswitch", false);
}
else
{
DLOG( "AppleKeyswitch::start - Initial keyswitch state is LOCKED\n" );
state = kSWITCH_STATE_IS_LOCKED;
setProperty("Keyswitch", true);
}
registerService();
DLOG("AppleKeyswitch::start - exit.\n");
return true;
}
void AppleKeyswitch::stop(IOService *provider)
{
#if defined( __ppc__ ) // ********************** PowerPC -- Start
interruptSource->disable();
myWorkLoop->removeEventSource(interruptSource);
if (interruptSource != NULL)
{
interruptSource->release();
interruptSource = NULL;
}
#elif defined ( __i386__ ) || defined( __x86_64__ ) // ********************** Intel -- Start
if ( switchEventNotify )
{
DLOG( "AppleKeyswitch::stop - de-registering interest in notifications\n" );
switchEventNotify->remove();
switchEventNotify = 0;
}
#endif // ********************** Intel -- End
if (myWorkLoop != NULL)
{
myWorkLoop->release();
myWorkLoop = NULL;
}
super::stop(provider);
}
#if defined( __ppc__ ) // ********************** PowerPC -- Start
void AppleKeyswitch::interruptOccurred(OSObject* obj, IOInterruptEventSource * source, int count)
{
AppleKeyswitch *AppleKeyswitchPtr = (AppleKeyswitch *)obj;
if (AppleKeyswitchPtr != NULL)
AppleKeyswitchPtr->toggle(false);
return;
}
#endif // ********************** PowerPC -- End
#if defined( __i386__ ) || defined( __x86_64__ ) // ********************** Intel -- Start
IOReturn
AppleKeyswitch::keyswitchNotification( void * target,
void * refCon,
UInt32 messageType,
IOService * provider,
void * messageArgument,
vm_size_t argSize )
{
AppleKeyswitch * me = (AppleKeyswitch *) target;
if ( me )
{
if ( (messageType == kIOACPIMessageDeviceNotification) && messageArgument )
{
UInt32 notifyCode = *(UInt32 *) messageArgument;
DLOG( "AppleKeyswitch::keyswitchNotification - notification received. notifyCode = %lX\n", notifyCode );
if ( notifyCode == 0x80 ) me->toggle( false );
}
}
return kIOReturnSuccess;
}
#endif // ********************** Intel -- End
void AppleKeyswitch::toggle( bool disableInts )
{
UInt8 val;
#if defined( __ppc__ ) // ********************** PowerPC -- Start
UInt8 total = 0;
int i;
if (disableInts)
interruptSource->disable();
for(i=0; i<=100; i++)
{
getKeyswitchState( &val ); total += val;
IOSleep(1);
}
if( total > 80 )
{
state = kSWITCH_STATE_IS_UNLOCKED;
DLOG( "AppleKeyswitch::toggle - changing state to UNLOCKED (%d)\n", state );
setProperty("Keyswitch", false);
registerService();
}
else if( total < 20 )
{
state = kSWITCH_STATE_IS_LOCKED;
DLOG( "AppleKeyswitch::toggle - changing state to LOCKED (%d)\n", state );
setProperty("Keyswitch", true);
registerService();
}
else
{
DLOG( "AppleKeyswitch::toggle - lock state does not yet debounced; leaving state alone\n" );
}
if (disableInts)
interruptSource->enable();
#elif defined ( __i386__ ) || defined( __x86_64__ ) // ********************** Intel -- Start
val = 0;
getKeyswitchState( &val );
if( val == KEYSWITCH_VALUE_UNLOCKED )
{
DLOG( "AppleKeyswitch::toggle - changing state to UNLOCKED (%d)\n", state );
state = kSWITCH_STATE_IS_UNLOCKED;
setProperty("Keyswitch", false);
}
else {
DLOG( "AppleKeyswitch::toggle - changing state to LOCKED (%d)\n", state );
state = kSWITCH_STATE_IS_LOCKED;
setProperty("Keyswitch", true);
}
registerService();
#endif // ********************** Intel -- End
return;
}
void AppleKeyswitch::getKeyswitchState( UInt8 * switchState )
{
UInt8 val = 0;
#if defined( __ppc__ ) // ********************** PowerPC -- Start
callPlatformFunction(keyLargo_safeReadRegUInt8, false, (void *)(kKeyLargoGPIOBaseAddr + *extIntGPIO), (void *)&val, (void *)0, (void *)0);
DLOG( "AppleKeyswitch::getKeyswitchState(ppc) - value read from property: 0x%02X\n", val );
val = ( val & 0x2 ) >> 1;
#elif defined ( __i386__ ) || defined( __x86_64__ ) // ********************** Intel -- Start
IOReturn err;
UInt32 num = 0;
err = myProvider->evaluateInteger( "KLCK", &num );
if ( err == kIOReturnSuccess )
{
DLOG( "AppleKeyswitch::getKeyswitchState(i386) - value read from property: 0x%08lX\n", num );
val = (UInt8) 1 - num;
}
else
{
DLOG( "AppleKeyswitch::getKeyswitchState(i386) - evaluateInteger did NOT succeed (%d)\n", err );
}
#endif // ********************** Intel -- End
* switchState = val;
DLOG( "AppleKeyswitch::getKeyswitchState - value returned to caller: 0x%02X\n", val );
return;
}