2 Routines that access 8042 keyboard controller
4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "Ps2Keyboard.h"
18 UINT16 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
568 // The WaitForValue time out
570 UINTN mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
572 BOOLEAN mEnableMouseInterface
;
577 Return the count of scancode in the queue.
579 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
581 @return Count of the scancode.
584 GetScancodeBufCount (
585 IN SCAN_CODE_QUEUE
*Queue
588 if (Queue
->Head
<= Queue
->Tail
) {
589 return Queue
->Tail
- Queue
->Head
;
591 return Queue
->Tail
+ KEYBOARD_SCAN_CODE_MAX_COUNT
- Queue
->Head
;
596 Read several bytes from the scancode buffer without removing them.
597 This function is called to see if there are enough bytes of scancode
598 representing a single key.
600 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
601 @param Count Number of bytes to be read
602 @param Buf Store the results
604 @retval EFI_SUCCESS success to scan the keyboard code
605 @retval EFI_NOT_READY invalid parameter
609 IN SCAN_CODE_QUEUE
*Queue
,
618 // check the valid range of parameter 'Count'
620 if (GetScancodeBufCount (Queue
) < Count
) {
621 return EFI_NOT_READY
;
624 // retrieve the values
626 for (Index
= 0, Pos
= Queue
->Head
; Index
< Count
; Index
++, Pos
= (Pos
+ 1) % KEYBOARD_SCAN_CODE_MAX_COUNT
) {
627 Buf
[Index
] = Queue
->Buffer
[Pos
];
634 Push one byte to the scancode buffer.
636 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
637 @param Scancode The byte to push.
640 PushScancodeBufTail (
641 IN SCAN_CODE_QUEUE
*Queue
,
645 if (GetScancodeBufCount (Queue
) == KEYBOARD_SCAN_CODE_MAX_COUNT
- 1) {
649 Queue
->Buffer
[Queue
->Tail
] = Scancode
;
650 Queue
->Tail
= (Queue
->Tail
+ 1) % KEYBOARD_SCAN_CODE_MAX_COUNT
;
655 Read & remove several bytes from the scancode buffer.
656 This function is usually called after GetScancodeBufHead()
658 @param Queue Pointer to instance of SCAN_CODE_QUEUE.
659 @param Count Number of bytes to be read
660 @param Buf Store the results
662 @retval EFI_SUCCESS success to scan the keyboard code
663 @retval EFI_NOT_READY invalid parameter
667 IN SCAN_CODE_QUEUE
*Queue
,
675 // Check the valid range of parameter 'Count'
677 if (GetScancodeBufCount (Queue
) < Count
) {
678 return EFI_NOT_READY
;
681 // Retrieve and remove the values
683 for (Index
= 0; Index
< Count
; Index
++, Queue
->Head
= (Queue
->Head
+ 1) % KEYBOARD_SCAN_CODE_MAX_COUNT
) {
684 Buf
[Index
] = Queue
->Buffer
[Queue
->Head
];
693 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
695 @return return the value
699 KeyReadDataRegister (
700 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
704 EFI_ISA_IO_PROTOCOL
*IsaIo
;
708 // Use IsaIo protocol to perform IO operations
710 IsaIo
= ConsoleIn
->IsaIo
;
715 ConsoleIn
->DataRegisterAddress
,
726 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
727 @param Data value wanted to be written
731 KeyWriteDataRegister (
732 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
736 ConsoleIn
->IsaIo
->Io
.Write (
739 ConsoleIn
->DataRegisterAddress
,
746 Read status register.
748 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
750 @return value in status register
754 KeyReadStatusRegister (
755 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
759 ConsoleIn
->IsaIo
->Io
.Read (
762 ConsoleIn
->StatusRegisterAddress
,
770 Write command register .
772 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
773 @param Data The value wanted to be written
777 KeyWriteCommandRegister (
778 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
782 ConsoleIn
->IsaIo
->Io
.Write (
785 ConsoleIn
->CommandRegisterAddress
,
792 Display error message.
794 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
795 @param ErrMsg Unicode string of error message
800 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
804 ConsoleIn
->KeyboardErr
= TRUE
;
808 Timer event handler: read a series of scancodes from 8042
809 and put them into memory scancode buffer.
810 it read as much scancodes to either fill
811 the memory buffer or empty the keyboard buffer.
812 It is registered as running under TPL_NOTIFY
814 @param Event The timer event
815 @param Context A KEYBOARD_CONSOLE_IN_DEV pointer
820 KeyboardTimerHandler (
828 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
830 ConsoleIn
= (KEYBOARD_CONSOLE_IN_DEV
*) Context
;
833 // Enter critical section
835 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
837 if (((KEYBOARD_CONSOLE_IN_DEV
*) Context
)->KeyboardErr
) {
839 // Leave critical section and return
841 gBS
->RestoreTPL (OldTpl
);
846 // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
847 // KB is not connected to system. If KB is not connected to system, driver will find there's something
848 // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
849 // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
850 // Just skip the 'resend' process simply.
853 while ((KeyReadStatusRegister (ConsoleIn
) & (KEYBOARD_STATUS_REGISTER_TRANSMIT_TIMEOUT
|KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
)) ==
854 KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
857 // Read one byte of the scan code and store it into the memory buffer
859 Data
= KeyReadDataRegister (ConsoleIn
);
860 PushScancodeBufTail (&ConsoleIn
->ScancodeQueue
, Data
);
862 KeyGetchar (ConsoleIn
);
865 // Leave critical section and return
867 gBS
->RestoreTPL (OldTpl
);
873 @param ConsoleIn - Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
874 @param Data - Pointer to outof buffer for keeping key value
876 @retval EFI_TIMEOUT Status resigter time out
877 @retval EFI_SUCCESS Success to read keyboard
882 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
894 // wait till output buffer full then perform the read
896 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
897 if (KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
) {
899 *Data
= KeyReadDataRegister (ConsoleIn
);
903 MicroSecondDelay (30);
906 if (RegFilled
== 0) {
914 write key to keyboard
916 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
917 @param Data value wanted to be written
919 @retval EFI_TIMEOUT The input buffer register is full for putting new value util timeout
920 @retval EFI_SUCCESS The new value is sucess put into input buffer register.
925 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
936 // wait for input buffer empty
938 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
939 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
944 MicroSecondDelay (30);
947 if (RegEmptied
== 0) {
953 KeyWriteDataRegister (ConsoleIn
, Data
);
959 Issue keyboard command.
961 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
962 @param Data The buff holding the command
964 @retval EFI_TIMEOUT Keyboard is not ready to issuing
965 @retval EFI_SUCCESS Success to issue keyboard command
970 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
981 // Wait For Input Buffer Empty
983 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
984 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
989 MicroSecondDelay (30);
992 if (RegEmptied
== 0) {
998 KeyWriteCommandRegister (ConsoleIn
, Data
);
1001 // Wait For Input Buffer Empty again
1004 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1005 if ((KeyReadStatusRegister (ConsoleIn
) & 0x02) == 0) {
1010 MicroSecondDelay (30);
1013 if (RegEmptied
== 0) {
1021 wait for a specific value to be presented on
1022 8042 Data register by keyboard and then read it,
1023 used in keyboard commands ack
1025 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1026 @param Value the value wanted to be waited.
1028 @retval EFI_TIMEOUT Fail to get specific value in given time
1029 @retval EFI_SUCCESS Success to get specific value in given time.
1033 KeyboardWaitForValue (
1034 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1048 // Make sure the initial value of 'Data' is different from 'Value'
1051 if (Data
== Value
) {
1055 // Read from 8042 (multiple times if needed)
1056 // until the expected value appears
1057 // use SumTimeOut to control the iteration
1063 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
1064 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
1065 Data
= KeyReadDataRegister (ConsoleIn
);
1069 MicroSecondDelay (30);
1072 SumTimeOut
+= TimeOut
;
1074 if (Data
== Value
) {
1079 if (SumTimeOut
>= mWaitForValueTimeOut
) {
1095 Show keyboard status lights according to
1096 indicators in ConsoleIn.
1098 @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
1100 @return status of updating keyboard register
1104 UpdateStatusLights (
1105 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1112 // Send keyboard command
1114 Status
= KeyboardWrite (ConsoleIn
, 0xed);
1115 if (EFI_ERROR (Status
)) {
1119 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1122 // Light configuration
1125 if (ConsoleIn
->CapsLock
) {
1129 if (ConsoleIn
->NumLock
) {
1133 if (ConsoleIn
->ScrollLock
) {
1137 Status
= KeyboardWrite (ConsoleIn
, Command
);
1139 if (EFI_ERROR (Status
)) {
1143 KeyboardWaitForValue (ConsoleIn
, 0xfa);
1148 Get scancode from scancode buffer and translate into EFI-scancode and unicode defined by EFI spec.
1150 The function is always called in TPL_NOTIFY.
1152 @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer
1157 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1165 EFI_KEY_DATA KeyData
;
1167 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
1171 UINT8 ScancodeArr
[4];
1172 UINT32 ScancodeArrPos
;
1175 // Check if there are enough bytes of scancode representing a single key
1176 // available in the buffer
1181 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, 1, ScancodeArr
);
1183 // point to the current position in ScancodeArr
1186 if (EFI_ERROR (Status
)) {
1190 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED
) {
1192 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, 2, ScancodeArr
);
1194 if (EFI_ERROR (Status
)) {
1199 // Checks for key scancode for PAUSE:E1-1D/45-E1/9D-C5
1200 // if present, ignore them
1202 if (ScancodeArr
[ScancodeArrPos
] == SCANCODE_EXTENDED1
) {
1204 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, 2, ScancodeArr
);
1207 if (EFI_ERROR (Status
)) {
1211 Status
= GetScancodeBufHead (&ConsoleIn
->ScancodeQueue
, 3, ScancodeArr
);
1214 if (EFI_ERROR (Status
)) {
1219 // if we reach this position, scancodes for a key is in buffer now,pop them
1221 Status
= PopScancodeBufHead (&ConsoleIn
->ScancodeQueue
, ScancodeArrPos
+ 1, ScancodeArr
);
1222 if (EFI_ERROR (Status
)) {
1228 // store the last available byte, this byte of scancode will be checked
1230 ScanCode
= ScancodeArr
[ScancodeArrPos
];
1233 // Check for special keys and update the driver state.
1237 case SCANCODE_CTRL_MAKE
:
1238 ConsoleIn
->Ctrl
= TRUE
;
1241 case SCANCODE_CTRL_BREAK
:
1242 ConsoleIn
->Ctrl
= FALSE
;
1245 case SCANCODE_ALT_MAKE
:
1246 ConsoleIn
->Alt
= TRUE
;
1249 case SCANCODE_ALT_BREAK
:
1250 ConsoleIn
->Alt
= FALSE
;
1253 case SCANCODE_LEFT_SHIFT_MAKE
:
1255 ConsoleIn
->Shift
= TRUE
;
1256 ConsoleIn
->LeftShift
= TRUE
;
1259 case SCANCODE_RIGHT_SHIFT_MAKE
:
1261 ConsoleIn
->Shift
= TRUE
;
1262 ConsoleIn
->RightShift
= TRUE
;
1266 case SCANCODE_LEFT_SHIFT_BREAK
:
1268 ConsoleIn
->Shift
= FALSE
;
1269 ConsoleIn
->LeftShift
= FALSE
;
1271 ConsoleIn
->SysReq
= FALSE
;
1274 case SCANCODE_RIGHT_SHIFT_BREAK
:
1276 ConsoleIn
->Shift
= FALSE
;
1277 ConsoleIn
->RightShift
= FALSE
;
1281 case SCANCODE_LEFT_LOGO_MAKE
:
1282 ConsoleIn
->LeftLogo
= TRUE
;
1284 case SCANCODE_LEFT_LOGO_BREAK
:
1285 ConsoleIn
->LeftLogo
= FALSE
;
1287 case SCANCODE_RIGHT_LOGO_MAKE
:
1288 ConsoleIn
->RightLogo
= TRUE
;
1290 case SCANCODE_RIGHT_LOGO_BREAK
:
1291 ConsoleIn
->RightLogo
= FALSE
;
1293 case SCANCODE_MENU_MAKE
:
1294 ConsoleIn
->Menu
= TRUE
;
1296 case SCANCODE_MENU_BREAK
:
1297 ConsoleIn
->Menu
= FALSE
;
1299 case SCANCODE_SYS_REQ_MAKE
:
1301 ConsoleIn
->SysReq
= TRUE
;
1304 case SCANCODE_CAPS_LOCK_MAKE
:
1305 ConsoleIn
->CapsLock
= (BOOLEAN
)!ConsoleIn
->CapsLock
;
1306 UpdateStatusLights (ConsoleIn
);
1308 case SCANCODE_NUM_LOCK_MAKE
:
1309 ConsoleIn
->NumLock
= (BOOLEAN
)!ConsoleIn
->NumLock
;
1310 UpdateStatusLights (ConsoleIn
);
1312 case SCANCODE_SCROLL_LOCK_MAKE
:
1313 ConsoleIn
->ScrollLock
= (BOOLEAN
)!ConsoleIn
->ScrollLock
;
1314 UpdateStatusLights (ConsoleIn
);
1318 // If this is above the valid range, ignore it
1320 if (ScanCode
>= SCANCODE_MAX_MAKE
) {
1327 // Store the last 2 available byte to check if it is Pause key
1329 ScanCode
= (UINT16
) (ScancodeArr
[ScancodeArrPos
] + (ScancodeArr
[ScancodeArrPos
- 1] << 8));
1330 if (ScanCode
== SCANCODE_PAUSE_MAKE
) {
1337 // Handle Ctrl+Alt+Del hotkey
1339 if (ConsoleIn
->Alt
&& ConsoleIn
->Ctrl
&& ScanCode
== SCANCODE_DELETE_MAKE
) {
1340 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1343 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1344 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1345 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
;
1346 KeyData
.KeyState
.KeyToggleState
= EFI_TOGGLE_STATE_VALID
;
1349 // Treat Numeric Key Pad "/" specially
1351 if (Extended
&& ScanCode
== 0x35) {
1352 KeyData
.Key
.UnicodeChar
= L
'/';
1353 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1356 // Convert Keyboard ScanCode into an EFI Key
1358 for (Index
= 0; ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
!= TABLE_END
; Index
+= 1) {
1359 if (ScanCode
== ConvertKeyboardScanCodeToEfiKey
[Index
].ScanCode
) {
1360 KeyData
.Key
.ScanCode
= ConvertKeyboardScanCodeToEfiKey
[Index
].EfiScanCode
;
1361 KeyData
.Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
;
1363 if (ConsoleIn
->Shift
&&
1364 (ConvertKeyboardScanCodeToEfiKey
[Index
].UnicodeChar
!= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
)) {
1365 KeyData
.Key
.UnicodeChar
= ConvertKeyboardScanCodeToEfiKey
[Index
].ShiftUnicodeChar
;
1367 // Need not return associated shift state if a class of printable characters that
1368 // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
1370 ConsoleIn
->LeftShift
= FALSE
;
1371 ConsoleIn
->RightShift
= FALSE
;
1374 // alphabetic key is affected by CapsLock State
1376 if (ConsoleIn
->CapsLock
) {
1377 if (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z') {
1378 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'a' + L
'A');
1379 } else if (KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') {
1380 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'A' + L
'a');
1389 // distinguish numeric key pad keys' 'up symbol' and 'down symbol'
1391 if (ScanCode
>= 0x47 && ScanCode
<= 0x53) {
1392 if (ConsoleIn
->NumLock
&& !ConsoleIn
->Shift
&& !Extended
) {
1393 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1394 } else if (ScanCode
!= 0x4a && ScanCode
!= 0x4e) {
1395 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1399 // If the key can not be converted then just return.
1401 if (KeyData
.Key
.ScanCode
== SCAN_NULL
&& KeyData
.Key
.UnicodeChar
== CHAR_NULL
) {
1406 // Save the Shift/Toggle state
1408 if (ConsoleIn
->Ctrl
) {
1409 KeyData
.KeyState
.KeyShiftState
|= (Extended
) ? EFI_RIGHT_CONTROL_PRESSED
: EFI_LEFT_CONTROL_PRESSED
;
1411 if (ConsoleIn
->Alt
) {
1412 KeyData
.KeyState
.KeyShiftState
|= (Extended
) ? EFI_RIGHT_ALT_PRESSED
: EFI_LEFT_ALT_PRESSED
;
1414 if (ConsoleIn
->LeftShift
) {
1415 KeyData
.KeyState
.KeyShiftState
|= EFI_LEFT_SHIFT_PRESSED
;
1417 if (ConsoleIn
->RightShift
) {
1418 KeyData
.KeyState
.KeyShiftState
|= EFI_RIGHT_SHIFT_PRESSED
;
1420 if (ConsoleIn
->LeftLogo
) {
1421 KeyData
.KeyState
.KeyShiftState
|= EFI_LEFT_LOGO_PRESSED
;
1423 if (ConsoleIn
->RightLogo
) {
1424 KeyData
.KeyState
.KeyShiftState
|= EFI_RIGHT_LOGO_PRESSED
;
1426 if (ConsoleIn
->Menu
) {
1427 KeyData
.KeyState
.KeyShiftState
|= EFI_MENU_KEY_PRESSED
;
1429 if (ConsoleIn
->SysReq
) {
1430 KeyData
.KeyState
.KeyShiftState
|= EFI_SYS_REQ_PRESSED
;
1432 if (ConsoleIn
->CapsLock
) {
1433 KeyData
.KeyState
.KeyToggleState
|= EFI_CAPS_LOCK_ACTIVE
;
1435 if (ConsoleIn
->NumLock
) {
1436 KeyData
.KeyState
.KeyToggleState
|= EFI_NUM_LOCK_ACTIVE
;
1438 if (ConsoleIn
->ScrollLock
) {
1439 KeyData
.KeyState
.KeyToggleState
|= EFI_SCROLL_LOCK_ACTIVE
;
1443 // Invoke notification functions if exist
1445 for (Link
= GetFirstNode (&ConsoleIn
->NotifyList
); !IsNull (&ConsoleIn
->NotifyList
, Link
); Link
= GetNextNode (&ConsoleIn
->NotifyList
, Link
)) {
1446 CurrentNotify
= CR (
1448 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
1450 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1452 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
1453 CurrentNotify
->KeyNotificationFn (&KeyData
);
1458 // Translate the CTRL-Alpha characters to their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
1460 if (ConsoleIn
->Ctrl
) {
1461 if (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z') {
1462 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'a' + 1);
1463 } else if (KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') {
1464 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'A' + 1);
1468 PushEfikeyBufTail (&ConsoleIn
->EfiKeyQueue
, &KeyData
);
1472 Perform 8042 controller and keyboard Initialization.
1473 If ExtendedVerification is TRUE, do additional test for
1474 the keyboard interface
1476 @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
1477 @param ExtendedVerification - indicates a thorough initialization
1479 @retval EFI_DEVICE_ERROR Fail to init keyboard
1480 @retval EFI_SUCCESS Success to init keyboard
1484 IN OUT KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
,
1485 IN BOOLEAN ExtendedVerification
1491 EFI_PS2_POLICY_PROTOCOL
*Ps2Policy
;
1494 Status
= EFI_SUCCESS
;
1495 mEnableMouseInterface
= TRUE
;
1499 // Get Ps2 policy to set this
1501 gBS
->LocateProtocol (
1502 &gEfiPs2PolicyProtocolGuid
,
1504 (VOID
**) &Ps2Policy
1507 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1509 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
,
1510 ConsoleIn
->DevicePath
1514 // Perform a read to cleanup the Status Register's
1515 // output buffer full bits within MAX TRY times
1517 while (!EFI_ERROR (Status
) && TryTime
< KEYBOARD_MAX_TRY
) {
1518 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1522 // Exceed the max try times. The device may be error.
1524 if (TryTime
== KEYBOARD_MAX_TRY
) {
1525 Status
= EFI_DEVICE_ERROR
;
1529 // We should disable mouse interface during the initialization process
1530 // since mouse device output could block keyboard device output in the
1531 // 60H port of 8042 controller.
1533 // So if we are not initializing 8042 controller for the
1534 // first time, we have to remember the previous mouse interface
1537 // Test the system flag in to determine whether this is the first
1538 // time initialization
1540 if ((KeyReadStatusRegister (ConsoleIn
) & KEYBOARD_STATUS_REGISTER_SYSTEM_FLAG
) != 0) {
1542 // 8042 controller is already setup (by myself or by mouse driver):
1543 // See whether mouse interface is already enabled
1544 // which determines whether we should enable it later
1547 // Read the command byte of 8042 controller
1549 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_READ
);
1550 if (EFI_ERROR (Status
)) {
1551 KeyboardError (ConsoleIn
, L
"\n\r");
1555 Status
= KeyboardRead (ConsoleIn
, &CommandByte
);
1556 if (EFI_ERROR (Status
)) {
1557 KeyboardError (ConsoleIn
, L
"\n\r");
1561 // Test the mouse enabling bit
1563 if ((CommandByte
& 0x20) != 0) {
1564 mEnableMouseInterface
= FALSE
;
1566 mEnableMouseInterface
= TRUE
;
1571 // 8042 controller is not setup yet:
1572 // 8042 controller selftest;
1573 // Don't enable mouse interface later.
1576 // Disable keyboard and mouse interfaces
1578 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1579 if (EFI_ERROR (Status
)) {
1580 KeyboardError (ConsoleIn
, L
"\n\r");
1584 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_MOUSE_INTERFACE
);
1585 if (EFI_ERROR (Status
)) {
1586 KeyboardError (ConsoleIn
, L
"\n\r");
1590 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1592 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
,
1593 ConsoleIn
->DevicePath
1596 // 8042 Controller Self Test
1598 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_CONTROLLER_SELF_TEST
);
1599 if (EFI_ERROR (Status
)) {
1600 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1604 Status
= KeyboardWaitForValue (ConsoleIn
, 0x55);
1605 if (EFI_ERROR (Status
)) {
1606 KeyboardError (ConsoleIn
, L
"8042 controller self test failed!\n\r");
1610 // Don't enable mouse interface later
1612 mEnableMouseInterface
= FALSE
;
1616 if (Ps2Policy
!= NULL
) {
1617 Ps2Policy
->Ps2InitHardware (ConsoleIn
->Handle
);
1620 // Write 8042 Command Byte, set System Flag
1621 // While at the same time:
1622 // 1. disable mouse interface,
1623 // 2. enable kbd interface,
1624 // 3. enable PC/XT kbd translation mode
1625 // 4. enable mouse and kbd interrupts
1627 // ( Command Byte bits:
1629 // 6: PC/XT translation mode
1630 // 5: Disable Auxiliary device interface
1631 // 4: Disable keyboard interface
1634 // 1: Enable Auxiliary device interrupt
1635 // 0: Enable Keyboard interrupt )
1637 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_WRITE
);
1638 if (EFI_ERROR (Status
)) {
1639 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1643 Status
= KeyboardWrite (ConsoleIn
, 0x67);
1644 if (EFI_ERROR (Status
)) {
1645 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1650 // Clear Memory Scancode Buffer
1652 ConsoleIn
->ScancodeQueue
.Head
= 0;
1653 ConsoleIn
->ScancodeQueue
.Tail
= 0;
1654 ConsoleIn
->EfiKeyQueue
.Head
= 0;
1655 ConsoleIn
->EfiKeyQueue
.Tail
= 0;
1658 // Reset the status indicators
1660 ConsoleIn
->Ctrl
= FALSE
;
1661 ConsoleIn
->Alt
= FALSE
;
1662 ConsoleIn
->Shift
= FALSE
;
1663 ConsoleIn
->CapsLock
= FALSE
;
1664 ConsoleIn
->NumLock
= FALSE
;
1665 ConsoleIn
->ScrollLock
= FALSE
;
1666 ConsoleIn
->LeftShift
= FALSE
;
1667 ConsoleIn
->RightShift
= FALSE
;
1668 ConsoleIn
->LeftLogo
= FALSE
;
1669 ConsoleIn
->RightLogo
= FALSE
;
1670 ConsoleIn
->Menu
= FALSE
;
1671 ConsoleIn
->SysReq
= FALSE
;
1674 // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1675 // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected
1676 // to system. So we only do the real reseting for keyboard when user asks and there is a real KB connected t system,
1677 // and normally during booting an OS, it's skipped.
1679 if (ExtendedVerification
&& CheckKeyboardConnect (ConsoleIn
)) {
1681 // Additional verifications for keyboard interface
1684 // Keyboard Interface Test
1686 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_KEYBOARD_INTERFACE_SELF_TEST
);
1687 if (EFI_ERROR (Status
)) {
1688 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1692 Status
= KeyboardWaitForValue (ConsoleIn
, 0x00);
1693 if (EFI_ERROR (Status
)) {
1696 L
"Some specific value not aquired from 8042 controller!\n\r"
1701 // Keyboard reset with a BAT(Basic Assurance Test)
1703 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_RESET
);
1704 if (EFI_ERROR (Status
)) {
1705 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1709 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1710 if (EFI_ERROR (Status
)) {
1711 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1715 // wait for BAT completion code
1717 mWaitForValueTimeOut
= KEYBOARD_BAT_TIMEOUT
;
1719 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_BAT_SUCCESS
);
1720 if (EFI_ERROR (Status
)) {
1721 KeyboardError (ConsoleIn
, L
"Keyboard self test failed!\n\r");
1725 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1728 // Set Keyboard to use Scan Code Set 2
1730 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_SELECT_SCAN_CODE_SET
);
1731 if (EFI_ERROR (Status
)) {
1732 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1736 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1737 if (EFI_ERROR (Status
)) {
1738 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1742 Status
= KeyboardWrite (ConsoleIn
, 0x02);
1743 if (EFI_ERROR (Status
)) {
1744 KeyboardError (ConsoleIn
, L
"8042 controller data write error!!\n\r");
1748 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1749 if (EFI_ERROR (Status
)) {
1750 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1755 // Clear Keyboard Scancode Buffer
1757 Status
= KeyboardWrite (ConsoleIn
, KEYBOARD_8048_COMMAND_CLEAR_OUTPUT_DATA
);
1758 if (EFI_ERROR (Status
)) {
1759 KeyboardError (ConsoleIn
, L
"8042 controller data write error!\n\r");
1763 Status
= KeyboardWaitForValue (ConsoleIn
, KEYBOARD_8048_RETURN_8042_ACK
);
1764 if (EFI_ERROR (Status
)) {
1765 KeyboardError (ConsoleIn
, L
"Some specific value not aquired from 8042 controller!\n\r");
1769 if (Ps2Policy
!= NULL
) {
1770 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_CAPSLOCK
) == EFI_KEYBOARD_CAPSLOCK
) {
1771 ConsoleIn
->CapsLock
= TRUE
;
1774 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_NUMLOCK
) == EFI_KEYBOARD_NUMLOCK
) {
1775 ConsoleIn
->NumLock
= TRUE
;
1778 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_SCROLLLOCK
) == EFI_KEYBOARD_SCROLLLOCK
) {
1779 ConsoleIn
->ScrollLock
= TRUE
;
1783 // Update Keyboard Lights
1785 Status
= UpdateStatusLights (ConsoleIn
);
1786 if (EFI_ERROR (Status
)) {
1787 KeyboardError (ConsoleIn
, L
"Update keyboard status lights error!\n\r");
1792 // At last, we can now enable the mouse interface if appropriate
1796 if (mEnableMouseInterface
) {
1798 // Enable mouse interface
1800 Status1
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_ENABLE_MOUSE_INTERFACE
);
1801 if (EFI_ERROR (Status1
)) {
1802 KeyboardError (ConsoleIn
, L
"8042 controller command write error!\n\r");
1803 return EFI_DEVICE_ERROR
;
1807 if (!EFI_ERROR (Status
)) {
1810 return EFI_DEVICE_ERROR
;
1816 Disable the keyboard interface of the 8042 controller.
1818 @param ConsoleIn The device instance
1820 @return status of issuing disable command
1825 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1831 // Disable keyboard interface
1833 Status
= KeyboardCommand (ConsoleIn
, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE
);
1834 if (EFI_ERROR (Status
)) {
1835 KeyboardError (ConsoleIn
, L
"\n\r");
1836 return EFI_DEVICE_ERROR
;
1843 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
1844 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
1845 should not be in system.
1847 @param[in] ConsoleIn Keyboard Private Data Structure
1849 @retval TRUE Keyboard in System.
1850 @retval FALSE Keyboard not in System.
1854 CheckKeyboardConnect (
1855 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
1859 UINTN WaitForValueTimeOutBcakup
;
1861 Status
= EFI_SUCCESS
;
1863 // enable keyboard itself and wait for its ack
1864 // If can't receive ack, Keyboard should not be connected.
1866 Status
= KeyboardWrite (
1871 if (EFI_ERROR (Status
)) {
1877 WaitForValueTimeOutBcakup
= mWaitForValueTimeOut
;
1878 mWaitForValueTimeOut
= KEYBOARD_WAITFORVALUE_TIMEOUT
;
1879 Status
= KeyboardWaitForValue (
1881 KEYBOARD_CMDECHO_ACK
1883 mWaitForValueTimeOut
= WaitForValueTimeOutBcakup
;
1885 if (EFI_ERROR (Status
)) {