AppleADBKeyboard.cpp   [plain text]


/*
 * Copyright (c) 1998-2003 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/*
 * 18 June 1998
 * Start IOKit version.
 */

#include "AppleADBKeyboard.h"
#include <IOKit/hidsystem/IOHIDTypes.h>
#include <IOKit/IOLib.h>
#include <IOKit/IODeviceTreeSupport.h>
#define super IOHIKeyboard
#ifndef kIOHIDFKeyModeKey
#define kIOHIDFKeyModeKey    "HIDFKeyMode"
#endif

OSDefineMetaClassAndStructors(AppleADBKeyboard,IOHIKeyboard)


static void new_kbd_data ( IOService * us, UInt8 adbCommand, IOByteCount length, UInt8 * data );
static void asyncSetLEDFunc ( thread_call_param_t, thread_call_param_t );

#if 0  //The following table is in Info.plist now
//Convert raw ADB codes to MacOS 9 KMAP virtual key codes in dispatchKeyboardEvent()
static unsigned char	kmapConvert[] = 
	{
	//00,00,00,00,  These 4 are in System resource, but are unused
	0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
	0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
	0x30,0x31,0x32,0x33,0x34,0x35,0x3B,0x37,0x38,0x39,0x3A,0x7B,0x7C,0x7D,0x7E,0x3F,
	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x3C,0x3D,0x3E,0x36,0x7F,
	00,00
	}; 	
#endif

void AppleADBKeyboard::stop( IOService * provider )
{
    if (adbDevice)
    {
	IORegistryEntry * us;
	
	us = this;
	adbDevice->releaseFromClient(us); //us is just a placeholder, not used

	adbDevice = 0;
    }

    super::stop(provider);
}

void AppleADBKeyboard::free( void )
{
    if (_keybrdLock)
    {
	IOLockFree(_keybrdLock);
	_keybrdLock = NULL;
    }

    if (adbDevice)
    {
	IORegistryEntry * us;
	
	us = this;
	adbDevice->releaseFromClient(us); //us is just a placeholder, not used

	adbDevice = 0;
    }

    super::free();
}

// **********************************************************************************
// start
//
// **********************************************************************************
bool AppleADBKeyboard::start ( IOService * theNub )
{
    OSString *		data;
    const char *	pTable;
    OSNumber 		*enable_fwd_delete;

    _keybrdLock = NULL;
    _fn_key_invoked_power = false;   //Used by iBook and PowerBooks
    enable_fwd_delete = OSDynamicCast( OSNumber, getProperty("PowerBook fn Foward Delete"));
    if (enable_fwd_delete)
    {
	_enable_fwd_delete = (bool) enable_fwd_delete->unsigned32BitValue();
    }
   
    adbDevice = (IOADBDevice *)theNub;
    if( !adbDevice->seizeForClient(this, new_kbd_data) ) {
	    IOLog("%s: Seize failed\n", getName());
	    return false;
    }
    
    //Get virtual key map table
    data = OSDynamicCast( OSString, getProperty( "ADBVirtualKeys" ));
    if (data)
    {
	pTable = data->getCStringNoCopy();
	if (data->getLength() < (5 * 0x7f)) //7f codes, 5 bytes per code in XML string
	{
	    IOLog("AppleADBKeyboard: too few virtual keys found in Info.plist");
	    for (int i=0; i<128; i++)
	    {
		_virtualmap[i] = i;	//Somewhat usable keymap
	    }
	} 
	else //pTable could get access violation if not all bytes are accounted for
	{
	    for (int i=0; i< 128; i++) //No codes greater than 0x7f allowed in packet()
	    {
		_virtualmap[i] = strtol(pTable, NULL, 16); //Must be base 16
		pTable += 5;  //Format is "0x00,0x01,0x02"
	    }
	}	
    }
    else
    {
	return false; 
    }
    
    _sticky_fn_ON = _stickymodeON = false;
    
    data = OSDynamicCast( OSString, getProperty( "fnVirtualKeys" ));  // 
    if (data)
    {
	pTable = data->getCStringNoCopy();
	if (data->getLength() < (5 * 0x7f)) //7f codes, 5 bytes per code in XML string
	{
	    IOLog("AppleADBKeyboard: too few sticky fn keys found in Info.plist");
	    for (int i=0; i<128; i++)
	    {
		_fnvirtualmap[i] = i;	//Somewhat usable keymap
	    }
	} 
	else 
	{
	    for (int i=0; i< 128; i++) 
	    {
		_fnvirtualmap[i] = strtol(pTable, NULL, 16); //Must be base 16
		pTable += 5;  //Format is "0x00,0x01,0x02"
	    }
	}	
    }
    else
    {
	IOLog("AppleADBKeyboard: no fn keymap found in Info.plist"); 
	//No error return if sticky fn data does not exist, it's not as critical since
	//   numlock on PB would accomplish the same thing.  However, _fnvirtualmap
	//   must be set to something valid
	memcpy(_fnvirtualmap, _virtualmap, 128);
    } 
    
    _get_last_keydown = OSSymbol::withCString("get_last_keydown");
    _get_handler_id = OSSymbol::withCString("get_handler_id");
    _get_device_flags = OSSymbol::withCString("get_device_flags");
    
    turnLEDon = ADBKS_LED_CAPSLOCK | ADBKS_LED_NUMLOCK | ADBKS_LED_SCROLLLOCK; //negative logic
    setAlphaLockFeedback(false);
    setNumLockFeedback(false);
    
    clock_interval_to_absolutetime_interval( 4, kSecondScale, &rebootTime);
    clock_interval_to_absolutetime_interval( 1, kSecondScale, &debuggerTime);
    
    _hasDualModeFunctionKeys = false;
    updateFKeyMap();  //UPDATE PMU DATA IF APPROPRIATE 
    
    getFKeyMode();  // this will update _hasDualModeFunctionKeys
    if (_hasDualModeFunctionKeys)
    {
        setFKeyMode( 0 );  //set PowerBook Function keys to default (0) mode.
    }
    
    getLEDStatus();
    if (LEDStatus & ADBKS_LED_CAPSLOCK) 
    {	
	_oneshotCAPSLOCK = true;
    }
    else
    {
	_oneshotCAPSLOCK = false;
    }

    _keybrdLock = IOLockAlloc(); 

    return super::start(theNub);
}



