⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ps2port.cpp

📁 三星2410的BSP开发包
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*

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.

*/

#include <windows.h>
#include <ceddk.h>

#include "ps2port.hpp"

// dpCurSettings is in kbdist.c
#define ZONE_ASSERT             DEBUGZONE(16)

DWORD gdwIoBase = 0;

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;
static const UINT8 cmdByteEnableXTTranslation	= 0x40;

//
// 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 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 ( 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 ( 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 waiting for output buffer full.\r\n")));
				ASSERT(!ZONE_ASSERT);
				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 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 InputBufferPut.\r\n")));
		ASSERT(0);
		}

	if ( !InputBufPollForEmpty() )
		{
		goto leave;
		}
	InputBufWrite(ui8Data);
	bRet = true;

leave:
	return bRet;
}




/*++

Ps2Port::
SelfTest:

Writes the self test command to the 8042 and reads the response.

Returns true if the success response is read from the 8042.


--*/
bool
Ps2Port::
SelfTest(
	void
	)
{
	bool	bRet = false;
	UINT8	ui8Data;


	EnterWrite();

	if ( !CommandPut(cmd8042SelfTest) )
		{
		goto leave;
		}
	
	if ( !OutputBufPollRead(&ui8Data) )
		{
		goto leave;
		}
	if ( ui8Data != 0x55 )
		{
		ASSERT(0);
		goto leave;
		}


	bRet = true;

leave:
	if ( !bRet )
		{
		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -