]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c
MdeModulePkg/Usb/EfiKey: Fix endpoint selection
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbKbDxe / EfiKey.c
index b971903a2dd85e1c170a2c191e6e0d9f8dd38ebf..ccb389067a615142bb48d655a6304d5d1c8fa3cd 100644 (file)
 /** @file\r
+  USB Keyboard Driver that manages USB keyboard and produces Simple Text Input\r
+  Protocol and Simple Text Input Ex Protocol.\r
 \r
-  USB Keyboard Driver that includes the implementation of interface.\r
-\r
-Copyright (c) 2004 - 2008, 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) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "EfiKey.h"\r
 #include "KeyBoard.h"\r
 \r
-/**\r
-  The Usb Keyboard Driver Entry Point.\r
-\r
-  @param  ImageHandle       The driver image handle.\r
-  @param  SystemTable       The system table.\r
-\r
-  @return EFI_SUCCESS      The component name protocol is installed.\r
-  @return Others           Failed to install.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-USBKeyboardDriverBindingEntryPoint (\r
-  IN EFI_HANDLE           ImageHandle,\r
-  IN EFI_SYSTEM_TABLE     *SystemTable\r
-  );\r
-\r
-/**\r
-  Check whether USB keyboard driver support this device.\r
-\r
-  @param  This                   The USB keyboard driver binding protocol.\r
-  @param  Controller             The controller handle to check.\r
-  @param  RemainingDevicePath    The remaining device path.\r
-\r
-  @retval EFI_SUCCESS            The driver supports this controller.\r
-  @retval EFI_UNSUPPORTED        This device isn't supported.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-USBKeyboardDriverBindingSupported (\r
-  IN EFI_DRIVER_BINDING_PROTOCOL    *This,\r
-  IN EFI_HANDLE                     Controller,\r
-  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\r
-  );\r
-\r
-/**\r
-  Start running driver on the controller.\r
-\r
-  @param  This                   The USB keyboard driver binding instance.\r
-  @param  Controller             The controller to check.\r
-  @param  RemainingDevicePath    The remaining device patch.\r
-\r
-  @retval EFI_SUCCESS            The controller is controlled by the usb keyboard driver.\r
-  @return Other                  The keyboard driver doesn't support this controller.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-USBKeyboardDriverBindingStart (\r
-  IN EFI_DRIVER_BINDING_PROTOCOL    *This,\r
-  IN EFI_HANDLE                     Controller,\r
-  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\r
-  );\r
-\r
-/**\r
-  Stop handle the controller by this USB keyboard driver.\r
-\r
-  @param  This                   The USB keyboard driver binding protocol.\r
-  @param  Controller             The controller to release.\r
-  @param  NumberOfChildren       The number of handles in ChildHandleBuffer.\r
-  @param  ChildHandleBuffer      The array of child handle.\r
-\r
-  @retval EFI_SUCCESS            The controller or children are stopped.\r
-  @retval EFI_DEVICE_ERROR       Failed to stop the driver.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-USBKeyboardDriverBindingStop (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,\r
-  IN  EFI_HANDLE                     Controller,\r
-  IN  UINTN                          NumberOfChildren,\r
-  IN  EFI_HANDLE                     *ChildHandleBuffer\r
-  );\r
-\r
-/**\r
-  Reset Usb Keyboard.\r
-\r
-  @param  This                  The protocol instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL.\r
-  @param  ExtendedVerification  Whether completely reset keyboard or not.\r
-\r
-  @retval EFI_SUCCESS           Reset keyboard successfully.\r
-  @retval EFI_DEVICE_ERROR      Reset keyboard failed.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-USBKeyboardReset (\r
-  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
-  IN  BOOLEAN                      ExtendedVerification\r
-  );\r
-\r
-/**\r
-  Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke() function.\r
-\r
-  @param  This                 The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.\r
-  @param  Key                  A pointer to a buffer that is filled in with the keystroke\r
-                               information for the key that was pressed.\r
-\r
-  @retval EFI_SUCCESS          Read key stroke successfully.\r
-  @retval Other                Read key stroke failed.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-USBKeyboardReadKeyStroke (\r
-  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *This,\r
-  OUT EFI_INPUT_KEY                 *Key\r
-  );\r
-\r
-/**\r
-  Handler function for WaitForKey event.\r
-\r
-  @param  Event        Event to be signaled when a key is pressed.\r
-  @param  Context      Points to USB_KB_DEV instance.\r
-\r
-  @return None.\r
-**/\r
-VOID\r
-EFIAPI\r
-USBKeyboardWaitForKey (\r
-  IN  EFI_EVENT               Event,\r
-  IN  VOID                    *Context\r
-  );\r
-\r
-/**\r
-  Check whether there is key pending.\r
-\r
-  @param  UsbKeyboardDevice    The USB_KB_DEV instance.\r
-\r
-  @retval EFI_SUCCESS          Have key pending to read.\r
-  @retval Other                Parse key failed.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-USBKeyboardCheckForKey (\r
-  IN  USB_KB_DEV      *UsbKeyboardDevice\r
-  );\r
-\r
-EFI_GUID  gEfiUsbKeyboardDriverGuid = {\r
-  0xa05f5f78, 0xfb3, 0x4d10, {0x90, 0x90, 0xac, 0x4, 0x6e, 0xeb, 0x7c, 0x3c}\r
-};\r
-\r
-/**\r
-  Free keyboard notify list.\r
-\r
-  @param  ListHead                The list head.\r
-\r
-  @retval EFI_SUCCESS             Free the notify list successfully.\r
-  @retval EFI_INVALID_PARAMETER   ListHead is invalid.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-KbdFreeNotifyList (\r
-  IN OUT LIST_ENTRY           *ListHead\r
-  );  \r
-\r
-/**\r
-  Whether the pressed key matches a registered key or not.\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 pressed matches a registered key.\r
-  @retval FLASE             Match failed.\r
-\r
-**/\r
-BOOLEAN\r
-EFIAPI\r
-IsKeyRegistered (\r
-  IN EFI_KEY_DATA  *RegsiteredData,\r
-  IN EFI_KEY_DATA  *InputData\r
-  );\r
-\r
-\r
 //\r
 // USB Keyboard Driver Global Variables\r
 //\r
