]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c
IntelFrameworkModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / Ps2KeyboardDxe / Ps2KbdTextIn.c
index fc613cac4feab00a5e2219311855e32931aa3cd9..1d167d171c861184532e1bd2cd1d5045d0cdcab7 100644 (file)
-/**@file\r
-  PS/2 Keyboard  driver\r
-  Routines that support SIMPLE_TEXT_IN protocol\r
+/** @file\r
+  Routines implements SIMPLE_TEXT_IN protocol's interfaces based on 8042 interfaces\r
+  provided by Ps2KbdCtrller.c.\r
 \r
-Copyright (c) 2006 - 2007, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution.  The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 \r
 #include "Ps2Keyboard.h"\r
 \r
-//\r
-// function declarations\r
-//\r
-EFI_STATUS\r
-EFIAPI\r
-KeyboardEfiReset (\r
-  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
-  IN  BOOLEAN                         ExtendedVerification\r
-  );\r
+/**\r
+  Check whether the EFI key buffer is empty.\r
 \r
-EFI_STATUS\r
-EFIAPI\r
-KeyboardReadKeyStroke (\r
-  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
-  OUT EFI_INPUT_KEY                   *Key\r
-  );\r
+  @param Queue     Pointer to instance of EFI_KEY_QUEUE.\r
 \r
-VOID\r
-EFIAPI\r
-KeyboardWaitForKey (\r
-  IN  EFI_EVENT               Event,\r
-  IN  VOID                    *Context\r
-  );\r
+  @retval TRUE    The EFI key buffer is empty.\r
+  @retval FALSE   The EFI key buffer isn't empty.\r
+**/\r
+BOOLEAN\r
+IsEfikeyBufEmpty (\r
+  IN  EFI_KEY_QUEUE         *Queue\r
+  )\r
+{\r
+  return (BOOLEAN) (Queue->Head == Queue->Tail);\r
+}\r
+\r
+/**\r
+  Read & remove one key data from the EFI key buffer.\r
 \r
+  @param Queue     Pointer to instance of EFI_KEY_QUEUE.\r
+  @param KeyData   Receive the key data.\r
+\r
+  @retval EFI_SUCCESS   The key data is popped successfully.\r
+  @retval EFI_NOT_READY There is no key data available.\r
+**/\r
 EFI_STATUS\r
