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