Updated modules to not depend on the IntelFrameworkPkg.
[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 EFI_STATUS\r
19 EFIAPI\r
20 TerminalConInReset (\r
21   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
22   IN  BOOLEAN                         ExtendedVerification\r
23   )\r
24 /*++\r
25   Routine Description:\r
26   \r
27     Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset().\r
28     This driver only perform dependent serial device reset regardless of \r
29     the value of ExtendeVerification\r
30   \r
31   Arguments:\r
32   \r
33     This - Indicates the calling context.\r
34     \r
35     ExtendedVerification - Skip by this driver.\r
36         \r
37   Returns:\r
38   \r
39     EFI_SUCCESS\r
40        The reset operation succeeds.   \r
41     \r
42     EFI_DEVICE_ERROR\r
43       The dependent serial port reset fails.\r
44                 \r
45 --*/\r
46 {\r
47   EFI_STATUS    Status;\r
48   TERMINAL_DEV  *TerminalDevice;\r
49 \r
50   TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);\r
51 \r
52   //\r
53   // Report progress code here\r
54   //\r
55   REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
56     EFI_PROGRESS_CODE,\r
57     PcdGet32 (PcdStatusCodeValueRemoteConsoleReset),\r
58     TerminalDevice->DevicePath\r
59     );\r
60 \r
61   Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo);\r
62 \r
63   //\r
64   // clear all the internal buffer for keys\r
65   //\r
66   InitializeRawFiFo (TerminalDevice);\r
67   InitializeUnicodeFiFo (TerminalDevice);\r
68   InitializeEfiKeyFiFo (TerminalDevice);\r
69 \r
70   if (EFI_ERROR (Status)) {\r
71     REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
72       EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
73       PcdGet32 (PcdStatusCodeValueRemoteConsoleError),\r
74       TerminalDevice->DevicePath\r
75       );\r
76   }\r
77 \r
78   return Status;\r
79 }\r
80 \r
81 EFI_STATUS\r
82 EFIAPI\r
83 TerminalConInReadKeyStroke (\r
84   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,\r
85   OUT EFI_INPUT_KEY                   *Key\r
86   )\r
87 /*++\r
88   Routine Description:\r
89   \r
90     Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke().\r
91       \r
92   Arguments:\r
93   \r
94     This - Indicates the calling context.\r
95     \r
96     Key  - A pointer to a buffer that is filled in with the keystroke\r
97         information for the key that was sent from terminal.        \r
98         \r
99   Returns:\r
100   \r
101     EFI_SUCCESS\r
102       The keystroke information is returned successfully.\r
103        \r
104     EFI_NOT_READY\r
105       There is no keystroke data available.\r
106  \r
107     EFI_DEVICE_ERROR\r
108       The dependent serial device encounters error.\r
109                 \r
110 --*/\r
111 {\r
112   TERMINAL_DEV  *TerminalDevice;\r
113   EFI_STATUS    Status;\r
114 \r
115   //\r
116   // Initialize *Key to nonsense value.\r
117   //\r
118   Key->ScanCode     = SCAN_NULL;\r
119   Key->UnicodeChar  = 0;\r
120   //\r
121   //  get TERMINAL_DEV from "This" parameter.\r
122   //\r
123   TerminalDevice  = TERMINAL_CON_IN_DEV_FROM_THIS (This);\r
124 \r
125   Status          = TerminalConInCheckForKey (This);\r
126   if (EFI_ERROR (Status)) {\r
127     return EFI_NOT_READY;\r
128   }\r
129 \r
130   EfiKeyFiFoRemoveOneKey (TerminalDevice, Key);\r
131 \r
132   return EFI_SUCCESS;\r
133 \r
134 }\r
135 \r
136 VOID\r
137 TranslateRawDataToEfiKey (\r
138   IN  TERMINAL_DEV      *TerminalDevice\r
139   )\r
140 /*++\r
141     Step1: Turn raw data into Unicode (according to different encode).\r
142     Step2: Translate Unicode into key information. \r
143     (according to different terminal standard).\r
144 --*/\r
145 {\r
146   switch (TerminalDevice->TerminalType) {\r
147 \r
148   case PcAnsiType:\r
149   case VT100Type:\r
150   case VT100PlusType:\r
151     AnsiRawDataToUnicode (TerminalDevice);\r
152     UnicodeToEfiKey (TerminalDevice);\r
153     break;\r
154 \r
155   case VTUTF8Type:\r
156     //\r
157     // Process all the raw data in the RawFIFO,\r
158     // put the processed key into UnicodeFIFO.\r
159     //\r
160     VTUTF8RawDataToUnicode (TerminalDevice);\r
161 \r
162     //\r
163     // Translate all the Unicode data in the UnicodeFIFO to Efi key,\r
164     // then put into EfiKeyFIFO.\r
165     //\r
166     UnicodeToEfiKey (TerminalDevice);\r
167 \r
168     break;\r
169   }\r
170 }\r
171 \r
172 VOID\r
173 EFIAPI\r
174 TerminalConInWaitForKey (\r
175   IN  EFI_EVENT       Event,\r
176   IN  VOID            *Context\r
177   )\r
178 /*++\r
179   Routine Description:\r
180   \r
181     Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event\r
182     Signal the event if there is key available     \r
183   \r
184   Arguments:\r
185   \r
186     Event - Indicates the event that invoke this function.\r
187     \r
188     Context - Indicates the calling context.\r
189         \r
190   Returns:\r
191   \r
192     N/A\r
193                 \r
194 --*/\r
195 {\r
196   //\r
197   // Someone is waiting on the keystroke event, if there's\r
198   // a key pending, signal the event\r
199   //\r
200   // Context is the pointer to EFI_SIMPLE_TEXT_INPUT_PROTOCOL\r
201   //\r
202   if (!EFI_ERROR (TerminalConInCheckForKey (Context))) {\r
203 \r
204     gBS->SignalEvent (Event);\r
205   }\r
206 }\r
207 \r
208 EFI_STATUS\r
209 TerminalConInCheckForKey (\r
210   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This\r
211   )\r
212 /*++\r
213   Routine Description:\r
214   \r
215     Check for a pending key in the Efi Key FIFO or Serial device buffer.\r
216   \r
217   Arguments:\r
218   \r
219     This - Indicates the calling context.\r
220         \r
221   Returns:\r
222   \r
223     EFI_SUCCESS\r
224        There is key pending.   \r
225     \r
226     EFI_NOT_READY\r
227       There is no key pending.\r
228       \r
229     EFI_DEVICE_ERROR\r
230                 \r
231 --*/\r
232 {\r
233   EFI_STATUS              Status;\r
234   TERMINAL_DEV            *TerminalDevice;\r
235   UINT32                  Control;\r
236   UINT8                   Input;\r
237   EFI_SERIAL_IO_MODE      *Mode;\r
238   EFI_SERIAL_IO_PROTOCOL  *SerialIo;\r
239   UINTN                   SerialInTimeOut;\r
240 \r
241   TerminalDevice  = TERMINAL_CON_IN_DEV_FROM_THIS (This);\r
242 \r
243   SerialIo        = TerminalDevice->SerialIo;\r
244   if (SerialIo == NULL) {\r
245     return EFI_DEVICE_ERROR;\r
246   }\r
247   //\r
248   //  if current timeout value for serial device is not identical with\r
249   //  the value saved in TERMINAL_DEV structure, then recalculate the\r
250   //  timeout value again and set serial attribute according to this value.\r
251   //\r
252   Mode = SerialIo->Mode;\r
253   if (Mode->Timeout != TerminalDevice->SerialInTimeOut) {\r
254 \r
255     SerialInTimeOut = 0;\r
256     if (Mode->BaudRate != 0) {\r
257       SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;\r
258     }\r
259 \r
260     Status = SerialIo->SetAttributes (\r
261                         SerialIo,\r
262                         Mode->BaudRate,\r
263                         Mode->ReceiveFifoDepth,\r
264                         (UINT32) SerialInTimeOut,\r
265                         (EFI_PARITY_TYPE) (Mode->Parity),\r
266                         (UINT8) Mode->DataBits,\r
267                         (EFI_STOP_BITS_TYPE) (Mode->StopBits)\r
268                         );\r
269 \r
270     if (EFI_ERROR (Status)) {\r
271       TerminalDevice->SerialInTimeOut = 0;\r
272     } else {\r
273       TerminalDevice->SerialInTimeOut = SerialInTimeOut;\r
274     }\r
275   }\r
276   //\r
277   //  check whether serial buffer is empty\r
278   //\r
279   Status = SerialIo->GetControl (SerialIo, &Control);\r
280 \r
281   if (Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) {\r
282     //\r
283     // Translate all the raw data in RawFIFO into EFI Key,\r
284     // according to different terminal type supported.\r
285     //\r
286     TranslateRawDataToEfiKey (TerminalDevice);\r
287 \r
288     //\r
289     //  if there is pre-fetched Efi Key in EfiKeyFIFO buffer,\r
290     //  return directly.\r
291     //\r
292     if (!IsEfiKeyFiFoEmpty (TerminalDevice)) {\r
293       return EFI_SUCCESS;\r
294     } else {\r
295       return EFI_NOT_READY;\r
296     }\r
297   }\r
298   //\r
299   // Fetch all the keys in the serial buffer,\r
300   // and insert the byte stream into RawFIFO.\r
301   //\r
302   do {\r
303 \r
304     Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input);\r
305 \r
306     if (EFI_ERROR (Status)) {\r
307       if (Status == EFI_DEVICE_ERROR) {\r
308         REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
309           EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
310           PcdGet32 (PcdStatusCodeValueRemoteConsoleInputError),\r
311           TerminalDevice->DevicePath\r
312           );\r
313       }\r
314       break;\r
315     }\r
316 \r
317     RawFiFoInsertOneKey (TerminalDevice, Input);\r
318   } while (TRUE);\r
319 \r
320   //\r
321   // Translate all the raw data in RawFIFO into EFI Key,\r
322   // according to different terminal type supported.\r
323   //\r
324   TranslateRawDataToEfiKey (TerminalDevice);\r
325 \r
326   if (IsEfiKeyFiFoEmpty (TerminalDevice)) {\r
327     return EFI_NOT_READY;\r
328   }\r
329 \r
330   return EFI_SUCCESS;\r
331 }\r
332 \r
333 EFI_STATUS\r
334 GetOneKeyFromSerial (\r
335   EFI_SERIAL_IO_PROTOCOL  *SerialIo,\r
336   UINT8                   *Input\r
337   )\r
338 /*++\r
339     Get one key out of serial buffer.\r
340     If serial buffer is empty, return EFI_NOT_READY;\r
341     if reading serial buffer encounter error, returns EFI_DEVICE_ERROR;\r
342     if reading serial buffer successfully, put the fetched key to \r
343     the parameter "Input", and return EFI_SUCCESS.\r
344 --*/\r
345 {\r
346   EFI_STATUS  Status;\r
347   UINTN       Size;\r
348 \r
349   Size    = 1;\r
350   *Input  = 0;\r
351 \r
352   Status  = SerialIo->Read (SerialIo, &Size, Input);\r
353 \r
354   if (EFI_ERROR (Status)) {\r
355 \r
356     if (Status == EFI_TIMEOUT) {\r
357       return EFI_NOT_READY;\r
358     }\r
359 \r
360     return EFI_DEVICE_ERROR;\r
361 \r
362   }\r
363 \r
364   if (*Input == 0) {\r
365     return EFI_NOT_READY;\r
366   }\r
367 \r
368   return EFI_SUCCESS;\r
369 }\r
370 \r
371 BOOLEAN\r
372 RawFiFoInsertOneKey (\r
373   TERMINAL_DEV      *TerminalDevice,\r
374   UINT8             Input\r
375   )\r
376 /*++\r
377     Insert one byte raw data into the Raw Data FIFO.\r
378     If FIFO is FULL before data insertion,\r
379     return FALSE, and the key is lost.\r
380 --*/\r
381 {\r
382   UINT8 Tail;\r
383 \r
384   Tail = TerminalDevice->RawFiFo.Tail;\r
385 \r
386   if (IsRawFiFoFull (TerminalDevice)) {\r
387     //\r
388     // Raw FIFO is full\r
389     //\r
390     return FALSE;\r
391   }\r
392 \r
393   TerminalDevice->RawFiFo.Data[Tail]  = Input;\r
394 \r
395   TerminalDevice->RawFiFo.Tail        = (UINT8) ((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1));\r
396 \r
397   return TRUE;\r
398 }\r
399 \r
400 BOOLEAN\r
401 RawFiFoRemoveOneKey (\r
402   TERMINAL_DEV  *TerminalDevice,\r
403   UINT8         *Output\r
404   )\r
405 /*++\r
406     Remove one byte raw data out of the Raw Data FIFO.\r
407     If FIFO buffer is empty before remove operation,\r
408     return FALSE.\r
409 --*/\r
410 {\r
411   UINT8 Head;\r
412 \r
413   Head = TerminalDevice->RawFiFo.Head;\r
414 \r
415   if (IsRawFiFoEmpty (TerminalDevice)) {\r
416     //\r
417     //  FIFO is empty\r
418     //\r
419     *Output = 0;\r
420     return FALSE;\r
421   }\r
422 \r
423   *Output                       = TerminalDevice->RawFiFo.Data[Head];\r
424 \r
425   TerminalDevice->RawFiFo.Head  = (UINT8) ((Head + 1) % (RAW_FIFO_MAX_NUMBER + 1));\r
426 \r
427   return TRUE;\r
428 }\r
429 \r
430 BOOLEAN\r
431 IsRawFiFoEmpty (\r
432   TERMINAL_DEV  *TerminalDevice\r
433   )\r
434 /*++\r
435     Clarify whether FIFO buffer is empty.\r
436 --*/\r
437 {\r
438   if (TerminalDevice->RawFiFo.Head == TerminalDevice->RawFiFo.Tail) {\r
439     return TRUE;\r
440   } else {\r
441     return FALSE;\r
442   }\r
443 }\r
444 \r
445 BOOLEAN\r
446 IsRawFiFoFull (\r
447   TERMINAL_DEV  *TerminalDevice\r
448   )\r
449 /*++\r
450     Clarify whether FIFO buffer is full.\r
451 --*/\r
452 {\r
453   UINT8 Tail;\r
454   UINT8 Head;\r
455 \r
456   Tail  = TerminalDevice->RawFiFo.Tail;\r
457   Head  = TerminalDevice->RawFiFo.Head;\r
458 \r
459   if (((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)) == Head) {\r
460 \r
461     return TRUE;\r
462   }\r
463 \r
464   return FALSE;\r
465 }\r
466 \r
467 BOOLEAN\r
468 EfiKeyFiFoInsertOneKey (\r
469   TERMINAL_DEV      *TerminalDevice,\r
470   EFI_INPUT_KEY     Key\r
471   )\r
472 /*++\r
473     Insert one pre-fetched key into the FIFO buffer.\r
474     If FIFO buffer is FULL before key insertion,\r
475     return FALSE, and the key is lost.\r
476 --*/\r
477 {\r
478   UINT8 Tail;\r
479 \r
480   Tail = TerminalDevice->EfiKeyFiFo.Tail;\r
481 \r
482   if (IsEfiKeyFiFoFull (TerminalDevice)) {\r
483     //\r
484     // Efi Key FIFO is full\r
485     //\r
486     return FALSE;\r
487   }\r
488 \r
489   TerminalDevice->EfiKeyFiFo.Data[Tail] = Key;\r
490 \r
491   TerminalDevice->EfiKeyFiFo.Tail       = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));\r
492 \r
493   return TRUE;\r
494 }\r
495 \r
496 BOOLEAN\r
497 EfiKeyFiFoRemoveOneKey (\r
498   TERMINAL_DEV  *TerminalDevice,\r
499   EFI_INPUT_KEY *Output\r
500   )\r
501 /*++\r
502     Remove one pre-fetched key out of the FIFO buffer.\r
503     If FIFO buffer is empty before remove operation,\r
504     return FALSE.\r
505 --*/\r
506 {\r
507   UINT8 Head;\r
508 \r
509   Head = TerminalDevice->EfiKeyFiFo.Head;\r
510 \r
511   if (IsEfiKeyFiFoEmpty (TerminalDevice)) {\r
512     //\r
513     //  FIFO is empty\r
514     //\r
515     Output->ScanCode    = SCAN_NULL;\r
516     Output->UnicodeChar = 0;\r
517     return FALSE;\r
518   }\r
519 \r
520   *Output                         = TerminalDevice->EfiKeyFiFo.Data[Head];\r
521 \r
522   TerminalDevice->EfiKeyFiFo.Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));\r
523 \r
524   return TRUE;\r
525 }\r
526 \r
527 BOOLEAN\r
528 IsEfiKeyFiFoEmpty (\r
529   TERMINAL_DEV  *TerminalDevice\r
530   )\r
531 /*++\r
532     Clarify whether FIFO buffer is empty.\r
533 --*/\r
534 {\r
535   if (TerminalDevice->EfiKeyFiFo.Head == TerminalDevice->EfiKeyFiFo.Tail) {\r
536     return TRUE;\r
537   } else {\r
538     return FALSE;\r
539   }\r
540 }\r
541 \r
542 BOOLEAN\r
543 IsEfiKeyFiFoFull (\r
544   TERMINAL_DEV  *TerminalDevice\r
545   )\r
546 /*++\r
547     Clarify whether FIFO buffer is full.\r
548 --*/\r
549 {\r
550   UINT8 Tail;\r
551   UINT8 Head;\r
552 \r
553   Tail  = TerminalDevice->EfiKeyFiFo.Tail;\r
554   Head  = TerminalDevice->EfiKeyFiFo.Head;\r
555 \r
556   if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {\r
557 \r
558     return TRUE;\r
559   }\r
560 \r
561   return FALSE;\r
562 }\r
563 \r
564 BOOLEAN\r
565 UnicodeFiFoInsertOneKey (\r
566   TERMINAL_DEV      *TerminalDevice,\r
567   UINT16            Input\r
568   )\r
569 /*++\r
570     Insert one pre-fetched key into the FIFO buffer.\r
571     If FIFO buffer is FULL before key insertion,\r
572     return FALSE, and the key is lost.\r
573 --*/\r
574 {\r
575   UINT8 Tail;\r
576 \r
577   Tail = TerminalDevice->UnicodeFiFo.Tail;\r
578 \r
579   if (IsUnicodeFiFoFull (TerminalDevice)) {\r
580     //\r
581     // Unicode FIFO is full\r
582     //\r
583     return FALSE;\r
584   }\r
585 \r
586   TerminalDevice->UnicodeFiFo.Data[Tail]  = Input;\r
587 \r
588   TerminalDevice->UnicodeFiFo.Tail        = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));\r
589 \r
590   return TRUE;\r
591 }\r
592 \r
593 BOOLEAN\r
594 UnicodeFiFoRemoveOneKey (\r
595   TERMINAL_DEV  *TerminalDevice,\r
596   UINT16        *Output\r
597   )\r
598 /*++\r
599     Remove one pre-fetched key out of the FIFO buffer.\r
600     If FIFO buffer is empty before remove operation,\r
601     return FALSE.\r
602 --*/\r
603 {\r
604   UINT8 Head;\r
605 \r
606   Head = TerminalDevice->UnicodeFiFo.Head;\r
607 \r
608   if (IsUnicodeFiFoEmpty (TerminalDevice)) {\r
609     //\r
610     //  FIFO is empty\r
611     //\r
612     Output = NULL;\r
613     return FALSE;\r
614   }\r
615 \r
616   *Output = TerminalDevice->UnicodeFiFo.Data[Head];\r
617 \r
618   TerminalDevice->UnicodeFiFo.Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));\r
619 \r
620   return TRUE;\r
621 }\r
622 \r
623 BOOLEAN\r
624 IsUnicodeFiFoEmpty (\r
625   TERMINAL_DEV  *TerminalDevice\r
626   )\r
627 /*++\r
628     Clarify whether FIFO buffer is empty.\r
629 --*/\r
630 {\r
631   if (TerminalDevice->UnicodeFiFo.Head == TerminalDevice->UnicodeFiFo.Tail) {\r
632     return TRUE;\r
633   } else {\r
634     return FALSE;\r
635   }\r
636 }\r
637 \r
638 BOOLEAN\r
639 IsUnicodeFiFoFull (\r
640   TERMINAL_DEV  *TerminalDevice\r
641   )\r
642 /*++\r
643     Clarify whether FIFO buffer is full.\r
644 --*/\r
645 {\r
646   UINT8 Tail;\r
647   UINT8 Head;\r
648 \r
649   Tail  = TerminalDevice->UnicodeFiFo.Tail;\r
650   Head  = TerminalDevice->UnicodeFiFo.Head;\r
651 \r
652   if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {\r
653 \r
654     return TRUE;\r
655   }\r
656 \r
657   return FALSE;\r
658 }\r
659 \r
660 UINT8\r
661 UnicodeFiFoGetKeyCount (\r
662   TERMINAL_DEV    *TerminalDevice\r
663   )\r
664 {\r
665   UINT8 Tail;\r
666   UINT8 Head;\r
667 \r
668   Tail  = TerminalDevice->UnicodeFiFo.Tail;\r
669   Head  = TerminalDevice->UnicodeFiFo.Head;\r
670 \r
671   if (Tail >= Head) {\r
672     return (UINT8) (Tail - Head);\r
673   } else {\r
674     return (UINT8) (Tail + FIFO_MAX_NUMBER + 1 - Head);\r
675   }\r
676 }\r
677 \r
678 STATIC\r
679 VOID\r
680 UnicodeToEfiKeyFlushState (\r
681   IN  TERMINAL_DEV    *TerminalDevice\r
682   )\r
683 {\r
684   EFI_INPUT_KEY Key;\r
685 \r
686   if (TerminalDevice->InputState & INPUT_STATE_ESC) {\r
687     Key.ScanCode    = SCAN_ESC;\r
688     Key.UnicodeChar = 0;\r
689     EfiKeyFiFoInsertOneKey (TerminalDevice, Key);\r
690   }\r
691 \r
692   if (TerminalDevice->InputState & INPUT_STATE_CSI) {\r
693     Key.ScanCode    = SCAN_NULL;\r
694     Key.UnicodeChar = CSI;\r
695     EfiKeyFiFoInsertOneKey (TerminalDevice, Key);\r
696   }\r
697 \r
698   if (TerminalDevice->InputState & INPUT_STATE_LEFTOPENBRACKET) {\r
699     Key.ScanCode    = SCAN_NULL;\r
700     Key.UnicodeChar = LEFTOPENBRACKET;\r
701     EfiKeyFiFoInsertOneKey (TerminalDevice, Key);\r
702   }\r
703 \r
704   if (TerminalDevice->InputState & INPUT_STATE_O) {\r
705     Key.ScanCode    = SCAN_NULL;\r
706     Key.UnicodeChar = 'O';\r
707     EfiKeyFiFoInsertOneKey (TerminalDevice, Key);\r
708   }\r
709 \r
710   if (TerminalDevice->InputState & INPUT_STATE_2) {\r
711     Key.ScanCode    = SCAN_NULL;\r
712     Key.UnicodeChar = '2';\r
713     EfiKeyFiFoInsertOneKey (TerminalDevice, Key);\r
714   }\r
715 \r
716   gBS->SetTimer (\r
717         TerminalDevice->TwoSecondTimeOut,\r
718         TimerCancel,\r
719         0\r
720         );\r
721 \r
722   TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
723 }\r
724 \r
725 VOID\r
726 UnicodeToEfiKey (\r
727   IN  TERMINAL_DEV    *TerminalDevice\r
728   )\r
729 /*++\r
730   Routine Description:\r
731   \r
732     Converts a stream of Unicode characters from a terminal input device into EFI Keys that\r
733     can be read through the Simple Input Protocol.  The table below shows the keyboard\r
734     input mappings that this function supports.  If the ESC sequence listed in one of the \r
735     columns is presented, then it is translated into the coorespoding EFI Scan Code.  If a\r
736     matching sequence is not found, then the raw key strokes are converted into EFI Keys.\r
737     \r
738     2 seconds are allowed for an ESC sequence to be completed.  If the ESC sequence is not \r
739     completed in 2 seconds, then the raw key strokes of the partial ESC sequence are \r
740     converted into EFI Keys.\r
741     \r
742     There is one special input sequence that will force the system to reset.  \r
743     This is ESC R ESC r ESC R.\r
744   \r
745   Arguments:\r
746 \r
747     TerminaDevice : The terminal device to use to translate raw input into EFI Keys\r
748         \r
749   Returns:\r
750 \r
751     None\r
752 \r
753 Symbols used in table below\r
754 ===========================\r
755   ESC = 0x1B  \r
756   CSI = 0x9B  \r
757   DEL = 0x7f  \r
758   ^   = CTRL\r
759 \r
760 +=========+======+===========+==========+==========+\r
761 |         | EFI  | EFI 1.10  |          |          |\r
762 |         | Scan |           |  VT100+  |          |\r
763 |   KEY   | Code |  PC ANSI  |  VTUTF8  |   VT100  |\r
764 +=========+======+===========+==========+==========+\r
765 | NULL    | 0x00 |           |          |          |\r
766 | UP      | 0x01 | ESC [ A   | ESC [ A  | ESC [ A  |\r
767 | DOWN    | 0x02 | ESC [ B   | ESC [ B  | ESC [ B  |\r
768 | RIGHT   | 0x03 | ESC [ C   | ESC [ C  | ESC [ C  | \r
769 | LEFT    | 0x04 | ESC [ D   | ESC [ D  | ESC [ D  |\r
770 | HOME    | 0x05 | ESC [ H   | ESC h    | ESC [ H  |\r
771 | END     | 0x06 | ESC [ F   | ESC k    | ESC [ K  |\r
772 | INSERT  | 0x07 | ESC [ @   | ESC +    | ESC [ @  |\r
773 |         |      | ESC [ L   |          | ESC [ L  |\r
774 | DELETE  | 0x08 | ESC [ X   | ESC -    | ESC [ P  |\r
775 | PG UP   | 0x09 | ESC [ I   | ESC ?    | ESC [ V  |\r
776 |         |      |           |          | ESC [ ?  |\r
777 | PG DOWN | 0x0A | ESC [ G   | ESC /    | ESC [ U  |\r
778 |         |      |           |          | ESC [ /  |\r
779 | F1      | 0x0B | ESC [ M   | ESC 1    | ESC O P  |\r
780 | F2      | 0x0C | ESC [ N   | ESC 2    | ESC O Q  |\r
781 | F3      | 0x0D | ESC [ O   | ESC 3    | ESC O w  |\r
782 | F4      | 0x0E | ESC [ P   | ESC 4    | ESC O x  |\r
783 | F5      | 0x0F | ESC [ Q   | ESC 5    | ESC O t  |\r
784 | F6      | 0x10 | ESC [ R   | ESC 6    | ESC O u  |\r
785 | F7      | 0x11 | ESC [ S   | ESC 7    | ESC O q  |\r
786 | F8      | 0x12 | ESC [ T   | ESC 8    | ESC O r  |\r
787 | F9      | 0x13 | ESC [ U   | ESC 9    | ESC O p  |\r
788 | F10     | 0x14 | ESC [ V   | ESC 0    | ESC O M  |\r
789 | Escape  | 0x17 | ESC       | ESC      | ESC      |\r
790 +=========+======+===========+==========+=========+\r
791 \r
792 Special Mappings\r
793 ================\r
794 ESC R ESC r ESC R = Reset System\r
795 \r
796 --*/\r
797 {\r
798   EFI_STATUS          Status;\r
799   EFI_STATUS          TimerStatus;\r
800   UINT16              UnicodeChar;\r
801   EFI_INPUT_KEY       Key;\r
802   BOOLEAN             SetDefaultResetState;\r
803   \r
804   TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);\r
805 \r
806   if (!EFI_ERROR (TimerStatus)) {\r
807     UnicodeToEfiKeyFlushState (TerminalDevice);\r
808     TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
809   }\r
810 \r
811   while (!IsUnicodeFiFoEmpty(TerminalDevice)) {\r
812     \r
813     if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {\r
814       //\r
815       // Check to see if the 2 second timer has expired\r
816       //\r
817       TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);\r
818       if (!EFI_ERROR (TimerStatus)) {\r
819         UnicodeToEfiKeyFlushState (TerminalDevice);\r
820         TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
821       }\r
822     }\r
823 \r
824     //\r
825     // Fetch one Unicode character from the Unicode FIFO\r
826     //\r
827     UnicodeFiFoRemoveOneKey (TerminalDevice,&UnicodeChar);\r
828 \r
829     SetDefaultResetState = TRUE;\r
830 \r
831     switch (TerminalDevice->InputState) {\r
832     case INPUT_STATE_DEFAULT:\r
833 \r
834       break;\r
835 \r
836     case INPUT_STATE_ESC:\r
837 \r
838       if (UnicodeChar == LEFTOPENBRACKET) {\r
839         TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET;\r
840         TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
841         continue;\r
842       }\r
843 \r
844       if (UnicodeChar == 'O' && TerminalDevice->TerminalType == VT100Type) {\r
845         TerminalDevice->InputState |= INPUT_STATE_O;\r
846         TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
847         continue;\r
848       }\r
849 \r
850       Key.ScanCode = SCAN_NULL;\r
851       \r
852       if (TerminalDevice->TerminalType == VT100PlusType || \r
853           TerminalDevice->TerminalType == VTUTF8Type) {\r
854         switch (UnicodeChar) {\r
855         case '1': \r
856           Key.ScanCode = SCAN_F1;         \r
857           break;\r
858         case '2': \r
859           Key.ScanCode = SCAN_F2;         \r
860           break;\r
861         case '3': \r
862           Key.ScanCode = SCAN_F3;         \r
863           break;\r
864         case '4': \r
865           Key.ScanCode = SCAN_F4;         \r
866           break;\r
867         case '5': \r
868           Key.ScanCode = SCAN_F5;         \r
869           break;\r
870         case '6': \r
871           Key.ScanCode = SCAN_F6;         \r
872           break;\r
873         case '7': \r
874           Key.ScanCode = SCAN_F7;         \r
875           break;\r
876         case '8': \r
877           Key.ScanCode = SCAN_F8;         \r
878           break;\r
879         case '9': \r
880           Key.ScanCode = SCAN_F9;         \r
881           break;\r
882         case '0': \r
883           Key.ScanCode = SCAN_F10;        \r
884           break;\r
885         case 'h': \r
886           Key.ScanCode = SCAN_HOME;       \r
887           break;\r
888         case 'k': \r
889           Key.ScanCode = SCAN_END;        \r
890           break;\r
891         case '+': \r
892           Key.ScanCode = SCAN_INSERT;     \r
893           break;\r
894         case '-': \r
895           Key.ScanCode = SCAN_DELETE;     \r
896           break;\r
897         case '/': \r
898           Key.ScanCode = SCAN_PAGE_DOWN;  \r
899           break;\r
900         case '?': \r
901           Key.ScanCode = SCAN_PAGE_UP;    \r
902           break;        \r
903         default :                                 \r
904           break;\r
905         }\r
906       }\r
907       \r
908       switch (UnicodeChar) {\r
909       case 'R': \r
910         if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) {\r
911           TerminalDevice->ResetState = RESET_STATE_ESC_R;\r
912           SetDefaultResetState = FALSE;\r
913         } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_r) {\r
914           gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
915         }\r
916         Key.ScanCode = SCAN_NULL;\r
917         break;\r
918       case 'r': \r
919         if (TerminalDevice->ResetState == RESET_STATE_ESC_R) {\r
920           TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_r;\r
921           SetDefaultResetState = FALSE;\r
922         }\r
923         Key.ScanCode = SCAN_NULL;\r
924         break;\r
925       default : \r
926         break;\r
927       }\r
928 \r
929       if (SetDefaultResetState) {\r
930         TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
931       }\r
932 \r
933       if (Key.ScanCode != SCAN_NULL) {\r
934         Key.UnicodeChar = 0;\r
935         EfiKeyFiFoInsertOneKey (TerminalDevice,Key);\r
936         TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
937         UnicodeToEfiKeyFlushState (TerminalDevice);\r
938         continue;\r
939       }\r
940 \r
941       UnicodeToEfiKeyFlushState (TerminalDevice);\r
942 \r
943       break;\r
944 \r
945     case INPUT_STATE_ESC | INPUT_STATE_O:\r
946 \r
947       TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
948 \r
949       Key.ScanCode = SCAN_NULL;\r
950       \r
951       if (TerminalDevice->TerminalType == VT100Type) {\r
952         switch (UnicodeChar) {\r
953         case 'P': \r
954           Key.ScanCode = SCAN_F1;         \r
955           break;\r
956         case 'Q': \r
957           Key.ScanCode = SCAN_F2;         \r
958           break;\r
959         case 'w': \r
960           Key.ScanCode = SCAN_F3;         \r
961           break;\r
962         case 'x': \r
963           Key.ScanCode = SCAN_F4;         \r
964           break;\r
965         case 't': \r
966           Key.ScanCode = SCAN_F5;         \r
967           break;\r
968         case 'u': \r
969           Key.ScanCode = SCAN_F6;         \r
970           break;\r
971         case 'q': \r
972           Key.ScanCode = SCAN_F7;         \r
973           break;\r
974         case 'r': \r
975           Key.ScanCode = SCAN_F8;         \r
976           break;\r
977         case 'p': \r
978           Key.ScanCode = SCAN_F9;         \r
979           break;\r
980         case 'M': \r
981           Key.ScanCode = SCAN_F10;        \r
982           break;\r
983         default :                                 \r
984           break;\r
985         }\r
986       }\r
987 \r
988       if (Key.ScanCode != SCAN_NULL) {\r
989         Key.UnicodeChar = 0;\r
990         EfiKeyFiFoInsertOneKey (TerminalDevice,Key);\r
991         TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
992         UnicodeToEfiKeyFlushState (TerminalDevice);\r
993         continue;\r
994       }\r
995 \r
996       UnicodeToEfiKeyFlushState (TerminalDevice);\r
997 \r
998       break;\r
999 \r
1000     case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET:\r
1001     \r
1002       TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
1003       \r
1004       Key.ScanCode = SCAN_NULL;\r
1005       \r
1006       if (TerminalDevice->TerminalType == PcAnsiType    ||\r
1007           TerminalDevice->TerminalType == VT100Type     ||\r
1008           TerminalDevice->TerminalType == VT100PlusType || \r
1009           TerminalDevice->TerminalType == VTUTF8Type) {\r
1010         switch (UnicodeChar) {\r
1011         case 'A': \r
1012           Key.ScanCode = SCAN_UP;         \r
1013           break;\r
1014         case 'B': \r
1015           Key.ScanCode = SCAN_DOWN;       \r
1016           break;\r
1017         case 'C': \r
1018           Key.ScanCode = SCAN_RIGHT;      \r
1019           break;\r
1020         case 'D': \r
1021           Key.ScanCode = SCAN_LEFT;       \r
1022           break;\r
1023         case 'H': \r
1024           if (TerminalDevice->TerminalType == PcAnsiType ||\r
1025               TerminalDevice->TerminalType == VT100Type) {\r
1026             Key.ScanCode = SCAN_HOME;       \r
1027           }\r
1028           break;\r
1029         case 'F': \r
1030           if (TerminalDevice->TerminalType == PcAnsiType) {\r
1031             Key.ScanCode = SCAN_END;\r
1032           }\r
1033           break;\r
1034         case 'K': \r
1035           if (TerminalDevice->TerminalType == VT100Type) {\r
1036             Key.ScanCode = SCAN_END;        \r
1037           }\r
1038           break;\r
1039         case 'L':   \r
1040         case '@': \r
1041           if (TerminalDevice->TerminalType == PcAnsiType ||\r
1042               TerminalDevice->TerminalType == VT100Type) {\r
1043             Key.ScanCode = SCAN_INSERT;     \r
1044           }\r
1045           break;\r
1046         case 'X': \r
1047           if (TerminalDevice->TerminalType == PcAnsiType) {\r
1048             Key.ScanCode = SCAN_DELETE;\r
1049           }\r
1050           break;\r
1051         case 'P': \r
1052           if (TerminalDevice->TerminalType == VT100Type) {\r
1053             Key.ScanCode = SCAN_DELETE;        \r
1054           } else if (TerminalDevice->TerminalType == PcAnsiType) {\r
1055             Key.ScanCode = SCAN_F4;\r
1056           }\r
1057           break;\r
1058         case 'I': \r
1059           if (TerminalDevice->TerminalType == PcAnsiType) {\r
1060             Key.ScanCode = SCAN_PAGE_UP;\r
1061           }\r
1062           break;        \r
1063         case 'V': \r
1064           if (TerminalDevice->TerminalType == PcAnsiType) {\r
1065             Key.ScanCode = SCAN_F10;\r
1066           }  \r
1067         case '?': \r
1068           if (TerminalDevice->TerminalType == VT100Type) {\r
1069             Key.ScanCode = SCAN_PAGE_UP;        \r
1070           }\r
1071           break;\r
1072         case 'G': \r
1073           if (TerminalDevice->TerminalType == PcAnsiType) {\r
1074             Key.ScanCode = SCAN_PAGE_DOWN;\r
1075           }\r
1076           break;        \r
1077         case 'U': \r
1078           if (TerminalDevice->TerminalType == PcAnsiType) {\r
1079             Key.ScanCode = SCAN_F9;\r
1080           }\r
1081         case '/': \r
1082           if (TerminalDevice->TerminalType == VT100Type) {\r
1083             Key.ScanCode = SCAN_PAGE_DOWN;        \r
1084           }\r
1085           break;\r
1086         case 'M': \r
1087           if (TerminalDevice->TerminalType == PcAnsiType) {\r
1088             Key.ScanCode = SCAN_F1;\r
1089           }\r
1090           break;        \r
1091         case 'N': \r
1092           if (TerminalDevice->TerminalType == PcAnsiType) {\r
1093             Key.ScanCode = SCAN_F2;\r
1094           }\r
1095           break;        \r
1096         case 'O': \r
1097           if (TerminalDevice->TerminalType == PcAnsiType) {\r
1098             Key.ScanCode = SCAN_F3;\r
1099           }\r
1100           break;        \r
1101         case 'Q': \r
1102           if (TerminalDevice->TerminalType == PcAnsiType) {\r
1103             Key.ScanCode = SCAN_F5;\r
1104           }\r
1105           break;        \r
1106         case 'R': \r
1107           if (TerminalDevice->TerminalType == PcAnsiType) {\r
1108             Key.ScanCode = SCAN_F6;\r
1109           }\r
1110           break;        \r
1111         case 'S': \r
1112           if (TerminalDevice->TerminalType == PcAnsiType) {\r
1113             Key.ScanCode = SCAN_F7;\r
1114           }\r
1115           break;        \r
1116         case 'T': \r
1117           if (TerminalDevice->TerminalType == PcAnsiType) {\r
1118             Key.ScanCode = SCAN_F8;\r
1119           }\r
1120           break;        \r
1121         default : \r
1122           break;\r
1123         }\r
1124       }\r
1125 \r
1126       if (Key.ScanCode != SCAN_NULL) {\r
1127         Key.UnicodeChar = 0;\r
1128         EfiKeyFiFoInsertOneKey (TerminalDevice,Key);\r
1129         TerminalDevice->InputState = INPUT_STATE_DEFAULT;\r
1130         UnicodeToEfiKeyFlushState (TerminalDevice);\r
1131         continue;\r
1132       }\r
1133 \r
1134       UnicodeToEfiKeyFlushState (TerminalDevice);\r
1135 \r
1136       break;\r
1137 \r
1138     \r
1139     default:\r
1140       //\r
1141       // Invalid state. This should never happen.\r
1142       //\r
1143       ASSERT (FALSE);\r
1144 \r
1145       UnicodeToEfiKeyFlushState (TerminalDevice);\r
1146 \r
1147       break;\r
1148     }\r
1149 \r
1150     if (UnicodeChar == ESC) {\r
1151       TerminalDevice->InputState = INPUT_STATE_ESC;\r
1152     }\r
1153     \r
1154     if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {\r
1155       Status = gBS->SetTimer(\r
1156                       TerminalDevice->TwoSecondTimeOut,\r
1157                       TimerRelative,\r
1158                       (UINT64)20000000\r
1159                       );\r
1160       ASSERT_EFI_ERROR (Status);\r
1161       continue;\r
1162     }\r
1163 \r
1164     if (SetDefaultResetState) {\r
1165       TerminalDevice->ResetState = RESET_STATE_DEFAULT;\r
1166     }\r
1167 \r
1168     if (UnicodeChar == DEL) {\r
1169       Key.ScanCode    = SCAN_DELETE;\r
1170       Key.UnicodeChar = 0;\r
1171     } else {\r
1172       Key.ScanCode    = SCAN_NULL;\r
1173       Key.UnicodeChar = UnicodeChar;\r
1174     }\r
1175 \r
1176     EfiKeyFiFoInsertOneKey (TerminalDevice,Key);\r
1177   }\r
1178 }\r