]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
MdeModulePkg/TerminalDxe: Avoid always append device path to *Dev
[mirror_edk2.git] / MdeModulePkg / Universal / Console / TerminalDxe / Terminal.c
index 604bda73af7e24061447a58a1edc58a746264188..60de2d4d6db2b09f8937226465ca98e9c2660d21 100644 (file)
@@ -264,154 +264,6 @@ TerminalDriverBindingSupported (
   return Status;\r
 }\r
 \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
-BuildTerminalDevpath  (\r
-  IN EFI_DEVICE_PATH_PROTOCOL       *ParentDevicePath,\r
-  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\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
@@ -466,11 +318,6 @@ InitializeTerminalConsoleTextMode (
 \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
@@ -616,31 +463,19 @@ TerminalDriverBindingStart (
   EFI_STATUS                          Status;\r
   EFI_SERIAL_IO_PROTOCOL              *SerialIo;\r
   EFI_DEVICE_PATH_PROTOCOL            *ParentDevicePath;\r
-  VENDOR_DEVICE_PATH                  *Node;\r
+  EFI_DEVICE_PATH_PROTOCOL            *Vendor;\r
+  EFI_HANDLE                          SerialIoHandle;\r
   EFI_SERIAL_IO_MODE                  *Mode;\r
   UINTN                               SerialInTimeOut;\r
   TERMINAL_DEV                        *TerminalDevice;\r
-  TERMINAL_TYPE                       TerminalType;\r
+  UINT8                               TerminalType;\r
   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
   UINTN                               EntryCount;\r
   UINTN                               Index;\r
-  EFI_DEVICE_PATH_PROTOCOL            *DevicePath;\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
+  EFI_UNICODE_STRING_TABLE            *ControllerNameTable;\r
+\r
   //\r
   // Get the Device Path Protocol to build the device path of the child device\r
   //\r
@@ -652,9 +487,7 @@ TerminalDriverBindingStart (
                   Controller,\r
                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
                   );\r
-  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
-    return Status;\r
-  }\r
+  ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));\r
 \r
   //\r
   // Open the Serial I/O Protocol BY_DRIVER.  It might already be started.\r
@@ -667,95 +500,37 @@ TerminalDriverBindingStart (
                   Controller,\r
                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
                   );\r
-  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
-    return Status;\r
-  }\r
+  ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));\r
 \r
-  if (Status != EFI_ALREADY_STARTED) {\r
+  if (!IsHotPlugDevice (ParentDevicePath)) {\r
     //\r
-    // the serial I/O protocol never be opened before, it is the first\r
-    // time to start the serial Io controller\r
+    // if the serial device is a hot plug device, do not update the\r
+    // ConInDev, ConOutDev, and StdErrDev variables.\r
     //\r
-    FirstEnter = TRUE;\r
+    TerminalUpdateConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);\r
+    TerminalUpdateConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
+    TerminalUpdateConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\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
+  // Do not create any child for END remaining device path.\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
-                    DuplicateDevicePath (ParentDevicePath),\r
-                    NULL\r
-                    );\r
-    if (EFI_ERROR (Status)) {\r
-      goto Error;\r
-    }\r
+  if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {\r
+    return EFI_SUCCESS;\r
+  }\r
 \r
-    if (!IsHotPlugDevice (ParentDevicePath)) {\r
+  if (Status == EFI_ALREADY_STARTED) {\r
+\r
+    if (RemainingDevicePath == NULL) {\r
       //\r
-      // if the serial device is a hot plug device, do not update the\r
-      // ConInDev, ConOutDev, and StdErrDev variables.\r
+      // If RemainingDevicePath is NULL or is the End of Device Path Node\r
       //\r
-      TerminalUpdateConsoleDevVariable (L"ConInDev", ParentDevicePath);\r
-      TerminalUpdateConsoleDevVariable (L"ConOutDev", ParentDevicePath);\r
-      TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath);\r
+      return EFI_SUCCESS;\r
     }\r
-  }\r
-\r
-  //\r
-  // Check the requirement for the SimpleTxtIn and SimpleTxtOut protocols\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
-  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
-  // 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 ((!ConInSelected)&&(!ConOutSelected)&&(!NullRemaining)) {\r
-    goto Error;\r
-  }\r
-\r
-  //\r
-  // create the child terminal handle during first entry\r
-  //\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
+    // This driver can only produce one child per serial port.\r
+    // Change its terminal type as remaining device path requests.\r
     //\r
     Status = gBS->OpenProtocolInformation (\r
                     Controller,\r
@@ -764,447 +539,312 @@ TerminalDriverBindingStart (
                     &EntryCount\r
                     );\r
     if (!EFI_ERROR (Status)) {\r
-      Status = EFI_SUCCESS;\r
+      Status = EFI_NOT_FOUND;\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
+          Status = gBS->OpenProtocol (\r
+                          OpenInfoBuffer[Index].ControllerHandle,\r
+                          &gEfiSimpleTextInProtocolGuid,\r
+                          (VOID **) &SimpleTextInput,\r
+                          This->DriverBindingHandle,\r
+                          Controller,\r
+                          EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                          );\r
+          if (!EFI_ERROR (Status)) {\r
+            TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);\r
+            TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *) RemainingDevicePath)->Guid);\r
+            ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));\r
+            if (TerminalDevice->TerminalType != TerminalType) {\r
+              Status = InitializeControllerNameTable (TerminalType, &ControllerNameTable);\r
+              if (!EFI_ERROR (Status)) {\r
+                StopTerminalStateMachine (TerminalDevice);\r
+                //\r
+                // Update the device path\r
+                //\r
+                Vendor = TerminalDevice->DevicePath;\r
+                Status = gBS->LocateDevicePath (&gEfiSerialIoProtocolGuid, &Vendor, &SerialIoHandle);\r
+                ASSERT_EFI_ERROR (Status);\r
+                CopyGuid (&((VENDOR_DEVICE_PATH *) Vendor)->Guid, mTerminalType[TerminalType]);\r
+                Status = gBS->ReinstallProtocolInterface (\r
+                                TerminalDevice->Handle,\r
+                                &gEfiDevicePathProtocolGuid,\r
+                                TerminalDevice->DevicePath,\r
+                                TerminalDevice->DevicePath\r
+                                );\r
+                if (!EFI_ERROR (Status)) {\r
+                  TerminalDevice->TerminalType = TerminalType;\r
+                  StartTerminalStateMachine (TerminalDevice);\r
+                  FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);\r
+                  TerminalDevice->ControllerNameTable = ControllerNameTable;\r
+                } else {\r
+                  //\r
+                  // Restore the device path on failure\r
+                  //\r
+                  CopyGuid (&((VENDOR_DEVICE_PATH *) Vendor)->Guid, mTerminalType[TerminalDevice->TerminalType]);\r
+                  FreeUnicodeStringTable (ControllerNameTable);\r
+                }\r
+              }\r
+            }\r
+          }\r
+          break;\r
         }\r
       }\r
-\r
       FreePool (OpenInfoBuffer);\r
-      if (EFI_ERROR (Status)) {\r
-          goto Error;\r
-      }\r
-    }\r
-\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
-    ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));\r
-\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
-    TerminalDevice->TerminalType  = TerminalType;\r
-    TerminalDevice->SerialIo      = SerialIo;\r
-\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
-    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
-    //\r
-    // Set the timeout value of serial buffer for\r
-    // keystroke response performance issue\r
-    //\r
-    Mode            = TerminalDevice->SerialIo->Mode;\r
-\r
-    SerialInTimeOut = 0;\r
-    if (Mode->BaudRate != 0) {\r
-      SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;\r
     }\r
+    return Status;\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
+  // Initialize the Terminal Dev\r
+  //\r
+  TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);\r
+  if (TerminalDevice == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto CloseProtocols;\r
+  }\r
 \r
+  if (RemainingDevicePath == NULL) {\r
     //\r
-    // For terminal devices, cursor is always visible\r
+    // If RemainingDevicePath is NULL, use default terminal type\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->TerminalType = PcdGet8 (PcdDefaultTerminalType);\r
+  } else {\r
     //\r
-    // Build the component name for the child device\r
+    // End of Device Path Node is handled in above.\r
     //\r
-    Status = InitializeControllerNameTable (TerminalDevice->TerminalType, &TerminalDevice->ControllerNameTable);\r
-    if (EFI_ERROR (Status)) {\r
-      goto Error;\r
-    }\r
-\r
+    ASSERT (!IsDevicePathEnd (RemainingDevicePath));\r
     //\r
-    // Build the device path for the child device\r
+    // If RemainingDevicePath isn't the End of Device Path Node,\r
+    // Use the RemainingDevicePath to determine the terminal type\r
     //\r
-    Status = SetTerminalDevicePath (\r
-              TerminalDevice->TerminalType,\r
-              ParentDevicePath,\r
-              &TerminalDevice->DevicePath\r
-              );\r
-    if (EFI_ERROR (Status)) {\r
-      goto Error;\r
-    }\r
-\r
-    Status = TerminalConOutReset (SimpleTextOutput, FALSE);\r
-    if (EFI_ERROR (Status)) {\r
-      goto ReportError;\r
-    }\r
-\r
-    Status = TerminalConOutSetMode (SimpleTextOutput, 0);\r
-    if (EFI_ERROR (Status)) {\r
-      goto ReportError;\r
-    }\r
+    TerminalDevice->TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *) RemainingDevicePath)->Guid);\r
+  }\r
+  ASSERT (TerminalDevice->TerminalType < ARRAY_SIZE (mTerminalType));\r
+  TerminalDevice->SerialIo = SerialIo;\r
 \r
-    Status = TerminalConOutEnableCursor (SimpleTextOutput, TRUE);\r
-    if (EFI_ERROR (Status)) {\r
-      goto ReportError;\r
-    }\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 FreeResources;\r
+  }\r
 \r
-    StartTerminalStateMachine (TerminalDevice);\r
+  //\r
+  // Build the device path for the child device\r
+  //\r
+  Status = SetTerminalDevicePath (TerminalDevice->TerminalType, ParentDevicePath, &TerminalDevice->DevicePath);\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreeResources;\r
+  }\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
+  InitializeListHead (&TerminalDevice->NotifyList);\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_WAIT,\r
+                  TPL_NOTIFY,\r
+                  TerminalConInWaitForKeyEx,\r
+                  TerminalDevice,\r
+                  &TerminalDevice->SimpleInputEx.WaitForKeyEx\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
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_WAIT,\r
+                  TPL_NOTIFY,\r
+                  TerminalConInWaitForKey,\r
+                  TerminalDevice,\r
+                  &TerminalDevice->SimpleInput.WaitForKey\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\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
-    //\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
-    }\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 FreeResources;\r
+  }\r
+  TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));\r
+  if (TerminalDevice->UnicodeFiFo == NULL) {\r
+    goto FreeResources;\r
+  }\r
+  TerminalDevice->EfiKeyFiFo = AllocateZeroPool (sizeof (EFI_KEY_FIFO));\r
+  if (TerminalDevice->EfiKeyFiFo == NULL) {\r
+    goto FreeResources;\r
+  }\r
+  TerminalDevice->EfiKeyFiFoForNotify = AllocateZeroPool (sizeof (EFI_KEY_FIFO));\r
+  if (TerminalDevice->EfiKeyFiFoForNotify == NULL) {\r
+    goto FreeResources;\r
   }\r
 \r
   //\r
-  // Find the child handle, and get its TerminalDevice private data\r
+  // Set the timeout value of serial buffer for keystroke response performance issue\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
+  Mode = TerminalDevice->SerialIo->Mode;\r
 \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
+  SerialInTimeOut = 0;\r
+  if (Mode->BaudRate != 0) {\r
+    SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;\r
+  }\r
 \r
-    FreePool (OpenInfoBuffer);\r
-    if (EFI_ERROR (Status)) {\r
-      goto ReportError;\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
-    goto ReportError;\r
+    TerminalDevice->SerialInTimeOut = SerialInTimeOut;\r
   }\r
 \r
-  ASSERT (TerminalDevice != NULL);\r
+  SimpleTextOutput = &TerminalDevice->SimpleTextOutput;\r
+  SimpleTextInput = &TerminalDevice->SimpleInput;\r
+\r
   //\r
-  // Only do the reset if the device path is in the Conout variable\r
+  // Initialize SimpleTextOut instance\r
   //\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
+  SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode;\r
+  TerminalDevice->TerminalConsoleModeData = InitializeTerminalConsoleTextMode (\r
+    &SimpleTextOutput->Mode->MaxMode\r
+  );\r
+  if (TerminalDevice->TerminalConsoleModeData == NULL) {\r
+    goto FreeResources;\r
   }\r
-\r
   //\r
-  // Only output the configure string to remote terminal if the device path\r
-  // is in the Conout variable\r
+  // For terminal devices, cursor is always visible\r
   //\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 = 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
-    }\r
-\r
-    Status = TerminalDevice->SimpleTextOutput.EnableCursor (\r
-                                                &TerminalDevice->SimpleTextOutput,\r
-                                                TRUE\r
-                                                );\r
-    if (EFI_ERROR (Status)) {\r
-      goto ReportError;\r
-    }\r
+  SimpleTextOutput->Mode->CursorVisible = TRUE;\r
+  Status = SimpleTextOutput->SetAttribute (SimpleTextOutput, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = SimpleTextOutput->Reset (SimpleTextOutput, FALSE);\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    goto ReportError;\r
   }\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
+  // Initialize SimpleTextInput instance\r
   //\r
-  if (!SimTxtInInstalled && (ConInSelected || NullRemaining)) {\r
-    Status = gBS->InstallMultipleProtocolInterfaces (\r
-                    &TerminalDevice->Handle,\r
-                    &gEfiSimpleTextInProtocolGuid,\r
-                    &TerminalDevice->SimpleInput,\r
-                    &gEfiSimpleTextInputExProtocolGuid,\r
-                    &TerminalDevice->SimpleInputEx,\r
-                    NULL\r
-                    );\r
-    if (EFI_ERROR (Status)) {\r
-      goto Error;\r
-    }\r
+  Status = SimpleTextInput->Reset (SimpleTextInput, FALSE);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ReportError;\r
   }\r
 \r
-  if (!SimTxtOutInstalled && (ConOutSelected || NullRemaining)) {\r
-    Status = gBS->InstallProtocolInterface (\r
-                    &TerminalDevice->Handle,\r
-                    &gEfiSimpleTextOutProtocolGuid,\r
-                    EFI_NATIVE_INTERFACE,\r
-                    &TerminalDevice->SimpleTextOutput\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &TerminalDevice->Handle,\r
+                  &gEfiSimpleTextInProtocolGuid,      &TerminalDevice->SimpleInput,\r
+                  &gEfiSimpleTextInputExProtocolGuid, &TerminalDevice->SimpleInputEx,\r
+                  &gEfiSimpleTextOutProtocolGuid,     &TerminalDevice->SimpleTextOutput,\r
+                  &gEfiDevicePathProtocolGuid,        TerminalDevice->DevicePath,\r
+                  NULL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\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
+    ASSERT_EFI_ERROR (Status);\r
+    StartTerminalStateMachine (TerminalDevice);\r
+    return Status;\r
   }\r
 \r
-  return EFI_SUCCESS;\r
-\r
 ReportError:\r
-  //\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_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),\r
-    DevicePath\r
+    ParentDevicePath\r
     );\r
 \r
-Error:\r
-  //\r
-  // Use the Stop() function to free all resources allocated in Start()\r
-  //\r
-  if (TerminalDevice != NULL) {\r
-\r
-    if (TerminalDevice->Handle != NULL) {\r
-      This->Stop (This, Controller, 1, &TerminalDevice->Handle);\r
-    } else {\r
-\r
-      if (TerminalDevice->TwoSecondTimeOut != NULL) {\r
-        gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);\r
-      }\r
+FreeResources:\r
+  ASSERT (TerminalDevice != NULL);\r
 \r
-      if (TerminalDevice->TimerEvent != NULL) {\r
-        gBS->CloseEvent (TerminalDevice->TimerEvent);\r
-      }\r
+  if (TerminalDevice->SimpleInput.WaitForKey != NULL) {\r
+    gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);\r
+  }\r
+  if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {\r
+    gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);\r
+  }\r
+  if (TerminalDevice->KeyNotifyProcessEvent != NULL) {\r
+    gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);\r
+  }\r
 \r
-      if (TerminalDevice->SimpleInput.WaitForKey != NULL) {\r
-        gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);\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->SimpleInputEx.WaitForKeyEx != NULL) {\r
-        gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);\r
-      }\r
+  if (TerminalDevice->ControllerNameTable != NULL) {\r
+    FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);\r
+  }\r
 \r
-      TerminalFreeNotifyList (&TerminalDevice->NotifyList);\r
+  if (TerminalDevice->DevicePath != NULL) {\r
+    FreePool (TerminalDevice->DevicePath);\r
+  }\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
+  if (TerminalDevice->TerminalConsoleModeData != NULL) {\r
+    FreePool (TerminalDevice->TerminalConsoleModeData);\r
+  }\r
 \r
-      if (TerminalDevice->DevicePath != NULL) {\r
-        FreePool (TerminalDevice->DevicePath);\r
-      }\r
+  FreePool (TerminalDevice);\r
 \r
-      if (TerminalDevice->TerminalConsoleModeData != NULL) {\r
-        FreePool (TerminalDevice->TerminalConsoleModeData);\r
-      }\r
+CloseProtocols:\r
 \r
-      FreePool (TerminalDevice);\r
-    }\r
-  }\r
+  //\r
+  // Remove Parent Device Path from\r
+  // the Console Device Environment Variables\r
+  //\r
+  TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);\r
+  TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
+  TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
 \r
-  This->Stop (This, Controller, 0, NULL);\r
+  Status = gBS->CloseProtocol (\r
+                  Controller,\r
+                  &gEfiSerialIoProtocolGuid,\r
+                  This->DriverBindingHandle,\r
+                  Controller\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
+  Status = gBS->CloseProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  This->DriverBindingHandle,\r
+                  Controller\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
   return Status;\r
 }\r
 \r
@@ -1239,16 +879,6 @@ TerminalDriverBindingStop (
   TERMINAL_DEV                     *TerminalDevice;\r
   EFI_DEVICE_PATH_PROTOCOL         *ParentDevicePath;\r
   EFI_SERIAL_IO_PROTOCOL           *SerialIo;\r
-  EFI_DEVICE_PATH_PROTOCOL         *DevicePath;\r
-\r
-  Status = gBS->HandleProtocol (\r
-                  Controller,\r
-                  &gEfiDevicePathProtocolGuid,\r
-                  (VOID **) &DevicePath\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
 \r
   //\r
   // Complete all outstanding transactions to Controller.\r
@@ -1260,38 +890,21 @@ TerminalDriverBindingStop (
     //\r
     Status = gBS->OpenProtocol (\r
                     Controller,\r
-                    &gEfiCallerIdGuid,\r
+                    &gEfiDevicePathProtocolGuid,\r
                     (VOID **) &ParentDevicePath,\r
                     This->DriverBindingHandle,\r
                     Controller,\r
                     EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
                     );\r
-    if (!EFI_ERROR (Status)) {\r
-      //\r
-      // Remove Parent Device Path from\r
-      // the Console Device Environment Variables\r
-      //\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
-      //\r
-      Status = gBS->UninstallMultipleProtocolInterfaces (\r
-                      Controller,\r
-                      &gEfiCallerIdGuid,\r
-                      ParentDevicePath,\r
-                      NULL\r
-                      );\r
+    ASSERT_EFI_ERROR (Status);\r
 \r
-      //\r
-      // Free the ParentDevicePath that was duplicated in Start()\r
-      //\r
-      if (!EFI_ERROR (Status)) {\r
-        FreePool (ParentDevicePath);\r
-      }\r
-    }\r
+    //\r
+    // Remove Parent Device Path from\r
+    // the Console Device Environment Variables\r
+    //\r
+    TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);\r
+    TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
+    TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);\r
 \r
     gBS->CloseProtocol (\r
           Controller,\r
@@ -1380,6 +993,49 @@ TerminalDriverBindingStop (
   return EFI_SUCCESS;\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
   Update terminal device path in Console Device Environment Variables.\r
 \r
@@ -1405,8 +1061,12 @@ TerminalUpdateConsoleDevVariable (
   //\r
   // Get global variable and its size according to the name given.\r
   //\r
-  GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);\r
-  if (Variable == NULL) {\r
+  Status = GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);\r
+  if (Status == EFI_NOT_FOUND) {\r
+    Status   = EFI_SUCCESS;\r
+    Variable = NULL;\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
     return;\r
   }\r
 \r
@@ -1415,17 +1075,21 @@ TerminalUpdateConsoleDevVariable (
   //\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
 \r
     if (TempDevicePath != NULL) {\r
+      if (!MatchDevicePaths (Variable, TempDevicePath)) {\r
+        NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);\r
+        if (NewVariable != NULL) {\r
+          if (Variable != NULL) {\r
+            FreePool (Variable);\r
+          }\r
+          Variable = NewVariable;\r
+        }\r
+      }\r
+\r
       FreePool (TempDevicePath);\r
     }\r
 \r
-    Variable = NewVariable;\r
   }\r
 \r
   VariableSize = GetDevicePathSize (Variable);\r
@@ -1608,7 +1272,7 @@ SetTerminalDevicePath (
   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
+  SetDevicePathNodeLength (&Node.Header, sizeof (VENDOR_DEVICE_PATH));\r
   CopyGuid (&Node.Guid, mTerminalType[TerminalType]);\r
 \r
   //\r