2 Routines that access 8042 keyboard controller
4 Copyright (c) 2006 - 2007, Intel Corporation
5 All rights reserved. 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
563 // The WaitForValue time out
565 UINTN mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
567 BOOLEAN mEnableMouseInterface
;
572 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
574 @return return the value
578 KeyReadDataRegister (
579 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
583 EFI_ISA_IO_PROTOCOL
*IsaIo
;
587 // Use IsaIo protocol to perform IO operations
589 IsaIo
= ConsoleIn
->IsaIo
;
594 ConsoleIn
->DataRegisterAddress
,
605 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
606 @param Data value wanted to be written
610 KeyWriteDataRegister (
611 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
616 EFI_ISA_IO_PROTOCOL
*IsaIo
;
619 // Use IsaIo protocol to perform IO operations
621 IsaIo
= ConsoleIn
->IsaIo
;
626 ConsoleIn
->DataRegisterAddress
,
634 Read status register.
636 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
638 @return value in status register
642 KeyReadStatusRegister (
643 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
646 EFI_ISA_IO_PROTOCOL
*IsaIo
;
650 // Use IsaIo protocol to perform IO operations
652 IsaIo
= ConsoleIn
->IsaIo
;
657 ConsoleIn
->StatusRegisterAddress
,
667 Write command register .
669 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
670 @param Data The value wanted to be written
674 KeyWriteCommandRegister (
675 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
679 EFI_ISA_IO_PROTOCOL
*IsaIo
;
682 // Use IsaIo protocol to perform IO operations
684 IsaIo
= ConsoleIn
->IsaIo
;
689 ConsoleIn
->CommandRegisterAddress
,
697 Display error message.
699 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
700 @param ErrMsg Unicode string of error message
705 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
709 ConsoleIn
->KeyboardErr
= TRUE
;
713 Timer event handler: read a series of scancodes from 8042
714 and put them into memory scancode buffer.
715 it read as much scancodes to either fill
716 the memory buffer or empty the keyboard buffer.
717 It is registered as running under TPL_NOTIFY
719 @param Event The timer event
720 @param Context A KEYBOARD_CONSOLE_IN_DEV pointer
725 KeyboardTimerHandler (
733 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
738 // Enter critical section
740 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
742 if (((KEYBOARD_CONSOLE_IN_DEV
*) Context
)->KeyboardErr
) {
744 // Leave critical section and return
746 gBS
->RestoreTPL (OldTpl
);
751 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
752 // KB is not connected to system. If KB is not connected to system, driver will find there's something
753 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
754 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
755 // Just skip the 'resend' process simply.
761 // if there is no key present, just return
763 if ((KeyReadStatusRegister (Context
) & (KEYBOARD_STATUS_REGISTER_TRANSMIT_TIMEOUT
|KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
)) != KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
) {
765 // Leave critical section and return
767 gBS
->RestoreTPL (OldTpl
);
772 // Read one byte of the scan code and store it into the memory buffer
774 if (ConsoleIn
->ScancodeBufCount
< KEYBOARD_BUFFER_MAX_COUNT
) {
776 Data
= KeyReadDataRegister (Context
);
778 // put the scancode into the memory scancode buffer
780 ConsoleIn
->ScancodeBufCount
++;
781 ConsoleIn
->ScancodeBufEndPos
++;
782 if (ConsoleIn
->ScancodeBufEndPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
783 ConsoleIn
->ScancodeBufEndPos
= 0;
786 ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufEndPos
] = Data
;
789 // Handle Alt+Ctrl+Del Key combination
792 case SCANCODE_CTRL_MAKE
:
793 ConsoleIn
->Ctrled
= TRUE
;
796 case SCANCODE_CTRL_BREAK
:
797 ConsoleIn
->Ctrled
= FALSE
;
800 case SCANCODE_ALT_MAKE
:
801 ConsoleIn
->Alted
= TRUE
;
804 case SCANCODE_ALT_BREAK
:
805 ConsoleIn
->Alted
= FALSE
;
809 // if Alt+Ctrl+Del, Reboot the System
811 if (ConsoleIn
->Ctrled
&& ConsoleIn
->Alted
&& Data
== 0x53) {
812 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
816 // Leave critical section and return
818 gBS
->RestoreTPL (OldTpl
);
824 Read several bytes from the scancode buffer without removing them.
825 This function is called to see if there are enough bytes of scancode
826 representing a single key.
828 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
829 @param Count Number of bytes to be read
830 @param Buf Store the results
832 @retval EFI_SUCCESS success to scan the keyboard code
833 @retval EFI_NOT_READY invalid parameter
837 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
849 // check the valid range of parameter 'Count'
851 if (Count
<= 0 || ConsoleIn
->ScancodeBufCount
< Count
) {
852 return EFI_NOT_READY
;
855 // retrieve the values
857 for (Index
= 0; Index
< Count
; Index
++) {
861 Pos
= ConsoleIn
->ScancodeBufStartPos
;
865 if (Pos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
870 Buf
[Index
] = ConsoleIn
->ScancodeBuf
[Pos
];
878 Read & remove several bytes from the scancode buffer.
879 This function is usually called after GetScancodeBufHead()
881 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
882 @param Count Number of bytes to be read
883 @param Buf Store the results
885 @retval EFI_SUCCESS success to scan the keyboard code
886 @retval EFI_NOT_READY invalid parameter
890 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
900 // Check the valid range of parameter 'Count'
902 if (Count
<= 0 || ConsoleIn
->ScancodeBufCount
< Count
) {
903 return EFI_NOT_READY
;
906 // Retrieve and remove the values
908 for (Index
= 0; Index
< Count
; Index
++) {
912 ConsoleIn
->ScancodeBufStartPos
++;
913 if (ConsoleIn
->ScancodeBufStartPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
914 ConsoleIn
->ScancodeBufStartPos
= 0;
918 Buf
[Index
] = ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufStartPos
];
919 ConsoleIn
->ScancodeBufCount
--;
922 ConsoleIn
->ScancodeBufStartPos
++;
923 if (ConsoleIn
->ScancodeBufStartPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
924 ConsoleIn
->ScancodeBufStartPos
= 0;
933 @param ConsoleIn - Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
934 @param Data - Pointer to outof buffer for keeping key value
936 @retval EFI_TIMEOUT Status resigter time out
937 @retval EFI_SUCCESS Success to read keyboard
942 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
954 // wait till output buffer full then perform the read
956 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
957 if (KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
) {
959 *Data
= KeyReadDataRegister (ConsoleIn
);
963 MicroSecondDelay (30);
966 if (RegFilled
== 0) {
974 write key to keyboard
976 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
977 @param Data value wanted to be written
979 @retval EFI_TIMEOUT The input buffer register is full for putting new value util timeout
980 @retval EFI_SUCCESS The new value is sucess put into input buffer register.
985 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
996 // wait for input buffer empty
998 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
999 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
1004 MicroSecondDelay (30);
1007 if (RegEmptied
== 0) {
1013 KeyWriteDataRegister (ConsoleIn
, Data
);
1019 Issue keyboard command.
1021 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1022 @param Data The buff holding the command
1024 @retval EFI_TIMEOUT Keyboard is not ready to issuing
1025 @retval EFI_SUCCESS Success to issue keyboard command
1030 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1041 // Wait For Input Buffer Empty
1043 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1044 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
1049 MicroSecondDelay (30);
1052 if (RegEmptied
== 0) {
1056 // issue the command
1058 KeyWriteCommandRegister (ConsoleIn
, Data
);
1061 // Wait For Input Buffer Empty again
1064 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1065 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
1070 MicroSecondDelay (30);
1073 if (RegEmptied
== 0) {
1081 wait for a specific value to be presented on
1082 8042 Data register by keyboard and then read it,
1083 used in keyboard commands ack
1085 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1086 @param Value the value wanted to be waited.
1088 @retval EFI_TIMEOUT Fail to get specific value in given time
1089 @retval EFI_SUCCESS Success to get specific value in given time.
1093 KeyboardWaitForValue (
1094 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1108 // Make sure the initial value of 'Data' is different from 'Value'
1111 if (Data
== Value
) {
1115 // Read from 8042 (multiple times if needed)
1116 // until the expected value appears
1117 // use SumTimeOut to control the iteration
1123 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1124 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1125 Data
= KeyReadDataRegister (ConsoleIn
);
1129 MicroSecondDelay (30);
1132 SumTimeOut
+= TimeOut
;
1134 if (Data
== Value
) {
1139 if (SumTimeOut
>= mWaitForValueTimeOut
) {
1155 Show keyboard status lights according to
1156 indicators in ConsoleIn.
1158 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1160 @return status of updating keyboard register
1164 UpdateStatusLights (
1165 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1172 // Send keyboard command
1174 Status
= KeyboardWrite (ConsoleIn
, 0xed);
1175 if (EFI_ERROR (Status
)) {
1179 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1182 // Light configuration
1185 if (ConsoleIn
->CapsLock
) {
1189 if (ConsoleIn
->NumLock
) {
1193 if (ConsoleIn
->ScrollLock
) {
1197 Status
= KeyboardWrite (ConsoleIn
, Command
);
1199 if (EFI_ERROR (Status
)) {
1203 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1208 Get scancode from scancode buffer
1209 and translate into EFI-scancode and unicode defined by EFI spec
1210 The function is always called in TPL_NOTIFY
1212 @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer
1214 @retval EFI_NOT_READY Input from console not ready yet.
1215 @retval EFI_SUCCESS Function executed successfully.
1220 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1227 UINT8 ScancodeArr
[4];
1232 UINT32 ScancodeArrPos
;
1234 // point to the current position in ScancodeArr
1242 // Read one byte of the scan code and store it into the memory buffer
1243 // This block of code is added to insert an action that is equivalent to
1244 // the timer event handling function, so as to increase the frequency of
1245 // detecting the availability of keys. Timer event has a max frequency of
1246 // 18Hz which is insufficient
1249 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
1250 // KB is not connected to system. If KB is not connected to system, driver will find there's something
1251 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
1252 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
1253 // Just skip the 'resend' process simply.
1257 if (((KeyReadStatusRegister (ConsoleIn
) & 0x21) == 0x1) && (ConsoleIn
->ScancodeBufCount
< KEYBOARD_BUFFER_MAX_COUNT
)) {
1259 Readed
= KeyReadDataRegister (ConsoleIn
);
1261 // put the scancode into the memory scancode buffer
1263 ConsoleIn
->ScancodeBufCount
++;
1264 ConsoleIn
->ScancodeBufEndPos
++;
1265 if (ConsoleIn
->ScancodeBufEndPos
>= KEYBOARD_BUFFER_MAX_COUNT
) {
1266 ConsoleIn
->ScancodeBufEndPos
= 0;
1269 ConsoleIn
->ScancodeBuf
[ConsoleIn
->ScancodeBufEndPos
] = Readed
;
1272 // Handle Alt+Ctrl+Del Key combination
1276 case SCANCODE_CTRL_MAKE
:
1277 ConsoleIn
->Ctrled
= TRUE
;
1280 case SCANCODE_CTRL_BREAK
:
1281 ConsoleIn
->Ctrled
= FALSE
;
1284 case SCANCODE_ALT_MAKE
:
1285 ConsoleIn
->Alted
= TRUE
;
1288 case SCANCODE_ALT_BREAK
:
1289 ConsoleIn
->Alted
= FALSE
;
1293 // if Alt+Ctrl+Del, Reboot the System
1295 if (ConsoleIn
->Ctrled
&& ConsoleIn
->Alted
&& Readed
== 0x53) {
1296 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1300 // Check if there are enough bytes of scancode representing a single key
1301 // available in the buffer
1305 Status
= GetScancodeBufHead (ConsoleIn
, 1, ScancodeArr
);
1307 if (EFI_ERROR (Status
)) {
1308 return EFI_NOT_READY
;
1311 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED
) {
1313 Status
= GetScancodeBufHead (ConsoleIn
, 2, ScancodeArr
);
1315 if (EFI_ERROR (Status
)) {
1316 return EFI_NOT_READY
;
1320 // Checks for key scancode for PAUSE:E1-1D/45-E1/9D-C5
1321 // if present, ignore them
1323 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED1
) {
1325 Status
= GetScancodeBufHead (ConsoleIn
, 2, ScancodeArr
);
1328 if (EFI_ERROR (Status
)) {
1329 return EFI_NOT_READY
;
1332 Status
= GetScancodeBufHead (ConsoleIn
, 3, ScancodeArr
);
1335 if (EFI_ERROR (Status
)) {
1336 return EFI_NOT_READY
;
1339 PopScancodeBufHead (ConsoleIn
, 3, ScancodeArr
);
1340 return EFI_NOT_READY
;
1343 // if we reach this position, scancodes for a key is in buffer now,pop them
1345 Status
= PopScancodeBufHead (ConsoleIn
, ScancodeArrPos
+ 1, ScancodeArr
);
1346 if (EFI_ERROR (Status
)) {
1347 return EFI_NOT_READY
;
1350 // store the last available byte, this byte of scancode will be checked
1352 ScanCode
= ScancodeArr
[ScancodeArrPos
];
1355 // Check for special keys and update the driver state.
1359 case SCANCODE_CTRL_MAKE
:
1360 ConsoleIn
->Ctrl
= TRUE
;
1363 case SCANCODE_CTRL_BREAK
:
1364 ConsoleIn
->Ctrl
= FALSE
;
1367 case SCANCODE_ALT_MAKE
:
1368 ConsoleIn
->Alt
= TRUE
;
1371 case SCANCODE_ALT_BREAK
:
1372 ConsoleIn
->Alt
= FALSE
;
1375 case SCANCODE_LEFT_SHIFT_MAKE
:
1377 ConsoleIn
->Shift
= TRUE
;
1378 ConsoleIn
->LeftShift
= TRUE
;
1381 case SCANCODE_RIGHT_SHIFT_MAKE
:
1383 ConsoleIn
->Shift
= TRUE
;
1384 ConsoleIn
->RightShift
= TRUE
;
1388 case SCANCODE_LEFT_SHIFT_BREAK
:
1390 ConsoleIn
->Shift
= FALSE
;
1391 ConsoleIn
->LeftShift
= FALSE
;
1393 ConsoleIn
->SysReq
= FALSE
;
1396 case SCANCODE_RIGHT_SHIFT_BREAK
:
1398 ConsoleIn
->Shift
= FALSE
;
1399 ConsoleIn
->RightShift
= FALSE
;
1403 case SCANCODE_LEFT_LOGO_MAKE
:
1404 ConsoleIn
->LeftLogo
= TRUE
;
1406 case SCANCODE_LEFT_LOGO_BREAK
:
1407 ConsoleIn
->LeftLogo
= FALSE
;
1409 case SCANCODE_RIGHT_LOGO_MAKE
:
1410 ConsoleIn
->RightLogo
= TRUE
;
1412 case SCANCODE_RIGHT_LOGO_BREAK
:
1413 ConsoleIn
->RightLogo
= FALSE
;
1415 case SCANCODE_MENU_MAKE
:
1416 ConsoleIn
->Menu
= TRUE
;
1418 case SCANCODE_MENU_BREAK
:
1419 ConsoleIn
->Menu
= FALSE
;
1421 case SCANCODE_SYS_REQ_MAKE
:
1423 ConsoleIn
->SysReq
= TRUE
;
1425 case SCANCODE_CAPS_LOCK_MAKE
:
1426 ConsoleIn
->CapsLock
= (BOOLEAN
)!ConsoleIn
->CapsLock
;
1427 UpdateStatusLights (ConsoleIn
);
1430 case SCANCODE_NUM_LOCK_MAKE
:
1431 ConsoleIn
->NumLock
= (BOOLEAN
)!ConsoleIn
->NumLock
;
1432 UpdateStatusLights (ConsoleIn
);
1435 case SCANCODE_SCROLL_LOCK_MAKE
:
1436 ConsoleIn
->ScrollLock
= (BOOLEAN
)!ConsoleIn
->ScrollLock
;
1437 UpdateStatusLights (ConsoleIn
);
1441 // If this is a BREAK Key or above the valid range, ignore it
1443 if (ScanCode
>= SCANCODE_MAX_MAKE
) {
1450 // Treat Numeric Key Pad "/" specially
1452 if (Extended
&& ScanCode
== 0x35) {
1453 ConsoleIn
->Key
.ScanCode
= SCAN_NULL
;
1454 ConsoleIn
->Key
.UnicodeChar
= L
'/';
1458 // Convert Keyboard ScanCode into an EFI Key
1460 for (Index
= 0; ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
!= TABLE_END
; Index
+= 1) {
1461 if (ScanCode
== ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
) {
1462 ConsoleIn
->Key
.ScanCode
= ConvertKeyboardScanCodeToEfiKey
[Index
].EfiScanCode
;
1463 if (ConsoleIn
->Shift
) {
1464 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1466 // Need not return associated shift state if a class of printable characters that
1467 // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
1469 if (ConsoleIn
->Key
.UnicodeChar
>= L
'A' && ConsoleIn
->Key
.UnicodeChar
<= L
'Z') {
1470 ConsoleIn
->LeftShift
= FALSE
;
1471 ConsoleIn
->RightShift
= FALSE
;
1474 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1477 // alphabetic key is affected by CapsLock State
1479 if (ConsoleIn
->CapsLock
) {
1480 if (ConsoleIn
->Key
.UnicodeChar
>= L
'a' && ConsoleIn
->Key
.UnicodeChar
<= L
'z') {
1481 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1482 } else if (ConsoleIn
->Key
.UnicodeChar
>= L
'A' && ConsoleIn
->Key
.UnicodeChar
<= L
'Z') {
1483 ConsoleIn
->Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1487 // Translate the CTRL-Alpha characters to their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
1489 if (ConsoleIn
->Ctrled
) {
1490 if (ConsoleIn
->Key
.UnicodeChar
>= L
'a' && ConsoleIn
->Key
.UnicodeChar
<= L
'z') {
1491 ConsoleIn
->Key
.UnicodeChar
= (UINT16
) (ConsoleIn
->Key
.UnicodeChar
- L
'a' + 1);
1492 } else if (ConsoleIn
->Key
.UnicodeChar
>= L
'A' && ConsoleIn
->Key
.UnicodeChar
<= L
'Z') {
1493 ConsoleIn
->Key
.UnicodeChar
= (UINT16
) (ConsoleIn
->Key
.UnicodeChar
- L
'A' + 1);
1502 // distinguish numeric key pad keys' 'up symbol' and 'down symbol'
1504 if (ScanCode
>= 0x47 && ScanCode
<= 0x53) {
1506 if (ConsoleIn
->NumLock
&& !ConsoleIn
->Shift
&& !Extended
) {
1507 ConsoleIn
->Key
.ScanCode
= SCAN_NULL
;
1508 } else if (ScanCode
!= 0x4a && ScanCode
!= 0x4e) {
1509 ConsoleIn
->Key
.UnicodeChar
= 0x0000;
1513 // If the key can not be converted then just return.
1515 if (ConsoleIn
->Key
.ScanCode
== SCAN_NULL
&& ConsoleIn
->Key
.UnicodeChar
== 0x0000) {
1516 return EFI_NOT_READY
;
1520 // Save the Shift/Toggle state
1522 if (ConsoleIn
->Ctrl
) {
1523 ConsoleIn
->KeyState
.KeyShiftState
|= (Extended
) ? EFI_RIGHT_CONTROL_PRESSED
: EFI_LEFT_CONTROL_PRESSED
;
1525 if (ConsoleIn
->Alt
) {
1526 ConsoleIn
->KeyState
.KeyShiftState
|= (Extended
) ? EFI_RIGHT_ALT_PRESSED
: EFI_LEFT_ALT_PRESSED
;
1528 if (ConsoleIn
->LeftShift
) {
1529 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_LEFT_SHIFT_PRESSED
;
1531 if (ConsoleIn
->RightShift
) {
1532 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_RIGHT_SHIFT_PRESSED
;
1534 if (ConsoleIn
->LeftLogo
) {
1535 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_LEFT_LOGO_PRESSED
;
1537 if (ConsoleIn
->RightLogo
) {
1538 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_RIGHT_LOGO_PRESSED
;
1540 if (ConsoleIn
->Menu
) {
1541 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_MENU_KEY_PRESSED
;
1543 if (ConsoleIn
->SysReq
) {
1544 ConsoleIn
->KeyState
.KeyShiftState
|= EFI_SYS_REQ_PRESSED
;
1546 if (ConsoleIn
->CapsLock
) {
1547 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_CAPS_LOCK_ACTIVE
;
1549 if (ConsoleIn
->NumLock
) {
1550 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_NUM_LOCK_ACTIVE
;
1552 if (ConsoleIn
->ScrollLock
) {
1553 ConsoleIn
->KeyState
.KeyToggleState
|= EFI_SCROLL_LOCK_ACTIVE
;
1560 Perform 8042 controller and keyboard Initialization.
1561 If ExtendedVerification is TRUE, do additional test for
1562 the keyboard interface
1564 @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
1565 @param ExtendedVerification - indicates a thorough initialization
1567 @retval EFI_DEVICE_ERROR Fail to init keyboard
1568 @retval EFI_SUCCESS Success to init keyboard
1572 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1573 IN BOOLEAN ExtendedVerification
1579 EFI_PS2_POLICY_PROTOCOL
*Ps2Policy
;
1582 Status
= EFI_SUCCESS
;
1583 mEnableMouseInterface
= TRUE
;
1587 // Get Ps2 policy to set this
1589 gBS
->LocateProtocol (
1590 &gEfiPs2PolicyProtocolGuid
,
1592 (VOID
**) &Ps2Policy
1595 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1597 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
,
1598 ConsoleIn
->DevicePath
1602 // Perform a read to cleanup the Status Register's
1603 // output buffer full bits within MAX TRY times
1605 while (!EFI_ERROR (Status
) && TryTime
< KEYBOARD_MAX_TRY
) {
1606 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1610 // Exceed the max try times. The device may be error.
1612 if (TryTime
== KEYBOARD_MAX_TRY
) {
1613 Status
= EFI_DEVICE_ERROR
;
1617 // We should disable mouse interface during the initialization process
1618 // since mouse device output could block keyboard device output in the
1619 // 60H port of 8042 controller.
1621 // So if we are not initializing 8042 controller for the
1622 // first time, we have to remember the previous mouse interface
1625 // Test the system flag in to determine whether this is the first
1626 // time initialization
1628 if ((KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_SYSTEM_FLAG
) != 0) {
1630 // 8042 controller is already setup (by myself or by mouse driver):
1631 // See whether mouse interface is already enabled
1632 // which determines whether we should enable it later
1635 // Read the command byte of 8042 controller
1637 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_READ
);
1638 if (EFI_ERROR (Status
)) {
1639 KeyboardError (ConsoleIn
, L
"\n\r");
1643 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1644 if (EFI_ERROR (Status
)) {
1645 KeyboardError (ConsoleIn
, L
"\n\r");
1649 // Test the mouse enabling bit
1651 if ((CommandByte
& 0x20) != 0) {
1652 mEnableMouseInterface
= FALSE
;
1654 mEnableMouseInterface
= TRUE
;
1659 // 8042 controller is not setup yet:
1660 // 8042 controller selftest;
1661 // Don't enable mouse interface later.
1664 // Disable keyboard and mouse interfaces
1666 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1667 if (EFI_ERROR (Status
)) {
1668 KeyboardError (ConsoleIn
, L
"\n\r");
1672 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_MOUSE_INTERFACE
);
1673 if (EFI_ERROR (Status
)) {
1674 KeyboardError (ConsoleIn
, L
"\n\r");
1678 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1680 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
,
1681 ConsoleIn
->DevicePath
1684 // 8042 Controller Self Test
1686 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_CONTROLLER_SELF_TEST
);
1687 if (EFI_ERROR (Status
)) {
1688 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1692 Status
= KeyboardWaitForValue (ConsoleIn
, 0x55);
1693 if (EFI_ERROR (Status
)) {
1694 KeyboardError (ConsoleIn
, L
"8042 controller self test failed!\n\r");
1698 // Don't enable mouse interface later
1700 mEnableMouseInterface
= FALSE
;
1704 if (Ps2Policy
!= NULL
) {
1705 Ps2Policy
->Ps2InitHardware (ConsoleIn
->Handle
);
1708 // Write 8042 Command Byte, set System Flag
1709 // While at the same time:
1710 // 1. disable mouse interface,
1711 // 2. enable kbd interface,
1712 // 3. enable PC/XT kbd translation mode
1713 // 4. enable mouse and kbd interrupts
1715 // ( Command Byte bits:
1717 // 6: PC/XT translation mode
1718 // 5: Disable Auxiliary device interface
1719 // 4: Disable keyboard interface
1722 // 1: Enable Auxiliary device interrupt
1723 // 0: Enable Keyboard interrupt )
1725 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_WRITE
);
1726 if (EFI_ERROR (Status
)) {
1727 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1731 Status
= KeyboardWrite (ConsoleIn
, 0x67);
1732 if (EFI_ERROR (Status
)) {
1733 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1738 // Clear Memory Scancode Buffer
1740 ConsoleIn
->ScancodeBufStartPos
= 0;
1741 ConsoleIn
->ScancodeBufEndPos
= KEYBOARD_BUFFER_MAX_COUNT
- 1;
1742 ConsoleIn
->ScancodeBufCount
= 0;
1743 ConsoleIn
->Ctrled
= FALSE
;
1744 ConsoleIn
->Alted
= FALSE
;
1747 // Reset the status indicators
1749 ConsoleIn
->Ctrl
= FALSE
;
1750 ConsoleIn
->Alt
= FALSE
;
1751 ConsoleIn
->Shift
= FALSE
;
1752 ConsoleIn
->CapsLock
= FALSE
;
1753 ConsoleIn
->NumLock
= FALSE
;
1754 ConsoleIn
->ScrollLock
= FALSE
;
1755 ConsoleIn
->LeftShift
= FALSE
;
1756 ConsoleIn
->RightShift
= FALSE
;
1757 ConsoleIn
->LeftLogo
= FALSE
;
1758 ConsoleIn
->RightLogo
= FALSE
;
1759 ConsoleIn
->Menu
= FALSE
;
1760 ConsoleIn
->SysReq
= FALSE
;
1763 // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1764 // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected
1765 // to system. So we only do the real reseting for keyboard when user asks and there is a real KB connected t system,
1766 // and normally during booting an OS, it's skipped.
1768 if (ExtendedVerification
&& CheckKeyboardConnect (ConsoleIn
)) {
1770 // Additional verifications for keyboard interface
1773 // Keyboard Interface Test
1775 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_KEYBOARD_INTERFACE_SELF_TEST
);
1776 if (EFI_ERROR (Status
)) {
1777 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1781 Status
= KeyboardWaitForValue (ConsoleIn
, 0x00);
1782 if (EFI_ERROR (Status
)) {
1785 L
"Some specific value not aquired from 8042 controller!\n\r"
1790 // Keyboard reset with a BAT(Basic Assurance Test)
1792 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_RESET
);
1793 if (EFI_ERROR (Status
)) {
1794 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1798 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1799 if (EFI_ERROR (Status
)) {
1800 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1804 // wait for BAT completion code
1806 mWaitForValueTimeOut
= KEYBOARD_BAT_TIMEOUT
;
1808 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_BAT_SUCCESS
);
1809 if (EFI_ERROR (Status
)) {
1810 KeyboardError (ConsoleIn
, L
"Keyboard self test failed!\n\r");
1814 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1817 // Set Keyboard to use Scan Code Set 2
1819 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_SELECT_SCAN_CODE_SET
);
1820 if (EFI_ERROR (Status
)) {
1821 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1825 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1826 if (EFI_ERROR (Status
)) {
1827 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1831 Status
= KeyboardWrite (ConsoleIn
, 0x02);
1832 if (EFI_ERROR (Status
)) {
1833 KeyboardError (ConsoleIn
, L
"8042 controller data write error!!\n\r");
1837 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1838 if (EFI_ERROR (Status
)) {
1839 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1844 // Clear Keyboard Scancode Buffer
1846 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_CLEAR_OUTPUT_DATA
);
1847 if (EFI_ERROR (Status
)) {
1848 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1852 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1853 if (EFI_ERROR (Status
)) {
1854 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1858 if (Ps2Policy
!= NULL
) {
1859 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_CAPSLOCK
) == EFI_KEYBOARD_CAPSLOCK
) {
1860 ConsoleIn
->CapsLock
= TRUE
;
1863 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_NUMLOCK
) == EFI_KEYBOARD_NUMLOCK
) {
1864 ConsoleIn
->NumLock
= TRUE
;
1867 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_SCROLLLOCK
) == EFI_KEYBOARD_SCROLLLOCK
) {
1868 ConsoleIn
->ScrollLock
= TRUE
;
1872 // Update Keyboard Lights
1874 Status
= UpdateStatusLights (ConsoleIn
);
1875 if (EFI_ERROR (Status
)) {
1876 KeyboardError (ConsoleIn
, L
"Update keyboard status lights error!\n\r");
1881 // At last, we can now enable the mouse interface if appropriate
1885 if (mEnableMouseInterface
) {
1887 // Enable mouse interface
1889 Status1
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_ENABLE_MOUSE_INTERFACE
);
1890 if (EFI_ERROR (Status1
)) {
1891 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1892 return EFI_DEVICE_ERROR
;
1896 if (!EFI_ERROR (Status
)) {
1899 return EFI_DEVICE_ERROR
;
1905 Disable the keyboard interface of the 8042 controller.
1907 @param ConsoleIn The device instance
1909 @return status of issuing disable command
1914 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1920 // Disable keyboard interface
1922 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1923 if (EFI_ERROR (Status
)) {
1924 KeyboardError (ConsoleIn
, L
"\n\r");
1925 return EFI_DEVICE_ERROR
;
1932 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
1933 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
1934 should not be in system.
1936 @param[in] ConsoleIn Keyboard Private Data Structure
1938 @retval TRUE Keyboard in System.
1939 @retval FALSE Keyboard not in System.
1943 CheckKeyboardConnect (
1944 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1948 UINTN WaitForValueTimeOutBcakup
;
1950 Status
= EFI_SUCCESS
;
1952 // enable keyboard itself and wait for its ack
1953 // If can't receive ack, Keyboard should not be connected.
1955 Status
= KeyboardWrite (
1960 if (EFI_ERROR (Status
)) {
1966 WaitForValueTimeOutBcakup
= mWaitForValueTimeOut
;
1967 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1968 Status
= KeyboardWaitForValue (
1970 KEYBOARD_CMDECHO_ACK
1972 mWaitForValueTimeOut
= WaitForValueTimeOutBcakup
;
1974 if (EFI_ERROR (Status
)) {