1350 lines
38 KiB
C
1350 lines
38 KiB
C
/** @file
|
|
Helper functions for I2C Keyboard Driver
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2014 - 2019, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
#include "Efikey.h"
|
|
#include "I2cKeyboard.h"
|
|
//
|
|
// I2C Key Code to Efi key mapping table
|
|
// Format:<efi scan code>, <unicode without shift>, <unicode with shift>
|
|
//
|
|
STATIC
|
|
UINT8 KeyConvertionTable[KEYCODE_MAX_MAKE][3] = {
|
|
SCAN_NULL, 'a', 'A', // 0x04
|
|
SCAN_NULL, 'b', 'B', // 0x05
|
|
SCAN_NULL, 'c', 'C', // 0x06
|
|
SCAN_NULL, 'd', 'D', // 0x07
|
|
SCAN_NULL, 'e', 'E', // 0x08
|
|
SCAN_NULL, 'f', 'F', // 0x09
|
|
SCAN_NULL, 'g', 'G', // 0x0A
|
|
SCAN_NULL, 'h', 'H', // 0x0B
|
|
SCAN_NULL, 'i', 'I', // 0x0C
|
|
SCAN_NULL, 'j', 'J', // 0x0D
|
|
SCAN_NULL, 'k', 'K', // 0x0E
|
|
SCAN_NULL, 'l', 'L', // 0x0F
|
|
SCAN_NULL, 'm', 'M', // 0x10
|
|
SCAN_NULL, 'n', 'N', // 0x11
|
|
SCAN_NULL, 'o', 'O', // 0x12
|
|
SCAN_NULL, 'p', 'P', // 0x13
|
|
SCAN_NULL, 'q', 'Q', // 0x14
|
|
SCAN_NULL, 'r', 'R', // 0x15
|
|
SCAN_NULL, 's', 'S', // 0x16
|
|
SCAN_NULL, 't', 'T', // 0x17
|
|
SCAN_NULL, 'u', 'U', // 0x18
|
|
SCAN_NULL, 'v', 'V', // 0x19
|
|
SCAN_NULL, 'w', 'W', // 0x1A
|
|
SCAN_NULL, 'x', 'X', // 0x1B
|
|
SCAN_NULL, 'y', 'Y', // 0x1C
|
|
SCAN_NULL, 'z', 'Z', // 0x1D
|
|
SCAN_NULL, '1', '!', // 0x1E
|
|
SCAN_NULL, '2', '@', // 0x1F
|
|
SCAN_NULL, '3', '#', // 0x20
|
|
SCAN_NULL, '4', '$', // 0x21
|
|
SCAN_NULL, '5', '%', // 0x22
|
|
SCAN_NULL, '6', '^', // 0x23
|
|
SCAN_NULL, '7', '&', // 0x24
|
|
SCAN_NULL, '8', '*', // 0x25
|
|
SCAN_NULL, '9', '(', // 0x26
|
|
SCAN_NULL, '0', ')', // 0x27
|
|
SCAN_NULL, 0x0d, 0x0d, // 0x28 Enter
|
|
SCAN_ESC, 0x00, 0x00, // 0x29 Esc
|
|
SCAN_NULL, 0x08, 0x08, // 0x2A Backspace
|
|
SCAN_NULL, 0x09, 0x09, // 0x2B Tab
|
|
SCAN_NULL, ' ', ' ', // 0x2C Spacebar
|
|
SCAN_NULL, '-', '_', // 0x2D
|
|
SCAN_NULL, '=', '+', // 0x2E
|
|
SCAN_NULL, '[', '{', // 0x2F
|
|
SCAN_NULL, ']', '}', // 0x30
|
|
SCAN_NULL, '\\', '|', // 0x31
|
|
SCAN_NULL, '\\', '|', // 0x32 Keyboard US \ and |
|
|
SCAN_NULL, ';', ':', // 0x33
|
|
SCAN_NULL, '\'', '"', // 0x34
|
|
SCAN_NULL, '`', '~', // 0x35 Keyboard Grave Accent and Tlide
|
|
SCAN_NULL, ',', '<', // 0x36
|
|
SCAN_NULL, '.', '>', // 0x37
|
|
SCAN_NULL, '/', '?', // 0x38
|
|
SCAN_NULL, 0x00, 0x00, // 0x39 CapsLock
|
|
SCAN_F1, 0x00, 0x00, // 0x3A
|
|
SCAN_F2, 0x00, 0x00, // 0x3B
|
|
SCAN_F3, 0x00, 0x00, // 0x3C
|
|
SCAN_F4, 0x00, 0x00, // 0x3D
|
|
SCAN_F5, 0x00, 0x00, // 0x3E
|
|
SCAN_F6, 0x00, 0x00, // 0x3F
|
|
SCAN_F7, 0x00, 0x00, // 0x40
|
|
SCAN_F8, 0x00, 0x00, // 0x41
|
|
SCAN_F9, 0x00, 0x00, // 0x42
|
|
SCAN_F10, 0x00, 0x00, // 0x43
|
|
SCAN_F11, 0x00, 0x00, // 0x44 F11
|
|
SCAN_F12, 0x00, 0x00, // 0x45 F12
|
|
SCAN_NULL, 0x00, 0x00, // 0x46 PrintScreen
|
|
SCAN_NULL, 0x00, 0x00, // 0x47 Scroll Lock
|
|
SCAN_PAUSE, 0x00, 0x00, // 0x48 Pause
|
|
SCAN_INSERT, 0x00, 0x00, // 0x49
|
|
SCAN_HOME, 0x00, 0x00, // 0x4A
|
|
SCAN_PAGE_UP, 0x00, 0x00, // 0x4B
|
|
SCAN_DELETE, 0x00, 0x00, // 0x4C
|
|
SCAN_END, 0x00, 0x00, // 0x4D
|
|
SCAN_PAGE_DOWN, 0x00, 0x00, // 0x4E
|
|
SCAN_RIGHT, 0x00, 0x00, // 0x4F
|
|
SCAN_LEFT, 0x00, 0x00, // 0x50
|
|
SCAN_DOWN, 0x00, 0x00, // 0x51
|
|
SCAN_UP, 0x00, 0x00, // 0x52
|
|
SCAN_NULL, 0x00, 0x00, // 0x53 NumLock
|
|
SCAN_NULL, '/', '/', // 0x54
|
|
SCAN_NULL, '*', '*', // 0x55
|
|
SCAN_NULL, '-', '-', // 0x56
|
|
SCAN_NULL, '+', '+', // 0x57
|
|
SCAN_NULL, 0x0d, 0x0d, // 0x58
|
|
SCAN_END, '1', '1', // 0x59
|
|
SCAN_DOWN, '2', '2', // 0x5A
|
|
SCAN_PAGE_DOWN, '3', '3', // 0x5B
|
|
SCAN_LEFT, '4', '4', // 0x5C
|
|
SCAN_NULL, '5', '5', // 0x5D
|
|
SCAN_RIGHT, '6', '6', // 0x5E
|
|
SCAN_HOME, '7', '7', // 0x5F
|
|
SCAN_UP, '8', '8', // 0x60
|
|
SCAN_PAGE_UP, '9', '9', // 0x61
|
|
SCAN_INSERT, '0', '0', // 0x62
|
|
SCAN_DELETE, '.', '.', // 0x63
|
|
SCAN_NULL, '\\', '|', // 0x64 Keyboard Non-US \ and |
|
|
SCAN_NULL, 0x00, 0x00, // 0x65 Keyboard Application
|
|
SCAN_NULL, 0x00, 0x00, // 0x66 Keyboard Power
|
|
SCAN_NULL, '=' , '=' , // 0x67 Keypad =
|
|
SCAN_F13, 0x00, 0x00, // 0x68
|
|
SCAN_F14, 0x00, 0x00, // 0x69
|
|
SCAN_F15, 0x00, 0x00, // 0x6A
|
|
SCAN_F16, 0x00, 0x00, // 0x6B
|
|
SCAN_F17, 0x00, 0x00, // 0x6C
|
|
SCAN_F18, 0x00, 0x00, // 0x6D
|
|
SCAN_F19, 0x00, 0x00, // 0x6E
|
|
SCAN_F20, 0x00, 0x00, // 0x6F
|
|
SCAN_F21, 0x00, 0x00, // 0x70
|
|
SCAN_F22, 0x00, 0x00, // 0x71
|
|
SCAN_F23, 0x00, 0x00, // 0x72
|
|
SCAN_F24, 0x00, 0x00, // 0x73
|
|
SCAN_MUTE, 0x00, 0x00, // 0x7F
|
|
SCAN_VOLUME_UP, 0x00, 0x00, // 0x80
|
|
SCAN_VOLUME_DOWN, 0x00, 0x00 // 0x81
|
|
};
|
|
|
|
STATIC KB_MODIFIER KB_Mod[8] = {
|
|
{ MOD_CONTROL_L, 0xe0 }, // 11100000
|
|
{ MOD_CONTROL_R, 0xe4 }, // 11100100
|
|
{ MOD_SHIFT_L, 0xe1 }, // 11100001
|
|
{ MOD_SHIFT_R, 0xe5 }, // 11100101
|
|
{ MOD_ALT_L, 0xe2 }, // 11100010
|
|
{ MOD_ALT_R, 0xe6 }, // 11100110
|
|
{ MOD_WIN_L, 0xe3 }, // 11100011
|
|
{ MOD_WIN_R, 0xe7 }, // 11100111
|
|
};
|
|
|
|
STATIC
|
|
UINT8 KbcCodeTable[][4] = {
|
|
// Original Shift Alt Ctrl
|
|
0x1E, 0x1E, 0x1E, 0x1E, // 0x04 'A'
|
|
0x30, 0x30, 0x30, 0x30, // 0x05 'B'
|
|
0x2E, 0x2E, 0x2E, 0x2E, // 0x06 'C'
|
|
0x20, 0x20, 0x20, 0x20, // 0x07 'D'
|
|
0x12, 0x12, 0x12, 0x12, // 0x08 'E'
|
|
0x21, 0x21, 0x21, 0x21, // 0x09 'F'
|
|
0x22, 0x22, 0x22, 0x22, // 0x0A 'G'
|
|
0x23, 0x23, 0x23, 0x23, // 0x0B 'H'
|
|
0x17, 0x17, 0x17, 0x17, // 0x0C 'I'
|
|
0x24, 0x24, 0x24, 0x24, // 0x0D 'J'
|
|
0x25, 0x25, 0x25, 0x25, // 0x0E 'K'
|
|
0x26, 0x26, 0x26, 0x26, // 0x0F 'L'
|
|
0x32, 0x32, 0x32, 0x32, // 0x10 'M'
|
|
0x31, 0x31, 0x31, 0x31, // 0x11 'N'
|
|
0x18, 0x18, 0x18, 0x18, // 0x12 'O'
|
|
0x19, 0x19, 0x19, 0x19, // 0x13 'P'
|
|
0x10, 0x10, 0x10, 0x10, // 0x14 'Q'
|
|
0x13, 0x13, 0x13, 0x13, // 0x15 'R'
|
|
0x1F, 0x1F, 0x1F, 0x1F, // 0x16 'S'
|
|
0x14, 0x14, 0x14, 0x14, // 0x17 'T'
|
|
0x16, 0x16, 0x16, 0x16, // 0x18 'U'
|
|
0x2F, 0x2F, 0x2F, 0x2F, // 0x19 'V'
|
|
0x11, 0x11, 0x11, 0x11, // 0x1A 'W'
|
|
0x2D, 0x2D, 0x2D, 0x2D, // 0x1B 'X'
|
|
0x15, 0x15, 0x15, 0x15, // 0x1C 'Y'
|
|
0x2C, 0x2C, 0x2C, 0x2C, // 0x1D 'Z'
|
|
0x02, 0x02, 0x78, 0x00, // 0x1E '1 !'
|
|
0x03, 0x03, 0x79, 0x03, // 0x1F '2 @'
|
|
0x04, 0x04, 0x7A, 0x00, // 0x20 '3 #'
|
|
0x05, 0x05, 0x7B, 0x00, // 0x21 '4 $'
|
|
0x06, 0x06, 0x7C, 0x00, // 0x22 '5 %'
|
|
0x07, 0x07, 0x7D, 0x07, // 0x23 '6 ^'
|
|
0x08, 0x08, 0x7E, 0x00, // 0x24 '7 &'
|
|
0x09, 0x09, 0x7F, 0x00, // 0x25 '8 *'
|
|
0x0A, 0x0A, 0x81, 0x00, // 0x26 '9 ('
|
|
0x0B, 0x0B, 0x82, 0x00, // 0x27 '0 )'
|
|
0x1C, 0x1C, 0x1C, 0x1C, // 0x28 'Enter'
|
|
0x01, 0x01, 0x01, 0x01, // 0x29 'Esc'
|
|
0x0E, 0x0E, 0x0E, 0x0E, // 0x2A 'Backspace'
|
|
0x0F, 0x0F, 0xA5, 0x94, // 0x2B 'Tab'
|
|
0x39, 0x39, 0x39, 0x39, // 0x2C 'Space bar'
|
|
0x0C, 0x0C, 0x82, 0x0C, // 0x2D '- _'
|
|
0x0D, 0x0D, 0x83, 0x00, // 0x2E '= +'
|
|
0x1A, 0x1A, 0x1A, 0x1A, // 0x2F '[ {'
|
|
0x1B, 0x1B, 0x1B, 0x1B, // 0x30 '] }'
|
|
0x2B, 0x2B, 0x2B, 0x2B, // 0x31 '\ |'
|
|
0x2B, 0x2B, 0x2B, 0x2B, // 0x32 Non-US '# ~' ******
|
|
0x27, 0x27, 0x27, 0x00, // 0x33 '; :'
|
|
0x28, 0x28, 0x28, 0x00, // 0x34 '' "'
|
|
0x29, 0x29, 0x29, 0x00, // 0x35 ;` ~'
|
|
0x33, 0x33, 0x33, 0x00, // 0x36 ', <'
|
|
0x34, 0x34, 0x34, 0x00, // 0x37 '. >'
|
|
0x35, 0x35, 0x35, 0x00, // 0x38 '/ ?'
|
|
0x3A, 0x3A, 0x3A, 0x3A, // 0x39 'CapsLock'
|
|
0x3B, 0x54, 0x68, 0x5E, // 0x3A 'F1'
|
|
0x3C, 0x55, 0x69, 0x5F, // 0x3B 'F2'
|
|
0x3D, 0x56, 0x6A, 0x60, // 0x3C 'F3'
|
|
0x3E, 0x57, 0x6B, 0x61, // 0x3D 'F4'
|
|
0x3F, 0x58, 0x6C, 0x62, // 0x3E 'F5'
|
|
0x40, 0x59, 0x6D, 0x63, // 0x3F 'F6'
|
|
0x41, 0x5A, 0x6E, 0x64, // 0x40 'F7'
|
|
0x42, 0x5B, 0x6F, 0x65, // 0x41 'F8'
|
|
0x43, 0x5C, 0x70, 0x66, // 0x42 'F9'
|
|
0x44, 0x5D, 0x71, 0x67, // 0x43 'F10'
|
|
0x57, 0x87, 0x8B, 0x89, // 0x44 'F11'
|
|
0x58, 0x88, 0x8C, 0x8A, // 0x45 'F12'
|
|
0x80, 0x80, 0x80, 0x72, // 0x46 'PrntScrn' E0,2A,E0,37 E0,B7,E0,AA
|
|
0x46, 0x46, 0x46, 0x46, // 0x47 'ScrollLock'
|
|
0x81, 0x81, 0x81, 0x81, // 0x48 'Pause' E1,1D,45 E1,9D,C5
|
|
0xD2, 0xD2, 0xA2, 0x92, // 0x49 'Insert' E0,52 E0,D2
|
|
0xC7, 0xC7, 0x97, 0x77, // 0x4A 'Home' E0,47 E0,C7
|
|
0xC9, 0xC9, 0x99, 0x84, // 0x4B 'PageUp' E0,49 E0,C9
|
|
0xD3, 0xD3, 0xA3, 0x93, // 0x4C 'Delete Forward' E0,53 E0,D3
|
|
0xCF, 0xCF, 0x9F, 0x75, // 0x4D 'End' E0,4F E0,CF
|
|
0xD1, 0xD1, 0xA1, 0x76, // 0x4E 'PageDown' E0,51 E0,D1
|
|
0xCD, 0xCD, 0x9D, 0x74, // 0x4F 'Right Arrow' E0,4D E0,CD
|
|
0xCB, 0xCB, 0x9B, 0x73, // 0x50 'Left Arrow' E0,4B E0,CB
|
|
0xD0, 0xD0, 0xA0, 0x91, // 0x51 'Down Arrow' E0,50 E0,D0
|
|
0xC8, 0xC8, 0x98, 0x8D, // 0x52 'Up Arrow' E0,48 E0,C8
|
|
0x45, 0x45, 0x45, 0x45, // 0x53 'NumLock'
|
|
0xB5, 0xB5, 0xA4, 0x95, // 0x54 'keypad /' E0,35 E0,B5
|
|
0x37, 0x37, 0x37, 0x96, // 0x55 'keypad *'
|
|
0x4A, 0x4A, 0x4A, 0x8E, // 0x56 'keypad -'
|
|
0x4E, 0x4E, 0x4E, 0x90, // 0x57 'keypad +'
|
|
0x9C, 0x9C, 0xA6, 0x9C, // 0x58 'keypad Enter' E0,1C E0,9C
|
|
0x4F, 0x4F, 0x9F, 0x75, // 0x59 'keypad 1 End'
|
|
0x50, 0x50, 0xA0, 0x91, // 0x5A 'keypad 2 DownArrow'
|
|
0x51, 0x51, 0xA1, 0x76, // 0x5B 'keypad 3 PageDn'
|
|
0x4B, 0x4B, 0x9B, 0x73, // 0x5C 'keypad 4 LeftArrow'
|
|
0x4C, 0x4C, 0x00, 0x8F, // 0x5D 'keypad 5'
|
|
0x4D, 0x4D, 0x9D, 0x74, // 0x5E 'keypad 6 RightArrow'
|
|
0x47, 0x47, 0x97, 0x77, // 0x5F 'keypad 7 Home'
|
|
0x48, 0x48, 0x98, 0x8D, // 0x60 'keypad 8 UpArrow'
|
|
0x49, 0x49, 0x99, 0x84, // 0x61 'keypad 9 PageUp'
|
|
0x52, 0x52, 0xA2, 0x92, // 0x62 'keypad 0 Insert'
|
|
0x53, 0x53, 0xA3, 0x93, // 0x63 'keypad . Del'
|
|
0x56, 0x56, 0x56, 0x56, // 0x64 '\ |'
|
|
0xDD, 0xDD, 0xDD, 0xDD // 0x65 'Application' E0,5D E0,DD
|
|
};
|
|
|
|
STATIC
|
|
UINT8 CtrlIgnoreKey[] = {
|
|
0x1E, // '1','!'
|
|
0x20, // '3','#'
|
|
0x21, // '4','$'
|
|
0x22, // '5','%'
|
|
0x24, // '7','&'
|
|
0x25, // '8','*'
|
|
0x26, // '9','('
|
|
0x27, // '0',')'
|
|
0x2E, // '=','+'
|
|
0x33, // ';',':'
|
|
0x34, // '\'','"'
|
|
0x35, // '`','~'
|
|
0x36, // ',','<'
|
|
0x37, // '.','>'
|
|
0x38 // '/','?'
|
|
};
|
|
|
|
/**
|
|
|
|
Handler function for I2C Keyboard's interrupt transfer.
|
|
|
|
@param Data A pointer to a buffer that is filled with key data which is
|
|
retrieved via asynchronous interrupt transfer.
|
|
@param DataLength Indicates the size of the data buffer.
|
|
@param Context Pointing to I2C_KB_DEV instance.
|
|
@param Result Indicates the result of the asynchronous interrupt transfer.
|
|
|
|
@retval EFI_SUCCESS Success
|
|
@retval EFI_DEVICE_ERROR Hardware Error
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
KeyboardHandler (
|
|
IN VOID *Data,
|
|
IN UINTN DataLength,
|
|
IN VOID *Context,
|
|
IN UINT32 Result
|
|
)
|
|
{
|
|
I2C_KB_DEV *KbDev;
|
|
UINT8 *CurKeyCodeBuffer;
|
|
UINT8 *OldKeyCodeBuffer;
|
|
UINT8 CurModifierMap;
|
|
UINT8 OldModifierMap;
|
|
UINTN Index;
|
|
UINT8 Index2;
|
|
BOOLEAN Down;
|
|
EFI_STATUS Status;
|
|
BOOLEAN KeyRelease;
|
|
BOOLEAN KeyPress;
|
|
UINTN SavedTail;
|
|
KEY Key;
|
|
UINT8 NewRepeatKey;
|
|
|
|
if (DataLength == 0 || Data == NULL) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
KbDev = (I2C_KB_DEV *) Context;
|
|
NewRepeatKey = 0;
|
|
CurKeyCodeBuffer = (UINT8 *) Data;
|
|
OldKeyCodeBuffer = KbDev->LastKeyCodeArray;
|
|
//
|
|
// checks for new key stroke.
|
|
// if no new key got, return immediately.
|
|
//
|
|
for (Index = 0; Index < 8; Index++) {
|
|
if (OldKeyCodeBuffer[Index] != CurKeyCodeBuffer[Index]) {
|
|
break;
|
|
}
|
|
}
|
|
if (Index == 8) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// Parse the modifier key
|
|
//
|
|
CurModifierMap = CurKeyCodeBuffer[0];
|
|
OldModifierMap = OldKeyCodeBuffer[0];
|
|
//
|
|
// handle modifier key's pressing or releasing situation.
|
|
//
|
|
for (Index = 0; Index < 8; Index++) {
|
|
|
|
if ((CurModifierMap & KB_Mod[Index].Mask) != (OldModifierMap & KB_Mod[Index].Mask)) {
|
|
//
|
|
// if current modifier key is up, then
|
|
// CurModifierMap & KB_Mod[Index].Mask = 0;
|
|
// otherwize it is a non-zero value.
|
|
// Inserts the pressed modifier key into key buffer.
|
|
//
|
|
Down = (UINT8) (CurModifierMap & KB_Mod[Index].Mask);
|
|
InsertKeyCode (KbDev, KB_Mod[Index].Key, Down);
|
|
}
|
|
}
|
|
//
|
|
// handle normal key's releasing situation
|
|
//
|
|
KeyRelease = FALSE;
|
|
for (Index = 2; Index < 8; Index++) {
|
|
|
|
if (!KBD_VALID_KEYCODE (OldKeyCodeBuffer[Index])) {
|
|
continue;
|
|
}
|
|
|
|
KeyRelease = TRUE;
|
|
for (Index2 = 2; Index2 < 8; Index2++) {
|
|
|
|
if (!KBD_VALID_KEYCODE (CurKeyCodeBuffer[Index2])) {
|
|
continue;
|
|
}
|
|
|
|
if (OldKeyCodeBuffer[Index] == CurKeyCodeBuffer[Index2]) {
|
|
KeyRelease = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (KeyRelease) {
|
|
InsertKeyCode (
|
|
KbDev,
|
|
OldKeyCodeBuffer[Index],
|
|
0
|
|
);
|
|
//
|
|
// the original reapeat key is released.
|
|
//
|
|
if (OldKeyCodeBuffer[Index] == KbDev->RepeatKey) {
|
|
KbDev->RepeatKey = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// original repeat key is released, cancel the repeat timer
|
|
//
|
|
if (KbDev->RepeatKey == 0 && KbDev->RepeatPollingHandle != NULL) {
|
|
gBS->CloseEvent (KbDev->RepeatPollingHandle);
|
|
KbDev->RepeatPollingHandle = NULL;
|
|
}
|
|
|
|
//
|
|
// handle normal key's pressing situation
|
|
//
|
|
KeyPress = FALSE;
|
|
for (Index = 2; Index < 8; Index++) {
|
|
|
|
if (!KBD_VALID_KEYCODE (CurKeyCodeBuffer[Index])) {
|
|
continue;
|
|
}
|
|
|
|
KeyPress = TRUE;
|
|
for (Index2 = 2; Index2 < 8; Index2++) {
|
|
|
|
if (!KBD_VALID_KEYCODE (OldKeyCodeBuffer[Index2])) {
|
|
continue;
|
|
}
|
|
|
|
if (CurKeyCodeBuffer[Index] == OldKeyCodeBuffer[Index2]) {
|
|
KeyPress = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (KeyPress) {
|
|
InsertKeyCode (KbDev, CurKeyCodeBuffer[Index], 1);
|
|
//
|
|
// NumLock/CapsLock/ScrollLock pressed
|
|
//
|
|
if (CurKeyCodeBuffer[Index] != 0x53 && CurKeyCodeBuffer[Index] != 0x39 && CurKeyCodeBuffer[Index] != 0x47) {
|
|
NewRepeatKey = CurKeyCodeBuffer[Index];
|
|
}
|
|
//
|
|
// do not repeat the original repeated key
|
|
//
|
|
KbDev->RepeatKey = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Update LastKeycodeArray[] buffer in the
|
|
// Usb Keyboard Device data structure.
|
|
//
|
|
for (Index = 0; Index < 8; Index++) {
|
|
KbDev->LastKeyCodeArray[Index] = CurKeyCodeBuffer[Index];
|
|
}
|
|
//
|
|
// pre-process I2cKeyQueue, pop out the ctrl,alt,del key in sequence
|
|
// and judge whether it will invoke reset event.
|
|
//
|
|
SavedTail = KbDev->I2cKeyQueue.Tail;
|
|
Index = KbDev->I2cKeyQueue.Head;
|
|
while (Index != SavedTail) {
|
|
Dequeue (&KbDev->I2cKeyQueue, &Key, sizeof (Key));
|
|
|
|
switch (Key.KeyCode) {
|
|
case 0xe1:
|
|
case 0xe5:
|
|
if (Key.Down) {
|
|
KbDev->ShiftOn = 1;
|
|
} else {
|
|
KbDev->ShiftOn = 0;
|
|
}
|
|
break;
|
|
|
|
case 0xe0:
|
|
case 0xe4:
|
|
if (Key.Down) {
|
|
KbDev->CtrlOn = 1;
|
|
} else {
|
|
KbDev->CtrlOn = 0;
|
|
}
|
|
break;
|
|
|
|
case 0xe2:
|
|
case 0xe6:
|
|
if (Key.Down) {
|
|
KbDev->AltOn = 1;
|
|
} else {
|
|
KbDev->AltOn = 0;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Del Key Code
|
|
//
|
|
case 0x4c:
|
|
case 0x63:
|
|
if (Key.Down) {
|
|
if (KbDev->CtrlOn && KbDev->AltOn) {
|
|
gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, KEYBOARD_RESET_SIGNATURE);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//
|
|
// insert the key back to the buffer.
|
|
// so the key sequence will not be destroyed.
|
|
//
|
|
InsertKeyCode (
|
|
KbDev,
|
|
Key.KeyCode,
|
|
Key.Down
|
|
);
|
|
Index = KbDev->I2cKeyQueue.Head;
|
|
}
|
|
//
|
|
// If have new key pressed, update the RepeatKey value, and set the
|
|
// timer to repeate delay timer
|
|
//
|
|
if (NewRepeatKey != 0) {
|
|
if (KbDev->RepeatPollingHandle) {
|
|
gBS->CloseEvent (KbDev->RepeatPollingHandle);
|
|
KbDev->RepeatPollingHandle = NULL;
|
|
}
|
|
//
|
|
// sets trigger time to "Repeat Delay Time",
|
|
// to trigger the repeat timer when the key is hold long
|
|
// enough time.
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EVT_TIMER | EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
KeyboardRepeatHandler,
|
|
KbDev,
|
|
&KbDev->RepeatPollingHandle
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
Status = gBS->SetTimer (
|
|
KbDev->RepeatPollingHandle,
|
|
TimerRelative,
|
|
KBD_REPEAT_DELAY
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
KbDev->RepeatKey = NewRepeatKey;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Convert key code to KBC scan code
|
|
|
|
@param KbDev The I2C_KB_DEV instance.
|
|
@param Key Key code
|
|
|
|
@retval KBC scan code
|
|
|
|
**/
|
|
STATIC
|
|
UINT16
|
|
ConvertKbcScanCode (
|
|
IN I2C_KB_DEV *KbDev,
|
|
IN UINT8 Key
|
|
)
|
|
{
|
|
UINT16 KbcScanCode;
|
|
|
|
if (Key < 4 || Key >= (sizeof (KbcCodeTable) / 4) + 4) return 0;
|
|
if (KbDev->AltOn) {
|
|
KbcScanCode = KbcCodeTable[Key - 4][2];
|
|
} else if (KbDev->CtrlOn) {
|
|
KbcScanCode = KbcCodeTable[Key - 4][3];
|
|
} else if (KbDev->ShiftOn) {
|
|
KbcScanCode = KbcCodeTable[Key - 4][1];
|
|
} else {
|
|
KbcScanCode = KbcCodeTable[Key - 4][0];
|
|
if (KbcScanCode == 0x57 || KbcScanCode == 0x58) {
|
|
//
|
|
// Convert F11/F12 to KBC converted code
|
|
//
|
|
KbcScanCode = 0x85 + (KbcScanCode - 0x57);
|
|
} else if (KbcScanCode >= 0x82) {
|
|
//
|
|
// Double code key
|
|
//
|
|
KbcScanCode &= ~0x80;
|
|
KbcScanCode <<= 8;
|
|
KbcScanCode |= 0xE0;
|
|
}
|
|
}
|
|
return KbcScanCode;
|
|
}
|
|
|
|
/**
|
|
|
|
Retrieves a key character after parsing the raw data in keyboard buffer.
|
|
|
|
@param KbDev The I2C_KB_DEV instance.
|
|
@param KeyChar Points to the Key character after key parsing.
|
|
|
|
@retval EFI_SUCCESS Success
|
|
@retval EFI_NOT_READY Device is not ready
|
|
|
|
**/
|
|
EFI_STATUS
|
|
ParseKey (
|
|
IN I2C_KB_DEV *KbDev,
|
|
OUT UINT8 *KeyChar
|
|
)
|
|
{
|
|
KEY Key;
|
|
|
|
*KeyChar = 0;
|
|
|
|
while (!IsQueueEmpty (&KbDev->I2cKeyQueue)) {
|
|
//
|
|
// pops one raw data off.
|
|
//
|
|
Dequeue (&KbDev->I2cKeyQueue, &Key, sizeof (Key));
|
|
|
|
if (!Key.Down) {
|
|
switch (Key.KeyCode) {
|
|
|
|
case 0xe0:
|
|
KbDev->LeftCtrlOn = 0;
|
|
KbDev->CtrlOn = 0;
|
|
break;
|
|
case 0xe4:
|
|
KbDev->RightCtrlOn = 0;
|
|
KbDev->CtrlOn = 0;
|
|
break;
|
|
case 0xe1:
|
|
KbDev->LeftShiftOn = 0;
|
|
KbDev->ShiftOn = 0;
|
|
break;
|
|
case 0xe5:
|
|
KbDev->RightShiftOn = 0;
|
|
KbDev->ShiftOn = 0;
|
|
break;
|
|
case 0xe2:
|
|
KbDev->LeftAltOn = 0;
|
|
KbDev->AltOn = 0;
|
|
break;
|
|
case 0xe6:
|
|
KbDev->RightAltOn = 0;
|
|
KbDev->AltOn = 0;
|
|
break;
|
|
//
|
|
// Logo release
|
|
//
|
|
case 0xe3:
|
|
KbDev->LeftLogoOn = 0;
|
|
break;
|
|
case 0xe7:
|
|
KbDev->RightLogoOn = 0;
|
|
break;
|
|
//
|
|
// Menu key (App/Apps) release
|
|
//
|
|
case 0x65:
|
|
KbDev->MenuKeyOn = 0;
|
|
break;
|
|
//
|
|
// SysReq release
|
|
//
|
|
case 0x46:
|
|
KbDev->SysReqOn = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Analyzes key pressing situation
|
|
//
|
|
switch (Key.KeyCode) {
|
|
|
|
case 0xe0:
|
|
KbDev->LeftCtrlOn = 1;
|
|
KbDev->CtrlOn = 1;
|
|
break;
|
|
case 0xe4:
|
|
KbDev->RightCtrlOn = 1;
|
|
KbDev->CtrlOn = 1;
|
|
break;
|
|
case 0xe1:
|
|
KbDev->LeftShiftOn = 1;
|
|
KbDev->ShiftOn = 1;
|
|
break;
|
|
case 0xe5:
|
|
KbDev->RightShiftOn = 1;
|
|
KbDev->ShiftOn = 1;
|
|
break;
|
|
case 0xe2:
|
|
KbDev->LeftAltOn = 1;
|
|
KbDev->AltOn = 1;
|
|
break;
|
|
case 0xe6:
|
|
KbDev->RightAltOn = 1;
|
|
KbDev->AltOn = 1;
|
|
break;
|
|
case 0xe3:
|
|
KbDev->LeftLogoOn = 1;
|
|
break;
|
|
case 0xe7:
|
|
KbDev->RightLogoOn = 1;
|
|
break;
|
|
|
|
case 0x53:
|
|
if (KbDev->IsCsmEnabled) {
|
|
if (!PS2_LED_UPDATING) {
|
|
USB_LED_UPDATE;
|
|
KbDev->NumLockOn ^= 1;
|
|
SyncKbdLed (KbDev);
|
|
USB_LED_UPDATED;
|
|
}
|
|
} else {
|
|
KbDev->NumLockOn ^= 1;
|
|
SyncKbdLed (KbDev);
|
|
}
|
|
break;
|
|
|
|
case 0x39:
|
|
if (KbDev->IsCsmEnabled) {
|
|
if (!PS2_LED_UPDATING) {
|
|
USB_LED_UPDATE;
|
|
KbDev->CapsOn ^= 1;
|
|
SyncKbdLed (KbDev);
|
|
USB_LED_UPDATED;
|
|
}
|
|
} else {
|
|
KbDev->CapsOn ^= 1;
|
|
SyncKbdLed (KbDev);
|
|
}
|
|
break;
|
|
|
|
case 0x47:
|
|
if (KbDev->IsCsmEnabled) {
|
|
if (!PS2_LED_UPDATING) {
|
|
USB_LED_UPDATE;
|
|
KbDev->ScrollOn ^= 1;
|
|
SyncKbdLed (KbDev);
|
|
USB_LED_UPDATED;
|
|
}
|
|
} else {
|
|
KbDev->ScrollOn ^= 1;
|
|
SyncKbdLed (KbDev);
|
|
}
|
|
break;
|
|
//
|
|
// PrintScreen,Pause,Application,Power
|
|
// keys are not valid EFI key
|
|
//
|
|
case 0x46:
|
|
KbDev->SysReqOn = 1;
|
|
break;
|
|
case 0x65:
|
|
KbDev->MenuKeyOn = 1;
|
|
break;
|
|
case 0x48:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//
|
|
// When encountered Del Key...
|
|
//
|
|
if (Key.KeyCode == 0x4c || Key.KeyCode == 0x63) {
|
|
if (KbDev->CtrlOn && KbDev->AltOn) {
|
|
gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, KEYBOARD_RESET_SIGNATURE);
|
|
}
|
|
}
|
|
*KeyChar = Key.KeyCode;
|
|
if ((KbDev->IsCsmEnabled) && (Key.Down) && (Key.KeyCode < 0xe0) && (Key.KeyCode != 0x46) && (Key.KeyCode != 0x48)) {
|
|
//
|
|
// Put the KBC scan code into EBDA+0x164. The PrntScrn and Pause will be filter out to sync with PS2 path
|
|
//
|
|
*(UINT16*)&(EBDA(EBDA_KEYBORD_SCAN_CODE)) = ConvertKbcScanCode (KbDev, Key.KeyCode);
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
return EFI_NOT_READY;
|
|
|
|
}
|
|
|
|
/**
|
|
Initialize the key state.
|
|
|
|
@param UsbKeyboardDevice The USB_KB_DEV instance.
|
|
@param KeyState A pointer to receive the key state information.
|
|
**/
|
|
VOID
|
|
InitializeKeyState (
|
|
IN I2C_KB_DEV *KbDev,
|
|
OUT EFI_KEY_STATE *KeyState
|
|
)
|
|
{
|
|
KeyState->KeyShiftState = EFI_SHIFT_STATE_VALID;
|
|
KeyState->KeyToggleState = EFI_TOGGLE_STATE_VALID;
|
|
|
|
if (KbDev->LeftCtrlOn) {
|
|
KeyState->KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
|
|
}
|
|
if (KbDev->RightCtrlOn) {
|
|
KeyState->KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;
|
|
}
|
|
if (KbDev->LeftAltOn) {
|
|
KeyState->KeyShiftState |= EFI_LEFT_ALT_PRESSED;
|
|
}
|
|
if (KbDev->RightAltOn) {
|
|
KeyState->KeyShiftState |= EFI_RIGHT_ALT_PRESSED;
|
|
}
|
|
if (KbDev->LeftShiftOn) {
|
|
KeyState->KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
|
|
}
|
|
if (KbDev->RightShiftOn) {
|
|
KeyState->KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
|
|
}
|
|
if (KbDev->LeftLogoOn) {
|
|
KeyState->KeyShiftState |= EFI_LEFT_LOGO_PRESSED;
|
|
}
|
|
if (KbDev->RightLogoOn) {
|
|
KeyState->KeyShiftState |= EFI_RIGHT_LOGO_PRESSED;
|
|
}
|
|
if (KbDev->MenuKeyOn) {
|
|
KeyState->KeyShiftState |= EFI_MENU_KEY_PRESSED;
|
|
}
|
|
if (KbDev->SysReqOn) {
|
|
KeyState->KeyShiftState |= EFI_SYS_REQ_PRESSED;
|
|
}
|
|
|
|
if (KbDev->ScrollOn) {
|
|
KeyState->KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;
|
|
}
|
|
if (KbDev->NumLockOn) {
|
|
KeyState->KeyToggleState |= EFI_NUM_LOCK_ACTIVE;
|
|
}
|
|
if (KbDev->CapsOn) {
|
|
KeyState->KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
|
|
}
|
|
if (KbDev->IsSupportPartialKey) {
|
|
KeyState->KeyToggleState |= EFI_KEY_STATE_EXPOSED;
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
Converts Keyboard code to EFI Scan Code.
|
|
|
|
@param KbDev The I2C_KB_DEV instance.
|
|
@param KeyChar Indicates the key code that will be interpreted.
|
|
@param Key A pointer to a buffer that is filled in with
|
|
the keystroke information for the key that
|
|
was pressed.
|
|
|
|
@retval EFI_NOT_READY Device is not ready
|
|
@retval EFI_SUCCESS Success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
KeyCodeToEFIScanCode (
|
|
IN I2C_KB_DEV *KbDev,
|
|
IN UINT8 KeyChar,
|
|
OUT EFI_INPUT_KEY *Key
|
|
)
|
|
{
|
|
UINT8 Index;
|
|
|
|
if (!KBD_VALID_KEYCODE (KeyChar)) {
|
|
return EFI_NOT_READY;
|
|
}
|
|
if ((KeyChar >= 0xe0) && (KeyChar <= 0xe7)) {
|
|
//
|
|
// For Partial Keystroke support
|
|
//
|
|
Key->ScanCode = SCAN_NULL;
|
|
Key->UnicodeChar = CHAR_NULL;
|
|
} else {
|
|
//
|
|
// valid Key Code starts from 4
|
|
//
|
|
Index = (UINT8) (KeyChar - 4);
|
|
|
|
if (Index >= KEYCODE_MAX_MAKE) {
|
|
return EFI_NOT_READY;
|
|
}
|
|
|
|
//
|
|
// Undefined entries from 0x74 to 0x7E
|
|
//
|
|
if (KeyChar > KEYCODE_MAX_MAKE) {
|
|
Index = Index - 11;
|
|
}
|
|
|
|
Key->ScanCode = KeyConvertionTable[Index][0];
|
|
|
|
if (KbDev->ShiftOn) {
|
|
|
|
Key->UnicodeChar = KeyConvertionTable[Index][2];
|
|
//
|
|
// Need not return associated shift state if a class of printable characters that
|
|
// are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
|
|
//
|
|
if ((KeyConvertionTable[Index][1] != CHAR_NULL) && (KeyConvertionTable[Index][2] != CHAR_NULL) &&
|
|
(KeyConvertionTable[Index][1] != KeyConvertionTable[Index][2])) {
|
|
KbDev->LeftShiftOn = 0;
|
|
KbDev->RightShiftOn = 0;
|
|
}
|
|
|
|
} else {
|
|
|
|
Key->UnicodeChar = KeyConvertionTable[Index][1];
|
|
}
|
|
|
|
if (KbDev->CapsOn) {
|
|
|
|
if (Key->UnicodeChar >= 'a' && Key->UnicodeChar <= 'z') {
|
|
|
|
Key->UnicodeChar = KeyConvertionTable[Index][2];
|
|
|
|
} else if (Key->UnicodeChar >= 'A' && Key->UnicodeChar <= 'Z') {
|
|
|
|
Key->UnicodeChar = KeyConvertionTable[Index][1];
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Translate the CTRL-Alpha characters to their corresponding control value
|
|
// (ctrl-a = 0x0001 through ctrl-Z = 0x001A, ctrl-[, ctrl-\, ctrl-], ctrl-^ and ctrl-_)
|
|
//
|
|
if (KbDev->CtrlOn) {
|
|
for (Index = 0; Index < sizeof (CtrlIgnoreKey); Index++) {
|
|
if (KeyChar == CtrlIgnoreKey[Index]) {
|
|
return EFI_NOT_READY;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (KeyChar >= 0x59 && KeyChar <= 0x63) {
|
|
|
|
if (KbDev->NumLockOn && !KbDev->ShiftOn) {
|
|
|
|
Key->ScanCode = SCAN_NULL;
|
|
|
|
} else {
|
|
|
|
Key->UnicodeChar = 0x00;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Key->UnicodeChar == 0 && Key->ScanCode == SCAN_NULL) {
|
|
if (!KbDev->IsSupportPartialKey) {
|
|
return EFI_NOT_READY;
|
|
}
|
|
}
|
|
//
|
|
// Save Shift/Toggle state
|
|
//
|
|
InitializeKeyState (KbDev, &KbDev->KeyState);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Create the queue.
|
|
|
|
@param Queue Points to the queue.
|
|
@param ItemSize Size of the single item.
|
|
|
|
**/
|
|
VOID
|
|
InitQueue (
|
|
IN OUT I2C_SIMPLE_QUEUE *Queue,
|
|
IN UINTN ItemSize
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
Queue->ItemSize = ItemSize;
|
|
Queue->Head = 0;
|
|
Queue->Tail = 0;
|
|
|
|
if (Queue->Buffer[0] != NULL) {
|
|
FreePool (Queue->Buffer[0]);
|
|
}
|
|
|
|
Queue->Buffer[0] = AllocatePool (sizeof (Queue->Buffer) / sizeof (Queue->Buffer[0]) * ItemSize);
|
|
ASSERT (Queue->Buffer[0] != NULL);
|
|
|
|
for (Index = 1; Index < sizeof (Queue->Buffer) / sizeof (Queue->Buffer[0]); Index++) {
|
|
Queue->Buffer[Index] = ((UINT8 *) Queue->Buffer[Index - 1]) + ItemSize;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Destroy the queue
|
|
|
|
@param Queue Points to the queue.
|
|
**/
|
|
VOID
|
|
DestroyQueue (
|
|
IN OUT I2C_SIMPLE_QUEUE *Queue
|
|
)
|
|
{
|
|
if (Queue->Buffer[0] != NULL) {
|
|
FreePool (Queue->Buffer[0]);
|
|
Queue->Buffer[0] = NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Check whether the queue is empty.
|
|
|
|
@param Queue Points to the queue.
|
|
|
|
@retval TRUE Queue is empty.
|
|
@retval FALSE Queue is not empty.
|
|
|
|
**/
|
|
BOOLEAN
|
|
IsQueueEmpty (
|
|
IN I2C_SIMPLE_QUEUE *Queue
|
|
)
|
|
{
|
|
//
|
|
// Meet FIFO empty condition
|
|
//
|
|
return (BOOLEAN) (Queue->Head == Queue->Tail);
|
|
}
|
|
|
|
/**
|
|
Check whether the queue is full.
|
|
|
|
@param Queue Points to the queue.
|
|
|
|
@retval TRUE Queue is full.
|
|
@retval FALSE Queue is not full.
|
|
|
|
**/
|
|
BOOLEAN
|
|
IsQueueFull (
|
|
IN I2C_SIMPLE_QUEUE *Queue
|
|
)
|
|
{
|
|
return (BOOLEAN) (((Queue->Tail + 1) % (MAX_KEY_ALLOWED + 1)) == Queue->Head);
|
|
}
|
|
|
|
/**
|
|
Enqueue the item to the queue.
|
|
|
|
@param Queue Points to the queue.
|
|
@param Item Points to the item to be enqueued.
|
|
@param ItemSize Size of the item.
|
|
**/
|
|
VOID
|
|
Enqueue (
|
|
IN OUT I2C_SIMPLE_QUEUE *Queue,
|
|
IN VOID *Item,
|
|
IN UINTN ItemSize
|
|
)
|
|
{
|
|
ASSERT (ItemSize == Queue->ItemSize);
|
|
//
|
|
// If keyboard buffer is full, throw the
|
|
// first key out of the keyboard buffer.
|
|
//
|
|
if (IsQueueFull (Queue)) {
|
|
Queue->Head = (Queue->Head + 1) % (MAX_KEY_ALLOWED + 1);
|
|
}
|
|
|
|
CopyMem (Queue->Buffer[Queue->Tail], Item, ItemSize);
|
|
|
|
//
|
|
// Adjust the tail pointer of the FIFO keyboard buffer.
|
|
//
|
|
Queue->Tail = (Queue->Tail + 1) % (MAX_KEY_ALLOWED + 1);
|
|
}
|
|
|
|
/**
|
|
Dequeue a item from the queue.
|
|
|
|
@param Queue Points to the queue.
|
|
@param Item Receives the item.
|
|
@param ItemSize Size of the item.
|
|
|
|
@retval EFI_SUCCESS Item was successfully dequeued.
|
|
@retval EFI_DEVICE_ERROR The queue is empty.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Dequeue (
|
|
IN OUT I2C_SIMPLE_QUEUE *Queue,
|
|
OUT VOID *Item,
|
|
IN UINTN ItemSize
|
|
)
|
|
{
|
|
ASSERT (Queue->ItemSize == ItemSize);
|
|
|
|
if (IsQueueEmpty (Queue)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
CopyMem (Item, Queue->Buffer[Queue->Head], ItemSize);
|
|
|
|
//
|
|
// Adjust the head pointer of the FIFO keyboard buffer.
|
|
//
|
|
Queue->Head = (Queue->Head + 1) % (MAX_KEY_ALLOWED + 1);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Sets monitor keys for SCU (SETUP_HOT_KEY / BOOT_MANAGER_HOT_KEY...)
|
|
|
|
@param KeyboardBuffer Points to the Keyboard Buffer.
|
|
@param Key Key code
|
|
|
|
**/
|
|
VOID
|
|
SetMonitorKey (
|
|
IN I2C_KB_DEV *KbDev,
|
|
IN UINT8 Key
|
|
)
|
|
{
|
|
UINT8 *FilterKeyList;
|
|
UINT8 ModKey;
|
|
UINTN Index;
|
|
UINTN BitIndex;
|
|
UINT16 KbcScanCode;
|
|
//
|
|
// Skip if no MonitorKey installed
|
|
//
|
|
if (EBDA(EBDA_MONITOR_KEY_TABLE) != 0x55 || Key >= 0xe0) return;
|
|
//
|
|
// Convert key code to KBC key code
|
|
//
|
|
KbcScanCode = ConvertKbcScanCode (KbDev, Key);
|
|
if ((KbcScanCode & 0xff) == 0xe0) {
|
|
//
|
|
// Convert double code back to single code
|
|
//
|
|
KbcScanCode >>= 8;
|
|
KbcScanCode |= 0x80;
|
|
}
|
|
//
|
|
// Get FilterKeyList pointer
|
|
//
|
|
FilterKeyList = (UINT8*)(UINTN)((*(UINT16*)&(EBDA(EBDA_MONITOR_KEY_TABLE + 3)) << 4) + *(UINT16*)&(EBDA(EBDA_MONITOR_KEY_TABLE + 1)));
|
|
for (Index = 0, BitIndex = 0; FilterKeyList[Index] != 0; Index += 3, BitIndex ++) {
|
|
if (FilterKeyList[Index] == (UINT8)KbcScanCode) {
|
|
//
|
|
// Also checks Shift/Alt/Ctrl keys
|
|
//
|
|
if ((ModKey = FilterKeyList[Index + 1]) != 0) {
|
|
if (((ModKey & 0x01) && !KbDev->ShiftOn) ||
|
|
((ModKey & 0x02) && !KbDev->AltOn) ||
|
|
((ModKey & 0x04) && !KbDev->CtrlOn)) {
|
|
continue;
|
|
}
|
|
}
|
|
*(UINT32*)&(EBDA(EBDA_MONITOR_KEY_TABLE + 5)) |= (1 << BitIndex);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
Sync the control key status to CSM environment
|
|
|
|
@param KeyboardBuffer Points to the Keyboard Buffer.
|
|
@param Key Key code
|
|
@param Down Special key
|
|
|
|
@retval EFI_SUCCESS Success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
SyncEfiKeyToCsmkey (
|
|
IN I2C_KB_DEV *KbDev,
|
|
IN UINT8 KeyCode,
|
|
IN UINT8 Down
|
|
)
|
|
{
|
|
QUALIFIER_STAT *QualifierStat;
|
|
|
|
QualifierStat = (QUALIFIER_STAT*)(UINTN)(BDA_QUALIFIER_STAT);
|
|
|
|
switch (KeyCode) {
|
|
case 0xe1:
|
|
if (Down) {
|
|
QualifierStat->LeftShift = 1;
|
|
} else {
|
|
QualifierStat->LeftShift = 0;
|
|
}
|
|
break;
|
|
case 0xe5:
|
|
if (Down) {
|
|
QualifierStat->RightShift = 1;
|
|
} else {
|
|
QualifierStat->RightShift = 0;
|
|
}
|
|
break;
|
|
|
|
case 0xe0:
|
|
case 0xe4:
|
|
if (Down) {
|
|
QualifierStat->Ctrl = 1;
|
|
} else {
|
|
QualifierStat->Ctrl = 0;
|
|
}
|
|
break;
|
|
|
|
case 0xe2:
|
|
case 0xe6:
|
|
if (Down) {
|
|
QualifierStat->Alt = 1;
|
|
} else {
|
|
QualifierStat->Alt = 0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Sync the control key status to EFI environment
|
|
|
|
@param KeyboardBuffer Points to the Keyboard Buffer.
|
|
@param Key Key code
|
|
@param Down Special key
|
|
|
|
@retval EFI_SUCCESS Success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
SyncCsmKeyToEfikey (
|
|
IN I2C_KB_DEV *KbDev,
|
|
IN UINT8 KeyCode,
|
|
IN UINT8 Down
|
|
)
|
|
{
|
|
KEY Key;
|
|
|
|
Key.KeyCode = KeyCode;
|
|
Key.Down = Down;
|
|
Enqueue (&KbDev->I2cKeyQueue, &Key, sizeof (Key));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Inserts a key code into keyboard buffer.
|
|
|
|
@param KeyboardBuffer Points to the Keyboard Buffer.
|
|
@param Key Key code
|
|
@param Down Special key
|
|
|
|
@retval EFI_SUCCESS Success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InsertKeyCode (
|
|
IN I2C_KB_DEV *KbDev,
|
|
IN UINT8 KeyCode,
|
|
IN UINT8 Down
|
|
)
|
|
{
|
|
KEY Key;
|
|
//
|
|
// Ignore LED update if it is updating by Int9
|
|
//
|
|
if (KbDev->IsCsmEnabled && PS2_LED_UPDATING && (KeyCode == 0x53 || KeyCode == 0x39 || KeyCode == 0x47)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
Key.KeyCode = KeyCode;
|
|
Key.Down = Down;
|
|
Enqueue (&KbDev->I2cKeyQueue, &Key, sizeof (Key));
|
|
|
|
//
|
|
// Sets monitor keys for SCU (SETUP_HOT_KEY / BOOT_MANAGER_HOT_KEY...)
|
|
//
|
|
if (KbDev->IsCsmEnabled) {
|
|
SetMonitorKey(KbDev, KeyCode);
|
|
if (KeyCode >= 0xe0) {
|
|
SyncEfiKeyToCsmkey (KbDev, KeyCode, Down);
|
|
}
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Timer handler for Repeat Key timer.
|
|
|
|
@param Context Points to the I2C_KB_DEV instance.
|
|
|
|
**/
|
|
VOID
|
|
KeyboardRepeatHandler (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
I2C_KB_DEV *KbDev;
|
|
|
|
|
|
KbDev = (I2C_KB_DEV *) Context;
|
|
//
|
|
// Do nothing when there is no repeat key.
|
|
//
|
|
if (KbDev->RepeatKey != 0) {
|
|
//
|
|
// Inserts one Repeat key into keyboard buffer,
|
|
//
|
|
InsertKeyCode (
|
|
KbDev,
|
|
KbDev->RepeatKey,
|
|
1
|
|
);
|
|
Status = gBS->CreateEvent (
|
|
EVT_TIMER | EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
KeyboardRepeatHandler,
|
|
KbDev,
|
|
&KbDev->RepeatPollingHandle
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return;
|
|
}
|
|
Status = gBS->SetTimer (
|
|
KbDev->RepeatPollingHandle,
|
|
TimerRelative,
|
|
KBD_REPEAT_RATE
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return;
|
|
}
|
|
}
|
|
}
|