// --------------------------------------------------------------------------
//
// Method: setFKeyMode
//
// Purpose:  set PowerBook function keys mode.  An argument of zero means
// default mode, while an argument of 1 means F keys primary.  The default
// mode will trigger functions as they appear on the keyboard.  Older
// portables like WallStreet will not be affected since F keys don't
// have dual purposes.  And of course external ADB keyboards are not affected.
void
AppleADBKeyboard::setFKeyMode(UInt8 mode)
{
    UInt16              value;
    IOByteCount         length = sizeof( UInt16);

    if (_hasDualModeFunctionKeys && adbDevice)
    {
        value = mode;
        adbDevice->writeRegister(1, (UInt8 *)&value, &length);
        setProperty(kIOHIDFKeyModeKey, mode, sizeof(UInt32));
    }
}



// --------------------------------------------------------------------------
//
// Method: getFKeyMode
//
// Purpose:  get PowerBook function keys mode.  Also set up instance variable
// to keep track of whether this device has dual mode Function Keys or not.
SInt8
AppleADBKeyboard::getFKeyMode(void)
{
    UInt8       	adbdata[8], isFnPrimary = 0;
    IOByteCount		length = 8;
    OSDictionary 	* FKeyModeParamDict;
    SInt32		dictData = -1;
    OSNumber 		* datan;

    if (!adbDevice)
	return -1;	// -1 means feature unsupported
    
    FKeyModeParamDict = OSDictionary::withCapacity(4);
    bzero(adbdata, 8);
    adbDevice->readRegister(1, adbdata, &length);
    // [1] contains F key mode and [0] contains world region (ANSI, JIS, ISO)
    _hasDualModeFunctionKeys = false;
    if (adbdata[0])	//is 0 for external keyboards.  
    {
	_hasDualModeFunctionKeys = true;
	if (adbdata[1] & 0x0001)
	    isFnPrimary = 1;
	setProperty(kIOHIDFKeyModeKey, isFnPrimary, sizeof(UInt32));
	dictData = isFnPrimary;
    }
    datan = OSNumber::withNumber((unsigned long long) dictData, 32 ); // 0, 1, or -1
    if( datan) {
	FKeyModeParamDict->setObject( kIOHIDFKeyModeKey, datan);
	datan->release();
    }
    if (_keyboardEventTarget)
    {
	((IOHIDSystem *)_keyboardEventTarget)->setParamProperties(FKeyModeParamDict); 
	//Merge new property with HIDSystem properties
    }
    FKeyModeParamDict->release();
    
    if (_hasDualModeFunctionKeys)
	return isFnPrimary;
    else
	return -1;	// -1 means feature unsupported
    
}


// --------------------------------------------------------------------------
//
// Method: updateFKeyMap
//
// Purpose:  Update the Fkey map in PMU with the values from the name
//   	     registry, if needed.  This came from the UpdateFKeyMap routine
//	     in OS9 Excelsior:OS:Wallyworld sources.       
/* static */ void
AppleADBKeyboard::updateFKeyMap()
{
    IORegistryEntry		*devicetreeRegEntry;
    typedef char  	keystrtype[4];
    unsigned long 	buttonkeyvalue; 	// button translation value from name registry
    unsigned char	fkeyindex;		// f key number being checked
    keystrtype mapentry[] = 
					{
					{"F0"},  {"F1"},  {"F2"},  {"F3"},  {"F4"},  {"F5"},  {"F6"},
							{"F7"},  {"F8"},  {"F9"},  {"F10"},  {"F11"},  {"F12"}, 
					};
    devicetreeRegEntry = fromPath("mac-io/via-pmu/adb/keyboard", gIODTPlane);
    if(devicetreeRegEntry != NULL)  {
	if (OSDynamicCast(OSData, devicetreeRegEntry->getProperty("AAPL,has-embedded-fn-keys"))) {
            for (fkeyindex = 1; fkeyindex <= 12;  fkeyindex++)
                {
		OSData *tmpData = OSDynamicCast(OSData, devicetreeRegEntry->getProperty(mapentry[fkeyindex]));
		if(tmpData != NULL) {
			memcpy(&buttonkeyvalue, (UInt8 *)tmpData->getBytesNoCopy(), sizeof(buttonkeyvalue));
			setButtonTransTableEntry(fkeyindex, buttonkeyvalue);
			}
		}
            }	    
	    devicetreeRegEntry->release();  //3172112
	}
}

