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