3 Routines that access 8042 keyboard controller
5 Copyright (c) 2006 - 2007, Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "Ps2Keyboard.h"
22 CHAR16 ShiftUnicodeChar
;
24 ConvertKeyboardScanCodeToEfiKey
[] = {
351 0x37, // Numeric Keypad *
357 0x38, //Left Alt/Extended Right Alt
477 0x4c, // Numeric Keypad 5
564 // The WaitForValue time out
566 UINTN mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
568 BOOLEAN mEnableMouseInterface
;
571 // Function declarations
574 KeyReadDataRegister (
575 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
579 KeyWriteDataRegister (
580 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
585 KeyWriteCommandRegister (
586 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
592 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
593 IN CHAR16
*ErrMsg
// should be a unicode string
598 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
605 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
612 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
618 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
623 KeyboardWaitForValue (
624 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
631 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
633 @return return the value
637 KeyReadDataRegister (
638 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
642 EFI_ISA_IO_PROTOCOL
*IsaIo
;
646 // Use IsaIo protocol to perform IO operations
648 IsaIo
= ConsoleIn
->IsaIo
;
653 ConsoleIn
->DataRegisterAddress
,
664 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
665 @param Data value wanted to be written
669 KeyWriteDataRegister (
670 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
675 EFI_ISA_IO_PROTOCOL
*IsaIo
;
678 // Use IsaIo protocol to perform IO operations
680 IsaIo
= ConsoleIn
->IsaIo
;
685 ConsoleIn
->DataRegisterAddress
,
691 // outp(ConsoleIn->DataRegisterAddress, Data);
698 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
700 @return value in status register
704 KeyReadStatusRegister (
705 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
708 EFI_ISA_IO_PROTOCOL
*IsaIo
;
712 // Use IsaIo protocol to perform IO operations
714 IsaIo
= ConsoleIn
->IsaIo
;
719 ConsoleIn
->StatusRegisterAddress
,
729 Write command register
731 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
732 @param Data The value wanted to be written
737 KeyWriteCommandRegister (
738 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
742 EFI_ISA_IO_PROTOCOL
*IsaIo
;
745 // Use IsaIo protocol to perform IO operations
747 IsaIo
= ConsoleIn
->IsaIo
;
752 ConsoleIn
->CommandRegisterAddress
,
760 Display error message
762 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
763 @param ErrMsg Unicode string of error message
768 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
772 ConsoleIn
->KeyboardErr
= TRUE
;
775 // gST -> ConOut -> OutputString (gST -> ConOut, L"Keyboard Driver: ");
776 // gST -> ConOut -> OutputString (gST -> ConOut, ErrMsg);
781 Timer event handler: read a series of scancodes from 8042
782 and put them into memory scancode buffer.
783 it read as much scancodes to either fill
784 the memory buffer or empty the keyboard buffer.
785 It is registered as running under TPL_NOTIFY
787 @param Event - The timer event
788 @param Context - A KEYBOARD_CONSOLE_IN_DEV pointer
793 KeyboardTimerHandler (
801 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
806 // Enter critical section
808 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
810 if (((KEYBOARD_CONSOLE_IN_DEV
*) Context
)->KeyboardErr
) {
812 // Leave critical section and return
814 gBS
->RestoreTPL (OldTpl
);
818 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
819 // KB is not connected to system. If KB is not connected to system, driver will find there's something
820 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
821 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
822 // Just skip the 'resend' process simply.
828 // if there is no key present, just return
830 if ((KeyReadStatusRegister (Context
) & 0x21) != 0x1) {
832 // Leave critical section and return
834 gBS
->RestoreTPL (OldTpl
);
839 // Read one byte of the scan code and store it into the memory buffer
841 if (ConsoleIn
->ScancodeBufCount
< KEYBOARD_BUFFER_MAX_COUNT
) {
843 Data
= KeyReadDataRegister (Context
);
845 // put the scancode into the memory scancode buffer
847 ConsoleIn
->ScancodeBufCount
++;
848 ConsoleIn
->ScancodeBufEndPos
++;
849 if (ConsoleIn
->ScancodeBufEndPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
850 ConsoleIn
->ScancodeBufEndPos
= 0;
853 ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufEndPos
] = Data
;
856 // Handle Alt+Ctrl+Del Key combination
859 case SCANCODE_CTRL_MAKE
:
860 ConsoleIn
->Ctrled
= TRUE
;
863 case SCANCODE_CTRL_BREAK
:
864 ConsoleIn
->Ctrled
= FALSE
;
867 case SCANCODE_ALT_MAKE
:
868 ConsoleIn
->Alted
= TRUE
;
871 case SCANCODE_ALT_BREAK
:
872 ConsoleIn
->Alted
= FALSE
;
876 // if Alt+Ctrl+Del, Reboot the System
878 if (ConsoleIn
->Ctrled
&& ConsoleIn
->Alted
&& Data
== 0x53) {
879 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
883 // Leave critical section and return
885 gBS
->RestoreTPL (OldTpl
);
891 Read several bytes from the scancode buffer without removing them.
892 This function is called to see if there are enough bytes of scancode
893 representing a single key.
895 @param Count - Number of bytes to be read
896 @param Buf - Store the results
898 @retval EFI_SUCCESS success to scan the keyboard code
899 @retval EFI_NOT_READY invalid parameter
903 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
915 // check the valid range of parameter 'Count'
917 if (Count
<= 0 || ConsoleIn
->ScancodeBufCount
< Count
) {
918 return EFI_NOT_READY
;
921 // retrieve the values
923 for (Index
= 0; Index
< Count
; Index
++) {
927 Pos
= ConsoleIn
->ScancodeBufStartPos
;
931 if (Pos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
936 Buf
[Index
] = ConsoleIn
->ScancodeBuf
[Pos
];
944 Read & remove several bytes from the scancode buffer.
945 This function is usually called after GetScancodeBufHead()
947 @param Count - Number of bytes to be read
948 @param Buf - Store the results
950 @retval EFI_SUCCESS success to scan the keyboard code
951 @retval EFI_NOT_READY invalid parameter
955 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
965 // Check the valid range of parameter 'Count'
967 if (Count
<= 0 || ConsoleIn
->ScancodeBufCount
< Count
) {
968 return EFI_NOT_READY
;
971 // Retrieve and remove the values
973 for (Index
= 0; Index
< Count
; Index
++) {
977 ConsoleIn
->ScancodeBufStartPos
++;
978 if (ConsoleIn
->ScancodeBufStartPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
979 ConsoleIn
->ScancodeBufStartPos
= 0;
983 Buf
[Index
] = ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufStartPos
];
984 ConsoleIn
->ScancodeBufCount
--;
987 ConsoleIn
->ScancodeBufStartPos
++;
988 if (ConsoleIn
->ScancodeBufStartPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
989 ConsoleIn
->ScancodeBufStartPos
= 0;
998 @param ConsoleIn - Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
999 @param Data - Pointer to outof buffer for keeping key value
1001 @retval EFI_TIMEOUT Status resigter time out
1002 @retval EFI_SUCCESS Success to read keyboard
1007 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1019 // wait till output buffer full then perform the read
1021 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1022 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1024 *Data
= KeyReadDataRegister (ConsoleIn
);
1039 write key to keyboard
1041 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1042 @param Data value wanted to be written
1044 @retval EFI_TIMEOUT - GC_TODO: Add description for return value
1045 @retval EFI_SUCCESS - GC_TODO: Add description for return value
1050 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1061 // wait for input buffer empty
1063 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1064 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x02)) {
1078 KeyWriteDataRegister (ConsoleIn
, Data
);
1084 Issue keyboard command
1086 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1087 @param Data The buff holding the command
1089 @retval EFI_TIMEOUT Keyboard is not ready to issuing
1090 @retval EFI_SUCCESS Success to issue keyboard command
1095 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1106 // Wait For Input Buffer Empty
1108 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1109 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x02)) {
1121 // issue the command
1123 KeyWriteCommandRegister (ConsoleIn
, Data
);
1126 // Wait For Input Buffer Empty again
1129 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1130 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x02)) {
1146 wait for a specific value to be presented on
1147 8042 Data register by keyboard and then read it,
1148 used in keyboard commands ack
1150 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1151 @param Value the value wanted to be waited.
1153 @retval EFI_TIMEOUT Fail to get specific value in given time
1154 @retval EFI_SUCCESS Success to get specific value in given time.
1158 KeyboardWaitForValue (
1159 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1173 // Make sure the initial value of 'Data' is different from 'Value'
1176 if (Data
== Value
) {
1180 // Read from 8042 (multiple times if needed)
1181 // until the expected value appears
1182 // use SumTimeOut to control the iteration
1188 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1189 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1190 Data
= KeyReadDataRegister (ConsoleIn
);
1197 SumTimeOut
+= TimeOut
;
1199 if (Data
== Value
) {
1204 if (SumTimeOut
>= mWaitForValueTimeOut
) {
1220 Show keyboard status lights according to
1221 indicators in ConsoleIn.
1223 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1229 UpdateStatusLights (
1230 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1237 // Send keyboard command
1239 Status
= KeyboardWrite (ConsoleIn
, 0xed);
1240 if (EFI_ERROR (Status
)) {
1244 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1247 // Light configuration
1250 if (ConsoleIn
->CapsLock
) {
1254 if (ConsoleIn
->NumLock
) {
1258 if (ConsoleIn
->ScrollLock
) {
1262 Status
= KeyboardWrite (ConsoleIn
, Command
);
1264 if (EFI_ERROR (Status
)) {
1268 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1273 Get scancode from scancode buffer
1274 and translate into EFI-scancode and unicode defined by EFI spec
1275 The function is always called in TPL_NOTIFY
1277 @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer
1279 @retval EFI_NOT_READY - Input from console not ready yet.
1280 @retval EFI_SUCCESS - Function executed successfully.
1285 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1292 UINT8 ScancodeArr
[4];
1297 UINT32 ScancodeArrPos
;
1299 // point to the current position in ScancodeArr
1307 // Read one byte of the scan code and store it into the memory buffer
1308 // This block of code is added to insert an action that is equivalent to
1309 // the timer event handling function, so as to increase the frequency of
1310 // detecting the availability of keys. Timer event has a max frequency of
1311 // 18Hz which is insufficient
1314 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
1315 // KB is not connected to system. If KB is not connected to system, driver will find there's something
1316 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
1317 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
1318 // Just skip the 'resend' process simply.
1322 if (((KeyReadStatusRegister (ConsoleIn
) & 0x21) == 0x1) && (ConsoleIn
->ScancodeBufCount
< KEYBOARD_BUFFER_MAX_COUNT
)) {
1324 Readed
= KeyReadDataRegister (ConsoleIn
);
1326 // put the scancode into the memory scancode buffer
1328 ConsoleIn
->ScancodeBufCount
++;
1329 ConsoleIn
->ScancodeBufEndPos
++;
1330 if (ConsoleIn
->ScancodeBufEndPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
1331 ConsoleIn
->ScancodeBufEndPos
= 0;
1334 ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufEndPos
] = Readed
;
1337 // Handle Alt+Ctrl+Del Key combination
1341 case SCANCODE_CTRL_MAKE
:
1342 ConsoleIn
->Ctrled
= TRUE
;
1345 case SCANCODE_CTRL_BREAK
:
1346 ConsoleIn
->Ctrled
= FALSE
;
1349 case SCANCODE_ALT_MAKE
:
1350 ConsoleIn
->Alted
= TRUE
;
1353 case SCANCODE_ALT_BREAK
:
1354 ConsoleIn
->Alted
= FALSE
;
1358 // if Alt+Ctrl+Del, Reboot the System
1360 if (ConsoleIn
->Ctrled
&& ConsoleIn
->Alted
&& Readed
== 0x53) {
1361 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1365 // Check if there are enough bytes of scancode representing a single key
1366 // available in the buffer
1370 Status
= GetScancodeBufHead (ConsoleIn
, 1, ScancodeArr
);
1372 if (EFI_ERROR (Status
)) {
1373 return EFI_NOT_READY
;
1376 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED
) {
1378 Status
= GetScancodeBufHead (ConsoleIn
, 2, ScancodeArr
);
1380 if (EFI_ERROR (Status
)) {
1381 return EFI_NOT_READY
;
1385 // Checks for key scancode for PAUSE:E1-1D/45-E1/9D-C5
1386 // if present, ignore them
1388 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED1
) {
1390 Status
= GetScancodeBufHead (ConsoleIn
, 2, ScancodeArr
);
1393 if (EFI_ERROR (Status
)) {
1394 return EFI_NOT_READY
;
1397 Status
= GetScancodeBufHead (ConsoleIn
, 3, ScancodeArr
);
1400 if (EFI_ERROR (Status
)) {
1401 return EFI_NOT_READY
;
1404 PopScancodeBufHead (ConsoleIn
, 3, ScancodeArr
);
1405 return EFI_NOT_READY
;
1408 // if we reach this position, scancodes for a key is in buffer now,pop them
1410 Status
= PopScancodeBufHead (ConsoleIn
, ScancodeArrPos
+ 1, ScancodeArr
);
1411 if (EFI_ERROR (Status
)) {
1412 return EFI_NOT_READY
;
1415 // store the last available byte, this byte of scancode will be checked
1417 ScanCode
= ScancodeArr
[ScancodeArrPos
];
1420 // Check for special keys and update the driver state.
1424 case SCANCODE_CTRL_MAKE
:
1425 ConsoleIn
->Ctrl
= TRUE
;
1428 case SCANCODE_CTRL_BREAK
:
1429 ConsoleIn
->Ctrl
= FALSE
;
1432 case SCANCODE_ALT_MAKE
:
1433 ConsoleIn
->Alt
= TRUE
;
1436 case SCANCODE_ALT_BREAK
:
1437 ConsoleIn
->Alt
= FALSE
;
1440 case SCANCODE_LEFT_SHIFT_MAKE
:
1442 ConsoleIn
->Shift
= TRUE
;
1443 ConsoleIn
->LeftShift
= TRUE
;
1446 case SCANCODE_RIGHT_SHIFT_MAKE
:
1448 ConsoleIn
->Shift
= TRUE
;
1449 ConsoleIn
->RightShift
= TRUE
;
1453 case SCANCODE_LEFT_SHIFT_BREAK
:
1455 ConsoleIn
->Shift
= FALSE
;
1456 ConsoleIn
->LeftShift
= FALSE
;
1458 ConsoleIn
->SysReq
= FALSE
;
1461 case SCANCODE_RIGHT_SHIFT_BREAK
:
1463 ConsoleIn
->Shift
= FALSE
;
1464 ConsoleIn
->RightShift
= FALSE
;
1468 case SCANCODE_LEFT_LOGO_MAKE
:
1469 ConsoleIn
->LeftLogo
= TRUE
;
1471 case SCANCODE_LEFT_LOGO_BREAK
:
1472 ConsoleIn
->LeftLogo
= FALSE
;
1474 case SCANCODE_RIGHT_LOGO_MAKE
:
1475 ConsoleIn
->RightLogo
= TRUE
;
1477 case SCANCODE_RIGHT_LOGO_BREAK
:
1478 ConsoleIn
->RightLogo
= FALSE
;
1480 case SCANCODE_MENU_MAKE
:
1481 ConsoleIn
->Menu
= TRUE
;
1483 case SCANCODE_MENU_BREAK
:
1484 ConsoleIn
->Menu
= FALSE
;
1486 case SCANCODE_SYS_REQ_MAKE
:
1488 ConsoleIn
->SysReq
= TRUE
;
1490 case SCANCODE_CAPS_LOCK_MAKE
:
1491 ConsoleIn
->CapsLock
= (BOOLEAN
)!ConsoleIn
->CapsLock
;
1492 UpdateStatusLights (ConsoleIn
);
1495 case SCANCODE_NUM_LOCK_MAKE
:
1496 ConsoleIn
->NumLock
= (BOOLEAN
)!ConsoleIn
->NumLock
;
1497 UpdateStatusLights (ConsoleIn
);
1500 case SCANCODE_SCROLL_LOCK_MAKE
:
1501 ConsoleIn
->ScrollLock
= (BOOLEAN
)!ConsoleIn
->ScrollLock
;
1502 UpdateStatusLights (ConsoleIn
);
1506 // If this is a BREAK Key or above the valid range, ignore it
1508 if (ScanCode
>= SCANCODE_MAX_MAKE
) {
1515 // Treat Numeric Key Pad "/" specially
1517 if (Extended
&& ScanCode
== 0x35) {
1518 ConsoleIn
->Key
.ScanCode
= SCAN_NULL
;
1519 ConsoleIn
->Key
.UnicodeChar
= '/';
1523 // Convert Keyboard ScanCode into an EFI Key
1525 for (Index
= 0; ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
!= TABLE_END
; Index
+= 1) {
1526 if (ScanCode
== ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
) {
1527 ConsoleIn
->Key
.ScanCode
= ConvertKeyboardScanCodeToEfiKey
[Index
].EfiScanCode
;
1528 if (ConsoleIn
->Shift
) {
1529 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1531 // Need not return associated shift state if a class of printable characters that
1532 // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
1534 if (ConsoleIn
->Key
.UnicodeChar
>= 'A' && ConsoleIn
->Key
.UnicodeChar
<= 'Z') {
1535 ConsoleIn
->LeftShift
= FALSE
;
1536 ConsoleIn
->RightShift
= FALSE
;
1539 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1542 // alphabetic key is affected by CapsLock State
1544 if (ConsoleIn
->CapsLock
) {
1545 if (ConsoleIn
->Key
.UnicodeChar
>= 'a' && ConsoleIn
->Key
.UnicodeChar
<= 'z') {
1546 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1547 } else if (ConsoleIn
->Key
.UnicodeChar
>= 'A' && ConsoleIn
->Key
.UnicodeChar
<= 'Z') {
1548 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1552 // Translate the CTRL-Alpha characters to their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
1554 if (ConsoleIn
->Ctrled
) {
1555 if (ConsoleIn
->Key
.UnicodeChar
>= 'a' && ConsoleIn
->Key
.UnicodeChar
<= 'z') {
1556 ConsoleIn
->Key
.UnicodeChar
= (UINT16
) (ConsoleIn
->Key
.UnicodeChar
- 'a' + 1);
1557 } else if (ConsoleIn
->Key
.UnicodeChar
>= 'A' && ConsoleIn
->Key
.UnicodeChar
<= 'Z') {
1558 ConsoleIn
->Key
.UnicodeChar
= (UINT16
) (ConsoleIn
->Key
.UnicodeChar
- 'A' + 1);
1567 // distinguish numeric key pad keys' 'up symbol' and 'down symbol'
1569 if (ScanCode
>= 0x47 && ScanCode
<= 0x53) {
1571 if (ConsoleIn
->NumLock
&& !ConsoleIn
->Shift
&& !Extended
) {
1572 ConsoleIn
->Key
.ScanCode
= SCAN_NULL
;
1573 } else if (ScanCode
!= 0x4a && ScanCode
!= 0x4e) {
1574 ConsoleIn
->Key
.UnicodeChar
= 0x00;
1578 // If the key can not be converted then just return.
1580 if (ConsoleIn
->Key
.ScanCode
== SCAN_NULL
&& ConsoleIn
->Key
.UnicodeChar
== 0x00) {
1581 return EFI_NOT_READY
;
1585 // Save the Shift/Toggle state
1587 if (ConsoleIn
->Ctrl
) {
1588 ConsoleIn
->KeyState
.KeyShiftState
|= (Extended
== TRUE
) ? EFI_RIGHT_CONTROL_PRESSED
: EFI_LEFT_CONTROL_PRESSED
;
1590 if (ConsoleIn
->Alt
) {
1591 ConsoleIn
->KeyState
.KeyShiftState
|= (Extended
== TRUE
) ? EFI_RIGHT_ALT_PRESSED
: EFI_LEFT_ALT_PRESSED
;
1593 if (ConsoleIn
->LeftShift
) {
1594 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_LEFT_SHIFT_PRESSED
;
1596 if (ConsoleIn
->RightShift
) {
1597 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_RIGHT_SHIFT_PRESSED
;
1599 if (ConsoleIn
->LeftLogo
) {
1600 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_LEFT_LOGO_PRESSED
;
1602 if (ConsoleIn
->RightLogo
) {
1603 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_RIGHT_LOGO_PRESSED
;
1605 if (ConsoleIn
->Menu
) {
1606 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_MENU_KEY_PRESSED
;
1608 if (ConsoleIn
->SysReq
) {
1609 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_SYS_REQ_PRESSED
;
1611 if (ConsoleIn
->CapsLock
) {
1612 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_CAPS_LOCK_ACTIVE
;
1614 if (ConsoleIn
->NumLock
) {
1615 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_NUM_LOCK_ACTIVE
;
1617 if (ConsoleIn
->ScrollLock
) {
1618 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_SCROLL_LOCK_ACTIVE
;
1625 Perform 8042 controller and keyboard Initialization
1626 If ExtendedVerification is TRUE, do additional test for
1627 the keyboard interface
1629 @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
1630 @param ExtendedVerification - indicates a thorough initialization
1632 @retval EFI_DEVICE_ERROR Fail to init keyboard
1633 @retval EFI_SUCCESS Success to init keyboard
1637 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1638 IN BOOLEAN ExtendedVerification
1644 EFI_PS2_POLICY_PROTOCOL
*Ps2Policy
;
1647 Status
= EFI_SUCCESS
;
1648 mEnableMouseInterface
= TRUE
;
1652 // Get Ps2 policy to set this
1654 gBS
->LocateProtocol (
1655 &gEfiPs2PolicyProtocolGuid
,
1657 (VOID
**) &Ps2Policy
1660 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1662 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
,
1663 ConsoleIn
->DevicePath
1667 // Perform a read to cleanup the Status Register's
1668 // output buffer full bits within MAX TRY times
1670 while (!EFI_ERROR (Status
) && TryTime
< KEYBOARD_MAX_TRY
) {
1671 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1675 // Exceed the max try times. The device may be error.
1677 if (TryTime
== KEYBOARD_MAX_TRY
) {
1678 Status
= EFI_DEVICE_ERROR
;
1682 // We should disable mouse interface during the initialization process
1683 // since mouse device output could block keyboard device output in the
1684 // 60H port of 8042 controller.
1686 // So if we are not initializing 8042 controller for the
1687 // first time, we have to remember the previous mouse interface
1690 // Test the system flag in to determine whether this is the first
1691 // time initialization
1693 if ((KeyReadStatusRegister (ConsoleIn
) & 0x04)) {
1695 // 8042 controller is already setup (by myself or by mouse driver):
1696 // See whether mouse interface is already enabled
1697 // which determines whether we should enable it later
1700 // Read the command byte of 8042 controller
1702 Status
= KeyboardCommand (ConsoleIn
, 0x20);
1703 if (EFI_ERROR (Status
)) {
1704 KeyboardError (ConsoleIn
, L
"\n\r");
1708 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1709 if (EFI_ERROR (Status
)) {
1710 KeyboardError (ConsoleIn
, L
"\n\r");
1714 // Test the mouse enabling bit
1716 if (CommandByte
& 0x20) {
1717 mEnableMouseInterface
= FALSE
;
1719 mEnableMouseInterface
= TRUE
;
1724 // 8042 controller is not setup yet:
1725 // 8042 controller selftest;
1726 // Don't enable mouse interface later.
1729 // Disable keyboard and mouse interfaces
1731 Status
= KeyboardCommand (ConsoleIn
, 0xad);
1732 if (EFI_ERROR (Status
)) {
1733 KeyboardError (ConsoleIn
, L
"\n\r");
1737 Status
= KeyboardCommand (ConsoleIn
, 0xa7);
1738 if (EFI_ERROR (Status
)) {
1739 KeyboardError (ConsoleIn
, L
"\n\r");
1743 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1745 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
,
1746 ConsoleIn
->DevicePath
1749 // 8042 Controller Self Test
1751 Status
= KeyboardCommand (ConsoleIn
, 0xaa);
1752 if (EFI_ERROR (Status
)) {
1753 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1757 Status
= KeyboardWaitForValue (ConsoleIn
, 0x55);
1758 if (EFI_ERROR (Status
)) {
1759 KeyboardError (ConsoleIn
, L
"8042 controller self test failed!\n\r");
1763 // Don't enable mouse interface later
1765 mEnableMouseInterface
= FALSE
;
1769 if (Ps2Policy
!= NULL
) {
1770 Ps2Policy
->Ps2InitHardware (ConsoleIn
->Handle
);
1773 // Write 8042 Command Byte, set System Flag
1774 // While at the same time:
1775 // 1. disable mouse interface,
1776 // 2. enable kbd interface,
1777 // 3. enable PC/XT kbd translation mode
1778 // 4. enable mouse and kbd interrupts
1780 // ( Command Byte bits:
1782 // 6: PC/XT translation mode
1783 // 5: Disable Auxiliary device interface
1784 // 4: Disable keyboard interface
1787 // 1: Enable Auxiliary device interrupt
1788 // 0: Enable Keyboard interrupt )
1790 Status
= KeyboardCommand (ConsoleIn
, 0x60);
1791 if (EFI_ERROR (Status
)) {
1792 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1796 Status
= KeyboardWrite (ConsoleIn
, 0x67);
1797 if (EFI_ERROR (Status
)) {
1798 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1803 // Clear Memory Scancode Buffer
1805 ConsoleIn
->ScancodeBufStartPos
= 0;
1806 ConsoleIn
->ScancodeBufEndPos
= KEYBOARD_BUFFER_MAX_COUNT
- 1;
1807 ConsoleIn
->ScancodeBufCount
= 0;
1808 ConsoleIn
->Ctrled
= FALSE
;
1809 ConsoleIn
->Alted
= FALSE
;
1812 // Reset the status indicators
1814 ConsoleIn
->Ctrl
= FALSE
;
1815 ConsoleIn
->Alt
= FALSE
;
1816 ConsoleIn
->Shift
= FALSE
;
1817 ConsoleIn
->CapsLock
= FALSE
;
1818 ConsoleIn
->NumLock
= FALSE
;
1819 ConsoleIn
->ScrollLock
= FALSE
;
1820 ConsoleIn
->LeftShift
= FALSE
;
1821 ConsoleIn
->RightShift
= FALSE
;
1822 ConsoleIn
->LeftLogo
= FALSE
;
1823 ConsoleIn
->RightLogo
= FALSE
;
1824 ConsoleIn
->Menu
= FALSE
;
1825 ConsoleIn
->SysReq
= FALSE
;
1828 // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1829 // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected
1830 // to system. So we only do the real reseting for keyboard when user asks and there is a real KB connected t system,
1831 // and normally during booting an OS, it's skipped.
1833 if (ExtendedVerification
&& CheckKeyboardConnect (ConsoleIn
)) {
1835 // Additional verifications for keyboard interface
1838 // Keyboard Interface Test
1840 Status
= KeyboardCommand (ConsoleIn
, 0xab);
1841 if (EFI_ERROR (Status
)) {
1842 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1846 Status
= KeyboardWaitForValue (ConsoleIn
, 0x00);
1847 if (EFI_ERROR (Status
)) {
1850 L
"Some specific value not aquired from 8042 controller!\n\r"
1855 // Keyboard reset with a BAT(Basic Assurance Test)
1857 Status
= KeyboardWrite (ConsoleIn
, 0xff);
1858 if (EFI_ERROR (Status
)) {
1859 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1863 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1864 if (EFI_ERROR (Status
)) {
1865 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1869 // wait for BAT completion code
1871 mWaitForValueTimeOut
= KEYBOARD_BAT_TIMEOUT
;
1873 Status
= KeyboardWaitForValue (ConsoleIn
, 0xaa);
1874 if (EFI_ERROR (Status
)) {
1875 KeyboardError (ConsoleIn
, L
"Keyboard self test failed!\n\r");
1879 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1882 // Set Keyboard to use Scan Code Set 2
1884 Status
= KeyboardWrite (ConsoleIn
, 0xf0);
1885 if (EFI_ERROR (Status
)) {
1886 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1890 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1891 if (EFI_ERROR (Status
)) {
1892 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1896 Status
= KeyboardWrite (ConsoleIn
, 0x02);
1897 if (EFI_ERROR (Status
)) {
1898 KeyboardError (ConsoleIn
, L
"8042 controller data write error!!\n\r");
1902 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1903 if (EFI_ERROR (Status
)) {
1904 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1909 // Clear Keyboard Scancode Buffer
1911 Status
= KeyboardWrite (ConsoleIn
, 0xf4);
1912 if (EFI_ERROR (Status
)) {
1913 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1917 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1918 if (EFI_ERROR (Status
)) {
1919 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1923 if (Ps2Policy
!= NULL
) {
1924 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_CAPSLOCK
) == EFI_KEYBOARD_CAPSLOCK
) {
1925 ConsoleIn
->CapsLock
= TRUE
;
1928 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_NUMLOCK
) == EFI_KEYBOARD_NUMLOCK
) {
1929 ConsoleIn
->NumLock
= TRUE
;
1932 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_SCROLLLOCK
) == EFI_KEYBOARD_SCROLLLOCK
) {
1933 ConsoleIn
->ScrollLock
= TRUE
;
1937 // Update Keyboard Lights
1939 Status
= UpdateStatusLights (ConsoleIn
);
1940 if (EFI_ERROR (Status
)) {
1941 KeyboardError (ConsoleIn
, L
"Update keyboard status lights error!\n\r");
1946 // At last, we can now enable the mouse interface if appropriate
1950 if (mEnableMouseInterface
) {
1952 // Enable mouse interface
1954 Status1
= KeyboardCommand (ConsoleIn
, 0xa8);
1955 if (EFI_ERROR (Status1
)) {
1956 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1957 return EFI_DEVICE_ERROR
;
1961 if (!EFI_ERROR (Status
)) {
1964 return EFI_DEVICE_ERROR
;
1970 Disable the keyboard interface of the 8042 controller
1972 @param ConsoleIn - the device instance
1974 @return status of issuing disable command
1979 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1985 // Disable keyboard interface
1987 Status
= KeyboardCommand (ConsoleIn
, 0xad);
1988 if (EFI_ERROR (Status
)) {
1989 KeyboardError (ConsoleIn
, L
"\n\r");
1990 return EFI_DEVICE_ERROR
;
1997 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
1998 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
1999 should not be in system.
2001 @param[in] ConsoleIn Keyboard Private Data Structure
2003 @retval TRUE Keyboard in System.
2004 @retval FALSE Keyboard not in System.
2008 CheckKeyboardConnect (
2009 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
2013 UINTN WaitForValueTimeOutBcakup
;
2015 Status
= EFI_SUCCESS
;
2017 // enable keyboard itself and wait for its ack
2018 // If can't receive ack, Keyboard should not be connected.
2020 Status
= KeyboardWrite (
2025 if (EFI_ERROR (Status
)) {
2031 WaitForValueTimeOutBcakup
= mWaitForValueTimeOut
;
2032 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
2033 Status
= KeyboardWaitForValue (
2035 KEYBOARD_CMDECHO_ACK
2037 mWaitForValueTimeOut
= WaitForValueTimeOutBcakup
;
2039 if (EFI_ERROR (Status
)) {