// ******************************************************************************************************
// Method:  setButtonTransTableEntry
//
// Purpose:	Used for local write to PMU adb interface (to set up PMU registers).
//		This is essentially a writeToDevice routine (as in ADB device).
//		The command string typically looks like (on the ApplePMU driver
//		sendMiscCommand side) as an example: 
//		ADBcmd ADBcnt IntKbdCmd AutoPollbit ADBcount PMUcount selector  F12key keyvalue
//		  20      07      28        02         04      03       01        0c      8b
// ******************************************************************************************************
/* static */ void
AppleADBKeyboard::setButtonTransTableEntry(unsigned char fkeynum, unsigned char transvalue)
{
    if (!adbDevice)
	return;
						// CMD: int KBD 2 reg 0 listen filled in by IOPMUADBController
    UInt8 oBuffer[3];				// embed. data count =3 to PMU filled in by IOPMUADBController
    oBuffer[0] = 1;				// selector for PMU: set fkey command
    oBuffer[1] = fkeynum;			// fkey to set
    oBuffer[2] = transvalue;			// button code to attach
    IOByteCount oLength = sizeof(oBuffer);
    adbDevice->writeRegister(0, oBuffer, &oLength);   // adbRegister = 0, IOADBDevice adds addr of 0x02 => 0x28
}	

// **********************************************************************************
// interfaceID
//
// **********************************************************************************
UInt32 AppleADBKeyboard::interfaceID ( void )
{
return NX_EVS_DEVICE_INTERFACE_ADB;
}


// **********************************************************************************
// deviceType
//
// **********************************************************************************
UInt32 AppleADBKeyboard::deviceType ( void )
{
    UInt32	id;	//We need handler ID to remap adjustable JIS keyboard
    IORegistryEntry 	*regEntry;
    OSData 		*data = 0;
    UInt32 		*dataptr;
    OSNumber 		*xml_handlerID;

    if (!adbDevice)
	return 2;

    xml_handlerID = OSDynamicCast( OSNumber, getProperty("alt_handler_id"));
    if (xml_handlerID)
    {
	id = xml_handlerID->unsigned32BitValue();
    }
    else
    {
	id = adbDevice->handlerID();
    }

    if (id == 18)  //Adjustable JIS
    {
	_virtualmap[0x32] = 0x35; //tilde to ESC
	_fnvirtualmap[0x32] = 0x35;
    }

    if ((id == 2) || (id == 3))  //External ADB keyboards may retain ID = 3 between boots
    {
	adbDevice->setHandlerID(3);
	id = 2;  // Gestalt.h has no idea what type 3 is since historically it was never used
    }
    else
    if (id == 5)  //ISO extended keyboard
    {
	adbDevice->setHandlerID(3);
	id = 5;  
    }
    
    if ((id == kgestaltPwrBkEKDomKbd) || (id == kgestaltPwrBkEKISOKbd) || 
	(id == kgestaltPwrBkEKJISKbd) || (id == kgestaltPwrBk99JISKbd))
    {	
	if( (regEntry = IORegistryEntry::fromPath( "/pci@f2000000/mac-io/via-pmu/adb/keyboard", gIODTPlane ))) 
	{
	    data = OSDynamicCast(OSData, regEntry->getProperty( "keyboard-id", gIODTPlane, kIORegistryIterateRecursively ));
	    if (data)
	    {
		dataptr = (UInt32 *)data->getBytesNoCopy();
		id = *dataptr; //make sure no byte swapping
	    }
	    regEntry->release();
	}
    }    

    return id;
}


// **********************************************************************************
// setAlphaLockFeedback
// This is usually called on a call-out thread after the caps-lock key is pressed.
// ADB operations to PMU are synchronous, and this is must not be done
// on the call-out thread since that is the PMU driver workloop thread, and
// it will block itself.
//
// Therefore, we schedule the ADB write to disconnect the call-out thread
// and the one that initiates the ADB write.
//
// **********************************************************************************
void AppleADBKeyboard::setAlphaLockFeedback ( bool to )
{    
    if (to)
	turnLEDon &= ~ADBKS_LED_CAPSLOCK; //Inverse logic applies here
    else
	turnLEDon |= ADBKS_LED_CAPSLOCK;

    if ( ! isInactive() ) {
	thread_call_func(asyncSetLEDFunc, (thread_call_param_t)this, true);
    }
}

void AppleADBKeyboard::setNumLockFeedback ( bool to )
{
     if (to) //LED on means clear that bit
	turnLEDon &= ~ ADBKS_LED_NUMLOCK; 
    else
	turnLEDon |= ADBKS_LED_NUMLOCK;

    if ( ! isInactive() ) {
	thread_call_func(asyncSetLEDFunc, (thread_call_param_t)this, true);
    }

}



