]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c
IntelFrameworkModulePkg/KeyboardDxe: Use macro to enable/disable page 0
[mirror_edk2.git] / IntelFrameworkModulePkg / Csm / BiosThunk / KeyboardDxe / BiosKeyboard.c
index 4ee20df1f725bfad0337c7d1630afd7396ea1a4b..ec525891dc7a5659af89d1151a008ee1cc84fd4f 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   ConsoleOut Routines that speak VGA.\r
 \r
 /** @file\r
   ConsoleOut Routines that speak VGA.\r
 \r
-Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>\r
 \r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions\r
 \r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions\r
@@ -272,6 +272,8 @@ BiosKeyboardDriverBindingStart (
   \r
   BiosKeyboardPrivate->Queue.Front                = 0;\r
   BiosKeyboardPrivate->Queue.Rear                 = 0;\r
   \r
   BiosKeyboardPrivate->Queue.Front                = 0;\r
   BiosKeyboardPrivate->Queue.Rear                 = 0;\r
+  BiosKeyboardPrivate->QueueForNotify.Front       = 0;\r
+  BiosKeyboardPrivate->QueueForNotify.Rear        = 0;\r
   BiosKeyboardPrivate->SimpleTextInputEx.Reset               = BiosKeyboardResetEx;\r
   BiosKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx     = BiosKeyboardReadKeyStrokeEx;\r
   BiosKeyboardPrivate->SimpleTextInputEx.SetState            = BiosKeyboardSetState;\r
   BiosKeyboardPrivate->SimpleTextInputEx.Reset               = BiosKeyboardResetEx;\r
   BiosKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx     = BiosKeyboardReadKeyStrokeEx;\r
   BiosKeyboardPrivate->SimpleTextInputEx.SetState            = BiosKeyboardSetState;\r
@@ -339,7 +341,20 @@ BiosKeyboardDriverBindingStart (
     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;\r
     goto Done;\r
   }\r
     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;\r
     goto Done;\r
   }\r
-  \r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  KeyNotifyProcessHandler,\r
+                  BiosKeyboardPrivate,\r
+                  &BiosKeyboardPrivate->KeyNotifyProcessEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    Status      = EFI_OUT_OF_RESOURCES;\r
+    StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;\r
+    goto Done;\r
+  }\r
+\r
   //\r
   // Report a Progress Code for an attempt to detect the precense of the keyboard device in the system\r
   //\r
   //\r
   // Report a Progress Code for an attempt to detect the precense of the keyboard device in the system\r
   //\r
@@ -403,7 +418,7 @@ BiosKeyboardDriverBindingStart (
     // Check bit 6 of Feature Byte 2.\r
     // If it is set, then Int 16 Func 09 is supported\r
     //\r
     // Check bit 6 of Feature Byte 2.\r
     // If it is set, then Int 16 Func 09 is supported\r
     //\r
-    if (*(UINT8 *)(UINTN) ((Regs.X.ES << 4) + Regs.X.BX + 0x06) & 0x40) {\r
+    if (*(UINT8 *) (((UINTN) Regs.X.ES << 4) + Regs.X.BX + 0x06) & 0x40) {\r
       //\r
       // Get Keyboard Functionality\r
       //\r
       //\r
       // Get Keyboard Functionality\r
       //\r
@@ -462,6 +477,11 @@ Done:
       if ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) {\r
         gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx);    \r
       }\r
       if ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) {\r
         gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx);    \r
       }\r
+\r
+      if (BiosKeyboardPrivate->KeyNotifyProcessEvent != NULL) {\r
+        gBS->CloseEvent (BiosKeyboardPrivate->KeyNotifyProcessEvent);\r
+      }\r
+\r
       BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);\r
 \r
       if (BiosKeyboardPrivate->TimerEvent != NULL) {\r
       BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);\r
 \r
       if (BiosKeyboardPrivate->TimerEvent != NULL) {\r
@@ -566,6 +586,7 @@ BiosKeyboardDriverBindingStop (
   gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);\r
   gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);\r
   gBS->CloseEvent (BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx);\r
   gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);\r
   gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);\r
   gBS->CloseEvent (BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx);\r
+  gBS->CloseEvent (BiosKeyboardPrivate->KeyNotifyProcessEvent);\r
   BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);\r
 \r
   FreePool (BiosKeyboardPrivate);\r
   BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);\r
 \r
   FreePool (BiosKeyboardPrivate);\r
@@ -934,7 +955,7 @@ KeyboardReadKeyStrokeWorker (
   }\r
 \r
   //\r
   }\r
 \r
   //\r
-  // Use TimerEvent callback funciton to check whether there's any key pressed\r
+  // Use TimerEvent callback function to check whether there's any key pressed\r
   //\r
   \r
   //\r
   //\r
   \r
   //\r
@@ -978,7 +999,7 @@ KeyboardReadKeyStrokeWorker (
   @param  ExtendedVerification  Whether perform the extra validation of keyboard. True: perform; FALSE: skip.\r
 \r
   @retval EFI_SUCCESS           The command byte is written successfully.\r
   @param  ExtendedVerification  Whether perform the extra validation of keyboard. True: perform; FALSE: skip.\r
 \r
   @retval EFI_SUCCESS           The command byte is written successfully.\r
-  @retval EFI_DEVICE_ERROR      Errors occurred during reseting keyboard.\r
+  @retval EFI_DEVICE_ERROR      Errors occurred during resetting keyboard.\r
 \r
 **/\r
 EFI_STATUS\r
 \r
 **/\r
 EFI_STATUS\r
