2 Routines that access 8042 keyboard controller
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5 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
562 // The WaitForValue time out
564 UINTN mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
566 BOOLEAN mEnableMouseInterface
;
571 Return the count of scancode in the queue.
573 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
575 @return Count of the scancode.
578 GetScancodeBufCount (
579 IN SCAN_CODE_QUEUE
*Queue
582 if (Queue
->Head
<= Queue
->Tail
) {
583 return Queue
->Tail
- Queue
->Head
;
585 return Queue
->Tail
+ KEYBOARD_SCAN_CODE_MAX_COUNT
- Queue
->Head
;
590 Read several bytes from the scancode buffer without removing them.
591 This function is called to see if there are enough bytes of scancode
592 representing a single key.
594 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
595 @param Count Number of bytes to be read
596 @param Buf Store the results
598 @retval EFI_SUCCESS success to scan the keyboard code
599 @retval EFI_NOT_READY invalid parameter
603 IN SCAN_CODE_QUEUE
*Queue
,
612 // check the valid range of parameter 'Count'
614 if (GetScancodeBufCount (Queue
) < Count
) {
615 return EFI_NOT_READY
;
618 // retrieve the values
620 for (Index
= 0, Pos
= Queue
->Head
; Index
< Count
; Index
++, Pos
= (Pos
+ 1) % KEYBOARD_SCAN_CODE_MAX_COUNT
) {
621 Buf
[Index
] = Queue
->Buffer
[Pos
];
629 Read & remove several bytes from the scancode buffer.
630 This function is usually called after GetScancodeBufHead()
632 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
633 @param Count Number of bytes to be read
634 @param Buf Store the results
636 @retval EFI_SUCCESS success to scan the keyboard code
637 @retval EFI_NOT_READY invalid parameter
641 IN SCAN_CODE_QUEUE
*Queue
,
643 OUT UINT8
*Buf OPTIONAL
649 // Check the valid range of parameter 'Count'
651 if (GetScancodeBufCount (Queue
) < Count
) {
652 return EFI_NOT_READY
;
655 // Retrieve and remove the values
657 for (Index
= 0; Index
< Count
; Index
++, Queue
->Head
= (Queue
->Head
+ 1) % KEYBOARD_SCAN_CODE_MAX_COUNT
) {
659 Buf
[Index
] = Queue
->Buffer
[Queue
->Head
];
667 Push one byte to the scancode buffer.
669 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
670 @param Scancode The byte to push.
673 PushScancodeBufTail (
674 IN SCAN_CODE_QUEUE
*Queue
,
678 if (GetScancodeBufCount (Queue
) == KEYBOARD_SCAN_CODE_MAX_COUNT
- 1) {
679 PopScancodeBufHead (Queue
, 1, NULL
);
682 Queue
->Buffer
[Queue
->Tail
] = Scancode
;
683 Queue
->Tail
= (Queue
->Tail
+ 1) % KEYBOARD_SCAN_CODE_MAX_COUNT
;
689 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
691 @return return the value
695 KeyReadDataRegister (
696 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
700 return IoRead8 (ConsoleIn
->DataRegisterAddress
);
706 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
707 @param Data value wanted to be written
711 KeyWriteDataRegister (
712 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
716 IoWrite8 (ConsoleIn
->DataRegisterAddress
, Data
);
720 Read status register.
722 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
724 @return value in status register
728 KeyReadStatusRegister (
729 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
732 return IoRead8 (ConsoleIn
->StatusRegisterAddress
);
736 Write command register .
738 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
739 @param Data The value wanted to be written
743 KeyWriteCommandRegister (
744 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
748 IoWrite8 (ConsoleIn
->CommandRegisterAddress
, Data
);
752 Display error message.
754 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
755 @param ErrMsg Unicode string of error message
760 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
764 ConsoleIn
->KeyboardErr
= TRUE
;
768 Timer event handler: read a series of scancodes from 8042
769 and put them into memory scancode buffer.
770 it read as much scancodes to either fill
771 the memory buffer or empty the keyboard buffer.
772 It is registered as running under TPL_NOTIFY
774 @param Event The timer event
775 @param Context A KEYBOARD_CONSOLE_IN_DEV pointer
780 KeyboardTimerHandler (
788 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
790 ConsoleIn
= (KEYBOARD_CONSOLE_IN_DEV
*) Context
;
793 // Enter critical section
795 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
797 if (((KEYBOARD_CONSOLE_IN_DEV
*) Context
)->KeyboardErr
) {
799 // Leave critical section and return
801 gBS
->RestoreTPL (OldTpl
);
806 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
807 // KB is not connected to system. If KB is not connected to system, driver will find there's something
808 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
809 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
810 // Just skip the 'resend' process simply.
813 while ((KeyReadStatusRegister (ConsoleIn
) & (KEYBOARD_STATUS_REGISTER_TRANSMIT_TIMEOUT
|KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
)) ==
814 KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
817 // Read one byte of the scan code and store it into the memory buffer
819 Data
= KeyReadDataRegister (ConsoleIn
);
820 PushScancodeBufTail (&ConsoleIn
->ScancodeQueue
, Data
);
822 KeyGetchar (ConsoleIn
);
825 // Leave critical section and return
827 gBS
->RestoreTPL (OldTpl
);
833 @param ConsoleIn - Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
834 @param Data - Pointer to outof buffer for keeping key value
836 @retval EFI_TIMEOUT Status resigter time out
837 @retval EFI_SUCCESS Success to read keyboard
842 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
854 // wait till output buffer full then perform the read
856 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
857 if (KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
) {
859 *Data
= KeyReadDataRegister (ConsoleIn
);
863 MicroSecondDelay (30);
866 if (RegFilled
== 0) {
874 write key to keyboard
876 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
877 @param Data value wanted to be written
879 @retval EFI_TIMEOUT The input buffer register is full for putting new value util timeout
880 @retval EFI_SUCCESS The new value is sucess put into input buffer register.
885 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
896 // wait for input buffer empty
898 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
899 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
904 MicroSecondDelay (30);
907 if (RegEmptied
== 0) {
913 KeyWriteDataRegister (ConsoleIn
, Data
);
919 Issue keyboard command.
921 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
922 @param Data The buff holding the command
924 @retval EFI_TIMEOUT Keyboard is not ready to issuing
925 @retval EFI_SUCCESS Success to issue keyboard command
930 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
941 // Wait For Input Buffer Empty
943 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
944 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
949 MicroSecondDelay (30);
952 if (RegEmptied
== 0) {
958 KeyWriteCommandRegister (ConsoleIn
, Data
);
961 // Wait For Input Buffer Empty again
964 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
965 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
970 MicroSecondDelay (30);
973 if (RegEmptied
== 0) {
981 wait for a specific value to be presented on
982 8042 Data register by keyboard and then read it,
983 used in keyboard commands ack
985 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
986 @param Value the value wanted to be waited.
988 @retval EFI_TIMEOUT Fail to get specific value in given time
989 @retval EFI_SUCCESS Success to get specific value in given time.
993 KeyboardWaitForValue (
994 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1008 // Make sure the initial value of 'Data' is different from 'Value'
1011 if (Data
== Value
) {
1015 // Read from 8042 (multiple times if needed)
1016 // until the expected value appears
1017 // use SumTimeOut to control the iteration
1023 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1024 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1025 Data
= KeyReadDataRegister (ConsoleIn
);
1029 MicroSecondDelay (30);
1032 SumTimeOut
+= TimeOut
;
1034 if (Data
== Value
) {
1039 if (SumTimeOut
>= mWaitForValueTimeOut
) {
1055 Show keyboard status lights according to
1056 indicators in ConsoleIn.
1058 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1060 @return status of updating keyboard register
1064 UpdateStatusLights (
1065 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1072 // Send keyboard command
1074 Status
= KeyboardWrite (ConsoleIn
, 0xed);
1075 if (EFI_ERROR (Status
)) {
1079 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1082 // Light configuration
1085 if (ConsoleIn
->CapsLock
) {
1089 if (ConsoleIn
->NumLock
) {
1093 if (ConsoleIn
->ScrollLock
) {
1097 Status
= KeyboardWrite (ConsoleIn
, Command
);
1099 if (EFI_ERROR (Status
)) {
1103 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1108 Get scancode from scancode buffer and translate into EFI-scancode and unicode defined by EFI spec.
1110 The function is always called in TPL_NOTIFY.
1112 @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer
1117 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1125 EFI_KEY_DATA KeyData
;
1127 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
1131 UINT8 ScancodeArr
[3];
1132 UINT32 ScancodeArrPos
;
1135 // Check if there are enough bytes of scancode representing a single key
1136 // available in the buffer
1142 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1143 if (EFI_ERROR (Status
)) {
1147 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED0
) {
1149 // E0 to look ahead 2 bytes
1153 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1154 if (EFI_ERROR (Status
)) {
1157 } else if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED1
) {
1159 // E1 to look ahead 3 bytes
1163 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1164 if (EFI_ERROR (Status
)) {
1169 // if we reach this position, scancodes for a key is in buffer now,pop them
1171 Status
= PopScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1172 ASSERT_EFI_ERROR (Status
);
1175 // store the last available byte, this byte of scancode will be checked
1177 ScanCode
= ScancodeArr
[ScancodeArrPos
];
1181 // Check for special keys and update the driver state.
1185 case SCANCODE_CTRL_MAKE
:
1187 ConsoleIn
->RightCtrl
= TRUE
;
1189 ConsoleIn
->LeftCtrl
= TRUE
;
1192 case SCANCODE_CTRL_BREAK
:
1194 ConsoleIn
->RightCtrl
= FALSE
;
1196 ConsoleIn
->LeftCtrl
= FALSE
;
1200 case SCANCODE_ALT_MAKE
:
1202 ConsoleIn
->RightAlt
= TRUE
;
1204 ConsoleIn
->LeftAlt
= TRUE
;
1207 case SCANCODE_ALT_BREAK
:
1209 ConsoleIn
->RightAlt
= FALSE
;
1211 ConsoleIn
->LeftAlt
= FALSE
;
1215 case SCANCODE_LEFT_SHIFT_MAKE
:
1217 // To avoid recognize PRNT_SCRN key as a L_SHIFT key
1218 // because PRNT_SCRN key generates E0 followed by L_SHIFT scan code.
1219 // If it the second byte of the PRNT_ScRN skip it.
1222 ConsoleIn
->LeftShift
= TRUE
;
1227 case SCANCODE_LEFT_SHIFT_BREAK
:
1229 ConsoleIn
->LeftShift
= FALSE
;
1233 case SCANCODE_RIGHT_SHIFT_MAKE
:
1234 ConsoleIn
->RightShift
= TRUE
;
1236 case SCANCODE_RIGHT_SHIFT_BREAK
:
1237 ConsoleIn
->RightShift
= FALSE
;
1240 case SCANCODE_LEFT_LOGO_MAKE
:
1241 ConsoleIn
->LeftLogo
= TRUE
;
1243 case SCANCODE_LEFT_LOGO_BREAK
:
1244 ConsoleIn
->LeftLogo
= FALSE
;
1247 case SCANCODE_RIGHT_LOGO_MAKE
:
1248 ConsoleIn
->RightLogo
= TRUE
;
1250 case SCANCODE_RIGHT_LOGO_BREAK
:
1251 ConsoleIn
->RightLogo
= FALSE
;
1254 case SCANCODE_MENU_MAKE
:
1255 ConsoleIn
->Menu
= TRUE
;
1257 case SCANCODE_MENU_BREAK
:
1258 ConsoleIn
->Menu
= FALSE
;
1261 case SCANCODE_SYS_REQ_MAKE
:
1263 ConsoleIn
->SysReq
= TRUE
;
1266 case SCANCODE_SYS_REQ_BREAK
:
1268 ConsoleIn
->SysReq
= FALSE
;
1272 case SCANCODE_SYS_REQ_MAKE_WITH_ALT
:
1273 ConsoleIn
->SysReq
= TRUE
;
1275 case SCANCODE_SYS_REQ_BREAK_WITH_ALT
:
1276 ConsoleIn
->SysReq
= FALSE
;
1279 case SCANCODE_CAPS_LOCK_MAKE
:
1280 ConsoleIn
->CapsLock
= (BOOLEAN
)!ConsoleIn
->CapsLock
;
1281 UpdateStatusLights (ConsoleIn
);
1283 case SCANCODE_NUM_LOCK_MAKE
:
1284 ConsoleIn
->NumLock
= (BOOLEAN
)!ConsoleIn
->NumLock
;
1285 UpdateStatusLights (ConsoleIn
);
1287 case SCANCODE_SCROLL_LOCK_MAKE
:
1289 ConsoleIn
->ScrollLock
= (BOOLEAN
)!ConsoleIn
->ScrollLock
;
1290 UpdateStatusLights (ConsoleIn
);
1297 // If this is above the valid range, ignore it
1299 if (ScanCode
>= SCANCODE_MAX_MAKE
) {
1307 // Handle Ctrl+Alt+Del hotkey
1309 if ((ConsoleIn
->LeftCtrl
|| ConsoleIn
->RightCtrl
) &&
1310 (ConsoleIn
->LeftAlt
|| ConsoleIn
->RightAlt
) &&
1311 ScanCode
== SCANCODE_DELETE_MAKE
1313 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1317 // Save the Shift/Toggle state
1319 KeyData
.KeyState
.KeyShiftState
= (UINT32
) (EFI_SHIFT_STATE_VALID
1320 | (ConsoleIn
->LeftCtrl
? EFI_LEFT_CONTROL_PRESSED
: 0)
1321 | (ConsoleIn
->RightCtrl
? EFI_RIGHT_CONTROL_PRESSED
: 0)
1322 | (ConsoleIn
->LeftAlt
? EFI_LEFT_ALT_PRESSED
: 0)
1323 | (ConsoleIn
->RightAlt
? EFI_RIGHT_ALT_PRESSED
: 0)
1324 | (ConsoleIn
->LeftShift
? EFI_LEFT_SHIFT_PRESSED
: 0)
1325 | (ConsoleIn
->RightShift
? EFI_RIGHT_SHIFT_PRESSED
: 0)
1326 | (ConsoleIn
->LeftLogo
? EFI_LEFT_LOGO_PRESSED
: 0)
1327 | (ConsoleIn
->RightLogo
? EFI_RIGHT_LOGO_PRESSED
: 0)
1328 | (ConsoleIn
->Menu
? EFI_MENU_KEY_PRESSED
: 0)
1329 | (ConsoleIn
->SysReq
? EFI_SYS_REQ_PRESSED
: 0)
1331 KeyData
.KeyState
.KeyToggleState
= (EFI_KEY_TOGGLE_STATE
) (EFI_TOGGLE_STATE_VALID
1332 | (ConsoleIn
->CapsLock
? EFI_CAPS_LOCK_ACTIVE
: 0)
1333 | (ConsoleIn
->NumLock
? EFI_NUM_LOCK_ACTIVE
: 0)
1334 | (ConsoleIn
->ScrollLock
? EFI_SCROLL_LOCK_ACTIVE
: 0)
1335 | (ConsoleIn
->IsSupportPartialKey
? EFI_KEY_STATE_EXPOSED
: 0)
1338 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1339 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1342 // Key Pad "/" shares the same scancode as that of "/" except Key Pad "/" has E0 prefix
1344 if (Extend0
&& ScanCode
== 0x35) {
1345 KeyData
.Key
.UnicodeChar
= L
'/';
1346 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1349 // PAUSE shares the same scancode as that of NUM except PAUSE has E1 prefix
1351 } else if (Extend1
&& ScanCode
== SCANCODE_NUM_LOCK_MAKE
) {
1352 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1353 KeyData
.Key
.ScanCode
= SCAN_PAUSE
;
1356 // PAUSE shares the same scancode as that of SCROLL except PAUSE (CTRL pressed) has E0 prefix
1358 } else if (Extend0
&& ScanCode
== SCANCODE_SCROLL_LOCK_MAKE
) {
1359 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1360 KeyData
.Key
.ScanCode
= SCAN_PAUSE
;
1363 // PRNT_SCRN shares the same scancode as that of Key Pad "*" except PRNT_SCRN has E0 prefix
1365 } else if (Extend0
&& ScanCode
== SCANCODE_SYS_REQ_MAKE
) {
1366 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1367 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1370 // Except the above special case, all others can be handled by convert table
1373 for (Index
= 0; ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
!= TABLE_END
; Index
++) {
1374 if (ScanCode
== ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
) {
1375 KeyData
.Key
.ScanCode
= ConvertKeyboardScanCodeToEfiKey
[Index
].EfiScanCode
;
1376 KeyData
.Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1378 if ((ConsoleIn
->LeftShift
|| ConsoleIn
->RightShift
) &&
1379 (ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
!= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
)) {
1380 KeyData
.Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1382 // Need not return associated shift state if a class of printable characters that
1383 // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
1385 KeyData
.KeyState
.KeyShiftState
&= ~(EFI_LEFT_SHIFT_PRESSED
| EFI_RIGHT_SHIFT_PRESSED
);
1388 // alphabetic key is affected by CapsLock State
1390 if (ConsoleIn
->CapsLock
) {
1391 if (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z') {
1392 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'a' + L
'A');
1393 } else if (KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') {
1394 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'A' + L
'a');
1403 // distinguish numeric key pad keys' 'up symbol' and 'down symbol'
1405 if (ScanCode
>= 0x47 && ScanCode
<= 0x53) {
1406 if (ConsoleIn
->NumLock
&& !(ConsoleIn
->LeftShift
|| ConsoleIn
->RightShift
) && !Extend0
) {
1407 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1408 } else if (ScanCode
!= 0x4a && ScanCode
!= 0x4e) {
1409 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1414 // If the key can not be converted then just return.
1416 if (KeyData
.Key
.ScanCode
== SCAN_NULL
&& KeyData
.Key
.UnicodeChar
== CHAR_NULL
) {
1417 if (!ConsoleIn
->IsSupportPartialKey
) {
1423 // Signal KeyNotify process event if this key pressed matches any key registered.
1425 for (Link
= GetFirstNode (&ConsoleIn
->NotifyList
); !IsNull (&ConsoleIn
->NotifyList
, Link
); Link
= GetNextNode (&ConsoleIn
->NotifyList
, Link
)) {
1426 CurrentNotify
= CR (
1428 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
1430 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1432 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
1434 // The key notification function needs to run at TPL_CALLBACK
1435 // while current TPL is TPL_NOTIFY. It will be invoked in
1436 // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.
1438 PushEfikeyBufTail (&ConsoleIn
->EfiKeyQueueForNotify
, &KeyData
);
1439 gBS
->SignalEvent (ConsoleIn
->KeyNotifyProcessEvent
);
1443 PushEfikeyBufTail (&ConsoleIn
->EfiKeyQueue
, &KeyData
);
1447 Perform 8042 controller and keyboard Initialization.
1448 If ExtendedVerification is TRUE, do additional test for
1449 the keyboard interface
1451 @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
1452 @param ExtendedVerification - indicates a thorough initialization
1454 @retval EFI_DEVICE_ERROR Fail to init keyboard
1455 @retval EFI_SUCCESS Success to init keyboard
1459 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1460 IN BOOLEAN ExtendedVerification
1466 EFI_PS2_POLICY_PROTOCOL
*Ps2Policy
;
1469 Status
= EFI_SUCCESS
;
1470 mEnableMouseInterface
= TRUE
;
1474 // Get Ps2 policy to set this
1476 gBS
->LocateProtocol (
1477 &gEfiPs2PolicyProtocolGuid
,
1479 (VOID
**) &Ps2Policy
1482 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1484 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
,
1485 ConsoleIn
->DevicePath
1489 // Perform a read to cleanup the Status Register's
1490 // output buffer full bits within MAX TRY times
1492 if ((KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
) != 0) {
1493 while (!EFI_ERROR (Status
) && TryTime
< KEYBOARD_MAX_TRY
) {
1494 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1498 // Exceed the max try times. The device may be error.
1500 if (TryTime
== KEYBOARD_MAX_TRY
) {
1501 Status
= EFI_DEVICE_ERROR
;
1506 // We should disable mouse interface during the initialization process
1507 // since mouse device output could block keyboard device output in the
1508 // 60H port of 8042 controller.
1510 // So if we are not initializing 8042 controller for the
1511 // first time, we have to remember the previous mouse interface
1514 // Test the system flag in to determine whether this is the first
1515 // time initialization
1517 if ((KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_SYSTEM_FLAG
) != 0) {
1518 if (!PcdGetBool (PcdFastPS2Detection
)) {
1520 // 8042 controller is already setup (by myself or by mouse driver):
1521 // See whether mouse interface is already enabled
1522 // which determines whether we should enable it later
1525 // Read the command byte of 8042 controller
1527 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_READ
);
1528 if (EFI_ERROR (Status
)) {
1529 KeyboardError (ConsoleIn
, L
"\n\r");
1533 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1534 if (EFI_ERROR (Status
)) {
1535 KeyboardError (ConsoleIn
, L
"\n\r");
1539 // Test the mouse enabling bit
1541 if ((CommandByte
& 0x20) != 0) {
1542 mEnableMouseInterface
= FALSE
;
1544 mEnableMouseInterface
= TRUE
;
1547 mEnableMouseInterface
= FALSE
;
1551 // 8042 controller is not setup yet:
1552 // 8042 controller selftest;
1553 // Don't enable mouse interface later.
1556 // Disable keyboard and mouse interfaces
1558 if (!PcdGetBool (PcdFastPS2Detection
)) {
1559 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1560 if (EFI_ERROR (Status
)) {
1561 KeyboardError (ConsoleIn
, L
"\n\r");
1565 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_MOUSE_INTERFACE
);
1566 if (EFI_ERROR (Status
)) {
1567 KeyboardError (ConsoleIn
, L
"\n\r");
1571 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1573 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
,
1574 ConsoleIn
->DevicePath
1577 // 8042 Controller Self Test
1579 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_CONTROLLER_SELF_TEST
);
1580 if (EFI_ERROR (Status
)) {
1581 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1585 Status
= KeyboardWaitForValue (ConsoleIn
, 0x55);
1586 if (EFI_ERROR (Status
)) {
1587 KeyboardError (ConsoleIn
, L
"8042 controller self test failed!\n\r");
1592 // Don't enable mouse interface later
1594 mEnableMouseInterface
= FALSE
;
1598 if (Ps2Policy
!= NULL
) {
1599 Ps2Policy
->Ps2InitHardware (ConsoleIn
->Handle
);
1602 // Write 8042 Command Byte, set System Flag
1603 // While at the same time:
1604 // 1. disable mouse interface,
1605 // 2. enable kbd interface,
1606 // 3. enable PC/XT kbd translation mode
1607 // 4. enable mouse and kbd interrupts
1609 // ( Command Byte bits:
1611 // 6: PC/XT translation mode
1612 // 5: Disable Auxiliary device interface
1613 // 4: Disable keyboard interface
1616 // 1: Enable Auxiliary device interrupt
1617 // 0: Enable Keyboard interrupt )
1619 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_WRITE
);
1620 if (EFI_ERROR (Status
)) {
1621 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1625 Status
= KeyboardWrite (ConsoleIn
, 0x67);
1626 if (EFI_ERROR (Status
)) {
1627 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1632 // Clear Memory Scancode Buffer
1634 ConsoleIn
->ScancodeQueue
.Head
= 0;
1635 ConsoleIn
->ScancodeQueue
.Tail
= 0;
1636 ConsoleIn
->EfiKeyQueue
.Head
= 0;
1637 ConsoleIn
->EfiKeyQueue
.Tail
= 0;
1638 ConsoleIn
->EfiKeyQueueForNotify
.Head
= 0;
1639 ConsoleIn
->EfiKeyQueueForNotify
.Tail
= 0;
1642 // Reset the status indicators
1644 ConsoleIn
->CapsLock
= FALSE
;
1645 ConsoleIn
->NumLock
= FALSE
;
1646 ConsoleIn
->ScrollLock
= FALSE
;
1647 ConsoleIn
->LeftCtrl
= FALSE
;
1648 ConsoleIn
->RightCtrl
= FALSE
;
1649 ConsoleIn
->LeftAlt
= FALSE
;
1650 ConsoleIn
->RightAlt
= FALSE
;
1651 ConsoleIn
->LeftShift
= FALSE
;
1652 ConsoleIn
->RightShift
= FALSE
;
1653 ConsoleIn
->LeftLogo
= FALSE
;
1654 ConsoleIn
->RightLogo
= FALSE
;
1655 ConsoleIn
->Menu
= FALSE
;
1656 ConsoleIn
->SysReq
= FALSE
;
1658 ConsoleIn
->IsSupportPartialKey
= FALSE
;
1660 // For resetting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1661 // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected
1662 // to system. So we only do the real resetting for keyboard when user asks and there is a real KB connected t system,
1663 // and normally during booting an OS, it's skipped.
1665 if (ExtendedVerification
&& CheckKeyboardConnect (ConsoleIn
)) {
1667 // Additional verifications for keyboard interface
1670 // Keyboard Interface Test
1672 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_KEYBOARD_INTERFACE_SELF_TEST
);
1673 if (EFI_ERROR (Status
)) {
1674 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1678 Status
= KeyboardWaitForValue (ConsoleIn
, 0x00);
1679 if (EFI_ERROR (Status
)) {
1682 L
"Some specific value not aquired from 8042 controller!\n\r"
1687 // Keyboard reset with a BAT(Basic Assurance Test)
1689 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_RESET
);
1690 if (EFI_ERROR (Status
)) {
1691 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1695 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1696 if (EFI_ERROR (Status
)) {
1697 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1701 // wait for BAT completion code
1703 mWaitForValueTimeOut
= KEYBOARD_BAT_TIMEOUT
;
1705 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_BAT_SUCCESS
);
1706 if (EFI_ERROR (Status
)) {
1707 KeyboardError (ConsoleIn
, L
"Keyboard self test failed!\n\r");
1711 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1714 // Set Keyboard to use Scan Code Set 2
1716 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_SELECT_SCAN_CODE_SET
);
1717 if (EFI_ERROR (Status
)) {
1718 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1722 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1723 if (EFI_ERROR (Status
)) {
1724 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1728 Status
= KeyboardWrite (ConsoleIn
, 0x02);
1729 if (EFI_ERROR (Status
)) {
1730 KeyboardError (ConsoleIn
, L
"8042 controller data write error!!\n\r");
1734 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1735 if (EFI_ERROR (Status
)) {
1736 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1741 // Clear Keyboard Scancode Buffer
1743 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_CLEAR_OUTPUT_DATA
);
1744 if (EFI_ERROR (Status
)) {
1745 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1749 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1750 if (EFI_ERROR (Status
)) {
1751 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1755 if (Ps2Policy
!= NULL
) {
1756 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_CAPSLOCK
) == EFI_KEYBOARD_CAPSLOCK
) {
1757 ConsoleIn
->CapsLock
= TRUE
;
1760 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_NUMLOCK
) == EFI_KEYBOARD_NUMLOCK
) {
1761 ConsoleIn
->NumLock
= TRUE
;
1764 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_SCROLLLOCK
) == EFI_KEYBOARD_SCROLLLOCK
) {
1765 ConsoleIn
->ScrollLock
= TRUE
;
1769 // Update Keyboard Lights
1771 Status
= UpdateStatusLights (ConsoleIn
);
1772 if (EFI_ERROR (Status
)) {
1773 KeyboardError (ConsoleIn
, L
"Update keyboard status lights error!\n\r");
1778 // At last, we can now enable the mouse interface if appropriate
1782 if (mEnableMouseInterface
) {
1784 // Enable mouse interface
1786 Status1
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_ENABLE_MOUSE_INTERFACE
);
1787 if (EFI_ERROR (Status1
)) {
1788 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1789 return EFI_DEVICE_ERROR
;
1793 if (!EFI_ERROR (Status
)) {
1796 return EFI_DEVICE_ERROR
;
1802 Disable the keyboard interface of the 8042 controller.
1804 @param ConsoleIn The device instance
1806 @return status of issuing disable command
1811 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1817 // Disable keyboard interface
1819 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1820 if (EFI_ERROR (Status
)) {
1821 KeyboardError (ConsoleIn
, L
"\n\r");
1822 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
)) {
1863 WaitForValueTimeOutBcakup
= mWaitForValueTimeOut
;
1864 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1865 Status
= KeyboardWaitForValue (
1867 KEYBOARD_CMDECHO_ACK
1869 mWaitForValueTimeOut
= WaitForValueTimeOutBcakup
;
1871 if (EFI_ERROR (Status
)) {