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