@@ -1176,8 +1197,8 @@ BiosKeyboardReset (
              );\r
 \r
   //\r
              );\r
 \r
   //\r
-  // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,\r
-  // so we only do the real reseting for keyboard when user asks, and normally during booting an OS, it's skipped.\r
+  // For resetting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,\r
+  // so we only do the real resetting for keyboard when user asks, and normally during booting an OS, it's skipped.\r
   // Call CheckKeyboardConnect() to check whether keyboard is connected, if it is not connected,\r
   // Real reset will not do.\r
   //\r
   // Call CheckKeyboardConnect() to check whether keyboard is connected, if it is not connected,\r
   // Real reset will not do.\r
   //\r
@@ -1431,7 +1452,7 @@ BiosKeyboardWaitForKey (
   //\r
   gBS->Stall (1000);\r
   //\r
   //\r
   gBS->Stall (1000);\r
   //\r
-  // Use TimerEvent callback funciton to check whether there's any key pressed\r
+  // Use TimerEvent callback function to check whether there's any key pressed\r
   //\r
   BiosKeyboardTimerHandler (NULL, BIOS_KEYBOARD_DEV_FROM_THIS (Context));\r
 \r
   //\r
   BiosKeyboardTimerHandler (NULL, BIOS_KEYBOARD_DEV_FROM_THIS (Context));\r
 \r
@@ -1795,7 +1816,7 @@ BiosKeyboardTimerHandler (
   // will be disabled after the thunk call finish, which means if user crazy input during int 9 being disabled, some keystrokes will be lost when \r
   // KB device own hardware buffer overflows. And if the lost keystroke code is CTRL or ALT or SHIFT release code, these function key flags bit \r
   // in BDA will not be updated. So the Int 16 will believe the CTRL or ALT or SHIFT is still pressed, and Int 16 will translate later scancode \r
   // will be disabled after the thunk call finish, which means if user crazy input during int 9 being disabled, some keystrokes will be lost when \r
   // KB device own hardware buffer overflows. And if the lost keystroke code is CTRL or ALT or SHIFT release code, these function key flags bit \r
   // in BDA will not be updated. So the Int 16 will believe the CTRL or ALT or SHIFT is still pressed, and Int 16 will translate later scancode \r
-  // to wrong ASCII code. We can increase the Thunk frequence to let Int 9 response in time, but this way will much hurt other dirvers \r
+  // to wrong ASCII code. We can increase the Thunk frequence to let Int 9 response in time, but this way will much hurt other drivers\r
   // performance, like USB.\r
   //\r
   // 1. If CTRL or ALT release code is missed,  all later input keys will be translated to wrong ASCII codes which the Tiano cannot support. In \r
   // performance, like USB.\r
   //\r
   // 1. If CTRL or ALT release code is missed,  all later input keys will be translated to wrong ASCII codes which the Tiano cannot support. In \r
@@ -1821,8 +1842,10 @@ BiosKeyboardTimerHandler (
   //\r
   // Clear the CTRL and ALT BDA flag\r
   //\r
   //\r
   // Clear the CTRL and ALT BDA flag\r
   //\r
-  KbFlag1 = *((UINT8 *) (UINTN) 0x417);  // read the STATUS FLAGS 1\r
-  KbFlag2 = *((UINT8 *) (UINTN) 0x418); // read STATUS FLAGS 2\r
+  ACCESS_PAGE0_CODE (\r
+    KbFlag1 = *((UINT8 *) (UINTN) 0x417); // read the STATUS FLAGS 1\r
+    KbFlag2 = *((UINT8 *) (UINTN) 0x418); // read STATUS FLAGS 2\r
+  );\r
 \r
   DEBUG_CODE (\r
     {\r
 \r
   DEBUG_CODE (\r
     {\r
@@ -1890,11 +1913,12 @@ BiosKeyboardTimerHandler (
   //\r
   // Clear left alt and left ctrl BDA flag\r
   //\r
   //\r
   // Clear left alt and left ctrl BDA flag\r
   //\r
-  KbFlag2 &= ~(KB_LEFT_ALT_PRESSED | KB_LEFT_CTRL_PRESSED);\r
-  *((UINT8 *) (UINTN) 0x418) = KbFlag2;\r
-  KbFlag1 &= ~0x0C;                      \r
-  *((UINT8 *) (UINTN) 0x417) = KbFlag1; \r
-\r
+  ACCESS_PAGE0_CODE (\r
+    KbFlag2 &= ~(KB_LEFT_ALT_PRESSED | KB_LEFT_CTRL_PRESSED);\r
+    *((UINT8 *) (UINTN) 0x418) = KbFlag2;\r
+    KbFlag1 &= ~0x0C;\r
+    *((UINT8 *) (UINTN) 0x417) = KbFlag1;\r
+  );\r
   \r
   //\r
   // Output EFI input key and shift/toggle state\r
   \r
   //\r
   // Output EFI input key and shift/toggle state\r
@@ -1941,7 +1965,7 @@ BiosKeyboardTimerHandler (
   }\r
 \r
   //\r
   }\r
 \r
   //\r
-  // Invoke notification functions if exist\r
+  // Signal KeyNotify process event if this key pressed matches any key registered.\r
   //\r
   for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {\r
     CurrentNotify = CR (\r
   //\r
   for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {\r
     CurrentNotify = CR (\r
@@ -1950,8 +1974,14 @@ BiosKeyboardTimerHandler (
                       NotifyEntry, \r
                       BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
                       );\r
                       NotifyEntry, \r
                       BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
                       );\r
-    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { \r
-      CurrentNotify->KeyNotificationFn (&KeyData);\r
+    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
+      //\r
+      // The key notification function needs to run at TPL_CALLBACK\r
+      // while current TPL is TPL_NOTIFY. It will be invoked in\r
+      // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.\r
+      //\r
+      Enqueue (&BiosKeyboardPrivate->QueueForNotify, &KeyData);\r
+      gBS->SignalEvent (BiosKeyboardPrivate->KeyNotifyProcessEvent);\r
     }\r
   }\r
 \r
     }\r
   }\r
 \r
@@ -1964,6 +1994,55 @@ BiosKeyboardTimerHandler (
   return ;  \r
 }\r
 \r
   return ;  \r
 }\r
 \r
+/**\r
+  Process key notify.\r
+\r
+  @param  Event                 Indicates the event that invoke this function.\r
+  @param  Context               Indicates the calling context.\r
+**/\r
+VOID\r
+EFIAPI\r
+KeyNotifyProcessHandler (\r
+  IN  EFI_EVENT                 Event,\r
+  IN  VOID                      *Context\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  BIOS_KEYBOARD_DEV                     *BiosKeyboardPrivate;\r
+  EFI_KEY_DATA                          KeyData;\r
+  LIST_ENTRY                            *Link;\r
+  LIST_ENTRY                            *NotifyList;\r
+  BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *CurrentNotify;\r
+  EFI_TPL                               OldTpl;\r
+\r
+  BiosKeyboardPrivate = (BIOS_KEYBOARD_DEV *) Context;\r
+\r
+  //\r
+  // Invoke notification functions.\r
+  //\r
+  NotifyList = &BiosKeyboardPrivate->NotifyList;\r
+  while (TRUE) {\r
+    //\r
+    // Enter critical section\r
+    //  \r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+    Status = Dequeue (&BiosKeyboardPrivate->QueueForNotify, &KeyData);\r
+    //\r
+    // Leave critical section\r
+    //\r
+    gBS->RestoreTPL (OldTpl);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {\r
+      CurrentNotify = CR (Link, BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE);\r
+      if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
+        CurrentNotify->KeyNotificationFn (&KeyData);\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
 /**\r
   Free keyboard notify list.\r
 \r
 /**\r
   Free keyboard notify list.\r
 \r
@@ -2202,15 +2281,18 @@ BiosKeyboardSetState (
 \r
   Status = KeyboardWrite (BiosKeyboardPrivate, 0xed);\r
   if (EFI_ERROR (Status)) {\r
 \r
   Status = KeyboardWrite (BiosKeyboardPrivate, 0xed);\r
   if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
   }  \r
   Status = KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);\r
   if (EFI_ERROR (Status)) {\r
   }  \r
   Status = KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);\r
   if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
   }\r
   Status = KeyboardWrite (BiosKeyboardPrivate, Command);\r
   if (EFI_ERROR (Status)) {\r
   }\r
   Status = KeyboardWrite (BiosKeyboardPrivate, Command);\r
   if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
   }  \r
   //\r
   // Call Legacy BIOS Protocol to set whatever is necessary\r
   }  \r
   //\r
   // Call Legacy BIOS Protocol to set whatever is necessary\r
@@ -2219,6 +2301,7 @@ BiosKeyboardSetState (
 \r
   Status = EFI_SUCCESS;\r
 \r
 \r
   Status = EFI_SUCCESS;\r
 \r
+Exit:\r
   //\r
   // Leave critical section and return\r
   //\r
   //\r
   // Leave critical section and return\r
   //\r
@@ -2233,17 +2316,20 @@ BiosKeyboardSetState (
 \r
   @param  This                    Protocol instance pointer.\r
   @param  KeyData                 A pointer to a buffer that is filled in with the keystroke \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
+                                  information data for the key that was pressed. If KeyData.Key,\r
+                                  KeyData.KeyState.KeyToggleState and KeyData.KeyState.KeyShiftState\r
+                                  are 0, then any incomplete keystroke will trigger a notification of\r
+                                  the KeyNotificationFunction.\r
   @param  KeyNotificationFunction Points to the function to be called when the key \r
   @param  KeyNotificationFunction Points to the function to be called when the key \r
-                                  sequence is typed specified by KeyData.                        \r
-  @param  NotifyHandle            Points to the unique handle assigned to the registered notification.                          \r
+                                  sequence is typed specified by KeyData. This notification function\r
+                                  should be called at <=TPL_CALLBACK.\r
+  @param  NotifyHandle            Points to the unique handle assigned to the registered notification.\r
 \r
 \r
-  \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_SUCCESS             The notification function was registered successfully.\r
   @retval EFI_OUT_OF_RESOURCES    Unable to allocate resources for necesssary data structures.\r
   @retval EFI_INVALID_PARAMETER   KeyData or NotifyHandle is NULL.\r
-                                                  \r
-**/   \r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 BiosKeyboardRegisterKeyNotify (\r
 EFI_STATUS\r
 EFIAPI\r
 BiosKeyboardRegisterKeyNotify (\r