]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
MdeModulePkg/TerminalDxe: Separate state machine start/stop logic
[mirror_edk2.git] / MdeModulePkg / Universal / Console / TerminalDxe / Terminal.c
index 01ab587bd69f25afee9537645cc1fa7b52f67d23..b8dcf0c472bd2670d1f5d8a4e51618833418558d 100644 (file)
@@ -1,7 +1,9 @@
-/*++\r
+/** @file\r
+  Produces Simple Text Input Protocol, Simple Text Input Extended Protocol and\r
+  Simple Text Output Protocol upon Serial IO Protocol.\r
 \r
-Copyright (c) 2006, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
 http://opensource.org/licenses/bsd-license.php\r
@@ -9,26 +11,11 @@ http://opensource.org/licenses/bsd-license.php
 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
 \r
-Module Name:\r
+**/\r
 \r
-    Terminal.c\r
-\r
-Abstract:\r
-\r
-Revision History:\r
-\r
---*/\r
-\r
-\r
-//\r
-// Include common header file for this module.\r
-//\r
-#include "CommonHeader.h"\r
 \r
 #include "Terminal.h"\r
 \r
-#include "FrameworkDxe.h"\r
-\r
 //\r
 // Globals\r
 //\r
@@ -42,6 +29,133 @@ EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = {
 };\r
 \r
 \r
