]> 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
-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
@@ -272,6 +272,8 @@ BiosKeyboardDriverBindingStart (
   \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
@@ -339,7 +341,20 @@ BiosKeyboardDriverBindingStart (
     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
@@ -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
-    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
@@ -462,6 +477,11 @@ Done:
       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
@@ -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->KeyNotifyProcessEvent);\r
   BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);\r
 \r
   FreePool (BiosKeyboardPrivate);\r
@@ -934,7 +955,7 @@ KeyboardReadKeyStrokeWorker (
   }\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
@@ -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
-  @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
@@ -1176,8 +1197,8 @@ BiosKeyboardReset (
              );\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
@@ -1431,7 +1452,7 @@ BiosKeyboardWaitForKey (
   //\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
@@ -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
-  // 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
@@ -1821,8 +1842,10 @@ BiosKeyboardTimerHandler (
   //\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
@@ -1890,11 +1913,12 @@ BiosKeyboardTimerHandler (
   //\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
@@ -1941,7 +1965,7 @@ BiosKeyboardTimerHandler (
   }\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
@@ -1950,8 +1974,14 @@ BiosKeyboardTimerHandler (
                       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
@@ -1964,6 +1994,55 @@ BiosKeyboardTimerHandler (
   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
@@ -2202,15 +2281,18 @@ BiosKeyboardSetState (
 \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
-    return EFI_DEVICE_ERROR;\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\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
@@ -2219,6 +2301,7 @@ BiosKeyboardSetState (
 \r
   Status = EFI_SUCCESS;\r
 \r
+Exit:\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
-                                  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
-                                  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
   @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