ApplePS2Controller.cpp [plain text]
#include <IOKit/assert.h>
#include <IOKit/IOService.h>
#include <IOKit/IOSyncer.h>
#include <IOKit/ps2/ApplePS2KeyboardDevice.h>
#include <IOKit/ps2/ApplePS2MouseDevice.h>
#include "ApplePS2Controller.h"
extern "C"
{
#include <machine/machine_routines.h>
}
#warning FIXME: use inb and outb from the kernel framework (2688371)
typedef unsigned short i386_ioport_t;
inline unsigned char inb(i386_ioport_t port)
{
unsigned char datum;
asm volatile("inb %1, %0" : "=a" (datum) : "d" (port));
return(datum);
}
inline void outb(i386_ioport_t port, unsigned char datum)
{
asm volatile("outb %0, %1" : : "a" (datum), "d" (port));
}
enum {
kPS2PowerStateSleep = 0,
kPS2PowerStateDoze = 1,
kPS2PowerStateNormal = 2,
kPS2PowerStateCount
};
static const IOPMPowerState PS2PowerStateArray[ kPS2PowerStateCount ] =
{
{ 1,0,0,0,0,0,0,0,0,0,0,0 },
{ 1,kIOPMDeviceUsable, kIOPMDoze, kIOPMDoze, 0,0,0,0,0,0,0,0 },
{ 1,kIOPMDeviceUsable, IOPMPowerOn, IOPMPowerOn, 0,0,0,0,0,0,0,0 }
};
static ApplePS2Controller * gApplePS2Controller = 0;
static void interruptHandlerMouse(OSObject *, void *, IOService *, int)
{
gApplePS2Controller->_interruptSourceMouse->interruptOccurred(0, 0, 0);
}
static void interruptHandlerKeyboard(OSObject *, void *, IOService *, int)
{
#if DEBUGGER_SUPPORT
UInt8 key;
UInt8 status;
int state;
gApplePS2Controller->lockController(&state);
if ( ((status = inb(kCommandPort)) & kOutputReady) )
{
if ( (status & kMouseData) )
{
interruptHandlerMouse(0, 0, 0, 0);
}
else
{
key = inb(kDataPort);
if (gApplePS2Controller->_debuggingEnabled == false ||
gApplePS2Controller->doEscape(key) == false)
gApplePS2Controller->enqueueKeyboardData(key);
gApplePS2Controller->_interruptSourceKeyboard->interruptOccurred(0, 0, 0);
}
}
gApplePS2Controller->unlockController(state);
#else
gApplePS2Controller->_interruptSourceKeyboard->interruptOccurred(0, 0, 0);
#endif DEBUGGER_SUPPORT
}
#define super IOService
OSDefineMetaClassAndStructors(ApplePS2Controller, IOService);
bool ApplePS2Controller::init(OSDictionary * properties)
{
if (!super::init(properties)) return false;
_workLoop = 0;
_interruptSourceKeyboard = 0;
_interruptSourceMouse = 0;
_interruptTargetKeyboard = 0;
_interruptTargetMouse = 0;
_interruptActionKeyboard = NULL;
_interruptActionMouse = NULL;
_interruptInstalledKeyboard = false;
_interruptInstalledMouse = false;
_mouseDevice = 0;
_keyboardDevice = 0;
queue_init(&_requestQueue);
_currentPowerState = kPS2PowerStateNormal;
#if DEBUGGER_SUPPORT
_extendedState = false;
_modifierState = 0x00;
_debuggingEnabled = false;
_keyboardQueueAlloc = NULL;
queue_init(&_keyboardQueue);
queue_init(&_keyboardQueueUnused);
_controllerLock = IOSimpleLockAlloc();
if (!_controllerLock) return false;
#endif DEBUGGER_SUPPORT
return true;
}
void ApplePS2Controller::free(void)
{
if (_controllerLock)
{
IOSimpleLockFree(_controllerLock);
_controllerLock = 0;
}
super::free();
}
bool ApplePS2Controller::start(IOService * provider)
{
if (!super::start(provider)) return false;
#if DEBUGGER_SUPPORT
int debugFlag = 0;
PE_parse_boot_arg("debug", &debugFlag);
if (debugFlag) _debuggingEnabled = true;
_keyboardQueueAlloc = (KeyboardQueueElement *)
IOMalloc(kKeyboardQueueSize*sizeof(KeyboardQueueElement));
if (!_keyboardQueueAlloc) goto fail;
for (int index = 0; index < kKeyboardQueueSize; index++)
queue_enter(&_keyboardQueueUnused, &_keyboardQueueAlloc[index],
KeyboardQueueElement *, chain);
#endif DEBUGGER_SUPPORT
UInt8 commandByte;
writeCommandPort(kCP_GetCommandByte);
commandByte = readDataPort(kDT_Keyboard);
commandByte &= ~(kCB_EnableMouseIRQ | kCB_DisableMouseClock);
writeCommandPort(kCP_SetCommandByte);
writeDataPort(commandByte);
writeDataPort(kDP_SetDefaultsAndDisable);
readDataPort(kDT_Keyboard);
writeCommandPort(kCP_TransmitToMouse);
writeDataPort(kDP_SetDefaultsAndDisable);
readDataPort(kDT_Mouse);
while ( inb(kCommandPort) & kOutputReady )
{
IODelay(kDataDelay);
inb(kDataPort);
IODelay(kDataDelay);
}
_requestQueueLock = IOSimpleLockAlloc();
if (!_requestQueueLock) goto fail;
_workLoop = IOWorkLoop::workLoop();
_interruptSourceMouse = IOInterruptEventSource::interruptEventSource(
this, (IOInterruptEventAction) &ApplePS2Controller::interruptOccurred);
_interruptSourceKeyboard = IOInterruptEventSource::interruptEventSource(
this, (IOInterruptEventAction) &ApplePS2Controller::interruptOccurred);
_interruptSourceQueue = IOInterruptEventSource::interruptEventSource(
this, (IOInterruptEventAction) &ApplePS2Controller::processRequestQueue);
if ( !_workLoop ||
!_interruptSourceMouse ||
!_interruptSourceKeyboard ||
!_interruptSourceQueue ) goto fail;
if ( _workLoop->addEventSource(_interruptSourceQueue) != kIOReturnSuccess )
goto fail;
_interruptSourceQueue->enable();
_powerChangeThreadCall = thread_call_allocate(
(thread_call_func_t) setPowerStateCallout,
(thread_call_param_t) this );
if ( !_powerChangeThreadCall )
goto fail;
PMinit();
registerPowerDriver( this, (IOPMPowerState *) PS2PowerStateArray,
kPS2PowerStateCount );
provider->joinPMtree(this);
_keyboardDevice = new ApplePS2KeyboardDevice;
if ( !_keyboardDevice ||
!_keyboardDevice->init() ||
!_keyboardDevice->attach(this) ) goto fail;
_mouseDevice = new ApplePS2MouseDevice;
if ( !_mouseDevice ||
!_mouseDevice->init() ||
!_mouseDevice->attach(this) ) goto fail;
gApplePS2Controller = this;
_keyboardDevice->registerService();
_mouseDevice->registerService();
return true;
fail:
stop(provider);
return false;
}
void ApplePS2Controller::stop(IOService * provider)
{
#define RELEASE(x) do { if(x) { (x)->release(); (x) = 0; } } while(0)
assert(_interruptInstalledKeyboard == false);
assert(_interruptInstalledMouse == false);
assert(_powerControlInstalledKeyboard == false);
assert(_powerControlInstalledMouse == false);
RELEASE(_keyboardDevice);
RELEASE(_mouseDevice);
RELEASE(_workLoop);
RELEASE(_interruptSourceKeyboard);
RELEASE(_interruptSourceMouse);
RELEASE(_interruptSourceQueue);
if (_requestQueueLock)
{
_hardwareOffline = true;
processRequestQueue(0, 0);
IOSimpleLockFree(_requestQueueLock);
_requestQueueLock = 0;
}
if (_powerChangeThreadCall)
{
thread_call_free(_powerChangeThreadCall);
_powerChangeThreadCall = 0;
}
PMstop();
#if DEBUGGER_SUPPORT
if (_keyboardQueueAlloc)
IOFree(_keyboardQueueAlloc,kKeyboardQueueSize*sizeof(KeyboardQueueElement));
#endif DEBUGGER_SUPPORT
gApplePS2Controller = 0;
super::stop(provider);
}
IOWorkLoop * ApplePS2Controller::getWorkLoop() const
{
return _workLoop;
}
void ApplePS2Controller::installInterruptAction(PS2DeviceType deviceType,
OSObject * target,
PS2InterruptAction action)
{
if (deviceType == kDT_Keyboard && _interruptInstalledKeyboard == false)
{
target->retain();
_interruptTargetKeyboard = target;
_interruptActionKeyboard = action;
_workLoop->addEventSource(_interruptSourceKeyboard);
getProvider()->registerInterrupt(kIRQ_Keyboard,0, interruptHandlerKeyboard);
getProvider()->enableInterrupt(kIRQ_Keyboard);
_interruptInstalledKeyboard = true;
}
else if (deviceType == kDT_Mouse && _interruptInstalledMouse == false)
{
target->retain();
_interruptTargetMouse = target;
_interruptActionMouse = action;
_workLoop->addEventSource(_interruptSourceMouse);
getProvider()->registerInterrupt(kIRQ_Mouse, 0, interruptHandlerMouse);
getProvider()->enableInterrupt(kIRQ_Mouse);
_interruptInstalledMouse = true;
}
}
void ApplePS2Controller::uninstallInterruptAction(PS2DeviceType deviceType)
{
if (deviceType == kDT_Keyboard && _interruptInstalledKeyboard == true)
{
getProvider()->disableInterrupt(kIRQ_Keyboard);
getProvider()->unregisterInterrupt(kIRQ_Keyboard);
_workLoop->removeEventSource(_interruptSourceKeyboard);
_interruptInstalledKeyboard = false;
_interruptActionKeyboard = NULL;
_interruptTargetKeyboard->release();
_interruptTargetKeyboard = 0;
}
else if (deviceType == kDT_Mouse && _interruptInstalledMouse == true)
{
getProvider()->disableInterrupt(kIRQ_Mouse);
getProvider()->unregisterInterrupt(kIRQ_Mouse);
_workLoop->removeEventSource(_interruptSourceMouse);
_interruptInstalledMouse = false;
_interruptActionMouse = NULL;
_interruptTargetMouse->release();
_interruptTargetMouse = 0;
}
}
PS2Request * ApplePS2Controller::allocateRequest()
{
PS2Request * request = (PS2Request *) IOMalloc(sizeof(PS2Request));
bzero(request, sizeof(PS2Request));
return request;
}
void ApplePS2Controller::freeRequest(PS2Request * request)
{
IOFree(request, sizeof(PS2Request));
}
bool ApplePS2Controller::submitRequest(PS2Request * request)
{
IOSimpleLockLock(_requestQueueLock);
queue_enter(&_requestQueue, request, PS2Request *, chain);
IOSimpleLockUnlock(_requestQueueLock);
_interruptSourceQueue->interruptOccurred(0, 0, 0);
return true;
}
void ApplePS2Controller::submitRequestAndBlock(PS2Request * request)
{
if (_workLoop->inGate())
{
request->completionTarget = this;
request->completionAction = submitRequestAndBlockCompletion;
request->completionParam = 0;
processRequestQueue(0, 0);
processRequest(request);
}
else
{
IOSyncer * completionSyncer = IOSyncer::create();
assert(completionSyncer);
request->completionTarget = this;
request->completionAction = submitRequestAndBlockCompletion;
request->completionParam = completionSyncer;
submitRequest(request);
completionSyncer->wait(); }
}
void ApplePS2Controller::submitRequestAndBlockCompletion(void *, void * param)
{ if (param)
{
IOSyncer * completionSyncer = (IOSyncer *) param;
completionSyncer->signal();
}
}
void ApplePS2Controller::interruptOccurred(IOInterruptEventSource *, int)
{
if (_hardwareOffline)
{
return;
}
UInt8 status;
#if DEBUGGER_SUPPORT
int state;
lockController(&state); while (1)
{
if (dequeueKeyboardData(&status))
{
unlockController(state);
dispatchDriverInterrupt(kDT_Keyboard, status);
lockController(&state);
}
else if ( (inb(kCommandPort) & (kOutputReady | kMouseData)) ==
(kOutputReady | kMouseData))
{
unlockController(state);
dispatchDriverInterrupt(kDT_Mouse, inb(kDataPort));
lockController(&state);
}
else break; }
unlockController(state); #else
while ( ((status = inb(kCommandPort)) & kOutputReady) )
{
dispatchDriverInterrupt((status&kMouseData)?kDT_Mouse:kDT_Keyboard,
inb(kDataPort));
}
#endif DEBUGGER_SUPPORT
}
void ApplePS2Controller::dispatchDriverInterrupt(PS2DeviceType deviceType,
UInt8 data)
{
if ( deviceType == kDT_Mouse )
{
if (_interruptInstalledMouse)
(*_interruptActionMouse)(_interruptTargetMouse, data);
}
else if ( deviceType == kDT_Keyboard )
{
if (_interruptInstalledKeyboard)
(*_interruptActionKeyboard)(_interruptTargetKeyboard, data);
}
}
void ApplePS2Controller::processRequest(PS2Request * request)
{
UInt8 byte;
PS2DeviceType deviceMode = kDT_Keyboard;
bool failed = false;
bool transmitToMouse = false;
unsigned index;
if (_hardwareOffline)
{
failed = true;
index = 0;
goto hardware_offline;
}
for (index = 0; index < request->commandsCount; index++)
{
switch (request->commands[index].command)
{
case kPS2C_ReadDataPort:
request->commands[index].inOrOut = readDataPort(deviceMode);
break;
case kPS2C_ReadDataPortAndCompare:
#if OUT_OF_ORDER_DATA_CORRECTION_FEATURE
byte = readDataPort(deviceMode, request->commands[index].inOrOut);
#else
byte = readDataPort(deviceMode);
#endif
failed = (byte != request->commands[index].inOrOut);
break;
case kPS2C_WriteDataPort:
writeDataPort(request->commands[index].inOrOut);
if (transmitToMouse) {
deviceMode = kDT_Mouse;
transmitToMouse = false;
}
else
{
deviceMode = kDT_Keyboard;
}
break;
case kPS2C_WriteCommandPort:
writeCommandPort(request->commands[index].inOrOut);
if (request->commands[index].inOrOut == kCP_TransmitToMouse)
transmitToMouse = true; break;
case kPS2C_SendMouseCommandAndCompareAck:
writeCommandPort(kCP_TransmitToMouse);
writeDataPort(request->commands[index].inOrOut);
deviceMode = kDT_Mouse;
#if OUT_OF_ORDER_DATA_CORRECTION_FEATURE
byte = readDataPort(kDT_Mouse, kSC_Acknowledge);
#else
byte = readDataPort(kDT_Mouse);
#endif
failed = (byte != kSC_Acknowledge);
break;
}
if (failed) break;
}
hardware_offline:
if (failed) request->commandsCount = index;
if (request->completionTarget && request->completionAction)
{
(*request->completionAction)(request->completionTarget,
request->completionParam);
}
else
{
freeRequest(request);
}
}
void ApplePS2Controller::processRequestQueue(IOInterruptEventSource *, int)
{
queue_head_t localQueue;
IOSimpleLockLock(_requestQueueLock);
if (!queue_empty(&_requestQueue))
{
queue_assign(&localQueue, &_requestQueue, PS2Request *, chain);
queue_init(&_requestQueue);
}
else queue_init(&localQueue);
IOSimpleLockUnlock(_requestQueueLock);
while (!queue_empty(&localQueue))
{
PS2Request * request;
queue_remove_first(&localQueue, request, PS2Request *, chain);
processRequest(request);
}
}
UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType)
{
UInt8 readByte;
UInt8 status;
UInt32 timeoutCounter = 10000;
while (1)
{
#if DEBUGGER_SUPPORT
int state;
lockController(&state); if (deviceType == kDT_Keyboard && dequeueKeyboardData(&readByte))
{
unlockController(state);
return readByte;
}
#endif DEBUGGER_SUPPORT
while (timeoutCounter && !((status = inb(kCommandPort)) & kOutputReady))
{
timeoutCounter--;
IODelay(kDataDelay);
}
if (timeoutCounter == 0)
{
#if DEBUGGER_SUPPORT
unlockController(state); #endif DEBUGGER_SUPPORT
IOLog("%s: Timed out on %s input stream.\n", getName(),
(deviceType == kDT_Keyboard) ? "keyboard" : "mouse");
return 0;
}
IODelay(kDataDelay);
readByte = inb(kDataPort);
#if DEBUGGER_SUPPORT
unlockController(state); #endif DEBUGGER_SUPPORT
if ( (status & kMouseData) )
{
if (deviceType == kDT_Mouse) return readByte;
}
else
{
if (deviceType == kDT_Keyboard) return readByte;
}
dispatchDriverInterrupt((deviceType==kDT_Keyboard)?kDT_Mouse:kDT_Keyboard,
readByte);
} }
#if OUT_OF_ORDER_DATA_CORRECTION_FEATURE
UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType,
UInt8 expectedByte)
{
UInt8 firstByte = 0;
bool firstByteHeld = false;
UInt8 readByte;
bool requestedStream;
UInt8 status;
UInt32 timeoutCounter = 10000;
while (1)
{
#if DEBUGGER_SUPPORT
int state;
lockController(&state); if (deviceType == kDT_Keyboard && dequeueKeyboardData(&readByte))
{
requestedStream = true;
goto skipForwardToY;
}
#endif DEBUGGER_SUPPORT
while (timeoutCounter && !((status = inb(kCommandPort)) & kOutputReady))
{
timeoutCounter--;
IODelay(kDataDelay);
}
if (timeoutCounter == 0)
{
#if DEBUGGER_SUPPORT
unlockController(state); #endif DEBUGGER_SUPPORT
if (firstByteHeld) return firstByte;
IOLog("%s: Timed out on %s input stream.\n", getName(),
(deviceType == kDT_Keyboard) ? "keyboard" : "mouse");
return 0;
}
IODelay(kDataDelay);
readByte = inb(kDataPort);
requestedStream = false;
if ( (status & kMouseData) )
{
if (deviceType == kDT_Mouse) requestedStream = true;
}
else
{
if (deviceType == kDT_Keyboard) requestedStream = true;
}
#if DEBUGGER_SUPPORT
skipForwardToY:
unlockController(state); #endif DEBUGGER_SUPPORT
if (requestedStream)
{
if (readByte == expectedByte)
{
if (firstByteHeld == false)
{
return readByte;
}
else
{
dispatchDriverInterrupt(deviceType, firstByte);
return readByte;
}
}
else {
if (firstByteHeld == false)
{
firstByteHeld = true;
firstByte = readByte;
}
else if (readByte != expectedByte)
{
dispatchDriverInterrupt(deviceType, readByte);
return firstByte;
}
}
}
else
{
dispatchDriverInterrupt((deviceType==kDT_Keyboard)?kDT_Mouse:kDT_Keyboard,
readByte);
}
} }
#endif
void ApplePS2Controller::writeDataPort(UInt8 byte)
{
while (inb(kCommandPort) & kInputBusy) IODelay(kDataDelay);
outb(kDataPort, byte);
}
void ApplePS2Controller::writeCommandPort(UInt8 byte)
{
while (inb(kCommandPort) & kInputBusy) IODelay(kDataDelay);
outb(kCommandPort, byte);
}
#if DEBUGGER_SUPPORT
#define kModifierShiftLeft 0x01
#define kModifierShiftRight 0x02
#define kModifierCtrlLeft 0x04
#define kModifierCtrlRight 0x08
#define kModifierAltLeft 0x10
#define kModifierAltRight 0x20
#define kModifierWindowsLeft 0x40
#define kModifierWindowsRight 0x80
#define kModifierShiftMask (kModifierShiftLeft | kModifierShiftRight )
#define kModifierCtrlMask (kModifierCtrlLeft | kModifierCtrlRight )
#define kModifierAltMask (kModifierAltLeft | kModifierAltRight )
#define kModifierWindowsMask (kModifierWindowsLeft | kModifierWindowsRight)
bool ApplePS2Controller::doEscape(UInt8 scancode)
{
static struct
{
UInt8 scancode;
UInt8 extended;
UInt16 modifier;
} modifierTable[] = { { kSC_Alt, false, kModifierAltLeft },
{ kSC_Alt, true, kModifierAltRight },
{ kSC_Ctrl, false, kModifierCtrlLeft },
{ kSC_Ctrl, true, kModifierCtrlRight },
{ kSC_ShiftLeft, false, kModifierShiftLeft },
{ kSC_ShiftRight, false, kModifierShiftRight },
{ kSC_WindowsLeft, true, kModifierWindowsLeft },
{ kSC_WindowsRight, true, kModifierWindowsRight },
{ 0, 0, 0 } };
UInt32 index;
bool releaseModifiers = false;
bool upBit = (scancode & kSC_UpBit) ? true : false;
if (scancode == kSC_Extend)
{
_extendedState = true;
return false;
}
scancode &= ~kSC_UpBit;
for (index = 0; modifierTable[index].scancode; index++)
{
if ( modifierTable[index].scancode == scancode &&
modifierTable[index].extended == _extendedState )
{
if (upBit) _modifierState &= ~modifierTable[index].modifier;
else _modifierState |= modifierTable[index].modifier;
_extendedState = false;
return false;
}
}
if (scancode == kSC_Delete) {
if ( _modifierState == (kModifierAltLeft | kModifierAltRight) )
{
while (inb(kCommandPort) & kInputBusy) IODelay(kDataDelay);
outb(kCommandPort, kCP_DisableMouseClock);
Debugger("Programmer Key");
while (inb(kCommandPort) & kInputBusy) IODelay(kDataDelay);
outb(kCommandPort, kCP_EnableMouseClock);
releaseModifiers = true;
}
}
if (releaseModifiers)
{
for (index = 0; modifierTable[index].scancode; index++)
{
if ( _modifierState & modifierTable[index].modifier )
{
if (modifierTable[index].extended) enqueueKeyboardData(kSC_Extend);
enqueueKeyboardData(modifierTable[index].scancode | kSC_UpBit);
}
}
_modifierState = 0x00;
}
_extendedState = false;
return (releaseModifiers);
}
void ApplePS2Controller::enqueueKeyboardData(UInt8 key)
{
KeyboardQueueElement * element;
if (!queue_empty(&_keyboardQueueUnused))
{
queue_remove_first(&_keyboardQueueUnused,
element, KeyboardQueueElement *, chain);
element->data = key;
queue_enter(&_keyboardQueue, element, KeyboardQueueElement *, chain);
}
}
bool ApplePS2Controller::dequeueKeyboardData(UInt8 * key)
{
KeyboardQueueElement * element;
if (!queue_empty(&_keyboardQueue))
{
queue_remove_first(&_keyboardQueue, element, KeyboardQueueElement *, chain);
*key = element->data;
queue_enter(&_keyboardQueueUnused, element, KeyboardQueueElement *, chain);
return true;
}
return false;
}
void ApplePS2Controller::unlockController(int state)
{
IOSimpleLockUnlockEnableInterrupt(_controllerLock, state);
}
void ApplePS2Controller::lockController(int * state)
{
*state = IOSimpleLockLockDisableInterrupt(_controllerLock);
}
#endif DEBUGGER_SUPPORT
IOReturn ApplePS2Controller::setPowerState( unsigned long powerStateOrdinal,
IOService * policyMaker)
{
IOReturn result = IOPMAckImplied;
retain();
if ( thread_call_enter1( _powerChangeThreadCall,
(void *) powerStateOrdinal ) == TRUE )
{
release();
}
result = 5000000;
return result;
}
void ApplePS2Controller::setPowerStateCallout( thread_call_param_t param0,
thread_call_param_t param1 )
{
ApplePS2Controller * me = (ApplePS2Controller *) param0;
if ( me && me->_workLoop )
{
me->_workLoop->runAction( setPowerStateAction,
me,
param1 );
}
me->release(); }
IOReturn ApplePS2Controller::setPowerStateAction( OSObject * target,
void * arg0, void * arg1,
void * arg2, void * arg3 )
{
ApplePS2Controller * me = (ApplePS2Controller *) target;
UInt32 powerState = (UInt32) arg0;
me->setPowerStateGated( powerState );
return kIOReturnSuccess;
}
void ApplePS2Controller::setPowerStateGated( UInt32 powerState )
{
UInt8 commandByte;
if ( _currentPowerState != powerState )
{
switch ( powerState )
{
case kPS2PowerStateSleep:
dispatchDriverPowerControl( kPS2C_DisableDevice );
_hardwareOffline = true;
#if 0
writeCommandPort( kCP_GetCommandByte );
commandByte = readDataPort( kDT_Keyboard );
commandByte |= ( kCB_DisableKeyboardClock |
kCB_DisableMouseClock );
commandByte &= ~( kCB_EnableKeyboardIRQ |
kCB_EnableMouseIRQ );
writeCommandPort( kCP_SetCommandByte );
writeDataPort( commandByte );
#endif
break;
case kPS2PowerStateDoze:
case kPS2PowerStateNormal:
if ( _currentPowerState != kPS2PowerStateSleep )
{
break;
}
writeCommandPort( kCP_GetCommandByte );
commandByte = readDataPort( kDT_Keyboard );
commandByte &= ~( kCB_DisableKeyboardClock |
kCB_DisableMouseClock );
commandByte |= ( kCB_EnableKeyboardIRQ |
kCB_EnableMouseIRQ );
writeCommandPort( kCP_SetCommandByte );
writeDataPort( commandByte );
_hardwareOffline = false;
dispatchDriverPowerControl( kPS2C_EnableDevice );
break;
default:
IOLog("%s: bad power state %ld\n", getName(), powerState);
break;
}
_currentPowerState = powerState;
}
acknowledgeSetPowerState();
}
void ApplePS2Controller::dispatchDriverPowerControl( UInt32 whatToDo )
{
if (_powerControlInstalledMouse)
(*_powerControlActionMouse)(_powerControlTargetMouse, whatToDo);
if (_powerControlInstalledKeyboard)
(*_powerControlActionKeyboard)(_powerControlTargetKeyboard, whatToDo);
}
void ApplePS2Controller::installPowerControlAction(
PS2DeviceType deviceType,
OSObject * target,
PS2PowerControlAction action )
{
if ( deviceType == kDT_Keyboard && _powerControlInstalledKeyboard == false )
{
target->retain();
_powerControlTargetKeyboard = target;
_powerControlActionKeyboard = action;
_powerControlInstalledKeyboard = true;
}
else if ( deviceType == kDT_Mouse && _powerControlInstalledMouse == false )
{
target->retain();
_powerControlTargetMouse = target;
_powerControlActionMouse = action;
_powerControlInstalledMouse = true;
}
}
void ApplePS2Controller::uninstallPowerControlAction( PS2DeviceType deviceType )
{
if ( deviceType == kDT_Keyboard && _powerControlInstalledKeyboard == true )
{
_powerControlInstalledKeyboard = false;
_powerControlActionKeyboard = NULL;
_powerControlTargetKeyboard->release();
_powerControlTargetKeyboard = 0;
}
else if ( deviceType == kDT_Mouse && _powerControlInstalledMouse == true )
{
_powerControlInstalledMouse = false;
_powerControlActionMouse = NULL;
_powerControlTargetMouse->release();
_powerControlTargetMouse = 0;
}
}