]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / Console / ConSplitterDxe / ConSplitter.c
index dc23e321c814ddb8ddc965658592824c6277937c..6fc0e4796f9c2fa02615e0645af0d69a0a049418 100644 (file)
   never removed. Such design ensures sytem function well during none console\r
   device situation.\r
 \r
   never removed. Such design ensures sytem function well during none console\r
   device situation.\r
 \r
-Copyright (c) 2006 - 2012, 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
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "ConSplitter.h"\r
 \r
 //\r
 \r
 **/\r
 \r
 #include "ConSplitter.h"\r
 \r
 //\r
-// Identify if ConIn is connected in PcdConInConnectOnDemand enabled mode. \r
+// Identify if ConIn is connected in PcdConInConnectOnDemand enabled mode.\r
 // default not connect\r
 //\r
 BOOLEAN  mConInIsConnect = FALSE;\r
 // default not connect\r
 //\r
 BOOLEAN  mConInIsConnect = FALSE;\r
@@ -66,6 +61,10 @@ GLOBAL_REMOVE_IF_UNREFERENCED TEXT_IN_SPLITTER_PRIVATE_DATA  mConIn = {
     (LIST_ENTRY *) NULL,\r
     (LIST_ENTRY *) NULL\r
   },\r
     (LIST_ENTRY *) NULL,\r
     (LIST_ENTRY *) NULL\r
   },\r
+  (EFI_KEY_DATA *) NULL,\r
+  0,\r
+  0,\r
+  FALSE,\r
 \r
   {\r
     ConSplitterSimplePointerReset,\r
 \r
   {\r
     ConSplitterSimplePointerReset,\r
@@ -299,6 +298,122 @@ EFI_DRIVER_BINDING_PROTOCOL           gConSplitterAbsolutePointerDriverBinding =
   NULL\r
 };\r
 \r
   NULL\r
 };\r
 \r