// **********************************************************************************
// asyncSetLEDFunc
//
// Called asynchronously to turn on/off the capslock and numlock LED
//
// **********************************************************************************
static void asyncSetLEDFunc ( thread_call_param_t self, thread_call_param_t )
{
    
UInt16		value;
IOByteCount	length = sizeof( UInt16);

    if (!((AppleADBKeyboard*)self)->adbDevice)
	return;

    value = ((AppleADBKeyboard*)self)->turnLEDon;
    ((AppleADBKeyboard*)self)->adbDevice->writeRegister(2, (UInt8 *)&value, &length);
}

/**********************************************************************
Get LED status by reading hardware.  Register 2 has 16 bits.
Note that early ADB keyboards don't support this much data in 
register 2, so it will come back all zeros and that is interpreted
as every LED being turned on.
**********************************************************************/
unsigned AppleADBKeyboard::getLEDStatus (void )
{  
    UInt8       data[8];  //8 bytes max for ADB read (talk) operation
    IOByteCount length = 8;

    if (!adbDevice)
	return 0;

    bzero(data, 8);
    LEDStatus = 0;
    adbDevice->readRegister(2, data, &length);

    if ((data[1] & ADBKS_LED_NUMLOCK) == 0)
	LEDStatus |= ADBKS_LED_NUMLOCK;
    if ((data[1] & ADBKS_LED_CAPSLOCK) == 0)
	LEDStatus |= ADBKS_LED_CAPSLOCK;
    if ((data[1] & ADBKS_LED_SCROLLLOCK) == 0)
	LEDStatus |= ADBKS_LED_SCROLLLOCK;

    return LEDStatus;
}

// **********************************************************************************
// new_kbd_data
//
// **********************************************************************************
static void new_kbd_data ( IOService * us, UInt8 adbCommand, IOByteCount length, UInt8 * data )
{
((AppleADBKeyboard *)us)->packet(data,length,adbCommand);
}

// **********************************************************************************
// dispatchKeyboardEvent
//
// **********************************************************************************
extern "C" {
void Debugger( const char * );
void boot(int paniced, int howto, char * command);
#define RB_HALT		0x08	/* don't reboot, just halt */
}

static void AppleADBKeyboardReboot( thread_call_param_t arg, thread_call_param_t )
{
    boot( 0, (int) arg, 0 );
}

void AppleADBKeyboard::dispatchKeyboardEvent(unsigned int	keyCode,
                            /* direction */ bool         	goingDown,
                            /* timeStamp */ AbsoluteTime	time)
{
    char * pvirtualmap;
 

    pvirtualmap = _virtualmap;
    if ((_stickymodeON) && (_sticky_fn_ON))
    {
	pvirtualmap = _fnvirtualmap;
    }

    if( !goingDown && programmerKey) {
	programmerKey = false;
	EVK_KEYUP( ADBK_CONTROL, _keyState);
	SUB_ABSOLUTETIME( &time, &programmerKeyTime );
        if( CMP_ABSOLUTETIME( &time, &rebootTime) >= 0) {
            
	    thread_call_func( AppleADBKeyboardReboot,
				(void *) RB_HALT, true );
	} else if( CMP_ABSOLUTETIME( &time, &debuggerTime) >= 0) {
	    Debugger("Programmer Key");
	}

    } 
    else if (keyCode == ADBK_POWER)
    {
	if (EVK_IS_KEYDOWN( ADBK_CONTROL, _keyState)) {

	    if( !programmerKey) {
		programmerKey = true;
		programmerKeyTime = time;
	    }
	    return;
	}
	else if (deviceFlags() & NX_SECONDARYFNMASK)
	{ 
	    //On PowerBooks fn + CMD creates a POWER keycode, so change it now to CMD code
	    keyCode = ADBK_FLOWER;
	    //If fn is released before CMD key, we need to fake another CMD key later,
	    //  but if CMD key is released first then we don't need to do anything else
	    //  later since the CMD key will still generate a POWER key-up when fn is down.
	    _fn_key_invoked_power = goingDown;
	}
	else if (_fn_key_invoked_power)
	{
	    //If fn key is released before CMD key, then when CMD key is released
	    //  the keycode is still 7f (POWER).  But that makes CMD key look like
	    //  it is stuck in the down position from line above, so fake CMD up now
	    keyCode = ADBK_FLOWER;
	    _fn_key_invoked_power = false;
	}
    }

    if ((_enable_fwd_delete) && (deviceFlags() & NX_SECONDARYFNMASK))
    {
	if (keyCode == ADBK_DELETE)
	{
	    keyCode = ADBK_FORWARD_DELETE;
	    _fwd_delete_down = goingDown;
	}
	else if (keyCode == ADBK_PBFNKEY)
	{
	    if ((!goingDown) && (_fwd_delete_down))
	    {
		super::dispatchKeyboardEvent( pvirtualmap[ADBK_FORWARD_DELETE], 
		    false, time );
		_fwd_delete_down = false;
	    }
	}
    
    }

    super::dispatchKeyboardEvent( pvirtualmap[keyCode], goingDown, time );
}

