]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Isa / Ps2KeyboardDxe / Ps2KbdCtrller.c
1 /** @file
2 Routines that access 8042 keyboard controller
3
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "Ps2Keyboard.h"
10
11 struct {
12 UINT8 ScanCode; ///< follows value defined in Scan Code Set1
13 UINT16 EfiScanCode;
14 CHAR16 UnicodeChar;
15 CHAR16 ShiftUnicodeChar;
16 } ConvertKeyboardScanCodeToEfiKey[] = {
17 {
18 0x01, // Escape
19 SCAN_ESC,
20 0x0000,
21 0x0000
22 },
23 {
24 0x02,
25 SCAN_NULL,
26 L'1',
27 L'!'
28 },
29 {
30 0x03,
31 SCAN_NULL,
32 L'2',
33 L'@'
34 },
35 {
36 0x04,
37 SCAN_NULL,
38 L'3',
39 L'#'
40 },
41 {
42 0x05,
43 SCAN_NULL,
44 L'4',
45 L'$'
46 },
47 {
48 0x06,
49 SCAN_NULL,
50 L'5',
51 L'%'
52 },
53 {
54 0x07,
55 SCAN_NULL,
56 L'6',
57 L'^'
58 },
59 {
60 0x08,
61 SCAN_NULL,
62 L'7',
63 L'&'
64 },
65 {
66 0x09,
67 SCAN_NULL,
68 L'8',
69 L'*'
70 },
71 {
72 0x0A,
73 SCAN_NULL,
74 L'9',
75 L'('
76 },
77 {
78 0x0B,
79 SCAN_NULL,
80 L'0',
81 L')'
82 },
83 {
84 0x0C,
85 SCAN_NULL,
86 L'-',
87 L'_'
88 },
89 {
90 0x0D,
91 SCAN_NULL,
92 L'=',
93 L'+'
94 },
95 {
96 0x0E, // BackSpace
97 SCAN_NULL,
98 0x0008,
99 0x0008
100 },
101 {
102 0x0F, // Tab
103 SCAN_NULL,
104 0x0009,
105 0x0009
106 },
107 {
108 0x10,
109 SCAN_NULL,
110 L'q',
111 L'Q'
112 },
113 {
114 0x11,
115 SCAN_NULL,
116 L'w',
117 L'W'
118 },
119 {
120 0x12,
121 SCAN_NULL,
122 L'e',
123 L'E'
124 },
125 {
126 0x13,
127 SCAN_NULL,
128 L'r',
129 L'R'
130 },
131 {
132 0x14,
133 SCAN_NULL,
134 L't',
135 L'T'
136 },
137 {
138 0x15,
139 SCAN_NULL,
140 L'y',
141 L'Y'
142 },
143 {
144 0x16,
145 SCAN_NULL,
146 L'u',
147 L'U'
148 },
149 {
150 0x17,
151 SCAN_NULL,
152 L'i',
153 L'I'
154 },
155 {
156 0x18,
157 SCAN_NULL,
158 L'o',
159 L'O'
160 },
161 {
162 0x19,
163 SCAN_NULL,
164 L'p',
165 L'P'
166 },
167 {
168 0x1a,
169 SCAN_NULL,
170 L'[',
171 L'{'
172 },
173 {
174 0x1b,
175 SCAN_NULL,
176 L']',
177 L'}'
178 },
179 {
180 0x1c, // Enter
181 SCAN_NULL,
182 0x000d,
183 0x000d
184 },
185 {
186 0x1d,
187 SCAN_NULL,
188 0x0000,
189 0x0000
190 },
191 {
192 0x1e,
193 SCAN_NULL,
194 L'a',
195 L'A'
196 },
197 {
198 0x1f,
199 SCAN_NULL,
200 L's',
201 L'S'
202 },
203 {
204 0x20,
205 SCAN_NULL,
206 L'd',
207 L'D'
208 },
209 {
210 0x21,
211 SCAN_NULL,
212 L'f',
213 L'F'
214 },
215 {
216 0x22,
217 SCAN_NULL,
218 L'g',
219 L'G'
220 },
221 {
222 0x23,
223 SCAN_NULL,
224 L'h',
225 L'H'
226 },
227 {
228 0x24,
229 SCAN_NULL,
230 L'j',
231 L'J'
232 },
233 {
234 0x25,
235 SCAN_NULL,
236 L'k',
237 L'K'
238 },
239 {
240 0x26,
241 SCAN_NULL,
242 L'l',
243 L'L'
244 },
245 {
246 0x27,
247 SCAN_NULL,
248 L';',
249 L':'
250 },
251 {
252 0x28,
253 SCAN_NULL,
254 L'\'',
255 L'"'
256 },
257 {
258 0x29,
259 SCAN_NULL,
260 L'`',
261 L'~'
262 },
263 {
264 0x2a, // Left Shift
265 SCAN_NULL,
266 0x0000,
267 0x0000
268 },
269 {
270 0x2b,
271 SCAN_NULL,
272 L'\\',
273 L'|'
274 },
275 {
276 0x2c,
277 SCAN_NULL,
278 L'z',
279 L'Z'
280 },
281 {
282 0x2d,
283 SCAN_NULL,
284 L'x',
285 L'X'
286 },
287 {
288 0x2e,
289 SCAN_NULL,
290 L'c',
291 L'C'
292 },
293 {
294 0x2f,
295 SCAN_NULL,
296 L'v',
297 L'V'
298 },
299 {
300 0x30,
301 SCAN_NULL,
302 L'b',
303 L'B'
304 },
305 {
306 0x31,
307 SCAN_NULL,
308 L'n',
309 L'N'
310 },
311 {
312 0x32,
313 SCAN_NULL,
314 L'm',
315 L'M'
316 },
317 {
318 0x33,
319 SCAN_NULL,
320 L',',
321 L'<'
322 },
323 {
324 0x34,
325 SCAN_NULL,
326 L'.',
327 L'>'
328 },
329 {
330 0x35,
331 SCAN_NULL,
332 L'/',
333 L'?'
334 },
335 {
336 0x36, // Right Shift
337 SCAN_NULL,
338 0x0000,
339 0x0000
340 },
341 {
342 0x37, // Numeric Keypad *
343 SCAN_NULL,
344 L'*',
345 L'*'
346 },
347 {
348 0x38, // Left Alt/Extended Right Alt
349 SCAN_NULL,
350 0x0000,
351 0x0000
352 },
353 {
354 0x39,
355 SCAN_NULL,
356 L' ',
357 L' '
358 },
359 {
360 0x3A, // CapsLock
361 SCAN_NULL,
362 0x0000,
363 0x0000
364 },
365 {
366 0x3B,
367 SCAN_F1,
368 0x0000,
369 0x0000
370 },
371 {
372 0x3C,
373 SCAN_F2,
374 0x0000,
375 0x0000
376 },
377 {
378 0x3D,
379 SCAN_F3,
380 0x0000,
381 0x0000
382 },
383 {
384 0x3E,
385 SCAN_F4,
386 0x0000,
387 0x0000
388 },
389 {
390 0x3F,
391 SCAN_F5,
392 0x0000,
393 0x0000
394 },
395 {
396 0x40,
397 SCAN_F6,
398 0x0000,
399 0x0000
400 },
401 {
402 0x41,
403 SCAN_F7,
404 0x0000,
405 0x0000
406 },
407 {
408 0x42,
409 SCAN_F8,
410 0x0000,
411 0x0000
412 },
413 {
414 0x43,
415 SCAN_F9,
416 0x0000,
417 0x0000
418 },
419 {
420 0x44,
421 SCAN_F10,
422 0x0000,
423 0x0000
424 },
425 {
426 0x45, // NumLock
427 SCAN_NULL,
428 0x0000,
429 0x0000
430 },
431 {
432 0x46, // ScrollLock
433 SCAN_NULL,
434 0x0000,
435 0x0000
436 },
437 {
438 0x47,
439 SCAN_HOME,
440 L'7',
441 L'7'
442 },
443 {
444 0x48,
445 SCAN_UP,
446 L'8',
447 L'8'
448 },
449 {
450 0x49,
451 SCAN_PAGE_UP,
452 L'9',
453 L'9'
454 },
455 {
456 0x4a,
457 SCAN_NULL,
458 L'-',
459 L'-'
460 },
461 {
462 0x4b,
463 SCAN_LEFT,
464 L'4',
465 L'4'
466 },
467 {
468 0x4c, // Numeric Keypad 5
469 SCAN_NULL,
470 L'5',
471 L'5'
472 },
473 {
474 0x4d,
475 SCAN_RIGHT,
476 L'6',
477 L'6'
478 },
479 {
480 0x4e,
481 SCAN_NULL,
482 L'+',
483 L'+'
484 },
485 {
486 0x4f,
487 SCAN_END,
488 L'1',
489 L'1'
490 },
491 {
492 0x50,
493 SCAN_DOWN,
494 L'2',
495 L'2'
496 },
497 {
498 0x51,
499 SCAN_PAGE_DOWN,
500 L'3',
501 L'3'
502 },
503 {
504 0x52,
505 SCAN_INSERT,
506 L'0',
507 L'0'
508 },
509 {
510 0x53,
511 SCAN_DELETE,
512 L'.',
513 L'.'
514 },
515 {
516 0x57,
517 SCAN_F11,
518 0x0000,
519 0x0000
520 },
521 {
522 0x58,
523 SCAN_F12,
524 0x0000,
525 0x0000
526 },
527 {
528 0x5B, // Left LOGO
529 SCAN_NULL,
530 0x0000,
531 0x0000
532 },
533 {
534 0x5C, // Right LOGO
535 SCAN_NULL,
536 0x0000,
537 0x0000
538 },
539 {
540 0x5D, // Menu key
541 SCAN_NULL,
542 0x0000,
543 0x0000
544 },
545 {
546 TABLE_END,
547 TABLE_END,
548 SCAN_NULL,
549 SCAN_NULL
550 },
551 };
552
553 //
554 // The WaitForValue time out
555 //
556 UINTN mWaitForValueTimeOut = KEYBOARD_WAITFORVALUE_TIMEOUT;
557
558 BOOLEAN mEnableMouseInterface;
559
560 /**
561 Return the count of scancode in the queue.
562
563 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
564
565 @return Count of the scancode.
566 **/
567 UINTN
568 GetScancodeBufCount (
569 IN SCAN_CODE_QUEUE *Queue
570 )
571 {
572 if (Queue->Head <= Queue->Tail) {
573 return Queue->Tail - Queue->Head;
574 } else {
575 return Queue->Tail + KEYBOARD_SCAN_CODE_MAX_COUNT - Queue->Head;
576 }
577 }
578
579 /**
580 Read several bytes from the scancode buffer without removing them.
581 This function is called to see if there are enough bytes of scancode
582 representing a single key.
583
584 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
585 @param Count Number of bytes to be read
586 @param Buf Store the results
587
588 @retval EFI_SUCCESS success to scan the keyboard code
589 @retval EFI_NOT_READY invalid parameter
590 **/
591 EFI_STATUS
592 GetScancodeBufHead (
593 IN SCAN_CODE_QUEUE *Queue,
594 IN UINTN Count,
595 OUT UINT8 *Buf
596 )
597 {
598 UINTN Index;
599 UINTN Pos;
600
601 //
602 // check the valid range of parameter 'Count'
603 //
604 if (GetScancodeBufCount (Queue) < Count) {
605 return EFI_NOT_READY;
606 }
607
608 //
609 // retrieve the values
610 //
611 for (Index = 0, Pos = Queue->Head; Index < Count; Index++, Pos = (Pos + 1) % KEYBOARD_SCAN_CODE_MAX_COUNT) {
612 Buf[Index] = Queue->Buffer[Pos];
613 }
614
615 return EFI_SUCCESS;
616 }
617
618 /**
619
620 Read & remove several bytes from the scancode buffer.
621 This function is usually called after GetScancodeBufHead()
622
623 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
624 @param Count Number of bytes to be read
625 @param Buf Store the results
626
627 @retval EFI_SUCCESS success to scan the keyboard code
628 @retval EFI_NOT_READY invalid parameter
629 **/
630 EFI_STATUS
631 PopScancodeBufHead (
632 IN SCAN_CODE_QUEUE *Queue,
633 IN UINTN Count,
634 OUT UINT8 *Buf OPTIONAL
635 )
636 {
637 UINTN Index;
638
639 //
640 // Check the valid range of parameter 'Count'
641 //
642 if (GetScancodeBufCount (Queue) < Count) {
643 return EFI_NOT_READY;
644 }
645
646 //
647 // Retrieve and remove the values
648 //
649 for (Index = 0; Index < Count; Index++, Queue->Head = (Queue->Head + 1) % KEYBOARD_SCAN_CODE_MAX_COUNT) {
650 if (Buf != NULL) {
651 Buf[Index] = Queue->Buffer[Queue->Head];
652 }
653 }
654
655 return EFI_SUCCESS;
656 }
657
658 /**
659 Push one byte to the scancode buffer.
660
661 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
662 @param Scancode The byte to push.
663 **/
664 VOID
665 PushScancodeBufTail (
666 IN SCAN_CODE_QUEUE *Queue,
667 IN UINT8 Scancode
668 )
669 {
670 if (GetScancodeBufCount (Queue) == KEYBOARD_SCAN_CODE_MAX_COUNT - 1) {
671 PopScancodeBufHead (Queue, 1, NULL);
672 }
673
674 Queue->Buffer[Queue->Tail] = Scancode;
675 Queue->Tail = (Queue->Tail + 1) % KEYBOARD_SCAN_CODE_MAX_COUNT;
676 }
677
678 /**
679 Read data register .
680
681 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
682
683 @return return the value
684
685 **/
686 UINT8
687 KeyReadDataRegister (
688 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
689 )
690
691 {
692 return IoRead8 (ConsoleIn->DataRegisterAddress);
693 }
694
695 /**
696 Write data register.
697
698 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
699 @param Data value wanted to be written
700
701 **/
702 VOID
703 KeyWriteDataRegister (
704 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
705 IN UINT8 Data
706 )
707 {
708 IoWrite8 (ConsoleIn->DataRegisterAddress, Data);
709 }
710
711 /**
712 Read status register.
713
714 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
715
716 @return value in status register
717
718 **/
719 UINT8
720 KeyReadStatusRegister (
721 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
722 )
723 {
724 return IoRead8 (ConsoleIn->StatusRegisterAddress);
725 }
726
727 /**
728 Write command register .
729
730 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
731 @param Data The value wanted to be written
732
733 **/
734 VOID
735 KeyWriteCommandRegister (
736 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
737 IN UINT8 Data
738 )
739 {
740 IoWrite8 (ConsoleIn->CommandRegisterAddress, Data);
741 }
742
743 /**
744 Display error message.
745
746 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
747 @param ErrMsg Unicode string of error message
748
749 **/
750 VOID
751 KeyboardError (
752 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
753 IN CHAR16 *ErrMsg
754 )
755 {
756 ConsoleIn->KeyboardErr = TRUE;
757 }
758
759 /**
760 Timer event handler: read a series of scancodes from 8042
761 and put them into memory scancode buffer.
762 it read as much scancodes to either fill
763 the memory buffer or empty the keyboard buffer.
764 It is registered as running under TPL_NOTIFY
765
766 @param Event The timer event
767 @param Context A KEYBOARD_CONSOLE_IN_DEV pointer
768
769 **/
770 VOID
771 EFIAPI
772 KeyboardTimerHandler (
773 IN EFI_EVENT Event,
774 IN VOID *Context
775 )
776
777 {
778 UINT8 Data;
779 EFI_TPL OldTpl;
780 KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
781
782 ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *)Context;
783
784 //
785 // Enter critical section
786 //
787 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
788
789 if (((KEYBOARD_CONSOLE_IN_DEV *)Context)->KeyboardErr) {
790 //
791 // Leave critical section and return
792 //
793 gBS->RestoreTPL (OldTpl);
794 return;
795 }
796
797 //
798 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
799 // KB is not connected to system. If KB is not connected to system, driver will find there's something
800 // error in the following code and wait for the input buffer empty, this waiting time should be short enough since
801 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
802 // Just skip the 'resend' process simply.
803 //
804
805 while ((KeyReadStatusRegister (ConsoleIn) & (KEYBOARD_STATUS_REGISTER_TRANSMIT_TIMEOUT|KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA)) ==
806 KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
807 )
808 {
809 //
810 // Read one byte of the scan code and store it into the memory buffer
811 //
812 Data = KeyReadDataRegister (ConsoleIn);
813 PushScancodeBufTail (&ConsoleIn->ScancodeQueue, Data);
814 }
815
816 KeyGetchar (ConsoleIn);
817
818 //
819 // Leave critical section and return
820 //
821 gBS->RestoreTPL (OldTpl);
822 }
823
824 /**
825 Read key value .
826
827 @param ConsoleIn - Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
828 @param Data - Pointer to outof buffer for keeping key value
829
830 @retval EFI_TIMEOUT Status register time out
831 @retval EFI_SUCCESS Success to read keyboard
832
833 **/
834 EFI_STATUS
835 KeyboardRead (
836 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
837 OUT UINT8 *Data
838 )
839
840 {
841 UINT32 TimeOut;
842 UINT32 RegFilled;
843
844 TimeOut = 0;
845 RegFilled = 0;
846
847 //
848 // wait till output buffer full then perform the read
849 //
850 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
851 if (KeyReadStatusRegister (ConsoleIn) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA) {
852 RegFilled = 1;
853 *Data = KeyReadDataRegister (ConsoleIn);
854 break;
855 }
856
857 MicroSecondDelay (30);
858 }
859
860 if (RegFilled == 0) {
861 return EFI_TIMEOUT;
862 }
863
864 return EFI_SUCCESS;
865 }
866
867 /**
868 write key to keyboard
869
870 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
871 @param Data value wanted to be written
872
873 @retval EFI_TIMEOUT The input buffer register is full for putting new value util timeout
874 @retval EFI_SUCCESS The new value is success put into input buffer register.
875
876 **/
877 EFI_STATUS
878 KeyboardWrite (
879 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
880 IN UINT8 Data
881 )
882 {
883 UINT32 TimeOut;
884 UINT32 RegEmptied;
885
886 TimeOut = 0;
887 RegEmptied = 0;
888
889 //
890 // wait for input buffer empty
891 //
892 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
893 if ((KeyReadStatusRegister (ConsoleIn) & 0x02) == 0) {
894 RegEmptied = 1;
895 break;
896 }
897
898 MicroSecondDelay (30);
899 }
900
901 if (RegEmptied == 0) {
902 return EFI_TIMEOUT;
903 }
904
905 //
906 // Write it
907 //
908 KeyWriteDataRegister (ConsoleIn, Data);
909
910 return EFI_SUCCESS;
911 }
912
913 /**
914 Issue keyboard command.
915
916 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
917 @param Data The buff holding the command
918
919 @retval EFI_TIMEOUT Keyboard is not ready to issuing
920 @retval EFI_SUCCESS Success to issue keyboard command
921
922 **/
923 EFI_STATUS
924 KeyboardCommand (
925 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
926 IN UINT8 Data
927 )
928 {
929 UINT32 TimeOut;
930 UINT32 RegEmptied;
931
932 TimeOut = 0;
933 RegEmptied = 0;
934
935 //
936 // Wait For Input Buffer Empty
937 //
938 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
939 if ((KeyReadStatusRegister (ConsoleIn) & 0x02) == 0) {
940 RegEmptied = 1;
941 break;
942 }
943
944 MicroSecondDelay (30);
945 }
946
947 if (RegEmptied == 0) {
948 return EFI_TIMEOUT;
949 }
950
951 //
952 // issue the command
953 //
954 KeyWriteCommandRegister (ConsoleIn, Data);
955
956 //
957 // Wait For Input Buffer Empty again
958 //
959 RegEmptied = 0;
960 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
961 if ((KeyReadStatusRegister (ConsoleIn) & 0x02) == 0) {
962 RegEmptied = 1;
963 break;
964 }
965
966 MicroSecondDelay (30);
967 }
968
969 if (RegEmptied == 0) {
970 return EFI_TIMEOUT;
971 }
972
973 return EFI_SUCCESS;
974 }
975
976 /**
977 wait for a specific value to be presented on
978 8042 Data register by keyboard and then read it,
979 used in keyboard commands ack
980
981 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
982 @param Value the value wanted to be waited.
983
984 @retval EFI_TIMEOUT Fail to get specific value in given time
985 @retval EFI_SUCCESS Success to get specific value in given time.
986
987 **/
988 EFI_STATUS
989 KeyboardWaitForValue (
990 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
991 IN UINT8 Value
992 )
993 {
994 UINT8 Data;
995 UINT32 TimeOut;
996 UINT32 SumTimeOut;
997 UINT32 GotIt;
998
999 GotIt = 0;
1000 TimeOut = 0;
1001 SumTimeOut = 0;
1002
1003 //
1004 // Make sure the initial value of 'Data' is different from 'Value'
1005 //
1006 Data = 0;
1007 if (Data == Value) {
1008 Data = 1;
1009 }
1010
1011 //
1012 // Read from 8042 (multiple times if needed)
1013 // until the expected value appears
1014 // use SumTimeOut to control the iteration
1015 //
1016 while (1) {
1017 //
1018 // Perform a read
1019 //
1020 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
1021 if (KeyReadStatusRegister (ConsoleIn) & 0x01) {
1022 Data = KeyReadDataRegister (ConsoleIn);
1023 break;
1024 }
1025
1026 MicroSecondDelay (30);
1027 }
1028
1029 SumTimeOut += TimeOut;
1030
1031 if (Data == Value) {
1032 GotIt = 1;
1033 break;
1034 }
1035
1036 if (SumTimeOut >= mWaitForValueTimeOut) {
1037 break;
1038 }
1039 }
1040
1041 //
1042 // Check results
1043 //
1044 if (GotIt == 1) {
1045 return EFI_SUCCESS;
1046 } else {
1047 return EFI_TIMEOUT;
1048 }
1049 }
1050
1051 /**
1052 Show keyboard status lights according to
1053 indicators in ConsoleIn.
1054
1055 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1056
1057 @return status of updating keyboard register
1058
1059 **/
1060 EFI_STATUS
1061 UpdateStatusLights (
1062 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
1063 )
1064 {
1065 EFI_STATUS Status;
1066 UINT8 Command;
1067
1068 //
1069 // Send keyboard command
1070 //
1071 Status = KeyboardWrite (ConsoleIn, 0xed);
1072 if (EFI_ERROR (Status)) {
1073 return Status;
1074 }
1075
1076 KeyboardWaitForValue (ConsoleIn, 0xfa);
1077
1078 //
1079 // Light configuration
1080 //
1081 Command = 0;
1082 if (ConsoleIn->CapsLock) {
1083 Command |= 4;
1084 }
1085
1086 if (ConsoleIn->NumLock) {
1087 Command |= 2;
1088 }
1089
1090 if (ConsoleIn->ScrollLock) {
1091 Command |= 1;
1092 }
1093
1094 Status = KeyboardWrite (ConsoleIn, Command);
1095
1096 if (EFI_ERROR (Status)) {
1097 return Status;
1098 }
1099
1100 KeyboardWaitForValue (ConsoleIn, 0xfa);
1101 return Status;
1102 }
1103
1104 /**
1105 Initialize the key state.
1106
1107 @param ConsoleIn The KEYBOARD_CONSOLE_IN_DEV instance.
1108 @param KeyState A pointer to receive the key state information.
1109 **/
1110 VOID
1111 InitializeKeyState (
1112 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
1113 OUT EFI_KEY_STATE *KeyState
1114 )
1115 {
1116 KeyState->KeyShiftState = EFI_SHIFT_STATE_VALID
1117 | (ConsoleIn->LeftCtrl ? EFI_LEFT_CONTROL_PRESSED : 0)
1118 | (ConsoleIn->RightCtrl ? EFI_RIGHT_CONTROL_PRESSED : 0)
1119 | (ConsoleIn->LeftAlt ? EFI_LEFT_ALT_PRESSED : 0)
1120 | (ConsoleIn->RightAlt ? EFI_RIGHT_ALT_PRESSED : 0)
1121 | (ConsoleIn->LeftShift ? EFI_LEFT_SHIFT_PRESSED : 0)
1122 | (ConsoleIn->RightShift ? EFI_RIGHT_SHIFT_PRESSED : 0)
1123 | (ConsoleIn->LeftLogo ? EFI_LEFT_LOGO_PRESSED : 0)
1124 | (ConsoleIn->RightLogo ? EFI_RIGHT_LOGO_PRESSED : 0)
1125 | (ConsoleIn->Menu ? EFI_MENU_KEY_PRESSED : 0)
1126 | (ConsoleIn->SysReq ? EFI_SYS_REQ_PRESSED : 0)
1127 ;
1128 KeyState->KeyToggleState = EFI_TOGGLE_STATE_VALID
1129 | (ConsoleIn->CapsLock ? EFI_CAPS_LOCK_ACTIVE : 0)
1130 | (ConsoleIn->NumLock ? EFI_NUM_LOCK_ACTIVE : 0)
1131 | (ConsoleIn->ScrollLock ? EFI_SCROLL_LOCK_ACTIVE : 0)
1132 | (ConsoleIn->IsSupportPartialKey ? EFI_KEY_STATE_EXPOSED : 0)
1133 ;
1134 }
1135
1136 /**
1137 Get scancode from scancode buffer and translate into EFI-scancode and unicode defined by EFI spec.
1138
1139 The function is always called in TPL_NOTIFY.
1140
1141 @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer
1142
1143 **/
1144 VOID
1145 KeyGetchar (
1146 IN OUT KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
1147 )
1148 {
1149 EFI_STATUS Status;
1150 UINT16 ScanCode;
1151 BOOLEAN Extend0;
1152 BOOLEAN Extend1;
1153 UINTN Index;
1154 EFI_KEY_DATA KeyData;
1155 LIST_ENTRY *Link;
1156 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1157 //
1158 // 3 bytes most
1159 //
1160 UINT8 ScancodeArr[3];
1161 UINT32 ScancodeArrPos;
1162
1163 //
1164 // Check if there are enough bytes of scancode representing a single key
1165 // available in the buffer
1166 //
1167 while (TRUE) {
1168 Extend0 = FALSE;
1169 Extend1 = FALSE;
1170 ScancodeArrPos = 0;
1171 Status = GetScancodeBufHead (&ConsoleIn->ScancodeQueue, ScancodeArrPos + 1, ScancodeArr);
1172 if (EFI_ERROR (Status)) {
1173 return;
1174 }
1175
1176 if (ScancodeArr[ScancodeArrPos] == SCANCODE_EXTENDED0) {
1177 //
1178 // E0 to look ahead 2 bytes
1179 //
1180 Extend0 = TRUE;
1181 ScancodeArrPos = 1;
1182 Status = GetScancodeBufHead (&ConsoleIn->ScancodeQueue, ScancodeArrPos + 1, ScancodeArr);
1183 if (EFI_ERROR (Status)) {
1184 return;
1185 }
1186 } else if (ScancodeArr[ScancodeArrPos] == SCANCODE_EXTENDED1) {
1187 //
1188 // E1 to look ahead 3 bytes
1189 //
1190 Extend1 = TRUE;
1191 ScancodeArrPos = 2;
1192 Status = GetScancodeBufHead (&ConsoleIn->ScancodeQueue, ScancodeArrPos + 1, ScancodeArr);
1193 if (EFI_ERROR (Status)) {
1194 return;
1195 }
1196 }
1197
1198 //
1199 // if we reach this position, scancodes for a key is in buffer now,pop them
1200 //
1201 Status = PopScancodeBufHead (&ConsoleIn->ScancodeQueue, ScancodeArrPos + 1, ScancodeArr);
1202 ASSERT_EFI_ERROR (Status);
1203
1204 //
1205 // store the last available byte, this byte of scancode will be checked
1206 //
1207 ScanCode = ScancodeArr[ScancodeArrPos];
1208
1209 if (!Extend1) {
1210 //
1211 // Check for special keys and update the driver state.
1212 //
1213 switch (ScanCode) {
1214 case SCANCODE_CTRL_MAKE:
1215 if (Extend0) {
1216 ConsoleIn->RightCtrl = TRUE;
1217 } else {
1218 ConsoleIn->LeftCtrl = TRUE;
1219 }
1220
1221 break;
1222 case SCANCODE_CTRL_BREAK:
1223 if (Extend0) {
1224 ConsoleIn->RightCtrl = FALSE;
1225 } else {
1226 ConsoleIn->LeftCtrl = FALSE;
1227 }
1228
1229 break;
1230
1231 case SCANCODE_ALT_MAKE:
1232 if (Extend0) {
1233 ConsoleIn->RightAlt = TRUE;
1234 } else {
1235 ConsoleIn->LeftAlt = TRUE;
1236 }
1237
1238 break;
1239 case SCANCODE_ALT_BREAK:
1240 if (Extend0) {
1241 ConsoleIn->RightAlt = FALSE;
1242 } else {
1243 ConsoleIn->LeftAlt = FALSE;
1244 }
1245
1246 break;
1247
1248 case SCANCODE_LEFT_SHIFT_MAKE:
1249 //
1250 // To avoid recognize PRNT_SCRN key as a L_SHIFT key
1251 // because PRNT_SCRN key generates E0 followed by L_SHIFT scan code.
1252 // If it the second byte of the PRNT_ScRN skip it.
1253 //
1254 if (!Extend0) {
1255 ConsoleIn->LeftShift = TRUE;
1256 break;
1257 }
1258
1259 continue;
1260
1261 case SCANCODE_LEFT_SHIFT_BREAK:
1262 if (!Extend0) {
1263 ConsoleIn->LeftShift = FALSE;
1264 }
1265
1266 break;
1267
1268 case SCANCODE_RIGHT_SHIFT_MAKE:
1269 ConsoleIn->RightShift = TRUE;
1270 break;
1271 case SCANCODE_RIGHT_SHIFT_BREAK:
1272 ConsoleIn->RightShift = FALSE;
1273 break;
1274
1275 case SCANCODE_LEFT_LOGO_MAKE:
1276 ConsoleIn->LeftLogo = TRUE;
1277 break;
1278 case SCANCODE_LEFT_LOGO_BREAK:
1279 ConsoleIn->LeftLogo = FALSE;
1280 break;
1281
1282 case SCANCODE_RIGHT_LOGO_MAKE:
1283 ConsoleIn->RightLogo = TRUE;
1284 break;
1285 case SCANCODE_RIGHT_LOGO_BREAK:
1286 ConsoleIn->RightLogo = FALSE;
1287 break;
1288
1289 case SCANCODE_MENU_MAKE:
1290 ConsoleIn->Menu = TRUE;
1291 break;
1292 case SCANCODE_MENU_BREAK:
1293 ConsoleIn->Menu = FALSE;
1294 break;
1295
1296 case SCANCODE_SYS_REQ_MAKE:
1297 if (Extend0) {
1298 ConsoleIn->SysReq = TRUE;
1299 }
1300
1301 break;
1302 case SCANCODE_SYS_REQ_BREAK:
1303 if (Extend0) {
1304 ConsoleIn->SysReq = FALSE;
1305 }
1306
1307 break;
1308
1309 case SCANCODE_SYS_REQ_MAKE_WITH_ALT:
1310 ConsoleIn->SysReq = TRUE;
1311 break;
1312 case SCANCODE_SYS_REQ_BREAK_WITH_ALT:
1313 ConsoleIn->SysReq = FALSE;
1314 break;
1315
1316 case SCANCODE_CAPS_LOCK_MAKE:
1317 ConsoleIn->CapsLock = (BOOLEAN) !ConsoleIn->CapsLock;
1318 UpdateStatusLights (ConsoleIn);
1319 break;
1320 case SCANCODE_NUM_LOCK_MAKE:
1321 ConsoleIn->NumLock = (BOOLEAN) !ConsoleIn->NumLock;
1322 UpdateStatusLights (ConsoleIn);
1323 break;
1324 case SCANCODE_SCROLL_LOCK_MAKE:
1325 if (!Extend0) {
1326 ConsoleIn->ScrollLock = (BOOLEAN) !ConsoleIn->ScrollLock;
1327 UpdateStatusLights (ConsoleIn);
1328 }
1329
1330 break;
1331 }
1332 }
1333
1334 //
1335 // If this is above the valid range, ignore it
1336 //
1337 if (ScanCode >= SCANCODE_MAX_MAKE) {
1338 continue;
1339 } else {
1340 break;
1341 }
1342 }
1343
1344 //
1345 // Handle Ctrl+Alt+Del hotkey
1346 //
1347 if ((ConsoleIn->LeftCtrl || ConsoleIn->RightCtrl) &&
1348 (ConsoleIn->LeftAlt || ConsoleIn->RightAlt) &&
1349 (ScanCode == SCANCODE_DELETE_MAKE)
1350 )
1351 {
1352 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
1353 }
1354
1355 //
1356 // Save the Shift/Toggle state
1357 //
1358 InitializeKeyState (ConsoleIn, &KeyData.KeyState);
1359 KeyData.Key.ScanCode = SCAN_NULL;
1360 KeyData.Key.UnicodeChar = CHAR_NULL;
1361
1362 //
1363 // Key Pad "/" shares the same scancode as that of "/" except Key Pad "/" has E0 prefix
1364 //
1365 if (Extend0 && (ScanCode == 0x35)) {
1366 KeyData.Key.UnicodeChar = L'/';
1367 KeyData.Key.ScanCode = SCAN_NULL;
1368
1369 //
1370 // PAUSE shares the same scancode as that of NUM except PAUSE has E1 prefix
1371 //
1372 } else if (Extend1 && (ScanCode == SCANCODE_NUM_LOCK_MAKE)) {
1373 KeyData.Key.UnicodeChar = CHAR_NULL;
1374 KeyData.Key.ScanCode = SCAN_PAUSE;
1375
1376 //
1377 // PAUSE shares the same scancode as that of SCROLL except PAUSE (CTRL pressed) has E0 prefix
1378 //
1379 } else if (Extend0 && (ScanCode == SCANCODE_SCROLL_LOCK_MAKE)) {
1380 KeyData.Key.UnicodeChar = CHAR_NULL;
1381 KeyData.Key.ScanCode = SCAN_PAUSE;
1382
1383 //
1384 // PRNT_SCRN shares the same scancode as that of Key Pad "*" except PRNT_SCRN has E0 prefix
1385 //
1386 } else if (Extend0 && (ScanCode == SCANCODE_SYS_REQ_MAKE)) {
1387 KeyData.Key.UnicodeChar = CHAR_NULL;
1388 KeyData.Key.ScanCode = SCAN_NULL;
1389
1390 //
1391 // Except the above special case, all others can be handled by convert table
1392 //
1393 } else {
1394 for (Index = 0; ConvertKeyboardScanCodeToEfiKey[Index].ScanCode != TABLE_END; Index++) {
1395 if (ScanCode == ConvertKeyboardScanCodeToEfiKey[Index].ScanCode) {
1396 KeyData.Key.ScanCode = ConvertKeyboardScanCodeToEfiKey[Index].EfiScanCode;
1397 KeyData.Key.UnicodeChar = ConvertKeyboardScanCodeToEfiKey[Index].UnicodeChar;
1398
1399 if ((ConsoleIn->LeftShift || ConsoleIn->RightShift) &&
1400 (ConvertKeyboardScanCodeToEfiKey[Index].UnicodeChar != ConvertKeyboardScanCodeToEfiKey[Index].ShiftUnicodeChar))
1401 {
1402 KeyData.Key.UnicodeChar = ConvertKeyboardScanCodeToEfiKey[Index].ShiftUnicodeChar;
1403 //
1404 // Need not return associated shift state if a class of printable characters that
1405 // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
1406 //
1407 KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);
1408 }
1409
1410 //
1411 // alphabetic key is affected by CapsLock State
1412 //
1413 if (ConsoleIn->CapsLock) {
1414 if ((KeyData.Key.UnicodeChar >= L'a') && (KeyData.Key.UnicodeChar <= L'z')) {
1415 KeyData.Key.UnicodeChar = (UINT16)(KeyData.Key.UnicodeChar - L'a' + L'A');
1416 } else if ((KeyData.Key.UnicodeChar >= L'A') && (KeyData.Key.UnicodeChar <= L'Z')) {
1417 KeyData.Key.UnicodeChar = (UINT16)(KeyData.Key.UnicodeChar - L'A' + L'a');
1418 }
1419 }
1420
1421 break;
1422 }
1423 }
1424 }
1425
1426 //
1427 // distinguish numeric key pad keys' 'up symbol' and 'down symbol'
1428 //
1429 if ((ScanCode >= 0x47) && (ScanCode <= 0x53)) {
1430 if (ConsoleIn->NumLock && !(ConsoleIn->LeftShift || ConsoleIn->RightShift) && !Extend0) {
1431 KeyData.Key.ScanCode = SCAN_NULL;
1432 } else if ((ScanCode != 0x4a) && (ScanCode != 0x4e)) {
1433 KeyData.Key.UnicodeChar = CHAR_NULL;
1434 }
1435 }
1436
1437 //
1438 // If the key can not be converted then just return.
1439 //
1440 if ((KeyData.Key.ScanCode == SCAN_NULL) && (KeyData.Key.UnicodeChar == CHAR_NULL)) {
1441 if (!ConsoleIn->IsSupportPartialKey) {
1442 return;
1443 }
1444 }
1445
1446 //
1447 // Signal KeyNotify process event if this key pressed matches any key registered.
1448 //
1449 for (Link = GetFirstNode (&ConsoleIn->NotifyList); !IsNull (&ConsoleIn->NotifyList, Link); Link = GetNextNode (&ConsoleIn->NotifyList, Link)) {
1450 CurrentNotify = CR (
1451 Link,
1452 KEYBOARD_CONSOLE_IN_EX_NOTIFY,
1453 NotifyEntry,
1454 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1455 );
1456 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
1457 //
1458 // The key notification function needs to run at TPL_CALLBACK
1459 // while current TPL is TPL_NOTIFY. It will be invoked in
1460 // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.
1461 //
1462 PushEfikeyBufTail (&ConsoleIn->EfiKeyQueueForNotify, &KeyData);
1463 gBS->SignalEvent (ConsoleIn->KeyNotifyProcessEvent);
1464 break;
1465 }
1466 }
1467
1468 PushEfikeyBufTail (&ConsoleIn->EfiKeyQueue, &KeyData);
1469 }
1470
1471 /**
1472 Perform 8042 controller and keyboard Initialization.
1473 If ExtendedVerification is TRUE, do additional test for
1474 the keyboard interface
1475
1476 @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
1477 @param ExtendedVerification - indicates a thorough initialization
1478
1479 @retval EFI_DEVICE_ERROR Fail to init keyboard
1480 @retval EFI_SUCCESS Success to init keyboard
1481 **/
1482 EFI_STATUS
1483 InitKeyboard (
1484 IN OUT KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
1485 IN BOOLEAN ExtendedVerification
1486 )
1487 {
1488 EFI_STATUS Status;
1489 EFI_STATUS Status1;
1490 UINT8 CommandByte;
1491 EFI_PS2_POLICY_PROTOCOL *Ps2Policy;
1492 UINT32 TryTime;
1493
1494 Status = EFI_SUCCESS;
1495 mEnableMouseInterface = TRUE;
1496 TryTime = 0;
1497
1498 //
1499 // Get Ps2 policy to set this
1500 //
1501 gBS->LocateProtocol (
1502 &gEfiPs2PolicyProtocolGuid,
1503 NULL,
1504 (VOID **)&Ps2Policy
1505 );
1506
1507 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1508 EFI_PROGRESS_CODE,
1509 EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER,
1510 ConsoleIn->DevicePath
1511 );
1512
1513 //
1514 // Perform a read to cleanup the Status Register's
1515 // output buffer full bits within MAX TRY times
1516 //
1517 if ((KeyReadStatusRegister (ConsoleIn) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA) != 0) {
1518 while (!EFI_ERROR (Status) && TryTime < KEYBOARD_MAX_TRY) {
1519 Status = KeyboardRead (ConsoleIn, &CommandByte);
1520 TryTime++;
1521 }
1522
1523 //
1524 // Exceed the max try times. The device may be error.
1525 //
1526 if (TryTime == KEYBOARD_MAX_TRY) {
1527 Status = EFI_DEVICE_ERROR;
1528 goto Done;
1529 }
1530 }
1531
1532 //
1533 // We should disable mouse interface during the initialization process
1534 // since mouse device output could block keyboard device output in the
1535 // 60H port of 8042 controller.
1536 //
1537 // So if we are not initializing 8042 controller for the
1538 // first time, we have to remember the previous mouse interface
1539 // enabling state
1540 //
1541 // Test the system flag in to determine whether this is the first
1542 // time initialization
1543 //
1544 if ((KeyReadStatusRegister (ConsoleIn) & KEYBOARD_STATUS_REGISTER_SYSTEM_FLAG) != 0) {
1545 if (!PcdGetBool (PcdFastPS2Detection)) {
1546 //
1547 // 8042 controller is already setup (by myself or by mouse driver):
1548 // See whether mouse interface is already enabled
1549 // which determines whether we should enable it later
1550 //
1551 //
1552 // Read the command byte of 8042 controller
1553 //
1554 Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_READ);
1555 if (EFI_ERROR (Status)) {
1556 KeyboardError (ConsoleIn, L"\n\r");
1557 goto Done;
1558 }
1559
1560 Status = KeyboardRead (ConsoleIn, &CommandByte);
1561 if (EFI_ERROR (Status)) {
1562 KeyboardError (ConsoleIn, L"\n\r");
1563 goto Done;
1564 }
1565
1566 //
1567 // Test the mouse enabling bit
1568 //
1569 if ((CommandByte & 0x20) != 0) {
1570 mEnableMouseInterface = FALSE;
1571 } else {
1572 mEnableMouseInterface = TRUE;
1573 }
1574 } else {
1575 mEnableMouseInterface = FALSE;
1576 }
1577 } else {
1578 //
1579 // 8042 controller is not setup yet:
1580 // 8042 controller selftest;
1581 // Don't enable mouse interface later.
1582 //
1583 //
1584 // Disable keyboard and mouse interfaces
1585 //
1586 if (!PcdGetBool (PcdFastPS2Detection)) {
1587 Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE);
1588 if (EFI_ERROR (Status)) {
1589 KeyboardError (ConsoleIn, L"\n\r");
1590 goto Done;
1591 }
1592
1593 Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_DISABLE_MOUSE_INTERFACE);
1594 if (EFI_ERROR (Status)) {
1595 KeyboardError (ConsoleIn, L"\n\r");
1596 goto Done;
1597 }
1598
1599 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1600 EFI_PROGRESS_CODE,
1601 EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST,
1602 ConsoleIn->DevicePath
1603 );
1604 //
1605 // 8042 Controller Self Test
1606 //
1607 Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_CONTROLLER_SELF_TEST);
1608 if (EFI_ERROR (Status)) {
1609 KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");
1610 goto Done;
1611 }
1612
1613 Status = KeyboardWaitForValue (ConsoleIn, 0x55);
1614 if (EFI_ERROR (Status)) {
1615 KeyboardError (ConsoleIn, L"8042 controller self test failed!\n\r");
1616 goto Done;
1617 }
1618 }
1619
1620 //
1621 // Don't enable mouse interface later
1622 //
1623 mEnableMouseInterface = FALSE;
1624 }
1625
1626 if (Ps2Policy != NULL) {
1627 Ps2Policy->Ps2InitHardware (ConsoleIn->Handle);
1628 }
1629
1630 //
1631 // Write 8042 Command Byte, set System Flag
1632 // While at the same time:
1633 // 1. disable mouse interface,
1634 // 2. enable kbd interface,
1635 // 3. enable PC/XT kbd translation mode
1636 // 4. enable mouse and kbd interrupts
1637 //
1638 // ( Command Byte bits:
1639 // 7: Reserved
1640 // 6: PC/XT translation mode
1641 // 5: Disable Auxiliary device interface
1642 // 4: Disable keyboard interface
1643 // 3: Reserved
1644 // 2: System Flag
1645 // 1: Enable Auxiliary device interrupt
1646 // 0: Enable Keyboard interrupt )
1647 //
1648 Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_WRITE);
1649 if (EFI_ERROR (Status)) {
1650 KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");
1651 goto Done;
1652 }
1653
1654 Status = KeyboardWrite (ConsoleIn, 0x67);
1655 if (EFI_ERROR (Status)) {
1656 KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");
1657 goto Done;
1658 }
1659
1660 //
1661 // Clear Memory Scancode Buffer
1662 //
1663 ConsoleIn->ScancodeQueue.Head = 0;
1664 ConsoleIn->ScancodeQueue.Tail = 0;
1665 ConsoleIn->EfiKeyQueue.Head = 0;
1666 ConsoleIn->EfiKeyQueue.Tail = 0;
1667 ConsoleIn->EfiKeyQueueForNotify.Head = 0;
1668 ConsoleIn->EfiKeyQueueForNotify.Tail = 0;
1669
1670 //
1671 // Reset the status indicators
1672 //
1673 ConsoleIn->CapsLock = FALSE;
1674 ConsoleIn->NumLock = FALSE;
1675 ConsoleIn->ScrollLock = FALSE;
1676 ConsoleIn->LeftCtrl = FALSE;
1677 ConsoleIn->RightCtrl = FALSE;
1678 ConsoleIn->LeftAlt = FALSE;
1679 ConsoleIn->RightAlt = FALSE;
1680 ConsoleIn->LeftShift = FALSE;
1681 ConsoleIn->RightShift = FALSE;
1682 ConsoleIn->LeftLogo = FALSE;
1683 ConsoleIn->RightLogo = FALSE;
1684 ConsoleIn->Menu = FALSE;
1685 ConsoleIn->SysReq = FALSE;
1686
1687 ConsoleIn->IsSupportPartialKey = FALSE;
1688 //
1689 // For resetting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1690 // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected
1691 // to system. So we only do the real resetting for keyboard when user asks and there is a real KB connected t system,
1692 // and normally during booting an OS, it's skipped.
1693 //
1694 if (ExtendedVerification && CheckKeyboardConnect (ConsoleIn)) {
1695 //
1696 // Additional verifications for keyboard interface
1697 //
1698 //
1699 // Keyboard Interface Test
1700 //
1701 Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_KEYBOARD_INTERFACE_SELF_TEST);
1702 if (EFI_ERROR (Status)) {
1703 KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");
1704 goto Done;
1705 }
1706
1707 Status = KeyboardWaitForValue (ConsoleIn, 0x00);
1708 if (EFI_ERROR (Status)) {
1709 KeyboardError (
1710 ConsoleIn,
1711 L"Some specific value not acquired from 8042 controller!\n\r"
1712 );
1713 goto Done;
1714 }
1715
1716 //
1717 // Keyboard reset with a BAT(Basic Assurance Test)
1718 //
1719 Status = KeyboardWrite (ConsoleIn, KEYBOARD_8048_COMMAND_RESET);
1720 if (EFI_ERROR (Status)) {
1721 KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");
1722 goto Done;
1723 }
1724
1725 Status = KeyboardWaitForValue (ConsoleIn, KEYBOARD_8048_RETURN_8042_ACK);
1726 if (EFI_ERROR (Status)) {
1727 KeyboardError (ConsoleIn, L"Some specific value not acquired from 8042 controller!\n\r");
1728 goto Done;
1729 }
1730
1731 //
1732 // wait for BAT completion code
1733 //
1734 KeyboardWaitForValue (ConsoleIn, KEYBOARD_8048_RETURN_8042_BAT_SUCCESS);
1735
1736 mWaitForValueTimeOut = KEYBOARD_WAITFORVALUE_TIMEOUT;
1737
1738 //
1739 // Set Keyboard to use Scan Code Set 2
1740 //
1741 Status = KeyboardWrite (ConsoleIn, KEYBOARD_8048_COMMAND_SELECT_SCAN_CODE_SET);
1742 if (EFI_ERROR (Status)) {
1743 KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");
1744 goto Done;
1745 }
1746
1747 Status = KeyboardWaitForValue (ConsoleIn, KEYBOARD_8048_RETURN_8042_ACK);
1748 if (EFI_ERROR (Status)) {
1749 KeyboardError (ConsoleIn, L"Some specific value not acquired from 8042 controller!\n\r");
1750 goto Done;
1751 }
1752
1753 Status = KeyboardWrite (ConsoleIn, 0x02);
1754 if (EFI_ERROR (Status)) {
1755 KeyboardError (ConsoleIn, L"8042 controller data write error!!\n\r");
1756 goto Done;
1757 }
1758
1759 Status = KeyboardWaitForValue (ConsoleIn, KEYBOARD_8048_RETURN_8042_ACK);
1760 if (EFI_ERROR (Status)) {
1761 KeyboardError (ConsoleIn, L"Some specific value not acquired from 8042 controller!\n\r");
1762 goto Done;
1763 }
1764
1765 //
1766 // Clear Keyboard Scancode Buffer
1767 //
1768 Status = KeyboardWrite (ConsoleIn, KEYBOARD_8048_COMMAND_CLEAR_OUTPUT_DATA);
1769 if (EFI_ERROR (Status)) {
1770 KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");
1771 goto Done;
1772 }
1773
1774 Status = KeyboardWaitForValue (ConsoleIn, KEYBOARD_8048_RETURN_8042_ACK);
1775 if (EFI_ERROR (Status)) {
1776 KeyboardError (ConsoleIn, L"Some specific value not acquired from 8042 controller!\n\r");
1777 goto Done;
1778 }
1779
1780 //
1781 if (Ps2Policy != NULL) {
1782 if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_CAPSLOCK) == EFI_KEYBOARD_CAPSLOCK) {
1783 ConsoleIn->CapsLock = TRUE;
1784 }
1785
1786 if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_NUMLOCK) == EFI_KEYBOARD_NUMLOCK) {
1787 ConsoleIn->NumLock = TRUE;
1788 }
1789
1790 if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_SCROLLLOCK) == EFI_KEYBOARD_SCROLLLOCK) {
1791 ConsoleIn->ScrollLock = TRUE;
1792 }
1793 }
1794
1795 //
1796 // Update Keyboard Lights
1797 //
1798 Status = UpdateStatusLights (ConsoleIn);
1799 if (EFI_ERROR (Status)) {
1800 KeyboardError (ConsoleIn, L"Update keyboard status lights error!\n\r");
1801 goto Done;
1802 }
1803 }
1804
1805 //
1806 // At last, we can now enable the mouse interface if appropriate
1807 //
1808 Done:
1809
1810 if (mEnableMouseInterface) {
1811 //
1812 // Enable mouse interface
1813 //
1814 Status1 = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_ENABLE_MOUSE_INTERFACE);
1815 if (EFI_ERROR (Status1)) {
1816 KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");
1817 return EFI_DEVICE_ERROR;
1818 }
1819 }
1820
1821 if (!EFI_ERROR (Status)) {
1822 return EFI_SUCCESS;
1823 } else {
1824 return EFI_DEVICE_ERROR;
1825 }
1826 }
1827
1828 /**
1829 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
1830 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
1831 should not be in system.
1832
1833 @param[in] ConsoleIn Keyboard Private Data Structure
1834
1835 @retval TRUE Keyboard in System.
1836 @retval FALSE Keyboard not in System.
1837 **/
1838 BOOLEAN
1839 EFIAPI
1840 CheckKeyboardConnect (
1841 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
1842 )
1843 {
1844 EFI_STATUS Status;
1845 UINTN WaitForValueTimeOutBcakup;
1846
1847 //
1848 // enable keyboard itself and wait for its ack
1849 // If can't receive ack, Keyboard should not be connected.
1850 //
1851 if (!PcdGetBool (PcdFastPS2Detection)) {
1852 Status = KeyboardWrite (
1853 ConsoleIn,
1854 KEYBOARD_KBEN
1855 );
1856
1857 if (EFI_ERROR (Status)) {
1858 return FALSE;
1859 }
1860
1861 //
1862 // wait for 1s
1863 //
1864 WaitForValueTimeOutBcakup = mWaitForValueTimeOut;
1865 mWaitForValueTimeOut = KEYBOARD_WAITFORVALUE_TIMEOUT;
1866 Status = KeyboardWaitForValue (
1867 ConsoleIn,
1868 KEYBOARD_CMDECHO_ACK
1869 );
1870 mWaitForValueTimeOut = WaitForValueTimeOutBcakup;
1871
1872 if (EFI_ERROR (Status)) {
1873 return FALSE;
1874 }
1875
1876 return TRUE;
1877 } else {
1878 return TRUE;
1879 }
1880 }