+/**\r
+  Key notify for toggle state sync.\r
+\r
+  @param KeyData        A pointer to a buffer that is filled in with\r
+                        the keystroke information for the key that was\r
+                        pressed.\r
+\r
+  @retval EFI_SUCCESS   Toggle state sync successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ToggleStateSyncKeyNotify (\r
+  IN EFI_KEY_DATA   *KeyData\r
+  )\r
+{\r
+  UINTN     Index;\r
+\r
+  if (((KeyData->KeyState.KeyToggleState & KEY_STATE_VALID_EXPOSED) == KEY_STATE_VALID_EXPOSED) &&\r
+      (KeyData->KeyState.KeyToggleState != mConIn.PhysicalKeyToggleState)) {\r
+    //\r
+    // There is toggle state change, sync to other console input devices.\r
+    //\r
+    for (Index = 0; Index < mConIn.CurrentNumberOfExConsoles; Index++) {\r
+      mConIn.TextInExList[Index]->SetState (\r
+                                    mConIn.TextInExList[Index],\r
+                                    &KeyData->KeyState.KeyToggleState\r
+                                    );\r
+    }\r
+    mConIn.PhysicalKeyToggleState = KeyData->KeyState.KeyToggleState;\r
+    DEBUG ((EFI_D_INFO, "Current toggle state is 0x%02x\n", mConIn.PhysicalKeyToggleState));\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialization for toggle state sync.\r
+\r
+  @param Private                    Text In Splitter pointer.\r
+\r
+**/\r
+VOID\r
+ToggleStateSyncInitialization (\r
+  IN TEXT_IN_SPLITTER_PRIVATE_DATA  *Private\r
+  )\r
+{\r
+  EFI_KEY_DATA      KeyData;\r
+  VOID              *NotifyHandle;\r
+\r
+  //\r
+  // Initialize PhysicalKeyToggleState that will be synced to new console\r
+  // input device to turn on physical TextInEx partial key report for\r
+  // toggle state sync.\r
+  //\r
+  Private->PhysicalKeyToggleState = KEY_STATE_VALID_EXPOSED;\r
+\r
+  //\r
+  // Initialize VirtualKeyStateExported to let the virtual TextInEx not report\r
+  // the partial key even though the physical TextInEx turns on the partial\r
+  // key report. The virtual TextInEx will report the partial key after it is\r
+  // required by calling SetState(X | KEY_STATE_VALID_EXPOSED) explicitly.\r
+  //\r
+  Private->VirtualKeyStateExported = FALSE;\r
+\r
+  //\r
+  // Register key notify for toggle state sync.\r
+  //\r
+  KeyData.Key.ScanCode = SCAN_NULL;\r
+  KeyData.Key.UnicodeChar = CHAR_NULL;\r
+  KeyData.KeyState.KeyShiftState = 0;\r
+  KeyData.KeyState.KeyToggleState = 0;\r
+  Private->TextInEx.RegisterKeyNotify (\r
+                      &Private->TextInEx,\r
+                      &KeyData,\r
+                      ToggleStateSyncKeyNotify,\r
+                      &NotifyHandle\r
+                      );\r
+}\r
+\r
+/**\r
+  Reinitialization for toggle state sync.\r
+\r
+  @param Private                    Text In Splitter pointer.\r
+\r
+**/\r
+VOID\r
+ToggleStateSyncReInitialization (\r
+  IN TEXT_IN_SPLITTER_PRIVATE_DATA  *Private\r
+  )\r
+{\r
+  UINTN             Index;\r
+\r
+  //\r
+  // Reinitialize PhysicalKeyToggleState that will be synced to new console\r
+  // input device to turn on physical TextInEx partial key report for\r
+  // toggle state sync.\r
+  //\r
+  Private->PhysicalKeyToggleState = KEY_STATE_VALID_EXPOSED;\r
+\r
+  //\r
+  // Reinitialize VirtualKeyStateExported to let the virtual TextInEx not report\r
+  // the partial key even though the physical TextInEx turns on the partial\r
+  // key report. The virtual TextInEx will report the partial key after it is\r
+  // required by calling SetState(X | KEY_STATE_VALID_EXPOSED) explicitly.\r
+  //\r
+  Private->VirtualKeyStateExported = FALSE;\r
+\r
+  for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {\r
+    Private->TextInExList[Index]->SetState (\r
+                                    Private->TextInExList[Index],\r
+                                    &Private->PhysicalKeyToggleState\r
+                                    );\r
+  }\r
+}\r
+\r
 /**\r
   The Entry Point for module ConSplitter. The user code starts with this function.\r
 \r
 /**\r
   The Entry Point for module ConSplitter. The user code starts with this function.\r
 \r
@@ -418,49 +533,12 @@ ConSplitterDriverEntry(
   //\r
   Status = ConSplitterTextOutConstructor (&mConOut);\r
   if (!EFI_ERROR (Status)) {\r
   //\r
   Status = ConSplitterTextOutConstructor (&mConOut);\r
   if (!EFI_ERROR (Status)) {\r
-    if (!FeaturePcdGet (PcdConOutGopSupport)) {\r
-      //\r
-      // If Graphics Outpurt protocol not supported, UGA Draw protocol is installed\r
-      // on the virtual handle.\r
-      //\r
-      Status = gBS->InstallMultipleProtocolInterfaces (\r
-                      &mConOut.VirtualHandle,\r
-                      &gEfiSimpleTextOutProtocolGuid,\r
-                      &mConOut.TextOut,\r
-                      &gEfiUgaDrawProtocolGuid,\r
-                      &mConOut.UgaDraw,\r
-                      NULL\r
-                      );\r
-    } else if (!FeaturePcdGet (PcdConOutUgaSupport)) {\r
-      //\r
-      // If UGA Draw protocol not supported, Graphics Output Protocol is installed\r
-      // on virtual handle.\r
-      //\r
-      Status = gBS->InstallMultipleProtocolInterfaces (\r
-                      &mConOut.VirtualHandle,\r
-                      &gEfiSimpleTextOutProtocolGuid,\r
-                      &mConOut.TextOut,\r
-                      &gEfiGraphicsOutputProtocolGuid,\r
-                      &mConOut.GraphicsOutput,\r
-                      NULL\r
-                      );\r
-    } else {\r
-      //\r
-      // Boot Graphics Output protocol and UGA Draw protocol are supported,\r
-      // both they will be installed on virtual handle.\r
-      //\r
-      Status = gBS->InstallMultipleProtocolInterfaces (\r
-                      &mConOut.VirtualHandle,\r
-                      &gEfiSimpleTextOutProtocolGuid,\r
-                      &mConOut.TextOut,\r
-                      &gEfiGraphicsOutputProtocolGuid,\r
-                      &mConOut.GraphicsOutput,\r
-                      &gEfiUgaDrawProtocolGuid,\r
-                      &mConOut.UgaDraw,\r
-                      NULL\r
-                      );\r
-    }\r
-\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &mConOut.VirtualHandle,\r
+                    &gEfiSimpleTextOutProtocolGuid,\r
+                    &mConOut.TextOut,\r
+                    NULL\r
+                    );\r
     if (!EFI_ERROR (Status)) {\r
       //\r
       // Update the EFI System Table with new virtual console\r
     if (!EFI_ERROR (Status)) {\r
       //\r
       // Update the EFI System Table with new virtual console\r
@@ -483,7 +561,7 @@ ConSplitterDriverEntry(
                     &mStdErr.TextOut,\r
                     NULL\r
                     );\r
                     &mStdErr.TextOut,\r
                     NULL\r
                     );\r
-    if (!EFI_ERROR (Status)) {  \r
+    if (!EFI_ERROR (Status)) {\r
       //\r
       // Update the EFI System Table with new virtual console\r
       // and update the pointer to Text Output protocol.\r
       //\r
       // Update the EFI System Table with new virtual console\r
       // and update the pointer to Text Output protocol.\r
@@ -492,7 +570,7 @@ ConSplitterDriverEntry(
       gST->StdErr               = &mStdErr.TextOut;\r
     }\r
   }\r
       gST->StdErr               = &mStdErr.TextOut;\r
     }\r
   }\r
-  \r
+\r
   //\r
   // Update the CRC32 in the EFI System Table header\r
   //\r
   //\r
   // Update the CRC32 in the EFI System Table header\r
   //\r
@@ -524,6 +602,7 @@ ConSplitterTextInConstructor (
   )\r
 {\r
   EFI_STATUS  Status;\r
   )\r
 {\r
   EFI_STATUS  Status;\r
+  UINTN       TextInExListCount;\r
 \r
   //\r
   // Allocate buffer for Simple Text Input device\r
 \r
   //\r
   // Allocate buffer for Simple Text Input device\r
@@ -549,6 +628,19 @@ ConSplitterTextInConstructor (
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
+  //\r
+  // Allocate buffer for KeyQueue\r
+  //\r
+  TextInExListCount = ConInPrivate->TextInExListCount;\r
+  Status = ConSplitterGrowBuffer (\r
+             sizeof (EFI_KEY_DATA),\r
+             &TextInExListCount,\r
+             (VOID **) &ConInPrivate->KeyQueue\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
   //\r
   // Allocate buffer for Simple Text Input Ex device\r
   //\r
   //\r
   // Allocate buffer for Simple Text Input Ex device\r
   //\r
@@ -574,6 +666,8 @@ ConSplitterTextInConstructor (
 \r
   InitializeListHead (&ConInPrivate->NotifyList);\r
 \r
 \r
   InitializeListHead (&ConInPrivate->NotifyList);\r
 \r
+  ToggleStateSyncInitialization (ConInPrivate);\r
+\r
   ConInPrivate->AbsolutePointer.Mode = &ConInPrivate->AbsolutePointerMode;\r
   //\r
   // Allocate buffer for Absolute Pointer device\r
   ConInPrivate->AbsolutePointer.Mode = &ConInPrivate->AbsolutePointerMode;\r
   //\r
   // Allocate buffer for Absolute Pointer device\r
@@ -620,6 +714,18 @@ ConSplitterTextInConstructor (
                   ConInPrivate,\r
                   &ConInPrivate->SimplePointer.WaitForInput\r
                   );\r
                   ConInPrivate,\r
                   &ConInPrivate->SimplePointer.WaitForInput\r
                   );\r
+  ASSERT_EFI_ERROR (Status);\r
+  //\r
+  // Create Event to signal ConIn connection request\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  EfiEventEmptyFunction,\r
+                  NULL,\r
+                  &gConnectConInEventGuid,\r
+                  &ConInPrivate->ConnectConInEvent\r
+                  );\r
 \r
   return Status;\r
 }\r
 \r
   return Status;\r
 }\r
@@ -1303,7 +1409,7 @@ ConSplitterConOutDriverBindingStart (
 \r
       FreePool (Info);\r
 \r
 \r
       FreePool (Info);\r
 \r
-    } else if (UgaDraw != NULL  && FeaturePcdGet (PcdUgaConsumeSupport)) {\r
+    } else if (UgaDraw != NULL) {\r
       Status = UgaDraw->GetMode (\r
                  UgaDraw,\r
                  &mConOut.UgaHorizontalResolution,\r
       Status = UgaDraw->GetMode (\r
                  UgaDraw,\r
                  &mConOut.UgaHorizontalResolution,\r
@@ -1369,9 +1475,6 @@ ConSplitterStdErrDriverBindingStart (
   //\r
   Status = ConSplitterTextOutAddDevice (&mStdErr, TextOut, NULL, NULL);\r
   ConSplitterTextOutSetAttribute (&mStdErr.TextOut, EFI_TEXT_ATTR (EFI_MAGENTA, EFI_BLACK));\r
   //\r
   Status = ConSplitterTextOutAddDevice (&mStdErr, TextOut, NULL, NULL);\r
   ConSplitterTextOutSetAttribute (&mStdErr.TextOut, EFI_TEXT_ATTR (EFI_MAGENTA, EFI_BLACK));\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
 \r
   return Status;\r
 }\r
 \r
   return Status;\r
 }\r
@@ -1875,6 +1978,17 @@ ConSplitterTextInExAddDevice (
         return EFI_OUT_OF_RESOURCES;\r
       }\r
     }\r
         return EFI_OUT_OF_RESOURCES;\r
       }\r
     }\r
+\r
+    TextInExListCount = Private->TextInExListCount;\r
+    Status = ConSplitterGrowBuffer (\r
+               sizeof (EFI_KEY_DATA),\r
+               &TextInExListCount,\r
+               (VOID **) &Private->KeyQueue\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
     Status = ConSplitterGrowBuffer (\r
               sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *),\r
               &Private->TextInExListCount,\r
     Status = ConSplitterGrowBuffer (\r
               sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *),\r
               &Private->TextInExListCount,\r
@@ -1914,6 +2028,11 @@ ConSplitterTextInExAddDevice (
   Private->TextInExList[Private->CurrentNumberOfExConsoles] = TextInEx;\r
   Private->CurrentNumberOfExConsoles++;\r
 \r
   Private->TextInExList[Private->CurrentNumberOfExConsoles] = TextInEx;\r
   Private->CurrentNumberOfExConsoles++;\r
 \r
+  //\r
+  // Sync current toggle state to this new console input device.\r
+  //\r
+  TextInEx->SetState (TextInEx, &Private->PhysicalKeyToggleState);\r
+\r
   //\r
   // Extra CheckEvent added to reduce the double CheckEvent().\r
   //\r
   //\r
   // Extra CheckEvent added to reduce the double CheckEvent().\r
   //\r
@@ -2134,6 +2253,8 @@ ConSplitterGrowMapTable (
   INT32 *OldTextOutModeMap;\r
   INT32 *SrcAddress;\r
   INT32 Index;\r
   INT32 *OldTextOutModeMap;\r
   INT32 *SrcAddress;\r
   INT32 Index;\r
+  UINTN OldStepSize;\r
+  UINTN NewStepSize;\r
 \r
   NewSize           = Private->TextOutListCount * sizeof (INT32);\r
   OldTextOutModeMap = Private->TextOutModeMap;\r
 \r
   NewSize           = Private->TextOutListCount * sizeof (INT32);\r
   OldTextOutModeMap = Private->TextOutModeMap;\r
@@ -2171,14 +2292,26 @@ ConSplitterGrowMapTable (
     Size        = Private->CurrentNumberOfConsoles * sizeof (INT32);\r
     Index       = 0;\r
     SrcAddress  = OldTextOutModeMap;\r
     Size        = Private->CurrentNumberOfConsoles * sizeof (INT32);\r
     Index       = 0;\r
     SrcAddress  = OldTextOutModeMap;\r
+    NewStepSize = NewSize / sizeof(INT32);\r
+    // If Private->CurrentNumberOfConsoles is not zero and OldTextOutModeMap\r
+    // is not NULL, it indicates that the original TextOutModeMap is not enough\r
+    // for the new console devices and has been enlarged by CONSOLE_SPLITTER_ALLOC_UNIT columns.\r
+    //\r
+    OldStepSize = NewStepSize - CONSOLE_SPLITTER_ALLOC_UNIT;\r
 \r
     //\r
     // Copy the old data to the new one\r
     //\r
     while (Index < Private->TextOutMode.MaxMode) {\r
       CopyMem (TextOutModeMap, SrcAddress, Size);\r
 \r
     //\r
     // Copy the old data to the new one\r
     //\r
     while (Index < Private->TextOutMode.MaxMode) {\r
       CopyMem (TextOutModeMap, SrcAddress, Size);\r
-      TextOutModeMap += NewSize;\r
-      SrcAddress += Size;\r
+      //\r
+      // Go to next row of new TextOutModeMap.\r
+      //\r
+      TextOutModeMap += NewStepSize;\r
+      //\r
+      // Go to next row of old TextOutModeMap.\r
+      //\r
+      SrcAddress += OldStepSize;\r
       Index++;\r
     }\r
     //\r
       Index++;\r
     }\r
     //\r
@@ -2526,7 +2659,7 @@ ConSplitterGetIntersectionBetweenConOutAndStrErr (
 \r
   //\r
   // Find the intersection of the two set of modes. If they actually intersect, the\r
 \r
   //\r
   // Find the intersection of the two set of modes. If they actually intersect, the\r
-  // correponding entry in the map table is set to 1.\r
+  // corresponding entry in the map table is set to 1.\r
   //\r
   Mode = 0;\r
   while (Mode < ConOutMaxMode) {\r
   //\r
   Mode = 0;\r
   while (Mode < ConOutMaxMode) {\r
@@ -2786,7 +2919,7 @@ ConSplitterAddGraphicsOutputMode (
         }\r
       }\r
     }\r
         }\r
       }\r
     }\r
-  } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {\r
+  } else if (UgaDraw != NULL) {\r
     //\r
     // Graphics console driver can ensure the same mode for all GOP devices\r
     // so we can get the current mode from this video device\r
     //\r
     // Graphics console driver can ensure the same mode for all GOP devices\r
     // so we can get the current mode from this video device\r
@@ -2826,14 +2959,14 @@ Done:
   if (GraphicsOutput != NULL) {\r
     Private->CurrentNumberOfGraphicsOutput++;\r
   }\r
   if (GraphicsOutput != NULL) {\r
     Private->CurrentNumberOfGraphicsOutput++;\r
   }\r
-  if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {\r
+  if (UgaDraw != NULL) {\r
     Private->CurrentNumberOfUgaDraw++;\r
   }\r
 \r
   //\r
   // Force GraphicsOutput mode to be set,\r
   //\r
     Private->CurrentNumberOfUgaDraw++;\r
   }\r
 \r
   //\r
   // Force GraphicsOutput mode to be set,\r
   //\r
-  \r
+\r
   Mode = &Private->GraphicsOutputModeBuffer[CurrentIndex];\r
   if ((GraphicsOutput != NULL) &&\r
       (Mode->HorizontalResolution == CurrentGraphicsOutputMode->Info->HorizontalResolution) &&\r
   Mode = &Private->GraphicsOutputModeBuffer[CurrentIndex];\r
   if ((GraphicsOutput != NULL) &&\r
       (Mode->HorizontalResolution == CurrentGraphicsOutputMode->Info->HorizontalResolution) &&\r
@@ -2912,7 +3045,7 @@ ConsplitterSetConsoleOutMode (
   MaxMode      = (UINTN) (TextOut->Mode->MaxMode);\r
 \r
   MaxModeInfo.Column = 0;\r
   MaxMode      = (UINTN) (TextOut->Mode->MaxMode);\r
 \r
   MaxModeInfo.Column = 0;\r
-  MaxModeInfo.Row    = 0; \r
+  MaxModeInfo.Row    = 0;\r
   ModeInfo.Column    = PcdGet32 (PcdConOutColumn);\r
   ModeInfo.Row       = PcdGet32 (PcdConOutRow);\r
 \r
   ModeInfo.Column    = PcdGet32 (PcdConOutColumn);\r
   ModeInfo.Row       = PcdGet32 (PcdConOutRow);\r
 \r
@@ -2957,8 +3090,10 @@ ConsplitterSetConsoleOutMode (
     Status = TextOut->SetMode (TextOut, BaseMode);\r
     ASSERT(!EFI_ERROR(Status));\r
 \r
     Status = TextOut->SetMode (TextOut, BaseMode);\r
     ASSERT(!EFI_ERROR(Status));\r
 \r
-    PcdSet32 (PcdConOutColumn, 80);\r
-    PcdSet32 (PcdConOutRow, 25);\r
+    Status = PcdSet32S (PcdConOutColumn, 80);\r
+    ASSERT(!EFI_ERROR(Status));\r
+    Status = PcdSet32S (PcdConOutRow, 25);\r
+    ASSERT(!EFI_ERROR(Status));\r
   }\r
 \r
   return ;\r
   }\r
 \r
   return ;\r
@@ -3049,13 +3184,13 @@ ConSplitterTextOutAddDevice (
   ASSERT (MaxMode >= 1);\r
 \r
   DeviceStatus = EFI_DEVICE_ERROR;\r
   ASSERT (MaxMode >= 1);\r
 \r
   DeviceStatus = EFI_DEVICE_ERROR;\r
-  if (FeaturePcdGet (PcdConOutGopSupport)) {\r
-    //\r
-    // If GOP is produced by Consplitter, this device display mode will be added into Graphics Ouput modes.\r
-    //\r
-    if ((GraphicsOutput != NULL) || (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport))) {\r
-      DeviceStatus = ConSplitterAddGraphicsOutputMode (Private, GraphicsOutput, UgaDraw);\r
-    }\r
+  Status       = EFI_DEVICE_ERROR;\r
+\r
+  //\r
+  // This device display mode will be added into Graphics Ouput modes.\r
+  //\r
+  if ((GraphicsOutput != NULL) || (UgaDraw != NULL)) {\r
+    DeviceStatus = ConSplitterAddGraphicsOutputMode (Private, GraphicsOutput, UgaDraw);\r
   }\r
 \r
   if (FeaturePcdGet (PcdConOutUgaSupport)) {\r
   }\r
 \r
   if (FeaturePcdGet (PcdConOutUgaSupport)) {\r
@@ -3074,7 +3209,7 @@ ConSplitterTextOutAddDevice (
 \r
       FreePool (Info);\r
 \r
 \r
       FreePool (Info);\r
 \r
-    } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {\r
+    } else if (UgaDraw != NULL) {\r
       Status = UgaDraw->GetMode (\r
                     UgaDraw,\r
                     &UgaHorizontalResolution,\r
       Status = UgaDraw->GetMode (\r
                     UgaDraw,\r
                     &UgaHorizontalResolution,\r
@@ -3109,6 +3244,46 @@ ConSplitterTextOutAddDevice (
     }\r
   }\r
 \r
     }\r
   }\r
 \r
+  if (((!EFI_ERROR (DeviceStatus)) || (!EFI_ERROR (Status))) &&\r
+      ((Private->CurrentNumberOfGraphicsOutput + Private->CurrentNumberOfUgaDraw) == 1)) {\r
+    if (!FeaturePcdGet (PcdConOutGopSupport)) {\r
+      //\r
+      // If Graphics Outpurt protocol not supported, UGA Draw protocol is installed\r
+      // on the virtual handle.\r
+      //\r
+      Status = gBS->InstallMultipleProtocolInterfaces (\r
+                      &mConOut.VirtualHandle,\r
+                      &gEfiUgaDrawProtocolGuid,\r
+                      &mConOut.UgaDraw,\r
+                      NULL\r
+                      );\r
+    } else if (!FeaturePcdGet (PcdConOutUgaSupport)) {\r
+      //\r
+      // If UGA Draw protocol not supported, Graphics Output Protocol is installed\r
+      // on virtual handle.\r
+      //\r
+      Status = gBS->InstallMultipleProtocolInterfaces (\r
+                      &mConOut.VirtualHandle,\r
+                      &gEfiGraphicsOutputProtocolGuid,\r
+                      &mConOut.GraphicsOutput,\r
+                      NULL\r
+                      );\r
+    } else {\r
+      //\r
+      // Boot Graphics Output protocol and UGA Draw protocol are supported,\r
+      // both they will be installed on virtual handle.\r
+      //\r
+      Status = gBS->InstallMultipleProtocolInterfaces (\r
+                      &mConOut.VirtualHandle,\r
+                      &gEfiGraphicsOutputProtocolGuid,\r
+                      &mConOut.GraphicsOutput,\r
+                      &gEfiUgaDrawProtocolGuid,\r
+                      &mConOut.UgaDraw,\r
+                      NULL\r
+                      );\r
+    }\r
+  }\r
+\r
   //\r
   // After adding new console device, all existing console devices should be\r
   // synced to the current shared mode.\r
   //\r
   // After adding new console device, all existing console devices should be\r
   // synced to the current shared mode.\r
@@ -3149,7 +3324,7 @@ ConSplitterTextOutDeleteDevice (
   TextOutList           = Private->TextOutList;\r
   while (Index >= 0) {\r
     if (TextOutList->TextOut == TextOut) {\r
   TextOutList           = Private->TextOutList;\r
   while (Index >= 0) {\r
     if (TextOutList->TextOut == TextOut) {\r
-      if (TextOutList->UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {\r
+      if (TextOutList->UgaDraw != NULL) {\r
         Private->CurrentNumberOfUgaDraw--;\r
       }\r
       if (TextOutList->GraphicsOutput != NULL) {\r
         Private->CurrentNumberOfUgaDraw--;\r
       }\r
       if (TextOutList->GraphicsOutput != NULL) {\r
@@ -3170,6 +3345,35 @@ ConSplitterTextOutDeleteDevice (
     return EFI_NOT_FOUND;\r
   }\r
 \r
     return EFI_NOT_FOUND;\r
   }\r
 \r
+  if ((Private->CurrentNumberOfGraphicsOutput == 0) && (Private->CurrentNumberOfUgaDraw == 0)) {\r
+    //\r
+    // If there is not any physical GOP and UGA device in system,\r
+    // Consplitter GOP or UGA protocol will be uninstalled\r
+    //\r
+    if (!FeaturePcdGet (PcdConOutGopSupport)) {\r
+      Status = gBS->UninstallProtocolInterface (\r
+                      Private->VirtualHandle,\r
+                      &gEfiUgaDrawProtocolGuid,\r
+                      &Private->UgaDraw\r
+                      );\r
+    } else if (!FeaturePcdGet (PcdConOutUgaSupport)) {\r
+      Status = gBS->UninstallProtocolInterface (\r
+                      Private->VirtualHandle,\r
+                      &gEfiGraphicsOutputProtocolGuid,\r
+                      &Private->GraphicsOutput\r
+                      );\r
+    } else {\r
+      Status = gBS->UninstallMultipleProtocolInterfaces (\r
+             Private->VirtualHandle,\r
+             &gEfiUgaDrawProtocolGuid,\r
+             &Private->UgaDraw,\r
+             &gEfiGraphicsOutputProtocolGuid,\r
+             &Private->GraphicsOutput,\r
+             NULL\r
+             );\r
+    }\r
+  }\r
+\r
   if (CurrentNumOfConsoles == 0) {\r
     //\r
     // If the number of consoles is zero, reset all parameters\r
   if (CurrentNumOfConsoles == 0) {\r
     //\r
     // If the number of consoles is zero, reset all parameters\r
@@ -3260,9 +3464,48 @@ ConSplitterTextInReset (
     }\r
   }\r
 \r
     }\r
   }\r
 \r
+  if (!EFI_ERROR (ReturnStatus)) {\r
+    ToggleStateSyncReInitialization (Private);\r
+    //\r
+    // Empty the key queue.\r
+    //\r
+    Private->CurrentNumberOfKeys = 0;\r
+  }\r
+\r
   return ReturnStatus;\r
 }\r
 \r
   return ReturnStatus;\r
 }\r
 \r
+/**\r
+  Dequeue the saved key from internal key queue.\r
+\r
+  @param  Private                  Protocol instance pointer.\r
+  @param  KeyData                  A pointer to a buffer that is filled in with the\r
+                                   keystroke state data for the key that was\r
+                                   pressed.\r
+  @retval EFI_NOT_FOUND            Queue is empty.\r
+  @retval EFI_SUCCESS              First key is dequeued and returned.\r
+**/\r
+EFI_STATUS\r
+ConSplitterTextInExDequeueKey (\r
+  IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,\r
+  OUT EFI_KEY_DATA                    *KeyData\r
+  )\r
+{\r
+  if (Private->CurrentNumberOfKeys == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  //\r
+  // Return the first saved key.\r
+  //\r
+  CopyMem (KeyData, &Private->KeyQueue[0], sizeof (EFI_KEY_DATA));\r
+  Private->CurrentNumberOfKeys--;\r
+  CopyMem (\r
+    &Private->KeyQueue[0],\r
+    &Private->KeyQueue[1],\r
+    Private->CurrentNumberOfKeys * sizeof (EFI_KEY_DATA)\r
+    );\r
+  return EFI_SUCCESS;\r
+}\r
 \r
 /**\r
   Reads the next keystroke from the input device. The WaitForKey Event can\r
 \r
 /**\r
   Reads the next keystroke from the input device. The WaitForKey Event can\r
@@ -3286,7 +3529,21 @@ ConSplitterTextInPrivateReadKeyStroke (
 {\r
   EFI_STATUS    Status;\r
   UINTN         Index;\r
 {\r
   EFI_STATUS    Status;\r
   UINTN         Index;\r
-  EFI_INPUT_KEY CurrentKey;\r
+  EFI_KEY_DATA  KeyData;\r
+\r
+  //\r
+  // Return the first saved non-NULL key.\r
+  //\r
+  while (TRUE) {\r
+    Status = ConSplitterTextInExDequeueKey (Private, &KeyData);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    if ((KeyData.Key.ScanCode != CHAR_NULL) || (KeyData.Key.UnicodeChar != SCAN_NULL)) {\r
+      CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
+      return Status;\r
+    }\r
+  }\r
 \r
   Key->UnicodeChar  = 0;\r
   Key->ScanCode     = SCAN_NULL;\r
 \r
   Key->UnicodeChar  = 0;\r
   Key->ScanCode     = SCAN_NULL;\r
@@ -3296,257 +3553,29 @@ ConSplitterTextInPrivateReadKeyStroke (
   // if any physical console input device has key input,\r
   // return the key and EFI_SUCCESS.\r
   //\r
   // if any physical console input device has key input,\r
   // return the key and EFI_SUCCESS.\r
   //\r
-  for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\r
+  for (Index = 0; Index < Private->CurrentNumberOfConsoles;) {\r
     Status = Private->TextInList[Index]->ReadKeyStroke (\r
                                           Private->TextInList[Index],\r
     Status = Private->TextInList[Index]->ReadKeyStroke (\r
                                           Private->TextInList[Index],\r
-                                          &CurrentKey\r
+                                          &KeyData.Key\r
                                           );\r
                                           );\r
-    if (!EFI_ERROR (Status)) {\r
-      *Key = CurrentKey;\r
-      return Status;\r
-    }\r
-  }\r
-\r
-  return EFI_NOT_READY;\r
-}\r
-\r
-/**\r
-  Connect the specific Usb device which match the short form device path,\r
-  and whose bus is determined by Host Controller.\r
-\r
-  @param  DevicePath             A short-form device path that starts with the first\r
-                                 element being a USB WWID or a USB Class device\r
-                                 path\r
-\r
-  @return EFI_INVALID_PARAMETER  DevicePath is NULL pointer.\r
-                                 DevicePath is not a USB device path.\r
-\r
-  @return EFI_SUCCESS            Success to connect USB device\r
-  @return EFI_NOT_FOUND          Fail to find handle for USB controller to connect.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-ConSplitterConnectUsbShortFormDevicePath (\r
-  IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath\r
-  )\r
-{\r
-  EFI_STATUS                            Status;\r
-  EFI_HANDLE                            *Handles;\r
-  UINTN                                 HandleCount;\r
-  UINTN                                 Index;\r
-  EFI_PCI_IO_PROTOCOL                   *PciIo;\r
-  UINT8                                 Class[3];\r
-  BOOLEAN                               AtLeastOneConnected;\r
-\r
-  //\r
-  // Check the passed in parameters\r
-  //\r
-  if (DevicePath == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  if ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) ||\r
-      ((DevicePathSubType (DevicePath) != MSG_USB_CLASS_DP) && (DevicePathSubType (DevicePath) != MSG_USB_WWID_DP))\r
-     ) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  //\r
-  // Find the usb host controller firstly, then connect with the remaining device path\r
-  //\r
-  AtLeastOneConnected = FALSE;\r
-  Status = gBS->LocateHandleBuffer (\r
-                  ByProtocol,\r
-                  &gEfiPciIoProtocolGuid,\r
-                  NULL,\r
-                  &HandleCount,\r
-                  &Handles\r
-                  );\r
-  for (Index = 0; Index < HandleCount; Index++) {\r
-    Status = gBS->HandleProtocol (\r
-                    Handles[Index],\r
-                    &gEfiPciIoProtocolGuid,\r
-                    (VOID **) &PciIo\r
-                    );\r
     if (!EFI_ERROR (Status)) {\r
       //\r
     if (!EFI_ERROR (Status)) {\r
       //\r
-      // Check whether the Pci device is the wanted usb host controller\r
+      // If it is not partial keystorke, return the key. Otherwise, continue\r
+      // to read key from THIS physical console input device.\r
       //\r
       //\r
-      Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);\r
-      if (!EFI_ERROR (Status) &&\r
-          ((PCI_CLASS_SERIAL == Class[2]) && (PCI_CLASS_SERIAL_USB == Class[1]))\r
-         ) {\r
-        Status = gBS->ConnectController (\r
-                        Handles[Index],\r
-                        NULL,\r
-                        DevicePath,\r
-                        FALSE\r
-                        );\r
-        if (!EFI_ERROR(Status)) {\r
-          AtLeastOneConnected = TRUE;\r
-        }\r
+      if ((KeyData.Key.ScanCode != CHAR_NULL) || (KeyData.Key.UnicodeChar != SCAN_NULL)) {\r
+        CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
+        return Status;\r
       }\r
       }\r
+    } else {\r
+      //\r
+      // Continue to read key from NEXT physical console input device.\r
+      //\r
+      Index++;\r
     }\r
   }\r
 \r
     }\r
   }\r
 \r
-  return AtLeastOneConnected ? EFI_SUCCESS : EFI_NOT_FOUND;\r
-}\r
-\r
-\r
-/**\r
-  This function will create all handles associate with every device\r
-  path node. If the handle associate with one device path node can not\r
-  be created successfully, then still give one chance to do the dispatch,\r
-  which load the missing drivers if possible.\r
-\r
-  @param  DevicePathToConnect   The device path which will be connected, it CANNOT be\r
-                                a multi-instance device path\r
-  @param  MatchingHandle        Return the controller handle closest to the DevicePathToConnect\r
-\r
-  @retval EFI_INVALID_PARAMETER DevicePathToConnect is NULL.\r
-  @retval EFI_NOT_FOUND         Failed to create all handles associate with every device path node.\r
-  @retval EFI_SUCCESS           Successful to create all handles associate with every device path node.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-ConSplitterConnectDevicePath (\r
-  IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePathToConnect,\r
-  OUT EFI_HANDLE                *MatchingHandle          OPTIONAL\r
-  )\r
-{\r
-  EFI_STATUS                Status;\r
-  EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;\r
-  EFI_HANDLE                Handle;\r
-  EFI_HANDLE                PreviousHandle;\r
-\r
-  if (DevicePathToConnect == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  //\r
-  // Start the real work of connect with RemainingDevicePath\r
-  //\r
-  PreviousHandle = NULL;\r
-  do {\r
-    //\r
-    // Find the handle that best matches the Device Path. If it is only a\r
-    // partial match the remaining part of the device path is returned in\r
-    // RemainingDevicePath.\r
-    //\r
-    RemainingDevicePath = DevicePathToConnect;\r
-    Status              = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);\r
-    if (!EFI_ERROR (Status)) {\r
-      if (Handle == PreviousHandle) {\r
-        //\r
-        // If no forward progress is made try invoking the Dispatcher.\r
-        // A new FV may have been added to the system an new drivers\r
-        // may now be found.\r
-        // Status == EFI_SUCCESS means a driver was dispatched\r
-        // Status == EFI_NOT_FOUND means no new drivers were dispatched\r
-        //\r
-        Status = gDS->Dispatch ();\r
-      }\r
-\r
-      if (!EFI_ERROR (Status)) {\r
-        PreviousHandle = Handle;\r
-        //\r
-        // Connect all drivers that apply to Handle and RemainingDevicePath,\r
-        // the Recursive flag is FALSE so only one level will be expanded.\r
-        //\r
-        // Do not check the connect status here, if the connect controller fail,\r
-        // then still give the chance to do dispatch, because partial\r
-        // RemainingDevicepath may be in the new FV\r
-        //\r
-        // 1. If the connect fail, RemainingDevicepath and handle will not\r
-        //    change, so next time will do the dispatch, then dispatch's status\r
-        //    will take effect\r
-        // 2. If the connect success, the RemainingDevicepath and handle will\r
-        //    change, then avoid the dispatch, we have chance to continue the\r
-        //    next connection\r
-        //\r
-        gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);\r
-        if (MatchingHandle != NULL) {\r
-          *MatchingHandle = Handle;\r
-        }\r
-      }\r
-    }\r
-    //\r
-    // Loop until RemainingDevicePath is an empty device path\r
-    //\r
-  } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));\r
-\r
-  ASSERT (EFI_ERROR (Status) || IsDevicePathEnd (RemainingDevicePath));\r
-\r
-  return Status;\r
-}\r
-\r
-\r
-/**\r
-  Connect to all ConIn device which is in the ConIn variable.\r
-\r
-  @param  DevicePath             A short-form device path that starts with the first\r
-                                 element being a USB WWID or a USB Class device\r
-                                 path\r
-\r
-  @return EFI_INVALID_PARAMETER  DevicePath is NULL pointer.\r
-                                 DevicePath is not a USB device path.\r
-\r
-  @return EFI_SUCCESS            Success to connect USB device\r
-  @return EFI_NOT_FOUND          Fail to find handle for USB controller to connect.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-ConSplitterConnectConInDevicePath (\r
-  \r
-  )\r
-{\r
-  EFI_DEVICE_PATH_PROTOCOL              *DevicePath;\r
-  EFI_DEVICE_PATH_PROTOCOL              *DevicePathInst;\r
-  EFI_DEVICE_PATH_PROTOCOL              *CopyDevicePath;\r
-  UINTN                                 Size;\r
-  EFI_DEVICE_PATH_PROTOCOL              *Next;\r
-\r
-  DevicePath = GetEfiGlobalVariable (L"ConIn");\r
-\r
-  //\r
-  // Check the passed in parameters\r
-  //\r
-  if (DevicePath == NULL) {\r
-    return EFI_NOT_FOUND;\r
-  }\r
-\r
-  CopyDevicePath = DevicePath;\r
-\r
-  DevicePathInst  = GetNextDevicePathInstance (&DevicePath, &Size);\r
-  while (DevicePathInst != NULL) {\r
-\r
-    Next      = DevicePathInst;\r
-    while (!IsDevicePathEndType (Next)) {\r
-      Next = NextDevicePathNode (Next);\r
-    }\r
-\r
-    SetDevicePathEndNode (Next);\r
-    \r
-    //\r
-    // Connect the USB console\r
-    // USB console device path is a short-form device path that \r
-    //  starts with the first element being a USB WWID\r
-    //  or a USB Class device path\r
-    //\r
-    if ((DevicePathType (DevicePathInst) == MESSAGING_DEVICE_PATH) &&\r
-       ((DevicePathSubType (DevicePathInst) == MSG_USB_CLASS_DP)\r
-       || (DevicePathSubType (DevicePathInst) == MSG_USB_WWID_DP)\r
-       )) {\r
-      ConSplitterConnectUsbShortFormDevicePath (DevicePathInst);\r
-    } else {\r
-      ConSplitterConnectDevicePath (DevicePathInst, NULL);\r
-    }    \r
-    DevicePathInst  = GetNextDevicePathInstance (&DevicePath, &Size);\r
-  }\r
-  return EFI_SUCCESS;\r
+  return EFI_NOT_READY;\r
 }\r
 \r
 \r
 }\r
 \r
 \r
@@ -3578,11 +3607,11 @@ ConSplitterTextInReadKeyStroke (
   Private->KeyEventSignalState = FALSE;\r
 \r
   //\r
   Private->KeyEventSignalState = FALSE;\r
 \r
   //\r
-  // Connect ConIn when first call in Lazy ConIn mode\r
+  // Signal ConnectConIn event on first call in Lazy ConIn mode\r
   //\r
   if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {\r
   //\r
   if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {\r
-    DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));    \r
-    ConSplitterConnectConInDevicePath ();\r
+    DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));\r
+    gBS->SignalEvent (Private->ConnectConInEvent);\r
     mConInIsConnect = TRUE;\r
   }\r
 \r
     mConInIsConnect = TRUE;\r
   }\r
 \r
@@ -3720,6 +3749,14 @@ ConSplitterTextInResetEx (
     }\r
   }\r
 \r
     }\r
   }\r
 \r
+  if (!EFI_ERROR (ReturnStatus)) {\r
+    ToggleStateSyncReInitialization (Private);\r
+    //\r
+    // Empty the key queue.\r
+    //\r
+    Private->CurrentNumberOfKeys = 0;\r
+  }\r
+\r
   return ReturnStatus;\r
 \r
 }\r
   return ReturnStatus;\r
 \r
 }\r
@@ -3751,6 +3788,7 @@ ConSplitterTextInReadKeyStrokeEx (
   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;\r
   EFI_STATUS                    Status;\r
   UINTN                         Index;\r
   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;\r
   EFI_STATUS                    Status;\r
   UINTN                         Index;\r
+  EFI_KEY_STATE                 KeyState;\r
   EFI_KEY_DATA                  CurrentKeyData;\r
 \r
 \r
   EFI_KEY_DATA                  CurrentKeyData;\r
 \r
 \r
@@ -3758,38 +3796,95 @@ ConSplitterTextInReadKeyStrokeEx (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  Private->KeyEventSignalState = FALSE;\r
+\r
   //\r
   //\r
-  // Connect ConIn when first call in Lazy ConIn mode\r
+  // Signal ConnectConIn event on first call in Lazy ConIn mode\r
   //\r
   if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {\r
   //\r
   if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {\r
-    DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));    \r
-    ConSplitterConnectConInDevicePath ();\r
+    DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));\r
+    gBS->SignalEvent (Private->ConnectConInEvent);\r
     mConInIsConnect = TRUE;\r
   }\r
 \r
     mConInIsConnect = TRUE;\r
   }\r
 \r
-  Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
-\r
-  Private->KeyEventSignalState = FALSE;\r
+  //\r
+  // Return the first saved key.\r
+  //\r
+  Status = ConSplitterTextInExDequeueKey (Private, KeyData);\r
+  if (!EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (Private->CurrentNumberOfKeys == 0);\r
 \r
 \r
-  KeyData->Key.UnicodeChar  = 0;\r
-  KeyData->Key.ScanCode     = SCAN_NULL;\r
+  ZeroMem (&KeyState, sizeof (KeyState));\r
 \r
   //\r
 \r
   //\r
-  // if no physical console input device exists, return EFI_NOT_READY;\r
-  // if any physical console input device has key input,\r
-  // return the key and EFI_SUCCESS.\r
+  // Iterate through all physical consoles to get key state.\r
+  // Some physical consoles may return valid key.\r
+  // Queue the valid keys.\r
   //\r
   for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {\r
   //\r
   for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {\r
+    ZeroMem (&CurrentKeyData, sizeof (EFI_KEY_DATA));\r
     Status = Private->TextInExList[Index]->ReadKeyStrokeEx (\r
     Status = Private->TextInExList[Index]->ReadKeyStrokeEx (\r
-                                          Private->TextInExList[Index],\r
-                                          &CurrentKeyData\r
-                                          );\r
+                                             Private->TextInExList[Index],\r
+                                             &CurrentKeyData\r
+                                             );\r
+    if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Consolidate the key state from all physical consoles.\r
+    //\r
+    if ((CurrentKeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) {\r
+      KeyState.KeyShiftState |= CurrentKeyData.KeyState.KeyShiftState;\r
+    }\r
+    if ((CurrentKeyData.KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != 0) {\r
+      KeyState.KeyToggleState |= CurrentKeyData.KeyState.KeyToggleState;\r
+    }\r
+\r
     if (!EFI_ERROR (Status)) {\r
     if (!EFI_ERROR (Status)) {\r
-      CopyMem (KeyData, &CurrentKeyData, sizeof (CurrentKeyData));\r
-      return Status;\r
+      //\r
+      // If virtual KeyState has been required to be exposed, or it is not\r
+      // partial keystorke, queue the key.\r
+      // It's possible that user presses at multiple keyboards at the same moment,\r
+      // Private->KeyQueue[] are the storage to save all the keys.\r
+      //\r
+      if ((Private->VirtualKeyStateExported) ||\r
+          (CurrentKeyData.Key.ScanCode != CHAR_NULL) ||\r
+          (CurrentKeyData.Key.UnicodeChar != SCAN_NULL)) {\r
+        CopyMem (\r
+          &Private->KeyQueue[Private->CurrentNumberOfKeys],\r
+          &CurrentKeyData,\r
+          sizeof (EFI_KEY_DATA)\r
+          );\r
+        Private->CurrentNumberOfKeys++;\r
+      }\r
     }\r
   }\r
 \r
     }\r
   }\r
 \r
+  //\r
+  // Consolidate the key state for all keys in Private->KeyQueue[]\r
+  //\r
+  for (Index = 0; Index < Private->CurrentNumberOfKeys; Index++) {\r
+    CopyMem (&Private->KeyQueue[Index].KeyState, &KeyState, sizeof (EFI_KEY_STATE));\r
+  }\r
+\r
+  //\r
+  // Return the first saved key.\r
+  //\r
+  Status = ConSplitterTextInExDequeueKey (Private, KeyData);\r
+  if (!EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Always return the key state even there is no key pressed.\r
+  //\r
+  ZeroMem (&KeyData->Key, sizeof (KeyData->Key));\r
+  CopyMem (&KeyData->KeyState, &KeyState, sizeof (KeyData->KeyState));\r
   return EFI_NOT_READY;\r
 }\r
 \r
   return EFI_NOT_READY;\r
 }\r
 \r
@@ -3819,6 +3914,7 @@ ConSplitterTextInSetState (
   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;\r
   EFI_STATUS                    Status;\r
   UINTN                         Index;\r
   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;\r
   EFI_STATUS                    Status;\r
   UINTN                         Index;\r
+  EFI_KEY_TOGGLE_STATE          PhysicalKeyToggleState;\r
 \r
   if (KeyToggleState == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
 \r
   if (KeyToggleState == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -3826,6 +3922,12 @@ ConSplitterTextInSetState (
 \r
   Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
 \r
 \r
   Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
 \r
+  //\r
+  // Always turn on physical TextInEx partial key report for\r
+  // toggle state sync.\r
+  //\r
+  PhysicalKeyToggleState = *KeyToggleState | EFI_KEY_STATE_EXPOSED;\r
+\r
   //\r
   // if no physical console input device exists, return EFI_SUCCESS;\r
   // otherwise return the status of setting state of physical console input device\r
   //\r
   // if no physical console input device exists, return EFI_SUCCESS;\r
   // otherwise return the status of setting state of physical console input device\r
@@ -3833,13 +3935,22 @@ ConSplitterTextInSetState (
   for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {\r
     Status = Private->TextInExList[Index]->SetState (\r
                                              Private->TextInExList[Index],\r
   for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {\r
     Status = Private->TextInExList[Index]->SetState (\r
                                              Private->TextInExList[Index],\r
-                                             KeyToggleState\r
+                                             &PhysicalKeyToggleState\r
                                              );\r
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
   }\r
 \r
                                              );\r
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
   }\r
 \r
+  //\r
+  // Record the physical KeyToggleState.\r
+  //\r
+  Private->PhysicalKeyToggleState = PhysicalKeyToggleState;\r
+  //\r
+  // Get if virtual KeyState has been required to be exposed.\r
+  //\r
+  Private->VirtualKeyStateExported = (((*KeyToggleState) & EFI_KEY_STATE_EXPOSED) != 0);\r
+\r
   return EFI_SUCCESS;\r
 \r
 }\r
   return EFI_SUCCESS;\r
 \r
 }\r
@@ -3849,11 +3960,14 @@ ConSplitterTextInSetState (
   Register a notification function for a particular keystroke for the input device.\r
 \r
   @param  This                     Protocol instance pointer.\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\r
-                                   keystroke information data for the key that was\r
-                                   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
   @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\r
                                    registered notification.\r
 \r
   @param  NotifyHandle             Points to the unique handle assigned to the\r
                                    registered notification.\r
 \r
@@ -3943,7 +4057,7 @@ ConSplitterTextInRegisterKeyNotify (
     }\r
   }\r
 \r
     }\r
   }\r
 \r
-  InsertTailList (&mConIn.NotifyList, &NewNotify->NotifyEntry);\r
+  InsertTailList (&Private->NotifyList, &NewNotify->NotifyEntry);\r
 \r
   *NotifyHandle                = NewNotify;\r
 \r
 \r
   *NotifyHandle                = NewNotify;\r
 \r
@@ -4275,7 +4389,18 @@ ConSplitterAbsolutePointerGetState (
   EFI_STATUS                    ReturnStatus;\r
   UINTN                         Index;\r
   EFI_ABSOLUTE_POINTER_STATE    CurrentState;\r
   EFI_STATUS                    ReturnStatus;\r
   UINTN                         Index;\r
   EFI_ABSOLUTE_POINTER_STATE    CurrentState;\r
-\r
+  UINT64                        MinX;\r
+  UINT64                        MinY;\r
+  UINT64                        MinZ;\r
+  UINT64                        MaxX;\r
+  UINT64                        MaxY;\r
+  UINT64                        MaxZ;\r
+  UINT64                        VirtualMinX;\r
+  UINT64                        VirtualMinY;\r
+  UINT64                        VirtualMinZ;\r
+  UINT64                        VirtualMaxX;\r
+  UINT64                        VirtualMaxY;\r
+  UINT64                        VirtualMaxZ;\r
 \r
   Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS (This);\r
 \r
 \r
   Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS (This);\r
 \r
@@ -4286,6 +4411,13 @@ ConSplitterAbsolutePointerGetState (
   State->CurrentZ                        = 0;\r
   State->ActiveButtons                   = 0;\r
 \r
   State->CurrentZ                        = 0;\r
   State->ActiveButtons                   = 0;\r
 \r
+  VirtualMinX = Private->AbsolutePointerMode.AbsoluteMinX;\r
+  VirtualMinY = Private->AbsolutePointerMode.AbsoluteMinY;\r
+  VirtualMinZ = Private->AbsolutePointerMode.AbsoluteMinZ;\r
+  VirtualMaxX = Private->AbsolutePointerMode.AbsoluteMaxX;\r
+  VirtualMaxY = Private->AbsolutePointerMode.AbsoluteMaxY;\r
+  VirtualMaxZ = Private->AbsolutePointerMode.AbsoluteMaxZ;\r
+\r
   //\r
   // if no physical pointer device exists, return EFI_NOT_READY;\r
   // if any physical pointer device has changed state,\r
   //\r
   // if no physical pointer device exists, return EFI_NOT_READY;\r
   // if any physical pointer device has changed state,\r
@@ -4303,16 +4435,47 @@ ConSplitterAbsolutePointerGetState (
         ReturnStatus = EFI_SUCCESS;\r
       }\r
 \r
         ReturnStatus = EFI_SUCCESS;\r
       }\r
 \r
+      MinX = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinX;\r
+      MinY = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinY;\r
+      MinZ = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinZ;\r
+      MaxX = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxX;\r
+      MaxY = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxY;\r
+      MaxZ = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxZ;\r
+\r
       State->ActiveButtons = CurrentState.ActiveButtons;\r
 \r
       State->ActiveButtons = CurrentState.ActiveButtons;\r
 \r
-      if (!(Private->AbsolutePointerMode.AbsoluteMinX == 0 && Private->AbsolutePointerMode.AbsoluteMaxX == 0)) {\r
-        State->CurrentX = CurrentState.CurrentX;\r
+      //\r
+      // Rescale to Con Splitter virtual Absolute Pointer's resolution.\r
+      //\r
+      if (!(MinX == 0 && MaxX == 0)) {\r
+        State->CurrentX = VirtualMinX + DivU64x64Remainder (\r
+                                          MultU64x64 (\r
+                                            CurrentState.CurrentX,\r
+                                            VirtualMaxX - VirtualMinX\r
+                                            ),\r
+                                          MaxX - MinX,\r
+                                          NULL\r
+                                          );\r
       }\r
       }\r
-      if (!(Private->AbsolutePointerMode.AbsoluteMinY == 0 && Private->AbsolutePointerMode.AbsoluteMaxY == 0)) {\r
-        State->CurrentY = CurrentState.CurrentY;\r
+      if (!(MinY == 0 && MaxY == 0)) {\r
+        State->CurrentY = VirtualMinY + DivU64x64Remainder (\r
+                                          MultU64x64 (\r
+                                            CurrentState.CurrentY,\r
+                                            VirtualMaxY - VirtualMinY\r
+                                            ),\r
+                                          MaxY - MinY,\r
+                                          NULL\r
+                                          );\r
       }\r
       }\r
-      if (!(Private->AbsolutePointerMode.AbsoluteMinZ == 0 && Private->AbsolutePointerMode.AbsoluteMaxZ == 0)) {\r
-        State->CurrentZ = CurrentState.CurrentZ;\r
+      if (!(MinZ == 0 && MaxZ == 0)) {\r
+        State->CurrentZ = VirtualMinZ + DivU64x64Remainder (\r
+                                          MultU64x64 (\r
+                                            CurrentState.CurrentZ,\r
+                                            VirtualMaxZ - VirtualMinZ\r
+                                            ),\r
+                                          MaxZ - MinZ,\r
+                                          NULL\r
+                                          );\r
       }\r
 \r
     } else if (Status == EFI_DEVICE_ERROR) {\r
       }\r
 \r
     } else if (Status == EFI_DEVICE_ERROR) {\r
@@ -4473,7 +4636,7 @@ ConSplitterTextOutOutputString (
     Private->TextOutMode.CursorRow    = Private->TextOutList[0].TextOut->Mode->CursorRow;\r
   } else {\r
     //\r
     Private->TextOutMode.CursorRow    = Private->TextOutList[0].TextOut->Mode->CursorRow;\r
   } else {\r
     //\r
-    // When there is no real console devices in system, \r
+    // When there is no real console devices in system,\r
     // update cursor position for the virtual device in consplitter.\r
     //\r
     Private->TextOut.QueryMode (\r
     // update cursor position for the virtual device in consplitter.\r
     //\r
     Private->TextOut.QueryMode (\r
@@ -4481,28 +4644,28 @@ ConSplitterTextOutOutputString (
                        Private->TextOutMode.Mode,\r
                        &MaxColumn,\r
                        &MaxRow\r
                        Private->TextOutMode.Mode,\r
                        &MaxColumn,\r
                        &MaxRow\r
-                       );    \r
+                       );\r
     for (; *WString != CHAR_NULL; WString++) {\r
       switch (*WString) {\r
       case CHAR_BACKSPACE:\r
         if (Private->TextOutMode.CursorColumn == 0 && Private->TextOutMode.CursorRow > 0) {\r
           Private->TextOutMode.CursorRow--;\r
     for (; *WString != CHAR_NULL; WString++) {\r
       switch (*WString) {\r
       case CHAR_BACKSPACE:\r
         if (Private->TextOutMode.CursorColumn == 0 && Private->TextOutMode.CursorRow > 0) {\r
           Private->TextOutMode.CursorRow--;\r
-          Private->TextOutMode.CursorColumn = (INT32) (MaxColumn - 1);          \r
+          Private->TextOutMode.CursorColumn = (INT32) (MaxColumn - 1);\r
         } else if (Private->TextOutMode.CursorColumn > 0) {\r
           Private->TextOutMode.CursorColumn--;\r
         }\r
         break;\r
         } else if (Private->TextOutMode.CursorColumn > 0) {\r
           Private->TextOutMode.CursorColumn--;\r
         }\r
         break;\r
-      \r
+\r
       case CHAR_LINEFEED:\r
         if (Private->TextOutMode.CursorRow < (INT32) (MaxRow - 1)) {\r
           Private->TextOutMode.CursorRow++;\r
         }\r
         break;\r
       case CHAR_LINEFEED:\r
         if (Private->TextOutMode.CursorRow < (INT32) (MaxRow - 1)) {\r
           Private->TextOutMode.CursorRow++;\r
         }\r
         break;\r
-      \r
+\r
       case CHAR_CARRIAGE_RETURN:\r
         Private->TextOutMode.CursorColumn = 0;\r
         break;\r
       case CHAR_CARRIAGE_RETURN:\r
         Private->TextOutMode.CursorColumn = 0;\r
         break;\r
-      \r
+\r
       default:\r
         if (Private->TextOutMode.CursorColumn < (INT32) (MaxColumn - 1)) {\r
           Private->TextOutMode.CursorColumn++;\r
       default:\r
         if (Private->TextOutMode.CursorColumn < (INT32) (MaxColumn - 1)) {\r
           Private->TextOutMode.CursorColumn++;\r
@@ -4738,7 +4901,7 @@ ConSplitterTextOutSetAttribute (
   //\r
   // Check whether param Attribute is valid.\r
   //\r
   //\r
   // Check whether param Attribute is valid.\r
   //\r
-  if ( (Attribute > (UINTN)(((UINT32)-1)>>1)) ) {\r
+  if ((Attribute | 0x7F) != 0x7F) {\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
@@ -4937,4 +5100,3 @@ ConSplitterTextOutEnableCursor (
 \r
   return ReturnStatus;\r
 }\r
 \r
   return ReturnStatus;\r
 }\r
-\r