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
;
16 } ConvertKeyboardScanCodeToEfiKey
[] = {
342 0x37, // Numeric Keypad *
348 0x38, // Left Alt/Extended Right Alt
468 0x4c, // Numeric Keypad 5
554 // The WaitForValue time out
556 UINTN mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
558 BOOLEAN mEnableMouseInterface
;
561 Return the count of scancode in the queue.
563 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
565 @return Count of the scancode.
568 GetScancodeBufCount (
569 IN SCAN_CODE_QUEUE
*Queue
572 if (Queue
->Head
<= Queue
->Tail
) {
573 return Queue
->Tail
- Queue
->Head
;
575 return Queue
->Tail
+ KEYBOARD_SCAN_CODE_MAX_COUNT
- Queue
->Head
;
580 Read several bytes from the scancode buffer without removing them.
581 This function is called to see if there are enough bytes of scancode
582 representing a single key.
584 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
585 @param Count Number of bytes to be read
586 @param Buf Store the results
588 @retval EFI_SUCCESS success to scan the keyboard code
589 @retval EFI_NOT_READY invalid parameter
593 IN SCAN_CODE_QUEUE
*Queue
,
602 // check the valid range of parameter 'Count'
604 if (GetScancodeBufCount (Queue
) < Count
) {
605 return EFI_NOT_READY
;
609 // retrieve the values
611 for (Index
= 0, Pos
= Queue
->Head
; Index
< Count
; Index
++, Pos
= (Pos
+ 1) % KEYBOARD_SCAN_CODE_MAX_COUNT
) {
612 Buf
[Index
] = Queue
->Buffer
[Pos
];
620 Read & remove several bytes from the scancode buffer.
621 This function is usually called after GetScancodeBufHead()
623 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
624 @param Count Number of bytes to be read
625 @param Buf Store the results
627 @retval EFI_SUCCESS success to scan the keyboard code
628 @retval EFI_NOT_READY invalid parameter
632 IN SCAN_CODE_QUEUE
*Queue
,
634 OUT UINT8
*Buf OPTIONAL
640 // Check the valid range of parameter 'Count'
642 if (GetScancodeBufCount (Queue
) < Count
) {
643 return EFI_NOT_READY
;
647 // Retrieve and remove the values
649 for (Index
= 0; Index
< Count
; Index
++, Queue
->Head
= (Queue
->Head
+ 1) % KEYBOARD_SCAN_CODE_MAX_COUNT
) {
651 Buf
[Index
] = Queue
->Buffer
[Queue
->Head
];
659 Push one byte to the scancode buffer.
661 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
662 @param Scancode The byte to push.
665 PushScancodeBufTail (
666 IN SCAN_CODE_QUEUE
*Queue
,
670 if (GetScancodeBufCount (Queue
) == KEYBOARD_SCAN_CODE_MAX_COUNT
- 1) {
671 PopScancodeBufHead (Queue
, 1, NULL
);
674 Queue
->Buffer
[Queue
->Tail
] = Scancode
;
675 Queue
->Tail
= (Queue
->Tail
+ 1) % KEYBOARD_SCAN_CODE_MAX_COUNT
;
681 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
683 @return return the value
687 KeyReadDataRegister (
688 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
692 return IoRead8 (ConsoleIn
->DataRegisterAddress
);
698 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
699 @param Data value wanted to be written
703 KeyWriteDataRegister (
704 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
708 IoWrite8 (ConsoleIn
->DataRegisterAddress
, Data
);
712 Read status register.
714 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
716 @return value in status register
720 KeyReadStatusRegister (
721 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
724 return IoRead8 (ConsoleIn
->StatusRegisterAddress
);
728 Write command register .
730 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
731 @param Data The value wanted to be written
735 KeyWriteCommandRegister (
736 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
740 IoWrite8 (ConsoleIn
->CommandRegisterAddress
, Data
);
744 Display error message.
746 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
747 @param ErrMsg Unicode string of error message
752 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
756 ConsoleIn
->KeyboardErr
= TRUE
;
760 Timer event handler: read a series of scancodes from 8042
761 and put them into memory scancode buffer.
762 it read as much scancodes to either fill
763 the memory buffer or empty the keyboard buffer.
764 It is registered as running under TPL_NOTIFY
766 @param Event The timer event
767 @param Context A KEYBOARD_CONSOLE_IN_DEV pointer
772 KeyboardTimerHandler (
780 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
782 ConsoleIn
= (KEYBOARD_CONSOLE_IN_DEV
*)Context
;
785 // Enter critical section
787 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
789 if (((KEYBOARD_CONSOLE_IN_DEV
*)Context
)->KeyboardErr
) {
791 // Leave critical section and return
793 gBS
->RestoreTPL (OldTpl
);
798 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
799 // KB is not connected to system. If KB is not connected to system, driver will find there's something
800 // error in the following code and wait for the input buffer empty, this waiting time should be short enough since
801 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
802 // Just skip the 'resend' process simply.
805 while ((KeyReadStatusRegister (ConsoleIn
) & (KEYBOARD_STATUS_REGISTER_TRANSMIT_TIMEOUT
|KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
)) ==
806 KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
810 // Read one byte of the scan code and store it into the memory buffer
812 Data
= KeyReadDataRegister (ConsoleIn
);
813 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 register 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 success 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) {
908 KeyWriteDataRegister (ConsoleIn
, Data
);
914 Issue keyboard command.
916 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
917 @param Data The buff holding the command
919 @retval EFI_TIMEOUT Keyboard is not ready to issuing
920 @retval EFI_SUCCESS Success to issue keyboard command
925 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
936 // Wait For Input Buffer Empty
938 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
939 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
944 MicroSecondDelay (30);
947 if (RegEmptied
== 0) {
954 KeyWriteCommandRegister (ConsoleIn
, Data
);
957 // Wait For Input Buffer Empty again
960 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
961 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
966 MicroSecondDelay (30);
969 if (RegEmptied
== 0) {
977 wait for a specific value to be presented on
978 8042 Data register by keyboard and then read it,
979 used in keyboard commands ack
981 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
982 @param Value the value wanted to be waited.
984 @retval EFI_TIMEOUT Fail to get specific value in given time
985 @retval EFI_SUCCESS Success to get specific value in given time.
989 KeyboardWaitForValue (
990 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1004 // Make sure the initial value of 'Data' is different from 'Value'
1007 if (Data
== Value
) {
1012 // Read from 8042 (multiple times if needed)
1013 // until the expected value appears
1014 // use SumTimeOut to control the iteration
1020 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1021 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1022 Data
= KeyReadDataRegister (ConsoleIn
);
1026 MicroSecondDelay (30);
1029 SumTimeOut
+= TimeOut
;
1031 if (Data
== Value
) {
1036 if (SumTimeOut
>= mWaitForValueTimeOut
) {
1052 Show keyboard status lights according to
1053 indicators in ConsoleIn.
1055 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1057 @return status of updating keyboard register
1061 UpdateStatusLights (
1062 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1069 // Send keyboard command
1071 Status
= KeyboardWrite (ConsoleIn
, 0xed);
1072 if (EFI_ERROR (Status
)) {
1076 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1079 // Light configuration
1082 if (ConsoleIn
->CapsLock
) {
1086 if (ConsoleIn
->NumLock
) {
1090 if (ConsoleIn
->ScrollLock
) {
1094 Status
= KeyboardWrite (ConsoleIn
, Command
);
1096 if (EFI_ERROR (Status
)) {
1100 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1105 Initialize the key state.
1107 @param ConsoleIn The KEYBOARD_CONSOLE_IN_DEV instance.
1108 @param KeyState A pointer to receive the key state information.
1111 InitializeKeyState (
1112 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1113 OUT EFI_KEY_STATE
*KeyState
1116 KeyState
->KeyShiftState
= EFI_SHIFT_STATE_VALID
1117 | (ConsoleIn
->LeftCtrl
? EFI_LEFT_CONTROL_PRESSED
: 0)
1118 | (ConsoleIn
->RightCtrl
? EFI_RIGHT_CONTROL_PRESSED
: 0)
1119 | (ConsoleIn
->LeftAlt
? EFI_LEFT_ALT_PRESSED
: 0)
1120 | (ConsoleIn
->RightAlt
? EFI_RIGHT_ALT_PRESSED
: 0)
1121 | (ConsoleIn
->LeftShift
? EFI_LEFT_SHIFT_PRESSED
: 0)
1122 | (ConsoleIn
->RightShift
? EFI_RIGHT_SHIFT_PRESSED
: 0)
1123 | (ConsoleIn
->LeftLogo
? EFI_LEFT_LOGO_PRESSED
: 0)
1124 | (ConsoleIn
->RightLogo
? EFI_RIGHT_LOGO_PRESSED
: 0)
1125 | (ConsoleIn
->Menu
? EFI_MENU_KEY_PRESSED
: 0)
1126 | (ConsoleIn
->SysReq
? EFI_SYS_REQ_PRESSED
: 0)
1128 KeyState
->KeyToggleState
= EFI_TOGGLE_STATE_VALID
1129 | (ConsoleIn
->CapsLock
? EFI_CAPS_LOCK_ACTIVE
: 0)
1130 | (ConsoleIn
->NumLock
? EFI_NUM_LOCK_ACTIVE
: 0)
1131 | (ConsoleIn
->ScrollLock
? EFI_SCROLL_LOCK_ACTIVE
: 0)
1132 | (ConsoleIn
->IsSupportPartialKey
? EFI_KEY_STATE_EXPOSED
: 0)
1137 Get scancode from scancode buffer and translate into EFI-scancode and unicode defined by EFI spec.
1139 The function is always called in TPL_NOTIFY.
1141 @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer
1146 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1154 EFI_KEY_DATA KeyData
;
1156 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
1160 UINT8 ScancodeArr
[3];
1161 UINT32 ScancodeArrPos
;
1164 // Check if there are enough bytes of scancode representing a single key
1165 // available in the buffer
1171 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1172 if (EFI_ERROR (Status
)) {
1176 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED0
) {
1178 // E0 to look ahead 2 bytes
1182 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1183 if (EFI_ERROR (Status
)) {
1186 } else if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED1
) {
1188 // E1 to look ahead 3 bytes
1192 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1193 if (EFI_ERROR (Status
)) {
1199 // if we reach this position, scancodes for a key is in buffer now,pop them
1201 Status
= PopScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1202 ASSERT_EFI_ERROR (Status
);
1205 // store the last available byte, this byte of scancode will be checked
1207 ScanCode
= ScancodeArr
[ScancodeArrPos
];
1211 // Check for special keys and update the driver state.
1214 case SCANCODE_CTRL_MAKE
:
1216 ConsoleIn
->RightCtrl
= TRUE
;
1218 ConsoleIn
->LeftCtrl
= TRUE
;
1222 case SCANCODE_CTRL_BREAK
:
1224 ConsoleIn
->RightCtrl
= FALSE
;
1226 ConsoleIn
->LeftCtrl
= FALSE
;
1231 case SCANCODE_ALT_MAKE
:
1233 ConsoleIn
->RightAlt
= TRUE
;
1235 ConsoleIn
->LeftAlt
= TRUE
;
1239 case SCANCODE_ALT_BREAK
:
1241 ConsoleIn
->RightAlt
= FALSE
;
1243 ConsoleIn
->LeftAlt
= FALSE
;
1248 case SCANCODE_LEFT_SHIFT_MAKE
:
1250 // To avoid recognize PRNT_SCRN key as a L_SHIFT key
1251 // because PRNT_SCRN key generates E0 followed by L_SHIFT scan code.
1252 // If it the second byte of the PRNT_ScRN skip it.
1255 ConsoleIn
->LeftShift
= TRUE
;
1261 case SCANCODE_LEFT_SHIFT_BREAK
:
1263 ConsoleIn
->LeftShift
= FALSE
;
1268 case SCANCODE_RIGHT_SHIFT_MAKE
:
1269 ConsoleIn
->RightShift
= TRUE
;
1271 case SCANCODE_RIGHT_SHIFT_BREAK
:
1272 ConsoleIn
->RightShift
= FALSE
;
1275 case SCANCODE_LEFT_LOGO_MAKE
:
1276 ConsoleIn
->LeftLogo
= TRUE
;
1278 case SCANCODE_LEFT_LOGO_BREAK
:
1279 ConsoleIn
->LeftLogo
= FALSE
;
1282 case SCANCODE_RIGHT_LOGO_MAKE
:
1283 ConsoleIn
->RightLogo
= TRUE
;
1285 case SCANCODE_RIGHT_LOGO_BREAK
:
1286 ConsoleIn
->RightLogo
= FALSE
;
1289 case SCANCODE_MENU_MAKE
:
1290 ConsoleIn
->Menu
= TRUE
;
1292 case SCANCODE_MENU_BREAK
:
1293 ConsoleIn
->Menu
= FALSE
;
1296 case SCANCODE_SYS_REQ_MAKE
:
1298 ConsoleIn
->SysReq
= TRUE
;
1302 case SCANCODE_SYS_REQ_BREAK
:
1304 ConsoleIn
->SysReq
= FALSE
;
1309 case SCANCODE_SYS_REQ_MAKE_WITH_ALT
:
1310 ConsoleIn
->SysReq
= TRUE
;
1312 case SCANCODE_SYS_REQ_BREAK_WITH_ALT
:
1313 ConsoleIn
->SysReq
= FALSE
;
1316 case SCANCODE_CAPS_LOCK_MAKE
:
1317 ConsoleIn
->CapsLock
= (BOOLEAN
) !ConsoleIn
->CapsLock
;
1318 UpdateStatusLights (ConsoleIn
);
1320 case SCANCODE_NUM_LOCK_MAKE
:
1321 ConsoleIn
->NumLock
= (BOOLEAN
) !ConsoleIn
->NumLock
;
1322 UpdateStatusLights (ConsoleIn
);
1324 case SCANCODE_SCROLL_LOCK_MAKE
:
1326 ConsoleIn
->ScrollLock
= (BOOLEAN
) !ConsoleIn
->ScrollLock
;
1327 UpdateStatusLights (ConsoleIn
);
1335 // If this is above the valid range, ignore it
1337 if (ScanCode
>= SCANCODE_MAX_MAKE
) {
1345 // Handle Ctrl+Alt+Del hotkey
1347 if ((ConsoleIn
->LeftCtrl
|| ConsoleIn
->RightCtrl
) &&
1348 (ConsoleIn
->LeftAlt
|| ConsoleIn
->RightAlt
) &&
1349 (ScanCode
== SCANCODE_DELETE_MAKE
)
1352 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1356 // Save the Shift/Toggle state
1358 InitializeKeyState (ConsoleIn
, &KeyData
.KeyState
);
1359 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1360 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1363 // Key Pad "/" shares the same scancode as that of "/" except Key Pad "/" has E0 prefix
1365 if (Extend0
&& (ScanCode
== 0x35)) {
1366 KeyData
.Key
.UnicodeChar
= L
'/';
1367 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1370 // PAUSE shares the same scancode as that of NUM except PAUSE has E1 prefix
1372 } else if (Extend1
&& (ScanCode
== SCANCODE_NUM_LOCK_MAKE
)) {
1373 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1374 KeyData
.Key
.ScanCode
= SCAN_PAUSE
;
1377 // PAUSE shares the same scancode as that of SCROLL except PAUSE (CTRL pressed) has E0 prefix
1379 } else if (Extend0
&& (ScanCode
== SCANCODE_SCROLL_LOCK_MAKE
)) {
1380 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1381 KeyData
.Key
.ScanCode
= SCAN_PAUSE
;
1384 // PRNT_SCRN shares the same scancode as that of Key Pad "*" except PRNT_SCRN has E0 prefix
1386 } else if (Extend0
&& (ScanCode
== SCANCODE_SYS_REQ_MAKE
)) {
1387 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1388 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1391 // Except the above special case, all others can be handled by convert table
1394 for (Index
= 0; ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
!= TABLE_END
; Index
++) {
1395 if (ScanCode
== ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
) {
1396 KeyData
.Key
.ScanCode
= ConvertKeyboardScanCodeToEfiKey
[Index
].EfiScanCode
;
1397 KeyData
.Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1399 if ((ConsoleIn
->LeftShift
|| ConsoleIn
->RightShift
) &&
1400 (ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
!= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
))
1402 KeyData
.Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1404 // Need not return associated shift state if a class of printable characters that
1405 // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
1407 KeyData
.KeyState
.KeyShiftState
&= ~(EFI_LEFT_SHIFT_PRESSED
| EFI_RIGHT_SHIFT_PRESSED
);
1411 // alphabetic key is affected by CapsLock State
1413 if (ConsoleIn
->CapsLock
) {
1414 if ((KeyData
.Key
.UnicodeChar
>= L
'a') && (KeyData
.Key
.UnicodeChar
<= L
'z')) {
1415 KeyData
.Key
.UnicodeChar
= (UINT16
)(KeyData
.Key
.UnicodeChar
- L
'a' + L
'A');
1416 } else if ((KeyData
.Key
.UnicodeChar
>= L
'A') && (KeyData
.Key
.UnicodeChar
<= L
'Z')) {
1417 KeyData
.Key
.UnicodeChar
= (UINT16
)(KeyData
.Key
.UnicodeChar
- L
'A' + L
'a');
1427 // distinguish numeric key pad keys' 'up symbol' and 'down symbol'
1429 if ((ScanCode
>= 0x47) && (ScanCode
<= 0x53)) {
1430 if (ConsoleIn
->NumLock
&& !(ConsoleIn
->LeftShift
|| ConsoleIn
->RightShift
) && !Extend0
) {
1431 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1432 } else if ((ScanCode
!= 0x4a) && (ScanCode
!= 0x4e)) {
1433 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1438 // If the key can not be converted then just return.
1440 if ((KeyData
.Key
.ScanCode
== SCAN_NULL
) && (KeyData
.Key
.UnicodeChar
== CHAR_NULL
)) {
1441 if (!ConsoleIn
->IsSupportPartialKey
) {
1447 // Signal KeyNotify process event if this key pressed matches any key registered.
1449 for (Link
= GetFirstNode (&ConsoleIn
->NotifyList
); !IsNull (&ConsoleIn
->NotifyList
, Link
); Link
= GetNextNode (&ConsoleIn
->NotifyList
, Link
)) {
1450 CurrentNotify
= CR (
1452 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
1454 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1456 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
1458 // The key notification function needs to run at TPL_CALLBACK
1459 // while current TPL is TPL_NOTIFY. It will be invoked in
1460 // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.
1462 PushEfikeyBufTail (&ConsoleIn
->EfiKeyQueueForNotify
, &KeyData
);
1463 gBS
->SignalEvent (ConsoleIn
->KeyNotifyProcessEvent
);
1468 PushEfikeyBufTail (&ConsoleIn
->EfiKeyQueue
, &KeyData
);
1472 Perform 8042 controller and keyboard Initialization.
1473 If ExtendedVerification is TRUE, do additional test for
1474 the keyboard interface
1476 @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
1477 @param ExtendedVerification - indicates a thorough initialization
1479 @retval EFI_DEVICE_ERROR Fail to init keyboard
1480 @retval EFI_SUCCESS Success to init keyboard
1484 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1485 IN BOOLEAN ExtendedVerification
1491 EFI_PS2_POLICY_PROTOCOL
*Ps2Policy
;
1494 Status
= EFI_SUCCESS
;
1495 mEnableMouseInterface
= TRUE
;
1499 // Get Ps2 policy to set this
1501 gBS
->LocateProtocol (
1502 &gEfiPs2PolicyProtocolGuid
,
1507 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1509 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
,
1510 ConsoleIn
->DevicePath
1514 // Perform a read to cleanup the Status Register's
1515 // output buffer full bits within MAX TRY times
1517 if ((KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
) != 0) {
1518 while (!EFI_ERROR (Status
) && TryTime
< KEYBOARD_MAX_TRY
) {
1519 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1524 // Exceed the max try times. The device may be error.
1526 if (TryTime
== KEYBOARD_MAX_TRY
) {
1527 Status
= EFI_DEVICE_ERROR
;
1533 // We should disable mouse interface during the initialization process
1534 // since mouse device output could block keyboard device output in the
1535 // 60H port of 8042 controller.
1537 // So if we are not initializing 8042 controller for the
1538 // first time, we have to remember the previous mouse interface
1541 // Test the system flag in to determine whether this is the first
1542 // time initialization
1544 if ((KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_SYSTEM_FLAG
) != 0) {
1545 if (!PcdGetBool (PcdFastPS2Detection
)) {
1547 // 8042 controller is already setup (by myself or by mouse driver):
1548 // See whether mouse interface is already enabled
1549 // which determines whether we should enable it later
1552 // Read the command byte of 8042 controller
1554 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_READ
);
1555 if (EFI_ERROR (Status
)) {
1556 KeyboardError (ConsoleIn
, L
"\n\r");
1560 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1561 if (EFI_ERROR (Status
)) {
1562 KeyboardError (ConsoleIn
, L
"\n\r");
1567 // Test the mouse enabling bit
1569 if ((CommandByte
& 0x20) != 0) {
1570 mEnableMouseInterface
= FALSE
;
1572 mEnableMouseInterface
= TRUE
;
1575 mEnableMouseInterface
= FALSE
;
1579 // 8042 controller is not setup yet:
1580 // 8042 controller selftest;
1581 // Don't enable mouse interface later.
1584 // Disable keyboard and mouse interfaces
1586 if (!PcdGetBool (PcdFastPS2Detection
)) {
1587 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1588 if (EFI_ERROR (Status
)) {
1589 KeyboardError (ConsoleIn
, L
"\n\r");
1593 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_MOUSE_INTERFACE
);
1594 if (EFI_ERROR (Status
)) {
1595 KeyboardError (ConsoleIn
, L
"\n\r");
1599 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1601 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
,
1602 ConsoleIn
->DevicePath
1605 // 8042 Controller Self Test
1607 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_CONTROLLER_SELF_TEST
);
1608 if (EFI_ERROR (Status
)) {
1609 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1613 Status
= KeyboardWaitForValue (ConsoleIn
, 0x55);
1614 if (EFI_ERROR (Status
)) {
1615 KeyboardError (ConsoleIn
, L
"8042 controller self test failed!\n\r");
1621 // Don't enable mouse interface later
1623 mEnableMouseInterface
= FALSE
;
1626 if (Ps2Policy
!= NULL
) {
1627 Ps2Policy
->Ps2InitHardware (ConsoleIn
->Handle
);
1631 // Write 8042 Command Byte, set System Flag
1632 // While at the same time:
1633 // 1. disable mouse interface,
1634 // 2. enable kbd interface,
1635 // 3. enable PC/XT kbd translation mode
1636 // 4. enable mouse and kbd interrupts
1638 // ( Command Byte bits:
1640 // 6: PC/XT translation mode
1641 // 5: Disable Auxiliary device interface
1642 // 4: Disable keyboard interface
1645 // 1: Enable Auxiliary device interrupt
1646 // 0: Enable Keyboard interrupt )
1648 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_WRITE
);
1649 if (EFI_ERROR (Status
)) {
1650 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1654 Status
= KeyboardWrite (ConsoleIn
, 0x67);
1655 if (EFI_ERROR (Status
)) {
1656 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1661 // Clear Memory Scancode Buffer
1663 ConsoleIn
->ScancodeQueue
.Head
= 0;
1664 ConsoleIn
->ScancodeQueue
.Tail
= 0;
1665 ConsoleIn
->EfiKeyQueue
.Head
= 0;
1666 ConsoleIn
->EfiKeyQueue
.Tail
= 0;
1667 ConsoleIn
->EfiKeyQueueForNotify
.Head
= 0;
1668 ConsoleIn
->EfiKeyQueueForNotify
.Tail
= 0;
1671 // Reset the status indicators
1673 ConsoleIn
->CapsLock
= FALSE
;
1674 ConsoleIn
->NumLock
= FALSE
;
1675 ConsoleIn
->ScrollLock
= FALSE
;
1676 ConsoleIn
->LeftCtrl
= FALSE
;
1677 ConsoleIn
->RightCtrl
= FALSE
;
1678 ConsoleIn
->LeftAlt
= FALSE
;
1679 ConsoleIn
->RightAlt
= FALSE
;
1680 ConsoleIn
->LeftShift
= FALSE
;
1681 ConsoleIn
->RightShift
= FALSE
;
1682 ConsoleIn
->LeftLogo
= FALSE
;
1683 ConsoleIn
->RightLogo
= FALSE
;
1684 ConsoleIn
->Menu
= FALSE
;
1685 ConsoleIn
->SysReq
= FALSE
;
1687 ConsoleIn
->IsSupportPartialKey
= FALSE
;
1689 // For resetting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1690 // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected
1691 // to system. So we only do the real resetting for keyboard when user asks and there is a real KB connected t system,
1692 // and normally during booting an OS, it's skipped.
1694 if (ExtendedVerification
&& CheckKeyboardConnect (ConsoleIn
)) {
1696 // Additional verifications for keyboard interface
1699 // Keyboard Interface Test
1701 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_KEYBOARD_INTERFACE_SELF_TEST
);
1702 if (EFI_ERROR (Status
)) {
1703 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1707 Status
= KeyboardWaitForValue (ConsoleIn
, 0x00);
1708 if (EFI_ERROR (Status
)) {
1711 L
"Some specific value not acquired from 8042 controller!\n\r"
1717 // Keyboard reset with a BAT(Basic Assurance Test)
1719 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_RESET
);
1720 if (EFI_ERROR (Status
)) {
1721 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1725 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1726 if (EFI_ERROR (Status
)) {
1727 KeyboardError (ConsoleIn
, L
"Some specific value not acquired from 8042 controller!\n\r");
1732 // wait for BAT completion code
1734 KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_BAT_SUCCESS
);
1736 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1739 // Set Keyboard to use Scan Code Set 2
1741 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_SELECT_SCAN_CODE_SET
);
1742 if (EFI_ERROR (Status
)) {
1743 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1747 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1748 if (EFI_ERROR (Status
)) {
1749 KeyboardError (ConsoleIn
, L
"Some specific value not acquired from 8042 controller!\n\r");
1753 Status
= KeyboardWrite (ConsoleIn
, 0x02);
1754 if (EFI_ERROR (Status
)) {
1755 KeyboardError (ConsoleIn
, L
"8042 controller data write error!!\n\r");
1759 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1760 if (EFI_ERROR (Status
)) {
1761 KeyboardError (ConsoleIn
, L
"Some specific value not acquired from 8042 controller!\n\r");
1766 // Clear Keyboard Scancode Buffer
1768 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_CLEAR_OUTPUT_DATA
);
1769 if (EFI_ERROR (Status
)) {
1770 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1774 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1775 if (EFI_ERROR (Status
)) {
1776 KeyboardError (ConsoleIn
, L
"Some specific value not acquired from 8042 controller!\n\r");
1781 if (Ps2Policy
!= NULL
) {
1782 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_CAPSLOCK
) == EFI_KEYBOARD_CAPSLOCK
) {
1783 ConsoleIn
->CapsLock
= TRUE
;
1786 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_NUMLOCK
) == EFI_KEYBOARD_NUMLOCK
) {
1787 ConsoleIn
->NumLock
= TRUE
;
1790 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_SCROLLLOCK
) == EFI_KEYBOARD_SCROLLLOCK
) {
1791 ConsoleIn
->ScrollLock
= TRUE
;
1796 // Update Keyboard Lights
1798 Status
= UpdateStatusLights (ConsoleIn
);
1799 if (EFI_ERROR (Status
)) {
1800 KeyboardError (ConsoleIn
, L
"Update keyboard status lights error!\n\r");
1806 // At last, we can now enable the mouse interface if appropriate
1810 if (mEnableMouseInterface
) {
1812 // Enable mouse interface
1814 Status1
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_ENABLE_MOUSE_INTERFACE
);
1815 if (EFI_ERROR (Status1
)) {
1816 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1817 return EFI_DEVICE_ERROR
;
1821 if (!EFI_ERROR (Status
)) {
1824 return EFI_DEVICE_ERROR
;
1829 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
1830 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
1831 should not be in system.
1833 @param[in] ConsoleIn Keyboard Private Data Structure
1835 @retval TRUE Keyboard in System.
1836 @retval FALSE Keyboard not in System.
1840 CheckKeyboardConnect (
1841 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1845 UINTN WaitForValueTimeOutBcakup
;
1848 // enable keyboard itself and wait for its ack
1849 // If can't receive ack, Keyboard should not be connected.
1851 if (!PcdGetBool (PcdFastPS2Detection
)) {
1852 Status
= KeyboardWrite (
1857 if (EFI_ERROR (Status
)) {
1864 WaitForValueTimeOutBcakup
= mWaitForValueTimeOut
;
1865 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1866 Status
= KeyboardWaitForValue (
1868 KEYBOARD_CMDECHO_ACK
1870 mWaitForValueTimeOut
= WaitForValueTimeOutBcakup
;
1872 if (EFI_ERROR (Status
)) {