-KeyboardCheckForKey (\r
-  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This\r
-  );\r
+PopEfikeyBufHead (\r
+  IN  EFI_KEY_QUEUE         *Queue,\r
+  OUT EFI_KEY_DATA          *KeyData OPTIONAL\r
+  )\r
+{\r
+  if (IsEfikeyBufEmpty (Queue)) {\r
+    return EFI_NOT_READY;\r
+  }\r
+  //\r
+  // Retrieve and remove the values\r
+  //\r
+  if (KeyData != NULL) {\r
+    CopyMem (KeyData, &Queue->Buffer[Queue->Head], sizeof (EFI_KEY_DATA));\r
+  }\r
+  Queue->Head = (Queue->Head + 1) % KEYBOARD_EFI_KEY_MAX_COUNT;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Push one key data to the EFI key buffer.\r
+\r
+  @param Queue     Pointer to instance of EFI_KEY_QUEUE.\r
+  @param KeyData   The key data to push.\r
+**/\r
+VOID\r
+PushEfikeyBufTail (\r
+  IN  EFI_KEY_QUEUE         *Queue,\r
+  IN  EFI_KEY_DATA          *KeyData\r
+  )\r
+{\r
+  if ((Queue->Tail + 1) % KEYBOARD_EFI_KEY_MAX_COUNT == Queue->Head) {\r
+    //\r
+    // If Queue is full, pop the one from head.\r
+    //\r
+    PopEfikeyBufHead (Queue, NULL);\r
+  }\r
+  CopyMem (&Queue->Buffer[Queue->Tail], KeyData, sizeof (EFI_KEY_DATA));\r
+  Queue->Tail = (Queue->Tail + 1) % KEYBOARD_EFI_KEY_MAX_COUNT;\r
+}\r
 \r
 /**\r
-  @param RegsiteredData    - A pointer to a buffer that is filled in with the keystroke \r
-                      state data for the key that was registered.\r
-  @param InputData         - A pointer to a buffer that is filled in with the keystroke \r
-                      state data for the key that was pressed.\r
-\r
-  @retval TRUE              - Key be pressed matches a registered key.\r
-  @retval FALSE             - Match failed. \r
-  \r
+  Judge whether is a registed key\r
+\r
+  @param RegsiteredData       A pointer to a buffer that is filled in with the keystroke\r
+                              state data for the key that was registered.\r
+  @param InputData            A pointer to a buffer that is filled in with the keystroke\r
+                              state data for the key that was pressed.\r
+\r
+  @retval TRUE                Key be pressed matches a registered key.\r
+  @retval FLASE               Match failed.\r
+\r
 **/\r
 BOOLEAN\r
 IsKeyRegistered (\r
   IN EFI_KEY_DATA  *RegsiteredData,\r
   IN EFI_KEY_DATA  *InputData\r
-  );\r
+  )\r
+\r
+{\r
+  ASSERT (RegsiteredData != NULL && InputData != NULL);\r
+\r
+  if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||\r
+      (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.\r
+  //\r
+  if (RegsiteredData->KeyState.KeyShiftState != 0 &&\r
+      RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {\r
+    return FALSE;\r
+  }\r
+  if (RegsiteredData->KeyState.KeyToggleState != 0 &&\r
+      RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+\r
+}\r
 \r
 /**\r
-    Reads the next keystroke from the input device. The WaitForKey Event can \r
+    Reads the next keystroke from the input device. The WaitForKey Event can\r
     be used to test for existance of a keystroke via WaitForEvent () call.\r
 \r
-  \r
-    @param ConsoleInDev          - Ps2 Keyboard private structure\r
-    @param KeyData               - A pointer to a buffer that is filled in with the keystroke \r
-                            state data for the key that was pressed.\r
+    @param ConsoleInDev          Ps2 Keyboard private structure\r
+    @param KeyData               A pointer to a buffer that is filled in with the keystroke\r
+                                 state data for the key that was pressed.\r
+\r
 \r
-  \r
-    @retval EFI_SUCCESS           - The keystroke information was returned.\r
-    @retval EFI_NOT_READY         - There was no keystroke data availiable.\r
-    @retval EFI_DEVICE_ERROR      - The keystroke information was not returned due to \r
-                            hardware errors.\r
-    @retval EFI_INVALID_PARAMETER - KeyData is NULL.                        \r
+    @retval EFI_SUCCESS             The keystroke information was returned.\r
+    @retval EFI_NOT_READY           There was no keystroke data availiable.\r
+    @retval EFI_DEVICE_ERROR        The keystroke information was not returned due to\r
+                                    hardware errors.\r
+    @retval EFI_INVALID_PARAMETER   KeyData is NULL.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -87,80 +143,39 @@ KeyboardReadKeyStrokeWorker (
 {\r
   EFI_STATUS                            Status;\r
   EFI_TPL                               OldTpl;\r
-  LIST_ENTRY                            *Link;\r
-  KEYBOARD_CONSOLE_IN_EX_NOTIFY         *CurrentNotify;\r
-  EFI_KEY_DATA                          OriginalKeyData;\r
+\r
   if (KeyData == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
+\r
   //\r
   // Enter critical section\r
   //\r
   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
 \r
+  KeyboardTimerHandler (NULL, ConsoleInDev);\r
+\r
   if (ConsoleInDev->KeyboardErr) {\r
-    gBS->RestoreTPL (OldTpl);\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
-  //\r
-  // If there's no key, just return\r
-  //\r
-  Status = KeyboardCheckForKey (&ConsoleInDev->ConIn);\r
-  if (EFI_ERROR (Status)) {\r
-    gBS->RestoreTPL (OldTpl);\r
-    return EFI_NOT_READY;\r
-  }\r
-  CopyMem (&KeyData->Key, &ConsoleInDev->Key, sizeof (EFI_INPUT_KEY));\r
-\r
-  ConsoleInDev->Key.ScanCode    = SCAN_NULL;          \r
-  ConsoleInDev->Key.UnicodeChar = 0x0000;     \r
-  CopyMem (&KeyData->KeyState, &ConsoleInDev->KeyState, sizeof (EFI_KEY_STATE));\r
-                                          \r
-  ConsoleInDev->KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID;\r
-  ConsoleInDev->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;\r
-  gBS->RestoreTPL (OldTpl);\r
-  //\r
-  //Switch the control value to their original characters. In KeyGetchar() the  CTRL-Alpha characters have been switched to \r
-  // their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A), here switch them back for notification function.\r
-  //\r
-  CopyMem (&OriginalKeyData, KeyData, sizeof (EFI_KEY_DATA));\r
-  if (ConsoleInDev->Ctrled) {\r
-    if (OriginalKeyData.Key.UnicodeChar >= 0x01 && OriginalKeyData.Key.UnicodeChar <= 0x1A) {\r
-      if (ConsoleInDev->CapsLock) {\r
-        OriginalKeyData.Key.UnicodeChar = (CHAR16)(OriginalKeyData.Key.UnicodeChar + 'A' - 1);\r
-      } else {\r
-        OriginalKeyData.Key.UnicodeChar = (CHAR16)(OriginalKeyData.Key.UnicodeChar + 'a' - 1);\r
-      } \r
-    }\r
-  }\r
-  //\r
-  // Invoke notification functions if exist\r
-  //\r
-  for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) {\r
-    CurrentNotify = CR (\r
-                      Link, \r
-                      KEYBOARD_CONSOLE_IN_EX_NOTIFY, \r
-                      NotifyEntry, \r
-                      KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
-                      );\r
-    if (IsKeyRegistered (&CurrentNotify->KeyData, &OriginalKeyData)) { \r
-      CurrentNotify->KeyNotificationFn (&OriginalKeyData);\r
+    Status = EFI_DEVICE_ERROR;\r
+  } else {\r
+    Status = PopEfikeyBufHead (&ConsoleInDev->EfiKeyQueue, KeyData);\r
+    if (Status == EFI_NOT_READY) {\r
+      ZeroMem (&KeyData->Key, sizeof (KeyData->Key));\r
+      InitializeKeyState (ConsoleInDev, &KeyData->KeyState);\r
     }\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
 }\r
 \r
 /**\r
-  logic reset keyboard\r
-  Implement SIMPLE_TEXT_IN.Reset()\r
-  Perform 8042 controller and keyboard initialization\r
+  Perform 8042 controller and keyboard initialization which implement SIMPLE_TEXT_IN.Reset()\r
 \r
-  @param This    Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL\r
-  @param ExtendedVerification Indicate that the driver may perform a more \r
-                              exhaustive verification operation of the device during \r
-                              reset, now this par is ignored in this driver    \r
+  @param This                 Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL\r
+  @param ExtendedVerification Indicate that the driver may perform a more\r
+                              exhaustive verification operation of the device during\r
+                              reset, now this par is ignored in this driver\r
 \r
 **/\r
 EFI_STATUS\r
@@ -201,11 +216,6 @@ KeyboardEfiReset (
     gBS->RestoreTPL (OldTpl);\r
     return EFI_DEVICE_ERROR;\r
   }\r
-  //\r
-  // Clear the status of ConsoleIn.Key\r
-  //\r
-  ConsoleIn->Key.ScanCode     = SCAN_NULL;\r
-  ConsoleIn->Key.UnicodeChar  = 0x0000;\r
 \r
   //\r
   // Leave critical section and return\r
@@ -225,7 +235,7 @@ KeyboardEfiReset (
   //\r
   // Report the status If keyboard is locked\r
   //\r
-  if (!(KeyReadStatusRegister (ConsoleIn) & 0x10)) {\r
+  if ((KeyReadStatusRegister (ConsoleIn) & 0x10) == 0) {\r
     REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
       EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
       EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_EC_LOCKED,\r
@@ -237,11 +247,10 @@ KeyboardEfiReset (
 }\r
 \r
 /**\r
-  Implement SIMPLE_TEXT_IN.ReadKeyStroke().\r
-  Retrieve key values for driver user.\r
+  Retrieve key values for driver user which implement SIMPLE_TEXT_IN.ReadKeyStroke().\r
 \r
   @param This    Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL\r
-  @param Key     The output buffer for key value \r
+  @param Key     The output buffer for key value\r
 \r
   @retval EFI_SUCCESS success to read key stroke\r
 **/\r
@@ -257,14 +266,41 @@ KeyboardReadKeyStroke (
   EFI_KEY_DATA            KeyData;\r
 \r
   ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);\r
-  Status = KeyboardReadKeyStrokeWorker (ConsoleIn, &KeyData);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
 \r
-  CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
-  return EFI_SUCCESS;\r
-  \r
+  //\r
+  // Considering if the partial keystroke is enabled, there maybe a partial\r
+  // keystroke in the queue, so here skip the partial keystroke and get the\r
+  // next key from the queue\r
+  //\r
+  while (1) {\r
+    //\r
+    // If there is no pending key, then return.\r
+    //\r
+    Status = KeyboardReadKeyStrokeWorker (ConsoleIn, &KeyData);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // If it is partial keystroke, skip it.\r
+    //\r
+    if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {\r
+      continue;\r
+    }\r
+    //\r
+    // Translate the CTRL-Alpha characters to their corresponding control value\r
+    // (ctrl-a = 0x0001 through ctrl-Z = 0x001A)\r
+    //\r
+    if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {\r
+      if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {\r
+        KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);\r
+      } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {\r
+        KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);\r
+      }\r
+    }\r
+\r
+    CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
+    return EFI_SUCCESS;\r
+  }\r
 }\r
 \r
 /**\r
@@ -282,104 +318,47 @@ KeyboardWaitForKey (
   IN  VOID                    *Context\r
   )\r
 {\r
-  EFI_TPL                 OldTpl;\r
-  KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;\r
+  EFI_TPL                     OldTpl;\r
+  KEYBOARD_CONSOLE_IN_DEV     *ConsoleIn;\r
+  EFI_KEY_DATA                KeyData;\r
 \r
-  ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (Context);\r
+  ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *) Context;\r
 \r
   //\r
   // Enter critical section\r
   //\r
   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
 \r
-  if (ConsoleIn->KeyboardErr) {\r
+  KeyboardTimerHandler (NULL, ConsoleIn);\r
+\r
+  if (!ConsoleIn->KeyboardErr) {\r
     //\r
-    // Leave critical section and return\r
+    // WaitforKey doesn't suppor the partial key.\r
+    // Considering if the partial keystroke is enabled, there maybe a partial\r
+    // keystroke in the queue, so here skip the partial keystroke and get the\r
+    // next key from the queue\r
     //\r
-    gBS->RestoreTPL (OldTpl);\r
-    return ;\r
-  }\r
-  //\r
-  // Someone is waiting on the keyboard event, if there's\r
-  // a key pending, signal the event\r
-  //\r
-  if (!EFI_ERROR (KeyboardCheckForKey (Context))) {\r
-    gBS->SignalEvent (Event);\r
+    while (!IsEfikeyBufEmpty (&ConsoleIn->EfiKeyQueue)) {\r
+      CopyMem (\r
+        &KeyData,\r
+        &(ConsoleIn->EfiKeyQueue.Buffer[ConsoleIn->EfiKeyQueue.Head]),\r
+        sizeof (EFI_KEY_DATA)\r
+        );\r
+      if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {\r
+        PopEfikeyBufHead (&ConsoleIn->EfiKeyQueue, &KeyData);\r
+        continue;\r
+      }\r
+      //\r
+      // if there is pending value key, signal the event.\r
+      //\r
+      gBS->SignalEvent (Event);\r
+      break;\r
+    }\r
   }\r
   //\r
   // Leave critical section and return\r
   //\r
   gBS->RestoreTPL (OldTpl);\r
-\r
-  return ;\r
-}\r
-\r
-/**\r
-  Check keyboard for given key value\r
-  \r
-  @param  This  Point to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL\r
-  \r
-  @retval EFI_SUCCESS success check keyboard value\r
-**/\r
-EFI_STATUS\r
-KeyboardCheckForKey (\r
-  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This\r
-  )\r
-{\r
-  KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;\r
-\r
-  ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);\r
-\r
-  //\r
-  // If ready to read next key, check it\r
-  //\r
-  if (ConsoleIn->Key.ScanCode == SCAN_NULL && ConsoleIn->Key.UnicodeChar == 0x00) {\r
-    return KeyGetchar (ConsoleIn);\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
-  Judge whether is a registed key\r
-\r
-  @param RegsiteredData    - A pointer to a buffer that is filled in with the keystroke \r
-                      state data for the key that was registered.\r
-  @param InputData         - A pointer to a buffer that is filled in with the keystroke \r
-                      state data for the key that was pressed.\r
-\r
-  @retval TRUE              - Key be pressed matches a registered key.\r
-  @retval FLASE             - Match failed. \r
-  \r
-**/\r
-BOOLEAN\r
-IsKeyRegistered (\r
-  IN EFI_KEY_DATA  *RegsiteredData,\r
-  IN EFI_KEY_DATA  *InputData\r
-  )\r
-\r
-{\r
-  ASSERT (RegsiteredData != NULL && InputData != NULL);\r
-  \r
-  if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||\r
-      (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {\r
-    return FALSE;  \r
-  }      \r
-  \r
-  //\r
-  // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.\r
-  //\r
-  if (RegsiteredData->KeyState.KeyShiftState != 0 &&\r
-      RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {\r
-    return FALSE;    \r
-  }   \r
-  if (RegsiteredData->KeyState.KeyToggleState != 0 &&\r
-      RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {\r
-    return FALSE;    \r
-  }     \r
-  \r
-  return TRUE;\r
-\r
 }\r
 \r
 /**\r
@@ -398,21 +377,17 @@ KeyboardWaitForKeyEx (
   )\r
 \r
 {\r
-  KEYBOARD_CONSOLE_IN_DEV               *ConsoleInDev;\r
-\r
-  ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (Context); \r
-  KeyboardWaitForKey (Event, &ConsoleInDev->ConIn);\r
-  \r
+  KeyboardWaitForKey (Event, Context);\r
 }\r
 \r
 /**\r
   Reset the input device and optionaly run diagnostics\r
 \r
-  @param This                 - Protocol instance pointer.\r
-  @param ExtendedVerification - Driver may perform diagnostics on reset.\r
+  @param This                     Protocol instance pointer.\r
+  @param ExtendedVerification     Driver may perform diagnostics on reset.\r
 \r
-  @retval EFI_SUCCESS           - The device was reset.\r
-  @retval EFI_DEVICE_ERROR      - The device is not functioning properly and could \r
+  @retval EFI_SUCCESS             The device was reset.\r
+  @retval EFI_DEVICE_ERROR        The device is not functioning properly and could\r
                                   not be reset.\r
 \r
 **/\r
@@ -424,47 +399,30 @@ KeyboardEfiResetEx (
   )\r
 \r
 {\r
-  EFI_STATUS                            Status;\r
   KEYBOARD_CONSOLE_IN_DEV               *ConsoleInDev;\r
-  EFI_TPL                               OldTpl;\r
 \r
-  ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This); \r
-  if (ConsoleInDev->KeyboardErr) {\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
-\r
-  Status = ConsoleInDev->ConIn.Reset (\r
-                                 &ConsoleInDev->ConIn, \r
-                                 ExtendedVerification\r
-                                 );\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
-\r
-  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
-\r
-  ConsoleInDev->KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID;\r
-  ConsoleInDev->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;\r
+  ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);\r
 \r
-  gBS->RestoreTPL (OldTpl);  \r
-  \r
-  return EFI_SUCCESS;\r
+  return ConsoleInDev->ConIn.Reset (\r
+                               &ConsoleInDev->ConIn,\r
+                               ExtendedVerification\r
+                               );\r
 }\r
 \r
 /**\r
-    Reads the next keystroke from the input device. The WaitForKey Event can \r
+    Reads the next keystroke from the input device. The WaitForKey Event can\r
     be used to test for existance of a keystroke via WaitForEvent () call.\r
 \r
 \r
-    @param This       - Protocol instance pointer.\r
-    @param KeyData    - A pointer to a buffer that is filled in with the keystroke \r
-                 state data for the key that was pressed.\r
+    @param This         Protocol instance pointer.\r
+    @param KeyData      A pointer to a buffer that is filled in with the keystroke\r
+                        state data for the key that was pressed.\r
 \r
-    @retval EFI_SUCCESS           The keystroke information was returned.\r
-    @retval EFI_NOT_READY         There was no keystroke data availiable.\r
-    @retval EFI_DEVICE_ERROR      - The keystroke information was not returned due to \r
-                            hardware errors.\r
-    @retval EFI_INVALID_PARAMETER - KeyData is NULL.                        \r
+    @retval EFI_SUCCESS           The keystroke information was returned.\r
+    @retval EFI_NOT_READY         There was no keystroke data availiable.\r
+    @retval EFI_DEVICE_ERROR      The keystroke information was not returned due to\r
+                                  hardware errors.\r
+    @retval EFI_INVALID_PARAMETER KeyData is NULL.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -483,23 +441,22 @@ KeyboardReadKeyStrokeEx (
 \r
   ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);\r
   return KeyboardReadKeyStrokeWorker (ConsoleInDev, KeyData);\r
-  \r
 }\r
 \r
 /**\r
   Set certain state for the input device.\r
 \r
-  @param This              - Protocol instance pointer.\r
-  @param KeyToggleState    - A pointer to the EFI_KEY_TOGGLE_STATE to set the \r
-                        state for the input device.\r
+  @param This               Protocol instance pointer.\r
+  @param KeyToggleState     A pointer to the EFI_KEY_TOGGLE_STATE to set the\r
+                            state for the input device.\r
 \r
-  @retval EFI_SUCCESS           The device state was set successfully.\r
-  @retval EFI_DEVICE_ERROR      - The device is not functioning correctly and could \r
-                            not have the setting adjusted.\r
-  @retval EFI_UNSUPPORTED       The device does not have the ability to set its state.\r
-  @retval EFI_INVALID_PARAMETER - KeyToggleState is NULL.                       \r
+  @retval EFI_SUCCESS           The device state was set successfully.\r
+  @retval EFI_DEVICE_ERROR      The device is not functioning correctly and could\r
+                                not have the setting adjusted.\r
+  @retval EFI_UNSUPPORTED       The device does not have the ability to set its state.\r
+  @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.\r
 \r
-**/   \r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 KeyboardSetState (\r
@@ -515,7 +472,7 @@ KeyboardSetState (
   if (KeyToggleState == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
+\r
   ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);\r
 \r
   //\r
@@ -528,37 +485,38 @@ KeyboardSetState (
     goto Exit;\r
   }\r
 \r
-  if (((ConsoleInDev->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||\r
-      ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {\r
+  if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) {\r
     Status = EFI_UNSUPPORTED;\r
     goto Exit;\r
   }\r
-  \r
+\r
   //\r
   // Update the status light\r
   //\r
-  ConsoleInDev->ScrollLock = FALSE;\r
-  ConsoleInDev->NumLock    = FALSE;\r
-  ConsoleInDev->CapsLock   = FALSE;\r
+  ConsoleInDev->ScrollLock          = FALSE;\r
+  ConsoleInDev->NumLock             = FALSE;\r
+  ConsoleInDev->CapsLock            = FALSE;\r
+  ConsoleInDev->IsSupportPartialKey = FALSE;\r
 \r
   if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {\r
     ConsoleInDev->ScrollLock = TRUE;\r
-  } \r
+  }\r
   if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {\r
     ConsoleInDev->NumLock = TRUE;\r
   }\r
   if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {\r
     ConsoleInDev->CapsLock = TRUE;\r
   }\r
+  if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {\r
+    ConsoleInDev->IsSupportPartialKey = TRUE;\r
+  }\r
 \r
   Status = UpdateStatusLights (ConsoleInDev);\r
   if (EFI_ERROR (Status)) {\r
-    Status = EFI_DEVICE_ERROR;    \r
+    Status = EFI_DEVICE_ERROR;\r
   }\r
 \r
-  ConsoleInDev->KeyState.KeyToggleState = *KeyToggleState;\r
-  \r
-Exit:   \r
+Exit:\r
   //\r
   // Leave critical section and return\r
   //\r
@@ -571,38 +529,42 @@ Exit:
 /**\r
     Register a notification function for a particular keystroke for the input device.\r
 \r
-    @param This                    - Protocol instance pointer.\r
-    @param KeyData                 - A pointer to a buffer that is filled in with the keystroke \r
-                              information data for the key that was pressed.\r
-    @param KeyNotificationFunction - Points to the function to be called when the key \r
-                              sequence is typed specified by KeyData.                        \r
-    @param NotifyHandle            - Points to the unique handle assigned to the registered notification.                          \r
-\r
-    @retval EFI_SUCCESS             - The notification function was registered successfully.\r
-    @retval EFI_OUT_OF_RESOURCES    - Unable to allocate resources for necesssary data structures.\r
-    @retval EFI_INVALID_PARAMETER   - KeyData or NotifyHandle is NULL.                       \r
-                              \r
-**/   \r
+    @param This                       Protocol instance pointer.\r
+    @param KeyData                    A pointer to a buffer that is filled in with the keystroke\r
+                                      information data for the key that was pressed. If KeyData.Key,\r
+                                      KeyData.KeyState.KeyToggleState and KeyData.KeyState.KeyShiftState\r
+                                      are 0, then any incomplete keystroke will trigger a notification of\r
+                                      the KeyNotificationFunction.\r
+    @param KeyNotificationFunction    Points to the function to be called when the key\r
+                                      sequence is typed specified by KeyData. This notification function\r
+                                      should be called at <=TPL_CALLBACK.\r
+    @param NotifyHandle               Points to the unique handle assigned to the registered notification.\r
+\r
+    @retval EFI_SUCCESS               The notification function was registered successfully.\r
+    @retval EFI_OUT_OF_RESOURCES      Unable to allocate resources for necesssary data structures.\r
+    @retval EFI_INVALID_PARAMETER     KeyData or NotifyHandle or KeyNotificationFunction is NULL.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 KeyboardRegisterKeyNotify (\r
   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
   IN EFI_KEY_DATA                       *KeyData,\r
   IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,\r
-  OUT EFI_HANDLE                        *NotifyHandle\r
+  OUT VOID                              **NotifyHandle\r
   )\r
 {\r
   EFI_STATUS                            Status;\r
   KEYBOARD_CONSOLE_IN_DEV               *ConsoleInDev;\r
   EFI_TPL                               OldTpl;\r
   LIST_ENTRY                            *Link;\r
-  KEYBOARD_CONSOLE_IN_EX_NOTIFY         *CurrentNotify;  \r
+  KEYBOARD_CONSOLE_IN_EX_NOTIFY         *CurrentNotify;\r
   KEYBOARD_CONSOLE_IN_EX_NOTIFY         *NewNotify;\r
 \r
   if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
+\r
   ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);\r
 \r
   //\r
@@ -615,45 +577,35 @@ KeyboardRegisterKeyNotify (
   //\r
   for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) {\r
     CurrentNotify = CR (\r
-                      Link, \r
-                      KEYBOARD_CONSOLE_IN_EX_NOTIFY, \r
-                      NotifyEntry, \r
+                      Link,\r
+                      KEYBOARD_CONSOLE_IN_EX_NOTIFY,\r
+                      NotifyEntry,\r
                       KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
                       );\r
-    if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { \r
+    if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {\r
       if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {\r
-        *NotifyHandle = CurrentNotify->NotifyHandle;        \r
+        *NotifyHandle = CurrentNotify;\r
         Status = EFI_SUCCESS;\r
         goto Exit;\r
       }\r
     }\r
-  }    \r
-  \r
+  }\r
+\r
   //\r
   // Allocate resource to save the notification function\r
-  //  \r
+  //\r
   NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));\r
   if (NewNotify == NULL) {\r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto Exit;\r
   }\r
 \r
-  NewNotify->Signature         = KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;     \r
+  NewNotify->Signature         = KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;\r
   NewNotify->KeyNotificationFn = KeyNotificationFunction;\r
   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));\r
   InsertTailList (&ConsoleInDev->NotifyList, &NewNotify->NotifyEntry);\r
 \r
-  //\r
-  // Use gSimpleTextInExNotifyGuid to get a valid EFI_HANDLE\r
-  //  \r
-  Status = gBS->InstallMultipleProtocolInterfaces (\r
-                  &NewNotify->NotifyHandle,\r
-                  &gSimpleTextInExNotifyGuid,\r
-                  NULL,\r
-                  NULL\r
-                  );\r
-  ASSERT_EFI_ERROR (Status);\r
-  *NotifyHandle                = NewNotify->NotifyHandle;  \r
+  *NotifyHandle                = NewNotify;\r
   Status                       = EFI_SUCCESS;\r
 \r
 Exit:\r
@@ -661,78 +613,59 @@ Exit:
   // Leave critical section and return\r
   //\r
   gBS->RestoreTPL (OldTpl);\r
-  return Status;  \r
+  return Status;\r
 \r
 }\r
 \r
 /**\r
     Remove a registered notification function from a particular keystroke.\r
 \r
-    @param This                    - Protocol instance pointer.    \r
-    @param NotificationHandle      - The handle of the notification function being unregistered.\r
+    @param This                       Protocol instance pointer.\r
+    @param NotificationHandle         The handle of the notification function being unregistered.\r
 \r
-  \r
-    @retval EFI_SUCCESS             - The notification function was unregistered successfully.\r
-    @retval EFI_INVALID_PARAMETER   - The NotificationHandle is invalid.\r
-    @retval EFI_NOT_FOUND           - Can not find the matching entry in database.  \r
-                              \r
-**/   \r
+\r
+    @retval EFI_SUCCESS               The notification function was unregistered successfully.\r
+    @retval EFI_INVALID_PARAMETER     The NotificationHandle is invalid.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 KeyboardUnregisterKeyNotify (\r
   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
-  IN EFI_HANDLE                         NotificationHandle\r
+  IN VOID                               *NotificationHandle\r
   )\r
 {\r
   EFI_STATUS                            Status;\r
   KEYBOARD_CONSOLE_IN_DEV               *ConsoleInDev;\r
   EFI_TPL                               OldTpl;\r
   LIST_ENTRY                            *Link;\r
-  KEYBOARD_CONSOLE_IN_EX_NOTIFY         *CurrentNotify;    \r
+  KEYBOARD_CONSOLE_IN_EX_NOTIFY         *CurrentNotify;\r
 \r
   if (NotificationHandle == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
-  } \r
-  \r
-  Status = gBS->OpenProtocol (\r
-                  NotificationHandle,\r
-                  &gSimpleTextInExNotifyGuid,\r
-                  NULL,\r
-                  NULL,\r
-                  NULL,\r
-                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);\r
-  \r
+\r
   //\r
   // Enter critical section\r
   //\r
-  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);  \r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
 \r
   for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) {\r
     CurrentNotify = CR (\r
-                      Link, \r
-                      KEYBOARD_CONSOLE_IN_EX_NOTIFY, \r
-                      NotifyEntry, \r
+                      Link,\r
+                      KEYBOARD_CONSOLE_IN_EX_NOTIFY,\r
+                      NotifyEntry,\r
                       KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
-                      );       \r
-    if (CurrentNotify->NotifyHandle == NotificationHandle) {\r
+                      );\r
+    if (CurrentNotify == NotificationHandle) {\r
       //\r
       // Remove the notification function from NotifyList and free resources\r
       //\r
-      RemoveEntryList (&CurrentNotify->NotifyEntry);      \r
-      Status = gBS->UninstallMultipleProtocolInterfaces (\r
-                      CurrentNotify->NotifyHandle,\r
-                      &gSimpleTextInExNotifyGuid,\r
-                      NULL,\r
-                      NULL\r
-                      );\r
-      ASSERT_EFI_ERROR (Status);\r
-      gBS->FreePool (CurrentNotify);            \r
+      RemoveEntryList (&CurrentNotify->NotifyEntry);\r
+\r
+      gBS->FreePool (CurrentNotify);\r
       Status = EFI_SUCCESS;\r
       goto Exit;\r
     }\r
@@ -741,7 +674,7 @@ KeyboardUnregisterKeyNotify (
   //\r
   // Can not find the specified Notification Handle\r
   //\r
-  Status = EFI_NOT_FOUND;\r
+  Status = EFI_INVALID_PARAMETER;\r
 Exit:\r
   //\r
   // Leave critical section and return\r
@@ -750,3 +683,52 @@ Exit:
   return Status;\r
 }\r
 \r
+/**\r
+  Process key notify.\r
+\r
+  @param  Event                 Indicates the event that invoke this function.\r
+  @param  Context               Indicates the calling context.\r
+**/\r
+VOID\r
+EFIAPI\r
+KeyNotifyProcessHandler (\r
+  IN  EFI_EVENT                 Event,\r
+  IN  VOID                      *Context\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  KEYBOARD_CONSOLE_IN_DEV       *ConsoleIn;\r
+  EFI_KEY_DATA                  KeyData;\r
+  LIST_ENTRY                    *Link;\r
+  LIST_ENTRY                    *NotifyList;\r
+  KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
+  EFI_TPL                       OldTpl;\r
+\r
+  ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *) Context;\r
+\r
+  //\r
+  // Invoke notification functions.\r
+  //\r
+  NotifyList = &ConsoleIn->NotifyList;\r
+  while (TRUE) {\r
+    //\r
+    // Enter critical section\r
+    //\r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+    Status = PopEfikeyBufHead (&ConsoleIn->EfiKeyQueueForNotify, &KeyData);\r
+    //\r
+    // Leave critical section\r
+    //\r
+    gBS->RestoreTPL (OldTpl);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {\r
+      CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE);\r
+      if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
+        CurrentNotify->KeyNotificationFn (&KeyData);\r
+      }\r
+    }\r
+  }\r
+}\r
+\r