]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / Console / ConSplitterDxe / ConSplitter.c
index ead6d654d8f15a7ba8b492d7910d9d68e8b7ca5d..8b5e62e3a883cebfca105265fa5f9290a49583ed 100644 (file)
@@ -1,6 +1,7 @@
-/**@file\r
-  Console Splitter Driver. Any Handle that attatched\r
-  EFI_CONSOLE_IDENTIFIER_PROTOCOL can be bound by this driver.\r
+/** @file\r
+  Console Splitter Driver. Any Handle that attached console I/O protocols\r
+  (Console In device, Console Out device, Console Error device, Simple Pointer\r
+  protocol, Absolute Pointer protocol) can be bound by this driver.\r
 \r
   So far it works like any other driver by opening a SimpleTextIn and/or\r
   SimpleTextOut protocol with EFI_OPEN_PROTOCOL_BY_DRIVER attributes. The big\r
@@ -8,52 +9,68 @@
   handle, or construct a child handle like a standard device or bus driver.\r
   This driver produces three virtual handles as children, one for console input\r
   splitter, one for console output splitter and one for error output splitter.\r
-  EFI_CONSOLE_SPLIT_PROTOCOL will be attatched onto each virtual handle to\r
-  identify the splitter type.\r
+  These 3 virtual handles would be installed on gST.\r
 \r
-  Each virtual handle, that supports both the EFI_CONSOLE_SPLIT_PROTOCOL\r
-  and Console I/O protocol, will be produced in the driver entry point.\r
-  The virtual handle are added on driver entry and never removed.\r
-  Such design ensures sytem function well during none console device situation.\r
+  Each virtual handle, that supports the Console I/O protocol, will be produced\r
+  in the driver entry point. The virtual handle are added on driver entry and\r
+  never removed. Such design ensures system function well during none console\r
+  device situation.\r
 \r
-Copyright (c) 2006 - 2007 Intel Corporation. <BR>\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution.  The full text of the license may be found at\r
-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
-// Include common header file for this module.\r
+// Identify if ConIn is connected in PcdConInConnectOnDemand enabled mode.\r
+// default not connect\r
 //\r
-#include "CommonHeader.h"\r
-\r
-#include "ConSplitter.h"\r
+BOOLEAN  mConInIsConnect = FALSE;\r
 \r
 //\r
-// Global Variables\r
+// Text In Splitter Private Data template\r
 //\r
-STATIC TEXT_IN_SPLITTER_PRIVATE_DATA  mConIn = {\r
+GLOBAL_REMOVE_IF_UNREFERENCED TEXT_IN_SPLITTER_PRIVATE_DATA  mConIn = {\r
   TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE,\r
-  (EFI_HANDLE) NULL,\r
+  (EFI_HANDLE)NULL,\r
+\r
   {\r
     ConSplitterTextInReset,\r
     ConSplitterTextInReadKeyStroke,\r
-    (EFI_EVENT) NULL\r
+    (EFI_EVENT)NULL\r
+  },\r
+  0,\r
+  (EFI_SIMPLE_TEXT_INPUT_PROTOCOL **)NULL,\r
+  0,\r
+\r
+  {\r
+    ConSplitterTextInResetEx,\r
+    ConSplitterTextInReadKeyStrokeEx,\r
+    (EFI_EVENT)NULL,\r
+    ConSplitterTextInSetState,\r
+    ConSplitterTextInRegisterKeyNotify,\r
+    ConSplitterTextInUnregisterKeyNotify\r
+  },\r
+  0,\r
+  (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL **)NULL,\r
+  0,\r
+  {\r
+    (LIST_ENTRY *)NULL,\r
+    (LIST_ENTRY *)NULL\r
   },\r
+  (EFI_KEY_DATA *)NULL,\r
   0,\r
-  (EFI_SIMPLE_TEXT_INPUT_PROTOCOL **) NULL,\r
   0,\r
+  FALSE,\r
 \r
   {\r
     ConSplitterSimplePointerReset,\r
     ConSplitterSimplePointerGetState,\r
-    (EFI_EVENT) NULL,\r
-    (EFI_SIMPLE_POINTER_MODE *) NULL\r
+    (EFI_EVENT)NULL,\r
+    (EFI_SIMPLE_POINTER_MODE *)NULL\r
   },\r
   {\r
     0x10000,\r
@@ -63,32 +80,58 @@ STATIC TEXT_IN_SPLITTER_PRIVATE_DATA  mConIn = {
     TRUE\r
   },\r
   0,\r
-  (EFI_SIMPLE_POINTER_PROTOCOL **) NULL,\r
+  (EFI_SIMPLE_POINTER_PROTOCOL **)NULL,\r
   0,\r
 \r
-  FALSE,\r
   {\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\r
+    ConSplitterAbsolutePointerReset,\r
+    ConSplitterAbsolutePointerGetState,\r
+    (EFI_EVENT)NULL,\r
+    (EFI_ABSOLUTE_POINTER_MODE *)NULL\r
   },\r
-  0,\r
   {\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\r
+    0,       // AbsoluteMinX\r
+    0,       // AbsoluteMinY\r
+    0,       // AbsoluteMinZ\r
+    0x10000, // AbsoluteMaxX\r
+    0x10000, // AbsoluteMaxY\r
+    0x10000, // AbsoluteMaxZ\r
+    0        // Attributes\r
   },\r
-  (EFI_EVENT) NULL,\r
+  0,\r
+  (EFI_ABSOLUTE_POINTER_PROTOCOL **)NULL,\r
+  0,\r
+  FALSE,\r
 \r
   FALSE,\r
   FALSE\r
 };\r
 \r
-STATIC TEXT_OUT_SPLITTER_PRIVATE_DATA mConOut = {\r
+//\r
+// Uga Draw Protocol Private Data template\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UGA_DRAW_PROTOCOL  mUgaDrawProtocolTemplate = {\r
+  ConSplitterUgaDrawGetMode,\r
+  ConSplitterUgaDrawSetMode,\r
+  ConSplitterUgaDrawBlt\r
+};\r
+\r
+//\r
+// Graphics Output Protocol Private Data template\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GRAPHICS_OUTPUT_PROTOCOL  mGraphicsOutputProtocolTemplate = {\r
+  ConSplitterGraphicsOutputQueryMode,\r
+  ConSplitterGraphicsOutputSetMode,\r
+  ConSplitterGraphicsOutputBlt,\r
+  NULL\r
+};\r
+\r
+//\r
+// Text Out Splitter Private Data template\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA  mConOut = {\r
   TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE,\r
-  (EFI_HANDLE) NULL,\r
+  (EFI_HANDLE)NULL,\r
   {\r
     ConSplitterTextOutReset,\r
     ConSplitterTextOutOutputString,\r
@@ -99,7 +142,7 @@ STATIC TEXT_OUT_SPLITTER_PRIVATE_DATA mConOut = {
     ConSplitterTextOutClearScreen,\r
     ConSplitterTextOutSetCursorPosition,\r
     ConSplitterTextOutEnableCursor,\r
-    (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL\r
+    (EFI_SIMPLE_TEXT_OUTPUT_MODE *)NULL\r
   },\r
   {\r
     1,\r
@@ -109,39 +152,42 @@ STATIC TEXT_OUT_SPLITTER_PRIVATE_DATA mConOut = {
     0,\r
     FALSE,\r
   },\r
+\r
   {\r
-    ConSpliterGraphicsOutputQueryMode,\r
-    ConSpliterGraphicsOutputSetMode,\r
-    ConSpliterGraphicsOutputBlt,\r
+    NULL,\r
+    NULL,\r
     NULL\r
   },\r
-  (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) NULL,\r
-  (TEXT_OUT_GOP_MODE *) NULL,\r
   0,\r
-  TRUE,\r
+  0,\r
+  0,\r
+  0,\r
+\r
   {\r
-    ConSpliterConsoleControlGetMode,\r
-    ConSpliterConsoleControlSetMode,\r
-    ConSpliterConsoleControlLockStdIn\r
+    NULL,\r
+    NULL,\r
+    NULL,\r
+    NULL\r
   },\r
-\r
-  0,\r
-  (TEXT_OUT_AND_GOP_DATA *) NULL,\r
+  (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *)NULL,\r
   0,\r
-  (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,\r
   0,\r
-  (INT32 *) NULL,\r
 \r
-  EfiConsoleControlScreenText,\r
   0,\r
+  (TEXT_OUT_AND_GOP_DATA *)NULL,\r
   0,\r
-  (CHAR16 *) NULL,\r
-  (INT32 *) NULL\r
+  (TEXT_OUT_SPLITTER_QUERY_DATA *)NULL,\r
+  0,\r
+  (INT32 *)NULL,\r
+  FALSE\r
 };\r
 \r
-STATIC TEXT_OUT_SPLITTER_PRIVATE_DATA mStdErr = {\r
+//\r
+// Standard Error Text Out Splitter Data Template\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA  mStdErr = {\r
   TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE,\r
-  (EFI_HANDLE) NULL,\r
+  (EFI_HANDLE)NULL,\r
   {\r
     ConSplitterTextOutReset,\r
     ConSplitterTextOutOutputString,\r
@@ -152,7 +198,7 @@ STATIC TEXT_OUT_SPLITTER_PRIVATE_DATA mStdErr = {
     ConSplitterTextOutClearScreen,\r
     ConSplitterTextOutSetCursorPosition,\r
     ConSplitterTextOutEnableCursor,\r
-    (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL\r
+    (EFI_SIMPLE_TEXT_OUTPUT_MODE *)NULL\r
   },\r
   {\r
     1,\r
@@ -162,37 +208,40 @@ STATIC TEXT_OUT_SPLITTER_PRIVATE_DATA mStdErr = {
     0,\r
     FALSE,\r
   },\r
+\r
   {\r
-    ConSpliterGraphicsOutputQueryMode,\r
-    ConSpliterGraphicsOutputSetMode,\r
-    ConSpliterGraphicsOutputBlt,\r
+    NULL,\r
+    NULL,\r
     NULL\r
   },\r
-  (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) NULL,\r
-  (TEXT_OUT_GOP_MODE *) NULL,\r
   0,\r
-  TRUE,\r
+  0,\r
+  0,\r
+  0,\r
+\r
   {\r
-    ConSpliterConsoleControlGetMode,\r
-    ConSpliterConsoleControlSetMode,\r
-    ConSpliterConsoleControlLockStdIn\r
+    NULL,\r
+    NULL,\r
+    NULL,\r
+    NULL\r
   },\r
-\r
-  0,\r
-  (TEXT_OUT_AND_GOP_DATA *) NULL,\r
+  (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *)NULL,\r
   0,\r
-  (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,\r
   0,\r
-  (INT32 *) NULL,\r
 \r
-  EfiConsoleControlScreenText,\r
   0,\r
+  (TEXT_OUT_AND_GOP_DATA *)NULL,\r
   0,\r
-  (CHAR16 *) NULL,\r
-  (INT32 *) NULL\r
+  (TEXT_OUT_SPLITTER_QUERY_DATA *)NULL,\r
+  0,\r
+  (INT32 *)NULL,\r
+  FALSE\r
 };\r
 \r
-EFI_DRIVER_BINDING_PROTOCOL           gConSplitterConInDriverBinding = {\r
+//\r
+// Driver binding instance for Console Input Device\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL  gConSplitterConInDriverBinding = {\r
   ConSplitterConInDriverBindingSupported,\r
   ConSplitterConInDriverBindingStart,\r
   ConSplitterConInDriverBindingStop,\r
@@ -201,16 +250,10 @@ EFI_DRIVER_BINDING_PROTOCOL           gConSplitterConInDriverBinding = {
   NULL\r
 };\r
 \r
-EFI_DRIVER_BINDING_PROTOCOL           gConSplitterSimplePointerDriverBinding = {\r
-  ConSplitterSimplePointerDriverBindingSupported,\r
-  ConSplitterSimplePointerDriverBindingStart,\r
-  ConSplitterSimplePointerDriverBindingStop,\r
-  0xa,\r
-  NULL,\r
-  NULL\r
-};\r
-\r
-EFI_DRIVER_BINDING_PROTOCOL           gConSplitterConOutDriverBinding = {\r
+//\r
+// Driver binding instance for Console Out device\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL  gConSplitterConOutDriverBinding = {\r
   ConSplitterConOutDriverBindingSupported,\r
   ConSplitterConOutDriverBindingStart,\r
   ConSplitterConOutDriverBindingStop,\r
@@ -219,7 +262,10 @@ EFI_DRIVER_BINDING_PROTOCOL           gConSplitterConOutDriverBinding = {
   NULL\r
 };\r
 \r
-EFI_DRIVER_BINDING_PROTOCOL           gConSplitterStdErrDriverBinding = {\r
+//\r
+// Driver binding instance for Standard Error device\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL  gConSplitterStdErrDriverBinding = {\r
   ConSplitterStdErrDriverBindingSupported,\r
   ConSplitterStdErrDriverBindingStart,\r
   ConSplitterStdErrDriverBindingStop,\r
@@ -228,124 +274,239 @@ EFI_DRIVER_BINDING_PROTOCOL           gConSplitterStdErrDriverBinding = {
   NULL\r
 };\r
 \r
+//\r
+// Driver binding instance for Simple Pointer protocol\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL  gConSplitterSimplePointerDriverBinding = {\r
+  ConSplitterSimplePointerDriverBindingSupported,\r
+  ConSplitterSimplePointerDriverBindingStart,\r
+  ConSplitterSimplePointerDriverBindingStop,\r
+  0xa,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+//\r
+// Driver binding instance for Absolute Pointer protocol\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL  gConSplitterAbsolutePointerDriverBinding = {\r
+  ConSplitterAbsolutePointerDriverBindingSupported,\r
+  ConSplitterAbsolutePointerDriverBindingStart,\r
+  ConSplitterAbsolutePointerDriverBindingStop,\r
+  0xa,\r
+  NULL,\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
+    //\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
+\r
+    mConIn.PhysicalKeyToggleState = KeyData->KeyState.KeyToggleState;\r
+    DEBUG ((DEBUG_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
+  Re-initialization 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 user Entry Point for module ConSplitter. The user code starts with this function.\r
+  The Entry Point for module ConSplitter. The user code starts with this function.\r
 \r
-  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
+  Installs driver module protocols and. Creates virtual device handles for ConIn,\r
+  ConOut, and StdErr. Installs Simple Text In protocol, Simple Text In Ex protocol,\r
+  Simple Pointer protocol, Absolute Pointer protocol on those virtual handlers.\r
+  Installs Graphics Output protocol and/or UGA Draw protocol if needed.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
   @param[in] SystemTable    A pointer to the EFI System Table.\r
-  \r
+\r
   @retval EFI_SUCCESS       The entry point is executed successfully.\r
   @retval other             Some error occurs when executing this entry point.\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-InitializeConSplitter(\r
-  IN EFI_HANDLE           ImageHandle,\r
-  IN EFI_SYSTEM_TABLE     *SystemTable\r
+ConSplitterDriverEntry (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
   )\r
 {\r
-  EFI_STATUS              Status;\r
+  EFI_STATUS  Status;\r
 \r
   //\r
   // Install driver model protocol(s).\r
   //\r
-  Status = EfiLibInstallAllDriverProtocols (\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
              ImageHandle,\r
              SystemTable,\r
              &gConSplitterConInDriverBinding,\r
              ImageHandle,\r
              &gConSplitterConInComponentName,\r
-             NULL,\r
-             NULL\r
+             &gConSplitterConInComponentName2\r
              );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  Status = EfiLibInstallAllDriverProtocols (\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
              ImageHandle,\r
              SystemTable,\r
              &gConSplitterSimplePointerDriverBinding,\r
              NULL,\r
              &gConSplitterSimplePointerComponentName,\r
+             &gConSplitterSimplePointerComponentName2\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gConSplitterAbsolutePointerDriverBinding,\r
              NULL,\r
-             NULL\r
+             &gConSplitterAbsolutePointerComponentName,\r
+             &gConSplitterAbsolutePointerComponentName2\r
              );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  Status = EfiLibInstallAllDriverProtocols (\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
              ImageHandle,\r
              SystemTable,\r
              &gConSplitterConOutDriverBinding,\r
              NULL,\r
              &gConSplitterConOutComponentName,\r
-             NULL,\r
-             NULL\r
+             &gConSplitterConOutComponentName2\r
              );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  Status = EfiLibInstallAllDriverProtocols (\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
              ImageHandle,\r
              SystemTable,\r
              &gConSplitterStdErrDriverBinding,\r
              NULL,\r
              &gConSplitterStdErrComponentName,\r
-             NULL,\r
-             NULL\r
+             &gConSplitterStdErrComponentName2\r
              );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-\r
   //\r
-  // Call the original Entry Point\r
+  // Either Graphics Output protocol or UGA Draw protocol must be supported.\r
   //\r
-  Status = ConSplitterDriverEntry (ImageHandle, SystemTable);\r
-\r
-  return Status;\r
-}\r
-\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-ConSplitterDriverEntry (\r
-  IN EFI_HANDLE                       ImageHandle,\r
-  IN EFI_SYSTEM_TABLE                 *SystemTable\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-  Intialize a virtual console device to act as an agrigator of physical console\r
-  devices.\r
-\r
-Arguments:\r
-  ImageHandle - (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)\r
-  SystemTable - (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)\r
-Returns:\r
-  EFI_SUCCESS\r
-\r
---*/\r
-{\r
-  EFI_STATUS  Status;\r
+  ASSERT (\r
+    FeaturePcdGet (PcdConOutGopSupport) ||\r
+    FeaturePcdGet (PcdConOutUgaSupport)\r
+    );\r
 \r
   //\r
-  // The driver creates virtual handles for ConIn, ConOut, and StdErr.\r
+  // The driver creates virtual handles for ConIn, ConOut, StdErr.\r
   // The virtual handles will always exist even if no console exist in the\r
   // system. This is need to support hotplug devices like USB.\r
   //\r
   //\r
-  // Create virtual device handle for StdErr Splitter\r
-  //\r
-  Status = ConSplitterTextOutConstructor (&mStdErr);\r
-  if (!EFI_ERROR (Status)) {\r
-    Status = gBS->InstallMultipleProtocolInterfaces (\r
-                    &mStdErr.VirtualHandle,\r
-                    &gEfiSimpleTextOutProtocolGuid,\r
-                    &mStdErr.TextOut,\r
-                    &gEfiPrimaryStandardErrorDeviceGuid,\r
-                    NULL,\r
-                    NULL\r
-                    );\r
-  }\r
-  //\r
   // Create virtual device handle for ConIn Splitter\r
   //\r
   Status = ConSplitterTextInConstructor (&mConIn);\r
@@ -354,107 +515,113 @@ Returns:
                     &mConIn.VirtualHandle,\r
                     &gEfiSimpleTextInProtocolGuid,\r
                     &mConIn.TextIn,\r
+                    &gEfiSimpleTextInputExProtocolGuid,\r
+                    &mConIn.TextInEx,\r
                     &gEfiSimplePointerProtocolGuid,\r
                     &mConIn.SimplePointer,\r
-                    &gEfiPrimaryConsoleInDeviceGuid,\r
-                    NULL,\r
+                    &gEfiAbsolutePointerProtocolGuid,\r
+                    &mConIn.AbsolutePointer,\r
                     NULL\r
                     );\r
     if (!EFI_ERROR (Status)) {\r
       //\r
       // Update the EFI System Table with new virtual console\r
+      // and update the pointer to Simple Text Input protocol.\r
       //\r
-      gST->ConsoleInHandle  = mConIn.VirtualHandle;\r
-      gST->ConIn            = &mConIn.TextIn;\r
+      gST->ConsoleInHandle = mConIn.VirtualHandle;\r
+      gST->ConIn           = &mConIn.TextIn;\r
     }\r
   }\r
+\r
   //\r
   // Create virtual device handle for ConOut Splitter\r
   //\r
   Status = ConSplitterTextOutConstructor (&mConOut);\r
   if (!EFI_ERROR (Status)) {\r
-    //\r
-    // In UEFI mode, Graphics Output Protocol is installed on virtual handle.\r
-    //\r
     Status = gBS->InstallMultipleProtocolInterfaces (\r
                     &mConOut.VirtualHandle,\r
                     &gEfiSimpleTextOutProtocolGuid,\r
                     &mConOut.TextOut,\r
-                    &gEfiGraphicsOutputProtocolGuid,\r
-                    &mConOut.GraphicsOutput,\r
-                    &gEfiConsoleControlProtocolGuid,\r
-                    &mConOut.ConsoleControl,\r
-                    &gEfiPrimaryConsoleOutDeviceGuid,\r
-                    NULL,\r
                     NULL\r
                     );\r
-\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
       gST->ConsoleOutHandle = mConOut.VirtualHandle;\r
       gST->ConOut           = &mConOut.TextOut;\r
     }\r
+  }\r
 \r
+  //\r
+  // Create virtual device handle for StdErr Splitter\r
+  //\r
+  Status = ConSplitterTextOutConstructor (&mStdErr);\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &mStdErr.VirtualHandle,\r
+                    &gEfiSimpleTextOutProtocolGuid,\r
+                    &mStdErr.TextOut,\r
+                    NULL\r
+                    );\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
+      gST->StandardErrorHandle = mStdErr.VirtualHandle;\r
+      gST->StdErr              = &mStdErr.TextOut;\r
+    }\r
   }\r
