diff options
Diffstat (limited to 'Core/EM/PS2CTL/ps2kbd.c')
-rw-r--r-- | Core/EM/PS2CTL/ps2kbd.c | 2888 |
1 files changed, 2888 insertions, 0 deletions
diff --git a/Core/EM/PS2CTL/ps2kbd.c b/Core/EM/PS2CTL/ps2kbd.c new file mode 100644 index 0000000..c74ba48 --- /dev/null +++ b/Core/EM/PS2CTL/ps2kbd.c @@ -0,0 +1,2888 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2009, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/SOURCE/Core/CORE_DXE/PS2CTL/ps2kbd.c 63 11/01/12 6:42a Deepthins $ +// +// $Revision: 63 $ +// +// $Date: 11/01/12 6:42a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Core/CORE_DXE/PS2CTL/ps2kbd.c $ +// +// 63 11/01/12 6:42a Deepthins +// [TAG] EIP101100 +// [Category] Improvement +// [Description] Multi Language is supported in Ps2ctl driver +// [Files] CORE_DXE.sdl, kbc.h, ps2kbd.c and Tokens.c +// +// 62 10/18/12 9:51a Deepthins +// [TAG] EIP95111 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] PS2 mouse is not working in setup. +// [RootCause] In stream mode data reporting is disabled by default. The +// mouse will not actually issue any movement data packets until it +// receives the "Enable Data Reporting" (0xF4) command. So even when the +// DETECT_PS2_KEYBOARD and DETECT_PS2_MOUSE token is disabled we need to +// send command 0xf4 to Enable Data Reporting. +// +// [Solution] In MouseReset function, Set sampleRate ,Resolution and +// Enable streaming. +// [Files] mouse.c and ps2kbd.c +// +// 61 10/18/12 9:03a Deepthins +// [TAG] EIP70313 +// [Category] Improvement +// [Description] Used CheckIssueLEDCmd in function LEDsOnOff instead of +// OutToKb(Kbd, 0xED) +// [Files] kbc.c, ps2kbd.c and kbc.h +// +// 60 7/13/12 7:21a Rajeshms +// [TAG] EIP57005 +// [Category] Improvement +// [Description] Need to clear Struck Keys in StartKeyboard() & +// KbdReset() for some kinds of Notebook KBC. Implemented this feature +// based on CLEAR_PENDING_KEYS_IN_PS2 token. +// [Files] Ps2Kbd.c, CORE_DXE.sdl +// +// 59 7/09/12 3:13a Rajeshms +// [TAG] EIP94186 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] side effect after adding the solution of can not catch F8 +// key event on Keyboard - PS2 KB generic implement (EIP6986) +// [RootCause] BDA is Checked even when CSM is not launched. So even +// though keys are not pressed Junk Keys are reproted +// [Solution] Checked whether CSm is launched based of Presence of +// Legacy BIOS Protocol. +// [Files] Ps2Kbd.c +// +// 58 5/31/12 7:56a Srilathasc +// [TAG] EIP89947 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Ps2Keyboard doesn't work after reconnect -r command from +// Shell +// [RootCause] The keyboard driver's stop function does not uninstall +// AMIEFIKEYCODE Protocol. +// [Solution] AMIEFIKEYCODE Protocol uninstalled in stop function. +// [Files] ps2kbd.c +// +// 57 5/24/12 6:49a Nimishsv +// [TAG] EIP90180 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Ps2driver doesn't return the proper ShiftState if the valid +// Unicode char's are pressed. +// [RootCause] Shift State was not cleared for printable characters +// [Solution] Shift state is cleared for printable characters +// [Files] ps2kbd.c +// +// 56 5/02/12 2:29a Deepthins +// [TAG] EIP63116 +// [Category] Improvement +// [Description] PS/2 Keyboard/Mouse IRQ mode generic support +// [Files] Ps2kbd.c, Mouse.c, kbc.h, kbc.c +// +// 55 4/30/12 2:22a Rajeshms +// [TAG] EIP86986 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] Can not detect F8 key on PS2 Keyboard while booting to EFI +// aware OS. +// [RootCause] Make code of F8 key (0x42) is taken by int09h and EFI +// aware OS calls only one ReadKeyStroke() for any key catch, Now PS2 +// driver will take Break Code of F8 key(0xC2) and returns EFI_NOT_READY. +// [Solution] Multiple Read from PS2 keyboard is implemented and read +// exits if any valid key is detected. Also, the BDA keyboard buffer is +// checked for any missed key in EFI. +// [Files] ps2kbd.c, kbc.c, CORE_DXE.sdl +// +// 54 4/24/12 2:19a Deepthins +// [TAG] EIP85747 +// [Category] Improvement +// [Description] USB-ReadKeyStrokeEx is returning EFI_SUCCESS with +// KEY_STATE_EXPOSED for Caps, Num and Scroll Lock Key's. +// KEY_STATE_EXPOSED only for the ShiftState Key's and not for togglestate +// key's. +// [Files] Efiusbkb.c, ps2kbd.c and kbc.h +// +// 53 4/23/12 8:52a Jittenkumarp +// [TAG] EIP84902 +// [Category] Bug Fix +// [Symptom] Enter key is not working in PS2 key board +// [RootCause] Filling wrong EFI KEY value in +// ScancodeToEfi_table.Therefor Enter key is interpreted wrongly as +// EfiKeyC12. +// [Solution] Replaced EfiKeyC12 value with EfiKeyEnter value to +// Interpreted Enter key properly. +// +// [Files] ps2kbd.c +// +// 52 4/10/12 2:35a Rameshr +// [TAG] EIP87058 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Not able to recognise Pause Key Click using ReadKeyStroke +// [RootCause] Pause Key detection should be done always and only the +// pause key action should be controlled by PAUSEKEY_SUPPORT SDL token +// [Solution] SDL token checking removed for the Pause Key detection +// [Files] Ps2kbd.c +// +// 51 2/01/12 2:01a Deepthins +// [TAG] EIP63116 +// [Category] New Feature +// [Description] PS/2 Keyboard/Mouse IRQ mode generic support +// [Files] Token.c, Ps2main.c, Ps2kbd.c, Mouse.c, kbc.h, kbc.c, +// CORE_DXE.sdl +// +// 50 9/22/11 7:39a Rameshr +// [TAG] EIP63054 +// [Category] New Feature +// [Description] 0000790: Add warning to ReadKeyStrokeEx for partial key +// press +// [Files] KeyboardCommonDefinitions.h, In.c, Kbc.h, Ps2Kbd.c, +// Efiusbkb.c, efiusbkb.h +// +// 49 6/21/11 12:24p Davidd +// [TAG] EIP55334 +// [Category] New Feature +// [Description] Add optional code to clear keyboard buffer at +// ReadyToBoot in PS2KB driver +// [Files] core_dxe.sdl +// ps2kbd.c +// +// 48 4/27/11 4:34a Lavanyap +// [TAG] - EIP49407 +// [Category] - IMPROVEMENT +// [Description] - Move the Ps2 driver SDL tokens from Core Source to Core +// Bin,So that we don't need to add Core source for changing the Ps2 +// driver SDL tokens. +// [Files] - Ps2Ctl.sdl, ps2kbd.c, ps2main.c, ps2ctl.h, kbc.c, mouse.c, +// hotkey.c, CORE_DXE.sdl, Tokens.c +// +// 47 1/05/11 12:58a Rameshr +// [TAG] EIPEIP 35306 +// [Category] Improvement +// [Description] Report the Ps2 Controller and Device Error Codes. +// [Files] AmiStatuscodes.h, Kbc.c, Kbc.h,Ps2ctl.sdl, ps2kbd.c, +// ps2main.c ,Statuscode.h +// +// 46 8/23/10 4:21a Rameshr +// Bug Fix : EIP 40838 +// Symptoms: KBC.C build failed in DetectPS2Keyboard() if +// DETECT_PS2_KEYBOARD=0 & PS2MOUSE_SUPPORT=0 +// Files Modified: Efismplpp.c, Kbc.c, Kbc.h, Mouse.c PS2ctl.cif, +// Ps2ctl.sdl, Ps2Kbd.c, Ps2Mouse.c +// Details: +// 1) Added Detect_PS2_Mouse sdl token and modified the code. +// 2) INSTALL_KEYBOARD_MOUSE_ALWAYS sdl token added. +// 1 - Install the Keyboard- SimpleTextIn, Mouse - AbsPointer Always, +// 0 - Install the Keyboard- SimpleTextIn, Mouse - AbsPointer only if +// the device is present at the time of detection. +// This is for Ps2Keyboard Hot plug support in EFI +// 3) Code clean up in mouse.c EfiSmplpp.c ,ps2mouse.h +// 4) Unused file automaton.h removed. +// +// 45 8/19/10 8:08a Fredericko +// [TAG] EIP40711 +// [Category] BUG FIX +// [Severity] Normal +// [Symptom] Keyboard sometimes does not work in DOS if KBD is being +// pressed hapazardly during post. +// [RootCause] After reprogramming of Interrupt Controller base; if +// keyboard is being pressed hapardzadly, KBD IRQ could be missed and KBD +// might not work in DOS. +// [Solution] Follow proper procedures to Reset KBD controller after +// reprogramming the base of the Interrrupt controller +// [Files] Thunk.c in CSM +// +// 44 7/20/10 4:31a Rameshr +// Corrected the FreePool call in UnRegisterKeyNotify function +// +// 43 5/14/10 11:07a Olegi +// Added FreePool call in UnRegisterKeyNotify function. +// +// 42 5/10/10 1:50a Rameshr +// Issue:Shift Key issues in RegsiterkeyNotify function +// Solution: ShiftKeyState and KeyToggleState verified for +// RegisterKeyNotify callback function. +// EIP 38211 +// +// 41 5/10/10 1:41a Rameshr +// PrintKey/SysRq key, Menu Key, Left Logo and Right Logo Key support +// added in Ps2 Keyboard driver +// EIP 38212 +// +// 40 3/15/10 2:40p Krishnakumarg +// Pressing DEL key continously intermittently or sticking does not enter +// setup. EIP: 34615 +// +// 39 1/29/10 2:11p Krishnakumarg +// When user press "Ctrl+Break" key, the Scr Lk LED will turn on - #EIP +// 34317 +// +// 38 8/13/09 3:02p Rameshr +// When item "num-lock status" set off, Num-lock will keep open until in +// DOS. +// EIP:21757 +// +// 37 7/01/09 12:32p Olegi +// Source is corrected according to the coding standard: function headers, +// copyright messages are updated. +// +// 36 6/26/09 4:03p Rameshr +// Symptom: Shift Key Status get set when DELL key pressed more +// frequently. +// Reason: DELL key scan code E0 taken by Reset Function and Int9. This +// has been handled by modifiying Reset function and using BDA. +// EIP:22611 +// +// 35 3/30/09 10:28a Pats +// Issue: EIP 19547 - Pause key support needed in Aptio +// Solution: Function HandleKBDData modified to pass EFI_KEY vaule of +// pause key on rather than rejecting it. +// +// 34 1/23/09 9:54a Rameshr +// Symptom:SCT failure in ReadKeystrokeEx function. +// Solution: Validated the Input parameters Keydata for the +// ReadKeystrokeEx Function. +// Eip: 19039 +// +// 33 11/17/08 10:04a Rameshraju +// Problem:SCT failure on RegisterKeyNotify, SetState and +// UnregisterKeyNotify. +// Fix : Validated the input parameters for RegisterKeyNotify, SetState +// and UnregisterKeyNotify. +// EIP:17578 +// +// 32 10/08/08 4:56p Olegi +// Implemented the Register/Unregister key notofocation function in +// SimpletextinEx protocol. +// +// 31 8/15/08 10:57a Olegi +// Correction in KbdReset function. +// +// 30 8/13/08 9:54a Olegi +// Change in KbdReset function, EIP#8330. +// +// 29 6/05/08 4:26p Olegi +// Added support for extended keys (EIP#13630) +// +// 28 6/05/08 3:19p Olegi +// Bugfix in processing the '5' key on a keypad when NumLock is off: +// nothing should be reported. +// +// 27 5/09/08 10:11a Olegi +// ProcessByte function modified +// +// 26 4/22/08 4:31p Felixp +// Additional progress codes added +// +// 25 4/21/08 5:49p Olegi +// +// 24 4/09/08 10:19a Olegi +// Changed the key attributes (modifiers and shift state) reporting. +// +// 23 10/25/07 4:48p Olegi +// +// 22 10/24/07 6:00p Olegi +// +// 21 10/23/07 4:04p Olegi +// Lock keys maintenance modifications. +// +// 20 9/18/07 11:51a Olegi +// +// 19 9/18/07 11:47a Olegi +// +// 18 9/17/07 3:56p Olegi +// +// 17 9/10/07 1:14p Olegi +// +// 16 9/07/07 4:34p Olegi +// EFI_KEY code implementation. +// +// 15 8/31/07 2:44p Olegi +// Added SimpleTextInEx definitions. +// +// 14 6/22/07 2:14p Pats +// Fixed problem of right Ctrl and Alt keys "sticking" and causing reset +// when Ctrl-Alt-Del pressed sequentially rather than all at once. +// +// 13 4/19/07 1:00p Felixp +// File reformatted to comply with AMI coding standards +// +// 11 4/17/07 10:34a Pats +// Modified to comply with coding standard. No code changes. +// +// 10 5/05/06 5:23p Ambikas +// +// 9 3/13/06 2:38a Felixp +// +// 8 1/09/06 11:38a Felixp +// +// 6 12/22/05 10:21a Srinin +// Optimized KBD Enable/Disable call +// +// 5 10/27/05 1:04p Srinin +// In KbdReset, KBD driver buffer is cleared. +// +// 4 10/11/05 4:09p Srinin +// KBD reset function implemented and other minor changes done. +// +// 3 8/30/05 1:08p Srinin +// KeyBoard buffer and handling of keys which send 4 scan codes modified. +// +// 2 3/04/05 3:55p Olegi +// Shift states corrected for non-letter keys. +// +// 1 2/01/05 1:10a Felixp +// +// 3 1/18/05 3:22p Felixp +// PrintDebugMessage renamed to Trace +// +// 2 12/16/04 2:28p Olegi +// Fix: Caps-Lock made irrelevant to the upper row of keys. +// +// 1 10/28/04 10:19a Olegi +// +// 10 9/30/04 8:13a Olegi +// HotKeys added. +// +//********************************************************************** + +//<AMI_FHDR_START> +//---------------------------------------------------------------------- +// +// Name: ps2kbd.c +// +// Description: PS/2 keyboard support routines +// +//---------------------------------------------------------------------- +//<AMI_FHDR_END> + +//---------------------------------------------------------------------- + +#include "ps2ctl.h" +#include "kbc.h" + + +#define E0_STATUS_IN_BDA BIT1 +#define E1_STATUS_IN_BDA BIT0 +#define LEGACY_8259_CONTROL_REGISTER_MASTER 0x20 + +#if CHECK_BDA_KEYBOARD_BUFFER +#if CSM_SUPPORT +#include <Protocol/LegacyBios.h> +UINT16 BdaSeg = 0x400; +UINT16 *BdaKbdHead = (UINT16 *)0x41A; +UINT16 *BdaKbdTail = (UINT16 *)0x41C; +EFI_LEGACY_BIOS_PROTOCOL *gLegacy=NULL; +BOOLEAN gLegacyBiosProtocolFound = FALSE; +#endif +#endif + +/* +Table 2. PS/2 Scan Codes Supported in Windows 2000/Windows XP and Windows Me + +HID usage/ key name Set 1Make Set 1Break Set 2Make Set 2Break + Scan Next Track E0 19 E0 99 E0 4D E0 F0 4D + Scan Previous Track E0 10 E0 90 E0 15 E0 F0 15 + Stop E0 24 E0 A4 E0 3B E0 F0 3B + Play/ Pause E0 22 E0 A2 E0 34 E0 F0 34 + Mute E0 20 E0 A0 E0 23 E0 F0 23 + Volume Increment E0 30 E0 B0 E0 32 E0 F0 32 + Volume Decrement E0 2E E0 AE E0 21 E0 F0 21 + AL Email Reader E0 6C E0 EC E0 48 E0 F0 48 + AC Search E0 65 E0 E5 E0 10 E0 F0 10 + AC Home E0 32 E0 B2 E0 3A E0 F0 3A + AC Back E0 6A E0 EA E0 38 E0 F0 38 + AC Forward E0 69 E0 E9 E0 30 E0 F0 30 + AC Stop E0 68 E0 E8 E0 28 E0 F0 28 + AC Refresh E0 67 E0 E7 E0 20 E0 F0 20 + AC Bookmarks E0 66 E0 E6 E0 18 E0 F0 18 + AL Calculator* E0 21 E0 A1 E0 2B E0 F0 2B + AL Local Browser* E0 6B E0 EB E0 40 E0 F0 40 + AL Consumer Control Configuration* + E0 6D E0 ED E0 50 E0 F0 50 +*/ +static UINT8 E0EnhancedKeys[] = {0x20,0x30,0x2E}; // only mute, volume-up, down +BOOLEAN IsEnhancedKey( UINT8 data) +{ + UINTN i; + + data &= 0x7F; // reset MSB + for ( i = 0; i < sizeof(E0EnhancedKeys); i++) { + if ( data == E0EnhancedKeys[i]) { + return TRUE; + } + } + return FALSE; +} + +//---------------------------------------------------------------------- + +extern BOOLEAN InsideGetMouseData; +extern BOOLEAN KBDEnableState; +extern UINT8 LedsAtStartup; +extern BOOLEAN InsideMouseReset; +BOOLEAN InsideKbdReadKey = FALSE; +BOOLEAN InsideOnWaitingOnKey = FALSE; +BOOLEAN InsideKbdReset = FALSE; +extern BOOLEAN InsidePS2DataDispatcher; +static EFI_GUID gAmiMultiLangSupportGuid = AMI_MULTI_LANG_SUPPORT_PROTOCOL_GUID; +AMI_MULTI_LANG_SUPPORT_PROTOCOL *gPs2MultiLangSupportProtocol=NULL; + +EFI_STATUS KbdReset( + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + BOOLEAN ExtendedVerification); + +EFI_STATUS KbdReadKey( + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + EFI_INPUT_KEY *key); + +EFI_STATUS KbdResetEx( + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + BOOLEAN ExtendedVerification ); + +EFI_STATUS KbdReadKeyEx ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + OUT EFI_KEY_DATA *KeyData +); + +EFI_STATUS KbdReadEfiKeyEx ( + IN AMI_EFIKEYCODE_PROTOCOL *This, + OUT AMI_EFI_KEY_DATA *KeyData +); + +EFI_STATUS SetState ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_TOGGLE_STATE *KeyToggleState +); + +EFI_STATUS RegisterKeyNotify( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_DATA *KeyData, + IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, + OUT EFI_HANDLE *NotifyHandle +); + +EFI_STATUS UnRegisterKeyNotify( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_HANDLE NotificationHandle +); + +void OnWaitingOnKey(EFI_EVENT Event, void *Context); + +#if CLEAR_PENDING_KEYS_IN_PS2 +VOID Ps2KbdReset ( VOID ); +VOID ClearOBF ( VOID ); +#endif + + +typedef struct _KEY_WAITING_RECORD{ + DLINK Link; + EFI_KEY_DATA Context; + EFI_KEY_NOTIFY_FUNCTION Callback; +} KEY_WAITING_RECORD; + +DLIST mPs2KeyboardData; +KEY_WAITING_RECORD *mPs2KeyboardRecord; +EFI_EVENT Ps2KeyEvent; +#define KEY_POLLING_INTERVAL 500000 +VOID StartPollingKey(EFI_EVENT Event, VOID *Context); + + +extern STATEMACHINEPROC DrivePS2KbdMachine; +void ReadAndProcessKey(void*); +void ProcessByte(KEYBOARD *Kbd, UINT8 data, BOOLEAN fourth_byte); +void ResetStateMachine(KEYBOARD *Kbd); +void LEDsOnOff(KEYBOARD* Kbd); + +static UINT8 E0SeqA[4] = {0x2A, 0xAA, 0x46, 0xB6}; +static UINT8 E0SeqB[11] = {0xD3, 0xD0, 0xCF, 0xC7, 0xD2, 0xCB, 0xD1, 0xC9, 0xCD, 0xC8, 0xB5}; +static UINT8 E1Seq[5] = {0x1D, 0x45, 0xE1, 0x9D, 0xC5}; + +static UINT8 code_table[59] = { // Lower case keys +0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 8, +9, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 13, +0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'','`', +0,'\\','z','x','c','v','b','n','m',',','.','/',0, +'*', 0, ' ', 0}; +static UINT8 Code_Table[59] = { // Upper case keys +0, 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 8, +9, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 13, +0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', +0, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, +'*', 0, ' ',0}; + +static UINT8 ScancodeToEfi_table[59] = { // EFI keys (UEFI Spec 2.1, Ch.28.4, Pg.1325) +0, EfiKeyEsc, EfiKeyE1, EfiKeyE2, EfiKeyE3,EfiKeyE4, EfiKeyE5, EfiKeyE6, +EfiKeyE7, EfiKeyE8, EfiKeyE9, EfiKeyE10, EfiKeyE11, EfiKeyE12, EfiKeyBackSpace, +EfiKeyTab, EfiKeyD1, EfiKeyD2, EfiKeyD3, EfiKeyD4, EfiKeyD5, EfiKeyD6, EfiKeyD7, +EfiKeyD8, EfiKeyD9, EfiKeyD10, EfiKeyD11, EfiKeyD12, EfiKeyEnter, +EfiKeyCapsLock, EfiKeyC1, EfiKeyC2, EfiKeyC3, EfiKeyC4, EfiKeyC5, EfiKeyC6, EfiKeyC7, +EfiKeyC8, EfiKeyC9, EfiKeyC10, EfiKeyC11, EfiKeyE0, +EfiKeyLShift, EfiKeyD13, EfiKeyB1, EfiKeyB2, EfiKeyB3, EfiKeyB4, EfiKeyB5, EfiKeyB6, +EfiKeyB7, EfiKeyB8, EfiKeyB9, EfiKeyB10, EfiKeyRshift, +0, 0, EfiKeySpaceBar, 0}; + +typedef struct { + UINT8 makecode; + UINT8 efi_scancode; + UINT8 efi_key; +}EFI_EXTKEY; + +static EFI_EXTKEY ScanCode_Table[] = { + 0x3B, EFI_SCAN_F1, EfiKeyF1, + 0x3C, EFI_SCAN_F2, EfiKeyF2, + 0x3D, EFI_SCAN_F3, EfiKeyF3, + 0x3E, EFI_SCAN_F4, EfiKeyF4, + 0x3F, EFI_SCAN_F5, EfiKeyF5, + 0x40, EFI_SCAN_F6, EfiKeyF6, + 0x41, EFI_SCAN_F7, EfiKeyF7, + 0x42, EFI_SCAN_F8, EfiKeyF8, + 0x43, EFI_SCAN_F9, EfiKeyF9, + 0x44, EFI_SCAN_F10, EfiKeyF10, + 0x57, EFI_SCAN_F11, EfiKeyF11, + 0x58, EFI_SCAN_F12, EfiKeyF12, + 0x47, EFI_SCAN_HOME, EfiKeyHome, + 0x48, EFI_SCAN_UP, EfiKeyUpArrow, + 0x49, EFI_SCAN_PGUP, EfiKeyPgUp, + 0x4B, EFI_SCAN_LEFT, EfiKeyLeftArrow, + 0x4D, EFI_SCAN_RIGHT, EfiKeyRightArrow, + 0x4F, EFI_SCAN_END, EfiKeyEnd, + 0x50, EFI_SCAN_DN, EfiKeyDownArrow, + 0x51, EFI_SCAN_PGDN, EfiKeyPgDn, + 0x52, EFI_SCAN_INS, EfiKeyIns, + 0x53, EFI_SCAN_DEL, EfiKeyDel, + 0xFF, 0xFF, 0xFF // End of table +}; + +static UINT8 KeyPad_Table[] = { + '7','8','9','-','4','5','6','+','1','2','3','0','.' +}; + +static UINT8 KeyPadEfiCode_Table[] = { + EfiKeySeven, EfiKeyEight, EfiKeyNine, EfiKeyMinus, + EfiKeyFour, EfiKeyFive, EfiKeySix, EfiKeyPlus, + EfiKeyOne, EfiKeyTwo, EfiKeyThree, + EfiKeyZero, EfiKeyPeriod +}; + +KEYBOARD gKbd; +KEYBOARD_IRQ_STORE gKeyboardIrqBuffer; +EFI_CPU_ARCH_PROTOCOL *gCpuArch; +EFI_LEGACY_8259_PROTOCOL *mLegacy8259; +BOOLEAN gKeyboardIrqInstall=FALSE; +BOOLEAN gKeyboardDriverStart=FALSE; + +extern BOOLEAN Ps2MouseDetected; +extern BOOLEAN KbdIrqSupport; +extern BOOLEAN KbRdBeforeInstall; +extern BOOLEAN InsideGetMouseData; +extern BOOLEAN KBDEnableState; + +#if CLEAR_PS2KB_BUFFER_AT_READYTOBOOT +EFI_EVENT gClearKbBufferEvent; + +// <AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: ClearKbBuffer +// +// Description: +// This function clear PS2 KB buffer +// +// Input: +// IN EFI_EVENT Event - signalled event +// IN VOID *Context - pointer to event context +// +// Output: +// VOID +// +// Modified: +// +// Referrals: +// +// Notes: +// +//-------------------------------------------------------------------------- +// <AMI_PHDR_END> + +EFI_STATUS +ClearKbBuffer( + IN EFI_EVENT Event, + IN VOID *Context +) +{ + KEYBOARD *Kbd = &gKbd; + UINT8 *BdaKbHead = (UINT8*)((UINTN) 0x41a); + UINT8 *BdaKbTail = (UINT8*)((UINTN) 0x41c); + UINT8 *BdaKbBuffer = (UINT8*)((UINTN) 0x41e); + + Kbd->pBufHead = Kbd->pBufStart; + Kbd->pBufTail = Kbd->pBufStart; + + pBS->SetMem(Kbd->pBufStart, BUFFER_SIZE * sizeof (AMI_EFI_KEY_DATA), 0); + + // Empty KB Buffer in BDA + pBS->SetMem(BdaKbBuffer, 32, 0); + *BdaKbTail = *BdaKbHead; + + pBS->CloseEvent(Event); + + return EFI_SUCCESS; +} +#endif + + +// <AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: UpdateVariabletoCheckBda +// +// Description: +// This function updates variable Legacy BIOS Protocol found,to check BDA +// for pending keys in EFI. +// +// Input: +// IN EFI_EVENT Event - signalled event +// IN VOID *Context - pointer to event context +// +// Output: +// VOID +// +// Modified: +// +// Referrals: +// +// Notes: +// +//-------------------------------------------------------------------------- +// <AMI_PHDR_END> +#if CHECK_BDA_KEYBOARD_BUFFER +#if CSM_SUPPORT +VOID UpdateVariabletoCheckBda( + IN EFI_EVENT Event, + IN VOID *Context +) +{ + EFI_STATUS Status; + // + // Update Variable to check BDA if Legacy Bios Protocol Found. + // + Status = pBS->LocateProtocol(&gEfiLegacyBiosProtocolGuid, NULL, &gLegacy); + if (!EFI_ERROR(Status)) { + gLegacyBiosProtocolFound = TRUE; + } +} +#endif +#endif + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: StartKeyboard +// +// Description: This routine is called from Driver Binding Start function, +// it starts the keyboard +// +// Paremeters: EFI_DRIVER_BINDING_PROTOCOL *This - A pointer to the +// EFI_DRIVER_BINDING_PROTOCOL instance +// EFI_HANDLE Controller - Handle for this controller +// +// Output: EFI_STATUS - status of the operation +// +// Referrals: gEfiSimpleTextInProtocolGuid +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS StartKeyboard( + EFI_DRIVER_BINDING_PROTOCOL *This, + EFI_HANDLE Controller) +{ + + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *pDummyDevPath; + KEYBOARD* Kbd = &gKbd; + KEYBOARD_IRQ_STORE* KbIrqBuffer = &gKeyboardIrqBuffer; + UINT8 Index=0; +#if CHECK_BDA_KEYBOARD_BUFFER +#if CSM_SUPPORT + EFI_EVENT Event; + VOID *pRegistration; +#endif +#endif + + if (EFI_ERROR(gSysTable->BootServices->OpenProtocol( + Controller, + &gEfiDevicePathProtocolGuid, + &pDummyDevPath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER))) { + return EFI_INVALID_PARAMETER; + } + +#if CLEAR_PENDING_KEYS_IN_PS2 + // + // Reset the keyboard and Clear Pending Keys as some + // NoteBook Kbc needs reset and Clearing the OBF. + // + Ps2KbdReset(); + ClearOBF (); +#endif + + DetectPS2KeyboardAndMouse(); + + if (EFI_ERROR(DetectPS2Keyboard())) { + gSysTable->BootServices->CloseProtocol( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller); + + return EFI_DEVICE_ERROR; + } + + // + // Initialize keyboard interface functions + // + (Kbd->iSimpleIn).Reset = KbdReset; + (Kbd->iSimpleIn).ReadKeyStroke = KbdReadKey; + + (Kbd->iSimpleInEx).Reset = KbdResetEx; + (Kbd->iSimpleInEx).ReadKeyStrokeEx = KbdReadKeyEx; + (Kbd->iSimpleInEx).SetState = SetState; + (Kbd->iSimpleInEx).RegisterKeyNotify = RegisterKeyNotify; + (Kbd->iSimpleInEx).UnregisterKeyNotify = UnRegisterKeyNotify; + + (Kbd->iKeycodeInEx).Reset = KbdResetEx; + (Kbd->iKeycodeInEx).ReadEfikey = KbdReadEfiKeyEx; + (Kbd->iKeycodeInEx).SetState = SetState; + (Kbd->iKeycodeInEx).RegisterKeyNotify = RegisterKeyNotify; + (Kbd->iKeycodeInEx).UnregisterKeyNotify = UnRegisterKeyNotify; + + gSysTable->BootServices->CreateEvent( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + OnWaitingOnKey, + Kbd, + &Kbd->iSimpleIn.WaitForKey); + + gSysTable->BootServices->CreateEvent( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + OnWaitingOnKey, + Kbd, + &Kbd->iSimpleInEx.WaitForKeyEx); + + gSysTable->BootServices->CreateEvent( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + OnWaitingOnKey, + Kbd, + &Kbd->iKeycodeInEx.WaitForKeyEx); + + // + // Install protocol interfaces for the keyboard device. + // + Status = gSysTable->BootServices->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiSimpleTextInProtocolGuid, &Kbd->iSimpleIn, + &gEfiSimpleTextInExProtocolGuid, &Kbd->iSimpleInEx, + &gAmiEfiKeycodeProtocolGuid, &Kbd->iKeycodeInEx, + NULL + ); + + if (EFI_ERROR(Status)) { + gSysTable->BootServices->CloseProtocol( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller); + + gSysTable->BootServices->CloseEvent(Kbd->iSimpleIn.WaitForKey); + gSysTable->BootServices->CloseEvent(Kbd->iSimpleInEx.WaitForKeyEx); + gSysTable->BootServices->CloseEvent(Kbd->iKeycodeInEx.WaitForKeyEx); + } + + if (!(EFI_ERROR(Status))) { + // + // Initialize keyboard device + // + Kbd->KeyIsReady = FALSE; + Kbd->ScannerState = KBST_READY; + Kbd->KeyData.KeyState.KeyToggleState = LedsAtStartup; + Kbd->KeyData.KeyState.KeyToggleState |= TOGGLE_STATE_VALID; + Kbd->KeyData.KeyState.KeyShiftState = SHIFT_STATE_VALID; + + Kbd->pBufStart = MallocZ(BUFFER_SIZE * sizeof (AMI_EFI_KEY_DATA)); + if(!Kbd->pBufStart) return EFI_OUT_OF_RESOURCES; + Kbd->pBufHead = Kbd->pBufStart; + Kbd->pBufTail = Kbd->pBufStart; + Kbd->pBufEnd = Kbd->pBufStart + BUFFER_SIZE; + + DrivePS2KbdMachine = ReadAndProcessKey; + + // + // Set LED's + // + LEDsOnOff(Kbd); + + InitHotKeys(Controller); // Produce HotKeys protocol + +// for (Count = 3; Count; Count--) { +// if(IssueCommand(0xF4) == 0xFA) break; // Clear the KBD buffer +// } + + Kbd->LEDCommandState = 0; + +#if CLEAR_PS2KB_BUFFER_AT_READYTOBOOT + gSysTable->BootServices->CreateEvent( + EFI_EVENT_SIGNAL_READY_TO_BOOT, + TPL_NOTIFY, + ClearKbBuffer, + NULL, + &gClearKbBufferEvent); +#endif + +#if CHECK_BDA_KEYBOARD_BUFFER +#if CSM_SUPPORT + RegisterProtocolCallback( + &gEfiLegacyBiosProtocolGuid, UpdateVariabletoCheckBda, + NULL, &Event,&pRegistration + ); + + // + // Check whether Legacy BIOS Protocol Installed. + // + UpdateVariabletoCheckBda(NULL,NULL); + +#endif +#endif + } + + DListInit(&mPs2KeyboardData); + + Status = pBS->CreateEvent( + EVT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + TPL_NOTIFY, + StartPollingKey, + Kbd, + &Ps2KeyEvent + ); + + // + // if before keyboard driver starts data is available in buffer + // it will be collected in local buffer in KeyboardInterrupt?Handler + // only if KBD_READ_BEFORE_INSTALL = 1, the avalable data in local + // buffer is processed. + // + if(KbRdBeforeInstall){ + for (Index=0;Index < KbIrqBuffer->KbdIndex; Index++){ + ProcessKBDData(Kbd, KbIrqBuffer->KbdBuffer[Index]); + } + } + gKeyboardDriverStart = TRUE; + // + // Re enable keyboard irq as it was previously disabled. + // if KBD_READ_BEFORE_INSTALL = 0 then initialize keyboard irq here + // + if(KbdIrqSupport){ + if(KbRdBeforeInstall){ + gKeyboardIrqInstall = TRUE; + // + // Now enable the interrupt + // + mLegacy8259->EnableIrq(mLegacy8259, SYSTEM_KEYBOARD_IRQ, FALSE); + } + else { + InitKeyboardIrq(); + } + } + // + // Enable the Keyboard and Keyboard Interrupt. We must initilize this + // one for the Keyboard to work on Legacy mode. And also Legacy mode AMIUSB driver + // expects Keyboard and Interrupt should be enabled once Port 60/64 is present. + // + Write8042CommandByte(0x65); + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: StopKeyboard +// +// Description: This routine is called from Driver Binding Stop function. +// +// Paremeters: EFI_DRIVER_BINDING_PROTOCOL *This - A pointer to the +// EFI_DRIVER_BINDING_PROTOCOL instance +// EFI_HANDLE Controller - Handle for this controller +// +// Output: EFI_STATUS - status of the operation +// +// Referrals: gEfiSimpleTextInProtocolGuid +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS StopKeyboard( + EFI_DRIVER_BINDING_PROTOCOL *This, + EFI_HANDLE Controller) +{ + KEYBOARD* Kbd = &gKbd; + EFI_STATUS Status; + + // + // Uninstall protocol interfaces from the keyboard device. + // + Status = gSysTable->BootServices->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiSimpleTextInProtocolGuid, &Kbd->iSimpleIn, + &gEfiSimpleTextInExProtocolGuid, &Kbd->iSimpleInEx, + &gAmiEfiKeycodeProtocolGuid, &Kbd->iKeycodeInEx, + NULL + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Close protocols that is open during Start + // + Status = gSysTable->BootServices->CloseProtocol( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller); + + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Kill wait event + // + gSysTable->BootServices->CloseEvent(Kbd->iSimpleIn.WaitForKey); + gSysTable->BootServices->CloseEvent(Kbd->iSimpleInEx.WaitForKeyEx); + gSysTable->BootServices->CloseEvent(Kbd->iKeycodeInEx.WaitForKeyEx); + gSysTable->BootServices->CloseEvent(Ps2KeyEvent); + + pBS->FreePool(Kbd->pBufStart); + + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: KbdReset +// +// Description: Resets the input device hardware. This routine is a part +// of SimpleTextIn protocol implementation. +// +// Parameters: EFI_SIMPLE_TEXT_INPUT_PROTOCOL +// *This - A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL +// instance. +// BOOLEAN +// ExtendedVerification - Indicates that the driver may +// perform a more exhaustive verification operation of the +// device during reset. +// +// Output: EFI_SUCCESS The device was reset. +// EFI_DEVICE_ERROR The device is not functioning correctly +// and could not be reset. +// +// Modified: KBDEnableState +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS KbdReset( + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + BOOLEAN ExtendedVerification ) +{ + UINT8 bCount, bData, bBCount; + KEYBOARD* Kbd = &gKbd; + EFI_STATUS Status; + + // + // Check for keyboard IRQ support + // + if(KbdIrqSupport && gKeyboardIrqInstall) { + // + // Now Disable the interrupt + // + mLegacy8259->DisableIrq(mLegacy8259, SYSTEM_KEYBOARD_IRQ); + } + InsideKbdReset = TRUE; + Kbd->KeyIsReady = FALSE; + Kbd->ScannerState = KBST_READY; + + Kbd->pBufHead = Kbd->pBufStart; + Kbd->pBufTail = Kbd->pBufStart; + + pBS->SetMem(Kbd->pBufStart, BUFFER_SIZE * sizeof (AMI_EFI_KEY_DATA), 0); + + DisableKeyboard(); + PROGRESS_CODE(DXE_KEYBOARD_RESET); + + for (bBCount = 0; bBCount < 4; bBCount++) { + for (bCount = 0; bCount < 3; bCount++) { + Status = ReadDevice(KBD_DISABLE_SCANNING, &bData, KB_ACK_COM); + if (!EFI_ERROR(Status)) { + break; + } + } + if (EFI_ERROR(Status)) { + continue; + } + for (bCount = 0; bCount < 3; bCount++) { + Status = ReadDevice(KBD_ENABLE_SCANNING, &bData, KB_ACK_COM); + if (!EFI_ERROR(Status)) { + break; + } + } + if (!EFI_ERROR(Status)) { + break; + } + } + // + // Report the Buffer FULL error code if there is failure. + // + if (EFI_ERROR(Status)) { + ERROR_CODE (DXE_KEYBOARD_BUFFER_FULL_ERROR, EFI_ERROR_MAJOR); + } + + KBDEnableState = FALSE; + Status = EnableKeyboard(); + + if (EFI_ERROR(Status)) { + // + // Report the KBC Controller error code. + // + ERROR_CODE (DXE_KEYBOARD_CONTROLLER_ERROR, EFI_ERROR_MAJOR); + } + +#if CLEAR_PENDING_KEYS_IN_PS2 + // + // Clear OBF as some Notebook KBC has some keys even after + // disabling and enabling scanning. + // + ClearOBF (); +#endif + + if(!gKeyboardIrqInstall){ + LEDsOnOff(Kbd); + } + + Kbd->LEDCommandState = 0; + InsideKbdReset = FALSE; + + if(KbdIrqSupport && gKeyboardIrqInstall) { + + + // + // Now enable the interrupt + // + mLegacy8259->EnableIrq(mLegacy8259, SYSTEM_KEYBOARD_IRQ, FALSE); + } + + return EFI_SUCCESS; + +} + + +EFI_STATUS KbdResetEx( + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + BOOLEAN ExtendedVerification ) +{ + return KbdReset(0, ExtendedVerification); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: KbdReadKey +// +// Description: Reads the next keystroke from the input device. This +// routine is a part of SimpleTextIn protocol +// implementation. +// +// Paremeters: EFI_SIMPLE_TEXT_INPUT_PROTOCOL +// This - A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL +// instance. +// EFI_INPUT_KEY +// InputKey - A pointer to a buffer that is to be filled in +// with the keystroke information for the key that was +// pressed. +// +// Output: EFI_SUCCESS - The keystroke information was returned. +// EFI_NOT_READY - There was no keystroke data available. +// EFI_DEVICE_ERROR - The keystroke information was not +// returned due to hardware errors. +// +// Modified: InsideKbdReadKey +// +// Referral(s): InsideGetMouseData, InsideGetMouseData, +// InsideOnWaitingOnKey +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS KbdReadKey( + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + EFI_INPUT_KEY *InputKey ) +{ + KEYBOARD* Kbd = &gKbd; + + if (InsideGetMouseData || InsideKbdReadKey || InsideOnWaitingOnKey || InsideKbdReset || InsideMouseReset) { + return GetKeyFromBuffer (Kbd, (VOID*)InputKey, sizeof(EFI_INPUT_KEY)); + } + + InsideKbdReadKey = TRUE; + + PS2DataDispatcher(This); + + InsideKbdReadKey = FALSE; + +#if CHECK_BDA_KEYBOARD_BUFFER +#if CSM_SUPPORT + if( gLegacyBiosProtocolFound ) { + if (!CheckKeyinBuffer(Kbd)) { + if( *BdaKbdHead != *BdaKbdTail ) { + ProcessKBDData (Kbd, *((UINT8 *)(*BdaKbdHead + BdaSeg + 1))); + *BdaKbdHead += 2; + if(*BdaKbdHead == 0x3E) { + *BdaKbdHead = 0x1E; + } + } + } + } +#endif +#endif + + return GetKeyFromBuffer (Kbd, (VOID*)InputKey, sizeof(EFI_INPUT_KEY)); + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: KbdReadKeyEx +// +// Description: Reads the next keystroke from the input device. This +// routine is a part of SimpleTextInEx protocol +// implementation. +// +// Paremeters: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL +// *This - A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL +// instance. +// +// Output: EFI_INPUT_KEY +// *key - A pointer to a buffer that is filled in with the +// keystroke state data for the key that was pressed. +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +KbdReadKeyEx ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + OUT EFI_KEY_DATA *KeyData +) +{ + EFI_STATUS Status; + KEYBOARD *Kbd = &gKbd; + + if(KeyData == NULL) { + return EFI_INVALID_PARAMETER; + } + if (!InsideGetMouseData && !InsideKbdReadKey && !InsideOnWaitingOnKey && !InsideKbdReset && !InsideMouseReset) { + InsideKbdReadKey = TRUE; + PS2DataDispatcher(This); + InsideKbdReadKey = FALSE; + } + +#if CHECK_BDA_KEYBOARD_BUFFER +#if CSM_SUPPORT + if( gLegacyBiosProtocolFound ) { + if (!CheckKeyinBuffer(Kbd)) { + if( *BdaKbdHead != *BdaKbdTail ) { + ProcessKBDData (Kbd, *((UINT8 *)(*BdaKbdHead + BdaSeg + 1))); + *BdaKbdHead += 2; + if(*BdaKbdHead == 0x3E) { + *BdaKbdHead = 0x1E; + } + } + } + } +#endif +#endif + + Status = GetKeyFromBuffer (Kbd, (VOID*)KeyData, sizeof(EFI_KEY_DATA)); + if (EFI_ERROR(Status)) { + + pBS->SetMem(KeyData, sizeof (EFI_KEY_DATA), 0); + // + // Check the partial Key. If found return Success with NULL data + // in EFI_INPUT_KEY. + // + Status=CheckPartialKey(Kbd, (EFI_KEY_DATA*)KeyData); + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS KbdReadEfiKeyEx ( + IN AMI_EFIKEYCODE_PROTOCOL *This, + OUT AMI_EFI_KEY_DATA *KeyData +) +{ + EFI_STATUS Status; + KEYBOARD *Kbd = &gKbd; + + if (!InsideGetMouseData && !InsideKbdReadKey && !InsideOnWaitingOnKey && !InsideKbdReset && !InsideMouseReset) { + InsideKbdReadKey = TRUE; + PS2DataDispatcher(This); + InsideKbdReadKey = FALSE; + } + + +#if CHECK_BDA_KEYBOARD_BUFFER +#if CSM_SUPPORT + if( gLegacyBiosProtocolFound ) { + // + // If there is no key, check whether any key is present BDA Keyboard buffer as + // we may miss any key in legacy mode. + // + if (!CheckKeyinBuffer(Kbd)) { + if( *BdaKbdHead != *BdaKbdTail ) { + // + // Get the scan code from BDA keyboard buffer and process it. + // + ProcessKBDData (Kbd, *((UINT8 *)(*BdaKbdHead + BdaSeg + 1))); + *BdaKbdHead += 2; + // + // Check whether we have reached end of circular buffer, if reached initialize + // header to beginning of the buffer. + // + if(*BdaKbdHead == 0x3E) { + *BdaKbdHead = 0x1E; + } + } + } + } +#endif +#endif + + Status = GetKeyFromBuffer (Kbd, (VOID*)KeyData, sizeof(AMI_EFI_KEY_DATA)); + if (EFI_ERROR(Status)) { + pBS->SetMem(KeyData, sizeof (AMI_EFI_KEY_DATA), 0); + // + // Check the partial Key. If found return Success with NULL data + // in EFI_INPUT_KEY. + // + Status=CheckPartialKey(Kbd, (EFI_KEY_DATA*)KeyData); + return Status; + } + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: SetState +// +// Description: Set certain state for the input device. +// +// Paremeters: This - A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL_EX +// instance. +// KeyToggleState - Pointer to the EFI_KEY_TOGGLE_STATE to +// set the state for the input device. +// +// Output: None +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +SetState ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_TOGGLE_STATE *KeyToggleState +) +{ + BOOLEAN ChgSL = FALSE; + BOOLEAN ChgCL = FALSE; + BOOLEAN ChgNL = FALSE; + + KEYBOARD* Kbd = &gKbd; + + if(KeyToggleState == NULL ) { + return EFI_INVALID_PARAMETER; + } + + if (!(*KeyToggleState & TOGGLE_STATE_VALID) || + ((*KeyToggleState & (~(TOGGLE_STATE_VALID | KEY_STATE_EXPOSED | + SCROLL_LOCK_ACTIVE | NUM_LOCK_ACTIVE | CAPS_LOCK_ACTIVE)))) ) { + return EFI_UNSUPPORTED; + } + + + ChgSL = ((*KeyToggleState & SCROLL_LOCK_ACTIVE)!=0) ^ ((Kbd->KeyData.KeyState.KeyToggleState & SCROLL_LOCK_ACTIVE)!=0); + ChgNL = ((*KeyToggleState & NUM_LOCK_ACTIVE)!=0) ^ ((Kbd->KeyData.KeyState.KeyToggleState & NUM_LOCK_ACTIVE)!=0); + ChgCL = ((*KeyToggleState & CAPS_LOCK_ACTIVE)!=0) ^ ((Kbd->KeyData.KeyState.KeyToggleState & CAPS_LOCK_ACTIVE)!=0); + + if (ChgSL || ChgCL || ChgNL) { + Kbd->KeyData.KeyState.KeyToggleState &= ~(SCROLL_LOCK_ACTIVE | NUM_LOCK_ACTIVE | CAPS_LOCK_ACTIVE); + + if (*KeyToggleState & SCROLL_LOCK_ACTIVE) Kbd->KeyData.KeyState.KeyToggleState |= SCROLL_LOCK_ACTIVE; + if (*KeyToggleState & NUM_LOCK_ACTIVE) Kbd->KeyData.KeyState.KeyToggleState |= NUM_LOCK_ACTIVE; + if (*KeyToggleState & CAPS_LOCK_ACTIVE) Kbd->KeyData.KeyState.KeyToggleState |= CAPS_LOCK_ACTIVE; + + LEDsOnOff(Kbd); + } + + return EFI_SUCCESS; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: StartPollingKey +// +// Description: Get the keys from the keyboard controller +// +// Paremeters: IN EFI_EVENT Event event that has been signaled +// IN VOID *Context +// +// Output: None +// +// +//<AMI_PHDR_END> +//********************************************************************** +VOID StartPollingKey(EFI_EVENT Event, VOID *Context) +{ + if (!InsideGetMouseData && !InsideKbdReadKey && !InsideOnWaitingOnKey && !InsideKbdReset && !InsideMouseReset) { + InsideKbdReadKey = TRUE; + PS2DataDispatcher(Context); + InsideKbdReadKey = FALSE; + } + return; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: CheckKeyNotify +// +// Description: Call the notification function based on the key pressed +// +// Input: Key - Key pressed +// +// Output: None +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS +CheckKeyNotify(AMI_EFI_KEY_DATA *Key) +{ + + KEY_WAITING_RECORD *Ps2KeyIn = OUTTER(mPs2KeyboardData.pHead, Link, KEY_WAITING_RECORD); + BOOLEAN KeyScanCodeMatch=FALSE; + BOOLEAN KeyUniCodeMatch=FALSE; + BOOLEAN ShiftKeyMatch=FALSE; + BOOLEAN CtrlKeyMatch=FALSE; + BOOLEAN AltKeyMatch=FALSE; + BOOLEAN LogoKeyMatch=FALSE; + BOOLEAN MenuKeyMatch=FALSE; + BOOLEAN SysRqKeyMatch=FALSE; + BOOLEAN KeyShiftCodeMatch=FALSE; + BOOLEAN KeyToggleKeyMatch=FALSE; + + // if the list is empty return the status that was passed in + if (Ps2KeyIn == NULL) + return EFI_SUCCESS; + + // check for a handle that was already identified + while ( Ps2KeyIn != NULL) + { + KeyScanCodeMatch=FALSE; + KeyUniCodeMatch=FALSE; + ShiftKeyMatch=FALSE; + CtrlKeyMatch=FALSE; + AltKeyMatch=FALSE; + LogoKeyMatch=FALSE; + MenuKeyMatch=FALSE; + SysRqKeyMatch=FALSE; + KeyShiftCodeMatch=FALSE; + KeyToggleKeyMatch=FALSE; + + // + // Check the Scan Code if the Scan code is not 0 + // + if (Ps2KeyIn->Context.Key.ScanCode != 0) { + if( Ps2KeyIn->Context.Key.ScanCode == Key->Key.ScanCode) { + KeyScanCodeMatch=TRUE; + } + } else { + KeyScanCodeMatch=TRUE; + } + + // + // Check the Uncide Code Matching + // + + if(Ps2KeyIn->Context.Key.UnicodeChar == Key->Key.UnicodeChar) { + KeyUniCodeMatch=TRUE; + } + + if(Ps2KeyIn->Context.KeyState.KeyShiftState & SHIFT_STATE_VALID){ + + // + // Check the ShiftKey Matching. Left Shift Key is matched with + // Left or Right Shift Key. Same for Right Shift Key + // + if (Ps2KeyIn->Context.KeyState.KeyShiftState & (RIGHT_SHIFT_PRESSED | LEFT_SHIFT_PRESSED)) { + if(Key->KeyState.KeyShiftState & (RIGHT_SHIFT_PRESSED | LEFT_SHIFT_PRESSED)) { + ShiftKeyMatch=TRUE; + } + } else { + ShiftKeyMatch=TRUE; + } + + // + // Check the Ctrl Matching. Left Ctrl Key is matched with + // Left or Right Ctrl Key. Same for Right Ctrl Key + // + if (Ps2KeyIn->Context.KeyState.KeyShiftState & (RIGHT_CONTROL_PRESSED | LEFT_CONTROL_PRESSED)) { + if(Key->KeyState.KeyShiftState & (RIGHT_CONTROL_PRESSED | LEFT_CONTROL_PRESSED)) { + CtrlKeyMatch=TRUE; + } + } else { + CtrlKeyMatch=TRUE; + } + + // + // Check the Alt Matching. Left Alt Key is matched with + // Left or Right Alt Key. Same for Right Alt Key + // + if (Ps2KeyIn->Context.KeyState.KeyShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) { + if(Key->KeyState.KeyShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) { + AltKeyMatch=TRUE; + } + } else { + AltKeyMatch=TRUE; + } + + // + // Check the Logo Matching. Left Logo Key is matched with + // Left or Right Logo Key. Same for Right Logo Key + // + if (Ps2KeyIn->Context.KeyState.KeyShiftState & (RIGHT_LOGO_PRESSED | LEFT_LOGO_PRESSED)) { + if(Key->KeyState.KeyShiftState & (RIGHT_LOGO_PRESSED | LEFT_LOGO_PRESSED)) { + LogoKeyMatch=TRUE; + } + } else { + LogoKeyMatch=TRUE; + } + + // + // Check the Menu Key Matching + // + if (Ps2KeyIn->Context.KeyState.KeyShiftState & MENU_KEY_PRESSED) { + if(Key->KeyState.KeyShiftState & MENU_KEY_PRESSED) { + MenuKeyMatch=TRUE; + } + } else { + MenuKeyMatch=TRUE; + } + + // + // Check the SysRq Key Matching + // + if (Ps2KeyIn->Context.KeyState.KeyShiftState & SYS_REQ_PRESSED) { + if(Key->KeyState.KeyShiftState & SYS_REQ_PRESSED) { + SysRqKeyMatch=TRUE; + } + } else { + SysRqKeyMatch=TRUE; + } + + KeyShiftCodeMatch=ShiftKeyMatch & CtrlKeyMatch & AltKeyMatch + & LogoKeyMatch & MenuKeyMatch & SysRqKeyMatch; + }else { + KeyShiftCodeMatch=TRUE; + } + // + // Check the Key Toggle State + // + if(Ps2KeyIn->Context.KeyState.KeyToggleState & TOGGLE_STATE_VALID){ + if(Ps2KeyIn->Context.KeyState.KeyToggleState == Key->KeyState.KeyToggleState) { + KeyToggleKeyMatch=TRUE; + } + } else { + KeyToggleKeyMatch=TRUE; + } + + // + // If everything matched, call the callback function. + // + if(KeyScanCodeMatch & KeyUniCodeMatch & KeyShiftCodeMatch & KeyToggleKeyMatch) { + //Call the notification function + // + Ps2KeyIn->Callback(&Ps2KeyIn->Context); + } + // go to the next element in the list + Ps2KeyIn = OUTTER(Ps2KeyIn->Link.pNext, Link, KEY_WAITING_RECORD); + } + + // if it is a new handle return the status pass in + return EFI_SUCCESS; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: RegisterKeyNotify +// +// Description: Register the callback function for the specific Key +// +// Input: This - A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL_EX +// instance. +// KeyData - Key value +// KeyNotificationFunction- Pointer to the Notification Function +// NotificationHandle - Handle to be unregisterd +// +// Output: None +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS +RegisterKeyNotify( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_DATA *KeyData, + IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, + OUT EFI_HANDLE *NotifyHandle +) +{ + EFI_STATUS Status; + + + if(KeyData == NULL || KeyNotificationFunction == NULL || NotifyHandle == NULL ) { + return EFI_INVALID_PARAMETER; + } + + // + // Create database record and add to database + // + Status = pBS->AllocatePool ( + EfiRuntimeServicesData, + sizeof (KEY_WAITING_RECORD), + &mPs2KeyboardRecord + ); + + if(EFI_ERROR(Status)) { + return Status; + } + + // + // Gather information about the registration request + // + + mPs2KeyboardRecord->Context = *KeyData; + mPs2KeyboardRecord->Callback = KeyNotificationFunction; + + DListAdd (&mPs2KeyboardData, &(mPs2KeyboardRecord->Link)); + + // + // Child's handle will be the address linked list link in the record + // + *NotifyHandle = (EFI_HANDLE) (&mPs2KeyboardRecord->Link); + + if(mPs2KeyboardData.Size == 1) { + pBS->SetTimer(Ps2KeyEvent, + TimerPeriodic, + KEY_POLLING_INTERVAL); + } + + return EFI_SUCCESS; +} +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: UnRegisterKeyNotify +// +// Description: Unregister the callback function +// +// Input: This - A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL_EX +// instance. +// NotificationHandle - Handle to be unregisterd +// +// Output: None +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS +UnRegisterKeyNotify( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_HANDLE NotificationHandle +) +{ + + DLINK *ListPtr; + KEY_WAITING_RECORD *Ps2KeyIn; + + if(NotificationHandle == NULL ) { + return EFI_INVALID_PARAMETER; + } + + ListPtr = mPs2KeyboardData.pHead; + while ( ListPtr != NULL) + { + Ps2KeyIn = OUTTER(ListPtr, Link, KEY_WAITING_RECORD); + if ( (&Ps2KeyIn->Link) == NotificationHandle) + { + DListDelete(&mPs2KeyboardData, ListPtr); + pBS->FreePool(Ps2KeyIn); + break; + } + + ListPtr = ListPtr->pNext; + } + + if(ListPtr == NULL) { + return EFI_INVALID_PARAMETER; + } + + if(mPs2KeyboardData.Size == 0) { + pBS->SetTimer(Ps2KeyEvent, + TimerCancel, + 0); + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: OnWaitingOnKey +// +// Description: Callback for the EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey +// event; +// checks whether the new key is available and if so - +// signals the event. +// +// Input: EFI_EVENT Event - Event to signal +// void Context - Event specific context (pointer to Kbd +// device) +// +// Output: None +// +// Modified: InsideOnWaitingOnKey +// +// Referrals: InsideGetMouseData, InsideKbdReadKey, +// InsideOnWaitingOnKey +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +OnWaitingOnKey ( + EFI_EVENT Event, + VOID *Context ) +{ + + if (InsideGetMouseData || InsideKbdReadKey || InsideOnWaitingOnKey || InsideKbdReset || InsideMouseReset) { + if (CheckKeyinBuffer((KEYBOARD*)Context)) gSysTable->BootServices->SignalEvent(Event); + return; + } + + InsideOnWaitingOnKey = TRUE; + + PS2DataDispatcher(Context); // Process new keys if available + + InsideOnWaitingOnKey = FALSE; + + if (CheckKeyinBuffer((KEYBOARD*)Context)) + { + gSysTable->BootServices->SignalEvent(Event); + } +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: ReadAndProcessKey +// +// Description: PS2 keyboard keys processor, called from main PS2 +// dispatcher. +// It gets the key from KBC output buffer and calls +// HandleKBDData. +// +// Paremeters: void *Context - keyboard device pointer +// +// Output: None +// +// Notes: PS2 output buffer has data, incoming key is processed, +// Context->KeyIsReady is updated. +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +ReadAndProcessKey ( + VOID *Context ) +{ + + KEYBOARD *Kbd = &gKbd; + UINT8 data; + + data = KBCGetData(); + ProcessKBDData (Kbd, data); + return; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: ProcessKBDData +// +// Description: If key is ready, processes any hotkey, and inserts key +// in buffer +// +// Parameters: +// KEYBOARD *Kbd - Pointer to key buffer +// UINT8 data - Key data +// +// Output: None +// +// Notes: Incoming key is processed, Context->KeyIsReady is updated +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +ProcessKBDData ( + KEYBOARD *Kbd, + UINT8 data +) +{ + EFI_KEY_DATA DummyKey; + + HandleKBDData(Kbd, data); + if (Kbd->KeyIsReady) { + + ProcessHotKey(Kbd->KeyData.PS2ScanCode, + (UINT16)Kbd->KeyData.KeyState.KeyShiftState); + InsertKeyToBuffer(Kbd, &Kbd->KeyData); + Kbd->KeyIsReady = FALSE; + } else { + if (Kbd->KeyData.Key.ScanCode == 0 && Kbd->KeyData.Key.UnicodeChar == 0 && Kbd->ScannerState == KBST_READY ) { + // + // If the Key ShiftState has valid key, report as Partial Key + // + if ((Kbd->KeyData.KeyState.KeyShiftState & ~SHIFT_STATE_VALID) != 0) { + + pBS->CopyMem(&DummyKey, &Kbd->KeyData, sizeof(EFI_KEY_DATA)); + DummyKey.KeyState.KeyToggleState |= KEY_STATE_EXPOSED; + CheckKeyNotify((AMI_EFI_KEY_DATA*)&DummyKey); + } + } + } + return; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: HandleKBDData +// +// Description: Processes the input data. If a callback function is +// associated with the key, then it is executed. +// +// Paremeters: +// KEYBOARD *Kbd - Pointer to key buffer +// UINT8 data - Key data +// +// Output: None +// +// +// Notes: This routine can be called re-entrantly from LEDsOnOff(OutToKb) +// e.g. when Numlock and Del is pressed continously. +// Incoming key is processed, Context->KeyIsReady is updated. +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +HandleKBDData ( + KEYBOARD *Kbd, + UINT8 data ) +{ + // + // PS2 keyboard could send one, two, four or six bytes in a row. + // Kbd->ScannerState is ST_READY if it is the first byte + // + if (Kbd->ScannerState == KBST_READY) + { + switch (data) { + case 0xE0: + Kbd->ScannerState = KBST_E0; + break; + case 0xE1: + Kbd->ScannerState = KBST_E1; + break; + default: + ProcessByte(Kbd, data, FALSE); + } + return; + } + else // Multi-byte sequence is being processed + { + if (Kbd->ScannerState == KBST_E1) // Processing E1 state + { + if (data != E1Seq[Kbd->Count]) { // Wrong byte in a sequence + ResetStateMachine(Kbd); + return; + } + // + // E1 sequence data is correct, proceed + // + if (Kbd->Count == 2) { // The ONLY 2-key sequence starting with E1 is Pause + Kbd->KeyData.EfiKey = EfiKeyPause; + Kbd->KeyIsReady = TRUE; + ResetStateMachine(Kbd); + return; + } + if (Kbd->Count == 4) { // E1 sequence has finished + ProcessByte(Kbd, data, FALSE); + ResetStateMachine(Kbd); + return; + } + // + // E1 sequence is not complete, update the counter and return + // + Kbd->Count++; + return; + } + else // Kbd->ScannerState == ST_E0 - processing E0 state + { + + // + // For E0 state the Count values will be: + // 0 for 1st and 2nd byte + // 2 for 3rd byte (if available) + // 1 for 4th byte (if available) + // No validity checking will be done for 2nd,3rd and 4th bytes + // + + if (Kbd->ScannerState == KBST_E0) { + if ( IsEnhancedKey( data)) { + ResetStateMachine(Kbd); + return; + } + // Processing E0 state, if data is 2A or AA or MSB bit is + // set (break key) ignore it. + if (data == 0x2A || data == 0xAA || data & 0x80 && \ + // except in special case of alt, ctrl, Print key, Left Logo, Right Logo and Menu Key + data != 0xb8 && data != 0x9d && data != 0xB7 && \ + data != 0xDB && data != 0xDC && data != 0xDD) { + ResetStateMachine(Kbd); + return; + } + else { + ProcessByte(Kbd, data, TRUE); + ResetStateMachine(Kbd); + return; + } + } + ProcessByte(Kbd, data, FALSE); + ResetStateMachine(Kbd); + return; + + } + } +} + + + +void ResetStateMachine(KEYBOARD *Kbd) +{ + Kbd->ScannerState = KBST_READY; + Kbd->Count = 0; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: IsLetter +// +// Description: Returns TRUE if the given make code belongs to the +// alphabetical symbol, otherwise returns FALSE. +// +// Paremeters: UINT8 data - The character to test +// +// Output: BOOLEAN - True if character is letter +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +BOOLEAN +IsLetter ( + UINT8 data ) +{ + if ((data >= 0x10 && data <= 0x19) || // Q...P + (data >= 0x1E && data <= 0x26) || // A...L + (data >= 0x2C && data <= 0x32)) { // Z...M + return TRUE; + } + return FALSE; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: ProcessByte +// +// Description: Checks for valid key, updates key modifiers, keyboard +// queue head and tail as well as Kbd->KeyIsReady field. +// +// Input: KEYBOARD *Kbd - A pointer to the KEYBOARD device. +// UINT8 data - byte to process +// BOOLEAN long_sequence - the indication of whether it is a +// 4 byte sequence or not; used to differentiate Shift keys +// +// Output: None +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +ProcessByte ( + KEYBOARD *Kbd, + UINT8 Data, + BOOLEAN long_sequence ) +{ + BOOLEAN bUpperCase, bShifted; + EFI_EXTKEY *extkey; + static BOOLEAN Make_Capslock = FALSE, Make_SCRLOCK = FALSE, Make_NUMLOCK = FALSE; + UINT8 *KeyboardTypeBda = (UINT8*)((UINTN) 0x496); + + + Kbd->KeyData.Key.ScanCode = 0; + Kbd->KeyData.Key.UnicodeChar = 0; + Kbd->KeyData.PS2ScanCode = Data; + + // + // Process ESC key + // + if (Data == 1) { + Kbd->KeyData.Key.ScanCode = EFI_SCAN_ESC; + Kbd->KeyData.EfiKey = EfiKeyEsc; + Kbd->KeyIsReady = TRUE; + return; + } + + // + // Get the E0, E1 Status from BDA (40:96). If those bit get set means Int9 processed the E0 + // E1 data and before processing other Scan code it came out of Legacy mode. + // Now EFI driver sees other scan code that's part of the E0 and E1 scan. So we don't want to Process + // those data. + // +#if CHECK_BDA_KEYBOARD_BUFFER +#if CSM_SUPPORT + if( gLegacyBiosProtocolFound ) { + if(*KeyboardTypeBda & (E0_STATUS_IN_BDA + E1_STATUS_IN_BDA)) { + *KeyboardTypeBda &=~(E0_STATUS_IN_BDA + E1_STATUS_IN_BDA); + return; + } + } +#endif +#endif + + // + // Process key modifiers: xyzLock (update LEDs) and Ctrl/Alt/Shift + // + switch (Data) { + case 0x38: + if (Kbd->ScannerState == KBST_E0) { + Kbd->KeyData.KeyState.KeyShiftState |= RIGHT_ALT_PRESSED; + } else { + Kbd->KeyData.KeyState.KeyShiftState |= LEFT_ALT_PRESSED; + } + return; //break; + case 0xB8: + if (Kbd->ScannerState == KBST_E0) { + Kbd->KeyData.KeyState.KeyShiftState &= ~RIGHT_ALT_PRESSED; + } else { + Kbd->KeyData.KeyState.KeyShiftState &= ~LEFT_ALT_PRESSED; + } + return; //break; + + case 0x1D: + if (Kbd->ScannerState == KBST_E0) { + Kbd->KeyData.KeyState.KeyShiftState |= RIGHT_CONTROL_PRESSED; + } else { + Kbd->KeyData.KeyState.KeyShiftState |= LEFT_CONTROL_PRESSED; + } + return; //break; + case 0x9D: + if (Kbd->ScannerState == KBST_E0) { + Kbd->KeyData.KeyState.KeyShiftState &= ~RIGHT_CONTROL_PRESSED; + } else { + Kbd->KeyData.KeyState.KeyShiftState &= ~LEFT_CONTROL_PRESSED; + } + return; //break; + + case 0x2A: { + Kbd->KeyData.KeyState.KeyShiftState |= LEFT_SHIFT_PRESSED; return; //break; + } + case 0xAA: // could be a part of a long break code + if (!long_sequence) { + Kbd->KeyData.KeyState.KeyShiftState &= ~LEFT_SHIFT_PRESSED; + } + return; //break; + + case 0x36: Kbd->KeyData.KeyState.KeyShiftState |= RIGHT_SHIFT_PRESSED; return; //break; + case 0xB6: Kbd->KeyData.KeyState.KeyShiftState &= ~RIGHT_SHIFT_PRESSED; return; //break; + + case 0x3A: + if (!Make_Capslock) { + Kbd->KeyData.KeyState.KeyToggleState ^= CAPS_LOCK_ACTIVE; + Make_Capslock = TRUE; + } + Kbd->KeyData.EfiKey = EfiKeyCapsLock; + Kbd->KeyIsReady = TRUE; + break; + + case 0xBA: Make_Capslock = FALSE; break; + + case 0x46: + if (Kbd->ScannerState != KBST_E0){ + if (!Make_SCRLOCK) { + Kbd->KeyData.KeyState.KeyToggleState ^= SCROLL_LOCK_ACTIVE; + Make_SCRLOCK = TRUE; + } + Kbd->KeyData.EfiKey = EfiKeySLck; + Kbd->KeyIsReady = TRUE; + } + break; + + case 0xC6: + if (Kbd->ScannerState != KBST_E0){ + Make_SCRLOCK = FALSE; + } + break; + case 0x45: + if (!Make_NUMLOCK) { + Kbd->KeyData.KeyState.KeyToggleState ^= NUM_LOCK_ACTIVE; + Make_NUMLOCK = TRUE; + } + Kbd->KeyData.EfiKey = EfiKeyNLck; + Kbd->KeyIsReady = TRUE; + break; + + case 0xC5: Make_NUMLOCK = FALSE; break; + // + // Handle the PrintScreen/SysRq make Code + // + case 0x37: + if (Kbd->ScannerState == KBST_E0) { + Kbd->KeyData.KeyState.KeyShiftState |= SYS_REQ_PRESSED; + return; + } + break; + + // + // Handle the PrintScreen/SysRq breakcode + // + case 0xB7: + if (Kbd->ScannerState == KBST_E0) { + Kbd->KeyData.KeyState.KeyShiftState &= ~ SYS_REQ_PRESSED; + return; + } + break; + + // + // Handle the Left Logo make Code + // + case 0x5B: + if (Kbd->ScannerState == KBST_E0) { + Kbd->KeyData.KeyState.KeyShiftState |= LEFT_LOGO_PRESSED; + return; + } + break; + + // + // Handle the Left Logo breakcode + // + case 0xDB: + if (Kbd->ScannerState == KBST_E0) { + Kbd->KeyData.KeyState.KeyShiftState &= ~ LEFT_LOGO_PRESSED; + return; + } + break; + + // + // Handle the Right Logo make Code + // + case 0x5C: + if (Kbd->ScannerState == KBST_E0) { + Kbd->KeyData.KeyState.KeyShiftState |= RIGHT_LOGO_PRESSED; + return; + } + break; + + // + // Handle the Right Logo breakcode + // + case 0xDC: + if (Kbd->ScannerState == KBST_E0) { + Kbd->KeyData.KeyState.KeyShiftState &= ~ RIGHT_LOGO_PRESSED; + return; + } + break; + + // + // Handle the Menu Key make Code + // + case 0x5D: + if (Kbd->ScannerState == KBST_E0) { + Kbd->KeyData.KeyState.KeyShiftState |= MENU_KEY_PRESSED; + return; + } + break; + + // + // Handle the Meny Key breakcode + // + case 0xDD: + if (Kbd->ScannerState == KBST_E0) { + Kbd->KeyData.KeyState.KeyShiftState &= ~ MENU_KEY_PRESSED; + return; + } + break; + + case 0xFA: ProcessKBDResponse(Kbd, Data); break; + case 0xFE: ProcessKBDResponse(Kbd, Data); break; + case 0xFF: ProcessKBDResponse(Kbd, Data); break; + } + + // + // Process main block of keys + // + if (Data < 0x3A && !(Kbd->ScannerState == KBST_E0 && Data == 0x37)) {// Exceptional case is Printscreen/sys req + + bShifted = Kbd->KeyData.KeyState.KeyShiftState & (RIGHT_SHIFT_PRESSED | LEFT_SHIFT_PRESSED); + + if (Kbd->ScannerState == KBST_E0) bShifted = 0; // Check for '/' in Keypad. Otherwise '?' will be sent + + + if (IsLetter(Data)) { // for not-a-letter Caps-Lock must not work + bUpperCase = (Kbd->KeyData.KeyState.KeyToggleState & CAPS_LOCK_ACTIVE)? !bShifted: bShifted; + } + else { + bUpperCase = bShifted; + } + if (bUpperCase) { + Kbd->KeyData.Key.UnicodeChar = Code_Table[Data]; // UPPER CASE TABLE + } + else { + Kbd->KeyData.Key.UnicodeChar = code_table[Data]; // lower case table + } + Kbd->KeyData.EfiKey = ScancodeToEfi_table[Data]; + if (Kbd->KeyData.Key.UnicodeChar != 0) { + Kbd->KeyIsReady = TRUE; + } + return; + } + +// UK Keyboard "|\" (EfiKeyB0) +// data = 0x56(ScanCode Set1), EfiKeyB0, "|\" + if ( Data == 0x56) { + bShifted = Kbd->KeyData.KeyState.KeyShiftState & (RIGHT_SHIFT_PRESSED | LEFT_SHIFT_PRESSED); + if ( Kbd->ScannerState == KBST_E0) bShifted = 0; // Check for '/' in Keypad. Otherwise '?' will be sent + bUpperCase = bShifted; // for not-a-letter Caps-Lock must not work + if (bUpperCase) { + Kbd->KeyData.Key.UnicodeChar = '|'; // UPPER CASE TABLE + } + else { + Kbd->KeyData.Key.UnicodeChar = '\\'; // lower case + } + Kbd->KeyData.EfiKey = EfiKeyB0; + Kbd->KeyIsReady = TRUE; + return; + } + + // + // Process keypad keys. Exceptional cases: -, + on keypad + // Keypad numbers when NUMLOCK only is ON OR Shift only is pressed. + if (Kbd->ScannerState != KBST_E0) { + if ((Data > 0x46) && (Data < 0x54) && !long_sequence) { + if (((Kbd->KeyData.KeyState.KeyToggleState & NUM_LOCK_ACTIVE) // Only NUMLOCK in ON + && ((Kbd->KeyData.KeyState.KeyShiftState & (RIGHT_SHIFT_PRESSED | LEFT_SHIFT_PRESSED)) == 0)) + || (((Kbd->KeyData.KeyState.KeyToggleState & NUM_LOCK_ACTIVE) == 0) // Only shift key is pressed + && (Kbd->KeyData.KeyState.KeyShiftState & (RIGHT_SHIFT_PRESSED | LEFT_SHIFT_PRESSED))) + || Data == 0x4a || Data ==0x4e) // check for -, + keys in keypad + { + Kbd->KeyData.Key.UnicodeChar = KeyPad_Table[Data-0x47]; + Kbd->KeyData.EfiKey = KeyPadEfiCode_Table[Data-0x47]; + Kbd->KeyIsReady = TRUE; + return; + } + } + } + // + // Process F-keys + // + for (extkey = ScanCode_Table; extkey->makecode != 0xFF; extkey++) { + if (Data == extkey->makecode) { + Kbd->KeyData.Key.ScanCode = extkey->efi_scancode; + Kbd->KeyData.EfiKey = extkey->efi_key; + Kbd->KeyIsReady = TRUE; + return; + } + } +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: LEDsOnOff +// +// Description: Turns keyboard LEDs on and off. +// +// Input: KEYBOARD *Kbd - A pointer to the KEYBOARD device. +// +// Output: None +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +void LEDsOnOff ( + KEYBOARD* Kbd ) +{ + + UINT8 bIndicators = Kbd->KeyData.KeyState.KeyToggleState & 7; // SCRL/NUM/CPSL + + if (InsidePS2DataDispatcher) return; + InsidePS2DataDispatcher = TRUE; + + // + // Check for keyboard IRQ support + // + if(KbdIrqSupport){ + if(gKeyboardIrqInstall && KBDEnableState){ + if (bIndicators != Kbd->Indicators){ + // + // Turn on/off the lights + // + Kbd->CommandResponded = NULL; + // + // Issue Keyboard LED Command 0xED + // + CheckIssueLEDCmd(Kbd); + if(Kbd->LEDCommandState == ED_COMMAND_ISSUED) { + // + // LED command "ED" has been issues. Process the Data here itself. + // + UINT32 Counter; + for (Counter = 1000; Counter > 0; Counter--) { + // + // The Interrupt handler will handle the response + // and set the Kbd->LEDCommandState to zero in both + // case with or without error. Exit once the response is + // handled. + // + if(Kbd->LEDCommandState == 0) { + break; + } + gSysTable->BootServices->Stall(1000); + + } + } + } + Kbd->LEDCommandState = NULL; + InsidePS2DataDispatcher = FALSE; + return; + } + } + + + if (bIndicators != Kbd->Indicators) { + // + // Issue Keyboard LED Command 0xED + // + CheckIssueLEDCmd(Kbd); + + // + //Process the led command and data + // + ProcessLEDCommandData(Kbd); + } + + InsidePS2DataDispatcher = FALSE; + return; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: GetKeyFromBuffer +// +// Description: Gets the next key from the circular buffer +// +// Input: KEYBOARD *Kbd - A pointer to the KEYBOARD device. +// EFI_INPUT_KEY *key - Pointer to input key data +// +// Output: EFI_SUCCESS - key.ScanCode and key.UnicodeChar updated +// EFI_NOT_READY - no key in buffer +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +GetKeyFromBuffer ( + KEYBOARD *Kbd, + VOID *Key, + UINT8 KeySize +) +{ + AMI_EFI_KEY_DATA TempKey; + + if (Kbd->pBufHead == Kbd->pBufTail) return EFI_NOT_READY; + + pBS->CopyMem(&TempKey, Kbd->pBufHead, sizeof(AMI_EFI_KEY_DATA)); + + + TempKey.EfiKeyIsValid = 1; + TempKey.PS2ScanCodeIsValid = 1; + + ProcessMultiLanguage(&TempKey); + + if (TempKey.Key.UnicodeChar != 0) { + TempKey.KeyState.KeyShiftState &= ~(RIGHT_SHIFT_PRESSED | LEFT_SHIFT_PRESSED); + } + + pBS->CopyMem(Key, &TempKey, KeySize); + + Kbd->pBufHead++; + if (Kbd->pBufHead >= Kbd->pBufEnd) Kbd->pBufHead = Kbd->pBufStart; // Point to the beginning + + return EFI_SUCCESS; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: InsertKeyToBuffer +// +// Description: Insert the key into the circular buffer +// +// Input: KEYBOARD *Kbd - A pointer to the KEYBOARD device. +// AMI_EFI_INPUT_KEY key - input key data +// +// Output: EFI_SUCCESS - Key placed in buffer +// EFI_WARN_BUFFER_TOO_SMALL - Buffer to small +// +// Notes: If buffer is full, the EFI_WARN_BUFFER_TOO_SMALL. +// Tail points to the new Data. +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +InsertKeyToBuffer ( + KEYBOARD *Kbd, + AMI_EFI_KEY_DATA *Key +) +{ + AMI_EFI_KEY_DATA *Temp = Kbd->pBufTail; + + CheckKeyNotify(Key); + if (Kbd->pBufTail != Kbd->pBufHead) { // Check if space available + Temp++; + if (Temp >= Kbd->pBufEnd) Temp = Kbd->pBufStart; + if (Kbd->pBufHead == Temp) return EFI_WARN_BUFFER_TOO_SMALL; // No more space + } + + *Kbd->pBufTail = *Key; + Kbd->pBufTail++; + + if (Kbd->pBufTail >= Kbd->pBufEnd) Kbd->pBufTail = Kbd->pBufStart; + + return EFI_SUCCESS; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: CheckKeyinBuffer +// +// Description: Checks if any key is present in the buffer +// +// Input: KEYBOARD *Kbd - A pointer to the KEYBOARD device. +// +// Output: BOOLEAN - TRUE if a key is in the buffer, FALSE otherwise. +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +BOOLEAN +CheckKeyinBuffer ( + KEYBOARD* Kbd +) +{ + if (Kbd->pBufHead == Kbd->pBufTail) return FALSE; + return TRUE; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: CheckPartialKey +// +// Description: Gets the next key from the circular buffer +// +// Input: KEYBOARD *Kbd - A pointer to the KEYBOARD device. +// EFI_INPUT_KEY *key - Pointer to input key data +// +// Output: EFI_SUCCESS - Partial Key Found +// EFI_NOT_READY - no key in buffer +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +CheckPartialKey ( + KEYBOARD *Kbd, + EFI_KEY_DATA *Key +) +{ + + if (Kbd->KeyData.Key.ScanCode == 0 && Kbd->KeyData.Key.UnicodeChar == 0) { + // + // If the Key ShiftState has valid key, report as Partial Key + // + if ((Kbd->KeyData.KeyState.KeyShiftState & ~SHIFT_STATE_VALID) != 0) { + + pBS->CopyMem(Key, &Kbd->KeyData, sizeof(EFI_KEY_DATA)); + Key->KeyState.KeyToggleState |= KEY_STATE_EXPOSED; + CheckKeyNotify((AMI_EFI_KEY_DATA*)Key); + return EFI_SUCCESS; + } + } + + return EFI_NOT_READY; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: KeyboardInterruptHandler +// +// Description: An interrupt handler for keyboard IRQ. +// +// +// Input: InterruptType Interrupt type +// SystemContext System context +// +// Output: EFI_SUCCESS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID KeyboardInterruptHandler( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext +) +{ + KEYBOARD_IRQ_STORE* KbIrqBuffer = &gKeyboardIrqBuffer; + KEYBOARD *Kbd = &gKbd; + UINT8 bIndicators = Kbd->KeyData.KeyState.KeyToggleState & 7; // SCRL/NUM/CPSL + UINT8 Data = IoRead8(KBC_DATA_PORT); + + gCpuArch->DisableInterrupt(gCpuArch); + + // + // Stored received acknowledgement + // + switch (Data) { + case 0xFA: + Kbd->CommandResponded = KB_ACK_COM; + if (Kbd->LEDCommandState == ED_COMMAND_ISSUED) { + Kbd->LEDCommandState = ED_DATA_ISSUED; + Kbd->Indicators = bIndicators; + WriteKeyboardData(bIndicators); + break; + } + + if (Kbd->LEDCommandState == ED_DATA_ISSUED) { + Kbd->LEDCommandState = 0; + break; + } + + break; + case 0xFE: + Kbd->CommandResponded = KB_RSND_COM; + if (Kbd->LEDCommandState == ED_COMMAND_ISSUED || Kbd->LEDCommandState == ED_DATA_ISSUED) { +// Error occured. Clear out the current indicator bits. +// Modifiers will have the correct bits that needs to be set. +// Next Call to CheckIssueLEDCmd will detect the mismatch +// and start the LED sequence. + WriteKeyboardData(0xF4); + Kbd->LEDCommandState = 0; + Kbd->KeyData.KeyState.KeyToggleState &= + ~(SCROLL_LOCK_ACTIVE | NUM_LOCK_ACTIVE | CAPS_LOCK_ACTIVE); + Kbd->Indicators &= 0xf0; + } + break; + case 0xFF: + Kbd->CommandResponded = KB_RSND_COM; + Kbd->LEDCommandState = 0; + break; + default: + // + // If key has been pressed before keyboard start then data will be saved in local buffer + // else data will be processed + // + if(!gKeyboardDriverStart){ + if (KbIrqBuffer->KbdIndex < BUFFER_SIZE){ + KbIrqBuffer->KbdBuffer[KbIrqBuffer->KbdIndex]=Data; + KbIrqBuffer->KbdIndex++; + } + } + else { + ProcessKBDData (Kbd, Data); + } + break; + } + + // + // End of interrupt command sent + // + mLegacy8259->EndOfInterrupt(mLegacy8259, SYSTEM_KEYBOARD_IRQ); + gCpuArch->EnableInterrupt(gCpuArch); +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: InitKeyboardIrq +// +// Description: To initialize keyboard interrupt, register keyboard +// handler, and enable the keyboard interrupt +// +// Input: +// +// Paremeters: +// +// Output: None +// +// +//<AMI_PHDR_END> +//********************************************************************** +VOID InitKeyboardIrq(VOID) +{ + + EFI_STATUS Status; + KEYBOARD_IRQ_STORE* KbIrqBuffer = &gKeyboardIrqBuffer; + EFI_GUID gEfiLegacy8259ProtocolGuid = EFI_LEGACY_8259_PROTOCOL_GUID; + EFI_GUID gEfiCpuArchProtocolGuid = EFI_CPU_ARCH_PROTOCOL_GUID; + UINT32 KeyboardVector = NULL; + + if (!gKeyboardIrqInstall){ + Status = pBS->LocateProtocol(&gEfiLegacy8259ProtocolGuid, NULL, &mLegacy8259); + if (EFI_ERROR(Status)) { + return; + } + + // Find the CPU Arch Protocol + Status = pBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, &gCpuArch); + if (EFI_ERROR(Status)) { + return; + } + + // + // Get keyboard Interrupt vector + // + Status = mLegacy8259->GetVector(mLegacy8259, SYSTEM_KEYBOARD_IRQ, (UINT8 *) & KeyboardVector); + if (EFI_ERROR(Status)) { + return; + } + + // + // Register interrupt handler for keyboard + // + Status = gCpuArch->RegisterInterruptHandler(gCpuArch, KeyboardVector, KeyboardInterruptHandler); + if (EFI_ERROR(Status)) { + return; + } + + KbIrqBuffer->KbdIndex=0; + gKeyboardIrqInstall = TRUE; + + // + // Now enable the interrupt + // + mLegacy8259->EnableIrq(mLegacy8259, SYSTEM_KEYBOARD_IRQ, FALSE); + } + return; +} + +#if CLEAR_PENDING_KEYS_IN_PS2 +// <AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: ClearOBF +// +// Description: +// Clears any pending keys in Ps2 Output Buffer. +// +// Input: +// VOID +// +// Output: +// VOID +// +// Modified: +// +// Referrals: +// +// Notes: This OBF clear is done since some PS2 KBC has pending keys even +// after resetting the Keyboard. +//--------------------------------------------------------------------------- +// <AMI_PHDR_END> +VOID +ClearOBF( +VOID +) +{ + UINT8 bData; + UINT8 Counter=200; + + pBS->Stall(10*1000); + + while( IoRead8(KBC_CMDSTS_PORT) & KBC_OBF ) + { + bData = IoRead8(KBC_DATA_PORT); + // + // wait 10 ms for KBC OBF output. + // + pBS->Stall(10*1000); + Counter--; + // + // If still keys are present after 2 sec. exit from the loop. + // + if(Counter==NULL) { + break; + } + } + return; +} + +// <AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: Ps2KbdReset +// +// Description: +// Reset the Ps2 Keyboard by sending disabling and Enabling scanning. +// +// Input: +// VOID +// +// Output: +// VOID +// +// Modified: +// +// Referrals: +// +// Notes: +// +//--------------------------------------------------------------------------- +// <AMI_PHDR_END> +VOID +Ps2KbdReset( +VOID +) +{ + EFI_STATUS Status; + UINT8 bCount, bData, bBCount; + + // + // Disable and enable keyboard to reset. + // + DisableKeyboard(); + + for (bBCount = 0; bBCount < 4; bBCount++) { + for (bCount = 0; bCount < 3; bCount++) { + Status = ReadDevice(KBD_DISABLE_SCANNING, &bData, KB_ACK_COM); + if (!EFI_ERROR(Status)) { + break; + } + } + + if (EFI_ERROR(Status)) { + continue; + } + + for (bCount = 0; bCount < 3; bCount++) { + Status = ReadDevice(KBD_ENABLE_SCANNING, &bData, KB_ACK_COM); + if (!EFI_ERROR(Status)) { + break; + } + } + + if (!EFI_ERROR(Status)) { + break; + } + } + + EnableKeyboard(); + return; +} + +#endif + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: ProcessLEDCommandData +// +// Description: Process the LED command and data. +// +// Input: KEYBOARD *Kbd - A pointer to the KEYBOARD device. +// +// Output: None +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +ProcessLEDCommandData( + KEYBOARD* Kbd ) +{ + + UINT32 Counter; + UINT8 data; + + if(Kbd->LEDCommandState == ED_COMMAND_ISSUED) { + // + // LED command "ED" has been issued. Disable the keyboard and + // Process the Data here itself. + // + + DisableKeyboard(); + + for (Counter = 1000; Counter > 0; Counter--) { + for(data = IoRead8(KBC_CMDSTS_PORT); data & KBC_OBF; data = IoRead8(KBC_CMDSTS_PORT)) { + if (!(data & KBC_AUX_OBF)) { + // + // Handle the Command or Data Status + // + DrivePS2KbdMachine(NULL); + } + } + + // + // If the command and data is processed with or without error, exit here. + // + if(Kbd->LEDCommandState == 0) { + return; + } + gSysTable->BootServices->Stall(1000); + } + EnableKeyboard(); + } + return; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: ProcessMultiLanguage +// +// Description: It maps the current key to a Unicode character from +// the keyboard layout +// +// Paremeters: KeyData - Pointer to the AMI_EFI_KEY_DATA . +// +// Output: None +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS ProcessMultiLanguage( + IN OUT AMI_EFI_KEY_DATA *KeyData) +{ + EFI_STATUS Status; + + if(gPs2MultiLangSupportProtocol == NULL) { + Status= pBS->LocateProtocol ( + &gAmiMultiLangSupportGuid, + NULL, + &gPs2MultiLangSupportProtocol + ); + if(EFI_ERROR(Status)) { + return EFI_NOT_FOUND; + } + } + Status = gPs2MultiLangSupportProtocol->KeyboardLayoutMap(gPs2MultiLangSupportProtocol,KeyData); + + return Status; +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2009, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** |