ps2port.cpp
来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C++ 代码 · 共 832 行 · 第 1/2 页
CPP
832 行
/* -*-C-*-
*
* $Revision: 1.1 $
* $Author: kwelton $
* $Date: 2000/04/12 00:50:42 $
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
* Copyright (c) 1995-1998 Microsoft Corporation
* Copyright (c) 2000 ARM Limited
* All Rights Reserved
*/
#include <windows.h>
#include <ceddk.h>
#include "ps2port.hpp"
static const unsigned int msPollLimit = 5000; // 5 seconds.
// Alternate and Output Buffer Full Table
//
// ABF OBF
// 0 0 output buf empty (data not valid)
// 0 1 output buffer has keyboard or command data
// 1 0 output buf empty (data not valid)
// 1 1 output buffer has auxilliary (mouse) data
//
// Commands sent to the 8042 command register.
//
static const UINT8 cmd8042ReadModeByte = 0x20;
static const UINT8 cmd8042WriteModeByte = 0x60;
static const UINT8 cmd8042SelfTest = 0xAA;
static const UINT8 cmd8042KeyboardInterfaceTest = 0xAB;
static const UINT8 cmd8042AuxDeviceWrite = 0xD4;
//
// Flags for the 8042 mode byte. Used by the read mode and write mode
// commands.
//
static const UINT8 cmdByteEnableAuxInterrupts = 0x02;
static const UINT8 cmdByteEnableKeybdInterrupts = 0x01;
static const UINT8 cmdByteDisableKeybdInterface = 0x10;
static const UINT8 cmdByteDisableAuxInterface = 0x20;
//
// Commands sent to the keyboard.
//
static const UINT8 cmdKeybdReset = 0xFF;
static const UINT8 cmdKeybdLights = 0xED;
//
// Commands sent to the mouse.
//
static const UINT8 cmdMouseReadId = 0xF2;
static const UINT8 cmdMouseSetReportRate = 0xF3;
static const UINT8 cmdMouseEnable = 0xF4;
//
// Status register flags.
//
static const UINT8 sts8042OutputBufFull = 0x01;
static const UINT8 sts8042InputBufFull = 0x02;
static const UINT8 sts8042OutputBufIsAux = 0x20;
//
// Status flags combinations for checking the output buffer full status.
//
static const UINT8 sts8042ObfFlags = 0x21;
static const UINT8 sts8042ObfMain = 0x01;
static const UINT8 sts8042ObfAux = 0x21;
//
// Mouse and Keyboard Response
//
static const UINT8 response8042Ack = 0xFA;
static const UINT8 response8042Resend = 0xFE;
static const UINT8 response8042IntelliMouseId = 0x03;
/**********************************************************************/
/*
* Ps2Port::MainOutputBufIsFull
*
* Returns true if the main output buffer is full.
*/
inline bool Ps2Port::MainOutputBufIsFull(void)
{
return (ui8StatusRead() & sts8042ObfFlags) == sts8042ObfMain;
}
/*
* Ps2Port::AuxOutputBufIsFull
*
* Returns true if the auxiliary output buffer is full.
*/
inline bool Ps2Port::AuxOutputBufIsFull(void)
{
return (ui8StatusRead() & sts8042ObfFlags) == sts8042ObfAux;
}
/*
* Ps2Port::InputBufPollForEmpty
*
* SPINS waiting for the input buffer to go empty. Returns true if the
* buffer is empty, false if the buffer did not go empty. Remember that input
* means input of the 8042, not the PC.
*/
bool Ps2Port::InputBufPollForEmpty(void)
{
bool bRet = false;
UINT8 ui8Status;
unsigned int msStart;
unsigned int msEnd;
// Poll while the input buffer is full
ui8Status = ui8StatusRead();
if (ui8Status & sts8042InputBufFull)
{
msStart = GetTickCount();
for (;;)
{
Sleep(0); // Time passes.
// See if buffer is still full.
ui8Status = ui8StatusRead();
if (ui8Status & sts8042InputBufFull)
{
//
// If still full, check elapsed time.
// Unsigned arithmetic deals with timer rollover.
//
msEnd = GetTickCount();
if ((msEnd - msStart) > msPollLimit)
{
ERRORMSG(1,(TEXT("Ps2Port::InputBufPollForEmpty: too long")
TEXT(" waiting for input buffer empty.\r\n")));
break;
}
}
else
{
bRet = true;
break;
}
}
}
else
bRet = true;
return bRet;
}
/*
* Ps2Port::OutputBufPollRead
*
* SPINS waiting for the output buffer to go full and then reads the data
* from the output buffer. Returns true if the buffer goes full, false if
* the buffer never goes full. Remember that output means output of the
* 8042, not the PC.
*/
bool Ps2Port::OutputBufPollRead(UINT8 *pui8)
{
bool bRet = false;
UINT8 ui8Status;
unsigned int msStart;
unsigned int msEnd;
// Check for data ready first.
ui8Status = ui8StatusRead();
#if 0
DEBUGMSG(1, (TEXT("status = 0x%X\r\n"), ui8Status));
#endif /* 0/1 */
if (ui8Status & sts8042OutputBufFull)
bRet = true;
else
{
// Start polling if output data not ready.
msStart = GetTickCount();
for (;;)
{
Sleep(0); // Time passes.
// Check for data again.
ui8Status = ui8StatusRead();
#if 0
DEBUGMSG(1, (TEXT("status2 = 0x%X\r\n"), ui8Status));
#endif /* 0/1 */
if (ui8Status & sts8042OutputBufFull)
{
bRet = true;
break;
}
// Check elapsed time.
// Unsigned arithmetic deals with timer rollover.
msEnd = GetTickCount();
if ((msEnd - msStart) > msPollLimit)
{
ERRORMSG(1,(TEXT("Ps2Port::OutputBufPollRead: too long ")
TEXT("waiting for output buffer full.\r\n")));
#if 0
ASSERT(0);
#endif /* 0/1 */
break;
}
}
}
// May as well read it even if we failed.
*pui8 = ui8OutputBufRead();
return bRet;
}
/*
* Ps2Port::EnterWrite:
*
* Must be called before writing data which is to be sent to the keyboard or
* mouse. Takes the write critical section if successful.
*
* Disables the keyboard and auxiliary interrupts.
*
* Disables the keyboard and auxiliary interfaces.
*
* May be called multiple times but only the first caller actually does the
* disabling.
*
* A count is kept to verify that the number of calls to LeaveWrite match the
* number of calls to EnterWrite.
*
* Returns true if successful, false if there is an error. If there is an
* error, the write critical section is not held.
*/
bool Ps2Port::EnterWrite(void)
{
UINT8 ui8CmdByte;
// Only one writer at a time.
EnterCriticalSection(&m_csWrite);
// If we are already in, we're done.
if (m_cEnterWrites++)
goto leave_success;
/*
* There does not seem to be any command to control the interrupt
* enable bits in the command byte. We cannot read the command
* byte since if the ints are enabled, the isr will pick up the
* data before we can get to it by polling. We can either coordinate
* with the keyboard isr or keep the command byte independently. I chose
* to keep the command byte independently so that we can still work
* even if something is wrong with the keyboard isr. This means however
* that we can't use the other commands for enabling the interfaces. We
* will need to modify these command byte bits directly also.
*/
ui8CmdByte = m_ui8CmdByte;
/*
* Disable the interface first. Note that we are changing the local copy
* of the command byte, not the member variable.
*/
ui8CmdByte |= cmdByteDisableKeybdInterface | cmdByteDisableAuxInterface;
// Write command byte directly.
if (!InputBufPollForEmpty())
{
ASSERT(0);
goto leave_fail;
}
CommandWrite(cmd8042WriteModeByte);
InputBufPut(ui8CmdByte);
// Wait for any data in the pipeline to finish. Most of the
// timings are on the order of 10's of microseconds, so 10
// milliseconds should be enough.
Sleep(10);
// Read any junk data.
ui8OutputBufRead();
// Now disable the interrupts.
ui8CmdByte &= ~(cmdByteEnableAuxInterrupts | cmdByteEnableKeybdInterrupts);
// Write the command byte directly.
if (!InputBufPollForEmpty())
{
ASSERT(0);
goto leave_fail;
}
CommandWrite(cmd8042WriteModeByte);
InputBufPut(ui8CmdByte);
leave_success:
// Keep the critical section if we succeed.
return true;
leave_fail:
// Don't hold the critical section if we fail.
m_cEnterWrites--;
LeaveCriticalSection(&m_csWrite);
return false;
}
/*
* Ps2Port::LeaveWrite
*
* Counterpart to EnterWrite. The last caller to LeaveWrite re-enables the
* interrupts and interfaces.
*
* Returns true if successful.
*/
bool Ps2Port::LeaveWrite(void)
{
bool bRet = false;
// Haven't really seen this but it's worth checking.
if (m_cEnterWrites == 0)
{
ERRORMSG(1,(TEXT("LeaveWrite: too many calls to LeaveWrite.\r\n")));
return bRet;
}
// Last one out turns everything back on.
if (m_cEnterWrites != 1)
{
bRet = true;
goto leave;
}
// Write command byte by sending command and writing.
if (!InputBufPollForEmpty())
{
ERRORMSG(1,(TEXT("LeaveWrite: too long waiting for input buffer ")
TEXT("to empty (2).\r\n")));
goto leave;
}
CommandWrite(cmd8042WriteModeByte);
InputBufPut(m_ui8CmdByte);
bRet = true;
leave:
--m_cEnterWrites;
LeaveCriticalSection(&m_csWrite);
return bRet;
}
/*
* Ps2Port::CommandPut
*
* Puts a command in the 8042 command register. Calls EnterWrite/ExitWrite.
*
* Returns true if successful.
*/
bool Ps2Port::CommandPut(UINT8 cmd8042)
{
bool bRet = false;
EnterWrite();
if (!InputBufPollForEmpty())
goto leave;
CommandWrite(cmd8042);
bRet = true;
leave:
LeaveWrite();
return bRet;
}
/*
* Ps2Port::InputBufPut
*
* Puts data in the 8042 input buffer. Caller must have called EnterWrite
* before calling.
*
* Returns true if successful.
*/
bool Ps2Port::InputBufPut(UINT8 ui8Data)
{
bool bRet = false;
if (!m_cEnterWrites)
{
ERRORMSG(1,(TEXT("Did not use EnterWrite before calling ")
TEXT("InputBufferPut.\r\n")));
ASSERT(0);
}
if (!InputBufPollForEmpty())
goto leave;
InputBufWrite(ui8Data);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?