mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 01:15:09 +00:00
[NTVDM]
- Completely rewrite the timing system. Replace hardcoded callbacks with dynamic hardware timers. - Finish implementing the PS/2 mouse. - Fix the DOS mouse driver. Inspired by a patch by Stefano Toncich (Tonix) (see CORE-9166). CORE-9166 #comment A different fix was committed in r67219. svn path=/trunk/; revision=67219
This commit is contained in:
parent
33d8a4b74b
commit
e4a1abcc2a
17 changed files with 886 additions and 455 deletions
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "io.h"
|
||||
#include "hardware/mouse.h"
|
||||
#include "hardware/ps2.h"
|
||||
|
||||
// HACK: For the PS/2 bypass and MOUSE.COM driver direct call
|
||||
#include "dos/mouse32.h"
|
||||
|
@ -28,13 +29,6 @@
|
|||
// Mouse IRQ 12
|
||||
static VOID WINAPI BiosMouseIrq(LPWORD Stack)
|
||||
{
|
||||
// HACK!! Call directly the MOUSE.COM driver instead of going
|
||||
// through the regular interfaces!!
|
||||
extern COORD DosNewPosition;
|
||||
extern WORD DosButtonState;
|
||||
DosMouseUpdatePosition(&DosNewPosition);
|
||||
DosMouseUpdateButtons(DosButtonState);
|
||||
|
||||
PicIRQComplete(Stack);
|
||||
}
|
||||
|
||||
|
@ -118,6 +112,7 @@ BOOLEAN MouseBios32Initialize(VOID)
|
|||
{
|
||||
/* Set up the HW vector interrupts */
|
||||
EnableHwIRQ(12, BiosMouseIrq);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,12 +14,13 @@
|
|||
#include "emulator.h"
|
||||
#include "cpu/cpu.h"
|
||||
|
||||
// #include "clock.h"
|
||||
#include "clock.h"
|
||||
|
||||
#include "hardware/cmos.h"
|
||||
#include "hardware/ps2.h"
|
||||
#include "hardware/pit.h"
|
||||
#include "hardware/video/vga.h"
|
||||
#include "hardware/mouse.h"
|
||||
|
||||
/* Extra PSDK/NDK Headers */
|
||||
#include <ndk/kefuncs.h>
|
||||
|
@ -28,8 +29,7 @@
|
|||
|
||||
/*
|
||||
* Activate IPS_DISPLAY if you want to display the
|
||||
* number of instructions per second, as well as
|
||||
* the computed number of ticks for the PIT.
|
||||
* number of instructions per second.
|
||||
*/
|
||||
// #define IPS_DISPLAY
|
||||
|
||||
|
@ -38,27 +38,27 @@
|
|||
*/
|
||||
// #define WORKING_TIMER
|
||||
|
||||
|
||||
/* Processor speed */
|
||||
#define STEPS_PER_CYCLE 256
|
||||
#define IRQ1_CYCLES 16
|
||||
#define IRQ12_CYCLES 16
|
||||
|
||||
/* VARIABLES ******************************************************************/
|
||||
|
||||
static LIST_ENTRY Timers;
|
||||
static LARGE_INTEGER StartPerfCount, Frequency;
|
||||
|
||||
static LARGE_INTEGER LastTimerTick, LastRtcTick, Counter;
|
||||
static LONGLONG TimerTicks;
|
||||
static DWORD StartTickCount, CurrentTickCount;
|
||||
static DWORD LastClockUpdate;
|
||||
static DWORD LastVerticalRefresh;
|
||||
|
||||
static DWORD LastIrq1Tick = 0, LastIrq12Tick = 0;
|
||||
static DWORD StartTickCount;
|
||||
|
||||
#ifdef IPS_DISPLAY
|
||||
static DWORD LastCyclePrintout;
|
||||
static ULONGLONG Cycles = 0;
|
||||
static ULONGLONG Cycles = 0ULL;
|
||||
#endif
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
#ifdef IPS_DISPLAY
|
||||
static VOID FASTCALL IpsDisplayCallback(ULONGLONG ElapsedTime)
|
||||
{
|
||||
DPRINT1("NTVDM: %I64u Instructions Per Second\n", Cycles / ElapsedTime);
|
||||
Cycles = 0ULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
@ -67,112 +67,159 @@ VOID ClockUpdate(VOID)
|
|||
{
|
||||
extern BOOLEAN CpuRunning;
|
||||
UINT i;
|
||||
// LARGE_INTEGER Counter;
|
||||
|
||||
#ifdef WORKING_TIMER
|
||||
DWORD PitResolution;
|
||||
#endif
|
||||
DWORD RtcFrequency;
|
||||
PLIST_ENTRY Entry;
|
||||
LARGE_INTEGER Counter;
|
||||
|
||||
while (VdmRunning && CpuRunning)
|
||||
{
|
||||
/* Get the current number of ticks */
|
||||
DWORD CurrentTickCount = GetTickCount();
|
||||
|
||||
#ifdef WORKING_TIMER
|
||||
PitResolution = PitGetResolution();
|
||||
if ((PitResolution <= 1000) && (RtcFrequency <= 1000))
|
||||
{
|
||||
/* Calculate the approximate performance counter value instead */
|
||||
Counter.QuadPart = StartPerfCount.QuadPart
|
||||
+ ((CurrentTickCount - StartTickCount)
|
||||
* Frequency.QuadPart) / 1000;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
RtcFrequency = RtcGetTicksPerSecond();
|
||||
{
|
||||
/* Get the current performance counter value */
|
||||
/// DWORD_PTR oldmask = SetThreadAffinityMask(GetCurrentThread(), 0);
|
||||
NtQueryPerformanceCounter(&Counter, NULL);
|
||||
/// SetThreadAffinityMask(GetCurrentThread(), oldmask);
|
||||
}
|
||||
|
||||
/* Get the current number of ticks */
|
||||
CurrentTickCount = GetTickCount();
|
||||
/* Continue CPU emulation */
|
||||
for (i = 0; VdmRunning && CpuRunning && (i < STEPS_PER_CYCLE); i++)
|
||||
{
|
||||
CpuStep();
|
||||
|
||||
#ifdef WORKING_TIMER
|
||||
if ((PitResolution <= 1000) && (RtcFrequency <= 1000))
|
||||
#ifdef IPS_DISPLAY
|
||||
++Cycles;
|
||||
#endif
|
||||
}
|
||||
|
||||
for (Entry = Timers.Flink; Entry != &Timers; Entry = Entry->Flink)
|
||||
{
|
||||
ULONGLONG Ticks = (ULONGLONG)-1;
|
||||
PHARDWARE_TIMER Timer = CONTAINING_RECORD(Entry, HARDWARE_TIMER, Link);
|
||||
|
||||
ASSERT((Timer->EnableCount > 0) && (Timer->Flags & HARDWARE_TIMER_ENABLED));
|
||||
|
||||
if (Timer->Delay)
|
||||
{
|
||||
if (Timer->Flags & HARDWARE_TIMER_PRECISE)
|
||||
{
|
||||
/* Use the performance counter for precise timers */
|
||||
if (Counter.QuadPart <= Timer->LastTick.QuadPart) continue;
|
||||
Ticks = (Counter.QuadPart - Timer->LastTick.QuadPart) / Timer->Delay;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use the regular tick count for normal timers */
|
||||
if (CurrentTickCount <= Timer->LastTick.LowPart) continue;
|
||||
Ticks = (CurrentTickCount - Timer->LastTick.LowPart) / (ULONG)Timer->Delay;
|
||||
}
|
||||
|
||||
if (Ticks == 0) continue;
|
||||
}
|
||||
|
||||
Timer->Callback(Ticks);
|
||||
|
||||
if (Timer->Flags & HARDWARE_TIMER_ONESHOT)
|
||||
{
|
||||
/* Disable this timer */
|
||||
DisableHardwareTimer(Timer);
|
||||
}
|
||||
|
||||
/* Update the time of the last timer tick */
|
||||
Timer->LastTick.QuadPart += Ticks * Timer->Delay;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PHARDWARE_TIMER CreateHardwareTimer(ULONG Flags, ULONG Delay, PHARDWARE_TIMER_PROC Callback)
|
||||
{
|
||||
PHARDWARE_TIMER Timer;
|
||||
|
||||
Timer = (PHARDWARE_TIMER)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(HARDWARE_TIMER));
|
||||
if (Timer == NULL) return NULL;
|
||||
|
||||
Timer->Flags = Flags & ~HARDWARE_TIMER_ENABLED;
|
||||
Timer->EnableCount = 0;
|
||||
Timer->Callback = Callback;
|
||||
SetHardwareTimerDelay(Timer, (ULONGLONG)Delay);
|
||||
|
||||
if (Flags & HARDWARE_TIMER_ENABLED) EnableHardwareTimer(Timer);
|
||||
return Timer;
|
||||
}
|
||||
|
||||
VOID EnableHardwareTimer(PHARDWARE_TIMER Timer)
|
||||
{
|
||||
/* Increment the count */
|
||||
Timer->EnableCount++;
|
||||
|
||||
/* Check if the count is above 0 but the timer isn't enabled */
|
||||
if ((Timer->EnableCount > 0) && !(Timer->Flags & HARDWARE_TIMER_ENABLED))
|
||||
{
|
||||
/* Calculate the approximate performance counter value instead */
|
||||
Counter.QuadPart = StartPerfCount.QuadPart
|
||||
+ (CurrentTickCount - StartTickCount)
|
||||
* (Frequency.QuadPart / 1000);
|
||||
if (Timer->Flags & HARDWARE_TIMER_PRECISE)
|
||||
{
|
||||
NtQueryPerformanceCounter(&Timer->LastTick, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
Timer->LastTick.LowPart = GetTickCount();
|
||||
}
|
||||
|
||||
Timer->Flags |= HARDWARE_TIMER_ENABLED;
|
||||
InsertTailList(&Timers, &Timer->Link);
|
||||
}
|
||||
}
|
||||
|
||||
VOID DisableHardwareTimer(PHARDWARE_TIMER Timer)
|
||||
{
|
||||
/* Decrement the count */
|
||||
Timer->EnableCount--;
|
||||
|
||||
/* Check if the count is 0 or less but the timer is enabled */
|
||||
if ((Timer->EnableCount <= 0) && (Timer->Flags & HARDWARE_TIMER_ENABLED))
|
||||
{
|
||||
/* Disable the timer */
|
||||
Timer->Flags &= ~HARDWARE_TIMER_ENABLED;
|
||||
RemoveEntryList(&Timer->Link);
|
||||
}
|
||||
}
|
||||
|
||||
VOID SetHardwareTimerDelay(PHARDWARE_TIMER Timer, ULONGLONG NewDelay)
|
||||
{
|
||||
if (Timer->Flags & HARDWARE_TIMER_PRECISE)
|
||||
{
|
||||
/* Convert the delay from nanoseconds to performance counter ticks */
|
||||
Timer->Delay = (NewDelay * Frequency.QuadPart + 500000000ULL) / 1000000000ULL;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Get the current performance counter value */
|
||||
/// DWORD_PTR oldmask = SetThreadAffinityMask(GetCurrentThread(), 0);
|
||||
NtQueryPerformanceCounter(&Counter, NULL);
|
||||
/// SetThreadAffinityMask(GetCurrentThread(), oldmask);
|
||||
Timer->Delay = NewDelay;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the number of PIT ticks that have passed */
|
||||
TimerTicks = ((Counter.QuadPart - LastTimerTick.QuadPart)
|
||||
* PIT_BASE_FREQUENCY) / Frequency.QuadPart;
|
||||
|
||||
/* Update the PIT */
|
||||
if (TimerTicks > 0)
|
||||
{
|
||||
PitClock(TimerTicks);
|
||||
LastTimerTick = Counter;
|
||||
}
|
||||
|
||||
/* Check for RTC update */
|
||||
if ((CurrentTickCount - LastClockUpdate) >= 1000)
|
||||
{
|
||||
RtcTimeUpdate();
|
||||
LastClockUpdate = CurrentTickCount;
|
||||
}
|
||||
|
||||
/* Check for RTC periodic tick */
|
||||
if ((Counter.QuadPart - LastRtcTick.QuadPart)
|
||||
>= (Frequency.QuadPart / (LONGLONG)RtcFrequency))
|
||||
{
|
||||
RtcPeriodicTick();
|
||||
LastRtcTick = Counter;
|
||||
}
|
||||
|
||||
/* Check for vertical retrace */
|
||||
if ((CurrentTickCount - LastVerticalRefresh) >= 15)
|
||||
{
|
||||
VgaRefreshDisplay();
|
||||
LastVerticalRefresh = CurrentTickCount;
|
||||
}
|
||||
|
||||
if ((CurrentTickCount - LastIrq1Tick) >= IRQ1_CYCLES)
|
||||
{
|
||||
GenerateIrq1();
|
||||
LastIrq1Tick = CurrentTickCount;
|
||||
}
|
||||
|
||||
if ((CurrentTickCount - LastIrq12Tick) >= IRQ12_CYCLES)
|
||||
{
|
||||
GenerateIrq12();
|
||||
LastIrq12Tick = CurrentTickCount;
|
||||
}
|
||||
|
||||
/* Horizontal retrace occurs as fast as possible */
|
||||
VgaHorizontalRetrace();
|
||||
|
||||
/* Continue CPU emulation */
|
||||
for (i = 0; VdmRunning && CpuRunning && (i < STEPS_PER_CYCLE); i++)
|
||||
{
|
||||
CpuStep();
|
||||
#ifdef IPS_DISPLAY
|
||||
++Cycles;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef IPS_DISPLAY
|
||||
if ((CurrentTickCount - LastCyclePrintout) >= 1000)
|
||||
{
|
||||
DPRINT1("NTVDM: %I64u Instructions Per Second; TimerTicks = %I64d\n", Cycles * 1000 / (CurrentTickCount - LastCyclePrintout), TimerTicks);
|
||||
LastCyclePrintout = CurrentTickCount;
|
||||
Cycles = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
VOID DestroyHardwareTimer(PHARDWARE_TIMER Timer)
|
||||
{
|
||||
if (Timer->Flags & HARDWARE_TIMER_ENABLED) RemoveEntryList(&Timer->Link);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, Timer);
|
||||
}
|
||||
|
||||
BOOLEAN ClockInitialize(VOID)
|
||||
{
|
||||
#ifdef IPS_DISPLAY
|
||||
PHARDWARE_TIMER IpsTimer;
|
||||
#endif
|
||||
|
||||
InitializeListHead(&Timers);
|
||||
|
||||
/* Initialize the performance counter (needed for hardware timers) */
|
||||
/* Find the starting performance */
|
||||
NtQueryPerformanceCounter(&StartPerfCount, &Frequency);
|
||||
|
@ -185,15 +232,16 @@ BOOLEAN ClockInitialize(VOID)
|
|||
/* Find the starting tick count */
|
||||
StartTickCount = GetTickCount();
|
||||
|
||||
/* Set the different last counts to the starting count */
|
||||
LastClockUpdate = LastVerticalRefresh =
|
||||
#ifdef IPS_DISPLAY
|
||||
LastCyclePrintout =
|
||||
#endif
|
||||
StartTickCount;
|
||||
|
||||
/* Set the last timer ticks to the current time */
|
||||
LastTimerTick = LastRtcTick = StartPerfCount;
|
||||
IpsTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, 1000, IpsDisplayCallback);
|
||||
if (IpsTimer == NULL)
|
||||
{
|
||||
wprintf(L"FATAL: Cannot create IPS display timer.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -10,8 +10,39 @@
|
|||
#ifndef _CLOCK_H_
|
||||
#define _CLOCK_H_
|
||||
|
||||
#include <ndk/rtlfuncs.h>
|
||||
|
||||
/* DEFINITIONS ****************************************************************/
|
||||
|
||||
#define HARDWARE_TIMER_ENABLED (1 << 0)
|
||||
#define HARDWARE_TIMER_ONESHOT (1 << 1)
|
||||
#define HARDWARE_TIMER_PRECISE (1 << 2)
|
||||
|
||||
typedef VOID (FASTCALL *PHARDWARE_TIMER_PROC)(ULONGLONG ElapsedTime);
|
||||
|
||||
typedef struct _HARDWARE_TIMER
|
||||
{
|
||||
LIST_ENTRY Link;
|
||||
ULONG Flags;
|
||||
LONG EnableCount;
|
||||
ULONGLONG Delay;
|
||||
PHARDWARE_TIMER_PROC Callback;
|
||||
LARGE_INTEGER LastTick;
|
||||
} HARDWARE_TIMER, *PHARDWARE_TIMER;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
PHARDWARE_TIMER CreateHardwareTimer
|
||||
(
|
||||
ULONG Flags,
|
||||
ULONG Delay, /* milliseconds for normal timers, nanoseconds for precise timers */
|
||||
PHARDWARE_TIMER_PROC Callback
|
||||
);
|
||||
VOID EnableHardwareTimer(PHARDWARE_TIMER Timer);
|
||||
VOID DisableHardwareTimer(PHARDWARE_TIMER Timer);
|
||||
VOID SetHardwareTimerDelay(PHARDWARE_TIMER Timer, ULONGLONG NewDelay);
|
||||
VOID DestroyHardwareTimer(PHARDWARE_TIMER Timer);
|
||||
|
||||
VOID ClockUpdate(VOID);
|
||||
BOOLEAN ClockInitialize(VOID);
|
||||
|
||||
|
|
|
@ -54,6 +54,8 @@ enum
|
|||
EMULATOR_EXCEPTION_PAGE_FAULT
|
||||
};
|
||||
#endif
|
||||
|
||||
extern BOOLEAN CpuRunning;
|
||||
extern FAST486_STATE EmulatorContext;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
|
|
@ -423,7 +423,7 @@ static VOID WINAPI DosStart(LPWORD Stack)
|
|||
RegisterBop(BOP_START_DOS, NULL);
|
||||
|
||||
/* Load the mouse driver */
|
||||
// DosMouseInitialize();
|
||||
DosMouseInitialize();
|
||||
|
||||
#ifndef STANDALONE
|
||||
|
||||
|
|
|
@ -13,36 +13,45 @@
|
|||
#include "emulator.h"
|
||||
#include "cpu/cpu.h"
|
||||
#include "int32.h"
|
||||
#include "hardware/mouse.h"
|
||||
#include "hardware/ps2.h"
|
||||
#include "hardware/pic.h"
|
||||
#include "hardware/video/vga.h"
|
||||
|
||||
#include "mouse32.h"
|
||||
#include "bios/bios.h"
|
||||
#include "bios/bios32/bios32p.h"
|
||||
|
||||
#include "io.h"
|
||||
#include "dos32krnl/dos.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
static BOOLEAN DriverEnabled = TRUE;
|
||||
static MOUSE_DRIVER_STATE DriverState;
|
||||
#define MICKEYS_PER_CELL_HORIZ 8
|
||||
#define MICKEYS_PER_CELL_VERT 16
|
||||
|
||||
/**/
|
||||
COORD DosNewPosition;
|
||||
WORD DosButtonState;
|
||||
/**/
|
||||
static MOUSE_PACKET Packet;
|
||||
static INT ByteCounter = 0;
|
||||
static BOOLEAN DriverEnabled = FALSE;
|
||||
static MOUSE_DRIVER_STATE DriverState;
|
||||
static DWORD OldIrqHandler;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
extern VOID WINAPI BiosMouseIrq(LPWORD Stack);
|
||||
|
||||
static VOID PaintMouseCursor(VOID)
|
||||
{
|
||||
if (Bda->VideoMode <= 3)
|
||||
{
|
||||
WORD Character;
|
||||
WORD CellX = DriverState.Position.X / 8;
|
||||
WORD CellY = DriverState.Position.Y / 8;
|
||||
DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize);
|
||||
|
||||
EmulatorReadMemory(&EmulatorContext,
|
||||
VideoAddress
|
||||
+ (DriverState.Position.Y * Bda->ScreenColumns
|
||||
+ DriverState.Position.X) * sizeof(WORD),
|
||||
+ (CellY * Bda->ScreenColumns + CellX) * sizeof(WORD),
|
||||
(LPVOID)&Character,
|
||||
sizeof(WORD));
|
||||
|
||||
|
@ -52,8 +61,7 @@ static VOID PaintMouseCursor(VOID)
|
|||
|
||||
EmulatorWriteMemory(&EmulatorContext,
|
||||
VideoAddress
|
||||
+ (DriverState.Position.Y * Bda->ScreenColumns
|
||||
+ DriverState.Position.X) * sizeof(WORD),
|
||||
+ (CellY * Bda->ScreenColumns + CellX) * sizeof(WORD),
|
||||
(LPVOID)&Character,
|
||||
sizeof(WORD));
|
||||
}
|
||||
|
@ -68,12 +76,13 @@ static VOID EraseMouseCursor(VOID)
|
|||
{
|
||||
if (Bda->VideoMode <= 3)
|
||||
{
|
||||
WORD CellX = DriverState.Position.X / 8;
|
||||
WORD CellY = DriverState.Position.Y / 8;
|
||||
DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize);
|
||||
|
||||
EmulatorWriteMemory(&EmulatorContext,
|
||||
VideoAddress
|
||||
+ (DriverState.Position.Y * Bda->ScreenColumns
|
||||
+ DriverState.Position.X) * sizeof(WORD),
|
||||
+ (CellY * Bda->ScreenColumns + CellX) * sizeof(WORD),
|
||||
(LPVOID)&DriverState.Character,
|
||||
sizeof(WORD));
|
||||
}
|
||||
|
@ -84,10 +93,45 @@ static VOID EraseMouseCursor(VOID)
|
|||
}
|
||||
}
|
||||
|
||||
static VOID ToMouseCoordinates(PCOORD Position)
|
||||
{
|
||||
COORD Resolution = VgaGetDisplayResolution();
|
||||
WORD Width = DriverState.MaxX - DriverState.MinX + 1;
|
||||
WORD Height = DriverState.MaxY - DriverState.MinY + 1;
|
||||
|
||||
if (!VgaGetDoubleVisionState(NULL, NULL))
|
||||
{
|
||||
Resolution.X *= 8;
|
||||
Resolution.Y *= 8;
|
||||
}
|
||||
|
||||
Position->X = DriverState.MinX + ((Position->X * Width) / Resolution.X);
|
||||
Position->Y = DriverState.MinY + ((Position->Y * Height) / Resolution.Y);
|
||||
}
|
||||
|
||||
static VOID FromMouseCoordinates(PCOORD Position)
|
||||
{
|
||||
COORD Resolution = VgaGetDisplayResolution();
|
||||
WORD Width = DriverState.MaxX - DriverState.MinX + 1;
|
||||
WORD Height = DriverState.MaxY - DriverState.MinY + 1;
|
||||
|
||||
if (!VgaGetDoubleVisionState(NULL, NULL))
|
||||
{
|
||||
Resolution.X *= 8;
|
||||
Resolution.Y *= 8;
|
||||
}
|
||||
|
||||
Position->X = (((Position->X - DriverState.MinX) * Resolution.X) / Width);
|
||||
Position->Y = (((Position->Y - DriverState.MinY) * Resolution.Y) / Height);
|
||||
}
|
||||
|
||||
static VOID CallMouseUserHandlers(USHORT CallMask)
|
||||
{
|
||||
USHORT i;
|
||||
USHORT AX, BX, CX, DX, SI, DI;
|
||||
COORD Position = DriverState.Position;
|
||||
|
||||
ToMouseCoordinates(&Position);
|
||||
|
||||
/* Call handler 0 */
|
||||
if ((DriverState.Handler0.CallMask & CallMask) != 0 &&
|
||||
|
@ -108,10 +152,10 @@ static VOID CallMouseUserHandlers(USHORT CallMask)
|
|||
|
||||
setAX(CallMask);
|
||||
setBX(DriverState.ButtonState);
|
||||
setCX(DriverState.Position.X);
|
||||
setDX(DriverState.Position.Y);
|
||||
setSI(DriverState.MickeysPerCellHoriz);
|
||||
setDI(DriverState.MickeysPerCellVert);
|
||||
setCX(Position.X);
|
||||
setDX(Position.Y);
|
||||
setSI(MICKEYS_PER_CELL_HORIZ);
|
||||
setDI(MICKEYS_PER_CELL_VERT);
|
||||
|
||||
DPRINT("Calling Handler0 %04X:%04X with CallMask 0x%04X\n",
|
||||
HIWORD(DriverState.Handler0.Callback),
|
||||
|
@ -150,10 +194,10 @@ static VOID CallMouseUserHandlers(USHORT CallMask)
|
|||
|
||||
setAX(CallMask);
|
||||
setBX(DriverState.ButtonState);
|
||||
setCX(DriverState.Position.X);
|
||||
setDX(DriverState.Position.Y);
|
||||
setSI(DriverState.MickeysPerCellHoriz);
|
||||
setDI(DriverState.MickeysPerCellVert);
|
||||
setCX(Position.X);
|
||||
setDX(Position.Y);
|
||||
setSI(MICKEYS_PER_CELL_HORIZ);
|
||||
setDI(MICKEYS_PER_CELL_VERT);
|
||||
|
||||
DPRINT1("Calling Handler[%d] %04X:%04X with CallMask 0x%04X\n",
|
||||
i,
|
||||
|
@ -174,6 +218,127 @@ static VOID CallMouseUserHandlers(USHORT CallMask)
|
|||
}
|
||||
}
|
||||
|
||||
static inline VOID DosUpdatePosition(PCOORD NewPosition)
|
||||
{
|
||||
COORD Resolution = VgaGetDisplayResolution();
|
||||
|
||||
/* Check for text mode */
|
||||
if (!VgaGetDoubleVisionState(NULL, NULL))
|
||||
{
|
||||
Resolution.X *= 8;
|
||||
Resolution.Y *= 8;
|
||||
}
|
||||
|
||||
if (DriverState.ShowCount > 0) EraseMouseCursor();
|
||||
DriverState.Position = *NewPosition;
|
||||
|
||||
/* Apply the clipping rectangle */
|
||||
if (DriverState.Position.X < DriverState.MinX) DriverState.Position.X = DriverState.MinX;
|
||||
if (DriverState.Position.X > DriverState.MaxX) DriverState.Position.X = DriverState.MaxX;
|
||||
if (DriverState.Position.Y < DriverState.MinY) DriverState.Position.Y = DriverState.MinY;
|
||||
if (DriverState.Position.Y > DriverState.MaxY) DriverState.Position.Y = DriverState.MaxY;
|
||||
|
||||
if (DriverState.ShowCount > 0) PaintMouseCursor();
|
||||
|
||||
/* Call the mouse handlers */
|
||||
CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
|
||||
}
|
||||
|
||||
static inline VOID DosUpdateButtons(BYTE ButtonState)
|
||||
{
|
||||
USHORT i;
|
||||
USHORT CallMask = 0x0000; // We use MS MOUSE v1.0+ format
|
||||
|
||||
for (i = 0; i < NUM_MOUSE_BUTTONS; i++)
|
||||
{
|
||||
BOOLEAN OldState = (DriverState.ButtonState >> i) & 1;
|
||||
BOOLEAN NewState = (ButtonState >> i) & 1;
|
||||
|
||||
if (NewState > OldState)
|
||||
{
|
||||
/* Mouse press */
|
||||
DriverState.PressCount[i]++;
|
||||
DriverState.LastPress[i] = DriverState.Position;
|
||||
|
||||
CallMask |= (1 << (2 * i + 1));
|
||||
}
|
||||
else if (NewState < OldState)
|
||||
{
|
||||
/* Mouse release */
|
||||
DriverState.ReleaseCount[i]++;
|
||||
DriverState.LastRelease[i] = DriverState.Position;
|
||||
|
||||
CallMask |= (1 << (2 * i + 2));
|
||||
}
|
||||
}
|
||||
|
||||
DriverState.ButtonState = ButtonState;
|
||||
|
||||
/* Call the mouse handlers */
|
||||
CallMouseUserHandlers(CallMask);
|
||||
}
|
||||
|
||||
static VOID WINAPI DosMouseIrq(LPWORD Stack)
|
||||
{
|
||||
COORD Position;
|
||||
BYTE ButtonState;
|
||||
|
||||
switch (ByteCounter)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Packet.Flags = IOReadB(PS2_DATA_PORT);
|
||||
break;
|
||||
}
|
||||
|
||||
case 1:
|
||||
{
|
||||
Packet.HorzCounter = IOReadB(PS2_DATA_PORT);
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
Packet.VertCounter = IOReadB(PS2_DATA_PORT);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
/* Shouldn't happen */
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
if (++ByteCounter == 3)
|
||||
{
|
||||
SHORT DeltaX = Packet.HorzCounter;
|
||||
SHORT DeltaY = Packet.VertCounter;
|
||||
|
||||
/* Adjust the sign */
|
||||
if (Packet.Flags & MOUSE_X_SIGN) DeltaX = -DeltaX;
|
||||
if (Packet.Flags & MOUSE_Y_SIGN) DeltaY = -DeltaY;
|
||||
|
||||
DriverState.HorizCount += DeltaX;
|
||||
DriverState.VertCount += DeltaY;
|
||||
|
||||
ByteCounter = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the absolute position directly from the mouse, this is the only
|
||||
* way to perfectly synchronize the host and guest mouse pointer.
|
||||
*/
|
||||
MouseGetDataFast(&Position, &ButtonState);
|
||||
|
||||
/* Call the update subroutines */
|
||||
DosUpdatePosition(&Position);
|
||||
DosUpdateButtons(ButtonState);
|
||||
|
||||
/* Complete the IRQ */
|
||||
PicIRQComplete(Stack);
|
||||
}
|
||||
|
||||
static VOID WINAPI DosMouseService(LPWORD Stack)
|
||||
{
|
||||
switch (getAX())
|
||||
|
@ -183,10 +348,15 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
|||
{
|
||||
SHORT i;
|
||||
|
||||
DriverEnabled = TRUE;
|
||||
DriverState.ShowCount = 0;
|
||||
DriverState.ButtonState = 0;
|
||||
|
||||
/* Initialize the default clipping range */
|
||||
DriverState.MinX = 0;
|
||||
DriverState.MaxX = MOUSE_MAX_HORIZ - 1;
|
||||
DriverState.MinY = 0;
|
||||
DriverState.MaxY = MOUSE_MAX_VERT - 1;
|
||||
|
||||
/* Set the default text cursor */
|
||||
DriverState.TextCursor.ScreenMask = 0xFFFF; /* Display everything */
|
||||
DriverState.TextCursor.CursorMask = 0xFF00; /* ... but with inverted attributes */
|
||||
|
@ -237,10 +407,6 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
|||
DriverState.PressCount[i] = DriverState.ReleaseCount[i] = 0;
|
||||
}
|
||||
|
||||
/* Initialize the resolution */
|
||||
DriverState.MickeysPerCellHoriz = 8;
|
||||
DriverState.MickeysPerCellVert = 16;
|
||||
|
||||
/* Return mouse information */
|
||||
setAX(0xFFFF); // Hardware & driver installed
|
||||
setBX(NUM_MOUSE_BUTTONS);
|
||||
|
@ -252,7 +418,7 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
|||
case 0x01:
|
||||
{
|
||||
DriverState.ShowCount++;
|
||||
if (DriverState.ShowCount > 0) PaintMouseCursor();
|
||||
if (DriverState.ShowCount == 1) PaintMouseCursor();
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -261,7 +427,7 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
|||
case 0x02:
|
||||
{
|
||||
DriverState.ShowCount--;
|
||||
if (DriverState.ShowCount <= 0) EraseMouseCursor();
|
||||
if (DriverState.ShowCount == 0) EraseMouseCursor();
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -269,23 +435,22 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
|||
/* Return Position And Button Status */
|
||||
case 0x03:
|
||||
{
|
||||
COORD Position = DriverState.Position;
|
||||
ToMouseCoordinates(&Position);
|
||||
|
||||
setBX(DriverState.ButtonState);
|
||||
setCX(DriverState.Position.X);
|
||||
setDX(DriverState.Position.Y);
|
||||
setCX(Position.X);
|
||||
setDX(Position.Y);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Position Mouse Cursor */
|
||||
case 0x04:
|
||||
{
|
||||
POINT Point;
|
||||
|
||||
Point.x = getCX();
|
||||
Point.y = getDX();
|
||||
|
||||
ClientToScreen(GetConsoleWindow(), &Point);
|
||||
SetCursorPos(Point.x, Point.y);
|
||||
COORD Position = { getCX(), getDX() };
|
||||
FromMouseCoordinates(&Position);
|
||||
|
||||
DriverState.Position = Position;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -293,11 +458,13 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
|||
case 0x05:
|
||||
{
|
||||
WORD Button = getBX();
|
||||
COORD LastPress = DriverState.LastPress[Button];
|
||||
ToMouseCoordinates(&LastPress);
|
||||
|
||||
setAX(DriverState.ButtonState);
|
||||
setBX(DriverState.PressCount[Button]);
|
||||
setCX(DriverState.LastPress[Button].X);
|
||||
setDX(DriverState.LastPress[Button].Y);
|
||||
setCX(LastPress.X);
|
||||
setDX(LastPress.Y);
|
||||
|
||||
/* Reset the counter */
|
||||
DriverState.PressCount[Button] = 0;
|
||||
|
@ -309,11 +476,13 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
|||
case 0x06:
|
||||
{
|
||||
WORD Button = getBX();
|
||||
COORD LastRelease = DriverState.LastRelease[Button];
|
||||
ToMouseCoordinates(&LastRelease);
|
||||
|
||||
setAX(DriverState.ButtonState);
|
||||
setBX(DriverState.ReleaseCount[Button]);
|
||||
setCX(DriverState.LastRelease[Button].X);
|
||||
setDX(DriverState.LastRelease[Button].Y);
|
||||
setCX(LastRelease.X);
|
||||
setDX(LastRelease.Y);
|
||||
|
||||
/* Reset the counter */
|
||||
DriverState.ReleaseCount[Button] = 0;
|
||||
|
@ -322,6 +491,24 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
|||
|
||||
}
|
||||
|
||||
/* Define Horizontal Cursor Range */
|
||||
case 0x07:
|
||||
{
|
||||
DPRINT("Setting mouse horizontal range: %u - %u\n", getCX(), getDX());
|
||||
DriverState.MinX = getCX();
|
||||
DriverState.MaxX = getDX();
|
||||
break;
|
||||
}
|
||||
|
||||
/* Define Vertical Cursor Range */
|
||||
case 0x08:
|
||||
{
|
||||
DPRINT("Setting mouse vertical range: %u - %u\n", getCX(), getDX());
|
||||
DriverState.MinY = getCX();
|
||||
DriverState.MaxY = getDX();
|
||||
break;
|
||||
}
|
||||
|
||||
/* Define Graphics Cursor */
|
||||
case 0x09:
|
||||
{
|
||||
|
@ -395,8 +582,7 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
|||
/* Define Mickey/Pixel Ratio */
|
||||
case 0x0F:
|
||||
{
|
||||
DriverState.MickeysPerCellHoriz = getCX();
|
||||
DriverState.MickeysPerCellVert = getDX();
|
||||
/* This call should be completely ignored */
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -588,14 +774,14 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
|||
setES(0x0000);
|
||||
setBX(0x0000);
|
||||
|
||||
DriverEnabled = FALSE;
|
||||
DosMouseDisable();
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable Mouse Driver */
|
||||
case 0x20:
|
||||
{
|
||||
DriverEnabled = TRUE;
|
||||
DosMouseEnable();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -608,6 +794,38 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
|||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID DosMouseEnable(VOID)
|
||||
{
|
||||
if (!DriverEnabled)
|
||||
{
|
||||
DriverEnabled = TRUE;
|
||||
|
||||
/* Get the old IRQ handler */
|
||||
OldIrqHandler = ((PDWORD)BaseAddress)[MOUSE_IRQ_INT];
|
||||
|
||||
/* Set the IRQ handler */
|
||||
RegisterDosInt32(MOUSE_IRQ_INT, DosMouseIrq);
|
||||
|
||||
/* Enable packet reporting */
|
||||
IOWriteB(PS2_CONTROL_PORT, 0xD4);
|
||||
IOWriteB(PS2_DATA_PORT, 0xF4);
|
||||
|
||||
/* Read the mouse ACK reply */
|
||||
PS2PortQueueRead(1);
|
||||
}
|
||||
}
|
||||
|
||||
VOID DosMouseDisable(VOID)
|
||||
{
|
||||
if (DriverEnabled)
|
||||
{
|
||||
/* Restore the old IRQ handler */
|
||||
((PDWORD)BaseAddress)[MOUSE_IRQ_INT] = OldIrqHandler;
|
||||
|
||||
DriverEnabled = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
VOID DosMouseUpdatePosition(PCOORD NewPosition)
|
||||
{
|
||||
SHORT DeltaX = NewPosition->X - DriverState.Position.X;
|
||||
|
@ -615,8 +833,8 @@ VOID DosMouseUpdatePosition(PCOORD NewPosition)
|
|||
|
||||
if (!DriverEnabled) return;
|
||||
|
||||
DriverState.HorizCount += (DeltaX * (SHORT)DriverState.MickeysPerCellHoriz) / 8;
|
||||
DriverState.VertCount += (DeltaY * (SHORT)DriverState.MickeysPerCellVert ) / 8;
|
||||
DriverState.HorizCount += (DeltaX * MICKEYS_PER_CELL_HORIZ) / 8;
|
||||
DriverState.VertCount += (DeltaY * MICKEYS_PER_CELL_VERT) / 8;
|
||||
|
||||
if (DriverState.ShowCount > 0) EraseMouseCursor();
|
||||
DriverState.Position = *NewPosition;
|
||||
|
@ -671,10 +889,12 @@ BOOLEAN DosMouseInitialize(VOID)
|
|||
/* Initialize the interrupt handler */
|
||||
RegisterDosInt32(DOS_MOUSE_INTERRUPT, DosMouseService);
|
||||
|
||||
DosMouseEnable();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID DosMouseCleanup(VOID)
|
||||
{
|
||||
if (DriverState.ShowCount > 0) EraseMouseCursor();
|
||||
DosMouseDisable();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define DOS_MOUSE_INTERRUPT 0x33
|
||||
#define MOUSE_IRQ_INT 0x74
|
||||
#define MOUSE_MAX_HORIZ 640
|
||||
#define MOUSE_MAX_VERT 200
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -47,8 +50,7 @@ typedef struct _MOUSE_DRIVER_STATE
|
|||
COORD LastRelease[NUM_MOUSE_BUTTONS];
|
||||
SHORT HorizCount;
|
||||
SHORT VertCount;
|
||||
WORD MickeysPerCellHoriz;
|
||||
WORD MickeysPerCellVert;
|
||||
WORD MinX, MaxX, MinY, MaxY;
|
||||
|
||||
/*
|
||||
* User Subroutine Handlers called on mouse events
|
||||
|
@ -72,9 +74,8 @@ typedef struct _MOUSE_DRIVER_STATE
|
|||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID DosMouseUpdatePosition(PCOORD NewPosition);
|
||||
VOID DosMouseUpdateButtons(WORD ButtonStatus);
|
||||
|
||||
VOID DosMouseEnable(VOID);
|
||||
VOID DosMouseDisable(VOID);
|
||||
BOOLEAN DosMouseInitialize(VOID);
|
||||
VOID DosMouseCleanup(VOID);
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "io.h"
|
||||
#include "pic.h"
|
||||
#include "clock.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
|
@ -24,14 +25,82 @@ static CMOS_MEMORY CmosMemory;
|
|||
static BOOLEAN NmiEnabled = TRUE;
|
||||
static CMOS_REGISTERS SelectedRegister = CMOS_REG_STATUS_D;
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
static PHARDWARE_TIMER ClockTimer;
|
||||
static PHARDWARE_TIMER PeriodicTimer;
|
||||
|
||||
BOOLEAN IsNmiEnabled(VOID)
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static VOID RtcUpdatePeriodicTimer(VOID)
|
||||
{
|
||||
return NmiEnabled;
|
||||
BYTE RateSelect = CmosMemory.StatusRegA & 0x0F;
|
||||
|
||||
if (RateSelect == 0)
|
||||
{
|
||||
/* No periodic interrupt */
|
||||
DisableHardwareTimer(PeriodicTimer);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 1 and 2 act like 8 and 9 */
|
||||
if (RateSelect <= 2) RateSelect += 7;
|
||||
|
||||
SetHardwareTimerDelay(PeriodicTimer, 1000000000ULL / (ULONGLONG)(1 << (16 - RateSelect)));
|
||||
EnableHardwareTimer(PeriodicTimer);
|
||||
}
|
||||
|
||||
VOID CmosWriteAddress(BYTE Value)
|
||||
static VOID FASTCALL RtcPeriodicTick(ULONGLONG ElapsedTime)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(ElapsedTime);
|
||||
|
||||
/* Set PF */
|
||||
CmosMemory.StatusRegC |= CMOS_STC_PF;
|
||||
|
||||
/* Check if there should be an interrupt on a periodic timer tick */
|
||||
if (CmosMemory.StatusRegB & CMOS_STB_INT_PERIODIC)
|
||||
{
|
||||
CmosMemory.StatusRegC |= CMOS_STC_IRQF;
|
||||
|
||||
/* Interrupt! */
|
||||
PicInterruptRequest(RTC_IRQ_NUMBER);
|
||||
}
|
||||
}
|
||||
|
||||
/* Should be called every second */
|
||||
static VOID FASTCALL RtcTimeUpdate(ULONGLONG ElapsedTime)
|
||||
{
|
||||
SYSTEMTIME CurrentTime;
|
||||
|
||||
UNREFERENCED_PARAMETER(ElapsedTime);
|
||||
|
||||
/* Get the current time */
|
||||
GetLocalTime(&CurrentTime);
|
||||
|
||||
/* Set UF */
|
||||
CmosMemory.StatusRegC |= CMOS_STC_UF;
|
||||
|
||||
/* Check if the time matches the alarm time */
|
||||
if ((CurrentTime.wHour == CmosMemory.AlarmHour ) &&
|
||||
(CurrentTime.wMinute == CmosMemory.AlarmMinute) &&
|
||||
(CurrentTime.wSecond == CmosMemory.AlarmSecond))
|
||||
{
|
||||
/* Set the alarm flag */
|
||||
CmosMemory.StatusRegC |= CMOS_STC_AF;
|
||||
|
||||
/* Set IRQF if there should be an interrupt */
|
||||
if (CmosMemory.StatusRegB & CMOS_STB_INT_ON_ALARM) CmosMemory.StatusRegC |= CMOS_STC_IRQF;
|
||||
}
|
||||
|
||||
/* Check if there should be an interrupt on update */
|
||||
if (CmosMemory.StatusRegB & CMOS_STB_INT_ON_UPDATE) CmosMemory.StatusRegC |= CMOS_STC_IRQF;
|
||||
|
||||
if (CmosMemory.StatusRegC & CMOS_STC_IRQF)
|
||||
{
|
||||
/* Interrupt! */
|
||||
PicInterruptRequest(RTC_IRQ_NUMBER);
|
||||
}
|
||||
}
|
||||
|
||||
static VOID CmosWriteAddress(BYTE Value)
|
||||
{
|
||||
/* Update the NMI enabled flag */
|
||||
NmiEnabled = !(Value & CMOS_DISABLE_NMI);
|
||||
|
@ -51,7 +120,7 @@ VOID CmosWriteAddress(BYTE Value)
|
|||
}
|
||||
}
|
||||
|
||||
BYTE CmosReadData(VOID)
|
||||
static BYTE CmosReadData(VOID)
|
||||
{
|
||||
BYTE Value;
|
||||
SYSTEMTIME CurrentTime;
|
||||
|
@ -181,7 +250,7 @@ BYTE CmosReadData(VOID)
|
|||
return Value;
|
||||
}
|
||||
|
||||
VOID CmosWriteData(BYTE Value)
|
||||
static VOID CmosWriteData(BYTE Value)
|
||||
{
|
||||
BOOLEAN ChangeTime = FALSE;
|
||||
SYSTEMTIME CurrentTime;
|
||||
|
@ -296,6 +365,7 @@ VOID CmosWriteData(BYTE Value)
|
|||
case CMOS_REG_STATUS_A:
|
||||
{
|
||||
CmosMemory.StatusRegA = Value & 0x7F; // Bit 7 is read-only
|
||||
RtcUpdatePeriodicTimer();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -342,13 +412,13 @@ VOID CmosWriteData(BYTE Value)
|
|||
SelectedRegister = CMOS_REG_STATUS_D;
|
||||
}
|
||||
|
||||
BYTE WINAPI CmosReadPort(USHORT Port)
|
||||
static BYTE WINAPI CmosReadPort(USHORT Port)
|
||||
{
|
||||
ASSERT(Port == CMOS_DATA_PORT);
|
||||
return CmosReadData();
|
||||
}
|
||||
|
||||
VOID WINAPI CmosWritePort(USHORT Port, BYTE Data)
|
||||
static VOID WINAPI CmosWritePort(USHORT Port, BYTE Data)
|
||||
{
|
||||
if (Port == CMOS_ADDRESS_PORT)
|
||||
CmosWriteAddress(Data);
|
||||
|
@ -356,68 +426,12 @@ VOID WINAPI CmosWritePort(USHORT Port, BYTE Data)
|
|||
CmosWriteData(Data);
|
||||
}
|
||||
|
||||
DWORD RtcGetTicksPerSecond(VOID)
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
BOOLEAN IsNmiEnabled(VOID)
|
||||
{
|
||||
BYTE RateSelect = CmosMemory.StatusRegB & 0x0F;
|
||||
|
||||
if (RateSelect == 0)
|
||||
{
|
||||
/* No periodic interrupt */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 1 and 2 act like 8 and 9 */
|
||||
if (RateSelect <= 2) RateSelect += 7;
|
||||
|
||||
return 1 << (16 - RateSelect);
|
||||
}
|
||||
|
||||
VOID RtcPeriodicTick(VOID)
|
||||
{
|
||||
/* Set PF */
|
||||
CmosMemory.StatusRegC |= CMOS_STC_PF;
|
||||
|
||||
/* Check if there should be an interrupt on a periodic timer tick */
|
||||
if (CmosMemory.StatusRegB & CMOS_STB_INT_PERIODIC)
|
||||
{
|
||||
CmosMemory.StatusRegC |= CMOS_STC_IRQF;
|
||||
|
||||
/* Interrupt! */
|
||||
PicInterruptRequest(RTC_IRQ_NUMBER);
|
||||
}
|
||||
}
|
||||
|
||||
/* Should be called every second */
|
||||
VOID RtcTimeUpdate(VOID)
|
||||
{
|
||||
SYSTEMTIME CurrentTime;
|
||||
|
||||
/* Get the current time */
|
||||
GetLocalTime(&CurrentTime);
|
||||
|
||||
/* Set UF */
|
||||
CmosMemory.StatusRegC |= CMOS_STC_UF;
|
||||
|
||||
/* Check if the time matches the alarm time */
|
||||
if ((CurrentTime.wHour == CmosMemory.AlarmHour ) &&
|
||||
(CurrentTime.wMinute == CmosMemory.AlarmMinute) &&
|
||||
(CurrentTime.wSecond == CmosMemory.AlarmSecond))
|
||||
{
|
||||
/* Set the alarm flag */
|
||||
CmosMemory.StatusRegC |= CMOS_STC_AF;
|
||||
|
||||
/* Set IRQF if there should be an interrupt */
|
||||
if (CmosMemory.StatusRegB & CMOS_STB_INT_ON_ALARM) CmosMemory.StatusRegC |= CMOS_STC_IRQF;
|
||||
}
|
||||
|
||||
/* Check if there should be an interrupt on update */
|
||||
if (CmosMemory.StatusRegB & CMOS_STB_INT_ON_UPDATE) CmosMemory.StatusRegC |= CMOS_STC_IRQF;
|
||||
|
||||
if (CmosMemory.StatusRegC & CMOS_STC_IRQF)
|
||||
{
|
||||
/* Interrupt! */
|
||||
PicInterruptRequest(RTC_IRQ_NUMBER);
|
||||
}
|
||||
return NmiEnabled;
|
||||
}
|
||||
|
||||
VOID CmosInitialize(VOID)
|
||||
|
@ -486,6 +500,11 @@ VOID CmosInitialize(VOID)
|
|||
/* Register the I/O Ports */
|
||||
RegisterIoPort(CMOS_ADDRESS_PORT, NULL , CmosWritePort);
|
||||
RegisterIoPort(CMOS_DATA_PORT , CmosReadPort, CmosWritePort);
|
||||
|
||||
ClockTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, 1000, RtcTimeUpdate);
|
||||
PeriodicTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED | HARDWARE_TIMER_PRECISE,
|
||||
1000000, /* 1,000,000 ns = 1 ms */
|
||||
RtcPeriodicTick);
|
||||
}
|
||||
|
||||
VOID CmosCleanup(VOID)
|
||||
|
@ -494,6 +513,9 @@ VOID CmosCleanup(VOID)
|
|||
|
||||
if (hCmosRam == INVALID_HANDLE_VALUE) return;
|
||||
|
||||
DestroyHardwareTimer(PeriodicTimer);
|
||||
DestroyHardwareTimer(ClockTimer);
|
||||
|
||||
/* Flush the CMOS memory back to the RAM file and close it */
|
||||
SetFilePointer(hCmosRam, 0, NULL, FILE_BEGIN);
|
||||
WriteFile(hCmosRam, &CmosMemory, CmosSize, &CmosSize, NULL);
|
||||
|
|
|
@ -128,8 +128,6 @@ C_ASSERT(sizeof(CMOS_MEMORY) == 0x40);
|
|||
|
||||
BOOLEAN IsNmiEnabled(VOID);
|
||||
DWORD RtcGetTicksPerSecond(VOID);
|
||||
VOID RtcPeriodicTick(VOID);
|
||||
VOID RtcTimeUpdate(VOID);
|
||||
|
||||
VOID CmosInitialize(VOID);
|
||||
VOID CmosCleanup(VOID);
|
||||
|
|
|
@ -12,31 +12,43 @@
|
|||
|
||||
#include "mouse.h"
|
||||
#include "ps2.h"
|
||||
// #include "pic.h"
|
||||
#include "clock.h"
|
||||
#include "video/vga.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
static const BYTE ScrollMagic[3] = { 200, 100, 80 };
|
||||
static const BYTE ExtraButtonMagic[3] = { 200, 200, 80 };
|
||||
|
||||
static HANDLE MouseMutex;
|
||||
static PHARDWARE_TIMER StreamTimer;
|
||||
static MOUSE_PACKET LastPacket;
|
||||
static MOUSE_MODE Mode, PreviousMode;
|
||||
static COORD Position;
|
||||
static ULONG WidthMm, HeightMm, WidthPixels, HeightPixels;
|
||||
static ULONG SampleRate;
|
||||
static ULONG Resolution;
|
||||
static BOOLEAN Scaling;
|
||||
static BYTE Resolution; /* Completely ignored */
|
||||
static BOOLEAN Scaling; /* Completely ignored */
|
||||
static BOOLEAN Reporting;
|
||||
static BYTE MouseId;
|
||||
static ULONG ButtonState;
|
||||
static SHORT HorzCounter;
|
||||
static SHORT VertCounter;
|
||||
static CHAR ScrollCounter;
|
||||
static BOOLEAN EventsOccurred = FALSE;
|
||||
static BYTE DataByteWait = 0;
|
||||
static BYTE ScrollMagicCounter = 0, ExtraButtonMagicCounter = 0;
|
||||
|
||||
static BYTE PS2Port = 1;
|
||||
|
||||
/* PUBLIC VARIABLES ***********************************************************/
|
||||
|
||||
UINT MouseCycles = 10;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static VOID MouseResetConfig(VOID)
|
||||
{
|
||||
/* Reset the configuration to defaults */
|
||||
SampleRate = 100;
|
||||
MouseCycles = 10;
|
||||
Resolution = 4;
|
||||
Scaling = FALSE;
|
||||
Reporting = FALSE;
|
||||
|
@ -45,7 +57,7 @@ static VOID MouseResetConfig(VOID)
|
|||
static VOID MouseResetCounters(VOID)
|
||||
{
|
||||
/* Reset all flags and counters */
|
||||
ButtonState = HorzCounter = VertCounter = ScrollCounter = 0;
|
||||
HorzCounter = VertCounter = ScrollCounter = 0;
|
||||
}
|
||||
|
||||
static VOID MouseReset(VOID)
|
||||
|
@ -57,42 +69,50 @@ static VOID MouseReset(VOID)
|
|||
/* Enter streaming mode and the reset the mouse ID */
|
||||
Mode = MOUSE_STREAMING_MODE;
|
||||
MouseId = 0;
|
||||
ScrollMagicCounter = ExtraButtonMagicCounter = 0;
|
||||
|
||||
/* Send the Basic Assurance Test success code and the device ID */
|
||||
PS2QueuePush(PS2Port, MOUSE_BAT_SUCCESS);
|
||||
PS2QueuePush(PS2Port, MouseId);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static VOID MouseGetPacket(PMOUSE_PACKET Packet)
|
||||
{
|
||||
/* Clear the packet */
|
||||
RtlZeroMemory(Packet, sizeof(*Packet));
|
||||
|
||||
/* Acquire the mutex */
|
||||
WaitForSingleObject(MouseMutex, INFINITE);
|
||||
|
||||
Packet->Flags |= MOUSE_ALWAYS_SET;
|
||||
|
||||
/* Check for horizontal overflows */
|
||||
if ((HorzCounter < MOUSE_MIN) || (HorzCounter > MOUSE_MAX))
|
||||
/* Set the sign flags */
|
||||
if (HorzCounter < 0)
|
||||
{
|
||||
if (HorzCounter > MOUSE_MAX) HorzCounter = MOUSE_MAX;
|
||||
if (HorzCounter < MOUSE_MIN) HorzCounter = MOUSE_MIN;
|
||||
Packet->Flags |= MOUSE_X_SIGN;
|
||||
HorzCounter = -HorzCounter;
|
||||
}
|
||||
|
||||
if (VertCounter < 0)
|
||||
{
|
||||
Packet->Flags |= MOUSE_Y_SIGN;
|
||||
VertCounter = -VertCounter;
|
||||
}
|
||||
|
||||
/* Check for horizontal overflows */
|
||||
if (HorzCounter > MOUSE_MAX)
|
||||
{
|
||||
HorzCounter = MOUSE_MAX;
|
||||
Packet->Flags |= MOUSE_X_OVERFLOW;
|
||||
}
|
||||
|
||||
/* Check for vertical overflows */
|
||||
if ((VertCounter < MOUSE_MIN) || (VertCounter > MOUSE_MAX))
|
||||
if (VertCounter > MOUSE_MAX)
|
||||
{
|
||||
if (VertCounter > MOUSE_MIN) VertCounter = MOUSE_MIN;
|
||||
if (VertCounter < MOUSE_MIN) VertCounter = MOUSE_MIN;
|
||||
|
||||
VertCounter = MOUSE_MAX;
|
||||
Packet->Flags |= MOUSE_Y_OVERFLOW;
|
||||
}
|
||||
|
||||
/* Set the sign flags */
|
||||
if (HorzCounter & MOUSE_SIGN_BIT) Packet->Flags |= MOUSE_X_SIGN;
|
||||
if (HorzCounter & MOUSE_SIGN_BIT) Packet->Flags |= MOUSE_Y_SIGN;
|
||||
|
||||
/* Set the button flags */
|
||||
if (ButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) Packet->Flags |= MOUSE_LEFT_BUTTON;
|
||||
if (ButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) Packet->Flags |= MOUSE_MIDDLE_BUTTON;
|
||||
|
@ -116,36 +136,94 @@ static VOID MouseGetPacket(PMOUSE_PACKET Packet)
|
|||
|
||||
/* Reset the counters */
|
||||
MouseResetCounters();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*static*/ VOID MouseUpdatePosition(PCOORD NewPosition)
|
||||
{
|
||||
/* Update the counters */
|
||||
HorzCounter += ((NewPosition->X - Position.X) * WidthMm * Resolution) / WidthPixels;
|
||||
VertCounter += ((NewPosition->Y - Position.Y) * HeightMm * Resolution) / HeightPixels;
|
||||
|
||||
/* Update the position */
|
||||
Position = *NewPosition;
|
||||
/* Release the mutex */
|
||||
ReleaseMutex(MouseMutex);
|
||||
}
|
||||
|
||||
/*static*/ VOID MouseUpdateButtons(ULONG NewButtonState)
|
||||
static VOID MouseDispatchPacket(PMOUSE_PACKET Packet)
|
||||
{
|
||||
ButtonState = NewButtonState;
|
||||
}
|
||||
|
||||
/*static*/ VOID MouseScroll(LONG Direction)
|
||||
{
|
||||
ScrollCounter += Direction;
|
||||
}
|
||||
|
||||
/*static*/ COORD MouseGetPosition(VOID)
|
||||
{
|
||||
return Position;
|
||||
PS2QueuePush(PS2Port, Packet->Flags);
|
||||
PS2QueuePush(PS2Port, Packet->HorzCounter);
|
||||
PS2QueuePush(PS2Port, Packet->VertCounter);
|
||||
if (MouseId >= 3) PS2QueuePush(PS2Port, Packet->Extra);
|
||||
}
|
||||
|
||||
static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command)
|
||||
{
|
||||
/* Check if we were waiting for a data byte */
|
||||
if (DataByteWait)
|
||||
{
|
||||
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||
|
||||
switch (DataByteWait)
|
||||
{
|
||||
/* Set Resolution */
|
||||
case 0xE8:
|
||||
{
|
||||
Resolution = Command;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set Sample Rate */
|
||||
case 0xF3:
|
||||
{
|
||||
/* Check for the scroll wheel enabling sequence */
|
||||
if (MouseId == 0)
|
||||
{
|
||||
if (Command == ScrollMagic[ScrollMagicCounter])
|
||||
{
|
||||
ScrollMagicCounter++;
|
||||
if (ScrollMagicCounter == 3) MouseId = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScrollMagicCounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for the 5-button enabling sequence */
|
||||
if (MouseId == 3)
|
||||
{
|
||||
if (Command == ExtraButtonMagic[ExtraButtonMagicCounter])
|
||||
{
|
||||
ExtraButtonMagicCounter++;
|
||||
if (ExtraButtonMagicCounter == 3) MouseId = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
ExtraButtonMagicCounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MouseCycles = 1000 / (UINT)Command;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
/* Shouldn't happen */
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
DataByteWait = 0;
|
||||
}
|
||||
|
||||
/* Check if we're in wrap mode */
|
||||
if (Mode == MOUSE_WRAP_MODE)
|
||||
{
|
||||
/*
|
||||
* In this mode, we just echo whatever byte we get,
|
||||
* except for the 0xEC and 0xFF commands.
|
||||
*/
|
||||
if (Command != 0xEC && Command != 0xFF)
|
||||
{
|
||||
PS2QueuePush(PS2Port, Command);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (Command)
|
||||
{
|
||||
/* Set 1:1 Scaling */
|
||||
|
@ -166,17 +244,27 @@ static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command)
|
|||
|
||||
/* Set Resolution */
|
||||
case 0xE8:
|
||||
/* Set Sample Rate */
|
||||
case 0xF3:
|
||||
{
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||
DataByteWait = Command;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read Status */
|
||||
case 0xE9:
|
||||
{
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
BYTE Status = ButtonState & 7;
|
||||
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||
|
||||
if (Scaling) Status |= 1 << 4;
|
||||
if (Reporting) Status |= 1 << 5;
|
||||
if (Mode == MOUSE_REMOTE_MODE) Status |= 1 << 6;
|
||||
|
||||
PS2QueuePush(PS2Port, Status);
|
||||
PS2QueuePush(PS2Port, Resolution);
|
||||
PS2QueuePush(PS2Port, (BYTE)(1000 / MouseCycles));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -193,8 +281,9 @@ static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command)
|
|||
/* Read Packet */
|
||||
case 0xEB:
|
||||
{
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||
MouseGetPacket(&LastPacket);
|
||||
MouseDispatchPacket(&LastPacket);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -247,14 +336,6 @@ static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Set Sample Rate */
|
||||
case 0xF3:
|
||||
{
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable Reporting */
|
||||
case 0xF4:
|
||||
{
|
||||
|
@ -283,8 +364,8 @@ static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command)
|
|||
/* Resend */
|
||||
case 0xFE:
|
||||
{
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||
MouseDispatchPacket(&LastPacket);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -303,50 +384,77 @@ static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command)
|
|||
}
|
||||
}
|
||||
|
||||
static VOID FASTCALL MouseStreamingCallback(ULONGLONG ElapsedTime)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(ElapsedTime);
|
||||
|
||||
/* Check if we're not in streaming mode, not reporting, or there's nothing to report */
|
||||
if (Mode != MOUSE_STREAMING_MODE || !Reporting || !EventsOccurred) return;
|
||||
|
||||
MouseGetPacket(&LastPacket);
|
||||
MouseDispatchPacket(&LastPacket);
|
||||
|
||||
EventsOccurred = FALSE;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID MouseGetDataFast(PCOORD CurrentPosition, PBYTE CurrentButtonState)
|
||||
{
|
||||
WaitForSingleObject(MouseMutex, INFINITE);
|
||||
*CurrentPosition = Position;
|
||||
*CurrentButtonState = LOBYTE(ButtonState);
|
||||
ReleaseMutex(MouseMutex);
|
||||
}
|
||||
|
||||
VOID MouseEventHandler(PMOUSE_EVENT_RECORD MouseEvent)
|
||||
{
|
||||
extern COORD DosNewPosition;
|
||||
extern WORD DosButtonState;
|
||||
COORD NewPosition = MouseEvent->dwMousePosition;
|
||||
BOOLEAN DoubleWidth = FALSE, DoubleHeight = FALSE;
|
||||
|
||||
// FIXME: Sync our private data
|
||||
MouseUpdatePosition(&MouseEvent->dwMousePosition);
|
||||
MouseUpdateButtons(MouseEvent->dwButtonState);
|
||||
if (!VgaGetDoubleVisionState(&DoubleWidth, &DoubleHeight))
|
||||
{
|
||||
/* Text mode */
|
||||
NewPosition.X *= 8;
|
||||
NewPosition.Y *= 8;
|
||||
}
|
||||
|
||||
// HACK: Bypass PS/2 and instead, notify the MOUSE.COM driver directly
|
||||
DosNewPosition = MouseEvent->dwMousePosition;
|
||||
DosButtonState = LOWORD(MouseEvent->dwButtonState);
|
||||
/* Adjust for double vision */
|
||||
if (DoubleWidth) NewPosition.X /= 2;
|
||||
if (DoubleHeight) NewPosition.Y /= 2;
|
||||
|
||||
// PS2QueuePush(PS2Port, Data);
|
||||
WaitForSingleObject(MouseMutex, INFINITE);
|
||||
|
||||
/* Update the counters */
|
||||
HorzCounter += NewPosition.X - Position.X;
|
||||
VertCounter += NewPosition.Y - Position.Y;
|
||||
|
||||
/* Update the position */
|
||||
Position = NewPosition;
|
||||
|
||||
/* Update the button state */
|
||||
ButtonState = MouseEvent->dwButtonState;
|
||||
|
||||
if (MouseEvent->dwEventFlags & MOUSE_WHEELED)
|
||||
{
|
||||
ScrollCounter += (SHORT)HIWORD(MouseEvent->dwButtonState);
|
||||
}
|
||||
|
||||
EventsOccurred = TRUE;
|
||||
ReleaseMutex(MouseMutex);
|
||||
}
|
||||
|
||||
BOOLEAN MouseInit(BYTE PS2Connector)
|
||||
{
|
||||
HWND hWnd;
|
||||
HDC hDC;
|
||||
|
||||
/* Get the console window */
|
||||
hWnd = GetConsoleWindow();
|
||||
if (hWnd == NULL) return FALSE;
|
||||
|
||||
/* Get the console window's device context */
|
||||
hDC = GetWindowDC(hWnd);
|
||||
if (hDC == NULL) return FALSE;
|
||||
|
||||
/* Get the parameters */
|
||||
WidthMm = (ULONG)GetDeviceCaps(hDC, HORZSIZE);
|
||||
HeightMm = (ULONG)GetDeviceCaps(hDC, VERTSIZE);
|
||||
WidthPixels = (ULONG)GetDeviceCaps(hDC, HORZRES);
|
||||
HeightPixels = (ULONG)GetDeviceCaps(hDC, VERTRES);
|
||||
|
||||
/* Release the device context */
|
||||
ReleaseDC(hWnd, hDC);
|
||||
|
||||
/* Finish to plug the mouse to the specified PS/2 port */
|
||||
PS2Port = PS2Connector;
|
||||
PS2SetDeviceCmdProc(PS2Port, NULL, MouseCommand);
|
||||
|
||||
MouseMutex = CreateMutex(NULL, FALSE, NULL);
|
||||
if (MouseMutex == NULL) return FALSE;
|
||||
|
||||
StreamTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, 10, MouseStreamingCallback);
|
||||
|
||||
MouseReset();
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -16,9 +16,7 @@
|
|||
/* DEFINES ********************************************************************/
|
||||
|
||||
/* Mouse packet constants */
|
||||
#define MOUSE_MIN -256
|
||||
#define MOUSE_MAX 255
|
||||
#define MOUSE_SIGN_BIT (1 << 8)
|
||||
|
||||
/* Mouse packet flags */
|
||||
#define MOUSE_LEFT_BUTTON (1 << 0)
|
||||
|
@ -69,6 +67,7 @@ typedef struct _MOUSE_PACKET
|
|||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID MouseEventHandler(PMOUSE_EVENT_RECORD MouseEvent);
|
||||
VOID MouseGetDataFast(PCOORD CurrentPosition, PBYTE CurrentButtonState);
|
||||
BOOLEAN MouseInit(BYTE PS2Connector);
|
||||
|
||||
#endif // _MOUSE_H_
|
||||
|
|
|
@ -16,10 +16,12 @@
|
|||
#include "io.h"
|
||||
#include "pit.h"
|
||||
#include "pic.h"
|
||||
#include "clock.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
static PIT_CHANNEL PitChannels[PIT_CHANNELS];
|
||||
static PHARDWARE_TIMER MasterClock;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
|
@ -451,6 +453,17 @@ static VOID PitDecrementCount(PPIT_CHANNEL Channel, DWORD Count)
|
|||
}
|
||||
}
|
||||
|
||||
static VOID FASTCALL PitClock(ULONGLONG Count)
|
||||
{
|
||||
UCHAR i;
|
||||
|
||||
for (i = 0; i < PIT_CHANNELS; i++)
|
||||
{
|
||||
// if (!PitChannels[i].Counting) continue;
|
||||
PitDecrementCount(&PitChannels[i], Count);
|
||||
}
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID PitSetOutFunction(BYTE Channel, LPVOID Param, PIT_OUT_FUNCTION OutFunction)
|
||||
|
@ -480,38 +493,6 @@ WORD PitGetReloadValue(BYTE Channel)
|
|||
return PitChannels[Channel].ReloadValue;
|
||||
}
|
||||
|
||||
DWORD PitGetResolution(VOID)
|
||||
{
|
||||
UCHAR i;
|
||||
DWORD MinReloadValue = 65536;
|
||||
|
||||
for (i = 0; i < PIT_CHANNELS; i++)
|
||||
{
|
||||
DWORD ReloadValue = PitChannels[i].ReloadValue;
|
||||
|
||||
/* 0 means 65536 */
|
||||
if (ReloadValue == 0) ReloadValue = 65536;
|
||||
|
||||
if (ReloadValue < MinReloadValue) MinReloadValue = ReloadValue;
|
||||
}
|
||||
|
||||
/* Return the frequency resolution */
|
||||
return PIT_BASE_FREQUENCY / MinReloadValue;
|
||||
}
|
||||
|
||||
VOID PitClock(DWORD Count)
|
||||
{
|
||||
UCHAR i;
|
||||
|
||||
if (Count == 0) return;
|
||||
|
||||
for (i = 0; i < PIT_CHANNELS; i++)
|
||||
{
|
||||
// if (!PitChannels[i].Counting) continue;
|
||||
PitDecrementCount(&PitChannels[i], Count);
|
||||
}
|
||||
}
|
||||
|
||||
VOID PitInitialize(VOID)
|
||||
{
|
||||
/* Set up the timers to their default value */
|
||||
|
@ -527,6 +508,11 @@ VOID PitInitialize(VOID)
|
|||
RegisterIoPort(PIT_DATA_PORT(0), PitReadPort, PitWritePort);
|
||||
RegisterIoPort(PIT_DATA_PORT(1), PitReadPort, PitWritePort);
|
||||
RegisterIoPort(PIT_DATA_PORT(2), PitReadPort, PitWritePort);
|
||||
|
||||
/* Register the hardware timer */
|
||||
MasterClock = CreateHardwareTimer(HARDWARE_TIMER_ENABLED | HARDWARE_TIMER_PRECISE,
|
||||
1000000000ULL / PIT_BASE_FREQUENCY,
|
||||
PitClock);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -79,9 +79,6 @@ VOID PitSetOutFunction(BYTE Channel, LPVOID Param, PIT_OUT_FUNCTION OutFunction)
|
|||
VOID PitSetGate(BYTE Channel, BOOLEAN State);
|
||||
WORD PitGetReloadValue(BYTE Channel);
|
||||
|
||||
DWORD PitGetResolution(VOID);
|
||||
VOID PitClock(DWORD Count);
|
||||
|
||||
VOID PitInitialize(VOID);
|
||||
|
||||
#endif // _PIT_H_
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "io.h"
|
||||
#include "ps2.h"
|
||||
#include "pic.h"
|
||||
#include "clock.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
|
@ -49,6 +50,8 @@ static BYTE StatusRegister = 0x00;
|
|||
// static BYTE InputBuffer = 0x00; // PS/2 Input Buffer
|
||||
static BYTE OutputBuffer = 0x00; // PS/2 Output Buffer
|
||||
|
||||
static PHARDWARE_TIMER IrqTimer = NULL;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static VOID PS2SendCommand(PPS2_PORT Port, BYTE Command)
|
||||
|
@ -262,7 +265,30 @@ static VOID WINAPI PS2WritePort(USHORT Port, BYTE Data)
|
|||
}
|
||||
}
|
||||
|
||||
static BOOLEAN PS2PortQueueRead(BYTE PS2Port)
|
||||
static VOID FASTCALL GeneratePS2Irq(ULONGLONG ElapsedTime)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(ElapsedTime);
|
||||
|
||||
/* Generate an IRQ 1 if there is data ready in the output queue */
|
||||
if (PS2PortQueueRead(0))
|
||||
{
|
||||
/* Generate an interrupt if interrupts for the first PS/2 port are enabled */
|
||||
if (ControllerConfig & 0x01) PicInterruptRequest(1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Generate an IRQ 12 if there is data ready in the output queue */
|
||||
if (PS2PortQueueRead(1))
|
||||
{
|
||||
/* Generate an interrupt if interrupts for the second PS/2 port are enabled */
|
||||
if (ControllerConfig & 0x02) PicInterruptRequest(12);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
BOOLEAN PS2PortQueueRead(BYTE PS2Port)
|
||||
{
|
||||
BOOLEAN Result = TRUE;
|
||||
PPS2_PORT Port;
|
||||
|
@ -316,8 +342,6 @@ Done:
|
|||
return Result;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID PS2SetDeviceCmdProc(BYTE PS2Port, LPVOID Param, PS2_DEVICE_CMDPROC DeviceCommand)
|
||||
{
|
||||
if (PS2Port >= PS2_PORTS) return;
|
||||
|
@ -354,43 +378,14 @@ BOOLEAN PS2QueuePush(BYTE PS2Port, BYTE Data)
|
|||
/* The queue is not empty anymore */
|
||||
Port->QueueEmpty = FALSE;
|
||||
|
||||
/*
|
||||
// Get the data
|
||||
OutputBuffer = Port->Queue[Port->QueueStart];
|
||||
StatusRegister |= (1 << 0); // There is something to read
|
||||
// FIXME: Sometimes StatusRegister |= (1 << 5); for the second PS/2 port
|
||||
|
||||
if (PS2Port == 0)
|
||||
PicInterruptRequest(1);
|
||||
else if (PS2Port == 1)
|
||||
PicInterruptRequest(12);
|
||||
*/
|
||||
/* Schedule the IRQ */
|
||||
EnableHardwareTimer(IrqTimer);
|
||||
|
||||
Done:
|
||||
ReleaseMutex(Port->QueueMutex);
|
||||
return Result;
|
||||
}
|
||||
|
||||
VOID GenerateIrq1(VOID)
|
||||
{
|
||||
/* Generate an interrupt if interrupts for the first PS/2 port are enabled */
|
||||
if (ControllerConfig & 0x01)
|
||||
{
|
||||
/* Generate an IRQ 1 if there is data ready in the output queue */
|
||||
if (PS2PortQueueRead(0)) PicInterruptRequest(1);
|
||||
}
|
||||
}
|
||||
|
||||
VOID GenerateIrq12(VOID)
|
||||
{
|
||||
/* Generate an interrupt if interrupts for the second PS/2 port are enabled */
|
||||
if (ControllerConfig & 0x02)
|
||||
{
|
||||
/* Generate an IRQ 12 if there is data ready in the output queue */
|
||||
if (PS2PortQueueRead(1)) PicInterruptRequest(12);
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN PS2Initialize(VOID)
|
||||
{
|
||||
/* Initialize the PS/2 ports */
|
||||
|
@ -410,11 +405,15 @@ BOOLEAN PS2Initialize(VOID)
|
|||
RegisterIoPort(PS2_CONTROL_PORT, PS2ReadPort, PS2WritePort);
|
||||
RegisterIoPort(PS2_DATA_PORT , PS2ReadPort, PS2WritePort);
|
||||
|
||||
IrqTimer = CreateHardwareTimer(HARDWARE_TIMER_ONESHOT, 20, GeneratePS2Irq);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID PS2Cleanup(VOID)
|
||||
{
|
||||
DestroyHardwareTimer(IrqTimer);
|
||||
|
||||
CloseHandle(Ports[1].QueueMutex);
|
||||
CloseHandle(Ports[0].QueueMutex);
|
||||
}
|
||||
|
|
|
@ -26,9 +26,7 @@ typedef VOID (WINAPI *PS2_DEVICE_CMDPROC)(LPVOID Param, BYTE Command);
|
|||
VOID PS2SetDeviceCmdProc(BYTE PS2Port, LPVOID Param, PS2_DEVICE_CMDPROC DeviceCommand);
|
||||
|
||||
BOOLEAN PS2QueuePush(BYTE PS2Port, BYTE Data);
|
||||
|
||||
VOID GenerateIrq1(VOID);
|
||||
VOID GenerateIrq12(VOID);
|
||||
BOOLEAN PS2PortQueueRead(BYTE PS2Port);
|
||||
|
||||
BOOLEAN PS2Initialize(VOID);
|
||||
VOID PS2Cleanup(VOID);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "memory.h"
|
||||
#include "io.h"
|
||||
#include "clock.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
|
@ -245,6 +246,9 @@ static HANDLE ConsoleMutex = NULL;
|
|||
static BOOLEAN DoubleWidth = FALSE;
|
||||
static BOOLEAN DoubleHeight = FALSE;
|
||||
|
||||
static PHARDWARE_TIMER VSyncTimer;
|
||||
static PHARDWARE_TIMER HSyncTimer;
|
||||
|
||||
/*
|
||||
* VGA Hardware
|
||||
*/
|
||||
|
@ -1754,60 +1758,12 @@ static VOID WINAPI VgaWritePort(USHORT Port, BYTE Data)
|
|||
}
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
COORD VgaGetDisplayResolution(VOID)
|
||||
{
|
||||
COORD Resolution;
|
||||
BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
|
||||
|
||||
/* The low 8 bits are in the display registers */
|
||||
Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG];
|
||||
Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG];
|
||||
|
||||
/* Set the top bits from the overflow register */
|
||||
if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
|
||||
{
|
||||
Resolution.Y |= 1 << 8;
|
||||
}
|
||||
if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
|
||||
{
|
||||
Resolution.Y |= 1 << 9;
|
||||
}
|
||||
|
||||
/* Increase the values by 1 */
|
||||
Resolution.X++;
|
||||
Resolution.Y++;
|
||||
|
||||
if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
|
||||
{
|
||||
/* Multiply the horizontal resolution by the 9/8 dot mode */
|
||||
Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
|
||||
? 8 : 9;
|
||||
|
||||
/* The horizontal resolution is halved in 8-bit mode */
|
||||
if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
|
||||
}
|
||||
|
||||
if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
|
||||
{
|
||||
/* Halve the vertical resolution */
|
||||
Resolution.Y >>= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
|
||||
Resolution.Y /= MaximumScanLine;
|
||||
}
|
||||
|
||||
/* Return the resolution */
|
||||
return Resolution;
|
||||
}
|
||||
|
||||
VOID VgaRefreshDisplay(VOID)
|
||||
static VOID FASTCALL VgaVerticalRetrace(ULONGLONG ElapsedTime)
|
||||
{
|
||||
HANDLE ConsoleBufferHandle = NULL;
|
||||
|
||||
UNREFERENCED_PARAMETER(ElapsedTime);
|
||||
|
||||
/* Set the vertical retrace flag */
|
||||
InVerticalRetrace = TRUE;
|
||||
|
||||
|
@ -1876,12 +1832,77 @@ VOID VgaRefreshDisplay(VOID)
|
|||
NeedsUpdate = FALSE;
|
||||
}
|
||||
|
||||
VOID VgaHorizontalRetrace(VOID)
|
||||
static VOID FASTCALL VgaHorizontalRetrace(ULONGLONG ElapsedTime)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(ElapsedTime);
|
||||
|
||||
/* Set the flag */
|
||||
InHorizontalRetrace = TRUE;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
COORD VgaGetDisplayResolution(VOID)
|
||||
{
|
||||
COORD Resolution;
|
||||
BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
|
||||
|
||||
/* The low 8 bits are in the display registers */
|
||||
Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG];
|
||||
Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG];
|
||||
|
||||
/* Set the top bits from the overflow register */
|
||||
if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
|
||||
{
|
||||
Resolution.Y |= 1 << 8;
|
||||
}
|
||||
if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
|
||||
{
|
||||
Resolution.Y |= 1 << 9;
|
||||
}
|
||||
|
||||
/* Increase the values by 1 */
|
||||
Resolution.X++;
|
||||
Resolution.Y++;
|
||||
|
||||
if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
|
||||
{
|
||||
/* Multiply the horizontal resolution by the 9/8 dot mode */
|
||||
Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
|
||||
? 8 : 9;
|
||||
|
||||
/* The horizontal resolution is halved in 8-bit mode */
|
||||
if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
|
||||
}
|
||||
|
||||
if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
|
||||
{
|
||||
/* Halve the vertical resolution */
|
||||
Resolution.Y >>= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
|
||||
Resolution.Y /= MaximumScanLine;
|
||||
}
|
||||
|
||||
/* Return the resolution */
|
||||
return Resolution;
|
||||
}
|
||||
|
||||
BOOLEAN VgaGetDoubleVisionState(PBOOLEAN Vertical, PBOOLEAN Horizontal)
|
||||
{
|
||||
if (GraphicsConsoleBuffer == NULL) return FALSE;
|
||||
if (Vertical) *Vertical = DoubleWidth;
|
||||
if (Horizontal) *Horizontal = DoubleHeight;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID VgaRefreshDisplay(VOID)
|
||||
{
|
||||
VgaVerticalRetrace(0);
|
||||
}
|
||||
|
||||
VOID NTAPI VgaReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
|
||||
{
|
||||
DWORD i;
|
||||
|
@ -2106,12 +2127,18 @@ BOOLEAN VgaInitialize(HANDLE TextHandle)
|
|||
RegisterIoPort(0x3D8, VgaReadPort, VgaWritePort); // CGA_MODE_CTRL_REG
|
||||
RegisterIoPort(0x3D9, VgaReadPort, VgaWritePort); // CGA_PAL_CTRL_REG
|
||||
|
||||
HSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, 0, VgaHorizontalRetrace);
|
||||
VSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, 16, VgaVerticalRetrace);
|
||||
|
||||
/* Return success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID VgaCleanup(VOID)
|
||||
{
|
||||
DestroyHardwareTimer(VSyncTimer);
|
||||
DestroyHardwareTimer(HSyncTimer);
|
||||
|
||||
if (ScreenMode == GRAPHICS_MODE)
|
||||
{
|
||||
/* Leave the current graphics mode */
|
||||
|
|
|
@ -260,9 +260,9 @@ VOID VgaDetachFromConsole(BOOL ChangeMode);
|
|||
|
||||
COORD VgaGetDisplayResolution(VOID);
|
||||
VOID VgaRefreshDisplay(VOID);
|
||||
VOID VgaHorizontalRetrace(VOID);
|
||||
VOID VgaWriteFont(UINT FontNumber, CONST UCHAR *FontData, UINT Height);
|
||||
VOID VgaClearMemory(VOID);
|
||||
BOOLEAN VgaGetDoubleVisionState(PBOOLEAN Vertical, PBOOLEAN Horizontal);
|
||||
|
||||
BOOLEAN VgaInitialize(HANDLE TextHandle);
|
||||
VOID VgaCleanup(VOID);
|
||||
|
|
Loading…
Reference in a new issue