]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c
IntelFrameworkModulePkg Ps2KbDxe: Execute key notify func at TPL_CALLBACK
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / Ps2KeyboardDxe / Ps2KbdCtrller.c
... / ...
CommitLineData
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 EFI_ISA_IO_PROTOCOL *IsaIo;\r
701 UINT8 Data;\r
702\r
703 //\r
704 // Use IsaIo protocol to perform IO operations\r
705 //\r
706 IsaIo = ConsoleIn->IsaIo;\r
707\r
708 IsaIo->Io.Read (\r
709 IsaIo,\r
710 EfiIsaIoWidthUint8,\r
711 ConsoleIn->DataRegisterAddress,\r
712 1,\r
713 &Data\r
714 );\r
715\r
716 return Data;\r
717}\r
718\r
719/**\r
720 Write data register.\r
721\r
722 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV\r
723 @param Data value wanted to be written\r
724\r
725**/\r
726VOID\r
727KeyWriteDataRegister (\r
728 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
729 IN UINT8 Data\r
730 )\r
731{\r
732 ConsoleIn->IsaIo->Io.Write (\r
733 ConsoleIn->IsaIo,\r
734 EfiIsaIoWidthUint8,\r
735 ConsoleIn->DataRegisterAddress,\r
736 1,\r
737 &Data\r
738 );\r
739}\r
740\r
741/**\r
742 Read status register.\r
743\r
744 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV\r
745\r
746 @return value in status register\r
747\r
748**/\r
749UINT8\r
750KeyReadStatusRegister (\r
751 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn\r
752 )\r
753{\r
754 UINT8 Data;\r
755 ConsoleIn->IsaIo->Io.Read (\r
756 ConsoleIn->IsaIo,\r
757 EfiIsaIoWidthUint8,\r
758 ConsoleIn->StatusRegisterAddress,\r
759 1,\r
760 &Data\r
761 );\r
762 return Data;\r
763}\r
764\r
765/**\r
766 Write command register .\r
767\r
768 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV\r
769 @param Data The value wanted to be written\r
770\r
771**/\r
772VOID\r
773KeyWriteCommandRegister (\r
774 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
775 IN UINT8 Data\r
776 )\r
777{\r
778 ConsoleIn->IsaIo->Io.Write (\r
779 ConsoleIn->IsaIo,\r
780 EfiIsaIoWidthUint8,\r
781 ConsoleIn->CommandRegisterAddress,\r
782 1,\r
783 &Data\r
784 );\r
785}\r
786\r
787/**\r
788 Display error message.\r
789\r
790 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV\r
791 @param ErrMsg Unicode string of error message\r
792\r
793**/\r
794VOID\r
795KeyboardError (\r
796 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
797 IN CHAR16 *ErrMsg\r
798 )\r
799{\r
800 ConsoleIn->KeyboardErr = TRUE;\r
801}\r
802\r
803/**\r
804 Timer event handler: read a series of scancodes from 8042\r
805 and put them into memory scancode buffer.\r
806 it read as much scancodes to either fill\r
807 the memory buffer or empty the keyboard buffer.\r
808 It is registered as running under TPL_NOTIFY\r
809\r
810 @param Event The timer event\r
811 @param Context A KEYBOARD_CONSOLE_IN_DEV pointer\r
812\r
813**/\r
814VOID\r
815EFIAPI\r
816KeyboardTimerHandler (\r
817 IN EFI_EVENT Event,\r
818 IN VOID *Context\r
819 )\r
820\r
821{\r
822 UINT8 Data;\r
823 EFI_TPL OldTpl;\r
824 KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;\r
825\r
826 ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *) Context;\r
827\r
828 //\r
829 // Enter critical section\r
830 //\r
831 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
832\r
833 if (((KEYBOARD_CONSOLE_IN_DEV *) Context)->KeyboardErr) {\r
834 //\r
835 // Leave critical section and return\r
836 //\r
837 gBS->RestoreTPL (OldTpl);\r
838 return ;\r
839 }\r
840\r
841 //\r
842 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that\r
843 // KB is not connected to system. If KB is not connected to system, driver will find there's something\r
844 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since\r
845 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.\r
846 // Just skip the 'resend' process simply.\r
847 //\r
848\r
849 while ((KeyReadStatusRegister (ConsoleIn) & (KEYBOARD_STATUS_REGISTER_TRANSMIT_TIMEOUT|KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA)) ==\r
850 KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA\r
851 ) {\r
852 //\r
853 // Read one byte of the scan code and store it into the memory buffer\r
854 //\r
855 Data = KeyReadDataRegister (ConsoleIn);\r
856 PushScancodeBufTail (&ConsoleIn->ScancodeQueue, Data);\r
857 }\r
858 KeyGetchar (ConsoleIn);\r
859\r
860 //\r
861 // Leave critical section and return\r
862 //\r
863 gBS->RestoreTPL (OldTpl);\r
864}\r
865\r
866/**\r
867 Read key value .\r
868\r
869 @param ConsoleIn - Pointer to instance of KEYBOARD_CONSOLE_IN_DEV\r
870 @param Data - Pointer to outof buffer for keeping key value\r
871\r
872 @retval EFI_TIMEOUT Status resigter time out\r
873 @retval EFI_SUCCESS Success to read keyboard\r
874\r
875**/\r
876EFI_STATUS\r
877KeyboardRead (\r
878 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
879 OUT UINT8 *Data\r
880 )\r
881\r
882{\r
883 UINT32 TimeOut;\r
884 UINT32 RegFilled;\r
885\r
886 TimeOut = 0;\r
887 RegFilled = 0;\r
888\r
889 //\r
890 // wait till output buffer full then perform the read\r
891 //\r
892 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
893 if (KeyReadStatusRegister (ConsoleIn) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA) {\r
894 RegFilled = 1;\r
895 *Data = KeyReadDataRegister (ConsoleIn);\r
896 break;\r
897 }\r
898\r
899 MicroSecondDelay (30);\r
900 }\r
901\r
902 if (RegFilled == 0) {\r
903 return EFI_TIMEOUT;\r
904 }\r
905\r
906 return EFI_SUCCESS;\r
907}\r
908\r
909/**\r
910 write key to keyboard\r
911\r
912 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV\r
913 @param Data value wanted to be written\r
914\r
915 @retval EFI_TIMEOUT The input buffer register is full for putting new value util timeout\r
916 @retval EFI_SUCCESS The new value is sucess put into input buffer register.\r
917\r
918**/\r
919EFI_STATUS\r
920KeyboardWrite (\r
921 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
922 IN UINT8 Data\r
923 )\r
924{\r
925 UINT32 TimeOut;\r
926 UINT32 RegEmptied;\r
927\r
928 TimeOut = 0;\r
929 RegEmptied = 0;\r
930\r
931 //\r
932 // wait for input buffer empty\r
933 //\r
934 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
935 if ((KeyReadStatusRegister (ConsoleIn) & 0x02) == 0) {\r
936 RegEmptied = 1;\r
937 break;\r
938 }\r
939\r
940 MicroSecondDelay (30);\r
941 }\r
942\r
943 if (RegEmptied == 0) {\r
944 return EFI_TIMEOUT;\r
945 }\r
946 //\r
947 // Write it\r
948 //\r
949 KeyWriteDataRegister (ConsoleIn, Data);\r
950\r
951 return EFI_SUCCESS;\r
952}\r
953\r
954/**\r
955 Issue keyboard command.\r
956\r
957 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV\r
958 @param Data The buff holding the command\r
959\r
960 @retval EFI_TIMEOUT Keyboard is not ready to issuing\r
961 @retval EFI_SUCCESS Success to issue keyboard command\r
962\r
963**/\r
964EFI_STATUS\r
965KeyboardCommand (\r
966 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
967 IN UINT8 Data\r
968 )\r
969{\r
970 UINT32 TimeOut;\r
971 UINT32 RegEmptied;\r
972\r
973 TimeOut = 0;\r
974 RegEmptied = 0;\r
975\r
976 //\r
977 // Wait For Input Buffer Empty\r
978 //\r
979 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
980 if ((KeyReadStatusRegister (ConsoleIn) & 0x02) == 0) {\r
981 RegEmptied = 1;\r
982 break;\r
983 }\r
984\r
985 MicroSecondDelay (30);\r
986 }\r
987\r
988 if (RegEmptied == 0) {\r
989 return EFI_TIMEOUT;\r
990 }\r
991 //\r
992 // issue the command\r
993 //\r
994 KeyWriteCommandRegister (ConsoleIn, Data);\r
995\r
996 //\r
997 // Wait For Input Buffer Empty again\r
998 //\r
999 RegEmptied = 0;\r
1000 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
1001 if ((KeyReadStatusRegister (ConsoleIn) & 0x02) == 0) {\r
1002 RegEmptied = 1;\r
1003 break;\r
1004 }\r
1005\r
1006 MicroSecondDelay (30);\r
1007 }\r
1008\r
1009 if (RegEmptied == 0) {\r
1010 return EFI_TIMEOUT;\r
1011 }\r
1012\r
1013 return EFI_SUCCESS;\r
1014}\r
1015\r
1016/**\r
1017 wait for a specific value to be presented on\r
1018 8042 Data register by keyboard and then read it,\r
1019 used in keyboard commands ack\r
1020\r
1021 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV\r
1022 @param Value the value wanted to be waited.\r
1023\r
1024 @retval EFI_TIMEOUT Fail to get specific value in given time\r
1025 @retval EFI_SUCCESS Success to get specific value in given time.\r
1026\r
1027**/\r
1028EFI_STATUS\r
1029KeyboardWaitForValue (\r
1030 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
1031 IN UINT8 Value\r
1032 )\r
1033{\r
1034 UINT8 Data;\r
1035 UINT32 TimeOut;\r
1036 UINT32 SumTimeOut;\r
1037 UINT32 GotIt;\r
1038\r
1039 GotIt = 0;\r
1040 TimeOut = 0;\r
1041 SumTimeOut = 0;\r
1042\r
1043 //\r
1044 // Make sure the initial value of 'Data' is different from 'Value'\r
1045 //\r
1046 Data = 0;\r
1047 if (Data == Value) {\r
1048 Data = 1;\r
1049 }\r
1050 //\r
1051 // Read from 8042 (multiple times if needed)\r
1052 // until the expected value appears\r
1053 // use SumTimeOut to control the iteration\r
1054 //\r
1055 while (1) {\r
1056 //\r
1057 // Perform a read\r
1058 //\r
1059 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
1060 if (KeyReadStatusRegister (ConsoleIn) & 0x01) {\r
1061 Data = KeyReadDataRegister (ConsoleIn);\r
1062 break;\r
1063 }\r
1064\r
1065 MicroSecondDelay (30);\r
1066 }\r
1067\r
1068 SumTimeOut += TimeOut;\r
1069\r
1070 if (Data == Value) {\r
1071 GotIt = 1;\r
1072 break;\r
1073 }\r
1074\r
1075 if (SumTimeOut >= mWaitForValueTimeOut) {\r
1076 break;\r
1077 }\r
1078 }\r
1079 //\r
1080 // Check results\r
1081 //\r
1082 if (GotIt == 1) {\r
1083 return EFI_SUCCESS;\r
1084 } else {\r
1085 return EFI_TIMEOUT;\r
1086 }\r
1087\r
1088}\r
1089\r
1090/**\r
1091 Show keyboard status lights according to\r
1092 indicators in ConsoleIn.\r
1093\r
1094 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV\r
1095\r
1096 @return status of updating keyboard register\r
1097\r
1098**/\r
1099EFI_STATUS\r
1100UpdateStatusLights (\r
1101 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn\r
1102 )\r
1103{\r
1104 EFI_STATUS Status;\r
1105 UINT8 Command;\r
1106\r
1107 //\r
1108 // Send keyboard command\r
1109 //\r
1110 Status = KeyboardWrite (ConsoleIn, 0xed);\r
1111 if (EFI_ERROR (Status)) {\r
1112 return Status;\r
1113 }\r
1114\r
1115 KeyboardWaitForValue (ConsoleIn, 0xfa);\r
1116\r
1117 //\r
1118 // Light configuration\r
1119 //\r
1120 Command = 0;\r
1121 if (ConsoleIn->CapsLock) {\r
1122 Command |= 4;\r
1123 }\r
1124\r
1125 if (ConsoleIn->NumLock) {\r
1126 Command |= 2;\r
1127 }\r
1128\r
1129 if (ConsoleIn->ScrollLock) {\r
1130 Command |= 1;\r
1131 }\r
1132\r
1133 Status = KeyboardWrite (ConsoleIn, Command);\r
1134\r
1135 if (EFI_ERROR (Status)) {\r
1136 return Status;\r
1137 }\r
1138\r
1139 KeyboardWaitForValue (ConsoleIn, 0xfa);\r
1140 return Status;\r
1141}\r
1142\r
1143/**\r
1144 Get scancode from scancode buffer and translate into EFI-scancode and unicode defined by EFI spec.\r
1145\r
1146 The function is always called in TPL_NOTIFY.\r
1147\r
1148 @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer\r
1149\r
1150**/\r
1151VOID\r
1152KeyGetchar (\r
1153 IN OUT KEYBOARD_CONSOLE_IN_DEV *ConsoleIn\r
1154 )\r
1155{\r
1156 EFI_STATUS Status;\r
1157 UINT16 ScanCode;\r
1158 BOOLEAN Extend0;\r
1159 BOOLEAN Extend1;\r
1160 UINTN Index;\r
1161 EFI_KEY_DATA KeyData;\r
1162 LIST_ENTRY *Link;\r
1163 KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
1164 //\r
1165 // 3 bytes most\r
1166 //\r
1167 UINT8 ScancodeArr[3];\r
1168 UINT32 ScancodeArrPos;\r
1169\r
1170 //\r
1171 // Check if there are enough bytes of scancode representing a single key\r
1172 // available in the buffer\r
1173 //\r
1174 while (TRUE) {\r
1175 Extend0 = FALSE;\r
1176 Extend1 = FALSE;\r
1177 ScancodeArrPos = 0;\r
1178 Status = GetScancodeBufHead (&ConsoleIn->ScancodeQueue, ScancodeArrPos + 1, ScancodeArr);\r
1179 if (EFI_ERROR (Status)) {\r
1180 return ;\r
1181 }\r
1182\r
1183 if (ScancodeArr[ScancodeArrPos] == SCANCODE_EXTENDED0) {\r
1184 //\r
1185 // E0 to look ahead 2 bytes\r
1186 //\r
1187 Extend0 = TRUE;\r
1188 ScancodeArrPos = 1;\r
1189 Status = GetScancodeBufHead (&ConsoleIn->ScancodeQueue, ScancodeArrPos + 1, ScancodeArr);\r
1190 if (EFI_ERROR (Status)) {\r
1191 return ;\r
1192 }\r
1193 } else if (ScancodeArr[ScancodeArrPos] == SCANCODE_EXTENDED1) {\r
1194 //\r
1195 // E1 to look ahead 3 bytes\r
1196 //\r
1197 Extend1 = TRUE;\r
1198 ScancodeArrPos = 2;\r
1199 Status = GetScancodeBufHead (&ConsoleIn->ScancodeQueue, ScancodeArrPos + 1, ScancodeArr);\r
1200 if (EFI_ERROR (Status)) {\r
1201 return ;\r
1202 }\r
1203 }\r
1204 //\r
1205 // if we reach this position, scancodes for a key is in buffer now,pop them\r
1206 //\r
1207 Status = PopScancodeBufHead (&ConsoleIn->ScancodeQueue, ScancodeArrPos + 1, ScancodeArr);\r
1208 ASSERT_EFI_ERROR (Status);\r
1209\r
1210 //\r
1211 // store the last available byte, this byte of scancode will be checked\r
1212 //\r
1213 ScanCode = ScancodeArr[ScancodeArrPos];\r
1214\r
1215 if (!Extend1) {\r
1216 //\r
1217 // Check for special keys and update the driver state.\r
1218 //\r
1219 switch (ScanCode) {\r
1220\r
1221 case SCANCODE_CTRL_MAKE:\r
1222 if (Extend0) {\r
1223 ConsoleIn->RightCtrl = TRUE;\r
1224 } else {\r
1225 ConsoleIn->LeftCtrl = TRUE;\r
1226 }\r
1227 break;\r
1228 case SCANCODE_CTRL_BREAK:\r
1229 if (Extend0) {\r
1230 ConsoleIn->RightCtrl = FALSE;\r
1231 } else {\r
1232 ConsoleIn->LeftCtrl = FALSE;\r
1233 }\r
1234 break;\r
1235\r
1236 case SCANCODE_ALT_MAKE:\r
1237 if (Extend0) {\r
1238 ConsoleIn->RightAlt = TRUE;\r
1239 } else {\r
1240 ConsoleIn->LeftAlt = TRUE;\r
1241 }\r
1242 break;\r
1243 case SCANCODE_ALT_BREAK:\r
1244 if (Extend0) {\r
1245 ConsoleIn->RightAlt = FALSE;\r
1246 } else {\r
1247 ConsoleIn->LeftAlt = FALSE;\r
1248 }\r
1249 break;\r
1250\r
1251 case SCANCODE_LEFT_SHIFT_MAKE:\r
1252 //\r
1253 // To avoid recognize PRNT_SCRN key as a L_SHIFT key\r
1254 // because PRNT_SCRN key generates E0 followed by L_SHIFT scan code.\r
1255 // If it the second byte of the PRNT_ScRN skip it.\r
1256 //\r
1257 if (!Extend0) {\r
1258 ConsoleIn->LeftShift = TRUE;\r
1259 break;\r
1260 }\r
1261 continue;\r
1262\r
1263 case SCANCODE_LEFT_SHIFT_BREAK:\r
1264 if (!Extend0) {\r
1265 ConsoleIn->LeftShift = FALSE;\r
1266 }\r
1267 break;\r
1268\r
1269 case SCANCODE_RIGHT_SHIFT_MAKE:\r
1270 ConsoleIn->RightShift = TRUE;\r
1271 break;\r
1272 case SCANCODE_RIGHT_SHIFT_BREAK:\r
1273 ConsoleIn->RightShift = FALSE;\r
1274 break;\r
1275\r
1276 case SCANCODE_LEFT_LOGO_MAKE:\r
1277 ConsoleIn->LeftLogo = TRUE;\r
1278 break;\r
1279 case SCANCODE_LEFT_LOGO_BREAK:\r
1280 ConsoleIn->LeftLogo = FALSE;\r
1281 break;\r
1282\r
1283 case SCANCODE_RIGHT_LOGO_MAKE:\r
1284 ConsoleIn->RightLogo = TRUE;\r
1285 break;\r
1286 case SCANCODE_RIGHT_LOGO_BREAK:\r
1287 ConsoleIn->RightLogo = FALSE;\r
1288 break;\r
1289\r
1290 case SCANCODE_MENU_MAKE:\r
1291 ConsoleIn->Menu = TRUE;\r
1292 break;\r
1293 case SCANCODE_MENU_BREAK:\r
1294 ConsoleIn->Menu = FALSE;\r
1295 break;\r
1296\r
1297 case SCANCODE_SYS_REQ_MAKE:\r
1298 if (Extend0) {\r
1299 ConsoleIn->SysReq = TRUE;\r
1300 }\r
1301 break;\r
1302 case SCANCODE_SYS_REQ_BREAK:\r
1303 if (Extend0) {\r
1304 ConsoleIn->SysReq = FALSE;\r
1305 }\r
1306 break;\r
1307\r
1308 case SCANCODE_SYS_REQ_MAKE_WITH_ALT:\r
1309 ConsoleIn->SysReq = TRUE;\r
1310 break;\r
1311 case SCANCODE_SYS_REQ_BREAK_WITH_ALT:\r
1312 ConsoleIn->SysReq = FALSE;\r
1313 break;\r
1314\r
1315 case SCANCODE_CAPS_LOCK_MAKE:\r
1316 ConsoleIn->CapsLock = (BOOLEAN)!ConsoleIn->CapsLock;\r
1317 UpdateStatusLights (ConsoleIn);\r
1318 break;\r
1319 case SCANCODE_NUM_LOCK_MAKE:\r
1320 ConsoleIn->NumLock = (BOOLEAN)!ConsoleIn->NumLock;\r
1321 UpdateStatusLights (ConsoleIn);\r
1322 break;\r
1323 case SCANCODE_SCROLL_LOCK_MAKE:\r
1324 if (!Extend0) {\r
1325 ConsoleIn->ScrollLock = (BOOLEAN)!ConsoleIn->ScrollLock;\r
1326 UpdateStatusLights (ConsoleIn);\r
1327 }\r
1328 break;\r
1329 }\r
1330 }\r
1331\r
1332 //\r
1333 // If this is above the valid range, ignore it\r
1334 //\r
1335 if (ScanCode >= SCANCODE_MAX_MAKE) {\r
1336 continue;\r
1337 } else {\r
1338 break;\r
1339 }\r
1340 }\r
1341\r
1342 //\r
1343 // Handle Ctrl+Alt+Del hotkey\r
1344 //\r
1345 if ((ConsoleIn->LeftCtrl || ConsoleIn->RightCtrl) &&\r
1346 (ConsoleIn->LeftAlt || ConsoleIn->RightAlt ) &&\r
1347 ScanCode == SCANCODE_DELETE_MAKE\r
1348 ) {\r
1349 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
1350 }\r
1351\r
1352 //\r
1353 // Save the Shift/Toggle state\r
1354 //\r
1355 KeyData.KeyState.KeyShiftState = (UINT32) (EFI_SHIFT_STATE_VALID\r
1356 | (ConsoleIn->LeftCtrl ? EFI_LEFT_CONTROL_PRESSED : 0)\r
1357 | (ConsoleIn->RightCtrl ? EFI_RIGHT_CONTROL_PRESSED : 0)\r
1358 | (ConsoleIn->LeftAlt ? EFI_LEFT_ALT_PRESSED : 0)\r
1359 | (ConsoleIn->RightAlt ? EFI_RIGHT_ALT_PRESSED : 0)\r
1360 | (ConsoleIn->LeftShift ? EFI_LEFT_SHIFT_PRESSED : 0)\r
1361 | (ConsoleIn->RightShift ? EFI_RIGHT_SHIFT_PRESSED : 0)\r
1362 | (ConsoleIn->LeftLogo ? EFI_LEFT_LOGO_PRESSED : 0)\r
1363 | (ConsoleIn->RightLogo ? EFI_RIGHT_LOGO_PRESSED : 0)\r
1364 | (ConsoleIn->Menu ? EFI_MENU_KEY_PRESSED : 0)\r
1365 | (ConsoleIn->SysReq ? EFI_SYS_REQ_PRESSED : 0)\r
1366 );\r
1367 KeyData.KeyState.KeyToggleState = (EFI_KEY_TOGGLE_STATE) (EFI_TOGGLE_STATE_VALID\r
1368 | (ConsoleIn->CapsLock ? EFI_CAPS_LOCK_ACTIVE : 0)\r
1369 | (ConsoleIn->NumLock ? EFI_NUM_LOCK_ACTIVE : 0)\r
1370 | (ConsoleIn->ScrollLock ? EFI_SCROLL_LOCK_ACTIVE : 0)\r
1371 | (ConsoleIn->IsSupportPartialKey ? EFI_KEY_STATE_EXPOSED : 0)\r
1372 );\r
1373\r
1374 KeyData.Key.ScanCode = SCAN_NULL;\r
1375 KeyData.Key.UnicodeChar = CHAR_NULL;\r
1376\r
1377 //\r
1378 // Key Pad "/" shares the same scancode as that of "/" except Key Pad "/" has E0 prefix\r
1379 //\r
1380 if (Extend0 && ScanCode == 0x35) {\r
1381 KeyData.Key.UnicodeChar = L'/';\r
1382 KeyData.Key.ScanCode = SCAN_NULL;\r
1383\r
1384 //\r
1385 // PAUSE shares the same scancode as that of NUM except PAUSE has E1 prefix\r
1386 //\r
1387 } else if (Extend1 && ScanCode == SCANCODE_NUM_LOCK_MAKE) {\r
1388 KeyData.Key.UnicodeChar = CHAR_NULL;\r
1389 KeyData.Key.ScanCode = SCAN_PAUSE;\r
1390\r
1391 //\r
1392 // PAUSE shares the same scancode as that of SCROLL except PAUSE (CTRL pressed) has E0 prefix\r
1393 //\r
1394 } else if (Extend0 && ScanCode == SCANCODE_SCROLL_LOCK_MAKE) {\r
1395 KeyData.Key.UnicodeChar = CHAR_NULL;\r
1396 KeyData.Key.ScanCode = SCAN_PAUSE;\r
1397\r
1398 //\r
1399 // PRNT_SCRN shares the same scancode as that of Key Pad "*" except PRNT_SCRN has E0 prefix\r
1400 //\r
1401 } else if (Extend0 && ScanCode == SCANCODE_SYS_REQ_MAKE) {\r
1402 KeyData.Key.UnicodeChar = CHAR_NULL;\r
1403 KeyData.Key.ScanCode = SCAN_NULL;\r
1404\r
1405 //\r
1406 // Except the above special case, all others can be handled by convert table\r
1407 //\r
1408 } else {\r
1409 for (Index = 0; ConvertKeyboardScanCodeToEfiKey[Index].ScanCode != TABLE_END; Index++) {\r
1410 if (ScanCode == ConvertKeyboardScanCodeToEfiKey[Index].ScanCode) {\r
1411 KeyData.Key.ScanCode = ConvertKeyboardScanCodeToEfiKey[Index].EfiScanCode;\r
1412 KeyData.Key.UnicodeChar = ConvertKeyboardScanCodeToEfiKey[Index].UnicodeChar;\r
1413\r
1414 if ((ConsoleIn->LeftShift || ConsoleIn->RightShift) &&\r
1415 (ConvertKeyboardScanCodeToEfiKey[Index].UnicodeChar != ConvertKeyboardScanCodeToEfiKey[Index].ShiftUnicodeChar)) {\r
1416 KeyData.Key.UnicodeChar = ConvertKeyboardScanCodeToEfiKey[Index].ShiftUnicodeChar;\r
1417 //\r
1418 // Need not return associated shift state if a class of printable characters that\r
1419 // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'\r
1420 //\r
1421 KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);\r
1422 }\r
1423 //\r
1424 // alphabetic key is affected by CapsLock State\r
1425 //\r
1426 if (ConsoleIn->CapsLock) {\r
1427 if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {\r
1428 KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar - L'a' + L'A');\r
1429 } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {\r
1430 KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar - L'A' + L'a');\r
1431 }\r
1432 }\r
1433 break;\r
1434 }\r
1435 }\r
1436 }\r
1437\r
1438 //\r
1439 // distinguish numeric key pad keys' 'up symbol' and 'down symbol'\r
1440 //\r
1441 if (ScanCode >= 0x47 && ScanCode <= 0x53) {\r
1442 if (ConsoleIn->NumLock && !(ConsoleIn->LeftShift || ConsoleIn->RightShift) && !Extend0) {\r
1443 KeyData.Key.ScanCode = SCAN_NULL;\r
1444 } else if (ScanCode != 0x4a && ScanCode != 0x4e) {\r
1445 KeyData.Key.UnicodeChar = CHAR_NULL;\r
1446 }\r
1447 }\r
1448\r
1449 //\r
1450 // If the key can not be converted then just return.\r
1451 //\r
1452 if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {\r
1453 if (!ConsoleIn->IsSupportPartialKey) {\r
1454 return ;\r
1455 }\r
1456 }\r
1457\r
1458 //\r
1459 // Signal KeyNotify process event if this key pressed matches any key registered.\r
1460 //\r
1461 for (Link = GetFirstNode (&ConsoleIn->NotifyList); !IsNull (&ConsoleIn->NotifyList, Link); Link = GetNextNode (&ConsoleIn->NotifyList, Link)) {\r
1462 CurrentNotify = CR (\r
1463 Link,\r
1464 KEYBOARD_CONSOLE_IN_EX_NOTIFY,\r
1465 NotifyEntry,\r
1466 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
1467 );\r
1468 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
1469 //\r
1470 // The key notification function needs to run at TPL_CALLBACK\r
1471 // while current TPL is TPL_NOTIFY. It will be invoked in\r
1472 // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.\r
1473 //\r
1474 PushEfikeyBufTail (&ConsoleIn->EfiKeyQueueForNotify, &KeyData);\r
1475 gBS->SignalEvent (ConsoleIn->KeyNotifyProcessEvent);\r
1476 }\r
1477 }\r
1478\r
1479 PushEfikeyBufTail (&ConsoleIn->EfiKeyQueue, &KeyData);\r
1480}\r
1481\r
1482/**\r
1483 Perform 8042 controller and keyboard Initialization.\r
1484 If ExtendedVerification is TRUE, do additional test for\r
1485 the keyboard interface\r
1486\r
1487 @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer\r
1488 @param ExtendedVerification - indicates a thorough initialization\r
1489\r
1490 @retval EFI_DEVICE_ERROR Fail to init keyboard\r
1491 @retval EFI_SUCCESS Success to init keyboard\r
1492**/\r
1493EFI_STATUS\r
1494InitKeyboard (\r
1495 IN OUT KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,\r
1496 IN BOOLEAN ExtendedVerification\r
1497 )\r
1498{\r
1499 EFI_STATUS Status;\r
1500 EFI_STATUS Status1;\r
1501 UINT8 CommandByte;\r
1502 EFI_PS2_POLICY_PROTOCOL *Ps2Policy;\r
1503 UINT32 TryTime;\r
1504\r
1505 Status = EFI_SUCCESS;\r
1506 mEnableMouseInterface = TRUE;\r
1507 TryTime = 0;\r
1508\r
1509 //\r
1510 // Get Ps2 policy to set this\r
1511 //\r
1512 gBS->LocateProtocol (\r
1513 &gEfiPs2PolicyProtocolGuid,\r
1514 NULL,\r
1515 (VOID **) &Ps2Policy\r
1516 );\r
1517\r
1518 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1519 EFI_PROGRESS_CODE,\r
1520 EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER,\r
1521 ConsoleIn->DevicePath\r
1522 );\r
1523\r
1524 //\r
1525 // Perform a read to cleanup the Status Register's\r
1526 // output buffer full bits within MAX TRY times\r
1527 //\r
1528 if ((KeyReadStatusRegister (ConsoleIn) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA) != 0) {\r
1529 while (!EFI_ERROR (Status) && TryTime < KEYBOARD_MAX_TRY) {\r
1530 Status = KeyboardRead (ConsoleIn, &CommandByte);\r
1531 TryTime ++;\r
1532 }\r
1533 //\r
1534 // Exceed the max try times. The device may be error.\r
1535 //\r
1536 if (TryTime == KEYBOARD_MAX_TRY) {\r
1537 Status = EFI_DEVICE_ERROR;\r
1538 goto Done;\r
1539 }\r
1540 }\r
1541 //\r
1542 // We should disable mouse interface during the initialization process\r
1543 // since mouse device output could block keyboard device output in the\r
1544 // 60H port of 8042 controller.\r
1545 //\r
1546 // So if we are not initializing 8042 controller for the\r
1547 // first time, we have to remember the previous mouse interface\r
1548 // enabling state\r
1549 //\r
1550 // Test the system flag in to determine whether this is the first\r
1551 // time initialization\r
1552 //\r
1553 if ((KeyReadStatusRegister (ConsoleIn) & KEYBOARD_STATUS_REGISTER_SYSTEM_FLAG) != 0) {\r
1554 if (!PcdGetBool (PcdFastPS2Detection)) {\r
1555 //\r
1556 // 8042 controller is already setup (by myself or by mouse driver):\r
1557 // See whether mouse interface is already enabled\r
1558 // which determines whether we should enable it later\r
1559 //\r
1560 //\r
1561 // Read the command byte of 8042 controller\r
1562 //\r
1563 Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_READ);\r
1564 if (EFI_ERROR (Status)) {\r
1565 KeyboardError (ConsoleIn, L"\n\r");\r
1566 goto Done;\r
1567 }\r
1568 \r
1569 Status = KeyboardRead (ConsoleIn, &CommandByte);\r
1570 if (EFI_ERROR (Status)) {\r
1571 KeyboardError (ConsoleIn, L"\n\r");\r
1572 goto Done;\r
1573 }\r
1574 //\r
1575 // Test the mouse enabling bit\r
1576 //\r
1577 if ((CommandByte & 0x20) != 0) {\r
1578 mEnableMouseInterface = FALSE;\r
1579 } else {\r
1580 mEnableMouseInterface = TRUE;\r
1581 }\r
1582 } else {\r
1583 mEnableMouseInterface = FALSE;\r
1584 } \r
1585 } else {\r
1586 //\r
1587 // 8042 controller is not setup yet:\r
1588 // 8042 controller selftest;\r
1589 // Don't enable mouse interface later.\r
1590 //\r
1591 //\r
1592 // Disable keyboard and mouse interfaces\r
1593 //\r
1594 if (!PcdGetBool (PcdFastPS2Detection)) {\r
1595 Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE);\r
1596 if (EFI_ERROR (Status)) {\r
1597 KeyboardError (ConsoleIn, L"\n\r");\r
1598 goto Done;\r
1599 }\r
1600 \r
1601 Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_DISABLE_MOUSE_INTERFACE);\r
1602 if (EFI_ERROR (Status)) {\r
1603 KeyboardError (ConsoleIn, L"\n\r");\r
1604 goto Done;\r
1605 }\r
1606 \r
1607 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1608 EFI_PROGRESS_CODE,\r
1609 EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST,\r
1610 ConsoleIn->DevicePath\r
1611 );\r
1612 //\r
1613 // 8042 Controller Self Test\r
1614 //\r
1615 Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_CONTROLLER_SELF_TEST);\r
1616 if (EFI_ERROR (Status)) {\r
1617 KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");\r
1618 goto Done;\r
1619 }\r
1620 \r
1621 Status = KeyboardWaitForValue (ConsoleIn, 0x55);\r
1622 if (EFI_ERROR (Status)) {\r
1623 KeyboardError (ConsoleIn, L"8042 controller self test failed!\n\r");\r
1624 goto Done;\r
1625 }\r
1626 }\r
1627 //\r
1628 // Don't enable mouse interface later\r
1629 //\r
1630 mEnableMouseInterface = FALSE;\r
1631\r
1632 }\r
1633\r
1634 if (Ps2Policy != NULL) {\r
1635 Ps2Policy->Ps2InitHardware (ConsoleIn->Handle);\r
1636 }\r
1637 //\r
1638 // Write 8042 Command Byte, set System Flag\r
1639 // While at the same time:\r
1640 // 1. disable mouse interface,\r
1641 // 2. enable kbd interface,\r
1642 // 3. enable PC/XT kbd translation mode\r
1643 // 4. enable mouse and kbd interrupts\r
1644 //\r
1645 // ( Command Byte bits:\r
1646 // 7: Reserved\r
1647 // 6: PC/XT translation mode\r
1648 // 5: Disable Auxiliary device interface\r
1649 // 4: Disable keyboard interface\r
1650 // 3: Reserved\r
1651 // 2: System Flag\r
1652 // 1: Enable Auxiliary device interrupt\r
1653 // 0: Enable Keyboard interrupt )\r
1654 //\r
1655 Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_WRITE);\r
1656 if (EFI_ERROR (Status)) {\r
1657 KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");\r
1658 goto Done;\r
1659 }\r
1660\r
1661 Status = KeyboardWrite (ConsoleIn, 0x67);\r
1662 if (EFI_ERROR (Status)) {\r
1663 KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");\r
1664 goto Done;\r
1665 }\r
1666\r
1667 //\r
1668 // Clear Memory Scancode Buffer\r
1669 //\r
1670 ConsoleIn->ScancodeQueue.Head = 0;\r
1671 ConsoleIn->ScancodeQueue.Tail = 0;\r
1672 ConsoleIn->EfiKeyQueue.Head = 0;\r
1673 ConsoleIn->EfiKeyQueue.Tail = 0;\r
1674 ConsoleIn->EfiKeyQueueForNotify.Head = 0;\r
1675 ConsoleIn->EfiKeyQueueForNotify.Tail = 0;\r
1676\r
1677 //\r
1678 // Reset the status indicators\r
1679 //\r
1680 ConsoleIn->CapsLock = FALSE;\r
1681 ConsoleIn->NumLock = FALSE;\r
1682 ConsoleIn->ScrollLock = FALSE;\r
1683 ConsoleIn->LeftCtrl = FALSE;\r
1684 ConsoleIn->RightCtrl = FALSE;\r
1685 ConsoleIn->LeftAlt = FALSE;\r
1686 ConsoleIn->RightAlt = FALSE;\r
1687 ConsoleIn->LeftShift = FALSE;\r
1688 ConsoleIn->RightShift = FALSE;\r
1689 ConsoleIn->LeftLogo = FALSE;\r
1690 ConsoleIn->RightLogo = FALSE;\r
1691 ConsoleIn->Menu = FALSE;\r
1692 ConsoleIn->SysReq = FALSE;\r
1693\r
1694 ConsoleIn->IsSupportPartialKey = FALSE;\r
1695 //\r
1696 // For resetting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,\r
1697 // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected\r
1698 // to system. So we only do the real resetting for keyboard when user asks and there is a real KB connected t system,\r
1699 // and normally during booting an OS, it's skipped.\r
1700 //\r
1701 if (ExtendedVerification && CheckKeyboardConnect (ConsoleIn)) {\r
1702 //\r
1703 // Additional verifications for keyboard interface\r
1704 //\r
1705 //\r
1706 // Keyboard Interface Test\r
1707 //\r
1708 Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_KEYBOARD_INTERFACE_SELF_TEST);\r
1709 if (EFI_ERROR (Status)) {\r
1710 KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");\r
1711 goto Done;\r
1712 }\r
1713\r
1714 Status = KeyboardWaitForValue (ConsoleIn, 0x00);\r
1715 if (EFI_ERROR (Status)) {\r
1716 KeyboardError (\r
1717 ConsoleIn,\r
1718 L"Some specific value not aquired from 8042 controller!\n\r"\r
1719 );\r
1720 goto Done;\r
1721 }\r
1722 //\r
1723 // Keyboard reset with a BAT(Basic Assurance Test)\r
1724 //\r
1725 Status = KeyboardWrite (ConsoleIn, KEYBOARD_8048_COMMAND_RESET);\r
1726 if (EFI_ERROR (Status)) {\r
1727 KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");\r
1728 goto Done;\r
1729 }\r
1730\r
1731 Status = KeyboardWaitForValue (ConsoleIn, KEYBOARD_8048_RETURN_8042_ACK);\r
1732 if (EFI_ERROR (Status)) {\r
1733 KeyboardError (ConsoleIn, L"Some specific value not aquired from 8042 controller!\n\r");\r
1734 goto Done;\r
1735 }\r
1736 //\r
1737 // wait for BAT completion code\r
1738 //\r
1739 mWaitForValueTimeOut = KEYBOARD_BAT_TIMEOUT;\r
1740\r
1741 Status = KeyboardWaitForValue (ConsoleIn, KEYBOARD_8048_RETURN_8042_BAT_SUCCESS);\r
1742 if (EFI_ERROR (Status)) {\r
1743 KeyboardError (ConsoleIn, L"Keyboard self test failed!\n\r");\r
1744 goto Done;\r
1745 }\r
1746\r
1747 mWaitForValueTimeOut = KEYBOARD_WAITFORVALUE_TIMEOUT;\r
1748\r
1749 //\r
1750 // Set Keyboard to use Scan Code Set 2\r
1751 //\r
1752 Status = KeyboardWrite (ConsoleIn, KEYBOARD_8048_COMMAND_SELECT_SCAN_CODE_SET);\r
1753 if (EFI_ERROR (Status)) {\r
1754 KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");\r
1755 goto Done;\r
1756 }\r
1757\r
1758 Status = KeyboardWaitForValue (ConsoleIn, KEYBOARD_8048_RETURN_8042_ACK);\r
1759 if (EFI_ERROR (Status)) {\r
1760 KeyboardError (ConsoleIn, L"Some specific value not aquired from 8042 controller!\n\r");\r
1761 goto Done;\r
1762 }\r
1763\r
1764 Status = KeyboardWrite (ConsoleIn, 0x02);\r
1765 if (EFI_ERROR (Status)) {\r
1766 KeyboardError (ConsoleIn, L"8042 controller data write error!!\n\r");\r
1767 goto Done;\r
1768 }\r
1769\r
1770 Status = KeyboardWaitForValue (ConsoleIn, KEYBOARD_8048_RETURN_8042_ACK);\r
1771 if (EFI_ERROR (Status)) {\r
1772 KeyboardError (ConsoleIn, L"Some specific value not aquired from 8042 controller!\n\r");\r
1773 goto Done;\r
1774 }\r
1775\r
1776 //\r
1777 // Clear Keyboard Scancode Buffer\r
1778 //\r
1779 Status = KeyboardWrite (ConsoleIn, KEYBOARD_8048_COMMAND_CLEAR_OUTPUT_DATA);\r
1780 if (EFI_ERROR (Status)) {\r
1781 KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");\r
1782 goto Done;\r
1783 }\r
1784\r
1785 Status = KeyboardWaitForValue (ConsoleIn, KEYBOARD_8048_RETURN_8042_ACK);\r
1786 if (EFI_ERROR (Status)) {\r
1787 KeyboardError (ConsoleIn, L"Some specific value not aquired from 8042 controller!\n\r");\r
1788 goto Done;\r
1789 }\r
1790 //\r
1791 if (Ps2Policy != NULL) {\r
1792 if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_CAPSLOCK) == EFI_KEYBOARD_CAPSLOCK) {\r
1793 ConsoleIn->CapsLock = TRUE;\r
1794 }\r
1795\r
1796 if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_NUMLOCK) == EFI_KEYBOARD_NUMLOCK) {\r
1797 ConsoleIn->NumLock = TRUE;\r
1798 }\r
1799\r
1800 if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_SCROLLLOCK) == EFI_KEYBOARD_SCROLLLOCK) {\r
1801 ConsoleIn->ScrollLock = TRUE;\r
1802 }\r
1803 }\r
1804 //\r
1805 // Update Keyboard Lights\r
1806 //\r
1807 Status = UpdateStatusLights (ConsoleIn);\r
1808 if (EFI_ERROR (Status)) {\r
1809 KeyboardError (ConsoleIn, L"Update keyboard status lights error!\n\r");\r
1810 goto Done;\r
1811 }\r
1812 }\r
1813 //\r
1814 // At last, we can now enable the mouse interface if appropriate\r
1815 //\r
1816Done:\r
1817\r
1818 if (mEnableMouseInterface) {\r
1819 //\r
1820 // Enable mouse interface\r
1821 //\r
1822 Status1 = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_ENABLE_MOUSE_INTERFACE);\r
1823 if (EFI_ERROR (Status1)) {\r
1824 KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");\r
1825 return EFI_DEVICE_ERROR;\r
1826 }\r
1827 }\r
1828\r
1829 if (!EFI_ERROR (Status)) {\r
1830 return EFI_SUCCESS;\r
1831 } else {\r
1832 return EFI_DEVICE_ERROR;\r
1833 }\r
1834\r
1835}\r
1836\r
1837/**\r
1838 Disable the keyboard interface of the 8042 controller.\r
1839\r
1840 @param ConsoleIn The device instance\r
1841\r
1842 @return status of issuing disable command\r
1843\r
1844**/\r
1845EFI_STATUS\r
1846DisableKeyboard (\r
1847 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn\r
1848 )\r
1849{\r
1850 EFI_STATUS Status;\r
1851\r
1852 //\r
1853 // Disable keyboard interface\r
1854 //\r
1855 Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE);\r
1856 if (EFI_ERROR (Status)) {\r
1857 KeyboardError (ConsoleIn, L"\n\r");\r
1858 return EFI_DEVICE_ERROR;\r
1859 }\r
1860\r
1861 return Status;\r
1862}\r
1863\r
1864/**\r
1865 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command\r
1866 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device\r
1867 should not be in system.\r
1868\r
1869 @param[in] ConsoleIn Keyboard Private Data Structure\r
1870\r
1871 @retval TRUE Keyboard in System.\r
1872 @retval FALSE Keyboard not in System.\r
1873**/\r
1874BOOLEAN\r
1875EFIAPI\r
1876CheckKeyboardConnect (\r
1877 IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn\r
1878 )\r
1879{\r
1880 EFI_STATUS Status;\r
1881 UINTN WaitForValueTimeOutBcakup;\r
1882\r
1883 //\r
1884 // enable keyboard itself and wait for its ack\r
1885 // If can't receive ack, Keyboard should not be connected.\r
1886 //\r
1887 if (!PcdGetBool (PcdFastPS2Detection)) {\r
1888 Status = KeyboardWrite (\r
1889 ConsoleIn,\r
1890 KEYBOARD_KBEN\r
1891 );\r
1892 \r
1893 if (EFI_ERROR (Status)) {\r
1894 return FALSE;\r
1895 }\r
1896 //\r
1897 // wait for 1s\r
1898 //\r
1899 WaitForValueTimeOutBcakup = mWaitForValueTimeOut;\r
1900 mWaitForValueTimeOut = KEYBOARD_WAITFORVALUE_TIMEOUT;\r
1901 Status = KeyboardWaitForValue (\r
1902 ConsoleIn,\r
1903 KEYBOARD_CMDECHO_ACK\r
1904 );\r
1905 mWaitForValueTimeOut = WaitForValueTimeOutBcakup;\r
1906 \r
1907 if (EFI_ERROR (Status)) {\r
1908 return FALSE;\r
1909 }\r
1910 \r
1911 return TRUE;\r
1912 } else {\r
1913 return TRUE;\r
1914 }\r
1915}\r
1916\r