]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / Console / TerminalDxe / TerminalConIn.c
index 662cd5682f74cb038a9c677b478b3e14fb974ca9..4ede41677493da9c72af5a37ac8cb175cb3b4567 100644 (file)
-/** @file
-  Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol.
-
-Copyright (c) 2006 - 2011, 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"
-
-
-/**
-  Reads the next keystroke from the input device. The WaitForKey Event can
-  be used to test for existence of a keystroke via WaitForEvent () call.
-
-  @param  TerminalDevice           Terminal driver private structure
-  @param  KeyData                  A pointer to a buffer that is filled in with the
-                                   keystroke state data for the key that was
-                                   pressed.
-
-  @retval EFI_SUCCESS              The keystroke information was returned.
-  @retval EFI_NOT_READY            There was no keystroke data available.
-  @retval EFI_INVALID_PARAMETER    KeyData is NULL.
-
-**/
-EFI_STATUS
-ReadKeyStrokeWorker (
-  IN  TERMINAL_DEV *TerminalDevice,
-  OUT EFI_KEY_DATA *KeyData
-  )
-{
-  if (KeyData == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (!EfiKeyFiFoRemoveOneKey (TerminalDevice, &KeyData->Key)) {
-    return EFI_NOT_READY;
-  }
-
-  KeyData->KeyState.KeyShiftState  = 0;
-  KeyData->KeyState.KeyToggleState = 0;
-
-
-  return EFI_SUCCESS;
-
-}
-
-/**
-  Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset().
-  This driver only perform dependent serial device reset regardless of
-  the value of ExtendeVerification
-
-  @param  This                     Indicates the calling context.
-  @param  ExtendedVerification     Skip by this driver.
-
-  @retval EFI_SUCCESS              The reset operation succeeds.
-  @retval EFI_DEVICE_ERROR         The dependent serial port reset fails.
-
-**/
-EFI_STATUS
-EFIAPI
-TerminalConInReset (
-  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
-  IN  BOOLEAN                         ExtendedVerification
-  )
-{
-  EFI_STATUS    Status;
-  TERMINAL_DEV  *TerminalDevice;
-
-  TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);
-
-  //
-  // Report progress code here
-  //
-  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
-    EFI_PROGRESS_CODE,
-    (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_RESET),
-    TerminalDevice->DevicePath
-    );
-
-  Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo);
-
-  //
-  // Make all the internal buffer empty for keys
-  //
-  TerminalDevice->RawFiFo->Head     = TerminalDevice->RawFiFo->Tail;
-  TerminalDevice->UnicodeFiFo->Head = TerminalDevice->UnicodeFiFo->Tail;
-  TerminalDevice->EfiKeyFiFo->Head  = TerminalDevice->EfiKeyFiFo->Tail;
-
-  if (EFI_ERROR (Status)) {
-    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
-      EFI_ERROR_CODE | EFI_ERROR_MINOR,
-      (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
-      TerminalDevice->DevicePath
-      );
-  }
-
-  return Status;
-}
-
-/**
-  Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke().
-
-  @param  This                Indicates the calling context.
-  @param  Key                 A pointer to a buffer that is filled in with the
-                              keystroke information for the key that was sent
-                              from terminal.
-
-  @retval EFI_SUCCESS         The keystroke information is returned successfully.
-  @retval EFI_NOT_READY       There is no keystroke data available.
-  @retval EFI_DEVICE_ERROR    The dependent serial device encounters error.
-
-**/
-EFI_STATUS
-EFIAPI
-TerminalConInReadKeyStroke (
-  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
-  OUT EFI_INPUT_KEY                   *Key
-  )
-{
-  TERMINAL_DEV  *TerminalDevice;
-  EFI_STATUS    Status;
-  EFI_KEY_DATA  KeyData;
-
-  //
-  //  get TERMINAL_DEV from "This" parameter.
-  //
-  TerminalDevice  = TERMINAL_CON_IN_DEV_FROM_THIS (This);
-
-  Status = ReadKeyStrokeWorker (TerminalDevice, &KeyData);
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
-
-  return EFI_SUCCESS;
-
-}
-
-/**
-  Check if the key already has been registered.
-
-  If both RegsiteredData and InputData is NULL, then ASSERT().
-
-  @param  RegsiteredData           A pointer to a buffer that is filled in with the
-                                   keystroke state data for the key that was
-                                   registered.
-  @param  InputData                A pointer to a buffer that is filled in with the
-                                   keystroke state data for the key that was
-                                   pressed.
-
-  @retval TRUE                     Key be pressed matches a registered key.
-  @retval FLASE                    Match failed.
-
-**/
-BOOLEAN
-IsKeyRegistered (
-  IN EFI_KEY_DATA  *RegsiteredData,
-  IN EFI_KEY_DATA  *InputData
-  )
-{
-  ASSERT (RegsiteredData != NULL && InputData != NULL);
-
-  if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
-      (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
-
-
-/**
-  Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
-  Signal the event if there is key available
-
-  @param  Event                    Indicates the event that invoke this function.
-  @param  Context                  Indicates the calling context.
-
-**/
-VOID
-EFIAPI
-TerminalConInWaitForKeyEx (
-  IN  EFI_EVENT       Event,
-  IN  VOID            *Context
-  )
-{
-  TerminalConInWaitForKey (Event, Context);
-}
-
-//
-// Simple Text Input Ex protocol functions
-//
-
-/**
-  Reset the input device and optionally run diagnostics
-
-  @param  This                     Protocol instance pointer.
-  @param  ExtendedVerification     Driver may perform diagnostics on reset.
-
-  @retval EFI_SUCCESS              The device was reset.
-  @retval EFI_DEVICE_ERROR         The device is not functioning properly and could
-                                   not be reset.
-
-**/
-EFI_STATUS
-EFIAPI
-TerminalConInResetEx (
-  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
-  IN BOOLEAN                            ExtendedVerification
-  )
-{
-  EFI_STATUS              Status;
-  TERMINAL_DEV            *TerminalDevice;
-
-  TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
-
-  Status = TerminalDevice->SimpleInput.Reset (&TerminalDevice->SimpleInput, ExtendedVerification);
-  if (EFI_ERROR (Status)) {
-    return EFI_DEVICE_ERROR;
-  }
-
-  return EFI_SUCCESS;
-
-}
-
-
-/**
-  Reads the next keystroke from the input device. The WaitForKey Event can
-  be used to test for existence of a keystroke via WaitForEvent () call.
-
-  @param  This                     Protocol instance pointer.
-  @param  KeyData                  A pointer to a buffer that is filled in with the
-                                   keystroke state data for the key that was
-                                   pressed.
-
-  @retval EFI_SUCCESS              The keystroke information was returned.
-  @retval EFI_NOT_READY            There was no keystroke data available.
-  @retval EFI_DEVICE_ERROR         The keystroke information was not returned due
-                                   to hardware errors.
-  @retval EFI_INVALID_PARAMETER    KeyData is NULL.
-
-**/
-EFI_STATUS
-EFIAPI
-TerminalConInReadKeyStrokeEx (
-  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
-  OUT EFI_KEY_DATA                      *KeyData
-  )
-{
-  TERMINAL_DEV                    *TerminalDevice;
-
-  if (KeyData == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
-
-  return ReadKeyStrokeWorker (TerminalDevice, KeyData);
-
-}
-
-
-/**
-  Set certain state for the input device.
-
-  @param  This                     Protocol instance pointer.
-  @param  KeyToggleState           A pointer to the EFI_KEY_TOGGLE_STATE to set the
-                                   state for the input device.
-
-  @retval EFI_SUCCESS              The device state was set successfully.
-  @retval EFI_DEVICE_ERROR         The device is not functioning correctly and
-                                   could not have the setting adjusted.
-  @retval EFI_UNSUPPORTED          The device does not have the ability to set its
-                                   state.
-  @retval EFI_INVALID_PARAMETER    KeyToggleState is NULL.
-
-**/
-EFI_STATUS
-EFIAPI
-TerminalConInSetState (
-  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
-  IN EFI_KEY_TOGGLE_STATE               *KeyToggleState
-  )
-{
-  if (KeyToggleState == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Register a notification function for a particular keystroke for the input device.
-
-  @param  This                     Protocol instance pointer.
-  @param  KeyData                  A pointer to a buffer that is filled in with the
-                                   keystroke information data for the key that was
-                                   pressed.
-  @param  KeyNotificationFunction  Points to the function to be called when the key
-                                   sequence is typed specified by KeyData.
-  @param  NotifyHandle             Points to the unique handle assigned to the
-                                   registered notification.
-
-  @retval EFI_SUCCESS              The notification function was registered
-                                   successfully.
-  @retval EFI_OUT_OF_RESOURCES     Unable to allocate resources for necessary data
-                                   structures.
-  @retval EFI_INVALID_PARAMETER    KeyData or NotifyHandle is NULL.
-
-**/
-EFI_STATUS
-EFIAPI
-TerminalConInRegisterKeyNotify (
-  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
-  IN EFI_KEY_DATA                       *KeyData,
-  IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
-  OUT EFI_HANDLE                        *NotifyHandle
-  )
-{
-  TERMINAL_DEV                    *TerminalDevice;
-  TERMINAL_CONSOLE_IN_EX_NOTIFY   *NewNotify;
-  LIST_ENTRY                      *Link;
-  LIST_ENTRY                      *NotifyList;
-  TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;
-
-  if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
-
-  //
-  // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
-  //
-  NotifyList = &TerminalDevice->NotifyList;
-  for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
-    CurrentNotify = CR (
-                      Link,
-                      TERMINAL_CONSOLE_IN_EX_NOTIFY,
-                      NotifyEntry,
-                      TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
-                      );
-    if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
-      if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
-        *NotifyHandle = CurrentNotify->NotifyHandle;
-        return EFI_SUCCESS;
-      }
-    }
-  }
-
-  //
-  // Allocate resource to save the notification function
-  //
-  NewNotify = (TERMINAL_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (TERMINAL_CONSOLE_IN_EX_NOTIFY));
-  if (NewNotify == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-
-  NewNotify->Signature         = TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
-  NewNotify->KeyNotificationFn = KeyNotificationFunction;
-  NewNotify->NotifyHandle      = (EFI_HANDLE) NewNotify;
-  CopyMem (&NewNotify->KeyData, KeyData, sizeof (KeyData));
-  InsertTailList (&TerminalDevice->NotifyList, &NewNotify->NotifyEntry);
-
-  *NotifyHandle                = NewNotify->NotifyHandle;
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Remove a registered notification function from a particular keystroke.
-
-  @param  This                     Protocol instance pointer.
-  @param  NotificationHandle       The handle of the notification function being
-                                   unregistered.
-
-  @retval EFI_SUCCESS              The notification function was unregistered
-                                   successfully.
-  @retval EFI_INVALID_PARAMETER    The NotificationHandle is invalid.
-
-**/
-EFI_STATUS
-EFIAPI
-TerminalConInUnregisterKeyNotify (
-  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
-  IN EFI_HANDLE                         NotificationHandle
-  )
-{
-  TERMINAL_DEV                    *TerminalDevice;
-  LIST_ENTRY                      *Link;
-  TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;
-  LIST_ENTRY                      *NotifyList;
-
-  if (NotificationHandle == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (((TERMINAL_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE) {
-    return EFI_INVALID_PARAMETER;
-  } 
-  
-  TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
-
-  NotifyList = &TerminalDevice->NotifyList;
-  for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
-    CurrentNotify = CR (
-                      Link,
-                      TERMINAL_CONSOLE_IN_EX_NOTIFY,
-                      NotifyEntry,
-                      TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
-                      );
-    if (CurrentNotify->NotifyHandle == NotificationHandle) {
-      //
-      // Remove the notification function from NotifyList and free resources
-      //
-      RemoveEntryList (&CurrentNotify->NotifyEntry);
-
-      gBS->FreePool (CurrentNotify);
-      return EFI_SUCCESS;
-    }
-  }
-
-  //
-  // Can not find the matching entry in database.
-  //
-  return EFI_INVALID_PARAMETER;
-}
-
-/**
-  Translate raw data into Unicode (according to different encode), and
-  translate Unicode into key information. (according to different standard).
-
-  @param  TerminalDevice       Terminal driver private structure.
-
-**/
-VOID
-TranslateRawDataToEfiKey (
-  IN  TERMINAL_DEV      *TerminalDevice
-  )
-{
-  switch (TerminalDevice->TerminalType) {
-
-  case PCANSITYPE:
-  case VT100TYPE:
-  case VT100PLUSTYPE:
-    AnsiRawDataToUnicode (TerminalDevice);
-    UnicodeToEfiKey (TerminalDevice);
-    break;
-
-  case VTUTF8TYPE:
-    //
-    // Process all the raw data in the RawFIFO,
-    // put the processed key into UnicodeFIFO.
-    //
-    VTUTF8RawDataToUnicode (TerminalDevice);
-
-    //
-    // Translate all the Unicode data in the UnicodeFIFO to Efi key,
-    // then put into EfiKeyFIFO.
-    //
-    UnicodeToEfiKey (TerminalDevice);
-
-    break;
-  }
-}
-
-/**
-  Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event
-  Signal the event if there is key available
-
-  @param  Event                    Indicates the event that invoke this function.
-  @param  Context                  Indicates the calling context.
-
-**/
-VOID
-EFIAPI
-TerminalConInWaitForKey (
-  IN  EFI_EVENT       Event,
-  IN  VOID            *Context
-  )
-{
-  //
-  // Someone is waiting on the keystroke event, if there's
-  // a key pending, signal the event
-  //
-  if (!IsEfiKeyFiFoEmpty ((TERMINAL_DEV *) Context)) {
-
-    gBS->SignalEvent (Event);
-  }
-}
-
-/**
-  Timer handler to poll the key from serial.
-
-  @param  Event                    Indicates the event that invoke this function.
-  @param  Context                  Indicates the calling context.
-**/
-VOID
-EFIAPI
-TerminalConInTimerHandler (
-  IN EFI_EVENT            Event,
-  IN VOID                 *Context
-  )
-{
-  EFI_STATUS              Status;
-  TERMINAL_DEV            *TerminalDevice;
-  UINT8                   Input;
-  EFI_SERIAL_IO_MODE      *Mode;
-  EFI_SERIAL_IO_PROTOCOL  *SerialIo;
-  UINTN                   SerialInTimeOut;
-
-  TerminalDevice  = (TERMINAL_DEV *) Context;
-
-  SerialIo        = TerminalDevice->SerialIo;
-  if (SerialIo == NULL) {
-    return ;
-  }
-  //
-  //  if current timeout value for serial device is not identical with
-  //  the value saved in TERMINAL_DEV structure, then recalculate the
-  //  timeout value again and set serial attribute according to this value.
-  //
-  Mode = SerialIo->Mode;
-  if (Mode->Timeout != TerminalDevice->SerialInTimeOut) {
-
-    SerialInTimeOut = 0;
-    if (Mode->BaudRate != 0) {
-      //
-      // According to BAUD rate to calculate the timeout value.
-      //
-      SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;
-    }
-
-    Status = SerialIo->SetAttributes (
-                        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)) {
-      TerminalDevice->SerialInTimeOut = 0;
-    } else {
-      TerminalDevice->SerialInTimeOut = SerialInTimeOut;
-    }
-  }
-
-  //
-  // Fetch all the keys in the serial buffer,
-  // and insert the byte stream into RawFIFO.
-  //
-  while( !IsRawFiFoFull(TerminalDevice) ) {
-
-    Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input);
-
-    if (EFI_ERROR (Status)) {
-      if (Status == EFI_DEVICE_ERROR) {
-        REPORT_STATUS_CODE_WITH_DEVICE_PATH (
-          EFI_ERROR_CODE | EFI_ERROR_MINOR,
-          (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_INPUT_ERROR),
-          TerminalDevice->DevicePath
-          );
-      }
-      break;
-    }
-
-    RawFiFoInsertOneKey (TerminalDevice, Input);
-  }
-
-  //
-  // Translate all the raw data in RawFIFO into EFI Key,
-  // according to different terminal type supported.
-  //
-  TranslateRawDataToEfiKey (TerminalDevice);
-}
-
-/**
-  Get one key out of serial buffer.
-
-  @param  SerialIo           Serial I/O protocol attached to the serial device.
-  @param  Output             The fetched key.
-
-  @retval EFI_NOT_READY      If serial buffer is empty.
-  @retval EFI_DEVICE_ERROR   If reading serial buffer encounter error.
-  @retval EFI_SUCCESS        If reading serial buffer successfully, put
-                             the fetched key to the parameter output.
-
-**/
-EFI_STATUS
-GetOneKeyFromSerial (
-  EFI_SERIAL_IO_PROTOCOL  *SerialIo,
-  UINT8                   *Output
-  )
-{
-  EFI_STATUS  Status;
-  UINTN       Size;
-
-  Size    = 1;
-  *Output = 0;
-
-  //
-  // Read one key from serial I/O device.
-  //
-  Status  = SerialIo->Read (SerialIo, &Size, Output);
-
-  if (EFI_ERROR (Status)) {
-
-    if (Status == EFI_TIMEOUT) {
-      return EFI_NOT_READY;
-    }
-
-    return EFI_DEVICE_ERROR;
-
-  }
-
-  if (*Output == 0) {
-    return EFI_NOT_READY;
-  }
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Insert one byte raw data into the Raw Data FIFO.
-
-  @param  TerminalDevice       Terminal driver private structure.
-  @param  Input                The key will be input.
-
-  @retval TRUE                 If insert successfully.
-  @retval FLASE                If Raw Data buffer is full before key insertion,
-                               and the key is lost.
-
-**/
-BOOLEAN
-RawFiFoInsertOneKey (
-  TERMINAL_DEV      *TerminalDevice,
-  UINT8             Input
-  )
-{
-  UINT8 Tail;
-
-  Tail = TerminalDevice->RawFiFo->Tail;
-
-  if (IsRawFiFoFull (TerminalDevice)) {
-    //
-    // Raw FIFO is full
-    //
-    return FALSE;
-  }
-
-  TerminalDevice->RawFiFo->Data[Tail]  = Input;
-
-  TerminalDevice->RawFiFo->Tail        = (UINT8) ((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1));
-
-  return TRUE;
-}
-
-/**
-  Remove one pre-fetched key out of the Raw Data FIFO.
-
-  @param  TerminalDevice       Terminal driver private structure.
-  @param  Output               The key will be removed.
-
-  @retval TRUE                 If insert successfully.
-  @retval FLASE                If Raw Data FIFO buffer is empty before remove operation.
-
-**/
-BOOLEAN
-RawFiFoRemoveOneKey (
-  TERMINAL_DEV  *TerminalDevice,
-  UINT8         *Output
-  )
-{
-  UINT8 Head;
-
-  Head = TerminalDevice->RawFiFo->Head;
-
-  if (IsRawFiFoEmpty (TerminalDevice)) {
-    //
-    //  FIFO is empty
-    //
-    *Output = 0;
-    return FALSE;
-  }
-
-  *Output                       = TerminalDevice->RawFiFo->Data[Head];
-
-  TerminalDevice->RawFiFo->Head  = (UINT8) ((Head + 1) % (RAW_FIFO_MAX_NUMBER + 1));
-
-  return TRUE;
-}
-
-/**
-  Clarify whether Raw Data FIFO buffer is empty.
-
-  @param  TerminalDevice       Terminal driver private structure
-
-  @retval TRUE                 If Raw Data FIFO buffer is empty.
-  @retval FLASE                If Raw Data FIFO buffer is not empty.
-
-**/
-BOOLEAN
-IsRawFiFoEmpty (
-  TERMINAL_DEV  *TerminalDevice
-  )
-{
-  if (TerminalDevice->RawFiFo->Head == TerminalDevice->RawFiFo->Tail) {
-    return TRUE;
-  } else {
-    return FALSE;
-  }
-}
-
-/**
-  Clarify whether Raw Data FIFO buffer is full.
-
-  @param  TerminalDevice       Terminal driver private structure
-
-  @retval TRUE                 If Raw Data FIFO buffer is full.
-  @retval FLASE                If Raw Data FIFO buffer is not full.
-
-**/
-BOOLEAN
-IsRawFiFoFull (
-  TERMINAL_DEV  *TerminalDevice
-  )
-{
-  UINT8 Tail;
-  UINT8 Head;
-
-  Tail  = TerminalDevice->RawFiFo->Tail;
-  Head  = TerminalDevice->RawFiFo->Head;
-
-  if (((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)) == Head) {
-
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
-/**
-  Insert one pre-fetched key into the FIFO buffer.
-
-  @param  TerminalDevice       Terminal driver private structure.
-  @param  Key                  The key will be input.
-
-  @retval TRUE                 If insert successfully.
-  @retval FLASE                If FIFO buffer is full before key insertion,
-                               and the key is lost.
-
-**/
-BOOLEAN
-EfiKeyFiFoInsertOneKey (
-  TERMINAL_DEV                    *TerminalDevice,
-  EFI_INPUT_KEY                   *Key
-  )
-{
-  UINT8                           Tail;
-  LIST_ENTRY                      *Link;
-  LIST_ENTRY                      *NotifyList;
-  TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;
-  EFI_KEY_DATA                    KeyData;
-
-  Tail = TerminalDevice->EfiKeyFiFo->Tail;
-
-  CopyMem (&KeyData.Key, Key, sizeof (EFI_INPUT_KEY));
-  KeyData.KeyState.KeyShiftState  = 0;
-  KeyData.KeyState.KeyToggleState = 0;
-
-  //
-  // Invoke notification functions if exist
-  //
-  NotifyList = &TerminalDevice->NotifyList;
-  for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
-    CurrentNotify = CR (
-                      Link,
-                      TERMINAL_CONSOLE_IN_EX_NOTIFY,
-                      NotifyEntry,
-                      TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
-                      );
-    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
-      CurrentNotify->KeyNotificationFn (&KeyData);
-    }
-  }
-  if (IsEfiKeyFiFoFull (TerminalDevice)) {
-    //
-    // Efi Key FIFO is full
-    //
-    return FALSE;
-  }
-
-  CopyMem (&TerminalDevice->EfiKeyFiFo->Data[Tail], Key, sizeof (EFI_INPUT_KEY));
-
-  TerminalDevice->EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
-
-  return TRUE;
-}
-
-/**
-  Remove one pre-fetched key out of the FIFO buffer.
-
-  @param  TerminalDevice       Terminal driver private structure.
-  @param  Output               The key will be removed.
-
-  @retval TRUE                 If insert successfully.
-  @retval FLASE                If FIFO buffer is empty before remove operation.
-
-**/
-BOOLEAN
-EfiKeyFiFoRemoveOneKey (
-  TERMINAL_DEV  *TerminalDevice,
-  EFI_INPUT_KEY *Output
-  )
-{
-  UINT8 Head;
-
-  Head = TerminalDevice->EfiKeyFiFo->Head;
-  ASSERT (Head < FIFO_MAX_NUMBER + 1);
-
-  if (IsEfiKeyFiFoEmpty (TerminalDevice)) {
-    //
-    //  FIFO is empty
-    //
-    Output->ScanCode    = SCAN_NULL;
-    Output->UnicodeChar = 0;
-    return FALSE;
-  }
-
-  *Output                         = TerminalDevice->EfiKeyFiFo->Data[Head];
-
-  TerminalDevice->EfiKeyFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
-
-  return TRUE;
-}
-
-/**
-  Clarify whether FIFO buffer is empty.
-
-  @param  TerminalDevice       Terminal driver private structure
-
-  @retval TRUE                 If FIFO buffer is empty.
-  @retval FLASE                If FIFO buffer is not empty.
-
-**/
-BOOLEAN
-IsEfiKeyFiFoEmpty (
-  TERMINAL_DEV  *TerminalDevice
-  )
-{
-  if (TerminalDevice->EfiKeyFiFo->Head == TerminalDevice->EfiKeyFiFo->Tail) {
-    return TRUE;
-  } else {
-    return FALSE;
-  }
-}
-
-/**
-  Clarify whether FIFO buffer is full.
-
-  @param  TerminalDevice       Terminal driver private structure
-
-  @retval TRUE                 If FIFO buffer is full.
-  @retval FLASE                If FIFO buffer is not full.
-
-**/
-BOOLEAN
-IsEfiKeyFiFoFull (
-  TERMINAL_DEV  *TerminalDevice
-  )
-{
-  UINT8 Tail;
-  UINT8 Head;
-
-  Tail  = TerminalDevice->EfiKeyFiFo->Tail;
-  Head  = TerminalDevice->EfiKeyFiFo->Head;
-
-  if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
-
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
-/**
-  Insert one pre-fetched key into the Unicode FIFO buffer.
-
-  @param  TerminalDevice       Terminal driver private structure.
-  @param  Input                The key will be input.
-
-  @retval TRUE                 If insert successfully.
-  @retval FLASE                If Unicode FIFO buffer is full before key insertion,
-                               and the key is lost.
-
-**/
-BOOLEAN
-UnicodeFiFoInsertOneKey (
-  TERMINAL_DEV      *TerminalDevice,
-  UINT16            Input
-  )
-{
-  UINT8 Tail;
-
-  Tail = TerminalDevice->UnicodeFiFo->Tail;
-  ASSERT (Tail < FIFO_MAX_NUMBER + 1);
-
-
-  if (IsUnicodeFiFoFull (TerminalDevice)) {
-    //
-    // Unicode FIFO is full
-    //
-    return FALSE;
-  }
-
-  TerminalDevice->UnicodeFiFo->Data[Tail]  = Input;
-
-  TerminalDevice->UnicodeFiFo->Tail        = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
-
-  return TRUE;
-}
-
-/**
-  Remove one pre-fetched key out of the Unicode FIFO buffer.
-
-  @param  TerminalDevice       Terminal driver private structure.
-  @param  Output               The key will be removed.
-
-  @retval TRUE                 If insert successfully.
-  @retval FLASE                If Unicode FIFO buffer is empty before remove operation.
-
-**/
-BOOLEAN
-UnicodeFiFoRemoveOneKey (
-  TERMINAL_DEV  *TerminalDevice,
-  UINT16        *Output
-  )
-{
-  UINT8 Head;
-
-  Head = TerminalDevice->UnicodeFiFo->Head;
-  ASSERT (Head < FIFO_MAX_NUMBER + 1);
-
-  if (IsUnicodeFiFoEmpty (TerminalDevice)) {
-    //
-    //  FIFO is empty
-    //
-    Output = NULL;
-    return FALSE;
-  }
-
-  *Output = TerminalDevice->UnicodeFiFo->Data[Head];
-
-  TerminalDevice->UnicodeFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
-
-  return TRUE;
-}
-
-/**
-  Clarify whether Unicode FIFO buffer is empty.
-
-  @param  TerminalDevice       Terminal driver private structure
-
-  @retval TRUE                 If Unicode FIFO buffer is empty.
-  @retval FLASE                If Unicode FIFO buffer is not empty.
-
-**/
-BOOLEAN
-IsUnicodeFiFoEmpty (
-  TERMINAL_DEV  *TerminalDevice
-  )
-{
-  if (TerminalDevice->UnicodeFiFo->Head == TerminalDevice->UnicodeFiFo->Tail) {
-    return TRUE;
-  } else {
-    return FALSE;
-  }
-}
-
-/**
-  Clarify whether Unicode FIFO buffer is full.
-
-  @param  TerminalDevice       Terminal driver private structure
-
-  @retval TRUE                 If Unicode FIFO buffer is full.
-  @retval FLASE                If Unicode FIFO buffer is not full.
-
-**/
-BOOLEAN
-IsUnicodeFiFoFull (
-  TERMINAL_DEV  *TerminalDevice
-  )
-{
-  UINT8 Tail;
-  UINT8 Head;
-
-  Tail  = TerminalDevice->UnicodeFiFo->Tail;
-  Head  = TerminalDevice->UnicodeFiFo->Head;
-
-  if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
-
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
-/**
-  Count Unicode FIFO buffer.
-
-  @param  TerminalDevice       Terminal driver private structure
-
-  @return The count in bytes of Unicode FIFO.
-
-**/
-UINT8
-UnicodeFiFoGetKeyCount (
-  TERMINAL_DEV    *TerminalDevice
-  )
-{
-  UINT8 Tail;
-  UINT8 Head;
-
-  Tail  = TerminalDevice->UnicodeFiFo->Tail;
-  Head  = TerminalDevice->UnicodeFiFo->Head;
-
-  if (Tail >= Head) {
-    return (UINT8) (Tail - Head);
-  } else {
-    return (UINT8) (Tail + FIFO_MAX_NUMBER + 1 - Head);
-  }
-}
-
-/**
-  Update the Unicode characters from a terminal input device into EFI Keys FIFO.
-
-  @param TerminalDevice   The terminal device to use to translate raw input into EFI Keys
-
-**/
-VOID
-UnicodeToEfiKeyFlushState (
-  IN  TERMINAL_DEV    *TerminalDevice
-  )
-{
-  EFI_INPUT_KEY Key;
-  UINT32        InputState;
-
-  InputState = TerminalDevice->InputState;
-
-  if( IsEfiKeyFiFoFull(TerminalDevice) ) return;
-
-  if ((InputState & INPUT_STATE_ESC) != 0) {
-    Key.ScanCode    = SCAN_ESC;
-    Key.UnicodeChar = 0;
-    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
-  }
-
-  if ((InputState & INPUT_STATE_CSI) != 0) {
-    Key.ScanCode    = SCAN_NULL;
-    Key.UnicodeChar = CSI;
-    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
-  }
-
-  if ((InputState & INPUT_STATE_LEFTOPENBRACKET) != 0) {
-    Key.ScanCode    = SCAN_NULL;
-    Key.UnicodeChar = LEFTOPENBRACKET;
-    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
-  }
-
-  if ((InputState & INPUT_STATE_O) != 0) {
-    Key.ScanCode    = SCAN_NULL;
-    Key.UnicodeChar = 'O';
-    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
-  }
-
-  if ((InputState & INPUT_STATE_2) != 0) {
-    Key.ScanCode    = SCAN_NULL;
-    Key.UnicodeChar = '2';
-    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
-  }
-
-  //
-  // Cancel the timer.
-  //
-  gBS->SetTimer (
-        TerminalDevice->TwoSecondTimeOut,
-        TimerCancel,
-        0
-        );
-
-  TerminalDevice->InputState = INPUT_STATE_DEFAULT;
-}
-
-
-/**
-  Converts a stream of Unicode characters from a terminal input device into EFI Keys that
-  can be read through the Simple Input Protocol.
-
-  The table below shows the keyboard input mappings that this function supports.
-  If the ESC sequence listed in one of the columns is presented, then it is translated
-  into the corresponding EFI Scan Code.  If a matching sequence is not found, then the raw
-  key strokes are converted into EFI Keys.
-
-  2 seconds are allowed for an ESC sequence to be completed.  If the ESC sequence is not
-  completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
-  converted into EFI Keys.
-  There is one special input sequence that will force the system to reset.
-  This is ESC R ESC r ESC R.
-
-  Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100. 
-        The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 /
-        DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example.
-        
-  Symbols used in table below
-  ===========================
-    ESC = 0x1B
-    CSI = 0x9B
-    DEL = 0x7f
-    ^   = CTRL
-
-  +=========+======+===========+==========+==========+
-  |         | EFI  | UEFI 2.0  |          |          |
-  |         | Scan |           |  VT100+  |          |
-  |   KEY   | Code |  PC ANSI  |  VTUTF8  |   VT100  |
-  +=========+======+===========+==========+==========+
-  | NULL    | 0x00 |           |          |          |
-  | UP      | 0x01 | ESC [ A   | ESC [ A  | ESC [ A  |
-  | DOWN    | 0x02 | ESC [ B   | ESC [ B  | ESC [ B  |
-  | RIGHT   | 0x03 | ESC [ C   | ESC [ C  | ESC [ C  |
-  | LEFT    | 0x04 | ESC [ D   | ESC [ D  | ESC [ D  |
-  | HOME    | 0x05 | ESC [ H   | ESC h    | ESC [ H  |
-  | END     | 0x06 | ESC [ F   | ESC k    | ESC [ K  |
-  | INSERT  | 0x07 | ESC [ @   | ESC +    | ESC [ @  |
-  |         |      | ESC [ L   |          | ESC [ L  |
-  | DELETE  | 0x08 | ESC [ X   | ESC -    | ESC [ P  |
-  | PG UP   | 0x09 | ESC [ I   | ESC ?    | ESC [ V  |
-  |         |      |           |          | ESC [ ?  |
-  | PG DOWN | 0x0A | ESC [ G   | ESC /    | ESC [ U  |
-  |         |      |           |          | ESC [ /  |
-  | F1      | 0x0B | ESC [ M   | ESC 1    | ESC O P  |
-  | F2      | 0x0C | ESC [ N   | ESC 2    | ESC O Q  |
-  | F3      | 0x0D | ESC [ O   | ESC 3    | ESC O w  |
-  | F4      | 0x0E | ESC [ P   | ESC 4    | ESC O x  |
-  | F5      | 0x0F | ESC [ Q   | ESC 5    | ESC O t  |
-  | F6      | 0x10 | ESC [ R   | ESC 6    | ESC O u  |
-  | F7      | 0x11 | ESC [ S   | ESC 7    | ESC O q  |
-  | F8      | 0x12 | ESC [ T   | ESC 8    | ESC O r  |
-  | F9      | 0x13 | ESC [ U   | ESC 9    | ESC O p  |
-  | F10     | 0x14 | ESC [ V   | ESC 0    | ESC O M  |
-  | Escape  | 0x17 | ESC       | ESC      | ESC      |
-  | F11     | 0x15 |           | ESC !    |          |
-  | F12     | 0x16 |           | ESC @    |          |
-  +=========+======+===========+==========+==========+
-
-  Special Mappings
-  ================
-  ESC R ESC r ESC R = Reset System
-
-  @param TerminalDevice   The terminal device to use to translate raw input into EFI Keys
-
-**/
-VOID
-UnicodeToEfiKey (
-  IN  TERMINAL_DEV    *TerminalDevice
-  )
-{
-  EFI_STATUS          Status;
-  EFI_STATUS          TimerStatus;
-  UINT16              UnicodeChar;
-  EFI_INPUT_KEY       Key;
-  BOOLEAN             SetDefaultResetState;
-
-  TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
-
-  if (!EFI_ERROR (TimerStatus)) {
-    UnicodeToEfiKeyFlushState (TerminalDevice);
-    TerminalDevice->ResetState = RESET_STATE_DEFAULT;
-  }
-
-  while (!IsUnicodeFiFoEmpty(TerminalDevice) && !IsEfiKeyFiFoFull(TerminalDevice) ) {
-
-    if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
-      //
-      // Check to see if the 2 seconds timer has expired
-      //
-      TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
-      if (!EFI_ERROR (TimerStatus)) {
-        UnicodeToEfiKeyFlushState (TerminalDevice);
-        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
-      }
-    }
-
-    //
-    // Fetch one Unicode character from the Unicode FIFO
-    //
-    UnicodeFiFoRemoveOneKey (TerminalDevice, &UnicodeChar);
-
-    SetDefaultResetState = TRUE;
-
-    switch (TerminalDevice->InputState) {
-    case INPUT_STATE_DEFAULT:
-
-      break;
-
-    case INPUT_STATE_ESC:
-
-      if (UnicodeChar == LEFTOPENBRACKET) {
-        TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET;
-        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
-        continue;
-      }
-
-      if (UnicodeChar == 'O' && TerminalDevice->TerminalType == VT100TYPE) {
-        TerminalDevice->InputState |= INPUT_STATE_O;
-        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
-        continue;
-      }
-
-      Key.ScanCode = SCAN_NULL;
-
-      if (TerminalDevice->TerminalType == VT100PLUSTYPE ||
-          TerminalDevice->TerminalType == VTUTF8TYPE) {
-        switch (UnicodeChar) {
-        case '1':
-          Key.ScanCode = SCAN_F1;
-          break;
-        case '2':
-          Key.ScanCode = SCAN_F2;
-          break;
-        case '3':
-          Key.ScanCode = SCAN_F3;
-          break;
-        case '4':
-          Key.ScanCode = SCAN_F4;
-          break;
-        case '5':
-          Key.ScanCode = SCAN_F5;
-          break;
-        case '6':
-          Key.ScanCode = SCAN_F6;
-          break;
-        case '7':
-          Key.ScanCode = SCAN_F7;
-          break;
-        case '8':
-          Key.ScanCode = SCAN_F8;
-          break;
-        case '9':
-          Key.ScanCode = SCAN_F9;
-          break;
-        case '0':
-          Key.ScanCode = SCAN_F10;
-          break;
-        case '!':
-          Key.ScanCode = SCAN_F11;
-          break;
-        case '@':
-          Key.ScanCode = SCAN_F12;
-          break;
-        case 'h':
-          Key.ScanCode = SCAN_HOME;
-          break;
-        case 'k':
-          Key.ScanCode = SCAN_END;
-          break;
-        case '+':
-          Key.ScanCode = SCAN_INSERT;
-          break;
-        case '-':
-          Key.ScanCode = SCAN_DELETE;
-          break;
-        case '/':
-          Key.ScanCode = SCAN_PAGE_DOWN;
-          break;
-        case '?':
-          Key.ScanCode = SCAN_PAGE_UP;
-          break;
-        default :
-          break;
-        }
-      }
-
-      switch (UnicodeChar) {
-      case 'R':
-        if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) {
-          TerminalDevice->ResetState = RESET_STATE_ESC_R;
-          SetDefaultResetState = FALSE;
-        } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_R) {
-          gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
-        }
-        Key.ScanCode = SCAN_NULL;
-        break;
-      case 'r':
-        if (TerminalDevice->ResetState == RESET_STATE_ESC_R) {
-          TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_R;
-          SetDefaultResetState = FALSE;
-        }
-        Key.ScanCode = SCAN_NULL;
-        break;
-      default :
-        break;
-      }
-
-      if (SetDefaultResetState) {
-        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
-      }
-
-      if (Key.ScanCode != SCAN_NULL) {
-        Key.UnicodeChar = 0;
-        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
-        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
-        UnicodeToEfiKeyFlushState (TerminalDevice);
-        continue;
-      }
-
-      UnicodeToEfiKeyFlushState (TerminalDevice);
-
-      break;
-
-    case INPUT_STATE_ESC | INPUT_STATE_O:
-
-      TerminalDevice->ResetState = RESET_STATE_DEFAULT;
-
-      Key.ScanCode = SCAN_NULL;
-
-      if (TerminalDevice->TerminalType == VT100TYPE) {
-        switch (UnicodeChar) {
-        case 'P':
-          Key.ScanCode = SCAN_F1;
-          break;
-        case 'Q':
-          Key.ScanCode = SCAN_F2;
-          break;
-        case 'w':
-          Key.ScanCode = SCAN_F3;
-          break;
-        case 'x':
-          Key.ScanCode = SCAN_F4;
-          break;
-        case 't':
-          Key.ScanCode = SCAN_F5;
-          break;
-        case 'u':
-          Key.ScanCode = SCAN_F6;
-          break;
-        case 'q':
-          Key.ScanCode = SCAN_F7;
-          break;
-        case 'r':
-          Key.ScanCode = SCAN_F8;
-          break;
-        case 'p':
-          Key.ScanCode = SCAN_F9;
-          break;
-        case 'M':
-          Key.ScanCode = SCAN_F10;
-          break;
-        default :
-          break;
-        }
-      }
-
-      if (Key.ScanCode != SCAN_NULL) {
-        Key.UnicodeChar = 0;
-        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
-        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
-        UnicodeToEfiKeyFlushState (TerminalDevice);
-        continue;
-      }
-
-      UnicodeToEfiKeyFlushState (TerminalDevice);
-
-      break;
-
-    case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET:
-
-      TerminalDevice->ResetState = RESET_STATE_DEFAULT;
-
-      Key.ScanCode = SCAN_NULL;
-
-      if (TerminalDevice->TerminalType == PCANSITYPE    ||
-          TerminalDevice->TerminalType == VT100TYPE     ||
-          TerminalDevice->TerminalType == VT100PLUSTYPE ||
-          TerminalDevice->TerminalType == VTUTF8TYPE) {
-        switch (UnicodeChar) {
-        case 'A':
-          Key.ScanCode = SCAN_UP;
-          break;
-        case 'B':
-          Key.ScanCode = SCAN_DOWN;
-          break;
-        case 'C':
-          Key.ScanCode = SCAN_RIGHT;
-          break;
-        case 'D':
-          Key.ScanCode = SCAN_LEFT;
-          break;
-        case 'H':
-          if (TerminalDevice->TerminalType == PCANSITYPE ||
-              TerminalDevice->TerminalType == VT100TYPE) {
-            Key.ScanCode = SCAN_HOME;
-          }
-          break;
-        case 'F':
-          if (TerminalDevice->TerminalType == PCANSITYPE) {
-            Key.ScanCode = SCAN_END;
-          }
-          break;
-        case 'K':
-          if (TerminalDevice->TerminalType == VT100TYPE) {
-            Key.ScanCode = SCAN_END;
-          }
-          break;
-        case 'L':
-        case '@':
-          if (TerminalDevice->TerminalType == PCANSITYPE ||
-              TerminalDevice->TerminalType == VT100TYPE) {
-            Key.ScanCode = SCAN_INSERT;
-          }
-          break;
-        case 'X':
-          if (TerminalDevice->TerminalType == PCANSITYPE) {
-            Key.ScanCode = SCAN_DELETE;
-          }
-          break;
-        case 'P':
-          if (TerminalDevice->TerminalType == VT100TYPE) {
-            Key.ScanCode = SCAN_DELETE;
-          } else if (TerminalDevice->TerminalType == PCANSITYPE) {
-            Key.ScanCode = SCAN_F4;
-          }
-          break;
-        case 'I':
-          if (TerminalDevice->TerminalType == PCANSITYPE) {
-            Key.ScanCode = SCAN_PAGE_UP;
-          }
-          break;
-        case 'V':
-          if (TerminalDevice->TerminalType == PCANSITYPE) {
-            Key.ScanCode = SCAN_F10;
-          }
-        case '?':
-          if (TerminalDevice->TerminalType == VT100TYPE) {
-            Key.ScanCode = SCAN_PAGE_UP;
-          }
-          break;
-        case 'G':
-          if (TerminalDevice->TerminalType == PCANSITYPE) {
-            Key.ScanCode = SCAN_PAGE_DOWN;
-          }
-          break;
-        case 'U':
-          if (TerminalDevice->TerminalType == PCANSITYPE) {
-            Key.ScanCode = SCAN_F9;
-          }
-        case '/':
-          if (TerminalDevice->TerminalType == VT100TYPE) {
-            Key.ScanCode = SCAN_PAGE_DOWN;
-          }
-          break;
-        case 'M':
-          if (TerminalDevice->TerminalType == PCANSITYPE) {
-            Key.ScanCode = SCAN_F1;
-          }
-          break;
-        case 'N':
-          if (TerminalDevice->TerminalType == PCANSITYPE) {
-            Key.ScanCode = SCAN_F2;
-          }
-          break;
-        case 'O':
-          if (TerminalDevice->TerminalType == PCANSITYPE) {
-            Key.ScanCode = SCAN_F3;
-          }
-          break;
-        case 'Q':
-          if (TerminalDevice->TerminalType == PCANSITYPE) {
-            Key.ScanCode = SCAN_F5;
-          }
-          break;
-        case 'R':
-          if (TerminalDevice->TerminalType == PCANSITYPE) {
-            Key.ScanCode = SCAN_F6;
-          }
-          break;
-        case 'S':
-          if (TerminalDevice->TerminalType == PCANSITYPE) {
-            Key.ScanCode = SCAN_F7;
-          }
-          break;
-        case 'T':
-          if (TerminalDevice->TerminalType == PCANSITYPE) {
-            Key.ScanCode = SCAN_F8;
-          }
-          break;
-        default :
-          break;
-        }
-      }
-
-      if (Key.ScanCode != SCAN_NULL) {
-        Key.UnicodeChar = 0;
-        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
-        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
-        UnicodeToEfiKeyFlushState (TerminalDevice);
-        continue;
-      }
-
-      UnicodeToEfiKeyFlushState (TerminalDevice);
-
-      break;
-
-
-    default:
-      //
-      // Invalid state. This should never happen.
-      //
-      ASSERT (FALSE);
-
-      UnicodeToEfiKeyFlushState (TerminalDevice);
-
-      break;
-    }
-
-    if (UnicodeChar == ESC) {
-      TerminalDevice->InputState = INPUT_STATE_ESC;
-    }
-
-    if (UnicodeChar == CSI) {
-      TerminalDevice->InputState = INPUT_STATE_CSI;
-    }
-
-    if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
-      Status = gBS->SetTimer(
-                      TerminalDevice->TwoSecondTimeOut,
-                      TimerRelative,
-                      (UINT64)20000000
-                      );
-      ASSERT_EFI_ERROR (Status);
-      continue;
-    }
-
-    if (SetDefaultResetState) {
-      TerminalDevice->ResetState = RESET_STATE_DEFAULT;
-    }
-
-    if (UnicodeChar == DEL) {
-      Key.ScanCode    = SCAN_DELETE;
-      Key.UnicodeChar = 0;
-    } else {
-      Key.ScanCode    = SCAN_NULL;
-      Key.UnicodeChar = UnicodeChar;
-    }
-
-    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
-  }
-}
+/** @file\r
+  Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol.\r
+\r
+(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (C) 2016 Silicon Graphics, Inc. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "Terminal.h"\r
+\r
+\r
+/**\r
+  Reads the next keystroke from the input device. The WaitForKey Event can\r
+  be used to test for existence of a keystroke via WaitForEvent () call.\r
+\r
+  @param  TerminalDevice           Terminal driver private structure\r
+  @param  KeyData                  A pointer to a buffer that is filled in with the\r
+                                   keystroke state data for the key that was\r
+                                   pressed.\r
+\r
+  @retval EFI_SUCCESS              The keystroke information was returned.\r
+  @retval EFI_NOT_READY            There was no keystroke data available.\r
+  @retval EFI_INVALID_PARAMETER    KeyData is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadKeyStrokeWorker (\r
+  IN  TERMINAL_DEV *TerminalDevice,\r
+  OUT EFI_KEY_DATA *KeyData\r
+  )\r
+{\r
+  if (KeyData == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  KeyData->KeyState.KeyShiftState  = 0;\r
+  KeyData->KeyState.KeyToggleState = 0;\r
+\r
+  if (!EfiKeyFiFoRemoveOneKey (TerminalDevice, &KeyData->Key)) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+  Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset().\r
+  This driver only perform dependent serial device reset regardless of\r
+  the value of ExtendeVerification\r
+\r
+  @param  This                     Indicates the calling context.\r
+  @param  ExtendedVerification     Skip by this driver.\r
+\r
+  @retval EFI_SUCCESS              The reset operation succeeds.\r
+  @retval EFI_DEVICE_ERROR         The dependent serial port reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TerminalConInReset (\r
+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
+  IN  BOOLEAN                         ExtendedVerification\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  TERMINAL_DEV  *TerminalDevice;\r
+\r
+  TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);\r
+\r
+  //\r
+  // Report progress code here\r
+  //\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_RESET),\r
+    TerminalDevice->DevicePath\r
+    );\r
+\r
+  Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo);\r
+\r
+  //\r
+  // Make all the internal buffer empty for keys\r
+  //\r
+  TerminalDevice->RawFiFo->Head     = TerminalDevice->RawFiFo->Tail;\r
+  TerminalDevice->UnicodeFiFo->Head = TerminalDevice->UnicodeFiFo->Tail;\r
+  TerminalDevice->EfiKeyFiFo->Head  = TerminalDevice->EfiKeyFiFo->Tail;\r
+  TerminalDevice->EfiKeyFiFoForNotify->Head = TerminalDevice->EfiKeyFiFoForNotify->Tail;\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),\r
+      TerminalDevice->DevicePath\r
+      );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke().\r
+\r
+  @param  This                Indicates the calling context.\r
+  @param  Key                 A pointer to a buffer that is filled in with the\r
+                              keystroke information for the key that was sent\r
+                              from terminal.\r
+\r
+  @retval EFI_SUCCESS         The keystroke information is returned successfully.\r
+  @retval EFI_NOT_READY       There is no keystroke data available.\r
+  @retval EFI_DEVICE_ERROR    The dependent serial device encounters error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TerminalConInReadKeyStroke (\r
+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
+  OUT EFI_INPUT_KEY                   *Key\r
+  )\r
+{\r
+  TERMINAL_DEV  *TerminalDevice;\r
+  EFI_STATUS    Status;\r
+  EFI_KEY_DATA  KeyData;\r
+\r
+  //\r
+  //  get TERMINAL_DEV from "This" parameter.\r
+  //\r
+  TerminalDevice  = TERMINAL_CON_IN_DEV_FROM_THIS (This);\r
+\r
+  Status = ReadKeyStrokeWorker (TerminalDevice, &KeyData);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+  Check if the key already has been registered.\r
+\r
+  If both RegsiteredData and InputData is NULL, then ASSERT().\r
+\r
+  @param  RegsiteredData           A pointer to a buffer that is filled in with the\r
+                                   keystroke state data for the key that was\r
+                                   registered.\r
+  @param  InputData                A pointer to a buffer that is filled in with the\r
+                                   keystroke state data for the key that was\r
+                                   pressed.\r
+\r
+  @retval TRUE                     Key be pressed matches a registered key.\r
+  @retval FALSE                    Match failed.\r
+\r
+**/\r
+BOOLEAN\r
+IsKeyRegistered (\r
+  IN EFI_KEY_DATA  *RegsiteredData,\r
+  IN EFI_KEY_DATA  *InputData\r
+  )\r
+{\r
+  ASSERT (RegsiteredData != NULL && InputData != NULL);\r
+\r
+  if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||\r
+      (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event\r
+  Signal the event if there is key available\r
+\r
+  @param  Event                    Indicates the event that invoke this function.\r
+  @param  Context                  Indicates the calling context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TerminalConInWaitForKeyEx (\r
+  IN  EFI_EVENT       Event,\r
+  IN  VOID            *Context\r
+  )\r
+{\r
+  TerminalConInWaitForKey (Event, Context);\r
+}\r
+\r
+//\r
+// Simple Text Input Ex protocol functions\r
+//\r
+\r
+/**\r
+  Reset the input device and optionally run diagnostics\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  ExtendedVerification     Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS              The device was reset.\r
+  @retval EFI_DEVICE_ERROR         The device is not functioning properly and could\r
+                                   not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TerminalConInResetEx (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN BOOLEAN                            ExtendedVerification\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  TERMINAL_DEV            *TerminalDevice;\r
+\r
+  TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);\r
+\r
+  Status = TerminalDevice->SimpleInput.Reset (&TerminalDevice->SimpleInput, ExtendedVerification);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+/**\r
+  Reads the next keystroke from the input device. The WaitForKey Event can\r
+  be used to test for existence of a keystroke via WaitForEvent () call.\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  KeyData                  A pointer to a buffer that is filled in with the\r
+                                   keystroke state data for the key that was\r
+                                   pressed.\r
+\r
+  @retval EFI_SUCCESS              The keystroke information was returned.\r
+  @retval EFI_NOT_READY            There was no keystroke data available.\r
+  @retval EFI_DEVICE_ERROR         The keystroke information was not returned due\r
+                                   to hardware errors.\r
+  @retval EFI_INVALID_PARAMETER    KeyData is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TerminalConInReadKeyStrokeEx (\r
+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
+  OUT EFI_KEY_DATA                      *KeyData\r
+  )\r
+{\r
+  TERMINAL_DEV                    *TerminalDevice;\r
+\r
+  if (KeyData == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);\r
+\r
+  return ReadKeyStrokeWorker (TerminalDevice, KeyData);\r
+\r
+}\r
+\r
+\r
+/**\r
+  Set certain state for the input device.\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  KeyToggleState           A pointer to the EFI_KEY_TOGGLE_STATE to set the\r
+                                   state for the input device.\r
+\r
+  @retval EFI_SUCCESS              The device state was set successfully.\r
+  @retval EFI_DEVICE_ERROR         The device is not functioning correctly and\r
+                                   could not have the setting adjusted.\r
+  @retval EFI_UNSUPPORTED          The device does not have the ability to set its\r
+                                   state.\r
+  @retval EFI_INVALID_PARAMETER    KeyToggleState is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TerminalConInSetState (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_KEY_TOGGLE_STATE               *KeyToggleState\r
+  )\r
+{\r
+  if (KeyToggleState == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Register a notification function for a particular keystroke for the input device.\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  KeyData                  A pointer to a buffer that is filled in with\r
+                                   the keystroke information for the key that was\r
+                                   pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState\r
+                                   and KeyData.KeyState.KeyShiftState are 0, then any incomplete\r
+                                   keystroke will trigger a notification of the KeyNotificationFunction.\r
+  @param  KeyNotificationFunction  Points to the function to be called when the key\r
+                                   sequence is typed specified by KeyData. This notification function\r
+                                   should be called at <=TPL_CALLBACK.\r
+  @param  NotifyHandle             Points to the unique handle assigned to the\r
+                                   registered notification.\r
+\r
+  @retval EFI_SUCCESS              The notification function was registered\r
+                                   successfully.\r
+  @retval EFI_OUT_OF_RESOURCES     Unable to allocate resources for necessary data\r
+                                   structures.\r
+  @retval EFI_INVALID_PARAMETER    KeyData or NotifyHandle is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TerminalConInRegisterKeyNotify (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_KEY_DATA                       *KeyData,\r
+  IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,\r
+  OUT VOID                              **NotifyHandle\r
+  )\r
+{\r
+  TERMINAL_DEV                    *TerminalDevice;\r
+  TERMINAL_CONSOLE_IN_EX_NOTIFY   *NewNotify;\r
+  LIST_ENTRY                      *Link;\r
+  LIST_ENTRY                      *NotifyList;\r
+  TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;\r
+\r
+  if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);\r
+\r
+  //\r
+  // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.\r
+  //\r
+  NotifyList = &TerminalDevice->NotifyList;\r
+  for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {\r
+    CurrentNotify = CR (\r
+                      Link,\r
+                      TERMINAL_CONSOLE_IN_EX_NOTIFY,\r
+                      NotifyEntry,\r
+                      TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
+                      );\r
+    if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {\r
+      if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {\r
+        *NotifyHandle = CurrentNotify;\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Allocate resource to save the notification function\r
+  //\r
+  NewNotify = (TERMINAL_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (TERMINAL_CONSOLE_IN_EX_NOTIFY));\r
+  if (NewNotify == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NewNotify->Signature         = TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE;\r
+  NewNotify->KeyNotificationFn = KeyNotificationFunction;\r
+  CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));\r
+  InsertTailList (&TerminalDevice->NotifyList, &NewNotify->NotifyEntry);\r
+\r
+  *NotifyHandle                = NewNotify;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Remove a registered notification function from a particular keystroke.\r
+\r
+  @param  This                     Protocol instance pointer.\r
+  @param  NotificationHandle       The handle of the notification function being\r
+                                   unregistered.\r
+\r
+  @retval EFI_SUCCESS              The notification function was unregistered\r
+                                   successfully.\r
+  @retval EFI_INVALID_PARAMETER    The NotificationHandle is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TerminalConInUnregisterKeyNotify (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN VOID                               *NotificationHandle\r
+  )\r
+{\r
+  TERMINAL_DEV                    *TerminalDevice;\r
+  LIST_ENTRY                      *Link;\r
+  TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;\r
+  LIST_ENTRY                      *NotifyList;\r
+\r
+  if (NotificationHandle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);\r
+\r
+  NotifyList = &TerminalDevice->NotifyList;\r
+  for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {\r
+    CurrentNotify = CR (\r
+                      Link,\r
+                      TERMINAL_CONSOLE_IN_EX_NOTIFY,\r
+                      NotifyEntry,\r
+                      TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
+                      );\r
+    if (CurrentNotify == NotificationHandle) {\r
+      //\r
+      // Remove the notification function from NotifyList and free resources\r
+      //\r
+      RemoveEntryList (&CurrentNotify->NotifyEntry);\r
+\r
+      gBS->FreePool (CurrentNotify);\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Can not find the matching entry in database.\r
+  //\r
+  return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+/**\r
+  Translate raw data into Unicode (according to different encode), and\r
+  translate Unicode into key information. (according to different standard).\r
+\r
+  @param  TerminalDevice       Terminal driver private structure.\r
+\r
+**/\r
+VOID\r
+TranslateRawDataToEfiKey (\r
+  IN  TERMINAL_DEV      *TerminalDevice\r
+  )\r
+{\r
+  switch (TerminalDevice->TerminalType) {\r
+\r
+  case TerminalTypePcAnsi:\r
+  case TerminalTypeVt100:\r
+  case TerminalTypeVt100Plus:\r
+  case TerminalTypeTtyTerm:\r
+    AnsiRawDataToUnicode (TerminalDevice);\r
+    UnicodeToEfiKey (TerminalDevice);\r
+    break;\r
+\r
+  case TerminalTypeVtUtf8:\r
+    //\r
+    // Process all the raw data in the RawFIFO,\r
+    // put the processed key into UnicodeFIFO.\r
+    //\r
+    VTUTF8RawDataToUnicode (TerminalDevice);\r
+\r
+    //\r
+    // Translate all the Unicode data in the UnicodeFIFO to Efi key,\r
+    // then put into EfiKeyFIFO.\r
+    //\r
+    UnicodeToEfiKey (TerminalDevice);\r
+\r
+    break;\r
+  }\r
+}\r
+\r
+/**\r
+  Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event\r
+  Signal the event if there is key available\r
+\r
+  @param  Event                    Indicates the event that invoke this function.\r
+  @param  Context                  Indicates the calling context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TerminalConInWaitForKey (\r
+  IN  EFI_EVENT       Event,\r
+  IN  VOID            *Context\r
+  )\r
+{\r
+  //\r
+  // Someone is waiting on the keystroke event, if there's\r
+  // a key pending, signal the event\r
+  //\r
+  if (!IsEfiKeyFiFoEmpty ((TERMINAL_DEV *) Context)) {\r
+\r
+    gBS->SignalEvent (Event);\r
+  }\r
+}\r
+\r
+/**\r
+  Timer handler to poll the key from serial.\r
+\r
+  @param  Event                    Indicates the event that invoke this function.\r
+  @param  Context                  Indicates the calling context.\r
+**/\r
+VOID\r
+EFIAPI\r
+TerminalConInTimerHandler (\r
+  IN EFI_EVENT            Event,\r
+  IN VOID                 *Context\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  TERMINAL_DEV            *TerminalDevice;\r
+  UINT32                  Control;\r
+  UINT8                   Input;\r
+  EFI_SERIAL_IO_MODE      *Mode;\r
+  EFI_SERIAL_IO_PROTOCOL  *SerialIo;\r
+  UINTN                   SerialInTimeOut;\r
+\r
+  TerminalDevice  = (TERMINAL_DEV *) Context;\r
+\r
+  SerialIo        = TerminalDevice->SerialIo;\r
+  if (SerialIo == NULL) {\r
+    return ;\r
+  }\r
+  //\r
+  //  if current timeout value for serial device is not identical with\r
+  //  the value saved in TERMINAL_DEV structure, then recalculate the\r
+  //  timeout value again and set serial attribute according to this value.\r
+  //\r
+  Mode = SerialIo->Mode;\r
+  if (Mode->Timeout != TerminalDevice->SerialInTimeOut) {\r
+\r
+    SerialInTimeOut = 0;\r
+    if (Mode->BaudRate != 0) {\r
+      //\r
+      // According to BAUD rate to calculate the timeout value.\r
+      //\r
+      SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;\r
+    }\r
+\r
+    Status = SerialIo->SetAttributes (\r
+                        SerialIo,\r
+                        Mode->BaudRate,\r
+                        Mode->ReceiveFifoDepth,\r
+                        (UINT32) SerialInTimeOut,\r
+                        (EFI_PARITY_TYPE) (Mode->Parity),\r
+                        (UINT8) Mode->DataBits,\r
+                        (EFI_STOP_BITS_TYPE) (Mode->StopBits)\r
+                        );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      TerminalDevice->SerialInTimeOut = 0;\r
+    } else {\r
+      TerminalDevice->SerialInTimeOut = SerialInTimeOut;\r
+    }\r
+  }\r
+  //\r
+  // Check whether serial buffer is empty.\r
+  // Skip the key transfer loop only if the SerialIo protocol instance\r
+  // successfully reports EFI_SERIAL_INPUT_BUFFER_EMPTY.\r
+  //\r
+  Status = SerialIo->GetControl (SerialIo, &Control);\r
+  if (EFI_ERROR (Status) || ((Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) == 0)) {\r
+    //\r
+    // Fetch all the keys in the serial buffer,\r
+    // and insert the byte stream into RawFIFO.\r
+    //\r
+    while (!IsRawFiFoFull (TerminalDevice)) {\r
+\r
+      Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        if (Status == EFI_DEVICE_ERROR) {\r
+          REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+            EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+            (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_INPUT_ERROR),\r
+            TerminalDevice->DevicePath\r
+            );\r
+        }\r
+        break;\r
+      }\r
+\r
+      RawFiFoInsertOneKey (TerminalDevice, Input);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Translate all the raw data in RawFIFO into EFI Key,\r
+  // according to different terminal type supported.\r
+  //\r
+  TranslateRawDataToEfiKey (TerminalDevice);\r
+}\r
+\r
+/**\r
+  Process key notify.\r
+\r
+  @param  Event                 Indicates the event that invoke this function.\r
+  @param  Context               Indicates the calling context.\r
+**/\r
+VOID\r
+EFIAPI\r
+KeyNotifyProcessHandler (\r
+  IN  EFI_EVENT                 Event,\r
+  IN  VOID                      *Context\r
+  )\r
+{\r
+  BOOLEAN                       HasKey;\r
+  TERMINAL_DEV                  *TerminalDevice;\r
+  EFI_INPUT_KEY                 Key;\r
+  EFI_KEY_DATA                  KeyData;\r
+  LIST_ENTRY                    *Link;\r
+  LIST_ENTRY                    *NotifyList;\r
+  TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
+  EFI_TPL                       OldTpl;\r
+\r
+  TerminalDevice = (TERMINAL_DEV *) Context;\r
+\r
+  //\r
+  // Invoke notification functions.\r
+  //\r
+  NotifyList = &TerminalDevice->NotifyList;\r
+  while (TRUE) {\r
+    //\r
+    // Enter critical section\r
+    //\r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+    HasKey = EfiKeyFiFoForNotifyRemoveOneKey (TerminalDevice->EfiKeyFiFoForNotify, &Key);\r
+    CopyMem (&KeyData.Key, &Key, sizeof (EFI_INPUT_KEY));\r
+    KeyData.KeyState.KeyShiftState  = 0;\r
+    KeyData.KeyState.KeyToggleState = 0;\r
+    //\r
+    // Leave critical section\r
+    //\r
+    gBS->RestoreTPL (OldTpl);\r
+    if (!HasKey) {\r
+      break;\r
+    }\r
+    for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {\r
+      CurrentNotify = CR (Link, TERMINAL_CONSOLE_IN_EX_NOTIFY, NotifyEntry, TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE);\r
+      if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
+        CurrentNotify->KeyNotificationFn (&KeyData);\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Get one key out of serial buffer.\r
+\r
+  @param  SerialIo           Serial I/O protocol attached to the serial device.\r
+  @param  Output             The fetched key.\r
+\r
+  @retval EFI_NOT_READY      If serial buffer is empty.\r
+  @retval EFI_DEVICE_ERROR   If reading serial buffer encounter error.\r
+  @retval EFI_SUCCESS        If reading serial buffer successfully, put\r
+                             the fetched key to the parameter output.\r
+\r
+**/\r
+EFI_STATUS\r
+GetOneKeyFromSerial (\r
+  EFI_SERIAL_IO_PROTOCOL  *SerialIo,\r
+  UINT8                   *Output\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       Size;\r
+\r
+  Size    = 1;\r
+  *Output = 0;\r
+\r
+  //\r
+  // Read one key from serial I/O device.\r
+  //\r
+  Status  = SerialIo->Read (SerialIo, &Size, Output);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+\r
+    if (Status == EFI_TIMEOUT) {\r
+      return EFI_NOT_READY;\r
+    }\r
+\r
+    return EFI_DEVICE_ERROR;\r
+\r
+  }\r
+\r
+  if (*Output == 0) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Insert one byte raw data into the Raw Data FIFO.\r
+\r
+  @param  TerminalDevice       Terminal driver private structure.\r
+  @param  Input                The key will be input.\r
+\r
+  @retval TRUE                 If insert successfully.\r
+  @retval FALSE                If Raw Data buffer is full before key insertion,\r
+                               and the key is lost.\r
+\r
+**/\r
+BOOLEAN\r
+RawFiFoInsertOneKey (\r
+  TERMINAL_DEV      *TerminalDevice,\r
+  UINT8             Input\r
+  )\r
+{\r
+  UINT8 Tail;\r
+\r
+  Tail = TerminalDevice->RawFiFo->Tail;\r
+\r
+  if (IsRawFiFoFull (TerminalDevice)) {\r
+    //\r
+    // Raw FIFO is full\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  TerminalDevice->RawFiFo->Data[Tail]  = Input;\r
+\r
+  TerminalDevice->RawFiFo->Tail        = (UINT8) ((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1));\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Remove one pre-fetched key out of the Raw Data FIFO.\r
+\r
+  @param  TerminalDevice       Terminal driver private structure.\r
+  @param  Output               The key will be removed.\r
+\r
+  @retval TRUE                 If insert successfully.\r
+  @retval FALSE                If Raw Data FIFO buffer is empty before remove operation.\r
+\r
+**/\r
+BOOLEAN\r
+RawFiFoRemoveOneKey (\r
+  TERMINAL_DEV  *TerminalDevice,\r
+  UINT8         *Output\r
+  )\r
+{\r
+  UINT8 Head;\r
+\r
+  Head = TerminalDevice->RawFiFo->Head;\r
+\r
+  if (IsRawFiFoEmpty (TerminalDevice)) {\r
+    //\r
+    //  FIFO is empty\r
+    //\r
+    *Output = 0;\r
+    return FALSE;\r
+  }\r
+\r
+  *Output                       = TerminalDevice->RawFiFo->Data[Head];\r
+\r
+  TerminalDevice->RawFiFo->Head  = (UINT8) ((Head + 1) % (RAW_FIFO_MAX_NUMBER + 1));\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Clarify whether Raw Data FIFO buffer is empty.\r
+\r
+  @param  TerminalDevice       Terminal driver private structure\r
+\r
+  @retval TRUE                 If Raw Data FIFO buffer is empty.\r
+  @retval FALSE                If Raw Data FIFO buffer is not empty.\r
+\r
+**/\r
+BOOLEAN\r
+IsRawFiFoEmpty (\r
+  TERMINAL_DEV  *TerminalDevice\r
+  )\r
+{\r
+  if (TerminalDevice->RawFiFo->Head == TerminalDevice->RawFiFo->Tail) {\r
+    return TRUE;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+  Clarify whether Raw Data FIFO buffer is full.\r
+\r
+  @param  TerminalDevice       Terminal driver private structure\r
+\r
+  @retval TRUE                 If Raw Data FIFO buffer is full.\r
+  @retval FALSE                If Raw Data FIFO buffer is not full.\r
+\r
+**/\r
+BOOLEAN\r
+IsRawFiFoFull (\r
+  TERMINAL_DEV  *TerminalDevice\r
+  )\r
+{\r
+  UINT8 Tail;\r
+  UINT8 Head;\r
+\r
+  Tail  = TerminalDevice->RawFiFo->Tail;\r
+  Head  = TerminalDevice->RawFiFo->Head;\r
+\r
+  if (((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)) == Head) {\r
+\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Insert one pre-fetched key into the FIFO buffer.\r
+\r
+  @param  EfiKeyFiFo            Pointer to instance of EFI_KEY_FIFO.\r
+  @param  Input                 The key will be input.\r
+\r
+  @retval TRUE                  If insert successfully.\r
+  @retval FALSE                 If FIFO buffer is full before key insertion,\r
+                                and the key is lost.\r
+\r
+**/\r
+BOOLEAN\r
+EfiKeyFiFoForNotifyInsertOneKey (\r
+  EFI_KEY_FIFO                  *EfiKeyFiFo,\r
+  EFI_INPUT_KEY                 *Input\r
+  )\r
+{\r
+  UINT8                         Tail;\r
+\r
+  Tail = EfiKeyFiFo->Tail;\r
+\r
+  if (IsEfiKeyFiFoForNotifyFull (EfiKeyFiFo)) {\r
+    //\r
+    // FIFO is full\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  CopyMem (&EfiKeyFiFo->Data[Tail], Input, sizeof (EFI_INPUT_KEY));\r
+\r
+  EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Remove one pre-fetched key out of the FIFO buffer.\r
+\r
+  @param  EfiKeyFiFo            Pointer to instance of EFI_KEY_FIFO.\r
+  @param  Output                The key will be removed.\r
+\r
+  @retval TRUE                  If remove successfully.\r
+  @retval FALSE                 If FIFO buffer is empty before remove operation.\r
+\r
+**/\r
+BOOLEAN\r
+EfiKeyFiFoForNotifyRemoveOneKey (\r
+  EFI_KEY_FIFO                  *EfiKeyFiFo,\r
+  EFI_INPUT_KEY                 *Output\r
+  )\r
+{\r
+  UINT8                         Head;\r
+\r
+  Head = EfiKeyFiFo->Head;\r
+  ASSERT (Head < FIFO_MAX_NUMBER + 1);\r
+\r
+  if (IsEfiKeyFiFoForNotifyEmpty (EfiKeyFiFo)) {\r
+    //\r
+    // FIFO is empty\r
+    //\r
+    Output->ScanCode    = SCAN_NULL;\r
+    Output->UnicodeChar = 0;\r
+    return FALSE;\r
+  }\r
+\r
+  CopyMem (Output, &EfiKeyFiFo->Data[Head], sizeof (EFI_INPUT_KEY));\r
+\r
+  EfiKeyFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Clarify whether FIFO buffer is empty.\r
+\r
+  @param  EfiKeyFiFo            Pointer to instance of EFI_KEY_FIFO.\r
+\r
+  @retval TRUE                  If FIFO buffer is empty.\r
+  @retval FALSE                 If FIFO buffer is not empty.\r
+\r
+**/\r
+BOOLEAN\r
+IsEfiKeyFiFoForNotifyEmpty (\r
+  EFI_KEY_FIFO                  *EfiKeyFiFo\r
+  )\r
+{\r
+  if (EfiKeyFiFo->Head == EfiKeyFiFo->Tail) {\r
+    return TRUE;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+  Clarify whether FIFO buffer is full.\r
+\r
+  @param  EfiKeyFiFo            Pointer to instance of EFI_KEY_FIFO.\r
+\r
+  @retval TRUE                  If FIFO buffer is full.\r
+  @retval FALSE                 If FIFO buffer is not full.\r
+\r
+**/\r
+BOOLEAN\r
+IsEfiKeyFiFoForNotifyFull (\r
+  EFI_KEY_FIFO                  *EfiKeyFiFo\r
+  )\r
+{\r
+  UINT8                         Tail;\r
+  UINT8                         Head;\r
+\r
+  Tail = EfiKeyFiFo->Tail;\r
+  Head = EfiKeyFiFo->Head;\r
+\r
+  if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Insert one pre-fetched key into the FIFO buffer.\r
+\r
+  @param  TerminalDevice       Terminal driver private structure.\r
+  @param  Key                  The key will be input.\r
+\r
+  @retval TRUE                 If insert successfully.\r
+  @retval FALSE                If FIFO buffer is full before key insertion,\r
+                               and the key is lost.\r
+\r
+**/\r
+BOOLEAN\r
+EfiKeyFiFoInsertOneKey (\r
+  TERMINAL_DEV                    *TerminalDevice,\r
+  EFI_INPUT_KEY                   *Key\r
+  )\r
+{\r
+  UINT8                           Tail;\r
+  LIST_ENTRY                      *Link;\r
+  LIST_ENTRY                      *NotifyList;\r
+  TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;\r
+  EFI_KEY_DATA                    KeyData;\r
+\r
+  Tail = TerminalDevice->EfiKeyFiFo->Tail;\r
+\r
+  CopyMem (&KeyData.Key, Key, sizeof (EFI_INPUT_KEY));\r
+  KeyData.KeyState.KeyShiftState  = 0;\r
+  KeyData.KeyState.KeyToggleState = 0;\r
+\r
+  //\r
+  // Signal KeyNotify process event if this key pressed matches any key registered.\r
+  //\r
+  NotifyList = &TerminalDevice->NotifyList;\r
+  for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {\r
+    CurrentNotify = CR (\r
+                      Link,\r
+                      TERMINAL_CONSOLE_IN_EX_NOTIFY,\r
+                      NotifyEntry,\r
+                      TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
+                      );\r
+    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
+      //\r
+      // The key notification function needs to run at TPL_CALLBACK\r
+      // while current TPL is TPL_NOTIFY. It will be invoked in\r
+      // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.\r
+      //\r
+      EfiKeyFiFoForNotifyInsertOneKey (TerminalDevice->EfiKeyFiFoForNotify, Key);\r
+      gBS->SignalEvent (TerminalDevice->KeyNotifyProcessEvent);\r
+      break;\r
+    }\r
+  }\r
+  if (IsEfiKeyFiFoFull (TerminalDevice)) {\r
+    //\r
+    // Efi Key FIFO is full\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  CopyMem (&TerminalDevice->EfiKeyFiFo->Data[Tail], Key, sizeof (EFI_INPUT_KEY));\r
+\r
+  TerminalDevice->EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Remove one pre-fetched key out of the FIFO buffer.\r
+\r
+  @param  TerminalDevice       Terminal driver private structure.\r
+  @param  Output               The key will be removed.\r
+\r
+  @retval TRUE                 If insert successfully.\r
+  @retval FALSE                If FIFO buffer is empty before remove operation.\r
+\r
+**/\r
+BOOLEAN\r
+EfiKeyFiFoRemoveOneKey (\r
+  TERMINAL_DEV  *TerminalDevice,\r
+  EFI_INPUT_KEY *Output\r
+  )\r
+{\r
+  UINT8 Head;\r
+\r
+  Head = TerminalDevice->EfiKeyFiFo->Head;\r
+  ASSERT (Head < FIFO_MAX_NUMBER + 1);\r
+\r
+  if (IsEfiKeyFiFoEmpty (TerminalDevice)) {\r
+    //\r
+    //  FIFO is empty\r
+    //\r
+    Output->ScanCode    = SCAN_NULL;\r
+    Output->UnicodeChar = 0;\r
+    return FALSE;\r
+  }\r
+\r
+  CopyMem (Output, &TerminalDevice->EfiKeyFiFo->Data[Head], sizeof (EFI_INPUT_KEY));\r
+\r
+  TerminalDevice->EfiKeyFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Clarify whether FIFO buffer is empty.\r
+\r
+  @param  TerminalDevice       Terminal driver private structure\r
+\r
+  @retval TRUE                 If FIFO buffer is empty.\r
+  @retval FALSE                If FIFO buffer is not empty.\r
+\r
+**/\r
+BOOLEAN\r
+IsEfiKeyFiFoEmpty (\r
+  TERMINAL_DEV  *TerminalDevice\r
+  )\r
+{\r
+  if (TerminalDevice->EfiKeyFiFo->Head == TerminalDevice->EfiKeyFiFo->Tail) {\r
+    return TRUE;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+  Clarify whether FIFO buffer is full.\r
+\r
+  @param  TerminalDevice       Terminal driver private structure\r
+\r
+  @retval TRUE                 If FIFO buffer is full.\r
+  @retval FALSE                If FIFO buffer is not full.\r
+\r
+**/\r
+BOOLEAN\r
+IsEfiKeyFiFoFull (\r
+  TERMINAL_DEV  *TerminalDevice\r
+  )\r
+{\r
+  UINT8 Tail;\r
+  UINT8 Head;\r
+\r
+  Tail  = TerminalDevice->EfiKeyFiFo->Tail;\r
+  Head  = TerminalDevice->EfiKeyFiFo->Head;\r
+\r
+  if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {\r
+\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Insert one pre-fetched key into the Unicode FIFO buffer.\r
+\r
+  @param  TerminalDevice       Terminal driver private structure.\r
+  @param  Input                The key will be input.\r
+\r
+  @retval TRUE                 If insert successfully.\r
+  @retval FALSE                If Unicode FIFO buffer is full before key insertion,\r
+                               and the key is lost.\r
+\r
+**/\r
+BOOLEAN\r
+UnicodeFiFoInsertOneKey (\r
+  TERMINAL_DEV      *TerminalDevice,\r
+  UINT16            Input\r
+  )\r
+{\r
+  UINT8 Tail;\r
+\r
+  Tail = TerminalDevice->UnicodeFiFo->Tail;\r
+  ASSERT (Tail < FIFO_MAX_NUMBER + 1);\r
+\r
+\r
+  if (IsUnicodeFiFoFull (TerminalDevice)) {\r
+    //\r
+    // Unicode FIFO is full\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  TerminalDevice->UnicodeFiFo->Data[Tail]  = Input;\r
+\r
+  TerminalDevice->UnicodeFiFo->Tail        = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Remove one pre-fetched key out of the Unicode FIFO buffer.\r
+  The caller should guarantee that Unicode FIFO buffer is not empty\r
+  by IsUnicodeFiFoEmpty ().\r
+\r
+  @param  TerminalDevice       Terminal driver private structure.\r
+  @param  Output               The key will be removed.\r
+\r
+**/\r
+VOID\r
+UnicodeFiFoRemoveOneKey (\r
+  TERMINAL_DEV  *TerminalDevice,\r
+  UINT16        *Output\r
+  )\r
+{\r
+  UINT8 Head;\r
+\r
+  Head = TerminalDevice->UnicodeFiFo->Head;\r
+  ASSERT (Head < FIFO_MAX_NUMBER + 1);\r
+\r
+  *Output = TerminalDevice->UnicodeFiFo->Data[Head];\r
+\r
+  TerminalDevice->UnicodeFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));\r
+}\r
+\r
+/**\r
+  Clarify whether Unicode FIFO buffer is empty.\r
+\r
+  @param  TerminalDevice       Terminal driver private structure\r
+\r
+  @retval TRUE                 If Unicode FIFO buffer is empty.\r
+  @retval FALSE                If Unicode FIFO buffer is not empty.\r
+\r
+**/\r
+BOOLEAN\r
+IsUnicodeFiFoEmpty (\r
+  TERMINAL_DEV  *TerminalDevice\r
+  )\r
+{\r
+  if (TerminalDevice->UnicodeFiFo->Head == TerminalDevice->UnicodeFiFo->Tail) {\r
+    return TRUE;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+  Clarify whether Unicode FIFO buffer is full.\r
+\r
+  @param  TerminalDevice       Terminal driver private structure\r
+\r
+  @retval TRUE                 If Unicode FIFO buffer is full.\r
+  @retval FALSE                If Unicode FIFO buffer is not full.\r
+\r
+**/\r
+BOOLEAN\r
+IsUnicodeFiFoFull (\r
+  TERMINAL_DEV  *TerminalDevice\r
+  )\r
+{\r
+  UINT8 Tail;\r
+  UINT8 Head;\r
+\r
+  Tail  = TerminalDevice->UnicodeFiFo->Tail;\r
+  Head  = TerminalDevice->UnicodeFiFo->Head;\r
+\r
+  if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {\r
+\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Update the Unicode characters from a terminal input device into EFI Keys FIFO.\r
+\r
+  @param TerminalDevice   The terminal device to use to translate raw input into EFI Keys\r
+\r
+**/\r
+VOID\r
+UnicodeToEfiKeyFlushState (\r
+  IN  TERMINAL_DEV    *TerminalDevice\r
+  )\r
+{\r
+  EFI_INPUT_KEY Key;\r
+  UINT32        InputState;\r
+\r
+  InputState = TerminalDevice->InputState;\r
+\r
+  if (IsEfiKeyFiFoFull (TerminalDevice)) {\r
+    return;\r
+  }\r
+\r
+  if ((InputState & INPUT_STATE_ESC) != 0) {\r
+    Key.ScanCode    = SCAN_ESC;\r
+    Key.UnicodeChar = 0;\r
+    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);\r
+  }\r
+\r
+  if ((InputState & INPUT_STATE_CSI) != 0) {\r
+    Key.ScanCode    = SCAN_NULL;\r
+    Key.UnicodeChar = CSI;\r
+    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);\r
+  }\r
+\r
+  if ((InputState & INPUT_STATE_LEFTOPENBRACKET) != 0) {\r
+    Key.ScanCode    = SCAN_NULL;\r
+    Key.UnicodeChar = LEFTOPENBRACKET;\r
+    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);\r
+  }\r
+\r
+  if ((InputState & INPUT_STATE_O) != 0) {\r
+    Key.ScanCode    = SCAN_NULL;\r
+    Key.UnicodeChar = 'O';\r
+    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);\r
+  }\r
+\r
+  if ((InputState & INPUT_STATE_2) != 0) {\r
+    Key.ScanCode    = SCAN_NULL;\r
+    Key.UnicodeChar = '2';\r
+    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);\r
+  }\r
+\r
+  //\r
+  // Cancel the timer.\r
+  //\r
+  gBS->SetTimer (\r
+        TerminalDevice->TwoSecondTimeOut,\r
+        TimerCancel,\r
+        0\r
+        );\r
+\r
+  TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
+}\r
+\r
+\r
+/**\r
+  Converts a stream of Unicode characters from a terminal input device into EFI Keys that\r
+  can be read through the Simple Input Protocol.\r
+\r
+  The table below shows the keyboard input mappings that this function supports.\r
+  If the ESC sequence listed in one of the columns is presented, then it is translated\r
+  into the corresponding EFI Scan Code.  If a matching sequence is not found, then the raw\r
+  key strokes are converted into EFI Keys.\r
+\r
+  2 seconds are allowed for an ESC sequence to be completed.  If the ESC sequence is not\r
+  completed in 2 seconds, then the raw key strokes of the partial ESC sequence are\r
+  converted into EFI Keys.\r
+  There is one special input sequence that will force the system to reset.\r
+  This is ESC R ESC r ESC R.\r
+\r
+  Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100.\r
+        The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 /\r
+        DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example.\r
+\r
+  Symbols used in table below\r
+  ===========================\r
+    ESC = 0x1B\r
+    CSI = 0x9B\r
+    DEL = 0x7f\r
+    ^   = CTRL\r
+\r
+  +=========+======+===========+==========+==========+\r
+  |         | EFI  | UEFI 2.0  |          |          |\r
+  |         | Scan |           |  VT100+  |          |\r
+  |   KEY   | Code |  PC ANSI  |  VTUTF8  |   VT100  |\r
+  +=========+======+===========+==========+==========+\r
+  | NULL    | 0x00 |           |          |          |\r
+  | UP      | 0x01 | ESC [ A   | ESC [ A  | ESC [ A  |\r
+  | DOWN    | 0x02 | ESC [ B   | ESC [ B  | ESC [ B  |\r
+  | RIGHT   | 0x03 | ESC [ C   | ESC [ C  | ESC [ C  |\r
+  | LEFT    | 0x04 | ESC [ D   | ESC [ D  | ESC [ D  |\r
+  | HOME    | 0x05 | ESC [ H   | ESC h    | ESC [ H  |\r
+  | END     | 0x06 | ESC [ F   | ESC k    | ESC [ K  |\r
+  | INSERT  | 0x07 | ESC [ @   | ESC +    | ESC [ @  |\r
+  |         |      | ESC [ L   |          | ESC [ L  |\r
+  | DELETE  | 0x08 | ESC [ X   | ESC -    | ESC [ P  |\r
+  | PG UP   | 0x09 | ESC [ I   | ESC ?    | ESC [ V  |\r
+  |         |      |           |          | ESC [ ?  |\r
+  | PG DOWN | 0x0A | ESC [ G   | ESC /    | ESC [ U  |\r
+  |         |      |           |          | ESC [ /  |\r
+  | F1      | 0x0B | ESC [ M   | ESC 1    | ESC O P  |\r
+  | F2      | 0x0C | ESC [ N   | ESC 2    | ESC O Q  |\r
+  | F3      | 0x0D | ESC [ O   | ESC 3    | ESC O w  |\r
+  | F4      | 0x0E | ESC [ P   | ESC 4    | ESC O x  |\r
+  | F5      | 0x0F | ESC [ Q   | ESC 5    | ESC O t  |\r
+  | F6      | 0x10 | ESC [ R   | ESC 6    | ESC O u  |\r
+  | F7      | 0x11 | ESC [ S   | ESC 7    | ESC O q  |\r
+  | F8      | 0x12 | ESC [ T   | ESC 8    | ESC O r  |\r
+  | F9      | 0x13 | ESC [ U   | ESC 9    | ESC O p  |\r
+  | F10     | 0x14 | ESC [ V   | ESC 0    | ESC O M  |\r
+  | Escape  | 0x17 | ESC       | ESC      | ESC      |\r
+  | F11     | 0x15 |           | ESC !    |          |\r
+  | F12     | 0x16 |           | ESC @    |          |\r
+  +=========+======+===========+==========+==========+\r
+\r
+  Special Mappings\r
+  ================\r
+  ESC R ESC r ESC R = Reset System\r
+\r
+  @param TerminalDevice   The terminal device to use to translate raw input into EFI Keys\r
+\r
+**/\r
+VOID\r
+UnicodeToEfiKey (\r
+  IN  TERMINAL_DEV    *TerminalDevice\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  EFI_STATUS          TimerStatus;\r
+  UINT16              UnicodeChar;\r
+  EFI_INPUT_KEY       Key;\r
+  BOOLEAN             SetDefaultResetState;\r
+\r
+  TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);\r
+\r
+  if (!EFI_ERROR (TimerStatus)) {\r
+    UnicodeToEfiKeyFlushState (TerminalDevice);\r
+    TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
+  }\r
+\r
+  while (!IsUnicodeFiFoEmpty (TerminalDevice) && !IsEfiKeyFiFoFull (TerminalDevice)) {\r
+\r
+    if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {\r
+      //\r
+      // Check to see if the 2 seconds timer has expired\r
+      //\r
+      TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);\r
+      if (!EFI_ERROR (TimerStatus)) {\r
+        UnicodeToEfiKeyFlushState (TerminalDevice);\r
+        TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Fetch one Unicode character from the Unicode FIFO\r
+    //\r
+    UnicodeFiFoRemoveOneKey (TerminalDevice, &UnicodeChar);\r
+\r
+    SetDefaultResetState = TRUE;\r
+\r
+    switch (TerminalDevice->InputState) {\r
+    case INPUT_STATE_DEFAULT:\r
+\r
+      break;\r
+\r
+    case INPUT_STATE_ESC:\r
+\r
+      if (UnicodeChar == LEFTOPENBRACKET) {\r
+        TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET;\r
+        TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
+        continue;\r
+      }\r
+\r
+      if (UnicodeChar == 'O' && (TerminalDevice->TerminalType == TerminalTypeVt100 ||\r
+                                 TerminalDevice->TerminalType == TerminalTypeTtyTerm)) {\r
+        TerminalDevice->InputState |= INPUT_STATE_O;\r
+        TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
+        continue;\r
+      }\r
+\r
+      Key.ScanCode = SCAN_NULL;\r
+\r
+      if (TerminalDevice->TerminalType == TerminalTypeVt100Plus ||\r
+          TerminalDevice->TerminalType == TerminalTypeVtUtf8) {\r
+        switch (UnicodeChar) {\r
+        case '1':\r
+          Key.ScanCode = SCAN_F1;\r
+          break;\r
+        case '2':\r
+          Key.ScanCode = SCAN_F2;\r
+          break;\r
+        case '3':\r
+          Key.ScanCode = SCAN_F3;\r
+          break;\r
+        case '4':\r
+          Key.ScanCode = SCAN_F4;\r
+          break;\r
+        case '5':\r
+          Key.ScanCode = SCAN_F5;\r
+          break;\r
+        case '6':\r
+          Key.ScanCode = SCAN_F6;\r
+          break;\r
+        case '7':\r
+          Key.ScanCode = SCAN_F7;\r
+          break;\r
+        case '8':\r
+          Key.ScanCode = SCAN_F8;\r
+          break;\r
+        case '9':\r
+          Key.ScanCode = SCAN_F9;\r
+          break;\r
+        case '0':\r
+          Key.ScanCode = SCAN_F10;\r
+          break;\r
+        case '!':\r
+          Key.ScanCode = SCAN_F11;\r
+          break;\r
+        case '@':\r
+          Key.ScanCode = SCAN_F12;\r
+          break;\r
+        case 'h':\r
+          Key.ScanCode = SCAN_HOME;\r
+          break;\r
+        case 'k':\r
+          Key.ScanCode = SCAN_END;\r
+          break;\r
+        case '+':\r
+          Key.ScanCode = SCAN_INSERT;\r
+          break;\r
+        case '-':\r
+          Key.ScanCode = SCAN_DELETE;\r
+          break;\r
+        case '/':\r
+          Key.ScanCode = SCAN_PAGE_DOWN;\r
+          break;\r
+        case '?':\r
+          Key.ScanCode = SCAN_PAGE_UP;\r
+          break;\r
+        default :\r
+          break;\r
+        }\r
+      }\r
+\r
+      switch (UnicodeChar) {\r
+      case 'R':\r
+        if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) {\r
+          TerminalDevice->ResetState = RESET_STATE_ESC_R;\r
+          SetDefaultResetState = FALSE;\r
+        } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_R) {\r
+          gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
+        }\r
+        Key.ScanCode = SCAN_NULL;\r
+        break;\r
+      case 'r':\r
+        if (TerminalDevice->ResetState == RESET_STATE_ESC_R) {\r
+          TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_R;\r
+          SetDefaultResetState = FALSE;\r
+        }\r
+        Key.ScanCode = SCAN_NULL;\r
+        break;\r
+      default :\r
+        break;\r
+      }\r
+\r
+      if (SetDefaultResetState) {\r
+        TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
+      }\r
+\r
+      if (Key.ScanCode != SCAN_NULL) {\r
+        Key.UnicodeChar = 0;\r
+        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);\r
+        TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
+        UnicodeToEfiKeyFlushState (TerminalDevice);\r
+        continue;\r
+      }\r
+\r
+      UnicodeToEfiKeyFlushState (TerminalDevice);\r
+\r
+      break;\r
+\r
+    case INPUT_STATE_ESC | INPUT_STATE_O:\r
+\r
+      TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
+\r
+      Key.ScanCode = SCAN_NULL;\r
+\r
+      if (TerminalDevice->TerminalType == TerminalTypeVt100) {\r
+        switch (UnicodeChar) {\r
+        case 'P':\r
+          Key.ScanCode = SCAN_F1;\r
+          break;\r
+        case 'Q':\r
+          Key.ScanCode = SCAN_F2;\r
+          break;\r
+        case 'w':\r
+          Key.ScanCode = SCAN_F3;\r
+          break;\r
+        case 'x':\r
+          Key.ScanCode = SCAN_F4;\r
+          break;\r
+        case 't':\r
+          Key.ScanCode = SCAN_F5;\r
+          break;\r
+        case 'u':\r
+          Key.ScanCode = SCAN_F6;\r
+          break;\r
+        case 'q':\r
+          Key.ScanCode = SCAN_F7;\r
+          break;\r
+        case 'r':\r
+          Key.ScanCode = SCAN_F8;\r
+          break;\r
+        case 'p':\r
+          Key.ScanCode = SCAN_F9;\r
+          break;\r
+        case 'M':\r
+          Key.ScanCode = SCAN_F10;\r
+          break;\r
+        default :\r
+          break;\r
+        }\r
+      } else if (TerminalDevice->TerminalType == TerminalTypeTtyTerm) {\r
+        /* Also accept VT100 escape codes for F1-F4, HOME and END for TTY term */\r
+        switch (UnicodeChar) {\r
+        case 'P':\r
+          Key.ScanCode = SCAN_F1;\r
+          break;\r
+        case 'Q':\r
+          Key.ScanCode = SCAN_F2;\r
+          break;\r
+        case 'R':\r
+          Key.ScanCode = SCAN_F3;\r
+          break;\r
+        case 'S':\r
+          Key.ScanCode = SCAN_F4;\r
+          break;\r
+        case 'H':\r
+          Key.ScanCode = SCAN_HOME;\r
+          break;\r
+        case 'F':\r
+          Key.ScanCode = SCAN_END;\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (Key.ScanCode != SCAN_NULL) {\r
+        Key.UnicodeChar = 0;\r
+        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);\r
+        TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
+        UnicodeToEfiKeyFlushState (TerminalDevice);\r
+        continue;\r
+      }\r
+\r
+      UnicodeToEfiKeyFlushState (TerminalDevice);\r
+\r
+      break;\r
+\r
+    case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET:\r
+\r
+      TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
+\r
+      Key.ScanCode = SCAN_NULL;\r
+\r
+      if (TerminalDevice->TerminalType == TerminalTypePcAnsi    ||\r
+          TerminalDevice->TerminalType == TerminalTypeVt100     ||\r
+          TerminalDevice->TerminalType == TerminalTypeVt100Plus ||\r
+          TerminalDevice->TerminalType == TerminalTypeVtUtf8    ||\r
+          TerminalDevice->TerminalType == TerminalTypeTtyTerm) {\r
+        switch (UnicodeChar) {\r
+        case 'A':\r
+          Key.ScanCode = SCAN_UP;\r
+          break;\r
+        case 'B':\r
+          Key.ScanCode = SCAN_DOWN;\r
+          break;\r
+        case 'C':\r
+          Key.ScanCode = SCAN_RIGHT;\r
+          break;\r
+        case 'D':\r
+          Key.ScanCode = SCAN_LEFT;\r
+          break;\r
+        case 'H':\r
+          if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||\r
+              TerminalDevice->TerminalType == TerminalTypeVt100  ||\r
+              TerminalDevice->TerminalType == TerminalTypeTtyTerm) {\r
+            Key.ScanCode = SCAN_HOME;\r
+          }\r
+          break;\r
+        case 'F':\r
+          if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||\r
+              TerminalDevice->TerminalType == TerminalTypeTtyTerm) {\r
+            Key.ScanCode = SCAN_END;\r
+          }\r
+          break;\r
+        case 'K':\r
+          if (TerminalDevice->TerminalType == TerminalTypeVt100) {\r
+            Key.ScanCode = SCAN_END;\r
+          }\r
+          break;\r
+        case 'L':\r
+        case '@':\r
+          if (TerminalDevice->TerminalType == TerminalTypePcAnsi ||\r
+              TerminalDevice->TerminalType == TerminalTypeVt100) {\r
+            Key.ScanCode = SCAN_INSERT;\r
+          }\r
+          break;\r
+        case 'X':\r
+          if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {\r
+            Key.ScanCode = SCAN_DELETE;\r
+          }\r
+          break;\r
+        case 'P':\r
+          if (TerminalDevice->TerminalType == TerminalTypeVt100) {\r
+            Key.ScanCode = SCAN_DELETE;\r
+          } else if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {\r
+            Key.ScanCode = SCAN_F4;\r
+          }\r
+          break;\r
+        case 'I':\r
+          if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {\r
+            Key.ScanCode = SCAN_PAGE_UP;\r
+          }\r
+          break;\r
+        case 'V':\r
+          if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {\r
+            Key.ScanCode = SCAN_F10;\r
+          }\r
+          break;\r
+        case '?':\r
+          if (TerminalDevice->TerminalType == TerminalTypeVt100) {\r
+            Key.ScanCode = SCAN_PAGE_UP;\r
+          }\r
+          break;\r
+        case 'G':\r
+          if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {\r
+            Key.ScanCode = SCAN_PAGE_DOWN;\r
+          }\r
+          break;\r
+        case 'U':\r
+          if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {\r
+            Key.ScanCode = SCAN_F9;\r
+          }\r
+          break;\r
+        case '/':\r
+          if (TerminalDevice->TerminalType == TerminalTypeVt100) {\r
+            Key.ScanCode = SCAN_PAGE_DOWN;\r
+          }\r
+          break;\r
+        case 'M':\r
+          if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {\r
+            Key.ScanCode = SCAN_F1;\r
+          }\r
+          break;\r
+        case 'N':\r
+          if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {\r
+            Key.ScanCode = SCAN_F2;\r
+          }\r
+          break;\r
+        case 'O':\r
+          if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {\r
+            Key.ScanCode = SCAN_F3;\r
+          }\r
+          break;\r
+        case 'Q':\r
+          if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {\r
+            Key.ScanCode = SCAN_F5;\r
+          }\r
+          break;\r
+        case 'R':\r
+          if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {\r
+            Key.ScanCode = SCAN_F6;\r
+          }\r
+          break;\r
+        case 'S':\r
+          if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {\r
+            Key.ScanCode = SCAN_F7;\r
+          }\r
+          break;\r
+        case 'T':\r
+          if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {\r
+            Key.ScanCode = SCAN_F8;\r
+          }\r
+          break;\r
+        default :\r
+          break;\r
+        }\r
+      }\r
+\r
+      /*\r
+       * The VT220 escape codes that the TTY terminal accepts all have\r
+       * numeric codes, and there are no ambiguous prefixes shared with\r
+       * other terminal types.\r
+       */\r
+      if (TerminalDevice->TerminalType == TerminalTypeTtyTerm &&\r
+          Key.ScanCode == SCAN_NULL &&\r
+          UnicodeChar >= '0' &&\r
+          UnicodeChar <= '9') {\r
+        TerminalDevice->TtyEscapeStr[0] = UnicodeChar;\r
+        TerminalDevice->TtyEscapeIndex = 1;\r
+        TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET_2;\r
+        continue;\r
+      }\r
+\r
+      if (Key.ScanCode != SCAN_NULL) {\r
+        Key.UnicodeChar = 0;\r
+        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);\r
+        TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
+        UnicodeToEfiKeyFlushState (TerminalDevice);\r
+        continue;\r
+      }\r
+\r
+      UnicodeToEfiKeyFlushState (TerminalDevice);\r
+\r
+      break;\r
+\r
+\r
+    case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_LEFTOPENBRACKET_2:\r
+      /*\r
+       * Here we handle the VT220 escape codes that we accept.  This\r
+       * state is only used by the TTY terminal type.\r
+       */\r
+      Key.ScanCode = SCAN_NULL;\r
+      if (TerminalDevice->TerminalType == TerminalTypeTtyTerm) {\r
+\r
+        if (UnicodeChar == '~' && TerminalDevice->TtyEscapeIndex <= 2) {\r
+          UINT16 EscCode;\r
+          TerminalDevice->TtyEscapeStr[TerminalDevice->TtyEscapeIndex] = 0; /* Terminate string */\r
+          EscCode = (UINT16) StrDecimalToUintn(TerminalDevice->TtyEscapeStr);\r
+          switch (EscCode) {\r
+          case 2:\r
+              Key.ScanCode = SCAN_INSERT;\r
+              break;\r
+          case 3:\r
+              Key.ScanCode = SCAN_DELETE;\r
+              break;\r
+          case 5:\r
+              Key.ScanCode = SCAN_PAGE_UP;\r
+              break;\r
+          case 6:\r
+              Key.ScanCode = SCAN_PAGE_DOWN;\r
+              break;\r
+          case 11:\r
+          case 12:\r
+          case 13:\r
+          case 14:\r
+          case 15:\r
+            Key.ScanCode = SCAN_F1 + EscCode - 11;\r
+            break;\r
+          case 17:\r
+          case 18:\r
+          case 19:\r
+          case 20:\r
+          case 21:\r
+            Key.ScanCode = SCAN_F6 + EscCode - 17;\r
+            break;\r
+          case 23:\r
+          case 24:\r
+            Key.ScanCode = SCAN_F11 + EscCode - 23;\r
+            break;\r
+          default:\r
+            break;\r
+          }\r
+        } else if (TerminalDevice->TtyEscapeIndex == 1){\r
+          /* 2 character escape code   */\r
+          TerminalDevice->TtyEscapeStr[TerminalDevice->TtyEscapeIndex++] = UnicodeChar;\r
+          continue;\r
+        }\r
+        else {\r
+          DEBUG ((EFI_D_ERROR, "Unexpected state in escape2\n"));\r
+        }\r
+      }\r
+      TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
+\r
+      if (Key.ScanCode != SCAN_NULL) {\r
+        Key.UnicodeChar = 0;\r
+        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);\r
+        TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
+        UnicodeToEfiKeyFlushState (TerminalDevice);\r
+        continue;\r
+      }\r
+\r
+      UnicodeToEfiKeyFlushState (TerminalDevice);\r
+      break;\r
+\r
+    default:\r
+      //\r
+      // Invalid state. This should never happen.\r
+      //\r
+      ASSERT (FALSE);\r
+\r
+      UnicodeToEfiKeyFlushState (TerminalDevice);\r
+\r
+      break;\r
+    }\r
+\r
+    if (UnicodeChar == ESC) {\r
+      TerminalDevice->InputState = INPUT_STATE_ESC;\r
+    }\r
+\r
+    if (UnicodeChar == CSI) {\r
+      TerminalDevice->InputState = INPUT_STATE_CSI;\r
+    }\r
+\r
+    if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {\r
+      Status = gBS->SetTimer(\r
+                      TerminalDevice->TwoSecondTimeOut,\r
+                      TimerRelative,\r
+                      (UINT64)20000000\r
+                      );\r
+      ASSERT_EFI_ERROR (Status);\r
+      continue;\r
+    }\r
+\r
+    if (SetDefaultResetState) {\r
+      TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
+    }\r
+\r
+    if (UnicodeChar == DEL) {\r
+      if (TerminalDevice->TerminalType == TerminalTypeTtyTerm) {\r
+        Key.ScanCode    = SCAN_NULL;\r
+        Key.UnicodeChar = CHAR_BACKSPACE;\r
+      }\r
+      else {\r
+        Key.ScanCode    = SCAN_DELETE;\r
+        Key.UnicodeChar = 0;\r
+      }\r
+    } else {\r
+      Key.ScanCode    = SCAN_NULL;\r
+      Key.UnicodeChar = UnicodeChar;\r
+    }\r
+\r
+    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);\r
+  }\r
+}\r