+/**@file\r
+ PS/2 Keyboard driver\r
+ Routines that access 8042 keyboard controller\r
+\r
+Copyright (c) 2006 - 2007 Intel Corporation. All rights reserved. <BR>\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+**/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "Ps2Keyboard.h"\r
+\r
+//\r
+// Function declarations\r
+//\r
+STATIC\r
+UINT8\r
+KeyReadDataRegister (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn\r
+ );\r
+\r
+STATIC\r
+VOID\r
+KeyWriteDataRegister (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN UINT8 Data\r
+ );\r
+\r
+STATIC\r
+VOID\r
+KeyWriteCommandRegister (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN UINT8 Data\r
+ );\r
+\r
+STATIC\r
+VOID\r
+KeyboardError (\r
+ IN KEYBOARD_CONSOLE_IN_DEV*ConsoleIn,\r
+ IN CHAR16 *ErrMsg // should be a unicode string\r
+ );\r
+\r
+STATIC\r
+EFI_STATUS\r
+GetScancodeBufHead (\r
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN UINT32 Count,\r
+ OUT UINT8 *Buf\r
+ );\r
+\r
+STATIC\r
+EFI_STATUS\r
+PopScancodeBufHead (\r
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN UINT32 Count,\r
+ OUT UINT8 *Buf\r
+ );\r
+\r
+STATIC\r
+EFI_STATUS\r
+KeyboardWrite (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN UINT8 Data\r
+ );\r
+\r
+STATIC\r
+EFI_STATUS\r
+KeyboardCommand (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN UINT8 Data\r
+ );\r
+\r
+STATIC\r
+EFI_STATUS\r
+KeyboardWaitForValue (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN UINT8 Value\r
+ );\r
+\r
+STATIC\r
+EFI_STATUS\r
+UpdateStatusLights (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn\r
+ );\r
+\r
+//\r
+// Global variables\r
+//\r
+\r
+STATIC struct {\r
+ UINT8 ScanCode;\r
+ UINT16 EfiScanCode;\r
+ CHAR16 UnicodeChar;\r
+ CHAR16 ShiftUnicodeChar;\r
+}\r
+ConvertKeyboardScanCodeToEfiKey[] = {\r
+\r
+ {\r
+ 0x01, // Escape\r
+ SCAN_ESC,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x02,\r
+ SCAN_NULL,\r
+ '1',\r
+ '!'\r
+ },\r
+ {\r
+ 0x03,\r
+ SCAN_NULL,\r
+ '2',\r
+ '@'\r
+ },\r
+ {\r
+ 0x04,\r
+ SCAN_NULL,\r
+ '3',\r
+ '#'\r
+ },\r
+ {\r
+ 0x05,\r
+ SCAN_NULL,\r
+ '4',\r
+ '$'\r
+ },\r
+ {\r
+ 0x06,\r
+ SCAN_NULL,\r
+ '5',\r
+ '%'\r
+ },\r
+ {\r
+ 0x07,\r
+ SCAN_NULL,\r
+ '6',\r
+ '^'\r
+ },\r
+ {\r
+ 0x08,\r
+ SCAN_NULL,\r
+ '7',\r
+ '&'\r
+ },\r
+ {\r
+ 0x09,\r
+ SCAN_NULL,\r
+ '8',\r
+ '*'\r
+ },\r
+ {\r
+ 0x0A,\r
+ SCAN_NULL,\r
+ '9',\r
+ '('\r
+ },\r
+ {\r
+ 0x0B,\r
+ SCAN_NULL,\r
+ '0',\r
+ ')'\r
+ },\r
+ {\r
+ 0x0C,\r
+ SCAN_NULL,\r
+ '-',\r
+ '_'\r
+ },\r
+ {\r
+ 0x0D,\r
+ SCAN_NULL,\r
+ '=',\r
+ '+'\r
+ },\r
+ {\r
+ 0x0E, // BackSpace\r
+ SCAN_NULL,\r
+ 0x08,\r
+ 0x08\r
+ },\r
+ {\r
+ 0x0F, // Tab\r
+ SCAN_NULL,\r
+ 0x09,\r
+ 0x09\r
+ },\r
+ {\r
+ 0x10,\r
+ SCAN_NULL,\r
+ 'q',\r
+ 'Q'\r
+ },\r
+ {\r
+ 0x11,\r
+ SCAN_NULL,\r
+ 'w',\r
+ 'W'\r
+ },\r
+ {\r
+ 0x12,\r
+ SCAN_NULL,\r
+ 'e',\r
+ 'E'\r
+ },\r
+ {\r
+ 0x13,\r
+ SCAN_NULL,\r
+ 'r',\r
+ 'R'\r
+ },\r
+ {\r
+ 0x14,\r
+ SCAN_NULL,\r
+ 't',\r
+ 'T'\r
+ },\r
+ {\r
+ 0x15,\r
+ SCAN_NULL,\r
+ 'y',\r
+ 'Y'\r
+ },\r
+ {\r
+ 0x16,\r
+ SCAN_NULL,\r
+ 'u',\r
+ 'U'\r
+ },\r
+ {\r
+ 0x17,\r
+ SCAN_NULL,\r
+ 'i',\r
+ 'I'\r
+ },\r
+ {\r
+ 0x18,\r
+ SCAN_NULL,\r
+ 'o',\r
+ 'O'\r
+ },\r
+ {\r
+ 0x19,\r
+ SCAN_NULL,\r
+ 'p',\r
+ 'P'\r
+ },\r
+ {\r
+ 0x1a,\r
+ SCAN_NULL,\r
+ '[',\r
+ '{'\r
+ },\r
+ {\r
+ 0x1b,\r
+ SCAN_NULL,\r
+ ']',\r
+ '}'\r
+ },\r
+ {\r
+ 0x1c, // Enter\r
+ SCAN_NULL,\r
+ 0x0d,\r
+ 0x0d\r
+ },\r
+ {\r
+ 0x1d,\r
+ SCAN_NULL,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x1e,\r
+ SCAN_NULL,\r
+ 'a',\r
+ 'A'\r
+ },\r
+ {\r
+ 0x1f,\r
+ SCAN_NULL,\r
+ 's',\r
+ 'S'\r
+ },\r
+ {\r
+ 0x20,\r
+ SCAN_NULL,\r
+ 'd',\r
+ 'D'\r
+ },\r
+ {\r
+ 0x21,\r
+ SCAN_NULL,\r
+ 'f',\r
+ 'F'\r
+ },\r
+ {\r
+ 0x22,\r
+ SCAN_NULL,\r
+ 'g',\r
+ 'G'\r
+ },\r
+ {\r
+ 0x23,\r
+ SCAN_NULL,\r
+ 'h',\r
+ 'H'\r
+ },\r
+ {\r
+ 0x24,\r
+ SCAN_NULL,\r
+ 'j',\r
+ 'J'\r
+ },\r
+ {\r
+ 0x25,\r
+ SCAN_NULL,\r
+ 'k',\r
+ 'K'\r
+ },\r
+ {\r
+ 0x26,\r
+ SCAN_NULL,\r
+ 'l',\r
+ 'L'\r
+ },\r
+ {\r
+ 0x27,\r
+ SCAN_NULL,\r
+ ';',\r
+ ':'\r
+ },\r
+ {\r
+ 0x28,\r
+ SCAN_NULL,\r
+ '\'',\r
+ '"'\r
+ },\r
+ {\r
+ 0x29,\r
+ SCAN_NULL,\r
+ '`',\r
+ '~'\r
+ },\r
+ {\r
+ 0x2a, // Left Shift\r
+ SCAN_NULL,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x2b,\r
+ SCAN_NULL,\r
+ '\\',\r
+ '|'\r
+ },\r
+ {\r
+ 0x2c,\r
+ SCAN_NULL,\r
+ 'z',\r
+ 'Z'\r
+ },\r
+ {\r
+ 0x2d,\r
+ SCAN_NULL,\r
+ 'x',\r
+ 'X'\r
+ },\r
+ {\r
+ 0x2e,\r
+ SCAN_NULL,\r
+ 'c',\r
+ 'C'\r
+ },\r
+ {\r
+ 0x2f,\r
+ SCAN_NULL,\r
+ 'v',\r
+ 'V'\r
+ },\r
+ {\r
+ 0x30,\r
+ SCAN_NULL,\r
+ 'b',\r
+ 'B'\r
+ },\r
+ {\r
+ 0x31,\r
+ SCAN_NULL,\r
+ 'n',\r
+ 'N'\r
+ },\r
+ {\r
+ 0x32,\r
+ SCAN_NULL,\r
+ 'm',\r
+ 'M'\r
+ },\r
+ {\r
+ 0x33,\r
+ SCAN_NULL,\r
+ ',',\r
+ '<'\r
+ },\r
+ {\r
+ 0x34,\r
+ SCAN_NULL,\r
+ '.',\r
+ '>'\r
+ },\r
+ {\r
+ 0x35,\r
+ SCAN_NULL,\r
+ '/',\r
+ '?'\r
+ },\r
+ {\r
+ 0x36, //Right Shift\r
+ SCAN_NULL,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x37, // Numeric Keypad *\r
+ SCAN_NULL,\r
+ '*',\r
+ '*'\r
+ },\r
+ {\r
+ 0x38, //Left Alt/Extended Right Alt\r
+ SCAN_NULL,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x39,\r
+ SCAN_NULL,\r
+ ' ',\r
+ ' '\r
+ },\r
+ {\r
+ 0x3A, //CapsLock\r
+ SCAN_NULL,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x3B,\r
+ SCAN_F1,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x3C,\r
+ SCAN_F2,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x3D,\r
+ SCAN_F3,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x3E,\r
+ SCAN_F4,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x3F,\r
+ SCAN_F5,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x40,\r
+ SCAN_F6,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x41,\r
+ SCAN_F7,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x42,\r
+ SCAN_F8,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x43,\r
+ SCAN_F9,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x44,\r
+ SCAN_F10,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x45, // NumLock\r
+ SCAN_NULL,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x46, // ScrollLock\r
+ SCAN_NULL,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x47,\r
+ SCAN_HOME,\r
+ '7',\r
+ '7'\r
+ },\r
+ {\r
+ 0x48,\r
+ SCAN_UP,\r
+ '8',\r
+ '8'\r
+ },\r
+ {\r
+ 0x49,\r
+ SCAN_PAGE_UP,\r
+ '9',\r
+ '9'\r
+ },\r
+ {\r
+ 0x4a,\r
+ SCAN_NULL,\r
+ '-',\r
+ '-'\r
+ },\r
+ {\r
+ 0x4b,\r
+ SCAN_LEFT,\r
+ '4',\r
+ '4'\r
+ },\r
+ {\r
+ 0x4c, // Numeric Keypad 5\r
+ SCAN_NULL,\r
+ '5',\r
+ '5'\r
+ },\r
+ {\r
+ 0x4d,\r
+ SCAN_RIGHT,\r
+ '6',\r
+ '6'\r
+ },\r
+ {\r
+ 0x4e,\r
+ SCAN_NULL,\r
+ '+',\r
+ '+'\r
+ },\r
+ {\r
+ 0x4f,\r
+ SCAN_END,\r
+ '1',\r
+ '1'\r
+ },\r
+ {\r
+ 0x50,\r
+ SCAN_DOWN,\r
+ '2',\r
+ '2'\r
+ },\r
+ {\r
+ 0x51,\r
+ SCAN_PAGE_DOWN,\r
+ '3',\r
+ '3'\r
+ },\r
+ {\r
+ 0x52,\r
+ SCAN_INSERT,\r
+ '0',\r
+ '0'\r
+ },\r
+ {\r
+ 0x53,\r
+ SCAN_DELETE,\r
+ '.',\r
+ '.'\r
+ },\r
+ {\r
+ 0x57,\r
+ SCAN_F11,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ 0x58,\r
+ SCAN_F12,\r
+ 0x00,\r
+ 0x00\r
+ },\r
+ {\r
+ TABLE_END,\r
+ TABLE_END,\r
+ SCAN_NULL,\r
+ SCAN_NULL\r
+ },\r
+};\r
+\r
+\r
+//\r
+// The WaitForValue time out\r
+//\r
+STATIC UINTN mWaitForValueTimeOut = KEYBOARD_WAITFORVALUE_TIMEOUT;\r
+\r
+STATIC\r
+UINT8\r
+KeyReadDataRegister (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ ConsoleIn - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ EFI_ISA_IO_PROTOCOL *IsaIo;\r
+ UINT8 Data;\r
+\r
+ //\r
+ // Use IsaIo protocol to perform IO operations\r
+ //\r
+ IsaIo = ConsoleIn->IsaIo;\r
+\r
+ IsaIo->Io.Read (\r
+ IsaIo,\r
+ EfiIsaIoWidthUint8,\r
+ ConsoleIn->DataRegisterAddress,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ return Data;\r
+}\r
+\r
+STATIC\r
+VOID\r
+KeyWriteDataRegister (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN UINT8 Data\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ ConsoleIn - GC_TODO: add argument description\r
+ Data - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ EFI_ISA_IO_PROTOCOL *IsaIo;\r
+\r
+ //\r
+ // Use IsaIo protocol to perform IO operations\r
+ //\r
+ IsaIo = ConsoleIn->IsaIo;\r
+\r
+ IsaIo->Io.Write (\r
+ IsaIo,\r
+ EfiIsaIoWidthUint8,\r
+ ConsoleIn->DataRegisterAddress,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ //\r
+ // outp(ConsoleIn->DataRegisterAddress, Data);\r
+ //\r
+}\r
+\r
+UINT8\r
+KeyReadStatusRegister (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ ConsoleIn - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ EFI_ISA_IO_PROTOCOL *IsaIo;\r
+ UINT8 Data;\r
+\r
+ //\r
+ // Use IsaIo protocol to perform IO operations\r
+ //\r
+ IsaIo = ConsoleIn->IsaIo;\r
+\r
+ IsaIo->Io.Read (\r
+ IsaIo,\r
+ EfiIsaIoWidthUint8,\r
+ ConsoleIn->StatusRegisterAddress,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ return Data;\r
+\r
+}\r
+\r
+STATIC\r
+VOID\r
+KeyWriteCommandRegister (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN UINT8 Data\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ ConsoleIn - GC_TODO: add argument description\r
+ Data - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ EFI_ISA_IO_PROTOCOL *IsaIo;\r
+\r
+ //\r
+ // Use IsaIo protocol to perform IO operations\r
+ //\r
+ IsaIo = ConsoleIn->IsaIo;\r
+\r
+ IsaIo->Io.Write (\r
+ IsaIo,\r
+ EfiIsaIoWidthUint8,\r
+ ConsoleIn->CommandRegisterAddress,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+}\r
+\r
+STATIC\r
+VOID\r
+KeyboardError (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN CHAR16 *ErrMsg\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Display error message\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+// GC_TODO: ConsoleIn - add argument and description to function comment\r
+// GC_TODO: ErrMsg - add argument and description to function comment\r
+{\r
+ ConsoleIn->KeyboardErr = TRUE;\r
+\r
+ //\r
+ // gST -> ConOut -> OutputString (gST -> ConOut, L"Keyboard Driver: ");\r
+ // gST -> ConOut -> OutputString (gST -> ConOut, ErrMsg);\r
+ //\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+KeyboardTimerHandler (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Timer event handler: read a series of scancodes from 8042\r
+ and put them into memory scancode buffer.\r
+ it read as much scancodes to either fill\r
+ the memory buffer or empty the keyboard buffer.\r
+ It is registered as running under TPL_NOTIFY\r
+\r
+Arguments:\r
+\r
+ Event - The timer event\r
+ Context - A KEYBOARD_CONSOLE_IN_DEV pointer\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+ UINT8 Data;\r
+ EFI_TPL OldTpl;\r
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;\r
+\r
+ ConsoleIn = Context;\r
+\r
+ //\r
+ // Enter critical section\r
+ //\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ if (((KEYBOARD_CONSOLE_IN_DEV *) Context)->KeyboardErr) {\r
+ //\r
+ // Leave critical section and return\r
+ //\r
+ gBS->RestoreTPL (OldTpl);\r
+ return ;\r
+ }\r
+ //\r
+ // To let KB driver support Hot plug, here should skip the 'resend' command for the case that\r
+ // KB is not connected to system. If KB is not connected to system, driver will find there's something\r
+ // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since\r
+ // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.\r
+ // Just skip the 'resend' process simply.\r
+ //\r
+\r
+ Data = 0;\r
+\r
+ //\r
+ // if there is no key present, just return\r
+ //\r
+ if ((KeyReadStatusRegister (Context) & 0x21) != 0x1) {\r
+ //\r
+ // Leave critical section and return\r
+ //\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return ;\r
+ }\r
+ //\r
+ // Read one byte of the scan code and store it into the memory buffer\r
+ //\r
+ if (ConsoleIn->ScancodeBufCount < KEYBOARD_BUFFER_MAX_COUNT) {\r
+\r
+ Data = KeyReadDataRegister (Context);\r
+ //\r
+ // put the scancode into the memory scancode buffer\r
+ //\r
+ ConsoleIn->ScancodeBufCount++;\r
+ ConsoleIn->ScancodeBufEndPos++;\r
+ if (ConsoleIn->ScancodeBufEndPos >= KEYBOARD_BUFFER_MAX_COUNT) {\r
+ ConsoleIn->ScancodeBufEndPos = 0;\r
+ }\r
+\r
+ ConsoleIn->ScancodeBuf[ConsoleIn->ScancodeBufEndPos] = Data;\r
+\r
+ //\r
+ // Handle Alt+Ctrl+Del Key combination\r
+ //\r
+ switch (Data) {\r
+ case SCANCODE_CTRL_MAKE:\r
+ ConsoleIn->Ctrled = TRUE;\r
+ break;\r
+\r
+ case SCANCODE_CTRL_BREAK:\r
+ ConsoleIn->Ctrled = FALSE;\r
+ break;\r
+\r
+ case SCANCODE_ALT_MAKE:\r
+ ConsoleIn->Alted = TRUE;\r
+ break;\r
+\r
+ case SCANCODE_ALT_BREAK:\r
+ ConsoleIn->Alted = FALSE;\r
+ break;\r
+ }\r
+ //\r
+ // if Alt+Ctrl+Del, Reboot the System\r
+ //\r
+ if (ConsoleIn->Ctrled && ConsoleIn->Alted && Data == 0x53) {\r
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
+ }\r
+ }\r
+ //\r
+ // Leave critical section and return\r
+ //\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return ;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+GetScancodeBufHead (\r
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN UINT32 Count,\r
+ OUT UINT8 *Buf\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Read several bytes from the scancode buffer without removing them.\r
+ This function is called to see if there are enough bytes of scancode\r
+ representing a single key.\r
+\r
+Arguments:\r
+\r
+ Count - Number of bytes to be read\r
+ Buf - Store the results\r
+\r
+Returns:\r
+\r
+ EFI_STATUS\r
+\r
+--*/\r
+// GC_TODO: ConsoleIn - add argument and description to function comment\r
+// GC_TODO: EFI_NOT_READY - add return value to function comment\r
+// GC_TODO: EFI_SUCCESS - add return value to function comment\r
+{\r
+ UINT32 Index;\r
+ UINT32 Pos;\r
+\r
+ Index = 0;\r
+ Pos = 0;\r
+\r
+ //\r
+ // check the valid range of parameter 'Count'\r
+ //\r
+ if (Count <= 0 || ConsoleIn->ScancodeBufCount < Count) {\r
+ return EFI_NOT_READY;\r
+ }\r
+ //\r
+ // retrieve the values\r
+ //\r
+ for (Index = 0; Index < Count; Index++) {\r
+\r
+ if (Index == 0) {\r
+\r
+ Pos = ConsoleIn->ScancodeBufStartPos;\r
+ } else {\r
+\r
+ Pos = Pos + 1;\r
+ if (Pos >= KEYBOARD_BUFFER_MAX_COUNT) {\r
+ Pos = 0;\r
+ }\r
+ }\r
+\r
+ Buf[Index] = ConsoleIn->ScancodeBuf[Pos];\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+PopScancodeBufHead (\r
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN UINT32 Count,\r
+ OUT UINT8 *Buf\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Read & remove several bytes from the scancode buffer.\r
+ This function is usually called after GetScancodeBufHead()\r
+\r
+Arguments:\r
+\r
+ Count - Number of bytes to be read\r
+ Buf - Store the results\r
+\r
+Returns:\r
+\r
+ EFI_STATUS\r
+\r
+--*/\r
+// GC_TODO: ConsoleIn - add argument and description to function comment\r
+// GC_TODO: EFI_NOT_READY - add return value to function comment\r
+// GC_TODO: EFI_SUCCESS - add return value to function comment\r
+{\r
+ UINT32 Index;\r
+\r
+ Index = 0;\r
+\r
+ //\r
+ // Check the valid range of parameter 'Count'\r
+ //\r
+ if (Count <= 0 || ConsoleIn->ScancodeBufCount < Count) {\r
+ return EFI_NOT_READY;\r
+ }\r
+ //\r
+ // Retrieve and remove the values\r
+ //\r
+ for (Index = 0; Index < Count; Index++) {\r
+\r
+ if (Index != 0) {\r
+\r
+ ConsoleIn->ScancodeBufStartPos++;\r
+ if (ConsoleIn->ScancodeBufStartPos >= KEYBOARD_BUFFER_MAX_COUNT) {\r
+ ConsoleIn->ScancodeBufStartPos = 0;\r
+ }\r
+ }\r
+\r
+ Buf[Index] = ConsoleIn->ScancodeBuf[ConsoleIn->ScancodeBufStartPos];\r
+ ConsoleIn->ScancodeBufCount--;\r
+ }\r
+\r
+ ConsoleIn->ScancodeBufStartPos++;\r
+ if (ConsoleIn->ScancodeBufStartPos >= KEYBOARD_BUFFER_MAX_COUNT) {\r
+ ConsoleIn->ScancodeBufStartPos = 0;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+KeyboardRead (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ OUT UINT8 *Data\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ ConsoleIn - GC_TODO: add argument description\r
+ Data - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ EFI_TIMEOUT - GC_TODO: Add description for return value\r
+ EFI_SUCCESS - GC_TODO: Add description for return value\r
+\r
+--*/\r
+{\r
+ UINT32 TimeOut;\r
+ UINT32 RegFilled;\r
+\r
+ TimeOut = 0;\r
+ RegFilled = 0;\r
+\r
+ //\r
+ // wait till output buffer full then perform the read\r
+ //\r
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
+ if (KeyReadStatusRegister (ConsoleIn) & 0x01) {\r
+ RegFilled = 1;\r
+ *Data = KeyReadDataRegister (ConsoleIn);\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (30);\r
+ }\r
+\r
+ if (!RegFilled) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+KeyboardWrite (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN UINT8 Data\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ ConsoleIn - GC_TODO: add argument description\r
+ Data - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ EFI_TIMEOUT - GC_TODO: Add description for return value\r
+ EFI_SUCCESS - GC_TODO: Add description for return value\r
+\r
+--*/\r
+{\r
+ UINT32 TimeOut;\r
+ UINT32 RegEmptied;\r
+\r
+ TimeOut = 0;\r
+ RegEmptied = 0;\r
+\r
+ //\r
+ // wait for input buffer empty\r
+ //\r
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
+ if (!(KeyReadStatusRegister (ConsoleIn) & 0x02)) {\r
+ RegEmptied = 1;\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (30);\r
+ }\r
+\r
+ if (!RegEmptied) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+ //\r
+ // Write it\r
+ //\r
+ KeyWriteDataRegister (ConsoleIn, Data);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+KeyboardCommand (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN UINT8 Data\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ ConsoleIn - GC_TODO: add argument description\r
+ Data - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ EFI_TIMEOUT - GC_TODO: Add description for return value\r
+ EFI_TIMEOUT - GC_TODO: Add description for return value\r
+ EFI_SUCCESS - GC_TODO: Add description for return value\r
+\r
+--*/\r
+{\r
+ UINT32 TimeOut;\r
+ UINT32 RegEmptied;\r
+\r
+ TimeOut = 0;\r
+ RegEmptied = 0;\r
+\r
+ //\r
+ // Wait For Input Buffer Empty\r
+ //\r
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
+ if (!(KeyReadStatusRegister (ConsoleIn) & 0x02)) {\r
+ RegEmptied = 1;\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (30);\r
+ }\r
+\r
+ if (!RegEmptied) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+ //\r
+ // issue the command\r
+ //\r
+ KeyWriteCommandRegister (ConsoleIn, Data);\r
+\r
+ //\r
+ // Wait For Input Buffer Empty again\r
+ //\r
+ RegEmptied = 0;\r
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
+ if (!(KeyReadStatusRegister (ConsoleIn) & 0x02)) {\r
+ RegEmptied = 1;\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (30);\r
+ }\r
+\r
+ if (!RegEmptied) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+KeyboardWaitForValue (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN UINT8 Value\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ wait for a specific value to be presented on\r
+ 8042 Data register by keyboard and then read it,\r
+ used in keyboard commands ack\r
+\r
+Arguments:\r
+\r
+ ConsoleIn - The KEYBOARD_CONSOLE_IN_DEV instance pointer\r
+ Value - The value to be waited for\r
+\r
+Returns:\r
+\r
+ EFI_STATUS\r
+\r
+--*/\r
+// GC_TODO: EFI_SUCCESS - add return value to function comment\r
+// GC_TODO: EFI_TIMEOUT - add return value to function comment\r
+{\r
+ UINT8 Data;\r
+ UINT32 TimeOut;\r
+ UINT32 SumTimeOut;\r
+ UINT32 GotIt;\r
+\r
+ GotIt = 0;\r
+ TimeOut = 0;\r
+ SumTimeOut = 0;\r
+\r
+ //\r
+ // Make sure the initial value of 'Data' is different from 'Value'\r
+ //\r
+ Data = 0;\r
+ if (Data == Value) {\r
+ Data = 1;\r
+ }\r
+ //\r
+ // Read from 8042 (multiple times if needed)\r
+ // until the expected value appears\r
+ // use SumTimeOut to control the iteration\r
+ //\r
+ while (1) {\r
+ //\r
+ // Perform a read\r
+ //\r
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
+ if (KeyReadStatusRegister (ConsoleIn) & 0x01) {\r
+ Data = KeyReadDataRegister (ConsoleIn);\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (30);\r
+ }\r
+\r
+ SumTimeOut += TimeOut;\r
+\r
+ if (Data == Value) {\r
+ GotIt = 1;\r
+ break;\r
+ }\r
+\r
+ if (SumTimeOut >= mWaitForValueTimeOut) {\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // Check results\r
+ //\r
+ if (GotIt) {\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+UpdateStatusLights (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Show keyboard status lights according to\r
+ indicators in ConsoleIn.\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+// GC_TODO: ConsoleIn - add argument and description to function comment\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Command;\r
+\r
+ //\r
+ // Send keyboard command\r
+ //\r
+ Status = KeyboardWrite (ConsoleIn, 0xed);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ KeyboardWaitForValue (ConsoleIn, 0xfa);\r
+\r
+ //\r
+ // Light configuration\r
+ //\r
+ Command = 0;\r
+ if (ConsoleIn->CapsLock) {\r
+ Command |= 4;\r
+ }\r
+\r
+ if (ConsoleIn->NumLock) {\r
+ Command |= 2;\r
+ }\r
+\r
+ if (ConsoleIn->ScrollLock) {\r
+ Command |= 1;\r
+ }\r
+\r
+ Status = KeyboardWrite (ConsoleIn, Command);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ KeyboardWaitForValue (ConsoleIn, 0xfa);\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+KeyGetchar (\r
+ IN OUT KEYBOARD_CONSOLE_IN_DEV *ConsoleIn\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get scancode from scancode buffer\r
+ and translate into EFI-scancode and unicode defined by EFI spec\r
+ The function is always called in TPL_NOTIFY\r
+\r
+Arguments:\r
+\r
+ ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer\r
+\r
+Returns:\r
+\r
+ EFI_NOT_READY - Input from console not ready yet.\r
+ EFI_SUCCESS - Function executed successfully.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 ScanCode;\r
+ UINT8 Readed;\r
+ BOOLEAN Extended;\r
+ UINT8 ScancodeArr[4];\r
+ UINTN Index;\r
+ //\r
+ // 4 bytes most\r
+ //\r
+ UINT32 ScancodeArrPos;\r
+ //\r
+ // point to the current position in ScancodeArr\r
+ //\r
+\r
+ Readed = 0;\r
+ Extended = FALSE;\r
+ ScancodeArrPos = 0;\r
+\r
+ //\r
+ // Read one byte of the scan code and store it into the memory buffer\r
+ // This block of code is added to insert an action that is equivalent to\r
+ // the timer event handling function, so as to increase the frequency of\r
+ // detecting the availability of keys. Timer event has a max frequency of\r
+ // 18Hz which is insufficient\r
+ //\r
+ //\r
+ // To let KB driver support Hot plug, here should skip the 'resend' command for the case that\r
+ // KB is not connected to system. If KB is not connected to system, driver will find there's something\r
+ // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since\r
+ // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.\r
+ // Just skip the 'resend' process simply.\r
+ //\r
+\r
+\r
+ if (((KeyReadStatusRegister (ConsoleIn) & 0x21) == 0x1) && (ConsoleIn->ScancodeBufCount < KEYBOARD_BUFFER_MAX_COUNT)) {\r
+\r
+ Readed = KeyReadDataRegister (ConsoleIn);\r
+ //\r
+ // put the scancode into the memory scancode buffer\r
+ //\r
+ ConsoleIn->ScancodeBufCount++;\r
+ ConsoleIn->ScancodeBufEndPos++;\r
+ if (ConsoleIn->ScancodeBufEndPos >= KEYBOARD_BUFFER_MAX_COUNT) {\r
+ ConsoleIn->ScancodeBufEndPos = 0;\r
+ }\r
+\r
+ ConsoleIn->ScancodeBuf[ConsoleIn->ScancodeBufEndPos] = Readed;\r
+\r
+ //\r
+ // Handle Alt+Ctrl+Del Key combination\r
+ //\r
+ switch (Readed) {\r
+\r
+ case SCANCODE_CTRL_MAKE:\r
+ ConsoleIn->Ctrled = TRUE;\r
+ break;\r
+\r
+ case SCANCODE_CTRL_BREAK:\r
+ ConsoleIn->Ctrled = FALSE;\r
+ break;\r
+\r
+ case SCANCODE_ALT_MAKE:\r
+ ConsoleIn->Alted = TRUE;\r
+ break;\r
+\r
+ case SCANCODE_ALT_BREAK:\r
+ ConsoleIn->Alted = FALSE;\r
+ break;\r
+ }\r
+ //\r
+ // if Alt+Ctrl+Del, Reboot the System\r
+ //\r
+ if (ConsoleIn->Ctrled && ConsoleIn->Alted && Readed == 0x53) {\r
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
+ }\r
+ }\r
+ //\r
+ // Check if there are enough bytes of scancode representing a single key\r
+ // available in the buffer\r
+ //\r
+ while (1) {\r
+\r
+ Status = GetScancodeBufHead (ConsoleIn, 1, ScancodeArr);\r
+ ScancodeArrPos = 0;\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ if (ScancodeArr[ScancodeArrPos] == SCANCODE_EXTENDED) {\r
+ Extended = TRUE;\r
+ Status = GetScancodeBufHead (ConsoleIn, 2, ScancodeArr);\r
+ ScancodeArrPos = 1;\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_READY;\r
+ }\r
+ }\r
+ //\r
+ // Checks for key scancode for PAUSE:E1-1D/45-E1/9D-C5\r
+ // if present, ignore them\r
+ //\r
+ if (ScancodeArr[ScancodeArrPos] == SCANCODE_EXTENDED1) {\r
+\r
+ Status = GetScancodeBufHead (ConsoleIn, 2, ScancodeArr);\r
+ ScancodeArrPos = 1;\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ Status = GetScancodeBufHead (ConsoleIn, 3, ScancodeArr);\r
+ ScancodeArrPos = 2;\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ PopScancodeBufHead (ConsoleIn, 3, ScancodeArr);\r
+ return EFI_NOT_READY;\r
+ }\r
+ //\r
+ // if we reach this position, scancodes for a key is in buffer now,pop them\r
+ //\r
+ Status = PopScancodeBufHead (ConsoleIn, ScancodeArrPos + 1, ScancodeArr);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_READY;\r
+ }\r
+ //\r
+ // store the last available byte, this byte of scancode will be checked\r
+ //\r
+ ScanCode = ScancodeArr[ScancodeArrPos];\r
+\r
+ //\r
+ // Check for special keys and update the driver state.\r
+ //\r
+ switch (ScanCode) {\r
+\r
+ case SCANCODE_CTRL_MAKE:\r
+ ConsoleIn->Ctrl = TRUE;\r
+ break;\r
+\r
+ case SCANCODE_CTRL_BREAK:\r
+ ConsoleIn->Ctrl = FALSE;\r
+ break;\r
+\r
+ case SCANCODE_ALT_MAKE:\r
+ ConsoleIn->Alt = TRUE;\r
+ break;\r
+\r
+ case SCANCODE_ALT_BREAK:\r
+ ConsoleIn->Alt = FALSE;\r
+ break;\r
+\r
+ case SCANCODE_LEFT_SHIFT_MAKE:\r
+ case SCANCODE_RIGHT_SHIFT_MAKE:\r
+ if (!Extended) {\r
+ ConsoleIn->Shift = TRUE;\r
+ }\r
+ break;\r
+\r
+ case SCANCODE_LEFT_SHIFT_BREAK:\r
+ case SCANCODE_RIGHT_SHIFT_BREAK:\r
+ if (!Extended) {\r
+ ConsoleIn->Shift = FALSE;\r
+ }\r
+ break;\r
+\r
+ case SCANCODE_CAPS_LOCK_MAKE:\r
+ ConsoleIn->CapsLock = (BOOLEAN)!ConsoleIn->CapsLock;\r
+ UpdateStatusLights (ConsoleIn);\r
+ break;\r
+\r
+ case SCANCODE_NUM_LOCK_MAKE:\r
+ ConsoleIn->NumLock = (BOOLEAN)!ConsoleIn->NumLock;\r
+ UpdateStatusLights (ConsoleIn);\r
+ break;\r
+\r
+ case SCANCODE_SCROLL_LOCK_MAKE:\r
+ ConsoleIn->ScrollLock = (BOOLEAN)!ConsoleIn->ScrollLock;\r
+ UpdateStatusLights (ConsoleIn);\r
+ break;\r
+ }\r
+ //\r
+ // If this is a BREAK Key or above the valid range, ignore it\r
+ //\r
+ if (ScanCode >= SCANCODE_MAX_MAKE) {\r
+ continue;\r
+ } else {\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // If this is the SysRq, ignore it\r
+ //\r
+ if (Extended && ScanCode == 0x37) {\r
+ return EFI_NOT_READY;\r
+ }\r
+ //\r
+ // Treat Numeric Key Pad "/" specially\r
+ //\r
+ if (Extended && ScanCode == 0x35) {\r
+ ConsoleIn->Key.ScanCode = SCAN_NULL;\r
+ ConsoleIn->Key.UnicodeChar = '/';\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // Convert Keyboard ScanCode into an EFI Key\r
+ //\r
+ for (Index = 0; ConvertKeyboardScanCodeToEfiKey[Index].ScanCode != TABLE_END; Index += 1) {\r
+ if (ScanCode == ConvertKeyboardScanCodeToEfiKey[Index].ScanCode) {\r
+ ConsoleIn->Key.ScanCode = ConvertKeyboardScanCodeToEfiKey[Index].EfiScanCode;\r
+ if (ConsoleIn->Shift) {\r
+ ConsoleIn->Key.UnicodeChar = ConvertKeyboardScanCodeToEfiKey[Index].ShiftUnicodeChar;\r
+ } else {\r
+ ConsoleIn->Key.UnicodeChar = ConvertKeyboardScanCodeToEfiKey[Index].UnicodeChar;\r
+ }\r
+ //\r
+ // alphabetic key is affected by CapsLock State\r
+ //\r
+ if (ConsoleIn->CapsLock) {\r
+ if (ConsoleIn->Key.UnicodeChar >= 'a' && ConsoleIn->Key.UnicodeChar <= 'z') {\r
+ ConsoleIn->Key.UnicodeChar = ConvertKeyboardScanCodeToEfiKey[Index].ShiftUnicodeChar;\r
+ } else if (ConsoleIn->Key.UnicodeChar >= 'A' && ConsoleIn->Key.UnicodeChar <= 'Z') {\r
+ ConsoleIn->Key.UnicodeChar = ConvertKeyboardScanCodeToEfiKey[Index].UnicodeChar;\r
+ }\r
+ }\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // distinguish numeric key pad keys' 'up symbol' and 'down symbol'\r
+ //\r
+ if (ScanCode >= 0x47 && ScanCode <= 0x53) {\r
+\r
+ if (ConsoleIn->NumLock && !ConsoleIn->Shift && !Extended) {\r
+ ConsoleIn->Key.ScanCode = SCAN_NULL;\r
+ } else if (ScanCode != 0x4a && ScanCode != 0x4e) {\r
+ ConsoleIn->Key.UnicodeChar = 0x00;\r
+ }\r
+ }\r
+ //\r
+ // If the key can not be converted then just return.\r
+ //\r
+ if (ConsoleIn->Key.ScanCode == SCAN_NULL && ConsoleIn->Key.UnicodeChar == 0x00) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+InitKeyboard (\r
+ IN OUT KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Perform 8042 controller and keyboard Initialization\r
+ If ExtendedVerification is TRUE, do additional test for\r
+ the keyboard interface\r
+\r
+Arguments:\r
+\r
+ ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer\r
+ ExtendedVerification - indicates a thorough initialization\r
+\r
+Returns:\r
+\r
+ EFI_STATUS\r
+\r
+--*/\r
+// GC_TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+// GC_TODO: EFI_SUCCESS - add return value to function comment\r
+// GC_TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STATUS Status1;\r
+ UINT8 CommandByte;\r
+ STATIC BOOLEAN EnableMouseInterface;\r
+ EFI_PS2_POLICY_PROTOCOL *Ps2Policy;\r
+\r
+ Status = EFI_SUCCESS;\r
+ EnableMouseInterface = TRUE;\r
+\r
+ //\r
+ // Get Ps2 policy to set this\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiPs2PolicyProtocolGuid,\r
+ NULL,\r
+ (VOID **) &Ps2Policy\r
+ );\r
+\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_PROGRESS_CODE,\r
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER,\r
+ ConsoleIn->DevicePath\r
+ );\r
+\r
+ //\r
+ // Perform a read to cleanup the Status Register's\r
+ // output buffer full bits\r
+ //\r
+ while (!EFI_ERROR (Status)) {\r
+ Status = KeyboardRead (ConsoleIn, &CommandByte);\r
+ }\r
+ //\r
+ // We should disable mouse interface during the initialization process\r
+ // since mouse device output could block keyboard device output in the\r
+ // 60H port of 8042 controller.\r
+ //\r
+ // So if we are not initializing 8042 controller for the\r
+ // first time, we have to remember the previous mouse interface\r
+ // enabling state\r
+ //\r
+ // Test the system flag in to determine whether this is the first\r
+ // time initialization\r
+ //\r
+ if ((KeyReadStatusRegister (ConsoleIn) & 0x04)) {\r
+ //\r
+ // 8042 controller is already setup (by myself or by mouse driver):\r
+ // See whether mouse interface is already enabled\r
+ // which determines whether we should enable it later\r
+ //\r
+ //\r
+ // Read the command byte of 8042 controller\r
+ //\r
+ Status = KeyboardCommand (ConsoleIn, 0x20);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"\n\r");\r
+ goto Done;\r
+ }\r
+\r
+ Status = KeyboardRead (ConsoleIn, &CommandByte);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"\n\r");\r
+ goto Done;\r
+ }\r
+ //\r
+ // Test the mouse enabling bit\r
+ //\r
+ if (CommandByte & 0x20) {\r
+ EnableMouseInterface = FALSE;\r
+ } else {\r
+ EnableMouseInterface = TRUE;\r
+ }\r
+\r
+ } else {\r
+ //\r
+ // 8042 controller is not setup yet:\r
+ // 8042 controller selftest;\r
+ // Don't enable mouse interface later.\r
+ //\r
+ //\r
+ // Disable keyboard and mouse interfaces\r
+ //\r
+ Status = KeyboardCommand (ConsoleIn, 0xad);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"\n\r");\r
+ goto Done;\r
+ }\r
+\r
+ Status = KeyboardCommand (ConsoleIn, 0xa7);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"\n\r");\r
+ goto Done;\r
+ }\r
+\r
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+ EFI_PROGRESS_CODE,\r
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST,\r
+ ConsoleIn->DevicePath\r
+ );\r
+ //\r
+ // 8042 Controller Self Test\r
+ //\r
+ Status = KeyboardCommand (ConsoleIn, 0xaa);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");\r
+ goto Done;\r
+ }\r
+\r
+ Status = KeyboardWaitForValue (ConsoleIn, 0x55);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"8042 controller self test failed!\n\r");\r
+ goto Done;\r
+ }\r
+ //\r
+ // Don't enable mouse interface later\r
+ //\r
+ EnableMouseInterface = FALSE;\r
+\r
+ }\r
+\r
+ if (Ps2Policy != NULL) {\r
+ Ps2Policy->Ps2InitHardware (ConsoleIn->Handle);\r
+ }\r
+ //\r
+ // Write 8042 Command Byte, set System Flag\r
+ // While at the same time:\r
+ // 1. disable mouse interface,\r
+ // 2. enable kbd interface,\r
+ // 3. enable PC/XT kbd translation mode\r
+ // 4. enable mouse and kbd interrupts\r
+ //\r
+ // ( Command Byte bits:\r
+ // 7: Reserved\r
+ // 6: PC/XT translation mode\r
+ // 5: Disable Auxiliary device interface\r
+ // 4: Disable keyboard interface\r
+ // 3: Reserved\r
+ // 2: System Flag\r
+ // 1: Enable Auxiliary device interrupt\r
+ // 0: Enable Keyboard interrupt )\r
+ //\r
+ Status = KeyboardCommand (ConsoleIn, 0x60);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");\r
+ goto Done;\r
+ }\r
+\r
+ Status = KeyboardWrite (ConsoleIn, 0x67);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Clear Memory Scancode Buffer\r
+ //\r
+ ConsoleIn->ScancodeBufStartPos = 0;\r
+ ConsoleIn->ScancodeBufEndPos = KEYBOARD_BUFFER_MAX_COUNT - 1;\r
+ ConsoleIn->ScancodeBufCount = 0;\r
+ ConsoleIn->Ctrled = FALSE;\r
+ ConsoleIn->Alted = FALSE;\r
+\r
+ //\r
+ // Reset the status indicators\r
+ //\r
+ ConsoleIn->Ctrl = FALSE;\r
+ ConsoleIn->Alt = FALSE;\r
+ ConsoleIn->Shift = FALSE;\r
+ ConsoleIn->CapsLock = FALSE;\r
+ ConsoleIn->NumLock = FALSE;\r
+ ConsoleIn->ScrollLock = FALSE;\r
+\r
+ //\r
+ // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,\r
+ // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected\r
+ // to system. So we only do the real reseting for keyboard when user asks and there is a real KB connected t system,\r
+ // and normally during booting an OS, it's skipped.\r
+ //\r
+ if (ExtendedVerification && CheckKeyboardConnect (ConsoleIn)) {\r
+ //\r
+ // Additional verifications for keyboard interface\r
+ //\r
+ //\r
+ // Keyboard Interface Test\r
+ //\r
+ Status = KeyboardCommand (ConsoleIn, 0xab);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");\r
+ goto Done;\r
+ }\r
+\r
+ Status = KeyboardWaitForValue (ConsoleIn, 0x00);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (\r
+ ConsoleIn,\r
+ L"Some specific value not aquired from 8042 controller!\n\r"\r
+ );\r
+ goto Done;\r
+ }\r
+ //\r
+ // Keyboard reset with a BAT(Basic Assurance Test)\r
+ //\r
+ Status = KeyboardWrite (ConsoleIn, 0xff);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");\r
+ goto Done;\r
+ }\r
+\r
+ Status = KeyboardWaitForValue (ConsoleIn, 0xfa);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"Some specific value not aquired from 8042 controller!\n\r");\r
+ goto Done;\r
+ }\r
+ //\r
+ // wait for BAT completion code\r
+ //\r
+ mWaitForValueTimeOut = KEYBOARD_BAT_TIMEOUT;\r
+\r
+ Status = KeyboardWaitForValue (ConsoleIn, 0xaa);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"Keyboard self test failed!\n\r");\r
+ goto Done;\r
+ }\r
+\r
+ mWaitForValueTimeOut = KEYBOARD_WAITFORVALUE_TIMEOUT;\r
+\r
+ //\r
+ // Set Keyboard to use Scan Code Set 2\r
+ //\r
+ Status = KeyboardWrite (ConsoleIn, 0xf0);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");\r
+ goto Done;\r
+ }\r
+\r
+ Status = KeyboardWaitForValue (ConsoleIn, 0xfa);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"Some specific value not aquired from 8042 controller!\n\r");\r
+ goto Done;\r
+ }\r
+\r
+ Status = KeyboardWrite (ConsoleIn, 0x02);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"8042 controller data write error!!\n\r");\r
+ goto Done;\r
+ }\r
+\r
+ Status = KeyboardWaitForValue (ConsoleIn, 0xfa);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"Some specific value not aquired from 8042 controller!\n\r");\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Clear Keyboard Scancode Buffer\r
+ //\r
+ Status = KeyboardWrite (ConsoleIn, 0xf4);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");\r
+ goto Done;\r
+ }\r
+\r
+ Status = KeyboardWaitForValue (ConsoleIn, 0xfa);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"Some specific value not aquired from 8042 controller!\n\r");\r
+ goto Done;\r
+ }\r
+ //\r
+ if (Ps2Policy != NULL) {\r
+ if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_CAPSLOCK) == EFI_KEYBOARD_CAPSLOCK) {\r
+ ConsoleIn->CapsLock = TRUE;\r
+ }\r
+\r
+ if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_NUMLOCK) == EFI_KEYBOARD_NUMLOCK) {\r
+ ConsoleIn->NumLock = TRUE;\r
+ }\r
+\r
+ if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_SCROLLLOCK) == EFI_KEYBOARD_SCROLLLOCK) {\r
+ ConsoleIn->ScrollLock = TRUE;\r
+ }\r
+ }\r
+ //\r
+ // Update Keyboard Lights\r
+ //\r
+ Status = UpdateStatusLights (ConsoleIn);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"Update keyboard status lights error!\n\r");\r
+ goto Done;\r
+ }\r
+ }\r
+ //\r
+ // At last, we can now enable the mouse interface if appropriate\r
+ //\r
+Done:\r
+\r
+ if (EnableMouseInterface) {\r
+ //\r
+ // Enable mouse interface\r
+ //\r
+ Status1 = KeyboardCommand (ConsoleIn, 0xa8);\r
+ if (EFI_ERROR (Status1)) {\r
+ KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+}\r
+\r
+EFI_STATUS\r
+DisableKeyboard (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Disable the keyboard interface of the 8042 controller\r
+\r
+Arguments:\r
+\r
+ ConsoleIn - the device instance\r
+\r
+Returns:\r
+\r
+ EFI_STATUS\r
+\r
+--*/\r
+// GC_TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Disable keyboard interface\r
+ //\r
+ Status = KeyboardCommand (ConsoleIn, 0xad);\r
+ if (EFI_ERROR (Status)) {\r
+ KeyboardError (ConsoleIn, L"\n\r");\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command\r
+ If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device\r
+ should not be in system.\r
+\r
+ @param[in] BiosKeyboardPrivate Keyboard Private Data Structure\r
+\r
+ @retval TRUE Keyboard in System.\r
+ @retval FALSE Keyboard not in System.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+CheckKeyboardConnect (\r
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN WaitForValueTimeOutBcakup;\r
+\r
+ Status = EFI_SUCCESS;\r
+ //\r
+ // enable keyboard itself and wait for its ack\r
+ // If can't receive ack, Keyboard should not be connected.\r
+ //\r
+ Status = KeyboardWrite (\r
+ ConsoleIn,\r
+ KEYBOARD_KBEN\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+ //\r
+ // wait for 1s\r
+ //\r
+ WaitForValueTimeOutBcakup = mWaitForValueTimeOut;\r
+ mWaitForValueTimeOut = KEYBOARD_WAITFORVALUE_TIMEOUT;\r
+ Status = KeyboardWaitForValue (\r
+ ConsoleIn,\r
+ KEYBOARD_CMDECHO_ACK\r
+ );\r
+ mWaitForValueTimeOut = WaitForValueTimeOutBcakup;\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r