+\r
   //\r
   // Update the CRC32 in the EFI System Table header\r
   //\r
   gST->Hdr.CRC32 = 0;\r
   gBS->CalculateCrc32 (\r
-        (UINT8 *) &gST->Hdr,\r
-        gST->Hdr.HeaderSize,\r
-        &gST->Hdr.CRC32\r
-        );\r
+         (UINT8 *)&gST->Hdr,\r
+         gST->Hdr.HeaderSize,\r
+         &gST->Hdr.CRC32\r
+         );\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
-EFI_STATUS\r
-ConSplitterTextInConstructor (\r
-  TEXT_IN_SPLITTER_PRIVATE_DATA       *ConInPrivate\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Construct the ConSplitter.\r
-\r
-Arguments:\r
+/**\r
+  Construct console input devices' private data.\r
 \r
-  ConInPrivate    - A pointer to the TEXT_IN_SPLITTER_PRIVATE_DATA structure.\r
+  @param  ConInPrivate             A pointer to the TEXT_IN_SPLITTER_PRIVATE_DATA\r
+                                   structure.\r
 \r
-Returns:\r
-  EFI_OUT_OF_RESOURCES - Out of resources.\r
+  @retval EFI_OUT_OF_RESOURCES     Out of resources.\r
+  @retval EFI_SUCCESS              Text Input Device's private data has been constructed.\r
+  @retval other                    Failed to construct private data.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ConSplitterTextInConstructor (\r
+  TEXT_IN_SPLITTER_PRIVATE_DATA  *ConInPrivate\r
+  )\r
 {\r
   EFI_STATUS  Status;\r
+  UINTN       TextInExListCount;\r
 \r
   //\r
-  // Initilize console input splitter's private data.\r
+  // Allocate buffer for Simple Text Input device\r
   //\r
   Status = ConSplitterGrowBuffer (\r
-            sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *),\r
-            &ConInPrivate->TextInListCount,\r
-            (VOID **) &ConInPrivate->TextInList\r
-            );\r
+             sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *),\r
+             &ConInPrivate->TextInListCount,\r
+             (VOID **)&ConInPrivate->TextInList\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
+\r
   //\r
-  // Create Event to support locking StdIn Device\r
+  // Create Event to wait for a key\r
   //\r
-  Status = gBS->CreateEvent (\r
-                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
-                  TPL_CALLBACK,\r
-                  ConSpliterConsoleControlLockStdInEvent,\r
-                  NULL,\r
-                  &ConInPrivate->LockEvent\r
-                  );\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_WAIT,\r
                   TPL_NOTIFY,\r
@@ -464,126 +631,253 @@ Returns:
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  ConInPrivate->SimplePointer.Mode = &ConInPrivate->SimplePointerMode;\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
   Status = ConSplitterGrowBuffer (\r
-            sizeof (EFI_SIMPLE_POINTER_PROTOCOL *),\r
-            &ConInPrivate->PointerListCount,\r
-            (VOID **) &ConInPrivate->PointerList\r
-            );\r
+             sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *),\r
+             &ConInPrivate->TextInExListCount,\r
+             (VOID **)&ConInPrivate->TextInExList\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
+  //\r
+  // Create Event to wait for a key Ex\r
+  //\r
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_WAIT,\r
                   TPL_NOTIFY,\r
-                  ConSplitterSimplePointerWaitForInput,\r
+                  ConSplitterTextInWaitForKey,\r
                   ConInPrivate,\r
-                  &ConInPrivate->SimplePointer.WaitForInput\r
+                  &ConInPrivate->TextInEx.WaitForKeyEx\r
                   );\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
-  return Status;\r
-}\r
+  InitializeListHead (&ConInPrivate->NotifyList);\r
 \r
-EFI_STATUS\r
-ConSplitterTextOutConstructor (\r
-  TEXT_OUT_SPLITTER_PRIVATE_DATA      *ConOutPrivate\r
-  )\r
-{\r
-  EFI_STATUS  Status;\r
+  ToggleStateSyncInitialization (ConInPrivate);\r
 \r
+  ConInPrivate->AbsolutePointer.Mode = &ConInPrivate->AbsolutePointerMode;\r
   //\r
-  // Initilize console output splitter's private data.\r
+  // Allocate buffer for Absolute Pointer device\r
   //\r
-  ConOutPrivate->TextOut.Mode = &ConOutPrivate->TextOutMode;\r
-\r
   Status = ConSplitterGrowBuffer (\r
-            sizeof (TEXT_OUT_AND_GOP_DATA),\r
-            &ConOutPrivate->TextOutListCount,\r
-            (VOID **) &ConOutPrivate->TextOutList\r
-            );\r
+             sizeof (EFI_ABSOLUTE_POINTER_PROTOCOL *),\r
+             &ConInPrivate->AbsolutePointerListCount,\r
+             (VOID **)&ConInPrivate->AbsolutePointerList\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  Status = ConSplitterGrowBuffer (\r
-            sizeof (TEXT_OUT_SPLITTER_QUERY_DATA),\r
-            &ConOutPrivate->TextOutQueryDataCount,\r
-            (VOID **) &ConOutPrivate->TextOutQueryData\r
-            );\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
   //\r
-  // Setup the DevNullTextOut console to 80 x 25\r
+  // Create Event to wait for device input for Absolute pointer device\r
   //\r
-  ConOutPrivate->TextOutQueryData[0].Columns  = 80;\r
-  ConOutPrivate->TextOutQueryData[0].Rows     = 25;\r
-  DevNullTextOutSetMode (ConOutPrivate, 0);\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_WAIT,\r
+                  TPL_NOTIFY,\r
+                  ConSplitterAbsolutePointerWaitForInput,\r
+                  ConInPrivate,\r
+                  &ConInPrivate->AbsolutePointer.WaitForInput\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
+  ConInPrivate->SimplePointer.Mode = &ConInPrivate->SimplePointerMode;\r
   //\r
-  // Setup resource for mode information in Graphics Output Protocol interface\r
+  // Allocate buffer for Simple Pointer device\r
   //\r
-  if ((ConOutPrivate->GraphicsOutput.Mode = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE))) == NULL) {\r
+  Status = ConSplitterGrowBuffer (\r
+             sizeof (EFI_SIMPLE_POINTER_PROTOCOL *),\r
+             &ConInPrivate->PointerListCount,\r
+             (VOID **)&ConInPrivate->PointerList\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
-  if ((ConOutPrivate->GraphicsOutput.Mode->Info = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION))) == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+\r
+  //\r
+  // Create Event to wait for device input for Simple pointer device\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_WAIT,\r
+                  TPL_NOTIFY,\r
+                  ConSplitterSimplePointerWaitForInput,\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
+/**\r
+  Construct console output devices' private data.\r
+\r
+  @param  ConOutPrivate            A pointer to the TEXT_OUT_SPLITTER_PRIVATE_DATA\r
+                                   structure.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES     Out of resources.\r
+  @retval EFI_SUCCESS              Text Input Devcie's private data has been constructed.\r
+\r
+**/\r
+EFI_STATUS\r
+ConSplitterTextOutConstructor (\r
+  TEXT_OUT_SPLITTER_PRIVATE_DATA  *ConOutPrivate\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;\r
+\r
+  //\r
+  // Copy protocols template\r
+  //\r
+  if (FeaturePcdGet (PcdConOutUgaSupport)) {\r
+    CopyMem (&ConOutPrivate->UgaDraw, &mUgaDrawProtocolTemplate, sizeof (EFI_UGA_DRAW_PROTOCOL));\r
+  }\r
+\r
+  if (FeaturePcdGet (PcdConOutGopSupport)) {\r
+    CopyMem (&ConOutPrivate->GraphicsOutput, &mGraphicsOutputProtocolTemplate, sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL));\r
   }\r
+\r
   //\r
-  // Setup the DevNullGraphicsOutput to 800 x 600 x 32 bits per pixel\r
+  // Initialize console output splitter's private data.\r
   //\r
-  if ((ConOutPrivate->GraphicsOutputModeBuffer = AllocateZeroPool (sizeof (TEXT_OUT_GOP_MODE))) == NULL) {\r
+  ConOutPrivate->TextOut.Mode = &ConOutPrivate->TextOutMode;\r
+\r
+  //\r
+  // When new console device is added, the new mode will be set later,\r
+  // so put current mode back to init state.\r
+  //\r
+  ConOutPrivate->TextOutMode.Mode = 0xFF;\r
+  //\r
+  // Allocate buffer for Console Out device\r
+  //\r
+  Status = ConSplitterGrowBuffer (\r
+             sizeof (TEXT_OUT_AND_GOP_DATA),\r
+             &ConOutPrivate->TextOutListCount,\r
+             (VOID **)&ConOutPrivate->TextOutList\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
-  ConOutPrivate->GraphicsOutputModeBuffer[0].HorizontalResolution = 800;\r
-  ConOutPrivate->GraphicsOutputModeBuffer[0].VerticalResolution = 600;\r
 \r
   //\r
-  // Initialize the following items, theset items remain unchanged in GraphicsOutput->SetMode()\r
-  //  GraphicsOutputMode->Info->Version, GraphicsOutputMode->Info->PixelFormat\r
-  //  GraphicsOutputMode->SizeOfInfo, GraphicsOutputMode->FrameBufferBase, GraphicsOutputMode->FrameBufferSize\r
+  // Allocate buffer for Text Out query data\r
   //\r
-  ConOutPrivate->GraphicsOutput.Mode->Info->Version = 0;\r
-  ConOutPrivate->GraphicsOutput.Mode->Info->PixelFormat = PixelBltOnly;\r
-  ConOutPrivate->GraphicsOutput.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
-  ConOutPrivate->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) NULL;\r
-  ConOutPrivate->GraphicsOutput.Mode->FrameBufferSize = 0;\r
+  Status = ConSplitterGrowBuffer (\r
+             sizeof (TEXT_OUT_SPLITTER_QUERY_DATA),\r
+             &ConOutPrivate->TextOutQueryDataCount,\r
+             (VOID **)&ConOutPrivate->TextOutQueryData\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
 \r
-  ConOutPrivate->GraphicsOutput.Mode->MaxMode = 1;\r
   //\r
-  // Initial current mode to unknow state, and then set to mode 0\r
+  // Setup the default console to 80 x 25 and mode to 0\r
   //\r
-  ConOutPrivate->GraphicsOutput.Mode->Mode = 0xffff;\r
-  ConOutPrivate->GraphicsOutput.SetMode (&ConOutPrivate->GraphicsOutput, 0);\r
+  ConOutPrivate->TextOutQueryData[0].Columns = 80;\r
+  ConOutPrivate->TextOutQueryData[0].Rows    = 25;\r
+  TextOutSetMode (ConOutPrivate, 0);\r
 \r
-  return Status;\r
-}\r
+  if (FeaturePcdGet (PcdConOutUgaSupport)) {\r
+    //\r
+    // Setup the UgaDraw to 800 x 600 x 32 bits per pixel, 60Hz.\r
+    //\r
+    ConSplitterUgaDrawSetMode (&ConOutPrivate->UgaDraw, 800, 600, 32, 60);\r
+  }\r
 \r
-STATIC\r
-EFI_STATUS\r
-ConSplitterSupported (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
-  IN  EFI_HANDLE                      ControllerHandle,\r
-  IN  EFI_GUID                        *Guid\r
-  )\r
-/*++\r
+  if (FeaturePcdGet (PcdConOutGopSupport)) {\r
+    //\r
+    // Setup resource for mode information in Graphics Output Protocol interface\r
+    //\r
+    if ((ConOutPrivate->GraphicsOutput.Mode = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE))) == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    if ((ConOutPrivate->GraphicsOutput.Mode->Info = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION))) == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    //\r
+    // Setup the DevNullGraphicsOutput to 800 x 600 x 32 bits per pixel\r
+    // DevNull will be updated to user-defined mode after driver has started.\r
+    //\r
+    if ((ConOutPrivate->GraphicsOutputModeBuffer = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION))) == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    Info                       = &ConOutPrivate->GraphicsOutputModeBuffer[0];\r
+    Info->Version              = 0;\r
+    Info->HorizontalResolution = 800;\r
+    Info->VerticalResolution   = 600;\r
+    Info->PixelFormat          = PixelBltOnly;\r
+    Info->PixelsPerScanLine    = 800;\r
+    CopyMem (ConOutPrivate->GraphicsOutput.Mode->Info, Info, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));\r
+    ConOutPrivate->GraphicsOutput.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
+\r
+    //\r
+    // Initialize the following items, theset items remain unchanged in GraphicsOutput->SetMode()\r
+    // GraphicsOutputMode->FrameBufferBase, GraphicsOutputMode->FrameBufferSize\r
+    //\r
+    ConOutPrivate->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;\r
+    ConOutPrivate->GraphicsOutput.Mode->FrameBufferSize = 0;\r
+\r
+    ConOutPrivate->GraphicsOutput.Mode->MaxMode = 1;\r
+    //\r
+    // Initial current mode to unknown state, and then set to mode 0\r
+    //\r
+    ConOutPrivate->GraphicsOutput.Mode->Mode = 0xffff;\r
+    ConOutPrivate->GraphicsOutput.SetMode (&ConOutPrivate->GraphicsOutput, 0);\r
+  }\r
 \r
-Routine Description:\r
-  Generic Supported Check\r
+  return EFI_SUCCESS;\r
+}\r
 \r
-Arguments:\r
-  This              - Pointer to protocol.\r
-  ControllerHandle  - Controller Handle.\r
-  Guid              - Guid.\r
+/**\r
+  Test to see if the specified protocol could be supported on the specified device.\r
 \r
-Returns:\r
+  @param  This                Driver Binding protocol pointer.\r
+  @param  ControllerHandle    Handle of device to test.\r
+  @param  Guid                The specified protocol.\r
 \r
-  EFI_UNSUPPORTED - unsupported.\r
-  EFI_SUCCESS     - operation is OK.\r
+  @retval EFI_SUCCESS         The specified protocol is supported on this device.\r
+  @retval EFI_UNSUPPORTED     The specified protocol attempts to be installed on virtual handle.\r
+  @retval other               Failed to open specified protocol on this device.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ConSplitterSupported (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_GUID                     *Guid\r
+  )\r
 {\r
   EFI_STATUS  Status;\r
   VOID        *Instance;\r
@@ -591,19 +885,16 @@ Returns:
   //\r
   // Make sure the Console Splitter does not attempt to attach to itself\r
   //\r
-  if (ControllerHandle == mConIn.VirtualHandle) {\r
-    return EFI_UNSUPPORTED;\r
-  }\r
-\r
-  if (ControllerHandle == mConOut.VirtualHandle) {\r
+  if ((ControllerHandle == mConIn.VirtualHandle) ||\r
+      (ControllerHandle == mConOut.VirtualHandle) ||\r
+      (ControllerHandle == mStdErr.VirtualHandle)\r
+      )\r
+  {\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-  if (ControllerHandle == mStdErr.VirtualHandle) {\r
-    return EFI_UNSUPPORTED;\r
-  }\r
   //\r
-  // Check to see whether the handle has the ConsoleInDevice GUID on it\r
+  // Check to see whether the specific protocol could be opened BY_DRIVER\r
   //\r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
@@ -619,165 +910,182 @@ Returns:
   }\r
 \r
   gBS->CloseProtocol (\r
-        ControllerHandle,\r
-        Guid,\r
-        This->DriverBindingHandle,\r
-        ControllerHandle\r
-        );\r
+         ControllerHandle,\r
+         Guid,\r
+         This->DriverBindingHandle,\r
+         ControllerHandle\r
+         );\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Test to see if Console In Device could be supported on the Controller.\r
+\r
+  @param  This                Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle    Handle of device to test.\r
+  @param  RemainingDevicePath Optional parameter use to pick a specific child\r
+                              device to start.\r
+\r
+  @retval EFI_SUCCESS         This driver supports this device.\r
+  @retval other               This driver does not support this device.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterConInDriverBindingSupported (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
-  IN  EFI_HANDLE                      ControllerHandle,\r
-  IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-  Console In Supported Check\r
-\r
-Arguments:\r
-  This              - Pointer to protocol.\r
-  ControllerHandle  - Controller handle.\r
-  RemainingDevicePath  - Remaining device path.\r
-\r
-Returns:\r
-\r
-  EFI_STATUS\r
-\r
---*/\r
 {\r
   return ConSplitterSupported (\r
-          This,\r
-          ControllerHandle,\r
-          &gEfiConsoleInDeviceGuid\r
-          );\r
+           This,\r
+           ControllerHandle,\r
+           &gEfiConsoleInDeviceGuid\r
+           );\r
 }\r
 \r
+/**\r
+  Test to see if Simple Pointer protocol could be supported on the Controller.\r
+\r
+  @param  This                Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle    Handle of device to test.\r
+  @param  RemainingDevicePath Optional parameter use to pick a specific child\r
+                              device to start.\r
+\r
+  @retval EFI_SUCCESS         This driver supports this device.\r
+  @retval other               This driver does not support this device.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterSimplePointerDriverBindingSupported (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
-  IN  EFI_HANDLE                      ControllerHandle,\r
-  IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-  Standard Error Supported Check\r
+{\r
+  return ConSplitterSupported (\r
+           This,\r
+           ControllerHandle,\r
+           &gEfiSimplePointerProtocolGuid\r
+           );\r
+}\r
 \r
-Arguments:\r
-  This              - Pointer to protocol.\r
-  ControllerHandle  - Controller handle.\r
-  RemainingDevicePath  - Remaining device path.\r
+/**\r
+  Test to see if Absolute Pointer protocol could be supported on the Controller.\r
 \r
-Returns:\r
+  @param  This                Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle    Handle of device to test.\r
+  @param  RemainingDevicePath Optional parameter use to pick a specific child\r
+                              device to start.\r
 \r
-  EFI_STATUS\r
+  @retval EFI_SUCCESS         This driver supports this device.\r
+  @retval other               This driver does not support this device.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ConSplitterAbsolutePointerDriverBindingSupported (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
 {\r
   return ConSplitterSupported (\r
-          This,\r
-          ControllerHandle,\r
-          &gEfiSimplePointerProtocolGuid\r
-          );\r
+           This,\r
+           ControllerHandle,\r
+           &gEfiAbsolutePointerProtocolGuid\r
+           );\r
 }\r
 \r
+/**\r
+  Test to see if Console Out Device could be supported on the Controller.\r
+\r
+  @param  This                Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle    Handle of device to test.\r
+  @param  RemainingDevicePath Optional parameter use to pick a specific child\r
+                              device to start.\r
+\r
+  @retval EFI_SUCCESS         This driver supports this device.\r
+  @retval other               This driver does not support this device.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterConOutDriverBindingSupported (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
-  IN  EFI_HANDLE                      ControllerHandle,\r
-  IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-  Console Out Supported Check\r
-\r
-Arguments:\r
-  This              - Pointer to protocol.\r
-  ControllerHandle  - Controller handle.\r
-  RemainingDevicePath  - Remaining device path.\r
-\r
-Returns:\r
-\r
-  EFI_STATUS\r
-\r
---*/\r
 {\r
   return ConSplitterSupported (\r
-          This,\r
-          ControllerHandle,\r
-          &gEfiConsoleOutDeviceGuid\r
-          );\r
+           This,\r
+           ControllerHandle,\r
+           &gEfiConsoleOutDeviceGuid\r
+           );\r
 }\r
 \r
+/**\r
+  Test to see if Standard Error Device could be supported on the Controller.\r
+\r
+  @param  This                Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle    Handle of device to test.\r
+  @param  RemainingDevicePath Optional parameter use to pick a specific child\r
+                              device to start.\r
+\r
+  @retval EFI_SUCCESS         This driver supports this device.\r
+  @retval other               This driver does not support this device.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterStdErrDriverBindingSupported (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
-  IN  EFI_HANDLE                      ControllerHandle,\r
-  IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-  Standard Error Supported Check\r
-\r
-Arguments:\r
-  This              - Pointer to protocol.\r
-  ControllerHandle  - Controller handle.\r
-  RemainingDevicePath  - Remaining device path.\r
-\r
-Returns:\r
-\r
-  EFI_STATUS\r
-\r
---*/\r
 {\r
   return ConSplitterSupported (\r
-          This,\r
-          ControllerHandle,\r
-          &gEfiStandardErrorDeviceGuid\r
-          );\r
+           This,\r
+           ControllerHandle,\r
+           &gEfiStandardErrorDeviceGuid\r
+           );\r
 }\r
 \r
