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