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