2 Routines that access 8042 keyboard controller
4 Copyright (c) 2006 - 2011, 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
];
628 Push one byte to the scancode buffer.
630 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
631 @param Scancode The byte to push.
634 PushScancodeBufTail (
635 IN SCAN_CODE_QUEUE
*Queue
,
639 if (GetScancodeBufCount (Queue
) == KEYBOARD_SCAN_CODE_MAX_COUNT
- 1) {
643 Queue
->Buffer
[Queue
->Tail
] = Scancode
;
644 Queue
->Tail
= (Queue
->Tail
+ 1) % KEYBOARD_SCAN_CODE_MAX_COUNT
;
649 Read & remove several bytes from the scancode buffer.
650 This function is usually called after GetScancodeBufHead()
652 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
653 @param Count Number of bytes to be read
654 @param Buf Store the results
656 @retval EFI_SUCCESS success to scan the keyboard code
657 @retval EFI_NOT_READY invalid parameter
661 IN SCAN_CODE_QUEUE
*Queue
,
669 // Check the valid range of parameter 'Count'
671 if (GetScancodeBufCount (Queue
) < Count
) {
672 return EFI_NOT_READY
;
675 // Retrieve and remove the values
677 for (Index
= 0; Index
< Count
; Index
++, Queue
->Head
= (Queue
->Head
+ 1) % KEYBOARD_SCAN_CODE_MAX_COUNT
) {
678 Buf
[Index
] = Queue
->Buffer
[Queue
->Head
];
687 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
689 @return return the value
693 KeyReadDataRegister (
694 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
698 EFI_ISA_IO_PROTOCOL
*IsaIo
;
702 // Use IsaIo protocol to perform IO operations
704 IsaIo
= ConsoleIn
->IsaIo
;
709 ConsoleIn
->DataRegisterAddress
,
720 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
721 @param Data value wanted to be written
725 KeyWriteDataRegister (
726 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
730 ConsoleIn
->IsaIo
->Io
.Write (
733 ConsoleIn
->DataRegisterAddress
,
740 Read status register.
742 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
744 @return value in status register
748 KeyReadStatusRegister (
749 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
753 ConsoleIn
->IsaIo
->Io
.Read (
756 ConsoleIn
->StatusRegisterAddress
,
764 Write command register .
766 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
767 @param Data The value wanted to be written
771 KeyWriteCommandRegister (
772 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
776 ConsoleIn
->IsaIo
->Io
.Write (
779 ConsoleIn
->CommandRegisterAddress
,
786 Display error message.
788 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
789 @param ErrMsg Unicode string of error message
794 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
798 ConsoleIn
->KeyboardErr
= TRUE
;
802 Timer event handler: read a series of scancodes from 8042
803 and put them into memory scancode buffer.
804 it read as much scancodes to either fill
805 the memory buffer or empty the keyboard buffer.
806 It is registered as running under TPL_NOTIFY
808 @param Event The timer event
809 @param Context A KEYBOARD_CONSOLE_IN_DEV pointer
814 KeyboardTimerHandler (
822 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
824 ConsoleIn
= (KEYBOARD_CONSOLE_IN_DEV
*) Context
;
827 // Enter critical section
829 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
831 if (((KEYBOARD_CONSOLE_IN_DEV
*) Context
)->KeyboardErr
) {
833 // Leave critical section and return
835 gBS
->RestoreTPL (OldTpl
);
840 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
841 // KB is not connected to system. If KB is not connected to system, driver will find there's something
842 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
843 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
844 // Just skip the 'resend' process simply.
847 while ((KeyReadStatusRegister (ConsoleIn
) & (KEYBOARD_STATUS_REGISTER_TRANSMIT_TIMEOUT
|KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
)) ==
848 KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
851 // Read one byte of the scan code and store it into the memory buffer
853 Data
= KeyReadDataRegister (ConsoleIn
);
854 PushScancodeBufTail (&ConsoleIn
->ScancodeQueue
, Data
);
856 KeyGetchar (ConsoleIn
);
859 // Leave critical section and return
861 gBS
->RestoreTPL (OldTpl
);
867 @param ConsoleIn - Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
868 @param Data - Pointer to outof buffer for keeping key value
870 @retval EFI_TIMEOUT Status resigter time out
871 @retval EFI_SUCCESS Success to read keyboard
876 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
888 // wait till output buffer full then perform the read
890 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
891 if (KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
) {
893 *Data
= KeyReadDataRegister (ConsoleIn
);
897 MicroSecondDelay (30);
900 if (RegFilled
== 0) {
908 write key to keyboard
910 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
911 @param Data value wanted to be written
913 @retval EFI_TIMEOUT The input buffer register is full for putting new value util timeout
914 @retval EFI_SUCCESS The new value is sucess put into input buffer register.
919 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
930 // wait for input buffer empty
932 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
933 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
938 MicroSecondDelay (30);
941 if (RegEmptied
== 0) {
947 KeyWriteDataRegister (ConsoleIn
, Data
);
953 Issue keyboard command.
955 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
956 @param Data The buff holding the command
958 @retval EFI_TIMEOUT Keyboard is not ready to issuing
959 @retval EFI_SUCCESS Success to issue keyboard command
964 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
975 // Wait For Input Buffer Empty
977 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
978 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
983 MicroSecondDelay (30);
986 if (RegEmptied
== 0) {
992 KeyWriteCommandRegister (ConsoleIn
, Data
);
995 // Wait For Input Buffer Empty again
998 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
999 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
1004 MicroSecondDelay (30);
1007 if (RegEmptied
== 0) {
1015 wait for a specific value to be presented on
1016 8042 Data register by keyboard and then read it,
1017 used in keyboard commands ack
1019 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1020 @param Value the value wanted to be waited.
1022 @retval EFI_TIMEOUT Fail to get specific value in given time
1023 @retval EFI_SUCCESS Success to get specific value in given time.
1027 KeyboardWaitForValue (
1028 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1042 // Make sure the initial value of 'Data' is different from 'Value'
1045 if (Data
== Value
) {
1049 // Read from 8042 (multiple times if needed)
1050 // until the expected value appears
1051 // use SumTimeOut to control the iteration
1057 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1058 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1059 Data
= KeyReadDataRegister (ConsoleIn
);
1063 MicroSecondDelay (30);
1066 SumTimeOut
+= TimeOut
;
1068 if (Data
== Value
) {
1073 if (SumTimeOut
>= mWaitForValueTimeOut
) {
1089 Show keyboard status lights according to
1090 indicators in ConsoleIn.
1092 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1094 @return status of updating keyboard register
1098 UpdateStatusLights (
1099 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1106 // Send keyboard command
1108 Status
= KeyboardWrite (ConsoleIn
, 0xed);
1109 if (EFI_ERROR (Status
)) {
1113 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1116 // Light configuration
1119 if (ConsoleIn
->CapsLock
) {
1123 if (ConsoleIn
->NumLock
) {
1127 if (ConsoleIn
->ScrollLock
) {
1131 Status
= KeyboardWrite (ConsoleIn
, Command
);
1133 if (EFI_ERROR (Status
)) {
1137 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1142 Get scancode from scancode buffer and translate into EFI-scancode and unicode defined by EFI spec.
1144 The function is always called in TPL_NOTIFY.
1146 @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer
1151 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1159 EFI_KEY_DATA KeyData
;
1161 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
1165 UINT8 ScancodeArr
[3];
1166 UINT32 ScancodeArrPos
;
1169 // Check if there are enough bytes of scancode representing a single key
1170 // available in the buffer
1176 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1177 if (EFI_ERROR (Status
)) {
1181 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED0
) {
1183 // E0 to look ahead 2 bytes
1187 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1188 if (EFI_ERROR (Status
)) {
1191 } else if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED1
) {
1193 // E1 to look ahead 3 bytes
1197 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1198 if (EFI_ERROR (Status
)) {
1203 // if we reach this position, scancodes for a key is in buffer now,pop them
1205 Status
= PopScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1206 ASSERT_EFI_ERROR (Status
);
1209 // store the last available byte, this byte of scancode will be checked
1211 ScanCode
= ScancodeArr
[ScancodeArrPos
];
1215 // Check for special keys and update the driver state.
1219 case SCANCODE_CTRL_MAKE
:
1221 ConsoleIn
->RightCtrl
= TRUE
;
1223 ConsoleIn
->LeftCtrl
= TRUE
;
1226 case SCANCODE_CTRL_BREAK
:
1228 ConsoleIn
->RightCtrl
= FALSE
;
1230 ConsoleIn
->LeftCtrl
= FALSE
;
1234 case SCANCODE_ALT_MAKE
:
1236 ConsoleIn
->RightAlt
= TRUE
;
1238 ConsoleIn
->LeftAlt
= TRUE
;
1241 case SCANCODE_ALT_BREAK
:
1243 ConsoleIn
->RightAlt
= FALSE
;
1245 ConsoleIn
->LeftAlt
= FALSE
;
1249 case SCANCODE_LEFT_SHIFT_MAKE
:
1251 // To avoid recognize PRNT_SCRN key as a L_SHIFT key
1252 // because PRNT_SCRN key generates E0 followed by L_SHIFT scan code
1255 ConsoleIn
->LeftShift
= TRUE
;
1258 case SCANCODE_LEFT_SHIFT_BREAK
:
1260 ConsoleIn
->LeftShift
= FALSE
;
1264 case SCANCODE_RIGHT_SHIFT_MAKE
:
1265 ConsoleIn
->RightShift
= TRUE
;
1267 case SCANCODE_RIGHT_SHIFT_BREAK
:
1268 ConsoleIn
->RightShift
= FALSE
;
1271 case SCANCODE_LEFT_LOGO_MAKE
:
1272 ConsoleIn
->LeftLogo
= TRUE
;
1274 case SCANCODE_LEFT_LOGO_BREAK
:
1275 ConsoleIn
->LeftLogo
= FALSE
;
1278 case SCANCODE_RIGHT_LOGO_MAKE
:
1279 ConsoleIn
->RightLogo
= TRUE
;
1281 case SCANCODE_RIGHT_LOGO_BREAK
:
1282 ConsoleIn
->RightLogo
= FALSE
;
1285 case SCANCODE_MENU_MAKE
:
1286 ConsoleIn
->Menu
= TRUE
;
1288 case SCANCODE_MENU_BREAK
:
1289 ConsoleIn
->Menu
= FALSE
;
1292 case SCANCODE_SYS_REQ_MAKE
:
1294 ConsoleIn
->SysReq
= TRUE
;
1297 case SCANCODE_SYS_REQ_BREAK
:
1299 ConsoleIn
->SysReq
= FALSE
;
1303 case SCANCODE_SYS_REQ_MAKE_WITH_ALT
:
1304 ConsoleIn
->SysReq
= TRUE
;
1306 case SCANCODE_SYS_REQ_BREAK_WITH_ALT
:
1307 ConsoleIn
->SysReq
= FALSE
;
1310 case SCANCODE_CAPS_LOCK_MAKE
:
1311 ConsoleIn
->CapsLock
= (BOOLEAN
)!ConsoleIn
->CapsLock
;
1312 UpdateStatusLights (ConsoleIn
);
1314 case SCANCODE_NUM_LOCK_MAKE
:
1315 ConsoleIn
->NumLock
= (BOOLEAN
)!ConsoleIn
->NumLock
;
1316 UpdateStatusLights (ConsoleIn
);
1318 case SCANCODE_SCROLL_LOCK_MAKE
:
1320 ConsoleIn
->ScrollLock
= (BOOLEAN
)!ConsoleIn
->ScrollLock
;
1321 UpdateStatusLights (ConsoleIn
);
1328 // If this is above the valid range, ignore it
1330 if (ScanCode
>= SCANCODE_MAX_MAKE
) {
1338 // Handle Ctrl+Alt+Del hotkey
1340 if ((ConsoleIn
->LeftCtrl
|| ConsoleIn
->RightCtrl
) &&
1341 (ConsoleIn
->LeftAlt
|| ConsoleIn
->RightAlt
) &&
1342 ScanCode
== SCANCODE_DELETE_MAKE
1344 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1348 // Save the Shift/Toggle state
1350 KeyData
.KeyState
.KeyShiftState
= (UINT32
) (EFI_SHIFT_STATE_VALID
1351 | (ConsoleIn
->LeftCtrl
? EFI_LEFT_CONTROL_PRESSED
: 0)
1352 | (ConsoleIn
->RightCtrl
? EFI_RIGHT_CONTROL_PRESSED
: 0)
1353 | (ConsoleIn
->LeftAlt
? EFI_LEFT_ALT_PRESSED
: 0)
1354 | (ConsoleIn
->RightAlt
? EFI_RIGHT_ALT_PRESSED
: 0)
1355 | (ConsoleIn
->LeftShift
? EFI_LEFT_SHIFT_PRESSED
: 0)
1356 | (ConsoleIn
->RightShift
? EFI_RIGHT_SHIFT_PRESSED
: 0)
1357 | (ConsoleIn
->LeftLogo
? EFI_LEFT_LOGO_PRESSED
: 0)
1358 | (ConsoleIn
->RightLogo
? EFI_RIGHT_LOGO_PRESSED
: 0)
1359 | (ConsoleIn
->Menu
? EFI_MENU_KEY_PRESSED
: 0)
1360 | (ConsoleIn
->SysReq
? EFI_SYS_REQ_PRESSED
: 0)
1363 KeyData
.KeyState
.KeyToggleState
= (EFI_KEY_TOGGLE_STATE
) (EFI_TOGGLE_STATE_VALID
1364 | (ConsoleIn
->CapsLock
? EFI_CAPS_LOCK_ACTIVE
: 0)
1365 | (ConsoleIn
->NumLock
? EFI_NUM_LOCK_ACTIVE
: 0)
1366 | (ConsoleIn
->ScrollLock
? EFI_SCROLL_LOCK_ACTIVE
: 0)
1369 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1370 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1373 // Key Pad "/" shares the same scancode as that of "/" except Key Pad "/" has E0 prefix
1375 if (Extend0
&& ScanCode
== 0x35) {
1376 KeyData
.Key
.UnicodeChar
= L
'/';
1377 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1380 // PAUSE shares the same scancode as that of NUM except PAUSE has E1 prefix
1382 } else if (Extend1
&& ScanCode
== SCANCODE_NUM_LOCK_MAKE
) {
1383 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1384 KeyData
.Key
.ScanCode
= SCAN_PAUSE
;
1387 // PAUSE shares the same scancode as that of SCROLL except PAUSE (CTRL pressed) has E0 prefix
1389 } else if (Extend0
&& ScanCode
== SCANCODE_SCROLL_LOCK_MAKE
) {
1390 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1391 KeyData
.Key
.ScanCode
= SCAN_PAUSE
;
1394 // PRNT_SCRN shares the same scancode as that of Key Pad "*" except PRNT_SCRN has E0 prefix
1396 } else if (Extend0
&& ScanCode
== SCANCODE_SYS_REQ_MAKE
) {
1397 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1398 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1401 // Except the above special case, all others can be handled by convert table
1404 for (Index
= 0; ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
!= TABLE_END
; Index
++) {
1405 if (ScanCode
== ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
) {
1406 KeyData
.Key
.ScanCode
= ConvertKeyboardScanCodeToEfiKey
[Index
].EfiScanCode
;
1407 KeyData
.Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1409 if ((ConsoleIn
->LeftShift
|| ConsoleIn
->RightShift
) &&
1410 (ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
!= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
)) {
1411 KeyData
.Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1413 // Need not return associated shift state if a class of printable characters that
1414 // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
1416 KeyData
.KeyState
.KeyShiftState
&= ~(EFI_LEFT_SHIFT_PRESSED
| EFI_RIGHT_SHIFT_PRESSED
);
1419 // alphabetic key is affected by CapsLock State
1421 if (ConsoleIn
->CapsLock
) {
1422 if (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z') {
1423 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'a' + L
'A');
1424 } else if (KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') {
1425 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'A' + L
'a');
1434 // distinguish numeric key pad keys' 'up symbol' and 'down symbol'
1436 if (ScanCode
>= 0x47 && ScanCode
<= 0x53) {
1437 if (ConsoleIn
->NumLock
&& !(ConsoleIn
->LeftShift
|| ConsoleIn
->RightShift
) && !Extend0
) {
1438 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1439 } else if (ScanCode
!= 0x4a && ScanCode
!= 0x4e) {
1440 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1444 // If the key can not be converted then just return.
1446 if (KeyData
.Key
.ScanCode
== SCAN_NULL
&& KeyData
.Key
.UnicodeChar
== CHAR_NULL
) {
1451 // Invoke notification functions if exist
1453 for (Link
= GetFirstNode (&ConsoleIn
->NotifyList
); !IsNull (&ConsoleIn
->NotifyList
, Link
); Link
= GetNextNode (&ConsoleIn
->NotifyList
, Link
)) {
1454 CurrentNotify
= CR (
1456 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
1458 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1460 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
1461 CurrentNotify
->KeyNotificationFn (&KeyData
);
1466 // Translate the CTRL-Alpha characters to their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
1468 if (ConsoleIn
->LeftCtrl
|| ConsoleIn
->RightCtrl
) {
1469 if (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z') {
1470 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'a' + 1);
1471 } else if (KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') {
1472 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'A' + 1);
1476 PushEfikeyBufTail (&ConsoleIn
->EfiKeyQueue
, &KeyData
);
1480 Perform 8042 controller and keyboard Initialization.
1481 If ExtendedVerification is TRUE, do additional test for
1482 the keyboard interface
1484 @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
1485 @param ExtendedVerification - indicates a thorough initialization
1487 @retval EFI_DEVICE_ERROR Fail to init keyboard
1488 @retval EFI_SUCCESS Success to init keyboard
1492 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1493 IN BOOLEAN ExtendedVerification
1499 EFI_PS2_POLICY_PROTOCOL
*Ps2Policy
;
1502 Status
= EFI_SUCCESS
;
1503 mEnableMouseInterface
= TRUE
;
1507 // Get Ps2 policy to set this
1509 gBS
->LocateProtocol (
1510 &gEfiPs2PolicyProtocolGuid
,
1512 (VOID
**) &Ps2Policy
1515 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1517 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
,
1518 ConsoleIn
->DevicePath
1522 // Perform a read to cleanup the Status Register's
1523 // output buffer full bits within MAX TRY times
1525 while (!EFI_ERROR (Status
) && TryTime
< KEYBOARD_MAX_TRY
) {
1526 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1530 // Exceed the max try times. The device may be error.
1532 if (TryTime
== KEYBOARD_MAX_TRY
) {
1533 Status
= EFI_DEVICE_ERROR
;
1537 // We should disable mouse interface during the initialization process
1538 // since mouse device output could block keyboard device output in the
1539 // 60H port of 8042 controller.
1541 // So if we are not initializing 8042 controller for the
1542 // first time, we have to remember the previous mouse interface
1545 // Test the system flag in to determine whether this is the first
1546 // time initialization
1548 if ((KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_SYSTEM_FLAG
) != 0) {
1550 // 8042 controller is already setup (by myself or by mouse driver):
1551 // See whether mouse interface is already enabled
1552 // which determines whether we should enable it later
1555 // Read the command byte of 8042 controller
1557 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_READ
);
1558 if (EFI_ERROR (Status
)) {
1559 KeyboardError (ConsoleIn
, L
"\n\r");
1563 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1564 if (EFI_ERROR (Status
)) {
1565 KeyboardError (ConsoleIn
, L
"\n\r");
1569 // Test the mouse enabling bit
1571 if ((CommandByte
& 0x20) != 0) {
1572 mEnableMouseInterface
= FALSE
;
1574 mEnableMouseInterface
= TRUE
;
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 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1587 if (EFI_ERROR (Status
)) {
1588 KeyboardError (ConsoleIn
, L
"\n\r");
1592 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_MOUSE_INTERFACE
);
1593 if (EFI_ERROR (Status
)) {
1594 KeyboardError (ConsoleIn
, L
"\n\r");
1598 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1600 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
,
1601 ConsoleIn
->DevicePath
1604 // 8042 Controller Self Test
1606 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_CONTROLLER_SELF_TEST
);
1607 if (EFI_ERROR (Status
)) {
1608 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1612 Status
= KeyboardWaitForValue (ConsoleIn
, 0x55);
1613 if (EFI_ERROR (Status
)) {
1614 KeyboardError (ConsoleIn
, L
"8042 controller self test failed!\n\r");
1618 // Don't enable mouse interface later
1620 mEnableMouseInterface
= FALSE
;
1624 if (Ps2Policy
!= NULL
) {
1625 Ps2Policy
->Ps2InitHardware (ConsoleIn
->Handle
);
1628 // Write 8042 Command Byte, set System Flag
1629 // While at the same time:
1630 // 1. disable mouse interface,
1631 // 2. enable kbd interface,
1632 // 3. enable PC/XT kbd translation mode
1633 // 4. enable mouse and kbd interrupts
1635 // ( Command Byte bits:
1637 // 6: PC/XT translation mode
1638 // 5: Disable Auxiliary device interface
1639 // 4: Disable keyboard interface
1642 // 1: Enable Auxiliary device interrupt
1643 // 0: Enable Keyboard interrupt )
1645 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_WRITE
);
1646 if (EFI_ERROR (Status
)) {
1647 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1651 Status
= KeyboardWrite (ConsoleIn
, 0x67);
1652 if (EFI_ERROR (Status
)) {
1653 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1658 // Clear Memory Scancode Buffer
1660 ConsoleIn
->ScancodeQueue
.Head
= 0;
1661 ConsoleIn
->ScancodeQueue
.Tail
= 0;
1662 ConsoleIn
->EfiKeyQueue
.Head
= 0;
1663 ConsoleIn
->EfiKeyQueue
.Tail
= 0;
1666 // Reset the status indicators
1668 ConsoleIn
->CapsLock
= FALSE
;
1669 ConsoleIn
->NumLock
= FALSE
;
1670 ConsoleIn
->ScrollLock
= FALSE
;
1671 ConsoleIn
->LeftCtrl
= FALSE
;
1672 ConsoleIn
->RightCtrl
= FALSE
;
1673 ConsoleIn
->LeftAlt
= FALSE
;
1674 ConsoleIn
->RightAlt
= FALSE
;
1675 ConsoleIn
->LeftShift
= FALSE
;
1676 ConsoleIn
->RightShift
= FALSE
;
1677 ConsoleIn
->LeftLogo
= FALSE
;
1678 ConsoleIn
->RightLogo
= FALSE
;
1679 ConsoleIn
->Menu
= FALSE
;
1680 ConsoleIn
->SysReq
= FALSE
;
1683 // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1684 // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected
1685 // to system. So we only do the real reseting for keyboard when user asks and there is a real KB connected t system,
1686 // and normally during booting an OS, it's skipped.
1688 if (ExtendedVerification
&& CheckKeyboardConnect (ConsoleIn
)) {
1690 // Additional verifications for keyboard interface
1693 // Keyboard Interface Test
1695 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_KEYBOARD_INTERFACE_SELF_TEST
);
1696 if (EFI_ERROR (Status
)) {
1697 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1701 Status
= KeyboardWaitForValue (ConsoleIn
, 0x00);
1702 if (EFI_ERROR (Status
)) {
1705 L
"Some specific value not aquired from 8042 controller!\n\r"
1710 // Keyboard reset with a BAT(Basic Assurance Test)
1712 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_RESET
);
1713 if (EFI_ERROR (Status
)) {
1714 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1718 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1719 if (EFI_ERROR (Status
)) {
1720 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1724 // wait for BAT completion code
1726 mWaitForValueTimeOut
= KEYBOARD_BAT_TIMEOUT
;
1728 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_BAT_SUCCESS
);
1729 if (EFI_ERROR (Status
)) {
1730 KeyboardError (ConsoleIn
, L
"Keyboard self test failed!\n\r");
1734 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1737 // Set Keyboard to use Scan Code Set 2
1739 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_SELECT_SCAN_CODE_SET
);
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 Status
= KeyboardWrite (ConsoleIn
, 0x02);
1752 if (EFI_ERROR (Status
)) {
1753 KeyboardError (ConsoleIn
, L
"8042 controller data write error!!\n\r");
1757 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1758 if (EFI_ERROR (Status
)) {
1759 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1764 // Clear Keyboard Scancode Buffer
1766 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_CLEAR_OUTPUT_DATA
);
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 if (Ps2Policy
!= NULL
) {
1779 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_CAPSLOCK
) == EFI_KEYBOARD_CAPSLOCK
) {
1780 ConsoleIn
->CapsLock
= TRUE
;
1783 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_NUMLOCK
) == EFI_KEYBOARD_NUMLOCK
) {
1784 ConsoleIn
->NumLock
= TRUE
;
1787 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_SCROLLLOCK
) == EFI_KEYBOARD_SCROLLLOCK
) {
1788 ConsoleIn
->ScrollLock
= TRUE
;
1792 // Update Keyboard Lights
1794 Status
= UpdateStatusLights (ConsoleIn
);
1795 if (EFI_ERROR (Status
)) {
1796 KeyboardError (ConsoleIn
, L
"Update keyboard status lights error!\n\r");
1801 // At last, we can now enable the mouse interface if appropriate
1805 if (mEnableMouseInterface
) {
1807 // Enable mouse interface
1809 Status1
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_ENABLE_MOUSE_INTERFACE
);
1810 if (EFI_ERROR (Status1
)) {
1811 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1812 return EFI_DEVICE_ERROR
;
1816 if (!EFI_ERROR (Status
)) {
1819 return EFI_DEVICE_ERROR
;
1825 Disable the keyboard interface of the 8042 controller.
1827 @param ConsoleIn The device instance
1829 @return status of issuing disable command
1834 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1840 // Disable keyboard interface
1842 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1843 if (EFI_ERROR (Status
)) {
1844 KeyboardError (ConsoleIn
, L
"\n\r");
1845 return EFI_DEVICE_ERROR
;
1852 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
1853 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
1854 should not be in system.
1856 @param[in] ConsoleIn Keyboard Private Data Structure
1858 @retval TRUE Keyboard in System.
1859 @retval FALSE Keyboard not in System.
1863 CheckKeyboardConnect (
1864 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1868 UINTN WaitForValueTimeOutBcakup
;
1870 Status
= EFI_SUCCESS
;
1872 // enable keyboard itself and wait for its ack
1873 // If can't receive ack, Keyboard should not be connected.
1875 Status
= KeyboardWrite (
1880 if (EFI_ERROR (Status
)) {
1886 WaitForValueTimeOutBcakup
= mWaitForValueTimeOut
;
1887 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1888 Status
= KeyboardWaitForValue (
1890 KEYBOARD_CMDECHO_ACK
1892 mWaitForValueTimeOut
= WaitForValueTimeOutBcakup
;
1894 if (EFI_ERROR (Status
)) {