]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Usb/UsbKbDxe/efikey.c
Update to support EFI_SIMPLE_INPUT_EX protocol
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbKbDxe / efikey.c
index 62fec041c3ce4386d00a338427c64a90759c865f..eee3827c2324ad12ff1acdf8494d2c9460cc8335 100644 (file)
@@ -100,6 +100,18 @@ USBKeyboardCheckForKey (
 EFI_GUID  gEfiUsbKeyboardDriverGuid = {\r
   0xa05f5f78, 0xfb3, 0x4d10, {0x90, 0x90, 0xac, 0x4, 0x6e, 0xeb, 0x7c, 0x3c}\r
 };\r
+STATIC\r
+EFI_STATUS\r
+KbdFreeNotifyList (\r
+  IN OUT LIST_ENTRY           *ListHead\r
+  );  \r
+STATIC\r
+BOOLEAN\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
@@ -349,6 +361,27 @@ USBKeyboardDriverBindingStart (
   UsbKeyboardDevice->Signature                  = USB_KB_DEV_SIGNATURE;\r
   UsbKeyboardDevice->SimpleInput.Reset          = USBKeyboardReset;\r
   UsbKeyboardDevice->SimpleInput.ReadKeyStroke  = USBKeyboardReadKeyStroke;\r
+\r
+  UsbKeyboardDevice->SimpleInputEx.Reset               = USBKeyboardResetEx;\r
+  UsbKeyboardDevice->SimpleInputEx.ReadKeyStrokeEx     = USBKeyboardReadKeyStrokeEx;\r
+  UsbKeyboardDevice->SimpleInputEx.SetState            = USBKeyboardSetState;\r
+  UsbKeyboardDevice->SimpleInputEx.RegisterKeyNotify   = USBKeyboardRegisterKeyNotify;\r
+  UsbKeyboardDevice->SimpleInputEx.UnregisterKeyNotify = USBKeyboardUnregisterKeyNotify; \r
+  \r
+  InitializeListHead (&UsbKeyboardDevice->NotifyList);\r
+  \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
+\r
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_WAIT,\r
                   TPL_NOTIFY,\r
@@ -380,6 +413,8 @@ USBKeyboardDriverBindingStart (
                   &Controller,\r
                   &gEfiSimpleTextInProtocolGuid,\r
                   &UsbKeyboardDevice->SimpleInput,\r
+                  &gEfiSimpleTextInputExProtocolGuid,\r
+                  &UsbKeyboardDevice->SimpleInputEx,\r
                   &gEfiHotPlugDeviceGuid,\r
                   NULL,\r
                   NULL\r
@@ -405,13 +440,15 @@ USBKeyboardDriverBindingStart (
                                             );\r
   if (EFI_ERROR (Status)) {\r
     gBS->UninstallMultipleProtocolInterfaces (\r
-          Controller,\r
-          &gEfiSimpleTextInProtocolGuid,\r
-          &UsbKeyboardDevice->SimpleInput,\r
-          &gEfiHotPlugDeviceGuid,\r
-          NULL,\r
-          NULL\r
-          );\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
@@ -442,13 +479,15 @@ USBKeyboardDriverBindingStart (
   if (EFI_ERROR (Status)) {\r
 \r
     gBS->UninstallMultipleProtocolInterfaces (\r
-          Controller,\r
-          &gEfiSimpleTextInProtocolGuid,\r
-          &UsbKeyboardDevice->SimpleInput,\r
-          &gEfiHotPlugDeviceGuid,\r
-          NULL,\r
-          NULL\r
-          );\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
@@ -478,6 +517,27 @@ USBKeyboardDriverBindingStart (
 \r
 \r
   return EFI_SUCCESS;\r
+\r
+ErrorExit:\r
+  if (UsbKeyboardDevice != NULL) {\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
+    UsbKeyboardDevice = NULL;\r
+  }\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiUsbIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+  return Status;\r
+\r
 }\r
 \r
 \r
@@ -518,7 +578,17 @@ USBKeyboardDriverBindingStop (
   if (EFI_ERROR (Status)) {\r
     return EFI_UNSUPPORTED;\r
   }\r
-\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiSimpleTextInputExProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
   //\r
   // Get USB_KB_DEV instance.\r
   //\r
@@ -565,6 +635,8 @@ USBKeyboardDriverBindingStop (
                   Controller,\r
                   &gEfiSimpleTextInProtocolGuid,\r
                   &UsbKeyboardDevice->SimpleInput,\r
+                  &gEfiSimpleTextInputExProtocolGuid,\r
+                  &UsbKeyboardDevice->SimpleInputEx,\r
                   &gEfiHotPlugDeviceGuid,\r
                   NULL,\r
                   NULL\r
@@ -575,6 +647,8 @@ USBKeyboardDriverBindingStop (
   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
 \r
   if (UsbKeyboardDevice->ControllerNameTable != NULL) {\r
     FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable);\r
@@ -586,20 +660,107 @@ USBKeyboardDriverBindingStop (
 \r
 }\r
 \r
+STATIC\r
+EFI_STATUS\r
+USBKeyboardReadKeyStrokeWorker (\r
+  IN  USB_KB_DEV                        *UsbKeyboardDevice,\r
+  OUT EFI_KEY_DATA                      *KeyData\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Reads the next keystroke from the input device. The WaitForKey Event can \r
+    be used to test for existance of a keystroke via WaitForEvent () call.\r
 \r
+  Arguments:\r
+    UsbKeyboardDevice     - Usb keyboard private structure.\r
+    KeyData               - A pointer to a buffer that is filled in with the keystroke \r
+                            state data for the key that was pressed.\r
 \r
-/**\r
-  Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset() function.\r
+  Returns:\r
+    EFI_SUCCESS           - The keystroke information was returned.\r
+    EFI_NOT_READY         - There was no keystroke data availiable.\r
+    EFI_DEVICE_ERROR      - The keystroke information was not returned due to \r
+                            hardware errors.\r
+    EFI_INVALID_PARAMETER - KeyData is NULL.                        \r
 \r
-  This      The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.\r
-  ExtendedVerification\r
-  Indicates that the driver may perform a more exhaustive\r
-  verification operation of the device during reset.\r
+--*/\r
+{\r
 \r
-  @retval EFI_SUCCESS           Success\r
-  @retval EFI_DEVICE_ERROR      Hardware Error\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
-**/\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
+  }\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) {\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 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
+\r
+  return EFI_SUCCESS;\r
+  \r
+}\r
 EFI_STATUS\r
 EFIAPI\r
 USBKeyboardReset (\r
@@ -668,36 +829,20 @@ USBKeyboardReadKeyStroke (
   OUT EFI_INPUT_KEY                 *Key\r
   )\r
 {\r
-  USB_KB_DEV  *UsbKeyboardDevice;\r
-  EFI_STATUS  Status;\r
-  UINT8       KeyChar;\r
+  USB_KB_DEV   *UsbKeyboardDevice;\r
+  EFI_STATUS   Status;\r
+  EFI_KEY_DATA KeyData;\r
 \r
   UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);\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
+  Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
 \r
-  Key->UnicodeChar              = 0;\r
-  Key->ScanCode                 = SCAN_NULL;\r
-\r
-  KeyChar                       = UsbKeyboardDevice->CurKeyChar;\r
+  CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
 \r
-  UsbKeyboardDevice->CurKeyChar = 0;\r
-\r
-  //\r
-  // Translate saved ASCII byte into EFI_INPUT_KEY\r
-  //\r
-  Status = USBKeyCodeToEFIScanCode (UsbKeyboardDevice, KeyChar, Key);\r
-\r
-  return Status;\r
+  return EFI_SUCCESS;\r
 \r
 }\r
 \r
@@ -792,3 +937,396 @@ KbdReportStatusCode (
     DevicePath\r
     );\r
 }\r
+STATIC\r
+EFI_STATUS\r
+KbdFreeNotifyList (\r
+  IN OUT LIST_ENTRY           *ListHead\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+  ListHead   - The list head\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Free the notify list successfully\r
+  EFI_INVALID_PARAMETER - ListHead is invalid.\r
+\r
+--*/\r
+{\r
+  KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;\r
+\r
+  if (ListHead == 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
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+BOOLEAN\r
+IsKeyRegistered (\r
+  IN EFI_KEY_DATA  *RegsiteredData,\r
+  IN EFI_KEY_DATA  *InputData\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+  RegsiteredData    - A pointer to a buffer that is filled in with the keystroke \r
+                      state data for the key that was registered.\r
+  InputData         - A pointer to a buffer that is filled in with the keystroke \r
+                      state data for the key that was pressed.\r
+\r
+Returns:\r
+  TRUE              - Key be pressed matches a registered key.\r
+  FLASE             - Match failed. \r
+  \r
+--*/\r
+{\r
+  ASSERT (RegsiteredData != NULL && InputData != NULL);\r
+  \r
+  if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||\r
+      (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {\r
+    return FALSE;  \r
+  }      \r
+  \r
+  //\r
+  // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.\r
+  //\r
+  if (RegsiteredData->KeyState.KeyShiftState != 0 &&\r
+      RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {\r
+    return FALSE;    \r
+  }   \r
+  if (RegsiteredData->KeyState.KeyToggleState != 0 &&\r
+      RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {\r
+    return FALSE;    \r
+  }     \r
+  \r
+  return TRUE;\r
+\r
+}\r
+\r
+//\r
+// Simple Text Input Ex protocol functions \r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+USBKeyboardResetEx (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN BOOLEAN                            ExtendedVerification\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Reset the input device and optionaly run diagnostics\r
+\r
+  Arguments:\r
+    This                 - Protocol instance pointer.\r
+    ExtendedVerification - Driver may perform diagnostics on reset.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The device was reset.\r
+    EFI_DEVICE_ERROR      - The device is not functioning properly and could \r
+                            not be reset.\r
+\r
+--*/\r
+{\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
+  Status = UsbKeyboardDevice->SimpleInput.Reset (&UsbKeyboardDevice->SimpleInput, ExtendedVerification);\r
+  if (EFI_ERROR (Status)) {\r
+    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
+EFI_STATUS\r
+EFIAPI\r
+USBKeyboardReadKeyStrokeEx (\r
+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
+  OUT EFI_KEY_DATA                      *KeyData\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Reads the next keystroke from the input device. The WaitForKey Event can \r
+    be used to test for existance of a keystroke via WaitForEvent () call.\r
+\r
+  Arguments:\r
+    This       - Protocol instance pointer.\r
+    KeyData    - A pointer to a buffer that is filled in with the keystroke \r
+                 state data for the key that was pressed.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The keystroke information was returned.\r
+    EFI_NOT_READY         - There was no keystroke data availiable.\r
+    EFI_DEVICE_ERROR      - The keystroke information was not returned due to \r
+                            hardware errors.\r
+    EFI_INVALID_PARAMETER - KeyData is NULL.                        \r
+\r
+--*/\r
+{\r
+  USB_KB_DEV                        *UsbKeyboardDevice;\r
+\r
+  if (KeyData == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);\r
+\r
+  return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, KeyData);\r
+  \r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+USBKeyboardSetState (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_KEY_TOGGLE_STATE               *KeyToggleState\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Set certain state for the input device.\r
+\r
+  Arguments:\r
+    This                  - Protocol instance pointer.\r
+    KeyToggleState        - A pointer to the EFI_KEY_TOGGLE_STATE to set the \r
+                            state for the input device.\r
+                          \r
+  Returns:                \r
+    EFI_SUCCESS           - The device state was set successfully.\r
+    EFI_DEVICE_ERROR      - The device is not functioning correctly and could \r
+                            not have the setting adjusted.\r
+    EFI_UNSUPPORTED       - The device does not have the ability to set its state.\r
+    EFI_INVALID_PARAMETER - KeyToggleState is NULL.                       \r
+\r
+--*/   \r
+{\r
+  USB_KB_DEV                        *UsbKeyboardDevice;\r
+\r
+  if (KeyToggleState == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);\r
+\r
+  if (((UsbKeyboardDevice->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||\r
+      ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Update the status light\r
+  //\r
+\r
+  UsbKeyboardDevice->ScrollOn   = 0;\r
+  UsbKeyboardDevice->NumLockOn  = 0;\r
+  UsbKeyboardDevice->CapsOn     = 0;\r
\r
+  if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {\r
+    UsbKeyboardDevice->ScrollOn = 1;\r
+  }\r
+  if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {\r
+    UsbKeyboardDevice->NumLockOn = 1;\r
+  }\r
+  if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {\r
+    UsbKeyboardDevice->CapsOn = 1;\r
+  }\r
+\r
+  SetKeyLED (UsbKeyboardDevice);\r
+\r
+  UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState;\r
+\r
+  return EFI_SUCCESS;\r
+  \r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+USBKeyboardRegisterKeyNotify (\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
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Register a notification function for a particular keystroke for the input device.\r
+\r
+  Arguments:\r
+    This                    - Protocol instance pointer.\r
+    KeyData                 - A pointer to a buffer that is filled in with the keystroke \r
+                              information data for the key that was pressed.\r
+    KeyNotificationFunction - Points to the function to be called when the key \r
+                              sequence is typed specified by KeyData.                        \r
+    NotifyHandle            - Points to the unique handle assigned to the registered notification.                          \r
+\r
+  Returns:\r
+    EFI_SUCCESS             - The notification function was registered successfully.\r
+    EFI_OUT_OF_RESOURCES    - Unable to allocate resources for necesssary data structures.\r
+    EFI_INVALID_PARAMETER   - KeyData or NotifyHandle is NULL.                       \r
+                              \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
+\r
+  if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);\r
+\r
+  //\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
+    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, KeyData)) { \r
+      if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {\r
+        *NotifyHandle = CurrentNotify->NotifyHandle;        \r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Allocate resource to save the notification function\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->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
+  return EFI_SUCCESS;\r
+  \r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+USBKeyboardUnregisterKeyNotify (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_HANDLE                         NotificationHandle\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Remove a registered notification function from a particular keystroke.\r
+\r
+  Arguments:\r
+    This                    - Protocol instance pointer.    \r
+    NotificationHandle      - The handle of the notification function being unregistered.\r
+\r
+  Returns:\r
+    EFI_SUCCESS             - The notification function was unregistered successfully.\r
+    EFI_INVALID_PARAMETER   - The NotificationHandle is invalid.\r
+    EFI_NOT_FOUND           - Can not find the matching entry in database.  \r
+                              \r
+--*/   \r
+{\r
+  USB_KB_DEV                        *UsbKeyboardDevice;\r
+  EFI_STATUS                        Status;\r
+  KEYBOARD_CONSOLE_IN_EX_NOTIFY     *CurrentNotify;\r
+  LIST_ENTRY                        *Link;\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
+    CurrentNotify = CR (\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
+      // 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
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;  \r
+}\r
+\r