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