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.
17 // Include common header file for this module.
19 #include "Ps2Keyboard.h"
22 // Function declarations
27 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
32 KeyWriteDataRegister (
33 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
39 KeyWriteCommandRegister (
40 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
47 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
48 IN CHAR16
*ErrMsg
// should be a unicode string
54 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
62 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
70 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
77 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
83 KeyboardWaitForValue (
84 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
92 CHAR16 ShiftUnicodeChar
;
94 ConvertKeyboardScanCodeToEfiKey
[] = {
421 0x37, // Numeric Keypad *
427 0x38, //Left Alt/Extended Right Alt
547 0x4c, // Numeric Keypad 5
634 // The WaitForValue time out
636 STATIC UINTN mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
641 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
643 @return return the value
648 KeyReadDataRegister (
649 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
653 EFI_ISA_IO_PROTOCOL
*IsaIo
;
657 // Use IsaIo protocol to perform IO operations
659 IsaIo
= ConsoleIn
->IsaIo
;
664 ConsoleIn
->DataRegisterAddress
,
675 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
676 @param Data value wanted to be written
681 KeyWriteDataRegister (
682 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
687 EFI_ISA_IO_PROTOCOL
*IsaIo
;
690 // Use IsaIo protocol to perform IO operations
692 IsaIo
= ConsoleIn
->IsaIo
;
697 ConsoleIn
->DataRegisterAddress
,
703 // outp(ConsoleIn->DataRegisterAddress, Data);
710 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
712 @return value in status register
716 KeyReadStatusRegister (
717 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
720 EFI_ISA_IO_PROTOCOL
*IsaIo
;
724 // Use IsaIo protocol to perform IO operations
726 IsaIo
= ConsoleIn
->IsaIo
;
731 ConsoleIn
->StatusRegisterAddress
,
741 Write command register
743 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
744 @param Data The value wanted to be written
750 KeyWriteCommandRegister (
751 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
755 EFI_ISA_IO_PROTOCOL
*IsaIo
;
758 // Use IsaIo protocol to perform IO operations
760 IsaIo
= ConsoleIn
->IsaIo
;
765 ConsoleIn
->CommandRegisterAddress
,
773 Display error message
775 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
776 @param ErrMsg Unicode string of error message
782 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
786 ConsoleIn
->KeyboardErr
= TRUE
;
789 // gST -> ConOut -> OutputString (gST -> ConOut, L"Keyboard Driver: ");
790 // gST -> ConOut -> OutputString (gST -> ConOut, ErrMsg);
795 Timer event handler: read a series of scancodes from 8042
796 and put them into memory scancode buffer.
797 it read as much scancodes to either fill
798 the memory buffer or empty the keyboard buffer.
799 It is registered as running under TPL_NOTIFY
801 @param Event - The timer event
802 @param Context - A KEYBOARD_CONSOLE_IN_DEV pointer
807 KeyboardTimerHandler (
815 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
820 // Enter critical section
822 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
824 if (((KEYBOARD_CONSOLE_IN_DEV
*) Context
)->KeyboardErr
) {
826 // Leave critical section and return
828 gBS
->RestoreTPL (OldTpl
);
832 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
833 // KB is not connected to system. If KB is not connected to system, driver will find there's something
834 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
835 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
836 // Just skip the 'resend' process simply.
842 // if there is no key present, just return
844 if ((KeyReadStatusRegister (Context
) & 0x21) != 0x1) {
846 // Leave critical section and return
848 gBS
->RestoreTPL (OldTpl
);
853 // Read one byte of the scan code and store it into the memory buffer
855 if (ConsoleIn
->ScancodeBufCount
< KEYBOARD_BUFFER_MAX_COUNT
) {
857 Data
= KeyReadDataRegister (Context
);
859 // put the scancode into the memory scancode buffer
861 ConsoleIn
->ScancodeBufCount
++;
862 ConsoleIn
->ScancodeBufEndPos
++;
863 if (ConsoleIn
->ScancodeBufEndPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
864 ConsoleIn
->ScancodeBufEndPos
= 0;
867 ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufEndPos
] = Data
;
870 // Handle Alt+Ctrl+Del Key combination
873 case SCANCODE_CTRL_MAKE
:
874 ConsoleIn
->Ctrled
= TRUE
;
877 case SCANCODE_CTRL_BREAK
:
878 ConsoleIn
->Ctrled
= FALSE
;
881 case SCANCODE_ALT_MAKE
:
882 ConsoleIn
->Alted
= TRUE
;
885 case SCANCODE_ALT_BREAK
:
886 ConsoleIn
->Alted
= FALSE
;
890 // if Alt+Ctrl+Del, Reboot the System
892 if (ConsoleIn
->Ctrled
&& ConsoleIn
->Alted
&& Data
== 0x53) {
893 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
897 // Leave critical section and return
899 gBS
->RestoreTPL (OldTpl
);
905 Read several bytes from the scancode buffer without removing them.
906 This function is called to see if there are enough bytes of scancode
907 representing a single key.
909 @param Count - Number of bytes to be read
910 @param Buf - Store the results
912 @retval EFI_SUCCESS success to scan the keyboard code
913 @retval EFI_NOT_READY invalid parameter
918 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
930 // check the valid range of parameter 'Count'
932 if (Count
<= 0 || ConsoleIn
->ScancodeBufCount
< Count
) {
933 return EFI_NOT_READY
;
936 // retrieve the values
938 for (Index
= 0; Index
< Count
; Index
++) {
942 Pos
= ConsoleIn
->ScancodeBufStartPos
;
946 if (Pos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
951 Buf
[Index
] = ConsoleIn
->ScancodeBuf
[Pos
];
959 Read & remove several bytes from the scancode buffer.
960 This function is usually called after GetScancodeBufHead()
962 @param Count - Number of bytes to be read
963 @param Buf - Store the results
965 @retval EFI_SUCCESS success to scan the keyboard code
966 @retval EFI_NOT_READY invalid parameter
971 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
981 // Check the valid range of parameter 'Count'
983 if (Count
<= 0 || ConsoleIn
->ScancodeBufCount
< Count
) {
984 return EFI_NOT_READY
;
987 // Retrieve and remove the values
989 for (Index
= 0; Index
< Count
; Index
++) {
993 ConsoleIn
->ScancodeBufStartPos
++;
994 if (ConsoleIn
->ScancodeBufStartPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
995 ConsoleIn
->ScancodeBufStartPos
= 0;
999 Buf
[Index
] = ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufStartPos
];
1000 ConsoleIn
->ScancodeBufCount
--;
1003 ConsoleIn
->ScancodeBufStartPos
++;
1004 if (ConsoleIn
->ScancodeBufStartPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
1005 ConsoleIn
->ScancodeBufStartPos
= 0;
1014 @param ConsoleIn - Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1015 @param Data - Pointer to outof buffer for keeping key value
1017 @retval EFI_TIMEOUT Status resigter time out
1018 @retval EFI_SUCCESS Success to read keyboard
1023 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1035 // wait till output buffer full then perform the read
1037 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1038 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1040 *Data
= KeyReadDataRegister (ConsoleIn
);
1055 write key to keyboard
1057 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1058 @param Data value wanted to be written
1060 @retval EFI_TIMEOUT - GC_TODO: Add description for return value
1061 @retval EFI_SUCCESS - GC_TODO: Add description for return value
1067 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1078 // wait for input buffer empty
1080 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1081 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x02)) {
1095 KeyWriteDataRegister (ConsoleIn
, Data
);
1101 Issue keyboard command
1103 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1104 @param Data The buff holding the command
1106 @retval EFI_TIMEOUT Keyboard is not ready to issuing
1107 @retval EFI_SUCCESS Success to issue keyboard command
1113 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1124 // Wait For Input Buffer Empty
1126 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1127 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x02)) {
1139 // issue the command
1141 KeyWriteCommandRegister (ConsoleIn
, Data
);
1144 // Wait For Input Buffer Empty again
1147 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1148 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x02)) {
1164 wait for a specific value to be presented on
1165 8042 Data register by keyboard and then read it,
1166 used in keyboard commands ack
1168 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1169 @param Value the value wanted to be waited.
1171 @retval EFI_TIMEOUT Fail to get specific value in given time
1172 @retval EFI_SUCCESS Success to get specific value in given time.
1177 KeyboardWaitForValue (
1178 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1192 // Make sure the initial value of 'Data' is different from 'Value'
1195 if (Data
== Value
) {
1199 // Read from 8042 (multiple times if needed)
1200 // until the expected value appears
1201 // use SumTimeOut to control the iteration
1207 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1208 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1209 Data
= KeyReadDataRegister (ConsoleIn
);
1216 SumTimeOut
+= TimeOut
;
1218 if (Data
== Value
) {
1223 if (SumTimeOut
>= mWaitForValueTimeOut
) {
1239 Show keyboard status lights according to
1240 indicators in ConsoleIn.
1242 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1248 UpdateStatusLights (
1249 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1256 // Send keyboard command
1258 Status
= KeyboardWrite (ConsoleIn
, 0xed);
1259 if (EFI_ERROR (Status
)) {
1263 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1266 // Light configuration
1269 if (ConsoleIn
->CapsLock
) {
1273 if (ConsoleIn
->NumLock
) {
1277 if (ConsoleIn
->ScrollLock
) {
1281 Status
= KeyboardWrite (ConsoleIn
, Command
);
1283 if (EFI_ERROR (Status
)) {
1287 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1292 Get scancode from scancode buffer
1293 and translate into EFI-scancode and unicode defined by EFI spec
1294 The function is always called in TPL_NOTIFY
1296 @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer
1298 @retval EFI_NOT_READY - Input from console not ready yet.
1299 @retval EFI_SUCCESS - Function executed successfully.
1304 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1311 UINT8 ScancodeArr
[4];
1316 UINT32 ScancodeArrPos
;
1318 // point to the current position in ScancodeArr
1326 // Read one byte of the scan code and store it into the memory buffer
1327 // This block of code is added to insert an action that is equivalent to
1328 // the timer event handling function, so as to increase the frequency of
1329 // detecting the availability of keys. Timer event has a max frequency of
1330 // 18Hz which is insufficient
1333 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
1334 // KB is not connected to system. If KB is not connected to system, driver will find there's something
1335 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
1336 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
1337 // Just skip the 'resend' process simply.
1341 if (((KeyReadStatusRegister (ConsoleIn
) & 0x21) == 0x1) && (ConsoleIn
->ScancodeBufCount
< KEYBOARD_BUFFER_MAX_COUNT
)) {
1343 Readed
= KeyReadDataRegister (ConsoleIn
);
1345 // put the scancode into the memory scancode buffer
1347 ConsoleIn
->ScancodeBufCount
++;
1348 ConsoleIn
->ScancodeBufEndPos
++;
1349 if (ConsoleIn
->ScancodeBufEndPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
1350 ConsoleIn
->ScancodeBufEndPos
= 0;
1353 ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufEndPos
] = Readed
;
1356 // Handle Alt+Ctrl+Del Key combination
1360 case SCANCODE_CTRL_MAKE
:
1361 ConsoleIn
->Ctrled
= TRUE
;
1364 case SCANCODE_CTRL_BREAK
:
1365 ConsoleIn
->Ctrled
= FALSE
;
1368 case SCANCODE_ALT_MAKE
:
1369 ConsoleIn
->Alted
= TRUE
;
1372 case SCANCODE_ALT_BREAK
:
1373 ConsoleIn
->Alted
= FALSE
;
1377 // if Alt+Ctrl+Del, Reboot the System
1379 if (ConsoleIn
->Ctrled
&& ConsoleIn
->Alted
&& Readed
== 0x53) {
1380 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1384 // Check if there are enough bytes of scancode representing a single key
1385 // available in the buffer
1389 Status
= GetScancodeBufHead (ConsoleIn
, 1, ScancodeArr
);
1391 if (EFI_ERROR (Status
)) {
1392 return EFI_NOT_READY
;
1395 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED
) {
1397 Status
= GetScancodeBufHead (ConsoleIn
, 2, ScancodeArr
);
1399 if (EFI_ERROR (Status
)) {
1400 return EFI_NOT_READY
;
1404 // Checks for key scancode for PAUSE:E1-1D/45-E1/9D-C5
1405 // if present, ignore them
1407 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED1
) {
1409 Status
= GetScancodeBufHead (ConsoleIn
, 2, ScancodeArr
);
1412 if (EFI_ERROR (Status
)) {
1413 return EFI_NOT_READY
;
1416 Status
= GetScancodeBufHead (ConsoleIn
, 3, ScancodeArr
);
1419 if (EFI_ERROR (Status
)) {
1420 return EFI_NOT_READY
;
1423 PopScancodeBufHead (ConsoleIn
, 3, ScancodeArr
);
1424 return EFI_NOT_READY
;
1427 // if we reach this position, scancodes for a key is in buffer now,pop them
1429 Status
= PopScancodeBufHead (ConsoleIn
, ScancodeArrPos
+ 1, ScancodeArr
);
1430 if (EFI_ERROR (Status
)) {
1431 return EFI_NOT_READY
;
1434 // store the last available byte, this byte of scancode will be checked
1436 ScanCode
= ScancodeArr
[ScancodeArrPos
];
1439 // Check for special keys and update the driver state.
1443 case SCANCODE_CTRL_MAKE
:
1444 ConsoleIn
->Ctrl
= TRUE
;
1447 case SCANCODE_CTRL_BREAK
:
1448 ConsoleIn
->Ctrl
= FALSE
;
1451 case SCANCODE_ALT_MAKE
:
1452 ConsoleIn
->Alt
= TRUE
;
1455 case SCANCODE_ALT_BREAK
:
1456 ConsoleIn
->Alt
= FALSE
;
1459 case SCANCODE_LEFT_SHIFT_MAKE
:
1461 ConsoleIn
->Shift
= TRUE
;
1462 ConsoleIn
->LeftShift
= TRUE
;
1465 case SCANCODE_RIGHT_SHIFT_MAKE
:
1467 ConsoleIn
->Shift
= TRUE
;
1468 ConsoleIn
->RightShift
= TRUE
;
1472 case SCANCODE_LEFT_SHIFT_BREAK
:
1474 ConsoleIn
->Shift
= FALSE
;
1475 ConsoleIn
->LeftShift
= FALSE
;
1477 ConsoleIn
->SysReq
= FALSE
;
1480 case SCANCODE_RIGHT_SHIFT_BREAK
:
1482 ConsoleIn
->Shift
= FALSE
;
1483 ConsoleIn
->RightShift
= FALSE
;
1487 case SCANCODE_LEFT_LOGO_MAKE
:
1488 ConsoleIn
->LeftLogo
= TRUE
;
1490 case SCANCODE_LEFT_LOGO_BREAK
:
1491 ConsoleIn
->LeftLogo
= FALSE
;
1493 case SCANCODE_RIGHT_LOGO_MAKE
:
1494 ConsoleIn
->RightLogo
= TRUE
;
1496 case SCANCODE_RIGHT_LOGO_BREAK
:
1497 ConsoleIn
->RightLogo
= FALSE
;
1499 case SCANCODE_MENU_MAKE
:
1500 ConsoleIn
->Menu
= TRUE
;
1502 case SCANCODE_MENU_BREAK
:
1503 ConsoleIn
->Menu
= FALSE
;
1505 case SCANCODE_SYS_REQ_MAKE
:
1507 ConsoleIn
->SysReq
= TRUE
;
1509 case SCANCODE_CAPS_LOCK_MAKE
:
1510 ConsoleIn
->CapsLock
= (BOOLEAN
)!ConsoleIn
->CapsLock
;
1511 UpdateStatusLights (ConsoleIn
);
1514 case SCANCODE_NUM_LOCK_MAKE
:
1515 ConsoleIn
->NumLock
= (BOOLEAN
)!ConsoleIn
->NumLock
;
1516 UpdateStatusLights (ConsoleIn
);
1519 case SCANCODE_SCROLL_LOCK_MAKE
:
1520 ConsoleIn
->ScrollLock
= (BOOLEAN
)!ConsoleIn
->ScrollLock
;
1521 UpdateStatusLights (ConsoleIn
);
1525 // If this is a BREAK Key or above the valid range, ignore it
1527 if (ScanCode
>= SCANCODE_MAX_MAKE
) {
1534 // Treat Numeric Key Pad "/" specially
1536 if (Extended
&& ScanCode
== 0x35) {
1537 ConsoleIn
->Key
.ScanCode
= SCAN_NULL
;
1538 ConsoleIn
->Key
.UnicodeChar
= '/';
1542 // Convert Keyboard ScanCode into an EFI Key
1544 for (Index
= 0; ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
!= TABLE_END
; Index
+= 1) {
1545 if (ScanCode
== ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
) {
1546 ConsoleIn
->Key
.ScanCode
= ConvertKeyboardScanCodeToEfiKey
[Index
].EfiScanCode
;
1547 if (ConsoleIn
->Shift
) {
1548 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1550 // Need not return associated shift state if a class of printable characters that
1551 // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
1553 if (ConsoleIn
->Key
.UnicodeChar
>= 'A' && ConsoleIn
->Key
.UnicodeChar
<= 'Z') {
1554 ConsoleIn
->LeftShift
= FALSE
;
1555 ConsoleIn
->RightShift
= FALSE
;
1558 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1561 // alphabetic key is affected by CapsLock State
1563 if (ConsoleIn
->CapsLock
) {
1564 if (ConsoleIn
->Key
.UnicodeChar
>= 'a' && ConsoleIn
->Key
.UnicodeChar
<= 'z') {
1565 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1566 } else if (ConsoleIn
->Key
.UnicodeChar
>= 'A' && ConsoleIn
->Key
.UnicodeChar
<= 'Z') {
1567 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1571 // Translate the CTRL-Alpha characters to their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
1573 if (ConsoleIn
->Ctrled
) {
1574 if (ConsoleIn
->Key
.UnicodeChar
>= 'a' && ConsoleIn
->Key
.UnicodeChar
<= 'z') {
1575 ConsoleIn
->Key
.UnicodeChar
= (UINT16
) (ConsoleIn
->Key
.UnicodeChar
- 'a' + 1);
1576 } else if (ConsoleIn
->Key
.UnicodeChar
>= 'A' && ConsoleIn
->Key
.UnicodeChar
<= 'Z') {
1577 ConsoleIn
->Key
.UnicodeChar
= (UINT16
) (ConsoleIn
->Key
.UnicodeChar
- 'A' + 1);
1586 // distinguish numeric key pad keys' 'up symbol' and 'down symbol'
1588 if (ScanCode
>= 0x47 && ScanCode
<= 0x53) {
1590 if (ConsoleIn
->NumLock
&& !ConsoleIn
->Shift
&& !Extended
) {
1591 ConsoleIn
->Key
.ScanCode
= SCAN_NULL
;
1592 } else if (ScanCode
!= 0x4a && ScanCode
!= 0x4e) {
1593 ConsoleIn
->Key
.UnicodeChar
= 0x00;
1597 // If the key can not be converted then just return.
1599 if (ConsoleIn
->Key
.ScanCode
== SCAN_NULL
&& ConsoleIn
->Key
.UnicodeChar
== 0x00) {
1600 return EFI_NOT_READY
;
1604 // Save the Shift/Toggle state
1606 if (ConsoleIn
->Ctrl
) {
1607 ConsoleIn
->KeyState
.KeyShiftState
|= (Extended
== TRUE
) ? EFI_RIGHT_CONTROL_PRESSED
: EFI_LEFT_CONTROL_PRESSED
;
1609 if (ConsoleIn
->Alt
) {
1610 ConsoleIn
->KeyState
.KeyShiftState
|= (Extended
== TRUE
) ? EFI_RIGHT_ALT_PRESSED
: EFI_LEFT_ALT_PRESSED
;
1612 if (ConsoleIn
->LeftShift
) {
1613 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_LEFT_SHIFT_PRESSED
;
1615 if (ConsoleIn
->RightShift
) {
1616 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_RIGHT_SHIFT_PRESSED
;
1618 if (ConsoleIn
->LeftLogo
) {
1619 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_LEFT_LOGO_PRESSED
;
1621 if (ConsoleIn
->RightLogo
) {
1622 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_RIGHT_LOGO_PRESSED
;
1624 if (ConsoleIn
->Menu
) {
1625 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_MENU_KEY_PRESSED
;
1627 if (ConsoleIn
->SysReq
) {
1628 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_SYS_REQ_PRESSED
;
1630 if (ConsoleIn
->CapsLock
) {
1631 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_CAPS_LOCK_ACTIVE
;
1633 if (ConsoleIn
->NumLock
) {
1634 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_NUM_LOCK_ACTIVE
;
1636 if (ConsoleIn
->ScrollLock
) {
1637 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_SCROLL_LOCK_ACTIVE
;
1644 Perform 8042 controller and keyboard Initialization
1645 If ExtendedVerification is TRUE, do additional test for
1646 the keyboard interface
1648 @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
1649 @param ExtendedVerification - indicates a thorough initialization
1651 @retval EFI_DEVICE_ERROR Fail to init keyboard
1652 @retval EFI_SUCCESS Success to init keyboard
1656 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1657 IN BOOLEAN ExtendedVerification
1663 STATIC BOOLEAN EnableMouseInterface
;
1664 EFI_PS2_POLICY_PROTOCOL
*Ps2Policy
;
1666 Status
= EFI_SUCCESS
;
1667 EnableMouseInterface
= TRUE
;
1670 // Get Ps2 policy to set this
1672 Status
= gBS
->LocateProtocol (
1673 &gEfiPs2PolicyProtocolGuid
,
1675 (VOID
**) &Ps2Policy
1678 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1680 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
,
1681 ConsoleIn
->DevicePath
1685 // Perform a read to cleanup the Status Register's
1686 // output buffer full bits
1688 while (!EFI_ERROR (Status
)) {
1689 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1692 // We should disable mouse interface during the initialization process
1693 // since mouse device output could block keyboard device output in the
1694 // 60H port of 8042 controller.
1696 // So if we are not initializing 8042 controller for the
1697 // first time, we have to remember the previous mouse interface
1700 // Test the system flag in to determine whether this is the first
1701 // time initialization
1703 if ((KeyReadStatusRegister (ConsoleIn
) & 0x04)) {
1705 // 8042 controller is already setup (by myself or by mouse driver):
1706 // See whether mouse interface is already enabled
1707 // which determines whether we should enable it later
1710 // Read the command byte of 8042 controller
1712 Status
= KeyboardCommand (ConsoleIn
, 0x20);
1713 if (EFI_ERROR (Status
)) {
1714 KeyboardError (ConsoleIn
, L
"\n\r");
1718 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1719 if (EFI_ERROR (Status
)) {
1720 KeyboardError (ConsoleIn
, L
"\n\r");
1724 // Test the mouse enabling bit
1726 if (CommandByte
& 0x20) {
1727 EnableMouseInterface
= FALSE
;
1729 EnableMouseInterface
= TRUE
;
1734 // 8042 controller is not setup yet:
1735 // 8042 controller selftest;
1736 // Don't enable mouse interface later.
1739 // Disable keyboard and mouse interfaces
1741 Status
= KeyboardCommand (ConsoleIn
, 0xad);
1742 if (EFI_ERROR (Status
)) {
1743 KeyboardError (ConsoleIn
, L
"\n\r");
1747 Status
= KeyboardCommand (ConsoleIn
, 0xa7);
1748 if (EFI_ERROR (Status
)) {
1749 KeyboardError (ConsoleIn
, L
"\n\r");
1753 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1755 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
,
1756 ConsoleIn
->DevicePath
1759 // 8042 Controller Self Test
1761 Status
= KeyboardCommand (ConsoleIn
, 0xaa);
1762 if (EFI_ERROR (Status
)) {
1763 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1767 Status
= KeyboardWaitForValue (ConsoleIn
, 0x55);
1768 if (EFI_ERROR (Status
)) {
1769 KeyboardError (ConsoleIn
, L
"8042 controller self test failed!\n\r");
1773 // Don't enable mouse interface later
1775 EnableMouseInterface
= FALSE
;
1779 if (Ps2Policy
!= NULL
) {
1780 Ps2Policy
->Ps2InitHardware (ConsoleIn
->Handle
);
1783 // Write 8042 Command Byte, set System Flag
1784 // While at the same time:
1785 // 1. disable mouse interface,
1786 // 2. enable kbd interface,
1787 // 3. enable PC/XT kbd translation mode
1788 // 4. enable mouse and kbd interrupts
1790 // ( Command Byte bits:
1792 // 6: PC/XT translation mode
1793 // 5: Disable Auxiliary device interface
1794 // 4: Disable keyboard interface
1797 // 1: Enable Auxiliary device interrupt
1798 // 0: Enable Keyboard interrupt )
1800 Status
= KeyboardCommand (ConsoleIn
, 0x60);
1801 if (EFI_ERROR (Status
)) {
1802 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1806 Status
= KeyboardWrite (ConsoleIn
, 0x67);
1807 if (EFI_ERROR (Status
)) {
1808 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1813 // Clear Memory Scancode Buffer
1815 ConsoleIn
->ScancodeBufStartPos
= 0;
1816 ConsoleIn
->ScancodeBufEndPos
= KEYBOARD_BUFFER_MAX_COUNT
- 1;
1817 ConsoleIn
->ScancodeBufCount
= 0;
1818 ConsoleIn
->Ctrled
= FALSE
;
1819 ConsoleIn
->Alted
= FALSE
;
1822 // Reset the status indicators
1824 ConsoleIn
->Ctrl
= FALSE
;
1825 ConsoleIn
->Alt
= FALSE
;
1826 ConsoleIn
->Shift
= FALSE
;
1827 ConsoleIn
->CapsLock
= FALSE
;
1828 ConsoleIn
->NumLock
= FALSE
;
1829 ConsoleIn
->ScrollLock
= FALSE
;
1830 ConsoleIn
->LeftShift
= FALSE
;
1831 ConsoleIn
->RightShift
= FALSE
;
1832 ConsoleIn
->LeftLogo
= FALSE
;
1833 ConsoleIn
->RightLogo
= FALSE
;
1834 ConsoleIn
->Menu
= FALSE
;
1835 ConsoleIn
->SysReq
= FALSE
;
1838 // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1839 // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected
1840 // to system. So we only do the real reseting for keyboard when user asks and there is a real KB connected t system,
1841 // and normally during booting an OS, it's skipped.
1843 if (ExtendedVerification
&& CheckKeyboardConnect (ConsoleIn
)) {
1845 // Additional verifications for keyboard interface
1848 // Keyboard Interface Test
1850 Status
= KeyboardCommand (ConsoleIn
, 0xab);
1851 if (EFI_ERROR (Status
)) {
1852 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1856 Status
= KeyboardWaitForValue (ConsoleIn
, 0x00);
1857 if (EFI_ERROR (Status
)) {
1860 L
"Some specific value not aquired from 8042 controller!\n\r"
1865 // Keyboard reset with a BAT(Basic Assurance Test)
1867 Status
= KeyboardWrite (ConsoleIn
, 0xff);
1868 if (EFI_ERROR (Status
)) {
1869 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1873 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1874 if (EFI_ERROR (Status
)) {
1875 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1879 // wait for BAT completion code
1881 mWaitForValueTimeOut
= KEYBOARD_BAT_TIMEOUT
;
1883 Status
= KeyboardWaitForValue (ConsoleIn
, 0xaa);
1884 if (EFI_ERROR (Status
)) {
1885 KeyboardError (ConsoleIn
, L
"Keyboard self test failed!\n\r");
1889 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1892 // Set Keyboard to use Scan Code Set 2
1894 Status
= KeyboardWrite (ConsoleIn
, 0xf0);
1895 if (EFI_ERROR (Status
)) {
1896 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1900 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1901 if (EFI_ERROR (Status
)) {
1902 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1906 Status
= KeyboardWrite (ConsoleIn
, 0x02);
1907 if (EFI_ERROR (Status
)) {
1908 KeyboardError (ConsoleIn
, L
"8042 controller data write error!!\n\r");
1912 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1913 if (EFI_ERROR (Status
)) {
1914 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1919 // Clear Keyboard Scancode Buffer
1921 Status
= KeyboardWrite (ConsoleIn
, 0xf4);
1922 if (EFI_ERROR (Status
)) {
1923 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1927 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1928 if (EFI_ERROR (Status
)) {
1929 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1933 if (Ps2Policy
!= NULL
) {
1934 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_CAPSLOCK
) == EFI_KEYBOARD_CAPSLOCK
) {
1935 ConsoleIn
->CapsLock
= TRUE
;
1938 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_NUMLOCK
) == EFI_KEYBOARD_NUMLOCK
) {
1939 ConsoleIn
->NumLock
= TRUE
;
1942 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_SCROLLLOCK
) == EFI_KEYBOARD_SCROLLLOCK
) {
1943 ConsoleIn
->ScrollLock
= TRUE
;
1947 // Update Keyboard Lights
1949 Status
= UpdateStatusLights (ConsoleIn
);
1950 if (EFI_ERROR (Status
)) {
1951 KeyboardError (ConsoleIn
, L
"Update keyboard status lights error!\n\r");
1956 // At last, we can now enable the mouse interface if appropriate
1960 if (EnableMouseInterface
) {
1962 // Enable mouse interface
1964 Status1
= KeyboardCommand (ConsoleIn
, 0xa8);
1965 if (EFI_ERROR (Status1
)) {
1966 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1967 return EFI_DEVICE_ERROR
;
1971 if (!EFI_ERROR (Status
)) {
1974 return EFI_DEVICE_ERROR
;
1980 Disable the keyboard interface of the 8042 controller
1982 @param ConsoleIn - the device instance
1984 @return status of issuing disable command
1989 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1995 // Disable keyboard interface
1997 Status
= KeyboardCommand (ConsoleIn
, 0xad);
1998 if (EFI_ERROR (Status
)) {
1999 KeyboardError (ConsoleIn
, L
"\n\r");
2000 return EFI_DEVICE_ERROR
;
2007 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
2008 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
2009 should not be in system.
2011 @param[in] BiosKeyboardPrivate Keyboard Private Data Structure
2013 @retval TRUE Keyboard in System.
2014 @retval FALSE Keyboard not in System.
2018 CheckKeyboardConnect (
2019 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
2023 UINTN WaitForValueTimeOutBcakup
;
2025 Status
= EFI_SUCCESS
;
2027 // enable keyboard itself and wait for its ack
2028 // If can't receive ack, Keyboard should not be connected.
2030 Status
= KeyboardWrite (
2035 if (EFI_ERROR (Status
)) {
2041 WaitForValueTimeOutBcakup
= mWaitForValueTimeOut
;
2042 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
2043 Status
= KeyboardWaitForValue (
2045 KEYBOARD_CMDECHO_ACK
2047 mWaitForValueTimeOut
= WaitForValueTimeOutBcakup
;
2049 if (EFI_ERROR (Status
)) {