Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

424 lines
14 KiB

//**************************************************************************
//
// PORTIO.C -- Xena Gaming Project
//
// Version 3.XX
//
// Copyright (c) 1997 Microsoft Corporation. All rights reserved.
//
// @doc
// @module PORTIO.C | Gameport Input/Output Routines
//**************************************************************************
#include "msgame.h"
//---------------------------------------------------------------------------
// Alloc_text pragma to specify routines that can be paged out.
//---------------------------------------------------------------------------
#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, PORTIO_DriverEntry)
#endif
//---------------------------------------------------------------------------
// Private Data
//---------------------------------------------------------------------------
static ULONG PortTimeOut = ONE_MILLI_SEC;
static KIRQL MaskedIrql = PASSIVE_LEVEL;
static KIRQL SpinLockIrql = PASSIVE_LEVEL;
static KSPIN_LOCK IoSpinLock = {0};
//---------------------------------------------------------------------------
// @func Driver entry point for portio layer
// @rdesc Returns NT status code
// @comm Public function
//---------------------------------------------------------------------------
NTSTATUS PORTIO_DriverEntry (VOID)
{
KeInitializeSpinLock (&IoSpinLock);
return (STATUS_SUCCESS);
}
//---------------------------------------------------------------------------
// @func Masks system interrupts for access to gameport
// @rdesc Returns nothing
// @comm Public function
//---------------------------------------------------------------------------
VOID PORTIO_MaskInterrupts (VOID)
{
KeRaiseIrql (PROFILE_LEVEL, &MaskedIrql);
}
//---------------------------------------------------------------------------
// @func Unmasks system interrupts for access to gameport
// @rdesc Returns nothing
// @comm Public function
//---------------------------------------------------------------------------
VOID PORTIO_UnMaskInterrupts (VOID)
{
KeLowerIrql (MaskedIrql);
}
//---------------------------------------------------------------------------
// @func Acquires exclusive access to gameport (mutex)
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @rdesc Returns true if successful
// @comm Public function
//---------------------------------------------------------------------------
BOOLEAN PORTIO_AcquirePort (PGAMEPORT PortInfo)
{
if (PortInfo->AcquirePort (PortInfo->PortContext) != STATUS_SUCCESS)
return (FALSE);
KeAcquireSpinLock (&IoSpinLock, &SpinLockIrql);
return (TRUE);
}
//---------------------------------------------------------------------------
// @func Releases exclusive access to gameport (mutex)
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @rdesc Returns nothing
// @comm Public function
//---------------------------------------------------------------------------
VOID PORTIO_ReleasePort (PGAMEPORT PortInfo)
{
KeReleaseSpinLock (&IoSpinLock, SpinLockIrql);
PortInfo->ReleasePort (PortInfo->PortContext);
}
//---------------------------------------------------------------------------
// @func Calculates port timeout value
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @rdesc Returns nothing
// @comm Public function
//---------------------------------------------------------------------------
VOID PORTIO_CalibrateTimeOut (PGAMEPORT PortInfo)
{
PortTimeOut = TIMER_CalibratePort (PortInfo, ONE_MILLI_SEC);
}
//---------------------------------------------------------------------------
// @func Reads byte from IO port
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @rdesc Returns byte from port
// @comm Public function
//---------------------------------------------------------------------------
#if _MSC_FULL_VER <= 13008829
#pragma optimize("y", off)
#endif
UCHAR PORTIO_Read (PGAMEPORT PortInfo)
{
UCHAR Value;
__asm pushad
Value = PortInfo->ReadAccessor (PortInfo->GameContext);
__asm popad
return (Value);
}
//---------------------------------------------------------------------------
// @func Write byte To IO port
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @parm UCHAR | Value | Value to write
// @rdesc Returns nothing
// @comm Public function
//---------------------------------------------------------------------------
VOID PORTIO_Write (PGAMEPORT PortInfo, UCHAR Value)
{
__asm pushad
PortInfo->WriteAccessor (PortInfo->GameContext, Value);
__asm popad
}
#if _MSC_FULL_VER <= 13008829
#pragma optimize("", on)
#endif
//---------------------------------------------------------------------------
// @func Get AckNak (buttons) from gameport
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @parm ULONG | Timeout | Calibrated status gate timeout
// @parm PUCHAR | AckNak | Pointer to AckNak buffer
// @rdesc Returns True if active, False otherwise
// @comm Public function
//---------------------------------------------------------------------------
BOOLEAN PORTIO_GetAckNak (PGAMEPORT PortInfo, ULONG Timeout, PUCHAR AckNak)
{
if (!PORTIO_WaitForStatusGate (PortInfo, CLOCK_BIT_MASK, Timeout))
return (FALSE);
TIMER_DelayMicroSecs (10);
*AckNak = PORTIO_Read (PortInfo);
return (TRUE);
}
//---------------------------------------------------------------------------
// @func Get NakAck (buttons) from gameport
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @parm ULONG | Timeout | Calibrated status gate timeout
// @parm PUCHAR | NakAck | Pointer to NakAck buffer
// @rdesc Returns True if active, False otherwise
// @comm Public function
//---------------------------------------------------------------------------
BOOLEAN PORTIO_GetNakAck (PGAMEPORT PortInfo, ULONG Timeout, PUCHAR NakAck)
{
if (!PORTIO_WaitForStatusGate (PortInfo, STATUS_GATE_MASK, Timeout))
return (FALSE);
TIMER_DelayMicroSecs (10);
*NakAck = PORTIO_Read (PortInfo);
return (TRUE);
}
//---------------------------------------------------------------------------
// @func Determines whether gameport clock is active
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @parm ULONG | DutyCycle | Calibrated maximum clock duty cycle
// @rdesc Returns True if active, False otherwise
// @comm Public function
//---------------------------------------------------------------------------
BOOLEAN PORTIO_IsClockActive (PGAMEPORT PortInfo, ULONG DutyCycle)
{
UCHAR Value;
Value = PORTIO_Read (PortInfo);
do if ((PORTIO_Read (PortInfo) ^ Value) & CLOCK_BIT_MASK)
return (TRUE);
while (--DutyCycle);
return (FALSE);
}
//---------------------------------------------------------------------------
// @func Waits until gameport clock line goes inactive
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @parm ULONG | DutyCycle | Calibrated maximum clock duty cycle
// @rdesc Returns True is sucessful, false on timeout
// @comm Public function
//---------------------------------------------------------------------------
BOOLEAN PORTIO_WaitClockInActive (PGAMEPORT PortInfo, ULONG DutyCycle)
{
ULONG TimeOut = PortTimeOut;
do if (!PORTIO_IsClockActive (PortInfo, DutyCycle))
return (TRUE);
while (--TimeOut);
MsGamePrint ((DBG_SEVERE, "PORTIO: Timeout at (WaitClockInActive)\n"));
return (FALSE);
}
//---------------------------------------------------------------------------
// @func Waits until gameport clock line goes low
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @rdesc Returns True is sucessfull, false on timeout
// @comm Public function
//---------------------------------------------------------------------------
BOOLEAN PORTIO_WaitClockLow (PGAMEPORT PortInfo)
{
ULONG TimeOut = PortTimeOut;
do if ((PORTIO_Read (PortInfo) & CLOCK_BIT_MASK) == 0)
return (TRUE);
while (--TimeOut);
MsGamePrint ((DBG_SEVERE, "PORTIO: Timeout at (WaitClockLow)\n"));
return (FALSE);
}
//---------------------------------------------------------------------------
// @func Waits until gameport clock line goes high
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @rdesc Returns True is sucessfull, false on timeout
// @comm Public function
//---------------------------------------------------------------------------
BOOLEAN PORTIO_WaitClockHigh (PGAMEPORT PortInfo)
{
ULONG TimeOut = PortTimeOut;
do if ((PORTIO_Read (PortInfo) & CLOCK_BIT_MASK))
return (TRUE);
while (--TimeOut);
MsGamePrint ((DBG_SEVERE, "PORTIO: Timeout at (WaitClockHigh)\n"));
return (FALSE);
}
//---------------------------------------------------------------------------
// @func Waits until gameport data2 line goes low
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @rdesc Returns True is sucessfull, false on timeout
// @comm Public function
//---------------------------------------------------------------------------
BOOLEAN PORTIO_WaitDataLow (PGAMEPORT PortInfo)
{
ULONG TimeOut = PortTimeOut;
do if ((PORTIO_Read (PortInfo) & DATA2_BIT_MASK) == 0)
return (TRUE);
while (--TimeOut);
MsGamePrint ((DBG_SEVERE, "PORTIO: Timeout at (WaitDataLow)\n"));
return (FALSE);
}
//---------------------------------------------------------------------------
// @func Waits until gameport XA line goes high to low
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @rdesc Returns True is sucessful, false on timeout
// @comm Public function
//---------------------------------------------------------------------------
BOOLEAN PORTIO_WaitXA_HighLow (PGAMEPORT PortInfo)
{
ULONG TimeOut = PortTimeOut;
if ((PORTIO_Read (PortInfo) & INTXA_BIT_MASK) == 0)
{
MsGamePrint ((DBG_SEVERE, "PORTIO: Initial (WaitXA_HighLow) Was Low\n"));
return (FALSE);
}
do if ((PORTIO_Read (PortInfo) & INTXA_BIT_MASK) == 0)
return (TRUE);
while (--TimeOut);
MsGamePrint ((DBG_SEVERE, "PORTIO: Timeout at (WaitXALow)\n"));
return (FALSE);
}
//---------------------------------------------------------------------------
// @func Waits until gameport XA and clock lines go low
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @rdesc Returns True is sucessful, false on timeout
// @comm Public function
//---------------------------------------------------------------------------
BOOLEAN PORTIO_WaitForIdle (PGAMEPORT PortInfo)
{
ULONG TimeOut = PortTimeOut;
do if ((PORTIO_Read (PortInfo) & (INTXA_BIT_MASK|CLOCK_BIT_MASK)) == 0)
return (TRUE);
while (--TimeOut);
MsGamePrint ((DBG_SEVERE, "PORTIO: Timeout at (WaitForIdle)\n"));
return (FALSE);
}
//---------------------------------------------------------------------------
// @func Waits until gameport XA and clock lines go low
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @parm UCHAR | Mask | Button mask to wait on
// @parm ULONG | Timeout | Calibrated status gate timeout
// @rdesc Returns True is sucessful, false on timeout
// @comm Public function
//---------------------------------------------------------------------------
BOOLEAN PORTIO_WaitForStatusGate (PGAMEPORT PortInfo, UCHAR Mask, ULONG Timeout)
{
do if ((PORTIO_Read (PortInfo) & STATUS_GATE_MASK) == Mask)
return (TRUE);
while (--Timeout);
MsGamePrint ((DBG_SEVERE, "PORTIO: Timeout at (WaitForStatusGate)\n"));
return (FALSE);
}
//---------------------------------------------------------------------------
// @func Waits for gameport XA low, clock inactive and then clock low
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @parm ULONG | DutyCycle | Calibrated maximum clock duty cycle
// @rdesc Returns True is sucessful, false on timeout
// @comm Public function
//---------------------------------------------------------------------------
BOOLEAN PORTIO_WaitForHandshake (PGAMEPORT PortInfo, ULONG DutyCycle)
{
return
(
PORTIO_WaitXA_HighLow (PortInfo) &&
PORTIO_WaitClockInActive (PortInfo, DutyCycle) &&
PORTIO_WaitClockLow (PortInfo)
);
}
//---------------------------------------------------------------------------
// @func Waits for gameport XA low, clock inactive and then clock low
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @parm ULONG | DutyCycle | Calibrated maximum clock duty cycle
// @rdesc Returns True is sucessful, false on timeout
// @comm Public function
//---------------------------------------------------------------------------
BOOLEAN PORTIO_WaitForIdleHandshake (PGAMEPORT PortInfo, ULONG DutyCycle)
{
ULONG TimeOut = PortTimeOut;
if (!PORTIO_WaitClockHigh (PortInfo))
return (FALSE);
if (!PORTIO_WaitForIdle (PortInfo))
return (FALSE);
do if (!PORTIO_IsClockActive (PortInfo, DutyCycle))
return (TRUE);
while (--TimeOut);
return (FALSE);
}
//---------------------------------------------------------------------------
// @func Pulses port and the waits for gameport handshake
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @parm ULONG | DutyCycle | Calibrated maximum clock duty cycle
// @parm ULONG | Pulses | Number of pulses to perform
// @rdesc Returns True is sucessfull, false on timeout
// @comm Public function
//---------------------------------------------------------------------------
BOOLEAN PORTIO_PulseAndWaitForHandshake (PGAMEPORT PortInfo, ULONG DutyCycle, ULONG Pulses)
{
while (Pulses--)
{
PORTIO_Write (PortInfo, 0);
if (!PORTIO_WaitForHandshake (PortInfo, DutyCycle))
return (FALSE);
}
return (TRUE);
}
//---------------------------------------------------------------------------
// @func Pulses port and the waits for gameport idle handshake
// @parm PGAMEPORT | PortInfo | Gameport parameters
// @parm ULONG | DutyCycle | Calibrated maximum clock duty cycle
// @parm ULONG | Pulses | Number of pulses to perform
// @rdesc Returns True is sucessfull, false on timeout
// @comm Public function
//---------------------------------------------------------------------------
BOOLEAN PORTIO_PulseAndWaitForIdleHandshake (PGAMEPORT PortInfo, ULONG DutyCycle, ULONG Pulses)
{
while (Pulses--)
{
PORTIO_Write (PortInfo, 0);
if (!PORTIO_WaitForIdleHandshake (PortInfo, DutyCycle))
return (FALSE);
}
return (TRUE);
}