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