]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
2286264b29e5833f1db346c7efa20406408ae2c9
[mirror_edk2.git] / MdeModulePkg / Universal / Console / TerminalDxe / TerminalConIn.c
1 /** @file
2 Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol.
3
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
6 Copyright (C) 2016 Silicon Graphics, Inc. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "Terminal.h"
12
13 /**
14 Reads the next keystroke from the input device. The WaitForKey Event can
15 be used to test for existence of a keystroke via WaitForEvent () call.
16
17 @param TerminalDevice Terminal driver private structure
18 @param KeyData A pointer to a buffer that is filled in with the
19 keystroke state data for the key that was
20 pressed.
21
22 @retval EFI_SUCCESS The keystroke information was returned.
23 @retval EFI_NOT_READY There was no keystroke data available.
24 @retval EFI_INVALID_PARAMETER KeyData is NULL.
25
26 **/
27 EFI_STATUS
28 ReadKeyStrokeWorker (
29 IN TERMINAL_DEV *TerminalDevice,
30 OUT EFI_KEY_DATA *KeyData
31 )
32 {
33 if (KeyData == NULL) {
34 return EFI_INVALID_PARAMETER;
35 }
36
37 KeyData->KeyState.KeyShiftState = 0;
38 KeyData->KeyState.KeyToggleState = 0;
39
40 if (!EfiKeyFiFoRemoveOneKey (TerminalDevice, &KeyData->Key)) {
41 return EFI_NOT_READY;
42 }
43
44 return EFI_SUCCESS;
45 }
46
47 /**
48 Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset().
49 This driver only perform dependent serial device reset regardless of
50 the value of ExtendeVerification
51
52 @param This Indicates the calling context.
53 @param ExtendedVerification Skip by this driver.
54
55 @retval EFI_SUCCESS The reset operation succeeds.
56 @retval EFI_DEVICE_ERROR The dependent serial port reset fails.
57
58 **/
59 EFI_STATUS
60 EFIAPI
61 TerminalConInReset (
62 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
63 IN BOOLEAN ExtendedVerification
64 )
65 {
66 EFI_STATUS Status;
67 TERMINAL_DEV *TerminalDevice;
68
69 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);
70
71 //
72 // Report progress code here
73 //
74 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
75 EFI_PROGRESS_CODE,
76 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_RESET),
77 TerminalDevice->DevicePath
78 );
79
80 Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo);
81
82 //
83 // Make all the internal buffer empty for keys
84 //
85 TerminalDevice->RawFiFo->Head = TerminalDevice->RawFiFo->Tail;
86 TerminalDevice->UnicodeFiFo->Head = TerminalDevice->UnicodeFiFo->Tail;
87 TerminalDevice->EfiKeyFiFo->Head = TerminalDevice->EfiKeyFiFo->Tail;
88 TerminalDevice->EfiKeyFiFoForNotify->Head = TerminalDevice->EfiKeyFiFoForNotify->Tail;
89
90 if (EFI_ERROR (Status)) {
91 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
92 EFI_ERROR_CODE | EFI_ERROR_MINOR,
93 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
94 TerminalDevice->DevicePath
95 );
96 }
97
98 return Status;
99 }
100
101 /**
102 Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke().
103
104 @param This Indicates the calling context.
105 @param Key A pointer to a buffer that is filled in with the
106 keystroke information for the key that was sent
107 from terminal.
108
109 @retval EFI_SUCCESS The keystroke information is returned successfully.
110 @retval EFI_NOT_READY There is no keystroke data available.
111 @retval EFI_DEVICE_ERROR The dependent serial device encounters error.
112
113 **/
114 EFI_STATUS
115 EFIAPI
116 TerminalConInReadKeyStroke (
117 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
118 OUT EFI_INPUT_KEY *Key
119 )
120 {
121 TERMINAL_DEV *TerminalDevice;
122 EFI_STATUS Status;
123 EFI_KEY_DATA KeyData;
124
125 //
126 // get TERMINAL_DEV from "This" parameter.
127 //
128 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);
129
130 Status = ReadKeyStrokeWorker (TerminalDevice, &KeyData);
131 if (EFI_ERROR (Status)) {
132 return Status;
133 }
134
135 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
136
137 return EFI_SUCCESS;
138 }
139
140 /**
141 Check if the key already has been registered.
142
143 If both RegsiteredData and InputData is NULL, then ASSERT().
144
145 @param RegsiteredData A pointer to a buffer that is filled in with the
146 keystroke state data for the key that was
147 registered.
148 @param InputData A pointer to a buffer that is filled in with the
149 keystroke state data for the key that was
150 pressed.
151
152 @retval TRUE Key be pressed matches a registered key.
153 @retval FALSE Match failed.
154
155 **/
156 BOOLEAN
157 IsKeyRegistered (
158 IN EFI_KEY_DATA *RegsiteredData,
159 IN EFI_KEY_DATA *InputData
160 )
161 {
162 ASSERT (RegsiteredData != NULL && InputData != NULL);
163
164 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
165 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar))
166 {
167 return FALSE;
168 }
169
170 return TRUE;
171 }
172
173 /**
174 Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
175 Signal the event if there is key available
176
177 @param Event Indicates the event that invoke this function.
178 @param Context Indicates the calling context.
179
180 **/
181 VOID
182 EFIAPI
183 TerminalConInWaitForKeyEx (
184 IN EFI_EVENT Event,
185 IN VOID *Context
186 )
187 {
188 TerminalConInWaitForKey (Event, Context);
189 }
190
191 //
192 // Simple Text Input Ex protocol functions
193 //
194
195 /**
196 Reset the input device and optionally run diagnostics
197
198 @param This Protocol instance pointer.
199 @param ExtendedVerification Driver may perform diagnostics on reset.
200
201 @retval EFI_SUCCESS The device was reset.
202 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
203 not be reset.
204
205 **/
206 EFI_STATUS
207 EFIAPI
208 TerminalConInResetEx (
209 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
210 IN BOOLEAN ExtendedVerification
211 )
212 {
213 EFI_STATUS Status;
214 TERMINAL_DEV *TerminalDevice;
215
216 TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
217
218 Status = TerminalDevice->SimpleInput.Reset (&TerminalDevice->SimpleInput, ExtendedVerification);
219 if (EFI_ERROR (Status)) {
220 return EFI_DEVICE_ERROR;
221 }
222
223 return EFI_SUCCESS;
224 }
225
226 /**
227 Reads the next keystroke from the input device. The WaitForKey Event can
228 be used to test for existence of a keystroke via WaitForEvent () call.
229
230 @param This Protocol instance pointer.
231 @param KeyData A pointer to a buffer that is filled in with the
232 keystroke state data for the key that was
233 pressed.
234
235 @retval EFI_SUCCESS The keystroke information was returned.
236 @retval EFI_NOT_READY There was no keystroke data available.
237 @retval EFI_DEVICE_ERROR The keystroke information was not returned due
238 to hardware errors.
239 @retval EFI_INVALID_PARAMETER KeyData is NULL.
240
241 **/
242 EFI_STATUS
243 EFIAPI
244 TerminalConInReadKeyStrokeEx (
245 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
246 OUT EFI_KEY_DATA *KeyData
247 )
248 {
249 TERMINAL_DEV *TerminalDevice;
250
251 if (KeyData == NULL) {
252 return EFI_INVALID_PARAMETER;
253 }
254
255 TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
256
257 return ReadKeyStrokeWorker (TerminalDevice, KeyData);
258 }
259
260 /**
261 Set certain state for the input device.
262
263 @param This Protocol instance pointer.
264 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
265 state for the input device.
266
267 @retval EFI_SUCCESS The device state was set successfully.
268 @retval EFI_DEVICE_ERROR The device is not functioning correctly and
269 could not have the setting adjusted.
270 @retval EFI_UNSUPPORTED The device does not have the ability to set its
271 state.
272 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
273
274 **/
275 EFI_STATUS
276 EFIAPI
277 TerminalConInSetState (
278 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
279 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
280 )
281 {
282 if (KeyToggleState == NULL) {
283 return EFI_INVALID_PARAMETER;
284 }
285
286 if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) {
287 return EFI_UNSUPPORTED;
288 }
289
290 return EFI_SUCCESS;
291 }
292
293 /**
294 Register a notification function for a particular keystroke for the input device.
295
296 @param This Protocol instance pointer.
297 @param KeyData A pointer to a buffer that is filled in with
298 the keystroke information for the key that was
299 pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState
300 and KeyData.KeyState.KeyShiftState are 0, then any incomplete
301 keystroke will trigger a notification of the KeyNotificationFunction.
302 @param KeyNotificationFunction Points to the function to be called when the key
303 sequence is typed specified by KeyData. This notification function
304 should be called at <=TPL_CALLBACK.
305 @param NotifyHandle Points to the unique handle assigned to the
306 registered notification.
307
308 @retval EFI_SUCCESS The notification function was registered
309 successfully.
310 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data
311 structures.
312 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
313
314 **/
315 EFI_STATUS
316 EFIAPI
317 TerminalConInRegisterKeyNotify (
318 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
319 IN EFI_KEY_DATA *KeyData,
320 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
321 OUT VOID **NotifyHandle
322 )
323 {
324 TERMINAL_DEV *TerminalDevice;
325 TERMINAL_CONSOLE_IN_EX_NOTIFY *NewNotify;
326 LIST_ENTRY *Link;
327 LIST_ENTRY *NotifyList;
328 TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
329
330 if ((KeyData == NULL) || (NotifyHandle == NULL) || (KeyNotificationFunction == NULL)) {
331 return EFI_INVALID_PARAMETER;
332 }
333
334 TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
335
336 //
337 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
338 //
339 NotifyList = &TerminalDevice->NotifyList;
340 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
341 CurrentNotify = CR (
342 Link,
343 TERMINAL_CONSOLE_IN_EX_NOTIFY,
344 NotifyEntry,
345 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
346 );
347 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
348 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
349 *NotifyHandle = CurrentNotify;
350 return EFI_SUCCESS;
351 }
352 }
353 }
354
355 //
356 // Allocate resource to save the notification function
357 //
358 NewNotify = (TERMINAL_CONSOLE_IN_EX_NOTIFY *)AllocateZeroPool (sizeof (TERMINAL_CONSOLE_IN_EX_NOTIFY));
359 if (NewNotify == NULL) {
360 return EFI_OUT_OF_RESOURCES;
361 }
362
363 NewNotify->Signature = TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
364 NewNotify->KeyNotificationFn = KeyNotificationFunction;
365 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
366 InsertTailList (&TerminalDevice->NotifyList, &NewNotify->NotifyEntry);
367
368 *NotifyHandle = NewNotify;
369
370 return EFI_SUCCESS;
371 }
372
373 /**
374 Remove a registered notification function from a particular keystroke.
375
376 @param This Protocol instance pointer.
377 @param NotificationHandle The handle of the notification function being
378 unregistered.
379
380 @retval EFI_SUCCESS The notification function was unregistered
381 successfully.
382 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
383
384 **/
385 EFI_STATUS
386 EFIAPI
387 TerminalConInUnregisterKeyNotify (
388 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
389 IN VOID *NotificationHandle
390 )
391 {
392 TERMINAL_DEV *TerminalDevice;
393 LIST_ENTRY *Link;
394 TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
395 LIST_ENTRY *NotifyList;
396
397 if (NotificationHandle == NULL) {
398 return EFI_INVALID_PARAMETER;
399 }
400
401 TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);
402
403 NotifyList = &TerminalDevice->NotifyList;
404 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
405 CurrentNotify = CR (
406 Link,
407 TERMINAL_CONSOLE_IN_EX_NOTIFY,
408 NotifyEntry,
409 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
410 );
411 if (CurrentNotify == NotificationHandle) {
412 //
413 // Remove the notification function from NotifyList and free resources
414 //
415 RemoveEntryList (&CurrentNotify->NotifyEntry);
416
417 gBS->FreePool (CurrentNotify);
418 return EFI_SUCCESS;
419 }
420 }
421
422 //
423 // Can not find the matching entry in database.
424 //
425 return EFI_INVALID_PARAMETER;
426 }
427
428 /**
429 Translate raw data into Unicode (according to different encode), and
430 translate Unicode into key information. (according to different standard).
431
432 @param TerminalDevice Terminal driver private structure.
433
434 **/
435 VOID
436 TranslateRawDataToEfiKey (
437 IN TERMINAL_DEV *TerminalDevice
438 )
439 {
440 switch (TerminalDevice->TerminalType) {
441 case TerminalTypePcAnsi:
442 case TerminalTypeVt100:
443 case TerminalTypeVt100Plus:
444 case TerminalTypeTtyTerm:
445 case TerminalTypeLinux:
446 case TerminalTypeXtermR6:
447 case TerminalTypeVt400:
448 case TerminalTypeSCO:
449 AnsiRawDataToUnicode (TerminalDevice);
450 UnicodeToEfiKey (TerminalDevice);
451 break;
452
453 case TerminalTypeVtUtf8:
454 //
455 // Process all the raw data in the RawFIFO,
456 // put the processed key into UnicodeFIFO.
457 //
458 VTUTF8RawDataToUnicode (TerminalDevice);
459
460 //
461 // Translate all the Unicode data in the UnicodeFIFO to Efi key,
462 // then put into EfiKeyFIFO.
463 //
464 UnicodeToEfiKey (TerminalDevice);
465
466 break;
467 }
468 }
469
470 /**
471 Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event
472 Signal the event if there is key available
473
474 @param Event Indicates the event that invoke this function.
475 @param Context Indicates the calling context.
476
477 **/
478 VOID
479 EFIAPI
480 TerminalConInWaitForKey (
481 IN EFI_EVENT Event,
482 IN VOID *Context
483 )
484 {
485 //
486 // Someone is waiting on the keystroke event, if there's
487 // a key pending, signal the event
488 //
489 if (!IsEfiKeyFiFoEmpty ((TERMINAL_DEV *)Context)) {
490 gBS->SignalEvent (Event);
491 }
492 }
493
494 /**
495 Timer handler to poll the key from serial.
496
497 @param Event Indicates the event that invoke this function.
498 @param Context Indicates the calling context.
499 **/
500 VOID
501 EFIAPI
502 TerminalConInTimerHandler (
503 IN EFI_EVENT Event,
504 IN VOID *Context
505 )
506 {
507 EFI_STATUS Status;
508 TERMINAL_DEV *TerminalDevice;
509 UINT32 Control;
510 UINT8 Input;
511 EFI_SERIAL_IO_MODE *Mode;
512 EFI_SERIAL_IO_PROTOCOL *SerialIo;
513 UINTN SerialInTimeOut;
514
515 TerminalDevice = (TERMINAL_DEV *)Context;
516
517 SerialIo = TerminalDevice->SerialIo;
518 if (SerialIo == NULL) {
519 return;
520 }
521
522 //
523 // if current timeout value for serial device is not identical with
524 // the value saved in TERMINAL_DEV structure, then recalculate the
525 // timeout value again and set serial attribute according to this value.
526 //
527 Mode = SerialIo->Mode;
528 if (Mode->Timeout != TerminalDevice->SerialInTimeOut) {
529 SerialInTimeOut = 0;
530 if (Mode->BaudRate != 0) {
531 //
532 // According to BAUD rate to calculate the timeout value.
533 //
534 SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN)Mode->BaudRate;
535 }
536
537 Status = SerialIo->SetAttributes (
538 SerialIo,
539 Mode->BaudRate,
540 Mode->ReceiveFifoDepth,
541 (UINT32)SerialInTimeOut,
542 (EFI_PARITY_TYPE)(Mode->Parity),
543 (UINT8)Mode->DataBits,
544 (EFI_STOP_BITS_TYPE)(Mode->StopBits)
545 );
546
547 if (EFI_ERROR (Status)) {
548 TerminalDevice->SerialInTimeOut = 0;
549 } else {
550 TerminalDevice->SerialInTimeOut = SerialInTimeOut;
551 }
552 }
553
554 //
555 // Check whether serial buffer is empty.
556 // Skip the key transfer loop only if the SerialIo protocol instance
557 // successfully reports EFI_SERIAL_INPUT_BUFFER_EMPTY.
558 //
559 Status = SerialIo->GetControl (SerialIo, &Control);
560 if (EFI_ERROR (Status) || ((Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) == 0)) {
561 //
562 // Fetch all the keys in the serial buffer,
563 // and insert the byte stream into RawFIFO.
564 //
565 while (!IsRawFiFoFull (TerminalDevice)) {
566 Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input);
567
568 if (EFI_ERROR (Status)) {
569 if (Status == EFI_DEVICE_ERROR) {
570 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
571 EFI_ERROR_CODE | EFI_ERROR_MINOR,
572 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_INPUT_ERROR),
573 TerminalDevice->DevicePath
574 );
575 }
576
577 break;
578 }
579
580 RawFiFoInsertOneKey (TerminalDevice, Input);
581 }
582 }
583
584 //
585 // Translate all the raw data in RawFIFO into EFI Key,
586 // according to different terminal type supported.
587 //
588 TranslateRawDataToEfiKey (TerminalDevice);
589 }
590
591 /**
592 Process key notify.
593
594 @param Event Indicates the event that invoke this function.
595 @param Context Indicates the calling context.
596 **/
597 VOID
598 EFIAPI
599 KeyNotifyProcessHandler (
600 IN EFI_EVENT Event,
601 IN VOID *Context
602 )
603 {
604 BOOLEAN HasKey;
605 TERMINAL_DEV *TerminalDevice;
606 EFI_INPUT_KEY Key;
607 EFI_KEY_DATA KeyData;
608 LIST_ENTRY *Link;
609 LIST_ENTRY *NotifyList;
610 TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
611 EFI_TPL OldTpl;
612
613 TerminalDevice = (TERMINAL_DEV *)Context;
614
615 //
616 // Invoke notification functions.
617 //
618 NotifyList = &TerminalDevice->NotifyList;
619 while (TRUE) {
620 //
621 // Enter critical section
622 //
623 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
624 HasKey = EfiKeyFiFoForNotifyRemoveOneKey (TerminalDevice->EfiKeyFiFoForNotify, &Key);
625 CopyMem (&KeyData.Key, &Key, sizeof (EFI_INPUT_KEY));
626 KeyData.KeyState.KeyShiftState = 0;
627 KeyData.KeyState.KeyToggleState = 0;
628 //
629 // Leave critical section
630 //
631 gBS->RestoreTPL (OldTpl);
632 if (!HasKey) {
633 break;
634 }
635
636 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
637 CurrentNotify = CR (Link, TERMINAL_CONSOLE_IN_EX_NOTIFY, NotifyEntry, TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
638 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
639 CurrentNotify->KeyNotificationFn (&KeyData);
640 }
641 }
642 }
643 }
644
645 /**
646 Get one key out of serial buffer.
647
648 @param SerialIo Serial I/O protocol attached to the serial device.
649 @param Output The fetched key.
650
651 @retval EFI_NOT_READY If serial buffer is empty.
652 @retval EFI_DEVICE_ERROR If reading serial buffer encounter error.
653 @retval EFI_SUCCESS If reading serial buffer successfully, put
654 the fetched key to the parameter output.
655
656 **/
657 EFI_STATUS
658 GetOneKeyFromSerial (
659 EFI_SERIAL_IO_PROTOCOL *SerialIo,
660 UINT8 *Output
661 )
662 {
663 EFI_STATUS Status;
664 UINTN Size;
665
666 Size = 1;
667 *Output = 0;
668
669 //
670 // Read one key from serial I/O device.
671 //
672 Status = SerialIo->Read (SerialIo, &Size, Output);
673
674 if (EFI_ERROR (Status)) {
675 if (Status == EFI_TIMEOUT) {
676 return EFI_NOT_READY;
677 }
678
679 return EFI_DEVICE_ERROR;
680 }
681
682 if (*Output == 0) {
683 return EFI_NOT_READY;
684 }
685
686 return EFI_SUCCESS;
687 }
688
689 /**
690 Insert one byte raw data into the Raw Data FIFO.
691
692 @param TerminalDevice Terminal driver private structure.
693 @param Input The key will be input.
694
695 @retval TRUE If insert successfully.
696 @retval FALSE If Raw Data buffer is full before key insertion,
697 and the key is lost.
698
699 **/
700 BOOLEAN
701 RawFiFoInsertOneKey (
702 TERMINAL_DEV *TerminalDevice,
703 UINT8 Input
704 )
705 {
706 UINT8 Tail;
707
708 Tail = TerminalDevice->RawFiFo->Tail;
709
710 if (IsRawFiFoFull (TerminalDevice)) {
711 //
712 // Raw FIFO is full
713 //
714 return FALSE;
715 }
716
717 TerminalDevice->RawFiFo->Data[Tail] = Input;
718
719 TerminalDevice->RawFiFo->Tail = (UINT8)((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1));
720
721 return TRUE;
722 }
723
724 /**
725 Remove one pre-fetched key out of the Raw Data FIFO.
726
727 @param TerminalDevice Terminal driver private structure.
728 @param Output The key will be removed.
729
730 @retval TRUE If insert successfully.
731 @retval FALSE If Raw Data FIFO buffer is empty before remove operation.
732
733 **/
734 BOOLEAN
735 RawFiFoRemoveOneKey (
736 TERMINAL_DEV *TerminalDevice,
737 UINT8 *Output
738 )
739 {
740 UINT8 Head;
741
742 Head = TerminalDevice->RawFiFo->Head;
743
744 if (IsRawFiFoEmpty (TerminalDevice)) {
745 //
746 // FIFO is empty
747 //
748 *Output = 0;
749 return FALSE;
750 }
751
752 *Output = TerminalDevice->RawFiFo->Data[Head];
753
754 TerminalDevice->RawFiFo->Head = (UINT8)((Head + 1) % (RAW_FIFO_MAX_NUMBER + 1));
755
756 return TRUE;
757 }
758
759 /**
760 Clarify whether Raw Data FIFO buffer is empty.
761
762 @param TerminalDevice Terminal driver private structure
763
764 @retval TRUE If Raw Data FIFO buffer is empty.
765 @retval FALSE If Raw Data FIFO buffer is not empty.
766
767 **/
768 BOOLEAN
769 IsRawFiFoEmpty (
770 TERMINAL_DEV *TerminalDevice
771 )
772 {
773 if (TerminalDevice->RawFiFo->Head == TerminalDevice->RawFiFo->Tail) {
774 return TRUE;
775 } else {
776 return FALSE;
777 }
778 }
779
780 /**
781 Clarify whether Raw Data FIFO buffer is full.
782
783 @param TerminalDevice Terminal driver private structure
784
785 @retval TRUE If Raw Data FIFO buffer is full.
786 @retval FALSE If Raw Data FIFO buffer is not full.
787
788 **/
789 BOOLEAN
790 IsRawFiFoFull (
791 TERMINAL_DEV *TerminalDevice
792 )
793 {
794 UINT8 Tail;
795 UINT8 Head;
796
797 Tail = TerminalDevice->RawFiFo->Tail;
798 Head = TerminalDevice->RawFiFo->Head;
799
800 if (((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)) == Head) {
801 return TRUE;
802 }
803
804 return FALSE;
805 }
806
807 /**
808 Insert one pre-fetched key into the FIFO buffer.
809
810 @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.
811 @param Input The key will be input.
812
813 @retval TRUE If insert successfully.
814 @retval FALSE If FIFO buffer is full before key insertion,
815 and the key is lost.
816
817 **/
818 BOOLEAN
819 EfiKeyFiFoForNotifyInsertOneKey (
820 EFI_KEY_FIFO *EfiKeyFiFo,
821 EFI_INPUT_KEY *Input
822 )
823 {
824 UINT8 Tail;
825
826 Tail = EfiKeyFiFo->Tail;
827
828 if (IsEfiKeyFiFoForNotifyFull (EfiKeyFiFo)) {
829 //
830 // FIFO is full
831 //
832 return FALSE;
833 }
834
835 CopyMem (&EfiKeyFiFo->Data[Tail], Input, sizeof (EFI_INPUT_KEY));
836
837 EfiKeyFiFo->Tail = (UINT8)((Tail + 1) % (FIFO_MAX_NUMBER + 1));
838
839 return TRUE;
840 }
841
842 /**
843 Remove one pre-fetched key out of the FIFO buffer.
844
845 @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.
846 @param Output The key will be removed.
847
848 @retval TRUE If remove successfully.
849 @retval FALSE If FIFO buffer is empty before remove operation.
850
851 **/
852 BOOLEAN
853 EfiKeyFiFoForNotifyRemoveOneKey (
854 EFI_KEY_FIFO *EfiKeyFiFo,
855 EFI_INPUT_KEY *Output
856 )
857 {
858 UINT8 Head;
859
860 Head = EfiKeyFiFo->Head;
861 ASSERT (Head < FIFO_MAX_NUMBER + 1);
862
863 if (IsEfiKeyFiFoForNotifyEmpty (EfiKeyFiFo)) {
864 //
865 // FIFO is empty
866 //
867 Output->ScanCode = SCAN_NULL;
868 Output->UnicodeChar = 0;
869 return FALSE;
870 }
871
872 CopyMem (Output, &EfiKeyFiFo->Data[Head], sizeof (EFI_INPUT_KEY));
873
874 EfiKeyFiFo->Head = (UINT8)((Head + 1) % (FIFO_MAX_NUMBER + 1));
875
876 return TRUE;
877 }
878
879 /**
880 Clarify whether FIFO buffer is empty.
881
882 @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.
883
884 @retval TRUE If FIFO buffer is empty.
885 @retval FALSE If FIFO buffer is not empty.
886
887 **/
888 BOOLEAN
889 IsEfiKeyFiFoForNotifyEmpty (
890 EFI_KEY_FIFO *EfiKeyFiFo
891 )
892 {
893 if (EfiKeyFiFo->Head == EfiKeyFiFo->Tail) {
894 return TRUE;
895 } else {
896 return FALSE;
897 }
898 }
899
900 /**
901 Clarify whether FIFO buffer is full.
902
903 @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.
904
905 @retval TRUE If FIFO buffer is full.
906 @retval FALSE If FIFO buffer is not full.
907
908 **/
909 BOOLEAN
910 IsEfiKeyFiFoForNotifyFull (
911 EFI_KEY_FIFO *EfiKeyFiFo
912 )
913 {
914 UINT8 Tail;
915 UINT8 Head;
916
917 Tail = EfiKeyFiFo->Tail;
918 Head = EfiKeyFiFo->Head;
919
920 if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
921 return TRUE;
922 }
923
924 return FALSE;
925 }
926
927 /**
928 Insert one pre-fetched key into the FIFO buffer.
929
930 @param TerminalDevice Terminal driver private structure.
931 @param Key The key will be input.
932
933 @retval TRUE If insert successfully.
934 @retval FALSE If FIFO buffer is full before key insertion,
935 and the key is lost.
936
937 **/
938 BOOLEAN
939 EfiKeyFiFoInsertOneKey (
940 TERMINAL_DEV *TerminalDevice,
941 EFI_INPUT_KEY *Key
942 )
943 {
944 UINT8 Tail;
945 LIST_ENTRY *Link;
946 LIST_ENTRY *NotifyList;
947 TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
948 EFI_KEY_DATA KeyData;
949
950 Tail = TerminalDevice->EfiKeyFiFo->Tail;
951
952 CopyMem (&KeyData.Key, Key, sizeof (EFI_INPUT_KEY));
953 KeyData.KeyState.KeyShiftState = 0;
954 KeyData.KeyState.KeyToggleState = 0;
955
956 //
957 // Signal KeyNotify process event if this key pressed matches any key registered.
958 //
959 NotifyList = &TerminalDevice->NotifyList;
960 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
961 CurrentNotify = CR (
962 Link,
963 TERMINAL_CONSOLE_IN_EX_NOTIFY,
964 NotifyEntry,
965 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
966 );
967 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
968 //
969 // The key notification function needs to run at TPL_CALLBACK
970 // while current TPL is TPL_NOTIFY. It will be invoked in
971 // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.
972 //
973 EfiKeyFiFoForNotifyInsertOneKey (TerminalDevice->EfiKeyFiFoForNotify, Key);
974 gBS->SignalEvent (TerminalDevice->KeyNotifyProcessEvent);
975 break;
976 }
977 }
978
979 if (IsEfiKeyFiFoFull (TerminalDevice)) {
980 //
981 // Efi Key FIFO is full
982 //
983 return FALSE;
984 }
985
986 CopyMem (&TerminalDevice->EfiKeyFiFo->Data[Tail], Key, sizeof (EFI_INPUT_KEY));
987
988 TerminalDevice->EfiKeyFiFo->Tail = (UINT8)((Tail + 1) % (FIFO_MAX_NUMBER + 1));
989
990 return TRUE;
991 }
992
993 /**
994 Remove one pre-fetched key out of the FIFO buffer.
995
996 @param TerminalDevice Terminal driver private structure.
997 @param Output The key will be removed.
998
999 @retval TRUE If insert successfully.
1000 @retval FALSE If FIFO buffer is empty before remove operation.
1001
1002 **/
1003 BOOLEAN
1004 EfiKeyFiFoRemoveOneKey (
1005 TERMINAL_DEV *TerminalDevice,
1006 EFI_INPUT_KEY *Output
1007 )
1008 {
1009 UINT8 Head;
1010
1011 Head = TerminalDevice->EfiKeyFiFo->Head;
1012 ASSERT (Head < FIFO_MAX_NUMBER + 1);
1013
1014 if (IsEfiKeyFiFoEmpty (TerminalDevice)) {
1015 //
1016 // FIFO is empty
1017 //
1018 Output->ScanCode = SCAN_NULL;
1019 Output->UnicodeChar = 0;
1020 return FALSE;
1021 }
1022
1023 CopyMem (Output, &TerminalDevice->EfiKeyFiFo->Data[Head], sizeof (EFI_INPUT_KEY));
1024
1025 TerminalDevice->EfiKeyFiFo->Head = (UINT8)((Head + 1) % (FIFO_MAX_NUMBER + 1));
1026
1027 return TRUE;
1028 }
1029
1030 /**
1031 Clarify whether FIFO buffer is empty.
1032
1033 @param TerminalDevice Terminal driver private structure
1034
1035 @retval TRUE If FIFO buffer is empty.
1036 @retval FALSE If FIFO buffer is not empty.
1037
1038 **/
1039 BOOLEAN
1040 IsEfiKeyFiFoEmpty (
1041 TERMINAL_DEV *TerminalDevice
1042 )
1043 {
1044 if (TerminalDevice->EfiKeyFiFo->Head == TerminalDevice->EfiKeyFiFo->Tail) {
1045 return TRUE;
1046 } else {
1047 return FALSE;
1048 }
1049 }
1050
1051 /**
1052 Clarify whether FIFO buffer is full.
1053
1054 @param TerminalDevice Terminal driver private structure
1055
1056 @retval TRUE If FIFO buffer is full.
1057 @retval FALSE If FIFO buffer is not full.
1058
1059 **/
1060 BOOLEAN
1061 IsEfiKeyFiFoFull (
1062 TERMINAL_DEV *TerminalDevice
1063 )
1064 {
1065 UINT8 Tail;
1066 UINT8 Head;
1067
1068 Tail = TerminalDevice->EfiKeyFiFo->Tail;
1069 Head = TerminalDevice->EfiKeyFiFo->Head;
1070
1071 if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
1072 return TRUE;
1073 }
1074
1075 return FALSE;
1076 }
1077
1078 /**
1079 Insert one pre-fetched key into the Unicode FIFO buffer.
1080
1081 @param TerminalDevice Terminal driver private structure.
1082 @param Input The key will be input.
1083
1084 @retval TRUE If insert successfully.
1085 @retval FALSE If Unicode FIFO buffer is full before key insertion,
1086 and the key is lost.
1087
1088 **/
1089 BOOLEAN
1090 UnicodeFiFoInsertOneKey (
1091 TERMINAL_DEV *TerminalDevice,
1092 UINT16 Input
1093 )
1094 {
1095 UINT8 Tail;
1096
1097 Tail = TerminalDevice->UnicodeFiFo->Tail;
1098 ASSERT (Tail < FIFO_MAX_NUMBER + 1);
1099
1100 if (IsUnicodeFiFoFull (TerminalDevice)) {
1101 //
1102 // Unicode FIFO is full
1103 //
1104 return FALSE;
1105 }
1106
1107 TerminalDevice->UnicodeFiFo->Data[Tail] = Input;
1108
1109 TerminalDevice->UnicodeFiFo->Tail = (UINT8)((Tail + 1) % (FIFO_MAX_NUMBER + 1));
1110
1111 return TRUE;
1112 }
1113
1114 /**
1115 Remove one pre-fetched key out of the Unicode FIFO buffer.
1116 The caller should guarantee that Unicode FIFO buffer is not empty
1117 by IsUnicodeFiFoEmpty ().
1118
1119 @param TerminalDevice Terminal driver private structure.
1120 @param Output The key will be removed.
1121
1122 **/
1123 VOID
1124 UnicodeFiFoRemoveOneKey (
1125 TERMINAL_DEV *TerminalDevice,
1126 UINT16 *Output
1127 )
1128 {
1129 UINT8 Head;
1130
1131 Head = TerminalDevice->UnicodeFiFo->Head;
1132 ASSERT (Head < FIFO_MAX_NUMBER + 1);
1133
1134 *Output = TerminalDevice->UnicodeFiFo->Data[Head];
1135
1136 TerminalDevice->UnicodeFiFo->Head = (UINT8)((Head + 1) % (FIFO_MAX_NUMBER + 1));
1137 }
1138
1139 /**
1140 Clarify whether Unicode FIFO buffer is empty.
1141
1142 @param TerminalDevice Terminal driver private structure
1143
1144 @retval TRUE If Unicode FIFO buffer is empty.
1145 @retval FALSE If Unicode FIFO buffer is not empty.
1146
1147 **/
1148 BOOLEAN
1149 IsUnicodeFiFoEmpty (
1150 TERMINAL_DEV *TerminalDevice
1151 )
1152 {
1153 if (TerminalDevice->UnicodeFiFo->Head == TerminalDevice->UnicodeFiFo->Tail) {
1154 return TRUE;
1155 } else {
1156 return FALSE;
1157 }
1158 }
1159
1160 /**
1161 Clarify whether Unicode FIFO buffer is full.
1162
1163 @param TerminalDevice Terminal driver private structure
1164
1165 @retval TRUE If Unicode FIFO buffer is full.
1166 @retval FALSE If Unicode FIFO buffer is not full.
1167
1168 **/
1169 BOOLEAN
1170 IsUnicodeFiFoFull (
1171 TERMINAL_DEV *TerminalDevice
1172 )
1173 {
1174 UINT8 Tail;
1175 UINT8 Head;
1176
1177 Tail = TerminalDevice->UnicodeFiFo->Tail;
1178 Head = TerminalDevice->UnicodeFiFo->Head;
1179
1180 if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
1181 return TRUE;
1182 }
1183
1184 return FALSE;
1185 }
1186
1187 /**
1188 Update the Unicode characters from a terminal input device into EFI Keys FIFO.
1189
1190 @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
1191
1192 **/
1193 VOID
1194 UnicodeToEfiKeyFlushState (
1195 IN TERMINAL_DEV *TerminalDevice
1196 )
1197 {
1198 EFI_INPUT_KEY Key;
1199 UINT32 InputState;
1200
1201 InputState = TerminalDevice->InputState;
1202
1203 if (IsEfiKeyFiFoFull (TerminalDevice)) {
1204 return;
1205 }
1206
1207 if ((InputState & INPUT_STATE_ESC) != 0) {
1208 Key.ScanCode = SCAN_ESC;
1209 Key.UnicodeChar = 0;
1210 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1211 }
1212
1213 if ((InputState & INPUT_STATE_CSI) != 0) {
1214 Key.ScanCode = SCAN_NULL;
1215 Key.UnicodeChar = CSI;
1216 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1217 }
1218
1219 if ((InputState & INPUT_STATE_LEFTOPENBRACKET) != 0) {
1220 Key.ScanCode = SCAN_NULL;
1221 Key.UnicodeChar = LEFTOPENBRACKET;
1222 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1223 }
1224
1225 if ((InputState & INPUT_STATE_O) != 0) {
1226 Key.ScanCode = SCAN_NULL;
1227 Key.UnicodeChar = 'O';
1228 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1229 }
1230
1231 if ((InputState & INPUT_STATE_2) != 0) {
1232 Key.ScanCode = SCAN_NULL;
1233 Key.UnicodeChar = '2';
1234 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1235 }
1236
1237 //
1238 // Cancel the timer.
1239 //
1240 gBS->SetTimer (
1241 TerminalDevice->TwoSecondTimeOut,
1242 TimerCancel,
1243 0
1244 );
1245
1246 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1247 }
1248
1249 /**
1250 Converts a stream of Unicode characters from a terminal input device into EFI Keys that
1251 can be read through the Simple Input Protocol.
1252
1253 The table below shows the keyboard input mappings that this function supports.
1254 If the ESC sequence listed in one of the columns is presented, then it is translated
1255 into the corresponding EFI Scan Code. If a matching sequence is not found, then the raw
1256 key strokes are converted into EFI Keys.
1257
1258 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not
1259 completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
1260 converted into EFI Keys.
1261 There is one special input sequence that will force the system to reset.
1262 This is ESC R ESC r ESC R.
1263
1264 Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100.
1265 The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 /
1266 DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example.
1267
1268 Symbols used in table below
1269 ===========================
1270 ESC = 0x1B
1271 CSI = 0x9B
1272 DEL = 0x7f
1273 ^ = CTRL
1274
1275 +=========+======+===========+==========+==========+
1276 | | EFI | UEFI 2.0 | | |
1277 | | Scan | | VT100+ | |
1278 | KEY | Code | PC ANSI | VTUTF8 | VT100 |
1279 +=========+======+===========+==========+==========+
1280 | NULL | 0x00 | | | |
1281 | UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |
1282 | DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |
1283 | RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C |
1284 | LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |
1285 | HOME | 0x05 | ESC [ H | ESC h | ESC [ H |
1286 | END | 0x06 | ESC [ F | ESC k | ESC [ K |
1287 | INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |
1288 | | | ESC [ L | | ESC [ L |
1289 | DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |
1290 | PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |
1291 | | | | | ESC [ ? |
1292 | PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
1293 | | | | | ESC [ / |
1294 | F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |
1295 | F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |
1296 | F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |
1297 | F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |
1298 | F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |
1299 | F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |
1300 | F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |
1301 | F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |
1302 | F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |
1303 | F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |
1304 | Escape | 0x17 | ESC | ESC | ESC |
1305 | F11 | 0x15 | | ESC ! | |
1306 | F12 | 0x16 | | ESC @ | |
1307 +=========+======+===========+==========+==========+
1308
1309 Putty function key map:
1310 +=========+======+===========+=============+=============+=============+=========+
1311 | | EFI | | | | | |
1312 | | Scan | | | Normal | | |
1313 | KEY | Code | VT100+ | Xterm R6 | VT400 | Linux | SCO |
1314 +=========+======+===========+=============+=============+=============+=========+
1315 | F1 | 0x0B | ESC O P | ESC O P | ESC [ 1 1 ~ | ESC [ [ A | ESC [ M |
1316 | F2 | 0x0C | ESC O Q | ESC O Q | ESC [ 1 2 ~ | ESC [ [ B | ESC [ N |
1317 | F3 | 0x0D | ESC O R | ESC O R | ESC [ 1 3 ~ | ESC [ [ C | ESC [ O |
1318 | F4 | 0x0E | ESC O S | ESC O S | ESC [ 1 4 ~ | ESC [ [ D | ESC [ P |
1319 | F5 | 0x0F | ESC O T | ESC [ 1 5 ~ | ESC [ 1 5 ~ | ESC [ [ E | ESC [ Q |
1320 | F6 | 0x10 | ESC O U | ESC [ 1 7 ~ | ESC [ 1 7 ~ | ESC [ 1 7 ~ | ESC [ R |
1321 | F7 | 0x11 | ESC O V | ESC [ 1 8 ~ | ESC [ 1 8 ~ | ESC [ 1 8 ~ | ESC [ S |
1322 | F8 | 0x12 | ESC O W | ESC [ 1 9 ~ | ESC [ 1 9 ~ | ESC [ 1 9 ~ | ESC [ T |
1323 | F9 | 0x13 | ESC O X | ESC [ 2 0 ~ | ESC [ 2 0 ~ | ESC [ 2 0 ~ | ESC [ U |
1324 | F10 | 0x14 | ESC O Y | ESC [ 2 1 ~ | ESC [ 2 1 ~ | ESC [ 2 1 ~ | ESC [ V |
1325 | Escape | 0x17 | ESC | ESC | ESC | ESC | ESC |
1326 | F11 | 0x15 | ESC O Z | ESC [ 2 3 ~ | ESC [ 2 3 ~ | ESC [ 2 3 ~ | ESC [ W |
1327 | F12 | 0x16 | ESC O [ | ESC [ 2 4 ~ | ESC [ 2 4 ~ | ESC [ 2 4 ~ | ESC [ X |
1328 +=========+======+===========+=============+=============+=============+=========+
1329
1330 Special Mappings
1331 ================
1332 ESC R ESC r ESC R = Reset System
1333
1334 @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
1335
1336 **/
1337 VOID
1338 UnicodeToEfiKey (
1339 IN TERMINAL_DEV *TerminalDevice
1340 )
1341 {
1342 EFI_STATUS Status;
1343 EFI_STATUS TimerStatus;
1344 UINT16 UnicodeChar;
1345 EFI_INPUT_KEY Key;
1346 BOOLEAN SetDefaultResetState;
1347
1348 TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
1349
1350 if (!EFI_ERROR (TimerStatus)) {
1351 UnicodeToEfiKeyFlushState (TerminalDevice);
1352 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1353 }
1354
1355 while (!IsUnicodeFiFoEmpty (TerminalDevice) && !IsEfiKeyFiFoFull (TerminalDevice)) {
1356 if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
1357 //
1358 // Check to see if the 2 seconds timer has expired
1359 //
1360 TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
1361 if (!EFI_ERROR (TimerStatus)) {
1362 UnicodeToEfiKeyFlushState (TerminalDevice);
1363 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1364 }
1365 }
1366
1367 //
1368 // Fetch one Unicode character from the Unicode FIFO
1369 //
1370 UnicodeFiFoRemoveOneKey (TerminalDevice, &UnicodeChar);
1371
1372 SetDefaultResetState = TRUE;
1373
1374 switch (TerminalDevice->InputState) {
1375 case INPUT_STATE_DEFAULT:
1376
1377 break;
1378
1379 case INPUT_STATE_ESC:
1380
1381 if (UnicodeChar == LEFTOPENBRACKET) {
1382 TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET;
1383 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1384 continue;
1385 }
1386
1387 if ((UnicodeChar == 'O') && ((TerminalDevice->TerminalType == TerminalTypeVt100) ||
1388 (TerminalDevice->TerminalType == TerminalTypeTtyTerm) ||
1389 (TerminalDevice->TerminalType == TerminalTypeXtermR6) ||
1390 (TerminalDevice->TerminalType == TerminalTypeVt100Plus)))
1391 {
1392 TerminalDevice->InputState |= INPUT_STATE_O;
1393 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1394 continue;
1395 }
1396
1397 Key.ScanCode = SCAN_NULL;
1398
1399 if ((TerminalDevice->TerminalType == TerminalTypeVt100Plus) ||
1400 (TerminalDevice->TerminalType == TerminalTypeVtUtf8))
1401 {
1402 switch (UnicodeChar) {
1403 case '1':
1404 Key.ScanCode = SCAN_F1;
1405 break;
1406 case '2':
1407 Key.ScanCode = SCAN_F2;
1408 break;
1409 case '3':
1410 Key.ScanCode = SCAN_F3;
1411 break;
1412 case '4':
1413 Key.ScanCode = SCAN_F4;
1414 break;
1415 case '5':
1416 Key.ScanCode = SCAN_F5;
1417 break;
1418 case '6':
1419 Key.ScanCode = SCAN_F6;
1420 break;
1421 case '7':
1422 Key.ScanCode = SCAN_F7;
1423 break;
1424 case '8':
1425 Key.ScanCode = SCAN_F8;
1426 break;
1427 case '9':
1428 Key.ScanCode = SCAN_F9;
1429 break;
1430 case '0':
1431 Key.ScanCode = SCAN_F10;
1432 break;
1433 case '!':
1434 Key.ScanCode = SCAN_F11;
1435 break;
1436 case '@':
1437 Key.ScanCode = SCAN_F12;
1438 break;
1439 case 'h':
1440 Key.ScanCode = SCAN_HOME;
1441 break;
1442 case 'k':
1443 Key.ScanCode = SCAN_END;
1444 break;
1445 case '+':
1446 Key.ScanCode = SCAN_INSERT;
1447 break;
1448 case '-':
1449 Key.ScanCode = SCAN_DELETE;
1450 break;
1451 case '/':
1452 Key.ScanCode = SCAN_PAGE_DOWN;
1453 break;
1454 case '?':
1455 Key.ScanCode = SCAN_PAGE_UP;
1456 break;
1457 default:
1458 break;
1459 }
1460 }
1461
1462 switch (UnicodeChar) {
1463 case 'R':
1464 if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) {
1465 TerminalDevice->ResetState = RESET_STATE_ESC_R;
1466 SetDefaultResetState = FALSE;
1467 } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_R) {
1468 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
1469 }
1470
1471 Key.ScanCode = SCAN_NULL;
1472 break;
1473 case 'r':
1474 if (TerminalDevice->ResetState == RESET_STATE_ESC_R) {
1475 TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_R;
1476 SetDefaultResetState = FALSE;
1477 }
1478
1479 Key.ScanCode = SCAN_NULL;
1480 break;
1481 default:
1482 break;
1483 }
1484
1485 if (SetDefaultResetState) {
1486 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1487 }
1488
1489 if (Key.ScanCode != SCAN_NULL) {
1490 Key.UnicodeChar = 0;
1491 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1492 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1493 UnicodeToEfiKeyFlushState (TerminalDevice);
1494 continue;
1495 }
1496
1497 UnicodeToEfiKeyFlushState (TerminalDevice);
1498
1499 break;
1500
1501 case INPUT_STATE_ESC | INPUT_STATE_O:
1502
1503 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1504
1505 Key.ScanCode = SCAN_NULL;
1506
1507 if (TerminalDevice->TerminalType == TerminalTypeVt100) {
1508 switch (UnicodeChar) {
1509 case 'P':
1510 Key.ScanCode = SCAN_F1;
1511 break;
1512 case 'Q':
1513 Key.ScanCode = SCAN_F2;
1514 break;
1515 case 'w':
1516 Key.ScanCode = SCAN_F3;
1517 break;
1518 case 'x':
1519 Key.ScanCode = SCAN_F4;
1520 break;
1521 case 't':
1522 Key.ScanCode = SCAN_F5;
1523 break;
1524 case 'u':
1525 Key.ScanCode = SCAN_F6;
1526 break;
1527 case 'q':
1528 Key.ScanCode = SCAN_F7;
1529 break;
1530 case 'r':
1531 Key.ScanCode = SCAN_F8;
1532 break;
1533 case 'p':
1534 Key.ScanCode = SCAN_F9;
1535 break;
1536 case 'M':
1537 Key.ScanCode = SCAN_F10;
1538 break;
1539 default:
1540 break;
1541 }
1542 } else if (TerminalDevice->TerminalType == TerminalTypeTtyTerm) {
1543 /* Also accept VT100 escape codes for F1-F4, HOME and END for TTY term */
1544 switch (UnicodeChar) {
1545 case 'P':
1546 Key.ScanCode = SCAN_F1;
1547 break;
1548 case 'Q':
1549 Key.ScanCode = SCAN_F2;
1550 break;
1551 case 'R':
1552 Key.ScanCode = SCAN_F3;
1553 break;
1554 case 'S':
1555 Key.ScanCode = SCAN_F4;
1556 break;
1557 case 'H':
1558 Key.ScanCode = SCAN_HOME;
1559 break;
1560 case 'F':
1561 Key.ScanCode = SCAN_END;
1562 break;
1563 }
1564 } else if (TerminalDevice->TerminalType == TerminalTypeVt100Plus) {
1565 switch (UnicodeChar) {
1566 case 'P':
1567 Key.ScanCode = SCAN_F1;
1568 break;
1569 case 'Q':
1570 Key.ScanCode = SCAN_F2;
1571 break;
1572 case 'R':
1573 Key.ScanCode = SCAN_F3;
1574 break;
1575 case 'S':
1576 Key.ScanCode = SCAN_F4;
1577 break;
1578 case 'T':
1579 Key.ScanCode = SCAN_F5;
1580 break;
1581 case 'U':
1582 Key.ScanCode = SCAN_F6;
1583 break;
1584 case 'V':
1585 Key.ScanCode = SCAN_F7;
1586 break;
1587 case 'W':
1588 Key.ScanCode = SCAN_F8;
1589 break;
1590 case 'X':
1591 Key.ScanCode = SCAN_F9;
1592 break;
1593 case 'Y':
1594 Key.ScanCode = SCAN_F10;
1595 break;
1596 case 'Z':
1597 Key.ScanCode = SCAN_F11;
1598 break;
1599 case '[':
1600 Key.ScanCode = SCAN_F12;
1601 break;
1602 }
1603 } else if (TerminalDevice->TerminalType == TerminalTypeXtermR6) {
1604 switch (UnicodeChar) {
1605 case 'P':
1606 Key.ScanCode = SCAN_F1;
1607 break;
1608 case 'Q':
1609 Key.ScanCode = SCAN_F2;
1610 break;
1611 case 'R':
1612 Key.ScanCode = SCAN_F3;
1613 break;
1614 case 'S':
1615 Key.ScanCode = SCAN_F4;
1616 break;
1617 }
1618 }
1619
1620 if (Key.ScanCode != SCAN_NULL) {
1621 Key.UnicodeChar = 0;
1622 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1623 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1624 UnicodeToEfiKeyFlushState (TerminalDevice);
1625 continue;
1626 }
1627
1628 UnicodeToEfiKeyFlushState (TerminalDevice);
1629
1630 break;
1631
1632 case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET:
1633
1634 if ((UnicodeChar == '1') && ((TerminalDevice->TerminalType == TerminalTypeXtermR6) ||
1635 (TerminalDevice->TerminalType == TerminalTypeVt400) ||
1636 (TerminalDevice->TerminalType == TerminalTypeLinux)))
1637 {
1638 TerminalDevice->InputState |= INPUT_STATE_1;
1639 continue;
1640 }
1641
1642 if ((UnicodeChar == '2') && ((TerminalDevice->TerminalType == TerminalTypeXtermR6) ||
1643 (TerminalDevice->TerminalType == TerminalTypeVt400) ||
1644 (TerminalDevice->TerminalType == TerminalTypeLinux)))
1645 {
1646 TerminalDevice->InputState |= INPUT_STATE_2;
1647 continue;
1648 }
1649
1650 if ((UnicodeChar == LEFTOPENBRACKET) && (TerminalDevice->TerminalType == TerminalTypeLinux)) {
1651 TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET_2ND;
1652 continue;
1653 }
1654
1655 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1656
1657 Key.ScanCode = SCAN_NULL;
1658
1659 if ((TerminalDevice->TerminalType == TerminalTypePcAnsi) ||
1660 (TerminalDevice->TerminalType == TerminalTypeVt100) ||
1661 (TerminalDevice->TerminalType == TerminalTypeVt100Plus) ||
1662 (TerminalDevice->TerminalType == TerminalTypeVtUtf8) ||
1663 (TerminalDevice->TerminalType == TerminalTypeTtyTerm) ||
1664 (TerminalDevice->TerminalType == TerminalTypeLinux) ||
1665 (TerminalDevice->TerminalType == TerminalTypeXtermR6) ||
1666 (TerminalDevice->TerminalType == TerminalTypeVt400) ||
1667 (TerminalDevice->TerminalType == TerminalTypeSCO))
1668 {
1669 switch (UnicodeChar) {
1670 case 'A':
1671 Key.ScanCode = SCAN_UP;
1672 break;
1673 case 'B':
1674 Key.ScanCode = SCAN_DOWN;
1675 break;
1676 case 'C':
1677 Key.ScanCode = SCAN_RIGHT;
1678 break;
1679 case 'D':
1680 Key.ScanCode = SCAN_LEFT;
1681 break;
1682 case 'H':
1683 if ((TerminalDevice->TerminalType == TerminalTypePcAnsi) ||
1684 (TerminalDevice->TerminalType == TerminalTypeVt100) ||
1685 (TerminalDevice->TerminalType == TerminalTypeTtyTerm))
1686 {
1687 Key.ScanCode = SCAN_HOME;
1688 }
1689
1690 break;
1691 case 'F':
1692 if ((TerminalDevice->TerminalType == TerminalTypePcAnsi) ||
1693 (TerminalDevice->TerminalType == TerminalTypeTtyTerm))
1694 {
1695 Key.ScanCode = SCAN_END;
1696 }
1697
1698 break;
1699 case 'K':
1700 if (TerminalDevice->TerminalType == TerminalTypeVt100) {
1701 Key.ScanCode = SCAN_END;
1702 }
1703
1704 break;
1705 case 'L':
1706 case '@':
1707 if ((TerminalDevice->TerminalType == TerminalTypePcAnsi) ||
1708 (TerminalDevice->TerminalType == TerminalTypeVt100))
1709 {
1710 Key.ScanCode = SCAN_INSERT;
1711 }
1712
1713 break;
1714 case 'X':
1715 if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {
1716 Key.ScanCode = SCAN_DELETE;
1717 } else if (TerminalDevice->TerminalType == TerminalTypeSCO) {
1718 Key.ScanCode = SCAN_F12;
1719 }
1720
1721 break;
1722 case 'P':
1723 if (TerminalDevice->TerminalType == TerminalTypeVt100) {
1724 Key.ScanCode = SCAN_DELETE;
1725 } else if ((TerminalDevice->TerminalType == TerminalTypePcAnsi) ||
1726 (TerminalDevice->TerminalType == TerminalTypeSCO))
1727 {
1728 Key.ScanCode = SCAN_F4;
1729 }
1730
1731 break;
1732 case 'I':
1733 if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {
1734 Key.ScanCode = SCAN_PAGE_UP;
1735 }
1736
1737 break;
1738 case 'V':
1739 if ((TerminalDevice->TerminalType == TerminalTypePcAnsi) ||
1740 (TerminalDevice->TerminalType == TerminalTypeSCO))
1741 {
1742 Key.ScanCode = SCAN_F10;
1743 }
1744
1745 break;
1746 case '?':
1747 if (TerminalDevice->TerminalType == TerminalTypeVt100) {
1748 Key.ScanCode = SCAN_PAGE_UP;
1749 }
1750
1751 break;
1752 case 'G':
1753 if (TerminalDevice->TerminalType == TerminalTypePcAnsi) {
1754 Key.ScanCode = SCAN_PAGE_DOWN;
1755 }
1756
1757 break;
1758 case 'U':
1759 if ((TerminalDevice->TerminalType == TerminalTypePcAnsi) ||
1760 (TerminalDevice->TerminalType == TerminalTypeSCO))
1761 {
1762 Key.ScanCode = SCAN_F9;
1763 }
1764
1765 break;
1766 case '/':
1767 if (TerminalDevice->TerminalType == TerminalTypeVt100) {
1768 Key.ScanCode = SCAN_PAGE_DOWN;
1769 }
1770
1771 break;
1772 case 'M':
1773 if ((TerminalDevice->TerminalType == TerminalTypePcAnsi) ||
1774 (TerminalDevice->TerminalType == TerminalTypeSCO))
1775 {
1776 Key.ScanCode = SCAN_F1;
1777 }
1778
1779 break;
1780 case 'N':
1781 if ((TerminalDevice->TerminalType == TerminalTypePcAnsi) ||
1782 (TerminalDevice->TerminalType == TerminalTypeSCO))
1783 {
1784 Key.ScanCode = SCAN_F2;
1785 }
1786
1787 break;
1788 case 'O':
1789 if ((TerminalDevice->TerminalType == TerminalTypePcAnsi) ||
1790 (TerminalDevice->TerminalType == TerminalTypeSCO))
1791 {
1792 Key.ScanCode = SCAN_F3;
1793 }
1794
1795 break;
1796 case 'Q':
1797 if ((TerminalDevice->TerminalType == TerminalTypePcAnsi) ||
1798 (TerminalDevice->TerminalType == TerminalTypeSCO))
1799 {
1800 Key.ScanCode = SCAN_F5;
1801 }
1802
1803 break;
1804 case 'R':
1805 if ((TerminalDevice->TerminalType == TerminalTypePcAnsi) ||
1806 (TerminalDevice->TerminalType == TerminalTypeSCO))
1807 {
1808 Key.ScanCode = SCAN_F6;
1809 }
1810
1811 break;
1812 case 'S':
1813 if ((TerminalDevice->TerminalType == TerminalTypePcAnsi) ||
1814 (TerminalDevice->TerminalType == TerminalTypeSCO))
1815 {
1816 Key.ScanCode = SCAN_F7;
1817 }
1818
1819 break;
1820 case 'T':
1821 if ((TerminalDevice->TerminalType == TerminalTypePcAnsi) ||
1822 (TerminalDevice->TerminalType == TerminalTypeSCO))
1823 {
1824 Key.ScanCode = SCAN_F8;
1825 }
1826
1827 break;
1828 case 'W':
1829 if (TerminalDevice->TerminalType == TerminalTypeSCO) {
1830 Key.ScanCode = SCAN_F11;
1831 }
1832
1833 break;
1834 default:
1835 break;
1836 }
1837 }
1838
1839 /*
1840 * The VT220 escape codes that the TTY terminal accepts all have
1841 * numeric codes, and there are no ambiguous prefixes shared with
1842 * other terminal types.
1843 */
1844 if ((TerminalDevice->TerminalType == TerminalTypeTtyTerm) &&
1845 (Key.ScanCode == SCAN_NULL) &&
1846 (UnicodeChar >= '0') &&
1847 (UnicodeChar <= '9'))
1848 {
1849 TerminalDevice->TtyEscapeStr[0] = UnicodeChar;
1850 TerminalDevice->TtyEscapeIndex = 1;
1851 TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET_TTY;
1852 continue;
1853 }
1854
1855 if (Key.ScanCode != SCAN_NULL) {
1856 Key.UnicodeChar = 0;
1857 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1858 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1859 UnicodeToEfiKeyFlushState (TerminalDevice);
1860 continue;
1861 }
1862
1863 UnicodeToEfiKeyFlushState (TerminalDevice);
1864
1865 break;
1866
1867 case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_1:
1868
1869 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1870
1871 Key.ScanCode = SCAN_NULL;
1872
1873 if ((TerminalDevice->TerminalType == TerminalTypeXtermR6) ||
1874 (TerminalDevice->TerminalType == TerminalTypeVt400) ||
1875 (TerminalDevice->TerminalType == TerminalTypeLinux))
1876 {
1877 switch (UnicodeChar) {
1878 case '1':
1879 if (TerminalDevice->TerminalType == TerminalTypeVt400) {
1880 Key.ScanCode = SCAN_F1;
1881 }
1882
1883 break;
1884 case '2':
1885 if (TerminalDevice->TerminalType == TerminalTypeVt400) {
1886 Key.ScanCode = SCAN_F2;
1887 }
1888
1889 break;
1890 case '3':
1891 if (TerminalDevice->TerminalType == TerminalTypeVt400) {
1892 Key.ScanCode = SCAN_F3;
1893 }
1894
1895 break;
1896 case '4':
1897 if (TerminalDevice->TerminalType == TerminalTypeVt400) {
1898 Key.ScanCode = SCAN_F4;
1899 }
1900
1901 break;
1902 case '5':
1903 if ((TerminalDevice->TerminalType == TerminalTypeXtermR6) ||
1904 (TerminalDevice->TerminalType == TerminalTypeVt400))
1905 {
1906 Key.ScanCode = SCAN_F5;
1907 }
1908
1909 break;
1910 case '7':
1911 Key.ScanCode = SCAN_F6;
1912 break;
1913 case '8':
1914 Key.ScanCode = SCAN_F7;
1915 break;
1916 case '9':
1917 Key.ScanCode = SCAN_F8;
1918 break;
1919 }
1920 }
1921
1922 if (Key.ScanCode != SCAN_NULL) {
1923 Key.UnicodeChar = 0;
1924 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1925 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1926 UnicodeToEfiKeyFlushState (TerminalDevice);
1927 continue;
1928 }
1929
1930 UnicodeToEfiKeyFlushState (TerminalDevice);
1931
1932 break;
1933
1934 case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_2:
1935
1936 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1937 Key.ScanCode = SCAN_NULL;
1938 if ((TerminalDevice->TerminalType == TerminalTypeXtermR6) ||
1939 (TerminalDevice->TerminalType == TerminalTypeVt400) ||
1940 (TerminalDevice->TerminalType == TerminalTypeLinux))
1941 {
1942 switch (UnicodeChar) {
1943 case '0':
1944 Key.ScanCode = SCAN_F9;
1945 break;
1946 case '1':
1947 Key.ScanCode = SCAN_F10;
1948 break;
1949 case '3':
1950 Key.ScanCode = SCAN_F11;
1951 break;
1952 case '4':
1953 Key.ScanCode = SCAN_F12;
1954 break;
1955 }
1956 }
1957
1958 if (Key.ScanCode != SCAN_NULL) {
1959 Key.UnicodeChar = 0;
1960 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1961 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1962 UnicodeToEfiKeyFlushState (TerminalDevice);
1963 continue;
1964 }
1965
1966 UnicodeToEfiKeyFlushState (TerminalDevice);
1967
1968 break;
1969
1970 case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_LEFTOPENBRACKET_2ND:
1971
1972 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1973 Key.ScanCode = SCAN_NULL;
1974
1975 if (TerminalDevice->TerminalType == TerminalTypeLinux) {
1976 switch (UnicodeChar) {
1977 case 'A':
1978 Key.ScanCode = SCAN_F1;
1979 break;
1980 case 'B':
1981 Key.ScanCode = SCAN_F2;
1982 break;
1983 case 'C':
1984 Key.ScanCode = SCAN_F3;
1985 break;
1986 case 'D':
1987 Key.ScanCode = SCAN_F4;
1988 break;
1989 case 'E':
1990 Key.ScanCode = SCAN_F5;
1991 break;
1992 }
1993 }
1994
1995 if (Key.ScanCode != SCAN_NULL) {
1996 Key.UnicodeChar = 0;
1997 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
1998 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1999 UnicodeToEfiKeyFlushState (TerminalDevice);
2000 continue;
2001 }
2002
2003 UnicodeToEfiKeyFlushState (TerminalDevice);
2004
2005 break;
2006
2007 case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_LEFTOPENBRACKET_TTY:
2008 /*
2009 * Here we handle the VT220 escape codes that we accept. This
2010 * state is only used by the TTY terminal type.
2011 */
2012 Key.ScanCode = SCAN_NULL;
2013 if (TerminalDevice->TerminalType == TerminalTypeTtyTerm) {
2014 if ((UnicodeChar == '~') && (TerminalDevice->TtyEscapeIndex <= 2)) {
2015 UINT16 EscCode;
2016 TerminalDevice->TtyEscapeStr[TerminalDevice->TtyEscapeIndex] = 0; /* Terminate string */
2017 EscCode = (UINT16)StrDecimalToUintn (TerminalDevice->TtyEscapeStr);
2018 switch (EscCode) {
2019 case 2:
2020 Key.ScanCode = SCAN_INSERT;
2021 break;
2022 case 3:
2023 Key.ScanCode = SCAN_DELETE;
2024 break;
2025 case 5:
2026 Key.ScanCode = SCAN_PAGE_UP;
2027 break;
2028 case 6:
2029 Key.ScanCode = SCAN_PAGE_DOWN;
2030 break;
2031 case 11:
2032 case 12:
2033 case 13:
2034 case 14:
2035 case 15:
2036 Key.ScanCode = SCAN_F1 + EscCode - 11;
2037 break;
2038 case 17:
2039 case 18:
2040 case 19:
2041 case 20:
2042 case 21:
2043 Key.ScanCode = SCAN_F6 + EscCode - 17;
2044 break;
2045 case 23:
2046 case 24:
2047 Key.ScanCode = SCAN_F11 + EscCode - 23;
2048 break;
2049 default:
2050 break;
2051 }
2052 } else if (TerminalDevice->TtyEscapeIndex == 1) {
2053 /* 2 character escape code */
2054 TerminalDevice->TtyEscapeStr[TerminalDevice->TtyEscapeIndex++] = UnicodeChar;
2055 continue;
2056 } else {
2057 DEBUG ((DEBUG_ERROR, "Unexpected state in escape2\n"));
2058 }
2059 }
2060
2061 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
2062
2063 if (Key.ScanCode != SCAN_NULL) {
2064 Key.UnicodeChar = 0;
2065 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
2066 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
2067 UnicodeToEfiKeyFlushState (TerminalDevice);
2068 continue;
2069 }
2070
2071 UnicodeToEfiKeyFlushState (TerminalDevice);
2072 break;
2073
2074 default:
2075 //
2076 // Invalid state. This should never happen.
2077 //
2078 ASSERT (FALSE);
2079
2080 UnicodeToEfiKeyFlushState (TerminalDevice);
2081
2082 break;
2083 }
2084
2085 if (UnicodeChar == ESC) {
2086 TerminalDevice->InputState = INPUT_STATE_ESC;
2087 }
2088
2089 if (UnicodeChar == CSI) {
2090 TerminalDevice->InputState = INPUT_STATE_CSI;
2091 }
2092
2093 if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
2094 Status = gBS->SetTimer (
2095 TerminalDevice->TwoSecondTimeOut,
2096 TimerRelative,
2097 (UINT64)20000000
2098 );
2099 ASSERT_EFI_ERROR (Status);
2100 continue;
2101 }
2102
2103 if (SetDefaultResetState) {
2104 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
2105 }
2106
2107 if (UnicodeChar == DEL) {
2108 if (TerminalDevice->TerminalType == TerminalTypeTtyTerm) {
2109 Key.ScanCode = SCAN_NULL;
2110 Key.UnicodeChar = CHAR_BACKSPACE;
2111 } else {
2112 Key.ScanCode = SCAN_DELETE;
2113 Key.UnicodeChar = 0;
2114 }
2115 } else {
2116 Key.ScanCode = SCAN_NULL;
2117 Key.UnicodeChar = UnicodeChar;
2118 }
2119
2120 EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
2121 }
2122 }