3 Routines that access 8042 keyboard controller
5 Copyright (c) 2006 - 2007, Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "Ps2Keyboard.h"
19 // Function declarations
23 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
27 KeyWriteDataRegister (
28 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
33 KeyWriteCommandRegister (
34 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
40 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
41 IN CHAR16
*ErrMsg
// should be a unicode string
46 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
53 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
60 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
66 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
71 KeyboardWaitForValue (
72 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
80 CHAR16 ShiftUnicodeChar
;
82 ConvertKeyboardScanCodeToEfiKey
[] = {
409 0x37, // Numeric Keypad *
415 0x38, //Left Alt/Extended Right Alt
535 0x4c, // Numeric Keypad 5
622 // The WaitForValue time out
624 UINTN mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
629 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
631 @return return the value
635 KeyReadDataRegister (
636 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
640 EFI_ISA_IO_PROTOCOL
*IsaIo
;
644 // Use IsaIo protocol to perform IO operations
646 IsaIo
= ConsoleIn
->IsaIo
;
651 ConsoleIn
->DataRegisterAddress
,
662 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
663 @param Data value wanted to be written
667 KeyWriteDataRegister (
668 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
673 EFI_ISA_IO_PROTOCOL
*IsaIo
;
676 // Use IsaIo protocol to perform IO operations
678 IsaIo
= ConsoleIn
->IsaIo
;
683 ConsoleIn
->DataRegisterAddress
,
689 // outp(ConsoleIn->DataRegisterAddress, Data);
696 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
698 @return value in status register
702 KeyReadStatusRegister (
703 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
706 EFI_ISA_IO_PROTOCOL
*IsaIo
;
710 // Use IsaIo protocol to perform IO operations
712 IsaIo
= ConsoleIn
->IsaIo
;
717 ConsoleIn
->StatusRegisterAddress
,
727 Write command register
729 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
730 @param Data The value wanted to be written
735 KeyWriteCommandRegister (
736 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
740 EFI_ISA_IO_PROTOCOL
*IsaIo
;
743 // Use IsaIo protocol to perform IO operations
745 IsaIo
= ConsoleIn
->IsaIo
;
750 ConsoleIn
->CommandRegisterAddress
,
758 Display error message
760 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
761 @param ErrMsg Unicode string of error message
766 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
770 ConsoleIn
->KeyboardErr
= TRUE
;
773 // gST -> ConOut -> OutputString (gST -> ConOut, L"Keyboard Driver: ");
774 // gST -> ConOut -> OutputString (gST -> ConOut, ErrMsg);
779 Timer event handler: read a series of scancodes from 8042
780 and put them into memory scancode buffer.
781 it read as much scancodes to either fill
782 the memory buffer or empty the keyboard buffer.
783 It is registered as running under TPL_NOTIFY
785 @param Event - The timer event
786 @param Context - A KEYBOARD_CONSOLE_IN_DEV pointer
791 KeyboardTimerHandler (
799 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
804 // Enter critical section
806 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
808 if (((KEYBOARD_CONSOLE_IN_DEV
*) Context
)->KeyboardErr
) {
810 // Leave critical section and return
812 gBS
->RestoreTPL (OldTpl
);
816 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
817 // KB is not connected to system. If KB is not connected to system, driver will find there's something
818 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
819 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
820 // Just skip the 'resend' process simply.
826 // if there is no key present, just return
828 if ((KeyReadStatusRegister (Context
) & 0x21) != 0x1) {
830 // Leave critical section and return
832 gBS
->RestoreTPL (OldTpl
);
837 // Read one byte of the scan code and store it into the memory buffer
839 if (ConsoleIn
->ScancodeBufCount
< KEYBOARD_BUFFER_MAX_COUNT
) {
841 Data
= KeyReadDataRegister (Context
);
843 // put the scancode into the memory scancode buffer
845 ConsoleIn
->ScancodeBufCount
++;
846 ConsoleIn
->ScancodeBufEndPos
++;
847 if (ConsoleIn
->ScancodeBufEndPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
848 ConsoleIn
->ScancodeBufEndPos
= 0;
851 ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufEndPos
] = Data
;
854 // Handle Alt+Ctrl+Del Key combination
857 case SCANCODE_CTRL_MAKE
:
858 ConsoleIn
->Ctrled
= TRUE
;
861 case SCANCODE_CTRL_BREAK
:
862 ConsoleIn
->Ctrled
= FALSE
;
865 case SCANCODE_ALT_MAKE
:
866 ConsoleIn
->Alted
= TRUE
;
869 case SCANCODE_ALT_BREAK
:
870 ConsoleIn
->Alted
= FALSE
;
874 // if Alt+Ctrl+Del, Reboot the System
876 if (ConsoleIn
->Ctrled
&& ConsoleIn
->Alted
&& Data
== 0x53) {
877 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
881 // Leave critical section and return
883 gBS
->RestoreTPL (OldTpl
);
889 Read several bytes from the scancode buffer without removing them.
890 This function is called to see if there are enough bytes of scancode
891 representing a single key.
893 @param Count - Number of bytes to be read
894 @param Buf - Store the results
896 @retval EFI_SUCCESS success to scan the keyboard code
897 @retval EFI_NOT_READY invalid parameter
901 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
913 // check the valid range of parameter 'Count'
915 if (Count
<= 0 || ConsoleIn
->ScancodeBufCount
< Count
) {
916 return EFI_NOT_READY
;
919 // retrieve the values
921 for (Index
= 0; Index
< Count
; Index
++) {
925 Pos
= ConsoleIn
->ScancodeBufStartPos
;
929 if (Pos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
934 Buf
[Index
] = ConsoleIn
->ScancodeBuf
[Pos
];
942 Read & remove several bytes from the scancode buffer.
943 This function is usually called after GetScancodeBufHead()
945 @param Count - Number of bytes to be read
946 @param Buf - Store the results
948 @retval EFI_SUCCESS success to scan the keyboard code
949 @retval EFI_NOT_READY invalid parameter
953 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
963 // Check the valid range of parameter 'Count'
965 if (Count
<= 0 || ConsoleIn
->ScancodeBufCount
< Count
) {
966 return EFI_NOT_READY
;
969 // Retrieve and remove the values
971 for (Index
= 0; Index
< Count
; Index
++) {
975 ConsoleIn
->ScancodeBufStartPos
++;
976 if (ConsoleIn
->ScancodeBufStartPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
977 ConsoleIn
->ScancodeBufStartPos
= 0;
981 Buf
[Index
] = ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufStartPos
];
982 ConsoleIn
->ScancodeBufCount
--;
985 ConsoleIn
->ScancodeBufStartPos
++;
986 if (ConsoleIn
->ScancodeBufStartPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
987 ConsoleIn
->ScancodeBufStartPos
= 0;
996 @param ConsoleIn - Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
997 @param Data - Pointer to outof buffer for keeping key value
999 @retval EFI_TIMEOUT Status resigter time out
1000 @retval EFI_SUCCESS Success to read keyboard
1005 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1017 // wait till output buffer full then perform the read
1019 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1020 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1022 *Data
= KeyReadDataRegister (ConsoleIn
);
1037 write key to keyboard
1039 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1040 @param Data value wanted to be written
1042 @retval EFI_TIMEOUT - GC_TODO: Add description for return value
1043 @retval EFI_SUCCESS - GC_TODO: Add description for return value
1048 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1059 // wait for input buffer empty
1061 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1062 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x02)) {
1076 KeyWriteDataRegister (ConsoleIn
, Data
);
1082 Issue keyboard command
1084 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1085 @param Data The buff holding the command
1087 @retval EFI_TIMEOUT Keyboard is not ready to issuing
1088 @retval EFI_SUCCESS Success to issue keyboard command
1093 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1104 // Wait For Input Buffer Empty
1106 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1107 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x02)) {
1119 // issue the command
1121 KeyWriteCommandRegister (ConsoleIn
, Data
);
1124 // Wait For Input Buffer Empty again
1127 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1128 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x02)) {
1144 wait for a specific value to be presented on
1145 8042 Data register by keyboard and then read it,
1146 used in keyboard commands ack
1148 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1149 @param Value the value wanted to be waited.
1151 @retval EFI_TIMEOUT Fail to get specific value in given time
1152 @retval EFI_SUCCESS Success to get specific value in given time.
1156 KeyboardWaitForValue (
1157 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1171 // Make sure the initial value of 'Data' is different from 'Value'
1174 if (Data
== Value
) {
1178 // Read from 8042 (multiple times if needed)
1179 // until the expected value appears
1180 // use SumTimeOut to control the iteration
1186 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1187 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1188 Data
= KeyReadDataRegister (ConsoleIn
);
1195 SumTimeOut
+= TimeOut
;
1197 if (Data
== Value
) {
1202 if (SumTimeOut
>= mWaitForValueTimeOut
) {
1218 Show keyboard status lights according to
1219 indicators in ConsoleIn.
1221 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1227 UpdateStatusLights (
1228 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1235 // Send keyboard command
1237 Status
= KeyboardWrite (ConsoleIn
, 0xed);
1238 if (EFI_ERROR (Status
)) {
1242 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1245 // Light configuration
1248 if (ConsoleIn
->CapsLock
) {
1252 if (ConsoleIn
->NumLock
) {
1256 if (ConsoleIn
->ScrollLock
) {
1260 Status
= KeyboardWrite (ConsoleIn
, Command
);
1262 if (EFI_ERROR (Status
)) {
1266 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1271 Get scancode from scancode buffer
1272 and translate into EFI-scancode and unicode defined by EFI spec
1273 The function is always called in TPL_NOTIFY
1275 @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer
1277 @retval EFI_NOT_READY - Input from console not ready yet.
1278 @retval EFI_SUCCESS - Function executed successfully.
1283 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1290 UINT8 ScancodeArr
[4];
1295 UINT32 ScancodeArrPos
;
1297 // point to the current position in ScancodeArr
1305 // Read one byte of the scan code and store it into the memory buffer
1306 // This block of code is added to insert an action that is equivalent to
1307 // the timer event handling function, so as to increase the frequency of
1308 // detecting the availability of keys. Timer event has a max frequency of
1309 // 18Hz which is insufficient
1312 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
1313 // KB is not connected to system. If KB is not connected to system, driver will find there's something
1314 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
1315 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
1316 // Just skip the 'resend' process simply.
1320 if (((KeyReadStatusRegister (ConsoleIn
) & 0x21) == 0x1) && (ConsoleIn
->ScancodeBufCount
< KEYBOARD_BUFFER_MAX_COUNT
)) {
1322 Readed
= KeyReadDataRegister (ConsoleIn
);
1324 // put the scancode into the memory scancode buffer
1326 ConsoleIn
->ScancodeBufCount
++;
1327 ConsoleIn
->ScancodeBufEndPos
++;
1328 if (ConsoleIn
->ScancodeBufEndPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
1329 ConsoleIn
->ScancodeBufEndPos
= 0;
1332 ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufEndPos
] = Readed
;
1335 // Handle Alt+Ctrl+Del Key combination
1339 case SCANCODE_CTRL_MAKE
:
1340 ConsoleIn
->Ctrled
= TRUE
;
1343 case SCANCODE_CTRL_BREAK
:
1344 ConsoleIn
->Ctrled
= FALSE
;
1347 case SCANCODE_ALT_MAKE
:
1348 ConsoleIn
->Alted
= TRUE
;
1351 case SCANCODE_ALT_BREAK
:
1352 ConsoleIn
->Alted
= FALSE
;
1356 // if Alt+Ctrl+Del, Reboot the System
1358 if (ConsoleIn
->Ctrled
&& ConsoleIn
->Alted
&& Readed
== 0x53) {
1359 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1363 // Check if there are enough bytes of scancode representing a single key
1364 // available in the buffer
1368 Status
= GetScancodeBufHead (ConsoleIn
, 1, ScancodeArr
);
1370 if (EFI_ERROR (Status
)) {
1371 return EFI_NOT_READY
;
1374 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED
) {
1376 Status
= GetScancodeBufHead (ConsoleIn
, 2, ScancodeArr
);
1378 if (EFI_ERROR (Status
)) {
1379 return EFI_NOT_READY
;
1383 // Checks for key scancode for PAUSE:E1-1D/45-E1/9D-C5
1384 // if present, ignore them
1386 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED1
) {
1388 Status
= GetScancodeBufHead (ConsoleIn
, 2, ScancodeArr
);
1391 if (EFI_ERROR (Status
)) {
1392 return EFI_NOT_READY
;
1395 Status
= GetScancodeBufHead (ConsoleIn
, 3, ScancodeArr
);
1398 if (EFI_ERROR (Status
)) {
1399 return EFI_NOT_READY
;
1402 PopScancodeBufHead (ConsoleIn
, 3, ScancodeArr
);
1403 return EFI_NOT_READY
;
1406 // if we reach this position, scancodes for a key is in buffer now,pop them
1408 Status
= PopScancodeBufHead (ConsoleIn
, ScancodeArrPos
+ 1, ScancodeArr
);
1409 if (EFI_ERROR (Status
)) {
1410 return EFI_NOT_READY
;
1413 // store the last available byte, this byte of scancode will be checked
1415 ScanCode
= ScancodeArr
[ScancodeArrPos
];
1418 // Check for special keys and update the driver state.
1422 case SCANCODE_CTRL_MAKE
:
1423 ConsoleIn
->Ctrl
= TRUE
;
1426 case SCANCODE_CTRL_BREAK
:
1427 ConsoleIn
->Ctrl
= FALSE
;
1430 case SCANCODE_ALT_MAKE
:
1431 ConsoleIn
->Alt
= TRUE
;
1434 case SCANCODE_ALT_BREAK
:
1435 ConsoleIn
->Alt
= FALSE
;
1438 case SCANCODE_LEFT_SHIFT_MAKE
:
1440 ConsoleIn
->Shift
= TRUE
;
1441 ConsoleIn
->LeftShift
= TRUE
;
1444 case SCANCODE_RIGHT_SHIFT_MAKE
:
1446 ConsoleIn
->Shift
= TRUE
;
1447 ConsoleIn
->RightShift
= TRUE
;
1451 case SCANCODE_LEFT_SHIFT_BREAK
:
1453 ConsoleIn
->Shift
= FALSE
;
1454 ConsoleIn
->LeftShift
= FALSE
;
1456 ConsoleIn
->SysReq
= FALSE
;
1459 case SCANCODE_RIGHT_SHIFT_BREAK
:
1461 ConsoleIn
->Shift
= FALSE
;
1462 ConsoleIn
->RightShift
= FALSE
;
1466 case SCANCODE_LEFT_LOGO_MAKE
:
1467 ConsoleIn
->LeftLogo
= TRUE
;
1469 case SCANCODE_LEFT_LOGO_BREAK
:
1470 ConsoleIn
->LeftLogo
= FALSE
;
1472 case SCANCODE_RIGHT_LOGO_MAKE
:
1473 ConsoleIn
->RightLogo
= TRUE
;
1475 case SCANCODE_RIGHT_LOGO_BREAK
:
1476 ConsoleIn
->RightLogo
= FALSE
;
1478 case SCANCODE_MENU_MAKE
:
1479 ConsoleIn
->Menu
= TRUE
;
1481 case SCANCODE_MENU_BREAK
:
1482 ConsoleIn
->Menu
= FALSE
;
1484 case SCANCODE_SYS_REQ_MAKE
:
1486 ConsoleIn
->SysReq
= TRUE
;
1488 case SCANCODE_CAPS_LOCK_MAKE
:
1489 ConsoleIn
->CapsLock
= (BOOLEAN
)!ConsoleIn
->CapsLock
;
1490 UpdateStatusLights (ConsoleIn
);
1493 case SCANCODE_NUM_LOCK_MAKE
:
1494 ConsoleIn
->NumLock
= (BOOLEAN
)!ConsoleIn
->NumLock
;
1495 UpdateStatusLights (ConsoleIn
);
1498 case SCANCODE_SCROLL_LOCK_MAKE
:
1499 ConsoleIn
->ScrollLock
= (BOOLEAN
)!ConsoleIn
->ScrollLock
;
1500 UpdateStatusLights (ConsoleIn
);
1504 // If this is a BREAK Key or above the valid range, ignore it
1506 if (ScanCode
>= SCANCODE_MAX_MAKE
) {
1513 // Treat Numeric Key Pad "/" specially
1515 if (Extended
&& ScanCode
== 0x35) {
1516 ConsoleIn
->Key
.ScanCode
= SCAN_NULL
;
1517 ConsoleIn
->Key
.UnicodeChar
= '/';
1521 // Convert Keyboard ScanCode into an EFI Key
1523 for (Index
= 0; ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
!= TABLE_END
; Index
+= 1) {
1524 if (ScanCode
== ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
) {
1525 ConsoleIn
->Key
.ScanCode
= ConvertKeyboardScanCodeToEfiKey
[Index
].EfiScanCode
;
1526 if (ConsoleIn
->Shift
) {
1527 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1529 // Need not return associated shift state if a class of printable characters that
1530 // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
1532 if (ConsoleIn
->Key
.UnicodeChar
>= 'A' && ConsoleIn
->Key
.UnicodeChar
<= 'Z') {
1533 ConsoleIn
->LeftShift
= FALSE
;
1534 ConsoleIn
->RightShift
= FALSE
;
1537 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1540 // alphabetic key is affected by CapsLock State
1542 if (ConsoleIn
->CapsLock
) {
1543 if (ConsoleIn
->Key
.UnicodeChar
>= 'a' && ConsoleIn
->Key
.UnicodeChar
<= 'z') {
1544 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1545 } else if (ConsoleIn
->Key
.UnicodeChar
>= 'A' && ConsoleIn
->Key
.UnicodeChar
<= 'Z') {
1546 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1550 // Translate the CTRL-Alpha characters to their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
1552 if (ConsoleIn
->Ctrled
) {
1553 if (ConsoleIn
->Key
.UnicodeChar
>= 'a' && ConsoleIn
->Key
.UnicodeChar
<= 'z') {
1554 ConsoleIn
->Key
.UnicodeChar
= (UINT16
) (ConsoleIn
->Key
.UnicodeChar
- 'a' + 1);
1555 } else if (ConsoleIn
->Key
.UnicodeChar
>= 'A' && ConsoleIn
->Key
.UnicodeChar
<= 'Z') {
1556 ConsoleIn
->Key
.UnicodeChar
= (UINT16
) (ConsoleIn
->Key
.UnicodeChar
- 'A' + 1);
1565 // distinguish numeric key pad keys' 'up symbol' and 'down symbol'
1567 if (ScanCode
>= 0x47 && ScanCode
<= 0x53) {
1569 if (ConsoleIn
->NumLock
&& !ConsoleIn
->Shift
&& !Extended
) {
1570 ConsoleIn
->Key
.ScanCode
= SCAN_NULL
;
1571 } else if (ScanCode
!= 0x4a && ScanCode
!= 0x4e) {
1572 ConsoleIn
->Key
.UnicodeChar
= 0x00;
1576 // If the key can not be converted then just return.
1578 if (ConsoleIn
->Key
.ScanCode
== SCAN_NULL
&& ConsoleIn
->Key
.UnicodeChar
== 0x00) {
1579 return EFI_NOT_READY
;
1583 // Save the Shift/Toggle state
1585 if (ConsoleIn
->Ctrl
) {
1586 ConsoleIn
->KeyState
.KeyShiftState
|= (Extended
== TRUE
) ? EFI_RIGHT_CONTROL_PRESSED
: EFI_LEFT_CONTROL_PRESSED
;
1588 if (ConsoleIn
->Alt
) {
1589 ConsoleIn
->KeyState
.KeyShiftState
|= (Extended
== TRUE
) ? EFI_RIGHT_ALT_PRESSED
: EFI_LEFT_ALT_PRESSED
;
1591 if (ConsoleIn
->LeftShift
) {
1592 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_LEFT_SHIFT_PRESSED
;
1594 if (ConsoleIn
->RightShift
) {
1595 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_RIGHT_SHIFT_PRESSED
;
1597 if (ConsoleIn
->LeftLogo
) {
1598 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_LEFT_LOGO_PRESSED
;
1600 if (ConsoleIn
->RightLogo
) {
1601 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_RIGHT_LOGO_PRESSED
;
1603 if (ConsoleIn
->Menu
) {
1604 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_MENU_KEY_PRESSED
;
1606 if (ConsoleIn
->SysReq
) {
1607 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_SYS_REQ_PRESSED
;
1609 if (ConsoleIn
->CapsLock
) {
1610 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_CAPS_LOCK_ACTIVE
;
1612 if (ConsoleIn
->NumLock
) {
1613 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_NUM_LOCK_ACTIVE
;
1615 if (ConsoleIn
->ScrollLock
) {
1616 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_SCROLL_LOCK_ACTIVE
;
1623 Perform 8042 controller and keyboard Initialization
1624 If ExtendedVerification is TRUE, do additional test for
1625 the keyboard interface
1627 @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
1628 @param ExtendedVerification - indicates a thorough initialization
1630 @retval EFI_DEVICE_ERROR Fail to init keyboard
1631 @retval EFI_SUCCESS Success to init keyboard
1635 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1636 IN BOOLEAN ExtendedVerification
1642 STATIC BOOLEAN EnableMouseInterface
;
1643 EFI_PS2_POLICY_PROTOCOL
*Ps2Policy
;
1645 Status
= EFI_SUCCESS
;
1646 EnableMouseInterface
= TRUE
;
1649 // Get Ps2 policy to set this
1651 Status
= gBS
->LocateProtocol (
1652 &gEfiPs2PolicyProtocolGuid
,
1654 (VOID
**) &Ps2Policy
1657 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1659 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
,
1660 ConsoleIn
->DevicePath
1664 // Perform a read to cleanup the Status Register's
1665 // output buffer full bits
1667 while (!EFI_ERROR (Status
)) {
1668 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1671 // We should disable mouse interface during the initialization process
1672 // since mouse device output could block keyboard device output in the
1673 // 60H port of 8042 controller.
1675 // So if we are not initializing 8042 controller for the
1676 // first time, we have to remember the previous mouse interface
1679 // Test the system flag in to determine whether this is the first
1680 // time initialization
1682 if ((KeyReadStatusRegister (ConsoleIn
) & 0x04)) {
1684 // 8042 controller is already setup (by myself or by mouse driver):
1685 // See whether mouse interface is already enabled
1686 // which determines whether we should enable it later
1689 // Read the command byte of 8042 controller
1691 Status
= KeyboardCommand (ConsoleIn
, 0x20);
1692 if (EFI_ERROR (Status
)) {
1693 KeyboardError (ConsoleIn
, L
"\n\r");
1697 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1698 if (EFI_ERROR (Status
)) {
1699 KeyboardError (ConsoleIn
, L
"\n\r");
1703 // Test the mouse enabling bit
1705 if (CommandByte
& 0x20) {
1706 EnableMouseInterface
= FALSE
;
1708 EnableMouseInterface
= TRUE
;
1713 // 8042 controller is not setup yet:
1714 // 8042 controller selftest;
1715 // Don't enable mouse interface later.
1718 // Disable keyboard and mouse interfaces
1720 Status
= KeyboardCommand (ConsoleIn
, 0xad);
1721 if (EFI_ERROR (Status
)) {
1722 KeyboardError (ConsoleIn
, L
"\n\r");
1726 Status
= KeyboardCommand (ConsoleIn
, 0xa7);
1727 if (EFI_ERROR (Status
)) {
1728 KeyboardError (ConsoleIn
, L
"\n\r");
1732 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1734 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
,
1735 ConsoleIn
->DevicePath
1738 // 8042 Controller Self Test
1740 Status
= KeyboardCommand (ConsoleIn
, 0xaa);
1741 if (EFI_ERROR (Status
)) {
1742 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1746 Status
= KeyboardWaitForValue (ConsoleIn
, 0x55);
1747 if (EFI_ERROR (Status
)) {
1748 KeyboardError (ConsoleIn
, L
"8042 controller self test failed!\n\r");
1752 // Don't enable mouse interface later
1754 EnableMouseInterface
= FALSE
;
1758 if (Ps2Policy
!= NULL
) {
1759 Ps2Policy
->Ps2InitHardware (ConsoleIn
->Handle
);
1762 // Write 8042 Command Byte, set System Flag
1763 // While at the same time:
1764 // 1. disable mouse interface,
1765 // 2. enable kbd interface,
1766 // 3. enable PC/XT kbd translation mode
1767 // 4. enable mouse and kbd interrupts
1769 // ( Command Byte bits:
1771 // 6: PC/XT translation mode
1772 // 5: Disable Auxiliary device interface
1773 // 4: Disable keyboard interface
1776 // 1: Enable Auxiliary device interrupt
1777 // 0: Enable Keyboard interrupt )
1779 Status
= KeyboardCommand (ConsoleIn
, 0x60);
1780 if (EFI_ERROR (Status
)) {
1781 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1785 Status
= KeyboardWrite (ConsoleIn
, 0x67);
1786 if (EFI_ERROR (Status
)) {
1787 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1792 // Clear Memory Scancode Buffer
1794 ConsoleIn
->ScancodeBufStartPos
= 0;
1795 ConsoleIn
->ScancodeBufEndPos
= KEYBOARD_BUFFER_MAX_COUNT
- 1;
1796 ConsoleIn
->ScancodeBufCount
= 0;
1797 ConsoleIn
->Ctrled
= FALSE
;
1798 ConsoleIn
->Alted
= FALSE
;
1801 // Reset the status indicators
1803 ConsoleIn
->Ctrl
= FALSE
;
1804 ConsoleIn
->Alt
= FALSE
;
1805 ConsoleIn
->Shift
= FALSE
;
1806 ConsoleIn
->CapsLock
= FALSE
;
1807 ConsoleIn
->NumLock
= FALSE
;
1808 ConsoleIn
->ScrollLock
= FALSE
;
1809 ConsoleIn
->LeftShift
= FALSE
;
1810 ConsoleIn
->RightShift
= FALSE
;
1811 ConsoleIn
->LeftLogo
= FALSE
;
1812 ConsoleIn
->RightLogo
= FALSE
;
1813 ConsoleIn
->Menu
= FALSE
;
1814 ConsoleIn
->SysReq
= FALSE
;
1817 // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1818 // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected
1819 // to system. So we only do the real reseting for keyboard when user asks and there is a real KB connected t system,
1820 // and normally during booting an OS, it's skipped.
1822 if (ExtendedVerification
&& CheckKeyboardConnect (ConsoleIn
)) {
1824 // Additional verifications for keyboard interface
1827 // Keyboard Interface Test
1829 Status
= KeyboardCommand (ConsoleIn
, 0xab);
1830 if (EFI_ERROR (Status
)) {
1831 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1835 Status
= KeyboardWaitForValue (ConsoleIn
, 0x00);
1836 if (EFI_ERROR (Status
)) {
1839 L
"Some specific value not aquired from 8042 controller!\n\r"
1844 // Keyboard reset with a BAT(Basic Assurance Test)
1846 Status
= KeyboardWrite (ConsoleIn
, 0xff);
1847 if (EFI_ERROR (Status
)) {
1848 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1852 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1853 if (EFI_ERROR (Status
)) {
1854 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1858 // wait for BAT completion code
1860 mWaitForValueTimeOut
= KEYBOARD_BAT_TIMEOUT
;
1862 Status
= KeyboardWaitForValue (ConsoleIn
, 0xaa);
1863 if (EFI_ERROR (Status
)) {
1864 KeyboardError (ConsoleIn
, L
"Keyboard self test failed!\n\r");
1868 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1871 // Set Keyboard to use Scan Code Set 2
1873 Status
= KeyboardWrite (ConsoleIn
, 0xf0);
1874 if (EFI_ERROR (Status
)) {
1875 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1879 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1880 if (EFI_ERROR (Status
)) {
1881 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1885 Status
= KeyboardWrite (ConsoleIn
, 0x02);
1886 if (EFI_ERROR (Status
)) {
1887 KeyboardError (ConsoleIn
, L
"8042 controller data write error!!\n\r");
1891 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1892 if (EFI_ERROR (Status
)) {
1893 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1898 // Clear Keyboard Scancode Buffer
1900 Status
= KeyboardWrite (ConsoleIn
, 0xf4);
1901 if (EFI_ERROR (Status
)) {
1902 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1906 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1907 if (EFI_ERROR (Status
)) {
1908 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1912 if (Ps2Policy
!= NULL
) {
1913 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_CAPSLOCK
) == EFI_KEYBOARD_CAPSLOCK
) {
1914 ConsoleIn
->CapsLock
= TRUE
;
1917 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_NUMLOCK
) == EFI_KEYBOARD_NUMLOCK
) {
1918 ConsoleIn
->NumLock
= TRUE
;
1921 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_SCROLLLOCK
) == EFI_KEYBOARD_SCROLLLOCK
) {
1922 ConsoleIn
->ScrollLock
= TRUE
;
1926 // Update Keyboard Lights
1928 Status
= UpdateStatusLights (ConsoleIn
);
1929 if (EFI_ERROR (Status
)) {
1930 KeyboardError (ConsoleIn
, L
"Update keyboard status lights error!\n\r");
1935 // At last, we can now enable the mouse interface if appropriate
1939 if (EnableMouseInterface
) {
1941 // Enable mouse interface
1943 Status1
= KeyboardCommand (ConsoleIn
, 0xa8);
1944 if (EFI_ERROR (Status1
)) {
1945 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1946 return EFI_DEVICE_ERROR
;
1950 if (!EFI_ERROR (Status
)) {
1953 return EFI_DEVICE_ERROR
;
1959 Disable the keyboard interface of the 8042 controller
1961 @param ConsoleIn - the device instance
1963 @return status of issuing disable command
1968 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1974 // Disable keyboard interface
1976 Status
= KeyboardCommand (ConsoleIn
, 0xad);
1977 if (EFI_ERROR (Status
)) {
1978 KeyboardError (ConsoleIn
, L
"\n\r");
1979 return EFI_DEVICE_ERROR
;
1986 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
1987 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
1988 should not be in system.
1990 @param[in] ConsoleIn Keyboard Private Data Structure
1992 @retval TRUE Keyboard in System.
1993 @retval FALSE Keyboard not in System.
1997 CheckKeyboardConnect (
1998 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
2002 UINTN WaitForValueTimeOutBcakup
;
2004 Status
= EFI_SUCCESS
;
2006 // enable keyboard itself and wait for its ack
2007 // If can't receive ack, Keyboard should not be connected.
2009 Status
= KeyboardWrite (
2014 if (EFI_ERROR (Status
)) {
2020 WaitForValueTimeOutBcakup
= mWaitForValueTimeOut
;
2021 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
2022 Status
= KeyboardWaitForValue (
2024 KEYBOARD_CMDECHO_ACK
2026 mWaitForValueTimeOut
= WaitForValueTimeOutBcakup
;
2028 if (EFI_ERROR (Status
)) {