]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c
MdeModulePkg/ConSplitterDxe: Optimize the ConSplitterTextOutSetMode
[mirror_edk2.git] / MdeModulePkg / Universal / Console / ConSplitterDxe / ConSplitter.c
index c1edd5dccf4bed91629dbcef7a12dbd6bb9ce2a4..63c814ae1816755f3011fcb588037d3dddea1320 100644 (file)
   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 - 2019, 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
+// Identify if ConIn is connected in PcdConInConnectOnDemand enabled mode.\r
+// default not connect\r
+//\r
+BOOLEAN  mConInIsConnect = FALSE;\r
+\r
 //\r
 // Text In Splitter Private Data template\r
 //\r
@@ -60,6 +61,10 @@ GLOBAL_REMOVE_IF_UNREFERENCED TEXT_IN_SPLITTER_PRIVATE_DATA  mConIn = {
     (LIST_ENTRY *) NULL,\r
     (LIST_ENTRY *) NULL\r
   },\r
+  (EFI_KEY_DATA *) NULL,\r
+  0,\r
+  0,\r
+  FALSE,\r
 \r
   {\r
     ConSplitterSimplePointerReset,\r
@@ -175,7 +180,8 @@ GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mConOut = {
   0,\r
   (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,\r
   0,\r
-  (INT32 *) NULL\r
+  (INT32 *) NULL,\r
+  FALSE\r
 };\r
 \r
 //\r
@@ -230,7 +236,8 @@ GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mStdErr = {
   0,\r
   (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,\r
   0,\r
-  (INT32 *) NULL\r
+  (INT32 *) NULL,\r
+  FALSE\r
 };\r
 \r
 //\r
@@ -293,6 +300,122 @@ EFI_DRIVER_BINDING_PROTOCOL           gConSplitterAbsolutePointerDriverBinding =
   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
@@ -412,49 +535,12 @@ ConSplitterDriverEntry(
   //\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
@@ -477,7 +563,7 @@ ConSplitterDriverEntry(
                     &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
@@ -486,7 +572,7 @@ ConSplitterDriverEntry(
       gST->StdErr               = &mStdErr.TextOut;\r
     }\r
   }\r
-  \r
+\r
   //\r
   // Update the CRC32 in the EFI System Table header\r
   //\r
@@ -518,6 +604,7 @@ ConSplitterTextInConstructor (
   )\r
 {\r
   EFI_STATUS  Status;\r
+  UINTN       TextInExListCount;\r
 \r
   //\r
   // Allocate buffer for Simple Text Input device\r
@@ -543,6 +630,19 @@ ConSplitterTextInConstructor (
                   );\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
@@ -568,6 +668,8 @@ ConSplitterTextInConstructor (
 \r
   InitializeListHead (&ConInPrivate->NotifyList);\r
 \r
+  ToggleStateSyncInitialization (ConInPrivate);\r
+\r
   ConInPrivate->AbsolutePointer.Mode = &ConInPrivate->AbsolutePointerMode;\r
   //\r
   // Allocate buffer for Absolute Pointer device\r
@@ -614,6 +716,18 @@ ConSplitterTextInConstructor (
                   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
@@ -1297,7 +1411,7 @@ ConSplitterConOutDriverBindingStart (
 \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
@@ -1363,9 +1477,6 @@ ConSplitterStdErrDriverBindingStart (
   //\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
@@ -1869,6 +1980,17 @@ ConSplitterTextInExAddDevice (
         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
@@ -1908,6 +2030,11 @@ ConSplitterTextInExAddDevice (
   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
@@ -2128,6 +2255,8 @@ ConSplitterGrowMapTable (
   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
@@ -2165,14 +2294,26 @@ ConSplitterGrowMapTable (
     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
-      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
@@ -2520,7 +2661,7 @@ ConSplitterGetIntersectionBetweenConOutAndStrErr (
 \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
@@ -2780,7 +2921,7 @@ ConSplitterAddGraphicsOutputMode (
         }\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
@@ -2820,14 +2961,14 @@ Done:
   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
-  \r
+\r
   Mode = &Private->GraphicsOutputModeBuffer[CurrentIndex];\r
   if ((GraphicsOutput != NULL) &&\r
       (Mode->HorizontalResolution == CurrentGraphicsOutputMode->Info->HorizontalResolution) &&\r
@@ -2906,7 +3047,7 @@ ConsplitterSetConsoleOutMode (
   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
@@ -2951,8 +3092,10 @@ ConsplitterSetConsoleOutMode (
     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
@@ -2991,8 +3134,9 @@ ConSplitterTextOutAddDevice (
   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;\r
   EFI_STATUS                           DeviceStatus;\r
 \r
-  Status                = EFI_SUCCESS;\r
-  CurrentNumOfConsoles  = Private->CurrentNumberOfConsoles;\r
+  Status                      = EFI_SUCCESS;\r
+  CurrentNumOfConsoles        = Private->CurrentNumberOfConsoles;\r
+  Private->AddingConOutDevice = TRUE;\r
 \r
   //\r
   // If the Text Out List is full, enlarge it by calling ConSplitterGrowBuffer().\r
@@ -3043,13 +3187,13 @@ ConSplitterTextOutAddDevice (
   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
@@ -3068,7 +3212,7 @@ ConSplitterTextOutAddDevice (
 \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
@@ -3103,12 +3247,54 @@ ConSplitterTextOutAddDevice (
     }\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
   ConsplitterSetConsoleOutMode (Private);\r
 \r
+  Private->AddingConOutDevice = FALSE;\r
+\r
   return Status;\r
 }\r
 \r
@@ -3143,7 +3329,7 @@ ConSplitterTextOutDeleteDevice (
   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
@@ -3164,6 +3350,35 @@ ConSplitterTextOutDeleteDevice (
     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
@@ -3254,9 +3469,48 @@ ConSplitterTextInReset (
     }\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
+/**\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
@@ -3280,7 +3534,21 @@ ConSplitterTextInPrivateReadKeyStroke (
 {\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
@@ -3290,14 +3558,25 @@ ConSplitterTextInPrivateReadKeyStroke (
   // 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
-                                          &CurrentKey\r
+                                          &KeyData.Key\r
                                           );\r
     if (!EFI_ERROR (Status)) {\r
-      *Key = CurrentKey;\r
-      return Status;\r
+      //\r
+      // If it is not partial keystorke, return the key. Otherwise, continue\r
+      // to read key from THIS physical console input device.\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
+    } else {\r
+      //\r
+      // Continue to read key from NEXT physical console input device.\r
+      //\r
+      Index++;\r
     }\r
   }\r
 \r
@@ -3305,6 +3584,7 @@ ConSplitterTextInPrivateReadKeyStroke (
 }\r
 \r
 \r
+\r
 /**\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
@@ -3331,6 +3611,15 @@ ConSplitterTextInReadKeyStroke (
 \r
   Private->KeyEventSignalState = FALSE;\r
 \r
+  //\r
+  // Signal ConnectConIn event on first call in Lazy ConIn mode\r
+  //\r
+  if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {\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
   return ConSplitterTextInPrivateReadKeyStroke (Private, Key);\r
 }\r
 \r
@@ -3465,6 +3754,14 @@ ConSplitterTextInResetEx (
     }\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
@@ -3496,6 +3793,7 @@ ConSplitterTextInReadKeyStrokeEx (
   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
@@ -3507,25 +3805,91 @@ ConSplitterTextInReadKeyStrokeEx (
 \r
   Private->KeyEventSignalState = FALSE;\r
 \r
-  KeyData->Key.UnicodeChar  = 0;\r
-  KeyData->Key.ScanCode     = SCAN_NULL;\r
+  //\r
+  // Signal ConnectConIn event on first call in Lazy ConIn mode\r
+  //\r
+  if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {\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
   //\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
+  // 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
+  ZeroMem (&KeyState, sizeof (KeyState));\r
+\r
+  //\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
+    ZeroMem (&CurrentKeyData, sizeof (EFI_KEY_DATA));\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
-      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
+  // 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
@@ -3555,6 +3919,7 @@ ConSplitterTextInSetState (
   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
@@ -3562,6 +3927,12 @@ ConSplitterTextInSetState (
 \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
@@ -3569,13 +3940,22 @@ ConSplitterTextInSetState (
   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
+  // 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
@@ -3585,11 +3965,14 @@ ConSplitterTextInSetState (
   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
-                                   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
@@ -3679,7 +4062,7 @@ ConSplitterTextInRegisterKeyNotify (
     }\r
   }\r
 \r
-  InsertTailList (&mConIn.NotifyList, &NewNotify->NotifyEntry);\r
+  InsertTailList (&Private->NotifyList, &NewNotify->NotifyEntry);\r
 \r
   *NotifyHandle                = NewNotify;\r
 \r
@@ -4011,7 +4394,18 @@ ConSplitterAbsolutePointerGetState (
   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
@@ -4022,6 +4416,13 @@ ConSplitterAbsolutePointerGetState (
   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
@@ -4039,16 +4440,47 @@ ConSplitterAbsolutePointerGetState (
         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
-      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
-      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
-      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
@@ -4209,7 +4641,7 @@ ConSplitterTextOutOutputString (
     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
@@ -4217,28 +4649,28 @@ ConSplitterTextOutOutputString (
                        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
-          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
-      \r
+\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
-      \r
+\r
       default:\r
         if (Private->TextOutMode.CursorColumn < (INT32) (MaxColumn - 1)) {\r
           Private->TextOutMode.CursorColumn++;\r
@@ -4422,12 +4854,18 @@ ConSplitterTextOutSetMode (
   //\r
   TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber;\r
   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {\r
-    Status = Private->TextOutList[Index].TextOut->SetMode (\r
-                                                    Private->TextOutList[Index].TextOut,\r
-                                                    TextOutModeMap[Index]\r
-                                                    );\r
-    if (EFI_ERROR (Status)) {\r
-      ReturnStatus = Status;\r
+    //\r
+    // While adding a console out device do not set same mode again for the same device.\r
+    //\r
+    if ((!Private->AddingConOutDevice) ||\r
+        (TextOutModeMap[Index] != Private->TextOutList[Index].TextOut->Mode->Mode)) {\r
+      Status = Private->TextOutList[Index].TextOut->SetMode (\r
+                                                      Private->TextOutList[Index].TextOut,\r
+                                                      TextOutModeMap[Index]\r
+                                                      );\r
+      if (EFI_ERROR (Status)) {\r
+        ReturnStatus = Status;\r
+      }\r
     }\r
   }\r
 \r
@@ -4474,7 +4912,7 @@ ConSplitterTextOutSetAttribute (
   //\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
@@ -4673,4 +5111,3 @@ ConSplitterTextOutEnableCursor (
 \r
   return ReturnStatus;\r
 }\r
-\r