mirror of https://github.com/acidanthera/audk.git
916 lines
20 KiB
C
916 lines
20 KiB
C
/** @file
|
|
PS2 Mouse Communication Interface.
|
|
|
|
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "Ps2Mouse.h"
|
|
#include "CommPs2.h"
|
|
|
|
UINT8 SampleRateTbl[MaxSampleRate] = { 0xa, 0x14, 0x28, 0x3c, 0x50, 0x64, 0xc8 };
|
|
|
|
UINT8 ResolutionTbl[MaxResolution] = { 0, 1, 2, 3 };
|
|
|
|
/**
|
|
Issue self test command via IsaIo interface.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
|
|
@return EFI_SUCCESS Success to do keyboard self testing.
|
|
@return others Fail to do keyboard self testing.
|
|
**/
|
|
EFI_STATUS
|
|
KbcSelfTest (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 Data;
|
|
|
|
//
|
|
// Keyboard controller self test
|
|
//
|
|
Status = Out8042Command (IsaIo, SELF_TEST);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Read return code
|
|
//
|
|
Status = In8042Data (IsaIo, &Data);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (Data != 0x55) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
//
|
|
// Set system flag
|
|
//
|
|
Status = Out8042Command (IsaIo, READ_CMD_BYTE);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = In8042Data (IsaIo, &Data);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = Out8042Command (IsaIo, WRITE_CMD_BYTE);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Data |= CMD_SYS_FLAG;
|
|
Status = Out8042Data (IsaIo, Data);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Issue command to enable keyboard AUX functionality.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
|
|
@return Status of command issuing.
|
|
**/
|
|
EFI_STATUS
|
|
KbcEnableAux (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo
|
|
)
|
|
{
|
|
//
|
|
// Send 8042 enable mouse command
|
|
//
|
|
return Out8042Command (IsaIo, ENABLE_AUX);
|
|
}
|
|
|
|
/**
|
|
Issue command to disable keyboard AUX functionality.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
|
|
@return Status of command issuing.
|
|
**/
|
|
EFI_STATUS
|
|
KbcDisableAux (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo
|
|
)
|
|
{
|
|
//
|
|
// Send 8042 disable mouse command
|
|
//
|
|
return Out8042Command (IsaIo, DISABLE_AUX);
|
|
}
|
|
|
|
/**
|
|
Issue command to enable keyboard.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
|
|
@return Status of command issuing.
|
|
**/
|
|
EFI_STATUS
|
|
KbcEnableKb (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo
|
|
)
|
|
{
|
|
//
|
|
// Send 8042 enable keyboard command
|
|
//
|
|
return Out8042Command (IsaIo, ENABLE_KB);
|
|
}
|
|
|
|
/**
|
|
Issue command to disable keyboard.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
|
|
@return Status of command issuing.
|
|
**/
|
|
EFI_STATUS
|
|
KbcDisableKb (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo
|
|
)
|
|
{
|
|
//
|
|
// Send 8042 disable keyboard command
|
|
//
|
|
return Out8042Command (IsaIo, DISABLE_KB);
|
|
}
|
|
|
|
/**
|
|
Issue command to check keyboard status.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
@param KeyboardEnable return whether keyboard is enable.
|
|
|
|
@return Status of command issuing.
|
|
**/
|
|
EFI_STATUS
|
|
CheckKbStatus (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo,
|
|
OUT BOOLEAN *KeyboardEnable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 Data;
|
|
|
|
//
|
|
// Send command to read KBC command byte
|
|
//
|
|
Status = Out8042Command (IsaIo, READ_CMD_BYTE);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = In8042Data (IsaIo, &Data);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Check keyboard enable or not
|
|
//
|
|
if ((Data & CMD_KB_STS) == CMD_KB_DIS) {
|
|
*KeyboardEnable = FALSE;
|
|
} else {
|
|
*KeyboardEnable = TRUE;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Issue command to reset keyboard.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
|
|
@return Status of command issuing.
|
|
**/
|
|
EFI_STATUS
|
|
PS2MouseReset (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 Data;
|
|
|
|
Status = Out8042AuxCommand (IsaIo, RESET_CMD, FALSE);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = In8042AuxData (IsaIo, &Data);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Check BAT Complete Code
|
|
//
|
|
if (Data != PS2MOUSE_BAT1) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Status = In8042AuxData (IsaIo, &Data);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Check BAT Complete Code
|
|
//
|
|
if (Data != PS2MOUSE_BAT2) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Issue command to set mouse's sample rate
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
@param SampleRate value of sample rate
|
|
|
|
@return Status of command issuing.
|
|
**/
|
|
EFI_STATUS
|
|
PS2MouseSetSampleRate (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo,
|
|
IN MOUSE_SR SampleRate
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Send auxiliary command to set mouse sample rate
|
|
//
|
|
Status = Out8042AuxCommand (IsaIo, SETSR_CMD, FALSE);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = Out8042AuxData (IsaIo, SampleRateTbl[SampleRate]);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Issue command to set mouse's resolution.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
@param Resolution value of resolution
|
|
|
|
@return Status of command issuing.
|
|
**/
|
|
EFI_STATUS
|
|
PS2MouseSetResolution (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo,
|
|
IN MOUSE_RE Resolution
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Send auxiliary command to set mouse resolution
|
|
//
|
|
Status = Out8042AuxCommand (IsaIo, SETRE_CMD, FALSE);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = Out8042AuxData (IsaIo, ResolutionTbl[Resolution]);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Issue command to set mouse's scaling.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
@param Scaling value of scaling
|
|
|
|
@return Status of command issuing.
|
|
**/
|
|
EFI_STATUS
|
|
PS2MouseSetScaling (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo,
|
|
IN MOUSE_SF Scaling
|
|
)
|
|
{
|
|
UINT8 Command;
|
|
|
|
Command = (UINT8) (Scaling == Scaling1 ? SETSF1_CMD : SETSF2_CMD);
|
|
|
|
//
|
|
// Send auxiliary command to set mouse scaling data
|
|
//
|
|
return Out8042AuxCommand (IsaIo, Command, FALSE);
|
|
}
|
|
|
|
/**
|
|
Issue command to enable Ps2 mouse.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
|
|
@return Status of command issuing.
|
|
**/
|
|
EFI_STATUS
|
|
PS2MouseEnable (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo
|
|
)
|
|
{
|
|
//
|
|
// Send auxiliary command to enable mouse
|
|
//
|
|
return Out8042AuxCommand (IsaIo, ENABLE_CMD, FALSE);
|
|
}
|
|
|
|
/**
|
|
Get mouse packet . Only care first 3 bytes
|
|
|
|
@param MouseDev Pointer of PS2 Mouse Private Data Structure
|
|
|
|
@retval EFI_NOT_READY Mouse Device not ready to input data packet, or some error happened during getting the packet
|
|
@retval EFI_SUCCESS The data packet is gotten successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
PS2MouseGetPacket (
|
|
PS2_MOUSE_DEV *MouseDev
|
|
)
|
|
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN KeyboardEnable;
|
|
UINT8 Packet[PS2_PACKET_LENGTH];
|
|
UINT8 Data;
|
|
UINTN Count;
|
|
UINTN State;
|
|
INT16 RelativeMovementX;
|
|
INT16 RelativeMovementY;
|
|
BOOLEAN LButton;
|
|
BOOLEAN RButton;
|
|
|
|
KeyboardEnable = FALSE;
|
|
Count = 1;
|
|
State = PS2_READ_BYTE_ONE;
|
|
|
|
//
|
|
// State machine to get mouse packet
|
|
//
|
|
while (1) {
|
|
|
|
switch (State) {
|
|
case PS2_READ_BYTE_ONE:
|
|
//
|
|
// Read mouse first byte data, if failed, immediately return
|
|
//
|
|
KbcDisableAux (MouseDev->IsaIo);
|
|
Status = PS2MouseRead (MouseDev->IsaIo, &Data, &Count, State);
|
|
if (EFI_ERROR (Status)) {
|
|
KbcEnableAux (MouseDev->IsaIo);
|
|
return EFI_NOT_READY;
|
|
}
|
|
|
|
if (Count != 1) {
|
|
KbcEnableAux (MouseDev->IsaIo);
|
|
return EFI_NOT_READY;
|
|
}
|
|
|
|
if (IS_PS2_SYNC_BYTE (Data)) {
|
|
Packet[0] = Data;
|
|
State = PS2_READ_DATA_BYTE;
|
|
|
|
CheckKbStatus (MouseDev->IsaIo, &KeyboardEnable);
|
|
KbcDisableKb (MouseDev->IsaIo);
|
|
KbcEnableAux (MouseDev->IsaIo);
|
|
}
|
|
break;
|
|
|
|
case PS2_READ_DATA_BYTE:
|
|
Count = 2;
|
|
Status = PS2MouseRead (MouseDev->IsaIo, (Packet + 1), &Count, State);
|
|
if (EFI_ERROR (Status)) {
|
|
if (KeyboardEnable) {
|
|
KbcEnableKb (MouseDev->IsaIo);
|
|
}
|
|
|
|
return EFI_NOT_READY;
|
|
}
|
|
|
|
if (Count != 2) {
|
|
if (KeyboardEnable) {
|
|
KbcEnableKb (MouseDev->IsaIo);
|
|
}
|
|
|
|
return EFI_NOT_READY;
|
|
}
|
|
|
|
State = PS2_PROCESS_PACKET;
|
|
break;
|
|
|
|
case PS2_PROCESS_PACKET:
|
|
if (KeyboardEnable) {
|
|
KbcEnableKb (MouseDev->IsaIo);
|
|
}
|
|
//
|
|
// Decode the packet
|
|
//
|
|
RelativeMovementX = Packet[1];
|
|
RelativeMovementY = Packet[2];
|
|
//
|
|
// Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0
|
|
// Byte 0 | Y overflow | X overflow | Y sign bit | X sign bit | Always 1 | Middle Btn | Right Btn | Left Btn
|
|
// Byte 1 | 8 bit X Movement
|
|
// Byte 2 | 8 bit Y Movement
|
|
//
|
|
// X sign bit + 8 bit X Movement : 9-bit signed twos complement integer that presents the relative displacement of the device in the X direction since the last data transmission.
|
|
// Y sign bit + 8 bit Y Movement : Same as X sign bit + 8 bit X Movement.
|
|
//
|
|
//
|
|
// First, Clear X and Y high 8 bits
|
|
//
|
|
RelativeMovementX = (INT16) (RelativeMovementX & 0xFF);
|
|
RelativeMovementY = (INT16) (RelativeMovementY & 0xFF);
|
|
//
|
|
// Second, if the 9-bit signed twos complement integer is negative, set the high 8 bit 0xff
|
|
//
|
|
if ((Packet[0] & 0x10) != 0) {
|
|
RelativeMovementX = (INT16) (RelativeMovementX | 0xFF00);
|
|
}
|
|
if ((Packet[0] & 0x20) != 0) {
|
|
RelativeMovementY = (INT16) (RelativeMovementY | 0xFF00);
|
|
}
|
|
|
|
|
|
RButton = (UINT8) (Packet[0] & 0x2);
|
|
LButton = (UINT8) (Packet[0] & 0x1);
|
|
|
|
//
|
|
// Update mouse state
|
|
//
|
|
MouseDev->State.RelativeMovementX += RelativeMovementX;
|
|
MouseDev->State.RelativeMovementY -= RelativeMovementY;
|
|
MouseDev->State.RightButton = (UINT8) (RButton ? TRUE : FALSE);
|
|
MouseDev->State.LeftButton = (UINT8) (LButton ? TRUE : FALSE);
|
|
MouseDev->StateChanged = TRUE;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Read data via IsaIo protocol with given number.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
@param Buffer Buffer receive data of mouse
|
|
@param BufSize The size of buffer
|
|
@param State Check input or read data
|
|
|
|
@return status of reading mouse data.
|
|
**/
|
|
EFI_STATUS
|
|
PS2MouseRead (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo,
|
|
OUT VOID *Buffer,
|
|
IN OUT UINTN *BufSize,
|
|
IN UINTN State
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN BytesRead;
|
|
|
|
Status = EFI_SUCCESS;
|
|
BytesRead = 0;
|
|
|
|
if (State == PS2_READ_BYTE_ONE) {
|
|
//
|
|
// Check input for mouse
|
|
//
|
|
Status = CheckForInput (IsaIo);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
while (BytesRead < *BufSize) {
|
|
|
|
Status = WaitOutputFull (IsaIo, TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Buffer);
|
|
|
|
BytesRead++;
|
|
Buffer = (UINT8 *) Buffer + 1;
|
|
}
|
|
//
|
|
// Verify the correct number of bytes read
|
|
//
|
|
if (BytesRead == 0 || BytesRead != *BufSize) {
|
|
Status = EFI_NOT_FOUND;
|
|
}
|
|
|
|
*BufSize = BytesRead;
|
|
return Status;
|
|
}
|
|
//
|
|
// 8042 I/O function
|
|
//
|
|
/**
|
|
I/O work flow of outing 8042 command.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
@param Command I/O command.
|
|
|
|
@retval EFI_SUCCESS Success to execute I/O work flow
|
|
@retval EFI_TIMEOUT Keyboard controller time out.
|
|
**/
|
|
EFI_STATUS
|
|
Out8042Command (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo,
|
|
IN UINT8 Command
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 Data;
|
|
|
|
//
|
|
// Wait keyboard controller input buffer empty
|
|
//
|
|
Status = WaitInputEmpty (IsaIo, TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Send command
|
|
//
|
|
Data = Command;
|
|
IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
|
|
|
|
Status = WaitInputEmpty (IsaIo, TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
I/O work flow of outing 8042 data.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
@param Data Data value
|
|
|
|
@retval EFI_SUCCESS Success to execute I/O work flow
|
|
@retval EFI_TIMEOUT Keyboard controller time out.
|
|
**/
|
|
EFI_STATUS
|
|
Out8042Data (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo,
|
|
IN UINT8 Data
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 Temp;
|
|
//
|
|
// Wait keyboard controller input buffer empty
|
|
//
|
|
Status = WaitInputEmpty (IsaIo, TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Temp = Data;
|
|
IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Temp);
|
|
|
|
Status = WaitInputEmpty (IsaIo, TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
I/O work flow of in 8042 data.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
@param Data Data value
|
|
|
|
@retval EFI_SUCCESS Success to execute I/O work flow
|
|
@retval EFI_TIMEOUT Keyboard controller time out.
|
|
**/
|
|
EFI_STATUS
|
|
In8042Data (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo,
|
|
IN OUT UINT8 *Data
|
|
)
|
|
{
|
|
UINTN Delay;
|
|
UINT8 Temp;
|
|
|
|
Delay = TIMEOUT / 50;
|
|
|
|
do {
|
|
IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Temp);
|
|
|
|
//
|
|
// Check keyboard controller status bit 0(output buffer status)
|
|
//
|
|
if ((Temp & KBC_OUTB) == KBC_OUTB) {
|
|
break;
|
|
}
|
|
|
|
gBS->Stall (50);
|
|
Delay--;
|
|
} while (Delay != 0);
|
|
|
|
if (Delay == 0) {
|
|
return EFI_TIMEOUT;
|
|
}
|
|
|
|
IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Data);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
I/O work flow of outing 8042 Aux command.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
@param Command Aux I/O command
|
|
@param Resend Whether need resend the Aux command.
|
|
|
|
@retval EFI_SUCCESS Success to execute I/O work flow
|
|
@retval EFI_TIMEOUT Keyboard controller time out.
|
|
**/
|
|
EFI_STATUS
|
|
Out8042AuxCommand (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo,
|
|
IN UINT8 Command,
|
|
IN BOOLEAN Resend
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 Data;
|
|
|
|
//
|
|
// Wait keyboard controller input buffer empty
|
|
//
|
|
Status = WaitInputEmpty (IsaIo, TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Send write to auxiliary device command
|
|
//
|
|
Data = WRITE_AUX_DEV;
|
|
IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
|
|
|
|
Status = WaitInputEmpty (IsaIo, TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Send auxiliary device command
|
|
//
|
|
IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Command);
|
|
|
|
//
|
|
// Read return code
|
|
//
|
|
Status = In8042AuxData (IsaIo, &Data);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (Data == PS2_ACK) {
|
|
//
|
|
// Receive mouse acknowledge, command send success
|
|
//
|
|
return EFI_SUCCESS;
|
|
|
|
} else if (Resend) {
|
|
//
|
|
// Resend fail
|
|
//
|
|
return EFI_DEVICE_ERROR;
|
|
|
|
} else if (Data == PS2_RESEND) {
|
|
//
|
|
// Resend command
|
|
//
|
|
Status = Out8042AuxCommand (IsaIo, Command, TRUE);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Invalid return code
|
|
//
|
|
return EFI_DEVICE_ERROR;
|
|
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
I/O work flow of outing 8042 Aux data.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
@param Data Buffer holding return value
|
|
|
|
@retval EFI_SUCCESS Success to execute I/O work flow
|
|
@retval EFI_TIMEOUT Keyboard controller time out.
|
|
**/
|
|
EFI_STATUS
|
|
Out8042AuxData (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo,
|
|
IN UINT8 Data
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 Temp;
|
|
//
|
|
// Wait keyboard controller input buffer empty
|
|
//
|
|
Status = WaitInputEmpty (IsaIo, TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Send write to auxiliary device command
|
|
//
|
|
Temp = WRITE_AUX_DEV;
|
|
IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Temp);
|
|
|
|
Status = WaitInputEmpty (IsaIo, TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Temp = Data;
|
|
IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Temp);
|
|
|
|
Status = WaitInputEmpty (IsaIo, TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
I/O work flow of in 8042 Aux data.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
@param Data Buffer holding return value.
|
|
|
|
@retval EFI_SUCCESS Success to execute I/O work flow
|
|
@retval EFI_TIMEOUT Keyboard controller time out.
|
|
**/
|
|
EFI_STATUS
|
|
In8042AuxData (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo,
|
|
IN OUT UINT8 *Data
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// wait for output data
|
|
//
|
|
Status = WaitOutputFull (IsaIo, BAT_TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Data);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Check keyboard controller status, if it is output buffer full and for auxiliary device.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
|
|
@retval EFI_SUCCESS Keyboard controller is ready
|
|
@retval EFI_NOT_READY Keyboard controller is not ready
|
|
**/
|
|
EFI_STATUS
|
|
CheckForInput (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo
|
|
)
|
|
{
|
|
UINT8 Data;
|
|
|
|
IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
|
|
|
|
//
|
|
// Check keyboard controller status, if it is output buffer full and for auxiliary device
|
|
//
|
|
if ((Data & (KBC_OUTB | KBC_AUXB)) != (KBC_OUTB | KBC_AUXB)) {
|
|
return EFI_NOT_READY;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
I/O work flow to wait input buffer empty in given time.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
@param Timeout Wating time.
|
|
|
|
@retval EFI_TIMEOUT if input is still not empty in given time.
|
|
@retval EFI_SUCCESS input is empty.
|
|
**/
|
|
EFI_STATUS
|
|
WaitInputEmpty (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo,
|
|
IN UINTN Timeout
|
|
)
|
|
{
|
|
UINTN Delay;
|
|
UINT8 Data;
|
|
|
|
Delay = Timeout / 50;
|
|
|
|
do {
|
|
IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
|
|
|
|
//
|
|
// Check keyboard controller status bit 1(input buffer status)
|
|
//
|
|
if ((Data & KBC_INPB) == 0) {
|
|
break;
|
|
}
|
|
|
|
gBS->Stall (50);
|
|
Delay--;
|
|
} while (Delay != 0);
|
|
|
|
if (Delay == 0) {
|
|
return EFI_TIMEOUT;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
I/O work flow to wait output buffer full in given time.
|
|
|
|
@param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
|
|
@param Timeout given time
|
|
|
|
@retval EFI_TIMEOUT output is not full in given time
|
|
@retval EFI_SUCCESS output is full in given time.
|
|
**/
|
|
EFI_STATUS
|
|
WaitOutputFull (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo,
|
|
IN UINTN Timeout
|
|
)
|
|
{
|
|
UINTN Delay;
|
|
UINT8 Data;
|
|
|
|
Delay = Timeout / 50;
|
|
|
|
do {
|
|
IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
|
|
|
|
//
|
|
// Check keyboard controller status bit 0(output buffer status)
|
|
// & bit5(output buffer for auxiliary device)
|
|
//
|
|
if ((Data & (KBC_OUTB | KBC_AUXB)) == (KBC_OUTB | KBC_AUXB)) {
|
|
break;
|
|
}
|
|
|
|
gBS->Stall (50);
|
|
Delay--;
|
|
} while (Delay != 0);
|
|
|
|
if (Delay == 0) {
|
|
return EFI_TIMEOUT;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|