]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Usb/UsbKbDxe/EfiKey.c
MdeModulePkg: Update comments in SimpleTextInEx according to UEFI 2.7
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbKbDxe / EfiKey.c
index 278c2da19a474d1b3c8dd39b3d9c51c9afa5347d..fb2bf3fd814de47f3d2e719ed5326d9152d140d2 100644 (file)
@@ -2,7 +2,7 @@
   USB Keyboard Driver that manages USB keyboard and produces Simple Text Input\r
   Protocol and Simple Text Input Ex Protocol.\r
 \r
-Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR>\r
 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
@@ -244,12 +244,25 @@ USBKeyboardDriverBindingStart (
 \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
     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
@@ -259,9 +272,23 @@ USBKeyboardDriverBindingStart (
   UsbKeyboardDevice->SimpleInputEx.SetState            = USBKeyboardSetState;\r
   UsbKeyboardDevice->SimpleInputEx.RegisterKeyNotify   = USBKeyboardRegisterKeyNotify;\r
   UsbKeyboardDevice->SimpleInputEx.UnregisterKeyNotify = USBKeyboardUnregisterKeyNotify;\r
-  \r
+\r
   InitializeListHead (&UsbKeyboardDevice->NotifyList);\r
-  \r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  USBKeyboardTimerHandler,\r
+                  UsbKeyboardDevice,\r
+                  &UsbKeyboardDevice->TimerEvent\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 = gBS->CreateEvent (\r
                   EVT_NOTIFY_WAIT,\r
                   TPL_NOTIFY,\r
@@ -285,6 +312,17 @@ USBKeyboardDriverBindingStart (
     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
+    goto ErrorExit;\r
+  }\r
+\r
   //\r
   // Install Simple Text Input Protocol and Simple Text Input Ex Protocol\r
   // for the USB keyboard device.\r
@@ -391,12 +429,18 @@ USBKeyboardDriverBindingStart (
 //\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
+    if (UsbKeyboardDevice->KeyNotifyProcessEvent != NULL) {\r
+      gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent);\r
+    }\r
     if (UsbKeyboardDevice->KeyboardLayoutEvent != NULL) {\r
       ReleaseKeyboardLayoutResources (UsbKeyboardDevice);\r
       gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);\r
@@ -513,11 +557,13 @@ USBKeyboardDriverBindingStop (
   //\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
@@ -526,6 +572,10 @@ USBKeyboardDriverBindingStop (
     FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable);\r
   }\r
 \r
+  DestroyQueue (&UsbKeyboardDevice->UsbKeyQueue);\r
+  DestroyQueue (&UsbKeyboardDevice->EfiKeyQueue);\r
+  DestroyQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify);\r
+\r
   FreePool (UsbKeyboardDevice);\r
 \r
   return Status;\r
@@ -547,89 +597,20 @@ USBKeyboardDriverBindingStop (
 \r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 USBKeyboardReadKeyStrokeWorker (\r
   IN OUT USB_KB_DEV                 *UsbKeyboardDevice,\r
      OUT EFI_KEY_DATA               *KeyData\r
   )\r
 {\r
-  EFI_STATUS                        Status;\r
-  UINT8                             KeyCode;  \r
-  LIST_ENTRY                        *Link;\r
-  LIST_ENTRY                        *NotifyList;\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 USB keycode, fetch it\r
-  // by calling USBKeyboardCheckForKey().\r
-  //\r
-  if (UsbKeyboardDevice->CurKeyCode == 0) {\r
-    Status = USBKeyboardCheckForKey (UsbKeyboardDevice);\r
-    if (EFI_ERROR (Status)) {\r
-      return EFI_NOT_READY;\r
-    }\r
-  }\r
-\r
-  KeyData->Key.UnicodeChar = 0;\r
-  KeyData->Key.ScanCode    = SCAN_NULL;\r
-\r
-  //\r
-  // Store the current keycode and clear it.\r
-  //\r
-  KeyCode = UsbKeyboardDevice->CurKeyCode;\r
-  UsbKeyboardDevice->CurKeyCode = 0;\r
-\r
-  //\r
-  // Translate saved USB keycode into EFI_INPUT_KEY\r
-  //\r
-  Status = UsbKeyCodeToEfiInputKey (UsbKeyboardDevice, KeyCode, &KeyData->Key);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
+  if (IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {\r
+    return EFI_NOT_READY;\r
   }\r
 \r
-  //\r
-  // Get current state of various toggled attributes as well as input modifier values,\r
-  // and set them as valid.\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.\r
-  // In UsbKeyCodeToEfiInputKey() the  CTRL-Alpha characters have been switched to \r
-  // their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A),\r
-  // here switch them back for notification function.\r
-  //\r
-  CopyMem (&OriginalKeyData, KeyData, sizeof (EFI_KEY_DATA));\r
-  if (UsbKeyboardDevice->CtrlOn) {\r
-    if (OriginalKeyData.Key.UnicodeChar >= 0x01 && OriginalKeyData.Key.UnicodeChar <= 0x1A) {\r
-      if (UsbKeyboardDevice->CapsOn) {\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 the key is registered.\r
-  //\r
-  NotifyList = &UsbKeyboardDevice->NotifyList;\r
-  for (Link = GetFirstNode (NotifyList);\r
-       !IsNull (NotifyList, Link);\r
-       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, &OriginalKeyData)) { \r
-      CurrentNotify->KeyNotificationFn (&OriginalKeyData);\r
-    }\r
-  }\r
+  Dequeue (&UsbKeyboardDevice->EfiKeyQueue, KeyData, sizeof (*KeyData));\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -680,8 +661,9 @@ USBKeyboardReset (
     //\r
     // Clear the key buffer of this USB keyboard\r
     //\r
-    InitUSBKeyBuffer (&(UsbKeyboardDevice->KeyboardBuffer));\r
-    UsbKeyboardDevice->CurKeyCode = 0;\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
     return EFI_SUCCESS;\r
   }\r
@@ -690,7 +672,6 @@ USBKeyboardReset (
   // Exhaustive reset\r
   //\r
   Status = InitUSBKeyboard (UsbKeyboardDevice);\r
-  UsbKeyboardDevice->CurKeyCode = 0;\r
   if (EFI_ERROR (Status)) {\r
     return EFI_DEVICE_ERROR;\r
   }\r
@@ -725,14 +706,37 @@ 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
+  // 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
-  return EFI_SUCCESS;\r
+    CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
+    return EFI_SUCCESS;\r
+  }\r
 }\r
 \r
 \r
@@ -752,41 +756,63 @@ 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->CurKeyCode == 0) {\r
-    if (EFI_ERROR (USBKeyboardCheckForKey (UsbKeyboardDevice))) {\r
-      //\r
-      // If no pending key, simply return.\r
-      //\r
-      return ;\r
+  //\r
+  // Enter critical section\r
+  //  \r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+  \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 there is pending key, 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 in the keyboard buffer.\r
-\r
-  @param  UsbKeyboardDevice    The USB_KB_DEV instance.\r
-\r
-  @retval EFI_SUCCESS          There is pending key to read.\r
-  @retval EFI_NOT_READY        No pending key to read.\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 OUT  USB_KB_DEV    *UsbKeyboardDevice\r
+USBKeyboardTimerHandler (\r
+  IN  EFI_EVENT                 Event,\r
+  IN  VOID                      *Context\r
   )\r
 {\r
-  EFI_STATUS  Status;\r
-  UINT8       KeyCode;\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 buffer,\r
@@ -794,11 +820,21 @@ USBKeyboardCheckForKey (
   //\r
   Status = USBParseKey (UsbKeyboardDevice, &KeyCode);\r
   if (EFI_ERROR (Status)) {\r
-    return EFI_NOT_READY;\r
+    return ;\r
   }\r
 \r
-  UsbKeyboardDevice->CurKeyCode = KeyCode;\r
-  return EFI_SUCCESS;\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
+  //\r
+  // Insert to the EFI Key queue\r
+  //\r
+  Enqueue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (KeyData));\r
 }\r
 \r
 /**\r
@@ -811,7 +847,6 @@ USBKeyboardCheckForKey (
 \r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 KbdFreeNotifyList (\r
   IN OUT LIST_ENTRY           *NotifyList\r
   )\r
@@ -828,7 +863,7 @@ KbdFreeNotifyList (
     RemoveEntryList (Link);\r
     FreePool (NotifyNode);\r
   }\r
-  \r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -843,36 +878,35 @@ KbdFreeNotifyList (
 \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 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
   Resets the input device hardware.\r
@@ -905,8 +939,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
@@ -915,10 +947,8 @@ 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
@@ -954,7 +984,7 @@ USBKeyboardReadKeyStrokeEx (
   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);\r
 \r
   return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, KeyData);\r
-  \r
+\r
 }\r
 \r
 /**\r
@@ -998,7 +1028,8 @@ USBKeyboardSetState (
   UsbKeyboardDevice->ScrollOn   = FALSE;\r
   UsbKeyboardDevice->NumLockOn  = FALSE;\r
   UsbKeyboardDevice->CapsOn     = FALSE;\r
\r
+  UsbKeyboardDevice->IsSupportPartialKey = FALSE;\r
+\r
   if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {\r
     UsbKeyboardDevice->ScrollOn = TRUE;\r
   }\r
@@ -1008,23 +1039,30 @@ USBKeyboardSetState (
   if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {\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
 \r
   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
@@ -1038,14 +1076,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
   KEYBOARD_CONSOLE_IN_EX_NOTIFY     *NewNotify;\r
   LIST_ENTRY                        *Link;\r
   LIST_ENTRY                        *NotifyList;\r
-  KEYBOARD_CONSOLE_IN_EX_NOTIFY     *CurrentNotify;  \r
+  KEYBOARD_CONSOLE_IN_EX_NOTIFY     *CurrentNotify;\r
 \r
   if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -1057,43 +1095,42 @@ USBKeyboardRegisterKeyNotify (
   // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.\r
   //\r
   NotifyList = &UsbKeyboardDevice->NotifyList;\r
-  \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
-  NewNotify->NotifyHandle      = (EFI_HANDLE) NewNotify;\r
   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));\r
   InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry);\r
 \r
 \r
-  *NotifyHandle = NewNotify->NotifyHandle;  \r
-  \r
+  *NotifyHandle = NewNotify;\r
+\r
   return EFI_SUCCESS;\r
-  \r
+\r
 }\r
 \r
 /**\r
@@ -1110,7 +1147,7 @@ EFI_STATUS
 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
@@ -1120,14 +1157,10 @@ USBKeyboardUnregisterKeyNotify (
 \r
   if (NotificationHandle == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
-  }  \r
+  }\r
 \r
-  if (((KEYBOARD_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE) {\r
-    return EFI_INVALID_PARAMETER;\r
-  } \r
-  \r
   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);\r
-  \r
+\r
   //\r
   // Traverse notify list of USB keyboard and remove the entry of NotificationHandle.\r
   //\r
@@ -1136,18 +1169,18 @@ USBKeyboardUnregisterKeyNotify (
        !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
+      RemoveEntryList (&CurrentNotify->NotifyEntry);\r
 \r
-      FreePool (CurrentNotify);            \r
+      FreePool (CurrentNotify);\r
       return EFI_SUCCESS;\r
     }\r
   }\r
@@ -1155,6 +1188,55 @@ USBKeyboardUnregisterKeyNotify (
   //\r
   // Cannot find the matching entry in database.\r
   //\r
-  return EFI_INVALID_PARAMETER;  \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