311 lines
6.7 KiB
C
311 lines
6.7 KiB
C
/** @file
|
|
DXE Chipset Services Library.
|
|
|
|
This file contains only one function that is DxeCsSvcSetIsaInfo().
|
|
The function DxeCsSvcSetIsaInfo() use chipset services to set ISA
|
|
information for common ISA driver utilization.
|
|
|
|
;***************************************************************************
|
|
;* Copyright (c) 2018, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
|
|
#include <Library/IoLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Protocol/PlatformNvsArea.h>
|
|
#include <Register/PchRegs.h>
|
|
#include <Register/PchRegsLpc.h>
|
|
//[-start-191225-IB16740000-add]// for PCI_DEVICE_NUMBER_PCH_LPC & PCI_FUNCTION_NUMBER_PCH_XHCI define
|
|
#include <PchBdfAssignment.h>
|
|
//[-end-191225-IB16740000-add]//
|
|
#define TIMEOUT 50000
|
|
#define STALL_UNIT 50
|
|
#define KBC_DATA_PORT 0x60
|
|
#define KBC_CMD_STS_PORT 0x64
|
|
#define DISABLE_KB 0xad
|
|
#define ENABLE_KB 0xae
|
|
#define KBC_OUTB 0x01
|
|
#define KBC_AUXB 0x20
|
|
#define KBC_INPB 0x02
|
|
#define KB_DEVICE_CHECK 0xEE
|
|
/**
|
|
To set ISA information for common ISA driver utilization.
|
|
|
|
@param[in, out] Function ISA function value
|
|
@param[in, out] Device ISA device value
|
|
|
|
@retval EFI_SUCCESS This function always return successfully.
|
|
*/
|
|
EFI_STATUS
|
|
SetIsaInfo (
|
|
IN OUT UINT8 *Function,
|
|
IN OUT UINT8 *Device
|
|
)
|
|
{
|
|
*Device = (UINT8)PCI_DEVICE_NUMBER_PCH_LPC;
|
|
*Function = (UINT8)PCI_FUNCTION_NUMBER_PCH_LPC;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
I/O work flow to wait output buffer full in given time.
|
|
|
|
@param Timeout given time
|
|
@param Keyboard: TRUE is PS2 keyboard, FALSE is PS2 mouse.
|
|
|
|
@retval EFI_TIMEOUT output is not full in given time
|
|
@retval EFI_SUCCESS output is full in given time.
|
|
*/
|
|
EFI_STATUS
|
|
WaitOutputFull (
|
|
IN UINTN Timeout,
|
|
IN BOOLEAN Keyboard
|
|
)
|
|
{
|
|
UINTN Delay;
|
|
UINT8 Data;
|
|
|
|
Delay = Timeout / 50;
|
|
|
|
do {
|
|
Data = IoRead8 (KBC_CMD_STS_PORT);
|
|
|
|
if (Keyboard) {
|
|
//
|
|
// Check keyboard controller status
|
|
// BIT0 1: output buffer full (ready to read)
|
|
// BIT5 0: the data in output buffer is not mouse data.
|
|
//
|
|
if ((Data & KBC_OUTB) == KBC_OUTB && (Data & KBC_AUXB) != KBC_AUXB) {
|
|
break;
|
|
}
|
|
} else {
|
|
//
|
|
// Check keyboard controller status bit 0(output buffer status)
|
|
// BIT0 1: output buffer full (ready to read)
|
|
// BIT5 1: the data in output buffer is mouse data.
|
|
//
|
|
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;
|
|
}
|
|
|
|
/**
|
|
I/O work flow to wait output buffer empty in given time.
|
|
|
|
@param Timeout given time
|
|
|
|
@retval EFI_TIMEOUT output is not empty in given time
|
|
@retval EFI_SUCCESS output is empty in given time.
|
|
**/
|
|
EFI_STATUS
|
|
WaitOutputEmpty (
|
|
IN UINTN Timeout
|
|
)
|
|
{
|
|
UINTN Delay;
|
|
UINT8 Data;
|
|
|
|
Delay = Timeout / 50;
|
|
|
|
do {
|
|
Data = IoRead8 (KBC_CMD_STS_PORT);
|
|
|
|
//
|
|
// Check keyboard controller status bit 0(output buffer status)
|
|
//
|
|
if ((Data & KBC_OUTB) == 0) {
|
|
break;
|
|
}
|
|
|
|
Data = IoRead8 (KBC_DATA_PORT);
|
|
|
|
gBS->Stall (50);
|
|
Delay--;
|
|
} while (Delay);
|
|
|
|
if (Delay == 0) {
|
|
return EFI_TIMEOUT;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
I/O work flow to wait input buffer empty in given time.
|
|
|
|
@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 UINTN Timeout
|
|
)
|
|
{
|
|
UINTN Delay;
|
|
UINT8 Data;
|
|
|
|
Delay = Timeout / STALL_UNIT;
|
|
|
|
do {
|
|
Data = IoRead8 (KBC_CMD_STS_PORT);
|
|
|
|
//
|
|
// Check keyboard controller status bit 1(input buffer status)
|
|
//
|
|
if ((Data & KBC_INPB) == 0) {
|
|
break;
|
|
}
|
|
|
|
gBS->Stall (STALL_UNIT);
|
|
Delay--;
|
|
} while (Delay != 0);
|
|
|
|
if (Delay == 0) {
|
|
return EFI_TIMEOUT;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
I/O work flow of outing 8042 command.
|
|
|
|
@param Command I/O command.
|
|
|
|
@retval EFI_SUCCESS Success to excute I/O work flow
|
|
@retval EFI_TIMEOUT Keyboard controller time out.
|
|
**/
|
|
EFI_STATUS
|
|
Out8042Command (
|
|
IN UINT8 Command
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 Data;
|
|
|
|
//
|
|
// Wait keyboard controller input buffer empty
|
|
//
|
|
Status = WaitInputEmpty (TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Send command
|
|
//
|
|
Data = Command;
|
|
IoWrite8 (KBC_CMD_STS_PORT, Data);
|
|
|
|
Status = WaitInputEmpty (TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
BOOLEAN
|
|
IsPs2KeyBoardConnected (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 Data;
|
|
EFI_TPL OldTpl;
|
|
|
|
Data = 0;
|
|
|
|
//
|
|
// We will raise TPL to avoid mouse impacts this detection.
|
|
//
|
|
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
|
|
|
|
//
|
|
// Disable "PS2 keyboard key-in action" during the detection (because any input will overwrite port 0x60 outdata)
|
|
//
|
|
Status = WaitInputEmpty (TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Exit_detect;
|
|
}
|
|
IoWrite8 (KBC_CMD_STS_PORT, DISABLE_KB);
|
|
|
|
//
|
|
// Send 0xEE to ckeck whether PS2 keyboard is attached on the PS2 slot or not
|
|
//
|
|
Status = WaitInputEmpty (TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Exit_detect;
|
|
}
|
|
IoWrite8 (KBC_DATA_PORT, KB_DEVICE_CHECK);
|
|
|
|
//
|
|
// Get result
|
|
//
|
|
Status = WaitOutputFull (TIMEOUT, TRUE);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Exit_detect;
|
|
}
|
|
Data = IoRead8 (KBC_DATA_PORT);
|
|
|
|
//
|
|
// Enable PS2 keyboard after the detection
|
|
//
|
|
Status = WaitInputEmpty (TIMEOUT);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Exit_detect;
|
|
}
|
|
IoWrite8 (KBC_CMD_STS_PORT, ENABLE_KB);
|
|
|
|
|
|
Exit_detect:
|
|
//
|
|
// Restore TPL before exiting the mechanism
|
|
//
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
//
|
|
// If the Keyboard is connected and not broken, 0xEE will be returned.
|
|
// Returned situation:
|
|
// 1. 0xEE: PS/2 keyboard attached
|
|
// 2. 0xFE: Re-send is required
|
|
// 3. Others: NO PS/2 keyboard (each MB will have the different return)
|
|
//
|
|
if (Data == 0xEE) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
EFIAPI
|
|
UpdatePs2KBStatus (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
PLATFORM_NVS_AREA *mPlatformNvsArea;
|
|
mPlatformNvsArea = (PLATFORM_NVS_AREA *) Context;
|
|
}
|