// **********************************************************************************
// packet
//
// **********************************************************************************
IOReturn AppleADBKeyboard::packet (UInt8 * data, IOByteCount, UInt8 adbCommand )
{
unsigned int	keycode1, keycode2;
bool		down;
AbsoluteTime	now;

keycode1 = *data;
down = ((keycode1 & 0x80) == 0);
keycode1 &= 0x7f;
if(keycode1 == 0x7e) keycode1 = ADBK_POWER;
clock_get_uptime(&now);
setTimeLastNonmodKeydown(now, keycode1);
dispatchKeyboardEvent(keycode1,down,now);

keycode2 = *(data + 1);
if( keycode2 != 0xff ) {
        down = ((keycode2 & 0x80) == 0);
        keycode2 &= 0x7f;
        if( keycode2 == 0x7e) keycode2 = ADBK_POWER;
	if( (keycode1 != ADBK_POWER) || (keycode2 != ADBK_POWER))
		dispatchKeyboardEvent(keycode2,down,now);
}

return kIOReturnSuccess;
}

//This is needed by trackpads to correct jitter when gestures
//  are enabled.
void AppleADBKeyboard::setTimeLastNonmodKeydown (AbsoluteTime now, unsigned int keycode)
{
    switch (_virtualmap[keycode]) {
	case  0x3b:	//left control, not raw
	case  ADBK_FLOWER:	
	case  ADBK_SHIFT:	
	case  ADBK_SHIFT_R:    
	case  ADBK_CAPSLOCK:	
	case  ADBK_OPTION:	
	case  ADBK_OPTION_R:
	case  ADBK_PBFNKEY:	//PowerBook secondary fn key
	    break;
	default:
	    _lastkeydown = now;
	    break;
    }
}

AbsoluteTime AppleADBKeyboard::getTimeLastNonmodKeydown (void)
{
    if (CMP_ABSOLUTETIME( &_lastkeyCGEvent, &_lastkeydown) > 0)
     	return _lastkeyCGEvent;  //time of autorepeat
    else
	return _lastkeydown;     //time of physical keypress
}

//The only reason this method is subclassed is to access autorepeat
//  events without changing IOHIKeyboard's public APIs.  All normal
//  as well as autorepeated keys must come through here
void AppleADBKeyboard::keyboardEvent(unsigned eventType,
	/* flags */              unsigned flags,
	/* keyCode */            unsigned keyCode,
	/* charCode */           unsigned charCode,
	/* charSet */            unsigned charSet,
	/* originalCharCode */   unsigned origCharCode,
	/* originalCharSet */    unsigned origCharSet)
{

    //only save time if autorepeated key
    //save my own time, ignore super's time.  
    switch ( _codeToRepeat)
    {
	case  ADBK_F9:
	case  ADBK_F10:
	case  ADBK_F11:
	case  ADBK_F12:
	case  (unsigned) -1:
	    break;
	default:
	    clock_get_uptime(&_lastkeyCGEvent);  
	    break;
    }
	
    super::keyboardEvent( eventType, flags, keyCode, charCode, charSet,
	origCharCode, origCharSet);
}

IOReturn AppleADBKeyboard::callPlatformFunction(const OSSymbol *functionName,
						    bool waitForFunction,
						    void *param1, void *param2,
						    void *param3, void *param4)
{  
    if (functionName == _get_last_keydown)
    {
	AbsoluteTime *timeptr;
	
	timeptr = (AbsoluteTime *)param1;
	*timeptr = getTimeLastNonmodKeydown();
	return kIOReturnSuccess;
    }
    
    if (functionName == _get_handler_id)
    {
	UInt32	*id;
	
	id = (UInt32 *)param1;
	*id = deviceType();
	return kIOReturnSuccess;
    }

    if (functionName == _get_device_flags)
    {
	UInt32	*id;
	
	id = (UInt32 *)param1;
	//TBD:  check if keyboard is external or embedded?
	*id = deviceFlags();
	return kIOReturnSuccess;
    }
    
    
    return kIOReturnBadArgument;
}


// **********************************************************************************
// maxKeyCodes
//
// **********************************************************************************
UInt32 AppleADBKeyboard::maxKeyCodes ( void )
{
return 0x80;
}

//Get key values from ev_keymap.h
bool AppleADBKeyboard:: doesKeyLock ( unsigned key)
{
    switch (key) {
	case NX_KEYTYPE_CAPS_LOCK:
		return true;
	case NX_KEYTYPE_NUM_LOCK:
		return false;
	default:
		return false;
    }
}

