2 Routines that access 8042 keyboard controller
4 Copyright (c) 2006 - 2007, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "Ps2Keyboard.h"
18 UINT8 ScanCode
; ///< follows value defined in Scan Code Set1
21 CHAR16 ShiftUnicodeChar
;
23 ConvertKeyboardScanCodeToEfiKey
[] = {
350 0x37, // Numeric Keypad *
356 0x38, //Left Alt/Extended Right Alt
476 0x4c, // Numeric Keypad 5
563 // The WaitForValue time out
565 UINTN mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
567 BOOLEAN mEnableMouseInterface
;
572 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
574 @return return the value
578 KeyReadDataRegister (
579 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
583 EFI_ISA_IO_PROTOCOL
*IsaIo
;
587 // Use IsaIo protocol to perform IO operations
589 IsaIo
= ConsoleIn
->IsaIo
;
594 ConsoleIn
->DataRegisterAddress
,
605 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
606 @param Data value wanted to be written
610 KeyWriteDataRegister (
611 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
616 EFI_ISA_IO_PROTOCOL
*IsaIo
;
619 // Use IsaIo protocol to perform IO operations
621 IsaIo
= ConsoleIn
->IsaIo
;
626 ConsoleIn
->DataRegisterAddress
,
636 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
638 @return value in status register
642 KeyReadStatusRegister (
643 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
646 EFI_ISA_IO_PROTOCOL
*IsaIo
;
650 // Use IsaIo protocol to perform IO operations
652 IsaIo
= ConsoleIn
->IsaIo
;
657 ConsoleIn
->StatusRegisterAddress
,
667 Write command register
669 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
670 @param Data The value wanted to be written
675 KeyWriteCommandRegister (
676 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
680 EFI_ISA_IO_PROTOCOL
*IsaIo
;
683 // Use IsaIo protocol to perform IO operations
685 IsaIo
= ConsoleIn
->IsaIo
;
690 ConsoleIn
->CommandRegisterAddress
,
698 Display error message
700 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
701 @param ErrMsg Unicode string of error message
706 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
710 ConsoleIn
->KeyboardErr
= TRUE
;
714 Timer event handler: read a series of scancodes from 8042
715 and put them into memory scancode buffer.
716 it read as much scancodes to either fill
717 the memory buffer or empty the keyboard buffer.
718 It is registered as running under TPL_NOTIFY
720 @param Event The timer event
721 @param Context A KEYBOARD_CONSOLE_IN_DEV pointer
726 KeyboardTimerHandler (
734 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
739 // Enter critical section
741 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
743 if (((KEYBOARD_CONSOLE_IN_DEV
*) Context
)->KeyboardErr
) {
745 // Leave critical section and return
747 gBS
->RestoreTPL (OldTpl
);
752 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
753 // KB is not connected to system. If KB is not connected to system, driver will find there's something
754 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
755 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
756 // Just skip the 'resend' process simply.
762 // if there is no key present, just return
764 if ((KeyReadStatusRegister (Context
) & (KEYBOARD_STATUS_REGISTER_TRANSMIT_TIMEOUT
|KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
)) != KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
) {
766 // Leave critical section and return
768 gBS
->RestoreTPL (OldTpl
);
773 // Read one byte of the scan code and store it into the memory buffer
775 if (ConsoleIn
->ScancodeBufCount
< KEYBOARD_BUFFER_MAX_COUNT
) {
777 Data
= KeyReadDataRegister (Context
);
779 // put the scancode into the memory scancode buffer
781 ConsoleIn
->ScancodeBufCount
++;
782 ConsoleIn
->ScancodeBufEndPos
++;
783 if (ConsoleIn
->ScancodeBufEndPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
784 ConsoleIn
->ScancodeBufEndPos
= 0;
787 ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufEndPos
] = Data
;
790 // Handle Alt+Ctrl+Del Key combination
793 case SCANCODE_CTRL_MAKE
:
794 ConsoleIn
->Ctrled
= TRUE
;
797 case SCANCODE_CTRL_BREAK
:
798 ConsoleIn
->Ctrled
= FALSE
;
801 case SCANCODE_ALT_MAKE
:
802 ConsoleIn
->Alted
= TRUE
;
805 case SCANCODE_ALT_BREAK
:
806 ConsoleIn
->Alted
= FALSE
;
810 // if Alt+Ctrl+Del, Reboot the System
812 if (ConsoleIn
->Ctrled
&& ConsoleIn
->Alted
&& Data
== 0x53) {
813 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
817 // Leave critical section and return
819 gBS
->RestoreTPL (OldTpl
);
825 Read several bytes from the scancode buffer without removing them.
826 This function is called to see if there are enough bytes of scancode
827 representing a single key.
829 @param Count - Number of bytes to be read
830 @param Buf - Store the results
832 @retval EFI_SUCCESS success to scan the keyboard code
833 @retval EFI_NOT_READY invalid parameter
837 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
849 // check the valid range of parameter 'Count'
851 if (Count
<= 0 || ConsoleIn
->ScancodeBufCount
< Count
) {
852 return EFI_NOT_READY
;
855 // retrieve the values
857 for (Index
= 0; Index
< Count
; Index
++) {
861 Pos
= ConsoleIn
->ScancodeBufStartPos
;
865 if (Pos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
870 Buf
[Index
] = ConsoleIn
->ScancodeBuf
[Pos
];
878 Read & remove several bytes from the scancode buffer.
879 This function is usually called after GetScancodeBufHead()
881 @param Count - Number of bytes to be read
882 @param Buf - Store the results
884 @retval EFI_SUCCESS success to scan the keyboard code
885 @retval EFI_NOT_READY invalid parameter
889 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
899 // Check the valid range of parameter 'Count'
901 if (Count
<= 0 || ConsoleIn
->ScancodeBufCount
< Count
) {
902 return EFI_NOT_READY
;
905 // Retrieve and remove the values
907 for (Index
= 0; Index
< Count
; Index
++) {
911 ConsoleIn
->ScancodeBufStartPos
++;
912 if (ConsoleIn
->ScancodeBufStartPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
913 ConsoleIn
->ScancodeBufStartPos
= 0;
917 Buf
[Index
] = ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufStartPos
];
918 ConsoleIn
->ScancodeBufCount
--;
921 ConsoleIn
->ScancodeBufStartPos
++;
922 if (ConsoleIn
->ScancodeBufStartPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
923 ConsoleIn
->ScancodeBufStartPos
= 0;
932 @param ConsoleIn - Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
933 @param Data - Pointer to outof buffer for keeping key value
935 @retval EFI_TIMEOUT Status resigter time out
936 @retval EFI_SUCCESS Success to read keyboard
941 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
953 // wait till output buffer full then perform the read
955 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
956 if (KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
) {
958 *Data
= KeyReadDataRegister (ConsoleIn
);
962 MicroSecondDelay (30);
973 write key to keyboard
975 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
976 @param Data value wanted to be written
978 @retval EFI_TIMEOUT The input buffer register is full for putting new value util timeout
979 @retval EFI_SUCCESS The new value is sucess put into input buffer register.
984 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
995 // wait for input buffer empty
997 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
998 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x02)) {
1003 MicroSecondDelay (30);
1012 KeyWriteDataRegister (ConsoleIn
, Data
);
1018 Issue keyboard command
1020 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1021 @param Data The buff holding the command
1023 @retval EFI_TIMEOUT Keyboard is not ready to issuing
1024 @retval EFI_SUCCESS Success to issue keyboard command
1029 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1040 // Wait For Input Buffer Empty
1042 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1043 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x02)) {
1048 MicroSecondDelay (30);
1055 // issue the command
1057 KeyWriteCommandRegister (ConsoleIn
, Data
);
1060 // Wait For Input Buffer Empty again
1063 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1064 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x02)) {
1069 MicroSecondDelay (30);
1080 wait for a specific value to be presented on
1081 8042 Data register by keyboard and then read it,
1082 used in keyboard commands ack
1084 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1085 @param Value the value wanted to be waited.
1087 @retval EFI_TIMEOUT Fail to get specific value in given time
1088 @retval EFI_SUCCESS Success to get specific value in given time.
1092 KeyboardWaitForValue (
1093 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1107 // Make sure the initial value of 'Data' is different from 'Value'
1110 if (Data
== Value
) {
1114 // Read from 8042 (multiple times if needed)
1115 // until the expected value appears
1116 // use SumTimeOut to control the iteration
1122 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1123 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1124 Data
= KeyReadDataRegister (ConsoleIn
);
1128 MicroSecondDelay (30);
1131 SumTimeOut
+= TimeOut
;
1133 if (Data
== Value
) {
1138 if (SumTimeOut
>= mWaitForValueTimeOut
) {
1154 Show keyboard status lights according to
1155 indicators in ConsoleIn.
1157 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1159 @return status of updating keyboard register
1163 UpdateStatusLights (
1164 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1171 // Send keyboard command
1173 Status
= KeyboardWrite (ConsoleIn
, 0xed);
1174 if (EFI_ERROR (Status
)) {
1178 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1181 // Light configuration
1184 if (ConsoleIn
->CapsLock
) {
1188 if (ConsoleIn
->NumLock
) {
1192 if (ConsoleIn
->ScrollLock
) {
1196 Status
= KeyboardWrite (ConsoleIn
, Command
);
1198 if (EFI_ERROR (Status
)) {
1202 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1207 Get scancode from scancode buffer
1208 and translate into EFI-scancode and unicode defined by EFI spec
1209 The function is always called in TPL_NOTIFY
1211 @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer
1213 @retval EFI_NOT_READY Input from console not ready yet.
1214 @retval EFI_SUCCESS Function executed successfully.
1219 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1226 UINT8 ScancodeArr
[4];
1231 UINT32 ScancodeArrPos
;
1233 // point to the current position in ScancodeArr
1241 // Read one byte of the scan code and store it into the memory buffer
1242 // This block of code is added to insert an action that is equivalent to
1243 // the timer event handling function, so as to increase the frequency of
1244 // detecting the availability of keys. Timer event has a max frequency of
1245 // 18Hz which is insufficient
1248 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
1249 // KB is not connected to system. If KB is not connected to system, driver will find there's something
1250 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
1251 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
1252 // Just skip the 'resend' process simply.
1256 if (((KeyReadStatusRegister (ConsoleIn
) & 0x21) == 0x1) && (ConsoleIn
->ScancodeBufCount
< KEYBOARD_BUFFER_MAX_COUNT
)) {
1258 Readed
= KeyReadDataRegister (ConsoleIn
);
1260 // put the scancode into the memory scancode buffer
1262 ConsoleIn
->ScancodeBufCount
++;
1263 ConsoleIn
->ScancodeBufEndPos
++;
1264 if (ConsoleIn
->ScancodeBufEndPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
1265 ConsoleIn
->ScancodeBufEndPos
= 0;
1268 ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufEndPos
] = Readed
;
1271 // Handle Alt+Ctrl+Del Key combination
1275 case SCANCODE_CTRL_MAKE
:
1276 ConsoleIn
->Ctrled
= TRUE
;
1279 case SCANCODE_CTRL_BREAK
:
1280 ConsoleIn
->Ctrled
= FALSE
;
1283 case SCANCODE_ALT_MAKE
:
1284 ConsoleIn
->Alted
= TRUE
;
1287 case SCANCODE_ALT_BREAK
:
1288 ConsoleIn
->Alted
= FALSE
;
1292 // if Alt+Ctrl+Del, Reboot the System
1294 if (ConsoleIn
->Ctrled
&& ConsoleIn
->Alted
&& Readed
== 0x53) {
1295 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1299 // Check if there are enough bytes of scancode representing a single key
1300 // available in the buffer
1304 Status
= GetScancodeBufHead (ConsoleIn
, 1, ScancodeArr
);
1306 if (EFI_ERROR (Status
)) {
1307 return EFI_NOT_READY
;
1310 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED
) {
1312 Status
= GetScancodeBufHead (ConsoleIn
, 2, ScancodeArr
);
1314 if (EFI_ERROR (Status
)) {
1315 return EFI_NOT_READY
;
1319 // Checks for key scancode for PAUSE:E1-1D/45-E1/9D-C5
1320 // if present, ignore them
1322 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED1
) {
1324 Status
= GetScancodeBufHead (ConsoleIn
, 2, ScancodeArr
);
1327 if (EFI_ERROR (Status
)) {
1328 return EFI_NOT_READY
;
1331 Status
= GetScancodeBufHead (ConsoleIn
, 3, ScancodeArr
);
1334 if (EFI_ERROR (Status
)) {
1335 return EFI_NOT_READY
;
1338 PopScancodeBufHead (ConsoleIn
, 3, ScancodeArr
);
1339 return EFI_NOT_READY
;
1342 // if we reach this position, scancodes for a key is in buffer now,pop them
1344 Status
= PopScancodeBufHead (ConsoleIn
, ScancodeArrPos
+ 1, ScancodeArr
);
1345 if (EFI_ERROR (Status
)) {
1346 return EFI_NOT_READY
;
1349 // store the last available byte, this byte of scancode will be checked
1351 ScanCode
= ScancodeArr
[ScancodeArrPos
];
1354 // Check for special keys and update the driver state.
1358 case SCANCODE_CTRL_MAKE
:
1359 ConsoleIn
->Ctrl
= TRUE
;
1362 case SCANCODE_CTRL_BREAK
:
1363 ConsoleIn
->Ctrl
= FALSE
;
1366 case SCANCODE_ALT_MAKE
:
1367 ConsoleIn
->Alt
= TRUE
;
1370 case SCANCODE_ALT_BREAK
:
1371 ConsoleIn
->Alt
= FALSE
;
1374 case SCANCODE_LEFT_SHIFT_MAKE
:
1376 ConsoleIn
->Shift
= TRUE
;
1377 ConsoleIn
->LeftShift
= TRUE
;
1380 case SCANCODE_RIGHT_SHIFT_MAKE
:
1382 ConsoleIn
->Shift
= TRUE
;
1383 ConsoleIn
->RightShift
= TRUE
;
1387 case SCANCODE_LEFT_SHIFT_BREAK
:
1389 ConsoleIn
->Shift
= FALSE
;
1390 ConsoleIn
->LeftShift
= FALSE
;
1392 ConsoleIn
->SysReq
= FALSE
;
1395 case SCANCODE_RIGHT_SHIFT_BREAK
:
1397 ConsoleIn
->Shift
= FALSE
;
1398 ConsoleIn
->RightShift
= FALSE
;
1402 case SCANCODE_LEFT_LOGO_MAKE
:
1403 ConsoleIn
->LeftLogo
= TRUE
;
1405 case SCANCODE_LEFT_LOGO_BREAK
:
1406 ConsoleIn
->LeftLogo
= FALSE
;
1408 case SCANCODE_RIGHT_LOGO_MAKE
:
1409 ConsoleIn
->RightLogo
= TRUE
;
1411 case SCANCODE_RIGHT_LOGO_BREAK
:
1412 ConsoleIn
->RightLogo
= FALSE
;
1414 case SCANCODE_MENU_MAKE
:
1415 ConsoleIn
->Menu
= TRUE
;
1417 case SCANCODE_MENU_BREAK
:
1418 ConsoleIn
->Menu
= FALSE
;
1420 case SCANCODE_SYS_REQ_MAKE
:
1422 ConsoleIn
->SysReq
= TRUE
;
1424 case SCANCODE_CAPS_LOCK_MAKE
:
1425 ConsoleIn
->CapsLock
= (BOOLEAN
)!ConsoleIn
->CapsLock
;
1426 UpdateStatusLights (ConsoleIn
);
1429 case SCANCODE_NUM_LOCK_MAKE
:
1430 ConsoleIn
->NumLock
= (BOOLEAN
)!ConsoleIn
->NumLock
;
1431 UpdateStatusLights (ConsoleIn
);
1434 case SCANCODE_SCROLL_LOCK_MAKE
:
1435 ConsoleIn
->ScrollLock
= (BOOLEAN
)!ConsoleIn
->ScrollLock
;
1436 UpdateStatusLights (ConsoleIn
);
1440 // If this is a BREAK Key or above the valid range, ignore it
1442 if (ScanCode
>= SCANCODE_MAX_MAKE
) {
1449 // Treat Numeric Key Pad "/" specially
1451 if (Extended
&& ScanCode
== 0x35) {
1452 ConsoleIn
->Key
.ScanCode
= SCAN_NULL
;
1453 ConsoleIn
->Key
.UnicodeChar
= L
'/';
1457 // Convert Keyboard ScanCode into an EFI Key
1459 for (Index
= 0; ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
!= TABLE_END
; Index
+= 1) {
1460 if (ScanCode
== ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
) {
1461 ConsoleIn
->Key
.ScanCode
= ConvertKeyboardScanCodeToEfiKey
[Index
].EfiScanCode
;
1462 if (ConsoleIn
->Shift
) {
1463 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1465 // Need not return associated shift state if a class of printable characters that
1466 // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
1468 if (ConsoleIn
->Key
.UnicodeChar
>= L
'A' && ConsoleIn
->Key
.UnicodeChar
<= L
'Z') {
1469 ConsoleIn
->LeftShift
= FALSE
;
1470 ConsoleIn
->RightShift
= FALSE
;
1473 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1476 // alphabetic key is affected by CapsLock State
1478 if (ConsoleIn
->CapsLock
) {
1479 if (ConsoleIn
->Key
.UnicodeChar
>= L
'a' && ConsoleIn
->Key
.UnicodeChar
<= L
'z') {
1480 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1481 } else if (ConsoleIn
->Key
.UnicodeChar
>= L
'A' && ConsoleIn
->Key
.UnicodeChar
<= L
'Z') {
1482 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1486 // Translate the CTRL-Alpha characters to their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
1488 if (ConsoleIn
->Ctrled
) {
1489 if (ConsoleIn
->Key
.UnicodeChar
>= L
'a' && ConsoleIn
->Key
.UnicodeChar
<= L
'z') {
1490 ConsoleIn
->Key
.UnicodeChar
= (UINT16
) (ConsoleIn
->Key
.UnicodeChar
- L
'a' + 1);
1491 } else if (ConsoleIn
->Key
.UnicodeChar
>= L
'A' && ConsoleIn
->Key
.UnicodeChar
<= L
'Z') {
1492 ConsoleIn
->Key
.UnicodeChar
= (UINT16
) (ConsoleIn
->Key
.UnicodeChar
- L
'A' + 1);
1501 // distinguish numeric key pad keys' 'up symbol' and 'down symbol'
1503 if (ScanCode
>= 0x47 && ScanCode
<= 0x53) {
1505 if (ConsoleIn
->NumLock
&& !ConsoleIn
->Shift
&& !Extended
) {
1506 ConsoleIn
->Key
.ScanCode
= SCAN_NULL
;
1507 } else if (ScanCode
!= 0x4a && ScanCode
!= 0x4e) {
1508 ConsoleIn
->Key
.UnicodeChar
= 0x0000;
1512 // If the key can not be converted then just return.
1514 if (ConsoleIn
->Key
.ScanCode
== SCAN_NULL
&& ConsoleIn
->Key
.UnicodeChar
== 0x0000) {
1515 return EFI_NOT_READY
;
1519 // Save the Shift/Toggle state
1521 if (ConsoleIn
->Ctrl
) {
1522 ConsoleIn
->KeyState
.KeyShiftState
|= (Extended
== TRUE
) ? EFI_RIGHT_CONTROL_PRESSED
: EFI_LEFT_CONTROL_PRESSED
;
1524 if (ConsoleIn
->Alt
) {
1525 ConsoleIn
->KeyState
.KeyShiftState
|= (Extended
== TRUE
) ? EFI_RIGHT_ALT_PRESSED
: EFI_LEFT_ALT_PRESSED
;
1527 if (ConsoleIn
->LeftShift
) {
1528 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_LEFT_SHIFT_PRESSED
;
1530 if (ConsoleIn
->RightShift
) {
1531 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_RIGHT_SHIFT_PRESSED
;
1533 if (ConsoleIn
->LeftLogo
) {
1534 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_LEFT_LOGO_PRESSED
;
1536 if (ConsoleIn
->RightLogo
) {
1537 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_RIGHT_LOGO_PRESSED
;
1539 if (ConsoleIn
->Menu
) {
1540 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_MENU_KEY_PRESSED
;
1542 if (ConsoleIn
->SysReq
) {
1543 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_SYS_REQ_PRESSED
;
1545 if (ConsoleIn
->CapsLock
) {
1546 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_CAPS_LOCK_ACTIVE
;
1548 if (ConsoleIn
->NumLock
) {
1549 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_NUM_LOCK_ACTIVE
;
1551 if (ConsoleIn
->ScrollLock
) {
1552 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_SCROLL_LOCK_ACTIVE
;
1559 Perform 8042 controller and keyboard Initialization
1560 If ExtendedVerification is TRUE, do additional test for
1561 the keyboard interface
1563 @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
1564 @param ExtendedVerification - indicates a thorough initialization
1566 @retval EFI_DEVICE_ERROR Fail to init keyboard
1567 @retval EFI_SUCCESS Success to init keyboard
1571 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1572 IN BOOLEAN ExtendedVerification
1578 EFI_PS2_POLICY_PROTOCOL
*Ps2Policy
;
1581 Status
= EFI_SUCCESS
;
1582 mEnableMouseInterface
= TRUE
;
1586 // Get Ps2 policy to set this
1588 gBS
->LocateProtocol (
1589 &gEfiPs2PolicyProtocolGuid
,
1591 (VOID
**) &Ps2Policy
1594 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1596 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
,
1597 ConsoleIn
->DevicePath
1601 // Perform a read to cleanup the Status Register's
1602 // output buffer full bits within MAX TRY times
1604 while (!EFI_ERROR (Status
) && TryTime
< KEYBOARD_MAX_TRY
) {
1605 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1609 // Exceed the max try times. The device may be error.
1611 if (TryTime
== KEYBOARD_MAX_TRY
) {
1612 Status
= EFI_DEVICE_ERROR
;
1616 // We should disable mouse interface during the initialization process
1617 // since mouse device output could block keyboard device output in the
1618 // 60H port of 8042 controller.
1620 // So if we are not initializing 8042 controller for the
1621 // first time, we have to remember the previous mouse interface
1624 // Test the system flag in to determine whether this is the first
1625 // time initialization
1627 if ((KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_SYSTEM_FLAG
)) {
1629 // 8042 controller is already setup (by myself or by mouse driver):
1630 // See whether mouse interface is already enabled
1631 // which determines whether we should enable it later
1634 // Read the command byte of 8042 controller
1636 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_READ
);
1637 if (EFI_ERROR (Status
)) {
1638 KeyboardError (ConsoleIn
, L
"\n\r");
1642 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1643 if (EFI_ERROR (Status
)) {
1644 KeyboardError (ConsoleIn
, L
"\n\r");
1648 // Test the mouse enabling bit
1650 if (CommandByte
& 0x20) {
1651 mEnableMouseInterface
= FALSE
;
1653 mEnableMouseInterface
= TRUE
;
1658 // 8042 controller is not setup yet:
1659 // 8042 controller selftest;
1660 // Don't enable mouse interface later.
1663 // Disable keyboard and mouse interfaces
1665 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1666 if (EFI_ERROR (Status
)) {
1667 KeyboardError (ConsoleIn
, L
"\n\r");
1671 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_MOUSE_INTERFACE
);
1672 if (EFI_ERROR (Status
)) {
1673 KeyboardError (ConsoleIn
, L
"\n\r");
1677 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1679 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
,
1680 ConsoleIn
->DevicePath
1683 // 8042 Controller Self Test
1685 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_CONTROLLER_SELF_TEST
);
1686 if (EFI_ERROR (Status
)) {
1687 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1691 Status
= KeyboardWaitForValue (ConsoleIn
, 0x55);
1692 if (EFI_ERROR (Status
)) {
1693 KeyboardError (ConsoleIn
, L
"8042 controller self test failed!\n\r");
1697 // Don't enable mouse interface later
1699 mEnableMouseInterface
= FALSE
;
1703 if (Ps2Policy
!= NULL
) {
1704 Ps2Policy
->Ps2InitHardware (ConsoleIn
->Handle
);
1707 // Write 8042 Command Byte, set System Flag
1708 // While at the same time:
1709 // 1. disable mouse interface,
1710 // 2. enable kbd interface,
1711 // 3. enable PC/XT kbd translation mode
1712 // 4. enable mouse and kbd interrupts
1714 // ( Command Byte bits:
1716 // 6: PC/XT translation mode
1717 // 5: Disable Auxiliary device interface
1718 // 4: Disable keyboard interface
1721 // 1: Enable Auxiliary device interrupt
1722 // 0: Enable Keyboard interrupt )
1724 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_WRITE
);
1725 if (EFI_ERROR (Status
)) {
1726 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1730 Status
= KeyboardWrite (ConsoleIn
, 0x67);
1731 if (EFI_ERROR (Status
)) {
1732 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1737 // Clear Memory Scancode Buffer
1739 ConsoleIn
->ScancodeBufStartPos
= 0;
1740 ConsoleIn
->ScancodeBufEndPos
= KEYBOARD_BUFFER_MAX_COUNT
- 1;
1741 ConsoleIn
->ScancodeBufCount
= 0;
1742 ConsoleIn
->Ctrled
= FALSE
;
1743 ConsoleIn
->Alted
= FALSE
;
1746 // Reset the status indicators
1748 ConsoleIn
->Ctrl
= FALSE
;
1749 ConsoleIn
->Alt
= FALSE
;
1750 ConsoleIn
->Shift
= FALSE
;
1751 ConsoleIn
->CapsLock
= FALSE
;
1752 ConsoleIn
->NumLock
= FALSE
;
1753 ConsoleIn
->ScrollLock
= FALSE
;
1754 ConsoleIn
->LeftShift
= FALSE
;
1755 ConsoleIn
->RightShift
= FALSE
;
1756 ConsoleIn
->LeftLogo
= FALSE
;
1757 ConsoleIn
->RightLogo
= FALSE
;
1758 ConsoleIn
->Menu
= FALSE
;
1759 ConsoleIn
->SysReq
= FALSE
;
1762 // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1763 // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected
1764 // to system. So we only do the real reseting for keyboard when user asks and there is a real KB connected t system,
1765 // and normally during booting an OS, it's skipped.
1767 if (ExtendedVerification
&& CheckKeyboardConnect (ConsoleIn
)) {
1769 // Additional verifications for keyboard interface
1772 // Keyboard Interface Test
1774 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_KEYBOARD_INTERFACE_SELF_TEST
);
1775 if (EFI_ERROR (Status
)) {
1776 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1780 Status
= KeyboardWaitForValue (ConsoleIn
, 0x00);
1781 if (EFI_ERROR (Status
)) {
1784 L
"Some specific value not aquired from 8042 controller!\n\r"
1789 // Keyboard reset with a BAT(Basic Assurance Test)
1791 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_RESET
);
1792 if (EFI_ERROR (Status
)) {
1793 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1797 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1798 if (EFI_ERROR (Status
)) {
1799 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1803 // wait for BAT completion code
1805 mWaitForValueTimeOut
= KEYBOARD_BAT_TIMEOUT
;
1807 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_BAT_SUCCESS
);
1808 if (EFI_ERROR (Status
)) {
1809 KeyboardError (ConsoleIn
, L
"Keyboard self test failed!\n\r");
1813 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1816 // Set Keyboard to use Scan Code Set 2
1818 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_SELECT_SCAN_CODE_SET
);
1819 if (EFI_ERROR (Status
)) {
1820 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1824 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1825 if (EFI_ERROR (Status
)) {
1826 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1830 Status
= KeyboardWrite (ConsoleIn
, 0x02);
1831 if (EFI_ERROR (Status
)) {
1832 KeyboardError (ConsoleIn
, L
"8042 controller data write error!!\n\r");
1836 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1837 if (EFI_ERROR (Status
)) {
1838 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1843 // Clear Keyboard Scancode Buffer
1845 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_CLEAR_OUTPUT_DATA
);
1846 if (EFI_ERROR (Status
)) {
1847 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1851 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1852 if (EFI_ERROR (Status
)) {
1853 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1857 if (Ps2Policy
!= NULL
) {
1858 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_CAPSLOCK
) == EFI_KEYBOARD_CAPSLOCK
) {
1859 ConsoleIn
->CapsLock
= TRUE
;
1862 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_NUMLOCK
) == EFI_KEYBOARD_NUMLOCK
) {
1863 ConsoleIn
->NumLock
= TRUE
;
1866 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_SCROLLLOCK
) == EFI_KEYBOARD_SCROLLLOCK
) {
1867 ConsoleIn
->ScrollLock
= TRUE
;
1871 // Update Keyboard Lights
1873 Status
= UpdateStatusLights (ConsoleIn
);
1874 if (EFI_ERROR (Status
)) {
1875 KeyboardError (ConsoleIn
, L
"Update keyboard status lights error!\n\r");
1880 // At last, we can now enable the mouse interface if appropriate
1884 if (mEnableMouseInterface
) {
1886 // Enable mouse interface
1888 Status1
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_ENABLE_MOUSE_INTERFACE
);
1889 if (EFI_ERROR (Status1
)) {
1890 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1891 return EFI_DEVICE_ERROR
;
1895 if (!EFI_ERROR (Status
)) {
1898 return EFI_DEVICE_ERROR
;
1904 Disable the keyboard interface of the 8042 controller
1906 @param ConsoleIn - the device instance
1908 @return status of issuing disable command
1913 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1919 // Disable keyboard interface
1921 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1922 if (EFI_ERROR (Status
)) {
1923 KeyboardError (ConsoleIn
, L
"\n\r");
1924 return EFI_DEVICE_ERROR
;
1931 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
1932 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
1933 should not be in system.
1935 @param[in] ConsoleIn Keyboard Private Data Structure
1937 @retval TRUE Keyboard in System.
1938 @retval FALSE Keyboard not in System.
1942 CheckKeyboardConnect (
1943 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1947 UINTN WaitForValueTimeOutBcakup
;
1949 Status
= EFI_SUCCESS
;
1951 // enable keyboard itself and wait for its ack
1952 // If can't receive ack, Keyboard should not be connected.
1954 Status
= KeyboardWrite (
1959 if (EFI_ERROR (Status
)) {
1965 WaitForValueTimeOutBcakup
= mWaitForValueTimeOut
;
1966 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1967 Status
= KeyboardWaitForValue (
1969 KEYBOARD_CMDECHO_ACK
1971 mWaitForValueTimeOut
= WaitForValueTimeOutBcakup
;
1973 if (EFI_ERROR (Status
)) {