]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c
IntelFrameworkModulePkg/KeyboardDxe: Use macro to enable/disable page 0
[mirror_edk2.git] / IntelFrameworkModulePkg / Csm / BiosThunk / KeyboardDxe / BiosKeyboard.c
index 24578aab8176ae8f8cecfdf4f28ba871abead753..ec525891dc7a5659af89d1151a008ee1cc84fd4f 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   ConsoleOut Routines that speak VGA.\r
 \r
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>\r
 \r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions\r
@@ -272,6 +272,8 @@ BiosKeyboardDriverBindingStart (
   \r
   BiosKeyboardPrivate->Queue.Front                = 0;\r
   BiosKeyboardPrivate->Queue.Rear                 = 0;\r
+  BiosKeyboardPrivate->QueueForNotify.Front       = 0;\r
+  BiosKeyboardPrivate->QueueForNotify.Rear        = 0;\r
   BiosKeyboardPrivate->SimpleTextInputEx.Reset               = BiosKeyboardResetEx;\r
   BiosKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx     = BiosKeyboardReadKeyStrokeEx;\r
   BiosKeyboardPrivate->SimpleTextInputEx.SetState            = BiosKeyboardSetState;\r
@@ -279,19 +281,12 @@ BiosKeyboardDriverBindingStart (
   BiosKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = BiosKeyboardUnregisterKeyNotify;    \r
   InitializeListHead (&BiosKeyboardPrivate->NotifyList);\r
 \r
-  Status = gBS->HandleProtocol (\r
-                  Controller,\r
-                  &gEfiDevicePathProtocolGuid,\r
-                  (VOID **) &BiosKeyboardPrivate->DevicePath\r
-                  );\r
-\r
   //\r
   // Report that the keyboard is being enabled\r
   //\r
-  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+  REPORT_STATUS_CODE (\r
     EFI_PROGRESS_CODE,\r
-    EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE,\r
-    BiosKeyboardPrivate->DevicePath\r
+    EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE\r
     );\r
 \r
   //\r
@@ -346,14 +341,26 @@ BiosKeyboardDriverBindingStart (
     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;\r
     goto Done;\r
   }\r
-  \r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  KeyNotifyProcessHandler,\r
+                  BiosKeyboardPrivate,\r
+                  &BiosKeyboardPrivate->KeyNotifyProcessEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    Status      = EFI_OUT_OF_RESOURCES;\r
+    StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;\r
+    goto Done;\r
+  }\r
+\r
   //\r
   // Report a Progress Code for an attempt to detect the precense of the keyboard device in the system\r
   //\r
-  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+  REPORT_STATUS_CODE (\r
     EFI_PROGRESS_CODE,\r
-    EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT,\r
-    BiosKeyboardPrivate->DevicePath\r
+    EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT\r
     );\r
 \r
   //\r
@@ -411,7 +418,7 @@ BiosKeyboardDriverBindingStart (
     // Check bit 6 of Feature Byte 2.\r
     // If it is set, then Int 16 Func 09 is supported\r
     //\r
-    if (*(UINT8 *)(UINTN) ((Regs.X.ES << 4) + Regs.X.BX + 0x06) & 0x40) {\r
+    if (*(UINT8 *) (((UINTN) Regs.X.ES << 4) + Regs.X.BX + 0x06) & 0x40) {\r
       //\r
       // Get Keyboard Functionality\r
       //\r
@@ -454,10 +461,9 @@ Done:
     //\r
     // Report an Error Code for failing to start the keyboard device\r
     //\r
-    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    REPORT_STATUS_CODE (\r
       EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
-      StatusCode,\r
-      BiosKeyboardPrivate->DevicePath\r
+      StatusCode\r
       );\r
   }\r
 \r
@@ -471,6 +477,11 @@ Done:
       if ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) {\r
         gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx);    \r
       }\r
+\r
+      if (BiosKeyboardPrivate->KeyNotifyProcessEvent != NULL) {\r
+        gBS->CloseEvent (BiosKeyboardPrivate->KeyNotifyProcessEvent);\r
+      }\r
+\r
       BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);\r
 \r
       if (BiosKeyboardPrivate->TimerEvent != NULL) {\r
@@ -575,6 +586,7 @@ BiosKeyboardDriverBindingStop (
   gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);\r
   gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);\r
   gBS->CloseEvent (BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx);\r
+  gBS->CloseEvent (BiosKeyboardPrivate->KeyNotifyProcessEvent);\r
   BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);\r
 \r
   FreePool (BiosKeyboardPrivate);\r
@@ -943,7 +955,7 @@ KeyboardReadKeyStrokeWorker (
   }\r
 \r
   //\r
-  // Use TimerEvent callback funciton to check whether there's any key pressed\r
+  // Use TimerEvent callback function to check whether there's any key pressed\r
   //\r
   \r
   //\r
@@ -987,7 +999,7 @@ KeyboardReadKeyStrokeWorker (
   @param  ExtendedVerification  Whether perform the extra validation of keyboard. True: perform; FALSE: skip.\r
 \r
   @retval EFI_SUCCESS           The command byte is written successfully.\r
-  @retval EFI_DEVICE_ERROR      Errors occurred during reseting keyboard.\r
+  @retval EFI_DEVICE_ERROR      Errors occurred during resetting keyboard.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -1011,19 +1023,17 @@ BiosKeyboardReset (
   // 1\r
   // Report reset progress code\r
   //\r
-  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+  REPORT_STATUS_CODE (\r
     EFI_PROGRESS_CODE,\r
-    EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET,\r
-    BiosKeyboardPrivate->DevicePath\r
+    EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET\r
     );\r
 \r
   //\r
   // Report a Progress Code for clearing the keyboard buffer\r
   //\r
-  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+  REPORT_STATUS_CODE (\r
     EFI_PROGRESS_CODE,\r
-    EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER,\r
-    BiosKeyboardPrivate->DevicePath\r
+    EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER\r
     );\r
 \r
   //\r
@@ -1048,96 +1058,96 @@ BiosKeyboardReset (
   // if not skip step 4&5 and jump to step 6 to selftest KBC and report this\r
   // else   go step 4\r
   //\r
-  if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_SYSF) != 0) {\r
-    //\r
-    // 4\r
-    // CheckMouseStatus to decide enable it later or not\r
-    //\r
-    //\r
-    // Read the command byte of KBC\r
-    //\r
-    Status = KeyboardCommand (\r
-               BiosKeyboardPrivate,\r
-               KBC_CMDREG_VIA64_CMDBYTE_R\r
-               );\r
-\r
-    if (EFI_ERROR (Status)) {\r
-      Status    = EFI_DEVICE_ERROR;\r
-      goto Exit;\r
-    }\r
-\r
-    Status = KeyboardRead (\r
-               BiosKeyboardPrivate,\r
-               &CommandByte\r
-               );\r
-\r
-    if (EFI_ERROR (Status)) {\r
-      Status    = EFI_DEVICE_ERROR;\r
-      goto Exit;\r
-    }\r
-    //\r
-    // Check mouse enabled or not before\r
-    //\r
-    if ((CommandByte & KB_CMMBYTE_DISABLE_AUX) != 0) {\r
-      MouseEnable = FALSE;\r
+  if (!PcdGetBool (PcdFastPS2Detection)) {\r
+    if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_SYSF) != 0) {\r
+      //\r
+      // 4\r
+      // CheckMouseStatus to decide enable it later or not\r
+      //\r
+      //\r
+      // Read the command byte of KBC\r
+      //\r
+      Status = KeyboardCommand (\r
+                 BiosKeyboardPrivate,\r
+                 KBC_CMDREG_VIA64_CMDBYTE_R\r
+                 );\r
+      \r
+      if (EFI_ERROR (Status)) {\r
+        Status    = EFI_DEVICE_ERROR;\r
+        goto Exit;\r
+      }\r
+      \r
+      Status = KeyboardRead (\r
+                 BiosKeyboardPrivate,\r
+                 &CommandByte\r
+                 );\r
+      \r
+      if (EFI_ERROR (Status)) {\r
+        Status    = EFI_DEVICE_ERROR;\r
+        goto Exit;\r
+      }\r
+      //\r
+      // Check mouse enabled or not before\r
+      //\r
+      if ((CommandByte & KB_CMMBYTE_DISABLE_AUX) != 0) {\r
+        MouseEnable = FALSE;\r
+      } else {\r
+        MouseEnable = TRUE;\r
+      }\r
+      //\r
+      // 5\r
+      // disable mouse (via KBC) and Keyborad device\r
+      //\r
+      Status = KeyboardCommand (\r
+                 BiosKeyboardPrivate,\r
+                 KBC_CMDREG_VIA64_AUX_DISABLE\r
+                 );\r
+      \r
+      if (EFI_ERROR (Status)) {\r
+        Status    = EFI_DEVICE_ERROR;\r
+        goto Exit;\r
+      }\r
+      \r
+      Status = KeyboardCommand (\r
+                 BiosKeyboardPrivate,\r
+                 KBC_CMDREG_VIA64_KB_DISABLE\r
+                 );\r
+      \r
+      if (EFI_ERROR (Status)) {\r
+        Status    = EFI_DEVICE_ERROR;\r
+        goto Exit;\r
+      }\r
     } else {\r
-      MouseEnable = TRUE;\r
-    }\r
-    //\r
-    // 5\r
-    // disable mouse (via KBC) and Keyborad device\r
-    //\r
-    Status = KeyboardCommand (\r
-               BiosKeyboardPrivate,\r
-               KBC_CMDREG_VIA64_AUX_DISABLE\r
-               );\r
-\r
-    if (EFI_ERROR (Status)) {\r
-      Status    = EFI_DEVICE_ERROR;\r
-      goto Exit;\r
-    }\r
-\r
-    Status = KeyboardCommand (\r
-               BiosKeyboardPrivate,\r
-               KBC_CMDREG_VIA64_KB_DISABLE\r
-               );\r
-\r
-    if (EFI_ERROR (Status)) {\r
-      Status    = EFI_DEVICE_ERROR;\r
-      goto Exit;\r
-    }\r
-\r
-  } else {\r
-    //\r
-    // 6\r
-    // KBC Self Test\r
-    //\r
-    //\r
-    // Report a Progress Code for performing a self test on the keyboard controller\r
-    //\r
-    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
-      EFI_PROGRESS_CODE,\r
-      EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST,\r
-      BiosKeyboardPrivate->DevicePath\r
-      );\r
-\r
-    Status = KeyboardCommand (\r
-               BiosKeyboardPrivate,\r
-               KBC_CMDREG_VIA64_KBC_SLFTEST\r
-               );\r
-    if (EFI_ERROR (Status)) {\r
-      Status    = EFI_DEVICE_ERROR;\r
-      goto Exit;\r
-    }\r
-\r
-    Status = KeyboardWaitForValue (\r
-               BiosKeyboardPrivate,\r
-               KBC_CMDECHO_KBCSLFTEST_OK,\r
-               KEYBOARD_WAITFORVALUE_TIMEOUT\r
-               );\r
-    if (EFI_ERROR (Status)) {\r
-      Status    = EFI_DEVICE_ERROR;\r
-      goto Exit;\r
+      //\r
+      // 6\r
+      // KBC Self Test\r
+      //\r
+      //\r
+      // Report a Progress Code for performing a self test on the keyboard controller\r
+      //    \r
+      REPORT_STATUS_CODE (\r
+        EFI_PROGRESS_CODE,\r
+        EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST\r
+        );\r
+      \r
+      Status = KeyboardCommand (\r
+                 BiosKeyboardPrivate,\r
+                 KBC_CMDREG_VIA64_KBC_SLFTEST\r
+                 );\r
+      if (EFI_ERROR (Status)) {\r
+        Status    = EFI_DEVICE_ERROR;\r
+        goto Exit;\r
+      }\r
+      \r
+      Status = KeyboardWaitForValue (\r
+                 BiosKeyboardPrivate,\r
+                 KBC_CMDECHO_KBCSLFTEST_OK,\r
+                 KEYBOARD_WAITFORVALUE_TIMEOUT\r
+                 );\r
+      if (EFI_ERROR (Status)) {\r
+        Status    = EFI_DEVICE_ERROR;\r
+        goto Exit;\r
+      }\r
     }\r
   }\r
   //\r