// **********************************************************************************
//  setParamProperties
//  
// **********************************************************************************
IOReturn AppleADBKeyboard::setParamProperties( OSDictionary * dict )
{
    OSNumber 	*datan;

    if (_keybrdLock)
	IOLockLock (_keybrdLock);
    
    if (datan = OSDynamicCast(OSNumber, dict->getObject(kIOHIDFKeyModeKey)))
    {
	bool	theFkeyMode;
	
	theFkeyMode = (bool) datan->unsigned32BitValue();
	setFKeyMode(theFkeyMode); //This calls setProperty too
    }
    
    if (datan = OSDynamicCast(OSNumber, dict->getObject(kIOHIDStickyKeysOnKey)))
    {
	UInt32	propertydata;
	
        propertydata = (bool) datan->unsigned32BitValue();;
		
	if (propertydata) 
	{
	    _stickymodeON = true;
	}
	else
	{
	    _stickymodeON = false;
	}
    }

    if (_oneshotCAPSLOCK && adbDevice) //If caps lock LED was set in prior session
    {
	AbsoluteTime	locktime;
	UInt32		id;

	_oneshotCAPSLOCK = false;  // only set to true by start()
	
	//check handler ID since keyboards of type 1 fail register 2 check
	id = adbDevice->handlerID();
	if (id > 0xc0) //Anything beyond 0xc0 is WallStreet or higher, and USB and BT
	{
	    clock_get_uptime(&locktime);
	    super::dispatchKeyboardEvent(ADBK_CAPSLOCK, true, locktime);
	}

    }
        
    if (_keybrdLock)
	IOLockUnlock (_keybrdLock);

    return super::setParamProperties(dict);
}

// **********************************************************************************
//  keyboardSpecialEvent
//  Used only to capture sticky PowerBook fn key from IOHIDSystem (in IOHIDFamily)
// **********************************************************************************
void AppleADBKeyboard::keyboardSpecialEvent( unsigned eventType, unsigned flags, 
	unsigned keyCode, unsigned flavor)
{
    if ((_stickymodeON) && (eventType == NX_SYSDEFINED) && (keyCode == NX_NOSPECIALKEY))
    {
	if (flavor == NX_SUBTYPE_STICKYKEYS_FN_UP)
	{
	    _sticky_fn_ON = false;
	}
	if ((flavor == NX_SUBTYPE_STICKYKEYS_FN_LOCK) || 
	    (flavor == NX_SUBTYPE_STICKYKEYS_FN_DOWN))
	{
	    _sticky_fn_ON = true;
	}
    }
    return super::keyboardSpecialEvent(eventType, flags, keyCode, flavor);
}

