Home | History | Annotate | Download | only in TerminalDxe
      1 /** @file
      2   Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol.
      3 
      4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
      5 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
      6 Copyright (C) 2016 Silicon Graphics, Inc. All rights reserved.<BR>
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions of the BSD License
      9 which accompanies this distribution.  The full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "Terminal.h"
     18 
     19 
     20 /**
     21   Reads the next keystroke from the input device. The WaitForKey Event can
     22   be used to test for existence of a keystroke via WaitForEvent () call.
     23 
     24   @param  TerminalDevice           Terminal driver private structure
     25   @param  KeyData                  A pointer to a buffer that is filled in with the
     26                                    keystroke state data for the key that was
     27                                    pressed.
     28 
     29   @retval EFI_SUCCESS              The keystroke information was returned.
     30   @retval EFI_NOT_READY            There was no keystroke data available.
     31   @retval EFI_INVALID_PARAMETER    KeyData is NULL.
     32 
     33 **/
     34 EFI_STATUS
     35 ReadKeyStrokeWorker (
     36   IN  TERMINAL_DEV *TerminalDevice,
     37   OUT EFI_KEY_DATA *KeyData
     38   )
     39 {
     40   if (KeyData == NULL) {
     41     return EFI_INVALID_PARAMETER;
     42   }
     43 
     44   if (!EfiKeyFiFoRemoveOneKey (TerminalDevice, &KeyData->Key)) {
     45     return EFI_NOT_READY;
     46   }
     47 
     48   KeyData->KeyState.KeyShiftState  = 0;
     49   KeyData->KeyState.KeyToggleState = 0;
     50 
     51 
     52   return EFI_SUCCESS;
     53 
     54 }
     55 
     56 /**
     57   Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset().
     58   This driver only perform dependent serial device reset regardless of
     59   the value of ExtendeVerification
     60 
     61   @param  This                     Indicates the calling context.
     62   @param  ExtendedVerification     Skip by this driver.
     63 
     64   @retval EFI_SUCCESS              The reset operation succeeds.
     65   @retval EFI_DEVICE_ERROR         The dependent serial port reset fails.
     66 
     67 **/
     68 EFI_STATUS
     69 EFIAPI
     70 TerminalConInReset (
     71   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
     72   IN  BOOLEAN                         ExtendedVerification
     73   )
     74 {
     75   EFI_STATUS    Status;
     76   TERMINAL_DEV  *TerminalDevice;
     77 
     78   TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);
     79 
     80   //
     81   // Report progress code here
     82   //
     83   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
     84     EFI_PROGRESS_CODE,
     85     (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_RESET),
     86     TerminalDevice->DevicePath
     87     );
     88 
     89   Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo);
     90 
     91   //
     92   // Make all the internal buffer empty for keys
     93   //
     94   TerminalDevice->RawFiFo->Head     = TerminalDevice->RawFiFo->Tail;
     95   TerminalDevice->UnicodeFiFo->Head = TerminalDevice->UnicodeFiFo->Tail;
     96   TerminalDevice->EfiKeyFiFo->Head  = TerminalDevice->EfiKeyFiFo->Tail;
     97   TerminalDevice->EfiKeyFiFoForNotify->Head = TerminalDevice->EfiKeyFiFoForNotify->Tail;
     98 
     99   if (EFI_ERROR (Status)) {
    100     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    101       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    102       (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
    103       TerminalDevice->DevicePath
    104       );
    105   }
    106 
    107   return Status;
    108 }
    109 
    110 /**
    111   Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke().
    112 
    113   @param  This                Indicates the calling context.
    114   @param  Key                 A pointer to a buffer that is filled in with the
    115                               keystroke information for the key that was sent
    116                               from terminal.
    117 
    118   @retval EFI_SUCCESS         The keystroke information is returned successfully.
    119   @retval EFI_NOT_READY       There is no keystroke data available.
    120   @retval EFI_DEVICE_ERROR    The dependent serial device encounters error.
    121 
    122 **/
    123 EFI_STATUS
    124 EFIAPI
    125 TerminalConInReadKeyStroke (
    126   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
    127   OUT EFI_INPUT_KEY                   *Key
    128   )
    129 {
    130   TERMINAL_DEV  *TerminalDevice;
    131   EFI_STATUS    Status;
    132   EFI_KEY_DATA  KeyData;
    133 
    134   //
    135   //  get TERMINAL_DEV from "This" parameter.
    136   //
    137   TerminalDevice  = TERMINAL_CON_IN_DEV_FROM_THIS (This);
    138 
    139   Status = ReadKeyStrokeWorker (TerminalDevice, &KeyData);
    140   if (EFI_ERROR (Status)) {
    141     return Status;
    142   }
    143 
    144   CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
    145 
    146   return EFI_SUCCESS;
    147 
    148 }
    149 
    150 /**
    151   Check if the key already has been registered.
    152 
    153   If both RegsiteredData and InputData is NULL, then ASSERT().
    154 
    155   @param  RegsiteredData           A pointer to a buffer that is filled in with the
    156                                    keystroke state data for the key that was
    157                                    registered.
    158   @param  InputData                A pointer to a buffer that is filled in with the
    159                                    keystroke state data for the key that was
    160                                    pressed.
    161 
    162   @retval TRUE                     Key be pressed matches a registered key.
    163   @retval FALSE                    Match failed.
    164 
    165 **/
    166 BOOLEAN
    167 IsKeyRegistered (
    168   IN EFI_KEY_DATA  *RegsiteredData,
    169   IN EFI_KEY_DATA  *InputData
    170   )
    171 {
    172   ASSERT (RegsiteredData != NULL && InputData != NULL);
    173 
    174   if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
    175       (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
    176     return FALSE;
    177   }
    178 
    179   return TRUE;
    180 }
    181 
    182 
    183 
    184 /**
    185   Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
    186   Signal the event if there is key available
    187 
    188   @param  Event                    Indicates the event that invoke this function.
    189   @param  Context                  Indicates the calling context.
    190 
    191 **/
    192 VOID
    193 EFIAPI
    194 TerminalConInWaitForKeyEx (
    195   IN  EFI_EVENT       Event,
    196   IN  VOID            *Context
    197   )
    198 {
    199   TerminalConInWaitForKey (Event, Context);
    200 }
    201 
    202 //
    203 // Simple Text Input Ex protocol functions
    204 //
    205 
    206 /**
    207   Reset the input device and optionally run diagnostics
    208 
    209   @param  This                     Protocol instance pointer.
    210   @param  ExtendedVerification     Driver may perform diagnostics on reset.
    211 
    212   @retval EFI_SUCCESS              The device was reset.
    213   @retval EFI_DEVICE_ERROR         The device is not functioning properly and could
    214                                    not be reset.
    215 
    216 **/
    217 EFI_STATUS
    218 EFIAPI
    219 TerminalConInResetEx (
    220   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
    221   IN BOOLEAN                            ExtendedVerification
    222   )
    223 {
    224   EFI_STATUS              Status;
    225   TERMINAL_DEV            *TerminalDevice;
    226 
    227   TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
    228 
    229   Status = TerminalDevice->SimpleInput.Reset (&TerminalDevice->SimpleInput, ExtendedVerification);
    230   if (EFI_ERROR (Status)) {
    231     return EFI_DEVICE_ERROR;
    232   }
    233 
    234   return EFI_SUCCESS;
    235 
    236 }
    237 
    238 
    239 /**
    240   Reads the next keystroke from the input device. The WaitForKey Event can
    241   be used to test for existence of a keystroke via WaitForEvent () call.
    242 
    243   @param  This                     Protocol instance pointer.
    244   @param  KeyData                  A pointer to a buffer that is filled in with the
    245                                    keystroke state data for the key that was
    246                                    pressed.
    247 
    248   @retval EFI_SUCCESS              The keystroke information was returned.
    249   @retval EFI_NOT_READY            There was no keystroke data available.
    250   @retval EFI_DEVICE_ERROR         The keystroke information was not returned due
    251                                    to hardware errors.
    252   @retval EFI_INVALID_PARAMETER    KeyData is NULL.
    253 
    254 **/
    255 EFI_STATUS
    256 EFIAPI
    257 TerminalConInReadKeyStrokeEx (
    258   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
    259   OUT EFI_KEY_DATA                      *KeyData
    260   )
    261 {
    262   TERMINAL_DEV                    *TerminalDevice;
    263 
    264   if (KeyData == NULL) {
    265     return EFI_INVALID_PARAMETER;
    266   }
    267 
    268   TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
    269 
    270   return ReadKeyStrokeWorker (TerminalDevice, KeyData);
    271 
    272 }
    273 
    274 
    275 /**
    276   Set certain state for the input device.
    277 
    278   @param  This                     Protocol instance pointer.
    279   @param  KeyToggleState           A pointer to the EFI_KEY_TOGGLE_STATE to set the
    280                                    state for the input device.
    281 
    282   @retval EFI_SUCCESS              The device state was set successfully.
    283   @retval EFI_DEVICE_ERROR         The device is not functioning correctly and
    284                                    could not have the setting adjusted.
    285   @retval EFI_UNSUPPORTED          The device does not have the ability to set its
    286                                    state.
    287   @retval EFI_INVALID_PARAMETER    KeyToggleState is NULL.
    288 
    289 **/
    290 EFI_STATUS
    291 EFIAPI
    292 TerminalConInSetState (
    293   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
    294   IN EFI_KEY_TOGGLE_STATE               *KeyToggleState
    295   )
    296 {
    297   if (KeyToggleState == NULL) {
    298     return EFI_INVALID_PARAMETER;
    299   }
    300 
    301   if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) {
    302     return EFI_UNSUPPORTED;
    303   }
    304 
    305   return EFI_SUCCESS;
    306 }
    307 
    308 
    309 /**
    310   Register a notification function for a particular keystroke for the input device.
    311 
    312   @param  This                     Protocol instance pointer.
    313   @param  KeyData                  A pointer to a buffer that is filled in with the
    314                                    keystroke information data for the key that was
    315                                    pressed.
    316   @param  KeyNotificationFunction  Points to the function to be called when the key
    317                                    sequence is typed specified by KeyData.
    318   @param  NotifyHandle             Points to the unique handle assigned to the
    319                                    registered notification.
    320 
    321   @retval EFI_SUCCESS              The notification function was registered
    322                                    successfully.
    323   @retval EFI_OUT_OF_RESOURCES     Unable to allocate resources for necessary data
    324                                    structures.
    325   @retval EFI_INVALID_PARAMETER    KeyData or NotifyHandle is NULL.
    326 
    327 **/
    328 EFI_STATUS
    329 EFIAPI
    330 TerminalConInRegisterKeyNotify (
    331   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
    332   IN EFI_KEY_DATA                       *KeyData,
    333   IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
    334   OUT VOID                              **NotifyHandle
    335   )
    336 {
    337   TERMINAL_DEV                    *TerminalDevice;
    338   TERMINAL_CONSOLE_IN_EX_NOTIFY   *NewNotify;
    339   LIST_ENTRY                      *Link;
    340   LIST_ENTRY                      *NotifyList;
    341   TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;
    342 
    343   if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
    344     return EFI_INVALID_PARAMETER;
    345   }
    346 
    347   TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
    348 
    349   //
    350   // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
    351   //
    352   NotifyList = &TerminalDevice->NotifyList;
    353   for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
    354     CurrentNotify = CR (
    355                       Link,
    356                       TERMINAL_CONSOLE_IN_EX_NOTIFY,
    357                       NotifyEntry,
    358                       TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
    359                       );
    360     if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
    361       if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
    362         *NotifyHandle = CurrentNotify;
    363         return EFI_SUCCESS;
    364       }
    365     }
    366   }
    367 
    368   //
    369   // Allocate resource to save the notification function
    370   //
    371   NewNotify = (TERMINAL_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (TERMINAL_CONSOLE_IN_EX_NOTIFY));
    372   if (NewNotify == NULL) {
    373     return EFI_OUT_OF_RESOURCES;
    374   }
    375 
    376   NewNotify->Signature         = TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
    377   NewNotify->KeyNotificationFn = KeyNotificationFunction;
    378   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
    379   InsertTailList (&TerminalDevice->NotifyList, &NewNotify->NotifyEntry);
    380 
    381   *NotifyHandle                = NewNotify;
    382 
    383   return EFI_SUCCESS;
    384 }
    385 
    386 
    387 /**
    388   Remove a registered notification function from a particular keystroke.
    389 
    390   @param  This                     Protocol instance pointer.
    391   @param  NotificationHandle       The handle of the notification function being
    392                                    unregistered.
    393 
    394   @retval EFI_SUCCESS              The notification function was unregistered
    395                                    successfully.
    396   @retval EFI_INVALID_PARAMETER    The NotificationHandle is invalid.
    397 
    398 **/
    399 EFI_STATUS
    400 EFIAPI
    401 TerminalConInUnregisterKeyNotify (
    402   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
    403   IN VOID                               *NotificationHandle
    404   )
    405 {
    406   TERMINAL_DEV                    *TerminalDevice;
    407   LIST_ENTRY                      *Link;
    408   TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;
    409   LIST_ENTRY                      *NotifyList;
    410 
    411   if (NotificationHandle == NULL) {
    412     return EFI_INVALID_PARAMETER;
    413   }
    414 
    415   TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
    416 
    417   NotifyList = &TerminalDevice->NotifyList;
    418   for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
    419     CurrentNotify = CR (
    420                       Link,
    421                       TERMINAL_CONSOLE_IN_EX_NOTIFY,
    422                       NotifyEntry,
    423                       TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
    424                       );
    425     if (CurrentNotify == NotificationHandle) {
    426       //
    427       // Remove the notification function from NotifyList and free resources
    428       //
    429       RemoveEntryList (&CurrentNotify->NotifyEntry);
    430 
    431       gBS->FreePool (CurrentNotify);
    432       return EFI_SUCCESS;
    433     }
    434   }
    435 
    436   //
    437   // Can not find the matching entry in database.
    438   //
    439   return EFI_INVALID_PARAMETER;
    440 }
    441 
    442 /**
    443   Translate raw data into Unicode (according to different encode), and
    444   translate Unicode into key information. (according to different standard).
    445 
    446   @param  TerminalDevice       Terminal driver private structure.
    447 
    448 **/
    449 VOID
    450 TranslateRawDataToEfiKey (
    451   IN  TERMINAL_DEV      *TerminalDevice
    452   )
    453 {
    454   switch (TerminalDevice->TerminalType) {
    455 
    456   case PCANSITYPE:
    457   case VT100TYPE:
    458   case VT100PLUSTYPE:
    459   case TTYTERMTYPE:
    460     AnsiRawDataToUnicode (TerminalDevice);
    461     UnicodeToEfiKey (TerminalDevice);
    462     break;
    463 
    464   case VTUTF8TYPE:
    465     //
    466     // Process all the raw data in the RawFIFO,
    467     // put the processed key into UnicodeFIFO.
    468     //
    469     VTUTF8RawDataToUnicode (TerminalDevice);
    470 
    471     //
    472     // Translate all the Unicode data in the UnicodeFIFO to Efi key,
    473     // then put into EfiKeyFIFO.
    474     //
    475     UnicodeToEfiKey (TerminalDevice);
    476 
    477     break;
    478   }
    479 }
    480 
    481 /**
    482   Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event
    483   Signal the event if there is key available
    484 
    485   @param  Event                    Indicates the event that invoke this function.
    486   @param  Context                  Indicates the calling context.
    487 
    488 **/
    489 VOID
    490 EFIAPI
    491 TerminalConInWaitForKey (
    492   IN  EFI_EVENT       Event,
    493   IN  VOID            *Context
    494   )
    495 {
    496   //
    497   // Someone is waiting on the keystroke event, if there's
    498   // a key pending, signal the event
    499   //
    500   if (!IsEfiKeyFiFoEmpty ((TERMINAL_DEV *) Context)) {
    501 
    502     gBS->SignalEvent (Event);
    503   }
    504 }
    505 
    506 /**
    507   Timer handler to poll the key from serial.
    508 
    509   @param  Event                    Indicates the event that invoke this function.
    510   @param  Context                  Indicates the calling context.
    511 **/
    512 VOID
    513 EFIAPI
    514 TerminalConInTimerHandler (
    515   IN EFI_EVENT            Event,
    516   IN VOID                 *Context
    517   )
    518 {
    519   EFI_STATUS              Status;
    520   TERMINAL_DEV            *TerminalDevice;
    521   UINT32                  Control;
    522   UINT8                   Input;
    523   EFI_SERIAL_IO_MODE      *Mode;
    524   EFI_SERIAL_IO_PROTOCOL  *SerialIo;
    525   UINTN                   SerialInTimeOut;
    526 
    527   TerminalDevice  = (TERMINAL_DEV *) Context;
    528 
    529   SerialIo        = TerminalDevice->SerialIo;
    530   if (SerialIo == NULL) {
    531     return ;
    532   }
    533   //
    534   //  if current timeout value for serial device is not identical with
    535   //  the value saved in TERMINAL_DEV structure, then recalculate the
    536   //  timeout value again and set serial attribute according to this value.
    537   //
    538   Mode = SerialIo->Mode;
    539   if (Mode->Timeout != TerminalDevice->SerialInTimeOut) {
    540 
    541     SerialInTimeOut = 0;
    542     if (Mode->BaudRate != 0) {
    543       //
    544       // According to BAUD rate to calculate the timeout value.
    545       //
    546       SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;
    547     }
    548 
    549     Status = SerialIo->SetAttributes (
    550                         SerialIo,
    551                         Mode->BaudRate,
    552                         Mode->ReceiveFifoDepth,
    553                         (UINT32) SerialInTimeOut,
    554                         (EFI_PARITY_TYPE) (Mode->Parity),
    555                         (UINT8) Mode->DataBits,
    556                         (EFI_STOP_BITS_TYPE) (Mode->StopBits)
    557                         );
    558 
    559     if (EFI_ERROR (Status)) {
    560       TerminalDevice->SerialInTimeOut = 0;
    561     } else {
    562       TerminalDevice->SerialInTimeOut = SerialInTimeOut;
    563     }
    564   }
    565   //
    566   // Check whether serial buffer is empty.
    567   // Skip the key transfer loop only if the SerialIo protocol instance
    568   // successfully reports EFI_SERIAL_INPUT_BUFFER_EMPTY.
    569   //
    570   Status = SerialIo->GetControl (SerialIo, &Control);
    571   if (EFI_ERROR (Status) || ((Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) == 0)) {
    572     //
    573     // Fetch all the keys in the serial buffer,
    574     // and insert the byte stream into RawFIFO.
    575     //
    576     while (!IsRawFiFoFull (TerminalDevice)) {
    577 
    578       Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input);
    579 
    580       if (EFI_ERROR (Status)) {
    581         if (Status == EFI_DEVICE_ERROR) {
    582           REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    583             EFI_ERROR_CODE | EFI_ERROR_MINOR,
    584             (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_INPUT_ERROR),
    585             TerminalDevice->DevicePath
    586             );
    587         }
    588         break;
    589       }
    590 
    591       RawFiFoInsertOneKey (TerminalDevice, Input);
    592     }
    593   }
    594 
    595   //
    596   // Translate all the raw data in RawFIFO into EFI Key,
    597   // according to different terminal type supported.
    598   //
    599   TranslateRawDataToEfiKey (TerminalDevice);
    600 }
    601 
    602 /**
    603   Process key notify.
    604 
    605   @param  Event                 Indicates the event that invoke this function.
    606   @param  Context               Indicates the calling context.
    607 **/
    608 VOID
    609 EFIAPI
    610 KeyNotifyProcessHandler (
    611   IN  EFI_EVENT                 Event,
    612   IN  VOID                      *Context
    613   )
    614 {
    615   BOOLEAN                       HasKey;
    616   TERMINAL_DEV                  *TerminalDevice;
    617   EFI_INPUT_KEY                 Key;
    618   EFI_KEY_DATA                  KeyData;
    619   LIST_ENTRY                    *Link;
    620   LIST_ENTRY                    *NotifyList;
    621   TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
    622   EFI_TPL                       OldTpl;
    623 
    624   TerminalDevice = (TERMINAL_DEV *) Context;
    625 
    626   //
    627   // Invoke notification functions.
    628   //
    629   NotifyList = &TerminalDevice->NotifyList;
    630   while (TRUE) {
    631     //
    632     // Enter critical section
    633     //
    634     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    635     HasKey = EfiKeyFiFoForNotifyRemoveOneKey (TerminalDevice->EfiKeyFiFoForNotify, &Key);
    636     CopyMem (&KeyData.Key, &Key, sizeof (EFI_INPUT_KEY));
    637     KeyData.KeyState.KeyShiftState  = 0;
    638     KeyData.KeyState.KeyToggleState = 0;
    639     //
    640     // Leave critical section
    641     //
    642     gBS->RestoreTPL (OldTpl);
    643     if (!HasKey) {
    644       break;
    645     }
    646     for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
    647       CurrentNotify = CR (Link, TERMINAL_CONSOLE_IN_EX_NOTIFY, NotifyEntry, TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
    648       if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
    649         CurrentNotify->KeyNotificationFn (&KeyData);
    650       }
    651     }
    652   }
    653 }
    654 
    655 /**
    656   Get one key out of serial buffer.
    657 
    658   @param  SerialIo           Serial I/O protocol attached to the serial device.
    659   @param  Output             The fetched key.
    660 
    661   @retval EFI_NOT_READY      If serial buffer is empty.
    662   @retval EFI_DEVICE_ERROR   If reading serial buffer encounter error.
    663   @retval EFI_SUCCESS        If reading serial buffer successfully, put
    664                              the fetched key to the parameter output.
    665 
    666 **/
    667 EFI_STATUS
    668 GetOneKeyFromSerial (
    669   EFI_SERIAL_IO_PROTOCOL  *SerialIo,
    670   UINT8                   *Output
    671   )
    672 {
    673   EFI_STATUS  Status;
    674   UINTN       Size;
    675 
    676   Size    = 1;
    677   *Output = 0;
    678 
    679   //
    680   // Read one key from serial I/O device.
    681   //
    682   Status  = SerialIo->Read (SerialIo, &Size, Output);
    683 
    684   if (EFI_ERROR (Status)) {
    685 
    686     if (Status == EFI_TIMEOUT) {
    687       return EFI_NOT_READY;
    688     }
    689 
    690     return EFI_DEVICE_ERROR;
    691 
    692   }
    693 
    694   if (*Output == 0) {
    695     return EFI_NOT_READY;
    696   }
    697 
    698   return EFI_SUCCESS;
    699 }
    700 
    701 /**
    702   Insert one byte raw data into the Raw Data FIFO.
    703 
    704   @param  TerminalDevice       Terminal driver private structure.
    705   @param  Input                The key will be input.
    706 
    707   @retval TRUE                 If insert successfully.
    708   @retval FALSE                If Raw Data buffer is full before key insertion,
    709                                and the key is lost.
    710 
    711 **/
    712 BOOLEAN
    713 RawFiFoInsertOneKey (
    714   TERMINAL_DEV      *TerminalDevice,
    715   UINT8             Input
    716   )
    717 {
    718   UINT8 Tail;
    719 
    720   Tail = TerminalDevice->RawFiFo->Tail;
    721 
    722   if (IsRawFiFoFull (TerminalDevice)) {
    723     //
    724     // Raw FIFO is full
    725     //
    726     return FALSE;
    727   }
    728 
    729   TerminalDevice->RawFiFo->Data[Tail]  = Input;
    730 
    731   TerminalDevice->RawFiFo->Tail        = (UINT8) ((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1));
    732 
    733   return TRUE;
    734 }
    735 
    736 /**
    737   Remove one pre-fetched key out of the Raw Data FIFO.
    738 
    739   @param  TerminalDevice       Terminal driver private structure.
    740   @param  Output               The key will be removed.
    741 
    742   @retval TRUE                 If insert successfully.
    743   @retval FALSE                If Raw Data FIFO buffer is empty before remove operation.
    744 
    745 **/
    746 BOOLEAN
    747 RawFiFoRemoveOneKey (
    748   TERMINAL_DEV  *TerminalDevice,
    749   UINT8         *Output
    750   )
    751 {
    752   UINT8 Head;
    753 
    754   Head = TerminalDevice->RawFiFo->Head;
    755 
    756   if (IsRawFiFoEmpty (TerminalDevice)) {
    757     //
    758     //  FIFO is empty
    759     //
    760     *Output = 0;
    761     return FALSE;
    762   }
    763 
    764   *Output                       = TerminalDevice->RawFiFo->Data[Head];
    765 
    766   TerminalDevice->RawFiFo->Head  = (UINT8) ((Head + 1) % (RAW_FIFO_MAX_NUMBER + 1));
    767 
    768   return TRUE;
    769 }
    770 
    771 /**
    772   Clarify whether Raw Data FIFO buffer is empty.
    773 
    774   @param  TerminalDevice       Terminal driver private structure
    775 
    776   @retval TRUE                 If Raw Data FIFO buffer is empty.
    777   @retval FALSE                If Raw Data FIFO buffer is not empty.
    778 
    779 **/
    780 BOOLEAN
    781 IsRawFiFoEmpty (
    782   TERMINAL_DEV  *TerminalDevice
    783   )
    784 {
    785   if (TerminalDevice->RawFiFo->Head == TerminalDevice->RawFiFo->Tail) {
    786     return TRUE;
    787   } else {
    788     return FALSE;
    789   }
    790 }
    791 
    792 /**
    793   Clarify whether Raw Data FIFO buffer is full.
    794 
    795   @param  TerminalDevice       Terminal driver private structure
    796 
    797   @retval TRUE                 If Raw Data FIFO buffer is full.
    798   @retval FALSE                If Raw Data FIFO buffer is not full.
    799 
    800 **/
    801 BOOLEAN
    802 IsRawFiFoFull (
    803   TERMINAL_DEV  *TerminalDevice
    804   )
    805 {
    806   UINT8 Tail;
    807   UINT8 Head;
    808 
    809   Tail  = TerminalDevice->RawFiFo->Tail;
    810   Head  = TerminalDevice->RawFiFo->Head;
    811 
    812   if (((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)) == Head) {
    813 
    814     return TRUE;
    815   }
    816 
    817   return FALSE;
    818 }
    819 
    820 /**
    821   Insert one pre-fetched key into the FIFO buffer.
    822 
    823   @param  EfiKeyFiFo            Pointer to instance of EFI_KEY_FIFO.
    824   @param  Input                 The key will be input.
    825 
    826   @retval TRUE                  If insert successfully.
    827   @retval FALSE                 If FIFO buffer is full before key insertion,
    828                                 and the key is lost.
    829 
    830 **/
    831 BOOLEAN
    832 EfiKeyFiFoForNotifyInsertOneKey (
    833   EFI_KEY_FIFO                  *EfiKeyFiFo,
    834   EFI_INPUT_KEY                 *Input
    835   )
    836 {
    837   UINT8                         Tail;
    838 
    839   Tail = EfiKeyFiFo->Tail;
    840 
    841   if (IsEfiKeyFiFoForNotifyFull (EfiKeyFiFo)) {
    842     //
    843     // FIFO is full
    844     //
    845     return FALSE;
    846   }
    847 
    848   CopyMem (&EfiKeyFiFo->Data[Tail], Input, sizeof (EFI_INPUT_KEY));
    849 
    850   EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
    851 
    852   return TRUE;
    853 }
    854 
    855 /**
    856   Remove one pre-fetched key out of the FIFO buffer.
    857 
    858   @param  EfiKeyFiFo            Pointer to instance of EFI_KEY_FIFO.
    859   @param  Output                The key will be removed.
    860 
    861   @retval TRUE                  If remove successfully.
    862   @retval FALSE                 If FIFO buffer is empty before remove operation.
    863 
    864 **/
    865 BOOLEAN
    866 EfiKeyFiFoForNotifyRemoveOneKey (
    867   EFI_KEY_FIFO                  *EfiKeyFiFo,
    868   EFI_INPUT_KEY                 *Output
    869   )
    870 {
    871   UINT8                         Head;
    872 
    873   Head = EfiKeyFiFo->Head;
    874   ASSERT (Head < FIFO_MAX_NUMBER + 1);
    875 
    876   if (IsEfiKeyFiFoForNotifyEmpty (EfiKeyFiFo)) {
    877     //
    878     // FIFO is empty
    879     //
    880     Output->ScanCode    = SCAN_NULL;
    881     Output->UnicodeChar = 0;
    882     return FALSE;
    883   }
    884 
    885   CopyMem (Output, &EfiKeyFiFo->Data[Head], sizeof (EFI_INPUT_KEY));
    886 
    887   EfiKeyFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
    888 
    889   return TRUE;
    890 }
    891 
    892 /**
    893   Clarify whether FIFO buffer is empty.
    894 
    895   @param  EfiKeyFiFo            Pointer to instance of EFI_KEY_FIFO.
    896 
    897   @retval TRUE                  If FIFO buffer is empty.
    898   @retval FALSE                 If FIFO buffer is not empty.
    899 
    900 **/
    901 BOOLEAN
    902 IsEfiKeyFiFoForNotifyEmpty (
    903   EFI_KEY_FIFO                  *EfiKeyFiFo
    904   )
    905 {
    906   if (EfiKeyFiFo->Head == EfiKeyFiFo->Tail) {
    907     return TRUE;
    908   } else {
    909     return FALSE;
    910   }
    911 }
    912 
    913 /**
    914   Clarify whether FIFO buffer is full.
    915 
    916   @param  EfiKeyFiFo            Pointer to instance of EFI_KEY_FIFO.
    917 
    918   @retval TRUE                  If FIFO buffer is full.
    919   @retval FALSE                 If FIFO buffer is not full.
    920 
    921 **/
    922 BOOLEAN
    923 IsEfiKeyFiFoForNotifyFull (
    924   EFI_KEY_FIFO                  *EfiKeyFiFo
    925   )
    926 {
    927   UINT8                         Tail;
    928   UINT8                         Head;
    929 
    930   Tail = EfiKeyFiFo->Tail;
    931   Head = EfiKeyFiFo->Head;
    932 
    933   if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
    934     return TRUE;
    935   }
    936 
    937   return FALSE;
    938 }
    939 
    940 /**
    941   Insert one pre-fetched key into the FIFO buffer.
    942 
    943   @param  TerminalDevice       Terminal driver private structure.
    944   @param  Key                  The key will be input.
    945 
    946   @retval TRUE                 If insert successfully.
    947   @retval FALSE                If FIFO buffer is full before key insertion,
    948                                and the key is lost.
    949 
    950 **/
    951 BOOLEAN
    952 EfiKeyFiFoInsertOneKey (
    953   TERMINAL_DEV                    *TerminalDevice,
    954   EFI_INPUT_KEY                   *Key
    955   )
    956 {
    957   UINT8                           Tail;
    958   LIST_ENTRY                      *Link;
    959   LIST_ENTRY                      *NotifyList;
    960   TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;
    961   EFI_KEY_DATA                    KeyData;
    962 
    963   Tail = TerminalDevice->EfiKeyFiFo->Tail;
    964 
    965   CopyMem (&KeyData.Key, Key, sizeof (EFI_INPUT_KEY));
    966   KeyData.KeyState.KeyShiftState  = 0;
    967   KeyData.KeyState.KeyToggleState = 0;
    968 
    969   //
    970   // Signal KeyNotify process event if this key pressed matches any key registered.
    971   //
    972   NotifyList = &TerminalDevice->NotifyList;
    973   for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
    974     CurrentNotify = CR (
    975                       Link,
    976                       TERMINAL_CONSOLE_IN_EX_NOTIFY,
    977                       NotifyEntry,
    978                       TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
    979                       );
    980     if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
    981       //
    982       // The key notification function needs to run at TPL_CALLBACK
    983       // while current TPL is TPL_NOTIFY. It will be invoked in
    984       // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.
    985       //
    986       EfiKeyFiFoForNotifyInsertOneKey (TerminalDevice->EfiKeyFiFoForNotify, Key);
    987       gBS->SignalEvent (TerminalDevice->KeyNotifyProcessEvent);
    988     }
    989   }
    990   if (IsEfiKeyFiFoFull (TerminalDevice)) {
    991     //
    992     // Efi Key FIFO is full
    993     //
    994     return FALSE;
    995   }
    996 
    997   CopyMem (&TerminalDevice->EfiKeyFiFo->Data[Tail], Key, sizeof (EFI_INPUT_KEY));
    998 
    999   TerminalDevice->EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
   1000 
   1001   return TRUE;
   1002 }
   1003 
   1004 /**
   1005   Remove one pre-fetched key out of the FIFO buffer.
   1006 
   1007   @param  TerminalDevice       Terminal driver private structure.
   1008   @param  Output               The key will be removed.
   1009 
   1010   @retval TRUE                 If insert successfully.
   1011   @retval FALSE                If FIFO buffer is empty before remove operation.
   1012 
   1013 **/
   1014 BOOLEAN
   1015 EfiKeyFiFoRemoveOneKey (
   1016   TERMINAL_DEV  *TerminalDevice,
   1017   EFI_INPUT_KEY *Output
   1018   )
   1019 {
   1020   UINT8 Head;
   1021 
   1022   Head = TerminalDevice->EfiKeyFiFo->Head;
   1023   ASSERT (Head < FIFO_MAX_NUMBER + 1);
   1024 
   1025   if (IsEfiKeyFiFoEmpty (TerminalDevice)) {
   1026     //
   1027     //  FIFO is empty
   1028     //
   1029     Output->ScanCode    = SCAN_NULL;
   1030     Output->UnicodeChar = 0;
   1031     return FALSE;
   1032   }
   1033 
   1034   CopyMem (Output, &TerminalDevice->EfiKeyFiFo->Data[Head], sizeof (EFI_INPUT_KEY));
   1035 
   1036   TerminalDevice->EfiKeyFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
   1037 
   1038   return TRUE;
   1039 }
   1040 
   1041 /**
   1042   Clarify whether FIFO buffer is empty.
   1043 
   1044   @param  TerminalDevice       Terminal driver private structure
   1045 
   1046   @retval TRUE                 If FIFO buffer is empty.
   1047   @retval FALSE                If FIFO buffer is not empty.
   1048 
   1049 **/
   1050 BOOLEAN
   1051 IsEfiKeyFiFoEmpty (
   1052   TERMINAL_DEV  *TerminalDevice
   1053   )
   1054 {
   1055   if (TerminalDevice->EfiKeyFiFo->Head == TerminalDevice->EfiKeyFiFo->Tail) {
   1056     return TRUE;
   1057   } else {
   1058     return FALSE;
   1059   }
   1060 }
   1061 
   1062 /**
   1063   Clarify whether FIFO buffer is full.
   1064 
   1065   @param  TerminalDevice       Terminal driver private structure
   1066 
   1067   @retval TRUE                 If FIFO buffer is full.
   1068   @retval FALSE                If FIFO buffer is not full.
   1069 
   1070 **/
   1071 BOOLEAN
   1072 IsEfiKeyFiFoFull (
   1073   TERMINAL_DEV  *TerminalDevice
   1074   )
   1075 {
   1076   UINT8 Tail;
   1077   UINT8 Head;
   1078 
   1079   Tail  = TerminalDevice->EfiKeyFiFo->Tail;
   1080   Head  = TerminalDevice->EfiKeyFiFo->Head;
   1081 
   1082   if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
   1083 
   1084     return TRUE;
   1085   }
   1086 
   1087   return FALSE;
   1088 }
   1089 
   1090 /**
   1091   Insert one pre-fetched key into the Unicode FIFO buffer.
   1092 
   1093   @param  TerminalDevice       Terminal driver private structure.
   1094   @param  Input                The key will be input.
   1095 
   1096   @retval TRUE                 If insert successfully.
   1097   @retval FALSE                If Unicode FIFO buffer is full before key insertion,
   1098                                and the key is lost.
   1099 
   1100 **/
   1101 BOOLEAN
   1102 UnicodeFiFoInsertOneKey (
   1103   TERMINAL_DEV      *TerminalDevice,
   1104   UINT16            Input
   1105   )
   1106 {
   1107   UINT8 Tail;
   1108 
   1109   Tail = TerminalDevice->UnicodeFiFo->Tail;
   1110   ASSERT (Tail < FIFO_MAX_NUMBER + 1);
   1111 
   1112 
   1113   if (IsUnicodeFiFoFull (TerminalDevice)) {
   1114     //
   1115     // Unicode FIFO is full
   1116     //
   1117     return FALSE;
   1118   }
   1119 
   1120   TerminalDevice->UnicodeFiFo->Data[Tail]  = Input;
   1121 
   1122   TerminalDevice->UnicodeFiFo->Tail        = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
   1123 
   1124   return TRUE;
   1125 }
   1126 
   1127 /**
   1128   Remove one pre-fetched key out of the Unicode FIFO buffer.
   1129   The caller should guarantee that Unicode FIFO buffer is not empty
   1130   by IsUnicodeFiFoEmpty ().
   1131 
   1132   @param  TerminalDevice       Terminal driver private structure.
   1133   @param  Output               The key will be removed.
   1134 
   1135 **/
   1136 VOID
   1137 UnicodeFiFoRemoveOneKey (
   1138   TERMINAL_DEV  *TerminalDevice,
   1139   UINT16        *Output
   1140   )
   1141 {
   1142   UINT8 Head;
   1143 
   1144   Head = TerminalDevice->UnicodeFiFo->Head;
   1145   ASSERT (Head < FIFO_MAX_NUMBER + 1);
   1146 
   1147   *Output = TerminalDevice->UnicodeFiFo->Data[Head];
   1148 
   1149   TerminalDevice->UnicodeFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
   1150 }
   1151 
   1152 /**
   1153   Clarify whether Unicode FIFO buffer is empty.
   1154 
   1155   @param  TerminalDevice       Terminal driver private structure
   1156 
   1157   @retval TRUE                 If Unicode FIFO buffer is empty.
   1158   @retval FALSE                If Unicode FIFO buffer is not empty.
   1159 
   1160 **/
   1161 BOOLEAN
   1162 IsUnicodeFiFoEmpty (
   1163   TERMINAL_DEV  *TerminalDevice
   1164   )
   1165 {
   1166   if (TerminalDevice->UnicodeFiFo->Head == TerminalDevice->UnicodeFiFo->Tail) {
   1167     return TRUE;
   1168   } else {
   1169     return FALSE;
   1170   }
   1171 }
   1172 
   1173 /**
   1174   Clarify whether Unicode FIFO buffer is full.
   1175 
   1176   @param  TerminalDevice       Terminal driver private structure
   1177 
   1178   @retval TRUE                 If Unicode FIFO buffer is full.
   1179   @retval FALSE                If Unicode FIFO buffer is not full.
   1180 
   1181 **/
   1182 BOOLEAN
   1183 IsUnicodeFiFoFull (
   1184   TERMINAL_DEV  *TerminalDevice
   1185   )
   1186 {
   1187   UINT8 Tail;
   1188   UINT8 Head;
   1189 
   1190   Tail  = TerminalDevice->UnicodeFiFo->Tail;
   1191   Head  = TerminalDevice->UnicodeFiFo->Head;
   1192 
   1193   if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
   1194 
   1195     return TRUE;
   1196   }
   1197 
   1198   return FALSE;
   1199 }
   1200 
   1201 /**
   1202   Count Unicode FIFO buffer.
   1203 
   1204   @param  TerminalDevice       Terminal driver private structure
   1205 
   1206   @return The count in bytes of Unicode FIFO.
   1207 
   1208 **/
   1209 UINT8
   1210 UnicodeFiFoGetKeyCount (
   1211   TERMINAL_DEV    *TerminalDevice
   1212   )
   1213 {
   1214   UINT8 Tail;
   1215   UINT8 Head;
   1216 
   1217   Tail  = TerminalDevice->UnicodeFiFo->Tail;
   1218   Head  = TerminalDevice->UnicodeFiFo->Head;
   1219 
   1220   if (Tail >= Head) {
   1221     return (UINT8) (Tail - Head);
   1222   } else {
   1223     return (UINT8) (Tail + FIFO_MAX_NUMBER + 1 - Head);
   1224   }
   1225 }
   1226 
   1227 /**
   1228   Update the Unicode characters from a terminal input device into EFI Keys FIFO.
   1229 
   1230   @param TerminalDevice   The terminal device to use to translate raw input into EFI Keys
   1231 
   1232 **/
   1233 VOID
   1234 UnicodeToEfiKeyFlushState (
   1235   IN  TERMINAL_DEV    *TerminalDevice
   1236   )
   1237 {
   1238   EFI_INPUT_KEY Key;
   1239   UINT32        InputState;
   1240 
   1241   InputState = TerminalDevice->InputState;
   1242 
   1243   if (IsEfiKeyFiFoFull (TerminalDevice)) {
   1244     return;
   1245   }
   1246 
   1247   if ((InputState & INPUT_STATE_ESC) != 0) {
   1248     Key.ScanCode    = SCAN_ESC;
   1249     Key.UnicodeChar = 0;
   1250     EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
   1251   }
   1252 
   1253   if ((InputState & INPUT_STATE_CSI) != 0) {
   1254     Key.ScanCode    = SCAN_NULL;
   1255     Key.UnicodeChar = CSI;
   1256     EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
   1257   }
   1258 
   1259   if ((InputState & INPUT_STATE_LEFTOPENBRACKET) != 0) {
   1260     Key.ScanCode    = SCAN_NULL;
   1261     Key.UnicodeChar = LEFTOPENBRACKET;
   1262     EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
   1263   }
   1264 
   1265   if ((InputState & INPUT_STATE_O) != 0) {
   1266     Key.ScanCode    = SCAN_NULL;
   1267     Key.UnicodeChar = 'O';
   1268     EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
   1269   }
   1270 
   1271   if ((InputState & INPUT_STATE_2) != 0) {
   1272     Key.ScanCode    = SCAN_NULL;
   1273     Key.UnicodeChar = '2';
   1274     EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
   1275   }
   1276 
   1277   //
   1278   // Cancel the timer.
   1279   //
   1280   gBS->SetTimer (
   1281         TerminalDevice->TwoSecondTimeOut,
   1282         TimerCancel,
   1283         0
   1284         );
   1285 
   1286   TerminalDevice->InputState = INPUT_STATE_DEFAULT;
   1287 }
   1288 
   1289 
   1290 /**
   1291   Converts a stream of Unicode characters from a terminal input device into EFI Keys that
   1292   can be read through the Simple Input Protocol.
   1293 
   1294   The table below shows the keyboard input mappings that this function supports.
   1295   If the ESC sequence listed in one of the columns is presented, then it is translated
   1296   into the corresponding EFI Scan Code.  If a matching sequence is not found, then the raw
   1297   key strokes are converted into EFI Keys.
   1298 
   1299   2 seconds are allowed for an ESC sequence to be completed.  If the ESC sequence is not
   1300   completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
   1301   converted into EFI Keys.
   1302   There is one special input sequence that will force the system to reset.
   1303   This is ESC R ESC r ESC R.
   1304 
   1305   Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100.
   1306         The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 /
   1307         DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example.
   1308 
   1309   Symbols used in table below
   1310   ===========================
   1311     ESC = 0x1B
   1312     CSI = 0x9B
   1313     DEL = 0x7f
   1314     ^   = CTRL
   1315 
   1316   +=========+======+===========+==========+==========+
   1317   |         | EFI  | UEFI 2.0  |          |          |
   1318   |         | Scan |           |  VT100+  |          |
   1319   |   KEY   | Code |  PC ANSI  |  VTUTF8  |   VT100  |
   1320   +=========+======+===========+==========+==========+
   1321   | NULL    | 0x00 |           |          |          |
   1322   | UP      | 0x01 | ESC [ A   | ESC [ A  | ESC [ A  |
   1323   | DOWN    | 0x02 | ESC [ B   | ESC [ B  | ESC [ B  |
   1324   | RIGHT   | 0x03 | ESC [ C   | ESC [ C  | ESC [ C  |
   1325   | LEFT    | 0x04 | ESC [ D   | ESC [ D  | ESC [ D  |
   1326   | HOME    | 0x05 | ESC [ H   | ESC h    | ESC [ H  |
   1327   | END     | 0x06 | ESC [ F   | ESC k    | ESC [ K  |
   1328   | INSERT  | 0x07 | ESC [ @   | ESC +    | ESC [ @  |
   1329   |         |      | ESC [ L   |          | ESC [ L  |
   1330   | DELETE  | 0x08 | ESC [ X   | ESC -    | ESC [ P  |
   1331   | PG UP   | 0x09 | ESC [ I   | ESC ?    | ESC [ V  |
   1332   |         |      |           |          | ESC [ ?  |
   1333   | PG DOWN | 0x0A | ESC [ G   | ESC /    | ESC [ U  |
   1334   |         |      |           |          | ESC [ /  |
   1335   | F1      | 0x0B | ESC [ M   | ESC 1    | ESC O P  |
   1336   | F2      | 0x0C | ESC [ N   | ESC 2    | ESC O Q  |
   1337   | F3      | 0x0D | ESC [ O   | ESC 3    | ESC O w  |
   1338   | F4      | 0x0E | ESC [ P   | ESC 4    | ESC O x  |
   1339   | F5      | 0x0F | ESC [ Q   | ESC 5    | ESC O t  |
   1340   | F6      | 0x10 | ESC [ R   | ESC 6    | ESC O u  |
   1341   | F7      | 0x11 | ESC [ S   | ESC 7    | ESC O q  |
   1342   | F8      | 0x12 | ESC [ T   | ESC 8    | ESC O r  |
   1343   | F9      | 0x13 | ESC [ U   | ESC 9    | ESC O p  |
   1344   | F10     | 0x14 | ESC [ V   | ESC 0    | ESC O M  |
   1345   | Escape  | 0x17 | ESC       | ESC      | ESC      |
   1346   | F11     | 0x15 |           | ESC !    |          |
   1347   | F12     | 0x16 |           | ESC @    |          |
   1348   +=========+======+===========+==========+==========+
   1349 
   1350   Special Mappings
   1351   ================
   1352   ESC R ESC r ESC R = Reset System
   1353 
   1354   @param TerminalDevice   The terminal device to use to translate raw input into EFI Keys
   1355 
   1356 **/
   1357 VOID
   1358 UnicodeToEfiKey (
   1359   IN  TERMINAL_DEV    *TerminalDevice
   1360   )
   1361 {
   1362   EFI_STATUS          Status;
   1363   EFI_STATUS          TimerStatus;
   1364   UINT16              UnicodeChar;
   1365   EFI_INPUT_KEY       Key;
   1366   BOOLEAN             SetDefaultResetState;
   1367 
   1368   TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
   1369 
   1370   if (!EFI_ERROR (TimerStatus)) {
   1371     UnicodeToEfiKeyFlushState (TerminalDevice);
   1372     TerminalDevice->ResetState = RESET_STATE_DEFAULT;
   1373   }
   1374 
   1375   while (!IsUnicodeFiFoEmpty (TerminalDevice) && !IsEfiKeyFiFoFull (TerminalDevice)) {
   1376 
   1377     if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
   1378       //
   1379       // Check to see if the 2 seconds timer has expired
   1380       //
   1381       TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
   1382       if (!EFI_ERROR (TimerStatus)) {
   1383         UnicodeToEfiKeyFlushState (TerminalDevice);
   1384         TerminalDevice->ResetState = RESET_STATE_DEFAULT;
   1385       }
   1386     }
   1387 
   1388     //
   1389     // Fetch one Unicode character from the Unicode FIFO
   1390     //
   1391     UnicodeFiFoRemoveOneKey (TerminalDevice, &UnicodeChar);
   1392 
   1393     SetDefaultResetState = TRUE;
   1394 
   1395     switch (TerminalDevice->InputState) {
   1396     case INPUT_STATE_DEFAULT:
   1397 
   1398       break;
   1399 
   1400     case INPUT_STATE_ESC:
   1401 
   1402       if (UnicodeChar == LEFTOPENBRACKET) {
   1403         TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET;
   1404         TerminalDevice->ResetState = RESET_STATE_DEFAULT;
   1405         continue;
   1406       }
   1407 
   1408       if (UnicodeChar == 'O' && (TerminalDevice->TerminalType == VT100TYPE ||
   1409                                  TerminalDevice->TerminalType == TTYTERMTYPE)) {
   1410         TerminalDevice->InputState |= INPUT_STATE_O;
   1411         TerminalDevice->ResetState = RESET_STATE_DEFAULT;
   1412         continue;
   1413       }
   1414 
   1415       Key.ScanCode = SCAN_NULL;
   1416 
   1417       if (TerminalDevice->TerminalType == VT100PLUSTYPE ||
   1418           TerminalDevice->TerminalType == VTUTF8TYPE) {
   1419         switch (UnicodeChar) {
   1420         case '1':
   1421           Key.ScanCode = SCAN_F1;
   1422           break;
   1423         case '2':
   1424           Key.ScanCode = SCAN_F2;
   1425           break;
   1426         case '3':
   1427           Key.ScanCode = SCAN_F3;
   1428           break;
   1429         case '4':
   1430           Key.ScanCode = SCAN_F4;
   1431           break;
   1432         case '5':
   1433           Key.ScanCode = SCAN_F5;
   1434           break;
   1435         case '6':
   1436           Key.ScanCode = SCAN_F6;
   1437           break;
   1438         case '7':
   1439           Key.ScanCode = SCAN_F7;
   1440           break;
   1441         case '8':
   1442           Key.ScanCode = SCAN_F8;
   1443           break;
   1444         case '9':
   1445           Key.ScanCode = SCAN_F9;
   1446           break;
   1447         case '0':
   1448           Key.ScanCode = SCAN_F10;
   1449           break;
   1450         case '!':
   1451           Key.ScanCode = SCAN_F11;
   1452           break;
   1453         case '@':
   1454           Key.ScanCode = SCAN_F12;
   1455           break;
   1456         case 'h':
   1457           Key.ScanCode = SCAN_HOME;
   1458           break;
   1459         case 'k':
   1460           Key.ScanCode = SCAN_END;
   1461           break;
   1462         case '+':
   1463           Key.ScanCode = SCAN_INSERT;
   1464           break;
   1465         case '-':
   1466           Key.ScanCode = SCAN_DELETE;
   1467           break;
   1468         case '/':
   1469           Key.ScanCode = SCAN_PAGE_DOWN;
   1470           break;
   1471         case '?':
   1472           Key.ScanCode = SCAN_PAGE_UP;
   1473           break;
   1474         default :
   1475           break;
   1476         }
   1477       }
   1478 
   1479       switch (UnicodeChar) {
   1480       case 'R':
   1481         if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) {
   1482           TerminalDevice->ResetState = RESET_STATE_ESC_R;
   1483           SetDefaultResetState = FALSE;
   1484         } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_R) {
   1485           gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
   1486         }
   1487         Key.ScanCode = SCAN_NULL;
   1488         break;
   1489       case 'r':
   1490         if (TerminalDevice->ResetState == RESET_STATE_ESC_R) {
   1491           TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_R;
   1492           SetDefaultResetState = FALSE;
   1493         }
   1494         Key.ScanCode = SCAN_NULL;
   1495         break;
   1496       default :
   1497         break;
   1498       }
   1499 
   1500       if (SetDefaultResetState) {
   1501         TerminalDevice->ResetState = RESET_STATE_DEFAULT;
   1502       }
   1503 
   1504       if (Key.ScanCode != SCAN_NULL) {
   1505         Key.UnicodeChar = 0;
   1506         EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
   1507         TerminalDevice->InputState = INPUT_STATE_DEFAULT;
   1508         UnicodeToEfiKeyFlushState (TerminalDevice);
   1509         continue;
   1510       }
   1511 
   1512       UnicodeToEfiKeyFlushState (TerminalDevice);
   1513 
   1514       break;
   1515 
   1516     case INPUT_STATE_ESC | INPUT_STATE_O:
   1517 
   1518       TerminalDevice->ResetState = RESET_STATE_DEFAULT;
   1519 
   1520       Key.ScanCode = SCAN_NULL;
   1521 
   1522       if (TerminalDevice->TerminalType == VT100TYPE) {
   1523         switch (UnicodeChar) {
   1524         case 'P':
   1525           Key.ScanCode = SCAN_F1;
   1526           break;
   1527         case 'Q':
   1528           Key.ScanCode = SCAN_F2;
   1529           break;
   1530         case 'w':
   1531           Key.ScanCode = SCAN_F3;
   1532           break;
   1533         case 'x':
   1534           Key.ScanCode = SCAN_F4;
   1535           break;
   1536         case 't':
   1537           Key.ScanCode = SCAN_F5;
   1538           break;
   1539         case 'u':
   1540           Key.ScanCode = SCAN_F6;
   1541           break;
   1542         case 'q':
   1543           Key.ScanCode = SCAN_F7;
   1544           break;
   1545         case 'r':
   1546           Key.ScanCode = SCAN_F8;
   1547           break;
   1548         case 'p':
   1549           Key.ScanCode = SCAN_F9;
   1550           break;
   1551         case 'M':
   1552           Key.ScanCode = SCAN_F10;
   1553           break;
   1554         default :
   1555           break;
   1556         }
   1557       } else if (TerminalDevice->TerminalType == TTYTERMTYPE) {
   1558         /* Also accept VT100 escape codes for F1-F4, HOME and END for TTY term */
   1559         switch (UnicodeChar) {
   1560         case 'P':
   1561           Key.ScanCode = SCAN_F1;
   1562           break;
   1563         case 'Q':
   1564           Key.ScanCode = SCAN_F2;
   1565           break;
   1566         case 'R':
   1567           Key.ScanCode = SCAN_F3;
   1568           break;
   1569         case 'S':
   1570           Key.ScanCode = SCAN_F4;
   1571           break;
   1572         case 'H':
   1573           Key.ScanCode = SCAN_HOME;
   1574           break;
   1575         case 'F':
   1576           Key.ScanCode = SCAN_END;
   1577           break;
   1578         }
   1579       }
   1580 
   1581       if (Key.ScanCode != SCAN_NULL) {
   1582         Key.UnicodeChar = 0;
   1583         EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
   1584         TerminalDevice->InputState = INPUT_STATE_DEFAULT;
   1585         UnicodeToEfiKeyFlushState (TerminalDevice);
   1586         continue;
   1587       }
   1588 
   1589       UnicodeToEfiKeyFlushState (TerminalDevice);
   1590 
   1591       break;
   1592 
   1593     case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET:
   1594 
   1595       TerminalDevice->ResetState = RESET_STATE_DEFAULT;
   1596 
   1597       Key.ScanCode = SCAN_NULL;
   1598 
   1599       if (TerminalDevice->TerminalType == PCANSITYPE    ||
   1600           TerminalDevice->TerminalType == VT100TYPE     ||
   1601           TerminalDevice->TerminalType == VT100PLUSTYPE ||
   1602           TerminalDevice->TerminalType == VTUTF8TYPE    ||
   1603           TerminalDevice->TerminalType == TTYTERMTYPE) {
   1604         switch (UnicodeChar) {
   1605         case 'A':
   1606           Key.ScanCode = SCAN_UP;
   1607           break;
   1608         case 'B':
   1609           Key.ScanCode = SCAN_DOWN;
   1610           break;
   1611         case 'C':
   1612           Key.ScanCode = SCAN_RIGHT;
   1613           break;
   1614         case 'D':
   1615           Key.ScanCode = SCAN_LEFT;
   1616           break;
   1617         case 'H':
   1618           if (TerminalDevice->TerminalType == PCANSITYPE ||
   1619               TerminalDevice->TerminalType == VT100TYPE  ||
   1620               TerminalDevice->TerminalType == TTYTERMTYPE) {
   1621             Key.ScanCode = SCAN_HOME;
   1622           }
   1623           break;
   1624         case 'F':
   1625           if (TerminalDevice->TerminalType == PCANSITYPE ||
   1626               TerminalDevice->TerminalType == TTYTERMTYPE) {
   1627             Key.ScanCode = SCAN_END;
   1628           }
   1629           break;
   1630         case 'K':
   1631           if (TerminalDevice->TerminalType == VT100TYPE) {
   1632             Key.ScanCode = SCAN_END;
   1633           }
   1634           break;
   1635         case 'L':
   1636         case '@':
   1637           if (TerminalDevice->TerminalType == PCANSITYPE ||
   1638               TerminalDevice->TerminalType == VT100TYPE) {
   1639             Key.ScanCode = SCAN_INSERT;
   1640           }
   1641           break;
   1642         case 'X':
   1643           if (TerminalDevice->TerminalType == PCANSITYPE) {
   1644             Key.ScanCode = SCAN_DELETE;
   1645           }
   1646           break;
   1647         case 'P':
   1648           if (TerminalDevice->TerminalType == VT100TYPE) {
   1649             Key.ScanCode = SCAN_DELETE;
   1650           } else if (TerminalDevice->TerminalType == PCANSITYPE) {
   1651             Key.ScanCode = SCAN_F4;
   1652           }
   1653           break;
   1654         case 'I':
   1655           if (TerminalDevice->TerminalType == PCANSITYPE) {
   1656             Key.ScanCode = SCAN_PAGE_UP;
   1657           }
   1658           break;
   1659         case 'V':
   1660           if (TerminalDevice->TerminalType == PCANSITYPE) {
   1661             Key.ScanCode = SCAN_F10;
   1662           }
   1663           break;
   1664         case '?':
   1665           if (TerminalDevice->TerminalType == VT100TYPE) {
   1666             Key.ScanCode = SCAN_PAGE_UP;
   1667           }
   1668           break;
   1669         case 'G':
   1670           if (TerminalDevice->TerminalType == PCANSITYPE) {
   1671             Key.ScanCode = SCAN_PAGE_DOWN;
   1672           }
   1673           break;
   1674         case 'U':
   1675           if (TerminalDevice->TerminalType == PCANSITYPE) {
   1676             Key.ScanCode = SCAN_F9;
   1677           }
   1678           break;
   1679         case '/':
   1680           if (TerminalDevice->TerminalType == VT100TYPE) {
   1681             Key.ScanCode = SCAN_PAGE_DOWN;
   1682           }
   1683           break;
   1684         case 'M':
   1685           if (TerminalDevice->TerminalType == PCANSITYPE) {
   1686             Key.ScanCode = SCAN_F1;
   1687           }
   1688           break;
   1689         case 'N':
   1690           if (TerminalDevice->TerminalType == PCANSITYPE) {
   1691             Key.ScanCode = SCAN_F2;
   1692           }
   1693           break;
   1694         case 'O':
   1695           if (TerminalDevice->TerminalType == PCANSITYPE) {
   1696             Key.ScanCode = SCAN_F3;
   1697           }
   1698           break;
   1699         case 'Q':
   1700           if (TerminalDevice->TerminalType == PCANSITYPE) {
   1701             Key.ScanCode = SCAN_F5;
   1702           }
   1703           break;
   1704         case 'R':
   1705           if (TerminalDevice->TerminalType == PCANSITYPE) {
   1706             Key.ScanCode = SCAN_F6;
   1707           }
   1708           break;
   1709         case 'S':
   1710           if (TerminalDevice->TerminalType == PCANSITYPE) {
   1711             Key.ScanCode = SCAN_F7;
   1712           }
   1713           break;
   1714         case 'T':
   1715           if (TerminalDevice->TerminalType == PCANSITYPE) {
   1716             Key.ScanCode = SCAN_F8;
   1717           }
   1718           break;
   1719         default :
   1720           break;
   1721         }
   1722       }
   1723 
   1724       /*
   1725        * The VT220 escape codes that the TTY terminal accepts all have
   1726        * numeric codes, and there are no ambiguous prefixes shared with
   1727        * other terminal types.
   1728        */
   1729       if (TerminalDevice->TerminalType == TTYTERMTYPE &&
   1730           Key.ScanCode == SCAN_NULL &&
   1731           UnicodeChar >= '0' &&
   1732           UnicodeChar <= '9') {
   1733         TerminalDevice->TtyEscapeStr[0] = UnicodeChar;
   1734         TerminalDevice->TtyEscapeIndex = 1;
   1735         TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET_2;
   1736         continue;
   1737       }
   1738 
   1739       if (Key.ScanCode != SCAN_NULL) {
   1740         Key.UnicodeChar = 0;
   1741         EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
   1742         TerminalDevice->InputState = INPUT_STATE_DEFAULT;
   1743         UnicodeToEfiKeyFlushState (TerminalDevice);
   1744         continue;
   1745       }
   1746 
   1747       UnicodeToEfiKeyFlushState (TerminalDevice);
   1748 
   1749       break;
   1750 
   1751 
   1752     case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_LEFTOPENBRACKET_2:
   1753       /*
   1754        * Here we handle the VT220 escape codes that we accept.  This
   1755        * state is only used by the TTY terminal type.
   1756        */
   1757       Key.ScanCode = SCAN_NULL;
   1758       if (TerminalDevice->TerminalType == TTYTERMTYPE) {
   1759 
   1760         if (UnicodeChar == '~' && TerminalDevice->TtyEscapeIndex <= 2) {
   1761           UINT16 EscCode;
   1762           TerminalDevice->TtyEscapeStr[TerminalDevice->TtyEscapeIndex] = 0; /* Terminate string */
   1763           EscCode = (UINT16) StrDecimalToUintn(TerminalDevice->TtyEscapeStr);
   1764           switch (EscCode) {
   1765           case 2:
   1766               Key.ScanCode = SCAN_INSERT;
   1767               break;
   1768           case 3:
   1769               Key.ScanCode = SCAN_DELETE;
   1770               break;
   1771           case 5:
   1772               Key.ScanCode = SCAN_PAGE_UP;
   1773               break;
   1774           case 6:
   1775               Key.ScanCode = SCAN_PAGE_DOWN;
   1776               break;
   1777           case 11:
   1778           case 12:
   1779           case 13:
   1780           case 14:
   1781           case 15:
   1782             Key.ScanCode = SCAN_F1 + EscCode - 11;
   1783             break;
   1784           case 17:
   1785           case 18:
   1786           case 19:
   1787           case 20:
   1788           case 21:
   1789             Key.ScanCode = SCAN_F6 + EscCode - 17;
   1790             break;
   1791           case 23:
   1792           case 24:
   1793             Key.ScanCode = SCAN_F11 + EscCode - 23;
   1794             break;
   1795           default:
   1796             break;
   1797           }
   1798         } else if (TerminalDevice->TtyEscapeIndex == 1){
   1799           /* 2 character escape code   */
   1800           TerminalDevice->TtyEscapeStr[TerminalDevice->TtyEscapeIndex++] = UnicodeChar;
   1801           continue;
   1802         }
   1803         else {
   1804           DEBUG ((EFI_D_ERROR, "Unexpected state in escape2\n"));
   1805         }
   1806       }
   1807       TerminalDevice->ResetState = RESET_STATE_DEFAULT;
   1808 
   1809       if (Key.ScanCode != SCAN_NULL) {
   1810         Key.UnicodeChar = 0;
   1811         EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
   1812         TerminalDevice->InputState = INPUT_STATE_DEFAULT;
   1813         UnicodeToEfiKeyFlushState (TerminalDevice);
   1814         continue;
   1815       }
   1816 
   1817       UnicodeToEfiKeyFlushState (TerminalDevice);
   1818       break;
   1819 
   1820     default:
   1821       //
   1822       // Invalid state. This should never happen.
   1823       //
   1824       ASSERT (FALSE);
   1825 
   1826       UnicodeToEfiKeyFlushState (TerminalDevice);
   1827 
   1828       break;
   1829     }
   1830 
   1831     if (UnicodeChar == ESC) {
   1832       TerminalDevice->InputState = INPUT_STATE_ESC;
   1833     }
   1834 
   1835     if (UnicodeChar == CSI) {
   1836       TerminalDevice->InputState = INPUT_STATE_CSI;
   1837     }
   1838 
   1839     if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
   1840       Status = gBS->SetTimer(
   1841                       TerminalDevice->TwoSecondTimeOut,
   1842                       TimerRelative,
   1843                       (UINT64)20000000
   1844                       );
   1845       ASSERT_EFI_ERROR (Status);
   1846       continue;
   1847     }
   1848 
   1849     if (SetDefaultResetState) {
   1850       TerminalDevice->ResetState = RESET_STATE_DEFAULT;
   1851     }
   1852 
   1853     if (UnicodeChar == DEL) {
   1854       if (TerminalDevice->TerminalType == TTYTERMTYPE) {
   1855         Key.ScanCode    = SCAN_NULL;
   1856         Key.UnicodeChar = CHAR_BACKSPACE;
   1857       }
   1858       else {
   1859         Key.ScanCode    = SCAN_DELETE;
   1860         Key.UnicodeChar = 0;
   1861       }
   1862     } else {
   1863       Key.ScanCode    = SCAN_NULL;
   1864       Key.UnicodeChar = UnicodeChar;
   1865     }
   1866 
   1867     EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
   1868   }
   1869 }
   1870