summaryrefslogtreecommitdiff
path: root/Core/EM/PS2CTL/kbc.c
diff options
context:
space:
mode:
Diffstat (limited to 'Core/EM/PS2CTL/kbc.c')
-rw-r--r--Core/EM/PS2CTL/kbc.c1495
1 files changed, 1495 insertions, 0 deletions
diff --git a/Core/EM/PS2CTL/kbc.c b/Core/EM/PS2CTL/kbc.c
new file mode 100644
index 0000000..1712196
--- /dev/null
+++ b/Core/EM/PS2CTL/kbc.c
@@ -0,0 +1,1495 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2009, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+
+//**********************************************************************
+// $Header: /Alaska/SOURCE/Core/CORE_DXE/PS2CTL/kbc.c 41 11/07/12 12:24a Srikantakumarp $
+//
+// $Revision: 41 $
+//
+// $Date: 11/07/12 12:24a $
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Core/CORE_DXE/PS2CTL/kbc.c $
+//
+// 41 11/07/12 12:24a Srikantakumarp
+// [TAG] EIP99411
+// [Category] Improvement
+// [Description] Add port validation check in the PS2Ctrl module before
+// starting the driver.
+// [Files] kbc.c, kbc.h, mouse.c, ps2main.c, CORE_DXE.sdl, Tokens.c
+//
+// 40 10/18/12 8:58a Deepthins
+// [TAG] EIP70313
+// [Category] Improvement
+// [Description] Used CheckIssueLEDCmd in function LEDsOnOff instead of
+// OutToKb(Kbd, 0xED)
+// [Files] kbc.c, ps2kbd.c and kbc.h
+//
+// 39 6/05/12 9:30a Lavanyap
+// [TAG] EIP91313
+// [Category] Bug Fix
+// [Severity] Critical
+// [Symptom] Ps2 keyboard does not work with Ps2Ctl label (INT)4.6.5.4
+// [RootCause] Could not process PS2 keyboard data since there were more
+// frequent calls to DISABLE the Keyboard.
+// [Solution] Disabled and enabled the keyboard only before processing
+// the PS2 keyboard data.
+// [Files] kbc.c
+//
+// 38 5/02/12 2:27a Deepthins
+// [TAG] EIP63116
+// [Category] Improvement
+// [Description] PS/2 Keyboard/Mouse IRQ mode generic support
+// [Files] Ps2kbd.c, Mouse.c, kbc.h, kbc.c
+//
+// 37 4/30/12 2:21a Rajeshms
+// [TAG] EIP86986
+// [Category] Bug Fix
+// [Severity] Important
+// [Symptom] Can not detect F8 key on PS2 Keyboard while booting to EFI
+// aware OS.
+// [RootCause] Make code of F8 key (0x42) is taken by int09h and EFI
+// aware OS calls only one ReadKeyStroke() for any key catch, Now PS2
+// driver will take Break Code of F8 key(0xC2) and returns EFI_NOT_READY.
+// [Solution] Multiple Read from PS2 keyboard is implemented and read
+// exits if any valid key is detected. Also, the BDA keyboard buffer is
+// checked for any missed key in EFI.
+// [Files] ps2kbd.c, kbc.c, CORE_DXE.sdl
+//
+// 36 2/01/12 1:59a Deepthins
+// [TAG] EIP63116
+// [Category] New Feature
+// [Description] PS/2 Keyboard/Mouse IRQ mode generic support
+// [Files] Token.c, Ps2main.c, Ps2kbd.c, Mouse.c, kbc.h, kbc.c,
+// CORE_DXE.sdl
+//
+// 35 8/02/11 4:43a Rameshr
+// [TAG] - EIP 58974
+// [Category]- BUG FIX
+// [Severity]- Minor
+// [Symptom] - Yellow exclamation mark in Windows when PS2 KB/MS are not
+// present.
+// [RootCause]- ACPI name space variable reports that PS2 device present
+// [Solution] - Updated the SIO device status based on the device present
+// after BDS.
+// [Files] - Kbc.c, Kbc.h , Ps2main.c
+//
+// 34 4/27/11 4:36a Lavanyap
+// [TAG] - EIP49407
+// [Category] - IMPROVEMENT
+// [Description] - Move the Ps2 driver SDL tokens from Core Source to Core
+// Bin,So that we don't need to add Core source for changing the Ps2
+// driver SDL tokens.
+// [Files] - Ps2Ctl.sdl, ps2kbd.c, ps2main.c, ps2ctl.h, kbc.c, mouse.c,
+// hotkey.c, CORE_DXE.sdl, Tokens.c
+//
+// 33 2/05/11 3:57p Artems
+// Fixed bug with ellow exclamation mark in Windows, when PS2 keyboard is
+// absent
+//
+// 32 1/24/11 3:39p Pats
+// [TAG] - EIP 18488
+// [Category] - Enhancement
+// [Severity] - Normal
+// [Symptom] - PS2CTL: Need hooks for port swap, Keybaord mouse detect.
+// [RootCause] - Support may be needed for kbc controller or SIO with
+// different support from AMI KB-5.
+// [Solution] - Removed token control of AutodetectKbdMousePortsPtr.
+// [Files] - kbc.c
+//
+// 31 1/05/11 1:02a Rameshr
+// [TAG] EIPEIP 35306
+// [Category] Improvement
+// [Description] Report the Ps2 Controller and Device Error Codes.
+// [Files] AmiStatuscodes.h, Kbc.c, Kbc.h,Ps2ctl.sdl, ps2kbd.c,
+// ps2main.c ,Statuscode.h
+//
+// 30 12/10/10 5:28a Rameshr
+// [TAG] - EIP 47011
+// [Category]- BUG FIX
+// [Severity]- Minor
+// [Symptom] - DTM IO Tests fail due to presence of PS/2 devices that are
+// not ready - no PS/2 devices attached during test.
+// [RootCause]- PS2 device _STA method returns that, device is present .
+// [Solution] - Updated the SIO device status based on the device
+// presence.
+// [Files] - Kbc.c , Kbc.h, Mouse.c
+//
+// 29 8/23/10 4:37a Rameshr
+// Bug Fix: EIP 41862
+// Symptoms: If plug PS/2 KB only, Can`t use hot key enter iSCSI OPROM
+// .The CheckIssueLEDCmd routine cause PS2 keyboard not work.
+// FilesModified: Kbc.c
+// Details: Send Data immediately after sending LED command "ED".
+//
+// 28 8/23/10 4:23a Rameshr
+// Bug Fix : EIP 40838
+// Symptoms: KBC.C build failed in DetectPS2Keyboard() if
+// DETECT_PS2_KEYBOARD=0 & PS2MOUSE_SUPPORT=0
+// Files Modified: Efismplpp.c, Kbc.c, Kbc.h, Mouse.c PS2ctl.cif,
+// Ps2ctl.sdl, Ps2Kbd.c, Ps2Mouse.c
+// Details:
+// 1) Added Detect_PS2_Mouse sdl token and modified the code.
+// 2) INSTALL_KEYBOARD_MOUSE_ALWAYS sdl token added.
+// 1 - Install the Keyboard- SimpleTextIn, Mouse - AbsPointer Always,
+// 0 - Install the Keyboard- SimpleTextIn, Mouse - AbsPointer only if
+// the device is present at the time of detection.
+// This is for Ps2Keyboard Hot plug support in EFI
+// 3) Code clean up in mouse.c EfiSmplpp.c ,ps2mouse.h
+// 4) Unused file automaton.h removed.
+//
+// 27 7/01/10 9:03a Rameshr
+// Issue:If PS/2 KBD isn't present, KBC returns oxFE when send 0xED
+// command, that makes system to hang for 5 to 10 Sec.
+// Solution:If command output is 0xFE (Resent) , tried for 3 times and
+// gets out.
+// EIP 40515
+//
+// 26 8/04/09 4:32p Rameshr
+// Symptom: Boot to Shell and Press Ps2 keyboard Key, Reduces the EFI
+// available memory.
+// RootCause: Progress_code macro allocate the memory for the Data hub and
+// when ever key pressed , Disable/enable keyboard gets called. That sends
+// the progress code.
+// Solution: Removed the Progress code from Disable/Enable keyboard
+// functions.
+//
+// 25 7/01/09 5:29p Olegi
+// Correction: previous file headers changes were done on the older file.
+// Now changes are applied to the latest file.
+//
+// 24 7/01/09 12:32p Olegi
+// Source is corrected according to the coding standard: function headers,
+// copyright messages are updated.
+//
+// 23 4/20/09 1:53p Rameshr
+// CCB byte programmed once Keyboard controller is avilable.
+// EIP 19880-CCB byte not programmed
+//
+// 22 4/22/08 4:31p Felixp
+// Additional progress codes added
+//
+// 21 4/09/08 10:19a Olegi
+// Changed the key attributes (modifiers and shift state) reporting.
+//
+// 20 10/23/07 4:05p Olegi
+// Removed BDA related data storage.
+//
+// 19 4/16/07 6:28p Pats
+// Modified to conform with coding standards. No code changes.
+//
+// 18 3/19/07 2:22p Pats
+// Removed test for keyboard active. Issues start keyboard command on
+// logic of SDL tokens only.
+//
+// 17 3/13/07 5:35p Pats
+// Fixed problem of Lakeport not seeing setup key.
+//
+// 16 3/13/07 3:01p Pats
+// If keyboard detection is disabled, tests for keyboard active and issues
+// keyboard enable command only if it is not active. This preserves the
+// input key if there is one.
+//
+// 15 3/13/07 11:11a Pats
+// Added line to enable keyboard if keyboard detection is disabled.
+// Required for some platforms.
+//
+// 14 3/01/07 3:20p Pats
+// Fixed problem of mouse not working if keyboard detection disabled.
+//
+// 13 2/28/07 6:05p Pats
+// Made PS2 Keyboard detection removable with SDL token, to speed up boot,
+// and to keep keep Setup key (F2 or Del) from being absorbed.
+//
+// 12 4/12/06 9:14a Srinin
+// Write to Port 80h removed.
+//
+// 11 1/09/06 11:38a Felixp
+//
+// 9 12/22/05 10:23a Srinin
+// KBD Enable/Disable call optimized. Cleaned up the code.
+//
+// 8 10/27/05 1:04p Srinin
+// When command to KBD is given, check for Timeout error added.
+//
+// 7 10/11/05 4:14p Srinin
+// KBD and Mouse init done together. Re-entry problem fixed.
+//
+// 6 8/31/05 6:21p Srinin
+// Comments added to "AutodetectKbdMousePorts"
+//
+// 5 8/31/05 4:45p Srinin
+// When KBD not connected, DetectPS2Keyboard
+// will returns EFI_SUCCESS in order to support hot plug.
+//
+// 4 8/30/05 5:23p Srinin
+// PortSwap logic changed.
+//
+// 3 5/03/05 8:51a Olegi
+// Delay correction in OutToKb function.
+//
+// 2 2/25/05 10:34a Olegi
+// Removed duplicated code.
+//
+// 1 2/01/05 1:10a Felixp
+//
+// 2 1/18/05 3:22p Felixp
+// PrintDebugMessage renamed to Trace
+//
+// 1 10/28/04 10:19a Olegi
+//
+// 2 9/17/04 7:02p Olegi
+//
+// 1 8/27/04 3:18p Olegi
+// Initial VSS checkin.
+//
+//**********************************************************************
+
+//<AMI_FHDR_START>
+//----------------------------------------------------------------------
+//
+// Name: kbc.c
+//
+// Description: PS/2 Controller I/O support fuctions
+//
+//----------------------------------------------------------------------
+//<AMI_FHDR_END>
+
+//----------------------------------------------------------------------
+
+#include "ps2ctl.h"
+#include "kbc.h"
+#include "genericSio.h"
+
+
+//----------------------------------------------------------------------
+
+extern BOOLEAN MouseResetRequired;
+extern BOOLEAN DetectPs2KeyboardValue;
+extern BOOLEAN InstallKeyboardMouseAlways;
+extern UINT32 IbFreeTimeoutValue;
+extern UINT32 IbFreeMaxTimeoutValue;
+BOOLEAN MouseEnableState = FALSE;
+BOOLEAN KBDEnableState = TRUE;
+BOOLEAN Ps2KbdDetected = FALSE;
+BOOLEAN Ps2KbdMouseDetected=FALSE;
+extern BOOLEAN Ps2MouseDetected;
+extern BOOLEAN KbdIrqSupport;
+extern UINT8 gKeyboardIrqInstall;
+extern EFI_LEGACY_8259_PROTOCOL *mLegacy8259;
+BOOLEAN InsidePS2DataDispatcher = FALSE;
+//----------------------------------------------------------------------
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: KBCDummyGetData
+//
+// Description: Reads keyboard data port to clear it
+//
+// Parameters: VOID *Context - Pointer to context
+//
+// Output: UINT8 - Keyboard data port data
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8
+KBCDummyGetData (
+ VOID *Context )
+{
+ UINT8 bData;
+ bData = IoRead8(KBC_DATA_PORT);
+ TRACEKBD((-1,"KD %X ", bData));
+ return bData;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: MouseDummyGetData
+//
+// Description: Reads keyboard data port to clear it
+//
+// Parameters: VOID *Context - Pointer to context
+//
+// Output: UINT8 - Keyboard data port data
+//
+// Modified: MouseResetRequired
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8
+MouseDummyGetData (
+ VOID *Context )
+{
+ UINT8 bData;
+ bData = IoRead8(KBC_DATA_PORT);
+ TRACEKBD((-1,"MD %X ", bData));
+ MouseResetRequired = TRUE; // Since a orphan mouse data is
+ // received, mouse packet will be out
+ // of sync.
+ return bData;
+
+}
+
+
+//----------------------------------------------------------------------
+// The following two fuction pointers are initialized with dummy
+// routines; they will be updated with the real routine pointers
+// in the corresponding device drivers' start functions.
+//----------------------------------------------------------------------
+
+STATEMACHINEPROC DrivePS2KbdMachine = KBCDummyGetData;
+STATEMACHINEPROC DrivePS2MouseMachine = MouseDummyGetData;
+
+extern KEYBOARD gKbd;
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: KBCBatTest
+//
+// Description: Runs Basic Assurance Test on KBC.
+//
+// Parameters: None
+//
+// Output: EFI_SUCCESS or EFI_DEVICE_ERROR
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS KBCBatTest()
+{
+ UINT16 wCounter = 0xFFFF;
+ PROGRESS_CODE(DXE_KEYBOARD_SELF_TEST);
+ //
+ // Empty KBC before BAT
+ //
+ for (; wCounter; wCounter--) {
+ IoRead8(KBC_DATA_PORT);
+ IoDelay();
+ if (!(IoRead8(KBC_CMDSTS_PORT) & (KBC_OBF | KBC_IBF))) {
+ break;
+ }
+ }
+ if (!wCounter) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Perform BAT
+ //
+ if (Read8042(0xAA) != 0x55) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: AutodetectKbdMousePorts
+//
+// Description: Auto detection of KB/MS using AMI KB-5. This code will
+// allow the connector swap of Keyboard and PS2 Mouse i.e.
+// keyboard can be connected to PS2 Mouse connector and
+// vice-versa.
+//
+// Parameters: None. AMI KB-5 present in the system, keyboard controller
+// BAT is complete.
+//
+// Output: None
+//
+//
+// Notes: This code should be used only if the motherboard has
+// AMI KB-5 which is also available in IO chipsets having KBC
+// e.g. SMC932, etc.
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID AutodetectKbdMousePorts()
+{
+ UINT8 bData, Index;
+
+ EFI_STATUS Status;
+ Status = IbFreeTimeout(IbFreeMaxTimeoutValue);
+ if (EFI_ERROR(Status)) {
+ return;
+ }
+ WriteKeyboardCommand(0x60); // Lock KBD
+ IoRead8(KBC_DATA_PORT); // Discard any data
+
+ Write8042CommandByte(0x74); // KBD and Aux device disabled
+
+// Check for KBC version
+ IoRead8(KBC_DATA_PORT); // Discard any data
+ WriteKeyboardCommand(0xa1); //
+ if (!ObFullReadTimeout(&bData, 20, TRUE) && bData == 0x35) {
+
+ WriteKeyboardCommand(0x60);
+ WriteKeyboardData(4);
+
+ for (Index = 6; Index; Index--){ // Read max. 6 data
+ if (ObFullReadTimeout(&bData, 10, TRUE)) break;
+ }
+
+ WriteKeyboardCommand(0xa7); // Disable Mouse
+ WriteKeyboardCommand(0xc8); // Select Primary
+
+ WriteKeyboardData(rKeyboardID); // Read KBD ID
+
+ ObFullReadTimeout(&bData, 1000, TRUE); // Read ACK
+
+ if (bData == rKeyboardID) goto PortSwap;
+
+ if (bData == KB_ACK_COM) {
+ ObFullReadTimeout(&bData, 100, TRUE);
+// When Mouse is connected to KBD port, control goes to PortSwap here
+ if (!bData) goto PortSwap;
+ ObFullReadTimeout(&bData, 100, TRUE);
+ }
+ bData = IoRead8(KBC_CMDSTS_PORT);
+// When KBD is connected to the KBD port, control returns here
+ if (!(bData & KBC_TIMEOUT_ERR)) return;
+
+ WriteKeyboardCommand(0xD4); // Secondary Port
+ WriteKeyboardData(rKeyboardID); // Read KBD ID
+ ObFullReadTimeout(&bData, 1000, TRUE);
+ if (bData == rKeyboardID) return;
+ if (bData == KB_ACK_COM) {
+// When Mouse alone is connected to Mouseport, control returns here
+ if (!ObFullRead()) return;
+ bData = ObFullRead();
+ }
+ bData = IoRead8(KBC_CMDSTS_PORT);
+// When KBD alone is connected to Mouse port, no time out error and control
+// goes to portswap.
+ if (bData & KBC_TIMEOUT_ERR) return;
+
+PortSwap:
+ WriteKeyboardCommand(0xC9);
+ return;
+ }
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: AuxDeviceCommand
+//
+// Description: This routine issues AuxDevice command, and returns the
+// from the AUX device
+// the connector swap of Keyboard and PS2 Mouse i.e. keyboard
+// can be connected to PS2 Mouse connector and vice-versa.
+//
+// Parameters: UINT8 bCmd - AUX device command
+//
+// Output: UINT8 Data from AUX device
+//
+// Notes: Only AUX commands that expect the response from AUX device
+// can be executed using this function; otherwise the code will
+// be stuck waiting for OBF
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8 AuxDeviceCommand (
+ UINT8 bCmd )
+{
+ EFI_STATUS Status;
+ Status = IbFreeTimeout(IbFreeMaxTimeoutValue);
+ if (EFI_ERROR(Status)) {
+ return (UINT8)Status;
+ }
+ IoWrite8(KBC_CMDSTS_PORT, 0xD4);
+
+ return IssueCommand(bCmd);
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: IssueCommand
+//
+// Description: Helper function to read the data after executing AUX
+// device command.
+//
+// Parameters: UINT8 bCmd - AUX device command
+//
+// Output: UINT8 Data from AUX device
+//
+// Notes: Only AUX commands that expect the response from AUX device
+// can be executed using this function; otherwise the code will
+// be stuck waiting for OBF
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8 IssueCommand (
+ UINT8 bCmd )
+{
+ EFI_STATUS Status;
+ Status = IbFreeTimeout(IbFreeMaxTimeoutValue);
+ if (EFI_ERROR(Status)) {
+ return (UINT8)Status;
+ }
+ IoWrite8(KBC_DATA_PORT, bCmd);
+ IbFree();
+ for (;;)
+ {
+ if (IoRead8(KBC_CMDSTS_PORT) & KBC_OBF) {
+ return IoRead8(KBC_DATA_PORT);
+ }
+ }
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: Read8042
+//
+// Description: Sends the given command to KBC, reads and returns the
+// acknowledgement byte returned from KBC.
+//
+// Parameters: UINT8 bCmd - Command to send to KBC
+//
+// Output: UINT8 Acknowledgment byte
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8 Read8042 (
+ UINT8 bCmd )
+{
+
+ UINT8 bData = 0xFE;
+ WriteKeyboardCommand(bCmd);
+ ObFullReadTimeout(&bData, 40, FALSE);
+ return bData;
+
+}
+
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: ReadDevice
+//
+// Description: Sends the given command to KBD, reads and returns the
+// acknowledgement byte returned from KBD.
+//
+// Parameters: UINT8 bCmd - Command to send to KBC
+// UINT8 *Data - Pointer to data buffer
+// UINT8 Response - Response expected
+//
+// Output: EFI_SUCCESS - Data == Response
+// EFI_DEVICE_ERROR - Data != Response
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS ReadDevice (
+ UINT8 bCmd,
+ UINT8 *Data,
+ UINT8 Response )
+{
+
+ WriteKeyboardData(bCmd);
+ if (ObFullReadTimeout(Data, 40, FALSE)) return EFI_DEVICE_ERROR;
+ if (*Data == Response) return EFI_SUCCESS;
+ return EFI_DEVICE_ERROR;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: WriteKeyboardCommand
+//
+// Description: Writes command to KBC.
+//
+// Parameters: UINT8 bCmd - Command to send to KBC
+//
+// Output: None
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID WriteKeyboardCommand (
+ UINT8 bCmd )
+{
+ EFI_STATUS Status;
+ Status = IbFreeTimeout(IbFreeMaxTimeoutValue);
+ if (EFI_ERROR(Status)) {
+ return;
+ }
+ IoWrite8(KBC_CMDSTS_PORT, bCmd);
+ IbFree();
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: WriteKeyboardData
+//
+// Description: Writes data to KBC.
+//
+// Parameters: UINT8 bCmd - Data to send to KBC
+//
+// Output: None
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID WriteKeyboardData (
+ UINT8 bCmd )
+{
+ EFI_STATUS Status;
+ Status = IbFreeTimeout(IbFreeMaxTimeoutValue);
+ if (EFI_ERROR(Status)) {
+ return;
+ }
+ IoWrite8(KBC_DATA_PORT, bCmd);
+ IbFree();
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: Write8042CommandByte
+//
+// Description: Writes CCB to KBC
+//
+// Parameters: UINT8 bCCB - Command byte to send to KBC
+//
+// Output: None
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID Write8042CommandByte (
+ UINT8 bCCB )
+{
+ EFI_STATUS Status;
+ Status = IbFreeTimeout(IbFreeMaxTimeoutValue);
+ if (EFI_ERROR(Status)) {
+ return;
+ }
+ WriteKeyboardCommand(0x60); // CMD to send command byte
+ IoWrite8(KBC_DATA_PORT, bCCB); // Write command byte into KBC
+ IbFree(); // Wait until input buffer is free
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: ObFullRead
+//
+// Description: Waits for Output Buffer Full and then reads the data port
+//
+// Parameters: None
+//
+// Output: UINT8 KBC Data port data
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8 ObFullRead()
+{
+ for (;;) {
+ if (IoRead8(KBC_CMDSTS_PORT) & KBC_OBF) {
+ return IoRead8(KBC_DATA_PORT);
+ }
+ }
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: IbFree
+//
+// Description: Waits for Iutput Buffer to be empty
+//
+// Parameters: None
+//
+// Output: None
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID IbFree()
+{
+ for (;;) {
+ if (!(IoRead8(KBC_CMDSTS_PORT) & KBC_IBF)) {
+ break;
+ }
+ }
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: IbFreeTimeout
+//
+// Description: Waits a specified timeout for Iutput Buffer to be empty
+//
+// Parameters: UINT32 TimeoutValue
+//
+// Return value: EFI_STATUS (EFI_SUCCESS or EFI_TIMEOUT)
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS IbFreeTimeout( UINT32 TimeoutValue)
+{
+ UINTN i;
+
+ for (i = 0; i < TimeoutValue; i++) {
+ if (!(IoRead8(KBC_CMDSTS_PORT) & KBC_IBF)) {
+ return EFI_SUCCESS;
+ }
+ gSysTable->BootServices->Stall(1000); // 1 ms
+ }
+ return EFI_TIMEOUT;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: IoDelay
+//
+// Description: Performs IO delay by executing IO read.
+//
+// Parameters: None
+//
+// Output: None
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID IoDelay()
+{
+ IoRead8(0x61);
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: ObFullReadTimeout
+//
+// Description: This routine checks for the data availbility in output
+// buffer for a short period of time, if data is available
+// within this time, it reads and returns the data from
+// output buffer.
+//
+// Paremeters: UINT8* data - Pointer to the byte to be updated
+// UINT32 msec - Milliseconds timeout
+// BOOLEAN ONLYOBF - Only waits for OBF if true
+//
+// Output: BOOLEAN - Returns FALSE if data is successfully updated
+// (no timeout), data is updated
+// Returns TRUE if time-out
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+BOOLEAN
+ObFullReadTimeout (
+ UINT8* data,
+ UINT32 msec,
+ BOOLEAN ONLYOBF )
+{
+
+ UINT8 bData;
+ UINT32 loopcount = msec << 1;
+
+
+ for (; loopcount; loopcount--) {
+
+ bData = IoRead8(KBC_CMDSTS_PORT);
+
+ if (ONLYOBF && (bData & KBC_OBF)) {
+ *data = IoRead8(KBC_DATA_PORT);
+ return FALSE;
+ }
+
+ if ((bData & (KBC_OBF|KBC_AUX_OBF)) == KBC_OBF) {
+ *data = IoRead8(KBC_DATA_PORT);
+ if (bData & 0x40) {
+ TRACEKBD((-1, "Status Reg K : %x, %x\n", bData, *data));
+ return TRUE;
+ }
+ else return FALSE; // No timeout
+ }
+
+ if ((bData & (KBC_OBF|KBC_AUX_OBF)) == (KBC_OBF | KBC_AUX_OBF)){
+ TRACEKBD((-1, "AUX OBF inside KBD"));
+ return TRUE;
+ }
+
+ gSysTable->BootServices->Stall(500); // 0.5msec
+
+ }
+ TRACEKBD((-1, "KBD data not available"));
+ return TRUE; // Timeout
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: OutToKb
+//
+// Description: Send the given command to KDB during runtime.
+//
+// Parameters: KEYBOARD* kbd - Pointer to keyboard buffer
+// UINT8 bCmd - Command to send to keyboard
+//
+// Output: EFI_SUCCESS or EFI_DEVICE_ERROR
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+OutToKb (
+ KEYBOARD* kbd,
+ UINT8 bCmd )
+{
+ UINT8 bCounter1, bData;
+ UINT32 Counter;
+ EFI_STATUS Status;
+
+ //
+ // If Keyboard irq is supported, device acknowlegement is prossed by IRQ
+ // Handler. The acknowledgement data is stored in Kbd->CommandResponded
+ //
+ if(KbdIrqSupport && gKeyboardIrqInstall){
+ if(KBDEnableState) {
+ Status = IbFreeTimeout(IbFreeMaxTimeoutValue);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ IoWrite8(KBC_DATA_PORT, bCmd);
+ IbFree();
+ for (Counter = 1000; Counter > 0; Counter--) {
+ if (kbd->CommandResponded == KB_ACK_COM){
+ kbd->CommandResponded =NULL;
+ return EFI_SUCCESS;
+ }
+ if (kbd->CommandResponded == KB_RSND_COM){
+ kbd->CommandResponded =NULL;
+ break;
+ }
+ gSysTable->BootServices->Stall(1000);
+ }
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+
+ for (bCounter1 = 3; bCounter1 > 0; bCounter1--) {
+ IbFree();
+ IoWrite8(KBC_DATA_PORT, bCmd);
+ IbFree();
+
+ for (Counter = 1000; Counter > 0; Counter--) {
+ if (IoRead8(KBC_CMDSTS_PORT) & KBC_OBF) {
+ bData = IoRead8(KBC_DATA_PORT);
+ if (bData == 0xFA) {
+ return EFI_SUCCESS;
+ } else if (bData == 0xFE) {
+ break;
+ } else {
+ if (IoRead8(KBC_CMDSTS_PORT) & KBC_TIMEOUT_ERR) break;
+ //
+ // Insert the key into the buffer
+ //
+ if (kbd) {
+ HandleKBDData(kbd, bData);
+ if (kbd->KeyIsReady) {
+ ProcessHotKey(kbd->KeyData.PS2ScanCode, kbd->KeyData.KeyState.KeyShiftState);
+ InsertKeyToBuffer(kbd, &kbd->KeyData);
+ kbd->KeyIsReady = FALSE;
+ }
+ }
+ }
+ }
+ gSysTable->BootServices->Stall(1000); // 1msec
+ }
+ }
+
+ return EFI_DEVICE_ERROR;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: DisableKeyboard
+//
+// Description: Disables KBD interface and reads the data from KBC
+// data port.
+//
+// Modified: KBDEnableState
+//
+// Referral(s): KBDEnableState
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID DisableKeyboard()
+{
+ EFI_STATUS Status;
+
+ if (!KBDEnableState) return;
+ Status = IbFreeTimeout(IbFreeMaxTimeoutValue);
+ if (EFI_ERROR(Status)) {
+ return;
+ }
+ IoWrite8(KBC_CMDSTS_PORT, 0xAD);
+ IbFree();
+ KBDEnableState = FALSE;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: EnableKeyboard
+//
+// Description: Enables KBD interface.
+//
+// Paremeters: None
+//
+// Output: Status
+//
+// Modified: KBDEnableState
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS EnableKeyboard()
+{
+ EFI_STATUS Status=EFI_SUCCESS;
+
+ if (KBDEnableState) {
+ return EFI_SUCCESS;
+ }
+ Status = IbFreeTimeout(IbFreeMaxTimeoutValue);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ IoWrite8(KBC_CMDSTS_PORT, 0xAE);
+ Status = IbFreeTimeout(IbFreeTimeoutValue);
+ KBDEnableState = TRUE;
+ if (EFI_ERROR(Status)) {
+ KBDEnableState = FALSE;
+ }
+
+ return Status;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: DisableAuxDevice
+//
+// Description: Disables Aux interface.
+//
+// Paremeters: None
+//
+// Output: None
+//
+// Modified: MouseEnableState
+//
+// Referrals: MouseEnableState
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID DisableAuxDevice()
+{
+ EFI_STATUS Status;
+ if (!MouseEnableState) return;
+ Status = IbFreeTimeout(IbFreeMaxTimeoutValue);
+ if (EFI_ERROR(Status)) {
+ return;
+ }
+ IoWrite8(KBC_CMDSTS_PORT, 0xA7);
+ IbFree();
+ MouseEnableState = FALSE;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: EnableAuxDevice
+//
+// Description: Enables Aux interface.
+//
+// Paremeters: None
+//
+// Output: None
+//
+// Modified: MouseEnableState
+//
+// Referrals: MouseEnableState
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID EnableAuxDevice()
+{
+ EFI_STATUS Status;
+ if (MouseEnableState) return;
+ Status = IbFreeTimeout(IbFreeMaxTimeoutValue);
+ if (EFI_ERROR(Status)) {
+ return;
+ }
+ IoWrite8(KBC_CMDSTS_PORT, 0xA8);
+ IbFree();
+ MouseEnableState = TRUE;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: DetectPS2KeyboardAndMouse
+//
+// Description: Detects the presence of Keyboard and Mouse in KBC port.
+//
+// Parameters: None. Keyboard interface is disabled.
+//
+// Output: Ps2KbdDetected and Ps2MouseDetected variable set accorinding
+// the device presence
+//
+// Modified: Ps2KbdDetected, Ps2MouseDetected
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS DetectPS2KeyboardAndMouse()
+{
+ UINT16 wCount;
+ UINT8 bData;
+ BOOLEAN bAck = FALSE;
+
+ if(Ps2KbdMouseDetected) {
+ //
+ // Ps2Keyboard and Mouse Detected already
+ //
+ return EFI_SUCCESS;
+ }
+
+ Ps2KbdMouseDetected=TRUE;
+
+ DetectPs2Mouse();
+
+
+ if ( DetectPs2KeyboardValue ) {
+
+ PROGRESS_CODE(DXE_KEYBOARD_DETECT);
+ Write8042CommandByte (0x6d);
+ KBCGetData(); // Dummy read
+
+ for (wCount = 0; wCount < 3; wCount++) {
+ // Disable Scanning
+ if (!ReadDevice(KBD_DISABLE_SCANNING, &bData, KB_ACK_COM)) break;
+ if (IoRead8(KBC_CMDSTS_PORT) & 0x40) { // Time out error
+ gSysTable->BootServices->Stall(6000); // 6 msec
+ // After power-up some junk data comes from KBD. If not eaten
+ // other command will fail.
+ KBCGetData();
+ }
+ }
+
+ DisableKeyboard();
+ KBCGetData();
+
+ //
+ // 3 times retry on keyboard reset
+ //
+ for (wCount = 0; wCount < 3; wCount++) {
+ if (!ReadDevice(KBD_RESET, &bData, KB_ACK_COM)) { // ACK received
+ TRACEKBD((-1,"KBD Reset Response %X ", bData));
+ bAck = TRUE;
+ break;
+ } else {
+ KBCGetData(); // Dummy read
+ }
+ }
+
+ if (bAck) { //If not not Keyboard
+ if (ObFullRead() == 0xAA) { // Reset successful
+ Ps2KbdDetected=TRUE;
+ } else if (Read8042(0xAB)) { // On Success returns 0
+ //
+ // 0x01 if Clock line stuck low, 0x02 if clock line stuck high,
+ // 0x03 if data line stuck low, and 0x04 if data line stuck high
+ //
+ Ps2KbdDetected=FALSE;
+ }
+ }
+
+ //
+ // Check for lock key
+ //
+ if (!(IoRead8(KBC_CMDSTS_PORT) & 0x10)) {
+ //
+ // Keyboard is locked, we can report it here
+ //
+ Ps2KbdDetected=FALSE;
+ }
+ } else {
+ Ps2KbdDetected = TRUE;
+ KBDEnableState = TRUE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: UpdateSioVariableForKeyboardMouse
+//
+// Description: Update the SIO variable in the ACPI name space depend on the
+// Ps2keyboard and Mouse Present state.
+//
+// Parameters: None
+//
+// Output: None
+//
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID UpdateSioVariableForKeyboardMouse(
+ EFI_EVENT Event,
+ VOID *Context
+)
+{
+ static EFI_GUID SioDevStatusVarGuid = SIO_DEV_STATUS_VAR_GUID;
+ UINTN SioDevStatusVarSize = sizeof(SIO_DEV_STATUS);
+ SIO_DEV_STATUS SioDevStatus;
+ UINT32 SioDevStatusVarAttributes = 0;
+ EFI_STATUS Status;
+
+ //
+ // Get the SIO variable.
+ //
+ Status = pRS->GetVariable( SIO_DEV_STATUS_VAR_NAME,
+ &SioDevStatusVarGuid,
+ &SioDevStatusVarAttributes,
+ &SioDevStatusVarSize,
+ &SioDevStatus.DEV_STATUS);
+
+ //
+ // If variable not found return without updating it.
+ //
+ if(EFI_ERROR(Status)) {
+ SioDevStatus.DEV_STATUS = 0;
+ SioDevStatusVarAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS;
+ SioDevStatus.Res3 = 1; // To indicate that PS2 state vas updated
+ }
+
+ //
+ // Set the flag based on the Ps2 keyboard presence state
+ //
+ if(Ps2KbdDetected) {
+ SioDevStatus.Key60_64 = 1;
+ } else {
+ SioDevStatus.Key60_64 = 0;
+ }
+
+
+ //
+ // Set the Mouse flag based on the Mouse Presence state.
+ //
+ if(Ps2MouseDetected) {
+ SioDevStatus.Ps2Mouse = 1;
+ } else {
+ SioDevStatus.Ps2Mouse = 0;
+ }
+
+ //
+ // Set the SIO variable.
+ //
+ Status = pRS->SetVariable( SIO_DEV_STATUS_VAR_NAME,
+ &SioDevStatusVarGuid,
+ SioDevStatusVarAttributes,
+ SioDevStatusVarSize,
+ &SioDevStatus);
+ return;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: DetectPS2Keyboard
+//
+// Description: Detects the presence of Keyboard in KBC port.
+//
+// Parameters: None
+//
+// Output: EFI_SUCCESS if mouse is detected
+// EFI_NOT_FOUND if mouse is not detected
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS DetectPS2Keyboard( )
+{
+ if ( InstallKeyboardMouseAlways ) {
+ return EFI_SUCCESS;
+ } else {
+ return Ps2KbdDetected ? EFI_SUCCESS : EFI_NOT_FOUND;
+ }
+}
+
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: PS2DataDispatcher
+//
+// Description: This fuction checks whether data is available in the PS2
+// controller output buffer. If so, it gives control to the
+// corresponding state machine executor.
+//
+// Parameters: VOID *Context - Pointer to the context for this function
+//
+// Output: None
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID PS2DataDispatcher (
+ VOID *Context )
+{
+ UINT8 data;
+ KEYBOARD *kbd = &gKbd;
+ UINT8 bIndicators;
+
+ bIndicators = kbd->KeyData.KeyState.KeyToggleState & 7; // SCRL/NUM/CPSL
+ if(KbdIrqSupport){
+
+ //
+ // if keyboard irq supported check status of SCRL/NUM/CPSL keys
+ // and send the command to Keyboard to update the LED status
+ //
+ UINT8 bIndicators = kbd->KeyData.KeyState.KeyToggleState & 7;
+ if (bIndicators != kbd->Indicators && kbd->LEDCommandState == 0){
+ LEDsOnOff(kbd);
+ }
+ return;
+ }
+
+ if (InsidePS2DataDispatcher) return;
+ InsidePS2DataDispatcher = TRUE;
+
+ for(data = IoRead8(KBC_CMDSTS_PORT); data & KBC_OBF; data = IoRead8(KBC_CMDSTS_PORT)) {
+ if (data & KBC_AUX_OBF) {
+ DrivePS2MouseMachine(Context);
+ }
+ else {
+ //
+ // Removed the DisableKeyboard() as to read multiple data from port60h,
+ // If any valid key is received we break out of the loop.
+ //
+ DrivePS2KbdMachine(Context);
+ if (CheckKeyinBuffer(kbd) ) {
+ break;
+ }
+ }
+ }
+
+ //
+ // Check LED state before issuing ED command
+ //
+ if (bIndicators != kbd->Indicators && kbd->LEDCommandState == 0) {
+ //
+ // Disable the keyboard before issuing ED command
+ //
+ DisableKeyboard();
+ CheckIssueLEDCmd(kbd);
+ }
+
+ //
+ //Process the led command and data
+ //
+ ProcessLEDCommandData(kbd);
+ EnableKeyboard();
+ InsidePS2DataDispatcher = FALSE;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: CheckIssueLEDCmd
+//
+// Description: This function check if KBD LED command ED needs to be
+// issued.
+// If 'yes', sends ED command. No data is read.
+//
+// Parameters: KEYBOARD *kbd - Pointer to keyboard buffer
+//
+// Output: None
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID CheckIssueLEDCmd (
+ KEYBOARD *Kbd )
+{
+
+ UINT8 bIndicators = Kbd->KeyData.KeyState.KeyToggleState & 7; // SCRL/NUM/CPSL
+
+ if (bIndicators != Kbd->Indicators && Kbd->LEDCommandState == 0) {
+ //
+ // Don't issue LED command when data is pending
+ //
+ if (IoRead8(KBC_CMDSTS_PORT) & KBC_OBF) return;
+ Kbd->LEDCommandState = ED_COMMAND_ISSUED;
+ WriteKeyboardData(0xED);
+ }
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: ProcessKBDResponse
+//
+// Description: If 0xFA is received as data, check for any pending ACK
+// and take necessary action.
+//
+// Parameters: KEYBOARD* kbd - Pointer to keyboard buffer
+// UINT8 bData - Data received from keyboard
+//
+// Output: None
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID ProcessKBDResponse (
+ KEYBOARD *Kbd,
+ UINT8 Data )
+{
+
+ UINT8 bIndicators = Kbd->KeyData.KeyState.KeyToggleState & 7; // SCRL/NUM/CPSL
+
+ switch (Data) {
+ case 0xFA:
+ if (Kbd->LEDCommandState == ED_COMMAND_ISSUED) {
+ Kbd->LEDCommandState = ED_DATA_ISSUED;
+ Kbd->Indicators = bIndicators;
+ WriteKeyboardData(bIndicators);
+ break;
+ }
+
+ if (Kbd->LEDCommandState == ED_DATA_ISSUED) {
+ Kbd->LEDCommandState = 0;
+ break;
+ }
+
+
+ case 0xFE:
+ if (Kbd->LEDCommandState == ED_COMMAND_ISSUED || Kbd->LEDCommandState == ED_DATA_ISSUED) {
+// Error occured. Clear out the current indicator bits.
+// Modifiers will have the correct bits that needs to be set.
+// Next Call to CheckIssueLEDCmd will detect the mismatch
+// and start the LED sequence.
+ WriteKeyboardData(0xF4);
+ Kbd->LEDCommandState = 0;
+ bIndicators = Kbd->KeyData.KeyState.KeyToggleState & 7;
+ Kbd->KeyData.KeyState.KeyToggleState &=
+ ~(SCROLL_LOCK_ACTIVE | NUM_LOCK_ACTIVE | CAPS_LOCK_ACTIVE);
+ Kbd->Indicators &= 0xf0;
+ break;
+ }
+
+ case 0xFF:
+ Kbd->LEDCommandState = 0;
+ break;
+ default: break;
+ }
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: KBCGetData
+//
+// Description: Reads and returns byte of data from KBC data port. Also
+// used as dummy KBC data process routine.
+//
+// Parameters: VOID *Context - Pointer to the context of this function
+//
+// Output: UINT8 Data read from KBC Data port.
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8 KBCGetData ()
+{
+ UINT8 Data;
+ Data = IoRead8(KBC_DATA_PORT);
+
+ return Data;
+}
+
+
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2009, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************