// **********************************************************************************
// defaultKeymapOfLength
//
// **********************************************************************************
const unsigned char * AppleADBKeyboard::defaultKeymapOfLength (UInt32 * length )
{
static const unsigned char appleUSAKeyMap[] = {
            0x00,0x00,
	    0x0b,	//11 modifier keys
	    0x00,0x01,0x39,  //NX_MODIFIERKEY_ALPHALOCK
	    0x01,0x01,0x38,  //NX_MODIFIERKEY_SHIFT virtual from KMAP
	    0x02,0x01,0x3b,  //NX_MODIFIERKEY_CONTROL
	    0x03,0x01,0x3a,  //NX_MODIFIERKEY_ALTERNATE
	    0x04,0x01,0x37,	  //NX_MODIFIERKEY_COMMAND
	    0x05,0x11,0x52,0x41,0x4c,0x53,0x54,0x55,0x45,0x58,0x57,0x56,0x5b,0x5c,
            0x43,0x4b,0x51,0x4e,0x59,  //NX_MODIFIERKEY_NUMERICPAD no longer includes arrows
	    0x06,0x01,0x72, //NX_MODIFIERKEY_HELP  7th modifier here
	    0x07,0x01,0x3f, //NX_MODIFIERKEY_SECONDARYFN 8th modifier
	    0x09,0x01,0x3c, // NX_MODIFIERKEY_RSHIFT
	    0x0a,0x01,0x3e, // NX_MODIFIERKEY_RCONTROL
	    0x0b,0x01,0x3d, // NX_MODIFIERKEY_RALTERNATE
	    //0x0c,0x01,0x36, // 36 (for NX_MODIFIERKEY_RCOMMAND) not possible with Apple ADB Extended Keyboard 
	    0x7f,0x0d,0x00,0x61,
            0x00,0x41,0x00,0x01,0x00,0x01,0x00,0xca,0x00,0xc7,0x00,0x01,0x00,0x01,0x0d,0x00,
            0x73,0x00,0x53,0x00,0x13,0x00,0x13,0x00,0xfb,0x00,0xa7,0x00,0x13,0x00,0x13,0x0d,
            0x00,0x64,0x00,0x44,0x00,0x04,0x00,0x04,0x01,0x44,0x01,0xb6,0x00,0x04,0x00,0x04,
            0x0d,0x00,0x66,0x00,0x46,0x00,0x06,0x00,0x06,0x00,0xa6,0x01,0xac,0x00,0x06,0x00,
            0x06,0x0d,0x00,0x68,0x00,0x48,0x00,0x08,0x00,0x08,0x00,0xe3,0x00,0xeb,0x00,0x00,
            0x18,0x00,0x0d,0x00,0x67,0x00,0x47,0x00,0x07,0x00,0x07,0x00,0xf1,0x00,0xe1,0x00,
            0x07,0x00,0x07,0x0d,0x00,0x7a,0x00,0x5a,0x00,0x1a,0x00,0x1a,0x00,0xcf,0x01,0x57,
            0x00,0x1a,0x00,0x1a,0x0d,0x00,0x78,0x00,0x58,0x00,0x18,0x00,0x18,0x01,0xb4,0x01,
            0xce,0x00,0x18,0x00,0x18,0x0d,0x00,0x63,0x00,0x43,0x00,0x03,0x00,0x03,0x01,0xe3,
            0x01,0xd3,0x00,0x03,0x00,0x03,0x0d,0x00,0x76,0x00,0x56,0x00,0x16,0x00,0x16,0x01,
            0xd6,0x01,0xe0,0x00,0x16,0x00,0x16,0x02,0x00,0x3c,0x00,0x3e,0x0d,0x00,0x62,0x00,
            0x42,0x00,0x02,0x00,0x02,0x01,0xe5,0x01,0xf2,0x00,0x02,0x00,0x02,0x0d,0x00,0x71,
            0x00,0x51,0x00,0x11,0x00,0x11,0x00,0xfa,0x00,0xea,0x00,0x11,0x00,0x11,0x0d,0x00,
            0x77,0x00,0x57,0x00,0x17,0x00,0x17,0x01,0xc8,0x01,0xc7,0x00,0x17,0x00,0x17,0x0d,
            0x00,0x65,0x00,0x45,0x00,0x05,0x00,0x05,0x00,0xc2,0x00,0xc5,0x00,0x05,0x00,0x05,
            0x0d,0x00,0x72,0x00,0x52,0x00,0x12,0x00,0x12,0x01,0xe2,0x01,0xd2,0x00,0x12,0x00,
            0x12,0x0d,0x00,0x79,0x00,0x59,0x00,0x19,0x00,0x19,0x00,0xa5,0x01,0xdb,0x00,0x19,
            0x00,0x19,0x0d,0x00,0x74,0x00,0x54,0x00,0x14,0x00,0x14,0x01,0xe4,0x01,0xd4,0x00,
            0x14,0x00,0x14,0x0a,0x00,0x31,0x00,0x21,0x01,0xad,0x00,0xa1,0x0e,0x00,0x32,0x00,
            0x40,0x00,0x32,0x00,0x00,0x00,0xb2,0x00,0xb3,0x00,0x00,0x00,0x00,0x0a,0x00,0x33,
            0x00,0x23,0x00,0xa3,0x01,0xba,0x0a,0x00,0x34,0x00,0x24,0x00,0xa2,0x00,0xa8,0x0e,
            0x00,0x36,0x00,0x5e,0x00,0x36,0x00,0x1e,0x00,0xb6,0x00,0xc3,0x00,0x1e,0x00,0x1e,
            0x0a,0x00,0x35,0x00,0x25,0x01,0xa5,0x00,0xbd,0x0a,0x00,0x3d,0x00,0x2b,0x01,0xb9,
            0x01,0xb1,0x0a,0x00,0x39,0x00,0x28,0x00,0xac,0x00,0xab,0x0a,0x00,0x37,0x00,0x26,
            0x01,0xb0,0x01,0xab,0x0e,0x00,0x2d,0x00,0x5f,0x00,0x1f,0x00,0x1f,0x00,0xb1,0x00,
            0xd0,0x00,0x1f,0x00,0x1f,0x0a,0x00,0x38,0x00,0x2a,0x00,0xb7,0x00,0xb4,0x0a,0x00,
            0x30,0x00,0x29,0x00,0xad,0x00,0xbb,0x0e,0x00,0x5d,0x00,0x7d,0x00,0x1d,0x00,0x1d,
            0x00,0x27,0x00,0xba,0x00,0x1d,0x00,0x1d,0x0d,0x00,0x6f,0x00,0x4f,0x00,0x0f,0x00,
            0x0f,0x00,0xf9,0x00,0xe9,0x00,0x0f,0x00,0x0f,0x0d,0x00,0x75,0x00,0x55,0x00,0x15,
            0x00,0x15,0x00,0xc8,0x00,0xcd,0x00,0x15,0x00,0x15,0x0e,0x00,0x5b,0x00,0x7b,0x00,
            0x1b,0x00,0x1b,0x00,0x60,0x00,0xaa,0x00,0x1b,0x00,0x1b,0x0d,0x00,0x69,0x00,0x49,
            0x00,0x09,0x00,0x09,0x00,0xc1,0x00,0xf5,0x00,0x09,0x00,0x09,0x0d,0x00,0x70,0x00,
            0x50,0x00,0x10,0x00,0x10,0x01,0x70,0x01,0x50,0x00,0x10,0x00,0x10,0x10,0x00,0x0d,
            0x00,0x03,0x0d,0x00,0x6c,0x00,0x4c,0x00,0x0c,0x00,0x0c,0x00,0xf8,0x00,0xe8,0x00,
            0x0c,0x00,0x0c,0x0d,0x00,0x6a,0x00,0x4a,0x00,0x0a,0x00,0x0a,0x00,0xc6,0x00,0xae,
            0x00,0x0a,0x00,0x0a,0x0a,0x00,0x27,0x00,0x22,0x00,0xa9,0x01,0xae,0x0d,0x00,0x6b,
            0x00,0x4b,0x00,0x0b,0x00,0x0b,0x00,0xce,0x00,0xaf,0x00,0x0b,0x00,0x0b,0x0a,0x00,
            0x3b,0x00,0x3a,0x01,0xb2,0x01,0xa2,0x0e,0x00,0x5c,0x00,0x7c,0x00,0x1c,0x00,0x1c,
            0x00,0xe3,0x00,0xeb,0x00,0x1c,0x00,0x1c,0x0a,0x00,0x2c,0x00,0x3c,0x00,0xcb,0x01,
            0xa3,0x0a,0x00,0x2f,0x00,0x3f,0x01,0xb8,0x00,0xbf,0x0d,0x00,0x6e,0x00,0x4e,0x00,
            0x0e,0x00,0x0e,0x00,0xc4,0x01,0xaf,0x00,0x0e,0x00,0x0e,0x0d,0x00,0x6d,0x00,0x4d,
            0x00,0x0d,0x00,0x0d,0x01,0x6d,0x01,0xd8,0x00,0x0d,0x00,0x0d,0x0a,0x00,0x2e,0x00,
            0x3e,0x00,0xbc,0x01,0xb3,0x02,0x00,0x09,0x00,0x19,0x0c,0x00,0x20,0x00,0x00,0x00,
            0x80,0x00,0x00,0x0a,0x00,0x60,0x00,0x7e,0x00,0x60,0x01,0xbb,0x02,0x00,0x7f,0x00,
            0x08,0xff,0x02,0x00,0x1b,0x00,0x7e,0xff,0xff,0xff,0xff,0xff,
	    /*
	    0x00,0x01,0xac,0x00,
            0x01,0xae,0x00,0x01,0xaf,0x00,0x01,0xad,
	    */
	    0xff, 0xff, 0xff, 0xff,
	    0xff,0xff,0x00,0x00,0x2e,0xff,0x00,0x00,
            0x2a,0xff,0x00,0x00,0x2b,0xff,0x00,0x00,0x1b,0xff,0xff,0xff,0x0e,0x00,0x2f,0x00,
            0x5c,0x00,0x2f,0x00,0x1c,0x00,0x2f,0x00,0x5c,0x00,0x00,0x0a,0x00,0x00,0x00,0x0d, //XX03
            0xff,0x00,0x00,0x2d,0xff,0xff,0x0e,0x00,0x3d,0x00,0x7c,0x00,0x3d,0x00,0x1c,0x00,
            0x3d,0x00,0x7c,0x00,0x00,0x18,0x46,0x00,0x00,0x30,0x00,0x00,0x31,0x00,0x00,0x32,
            0x00,0x00,0x33,0x00,0x00,0x34,0x00,0x00,0x35,0x00,0x00,0x36,0x00,0x00,0x37,0xff,
            0x00,0x00,0x38,0x00,0x00,0x39,0xff,0xff,0xff,0x00,0xfe,0x24,0x00,0xfe,0x25,0x00,
            0xfe,0x26,0x00,0xfe,0x22,0x00,0xfe,0x27,0x00,0xfe,0x28,0xff,0x00,0xfe,0x2a,0xff,
            0x00,0xfe,0x32,0xff,0x00,0xfe,0x33,0xff,0x00,0xfe,0x29,0xff,0x00,0xfe,0x2b,0xff,
            0x00,0xfe,0x34,0xff,0x00,0xfe,0x2e,0x00,0xfe,0x30,0x00,0xfe,0x2d,0x00,0xfe,0x23,
            0x00,0xfe,0x2f,0x00,0xfe,0x21,0x00,0xfe,0x31,0x00,0xfe,0x20,
	    //A.W.  Added following 4 lines to fix wakeup on PowerBooks. 
	    0x00,0x01,0xac, //ADB=0x7b is left arrow
	    0x00,0x01,0xae, //ADB = 0x7c is right arrow
	    0x00,0x01,0xaf, //ADB=0x7d is down arrow. 
	    0x00,0x01,0xad, //ADB=0x7e is up arrow	
	    0x0f,0x02,0xff,0x04,
            0x00,0x31,0x02,0xff,0x04,0x00,0x32,0x02,0xff,0x04,0x00,0x33,0x02,0xff,0x04,0x00,
            0x34,0x02,0xff,0x04,0x00,0x35,0x02,0xff,0x04,0x00,0x36,0x02,0xff,0x04,0x00,0x37,
            0x02,0xff,0x04,0x00,0x38,0x02,0xff,0x04,0x00,0x39,0x02,0xff,0x04,0x00,0x30,0x02,
            0xff,0x04,0x00,0x2d,0x02,0xff,0x04,0x00,0x3d,0x02,0xff,0x04,0x00,0x70,0x02,0xff,
            0x04,0x00,0x5d,0x02,0xff,0x04,0x00,0x5b,
0x06, // following are 6 special keys
0x05,0x72,  //NX_KEYTYPE_HELP is 5, ADB code is 0x72
0x06,0x7f,  //NX_POWER_KEY is 6, ADB code is 0x7f
0x07,0x4a,  //NX_KEYTYPE_MUTE is 7, ADB code is 0x4a
0x08,0x3e,  //NX_UP_ARROW_KEY is 8, ADB is 3e raw, 7e virtual (KMAP)
0x09,0x3d,   //NX_DOWN_ARROW_KEY is 9, ADB is 0x3d raw, 7d virtual
0x0a,0x47   //NX_KEYTYPE_NUM_LOCK is 10, ADB combines with CLEAR key for numlock
    };

*length = sizeof(appleUSAKeyMap);
return appleUSAKeyMap;
}