@@ -208,13 +23,15 @@ EFI_DRIVER_BINDING_PROTOCOL gUsbKeyboardDriverBinding = {
 };\r
 \r
 /**\r
-  The Usb Keyboard Driver Entry Point.\r
+  Entrypoint of USB Keyboard Driver.\r
+\r
+  This function is the entrypoint of USB Keyboard Driver. It installs Driver Binding\r
+  Protocols together with Component Name Protocols.\r
 \r
-  @param  ImageHandle       The driver image handle.\r
-  @param  SystemTable       The system table.\r
+  @param  ImageHandle       The firmware allocated handle for the EFI image.\r
+  @param  SystemTable       A pointer to the EFI System Table.\r
 \r
-  @return EFI_SUCCESS      The component name protocol is installed.\r
-  @return Others           Failed to install.\r
+  @retval EFI_SUCCESS       The entry point is executed successfully.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -224,25 +41,31 @@ USBKeyboardDriverBindingEntryPoint (
   IN EFI_SYSTEM_TABLE     *SystemTable\r
   )\r
 {\r
-  return EfiLibInstallDriverBindingComponentName2 (\r
-           ImageHandle,\r
-           SystemTable,\r
-           &gUsbKeyboardDriverBinding,\r
-           ImageHandle,\r
-           &gUsbKeyboardComponentName,\r
-           &gUsbKeyboardComponentName2\r
-           );\r
+  EFI_STATUS              Status;\r
+\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gUsbKeyboardDriverBinding,\r
+             ImageHandle,\r
+             &gUsbKeyboardComponentName,\r
+             &gUsbKeyboardComponentName2\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  Check whether USB keyboard driver support this device.\r
+  Check whether USB keyboard driver supports this device.\r
 \r
   @param  This                   The USB keyboard driver binding protocol.\r
   @param  Controller             The controller handle to check.\r
   @param  RemainingDevicePath    The remaining device path.\r
 \r
   @retval EFI_SUCCESS            The driver supports this controller.\r
-  @retval EFI_UNSUPPORTED        This device isn't supported.\r
+  @retval other                  This device isn't supported.\r
+\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -252,28 +75,27 @@ USBKeyboardDriverBindingSupported (
   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\r
   )\r
 {\r
-  EFI_STATUS          OpenStatus;\r
-  EFI_USB_IO_PROTOCOL *UsbIo;\r
   EFI_STATUS          Status;\r
+  EFI_USB_IO_PROTOCOL *UsbIo;\r
 \r
   //\r
-  // Check if USB_IO protocol is attached on the controller handle.\r
+  // Check if USB I/O Protocol is attached on the controller handle.\r
   //\r
-  OpenStatus = gBS->OpenProtocol (\r
-                      Controller,\r
-                      &gEfiUsbIoProtocolGuid,\r
-                      (VOID **) &UsbIo,\r
-                      This->DriverBindingHandle,\r
-                      Controller,\r
-                      EFI_OPEN_PROTOCOL_BY_DRIVER\r
-                      );\r
-  if (EFI_ERROR (OpenStatus)) {\r
-    return OpenStatus;\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiUsbIoProtocolGuid,\r
+                  (VOID **) &UsbIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
 \r
   //\r
-  // Use the USB I/O protocol interface to check whether the Controller is\r
-  // the Keyboard controller that can be managed by this driver.\r
+  // Use the USB I/O Protocol interface to check whether Controller is\r
+  // a keyboard device that can be managed by this driver.\r
   //\r
   Status = EFI_SUCCESS;\r
 \r
@@ -282,24 +104,30 @@ USBKeyboardDriverBindingSupported (
   }\r
 \r
   gBS->CloseProtocol (\r
-        Controller,\r
-        &gEfiUsbIoProtocolGuid,\r
-        This->DriverBindingHandle,\r
-        Controller\r
-        );\r
+         Controller,\r
+         &gEfiUsbIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
 \r
   return Status;\r
 }\r
 \r
 /**\r
-  Start running driver on the controller.\r
+  Starts the keyboard device with this driver.\r
+\r
+  This function produces Simple Text Input Protocol and Simple Text Input Ex Protocol,\r
+  initializes the keyboard device, and submit Asynchronous Interrupt Transfer to manage\r
+  this keyboard device.\r
 \r
   @param  This                   The USB keyboard driver binding instance.\r
-  @param  Controller             The controller to check.\r
-  @param  RemainingDevicePath    The remaining device patch.\r
+  @param  Controller             Handle of device to bind driver to.\r
+  @param  RemainingDevicePath    Optional parameter use to pick a specific child\r
+                                 device to start.\r
 \r
   @retval EFI_SUCCESS            The controller is controlled by the usb keyboard driver.\r
-  @return Other                  The keyboard driver doesn't support this controller.\r
+  @retval EFI_UNSUPPORTED        No interrupt endpoint can be found.\r
+  @retval Other                  This controller cannot be started.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -320,12 +148,11 @@ USBKeyboardDriverBindingStart (
   UINT8                         PollingInterval;\r
   UINT8                         PacketSize;\r
   BOOLEAN                       Found;\r
+  EFI_TPL                       OldTpl;\r
 \r
-  UsbKeyboardDevice = NULL;\r
-  Found             = FALSE;\r
-\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
   //\r
-  // Open USB_IO Protocol\r
+  // Open USB I/O Protocol\r
   //\r
   Status = gBS->OpenProtocol (\r
                   Controller,\r
@@ -336,19 +163,12 @@ USBKeyboardDriverBindingStart (
                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    return Status;\r
+    goto ErrorExit1;\r
   }\r
 \r
   UsbKeyboardDevice = AllocateZeroPool (sizeof (USB_KB_DEV));\r
-  if (UsbKeyboardDevice == NULL) {\r
-    gBS->CloseProtocol (\r
-          Controller,\r
-          &gEfiUsbIoProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Controller\r
-          );\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
+  ASSERT (UsbKeyboardDevice != NULL);\r
+\r
   //\r
   // Get the Device Path Protocol on Controller's handle\r
   //\r
@@ -362,79 +182,82 @@ USBKeyboardDriverBindingStart (
                   );\r
 \r
   if (EFI_ERROR (Status)) {\r
-    gBS->FreePool (UsbKeyboardDevice);\r
-    gBS->CloseProtocol (\r
-          Controller,\r
-          &gEfiUsbIoProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Controller\r
-          );\r
-    return Status;\r
+    goto ErrorExit;\r
   }\r
   //\r
-  // Report that the usb keyboard is being enabled\r
+  // Report that the USB keyboard is being enabled\r
   //\r
-  KbdReportStatusCode (\r
-    UsbKeyboardDevice->DevicePath,\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
     EFI_PROGRESS_CODE,\r
-    PcdGet32 (PcdStatusCodeValueKeyboardEnable)\r
+    (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE),\r
+    UsbKeyboardDevice->DevicePath\r
     );\r
 \r
   //\r
   // This is pretty close to keyboard detection, so log progress\r
   //\r
-  KbdReportStatusCode (\r
-    UsbKeyboardDevice->DevicePath,\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
     EFI_PROGRESS_CODE,\r
-    PcdGet32 (PcdStatusCodeValueKeyboardPresenceDetect)\r
+    (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT),\r
+    UsbKeyboardDevice->DevicePath\r
     );\r
 \r
-  //\r
-  // Initialize UsbKeyboardDevice\r
-  //\r
   UsbKeyboardDevice->UsbIo = UsbIo;\r
 \r
   //\r
   // Get interface & endpoint descriptor\r
   //\r
   UsbIo->UsbGetInterfaceDescriptor (\r
-          UsbIo,\r
-          &UsbKeyboardDevice->InterfaceDescriptor\r
-          );\r
+           UsbIo,\r
+           &UsbKeyboardDevice->InterfaceDescriptor\r
+           );\r
 \r
   EndpointNumber = UsbKeyboardDevice->InterfaceDescriptor.NumEndpoints;\r
 \r
+  //\r
+  // Traverse endpoints to find interrupt endpoint IN\r
+  //\r
+  Found = FALSE;\r
   for (Index = 0; Index < EndpointNumber; Index++) {\r
 \r
     UsbIo->UsbGetEndpointDescriptor (\r
-            UsbIo,\r
-            Index,\r
-            &EndpointDescriptor\r
-            );\r
+             UsbIo,\r
+             Index,\r
+             &EndpointDescriptor\r
+             );\r
 \r
-    if ((EndpointDescriptor.Attributes & 0x03) == 0x03) {\r
+    if (((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) &&\r
+        ((EndpointDescriptor.EndpointAddress & USB_ENDPOINT_DIR_IN) != 0)) {\r
       //\r
       // We only care interrupt endpoint here\r
       //\r
       CopyMem(&UsbKeyboardDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor));\r
       Found = TRUE;\r
+      break;\r
     }\r
   }\r
 \r
   if (!Found) {\r
     //\r
+    // Report Status Code to indicate that there is no USB keyboard\r
+    //\r
+    REPORT_STATUS_CODE (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      (EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED)\r
+      );\r
+    //\r
     // No interrupt endpoint found, then return unsupported.\r
     //\r
-    gBS->FreePool (UsbKeyboardDevice);\r
-    gBS->CloseProtocol (\r
-          Controller,\r
-          &gEfiUsbIoProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Controller\r
-          );\r
-    return EFI_UNSUPPORTED;\r
+    Status = EFI_UNSUPPORTED;\r
+    goto ErrorExit;\r
   }\r
 \r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DETECTED),\r
+    UsbKeyboardDevice->DevicePath\r
+    );\r
+\r
   UsbKeyboardDevice->Signature                  = USB_KB_DEV_SIGNATURE;\r
   UsbKeyboardDevice->SimpleInput.Reset          = USBKeyboardReset;\r
   UsbKeyboardDevice->SimpleInput.ReadKeyStroke  = USBKeyboardReadKeyStroke;\r
@@ -443,23 +266,32 @@ USBKeyboardDriverBindingStart (
   UsbKeyboardDevice->SimpleInputEx.ReadKeyStrokeEx     = USBKeyboardReadKeyStrokeEx;\r
   UsbKeyboardDevice->SimpleInputEx.SetState            = USBKeyboardSetState;\r
   UsbKeyboardDevice->SimpleInputEx.RegisterKeyNotify   = USBKeyboardRegisterKeyNotify;\r
-  UsbKeyboardDevice->SimpleInputEx.UnregisterKeyNotify = USBKeyboardUnregisterKeyNotify; \r
-  \r
+  UsbKeyboardDevice->SimpleInputEx.UnregisterKeyNotify = USBKeyboardUnregisterKeyNotify;\r
+\r
   InitializeListHead (&UsbKeyboardDevice->NotifyList);\r
-  \r
+\r
   Status = gBS->CreateEvent (\r
-                  EVT_NOTIFY_WAIT,\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
                   TPL_NOTIFY,\r
-                  USBKeyboardWaitForKey,\r
+                  USBKeyboardTimerHandler,\r
                   UsbKeyboardDevice,\r
-                  &(UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx)\r
+                  &UsbKeyboardDevice->TimerEvent\r
                   );\r
-\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = gBS->SetTimer (UsbKeyboardDevice->TimerEvent, TimerPeriodic, KEYBOARD_TIMER_INTERVAL);\r
+  }\r
   if (EFI_ERROR (Status)) {\r
     goto ErrorExit;\r
   }\r
 \r
-  Status = InitKeyboardLayout (UsbKeyboardDevice);\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_WAIT,\r
+                  TPL_NOTIFY,\r
+                  USBKeyboardWaitForKey,\r
+                  UsbKeyboardDevice,\r
+                  &(UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx)\r
+                  );\r
+\r
   if (EFI_ERROR (Status)) {\r
     goto ErrorExit;\r
   }\r
@@ -471,25 +303,27 @@ USBKeyboardDriverBindingStart (
                   UsbKeyboardDevice,\r
                   &(UsbKeyboardDevice->SimpleInput.WaitForKey)\r
                   );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ErrorExit;\r
+  }\r
 \r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  KeyNotifyProcessHandler,\r
+                  UsbKeyboardDevice,\r
+                  &UsbKeyboardDevice->KeyNotifyProcessEvent\r
+                  );\r
   if (EFI_ERROR (Status)) {\r
-    gBS->FreePool (UsbKeyboardDevice);\r
-    gBS->CloseProtocol (\r
-          Controller,\r
-          &gEfiUsbIoProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Controller\r
-          );\r
-    return Status;\r
+    goto ErrorExit;\r
   }\r
 \r
   //\r
-  // Install simple txt in protocol interface\r
-  // for the usb keyboard device.\r
-  // Usb keyboard is a hot plug device, and expected to work immediately\r
-  // when plugging into system, so a HotPlugDeviceGuid is installed onto\r
-  // the usb keyboard device handle, to distinguish it from other conventional\r
-  // console devices.\r
+  // Install Simple Text Input Protocol and Simple Text Input Ex Protocol\r
+  // for the USB keyboard device.\r
+  // USB keyboard is a hot plug device, and expected to work immediately\r
+  // when plugging into system, other conventional console devices could\r
+  // distinguish it by its device path.\r
   //\r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
                   &Controller,\r
@@ -497,27 +331,32 @@ USBKeyboardDriverBindingStart (
                   &UsbKeyboardDevice->SimpleInput,\r
                   &gEfiSimpleTextInputExProtocolGuid,\r
                   &UsbKeyboardDevice->SimpleInputEx,\r
-                  &gEfiHotPlugDeviceGuid,\r
-                  NULL,\r
                   NULL\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);\r
-    gBS->FreePool (UsbKeyboardDevice);\r
-    gBS->CloseProtocol (\r
-          Controller,\r
-          &gEfiUsbIoProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Controller\r
-          );\r
-    return Status;\r
+    goto ErrorExit;\r
+  }\r
+\r
+  UsbKeyboardDevice->ControllerHandle = Controller;\r
+  Status = InitKeyboardLayout (UsbKeyboardDevice);\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->UninstallMultipleProtocolInterfaces (\r
+      Controller,\r
+      &gEfiSimpleTextInProtocolGuid,\r
+      &UsbKeyboardDevice->SimpleInput,\r
+      &gEfiSimpleTextInputExProtocolGuid,\r
+      &UsbKeyboardDevice->SimpleInputEx,\r
+      NULL\r
+      );\r
+    goto ErrorExit;\r
   }\r
 \r
+\r
   //\r
-  // Reset USB Keyboard Device\r
+  // Reset USB Keyboard Device exhaustively.\r
   //\r
-  Status = UsbKeyboardDevice->SimpleInput.Reset (\r
-                                            &UsbKeyboardDevice->SimpleInput,\r
+  Status = UsbKeyboardDevice->SimpleInputEx.Reset (\r
+                                            &UsbKeyboardDevice->SimpleInputEx,\r
                                             TRUE\r
                                             );\r
   if (EFI_ERROR (Status)) {\r
@@ -527,22 +366,13 @@ USBKeyboardDriverBindingStart (
            &UsbKeyboardDevice->SimpleInput,\r
            &gEfiSimpleTextInputExProtocolGuid,\r
            &UsbKeyboardDevice->SimpleInputEx,\r
-           &gEfiHotPlugDeviceGuid,\r
-           NULL,\r
            NULL\r
            );\r
-    gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);\r
-    gBS->FreePool (UsbKeyboardDevice);\r
-    gBS->CloseProtocol (\r
-          Controller,\r
-          &gEfiUsbIoProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Controller\r
-          );\r
-    return Status;\r
+    goto ErrorExit;\r
   }\r
+\r
   //\r
-  // submit async interrupt transfer\r
+  // Submit Asynchronous Interrupt Transfer to manage this device.\r
   //\r
   EndpointAddr    = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress;\r
   PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval;\r
@@ -559,26 +389,15 @@ USBKeyboardDriverBindingStart (
                     );\r
 \r
   if (EFI_ERROR (Status)) {\r
-\r
     gBS->UninstallMultipleProtocolInterfaces (\r
            Controller,\r
            &gEfiSimpleTextInProtocolGuid,\r
            &UsbKeyboardDevice->SimpleInput,\r
            &gEfiSimpleTextInputExProtocolGuid,\r
            &UsbKeyboardDevice->SimpleInputEx,\r
-           &gEfiHotPlugDeviceGuid,\r
-           NULL,\r
            NULL\r
            );\r
-    gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);\r
-    gBS->FreePool (UsbKeyboardDevice);\r
-    gBS->CloseProtocol (\r
-          Controller,\r
-          &gEfiUsbIoProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Controller\r
-          );\r
-    return Status;\r
+    goto ErrorExit;\r
   }\r
 \r
   UsbKeyboardDevice->ControllerNameTable = NULL;\r
@@ -597,19 +416,31 @@ USBKeyboardDriverBindingStart (
     FALSE\r
     );\r
 \r
-\r
+  gBS->RestoreTPL (OldTpl);\r
   return EFI_SUCCESS;\r
 \r
+//\r
+// Error handler\r
+//\r
 ErrorExit:\r
   if (UsbKeyboardDevice != NULL) {\r
+    if (UsbKeyboardDevice->TimerEvent != NULL) {\r
+      gBS->CloseEvent (UsbKeyboardDevice->TimerEvent);\r
+    }\r
     if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) {\r
       gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);\r
     }\r
     if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) {\r
       gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);\r
     }\r
-    KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList);    \r
-    gBS->FreePool (UsbKeyboardDevice);\r
+    if (UsbKeyboardDevice->KeyNotifyProcessEvent != NULL) {\r
+      gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent);\r
+    }\r
+    if (UsbKeyboardDevice->KeyboardLayoutEvent != NULL) {\r
+      ReleaseKeyboardLayoutResources (UsbKeyboardDevice);\r
+      gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);\r
+    }\r
+    FreePool (UsbKeyboardDevice);\r
     UsbKeyboardDevice = NULL;\r
   }\r
   gBS->CloseProtocol (\r
@@ -618,21 +449,28 @@ ErrorExit:
          This->DriverBindingHandle,\r
          Controller\r
          );\r
+\r
+ErrorExit1:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
   return Status;\r
 \r
 }\r
 \r
 \r
 /**\r
-  Stop handle the controller by this USB keyboard driver.\r
+  Stop the USB keyboard device handled by this driver.\r
 \r
   @param  This                   The USB keyboard driver binding protocol.\r
   @param  Controller             The controller to release.\r
   @param  NumberOfChildren       The number of handles in ChildHandleBuffer.\r
   @param  ChildHandleBuffer      The array of child handle.\r
 \r
-  @retval EFI_SUCCESS            The controller or children are stopped.\r
-  @retval EFI_DEVICE_ERROR       Failed to stop the driver.\r
+  @retval EFI_SUCCESS            The device was stopped.\r
+  @retval EFI_UNSUPPORTED        Simple Text In Protocol or Simple Text In Ex Protocol\r
+                                 is not installed on Controller.\r
+  @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.\r
+  @retval Others                 Fail to uninstall protocols attached on the device.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -644,9 +482,9 @@ USBKeyboardDriverBindingStop (
   IN  EFI_HANDLE                     *ChildHandleBuffer\r
   )\r
 {\r
-  EFI_STATUS                  Status;\r
+  EFI_STATUS                     Status;\r
   EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleInput;\r
-  USB_KB_DEV                  *UsbKeyboardDevice;\r
+  USB_KB_DEV                     *UsbKeyboardDevice;\r
 \r
   Status = gBS->OpenProtocol (\r
                   Controller,\r
@@ -659,6 +497,7 @@ USBKeyboardDriverBindingStop (
   if (EFI_ERROR (Status)) {\r
     return EFI_UNSUPPORTED;\r
   }\r
+\r
   Status = gBS->OpenProtocol (\r
                   Controller,\r
                   &gEfiSimpleTextInputExProtocolGuid,\r
@@ -670,30 +509,20 @@ USBKeyboardDriverBindingStop (
   if (EFI_ERROR (Status)) {\r
     return EFI_UNSUPPORTED;\r
   }\r
-  //\r
-  // Get USB_KB_DEV instance.\r
-  //\r
-  UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput);\r
 \r
-  gBS->CloseProtocol (\r
-        Controller,\r
-        &gEfiSimpleTextInProtocolGuid,\r
-        This->DriverBindingHandle,\r
-        Controller\r
-        );\r
+  UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput);\r
 \r
   //\r
-  // Uninstall the Asyn Interrupt Transfer from this device\r
-  // will disable the key data input from this device\r
+  // The key data input from this device will be disabled.\r
   //\r
-  KbdReportStatusCode (\r
-    UsbKeyboardDevice->DevicePath,\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
     EFI_PROGRESS_CODE,\r
-    PcdGet32 (PcdStatusCodeValueKeyboardDisable)\r
+    (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE),\r
+    UsbKeyboardDevice->DevicePath\r
     );\r
 \r
   //\r
-  // Destroy asynchronous interrupt transfer\r
+  // Delete the Asynchronous Interrupt Transfer from this device\r
   //\r
   UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer (\r
                               UsbKeyboardDevice->UsbIo,\r
@@ -706,11 +535,11 @@ USBKeyboardDriverBindingStop (
                               );\r
 \r
   gBS->CloseProtocol (\r
-        Controller,\r
-        &gEfiUsbIoProtocolGuid,\r
-        This->DriverBindingHandle,\r
-        Controller\r
-        );\r
+         Controller,\r
+         &gEfiUsbIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
 \r
   Status = gBS->UninstallMultipleProtocolInterfaces (\r
                   Controller,\r
@@ -718,18 +547,18 @@ USBKeyboardDriverBindingStop (
                   &UsbKeyboardDevice->SimpleInput,\r
                   &gEfiSimpleTextInputExProtocolGuid,\r
                   &UsbKeyboardDevice->SimpleInputEx,\r
-                  &gEfiHotPlugDeviceGuid,\r
-                  NULL,\r
                   NULL\r
                   );\r
   //\r
-  // free all the resources.\r
+  // Free all resources.\r
   //\r
+  gBS->CloseEvent (UsbKeyboardDevice->TimerEvent);\r
   gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer);\r
   gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent);\r
-  gBS->CloseEvent ((UsbKeyboardDevice->SimpleInput).WaitForKey);\r
-  gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);  \r
-  KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList);    \r
+  gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);\r
+  gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);\r
+  gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent);\r
+  KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList);\r
 \r
   ReleaseKeyboardLayoutResources (UsbKeyboardDevice);\r
   gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);\r
@@ -738,125 +567,71 @@ USBKeyboardDriverBindingStop (
     FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable);\r
   }\r
 \r
-  gBS->FreePool (UsbKeyboardDevice);\r
+  DestroyQueue (&UsbKeyboardDevice->UsbKeyQueue);\r
+  DestroyQueue (&UsbKeyboardDevice->EfiKeyQueue);\r
+  DestroyQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify);\r
 \r
-  return Status;\r
+  FreePool (UsbKeyboardDevice);\r
 \r
+  return Status;\r
 }\r
 \r
 /**\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
+  Internal function to read the next keystroke from the keyboard buffer.\r
 \r
-  @param  UsbKeyboardDevice       Usb keyboard's 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  UsbKeyboardDevice       USB keyboard's private structure.\r
+  @param  KeyData                 A pointer to buffer to hold the keystroke\r
+                                  data for the key that was pressed.\r
 \r
-  @return EFI_SUCCESS             The keystroke information was returned.\r
-  @return EFI_NOT_READY           There was no keystroke data availiable.\r
-  @return EFI_DEVICE_ERROR        The keystroke information was not returned due to\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
-  @return EFI_INVALID_PARAMETER   KeyData is NULL.\r
+  @retval EFI_INVALID_PARAMETER   KeyData is NULL.\r
+  @retval Others                  Fail to translate keycode into EFI_INPUT_KEY\r
 \r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 USBKeyboardReadKeyStrokeWorker (\r
-  IN  USB_KB_DEV                        *UsbKeyboardDevice,\r
-  OUT EFI_KEY_DATA                      *KeyData\r
+  IN OUT USB_KB_DEV                 *UsbKeyboardDevice,\r
+     OUT EFI_KEY_DATA               *KeyData\r
   )\r
 {\r
-\r
-  EFI_STATUS                        Status;\r
-  UINT8                             KeyChar;  \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
-  // if there is no saved ASCII byte, fetch it\r
-  // by calling USBKeyboardCheckForKey().\r
-  //\r
-  if (UsbKeyboardDevice->CurKeyChar == 0) {\r
-    Status = USBKeyboardCheckForKey (UsbKeyboardDevice);\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
+  if (IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {\r
+    ZeroMem (&KeyData->Key, sizeof (KeyData->Key));\r
+    InitializeKeyState (UsbKeyboardDevice, &KeyData->KeyState);\r
+    return EFI_NOT_READY;\r
   }\r
 \r
-  KeyData->Key.UnicodeChar = 0;\r
-  KeyData->Key.ScanCode    = SCAN_NULL;\r
-\r
-  KeyChar = UsbKeyboardDevice->CurKeyChar;\r
-\r
-  UsbKeyboardDevice->CurKeyChar = 0;\r
-\r
-  //\r
-  // Translate saved ASCII byte into EFI_INPUT_KEY\r
-  //\r
-  Status = USBKeyCodeToEFIScanCode (UsbKeyboardDevice, KeyChar, &KeyData->Key);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
-  CopyMem (&KeyData->KeyState, &UsbKeyboardDevice->KeyState, sizeof (KeyData->KeyState));\r
-  \r
-  UsbKeyboardDevice->KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID;\r
-  UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;\r
-\r
-  //\r
-  //Switch the control value to their original characters. In USBKeyCodeToEFIScanCode() 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 (UsbKeyboardDevice->CtrlOn != 0) {\r
-    if (OriginalKeyData.Key.UnicodeChar >= 0x01 && OriginalKeyData.Key.UnicodeChar <= 0x1A) {\r
-      if (UsbKeyboardDevice->CapsOn != 0) {\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
-  //\r
-  // Invoke notification functions if exist\r
-  //\r
-  for (Link = UsbKeyboardDevice->NotifyList.ForwardLink; Link != &UsbKeyboardDevice->NotifyList; Link = Link->ForwardLink) {\r
-    CurrentNotify = CR (\r
-                      Link, \r
-                      KEYBOARD_CONSOLE_IN_EX_NOTIFY, \r
-                      NotifyEntry, \r
-                      USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
-                      );\r
-    if (IsKeyRegistered (&CurrentNotify->KeyData, &OriginalKeyData)) { \r
-      CurrentNotify->KeyNotificationFn (&OriginalKeyData);\r
-    }\r
-  }\r
+  Dequeue (&UsbKeyboardDevice->EfiKeyQueue, KeyData, sizeof (*KeyData));\r
 \r
   return EFI_SUCCESS;\r
-  \r
 }\r
 \r
 /**\r
-  Reset Usb Keyboard.\r
+  Reset the input device and optionally run diagnostics\r
+\r
+  There are 2 types of reset for USB keyboard.\r
+  For non-exhaustive reset, only keyboard buffer is cleared.\r
+  For exhaustive reset, in addition to clearance of keyboard buffer, the hardware status\r
+  is also re-initialized.\r
 \r
-  @param  This                  The protocol instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL.\r
-  @param  ExtendedVerification  Whether completely reset keyboard or not.\r
+  @param  This                 Protocol instance pointer.\r
+  @param  ExtendedVerification Driver may perform diagnostics on reset.\r
 \r
-  @retval EFI_SUCCESS           Reset keyboard successfully.\r
-  @retval EFI_DEVICE_ERROR      Reset keyboard failed.\r
+  @retval EFI_SUCCESS          The device was reset.\r
+  @retval EFI_DEVICE_ERROR     The device is not functioning properly and could not be reset.\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 USBKeyboardReset (\r
   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *This,\r
-  IN  BOOLEAN                       ExtendedVerification\r
+  IN  BOOLEAN                          ExtendedVerification\r
   )\r
 {\r
   EFI_STATUS          Status;\r
@@ -864,36 +639,36 @@ USBKeyboardReset (
 \r
   UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);\r
 \r
-  KbdReportStatusCode (\r
-    UsbKeyboardDevice->DevicePath,\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
     EFI_PROGRESS_CODE,\r
-        PcdGet32 (PcdStatusCodeValueKeyboardReset)\r
+    (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET),\r
+    UsbKeyboardDevice->DevicePath\r
     );\r
 \r
   //\r
-  // Non Exhaustive reset:\r
+  // Non-exhaustive reset:\r
   // only reset private data structures.\r
   //\r
   if (!ExtendedVerification) {\r
-    //\r
-    // Clear the key buffer of this Usb keyboard\r
-    //\r
-    KbdReportStatusCode (\r
-      UsbKeyboardDevice->DevicePath,\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
       EFI_PROGRESS_CODE,\r
-      PcdGet32 (PcdStatusCodeValueKeyboardClearBuffer)\r
+      (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER),\r
+      UsbKeyboardDevice->DevicePath\r
       );\r
+    //\r
+    // Clear the key buffer of this USB keyboard\r
+    //\r
+    InitQueue (&UsbKeyboardDevice->UsbKeyQueue, sizeof (USB_KEY));\r
+    InitQueue (&UsbKeyboardDevice->EfiKeyQueue, sizeof (EFI_KEY_DATA));\r
+    InitQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify, sizeof (EFI_KEY_DATA));\r
 \r
-    InitUSBKeyBuffer (&(UsbKeyboardDevice->KeyboardBuffer));\r
-    UsbKeyboardDevice->CurKeyChar = 0;\r
     return EFI_SUCCESS;\r
   }\r
 \r
   //\r
   // Exhaustive reset\r
   //\r
-  Status                        = InitUSBKeyboard (UsbKeyboardDevice);\r
-  UsbKeyboardDevice->CurKeyChar = 0;\r
+  Status = InitUSBKeyboard (UsbKeyboardDevice);\r
   if (EFI_ERROR (Status)) {\r
     return EFI_DEVICE_ERROR;\r
   }\r
@@ -903,21 +678,23 @@ USBKeyboardReset (
 \r
 \r
 /**\r
-  Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke() function.\r
+  Reads the next keystroke from the input device.\r
 \r
   @param  This                 The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.\r
   @param  Key                  A pointer to a buffer that is filled in with the keystroke\r
                                information for the key that was pressed.\r
 \r
-  @retval EFI_SUCCESS          Read key stroke successfully.\r
-  @retval Other                Read key stroke failed.\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
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 USBKeyboardReadKeyStroke (\r
   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *This,\r
-  OUT EFI_INPUT_KEY                 *Key\r
+  OUT EFI_INPUT_KEY                    *Key\r
   )\r
 {\r
   USB_KB_DEV   *UsbKeyboardDevice;\r
@@ -926,25 +703,47 @@ USBKeyboardReadKeyStroke (
 \r
   UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);\r
 \r
-  Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
-  CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
-\r
-  return EFI_SUCCESS;\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
+    Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // SimpleTextIn Protocol doesn't support partial keystroke;\r
+    //\r
+    if (KeyData.Key.ScanCode == CHAR_NULL && KeyData.Key.UnicodeChar == SCAN_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
 /**\r
-  Handler function for WaitForKey event.\r
+  Event notification function registered for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx\r
+  and EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey.\r
 \r
   @param  Event        Event to be signaled when a key is pressed.\r
   @param  Context      Points to USB_KB_DEV instance.\r
 \r
-  @return None.\r
 **/\r
 VOID\r
 EFIAPI\r
