TerminalConIn.c revision 6e3227c88c0a53df0a963628b1110f7d39e89883
1/** @file
2  Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol.
3
4(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
6This program and the accompanying materials
7are licensed and made available under the terms and conditions of the BSD License
8which accompanies this distribution.  The full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT 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**/
33EFI_STATUS
34ReadKeyStrokeWorker (
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**/
67EFI_STATUS
68EFIAPI
69TerminalConInReset (
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**/
121EFI_STATUS
122EFIAPI
123TerminalConInReadKeyStroke (
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**/
164BOOLEAN
165IsKeyRegistered (
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**/
190VOID
191EFIAPI
192TerminalConInWaitForKeyEx (
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**/
215EFI_STATUS
216EFIAPI
217TerminalConInResetEx (
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**/
253EFI_STATUS
254EFIAPI
255TerminalConInReadKeyStrokeEx (
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**/
288EFI_STATUS
289EFIAPI
290TerminalConInSetState (
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**/
326EFI_STATUS
327EFIAPI
328TerminalConInRegisterKeyNotify (
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**/
397EFI_STATUS
398EFIAPI
399TerminalConInUnregisterKeyNotify (
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**/
447VOID
448TranslateRawDataToEfiKey (
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**/
487VOID
488EFIAPI
489TerminalConInWaitForKey (
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**/
510VOID
511EFIAPI
512TerminalConInTimerHandler (
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                        Mode->ReceiveFifoDepth,
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  //
566  Status = SerialIo->GetControl (SerialIo, &Control);
567
568  if ((Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) == 0) {
569    //
570    // Fetch all the keys in the serial buffer,
571    // and insert the byte stream into RawFIFO.
572    //
573    while (!IsRawFiFoFull (TerminalDevice)) {
574
575      Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input);
576
577      if (EFI_ERROR (Status)) {
578        if (Status == EFI_DEVICE_ERROR) {
579          REPORT_STATUS_CODE_WITH_DEVICE_PATH (
580            EFI_ERROR_CODE | EFI_ERROR_MINOR,
581            (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_INPUT_ERROR),
582            TerminalDevice->DevicePath
583            );
584        }
585        break;
586      }
587
588      RawFiFoInsertOneKey (TerminalDevice, Input);
589    }
590  }
591
592  //
593  // Translate all the raw data in RawFIFO into EFI Key,
594  // according to different terminal type supported.
595  //
596  TranslateRawDataToEfiKey (TerminalDevice);
597}
598
599/**
600  Get one key out of serial buffer.
601
602  @param  SerialIo           Serial I/O protocol attached to the serial device.
603  @param  Output             The fetched key.
604
605  @retval EFI_NOT_READY      If serial buffer is empty.
606  @retval EFI_DEVICE_ERROR   If reading serial buffer encounter error.
607  @retval EFI_SUCCESS        If reading serial buffer successfully, put
608                             the fetched key to the parameter output.
609
610**/
611EFI_STATUS
612GetOneKeyFromSerial (
613  EFI_SERIAL_IO_PROTOCOL  *SerialIo,
614  UINT8                   *Output
615  )
616{
617  EFI_STATUS  Status;
618  UINTN       Size;
619
620  Size    = 1;
621  *Output = 0;
622
623  //
624  // Read one key from serial I/O device.
625  //
626  Status  = SerialIo->Read (SerialIo, &Size, Output);
627
628  if (EFI_ERROR (Status)) {
629
630    if (Status == EFI_TIMEOUT) {
631      return EFI_NOT_READY;
632    }
633
634    return EFI_DEVICE_ERROR;
635
636  }
637
638  if (*Output == 0) {
639    return EFI_NOT_READY;
640  }
641
642  return EFI_SUCCESS;
643}
644
645/**
646  Insert one byte raw data into the Raw Data FIFO.
647
648  @param  TerminalDevice       Terminal driver private structure.
649  @param  Input                The key will be input.
650
651  @retval TRUE                 If insert successfully.
652  @retval FALSE                If Raw Data buffer is full before key insertion,
653                               and the key is lost.
654
655**/
656BOOLEAN
657RawFiFoInsertOneKey (
658  TERMINAL_DEV      *TerminalDevice,
659  UINT8             Input
660  )
661{
662  UINT8 Tail;
663
664  Tail = TerminalDevice->RawFiFo->Tail;
665
666  if (IsRawFiFoFull (TerminalDevice)) {
667    //
668    // Raw FIFO is full
669    //
670    return FALSE;
671  }
672
673  TerminalDevice->RawFiFo->Data[Tail]  = Input;
674
675  TerminalDevice->RawFiFo->Tail        = (UINT8) ((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1));
676
677  return TRUE;
678}
679
680/**
681  Remove one pre-fetched key out of the Raw Data FIFO.
682
683  @param  TerminalDevice       Terminal driver private structure.
684  @param  Output               The key will be removed.
685
686  @retval TRUE                 If insert successfully.
687  @retval FALSE                If Raw Data FIFO buffer is empty before remove operation.
688
689**/
690BOOLEAN
691RawFiFoRemoveOneKey (
692  TERMINAL_DEV  *TerminalDevice,
693  UINT8         *Output
694  )
695{
696  UINT8 Head;
697
698  Head = TerminalDevice->RawFiFo->Head;
699
700  if (IsRawFiFoEmpty (TerminalDevice)) {
701    //
702    //  FIFO is empty
703    //
704    *Output = 0;
705    return FALSE;
706  }
707
708  *Output                       = TerminalDevice->RawFiFo->Data[Head];
709
710  TerminalDevice->RawFiFo->Head  = (UINT8) ((Head + 1) % (RAW_FIFO_MAX_NUMBER + 1));
711
712  return TRUE;
713}
714
715/**
716  Clarify whether Raw Data FIFO buffer is empty.
717
718  @param  TerminalDevice       Terminal driver private structure
719
720  @retval TRUE                 If Raw Data FIFO buffer is empty.
721  @retval FALSE                If Raw Data FIFO buffer is not empty.
722
723**/
724BOOLEAN
725IsRawFiFoEmpty (
726  TERMINAL_DEV  *TerminalDevice
727  )
728{
729  if (TerminalDevice->RawFiFo->Head == TerminalDevice->RawFiFo->Tail) {
730    return TRUE;
731  } else {
732    return FALSE;
733  }
734}
735
736/**
737  Clarify whether Raw Data FIFO buffer is full.
738
739  @param  TerminalDevice       Terminal driver private structure
740
741  @retval TRUE                 If Raw Data FIFO buffer is full.
742  @retval FALSE                If Raw Data FIFO buffer is not full.
743
744**/
745BOOLEAN
746IsRawFiFoFull (
747  TERMINAL_DEV  *TerminalDevice
748  )
749{
750  UINT8 Tail;
751  UINT8 Head;
752
753  Tail  = TerminalDevice->RawFiFo->Tail;
754  Head  = TerminalDevice->RawFiFo->Head;
755
756  if (((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)) == Head) {
757
758    return TRUE;
759  }
760
761  return FALSE;
762}
763
764/**
765  Insert one pre-fetched key into the FIFO buffer.
766
767  @param  TerminalDevice       Terminal driver private structure.
768  @param  Key                  The key will be input.
769
770  @retval TRUE                 If insert successfully.
771  @retval FALSE                If FIFO buffer is full before key insertion,
772                               and the key is lost.
773
774**/
775BOOLEAN
776EfiKeyFiFoInsertOneKey (
777  TERMINAL_DEV                    *TerminalDevice,
778  EFI_INPUT_KEY                   *Key
779  )
780{
781  UINT8                           Tail;
782  LIST_ENTRY                      *Link;
783  LIST_ENTRY                      *NotifyList;
784  TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;
785  EFI_KEY_DATA                    KeyData;
786
787  Tail = TerminalDevice->EfiKeyFiFo->Tail;
788
789  CopyMem (&KeyData.Key, Key, sizeof (EFI_INPUT_KEY));
790  KeyData.KeyState.KeyShiftState  = 0;
791  KeyData.KeyState.KeyToggleState = 0;
792
793  //
794  // Invoke notification functions if exist
795  //
796  NotifyList = &TerminalDevice->NotifyList;
797  for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
798    CurrentNotify = CR (
799                      Link,
800                      TERMINAL_CONSOLE_IN_EX_NOTIFY,
801                      NotifyEntry,
802                      TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
803                      );
804    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
805      CurrentNotify->KeyNotificationFn (&KeyData);
806    }
807  }
808  if (IsEfiKeyFiFoFull (TerminalDevice)) {
809    //
810    // Efi Key FIFO is full
811    //
812    return FALSE;
813  }
814
815  CopyMem (&TerminalDevice->EfiKeyFiFo->Data[Tail], Key, sizeof (EFI_INPUT_KEY));
816
817  TerminalDevice->EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
818
819  return TRUE;
820}
821
822/**
823  Remove one pre-fetched key out of the FIFO buffer.
824
825  @param  TerminalDevice       Terminal driver private structure.
826  @param  Output               The key will be removed.
827
828  @retval TRUE                 If insert successfully.
829  @retval FALSE                If FIFO buffer is empty before remove operation.
830
831**/
832BOOLEAN
833EfiKeyFiFoRemoveOneKey (
834  TERMINAL_DEV  *TerminalDevice,
835  EFI_INPUT_KEY *Output
836  )
837{
838  UINT8 Head;
839
840  Head = TerminalDevice->EfiKeyFiFo->Head;
841  ASSERT (Head < FIFO_MAX_NUMBER + 1);
842
843  if (IsEfiKeyFiFoEmpty (TerminalDevice)) {
844    //
845    //  FIFO is empty
846    //
847    Output->ScanCode    = SCAN_NULL;
848    Output->UnicodeChar = 0;
849    return FALSE;
850  }
851
852  CopyMem (Output, &TerminalDevice->EfiKeyFiFo->Data[Head], sizeof (EFI_INPUT_KEY));
853
854  TerminalDevice->EfiKeyFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
855
856  return TRUE;
857}
858
859/**
860  Clarify whether FIFO buffer is empty.
861
862  @param  TerminalDevice       Terminal driver private structure
863
864  @retval TRUE                 If FIFO buffer is empty.
865  @retval FALSE                If FIFO buffer is not empty.
866
867**/
868BOOLEAN
869IsEfiKeyFiFoEmpty (
870  TERMINAL_DEV  *TerminalDevice
871  )
872{
873  if (TerminalDevice->EfiKeyFiFo->Head == TerminalDevice->EfiKeyFiFo->Tail) {
874    return TRUE;
875  } else {
876    return FALSE;
877  }
878}
879
880/**
881  Clarify whether FIFO buffer is full.
882
883  @param  TerminalDevice       Terminal driver private structure
884
885  @retval TRUE                 If FIFO buffer is full.
886  @retval FALSE                If FIFO buffer is not full.
887
888**/
889BOOLEAN
890IsEfiKeyFiFoFull (
891  TERMINAL_DEV  *TerminalDevice
892  )
893{
894  UINT8 Tail;
895  UINT8 Head;
896
897  Tail  = TerminalDevice->EfiKeyFiFo->Tail;
898  Head  = TerminalDevice->EfiKeyFiFo->Head;
899
900  if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
901
902    return TRUE;
903  }
904
905  return FALSE;
906}
907
908/**
909  Insert one pre-fetched key into the Unicode FIFO buffer.
910
911  @param  TerminalDevice       Terminal driver private structure.
912  @param  Input                The key will be input.
913
914  @retval TRUE                 If insert successfully.
915  @retval FALSE                If Unicode FIFO buffer is full before key insertion,
916                               and the key is lost.
917
918**/
919BOOLEAN
920UnicodeFiFoInsertOneKey (
921  TERMINAL_DEV      *TerminalDevice,
922  UINT16            Input
923  )
924{
925  UINT8 Tail;
926
927  Tail = TerminalDevice->UnicodeFiFo->Tail;
928  ASSERT (Tail < FIFO_MAX_NUMBER + 1);
929
930
931  if (IsUnicodeFiFoFull (TerminalDevice)) {
932    //
933    // Unicode FIFO is full
934    //
935    return FALSE;
936  }
937
938  TerminalDevice->UnicodeFiFo->Data[Tail]  = Input;
939
940  TerminalDevice->UnicodeFiFo->Tail        = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
941
942  return TRUE;
943}
944
945/**
946  Remove one pre-fetched key out of the Unicode FIFO buffer.
947  The caller should guarantee that Unicode FIFO buffer is not empty
948  by IsUnicodeFiFoEmpty ().
949
950  @param  TerminalDevice       Terminal driver private structure.
951  @param  Output               The key will be removed.
952
953**/
954VOID
955UnicodeFiFoRemoveOneKey (
956  TERMINAL_DEV  *TerminalDevice,
957  UINT16        *Output
958  )
959{
960  UINT8 Head;
961
962  Head = TerminalDevice->UnicodeFiFo->Head;
963  ASSERT (Head < FIFO_MAX_NUMBER + 1);
964
965  *Output = TerminalDevice->UnicodeFiFo->Data[Head];
966
967  TerminalDevice->UnicodeFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
968}
969
970/**
971  Clarify whether Unicode FIFO buffer is empty.
972
973  @param  TerminalDevice       Terminal driver private structure
974
975  @retval TRUE                 If Unicode FIFO buffer is empty.
976  @retval FALSE                If Unicode FIFO buffer is not empty.
977
978**/
979BOOLEAN
980IsUnicodeFiFoEmpty (
981  TERMINAL_DEV  *TerminalDevice
982  )
983{
984  if (TerminalDevice->UnicodeFiFo->Head == TerminalDevice->UnicodeFiFo->Tail) {
985    return TRUE;
986  } else {
987    return FALSE;
988  }
989}
990
991/**
992  Clarify whether Unicode FIFO buffer is full.
993
994  @param  TerminalDevice       Terminal driver private structure
995
996  @retval TRUE                 If Unicode FIFO buffer is full.
997  @retval FALSE                If Unicode FIFO buffer is not full.
998
999**/
1000BOOLEAN
1001IsUnicodeFiFoFull (
1002  TERMINAL_DEV  *TerminalDevice
1003  )
1004{
1005  UINT8 Tail;
1006  UINT8 Head;
1007
1008  Tail  = TerminalDevice->UnicodeFiFo->Tail;
1009  Head  = TerminalDevice->UnicodeFiFo->Head;
1010
1011  if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
1012
1013    return TRUE;
1014  }
1015
1016  return FALSE;
1017}
1018
1019/**
1020  Count Unicode FIFO buffer.
1021
1022  @param  TerminalDevice       Terminal driver private structure
1023
1024  @return The count in bytes of Unicode FIFO.
1025
1026**/
1027UINT8
1028UnicodeFiFoGetKeyCount (
1029  TERMINAL_DEV    *TerminalDevice
1030  )
1031{
1032  UINT8 Tail;
1033  UINT8 Head;
1034
1035  Tail  = TerminalDevice->UnicodeFiFo->Tail;
1036  Head  = TerminalDevice->UnicodeFiFo->Head;
1037
1038  if (Tail >= Head) {
1039    return (UINT8) (Tail - Head);
1040  } else {
1041    return (UINT8) (Tail + FIFO_MAX_NUMBER + 1 - Head);
1042  }
1043}
1044
1045/**
1046  Update the Unicode characters from a terminal input device into EFI Keys FIFO.
1047
1048  @param TerminalDevice   The terminal device to use to translate raw input into EFI Keys
1049
1050**/
1051VOID
1052UnicodeToEfiKeyFlushState (
1053  IN  TERMINAL_DEV    *TerminalDevice
1054  )
1055{
1056  EFI_INPUT_KEY Key;
1057  UINT32        InputState;
1058
1059  InputState = TerminalDevice->InputState;
1060
1061  if (IsEfiKeyFiFoFull (TerminalDevice)) {
1062    return;
1063  }
1064
1065  if ((InputState & INPUT_STATE_ESC) != 0) {
1066    Key.ScanCode    = SCAN_ESC;
1067    Key.UnicodeChar = 0;
1068    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1069  }
1070
1071  if ((InputState & INPUT_STATE_CSI) != 0) {
1072    Key.ScanCode    = SCAN_NULL;
1073    Key.UnicodeChar = CSI;
1074    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1075  }
1076
1077  if ((InputState & INPUT_STATE_LEFTOPENBRACKET) != 0) {
1078    Key.ScanCode    = SCAN_NULL;
1079    Key.UnicodeChar = LEFTOPENBRACKET;
1080    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1081  }
1082
1083  if ((InputState & INPUT_STATE_O) != 0) {
1084    Key.ScanCode    = SCAN_NULL;
1085    Key.UnicodeChar = 'O';
1086    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1087  }
1088
1089  if ((InputState & INPUT_STATE_2) != 0) {
1090    Key.ScanCode    = SCAN_NULL;
1091    Key.UnicodeChar = '2';
1092    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1093  }
1094
1095  //
1096  // Cancel the timer.
1097  //
1098  gBS->SetTimer (
1099        TerminalDevice->TwoSecondTimeOut,
1100        TimerCancel,
1101        0
1102        );
1103
1104  TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1105}
1106
1107
1108/**
1109  Converts a stream of Unicode characters from a terminal input device into EFI Keys that
1110  can be read through the Simple Input Protocol.
1111
1112  The table below shows the keyboard input mappings that this function supports.
1113  If the ESC sequence listed in one of the columns is presented, then it is translated
1114  into the corresponding EFI Scan Code.  If a matching sequence is not found, then the raw
1115  key strokes are converted into EFI Keys.
1116
1117  2 seconds are allowed for an ESC sequence to be completed.  If the ESC sequence is not
1118  completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
1119  converted into EFI Keys.
1120  There is one special input sequence that will force the system to reset.
1121  This is ESC R ESC r ESC R.
1122
1123  Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100.
1124        The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 /
1125        DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example.
1126
1127  Symbols used in table below
1128  ===========================
1129    ESC = 0x1B
1130    CSI = 0x9B
1131    DEL = 0x7f
1132    ^   = CTRL
1133
1134  +=========+======+===========+==========+==========+
1135  |         | EFI  | UEFI 2.0  |          |          |
1136  |         | Scan |           |  VT100+  |          |
1137  |   KEY   | Code |  PC ANSI  |  VTUTF8  |   VT100  |
1138  +=========+======+===========+==========+==========+
1139  | NULL    | 0x00 |           |          |          |
1140  | UP      | 0x01 | ESC [ A   | ESC [ A  | ESC [ A  |
1141  | DOWN    | 0x02 | ESC [ B   | ESC [ B  | ESC [ B  |
1142  | RIGHT   | 0x03 | ESC [ C   | ESC [ C  | ESC [ C  |
1143  | LEFT    | 0x04 | ESC [ D   | ESC [ D  | ESC [ D  |
1144  | HOME    | 0x05 | ESC [ H   | ESC h    | ESC [ H  |
1145  | END     | 0x06 | ESC [ F   | ESC k    | ESC [ K  |
1146  | INSERT  | 0x07 | ESC [ @   | ESC +    | ESC [ @  |
1147  |         |      | ESC [ L   |          | ESC [ L  |
1148  | DELETE  | 0x08 | ESC [ X   | ESC -    | ESC [ P  |
1149  | PG UP   | 0x09 | ESC [ I   | ESC ?    | ESC [ V  |
1150  |         |      |           |          | ESC [ ?  |
1151  | PG DOWN | 0x0A | ESC [ G   | ESC /    | ESC [ U  |
1152  |         |      |           |          | ESC [ /  |
1153  | F1      | 0x0B | ESC [ M   | ESC 1    | ESC O P  |
1154  | F2      | 0x0C | ESC [ N   | ESC 2    | ESC O Q  |
1155  | F3      | 0x0D | ESC [ O   | ESC 3    | ESC O w  |
1156  | F4      | 0x0E | ESC [ P   | ESC 4    | ESC O x  |
1157  | F5      | 0x0F | ESC [ Q   | ESC 5    | ESC O t  |
1158  | F6      | 0x10 | ESC [ R   | ESC 6    | ESC O u  |
1159  | F7      | 0x11 | ESC [ S   | ESC 7    | ESC O q  |
1160  | F8      | 0x12 | ESC [ T   | ESC 8    | ESC O r  |
1161  | F9      | 0x13 | ESC [ U   | ESC 9    | ESC O p  |
1162  | F10     | 0x14 | ESC [ V   | ESC 0    | ESC O M  |
1163  | Escape  | 0x17 | ESC       | ESC      | ESC      |
1164  | F11     | 0x15 |           | ESC !    |          |
1165  | F12     | 0x16 |           | ESC @    |          |
1166  +=========+======+===========+==========+==========+
1167
1168  Special Mappings
1169  ================
1170  ESC R ESC r ESC R = Reset System
1171
1172  @param TerminalDevice   The terminal device to use to translate raw input into EFI Keys
1173
1174**/
1175VOID
1176UnicodeToEfiKey (
1177  IN  TERMINAL_DEV    *TerminalDevice
1178  )
1179{
1180  EFI_STATUS          Status;
1181  EFI_STATUS          TimerStatus;
1182  UINT16              UnicodeChar;
1183  EFI_INPUT_KEY       Key;
1184  BOOLEAN             SetDefaultResetState;
1185
1186  TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
1187
1188  if (!EFI_ERROR (TimerStatus)) {
1189    UnicodeToEfiKeyFlushState (TerminalDevice);
1190    TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1191  }
1192
1193  while (!IsUnicodeFiFoEmpty (TerminalDevice) && !IsEfiKeyFiFoFull (TerminalDevice)) {
1194
1195    if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
1196      //
1197      // Check to see if the 2 seconds timer has expired
1198      //
1199      TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
1200      if (!EFI_ERROR (TimerStatus)) {
1201        UnicodeToEfiKeyFlushState (TerminalDevice);
1202        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1203      }
1204    }
1205
1206    //
1207    // Fetch one Unicode character from the Unicode FIFO
1208    //
1209    UnicodeFiFoRemoveOneKey (TerminalDevice, &UnicodeChar);
1210
1211    SetDefaultResetState = TRUE;
1212
1213    switch (TerminalDevice->InputState) {
1214    case INPUT_STATE_DEFAULT:
1215
1216      break;
1217
1218    case INPUT_STATE_ESC:
1219
1220      if (UnicodeChar == LEFTOPENBRACKET) {
1221        TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET;
1222        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1223        continue;
1224      }
1225
1226      if (UnicodeChar == 'O' && TerminalDevice->TerminalType == VT100TYPE) {
1227        TerminalDevice->InputState |= INPUT_STATE_O;
1228        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1229        continue;
1230      }
1231
1232      Key.ScanCode = SCAN_NULL;
1233
1234      if (TerminalDevice->TerminalType == VT100PLUSTYPE ||
1235          TerminalDevice->TerminalType == VTUTF8TYPE) {
1236        switch (UnicodeChar) {
1237        case '1':
1238          Key.ScanCode = SCAN_F1;
1239          break;
1240        case '2':
1241          Key.ScanCode = SCAN_F2;
1242          break;
1243        case '3':
1244          Key.ScanCode = SCAN_F3;
1245          break;
1246        case '4':
1247          Key.ScanCode = SCAN_F4;
1248          break;
1249        case '5':
1250          Key.ScanCode = SCAN_F5;
1251          break;
1252        case '6':
1253          Key.ScanCode = SCAN_F6;
1254          break;
1255        case '7':
1256          Key.ScanCode = SCAN_F7;
1257          break;
1258        case '8':
1259          Key.ScanCode = SCAN_F8;
1260          break;
1261        case '9':
1262          Key.ScanCode = SCAN_F9;
1263          break;
1264        case '0':
1265          Key.ScanCode = SCAN_F10;
1266          break;
1267        case '!':
1268          Key.ScanCode = SCAN_F11;
1269          break;
1270        case '@':
1271          Key.ScanCode = SCAN_F12;
1272          break;
1273        case 'h':
1274          Key.ScanCode = SCAN_HOME;
1275          break;
1276        case 'k':
1277          Key.ScanCode = SCAN_END;
1278          break;
1279        case '+':
1280          Key.ScanCode = SCAN_INSERT;
1281          break;
1282        case '-':
1283          Key.ScanCode = SCAN_DELETE;
1284          break;
1285        case '/':
1286          Key.ScanCode = SCAN_PAGE_DOWN;
1287          break;
1288        case '?':
1289          Key.ScanCode = SCAN_PAGE_UP;
1290          break;
1291        default :
1292          break;
1293        }
1294      }
1295
1296      switch (UnicodeChar) {
1297      case 'R':
1298        if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) {
1299          TerminalDevice->ResetState = RESET_STATE_ESC_R;
1300          SetDefaultResetState = FALSE;
1301        } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_R) {
1302          gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
1303        }
1304        Key.ScanCode = SCAN_NULL;
1305        break;
1306      case 'r':
1307        if (TerminalDevice->ResetState == RESET_STATE_ESC_R) {
1308          TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_R;
1309          SetDefaultResetState = FALSE;
1310        }
1311        Key.ScanCode = SCAN_NULL;
1312        break;
1313      default :
1314        break;
1315      }
1316
1317      if (SetDefaultResetState) {
1318        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1319      }
1320
1321      if (Key.ScanCode != SCAN_NULL) {
1322        Key.UnicodeChar = 0;
1323        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1324        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1325        UnicodeToEfiKeyFlushState (TerminalDevice);
1326        continue;
1327      }
1328
1329      UnicodeToEfiKeyFlushState (TerminalDevice);
1330
1331      break;
1332
1333    case INPUT_STATE_ESC | INPUT_STATE_O:
1334
1335      TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1336
1337      Key.ScanCode = SCAN_NULL;
1338
1339      if (TerminalDevice->TerminalType == VT100TYPE) {
1340        switch (UnicodeChar) {
1341        case 'P':
1342          Key.ScanCode = SCAN_F1;
1343          break;
1344        case 'Q':
1345          Key.ScanCode = SCAN_F2;
1346          break;
1347        case 'w':
1348          Key.ScanCode = SCAN_F3;
1349          break;
1350        case 'x':
1351          Key.ScanCode = SCAN_F4;
1352          break;
1353        case 't':
1354          Key.ScanCode = SCAN_F5;
1355          break;
1356        case 'u':
1357          Key.ScanCode = SCAN_F6;
1358          break;
1359        case 'q':
1360          Key.ScanCode = SCAN_F7;
1361          break;
1362        case 'r':
1363          Key.ScanCode = SCAN_F8;
1364          break;
1365        case 'p':
1366          Key.ScanCode = SCAN_F9;
1367          break;
1368        case 'M':
1369          Key.ScanCode = SCAN_F10;
1370          break;
1371        default :
1372          break;
1373        }
1374      }
1375
1376      if (Key.ScanCode != SCAN_NULL) {
1377        Key.UnicodeChar = 0;
1378        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1379        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1380        UnicodeToEfiKeyFlushState (TerminalDevice);
1381        continue;
1382      }
1383
1384      UnicodeToEfiKeyFlushState (TerminalDevice);
1385
1386      break;
1387
1388    case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET:
1389
1390      TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1391
1392      Key.ScanCode = SCAN_NULL;
1393
1394      if (TerminalDevice->TerminalType == PCANSITYPE    ||
1395          TerminalDevice->TerminalType == VT100TYPE     ||
1396          TerminalDevice->TerminalType == VT100PLUSTYPE ||
1397          TerminalDevice->TerminalType == VTUTF8TYPE    ||
1398          TerminalDevice->TerminalType == TTYTERMTYPE) {
1399        switch (UnicodeChar) {
1400        case 'A':
1401          Key.ScanCode = SCAN_UP;
1402          break;
1403        case 'B':
1404          Key.ScanCode = SCAN_DOWN;
1405          break;
1406        case 'C':
1407          Key.ScanCode = SCAN_RIGHT;
1408          break;
1409        case 'D':
1410          Key.ScanCode = SCAN_LEFT;
1411          break;
1412        case 'H':
1413          if (TerminalDevice->TerminalType == PCANSITYPE ||
1414              TerminalDevice->TerminalType == VT100TYPE) {
1415            Key.ScanCode = SCAN_HOME;
1416          }
1417          break;
1418        case 'F':
1419          if (TerminalDevice->TerminalType == PCANSITYPE) {
1420            Key.ScanCode = SCAN_END;
1421          }
1422          break;
1423        case 'K':
1424          if (TerminalDevice->TerminalType == VT100TYPE) {
1425            Key.ScanCode = SCAN_END;
1426          }
1427          break;
1428        case 'L':
1429        case '@':
1430          if (TerminalDevice->TerminalType == PCANSITYPE ||
1431              TerminalDevice->TerminalType == VT100TYPE) {
1432            Key.ScanCode = SCAN_INSERT;
1433          }
1434          break;
1435        case 'X':
1436          if (TerminalDevice->TerminalType == PCANSITYPE) {
1437            Key.ScanCode = SCAN_DELETE;
1438          }
1439          break;
1440        case 'P':
1441          if (TerminalDevice->TerminalType == VT100TYPE) {
1442            Key.ScanCode = SCAN_DELETE;
1443          } else if (TerminalDevice->TerminalType == PCANSITYPE) {
1444            Key.ScanCode = SCAN_F4;
1445          }
1446          break;
1447        case 'I':
1448          if (TerminalDevice->TerminalType == PCANSITYPE) {
1449            Key.ScanCode = SCAN_PAGE_UP;
1450          }
1451          break;
1452        case 'V':
1453          if (TerminalDevice->TerminalType == PCANSITYPE) {
1454            Key.ScanCode = SCAN_F10;
1455          }
1456          break;
1457        case '?':
1458          if (TerminalDevice->TerminalType == VT100TYPE) {
1459            Key.ScanCode = SCAN_PAGE_UP;
1460          }
1461          break;
1462        case 'G':
1463          if (TerminalDevice->TerminalType == PCANSITYPE) {
1464            Key.ScanCode = SCAN_PAGE_DOWN;
1465          }
1466          break;
1467        case 'U':
1468          if (TerminalDevice->TerminalType == PCANSITYPE) {
1469            Key.ScanCode = SCAN_F9;
1470          }
1471          break;
1472        case '/':
1473          if (TerminalDevice->TerminalType == VT100TYPE) {
1474            Key.ScanCode = SCAN_PAGE_DOWN;
1475          }
1476          break;
1477        case 'M':
1478          if (TerminalDevice->TerminalType == PCANSITYPE) {
1479            Key.ScanCode = SCAN_F1;
1480          }
1481          break;
1482        case 'N':
1483          if (TerminalDevice->TerminalType == PCANSITYPE) {
1484            Key.ScanCode = SCAN_F2;
1485          }
1486          break;
1487        case 'O':
1488          if (TerminalDevice->TerminalType == PCANSITYPE) {
1489            Key.ScanCode = SCAN_F3;
1490          }
1491          break;
1492        case 'Q':
1493          if (TerminalDevice->TerminalType == PCANSITYPE) {
1494            Key.ScanCode = SCAN_F5;
1495          }
1496          break;
1497        case 'R':
1498          if (TerminalDevice->TerminalType == PCANSITYPE) {
1499            Key.ScanCode = SCAN_F6;
1500          }
1501          break;
1502        case 'S':
1503          if (TerminalDevice->TerminalType == PCANSITYPE) {
1504            Key.ScanCode = SCAN_F7;
1505          }
1506          break;
1507        case 'T':
1508          if (TerminalDevice->TerminalType == PCANSITYPE) {
1509            Key.ScanCode = SCAN_F8;
1510          }
1511          break;
1512        default :
1513          break;
1514        }
1515      }
1516
1517      if (Key.ScanCode != SCAN_NULL) {
1518        Key.UnicodeChar = 0;
1519        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1520        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1521        UnicodeToEfiKeyFlushState (TerminalDevice);
1522        continue;
1523      }
1524
1525      UnicodeToEfiKeyFlushState (TerminalDevice);
1526
1527      break;
1528
1529
1530    default:
1531      //
1532      // Invalid state. This should never happen.
1533      //
1534      ASSERT (FALSE);
1535
1536      UnicodeToEfiKeyFlushState (TerminalDevice);
1537
1538      break;
1539    }
1540
1541    if (UnicodeChar == ESC) {
1542      TerminalDevice->InputState = INPUT_STATE_ESC;
1543    }
1544
1545    if (UnicodeChar == CSI) {
1546      TerminalDevice->InputState = INPUT_STATE_CSI;
1547    }
1548
1549    if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
1550      Status = gBS->SetTimer(
1551                      TerminalDevice->TwoSecondTimeOut,
1552                      TimerRelative,
1553                      (UINT64)20000000
1554                      );
1555      ASSERT_EFI_ERROR (Status);
1556      continue;
1557    }
1558
1559    if (SetDefaultResetState) {
1560      TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1561    }
1562
1563    if (UnicodeChar == DEL) {
1564      Key.ScanCode    = SCAN_DELETE;
1565      Key.UnicodeChar = 0;
1566    } else {
1567      Key.ScanCode    = SCAN_NULL;
1568      Key.UnicodeChar = UnicodeChar;
1569    }
1570
1571    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1572  }
1573}
1574