]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/Console/Terminal/Dxe/TerminalConIn.c
Partially make EdkModulePkg pass intel IPF compiler with /W4 /WX switched on.
[mirror_edk2.git] / EdkModulePkg / Universal / Console / Terminal / Dxe / TerminalConIn.c
1 /*++
2
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 TerminalConIn.c
15
16 Abstract:
17
18
19 Revision History
20 --*/
21
22 #include "Terminal.h"
23
24 EFI_STATUS
25 EFIAPI
26 TerminalConInReset (
27 IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This,
28 IN BOOLEAN ExtendedVerification
29 )
30 /*++
31 Routine Description:
32
33 Implements EFI_SIMPLE_TEXT_IN_PROTOCOL.Reset().
34 This driver only perform dependent serial device reset regardless of
35 the value of ExtendeVerification
36
37 Arguments:
38
39 This - Indicates the calling context.
40
41 ExtendedVerification - Skip by this driver.
42
43 Returns:
44
45 EFI_SUCCESS
46 The reset operation succeeds.
47
48 EFI_DEVICE_ERROR
49 The dependent serial port reset fails.
50
51 --*/
52 {
53 EFI_STATUS Status;
54 TERMINAL_DEV *TerminalDevice;
55
56 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);
57
58 //
59 // Report progress code here
60 //
61 Status = REPORT_STATUS_CODE_WITH_DEVICE_PATH (
62 EFI_PROGRESS_CODE,
63 EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_RESET,
64 TerminalDevice->DevicePath
65 );
66
67 Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo);
68
69 //
70 // clear all the internal buffer for keys
71 //
72 InitializeRawFiFo (TerminalDevice);
73 InitializeUnicodeFiFo (TerminalDevice);
74 InitializeEfiKeyFiFo (TerminalDevice);
75
76 if (EFI_ERROR (Status)) {
77 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
78 EFI_ERROR_CODE | EFI_ERROR_MINOR,
79 EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,
80 TerminalDevice->DevicePath
81 );
82 }
83
84 return Status;
85 }
86
87 EFI_STATUS
88 EFIAPI
89 TerminalConInReadKeyStroke (
90 IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This,
91 OUT EFI_INPUT_KEY *Key
92 )
93 /*++
94 Routine Description:
95
96 Implements EFI_SIMPLE_TEXT_IN_PROTOCOL.ReadKeyStroke().
97
98 Arguments:
99
100 This - Indicates the calling context.
101
102 Key - A pointer to a buffer that is filled in with the keystroke
103 information for the key that was sent from terminal.
104
105 Returns:
106
107 EFI_SUCCESS
108 The keystroke information is returned successfully.
109
110 EFI_NOT_READY
111 There is no keystroke data available.
112
113 EFI_DEVICE_ERROR
114 The dependent serial device encounters error.
115
116 --*/
117 {
118 TERMINAL_DEV *TerminalDevice;
119 EFI_STATUS Status;
120
121 //
122 // Initialize *Key to nonsense value.
123 //
124 Key->ScanCode = SCAN_NULL;
125 Key->UnicodeChar = 0;
126 //
127 // get TERMINAL_DEV from "This" parameter.
128 //
129 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);
130
131 Status = TerminalConInCheckForKey (This);
132 if (EFI_ERROR (Status)) {
133 return EFI_NOT_READY;
134 }
135
136 EfiKeyFiFoRemoveOneKey (TerminalDevice, Key);
137
138 return EFI_SUCCESS;
139
140 }
141
142 VOID
143 TranslateRawDataToEfiKey (
144 IN TERMINAL_DEV *TerminalDevice
145 )
146 /*++
147 Step1: Turn raw data into Unicode (according to different encode).
148 Step2: Translate Unicode into key information.
149 (according to different terminal standard).
150 --*/
151 {
152 switch (TerminalDevice->TerminalType) {
153
154 case PcAnsiType:
155 case VT100Type:
156 case VT100PlusType:
157 AnsiRawDataToUnicode (TerminalDevice);
158 UnicodeToEfiKey (TerminalDevice);
159 break;
160
161 case VTUTF8Type:
162 //
163 // Process all the raw data in the RawFIFO,
164 // put the processed key into UnicodeFIFO.
165 //
166 VTUTF8RawDataToUnicode (TerminalDevice);
167
168 //
169 // Translate all the Unicode data in the UnicodeFIFO to Efi key,
170 // then put into EfiKeyFIFO.
171 //
172 UnicodeToEfiKey (TerminalDevice);
173
174 break;
175 }
176 }
177
178 VOID
179 EFIAPI
180 TerminalConInWaitForKey (
181 IN EFI_EVENT Event,
182 IN VOID *Context
183 )
184 /*++
185 Routine Description:
186
187 Event notification function for EFI_SIMPLE_TEXT_IN_PROTOCOL.WaitForKey event
188 Signal the event if there is key available
189
190 Arguments:
191
192 Event - Indicates the event that invoke this function.
193
194 Context - Indicates the calling context.
195
196 Returns:
197
198 N/A
199
200 --*/
201 {
202 //
203 // Someone is waiting on the keystroke event, if there's
204 // a key pending, signal the event
205 //
206 // Context is the pointer to EFI_SIMPLE_TEXT_IN_PROTOCOL
207 //
208 if (!EFI_ERROR (TerminalConInCheckForKey (Context))) {
209
210 gBS->SignalEvent (Event);
211 }
212 }
213
214 EFI_STATUS
215 TerminalConInCheckForKey (
216 IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This
217 )
218 /*++
219 Routine Description:
220
221 Check for a pending key in the Efi Key FIFO or Serial device buffer.
222
223 Arguments:
224
225 This - Indicates the calling context.
226
227 Returns:
228
229 EFI_SUCCESS
230 There is key pending.
231
232 EFI_NOT_READY
233 There is no key pending.
234
235 EFI_DEVICE_ERROR
236
237 --*/
238 {
239 EFI_STATUS Status;
240 TERMINAL_DEV *TerminalDevice;
241 UINT32 Control;
242 UINT8 Input;
243 EFI_SERIAL_IO_MODE *Mode;
244 EFI_SERIAL_IO_PROTOCOL *SerialIo;
245 UINTN SerialInTimeOut;
246
247 TerminalDevice = TERMINAL_CON_IN_DEV_FROM_THIS (This);
248
249 SerialIo = TerminalDevice->SerialIo;
250 if (SerialIo == NULL) {
251 return EFI_DEVICE_ERROR;
252 }
253 //
254 // if current timeout value for serial device is not identical with
255 // the value saved in TERMINAL_DEV structure, then recalculate the
256 // timeout value again and set serial attribute according to this value.
257 //
258 Mode = SerialIo->Mode;
259 if (Mode->Timeout != TerminalDevice->SerialInTimeOut) {
260
261 SerialInTimeOut = 0;
262 if (Mode->BaudRate != 0) {
263 SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;
264 }
265
266 Status = SerialIo->SetAttributes (
267 SerialIo,
268 Mode->BaudRate,
269 Mode->ReceiveFifoDepth,
270 (UINT32) SerialInTimeOut,
271 (EFI_PARITY_TYPE) (Mode->Parity),
272 (UINT8) Mode->DataBits,
273 (EFI_STOP_BITS_TYPE) (Mode->StopBits)
274 );
275
276 if (EFI_ERROR (Status)) {
277 TerminalDevice->SerialInTimeOut = 0;
278 } else {
279 TerminalDevice->SerialInTimeOut = SerialInTimeOut;
280 }
281 }
282 //
283 // check whether serial buffer is empty
284 //
285 Status = SerialIo->GetControl (SerialIo, &Control);
286
287 if (Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) {
288 //
289 // Translate all the raw data in RawFIFO into EFI Key,
290 // according to different terminal type supported.
291 //
292 TranslateRawDataToEfiKey (TerminalDevice);
293
294 //
295 // if there is pre-fetched Efi Key in EfiKeyFIFO buffer,
296 // return directly.
297 //
298 if (!IsEfiKeyFiFoEmpty (TerminalDevice)) {
299 return EFI_SUCCESS;
300 } else {
301 return EFI_NOT_READY;
302 }
303 }
304 //
305 // Fetch all the keys in the serial buffer,
306 // and insert the byte stream into RawFIFO.
307 //
308 do {
309
310 Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input);
311
312 if (EFI_ERROR (Status)) {
313 if (Status == EFI_DEVICE_ERROR) {
314 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
315 EFI_ERROR_CODE | EFI_ERROR_MINOR,
316 EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_INPUT_ERROR,
317 TerminalDevice->DevicePath
318 );
319 }
320 break;
321 }
322
323 RawFiFoInsertOneKey (TerminalDevice, Input);
324 } while (TRUE);
325
326 //
327 // Translate all the raw data in RawFIFO into EFI Key,
328 // according to different terminal type supported.
329 //
330 TranslateRawDataToEfiKey (TerminalDevice);
331
332 if (IsEfiKeyFiFoEmpty (TerminalDevice)) {
333 return EFI_NOT_READY;
334 }
335
336 return EFI_SUCCESS;
337 }
338
339 EFI_STATUS
340 GetOneKeyFromSerial (
341 EFI_SERIAL_IO_PROTOCOL *SerialIo,
342 UINT8 *Input
343 )
344 /*++
345 Get one key out of serial buffer.
346 If serial buffer is empty, return EFI_NOT_READY;
347 if reading serial buffer encounter error, returns EFI_DEVICE_ERROR;
348 if reading serial buffer successfully, put the fetched key to
349 the parameter "Input", and return EFI_SUCCESS.
350 --*/
351 {
352 EFI_STATUS Status;
353 UINTN Size;
354
355 Size = 1;
356 *Input = 0;
357
358 Status = SerialIo->Read (SerialIo, &Size, Input);
359
360 if (EFI_ERROR (Status)) {
361
362 if (Status == EFI_TIMEOUT) {
363 return EFI_NOT_READY;
364 }
365
366 return EFI_DEVICE_ERROR;
367
368 }
369
370 if (*Input == 0) {
371 return EFI_NOT_READY;
372 }
373
374 return EFI_SUCCESS;
375 }
376
377 BOOLEAN
378 RawFiFoInsertOneKey (
379 TERMINAL_DEV *TerminalDevice,
380 UINT8 Input
381 )
382 /*++
383 Insert one byte raw data into the Raw Data FIFO.
384 If FIFO is FULL before data insertion,
385 return FALSE, and the key is lost.
386 --*/
387 {
388 UINT8 Tail;
389
390 Tail = TerminalDevice->RawFiFo.Tail;
391
392 if (IsRawFiFoFull (TerminalDevice)) {
393 //
394 // Raw FIFO is full
395 //
396 return FALSE;
397 }
398
399 TerminalDevice->RawFiFo.Data[Tail] = Input;
400
401 TerminalDevice->RawFiFo.Tail = (UINT8) ((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1));
402
403 return TRUE;
404 }
405
406 BOOLEAN
407 RawFiFoRemoveOneKey (
408 TERMINAL_DEV *TerminalDevice,
409 UINT8 *Output
410 )
411 /*++
412 Remove one byte raw data out of the Raw Data FIFO.
413 If FIFO buffer is empty before remove operation,
414 return FALSE.
415 --*/
416 {
417 UINT8 Head;
418
419 Head = TerminalDevice->RawFiFo.Head;
420
421 if (IsRawFiFoEmpty (TerminalDevice)) {
422 //
423 // FIFO is empty
424 //
425 *Output = 0;
426 return FALSE;
427 }
428
429 *Output = TerminalDevice->RawFiFo.Data[Head];
430
431 TerminalDevice->RawFiFo.Head = (UINT8) ((Head + 1) % (RAW_FIFO_MAX_NUMBER + 1));
432
433 return TRUE;
434 }
435
436 BOOLEAN
437 IsRawFiFoEmpty (
438 TERMINAL_DEV *TerminalDevice
439 )
440 /*++
441 Clarify whether FIFO buffer is empty.
442 --*/
443 {
444 if (TerminalDevice->RawFiFo.Head == TerminalDevice->RawFiFo.Tail) {
445 return TRUE;
446 } else {
447 return FALSE;
448 }
449 }
450
451 BOOLEAN
452 IsRawFiFoFull (
453 TERMINAL_DEV *TerminalDevice
454 )
455 /*++
456 Clarify whether FIFO buffer is full.
457 --*/
458 {
459 UINT8 Tail;
460 UINT8 Head;
461
462 Tail = TerminalDevice->RawFiFo.Tail;
463 Head = TerminalDevice->RawFiFo.Head;
464
465 if (((Tail + 1) % (RAW_FIFO_MAX_NUMBER + 1)) == Head) {
466
467 return TRUE;
468 }
469
470 return FALSE;
471 }
472
473 BOOLEAN
474 EfiKeyFiFoInsertOneKey (
475 TERMINAL_DEV *TerminalDevice,
476 EFI_INPUT_KEY Key
477 )
478 /*++
479 Insert one pre-fetched key into the FIFO buffer.
480 If FIFO buffer is FULL before key insertion,
481 return FALSE, and the key is lost.
482 --*/
483 {
484 UINT8 Tail;
485
486 Tail = TerminalDevice->EfiKeyFiFo.Tail;
487
488 if (IsEfiKeyFiFoFull (TerminalDevice)) {
489 //
490 // Efi Key FIFO is full
491 //
492 return FALSE;
493 }
494
495 TerminalDevice->EfiKeyFiFo.Data[Tail] = Key;
496
497 TerminalDevice->EfiKeyFiFo.Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
498
499 return TRUE;
500 }
501
502 BOOLEAN
503 EfiKeyFiFoRemoveOneKey (
504 TERMINAL_DEV *TerminalDevice,
505 EFI_INPUT_KEY *Output
506 )
507 /*++
508 Remove one pre-fetched key out of the FIFO buffer.
509 If FIFO buffer is empty before remove operation,
510 return FALSE.
511 --*/
512 {
513 UINT8 Head;
514
515 Head = TerminalDevice->EfiKeyFiFo.Head;
516
517 if (IsEfiKeyFiFoEmpty (TerminalDevice)) {
518 //
519 // FIFO is empty
520 //
521 Output->ScanCode = SCAN_NULL;
522 Output->UnicodeChar = 0;
523 return FALSE;
524 }
525
526 *Output = TerminalDevice->EfiKeyFiFo.Data[Head];
527
528 TerminalDevice->EfiKeyFiFo.Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
529
530 return TRUE;
531 }
532
533 BOOLEAN
534 IsEfiKeyFiFoEmpty (
535 TERMINAL_DEV *TerminalDevice
536 )
537 /*++
538 Clarify whether FIFO buffer is empty.
539 --*/
540 {
541 if (TerminalDevice->EfiKeyFiFo.Head == TerminalDevice->EfiKeyFiFo.Tail) {
542 return TRUE;
543 } else {
544 return FALSE;
545 }
546 }
547
548 BOOLEAN
549 IsEfiKeyFiFoFull (
550 TERMINAL_DEV *TerminalDevice
551 )
552 /*++
553 Clarify whether FIFO buffer is full.
554 --*/
555 {
556 UINT8 Tail;
557 UINT8 Head;
558
559 Tail = TerminalDevice->EfiKeyFiFo.Tail;
560 Head = TerminalDevice->EfiKeyFiFo.Head;
561
562 if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
563
564 return TRUE;
565 }
566
567 return FALSE;
568 }
569
570 BOOLEAN
571 UnicodeFiFoInsertOneKey (
572 TERMINAL_DEV *TerminalDevice,
573 UINT16 Input
574 )
575 /*++
576 Insert one pre-fetched key into the FIFO buffer.
577 If FIFO buffer is FULL before key insertion,
578 return FALSE, and the key is lost.
579 --*/
580 {
581 UINT8 Tail;
582
583 Tail = TerminalDevice->UnicodeFiFo.Tail;
584
585 if (IsUnicodeFiFoFull (TerminalDevice)) {
586 //
587 // Unicode FIFO is full
588 //
589 return FALSE;
590 }
591
592 TerminalDevice->UnicodeFiFo.Data[Tail] = Input;
593
594 TerminalDevice->UnicodeFiFo.Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));
595
596 return TRUE;
597 }
598
599 BOOLEAN
600 UnicodeFiFoRemoveOneKey (
601 TERMINAL_DEV *TerminalDevice,
602 UINT16 *Output
603 )
604 /*++
605 Remove one pre-fetched key out of the FIFO buffer.
606 If FIFO buffer is empty before remove operation,
607 return FALSE.
608 --*/
609 {
610 UINT8 Head;
611
612 Head = TerminalDevice->UnicodeFiFo.Head;
613
614 if (IsUnicodeFiFoEmpty (TerminalDevice)) {
615 //
616 // FIFO is empty
617 //
618 Output = NULL;
619 return FALSE;
620 }
621
622 *Output = TerminalDevice->UnicodeFiFo.Data[Head];
623
624 TerminalDevice->UnicodeFiFo.Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));
625
626 return TRUE;
627 }
628
629 BOOLEAN
630 IsUnicodeFiFoEmpty (
631 TERMINAL_DEV *TerminalDevice
632 )
633 /*++
634 Clarify whether FIFO buffer is empty.
635 --*/
636 {
637 if (TerminalDevice->UnicodeFiFo.Head == TerminalDevice->UnicodeFiFo.Tail) {
638 return TRUE;
639 } else {
640 return FALSE;
641 }
642 }
643
644 BOOLEAN
645 IsUnicodeFiFoFull (
646 TERMINAL_DEV *TerminalDevice
647 )
648 /*++
649 Clarify whether FIFO buffer is full.
650 --*/
651 {
652 UINT8 Tail;
653 UINT8 Head;
654
655 Tail = TerminalDevice->UnicodeFiFo.Tail;
656 Head = TerminalDevice->UnicodeFiFo.Head;
657
658 if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
659
660 return TRUE;
661 }
662
663 return FALSE;
664 }
665
666 UINT8
667 UnicodeFiFoGetKeyCount (
668 TERMINAL_DEV *TerminalDevice
669 )
670 {
671 UINT8 Tail;
672 UINT8 Head;
673
674 Tail = TerminalDevice->UnicodeFiFo.Tail;
675 Head = TerminalDevice->UnicodeFiFo.Head;
676
677 if (Tail >= Head) {
678 return (UINT8) (Tail - Head);
679 } else {
680 return (UINT8) (Tail + FIFO_MAX_NUMBER + 1 - Head);
681 }
682 }
683
684 STATIC
685 VOID
686 UnicodeToEfiKeyFlushState (
687 IN TERMINAL_DEV *TerminalDevice
688 )
689 {
690 EFI_INPUT_KEY Key;
691
692 if (TerminalDevice->InputState & INPUT_STATE_ESC) {
693 Key.ScanCode = SCAN_ESC;
694 Key.UnicodeChar = 0;
695 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);
696 }
697
698 if (TerminalDevice->InputState & INPUT_STATE_CSI) {
699 Key.ScanCode = SCAN_NULL;
700 Key.UnicodeChar = CSI;
701 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);
702 }
703
704 if (TerminalDevice->InputState & INPUT_STATE_LEFTOPENBRACKET) {
705 Key.ScanCode = SCAN_NULL;
706 Key.UnicodeChar = LEFTOPENBRACKET;
707 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);
708 }
709
710 if (TerminalDevice->InputState & INPUT_STATE_O) {
711 Key.ScanCode = SCAN_NULL;
712 Key.UnicodeChar = 'O';
713 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);
714 }
715
716 if (TerminalDevice->InputState & INPUT_STATE_2) {
717 Key.ScanCode = SCAN_NULL;
718 Key.UnicodeChar = '2';
719 EfiKeyFiFoInsertOneKey (TerminalDevice, Key);
720 }
721
722 gBS->SetTimer (
723 TerminalDevice->TwoSecondTimeOut,
724 TimerCancel,
725 0
726 );
727
728 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
729 }
730
731 VOID
732 UnicodeToEfiKey (
733 IN TERMINAL_DEV *TerminalDevice
734 )
735 /*++
736 Routine Description:
737
738 Converts a stream of Unicode characters from a terminal input device into EFI Keys that
739 can be read through the Simple Input Protocol. The table below shows the keyboard
740 input mappings that this function supports. If the ESC sequence listed in one of the
741 columns is presented, then it is translated into the coorespoding EFI Scan Code. If a
742 matching sequence is not found, then the raw key strokes are converted into EFI Keys.
743
744 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not
745 completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
746 converted into EFI Keys.
747
748 There is one special input sequence that will force the system to reset.
749 This is ESC R ESC r ESC R.
750
751 Arguments:
752
753 TerminaDevice : The terminal device to use to translate raw input into EFI Keys
754
755 Returns:
756
757 None
758
759 Symbols used in table below
760 ===========================
761 ESC = 0x1B
762 CSI = 0x9B
763 DEL = 0x7f
764 ^ = CTRL
765
766 +=========+======+===========+==========+==========+
767 | | EFI | EFI 1.10 | | |
768 | | Scan | | VT100+ | |
769 | KEY | Code | PC ANSI | VTUTF8 | VT100 |
770 +=========+======+===========+==========+==========+
771 | NULL | 0x00 | | | |
772 | UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |
773 | DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |
774 | RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C |
775 | LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |
776 | HOME | 0x05 | ESC [ H | ESC h | ESC [ H |
777 | END | 0x06 | ESC [ F | ESC k | ESC [ K |
778 | INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |
779 | | | ESC [ L | | ESC [ L |
780 | DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |
781 | PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |
782 | | | | | ESC [ ? |
783 | PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
784 | | | | | ESC [ / |
785 | F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |
786 | F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |
787 | F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |
788 | F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |
789 | F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |
790 | F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |
791 | F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |
792 | F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |
793 | F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |
794 | F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |
795 | Escape | 0x17 | ESC | ESC | ESC |
796 +=========+======+===========+==========+=========+
797
798 Special Mappings
799 ================
800 ESC R ESC r ESC R = Reset System
801
802 --*/
803 {
804 EFI_STATUS Status;
805 EFI_STATUS TimerStatus;
806 UINT16 UnicodeChar;
807 EFI_INPUT_KEY Key;
808 BOOLEAN SetDefaultResetState;
809
810 TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
811
812 if (!EFI_ERROR (TimerStatus)) {
813 UnicodeToEfiKeyFlushState (TerminalDevice);
814 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
815 }
816
817 while (!IsUnicodeFiFoEmpty(TerminalDevice)) {
818
819 if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
820 //
821 // Check to see if the 2 second timer has expired
822 //
823 TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
824 if (!EFI_ERROR (TimerStatus)) {
825 UnicodeToEfiKeyFlushState (TerminalDevice);
826 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
827 }
828 }
829
830 //
831 // Fetch one Unicode character from the Unicode FIFO
832 //
833 UnicodeFiFoRemoveOneKey (TerminalDevice,&UnicodeChar);
834
835 SetDefaultResetState = TRUE;
836
837 switch (TerminalDevice->InputState) {
838 case INPUT_STATE_DEFAULT:
839
840 break;
841
842 case INPUT_STATE_ESC:
843
844 if (UnicodeChar == LEFTOPENBRACKET) {
845 TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET;
846 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
847 continue;
848 }
849
850 if (UnicodeChar == 'O' && TerminalDevice->TerminalType == VT100Type) {
851 TerminalDevice->InputState |= INPUT_STATE_O;
852 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
853 continue;
854 }
855
856 Key.ScanCode = SCAN_NULL;
857
858 if (TerminalDevice->TerminalType == VT100PlusType ||
859 TerminalDevice->TerminalType == VTUTF8Type) {
860 switch (UnicodeChar) {
861 case '1':
862 Key.ScanCode = SCAN_F1;
863 break;
864 case '2':
865 Key.ScanCode = SCAN_F2;
866 break;
867 case '3':
868 Key.ScanCode = SCAN_F3;
869 break;
870 case '4':
871 Key.ScanCode = SCAN_F4;
872 break;
873 case '5':
874 Key.ScanCode = SCAN_F5;
875 break;
876 case '6':
877 Key.ScanCode = SCAN_F6;
878 break;
879 case '7':
880 Key.ScanCode = SCAN_F7;
881 break;
882 case '8':
883 Key.ScanCode = SCAN_F8;
884 break;
885 case '9':
886 Key.ScanCode = SCAN_F9;
887 break;
888 case '0':
889 Key.ScanCode = SCAN_F10;
890 break;
891 case 'h':
892 Key.ScanCode = SCAN_HOME;
893 break;
894 case 'k':
895 Key.ScanCode = SCAN_END;
896 break;
897 case '+':
898 Key.ScanCode = SCAN_INSERT;
899 break;
900 case '-':
901 Key.ScanCode = SCAN_DELETE;
902 break;
903 case '/':
904 Key.ScanCode = SCAN_PAGE_DOWN;
905 break;
906 case '?':
907 Key.ScanCode = SCAN_PAGE_UP;
908 break;
909 default :
910 break;
911 }
912 }
913
914 switch (UnicodeChar) {
915 case 'R':
916 if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) {
917 TerminalDevice->ResetState = RESET_STATE_ESC_R;
918 SetDefaultResetState = FALSE;
919 } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_r) {
920 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
921 }
922 Key.ScanCode = SCAN_NULL;
923 break;
924 case 'r':
925 if (TerminalDevice->ResetState == RESET_STATE_ESC_R) {
926 TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_r;
927 SetDefaultResetState = FALSE;
928 }
929 Key.ScanCode = SCAN_NULL;
930 break;
931 default :
932 break;
933 }
934
935 if (SetDefaultResetState) {
936 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
937 }
938
939 if (Key.ScanCode != SCAN_NULL) {
940 Key.UnicodeChar = 0;
941 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
942 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
943 UnicodeToEfiKeyFlushState (TerminalDevice);
944 continue;
945 }
946
947 UnicodeToEfiKeyFlushState (TerminalDevice);
948
949 break;
950
951 case INPUT_STATE_ESC | INPUT_STATE_O:
952
953 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
954
955 Key.ScanCode = SCAN_NULL;
956
957 if (TerminalDevice->TerminalType == VT100Type) {
958 switch (UnicodeChar) {
959 case 'P':
960 Key.ScanCode = SCAN_F1;
961 break;
962 case 'Q':
963 Key.ScanCode = SCAN_F2;
964 break;
965 case 'w':
966 Key.ScanCode = SCAN_F3;
967 break;
968 case 'x':
969 Key.ScanCode = SCAN_F4;
970 break;
971 case 't':
972 Key.ScanCode = SCAN_F5;
973 break;
974 case 'u':
975 Key.ScanCode = SCAN_F6;
976 break;
977 case 'q':
978 Key.ScanCode = SCAN_F7;
979 break;
980 case 'r':
981 Key.ScanCode = SCAN_F8;
982 break;
983 case 'p':
984 Key.ScanCode = SCAN_F9;
985 break;
986 case 'M':
987 Key.ScanCode = SCAN_F10;
988 break;
989 default :
990 break;
991 }
992 }
993
994 if (Key.ScanCode != SCAN_NULL) {
995 Key.UnicodeChar = 0;
996 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
997 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
998 UnicodeToEfiKeyFlushState (TerminalDevice);
999 continue;
1000 }
1001
1002 UnicodeToEfiKeyFlushState (TerminalDevice);
1003
1004 break;
1005
1006 case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET:
1007
1008 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1009
1010 Key.ScanCode = SCAN_NULL;
1011
1012 if (TerminalDevice->TerminalType == PcAnsiType ||
1013 TerminalDevice->TerminalType == VT100Type ||
1014 TerminalDevice->TerminalType == VT100PlusType ||
1015 TerminalDevice->TerminalType == VTUTF8Type) {
1016 switch (UnicodeChar) {
1017 case 'A':
1018 Key.ScanCode = SCAN_UP;
1019 break;
1020 case 'B':
1021 Key.ScanCode = SCAN_DOWN;
1022 break;
1023 case 'C':
1024 Key.ScanCode = SCAN_RIGHT;
1025 break;
1026 case 'D':
1027 Key.ScanCode = SCAN_LEFT;
1028 break;
1029 case 'H':
1030 if (TerminalDevice->TerminalType == PcAnsiType ||
1031 TerminalDevice->TerminalType == VT100Type) {
1032 Key.ScanCode = SCAN_HOME;
1033 }
1034 break;
1035 case 'F':
1036 if (TerminalDevice->TerminalType == PcAnsiType) {
1037 Key.ScanCode = SCAN_END;
1038 }
1039 break;
1040 case 'K':
1041 if (TerminalDevice->TerminalType == VT100Type) {
1042 Key.ScanCode = SCAN_END;
1043 }
1044 break;
1045 case 'L':
1046 case '@':
1047 if (TerminalDevice->TerminalType == PcAnsiType ||
1048 TerminalDevice->TerminalType == VT100Type) {
1049 Key.ScanCode = SCAN_INSERT;
1050 }
1051 break;
1052 case 'X':
1053 if (TerminalDevice->TerminalType == PcAnsiType) {
1054 Key.ScanCode = SCAN_DELETE;
1055 }
1056 break;
1057 case 'P':
1058 if (TerminalDevice->TerminalType == VT100Type) {
1059 Key.ScanCode = SCAN_DELETE;
1060 } else if (TerminalDevice->TerminalType == PcAnsiType) {
1061 Key.ScanCode = SCAN_F4;
1062 }
1063 break;
1064 case 'I':
1065 if (TerminalDevice->TerminalType == PcAnsiType) {
1066 Key.ScanCode = SCAN_PAGE_UP;
1067 }
1068 break;
1069 case 'V':
1070 if (TerminalDevice->TerminalType == PcAnsiType) {
1071 Key.ScanCode = SCAN_F10;
1072 }
1073 case '?':
1074 if (TerminalDevice->TerminalType == VT100Type) {
1075 Key.ScanCode = SCAN_PAGE_UP;
1076 }
1077 break;
1078 case 'G':
1079 if (TerminalDevice->TerminalType == PcAnsiType) {
1080 Key.ScanCode = SCAN_PAGE_DOWN;
1081 }
1082 break;
1083 case 'U':
1084 if (TerminalDevice->TerminalType == PcAnsiType) {
1085 Key.ScanCode = SCAN_F9;
1086 }
1087 case '/':
1088 if (TerminalDevice->TerminalType == VT100Type) {
1089 Key.ScanCode = SCAN_PAGE_DOWN;
1090 }
1091 break;
1092 case 'M':
1093 if (TerminalDevice->TerminalType == PcAnsiType) {
1094 Key.ScanCode = SCAN_F1;
1095 }
1096 break;
1097 case 'N':
1098 if (TerminalDevice->TerminalType == PcAnsiType) {
1099 Key.ScanCode = SCAN_F2;
1100 }
1101 break;
1102 case 'O':
1103 if (TerminalDevice->TerminalType == PcAnsiType) {
1104 Key.ScanCode = SCAN_F3;
1105 }
1106 break;
1107 case 'Q':
1108 if (TerminalDevice->TerminalType == PcAnsiType) {
1109 Key.ScanCode = SCAN_F5;
1110 }
1111 break;
1112 case 'R':
1113 if (TerminalDevice->TerminalType == PcAnsiType) {
1114 Key.ScanCode = SCAN_F6;
1115 }
1116 break;
1117 case 'S':
1118 if (TerminalDevice->TerminalType == PcAnsiType) {
1119 Key.ScanCode = SCAN_F7;
1120 }
1121 break;
1122 case 'T':
1123 if (TerminalDevice->TerminalType == PcAnsiType) {
1124 Key.ScanCode = SCAN_F8;
1125 }
1126 break;
1127 default :
1128 break;
1129 }
1130 }
1131
1132 if (Key.ScanCode != SCAN_NULL) {
1133 Key.UnicodeChar = 0;
1134 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
1135 TerminalDevice->InputState = INPUT_STATE_DEFAULT;
1136 UnicodeToEfiKeyFlushState (TerminalDevice);
1137 continue;
1138 }
1139
1140 UnicodeToEfiKeyFlushState (TerminalDevice);
1141
1142 break;
1143
1144
1145 default:
1146 //
1147 // Invalid state. This should never happen.
1148 //
1149 ASSERT (FALSE);
1150
1151 UnicodeToEfiKeyFlushState (TerminalDevice);
1152
1153 break;
1154 }
1155
1156 if (UnicodeChar == ESC) {
1157 TerminalDevice->InputState = INPUT_STATE_ESC;
1158 }
1159
1160 if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
1161 Status = gBS->SetTimer(
1162 TerminalDevice->TwoSecondTimeOut,
1163 TimerRelative,
1164 (UINT64)20000000
1165 );
1166 ASSERT_EFI_ERROR (Status);
1167 continue;
1168 }
1169
1170 if (SetDefaultResetState) {
1171 TerminalDevice->ResetState = RESET_STATE_DEFAULT;
1172 }
1173
1174 if (UnicodeChar == DEL) {
1175 Key.ScanCode = SCAN_DELETE;
1176 Key.UnicodeChar = 0;
1177 } else {
1178 Key.ScanCode = SCAN_NULL;
1179 Key.UnicodeChar = UnicodeChar;
1180 }
1181
1182 EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
1183 }
1184 }