REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the MdeModulePkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
		
			
				
	
	
		
			1412 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1412 lines
		
	
	
		
			42 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 - 2019, Intel Corporation. All rights reserved.<BR>
 | 
						|
SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "Terminal.h"
 | 
						|
 | 
						|
//
 | 
						|
// Globals
 | 
						|
//
 | 
						|
EFI_DRIVER_BINDING_PROTOCOL  gTerminalDriverBinding = {
 | 
						|
  TerminalDriverBindingSupported,
 | 
						|
  TerminalDriverBindingStart,
 | 
						|
  TerminalDriverBindingStop,
 | 
						|
  0xa,
 | 
						|
  NULL,
 | 
						|
  NULL
 | 
						|
};
 | 
						|
 | 
						|
EFI_GUID  *mTerminalType[] = {
 | 
						|
  &gEfiPcAnsiGuid,
 | 
						|
  &gEfiVT100Guid,
 | 
						|
  &gEfiVT100PlusGuid,
 | 
						|
  &gEfiVTUTF8Guid,
 | 
						|
  &gEfiTtyTermGuid,
 | 
						|
  &gEdkiiLinuxTermGuid,
 | 
						|
  &gEdkiiXtermR6Guid,
 | 
						|
  &gEdkiiVT400Guid,
 | 
						|
  &gEdkiiSCOTermGuid
 | 
						|
};
 | 
						|
 | 
						|
CHAR16  *mSerialConsoleNames[] = {
 | 
						|
  L"PC-ANSI Serial Console",
 | 
						|
  L"VT-100 Serial Console",
 | 
						|
  L"VT-100+ Serial Console",
 | 
						|
  L"VT-UTF8 Serial Console",
 | 
						|
  L"Tty Terminal Serial Console",
 | 
						|
  L"Linux Terminal Serial Console",
 | 
						|
  L"Xterm R6 Serial Console",
 | 
						|
  L"VT-400 Serial Console",
 | 
						|
  L"SCO Terminal Serial Console"
 | 
						|
};
 | 
						|
 | 
						|
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, // EfiKeyFiFoForNotify
 | 
						|
 | 
						|
  NULL, // ControllerNameTable
 | 
						|
  NULL, // TimerEvent
 | 
						|
  NULL, // TwoSecondTimeOut
 | 
						|
  INPUT_STATE_DEFAULT,
 | 
						|
  RESET_STATE_DEFAULT,
 | 
						|
  {
 | 
						|
    0,
 | 
						|
    0,
 | 
						|
    0
 | 
						|
  },
 | 
						|
  0,
 | 
						|
  FALSE,
 | 
						|
  {   // SimpleTextInputEx
 | 
						|
    TerminalConInResetEx,
 | 
						|
    TerminalConInReadKeyStrokeEx,
 | 
						|
    NULL,
 | 
						|
    TerminalConInSetState,
 | 
						|
    TerminalConInRegisterKeyNotify,
 | 
						|
    TerminalConInUnregisterKeyNotify,
 | 
						|
  },
 | 
						|
  {   // NotifyList
 | 
						|
    NULL,
 | 
						|
    NULL,
 | 
						|
  },
 | 
						|
  NULL // KeyNotifyProcessEvent
 | 
						|
};
 | 
						|
 | 
						|
