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