2 Routines that access 8042 keyboard controller
4 Copyright (c) 2006 - 2018, 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 EFI_ISA_IO_PROTOCOL
*IsaIo
;
704 // Use IsaIo protocol to perform IO operations
706 IsaIo
= ConsoleIn
->IsaIo
;
711 ConsoleIn
->DataRegisterAddress
,
722 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
723 @param Data value wanted to be written
727 KeyWriteDataRegister (
728 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
732 ConsoleIn
->IsaIo
->Io
.Write (
735 ConsoleIn
->DataRegisterAddress
,
742 Read status register.
744 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
746 @return value in status register
750 KeyReadStatusRegister (
751 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
755 ConsoleIn
->IsaIo
->Io
.Read (
758 ConsoleIn
->StatusRegisterAddress
,
766 Write command register .
768 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
769 @param Data The value wanted to be written
773 KeyWriteCommandRegister (
774 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
778 ConsoleIn
->IsaIo
->Io
.Write (
781 ConsoleIn
->CommandRegisterAddress
,
788 Display error message.
790 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
791 @param ErrMsg Unicode string of error message
796 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
800 ConsoleIn
->KeyboardErr
= TRUE
;
804 Timer event handler: read a series of scancodes from 8042
805 and put them into memory scancode buffer.
806 it read as much scancodes to either fill
807 the memory buffer or empty the keyboard buffer.
808 It is registered as running under TPL_NOTIFY
810 @param Event The timer event
811 @param Context A KEYBOARD_CONSOLE_IN_DEV pointer
816 KeyboardTimerHandler (
824 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
826 ConsoleIn
= (KEYBOARD_CONSOLE_IN_DEV
*) Context
;
829 // Enter critical section
831 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
833 if (((KEYBOARD_CONSOLE_IN_DEV
*) Context
)->KeyboardErr
) {
835 // Leave critical section and return
837 gBS
->RestoreTPL (OldTpl
);
842 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
843 // KB is not connected to system. If KB is not connected to system, driver will find there's something
844 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
845 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
846 // Just skip the 'resend' process simply.
849 while ((KeyReadStatusRegister (ConsoleIn
) & (KEYBOARD_STATUS_REGISTER_TRANSMIT_TIMEOUT
|KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
)) ==
850 KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
853 // Read one byte of the scan code and store it into the memory buffer
855 Data
= KeyReadDataRegister (ConsoleIn
);
856 PushScancodeBufTail (&ConsoleIn
->ScancodeQueue
, Data
);
858 KeyGetchar (ConsoleIn
);
861 // Leave critical section and return
863 gBS
->RestoreTPL (OldTpl
);
869 @param ConsoleIn - Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
870 @param Data - Pointer to outof buffer for keeping key value
872 @retval EFI_TIMEOUT Status resigter time out
873 @retval EFI_SUCCESS Success to read keyboard
878 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
890 // wait till output buffer full then perform the read
892 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
893 if (KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
) {
895 *Data
= KeyReadDataRegister (ConsoleIn
);
899 MicroSecondDelay (30);
902 if (RegFilled
== 0) {
910 write key to keyboard
912 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
913 @param Data value wanted to be written
915 @retval EFI_TIMEOUT The input buffer register is full for putting new value util timeout
916 @retval EFI_SUCCESS The new value is sucess put into input buffer register.
921 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
932 // wait for input buffer empty
934 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
935 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
940 MicroSecondDelay (30);
943 if (RegEmptied
== 0) {
949 KeyWriteDataRegister (ConsoleIn
, Data
);
955 Issue keyboard command.
957 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
958 @param Data The buff holding the command
960 @retval EFI_TIMEOUT Keyboard is not ready to issuing
961 @retval EFI_SUCCESS Success to issue keyboard command
966 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
977 // Wait For Input Buffer Empty
979 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
980 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
985 MicroSecondDelay (30);
988 if (RegEmptied
== 0) {
994 KeyWriteCommandRegister (ConsoleIn
, Data
);
997 // Wait For Input Buffer Empty again
1000 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1001 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
1006 MicroSecondDelay (30);
1009 if (RegEmptied
== 0) {
1017 wait for a specific value to be presented on
1018 8042 Data register by keyboard and then read it,
1019 used in keyboard commands ack
1021 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1022 @param Value the value wanted to be waited.
1024 @retval EFI_TIMEOUT Fail to get specific value in given time
1025 @retval EFI_SUCCESS Success to get specific value in given time.
1029 KeyboardWaitForValue (
1030 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1044 // Make sure the initial value of 'Data' is different from 'Value'
1047 if (Data
== Value
) {
1051 // Read from 8042 (multiple times if needed)
1052 // until the expected value appears
1053 // use SumTimeOut to control the iteration
1059 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1060 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1061 Data
= KeyReadDataRegister (ConsoleIn
);
1065 MicroSecondDelay (30);
1068 SumTimeOut
+= TimeOut
;
1070 if (Data
== Value
) {
1075 if (SumTimeOut
>= mWaitForValueTimeOut
) {
1091 Show keyboard status lights according to
1092 indicators in ConsoleIn.
1094 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1096 @return status of updating keyboard register
1100 UpdateStatusLights (
1101 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1108 // Send keyboard command
1110 Status
= KeyboardWrite (ConsoleIn
, 0xed);
1111 if (EFI_ERROR (Status
)) {
1115 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1118 // Light configuration
1121 if (ConsoleIn
->CapsLock
) {
1125 if (ConsoleIn
->NumLock
) {
1129 if (ConsoleIn
->ScrollLock
) {
1133 Status
= KeyboardWrite (ConsoleIn
, Command
);
1135 if (EFI_ERROR (Status
)) {
1139 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1144 Initialize the key state.
1146 @param ConsoleIn The KEYBOARD_CONSOLE_IN_DEV instance.
1147 @param KeyState A pointer to receive the key state information.
1150 InitializeKeyState (
1151 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1152 OUT EFI_KEY_STATE
*KeyState
1155 KeyState
->KeyShiftState
= EFI_SHIFT_STATE_VALID
1156 | (ConsoleIn
->LeftCtrl
? EFI_LEFT_CONTROL_PRESSED
: 0)
1157 | (ConsoleIn
->RightCtrl
? EFI_RIGHT_CONTROL_PRESSED
: 0)
1158 | (ConsoleIn
->LeftAlt
? EFI_LEFT_ALT_PRESSED
: 0)
1159 | (ConsoleIn
->RightAlt
? EFI_RIGHT_ALT_PRESSED
: 0)
1160 | (ConsoleIn
->LeftShift
? EFI_LEFT_SHIFT_PRESSED
: 0)
1161 | (ConsoleIn
->RightShift
? EFI_RIGHT_SHIFT_PRESSED
: 0)
1162 | (ConsoleIn
->LeftLogo
? EFI_LEFT_LOGO_PRESSED
: 0)
1163 | (ConsoleIn
->RightLogo
? EFI_RIGHT_LOGO_PRESSED
: 0)
1164 | (ConsoleIn
->Menu
? EFI_MENU_KEY_PRESSED
: 0)
1165 | (ConsoleIn
->SysReq
? EFI_SYS_REQ_PRESSED
: 0)
1167 KeyState
->KeyToggleState
= EFI_TOGGLE_STATE_VALID
1168 | (ConsoleIn
->CapsLock
? EFI_CAPS_LOCK_ACTIVE
: 0)
1169 | (ConsoleIn
->NumLock
? EFI_NUM_LOCK_ACTIVE
: 0)
1170 | (ConsoleIn
->ScrollLock
? EFI_SCROLL_LOCK_ACTIVE
: 0)
1171 | (ConsoleIn
->IsSupportPartialKey
? EFI_KEY_STATE_EXPOSED
: 0)
1176 Get scancode from scancode buffer and translate into EFI-scancode and unicode defined by EFI spec.
1178 The function is always called in TPL_NOTIFY.
1180 @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer
1185 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1193 EFI_KEY_DATA KeyData
;
1195 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
1199 UINT8 ScancodeArr
[3];
1200 UINT32 ScancodeArrPos
;
1203 // Check if there are enough bytes of scancode representing a single key
1204 // available in the buffer
1210 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1211 if (EFI_ERROR (Status
)) {
1215 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED0
) {
1217 // E0 to look ahead 2 bytes
1221 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1222 if (EFI_ERROR (Status
)) {
1225 } else if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED1
) {
1227 // E1 to look ahead 3 bytes
1231 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1232 if (EFI_ERROR (Status
)) {
1237 // if we reach this position, scancodes for a key is in buffer now,pop them
1239 Status
= PopScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1240 ASSERT_EFI_ERROR (Status
);
1243 // store the last available byte, this byte of scancode will be checked
1245 ScanCode
= ScancodeArr
[ScancodeArrPos
];
1249 // Check for special keys and update the driver state.
1253 case SCANCODE_CTRL_MAKE
:
1255 ConsoleIn
->RightCtrl
= TRUE
;
1257 ConsoleIn
->LeftCtrl
= TRUE
;
1260 case SCANCODE_CTRL_BREAK
:
1262 ConsoleIn
->RightCtrl
= FALSE
;
1264 ConsoleIn
->LeftCtrl
= FALSE
;
1268 case SCANCODE_ALT_MAKE
:
1270 ConsoleIn
->RightAlt
= TRUE
;
1272 ConsoleIn
->LeftAlt
= TRUE
;
1275 case SCANCODE_ALT_BREAK
:
1277 ConsoleIn
->RightAlt
= FALSE
;
1279 ConsoleIn
->LeftAlt
= FALSE
;
1283 case SCANCODE_LEFT_SHIFT_MAKE
:
1285 // To avoid recognize PRNT_SCRN key as a L_SHIFT key
1286 // because PRNT_SCRN key generates E0 followed by L_SHIFT scan code.
1287 // If it the second byte of the PRNT_ScRN skip it.
1290 ConsoleIn
->LeftShift
= TRUE
;
1295 case SCANCODE_LEFT_SHIFT_BREAK
:
1297 ConsoleIn
->LeftShift
= FALSE
;
1301 case SCANCODE_RIGHT_SHIFT_MAKE
:
1302 ConsoleIn
->RightShift
= TRUE
;
1304 case SCANCODE_RIGHT_SHIFT_BREAK
:
1305 ConsoleIn
->RightShift
= FALSE
;
1308 case SCANCODE_LEFT_LOGO_MAKE
:
1309 ConsoleIn
->LeftLogo
= TRUE
;
1311 case SCANCODE_LEFT_LOGO_BREAK
:
1312 ConsoleIn
->LeftLogo
= FALSE
;
1315 case SCANCODE_RIGHT_LOGO_MAKE
:
1316 ConsoleIn
->RightLogo
= TRUE
;
1318 case SCANCODE_RIGHT_LOGO_BREAK
:
1319 ConsoleIn
->RightLogo
= FALSE
;
1322 case SCANCODE_MENU_MAKE
:
1323 ConsoleIn
->Menu
= TRUE
;
1325 case SCANCODE_MENU_BREAK
:
1326 ConsoleIn
->Menu
= FALSE
;
1329 case SCANCODE_SYS_REQ_MAKE
:
1331 ConsoleIn
->SysReq
= TRUE
;
1334 case SCANCODE_SYS_REQ_BREAK
:
1336 ConsoleIn
->SysReq
= FALSE
;
1340 case SCANCODE_SYS_REQ_MAKE_WITH_ALT
:
1341 ConsoleIn
->SysReq
= TRUE
;
1343 case SCANCODE_SYS_REQ_BREAK_WITH_ALT
:
1344 ConsoleIn
->SysReq
= FALSE
;
1347 case SCANCODE_CAPS_LOCK_MAKE
:
1348 ConsoleIn
->CapsLock
= (BOOLEAN
)!ConsoleIn
->CapsLock
;
1349 UpdateStatusLights (ConsoleIn
);
1351 case SCANCODE_NUM_LOCK_MAKE
:
1352 ConsoleIn
->NumLock
= (BOOLEAN
)!ConsoleIn
->NumLock
;
1353 UpdateStatusLights (ConsoleIn
);
1355 case SCANCODE_SCROLL_LOCK_MAKE
:
1357 ConsoleIn
->ScrollLock
= (BOOLEAN
)!ConsoleIn
->ScrollLock
;
1358 UpdateStatusLights (ConsoleIn
);
1365 // If this is above the valid range, ignore it
1367 if (ScanCode
>= SCANCODE_MAX_MAKE
) {
1375 // Handle Ctrl+Alt+Del hotkey
1377 if ((ConsoleIn
->LeftCtrl
|| ConsoleIn
->RightCtrl
) &&
1378 (ConsoleIn
->LeftAlt
|| ConsoleIn
->RightAlt
) &&
1379 ScanCode
== SCANCODE_DELETE_MAKE
1381 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1385 // Save the Shift/Toggle state
1387 InitializeKeyState (ConsoleIn
, &KeyData
.KeyState
);
1388 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1389 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1392 // Key Pad "/" shares the same scancode as that of "/" except Key Pad "/" has E0 prefix
1394 if (Extend0
&& ScanCode
== 0x35) {
1395 KeyData
.Key
.UnicodeChar
= L
'/';
1396 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1399 // PAUSE shares the same scancode as that of NUM except PAUSE has E1 prefix
1401 } else if (Extend1
&& ScanCode
== SCANCODE_NUM_LOCK_MAKE
) {
1402 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1403 KeyData
.Key
.ScanCode
= SCAN_PAUSE
;
1406 // PAUSE shares the same scancode as that of SCROLL except PAUSE (CTRL pressed) has E0 prefix
1408 } else if (Extend0
&& ScanCode
== SCANCODE_SCROLL_LOCK_MAKE
) {
1409 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1410 KeyData
.Key
.ScanCode
= SCAN_PAUSE
;
1413 // PRNT_SCRN shares the same scancode as that of Key Pad "*" except PRNT_SCRN has E0 prefix
1415 } else if (Extend0
&& ScanCode
== SCANCODE_SYS_REQ_MAKE
) {
1416 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1417 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1420 // Except the above special case, all others can be handled by convert table
1423 for (Index
= 0; ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
!= TABLE_END
; Index
++) {
1424 if (ScanCode
== ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
) {
1425 KeyData
.Key
.ScanCode
= ConvertKeyboardScanCodeToEfiKey
[Index
].EfiScanCode
;
1426 KeyData
.Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1428 if ((ConsoleIn
->LeftShift
|| ConsoleIn
->RightShift
) &&
1429 (ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
!= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
)) {
1430 KeyData
.Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1432 // Need not return associated shift state if a class of printable characters that
1433 // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
1435 KeyData
.KeyState
.KeyShiftState
&= ~(EFI_LEFT_SHIFT_PRESSED
| EFI_RIGHT_SHIFT_PRESSED
);
1438 // alphabetic key is affected by CapsLock State
1440 if (ConsoleIn
->CapsLock
) {
1441 if (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z') {
1442 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'a' + L
'A');
1443 } else if (KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') {
1444 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'A' + L
'a');
1453 // distinguish numeric key pad keys' 'up symbol' and 'down symbol'
1455 if (ScanCode
>= 0x47 && ScanCode
<= 0x53) {
1456 if (ConsoleIn
->NumLock
&& !(ConsoleIn
->LeftShift
|| ConsoleIn
->RightShift
) && !Extend0
) {
1457 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1458 } else if (ScanCode
!= 0x4a && ScanCode
!= 0x4e) {
1459 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1464 // If the key can not be converted then just return.
1466 if (KeyData
.Key
.ScanCode
== SCAN_NULL
&& KeyData
.Key
.UnicodeChar
== CHAR_NULL
) {
1467 if (!ConsoleIn
->IsSupportPartialKey
) {
1473 // Signal KeyNotify process event if this key pressed matches any key registered.
1475 for (Link
= GetFirstNode (&ConsoleIn
->NotifyList
); !IsNull (&ConsoleIn
->NotifyList
, Link
); Link
= GetNextNode (&ConsoleIn
->NotifyList
, Link
)) {
1476 CurrentNotify
= CR (
1478 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
1480 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1482 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
1484 // The key notification function needs to run at TPL_CALLBACK
1485 // while current TPL is TPL_NOTIFY. It will be invoked in
1486 // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.
1488 PushEfikeyBufTail (&ConsoleIn
->EfiKeyQueueForNotify
, &KeyData
);
1489 gBS
->SignalEvent (ConsoleIn
->KeyNotifyProcessEvent
);
1493 PushEfikeyBufTail (&ConsoleIn
->EfiKeyQueue
, &KeyData
);
1497 Perform 8042 controller and keyboard Initialization.
1498 If ExtendedVerification is TRUE, do additional test for
1499 the keyboard interface
1501 @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
1502 @param ExtendedVerification - indicates a thorough initialization
1504 @retval EFI_DEVICE_ERROR Fail to init keyboard
1505 @retval EFI_SUCCESS Success to init keyboard
1509 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1510 IN BOOLEAN ExtendedVerification
1516 EFI_PS2_POLICY_PROTOCOL
*Ps2Policy
;
1519 Status
= EFI_SUCCESS
;
1520 mEnableMouseInterface
= TRUE
;
1524 // Get Ps2 policy to set this
1526 gBS
->LocateProtocol (
1527 &gEfiPs2PolicyProtocolGuid
,
1529 (VOID
**) &Ps2Policy
1532 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1534 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
,
1535 ConsoleIn
->DevicePath
1539 // Perform a read to cleanup the Status Register's
1540 // output buffer full bits within MAX TRY times
1542 if ((KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
) != 0) {
1543 while (!EFI_ERROR (Status
) && TryTime
< KEYBOARD_MAX_TRY
) {
1544 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1548 // Exceed the max try times. The device may be error.
1550 if (TryTime
== KEYBOARD_MAX_TRY
) {
1551 Status
= EFI_DEVICE_ERROR
;
1556 // We should disable mouse interface during the initialization process
1557 // since mouse device output could block keyboard device output in the
1558 // 60H port of 8042 controller.
1560 // So if we are not initializing 8042 controller for the
1561 // first time, we have to remember the previous mouse interface
1564 // Test the system flag in to determine whether this is the first
1565 // time initialization
1567 if ((KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_SYSTEM_FLAG
) != 0) {
1568 if (!PcdGetBool (PcdFastPS2Detection
)) {
1570 // 8042 controller is already setup (by myself or by mouse driver):
1571 // See whether mouse interface is already enabled
1572 // which determines whether we should enable it later
1575 // Read the command byte of 8042 controller
1577 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_READ
);
1578 if (EFI_ERROR (Status
)) {
1579 KeyboardError (ConsoleIn
, L
"\n\r");
1583 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1584 if (EFI_ERROR (Status
)) {
1585 KeyboardError (ConsoleIn
, L
"\n\r");
1589 // Test the mouse enabling bit
1591 if ((CommandByte
& 0x20) != 0) {
1592 mEnableMouseInterface
= FALSE
;
1594 mEnableMouseInterface
= TRUE
;
1597 mEnableMouseInterface
= FALSE
;
1601 // 8042 controller is not setup yet:
1602 // 8042 controller selftest;
1603 // Don't enable mouse interface later.
1606 // Disable keyboard and mouse interfaces
1608 if (!PcdGetBool (PcdFastPS2Detection
)) {
1609 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1610 if (EFI_ERROR (Status
)) {
1611 KeyboardError (ConsoleIn
, L
"\n\r");
1615 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_MOUSE_INTERFACE
);
1616 if (EFI_ERROR (Status
)) {
1617 KeyboardError (ConsoleIn
, L
"\n\r");
1621 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1623 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
,
1624 ConsoleIn
->DevicePath
1627 // 8042 Controller Self Test
1629 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_CONTROLLER_SELF_TEST
);
1630 if (EFI_ERROR (Status
)) {
1631 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1635 Status
= KeyboardWaitForValue (ConsoleIn
, 0x55);
1636 if (EFI_ERROR (Status
)) {
1637 KeyboardError (ConsoleIn
, L
"8042 controller self test failed!\n\r");
1642 // Don't enable mouse interface later
1644 mEnableMouseInterface
= FALSE
;
1648 if (Ps2Policy
!= NULL
) {
1649 Ps2Policy
->Ps2InitHardware (ConsoleIn
->Handle
);
1652 // Write 8042 Command Byte, set System Flag
1653 // While at the same time:
1654 // 1. disable mouse interface,
1655 // 2. enable kbd interface,
1656 // 3. enable PC/XT kbd translation mode
1657 // 4. enable mouse and kbd interrupts
1659 // ( Command Byte bits:
1661 // 6: PC/XT translation mode
1662 // 5: Disable Auxiliary device interface
1663 // 4: Disable keyboard interface
1666 // 1: Enable Auxiliary device interrupt
1667 // 0: Enable Keyboard interrupt )
1669 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_WRITE
);
1670 if (EFI_ERROR (Status
)) {
1671 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1675 Status
= KeyboardWrite (ConsoleIn
, 0x67);
1676 if (EFI_ERROR (Status
)) {
1677 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1682 // Clear Memory Scancode Buffer
1684 ConsoleIn
->ScancodeQueue
.Head
= 0;
1685 ConsoleIn
->ScancodeQueue
.Tail
= 0;
1686 ConsoleIn
->EfiKeyQueue
.Head
= 0;
1687 ConsoleIn
->EfiKeyQueue
.Tail
= 0;
1688 ConsoleIn
->EfiKeyQueueForNotify
.Head
= 0;
1689 ConsoleIn
->EfiKeyQueueForNotify
.Tail
= 0;
1692 // Reset the status indicators
1694 ConsoleIn
->CapsLock
= FALSE
;
1695 ConsoleIn
->NumLock
= FALSE
;
1696 ConsoleIn
->ScrollLock
= FALSE
;
1697 ConsoleIn
->LeftCtrl
= FALSE
;
1698 ConsoleIn
->RightCtrl
= FALSE
;
1699 ConsoleIn
->LeftAlt
= FALSE
;
1700 ConsoleIn
->RightAlt
= FALSE
;
1701 ConsoleIn
->LeftShift
= FALSE
;
1702 ConsoleIn
->RightShift
= FALSE
;
1703 ConsoleIn
->LeftLogo
= FALSE
;
1704 ConsoleIn
->RightLogo
= FALSE
;
1705 ConsoleIn
->Menu
= FALSE
;
1706 ConsoleIn
->SysReq
= FALSE
;
1708 ConsoleIn
->IsSupportPartialKey
= FALSE
;
1710 // For resetting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1711 // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected
1712 // to system. So we only do the real resetting for keyboard when user asks and there is a real KB connected t system,
1713 // and normally during booting an OS, it's skipped.
1715 if (ExtendedVerification
&& CheckKeyboardConnect (ConsoleIn
)) {
1717 // Additional verifications for keyboard interface
1720 // Keyboard Interface Test
1722 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_KEYBOARD_INTERFACE_SELF_TEST
);
1723 if (EFI_ERROR (Status
)) {
1724 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1728 Status
= KeyboardWaitForValue (ConsoleIn
, 0x00);
1729 if (EFI_ERROR (Status
)) {
1732 L
"Some specific value not aquired from 8042 controller!\n\r"
1737 // Keyboard reset with a BAT(Basic Assurance Test)
1739 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_RESET
);
1740 if (EFI_ERROR (Status
)) {
1741 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1745 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1746 if (EFI_ERROR (Status
)) {
1747 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1751 // wait for BAT completion code
1753 mWaitForValueTimeOut
= KEYBOARD_BAT_TIMEOUT
;
1755 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_BAT_SUCCESS
);
1756 if (EFI_ERROR (Status
)) {
1757 KeyboardError (ConsoleIn
, L
"Keyboard self test failed!\n\r");
1761 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1764 // Set Keyboard to use Scan Code Set 2
1766 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_SELECT_SCAN_CODE_SET
);
1767 if (EFI_ERROR (Status
)) {
1768 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1772 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1773 if (EFI_ERROR (Status
)) {
1774 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1778 Status
= KeyboardWrite (ConsoleIn
, 0x02);
1779 if (EFI_ERROR (Status
)) {
1780 KeyboardError (ConsoleIn
, L
"8042 controller data write error!!\n\r");
1784 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1785 if (EFI_ERROR (Status
)) {
1786 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1791 // Clear Keyboard Scancode Buffer
1793 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_CLEAR_OUTPUT_DATA
);
1794 if (EFI_ERROR (Status
)) {
1795 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1799 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1800 if (EFI_ERROR (Status
)) {
1801 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1805 if (Ps2Policy
!= NULL
) {
1806 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_CAPSLOCK
) == EFI_KEYBOARD_CAPSLOCK
) {
1807 ConsoleIn
->CapsLock
= TRUE
;
1810 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_NUMLOCK
) == EFI_KEYBOARD_NUMLOCK
) {
1811 ConsoleIn
->NumLock
= TRUE
;
1814 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_SCROLLLOCK
) == EFI_KEYBOARD_SCROLLLOCK
) {
1815 ConsoleIn
->ScrollLock
= TRUE
;
1819 // Update Keyboard Lights
1821 Status
= UpdateStatusLights (ConsoleIn
);
1822 if (EFI_ERROR (Status
)) {
1823 KeyboardError (ConsoleIn
, L
"Update keyboard status lights error!\n\r");
1828 // At last, we can now enable the mouse interface if appropriate
1832 if (mEnableMouseInterface
) {
1834 // Enable mouse interface
1836 Status1
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_ENABLE_MOUSE_INTERFACE
);
1837 if (EFI_ERROR (Status1
)) {
1838 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1839 return EFI_DEVICE_ERROR
;
1843 if (!EFI_ERROR (Status
)) {
1846 return EFI_DEVICE_ERROR
;
1852 Disable the keyboard interface of the 8042 controller.
1854 @param ConsoleIn The device instance
1856 @return status of issuing disable command
1861 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1867 // Disable keyboard interface
1869 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1870 if (EFI_ERROR (Status
)) {
1871 KeyboardError (ConsoleIn
, L
"\n\r");
1872 return EFI_DEVICE_ERROR
;
1879 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
1880 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
1881 should not be in system.
1883 @param[in] ConsoleIn Keyboard Private Data Structure
1885 @retval TRUE Keyboard in System.
1886 @retval FALSE Keyboard not in System.
1890 CheckKeyboardConnect (
1891 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1895 UINTN WaitForValueTimeOutBcakup
;
1898 // enable keyboard itself and wait for its ack
1899 // If can't receive ack, Keyboard should not be connected.
1901 if (!PcdGetBool (PcdFastPS2Detection
)) {
1902 Status
= KeyboardWrite (
1907 if (EFI_ERROR (Status
)) {
1913 WaitForValueTimeOutBcakup
= mWaitForValueTimeOut
;
1914 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1915 Status
= KeyboardWaitForValue (
1917 KEYBOARD_CMDECHO_ACK
1919 mWaitForValueTimeOut
= WaitForValueTimeOutBcakup
;
1921 if (EFI_ERROR (Status
)) {