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