+EFI_GUID  *mTerminalType[] = {\r
+  &gEfiPcAnsiGuid,\r
+  &gEfiVT100Guid,\r
+  &gEfiVT100PlusGuid,\r
+  &gEfiVTUTF8Guid,\r
+  &gEfiTtyTermGuid\r
+};\r
+\r
+\r
+CHAR16 *mSerialConsoleNames[] = {\r
+  L"PC-ANSI Serial Console",\r
+  L"VT-100 Serial Console",\r
+  L"VT-100+ Serial Console",\r
+  L"VT-UTF8 Serial Console",\r
+  L"Tty Terminal Serial Console"\r
+};\r
+\r
+TERMINAL_DEV  mTerminalDevTemplate = {\r
+  TERMINAL_DEV_SIGNATURE,\r
+  NULL,\r
+  0,\r
+  NULL,\r
+  NULL,\r
+  {   // SimpleTextInput\r
+    TerminalConInReset,\r
+    TerminalConInReadKeyStroke,\r
+    NULL\r
+  },\r
+  {   // SimpleTextOutput\r
+    TerminalConOutReset,\r
+    TerminalConOutOutputString,\r
+    TerminalConOutTestString,\r
+    TerminalConOutQueryMode,\r
+    TerminalConOutSetMode,\r
+    TerminalConOutSetAttribute,\r
+    TerminalConOutClearScreen,\r
+    TerminalConOutSetCursorPosition,\r
+    TerminalConOutEnableCursor,\r
+    NULL\r
+  },\r
+  {   // SimpleTextOutputMode\r
+    1,                                           // MaxMode\r
+    0,                                           // Mode\r
+    EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK),    // Attribute\r
+    0,                                           // CursorColumn\r
+    0,                                           // CursorRow\r
+    TRUE                                         // CursorVisible\r
+  },\r
+  NULL, // TerminalConsoleModeData\r
+  0,  // SerialInTimeOut\r
+\r
+  NULL, // RawFifo\r
+  NULL, // UnicodeFiFo\r
+  NULL, // EfiKeyFiFo\r
+  NULL, // EfiKeyFiFoForNotify\r
+\r
+  NULL, // ControllerNameTable\r
+  NULL, // TimerEvent\r
+  NULL, // TwoSecondTimeOut\r
+  INPUT_STATE_DEFAULT,\r
+  RESET_STATE_DEFAULT,\r
+  {\r
+      0,\r
+      0,\r
+      0\r
+  },\r
+  0,\r
+  FALSE,\r
+  {   // SimpleTextInputEx\r
+    TerminalConInResetEx,\r
+    TerminalConInReadKeyStrokeEx,\r
+    NULL,\r
+    TerminalConInSetState,\r
+    TerminalConInRegisterKeyNotify,\r
+    TerminalConInUnregisterKeyNotify,\r
+  },\r
+  {   // NotifyList\r
+    NULL,\r
+    NULL,\r
+  },\r
+  NULL // KeyNotifyProcessEvent\r
+};\r
+\r
+TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData[] = {\r
+  {80,  25},\r
+  {80,  50},\r
+  {100, 31},\r
+  //\r
+  // New modes can be added here.\r
+  //\r
+};\r
+\r
+/**\r
+  Convert the GUID representation of terminal type to enum type.\r
+\r
+  @param Guid  The GUID representation of terminal type.\r
+\r
+  @return  The terminal type in enum type.\r
+**/\r
+TERMINAL_TYPE\r
+TerminalTypeFromGuid (\r
+  IN EFI_GUID                     *Guid\r
+)\r
+{\r
+  TERMINAL_TYPE                   Type;\r
+\r
+  for (Type = 0; Type < ARRAY_SIZE (mTerminalType); Type++) {\r
+    if (CompareGuid (Guid, mTerminalType[Type])) {\r
+      break;\r
+    }\r
+  }\r
+  return Type;\r
+}\r
+\r
+/**\r
+  Test to see if this driver supports Controller.\r
+\r
+  @param  This                Protocol instance pointer.\r
+  @param  Controller          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 EFI_ALREADY_STARTED This driver is already running on this device.\r
+  @retval other               This driver does not support this device.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 TerminalDriverBindingSupported (\r
@@ -60,34 +174,42 @@ TerminalDriverBindingSupported (
   // device path that describes a terminal communications protocol.\r
   //\r
   if (RemainingDevicePath != NULL) {\r
-\r
-    Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;\r
-\r
-    if (Node->Header.Type != MESSAGING_DEVICE_PATH ||\r
-        Node->Header.SubType != MSG_VENDOR_DP ||\r
-        DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) {\r
-\r
-      return EFI_UNSUPPORTED;\r
-\r
-    }\r
     //\r
-    // only supports PC ANSI, VT100, VT100+ and VT-UTF8 terminal types\r
+    // Check if RemainingDevicePath is the End of Device Path Node,\r
+    // if yes, go on checking other conditions\r
     //\r
-    if (!CompareGuid (&Node->Guid, &gEfiPcAnsiGuid) &&\r
-        !CompareGuid (&Node->Guid, &gEfiVT100Guid) &&\r
-        !CompareGuid (&Node->Guid, &gEfiVT100PlusGuid) &&\r
-        !CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {\r
+    if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+      //\r
+      // If RemainingDevicePath isn't the End of Device Path Node,\r
+      // check its validation\r
+      //\r
+      Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;\r
 \r
-      return EFI_UNSUPPORTED;\r
+      if (Node->Header.Type != MESSAGING_DEVICE_PATH ||\r
+          Node->Header.SubType != MSG_VENDOR_DP ||\r
+          DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) {\r
+\r
+        return EFI_UNSUPPORTED;\r
+\r
+      }\r
+      //\r
+      // only supports PC ANSI, VT100, VT100+, VT-UTF8, and TtyTerm terminal types\r
+      //\r
+      if (TerminalTypeFromGuid (&Node->Guid) == ARRAY_SIZE (mTerminalType)) {\r
+        return EFI_UNSUPPORTED;\r
+      }\r
     }\r
   }\r
   //\r
   // Open the IO Abstraction(s) needed to perform the supported test\r
+  // The Controller must support the Serial I/O Protocol.\r
+  // This driver is a bus driver with at most 1 child device, so it is\r
+  // ok for it to be already started.\r
   //\r
   Status = gBS->OpenProtocol (\r
                   Controller,\r
-                  &gEfiDevicePathProtocolGuid,\r
-                  (VOID **) &ParentDevicePath,\r
+                  &gEfiSerialIoProtocolGuid,\r
+                  (VOID **) &SerialIo,\r
                   This->DriverBindingHandle,\r
                   Controller,\r
                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
@@ -100,22 +222,23 @@ TerminalDriverBindingSupported (
     return Status;\r
   }\r
 \r
+  //\r
+  // Close the I/O Abstraction(s) used to perform the supported test\r
+  //\r
   gBS->CloseProtocol (\r
         Controller,\r
-        &gEfiDevicePathProtocolGuid,\r
+        &gEfiSerialIoProtocolGuid,\r
         This->DriverBindingHandle,\r
         Controller\r
         );\r
 \r
   //\r
-  // The Controller must support the Serial I/O Protocol.\r
-  // This driver is a bus driver with at most 1 child device, so it is\r
-  // ok for it to be already started.\r
+  // Open the EFI Device Path protocol needed to perform the supported test\r
   //\r
   Status = gBS->OpenProtocol (\r
                   Controller,\r
-                  &gEfiSerialIoProtocolGuid,\r
-                  (VOID **) &SerialIo,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &ParentDevicePath,\r
                   This->DriverBindingHandle,\r
                   Controller,\r
                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
@@ -127,12 +250,13 @@ TerminalDriverBindingSupported (
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
+\r
   //\r
-  // Close the I/O Abstraction(s) used to perform the supported test\r
+  // Close protocol, don't use device path protocol in the Support() function\r
   //\r
   gBS->CloseProtocol (\r
         Controller,\r
-        &gEfiSerialIoProtocolGuid,\r
+        &gEfiDevicePathProtocolGuid,\r
         This->DriverBindingHandle,\r
         Controller\r
         );\r
@@ -140,47 +264,383 @@ TerminalDriverBindingSupported (
   return Status;\r
 }\r
 \r
-EFI_STATUS\r
+/**\r
+  Build the terminal device path for the child device according to the\r
+  terminal type.\r
+\r
+  @param  ParentDevicePath         Parent device path.\r
+  @param  RemainingDevicePath      A specific child device.\r
+\r
+  @return The child device path built.\r
+\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL*\r
 EFIAPI\r
-TerminalDriverBindingStart (\r
-  IN EFI_DRIVER_BINDING_PROTOCOL    *This,\r
-  IN EFI_HANDLE                     Controller,\r
+BuildTerminalDevpath  (\r
+  IN EFI_DEVICE_PATH_PROTOCOL       *ParentDevicePath,\r
   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\r
   )\r
-/*++\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL          *TerminalDevicePath;\r
+  TERMINAL_TYPE                     TerminalType;\r
+  VENDOR_DEVICE_PATH                *Node;\r
+  EFI_STATUS                        Status;\r
+\r
+  TerminalDevicePath = NULL;\r
+\r
+  //\r
+  // Use the RemainingDevicePath to determine the terminal type\r
+  //\r
+  Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;\r
+  if (Node == NULL) {\r
+    TerminalType = PcdGet8 (PcdDefaultTerminalType);\r
+\r
+  } else if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {\r
+\r
+    TerminalType = TerminalTypePcAnsi;\r
+\r
+  } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {\r
+\r
+    TerminalType = TerminalTypeVt100;\r
+\r
+  } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {\r
+\r
+    TerminalType = TerminalTypeVt100Plus;\r
+\r
+  } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {\r
+\r
+    TerminalType = TerminalTypeVtUtf8;\r
+\r
+  } else if (CompareGuid (&Node->Guid, &gEfiTtyTermGuid)) {\r
+\r
+    TerminalType = TerminalTypeTtyTerm;\r
+\r
+  } else {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Build the device path for the child device\r
+  //\r
+  Status = SetTerminalDevicePath (\r
+            TerminalType,\r
+            ParentDevicePath,\r
+            &TerminalDevicePath\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+  return TerminalDevicePath;\r
+}\r
+\r
+/**\r
+  Compare a device path data structure to that of all the nodes of a\r
+  second device path instance.\r
+\r
+  @param  Multi          A pointer to a multi-instance device path data structure.\r
+  @param  Single         A pointer to a single-instance device path data structure.\r
+\r
+  @retval TRUE           If the Single is contained within Multi.\r
+  @retval FALSE          The Single is not match within Multi.\r
+\r
+**/\r
+BOOLEAN\r
+MatchDevicePaths (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *Single\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathInst;\r
+  UINTN                     Size;\r
+\r
+  DevicePath      = Multi;\r
+  DevicePathInst  = GetNextDevicePathInstance (&DevicePath, &Size);\r
+  //\r
+  // Search for the match of 'Single' in 'Multi'\r
+  //\r
+  while (DevicePathInst != NULL) {\r
+    //\r
+    // If the single device path is found in multiple device paths,\r
+    // return success\r
+    //\r
+    if (CompareMem (Single, DevicePathInst, Size) == 0) {\r
+      FreePool (DevicePathInst);\r
+      return TRUE;\r
+    }\r
+\r
+    FreePool (DevicePathInst);\r
+    DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Check whether the terminal device path is in the global variable.\r
+\r
+  @param  VariableName          Pointer to one global variable.\r
+  @param  TerminalDevicePath    Pointer to the terminal device's device path.\r
+\r
+  @retval TRUE                  The devcie is in the global variable.\r
+  @retval FALSE                 The devcie is not in the global variable.\r
+\r
+**/\r
+BOOLEAN\r
+IsTerminalInConsoleVariable (\r
+  IN CHAR16                    *VariableName,\r
+  IN EFI_DEVICE_PATH_PROTOCOL  *TerminalDevicePath\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL  *Variable;\r
+  BOOLEAN                   ReturnFlag;\r
+\r
+  //\r
+  // Get global variable and its size according to the name given.\r
+  //\r
+  GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);\r
+  if (Variable == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check whether the terminal device path is one of the variable instances.\r
+  //\r
+  ReturnFlag = MatchDevicePaths (Variable, TerminalDevicePath);\r
+\r
+  FreePool (Variable);\r
+\r
+  return ReturnFlag;\r
+}\r
+\r
+/**\r
+  Free notify functions list.\r
+\r
+  @param  ListHead               The list head\r
+\r
+  @retval EFI_SUCCESS            Free the notify list successfully.\r
+  @retval EFI_INVALID_PARAMETER  ListHead is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+TerminalFreeNotifyList (\r
+  IN OUT LIST_ENTRY           *ListHead\r
+  )\r
+{\r
+  TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;\r
+\r
+  if (ListHead == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  while (!IsListEmpty (ListHead)) {\r
+    NotifyNode = CR (\r
+                   ListHead->ForwardLink,\r
+                   TERMINAL_CONSOLE_IN_EX_NOTIFY,\r
+                   NotifyEntry,\r
+                   TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
+                   );\r
+    RemoveEntryList (ListHead->ForwardLink);\r
+    FreePool (NotifyNode);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialize all the text modes which the terminal console supports.\r
+\r
+  It returns information for available text modes that the terminal can support.\r
+\r
+  @param[out] TextModeCount      The total number of text modes that terminal console supports.\r
+\r
+  @return   The buffer to the text modes column and row information.\r
+            Caller is responsible to free it when it's non-NULL.\r
+\r
+**/\r
+TERMINAL_CONSOLE_MODE_DATA *\r
+InitializeTerminalConsoleTextMode (\r
+  OUT INT32                         *TextModeCount\r
+)\r
+{\r
+  TERMINAL_CONSOLE_MODE_DATA  *TextModeData;\r
+\r
+  ASSERT (TextModeCount != NULL);\r
+\r
+  //\r
+  // Here we make sure that the final mode exposed does not include the duplicated modes,\r
+  // and does not include the invalid modes which exceed the max column and row.\r
+  // Reserve 2 modes for 80x25, 80x50 of terminal console.\r
+  //\r
+  TextModeData = AllocateCopyPool (sizeof (mTerminalConsoleModeData), mTerminalConsoleModeData);\r
+  if (TextModeData == NULL) {\r
+    return NULL;\r
+  }\r
+  *TextModeCount = ARRAY_SIZE (mTerminalConsoleModeData);\r
+\r
+  DEBUG_CODE (\r
+    INT32 Index;\r
+    for (Index = 0; Index < *TextModeCount; Index++) {\r
+      DEBUG ((DEBUG_INFO, "Terminal - Mode %d, Column = %d, Row = %d\n",\r
+              Index, TextModeData[Index].Columns, TextModeData[Index].Rows));\r
+    }\r
+  );\r
+  return TextModeData;\r
+}\r
+\r
+/**\r
+  Stop the terminal state machine.\r
+\r
+  @param TerminalDevice    The terminal device.\r
+**/\r
+VOID\r
+StopTerminalStateMachine (\r
+  TERMINAL_DEV             *TerminalDevice\r
+  )\r
+{\r
+  EFI_TPL                  OriginalTpl;\r
+\r
+  OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+  gBS->CloseEvent (TerminalDevice->TimerEvent);\r
+  gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);\r
+\r
+  gBS->RestoreTPL (OriginalTpl);\r
+}\r
+\r
+/**\r
+  Start the terminal state machine.\r
+\r
+  @param TerminalDevice    The terminal device.\r
+**/\r
+VOID\r
+StartTerminalStateMachine (\r
+  TERMINAL_DEV             *TerminalDevice\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  TerminalConInTimerHandler,\r
+                  TerminalDevice,\r
+                  &TerminalDevice->TimerEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = gBS->SetTimer (\r
+                  TerminalDevice->TimerEvent,\r
+                  TimerPeriodic,\r
+                  KEYBOARD_TIMER_INTERVAL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
-  Routine Description:\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER,\r
+                  TPL_CALLBACK,\r
+                  NULL,\r
+                  NULL,\r
+                  &TerminalDevice->TwoSecondTimeOut\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
 \r
-    Start the controller.\r
+/**\r
+  Initialize the controller name table.\r
 \r
-  Arguments:\r
+  @param TerminalType        The terminal type.\r
+  @param ControllerNameTable The controller name table.\r
 \r
-    This                - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
-    Controller          - The handle of the controller to start.\r
-    RemainingDevicePath - A pointer to the remaining portion of a devcie path.\r
+  @retval EFI_SUCCESS  The controller name table is initialized successfully.\r
+  @retval others       Return status of AddUnicodeString2 ().\r
+**/\r
+EFI_STATUS\r
+InitializeControllerNameTable (\r
+  TERMINAL_TYPE             TerminalType,\r
+  EFI_UNICODE_STRING_TABLE  **ControllerNameTable\r
+)\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_UNICODE_STRING_TABLE  *Table;\r
+\r
+  ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));\r
+  Table = NULL;\r
+  Status = AddUnicodeString2 (\r
+             "eng",\r
+             gTerminalComponentName.SupportedLanguages,\r
+             &Table,\r
+             mSerialConsoleNames[TerminalType],\r
+             TRUE\r
+             );\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = AddUnicodeString2 (\r
+               "en",\r
+               gTerminalComponentName2.SupportedLanguages,\r
+               &Table,\r
+               mSerialConsoleNames[TerminalType],\r
+               FALSE\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      FreeUnicodeStringTable (Table);\r
+    }\r
+  }\r
+  if (!EFI_ERROR (Status)) {\r
+    *ControllerNameTable = Table;\r
+  }\r
+  return Status;\r
+}\r
 \r
