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
1158 EFI_KEY_DATA KeyData
;
1160 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
1164 UINT8 ScancodeArr
[4];
1165 UINT32 ScancodeArrPos
;
1167 // point to the current position in ScancodeArr
1174 // Check if there are enough bytes of scancode representing a single key
1175 // available in the buffer
1179 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, 1, ScancodeArr
);
1181 if (EFI_ERROR (Status
)) {
1185 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED
) {
1187 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, 2, ScancodeArr
);
1189 if (EFI_ERROR (Status
)) {
1194 // Checks for key scancode for PAUSE:E1-1D/45-E1/9D-C5
1195 // if present, ignore them
1197 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED1
) {
1199 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, 2, ScancodeArr
);
1202 if (EFI_ERROR (Status
)) {
1206 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, 3, ScancodeArr
);
1209 if (EFI_ERROR (Status
)) {
1213 PopScancodeBufHead (&ConsoleIn
->ScancodeQueue
, 3, ScancodeArr
);
1217 // if we reach this position, scancodes for a key is in buffer now,pop them
1219 Status
= PopScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1220 if (EFI_ERROR (Status
)) {
1224 // store the last available byte, this byte of scancode will be checked
1226 ScanCode
= ScancodeArr
[ScancodeArrPos
];
1229 // Check for special keys and update the driver state.
1233 case SCANCODE_CTRL_MAKE
:
1234 ConsoleIn
->Ctrl
= TRUE
;
1237 case SCANCODE_CTRL_BREAK
:
1238 ConsoleIn
->Ctrl
= FALSE
;
1241 case SCANCODE_ALT_MAKE
:
1242 ConsoleIn
->Alt
= TRUE
;
1245 case SCANCODE_ALT_BREAK
:
1246 ConsoleIn
->Alt
= FALSE
;
1249 case SCANCODE_LEFT_SHIFT_MAKE
:
1251 ConsoleIn
->Shift
= TRUE
;
1252 ConsoleIn
->LeftShift
= TRUE
;
1255 case SCANCODE_RIGHT_SHIFT_MAKE
:
1257 ConsoleIn
->Shift
= TRUE
;
1258 ConsoleIn
->RightShift
= TRUE
;
1262 case SCANCODE_LEFT_SHIFT_BREAK
:
1264 ConsoleIn
->Shift
= FALSE
;
1265 ConsoleIn
->LeftShift
= FALSE
;
1267 ConsoleIn
->SysReq
= FALSE
;
1270 case SCANCODE_RIGHT_SHIFT_BREAK
:
1272 ConsoleIn
->Shift
= FALSE
;
1273 ConsoleIn
->RightShift
= FALSE
;
1277 case SCANCODE_LEFT_LOGO_MAKE
:
1278 ConsoleIn
->LeftLogo
= TRUE
;
1280 case SCANCODE_LEFT_LOGO_BREAK
:
1281 ConsoleIn
->LeftLogo
= FALSE
;
1283 case SCANCODE_RIGHT_LOGO_MAKE
:
1284 ConsoleIn
->RightLogo
= TRUE
;
1286 case SCANCODE_RIGHT_LOGO_BREAK
:
1287 ConsoleIn
->RightLogo
= FALSE
;
1289 case SCANCODE_MENU_MAKE
:
1290 ConsoleIn
->Menu
= TRUE
;
1292 case SCANCODE_MENU_BREAK
:
1293 ConsoleIn
->Menu
= FALSE
;
1295 case SCANCODE_SYS_REQ_MAKE
:
1297 ConsoleIn
->SysReq
= TRUE
;
1299 case SCANCODE_CAPS_LOCK_MAKE
:
1300 ConsoleIn
->CapsLock
= (BOOLEAN
)!ConsoleIn
->CapsLock
;
1301 UpdateStatusLights (ConsoleIn
);
1304 case SCANCODE_NUM_LOCK_MAKE
:
1305 ConsoleIn
->NumLock
= (BOOLEAN
)!ConsoleIn
->NumLock
;
1306 UpdateStatusLights (ConsoleIn
);
1309 case SCANCODE_SCROLL_LOCK_MAKE
:
1310 ConsoleIn
->ScrollLock
= (BOOLEAN
)!ConsoleIn
->ScrollLock
;
1311 UpdateStatusLights (ConsoleIn
);
1315 // If this is a BREAK Key or above the valid range, ignore it
1317 if (ScanCode
>= SCANCODE_MAX_MAKE
) {
1325 // Handle Ctrl+Alt+Del hotkey
1327 if (ConsoleIn
->Alt
&& ConsoleIn
->Ctrl
&& ScanCode
== SCANCODE_DELETE_MAKE
) {
1328 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1331 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1332 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1333 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
;
1334 KeyData
.KeyState
.KeyToggleState
= EFI_TOGGLE_STATE_VALID
;
1337 // Treat Numeric Key Pad "/" specially
1339 if (Extended
&& ScanCode
== 0x35) {
1340 KeyData
.Key
.UnicodeChar
= L
'/';
1341 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1344 // Convert Keyboard ScanCode into an EFI Key
1346 for (Index
= 0; ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
!= TABLE_END
; Index
+= 1) {
1347 if (ScanCode
== ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
) {
1348 KeyData
.Key
.ScanCode
= ConvertKeyboardScanCodeToEfiKey
[Index
].EfiScanCode
;
1349 KeyData
.Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1351 if (ConsoleIn
->Shift
&&
1352 (ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
!= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
)) {
1353 KeyData
.Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1355 // Need not return associated shift state if a class of printable characters that
1356 // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
1358 ConsoleIn
->LeftShift
= FALSE
;
1359 ConsoleIn
->RightShift
= FALSE
;
1362 // alphabetic key is affected by CapsLock State
1364 if (ConsoleIn
->CapsLock
) {
1365 if (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z') {
1366 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'a' + L
'A');
1367 } else if (KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') {
1368 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'A' + L
'a');
1377 // distinguish numeric key pad keys' 'up symbol' and 'down symbol'
1379 if (ScanCode
>= 0x47 && ScanCode
<= 0x53) {
1380 if (ConsoleIn
->NumLock
&& !ConsoleIn
->Shift
&& !Extended
) {
1381 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1382 } else if (ScanCode
!= 0x4a && ScanCode
!= 0x4e) {
1383 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1387 // If the key can not be converted then just return.
1389 if (KeyData
.Key
.ScanCode
== SCAN_NULL
&& KeyData
.Key
.UnicodeChar
== CHAR_NULL
) {
1394 // Save the Shift/Toggle state
1396 if (ConsoleIn
->Ctrl
) {
1397 KeyData
.KeyState
.KeyShiftState
|= (Extended
) ? EFI_RIGHT_CONTROL_PRESSED
: EFI_LEFT_CONTROL_PRESSED
;
1399 if (ConsoleIn
->Alt
) {
1400 KeyData
.KeyState
.KeyShiftState
|= (Extended
) ? EFI_RIGHT_ALT_PRESSED
: EFI_LEFT_ALT_PRESSED
;
1402 if (ConsoleIn
->LeftShift
) {
1403 KeyData
.KeyState
.KeyShiftState
|= EFI_LEFT_SHIFT_PRESSED
;
1405 if (ConsoleIn
->RightShift
) {
1406 KeyData
.KeyState
.KeyShiftState
|= EFI_RIGHT_SHIFT_PRESSED
;
1408 if (ConsoleIn
->LeftLogo
) {
1409 KeyData
.KeyState
.KeyShiftState
|= EFI_LEFT_LOGO_PRESSED
;
1411 if (ConsoleIn
->RightLogo
) {
1412 KeyData
.KeyState
.KeyShiftState
|= EFI_RIGHT_LOGO_PRESSED
;
1414 if (ConsoleIn
->Menu
) {
1415 KeyData
.KeyState
.KeyShiftState
|= EFI_MENU_KEY_PRESSED
;
1417 if (ConsoleIn
->SysReq
) {
1418 KeyData
.KeyState
.KeyShiftState
|= EFI_SYS_REQ_PRESSED
;
1420 if (ConsoleIn
->CapsLock
) {
1421 KeyData
.KeyState
.KeyToggleState
|= EFI_CAPS_LOCK_ACTIVE
;
1423 if (ConsoleIn
->NumLock
) {
1424 KeyData
.KeyState
.KeyToggleState
|= EFI_NUM_LOCK_ACTIVE
;
1426 if (ConsoleIn
->ScrollLock
) {
1427 KeyData
.KeyState
.KeyToggleState
|= EFI_SCROLL_LOCK_ACTIVE
;
1431 // Invoke notification functions if exist
1433 for (Link
= GetFirstNode (&ConsoleIn
->NotifyList
); !IsNull (&ConsoleIn
->NotifyList
, Link
); Link
= GetNextNode (&ConsoleIn
->NotifyList
, Link
)) {
1434 CurrentNotify
= CR (
1436 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
1438 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1440 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
1441 CurrentNotify
->KeyNotificationFn (&KeyData
);
1446 // Translate the CTRL-Alpha characters to their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
1448 if (ConsoleIn
->Ctrl
) {
1449 if (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z') {
1450 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'a' + 1);
1451 } else if (KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') {
1452 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'A' + 1);
1456 PushEfikeyBufTail (&ConsoleIn
->EfiKeyQueue
, &KeyData
);
1460 Perform 8042 controller and keyboard Initialization.
1461 If ExtendedVerification is TRUE, do additional test for
1462 the keyboard interface
1464 @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
1465 @param ExtendedVerification - indicates a thorough initialization
1467 @retval EFI_DEVICE_ERROR Fail to init keyboard
1468 @retval EFI_SUCCESS Success to init keyboard
1472 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1473 IN BOOLEAN ExtendedVerification
1479 EFI_PS2_POLICY_PROTOCOL
*Ps2Policy
;
1482 Status
= EFI_SUCCESS
;
1483 mEnableMouseInterface
= TRUE
;
1487 // Get Ps2 policy to set this
1489 gBS
->LocateProtocol (
1490 &gEfiPs2PolicyProtocolGuid
,
1492 (VOID
**) &Ps2Policy
1495 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1497 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
,
1498 ConsoleIn
->DevicePath
1502 // Perform a read to cleanup the Status Register's
1503 // output buffer full bits within MAX TRY times
1505 while (!EFI_ERROR (Status
) && TryTime
< KEYBOARD_MAX_TRY
) {
1506 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1510 // Exceed the max try times. The device may be error.
1512 if (TryTime
== KEYBOARD_MAX_TRY
) {
1513 Status
= EFI_DEVICE_ERROR
;
1517 // We should disable mouse interface during the initialization process
1518 // since mouse device output could block keyboard device output in the
1519 // 60H port of 8042 controller.
1521 // So if we are not initializing 8042 controller for the
1522 // first time, we have to remember the previous mouse interface
1525 // Test the system flag in to determine whether this is the first
1526 // time initialization
1528 if ((KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_SYSTEM_FLAG
) != 0) {
1530 // 8042 controller is already setup (by myself or by mouse driver):
1531 // See whether mouse interface is already enabled
1532 // which determines whether we should enable it later
1535 // Read the command byte of 8042 controller
1537 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_READ
);
1538 if (EFI_ERROR (Status
)) {
1539 KeyboardError (ConsoleIn
, L
"\n\r");
1543 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1544 if (EFI_ERROR (Status
)) {
1545 KeyboardError (ConsoleIn
, L
"\n\r");
1549 // Test the mouse enabling bit
1551 if ((CommandByte
& 0x20) != 0) {
1552 mEnableMouseInterface
= FALSE
;
1554 mEnableMouseInterface
= TRUE
;
1559 // 8042 controller is not setup yet:
1560 // 8042 controller selftest;
1561 // Don't enable mouse interface later.
1564 // Disable keyboard and mouse interfaces
1566 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1567 if (EFI_ERROR (Status
)) {
1568 KeyboardError (ConsoleIn
, L
"\n\r");
1572 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_MOUSE_INTERFACE
);
1573 if (EFI_ERROR (Status
)) {
1574 KeyboardError (ConsoleIn
, L
"\n\r");
1578 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1580 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
,
1581 ConsoleIn
->DevicePath
1584 // 8042 Controller Self Test
1586 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_CONTROLLER_SELF_TEST
);
1587 if (EFI_ERROR (Status
)) {
1588 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1592 Status
= KeyboardWaitForValue (ConsoleIn
, 0x55);
1593 if (EFI_ERROR (Status
)) {
1594 KeyboardError (ConsoleIn
, L
"8042 controller self test failed!\n\r");
1598 // Don't enable mouse interface later
1600 mEnableMouseInterface
= FALSE
;
1604 if (Ps2Policy
!= NULL
) {
1605 Ps2Policy
->Ps2InitHardware (ConsoleIn
->Handle
);
1608 // Write 8042 Command Byte, set System Flag
1609 // While at the same time:
1610 // 1. disable mouse interface,
1611 // 2. enable kbd interface,
1612 // 3. enable PC/XT kbd translation mode
1613 // 4. enable mouse and kbd interrupts
1615 // ( Command Byte bits:
1617 // 6: PC/XT translation mode
1618 // 5: Disable Auxiliary device interface
1619 // 4: Disable keyboard interface
1622 // 1: Enable Auxiliary device interrupt
1623 // 0: Enable Keyboard interrupt )
1625 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_WRITE
);
1626 if (EFI_ERROR (Status
)) {
1627 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1631 Status
= KeyboardWrite (ConsoleIn
, 0x67);
1632 if (EFI_ERROR (Status
)) {
1633 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1638 // Clear Memory Scancode Buffer
1640 ConsoleIn
->ScancodeQueue
.Head
= 0;
1641 ConsoleIn
->ScancodeQueue
.Tail
= 0;
1642 ConsoleIn
->EfiKeyQueue
.Head
= 0;
1643 ConsoleIn
->EfiKeyQueue
.Tail
= 0;
1646 // Reset the status indicators
1648 ConsoleIn
->Ctrl
= FALSE
;
1649 ConsoleIn
->Alt
= FALSE
;
1650 ConsoleIn
->Shift
= FALSE
;
1651 ConsoleIn
->CapsLock
= FALSE
;
1652 ConsoleIn
->NumLock
= FALSE
;
1653 ConsoleIn
->ScrollLock
= FALSE
;
1654 ConsoleIn
->LeftShift
= FALSE
;
1655 ConsoleIn
->RightShift
= FALSE
;
1656 ConsoleIn
->LeftLogo
= FALSE
;
1657 ConsoleIn
->RightLogo
= FALSE
;
1658 ConsoleIn
->Menu
= FALSE
;
1659 ConsoleIn
->SysReq
= FALSE
;
1662 // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1663 // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected
1664 // to system. So we only do the real reseting for keyboard when user asks and there is a real KB connected t system,
1665 // and normally during booting an OS, it's skipped.
1667 if (ExtendedVerification
&& CheckKeyboardConnect (ConsoleIn
)) {
1669 // Additional verifications for keyboard interface
1672 // Keyboard Interface Test
1674 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_KEYBOARD_INTERFACE_SELF_TEST
);
1675 if (EFI_ERROR (Status
)) {
1676 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1680 Status
= KeyboardWaitForValue (ConsoleIn
, 0x00);
1681 if (EFI_ERROR (Status
)) {
1684 L
"Some specific value not aquired from 8042 controller!\n\r"
1689 // Keyboard reset with a BAT(Basic Assurance Test)
1691 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_RESET
);
1692 if (EFI_ERROR (Status
)) {
1693 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1697 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1698 if (EFI_ERROR (Status
)) {
1699 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1703 // wait for BAT completion code
1705 mWaitForValueTimeOut
= KEYBOARD_BAT_TIMEOUT
;
1707 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_BAT_SUCCESS
);
1708 if (EFI_ERROR (Status
)) {
1709 KeyboardError (ConsoleIn
, L
"Keyboard self test failed!\n\r");
1713 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1716 // Set Keyboard to use Scan Code Set 2
1718 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_SELECT_SCAN_CODE_SET
);
1719 if (EFI_ERROR (Status
)) {
1720 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1724 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1725 if (EFI_ERROR (Status
)) {
1726 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1730 Status
= KeyboardWrite (ConsoleIn
, 0x02);
1731 if (EFI_ERROR (Status
)) {
1732 KeyboardError (ConsoleIn
, L
"8042 controller data write error!!\n\r");
1736 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1737 if (EFI_ERROR (Status
)) {
1738 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1743 // Clear Keyboard Scancode Buffer
1745 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_CLEAR_OUTPUT_DATA
);
1746 if (EFI_ERROR (Status
)) {
1747 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1751 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1752 if (EFI_ERROR (Status
)) {
1753 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1757 if (Ps2Policy
!= NULL
) {
1758 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_CAPSLOCK
) == EFI_KEYBOARD_CAPSLOCK
) {
1759 ConsoleIn
->CapsLock
= TRUE
;
1762 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_NUMLOCK
) == EFI_KEYBOARD_NUMLOCK
) {
1763 ConsoleIn
->NumLock
= TRUE
;
1766 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_SCROLLLOCK
) == EFI_KEYBOARD_SCROLLLOCK
) {
1767 ConsoleIn
->ScrollLock
= TRUE
;
1771 // Update Keyboard Lights
1773 Status
= UpdateStatusLights (ConsoleIn
);
1774 if (EFI_ERROR (Status
)) {
1775 KeyboardError (ConsoleIn
, L
"Update keyboard status lights error!\n\r");
1780 // At last, we can now enable the mouse interface if appropriate
1784 if (mEnableMouseInterface
) {
1786 // Enable mouse interface
1788 Status1
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_ENABLE_MOUSE_INTERFACE
);
1789 if (EFI_ERROR (Status1
)) {
1790 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1791 return EFI_DEVICE_ERROR
;
1795 if (!EFI_ERROR (Status
)) {
1798 return EFI_DEVICE_ERROR
;
1804 Disable the keyboard interface of the 8042 controller.
1806 @param ConsoleIn The device instance
1808 @return status of issuing disable command
1813 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1819 // Disable keyboard interface
1821 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1822 if (EFI_ERROR (Status
)) {
1823 KeyboardError (ConsoleIn
, L
"\n\r");
1824 return EFI_DEVICE_ERROR
;
1831 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
1832 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
1833 should not be in system.
1835 @param[in] ConsoleIn Keyboard Private Data Structure
1837 @retval TRUE Keyboard in System.
1838 @retval FALSE Keyboard not in System.
1842 CheckKeyboardConnect (
1843 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1847 UINTN WaitForValueTimeOutBcakup
;
1849 Status
= EFI_SUCCESS
;
1851 // enable keyboard itself and wait for its ack
1852 // If can't receive ack, Keyboard should not be connected.
1854 Status
= KeyboardWrite (
1859 if (EFI_ERROR (Status
)) {
1865 WaitForValueTimeOutBcakup
= mWaitForValueTimeOut
;
1866 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1867 Status
= KeyboardWaitForValue (
1869 KEYBOARD_CMDECHO_ACK
1871 mWaitForValueTimeOut
= WaitForValueTimeOutBcakup
;
1873 if (EFI_ERROR (Status
)) {