https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com>
		
			
				
	
	
		
			918 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			918 lines
		
	
	
		
			21 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 "Ps2MouseAbsolutePointer.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 MouseAbsolutePointerDev  Pointer to PS2 Absolute Pointer Simulation Device 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_ABSOLUTE_POINTER_DEV     *MouseAbsolutePointerDev
 | 
						|
  )
 | 
						|
 | 
						|
{
 | 
						|
  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 (MouseAbsolutePointerDev->IsaIo);
 | 
						|
      Status = PS2MouseRead (MouseAbsolutePointerDev->IsaIo, &Data, &Count, State);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        KbcEnableAux (MouseAbsolutePointerDev->IsaIo);
 | 
						|
        return EFI_NOT_READY;
 | 
						|
      }
 | 
						|
 | 
						|
      if (Count != 1) {
 | 
						|
        KbcEnableAux (MouseAbsolutePointerDev->IsaIo);
 | 
						|
        return EFI_NOT_READY;
 | 
						|
      }
 | 
						|
 | 
						|
      if (IS_PS2_SYNC_BYTE (Data)) {
 | 
						|
        Packet[0] = Data;
 | 
						|
        State     = PS2_READ_DATA_BYTE;
 | 
						|
 | 
						|
        CheckKbStatus (MouseAbsolutePointerDev->IsaIo, &KeyboardEnable);
 | 
						|
        KbcDisableKb (MouseAbsolutePointerDev->IsaIo);
 | 
						|
        KbcEnableAux (MouseAbsolutePointerDev->IsaIo);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    case PS2_READ_DATA_BYTE:
 | 
						|
      Count   = 2;
 | 
						|
      Status  = PS2MouseRead (MouseAbsolutePointerDev->IsaIo, (Packet + 1), &Count, State);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        if (KeyboardEnable) {
 | 
						|
          KbcEnableKb (MouseAbsolutePointerDev->IsaIo);
 | 
						|
        }
 | 
						|
 | 
						|
        return EFI_NOT_READY;
 | 
						|
      }
 | 
						|
 | 
						|
      if (Count != 2) {
 | 
						|
        if (KeyboardEnable) {
 | 
						|
          KbcEnableKb (MouseAbsolutePointerDev->IsaIo);
 | 
						|
        }
 | 
						|
 | 
						|
        return EFI_NOT_READY;
 | 
						|
      }
 | 
						|
 | 
						|
      State = PS2_PROCESS_PACKET;
 | 
						|
      break;
 | 
						|
 | 
						|
    case PS2_PROCESS_PACKET:
 | 
						|
      if (KeyboardEnable) {
 | 
						|
        KbcEnableKb (MouseAbsolutePointerDev->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
 | 
						|
      //
 | 
						|
      MouseAbsolutePointerDev->State.CurrentX += RelativeMovementX;
 | 
						|
      MouseAbsolutePointerDev->State.CurrentY -= RelativeMovementY;
 | 
						|
      MouseAbsolutePointerDev->State.CurrentZ = 0;
 | 
						|
      MouseAbsolutePointerDev->State.ActiveButtons = (UINT8) (LButton || RButton) & 0x3;
 | 
						|
      MouseAbsolutePointerDev->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;
 | 
						|
}
 | 
						|
 |