-  Returns:\r
+/**\r
+  Start this driver on Controller by opening a Serial IO protocol,\r
+  reading Device Path, and creating a child handle with a Simple Text In,\r
+  Simple Text In Ex and Simple Text Out protocol, and device path protocol.\r
+  And store Console Device Environment Variables.\r
 \r
-    EFI_SUCCESS.\r
+  @param  This                 Protocol instance pointer.\r
+  @param  Controller           Handle of device to bind driver to\r
+  @param  RemainingDevicePath  Optional parameter use to pick a specific child\r
+                               device to start.\r
 \r
---*/\r
+  @retval EFI_SUCCESS          This driver is added to Controller.\r
+  @retval EFI_ALREADY_STARTED  This driver is already running on Controller.\r
+  @retval other                This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TerminalDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,\r
+  IN EFI_HANDLE                     Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\r
+  )\r
 {\r
   EFI_STATUS                          Status;\r
   EFI_SERIAL_IO_PROTOCOL              *SerialIo;\r
   EFI_DEVICE_PATH_PROTOCOL            *ParentDevicePath;\r
   VENDOR_DEVICE_PATH                  *Node;\r
-  VENDOR_DEVICE_PATH                  *DefaultNode;\r
   EFI_SERIAL_IO_MODE                  *Mode;\r
   UINTN                               SerialInTimeOut;\r
   TERMINAL_DEV                        *TerminalDevice;\r
-  UINT8                               TerminalType;\r
+  TERMINAL_TYPE                       TerminalType;\r
   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
   UINTN                               EntryCount;\r
   UINTN                               Index;\r
   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;\r
-\r
-  TerminalDevice = NULL;\r
-  DefaultNode    = NULL;\r
+  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL     *SimpleTextOutput;\r
+  EFI_SIMPLE_TEXT_INPUT_PROTOCOL      *SimpleTextInput;\r
+  BOOLEAN                             ConInSelected;\r
+  BOOLEAN                             ConOutSelected;\r
+  BOOLEAN                             NullRemaining;\r
+  BOOLEAN                             SimTxtInInstalled;\r
+  BOOLEAN                             SimTxtOutInstalled;\r
+  BOOLEAN                             FirstEnter;\r
+\r
+  TerminalDevice     = NULL;\r
+  ConInSelected      = FALSE;\r
+  ConOutSelected     = FALSE;\r
+  NullRemaining      = FALSE;\r
+  SimTxtInInstalled  = FALSE;\r
+  SimTxtOutInstalled = FALSE;\r
+  FirstEnter         = FALSE;\r
   //\r
   // Get the Device Path Protocol to build the device path of the child device\r
   //\r
@@ -195,15 +655,6 @@ TerminalDriverBindingStart (
   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
     return Status;\r
   }\r
-  //\r
-  // Report that the remote terminal is being enabled\r
-  //\r
-  DevicePath = ParentDevicePath;\r
-  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
-    EFI_PROGRESS_CODE,\r
-    EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_ENABLE,\r
-    DevicePath\r
-    );\r
 \r
   //\r
   // Open the Serial I/O Protocol BY_DRIVER.  It might already be started.\r
@@ -222,358 +673,464 @@ TerminalDriverBindingStart (
 \r
   if (Status != EFI_ALREADY_STARTED) {\r
     //\r
-    // If Serial I/O is not already open by this driver, then tag the handle\r
-    // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and\r
-    // StdErrDev variables with the list of possible terminal types on this\r
-    // serial port.\r
+    // the serial I/O protocol never be opened before, it is the first\r
+    // time to start the serial Io controller\r
     //\r
-    Status = gBS->OpenProtocol (\r
-                    Controller,\r
+    FirstEnter = TRUE;\r
+  }\r
+\r
+  //\r
+  // Serial I/O is not already open by this driver, then tag the handle\r
+  // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and\r
+  // StdErrDev variables with the list of possible terminal types on this\r
+  // serial port.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiCallerIdGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &Controller,\r
                     &gEfiCallerIdGuid,\r
-                    NULL,\r
-                    This->DriverBindingHandle,\r
-                    Controller,\r
-                    EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                    DuplicateDevicePath (ParentDevicePath),\r
+                    NULL\r
                     );\r
     if (EFI_ERROR (Status)) {\r
-      Status = gBS->InstallMultipleProtocolInterfaces (\r
-                      &Controller,\r
-                      &gEfiCallerIdGuid,\r
-                      DuplicateDevicePath (ParentDevicePath),\r
-                      NULL\r
-                      );\r
-      if (EFI_ERROR (Status)) {\r
-        goto Error;\r
-      }\r
+      goto Error;\r
+    }\r
+\r
+    if (!IsHotPlugDevice (ParentDevicePath)) {\r
       //\r
       // if the serial device is a hot plug device, do not update the\r
       // ConInDev, ConOutDev, and StdErrDev variables.\r
       //\r
-      Status = gBS->OpenProtocol (\r
-                      Controller,\r
-                      &gEfiHotPlugDeviceGuid,\r
-                      NULL,\r
-                      This->DriverBindingHandle,\r
-                      Controller,\r
-                      EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
-                      );\r
-      if (EFI_ERROR (Status)) {\r
-        TerminalUpdateConsoleDevVariable ((CHAR16 *)VarConsoleInpDev, ParentDevicePath);\r
-        TerminalUpdateConsoleDevVariable ((CHAR16 *)VarConsoleOutDev, ParentDevicePath);\r
-        TerminalUpdateConsoleDevVariable ((CHAR16 *)VarErrorOutDev, ParentDevicePath);\r
-      }\r
+      TerminalUpdateConsoleDevVariable (L"ConInDev", ParentDevicePath);\r
+      TerminalUpdateConsoleDevVariable (L"ConOutDev", ParentDevicePath);\r
+      TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath);\r
     }\r
   }\r
+\r
   //\r
-  // Make sure a child handle does not already exist.  This driver can only\r
-  // produce one child per serial port.\r
+  // Check the requirement for the SimpleTxtIn and SimpleTxtOut protocols\r
   //\r
-  Status = gBS->OpenProtocolInformation (\r
-                  Controller,\r
-                  &gEfiSerialIoProtocolGuid,\r
-                  &OpenInfoBuffer,\r
-                  &EntryCount\r
-                  );\r
-  if (!EFI_ERROR (Status)) {\r
-    Status = EFI_SUCCESS;\r
-    for (Index = 0; Index < EntryCount; Index++) {\r
-      if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {\r
-        Status = EFI_ALREADY_STARTED;\r
-      }\r
-    }\r
+  // Simple In/Out Protocol will not be installed onto the handle if the\r
+  // device path to the handle is not present in the ConIn/ConOut\r
+  // environment variable. But If RemainingDevicePath is NULL, then always\r
+  // produce both Simple In and Simple Text Output Protocols. This is required\r
+  // for the connect all sequences to make sure all possible consoles are\r
+  // produced no matter what the current values of ConIn, ConOut, or StdErr are.\r
+  //\r
+  if (RemainingDevicePath == NULL) {\r
+    NullRemaining = TRUE;\r
+  }\r
 \r
-    FreePool (OpenInfoBuffer);\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
+  DevicePath = BuildTerminalDevpath (ParentDevicePath, RemainingDevicePath);\r
+  if (DevicePath != NULL) {\r
+    ConInSelected  = IsTerminalInConsoleVariable (L"ConIn", DevicePath);\r
+    ConOutSelected = IsTerminalInConsoleVariable (L"ConOut", DevicePath);\r
+    FreePool (DevicePath);\r
+  } else {\r
+    goto Error;\r
   }\r
   //\r
-  // If RemainingDevicePath is NULL, then create default device path node\r
+  // Not create the child terminal handle if both Simple In/In Ex and\r
+  // Simple text Out protocols are not required to be published\r
   //\r
-  if (RemainingDevicePath == NULL) {\r
-    DefaultNode = AllocatePool (sizeof (VENDOR_DEVICE_PATH));\r
-    if (DefaultNode == NULL) {\r
-      Status = EFI_OUT_OF_RESOURCES;\r
-      goto Error;\r
-    }\r
-\r
-    CopyMem (&DefaultNode->Guid, &gEfiPcAnsiGuid, sizeof (EFI_GUID));\r
-    RemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL*) DefaultNode;\r
+  if ((!ConInSelected)&&(!ConOutSelected)&&(!NullRemaining)) {\r
+    goto Error;\r
   }\r
+\r
   //\r
-  // Use the RemainingDevicePath to determine the terminal type\r
+  // create the child terminal handle during first entry\r
   //\r
-  Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;\r
+  if (FirstEnter) {\r
+    //\r
+    // First enther the start function\r
+    //\r
+    FirstEnter = FALSE;\r
+    //\r
+    // Make sure a child handle does not already exist.  This driver can only\r
+    // produce one child per serial port.\r
+    //\r
+    Status = gBS->OpenProtocolInformation (\r
+                    Controller,\r
+                    &gEfiSerialIoProtocolGuid,\r
+                    &OpenInfoBuffer,\r
+                    &EntryCount\r
+                    );\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = EFI_SUCCESS;\r
+      for (Index = 0; Index < EntryCount; Index++) {\r
+        if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
+          Status = EFI_ALREADY_STARTED;\r
+        }\r
+      }\r
 \r
-  if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {\r
+      FreePool (OpenInfoBuffer);\r
+      if (EFI_ERROR (Status)) {\r
+          goto Error;\r
+      }\r
+    }\r
 \r
-    TerminalType = PcAnsiType;\r
+    //\r
+    // If RemainingDevicePath is NULL, use default terminal type\r
+    //\r
+    if (RemainingDevicePath == NULL) {\r
+      TerminalType = PcdGet8 (PcdDefaultTerminalType);\r
+    } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+      //\r
+      // If RemainingDevicePath isn't the End of Device Path Node,\r
+      // Use the RemainingDevicePath to determine the terminal type\r
+      //\r
+      Node = (VENDOR_DEVICE_PATH *)RemainingDevicePath;\r
+      TerminalType = TerminalTypeFromGuid (&Node->Guid);\r
+    } else {\r
+      //\r
+      // If RemainingDevicePath is the End of Device Path Node,\r
+      // skip enumerate any device and return EFI_SUCESSS\r
+      //\r
+      return EFI_SUCCESS;\r
+    }\r
 \r
-  } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {\r
+    ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));\r
 \r
-    TerminalType = VT100Type;\r
+    //\r
+    // Initialize the Terminal Dev\r
+    //\r
+    TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);\r
+    if (TerminalDevice == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Error;\r
+    }\r
 \r
-  } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {\r
+    TerminalDevice->TerminalType  = TerminalType;\r
+    TerminalDevice->SerialIo      = SerialIo;\r
 \r
-    TerminalType = VT100PlusType;\r
+    InitializeListHead (&TerminalDevice->NotifyList);\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_WAIT,\r
+                    TPL_NOTIFY,\r
+                    TerminalConInWaitForKeyEx,\r
+                    TerminalDevice,\r
+                    &TerminalDevice->SimpleInputEx.WaitForKeyEx\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
 \r
-  } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_WAIT,\r
+                    TPL_NOTIFY,\r
+                    TerminalConInWaitForKey,\r
+                    TerminalDevice,\r
+                    &TerminalDevice->SimpleInput.WaitForKey\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+    //\r
+    // Allocates and initializes the FIFO buffer to be zero, used for accommodating\r
+    // the pre-read pending characters.\r
+    //\r
+    TerminalDevice->RawFiFo     = AllocateZeroPool (sizeof (RAW_DATA_FIFO));\r
+    if (TerminalDevice->RawFiFo == NULL) {\r
+      goto Error;\r
+    }\r
+    TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));\r
+    if (TerminalDevice->UnicodeFiFo == NULL) {\r
+      goto Error;\r
+    }\r
+    TerminalDevice->EfiKeyFiFo  = AllocateZeroPool (sizeof (EFI_KEY_FIFO));\r
+    if (TerminalDevice->EfiKeyFiFo == NULL) {\r
+      goto Error;\r
+    }\r
+    TerminalDevice->EfiKeyFiFoForNotify = AllocateZeroPool (sizeof (EFI_KEY_FIFO));\r
+    if (TerminalDevice->EfiKeyFiFoForNotify == NULL) {\r
+      goto Error;\r
+    }\r
 \r
-    TerminalType = VTUTF8Type;\r
+    //\r
+    // Set the timeout value of serial buffer for\r
+    // keystroke response performance issue\r
+    //\r
+    Mode            = TerminalDevice->SerialIo->Mode;\r
 \r
-  } else {\r
-    goto Error;\r
-  }\r
-  //\r
-  // Initialize the Terminal Dev\r
-  //\r
-  TerminalDevice = AllocatePool (sizeof (TERMINAL_DEV));\r
-  if (TerminalDevice == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto Error;\r
-  }\r
+    SerialInTimeOut = 0;\r
+    if (Mode->BaudRate != 0) {\r
+      SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;\r
+    }\r
+\r
+    Status = TerminalDevice->SerialIo->SetAttributes (\r
+                                        TerminalDevice->SerialIo,\r
+                                        Mode->BaudRate,\r
+                                        Mode->ReceiveFifoDepth,\r
+                                        (UINT32) SerialInTimeOut,\r
+                                        (EFI_PARITY_TYPE) (Mode->Parity),\r
+                                        (UINT8) Mode->DataBits,\r
+                                        (EFI_STOP_BITS_TYPE) (Mode->StopBits)\r
+                                        );\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // if set attributes operation fails, invalidate\r
+      // the value of SerialInTimeOut,thus make it\r
+      // inconsistent with the default timeout value\r
+      // of serial buffer. This will invoke the recalculation\r
+      // in the readkeystroke routine.\r
+      //\r
+      TerminalDevice->SerialInTimeOut = 0;\r
+    } else {\r
+      TerminalDevice->SerialInTimeOut = SerialInTimeOut;\r
+    }\r
+    //\r
+    // Set Simple Text Output Protocol from template.\r
+    //\r
+    SimpleTextOutput = CopyMem (\r
+                         &TerminalDevice->SimpleTextOutput,\r
+                         &mTerminalDevTemplate.SimpleTextOutput,\r
+                         sizeof (mTerminalDevTemplate.SimpleTextOutput)\r
+                         );\r
+    SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode;\r
+    \r
+    TerminalDevice->TerminalConsoleModeData = InitializeTerminalConsoleTextMode (\r
+                                                &SimpleTextOutput->Mode->MaxMode\r
+                                                );\r
+    if (TerminalDevice->TerminalConsoleModeData == NULL) {\r
+      goto ReportError;\r
+    }\r
 \r
-  ZeroMem (TerminalDevice, sizeof (TERMINAL_DEV));\r
+    //\r
+    // For terminal devices, cursor is always visible\r
+    //\r
+    TerminalDevice->SimpleTextOutputMode.CursorVisible = TRUE;\r
+    Status = TerminalConOutSetAttribute (\r
+               SimpleTextOutput,\r
+               EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ReportError;\r
+    }\r
 \r
-  TerminalDevice->Signature     = TERMINAL_DEV_SIGNATURE;\r
+    //\r
+    // Build the component name for the child device\r
+    //\r
+    Status = InitializeControllerNameTable (TerminalDevice->TerminalType, &TerminalDevice->ControllerNameTable);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
 \r
-  TerminalDevice->TerminalType  = TerminalType;\r
+    //\r
+    // Build the device path for the child device\r
+    //\r
+    Status = SetTerminalDevicePath (\r
+              TerminalDevice->TerminalType,\r
+              ParentDevicePath,\r
+              &TerminalDevice->DevicePath\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
 \r
-  TerminalDevice->SerialIo      = SerialIo;\r
+    Status = TerminalConOutReset (SimpleTextOutput, FALSE);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ReportError;\r
+    }\r
 \r
-  //\r
-  // Simple Input Protocol\r
-  //\r
-  TerminalDevice->SimpleInput.Reset         = TerminalConInReset;\r
-  TerminalDevice->SimpleInput.ReadKeyStroke = TerminalConInReadKeyStroke;\r
+    Status = TerminalConOutSetMode (SimpleTextOutput, 0);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ReportError;\r
+    }\r
 \r
-  Status = gBS->CreateEvent (\r
-                  EVT_NOTIFY_WAIT,\r
-                  TPL_NOTIFY,\r
-                  TerminalConInWaitForKey,\r
-                  &TerminalDevice->SimpleInput,\r
-                  &TerminalDevice->SimpleInput.WaitForKey\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    goto Error;\r
-  }\r
-  //\r
-  // initialize the FIFO buffer used for accommodating\r
-  // the pre-read pending characters\r
-  //\r
-  InitializeRawFiFo (TerminalDevice);\r
-  InitializeUnicodeFiFo (TerminalDevice);\r
-  InitializeEfiKeyFiFo (TerminalDevice);\r
+    Status = TerminalConOutEnableCursor (SimpleTextOutput, TRUE);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ReportError;\r
+    }\r
 \r
-  //\r
-  // Set the timeout value of serial buffer for\r
-  // keystroke response performance issue\r
-  //\r
-  Mode            = TerminalDevice->SerialIo->Mode;\r
+    StartTerminalStateMachine (TerminalDevice);\r
 \r
-  SerialInTimeOut = 0;\r
-  if (Mode->BaudRate != 0) {\r
-    SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;\r
-  }\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_CALLBACK,\r
+                    KeyNotifyProcessHandler,\r
+                    TerminalDevice,\r
+                    &TerminalDevice->KeyNotifyProcessEvent\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    Status = gBS->InstallProtocolInterface (\r
+                    &TerminalDevice->Handle,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    TerminalDevice->DevicePath\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
 \r
-  Status = TerminalDevice->SerialIo->SetAttributes (\r
-                                      TerminalDevice->SerialIo,\r
-                                      Mode->BaudRate,\r
-                                      Mode->ReceiveFifoDepth,\r
-                                      (UINT32) SerialInTimeOut,\r
-                                      (EFI_PARITY_TYPE) (Mode->Parity),\r
-                                      (UINT8) Mode->DataBits,\r
-                                      (EFI_STOP_BITS_TYPE) (Mode->StopBits)\r
-                                      );\r
-  if (EFI_ERROR (Status)) {\r
     //\r
-    // if set attributes operation fails, invalidate\r
-    // the value of SerialInTimeOut,thus make it\r
-    // inconsistent with the default timeout value\r
-    // of serial buffer. This will invoke the recalculation\r
-    // in the readkeystroke routine.\r
+    // Register the Parent-Child relationship via\r
+    // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
     //\r
-    TerminalDevice->SerialInTimeOut = 0;\r
-  } else {\r
-    TerminalDevice->SerialInTimeOut = SerialInTimeOut;\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &gEfiSerialIoProtocolGuid,\r
+                    (VOID **) &TerminalDevice->SerialIo,\r
+                    This->DriverBindingHandle,\r
+                    TerminalDevice->Handle,\r
+                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
   }\r
+\r
   //\r
-  // Build the device path for the child device\r
+  // Find the child handle, and get its TerminalDevice private data\r
   //\r
-  Status = SetTerminalDevicePath (\r
-            TerminalDevice->TerminalType,\r
-            ParentDevicePath,\r
-            &TerminalDevice->DevicePath\r
-            );\r
-  if (EFI_ERROR (Status)) {\r
-    goto Error;\r
-  }\r
+  Status = gBS->OpenProtocolInformation (\r
+                  Controller,\r
+                  &gEfiSerialIoProtocolGuid,\r
+                  &OpenInfoBuffer,\r
+                  &EntryCount\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = EFI_NOT_FOUND;\r
+    ASSERT (OpenInfoBuffer != NULL);\r
+    for (Index = 0; Index < EntryCount; Index++) {\r
+      if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
+        //\r
+        // Find the child terminal handle.\r
+        // Test whether the SimpleTxtIn and SimpleTxtOut have been published\r
+        //\r
+        Status = gBS->OpenProtocol (\r
+                        OpenInfoBuffer[Index].ControllerHandle,\r
+                        &gEfiSimpleTextInProtocolGuid,\r
+                        (VOID **) &SimpleTextInput,\r
+                        This->DriverBindingHandle,\r
+                        OpenInfoBuffer[Index].ControllerHandle,\r
+                        EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                        );\r
+        if (!EFI_ERROR (Status)) {\r
+          SimTxtInInstalled = TRUE;\r
+          TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);\r
+        }\r
 \r
-  DevicePath = TerminalDevice->DevicePath;\r
+        Status = gBS->OpenProtocol (\r
+                        OpenInfoBuffer[Index].ControllerHandle,\r
+                        &gEfiSimpleTextOutProtocolGuid,\r
+                        (VOID **) &SimpleTextOutput,\r
+                        This->DriverBindingHandle,\r
+                        OpenInfoBuffer[Index].ControllerHandle,\r
+                        EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                        );\r
+        if (!EFI_ERROR (Status)) {\r
+          SimTxtOutInstalled = TRUE;\r
+          TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);\r
+        }\r
+        Status = EFI_SUCCESS;\r
+        break;\r
+      }\r
+    }\r
 \r
-  Status = TerminalDevice->SimpleInput.Reset (\r
-                                        &TerminalDevice->SimpleInput,\r
-                                        FALSE\r
-                                        );\r
-  if (EFI_ERROR (Status)) {\r
-    //\r
-    // Need to report Error Code first\r
-    //\r
+    FreePool (OpenInfoBuffer);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ReportError;\r
+    }\r
+  } else {\r
     goto ReportError;\r
   }\r
-  //\r
-  // Simple Text Output Protocol\r
-  //\r
-  TerminalDevice->SimpleTextOutput.Reset              = TerminalConOutReset;\r
-  TerminalDevice->SimpleTextOutput.OutputString       = TerminalConOutOutputString;\r
-  TerminalDevice->SimpleTextOutput.TestString         = TerminalConOutTestString;\r
-  TerminalDevice->SimpleTextOutput.QueryMode          = TerminalConOutQueryMode;\r
-  TerminalDevice->SimpleTextOutput.SetMode            = TerminalConOutSetMode;\r
-  TerminalDevice->SimpleTextOutput.SetAttribute       = TerminalConOutSetAttribute;\r
-  TerminalDevice->SimpleTextOutput.ClearScreen        = TerminalConOutClearScreen;\r
-  TerminalDevice->SimpleTextOutput.SetCursorPosition  = TerminalConOutSetCursorPosition;\r
-  TerminalDevice->SimpleTextOutput.EnableCursor       = TerminalConOutEnableCursor;\r
-  TerminalDevice->SimpleTextOutput.Mode               = &TerminalDevice->SimpleTextOutputMode;\r
 \r
-  TerminalDevice->SimpleTextOutputMode.MaxMode        = 1;\r
+  ASSERT (TerminalDevice != NULL);\r
   //\r
-  // For terminal devices, cursor is always visible\r
+  // Only do the reset if the device path is in the Conout variable\r
   //\r
-  TerminalDevice->SimpleTextOutputMode.CursorVisible  = TRUE;\r
-  TerminalDevice->SimpleTextOutputMode.Attribute      = EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK);\r
-\r
-  Status = TerminalDevice->SimpleTextOutput.Reset (\r
-                                              &TerminalDevice->SimpleTextOutput,\r
-                                              FALSE\r
-                                              );\r
-  if (EFI_ERROR (Status)) {\r
-    goto ReportError;\r
-  }\r
-\r
-  Status = TerminalDevice->SimpleTextOutput.SetMode (\r
-                                              &TerminalDevice->SimpleTextOutput,\r
-                                              0\r
-                                              );\r
-  if (EFI_ERROR (Status)) {\r
-    goto ReportError;\r
+  if (ConInSelected && !SimTxtInInstalled) {\r
+    Status = TerminalDevice->SimpleInput.Reset (\r
+                                          &TerminalDevice->SimpleInput,\r
+                                          FALSE\r
+                                          );\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Need to report Error Code first\r
+      //\r
+      goto ReportError;\r
+    }\r
   }\r
 \r
-  Status = TerminalDevice->SimpleTextOutput.EnableCursor (\r
-                                              &TerminalDevice->SimpleTextOutput,\r
-                                              TRUE\r
-                                              );\r
-  if (EFI_ERROR (Status)) {\r
-    goto ReportError;\r
-  }\r
   //\r
+  // Only output the configure string to remote terminal if the device path\r
+  // is in the Conout variable\r
   //\r
-  //\r
-  TerminalDevice->InputState  = INPUT_STATE_DEFAULT;\r
-  TerminalDevice->ResetState  = RESET_STATE_DEFAULT;\r
+  if (ConOutSelected && !SimTxtOutInstalled) {\r
+    Status = TerminalDevice->SimpleTextOutput.SetAttribute (\r
+                                                        &TerminalDevice->SimpleTextOutput,\r
+                                                        EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)\r
+                                                        );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ReportError;\r
+    }\r
 \r
-  Status = gBS->CreateEvent (\r
-                  EVT_TIMER,\r
-                  TPL_CALLBACK,\r
-                  NULL,\r
-                  NULL,\r
-                  &TerminalDevice->TwoSecondTimeOut\r
-                  );\r
+    Status = TerminalDevice->SimpleTextOutput.Reset (\r
+                                                &TerminalDevice->SimpleTextOutput,\r
+                                                FALSE\r
+                                                );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ReportError;\r
+    }\r
 \r
-  //\r
-  // Build the component name for the child device\r
-  //\r
-  TerminalDevice->ControllerNameTable = NULL;\r
-  switch (TerminalDevice->TerminalType) {\r
-  case PcAnsiType:\r
-    AddUnicodeString (\r
-      "eng",\r
-      gTerminalComponentName.SupportedLanguages,\r
-      &TerminalDevice->ControllerNameTable,\r
-      (CHAR16 *)L"PC-ANSI Serial Console"\r
-      );\r
-    break;\r
-\r
-  case VT100Type:\r
-    AddUnicodeString (\r
-      "eng",\r
-      gTerminalComponentName.SupportedLanguages,\r
-      &TerminalDevice->ControllerNameTable,\r
-      (CHAR16 *)L"VT-100 Serial Console"\r
-      );\r
-    break;\r
-\r
-  case VT100PlusType:\r
-    AddUnicodeString (\r
-      "eng",\r
-      gTerminalComponentName.SupportedLanguages,\r
-      &TerminalDevice->ControllerNameTable,\r
-      (CHAR16 *)L"VT-100+ Serial Console"\r
-      );\r
-    break;\r
-\r
-  case VTUTF8Type:\r
-    AddUnicodeString (\r
-      "eng",\r
-      gTerminalComponentName.SupportedLanguages,\r
-      &TerminalDevice->ControllerNameTable,\r
-      (CHAR16 *)L"VT-UTF8 Serial Console"\r
-      );\r
-    break;\r
-  }\r
-  //\r
-  // Install protocol interfaces for the serial device.\r
-  //\r
-  Status = gBS->InstallMultipleProtocolInterfaces (\r
-                  &TerminalDevice->Handle,\r
-                  &gEfiDevicePathProtocolGuid,\r
-                  TerminalDevice->DevicePath,\r
-                  &gEfiSimpleTextInProtocolGuid,\r
-                  &TerminalDevice->SimpleInput,\r
-                  &gEfiSimpleTextOutProtocolGuid,\r
-                  &TerminalDevice->SimpleTextOutput,\r
-                  NULL\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    goto Error;\r
+    Status = TerminalDevice->SimpleTextOutput.SetMode (\r
+                                                &TerminalDevice->SimpleTextOutput,\r
+                                                0\r
+                                                );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ReportError;\r
+    }\r
+\r
+    Status = TerminalDevice->SimpleTextOutput.EnableCursor (\r
+                                                &TerminalDevice->SimpleTextOutput,\r
+                                                TRUE\r
+                                                );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ReportError;\r
+    }\r
   }\r
+\r
   //\r
-  // if the serial device is a hot plug device, attaches the HotPlugGuid\r
-  // onto the terminal device handle.\r
+  // Simple In/Out Protocol will not be installed onto the handle if the\r
+  // device path to the handle is not present in the ConIn/ConOut\r
+  // environment variable. But If RemainingDevicePath is NULL, then always\r
+  // produce both Simple In and Simple Text Output Protocols. This is required\r
+  // for the connect all sequences to make sure all possible consoles are\r
+  // produced no matter what the current values of ConIn, ConOut, or StdErr are.\r
   //\r
-  Status = gBS->OpenProtocol (\r
-                  Controller,\r
-                  &gEfiHotPlugDeviceGuid,\r
-                  NULL,\r
-                  This->DriverBindingHandle,\r
-                  Controller,\r
-                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
-                  );\r
-  if (!EFI_ERROR (Status)) {\r
+  if (!SimTxtInInstalled && (ConInSelected || NullRemaining)) {\r
     Status = gBS->InstallMultipleProtocolInterfaces (\r
                     &TerminalDevice->Handle,\r
-                    &gEfiHotPlugDeviceGuid,\r
-                    NULL,\r
+                    &gEfiSimpleTextInProtocolGuid,\r
+                    &TerminalDevice->SimpleInput,\r
+                    &gEfiSimpleTextInputExProtocolGuid,\r
+                    &TerminalDevice->SimpleInputEx,\r
                     NULL\r
                     );\r
-  }\r
-  //\r
-  // Register the Parent-Child relationship via\r
-  // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
-  //\r
-  Status = gBS->OpenProtocol (\r
-                  Controller,\r
-                  &gEfiSerialIoProtocolGuid,\r
-                  (VOID **) &TerminalDevice->SerialIo,\r
-                  This->DriverBindingHandle,\r
-                  TerminalDevice->Handle,\r
-                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    goto Error;\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
   }\r
 \r
-  if (DefaultNode != NULL) {\r
-    FreePool (DefaultNode);\r
+  if (!SimTxtOutInstalled && (ConOutSelected || NullRemaining)) {\r
+    Status = gBS->InstallProtocolInterface (\r
+                    &TerminalDevice->Handle,\r
+                    &gEfiSimpleTextOutProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    &TerminalDevice->SimpleTextOutput\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
   }\r
 \r
   return EFI_SUCCESS;\r
@@ -582,9 +1139,10 @@ ReportError:
   //\r
   // Report error code before exiting\r
   //\r
+  DevicePath = ParentDevicePath;\r
   REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
     EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
-    EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,\r
+    (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),\r
     DevicePath\r
     );\r
 \r
@@ -602,10 +1160,33 @@ Error:
         gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);\r
       }\r
 \r
+      if (TerminalDevice->TimerEvent != NULL) {\r
+        gBS->CloseEvent (TerminalDevice->TimerEvent);\r
+      }\r
+\r
       if (TerminalDevice->SimpleInput.WaitForKey != NULL) {\r
         gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);\r
       }\r
 \r
+      if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {\r
+        gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);\r
+      }\r
+\r
+      TerminalFreeNotifyList (&TerminalDevice->NotifyList);\r
+\r
+      if (TerminalDevice->RawFiFo != NULL) {\r
+        FreePool (TerminalDevice->RawFiFo);\r
+      }\r
+      if (TerminalDevice->UnicodeFiFo != NULL) {\r
+        FreePool (TerminalDevice->UnicodeFiFo);\r
+      }\r
+      if (TerminalDevice->EfiKeyFiFo != NULL) {\r
+        FreePool (TerminalDevice->EfiKeyFiFo);\r
+      }\r
+      if (TerminalDevice->EfiKeyFiFoForNotify != NULL) {\r
+        FreePool (TerminalDevice->EfiKeyFiFoForNotify);\r
+      }\r
+  \r
       if (TerminalDevice->ControllerNameTable != NULL) {\r
         FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);\r
       }\r
@@ -614,19 +1195,34 @@ Error:
         FreePool (TerminalDevice->DevicePath);\r
       }\r
 \r
+      if (TerminalDevice->TerminalConsoleModeData != NULL) {\r
+        FreePool (TerminalDevice->TerminalConsoleModeData);\r
+      }\r
+\r
       FreePool (TerminalDevice);\r
     }\r
   }\r
 \r
-  if (DefaultNode != NULL) {\r
-    FreePool (DefaultNode);\r
-  }\r
-\r
   This->Stop (This, Controller, 0, NULL);\r
 \r
   return Status;\r
 }\r
 \r
+/**\r
+  Stop this driver on Controller by closing Simple Text In, Simple Text\r
+  In Ex, Simple Text Out protocol, and removing parent device path from\r
+  Console Device Environment Variables.\r
+\r
+  @param  This              Protocol instance pointer.\r
+  @param  Controller        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 Controller.\r
+  @retval other             This driver could not be removed from this device.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 TerminalDriverBindingStop (\r
@@ -635,25 +1231,6 @@ TerminalDriverBindingStop (
   IN  UINTN                         NumberOfChildren,\r
   IN  EFI_HANDLE                    *ChildHandleBuffer\r
   )\r
-/*++\r
-\r
-  Routine Description:\r
-\r
-    Stop a device controller.\r
-\r
-  Arguments:\r
-\r
-    This              - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
-    Controller        - A handle to the device being stopped.\r
-    NumberOfChildren  - The number of child device handles in ChildHandleBuffer.\r
-    ChildHandleBuffer - An array of child handles to be freed.\r
-\r
-  Returns:\r
-\r
-    EFI_SUCCESS      - Operation successful.\r
-    EFI_DEVICE_ERROR - Devices error.\r
-\r
---*/\r
 {\r
   EFI_STATUS                       Status;\r
   UINTN                            Index;\r
@@ -672,14 +1249,6 @@ TerminalDriverBindingStop (
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
-  //\r
-  // Report that the remote terminal is being disabled\r
-  //\r
-  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
-    EFI_PROGRESS_CODE,\r
-    EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_DISABLE,\r
-    DevicePath\r
-    );\r
 \r
   //\r
   // Complete all outstanding transactions to Controller.\r
@@ -702,9 +1271,9 @@ TerminalDriverBindingStop (
       // Remove Parent Device Path from\r
       // the Console Device Environment Variables\r
       //\r
-      TerminalRemoveConsoleDevVariable ((CHAR16 *)VarConsoleInpDev, ParentDevicePath);\r
-      TerminalRemoveConsoleDevVariable ((CHAR16 *)VarConsoleOutDev, ParentDevicePath);\r
-      TerminalRemoveConsoleDevVariable ((CHAR16 *)VarErrorOutDev, ParentDevicePath);\r
+      TerminalRemoveConsoleDevVariable (L"ConInDev", ParentDevicePath);\r
+      TerminalRemoveConsoleDevVariable (L"ConOutDev", ParentDevicePath);\r
+      TerminalRemoveConsoleDevVariable (L"ErrOutDev", ParentDevicePath);\r
 \r
       //\r
       // Uninstall the Terminal Driver's GUID Tag from the Serial controller\r
@@ -768,6 +1337,8 @@ TerminalDriverBindingStop (
                       ChildHandleBuffer[Index],\r
                       &gEfiSimpleTextInProtocolGuid,\r
                       &TerminalDevice->SimpleInput,\r
+                      &gEfiSimpleTextInputExProtocolGuid,\r
+                      &TerminalDevice->SimpleInputEx,\r
                       &gEfiSimpleTextOutProtocolGuid,\r
                       &TerminalDevice->SimpleTextOutput,\r
                       &gEfiDevicePathProtocolGuid,\r
@@ -789,28 +1360,15 @@ TerminalDriverBindingStop (
           FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);\r
         }\r
 \r
-        Status = gBS->OpenProtocol (\r
-                        ChildHandleBuffer[Index],\r
-                        &gEfiHotPlugDeviceGuid,\r
-                        NULL,\r
-                        This->DriverBindingHandle,\r
-                        Controller,\r
-                        EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
-                        );\r
-        if (!EFI_ERROR (Status)) {\r
-          Status = gBS->UninstallMultipleProtocolInterfaces (\r
-                          ChildHandleBuffer[Index],\r
-                          &gEfiHotPlugDeviceGuid,\r
-                          NULL,\r
-                          NULL\r
-                          );\r
-        } else {\r
-          Status = EFI_SUCCESS;\r
-        }\r
-\r
-        gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);\r
+        StopTerminalStateMachine (TerminalDevice);\r
         gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);\r
+        gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);\r
+        gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);\r
+        TerminalFreeNotifyList (&TerminalDevice->NotifyList);\r
         FreePool (TerminalDevice->DevicePath);\r
+        if (TerminalDevice->TerminalConsoleModeData != NULL) {\r
+          FreePool (TerminalDevice->TerminalConsoleModeData);\r
+        }\r
         FreePool (TerminalDevice);\r
       }\r
     }\r
@@ -827,6 +1385,13 @@ TerminalDriverBindingStop (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Update terminal device path in Console Device Environment Variables.\r
+\r
+  @param  VariableName           The Console Device Environment Variable.\r
+  @param  ParentDevicePath       The terminal device path to be updated.\r
+\r
+**/\r
 VOID\r
 TerminalUpdateConsoleDevVariable (\r
   IN CHAR16                    *VariableName,\r
@@ -834,28 +1399,29 @@ TerminalUpdateConsoleDevVariable (
   )\r
 {\r
   EFI_STATUS                Status;\r
+  UINTN                     NameSize;\r
   UINTN                     VariableSize;\r
-  UINT8                     TerminalType;\r
+  TERMINAL_TYPE             TerminalType;\r
   EFI_DEVICE_PATH_PROTOCOL  *Variable;\r
   EFI_DEVICE_PATH_PROTOCOL  *NewVariable;\r
   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;\r
-\r
-  Variable = NULL;\r
+  EDKII_SET_VARIABLE_STATUS *SetVariableStatus;\r
 \r
   //\r
   // Get global variable and its size according to the name given.\r
   //\r
-  Variable = TerminalGetVariableAndSize (\r
-              VariableName,\r
-              &gEfiGlobalVariableGuid,\r
-              &VariableSize\r
-              );\r
+  GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);\r
+  if (Variable == NULL) {\r
+    return;\r
+  }\r
+\r
   //\r
   // Append terminal device path onto the variable.\r
   //\r
-  for (TerminalType = PcAnsiType; TerminalType <= VTUTF8Type; TerminalType++) {\r
+  for (TerminalType = 0; TerminalType < ARRAY_SIZE (mTerminalType); TerminalType++) {\r
     SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);\r
     NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);\r
+    ASSERT (NewVariable != NULL);\r
     if (Variable != NULL) {\r
       FreePool (Variable);\r
     }\r
@@ -876,38 +1442,58 @@ TerminalUpdateConsoleDevVariable (
                   VariableSize,\r
                   Variable\r
                   );\r
-  ASSERT_EFI_ERROR (Status);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    NameSize = StrSize (VariableName);\r
+    SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize);\r
+    if (SetVariableStatus != NULL) {\r
+      CopyGuid (&SetVariableStatus->Guid, &gEfiGlobalVariableGuid);\r
+      SetVariableStatus->NameSize   = NameSize;\r
+      SetVariableStatus->DataSize   = VariableSize;\r
+      SetVariableStatus->SetStatus  = Status;\r
+      SetVariableStatus->Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
+      CopyMem (SetVariableStatus + 1,                          VariableName, NameSize);\r
+      CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Variable,     VariableSize);\r
+\r
+      REPORT_STATUS_CODE_EX (\r
+        EFI_ERROR_CODE,\r
+        PcdGet32 (PcdErrorCodeSetVariable),\r
+        0,\r
+        NULL,\r
+        &gEdkiiStatusCodeDataTypeVariableGuid,\r
+        SetVariableStatus,\r
+        sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize\r
+        );\r
+\r
+      FreePool (SetVariableStatus);\r
+    }\r
+  }\r
+\r
   FreePool (Variable);\r
 \r
   return ;\r
 }\r
 \r
+\r
+/**\r
+  Remove terminal device path from Console Device Environment Variables.\r
+\r
+  @param  VariableName           Console Device Environment Variables.\r
+  @param  ParentDevicePath       The terminal device path to be updated.\r
+\r
+**/\r
 VOID\r
 TerminalRemoveConsoleDevVariable (\r
   IN CHAR16                    *VariableName,\r
   IN EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath\r
   )\r
-/*++\r
-\r
-  Routine Description:\r
-\r
-    Remove console device variable.\r
-\r
-  Arguments:\r
-\r
-    VariableName     - A pointer to the variable name.\r
-    ParentDevicePath - A pointer to the parent device path.\r
-\r
-  Returns:\r
-\r
---*/\r
 {\r
   EFI_STATUS                Status;\r
   BOOLEAN                   FoundOne;\r
   BOOLEAN                   Match;\r
   UINTN                     VariableSize;\r
   UINTN                     InstanceSize;\r
-  UINT8                     TerminalType;\r
+  TERMINAL_TYPE             TerminalType;\r
   EFI_DEVICE_PATH_PROTOCOL  *Instance;\r
   EFI_DEVICE_PATH_PROTOCOL  *Variable;\r
   EFI_DEVICE_PATH_PROTOCOL  *OriginalVariable;\r
@@ -915,17 +1501,12 @@ TerminalRemoveConsoleDevVariable (
   EFI_DEVICE_PATH_PROTOCOL  *SavedNewVariable;\r
   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;\r
 \r
-  Variable  = NULL;\r
   Instance  = NULL;\r
 \r
   //\r
   // Get global variable and its size according to the name given.\r
   //\r
-  Variable = TerminalGetVariableAndSize (\r
-              VariableName,\r
-              &gEfiGlobalVariableGuid,\r
-              &VariableSize\r
-              );\r
+  GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);\r
   if (Variable == NULL) {\r
     return ;\r
   }\r
@@ -950,12 +1531,12 @@ TerminalRemoveConsoleDevVariable (
     // Loop through all the terminal types that this driver supports\r
     //\r
     Match = FALSE;\r
-    for (TerminalType = PcAnsiType; TerminalType <= VTUTF8Type; TerminalType++) {\r
+    for (TerminalType = 0; TerminalType < ARRAY_SIZE (mTerminalType); TerminalType++) {\r
 \r
       SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);\r
 \r
       //\r
-      // Compare the genterated device path to the current device path instance\r
+      // Compare the generated device path to the current device path instance\r
       //\r
       if (TempDevicePath != NULL) {\r
         if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {\r
@@ -995,6 +1576,9 @@ TerminalRemoveConsoleDevVariable (
                     VariableSize,\r
                     NewVariable\r
                     );\r
+    //\r
+    // Shrinking variable with existing variable driver implementation shouldn't fail.\r
+    //\r
     ASSERT_EFI_ERROR (Status);\r
   }\r
 \r
@@ -1005,148 +1589,35 @@ TerminalRemoveConsoleDevVariable (
   return ;\r
 }\r
 \r
-VOID *\r
-TerminalGetVariableAndSize (\r
-  IN  CHAR16              *Name,\r
-  IN  EFI_GUID            *VendorGuid,\r
-  OUT UINTN               *VariableSize\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-  Read the EFI variable (VendorGuid/Name) and return a dynamically allocated\r
-  buffer, and the size of the buffer. On failure return NULL.\r
-\r
-Arguments:\r
-  Name       - String part of EFI variable name\r
-\r
-  VendorGuid - GUID part of EFI variable name\r
+/**\r
+  Build terminal device path according to terminal type.\r
 \r
-  VariableSize - Returns the size of the EFI variable that was read\r
+  @param  TerminalType           The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.\r
+  @param  ParentDevicePath       Parent device path.\r
+  @param  TerminalDevicePath     Returned terminal device path, if building successfully.\r
 \r
-Returns:\r
-  Dynamically allocated memory that contains a copy of the EFI variable.\r
-  Caller is repsoncible freeing the buffer.\r
-\r
-  NULL - Variable was not read\r
-\r
---*/\r
-{\r
-  EFI_STATUS  Status;\r
-  UINTN       BufferSize;\r
-  VOID        *Buffer;\r
-\r
-  Buffer = NULL;\r
-\r
-  //\r
-  // Pass in a small size buffer to find the actual variable size.\r
-  //\r
-  BufferSize  = 1;\r
-  Buffer      = AllocatePool (BufferSize);\r
-  if (Buffer == NULL) {\r
-    *VariableSize = 0;\r
-    return NULL;\r
-  }\r
-\r
-  Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
-\r
-  if (Status == EFI_SUCCESS) {\r
-    *VariableSize = BufferSize;\r
-    return Buffer;\r
-\r
-  } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
-    //\r
-    // Allocate the buffer to return\r
-    //\r
-    FreePool (Buffer);\r
-    Buffer = AllocatePool (BufferSize);\r
-    if (Buffer == NULL) {\r
-      *VariableSize = 0;\r
-      return NULL;\r
-    }\r
-    //\r
-    // Read variable into the allocated buffer.\r
-    //\r
-    Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
-    if (EFI_ERROR (Status)) {\r
-      BufferSize = 0;\r
-      FreePool (Buffer);\r
-      Buffer = NULL;\r
-    }\r
-  } else {\r
-    //\r
-    // Variable not found or other errors met.\r
-    //\r
-    BufferSize = 0;\r
-    FreePool (Buffer);\r
-    Buffer = NULL;\r
-  }\r
-\r
-  *VariableSize = BufferSize;\r
-  return Buffer;\r
-}\r
+  @retval EFI_UNSUPPORTED        Terminal does not belong to the supported type.\r
+  @retval EFI_OUT_OF_RESOURCES   Generate terminal device path failed.\r
+  @retval EFI_SUCCESS            Build terminal device path successfully.\r
 \r
+**/\r
 EFI_STATUS\r
 SetTerminalDevicePath (\r
-  IN  UINT8                       TerminalType,\r
+  IN  TERMINAL_TYPE               TerminalType,\r
   IN  EFI_DEVICE_PATH_PROTOCOL    *ParentDevicePath,\r
   OUT EFI_DEVICE_PATH_PROTOCOL    **TerminalDevicePath\r
   )\r
 {\r
   VENDOR_DEVICE_PATH  Node;\r
 \r
-  *TerminalDevicePath = NULL;\r
+  ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));\r
   Node.Header.Type    = MESSAGING_DEVICE_PATH;\r
   Node.Header.SubType = MSG_VENDOR_DP;\r
+  SetDevicePathNodeLength (&Node, sizeof (VENDOR_DEVICE_PATH));\r
+  CopyGuid (&Node.Guid, mTerminalType[TerminalType]);\r
 \r
   //\r
-  // generate terminal device path node according to terminal type.\r
-  //\r
-  switch (TerminalType) {\r
-\r
-  case PcAnsiType:\r
-    CopyMem (\r
-      &Node.Guid,\r
-      &gEfiPcAnsiGuid,\r
-      sizeof (EFI_GUID)\r
-      );\r
-    break;\r
-\r
-  case VT100Type:\r
-    CopyMem (\r
-      &Node.Guid,\r
-      &gEfiVT100Guid,\r
-      sizeof (EFI_GUID)\r
-      );\r
-    break;\r
-\r
-  case VT100PlusType:\r
-    CopyMem (\r
-      &Node.Guid,\r
-      &gEfiVT100PlusGuid,\r
-      sizeof (EFI_GUID)\r
-      );\r
-    break;\r
-\r
-  case VTUTF8Type:\r
-    CopyMem (\r
-      &Node.Guid,\r
-      &gEfiVTUTF8Guid,\r
-      sizeof (EFI_GUID)\r
-      );\r
-    break;\r
-\r
-  default:\r
-    return EFI_UNSUPPORTED;\r
-    break;\r
-  }\r
-\r
-  SetDevicePathNodeLength (\r
-    &Node.Header,\r
-    sizeof (VENDOR_DEVICE_PATH)\r
-    );\r
-  //\r
-  // append the terminal node onto parent device path\r
+  // Append the terminal node onto parent device path\r
   // to generate a complete terminal device path.\r
   //\r
   *TerminalDevicePath = AppendDevicePathNode (\r
@@ -1160,35 +1631,85 @@ SetTerminalDevicePath (
   return EFI_SUCCESS;\r
 }\r
 \r
-VOID\r
-InitializeRawFiFo (\r
-  IN  TERMINAL_DEV  *TerminalDevice\r
-  )\r
-{\r
-  //\r
-  // Make the raw fifo empty.\r
-  //\r
-  TerminalDevice->RawFiFo.Head = TerminalDevice->RawFiFo.Tail;\r
-}\r
+/**\r
+  The user Entry Point for module Terminal. The user code starts with this function.\r
 \r
-VOID\r
-InitializeUnicodeFiFo (\r
-  IN  TERMINAL_DEV  *TerminalDevice\r
+  @param  ImageHandle    The firmware allocated handle for the EFI image.\r
+  @param  SystemTable    A pointer to the EFI System Table.\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
+InitializeTerminal(\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
   )\r
 {\r
+  EFI_STATUS              Status;\r
+\r
   //\r
-  // Make the unicode fifo empty\r
+  // Install driver model protocol(s).\r
   //\r
-  TerminalDevice->UnicodeFiFo.Head = TerminalDevice->UnicodeFiFo.Tail;\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gTerminalDriverBinding,\r
+             ImageHandle,\r
+             &gTerminalComponentName,\r
+             &gTerminalComponentName2\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
 }\r
 \r
-VOID\r
-InitializeEfiKeyFiFo (\r
-  IN  TERMINAL_DEV  *TerminalDevice\r
+/**\r
+  Check if the device supports hot-plug through its device path.\r
+\r
+  This function could be updated to check more types of Hot Plug devices.\r
+  Currently, it checks USB and PCCard device.\r
+\r
+  @param  DevicePath            Pointer to device's device path.\r
+\r
+  @retval TRUE                  The devcie is a hot-plug device\r
+  @retval FALSE                 The devcie is not a hot-plug device.\r
+\r
+**/\r
+BOOLEAN\r
+IsHotPlugDevice (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath\r
   )\r
 {\r
-  //\r
-  // Make the efi key fifo empty\r
-  //\r
-  TerminalDevice->EfiKeyFiFo.Head = TerminalDevice->EfiKeyFiFo.Tail;\r
+  EFI_DEVICE_PATH_PROTOCOL     *CheckDevicePath;\r
+\r
+  CheckDevicePath = DevicePath;\r
+  while (!IsDevicePathEnd (CheckDevicePath)) {\r
+    //\r
+    // Check device whether is hot plug device or not throught Device Path\r
+    //\r
+    if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&\r
+        (DevicePathSubType (CheckDevicePath) == MSG_USB_DP ||\r
+         DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP ||\r
+         DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) {\r
+      //\r
+      // If Device is USB device\r
+      //\r
+      return TRUE;\r
+    }\r
+    if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&\r
+        (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) {\r
+      //\r
+      // If Device is PCCard\r
+      //\r
+      return TRUE;\r
+    }\r
+\r
+    CheckDevicePath = NextDevicePathNode (CheckDevicePath);\r
+  }\r
+\r
+  return FALSE;\r
 }\r
+\r