2 Routines that access 8042 keyboard controller
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "Ps2Keyboard.h"
12 UINT8 ScanCode
; ///< follows value defined in Scan Code Set1
15 CHAR16 ShiftUnicodeChar
;
17 ConvertKeyboardScanCodeToEfiKey
[] = {
344 0x37, // Numeric Keypad *
350 0x38, //Left Alt/Extended Right Alt
470 0x4c, // Numeric Keypad 5
556 // The WaitForValue time out
558 UINTN mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
560 BOOLEAN mEnableMouseInterface
;
565 Return the count of scancode in the queue.
567 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
569 @return Count of the scancode.
572 GetScancodeBufCount (
573 IN SCAN_CODE_QUEUE
*Queue
576 if (Queue
->Head
<= Queue
->Tail
) {
577 return Queue
->Tail
- Queue
->Head
;
579 return Queue
->Tail
+ KEYBOARD_SCAN_CODE_MAX_COUNT
- Queue
->Head
;
584 Read several bytes from the scancode buffer without removing them.
585 This function is called to see if there are enough bytes of scancode
586 representing a single key.
588 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
589 @param Count Number of bytes to be read
590 @param Buf Store the results
592 @retval EFI_SUCCESS success to scan the keyboard code
593 @retval EFI_NOT_READY invalid parameter
597 IN SCAN_CODE_QUEUE
*Queue
,
606 // check the valid range of parameter 'Count'
608 if (GetScancodeBufCount (Queue
) < Count
) {
609 return EFI_NOT_READY
;
612 // retrieve the values
614 for (Index
= 0, Pos
= Queue
->Head
; Index
< Count
; Index
++, Pos
= (Pos
+ 1) % KEYBOARD_SCAN_CODE_MAX_COUNT
) {
615 Buf
[Index
] = Queue
->Buffer
[Pos
];
623 Read & remove several bytes from the scancode buffer.
624 This function is usually called after GetScancodeBufHead()
626 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
627 @param Count Number of bytes to be read
628 @param Buf Store the results
630 @retval EFI_SUCCESS success to scan the keyboard code
631 @retval EFI_NOT_READY invalid parameter
635 IN SCAN_CODE_QUEUE
*Queue
,
637 OUT UINT8
*Buf OPTIONAL
643 // Check the valid range of parameter 'Count'
645 if (GetScancodeBufCount (Queue
) < Count
) {
646 return EFI_NOT_READY
;
649 // Retrieve and remove the values
651 for (Index
= 0; Index
< Count
; Index
++, Queue
->Head
= (Queue
->Head
+ 1) % KEYBOARD_SCAN_CODE_MAX_COUNT
) {
653 Buf
[Index
] = Queue
->Buffer
[Queue
->Head
];
661 Push one byte to the scancode buffer.
663 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
664 @param Scancode The byte to push.
667 PushScancodeBufTail (
668 IN SCAN_CODE_QUEUE
*Queue
,
672 if (GetScancodeBufCount (Queue
) == KEYBOARD_SCAN_CODE_MAX_COUNT
- 1) {
673 PopScancodeBufHead (Queue
, 1, NULL
);
676 Queue
->Buffer
[Queue
->Tail
] = Scancode
;
677 Queue
->Tail
= (Queue
->Tail
+ 1) % KEYBOARD_SCAN_CODE_MAX_COUNT
;
683 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
685 @return return the value
689 KeyReadDataRegister (
690 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
694 return IoRead8 (ConsoleIn
->DataRegisterAddress
);
700 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
701 @param Data value wanted to be written
705 KeyWriteDataRegister (
706 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
710 IoWrite8 (ConsoleIn
->DataRegisterAddress
, Data
);
714 Read status register.
716 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
718 @return value in status register
722 KeyReadStatusRegister (
723 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
726 return IoRead8 (ConsoleIn
->StatusRegisterAddress
);
730 Write command register .
732 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
733 @param Data The value wanted to be written
737 KeyWriteCommandRegister (
738 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
742 IoWrite8 (ConsoleIn
->CommandRegisterAddress
, Data
);
746 Display error message.
748 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
749 @param ErrMsg Unicode string of error message
754 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
758 ConsoleIn
->KeyboardErr
= TRUE
;
762 Timer event handler: read a series of scancodes from 8042
763 and put them into memory scancode buffer.
764 it read as much scancodes to either fill
765 the memory buffer or empty the keyboard buffer.
766 It is registered as running under TPL_NOTIFY
768 @param Event The timer event
769 @param Context A KEYBOARD_CONSOLE_IN_DEV pointer
774 KeyboardTimerHandler (
782 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
784 ConsoleIn
= (KEYBOARD_CONSOLE_IN_DEV
*) Context
;
787 // Enter critical section
789 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
791 if (((KEYBOARD_CONSOLE_IN_DEV
*) Context
)->KeyboardErr
) {
793 // Leave critical section and return
795 gBS
->RestoreTPL (OldTpl
);
800 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
801 // KB is not connected to system. If KB is not connected to system, driver will find there's something
802 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
803 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
804 // Just skip the 'resend' process simply.
807 while ((KeyReadStatusRegister (ConsoleIn
) & (KEYBOARD_STATUS_REGISTER_TRANSMIT_TIMEOUT
|KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
)) ==
808 KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
811 // Read one byte of the scan code and store it into the memory buffer
813 Data
= KeyReadDataRegister (ConsoleIn
);
814 PushScancodeBufTail (&ConsoleIn
->ScancodeQueue
, Data
);
816 KeyGetchar (ConsoleIn
);
819 // Leave critical section and return
821 gBS
->RestoreTPL (OldTpl
);
827 @param ConsoleIn - Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
828 @param Data - Pointer to outof buffer for keeping key value
830 @retval EFI_TIMEOUT Status resigter time out
831 @retval EFI_SUCCESS Success to read keyboard
836 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
848 // wait till output buffer full then perform the read
850 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
851 if (KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
) {
853 *Data
= KeyReadDataRegister (ConsoleIn
);
857 MicroSecondDelay (30);
860 if (RegFilled
== 0) {
868 write key to keyboard
870 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
871 @param Data value wanted to be written
873 @retval EFI_TIMEOUT The input buffer register is full for putting new value util timeout
874 @retval EFI_SUCCESS The new value is sucess put into input buffer register.
879 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
890 // wait for input buffer empty
892 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
893 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
898 MicroSecondDelay (30);
901 if (RegEmptied
== 0) {
907 KeyWriteDataRegister (ConsoleIn
, Data
);
913 Issue keyboard command.
915 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
916 @param Data The buff holding the command
918 @retval EFI_TIMEOUT Keyboard is not ready to issuing
919 @retval EFI_SUCCESS Success to issue keyboard command
924 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
935 // Wait For Input Buffer Empty
937 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
938 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
943 MicroSecondDelay (30);
946 if (RegEmptied
== 0) {
952 KeyWriteCommandRegister (ConsoleIn
, Data
);
955 // Wait For Input Buffer Empty again
958 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
959 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
964 MicroSecondDelay (30);
967 if (RegEmptied
== 0) {
975 wait for a specific value to be presented on
976 8042 Data register by keyboard and then read it,
977 used in keyboard commands ack
979 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
980 @param Value the value wanted to be waited.
982 @retval EFI_TIMEOUT Fail to get specific value in given time
983 @retval EFI_SUCCESS Success to get specific value in given time.
987 KeyboardWaitForValue (
988 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1002 // Make sure the initial value of 'Data' is different from 'Value'
1005 if (Data
== Value
) {
1009 // Read from 8042 (multiple times if needed)
1010 // until the expected value appears
1011 // use SumTimeOut to control the iteration
1017 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1018 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1019 Data
= KeyReadDataRegister (ConsoleIn
);
1023 MicroSecondDelay (30);
1026 SumTimeOut
+= TimeOut
;
1028 if (Data
== Value
) {
1033 if (SumTimeOut
>= mWaitForValueTimeOut
) {
1049 Show keyboard status lights according to
1050 indicators in ConsoleIn.
1052 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1054 @return status of updating keyboard register
1058 UpdateStatusLights (
1059 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1066 // Send keyboard command
1068 Status
= KeyboardWrite (ConsoleIn
, 0xed);
1069 if (EFI_ERROR (Status
)) {
1073 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1076 // Light configuration
1079 if (ConsoleIn
->CapsLock
) {
1083 if (ConsoleIn
->NumLock
) {
1087 if (ConsoleIn
->ScrollLock
) {
1091 Status
= KeyboardWrite (ConsoleIn
, Command
);
1093 if (EFI_ERROR (Status
)) {
1097 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1102 Initialize the key state.
1104 @param ConsoleIn The KEYBOARD_CONSOLE_IN_DEV instance.
1105 @param KeyState A pointer to receive the key state information.
1108 InitializeKeyState (
1109 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1110 OUT EFI_KEY_STATE
*KeyState
1113 KeyState
->KeyShiftState
= EFI_SHIFT_STATE_VALID
1114 | (ConsoleIn
->LeftCtrl
? EFI_LEFT_CONTROL_PRESSED
: 0)
1115 | (ConsoleIn
->RightCtrl
? EFI_RIGHT_CONTROL_PRESSED
: 0)
1116 | (ConsoleIn
->LeftAlt
? EFI_LEFT_ALT_PRESSED
: 0)
1117 | (ConsoleIn
->RightAlt
? EFI_RIGHT_ALT_PRESSED
: 0)
1118 | (ConsoleIn
->LeftShift
? EFI_LEFT_SHIFT_PRESSED
: 0)
1119 | (ConsoleIn
->RightShift
? EFI_RIGHT_SHIFT_PRESSED
: 0)
1120 | (ConsoleIn
->LeftLogo
? EFI_LEFT_LOGO_PRESSED
: 0)
1121 | (ConsoleIn
->RightLogo
? EFI_RIGHT_LOGO_PRESSED
: 0)
1122 | (ConsoleIn
->Menu
? EFI_MENU_KEY_PRESSED
: 0)
1123 | (ConsoleIn
->SysReq
? EFI_SYS_REQ_PRESSED
: 0)
1125 KeyState
->KeyToggleState
= EFI_TOGGLE_STATE_VALID
1126 | (ConsoleIn
->CapsLock
? EFI_CAPS_LOCK_ACTIVE
: 0)
1127 | (ConsoleIn
->NumLock
? EFI_NUM_LOCK_ACTIVE
: 0)
1128 | (ConsoleIn
->ScrollLock
? EFI_SCROLL_LOCK_ACTIVE
: 0)
1129 | (ConsoleIn
->IsSupportPartialKey
? EFI_KEY_STATE_EXPOSED
: 0)
1134 Get scancode from scancode buffer and translate into EFI-scancode and unicode defined by EFI spec.
1136 The function is always called in TPL_NOTIFY.
1138 @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer
1143 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1151 EFI_KEY_DATA KeyData
;
1153 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
1157 UINT8 ScancodeArr
[3];
1158 UINT32 ScancodeArrPos
;
1161 // Check if there are enough bytes of scancode representing a single key
1162 // available in the buffer
1168 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1169 if (EFI_ERROR (Status
)) {
1173 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED0
) {
1175 // E0 to look ahead 2 bytes
1179 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1180 if (EFI_ERROR (Status
)) {
1183 } else if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED1
) {
1185 // E1 to look ahead 3 bytes
1189 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1190 if (EFI_ERROR (Status
)) {
1195 // if we reach this position, scancodes for a key is in buffer now,pop them
1197 Status
= PopScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1198 ASSERT_EFI_ERROR (Status
);
1201 // store the last available byte, this byte of scancode will be checked
1203 ScanCode
= ScancodeArr
[ScancodeArrPos
];
1207 // Check for special keys and update the driver state.
1211 case SCANCODE_CTRL_MAKE
:
1213 ConsoleIn
->RightCtrl
= TRUE
;
1215 ConsoleIn
->LeftCtrl
= TRUE
;
1218 case SCANCODE_CTRL_BREAK
:
1220 ConsoleIn
->RightCtrl
= FALSE
;
1222 ConsoleIn
->LeftCtrl
= FALSE
;
1226 case SCANCODE_ALT_MAKE
:
1228 ConsoleIn
->RightAlt
= TRUE
;
1230 ConsoleIn
->LeftAlt
= TRUE
;
1233 case SCANCODE_ALT_BREAK
:
1235 ConsoleIn
->RightAlt
= FALSE
;
1237 ConsoleIn
->LeftAlt
= FALSE
;
1241 case SCANCODE_LEFT_SHIFT_MAKE
:
1243 // To avoid recognize PRNT_SCRN key as a L_SHIFT key
1244 // because PRNT_SCRN key generates E0 followed by L_SHIFT scan code.
1245 // If it the second byte of the PRNT_ScRN skip it.
1248 ConsoleIn
->LeftShift
= TRUE
;
1253 case SCANCODE_LEFT_SHIFT_BREAK
:
1255 ConsoleIn
->LeftShift
= FALSE
;
1259 case SCANCODE_RIGHT_SHIFT_MAKE
:
1260 ConsoleIn
->RightShift
= TRUE
;
1262 case SCANCODE_RIGHT_SHIFT_BREAK
:
1263 ConsoleIn
->RightShift
= FALSE
;
1266 case SCANCODE_LEFT_LOGO_MAKE
:
1267 ConsoleIn
->LeftLogo
= TRUE
;
1269 case SCANCODE_LEFT_LOGO_BREAK
:
1270 ConsoleIn
->LeftLogo
= FALSE
;
1273 case SCANCODE_RIGHT_LOGO_MAKE
:
1274 ConsoleIn
->RightLogo
= TRUE
;
1276 case SCANCODE_RIGHT_LOGO_BREAK
:
1277 ConsoleIn
->RightLogo
= FALSE
;
1280 case SCANCODE_MENU_MAKE
:
1281 ConsoleIn
->Menu
= TRUE
;
1283 case SCANCODE_MENU_BREAK
:
1284 ConsoleIn
->Menu
= FALSE
;
1287 case SCANCODE_SYS_REQ_MAKE
:
1289 ConsoleIn
->SysReq
= TRUE
;
1292 case SCANCODE_SYS_REQ_BREAK
:
1294 ConsoleIn
->SysReq
= FALSE
;
1298 case SCANCODE_SYS_REQ_MAKE_WITH_ALT
:
1299 ConsoleIn
->SysReq
= TRUE
;
1301 case SCANCODE_SYS_REQ_BREAK_WITH_ALT
:
1302 ConsoleIn
->SysReq
= FALSE
;
1305 case SCANCODE_CAPS_LOCK_MAKE
:
1306 ConsoleIn
->CapsLock
= (BOOLEAN
)!ConsoleIn
->CapsLock
;
1307 UpdateStatusLights (ConsoleIn
);
1309 case SCANCODE_NUM_LOCK_MAKE
:
1310 ConsoleIn
->NumLock
= (BOOLEAN
)!ConsoleIn
->NumLock
;
1311 UpdateStatusLights (ConsoleIn
);
1313 case SCANCODE_SCROLL_LOCK_MAKE
:
1315 ConsoleIn
->ScrollLock
= (BOOLEAN
)!ConsoleIn
->ScrollLock
;
1316 UpdateStatusLights (ConsoleIn
);
1323 // If this is above the valid range, ignore it
1325 if (ScanCode
>= SCANCODE_MAX_MAKE
) {
1333 // Handle Ctrl+Alt+Del hotkey
1335 if ((ConsoleIn
->LeftCtrl
|| ConsoleIn
->RightCtrl
) &&
1336 (ConsoleIn
->LeftAlt
|| ConsoleIn
->RightAlt
) &&
1337 ScanCode
== SCANCODE_DELETE_MAKE
1339 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1343 // Save the Shift/Toggle state
1345 InitializeKeyState (ConsoleIn
, &KeyData
.KeyState
);
1346 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1347 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1350 // Key Pad "/" shares the same scancode as that of "/" except Key Pad "/" has E0 prefix
1352 if (Extend0
&& ScanCode
== 0x35) {
1353 KeyData
.Key
.UnicodeChar
= L
'/';
1354 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1357 // PAUSE shares the same scancode as that of NUM except PAUSE has E1 prefix
1359 } else if (Extend1
&& ScanCode
== SCANCODE_NUM_LOCK_MAKE
) {
1360 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1361 KeyData
.Key
.ScanCode
= SCAN_PAUSE
;
1364 // PAUSE shares the same scancode as that of SCROLL except PAUSE (CTRL pressed) has E0 prefix
1366 } else if (Extend0
&& ScanCode
== SCANCODE_SCROLL_LOCK_MAKE
) {
1367 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1368 KeyData
.Key
.ScanCode
= SCAN_PAUSE
;
1371 // PRNT_SCRN shares the same scancode as that of Key Pad "*" except PRNT_SCRN has E0 prefix
1373 } else if (Extend0
&& ScanCode
== SCANCODE_SYS_REQ_MAKE
) {
1374 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1375 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1378 // Except the above special case, all others can be handled by convert table
1381 for (Index
= 0; ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
!= TABLE_END
; Index
++) {
1382 if (ScanCode
== ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
) {
1383 KeyData
.Key
.ScanCode
= ConvertKeyboardScanCodeToEfiKey
[Index
].EfiScanCode
;
1384 KeyData
.Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1386 if ((ConsoleIn
->LeftShift
|| ConsoleIn
->RightShift
) &&
1387 (ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
!= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
)) {
1388 KeyData
.Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1390 // Need not return associated shift state if a class of printable characters that
1391 // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
1393 KeyData
.KeyState
.KeyShiftState
&= ~(EFI_LEFT_SHIFT_PRESSED
| EFI_RIGHT_SHIFT_PRESSED
);
1396 // alphabetic key is affected by CapsLock State
1398 if (ConsoleIn
->CapsLock
) {
1399 if (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z') {
1400 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'a' + L
'A');
1401 } else if (KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') {
1402 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'A' + L
'a');
1411 // distinguish numeric key pad keys' 'up symbol' and 'down symbol'
1413 if (ScanCode
>= 0x47 && ScanCode
<= 0x53) {
1414 if (ConsoleIn
->NumLock
&& !(ConsoleIn
->LeftShift
|| ConsoleIn
->RightShift
) && !Extend0
) {
1415 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1416 } else if (ScanCode
!= 0x4a && ScanCode
!= 0x4e) {
1417 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1422 // If the key can not be converted then just return.
1424 if (KeyData
.Key
.ScanCode
== SCAN_NULL
&& KeyData
.Key
.UnicodeChar
== CHAR_NULL
) {
1425 if (!ConsoleIn
->IsSupportPartialKey
) {
1431 // Signal KeyNotify process event if this key pressed matches any key registered.
1433 for (Link
= GetFirstNode (&ConsoleIn
->NotifyList
); !IsNull (&ConsoleIn
->NotifyList
, Link
); Link
= GetNextNode (&ConsoleIn
->NotifyList
, Link
)) {
1434 CurrentNotify
= CR (
1436 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
1438 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1440 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
1442 // The key notification function needs to run at TPL_CALLBACK
1443 // while current TPL is TPL_NOTIFY. It will be invoked in
1444 // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.
1446 PushEfikeyBufTail (&ConsoleIn
->EfiKeyQueueForNotify
, &KeyData
);
1447 gBS
->SignalEvent (ConsoleIn
->KeyNotifyProcessEvent
);
1452 PushEfikeyBufTail (&ConsoleIn
->EfiKeyQueue
, &KeyData
);
1456 Perform 8042 controller and keyboard Initialization.
1457 If ExtendedVerification is TRUE, do additional test for
1458 the keyboard interface
1460 @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
1461 @param ExtendedVerification - indicates a thorough initialization
1463 @retval EFI_DEVICE_ERROR Fail to init keyboard
1464 @retval EFI_SUCCESS Success to init keyboard
1468 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1469 IN BOOLEAN ExtendedVerification
1475 EFI_PS2_POLICY_PROTOCOL
*Ps2Policy
;
1478 Status
= EFI_SUCCESS
;
1479 mEnableMouseInterface
= TRUE
;
1483 // Get Ps2 policy to set this
1485 gBS
->LocateProtocol (
1486 &gEfiPs2PolicyProtocolGuid
,
1488 (VOID
**) &Ps2Policy
1491 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1493 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
,
1494 ConsoleIn
->DevicePath
1498 // Perform a read to cleanup the Status Register's
1499 // output buffer full bits within MAX TRY times
1501 if ((KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
) != 0) {
1502 while (!EFI_ERROR (Status
) && TryTime
< KEYBOARD_MAX_TRY
) {
1503 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1507 // Exceed the max try times. The device may be error.
1509 if (TryTime
== KEYBOARD_MAX_TRY
) {
1510 Status
= EFI_DEVICE_ERROR
;
1515 // We should disable mouse interface during the initialization process
1516 // since mouse device output could block keyboard device output in the
1517 // 60H port of 8042 controller.
1519 // So if we are not initializing 8042 controller for the
1520 // first time, we have to remember the previous mouse interface
1523 // Test the system flag in to determine whether this is the first
1524 // time initialization
1526 if ((KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_SYSTEM_FLAG
) != 0) {
1527 if (!PcdGetBool (PcdFastPS2Detection
)) {
1529 // 8042 controller is already setup (by myself or by mouse driver):
1530 // See whether mouse interface is already enabled
1531 // which determines whether we should enable it later
1534 // Read the command byte of 8042 controller
1536 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_READ
);
1537 if (EFI_ERROR (Status
)) {
1538 KeyboardError (ConsoleIn
, L
"\n\r");
1542 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1543 if (EFI_ERROR (Status
)) {
1544 KeyboardError (ConsoleIn
, L
"\n\r");
1548 // Test the mouse enabling bit
1550 if ((CommandByte
& 0x20) != 0) {
1551 mEnableMouseInterface
= FALSE
;
1553 mEnableMouseInterface
= TRUE
;
1556 mEnableMouseInterface
= FALSE
;
1560 // 8042 controller is not setup yet:
1561 // 8042 controller selftest;
1562 // Don't enable mouse interface later.
1565 // Disable keyboard and mouse interfaces
1567 if (!PcdGetBool (PcdFastPS2Detection
)) {
1568 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1569 if (EFI_ERROR (Status
)) {
1570 KeyboardError (ConsoleIn
, L
"\n\r");
1574 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_MOUSE_INTERFACE
);
1575 if (EFI_ERROR (Status
)) {
1576 KeyboardError (ConsoleIn
, L
"\n\r");
1580 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1582 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
,
1583 ConsoleIn
->DevicePath
1586 // 8042 Controller Self Test
1588 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_CONTROLLER_SELF_TEST
);
1589 if (EFI_ERROR (Status
)) {
1590 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1594 Status
= KeyboardWaitForValue (ConsoleIn
, 0x55);
1595 if (EFI_ERROR (Status
)) {
1596 KeyboardError (ConsoleIn
, L
"8042 controller self test failed!\n\r");
1601 // Don't enable mouse interface later
1603 mEnableMouseInterface
= FALSE
;
1607 if (Ps2Policy
!= NULL
) {
1608 Ps2Policy
->Ps2InitHardware (ConsoleIn
->Handle
);
1611 // Write 8042 Command Byte, set System Flag
1612 // While at the same time:
1613 // 1. disable mouse interface,
1614 // 2. enable kbd interface,
1615 // 3. enable PC/XT kbd translation mode
1616 // 4. enable mouse and kbd interrupts
1618 // ( Command Byte bits:
1620 // 6: PC/XT translation mode
1621 // 5: Disable Auxiliary device interface
1622 // 4: Disable keyboard interface
1625 // 1: Enable Auxiliary device interrupt
1626 // 0: Enable Keyboard interrupt )
1628 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_WRITE
);
1629 if (EFI_ERROR (Status
)) {
1630 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1634 Status
= KeyboardWrite (ConsoleIn
, 0x67);
1635 if (EFI_ERROR (Status
)) {
1636 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1641 // Clear Memory Scancode Buffer
1643 ConsoleIn
->ScancodeQueue
.Head
= 0;
1644 ConsoleIn
->ScancodeQueue
.Tail
= 0;
1645 ConsoleIn
->EfiKeyQueue
.Head
= 0;
1646 ConsoleIn
->EfiKeyQueue
.Tail
= 0;
1647 ConsoleIn
->EfiKeyQueueForNotify
.Head
= 0;
1648 ConsoleIn
->EfiKeyQueueForNotify
.Tail
= 0;
1651 // Reset the status indicators
1653 ConsoleIn
->CapsLock
= FALSE
;
1654 ConsoleIn
->NumLock
= FALSE
;
1655 ConsoleIn
->ScrollLock
= FALSE
;
1656 ConsoleIn
->LeftCtrl
= FALSE
;
1657 ConsoleIn
->RightCtrl
= FALSE
;
1658 ConsoleIn
->LeftAlt
= FALSE
;
1659 ConsoleIn
->RightAlt
= FALSE
;
1660 ConsoleIn
->LeftShift
= FALSE
;
1661 ConsoleIn
->RightShift
= FALSE
;
1662 ConsoleIn
->LeftLogo
= FALSE
;
1663 ConsoleIn
->RightLogo
= FALSE
;
1664 ConsoleIn
->Menu
= FALSE
;
1665 ConsoleIn
->SysReq
= FALSE
;
1667 ConsoleIn
->IsSupportPartialKey
= FALSE
;
1669 // For resetting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1670 // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected
1671 // to system. So we only do the real resetting for keyboard when user asks and there is a real KB connected t system,
1672 // and normally during booting an OS, it's skipped.
1674 if (ExtendedVerification
&& CheckKeyboardConnect (ConsoleIn
)) {
1676 // Additional verifications for keyboard interface
1679 // Keyboard Interface Test
1681 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_KEYBOARD_INTERFACE_SELF_TEST
);
1682 if (EFI_ERROR (Status
)) {
1683 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1687 Status
= KeyboardWaitForValue (ConsoleIn
, 0x00);
1688 if (EFI_ERROR (Status
)) {
1691 L
"Some specific value not aquired from 8042 controller!\n\r"
1696 // Keyboard reset with a BAT(Basic Assurance Test)
1698 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_RESET
);
1699 if (EFI_ERROR (Status
)) {
1700 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1704 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1705 if (EFI_ERROR (Status
)) {
1706 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1710 // wait for BAT completion code
1712 mWaitForValueTimeOut
= KEYBOARD_BAT_TIMEOUT
;
1714 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_BAT_SUCCESS
);
1715 if (EFI_ERROR (Status
)) {
1716 KeyboardError (ConsoleIn
, L
"Keyboard self test failed!\n\r");
1720 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1723 // Set Keyboard to use Scan Code Set 2
1725 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_SELECT_SCAN_CODE_SET
);
1726 if (EFI_ERROR (Status
)) {
1727 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1731 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1732 if (EFI_ERROR (Status
)) {
1733 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1737 Status
= KeyboardWrite (ConsoleIn
, 0x02);
1738 if (EFI_ERROR (Status
)) {
1739 KeyboardError (ConsoleIn
, L
"8042 controller data write error!!\n\r");
1743 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1744 if (EFI_ERROR (Status
)) {
1745 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1750 // Clear Keyboard Scancode Buffer
1752 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_CLEAR_OUTPUT_DATA
);
1753 if (EFI_ERROR (Status
)) {
1754 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1758 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1759 if (EFI_ERROR (Status
)) {
1760 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1764 if (Ps2Policy
!= NULL
) {
1765 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_CAPSLOCK
) == EFI_KEYBOARD_CAPSLOCK
) {
1766 ConsoleIn
->CapsLock
= TRUE
;
1769 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_NUMLOCK
) == EFI_KEYBOARD_NUMLOCK
) {
1770 ConsoleIn
->NumLock
= TRUE
;
1773 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_SCROLLLOCK
) == EFI_KEYBOARD_SCROLLLOCK
) {
1774 ConsoleIn
->ScrollLock
= TRUE
;
1778 // Update Keyboard Lights
1780 Status
= UpdateStatusLights (ConsoleIn
);
1781 if (EFI_ERROR (Status
)) {
1782 KeyboardError (ConsoleIn
, L
"Update keyboard status lights error!\n\r");
1787 // At last, we can now enable the mouse interface if appropriate
1791 if (mEnableMouseInterface
) {
1793 // Enable mouse interface
1795 Status1
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_ENABLE_MOUSE_INTERFACE
);
1796 if (EFI_ERROR (Status1
)) {
1797 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1798 return EFI_DEVICE_ERROR
;
1802 if (!EFI_ERROR (Status
)) {
1805 return EFI_DEVICE_ERROR
;
1812 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
1813 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
1814 should not be in system.
1816 @param[in] ConsoleIn Keyboard Private Data Structure
1818 @retval TRUE Keyboard in System.
1819 @retval FALSE Keyboard not in System.
1823 CheckKeyboardConnect (
1824 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1828 UINTN WaitForValueTimeOutBcakup
;
1831 // enable keyboard itself and wait for its ack
1832 // If can't receive ack, Keyboard should not be connected.
1834 if (!PcdGetBool (PcdFastPS2Detection
)) {
1835 Status
= KeyboardWrite (
1840 if (EFI_ERROR (Status
)) {
1846 WaitForValueTimeOutBcakup
= mWaitForValueTimeOut
;
1847 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1848 Status
= KeyboardWaitForValue (
1850 KEYBOARD_CMDECHO_ACK
1852 mWaitForValueTimeOut
= WaitForValueTimeOutBcakup
;
1854 if (EFI_ERROR (Status
)) {