@@ -1187,8 +1197,8 @@ BiosKeyboardReset (
              );\r
 \r
   //\r
-  // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,\r
-  // so we only do the real reseting for keyboard when user asks, and normally during booting an OS, it's skipped.\r
+  // For resetting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,\r
+  // so we only do the real resetting for keyboard when user asks, and normally during booting an OS, it's skipped.\r
   // Call CheckKeyboardConnect() to check whether keyboard is connected, if it is not connected,\r
   // Real reset will not do.\r
   //\r
@@ -1333,14 +1343,16 @@ BiosKeyboardReset (
   // Done for validating keyboard. Enable keyboard (via KBC)\r
   // and recover the command byte to proper value\r
   //\r
-  Status = KeyboardCommand (\r
-             BiosKeyboardPrivate,\r
-             KBC_CMDREG_VIA64_KB_ENABLE\r
-             );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    Status    = EFI_DEVICE_ERROR;\r
-    goto Exit;\r
+  if (!PcdGetBool (PcdFastPS2Detection)) {\r
+    Status = KeyboardCommand (\r
+               BiosKeyboardPrivate,\r
+               KBC_CMDREG_VIA64_KB_ENABLE\r
+               );\r
+    \r
+    if (EFI_ERROR (Status)) {\r
+      Status    = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
   }\r
 \r
   //\r
@@ -1398,6 +1410,17 @@ BiosKeyboardReadKeyStroke (
     return Status;\r
   }\r
 \r
+  //\r
+  // Convert the Ctrl+[a-z] to Ctrl+[1-26]\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
 \r
   return EFI_SUCCESS;\r
@@ -1429,7 +1452,7 @@ BiosKeyboardWaitForKey (
   //\r
   gBS->Stall (1000);\r
   //\r
-  // Use TimerEvent callback funciton to check whether there's any key pressed\r
+  // Use TimerEvent callback function to check whether there's any key pressed\r
   //\r
   BiosKeyboardTimerHandler (NULL, BIOS_KEYBOARD_DEV_FROM_THIS (Context));\r
 \r
@@ -1675,37 +1698,38 @@ CheckKeyboardConnect (
   // enable keyboard itself and wait for its ack\r
   // If can't receive ack, Keyboard should not be connected.\r
   //\r
-  Status = KeyboardWrite (\r
-             BiosKeyboardPrivate,\r
-             KBC_INPBUF_VIA60_KBEN\r
-             );\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Keyboard enable failed!\n"));\r
-    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
-      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
-      EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR,\r
-      BiosKeyboardPrivate->DevicePath\r
-      );\r
-    return FALSE;\r
-  }\r
+  if (!PcdGetBool (PcdFastPS2Detection)) {\r
+    Status = KeyboardWrite (\r
+               BiosKeyboardPrivate,\r
+               KBC_INPBUF_VIA60_KBEN\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Keyboard enable failed!\n"));\r
+      REPORT_STATUS_CODE (\r
+        EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+        EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR\r
+        );\r
+      return FALSE;\r
+    }\r
 \r
-  Status = KeyboardWaitForValue (\r
-             BiosKeyboardPrivate,\r
-             KBC_CMDECHO_ACK,\r
-             KEYBOARD_WAITFORVALUE_TIMEOUT\r
-             );\r
+    Status = KeyboardWaitForValue (\r
+               BiosKeyboardPrivate,\r
+               KBC_CMDECHO_ACK,\r
+               KEYBOARD_WAITFORVALUE_TIMEOUT\r
+               );\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Timeout!\n"));\r
-    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
-      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
-      EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR,\r
-      BiosKeyboardPrivate->DevicePath\r
-      );\r
-    return FALSE;\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Timeout!\n"));\r
+      REPORT_STATUS_CODE (\r
+        EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+        EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR\r
+        );\r
+      return FALSE;\r
+    }\r
+    return TRUE;\r
+  } else {\r
+    return TRUE;\r
   }\r
