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