Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Elvin Li <elvin.li@intel.com> Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15407 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1770 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1770 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Produces Simple Text Input Protocol, Simple Text Input Extended Protocol and
 | |
|   Simple Text Output Protocol upon Serial IO Protocol.
 | |
| 
 | |
| Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
 | |
| This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions of the BSD License
 | |
| which accompanies this distribution.  The full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| 
 | |
| #include "Terminal.h"
 | |
| 
 | |
| //
 | |
| // Globals
 | |
| //
 | |
| EFI_DRIVER_BINDING_PROTOCOL gTerminalDriverBinding = {
 | |
|   TerminalDriverBindingSupported,
 | |
|   TerminalDriverBindingStart,
 | |
|   TerminalDriverBindingStop,
 | |
|   0xa,
 | |
|   NULL,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| 
 | |
| EFI_GUID  *gTerminalType[] = {
 | |
|   &gEfiPcAnsiGuid,
 | |
|   &gEfiVT100Guid,
 | |
|   &gEfiVT100PlusGuid,
 | |
|   &gEfiVTUTF8Guid
 | |
| };
 | |
| 
 | |
| 
 | |
| TERMINAL_DEV  mTerminalDevTemplate = {
 | |
|   TERMINAL_DEV_SIGNATURE,
 | |
|   NULL,
 | |
|   0,
 | |
|   NULL,
 | |
|   NULL,
 | |
|   {   // SimpleTextInput
 | |
|     TerminalConInReset,
 | |
|     TerminalConInReadKeyStroke,
 | |
|     NULL
 | |
|   },
 | |
|   {   // SimpleTextOutput
 | |
|     TerminalConOutReset,
 | |
|     TerminalConOutOutputString,
 | |
|     TerminalConOutTestString,
 | |
|     TerminalConOutQueryMode,
 | |
|     TerminalConOutSetMode,
 | |
|     TerminalConOutSetAttribute,
 | |
|     TerminalConOutClearScreen,
 | |
|     TerminalConOutSetCursorPosition,
 | |
|     TerminalConOutEnableCursor,
 | |
|     NULL
 | |
|   },
 | |
|   {   // SimpleTextOutputMode
 | |
|     1,                                           // MaxMode
 | |
|     0,                                           // Mode
 | |
|     EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK),    // Attribute
 | |
|     0,                                           // CursorColumn
 | |
|     0,                                           // CursorRow
 | |
|     TRUE                                         // CursorVisible
 | |
|   },
 | |
|   NULL, // TerminalConsoleModeData
 | |
|   0,  // SerialInTimeOut
 | |
| 
 | |
|   NULL, // RawFifo
 | |
|   NULL, // UnicodeFiFo
 | |
|   NULL, // EfiKeyFiFo
 | |
| 
 | |
|   NULL, // ControllerNameTable
 | |
|   NULL, // TimerEvent
 | |
|   NULL, // TwoSecondTimeOut
 | |
|   INPUT_STATE_DEFAULT,
 | |
|   RESET_STATE_DEFAULT,
 | |
|   FALSE,
 | |
|   {   // SimpleTextInputEx
 | |
|     TerminalConInResetEx,
 | |
|     TerminalConInReadKeyStrokeEx,
 | |
|     NULL,
 | |
|     TerminalConInSetState,
 | |
|     TerminalConInRegisterKeyNotify,
 | |
|     TerminalConInUnregisterKeyNotify,
 | |
|   },
 | |
|   {   // NotifyList
 | |
|     NULL,
 | |
|     NULL,
 | |
|   }
 | |
| };
 | |
| 
 | |
