/** @file handles console redirection from boot manager @copyright INTEL CONFIDENTIAL Copyright 2004 - 2021 Intel Corporation. The source code contained or described herein and all documents related to the source code ("Material") are owned by Intel Corporation or its suppliers or licensors. Title to the Material remains with Intel Corporation or its suppliers and licensors. The Material may contain trade secrets and proprietary and confidential information of Intel Corporation and its suppliers and licensors, and is protected by worldwide copyright and trade secret laws and treaty provisions. No part of the Material may be used, copied, reproduced, modified, published, uploaded, posted, transmitted, distributed, or disclosed in any way without Intel's prior express written permission. No license under any patent, copyright, trade secret or other intellectual property right is granted to or conferred upon you by disclosure or delivery of the Materials, either expressly, by implication, inducement, estoppel or otherwise. Any license under such intellectual property rights must be express and approved by Intel in writing. Unless otherwise agreed by Intel in writing, you may not remove or alter this notice or any other notice embedded in Materials by Intel or Intel's suppliers or licensors in any way. This file contains a 'Sample Driver' and is licensed as such under the terms of your license agreement with Intel or your vendor. This file may be modified by the user, subject to the additional terms of the license agreement. @par Specification Reference: **/ #include "BootMaint.h" GLOBAL_REMOVE_IF_UNREFERENCED UART_FLOW_CONTROL_DEVICE_PATH mFlowControlDevicePath = { { MESSAGING_DEVICE_PATH, MSG_VENDOR_DP, { (UINT8)(sizeof(UART_FLOW_CONTROL_DEVICE_PATH)), (UINT8)((sizeof(UART_FLOW_CONTROL_DEVICE_PATH)) >> 8) } }, DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL, UART_FLOW_CONTROL_HARDWARE }; /** Check the device path node whether it's the Flow Control node or not. @param[in] FlowControl The device path node to be checked. @retval TRUE It's the Flow Control node. @retval FALSE It's not. **/ BOOLEAN IsUartFlowControlNode ( IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl ) { return (BOOLEAN) ( (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) && (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid)) ); } /** Function compares a device path data structure to that of all the nodes of a second device path instance. @param Multi A pointer to a multi-instance device path data structure. @param Single A pointer to a single-instance device path data structure. @retval TRUE If the Single device path is contained within Multi device path. @retval FALSE The Single device path is not match within Multi device path. **/ BOOLEAN MatchDevicePaths ( IN EFI_DEVICE_PATH_PROTOCOL *Multi, IN EFI_DEVICE_PATH_PROTOCOL *Single ) { EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_DEVICE_PATH_PROTOCOL *DevicePathInst; UINTN Size; if (Multi == NULL || Single == NULL) { return FALSE; } DevicePath = Multi; DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size); // // Search for the match of 'Single' in 'Multi' // while (DevicePathInst != NULL) { // // If the single device path is found in multiple device paths, // return success // if (CompareMem (Single, DevicePathInst, Size) == 0) { FreePool (DevicePathInst); return TRUE; } FreePool (DevicePathInst); DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size); } return FALSE; } /** Check whether the device path node is ISA Serial Node. @param Acpi Device path node to be checked @retval TRUE It's ISA Serial Node. @retval FALSE It's NOT ISA Serial Node. **/ BOOLEAN IsIsaSerialNode ( IN ACPI_HID_DEVICE_PATH *Acpi ) { return (BOOLEAN) ( (DevicePathType (Acpi) == ACPI_DEVICE_PATH) && (DevicePathSubType (Acpi) == ACPI_DP) && (ReadUnaligned32 (&Acpi->HID) == EISA_PNP_ID (0x0501)) ); } /** Update Com Ports attributes from DevicePath @param DevicePath DevicePath that contains Com ports @param ComAttributes Com attributes buffer. @retval EFI_SUCCESS The update is successful. **/ EFI_STATUS UpdateComAttributeFromVariable ( EFI_DEVICE_PATH_PROTOCOL *DevicePath, TOTAL_SERIAL_PORT_INFO *ComAttributes ); /** Update the multi-instance device path of Terminal Device based on the global TerminalMenu. If ChangeTernimal is TRUE, the terminal device path in the Terminal Device in TerminalMenu is also updated. @param DevicePath The multi-instance device path. @param ChangeTerminal TRUE, then device path in the Terminal Device in TerminalMenu is also updated; FALSE, no update. @return EFI_SUCCESS The function completes successfully. **/ EFI_STATUS ChangeTerminalDevicePath ( IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, IN BOOLEAN ChangeTerminal ) { EFI_DEVICE_PATH_PROTOCOL *Node; EFI_DEVICE_PATH_PROTOCOL *Node1; ACPI_HID_DEVICE_PATH *Acpi; UART_DEVICE_PATH *Uart; UART_DEVICE_PATH *Uart1; UINTN Com; BM_TERMINAL_CONTEXT *NewTerminalContext; BM_MENU_ENTRY *NewMenuEntry; UART_FLOW_CONTROL_DEVICE_PATH *FlowControlNode; Node = *DevicePath; Node = NextDevicePathNode (Node); Com = 0; while (!IsDevicePathEnd (Node)) { Acpi = (ACPI_HID_DEVICE_PATH *) Node; if (IsIsaSerialNode (Acpi)) { CopyMem (&Com, &Acpi->UID, sizeof (UINT32)); } NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Com); NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) { Uart = (UART_DEVICE_PATH *) Node; CopyMem ( &Uart->BaudRate, &NewTerminalContext->BaudRate, sizeof (UINT64) ); CopyMem ( &Uart->DataBits, &NewTerminalContext->DataBits, sizeof (UINT8) ); CopyMem ( &Uart->Parity, &NewTerminalContext->Parity, sizeof (UINT8) ); CopyMem ( &Uart->StopBits, &NewTerminalContext->StopBits, sizeof (UINT8) ); FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Node); if (IsUartFlowControlNode (FlowControlNode)) { FlowControlNode->FlowControlMap = NewTerminalContext->FlowControl; } else { // // Append the Flow control device node when user enable flow control. // if (NewTerminalContext->FlowControl != 0) { mFlowControlDevicePath.FlowControlMap = NewTerminalContext->FlowControl; *DevicePath = AppendDevicePathNode ( *DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) (&mFlowControlDevicePath) ); } } // // Change the device path in the ComPort // if (ChangeTerminal) { Node1 = NewTerminalContext->DevicePath; Node1 = NextDevicePathNode (Node1); while (!IsDevicePathEnd (Node1)) { if ((DevicePathType (Node1) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node1) == MSG_UART_DP)) { Uart1 = (UART_DEVICE_PATH *) Node1; CopyMem ( &Uart1->BaudRate, &NewTerminalContext->BaudRate, sizeof (UINT64) ); CopyMem ( &Uart1->DataBits, &NewTerminalContext->DataBits, sizeof (UINT8) ); CopyMem ( &Uart1->Parity, &NewTerminalContext->Parity, sizeof (UINT8) ); CopyMem ( &Uart1->StopBits, &NewTerminalContext->StopBits, sizeof (UINT8) ); break; } // // end if // Node1 = NextDevicePathNode (Node1); } // // end while // break; } } Node = NextDevicePathNode (Node); } return EFI_SUCCESS; } /** Update the device path that describing a terminal device based on the new BaudRate, Data Bits, parity and Stop Bits set. @param DevicePath terminal device's path **/ VOID ChangeVariableDevicePath ( IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { EFI_DEVICE_PATH_PROTOCOL *Node; ACPI_HID_DEVICE_PATH *Acpi; UART_DEVICE_PATH *Uart; UINTN Com; BM_TERMINAL_CONTEXT *NewTerminalContext; BM_MENU_ENTRY *NewMenuEntry; Node = DevicePath; Node = NextDevicePathNode (Node); Com = 0; while (!IsDevicePathEnd (Node)) { Acpi = (ACPI_HID_DEVICE_PATH *) Node; if (IsIsaSerialNode (Acpi)) { CopyMem (&Com, &Acpi->UID, sizeof (UINT32)); } if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) { NewMenuEntry = BOpt_GetMenuEntry ( &TerminalMenu, Com ); ASSERT (NewMenuEntry != NULL); if (NewMenuEntry == NULL) { return; } NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; Uart = (UART_DEVICE_PATH *) Node; CopyMem ( &Uart->BaudRate, &NewTerminalContext->BaudRate, sizeof (UINT64) ); CopyMem ( &Uart->DataBits, &NewTerminalContext->DataBits, sizeof (UINT8) ); CopyMem ( &Uart->Parity, &NewTerminalContext->Parity, sizeof (UINT8) ); CopyMem ( &Uart->StopBits, &NewTerminalContext->StopBits, sizeof (UINT8) ); } Node = NextDevicePathNode (Node); } } /** Retrieve ACPI UID of UART from device path @param Handle The handle for the UART device. @param AcpiUid The ACPI UID on output. @retval TRUE Find valid UID from device path @retval FALSE Can't find **/ BOOLEAN RetrieveUartUid ( IN EFI_HANDLE Handle, IN OUT UINT32 *AcpiUid ) { EFI_STATUS Status; ACPI_HID_DEVICE_PATH *Acpi; EFI_DEVICE_PATH_PROTOCOL *DevicePath; Status = gBS->HandleProtocol ( Handle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePath ); if (EFI_ERROR (Status)) { return FALSE; } Acpi = NULL; for (; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) { if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (DevicePath) == MSG_UART_DP)) { break; } // // Acpi points to the node before the Uart node // Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath; } if ((Acpi != NULL) && IsIsaSerialNode (Acpi)) { if (AcpiUid != NULL) { CopyMem (AcpiUid, &Acpi->UID, sizeof (UINT32)); } return TRUE; } else { return FALSE; } } /** Sort Uart handles array with Acpi->UID from low to high. @param Handles EFI_SERIAL_IO_PROTOCOL handle buffer @param NoHandles EFI_SERIAL_IO_PROTOCOL handle count **/ VOID SortedUartHandle ( IN EFI_HANDLE *Handles, IN UINTN NoHandles ) { UINTN Index1; UINTN Index2; UINTN Position; UINT32 AcpiUid1; UINT32 AcpiUid2; UINT32 TempAcpiUid; EFI_HANDLE TempHandle; for (Index1 = 0; Index1 < NoHandles-1; Index1++) { if (!RetrieveUartUid (Handles[Index1], &AcpiUid1)) { continue; } TempHandle = Handles[Index1]; Position = Index1; TempAcpiUid = AcpiUid1; for (Index2 = Index1+1; Index2 < NoHandles; Index2++) { if (!RetrieveUartUid (Handles[Index2], &AcpiUid2)) { continue; } if (AcpiUid2 < TempAcpiUid) { TempAcpiUid = AcpiUid2; TempHandle = Handles[Index2]; Position = Index2; } } Handles[Position] = Handles[Index1]; Handles[Index1] = TempHandle; } } /** Test whether DevicePath is a valid Terminal @param DevicePath DevicePath to be checked @param Termi If DevicePath is valid Terminal, terminal type is returned. @param Com If DevicePath is valid Terminal, Com Port type is returned. @retval TRUE If DevicePath point to a Terminal. @retval FALSE If DevicePath does not point to a Terminal. **/ BOOLEAN IsTerminalDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, OUT TYPE_OF_TERMINAL *Termi, OUT UINTN *Com ); /** Get Com port attributes according to the com port index or device path. @param ComAttributes The com port array which save com port info. @param Com The com port index or NULL. @param DevicePath DevicePath info belong to the com port device or NULL @retval The com port info. **/ SERIAL_PORT_ATTRIBUTE * GetComAttributes ( IN UINT8 *ComAttributes, IN UINTN *Com, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { SERIAL_PORT_ATTRIBUTE *CurNode; TOTAL_SERIAL_PORT_INFO *TotalInfo; UINT64 TotalSize; UINT64 TotalInfoSize; TotalSize = 0; if (ComAttributes == NULL) { return NULL; } TotalInfo = (TOTAL_SERIAL_PORT_INFO *)ComAttributes; TotalInfoSize = TotalInfo->TotalSize - sizeof (UINT64); while (TotalSize < TotalInfoSize) { CurNode = (SERIAL_PORT_ATTRIBUTE *) (((UINT8*) TotalInfo->PortAttributes) + TotalSize); if (Com != NULL && CurNode->ComTag.ComNum == *Com) { return CurNode; } if (DevicePath != NULL && CurNode->Length != 0 && CompareMem ((VOID *) &CurNode->ComTag.ComNum, DevicePath, CurNode->Length) == 0) { return CurNode; } TotalSize += sizeof (SERIAL_PORT_ATTRIBUTE) + CurNode->Length; } return NULL; } /** Get Serial Attributes from device path or saved attributes info. @param Handle Device handle which has the Serial io protocol. @param NewTerminalContext Menu context has the info. @param ComAttributes Com attributes info saved in golcal parameter. @param Com If DevicePath is valid Terminal, Com Port number is returned. @param DevicePath If Device **/ VOID UpdateTerminalContext ( IN EFI_HANDLE Handle, IN OUT BM_TERMINAL_CONTEXT *NewTerminalContext, IN OUT UINT8 **ComAttributes, OUT BOOLEAN *NewInitialize, IN UINTN *Com, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { EFI_SERIAL_IO_PROTOCOL *SerialIo; UINT32 FlowControl; UINTN NewNodeSize; UINTN OldNodeSize; SERIAL_PORT_ATTRIBUTE *ComInfo; UINT8 *TmpInfo; TOTAL_SERIAL_PORT_INFO *TotalInfo; TotalInfo = (TOTAL_SERIAL_PORT_INFO *) (*ComAttributes); ComInfo = GetComAttributes (*ComAttributes, Com, DevicePath); if (ComInfo != NULL) { NewTerminalContext->BaudRate = ComInfo->BaudRate; NewTerminalContext->DataBits = ComInfo->DataBits; NewTerminalContext->Parity = ComInfo->Parity; NewTerminalContext->StopBits = ComInfo->StopBits; NewTerminalContext->FlowControl = ComInfo->FlowControl; NewTerminalContext->TerminalType = ComInfo->TerminalType; NewTerminalContext->IsEnabled = ComInfo->IsEnabled; NewTerminalContext->LegacyResolution = ComInfo->LegacyResolution; } else { *NewInitialize = TRUE; gBS->HandleProtocol ( Handle, &gEfiSerialIoProtocolGuid, (VOID **) &SerialIo ); CopyMem ( &NewTerminalContext->BaudRate, &SerialIo->Mode->BaudRate, sizeof (UINT64) ); CopyMem ( &NewTerminalContext->DataBits, &SerialIo->Mode->DataBits, sizeof (UINT8) ); CopyMem ( &NewTerminalContext->Parity, &SerialIo->Mode->Parity, sizeof (UINT8) ); CopyMem ( &NewTerminalContext->StopBits, &SerialIo->Mode->StopBits, sizeof (UINT8) ); NewTerminalContext->FlowControl = 0; FlowControl = 0; SerialIo->GetControl(SerialIo, &FlowControl); if ((FlowControl & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) != 0) { NewTerminalContext->FlowControl = UART_FLOW_CONTROL_HARDWARE; } NewTerminalContext->LegacyResolution = 0x01; NewTerminalContext->TerminalType = 0x00; NewTerminalContext->IsEnabled = 0x00; // // Initialize the ComAttribute parameter. // if (Com != NULL) { NewNodeSize = sizeof (SERIAL_PORT_ATTRIBUTE); } else { NewNodeSize = sizeof (SERIAL_PORT_ATTRIBUTE) + GetDevicePathSize (DevicePath); } if (TotalInfo == NULL) { NewNodeSize += sizeof (UINT64); OldNodeSize = 0; } else { OldNodeSize = TotalInfo->TotalSize; } TmpInfo = (UINT8 *) AllocateZeroPool (NewNodeSize + OldNodeSize); ASSERT (TmpInfo != NULL); if (TmpInfo == NULL) { return; } CopyMem(TmpInfo, (UINT8*)*ComAttributes, OldNodeSize); if (*ComAttributes != NULL) { FreePool (*ComAttributes); } *ComAttributes = TmpInfo; TotalInfo = (TOTAL_SERIAL_PORT_INFO *) (*ComAttributes); TotalInfo->TotalSize += NewNodeSize; if (OldNodeSize == 0) { ComInfo = TotalInfo->PortAttributes; } else { ComInfo = (SERIAL_PORT_ATTRIBUTE*) ((UINT8*) TotalInfo + OldNodeSize); } ComInfo->BaudRate = NewTerminalContext->BaudRate; ComInfo->DataBits = NewTerminalContext->DataBits; ComInfo->Parity = NewTerminalContext->Parity; ComInfo->StopBits = NewTerminalContext->StopBits; ComInfo->FlowControl = NewTerminalContext->FlowControl; ComInfo->LegacyResolution = NewTerminalContext->LegacyResolution; ComInfo->TerminalType = NewTerminalContext->TerminalType; ComInfo->IsEnabled = 0x00; if (Com != NULL) { ComInfo->ComTag.ComNum = (UINT8) (*Com); } else { ComInfo->Length = (UINT8)GetDevicePathSize(DevicePath); CopyMem ((VOID *) &ComInfo->ComTag.ComNum, DevicePath, ComInfo->Length); } } } /** Build a list containing all serial devices. @retval EFI_SUCCESS The function complete successfully. @retval EFI_UNSUPPORTED No serial ports present. **/ EFI_STATUS LocateSerialIo ( VOID ) { UINTN Index; UINTN Index2; UINTN NoHandles; EFI_HANDLE *Handles; EFI_STATUS Status; ACPI_HID_DEVICE_PATH *Acpi; EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_DEVICE_PATH_PROTOCOL *Node; EFI_DEVICE_PATH_PROTOCOL *OutDevicePath; EFI_DEVICE_PATH_PROTOCOL *InpDevicePath; EFI_DEVICE_PATH_PROTOCOL *ErrDevicePath; BM_MENU_ENTRY *NewMenuEntry; BM_TERMINAL_CONTEXT *NewTerminalContext; EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; VENDOR_DEVICE_PATH Vendor; UINTN DevicePathLen; TOTAL_SERIAL_PORT_INFO *ComAttributes; BOOLEAN NewInitialize; BOOLEAN GetUartNode; SERIAL_PORT_ATTRIBUTE *TmpComInfo; ComAttributes = NULL; NewInitialize = FALSE; GetUartNode = FALSE; Status = EFI_SUCCESS; Handles = NULL; Acpi = NULL; DevicePath = NULL; Node = NULL; OutDevicePath = NULL; InpDevicePath = NULL; ErrDevicePath = NULL; NewMenuEntry = NULL; NewTerminalContext = NULL; NewDevicePath = NULL; TmpComInfo = NULL; // // Get all handles that have SerialIo protocol installed // InitializeListHead (&TerminalMenu.Head); TerminalMenu.MenuNumber = 0; Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiSerialIoProtocolGuid, NULL, &NoHandles, &Handles ); if (EFI_ERROR (Status) || Handles == NULL) { // // No serial ports present // Status = EFI_UNSUPPORTED; goto EXIT; } // // Sort Uart handles array with Acpi->UID from low to high // then Terminal menu can be built from low Acpi->UID to high Acpi->UID // SortedUartHandle (Handles, NoHandles); // // Get legacy resolution setting from the variable. // if (NoHandles > 0) { GetVariable2 (L"ComAttributes", &gSetupVariableGuid, (VOID **) &ComAttributes, NULL); if (ComAttributes == NULL) { Status = EFI_NOT_FOUND; goto EXIT; } } for (Index = 0; Index < NoHandles; Index++) { // // Check to see whether the handle has DevicePath Protocol installed // gBS->HandleProtocol ( Handles[Index], &gEfiDevicePathProtocolGuid, (VOID **) &DevicePath ); Acpi = NULL; for (Node = DevicePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) { if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) { GetUartNode = TRUE; break; } // // Acpi points to the node before Uart node // Acpi = (ACPI_HID_DEVICE_PATH *) Node; } if (GetUartNode == FALSE) { continue; } GetUartNode = FALSE; NewMenuEntry = BOpt_CreateMenuEntry (BM_TERMINAL_CONTEXT_SELECT); if (NewMenuEntry == NULL) { Status = EFI_OUT_OF_RESOURCES; goto EXIT; } NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; NewTerminalContext->DevicePath = DuplicateDevicePath (DevicePath); if ((Acpi != NULL) && IsIsaSerialNode (Acpi)) { CopyMem (&NewMenuEntry->OptionNumber, &Acpi->UID, sizeof (UINT32)); // // Save Display String "COM* " // NewMenuEntry->DisplayString = AllocateZeroPool (10); if (NewMenuEntry->DisplayString == NULL) { Status = EFI_OUT_OF_RESOURCES; goto EXIT; } StrCatS (NewMenuEntry->DisplayString, 10 / sizeof (CHAR16), L"COM"); UnicodeValueToStringS(NewMenuEntry->DisplayString + StrLen(NewMenuEntry->DisplayString), sizeof (NewMenuEntry->DisplayString + StrLen(NewMenuEntry->DisplayString)), 0, NewMenuEntry->OptionNumber, 0); UpdateTerminalContext(Handles[Index], NewTerminalContext, (UINT8**) &ComAttributes, &NewInitialize, &NewMenuEntry->OptionNumber, NULL); } else { NewMenuEntry->OptionNumber = NO_COM_INDEX_NUM; NewMenuEntry->DisplayString = EfiLibStrFromDatahub (DevicePath); if (NULL == NewMenuEntry->DisplayString) { NewMenuEntry->DisplayString = UiDevicePathToStr (DevicePath); } UpdateTerminalContext(Handles[Index], NewTerminalContext, (UINT8**)&ComAttributes, &NewInitialize, NULL, DevicePath); } InsertTailList (&TerminalMenu.Head, &NewMenuEntry->Link); TerminalMenu.MenuNumber++; } if (NewInitialize) { // // Get L"ConOut", L"ConIn" and L"ErrOut" from the Var // GetEfiGlobalVariable2 (L"ConOut", (VOID **) &OutDevicePath, NULL); GetEfiGlobalVariable2 (L"ConIn", (VOID **) &InpDevicePath, NULL); GetEfiGlobalVariable2 (L"ErrOut", (VOID **) &ErrDevicePath, NULL); if (OutDevicePath != NULL) { UpdateComAttributeFromVariable (OutDevicePath, ComAttributes); } if (InpDevicePath != NULL) { UpdateComAttributeFromVariable (InpDevicePath, ComAttributes); } if (ErrDevicePath != NULL) { UpdateComAttributeFromVariable (ErrDevicePath, ComAttributes); } for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index); if (NULL == NewMenuEntry) { Status = EFI_NOT_FOUND; goto EXIT; } NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; TmpComInfo = GetComAttributes((UINT8*) ComAttributes, &NewMenuEntry->OptionNumber, NewTerminalContext->DevicePath); if (TmpComInfo == NULL) { Status = EFI_NOT_FOUND; goto EXIT; } NewTerminalContext->TerminalType = TmpComInfo->TerminalType; Vendor.Header.Type = MESSAGING_DEVICE_PATH; Vendor.Header.SubType = MSG_VENDOR_DP; for (Index2 = 0; Index2 < 4; Index2++) { CopyMem (&Vendor.Guid, &TerminalTypeGuid[Index2], sizeof (EFI_GUID)); SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH)); NewDevicePath = AppendDevicePathNode ( NewTerminalContext->DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &Vendor ); if (NewMenuEntry->HelpString != NULL) { FreePool (NewMenuEntry->HelpString); } // // NewMenuEntry->HelpString = UiDevicePathToStr (NewDevicePath); // NewMenuEntry->DisplayString = NewMenuEntry->HelpString; // NewMenuEntry->HelpString = NULL; if (MatchDevicePaths (OutDevicePath, NewDevicePath)) { NewTerminalContext->IsEnabled = 0x01; NewTerminalContext->TerminalType = (UINT8) Index2; } if (MatchDevicePaths (InpDevicePath, NewDevicePath)) { NewTerminalContext->IsEnabled = 0x01; NewTerminalContext->TerminalType = (UINT8) Index2; } if (MatchDevicePaths (ErrDevicePath, NewDevicePath)) { NewTerminalContext->IsEnabled = 0x01; NewTerminalContext->TerminalType = (UINT8) Index2; } TmpComInfo->IsEnabled = NewTerminalContext->IsEnabled; TmpComInfo->TerminalType = NewTerminalContext->TerminalType; } } Status = gRT->SetVariable ( L"ComAttributes", &gSetupVariableGuid, VAR_ATTR_NV_BS, ComAttributes->TotalSize, ComAttributes ); if (EFI_ERROR (Status)) { ASSERT (FALSE); } // // Update EfiVarStore opcode. // UpdateComAttributesVarStore (ComAttributes); } // // Initial the Out Of Band variable. // GetVariable2 (L"OutOfBand", &gOutOfBandGuid, (VOID **) &DevicePath, NULL); for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index); NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; NewTerminalContext->IsOutOfBand = FALSE; if (DevicePath != NULL) { DevicePathLen = GetDevicePathSize(NewTerminalContext->DevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); if (CompareMem(NewTerminalContext->DevicePath, DevicePath, DevicePathLen) == 0) { NewTerminalContext->IsOutOfBand = TRUE; } } } EXIT: if (ComAttributes != NULL) { FreePool (ComAttributes); } if (Handles != NULL) { FreePool (Handles); } if (NewMenuEntry != NULL) { if (NewMenuEntry->HelpString != NULL) { FreePool (NewMenuEntry->HelpString); } } return Status; } /** Update Com Ports attributes from DevicePath @param DevicePath DevicePath that contains Com ports @param ComAttributes Com attributes buffer. @retval EFI_SUCCESS The update is successful. @retval EFI_NOT_FOUND Can not find specific menu entry **/ EFI_STATUS UpdateComAttributeFromVariable ( EFI_DEVICE_PATH_PROTOCOL *DevicePath, TOTAL_SERIAL_PORT_INFO *ComAttributes ) { EFI_DEVICE_PATH_PROTOCOL *Node; EFI_DEVICE_PATH_PROTOCOL *SerialNode; ACPI_HID_DEVICE_PATH *Acpi; UART_DEVICE_PATH *Uart; UART_DEVICE_PATH *Uart1; UINTN TerminalNumber; BM_MENU_ENTRY *NewMenuEntry; BM_TERMINAL_CONTEXT *NewTerminalContext; UART_FLOW_CONTROL_DEVICE_PATH *FlowControlNode; BOOLEAN HasFlowControlNode; SERIAL_PORT_ATTRIBUTE *ComInfo; EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; EFI_DEVICE_PATH_PROTOCOL *DevicePathInst; UINTN Size; BOOLEAN HasSerialNode; HasFlowControlNode = FALSE; TmpDevicePath = DevicePath; DevicePathInst = GetNextDevicePathInstance (&TmpDevicePath, &Size); // // Search for the match of 'Single' in 'Multi' // while (DevicePathInst != NULL) { Node = DevicePathInst; Node = NextDevicePathNode (Node); TerminalNumber = 0; HasSerialNode = FALSE; while (!IsDevicePathEnd (Node)) { Acpi = (ACPI_HID_DEVICE_PATH *) Node; if (IsIsaSerialNode (Acpi)) { HasSerialNode = TRUE; CopyMem (&TerminalNumber, &Acpi->UID, sizeof (UINT32)); } if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) { Uart = (UART_DEVICE_PATH *) Node; if (HasSerialNode) { NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, TerminalNumber); } else { NewMenuEntry = BOpt_GetMenuEntryFromDevicePath(&TerminalMenu, DevicePathInst); } if (NULL == NewMenuEntry) { return EFI_NOT_FOUND; } NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; CopyMem ( &NewTerminalContext->BaudRate, &Uart->BaudRate, sizeof (UINT64) ); CopyMem ( &NewTerminalContext->DataBits, &Uart->DataBits, sizeof (UINT8) ); CopyMem ( &NewTerminalContext->Parity, &Uart->Parity, sizeof (UINT8) ); CopyMem ( &NewTerminalContext->StopBits, &Uart->StopBits, sizeof (UINT8) ); FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Node); if (IsUartFlowControlNode (FlowControlNode)) { HasFlowControlNode = TRUE; NewTerminalContext->FlowControl = (UINT8) ReadUnaligned32 (&FlowControlNode->FlowControlMap); } else if (NewTerminalContext->FlowControl != 0) { // // No Flow Control device path node, assumption no Flow control // NewTerminalContext->FlowControl = 0; } // // Update info saved in "ComAttributes". // if (HasSerialNode) { ComInfo = GetComAttributes((UINT8*)ComAttributes, &TerminalNumber, NULL); } else { ComInfo = GetComAttributes((UINT8*)ComAttributes, NULL, DevicePathInst); } if (ComInfo == NULL) { return EFI_NOT_FOUND; } ComInfo->BaudRate = NewTerminalContext->BaudRate; ComInfo->DataBits = NewTerminalContext->DataBits; ComInfo->Parity = NewTerminalContext->Parity; ComInfo->StopBits = NewTerminalContext->StopBits; ComInfo->FlowControl = NewTerminalContext->FlowControl; SerialNode = NewTerminalContext->DevicePath; SerialNode = NextDevicePathNode (SerialNode); while (!IsDevicePathEnd (SerialNode)) { if ((DevicePathType (SerialNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (SerialNode) == MSG_UART_DP)) { // // Update following device paths according to // previous acquired uart attributes // Uart1 = (UART_DEVICE_PATH *) SerialNode; CopyMem ( &Uart1->BaudRate, &NewTerminalContext->BaudRate, sizeof (UINT64) ); CopyMem ( &Uart1->DataBits, &NewTerminalContext->DataBits, sizeof (UINT8) ); CopyMem ( &Uart1->Parity, &NewTerminalContext->Parity, sizeof (UINT8) ); CopyMem ( &Uart1->StopBits, &NewTerminalContext->StopBits, sizeof (UINT8) ); FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (SerialNode); if (IsUartFlowControlNode (FlowControlNode)) { FlowControlNode->FlowControlMap = NewTerminalContext->FlowControl; } else { if (HasFlowControlNode) { mFlowControlDevicePath.FlowControlMap = NewTerminalContext->FlowControl; NewTerminalContext->DevicePath = AppendDevicePathNode ( NewTerminalContext->DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) (&mFlowControlDevicePath) ); } } break; } SerialNode = NextDevicePathNode (SerialNode); } // // end while // } Node = NextDevicePathNode (Node); } FreePool (DevicePathInst); DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size); } return EFI_SUCCESS; } /** Build up Console Menu based on types passed in. The type can be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT and BM_CONSOLE_ERR_CONTEXT_SELECT. @param ConsoleMenuType Can be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT and BM_CONSOLE_ERR_CONTEXT_SELECT. @retval EFI_UNSUPPORTED The type passed in is not in the 3 types defined. @retval EFI_NOT_FOUND If the EFI Variable defined in UEFI spec with name "ConOutDev", "ConInDev" or "ConErrDev" doesn't exists. @retval EFI_OUT_OF_RESOURCES Not enough resource to complete the operations. @retval EFI_SUCCESS Function completes successfully. **/ EFI_STATUS GetConsoleMenu ( IN UINTN ConsoleMenuType ) { EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_DEVICE_PATH_PROTOCOL *AllDevicePath; EFI_DEVICE_PATH_PROTOCOL *MultiDevicePath; EFI_DEVICE_PATH_PROTOCOL *DevicePathInst; UINTN Size; UINTN DevicePathSize; UINTN AllDevicePathSize; UINTN AllCount; UINTN Index; UINTN Index2; BM_MENU_ENTRY *NewMenuEntry; BM_CONSOLE_CONTEXT *NewConsoleContext; TYPE_OF_TERMINAL Terminal; UINTN Com; BM_MENU_OPTION *ConsoleMenu; DevicePath = NULL; AllDevicePath = NULL; AllCount = 0; switch (ConsoleMenuType) { case BM_CONSOLE_IN_CONTEXT_SELECT: ConsoleMenu = &ConsoleInpMenu; GetEfiGlobalVariable2 (L"ConIn", (VOID **) &DevicePath, &DevicePathSize); GetEfiGlobalVariable2 (L"ConInDev", (VOID **) &AllDevicePath, &AllDevicePathSize); break; case BM_CONSOLE_OUT_CONTEXT_SELECT: ConsoleMenu = &ConsoleOutMenu; GetEfiGlobalVariable2 (L"ConOut", (VOID **) &DevicePath, &DevicePathSize); GetEfiGlobalVariable2 (L"ConOutDev", (VOID **) &AllDevicePath, &AllDevicePathSize); break; case BM_CONSOLE_ERR_CONTEXT_SELECT: ConsoleMenu = &ConsoleErrMenu; GetEfiGlobalVariable2 (L"ErrOut", (VOID **) &DevicePath, &DevicePathSize); GetEfiGlobalVariable2 (L"ErrOutDev", (VOID **) &AllDevicePath, &AllDevicePathSize); break; default: return EFI_UNSUPPORTED; } if ((NULL == DevicePath) || (DevicePathSize < sizeof (EFI_DEVICE_PATH_PROTOCOL))) { return EFI_NOT_FOUND; } if ((NULL == AllDevicePath) || (AllDevicePathSize < sizeof (EFI_DEVICE_PATH_PROTOCOL))) { return EFI_NOT_FOUND; } InitializeListHead (&ConsoleMenu->Head); AllCount = EfiDevicePathInstanceCount (AllDevicePath); ConsoleMenu->MenuNumber = 0; // // Following is menu building up for Console Devices selected. // MultiDevicePath = AllDevicePath; Index2 = 0; for (Index = 0; Index < AllCount; Index++) { DevicePathInst = GetNextDevicePathInstance (&MultiDevicePath, &Size); NewMenuEntry = BOpt_CreateMenuEntry (BM_CONSOLE_CONTEXT_SELECT); if (NULL == NewMenuEntry) { return EFI_OUT_OF_RESOURCES; } NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext; NewMenuEntry->OptionNumber = Index2; NewConsoleContext->DevicePath = DuplicateDevicePath (DevicePathInst); ASSERT (NewConsoleContext->DevicePath != NULL); if (NewConsoleContext->DevicePath == NULL) { return EFI_OUT_OF_RESOURCES; } NewMenuEntry->DisplayString = EfiLibStrFromDatahub (NewConsoleContext->DevicePath); if (NULL == NewMenuEntry->DisplayString) { NewMenuEntry->DisplayString = UiDevicePathToStr (NewConsoleContext->DevicePath); } NewConsoleContext->IsTerminal = IsTerminalDevicePath ( NewConsoleContext->DevicePath, &Terminal, &Com ); NewConsoleContext->IsActive = MatchDevicePaths ( DevicePath, NewConsoleContext->DevicePath ); if (NewConsoleContext->IsTerminal) { BOpt_DestroyMenuEntry (NewMenuEntry); } else { Index2++; ConsoleMenu->MenuNumber++; InsertTailList (&ConsoleMenu->Head, &NewMenuEntry->Link); } } return EFI_SUCCESS; } /** Build up ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu @retval EFI_SUCCESS The function always complete successfully. **/ EFI_STATUS GetAllConsoles ( VOID ) { GetConsoleMenu (BM_CONSOLE_IN_CONTEXT_SELECT); GetConsoleMenu (BM_CONSOLE_OUT_CONTEXT_SELECT); GetConsoleMenu (BM_CONSOLE_ERR_CONTEXT_SELECT); return EFI_SUCCESS; } /** Free ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu @retval EFI_SUCCESS The function always complete successfully. **/ EFI_STATUS FreeAllConsoles ( VOID ) { BOpt_FreeMenu (&ConsoleOutMenu); BOpt_FreeMenu (&ConsoleInpMenu); BOpt_FreeMenu (&ConsoleErrMenu); BOpt_FreeMenu (&TerminalMenu); return EFI_SUCCESS; } /** Test whether DevicePath is a valid Terminal @param DevicePath DevicePath to be checked @param Termi If DevicePath is valid Terminal, terminal type is returned. @param Com If DevicePath is valid Terminal, Com Port type is returned. @retval TRUE If DevicePath point to a Terminal. @retval FALSE If DevicePath does not point to a Terminal. **/ BOOLEAN IsTerminalDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, OUT TYPE_OF_TERMINAL *Termi, OUT UINTN *Com ) { BOOLEAN IsTerminal; EFI_DEVICE_PATH_PROTOCOL *Node; VENDOR_DEVICE_PATH *Vendor; UART_DEVICE_PATH *Uart; ACPI_HID_DEVICE_PATH *Acpi; IsTerminal = FALSE; Uart = NULL; Vendor = NULL; Acpi = NULL; for (Node = DevicePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) { // // Vendor points to the node before the End node // Vendor = (VENDOR_DEVICE_PATH *) Node; if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) { Uart = (UART_DEVICE_PATH *) Node; } if (Uart == NULL) { // // Acpi points to the node before the UART node // Acpi = (ACPI_HID_DEVICE_PATH *) Node; } } if (Vendor == NULL || DevicePathType (Vendor) != MESSAGING_DEVICE_PATH || DevicePathSubType (Vendor) != MSG_VENDOR_DP || Uart == NULL) { return FALSE; } // // There are four kinds of Terminal types // check to see whether this devicepath // is one of that type // if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[0])) { *Termi = TerminalTypePcAnsi; IsTerminal = TRUE; } else { if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[1])) { *Termi = TerminalTypeVt100; IsTerminal = TRUE; } else { if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[2])) { *Termi = TerminalTypeVt100Plus; IsTerminal = TRUE; } else { if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[3])) { *Termi = TerminalTypeVtUtf8; IsTerminal = TRUE; } else { IsTerminal = FALSE; } } } } if (!IsTerminal) { return FALSE; } if ((Acpi != NULL) && IsIsaSerialNode (Acpi)) { CopyMem (Com, &Acpi->UID, sizeof (UINT32)); } else { return FALSE; } return TRUE; } /** Get mode number according to column and row @param CallbackData The BMM context data. **/ VOID GetConsoleOutMode ( IN BMM_CALLBACK_DATA *CallbackData ) { UINTN Col; UINTN Row; UINTN CurrentCol; UINTN CurrentRow; UINTN Mode; UINTN MaxMode; EFI_STATUS Status; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; ConOut = gST->ConOut; MaxMode = (UINTN) (ConOut->Mode->MaxMode); CurrentCol = PcdGet32 (PcdConOutColumn); CurrentRow = PcdGet32 (PcdConOutRow); for (Mode = 0; Mode < MaxMode; Mode++) { Status = ConOut->QueryMode (ConOut, Mode, &Col, &Row); if (!EFI_ERROR(Status)) { if (CurrentCol == Col && CurrentRow == Row) { CallbackData->BmmFakeNvData.ConsoleOutMode = (UINT16) Mode; break; } } } } /** Initialize console input device check box to ConsoleInCheck[MAX_MENU_NUMBER] in BMM_FAKE_NV_DATA structure. @param CallbackData The BMM context data. **/ VOID GetConsoleInCheck ( IN BMM_CALLBACK_DATA *CallbackData ) { UINT16 Index; BM_MENU_ENTRY *NewMenuEntry; UINT8 *ConInCheck; BM_CONSOLE_CONTEXT *NewConsoleContext; ASSERT (CallbackData != NULL); if (CallbackData == NULL) { return; } ConInCheck = &CallbackData->BmmFakeNvData.ConsoleInCheck[0]; if (ConInCheck == NULL) { return; } for (Index = 0; ((Index < ConsoleInpMenu.MenuNumber) && \ (Index < MAX_MENU_NUMBER)) ; Index++) { NewMenuEntry = BOpt_GetMenuEntry (&ConsoleInpMenu, Index); NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext; ConInCheck[Index] = NewConsoleContext->IsActive; } } /** Initialize console output device check box to ConsoleOutCheck[MAX_MENU_NUMBER] in BMM_FAKE_NV_DATA structure. @param CallbackData The BMM context data. **/ VOID GetConsoleOutCheck ( IN BMM_CALLBACK_DATA *CallbackData ) { UINT16 Index; BM_MENU_ENTRY *NewMenuEntry; UINT8 *ConOutCheck; BM_CONSOLE_CONTEXT *NewConsoleContext; ASSERT (CallbackData != NULL); if (CallbackData == NULL) return; ConOutCheck = &CallbackData->BmmFakeNvData.ConsoleOutCheck[0]; if (ConOutCheck != NULL) { for (Index = 0; ((Index < ConsoleOutMenu.MenuNumber) && \ (Index < MAX_MENU_NUMBER)) ; Index++) { NewMenuEntry = BOpt_GetMenuEntry (&ConsoleOutMenu, Index); NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext; ConOutCheck[Index] = NewConsoleContext->IsActive; } } } /** Initialize standard error output device check box to ConsoleErrCheck[MAX_MENU_NUMBER] in BMM_FAKE_NV_DATA structure. @param CallbackData The BMM context data. **/ VOID GetConsoleErrCheck ( IN BMM_CALLBACK_DATA *CallbackData ) { UINT16 Index; BM_MENU_ENTRY *NewMenuEntry; UINT8 *ConErrCheck; BM_CONSOLE_CONTEXT *NewConsoleContext; ASSERT (CallbackData != NULL); if (CallbackData == NULL) return; ConErrCheck = &CallbackData->BmmFakeNvData.ConsoleErrCheck[0]; if (ConErrCheck != NULL) { for (Index = 0; ((Index < ConsoleErrMenu.MenuNumber) && \ (Index < MAX_MENU_NUMBER)) ; Index++) { NewMenuEntry = BOpt_GetMenuEntry (&ConsoleErrMenu, Index); NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext; ConErrCheck[Index] = NewConsoleContext->IsActive; } } } /** Initialize terminal attributes (baudrate, data rate, stop bits, parity and terminal type) to BMM_FAKE_NV_DATA structure. @param CallbackData The BMM context data. **/ VOID GetTerminalAttribute ( IN BMM_CALLBACK_DATA *CallbackData ) { BMM_FAKE_NV_DATA *CurrentFakeNVMap; BM_MENU_ENTRY *NewMenuEntry; BM_TERMINAL_CONTEXT *NewTerminalContext; UINT16 TerminalIndex; UINT8 AttributeIndex; ASSERT (CallbackData != NULL); if (CallbackData == NULL) { return; } CurrentFakeNVMap = &CallbackData->BmmFakeNvData; if (CurrentFakeNVMap == NULL) { return; } for (TerminalIndex = 0; ((TerminalIndex < TerminalMenu.MenuNumber) && \ (TerminalIndex < MAX_MENU_NUMBER)); TerminalIndex++) { NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, TerminalIndex); NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; for (AttributeIndex = 0; AttributeIndex < sizeof (BaudRateList) / sizeof (BaudRateList [0]); AttributeIndex++) { if (NewTerminalContext->BaudRate == (UINT64) (BaudRateList[AttributeIndex].Value)) { NewTerminalContext->BaudRateIndex = AttributeIndex; break; } } for (AttributeIndex = 0; AttributeIndex < sizeof (DataBitsList) / sizeof (DataBitsList[0]); AttributeIndex++) { if (NewTerminalContext->DataBits == (UINT64) (DataBitsList[AttributeIndex].Value)) { NewTerminalContext->DataBitsIndex = AttributeIndex; break; } } for (AttributeIndex = 0; AttributeIndex < sizeof (ParityList) / sizeof (ParityList[0]); AttributeIndex++) { if (NewTerminalContext->Parity == (UINT64) (ParityList[AttributeIndex].Value)) { NewTerminalContext->ParityIndex = AttributeIndex; break; } } for (AttributeIndex = 0; AttributeIndex < sizeof (StopBitsList) / sizeof (StopBitsList[0]); AttributeIndex++) { if (NewTerminalContext->StopBits == (UINT64) (StopBitsList[AttributeIndex].Value)) { NewTerminalContext->StopBitsIndex = AttributeIndex; break; } } CurrentFakeNVMap->COMBaudRate[TerminalIndex] = NewTerminalContext->BaudRateIndex; CurrentFakeNVMap->COMDataRate[TerminalIndex] = NewTerminalContext->DataBitsIndex; CurrentFakeNVMap->COMStopBits[TerminalIndex] = NewTerminalContext->StopBitsIndex; CurrentFakeNVMap->COMParity[TerminalIndex] = NewTerminalContext->ParityIndex; CurrentFakeNVMap->COMTerminalType[TerminalIndex] = NewTerminalContext->TerminalType; CurrentFakeNVMap->COMFlowControl[TerminalIndex] = NewTerminalContext->FlowControl; CurrentFakeNVMap->COMLegacyResolution[TerminalIndex] = NewTerminalContext->LegacyResolution; CurrentFakeNVMap->COMIsEnabled[TerminalIndex] = NewTerminalContext->IsEnabled; } } /** Initialize Com Output band port (COMOutOfBandPort) to BMM_FAKE_NV_DATA structure. @param CallbackData The BMM context data. **/ VOID GetComOutOfBandPort ( IN BMM_CALLBACK_DATA *CallbackData ) { UINT16 Index; BM_MENU_ENTRY *NewMenuEntry; BM_TERMINAL_CONTEXT *NewTerminalContext; if (CallbackData == NULL) { return; } if (TerminalMenu.MenuNumber > 0) { for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index); NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext; if (NewTerminalContext->IsOutOfBand) { CallbackData->BmmFakeNvData.COMOutOfBandPort = Index; break; } } if (Index == TerminalMenu.MenuNumber) { CallbackData->BmmFakeNvData.COMOutOfBandPort = Index; } } }