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