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
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);
|
|
}
|
|
|