mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 23:33:01 +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 "io.h"
|
||||||
#include "hardware/mouse.h"
|
#include "hardware/mouse.h"
|
||||||
|
#include "hardware/ps2.h"
|
||||||
|
|
||||||
// HACK: For the PS/2 bypass and MOUSE.COM driver direct call
|
// HACK: For the PS/2 bypass and MOUSE.COM driver direct call
|
||||||
#include "dos/mouse32.h"
|
#include "dos/mouse32.h"
|
||||||
|
@ -28,13 +29,6 @@
|
||||||
// Mouse IRQ 12
|
// Mouse IRQ 12
|
||||||
static VOID WINAPI BiosMouseIrq(LPWORD Stack)
|
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);
|
PicIRQComplete(Stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,6 +112,7 @@ BOOLEAN MouseBios32Initialize(VOID)
|
||||||
{
|
{
|
||||||
/* Set up the HW vector interrupts */
|
/* Set up the HW vector interrupts */
|
||||||
EnableHwIRQ(12, BiosMouseIrq);
|
EnableHwIRQ(12, BiosMouseIrq);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,13 @@
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
#include "cpu/cpu.h"
|
#include "cpu/cpu.h"
|
||||||
|
|
||||||
// #include "clock.h"
|
#include "clock.h"
|
||||||
|
|
||||||
#include "hardware/cmos.h"
|
#include "hardware/cmos.h"
|
||||||
#include "hardware/ps2.h"
|
#include "hardware/ps2.h"
|
||||||
#include "hardware/pit.h"
|
#include "hardware/pit.h"
|
||||||
#include "hardware/video/vga.h"
|
#include "hardware/video/vga.h"
|
||||||
|
#include "hardware/mouse.h"
|
||||||
|
|
||||||
/* Extra PSDK/NDK Headers */
|
/* Extra PSDK/NDK Headers */
|
||||||
#include <ndk/kefuncs.h>
|
#include <ndk/kefuncs.h>
|
||||||
|
@ -28,8 +29,7 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Activate IPS_DISPLAY if you want to display the
|
* Activate IPS_DISPLAY if you want to display the
|
||||||
* number of instructions per second, as well as
|
* number of instructions per second.
|
||||||
* the computed number of ticks for the PIT.
|
|
||||||
*/
|
*/
|
||||||
// #define IPS_DISPLAY
|
// #define IPS_DISPLAY
|
||||||
|
|
||||||
|
@ -38,27 +38,27 @@
|
||||||
*/
|
*/
|
||||||
// #define WORKING_TIMER
|
// #define WORKING_TIMER
|
||||||
|
|
||||||
|
|
||||||
/* Processor speed */
|
/* Processor speed */
|
||||||
#define STEPS_PER_CYCLE 256
|
#define STEPS_PER_CYCLE 256
|
||||||
#define IRQ1_CYCLES 16
|
|
||||||
#define IRQ12_CYCLES 16
|
|
||||||
|
|
||||||
/* VARIABLES ******************************************************************/
|
/* VARIABLES ******************************************************************/
|
||||||
|
|
||||||
|
static LIST_ENTRY Timers;
|
||||||
static LARGE_INTEGER StartPerfCount, Frequency;
|
static LARGE_INTEGER StartPerfCount, Frequency;
|
||||||
|
static DWORD StartTickCount;
|
||||||
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;
|
|
||||||
|
|
||||||
#ifdef IPS_DISPLAY
|
#ifdef IPS_DISPLAY
|
||||||
static DWORD LastCyclePrintout;
|
static ULONGLONG Cycles = 0ULL;
|
||||||
static ULONGLONG Cycles = 0;
|
#endif
|
||||||
|
|
||||||
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
|
#ifdef IPS_DISPLAY
|
||||||
|
static VOID FASTCALL IpsDisplayCallback(ULONGLONG ElapsedTime)
|
||||||
|
{
|
||||||
|
DPRINT1("NTVDM: %I64u Instructions Per Second\n", Cycles / ElapsedTime);
|
||||||
|
Cycles = 0ULL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||||
|
@ -67,112 +67,159 @@ VOID ClockUpdate(VOID)
|
||||||
{
|
{
|
||||||
extern BOOLEAN CpuRunning;
|
extern BOOLEAN CpuRunning;
|
||||||
UINT i;
|
UINT i;
|
||||||
// LARGE_INTEGER Counter;
|
PLIST_ENTRY Entry;
|
||||||
|
LARGE_INTEGER Counter;
|
||||||
#ifdef WORKING_TIMER
|
|
||||||
DWORD PitResolution;
|
|
||||||
#endif
|
|
||||||
DWORD RtcFrequency;
|
|
||||||
|
|
||||||
while (VdmRunning && CpuRunning)
|
while (VdmRunning && CpuRunning)
|
||||||
{
|
{
|
||||||
|
/* Get the current number of ticks */
|
||||||
|
DWORD CurrentTickCount = GetTickCount();
|
||||||
|
|
||||||
#ifdef WORKING_TIMER
|
#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
|
#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 */
|
/* Continue CPU emulation */
|
||||||
CurrentTickCount = GetTickCount();
|
for (i = 0; VdmRunning && CpuRunning && (i < STEPS_PER_CYCLE); i++)
|
||||||
|
{
|
||||||
|
CpuStep();
|
||||||
|
|
||||||
#ifdef WORKING_TIMER
|
#ifdef IPS_DISPLAY
|
||||||
if ((PitResolution <= 1000) && (RtcFrequency <= 1000))
|
++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 */
|
if (Timer->Flags & HARDWARE_TIMER_PRECISE)
|
||||||
Counter.QuadPart = StartPerfCount.QuadPart
|
{
|
||||||
+ (CurrentTickCount - StartTickCount)
|
NtQueryPerformanceCounter(&Timer->LastTick, NULL);
|
||||||
* (Frequency.QuadPart / 1000);
|
}
|
||||||
|
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
|
else
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
/* Get the current performance counter value */
|
Timer->Delay = NewDelay;
|
||||||
/// DWORD_PTR oldmask = SetThreadAffinityMask(GetCurrentThread(), 0);
|
|
||||||
NtQueryPerformanceCounter(&Counter, NULL);
|
|
||||||
/// SetThreadAffinityMask(GetCurrentThread(), oldmask);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the number of PIT ticks that have passed */
|
VOID DestroyHardwareTimer(PHARDWARE_TIMER Timer)
|
||||||
TimerTicks = ((Counter.QuadPart - LastTimerTick.QuadPart)
|
{
|
||||||
* PIT_BASE_FREQUENCY) / Frequency.QuadPart;
|
if (Timer->Flags & HARDWARE_TIMER_ENABLED) RemoveEntryList(&Timer->Link);
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, Timer);
|
||||||
/* 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
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN ClockInitialize(VOID)
|
BOOLEAN ClockInitialize(VOID)
|
||||||
{
|
{
|
||||||
|
#ifdef IPS_DISPLAY
|
||||||
|
PHARDWARE_TIMER IpsTimer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
InitializeListHead(&Timers);
|
||||||
|
|
||||||
/* Initialize the performance counter (needed for hardware timers) */
|
/* Initialize the performance counter (needed for hardware timers) */
|
||||||
/* Find the starting performance */
|
/* Find the starting performance */
|
||||||
NtQueryPerformanceCounter(&StartPerfCount, &Frequency);
|
NtQueryPerformanceCounter(&StartPerfCount, &Frequency);
|
||||||
|
@ -185,15 +232,16 @@ BOOLEAN ClockInitialize(VOID)
|
||||||
/* Find the starting tick count */
|
/* Find the starting tick count */
|
||||||
StartTickCount = GetTickCount();
|
StartTickCount = GetTickCount();
|
||||||
|
|
||||||
/* Set the different last counts to the starting count */
|
|
||||||
LastClockUpdate = LastVerticalRefresh =
|
|
||||||
#ifdef IPS_DISPLAY
|
#ifdef IPS_DISPLAY
|
||||||
LastCyclePrintout =
|
|
||||||
#endif
|
|
||||||
StartTickCount;
|
|
||||||
|
|
||||||
/* Set the last timer ticks to the current time */
|
IpsTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, 1000, IpsDisplayCallback);
|
||||||
LastTimerTick = LastRtcTick = StartPerfCount;
|
if (IpsTimer == NULL)
|
||||||
|
{
|
||||||
|
wprintf(L"FATAL: Cannot create IPS display timer.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,39 @@
|
||||||
#ifndef _CLOCK_H_
|
#ifndef _CLOCK_H_
|
||||||
#define _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 ******************************************************************/
|
/* 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);
|
VOID ClockUpdate(VOID);
|
||||||
BOOLEAN ClockInitialize(VOID);
|
BOOLEAN ClockInitialize(VOID);
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,8 @@ enum
|
||||||
EMULATOR_EXCEPTION_PAGE_FAULT
|
EMULATOR_EXCEPTION_PAGE_FAULT
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern BOOLEAN CpuRunning;
|
||||||
extern FAST486_STATE EmulatorContext;
|
extern FAST486_STATE EmulatorContext;
|
||||||
|
|
||||||
/* FUNCTIONS ******************************************************************/
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
|
@ -423,7 +423,7 @@ static VOID WINAPI DosStart(LPWORD Stack)
|
||||||
RegisterBop(BOP_START_DOS, NULL);
|
RegisterBop(BOP_START_DOS, NULL);
|
||||||
|
|
||||||
/* Load the mouse driver */
|
/* Load the mouse driver */
|
||||||
// DosMouseInitialize();
|
DosMouseInitialize();
|
||||||
|
|
||||||
#ifndef STANDALONE
|
#ifndef STANDALONE
|
||||||
|
|
||||||
|
|
|
@ -13,36 +13,45 @@
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
#include "cpu/cpu.h"
|
#include "cpu/cpu.h"
|
||||||
#include "int32.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 "mouse32.h"
|
||||||
#include "bios/bios.h"
|
#include "bios/bios.h"
|
||||||
|
#include "bios/bios32/bios32p.h"
|
||||||
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "dos32krnl/dos.h"
|
#include "dos32krnl/dos.h"
|
||||||
|
|
||||||
/* PRIVATE VARIABLES **********************************************************/
|
/* PRIVATE VARIABLES **********************************************************/
|
||||||
|
|
||||||
static BOOLEAN DriverEnabled = TRUE;
|
#define MICKEYS_PER_CELL_HORIZ 8
|
||||||
static MOUSE_DRIVER_STATE DriverState;
|
#define MICKEYS_PER_CELL_VERT 16
|
||||||
|
|
||||||
/**/
|
static MOUSE_PACKET Packet;
|
||||||
COORD DosNewPosition;
|
static INT ByteCounter = 0;
|
||||||
WORD DosButtonState;
|
static BOOLEAN DriverEnabled = FALSE;
|
||||||
/**/
|
static MOUSE_DRIVER_STATE DriverState;
|
||||||
|
static DWORD OldIrqHandler;
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS **********************************************************/
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
|
extern VOID WINAPI BiosMouseIrq(LPWORD Stack);
|
||||||
|
|
||||||
static VOID PaintMouseCursor(VOID)
|
static VOID PaintMouseCursor(VOID)
|
||||||
{
|
{
|
||||||
if (Bda->VideoMode <= 3)
|
if (Bda->VideoMode <= 3)
|
||||||
{
|
{
|
||||||
WORD Character;
|
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);
|
DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize);
|
||||||
|
|
||||||
EmulatorReadMemory(&EmulatorContext,
|
EmulatorReadMemory(&EmulatorContext,
|
||||||
VideoAddress
|
VideoAddress
|
||||||
+ (DriverState.Position.Y * Bda->ScreenColumns
|
+ (CellY * Bda->ScreenColumns + CellX) * sizeof(WORD),
|
||||||
+ DriverState.Position.X) * sizeof(WORD),
|
|
||||||
(LPVOID)&Character,
|
(LPVOID)&Character,
|
||||||
sizeof(WORD));
|
sizeof(WORD));
|
||||||
|
|
||||||
|
@ -52,8 +61,7 @@ static VOID PaintMouseCursor(VOID)
|
||||||
|
|
||||||
EmulatorWriteMemory(&EmulatorContext,
|
EmulatorWriteMemory(&EmulatorContext,
|
||||||
VideoAddress
|
VideoAddress
|
||||||
+ (DriverState.Position.Y * Bda->ScreenColumns
|
+ (CellY * Bda->ScreenColumns + CellX) * sizeof(WORD),
|
||||||
+ DriverState.Position.X) * sizeof(WORD),
|
|
||||||
(LPVOID)&Character,
|
(LPVOID)&Character,
|
||||||
sizeof(WORD));
|
sizeof(WORD));
|
||||||
}
|
}
|
||||||
|
@ -68,12 +76,13 @@ static VOID EraseMouseCursor(VOID)
|
||||||
{
|
{
|
||||||
if (Bda->VideoMode <= 3)
|
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);
|
DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize);
|
||||||
|
|
||||||
EmulatorWriteMemory(&EmulatorContext,
|
EmulatorWriteMemory(&EmulatorContext,
|
||||||
VideoAddress
|
VideoAddress
|
||||||
+ (DriverState.Position.Y * Bda->ScreenColumns
|
+ (CellY * Bda->ScreenColumns + CellX) * sizeof(WORD),
|
||||||
+ DriverState.Position.X) * sizeof(WORD),
|
|
||||||
(LPVOID)&DriverState.Character,
|
(LPVOID)&DriverState.Character,
|
||||||
sizeof(WORD));
|
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)
|
static VOID CallMouseUserHandlers(USHORT CallMask)
|
||||||
{
|
{
|
||||||
USHORT i;
|
USHORT i;
|
||||||
USHORT AX, BX, CX, DX, SI, DI;
|
USHORT AX, BX, CX, DX, SI, DI;
|
||||||
|
COORD Position = DriverState.Position;
|
||||||
|
|
||||||
|
ToMouseCoordinates(&Position);
|
||||||
|
|
||||||
/* Call handler 0 */
|
/* Call handler 0 */
|
||||||
if ((DriverState.Handler0.CallMask & CallMask) != 0 &&
|
if ((DriverState.Handler0.CallMask & CallMask) != 0 &&
|
||||||
|
@ -108,10 +152,10 @@ static VOID CallMouseUserHandlers(USHORT CallMask)
|
||||||
|
|
||||||
setAX(CallMask);
|
setAX(CallMask);
|
||||||
setBX(DriverState.ButtonState);
|
setBX(DriverState.ButtonState);
|
||||||
setCX(DriverState.Position.X);
|
setCX(Position.X);
|
||||||
setDX(DriverState.Position.Y);
|
setDX(Position.Y);
|
||||||
setSI(DriverState.MickeysPerCellHoriz);
|
setSI(MICKEYS_PER_CELL_HORIZ);
|
||||||
setDI(DriverState.MickeysPerCellVert);
|
setDI(MICKEYS_PER_CELL_VERT);
|
||||||
|
|
||||||
DPRINT("Calling Handler0 %04X:%04X with CallMask 0x%04X\n",
|
DPRINT("Calling Handler0 %04X:%04X with CallMask 0x%04X\n",
|
||||||
HIWORD(DriverState.Handler0.Callback),
|
HIWORD(DriverState.Handler0.Callback),
|
||||||
|
@ -150,10 +194,10 @@ static VOID CallMouseUserHandlers(USHORT CallMask)
|
||||||
|
|
||||||
setAX(CallMask);
|
setAX(CallMask);
|
||||||
setBX(DriverState.ButtonState);
|
setBX(DriverState.ButtonState);
|
||||||
setCX(DriverState.Position.X);
|
setCX(Position.X);
|
||||||
setDX(DriverState.Position.Y);
|
setDX(Position.Y);
|
||||||
setSI(DriverState.MickeysPerCellHoriz);
|
setSI(MICKEYS_PER_CELL_HORIZ);
|
||||||
setDI(DriverState.MickeysPerCellVert);
|
setDI(MICKEYS_PER_CELL_VERT);
|
||||||
|
|
||||||
DPRINT1("Calling Handler[%d] %04X:%04X with CallMask 0x%04X\n",
|
DPRINT1("Calling Handler[%d] %04X:%04X with CallMask 0x%04X\n",
|
||||||
i,
|
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)
|
static VOID WINAPI DosMouseService(LPWORD Stack)
|
||||||
{
|
{
|
||||||
switch (getAX())
|
switch (getAX())
|
||||||
|
@ -183,10 +348,15 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
||||||
{
|
{
|
||||||
SHORT i;
|
SHORT i;
|
||||||
|
|
||||||
DriverEnabled = TRUE;
|
|
||||||
DriverState.ShowCount = 0;
|
DriverState.ShowCount = 0;
|
||||||
DriverState.ButtonState = 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 */
|
/* Set the default text cursor */
|
||||||
DriverState.TextCursor.ScreenMask = 0xFFFF; /* Display everything */
|
DriverState.TextCursor.ScreenMask = 0xFFFF; /* Display everything */
|
||||||
DriverState.TextCursor.CursorMask = 0xFF00; /* ... but with inverted attributes */
|
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;
|
DriverState.PressCount[i] = DriverState.ReleaseCount[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the resolution */
|
|
||||||
DriverState.MickeysPerCellHoriz = 8;
|
|
||||||
DriverState.MickeysPerCellVert = 16;
|
|
||||||
|
|
||||||
/* Return mouse information */
|
/* Return mouse information */
|
||||||
setAX(0xFFFF); // Hardware & driver installed
|
setAX(0xFFFF); // Hardware & driver installed
|
||||||
setBX(NUM_MOUSE_BUTTONS);
|
setBX(NUM_MOUSE_BUTTONS);
|
||||||
|
@ -252,7 +418,7 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
||||||
case 0x01:
|
case 0x01:
|
||||||
{
|
{
|
||||||
DriverState.ShowCount++;
|
DriverState.ShowCount++;
|
||||||
if (DriverState.ShowCount > 0) PaintMouseCursor();
|
if (DriverState.ShowCount == 1) PaintMouseCursor();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -261,7 +427,7 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
||||||
case 0x02:
|
case 0x02:
|
||||||
{
|
{
|
||||||
DriverState.ShowCount--;
|
DriverState.ShowCount--;
|
||||||
if (DriverState.ShowCount <= 0) EraseMouseCursor();
|
if (DriverState.ShowCount == 0) EraseMouseCursor();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -269,23 +435,22 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
||||||
/* Return Position And Button Status */
|
/* Return Position And Button Status */
|
||||||
case 0x03:
|
case 0x03:
|
||||||
{
|
{
|
||||||
|
COORD Position = DriverState.Position;
|
||||||
|
ToMouseCoordinates(&Position);
|
||||||
|
|
||||||
setBX(DriverState.ButtonState);
|
setBX(DriverState.ButtonState);
|
||||||
setCX(DriverState.Position.X);
|
setCX(Position.X);
|
||||||
setDX(DriverState.Position.Y);
|
setDX(Position.Y);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Position Mouse Cursor */
|
/* Position Mouse Cursor */
|
||||||
case 0x04:
|
case 0x04:
|
||||||
{
|
{
|
||||||
POINT Point;
|
COORD Position = { getCX(), getDX() };
|
||||||
|
FromMouseCoordinates(&Position);
|
||||||
Point.x = getCX();
|
|
||||||
Point.y = getDX();
|
|
||||||
|
|
||||||
ClientToScreen(GetConsoleWindow(), &Point);
|
|
||||||
SetCursorPos(Point.x, Point.y);
|
|
||||||
|
|
||||||
|
DriverState.Position = Position;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,11 +458,13 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
||||||
case 0x05:
|
case 0x05:
|
||||||
{
|
{
|
||||||
WORD Button = getBX();
|
WORD Button = getBX();
|
||||||
|
COORD LastPress = DriverState.LastPress[Button];
|
||||||
|
ToMouseCoordinates(&LastPress);
|
||||||
|
|
||||||
setAX(DriverState.ButtonState);
|
setAX(DriverState.ButtonState);
|
||||||
setBX(DriverState.PressCount[Button]);
|
setBX(DriverState.PressCount[Button]);
|
||||||
setCX(DriverState.LastPress[Button].X);
|
setCX(LastPress.X);
|
||||||
setDX(DriverState.LastPress[Button].Y);
|
setDX(LastPress.Y);
|
||||||
|
|
||||||
/* Reset the counter */
|
/* Reset the counter */
|
||||||
DriverState.PressCount[Button] = 0;
|
DriverState.PressCount[Button] = 0;
|
||||||
|
@ -309,11 +476,13 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
||||||
case 0x06:
|
case 0x06:
|
||||||
{
|
{
|
||||||
WORD Button = getBX();
|
WORD Button = getBX();
|
||||||
|
COORD LastRelease = DriverState.LastRelease[Button];
|
||||||
|
ToMouseCoordinates(&LastRelease);
|
||||||
|
|
||||||
setAX(DriverState.ButtonState);
|
setAX(DriverState.ButtonState);
|
||||||
setBX(DriverState.ReleaseCount[Button]);
|
setBX(DriverState.ReleaseCount[Button]);
|
||||||
setCX(DriverState.LastRelease[Button].X);
|
setCX(LastRelease.X);
|
||||||
setDX(DriverState.LastRelease[Button].Y);
|
setDX(LastRelease.Y);
|
||||||
|
|
||||||
/* Reset the counter */
|
/* Reset the counter */
|
||||||
DriverState.ReleaseCount[Button] = 0;
|
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 */
|
/* Define Graphics Cursor */
|
||||||
case 0x09:
|
case 0x09:
|
||||||
{
|
{
|
||||||
|
@ -395,8 +582,7 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
||||||
/* Define Mickey/Pixel Ratio */
|
/* Define Mickey/Pixel Ratio */
|
||||||
case 0x0F:
|
case 0x0F:
|
||||||
{
|
{
|
||||||
DriverState.MickeysPerCellHoriz = getCX();
|
/* This call should be completely ignored */
|
||||||
DriverState.MickeysPerCellVert = getDX();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,14 +774,14 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
||||||
setES(0x0000);
|
setES(0x0000);
|
||||||
setBX(0x0000);
|
setBX(0x0000);
|
||||||
|
|
||||||
DriverEnabled = FALSE;
|
DosMouseDisable();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable Mouse Driver */
|
/* Enable Mouse Driver */
|
||||||
case 0x20:
|
case 0x20:
|
||||||
{
|
{
|
||||||
DriverEnabled = TRUE;
|
DosMouseEnable();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -608,6 +794,38 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
|
||||||
|
|
||||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
/* 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)
|
VOID DosMouseUpdatePosition(PCOORD NewPosition)
|
||||||
{
|
{
|
||||||
SHORT DeltaX = NewPosition->X - DriverState.Position.X;
|
SHORT DeltaX = NewPosition->X - DriverState.Position.X;
|
||||||
|
@ -615,8 +833,8 @@ VOID DosMouseUpdatePosition(PCOORD NewPosition)
|
||||||
|
|
||||||
if (!DriverEnabled) return;
|
if (!DriverEnabled) return;
|
||||||
|
|
||||||
DriverState.HorizCount += (DeltaX * (SHORT)DriverState.MickeysPerCellHoriz) / 8;
|
DriverState.HorizCount += (DeltaX * MICKEYS_PER_CELL_HORIZ) / 8;
|
||||||
DriverState.VertCount += (DeltaY * (SHORT)DriverState.MickeysPerCellVert ) / 8;
|
DriverState.VertCount += (DeltaY * MICKEYS_PER_CELL_VERT) / 8;
|
||||||
|
|
||||||
if (DriverState.ShowCount > 0) EraseMouseCursor();
|
if (DriverState.ShowCount > 0) EraseMouseCursor();
|
||||||
DriverState.Position = *NewPosition;
|
DriverState.Position = *NewPosition;
|
||||||
|
@ -671,10 +889,12 @@ BOOLEAN DosMouseInitialize(VOID)
|
||||||
/* Initialize the interrupt handler */
|
/* Initialize the interrupt handler */
|
||||||
RegisterDosInt32(DOS_MOUSE_INTERRUPT, DosMouseService);
|
RegisterDosInt32(DOS_MOUSE_INTERRUPT, DosMouseService);
|
||||||
|
|
||||||
|
DosMouseEnable();
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID DosMouseCleanup(VOID)
|
VOID DosMouseCleanup(VOID)
|
||||||
{
|
{
|
||||||
if (DriverState.ShowCount > 0) EraseMouseCursor();
|
if (DriverState.ShowCount > 0) EraseMouseCursor();
|
||||||
|
DosMouseDisable();
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
/* DEFINES ********************************************************************/
|
/* DEFINES ********************************************************************/
|
||||||
|
|
||||||
#define DOS_MOUSE_INTERRUPT 0x33
|
#define DOS_MOUSE_INTERRUPT 0x33
|
||||||
|
#define MOUSE_IRQ_INT 0x74
|
||||||
|
#define MOUSE_MAX_HORIZ 640
|
||||||
|
#define MOUSE_MAX_VERT 200
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -47,8 +50,7 @@ typedef struct _MOUSE_DRIVER_STATE
|
||||||
COORD LastRelease[NUM_MOUSE_BUTTONS];
|
COORD LastRelease[NUM_MOUSE_BUTTONS];
|
||||||
SHORT HorizCount;
|
SHORT HorizCount;
|
||||||
SHORT VertCount;
|
SHORT VertCount;
|
||||||
WORD MickeysPerCellHoriz;
|
WORD MinX, MaxX, MinY, MaxY;
|
||||||
WORD MickeysPerCellVert;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* User Subroutine Handlers called on mouse events
|
* User Subroutine Handlers called on mouse events
|
||||||
|
@ -72,9 +74,8 @@ typedef struct _MOUSE_DRIVER_STATE
|
||||||
|
|
||||||
/* FUNCTIONS ******************************************************************/
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
||||||
VOID DosMouseUpdatePosition(PCOORD NewPosition);
|
VOID DosMouseEnable(VOID);
|
||||||
VOID DosMouseUpdateButtons(WORD ButtonStatus);
|
VOID DosMouseDisable(VOID);
|
||||||
|
|
||||||
BOOLEAN DosMouseInitialize(VOID);
|
BOOLEAN DosMouseInitialize(VOID);
|
||||||
VOID DosMouseCleanup(VOID);
|
VOID DosMouseCleanup(VOID);
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "pic.h"
|
#include "pic.h"
|
||||||
|
#include "clock.h"
|
||||||
|
|
||||||
/* PRIVATE VARIABLES **********************************************************/
|
/* PRIVATE VARIABLES **********************************************************/
|
||||||
|
|
||||||
|
@ -24,14 +25,82 @@ static CMOS_MEMORY CmosMemory;
|
||||||
static BOOLEAN NmiEnabled = TRUE;
|
static BOOLEAN NmiEnabled = TRUE;
|
||||||
static CMOS_REGISTERS SelectedRegister = CMOS_REG_STATUS_D;
|
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 */
|
/* Update the NMI enabled flag */
|
||||||
NmiEnabled = !(Value & CMOS_DISABLE_NMI);
|
NmiEnabled = !(Value & CMOS_DISABLE_NMI);
|
||||||
|
@ -51,7 +120,7 @@ VOID CmosWriteAddress(BYTE Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BYTE CmosReadData(VOID)
|
static BYTE CmosReadData(VOID)
|
||||||
{
|
{
|
||||||
BYTE Value;
|
BYTE Value;
|
||||||
SYSTEMTIME CurrentTime;
|
SYSTEMTIME CurrentTime;
|
||||||
|
@ -181,7 +250,7 @@ BYTE CmosReadData(VOID)
|
||||||
return Value;
|
return Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID CmosWriteData(BYTE Value)
|
static VOID CmosWriteData(BYTE Value)
|
||||||
{
|
{
|
||||||
BOOLEAN ChangeTime = FALSE;
|
BOOLEAN ChangeTime = FALSE;
|
||||||
SYSTEMTIME CurrentTime;
|
SYSTEMTIME CurrentTime;
|
||||||
|
@ -296,6 +365,7 @@ VOID CmosWriteData(BYTE Value)
|
||||||
case CMOS_REG_STATUS_A:
|
case CMOS_REG_STATUS_A:
|
||||||
{
|
{
|
||||||
CmosMemory.StatusRegA = Value & 0x7F; // Bit 7 is read-only
|
CmosMemory.StatusRegA = Value & 0x7F; // Bit 7 is read-only
|
||||||
|
RtcUpdatePeriodicTimer();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,13 +412,13 @@ VOID CmosWriteData(BYTE Value)
|
||||||
SelectedRegister = CMOS_REG_STATUS_D;
|
SelectedRegister = CMOS_REG_STATUS_D;
|
||||||
}
|
}
|
||||||
|
|
||||||
BYTE WINAPI CmosReadPort(USHORT Port)
|
static BYTE WINAPI CmosReadPort(USHORT Port)
|
||||||
{
|
{
|
||||||
ASSERT(Port == CMOS_DATA_PORT);
|
ASSERT(Port == CMOS_DATA_PORT);
|
||||||
return CmosReadData();
|
return CmosReadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID WINAPI CmosWritePort(USHORT Port, BYTE Data)
|
static VOID WINAPI CmosWritePort(USHORT Port, BYTE Data)
|
||||||
{
|
{
|
||||||
if (Port == CMOS_ADDRESS_PORT)
|
if (Port == CMOS_ADDRESS_PORT)
|
||||||
CmosWriteAddress(Data);
|
CmosWriteAddress(Data);
|
||||||
|
@ -356,68 +426,12 @@ VOID WINAPI CmosWritePort(USHORT Port, BYTE Data)
|
||||||
CmosWriteData(Data);
|
CmosWriteData(Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD RtcGetTicksPerSecond(VOID)
|
|
||||||
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||||
|
|
||||||
|
BOOLEAN IsNmiEnabled(VOID)
|
||||||
{
|
{
|
||||||
BYTE RateSelect = CmosMemory.StatusRegB & 0x0F;
|
return NmiEnabled;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID CmosInitialize(VOID)
|
VOID CmosInitialize(VOID)
|
||||||
|
@ -486,6 +500,11 @@ VOID CmosInitialize(VOID)
|
||||||
/* Register the I/O Ports */
|
/* Register the I/O Ports */
|
||||||
RegisterIoPort(CMOS_ADDRESS_PORT, NULL , CmosWritePort);
|
RegisterIoPort(CMOS_ADDRESS_PORT, NULL , CmosWritePort);
|
||||||
RegisterIoPort(CMOS_DATA_PORT , CmosReadPort, 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)
|
VOID CmosCleanup(VOID)
|
||||||
|
@ -494,6 +513,9 @@ VOID CmosCleanup(VOID)
|
||||||
|
|
||||||
if (hCmosRam == INVALID_HANDLE_VALUE) return;
|
if (hCmosRam == INVALID_HANDLE_VALUE) return;
|
||||||
|
|
||||||
|
DestroyHardwareTimer(PeriodicTimer);
|
||||||
|
DestroyHardwareTimer(ClockTimer);
|
||||||
|
|
||||||
/* Flush the CMOS memory back to the RAM file and close it */
|
/* Flush the CMOS memory back to the RAM file and close it */
|
||||||
SetFilePointer(hCmosRam, 0, NULL, FILE_BEGIN);
|
SetFilePointer(hCmosRam, 0, NULL, FILE_BEGIN);
|
||||||
WriteFile(hCmosRam, &CmosMemory, CmosSize, &CmosSize, NULL);
|
WriteFile(hCmosRam, &CmosMemory, CmosSize, &CmosSize, NULL);
|
||||||
|
|
|
@ -128,8 +128,6 @@ C_ASSERT(sizeof(CMOS_MEMORY) == 0x40);
|
||||||
|
|
||||||
BOOLEAN IsNmiEnabled(VOID);
|
BOOLEAN IsNmiEnabled(VOID);
|
||||||
DWORD RtcGetTicksPerSecond(VOID);
|
DWORD RtcGetTicksPerSecond(VOID);
|
||||||
VOID RtcPeriodicTick(VOID);
|
|
||||||
VOID RtcTimeUpdate(VOID);
|
|
||||||
|
|
||||||
VOID CmosInitialize(VOID);
|
VOID CmosInitialize(VOID);
|
||||||
VOID CmosCleanup(VOID);
|
VOID CmosCleanup(VOID);
|
||||||
|
|
|
@ -12,31 +12,43 @@
|
||||||
|
|
||||||
#include "mouse.h"
|
#include "mouse.h"
|
||||||
#include "ps2.h"
|
#include "ps2.h"
|
||||||
// #include "pic.h"
|
#include "clock.h"
|
||||||
|
#include "video/vga.h"
|
||||||
|
|
||||||
/* PRIVATE VARIABLES **********************************************************/
|
/* 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 MOUSE_MODE Mode, PreviousMode;
|
||||||
static COORD Position;
|
static COORD Position;
|
||||||
static ULONG WidthMm, HeightMm, WidthPixels, HeightPixels;
|
static BYTE Resolution; /* Completely ignored */
|
||||||
static ULONG SampleRate;
|
static BOOLEAN Scaling; /* Completely ignored */
|
||||||
static ULONG Resolution;
|
|
||||||
static BOOLEAN Scaling;
|
|
||||||
static BOOLEAN Reporting;
|
static BOOLEAN Reporting;
|
||||||
static BYTE MouseId;
|
static BYTE MouseId;
|
||||||
static ULONG ButtonState;
|
static ULONG ButtonState;
|
||||||
static SHORT HorzCounter;
|
static SHORT HorzCounter;
|
||||||
static SHORT VertCounter;
|
static SHORT VertCounter;
|
||||||
static CHAR ScrollCounter;
|
static CHAR ScrollCounter;
|
||||||
|
static BOOLEAN EventsOccurred = FALSE;
|
||||||
|
static BYTE DataByteWait = 0;
|
||||||
|
static BYTE ScrollMagicCounter = 0, ExtraButtonMagicCounter = 0;
|
||||||
|
|
||||||
static BYTE PS2Port = 1;
|
static BYTE PS2Port = 1;
|
||||||
|
|
||||||
|
/* PUBLIC VARIABLES ***********************************************************/
|
||||||
|
|
||||||
|
UINT MouseCycles = 10;
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS **********************************************************/
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
static VOID MouseResetConfig(VOID)
|
static VOID MouseResetConfig(VOID)
|
||||||
{
|
{
|
||||||
/* Reset the configuration to defaults */
|
/* Reset the configuration to defaults */
|
||||||
SampleRate = 100;
|
MouseCycles = 10;
|
||||||
Resolution = 4;
|
Resolution = 4;
|
||||||
Scaling = FALSE;
|
Scaling = FALSE;
|
||||||
Reporting = FALSE;
|
Reporting = FALSE;
|
||||||
|
@ -45,7 +57,7 @@ static VOID MouseResetConfig(VOID)
|
||||||
static VOID MouseResetCounters(VOID)
|
static VOID MouseResetCounters(VOID)
|
||||||
{
|
{
|
||||||
/* Reset all flags and counters */
|
/* Reset all flags and counters */
|
||||||
ButtonState = HorzCounter = VertCounter = ScrollCounter = 0;
|
HorzCounter = VertCounter = ScrollCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VOID MouseReset(VOID)
|
static VOID MouseReset(VOID)
|
||||||
|
@ -57,42 +69,50 @@ static VOID MouseReset(VOID)
|
||||||
/* Enter streaming mode and the reset the mouse ID */
|
/* Enter streaming mode and the reset the mouse ID */
|
||||||
Mode = MOUSE_STREAMING_MODE;
|
Mode = MOUSE_STREAMING_MODE;
|
||||||
MouseId = 0;
|
MouseId = 0;
|
||||||
|
ScrollMagicCounter = ExtraButtonMagicCounter = 0;
|
||||||
|
|
||||||
/* Send the Basic Assurance Test success code and the device ID */
|
/* Send the Basic Assurance Test success code and the device ID */
|
||||||
PS2QueuePush(PS2Port, MOUSE_BAT_SUCCESS);
|
PS2QueuePush(PS2Port, MOUSE_BAT_SUCCESS);
|
||||||
PS2QueuePush(PS2Port, MouseId);
|
PS2QueuePush(PS2Port, MouseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
static VOID MouseGetPacket(PMOUSE_PACKET Packet)
|
static VOID MouseGetPacket(PMOUSE_PACKET Packet)
|
||||||
{
|
{
|
||||||
/* Clear the packet */
|
/* Clear the packet */
|
||||||
RtlZeroMemory(Packet, sizeof(*Packet));
|
RtlZeroMemory(Packet, sizeof(*Packet));
|
||||||
|
|
||||||
|
/* Acquire the mutex */
|
||||||
|
WaitForSingleObject(MouseMutex, INFINITE);
|
||||||
|
|
||||||
Packet->Flags |= MOUSE_ALWAYS_SET;
|
Packet->Flags |= MOUSE_ALWAYS_SET;
|
||||||
|
|
||||||
/* Check for horizontal overflows */
|
/* Set the sign flags */
|
||||||
if ((HorzCounter < MOUSE_MIN) || (HorzCounter > MOUSE_MAX))
|
if (HorzCounter < 0)
|
||||||
{
|
{
|
||||||
if (HorzCounter > MOUSE_MAX) HorzCounter = MOUSE_MAX;
|
Packet->Flags |= MOUSE_X_SIGN;
|
||||||
if (HorzCounter < MOUSE_MIN) HorzCounter = MOUSE_MIN;
|
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;
|
Packet->Flags |= MOUSE_X_OVERFLOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for vertical overflows */
|
/* Check for vertical overflows */
|
||||||
if ((VertCounter < MOUSE_MIN) || (VertCounter > MOUSE_MAX))
|
if (VertCounter > MOUSE_MAX)
|
||||||
{
|
{
|
||||||
if (VertCounter > MOUSE_MIN) VertCounter = MOUSE_MIN;
|
VertCounter = MOUSE_MAX;
|
||||||
if (VertCounter < MOUSE_MIN) VertCounter = MOUSE_MIN;
|
|
||||||
|
|
||||||
Packet->Flags |= MOUSE_Y_OVERFLOW;
|
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 */
|
/* Set the button flags */
|
||||||
if (ButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) Packet->Flags |= MOUSE_LEFT_BUTTON;
|
if (ButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) Packet->Flags |= MOUSE_LEFT_BUTTON;
|
||||||
if (ButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) Packet->Flags |= MOUSE_MIDDLE_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 */
|
/* Reset the counters */
|
||||||
MouseResetCounters();
|
MouseResetCounters();
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*static*/ VOID MouseUpdatePosition(PCOORD NewPosition)
|
/* Release the mutex */
|
||||||
{
|
ReleaseMutex(MouseMutex);
|
||||||
/* Update the counters */
|
|
||||||
HorzCounter += ((NewPosition->X - Position.X) * WidthMm * Resolution) / WidthPixels;
|
|
||||||
VertCounter += ((NewPosition->Y - Position.Y) * HeightMm * Resolution) / HeightPixels;
|
|
||||||
|
|
||||||
/* Update the position */
|
|
||||||
Position = *NewPosition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ VOID MouseUpdateButtons(ULONG NewButtonState)
|
static VOID MouseDispatchPacket(PMOUSE_PACKET Packet)
|
||||||
{
|
{
|
||||||
ButtonState = NewButtonState;
|
PS2QueuePush(PS2Port, Packet->Flags);
|
||||||
}
|
PS2QueuePush(PS2Port, Packet->HorzCounter);
|
||||||
|
PS2QueuePush(PS2Port, Packet->VertCounter);
|
||||||
/*static*/ VOID MouseScroll(LONG Direction)
|
if (MouseId >= 3) PS2QueuePush(PS2Port, Packet->Extra);
|
||||||
{
|
|
||||||
ScrollCounter += Direction;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*static*/ COORD MouseGetPosition(VOID)
|
|
||||||
{
|
|
||||||
return Position;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command)
|
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)
|
switch (Command)
|
||||||
{
|
{
|
||||||
/* Set 1:1 Scaling */
|
/* Set 1:1 Scaling */
|
||||||
|
@ -166,17 +244,27 @@ static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command)
|
||||||
|
|
||||||
/* Set Resolution */
|
/* Set Resolution */
|
||||||
case 0xE8:
|
case 0xE8:
|
||||||
|
/* Set Sample Rate */
|
||||||
|
case 0xF3:
|
||||||
{
|
{
|
||||||
// TODO: NOT IMPLEMENTED
|
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||||
UNIMPLEMENTED;
|
DataByteWait = Command;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read Status */
|
/* Read Status */
|
||||||
case 0xE9:
|
case 0xE9:
|
||||||
{
|
{
|
||||||
// TODO: NOT IMPLEMENTED
|
BYTE Status = ButtonState & 7;
|
||||||
UNIMPLEMENTED;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,8 +281,9 @@ static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command)
|
||||||
/* Read Packet */
|
/* Read Packet */
|
||||||
case 0xEB:
|
case 0xEB:
|
||||||
{
|
{
|
||||||
// TODO: NOT IMPLEMENTED
|
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||||
UNIMPLEMENTED;
|
MouseGetPacket(&LastPacket);
|
||||||
|
MouseDispatchPacket(&LastPacket);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,14 +336,6 @@ static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set Sample Rate */
|
|
||||||
case 0xF3:
|
|
||||||
{
|
|
||||||
// TODO: NOT IMPLEMENTED
|
|
||||||
UNIMPLEMENTED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enable Reporting */
|
/* Enable Reporting */
|
||||||
case 0xF4:
|
case 0xF4:
|
||||||
{
|
{
|
||||||
|
@ -283,8 +364,8 @@ static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command)
|
||||||
/* Resend */
|
/* Resend */
|
||||||
case 0xFE:
|
case 0xFE:
|
||||||
{
|
{
|
||||||
// TODO: NOT IMPLEMENTED
|
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||||
UNIMPLEMENTED;
|
MouseDispatchPacket(&LastPacket);
|
||||||
break;
|
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 ***********************************************************/
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||||
|
|
||||||
|
VOID MouseGetDataFast(PCOORD CurrentPosition, PBYTE CurrentButtonState)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(MouseMutex, INFINITE);
|
||||||
|
*CurrentPosition = Position;
|
||||||
|
*CurrentButtonState = LOBYTE(ButtonState);
|
||||||
|
ReleaseMutex(MouseMutex);
|
||||||
|
}
|
||||||
|
|
||||||
VOID MouseEventHandler(PMOUSE_EVENT_RECORD MouseEvent)
|
VOID MouseEventHandler(PMOUSE_EVENT_RECORD MouseEvent)
|
||||||
{
|
{
|
||||||
extern COORD DosNewPosition;
|
COORD NewPosition = MouseEvent->dwMousePosition;
|
||||||
extern WORD DosButtonState;
|
BOOLEAN DoubleWidth = FALSE, DoubleHeight = FALSE;
|
||||||
|
|
||||||
// FIXME: Sync our private data
|
if (!VgaGetDoubleVisionState(&DoubleWidth, &DoubleHeight))
|
||||||
MouseUpdatePosition(&MouseEvent->dwMousePosition);
|
{
|
||||||
MouseUpdateButtons(MouseEvent->dwButtonState);
|
/* Text mode */
|
||||||
|
NewPosition.X *= 8;
|
||||||
|
NewPosition.Y *= 8;
|
||||||
|
}
|
||||||
|
|
||||||
// HACK: Bypass PS/2 and instead, notify the MOUSE.COM driver directly
|
/* Adjust for double vision */
|
||||||
DosNewPosition = MouseEvent->dwMousePosition;
|
if (DoubleWidth) NewPosition.X /= 2;
|
||||||
DosButtonState = LOWORD(MouseEvent->dwButtonState);
|
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)
|
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 */
|
/* Finish to plug the mouse to the specified PS/2 port */
|
||||||
PS2Port = PS2Connector;
|
PS2Port = PS2Connector;
|
||||||
PS2SetDeviceCmdProc(PS2Port, NULL, MouseCommand);
|
PS2SetDeviceCmdProc(PS2Port, NULL, MouseCommand);
|
||||||
|
|
||||||
|
MouseMutex = CreateMutex(NULL, FALSE, NULL);
|
||||||
|
if (MouseMutex == NULL) return FALSE;
|
||||||
|
|
||||||
|
StreamTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, 10, MouseStreamingCallback);
|
||||||
|
|
||||||
MouseReset();
|
MouseReset();
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,7 @@
|
||||||
/* DEFINES ********************************************************************/
|
/* DEFINES ********************************************************************/
|
||||||
|
|
||||||
/* Mouse packet constants */
|
/* Mouse packet constants */
|
||||||
#define MOUSE_MIN -256
|
|
||||||
#define MOUSE_MAX 255
|
#define MOUSE_MAX 255
|
||||||
#define MOUSE_SIGN_BIT (1 << 8)
|
|
||||||
|
|
||||||
/* Mouse packet flags */
|
/* Mouse packet flags */
|
||||||
#define MOUSE_LEFT_BUTTON (1 << 0)
|
#define MOUSE_LEFT_BUTTON (1 << 0)
|
||||||
|
@ -69,6 +67,7 @@ typedef struct _MOUSE_PACKET
|
||||||
/* FUNCTIONS ******************************************************************/
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
||||||
VOID MouseEventHandler(PMOUSE_EVENT_RECORD MouseEvent);
|
VOID MouseEventHandler(PMOUSE_EVENT_RECORD MouseEvent);
|
||||||
|
VOID MouseGetDataFast(PCOORD CurrentPosition, PBYTE CurrentButtonState);
|
||||||
BOOLEAN MouseInit(BYTE PS2Connector);
|
BOOLEAN MouseInit(BYTE PS2Connector);
|
||||||
|
|
||||||
#endif // _MOUSE_H_
|
#endif // _MOUSE_H_
|
||||||
|
|
|
@ -16,10 +16,12 @@
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "pit.h"
|
#include "pit.h"
|
||||||
#include "pic.h"
|
#include "pic.h"
|
||||||
|
#include "clock.h"
|
||||||
|
|
||||||
/* PRIVATE VARIABLES **********************************************************/
|
/* PRIVATE VARIABLES **********************************************************/
|
||||||
|
|
||||||
static PIT_CHANNEL PitChannels[PIT_CHANNELS];
|
static PIT_CHANNEL PitChannels[PIT_CHANNELS];
|
||||||
|
static PHARDWARE_TIMER MasterClock;
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS **********************************************************/
|
/* 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 ***********************************************************/
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||||
|
|
||||||
VOID PitSetOutFunction(BYTE Channel, LPVOID Param, PIT_OUT_FUNCTION OutFunction)
|
VOID PitSetOutFunction(BYTE Channel, LPVOID Param, PIT_OUT_FUNCTION OutFunction)
|
||||||
|
@ -480,38 +493,6 @@ WORD PitGetReloadValue(BYTE Channel)
|
||||||
return PitChannels[Channel].ReloadValue;
|
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)
|
VOID PitInitialize(VOID)
|
||||||
{
|
{
|
||||||
/* Set up the timers to their default value */
|
/* 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(0), PitReadPort, PitWritePort);
|
||||||
RegisterIoPort(PIT_DATA_PORT(1), PitReadPort, PitWritePort);
|
RegisterIoPort(PIT_DATA_PORT(1), PitReadPort, PitWritePort);
|
||||||
RegisterIoPort(PIT_DATA_PORT(2), 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 */
|
/* EOF */
|
||||||
|
|
|
@ -79,9 +79,6 @@ VOID PitSetOutFunction(BYTE Channel, LPVOID Param, PIT_OUT_FUNCTION OutFunction)
|
||||||
VOID PitSetGate(BYTE Channel, BOOLEAN State);
|
VOID PitSetGate(BYTE Channel, BOOLEAN State);
|
||||||
WORD PitGetReloadValue(BYTE Channel);
|
WORD PitGetReloadValue(BYTE Channel);
|
||||||
|
|
||||||
DWORD PitGetResolution(VOID);
|
|
||||||
VOID PitClock(DWORD Count);
|
|
||||||
|
|
||||||
VOID PitInitialize(VOID);
|
VOID PitInitialize(VOID);
|
||||||
|
|
||||||
#endif // _PIT_H_
|
#endif // _PIT_H_
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "ps2.h"
|
#include "ps2.h"
|
||||||
#include "pic.h"
|
#include "pic.h"
|
||||||
|
#include "clock.h"
|
||||||
|
|
||||||
/* PRIVATE VARIABLES **********************************************************/
|
/* PRIVATE VARIABLES **********************************************************/
|
||||||
|
|
||||||
|
@ -49,6 +50,8 @@ static BYTE StatusRegister = 0x00;
|
||||||
// static BYTE InputBuffer = 0x00; // PS/2 Input Buffer
|
// static BYTE InputBuffer = 0x00; // PS/2 Input Buffer
|
||||||
static BYTE OutputBuffer = 0x00; // PS/2 Output Buffer
|
static BYTE OutputBuffer = 0x00; // PS/2 Output Buffer
|
||||||
|
|
||||||
|
static PHARDWARE_TIMER IrqTimer = NULL;
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS **********************************************************/
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
static VOID PS2SendCommand(PPS2_PORT Port, BYTE Command)
|
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;
|
BOOLEAN Result = TRUE;
|
||||||
PPS2_PORT Port;
|
PPS2_PORT Port;
|
||||||
|
@ -316,8 +342,6 @@ Done:
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
|
||||||
|
|
||||||
VOID PS2SetDeviceCmdProc(BYTE PS2Port, LPVOID Param, PS2_DEVICE_CMDPROC DeviceCommand)
|
VOID PS2SetDeviceCmdProc(BYTE PS2Port, LPVOID Param, PS2_DEVICE_CMDPROC DeviceCommand)
|
||||||
{
|
{
|
||||||
if (PS2Port >= PS2_PORTS) return;
|
if (PS2Port >= PS2_PORTS) return;
|
||||||
|
@ -354,43 +378,14 @@ BOOLEAN PS2QueuePush(BYTE PS2Port, BYTE Data)
|
||||||
/* The queue is not empty anymore */
|
/* The queue is not empty anymore */
|
||||||
Port->QueueEmpty = FALSE;
|
Port->QueueEmpty = FALSE;
|
||||||
|
|
||||||
/*
|
/* Schedule the IRQ */
|
||||||
// Get the data
|
EnableHardwareTimer(IrqTimer);
|
||||||
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);
|
|
||||||
*/
|
|
||||||
|
|
||||||
Done:
|
Done:
|
||||||
ReleaseMutex(Port->QueueMutex);
|
ReleaseMutex(Port->QueueMutex);
|
||||||
return Result;
|
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)
|
BOOLEAN PS2Initialize(VOID)
|
||||||
{
|
{
|
||||||
/* Initialize the PS/2 ports */
|
/* Initialize the PS/2 ports */
|
||||||
|
@ -410,11 +405,15 @@ BOOLEAN PS2Initialize(VOID)
|
||||||
RegisterIoPort(PS2_CONTROL_PORT, PS2ReadPort, PS2WritePort);
|
RegisterIoPort(PS2_CONTROL_PORT, PS2ReadPort, PS2WritePort);
|
||||||
RegisterIoPort(PS2_DATA_PORT , PS2ReadPort, PS2WritePort);
|
RegisterIoPort(PS2_DATA_PORT , PS2ReadPort, PS2WritePort);
|
||||||
|
|
||||||
|
IrqTimer = CreateHardwareTimer(HARDWARE_TIMER_ONESHOT, 20, GeneratePS2Irq);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID PS2Cleanup(VOID)
|
VOID PS2Cleanup(VOID)
|
||||||
{
|
{
|
||||||
|
DestroyHardwareTimer(IrqTimer);
|
||||||
|
|
||||||
CloseHandle(Ports[1].QueueMutex);
|
CloseHandle(Ports[1].QueueMutex);
|
||||||
CloseHandle(Ports[0].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);
|
VOID PS2SetDeviceCmdProc(BYTE PS2Port, LPVOID Param, PS2_DEVICE_CMDPROC DeviceCommand);
|
||||||
|
|
||||||
BOOLEAN PS2QueuePush(BYTE PS2Port, BYTE Data);
|
BOOLEAN PS2QueuePush(BYTE PS2Port, BYTE Data);
|
||||||
|
BOOLEAN PS2PortQueueRead(BYTE PS2Port);
|
||||||
VOID GenerateIrq1(VOID);
|
|
||||||
VOID GenerateIrq12(VOID);
|
|
||||||
|
|
||||||
BOOLEAN PS2Initialize(VOID);
|
BOOLEAN PS2Initialize(VOID);
|
||||||
VOID PS2Cleanup(VOID);
|
VOID PS2Cleanup(VOID);
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
#include "clock.h"
|
||||||
|
|
||||||
/* PRIVATE VARIABLES **********************************************************/
|
/* PRIVATE VARIABLES **********************************************************/
|
||||||
|
|
||||||
|
@ -245,6 +246,9 @@ static HANDLE ConsoleMutex = NULL;
|
||||||
static BOOLEAN DoubleWidth = FALSE;
|
static BOOLEAN DoubleWidth = FALSE;
|
||||||
static BOOLEAN DoubleHeight = FALSE;
|
static BOOLEAN DoubleHeight = FALSE;
|
||||||
|
|
||||||
|
static PHARDWARE_TIMER VSyncTimer;
|
||||||
|
static PHARDWARE_TIMER HSyncTimer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VGA Hardware
|
* VGA Hardware
|
||||||
*/
|
*/
|
||||||
|
@ -1754,60 +1758,12 @@ static VOID WINAPI VgaWritePort(USHORT Port, BYTE Data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
static VOID FASTCALL VgaVerticalRetrace(ULONGLONG ElapsedTime)
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
HANDLE ConsoleBufferHandle = NULL;
|
HANDLE ConsoleBufferHandle = NULL;
|
||||||
|
|
||||||
|
UNREFERENCED_PARAMETER(ElapsedTime);
|
||||||
|
|
||||||
/* Set the vertical retrace flag */
|
/* Set the vertical retrace flag */
|
||||||
InVerticalRetrace = TRUE;
|
InVerticalRetrace = TRUE;
|
||||||
|
|
||||||
|
@ -1876,12 +1832,77 @@ VOID VgaRefreshDisplay(VOID)
|
||||||
NeedsUpdate = FALSE;
|
NeedsUpdate = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID VgaHorizontalRetrace(VOID)
|
static VOID FASTCALL VgaHorizontalRetrace(ULONGLONG ElapsedTime)
|
||||||
{
|
{
|
||||||
|
UNREFERENCED_PARAMETER(ElapsedTime);
|
||||||
|
|
||||||
/* Set the flag */
|
/* Set the flag */
|
||||||
InHorizontalRetrace = TRUE;
|
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)
|
VOID NTAPI VgaReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
|
||||||
{
|
{
|
||||||
DWORD i;
|
DWORD i;
|
||||||
|
@ -2106,12 +2127,18 @@ BOOLEAN VgaInitialize(HANDLE TextHandle)
|
||||||
RegisterIoPort(0x3D8, VgaReadPort, VgaWritePort); // CGA_MODE_CTRL_REG
|
RegisterIoPort(0x3D8, VgaReadPort, VgaWritePort); // CGA_MODE_CTRL_REG
|
||||||
RegisterIoPort(0x3D9, VgaReadPort, VgaWritePort); // CGA_PAL_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 success */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID VgaCleanup(VOID)
|
VOID VgaCleanup(VOID)
|
||||||
{
|
{
|
||||||
|
DestroyHardwareTimer(VSyncTimer);
|
||||||
|
DestroyHardwareTimer(HSyncTimer);
|
||||||
|
|
||||||
if (ScreenMode == GRAPHICS_MODE)
|
if (ScreenMode == GRAPHICS_MODE)
|
||||||
{
|
{
|
||||||
/* Leave the current graphics mode */
|
/* Leave the current graphics mode */
|
||||||
|
|
|
@ -260,9 +260,9 @@ VOID VgaDetachFromConsole(BOOL ChangeMode);
|
||||||
|
|
||||||
COORD VgaGetDisplayResolution(VOID);
|
COORD VgaGetDisplayResolution(VOID);
|
||||||
VOID VgaRefreshDisplay(VOID);
|
VOID VgaRefreshDisplay(VOID);
|
||||||
VOID VgaHorizontalRetrace(VOID);
|
|
||||||
VOID VgaWriteFont(UINT FontNumber, CONST UCHAR *FontData, UINT Height);
|
VOID VgaWriteFont(UINT FontNumber, CONST UCHAR *FontData, UINT Height);
|
||||||
VOID VgaClearMemory(VOID);
|
VOID VgaClearMemory(VOID);
|
||||||
|
BOOLEAN VgaGetDoubleVisionState(PBOOLEAN Vertical, PBOOLEAN Horizontal);
|
||||||
|
|
||||||
BOOLEAN VgaInitialize(HANDLE TextHandle);
|
BOOLEAN VgaInitialize(HANDLE TextHandle);
|
||||||
VOID VgaCleanup(VOID);
|
VOID VgaCleanup(VOID);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue