]> 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 a8e4a1a0b21ea6ee271ef1fefd44072526d0b065..60de2d4d6db2b09f8937226465ca98e9c2660d21 100644 (file)
@@ -1,9 +1,9 @@
 /** @file\r
-  Produces Simple Text Input Protocl, Simple Text Input Extended Protocol and\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 - 2008, Intel Corporation. <BR>\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
@@ -29,14 +29,23 @@ EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = {
 };\r
 \r
 \r
-EFI_GUID  *gTerminalType[] = {\r
+EFI_GUID  *mTerminalType[] = {\r
   &gEfiPcAnsiGuid,\r
   &gEfiVT100Guid,\r
   &gEfiVT100PlusGuid,\r
-  &gEfiVTUTF8Guid\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
@@ -62,32 +71,31 @@ TERMINAL_DEV  mTerminalDevTemplate = {
   },\r
   {   // SimpleTextOutputMode\r
     1,                                           // MaxMode\r
-    0,                                           // Mode?\r
+    0,                                           // Mode\r
     EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK),    // Attribute\r
     0,                                           // CursorColumn\r
     0,                                           // CursorRow\r
     TRUE                                         // CursorVisible\r
   },\r
-  0,\r
-  {\r
-    0,\r
-    0,\r
-    { 0 }\r
-  },\r
-  {\r
-    0,\r
-    0,\r
-    { 0 }\r
-  },\r
-  {\r
-    0,\r
-    0,\r
-    { {0} }\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,\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
@@ -97,29 +105,46 @@ TERMINAL_DEV  mTerminalDevTemplate = {
     TerminalConInRegisterKeyNotify,\r
     TerminalConInUnregisterKeyNotify,\r
   },\r
-  {\r
+  {   // NotifyList\r
     NULL,\r
     NULL,\r
-  }\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
-  Free notify functions list.\r
+  Convert the GUID representation of terminal type to enum type.\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
+  @param Guid  The GUID representation of terminal type.\r
 \r
+  @return  The terminal type in enum type.\r
 **/\r
