/** @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 #include #include #include #include //[-start-191225-IB16740000-add]// for PCI_DEVICE_NUMBER_PCH_LPC & PCI_FUNCTION_NUMBER_PCH_XHCI define #include //[-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; }