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