TerminalConIn.c revision 4bc6ad3935d7b57e5eacda5e6e70b32d786d43dd
1/** @file
2  Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol.
3
4Copyright (c) 2006 - 2011, 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  return EFI_SUCCESS;
299}
300
301
302/**
303  Register a notification function for a particular keystroke for the input device.
304
305  @param  This                     Protocol instance pointer.
306  @param  KeyData                  A pointer to a buffer that is filled in with the
307                                   keystroke information data for the key that was
308                                   pressed.
309  @param  KeyNotificationFunction  Points to the function to be called when the key
310                                   sequence is typed specified by KeyData.
311  @param  NotifyHandle             Points to the unique handle assigned to the
312                                   registered notification.
313
314  @retval EFI_SUCCESS              The notification function was registered
315                                   successfully.
316  @retval EFI_OUT_OF_RESOURCES     Unable to allocate resources for necessary data
317                                   structures.
318  @retval EFI_INVALID_PARAMETER    KeyData or NotifyHandle is NULL.
319
320**/
321EFI_STATUS
322EFIAPI
323TerminalConInRegisterKeyNotify (
324  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
325  IN EFI_KEY_DATA                       *KeyData,
326  IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
327  OUT EFI_HANDLE                        *NotifyHandle
328  )
329{
330  TERMINAL_DEV                    *TerminalDevice;
331  TERMINAL_CONSOLE_IN_EX_NOTIFY   *NewNotify;
332  LIST_ENTRY                      *Link;
333  LIST_ENTRY                      *NotifyList;
334  TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;
335
336  if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
337    return EFI_INVALID_PARAMETER;
338  }
339
340  TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
341
342  //
343  // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
344  //
345  NotifyList = &TerminalDevice->NotifyList;
346  for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
347    CurrentNotify = CR (
348                      Link,
349                      TERMINAL_CONSOLE_IN_EX_NOTIFY,
350                      NotifyEntry,
351                      TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
352                      );
353    if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
354      if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
355        *NotifyHandle = CurrentNotify->NotifyHandle;
356        return EFI_SUCCESS;
357      }
358    }
359  }
360
361  //
362  // Allocate resource to save the notification function
363  //
364  NewNotify = (TERMINAL_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (TERMINAL_CONSOLE_IN_EX_NOTIFY));
365  if (NewNotify == NULL) {
366    return EFI_OUT_OF_RESOURCES;
367  }
368
369  NewNotify->Signature         = TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
370  NewNotify->KeyNotificationFn = KeyNotificationFunction;
371  NewNotify->NotifyHandle      = (EFI_HANDLE) NewNotify;
372  CopyMem (&NewNotify->KeyData, KeyData, sizeof (KeyData));
373  InsertTailList (&TerminalDevice->NotifyList, &NewNotify->NotifyEntry);
374
375  *NotifyHandle                = NewNotify->NotifyHandle;
376
377  return EFI_SUCCESS;
378}
379
380
381/**
382  Remove a registered notification function from a particular keystroke.
383
384  @param  This                     Protocol instance pointer.
385  @param  NotificationHandle       The handle of the notification function being
386                                   unregistered.
387
388  @retval EFI_SUCCESS              The notification function was unregistered
389                                   successfully.
390  @retval EFI_INVALID_PARAMETER    The NotificationHandle is invalid.
391
392**/
393EFI_STATUS
394EFIAPI
395TerminalConInUnregisterKeyNotify (
396  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
397  IN EFI_HANDLE                         NotificationHandle
398  )
399{
400  TERMINAL_DEV                    *TerminalDevice;
401  LIST_ENTRY                      *Link;
402  TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;
403  LIST_ENTRY                      *NotifyList;
404
405  if (NotificationHandle == NULL) {
406    return EFI_INVALID_PARAMETER;
407  }
408
409  if (((TERMINAL_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE) {
410    return EFI_INVALID_PARAMETER;
411  }
412
413  TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
414
415  NotifyList = &TerminalDevice->NotifyList;
416  for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
417    CurrentNotify = CR (
418                      Link,
419                      TERMINAL_CONSOLE_IN_EX_NOTIFY,
420                      NotifyEntry,
421                      TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
422                      );
423    if (CurrentNotify->NotifyHandle == NotificationHandle) {
424      //
425      // Remove the notification function from NotifyList and free resources
426      //
427      RemoveEntryList (&CurrentNotify->NotifyEntry);
428
429      gBS->FreePool (CurrentNotify);
430      return EFI_SUCCESS;
431    }
432  }
433
434  //
435  // Can not find the matching entry in database.
436  //
437  return EFI_INVALID_PARAMETER;
438}
439
440/**
441  Translate raw data into Unicode (according to different encode), and
442  translate Unicode into key information. (according to different standard).
443
444  @param  TerminalDevice       Terminal driver private structure.
445
446**/
447VOID
448TranslateRawDataToEfiKey (
449  IN  TERMINAL_DEV      *TerminalDevice
450  )
451{
452  switch (TerminalDevice->TerminalType) {
453
454  case PCANSITYPE:
455  case VT100TYPE:
456  case VT100PLUSTYPE:
457    AnsiRawDataToUnicode (TerminalDevice);
458    UnicodeToEfiKey (TerminalDevice);
459    break;
460
461  case VTUTF8TYPE:
462    //
463    // Process all the raw data in the RawFIFO,
464    // put the processed key into UnicodeFIFO.
465    //
466    VTUTF8RawDataToUnicode (TerminalDevice);
467
468    //
469    // Translate all the Unicode data in the UnicodeFIFO to Efi key,
470    // then put into EfiKeyFIFO.
471    //
472    UnicodeToEfiKey (TerminalDevice);
473
474    break;
475  }
476}
477
478/**
479  Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event
480  Signal the event if there is key available
481
482  @param  Event                    Indicates the event that invoke this function.
483  @param  Context                  Indicates the calling context.
484
485**/
486VOID
487EFIAPI
488TerminalConInWaitForKey (
489  IN  EFI_EVENT       Event,
490  IN  VOID            *Context
491  )
492{
493  //
494  // Someone is waiting on the keystroke event, if there's
495  // a key pending, signal the event
496  //
497  if (!IsEfiKeyFiFoEmpty ((TERMINAL_DEV *) Context)) {
498
499    gBS->SignalEvent (Event);
500  }
501}
502
503/**
504  Timer handler to poll the key from serial.
505
506  @param  Event                    Indicates the event that invoke this function.
507  @param  Context                  Indicates the calling context.
508**/
509VOID
510EFIAPI
511TerminalConInTimerHandler (
512  IN EFI_EVENT            Event,
513  IN VOID                 *Context
514  )
515{
516  EFI_STATUS              Status;
517  TERMINAL_DEV            *TerminalDevice;
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  //
563  // Fetch all the keys in the serial buffer,
564  // and insert the byte stream into RawFIFO.
565  //
566  while (!IsRawFiFoFull (TerminalDevice)) {
567
568    Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input);
569
570    if (EFI_ERROR (Status)) {
571      if (Status == EFI_DEVICE_ERROR) {
572        REPORT_STATUS_CODE_WITH_DEVICE_PATH (
573          EFI_ERROR_CODE | EFI_ERROR_MINOR,
574          (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_INPUT_ERROR),
575          TerminalDevice->DevicePath
576          );
577      }
578      break;
579    }
580
581    RawFiFoInsertOneKey (TerminalDevice, Input);
582  }
583
584  //
585  // Translate all the raw data in RawFIFO into EFI Key,
586  // according to different terminal type supported.
587  //
588  TranslateRawDataToEfiKey (TerminalDevice);
589}
590
591/**
592  Get one key out of serial buffer.
593
594  @param  SerialIo           Serial I/O protocol attached to the serial device.
595  @param  Output             The fetched key.
596
597  @retval EFI_NOT_READY      If serial buffer is empty.
598  @retval EFI_DEVICE_ERROR   If reading serial buffer encounter error.
599  @retval EFI_SUCCESS        If reading serial buffer successfully, put
600                             the fetched key to the parameter output.
601
602**/
603EFI_STATUS
604GetOneKeyFromSerial (
605  EFI_SERIAL_IO_PROTOCOL  *SerialIo,
606  UINT8                   *Output
607  )
608{
609  EFI_STATUS  Status;
610  UINTN       Size;
611
612  Size    = 1;
613  *Output = 0;
614
615  //
616  // Read one key from serial I/O device.
617  //
618  Status  = SerialIo->Read (SerialIo, &Size, Output);
619
620  if (EFI_ERROR (Status)) {
621
622    if (Status == EFI_TIMEOUT) {
623      return EFI_NOT_READY;
624    }
625
626    return EFI_DEVICE_ERROR;
627
628  }
629
630  if (*Output == 0) {
631    return EFI_NOT_READY;
632  }
633
634  return EFI_SUCCESS;
635}
636
637/**
638  Insert one byte raw data into the Raw Data FIFO.
639
640  @param  TerminalDevice       Terminal driver private structure.
641  @param  Input                The key will be input.
642
643  @retval TRUE                 If insert successfully.
644  @retval FLASE                If Raw Data buffer is full before key insertion,
645                               and the key is lost.
646
647**/
648BOOLEAN
649RawFiFoInsertOneKey (
650  TERMINAL_DEV      *TerminalDevice,
651  UINT8             Input
652  )
653{
654  UINT8 Tail;
655
656  Tail = TerminalDevice->RawFiFo->Tail;
657
658  if (IsRawFiFoFull (TerminalDevice)) {
659    //
660    // Raw FIFO is full
661    //
662    return FALSE;
663  }
664
665  TerminalDevice->RawFiFo->Data[Tail]  = Input;
666
667  TerminalDevice->RawFiFo->Tail        = (UINT8) ((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1));
668
669  return TRUE;
670}
671
672/**
673  Remove one pre-fetched key out of the Raw Data FIFO.
674
675  @param  TerminalDevice       Terminal driver private structure.
676  @param  Output               The key will be removed.
677
678  @retval TRUE                 If insert successfully.
679  @retval FLASE                If Raw Data FIFO buffer is empty before remove operation.
680
681**/
682BOOLEAN
683RawFiFoRemoveOneKey (
684  TERMINAL_DEV  *TerminalDevice,
685  UINT8         *Output
686  )
687{
688  UINT8 Head;
689
690  Head = TerminalDevice->RawFiFo->Head;
691
692  if (IsRawFiFoEmpty (TerminalDevice)) {
693    //
694    //  FIFO is empty
695    //
696    *Output = 0;
697    return FALSE;
698  }
699
700  *Output                       = TerminalDevice->RawFiFo->Data[Head];
701
702  TerminalDevice->RawFiFo->Head  = (UINT8) ((Head + 1) % (RAW_FIFO_MAX_NUMBER + 1));
703
704  return TRUE;
705}
706
707/**
708  Clarify whether Raw Data FIFO buffer is empty.
709
710  @param  TerminalDevice       Terminal driver private structure
711
712  @retval TRUE                 If Raw Data FIFO buffer is empty.
713  @retval FLASE                If Raw Data FIFO buffer is not empty.
714
715**/
716BOOLEAN
717IsRawFiFoEmpty (
718  TERMINAL_DEV  *TerminalDevice
719  )
720{
721  if (TerminalDevice->RawFiFo->Head == TerminalDevice->RawFiFo->Tail) {
722    return TRUE;
723  } else {
724    return FALSE;
725  }
726}
727
728/**
729  Clarify whether Raw Data FIFO buffer is full.
730
731  @param  TerminalDevice       Terminal driver private structure
732
733  @retval TRUE                 If Raw Data FIFO buffer is full.
734  @retval FLASE                If Raw Data FIFO buffer is not full.
735
736**/
737BOOLEAN
738IsRawFiFoFull (
739  TERMINAL_DEV  *TerminalDevice
740  )
741{
742  UINT8 Tail;
743  UINT8 Head;
744
745  Tail  = TerminalDevice->RawFiFo->Tail;
746  Head  = TerminalDevice->RawFiFo->Head;
747
748  if (((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)) == Head) {
749
750    return TRUE;
751  }
752
753  return FALSE;
754}
755
756/**
757  Insert one pre-fetched key into the FIFO buffer.
758
759  @param  TerminalDevice       Terminal driver private structure.
760  @param  Key                  The key will be input.
761
762  @retval TRUE                 If insert successfully.
763  @retval FLASE                If FIFO buffer is full before key insertion,
764                               and the key is lost.
765
766**/
767BOOLEAN
768EfiKeyFiFoInsertOneKey (
769  TERMINAL_DEV                    *TerminalDevice,
770  EFI_INPUT_KEY                   *Key
771  )
772{
773  UINT8                           Tail;
774  LIST_ENTRY                      *Link;
775  LIST_ENTRY                      *NotifyList;
776  TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;
777  EFI_KEY_DATA                    KeyData;
778
779  Tail = TerminalDevice->EfiKeyFiFo->Tail;
780
781  CopyMem (&KeyData.Key, Key, sizeof (EFI_INPUT_KEY));
782  KeyData.KeyState.KeyShiftState  = 0;
783  KeyData.KeyState.KeyToggleState = 0;
784
785  //
786  // Invoke notification functions if exist
787  //
788  NotifyList = &TerminalDevice->NotifyList;
789  for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {
790    CurrentNotify = CR (
791                      Link,
792                      TERMINAL_CONSOLE_IN_EX_NOTIFY,
793                      NotifyEntry,
794                      TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
795                      );
796    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
797      CurrentNotify->KeyNotificationFn (&KeyData);
798    }
799  }
800  if (IsEfiKeyFiFoFull (TerminalDevice)) {
801    //
802    // Efi Key FIFO is full
803    //
804    return FALSE;
805  }
806
807  CopyMem (&TerminalDevice->EfiKeyFiFo->Data[Tail], Key, sizeof (EFI_INPUT_KEY));
808
809  TerminalDevice->EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
810
811  return TRUE;
812}
813
814/**
815  Remove one pre-fetched key out of the FIFO buffer.
816
817  @param  TerminalDevice       Terminal driver private structure.
818  @param  Output               The key will be removed.
819
820  @retval TRUE                 If insert successfully.
821  @retval FLASE                If FIFO buffer is empty before remove operation.
822
823**/
824BOOLEAN
825EfiKeyFiFoRemoveOneKey (
826  TERMINAL_DEV  *TerminalDevice,
827  EFI_INPUT_KEY *Output
828  )
829{
830  UINT8 Head;
831
832  Head = TerminalDevice->EfiKeyFiFo->Head;
833  ASSERT (Head < FIFO_MAX_NUMBER + 1);
834
835  if (IsEfiKeyFiFoEmpty (TerminalDevice)) {
836    //
837    //  FIFO is empty
838    //
839    Output->ScanCode    = SCAN_NULL;
840    Output->UnicodeChar = 0;
841    return FALSE;
842  }
843
844  *Output                         = TerminalDevice->EfiKeyFiFo->Data[Head];
845
846  TerminalDevice->EfiKeyFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
847
848  return TRUE;
849}
850
851/**
852  Clarify whether FIFO buffer is empty.
853
854  @param  TerminalDevice       Terminal driver private structure
855
856  @retval TRUE                 If FIFO buffer is empty.
857  @retval FLASE                If FIFO buffer is not empty.
858
859**/
860BOOLEAN
861IsEfiKeyFiFoEmpty (
862  TERMINAL_DEV  *TerminalDevice
863  )
864{
865  if (TerminalDevice->EfiKeyFiFo->Head == TerminalDevice->EfiKeyFiFo->Tail) {
866    return TRUE;
867  } else {
868    return FALSE;
869  }
870}
871
872/**
873  Clarify whether FIFO buffer is full.
874
875  @param  TerminalDevice       Terminal driver private structure
876
877  @retval TRUE                 If FIFO buffer is full.
878  @retval FLASE                If FIFO buffer is not full.
879
880**/
881BOOLEAN
882IsEfiKeyFiFoFull (
883  TERMINAL_DEV  *TerminalDevice
884  )
885{
886  UINT8 Tail;
887  UINT8 Head;
888
889  Tail  = TerminalDevice->EfiKeyFiFo->Tail;
890  Head  = TerminalDevice->EfiKeyFiFo->Head;
891
892  if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
893
894    return TRUE;
895  }
896
897  return FALSE;
898}
899
900/**
901  Insert one pre-fetched key into the Unicode FIFO buffer.
902
903  @param  TerminalDevice       Terminal driver private structure.
904  @param  Input                The key will be input.
905
906  @retval TRUE                 If insert successfully.
907  @retval FLASE                If Unicode FIFO buffer is full before key insertion,
908                               and the key is lost.
909
910**/
911BOOLEAN
912UnicodeFiFoInsertOneKey (
913  TERMINAL_DEV      *TerminalDevice,
914  UINT16            Input
915  )
916{
917  UINT8 Tail;
918
919  Tail = TerminalDevice->UnicodeFiFo->Tail;
920  ASSERT (Tail < FIFO_MAX_NUMBER + 1);
921
922
923  if (IsUnicodeFiFoFull (TerminalDevice)) {
924    //
925    // Unicode FIFO is full
926    //
927    return FALSE;
928  }
929
930  TerminalDevice->UnicodeFiFo->Data[Tail]  = Input;
931
932  TerminalDevice->UnicodeFiFo->Tail        = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
933
934  return TRUE;
935}
936
937/**
938  Remove one pre-fetched key out of the Unicode FIFO buffer.
939
940  @param  TerminalDevice       Terminal driver private structure.
941  @param  Output               The key will be removed.
942
943  @retval TRUE                 If insert successfully.
944  @retval FLASE                If Unicode FIFO buffer is empty before remove operation.
945
946**/
947BOOLEAN
948UnicodeFiFoRemoveOneKey (
949  TERMINAL_DEV  *TerminalDevice,
950  UINT16        *Output
951  )
952{
953  UINT8 Head;
954
955  Head = TerminalDevice->UnicodeFiFo->Head;
956  ASSERT (Head < FIFO_MAX_NUMBER + 1);
957
958  if (IsUnicodeFiFoEmpty (TerminalDevice)) {
959    //
960    //  FIFO is empty
961    //
962    Output = NULL;
963    return FALSE;
964  }
965
966  *Output = TerminalDevice->UnicodeFiFo->Data[Head];
967
968  TerminalDevice->UnicodeFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
969
970  return TRUE;
971}
972
973/**
974  Clarify whether Unicode FIFO buffer is empty.
975
976  @param  TerminalDevice       Terminal driver private structure
977
978  @retval TRUE                 If Unicode FIFO buffer is empty.
979  @retval FLASE                If Unicode FIFO buffer is not empty.
980
981**/
982BOOLEAN
983IsUnicodeFiFoEmpty (
984  TERMINAL_DEV  *TerminalDevice
985  )
986{
987  if (TerminalDevice->UnicodeFiFo->Head == TerminalDevice->UnicodeFiFo->Tail) {
988    return TRUE;
989  } else {
990    return FALSE;
991  }
992}
993
994/**
995  Clarify whether Unicode FIFO buffer is full.
996
997  @param  TerminalDevice       Terminal driver private structure
998
999  @retval TRUE                 If Unicode FIFO buffer is full.
1000  @retval FLASE                If Unicode FIFO buffer is not full.
1001
1002**/
1003BOOLEAN
1004IsUnicodeFiFoFull (
1005  TERMINAL_DEV  *TerminalDevice
1006  )
1007{
1008  UINT8 Tail;
1009  UINT8 Head;
1010
1011  Tail  = TerminalDevice->UnicodeFiFo->Tail;
1012  Head  = TerminalDevice->UnicodeFiFo->Head;
1013
1014  if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
1015
1016    return TRUE;
1017  }
1018
1019  return FALSE;
1020}
1021
1022/**
1023  Count Unicode FIFO buffer.
1024
1025  @param  TerminalDevice       Terminal driver private structure
1026
1027  @return The count in bytes of Unicode FIFO.
1028
1029**/
1030UINT8
1031UnicodeFiFoGetKeyCount (
1032  TERMINAL_DEV    *TerminalDevice
1033  )
1034{
1035  UINT8 Tail;
1036  UINT8 Head;
1037
1038  Tail  = TerminalDevice->UnicodeFiFo->Tail;
1039  Head  = TerminalDevice->UnicodeFiFo->Head;
1040
1041  if (Tail >= Head) {
1042    return (UINT8) (Tail - Head);
1043  } else {
1044    return (UINT8) (Tail + FIFO_MAX_NUMBER + 1 - Head);
1045  }
1046}
1047
1048/**
1049  Update the Unicode characters from a terminal input device into EFI Keys FIFO.
1050
1051  @param TerminalDevice   The terminal device to use to translate raw input into EFI Keys
1052
1053**/
1054VOID
1055UnicodeToEfiKeyFlushState (
1056  IN  TERMINAL_DEV    *TerminalDevice
1057  )
1058{
1059  EFI_INPUT_KEY Key;
1060  UINT32        InputState;
1061
1062  InputState = TerminalDevice->InputState;
1063
1064  if (IsEfiKeyFiFoFull (TerminalDevice)) {
1065    return;
1066  }
1067
1068  if ((InputState & INPUT_STATE_ESC) != 0) {
1069    Key.ScanCode    = SCAN_ESC;
1070    Key.UnicodeChar = 0;
1071    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1072  }
1073
1074  if ((InputState & INPUT_STATE_CSI) != 0) {
1075    Key.ScanCode    = SCAN_NULL;
1076    Key.UnicodeChar = CSI;
1077    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1078  }
1079
1080  if ((InputState & INPUT_STATE_LEFTOPENBRACKET) != 0) {
1081    Key.ScanCode    = SCAN_NULL;
1082    Key.UnicodeChar = LEFTOPENBRACKET;
1083    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1084  }
1085
1086  if ((InputState & INPUT_STATE_O) != 0) {
1087    Key.ScanCode    = SCAN_NULL;
1088    Key.UnicodeChar = 'O';
1089    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1090  }
1091
1092  if ((InputState & INPUT_STATE_2) != 0) {
1093    Key.ScanCode    = SCAN_NULL;
1094    Key.UnicodeChar = '2';
1095    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1096  }
1097
1098  //
1099  // Cancel the timer.
1100  //
1101  gBS->SetTimer (
1102        TerminalDevice->TwoSecondTimeOut,
1103        TimerCancel,
1104        0
1105        );
1106
1107  TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1108}
1109
1110
1111/**
1112  Converts a stream of Unicode characters from a terminal input device into EFI Keys that
1113  can be read through the Simple Input Protocol.
1114
1115  The table below shows the keyboard input mappings that this function supports.
1116  If the ESC sequence listed in one of the columns is presented, then it is translated
1117  into the corresponding EFI Scan Code.  If a matching sequence is not found, then the raw
1118  key strokes are converted into EFI Keys.
1119
1120  2 seconds are allowed for an ESC sequence to be completed.  If the ESC sequence is not
1121  completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
1122  converted into EFI Keys.
1123  There is one special input sequence that will force the system to reset.
1124  This is ESC R ESC r ESC R.
1125
1126  Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100.
1127        The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 /
1128        DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example.
1129
1130  Symbols used in table below
1131  ===========================
1132    ESC = 0x1B
1133    CSI = 0x9B
1134    DEL = 0x7f
1135    ^   = CTRL
1136
1137  +=========+======+===========+==========+==========+
1138  |         | EFI  | UEFI 2.0  |          |          |
1139  |         | Scan |           |  VT100+  |          |
1140  |   KEY   | Code |  PC ANSI  |  VTUTF8  |   VT100  |
1141  +=========+======+===========+==========+==========+
1142  | NULL    | 0x00 |           |          |          |
1143  | UP      | 0x01 | ESC [ A   | ESC [ A  | ESC [ A  |
1144  | DOWN    | 0x02 | ESC [ B   | ESC [ B  | ESC [ B  |
1145  | RIGHT   | 0x03 | ESC [ C   | ESC [ C  | ESC [ C  |
1146  | LEFT    | 0x04 | ESC [ D   | ESC [ D  | ESC [ D  |
1147  | HOME    | 0x05 | ESC [ H   | ESC h    | ESC [ H  |
1148  | END     | 0x06 | ESC [ F   | ESC k    | ESC [ K  |
1149  | INSERT  | 0x07 | ESC [ @   | ESC +    | ESC [ @  |
1150  |         |      | ESC [ L   |          | ESC [ L  |
1151  | DELETE  | 0x08 | ESC [ X   | ESC -    | ESC [ P  |
1152  | PG UP   | 0x09 | ESC [ I   | ESC ?    | ESC [ V  |
1153  |         |      |           |          | ESC [ ?  |
1154  | PG DOWN | 0x0A | ESC [ G   | ESC /    | ESC [ U  |
1155  |         |      |           |          | ESC [ /  |
1156  | F1      | 0x0B | ESC [ M   | ESC 1    | ESC O P  |
1157  | F2      | 0x0C | ESC [ N   | ESC 2    | ESC O Q  |
1158  | F3      | 0x0D | ESC [ O   | ESC 3    | ESC O w  |
1159  | F4      | 0x0E | ESC [ P   | ESC 4    | ESC O x  |
1160  | F5      | 0x0F | ESC [ Q   | ESC 5    | ESC O t  |
1161  | F6      | 0x10 | ESC [ R   | ESC 6    | ESC O u  |
1162  | F7      | 0x11 | ESC [ S   | ESC 7    | ESC O q  |
1163  | F8      | 0x12 | ESC [ T   | ESC 8    | ESC O r  |
1164  | F9      | 0x13 | ESC [ U   | ESC 9    | ESC O p  |
1165  | F10     | 0x14 | ESC [ V   | ESC 0    | ESC O M  |
1166  | Escape  | 0x17 | ESC       | ESC      | ESC      |
1167  | F11     | 0x15 |           | ESC !    |          |
1168  | F12     | 0x16 |           | ESC @    |          |
1169  +=========+======+===========+==========+==========+
1170
1171  Special Mappings
1172  ================
1173  ESC R ESC r ESC R = Reset System
1174
1175  @param TerminalDevice   The terminal device to use to translate raw input into EFI Keys
1176
1177**/
1178VOID
1179UnicodeToEfiKey (
1180  IN  TERMINAL_DEV    *TerminalDevice
1181  )
1182{
1183  EFI_STATUS          Status;
1184  EFI_STATUS          TimerStatus;
1185  UINT16              UnicodeChar;
1186  EFI_INPUT_KEY       Key;
1187  BOOLEAN             SetDefaultResetState;
1188
1189  TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
1190
1191  if (!EFI_ERROR (TimerStatus)) {
1192    UnicodeToEfiKeyFlushState (TerminalDevice);
1193    TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1194  }
1195
1196  while (!IsUnicodeFiFoEmpty (TerminalDevice) && !IsEfiKeyFiFoFull (TerminalDevice)) {
1197
1198    if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
1199      //
1200      // Check to see if the 2 seconds timer has expired
1201      //
1202      TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
1203      if (!EFI_ERROR (TimerStatus)) {
1204        UnicodeToEfiKeyFlushState (TerminalDevice);
1205        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1206      }
1207    }
1208
1209    //
1210    // Fetch one Unicode character from the Unicode FIFO
1211    //
1212    UnicodeFiFoRemoveOneKey (TerminalDevice, &UnicodeChar);
1213
1214    SetDefaultResetState = TRUE;
1215
1216    switch (TerminalDevice->InputState) {
1217    case INPUT_STATE_DEFAULT:
1218
1219      break;
1220
1221    case INPUT_STATE_ESC:
1222
1223      if (UnicodeChar == LEFTOPENBRACKET) {
1224        TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET;
1225        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1226        continue;
1227      }
1228
1229      if (UnicodeChar == 'O' && TerminalDevice->TerminalType == VT100TYPE) {
1230        TerminalDevice->InputState |= INPUT_STATE_O;
1231        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1232        continue;
1233      }
1234
1235      Key.ScanCode = SCAN_NULL;
1236
1237      if (TerminalDevice->TerminalType == VT100PLUSTYPE ||
1238          TerminalDevice->TerminalType == VTUTF8TYPE) {
1239        switch (UnicodeChar) {
1240        case '1':
1241          Key.ScanCode = SCAN_F1;
1242          break;
1243        case '2':
1244          Key.ScanCode = SCAN_F2;
1245          break;
1246        case '3':
1247          Key.ScanCode = SCAN_F3;
1248          break;
1249        case '4':
1250          Key.ScanCode = SCAN_F4;
1251          break;
1252        case '5':
1253          Key.ScanCode = SCAN_F5;
1254          break;
1255        case '6':
1256          Key.ScanCode = SCAN_F6;
1257          break;
1258        case '7':
1259          Key.ScanCode = SCAN_F7;
1260          break;
1261        case '8':
1262          Key.ScanCode = SCAN_F8;
1263          break;
1264        case '9':
1265          Key.ScanCode = SCAN_F9;
1266          break;
1267        case '0':
1268          Key.ScanCode = SCAN_F10;
1269          break;
1270        case '!':
1271          Key.ScanCode = SCAN_F11;
1272          break;
1273        case '@':
1274          Key.ScanCode = SCAN_F12;
1275          break;
1276        case 'h':
1277          Key.ScanCode = SCAN_HOME;
1278          break;
1279        case 'k':
1280          Key.ScanCode = SCAN_END;
1281          break;
1282        case '+':
1283          Key.ScanCode = SCAN_INSERT;
1284          break;
1285        case '-':
1286          Key.ScanCode = SCAN_DELETE;
1287          break;
1288        case '/':
1289          Key.ScanCode = SCAN_PAGE_DOWN;
1290          break;
1291        case '?':
1292          Key.ScanCode = SCAN_PAGE_UP;
1293          break;
1294        default :
1295          break;
1296        }
1297      }
1298
1299      switch (UnicodeChar) {
1300      case 'R':
1301        if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) {
1302          TerminalDevice->ResetState = RESET_STATE_ESC_R;
1303          SetDefaultResetState = FALSE;
1304        } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_R) {
1305          gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
1306        }
1307        Key.ScanCode = SCAN_NULL;
1308        break;
1309      case 'r':
1310        if (TerminalDevice->ResetState == RESET_STATE_ESC_R) {
1311          TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_R;
1312          SetDefaultResetState = FALSE;
1313        }
1314        Key.ScanCode = SCAN_NULL;
1315        break;
1316      default :
1317        break;
1318      }
1319
1320      if (SetDefaultResetState) {
1321        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1322      }
1323
1324      if (Key.ScanCode != SCAN_NULL) {
1325        Key.UnicodeChar = 0;
1326        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1327        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1328        UnicodeToEfiKeyFlushState (TerminalDevice);
1329        continue;
1330      }
1331
1332      UnicodeToEfiKeyFlushState (TerminalDevice);
1333
1334      break;
1335
1336    case INPUT_STATE_ESC | INPUT_STATE_O:
1337
1338      TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1339
1340      Key.ScanCode = SCAN_NULL;
1341
1342      if (TerminalDevice->TerminalType == VT100TYPE) {
1343        switch (UnicodeChar) {
1344        case 'P':
1345          Key.ScanCode = SCAN_F1;
1346          break;
1347        case 'Q':
1348          Key.ScanCode = SCAN_F2;
1349          break;
1350        case 'w':
1351          Key.ScanCode = SCAN_F3;
1352          break;
1353        case 'x':
1354          Key.ScanCode = SCAN_F4;
1355          break;
1356        case 't':
1357          Key.ScanCode = SCAN_F5;
1358          break;
1359        case 'u':
1360          Key.ScanCode = SCAN_F6;
1361          break;
1362        case 'q':
1363          Key.ScanCode = SCAN_F7;
1364          break;
1365        case 'r':
1366          Key.ScanCode = SCAN_F8;
1367          break;
1368        case 'p':
1369          Key.ScanCode = SCAN_F9;
1370          break;
1371        case 'M':
1372          Key.ScanCode = SCAN_F10;
1373          break;
1374        default :
1375          break;
1376        }
1377      }
1378
1379      if (Key.ScanCode != SCAN_NULL) {
1380        Key.UnicodeChar = 0;
1381        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1382        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1383        UnicodeToEfiKeyFlushState (TerminalDevice);
1384        continue;
1385      }
1386
1387      UnicodeToEfiKeyFlushState (TerminalDevice);
1388
1389      break;
1390
1391    case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET:
1392
1393      TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1394
1395      Key.ScanCode = SCAN_NULL;
1396
1397      if (TerminalDevice->TerminalType == PCANSITYPE    ||
1398          TerminalDevice->TerminalType == VT100TYPE     ||
1399          TerminalDevice->TerminalType == VT100PLUSTYPE ||
1400          TerminalDevice->TerminalType == VTUTF8TYPE) {
1401        switch (UnicodeChar) {
1402        case 'A':
1403          Key.ScanCode = SCAN_UP;
1404          break;
1405        case 'B':
1406          Key.ScanCode = SCAN_DOWN;
1407          break;
1408        case 'C':
1409          Key.ScanCode = SCAN_RIGHT;
1410          break;
1411        case 'D':
1412          Key.ScanCode = SCAN_LEFT;
1413          break;
1414        case 'H':
1415          if (TerminalDevice->TerminalType == PCANSITYPE ||
1416              TerminalDevice->TerminalType == VT100TYPE) {
1417            Key.ScanCode = SCAN_HOME;
1418          }
1419          break;
1420        case 'F':
1421          if (TerminalDevice->TerminalType == PCANSITYPE) {
1422            Key.ScanCode = SCAN_END;
1423          }
1424          break;
1425        case 'K':
1426          if (TerminalDevice->TerminalType == VT100TYPE) {
1427            Key.ScanCode = SCAN_END;
1428          }
1429          break;
1430        case 'L':
1431        case '@':
1432          if (TerminalDevice->TerminalType == PCANSITYPE ||
1433              TerminalDevice->TerminalType == VT100TYPE) {
1434            Key.ScanCode = SCAN_INSERT;
1435          }
1436          break;
1437        case 'X':
1438          if (TerminalDevice->TerminalType == PCANSITYPE) {
1439            Key.ScanCode = SCAN_DELETE;
1440          }
1441          break;
1442        case 'P':
1443          if (TerminalDevice->TerminalType == VT100TYPE) {
1444            Key.ScanCode = SCAN_DELETE;
1445          } else if (TerminalDevice->TerminalType == PCANSITYPE) {
1446            Key.ScanCode = SCAN_F4;
1447          }
1448          break;
1449        case 'I':
1450          if (TerminalDevice->TerminalType == PCANSITYPE) {
1451            Key.ScanCode = SCAN_PAGE_UP;
1452          }
1453          break;
1454        case 'V':
1455          if (TerminalDevice->TerminalType == PCANSITYPE) {
1456            Key.ScanCode = SCAN_F10;
1457          }
1458        case '?':
1459          if (TerminalDevice->TerminalType == VT100TYPE) {
1460            Key.ScanCode = SCAN_PAGE_UP;
1461          }
1462          break;
1463        case 'G':
1464          if (TerminalDevice->TerminalType == PCANSITYPE) {
1465            Key.ScanCode = SCAN_PAGE_DOWN;
1466          }
1467          break;
1468        case 'U':
1469          if (TerminalDevice->TerminalType == PCANSITYPE) {
1470            Key.ScanCode = SCAN_F9;
1471          }
1472        case '/':
1473          if (TerminalDevice->TerminalType == VT100TYPE) {
1474            Key.ScanCode = SCAN_PAGE_DOWN;
1475          }
1476          break;
1477        case 'M':
1478          if (TerminalDevice->TerminalType == PCANSITYPE) {
1479            Key.ScanCode = SCAN_F1;
1480          }
1481          break;
1482        case 'N':
1483          if (TerminalDevice->TerminalType == PCANSITYPE) {
1484            Key.ScanCode = SCAN_F2;
1485          }
1486          break;
1487        case 'O':
1488          if (TerminalDevice->TerminalType == PCANSITYPE) {
1489            Key.ScanCode = SCAN_F3;
1490          }
1491          break;
1492        case 'Q':
1493          if (TerminalDevice->TerminalType == PCANSITYPE) {
1494            Key.ScanCode = SCAN_F5;
1495          }
1496          break;
1497        case 'R':
1498          if (TerminalDevice->TerminalType == PCANSITYPE) {
1499            Key.ScanCode = SCAN_F6;
1500          }
1501          break;
1502        case 'S':
1503          if (TerminalDevice->TerminalType == PCANSITYPE) {
1504            Key.ScanCode = SCAN_F7;
1505          }
1506          break;
1507        case 'T':
1508          if (TerminalDevice->TerminalType == PCANSITYPE) {
1509            Key.ScanCode = SCAN_F8;
1510          }
1511          break;
1512        default :
1513          break;
1514        }
1515      }
1516
1517      if (Key.ScanCode != SCAN_NULL) {
1518        Key.UnicodeChar = 0;
1519        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1520        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1521        UnicodeToEfiKeyFlushState (TerminalDevice);
1522        continue;
1523      }
1524
1525      UnicodeToEfiKeyFlushState (TerminalDevice);
1526
1527      break;
1528
1529
1530    default:
1531      //
1532      // Invalid state. This should never happen.
1533      //
1534      ASSERT (FALSE);
1535
1536      UnicodeToEfiKeyFlushState (TerminalDevice);
1537
1538      break;
1539    }
1540
1541    if (UnicodeChar == ESC) {
1542      TerminalDevice->InputState = INPUT_STATE_ESC;
1543    }
1544
1545    if (UnicodeChar == CSI) {
1546      TerminalDevice->InputState = INPUT_STATE_CSI;
1547    }
1548
1549    if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
1550      Status = gBS->SetTimer(
1551                      TerminalDevice->TwoSecondTimeOut,
1552                      TimerRelative,
1553                      (UINT64)20000000
1554                      );
1555      ASSERT_EFI_ERROR (Status);
1556      continue;
1557    }
1558
1559    if (SetDefaultResetState) {
1560      TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1561    }
1562
1563    if (UnicodeChar == DEL) {
1564      Key.ScanCode    = SCAN_DELETE;
1565      Key.UnicodeChar = 0;
1566    } else {
1567      Key.ScanCode    = SCAN_NULL;
1568      Key.UnicodeChar = UnicodeChar;
1569    }
1570
1571    EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1572  }
1573}
1574