-STATIC\r
-EFI_STATUS\r
-EFIAPI\r
-ConSplitterStart (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
-  IN  EFI_HANDLE                      ControllerHandle,\r
-  IN  EFI_HANDLE                      ConSplitterVirtualHandle,\r
-  IN  EFI_GUID                        *DeviceGuid,\r
-  IN  EFI_GUID                        *InterfaceGuid,\r
-  IN  VOID                            **Interface\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-  Start ConSplitter on ControllerHandle, and create the virtual\r
-  agrogated console device on first call Start for a SimpleTextIn handle.\r
+/**\r
+  Start ConSplitter on devcie handle by opening Console Device Guid on device handle\r
+  and the console virtual handle. And Get the console interface on controller handle.\r
 \r
-Arguments:\r
-  (Standard DriverBinding Protocol Start() function)\r
+  @param  This                      Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle          Handle of device.\r
+  @param  ConSplitterVirtualHandle  Console virtual Handle.\r
+  @param  DeviceGuid                The specified Console Device, such as ConInDev,\r
+                                    ConOutDev.\r
+  @param  InterfaceGuid             The specified protocol to be opened.\r
+  @param  Interface                 Protocol interface returned.\r
 \r
-Returns:\r
-  EFI_ERROR if a SimpleTextIn protocol is not started.\r
+  @retval EFI_SUCCESS               This driver supports this device.\r
+  @retval other                     Failed to open the specified Console Device Guid\r
+                                    or specified protocol.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ConSplitterStart (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_HANDLE                   ConSplitterVirtualHandle,\r
+  IN  EFI_GUID                     *DeviceGuid,\r
+  IN  EFI_GUID                     *InterfaceGuid,\r
+  OUT VOID                         **Interface\r
+  )\r
 {\r
   EFI_STATUS  Status;\r
   VOID        *Instance;\r
 \r
   //\r
-  // Check to see whether the handle has the ConsoleInDevice GUID on it\r
+  // Check to see whether the ControllerHandle has the DeviceGuid on it.\r
   //\r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
@@ -791,6 +1099,9 @@ Returns:
     return Status;\r
   }\r
 \r
+  //\r
+  // Open the Parent Handle for the child.\r
+  //\r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
                   DeviceGuid,\r
@@ -800,175 +1111,284 @@ Returns:
                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    return Status;\r
+    goto Err;\r
   }\r
 \r
-  return gBS->OpenProtocol (\r
-                ControllerHandle,\r
-                InterfaceGuid,\r
-                Interface,\r
-                This->DriverBindingHandle,\r
-                ConSplitterVirtualHandle,\r
-                EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
-                );\r
-}\r
+  //\r
+  // Open InterfaceGuid on the virtual handle.\r
+  //\r
+  Status =  gBS->OpenProtocol (\r
+                   ControllerHandle,\r
+                   InterfaceGuid,\r
+                   Interface,\r
+                   This->DriverBindingHandle,\r
+                   ConSplitterVirtualHandle,\r
+                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                   );\r
 \r
-EFI_STATUS\r
-EFIAPI\r
-ConSplitterConInDriverBindingStart (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
-  IN  EFI_HANDLE                      ControllerHandle,\r
-  IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
-  )\r
-/*++\r
+  if (!EFI_ERROR (Status)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // close the DeviceGuid on ConSplitter VirtualHandle.\r
+  //\r
+  gBS->CloseProtocol (\r
+         ControllerHandle,\r
+         DeviceGuid,\r
+         This->DriverBindingHandle,\r
+         ConSplitterVirtualHandle\r
+         );\r
+\r
+Err:\r
+  //\r
+  // close the DeviceGuid on ControllerHandle.\r
+  //\r
+  gBS->CloseProtocol (\r
+         ControllerHandle,\r
+         DeviceGuid,\r
+         This->DriverBindingHandle,\r
+         ControllerHandle\r
+         );\r
 \r
-Routine Description:\r
-  Start ConSplitter on ControllerHandle, and create the virtual\r
-  agrogated console device on first call Start for a SimpleTextIn handle.\r
+  return Status;\r
+}\r
 \r
-Arguments:\r
-  This              - Pointer to protocol.\r
-  ControllerHandle  - Controller handle.\r
-  RemainingDevicePath  - Remaining device path.\r
+/**\r
+  Start Console In Consplitter on device handle.\r
 \r
-Returns:\r
+  @param  This                 Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle     Handle of device to bind driver to.\r
+  @param  RemainingDevicePath  Optional parameter use to pick a specific child\r
+                               device to start.\r
 \r
-  EFI_STATUS\r
-  EFI_ERROR if a SimpleTextIn protocol is not started.\r
+  @retval EFI_SUCCESS          Console In Consplitter is added to ControllerHandle.\r
+  @retval other                Console In Consplitter does not support this device.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ConSplitterConInDriverBindingStart (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
 {\r
-  EFI_STATUS                     Status;\r
-  EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn;\r
+  EFI_STATUS                         Status;\r
+  EFI_SIMPLE_TEXT_INPUT_PROTOCOL     *TextIn;\r
+  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *TextInEx;\r
 \r
   //\r
   // Start ConSplitter on ControllerHandle, and create the virtual\r
-  // agrogated console device on first call Start for a SimpleTextIn handle.\r
+  // aggregated console device on first call Start for a SimpleTextIn handle.\r
   //\r
   Status = ConSplitterStart (\r
-            This,\r
-            ControllerHandle,\r
-            mConIn.VirtualHandle,\r
-            &gEfiConsoleInDeviceGuid,\r
-            &gEfiSimpleTextInProtocolGuid,\r
-            (VOID **) &TextIn\r
-            );\r
+             This,\r
+             ControllerHandle,\r
+             mConIn.VirtualHandle,\r
+             &gEfiConsoleInDeviceGuid,\r
+             &gEfiSimpleTextInProtocolGuid,\r
+             (VOID **)&TextIn\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  return ConSplitterTextInAddDevice (&mConIn, TextIn);\r
+  //\r
+  // Add this device into Text In devices list.\r
+  //\r
+  Status = ConSplitterTextInAddDevice (&mConIn, TextIn);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiSimpleTextInputExProtocolGuid,\r
+                  (VOID **)&TextInEx,\r
+                  This->DriverBindingHandle,\r
+                  mConIn.VirtualHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // If Simple Text Input Ex protocol exists,\r
+    // add this device into Text In Ex devices list.\r
+    //\r
+    Status = ConSplitterTextInExAddDevice (&mConIn, TextInEx);\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
+/**\r
+  Start Simple Pointer Consplitter on device handle.\r
+\r
+  @param  This                 Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle     Handle of device to bind driver to.\r
+  @param  RemainingDevicePath  Optional parameter use to pick a specific child\r
+                               device to start.\r
+\r
+  @retval EFI_SUCCESS          Simple Pointer Consplitter is added to ControllerHandle.\r
+  @retval other                Simple Pointer Consplitter does not support this device.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterSimplePointerDriverBindingStart (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
-  IN  EFI_HANDLE                      ControllerHandle,\r
-  IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
   )\r
-/*++\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_SIMPLE_POINTER_PROTOCOL  *SimplePointer;\r
+\r
+  //\r
+  // Start ConSplitter on ControllerHandle, and create the virtual\r
+  // aggregated console device on first call Start for a SimplePointer handle.\r
+  //\r
+  Status = ConSplitterStart (\r
+             This,\r
+             ControllerHandle,\r
+             mConIn.VirtualHandle,\r
+             &gEfiSimplePointerProtocolGuid,\r
+             &gEfiSimplePointerProtocolGuid,\r
+             (VOID **)&SimplePointer\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
 \r
-Routine Description:\r
-  Start ConSplitter on ControllerHandle, and create the virtual\r
-  agrogated console device on first call Start for a SimpleTextIn handle.\r
+  //\r
+  // Add this devcie into Simple Pointer devices list.\r
+  //\r
+  return ConSplitterSimplePointerAddDevice (&mConIn, SimplePointer);\r
+}\r
 \r
-Arguments:\r
-  This              - Pointer to protocol.\r
-  ControllerHandle  - Controller handle.\r
-  RemainingDevicePath  - Remaining device path.\r
+/**\r
+  Start Absolute Pointer Consplitter on device handle.\r
 \r
-Returns:\r
+  @param  This                 Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle     Handle of device to bind driver to.\r
+  @param  RemainingDevicePath  Optional parameter use to pick a specific child\r
+                               device to start.\r
 \r
-  EFI_ERROR if a SimpleTextIn protocol is not started.\r
+  @retval EFI_SUCCESS          Absolute Pointer Consplitter is added to ControllerHandle.\r
+  @retval other                Absolute Pointer Consplitter does not support this device.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ConSplitterAbsolutePointerDriverBindingStart (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
 {\r
-  EFI_STATUS                  Status;\r
-  EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer;\r
+  EFI_STATUS                     Status;\r
+  EFI_ABSOLUTE_POINTER_PROTOCOL  *AbsolutePointer;\r
 \r
+  //\r
+  // Start ConSplitter on ControllerHandle, and create the virtual\r
+  // aggregated console device on first call Start for a AbsolutePointer handle.\r
+  //\r
   Status = ConSplitterStart (\r
-            This,\r
-            ControllerHandle,\r
-            mConIn.VirtualHandle,\r
-            &gEfiSimplePointerProtocolGuid,\r
-            &gEfiSimplePointerProtocolGuid,\r
-            (VOID **) &SimplePointer\r
-            );\r
+             This,\r
+             ControllerHandle,\r
+             mConIn.VirtualHandle,\r
+             &gEfiAbsolutePointerProtocolGuid,\r
+             &gEfiAbsolutePointerProtocolGuid,\r
+             (VOID **)&AbsolutePointer\r
+             );\r
+\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  return ConSplitterSimplePointerAddDevice (&mConIn, SimplePointer);\r
+  //\r
+  // Add this devcie into Absolute Pointer devices list.\r
+  //\r
+  return ConSplitterAbsolutePointerAddDevice (&mConIn, AbsolutePointer);\r
 }\r
 \r
+/**\r
+  Start Console Out Consplitter on device handle.\r
+\r
+  @param  This                 Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle     Handle of device to bind driver to.\r
+  @param  RemainingDevicePath  Optional parameter use to pick a specific child\r
+                               device to start.\r
+\r
+  @retval EFI_SUCCESS          Console Out Consplitter is added to ControllerHandle.\r
+  @retval other                Console Out Consplitter does not support this device.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterConOutDriverBindingStart (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
-  IN  EFI_HANDLE                      ControllerHandle,\r
-  IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-  Start ConSplitter on ControllerHandle, and create the virtual\r
-  agrogated console device on first call Start for a SimpleTextIn handle.\r
-\r
-Arguments:\r
-  This              - Pointer to protocol.\r
-  ControllerHandle  - Controller handle.\r
-  RemainingDevicePath  - Remaining device path.\r
-\r
-Returns:\r
-  EFI_ERROR if a SimpleTextIn protocol is not started.\r
-\r
---*/\r
 {\r
-  EFI_STATUS                       Status;\r
-  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;\r
-  EFI_GRAPHICS_OUTPUT_PROTOCOL     *GraphicsOutput;\r
-  EFI_UGA_DRAW_PROTOCOL            *UgaDraw;\r
+  EFI_STATUS                            Status;\r
+  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL       *TextOut;\r
+  EFI_GRAPHICS_OUTPUT_PROTOCOL          *GraphicsOutput;\r
+  EFI_UGA_DRAW_PROTOCOL                 *UgaDraw;\r
+  UINTN                                 SizeOfInfo;\r
+  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;\r
 \r
+  //\r
+  // Start ConSplitter on ControllerHandle, and create the virtual\r
+  // aggregated console device on first call Start for a ConsoleOut handle.\r
+  //\r
   Status = ConSplitterStart (\r
-            This,\r
-            ControllerHandle,\r
-            mConOut.VirtualHandle,\r
-            &gEfiConsoleOutDeviceGuid,\r
-            &gEfiSimpleTextOutProtocolGuid,\r
-            (VOID **) &TextOut\r
-            );\r
+             This,\r
+             ControllerHandle,\r
+             mConOut.VirtualHandle,\r
+             &gEfiConsoleOutDeviceGuid,\r
+             &gEfiSimpleTextOutProtocolGuid,\r
+             (VOID **)&TextOut\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
+\r
+  GraphicsOutput = NULL;\r
+  UgaDraw        = NULL;\r
   //\r
   // Try to Open Graphics Output protocol\r
   //\r
   Status = gBS->OpenProtocol (\r
                   ControllerHandle,\r
                   &gEfiGraphicsOutputProtocolGuid,\r
-                  (VOID **) &GraphicsOutput,\r
+                  (VOID **)&GraphicsOutput,\r
                   This->DriverBindingHandle,\r
                   mConOut.VirtualHandle,\r
                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
                   );\r
-  if (EFI_ERROR (Status)) {\r
-    GraphicsOutput = NULL;\r
+\r
+  if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {\r
+    //\r
+    // Open UGA DRAW protocol\r
+    //\r
+    gBS->OpenProtocol (\r
+           ControllerHandle,\r
+           &gEfiUgaDrawProtocolGuid,\r
+           (VOID **)&UgaDraw,\r
+           This->DriverBindingHandle,\r
+           mConOut.VirtualHandle,\r
+           EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+           );\r
   }\r
+\r
   //\r
-  // Open UGA_DRAW protocol\r
+  // When new console device is added, the new mode will be set later,\r
+  // so put current mode back to init state.\r
   //\r
-  Status = gBS->OpenProtocol (\r
-                  ControllerHandle,\r
-                  &gEfiUgaDrawProtocolGuid,\r
-                  (VOID **) &UgaDraw,\r
-                  This->DriverBindingHandle,\r
-                  mConOut.VirtualHandle,\r
-                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    UgaDraw = NULL;\r
-  }\r
+  mConOut.TextOutMode.Mode = 0xFF;\r
+\r
   //\r
   // If both ConOut and StdErr incorporate the same Text Out device,\r
   // their MaxMode and QueryData should be the intersection of both.\r
@@ -976,96 +1396,118 @@ Returns:
   Status = ConSplitterTextOutAddDevice (&mConOut, TextOut, GraphicsOutput, UgaDraw);\r
   ConSplitterTextOutSetAttribute (&mConOut.TextOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
 \r
+  if (FeaturePcdGet (PcdConOutUgaSupport)) {\r
+    //\r
+    // Get the UGA mode data of ConOut from the current mode\r
+    //\r
+    if (GraphicsOutput != NULL) {\r
+      Status = GraphicsOutput->QueryMode (GraphicsOutput, GraphicsOutput->Mode->Mode, &SizeOfInfo, &Info);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      ASSERT (SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));\r
+\r
+      mConOut.UgaHorizontalResolution = Info->HorizontalResolution;\r
+      mConOut.UgaVerticalResolution   = Info->VerticalResolution;\r
+      mConOut.UgaColorDepth           = 32;\r
+      mConOut.UgaRefreshRate          = 60;\r
+\r
+      FreePool (Info);\r
+    } else if (UgaDraw != NULL) {\r
+      Status = UgaDraw->GetMode (\r
+                          UgaDraw,\r
+                          &mConOut.UgaHorizontalResolution,\r
+                          &mConOut.UgaVerticalResolution,\r
+                          &mConOut.UgaColorDepth,\r
+                          &mConOut.UgaRefreshRate\r
+                          );\r
+    }\r
+  }\r
+\r
   return Status;\r
 }\r
 \r
+/**\r
+  Start Standard Error Consplitter on device handle.\r
+\r
+  @param  This                 Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle     Handle of device to bind driver to.\r
+  @param  RemainingDevicePath  Optional parameter use to pick a specific child\r
+                               device to start.\r
+\r
+  @retval EFI_SUCCESS          Standard Error Consplitter is added to ControllerHandle.\r
+  @retval other                Standard Error Consplitter does not support this device.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterStdErrDriverBindingStart (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
-  IN  EFI_HANDLE                      ControllerHandle,\r
-  IN  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-  Start ConSplitter on ControllerHandle, and create the virtual\r
-  agrogated console device on first call Start for a SimpleTextIn handle.\r
-\r
-Arguments:\r
-  This              - Pointer to protocol.\r
-  ControllerHandle  - Controller handle.\r
-  RemainingDevicePath  - Remaining device path.\r
-\r
-Returns:\r
-  EFI_ERROR if a SimpleTextIn protocol is not started.\r
-\r
---*/\r
 {\r
   EFI_STATUS                       Status;\r
   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;\r
 \r
+  //\r
+  // Start ConSplitter on ControllerHandle, and create the virtual\r
+  // aggregated console device on first call Start for a StandardError handle.\r
+  //\r
   Status = ConSplitterStart (\r
-            This,\r
-            ControllerHandle,\r
-            mStdErr.VirtualHandle,\r
-            &gEfiStandardErrorDeviceGuid,\r
-            &gEfiSimpleTextOutProtocolGuid,\r
-            (VOID **) &TextOut\r
-            );\r
+             This,\r
+             ControllerHandle,\r
+             mStdErr.VirtualHandle,\r
+             &gEfiStandardErrorDeviceGuid,\r
+             &gEfiSimpleTextOutProtocolGuid,\r
+             (VOID **)&TextOut\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
+\r
+  //\r
+  // When new console device is added, the new mode will be set later,\r
+  // so put current mode back to init state.\r
+  //\r
+  mStdErr.TextOutMode.Mode = 0xFF;\r
+\r
   //\r
   // If both ConOut and StdErr incorporate the same Text Out device,\r
   // their MaxMode and QueryData should be the intersection of both.\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
-  if (mStdErr.CurrentNumberOfConsoles == 1) {\r
-    gST->StandardErrorHandle  = mStdErr.VirtualHandle;\r
-    gST->StdErr               = &mStdErr.TextOut;\r
-    //\r
-    // Update the CRC32 in the EFI System Table header\r
-    //\r
-    gST->Hdr.CRC32 = 0;\r
-    gBS->CalculateCrc32 (\r
-          (UINT8 *) &gST->Hdr,\r
-          gST->Hdr.HeaderSize,\r
-          &gST->Hdr.CRC32\r
-          );\r
-  }\r
+  ConSplitterTextOutSetAttribute (&mStdErr.TextOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
 \r
   return Status;\r
 }\r
 \r
-STATIC\r
-EFI_STATUS\r
-EFIAPI\r
-ConSplitterStop (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
-  IN  EFI_HANDLE                      ControllerHandle,\r
-  IN  EFI_HANDLE                      ConSplitterVirtualHandle,\r
-  IN  EFI_GUID                        *DeviceGuid,\r
-  IN  EFI_GUID                        *InterfaceGuid,\r
-  IN  VOID                            **Interface\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-Arguments:\r
-  (Standard DriverBinding Protocol Stop() function)\r
+/**\r
+  Stop ConSplitter on device handle by closing Console Device Guid on device handle\r
+  and the console virtual handle.\r
 \r
-Returns:\r
+  @param  This                      Protocol instance pointer.\r
+  @param  ControllerHandle          Handle of device.\r
+  @param  ConSplitterVirtualHandle  Console virtual Handle.\r
+  @param  DeviceGuid                The specified Console Device, such as ConInDev,\r
+                                    ConOutDev.\r
+  @param  InterfaceGuid             The specified protocol to be opened.\r
+  @param  Interface                 Protocol interface returned.\r
 \r
-  None\r
+  @retval EFI_SUCCESS               Stop ConSplitter on ControllerHandle successfully.\r
+  @retval other                     Failed to Stop ConSplitter on ControllerHandle.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ConSplitterStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_HANDLE                   ConSplitterVirtualHandle,\r
+  IN  EFI_GUID                     *DeviceGuid,\r
+  IN  EFI_GUID                     *InterfaceGuid,\r
+  IN  VOID                         **Interface\r
+  )\r
 {\r
   EFI_STATUS  Status;\r
 \r
@@ -1080,135 +1522,220 @@ Returns:
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
+\r
   //\r
-  // close the protocol refered.\r
+  // close the protocol referred.\r
   //\r
   gBS->CloseProtocol (\r
-        ControllerHandle,\r
-        DeviceGuid,\r
-        This->DriverBindingHandle,\r
-        ConSplitterVirtualHandle\r
-        );\r
+         ControllerHandle,\r
+         DeviceGuid,\r
+         This->DriverBindingHandle,\r
+         ConSplitterVirtualHandle\r
+         );\r
+\r
   gBS->CloseProtocol (\r
-        ControllerHandle,\r
-        DeviceGuid,\r
-        This->DriverBindingHandle,\r
-        ControllerHandle\r
-        );\r
+         ControllerHandle,\r
+         DeviceGuid,\r
+         This->DriverBindingHandle,\r
+         ControllerHandle\r
+         );\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Stop Console In ConSplitter on ControllerHandle by closing Console In Device GUID.\r
+\r
+  @param  This              Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle  Handle of device to stop driver on\r
+  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
+                            children is zero stop the entire bus driver.\r
+  @param  ChildHandleBuffer List of Child Handles to Stop.\r
+\r
+  @retval EFI_SUCCESS       This driver is removed ControllerHandle\r
+  @retval other             This driver was not removed from this device\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterConInDriverBindingStop (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
-  IN  EFI_HANDLE                      ControllerHandle,\r
-  IN  UINTN                           NumberOfChildren,\r
-  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  UINTN                        NumberOfChildren,\r
+  IN  EFI_HANDLE                   *ChildHandleBuffer\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-Arguments:\r
-  (Standard DriverBinding Protocol Stop() function)\r
-\r
-Returns:\r
-\r
-  None\r
-\r
---*/\r
 {\r
-  EFI_STATUS                     Status;\r
-  EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn;\r
+  EFI_STATUS                         Status;\r
+  EFI_SIMPLE_TEXT_INPUT_PROTOCOL     *TextIn;\r
+  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *TextInEx;\r
 \r
   if (NumberOfChildren == 0) {\r
     return EFI_SUCCESS;\r
   }\r
 \r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiSimpleTextInputExProtocolGuid,\r
+                  (VOID **)&TextInEx,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // If Simple Text Input Ex protocol exists,\r
+    // remove device from Text Input Ex devices list.\r
+    //\r
+    Status = ConSplitterTextInExDeleteDevice (&mConIn, TextInEx);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Close Simple Text In protocol on controller handle and virtual handle.\r
+  //\r
   Status = ConSplitterStop (\r
-            This,\r
-            ControllerHandle,\r
-            mConIn.VirtualHandle,\r
-            &gEfiConsoleInDeviceGuid,\r
-            &gEfiSimpleTextInProtocolGuid,\r
-            (VOID **) &TextIn\r
-            );\r
+             This,\r
+             ControllerHandle,\r
+             mConIn.VirtualHandle,\r
+             &gEfiConsoleInDeviceGuid,\r
+             &gEfiSimpleTextInProtocolGuid,\r
+             (VOID **)&TextIn\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
+\r
   //\r
-  // Delete this console input device's data structures.\r
+  // Remove device from Text Input devices list.\r
   //\r
   return ConSplitterTextInDeleteDevice (&mConIn, TextIn);\r
 }\r
 \r
+/**\r
+  Stop Simple Pointer protocol ConSplitter on ControllerHandle by closing\r
+  Simple Pointer protocol.\r
+\r
+  @param  This              Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle  Handle of device to stop driver on\r
+  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
+                            children is zero stop the entire bus driver.\r
+  @param  ChildHandleBuffer List of Child Handles to Stop.\r
+\r
+  @retval EFI_SUCCESS       This driver is removed ControllerHandle\r
+  @retval other             This driver was not removed from this device\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterSimplePointerDriverBindingStop (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
-  IN  EFI_HANDLE                      ControllerHandle,\r
-  IN  UINTN                           NumberOfChildren,\r
-  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  UINTN                        NumberOfChildren,\r
+  IN  EFI_HANDLE                   *ChildHandleBuffer\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-Arguments:\r
-  (Standard DriverBinding Protocol Stop() function)\r
-\r
-Returns:\r
-\r
-  None\r
-\r
---*/\r
 {\r
-  EFI_STATUS                  Status;\r
-  EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer;\r
+  EFI_STATUS                   Status;\r
+  EFI_SIMPLE_POINTER_PROTOCOL  *SimplePointer;\r
 \r
   if (NumberOfChildren == 0) {\r
     return EFI_SUCCESS;\r
   }\r
 \r
+  //\r
+  // Close Simple Pointer protocol on controller handle and virtual handle.\r
+  //\r
   Status = ConSplitterStop (\r
-            This,\r
-            ControllerHandle,\r
-            mConIn.VirtualHandle,\r
-            &gEfiSimplePointerProtocolGuid,\r
-            &gEfiSimplePointerProtocolGuid,\r
-            (VOID **) &SimplePointer\r
-            );\r
+             This,\r
+             ControllerHandle,\r
+             mConIn.VirtualHandle,\r
+             &gEfiSimplePointerProtocolGuid,\r
+             &gEfiSimplePointerProtocolGuid,\r
+             (VOID **)&SimplePointer\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
+\r
   //\r
-  // Delete this console input device's data structures.\r
+  // Remove this device from Simple Pointer device list.\r
   //\r
   return ConSplitterSimplePointerDeleteDevice (&mConIn, SimplePointer);\r
 }\r
 \r
+/**\r
+  Stop Absolute Pointer protocol ConSplitter on ControllerHandle by closing\r
+  Absolute Pointer protocol.\r
+\r
+  @param  This              Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle  Handle of device to stop driver on\r
+  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
+                            children is zero stop the entire bus driver.\r
+  @param  ChildHandleBuffer List of Child Handles to Stop.\r
+\r
+  @retval EFI_SUCCESS       This driver is removed ControllerHandle\r
+  @retval other             This driver was not removed from this device\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
-ConSplitterConOutDriverBindingStop (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
-  IN  EFI_HANDLE                      ControllerHandle,\r
-  IN  UINTN                           NumberOfChildren,\r
-  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+ConSplitterAbsolutePointerDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  UINTN                        NumberOfChildren,\r
+  IN  EFI_HANDLE                   *ChildHandleBuffer\r
   )\r
-/*++\r
+{\r
+  EFI_STATUS                     Status;\r
+  EFI_ABSOLUTE_POINTER_PROTOCOL  *AbsolutePointer;\r
+\r
+  if (NumberOfChildren == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Close Absolute Pointer protocol on controller handle and virtual handle.\r
+  //\r
+  Status = ConSplitterStop (\r
+             This,\r
+             ControllerHandle,\r
+             mConIn.VirtualHandle,\r
+             &gEfiAbsolutePointerProtocolGuid,\r
+             &gEfiAbsolutePointerProtocolGuid,\r
+             (VOID **)&AbsolutePointer\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
 \r
-Routine Description:\r
+  //\r
+  // Remove this device from Absolute Pointer device list.\r
+  //\r
+  return ConSplitterAbsolutePointerDeleteDevice (&mConIn, AbsolutePointer);\r
+}\r
 \r
-Arguments:\r
-  (Standard DriverBinding Protocol Stop() function)\r
+/**\r
+  Stop Console Out ConSplitter on device handle by closing Console Out Devcie GUID.\r
 \r
-Returns:\r
+  @param  This              Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle  Handle of device to stop driver on\r
+  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
+                            children is zero stop the entire bus driver.\r
+  @param  ChildHandleBuffer List of Child Handles to Stop.\r
 \r
-  None\r
+  @retval EFI_SUCCESS       This driver is removed ControllerHandle\r
+  @retval other             This driver was not removed from this device\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ConSplitterConOutDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  UINTN                        NumberOfChildren,\r
+  IN  EFI_HANDLE                   *ChildHandleBuffer\r
+  )\r
 {\r
   EFI_STATUS                       Status;\r
   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;\r
@@ -1217,44 +1744,48 @@ Returns:
     return EFI_SUCCESS;\r
   }\r
 \r
+  //\r
+  // Close Absolute Pointer protocol on controller handle and virtual handle.\r
+  //\r
   Status = ConSplitterStop (\r
-            This,\r
-            ControllerHandle,\r
-            mConOut.VirtualHandle,\r
-            &gEfiConsoleOutDeviceGuid,\r
-            &gEfiSimpleTextOutProtocolGuid,\r
-            (VOID **) &TextOut\r
-            );\r
+             This,\r
+             ControllerHandle,\r
+             mConOut.VirtualHandle,\r
+             &gEfiConsoleOutDeviceGuid,\r
+             &gEfiSimpleTextOutProtocolGuid,\r
+             (VOID **)&TextOut\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
   //\r
-  // Delete this console output device's data structures.\r
+  // Remove this device from Text Out device list.\r
   //\r
   return ConSplitterTextOutDeleteDevice (&mConOut, TextOut);\r
 }\r
 \r
+/**\r
+  Stop Standard Error ConSplitter on ControllerHandle by closing Standard Error GUID.\r
+\r
+  @param  This              Driver Binding protocol instance pointer.\r
+  @param  ControllerHandle  Handle of device to stop driver on\r
+  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
+                            children is zero stop the entire bus driver.\r
+  @param  ChildHandleBuffer List of Child Handles to Stop.\r
+\r
+  @retval EFI_SUCCESS       This driver is removed ControllerHandle\r
+  @retval other             This driver was not removed from this device\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterStdErrDriverBindingStop (\r
-  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
-  IN  EFI_HANDLE                      ControllerHandle,\r
-  IN  UINTN                           NumberOfChildren,\r
-  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  UINTN                        NumberOfChildren,\r
+  IN  EFI_HANDLE                   *ChildHandleBuffer\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-Arguments:\r
-  (Standard DriverBinding Protocol Stop() function)\r
-\r
-Returns:\r
-\r
-  EFI_SUCCESS - Complete successfully.\r
-\r
---*/\r
 {\r
   EFI_STATUS                       Status;\r
   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;\r
@@ -1263,72 +1794,49 @@ Returns:
     return EFI_SUCCESS;\r
   }\r
 \r
+  //\r
+  // Close Standard Error Device on controller handle and virtual handle.\r
+  //\r
   Status = ConSplitterStop (\r
-            This,\r
-            ControllerHandle,\r
-            mStdErr.VirtualHandle,\r
-            &gEfiStandardErrorDeviceGuid,\r
-            &gEfiSimpleTextOutProtocolGuid,\r
-            (VOID **) &TextOut\r
-            );\r
+             This,\r
+             ControllerHandle,\r
+             mStdErr.VirtualHandle,\r
+             &gEfiStandardErrorDeviceGuid,\r
+             &gEfiSimpleTextOutProtocolGuid,\r
+             (VOID **)&TextOut\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
+\r
   //\r
   // Delete this console error out device's data structures.\r
   //\r
-  Status = ConSplitterTextOutDeleteDevice (&mStdErr, TextOut);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
+  return ConSplitterTextOutDeleteDevice (&mStdErr, TextOut);\r
+}\r
 \r
-  if (mStdErr.CurrentNumberOfConsoles == 0) {\r
-    gST->StandardErrorHandle  = NULL;\r
-    gST->StdErr               = NULL;\r
-    //\r
-    // Update the CRC32 in the EFI System Table header\r
-    //\r
-    gST->Hdr.CRC32 = 0;\r
-    gBS->CalculateCrc32 (\r
-          (UINT8 *) &gST->Hdr,\r
-          gST->Hdr.HeaderSize,\r
-          &gST->Hdr.CRC32\r
-          );\r
-  }\r
+/**\r
+  Take the passed in Buffer of size ElementSize and grow the buffer\r
+  by CONSOLE_SPLITTER_ALLOC_UNIT * ElementSize bytes.\r
+  Copy the current data in Buffer to the new version of Buffer and\r
+  free the old version of buffer.\r
 \r
-  return Status;\r
-}\r
+  @param  ElementSize              Size of element in array.\r
+  @param  Count                    Current number of elements in array.\r
+  @param  Buffer                   Bigger version of passed in Buffer with all the\r
+                                   data.\r
 \r
+  @retval EFI_SUCCESS              Buffer size has grown.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.\r
+\r
+**/\r
 EFI_STATUS\r
 ConSplitterGrowBuffer (\r
-  IN  UINTN                           SizeOfCount,\r
-  IN  UINTN                           *Count,\r
-  IN OUT  VOID                        **Buffer\r
+  IN      UINTN  ElementSize,\r
+  IN OUT  UINTN  *Count,\r
+  IN OUT  VOID   **Buffer\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-  Take the passed in Buffer of size SizeOfCount and grow the buffer\r
-  by MAX (CONSOLE_SPLITTER_CONSOLES_ALLOC_UNIT, MaxGrow) * SizeOfCount\r
-  bytes. Copy the current data in Buffer to the new version of Buffer\r
-  and free the old version of buffer.\r
-\r
-\r
-Arguments:\r
-  SizeOfCount - Size of element in array\r
-  Count       - Current number of elements in array\r
-  Buffer      - Bigger version of passed in Buffer with all the data\r
-\r
-Returns:\r
-  EFI_SUCCESS - Buffer size has grown\r
-  EFI_OUT_OF_RESOURCES - Could not grow the buffer size\r
-\r
-  None\r
-\r
---*/\r
 {\r
-  UINTN NewSize;\r
-  UINTN OldSize;\r
   VOID  *Ptr;\r
 \r
   //\r
@@ -1336,59 +1844,52 @@ Returns:
   // copy the old buffer's content to the new-size buffer,\r
   // then free the old buffer.\r
   //\r
-  OldSize = *Count * SizeOfCount;\r
-  *Count += CONSOLE_SPLITTER_CONSOLES_ALLOC_UNIT;\r
-  NewSize = *Count * SizeOfCount;\r
-\r
-  Ptr     = AllocateZeroPool (NewSize);\r
+  Ptr = ReallocatePool (\r
+          ElementSize * (*Count),\r
+          ElementSize * ((*Count) + CONSOLE_SPLITTER_ALLOC_UNIT),\r
+          *Buffer\r
+          );\r
   if (Ptr == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  CopyMem (Ptr, *Buffer, OldSize);\r
-\r
-  if (*Buffer != NULL) {\r
-    FreePool (*Buffer);\r
-  }\r
-\r
+  *Count += CONSOLE_SPLITTER_ALLOC_UNIT;\r
   *Buffer = Ptr;\r
-\r
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Add Text Input Device in Consplitter Text Input list.\r
+\r
+  @param  Private                  Text In Splitter pointer.\r
+  @param  TextIn                   Simple Text Input protocol pointer.\r
+\r
+  @retval EFI_SUCCESS              Text Input Device added successfully.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.\r
+\r
+**/\r
 EFI_STATUS\r
 ConSplitterTextInAddDevice (\r
   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,\r
   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *TextIn\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-Arguments:\r
-\r
-Returns:\r
-\r
-  EFI_SUCCESS\r
-  EFI_OUT_OF_RESOURCES\r
-\r
---*/\r
 {\r
   EFI_STATUS  Status;\r
 \r
   //\r
-  // If the Text In List is full, enlarge it by calling growbuffer().\r
+  // If the Text In List is full, enlarge it by calling ConSplitterGrowBuffer().\r
   //\r
   if (Private->CurrentNumberOfConsoles >= Private->TextInListCount) {\r
     Status = ConSplitterGrowBuffer (\r
-              sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *),\r
-              &Private->TextInListCount,\r
-              (VOID **) &Private->TextInList\r
-              );\r
+               sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *),\r
+               &Private->TextInListCount,\r
+               (VOID **)&Private->TextInList\r
+               );\r
     if (EFI_ERROR (Status)) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
   }\r
+\r
   //\r
   // Add the new text-in device data structure into the Text In List.\r
   //\r
@@ -1396,39 +1897,38 @@ Returns:
   Private->CurrentNumberOfConsoles++;\r
 \r
   //\r
-  // Extra CheckEvent added to reduce the double CheckEvent() in UI.c\r
+  // Extra CheckEvent added to reduce the double CheckEvent().\r
   //\r
   gBS->CheckEvent (TextIn->WaitForKey);\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Remove Text Input Device from Consplitter Text Input list.\r
+\r
+  @param  Private                  Text In Splitter pointer.\r
+  @param  TextIn                   Simple Text protocol pointer.\r
+\r
+  @retval EFI_SUCCESS              Simple Text Device removed successfully.\r
+  @retval EFI_NOT_FOUND            No Simple Text Device found.\r
+\r
+**/\r
 EFI_STATUS\r
 ConSplitterTextInDeleteDevice (\r
   IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,\r
   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *TextIn\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-Arguments:\r
-\r
-Returns:\r
-\r
-  EFI_SUCCESS\r
-  EFI_NOT_FOUND\r
-\r
---*/\r
 {\r
-  UINTN Index;\r
+  UINTN  Index;\r
+\r
   //\r
   // Remove the specified text-in device data structure from the Text In List,\r
   // and rearrange the remaining data structures in the Text In List.\r
   //\r
   for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\r
     if (Private->TextInList[Index] == TextIn) {\r
-      for (Index = Index; Index < Private->CurrentNumberOfConsoles - 1; Index++) {\r
+      for ( ; Index < Private->CurrentNumberOfConsoles - 1; Index++) {\r
         Private->TextInList[Index] = Private->TextInList[Index + 1];\r
       }\r
 \r
@@ -1440,76 +1940,137 @@ Returns:
   return EFI_NOT_FOUND;\r
 }\r
 \r
-EFI_STATUS\r
-ConSplitterSimplePointerAddDevice (\r
-  IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,\r
-  IN  EFI_SIMPLE_POINTER_PROTOCOL     *SimplePointer\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-Arguments:\r
+/**\r
+  Add Text Input Ex Device in Consplitter Text Input Ex list.\r
 \r
-Returns:\r
+  @param  Private                  Text In Splitter pointer.\r
+  @param  TextInEx                 Simple Text Input Ex Input protocol pointer.\r
 \r
-  EFI_OUT_OF_RESOURCES\r
-  EFI_SUCCESS\r
+  @retval EFI_SUCCESS              Text Input Ex Device added successfully.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ConSplitterTextInExAddDevice (\r
+  IN  TEXT_IN_SPLITTER_PRIVATE_DATA      *Private,\r
+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *TextInEx\r
+  )\r
 {\r
-  EFI_STATUS  Status;\r
+  EFI_STATUS                  Status;\r
+  LIST_ENTRY                  *Link;\r
+  TEXT_IN_EX_SPLITTER_NOTIFY  *CurrentNotify;\r
+  UINTN                       TextInExListCount;\r
 \r
   //\r
-  // If the Text In List is full, enlarge it by calling growbuffer().\r
+  // Enlarge the NotifyHandleList and the TextInExList\r
   //\r
-  if (Private->CurrentNumberOfPointers >= Private->PointerListCount) {\r
+  if (Private->CurrentNumberOfExConsoles >= Private->TextInExListCount) {\r
+    for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {\r
+      CurrentNotify     = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);\r
+      TextInExListCount = Private->TextInExListCount;\r
+\r
+      Status = ConSplitterGrowBuffer (\r
+                 sizeof (EFI_HANDLE),\r
+                 &TextInExListCount,\r
+                 (VOID **)&CurrentNotify->NotifyHandleList\r
+                 );\r
+      if (EFI_ERROR (Status)) {\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_POINTER_PROTOCOL *),\r
-              &Private->PointerListCount,\r
-              (VOID **) &Private->PointerList\r
-              );\r
+               sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *),\r
+               &Private->TextInExListCount,\r
+               (VOID **)&Private->TextInExList\r
+               );\r
     if (EFI_ERROR (Status)) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
   }\r
+\r
   //\r
-  // Add the new text-in device data structure into the Text In List.\r
+  // Register the key notify in the new text-in device\r
   //\r
-  Private->PointerList[Private->CurrentNumberOfPointers] = SimplePointer;\r
-  Private->CurrentNumberOfPointers++;\r
-  return EFI_SUCCESS;\r
-}\r
+  for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {\r
+    CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);\r
+    Status        = TextInEx->RegisterKeyNotify (\r
+                                TextInEx,\r
+                                &CurrentNotify->KeyData,\r
+                                CurrentNotify->KeyNotificationFn,\r
+                                &CurrentNotify->NotifyHandleList[Private->CurrentNumberOfExConsoles]\r
+                                );\r
+    if (EFI_ERROR (Status)) {\r
+      for (Link = Link->BackLink; Link != &Private->NotifyList; Link = Link->BackLink) {\r
+        CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);\r
+        TextInEx->UnregisterKeyNotify (\r
+                    TextInEx,\r
+                    CurrentNotify->NotifyHandleList[Private->CurrentNumberOfExConsoles]\r
+                    );\r
+      }\r
 \r
-EFI_STATUS\r
-ConSplitterSimplePointerDeleteDevice (\r
-  IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,\r
-  IN  EFI_SIMPLE_POINTER_PROTOCOL     *SimplePointer\r
-  )\r
-/*++\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Add the new text-in device data structure into the Text Input Ex List.\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
+  gBS->CheckEvent (TextInEx->WaitForKeyEx);\r
 \r
-Routine Description:\r
+  return EFI_SUCCESS;\r
+}\r
 \r
-Arguments:\r
+/**\r
+  Remove Text Ex Device from Consplitter Text Input Ex list.\r
 \r
-Returns:\r
+  @param  Private                  Text In Splitter pointer.\r
+  @param  TextInEx                 Simple Text Ex protocol pointer.\r
 \r
-  None\r
+  @retval EFI_SUCCESS              Simple Text Input Ex Device removed successfully.\r
+  @retval EFI_NOT_FOUND            No Simple Text Input Ex Device found.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ConSplitterTextInExDeleteDevice (\r
+  IN  TEXT_IN_SPLITTER_PRIVATE_DATA      *Private,\r
+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *TextInEx\r
+  )\r
 {\r
-  UINTN Index;\r
+  UINTN  Index;\r
+\r
   //\r
-  // Remove the specified text-in device data structure from the Text In List,\r
+  // Remove the specified text-in device data structure from the Text Input Ex List,\r
   // and rearrange the remaining data structures in the Text In List.\r
   //\r
-  for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {\r
-    if (Private->PointerList[Index] == SimplePointer) {\r
-      for (Index = Index; Index < Private->CurrentNumberOfPointers - 1; Index++) {\r
-        Private->PointerList[Index] = Private->PointerList[Index + 1];\r
+  for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {\r
+    if (Private->TextInExList[Index] == TextInEx) {\r
+      for ( ; Index < Private->CurrentNumberOfExConsoles - 1; Index++) {\r
+        Private->TextInExList[Index] = Private->TextInExList[Index + 1];\r
       }\r
 \r
-      Private->CurrentNumberOfPointers--;\r
+      Private->CurrentNumberOfExConsoles--;\r
       return EFI_SUCCESS;\r
     }\r
   }\r
@@ -1517,36 +2078,194 @@ Returns:
   return EFI_NOT_FOUND;\r
 }\r
 \r
-STATIC\r
-EFI_STATUS\r
-ConSplitterGrowMapTable (\r
-  IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private\r
-  )\r
-/*++\r
+/**\r
+  Add Simple Pointer Device in Consplitter Simple Pointer list.\r
+\r
+  @param  Private                  Text In Splitter pointer.\r
+  @param  SimplePointer            Simple Pointer protocol pointer.\r
+\r
+  @retval EFI_SUCCESS              Simple Pointer Device added successfully.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.\r
+\r
+**/\r
+EFI_STATUS\r
+ConSplitterSimplePointerAddDevice (\r
+  IN  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private,\r
+  IN  EFI_SIMPLE_POINTER_PROTOCOL    *SimplePointer\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // If the Simple Pointer List is full, enlarge it by calling ConSplitterGrowBuffer().\r
+  //\r
+  if (Private->CurrentNumberOfPointers >= Private->PointerListCount) {\r
+    Status = ConSplitterGrowBuffer (\r
+               sizeof (EFI_SIMPLE_POINTER_PROTOCOL *),\r
+               &Private->PointerListCount,\r
+               (VOID **)&Private->PointerList\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Add the new text-in device data structure into the Simple Pointer List.\r
+  //\r
+  Private->PointerList[Private->CurrentNumberOfPointers] = SimplePointer;\r
+  Private->CurrentNumberOfPointers++;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Remove Simple Pointer Device from Consplitter Simple Pointer list.\r
+\r
+  @param  Private                  Text In Splitter pointer.\r
+  @param  SimplePointer            Simple Pointer protocol pointer.\r
+\r
+  @retval EFI_SUCCESS              Simple Pointer Device removed successfully.\r
+  @retval EFI_NOT_FOUND            No Simple Pointer Device found.\r
+\r
+**/\r
+EFI_STATUS\r
+ConSplitterSimplePointerDeleteDevice (\r
+  IN  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private,\r
+  IN  EFI_SIMPLE_POINTER_PROTOCOL    *SimplePointer\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  //\r
+  // Remove the specified text-in device data structure from the Simple Pointer List,\r
+  // and rearrange the remaining data structures in the Text In List.\r
+  //\r
+  for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {\r
+    if (Private->PointerList[Index] == SimplePointer) {\r
+      for ( ; Index < Private->CurrentNumberOfPointers - 1; Index++) {\r
+        Private->PointerList[Index] = Private->PointerList[Index + 1];\r
+      }\r
+\r
+      Private->CurrentNumberOfPointers--;\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Add Absolute Pointer Device in Consplitter Absolute Pointer list.\r
+\r
+  @param  Private                  Text In Splitter pointer.\r
+  @param  AbsolutePointer          Absolute Pointer protocol pointer.\r
+\r
+  @retval EFI_SUCCESS              Absolute Pointer Device added successfully.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.\r
+\r
+**/\r
+EFI_STATUS\r
+ConSplitterAbsolutePointerAddDevice (\r
+  IN  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private,\r
+  IN  EFI_ABSOLUTE_POINTER_PROTOCOL  *AbsolutePointer\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // If the Absolute Pointer List is full, enlarge it by calling ConSplitterGrowBuffer().\r
+  //\r
+  if (Private->CurrentNumberOfAbsolutePointers >= Private->AbsolutePointerListCount) {\r
+    Status = ConSplitterGrowBuffer (\r
+               sizeof (EFI_ABSOLUTE_POINTER_PROTOCOL *),\r
+               &Private->AbsolutePointerListCount,\r
+               (VOID **)&Private->AbsolutePointerList\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Add the new text-in device data structure into the Absolute Pointer List.\r
+  //\r
+  Private->AbsolutePointerList[Private->CurrentNumberOfAbsolutePointers] = AbsolutePointer;\r
+  Private->CurrentNumberOfAbsolutePointers++;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Remove Absolute Pointer Device from Consplitter Absolute Pointer list.\r
+\r
+  @param  Private                  Text In Splitter pointer.\r
+  @param  AbsolutePointer          Absolute Pointer protocol pointer.\r
+\r
+  @retval EFI_SUCCESS              Absolute Pointer Device removed successfully.\r
+  @retval EFI_NOT_FOUND            No Absolute Pointer Device found.\r
+\r
+**/\r
+EFI_STATUS\r
+ConSplitterAbsolutePointerDeleteDevice (\r
+  IN  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private,\r
+  IN  EFI_ABSOLUTE_POINTER_PROTOCOL  *AbsolutePointer\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  //\r
+  // Remove the specified text-in device data structure from the Absolute Pointer List,\r
+  // and rearrange the remaining data structures from the Absolute Pointer List.\r
+  //\r
+  for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {\r
+    if (Private->AbsolutePointerList[Index] == AbsolutePointer) {\r
+      for ( ; Index < Private->CurrentNumberOfAbsolutePointers - 1; Index++) {\r
+        Private->AbsolutePointerList[Index] = Private->AbsolutePointerList[Index + 1];\r
+      }\r
+\r
+      Private->CurrentNumberOfAbsolutePointers--;\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
 \r
-Routine Description:\r
+/**\r
+  Reallocate Text Out mode map.\r
 \r
-Arguments:\r
+  Allocate new buffer and copy original buffer into the new buffer.\r
 \r
-Returns:\r
+  @param  Private                  Consplitter Text Out pointer.\r
 \r
-  None\r
+  @retval EFI_SUCCESS              Buffer size has grown\r
+  @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ConSplitterGrowMapTable (\r
+  IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private\r
+  )\r
 {\r
-  UINTN Size;\r
-  UINTN NewSize;\r
-  UINTN TotalSize;\r
-  INT32 *TextOutModeMap;\r
-  INT32 *OldTextOutModeMap;\r
-  INT32 *SrcAddress;\r
-  INT32 Index;\r
+  UINTN  Size;\r
+  UINTN  NewSize;\r
+  UINTN  TotalSize;\r
+  INT32  *TextOutModeMap;\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
-  TotalSize         = NewSize * Private->TextOutQueryDataCount;\r
+  TotalSize         = NewSize * (Private->TextOutQueryDataCount);\r
 \r
-  TextOutModeMap    = AllocateZeroPool (TotalSize);\r
+  //\r
+  // Allocate new buffer for Text Out List.\r
+  //\r
+  TextOutModeMap = AllocatePool (TotalSize);\r
   if (TextOutModeMap == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
@@ -1571,20 +2290,32 @@ Returns:
   // QueryDataCount\r
   //\r
   if (OldTextOutModeMap != NULL) {\r
-\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
-      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
     //\r
     // Free the old buffer\r
     //\r
@@ -1594,46 +2325,45 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
-STATIC\r
-EFI_STATUS\r
-ConSplitterAddOutputMode (\r
-  IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,\r
-  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-Arguments:\r
+/**\r
+  Add new device's output mode to console splitter's mode list.\r
 \r
-Returns:\r
+  @param  Private               Text Out Splitter pointer\r
+  @param  TextOut               Simple Text Output protocol pointer.\r
 \r
-  None\r
+  @retval EFI_SUCCESS           Device added successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Could not grow the buffer size.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ConSplitterAddOutputMode (\r
+  IN  TEXT_OUT_SPLITTER_PRIVATE_DATA   *Private,\r
+  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut\r
+  )\r
 {\r
   EFI_STATUS  Status;\r
   INT32       MaxMode;\r
   INT32       Mode;\r
   UINTN       Index;\r
 \r
-  MaxMode                       = TextOut->Mode->MaxMode;\r
-  Private->TextOutMode.MaxMode  = MaxMode;\r
+  MaxMode                      = TextOut->Mode->MaxMode;\r
+  Private->TextOutMode.MaxMode = MaxMode;\r
 \r
   //\r
   // Grow the buffer if query data buffer is not large enough to\r
   // hold all the mode supported by the first console.\r
   //\r
-  while (MaxMode > (INT32) Private->TextOutQueryDataCount) {\r
+  while (MaxMode > (INT32)Private->TextOutQueryDataCount) {\r
     Status = ConSplitterGrowBuffer (\r
-              sizeof (TEXT_OUT_SPLITTER_QUERY_DATA),\r
-              &Private->TextOutQueryDataCount,\r
-              (VOID **) &Private->TextOutQueryData\r
-              );\r
+               sizeof (TEXT_OUT_SPLITTER_QUERY_DATA),\r
+               &Private->TextOutQueryDataCount,\r
+               (VOID **)&Private->TextOutQueryData\r
+               );\r
     if (EFI_ERROR (Status)) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
   }\r
+\r
   //\r
   // Allocate buffer for the output mode map\r
   //\r
@@ -1641,6 +2371,7 @@ Returns:
   if (EFI_ERROR (Status)) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
+\r
   //\r
   // As the first textout device, directly add the mode in to QueryData\r
   // and at the same time record the mapping between QueryData and TextOut.\r
@@ -1648,12 +2379,21 @@ Returns:
   Mode  = 0;\r
   Index = 0;\r
   while (Mode < MaxMode) {\r
-    TextOut->QueryMode (\r
-              TextOut,\r
-              Mode,\r
-              &Private->TextOutQueryData[Mode].Columns,\r
-              &Private->TextOutQueryData[Mode].Rows\r
-              );\r
+    Status = TextOut->QueryMode (\r
+                        TextOut,\r
+                        Mode,\r
+                        &Private->TextOutQueryData[Mode].Columns,\r
+                        &Private->TextOutQueryData[Mode].Rows\r
+                        );\r
+    //\r
+    // If mode 1 (80x50) is not supported, make sure mode 1 in TextOutQueryData\r
+    // is clear to 0x0.\r
+    //\r
+    if ((EFI_ERROR (Status)) && (Mode == 1)) {\r
+      Private->TextOutQueryData[Mode].Columns = 0;\r
+      Private->TextOutQueryData[Mode].Rows    = 0;\r
+    }\r
+\r
     Private->TextOutModeMap[Index] = Mode;\r
     Mode++;\r
     Index += Private->TextOutListCount;\r
@@ -1662,31 +2402,54 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
-STATIC\r
+/**\r
+  Reconstruct TextOutModeMap to get intersection of modes.\r
+\r
+  This routine reconstruct TextOutModeMap to get the intersection\r
+  of modes for all console out devices. Because EFI/UEFI spec require\r
+  mode 0 is 80x25, mode 1 is 80x50, this routine will not check the\r
+  intersection for mode 0 and mode 1.\r
+\r
+  @param TextOutModeMap  Current text out mode map, begin with the mode 80x25\r
+  @param NewlyAddedMap   New text out mode map, begin with the mode 80x25\r
+  @param MapStepSize     Mode step size for one console device\r
+  @param NewMapStepSize  New Mode step size for one console device\r
+  @param MaxMode         IN: Current max text mode, OUT: Updated max text mode.\r
+  @param CurrentMode     IN: Current text mode,     OUT: Updated current text mode.\r
+\r
+**/\r
 VOID\r
 ConSplitterGetIntersection (\r
-  IN  INT32                           *TextOutModeMap,\r
-  IN  INT32                           *NewlyAddedMap,\r
-  IN  UINTN                           MapStepSize,\r
-  IN  UINTN                           NewMapStepSize,\r
-  OUT INT32                           *MaxMode,\r
-  OUT INT32                           *CurrentMode\r
-  )\r
-{\r
-  INT32 Index;\r
-  INT32 *CurrentMapEntry;\r
-  INT32 *NextMapEntry;\r
-  INT32 CurrentMaxMode;\r
-  INT32 Mode;\r
-\r
-  Index           = 0;\r
-  CurrentMapEntry = TextOutModeMap;\r
-  NextMapEntry    = TextOutModeMap;\r
-  CurrentMaxMode  = *MaxMode;\r
-  Mode            = *CurrentMode;\r
+  IN     INT32  *TextOutModeMap,\r
+  IN     INT32  *NewlyAddedMap,\r
+  IN     UINTN  MapStepSize,\r
+  IN     UINTN  NewMapStepSize,\r
+  IN OUT INT32  *MaxMode,\r
+  IN OUT INT32  *CurrentMode\r
+  )\r
+{\r
+  INT32  Index;\r
+  INT32  *CurrentMapEntry;\r
+  INT32  *NextMapEntry;\r
+  INT32  *NewMapEntry;\r
+  INT32  CurrentMaxMode;\r
+  INT32  Mode;\r
+\r
+  //\r
+  // According to EFI/UEFI spec, mode 0 and mode 1 have been reserved\r
+  // for 80x25 and 80x50 in Simple Text Out protocol, so don't make intersection\r
+  // for mode 0 and mode 1, mode number starts from 2.\r
+  //\r
+  Index           = 2;\r
+  CurrentMapEntry = &TextOutModeMap[MapStepSize * 2];\r
+  NextMapEntry    = CurrentMapEntry;\r
+  NewMapEntry     = &NewlyAddedMap[NewMapStepSize * 2];\r
+\r
+  CurrentMaxMode = *MaxMode;\r
+  Mode           = *CurrentMode;\r
 \r
   while (Index < CurrentMaxMode) {\r
-    if (*NewlyAddedMap == -1) {\r
+    if (*NewMapEntry == -1) {\r
       //\r
       // This mode is not supported any more. Remove it. Special care\r
       // must be taken as this remove will also affect current mode;\r
@@ -1696,6 +2459,7 @@ ConSplitterGetIntersection (
       } else if (Index < *CurrentMode) {\r
         Mode--;\r
       }\r
+\r
       (*MaxMode)--;\r
     } else {\r
       if (CurrentMapEntry != NextMapEntry) {\r
@@ -1706,66 +2470,78 @@ ConSplitterGetIntersection (
     }\r
 \r
     CurrentMapEntry += MapStepSize;\r
-    NewlyAddedMap += NewMapStepSize;\r
+    NewMapEntry     += NewMapStepSize;\r
     Index++;\r
   }\r
 \r
   *CurrentMode = Mode;\r
 \r
-  return ;\r
+  return;\r
 }\r
 \r
-STATIC\r
+/**\r
+  Sync the device's output mode to console splitter's mode list.\r
+\r
+  @param  Private               Text Out Splitter pointer.\r
+  @param  TextOut               Simple Text Output protocol pointer.\r
+\r
+**/\r
 VOID\r
 ConSplitterSyncOutputMode (\r
-  IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,\r
-  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut\r
+  IN  TEXT_OUT_SPLITTER_PRIVATE_DATA   *Private,\r
+  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-Arguments:\r
-  Private - Private data structure.\r
-  TextOut - Text Out Protocol.\r
-Returns:\r
-\r
-  None\r
-\r
---*/\r
 {\r
   INT32                         CurrentMaxMode;\r
   INT32                         Mode;\r
   INT32                         Index;\r
   INT32                         *TextOutModeMap;\r
   INT32                         *MapTable;\r
+  INT32                         QueryMode;\r
   TEXT_OUT_SPLITTER_QUERY_DATA  *TextOutQueryData;\r
   UINTN                         Rows;\r
   UINTN                         Columns;\r
   UINTN                         StepSize;\r
+  EFI_STATUS                    Status;\r
 \r
   //\r
   // Must make sure that current mode won't change even if mode number changes\r
   //\r
-  CurrentMaxMode    = Private->TextOutMode.MaxMode;\r
-  TextOutModeMap    = Private->TextOutModeMap;\r
-  StepSize          = Private->TextOutListCount;\r
-  TextOutQueryData  = Private->TextOutQueryData;\r
+  CurrentMaxMode   = Private->TextOutMode.MaxMode;\r
+  TextOutModeMap   = Private->TextOutModeMap;\r
+  StepSize         = Private->TextOutListCount;\r
+  TextOutQueryData = Private->TextOutQueryData;\r
 \r
   //\r
   // Query all the mode that the newly added TextOut supports\r
   //\r
-  Mode      = 0;\r
-  MapTable  = TextOutModeMap + Private->CurrentNumberOfConsoles;\r
+  Mode     = 0;\r
+  MapTable = TextOutModeMap + Private->CurrentNumberOfConsoles;\r
   while (Mode < TextOut->Mode->MaxMode) {\r
-    TextOut->QueryMode (TextOut, Mode, &Columns, &Rows);\r
+    Status = TextOut->QueryMode (TextOut, Mode, &Columns, &Rows);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      if (Mode == 1) {\r
+        //\r
+        // If mode 1 (80x50) is not supported, make sure mode 1 in TextOutQueryData\r
+        // is clear to 0x0.\r
+        //\r
+        MapTable[StepSize]             = Mode;\r
+        TextOutQueryData[Mode].Columns = 0;\r
+        TextOutQueryData[Mode].Rows    = 0;\r
+      }\r
+\r
+      Mode++;\r
+      continue;\r
+    }\r
 \r
     //\r
-    // Search the QueryData database to see if they intersects\r
+    // Search the intersection map and QueryData database to see if they intersects\r
     //\r
     Index = 0;\r
     while (Index < CurrentMaxMode) {\r
-      if ((TextOutQueryData[Index].Rows == Rows) && (TextOutQueryData[Index].Columns == Columns)) {\r
+      QueryMode = *(TextOutModeMap + Index * StepSize);\r
+      if ((TextOutQueryData[QueryMode].Rows == Rows) && (TextOutQueryData[QueryMode].Columns == Columns)) {\r
         MapTable[Index * StepSize] = Mode;\r
         break;\r
       }\r
@@ -1775,6 +2551,7 @@ Returns:
 \r
     Mode++;\r
   }\r
+\r
   //\r
   // Now search the TextOutModeMap table to find the intersection of supported\r
   // mode between ConSplitter and the newly added device.\r
@@ -1788,26 +2565,20 @@ Returns:
     &Private->TextOutMode.Mode\r
     );\r
 \r
-  return ;\r
+  return;\r
 }\r
 \r
-STATIC\r
+/**\r
+  Sync output device between ConOut and StdErr output.\r
+\r
+  @retval EFI_SUCCESS              Sync implemented successfully.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.\r
+\r
+**/\r
 EFI_STATUS\r
 ConSplitterGetIntersectionBetweenConOutAndStrErr (\r
   VOID\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-Arguments:\r
-\r
-Returns:\r
-\r
-  None\r
-  EFI_OUT_OF_RESOURCES\r
-\r
---*/\r
 {\r
   UINTN                         ConOutNumOfConsoles;\r
   UINTN                         StdErrNumOfConsoles;\r
@@ -1815,10 +2586,14 @@ Returns:
   TEXT_OUT_AND_GOP_DATA         *StdErrTextOutList;\r
   UINTN                         Indexi;\r
   UINTN                         Indexj;\r
-  UINTN                         Rows;\r
-  UINTN                         Columns;\r
+  UINTN                         ConOutRows;\r
+  UINTN                         ConOutColumns;\r
+  UINTN                         StdErrRows;\r
+  UINTN                         StdErrColumns;\r
   INT32                         ConOutMaxMode;\r
   INT32                         StdErrMaxMode;\r
+  INT32                         ConOutMode;\r
+  INT32                         StdErrMode;\r
   INT32                         Mode;\r
   INT32                         Index;\r
   INT32                         *ConOutModeMap;\r
@@ -1827,6 +2602,8 @@ Returns:
   INT32                         *StdErrMapTable;\r
   TEXT_OUT_SPLITTER_QUERY_DATA  *ConOutQueryData;\r
   TEXT_OUT_SPLITTER_QUERY_DATA  *StdErrQueryData;\r
+  UINTN                         ConOutStepSize;\r
+  UINTN                         StdErrStepSize;\r
   BOOLEAN                       FoundTheSameTextOut;\r
   UINTN                         ConOutMapTableSize;\r
   UINTN                         StdErrMapTableSize;\r
@@ -1857,30 +2634,33 @@ Returns:
   if (!FoundTheSameTextOut) {\r
     return EFI_SUCCESS;\r
   }\r
+\r
   //\r
   // Must make sure that current mode won't change even if mode number changes\r
   //\r
-  ConOutMaxMode     = mConOut.TextOutMode.MaxMode;\r
-  ConOutModeMap     = mConOut.TextOutModeMap;\r
-  ConOutQueryData   = mConOut.TextOutQueryData;\r
+  ConOutMaxMode   = mConOut.TextOutMode.MaxMode;\r
+  ConOutModeMap   = mConOut.TextOutModeMap;\r
+  ConOutStepSize  = mConOut.TextOutListCount;\r
+  ConOutQueryData = mConOut.TextOutQueryData;\r
 \r
-  StdErrMaxMode     = mStdErr.TextOutMode.MaxMode;\r
-  StdErrModeMap     = mStdErr.TextOutModeMap;\r
-  StdErrQueryData   = mStdErr.TextOutQueryData;\r
+  StdErrMaxMode   = mStdErr.TextOutMode.MaxMode;\r
+  StdErrModeMap   = mStdErr.TextOutModeMap;\r
+  StdErrStepSize  = mStdErr.TextOutListCount;\r
+  StdErrQueryData = mStdErr.TextOutQueryData;\r
 \r
   //\r
   // Allocate the map table and set the map table's index to -1.\r
   //\r
-  ConOutMapTableSize  = ConOutMaxMode * sizeof (INT32);\r
-  ConOutMapTable      = AllocateZeroPool (ConOutMapTableSize);\r
+  ConOutMapTableSize = ConOutMaxMode * sizeof (INT32);\r
+  ConOutMapTable     = AllocateZeroPool (ConOutMapTableSize);\r
   if (ConOutMapTable == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
   SetMem (ConOutMapTable, ConOutMapTableSize, 0xFF);\r
 \r
-  StdErrMapTableSize  = StdErrMaxMode * sizeof (INT32);\r
-  StdErrMapTable      = AllocateZeroPool (StdErrMapTableSize);\r
+  StdErrMapTableSize = StdErrMaxMode * sizeof (INT32);\r
+  StdErrMapTable     = AllocateZeroPool (StdErrMapTableSize);\r
   if (StdErrMapTable == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
@@ -1889,18 +2669,22 @@ Returns:
 \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
-    // Search the other's QueryData database to see if they intersect\r
+    // Search the intersection map and QueryData database to see if they intersect\r
     //\r
-    Index   = 0;\r
-    Rows    = ConOutQueryData[Mode].Rows;\r
-    Columns = ConOutQueryData[Mode].Columns;\r
+    Index         = 0;\r
+    ConOutMode    = *(ConOutModeMap + Mode * ConOutStepSize);\r
+    ConOutRows    = ConOutQueryData[ConOutMode].Rows;\r
+    ConOutColumns = ConOutQueryData[ConOutMode].Columns;\r
     while (Index < StdErrMaxMode) {\r
-      if ((StdErrQueryData[Index].Rows == Rows) && (StdErrQueryData[Index].Columns == Columns)) {\r
+      StdErrMode    = *(StdErrModeMap + Index * StdErrStepSize);\r
+      StdErrRows    = StdErrQueryData[StdErrMode].Rows;\r
+      StdErrColumns = StdErrQueryData[StdErrMode].Columns;\r
+      if ((StdErrRows == ConOutRows) && (StdErrColumns == ConOutColumns)) {\r
         ConOutMapTable[Mode]  = 1;\r
         StdErrMapTable[Index] = 1;\r
         break;\r
@@ -1911,6 +2695,7 @@ Returns:
 \r
     Mode++;\r
   }\r
+\r
   //\r
   // Now search the TextOutModeMap table to find the intersection of supported\r
   // mode between ConSplitter and the newly added device.\r
@@ -1923,6 +2708,7 @@ Returns:
     &(mConOut.TextOutMode.MaxMode),\r
     &(mConOut.TextOutMode.Mode)\r
     );\r
+\r
   if (mConOut.TextOutMode.Mode < 0) {\r
     mConOut.TextOut.SetMode (&(mConOut.TextOut), 0);\r
   }\r
@@ -1935,6 +2721,7 @@ Returns:
     &(mStdErr.TextOutMode.MaxMode),\r
     &(mStdErr.TextOutMode.Mode)\r
     );\r
+\r
   if (mStdErr.TextOutMode.Mode < 0) {\r
     mStdErr.TextOut.SetMode (&(mStdErr.TextOut), 0);\r
   }\r
@@ -1945,109 +2732,164 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
-STATIC\r
+/**\r
+  Add Graphics Output modes into Consplitter Text Out list.\r
+\r
+  @param  Private               Text Out Splitter pointer.\r
+  @param  GraphicsOutput        Graphics Output protocol pointer.\r
+  @param  UgaDraw               UGA Draw protocol pointer.\r
+\r
+  @retval EFI_SUCCESS           Output mode added successfully.\r
+  @retval other                 Failed to add output mode.\r
+\r
+**/\r
 EFI_STATUS\r
 ConSplitterAddGraphicsOutputMode (\r
   IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private,\r
   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL    *GraphicsOutput,\r
   IN  EFI_UGA_DRAW_PROTOCOL           *UgaDraw\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-Arguments:\r
-\r
-Returns:\r
+{\r
+  EFI_STATUS                            Status;\r
+  UINTN                                 Index;\r
+  UINTN                                 CurrentIndex;\r
+  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Mode;\r
+  UINTN                                 SizeOfInfo;\r
+  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;\r
+  EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE     *CurrentGraphicsOutputMode;\r
+  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *ModeBuffer;\r
+  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *MatchedMode;\r
+  UINTN                                 NumberIndex;\r
+  BOOLEAN                               Match;\r
+  BOOLEAN                               AlreadyExist;\r
+  UINT32                                UgaHorizontalResolution;\r
+  UINT32                                UgaVerticalResolution;\r
+  UINT32                                UgaColorDepth;\r
+  UINT32                                UgaRefreshRate;\r
+\r
+  ASSERT (GraphicsOutput != NULL || UgaDraw != NULL);\r
 \r
-  None\r
+  CurrentGraphicsOutputMode = Private->GraphicsOutput.Mode;\r
 \r
---*/\r
-{\r
-  EFI_STATUS                           Status;\r
-  UINTN                                Index;\r
-  TEXT_OUT_GOP_MODE                    *Mode;\r
-  UINTN                                SizeOfInfo;\r
-  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;\r
-  EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE    *CurrentGraphicsOutputMode;\r
-  TEXT_OUT_GOP_MODE                    *ModeBuffer;\r
-  TEXT_OUT_GOP_MODE                    *MatchedMode;\r
-  UINTN                                NumberIndex;\r
-  BOOLEAN                              Match;\r
+  Index        = 0;\r
+  CurrentIndex = 0;\r
+  Status       = EFI_SUCCESS;\r
 \r
-  if ((GraphicsOutput == NULL) && (UgaDraw == NULL)) {\r
-    return EFI_UNSUPPORTED;\r
+  if (Private->CurrentNumberOfUgaDraw != 0) {\r
+    //\r
+    // If any UGA device has already been added, then there is no need to\r
+    // calculate intersection of display mode of different GOP/UGA device,\r
+    // since only one display mode will be exported (i.e. user-defined mode)\r
+    //\r
+    goto Done;\r
   }\r
 \r
-  CurrentGraphicsOutputMode = Private->GraphicsOutput.Mode;\r
-\r
   if (GraphicsOutput != NULL) {\r
     if (Private->CurrentNumberOfGraphicsOutput == 0) {\r
-        //\r
-        // This is the first Graphics Output device added\r
-        //\r
-        CurrentGraphicsOutputMode->MaxMode = GraphicsOutput->Mode->MaxMode;\r
-        CurrentGraphicsOutputMode->Mode = GraphicsOutput->Mode->Mode;\r
-        CopyMem (CurrentGraphicsOutputMode->Info, GraphicsOutput->Mode->Info, GraphicsOutput->Mode->SizeOfInfo);\r
-        CurrentGraphicsOutputMode->SizeOfInfo = GraphicsOutput->Mode->SizeOfInfo;\r
-        CurrentGraphicsOutputMode->FrameBufferBase = GraphicsOutput->Mode->FrameBufferBase;\r
-        CurrentGraphicsOutputMode->FrameBufferSize = GraphicsOutput->Mode->FrameBufferSize;\r
+      //\r
+      // This is the first Graphics Output device added\r
+      //\r
+      CurrentGraphicsOutputMode->MaxMode = GraphicsOutput->Mode->MaxMode;\r
+      CurrentGraphicsOutputMode->Mode    = GraphicsOutput->Mode->Mode;\r
+      CopyMem (CurrentGraphicsOutputMode->Info, GraphicsOutput->Mode->Info, GraphicsOutput->Mode->SizeOfInfo);\r
+      CurrentGraphicsOutputMode->SizeOfInfo      = GraphicsOutput->Mode->SizeOfInfo;\r
+      CurrentGraphicsOutputMode->FrameBufferBase = GraphicsOutput->Mode->FrameBufferBase;\r
+      CurrentGraphicsOutputMode->FrameBufferSize = GraphicsOutput->Mode->FrameBufferSize;\r
 \r
-        //\r
-        // Allocate resource for the private mode buffer\r
-        //\r
-        ModeBuffer = AllocatePool (sizeof (TEXT_OUT_GOP_MODE) * GraphicsOutput->Mode->MaxMode);\r
-        if (ModeBuffer == NULL) {\r
-          return EFI_OUT_OF_RESOURCES;\r
-        }\r
-        FreePool (Private->GraphicsOutputModeBuffer);\r
-        Private->GraphicsOutputModeBuffer = ModeBuffer;\r
+      //\r
+      // Allocate resource for the private mode buffer\r
+      //\r
+      ModeBuffer = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * GraphicsOutput->Mode->MaxMode);\r
+      if (ModeBuffer == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
 \r
+      FreePool (Private->GraphicsOutputModeBuffer);\r
+      Private->GraphicsOutputModeBuffer = ModeBuffer;\r
+\r
+      //\r
+      // Store all supported display modes to the private mode buffer\r
+      //\r
+      Mode = ModeBuffer;\r
+      for (Index = 0; Index < GraphicsOutput->Mode->MaxMode; Index++) {\r
         //\r
-        // Store all supported display modes to the private mode buffer\r
+        // The Info buffer would be allocated by callee\r
         //\r
-        Mode = ModeBuffer;\r
-        for (Index = 0; Index < GraphicsOutput->Mode->MaxMode; Index++) {\r
-          Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) Index, &SizeOfInfo, &Info);\r
-          if (EFI_ERROR (Status)) {\r
-            return Status;\r
-          }\r
-          Mode->HorizontalResolution = Info->HorizontalResolution;\r
-          Mode->VerticalResolution = Info->VerticalResolution;\r
-          Mode++;\r
-          FreePool (Info);\r
+        Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32)Index, &SizeOfInfo, &Info);\r
+        if (EFI_ERROR (Status)) {\r
+          return Status;\r
         }\r
+\r
+        ASSERT (SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));\r
+        CopyMem (Mode, Info, SizeOfInfo);\r
+        Mode++;\r
+        FreePool (Info);\r
+      }\r
     } else {\r
       //\r
       // Check intersection of display mode\r
       //\r
-      ModeBuffer = AllocatePool (sizeof (TEXT_OUT_GOP_MODE) * CurrentGraphicsOutputMode->MaxMode);\r
+      ModeBuffer = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * CurrentGraphicsOutputMode->MaxMode);\r
       if (ModeBuffer == NULL) {\r
         return EFI_OUT_OF_RESOURCES;\r
       }\r
 \r
       MatchedMode = ModeBuffer;\r
-      Mode = &Private->GraphicsOutputModeBuffer[0];\r
+      Mode        = &Private->GraphicsOutputModeBuffer[0];\r
       for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) {\r
         Match = FALSE;\r
 \r
         for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex++) {\r
-          Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info);\r
+          //\r
+          // The Info buffer would be allocated by callee\r
+          //\r
+          Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32)NumberIndex, &SizeOfInfo, &Info);\r
           if (EFI_ERROR (Status)) {\r
             return Status;\r
           }\r
+\r
           if ((Info->HorizontalResolution == Mode->HorizontalResolution) &&\r
-              (Info->VerticalResolution == Mode->VerticalResolution)){\r
+              (Info->VerticalResolution == Mode->VerticalResolution))\r
+          {\r
+            //\r
+            // If GOP device supports one mode in current mode buffer,\r
+            // it will be added into matched mode buffer\r
+            //\r
             Match = TRUE;\r
             FreePool (Info);\r
             break;\r
           }\r
+\r
           FreePool (Info);\r
         }\r
 \r
         if (Match) {\r
-          CopyMem (MatchedMode, Mode, sizeof (TEXT_OUT_GOP_MODE));\r
-          MatchedMode++;\r
+          AlreadyExist = FALSE;\r
+\r
+          //\r
+          // Check if GOP mode has been in the mode buffer, ModeBuffer = MatchedMode at begin.\r
+          //\r
+          for (Info = ModeBuffer; Info < MatchedMode; Info++) {\r
+            if ((Info->HorizontalResolution == Mode->HorizontalResolution) &&\r
+                (Info->VerticalResolution == Mode->VerticalResolution))\r
+            {\r
+              AlreadyExist = TRUE;\r
+              break;\r
+            }\r
+          }\r
+\r
+          if (!AlreadyExist) {\r
+            CopyMem (MatchedMode, Mode, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));\r
+\r
+            //\r
+            // Physical frame buffer is no longer available, change PixelFormat to PixelBltOnly\r
+            //\r
+            MatchedMode->Version     = 0;\r
+            MatchedMode->PixelFormat = PixelBltOnly;\r
+            ZeroMem (&MatchedMode->PixelInformation, sizeof (EFI_PIXEL_BITMASK));\r
+\r
+            MatchedMode++;\r
+          }\r
         }\r
 \r
         Mode++;\r
@@ -2062,115 +2904,275 @@ Returns:
       //\r
       // Physical frame buffer is no longer available when there are more than one physical GOP devices\r
       //\r
-      CurrentGraphicsOutputMode->MaxMode = (UINT32) (((UINTN) MatchedMode - (UINTN) ModeBuffer) / sizeof (TEXT_OUT_GOP_MODE));\r
+      CurrentGraphicsOutputMode->MaxMode           = (UINT32)(((UINTN)MatchedMode - (UINTN)ModeBuffer) / sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));\r
       CurrentGraphicsOutputMode->Info->PixelFormat = PixelBltOnly;\r
       ZeroMem (&CurrentGraphicsOutputMode->Info->PixelInformation, sizeof (EFI_PIXEL_BITMASK));\r
-      CurrentGraphicsOutputMode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
-      CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) NULL;\r
+      CurrentGraphicsOutputMode->SizeOfInfo      = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
+      CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;\r
       CurrentGraphicsOutputMode->FrameBufferSize = 0;\r
     }\r
 \r
     //\r
-    // Select a prefered Display mode 800x600\r
+    // Graphics console driver can ensure the same mode for all GOP devices\r
     //\r
     for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) {\r
       Mode = &Private->GraphicsOutputModeBuffer[Index];\r
-      if ((Mode->HorizontalResolution == 800) && (Mode->VerticalResolution == 600)) {\r
+      if ((Mode->HorizontalResolution == GraphicsOutput->Mode->Info->HorizontalResolution) &&\r
+          (Mode->VerticalResolution == GraphicsOutput->Mode->Info->VerticalResolution))\r
+      {\r
+        CurrentIndex = Index;\r
         break;\r
       }\r
     }\r
-    //\r
-    // Prefered mode is not found, set to mode 0\r
-    //\r
+\r
     if (Index >= CurrentGraphicsOutputMode->MaxMode) {\r
-      Index = 0;\r
+      //\r
+      // if user defined mode is not found, set to default mode 800x600\r
+      //\r
+      for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) {\r
+        Mode = &Private->GraphicsOutputModeBuffer[Index];\r
+        if ((Mode->HorizontalResolution == 800) && (Mode->VerticalResolution == 600)) {\r
+          CurrentIndex = Index;\r
+          break;\r
+        }\r
+      }\r
     }\r
-\r
-    //\r
-    // Current mode number may need update now, so set it to an invalide mode number\r
+  } else if (UgaDraw != NULL) {\r
     //\r
-    CurrentGraphicsOutputMode->Mode = 0xffff;\r
-  } else {\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
-    // For UGA device, it's inconvenient to retrieve all the supported display modes.\r
-    // To simplify the implementation, only add one resolution(800x600, 32bit color depth) as defined in UEFI spec\r
-    //\r
-    CurrentGraphicsOutputMode->MaxMode = 1;\r
-    CurrentGraphicsOutputMode->Info->Version = 0;\r
-    CurrentGraphicsOutputMode->Info->HorizontalResolution = 800;\r
-    CurrentGraphicsOutputMode->Info->VerticalResolution = 600;\r
-    CurrentGraphicsOutputMode->Info->PixelFormat = PixelBltOnly;\r
-    CurrentGraphicsOutputMode->Info->PixelsPerScanLine = 800;\r
-    CurrentGraphicsOutputMode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
-    CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) NULL;\r
+    UgaDraw->GetMode (\r
+               UgaDraw,\r
+               &UgaHorizontalResolution,\r
+               &UgaVerticalResolution,\r
+               &UgaColorDepth,\r
+               &UgaRefreshRate\r
+               );\r
+\r
+    CurrentGraphicsOutputMode->MaxMode         = 1;\r
+    Info                                       = CurrentGraphicsOutputMode->Info;\r
+    Info->Version                              = 0;\r
+    Info->HorizontalResolution                 = UgaHorizontalResolution;\r
+    Info->VerticalResolution                   = UgaVerticalResolution;\r
+    Info->PixelFormat                          = PixelBltOnly;\r
+    Info->PixelsPerScanLine                    = UgaHorizontalResolution;\r
+    CurrentGraphicsOutputMode->SizeOfInfo      = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);\r
+    CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;\r
     CurrentGraphicsOutputMode->FrameBufferSize = 0;\r
 \r
     //\r
     // Update the private mode buffer\r
     //\r
-    ModeBuffer = &Private->GraphicsOutputModeBuffer[0];\r
-    ModeBuffer->HorizontalResolution = 800;\r
-    ModeBuffer->VerticalResolution   = 600;\r
+    CopyMem (&Private->GraphicsOutputModeBuffer[0], Info, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));\r
 \r
     //\r
-    // Current mode is unknow now, set it to an invalid mode number 0xffff\r
+    // Only mode 0 is available to be set\r
     //\r
-    CurrentGraphicsOutputMode->Mode = 0xffff;\r
-    Index = 0;\r
+    CurrentIndex = 0;\r
+  }\r
+\r
+Done:\r
+\r
+  if (GraphicsOutput != NULL) {\r
+    Private->CurrentNumberOfGraphicsOutput++;\r
+  }\r
+\r
+  if (UgaDraw != NULL) {\r
+    Private->CurrentNumberOfUgaDraw++;\r
   }\r
 \r
   //\r
   // Force GraphicsOutput mode to be set,\r
-  // regardless whether the console is in EfiConsoleControlScreenGraphics or EfiConsoleControlScreenText mode\r
   //\r
-  Private->HardwareNeedsStarting = TRUE;\r
-  Status = Private->GraphicsOutput.SetMode (&Private->GraphicsOutput, (UINT32) Index);\r
 \r
-  Private->CurrentNumberOfGraphicsOutput++;\r
+  Mode = &Private->GraphicsOutputModeBuffer[CurrentIndex];\r
+  if ((GraphicsOutput != NULL) &&\r
+      (Mode->HorizontalResolution == CurrentGraphicsOutputMode->Info->HorizontalResolution) &&\r
+      (Mode->VerticalResolution == CurrentGraphicsOutputMode->Info->VerticalResolution))\r
+  {\r
+    CurrentGraphicsOutputMode->Mode = (UINT32)CurrentIndex;\r
+    if ((Mode->HorizontalResolution != GraphicsOutput->Mode->Info->HorizontalResolution) ||\r
+        (Mode->VerticalResolution != GraphicsOutput->Mode->Info->VerticalResolution))\r
+    {\r
+      //\r
+      // If all existing video device has been set to common mode, only set new GOP device to\r
+      // the common mode\r
+      //\r
+      for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex++) {\r
+        Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32)NumberIndex, &SizeOfInfo, &Info);\r
+        if (EFI_ERROR (Status)) {\r
+          return Status;\r
+        }\r
 \r
-  return Status;\r
-}\r
+        if ((Info->HorizontalResolution == Mode->HorizontalResolution) && (Info->VerticalResolution == Mode->VerticalResolution)) {\r
+          FreePool (Info);\r
+          break;\r
+        }\r
 \r
-EFI_STATUS\r
-ConSplitterTextOutAddDevice (\r
-  IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,\r
-  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut,\r
-  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL       *GraphicsOutput,\r
-  IN  EFI_UGA_DRAW_PROTOCOL              *UgaDraw\r
-  )\r
-/*++\r
+        FreePool (Info);\r
+      }\r
 \r
-Routine Description:\r
+      Status = GraphicsOutput->SetMode (GraphicsOutput, (UINT32)NumberIndex);\r
+    }\r
+  } else {\r
+    //\r
+    // Current mode number may need update now, so set it to an invalid mode number\r
+    //\r
+    CurrentGraphicsOutputMode->Mode = 0xffff;\r
+    //\r
+    // Graphics console can ensure all GOP devices have the same mode which can be taken as current mode.\r
+    //\r
+    Status = Private->GraphicsOutput.SetMode (&Private->GraphicsOutput, (UINT32)CurrentIndex);\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // If user defined mode is not valid for display device, set to the default mode 800x600.\r
+      //\r
+      (Private->GraphicsOutputModeBuffer[0]).HorizontalResolution = 800;\r
+      (Private->GraphicsOutputModeBuffer[0]).VerticalResolution   = 600;\r
+      Status                                                      = Private->GraphicsOutput.SetMode (&Private->GraphicsOutput, 0);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set the current console out mode.\r
+\r
+  This routine will get the current console mode information (column, row)\r
+  from ConsoleOutMode variable and set it; if the variable does not exist,\r
+  set to user defined console mode.\r
+\r
+  @param  Private            Consplitter Text Out pointer.\r
+\r
+**/\r
+VOID\r
+ConsplitterSetConsoleOutMode (\r
+  IN  TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private\r
+  )\r
+{\r
+  UINTN                            Col;\r
+  UINTN                            Row;\r
+  UINTN                            Mode;\r
+  UINTN                            PreferMode;\r
+  UINTN                            BaseMode;\r
+  UINTN                            MaxMode;\r
+  EFI_STATUS                       Status;\r
+  CONSOLE_OUT_MODE                 ModeInfo;\r
+  CONSOLE_OUT_MODE                 MaxModeInfo;\r
+  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;\r
+\r
+  PreferMode = 0xFF;\r
+  BaseMode   = 0xFF;\r
+  TextOut    = &Private->TextOut;\r
+  MaxMode    = (UINTN)(TextOut->Mode->MaxMode);\r
+\r
+  MaxModeInfo.Column = 0;\r
+  MaxModeInfo.Row    = 0;\r
+  ModeInfo.Column    = PcdGet32 (PcdConOutColumn);\r
+  ModeInfo.Row       = PcdGet32 (PcdConOutRow);\r
+\r
+  //\r
+  // To find the prefer mode and basic mode from Text Out mode list\r
+  //\r
+  for (Mode = 0; Mode < MaxMode; Mode++) {\r
+    Status = TextOut->QueryMode (TextOut, Mode, &Col, &Row);\r
+    if (!EFI_ERROR (Status)) {\r
+      if ((ModeInfo.Column != 0) && (ModeInfo.Row != 0)) {\r
+        //\r
+        // Use user defined column and row\r
+        //\r
+        if ((Col == ModeInfo.Column) && (Row == ModeInfo.Row)) {\r
+          PreferMode = Mode;\r
+        }\r
+      } else {\r
+        //\r
+        // If user sets PcdConOutColumn or PcdConOutRow to 0,\r
+        // find and set the highest text mode.\r
+        //\r
+        if ((Col >= MaxModeInfo.Column) && (Row >= MaxModeInfo.Row)) {\r
+          MaxModeInfo.Column = Col;\r
+          MaxModeInfo.Row    = Row;\r
+          PreferMode         = Mode;\r
+        }\r
+      }\r
+\r
+      if ((Col == 80) && (Row == 25)) {\r
+        BaseMode = Mode;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Set prefer mode to Text Out devices.\r
+  //\r
+  Status = TextOut->SetMode (TextOut, PreferMode);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // if current mode setting is failed, default 80x25 mode will be set.\r
+    //\r
+    Status = TextOut->SetMode (TextOut, BaseMode);\r
+    ASSERT (!EFI_ERROR (Status));\r
+\r
+    Status = PcdSet32S (PcdConOutColumn, 80);\r
+    ASSERT (!EFI_ERROR (Status));\r
+    Status = PcdSet32S (PcdConOutRow, 25);\r
+    ASSERT (!EFI_ERROR (Status));\r
+  }\r
 \r
-Arguments:\r
+  return;\r
+}\r
+\r
+/**\r
+  Add Text Output Device in Consplitter Text Output list.\r
 \r
-Returns:\r
+  @param  Private                  Text Out Splitter pointer.\r
+  @param  TextOut                  Simple Text Output protocol pointer.\r
+  @param  GraphicsOutput           Graphics Output protocol pointer.\r
+  @param  UgaDraw                  UGA Draw protocol pointer.\r
 \r
-  None\r
+  @retval EFI_SUCCESS              Text Output Device added successfully.\r
+  @retval EFI_OUT_OF_RESOURCES     Could not grow the buffer size.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ConSplitterTextOutAddDevice (\r
+  IN  TEXT_OUT_SPLITTER_PRIVATE_DATA   *Private,\r
+  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut,\r
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL     *GraphicsOutput,\r
+  IN  EFI_UGA_DRAW_PROTOCOL            *UgaDraw\r
+  )\r
 {\r
-  EFI_STATUS            Status;\r
-  UINTN                 CurrentNumOfConsoles;\r
-  INT32                 CurrentMode;\r
-  INT32                 MaxMode;\r
-  TEXT_OUT_AND_GOP_DATA *TextAndGop;\r
+  EFI_STATUS                            Status;\r
+  UINTN                                 CurrentNumOfConsoles;\r
+  INT32                                 MaxMode;\r
+  UINT32                                UgaHorizontalResolution;\r
+  UINT32                                UgaVerticalResolution;\r
+  UINT32                                UgaColorDepth;\r
+  UINT32                                UgaRefreshRate;\r
+  TEXT_OUT_AND_GOP_DATA                 *TextAndGop;\r
+  UINTN                                 SizeOfInfo;\r
+  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 growbuffer().\r
+  // If the Text Out List is full, enlarge it by calling ConSplitterGrowBuffer().\r
   //\r
   while (CurrentNumOfConsoles >= Private->TextOutListCount) {\r
     Status = ConSplitterGrowBuffer (\r
-              sizeof (TEXT_OUT_AND_GOP_DATA),\r
-              &Private->TextOutListCount,\r
-              (VOID **) &Private->TextOutList\r
-              );\r
+               sizeof (TEXT_OUT_AND_GOP_DATA),\r
+               &Private->TextOutListCount,\r
+               (VOID **)&Private->TextOutList\r
+               );\r
     if (EFI_ERROR (Status)) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
+\r
     //\r
     // Also need to reallocate the TextOutModeMap table\r
     //\r
@@ -2180,23 +3182,11 @@ Returns:
     }\r
   }\r
 \r
-  TextAndGop          = &Private->TextOutList[CurrentNumOfConsoles];\r
+  TextAndGop = &Private->TextOutList[CurrentNumOfConsoles];\r
 \r
-  TextAndGop->TextOut = TextOut;\r
+  TextAndGop->TextOut        = TextOut;\r
   TextAndGop->GraphicsOutput = GraphicsOutput;\r
-  TextAndGop->UgaDraw = UgaDraw;\r
-\r
-  if ((GraphicsOutput == NULL) && (UgaDraw == NULL)) {\r
-    //\r
-    // If No UGA device then use the ConOut device\r
-    //\r
-    TextAndGop->TextOutEnabled = TRUE;\r
-  } else {\r
-    //\r
-    // If UGA device use ConOut device only used if UGA screen is in Text mode\r
-    //\r
-    TextAndGop->TextOutEnabled = (BOOLEAN) (Private->ConsoleOutputMode == EfiConsoleControlScreenText);\r
-  }\r
+  TextAndGop->UgaDraw        = UgaDraw;\r
 \r
   if (CurrentNumOfConsoles == 0) {\r
     //\r
@@ -2216,65 +3206,161 @@ Returns:
   //\r
   ConSplitterGetIntersectionBetweenConOutAndStrErr ();\r
 \r
-  CurrentMode = Private->TextOutMode.Mode;\r
-  MaxMode     = Private->TextOutMode.MaxMode;\r
+  MaxMode = Private->TextOutMode.MaxMode;\r
   ASSERT (MaxMode >= 1);\r
 \r
+  DeviceStatus = EFI_DEVICE_ERROR;\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
-    ConSplitterAddGraphicsOutputMode (Private, GraphicsOutput, UgaDraw);\r
+    DeviceStatus = ConSplitterAddGraphicsOutputMode (Private, GraphicsOutput, UgaDraw);\r
   }\r
 \r
-  if (Private->ConsoleOutputMode == EfiConsoleControlScreenGraphics && GraphicsOutput != NULL) {\r
-    //\r
-    // We just added a new UGA device in graphics mode\r
-    //\r
-    DevNullGopSync (Private, GraphicsOutput, UgaDraw);\r
-  } else if ((CurrentMode >= 0) && ((GraphicsOutput != NULL) || (UgaDraw != NULL)) && (CurrentMode < Private->TextOutMode.MaxMode)) {\r
+  if (FeaturePcdGet (PcdConOutUgaSupport)) {\r
     //\r
-    // The new console supports the same mode of the current console so sync up\r
+    // If UGA is produced by Consplitter\r
     //\r
-    DevNullSyncGopStdOut (Private);\r
-  } else {\r
-    //\r
-    // If ConOut, then set the mode to Mode #0 which us 80 x 25\r
-    //\r
-    Private->TextOut.SetMode (&Private->TextOut, 0);\r
+    if (GraphicsOutput != NULL) {\r
+      Status = GraphicsOutput->QueryMode (GraphicsOutput, GraphicsOutput->Mode->Mode, &SizeOfInfo, &Info);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      ASSERT (SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));\r
+\r
+      UgaHorizontalResolution = Info->HorizontalResolution;\r
+      UgaVerticalResolution   = Info->VerticalResolution;\r
+\r
+      FreePool (Info);\r
+    } else if (UgaDraw != NULL) {\r
+      Status = UgaDraw->GetMode (\r
+                          UgaDraw,\r
+                          &UgaHorizontalResolution,\r
+                          &UgaVerticalResolution,\r
+                          &UgaColorDepth,\r
+                          &UgaRefreshRate\r
+                          );\r
+      if (!EFI_ERROR (Status) && EFI_ERROR (DeviceStatus)) {\r
+        //\r
+        // if GetMode is successfully and UGA device hasn't been set, set it\r
+        //\r
+        Status = ConSplitterUgaDrawSetMode (\r
+                   &Private->UgaDraw,\r
+                   UgaHorizontalResolution,\r
+                   UgaVerticalResolution,\r
+                   UgaColorDepth,\r
+                   UgaRefreshRate\r
+                   );\r
+      }\r
+\r
+      //\r
+      // If GetMode/SetMode is failed, set to 800x600 mode\r
+      //\r
+      if (EFI_ERROR (Status)) {\r
+        Status = ConSplitterUgaDrawSetMode (\r
+                   &Private->UgaDraw,\r
+                   800,\r
+                   600,\r
+                   32,\r
+                   60\r
+                   );\r
+      }\r
+    }\r
   }\r
 \r
-  return Status;\r
-}\r
+  if (((!EFI_ERROR (DeviceStatus)) || (!EFI_ERROR (Status))) &&\r
+      ((Private->CurrentNumberOfGraphicsOutput + Private->CurrentNumberOfUgaDraw) == 1))\r
+  {\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
-EFI_STATUS\r
-ConSplitterTextOutDeleteDevice (\r
-  IN  TEXT_OUT_SPLITTER_PRIVATE_DATA     *Private,\r
-  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *TextOut\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
-Routine Description:\r
+  Private->AddingConOutDevice = FALSE;\r
 \r
-Arguments:\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Remove Text Out Device in Consplitter Text Out list.\r
 \r
-Returns:\r
+  @param  Private                  Text Out Splitter pointer.\r
+  @param  TextOut                  Simple Text Output Pointer protocol pointer.\r
 \r
-  None\r
+  @retval EFI_SUCCESS              Text Out Device removed successfully.\r
+  @retval EFI_NOT_FOUND            No Text Out Device found.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ConSplitterTextOutDeleteDevice (\r
+  IN  TEXT_OUT_SPLITTER_PRIVATE_DATA   *Private,\r
+  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut\r
+  )\r
 {\r
-  INT32                 Index;\r
-  UINTN                 CurrentNumOfConsoles;\r
-  TEXT_OUT_AND_GOP_DATA *TextOutList;\r
-  EFI_STATUS            Status;\r
+  INT32                  Index;\r
+  UINTN                  CurrentNumOfConsoles;\r
+  TEXT_OUT_AND_GOP_DATA  *TextOutList;\r
+  EFI_STATUS             Status;\r
 \r
   //\r
   // Remove the specified text-out device data structure from the Text out List,\r
   // and rearrange the remaining data structures in the Text out List.\r
   //\r
-  CurrentNumOfConsoles  = Private->CurrentNumberOfConsoles;\r
-  Index                 = (INT32) CurrentNumOfConsoles - 1;\r
-  TextOutList           = Private->TextOutList;\r
+  CurrentNumOfConsoles = Private->CurrentNumberOfConsoles;\r
+  Index                = (INT32)CurrentNumOfConsoles - 1;\r
+  TextOutList          = Private->TextOutList;\r
   while (Index >= 0) {\r
     if (TextOutList->TextOut == TextOut) {\r
+      if (TextOutList->UgaDraw != NULL) {\r
+        Private->CurrentNumberOfUgaDraw--;\r
+      }\r
+\r
+      if (TextOutList->GraphicsOutput != NULL) {\r
+        Private->CurrentNumberOfGraphicsOutput--;\r
+      }\r
+\r
       CopyMem (TextOutList, TextOutList + 1, sizeof (TEXT_OUT_AND_GOP_DATA) * Index);\r
       CurrentNumOfConsoles--;\r
       break;\r
@@ -2283,6 +3369,7 @@ Returns:
     Index--;\r
     TextOutList++;\r
   }\r
+\r
   //\r
   // The specified TextOut is not managed by the ConSplitter driver\r
   //\r
@@ -2290,20 +3377,50 @@ Returns:
     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 clear the Dev NULL device\r
+    // If the number of consoles is zero, reset all parameters\r
     //\r
-    Private->CurrentNumberOfConsoles      = 0;\r
-    Private->TextOutMode.MaxMode          = 1;\r
-    Private->TextOutQueryData[0].Columns  = 80;\r
-    Private->TextOutQueryData[0].Rows     = 25;\r
-    DevNullTextOutSetMode (Private, 0);\r
+    Private->CurrentNumberOfConsoles     = 0;\r
+    Private->TextOutMode.MaxMode         = 1;\r
+    Private->TextOutQueryData[0].Columns = 80;\r
+    Private->TextOutQueryData[0].Rows    = 25;\r
+    TextOutSetMode (Private, 0);\r
 \r
     return EFI_SUCCESS;\r
   }\r
+\r
   //\r
-  // Max Mode is realy an intersection of the QueryMode command to all\r
+  // Max Mode is really an intersection of the QueryMode command to all\r
   // devices. So we must copy the QueryMode of the first device to\r
   // QueryData.\r
   //\r
@@ -2324,10 +3441,10 @@ Returns:
   //\r
   // Now add one by one\r
   //\r
-  Index = 1;\r
+  Index                            = 1;\r
   Private->CurrentNumberOfConsoles = 1;\r
   TextOutList++;\r
-  while ((UINTN) Index < CurrentNumOfConsoles) {\r
+  while ((UINTN)Index < CurrentNumOfConsoles) {\r
     ConSplitterSyncOutputMode (Private, TextOutList->TextOut);\r
     Index++;\r
     Private->CurrentNumberOfConsoles++;\r
@@ -2338,384 +3455,730 @@ Returns:
 \r
   return Status;\r
 }\r
-//\r
-// ConSplitter TextIn member functions\r
-//\r
+\r
+/**\r
+  Reset the input device and optionally run diagnostics\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  ExtendedVerification     Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS              The device was reset.\r
+  @retval EFI_DEVICE_ERROR         The device is not functioning properly and could\r
+                                   not be reset.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterTextInReset (\r
   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
   IN  BOOLEAN                         ExtendedVerification\r
   )\r
-/*++\r
-\r
-  Routine Description:\r
-    Reset the input device and optionaly run diagnostics\r
-\r
-  Arguments:\r
-    This                 - Protocol instance pointer.\r
-    ExtendedVerification - Driver may perform diagnostics on reset.\r
-\r
-  Returns:\r
-    EFI_SUCCESS           - The device was reset.\r
-    EFI_DEVICE_ERROR      - The device is not functioning properly and could\r
-                            not be reset.\r
-\r
---*/\r
 {\r
-  EFI_STATUS                    Status;\r
-  EFI_STATUS                    ReturnStatus;\r
-  TEXT_IN_SPLITTER_PRIVATE_DATA *Private;\r
-  UINTN                         Index;\r
+  EFI_STATUS                     Status;\r
+  EFI_STATUS                     ReturnStatus;\r
+  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private;\r
+  UINTN                          Index;\r
 \r
-  Private                       = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
+  Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
 \r
-  Private->KeyEventSignalState  = FALSE;\r
+  Private->KeyEventSignalState = FALSE;\r
 \r
   //\r
   // return the worst status met\r
   //\r
   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {\r
     Status = Private->TextInList[Index]->Reset (\r
-                                          Private->TextInList[Index],\r
-                                          ExtendedVerification\r
-                                          );\r
+                                           Private->TextInList[Index],\r
+                                           ExtendedVerification\r
+                                           );\r
     if (EFI_ERROR (Status)) {\r
       ReturnStatus = Status;\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
+/**\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
-EFIAPI\r
-ConSplitterTextInPrivateReadKeyStroke (\r
-  IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,\r
-  OUT EFI_INPUT_KEY                   *Key\r
+ConSplitterTextInExDequeueKey (\r
+  IN  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private,\r
+  OUT EFI_KEY_DATA                   *KeyData\r
   )\r
-/*++\r
+{\r
+  if (Private->CurrentNumberOfKeys == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\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
-  Routine Description:\r
-    Reads the next keystroke from the input device. The WaitForKey Event can\r
-    be used to test for existance of a keystroke via WaitForEvent () call.\r
+/**\r
+  Reads the next keystroke from the input device. The WaitForKey Event can\r
+  be used to test for existence of a keystroke via WaitForEvent () call.\r
 \r
-  Arguments:\r
-    This   - Protocol instance pointer.\r
-    Key    - Driver may perform diagnostics on reset.\r
+  @param  Private                  Protocol instance pointer.\r
+  @param  Key                      Driver may perform diagnostics on reset.\r
 \r
-  Returns:\r
-    EFI_SUCCESS       - The keystroke information was returned.\r
-    EFI_NOT_READY     - There was no keystroke data availiable.\r
-    EFI_DEVICE_ERROR  - The keydtroke information was not returned due to\r
-                        hardware errors.\r
+  @retval EFI_SUCCESS              The keystroke information was returned.\r
+  @retval EFI_NOT_READY            There was no keystroke data availiable.\r
+  @retval EFI_DEVICE_ERROR         The keydtroke information was not returned due\r
+                                   to hardware errors.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ConSplitterTextInPrivateReadKeyStroke (\r
+  IN  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private,\r
+  OUT EFI_INPUT_KEY                  *Key\r
+  )\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
+\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
+  Key->UnicodeChar = 0;\r
+  Key->ScanCode    = SCAN_NULL;\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
   //\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
-                                          );\r
+                                           Private->TextInList[Index],\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
   return EFI_NOT_READY;\r
 }\r
 \r
-BOOLEAN\r
-ConSpliterConssoleControlStdInLocked (\r
-  VOID\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-  Return TRUE if StdIn is locked. The ConIn device on the virtual handle is\r
-  the only device locked.\r
-\r
-Arguments:\r
-  NONE\r
+/**\r
+  Reads the next keystroke from the input device. The WaitForKey Event can\r
+  be used to test for existence of a keystroke via WaitForEvent () call.\r
 \r
-Returns:\r
-  TRUE  - StdIn locked\r
-  FALSE - StdIn working normally\r
+  @param  This                     Protocol instance pointer.\r
+  @param  Key                      Driver may perform diagnostics on reset.\r
 \r
---*/\r
-{\r
-  return mConIn.PasswordEnabled;\r
-}\r
+  @retval EFI_SUCCESS              The keystroke information was returned.\r
+  @retval EFI_NOT_READY            There was no keystroke data availiable.\r
+  @retval EFI_DEVICE_ERROR         The keydtroke information was not returned due\r
+                                   to hardware errors.\r
 \r
-VOID\r
+**/\r
+EFI_STATUS\r
 EFIAPI\r
-ConSpliterConsoleControlLockStdInEvent (\r
-  IN  EFI_EVENT                       Event,\r
-  IN  VOID                            *Context\r
+ConSplitterTextInReadKeyStroke (\r
+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
+  OUT EFI_INPUT_KEY                   *Key\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-  This timer event will fire when StdIn is locked. It will check the key\r
-  sequence on StdIn to see if it matches the password. Any error in the\r
-  password will cause the check to reset. As long a mConIn.PasswordEnabled is\r
-  TRUE the StdIn splitter will not report any input.\r
-\r
-Arguments:\r
-  (Standard EFI_EVENT_NOTIFY)\r
-\r
-Returns:\r
-  None\r
-\r
---*/\r
 {\r
-  EFI_STATUS    Status;\r
-  EFI_INPUT_KEY Key;\r
-  CHAR16        BackSpaceString[2];\r
-  CHAR16        SpaceString[2];\r
-\r
-  do {\r
-    Status = ConSplitterTextInPrivateReadKeyStroke (&mConIn, &Key);\r
-    if (!EFI_ERROR (Status)) {\r
-      //\r
-      // if it's an ENTER, match password\r
-      //\r
-      if ((Key.UnicodeChar == CHAR_CARRIAGE_RETURN) && (Key.ScanCode == SCAN_NULL)) {\r
-        mConIn.PwdAttempt[mConIn.PwdIndex] = CHAR_NULL;\r
-        if (StrCmp (mConIn.Password, mConIn.PwdAttempt)) {\r
-          //\r
-          // Password not match\r
-          //\r
-          ConSplitterTextOutOutputString (&mConOut.TextOut, (CHAR16 *) L"\n\rPassword not correct\n\r");\r
-          mConIn.PwdIndex = 0;\r
-        } else {\r
-          //\r
-          // Key matches password sequence\r
-          //\r
-          gBS->SetTimer (mConIn.LockEvent, TimerPeriodic, 0);\r
-          mConIn.PasswordEnabled  = FALSE;\r
-          Status                  = EFI_NOT_READY;\r
-        }\r
-      } else if ((Key.UnicodeChar == CHAR_BACKSPACE) && (Key.ScanCode == SCAN_NULL)) {\r
-        //\r
-        // BackSpace met\r
-        //\r
-        if (mConIn.PwdIndex > 0) {\r
-          BackSpaceString[0]  = CHAR_BACKSPACE;\r
-          BackSpaceString[1]  = 0;\r
+  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private;\r
 \r
-          SpaceString[0]      = ' ';\r
-          SpaceString[1]      = 0;\r
+  Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
 \r
-          ConSplitterTextOutOutputString (&mConOut.TextOut, BackSpaceString);\r
-          ConSplitterTextOutOutputString (&mConOut.TextOut, SpaceString);\r
-          ConSplitterTextOutOutputString (&mConOut.TextOut, BackSpaceString);\r
+  Private->KeyEventSignalState = FALSE;\r
 \r
-          mConIn.PwdIndex--;\r
-        }\r
-      } else if ((Key.ScanCode == SCAN_NULL) && (Key.UnicodeChar >= 32)) {\r
-        //\r
-        // If it's not an ENTER, neigher a function key, nor a CTRL-X or ALT-X, record the input\r
-        //\r
-        if (mConIn.PwdIndex < (MAX_STD_IN_PASSWORD - 1)) {\r
-          if (mConIn.PwdIndex == 0) {\r
-            ConSplitterTextOutOutputString (&mConOut.TextOut, (CHAR16 *) L"\n\r");\r
-          }\r
+  //\r
+  // Signal ConnectConIn event on first call in Lazy ConIn mode\r
+  //\r
+  if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {\r
+    DEBUG ((DEBUG_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));\r
+    gBS->SignalEvent (Private->ConnectConInEvent);\r
+    mConInIsConnect = TRUE;\r
+  }\r
 \r
-          ConSplitterTextOutOutputString (&mConOut.TextOut, (CHAR16 *) L"*");\r
-          mConIn.PwdAttempt[mConIn.PwdIndex] = Key.UnicodeChar;\r
-          mConIn.PwdIndex++;\r
-        }\r
-      }\r
-    }\r
-  } while (!EFI_ERROR (Status));\r
+  return ConSplitterTextInPrivateReadKeyStroke (Private, Key);\r
 }\r
 \r
-EFI_STATUS\r
-EFIAPI\r
-ConSpliterConsoleControlLockStdIn (\r
-  IN  EFI_CONSOLE_CONTROL_PROTOCOL    *This,\r
-  IN  CHAR16                          *Password\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-  If Password is NULL unlock the password state variable and set the event\r
-  timer. If the Password is too big return an error. If the Password is valid\r
-  Copy the Password and enable state variable and then arm the periodic timer\r
+/**\r
+  This event aggregates all the events of the ConIn devices in the spliter.\r
 \r
-Arguments:\r
+  If any events of physical ConIn devices are signaled, signal the ConIn\r
+  spliter event. This will cause the calling code to call\r
+  ConSplitterTextInReadKeyStroke ().\r
 \r
-Returns:\r
-  EFI_SUCCESS           - Lock the StdIn device\r
-  EFI_INVALID_PARAMETER - Password is NULL\r
-  EFI_OUT_OF_RESOURCES  - Buffer allocation to store the password fails\r
+  @param  Event                    The Event associated with callback.\r
+  @param  Context                  Context registered when Event was created.\r
 \r
---*/\r
+**/\r
+VOID\r
+EFIAPI\r
+ConSplitterTextInWaitForKey (\r
+  IN  EFI_EVENT  Event,\r
+  IN  VOID       *Context\r
+  )\r
 {\r
-  if (Password == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+  EFI_STATUS                     Status;\r
+  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private;\r
+  UINTN                          Index;\r
+\r
+  Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *)Context;\r
 \r
-  if (StrLen (Password) >= MAX_STD_IN_PASSWORD) {\r
+  if (Private->KeyEventSignalState) {\r
     //\r
-    // Currently have a max password size\r
+    // If KeyEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke()\r
     //\r
-    return EFI_OUT_OF_RESOURCES;\r
+    gBS->SignalEvent (Event);\r
+    return;\r
   }\r
+\r
   //\r
-  // Save the password, initialize state variables and arm event timer\r
+  // If any physical console input device has key input, signal the event.\r
   //\r
-  StrCpy (mConIn.Password, Password);\r
-  mConIn.PasswordEnabled  = TRUE;\r
-  mConIn.PwdIndex         = 0;\r
-  gBS->SetTimer (mConIn.LockEvent, TimerPeriodic, (10000 * 25));\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-ConSplitterTextInReadKeyStroke (\r
-  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
-  OUT EFI_INPUT_KEY                   *Key\r
+  for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\r
+    Status = gBS->CheckEvent (Private->TextInList[Index]->WaitForKey);\r
+    if (!EFI_ERROR (Status)) {\r
+      gBS->SignalEvent (Event);\r
+      Private->KeyEventSignalState = TRUE;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Test if the key has been registered on input device.\r
+\r
+  @param  RegsiteredData           A pointer to a buffer that is filled in with the\r
+                                   keystroke state data for the key that was\r
+                                   registered.\r
+  @param  InputData                A pointer to a buffer that is filled in with the\r
+                                   keystroke state data for the key that was\r
+                                   pressed.\r
+\r
+  @retval TRUE                     Key be pressed matches a registered key.\r
+  @retval FALSE                    Match failed.\r
+\r
+**/\r
+BOOLEAN\r
+IsKeyRegistered (\r
+  IN EFI_KEY_DATA  *RegsiteredData,\r
+  IN EFI_KEY_DATA  *InputData\r
   )\r
-/*++\r
+{\r
+  ASSERT (RegsiteredData != NULL && InputData != NULL);\r
 \r
-  Routine Description:\r
-    Reads the next keystroke from the input device. The WaitForKey Event can\r
-    be used to test for existance of a keystroke via WaitForEvent () call.\r
-    If the ConIn is password locked make it look like no keystroke is availible\r
+  if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||\r
+      (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar))\r
+  {\r
+    return FALSE;\r
+  }\r
 \r
-  Arguments:\r
-    This   - Protocol instance pointer.\r
-    Key    - Driver may perform diagnostics on reset.\r
+  //\r
+  // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.\r
+  //\r
+  if ((RegsiteredData->KeyState.KeyShiftState != 0) &&\r
+      (RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState))\r
+  {\r
+    return FALSE;\r
+  }\r
+\r
+  if ((RegsiteredData->KeyState.KeyToggleState != 0) &&\r
+      (RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState))\r
+  {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Reset the input device and optionally run diagnostics\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  ExtendedVerification     Driver may perform diagnostics on reset.\r
 \r
-  Returns:\r
-    EFI_SUCCESS       - The keystroke information was returned.\r
-    EFI_NOT_READY     - There was no keystroke data availiable.\r
-    EFI_DEVICE_ERROR  - The keydtroke information was not returned due to\r
-                        hardware errors.\r
+  @retval EFI_SUCCESS              The device was reset.\r
+  @retval EFI_DEVICE_ERROR         The device is not functioning properly and could\r
+                                   not be reset.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ConSplitterTextInResetEx (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN BOOLEAN                            ExtendedVerification\r
+  )\r
 {\r
-  TEXT_IN_SPLITTER_PRIVATE_DATA *Private;\r
+  EFI_STATUS                     Status;\r
+  EFI_STATUS                     ReturnStatus;\r
+  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private;\r
+  UINTN                          Index;\r
 \r
-  Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
-  if (Private->PasswordEnabled) {\r
+  Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  Private->KeyEventSignalState = FALSE;\r
+\r
+  //\r
+  // return the worst status met\r
+  //\r
+  for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfExConsoles; Index++) {\r
+    Status = Private->TextInExList[Index]->Reset (\r
+                                             Private->TextInExList[Index],\r
+                                             ExtendedVerification\r
+                                             );\r
+    if (EFI_ERROR (Status)) {\r
+      ReturnStatus = Status;\r
+    }\r
+  }\r
+\r
+  if (!EFI_ERROR (ReturnStatus)) {\r
+    ToggleStateSyncReInitialization (Private);\r
     //\r
-    // If StdIn Locked return not ready\r
+    // Empty the key queue.\r
     //\r
-    return EFI_NOT_READY;\r
+    Private->CurrentNumberOfKeys = 0;\r
   }\r
 \r
+  return ReturnStatus;\r
+}\r
+\r
+/**\r
+  Reads the next keystroke from the input device. The WaitForKey Event can\r
+  be used to test for existence of a keystroke via WaitForEvent () call.\r
+\r
+  @param  This                     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
+\r
+  @retval EFI_SUCCESS              The keystroke information was returned.\r
+  @retval EFI_NOT_READY            There was no keystroke data availiable.\r
+  @retval EFI_DEVICE_ERROR         The keystroke information was not returned due\r
+                                   to hardware errors.\r
+  @retval EFI_INVALID_PARAMETER    KeyData is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ConSplitterTextInReadKeyStrokeEx (\r
+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  OUT EFI_KEY_DATA                       *KeyData\r
+  )\r
+{\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
+  if (KeyData == NULL) {\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
-  return ConSplitterTextInPrivateReadKeyStroke (Private, Key);\r
+  //\r
+  // Signal ConnectConIn event on first call in Lazy ConIn mode\r
+  //\r
+  if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {\r
+    DEBUG ((DEBUG_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));\r
+    gBS->SignalEvent (Private->ConnectConInEvent);\r
+    mConInIsConnect = TRUE;\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
+  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
+    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
+\r
+    if ((CurrentKeyData.KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != 0) {\r
+      KeyState.KeyToggleState |= CurrentKeyData.KeyState.KeyToggleState;\r
+    }\r
+\r
+    if (!EFI_ERROR (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
+      {\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
-VOID\r
+/**\r
+  Set certain state for the input device.\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  KeyToggleState           A pointer to the EFI_KEY_TOGGLE_STATE to set the\r
+                                   state for the input device.\r
+\r
+  @retval EFI_SUCCESS              The device state was set successfully.\r
+  @retval EFI_DEVICE_ERROR         The device is not functioning correctly and\r
+                                   could not have the setting adjusted.\r
+  @retval EFI_UNSUPPORTED          The device does not have the ability to set its\r
+                                   state.\r
+  @retval EFI_INVALID_PARAMETER    KeyToggleState is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
 EFIAPI\r
-ConSplitterTextInWaitForKey (\r
-  IN  EFI_EVENT                       Event,\r
-  IN  VOID                            *Context\r
+ConSplitterTextInSetState (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_KEY_TOGGLE_STATE               *KeyToggleState\r
   )\r
-/*++\r
+{\r
+  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private;\r
+  EFI_STATUS                     Status;\r
+  UINTN                          Index;\r
+  EFI_KEY_TOGGLE_STATE           PhysicalKeyToggleState;\r
 \r
-Routine Description:\r
-  This event agregates all the events of the ConIn devices in the spliter.\r
-  If the ConIn is password locked then return.\r
-  If any events of physical ConIn devices are signaled, signal the ConIn\r
-  spliter event. This will cause the calling code to call\r
-  ConSplitterTextInReadKeyStroke ().\r
+  if (KeyToggleState == NULL) {\r
+    return EFI_INVALID_PARAMETER;\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
+  for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {\r
+    Status = Private->TextInExList[Index]->SetState (\r
+                                             Private->TextInExList[Index],\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
-Arguments:\r
-  Event   - The Event assoicated with callback.\r
-  Context - Context registered when Event was created.\r
+  return EFI_SUCCESS;\r
+}\r
 \r
-Returns:\r
-  None\r
+/**\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\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. 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
+  @retval EFI_SUCCESS              The notification function was registered\r
+                                   successfully.\r
+  @retval EFI_OUT_OF_RESOURCES     Unable to allocate resources for necessary data\r
+                                   structures.\r
+  @retval EFI_INVALID_PARAMETER    KeyData or KeyNotificationFunction or NotifyHandle is NULL.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ConSplitterTextInRegisterKeyNotify (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_KEY_DATA                       *KeyData,\r
+  IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,\r
+  OUT VOID                              **NotifyHandle\r
+  )\r
 {\r
-  EFI_STATUS                    Status;\r
-  TEXT_IN_SPLITTER_PRIVATE_DATA *Private;\r
-  UINTN                         Index;\r
+  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private;\r
+  EFI_STATUS                     Status;\r
+  UINTN                          Index;\r
+  TEXT_IN_EX_SPLITTER_NOTIFY     *NewNotify;\r
+  LIST_ENTRY                     *Link;\r
+  TEXT_IN_EX_SPLITTER_NOTIFY     *CurrentNotify;\r
 \r
-  Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context;\r
-  if (Private->PasswordEnabled) {\r
-    //\r
-    // If StdIn Locked return not ready\r
-    //\r
-    return ;\r
+  if ((KeyData == NULL) || (NotifyHandle == NULL) || (KeyNotificationFunction == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
+\r
   //\r
-  // if KeyEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke()\r
+  // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.\r
   //\r
-  if (Private->KeyEventSignalState) {\r
-    gBS->SignalEvent (Event);\r
-    return ;\r
+  for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {\r
+    CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);\r
+    if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {\r
+      if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {\r
+        *NotifyHandle = CurrentNotify;\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
   }\r
+\r
   //\r
-  // if any physical console input device has key input, signal the event.\r
+  // Allocate resource to save the notification function\r
   //\r
-  for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\r
-    Status = gBS->CheckEvent (Private->TextInList[Index]->WaitForKey);\r
-    if (!EFI_ERROR (Status)) {\r
-      gBS->SignalEvent (Event);\r
-      Private->KeyEventSignalState = TRUE;\r
+  NewNotify = (TEXT_IN_EX_SPLITTER_NOTIFY *)AllocateZeroPool (sizeof (TEXT_IN_EX_SPLITTER_NOTIFY));\r
+  if (NewNotify == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NewNotify->NotifyHandleList = (VOID **)AllocateZeroPool (sizeof (VOID *) *  Private->TextInExListCount);\r
+  if (NewNotify->NotifyHandleList == NULL) {\r
+    gBS->FreePool (NewNotify);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NewNotify->Signature         = TEXT_IN_EX_SPLITTER_NOTIFY_SIGNATURE;\r
+  NewNotify->KeyNotificationFn = KeyNotificationFunction;\r
+  CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));\r
+\r
+  //\r
+  // Return the wrong status of registering key notify of\r
+  // physical console input device if meet problems\r
+  //\r
+  for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {\r
+    Status = Private->TextInExList[Index]->RegisterKeyNotify (\r
+                                             Private->TextInExList[Index],\r
+                                             KeyData,\r
+                                             KeyNotificationFunction,\r
+                                             &NewNotify->NotifyHandleList[Index]\r
+                                             );\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Un-register the key notify on all physical console input devices\r
+      //\r
+      while (Index-- != 0) {\r
+        Private->TextInExList[Index]->UnregisterKeyNotify (\r
+                                        Private->TextInExList[Index],\r
+                                        NewNotify->NotifyHandleList[Index]\r
+                                        );\r
+      }\r
+\r
+      gBS->FreePool (NewNotify->NotifyHandleList);\r
+      gBS->FreePool (NewNotify);\r
+      return Status;\r
     }\r
   }\r
+\r
+  InsertTailList (&Private->NotifyList, &NewNotify->NotifyEntry);\r
+\r
+  *NotifyHandle = NewNotify;\r
+\r
+  return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Remove a registered notification function from a particular keystroke.\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  NotificationHandle       The handle of the notification function being\r
+                                   unregistered.\r
+\r
+  @retval EFI_SUCCESS              The notification function was unregistered\r
+                                   successfully.\r
+  @retval EFI_INVALID_PARAMETER    The NotificationHandle is invalid.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
-ConSplitterSimplePointerReset (\r
-  IN  EFI_SIMPLE_POINTER_PROTOCOL     *This,\r
-  IN  BOOLEAN                         ExtendedVerification\r
+ConSplitterTextInUnregisterKeyNotify (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN VOID                               *NotificationHandle\r
   )\r
-/*++\r
+{\r
+  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private;\r
+  UINTN                          Index;\r
+  TEXT_IN_EX_SPLITTER_NOTIFY     *CurrentNotify;\r
+  LIST_ENTRY                     *Link;\r
 \r
-  Routine Description:\r
-    Reset the input device and optionaly run diagnostics\r
+  if (NotificationHandle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
 \r
-  Arguments:\r
-    This                 - Protocol instance pointer.\r
-    ExtendedVerification - Driver may perform diagnostics on reset.\r
+  for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {\r
+    CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link);\r
+    if (CurrentNotify == NotificationHandle) {\r
+      for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {\r
+        Private->TextInExList[Index]->UnregisterKeyNotify (\r
+                                        Private->TextInExList[Index],\r
+                                        CurrentNotify->NotifyHandleList[Index]\r
+                                        );\r
+      }\r
 \r
-  Returns:\r
-    EFI_SUCCESS           - The device was reset.\r
-    EFI_DEVICE_ERROR      - The device is not functioning properly and could\r
-                            not be reset.\r
+      RemoveEntryList (&CurrentNotify->NotifyEntry);\r
 \r
---*/\r
+      gBS->FreePool (CurrentNotify->NotifyHandleList);\r
+      gBS->FreePool (CurrentNotify);\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  //\r
+  // NotificationHandle is not found in database\r
+  //\r
+  return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+/**\r
+  Reset the input device and optionally run diagnostics\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  ExtendedVerification     Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS              The device was reset.\r
+  @retval EFI_DEVICE_ERROR         The device is not functioning properly and could\r
+                                   not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ConSplitterSimplePointerReset (\r
+  IN  EFI_SIMPLE_POINTER_PROTOCOL  *This,\r
+  IN  BOOLEAN                      ExtendedVerification\r
+  )\r
 {\r
-  EFI_STATUS                    Status;\r
-  EFI_STATUS                    ReturnStatus;\r
-  TEXT_IN_SPLITTER_PRIVATE_DATA *Private;\r
-  UINTN                         Index;\r
+  EFI_STATUS                     Status;\r
+  EFI_STATUS                     ReturnStatus;\r
+  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private;\r
+  UINTN                          Index;\r
 \r
-  Private                         = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This);\r
+  Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This);\r
 \r
-  Private->InputEventSignalState  = FALSE;\r
+  Private->InputEventSignalState = FALSE;\r
 \r
   if (Private->CurrentNumberOfPointers == 0) {\r
     return EFI_SUCCESS;\r
   }\r
+\r
   //\r
   // return the worst status met\r
   //\r
@@ -2732,41 +4195,36 @@ ConSplitterSimplePointerReset (
   return ReturnStatus;\r
 }\r
 \r
-STATIC\r
+/**\r
+  Reads the next keystroke from the input device. The WaitForKey Event can\r
+  be used to test for existence of a keystroke via WaitForEvent () call.\r
+\r
+  @param  Private                  Protocol instance pointer.\r
+  @param  State                    The state information of simple pointer device.\r
+\r
+  @retval EFI_SUCCESS              The keystroke information was returned.\r
+  @retval EFI_NOT_READY            There was no keystroke data availiable.\r
+  @retval EFI_DEVICE_ERROR         The keydtroke information was not returned due\r
+                                   to hardware errors.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterSimplePointerPrivateGetState (\r
-  IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,\r
-  IN OUT EFI_SIMPLE_POINTER_STATE     *State\r
+  IN  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private,\r
+  IN OUT EFI_SIMPLE_POINTER_STATE    *State\r
   )\r
-/*++\r
-\r
-  Routine Description:\r
-    Reads the next keystroke from the input device. The WaitForKey Event can\r
-    be used to test for existance of a keystroke via WaitForEvent () call.\r
-\r
-  Arguments:\r
-    This   - Protocol instance pointer.\r
-    State  -\r
-\r
-  Returns:\r
-    EFI_SUCCESS       - The keystroke information was returned.\r
-    EFI_NOT_READY     - There was no keystroke data availiable.\r
-    EFI_DEVICE_ERROR  - The keydtroke information was not returned due to\r
-                        hardware errors.\r
-\r
---*/\r
 {\r
   EFI_STATUS                Status;\r
   EFI_STATUS                ReturnStatus;\r
   UINTN                     Index;\r
   EFI_SIMPLE_POINTER_STATE  CurrentState;\r
 \r
-  State->RelativeMovementX  = 0;\r
-  State->RelativeMovementY  = 0;\r
-  State->RelativeMovementZ  = 0;\r
-  State->LeftButton         = FALSE;\r
-  State->RightButton        = FALSE;\r
+  State->RelativeMovementX = 0;\r
+  State->RelativeMovementY = 0;\r
+  State->RelativeMovementZ = 0;\r
+  State->LeftButton        = FALSE;\r
+  State->RightButton       = FALSE;\r
 \r
   //\r
   // if no physical console input device exists, return EFI_NOT_READY;\r
@@ -2774,35 +4232,277 @@ ConSplitterSimplePointerPrivateGetState (
   // return the key and EFI_SUCCESS.\r
   //\r
   ReturnStatus = EFI_NOT_READY;\r
-  for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {\r
-\r
-    Status = Private->PointerList[Index]->GetState (\r
-                                            Private->PointerList[Index],\r
-                                            &CurrentState\r
-                                            );\r
+  for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {\r
+    Status = Private->PointerList[Index]->GetState (\r
+                                            Private->PointerList[Index],\r
+                                            &CurrentState\r
+                                            );\r
+    if (!EFI_ERROR (Status)) {\r
+      if (ReturnStatus == EFI_NOT_READY) {\r
+        ReturnStatus = EFI_SUCCESS;\r
+      }\r
+\r
+      if (CurrentState.LeftButton) {\r
+        State->LeftButton = TRUE;\r
+      }\r
+\r
+      if (CurrentState.RightButton) {\r
+        State->RightButton = TRUE;\r
+      }\r
+\r
+      if ((CurrentState.RelativeMovementX != 0) && (Private->PointerList[Index]->Mode->ResolutionX != 0)) {\r
+        State->RelativeMovementX += (CurrentState.RelativeMovementX * (INT32)Private->SimplePointerMode.ResolutionX) / (INT32)Private->PointerList[Index]->Mode->ResolutionX;\r
+      }\r
+\r
+      if ((CurrentState.RelativeMovementY != 0) && (Private->PointerList[Index]->Mode->ResolutionY != 0)) {\r
+        State->RelativeMovementY += (CurrentState.RelativeMovementY * (INT32)Private->SimplePointerMode.ResolutionY) / (INT32)Private->PointerList[Index]->Mode->ResolutionY;\r
+      }\r
+\r
+      if ((CurrentState.RelativeMovementZ != 0) && (Private->PointerList[Index]->Mode->ResolutionZ != 0)) {\r
+        State->RelativeMovementZ += (CurrentState.RelativeMovementZ * (INT32)Private->SimplePointerMode.ResolutionZ) / (INT32)Private->PointerList[Index]->Mode->ResolutionZ;\r
+      }\r
+    } else if (Status == EFI_DEVICE_ERROR) {\r
+      ReturnStatus = EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+  return ReturnStatus;\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
+\r
+  @param  This                     A pointer to protocol instance.\r
+  @param  State                    A pointer to state information on the pointer device\r
+\r
+  @retval EFI_SUCCESS              The keystroke information was returned in State.\r
+  @retval EFI_NOT_READY            There was no keystroke data availiable.\r
+  @retval EFI_DEVICE_ERROR         The keydtroke information was not returned due\r
+                                   to hardware errors.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ConSplitterSimplePointerGetState (\r
+  IN  EFI_SIMPLE_POINTER_PROTOCOL  *This,\r
+  IN OUT EFI_SIMPLE_POINTER_STATE  *State\r
+  )\r
+{\r
+  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private;\r
+\r
+  Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This);\r
+\r
+  Private->InputEventSignalState = FALSE;\r
+\r
+  return ConSplitterSimplePointerPrivateGetState (Private, State);\r
+}\r
+\r
+/**\r
+  This event aggregates all the events of the ConIn devices in the spliter.\r
+  If any events of physical ConIn devices are signaled, signal the ConIn\r
+  spliter event. This will cause the calling code to call\r
+  ConSplitterTextInReadKeyStroke ().\r
+\r
+  @param  Event                    The Event associated with callback.\r
+  @param  Context                  Context registered when Event was created.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ConSplitterSimplePointerWaitForInput (\r
+  IN  EFI_EVENT  Event,\r
+  IN  VOID       *Context\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private;\r
+  UINTN                          Index;\r
+\r
+  Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *)Context;\r
+\r
+  //\r
+  // if InputEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke()\r
+  //\r
+  if (Private->InputEventSignalState) {\r
+    gBS->SignalEvent (Event);\r
+    return;\r
+  }\r
+\r
+  //\r
+  // if any physical console input device has key input, signal the event.\r
+  //\r
+  for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {\r
+    Status = gBS->CheckEvent (Private->PointerList[Index]->WaitForInput);\r
+    if (!EFI_ERROR (Status)) {\r
+      gBS->SignalEvent (Event);\r
+      Private->InputEventSignalState = TRUE;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Resets the pointer device hardware.\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  ExtendedVerification     Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS              The device was reset.\r
+  @retval EFI_DEVICE_ERROR         The device is not functioning correctly and\r
+                                   could not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ConSplitterAbsolutePointerReset (\r
+  IN EFI_ABSOLUTE_POINTER_PROTOCOL  *This,\r
+  IN BOOLEAN                        ExtendedVerification\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  EFI_STATUS                     ReturnStatus;\r
+  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private;\r
+  UINTN                          Index;\r
+\r
+  Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS (This);\r
+\r
+  Private->AbsoluteInputEventSignalState = FALSE;\r
+\r
+  if (Private->CurrentNumberOfAbsolutePointers == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // return the worst status met\r
+  //\r
+  for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {\r
+    Status = Private->AbsolutePointerList[Index]->Reset (\r
+                                                    Private->AbsolutePointerList[Index],\r
+                                                    ExtendedVerification\r
+                                                    );\r
+    if (EFI_ERROR (Status)) {\r
+      ReturnStatus = Status;\r
+    }\r
+  }\r
+\r
+  return ReturnStatus;\r
+}\r
+\r
+/**\r
+  Retrieves the current state of a pointer device.\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  State                    A pointer to the state information on the\r
+                                   pointer device.\r
+\r
+  @retval EFI_SUCCESS              The state of the pointer device was returned in\r
+                                   State..\r
+  @retval EFI_NOT_READY            The state of the pointer device has not changed\r
+                                   since the last call to GetState().\r
+  @retval EFI_DEVICE_ERROR         A device error occurred while attempting to\r
+                                   retrieve the pointer device's current state.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ConSplitterAbsolutePointerGetState (\r
+  IN EFI_ABSOLUTE_POINTER_PROTOCOL   *This,\r
+  IN OUT EFI_ABSOLUTE_POINTER_STATE  *State\r
+  )\r
+{\r
+  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private;\r
+  EFI_STATUS                     Status;\r
+  EFI_STATUS                     ReturnStatus;\r
+  UINTN                          Index;\r
+  EFI_ABSOLUTE_POINTER_STATE     CurrentState;\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
+  Private->AbsoluteInputEventSignalState = FALSE;\r
+\r
+  State->CurrentX      = 0;\r
+  State->CurrentY      = 0;\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
+  // return the state and EFI_SUCCESS.\r
+  //\r
+  ReturnStatus = EFI_NOT_READY;\r
+  for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {\r
+    Status = Private->AbsolutePointerList[Index]->GetState (\r
+                                                    Private->AbsolutePointerList[Index],\r
+                                                    &CurrentState\r
+                                                    );\r
     if (!EFI_ERROR (Status)) {\r
       if (ReturnStatus == EFI_NOT_READY) {\r
         ReturnStatus = EFI_SUCCESS;\r
       }\r
 \r
-      if (CurrentState.LeftButton) {\r
-        State->LeftButton = TRUE;\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
-      if (CurrentState.RightButton) {\r
-        State->RightButton = TRUE;\r
-      }\r
+      State->ActiveButtons = CurrentState.ActiveButtons;\r
 \r
-      if (CurrentState.RelativeMovementX != 0 && Private->PointerList[Index]->Mode->ResolutionX != 0) {\r
-        State->RelativeMovementX += (CurrentState.RelativeMovementX * (INT32) Private->SimplePointerMode.ResolutionX) / (INT32) Private->PointerList[Index]->Mode->ResolutionX;\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 (CurrentState.RelativeMovementY != 0 && Private->PointerList[Index]->Mode->ResolutionY != 0) {\r
-        State->RelativeMovementY += (CurrentState.RelativeMovementY * (INT32) Private->SimplePointerMode.ResolutionY) / (INT32) Private->PointerList[Index]->Mode->ResolutionY;\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 (CurrentState.RelativeMovementZ != 0 && Private->PointerList[Index]->Mode->ResolutionZ != 0) {\r
-        State->RelativeMovementZ += (CurrentState.RelativeMovementZ * (INT32) Private->SimplePointerMode.ResolutionZ) / (INT32) Private->PointerList[Index]->Mode->ResolutionZ;\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
     } else if (Status == EFI_DEVICE_ERROR) {\r
       ReturnStatus = EFI_DEVICE_ERROR;\r
@@ -2812,123 +4512,68 @@ ConSplitterSimplePointerPrivateGetState (
   return ReturnStatus;\r
 }\r
 \r
-EFI_STATUS\r
-EFIAPI\r
-ConSplitterSimplePointerGetState (\r
-  IN  EFI_SIMPLE_POINTER_PROTOCOL     *This,\r
-  IN OUT EFI_SIMPLE_POINTER_STATE     *State\r
-  )\r
-/*++\r
-\r
-  Routine Description:\r
-    Reads the next keystroke from the input device. The WaitForKey Event can\r
-    be used to test for existance of a keystroke via WaitForEvent () call.\r
-    If the ConIn is password locked make it look like no keystroke is availible\r
-\r
-  Arguments:\r
-    This   - Protocol instance pointer.\r
-    State  -\r
-\r
-  Returns:\r
-    EFI_SUCCESS       - The keystroke information was returned.\r
-    EFI_NOT_READY     - There was no keystroke data availiable.\r
-    EFI_DEVICE_ERROR  - The keydtroke information was not returned due to\r
-                        hardware errors.\r
-\r
---*/\r
-{\r
-  TEXT_IN_SPLITTER_PRIVATE_DATA *Private;\r
-\r
-  Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This);\r
-  if (Private->PasswordEnabled) {\r
-    //\r
-    // If StdIn Locked return not ready\r
-    //\r
-    return EFI_NOT_READY;\r
-  }\r
-\r
-  Private->InputEventSignalState = FALSE;\r
+/**\r
+  This event aggregates all the events of the pointer devices in the splitter.\r
+  If any events of physical pointer devices are signaled, signal the pointer\r
+  splitter event. This will cause the calling code to call\r
+  ConSplitterAbsolutePointerGetState ().\r
 \r
-  return ConSplitterSimplePointerPrivateGetState (Private, State);\r
-}\r
+  @param  Event                    The Event associated with callback.\r
+  @param  Context                  Context registered when Event was created.\r
 \r
+**/\r
 VOID\r
 EFIAPI\r
-ConSplitterSimplePointerWaitForInput (\r
-  IN  EFI_EVENT                       Event,\r
-  IN  VOID                            *Context\r
+ConSplitterAbsolutePointerWaitForInput (\r
+  IN  EFI_EVENT  Event,\r
+  IN  VOID       *Context\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-  This event agregates all the events of the ConIn devices in the spliter.\r
-  If the ConIn is password locked then return.\r
-  If any events of physical ConIn devices are signaled, signal the ConIn\r
-  spliter event. This will cause the calling code to call\r
-  ConSplitterTextInReadKeyStroke ().\r
-\r
-Arguments:\r
-  Event   - The Event assoicated with callback.\r
-  Context - Context registered when Event was created.\r
-\r
-Returns:\r
-  None\r
-\r
---*/\r
 {\r
-  EFI_STATUS                    Status;\r
-  TEXT_IN_SPLITTER_PRIVATE_DATA *Private;\r
-  UINTN                         Index;\r
+  EFI_STATUS                     Status;\r
+  TEXT_IN_SPLITTER_PRIVATE_DATA  *Private;\r
+  UINTN                          Index;\r
 \r
-  Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context;\r
-  if (Private->PasswordEnabled) {\r
-    //\r
-    // If StdIn Locked return not ready\r
-    //\r
-    return ;\r
-  }\r
+  Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *)Context;\r
 \r
   //\r
-  // if InputEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke()\r
+  // if AbsoluteInputEventSignalState is flagged before,\r
+  // and not cleared by Reset() or GetState(), signal it\r
   //\r
-  if (Private->InputEventSignalState) {\r
+  if (Private->AbsoluteInputEventSignalState) {\r
     gBS->SignalEvent (Event);\r
-    return ;\r
+    return;\r
   }\r
+\r
   //\r
   // if any physical console input device has key input, signal the event.\r
   //\r
-  for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) {\r
-    Status = gBS->CheckEvent (Private->PointerList[Index]->WaitForInput);\r
+  for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) {\r
+    Status = gBS->CheckEvent (Private->AbsolutePointerList[Index]->WaitForInput);\r
     if (!EFI_ERROR (Status)) {\r
       gBS->SignalEvent (Event);\r
-      Private->InputEventSignalState = TRUE;\r
+      Private->AbsoluteInputEventSignalState = TRUE;\r
     }\r
   }\r
 }\r
 \r
+/**\r
+  Reset the text output device hardware and optionally run diagnostics\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  ExtendedVerification     Driver may perform more exhaustive verification\r
+                                   operation of the device during reset.\r
+\r
+  @retval EFI_SUCCESS              The text output device was reset.\r
+  @retval EFI_DEVICE_ERROR         The text output device is not functioning\r
+                                   correctly and could not be reset.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterTextOutReset (\r
-  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,\r
-  IN  BOOLEAN                            ExtendedVerification\r
+  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,\r
+  IN  BOOLEAN                          ExtendedVerification\r
   )\r
-/*++\r
-\r
-  Routine Description:\r
-    Reset the text output device hardware and optionaly run diagnostics\r
-\r
-  Arguments:\r
-    This                 - Protocol instance pointer.\r
-    ExtendedVerification - Driver may perform more exhaustive verfication\r
-                           operation of the device during reset.\r
-\r
-  Returns:\r
-    EFI_SUCCESS       - The text output device was reset.\r
-    EFI_DEVICE_ERROR  - The text output device is not functioning correctly and\r
-                        could not be reset.\r
-\r
---*/\r
 {\r
   EFI_STATUS                      Status;\r
   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
@@ -2941,135 +4586,151 @@ ConSplitterTextOutReset (
   // return the worst status met\r
   //\r
   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {\r
-\r
-    if (Private->TextOutList[Index].TextOutEnabled) {\r
-\r
-      Status = Private->TextOutList[Index].TextOut->Reset (\r
-                                                      Private->TextOutList[Index].TextOut,\r
-                                                      ExtendedVerification\r
-                                                      );\r
-      if (EFI_ERROR (Status)) {\r
-        ReturnStatus = Status;\r
-      }\r
+    Status = Private->TextOutList[Index].TextOut->Reset (\r
+                                                    Private->TextOutList[Index].TextOut,\r
+                                                    ExtendedVerification\r
+                                                    );\r
+    if (EFI_ERROR (Status)) {\r
+      ReturnStatus = Status;\r
     }\r
   }\r
 \r
-  This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK));\r
+  This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BLACK));\r
 \r
-  Status = DevNullTextOutSetMode (Private, 0);\r
-  if (EFI_ERROR (Status)) {\r
-    ReturnStatus = Status;\r
-  }\r
+  //\r
+  // reset all mode parameters\r
+  //\r
+  TextOutSetMode (Private, 0);\r
 \r
   return ReturnStatus;\r
 }\r
 \r
+/**\r
+  Write a Unicode string to the output device.\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  WString                  The NULL-terminated Unicode string to be\r
+                                   displayed on the output device(s). All output\r
+                                   devices must also support the Unicode drawing\r
+                                   defined in this file.\r
+\r
+  @retval EFI_SUCCESS              The string was output to the device.\r
+  @retval EFI_DEVICE_ERROR         The device reported an error while attempting to\r
+                                   output the text.\r
+  @retval EFI_UNSUPPORTED          The output device's mode is not currently in a\r
+                                   defined text mode.\r
+  @retval EFI_WARN_UNKNOWN_GLYPH   This warning code indicates that some of the\r
+                                   characters in the Unicode string could not be\r
+                                   rendered and were skipped.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterTextOutOutputString (\r
-  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,\r
-  IN  CHAR16                             *WString\r
+  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,\r
+  IN  CHAR16                           *WString\r
   )\r
-/*++\r
-\r
-  Routine Description:\r
-    Write a Unicode string to the output device.\r
-\r
-  Arguments:\r
-    This    - Protocol instance pointer.\r
-    String  - The NULL-terminated Unicode string to be displayed on the output\r
-              device(s). All output devices must also support the Unicode\r
-              drawing defined in this file.\r
-\r
-  Returns:\r
-    EFI_SUCCESS       - The string was output to the device.\r
-    EFI_DEVICE_ERROR  - The device reported an error while attempting to output\r
-                         the text.\r
-    EFI_UNSUPPORTED        - The output device's mode is not currently in a\r
-                              defined text mode.\r
-    EFI_WARN_UNKNOWN_GLYPH - This warning code indicates that some of the\r
-                              characters in the Unicode string could not be\r
-                              rendered and were skipped.\r
-\r
---*/\r
 {\r
   EFI_STATUS                      Status;\r
   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
   UINTN                           Index;\r
-  UINTN                           BackSpaceCount;\r
   EFI_STATUS                      ReturnStatus;\r
-  CHAR16                          *TargetString;\r
+  UINTN                           MaxColumn;\r
+  UINTN                           MaxRow;\r
 \r
   This->SetAttribute (This, This->Mode->Attribute);\r
 \r
-  Private         = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
-\r
-  BackSpaceCount  = 0;\r
-  for (TargetString = WString; *TargetString; TargetString++) {\r
-    if (*TargetString == CHAR_BACKSPACE) {\r
-      BackSpaceCount++;\r
-    }\r
-\r
-  }\r
+  Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
 \r
-  if (BackSpaceCount == 0) {\r
-    TargetString = WString;\r
-  } else {\r
-    TargetString = AllocatePool (sizeof (CHAR16) * (StrLen (WString) + BackSpaceCount + 1));\r
-    StrCpy (TargetString, WString);\r
-  }\r
   //\r
   // return the worst status met\r
   //\r
-  Status = DevNullTextOutOutputString (Private, TargetString);\r
-  if (EFI_ERROR (Status)) {\r
-    ReturnStatus = Status;\r
+  for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {\r
+    Status = Private->TextOutList[Index].TextOut->OutputString (\r
+                                                    Private->TextOutList[Index].TextOut,\r
+                                                    WString\r
+                                                    );\r
+    if (EFI_ERROR (Status)) {\r
+      ReturnStatus = Status;\r
+    }\r
   }\r
 \r
-  for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {\r
+  if (Private->CurrentNumberOfConsoles > 0) {\r
+    Private->TextOutMode.CursorColumn = Private->TextOutList[0].TextOut->Mode->CursorColumn;\r
+    Private->TextOutMode.CursorRow    = Private->TextOutList[0].TextOut->Mode->CursorRow;\r
+  } else {\r
+    //\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
+                       &Private->TextOut,\r
+                       Private->TextOutMode.Mode,\r
+                       &MaxColumn,\r
+                       &MaxRow\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
+          } else if (Private->TextOutMode.CursorColumn > 0) {\r
+            Private->TextOutMode.CursorColumn--;\r
+          }\r
 \r
-    if (Private->TextOutList[Index].TextOutEnabled) {\r
-      Status = Private->TextOutList[Index].TextOut->OutputString (\r
-                                                      Private->TextOutList[Index].TextOut,\r
-                                                      TargetString\r
-                                                      );\r
-      if (EFI_ERROR (Status)) {\r
-        ReturnStatus = Status;\r
+          break;\r
+\r
+        case CHAR_LINEFEED:\r
+          if (Private->TextOutMode.CursorRow < (INT32)(MaxRow - 1)) {\r
+            Private->TextOutMode.CursorRow++;\r
+          }\r
+\r
+          break;\r
+\r
+        case CHAR_CARRIAGE_RETURN:\r
+          Private->TextOutMode.CursorColumn = 0;\r
+          break;\r
+\r
+        default:\r
+          if (Private->TextOutMode.CursorColumn < (INT32)(MaxColumn - 1)) {\r
+            Private->TextOutMode.CursorColumn++;\r
+          } else {\r
+            Private->TextOutMode.CursorColumn = 0;\r
+            if (Private->TextOutMode.CursorRow < (INT32)(MaxRow - 1)) {\r
+              Private->TextOutMode.CursorRow++;\r
+            }\r
+          }\r
+\r
+          break;\r
       }\r
     }\r
   }\r
 \r
-  if (BackSpaceCount) {\r
-    FreePool (TargetString);\r
-  }\r
-\r
   return ReturnStatus;\r
 }\r
 \r
+/**\r
+  Verifies that all characters in a Unicode string can be output to the\r
+  target device.\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  WString                  The NULL-terminated Unicode string to be\r
+                                   examined for the output device(s).\r
+\r
+  @retval EFI_SUCCESS              The device(s) are capable of rendering the\r
+                                   output string.\r
+  @retval EFI_UNSUPPORTED          Some of the characters in the Unicode string\r
+                                   cannot be rendered by one or more of the output\r
+                                   devices mapped by the EFI handle.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterTextOutTestString (\r
-  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,\r
-  IN  CHAR16                             *WString\r
+  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,\r
+  IN  CHAR16                           *WString\r
   )\r
-/*++\r
-\r
-  Routine Description:\r
-    Verifies that all characters in a Unicode string can be output to the\r
-    target device.\r
-\r
-  Arguments:\r
-    This    - Protocol instance pointer.\r
-    String  - The NULL-terminated Unicode string to be examined for the output\r
-               device(s).\r
-\r
-  Returns:\r
-    EFI_SUCCESS     - The device(s) are capable of rendering the output string.\r
-    EFI_UNSUPPORTED - Some of the characters in the Unicode string cannot be\r
-                       rendered by one or more of the output devices mapped\r
-                       by the EFI handle.\r
-\r
---*/\r
 {\r
   EFI_STATUS                      Status;\r
   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
@@ -3082,16 +4743,15 @@ ConSplitterTextOutTestString (
   // return the worst status met\r
   //\r
   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {\r
-    if (Private->TextOutList[Index].TextOutEnabled) {\r
-      Status = Private->TextOutList[Index].TextOut->TestString (\r
-                                                      Private->TextOutList[Index].TextOut,\r
-                                                      WString\r
-                                                      );\r
-      if (EFI_ERROR (Status)) {\r
-        ReturnStatus = Status;\r
-      }\r
+    Status = Private->TextOutList[Index].TextOut->TestString (\r
+                                                    Private->TextOutList[Index].TextOut,\r
+                                                    WString\r
+                                                    );\r
+    if (EFI_ERROR (Status)) {\r
+      ReturnStatus = Status;\r
     }\r
   }\r
+\r
   //\r
   // There is no DevNullTextOutTestString () since a Unicode buffer would\r
   // always return EFI_SUCCESS.\r
@@ -3100,35 +4760,35 @@ ConSplitterTextOutTestString (
   return ReturnStatus;\r
 }\r
 \r
+/**\r
+  Returns information for an available text mode that the output device(s)\r
+  supports.\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  ModeNumber               The mode number to return information on.\r
+  @param  Columns                  Returns the columns of the text output device\r
+                                   for the requested ModeNumber.\r
+  @param  Rows                     Returns the rows of the text output device\r
+                                   for the requested ModeNumber.\r
+\r
+  @retval EFI_SUCCESS              The requested mode information was returned.\r
+  @retval EFI_DEVICE_ERROR         The device had an error and could not complete\r
+                                   the request.\r
+  @retval EFI_UNSUPPORTED          The mode number was not valid.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterTextOutQueryMode (\r
-  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,\r
-  IN  UINTN                              ModeNumber,\r
-  OUT UINTN                              *Columns,\r
-  OUT UINTN                              *Rows\r
+  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,\r
+  IN  UINTN                            ModeNumber,\r
+  OUT UINTN                            *Columns,\r
+  OUT UINTN                            *Rows\r
   )\r
-/*++\r
-\r
-  Routine Description:\r
-    Returns information for an available text mode that the output device(s)\r
-    supports.\r
-\r
-  Arguments:\r
-    This       - Protocol instance pointer.\r
-    ModeNumber - The mode number to return information on.\r
-    Columns, Rows - Returns the geometry of the text output device for the\r
-                    requested ModeNumber.\r
-\r
-  Returns:\r
-    EFI_SUCCESS      - The requested mode information was returned.\r
-    EFI_DEVICE_ERROR - The device had an error and could not\r
-                       complete the request.\r
-    EFI_UNSUPPORTED - The mode number was not valid.\r
-\r
---*/\r
 {\r
   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
+  UINTN                           CurrentMode;\r
+  INT32                           *TextOutModeMap;\r
 \r
   Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
 \r
@@ -3136,47 +4796,52 @@ ConSplitterTextOutQueryMode (
   // Check whether param ModeNumber is valid.\r
   // ModeNumber should be within range 0 ~ MaxMode - 1.\r
   //\r
-  if ( (ModeNumber > (UINTN)(((UINT32)-1)>>1)) ) {\r
+  if ((ModeNumber > (UINTN)(((UINT32)-1)>>1))) {\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-  if ((INT32) ModeNumber >= This->Mode->MaxMode) {\r
+  if ((INT32)ModeNumber >= This->Mode->MaxMode) {\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-  *Columns  = Private->TextOutQueryData[ModeNumber].Columns;\r
-  *Rows     = Private->TextOutQueryData[ModeNumber].Rows;\r
+  //\r
+  // We get the available mode from mode intersection map if it's available\r
+  //\r
+  if (Private->TextOutModeMap != NULL) {\r
+    TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber;\r
+    CurrentMode    = (UINTN)(*TextOutModeMap);\r
+    *Columns       = Private->TextOutQueryData[CurrentMode].Columns;\r
+    *Rows          = Private->TextOutQueryData[CurrentMode].Rows;\r
+  } else {\r
+    *Columns = Private->TextOutQueryData[ModeNumber].Columns;\r
+    *Rows    = Private->TextOutQueryData[ModeNumber].Rows;\r
+  }\r
 \r
-  if (*Columns <= 0 && *Rows <= 0) {\r
+  if ((*Columns <= 0) && (*Rows <= 0)) {\r
     return EFI_UNSUPPORTED;\r
-\r
   }\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Sets the output device(s) to a specified mode.\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  ModeNumber               The mode number to set.\r
+\r
+  @retval EFI_SUCCESS              The requested text mode was set.\r
+  @retval EFI_DEVICE_ERROR         The device had an error and could not complete\r
+                                   the request.\r
+  @retval EFI_UNSUPPORTED          The mode number was not valid.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterTextOutSetMode (\r
-  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,\r
-  IN  UINTN                              ModeNumber\r
+  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,\r
+  IN  UINTN                            ModeNumber\r
   )\r
-/*++\r
-\r
-  Routine Description:\r
-    Sets the output device(s) to a specified mode.\r
-\r
-  Arguments:\r
-    This       - Protocol instance pointer.\r
-    ModeNumber - The mode number to set.\r
-\r
-  Returns:\r
-    EFI_SUCCESS      - The requested text mode was set.\r
-    EFI_DEVICE_ERROR - The device had an error and\r
-                       could not complete the request.\r
-    EFI_UNSUPPORTED - The mode number was not valid.\r
-\r
---*/\r
 {\r
   EFI_STATUS                      Status;\r
   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
@@ -3190,79 +4855,73 @@ ConSplitterTextOutSetMode (
   // Check whether param ModeNumber is valid.\r
   // ModeNumber should be within range 0 ~ MaxMode - 1.\r
   //\r
-  if ( (ModeNumber > (UINTN)(((UINT32)-1)>>1)) ) {\r
+  if ((ModeNumber > (UINTN)(((UINT32)-1)>>1))) {\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-  if ((INT32) ModeNumber >= This->Mode->MaxMode) {\r
+  if ((INT32)ModeNumber >= This->Mode->MaxMode) {\r
     return EFI_UNSUPPORTED;\r
   }\r
+\r
   //\r
   // If the mode is being set to the curent mode, then just clear the screen and return.\r
   //\r
-  if (Private->TextOutMode.Mode == (INT32) ModeNumber) {\r
+  if (Private->TextOutMode.Mode == (INT32)ModeNumber) {\r
     return ConSplitterTextOutClearScreen (This);\r
   }\r
+\r
   //\r
   // return the worst status met\r
   //\r
   TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber;\r
   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {\r
-\r
-    if (Private->TextOutList[Index].TextOutEnabled) {\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
+    {\r
       Status = Private->TextOutList[Index].TextOut->SetMode (\r
                                                       Private->TextOutList[Index].TextOut,\r
                                                       TextOutModeMap[Index]\r
                                                       );\r
-      //\r
-      // If this console device is based on a UGA device, then sync up the bitmap from\r
-      // the UGA splitter and reclear the text portion of the display in the new mode.\r
-      //\r
-      if ((Private->TextOutList[Index].GraphicsOutput != NULL) || (Private->TextOutList[Index].UgaDraw != NULL)) {\r
-        Private->TextOutList[Index].TextOut->ClearScreen (Private->TextOutList[Index].TextOut);\r
-      }\r
-\r
       if (EFI_ERROR (Status)) {\r
         ReturnStatus = Status;\r
       }\r
     }\r
   }\r
+\r
   //\r
-  // The DevNull Console will support any possible mode as it allocates memory\r
+  // Set mode parameter to specified mode number\r
   //\r
-  Status = DevNullTextOutSetMode (Private, ModeNumber);\r
-  if (EFI_ERROR (Status)) {\r
-    ReturnStatus = Status;\r
-  }\r
+  TextOutSetMode (Private, ModeNumber);\r
 \r
   return ReturnStatus;\r
 }\r
 \r
+/**\r
+  Sets the background and foreground colors for the OutputString () and\r
+  ClearScreen () functions.\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  Attribute                The attribute to set. Bits 0..3 are the\r
+                                   foreground color, and bits 4..6 are the\r
+                                   background color. All other bits are undefined\r
+                                   and must be zero. The valid Attributes are\r
+                                   defined in this file.\r
+\r
+  @retval EFI_SUCCESS              The attribute was set.\r
+  @retval EFI_DEVICE_ERROR         The device had an error and could not complete\r
+                                   the request.\r
+  @retval EFI_UNSUPPORTED          The attribute requested is not defined.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterTextOutSetAttribute (\r
-  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,\r
-  IN  UINTN                              Attribute\r
+  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,\r
+  IN  UINTN                            Attribute\r
   )\r
-/*++\r
-\r
-  Routine Description:\r
-    Sets the background and foreground colors for the OutputString () and\r
-    ClearScreen () functions.\r
-\r
-  Arguments:\r
-    This      - Protocol instance pointer.\r
-    Attribute - The attribute to set. Bits 0..3 are the foreground color, and\r
-                bits 4..6 are the background color. All other bits are undefined\r
-                and must be zero. The valid Attributes are defined in this file.\r
-\r
-  Returns:\r
-    EFI_SUCCESS      - The attribute was set.\r
-    EFI_DEVICE_ERROR - The device had an error and\r
-                       could not complete the request.\r
-    EFI_UNSUPPORTED - The attribute requested is not defined.\r
-\r
---*/\r
 {\r
   EFI_STATUS                      Status;\r
   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
@@ -3274,7 +4933,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
@@ -3282,44 +4941,37 @@ ConSplitterTextOutSetAttribute (
   // return the worst status met\r
   //\r
   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {\r
-\r
-    if (Private->TextOutList[Index].TextOutEnabled) {\r
-      Status = Private->TextOutList[Index].TextOut->SetAttribute (\r
-                                                      Private->TextOutList[Index].TextOut,\r
-                                                      Attribute\r
-                                                      );\r
-      if (EFI_ERROR (Status)) {\r
-        ReturnStatus = Status;\r
-      }\r
+    Status = Private->TextOutList[Index].TextOut->SetAttribute (\r
+                                                    Private->TextOutList[Index].TextOut,\r
+                                                    Attribute\r
+                                                    );\r
+    if (EFI_ERROR (Status)) {\r
+      ReturnStatus = Status;\r
     }\r
   }\r
 \r
-  Private->TextOutMode.Attribute = (INT32) Attribute;\r
+  Private->TextOutMode.Attribute = (INT32)Attribute;\r
 \r
   return ReturnStatus;\r
 }\r
 \r
+/**\r
+  Clears the output device(s) display to the currently selected background\r
+  color.\r
+\r
+  @param  This                     Protocol instance pointer.\r
+\r
+  @retval EFI_SUCCESS              The operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR         The device had an error and could not complete\r
+                                   the request.\r
+  @retval EFI_UNSUPPORTED          The output device is not in a valid text mode.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterTextOutClearScreen (\r
-  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This\r
+  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This\r
   )\r
-/*++\r
-\r
-  Routine Description:\r
-    Clears the output device(s) display to the currently selected background\r
-    color.\r
-\r
-  Arguments:\r
-    This      - Protocol instance pointer.\r
-\r
-  Returns:\r
-    EFI_SUCCESS      - The operation completed successfully.\r
-    EFI_DEVICE_ERROR - The device had an error and\r
-                       could not complete the request.\r
-    EFI_UNSUPPORTED - The output device is not in a valid text mode.\r
-\r
---*/\r
 {\r
   EFI_STATUS                      Status;\r
   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
@@ -3332,49 +4984,50 @@ ConSplitterTextOutClearScreen (
   // return the worst status met\r
   //\r
   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {\r
-\r
-    if (Private->TextOutList[Index].TextOutEnabled) {\r
-      Status = Private->TextOutList[Index].TextOut->ClearScreen (Private->TextOutList[Index].TextOut);\r
-      if (EFI_ERROR (Status)) {\r
-        ReturnStatus = Status;\r
-      }\r
+    Status = Private->TextOutList[Index].TextOut->ClearScreen (Private->TextOutList[Index].TextOut);\r
+    if (EFI_ERROR (Status)) {\r
+      ReturnStatus = Status;\r
     }\r
   }\r
 \r
-  Status = DevNullTextOutClearScreen (Private);\r
-  if (EFI_ERROR (Status)) {\r
-    ReturnStatus = Status;\r
-  }\r
+  //\r
+  // No need to do extra check here as whether (Column, Row) is valid has\r
+  // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should\r
+  // always be supported.\r
+  //\r
+  Private->TextOutMode.CursorColumn  = 0;\r
+  Private->TextOutMode.CursorRow     = 0;\r
+  Private->TextOutMode.CursorVisible = TRUE;\r
 \r
   return ReturnStatus;\r
 }\r
 \r
+/**\r
+  Sets the current coordinates of the cursor position\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  Column                   The column position to set the cursor to. Must be\r
+                                   greater than or equal to zero and less than the\r
+                                   number of columns by QueryMode ().\r
+  @param  Row                      The row position to set the cursor to. Must be\r
+                                   greater than or equal to zero and less than the\r
+                                   number of rows by QueryMode ().\r
+\r
+  @retval EFI_SUCCESS              The operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR         The device had an error and could not complete\r
+                                   the request.\r
+  @retval EFI_UNSUPPORTED          The output device is not in a valid text mode,\r
+                                   or the cursor position is invalid for the\r
+                                   current mode.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterTextOutSetCursorPosition (\r
-  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,\r
-  IN  UINTN                              Column,\r
-  IN  UINTN                              Row\r
+  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,\r
+  IN  UINTN                            Column,\r
+  IN  UINTN                            Row\r
   )\r
-/*++\r
-\r
-  Routine Description:\r
-    Sets the current coordinates of the cursor position\r
-\r
-  Arguments:\r
-    This        - Protocol instance pointer.\r
-    Column, Row - the position to set the cursor to. Must be greater than or\r
-                  equal to zero and less than the number of columns and rows\r
-                  by QueryMode ().\r
-\r
-  Returns:\r
-    EFI_SUCCESS      - The operation completed successfully.\r
-    EFI_DEVICE_ERROR - The device had an error and\r
-                       could not complete the request.\r
-    EFI_UNSUPPORTED - The output device is not in a valid text mode, or the\r
-                       cursor position is invalid for the current mode.\r
-\r
---*/\r
 {\r
   EFI_STATUS                      Status;\r
   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
@@ -3382,61 +5035,76 @@ ConSplitterTextOutSetCursorPosition (
   EFI_STATUS                      ReturnStatus;\r
   UINTN                           MaxColumn;\r
   UINTN                           MaxRow;\r
+  INT32                           *TextOutModeMap;\r
+  INT32                           ModeNumber;\r
+  INT32                           CurrentMode;\r
+\r
+  Private        = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
+  TextOutModeMap = NULL;\r
+  ModeNumber     = Private->TextOutMode.Mode;\r
 \r
-  Private   = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
+  //\r
+  // Get current MaxColumn and MaxRow from intersection map\r
+  //\r
+  if (Private->TextOutModeMap != NULL) {\r
+    TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber;\r
+    CurrentMode    = *TextOutModeMap;\r
+  } else {\r
+    CurrentMode = ModeNumber;\r
+  }\r
 \r
-  MaxColumn = Private->TextOutQueryData[Private->TextOutMode.Mode].Columns;\r
-  MaxRow    = Private->TextOutQueryData[Private->TextOutMode.Mode].Rows;\r
+  MaxColumn = Private->TextOutQueryData[CurrentMode].Columns;\r
+  MaxRow    = Private->TextOutQueryData[CurrentMode].Rows;\r
 \r
-  if (Column >= MaxColumn || Row >= MaxRow) {\r
+  if ((Column >= MaxColumn) || (Row >= MaxRow)) {\r
     return EFI_UNSUPPORTED;\r
   }\r
+\r
   //\r
   // return the worst status met\r
   //\r
   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {\r
-\r
-    if (Private->TextOutList[Index].TextOutEnabled) {\r
-      Status = Private->TextOutList[Index].TextOut->SetCursorPosition (\r
-                                                      Private->TextOutList[Index].TextOut,\r
-                                                      Column,\r
-                                                      Row\r
-                                                      );\r
-      if (EFI_ERROR (Status)) {\r
-        ReturnStatus = Status;\r
-      }\r
+    Status = Private->TextOutList[Index].TextOut->SetCursorPosition (\r
+                                                    Private->TextOutList[Index].TextOut,\r
+                                                    Column,\r
+                                                    Row\r
+                                                    );\r
+    if (EFI_ERROR (Status)) {\r
+      ReturnStatus = Status;\r
     }\r
   }\r
 \r
-  DevNullTextOutSetCursorPosition (Private, Column, Row);\r
+  //\r
+  // No need to do extra check here as whether (Column, Row) is valid has\r
+  // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should\r
+  // always be supported.\r
+  //\r
+  Private->TextOutMode.CursorColumn = (INT32)Column;\r
+  Private->TextOutMode.CursorRow    = (INT32)Row;\r
 \r
   return ReturnStatus;\r
 }\r
 \r
+/**\r
+  Makes the cursor visible or invisible\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  Visible                  If TRUE, the cursor is set to be visible. If\r
+                                   FALSE, the cursor is set to be invisible.\r
+\r
+  @retval EFI_SUCCESS              The operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR         The device had an error and could not complete\r
+                                   the request, or the device does not support\r
+                                   changing the cursor mode.\r
+  @retval EFI_UNSUPPORTED          The output device is not in a valid text mode.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ConSplitterTextOutEnableCursor (\r
-  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,\r
-  IN  BOOLEAN                            Visible\r
+  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,\r
+  IN  BOOLEAN                          Visible\r
   )\r
-/*++\r
-\r
-  Routine Description:\r
-    Makes the cursor visible or invisible\r
-\r
-  Arguments:\r
-    This    - Protocol instance pointer.\r
-    Visible - If TRUE, the cursor is set to be visible. If FALSE, the cursor is\r
-              set to be invisible.\r
-\r
-  Returns:\r
-    EFI_SUCCESS      - The operation completed successfully.\r
-    EFI_DEVICE_ERROR - The device had an error and could not complete the\r
-                        request, or the device does not support changing\r
-                        the cursor mode.\r
-    EFI_UNSUPPORTED - The output device is not in a valid text mode.\r
-\r
---*/\r
 {\r
   EFI_STATUS                      Status;\r
   TEXT_OUT_SPLITTER_PRIVATE_DATA  *Private;\r
@@ -3449,19 +5117,16 @@ ConSplitterTextOutEnableCursor (
   // return the worst status met\r
   //\r
   for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {\r
-\r
-    if (Private->TextOutList[Index].TextOutEnabled) {\r
-      Status = Private->TextOutList[Index].TextOut->EnableCursor (\r
-                                                      Private->TextOutList[Index].TextOut,\r
-                                                      Visible\r
-                                                      );\r
-      if (EFI_ERROR (Status)) {\r
-        ReturnStatus = Status;\r
-      }\r
+    Status = Private->TextOutList[Index].TextOut->EnableCursor (\r
+                                                    Private->TextOutList[Index].TextOut,\r
+                                                    Visible\r
+                                                    );\r
+    if (EFI_ERROR (Status)) {\r
+      ReturnStatus = Status;\r
     }\r
   }\r
 \r
-  DevNullTextOutEnableCursor (Private, Visible);\r
+  Private->TextOutMode.CursorVisible = Visible;\r
 \r
   return ReturnStatus;\r
 }\r