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