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