Source to iokit/Drivers/usb/drvAppleKeyboard/AppleKeyboard.cpp
/*
* Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.1 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This 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 OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* Copyright (c) 1998, 1999 Apple Computer, Inc. All rights reserved.
*
* HISTORY
*
*/
#include <libkern/OSByteOrder.h>
#include "AppleKeyboard.h"
#include <IOKit/hidsystem/IOHIPointing.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/usb/IOUSBInterface.h>
#include <IOKit/usb/IOUSBPipe.h>
#include <IOKit/usb/IOUSBController.h>
extern "C" {
#include <pexpert/pexpert.h>
}
#define super IOHIKeyboard
#define self this
#define DEBUGGING_LEVEL 0
OSDefineMetaClassAndStructors(AppleKeyboard, IOHIKeyboard)
extern unsigned char usb_2_adb_keymap[]; //In Cosmo_USB2ADB.cpp
static IOUSBController *sPollControl;
static IOUSBPipe *sPollPipe;
static UInt8 sBuffer[8];
static IOMemoryDescriptor *sBufDesc;
static bool sComplete = true;
static void bodgeComplete(void *target, void * parameter, IOReturn status, UInt32 bufferSizeRemaining)
{
sComplete = true;
}
static int PE_usb_poll_input(unsigned int options, char * c)
{
static char adbkeycodes2ascii[] = "asdfhgzxcv_bqwer"//00
"yt123465=97-80]o" //10
"u[ip\nlj'k;_,/nm." //20
"\t_"; //30
*c = 0xff;
if(!sPollPipe)
return 0;
if(sComplete) {
IOUSBCompletion completion;
sComplete = false;
*c = adbkeycodes2ascii[usb_2_adb_keymap[sBuffer[2]]];
completion.target = 0;
completion.action = bodgeComplete;
completion.parameter = 0;
sPollControl->PolledRead(
sPollPipe->address() /*functionAddress*/,
sPollPipe->endpoint()->number /*endpointNumber*/,
completion /*completion*/,
sBufDesc /*buffer*/,
true /*bufferRounding*/,
sizeof(sBuffer) /*bufferSize*/);
}
else
sPollControl->pollInterrupts(bodgeComplete); // Only complete our transactions
return 0;
}
void usb_asyncLED ( AppleKeyboard * me );
AppleKeyboard *glob_usbkeyboard_obj;
bool AppleKeyboard::start(IOService * provider)
{
IOReturn err = 0;
if( !super::start(provider))
return (false);
// remember my device
_interface = OSDynamicCast(IOUSBInterface, provider);
_deviceDescriptor = _interface->deviceDescriptor();
_prevent_LED_set = FALSE;
//Following 3 lines moved here from Simulate_ADB_Event to make multiple
// keyboards work correctly. The instance variables cannot be shared
// between each instance of this driver for each USB keyboard.
prev_bytes_read=8;
oldmodifier = 0xff;
bzero( old_array, kUSB_LOWSPEED_MAXPACKET);
if (_interface->open(self) == false) return false;
//Fix hardware bug in iMac USB keyboard mapping for ISO keyboards
//kprintf("\nUSB product = %x, vendor = %x\n", _deviceDescriptor->product, _deviceDescriptor->vendor);
if ( _deviceDescriptor) //just to be safe
{
if (_deviceDescriptor->vendor == 0xac05) //Apple Corp. vendor ID, not byte swapped
{
switch (_deviceDescriptor->product)
{
case 0x0201: //North American iMac keyboard
break; // return 18
case 0x0203: //38=Japanese. 34 is adjustable JIS
break; // return 34;
case 0x0202: //Arabic, other ISO such as German
//Swap two ISO keys around
usb_2_adb_keymap[0x35] = 0x0a; //Cosmo key18 swaps with key74, 0a is ADB keycode
usb_2_adb_keymap[0x64] = 0x32;
break;
// return 21; //21 is Apple ISO Extended Keyboard
default:
//return 18;
break;
}
}
if (_deviceDescriptor->vendor == 0x5e04) //Microsoft ID
{
//Figure out what to do with Microsoft keyboard later
//if (usb_kbd_product_id == 0x000b) //Natural USB+PS/2 keyboard
//return 18;
}
}
do {
IOLog("%s: USB Generic Keyboard @ %d\n", getName(), _interface->address());
#if 0
kprintf("Adam: Class is %d\n", req.theClass); //3 HID
kprintf("Adam: SubClass is %d\n", req.subClass); //1
kprintf("Adam: Protocol is %d\n", req.protocol); //1 keyboard
kprintf("Adam: Type is %d\n", (_interface->endpoints[0])->transferType); //I get 1
kprintf("Adam: Number is %d\n", (_interface->endpoints[0])->number); // I get 1
#endif
//setAlphaLockFeedback(false); //Disable caps lock LED at first
IOUSBFindEndpointRequest request;
request.type = kUSBInterrupt;
request.direction = kUSBIn;
_interruptPipe = _interface->findNextPipe(NULL, &request);
if(!_interruptPipe)
return false;
_maxPacketSize = request.maxPacketSize;
_buffer = IOBufferMemoryDescriptor::withCapacity(8, kIODirectionIn);
_completion.target = (void *)self;
_completion.action = (IOUSBCompletionAction) &AppleKeyboard::readHandler;
_completion.parameter = (void *)0; // not used
_buffer->setLength(_maxPacketSize); // shouldn't this be _maxPacketSize?
if ((err = _interruptPipe->read(_buffer, &_completion)))
break;
#if (DEBUGGING_LEVEL > 0)
//printInterfaceDescriptor(_interface->descriptor);
#endif
// Save stuff for polled mode
sPollControl = _interface->bus();
sPollPipe = _interruptPipe;
sBufDesc = IOMemoryDescriptor::withAddress(sBuffer, 8, kIODirectionIn);
PE_poll_input = PE_usb_poll_input;
return(true);
} while (false);
IOLog("%s: aborting startup. err = %d\n", getName(), err);
provider->close(this);
stop(provider);
return(false);
}
void AppleKeyboard::stop(IOService * provider)
{
if (_buffer) {
_buffer->release();
_buffer = 0;
}
if(sPollPipe == _interruptPipe) {
sPollControl = NULL;
sPollPipe = NULL;
sBufDesc->release();
sBufDesc = NULL;
}
super::stop(provider);
}
void AppleKeyboard::test_myusb_f1(void)
{
/*
char dummy[8];
IOReturn err = kIOReturnSuccess;
OSData *writebuf;
IOUSBPipe * tinterruptPipe;
writebuf = OSData::withCapacity(8);
err = _device->openPipe(&tinterruptPipe, _interface->endpoints[0]);
kprintf("Adam1: err is %x\n", err);
dummy[0] = 0xff;
dummy[1] = 0xff;
dummy[2] = 0xff;
dummy[3] = 0xff;
dummy[4] = 0xff;
dummy[5] = 0xff;
dummy[6] = 0xff;
dummy[7] = 0xff;
writebuf->appendBytes(dummy, 8);
// err = _device->write(writebuf, tinterruptPipe);
kprintf("Adam2: err is %x\n", err);
//deallocate writebuf
*/
}
//bits = 2 is Caps Lock, I haven't tried anything else. 0 clears all
void AppleKeyboard::Set_LED_States(UInt8 bits)
{
IOReturn err = kIOReturnSuccess;
IOUSBCompletion completion;
if (_prevent_LED_set)
return;
//_request and _hid_report must be static because the deviceRequest() call
// is asynchronous.
_request.rqDirection = kUSBOut;
_request.rqType = kUSBClass;
_request.rqRecipient = kUSBInterface;
_request.bRequest = kHIDRqSetReport; //Set Report in HID specs
OSWriteLittleInt16(&_request.wValue, 0, (UInt16) kHIDRtOutputReport << 8 );
OSWriteLittleInt16(&_request.wIndex, 0,
_interface->interfaceDescriptor()->interfaceNumber); // 0 for iMac keyboards
OSWriteLittleInt16(&_request.wLength, 0, 1); // MacOS 8.5 hard-codes it to 1 byte length
_hid_report[0] = bits; // 2 to set LED, 0 to clear all LEDs
_hid_report[1] = 0;
_request.pData = (void *)_hid_report;
completion.target = (void *)self;
completion.action = &AppleKeyboard::setLEDHandler;
completion.parameter = (void *)0;
err = _interface->deviceRequest(&_request, &completion);
return;
}
extern "C" {
void Debugger( const char * );
void boot(int paniced, int howto, char * command);
#define RB_BOOT 1 /* Causes reboot, not halt. Is in xnu/bsd/sys/reboot.h */
}
//This helper function is only called by StartHandler below. key_ptr points
// to 8 (kUSB_LOWSPEED_MAXPACKET) valid bytes of data
void AppleKeyboard::Simulate_ADB_Event(UInt8 *key_ptr, UInt32 bytes_read)
{
UInt8 alpha, modifier=0;
bool found;
AbsoluteTime now;
UInt8 seq_key, i;//counter for alpha keys pressed.
/**
UInt8 *kbdData;
kbdData = key_ptr;
kprintf("Num = %d x%x x%x x%x x%x x%x x%x x%x x%x\n",
bytes_read, *kbdData, *(kbdData +1),
*(kbdData+2), *(kbdData +3),
*(kbdData+4), *(kbdData +5),
*(kbdData+6), *(kbdData +7)
);
**/
// Test for the keyboard bug where all the keys are 0x01. JDC.
found = true;
for (seq_key = 2; seq_key < prev_bytes_read; seq_key++) {
if (*(key_ptr + seq_key) != 1) found = false;
}
if (found) return;
if (bytes_read > kUSB_LOWSPEED_MAXPACKET) // 8 bytes
{
bytes_read = kUSB_LOWSPEED_MAXPACKET; //Limit myself to low-speed keyboards
}
modifier = *key_ptr;
//alpha = *(key_ptr +2); // byte +1 seems to be unused
//adb_code = usb_2_adb_keymap[alpha];
//Handle new key information. The first byte is a set of bits describing
// which modifier keys are down. The 2nd byte never seems to be used.
// The third byte is the first USB key down, and the fourth byte is the
// second key down, and so on.
//When a key is released, there's no code... just a zero upon USB polling
//8/2/99 A.W. fixed Blue Box's multiple modifier keys being pressed
// simultaneously. The trick is if a modifier key DOWN event is reported,
// and another DOWN is reported, then Blue Box loses track of it. I must
// report a UP key event first, or else avoid resending the DOWN event.
//SECTION 1. Handle modifier keys here first
if (modifier == oldmodifier)
{
//Do nothing. Same keys are still pressed, or if 0 then none pressed
// so don't overload the HID system with useless events.
}
else //Modifiers may or may not be pressed right now
{
//kprintf("mod is %x\n", modifier);
clock_get_uptime(&now);
//left-hand CONTROL modifier key
if ((modifier & kUSB_LEFT_CONTROL_BIT) && !(oldmodifier & kUSB_LEFT_CONTROL_BIT))
{
dispatchKeyboardEvent(0x36, true, now); //ADB left-hand CONTROL
_control_key = true; //determine if we reboot CPU. Is instance variable.
}
else if ((oldmodifier & kUSB_LEFT_CONTROL_BIT) && !(modifier & kUSB_LEFT_CONTROL_BIT))
{
//Now check for released modifier keys
dispatchKeyboardEvent(0x36, false, now);
_control_key = false;
}
//right-hand CONTROL modifier
if ((modifier & kUSB_RIGHT_CONTROL_BIT) && !(oldmodifier & kUSB_RIGHT_CONTROL_BIT))
{
dispatchKeyboardEvent(0x7d, true, now); //right-hand CONTROL
_control_key = true; //determine if we reboot CPU. Is instance variable.
}
else if ((oldmodifier & kUSB_RIGHT_CONTROL_BIT) && !(modifier & kUSB_RIGHT_CONTROL_BIT))
{
dispatchKeyboardEvent(0x7d, false, now);
_control_key = false;
}
//left-hand SHIFT
if ((modifier & kUSB_LEFT_SHIFT_BIT) && !(oldmodifier & kUSB_LEFT_SHIFT_BIT))
{
// Debugger("LEFT SHIFT");
dispatchKeyboardEvent(0x38, true, now);
}
else if ((oldmodifier & kUSB_LEFT_SHIFT_BIT) && !(modifier & kUSB_LEFT_SHIFT_BIT))
{
dispatchKeyboardEvent(0x38, false, now);
}
//right-hand SHIFT
if ((modifier & kUSB_RIGHT_SHIFT_BIT) && !(oldmodifier & kUSB_RIGHT_SHIFT_BIT))
{
dispatchKeyboardEvent(0x7b, true, now);
}
else if ((oldmodifier & kUSB_RIGHT_SHIFT_BIT) && !(modifier & kUSB_RIGHT_SHIFT_BIT))
{
dispatchKeyboardEvent(0x7b, false, now);
}
if ((modifier & kUSB_LEFT_ALT_BIT) && !(oldmodifier & kUSB_LEFT_ALT_BIT))
{
dispatchKeyboardEvent(0x3a, true, now);
}
else if ((oldmodifier & kUSB_LEFT_ALT_BIT) && !(modifier & kUSB_LEFT_ALT_BIT))
{
dispatchKeyboardEvent(0x3a, false, now);
}
if ((modifier & kUSB_RIGHT_ALT_BIT) && !(oldmodifier & kUSB_RIGHT_ALT_BIT))
{
dispatchKeyboardEvent(0x7c, true, now);
}
else if ((oldmodifier & kUSB_RIGHT_ALT_BIT) && !(modifier & kUSB_RIGHT_ALT_BIT))
{
dispatchKeyboardEvent(0x7c, false, now);
}
if ((modifier & kUSB_LEFT_FLOWER_BIT) && !(oldmodifier & kUSB_LEFT_FLOWER_BIT))
{
dispatchKeyboardEvent(0x37, true, now);
_flower_key = true; //determine if we go into kernel debugger, or reboot CPU
}
else if ((oldmodifier & kUSB_LEFT_FLOWER_BIT) && !(modifier & kUSB_LEFT_FLOWER_BIT))
{
dispatchKeyboardEvent(0x37, false, now);
_flower_key = false;
}
if ((modifier & kUSB_RIGHT_FLOWER_BIT) && !(oldmodifier & kUSB_RIGHT_FLOWER_BIT))
{
//dispatchKeyboardEvent(0x7e, true, now);
//WARNING... NeXT only recognizes left-hand flower key, so
// emulate that for now
dispatchKeyboardEvent(0x37, true, now);
_flower_key = true;
}
else if ((oldmodifier & kUSB_RIGHT_FLOWER_BIT) && !(modifier & kUSB_RIGHT_FLOWER_BIT))
{
dispatchKeyboardEvent(0x37, false, now);
_flower_key = false;
}
}
//SECTION 2. Handle regular alphanumeric keys now. Look first at previous keystrokes.
// Alphanumeric portion of HID report starts at byte +2.
for (seq_key = 2; seq_key < prev_bytes_read; seq_key++)
{
alpha = old_array[seq_key];
if (alpha == 0) //No keys pressed
{
break;
}
found = false;
for (i = 2; i < bytes_read; i++) //Look through current keypresses
{
if (alpha == *(key_ptr + i))
{
found = true; //This key has been held down for a while, so do nothing.
break; // Autorepeat is taken care of by IOKit.
}
}
if (!found)
{
clock_get_uptime(&now);
if (alpha == 0x39) //This is USB Caps Lock scan code
{
if (!_capsLockState)
{
dispatchKeyboardEvent(usb_2_adb_keymap[0x39], false, now);
//Only dispatch if we're in the correct state for Caps Lock
Set_LED_States(0);
}
}
else //For any other keys except LED-setting keys, dispatch immediately
{
dispatchKeyboardEvent(usb_2_adb_keymap[alpha], false, now); //KEY UP
}
}
}
//Now take care of KEY DOWN.
for (seq_key = 2; seq_key < bytes_read; seq_key++)
{
alpha = *(key_ptr + seq_key);
if (alpha == 0) //No keys pressed
{
break;
}
else if (alpha == 0x66) //POWER ON key
{
if ((_control_key) && (_flower_key)) //User wants to reboot
{
boot( RB_BOOT, 0, 0 ); //call to xnu/bsd/kern/kern_shutdown.c
}
if (_flower_key) // Apple CMD modifier must be simultaneously held down
{
PE_enter_debugger("USB Programmer Key");
//In xnu/pexpert/ppc/pe_interrupt.c and defined in pexpert.h above
}
//The reason this kernel debugger call is made here instead of KEY UP
// is that the HID system will see the POWER key and bring up a
// dialog box to shut down the computer, which is not what we want.
}
//Don't dispatch the same key again which was held down previously
found = false;
for (i = 2; i < prev_bytes_read; i++)
{
if (alpha == old_array[i])
{
found = true;
break;
}
}
if (!found)
{
clock_get_uptime(&now);
//If Debugger() is triggered then I shouldn't show the restart dialog
// box, but I think developers doing kernel debugging can live with
// this minor incovenience. Otherwise I need to do more checking here.
if (alpha == 0x39) //This is USB Caps Lock scan code
{
if (_capsLockState)
{
_capsLockState = 0;
//Don't do anything else, wait for KEY_UP loop above to handle it
}
else
{
_capsLockState = 1;
Set_LED_States(kUSB_CAPSLOCKLED_SET); // kUSB_CAPSLOCKLED_SET = 2
}
}
dispatchKeyboardEvent(usb_2_adb_keymap[alpha], true, now);
}
}
//Save the history for next time
oldmodifier = modifier;
prev_bytes_read = bytes_read;
for (i=0; i< bytes_read; i++) //guaranteed not to exceed 8
{
old_array[i] = *(key_ptr + i);
}
}
void AppleKeyboard::setLEDHandler(void * parameter,
IOReturn status,
UInt32 bufferSizeRemaining)
{
if (status)
{
//Setting the LED causes problems on CMD USB controller on MacOSX,
// so if error then prevent further attempts. Log the failure
IOLog("USB Keyboard Caps Lock LED failed\n");
kprintf("USB Keyboard Caps Lock LED failed\n");
_prevent_LED_set = TRUE;
}
}
void AppleKeyboard::readHandler(void * parameter,
IOReturn status,
UInt32 bufferSizeRemaining)
{
IOReturn err = kIOReturnSuccess;
// Handle the error if any
switch (status)
{
case kIOReturnSuccess:
break;
case kIOReturnOverrun:
// Not sure what to do with this error. It means more data
// came back than the size of a descriptor. Hmmm. For now
// just ignore it and assume the data that did come back is
// useful.
IOLog("%s: overrun error. ignoring.\n", getName());
break;
case kIOReturnNotResponding:
// This probably means the device was unplugged. Now
// we need to close the driver.
IOLog("%s: Device unplugged. Goodbye\n", getName());
goto close;
default:
// We should handle other errors more intelligently, but
// for now just return and assume the error is recoverable.
IOLog("%s: error %d reading interrupt pipe\n", getName(), status);
goto queueAnother;
}
// Handle the data
Simulate_ADB_Event((UInt8 *)_buffer->getBytesNoCopy(),
(UInt32) _maxPacketSize - bufferSizeRemaining);
queueAnother:
// Reset the buffer
_buffer->setLength(_maxPacketSize);
// Queue up another one before we leave.
if ((err = _interruptPipe->read(_buffer, &_completion)))
{
// This is bad. We probably shouldn't continue on from here.
IOLog("%s: immediate error %d queueing read\n", getName(), err);
goto close;
}
return;
close:
_interface->close(this);
return;
}
// ***************************************************************************
// usb_asyncLED
//
// Called asynchronously to turn on/off the keyboard LED
//
// **************************************************************************
void usb_asyncLED( thread_call_param_t param, thread_call_param_t )
{
AppleKeyboard * me = (AppleKeyboard *) param;
me->Set_LED_States( me->_ledState );
}
//******************************************************************************
// COPIED from ADB keyboard driver 3/25/99
// 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 AppleKeyboard::setLEDFeedback( UInt8 LED_state)
{
_ledState = LED_state;
thread_call_func(usb_asyncLED, (thread_call_param_t)this, true);
}
// *****************************************************************************
// maxKeyCodes
// A.W. copied 3/25/99 from ADB keyboard driver, I don't know what this does
// ***************************************************************************
UInt32 AppleKeyboard::maxKeyCodes (void )
{
return 0x80;
}
// *************************************************************************
// deviceType
//
// **************************************************************************
UInt32 AppleKeyboard::deviceType ( void )
{
return 2;
}
// ************************************************************************
// interfaceID. Fake ADB for now since USB defaultKeymapOfLength is too complex
//
// **************************************************************************
UInt32 AppleKeyboard::interfaceID ( void )
{
//Return value must match "interface" line in .keyboard file
return NX_EVS_DEVICE_INTERFACE_ADB; // 2 This matches contents of AppleExt.keyboard
}
/***********************************************/
//Get handler ID
//
// I assume that this method is only called if a valid USB keyboard
// is found. This method should return a 0 or something if there's
// no keyboard, but then the USB keyboard driver should never have
// been probed if there's no keyboard, so for now it won't return 0.
UInt32 AppleKeyboard::handlerID ( void )
{
UInt32 ret_id = 0x201; //513 decimal is ANSI USB iMac keyboard
//Return value must match "handler_id" line in .keyboard file
// For some reason the ADB and PS/2 keyboard drivers are missing this method
// Also, Beaker Keyboard Prefs doesn't run properly
//Fix hardware bug in iMac USB keyboard mapping for ISO keyboards
//kprintf("\nUSB product = %x, vendor = %x\n", _deviceDescriptor->product, _deviceDescriptor->vendor);
if ( _deviceDescriptor) //just to be safe
{
if (_deviceDescriptor->vendor == 0xac05) //Apple USB keyboards
{
ret_id = _deviceDescriptor->product; //0x201=ANSI, 0x202=ISO, or 0x203=JIS
if (ret_id == 0x202)
{
usb_2_adb_keymap[0x35] = 0x0a; //Cosmo key18 swaps with key74, 0a is ADB keycode
usb_2_adb_keymap[0x64] = 0x32;
IOLog("USB ISO keys swapped\n");
}
}
if (_deviceDescriptor->vendor == 0x045e) //Microsoft ID
{
if (_deviceDescriptor->product == 0x000b) //Natural USB+PS/2 keyboard
ret_id = 18; //18 is Apple Extended ADB keyboard
}
}
return ret_id;
}
// *****************************************************************************
// defaultKeymapOfLength
// A.W. copied from ADB keyboard, I don't have time to make custom USB version
// *****************************************************************************
const unsigned char * AppleKeyboard::defaultKeymapOfLength (UInt32 * length )
{
static const unsigned char appleUSAKeyMap[] = {
0x00,0x00,0x07,
0x00,0x01,0x39,
0x01,0x02,0x38,0x7b,
0x02,0x02,0x36,0x7d,0x03,0x02,0x3a,0x7c,0x04,
0x01,0x37,0x05,0x15,0x52,0x41,0x4c,0x53,0x54,0x55,0x45,0x58,0x57,0x56,0x5b,0x5c,
0x43,0x4b,0x51,0x3b,0x3d,0x3e,0x3c,0x4e,0x59,0x06,0x01,0x72,0x7b,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,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,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,0x04,0x05,0x72,0x06,0x7f,0x07,
0x3e,0x08,0x3d
};
*length = sizeof(appleUSAKeyMap);
return appleUSAKeyMap;
}