| TERMINAL_CONSOLE_MODE_DATA mTerminalConsoleModeData[] = {
 | |
|   {100, 31},
 | |
|   //
 | |
|   // New modes can be added here.
 | |
|   //
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Test to see if this driver supports Controller.
 | |
| 
 | |
|   @param  This                Protocol instance pointer.
 | |
|   @param  Controller          Handle of device to test
 | |
|   @param  RemainingDevicePath Optional parameter use to pick a specific child
 | |
|                               device to start.
 | |
| 
 | |
|   @retval EFI_SUCCESS         This driver supports this device.
 | |
|   @retval EFI_ALREADY_STARTED This driver is already running on this device.
 | |
|   @retval other               This driver does not support this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| TerminalDriverBindingSupported (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
 | |
|   IN EFI_HANDLE                     Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                Status;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
 | |
|   EFI_SERIAL_IO_PROTOCOL    *SerialIo;
 | |
|   VENDOR_DEVICE_PATH        *Node;
 | |
| 
 | |
|   //
 | |
|   // If remaining device path is not NULL, then make sure it is a
 | |
|   // device path that describes a terminal communications protocol.
 | |
|   //
 | |
|   if (RemainingDevicePath != NULL) {
 | |
|     //
 | |
|     // Check if RemainingDevicePath is the End of Device Path Node,
 | |
|     // if yes, go on checking other conditions
 | |
|     //
 | |
|     if (!IsDevicePathEnd (RemainingDevicePath)) {
 | |
|       //
 | |
|       // If RemainingDevicePath isn't the End of Device Path Node,
 | |
|       // check its validation
 | |
|       //
 | |
|       Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
 | |
| 
 | |
|       if (Node->Header.Type != MESSAGING_DEVICE_PATH ||
 | |
|           Node->Header.SubType != MSG_VENDOR_DP ||
 | |
|           DevicePathNodeLength(&Node->Header) != sizeof(VENDOR_DEVICE_PATH)) {
 | |
| 
 | |
|         return EFI_UNSUPPORTED;
 | |
| 
 | |
|       }
 | |
|       //
 | |
|       // only supports PC ANSI, VT100, VT100+ and VT-UTF8 terminal types
 | |
|       //
 | |
|       if (!CompareGuid (&Node->Guid, &gEfiPcAnsiGuid) &&
 | |
|           !CompareGuid (&Node->Guid, &gEfiVT100Guid) &&
 | |
|           !CompareGuid (&Node->Guid, &gEfiVT100PlusGuid) &&
 | |
|           !CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
 | |
| 
 | |
|         return EFI_UNSUPPORTED;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Open the IO Abstraction(s) needed to perform the supported test
 | |
|   // The Controller must support the Serial I/O Protocol.
 | |
|   // This driver is a bus driver with at most 1 child device, so it is
 | |
|   // ok for it to be already started.
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiSerialIoProtocolGuid,
 | |
|                   (VOID **) &SerialIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (Status == EFI_ALREADY_STARTED) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Close the I/O Abstraction(s) used to perform the supported test
 | |
|   //
 | |
|   gBS->CloseProtocol (
 | |
|         Controller,
 | |
|         &gEfiSerialIoProtocolGuid,
 | |
|         This->DriverBindingHandle,
 | |
|         Controller
 | |
|         );
 | |
| 
 | |
|   //
 | |
|   // Open the EFI Device Path protocol needed to perform the supported test
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   (VOID **) &ParentDevicePath,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (Status == EFI_ALREADY_STARTED) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Close protocol, don't use device path protocol in the Support() function
 | |
|   //
 | |
|   gBS->CloseProtocol (
 | |
|         Controller,
 | |
|         &gEfiDevicePathProtocolGuid,
 | |
|         This->DriverBindingHandle,
 | |
|         Controller
 | |
|         );
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build the terminal device path for the child device according to the
 | |
|   terminal type.
 | |
| 
 | |
|   @param  ParentDevicePath         Parent device path.
 | |
|   @param  RemainingDevicePath      A specific child device.
 | |
| 
 | |
|   @return The child device path built.
 | |
| 
 | |
| **/
 | |
| EFI_DEVICE_PATH_PROTOCOL*
 | |
| EFIAPI
 | |
| BuildTerminalDevpath  (
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL       *ParentDevicePath,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_DEVICE_PATH_PROTOCOL          *TerminalDevicePath;
 | |
|   UINT8                             TerminalType;
 | |
|   VENDOR_DEVICE_PATH                *Node;
 | |
|   EFI_STATUS                        Status;
 | |
| 
 | |
|   TerminalDevicePath = NULL;
 | |
|   TerminalType = PCANSITYPE;
 | |
| 
 | |
|   //
 | |
|   // Use the RemainingDevicePath to determine the terminal type
 | |
|   //
 | |
|   Node = (VENDOR_DEVICE_PATH *) RemainingDevicePath;
 | |
|   if (Node == NULL) {
 | |
|     TerminalType = PCANSITYPE;
 | |
| 
 | |
|   } else if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {
 | |
| 
 | |
|     TerminalType = PCANSITYPE;
 | |
| 
 | |
|   } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {
 | |
| 
 | |
|     TerminalType = VT100TYPE;
 | |
| 
 | |
|   } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {
 | |
| 
 | |
|     TerminalType = VT100PLUSTYPE;
 | |
| 
 | |
|   } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
 | |
| 
 | |
|     TerminalType = VTUTF8TYPE;
 | |
| 
 | |
|   } else {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Build the device path for the child device
 | |
|   //
 | |
|   Status = SetTerminalDevicePath (
 | |
|             TerminalType,
 | |
|             ParentDevicePath,
 | |
|             &TerminalDevicePath
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return NULL;
 | |
|   }
 | |
|   return TerminalDevicePath;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Compare 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 is contained within Multi.
 | |
|   @retval FALSE          The Single is not match within Multi.
 | |
| 
 | |
| **/
 | |
| 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;
 | |
| 
 | |
|   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 terminal device path is in the global variable.
 | |
| 
 | |
|   @param  VariableName          Pointer to one global variable.
 | |
|   @param  TerminalDevicePath    Pointer to the terminal device's device path.
 | |
| 
 | |
|   @retval TRUE                  The devcie is in the global variable.
 | |
|   @retval FALSE                 The devcie is not in the global variable.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| IsTerminalInConsoleVariable (
 | |
|   IN CHAR16                    *VariableName,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL  *TerminalDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *Variable;
 | |
|   BOOLEAN                   ReturnFlag;
 | |
| 
 | |
|   //
 | |
|   // Get global variable and its size according to the name given.
 | |
|   //
 | |
|   GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
 | |
|   if (Variable == NULL) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check whether the terminal device path is one of the variable instances.
 | |
|   //
 | |
|   ReturnFlag = MatchDevicePaths (Variable, TerminalDevicePath);
 | |
| 
 | |
|   FreePool (Variable);
 | |
| 
 | |
|   return ReturnFlag;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Free notify functions list.
 | |
| 
 | |
|   @param  ListHead               The list head
 | |
| 
 | |
|   @retval EFI_SUCCESS            Free the notify list successfully.
 | |
|   @retval EFI_INVALID_PARAMETER  ListHead is NULL.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| TerminalFreeNotifyList (
 | |
|   IN OUT LIST_ENTRY           *ListHead
 | |
|   )
 | |
| {
 | |
|   TERMINAL_CONSOLE_IN_EX_NOTIFY *NotifyNode;
 | |
| 
 | |
|   if (ListHead == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   while (!IsListEmpty (ListHead)) {
 | |
|     NotifyNode = CR (
 | |
|                    ListHead->ForwardLink,
 | |
|                    TERMINAL_CONSOLE_IN_EX_NOTIFY,
 | |
|                    NotifyEntry,
 | |
|                    TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
 | |
|                    );
 | |
|     RemoveEntryList (ListHead->ForwardLink);
 | |
|     FreePool (NotifyNode);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize all the text modes which the terminal console supports.
 | |
| 
 | |
|   It returns information for available text modes that the terminal can support.
 | |
| 
 | |
|   @param[out] TextModeCount      The total number of text modes that terminal console supports.
 | |
|   @param[out] TextModeData       The buffer to the text modes column and row information.
 | |
|                                  Caller is responsible to free it when it's non-NULL.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The supporting mode information is returned.
 | |
|   @retval EFI_INVALID_PARAMETER  The parameters are invalid.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| InitializeTerminalConsoleTextMode (
 | |
|   OUT UINTN                         *TextModeCount,
 | |
|   OUT TERMINAL_CONSOLE_MODE_DATA    **TextModeData
 | |
|   )
 | |
| {
 | |
|   UINTN                       Index;
 | |
|   UINTN                       Count;
 | |
|   TERMINAL_CONSOLE_MODE_DATA  *ModeBuffer;
 | |
|   TERMINAL_CONSOLE_MODE_DATA  *NewModeBuffer;
 | |
|   UINTN                       ValidCount;
 | |
|   UINTN                       ValidIndex;
 | |
|   
 | |
|   if ((TextModeCount == NULL) || (TextModeData == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   
 | |
|   Count = sizeof (mTerminalConsoleModeData) / sizeof (TERMINAL_CONSOLE_MODE_DATA);
 | |
|   
 | |
|   //
 | |
|   // Get defined mode buffer pointer.
 | |
|   //
 | |
|   ModeBuffer = mTerminalConsoleModeData;
 | |
|     
 | |
|   //
 | |
|   // Here we make sure that the final mode exposed does not include the duplicated modes,
 | |
|   // and does not include the invalid modes which exceed the max column and row.
 | |
|   // Reserve 2 modes for 80x25, 80x50 of terminal console.
 | |
|   //
 | |
|   NewModeBuffer = AllocateZeroPool (sizeof (TERMINAL_CONSOLE_MODE_DATA) * (Count + 2));
 | |
|   ASSERT (NewModeBuffer != NULL);
 | |
| 
 | |
|   //
 | |
|   // Mode 0 and mode 1 is for 80x25, 80x50 according to UEFI spec.
 | |
|   //
 | |
|   ValidCount = 0;  
 | |
| 
 | |
|   NewModeBuffer[ValidCount].Columns = 80;
 | |
|   NewModeBuffer[ValidCount].Rows    = 25;
 | |
|   ValidCount++;
 | |
| 
 | |
|   NewModeBuffer[ValidCount].Columns = 80;
 | |
|   NewModeBuffer[ValidCount].Rows    = 50;
 | |
|   ValidCount++;
 | |
|   
 | |
|   //
 | |
|   // Start from mode 2 to put the valid mode other than 80x25 and 80x50 in the output mode buffer.
 | |
|   //
 | |
|   for (Index = 0; Index < Count; Index++) {
 | |
|     if ((ModeBuffer[Index].Columns == 0) || (ModeBuffer[Index].Rows == 0)) {
 | |
|       //
 | |
|       // Skip the pre-defined mode which is invalid.
 | |
|       //
 | |
|       continue;
 | |
|     }
 | |
|     for (ValidIndex = 0; ValidIndex < ValidCount; ValidIndex++) {
 | |
|       if ((ModeBuffer[Index].Columns == NewModeBuffer[ValidIndex].Columns) &&
 | |
|           (ModeBuffer[Index].Rows == NewModeBuffer[ValidIndex].Rows)) {
 | |
|         //
 | |
|         // Skip the duplicated mode.
 | |
|         //
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|     if (ValidIndex == ValidCount) {
 | |
|       NewModeBuffer[ValidCount].Columns = ModeBuffer[Index].Columns;
 | |
|       NewModeBuffer[ValidCount].Rows    = ModeBuffer[Index].Rows;
 | |
|       ValidCount++;
 | |
|     }
 | |
|   }
 | |
|  
 | |
|   DEBUG_CODE (
 | |
|     for (Index = 0; Index < ValidCount; Index++) {
 | |
|       DEBUG ((EFI_D_INFO, "Terminal - Mode %d, Column = %d, Row = %d\n", 
 | |
|                            Index, NewModeBuffer[Index].Columns, NewModeBuffer[Index].Rows));  
 | |
|     }
 | |
|   );
 | |
|   
 | |
|   //
 | |
|   // Return valid mode count and mode information buffer.
 | |
|   //
 | |
|   *TextModeCount = ValidCount;
 | |
|   *TextModeData  = NewModeBuffer;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Start this driver on Controller by opening a Serial IO protocol,
 | |
|   reading Device Path, and creating a child handle with a Simple Text In,
 | |
|   Simple Text In Ex and Simple Text Out protocol, and device path protocol.
 | |
|   And store Console Device Environment Variables.
 | |
| 
 | |
|   @param  This                 Protocol instance pointer.
 | |
|   @param  Controller           Handle of device to bind driver to
 | |
|   @param  RemainingDevicePath  Optional parameter use to pick a specific child
 | |
|                                device to start.
 | |
| 
 | |
|   @retval EFI_SUCCESS          This driver is added to Controller.
 | |
|   @retval EFI_ALREADY_STARTED  This driver is already running on Controller.
 | |
|   @retval other                This driver does not support this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| TerminalDriverBindingStart (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
 | |
|   IN EFI_HANDLE                     Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                          Status;
 | |
|   EFI_SERIAL_IO_PROTOCOL              *SerialIo;
 | |
|   EFI_DEVICE_PATH_PROTOCOL            *ParentDevicePath;
 | |
|   VENDOR_DEVICE_PATH                  *Node;
 | |
|   VENDOR_DEVICE_PATH                  *DefaultNode;
 | |
|   EFI_SERIAL_IO_MODE                  *Mode;
 | |
|   UINTN                               SerialInTimeOut;
 | |
|   TERMINAL_DEV                        *TerminalDevice;
 | |
|   UINT8                               TerminalType;
 | |
|   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
 | |
|   UINTN                               EntryCount;
 | |
|   UINTN                               Index;
 | |
|   EFI_DEVICE_PATH_PROTOCOL            *DevicePath;
 | |
|   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL     *SimpleTextOutput;
 | |
|   EFI_SIMPLE_TEXT_INPUT_PROTOCOL      *SimpleTextInput;
 | |
|   BOOLEAN                             ConInSelected;
 | |
|   BOOLEAN                             ConOutSelected;
 | |
|   BOOLEAN                             NullRemaining;
 | |
|   BOOLEAN                             SimTxtInInstalled;
 | |
|   BOOLEAN                             SimTxtOutInstalled;
 | |
|   BOOLEAN                             FirstEnter;
 | |
|   UINTN                               ModeCount;
 | |
| 
 | |
|   TerminalDevice     = NULL;
 | |
|   DefaultNode        = NULL;
 | |
|   ConInSelected       = FALSE;
 | |
|   ConOutSelected      = FALSE;
 | |
|   NullRemaining      = TRUE;
 | |
|   SimTxtInInstalled  = FALSE;
 | |
|   SimTxtOutInstalled = FALSE;
 | |
|   FirstEnter         = FALSE;
 | |
|   //
 | |
|   // Get the Device Path Protocol to build the device path of the child device
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   (VOID **) &ParentDevicePath,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Open the Serial I/O Protocol BY_DRIVER.  It might already be started.
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiSerialIoProtocolGuid,
 | |
|                   (VOID **) &SerialIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (Status != EFI_ALREADY_STARTED) {
 | |
|     //
 | |
|     // the serial I/O protocol never be opened before, it is the first
 | |
|     // time to start the serial Io controller
 | |
|     //
 | |
|     FirstEnter = TRUE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Serial I/O is not already open by this driver, then tag the handle
 | |
|   // with the Terminal Driver GUID and update the ConInDev, ConOutDev, and
 | |
|   // StdErrDev variables with the list of possible terminal types on this
 | |
|   // serial port.
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiCallerIdGuid,
 | |
|                   NULL,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                     &Controller,
 | |
|                     &gEfiCallerIdGuid,
 | |
|                     DuplicateDevicePath (ParentDevicePath),
 | |
|                     NULL
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Error;
 | |
|     }
 | |
| 
 | |
|     if (!IsHotPlugDevice (ParentDevicePath)) {
 | |
|       //
 | |
|       // if the serial device is a hot plug device, do not update the
 | |
|       // ConInDev, ConOutDev, and StdErrDev variables.
 | |
|       //
 | |
|       TerminalUpdateConsoleDevVariable (L"ConInDev", ParentDevicePath);
 | |
|       TerminalUpdateConsoleDevVariable (L"ConOutDev", ParentDevicePath);
 | |
|       TerminalUpdateConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check the requirement for the SimpleTxtIn and SimpleTxtOut protocols
 | |
|   //
 | |
|   // Simple In/Out Protocol will not be installed onto the handle if the
 | |
|   // device path to the handle is not present in the ConIn/ConOut
 | |
|   // environment variable. But If RemainingDevicePath is NULL, then always
 | |
|   // produce both Simple In and Simple Text Output Protocols. This is required
 | |
|   // for the connect all sequences to make sure all possible consoles are
 | |
|   // produced no matter what the current values of ConIn, ConOut, or StdErr are.
 | |
|   //
 | |
|   if (RemainingDevicePath == NULL) {
 | |
|     NullRemaining = TRUE;
 | |
|   }
 | |
| 
 | |
|   DevicePath = BuildTerminalDevpath (ParentDevicePath, RemainingDevicePath);
 | |
|   if (DevicePath != NULL) {
 | |
|     ConInSelected  = IsTerminalInConsoleVariable (L"ConIn", DevicePath);
 | |
|     ConOutSelected = IsTerminalInConsoleVariable (L"ConOut", DevicePath);
 | |
|     FreePool (DevicePath);
 | |
|   } else {
 | |
|     goto Error;
 | |
|   }
 | |
|   //
 | |
|   // Not create the child terminal handle if both Simple In/In Ex and
 | |
|   // Simple text Out protocols are not required to be published
 | |
|   //
 | |
|   if ((!ConInSelected)&&(!ConOutSelected)&&(!NullRemaining)) {
 | |
|     goto Error;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // create the child terminal handle during first entry
 | |
|   //
 | |
|   if (FirstEnter) {
 | |
|     //
 | |
|     // First enther the start funciton
 | |
|     //
 | |
|     FirstEnter = FALSE;
 | |
|     //
 | |
|     // Make sure a child handle does not already exist.  This driver can only
 | |
|     // produce one child per serial port.
 | |
|     //
 | |
|     Status = gBS->OpenProtocolInformation (
 | |
|                     Controller,
 | |
|                     &gEfiSerialIoProtocolGuid,
 | |
|                     &OpenInfoBuffer,
 | |
|                     &EntryCount
 | |
|                     );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       Status = EFI_SUCCESS;
 | |
|       for (Index = 0; Index < EntryCount; Index++) {
 | |
|         if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
 | |
|           Status = EFI_ALREADY_STARTED;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       FreePool (OpenInfoBuffer);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|           goto Error;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // If RemainingDevicePath is NULL, then create default device path node
 | |
|     //
 | |
|     if (RemainingDevicePath == NULL) {
 | |
|       DefaultNode = AllocateZeroPool (sizeof (VENDOR_DEVICE_PATH));
 | |
|       if (DefaultNode == NULL) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto Error;
 | |
|       }
 | |
| 
 | |
|       TerminalType = PcdGet8 (PcdDefaultTerminalType);
 | |
|       //
 | |
|       // Must be between PCANSITYPE (0) and VTUTF8TYPE (3)
 | |
|       //
 | |
|       ASSERT (TerminalType <= VTUTF8TYPE);
 | |
| 
 | |
|       CopyMem (&DefaultNode->Guid, gTerminalType[TerminalType], sizeof (EFI_GUID));
 | |
|       RemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DefaultNode;
 | |
|     } else if (!IsDevicePathEnd (RemainingDevicePath)) {
 | |
|       //
 | |
|       // If RemainingDevicePath isn't the End of Device Path Node,
 | |
|       // Use the RemainingDevicePath to determine the terminal type
 | |
|       //
 | |
|       Node = (VENDOR_DEVICE_PATH *)RemainingDevicePath;
 | |
|       if (CompareGuid (&Node->Guid, &gEfiPcAnsiGuid)) {
 | |
|         TerminalType = PCANSITYPE;
 | |
|       } else if (CompareGuid (&Node->Guid, &gEfiVT100Guid)) {
 | |
|         TerminalType = VT100TYPE;
 | |
|       } else if (CompareGuid (&Node->Guid, &gEfiVT100PlusGuid)) {
 | |
|         TerminalType = VT100PLUSTYPE;
 | |
|       } else if (CompareGuid (&Node->Guid, &gEfiVTUTF8Guid)) {
 | |
|         TerminalType = VTUTF8TYPE;
 | |
|       } else {
 | |
|         goto Error;
 | |
|       }
 | |
|     } else {
 | |
|       //
 | |
|       // If RemainingDevicePath is the End of Device Path Node,
 | |
|       // skip enumerate any device and return EFI_SUCESSS
 | |
|       //
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Initialize the Terminal Dev
 | |
|     //
 | |
|     TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);
 | |
|     if (TerminalDevice == NULL) {
 | |
|       Status = EFI_OUT_OF_RESOURCES;
 | |
|       goto Error;
 | |
|     }
 | |
| 
 | |
|     TerminalDevice->TerminalType  = TerminalType;
 | |
|     TerminalDevice->SerialIo      = SerialIo;
 | |
| 
 | |
|     InitializeListHead (&TerminalDevice->NotifyList);
 | |
|     Status = gBS->CreateEvent (
 | |
|                     EVT_NOTIFY_WAIT,
 | |
|                     TPL_NOTIFY,
 | |
|                     TerminalConInWaitForKeyEx,
 | |
|                     TerminalDevice,
 | |
|                     &TerminalDevice->SimpleInputEx.WaitForKeyEx
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Error;
 | |
|     }
 | |
| 
 | |
|     Status = gBS->CreateEvent (
 | |
|                     EVT_NOTIFY_WAIT,
 | |
|                     TPL_NOTIFY,
 | |
|                     TerminalConInWaitForKey,
 | |
|                     TerminalDevice,
 | |
|                     &TerminalDevice->SimpleInput.WaitForKey
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Error;
 | |
|     }
 | |
|     //
 | |
|     // Allocates and initializes the FIFO buffer to be zero, used for accommodating
 | |
|     // the pre-read pending characters.
 | |
|     //
 | |
|     TerminalDevice->RawFiFo     = AllocateZeroPool (sizeof (RAW_DATA_FIFO));
 | |
|     if (TerminalDevice->RawFiFo == NULL) {
 | |
|       goto Error;
 | |
|     }
 | |
|     TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));
 | |
|     if (TerminalDevice->UnicodeFiFo == NULL) {
 | |
|       goto Error;
 | |
|     }
 | |
|     TerminalDevice->EfiKeyFiFo  = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
 | |
|     if (TerminalDevice->EfiKeyFiFo == NULL) {
 | |
|       goto Error;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Set the timeout value of serial buffer for
 | |
|     // keystroke response performance issue
 | |
|     //
 | |
|     Mode            = TerminalDevice->SerialIo->Mode;
 | |
| 
 | |
|     SerialInTimeOut = 0;
 | |
|     if (Mode->BaudRate != 0) {
 | |
|       SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;
 | |
|     }
 | |
| 
 | |
|     Status = TerminalDevice->SerialIo->SetAttributes (
 | |
|                                         TerminalDevice->SerialIo,
 | |
|                                         Mode->BaudRate,
 | |
|                                         Mode->ReceiveFifoDepth,
 | |
|                                         (UINT32) SerialInTimeOut,
 | |
|                                         (EFI_PARITY_TYPE) (Mode->Parity),
 | |
|                                         (UINT8) Mode->DataBits,
 | |
|                                         (EFI_STOP_BITS_TYPE) (Mode->StopBits)
 | |
|                                         );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // if set attributes operation fails, invalidate
 | |
|       // the value of SerialInTimeOut,thus make it
 | |
|       // inconsistent with the default timeout value
 | |
|       // of serial buffer. This will invoke the recalculation
 | |
|       // in the readkeystroke routine.
 | |
|       //
 | |
|       TerminalDevice->SerialInTimeOut = 0;
 | |
|     } else {
 | |
|       TerminalDevice->SerialInTimeOut = SerialInTimeOut;
 | |
|     }
 | |
|     //
 | |
|     // Set Simple Text Output Protocol from template.
 | |
|     //
 | |
|     SimpleTextOutput = CopyMem (
 | |
|                          &TerminalDevice->SimpleTextOutput,
 | |
|                          &mTerminalDevTemplate.SimpleTextOutput,
 | |
|                          sizeof (mTerminalDevTemplate.SimpleTextOutput)
 | |
|                          );
 | |
|     SimpleTextOutput->Mode = &TerminalDevice->SimpleTextOutputMode;
 | |
|     
 | |
|     Status = InitializeTerminalConsoleTextMode (&ModeCount, &TerminalDevice->TerminalConsoleModeData);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ReportError;
 | |
|     }
 | |
|     TerminalDevice->SimpleTextOutputMode.MaxMode = (INT32) ModeCount;
 | |
|     
 | |
|     //
 | |
|     // For terminal devices, cursor is always visible
 | |
|     //
 | |
|     TerminalDevice->SimpleTextOutputMode.CursorVisible = TRUE;
 | |
|     Status = TerminalConOutSetAttribute (
 | |
|                SimpleTextOutput,
 | |
|                EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ReportError;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Build the component name for the child device
 | |
|     //
 | |
|     TerminalDevice->ControllerNameTable = NULL;
 | |
|     switch (TerminalDevice->TerminalType) {
 | |
|     case PCANSITYPE:
 | |
|       AddUnicodeString2 (
 | |
|         "eng",
 | |
|         gTerminalComponentName.SupportedLanguages,
 | |
|         &TerminalDevice->ControllerNameTable,
 | |
|         (CHAR16 *)L"PC-ANSI Serial Console",
 | |
|         TRUE
 | |
|         );
 | |
|       AddUnicodeString2 (
 | |
|         "en",
 | |
|         gTerminalComponentName2.SupportedLanguages,
 | |
|         &TerminalDevice->ControllerNameTable,
 | |
|         (CHAR16 *)L"PC-ANSI Serial Console",
 | |
|         FALSE
 | |
|         );
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case VT100TYPE:
 | |
|       AddUnicodeString2 (
 | |
|         "eng",
 | |
|         gTerminalComponentName.SupportedLanguages,
 | |
|         &TerminalDevice->ControllerNameTable,
 | |
|         (CHAR16 *)L"VT-100 Serial Console",
 | |
|         TRUE
 | |
|         );
 | |
|       AddUnicodeString2 (
 | |
|         "en",
 | |
|         gTerminalComponentName2.SupportedLanguages,
 | |
|         &TerminalDevice->ControllerNameTable,
 | |
|         (CHAR16 *)L"VT-100 Serial Console",
 | |
|         FALSE
 | |
|         );
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case VT100PLUSTYPE:
 | |
|       AddUnicodeString2 (
 | |
|         "eng",
 | |
|         gTerminalComponentName.SupportedLanguages,
 | |
|         &TerminalDevice->ControllerNameTable,
 | |
|         (CHAR16 *)L"VT-100+ Serial Console",
 | |
|         TRUE
 | |
|         );
 | |
|       AddUnicodeString2 (
 | |
|         "en",
 | |
|         gTerminalComponentName2.SupportedLanguages,
 | |
|         &TerminalDevice->ControllerNameTable,
 | |
|         (CHAR16 *)L"VT-100+ Serial Console",
 | |
|         FALSE
 | |
|         );
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case VTUTF8TYPE:
 | |
|       AddUnicodeString2 (
 | |
|         "eng",
 | |
|         gTerminalComponentName.SupportedLanguages,
 | |
|         &TerminalDevice->ControllerNameTable,
 | |
|         (CHAR16 *)L"VT-UTF8 Serial Console",
 | |
|         TRUE
 | |
|         );
 | |
|       AddUnicodeString2 (
 | |
|         "en",
 | |
|         gTerminalComponentName2.SupportedLanguages,
 | |
|         &TerminalDevice->ControllerNameTable,
 | |
|         (CHAR16 *)L"VT-UTF8 Serial Console",
 | |
|         FALSE
 | |
|         );
 | |
| 
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Build the device path for the child device
 | |
|     //
 | |
|     Status = SetTerminalDevicePath (
 | |
|               TerminalDevice->TerminalType,
 | |
|               ParentDevicePath,
 | |
|               &TerminalDevice->DevicePath
 | |
|               );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Error;
 | |
|     }
 | |
| 
 | |
|     Status = TerminalConOutReset (SimpleTextOutput, FALSE);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ReportError;
 | |
|     }
 | |
| 
 | |
|     Status = TerminalConOutSetMode (SimpleTextOutput, 0);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ReportError;
 | |
|     }
 | |
| 
 | |
|     Status = TerminalConOutEnableCursor (SimpleTextOutput, TRUE);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ReportError;
 | |
|     }
 | |
| 
 | |
|     Status = gBS->CreateEvent (
 | |
|                     EVT_TIMER | EVT_NOTIFY_SIGNAL,
 | |
|                     TPL_NOTIFY,
 | |
|                     TerminalConInTimerHandler,
 | |
|                     TerminalDevice,
 | |
|                     &TerminalDevice->TimerEvent
 | |
|                     );
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|     Status = gBS->SetTimer (
 | |
|                     TerminalDevice->TimerEvent,
 | |
|                     TimerPeriodic,
 | |
|                     KEYBOARD_TIMER_INTERVAL
 | |
|                     );
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|     Status = gBS->CreateEvent (
 | |
|                     EVT_TIMER,
 | |
|                     TPL_CALLBACK,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     &TerminalDevice->TwoSecondTimeOut
 | |
|                     );
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|     Status = gBS->InstallProtocolInterface (
 | |
|                     &TerminalDevice->Handle,
 | |
|                     &gEfiDevicePathProtocolGuid,
 | |
|                     EFI_NATIVE_INTERFACE,
 | |
|                     TerminalDevice->DevicePath
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Error;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Register the Parent-Child relationship via
 | |
|     // EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
 | |
|     //
 | |
|     Status = gBS->OpenProtocol (
 | |
|                     Controller,
 | |
|                     &gEfiSerialIoProtocolGuid,
 | |
|                     (VOID **) &TerminalDevice->SerialIo,
 | |
|                     This->DriverBindingHandle,
 | |
|                     TerminalDevice->Handle,
 | |
|                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Error;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Find the child handle, and get its TerminalDevice private data
 | |
|   //
 | |
|   Status = gBS->OpenProtocolInformation (
 | |
|                   Controller,
 | |
|                   &gEfiSerialIoProtocolGuid,
 | |
|                   &OpenInfoBuffer,
 | |
|                   &EntryCount
 | |
|                   );
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     Status = EFI_NOT_FOUND;
 | |
|     ASSERT (OpenInfoBuffer != NULL);
 | |
|     for (Index = 0; Index < EntryCount; Index++) {
 | |
|       if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
 | |
|         //
 | |
|         // Find the child terminal handle.
 | |
|         // Test whether the SimpleTxtIn and SimpleTxtOut have been published
 | |
|         //
 | |
|         Status = gBS->OpenProtocol (
 | |
|                         OpenInfoBuffer[Index].ControllerHandle,
 | |
|                         &gEfiSimpleTextInProtocolGuid,
 | |
|                         (VOID **) &SimpleTextInput,
 | |
|                         This->DriverBindingHandle,
 | |
|                         OpenInfoBuffer[Index].ControllerHandle,
 | |
|                         EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                         );
 | |
|         if (!EFI_ERROR (Status)) {
 | |
|           SimTxtInInstalled = TRUE;
 | |
|           TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);
 | |
|         }
 | |
| 
 | |
|         Status = gBS->OpenProtocol (
 | |
|                         OpenInfoBuffer[Index].ControllerHandle,
 | |
|                         &gEfiSimpleTextOutProtocolGuid,
 | |
|                         (VOID **) &SimpleTextOutput,
 | |
|                         This->DriverBindingHandle,
 | |
|                         OpenInfoBuffer[Index].ControllerHandle,
 | |
|                         EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                         );
 | |
|         if (!EFI_ERROR (Status)) {
 | |
|           SimTxtOutInstalled = TRUE;
 | |
|           TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
 | |
|         }
 | |
|         Status = EFI_SUCCESS;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     FreePool (OpenInfoBuffer);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ReportError;
 | |
|     }
 | |
|   } else {
 | |
|     goto ReportError;
 | |
|   }
 | |
| 
 | |
|   ASSERT (TerminalDevice != NULL);
 | |
|   //
 | |
|   // Only do the reset if the device path is in the Conout variable
 | |
|   //
 | |
|   if (ConInSelected && !SimTxtInInstalled) {
 | |
|     Status = TerminalDevice->SimpleInput.Reset (
 | |
|                                           &TerminalDevice->SimpleInput,
 | |
|                                           FALSE
 | |
|                                           );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Need to report Error Code first
 | |
|       //
 | |
|       goto ReportError;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Only output the configure string to remote terminal if the device path
 | |
|   // is in the Conout variable
 | |
|   //
 | |
|   if (ConOutSelected && !SimTxtOutInstalled) {
 | |
|     Status = TerminalDevice->SimpleTextOutput.SetAttribute (
 | |
|                                                         &TerminalDevice->SimpleTextOutput,
 | |
|                                                         EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
 | |
|                                                         );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ReportError;
 | |
|     }
 | |
| 
 | |
|     Status = TerminalDevice->SimpleTextOutput.Reset (
 | |
|                                                 &TerminalDevice->SimpleTextOutput,
 | |
|                                                 FALSE
 | |
|                                                 );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ReportError;
 | |
|     }
 | |
| 
 | |
|     Status = TerminalDevice->SimpleTextOutput.SetMode (
 | |
|                                                 &TerminalDevice->SimpleTextOutput,
 | |
|                                                 0
 | |
|                                                 );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ReportError;
 | |
|     }
 | |
| 
 | |
|     Status = TerminalDevice->SimpleTextOutput.EnableCursor (
 | |
|                                                 &TerminalDevice->SimpleTextOutput,
 | |
|                                                 TRUE
 | |
|                                                 );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ReportError;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Simple In/Out Protocol will not be installed onto the handle if the
 | |
|   // device path to the handle is not present in the ConIn/ConOut
 | |
|   // environment variable. But If RemainingDevicePath is NULL, then always
 | |
|   // produce both Simple In and Simple Text Output Protocols. This is required
 | |
|   // for the connect all sequences to make sure all possible consoles are
 | |
|   // produced no matter what the current values of ConIn, ConOut, or StdErr are.
 | |
|   //
 | |
|   if (!SimTxtInInstalled && (ConInSelected || NullRemaining)) {
 | |
|     Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                     &TerminalDevice->Handle,
 | |
|                     &gEfiSimpleTextInProtocolGuid,
 | |
|                     &TerminalDevice->SimpleInput,
 | |
|                     &gEfiSimpleTextInputExProtocolGuid,
 | |
|                     &TerminalDevice->SimpleInputEx,
 | |
|                     NULL
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Error;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!SimTxtOutInstalled && (ConOutSelected || NullRemaining)) {
 | |
|     Status = gBS->InstallProtocolInterface (
 | |
|                     &TerminalDevice->Handle,
 | |
|                     &gEfiSimpleTextOutProtocolGuid,
 | |
|                     EFI_NATIVE_INTERFACE,
 | |
|                     &TerminalDevice->SimpleTextOutput
 | |
|                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Error;
 | |
|     }
 | |
|   }
 | |
|   if (DefaultNode != NULL) {
 | |
|     FreePool (DefaultNode);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| ReportError:
 | |
|   //
 | |
|   // Report error code before exiting
 | |
|   //
 | |
|   DevicePath = ParentDevicePath;
 | |
|   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|     EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | |
|     (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
 | |
|     DevicePath
 | |
|     );
 | |
| 
 | |
| Error:
 | |
|   //
 | |
|   // Use the Stop() function to free all resources allocated in Start()
 | |
|   //
 | |
|   if (TerminalDevice != NULL) {
 | |
| 
 | |
|     if (TerminalDevice->Handle != NULL) {
 | |
|       This->Stop (This, Controller, 1, &TerminalDevice->Handle);
 | |
|     } else {
 | |
| 
 | |
|       if (TerminalDevice->TwoSecondTimeOut != NULL) {
 | |
|         gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
 | |
|       }
 | |
| 
 | |
|       if (TerminalDevice->TimerEvent != NULL) {
 | |
|         gBS->CloseEvent (TerminalDevice->TimerEvent);
 | |
|       }
 | |
| 
 | |
|       if (TerminalDevice->SimpleInput.WaitForKey != NULL) {
 | |
|         gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
 | |
|       }
 | |
| 
 | |
|       if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {
 | |
|         gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
 | |
|       }
 | |
| 
 | |
|       TerminalFreeNotifyList (&TerminalDevice->NotifyList);
 | |
| 
 | |
|       if (TerminalDevice->RawFiFo != NULL) {
 | |
|         FreePool (TerminalDevice->RawFiFo);
 | |
|       }
 | |
|       if (TerminalDevice->UnicodeFiFo != NULL) {
 | |
|         FreePool (TerminalDevice->UnicodeFiFo);
 | |
|       }
 | |
|       if (TerminalDevice->EfiKeyFiFo != NULL) {
 | |
|         FreePool (TerminalDevice->EfiKeyFiFo);
 | |
|       }
 | |
| 
 | |
|       if (TerminalDevice->ControllerNameTable != NULL) {
 | |
|         FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
 | |
|       }
 | |
| 
 | |
|       if (TerminalDevice->DevicePath != NULL) {
 | |
|         FreePool (TerminalDevice->DevicePath);
 | |
|       }
 | |
| 
 | |
|       if (TerminalDevice->TerminalConsoleModeData != NULL) {
 | |
|         FreePool (TerminalDevice->TerminalConsoleModeData);
 | |
|       }
 | |
| 
 | |
|       FreePool (TerminalDevice);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (DefaultNode != NULL) {
 | |
|     FreePool (DefaultNode);
 | |
|   }
 | |
| 
 | |
|   This->Stop (This, Controller, 0, NULL);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Stop this driver on Controller by closing Simple Text In, Simple Text
 | |
|   In Ex, Simple Text Out protocol, and removing parent device path from
 | |
|   Console Device Environment Variables.
 | |
| 
 | |
|   @param  This              Protocol instance pointer.
 | |
|   @param  Controller        Handle of device to stop driver on
 | |
|   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
 | |
|                             children is zero stop the entire bus driver.
 | |
|   @param  ChildHandleBuffer List of Child Handles to Stop.
 | |
| 
 | |
|   @retval EFI_SUCCESS       This driver is removed Controller.
 | |
|   @retval other             This driver could not be removed from this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| TerminalDriverBindingStop (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
 | |
|   IN  EFI_HANDLE                    Controller,
 | |
|   IN  UINTN                         NumberOfChildren,
 | |
|   IN  EFI_HANDLE                    *ChildHandleBuffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                       Status;
 | |
|   UINTN                            Index;
 | |
|   BOOLEAN                          AllChildrenStopped;
 | |
|   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *SimpleTextOutput;
 | |
|   TERMINAL_DEV                     *TerminalDevice;
 | |
|   EFI_DEVICE_PATH_PROTOCOL         *ParentDevicePath;
 | |
|   EFI_SERIAL_IO_PROTOCOL           *SerialIo;
 | |
|   EFI_DEVICE_PATH_PROTOCOL         *DevicePath;
 | |
| 
 | |
|   Status = gBS->HandleProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   (VOID **) &DevicePath
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Complete all outstanding transactions to Controller.
 | |
|   // Don't allow any new transaction to Controller to be started.
 | |
|   //
 | |
|   if (NumberOfChildren == 0) {
 | |
|     //
 | |
|     // Close the bus driver
 | |
|     //
 | |
|     Status = gBS->OpenProtocol (
 | |
|                     Controller,
 | |
|                     &gEfiCallerIdGuid,
 | |
|                     (VOID **) &ParentDevicePath,
 | |
|                     This->DriverBindingHandle,
 | |
|                     Controller,
 | |
|                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                     );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Remove Parent Device Path from
 | |
|       // the Console Device Environment Variables
 | |
|       //
 | |
|       TerminalRemoveConsoleDevVariable (L"ConInDev", ParentDevicePath);
 | |
|       TerminalRemoveConsoleDevVariable (L"ConOutDev", ParentDevicePath);
 | |
|       TerminalRemoveConsoleDevVariable (L"ErrOutDev", ParentDevicePath);
 | |
| 
 | |
|       //
 | |
|       // Uninstall the Terminal Driver's GUID Tag from the Serial controller
 | |
|       //
 | |
|       Status = gBS->UninstallMultipleProtocolInterfaces (
 | |
|                       Controller,
 | |
|                       &gEfiCallerIdGuid,
 | |
|                       ParentDevicePath,
 | |
|                       NULL
 | |
|                       );
 | |
| 
 | |
|       //
 | |
|       // Free the ParentDevicePath that was duplicated in Start()
 | |
|       //
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         FreePool (ParentDevicePath);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     gBS->CloseProtocol (
 | |
|           Controller,
 | |
|           &gEfiSerialIoProtocolGuid,
 | |
|           This->DriverBindingHandle,
 | |
|           Controller
 | |
|           );
 | |
| 
 | |
|     gBS->CloseProtocol (
 | |
|           Controller,
 | |
|           &gEfiDevicePathProtocolGuid,
 | |
|           This->DriverBindingHandle,
 | |
|           Controller
 | |
|           );
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   AllChildrenStopped = TRUE;
 | |
| 
 | |
|   for (Index = 0; Index < NumberOfChildren; Index++) {
 | |
| 
 | |
|     Status = gBS->OpenProtocol (
 | |
|                     ChildHandleBuffer[Index],
 | |
|                     &gEfiSimpleTextOutProtocolGuid,
 | |
|                     (VOID **) &SimpleTextOutput,
 | |
|                     This->DriverBindingHandle,
 | |
|                     ChildHandleBuffer[Index],
 | |
|                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                     );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
| 
 | |
|       TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (SimpleTextOutput);
 | |
| 
 | |
|       gBS->CloseProtocol (
 | |
|             Controller,
 | |
|             &gEfiSerialIoProtocolGuid,
 | |
|             This->DriverBindingHandle,
 | |
|             ChildHandleBuffer[Index]
 | |
|             );
 | |
| 
 | |
|       Status = gBS->UninstallMultipleProtocolInterfaces (
 | |
|                       ChildHandleBuffer[Index],
 | |
|                       &gEfiSimpleTextInProtocolGuid,
 | |
|                       &TerminalDevice->SimpleInput,
 | |
|                       &gEfiSimpleTextInputExProtocolGuid,
 | |
|                       &TerminalDevice->SimpleInputEx,
 | |
|                       &gEfiSimpleTextOutProtocolGuid,
 | |
|                       &TerminalDevice->SimpleTextOutput,
 | |
|                       &gEfiDevicePathProtocolGuid,
 | |
|                       TerminalDevice->DevicePath,
 | |
|                       NULL
 | |
|                       );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         gBS->OpenProtocol (
 | |
|               Controller,
 | |
|               &gEfiSerialIoProtocolGuid,
 | |
|               (VOID **) &SerialIo,
 | |
|               This->DriverBindingHandle,
 | |
|               ChildHandleBuffer[Index],
 | |
|               EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | |
|               );
 | |
|       } else {
 | |
| 
 | |
|         if (TerminalDevice->ControllerNameTable != NULL) {
 | |
|           FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
 | |
|         }
 | |
| 
 | |
|         gBS->CloseEvent (TerminalDevice->TimerEvent);
 | |
|         gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
 | |
|         gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
 | |
|         gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
 | |
|         TerminalFreeNotifyList (&TerminalDevice->NotifyList);
 | |
|         FreePool (TerminalDevice->DevicePath);
 | |
|         if (TerminalDevice->TerminalConsoleModeData != NULL) {
 | |
|           FreePool (TerminalDevice->TerminalConsoleModeData);
 | |
|         }
 | |
|         FreePool (TerminalDevice);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       AllChildrenStopped = FALSE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!AllChildrenStopped) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Update terminal device path in Console Device Environment Variables.
 | |
| 
 | |
|   @param  VariableName           The Console Device Environment Variable.
 | |
|   @param  ParentDevicePath       The terminal device path to be updated.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| TerminalUpdateConsoleDevVariable (
 | |
|   IN CHAR16                    *VariableName,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                Status;
 | |
|   UINTN                     NameSize;
 | |
|   UINTN                     VariableSize;
 | |
|   UINT8                     TerminalType;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *Variable;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *NewVariable;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
 | |
|   EDKII_SET_VARIABLE_STATUS *SetVariableStatus;
 | |
| 
 | |
|   //
 | |
|   // Get global variable and its size according to the name given.
 | |
|   //
 | |
|   GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
 | |
|   if (Variable == NULL) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Append terminal device path onto the variable.
 | |
|   //
 | |
|   for (TerminalType = PCANSITYPE; TerminalType <= VTUTF8TYPE; TerminalType++) {
 | |
|     SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
 | |
|     NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);
 | |
|     ASSERT (NewVariable != NULL);
 | |
|     if (Variable != NULL) {
 | |
|       FreePool (Variable);
 | |
|     }
 | |
| 
 | |
|     if (TempDevicePath != NULL) {
 | |
|       FreePool (TempDevicePath);
 | |
|     }
 | |
| 
 | |
|     Variable = NewVariable;
 | |
|   }
 | |
| 
 | |
|   VariableSize = GetDevicePathSize (Variable);
 | |
| 
 | |
|   Status = gRT->SetVariable (
 | |
|                   VariableName,
 | |
|                   &gEfiGlobalVariableGuid,
 | |
|                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|                   VariableSize,
 | |
|                   Variable
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     NameSize = StrSize (VariableName);
 | |
|     SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize);
 | |
|     if (SetVariableStatus != NULL) {
 | |
|       CopyGuid (&SetVariableStatus->Guid, &gEfiGlobalVariableGuid);
 | |
|       SetVariableStatus->NameSize   = NameSize;
 | |
|       SetVariableStatus->DataSize   = VariableSize;
 | |
|       SetVariableStatus->SetStatus  = Status;
 | |
|       SetVariableStatus->Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
 | |
|       CopyMem (SetVariableStatus + 1,                          VariableName, NameSize);
 | |
|       CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Variable,     VariableSize);
 | |
| 
 | |
|       REPORT_STATUS_CODE_EX (
 | |
|         EFI_ERROR_CODE,
 | |
|         PcdGet32 (PcdErrorCodeSetVariable),
 | |
|         0,
 | |
|         NULL,
 | |
|         &gEdkiiStatusCodeDataTypeVariableGuid,
 | |
|         SetVariableStatus,
 | |
|         sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + VariableSize
 | |
|         );
 | |
| 
 | |
|       FreePool (SetVariableStatus);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   FreePool (Variable);
 | |
| 
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Remove terminal device path from Console Device Environment Variables.
 | |
| 
 | |
|   @param  VariableName           Console Device Environment Variables.
 | |
|   @param  ParentDevicePath       The terminal device path to be updated.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| TerminalRemoveConsoleDevVariable (
 | |
|   IN CHAR16                    *VariableName,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                Status;
 | |
|   BOOLEAN                   FoundOne;
 | |
|   BOOLEAN                   Match;
 | |
|   UINTN                     VariableSize;
 | |
|   UINTN                     InstanceSize;
 | |
|   UINT8                     TerminalType;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *Instance;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *Variable;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *OriginalVariable;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *NewVariable;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *SavedNewVariable;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
 | |
| 
 | |
|   Instance  = NULL;
 | |
| 
 | |
|   //
 | |
|   // Get global variable and its size according to the name given.
 | |
|   //
 | |
|   GetEfiGlobalVariable2 (VariableName, (VOID**)&Variable, NULL);
 | |
|   if (Variable == NULL) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   FoundOne          = FALSE;
 | |
|   OriginalVariable  = Variable;
 | |
|   NewVariable       = NULL;
 | |
| 
 | |
|   //
 | |
|   // Get first device path instance from Variable
 | |
|   //
 | |
|   Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
 | |
|   if (Instance == NULL) {
 | |
|     FreePool (OriginalVariable);
 | |
|     return ;
 | |
|   }
 | |
|   //
 | |
|   // Loop through all the device path instances of Variable
 | |
|   //
 | |
|   do {
 | |
|     //
 | |
|     // Loop through all the terminal types that this driver supports
 | |
|     //
 | |
|     Match = FALSE;
 | |
|     for (TerminalType = PCANSITYPE; TerminalType <= VTUTF8TYPE; TerminalType++) {
 | |
| 
 | |
|       SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
 | |
| 
 | |
|       //
 | |
|       // Compare the generated device path to the current device path instance
 | |
|       //
 | |
|       if (TempDevicePath != NULL) {
 | |
|         if (CompareMem (Instance, TempDevicePath, InstanceSize) == 0) {
 | |
|           Match     = TRUE;
 | |
|           FoundOne  = TRUE;
 | |
|         }
 | |
| 
 | |
|         FreePool (TempDevicePath);
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // If a match was not found, then keep the current device path instance
 | |
|     //
 | |
|     if (!Match) {
 | |
|       SavedNewVariable  = NewVariable;
 | |
|       NewVariable       = AppendDevicePathInstance (NewVariable, Instance);
 | |
|       if (SavedNewVariable != NULL) {
 | |
|         FreePool (SavedNewVariable);
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // Get next device path instance from Variable
 | |
|     //
 | |
|     FreePool (Instance);
 | |
|     Instance = GetNextDevicePathInstance (&Variable, &InstanceSize);
 | |
|   } while (Instance != NULL);
 | |
| 
 | |
|   FreePool (OriginalVariable);
 | |
| 
 | |
|   if (FoundOne) {
 | |
|     VariableSize = GetDevicePathSize (NewVariable);
 | |
| 
 | |
|     Status = gRT->SetVariable (
 | |
|                     VariableName,
 | |
|                     &gEfiGlobalVariableGuid,
 | |
|                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|                     VariableSize,
 | |
|                     NewVariable
 | |
|                     );
 | |
|     //
 | |
|     // Shrinking variable with existing variable driver implementation shouldn't fail.
 | |
|     //
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
|   }
 | |
| 
 | |
|   if (NewVariable != NULL) {
 | |
|     FreePool (NewVariable);
 | |
|   }
 | |
| 
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Build terminal device path according to terminal type.
 | |
| 
 | |
|   @param  TerminalType           The terminal type is PC ANSI, VT100, VT100+ or VT-UTF8.
 | |
|   @param  ParentDevicePath       Parent device path.
 | |
|   @param  TerminalDevicePath     Returned terminal device path, if building successfully.
 | |
| 
 | |
|   @retval EFI_UNSUPPORTED        Terminal does not belong to the supported type.
 | |
|   @retval EFI_OUT_OF_RESOURCES   Generate terminal device path failed.
 | |
|   @retval EFI_SUCCESS            Build terminal device path successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SetTerminalDevicePath (
 | |
|   IN  UINT8                       TerminalType,
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL    *ParentDevicePath,
 | |
|   OUT EFI_DEVICE_PATH_PROTOCOL    **TerminalDevicePath
 | |
|   )
 | |
| {
 | |
|   VENDOR_DEVICE_PATH  Node;
 | |
| 
 | |
|   *TerminalDevicePath = NULL;
 | |
|   Node.Header.Type    = MESSAGING_DEVICE_PATH;
 | |
|   Node.Header.SubType = MSG_VENDOR_DP;
 | |
| 
 | |
|   //
 | |
|   // Generate terminal device path node according to terminal type.
 | |
|   //
 | |
|   switch (TerminalType) {
 | |
| 
 | |
|   case PCANSITYPE:
 | |
|     CopyGuid (&Node.Guid, &gEfiPcAnsiGuid);
 | |
|     break;
 | |
| 
 | |
|   case VT100TYPE:
 | |
|     CopyGuid (&Node.Guid, &gEfiVT100Guid);
 | |
|     break;
 | |
| 
 | |
|   case VT100PLUSTYPE:
 | |
|     CopyGuid (&Node.Guid, &gEfiVT100PlusGuid);
 | |
|     break;
 | |
| 
 | |
|   case VTUTF8TYPE:
 | |
|     CopyGuid (&Node.Guid, &gEfiVTUTF8Guid);
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get VENDOR_DEVCIE_PATH size and put into Node.Header
 | |
|   //
 | |
|   SetDevicePathNodeLength (
 | |
|     &Node.Header,
 | |
|     sizeof (VENDOR_DEVICE_PATH)
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Append the terminal node onto parent device path
 | |
|   // to generate a complete terminal device path.
 | |
|   //
 | |
|   *TerminalDevicePath = AppendDevicePathNode (
 | |
|                           ParentDevicePath,
 | |
|                           (EFI_DEVICE_PATH_PROTOCOL *) &Node
 | |
|                           );
 | |
|   if (*TerminalDevicePath == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The user Entry Point for module Terminal. The user code starts with this function.
 | |
| 
 | |
|   @param  ImageHandle    The firmware allocated handle for the EFI image.
 | |
|   @param  SystemTable    A pointer to the EFI System Table.
 | |
| 
 | |
|   @retval EFI_SUCCESS       The entry point is executed successfully.
 | |
|   @retval other             Some error occurs when executing this entry point.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| InitializeTerminal(
 | |
|   IN EFI_HANDLE           ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE     *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
| 
 | |
|   //
 | |
|   // Install driver model protocol(s).
 | |
|   //
 | |
|   Status = EfiLibInstallDriverBindingComponentName2 (
 | |
|              ImageHandle,
 | |
|              SystemTable,
 | |
|              &gTerminalDriverBinding,
 | |
|              ImageHandle,
 | |
|              &gTerminalComponentName,
 | |
|              &gTerminalComponentName2
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check if the device supports hot-plug through its device path.
 | |
| 
 | |
|   This function could be updated to check more types of Hot Plug devices.
 | |
|   Currently, it checks USB and PCCard device.
 | |
| 
 | |
|   @param  DevicePath            Pointer to device's device path.
 | |
| 
 | |
|   @retval TRUE                  The devcie is a hot-plug device
 | |
|   @retval FALSE                 The devcie is not a hot-plug device.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| IsHotPlugDevice (
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_DEVICE_PATH_PROTOCOL     *CheckDevicePath;
 | |
| 
 | |
|   CheckDevicePath = DevicePath;
 | |
|   while (!IsDevicePathEnd (CheckDevicePath)) {
 | |
|     //
 | |
|     // Check device whether is hot plug device or not throught Device Path
 | |
|     //
 | |
|     if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&
 | |
|         (DevicePathSubType (CheckDevicePath) == MSG_USB_DP ||
 | |
|          DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP ||
 | |
|          DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) {
 | |
|       //
 | |
|       // If Device is USB device
 | |
|       //
 | |
|       return TRUE;
 | |
|     }
 | |
|     if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&
 | |
|         (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) {
 | |
|       //
 | |
|       // If Device is PCCard
 | |
|       //
 | |
|       return TRUE;
 | |
|     }
 | |
| 
 | |
|     CheckDevicePath = NextDevicePathNode (CheckDevicePath);
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 |