Home | History | Annotate | Download | only in BootMaint
      1 /** @file
      2   handles console redirection from boot manager
      3 
      4 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "BootMaint.h"
     16 
     17 UART_FLOW_CONTROL_DEVICE_PATH mFlowControlDevicePath =
     18 {
     19   {
     20     MESSAGING_DEVICE_PATH,
     21     MSG_VENDOR_DP,
     22     {
     23       (UINT8)(sizeof(UART_FLOW_CONTROL_DEVICE_PATH)),
     24       (UINT8)((sizeof(UART_FLOW_CONTROL_DEVICE_PATH)) >> 8)
     25     }
     26   },
     27   DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL,
     28   UART_FLOW_CONTROL_HARDWARE
     29 };
     30 
     31 /**
     32   Check the device path node whether it's the Flow Control node or not.
     33 
     34   @param[in] FlowControl    The device path node to be checked.
     35 
     36   @retval TRUE              It's the Flow Control node.
     37   @retval FALSE             It's not.
     38 
     39 **/
     40 BOOLEAN
     41 IsUartFlowControlNode (
     42   IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl
     43   )
     44 {
     45   return (BOOLEAN) (
     46            (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&
     47            (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&
     48            (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))
     49            );
     50 }
     51 
     52 /**
     53   Check whether the device path node is ISA Serial Node.
     54 
     55   @param Acpi           Device path node to be checked
     56 
     57   @retval TRUE          It's ISA Serial Node.
     58   @retval FALSE         It's NOT ISA Serial Node.
     59 
     60 **/
     61 BOOLEAN
     62 IsIsaSerialNode (
     63   IN ACPI_HID_DEVICE_PATH *Acpi
     64   )
     65 {
     66   return (BOOLEAN) (
     67       (DevicePathType (Acpi) == ACPI_DEVICE_PATH) &&
     68       (DevicePathSubType (Acpi) == ACPI_DP) &&
     69       (ReadUnaligned32 (&Acpi->HID) == EISA_PNP_ID (0x0501))
     70       );
     71 }
     72 
     73 /**
     74   Update Com Ports attributes from DevicePath
     75 
     76   @param DevicePath      DevicePath that contains Com ports
     77 
     78   @retval EFI_SUCCESS   The update is successful.
     79 
     80 **/
     81 EFI_STATUS
     82 UpdateComAttributeFromVariable (
     83   EFI_DEVICE_PATH_PROTOCOL  *DevicePath
     84   );
     85 
     86 /**
     87   Update the multi-instance device path of Terminal Device based on
     88   the global TerminalMenu. If ChangeTernimal is TRUE, the terminal
     89   device path in the Terminal Device in TerminalMenu is also updated.
     90 
     91   @param DevicePath      The multi-instance device path.
     92   @param ChangeTerminal  TRUE, then device path in the Terminal Device
     93                          in TerminalMenu is also updated; FALSE, no update.
     94 
     95   @return EFI_SUCCESS    The function completes successfully.
     96 
     97 **/
     98 EFI_STATUS
     99 ChangeTerminalDevicePath (
    100   IN OUT    EFI_DEVICE_PATH_PROTOCOL  **DevicePath,
    101   IN        BOOLEAN                   ChangeTerminal
    102   )
    103 {
    104   EFI_DEVICE_PATH_PROTOCOL  *Node;
    105   EFI_DEVICE_PATH_PROTOCOL  *Node1;
    106   ACPI_HID_DEVICE_PATH      *Acpi;
    107   UART_DEVICE_PATH          *Uart;
    108   UART_DEVICE_PATH          *Uart1;
    109   UINTN                     Com;
    110   BM_TERMINAL_CONTEXT       *NewTerminalContext;
    111   BM_MENU_ENTRY             *NewMenuEntry;
    112   UART_FLOW_CONTROL_DEVICE_PATH *FlowControlNode;
    113 
    114   Node  = *DevicePath;
    115   Node  = NextDevicePathNode (Node);
    116   Com   = 0;
    117   while (!IsDevicePathEnd (Node)) {
    118     Acpi = (ACPI_HID_DEVICE_PATH *) Node;
    119     if (IsIsaSerialNode (Acpi)) {
    120       CopyMem (&Com, &Acpi->UID, sizeof (UINT32));
    121     }
    122 
    123     NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Com);
    124 
    125     NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
    126     if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
    127       Uart = (UART_DEVICE_PATH *) Node;
    128       CopyMem (
    129         &Uart->BaudRate,
    130         &NewTerminalContext->BaudRate,
    131         sizeof (UINT64)
    132         );
    133 
    134       CopyMem (
    135         &Uart->DataBits,
    136         &NewTerminalContext->DataBits,
    137         sizeof (UINT8)
    138         );
    139 
    140       CopyMem (
    141         &Uart->Parity,
    142         &NewTerminalContext->Parity,
    143         sizeof (UINT8)
    144         );
    145 
    146       CopyMem (
    147         &Uart->StopBits,
    148         &NewTerminalContext->StopBits,
    149         sizeof (UINT8)
    150         );
    151 
    152       FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Node);
    153       if (IsUartFlowControlNode (FlowControlNode)) {
    154         FlowControlNode->FlowControlMap = NewTerminalContext->FlowControl;
    155       } else {
    156         //
    157         // Append the Flow control device node when user enable flow control.
    158         //
    159         if (NewTerminalContext->FlowControl != 0) {
    160           mFlowControlDevicePath.FlowControlMap = NewTerminalContext->FlowControl;
    161           *DevicePath = AppendDevicePathNode (
    162                                        *DevicePath,
    163                                        (EFI_DEVICE_PATH_PROTOCOL *) (&mFlowControlDevicePath)
    164                                        );
    165         }
    166       }
    167 
    168       //
    169       // Change the device path in the ComPort
    170       //
    171       if (ChangeTerminal) {
    172         Node1 = NewTerminalContext->DevicePath;
    173         Node1 = NextDevicePathNode (Node1);
    174         while (!IsDevicePathEnd (Node1)) {
    175           if ((DevicePathType (Node1) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node1) == MSG_UART_DP)) {
    176             Uart1 = (UART_DEVICE_PATH *) Node1;
    177             CopyMem (
    178               &Uart1->BaudRate,
    179               &NewTerminalContext->BaudRate,
    180               sizeof (UINT64)
    181               );
    182 
    183             CopyMem (
    184               &Uart1->DataBits,
    185               &NewTerminalContext->DataBits,
    186               sizeof (UINT8)
    187               );
    188 
    189             CopyMem (
    190               &Uart1->Parity,
    191               &NewTerminalContext->Parity,
    192               sizeof (UINT8)
    193               );
    194 
    195             CopyMem (
    196               &Uart1->StopBits,
    197               &NewTerminalContext->StopBits,
    198               sizeof (UINT8)
    199               );
    200             break;
    201           }
    202           //
    203           // end if
    204           //
    205           Node1 = NextDevicePathNode (Node1);
    206         }
    207         //
    208         // end while
    209         //
    210         break;
    211       }
    212     }
    213 
    214     Node = NextDevicePathNode (Node);
    215   }
    216 
    217   return EFI_SUCCESS;
    218 
    219 }
    220 
    221 /**
    222   Update the device path that describing a terminal device
    223   based on the new BaudRate, Data Bits, parity and Stop Bits
    224   set.
    225 
    226   @param DevicePath terminal device's path
    227 
    228 **/
    229 VOID
    230 ChangeVariableDevicePath (
    231   IN OUT EFI_DEVICE_PATH_PROTOCOL  *DevicePath
    232   )
    233 {
    234   EFI_DEVICE_PATH_PROTOCOL  *Node;
    235   ACPI_HID_DEVICE_PATH      *Acpi;
    236   UART_DEVICE_PATH          *Uart;
    237   UINTN                     Com;
    238   BM_TERMINAL_CONTEXT       *NewTerminalContext;
    239   BM_MENU_ENTRY             *NewMenuEntry;
    240 
    241   Node  = DevicePath;
    242   Node  = NextDevicePathNode (Node);
    243   Com   = 0;
    244   while (!IsDevicePathEnd (Node)) {
    245     Acpi = (ACPI_HID_DEVICE_PATH *) Node;
    246     if (IsIsaSerialNode (Acpi)) {
    247       CopyMem (&Com, &Acpi->UID, sizeof (UINT32));
    248     }
    249 
    250     if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
    251       NewMenuEntry = BOpt_GetMenuEntry (
    252                       &TerminalMenu,
    253                       Com
    254                       );
    255       ASSERT (NewMenuEntry != NULL);
    256       NewTerminalContext  = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
    257       Uart                = (UART_DEVICE_PATH *) Node;
    258       CopyMem (
    259         &Uart->BaudRate,
    260         &NewTerminalContext->BaudRate,
    261         sizeof (UINT64)
    262         );
    263 
    264       CopyMem (
    265         &Uart->DataBits,
    266         &NewTerminalContext->DataBits,
    267         sizeof (UINT8)
    268         );
    269 
    270       CopyMem (
    271         &Uart->Parity,
    272         &NewTerminalContext->Parity,
    273         sizeof (UINT8)
    274         );
    275 
    276       CopyMem (
    277         &Uart->StopBits,
    278         &NewTerminalContext->StopBits,
    279         sizeof (UINT8)
    280         );
    281     }
    282 
    283     Node = NextDevicePathNode (Node);
    284   }
    285 }
    286 
    287 /**
    288   Retrieve ACPI UID of UART from device path
    289 
    290   @param Handle          The handle for the UART device.
    291   @param AcpiUid         The ACPI UID on output.
    292 
    293   @retval  TRUE   Find valid UID from device path
    294   @retval  FALSE  Can't find
    295 
    296 **/
    297 BOOLEAN
    298 RetrieveUartUid (
    299   IN EFI_HANDLE   Handle,
    300   IN OUT UINT32   *AcpiUid
    301   )
    302 {
    303   EFI_STATUS                Status;
    304   ACPI_HID_DEVICE_PATH      *Acpi;
    305   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    306 
    307   Status = gBS->HandleProtocol (
    308                   Handle,
    309                   &gEfiDevicePathProtocolGuid,
    310                   (VOID **) &DevicePath
    311                   );
    312   if (EFI_ERROR (Status)) {
    313     return FALSE;
    314   }
    315 
    316   Acpi = NULL;
    317   for (; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) {
    318     if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (DevicePath) == MSG_UART_DP)) {
    319       break;
    320     }
    321     //
    322     // Acpi points to the node before the Uart node
    323     //
    324     Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath;
    325   }
    326 
    327   if ((Acpi != NULL) && IsIsaSerialNode (Acpi)) {
    328     if (AcpiUid != NULL) {
    329       CopyMem (AcpiUid, &Acpi->UID, sizeof (UINT32));
    330     }
    331     return TRUE;
    332   } else {
    333     return FALSE;
    334   }
    335 }
    336 
    337 /**
    338   Sort Uart handles array with Acpi->UID from low to high.
    339 
    340   @param Handles         EFI_SERIAL_IO_PROTOCOL handle buffer
    341   @param NoHandles       EFI_SERIAL_IO_PROTOCOL handle count
    342 **/
    343 VOID
    344 SortedUartHandle (
    345   IN  EFI_HANDLE *Handles,
    346   IN  UINTN      NoHandles
    347   )
    348 {
    349   UINTN       Index1;
    350   UINTN       Index2;
    351   UINTN       Position;
    352   UINT32      AcpiUid1;
    353   UINT32      AcpiUid2;
    354   UINT32      TempAcpiUid;
    355   EFI_HANDLE  TempHandle;
    356 
    357   for (Index1 = 0; Index1 < NoHandles-1; Index1++) {
    358     if (!RetrieveUartUid (Handles[Index1], &AcpiUid1)) {
    359       continue;
    360     }
    361     TempHandle  = Handles[Index1];
    362     Position    = Index1;
    363     TempAcpiUid = AcpiUid1;
    364 
    365     for (Index2 = Index1+1; Index2 < NoHandles; Index2++) {
    366       if (!RetrieveUartUid (Handles[Index2], &AcpiUid2)) {
    367         continue;
    368       }
    369       if (AcpiUid2 < TempAcpiUid) {
    370         TempAcpiUid = AcpiUid2;
    371         TempHandle  = Handles[Index2];
    372         Position    = Index2;
    373       }
    374     }
    375     Handles[Position] = Handles[Index1];
    376     Handles[Index1]   = TempHandle;
    377   }
    378 }
    379 
    380 /**
    381   Test whether DevicePath is a valid Terminal
    382 
    383 
    384   @param DevicePath      DevicePath to be checked
    385   @param Termi           If DevicePath is valid Terminal, terminal type is returned.
    386   @param Com             If DevicePath is valid Terminal, Com Port type is returned.
    387 
    388   @retval  TRUE         If DevicePath point to a Terminal.
    389   @retval  FALSE        If DevicePath does not point to a Terminal.
    390 
    391 **/
    392 BOOLEAN
    393 IsTerminalDevicePath (
    394   IN  EFI_DEVICE_PATH_PROTOCOL *DevicePath,
    395   OUT TYPE_OF_TERMINAL         *Termi,
    396   OUT UINTN                    *Com
    397   );
    398 
    399 /**
    400   Build a list containing all serial devices.
    401 
    402 
    403   @retval EFI_SUCCESS The function complete successfully.
    404   @retval EFI_UNSUPPORTED No serial ports present.
    405 
    406 **/
    407 EFI_STATUS
    408 LocateSerialIo (
    409   VOID
    410   )
    411 {
    412   UINTN                     Index;
    413   UINTN                     Index2;
    414   UINTN                     NoHandles;
    415   EFI_HANDLE                *Handles;
    416   EFI_STATUS                Status;
    417   ACPI_HID_DEVICE_PATH      *Acpi;
    418   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    419   EFI_SERIAL_IO_PROTOCOL    *SerialIo;
    420   EFI_DEVICE_PATH_PROTOCOL  *Node;
    421   EFI_DEVICE_PATH_PROTOCOL  *OutDevicePath;
    422   EFI_DEVICE_PATH_PROTOCOL  *InpDevicePath;
    423   EFI_DEVICE_PATH_PROTOCOL  *ErrDevicePath;
    424   BM_MENU_ENTRY             *NewMenuEntry;
    425   BM_TERMINAL_CONTEXT       *NewTerminalContext;
    426   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
    427   VENDOR_DEVICE_PATH        Vendor;
    428   UINT32                    FlowControl;
    429   //
    430   // Get all handles that have SerialIo protocol installed
    431   //
    432   InitializeListHead (&TerminalMenu.Head);
    433   TerminalMenu.MenuNumber = 0;
    434   Status = gBS->LocateHandleBuffer (
    435                   ByProtocol,
    436                   &gEfiSerialIoProtocolGuid,
    437                   NULL,
    438                   &NoHandles,
    439                   &Handles
    440                   );
    441   if (EFI_ERROR (Status)) {
    442     //
    443     // No serial ports present
    444     //
    445     return EFI_UNSUPPORTED;
    446   }
    447 
    448   //
    449   // Sort Uart handles array with Acpi->UID from low to high
    450   // then Terminal menu can be built from low Acpi->UID to high Acpi->UID
    451   //
    452   SortedUartHandle (Handles, NoHandles);
    453 
    454   for (Index = 0; Index < NoHandles; Index++) {
    455     //
    456     // Check to see whether the handle has DevicePath Protocol installed
    457     //
    458     gBS->HandleProtocol (
    459           Handles[Index],
    460           &gEfiDevicePathProtocolGuid,
    461           (VOID **) &DevicePath
    462           );
    463 
    464     Acpi = NULL;
    465     for (Node = DevicePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
    466       if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
    467         break;
    468       }
    469       //
    470       // Acpi points to the node before Uart node
    471       //
    472       Acpi = (ACPI_HID_DEVICE_PATH *) Node;
    473     }
    474 
    475     if ((Acpi != NULL) && IsIsaSerialNode (Acpi)) {
    476       NewMenuEntry = BOpt_CreateMenuEntry (BM_TERMINAL_CONTEXT_SELECT);
    477       if (NewMenuEntry == NULL) {
    478         FreePool (Handles);
    479         return EFI_OUT_OF_RESOURCES;
    480       }
    481 
    482       NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
    483       CopyMem (&NewMenuEntry->OptionNumber, &Acpi->UID, sizeof (UINT32));
    484       NewTerminalContext->DevicePath = DuplicateDevicePath (DevicePath);
    485       //
    486       // BugBug: I have no choice, calling EfiLibStrFromDatahub will hang the system!
    487       // coz' the misc data for each platform is not correct, actually it's the device path stored in
    488       // datahub which is not completed, so a searching for end of device path will enter a
    489       // dead-loop.
    490       //
    491       NewMenuEntry->DisplayString = EfiLibStrFromDatahub (DevicePath);
    492       if (NULL == NewMenuEntry->DisplayString) {
    493         NewMenuEntry->DisplayString = DevicePathToStr (DevicePath);
    494       }
    495 
    496       NewMenuEntry->HelpString = NULL;
    497 
    498       gBS->HandleProtocol (
    499             Handles[Index],
    500             &gEfiSerialIoProtocolGuid,
    501             (VOID **) &SerialIo
    502             );
    503 
    504       CopyMem (
    505         &NewTerminalContext->BaudRate,
    506         &SerialIo->Mode->BaudRate,
    507         sizeof (UINT64)
    508         );
    509 
    510       CopyMem (
    511         &NewTerminalContext->DataBits,
    512         &SerialIo->Mode->DataBits,
    513         sizeof (UINT8)
    514         );
    515 
    516       CopyMem (
    517         &NewTerminalContext->Parity,
    518         &SerialIo->Mode->Parity,
    519         sizeof (UINT8)
    520         );
    521 
    522       CopyMem (
    523         &NewTerminalContext->StopBits,
    524         &SerialIo->Mode->StopBits,
    525         sizeof (UINT8)
    526         );
    527 
    528       NewTerminalContext->FlowControl = 0;
    529       SerialIo->GetControl(SerialIo, &FlowControl);
    530       if ((FlowControl & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) != 0) {
    531         NewTerminalContext->FlowControl = UART_FLOW_CONTROL_HARDWARE;
    532       }
    533 
    534       InsertTailList (&TerminalMenu.Head, &NewMenuEntry->Link);
    535       TerminalMenu.MenuNumber++;
    536     }
    537   }
    538   if (Handles != NULL) {
    539     FreePool (Handles);
    540   }
    541 
    542   //
    543   // Get L"ConOut", L"ConIn" and L"ErrOut" from the Var
    544   //
    545   OutDevicePath = EfiLibGetVariable (L"ConOut", &gEfiGlobalVariableGuid);
    546   InpDevicePath = EfiLibGetVariable (L"ConIn", &gEfiGlobalVariableGuid);
    547   ErrDevicePath = EfiLibGetVariable (L"ErrOut", &gEfiGlobalVariableGuid);
    548   if (OutDevicePath != NULL) {
    549     UpdateComAttributeFromVariable (OutDevicePath);
    550   }
    551 
    552   if (InpDevicePath != NULL) {
    553     UpdateComAttributeFromVariable (InpDevicePath);
    554   }
    555 
    556   if (ErrDevicePath != NULL) {
    557     UpdateComAttributeFromVariable (ErrDevicePath);
    558   }
    559 
    560   for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
    561     NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
    562     if (NULL == NewMenuEntry) {
    563       return EFI_NOT_FOUND;
    564     }
    565 
    566     NewTerminalContext                = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
    567 
    568     NewTerminalContext->TerminalType  = 0;
    569     NewTerminalContext->IsConIn       = FALSE;
    570     NewTerminalContext->IsConOut      = FALSE;
    571     NewTerminalContext->IsStdErr      = FALSE;
    572 
    573     Vendor.Header.Type                = MESSAGING_DEVICE_PATH;
    574     Vendor.Header.SubType             = MSG_VENDOR_DP;
    575 
    576     for (Index2 = 0; Index2 < 4; Index2++) {
    577       CopyMem (&Vendor.Guid, &TerminalTypeGuid[Index2], sizeof (EFI_GUID));
    578       SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH));
    579       NewDevicePath = AppendDevicePathNode (
    580                         NewTerminalContext->DevicePath,
    581                         (EFI_DEVICE_PATH_PROTOCOL *) &Vendor
    582                         );
    583       if (NewMenuEntry->HelpString != NULL) {
    584         FreePool (NewMenuEntry->HelpString);
    585       }
    586       //
    587       // NewMenuEntry->HelpString = DevicePathToStr (NewDevicePath);
    588       // NewMenuEntry->DisplayString = NewMenuEntry->HelpString;
    589       //
    590       NewMenuEntry->HelpString = NULL;
    591 
    592       if (BdsLibMatchDevicePaths (OutDevicePath, NewDevicePath)) {
    593         NewTerminalContext->IsConOut      = TRUE;
    594         NewTerminalContext->TerminalType  = (UINT8) Index2;
    595       }
    596 
    597       if (BdsLibMatchDevicePaths (InpDevicePath, NewDevicePath)) {
    598         NewTerminalContext->IsConIn       = TRUE;
    599         NewTerminalContext->TerminalType  = (UINT8) Index2;
    600       }
    601 
    602       if (BdsLibMatchDevicePaths (ErrDevicePath, NewDevicePath)) {
    603         NewTerminalContext->IsStdErr      = TRUE;
    604         NewTerminalContext->TerminalType  = (UINT8) Index2;
    605       }
    606     }
    607   }
    608 
    609   return EFI_SUCCESS;
    610 }
    611 
    612 /**
    613   Update Com Ports attributes from DevicePath
    614 
    615   @param DevicePath      DevicePath that contains Com ports
    616 
    617   @retval EFI_SUCCESS   The update is successful.
    618   @retval EFI_NOT_FOUND Can not find specific menu entry
    619 **/
    620 EFI_STATUS
    621 UpdateComAttributeFromVariable (
    622   EFI_DEVICE_PATH_PROTOCOL  *DevicePath
    623   )
    624 {
    625   EFI_DEVICE_PATH_PROTOCOL  *Node;
    626   EFI_DEVICE_PATH_PROTOCOL  *SerialNode;
    627   ACPI_HID_DEVICE_PATH      *Acpi;
    628   UART_DEVICE_PATH          *Uart;
    629   UART_DEVICE_PATH          *Uart1;
    630   UINTN                     TerminalNumber;
    631   BM_MENU_ENTRY             *NewMenuEntry;
    632   BM_TERMINAL_CONTEXT       *NewTerminalContext;
    633   UINTN                     Index;
    634   UART_FLOW_CONTROL_DEVICE_PATH *FlowControlNode;
    635   BOOLEAN                   HasFlowControlNode;
    636 
    637   HasFlowControlNode = FALSE;
    638   Node            = DevicePath;
    639   Node            = NextDevicePathNode (Node);
    640   TerminalNumber  = 0;
    641   for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
    642     while (!IsDevicePathEnd (Node)) {
    643       Acpi = (ACPI_HID_DEVICE_PATH *) Node;
    644       if (IsIsaSerialNode (Acpi)) {
    645         CopyMem (&TerminalNumber, &Acpi->UID, sizeof (UINT32));
    646       }
    647 
    648       if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
    649         Uart          = (UART_DEVICE_PATH *) Node;
    650         NewMenuEntry  = BOpt_GetMenuEntry (&TerminalMenu, TerminalNumber);
    651         if (NULL == NewMenuEntry) {
    652           return EFI_NOT_FOUND;
    653         }
    654 
    655         NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
    656         CopyMem (
    657           &NewTerminalContext->BaudRate,
    658           &Uart->BaudRate,
    659           sizeof (UINT64)
    660           );
    661 
    662         CopyMem (
    663           &NewTerminalContext->DataBits,
    664           &Uart->DataBits,
    665           sizeof (UINT8)
    666           );
    667 
    668         CopyMem (
    669           &NewTerminalContext->Parity,
    670           &Uart->Parity,
    671           sizeof (UINT8)
    672           );
    673 
    674         CopyMem (
    675           &NewTerminalContext->StopBits,
    676           &Uart->StopBits,
    677           sizeof (UINT8)
    678           );
    679 
    680         FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Node);
    681         if (IsUartFlowControlNode (FlowControlNode)) {
    682           HasFlowControlNode = TRUE;
    683           NewTerminalContext->FlowControl = (UINT8) ReadUnaligned32 (&FlowControlNode->FlowControlMap);
    684         } else if (NewTerminalContext->FlowControl != 0) {
    685           //
    686           // No Flow Control device path node, assumption no Flow control
    687           //
    688           NewTerminalContext->FlowControl = 0;
    689         }
    690 
    691         SerialNode  = NewTerminalContext->DevicePath;
    692         SerialNode  = NextDevicePathNode (SerialNode);
    693         while (!IsDevicePathEnd (SerialNode)) {
    694           if ((DevicePathType (SerialNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (SerialNode) == MSG_UART_DP)) {
    695             //
    696             // Update following device paths according to
    697             // previous acquired uart attributes
    698             //
    699             Uart1 = (UART_DEVICE_PATH *) SerialNode;
    700             CopyMem (
    701               &Uart1->BaudRate,
    702               &NewTerminalContext->BaudRate,
    703               sizeof (UINT64)
    704               );
    705 
    706             CopyMem (
    707               &Uart1->DataBits,
    708               &NewTerminalContext->DataBits,
    709               sizeof (UINT8)
    710               );
    711             CopyMem (
    712               &Uart1->Parity,
    713               &NewTerminalContext->Parity,
    714               sizeof (UINT8)
    715               );
    716             CopyMem (
    717               &Uart1->StopBits,
    718               &NewTerminalContext->StopBits,
    719               sizeof (UINT8)
    720               );
    721 
    722             FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (SerialNode);
    723             if (IsUartFlowControlNode (FlowControlNode)) {
    724               FlowControlNode->FlowControlMap = NewTerminalContext->FlowControl;
    725             } else {
    726               if (HasFlowControlNode) {
    727                 mFlowControlDevicePath.FlowControlMap = NewTerminalContext->FlowControl;
    728                 NewTerminalContext->DevicePath = AppendDevicePathNode (
    729                                              NewTerminalContext->DevicePath,
    730                                              (EFI_DEVICE_PATH_PROTOCOL *) (&mFlowControlDevicePath)
    731                                              );
    732               }
    733             }
    734             break;
    735           }
    736 
    737           SerialNode = NextDevicePathNode (SerialNode);
    738         }
    739         //
    740         // end while
    741         //
    742       }
    743 
    744       Node = NextDevicePathNode (Node);
    745     }
    746     //
    747     // end while
    748     //
    749   }
    750 
    751   return EFI_SUCCESS;
    752 }
    753 
    754 /**
    755   Build up Console Menu based on types passed in. The type can
    756   be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT
    757   and BM_CONSOLE_ERR_CONTEXT_SELECT.
    758 
    759   @param ConsoleMenuType Can be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT
    760                          and BM_CONSOLE_ERR_CONTEXT_SELECT.
    761 
    762   @retval EFI_UNSUPPORTED The type passed in is not in the 3 types defined.
    763   @retval EFI_NOT_FOUND   If the EFI Variable defined in UEFI spec with name "ConOutDev",
    764                           "ConInDev" or "ConErrDev" doesn't exists.
    765   @retval EFI_OUT_OF_RESOURCES Not enough resource to complete the operations.
    766   @retval EFI_SUCCESS          Function completes successfully.
    767 
    768 **/
    769 EFI_STATUS
    770 GetConsoleMenu (
    771   IN UINTN              ConsoleMenuType
    772   )
    773 {
    774   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    775   EFI_DEVICE_PATH_PROTOCOL  *AllDevicePath;
    776   EFI_DEVICE_PATH_PROTOCOL  *MultiDevicePath;
    777   EFI_DEVICE_PATH_PROTOCOL  *DevicePathInst;
    778   UINTN                     Size;
    779   UINTN                     AllCount;
    780   UINTN                     Index;
    781   UINTN                     Index2;
    782   BM_MENU_ENTRY             *NewMenuEntry;
    783   BM_CONSOLE_CONTEXT        *NewConsoleContext;
    784   TYPE_OF_TERMINAL          Terminal;
    785   UINTN                     Com;
    786   BM_MENU_OPTION            *ConsoleMenu;
    787 
    788   DevicePath    = NULL;
    789   AllDevicePath = NULL;
    790   AllCount      = 0;
    791   switch (ConsoleMenuType) {
    792   case BM_CONSOLE_IN_CONTEXT_SELECT:
    793     ConsoleMenu = &ConsoleInpMenu;
    794     DevicePath = EfiLibGetVariable (
    795                   L"ConIn",
    796                   &gEfiGlobalVariableGuid
    797                   );
    798 
    799     AllDevicePath = EfiLibGetVariable (
    800                       L"ConInDev",
    801                       &gEfiGlobalVariableGuid
    802                       );
    803     break;
    804 
    805   case BM_CONSOLE_OUT_CONTEXT_SELECT:
    806     ConsoleMenu = &ConsoleOutMenu;
    807     DevicePath = EfiLibGetVariable (
    808                   L"ConOut",
    809                   &gEfiGlobalVariableGuid
    810                   );
    811 
    812     AllDevicePath = EfiLibGetVariable (
    813                       L"ConOutDev",
    814                       &gEfiGlobalVariableGuid
    815                       );
    816     break;
    817 
    818   case BM_CONSOLE_ERR_CONTEXT_SELECT:
    819     ConsoleMenu = &ConsoleErrMenu;
    820     DevicePath = EfiLibGetVariable (
    821                   L"ErrOut",
    822                   &gEfiGlobalVariableGuid
    823                   );
    824 
    825     AllDevicePath = EfiLibGetVariable (
    826                       L"ErrOutDev",
    827                       &gEfiGlobalVariableGuid
    828                       );
    829     break;
    830 
    831   default:
    832     return EFI_UNSUPPORTED;
    833   }
    834 
    835   if (NULL == AllDevicePath) {
    836     return EFI_NOT_FOUND;
    837   }
    838 
    839   InitializeListHead (&ConsoleMenu->Head);
    840 
    841   AllCount                = EfiDevicePathInstanceCount (AllDevicePath);
    842   ConsoleMenu->MenuNumber = 0;
    843   //
    844   // Following is menu building up for Console Devices selected.
    845   //
    846   MultiDevicePath = AllDevicePath;
    847   Index2          = 0;
    848   for (Index = 0; Index < AllCount; Index++) {
    849     DevicePathInst  = GetNextDevicePathInstance (&MultiDevicePath, &Size);
    850 
    851     NewMenuEntry    = BOpt_CreateMenuEntry (BM_CONSOLE_CONTEXT_SELECT);
    852     if (NULL == NewMenuEntry) {
    853       return EFI_OUT_OF_RESOURCES;
    854     }
    855 
    856     NewConsoleContext             = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
    857     NewMenuEntry->OptionNumber    = Index2;
    858 
    859     NewConsoleContext->DevicePath = DuplicateDevicePath (DevicePathInst);
    860     ASSERT (NewConsoleContext->DevicePath != NULL);
    861     NewMenuEntry->DisplayString   = EfiLibStrFromDatahub (NewConsoleContext->DevicePath);
    862     if (NULL == NewMenuEntry->DisplayString) {
    863       NewMenuEntry->DisplayString = DevicePathToStr (NewConsoleContext->DevicePath);
    864     }
    865 
    866     NewConsoleContext->IsTerminal = IsTerminalDevicePath (
    867                                       NewConsoleContext->DevicePath,
    868                                       &Terminal,
    869                                       &Com
    870                                       );
    871 
    872     NewConsoleContext->IsActive = BdsLibMatchDevicePaths (
    873                                     DevicePath,
    874                                     NewConsoleContext->DevicePath
    875                                     );
    876 
    877     if (NewConsoleContext->IsTerminal) {
    878       BOpt_DestroyMenuEntry (NewMenuEntry);
    879     } else {
    880       Index2++;
    881       ConsoleMenu->MenuNumber++;
    882       InsertTailList (&ConsoleMenu->Head, &NewMenuEntry->Link);
    883     }
    884   }
    885 
    886   return EFI_SUCCESS;
    887 }
    888 
    889 /**
    890   Build up ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
    891 
    892   @retval EFI_SUCCESS    The function always complete successfully.
    893 
    894 **/
    895 EFI_STATUS
    896 GetAllConsoles (
    897   VOID
    898   )
    899 {
    900   GetConsoleMenu (BM_CONSOLE_IN_CONTEXT_SELECT);
    901   GetConsoleMenu (BM_CONSOLE_OUT_CONTEXT_SELECT);
    902   GetConsoleMenu (BM_CONSOLE_ERR_CONTEXT_SELECT);
    903   return EFI_SUCCESS;
    904 }
    905 
    906 /**
    907   Free ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
    908 
    909   @retval EFI_SUCCESS    The function always complete successfully.
    910 **/
    911 EFI_STATUS
    912 FreeAllConsoles (
    913   VOID
    914   )
    915 {
    916   BOpt_FreeMenu (&ConsoleOutMenu);
    917   BOpt_FreeMenu (&ConsoleInpMenu);
    918   BOpt_FreeMenu (&ConsoleErrMenu);
    919   BOpt_FreeMenu (&TerminalMenu);
    920   return EFI_SUCCESS;
    921 }
    922 
    923 /**
    924   Test whether DevicePath is a valid Terminal
    925 
    926 
    927   @param DevicePath      DevicePath to be checked
    928   @param Termi           If DevicePath is valid Terminal, terminal type is returned.
    929   @param Com             If DevicePath is valid Terminal, Com Port type is returned.
    930 
    931   @retval  TRUE         If DevicePath point to a Terminal.
    932   @retval  FALSE        If DevicePath does not point to a Terminal.
    933 
    934 **/
    935 BOOLEAN
    936 IsTerminalDevicePath (
    937   IN  EFI_DEVICE_PATH_PROTOCOL *DevicePath,
    938   OUT TYPE_OF_TERMINAL         *Termi,
    939   OUT UINTN                    *Com
    940   )
    941 {
    942   BOOLEAN                   IsTerminal;
    943   EFI_DEVICE_PATH_PROTOCOL  *Node;
    944   VENDOR_DEVICE_PATH        *Vendor;
    945   UART_DEVICE_PATH          *Uart;
    946   ACPI_HID_DEVICE_PATH      *Acpi;
    947 
    948   IsTerminal = FALSE;
    949 
    950   Uart   = NULL;
    951   Vendor = NULL;
    952   Acpi   = NULL;
    953   for (Node = DevicePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
    954     //
    955     // Vendor points to the node before the End node
    956     //
    957     Vendor = (VENDOR_DEVICE_PATH *) Node;
    958 
    959     if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
    960       Uart = (UART_DEVICE_PATH *) Node;
    961     }
    962 
    963     if (Uart == NULL) {
    964       //
    965       // Acpi points to the node before the UART node
    966       //
    967       Acpi = (ACPI_HID_DEVICE_PATH *) Node;
    968     }
    969   }
    970 
    971   if (Vendor == NULL ||
    972       DevicePathType (Vendor) != MESSAGING_DEVICE_PATH ||
    973       DevicePathSubType (Vendor) != MSG_VENDOR_DP ||
    974       Uart == NULL) {
    975     return FALSE;
    976   }
    977 
    978   //
    979   // There are four kinds of Terminal types
    980   // check to see whether this devicepath
    981   // is one of that type
    982   //
    983   if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[0])) {
    984     *Termi      = TerminalTypePcAnsi;
    985     IsTerminal  = TRUE;
    986   } else {
    987     if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[1])) {
    988       *Termi      = TerminalTypeVt100;
    989       IsTerminal  = TRUE;
    990     } else {
    991       if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[2])) {
    992         *Termi      = TerminalTypeVt100Plus;
    993         IsTerminal  = TRUE;
    994       } else {
    995         if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[3])) {
    996           *Termi      = TerminalTypeVtUtf8;
    997           IsTerminal  = TRUE;
    998         } else {
    999           IsTerminal = FALSE;
   1000         }
   1001       }
   1002     }
   1003   }
   1004 
   1005   if (!IsTerminal) {
   1006     return FALSE;
   1007   }
   1008 
   1009   if ((Acpi != NULL) && IsIsaSerialNode (Acpi)) {
   1010     CopyMem (Com, &Acpi->UID, sizeof (UINT32));
   1011   } else {
   1012     return FALSE;
   1013   }
   1014 
   1015   return TRUE;
   1016 }
   1017 
   1018 /**
   1019   Get mode number according to column and row
   1020 
   1021   @param CallbackData    The BMM context data.
   1022 **/
   1023 VOID
   1024 GetConsoleOutMode (
   1025   IN  BMM_CALLBACK_DATA    *CallbackData
   1026   )
   1027 {
   1028   UINTN                         Col;
   1029   UINTN                         Row;
   1030   UINTN                         CurrentCol;
   1031   UINTN                         CurrentRow;
   1032   UINTN                         Mode;
   1033   UINTN                         MaxMode;
   1034   EFI_STATUS                    Status;
   1035   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *ConOut;
   1036 
   1037   ConOut   = gST->ConOut;
   1038   MaxMode  = (UINTN) (ConOut->Mode->MaxMode);
   1039 
   1040   CurrentCol = PcdGet32 (PcdSetupConOutColumn);
   1041   CurrentRow = PcdGet32 (PcdSetupConOutRow);
   1042   for (Mode = 0; Mode < MaxMode; Mode++) {
   1043     Status = ConOut->QueryMode (ConOut, Mode, &Col, &Row);
   1044     if (!EFI_ERROR(Status)) {
   1045       if (CurrentCol == Col && CurrentRow == Row) {
   1046         CallbackData->BmmFakeNvData.ConsoleOutMode = (UINT16) Mode;
   1047         break;
   1048       }
   1049     }
   1050   }
   1051 }
   1052 
   1053 /**
   1054 
   1055   Initialize console input device check box to ConsoleInCheck[MAX_MENU_NUMBER]
   1056   in BMM_FAKE_NV_DATA structure.
   1057 
   1058   @param CallbackData    The BMM context data.
   1059 
   1060 **/
   1061 VOID
   1062 GetConsoleInCheck (
   1063   IN  BMM_CALLBACK_DATA    *CallbackData
   1064   )
   1065 {
   1066   UINT16              Index;
   1067   BM_MENU_ENTRY       *NewMenuEntry;
   1068   UINT8               *ConInCheck;
   1069   BM_CONSOLE_CONTEXT  *NewConsoleContext;
   1070 
   1071   ASSERT (CallbackData != NULL);
   1072 
   1073   ConInCheck = &CallbackData->BmmFakeNvData.ConsoleInCheck[0];
   1074   for (Index = 0; ((Index < ConsoleInpMenu.MenuNumber) && \
   1075        (Index < MAX_MENU_NUMBER)) ; Index++) {
   1076     NewMenuEntry      = BOpt_GetMenuEntry (&ConsoleInpMenu, Index);
   1077     NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
   1078     ConInCheck[Index] = NewConsoleContext->IsActive;
   1079   }
   1080 }
   1081 
   1082 /**
   1083 
   1084   Initialize console output device check box to ConsoleOutCheck[MAX_MENU_NUMBER]
   1085   in BMM_FAKE_NV_DATA structure.
   1086 
   1087   @param CallbackData    The BMM context data.
   1088 
   1089 **/
   1090 VOID
   1091 GetConsoleOutCheck (
   1092   IN  BMM_CALLBACK_DATA    *CallbackData
   1093   )
   1094 {
   1095   UINT16              Index;
   1096   BM_MENU_ENTRY       *NewMenuEntry;
   1097   UINT8               *ConOutCheck;
   1098   BM_CONSOLE_CONTEXT  *NewConsoleContext;
   1099 
   1100   ASSERT (CallbackData != NULL);
   1101   ConOutCheck = &CallbackData->BmmFakeNvData.ConsoleOutCheck[0];
   1102   for (Index = 0; ((Index < ConsoleOutMenu.MenuNumber) && \
   1103        (Index < MAX_MENU_NUMBER)) ; Index++) {
   1104     NewMenuEntry      = BOpt_GetMenuEntry (&ConsoleOutMenu, Index);
   1105     NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
   1106     ConOutCheck[Index] = NewConsoleContext->IsActive;
   1107   }
   1108 }
   1109 
   1110 /**
   1111 
   1112   Initialize standard error output device check box to ConsoleErrCheck[MAX_MENU_NUMBER]
   1113   in BMM_FAKE_NV_DATA structure.
   1114 
   1115   @param CallbackData    The BMM context data.
   1116 
   1117 **/
   1118 VOID
   1119 GetConsoleErrCheck (
   1120   IN  BMM_CALLBACK_DATA    *CallbackData
   1121   )
   1122 {
   1123   UINT16              Index;
   1124   BM_MENU_ENTRY       *NewMenuEntry;
   1125   UINT8               *ConErrCheck;
   1126   BM_CONSOLE_CONTEXT  *NewConsoleContext;
   1127 
   1128   ASSERT (CallbackData != NULL);
   1129   ConErrCheck = &CallbackData->BmmFakeNvData.ConsoleErrCheck[0];
   1130   for (Index = 0; ((Index < ConsoleErrMenu.MenuNumber) && \
   1131        (Index < MAX_MENU_NUMBER)) ; Index++) {
   1132     NewMenuEntry      = BOpt_GetMenuEntry (&ConsoleErrMenu, Index);
   1133     NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
   1134     ConErrCheck[Index] = NewConsoleContext->IsActive;
   1135   }
   1136 }
   1137 
   1138 /**
   1139 
   1140   Initialize terminal attributes (baudrate, data rate, stop bits, parity and terminal type)
   1141   to BMM_FAKE_NV_DATA structure.
   1142 
   1143   @param CallbackData    The BMM context data.
   1144 
   1145 **/
   1146 VOID
   1147 GetTerminalAttribute (
   1148   IN  BMM_CALLBACK_DATA    *CallbackData
   1149   )
   1150 {
   1151   BMM_FAKE_NV_DATA     *CurrentFakeNVMap;
   1152   BM_MENU_ENTRY        *NewMenuEntry;
   1153   BM_TERMINAL_CONTEXT  *NewTerminalContext;
   1154   UINT16               TerminalIndex;
   1155   UINT8                AttributeIndex;
   1156 
   1157   ASSERT (CallbackData != NULL);
   1158 
   1159   CurrentFakeNVMap = &CallbackData->BmmFakeNvData;
   1160   for (TerminalIndex = 0; ((TerminalIndex < TerminalMenu.MenuNumber) && \
   1161        (TerminalIndex < MAX_MENU_NUMBER)); TerminalIndex++) {
   1162     NewMenuEntry        = BOpt_GetMenuEntry (&TerminalMenu, TerminalIndex);
   1163     NewTerminalContext  = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
   1164     for (AttributeIndex = 0; AttributeIndex < sizeof (BaudRateList) / sizeof (BaudRateList [0]); AttributeIndex++) {
   1165       if (NewTerminalContext->BaudRate == (UINT64) (BaudRateList[AttributeIndex].Value)) {
   1166         NewTerminalContext->BaudRateIndex = AttributeIndex;
   1167         break;
   1168       }
   1169     }
   1170     for (AttributeIndex = 0; AttributeIndex < sizeof (DataBitsList) / sizeof (DataBitsList[0]); AttributeIndex++) {
   1171       if (NewTerminalContext->DataBits == (UINT64) (DataBitsList[AttributeIndex].Value)) {
   1172         NewTerminalContext->DataBitsIndex = AttributeIndex;
   1173         break;
   1174       }
   1175     }
   1176 
   1177     for (AttributeIndex = 0; AttributeIndex < sizeof (ParityList) / sizeof (ParityList[0]); AttributeIndex++) {
   1178       if (NewTerminalContext->Parity == (UINT64) (ParityList[AttributeIndex].Value)) {
   1179         NewTerminalContext->ParityIndex = AttributeIndex;
   1180         break;
   1181       }
   1182     }
   1183 
   1184     for (AttributeIndex = 0; AttributeIndex < sizeof (StopBitsList) / sizeof (StopBitsList[0]); AttributeIndex++) {
   1185       if (NewTerminalContext->StopBits == (UINT64) (StopBitsList[AttributeIndex].Value)) {
   1186         NewTerminalContext->StopBitsIndex = AttributeIndex;
   1187         break;
   1188       }
   1189     }
   1190     CurrentFakeNVMap->COMBaudRate[TerminalIndex]     = NewTerminalContext->BaudRateIndex;
   1191     CurrentFakeNVMap->COMDataRate[TerminalIndex]     = NewTerminalContext->DataBitsIndex;
   1192     CurrentFakeNVMap->COMStopBits[TerminalIndex]     = NewTerminalContext->StopBitsIndex;
   1193     CurrentFakeNVMap->COMParity[TerminalIndex]       = NewTerminalContext->ParityIndex;
   1194     CurrentFakeNVMap->COMTerminalType[TerminalIndex] = NewTerminalContext->TerminalType;
   1195     CurrentFakeNVMap->COMFlowControl[TerminalIndex]  = NewTerminalContext->FlowControl;
   1196   }
   1197 }
   1198 
   1199