-\r
-  return TRUE;\r
 }\r
 \r
 /**\r
@@ -1792,7 +1816,7 @@ BiosKeyboardTimerHandler (
   // will be disabled after the thunk call finish, which means if user crazy input during int 9 being disabled, some keystrokes will be lost when \r
   // KB device own hardware buffer overflows. And if the lost keystroke code is CTRL or ALT or SHIFT release code, these function key flags bit \r
   // in BDA will not be updated. So the Int 16 will believe the CTRL or ALT or SHIFT is still pressed, and Int 16 will translate later scancode \r
-  // to wrong ASCII code. We can increase the Thunk frequence to let Int 9 response in time, but this way will much hurt other dirvers \r
+  // to wrong ASCII code. We can increase the Thunk frequence to let Int 9 response in time, but this way will much hurt other drivers\r
   // performance, like USB.\r
   //\r
   // 1. If CTRL or ALT release code is missed,  all later input keys will be translated to wrong ASCII codes which the Tiano cannot support. In \r
@@ -1818,8 +1842,10 @@ BiosKeyboardTimerHandler (
   //\r
   // Clear the CTRL and ALT BDA flag\r
   //\r
-  KbFlag1 = *((UINT8 *) (UINTN) 0x417);  // read the STATUS FLAGS 1\r
-  KbFlag2 = *((UINT8 *) (UINTN) 0x418); // read STATUS FLAGS 2\r
+  ACCESS_PAGE0_CODE (\r
+    KbFlag1 = *((UINT8 *) (UINTN) 0x417); // read the STATUS FLAGS 1\r
+    KbFlag2 = *((UINT8 *) (UINTN) 0x418); // read STATUS FLAGS 2\r
+  );\r
 \r
   DEBUG_CODE (\r
     {\r
@@ -1887,11 +1913,12 @@ BiosKeyboardTimerHandler (
   //\r
   // Clear left alt and left ctrl BDA flag\r
   //\r
-  KbFlag2 &= ~(KB_LEFT_ALT_PRESSED | KB_LEFT_CTRL_PRESSED);\r
-  *((UINT8 *) (UINTN) 0x418) = KbFlag2;\r
-  KbFlag1 &= ~0x0C;                      \r
-  *((UINT8 *) (UINTN) 0x417) = KbFlag1; \r
-\r
+  ACCESS_PAGE0_CODE (\r
+    KbFlag2 &= ~(KB_LEFT_ALT_PRESSED | KB_LEFT_CTRL_PRESSED);\r
+    *((UINT8 *) (UINTN) 0x418) = KbFlag2;\r
+    KbFlag1 &= ~0x0C;\r
+    *((UINT8 *) (UINTN) 0x417) = KbFlag1;\r
+  );\r
   \r
   //\r
   // Output EFI input key and shift/toggle state\r
@@ -1938,7 +1965,7 @@ BiosKeyboardTimerHandler (
   }\r
 \r
   //\r
-  // Invoke notification functions if exist\r
+  // Signal KeyNotify process event if this key pressed matches any key registered.\r
   //\r
   for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {\r
     CurrentNotify = CR (\r
@@ -1947,21 +1974,17 @@ BiosKeyboardTimerHandler (
                       NotifyEntry, \r
                       BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
                       );\r
-    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { \r
-      CurrentNotify->KeyNotificationFn (&KeyData);\r
+    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
+      //\r
+      // The key notification function needs to run at TPL_CALLBACK\r
+      // while current TPL is TPL_NOTIFY. It will be invoked in\r
+      // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.\r
+      //\r
+      Enqueue (&BiosKeyboardPrivate->QueueForNotify, &KeyData);\r
+      gBS->SignalEvent (BiosKeyboardPrivate->KeyNotifyProcessEvent);\r
     }\r
   }\r
 \r
-  //\r
-  // Convert the Ctrl+[a-z] to Ctrl+[1-26]\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 = (UINT16) (KeyData.Key.UnicodeChar - L'a' + 1);\r
-    } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {\r
-      KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar - L'A' + 1);\r
-    }\r
-  }\r
   Enqueue (&BiosKeyboardPrivate->Queue, &KeyData);\r
   //\r
   // Leave critical section and return\r
@@ -1971,6 +1994,55 @@ BiosKeyboardTimerHandler (
   return ;  \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
+  BIOS_KEYBOARD_DEV                     *BiosKeyboardPrivate;\r
+  EFI_KEY_DATA                          KeyData;\r
+  LIST_ENTRY                            *Link;\r
+  LIST_ENTRY                            *NotifyList;\r
+  BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *CurrentNotify;\r
+  EFI_TPL                               OldTpl;\r
+\r
+  BiosKeyboardPrivate = (BIOS_KEYBOARD_DEV *) Context;\r
+\r
+  //\r
+  // Invoke notification functions.\r
+  //\r
+  NotifyList = &BiosKeyboardPrivate->NotifyList;\r
+  while (TRUE) {\r
+    //\r
+    // Enter critical section\r
+    //  \r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+    Status = Dequeue (&BiosKeyboardPrivate->QueueForNotify, &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, BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE);\r
+      if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
+        CurrentNotify->KeyNotificationFn (&KeyData);\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
 /**\r
   Free keyboard notify list.\r
 \r
@@ -2171,7 +2243,12 @@ BiosKeyboardSetState (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) {\r
+  //\r
+  // Thunk keyboard driver doesn't support partial keystroke.\r
+  //\r
+  if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID ||\r
+      (*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED\r
+      ) {\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
@@ -2204,15 +2281,18 @@ BiosKeyboardSetState (
 \r
   Status = KeyboardWrite (BiosKeyboardPrivate, 0xed);\r
   if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
   }  \r
   Status = KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);\r
   if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
   }\r
   Status = KeyboardWrite (BiosKeyboardPrivate, Command);\r
   if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
   }  \r
   //\r
   // Call Legacy BIOS Protocol to set whatever is necessary\r
@@ -2221,6 +2301,7 @@ BiosKeyboardSetState (
 \r
   Status = EFI_SUCCESS;\r
 \r
+Exit:\r
   //\r
   // Leave critical section and return\r
   //\r
@@ -2235,24 +2316,27 @@ BiosKeyboardSetState (
 \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
+                                  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.                        \r
-  @param  NotifyHandle            Points to the unique handle assigned to the registered notification.                          \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
-  \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
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 BiosKeyboardRegisterKeyNotify (\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
@@ -2285,7 +2369,7 @@ BiosKeyboardRegisterKeyNotify (
                       );\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
@@ -2304,11 +2388,10 @@ BiosKeyboardRegisterKeyNotify (
 \r
   NewNotify->Signature         = BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;\r
   NewNotify->KeyNotificationFn = KeyNotificationFunction;\r
-  NewNotify->NotifyHandle      = (EFI_HANDLE) NewNotify;\r
   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));\r
   InsertTailList (&BiosKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry);\r
 \r
-  *NotifyHandle                = NewNotify->NotifyHandle;  \r
+  *NotifyHandle                = NewNotify;\r
   Status                       = EFI_SUCCESS;\r
   \r
 Exit:\r
@@ -2333,7 +2416,7 @@ EFI_STATUS
 EFIAPI\r
 BiosKeyboardUnregisterKeyNotify (\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
@@ -2358,7 +2441,7 @@ BiosKeyboardUnregisterKeyNotify (
   //\r
   // Enter critical section\r
   //\r
-  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);  \r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
 \r
   for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {\r
     CurrentNotify = CR (\r
@@ -2367,7 +2450,7 @@ BiosKeyboardUnregisterKeyNotify (
                       NotifyEntry, \r
                       BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
                       );    \r
-    if (CurrentNotify->NotifyHandle == NotificationHandle) {\r
+    if (CurrentNotify == NotificationHandle) {\r
       //\r
       // Remove the notification function from NotifyList and free resources\r
       //\r