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"
19 // Function declarations
24 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
29 KeyWriteDataRegister (
30 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
36 KeyWriteCommandRegister (
37 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
44 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
45 IN CHAR16
*ErrMsg
// should be a unicode string
51 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
59 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
67 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
74 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
80 KeyboardWaitForValue (
81 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
89 CHAR16 ShiftUnicodeChar
;
91 ConvertKeyboardScanCodeToEfiKey
[] = {
418 0x37, // Numeric Keypad *
424 0x38, //Left Alt/Extended Right Alt
544 0x4c, // Numeric Keypad 5
631 // The WaitForValue time out
633 STATIC UINTN mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
638 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
640 @return return the value
645 KeyReadDataRegister (
646 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
650 EFI_ISA_IO_PROTOCOL
*IsaIo
;
654 // Use IsaIo protocol to perform IO operations
656 IsaIo
= ConsoleIn
->IsaIo
;
661 ConsoleIn
->DataRegisterAddress
,
672 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
673 @param Data value wanted to be written
678 KeyWriteDataRegister (
679 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
684 EFI_ISA_IO_PROTOCOL
*IsaIo
;
687 // Use IsaIo protocol to perform IO operations
689 IsaIo
= ConsoleIn
->IsaIo
;
694 ConsoleIn
->DataRegisterAddress
,
700 // outp(ConsoleIn->DataRegisterAddress, Data);
707 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
709 @return value in status register
713 KeyReadStatusRegister (
714 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
717 EFI_ISA_IO_PROTOCOL
*IsaIo
;
721 // Use IsaIo protocol to perform IO operations
723 IsaIo
= ConsoleIn
->IsaIo
;
728 ConsoleIn
->StatusRegisterAddress
,
738 Write command register
740 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
741 @param Data The value wanted to be written
747 KeyWriteCommandRegister (
748 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
752 EFI_ISA_IO_PROTOCOL
*IsaIo
;
755 // Use IsaIo protocol to perform IO operations
757 IsaIo
= ConsoleIn
->IsaIo
;
762 ConsoleIn
->CommandRegisterAddress
,
770 Display error message
772 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
773 @param ErrMsg Unicode string of error message
779 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
783 ConsoleIn
->KeyboardErr
= TRUE
;
786 // gST -> ConOut -> OutputString (gST -> ConOut, L"Keyboard Driver: ");
787 // gST -> ConOut -> OutputString (gST -> ConOut, ErrMsg);
792 Timer event handler: read a series of scancodes from 8042
793 and put them into memory scancode buffer.
794 it read as much scancodes to either fill
795 the memory buffer or empty the keyboard buffer.
796 It is registered as running under TPL_NOTIFY
798 @param Event - The timer event
799 @param Context - A KEYBOARD_CONSOLE_IN_DEV pointer
804 KeyboardTimerHandler (
812 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
817 // Enter critical section
819 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
821 if (((KEYBOARD_CONSOLE_IN_DEV
*) Context
)->KeyboardErr
) {
823 // Leave critical section and return
825 gBS
->RestoreTPL (OldTpl
);
829 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
830 // KB is not connected to system. If KB is not connected to system, driver will find there's something
831 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
832 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
833 // Just skip the 'resend' process simply.
839 // if there is no key present, just return
841 if ((KeyReadStatusRegister (Context
) & 0x21) != 0x1) {
843 // Leave critical section and return
845 gBS
->RestoreTPL (OldTpl
);
850 // Read one byte of the scan code and store it into the memory buffer
852 if (ConsoleIn
->ScancodeBufCount
< KEYBOARD_BUFFER_MAX_COUNT
) {
854 Data
= KeyReadDataRegister (Context
);
856 // put the scancode into the memory scancode buffer
858 ConsoleIn
->ScancodeBufCount
++;
859 ConsoleIn
->ScancodeBufEndPos
++;
860 if (ConsoleIn
->ScancodeBufEndPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
861 ConsoleIn
->ScancodeBufEndPos
= 0;
864 ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufEndPos
] = Data
;
867 // Handle Alt+Ctrl+Del Key combination
870 case SCANCODE_CTRL_MAKE
:
871 ConsoleIn
->Ctrled
= TRUE
;
874 case SCANCODE_CTRL_BREAK
:
875 ConsoleIn
->Ctrled
= FALSE
;
878 case SCANCODE_ALT_MAKE
:
879 ConsoleIn
->Alted
= TRUE
;
882 case SCANCODE_ALT_BREAK
:
883 ConsoleIn
->Alted
= FALSE
;
887 // if Alt+Ctrl+Del, Reboot the System
889 if (ConsoleIn
->Ctrled
&& ConsoleIn
->Alted
&& Data
== 0x53) {
890 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
894 // Leave critical section and return
896 gBS
->RestoreTPL (OldTpl
);
902 Read several bytes from the scancode buffer without removing them.
903 This function is called to see if there are enough bytes of scancode
904 representing a single key.
906 @param Count - Number of bytes to be read
907 @param Buf - Store the results
909 @retval EFI_SUCCESS success to scan the keyboard code
910 @retval EFI_NOT_READY invalid parameter
915 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
927 // check the valid range of parameter 'Count'
929 if (Count
<= 0 || ConsoleIn
->ScancodeBufCount
< Count
) {
930 return EFI_NOT_READY
;
933 // retrieve the values
935 for (Index
= 0; Index
< Count
; Index
++) {
939 Pos
= ConsoleIn
->ScancodeBufStartPos
;
943 if (Pos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
948 Buf
[Index
] = ConsoleIn
->ScancodeBuf
[Pos
];
956 Read & remove several bytes from the scancode buffer.
957 This function is usually called after GetScancodeBufHead()
959 @param Count - Number of bytes to be read
960 @param Buf - Store the results
962 @retval EFI_SUCCESS success to scan the keyboard code
963 @retval EFI_NOT_READY invalid parameter
968 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
978 // Check the valid range of parameter 'Count'
980 if (Count
<= 0 || ConsoleIn
->ScancodeBufCount
< Count
) {
981 return EFI_NOT_READY
;
984 // Retrieve and remove the values
986 for (Index
= 0; Index
< Count
; Index
++) {
990 ConsoleIn
->ScancodeBufStartPos
++;
991 if (ConsoleIn
->ScancodeBufStartPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
992 ConsoleIn
->ScancodeBufStartPos
= 0;
996 Buf
[Index
] = ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufStartPos
];
997 ConsoleIn
->ScancodeBufCount
--;
1000 ConsoleIn
->ScancodeBufStartPos
++;
1001 if (ConsoleIn
->ScancodeBufStartPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
1002 ConsoleIn
->ScancodeBufStartPos
= 0;
1011 @param ConsoleIn - Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1012 @param Data - Pointer to outof buffer for keeping key value
1014 @retval EFI_TIMEOUT Status resigter time out
1015 @retval EFI_SUCCESS Success to read keyboard
1020 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1032 // wait till output buffer full then perform the read
1034 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1035 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1037 *Data
= KeyReadDataRegister (ConsoleIn
);
1052 write key to keyboard
1054 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1055 @param Data value wanted to be written
1057 @retval EFI_TIMEOUT - GC_TODO: Add description for return value
1058 @retval EFI_SUCCESS - GC_TODO: Add description for return value
1064 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1075 // wait for input buffer empty
1077 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1078 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x02)) {
1092 KeyWriteDataRegister (ConsoleIn
, Data
);
1098 Issue keyboard command
1100 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1101 @param Data The buff holding the command
1103 @retval EFI_TIMEOUT Keyboard is not ready to issuing
1104 @retval EFI_SUCCESS Success to issue keyboard command
1110 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1121 // Wait For Input Buffer Empty
1123 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1124 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x02)) {
1136 // issue the command
1138 KeyWriteCommandRegister (ConsoleIn
, Data
);
1141 // Wait For Input Buffer Empty again
1144 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1145 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x02)) {
1161 wait for a specific value to be presented on
1162 8042 Data register by keyboard and then read it,
1163 used in keyboard commands ack
1165 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1166 @param Value the value wanted to be waited.
1168 @retval EFI_TIMEOUT Fail to get specific value in given time
1169 @retval EFI_SUCCESS Success to get specific value in given time.
1174 KeyboardWaitForValue (
1175 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1189 // Make sure the initial value of 'Data' is different from 'Value'
1192 if (Data
== Value
) {
1196 // Read from 8042 (multiple times if needed)
1197 // until the expected value appears
1198 // use SumTimeOut to control the iteration
1204 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1205 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1206 Data
= KeyReadDataRegister (ConsoleIn
);
1213 SumTimeOut
+= TimeOut
;
1215 if (Data
== Value
) {
1220 if (SumTimeOut
>= mWaitForValueTimeOut
) {
1236 Show keyboard status lights according to
1237 indicators in ConsoleIn.
1239 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1245 UpdateStatusLights (
1246 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1253 // Send keyboard command
1255 Status
= KeyboardWrite (ConsoleIn
, 0xed);
1256 if (EFI_ERROR (Status
)) {
1260 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1263 // Light configuration
1266 if (ConsoleIn
->CapsLock
) {
1270 if (ConsoleIn
->NumLock
) {
1274 if (ConsoleIn
->ScrollLock
) {
1278 Status
= KeyboardWrite (ConsoleIn
, Command
);
1280 if (EFI_ERROR (Status
)) {
1284 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1289 Get scancode from scancode buffer
1290 and translate into EFI-scancode and unicode defined by EFI spec
1291 The function is always called in TPL_NOTIFY
1293 @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer
1295 @retval EFI_NOT_READY - Input from console not ready yet.
1296 @retval EFI_SUCCESS - Function executed successfully.
1301 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1308 UINT8 ScancodeArr
[4];
1313 UINT32 ScancodeArrPos
;
1315 // point to the current position in ScancodeArr
1323 // Read one byte of the scan code and store it into the memory buffer
1324 // This block of code is added to insert an action that is equivalent to
1325 // the timer event handling function, so as to increase the frequency of
1326 // detecting the availability of keys. Timer event has a max frequency of
1327 // 18Hz which is insufficient
1330 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
1331 // KB is not connected to system. If KB is not connected to system, driver will find there's something
1332 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
1333 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
1334 // Just skip the 'resend' process simply.
1338 if (((KeyReadStatusRegister (ConsoleIn
) & 0x21) == 0x1) && (ConsoleIn
->ScancodeBufCount
< KEYBOARD_BUFFER_MAX_COUNT
)) {
1340 Readed
= KeyReadDataRegister (ConsoleIn
);
1342 // put the scancode into the memory scancode buffer
1344 ConsoleIn
->ScancodeBufCount
++;
1345 ConsoleIn
->ScancodeBufEndPos
++;
1346 if (ConsoleIn
->ScancodeBufEndPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
1347 ConsoleIn
->ScancodeBufEndPos
= 0;
1350 ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufEndPos
] = Readed
;
1353 // Handle Alt+Ctrl+Del Key combination
1357 case SCANCODE_CTRL_MAKE
:
1358 ConsoleIn
->Ctrled
= TRUE
;
1361 case SCANCODE_CTRL_BREAK
:
1362 ConsoleIn
->Ctrled
= FALSE
;
1365 case SCANCODE_ALT_MAKE
:
1366 ConsoleIn
->Alted
= TRUE
;
1369 case SCANCODE_ALT_BREAK
:
1370 ConsoleIn
->Alted
= FALSE
;
1374 // if Alt+Ctrl+Del, Reboot the System
1376 if (ConsoleIn
->Ctrled
&& ConsoleIn
->Alted
&& Readed
== 0x53) {
1377 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1381 // Check if there are enough bytes of scancode representing a single key
1382 // available in the buffer
1386 Status
= GetScancodeBufHead (ConsoleIn
, 1, ScancodeArr
);
1388 if (EFI_ERROR (Status
)) {
1389 return EFI_NOT_READY
;
1392 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED
) {
1394 Status
= GetScancodeBufHead (ConsoleIn
, 2, ScancodeArr
);
1396 if (EFI_ERROR (Status
)) {
1397 return EFI_NOT_READY
;
1401 // Checks for key scancode for PAUSE:E1-1D/45-E1/9D-C5
1402 // if present, ignore them
1404 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED1
) {
1406 Status
= GetScancodeBufHead (ConsoleIn
, 2, ScancodeArr
);
1409 if (EFI_ERROR (Status
)) {
1410 return EFI_NOT_READY
;
1413 Status
= GetScancodeBufHead (ConsoleIn
, 3, ScancodeArr
);
1416 if (EFI_ERROR (Status
)) {
1417 return EFI_NOT_READY
;
1420 PopScancodeBufHead (ConsoleIn
, 3, ScancodeArr
);
1421 return EFI_NOT_READY
;
1424 // if we reach this position, scancodes for a key is in buffer now,pop them
1426 Status
= PopScancodeBufHead (ConsoleIn
, ScancodeArrPos
+ 1, ScancodeArr
);
1427 if (EFI_ERROR (Status
)) {
1428 return EFI_NOT_READY
;
1431 // store the last available byte, this byte of scancode will be checked
1433 ScanCode
= ScancodeArr
[ScancodeArrPos
];
1436 // Check for special keys and update the driver state.
1440 case SCANCODE_CTRL_MAKE
:
1441 ConsoleIn
->Ctrl
= TRUE
;
1444 case SCANCODE_CTRL_BREAK
:
1445 ConsoleIn
->Ctrl
= FALSE
;
1448 case SCANCODE_ALT_MAKE
:
1449 ConsoleIn
->Alt
= TRUE
;
1452 case SCANCODE_ALT_BREAK
:
1453 ConsoleIn
->Alt
= FALSE
;
1456 case SCANCODE_LEFT_SHIFT_MAKE
:
1458 ConsoleIn
->Shift
= TRUE
;
1459 ConsoleIn
->LeftShift
= TRUE
;
1462 case SCANCODE_RIGHT_SHIFT_MAKE
:
1464 ConsoleIn
->Shift
= TRUE
;
1465 ConsoleIn
->RightShift
= TRUE
;
1469 case SCANCODE_LEFT_SHIFT_BREAK
:
1471 ConsoleIn
->Shift
= FALSE
;
1472 ConsoleIn
->LeftShift
= FALSE
;
1474 ConsoleIn
->SysReq
= FALSE
;
1477 case SCANCODE_RIGHT_SHIFT_BREAK
:
1479 ConsoleIn
->Shift
= FALSE
;
1480 ConsoleIn
->RightShift
= FALSE
;
1484 case SCANCODE_LEFT_LOGO_MAKE
:
1485 ConsoleIn
->LeftLogo
= TRUE
;
1487 case SCANCODE_LEFT_LOGO_BREAK
:
1488 ConsoleIn
->LeftLogo
= FALSE
;
1490 case SCANCODE_RIGHT_LOGO_MAKE
:
1491 ConsoleIn
->RightLogo
= TRUE
;
1493 case SCANCODE_RIGHT_LOGO_BREAK
:
1494 ConsoleIn
->RightLogo
= FALSE
;
1496 case SCANCODE_MENU_MAKE
:
1497 ConsoleIn
->Menu
= TRUE
;
1499 case SCANCODE_MENU_BREAK
:
1500 ConsoleIn
->Menu
= FALSE
;
1502 case SCANCODE_SYS_REQ_MAKE
:
1504 ConsoleIn
->SysReq
= TRUE
;
1506 case SCANCODE_CAPS_LOCK_MAKE
:
1507 ConsoleIn
->CapsLock
= (BOOLEAN
)!ConsoleIn
->CapsLock
;
1508 UpdateStatusLights (ConsoleIn
);
1511 case SCANCODE_NUM_LOCK_MAKE
:
1512 ConsoleIn
->NumLock
= (BOOLEAN
)!ConsoleIn
->NumLock
;
1513 UpdateStatusLights (ConsoleIn
);
1516 case SCANCODE_SCROLL_LOCK_MAKE
:
1517 ConsoleIn
->ScrollLock
= (BOOLEAN
)!ConsoleIn
->ScrollLock
;
1518 UpdateStatusLights (ConsoleIn
);
1522 // If this is a BREAK Key or above the valid range, ignore it
1524 if (ScanCode
>= SCANCODE_MAX_MAKE
) {
1531 // Treat Numeric Key Pad "/" specially
1533 if (Extended
&& ScanCode
== 0x35) {
1534 ConsoleIn
->Key
.ScanCode
= SCAN_NULL
;
1535 ConsoleIn
->Key
.UnicodeChar
= '/';
1539 // Convert Keyboard ScanCode into an EFI Key
1541 for (Index
= 0; ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
!= TABLE_END
; Index
+= 1) {
1542 if (ScanCode
== ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
) {
1543 ConsoleIn
->Key
.ScanCode
= ConvertKeyboardScanCodeToEfiKey
[Index
].EfiScanCode
;
1544 if (ConsoleIn
->Shift
) {
1545 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1547 // Need not return associated shift state if a class of printable characters that
1548 // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
1550 if (ConsoleIn
->Key
.UnicodeChar
>= 'A' && ConsoleIn
->Key
.UnicodeChar
<= 'Z') {
1551 ConsoleIn
->LeftShift
= FALSE
;
1552 ConsoleIn
->RightShift
= FALSE
;
1555 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1558 // alphabetic key is affected by CapsLock State
1560 if (ConsoleIn
->CapsLock
) {
1561 if (ConsoleIn
->Key
.UnicodeChar
>= 'a' && ConsoleIn
->Key
.UnicodeChar
<= 'z') {
1562 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1563 } else if (ConsoleIn
->Key
.UnicodeChar
>= 'A' && ConsoleIn
->Key
.UnicodeChar
<= 'Z') {
1564 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1568 // Translate the CTRL-Alpha characters to their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
1570 if (ConsoleIn
->Ctrled
) {
1571 if (ConsoleIn
->Key
.UnicodeChar
>= 'a' && ConsoleIn
->Key
.UnicodeChar
<= 'z') {
1572 ConsoleIn
->Key
.UnicodeChar
= (UINT16
) (ConsoleIn
->Key
.UnicodeChar
- 'a' + 1);
1573 } else if (ConsoleIn
->Key
.UnicodeChar
>= 'A' && ConsoleIn
->Key
.UnicodeChar
<= 'Z') {
1574 ConsoleIn
->Key
.UnicodeChar
= (UINT16
) (ConsoleIn
->Key
.UnicodeChar
- 'A' + 1);
1583 // distinguish numeric key pad keys' 'up symbol' and 'down symbol'
1585 if (ScanCode
>= 0x47 && ScanCode
<= 0x53) {
1587 if (ConsoleIn
->NumLock
&& !ConsoleIn
->Shift
&& !Extended
) {
1588 ConsoleIn
->Key
.ScanCode
= SCAN_NULL
;
1589 } else if (ScanCode
!= 0x4a && ScanCode
!= 0x4e) {
1590 ConsoleIn
->Key
.UnicodeChar
= 0x00;
1594 // If the key can not be converted then just return.
1596 if (ConsoleIn
->Key
.ScanCode
== SCAN_NULL
&& ConsoleIn
->Key
.UnicodeChar
== 0x00) {
1597 return EFI_NOT_READY
;
1601 // Save the Shift/Toggle state
1603 if (ConsoleIn
->Ctrl
) {
1604 ConsoleIn
->KeyState
.KeyShiftState
|= (Extended
== TRUE
) ? EFI_RIGHT_CONTROL_PRESSED
: EFI_LEFT_CONTROL_PRESSED
;
1606 if (ConsoleIn
->Alt
) {
1607 ConsoleIn
->KeyState
.KeyShiftState
|= (Extended
== TRUE
) ? EFI_RIGHT_ALT_PRESSED
: EFI_LEFT_ALT_PRESSED
;
1609 if (ConsoleIn
->LeftShift
) {
1610 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_LEFT_SHIFT_PRESSED
;
1612 if (ConsoleIn
->RightShift
) {
1613 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_RIGHT_SHIFT_PRESSED
;
1615 if (ConsoleIn
->LeftLogo
) {
1616 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_LEFT_LOGO_PRESSED
;
1618 if (ConsoleIn
->RightLogo
) {
1619 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_RIGHT_LOGO_PRESSED
;
1621 if (ConsoleIn
->Menu
) {
1622 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_MENU_KEY_PRESSED
;
1624 if (ConsoleIn
->SysReq
) {
1625 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_SYS_REQ_PRESSED
;
1627 if (ConsoleIn
->CapsLock
) {
1628 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_CAPS_LOCK_ACTIVE
;
1630 if (ConsoleIn
->NumLock
) {
1631 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_NUM_LOCK_ACTIVE
;
1633 if (ConsoleIn
->ScrollLock
) {
1634 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_SCROLL_LOCK_ACTIVE
;
1641 Perform 8042 controller and keyboard Initialization
1642 If ExtendedVerification is TRUE, do additional test for
1643 the keyboard interface
1645 @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
1646 @param ExtendedVerification - indicates a thorough initialization
1648 @retval EFI_DEVICE_ERROR Fail to init keyboard
1649 @retval EFI_SUCCESS Success to init keyboard
1653 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1654 IN BOOLEAN ExtendedVerification
1660 STATIC BOOLEAN EnableMouseInterface
;
1661 EFI_PS2_POLICY_PROTOCOL
*Ps2Policy
;
1663 Status
= EFI_SUCCESS
;
1664 EnableMouseInterface
= TRUE
;
1667 // Get Ps2 policy to set this
1669 Status
= gBS
->LocateProtocol (
1670 &gEfiPs2PolicyProtocolGuid
,
1672 (VOID
**) &Ps2Policy
1675 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1677 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
,
1678 ConsoleIn
->DevicePath
1682 // Perform a read to cleanup the Status Register's
1683 // output buffer full bits
1685 while (!EFI_ERROR (Status
)) {
1686 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1689 // We should disable mouse interface during the initialization process
1690 // since mouse device output could block keyboard device output in the
1691 // 60H port of 8042 controller.
1693 // So if we are not initializing 8042 controller for the
1694 // first time, we have to remember the previous mouse interface
1697 // Test the system flag in to determine whether this is the first
1698 // time initialization
1700 if ((KeyReadStatusRegister (ConsoleIn
) & 0x04)) {
1702 // 8042 controller is already setup (by myself or by mouse driver):
1703 // See whether mouse interface is already enabled
1704 // which determines whether we should enable it later
1707 // Read the command byte of 8042 controller
1709 Status
= KeyboardCommand (ConsoleIn
, 0x20);
1710 if (EFI_ERROR (Status
)) {
1711 KeyboardError (ConsoleIn
, L
"\n\r");
1715 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1716 if (EFI_ERROR (Status
)) {
1717 KeyboardError (ConsoleIn
, L
"\n\r");
1721 // Test the mouse enabling bit
1723 if (CommandByte
& 0x20) {
1724 EnableMouseInterface
= FALSE
;
1726 EnableMouseInterface
= TRUE
;
1731 // 8042 controller is not setup yet:
1732 // 8042 controller selftest;
1733 // Don't enable mouse interface later.
1736 // Disable keyboard and mouse interfaces
1738 Status
= KeyboardCommand (ConsoleIn
, 0xad);
1739 if (EFI_ERROR (Status
)) {
1740 KeyboardError (ConsoleIn
, L
"\n\r");
1744 Status
= KeyboardCommand (ConsoleIn
, 0xa7);
1745 if (EFI_ERROR (Status
)) {
1746 KeyboardError (ConsoleIn
, L
"\n\r");
1750 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1752 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
,
1753 ConsoleIn
->DevicePath
1756 // 8042 Controller Self Test
1758 Status
= KeyboardCommand (ConsoleIn
, 0xaa);
1759 if (EFI_ERROR (Status
)) {
1760 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1764 Status
= KeyboardWaitForValue (ConsoleIn
, 0x55);
1765 if (EFI_ERROR (Status
)) {
1766 KeyboardError (ConsoleIn
, L
"8042 controller self test failed!\n\r");
1770 // Don't enable mouse interface later
1772 EnableMouseInterface
= FALSE
;
1776 if (Ps2Policy
!= NULL
) {
1777 Ps2Policy
->Ps2InitHardware (ConsoleIn
->Handle
);
1780 // Write 8042 Command Byte, set System Flag
1781 // While at the same time:
1782 // 1. disable mouse interface,
1783 // 2. enable kbd interface,
1784 // 3. enable PC/XT kbd translation mode
1785 // 4. enable mouse and kbd interrupts
1787 // ( Command Byte bits:
1789 // 6: PC/XT translation mode
1790 // 5: Disable Auxiliary device interface
1791 // 4: Disable keyboard interface
1794 // 1: Enable Auxiliary device interrupt
1795 // 0: Enable Keyboard interrupt )
1797 Status
= KeyboardCommand (ConsoleIn
, 0x60);
1798 if (EFI_ERROR (Status
)) {
1799 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1803 Status
= KeyboardWrite (ConsoleIn
, 0x67);
1804 if (EFI_ERROR (Status
)) {
1805 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1810 // Clear Memory Scancode Buffer
1812 ConsoleIn
->ScancodeBufStartPos
= 0;
1813 ConsoleIn
->ScancodeBufEndPos
= KEYBOARD_BUFFER_MAX_COUNT
- 1;
1814 ConsoleIn
->ScancodeBufCount
= 0;
1815 ConsoleIn
->Ctrled
= FALSE
;
1816 ConsoleIn
->Alted
= FALSE
;
1819 // Reset the status indicators
1821 ConsoleIn
->Ctrl
= FALSE
;
1822 ConsoleIn
->Alt
= FALSE
;
1823 ConsoleIn
->Shift
= FALSE
;
1824 ConsoleIn
->CapsLock
= FALSE
;
1825 ConsoleIn
->NumLock
= FALSE
;
1826 ConsoleIn
->ScrollLock
= FALSE
;
1827 ConsoleIn
->LeftShift
= FALSE
;
1828 ConsoleIn
->RightShift
= FALSE
;
1829 ConsoleIn
->LeftLogo
= FALSE
;
1830 ConsoleIn
->RightLogo
= FALSE
;
1831 ConsoleIn
->Menu
= FALSE
;
1832 ConsoleIn
->SysReq
= FALSE
;
1835 // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1836 // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected
1837 // to system. So we only do the real reseting for keyboard when user asks and there is a real KB connected t system,
1838 // and normally during booting an OS, it's skipped.
1840 if (ExtendedVerification
&& CheckKeyboardConnect (ConsoleIn
)) {
1842 // Additional verifications for keyboard interface
1845 // Keyboard Interface Test
1847 Status
= KeyboardCommand (ConsoleIn
, 0xab);
1848 if (EFI_ERROR (Status
)) {
1849 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1853 Status
= KeyboardWaitForValue (ConsoleIn
, 0x00);
1854 if (EFI_ERROR (Status
)) {
1857 L
"Some specific value not aquired from 8042 controller!\n\r"
1862 // Keyboard reset with a BAT(Basic Assurance Test)
1864 Status
= KeyboardWrite (ConsoleIn
, 0xff);
1865 if (EFI_ERROR (Status
)) {
1866 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1870 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1871 if (EFI_ERROR (Status
)) {
1872 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1876 // wait for BAT completion code
1878 mWaitForValueTimeOut
= KEYBOARD_BAT_TIMEOUT
;
1880 Status
= KeyboardWaitForValue (ConsoleIn
, 0xaa);
1881 if (EFI_ERROR (Status
)) {
1882 KeyboardError (ConsoleIn
, L
"Keyboard self test failed!\n\r");
1886 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1889 // Set Keyboard to use Scan Code Set 2
1891 Status
= KeyboardWrite (ConsoleIn
, 0xf0);
1892 if (EFI_ERROR (Status
)) {
1893 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1897 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1898 if (EFI_ERROR (Status
)) {
1899 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1903 Status
= KeyboardWrite (ConsoleIn
, 0x02);
1904 if (EFI_ERROR (Status
)) {
1905 KeyboardError (ConsoleIn
, L
"8042 controller data write error!!\n\r");
1909 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1910 if (EFI_ERROR (Status
)) {
1911 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1916 // Clear Keyboard Scancode Buffer
1918 Status
= KeyboardWrite (ConsoleIn
, 0xf4);
1919 if (EFI_ERROR (Status
)) {
1920 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1924 Status
= KeyboardWaitForValue (ConsoleIn
, 0xfa);
1925 if (EFI_ERROR (Status
)) {
1926 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1930 if (Ps2Policy
!= NULL
) {
1931 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_CAPSLOCK
) == EFI_KEYBOARD_CAPSLOCK
) {
1932 ConsoleIn
->CapsLock
= TRUE
;
1935 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_NUMLOCK
) == EFI_KEYBOARD_NUMLOCK
) {
1936 ConsoleIn
->NumLock
= TRUE
;
1939 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_SCROLLLOCK
) == EFI_KEYBOARD_SCROLLLOCK
) {
1940 ConsoleIn
->ScrollLock
= TRUE
;
1944 // Update Keyboard Lights
1946 Status
= UpdateStatusLights (ConsoleIn
);
1947 if (EFI_ERROR (Status
)) {
1948 KeyboardError (ConsoleIn
, L
"Update keyboard status lights error!\n\r");
1953 // At last, we can now enable the mouse interface if appropriate
1957 if (EnableMouseInterface
) {
1959 // Enable mouse interface
1961 Status1
= KeyboardCommand (ConsoleIn
, 0xa8);
1962 if (EFI_ERROR (Status1
)) {
1963 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1964 return EFI_DEVICE_ERROR
;
1968 if (!EFI_ERROR (Status
)) {
1971 return EFI_DEVICE_ERROR
;
1977 Disable the keyboard interface of the 8042 controller
1979 @param ConsoleIn - the device instance
1981 @return status of issuing disable command
1986 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1992 // Disable keyboard interface
1994 Status
= KeyboardCommand (ConsoleIn
, 0xad);
1995 if (EFI_ERROR (Status
)) {
1996 KeyboardError (ConsoleIn
, L
"\n\r");
1997 return EFI_DEVICE_ERROR
;
2004 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
2005 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
2006 should not be in system.
2008 @param[in] ConsoleIn Keyboard Private Data Structure
2010 @retval TRUE Keyboard in System.
2011 @retval FALSE Keyboard not in System.
2015 CheckKeyboardConnect (
2016 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
2020 UINTN WaitForValueTimeOutBcakup
;
2022 Status
= EFI_SUCCESS
;
2024 // enable keyboard itself and wait for its ack
2025 // If can't receive ack, Keyboard should not be connected.
2027 Status
= KeyboardWrite (
2032 if (EFI_ERROR (Status
)) {
2038 WaitForValueTimeOutBcakup
= mWaitForValueTimeOut
;
2039 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
2040 Status
= KeyboardWaitForValue (
2042 KEYBOARD_CMDECHO_ACK
2044 mWaitForValueTimeOut
= WaitForValueTimeOutBcakup
;
2046 if (EFI_ERROR (Status
)) {