mirror of
https://github.com/reactos/reactos.git
synced 2025-01-03 21:09:19 +00:00
1314 lines
40 KiB
C
1314 lines
40 KiB
C
/*
|
|
* COPYRIGHT: GPL - See COPYING in the top level directory
|
|
* PROJECT: ReactOS Virtual DOS Machine
|
|
* FILE: subsystems/mvdm/ntvdm/dos/mouse32.c
|
|
* PURPOSE: VDM 32-bit compatible PS/2 MOUSE.COM driver
|
|
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "ntvdm.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* Driver Version number and Copyright */
|
|
#include <reactos/buildno.h>
|
|
#include <reactos/version.h>
|
|
|
|
#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/svga.h"
|
|
/**/
|
|
#include "../console/video.h"
|
|
/**/
|
|
|
|
#include "mouse32.h"
|
|
#include "bios/bios.h"
|
|
#include "bios/bios32/bios32p.h"
|
|
|
|
#include "memory.h"
|
|
#include "io.h"
|
|
#include "dos32krnl/memory.h"
|
|
|
|
/* PRIVATE VARIABLES **********************************************************/
|
|
|
|
static const CHAR MouseCopyright[] =
|
|
"ReactOS PS/2 16/32-bit Mouse Driver Compatible MS-MOUSE 6.26\r\n"
|
|
"Version "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\r\n"
|
|
"Copyright (C) ReactOS Team 1996-"COPYRIGHT_YEAR"\0";
|
|
|
|
#pragma pack(push, 1)
|
|
|
|
typedef struct _MOUSE_DRIVER
|
|
{
|
|
CHAR Copyright[sizeof(MouseCopyright)];
|
|
WORD Version;
|
|
BYTE MouseContextScratch[TRAMPOLINE_SIZE];
|
|
BYTE MouseDosInt16Stub[Int16To32StubSize];
|
|
BYTE MouseIrqInt16Stub[Int16To32StubSize];
|
|
} MOUSE_DRIVER, *PMOUSE_DRIVER;
|
|
|
|
#pragma pack(pop)
|
|
|
|
/* Global data contained in guest memory */
|
|
static WORD MouseDataSegment;
|
|
static PMOUSE_DRIVER MouseData;
|
|
static CALLBACK16 MouseContext;
|
|
|
|
#define MICKEYS_PER_CELL_HORIZ 8
|
|
#define MICKEYS_PER_CELL_VERT 16
|
|
|
|
static BOOLEAN DriverEnabled = FALSE;
|
|
static MOUSE_DRIVER_STATE DriverState;
|
|
static DWORD OldIrqHandler;
|
|
static DWORD OldIntHandler;
|
|
|
|
static WORD DefaultGfxScreenMask[16] =
|
|
{
|
|
0xE7FF, // 1110011111111111
|
|
0xE3FF, // 1110001111111111
|
|
0xE1FF, // 1110000111111111
|
|
0xE0FF, // 1110000011111111
|
|
0xE07F, // 1110000001111111
|
|
0xE03F, // 1110000000111111
|
|
0xE01F, // 1110000000011111
|
|
0xE00F, // 1110000000001111
|
|
0xE007, // 1110000000000111
|
|
0xE007, // 1110000000000111
|
|
0xE03F, // 1110000000111111
|
|
0xE21F, // 1110001000011111
|
|
0xE61F, // 1110011000011111
|
|
0xFF0F, // 1111111100001111
|
|
0xFF0F, // 1111111100001111
|
|
0xFF8F, // 1111111110001111
|
|
};
|
|
|
|
static WORD DefaultGfxCursorMask[16] =
|
|
{
|
|
0x0000, // 0000000000000000
|
|
0x0800, // 0000100000000000
|
|
0x0C00, // 0000110000000000
|
|
0x0E00, // 0000111000000000
|
|
0x0F00, // 0000111100000000
|
|
0x0F80, // 0000111110000000
|
|
0x0FC0, // 0000111111000000
|
|
0x0FE0, // 0000111111100000
|
|
0x0FF0, // 0000111111110000
|
|
0x0F80, // 0000111110000000
|
|
0x0D80, // 0000110110000000
|
|
0x08C0, // 0000100011000000
|
|
0x00C0, // 0000000011000000
|
|
0x0060, // 0000000001100000
|
|
0x0060, // 0000000001100000
|
|
0x0000, // 0000000000000000
|
|
};
|
|
|
|
/* PRIVATE FUNCTIONS **********************************************************/
|
|
|
|
/* static */
|
|
VOID BiosPs2Service(UCHAR Function)
|
|
{
|
|
/* Save AX and BX */
|
|
USHORT AX = getAX();
|
|
// USHORT BX = getBX();
|
|
|
|
/*
|
|
* Set the parameters:
|
|
* AL contains the character to print (already set),
|
|
* BL contains the character attribute,
|
|
* BH contains the video page to use.
|
|
*/
|
|
// setBL(DOS_CHAR_ATTRIBUTE);
|
|
// setBH(Bda->VideoPage);
|
|
setAL(Function);
|
|
|
|
/* Call the BIOS INT 15h, AH=C2h "Pointing Device BIOS Interface (PS)" */
|
|
setAH(0xC2);
|
|
Int32Call(&MouseContext, BIOS_MISC_INTERRUPT);
|
|
|
|
/* Restore AX and BX */
|
|
// setBX(BX);
|
|
setAX(AX);
|
|
}
|
|
|
|
|
|
|
|
static VOID DosMouseEnable(VOID);
|
|
static VOID DosMouseDisable(VOID);
|
|
|
|
|
|
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
|
|
+ (CellY * Bda->ScreenColumns + CellX) * sizeof(WORD),
|
|
(LPVOID)&Character,
|
|
sizeof(WORD));
|
|
|
|
DriverState.Character = Character;
|
|
Character &= DriverState.TextCursor.ScreenMask;
|
|
Character ^= DriverState.TextCursor.CursorMask;
|
|
|
|
EmulatorWriteMemory(&EmulatorContext,
|
|
VideoAddress
|
|
+ (CellY * Bda->ScreenColumns + CellX) * sizeof(WORD),
|
|
(LPVOID)&Character,
|
|
sizeof(WORD));
|
|
}
|
|
else if (Bda->VideoMode == 0x12)
|
|
{
|
|
INT i, j;
|
|
BYTE OldMask;
|
|
BYTE OldMap;
|
|
|
|
/* Save the write mask */
|
|
IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_MASK_REG);
|
|
OldMask = IOReadB(VGA_SEQ_DATA);
|
|
|
|
/* And the selected reading plane */
|
|
IOWriteB(VGA_GC_INDEX, VGA_GC_READ_MAP_SEL_REG);
|
|
OldMap = IOReadB(VGA_GC_DATA);
|
|
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
WORD CursorLine[4];
|
|
DWORD VideoAddress = TO_LINEAR(GRAPHICS_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize)
|
|
+ ((DriverState.Position.Y + i) * 640 + DriverState.Position.X) / 8;
|
|
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
/* Select the reading plane */
|
|
IOWriteB(VGA_GC_INDEX, VGA_GC_READ_MAP_SEL_REG);
|
|
IOWriteB(VGA_GC_DATA, j);
|
|
|
|
/* Read a part of the scanline */
|
|
EmulatorReadMemory(&EmulatorContext, VideoAddress, &CursorLine[j], sizeof(CursorLine[j]));
|
|
}
|
|
|
|
/* Save the data below the cursor */
|
|
for (j = 0; j < 16; j++)
|
|
{
|
|
DriverState.GraphicsData[i * 16 + j] = 0;
|
|
|
|
if (CursorLine[0] & (1 << j)) DriverState.GraphicsData[i * 16 + j] |= 1 << 0;
|
|
if (CursorLine[1] & (1 << j)) DriverState.GraphicsData[i * 16 + j] |= 1 << 1;
|
|
if (CursorLine[2] & (1 << j)) DriverState.GraphicsData[i * 16 + j] |= 1 << 2;
|
|
if (CursorLine[3] & (1 << j)) DriverState.GraphicsData[i * 16 + j] |= 1 << 3;
|
|
}
|
|
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
/* Apply the screen mask */
|
|
CursorLine[j] &= MAKEWORD(HIBYTE(DriverState.GraphicsCursor.ScreenMask[i]),
|
|
LOBYTE(DriverState.GraphicsCursor.ScreenMask[i]));
|
|
|
|
/* And the cursor mask */
|
|
CursorLine[j] ^= MAKEWORD(HIBYTE(DriverState.GraphicsCursor.CursorMask[i]),
|
|
LOBYTE(DriverState.GraphicsCursor.CursorMask[i]));
|
|
|
|
/* Select the writing plane */
|
|
IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_MASK_REG);
|
|
IOWriteB(VGA_SEQ_DATA, 1 << j);
|
|
|
|
/* Write the cursor data for this scanline */
|
|
EmulatorWriteMemory(&EmulatorContext, VideoAddress, &CursorLine[j], sizeof(CursorLine[j]));
|
|
}
|
|
}
|
|
|
|
/* Restore the old mask */
|
|
IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_MASK_REG);
|
|
IOWriteB(VGA_SEQ_DATA, OldMask);
|
|
|
|
/* And the old reading plane */
|
|
IOWriteB(VGA_GC_INDEX, VGA_GC_READ_MAP_SEL_REG);
|
|
IOWriteB(VGA_GC_DATA, OldMap);
|
|
}
|
|
else if (Bda->VideoMode == 0x13)
|
|
{
|
|
INT i, j;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
BYTE CursorLine[16];
|
|
DWORD VideoAddress = TO_LINEAR(GRAPHICS_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize)
|
|
+ (DriverState.Position.Y + i) * 320 + DriverState.Position.X;
|
|
|
|
/* Read a part of the scanline */
|
|
EmulatorReadMemory(&EmulatorContext,
|
|
VideoAddress,
|
|
&DriverState.GraphicsData[i * 16],
|
|
sizeof(CursorLine));
|
|
|
|
for (j = 0; j < 16; j++)
|
|
{
|
|
/* Apply the screen mask by leaving only the masked pixels intact */
|
|
CursorLine[j] = (DriverState.GraphicsCursor.ScreenMask[i] & (1 << j))
|
|
? DriverState.GraphicsData[i * 16]
|
|
: 0x00;
|
|
|
|
/* Apply the cursor mask... */
|
|
if (DriverState.GraphicsCursor.CursorMask[i] & (1 << j))
|
|
{
|
|
/* ... by inverting the color of each masked pixel */
|
|
CursorLine[j] ^= 0x0F;
|
|
}
|
|
}
|
|
|
|
/* Write the cursor data for this scanline */
|
|
EmulatorWriteMemory(&EmulatorContext, VideoAddress, &CursorLine, sizeof(CursorLine));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO: NOT IMPLEMENTED
|
|
UNIMPLEMENTED;
|
|
}
|
|
}
|
|
|
|
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
|
|
+ (CellY * Bda->ScreenColumns + CellX) * sizeof(WORD),
|
|
(LPVOID)&DriverState.Character,
|
|
sizeof(WORD));
|
|
}
|
|
else if (Bda->VideoMode == 0x12)
|
|
{
|
|
INT i, j;
|
|
BYTE OldMask;
|
|
|
|
/* Save the write mask */
|
|
IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_MASK_REG);
|
|
OldMask = IOReadB(VGA_SEQ_DATA);
|
|
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
WORD CursorLine[4] = {0};
|
|
DWORD VideoAddress = TO_LINEAR(GRAPHICS_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize)
|
|
+ ((DriverState.Position.Y + i) * 640 + DriverState.Position.X) / 8;
|
|
|
|
/* Restore the data that was below the cursor */
|
|
for (j = 0; j < 16; j++)
|
|
{
|
|
if (DriverState.GraphicsData[i * 16 + j] & (1 << 0)) CursorLine[0] |= 1 << j;
|
|
if (DriverState.GraphicsData[i * 16 + j] & (1 << 1)) CursorLine[1] |= 1 << j;
|
|
if (DriverState.GraphicsData[i * 16 + j] & (1 << 2)) CursorLine[2] |= 1 << j;
|
|
if (DriverState.GraphicsData[i * 16 + j] & (1 << 3)) CursorLine[3] |= 1 << j;
|
|
}
|
|
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
/* Select the writing plane */
|
|
IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_MASK_REG);
|
|
IOWriteB(VGA_SEQ_DATA, 1 << j);
|
|
|
|
/* Write the original data for this scanline */
|
|
EmulatorWriteMemory(&EmulatorContext, VideoAddress, &CursorLine[j], sizeof(CursorLine[j]));
|
|
}
|
|
}
|
|
|
|
/* Restore the old mask */
|
|
IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_MASK_REG);
|
|
IOWriteB(VGA_SEQ_DATA, OldMask);
|
|
}
|
|
else if (Bda->VideoMode == 0x13)
|
|
{
|
|
INT i;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
DWORD VideoAddress = TO_LINEAR(GRAPHICS_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize)
|
|
+ (DriverState.Position.Y + i) * 320 + DriverState.Position.X;
|
|
|
|
/* Write the original data for this scanline */
|
|
EmulatorWriteMemory(&EmulatorContext,
|
|
VideoAddress,
|
|
&DriverState.GraphicsData[i * 16],
|
|
16 * sizeof(BYTE));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO: NOT IMPLEMENTED
|
|
UNIMPLEMENTED;
|
|
}
|
|
}
|
|
|
|
static VOID ToMouseCoordinates(PCOORD Position)
|
|
{
|
|
COORD Resolution = VgaGetDisplayResolution();
|
|
DWORD Width = DriverState.MaxX - DriverState.MinX + 1;
|
|
DWORD 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();
|
|
DWORD Width = DriverState.MaxX - DriverState.MinX + 1;
|
|
DWORD 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, BP, SI, DI, DS, ES;
|
|
COORD Position = DriverState.Position;
|
|
|
|
ToMouseCoordinates(&Position);
|
|
|
|
/* Call handler 0 */
|
|
if ((DriverState.Handler0.CallMask & CallMask) != 0 &&
|
|
DriverState.Handler0.Callback != NULL32)
|
|
{
|
|
/*
|
|
* Set the parameters for the callback.
|
|
* NOTE: In text modes, the row and column will be reported
|
|
* as a multiple of the cell size, typically 8x8 pixels.
|
|
*/
|
|
|
|
AX = getAX();
|
|
BX = getBX();
|
|
CX = getCX();
|
|
DX = getDX();
|
|
BP = getBP();
|
|
SI = getSI();
|
|
DI = getDI();
|
|
DS = getDS();
|
|
ES = getES();
|
|
|
|
setAX(CallMask);
|
|
setBX(DriverState.ButtonState);
|
|
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),
|
|
LOWORD(DriverState.Handler0.Callback),
|
|
CallMask);
|
|
|
|
/* Call the callback */
|
|
RunCallback16(&MouseContext, DriverState.Handler0.Callback);
|
|
|
|
setAX(AX);
|
|
setBX(BX);
|
|
setCX(CX);
|
|
setDX(DX);
|
|
setBP(BP);
|
|
setSI(SI);
|
|
setDI(DI);
|
|
setDS(DS);
|
|
setES(ES);
|
|
}
|
|
|
|
for (i = 0; i < ARRAYSIZE(DriverState.Handlers); ++i)
|
|
{
|
|
/* Call the suitable handlers */
|
|
if ((DriverState.Handlers[i].CallMask & CallMask) != 0 &&
|
|
DriverState.Handlers[i].Callback != NULL32)
|
|
{
|
|
/*
|
|
* Set the parameters for the callback.
|
|
* NOTE: In text modes, the row and column will be reported
|
|
* as a multiple of the cell size, typically 8x8 pixels.
|
|
*/
|
|
|
|
AX = getAX();
|
|
BX = getBX();
|
|
CX = getCX();
|
|
DX = getDX();
|
|
BP = getBP();
|
|
SI = getSI();
|
|
DI = getDI();
|
|
DS = getDS();
|
|
ES = getES();
|
|
|
|
setAX(CallMask);
|
|
setBX(DriverState.ButtonState);
|
|
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,
|
|
HIWORD(DriverState.Handlers[i].Callback),
|
|
LOWORD(DriverState.Handlers[i].Callback),
|
|
CallMask);
|
|
|
|
/* Call the callback */
|
|
RunCallback16(&MouseContext, DriverState.Handlers[i].Callback);
|
|
|
|
setAX(AX);
|
|
setBX(BX);
|
|
setCX(CX);
|
|
setDX(DX);
|
|
setBP(BP);
|
|
setSI(SI);
|
|
setDI(DI);
|
|
setDS(DS);
|
|
setES(ES);
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
if (DriverState.ShowCount > 0) PaintMouseCursor();
|
|
|
|
/* Call the mouse handlers */
|
|
CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
|
|
}
|
|
|
|
static inline VOID DosUpdateButtons(BYTE ButtonState) // WORD 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)
|
|
{
|
|
BYTE Flags;
|
|
SHORT DeltaX, DeltaY;
|
|
COORD Position;
|
|
BYTE ButtonState;
|
|
|
|
/* Read the whole packet at once */
|
|
Flags = IOReadB(PS2_DATA_PORT);
|
|
PS2PortQueueRead(1); // NOTE: Should be a IOReadB! But see r67231
|
|
DeltaX = IOReadB(PS2_DATA_PORT);
|
|
PS2PortQueueRead(1); // NOTE: Should be a IOReadB! But see r67231
|
|
DeltaY = IOReadB(PS2_DATA_PORT);
|
|
|
|
/* Adjust the sign */
|
|
if (Flags & MOUSE_X_SIGN) DeltaX = -DeltaX;
|
|
if (Flags & MOUSE_Y_SIGN) DeltaY = -DeltaY;
|
|
|
|
/* Update the counters */
|
|
DriverState.HorizCount += DeltaX;
|
|
DriverState.VertCount += DeltaY;
|
|
|
|
/*
|
|
* 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(LOBYTE(Stack[STACK_INT_NUM]));
|
|
}
|
|
|
|
static VOID WINAPI DosMouseService(LPWORD Stack)
|
|
{
|
|
switch (getAX())
|
|
{
|
|
/* Reset Driver */
|
|
case 0x00:
|
|
{
|
|
SHORT i;
|
|
|
|
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 */
|
|
|
|
/* Set the default graphics cursor */
|
|
DriverState.GraphicsCursor.HotSpot.X = 3;
|
|
DriverState.GraphicsCursor.HotSpot.Y = 1;
|
|
|
|
RtlCopyMemory(DriverState.GraphicsCursor.ScreenMask,
|
|
DefaultGfxScreenMask,
|
|
sizeof(DriverState.GraphicsCursor.ScreenMask));
|
|
|
|
RtlCopyMemory(DriverState.GraphicsCursor.CursorMask,
|
|
DefaultGfxCursorMask,
|
|
sizeof(DriverState.GraphicsCursor.CursorMask));
|
|
|
|
/* Initialize the counters */
|
|
DriverState.HorizCount = DriverState.VertCount = 0;
|
|
|
|
for (i = 0; i < NUM_MOUSE_BUTTONS; i++)
|
|
{
|
|
DriverState.PressCount[i] = DriverState.ReleaseCount[i] = 0;
|
|
}
|
|
|
|
/* Return mouse information */
|
|
setAX(0xFFFF); // Hardware & driver installed
|
|
setBX(NUM_MOUSE_BUTTONS);
|
|
|
|
break;
|
|
}
|
|
|
|
/* Show Mouse Cursor */
|
|
case 0x01:
|
|
{
|
|
DriverState.ShowCount++;
|
|
if (DriverState.ShowCount == 1) PaintMouseCursor();
|
|
|
|
break;
|
|
}
|
|
|
|
/* Hide Mouse Cursor */
|
|
case 0x02:
|
|
{
|
|
DriverState.ShowCount--;
|
|
if (DriverState.ShowCount == 0) EraseMouseCursor();
|
|
|
|
break;
|
|
}
|
|
|
|
/* Return Position and Button Status */
|
|
case 0x03:
|
|
{
|
|
COORD Position = DriverState.Position;
|
|
ToMouseCoordinates(&Position);
|
|
|
|
setBX(DriverState.ButtonState);
|
|
setCX(Position.X);
|
|
setDX(Position.Y);
|
|
break;
|
|
}
|
|
|
|
/* Position Mouse Cursor */
|
|
case 0x04:
|
|
{
|
|
COORD Position = { getCX(), getDX() };
|
|
FromMouseCoordinates(&Position);
|
|
|
|
DriverState.Position = Position;
|
|
break;
|
|
}
|
|
|
|
/* Return Button Press Data */
|
|
case 0x05:
|
|
{
|
|
WORD Button = getBX();
|
|
COORD LastPress = DriverState.LastPress[Button];
|
|
ToMouseCoordinates(&LastPress);
|
|
|
|
setAX(DriverState.ButtonState);
|
|
setBX(DriverState.PressCount[Button]);
|
|
setCX(LastPress.X);
|
|
setDX(LastPress.Y);
|
|
|
|
/* Reset the counter */
|
|
DriverState.PressCount[Button] = 0;
|
|
|
|
break;
|
|
}
|
|
|
|
/* Return Button Release Data */
|
|
case 0x06:
|
|
{
|
|
WORD Button = getBX();
|
|
COORD LastRelease = DriverState.LastRelease[Button];
|
|
ToMouseCoordinates(&LastRelease);
|
|
|
|
setAX(DriverState.ButtonState);
|
|
setBX(DriverState.ReleaseCount[Button]);
|
|
setCX(LastRelease.X);
|
|
setDX(LastRelease.Y);
|
|
|
|
/* Reset the counter */
|
|
DriverState.ReleaseCount[Button] = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Define Horizontal Cursor Range */
|
|
case 0x07:
|
|
{
|
|
WORD Min = getCX();
|
|
WORD Max = getDX();
|
|
|
|
if (!VgaGetDoubleVisionState(NULL, NULL))
|
|
{
|
|
/* Text mode */
|
|
Min &= ~0x07;
|
|
Max |= 0x07;
|
|
}
|
|
|
|
DPRINT("Setting mouse horizontal range: %u - %u\n", Min, Max);
|
|
DriverState.MinX = Min;
|
|
DriverState.MaxX = Max;
|
|
break;
|
|
}
|
|
|
|
/* Define Vertical Cursor Range */
|
|
case 0x08:
|
|
{
|
|
WORD Min = getCX();
|
|
WORD Max = getDX();
|
|
|
|
if (!VgaGetDoubleVisionState(NULL, NULL))
|
|
{
|
|
/* Text mode */
|
|
Min &= ~0x07;
|
|
Max |= 0x07;
|
|
}
|
|
|
|
DPRINT("Setting mouse vertical range: %u - %u\n", Min, Max);
|
|
DriverState.MinY = Min;
|
|
DriverState.MaxY = Max;
|
|
break;
|
|
}
|
|
|
|
/* Define Graphics Cursor */
|
|
case 0x09:
|
|
{
|
|
PWORD MaskBitmap = (PWORD)SEG_OFF_TO_PTR(getES(), getDX());
|
|
|
|
DriverState.GraphicsCursor.HotSpot.X = getBX();
|
|
DriverState.GraphicsCursor.HotSpot.Y = getCX();
|
|
|
|
RtlCopyMemory(DriverState.GraphicsCursor.ScreenMask,
|
|
MaskBitmap,
|
|
sizeof(DriverState.GraphicsCursor.ScreenMask));
|
|
|
|
RtlCopyMemory(DriverState.GraphicsCursor.CursorMask,
|
|
&MaskBitmap[16],
|
|
sizeof(DriverState.GraphicsCursor.CursorMask));
|
|
|
|
break;
|
|
}
|
|
|
|
/* Define Text Cursor */
|
|
case 0x0A:
|
|
{
|
|
USHORT BX = getBX();
|
|
|
|
if (BX == 0x0000)
|
|
{
|
|
/* Define software cursor */
|
|
DriverState.TextCursor.ScreenMask = getCX();
|
|
DriverState.TextCursor.CursorMask = getDX();
|
|
}
|
|
else if (BX == 0x0001)
|
|
{
|
|
/* Define hardware cursor */
|
|
DPRINT1("Defining hardware cursor is unimplemented\n");
|
|
UNIMPLEMENTED;
|
|
// CX == start scan line
|
|
// DX == end scan line
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("Invalid BX value 0x%04X\n", BX);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/* Read Motion Counters */
|
|
case 0x0B:
|
|
{
|
|
setCX(DriverState.HorizCount);
|
|
setDX(DriverState.VertCount);
|
|
|
|
/* Reset the counters */
|
|
DriverState.HorizCount = DriverState.VertCount = 0;
|
|
|
|
break;
|
|
}
|
|
|
|
/* Define Interrupt Subroutine Parameters, compatible MS MOUSE v1.0+ */
|
|
case 0x0C:
|
|
{
|
|
DriverState.Handler0.CallMask = getCX();
|
|
DriverState.Handler0.Callback = MAKELONG(getDX(), getES()); // Far pointer to the callback
|
|
DPRINT1("Define callback 0x%04X, %04X:%04X\n",
|
|
DriverState.Handler0.CallMask,
|
|
HIWORD(DriverState.Handler0.Callback),
|
|
LOWORD(DriverState.Handler0.Callback));
|
|
break;
|
|
}
|
|
|
|
/* Define Mickey/Pixel Ratio */
|
|
case 0x0F:
|
|
{
|
|
/* This call should be completely ignored */
|
|
break;
|
|
}
|
|
|
|
/* Set Exclusion Area */
|
|
// http://www.ctyme.com/intr/rb-5972.htm
|
|
// http://www.techhelpmanual.com/849-int_33h_0010h__set_exclusion_area.html
|
|
//case 0x10:
|
|
//{
|
|
//}
|
|
|
|
/* Define Double-Speed Threshold */
|
|
case 0x13:
|
|
{
|
|
DPRINT1("INT 33h, AH=13h: Mouse double-speed threshold is UNSUPPORTED\n");
|
|
break;
|
|
}
|
|
|
|
/* Exchange Interrupt Subroutines, compatible MS MOUSE v3.0+ (see function 0x0C) */
|
|
case 0x14:
|
|
{
|
|
USHORT OldCallMask = DriverState.Handler0.CallMask;
|
|
ULONG OldCallback = DriverState.Handler0.Callback;
|
|
|
|
DriverState.Handler0.CallMask = getCX();
|
|
DriverState.Handler0.Callback = MAKELONG(getDX(), getES()); // Far pointer to the callback
|
|
DPRINT1("Exchange old callback 0x%04X, %04X:%04X with new callback 0x%04X, %04X:%04X\n",
|
|
OldCallMask,
|
|
HIWORD(OldCallback),
|
|
LOWORD(OldCallback),
|
|
DriverState.Handler0.CallMask,
|
|
HIWORD(DriverState.Handler0.Callback),
|
|
LOWORD(DriverState.Handler0.Callback));
|
|
|
|
/* Return old callmask in CX and callback vector in ES:DX */
|
|
setCX(OldCallMask);
|
|
setES(HIWORD(OldCallback));
|
|
setDX(LOWORD(OldCallback));
|
|
break;
|
|
}
|
|
|
|
/* Return Driver Storage Requirements */
|
|
case 0x15:
|
|
{
|
|
setBX(sizeof(MOUSE_DRIVER_STATE));
|
|
break;
|
|
}
|
|
|
|
/* Save Driver State */
|
|
case 0x16:
|
|
{
|
|
/* Check whether the user buffer has correct size and fail if not */
|
|
if (getBX() != sizeof(MOUSE_DRIVER_STATE)) break;
|
|
|
|
*((PMOUSE_DRIVER_STATE)SEG_OFF_TO_PTR(getES(), getDX())) = DriverState;
|
|
break;
|
|
}
|
|
|
|
/* Restore Driver State */
|
|
case 0x17:
|
|
{
|
|
/* Check whether the user buffer has correct size and fail if not */
|
|
if (getBX() != sizeof(MOUSE_DRIVER_STATE)) break;
|
|
|
|
DriverState = *((PMOUSE_DRIVER_STATE)SEG_OFF_TO_PTR(getES(), getDX()));
|
|
break;
|
|
}
|
|
|
|
/* Set Alternate Mouse User Handler, compatible MS MOUSE v6.0+ */
|
|
case 0x18:
|
|
{
|
|
/*
|
|
* Up to three handlers can be defined by separate calls to this
|
|
* function, each with a different combination of shift states in
|
|
* the call mask; calling this function again with a call mask of
|
|
* 0000h undefines the specified handler (official documentation);
|
|
* specifying the same call mask and an address of 0000h:0000h
|
|
* undefines the handler (real life).
|
|
* See Ralf Brown: http://www.ctyme.com/intr/rb-5981.htm
|
|
* for more information.
|
|
*/
|
|
|
|
USHORT i;
|
|
USHORT CallMask = getCX();
|
|
ULONG Callback = MAKELONG(getDX(), getES()); // Far pointer to the callback
|
|
BOOLEAN Success = FALSE;
|
|
|
|
DPRINT1("Define v6.0+ callback 0x%04X, %04X:%04X\n",
|
|
CallMask, HIWORD(Callback), LOWORD(Callback));
|
|
|
|
if (CallMask == 0x0000)
|
|
{
|
|
/*
|
|
* Find the handler entry corresponding to the given
|
|
* callback and undefine it.
|
|
*/
|
|
for (i = 0; i < ARRAYSIZE(DriverState.Handlers); ++i)
|
|
{
|
|
if (DriverState.Handlers[i].Callback == Callback)
|
|
{
|
|
/* Found it, undefine the handler */
|
|
DriverState.Handlers[i].CallMask = 0x0000;
|
|
DriverState.Handlers[i].Callback = NULL32;
|
|
Success = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (Callback == NULL32)
|
|
{
|
|
/*
|
|
* Find the handler entry corresponding to the given
|
|
* callmask and undefine it.
|
|
*/
|
|
for (i = 0; i < ARRAYSIZE(DriverState.Handlers); ++i)
|
|
{
|
|
if (DriverState.Handlers[i].CallMask == CallMask)
|
|
{
|
|
/* Found it, undefine the handler */
|
|
DriverState.Handlers[i].CallMask = 0x0000;
|
|
DriverState.Handlers[i].Callback = NULL32;
|
|
Success = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Try to find a handler entry corresponding to the given
|
|
* callmask to redefine it, otherwise find an empty handler
|
|
* entry and set the new handler in there.
|
|
*/
|
|
|
|
USHORT EmptyHandler = 0xFFFF; // Invalid handler
|
|
|
|
for (i = 0; i < ARRAYSIZE(DriverState.Handlers); ++i)
|
|
{
|
|
/* Find the first empty handler */
|
|
if (EmptyHandler == 0xFFFF &&
|
|
DriverState.Handlers[i].CallMask == 0x0000 &&
|
|
DriverState.Handlers[i].Callback == NULL32)
|
|
{
|
|
EmptyHandler = i;
|
|
}
|
|
|
|
if (DriverState.Handlers[i].CallMask == CallMask)
|
|
{
|
|
/* Found it, redefine the handler */
|
|
DriverState.Handlers[i].CallMask = CallMask;
|
|
DriverState.Handlers[i].Callback = Callback;
|
|
Success = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we haven't found anything and we found
|
|
* an empty handler, set it.
|
|
*/
|
|
if (!Success && EmptyHandler != 0xFFFF
|
|
/* && EmptyHandler < ARRAYSIZE(DriverState.Handlers) */)
|
|
{
|
|
DriverState.Handlers[EmptyHandler].CallMask = CallMask;
|
|
DriverState.Handlers[EmptyHandler].Callback = Callback;
|
|
Success = TRUE;
|
|
}
|
|
}
|
|
|
|
/* If we failed, set error code */
|
|
if (!Success) setAX(0xFFFF);
|
|
|
|
break;
|
|
}
|
|
|
|
/* Return User Alternate Interrupt Vector, compatible MS MOUSE v6.0+ */
|
|
case 0x19:
|
|
{
|
|
USHORT i;
|
|
USHORT CallMask = getCX();
|
|
ULONG Callback;
|
|
BOOLEAN Success = FALSE;
|
|
|
|
/*
|
|
* Find the handler entry corresponding to the given callmask.
|
|
*/
|
|
for (i = 0; i < ARRAYSIZE(DriverState.Handlers); ++i)
|
|
{
|
|
if (DriverState.Handlers[i].CallMask == CallMask)
|
|
{
|
|
/* Found it */
|
|
Callback = DriverState.Handlers[i].Callback;
|
|
Success = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Success)
|
|
{
|
|
/* Return the callback vector in BX:DX */
|
|
setBX(HIWORD(Callback));
|
|
setDX(LOWORD(Callback));
|
|
}
|
|
else
|
|
{
|
|
/* We failed, set error code */
|
|
setCX(0x0000);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/* Set Mouse Sensitivity */
|
|
case 0x1A:
|
|
{
|
|
DPRINT1("INT 33h, AH=1Ah: Mouse sensitivity is UNSUPPORTED\n");
|
|
|
|
// FIXME: Do that at runtime!
|
|
|
|
// UCHAR BH = getBH();
|
|
// setBH(0x00);
|
|
// BiosPs2Service(0x00);
|
|
// FIXME: Check for return status in AH and CF
|
|
// setBH(BH);
|
|
|
|
break;
|
|
}
|
|
|
|
/* Return Mouse Sensitivity */
|
|
case 0x1B:
|
|
{
|
|
DPRINT1("INT 33h, AH=1Bh: Mouse sensitivity is UNSUPPORTED\n");
|
|
|
|
/* Return default values */
|
|
setBX(50); // Horizontal speed
|
|
setCX(50); // Vertical speed
|
|
setDX(50); // Double speed threshold
|
|
|
|
// FIXME: Get that at runtime!
|
|
|
|
// UCHAR BH = getBH();
|
|
// setBH(0x00);
|
|
// BiosPs2Service(0x00);
|
|
// FIXME: Check for return status in AH and CF
|
|
// setBH(BH);
|
|
|
|
break;
|
|
}
|
|
|
|
/* Disable Mouse Driver */
|
|
case 0x1F:
|
|
{
|
|
/* INT 33h vector before the mouse driver was first installed */
|
|
setES(HIWORD(OldIntHandler));
|
|
setBX(LOWORD(OldIntHandler));
|
|
|
|
DosMouseDisable();
|
|
// UCHAR BH = getBH();
|
|
// setBH(0x00);
|
|
// BiosPs2Service(0x00);
|
|
// FIXME: Check for return status in AH and CF
|
|
// setBH(BH);
|
|
break;
|
|
}
|
|
|
|
/* Enable Mouse Driver */
|
|
case 0x20:
|
|
{
|
|
DosMouseEnable();
|
|
// UCHAR BH = getBH();
|
|
// setBH(0x01);
|
|
// BiosPs2Service(0x00);
|
|
// FIXME: Check for return status in AH and CF
|
|
// setBH(BH);
|
|
break;
|
|
}
|
|
|
|
/* Software Reset */
|
|
case 0x21:
|
|
{
|
|
/*
|
|
* See: http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte3sq8.htm
|
|
* for detailed information and differences with respect to subfunction 0x00:
|
|
* http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte3j74.htm
|
|
*/
|
|
|
|
SHORT i;
|
|
|
|
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;
|
|
|
|
/* Initialize the counters */
|
|
DriverState.HorizCount = DriverState.VertCount = 0;
|
|
|
|
for (i = 0; i < NUM_MOUSE_BUTTONS; i++)
|
|
{
|
|
DriverState.PressCount[i] = DriverState.ReleaseCount[i] = 0;
|
|
}
|
|
|
|
/* Return mouse information */
|
|
setAX(0xFFFF); // Hardware & driver installed
|
|
setBX(NUM_MOUSE_BUTTONS);
|
|
|
|
break;
|
|
}
|
|
|
|
/* Get Software Version, Mouse Type, and IRQ Number, compatible MS MOUSE v6.26+ */
|
|
case 0x24:
|
|
{
|
|
setBX(MOUSE_VERSION); // Version Number
|
|
|
|
/*
|
|
* See Ralf Brown: http://www.ctyme.com/intr/rb-5993.htm
|
|
* for the list of possible values.
|
|
*/
|
|
// FIXME: To be determined at runtime!
|
|
setCH(0x04); // PS/2 Type
|
|
setCL(0x00); // PS/2 Interrupt
|
|
|
|
break;
|
|
}
|
|
|
|
// BIOS Function INT 33h, AX = 0x0025 NOT IMPLEMENTED
|
|
case 0x25:
|
|
{
|
|
setAX(0);
|
|
setBX(0);
|
|
setCX(0);
|
|
setDX(0);
|
|
UNIMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
/* Get Maximum Virtual Coordinates */
|
|
case 0x26:
|
|
{
|
|
setBX(!DriverEnabled);
|
|
// FIXME: In fact the MaxX and MaxY here are
|
|
// theoretical values for the current video mode.
|
|
// They therefore can be different from the current
|
|
// min/max values.
|
|
// See http://www.ctyme.com/intr/rb-5995.htm
|
|
// for more details.
|
|
setCX(DriverState.MaxX);
|
|
setDX(DriverState.MaxY);
|
|
break;
|
|
}
|
|
|
|
/* Get Current Minimum/Maximum Virtual Coordinates */
|
|
case 0x31:
|
|
{
|
|
setAX(DriverState.MinX);
|
|
setBX(DriverState.MinY);
|
|
setCX(DriverState.MaxX);
|
|
setDX(DriverState.MaxY);
|
|
break;
|
|
}
|
|
|
|
#if 0
|
|
case 0x33:
|
|
{
|
|
/*
|
|
* Related to http://www.ctyme.com/intr/rb-5985.htm
|
|
* INT 33h, AX=001Ch "SET INTERRUPT RATE":
|
|
|
|
* Values for mouse interrupt rate:
|
|
* BX = rate
|
|
00h no interrupts allowed
|
|
01h 30 per second
|
|
02h 50 per second
|
|
03h 100 per second
|
|
04h 200 per second
|
|
*/
|
|
}
|
|
#endif
|
|
|
|
/* Return Pointer to Copyright String */
|
|
case 0x4D:
|
|
{
|
|
setES(MouseDataSegment);
|
|
setDI(FIELD_OFFSET(MOUSE_DRIVER, Copyright));
|
|
break;
|
|
}
|
|
|
|
/* Get Version String (pointer) */
|
|
case 0x6D:
|
|
{
|
|
/*
|
|
* The format of the version "string" is:
|
|
* Offset Size Description
|
|
* 00h BYTE major version
|
|
* 01h BYTE minor version (BCD)
|
|
*/
|
|
setES(MouseDataSegment);
|
|
setDI(FIELD_OFFSET(MOUSE_DRIVER, Version));
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DPRINT1("BIOS Function INT 33h, AX = 0x%04X NOT IMPLEMENTED\n", getAX());
|
|
}
|
|
}
|
|
}
|
|
|
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
|
|
|
static
|
|
VOID DosMouseEnable(VOID)
|
|
{
|
|
if (DriverEnabled) return;
|
|
|
|
DriverEnabled = TRUE;
|
|
|
|
/* Get the old IRQ handler */
|
|
OldIrqHandler = ((PDWORD)BaseAddress)[MOUSE_IRQ_INT];
|
|
|
|
/* Set the IRQ handler */
|
|
RegisterInt32(MAKELONG(FIELD_OFFSET(MOUSE_DRIVER, MouseIrqInt16Stub), MouseDataSegment),
|
|
MOUSE_IRQ_INT, DosMouseIrq, NULL);
|
|
}
|
|
|
|
static
|
|
VOID DosMouseDisable(VOID)
|
|
{
|
|
if (!DriverEnabled) return;
|
|
|
|
/* Restore the old IRQ handler */
|
|
((PDWORD)BaseAddress)[MOUSE_IRQ_INT] = OldIrqHandler;
|
|
|
|
DriverEnabled = FALSE;
|
|
}
|
|
|
|
BOOLEAN DosMouseInitialize(VOID)
|
|
{
|
|
/* Initialize some memory for storing our data that should be available to DOS */
|
|
MouseDataSegment = DosAllocateMemory(sizeof(MOUSE_DRIVER), NULL);
|
|
if (MouseDataSegment == 0) return FALSE;
|
|
MouseData = (PMOUSE_DRIVER)SEG_OFF_TO_PTR(MouseDataSegment, 0x0000);
|
|
|
|
/* Initialize the callback context */
|
|
InitializeContext(&MouseContext, MouseDataSegment, FIELD_OFFSET(MOUSE_DRIVER, MouseContextScratch));
|
|
|
|
/* Clear the state */
|
|
RtlZeroMemory(&DriverState, sizeof(DriverState));
|
|
|
|
/* Mouse Driver Copyright */
|
|
RtlCopyMemory(MouseData->Copyright, MouseCopyright, sizeof(MouseCopyright)-1);
|
|
|
|
/* Mouse Driver Version in BCD format, compatible MS-MOUSE */
|
|
MouseData->Version = MAKEWORD(MOUSE_VERSION/0x0100, MOUSE_VERSION%0x0100);
|
|
|
|
/* Get the old mouse service interrupt handler */
|
|
OldIntHandler = ((PDWORD)BaseAddress)[DOS_MOUSE_INTERRUPT];
|
|
|
|
/* Initialize the interrupt handler */
|
|
RegisterInt32(MAKELONG(FIELD_OFFSET(MOUSE_DRIVER, MouseDosInt16Stub), MouseDataSegment),
|
|
DOS_MOUSE_INTERRUPT, DosMouseService, NULL);
|
|
|
|
DosMouseEnable();
|
|
// UCHAR BH = getBH();
|
|
// setBH(0x01);
|
|
// BiosPs2Service(0x00);
|
|
// FIXME: Check for return status in AH and CF
|
|
// setBH(BH);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID DosMouseCleanup(VOID)
|
|
{
|
|
if (DriverState.ShowCount > 0) EraseMouseCursor();
|
|
DosMouseDisable();
|
|
// UCHAR BH = getBH();
|
|
// setBH(0x00);
|
|
// BiosPs2Service(0x00);
|
|
// FIXME: Check for return status in AH and CF
|
|
// setBH(BH);
|
|
|
|
/* Restore the old mouse service interrupt handler */
|
|
((PDWORD)BaseAddress)[DOS_MOUSE_INTERRUPT] = OldIntHandler;
|
|
|
|
DosFreeMemory(MouseDataSegment);
|
|
MouseDataSegment = 0;
|
|
MouseData = 0;
|
|
}
|
|
|
|
/* EOF */
|