-EFI_STATUS\r
-TerminalFreeNotifyList (\r
-  IN OUT LIST_ENTRY           *ListHead\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
+  Test to see if this driver supports Controller.\r
 \r
   @param  This                Protocol instance pointer.\r
   @param  Controller          Handle of device to test\r
@@ -149,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
+      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
-      return EFI_UNSUPPORTED;\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
@@ -189,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
@@ -216,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
@@ -229,6 +264,178 @@ TerminalDriverBindingSupported (
   return Status;\r
 }\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
+  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
+  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
+/**\r
+  Initialize the controller name table.\r
+\r
+  @param TerminalType        The terminal type.\r
+  @param ControllerNameTable The controller name table.\r
+\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
 /**\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
@@ -256,8 +463,8 @@ TerminalDriverBindingStart (
   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_DEVICE_PATH_PROTOCOL            *Vendor;\r
+  EFI_HANDLE                          SerialIoHandle;\r
   EFI_SERIAL_IO_MODE                  *Mode;\r
   UINTN                               SerialInTimeOut;\r
   TERMINAL_DEV                        *TerminalDevice;\r
@@ -265,10 +472,10 @@ TerminalDriverBindingStart (
   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
+  EFI_UNICODE_STRING_TABLE            *ControllerNameTable;\r
 \r
-  TerminalDevice = NULL;\r
-  DefaultNode    = NULL;\r
   //\r
   // Get the Device Path Protocol to build the device path of the child device\r
   //\r
@@ -280,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
@@ -295,161 +500,196 @@ 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
-    // 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
+    // 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
-                    &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
-      //\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 (L"ConInDev", ParentDevicePath);\r
-        TerminalUpdateConsoleDevVariable (L"ConOutDev", ParentDevicePath);\r
-        TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath);\r
-      }\r
-    }\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
-  // Make sure a child handle does not already exist.  This driver can only\r
-  // produce one child per serial port.\r
+  // Do not create any child for END remaining device path.\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
+  if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (Status == EFI_ALREADY_STARTED) {\r
+\r
+    if (RemainingDevicePath == NULL) {\r
+      //\r
+      // If RemainingDevicePath is NULL or is the End of Device Path Node\r
+      //\r
+      return EFI_SUCCESS;\r
     }\r
 \r
-    FreePool (OpenInfoBuffer);\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
+    //\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
+                    &gEfiSerialIoProtocolGuid,\r
+                    &OpenInfoBuffer,\r
+                    &EntryCount\r
+                    );\r
+    if (!EFI_ERROR (Status)) {\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 = 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
+      FreePool (OpenInfoBuffer);\r
     }\r
+    return Status;\r
   }\r
+\r
   //\r
-  // If RemainingDevicePath is NULL, then create default device path node\r
+  // Initialize the Terminal Dev\r
   //\r
-  if (RemainingDevicePath == NULL) {\r
-    DefaultNode = AllocateZeroPool (sizeof (VENDOR_DEVICE_PATH));\r
-    if (DefaultNode == NULL) {\r
-      Status = EFI_OUT_OF_RESOURCES;\r
-      goto Error;\r
-    }\r
+  TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);\r
+  if (TerminalDevice == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto CloseProtocols;\r
+  }\r
 \r
-    TerminalType = FixedPcdGet8 (PcdDefaultTerminalType);\r
+  if (RemainingDevicePath == NULL) {\r
     //\r
-    // Must be between PCANSITYPE (0) and VTUTF8TYPE (3)\r
+    // If RemainingDevicePath is NULL, use default terminal type\r
     //\r
-    ASSERT (TerminalType <= VTUTF8TYPE);\r
-\r
-    CopyMem (&DefaultNode->Guid, gTerminalType[TerminalType], sizeof (EFI_GUID));\r
-    RemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DefaultNode;\r
+    TerminalDevice->TerminalType = PcdGet8 (PcdDefaultTerminalType);\r
   } else {\r
     //\r
+    // End of Device Path Node is handled in above.\r
+    //\r
+    ASSERT (!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
-    if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {\r
-      TerminalType = PCANSITYPE;\r
-    } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {\r
-      TerminalType = VT100TYPE;\r
-    } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {\r
-      TerminalType = VT100PLUSTYPE;\r
-    } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {\r
-      TerminalType = VTUTF8TYPE;\r
-    } else {\r
-      goto Error;\r
-    }\r
+    TerminalDevice->TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *) RemainingDevicePath)->Guid);\r
   }\r
+  ASSERT (TerminalDevice->TerminalType < ARRAY_SIZE (mTerminalType));\r
+  TerminalDevice->SerialIo = SerialIo;\r
 \r
   //\r
-  // Initialize the Terminal Dev\r
+  // Build the component name for the child device\r
   //\r
-  TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);\r
-  if (TerminalDevice == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto Error;\r
+  Status = InitializeControllerNameTable (TerminalDevice->TerminalType, &TerminalDevice->ControllerNameTable);\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreeResources;\r
   }\r
 \r
-  TerminalDevice->TerminalType  = TerminalType;\r
-  TerminalDevice->SerialIo      = SerialIo;\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
   InitializeListHead (&TerminalDevice->NotifyList);\r
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_WAIT,\r
                   TPL_NOTIFY,\r
                   TerminalConInWaitForKeyEx,\r
-                  &TerminalDevice->SimpleInputEx,\r
+                  TerminalDevice,\r
                   &TerminalDevice->SimpleInputEx.WaitForKeyEx\r
                   );\r
-  if (EFI_ERROR (Status)) {\r
-    goto Error;\r
-  }\r
-\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_WAIT,\r
                   TPL_NOTIFY,\r
                   TerminalConInWaitForKey,\r
-                  &TerminalDevice->SimpleInput,\r
+                  TerminalDevice,\r
                   &TerminalDevice->SimpleInput.WaitForKey\r
                   );\r
-  if (EFI_ERROR (Status)) {\r
-    goto Error;\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
-  // initialize the FIFO buffer used for accommodating\r
-  // the pre-read pending characters\r
+  // Allocates and initializes the FIFO buffer to be zero, used for accommodating\r
+  // the pre-read pending characters.\r
   //\r
-  InitializeRawFiFo (TerminalDevice);\r
-  InitializeUnicodeFiFo (TerminalDevice);\r
-  InitializeEfiKeyFiFo (TerminalDevice);\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
-  // Set the timeout value of serial buffer for\r
-  // keystroke response performance issue\r
+  // Set the timeout value of serial buffer for keystroke response performance issue\r
   //\r
-  Mode            = TerminalDevice->SerialIo->Mode;\r
+  Mode = TerminalDevice->SerialIo->Mode;\r
 \r
   SerialInTimeOut = 0;\r
   if (Mode->BaudRate != 0) {\r
@@ -457,14 +697,14 @@ TerminalDriverBindingStart (
   }\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
+                                       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
@@ -477,285 +717,141 @@ TerminalDriverBindingStart (
   } else {\r
     TerminalDevice->SerialInTimeOut = SerialInTimeOut;\r
   }\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
-  DevicePath = TerminalDevice->DevicePath;\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
-    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        = 3;\r
-  //\r
-  // For terminal devices, cursor is always visible\r
-  //\r
-  TerminalDevice->SimpleTextOutputMode.CursorVisible  = TRUE;\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
 \r
-  Status = gBS->CreateEvent (\r
-                  EVT_TIMER,\r
-                  TPL_CALLBACK,\r
-                  NULL,\r
-                  NULL,\r
-                  &TerminalDevice->TwoSecondTimeOut\r
-                  );\r
+  SimpleTextOutput = &TerminalDevice->SimpleTextOutput;\r
+  SimpleTextInput = &TerminalDevice->SimpleInput;\r
 \r
   //\r
-  // Build the component name for the child device\r
+  // Initialize SimpleTextOut instance\r
   //\r
-  TerminalDevice->ControllerNameTable = NULL;\r
-  switch (TerminalDevice->TerminalType) {\r
-  case PCANSITYPE:\r
-    AddUnicodeString2 (\r
-      "eng",\r
-      gTerminalComponentName.SupportedLanguages,\r
-      &TerminalDevice->ControllerNameTable,\r
-      (CHAR16 *)L"PC-ANSI Serial Console",\r
-      TRUE\r
-      );\r
-    AddUnicodeString2 (\r
-      "en",\r
-      gTerminalComponentName2.SupportedLanguages,\r
-      &TerminalDevice->ControllerNameTable,\r
-      (CHAR16 *)L"PC-ANSI Serial Console",\r
-      FALSE\r
-      );\r
-\r
-    break;\r
-\r
-  case VT100TYPE:\r
-    AddUnicodeString2 (\r
-      "eng",\r
-      gTerminalComponentName.SupportedLanguages,\r
-      &TerminalDevice->ControllerNameTable,\r
-      (CHAR16 *)L"VT-100 Serial Console",\r
-      TRUE\r
-      );\r
-    AddUnicodeString2 (\r
-      "en",\r
-      gTerminalComponentName2.SupportedLanguages,\r
-      &TerminalDevice->ControllerNameTable,\r
-      (CHAR16 *)L"VT-100 Serial Console",\r
-      FALSE\r
-      );\r
-\r
-    break;\r
-\r
-  case VT100PLUSTYPE:\r
-    AddUnicodeString2 (\r
-      "eng",\r
-      gTerminalComponentName.SupportedLanguages,\r
-      &TerminalDevice->ControllerNameTable,\r
-      (CHAR16 *)L"VT-100+ Serial Console",\r
-      TRUE\r
-      );\r
-    AddUnicodeString2 (\r
-      "en",\r
-      gTerminalComponentName2.SupportedLanguages,\r
-      &TerminalDevice->ControllerNameTable,\r
-      (CHAR16 *)L"VT-100+ Serial Console",\r
-      FALSE\r
-      );\r
-\r
-    break;\r
-\r
-  case VTUTF8TYPE:\r
-    AddUnicodeString2 (\r
-      "eng",\r
-      gTerminalComponentName.SupportedLanguages,\r
-      &TerminalDevice->ControllerNameTable,\r
-      (CHAR16 *)L"VT-UTF8 Serial Console",\r
-      TRUE\r
-      );\r
-    AddUnicodeString2 (\r
-      "en",\r
-      gTerminalComponentName2.SupportedLanguages,\r
-      &TerminalDevice->ControllerNameTable,\r
-      (CHAR16 *)L"VT-UTF8 Serial Console",\r
-      FALSE\r
-      );\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
-                  &gEfiSimpleTextInputExProtocolGuid,\r
-                  &TerminalDevice->SimpleInputEx,\r
-                  &gEfiSimpleTextOutProtocolGuid,\r
-                  &TerminalDevice->SimpleTextOutput,\r
-                  NULL\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    goto Error;\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
-  // if the serial device is a hot plug device, attaches the HotPlugGuid\r
-  // onto the terminal device handle.\r
+  // For terminal devices, cursor is always visible\r
   //\r
-  Status = gBS->OpenProtocol (\r
-                  Controller,\r
-                  &gEfiHotPlugDeviceGuid,\r
-                  NULL,\r
-                  This->DriverBindingHandle,\r
-                  Controller,\r
-                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\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 = gBS->InstallMultipleProtocolInterfaces (\r
-                    &TerminalDevice->Handle,\r
-                    &gEfiHotPlugDeviceGuid,\r
-                    NULL,\r
-                    NULL\r
-                    );\r
+    Status = SimpleTextOutput->Reset (SimpleTextOutput, FALSE);\r
   }\r
+  if (EFI_ERROR (Status)) {\r
+    goto ReportError;\r
+  }\r
+\r
   //\r
-  // Register the Parent-Child relationship via\r
-  // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+  // Initialize SimpleTextInput instance\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
+  Status = SimpleTextInput->Reset (SimpleTextInput, FALSE);\r
   if (EFI_ERROR (Status)) {\r
-    goto Error;\r
+    goto ReportError;\r
   }\r
 \r
-  if (DefaultNode != NULL) {\r
-    FreePool (DefaultNode);\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
+    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
   REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
     EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
-    PcdGet32 (PcdStatusCodeValueRemoteConsoleError),\r
-    DevicePath\r
+    (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),\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
+FreeResources:\r
+  ASSERT (TerminalDevice != NULL);\r
 \r
-      if (TerminalDevice->TwoSecondTimeOut != NULL) {\r
-        gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);\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->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
-      FreePool (TerminalDevice);\r
-    }\r
-  }\r
+CloseProtocols:\r
 \r
-  if (DefaultNode != NULL) {\r
-    FreePool (DefaultNode);\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
 /**\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
+  Console Device Environment Variables.\r
 \r
   @param  This              Protocol instance pointer.\r
   @param  Controller        Handle of device to stop driver on\r
@@ -783,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
@@ -804,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
@@ -900,34 +969,14 @@ TerminalDriverBindingStop (
               );\r
       } else {\r
 \r
-        if (TerminalDevice->ControllerNameTable != NULL) {\r
-          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
+        FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);\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
+        FreePool (TerminalDevice->TerminalConsoleModeData);\r
         FreePool (TerminalDevice);\r
       }\r
     }\r
@@ -944,48 +993,54 @@ TerminalDriverBindingStop (
   return EFI_SUCCESS;\r
 }\r
 \r
-\r
 /**\r
-  Free notify functions list.\r
+  Compare a device path data structure to that of all the nodes of a\r
+  second device path instance.\r
 \r
-  @param  ListHead               The list head\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 EFI_SUCCESS            Free the notify list successfully.\r
-  @retval EFI_INVALID_PARAMETER  ListHead is NULL.\r
+  @retval TRUE           If the Single is contained within Multi.\r
+  @retval FALSE          The Single is not match within Multi.\r
 \r
 **/\r
-EFI_STATUS\r
-TerminalFreeNotifyList (\r
-  IN OUT LIST_ENTRY           *ListHead\r
+BOOLEAN\r
+MatchDevicePaths (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *Single\r
   )\r
 {\r
-  TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathInst;\r
+  UINTN                     Size;\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
+  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 EFI_SUCCESS;\r
+  return FALSE;\r
 }\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 devcie path to be updated.\r
-\r
-  @return None.\r
+  @param  ParentDevicePath       The terminal device path to be updated.\r
 \r
 **/\r
 VOID\r
@@ -995,37 +1050,46 @@ 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
+  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
   //\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
-    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
@@ -1037,7 +1101,33 @@ 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
@@ -1048,9 +1138,7 @@ TerminalUpdateConsoleDevVariable (
   Remove terminal device path from Console Device Environment Variables.\r
 \r
   @param  VariableName           Console Device Environment Variables.\r
-  @param  ParentDevicePath       The terminal devcie path to be updated.\r
-\r
-  @return None.\r
+  @param  ParentDevicePath       The terminal device path to be updated.\r
 \r
 **/\r
 VOID\r
@@ -1064,7 +1152,7 @@ TerminalRemoveConsoleDevVariable (
   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
@@ -1072,17 +1160,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
@@ -1107,12 +1190,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
@@ -1152,6 +1235,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
@@ -1162,86 +1248,11 @@ TerminalRemoveConsoleDevVariable (
   return ;\r
 }\r
 \r
-\r
-/**\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
-  @param  Name                   String part of EFI variable name\r
-  @param  VendorGuid             GUID part of EFI variable name\r
-  @param  VariableSize           Returns the size of the EFI variable that was read\r
-\r
-  @return Dynamically allocated memory that contains a copy of the EFI variable.\r
-          Caller is repsoncible freeing the buffer. If variable was not read, \r
-          NULL regturned.\r
-\r
-**/\r
-VOID *\r
-TerminalGetVariableAndSize (\r
-  IN  CHAR16              *Name,\r
-  IN  EFI_GUID            *VendorGuid,\r
-  OUT UINTN               *VariableSize\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
-\r
 /**\r
-  Build termial device path according to terminal type.\r
+  Build terminal device path according to terminal type.\r
 \r
   @param  TerminalType           The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.\r
-  @param  ParentDevicePath       Parent devcie path.\r
+  @param  ParentDevicePath       Parent device path.\r
   @param  TerminalDevicePath     Returned terminal device path, if building successfully.\r
 \r
   @retval EFI_UNSUPPORTED        Terminal does not belong to the supported type.\r
@@ -1251,49 +1262,18 @@ TerminalGetVariableAndSize (
 **/\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
-\r
-  //\r
-  // Generate terminal device path node according to terminal type.\r
-  //\r
-  switch (TerminalType) {\r
-\r
-  case PCANSITYPE:\r
-    CopyGuid (&Node.Guid, &gEfiPcAnsiGuid);\r
-    break;\r
-\r
-  case VT100TYPE:\r
-    CopyGuid (&Node.Guid, &gEfiVT100Guid);\r
-    break;\r
-\r
-  case VT100PLUSTYPE:\r
-    CopyGuid (&Node.Guid, &gEfiVT100PlusGuid);\r
-    break;\r
-\r
-  case VTUTF8TYPE:\r
-    CopyGuid (&Node.Guid, &gEfiVTUTF8Guid);\r
-    break;\r
-\r
-  default:\r
-    return EFI_UNSUPPORTED;\r
-  }\r
-\r
-  //\r
-  // Get VENDOR_DEVCIE_PATH size and put into Node.Header\r
-  //\r
-  SetDevicePathNodeLength (\r
-    &Node.Header,\r
-    sizeof (VENDOR_DEVICE_PATH)\r
-    );\r
+  SetDevicePathNodeLength (&Node.Header, sizeof (VENDOR_DEVICE_PATH));\r
+  CopyGuid (&Node.Guid, mTerminalType[TerminalType]);\r
 \r
   //\r
   // Append the terminal node onto parent device path\r
@@ -1310,64 +1290,6 @@ SetTerminalDevicePath (
   return EFI_SUCCESS;\r
 }\r
 \r
-/**\r
-  Initialize the Raw Data FIFO.\r
-\r
-  @param TerminalDevice          The terminal device.\r
-\r
-  @return None.\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
-/**\r
-  Initialize the Unicode FIFO.\r
-\r
-  @param TerminalDevice          The terminal device.\r
-\r
-  @return None.\r
-\r
-**/\r
-VOID\r
-InitializeUnicodeFiFo (\r
-  IN  TERMINAL_DEV  *TerminalDevice\r
-  )\r
-{\r
-  //\r
-  // Make the unicode fifo empty\r
-  //\r
-  TerminalDevice->UnicodeFiFo.Head = TerminalDevice->UnicodeFiFo.Tail;\r
-}\r
-\r
-/**\r
-  Initialize the EFI Key FIFO.\r
-\r
-  @param TerminalDevice          The terminal device.\r
-\r
-  @return None.\r
-\r
-**/\r
-VOID\r
-InitializeEfiKeyFiFo (\r
-  IN  TERMINAL_DEV  *TerminalDevice\r
-  )\r
-{\r
-  //\r
-  // Make the efi key fifo empty\r
-  //\r
-  TerminalDevice->EfiKeyFiFo.Head = TerminalDevice->EfiKeyFiFo.Tail;\r
-}\r
-\r
-\r
 /**\r
   The user Entry Point for module Terminal. The user code starts with this function.\r
 \r
@@ -1400,6 +1322,53 @@ InitializeTerminal(
              );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-\r
   return Status;\r
 }\r
+\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
+  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