Home | History | Annotate | Download | only in TerminalDxe
      1 /** @file
      2   Produces Simple Text Input Protocol, Simple Text Input Extended Protocol and
      3   Simple Text Output Protocol upon Serial IO Protocol.
      4 
      5 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 
     17 #include "Terminal.h"
     18 
     19 //
     20 // Globals
     21 //
     22 EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = {
     23   TerminalDriverBindingSupported,
     24   TerminalDriverBindingStart,
     25   TerminalDriverBindingStop,
     26   0xa,
     27   NULL,
     28   NULL
     29 };
     30 
     31 
     32 EFI_GUID  *gTerminalType[] = {
     33   &gEfiPcAnsiGuid,
     34   &gEfiVT100Guid,
     35   &gEfiVT100PlusGuid,
     36   &gEfiVTUTF8Guid,
     37   &gEfiTtyTermGuid
     38 };
     39 
     40 
     41 TERMINAL_DEV  mTerminalDevTemplate = {
     42   TERMINAL_DEV_SIGNATURE,
     43   NULL,
     44   0,
     45   NULL,
     46   NULL,
     47   {   // SimpleTextInput
     48     TerminalConInReset,
     49     TerminalConInReadKeyStroke,
     50     NULL
     51   },
     52   {   // SimpleTextOutput
     53     TerminalConOutReset,
     54     TerminalConOutOutputString,
     55     TerminalConOutTestString,
     56     TerminalConOutQueryMode,
     57     TerminalConOutSetMode,
     58     TerminalConOutSetAttribute,
     59     TerminalConOutClearScreen,
     60     TerminalConOutSetCursorPosition,
     61     TerminalConOutEnableCursor,
     62     NULL
     63   },
     64   {   // SimpleTextOutputMode
     65     1,                                           // MaxMode
     66     0,                                           // Mode
     67     EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK),    // Attribute
     68     0,                                           // CursorColumn
     69     0,                                           // CursorRow
     70     TRUE                                         // CursorVisible
     71   },
     72   NULL, // TerminalConsoleModeData
     73   0,  // SerialInTimeOut
     74 
     75   NULL, // RawFifo
     76   NULL, // UnicodeFiFo
     77   NULL, // EfiKeyFiFo
     78 
     79   NULL, // ControllerNameTable
     80   NULL, // TimerEvent
     81   NULL, // TwoSecondTimeOut
     82   INPUT_STATE_DEFAULT,
     83   RESET_STATE_DEFAULT,
     84   {
     85       0,
     86       0,
     87       0
     88   },
     89   0,
     90   FALSE,
     91   {   // SimpleTextInputEx
     92     TerminalConInResetEx,
     93     TerminalConInReadKeyStrokeEx,
     94     NULL,
     95     TerminalConInSetState,
     96     TerminalConInRegisterKeyNotify,
     97     TerminalConInUnregisterKeyNotify,
     98   },
     99   {   // NotifyList
    100     NULL,
    101     NULL,
    102   }
    103 };
    104 
    105 TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData[] = {
    106   {100, 31},
    107   //
    108   // New modes can be added here.
    109   //
    110 };
    111 
    112 /**
    113   Test to see if this driver supports Controller.
    114 
    115   @param  This                Protocol instance pointer.
    116   @param  Controller          Handle of device to test
    117   @param  RemainingDevicePath Optional parameter use to pick a specific child
    118                               device to start.
    119 
    120   @retval EFI_SUCCESS         This driver supports this device.
    121   @retval EFI_ALREADY_STARTED This driver is already running on this device.
    122   @retval other               This driver does not support this device.
    123 
    124 **/
    125 EFI_STATUS
    126 EFIAPI
    127 TerminalDriverBindingSupported (
    128   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    129   IN EFI_HANDLE                     Controller,
    130   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    131   )
    132 {
    133   EFI_STATUS                Status;
    134   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
    135   EFI_SERIAL_IO_PROTOCOL    *SerialIo;
    136   VENDOR_DEVICE_PATH        *Node;
    137 
    138   //
    139   // If remaining device path is not NULL, then make sure it is a
    140   // device path that describes a terminal communications protocol.
    141   //
    142   if (RemainingDevicePath != NULL) {
    143     //
    144     // Check if RemainingDevicePath is the End of Device Path Node,
    145     // if yes, go on checking other conditions
    146     //
    147     if (!IsDevicePathEnd (RemainingDevicePath)) {
    148       //
    149       // If RemainingDevicePath isn't the End of Device Path Node,
    150       // check its validation
    151       //
    152       Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
    153 
    154       if (Node->Header.Type != MESSAGING_DEVICE_PATH ||
    155           Node->Header.SubType != MSG_VENDOR_DP ||
    156           DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) {
    157 
    158         return EFI_UNSUPPORTED;
    159 
    160       }
    161       //
    162       // only supports PC ANSI, VT100, VT100+, VT-UTF8, and TtyTerm terminal types
    163       //
    164       if (!CompareGuid (&Node->Guid, &gEfiPcAnsiGuid) &&
    165           !CompareGuid (&Node->Guid, &gEfiVT100Guid) &&
    166           !CompareGuid (&Node->Guid, &gEfiVT100PlusGuid) &&
    167           !CompareGuid (&Node->Guid, &gEfiVTUTF8Guid) &&
    168           !CompareGuid (&Node->Guid, &gEfiTtyTermGuid)) {
    169 
    170         return EFI_UNSUPPORTED;
    171       }
    172     }
    173   }
    174   //
    175   // Open the IO Abstraction(s) needed to perform the supported test
    176   // The Controller must support the Serial I/O Protocol.
    177   // This driver is a bus driver with at most 1 child device, so it is
    178   // ok for it to be already started.
    179   //
    180   Status = gBS->OpenProtocol (
    181                   Controller,
    182                   &gEfiSerialIoProtocolGuid,
    183                   (VOID **) &SerialIo,
    184                   This->DriverBindingHandle,
    185                   Controller,
    186                   EFI_OPEN_PROTOCOL_BY_DRIVER
    187                   );
    188   if (Status == EFI_ALREADY_STARTED) {
    189     return EFI_SUCCESS;
    190   }
    191 
    192   if (EFI_ERROR (Status)) {
    193     return Status;
    194   }
    195 
    196   //
    197   // Close the I/O Abstraction(s) used to perform the supported test
    198   //
    199   gBS->CloseProtocol (
    200         Controller,
    201         &gEfiSerialIoProtocolGuid,
    202         This->DriverBindingHandle,
    203         Controller
    204         );
    205 
    206   //
    207   // Open the EFI Device Path protocol needed to perform the supported test
    208   //
    209   Status = gBS->OpenProtocol (
    210                   Controller,
    211                   &gEfiDevicePathProtocolGuid,
    212                   (VOID **) &ParentDevicePath,
    213                   This->DriverBindingHandle,
    214                   Controller,
    215                   EFI_OPEN_PROTOCOL_BY_DRIVER
    216                   );
    217   if (Status == EFI_ALREADY_STARTED) {
    218     return EFI_SUCCESS;
    219   }
    220 
    221   if (EFI_ERROR (Status)) {
    222     return Status;
    223   }
    224 
    225   //
    226   // Close protocol, don't use device path protocol in the Support() function
    227   //
    228   gBS->CloseProtocol (
    229         Controller,
    230         &gEfiDevicePathProtocolGuid,
    231         This->DriverBindingHandle,
    232         Controller
    233         );
    234 
    235   return Status;
    236 }
    237 
    238 /**
    239   Build the terminal device path for the child device according to the
    240   terminal type.
    241 
    242   @param  ParentDevicePath         Parent device path.
    243   @param  RemainingDevicePath      A specific child device.
    244 
    245   @return The child device path built.
    246 
    247 **/
    248 EFI_DEVICE_PATH_PROTOCOL*
    249 EFIAPI
    250 BuildTerminalDevpath  (
    251   IN EFI_DEVICE_PATH_PROTOCOL       *ParentDevicePath,
    252   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    253   )
    254 {
    255   EFI_DEVICE_PATH_PROTOCOL          *TerminalDevicePath;
    256   UINT8                             TerminalType;
    257   VENDOR_DEVICE_PATH                *Node;
    258   EFI_STATUS                        Status;
    259 
    260   TerminalDevicePath = NULL;
    261 
    262   //
    263   // Use the RemainingDevicePath to determine the terminal type
    264   //
    265   Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
    266   if (Node == NULL) {
    267     TerminalType = PcdGet8 (PcdDefaultTerminalType);
    268 
    269   } else if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {
    270 
    271     TerminalType = PCANSITYPE;
    272 
    273   } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {
    274 
    275     TerminalType = VT100TYPE;
    276 
    277   } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {
    278 
    279     TerminalType = VT100PLUSTYPE;
    280 
    281   } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
    282 
    283     TerminalType = VTUTF8TYPE;
    284 
    285   } else if (CompareGuid (&Node->Guid, &gEfiTtyTermGuid)) {
    286 
    287     TerminalType = TTYTERMTYPE;
    288 
    289   } else {
    290     return NULL;
    291   }
    292 
    293   //
    294   // Build the device path for the child device
    295   //
    296   Status = SetTerminalDevicePath (
    297             TerminalType,
    298             ParentDevicePath,
    299             &TerminalDevicePath
    300             );
    301   if (EFI_ERROR (Status)) {
    302     return NULL;
    303   }
    304   return TerminalDevicePath;
    305 }
    306 
    307 /**
    308   Compare a device path data structure to that of all the nodes of a
    309   second device path instance.
    310 
    311   @param  Multi          A pointer to a multi-instance device path data structure.
    312   @param  Single         A pointer to a single-instance device path data structure.
    313 
    314   @retval TRUE           If the Single is contained within Multi.
    315   @retval FALSE          The Single is not match within Multi.
    316 
    317 **/
    318 BOOLEAN
    319 MatchDevicePaths (
    320   IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,
    321   IN  EFI_DEVICE_PATH_PROTOCOL  *Single
    322   )
    323 {
    324   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    325   EFI_DEVICE_PATH_PROTOCOL  *DevicePathInst;
    326   UINTN                     Size;
    327 
    328   DevicePath      = Multi;
    329   DevicePathInst  = GetNextDevicePathInstance (&DevicePath, &Size);
    330   //
    331   // Search for the match of 'Single' in 'Multi'
    332   //
    333   while (DevicePathInst != NULL) {
    334     //
    335     // If the single device path is found in multiple device paths,
    336     // return success
    337     //
    338     if (CompareMem (Single, DevicePathInst, Size) == 0) {
    339       FreePool (DevicePathInst);
    340       return TRUE;
    341     }
    342 
    343     FreePool (DevicePathInst);
    344     DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
    345   }
    346 
    347   return FALSE;
    348 }
    349 
    350 /**
    351   Check whether the terminal device path is in the global variable.
    352 
    353   @param  VariableName          Pointer to one global variable.
    354   @param  TerminalDevicePath    Pointer to the terminal device's device path.
    355 
    356   @retval TRUE                  The devcie is in the global variable.
    357   @retval FALSE                 The devcie is not in the global variable.
    358 
    359 **/
    360 BOOLEAN
    361 IsTerminalInConsoleVariable (
    362   IN CHAR16                    *VariableName,
    363   IN EFI_DEVICE_PATH_PROTOCOL  *TerminalDevicePath
    364   )
    365 {
    366   EFI_DEVICE_PATH_PROTOCOL  *Variable;
    367   BOOLEAN                   ReturnFlag;
    368 
    369   //
    370   // Get global variable and its size according to the name given.
    371   //
    372   GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
    373   if (Variable == NULL) {
    374     return FALSE;
    375   }
    376 
    377   //
    378   // Check whether the terminal device path is one of the variable instances.
    379   //
    380   ReturnFlag = MatchDevicePaths (Variable, TerminalDevicePath);
    381 
    382   FreePool (Variable);
    383 
    384   return ReturnFlag;
    385 }
    386 
    387 /**
    388   Free notify functions list.
    389 
    390   @param  ListHead               The list head
    391 
    392   @retval EFI_SUCCESS            Free the notify list successfully.
    393   @retval EFI_INVALID_PARAMETER  ListHead is NULL.
    394 
    395 **/
    396 EFI_STATUS
    397 TerminalFreeNotifyList (
    398   IN OUT LIST_ENTRY           *ListHead
    399   )
    400 {
    401   TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;
    402 
    403   if (ListHead == NULL) {
    404     return EFI_INVALID_PARAMETER;
    405   }
    406   while (!IsListEmpty (ListHead)) {
    407     NotifyNode = CR (
    408                    ListHead->ForwardLink,
    409                    TERMINAL_CONSOLE_IN_EX_NOTIFY,
    410                    NotifyEntry,
    411                    TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
    412                    );
    413     RemoveEntryList (ListHead->ForwardLink);
    414     FreePool (NotifyNode);
    415   }
    416 
    417   return EFI_SUCCESS;
    418 }
    419 
    420 /**
    421   Initialize all the text modes which the terminal console supports.
    422 
    423   It returns information for available text modes that the terminal can support.
    424 
    425   @param[out] TextModeCount      The total number of text modes that terminal console supports.
    426   @param[out] TextModeData       The buffer to the text modes column and row information.
    427                                  Caller is responsible to free it when it's non-NULL.
    428 
    429   @retval EFI_SUCCESS            The supporting mode information is returned.
    430   @retval EFI_INVALID_PARAMETER  The parameters are invalid.
    431 
    432 **/
    433 EFI_STATUS
    434 InitializeTerminalConsoleTextMode (
    435   OUT UINTN                         *TextModeCount,
    436   OUT TERMINAL_CONSOLE_MODE_DATA    **TextModeData
    437   )
    438 {
    439   UINTN                       Index;
    440   UINTN                       Count;
    441   TERMINAL_CONSOLE_MODE_DATA  *ModeBuffer;
    442   TERMINAL_CONSOLE_MODE_DATA  *NewModeBuffer;
    443   UINTN                       ValidCount;
    444   UINTN                       ValidIndex;
    445 
    446   if ((TextModeCount == NULL) || (TextModeData == NULL)) {
    447     return EFI_INVALID_PARAMETER;
    448   }
    449 
    450   Count = sizeof (mTerminalConsoleModeData) / sizeof (TERMINAL_CONSOLE_MODE_DATA);
    451 
    452   //
    453   // Get defined mode buffer pointer.
    454   //
    455   ModeBuffer = mTerminalConsoleModeData;
    456 
    457   //
    458   // Here we make sure that the final mode exposed does not include the duplicated modes,
    459   // and does not include the invalid modes which exceed the max column and row.
    460   // Reserve 2 modes for 80x25, 80x50 of terminal console.
    461   //
    462   NewModeBuffer = AllocateZeroPool (sizeof (TERMINAL_CONSOLE_MODE_DATA) * (Count + 2));
    463   ASSERT (NewModeBuffer != NULL);
    464 
    465   //
    466   // Mode 0 and mode 1 is for 80x25, 80x50 according to UEFI spec.
    467   //
    468   ValidCount = 0;
    469 
    470   NewModeBuffer[ValidCount].Columns = 80;
    471   NewModeBuffer[ValidCount].Rows    = 25;
    472   ValidCount++;
    473 
    474   NewModeBuffer[ValidCount].Columns = 80;
    475   NewModeBuffer[ValidCount].Rows    = 50;
    476   ValidCount++;
    477 
    478   //
    479   // Start from mode 2 to put the valid mode other than 80x25 and 80x50 in the output mode buffer.
    480   //
    481   for (Index = 0; Index < Count; Index++) {
    482     if ((ModeBuffer[Index].Columns == 0) || (ModeBuffer[Index].Rows == 0)) {
    483       //
    484       // Skip the pre-defined mode which is invalid.
    485       //
    486       continue;
    487     }
    488     for (ValidIndex = 0; ValidIndex < ValidCount; ValidIndex++) {
    489       if ((ModeBuffer[Index].Columns == NewModeBuffer[ValidIndex].Columns) &&
    490           (ModeBuffer[Index].Rows == NewModeBuffer[ValidIndex].Rows)) {
    491         //
    492         // Skip the duplicated mode.
    493         //
    494         break;
    495       }
    496     }
    497     if (ValidIndex == ValidCount) {
    498       NewModeBuffer[ValidCount].Columns = ModeBuffer[Index].Columns;
    499       NewModeBuffer[ValidCount].Rows    = ModeBuffer[Index].Rows;
    500       ValidCount++;
    501     }
    502   }
    503 
    504   DEBUG_CODE (
    505     for (Index = 0; Index < ValidCount; Index++) {
    506       DEBUG ((EFI_D_INFO, "Terminal - Mode %d, Column = %d, Row = %d\n",
    507                            Index, NewModeBuffer[Index].Columns, NewModeBuffer[Index].Rows));
    508     }
    509   );
    510 
    511   //
    512   // Return valid mode count and mode information buffer.
    513   //
    514   *TextModeCount = ValidCount;
    515   *TextModeData  = NewModeBuffer;
    516   return EFI_SUCCESS;
    517 }
    518 
    519 /**
    520   Start this driver on Controller by opening a Serial IO protocol,
    521   reading Device Path, and creating a child handle with a Simple Text In,
    522   Simple Text In Ex and Simple Text Out protocol, and device path protocol.
    523   And store Console Device Environment Variables.
    524 
    525   @param  This                 Protocol instance pointer.
    526   @param  Controller           Handle of device to bind driver to
    527   @param  RemainingDevicePath  Optional parameter use to pick a specific child
    528                                device to start.
    529 
    530   @retval EFI_SUCCESS          This driver is added to Controller.
    531   @retval EFI_ALREADY_STARTED  This driver is already running on Controller.
    532   @retval other                This driver does not support this device.
    533 
    534 **/
    535 EFI_STATUS
    536 EFIAPI
    537 TerminalDriverBindingStart (
    538   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    539   IN EFI_HANDLE                     Controller,
    540   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    541   )
    542 {
    543   EFI_STATUS                          Status;
    544   EFI_SERIAL_IO_PROTOCOL              *SerialIo;
    545   EFI_DEVICE_PATH_PROTOCOL            *ParentDevicePath;
    546   VENDOR_DEVICE_PATH                  *Node;
    547   EFI_SERIAL_IO_MODE                  *Mode;
    548   UINTN                               SerialInTimeOut;
    549   TERMINAL_DEV                        *TerminalDevice;
    550   UINT8                               TerminalType;
    551   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
    552   UINTN                               EntryCount;
    553   UINTN                               Index;
    554   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;
    555   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL     *SimpleTextOutput;
    556   EFI_SIMPLE_TEXT_INPUT_PROTOCOL      *SimpleTextInput;
    557   BOOLEAN                             ConInSelected;
    558   BOOLEAN                             ConOutSelected;
    559   BOOLEAN                             NullRemaining;
    560   BOOLEAN                             SimTxtInInstalled;
    561   BOOLEAN                             SimTxtOutInstalled;
    562   BOOLEAN                             FirstEnter;
    563   UINTN                               ModeCount;
    564 
    565   TerminalDevice     = NULL;
    566   ConInSelected      = FALSE;
    567   ConOutSelected     = FALSE;
    568   NullRemaining      = FALSE;
    569   SimTxtInInstalled  = FALSE;
    570   SimTxtOutInstalled = FALSE;
    571   FirstEnter         = FALSE;
    572   //
    573   // Get the Device Path Protocol to build the device path of the child device
    574   //
    575   Status = gBS->OpenProtocol (
    576                   Controller,
    577                   &gEfiDevicePathProtocolGuid,
    578                   (VOID **) &ParentDevicePath,
    579                   This->DriverBindingHandle,
    580                   Controller,
    581                   EFI_OPEN_PROTOCOL_BY_DRIVER
    582                   );
    583   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
    584     return Status;
    585   }
    586 
    587   //
    588   // Open the Serial I/O Protocol BY_DRIVER.  It might already be started.
    589   //
    590   Status = gBS->OpenProtocol (
    591                   Controller,
    592                   &gEfiSerialIoProtocolGuid,
    593                   (VOID **) &SerialIo,
    594                   This->DriverBindingHandle,
    595                   Controller,
    596                   EFI_OPEN_PROTOCOL_BY_DRIVER
    597                   );
    598   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
    599     return Status;
    600   }
    601 
    602   if (Status != EFI_ALREADY_STARTED) {
    603     //
    604     // the serial I/O protocol never be opened before, it is the first
    605     // time to start the serial Io controller
    606     //
    607     FirstEnter = TRUE;
    608   }
    609 
    610   //
    611   // Serial I/O is not already open by this driver, then tag the handle
    612   // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and
    613   // StdErrDev variables with the list of possible terminal types on this
    614   // serial port.
    615   //
    616   Status = gBS->OpenProtocol (
    617                   Controller,
    618                   &gEfiCallerIdGuid,
    619                   NULL,
    620                   This->DriverBindingHandle,
    621                   Controller,
    622                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    623                   );
    624   if (EFI_ERROR (Status)) {
    625     Status = gBS->InstallMultipleProtocolInterfaces (
    626                     &Controller,
    627                     &gEfiCallerIdGuid,
    628                     DuplicateDevicePath (ParentDevicePath),
    629                     NULL
    630                     );
    631     if (EFI_ERROR (Status)) {
    632       goto Error;
    633     }
    634 
    635     if (!IsHotPlugDevice (ParentDevicePath)) {
    636       //
    637       // if the serial device is a hot plug device, do not update the
    638       // ConInDev, ConOutDev, and StdErrDev variables.
    639       //
    640       TerminalUpdateConsoleDevVariable (L"ConInDev", ParentDevicePath);
    641       TerminalUpdateConsoleDevVariable (L"ConOutDev", ParentDevicePath);
    642       TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
    643     }
    644   }
    645 
    646   //
    647   // Check the requirement for the SimpleTxtIn and SimpleTxtOut protocols
    648   //
    649   // Simple In/Out Protocol will not be installed onto the handle if the
    650   // device path to the handle is not present in the ConIn/ConOut
    651   // environment variable. But If RemainingDevicePath is NULL, then always
    652   // produce both Simple In and Simple Text Output Protocols. This is required
    653   // for the connect all sequences to make sure all possible consoles are
    654   // produced no matter what the current values of ConIn, ConOut, or StdErr are.
    655   //
    656   if (RemainingDevicePath == NULL) {
    657     NullRemaining = TRUE;
    658   }
    659 
    660   DevicePath = BuildTerminalDevpath (ParentDevicePath, RemainingDevicePath);
    661   if (DevicePath != NULL) {
    662     ConInSelected  = IsTerminalInConsoleVariable (L"ConIn", DevicePath);
    663     ConOutSelected = IsTerminalInConsoleVariable (L"ConOut", DevicePath);
    664     FreePool (DevicePath);
    665   } else {
    666     goto Error;
    667   }
    668   //
    669   // Not create the child terminal handle if both Simple In/In Ex and
    670   // Simple text Out protocols are not required to be published
    671   //
    672   if ((!ConInSelected)&&(!ConOutSelected)&&(!NullRemaining)) {
    673     goto Error;
    674   }
    675 
    676   //
    677   // create the child terminal handle during first entry
    678   //
    679   if (FirstEnter) {
    680     //
    681     // First enther the start funciton
    682     //
    683     FirstEnter = FALSE;
    684     //
    685     // Make sure a child handle does not already exist.  This driver can only
    686     // produce one child per serial port.
    687     //
    688     Status = gBS->OpenProtocolInformation (
    689                     Controller,
    690                     &gEfiSerialIoProtocolGuid,
    691                     &OpenInfoBuffer,
    692                     &EntryCount
    693                     );
    694     if (!EFI_ERROR (Status)) {
    695       Status = EFI_SUCCESS;
    696       for (Index = 0; Index < EntryCount; Index++) {
    697         if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
    698           Status = EFI_ALREADY_STARTED;
    699         }
    700       }
    701 
    702       FreePool (OpenInfoBuffer);
    703       if (EFI_ERROR (Status)) {
    704           goto Error;
    705       }
    706     }
    707 
    708     //
    709     // If RemainingDevicePath is NULL, use default terminal type
    710     //
    711     if (RemainingDevicePath == NULL) {
    712       TerminalType = PcdGet8 (PcdDefaultTerminalType);
    713       //
    714       // Must be between PCANSITYPE (0) and TTYTERMTYPE (4)
    715       //
    716       ASSERT (TerminalType <= TTYTERMTYPE);
    717     } else if (!IsDevicePathEnd (RemainingDevicePath)) {
    718       //
    719       // If RemainingDevicePath isn't the End of Device Path Node,
    720       // Use the RemainingDevicePath to determine the terminal type
    721       //
    722       Node = (VENDOR_DEVICE_PATH *)RemainingDevicePath;
    723       if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {
    724         TerminalType = PCANSITYPE;
    725       } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {
    726         TerminalType = VT100TYPE;
    727       } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {
    728         TerminalType = VT100PLUSTYPE;
    729       } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
    730         TerminalType = VTUTF8TYPE;
    731       } else if (CompareGuid (&Node->Guid, &gEfiTtyTermGuid)) {
    732         TerminalType = TTYTERMTYPE;
    733       } else {
    734         goto Error;
    735       }
    736     } else {
    737       //
    738       // If RemainingDevicePath is the End of Device Path Node,
    739       // skip enumerate any device and return EFI_SUCESSS
    740       //
    741       return EFI_SUCCESS;
    742     }
    743 
    744     //
    745     // Initialize the Terminal Dev
    746     //
    747     TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);
    748     if (TerminalDevice == NULL) {
    749       Status = EFI_OUT_OF_RESOURCES;
    750       goto Error;
    751     }
    752 
    753     TerminalDevice->TerminalType  = TerminalType;
    754     TerminalDevice->SerialIo      = SerialIo;
    755 
    756     InitializeListHead (&TerminalDevice->NotifyList);
    757     Status = gBS->CreateEvent (
    758                     EVT_NOTIFY_WAIT,
    759                     TPL_NOTIFY,
    760                     TerminalConInWaitForKeyEx,
    761                     TerminalDevice,
    762                     &TerminalDevice->SimpleInputEx.WaitForKeyEx
    763                     );
    764     if (EFI_ERROR (Status)) {
    765       goto Error;
    766     }
    767 
    768     Status = gBS->CreateEvent (
    769                     EVT_NOTIFY_WAIT,
    770                     TPL_NOTIFY,
    771                     TerminalConInWaitForKey,
    772                     TerminalDevice,
    773                     &TerminalDevice->SimpleInput.WaitForKey
    774                     );
    775     if (EFI_ERROR (Status)) {
    776       goto Error;
    777     }
    778     //
    779     // Allocates and initializes the FIFO buffer to be zero, used for accommodating
    780     // the pre-read pending characters.
    781     //
    782     TerminalDevice->RawFiFo     = AllocateZeroPool (sizeof (RAW_DATA_FIFO));
    783     if (TerminalDevice->RawFiFo == NULL) {
    784       goto Error;
    785     }
    786     TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));
    787     if (TerminalDevice->UnicodeFiFo == NULL) {
    788       goto Error;
    789     }
    790     TerminalDevice->EfiKeyFiFo  = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
    791     if (TerminalDevice->EfiKeyFiFo == NULL) {
    792       goto Error;
    793     }
    794 
    795     //
    796     // Set the timeout value of serial buffer for
    797     // keystroke response performance issue
    798     //
    799     Mode            = TerminalDevice->SerialIo->Mode;
    800 
    801     SerialInTimeOut = 0;
    802     if (Mode->BaudRate != 0) {
    803       SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;
    804     }
    805 
    806     Status = TerminalDevice->SerialIo->SetAttributes (
    807                                         TerminalDevice->SerialIo,
    808                                         Mode->BaudRate,
    809                                         0, // the device's default FIFO depth
    810                                         (UINT32) SerialInTimeOut,
    811                                         (EFI_PARITY_TYPE) (Mode->Parity),
    812                                         (UINT8) Mode->DataBits,
    813                                         (EFI_STOP_BITS_TYPE) (Mode->StopBits)
    814                                         );
    815     if (EFI_ERROR (Status)) {
    816       //
    817       // if set attributes operation fails, invalidate
    818       // the value of SerialInTimeOut,thus make it
    819       // inconsistent with the default timeout value
    820       // of serial buffer. This will invoke the recalculation
    821       // in the readkeystroke routine.
    822       //
    823       TerminalDevice->SerialInTimeOut = 0;
    824     } else {
    825       TerminalDevice->SerialInTimeOut = SerialInTimeOut;
    826     }
    827     //
    828     // Set Simple Text Output Protocol from template.
    829     //
    830     SimpleTextOutput = CopyMem (
    831                          &TerminalDevice->SimpleTextOutput,
    832                          &mTerminalDevTemplate.SimpleTextOutput,
    833                          sizeof (mTerminalDevTemplate.SimpleTextOutput)
    834                          );
    835     SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode;
    836 
    837     Status = InitializeTerminalConsoleTextMode (&ModeCount, &TerminalDevice->TerminalConsoleModeData);
    838     if (EFI_ERROR (Status)) {
    839       goto ReportError;
    840     }
    841     TerminalDevice->SimpleTextOutputMode.MaxMode = (INT32) ModeCount;
    842 
    843     //
    844     // For terminal devices, cursor is always visible
    845     //
    846     TerminalDevice->SimpleTextOutputMode.CursorVisible = TRUE;
    847     Status = TerminalConOutSetAttribute (
    848                SimpleTextOutput,
    849                EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
    850                );
    851     if (EFI_ERROR (Status)) {
    852       goto ReportError;
    853     }
    854 
    855     //
    856     // Build the component name for the child device
    857     //
    858     TerminalDevice->ControllerNameTable = NULL;
    859     switch (TerminalDevice->TerminalType) {
    860     case PCANSITYPE:
    861       AddUnicodeString2 (
    862         "eng",
    863         gTerminalComponentName.SupportedLanguages,
    864         &TerminalDevice->ControllerNameTable,
    865         (CHAR16 *)L"PC-ANSI Serial Console",
    866         TRUE
    867         );
    868       AddUnicodeString2 (
    869         "en",
    870         gTerminalComponentName2.SupportedLanguages,
    871         &TerminalDevice->ControllerNameTable,
    872         (CHAR16 *)L"PC-ANSI Serial Console",
    873         FALSE
    874         );
    875 
    876       break;
    877 
    878     case VT100TYPE:
    879       AddUnicodeString2 (
    880         "eng",
    881         gTerminalComponentName.SupportedLanguages,
    882         &TerminalDevice->ControllerNameTable,
    883         (CHAR16 *)L"VT-100 Serial Console",
    884         TRUE
    885         );
    886       AddUnicodeString2 (
    887         "en",
    888         gTerminalComponentName2.SupportedLanguages,
    889         &TerminalDevice->ControllerNameTable,
    890         (CHAR16 *)L"VT-100 Serial Console",
    891         FALSE
    892         );
    893 
    894       break;
    895 
    896     case VT100PLUSTYPE:
    897       AddUnicodeString2 (
    898         "eng",
    899         gTerminalComponentName.SupportedLanguages,
    900         &TerminalDevice->ControllerNameTable,
    901         (CHAR16 *)L"VT-100+ Serial Console",
    902         TRUE
    903         );
    904       AddUnicodeString2 (
    905         "en",
    906         gTerminalComponentName2.SupportedLanguages,
    907         &TerminalDevice->ControllerNameTable,
    908         (CHAR16 *)L"VT-100+ Serial Console",
    909         FALSE
    910         );
    911 
    912       break;
    913 
    914     case VTUTF8TYPE:
    915       AddUnicodeString2 (
    916         "eng",
    917         gTerminalComponentName.SupportedLanguages,
    918         &TerminalDevice->ControllerNameTable,
    919         (CHAR16 *)L"VT-UTF8 Serial Console",
    920         TRUE
    921         );
    922       AddUnicodeString2 (
    923         "en",
    924         gTerminalComponentName2.SupportedLanguages,
    925         &TerminalDevice->ControllerNameTable,
    926         (CHAR16 *)L"VT-UTF8 Serial Console",
    927         FALSE
    928         );
    929 
    930       break;
    931 
    932     case TTYTERMTYPE:
    933       AddUnicodeString2 (
    934         "eng",
    935         gTerminalComponentName.SupportedLanguages,
    936         &TerminalDevice->ControllerNameTable,
    937         (CHAR16 *)L"Tty Terminal Serial Console",
    938         TRUE
    939         );
    940       AddUnicodeString2 (
    941         "en",
    942         gTerminalComponentName2.SupportedLanguages,
    943         &TerminalDevice->ControllerNameTable,
    944         (CHAR16 *)L"Tty Terminal Serial Console",
    945         FALSE
    946         );
    947 
    948       break;
    949     }
    950 
    951     //
    952     // Build the device path for the child device
    953     //
    954     Status = SetTerminalDevicePath (
    955               TerminalDevice->TerminalType,
    956               ParentDevicePath,
    957               &TerminalDevice->DevicePath
    958               );
    959     if (EFI_ERROR (Status)) {
    960       goto Error;
    961     }
    962 
    963     Status = TerminalConOutReset (SimpleTextOutput, FALSE);
    964     if (EFI_ERROR (Status)) {
    965       goto ReportError;
    966     }
    967 
    968     Status = TerminalConOutSetMode (SimpleTextOutput, 0);
    969     if (EFI_ERROR (Status)) {
    970       goto ReportError;
    971     }
    972 
    973     Status = TerminalConOutEnableCursor (SimpleTextOutput, TRUE);
    974     if (EFI_ERROR (Status)) {
    975       goto ReportError;
    976     }
    977 
    978     Status = gBS->CreateEvent (
    979                     EVT_TIMER | EVT_NOTIFY_SIGNAL,
    980                     TPL_NOTIFY,
    981                     TerminalConInTimerHandler,
    982                     TerminalDevice,
    983                     &TerminalDevice->TimerEvent
    984                     );
    985     ASSERT_EFI_ERROR (Status);
    986 
    987     Status = gBS->SetTimer (
    988                     TerminalDevice->TimerEvent,
    989                     TimerPeriodic,
    990                     KEYBOARD_TIMER_INTERVAL
    991                     );
    992     ASSERT_EFI_ERROR (Status);
    993 
    994     Status = gBS->CreateEvent (
    995                     EVT_TIMER,
    996                     TPL_CALLBACK,
    997                     NULL,
    998                     NULL,
    999                     &TerminalDevice->TwoSecondTimeOut
   1000                     );
   1001     ASSERT_EFI_ERROR (Status);
   1002 
   1003     Status = gBS->InstallProtocolInterface (
   1004                     &TerminalDevice->Handle,
   1005                     &gEfiDevicePathProtocolGuid,
   1006                     EFI_NATIVE_INTERFACE,
   1007                     TerminalDevice->DevicePath
   1008                     );
   1009     if (EFI_ERROR (Status)) {
   1010       goto Error;
   1011     }
   1012 
   1013     //
   1014     // Register the Parent-Child relationship via
   1015     // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
   1016     //
   1017     Status = gBS->OpenProtocol (
   1018                     Controller,
   1019                     &gEfiSerialIoProtocolGuid,
   1020                     (VOID **) &TerminalDevice->SerialIo,
   1021                     This->DriverBindingHandle,
   1022                     TerminalDevice->Handle,
   1023                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
   1024                     );
   1025     if (EFI_ERROR (Status)) {
   1026       goto Error;
   1027     }
   1028   }
   1029 
   1030   //
   1031   // Find the child handle, and get its TerminalDevice private data
   1032   //
   1033   Status = gBS->OpenProtocolInformation (
   1034                   Controller,
   1035                   &gEfiSerialIoProtocolGuid,
   1036                   &OpenInfoBuffer,
   1037                   &EntryCount
   1038                   );
   1039   if (!EFI_ERROR (Status)) {
   1040     Status = EFI_NOT_FOUND;
   1041     ASSERT (OpenInfoBuffer != NULL);
   1042     for (Index = 0; Index < EntryCount; Index++) {
   1043       if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
   1044         //
   1045         // Find the child terminal handle.
   1046         // Test whether the SimpleTxtIn and SimpleTxtOut have been published
   1047         //
   1048         Status = gBS->OpenProtocol (
   1049                         OpenInfoBuffer[Index].ControllerHandle,
   1050                         &gEfiSimpleTextInProtocolGuid,
   1051                         (VOID **) &SimpleTextInput,
   1052                         This->DriverBindingHandle,
   1053                         OpenInfoBuffer[Index].ControllerHandle,
   1054                         EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1055                         );
   1056         if (!EFI_ERROR (Status)) {
   1057           SimTxtInInstalled = TRUE;
   1058           TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);
   1059         }
   1060 
   1061         Status = gBS->OpenProtocol (
   1062                         OpenInfoBuffer[Index].ControllerHandle,
   1063                         &gEfiSimpleTextOutProtocolGuid,
   1064                         (VOID **) &SimpleTextOutput,
   1065                         This->DriverBindingHandle,
   1066                         OpenInfoBuffer[Index].ControllerHandle,
   1067                         EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1068                         );
   1069         if (!EFI_ERROR (Status)) {
   1070           SimTxtOutInstalled = TRUE;
   1071           TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
   1072         }
   1073         Status = EFI_SUCCESS;
   1074         break;
   1075       }
   1076     }
   1077 
   1078     FreePool (OpenInfoBuffer);
   1079     if (EFI_ERROR (Status)) {
   1080       goto ReportError;
   1081     }
   1082   } else {
   1083     goto ReportError;
   1084   }
   1085 
   1086   ASSERT (TerminalDevice != NULL);
   1087   //
   1088   // Only do the reset if the device path is in the Conout variable
   1089   //
   1090   if (ConInSelected && !SimTxtInInstalled) {
   1091     Status = TerminalDevice->SimpleInput.Reset (
   1092                                           &TerminalDevice->SimpleInput,
   1093                                           FALSE
   1094                                           );
   1095     if (EFI_ERROR (Status)) {
   1096       //
   1097       // Need to report Error Code first
   1098       //
   1099       goto ReportError;
   1100     }
   1101   }
   1102 
   1103   //
   1104   // Only output the configure string to remote terminal if the device path
   1105   // is in the Conout variable
   1106   //
   1107   if (ConOutSelected && !SimTxtOutInstalled) {
   1108     Status = TerminalDevice->SimpleTextOutput.SetAttribute (
   1109                                                         &TerminalDevice->SimpleTextOutput,
   1110                                                         EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
   1111                                                         );
   1112     if (EFI_ERROR (Status)) {
   1113       goto ReportError;
   1114     }
   1115 
   1116     Status = TerminalDevice->SimpleTextOutput.Reset (
   1117                                                 &TerminalDevice->SimpleTextOutput,
   1118                                                 FALSE
   1119                                                 );
   1120     if (EFI_ERROR (Status)) {
   1121       goto ReportError;
   1122     }
   1123 
   1124     Status = TerminalDevice->SimpleTextOutput.SetMode (
   1125                                                 &TerminalDevice->SimpleTextOutput,
   1126                                                 0
   1127                                                 );
   1128     if (EFI_ERROR (Status)) {
   1129       goto ReportError;
   1130     }
   1131 
   1132     Status = TerminalDevice->SimpleTextOutput.EnableCursor (
   1133                                                 &TerminalDevice->SimpleTextOutput,
   1134                                                 TRUE
   1135                                                 );
   1136     if (EFI_ERROR (Status)) {
   1137       goto ReportError;
   1138     }
   1139   }
   1140 
   1141   //
   1142   // Simple In/Out Protocol will not be installed onto the handle if the
   1143   // device path to the handle is not present in the ConIn/ConOut
   1144   // environment variable. But If RemainingDevicePath is NULL, then always
   1145   // produce both Simple In and Simple Text Output Protocols. This is required
   1146   // for the connect all sequences to make sure all possible consoles are
   1147   // produced no matter what the current values of ConIn, ConOut, or StdErr are.
   1148   //
   1149   if (!SimTxtInInstalled && (ConInSelected || NullRemaining)) {
   1150     Status = gBS->InstallMultipleProtocolInterfaces (
   1151                     &TerminalDevice->Handle,
   1152                     &gEfiSimpleTextInProtocolGuid,
   1153                     &TerminalDevice->SimpleInput,
   1154                     &gEfiSimpleTextInputExProtocolGuid,
   1155                     &TerminalDevice->SimpleInputEx,
   1156                     NULL
   1157                     );
   1158     if (EFI_ERROR (Status)) {
   1159       goto Error;
   1160     }
   1161   }
   1162 
   1163   if (!SimTxtOutInstalled && (ConOutSelected || NullRemaining)) {
   1164     Status = gBS->InstallProtocolInterface (
   1165                     &TerminalDevice->Handle,
   1166                     &gEfiSimpleTextOutProtocolGuid,
   1167                     EFI_NATIVE_INTERFACE,
   1168                     &TerminalDevice->SimpleTextOutput
   1169                     );
   1170     if (EFI_ERROR (Status)) {
   1171       goto Error;
   1172     }
   1173   }
   1174 
   1175   return EFI_SUCCESS;
   1176 
   1177 ReportError:
   1178   //
   1179   // Report error code before exiting
   1180   //
   1181   DevicePath = ParentDevicePath;
   1182   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
   1183     EFI_ERROR_CODE | EFI_ERROR_MINOR,
   1184     (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
   1185     DevicePath
   1186     );
   1187 
   1188 Error:
   1189   //
   1190   // Use the Stop() function to free all resources allocated in Start()
   1191   //
   1192   if (TerminalDevice != NULL) {
   1193 
   1194     if (TerminalDevice->Handle != NULL) {
   1195       This->Stop (This, Controller, 1, &TerminalDevice->Handle);
   1196     } else {
   1197 
   1198       if (TerminalDevice->TwoSecondTimeOut != NULL) {
   1199         gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
   1200       }
   1201 
   1202       if (TerminalDevice->TimerEvent != NULL) {
   1203         gBS->CloseEvent (TerminalDevice->TimerEvent);
   1204       }
   1205 
   1206       if (TerminalDevice->SimpleInput.WaitForKey != NULL) {
   1207         gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
   1208       }
   1209 
   1210       if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {
   1211         gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
   1212       }
   1213 
   1214       TerminalFreeNotifyList (&TerminalDevice->NotifyList);
   1215 
   1216       if (TerminalDevice->RawFiFo != NULL) {
   1217         FreePool (TerminalDevice->RawFiFo);
   1218       }
   1219       if (TerminalDevice->UnicodeFiFo != NULL) {
   1220         FreePool (TerminalDevice->UnicodeFiFo);
   1221       }
   1222       if (TerminalDevice->EfiKeyFiFo != NULL) {
   1223         FreePool (TerminalDevice->EfiKeyFiFo);
   1224       }
   1225 
   1226       if (TerminalDevice->ControllerNameTable != NULL) {
   1227         FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
   1228       }
   1229 
   1230       if (TerminalDevice->DevicePath != NULL) {
   1231         FreePool (TerminalDevice->DevicePath);
   1232       }
   1233 
   1234       if (TerminalDevice->TerminalConsoleModeData != NULL) {
   1235         FreePool (TerminalDevice->TerminalConsoleModeData);
   1236       }
   1237 
   1238       FreePool (TerminalDevice);
   1239     }
   1240   }
   1241 
   1242   This->Stop (This, Controller, 0, NULL);
   1243 
   1244   return Status;
   1245 }
   1246 
   1247 /**
   1248   Stop this driver on Controller by closing Simple Text In, Simple Text
   1249   In Ex, Simple Text Out protocol, and removing parent device path from
   1250   Console Device Environment Variables.
   1251 
   1252   @param  This              Protocol instance pointer.
   1253   @param  Controller        Handle of device to stop driver on
   1254   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
   1255                             children is zero stop the entire bus driver.
   1256   @param  ChildHandleBuffer List of Child Handles to Stop.
   1257 
   1258   @retval EFI_SUCCESS       This driver is removed Controller.
   1259   @retval other             This driver could not be removed from this device.
   1260 
   1261 **/
   1262 EFI_STATUS
   1263 EFIAPI
   1264 TerminalDriverBindingStop (
   1265   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
   1266   IN  EFI_HANDLE                    Controller,
   1267   IN  UINTN                         NumberOfChildren,
   1268   IN  EFI_HANDLE                    *ChildHandleBuffer
   1269   )
   1270 {
   1271   EFI_STATUS                       Status;
   1272   UINTN                            Index;
   1273   BOOLEAN                          AllChildrenStopped;
   1274   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *SimpleTextOutput;
   1275   TERMINAL_DEV                     *TerminalDevice;
   1276   EFI_DEVICE_PATH_PROTOCOL         *ParentDevicePath;
   1277   EFI_SERIAL_IO_PROTOCOL           *SerialIo;
   1278   EFI_DEVICE_PATH_PROTOCOL         *DevicePath;
   1279 
   1280   Status = gBS->HandleProtocol (
   1281                   Controller,
   1282                   &gEfiDevicePathProtocolGuid,
   1283                   (VOID **) &DevicePath
   1284                   );
   1285   if (EFI_ERROR (Status)) {
   1286     return Status;
   1287   }
   1288 
   1289   //
   1290   // Complete all outstanding transactions to Controller.
   1291   // Don't allow any new transaction to Controller to be started.
   1292   //
   1293   if (NumberOfChildren == 0) {
   1294     //
   1295     // Close the bus driver
   1296     //
   1297     Status = gBS->OpenProtocol (
   1298                     Controller,
   1299                     &gEfiCallerIdGuid,
   1300                     (VOID **) &ParentDevicePath,
   1301                     This->DriverBindingHandle,
   1302                     Controller,
   1303                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1304                     );
   1305     if (!EFI_ERROR (Status)) {
   1306       //
   1307       // Remove Parent Device Path from
   1308       // the Console Device Environment Variables
   1309       //
   1310       TerminalRemoveConsoleDevVariable (L"ConInDev", ParentDevicePath);
   1311       TerminalRemoveConsoleDevVariable (L"ConOutDev", ParentDevicePath);
   1312       TerminalRemoveConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
   1313 
   1314       //
   1315       // Uninstall the Terminal Driver's GUID Tag from the Serial controller
   1316       //
   1317       Status = gBS->UninstallMultipleProtocolInterfaces (
   1318                       Controller,
   1319                       &gEfiCallerIdGuid,
   1320                       ParentDevicePath,
   1321                       NULL
   1322                       );
   1323 
   1324       //
   1325       // Free the ParentDevicePath that was duplicated in Start()
   1326       //
   1327       if (!EFI_ERROR (Status)) {
   1328         FreePool (ParentDevicePath);
   1329       }
   1330     }
   1331 
   1332     gBS->CloseProtocol (
   1333           Controller,
   1334           &gEfiSerialIoProtocolGuid,
   1335           This->DriverBindingHandle,
   1336           Controller
   1337           );
   1338 
   1339     gBS->CloseProtocol (
   1340           Controller,
   1341           &gEfiDevicePathProtocolGuid,
   1342           This->DriverBindingHandle,
   1343           Controller
   1344           );
   1345 
   1346     return EFI_SUCCESS;
   1347   }
   1348 
   1349   AllChildrenStopped = TRUE;
   1350 
   1351   for (Index = 0; Index < NumberOfChildren; Index++) {
   1352 
   1353     Status = gBS->OpenProtocol (
   1354                     ChildHandleBuffer[Index],
   1355                     &gEfiSimpleTextOutProtocolGuid,
   1356                     (VOID **) &SimpleTextOutput,
   1357                     This->DriverBindingHandle,
   1358                     ChildHandleBuffer[Index],
   1359                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1360                     );
   1361     if (!EFI_ERROR (Status)) {
   1362 
   1363       TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
   1364 
   1365       gBS->CloseProtocol (
   1366             Controller,
   1367             &gEfiSerialIoProtocolGuid,
   1368             This->DriverBindingHandle,
   1369             ChildHandleBuffer[Index]
   1370             );
   1371 
   1372       Status = gBS->UninstallMultipleProtocolInterfaces (
   1373                       ChildHandleBuffer[Index],
   1374                       &gEfiSimpleTextInProtocolGuid,
   1375                       &TerminalDevice->SimpleInput,
   1376                       &gEfiSimpleTextInputExProtocolGuid,
   1377                       &TerminalDevice->SimpleInputEx,
   1378                       &gEfiSimpleTextOutProtocolGuid,
   1379                       &TerminalDevice->SimpleTextOutput,
   1380                       &gEfiDevicePathProtocolGuid,
   1381                       TerminalDevice->DevicePath,
   1382                       NULL
   1383                       );
   1384       if (EFI_ERROR (Status)) {
   1385         gBS->OpenProtocol (
   1386               Controller,
   1387               &gEfiSerialIoProtocolGuid,
   1388               (VOID **) &SerialIo,
   1389               This->DriverBindingHandle,
   1390               ChildHandleBuffer[Index],
   1391               EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
   1392               );
   1393       } else {
   1394 
   1395         if (TerminalDevice->ControllerNameTable != NULL) {
   1396           FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
   1397         }
   1398 
   1399         gBS->CloseEvent (TerminalDevice->TimerEvent);
   1400         gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
   1401         gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
   1402         gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
   1403         TerminalFreeNotifyList (&TerminalDevice->NotifyList);
   1404         FreePool (TerminalDevice->DevicePath);
   1405         if (TerminalDevice->TerminalConsoleModeData != NULL) {
   1406           FreePool (TerminalDevice->TerminalConsoleModeData);
   1407         }
   1408         FreePool (TerminalDevice);
   1409       }
   1410     }
   1411 
   1412     if (EFI_ERROR (Status)) {
   1413       AllChildrenStopped = FALSE;
   1414     }
   1415   }
   1416 
   1417   if (!AllChildrenStopped) {
   1418     return EFI_DEVICE_ERROR;
   1419   }
   1420 
   1421   return EFI_SUCCESS;
   1422 }
   1423 
   1424 /**
   1425   Update terminal device path in Console Device Environment Variables.
   1426 
   1427   @param  VariableName           The Console Device Environment Variable.
   1428   @param  ParentDevicePath       The terminal device path to be updated.
   1429 
   1430 **/
   1431 VOID
   1432 TerminalUpdateConsoleDevVariable (
   1433   IN CHAR16                    *VariableName,
   1434   IN EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath
   1435   )
   1436 {
   1437   EFI_STATUS                Status;
   1438   UINTN                     NameSize;
   1439   UINTN                     VariableSize;
   1440   UINT8                     TerminalType;
   1441   EFI_DEVICE_PATH_PROTOCOL  *Variable;
   1442   EFI_DEVICE_PATH_PROTOCOL  *NewVariable;
   1443   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
   1444   EDKII_SET_VARIABLE_STATUS *SetVariableStatus;
   1445 
   1446   //
   1447   // Get global variable and its size according to the name given.
   1448   //
   1449   GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
   1450   if (Variable == NULL) {
   1451     return;
   1452   }
   1453 
   1454   //
   1455   // Append terminal device path onto the variable.
   1456   //
   1457   for (TerminalType = PCANSITYPE; TerminalType <= TTYTERMTYPE; TerminalType++) {
   1458     SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
   1459     NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);
   1460     ASSERT (NewVariable != NULL);
   1461     if (Variable != NULL) {
   1462       FreePool (Variable);
   1463     }
   1464 
   1465     if (TempDevicePath != NULL) {
   1466       FreePool (TempDevicePath);
   1467     }
   1468 
   1469     Variable = NewVariable;
   1470   }
   1471 
   1472   VariableSize = GetDevicePathSize (Variable);
   1473 
   1474   Status = gRT->SetVariable (
   1475                   VariableName,
   1476                   &gEfiGlobalVariableGuid,
   1477                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
   1478                   VariableSize,
   1479                   Variable
   1480                   );
   1481 
   1482   if (EFI_ERROR (Status)) {
   1483     NameSize = StrSize (VariableName);
   1484     SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize);
   1485     if (SetVariableStatus != NULL) {
   1486       CopyGuid (&SetVariableStatus->Guid, &gEfiGlobalVariableGuid);
   1487       SetVariableStatus->NameSize   = NameSize;
   1488       SetVariableStatus->DataSize   = VariableSize;
   1489       SetVariableStatus->SetStatus  = Status;
   1490       SetVariableStatus->Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
   1491       CopyMem (SetVariableStatus + 1,                          VariableName, NameSize);
   1492       CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Variable,     VariableSize);
   1493 
   1494       REPORT_STATUS_CODE_EX (
   1495         EFI_ERROR_CODE,
   1496         PcdGet32 (PcdErrorCodeSetVariable),
   1497         0,
   1498         NULL,
   1499         &gEdkiiStatusCodeDataTypeVariableGuid,
   1500         SetVariableStatus,
   1501         sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize
   1502         );
   1503 
   1504       FreePool (SetVariableStatus);
   1505     }
   1506   }
   1507 
   1508   FreePool (Variable);
   1509 
   1510   return ;
   1511 }
   1512 
   1513 
   1514 /**
   1515   Remove terminal device path from Console Device Environment Variables.
   1516 
   1517   @param  VariableName           Console Device Environment Variables.
   1518   @param  ParentDevicePath       The terminal device path to be updated.
   1519 
   1520 **/
   1521 VOID
   1522 TerminalRemoveConsoleDevVariable (
   1523   IN CHAR16                    *VariableName,
   1524   IN EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath
   1525   )
   1526 {
   1527   EFI_STATUS                Status;
   1528   BOOLEAN                   FoundOne;
   1529   BOOLEAN                   Match;
   1530   UINTN                     VariableSize;
   1531   UINTN                     InstanceSize;
   1532   UINT8                     TerminalType;
   1533   EFI_DEVICE_PATH_PROTOCOL  *Instance;
   1534   EFI_DEVICE_PATH_PROTOCOL  *Variable;
   1535   EFI_DEVICE_PATH_PROTOCOL  *OriginalVariable;
   1536   EFI_DEVICE_PATH_PROTOCOL  *NewVariable;
   1537   EFI_DEVICE_PATH_PROTOCOL  *SavedNewVariable;
   1538   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
   1539 
   1540   Instance  = NULL;
   1541 
   1542   //
   1543   // Get global variable and its size according to the name given.
   1544   //
   1545   GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
   1546   if (Variable == NULL) {
   1547     return ;
   1548   }
   1549 
   1550   FoundOne          = FALSE;
   1551   OriginalVariable  = Variable;
   1552   NewVariable       = NULL;
   1553 
   1554   //
   1555   // Get first device path instance from Variable
   1556   //
   1557   Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
   1558   if (Instance == NULL) {
   1559     FreePool (OriginalVariable);
   1560     return ;
   1561   }
   1562   //
   1563   // Loop through all the device path instances of Variable
   1564   //
   1565   do {
   1566     //
   1567     // Loop through all the terminal types that this driver supports
   1568     //
   1569     Match = FALSE;
   1570     for (TerminalType = PCANSITYPE; TerminalType <= TTYTERMTYPE; TerminalType++) {
   1571 
   1572       SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
   1573 
   1574       //
   1575       // Compare the generated device path to the current device path instance
   1576       //
   1577       if (TempDevicePath != NULL) {
   1578         if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {
   1579           Match     = TRUE;
   1580           FoundOne  = TRUE;
   1581         }
   1582 
   1583         FreePool (TempDevicePath);
   1584       }
   1585     }
   1586     //
   1587     // If a match was not found, then keep the current device path instance
   1588     //
   1589     if (!Match) {
   1590       SavedNewVariable  = NewVariable;
   1591       NewVariable       = AppendDevicePathInstance (NewVariable, Instance);
   1592       if (SavedNewVariable != NULL) {
   1593         FreePool (SavedNewVariable);
   1594       }
   1595     }
   1596     //
   1597     // Get next device path instance from Variable
   1598     //
   1599     FreePool (Instance);
   1600     Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
   1601   } while (Instance != NULL);
   1602 
   1603   FreePool (OriginalVariable);
   1604 
   1605   if (FoundOne) {
   1606     VariableSize = GetDevicePathSize (NewVariable);
   1607 
   1608     Status = gRT->SetVariable (
   1609                     VariableName,
   1610                     &gEfiGlobalVariableGuid,
   1611                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
   1612                     VariableSize,
   1613                     NewVariable
   1614                     );
   1615     //
   1616     // Shrinking variable with existing variable driver implementation shouldn't fail.
   1617     //
   1618     ASSERT_EFI_ERROR (Status);
   1619   }
   1620 
   1621   if (NewVariable != NULL) {
   1622     FreePool (NewVariable);
   1623   }
   1624 
   1625   return ;
   1626 }
   1627 
   1628 /**
   1629   Build terminal device path according to terminal type.
   1630 
   1631   @param  TerminalType           The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.
   1632   @param  ParentDevicePath       Parent device path.
   1633   @param  TerminalDevicePath     Returned terminal device path, if building successfully.
   1634 
   1635   @retval EFI_UNSUPPORTED        Terminal does not belong to the supported type.
   1636   @retval EFI_OUT_OF_RESOURCES   Generate terminal device path failed.
   1637   @retval EFI_SUCCESS            Build terminal device path successfully.
   1638 
   1639 **/
   1640 EFI_STATUS
   1641 SetTerminalDevicePath (
   1642   IN  UINT8                       TerminalType,
   1643   IN  EFI_DEVICE_PATH_PROTOCOL    *ParentDevicePath,
   1644   OUT EFI_DEVICE_PATH_PROTOCOL    **TerminalDevicePath
   1645   )
   1646 {
   1647   VENDOR_DEVICE_PATH  Node;
   1648 
   1649   *TerminalDevicePath = NULL;
   1650   Node.Header.Type    = MESSAGING_DEVICE_PATH;
   1651   Node.Header.SubType = MSG_VENDOR_DP;
   1652 
   1653   //
   1654   // Generate terminal device path node according to terminal type.
   1655   //
   1656   switch (TerminalType) {
   1657 
   1658   case PCANSITYPE:
   1659     CopyGuid (&Node.Guid, &gEfiPcAnsiGuid);
   1660     break;
   1661 
   1662   case VT100TYPE:
   1663     CopyGuid (&Node.Guid, &gEfiVT100Guid);
   1664     break;
   1665 
   1666   case VT100PLUSTYPE:
   1667     CopyGuid (&Node.Guid, &gEfiVT100PlusGuid);
   1668     break;
   1669 
   1670   case VTUTF8TYPE:
   1671     CopyGuid (&Node.Guid, &gEfiVTUTF8Guid);
   1672     break;
   1673 
   1674   case TTYTERMTYPE:
   1675     CopyGuid (&Node.Guid, &gEfiTtyTermGuid);
   1676     break;
   1677 
   1678   default:
   1679     return EFI_UNSUPPORTED;
   1680   }
   1681 
   1682   //
   1683   // Get VENDOR_DEVCIE_PATH size and put into Node.Header
   1684   //
   1685   SetDevicePathNodeLength (
   1686     &Node.Header,
   1687     sizeof (VENDOR_DEVICE_PATH)
   1688     );
   1689 
   1690   //
   1691   // Append the terminal node onto parent device path
   1692   // to generate a complete terminal device path.
   1693   //
   1694   *TerminalDevicePath = AppendDevicePathNode (
   1695                           ParentDevicePath,
   1696                           (EFI_DEVICE_PATH_PROTOCOL *) &Node
   1697                           );
   1698   if (*TerminalDevicePath == NULL) {
   1699     return EFI_OUT_OF_RESOURCES;
   1700   }
   1701 
   1702   return EFI_SUCCESS;
   1703 }
   1704 
   1705 /**
   1706   The user Entry Point for module Terminal. The user code starts with this function.
   1707 
   1708   @param  ImageHandle    The firmware allocated handle for the EFI image.
   1709   @param  SystemTable    A pointer to the EFI System Table.
   1710 
   1711   @retval EFI_SUCCESS       The entry point is executed successfully.
   1712   @retval other             Some error occurs when executing this entry point.
   1713 
   1714 **/
   1715 EFI_STATUS
   1716 EFIAPI
   1717 InitializeTerminal(
   1718   IN EFI_HANDLE           ImageHandle,
   1719   IN EFI_SYSTEM_TABLE     *SystemTable
   1720   )
   1721 {
   1722   EFI_STATUS              Status;
   1723 
   1724   //
   1725   // Install driver model protocol(s).
   1726   //
   1727   Status = EfiLibInstallDriverBindingComponentName2 (
   1728              ImageHandle,
   1729              SystemTable,
   1730              &gTerminalDriverBinding,
   1731              ImageHandle,
   1732              &gTerminalComponentName,
   1733              &gTerminalComponentName2
   1734              );
   1735   ASSERT_EFI_ERROR (Status);
   1736 
   1737   return Status;
   1738 }
   1739 
   1740 /**
   1741   Check if the device supports hot-plug through its device path.
   1742 
   1743   This function could be updated to check more types of Hot Plug devices.
   1744   Currently, it checks USB and PCCard device.
   1745 
   1746   @param  DevicePath            Pointer to device's device path.
   1747 
   1748   @retval TRUE                  The devcie is a hot-plug device
   1749   @retval FALSE                 The devcie is not a hot-plug device.
   1750 
   1751 **/
   1752 BOOLEAN
   1753 IsHotPlugDevice (
   1754   IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath
   1755   )
   1756 {
   1757   EFI_DEVICE_PATH_PROTOCOL     *CheckDevicePath;
   1758 
   1759   CheckDevicePath = DevicePath;
   1760   while (!IsDevicePathEnd (CheckDevicePath)) {
   1761     //
   1762     // Check device whether is hot plug device or not throught Device Path
   1763     //
   1764     if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&
   1765         (DevicePathSubType (CheckDevicePath) == MSG_USB_DP ||
   1766          DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP ||
   1767          DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) {
   1768       //
   1769       // If Device is USB device
   1770       //
   1771       return TRUE;
   1772     }
   1773     if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&
   1774         (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) {
   1775       //
   1776       // If Device is PCCard
   1777       //
   1778       return TRUE;
   1779     }
   1780 
   1781     CheckDevicePath = NextDevicePathNode (CheckDevicePath);
   1782   }
   1783 
   1784   return FALSE;
   1785 }
   1786 
   1787