@@ -954,167 +753,178 @@ USBKeyboardWaitForKey (
   )\r
 {\r
   USB_KB_DEV  *UsbKeyboardDevice;\r
+  EFI_KEY_DATA KeyData;\r
+  EFI_TPL      OldTpl;\r
 \r
   UsbKeyboardDevice = (USB_KB_DEV *) Context;\r
 \r
-  if (UsbKeyboardDevice->CurKeyChar == 0) {\r
+  //\r
+  // Enter critical section\r
+  //\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
 \r
-    if (EFI_ERROR (USBKeyboardCheckForKey (UsbKeyboardDevice))) {\r
-      return ;\r
+  //\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
+  while (!IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {\r
+    //\r
+    // If there is pending key, signal the event.\r
+    //\r
+    CopyMem (\r
+      &KeyData,\r
+      UsbKeyboardDevice->EfiKeyQueue.Buffer[UsbKeyboardDevice->EfiKeyQueue.Head],\r
+      sizeof (EFI_KEY_DATA)\r
+      );\r
+    if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {\r
+      Dequeue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (EFI_KEY_DATA));\r
+      continue;\r
     }\r
+    gBS->SignalEvent (Event);\r
+    break;\r
   }\r
   //\r
-  // If has key pending, signal the event.\r
+  // Leave critical section and return\r
   //\r
-  gBS->SignalEvent (Event);\r
+  gBS->RestoreTPL (OldTpl);\r
 }\r
 \r
-\r
 /**\r
-  Check whether there is key pending.\r
-\r
-  @param  UsbKeyboardDevice    The USB_KB_DEV instance.\r
-\r
-  @retval EFI_SUCCESS          Have key pending to read.\r
-  @retval Other                Parse key failed.\r
+  Timer handler to convert the key from USB.\r
 \r
+  @param  Event                    Indicates the event that invoke this function.\r
+  @param  Context                  Indicates the calling context.\r
 **/\r
-EFI_STATUS\r
+VOID\r
 EFIAPI\r
-USBKeyboardCheckForKey (\r
-  IN  USB_KB_DEV    *UsbKeyboardDevice\r
+USBKeyboardTimerHandler (\r
+  IN  EFI_EVENT                 Event,\r
+  IN  VOID                      *Context\r
   )\r
 {\r
-  EFI_STATUS  Status;\r
-  UINT8       KeyChar;\r
+  EFI_STATUS                    Status;\r
+  USB_KB_DEV                    *UsbKeyboardDevice;\r
+  UINT8                         KeyCode;\r
+  EFI_KEY_DATA                  KeyData;\r
+\r
+  UsbKeyboardDevice = (USB_KB_DEV *) Context;\r
 \r
   //\r
-  // Fetch raw data from the USB keyboard input,\r
-  // and translate it into ASCII data.\r
+  // Fetch raw data from the USB keyboard buffer,\r
+  // and translate it into USB keycode.\r
   //\r
-  Status = USBParseKey (UsbKeyboardDevice, &KeyChar);\r
+  Status = USBParseKey (UsbKeyboardDevice, &KeyCode);\r
   if (EFI_ERROR (Status)) {\r
-    return Status;\r
+    return ;\r
   }\r
 \r
-  UsbKeyboardDevice->CurKeyChar = KeyChar;\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
-  Report Status Code in Usb Keyboard Driver.\r
-\r
-  @param  DevicePath            Use this to get Device Path.\r
-  @param  CodeType              Status Code Type.\r
-  @param  CodeValue             Status Code Value.\r
-\r
-  @return None.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-KbdReportStatusCode (\r
-  IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath,\r
-  IN EFI_STATUS_CODE_TYPE      CodeType,\r
-  IN EFI_STATUS_CODE_VALUE     Value\r
-  )\r
-{\r
+  //\r
+  // Translate saved USB keycode into EFI_INPUT_KEY\r
+  //\r
+  Status = UsbKeyCodeToEfiInputKey (UsbKeyboardDevice, KeyCode, &KeyData);\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
 \r
-  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
-    CodeType,\r
-    Value,\r
-    DevicePath\r
-    );\r
+  //\r
+  // Insert to the EFI Key queue\r
+  //\r
+  Enqueue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (KeyData));\r
 }\r
 \r
 /**\r
   Free keyboard notify list.\r
 \r
-  @param  ListHead                The list head.\r
+  @param  NotifyList              The keyboard notify list to free.\r
 \r
   @retval EFI_SUCCESS             Free the notify list successfully.\r
-  @retval EFI_INVALID_PARAMETER   ListHead is invalid.\r
+  @retval EFI_INVALID_PARAMETER   NotifyList is NULL.\r
 \r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 KbdFreeNotifyList (\r
-  IN OUT LIST_ENTRY           *ListHead\r
+  IN OUT LIST_ENTRY           *NotifyList\r
   )\r
 {\r
   KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;\r
+  LIST_ENTRY                    *Link;\r
 \r
-  if (ListHead == NULL) {\r
+  if (NotifyList == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  while (!IsListEmpty (ListHead)) {\r
-    NotifyNode = CR (\r
-                   ListHead->ForwardLink, \r
-                   KEYBOARD_CONSOLE_IN_EX_NOTIFY, \r
-                   NotifyEntry, \r
-                   USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
-                   );\r
-    RemoveEntryList (ListHead->ForwardLink);\r
-    gBS->FreePool (NotifyNode);\r
+  while (!IsListEmpty (NotifyList)) {\r
+    Link = GetFirstNode (NotifyList);\r
+    NotifyNode = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);\r
+    RemoveEntryList (Link);\r
+    FreePool (NotifyNode);\r
   }\r
-  \r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  Whether the pressed key matches a registered key or not.\r
+  Check whether the pressed key matches a registered key or not.\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
+  @param  RegsiteredData    A pointer to keystroke data for the key that was registered.\r
+  @param  InputData         A pointer to keystroke data for the key that was pressed.\r
 \r
   @retval TRUE              Key pressed matches a registered key.\r
-  @retval FLASE             Match failed.\r
+  @retval FLASE             Key pressed does not matches a registered key.\r
 \r
 **/\r
 BOOLEAN\r
-EFIAPI\r
 IsKeyRegistered (\r
   IN EFI_KEY_DATA  *RegsiteredData,\r
   IN EFI_KEY_DATA  *InputData\r
   )\r
 {\r
   ASSERT (RegsiteredData != NULL && InputData != NULL);\r
-  \r
+\r
   if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||\r
       (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {\r
-    return FALSE;  \r
-  }      \r
-  \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
+    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
+    return FALSE;\r
+  }\r
 \r
+  return TRUE;\r
 }\r
 \r
 //\r
-// Simple Text Input Ex protocol functions \r
+// Simple Text Input Ex protocol functions\r
 //\r
 /**\r
-  The extension routine to reset the input device.\r
+  Resets the input device hardware.\r
+\r
+  The Reset() function resets the input device hardware. As part\r
+  of initialization process, the firmware/device will make a quick\r
+  but reasonable attempt to verify that the device is functioning.\r
+  If the ExtendedVerification flag is TRUE the firmware may take\r
+  an extended amount of time to verify the device is operating on\r
+  reset. Otherwise the reset operation is to occur as quickly as\r
+  possible. The hardware verification process is not defined by\r
+  this specification and is left up to the platform firmware or\r
+  driver to implement.\r
 \r
-  @param This                     Protocol instance pointer.\r
-  @param ExtendedVerification     Driver may perform diagnostics on reset.\r
+  @param This                 A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.\r
 \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
+  @param ExtendedVerification Indicates that the driver may perform a more exhaustive\r
+                              verification operation of the device during reset.\r
+\r
+  @retval EFI_SUCCESS         The device was reset.\r
+  @retval EFI_DEVICE_ERROR    The device is not functioning correctly and could not be reset.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -1126,8 +936,6 @@ USBKeyboardResetEx (
 {\r
   EFI_STATUS                Status;\r
   USB_KB_DEV                *UsbKeyboardDevice;\r
-  EFI_TPL                   OldTpl;\r
-  \r
 \r
   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);\r
 \r
@@ -1136,26 +944,25 @@ USBKeyboardResetEx (
     return EFI_DEVICE_ERROR;\r
   }\r
 \r
-  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
   UsbKeyboardDevice->KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID;\r
   UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;\r
-  gBS->RestoreTPL (OldTpl);\r
 \r
   return EFI_SUCCESS;\r
 \r
 }\r
 \r
 /**\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
+  Reads the next keystroke from 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
-                                  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
-  @return EFI_SUCCESS             The keystroke information was returned successfully.\r
-  @retval EFI_INVALID_PARAMETER   KeyData is NULL.\r
-  @retval Other                   Read key stroke information failed.\r
+  @retval EFI_SUCCESS            The keystroke information was returned.\r
+  @retval EFI_NOT_READY          There was no keystroke data available.\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
@@ -1174,7 +981,7 @@ USBKeyboardReadKeyStrokeEx (
   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);\r
 \r
   return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, KeyData);\r
-  \r
+\r
 }\r
 \r
 /**\r
@@ -1184,8 +991,10 @@ USBKeyboardReadKeyStrokeEx (
   @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_UNSUPPORTED         The device does not have the ability to set its state.\r
+  @retval EFI_SUCCESS             The device state was set appropriately.\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 support the ability to have its state set.\r
   @retval EFI_INVALID_PARAMETER   KeyToggleState is NULL.\r
 \r
 **/\r
@@ -1213,18 +1022,22 @@ USBKeyboardSetState (
   // Update the status light\r
   //\r
 \r
-  UsbKeyboardDevice->ScrollOn   = 0;\r
-  UsbKeyboardDevice->NumLockOn  = 0;\r
-  UsbKeyboardDevice->CapsOn     = 0;\r
\r
+  UsbKeyboardDevice->ScrollOn   = FALSE;\r
+  UsbKeyboardDevice->NumLockOn  = FALSE;\r
+  UsbKeyboardDevice->CapsOn     = FALSE;\r
+  UsbKeyboardDevice->IsSupportPartialKey = FALSE;\r
+\r
   if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {\r
-    UsbKeyboardDevice->ScrollOn = 1;\r
+    UsbKeyboardDevice->ScrollOn = TRUE;\r
   }\r
   if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {\r
-    UsbKeyboardDevice->NumLockOn = 1;\r
+    UsbKeyboardDevice->NumLockOn = TRUE;\r
   }\r
   if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {\r
-    UsbKeyboardDevice->CapsOn = 1;\r
+    UsbKeyboardDevice->CapsOn = TRUE;\r
+  }\r
+  if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {\r
+    UsbKeyboardDevice->IsSupportPartialKey = TRUE;\r
   }\r
 \r
   SetKeyLED (UsbKeyboardDevice);\r
@@ -1232,22 +1045,26 @@ USBKeyboardSetState (
   UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState;\r
 \r
   return EFI_SUCCESS;\r
-  \r
+\r
 }\r
 \r
 /**\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  KeyData                     A pointer to a buffer that is filled in with\r
+                                      the keystroke information for the key that was\r
+                                      pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState\r
+                                      and KeyData.KeyState.KeyShiftState are 0, then any incomplete\r
+                                      keystroke will trigger a notification of the KeyNotificationFunction.\r
   @param  KeyNotificationFunction     Points to the function to be called when the key\r
-                                      sequence is typed specified by KeyData.\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 is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES        Unable to allocate resources for necessary data structures.\r
+  @retval EFI_INVALID_PARAMETER       KeyData or NotifyHandle or KeyNotificationFunction is NULL.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -1256,14 +1073,14 @@ USBKeyboardRegisterKeyNotify (
   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
   USB_KB_DEV                        *UsbKeyboardDevice;\r
-  EFI_STATUS                        Status;\r
   KEYBOARD_CONSOLE_IN_EX_NOTIFY     *NewNotify;\r
   LIST_ENTRY                        *Link;\r
-  KEYBOARD_CONSOLE_IN_EX_NOTIFY     *CurrentNotify;  \r
+  LIST_ENTRY                        *NotifyList;\r
+  KEYBOARD_CONSOLE_IN_EX_NOTIFY     *CurrentNotify;\r
 \r
   if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -1274,49 +1091,43 @@ USBKeyboardRegisterKeyNotify (
   //\r
   // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.\r
   //\r
-  for (Link = UsbKeyboardDevice->NotifyList.ForwardLink; Link != &UsbKeyboardDevice->NotifyList; Link = Link->ForwardLink) {\r
+  NotifyList = &UsbKeyboardDevice->NotifyList;\r
+\r
+  for (Link = GetFirstNode (NotifyList);\r
+       !IsNull (NotifyList, Link);\r
+       Link = GetNextNode (NotifyList, Link)) {\r
     CurrentNotify = CR (\r
-                      Link, \r
-                      KEYBOARD_CONSOLE_IN_EX_NOTIFY, \r
-                      NotifyEntry, \r
+                      Link,\r
+                      KEYBOARD_CONSOLE_IN_EX_NOTIFY,\r
+                      NotifyEntry,\r
                       USB_KB_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
         return EFI_SUCCESS;\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
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  NewNotify->Signature         = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE;     \r
+  NewNotify->Signature         = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE;\r
   NewNotify->KeyNotificationFn = KeyNotificationFunction;\r
   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));\r
   InsertTailList (&UsbKeyboardDevice->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
-  \r
-  *NotifyHandle = NewNotify->NotifyHandle;  \r
-  \r
+\r
+  *NotifyHandle = NewNotify;\r
+\r
   return EFI_SUCCESS;\r
-  \r
+\r
 }\r
 \r
 /**\r
@@ -1326,65 +1137,103 @@ USBKeyboardRegisterKeyNotify (
   @param  NotificationHandle        The handle of the notification function being unregistered.\r
 \r
   @retval EFI_SUCCESS              The notification function was unregistered successfully.\r
-  @retval EFI_INVALID_PARAMETER    The NotificationHandle is invalid or opening gSimpleTextInExNotifyGuid\r
-                                   on NotificationHandle fails.\r
-  @retval EFI_NOT_FOUND            Can not find the matching entry in database.\r
+  @retval EFI_INVALID_PARAMETER    The NotificationHandle is invalid\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 USBKeyboardUnregisterKeyNotify (\r
   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
-  IN EFI_HANDLE                         NotificationHandle\r
+  IN VOID                               *NotificationHandle\r
   )\r
 {\r
   USB_KB_DEV                        *UsbKeyboardDevice;\r
-  EFI_STATUS                        Status;\r
   KEYBOARD_CONSOLE_IN_EX_NOTIFY     *CurrentNotify;\r
   LIST_ENTRY                        *Link;\r
+  LIST_ENTRY                        *NotifyList;\r
 \r
   if (NotificationHandle == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
-  }  \r
-  \r
-  UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);\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
-  for (Link = UsbKeyboardDevice->NotifyList.ForwardLink; Link != &UsbKeyboardDevice->NotifyList; Link = Link->ForwardLink) {\r
+  UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);\r
+\r
+  //\r
+  // Traverse notify list of USB keyboard and remove the entry of NotificationHandle.\r
+  //\r
+  NotifyList = &UsbKeyboardDevice->NotifyList;\r
+  for (Link = GetFirstNode (NotifyList);\r
+       !IsNull (NotifyList, Link);\r
+       Link = GetNextNode (NotifyList, Link)) {\r
     CurrentNotify = CR (\r
-                      Link, \r
-                      KEYBOARD_CONSOLE_IN_EX_NOTIFY, \r
-                      NotifyEntry, \r
+                      Link,\r
+                      KEYBOARD_CONSOLE_IN_EX_NOTIFY,\r
+                      NotifyEntry,\r
                       USB_KB_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
+      FreePool (CurrentNotify);\r
       return EFI_SUCCESS;\r
     }\r
   }\r
 \r
-  return EFI_NOT_FOUND;  \r
+  //\r
+  // Cannot find the matching entry in database.\r
+  //\r
+  return EFI_INVALID_PARAMETER;\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
+  USB_KB_DEV                    *UsbKeyboardDevice;\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
+  UsbKeyboardDevice = (USB_KB_DEV *) Context;\r
+\r
+  //\r
+  // Invoke notification functions.\r
+  //\r
+  NotifyList = &UsbKeyboardDevice->NotifyList;\r
+  while (TRUE) {\r
+    //\r
+    // Enter critical section\r
+    //\r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+    Status = Dequeue (&UsbKeyboardDevice->EfiKeyQueueForNotify, &KeyData, sizeof (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, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);\r
+      if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
+        CurrentNotify->KeyNotificationFn (&KeyData);\r
+      }\r
+    }\r
+  }\r
 }\r
 \r