]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Usb/UsbKbDxe/efikey.c
Merged in the following trackers from EDK:
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbKbDxe / efikey.c
index 62fec041c3ce4386d00a338427c64a90759c865f..50413bd500b0807bbb1dfc18047180d9cd41770d 100644 (file)
@@ -1,6 +1,6 @@
 /** @file\r
 \r
-Copyright (c) 2004 - 2007, Intel Corporation\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
@@ -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,32 @@ 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 = InitKeyboardLayout (UsbKeyboardDevice);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ErrorExit;\r
+  }\r
+\r
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_WAIT,\r
                   TPL_NOTIFY,\r
@@ -380,6 +418,8 @@ USBKeyboardDriverBindingStart (
                   &Controller,\r
                   &gEfiSimpleTextInProtocolGuid,\r
                   &UsbKeyboardDevice->SimpleInput,\r
+                  &gEfiSimpleTextInputExProtocolGuid,\r
+                  &UsbKeyboardDevice->SimpleInputEx,\r
                   &gEfiHotPlugDeviceGuid,\r
                   NULL,\r
                   NULL\r
@@ -405,13 +445,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 +484,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 +522,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
@@ -513,12 +578,22 @@ USBKeyboardDriverBindingStop (
                   (VOID **) &SimpleInput,\r
                   This->DriverBindingHandle,\r
                   Controller,\r
-                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\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
   //\r
   // Get USB_KB_DEV instance.\r
   //\r
@@ -565,6 +640,8 @@ USBKeyboardDriverBindingStop (
                   Controller,\r
                   &gEfiSimpleTextInProtocolGuid,\r
                   &UsbKeyboardDevice->SimpleInput,\r
+                  &gEfiSimpleTextInputExProtocolGuid,\r
+                  &UsbKeyboardDevice->SimpleInputEx,\r
                   &gEfiHotPlugDeviceGuid,\r
                   NULL,\r
                   NULL\r
@@ -575,6 +652,11 @@ 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
+  ReleaseKeyboardLayoutResources (UsbKeyboardDevice);\r
+  gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);\r
 \r
   if (UsbKeyboardDevice->ControllerNameTable != NULL) {\r
     FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable);\r
@@ -586,20 +668,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
-/**\r
-  Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset() function.\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
-  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
+  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
-  @retval EFI_SUCCESS           Success\r
-  @retval EFI_DEVICE_ERROR      Hardware Error\r
+--*/\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
+  }\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 +837,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
-\r
-  UsbKeyboardDevice->CurKeyChar = 0;\r
-\r
-  //\r
-  // Translate saved ASCII byte into EFI_INPUT_KEY\r
-  //\r
-  Status = USBKeyCodeToEFIScanCode (UsbKeyboardDevice, KeyChar, Key);\r
+  CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
 \r
-  return Status;\r
+  return EFI_SUCCESS;\r
 \r
 }\r
 \r
@@ -792,3 +945,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