TERMINAL_CONSOLE_MODE_DATA  mTerminalConsoleModeData[] = {
 | 
						|
  { 80,  25 },
 | 
						|
  { 80,  50 },
 | 
						|
  { 100, 31 },
 | 
						|
  //
 | 
						|
  // New modes can be added here.
 | 
						|
  //
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Convert the GUID representation of terminal type to enum type.
 | 
						|
 | 
						|
  @param Guid  The GUID representation of terminal type.
 | 
						|
 | 
						|
  @return  The terminal type in enum type.
 | 
						|
**/
 | 
						|
TERMINAL_TYPE
 | 
						|
TerminalTypeFromGuid (
 | 
						|
  IN EFI_GUID  *Guid
 | 
						|
  )
 | 
						|
{
 | 
						|
  TERMINAL_TYPE  Type;
 | 
						|
 | 
						|
  for (Type = 0; Type < ARRAY_SIZE (mTerminalType); Type++) {
 | 
						|
    if (CompareGuid (Guid, mTerminalType[Type])) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Type;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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+, VT-UTF8, TtyTerm
 | 
						|
      // Linux, XtermR6, VT400 and SCO terminal types
 | 
						|
      //
 | 
						|
      if (TerminalTypeFromGuid (&Node->Guid) == ARRAY_SIZE (mTerminalType)) {
 | 
						|
        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;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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.
 | 
						|
 | 
						|
  @return   The buffer to the text modes column and row information.
 | 
						|
            Caller is responsible to free it when it's non-NULL.
 | 
						|
 | 
						|
**/
 | 
						|
TERMINAL_CONSOLE_MODE_DATA *
 | 
						|
InitializeTerminalConsoleTextMode (
 | 
						|
  OUT INT32  *TextModeCount
 | 
						|
  )
 | 
						|
{
 | 
						|
  TERMINAL_CONSOLE_MODE_DATA  *TextModeData;
 | 
						|
 | 
						|
  ASSERT (TextModeCount != NULL);
 | 
						|
 | 
						|
  TextModeData = AllocateCopyPool (sizeof (mTerminalConsoleModeData), mTerminalConsoleModeData);
 | 
						|
  if (TextModeData == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  *TextModeCount = ARRAY_SIZE (mTerminalConsoleModeData);
 | 
						|
 | 
						|
  DEBUG_CODE_BEGIN ();
 | 
						|
  INT32  Index;
 | 
						|
 | 
						|
  for (Index = 0; Index < *TextModeCount; Index++) {
 | 
						|
    DEBUG ((
 | 
						|
      DEBUG_INFO,
 | 
						|
      "Terminal - Mode %d, Column = %d, Row = %d\n",
 | 
						|
      Index,
 | 
						|
      TextModeData[Index].Columns,
 | 
						|
      TextModeData[Index].Rows
 | 
						|
      ));
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG_CODE_END ();
 | 
						|
  return TextModeData;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Stop the terminal state machine.
 | 
						|
 | 
						|
  @param TerminalDevice    The terminal device.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
StopTerminalStateMachine (
 | 
						|
  TERMINAL_DEV  *TerminalDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_TPL  OriginalTpl;
 | 
						|
 | 
						|
  OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY);
 | 
						|
 | 
						|
  gBS->CloseEvent (TerminalDevice->TimerEvent);
 | 
						|
  gBS->CloseEvent (TerminalDevice->TwoSecondTimeOut);
 | 
						|
 | 
						|
  gBS->RestoreTPL (OriginalTpl);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Start the terminal state machine.
 | 
						|
 | 
						|
  @param TerminalDevice    The terminal device.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
StartTerminalStateMachine (
 | 
						|
  TERMINAL_DEV  *TerminalDevice
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize the controller name table.
 | 
						|
 | 
						|
  @param TerminalType        The terminal type.
 | 
						|
  @param ControllerNameTable The controller name table.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS  The controller name table is initialized successfully.
 | 
						|
  @retval others       Return status of AddUnicodeString2 ().
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
InitializeControllerNameTable (
 | 
						|
  TERMINAL_TYPE             TerminalType,
 | 
						|
  EFI_UNICODE_STRING_TABLE  **ControllerNameTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_UNICODE_STRING_TABLE  *Table;
 | 
						|
 | 
						|
  ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));
 | 
						|
  Table  = NULL;
 | 
						|
  Status = AddUnicodeString2 (
 | 
						|
             "eng",
 | 
						|
             gTerminalComponentName.SupportedLanguages,
 | 
						|
             &Table,
 | 
						|
             mSerialConsoleNames[TerminalType],
 | 
						|
             TRUE
 | 
						|
             );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    Status = AddUnicodeString2 (
 | 
						|
               "en",
 | 
						|
               gTerminalComponentName2.SupportedLanguages,
 | 
						|
               &Table,
 | 
						|
               mSerialConsoleNames[TerminalType],
 | 
						|
               FALSE
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      FreeUnicodeStringTable (Table);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    *ControllerNameTable = Table;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL             *Vendor;
 | 
						|
  EFI_HANDLE                           SerialIoHandle;
 | 
						|
  EFI_SERIAL_IO_MODE                   *Mode;
 | 
						|
  UINTN                                SerialInTimeOut;
 | 
						|
  TERMINAL_DEV                         *TerminalDevice;
 | 
						|
  UINT8                                TerminalType;
 | 
						|
  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfoBuffer;
 | 
						|
  UINTN                                EntryCount;
 | 
						|
  UINTN                                Index;
 | 
						|
  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL      *SimpleTextOutput;
 | 
						|
  EFI_SIMPLE_TEXT_INPUT_PROTOCOL       *SimpleTextInput;
 | 
						|
  EFI_UNICODE_STRING_TABLE             *ControllerNameTable;
 | 
						|
 | 
						|
  //
 | 
						|
  // 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
 | 
						|
                  );
 | 
						|
  ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));
 | 
						|
  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
 | 
						|
                  );
 | 
						|
  ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_ALREADY_STARTED));
 | 
						|
  if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!IsHotPlugDevice (ParentDevicePath)) {
 | 
						|
    //
 | 
						|
    // if the serial device is a hot plug device, do not update the
 | 
						|
    // ConInDev, ConOutDev, and StdErrDev variables.
 | 
						|
    //
 | 
						|
    TerminalUpdateConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);
 | 
						|
    TerminalUpdateConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
 | 
						|
    TerminalUpdateConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Do not create any child for END remaining device path.
 | 
						|
  //
 | 
						|
  if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Status == EFI_ALREADY_STARTED) {
 | 
						|
    if (RemainingDevicePath == NULL) {
 | 
						|
      //
 | 
						|
      // If RemainingDevicePath is NULL or is the End of Device Path Node
 | 
						|
      //
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // This driver can only produce one child per serial port.
 | 
						|
    // Change its terminal type as remaining device path requests.
 | 
						|
    //
 | 
						|
    Status = gBS->OpenProtocolInformation (
 | 
						|
                    Controller,
 | 
						|
                    &gEfiSerialIoProtocolGuid,
 | 
						|
                    &OpenInfoBuffer,
 | 
						|
                    &EntryCount
 | 
						|
                    );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      Status = EFI_NOT_FOUND;
 | 
						|
      for (Index = 0; Index < EntryCount; Index++) {
 | 
						|
        if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
 | 
						|
          Status = gBS->OpenProtocol (
 | 
						|
                          OpenInfoBuffer[Index].ControllerHandle,
 | 
						|
                          &gEfiSimpleTextInProtocolGuid,
 | 
						|
                          (VOID **)&SimpleTextInput,
 | 
						|
                          This->DriverBindingHandle,
 | 
						|
                          Controller,
 | 
						|
                          EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                          );
 | 
						|
          if (!EFI_ERROR (Status)) {
 | 
						|
            TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (SimpleTextInput);
 | 
						|
            TerminalType   = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *)RemainingDevicePath)->Guid);
 | 
						|
            ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));
 | 
						|
            if (TerminalDevice->TerminalType != TerminalType) {
 | 
						|
              Status = InitializeControllerNameTable (TerminalType, &ControllerNameTable);
 | 
						|
              if (!EFI_ERROR (Status)) {
 | 
						|
                StopTerminalStateMachine (TerminalDevice);
 | 
						|
                //
 | 
						|
                // Update the device path
 | 
						|
                //
 | 
						|
                Vendor = TerminalDevice->DevicePath;
 | 
						|
                Status = gBS->LocateDevicePath (&gEfiSerialIoProtocolGuid, &Vendor, &SerialIoHandle);
 | 
						|
                ASSERT_EFI_ERROR (Status);
 | 
						|
                CopyGuid (&((VENDOR_DEVICE_PATH *)Vendor)->Guid, mTerminalType[TerminalType]);
 | 
						|
                Status = gBS->ReinstallProtocolInterface (
 | 
						|
                                TerminalDevice->Handle,
 | 
						|
                                &gEfiDevicePathProtocolGuid,
 | 
						|
                                TerminalDevice->DevicePath,
 | 
						|
                                TerminalDevice->DevicePath
 | 
						|
                                );
 | 
						|
                if (!EFI_ERROR (Status)) {
 | 
						|
                  TerminalDevice->TerminalType = TerminalType;
 | 
						|
                  StartTerminalStateMachine (TerminalDevice);
 | 
						|
                  FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
 | 
						|
                  TerminalDevice->ControllerNameTable = ControllerNameTable;
 | 
						|
                } else {
 | 
						|
                  //
 | 
						|
                  // Restore the device path on failure
 | 
						|
                  //
 | 
						|
                  CopyGuid (&((VENDOR_DEVICE_PATH *)Vendor)->Guid, mTerminalType[TerminalDevice->TerminalType]);
 | 
						|
                  FreeUnicodeStringTable (ControllerNameTable);
 | 
						|
                }
 | 
						|
              }
 | 
						|
            }
 | 
						|
          }
 | 
						|
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      FreePool (OpenInfoBuffer);
 | 
						|
    }
 | 
						|
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the Terminal Dev
 | 
						|
  //
 | 
						|
  TerminalDevice = AllocateCopyPool (sizeof (TERMINAL_DEV), &mTerminalDevTemplate);
 | 
						|
  if (TerminalDevice == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto CloseProtocols;
 | 
						|
  }
 | 
						|
 | 
						|
  if (RemainingDevicePath == NULL) {
 | 
						|
    //
 | 
						|
    // If RemainingDevicePath is NULL, use default terminal type
 | 
						|
    //
 | 
						|
    TerminalDevice->TerminalType = PcdGet8 (PcdDefaultTerminalType);
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // End of Device Path Node is handled in above.
 | 
						|
    //
 | 
						|
    ASSERT (!IsDevicePathEnd (RemainingDevicePath));
 | 
						|
    //
 | 
						|
    // If RemainingDevicePath isn't the End of Device Path Node,
 | 
						|
    // Use the RemainingDevicePath to determine the terminal type
 | 
						|
    //
 | 
						|
    TerminalDevice->TerminalType = TerminalTypeFromGuid (&((VENDOR_DEVICE_PATH *)RemainingDevicePath)->Guid);
 | 
						|
  }
 | 
						|
 | 
						|
  ASSERT (TerminalDevice->TerminalType < ARRAY_SIZE (mTerminalType));
 | 
						|
  TerminalDevice->SerialIo = SerialIo;
 | 
						|
 | 
						|
  //
 | 
						|
  // Build the component name for the child device
 | 
						|
  //
 | 
						|
  Status = InitializeControllerNameTable (TerminalDevice->TerminalType, &TerminalDevice->ControllerNameTable);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto FreeResources;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Build the device path for the child device
 | 
						|
  //
 | 
						|
  Status = SetTerminalDevicePath (TerminalDevice->TerminalType, ParentDevicePath, &TerminalDevice->DevicePath);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto FreeResources;
 | 
						|
  }
 | 
						|
 | 
						|
  InitializeListHead (&TerminalDevice->NotifyList);
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EVT_NOTIFY_WAIT,
 | 
						|
                  TPL_NOTIFY,
 | 
						|
                  TerminalConInWaitForKeyEx,
 | 
						|
                  TerminalDevice,
 | 
						|
                  &TerminalDevice->SimpleInputEx.WaitForKeyEx
 | 
						|
                  );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EVT_NOTIFY_WAIT,
 | 
						|
                  TPL_NOTIFY,
 | 
						|
                  TerminalConInWaitForKey,
 | 
						|
                  TerminalDevice,
 | 
						|
                  &TerminalDevice->SimpleInput.WaitForKey
 | 
						|
                  );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EVT_NOTIFY_SIGNAL,
 | 
						|
                  TPL_CALLBACK,
 | 
						|
                  KeyNotifyProcessHandler,
 | 
						|
                  TerminalDevice,
 | 
						|
                  &TerminalDevice->KeyNotifyProcessEvent
 | 
						|
                  );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  //
 | 
						|
  // 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 FreeResources;
 | 
						|
  }
 | 
						|
 | 
						|
  TerminalDevice->UnicodeFiFo = AllocateZeroPool (sizeof (UNICODE_FIFO));
 | 
						|
  if (TerminalDevice->UnicodeFiFo == NULL) {
 | 
						|
    goto FreeResources;
 | 
						|
  }
 | 
						|
 | 
						|
  TerminalDevice->EfiKeyFiFo = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
 | 
						|
  if (TerminalDevice->EfiKeyFiFo == NULL) {
 | 
						|
    goto FreeResources;
 | 
						|
  }
 | 
						|
 | 
						|
  TerminalDevice->EfiKeyFiFoForNotify = AllocateZeroPool (sizeof (EFI_KEY_FIFO));
 | 
						|
  if (TerminalDevice->EfiKeyFiFoForNotify == NULL) {
 | 
						|
    goto FreeResources;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 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;
 | 
						|
  }
 | 
						|
 | 
						|
  SimpleTextOutput = &TerminalDevice->SimpleTextOutput;
 | 
						|
  SimpleTextInput  = &TerminalDevice->SimpleInput;
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize SimpleTextOut instance
 | 
						|
  //
 | 
						|
  SimpleTextOutput->Mode                  = &TerminalDevice->SimpleTextOutputMode;
 | 
						|
  TerminalDevice->TerminalConsoleModeData = InitializeTerminalConsoleTextMode (
 | 
						|
                                              &SimpleTextOutput->Mode->MaxMode
 | 
						|
                                              );
 | 
						|
  if (TerminalDevice->TerminalConsoleModeData == NULL) {
 | 
						|
    goto FreeResources;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // For terminal devices, cursor is always visible
 | 
						|
  //
 | 
						|
  SimpleTextOutput->Mode->CursorVisible = TRUE;
 | 
						|
  Status                                = SimpleTextOutput->SetAttribute (SimpleTextOutput, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    Status = SimpleTextOutput->Reset (SimpleTextOutput, FALSE);
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ReportError;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize SimpleTextInput instance
 | 
						|
  //
 | 
						|
  Status = SimpleTextInput->Reset (SimpleTextInput, FALSE);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ReportError;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                  &TerminalDevice->Handle,
 | 
						|
                  &gEfiSimpleTextInProtocolGuid,
 | 
						|
                  &TerminalDevice->SimpleInput,
 | 
						|
                  &gEfiSimpleTextInputExProtocolGuid,
 | 
						|
                  &TerminalDevice->SimpleInputEx,
 | 
						|
                  &gEfiSimpleTextOutProtocolGuid,
 | 
						|
                  &TerminalDevice->SimpleTextOutput,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  TerminalDevice->DevicePath,
 | 
						|
                  NULL
 | 
						|
                  );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    Status = gBS->OpenProtocol (
 | 
						|
                    Controller,
 | 
						|
                    &gEfiSerialIoProtocolGuid,
 | 
						|
                    (VOID **)&TerminalDevice->SerialIo,
 | 
						|
                    This->DriverBindingHandle,
 | 
						|
                    TerminalDevice->Handle,
 | 
						|
                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | 
						|
                    );
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
    StartTerminalStateMachine (TerminalDevice);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
ReportError:
 | 
						|
  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
    EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | 
						|
    (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
 | 
						|
    ParentDevicePath
 | 
						|
    );
 | 
						|
 | 
						|
FreeResources:
 | 
						|
  ASSERT (TerminalDevice != NULL);
 | 
						|
 | 
						|
  if (TerminalDevice->SimpleInput.WaitForKey != NULL) {
 | 
						|
    gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
 | 
						|
  }
 | 
						|
 | 
						|
  if (TerminalDevice->SimpleInputEx.WaitForKeyEx != NULL) {
 | 
						|
    gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
 | 
						|
  }
 | 
						|
 | 
						|
  if (TerminalDevice->KeyNotifyProcessEvent != NULL) {
 | 
						|
    gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);
 | 
						|
  }
 | 
						|
 | 
						|
  if (TerminalDevice->RawFiFo != NULL) {
 | 
						|
    FreePool (TerminalDevice->RawFiFo);
 | 
						|
  }
 | 
						|
 | 
						|
  if (TerminalDevice->UnicodeFiFo != NULL) {
 | 
						|
    FreePool (TerminalDevice->UnicodeFiFo);
 | 
						|
  }
 | 
						|
 | 
						|
  if (TerminalDevice->EfiKeyFiFo != NULL) {
 | 
						|
    FreePool (TerminalDevice->EfiKeyFiFo);
 | 
						|
  }
 | 
						|
 | 
						|
  if (TerminalDevice->EfiKeyFiFoForNotify != NULL) {
 | 
						|
    FreePool (TerminalDevice->EfiKeyFiFoForNotify);
 | 
						|
  }
 | 
						|
 | 
						|
  if (TerminalDevice->ControllerNameTable != NULL) {
 | 
						|
    FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
 | 
						|
  }
 | 
						|
 | 
						|
  if (TerminalDevice->DevicePath != NULL) {
 | 
						|
    FreePool (TerminalDevice->DevicePath);
 | 
						|
  }
 | 
						|
 | 
						|
  if (TerminalDevice->TerminalConsoleModeData != NULL) {
 | 
						|
    FreePool (TerminalDevice->TerminalConsoleModeData);
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (TerminalDevice);
 | 
						|
 | 
						|
CloseProtocols:
 | 
						|
 | 
						|
  //
 | 
						|
  // Remove Parent Device Path from
 | 
						|
  // the Console Device Environment Variables
 | 
						|
  //
 | 
						|
  TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);
 | 
						|
  TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
 | 
						|
  TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
 | 
						|
 | 
						|
  Status = gBS->CloseProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiSerialIoProtocolGuid,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller
 | 
						|
                  );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  Status = gBS->CloseProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller
 | 
						|
                  );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  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;
 | 
						|
 | 
						|
  //
 | 
						|
  // 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,
 | 
						|
                    &gEfiDevicePathProtocolGuid,
 | 
						|
                    (VOID **)&ParentDevicePath,
 | 
						|
                    This->DriverBindingHandle,
 | 
						|
                    Controller,
 | 
						|
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                    );
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
    //
 | 
						|
    // Remove Parent Device Path from
 | 
						|
    // the Console Device Environment Variables
 | 
						|
    //
 | 
						|
    TerminalRemoveConsoleDevVariable (EFI_CON_IN_DEV_VARIABLE_NAME, ParentDevicePath);
 | 
						|
    TerminalRemoveConsoleDevVariable (EFI_CON_OUT_DEV_VARIABLE_NAME, ParentDevicePath);
 | 
						|
    TerminalRemoveConsoleDevVariable (EFI_ERR_OUT_DEV_VARIABLE_NAME, 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 {
 | 
						|
        FreeUnicodeStringTable (TerminalDevice->ControllerNameTable);
 | 
						|
        StopTerminalStateMachine (TerminalDevice);
 | 
						|
        gBS->CloseEvent (TerminalDevice->SimpleInput.WaitForKey);
 | 
						|
        gBS->CloseEvent (TerminalDevice->SimpleInputEx.WaitForKeyEx);
 | 
						|
        gBS->CloseEvent (TerminalDevice->KeyNotifyProcessEvent);
 | 
						|
        TerminalFreeNotifyList (&TerminalDevice->NotifyList);
 | 
						|
        FreePool (TerminalDevice->DevicePath);
 | 
						|
        FreePool (TerminalDevice->TerminalConsoleModeData);
 | 
						|
        FreePool (TerminalDevice);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      AllChildrenStopped = FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!AllChildrenStopped) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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;
 | 
						|
  TERMINAL_TYPE              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.
 | 
						|
  //
 | 
						|
  Status = GetEfiGlobalVariable2 (VariableName, (VOID **)&Variable, NULL);
 | 
						|
  if (Status == EFI_NOT_FOUND) {
 | 
						|
    Status   = EFI_SUCCESS;
 | 
						|
    Variable = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Append terminal device path onto the variable.
 | 
						|
  //
 | 
						|
  for (TerminalType = 0; TerminalType < ARRAY_SIZE (mTerminalType); TerminalType++) {
 | 
						|
    SetTerminalDevicePath (TerminalType, ParentDevicePath, &TempDevicePath);
 | 
						|
 | 
						|
    if (TempDevicePath != NULL) {
 | 
						|
      if (!MatchDevicePaths (Variable, TempDevicePath)) {
 | 
						|
        NewVariable = AppendDevicePathInstance (Variable, TempDevicePath);
 | 
						|
        if (NewVariable != NULL) {
 | 
						|
          if (Variable != NULL) {
 | 
						|
            FreePool (Variable);
 | 
						|
          }
 | 
						|
 | 
						|
          Variable = NewVariable;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      FreePool (TempDevicePath);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  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;
 | 
						|
  TERMINAL_TYPE             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 = 0; TerminalType < ARRAY_SIZE (mTerminalType); 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  TERMINAL_TYPE             TerminalType,
 | 
						|
  IN  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath,
 | 
						|
  OUT EFI_DEVICE_PATH_PROTOCOL  **TerminalDevicePath
 | 
						|
  )
 | 
						|
{
 | 
						|
  VENDOR_DEVICE_PATH  Node;
 | 
						|
 | 
						|
  ASSERT (TerminalType < ARRAY_SIZE (mTerminalType));
 | 
						|
  Node.Header.Type    = MESSAGING_DEVICE_PATH;
 | 
						|
  Node.Header.SubType = MSG_VENDOR_DP;
 | 
						|
  SetDevicePathNodeLength (&Node.Header, sizeof (VENDOR_DEVICE_PATH));
 | 
						|
  CopyGuid (&Node.Guid, mTerminalType[TerminalType]);
 | 
						|
 | 
						|
  //
 | 
						|
  // 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;
 | 
						|
}
 |