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