mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 01:15:09 +00:00
[NTVDM]
- Move the mouse driver to DOS since it's our 32bit version of mouse.com, in some sense, - Temporarily disable the mouse user callbacks because currently they went called in a parallel thread than the CPU one, that caused CPU corruption, - In the same way we currently trigger IRQ1 interrupts, we do the same for IRQ12, - Make the console input pump more modular (and mouse presence detection code is WIP), - Put keyboard code into a dedicated file (as done for the mouse), - Adapt the existing PS/2 emulation code to support two PS/2 ports controlled by 1 controller. Please note that some documentations precise that the response byte (answer to a PS/2 controller command) is written directly to the PS/2 output port. svn path=/trunk/; revision=64168
This commit is contained in:
parent
9c5062a147
commit
0c86291749
17 changed files with 1222 additions and 862 deletions
|
@ -15,15 +15,17 @@ list(APPEND SOURCE
|
|||
bios/rom.c
|
||||
bios/vidbios.c
|
||||
hardware/cmos.c
|
||||
hardware/keyboard.c
|
||||
hardware/mouse.c
|
||||
hardware/pic.c
|
||||
hardware/ps2.c
|
||||
hardware/speaker.c
|
||||
hardware/timer.c
|
||||
hardware/vga.c
|
||||
hardware/mouse.c
|
||||
dos/dos32krnl/bios.c
|
||||
dos/dos32krnl/dos.c
|
||||
dos/dos32krnl/dosfiles.c
|
||||
dos/mouse32.c
|
||||
dos/dem.c
|
||||
bop.c
|
||||
callback.c
|
||||
|
|
|
@ -21,618 +21,24 @@
|
|||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
static BOOLEAN DriverEnabled = TRUE;
|
||||
static MOUSE_DRIVER_STATE DriverState;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static VOID PaintMouseCursor(VOID)
|
||||
// Mouse IRQ 12
|
||||
static VOID WINAPI BiosMouseIrq(LPWORD Stack)
|
||||
{
|
||||
if (Bda->VideoMode <= 3)
|
||||
{
|
||||
WORD Character;
|
||||
DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize);
|
||||
|
||||
EmulatorReadMemory(&EmulatorContext,
|
||||
VideoAddress
|
||||
+ (DriverState.Position.Y * Bda->ScreenColumns
|
||||
+ DriverState.Position.X) * sizeof(WORD),
|
||||
(LPVOID)&Character,
|
||||
sizeof(WORD));
|
||||
|
||||
DriverState.Character = Character;
|
||||
Character &= DriverState.TextCursor.ScreenMask;
|
||||
Character ^= DriverState.TextCursor.CursorMask;
|
||||
|
||||
EmulatorWriteMemory(&EmulatorContext,
|
||||
VideoAddress
|
||||
+ (DriverState.Position.Y * Bda->ScreenColumns
|
||||
+ DriverState.Position.X) * sizeof(WORD),
|
||||
(LPVOID)&Character,
|
||||
sizeof(WORD));
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
static VOID EraseMouseCursor(VOID)
|
||||
{
|
||||
if (Bda->VideoMode <= 3)
|
||||
{
|
||||
DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize);
|
||||
|
||||
EmulatorWriteMemory(&EmulatorContext,
|
||||
VideoAddress
|
||||
+ (DriverState.Position.Y * Bda->ScreenColumns
|
||||
+ DriverState.Position.X) * sizeof(WORD),
|
||||
(LPVOID)&DriverState.Character,
|
||||
sizeof(WORD));
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
static VOID CallMouseUserHandlers(USHORT CallMask)
|
||||
{
|
||||
USHORT i;
|
||||
|
||||
/* Call handler 0 */
|
||||
if ((DriverState.Handler0.CallMask & CallMask) != 0 &&
|
||||
DriverState.Handler0.Callback != (ULONG)NULL)
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
setAX(CallMask);
|
||||
setBX(DriverState.ButtonState);
|
||||
setCX(DriverState.Position.X);
|
||||
setDX(DriverState.Position.Y);
|
||||
setSI(DriverState.MickeysPerCellHoriz);
|
||||
setDI(DriverState.MickeysPerCellVert);
|
||||
|
||||
DPRINT1("Calling Handler0 0x%08x with CallMask 0x%04x\n",
|
||||
DriverState.Handler0.Callback, CallMask);
|
||||
|
||||
/* Call the callback */
|
||||
RunCallback16(&BiosContext, DriverState.Handler0.Callback);
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
|
||||
{
|
||||
/* Call the suitable handlers */
|
||||
if ((DriverState.Handlers[i].CallMask & CallMask) != 0 &&
|
||||
DriverState.Handlers[i].Callback != (ULONG)NULL)
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
setAX(CallMask);
|
||||
setBX(DriverState.ButtonState);
|
||||
setCX(DriverState.Position.X);
|
||||
setDX(DriverState.Position.Y);
|
||||
setSI(DriverState.MickeysPerCellHoriz);
|
||||
setDI(DriverState.MickeysPerCellVert);
|
||||
|
||||
DPRINT1("Calling Handler[%d] 0x%08x with CallMask 0x%04x\n",
|
||||
i, DriverState.Handlers[i].Callback, CallMask);
|
||||
|
||||
/* Call the callback */
|
||||
RunCallback16(&BiosContext, DriverState.Handlers[i].Callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VOID WINAPI BiosMouseService(LPWORD Stack)
|
||||
{
|
||||
switch (getAX())
|
||||
{
|
||||
/* Reset Driver */
|
||||
case 0x00:
|
||||
{
|
||||
SHORT i;
|
||||
|
||||
DriverEnabled = TRUE;
|
||||
DriverState.ShowCount = 0;
|
||||
DriverState.ButtonState = 0;
|
||||
|
||||
/* 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;
|
||||
|
||||
DriverState.GraphicsCursor.ScreenMask[0] = 0xC3FF; // 1100001111111111
|
||||
DriverState.GraphicsCursor.ScreenMask[1] = 0xC0FF; // 1100000011111111
|
||||
DriverState.GraphicsCursor.ScreenMask[2] = 0xC07F; // 1100000001111111
|
||||
DriverState.GraphicsCursor.ScreenMask[3] = 0xC01F; // 1100000000011111
|
||||
DriverState.GraphicsCursor.ScreenMask[4] = 0xC00F; // 1100000000001111
|
||||
DriverState.GraphicsCursor.ScreenMask[5] = 0xC007; // 1100000000000111
|
||||
DriverState.GraphicsCursor.ScreenMask[6] = 0xC003; // 1100000000000011
|
||||
DriverState.GraphicsCursor.ScreenMask[7] = 0xC007; // 1100000000000111
|
||||
DriverState.GraphicsCursor.ScreenMask[8] = 0xC01F; // 1100000000011111
|
||||
DriverState.GraphicsCursor.ScreenMask[9] = 0xC01F; // 1100000000011111
|
||||
DriverState.GraphicsCursor.ScreenMask[10] = 0xC00F; // 1100000000001111
|
||||
DriverState.GraphicsCursor.ScreenMask[11] = 0xC60F; // 1100011000001111
|
||||
DriverState.GraphicsCursor.ScreenMask[12] = 0xFF07; // 1111111100000111
|
||||
DriverState.GraphicsCursor.ScreenMask[13] = 0xFF07; // 1111111100000111
|
||||
DriverState.GraphicsCursor.ScreenMask[14] = 0xFF87; // 1111111110000111
|
||||
DriverState.GraphicsCursor.ScreenMask[15] = 0xFFCF; // 1111111111001111
|
||||
|
||||
DriverState.GraphicsCursor.CursorMask[0] = 0x0000; // 0000000000000000
|
||||
DriverState.GraphicsCursor.CursorMask[1] = 0x1C00; // 0001110000000000
|
||||
DriverState.GraphicsCursor.CursorMask[2] = 0x1F00; // 0001111100000000
|
||||
DriverState.GraphicsCursor.CursorMask[3] = 0x1F80; // 0001111110000000
|
||||
DriverState.GraphicsCursor.CursorMask[4] = 0x1FE0; // 0001111111100000
|
||||
DriverState.GraphicsCursor.CursorMask[5] = 0x1FF0; // 0001111111110000
|
||||
DriverState.GraphicsCursor.CursorMask[6] = 0x1FF8; // 0001111111111000
|
||||
DriverState.GraphicsCursor.CursorMask[7] = 0x1FE0; // 0001111111100000
|
||||
DriverState.GraphicsCursor.CursorMask[8] = 0x1FC0; // 0001111111000000
|
||||
DriverState.GraphicsCursor.CursorMask[9] = 0x1FC0; // 0001111111000000
|
||||
DriverState.GraphicsCursor.CursorMask[10] = 0x19E0; // 0001100111100000
|
||||
DriverState.GraphicsCursor.CursorMask[11] = 0x00E0; // 0000000011100000
|
||||
DriverState.GraphicsCursor.CursorMask[12] = 0x0070; // 0000000001110000
|
||||
DriverState.GraphicsCursor.CursorMask[13] = 0x0070; // 0000000001110000
|
||||
DriverState.GraphicsCursor.CursorMask[14] = 0x0030; // 0000000000110000
|
||||
DriverState.GraphicsCursor.CursorMask[15] = 0x0000; // 0000000000000000
|
||||
|
||||
/* Initialize the counters */
|
||||
DriverState.HorizCount = DriverState.VertCount = 0;
|
||||
|
||||
for (i = 0; i < NUM_MOUSE_BUTTONS; i++)
|
||||
{
|
||||
DriverState.PressCount[i] = DriverState.ReleaseCount[i] = 0;
|
||||
}
|
||||
|
||||
/* Initialize the resolution */
|
||||
DriverState.MickeysPerCellHoriz = 8;
|
||||
DriverState.MickeysPerCellVert = 16;
|
||||
|
||||
/* Return mouse information */
|
||||
setAX(0xFFFF); // Hardware & driver installed
|
||||
setBX(NUM_MOUSE_BUTTONS);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Show Mouse Cursor */
|
||||
case 0x01:
|
||||
{
|
||||
DriverState.ShowCount++;
|
||||
if (DriverState.ShowCount > 0) PaintMouseCursor();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Hide Mouse Cursor */
|
||||
case 0x02:
|
||||
{
|
||||
DriverState.ShowCount--;
|
||||
if (DriverState.ShowCount <= 0) EraseMouseCursor();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return Position And Button Status */
|
||||
case 0x03:
|
||||
{
|
||||
setBX(DriverState.ButtonState);
|
||||
setCX(DriverState.Position.X);
|
||||
setDX(DriverState.Position.Y);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Position Mouse Cursor */
|
||||
case 0x04:
|
||||
{
|
||||
POINT Point;
|
||||
|
||||
Point.x = getCX();
|
||||
Point.y = getDX();
|
||||
|
||||
ClientToScreen(GetConsoleWindow(), &Point);
|
||||
SetCursorPos(Point.x, Point.y);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return Button Press Data */
|
||||
case 0x05:
|
||||
{
|
||||
WORD Button = getBX();
|
||||
|
||||
setAX(DriverState.ButtonState);
|
||||
setBX(DriverState.PressCount[Button]);
|
||||
setCX(DriverState.LastPress[Button].X);
|
||||
setDX(DriverState.LastPress[Button].Y);
|
||||
|
||||
/* Reset the counter */
|
||||
DriverState.PressCount[Button] = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return Button Release Data */
|
||||
case 0x06:
|
||||
{
|
||||
WORD Button = getBX();
|
||||
|
||||
setAX(DriverState.ButtonState);
|
||||
setBX(DriverState.ReleaseCount[Button]);
|
||||
setCX(DriverState.LastRelease[Button].X);
|
||||
setDX(DriverState.LastRelease[Button].Y);
|
||||
|
||||
/* Reset the counter */
|
||||
DriverState.ReleaseCount[Button] = 0;
|
||||
|
||||
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();
|
||||
|
||||
RtlMoveMemory(DriverState.GraphicsCursor.ScreenMask,
|
||||
MaskBitmap,
|
||||
sizeof(DriverState.GraphicsCursor.ScreenMask));
|
||||
|
||||
RtlMoveMemory(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, 0x%08x\n",
|
||||
DriverState.Handler0.CallMask, DriverState.Handler0.Callback);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Define Mickey/Pixel Ratio */
|
||||
case 0x0F:
|
||||
{
|
||||
DriverState.MickeysPerCellHoriz = getCX();
|
||||
DriverState.MickeysPerCellVert = getDX();
|
||||
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
|
||||
|
||||
/* 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:
|
||||
{
|
||||
*((PMOUSE_DRIVER_STATE)SEG_OFF_TO_PTR(getES(), getDX())) = DriverState;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Restore Driver State */
|
||||
case 0x17:
|
||||
{
|
||||
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, 0x%08x\n",
|
||||
CallMask, Callback);
|
||||
|
||||
if (CallMask == 0x0000)
|
||||
{
|
||||
/*
|
||||
* Find the handler entry corresponding to the given
|
||||
* callback and undefine it.
|
||||
*/
|
||||
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
|
||||
{
|
||||
if (DriverState.Handlers[i].Callback == Callback)
|
||||
{
|
||||
/* Found it, undefine the handler */
|
||||
DriverState.Handlers[i].CallMask = 0x0000;
|
||||
DriverState.Handlers[i].Callback = (ULONG)NULL;
|
||||
Success = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Callback == (ULONG)NULL)
|
||||
{
|
||||
/*
|
||||
* Find the handler entry corresponding to the given
|
||||
* callmask and undefine it.
|
||||
*/
|
||||
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
|
||||
{
|
||||
if (DriverState.Handlers[i].CallMask == CallMask)
|
||||
{
|
||||
/* Found it, undefine the handler */
|
||||
DriverState.Handlers[i].CallMask = 0x0000;
|
||||
DriverState.Handlers[i].Callback = (ULONG)NULL;
|
||||
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 < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
|
||||
{
|
||||
/* Find the first empty handler */
|
||||
if (EmptyHandler == 0xFFFF &&
|
||||
DriverState.Handlers[i].CallMask == 0x0000 &&
|
||||
DriverState.Handlers[i].Callback == (ULONG)NULL)
|
||||
{
|
||||
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 < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]) */)
|
||||
{
|
||||
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 < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++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;
|
||||
}
|
||||
|
||||
/* Disable Mouse Driver */
|
||||
case 0x1F:
|
||||
{
|
||||
setES(0x0000);
|
||||
setBX(0x0000);
|
||||
|
||||
DriverEnabled = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable Mouse Driver */
|
||||
case 0x20:
|
||||
{
|
||||
DriverEnabled = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
DPRINT1("BIOS Function INT 33h, AX = 0x%04X NOT IMPLEMENTED\n", getAX());
|
||||
}
|
||||
}
|
||||
PicIRQComplete(Stack);
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID MouseBiosUpdatePosition(PCOORD NewPosition)
|
||||
{
|
||||
SHORT DeltaX = NewPosition->X - DriverState.Position.X;
|
||||
SHORT DeltaY = NewPosition->Y - DriverState.Position.Y;
|
||||
|
||||
if (!DriverEnabled) return;
|
||||
|
||||
DriverState.HorizCount += (DeltaX * (SHORT)DriverState.MickeysPerCellHoriz) / 8;
|
||||
DriverState.VertCount += (DeltaY * (SHORT)DriverState.MickeysPerCellVert ) / 8;
|
||||
|
||||
if (DriverState.ShowCount > 0)
|
||||
{
|
||||
EraseMouseCursor();
|
||||
DriverState.Position = *NewPosition;
|
||||
PaintMouseCursor();
|
||||
}
|
||||
|
||||
/* Call the mouse handlers */
|
||||
CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
|
||||
}
|
||||
|
||||
VOID MouseBiosUpdateButtons(WORD ButtonState)
|
||||
{
|
||||
USHORT i;
|
||||
USHORT CallMask = 0x0000; // We use MS MOUSE v1.0+ format
|
||||
|
||||
if (!DriverEnabled) return;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
BOOLEAN MouseBios32Initialize(VOID)
|
||||
{
|
||||
/* Clear the state */
|
||||
ZeroMemory(&DriverState, sizeof(DriverState));
|
||||
|
||||
/* Initialize the interrupt handler */
|
||||
RegisterBiosInt32(BIOS_MOUSE_INTERRUPT, BiosMouseService);
|
||||
/* Set up the HW vector interrupts */
|
||||
EnableHwIRQ(12, BiosMouseIrq);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID MouseBios32Cleanup(VOID)
|
||||
{
|
||||
if (DriverState.ShowCount > 0) EraseMouseCursor();
|
||||
}
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
|
||||
/* Processor speed */
|
||||
#define STEPS_PER_CYCLE 256
|
||||
#define KBD_INT_CYCLES 16
|
||||
#define IRQ1_CYCLES 16
|
||||
#define IRQ12_CYCLES 16
|
||||
|
||||
/* VARIABLES ******************************************************************/
|
||||
|
||||
|
@ -48,7 +49,9 @@ LONGLONG TimerTicks;
|
|||
DWORD StartTickCount, CurrentTickCount;
|
||||
DWORD LastClockUpdate;
|
||||
DWORD LastVerticalRefresh;
|
||||
INT KeyboardIntCounter = 0;
|
||||
|
||||
UINT Irq1Counter = 0;
|
||||
UINT Irq12Counter = 0;
|
||||
|
||||
#ifdef IPS_DISPLAY
|
||||
DWORD LastCyclePrintout;
|
||||
|
@ -118,10 +121,16 @@ VOID ClockUpdate(VOID)
|
|||
LastVerticalRefresh = CurrentTickCount;
|
||||
}
|
||||
|
||||
if (++KeyboardIntCounter == KBD_INT_CYCLES)
|
||||
if (++Irq1Counter == IRQ1_CYCLES)
|
||||
{
|
||||
GenerateKeyboardInterrupts();
|
||||
KeyboardIntCounter = 0;
|
||||
GenerateIrq1();
|
||||
Irq1Counter = 0;
|
||||
}
|
||||
|
||||
if (++Irq12Counter == IRQ12_CYCLES)
|
||||
{
|
||||
GenerateIrq12();
|
||||
Irq12Counter = 0;
|
||||
}
|
||||
|
||||
/* Horizontal retrace occurs as fast as possible */
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "bop.h"
|
||||
|
||||
#include "bios/bios.h"
|
||||
#include "mouse32.h"
|
||||
|
||||
/* Extra PSDK/NDK Headers */
|
||||
#include <ndk/obtypes.h>
|
||||
|
@ -234,6 +235,7 @@ BOOLEAN DosInitialize(IN LPCSTR DosKernelFileName)
|
|||
BOOLEAN Result;
|
||||
|
||||
Result = DosBIOSInitialize();
|
||||
DosMouseInitialize(); // FIXME: Should be done by the DOS BIOS
|
||||
// Result &= DosKRNLInitialize();
|
||||
|
||||
return Result;
|
||||
|
|
671
reactos/subsystems/ntvdm/dos/mouse32.c
Normal file
671
reactos/subsystems/ntvdm/dos/mouse32.c
Normal file
|
@ -0,0 +1,671 @@
|
|||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: mouse32.c
|
||||
* PURPOSE: VDM 32-bit compatible MOUSE.COM driver
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "callback.h"
|
||||
|
||||
#include "mouse32.h"
|
||||
#include "bios/bios.h"
|
||||
|
||||
#include "io.h"
|
||||
#include "dos32krnl/dos.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
static BOOLEAN DriverEnabled = TRUE;
|
||||
static MOUSE_DRIVER_STATE DriverState;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static VOID PaintMouseCursor(VOID)
|
||||
{
|
||||
if (Bda->VideoMode <= 3)
|
||||
{
|
||||
WORD Character;
|
||||
DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize);
|
||||
|
||||
EmulatorReadMemory(&EmulatorContext,
|
||||
VideoAddress
|
||||
+ (DriverState.Position.Y * Bda->ScreenColumns
|
||||
+ DriverState.Position.X) * sizeof(WORD),
|
||||
(LPVOID)&Character,
|
||||
sizeof(WORD));
|
||||
|
||||
DriverState.Character = Character;
|
||||
Character &= DriverState.TextCursor.ScreenMask;
|
||||
Character ^= DriverState.TextCursor.CursorMask;
|
||||
|
||||
EmulatorWriteMemory(&EmulatorContext,
|
||||
VideoAddress
|
||||
+ (DriverState.Position.Y * Bda->ScreenColumns
|
||||
+ DriverState.Position.X) * sizeof(WORD),
|
||||
(LPVOID)&Character,
|
||||
sizeof(WORD));
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
static VOID EraseMouseCursor(VOID)
|
||||
{
|
||||
if (Bda->VideoMode <= 3)
|
||||
{
|
||||
DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize);
|
||||
|
||||
EmulatorWriteMemory(&EmulatorContext,
|
||||
VideoAddress
|
||||
+ (DriverState.Position.Y * Bda->ScreenColumns
|
||||
+ DriverState.Position.X) * sizeof(WORD),
|
||||
(LPVOID)&DriverState.Character,
|
||||
sizeof(WORD));
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
static VOID CallMouseUserHandlers(USHORT CallMask)
|
||||
{
|
||||
#if 0
|
||||
USHORT i;
|
||||
USHORT AX, BX, CX, DX, SI, DI;
|
||||
|
||||
/* Call handler 0 */
|
||||
if ((DriverState.Handler0.CallMask & CallMask) != 0 &&
|
||||
DriverState.Handler0.Callback != (ULONG)NULL)
|
||||
{
|
||||
/*
|
||||
* 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();
|
||||
SI = getSI();
|
||||
DI = getDI();
|
||||
|
||||
setAX(CallMask);
|
||||
setBX(DriverState.ButtonState);
|
||||
setCX(DriverState.Position.X);
|
||||
setDX(DriverState.Position.Y);
|
||||
setSI(DriverState.MickeysPerCellHoriz);
|
||||
setDI(DriverState.MickeysPerCellVert);
|
||||
|
||||
DPRINT1("Calling Handler0 0x%08x with CallMask 0x%04x\n",
|
||||
DriverState.Handler0.Callback, CallMask);
|
||||
|
||||
/* Call the callback */
|
||||
RunCallback16(&DosContext, DriverState.Handler0.Callback);
|
||||
|
||||
setAX(AX);
|
||||
setBX(BX);
|
||||
setCX(CX);
|
||||
setDX(DX);
|
||||
setSI(SI);
|
||||
setDI(DI);
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
|
||||
{
|
||||
/* Call the suitable handlers */
|
||||
if ((DriverState.Handlers[i].CallMask & CallMask) != 0 &&
|
||||
DriverState.Handlers[i].Callback != (ULONG)NULL)
|
||||
{
|
||||
/*
|
||||
* 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();
|
||||
SI = getSI();
|
||||
DI = getDI();
|
||||
|
||||
setAX(CallMask);
|
||||
setBX(DriverState.ButtonState);
|
||||
setCX(DriverState.Position.X);
|
||||
setDX(DriverState.Position.Y);
|
||||
setSI(DriverState.MickeysPerCellHoriz);
|
||||
setDI(DriverState.MickeysPerCellVert);
|
||||
|
||||
DPRINT1("Calling Handler[%d] 0x%08x with CallMask 0x%04x\n",
|
||||
i, DriverState.Handlers[i].Callback, CallMask);
|
||||
|
||||
/* Call the callback */
|
||||
RunCallback16(&DosContext, DriverState.Handlers[i].Callback);
|
||||
|
||||
setAX(AX);
|
||||
setBX(BX);
|
||||
setCX(CX);
|
||||
setDX(DX);
|
||||
setSI(SI);
|
||||
setDI(DI);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static VOID WINAPI BiosMouseService(LPWORD Stack)
|
||||
{
|
||||
switch (getAX())
|
||||
{
|
||||
/* Reset Driver */
|
||||
case 0x00:
|
||||
{
|
||||
SHORT i;
|
||||
|
||||
DriverEnabled = TRUE;
|
||||
DriverState.ShowCount = 0;
|
||||
DriverState.ButtonState = 0;
|
||||
|
||||
/* 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;
|
||||
|
||||
DriverState.GraphicsCursor.ScreenMask[0] = 0xC3FF; // 1100001111111111
|
||||
DriverState.GraphicsCursor.ScreenMask[1] = 0xC0FF; // 1100000011111111
|
||||
DriverState.GraphicsCursor.ScreenMask[2] = 0xC07F; // 1100000001111111
|
||||
DriverState.GraphicsCursor.ScreenMask[3] = 0xC01F; // 1100000000011111
|
||||
DriverState.GraphicsCursor.ScreenMask[4] = 0xC00F; // 1100000000001111
|
||||
DriverState.GraphicsCursor.ScreenMask[5] = 0xC007; // 1100000000000111
|
||||
DriverState.GraphicsCursor.ScreenMask[6] = 0xC003; // 1100000000000011
|
||||
DriverState.GraphicsCursor.ScreenMask[7] = 0xC007; // 1100000000000111
|
||||
DriverState.GraphicsCursor.ScreenMask[8] = 0xC01F; // 1100000000011111
|
||||
DriverState.GraphicsCursor.ScreenMask[9] = 0xC01F; // 1100000000011111
|
||||
DriverState.GraphicsCursor.ScreenMask[10] = 0xC00F; // 1100000000001111
|
||||
DriverState.GraphicsCursor.ScreenMask[11] = 0xC60F; // 1100011000001111
|
||||
DriverState.GraphicsCursor.ScreenMask[12] = 0xFF07; // 1111111100000111
|
||||
DriverState.GraphicsCursor.ScreenMask[13] = 0xFF07; // 1111111100000111
|
||||
DriverState.GraphicsCursor.ScreenMask[14] = 0xFF87; // 1111111110000111
|
||||
DriverState.GraphicsCursor.ScreenMask[15] = 0xFFCF; // 1111111111001111
|
||||
|
||||
DriverState.GraphicsCursor.CursorMask[0] = 0x0000; // 0000000000000000
|
||||
DriverState.GraphicsCursor.CursorMask[1] = 0x1C00; // 0001110000000000
|
||||
DriverState.GraphicsCursor.CursorMask[2] = 0x1F00; // 0001111100000000
|
||||
DriverState.GraphicsCursor.CursorMask[3] = 0x1F80; // 0001111110000000
|
||||
DriverState.GraphicsCursor.CursorMask[4] = 0x1FE0; // 0001111111100000
|
||||
DriverState.GraphicsCursor.CursorMask[5] = 0x1FF0; // 0001111111110000
|
||||
DriverState.GraphicsCursor.CursorMask[6] = 0x1FF8; // 0001111111111000
|
||||
DriverState.GraphicsCursor.CursorMask[7] = 0x1FE0; // 0001111111100000
|
||||
DriverState.GraphicsCursor.CursorMask[8] = 0x1FC0; // 0001111111000000
|
||||
DriverState.GraphicsCursor.CursorMask[9] = 0x1FC0; // 0001111111000000
|
||||
DriverState.GraphicsCursor.CursorMask[10] = 0x19E0; // 0001100111100000
|
||||
DriverState.GraphicsCursor.CursorMask[11] = 0x00E0; // 0000000011100000
|
||||
DriverState.GraphicsCursor.CursorMask[12] = 0x0070; // 0000000001110000
|
||||
DriverState.GraphicsCursor.CursorMask[13] = 0x0070; // 0000000001110000
|
||||
DriverState.GraphicsCursor.CursorMask[14] = 0x0030; // 0000000000110000
|
||||
DriverState.GraphicsCursor.CursorMask[15] = 0x0000; // 0000000000000000
|
||||
|
||||
/* Initialize the counters */
|
||||
DriverState.HorizCount = DriverState.VertCount = 0;
|
||||
|
||||
for (i = 0; i < NUM_MOUSE_BUTTONS; i++)
|
||||
{
|
||||
DriverState.PressCount[i] = DriverState.ReleaseCount[i] = 0;
|
||||
}
|
||||
|
||||
/* Initialize the resolution */
|
||||
DriverState.MickeysPerCellHoriz = 8;
|
||||
DriverState.MickeysPerCellVert = 16;
|
||||
|
||||
/* Return mouse information */
|
||||
setAX(0xFFFF); // Hardware & driver installed
|
||||
setBX(NUM_MOUSE_BUTTONS);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Show Mouse Cursor */
|
||||
case 0x01:
|
||||
{
|
||||
DriverState.ShowCount++;
|
||||
if (DriverState.ShowCount > 0) PaintMouseCursor();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Hide Mouse Cursor */
|
||||
case 0x02:
|
||||
{
|
||||
DriverState.ShowCount--;
|
||||
if (DriverState.ShowCount <= 0) EraseMouseCursor();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return Position And Button Status */
|
||||
case 0x03:
|
||||
{
|
||||
setBX(DriverState.ButtonState);
|
||||
setCX(DriverState.Position.X);
|
||||
setDX(DriverState.Position.Y);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Position Mouse Cursor */
|
||||
case 0x04:
|
||||
{
|
||||
POINT Point;
|
||||
|
||||
Point.x = getCX();
|
||||
Point.y = getDX();
|
||||
|
||||
ClientToScreen(GetConsoleWindow(), &Point);
|
||||
SetCursorPos(Point.x, Point.y);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return Button Press Data */
|
||||
case 0x05:
|
||||
{
|
||||
WORD Button = getBX();
|
||||
|
||||
setAX(DriverState.ButtonState);
|
||||
setBX(DriverState.PressCount[Button]);
|
||||
setCX(DriverState.LastPress[Button].X);
|
||||
setDX(DriverState.LastPress[Button].Y);
|
||||
|
||||
/* Reset the counter */
|
||||
DriverState.PressCount[Button] = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return Button Release Data */
|
||||
case 0x06:
|
||||
{
|
||||
WORD Button = getBX();
|
||||
|
||||
setAX(DriverState.ButtonState);
|
||||
setBX(DriverState.ReleaseCount[Button]);
|
||||
setCX(DriverState.LastRelease[Button].X);
|
||||
setDX(DriverState.LastRelease[Button].Y);
|
||||
|
||||
/* Reset the counter */
|
||||
DriverState.ReleaseCount[Button] = 0;
|
||||
|
||||
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();
|
||||
|
||||
RtlMoveMemory(DriverState.GraphicsCursor.ScreenMask,
|
||||
MaskBitmap,
|
||||
sizeof(DriverState.GraphicsCursor.ScreenMask));
|
||||
|
||||
RtlMoveMemory(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, 0x%08x\n",
|
||||
DriverState.Handler0.CallMask, DriverState.Handler0.Callback);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Define Mickey/Pixel Ratio */
|
||||
case 0x0F:
|
||||
{
|
||||
DriverState.MickeysPerCellHoriz = getCX();
|
||||
DriverState.MickeysPerCellVert = getDX();
|
||||
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
|
||||
|
||||
/* 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:
|
||||
{
|
||||
*((PMOUSE_DRIVER_STATE)SEG_OFF_TO_PTR(getES(), getDX())) = DriverState;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Restore Driver State */
|
||||
case 0x17:
|
||||
{
|
||||
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, 0x%08x\n",
|
||||
CallMask, Callback);
|
||||
|
||||
if (CallMask == 0x0000)
|
||||
{
|
||||
/*
|
||||
* Find the handler entry corresponding to the given
|
||||
* callback and undefine it.
|
||||
*/
|
||||
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
|
||||
{
|
||||
if (DriverState.Handlers[i].Callback == Callback)
|
||||
{
|
||||
/* Found it, undefine the handler */
|
||||
DriverState.Handlers[i].CallMask = 0x0000;
|
||||
DriverState.Handlers[i].Callback = (ULONG)NULL;
|
||||
Success = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Callback == (ULONG)NULL)
|
||||
{
|
||||
/*
|
||||
* Find the handler entry corresponding to the given
|
||||
* callmask and undefine it.
|
||||
*/
|
||||
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
|
||||
{
|
||||
if (DriverState.Handlers[i].CallMask == CallMask)
|
||||
{
|
||||
/* Found it, undefine the handler */
|
||||
DriverState.Handlers[i].CallMask = 0x0000;
|
||||
DriverState.Handlers[i].Callback = (ULONG)NULL;
|
||||
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 < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
|
||||
{
|
||||
/* Find the first empty handler */
|
||||
if (EmptyHandler == 0xFFFF &&
|
||||
DriverState.Handlers[i].CallMask == 0x0000 &&
|
||||
DriverState.Handlers[i].Callback == (ULONG)NULL)
|
||||
{
|
||||
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 < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]) */)
|
||||
{
|
||||
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 < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++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;
|
||||
}
|
||||
|
||||
/* Disable Mouse Driver */
|
||||
case 0x1F:
|
||||
{
|
||||
setES(0x0000);
|
||||
setBX(0x0000);
|
||||
|
||||
DriverEnabled = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable Mouse Driver */
|
||||
case 0x20:
|
||||
{
|
||||
DriverEnabled = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
DPRINT1("BIOS Function INT 33h, AX = 0x%04X NOT IMPLEMENTED\n", getAX());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID MouseBiosUpdatePosition(PCOORD NewPosition)
|
||||
{
|
||||
SHORT DeltaX = NewPosition->X - DriverState.Position.X;
|
||||
SHORT DeltaY = NewPosition->Y - DriverState.Position.Y;
|
||||
|
||||
if (!DriverEnabled) return;
|
||||
|
||||
DriverState.HorizCount += (DeltaX * (SHORT)DriverState.MickeysPerCellHoriz) / 8;
|
||||
DriverState.VertCount += (DeltaY * (SHORT)DriverState.MickeysPerCellVert ) / 8;
|
||||
|
||||
if (DriverState.ShowCount > 0)
|
||||
{
|
||||
EraseMouseCursor();
|
||||
DriverState.Position = *NewPosition;
|
||||
PaintMouseCursor();
|
||||
}
|
||||
|
||||
/* Call the mouse handlers */
|
||||
CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
|
||||
}
|
||||
|
||||
VOID MouseBiosUpdateButtons(WORD ButtonState)
|
||||
{
|
||||
USHORT i;
|
||||
USHORT CallMask = 0x0000; // We use MS MOUSE v1.0+ format
|
||||
|
||||
if (!DriverEnabled) return;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
BOOLEAN DosMouseInitialize(VOID)
|
||||
{
|
||||
/* Clear the state */
|
||||
ZeroMemory(&DriverState, sizeof(DriverState));
|
||||
|
||||
/* Initialize the interrupt handler */
|
||||
RegisterDosInt32(BIOS_MOUSE_INTERRUPT, BiosMouseService);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID DosMouseCleanup(VOID)
|
||||
{
|
||||
if (DriverState.ShowCount > 0) EraseMouseCursor();
|
||||
}
|
83
reactos/subsystems/ntvdm/dos/mouse32.h
Normal file
83
reactos/subsystems/ntvdm/dos/mouse32.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: mouse32.h
|
||||
* PURPOSE: VDM 32-bit compatible MOUSE.COM driver
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
#ifndef _MOUSE32_H_
|
||||
#define _MOUSE32_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define BIOS_MOUSE_INTERRUPT 0x33
|
||||
|
||||
enum
|
||||
{
|
||||
MOUSE_BUTTON_LEFT,
|
||||
MOUSE_BUTTON_RIGHT,
|
||||
MOUSE_BUTTON_MIDDLE,
|
||||
NUM_MOUSE_BUTTONS
|
||||
};
|
||||
|
||||
typedef struct _MOUSE_USER_HANDLER
|
||||
{
|
||||
/*
|
||||
* CallMask format: see table: http://www.ctyme.com/intr/rb-5968.htm#Table3171
|
||||
* Alternatively, see table: http://www.ctyme.com/intr/rb-5981.htm#Table3174
|
||||
*/
|
||||
USHORT CallMask;
|
||||
ULONG Callback; // Far pointer to the callback
|
||||
} MOUSE_USER_HANDLER, *PMOUSE_USER_HANDLER;
|
||||
|
||||
typedef struct _MOUSE_DRIVER_STATE
|
||||
{
|
||||
SHORT ShowCount;
|
||||
COORD Position;
|
||||
WORD Character;
|
||||
WORD ButtonState;
|
||||
WORD PressCount[NUM_MOUSE_BUTTONS];
|
||||
COORD LastPress[NUM_MOUSE_BUTTONS];
|
||||
WORD ReleaseCount[NUM_MOUSE_BUTTONS];
|
||||
COORD LastRelease[NUM_MOUSE_BUTTONS];
|
||||
SHORT HorizCount;
|
||||
SHORT VertCount;
|
||||
WORD MickeysPerCellHoriz;
|
||||
WORD MickeysPerCellVert;
|
||||
|
||||
/*
|
||||
* User Subroutine Handlers called on mouse events
|
||||
*/
|
||||
MOUSE_USER_HANDLER Handler0; // Handler compatible MS MOUSE v1.0+
|
||||
MOUSE_USER_HANDLER Handlers[3]; // Handlers compatible MS MOUSE v6.0+
|
||||
|
||||
struct
|
||||
{
|
||||
WORD ScreenMask;
|
||||
WORD CursorMask;
|
||||
} TextCursor;
|
||||
|
||||
struct
|
||||
{
|
||||
COORD HotSpot;
|
||||
WORD ScreenMask[16];
|
||||
WORD CursorMask[16];
|
||||
} GraphicsCursor;
|
||||
} MOUSE_DRIVER_STATE, *PMOUSE_DRIVER_STATE;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID MouseBiosUpdatePosition(PCOORD NewPosition);
|
||||
VOID MouseBiosUpdateButtons(WORD ButtonStatus);
|
||||
|
||||
BOOLEAN DosMouseInitialize(VOID);
|
||||
VOID DosMouseCleanup(VOID);
|
||||
|
||||
#endif // _MOUSE32_H_
|
||||
|
||||
/* EOF */
|
|
@ -16,6 +16,8 @@
|
|||
#include "clock.h"
|
||||
#include "bios/rom.h"
|
||||
#include "hardware/cmos.h"
|
||||
#include "hardware/keyboard.h"
|
||||
#include "hardware/mouse.h"
|
||||
#include "hardware/pic.h"
|
||||
#include "hardware/ps2.h"
|
||||
#include "hardware/speaker.h"
|
||||
|
@ -335,6 +337,95 @@ static VOID WINAPI PitChan2Out(LPVOID Param, BOOLEAN State)
|
|||
// SpeakerChange();
|
||||
}
|
||||
|
||||
|
||||
static DWORD
|
||||
WINAPI
|
||||
PumpConsoleInput(LPVOID Parameter)
|
||||
{
|
||||
HANDLE ConsoleInput = (HANDLE)Parameter;
|
||||
INPUT_RECORD InputRecord;
|
||||
DWORD Count;
|
||||
|
||||
while (VdmRunning)
|
||||
{
|
||||
/* Make sure the task event is signaled */
|
||||
WaitForSingleObject(VdmTaskEvent, INFINITE);
|
||||
|
||||
/* Wait for an input record */
|
||||
if (!ReadConsoleInput(ConsoleInput, &InputRecord, 1, &Count))
|
||||
{
|
||||
DWORD LastError = GetLastError();
|
||||
DPRINT1("Error reading console input (0x%p, %lu) - Error %lu\n", ConsoleInput, Count, LastError);
|
||||
return LastError;
|
||||
}
|
||||
|
||||
ASSERT(Count != 0);
|
||||
|
||||
/* Check the event type */
|
||||
switch (InputRecord.EventType)
|
||||
{
|
||||
/*
|
||||
* Hardware events
|
||||
*/
|
||||
case KEY_EVENT:
|
||||
KeyboardEventHandler(&InputRecord.Event.KeyEvent);
|
||||
break;
|
||||
|
||||
case MOUSE_EVENT:
|
||||
MouseEventHandler(&InputRecord.Event.MouseEvent);
|
||||
break;
|
||||
|
||||
case WINDOW_BUFFER_SIZE_EVENT:
|
||||
ScreenEventHandler(&InputRecord.Event.WindowBufferSizeEvent);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Interface events
|
||||
*/
|
||||
case MENU_EVENT:
|
||||
MenuEventHandler(&InputRecord.Event.MenuEvent);
|
||||
break;
|
||||
|
||||
case FOCUS_EVENT:
|
||||
FocusEventHandler(&InputRecord.Event.FocusEvent);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static VOID EnableExtraHardware(HANDLE ConsoleInput)
|
||||
{
|
||||
DWORD ConInMode;
|
||||
|
||||
if (GetConsoleMode(ConsoleInput, &ConInMode))
|
||||
{
|
||||
#if 0
|
||||
// GetNumberOfConsoleMouseButtons();
|
||||
// GetSystemMetrics(SM_CMOUSEBUTTONS);
|
||||
// GetSystemMetrics(SM_MOUSEPRESENT);
|
||||
if (MousePresent)
|
||||
{
|
||||
#endif
|
||||
/* Support mouse input events if there is a mouse on the system */
|
||||
ConInMode |= ENABLE_MOUSE_INPUT;
|
||||
#if 0
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Do not support mouse input events if there is no mouse on the system */
|
||||
ConInMode &= ~ENABLE_MOUSE_INPUT;
|
||||
}
|
||||
#endif
|
||||
|
||||
SetConsoleMode(ConsoleInput, ConInMode);
|
||||
}
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID DumpMemory(VOID)
|
||||
|
@ -421,8 +512,6 @@ VOID DumpMemory(VOID)
|
|||
DPRINT1("Memory dump done\n");
|
||||
}
|
||||
|
||||
DWORD WINAPI PumpConsoleInput(LPVOID Parameter);
|
||||
|
||||
BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
|
||||
{
|
||||
/* Allocate memory for the 16-bit address space */
|
||||
|
@ -476,8 +565,14 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
|
|||
SetConsoleMode(ConsoleInput, ENABLE_PROCESSED_INPUT /* | ENABLE_WINDOW_INPUT */);
|
||||
// SetConsoleMode(ConsoleOutput, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
|
||||
|
||||
/* Initialize the PS2 port */
|
||||
PS2Initialize(ConsoleInput);
|
||||
/**/EnableExtraHardware(ConsoleInput);/**/
|
||||
|
||||
/* Initialize the PS/2 port */
|
||||
PS2Initialize();
|
||||
|
||||
/* Initialize the keyboard and mouse and connect them to their PS/2 ports */
|
||||
KeyboardInit(0);
|
||||
MouseInit(1);
|
||||
|
||||
/**************** ATTACH INPUT WITH CONSOLE *****************/
|
||||
/* Start the input thread */
|
||||
|
|
46
reactos/subsystems/ntvdm/hardware/keyboard.c
Normal file
46
reactos/subsystems/ntvdm/hardware/keyboard.c
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: keyboard.c
|
||||
* PURPOSE: Keyboard emulation
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "keyboard.h"
|
||||
#include "ps2.h"
|
||||
|
||||
static BYTE PS2Port = 0;
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID KeyboardEventHandler(PKEY_EVENT_RECORD KeyEvent)
|
||||
{
|
||||
WORD i;
|
||||
BYTE ScanCode = (BYTE)KeyEvent->wVirtualScanCode;
|
||||
|
||||
/* If this is a key release, set the highest bit in the scan code */
|
||||
if (!KeyEvent->bKeyDown) ScanCode |= 0x80;
|
||||
|
||||
/* Push the scan code into the PS/2 queue */
|
||||
for (i = 0; i < KeyEvent->wRepeatCount; i++)
|
||||
{
|
||||
PS2QueuePush(PS2Port, ScanCode);
|
||||
}
|
||||
|
||||
// PicInterruptRequest(1);
|
||||
}
|
||||
|
||||
VOID KeyboardCommand(BYTE Command)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
BOOLEAN KeyboardInit(BYTE PS2Connector)
|
||||
{
|
||||
PS2Port = PS2Connector;
|
||||
return TRUE;
|
||||
}
|
28
reactos/subsystems/ntvdm/hardware/keyboard.h
Normal file
28
reactos/subsystems/ntvdm/hardware/keyboard.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: keyboard.h
|
||||
* PURPOSE: Keyboard emulation
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
#ifndef _KEYBOARD_H_
|
||||
#define _KEYBOARD_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
/* Command responses */
|
||||
#define KEYBOARD_ACK 0xFA
|
||||
#define KEYBOARD_RESEND 0xFE
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID KeyboardEventHandler(PKEY_EVENT_RECORD KeyEvent);
|
||||
VOID KeyboardCommand(BYTE Command);
|
||||
BOOLEAN KeyboardInit(BYTE PS2Connector);
|
||||
|
||||
#endif // _KEYBOARD_H_
|
|
@ -13,6 +13,9 @@
|
|||
#include "mouse.h"
|
||||
#include "ps2.h"
|
||||
|
||||
// HACK: For the PS/2 bypass and MOUSE.COM driver direct call
|
||||
#include "dos/mouse32.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
static MOUSE_MODE Mode, PreviousMode;
|
||||
|
@ -28,6 +31,8 @@ static SHORT HorzCounter;
|
|||
static SHORT VertCounter;
|
||||
static CHAR ScrollCounter;
|
||||
|
||||
static BYTE PS2Port = 1;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static VOID MouseResetConfig(VOID)
|
||||
|
@ -56,8 +61,8 @@ static VOID MouseReset(VOID)
|
|||
MouseId = 0;
|
||||
|
||||
/* Send the Basic Assurance Test success code and the device ID */
|
||||
KeyboardQueuePush(MOUSE_BAT_SUCCESS);
|
||||
KeyboardQueuePush(MouseId);
|
||||
PS2QueuePush(PS2Port, MOUSE_BAT_SUCCESS);
|
||||
PS2QueuePush(PS2Port, MouseId);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -116,9 +121,7 @@ static VOID MouseGetPacket(PMOUSE_PACKET Packet)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID MouseUpdatePosition(PCOORD NewPosition)
|
||||
/*static*/ VOID MouseUpdatePosition(PCOORD NewPosition)
|
||||
{
|
||||
/* Update the counters */
|
||||
HorzCounter += ((NewPosition->X - Position.X) * WidthMm * Resolution) / WidthPixels;
|
||||
|
@ -128,11 +131,25 @@ VOID MouseUpdatePosition(PCOORD NewPosition)
|
|||
Position = *NewPosition;
|
||||
}
|
||||
|
||||
VOID MouseUpdateButtons(ULONG NewButtonState)
|
||||
/*static*/ VOID MouseUpdateButtons(ULONG NewButtonState)
|
||||
{
|
||||
ButtonState = NewButtonState;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID MouseEventHandler(PMOUSE_EVENT_RECORD MouseEvent)
|
||||
{
|
||||
// FIXME: Sync our private data
|
||||
|
||||
// HACK: Bypass PS/2 and instead, notify the MOUSE.COM driver directly
|
||||
MouseBiosUpdatePosition(&MouseEvent->dwMousePosition);
|
||||
MouseBiosUpdateButtons(LOWORD(MouseEvent->dwButtonState));
|
||||
|
||||
// PS2QueuePush(PS2Port, Data);
|
||||
// PicInterruptRequest(12);
|
||||
}
|
||||
|
||||
VOID MouseScroll(LONG Direction)
|
||||
{
|
||||
ScrollCounter += Direction;
|
||||
|
@ -151,7 +168,7 @@ VOID MouseCommand(BYTE Command)
|
|||
case 0xE6:
|
||||
{
|
||||
Scaling = FALSE;
|
||||
KeyboardQueuePush(MOUSE_ACK);
|
||||
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -159,7 +176,7 @@ VOID MouseCommand(BYTE Command)
|
|||
case 0xE7:
|
||||
{
|
||||
Scaling = TRUE;
|
||||
KeyboardQueuePush(MOUSE_ACK);
|
||||
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -185,7 +202,7 @@ VOID MouseCommand(BYTE Command)
|
|||
MouseResetCounters();
|
||||
Mode = MOUSE_STREAMING_MODE;
|
||||
|
||||
KeyboardQueuePush(MOUSE_ACK);
|
||||
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -205,9 +222,9 @@ VOID MouseCommand(BYTE Command)
|
|||
/* Restore the previous mode */
|
||||
MouseResetCounters();
|
||||
Mode = PreviousMode;
|
||||
KeyboardQueuePush(MOUSE_ACK);
|
||||
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||
}
|
||||
else KeyboardQueuePush(MOUSE_ERROR);
|
||||
else PS2QueuePush(PS2Port, MOUSE_ERROR);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -224,7 +241,7 @@ VOID MouseCommand(BYTE Command)
|
|||
MouseResetCounters();
|
||||
Mode = MOUSE_WRAP_MODE;
|
||||
|
||||
KeyboardQueuePush(MOUSE_ACK);
|
||||
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -234,15 +251,15 @@ VOID MouseCommand(BYTE Command)
|
|||
MouseResetCounters();
|
||||
Mode = MOUSE_REMOTE_MODE;
|
||||
|
||||
KeyboardQueuePush(MOUSE_ACK);
|
||||
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get Mouse ID */
|
||||
case 0xF2:
|
||||
{
|
||||
KeyboardQueuePush(MOUSE_ACK);
|
||||
KeyboardQueuePush(MouseId);
|
||||
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||
PS2QueuePush(PS2Port, MouseId);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -258,7 +275,7 @@ VOID MouseCommand(BYTE Command)
|
|||
case 0xF4:
|
||||
{
|
||||
Reporting = TRUE;
|
||||
KeyboardQueuePush(MOUSE_ACK);
|
||||
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -266,7 +283,7 @@ VOID MouseCommand(BYTE Command)
|
|||
case 0xF5:
|
||||
{
|
||||
Reporting = FALSE;
|
||||
KeyboardQueuePush(MOUSE_ACK);
|
||||
PS2QueuePush(PS2Port, MOUSE_ACK);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -297,12 +314,12 @@ VOID MouseCommand(BYTE Command)
|
|||
/* Unknown command */
|
||||
default:
|
||||
{
|
||||
KeyboardQueuePush(MOUSE_ERROR);
|
||||
PS2QueuePush(PS2Port, MOUSE_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN MouseInit(VOID)
|
||||
BOOLEAN MouseInit(BYTE PS2Connector)
|
||||
{
|
||||
HWND hWnd;
|
||||
HDC hDC;
|
||||
|
@ -324,6 +341,8 @@ BOOLEAN MouseInit(VOID)
|
|||
/* Release the device context */
|
||||
ReleaseDC(hWnd, hDC);
|
||||
|
||||
PS2Port = PS2Connector;
|
||||
|
||||
MouseReset();
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -68,11 +68,12 @@ typedef struct _MOUSE_PACKET
|
|||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID MouseUpdatePosition(PCOORD NewPosition);
|
||||
VOID MouseUpdateButtons(ULONG NewButtonState);
|
||||
VOID MouseEventHandler(PMOUSE_EVENT_RECORD MouseEvent);
|
||||
|
||||
VOID MouseScroll(LONG Direction);
|
||||
COORD MouseGetPosition(VOID);
|
||||
|
||||
VOID MouseCommand(BYTE Command);
|
||||
BOOLEAN MouseInit(VOID);
|
||||
BOOLEAN MouseInit(BYTE PS2Connector);
|
||||
|
||||
#endif // _MOUSE_H_
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* FILE: ps2.c
|
||||
* PURPOSE: PS/2 controller emulation
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
@ -14,19 +15,39 @@
|
|||
#include "io.h"
|
||||
#include "ps2.h"
|
||||
#include "pic.h"
|
||||
|
||||
#include "keyboard.h"
|
||||
#include "mouse.h"
|
||||
#include "../bios/bios32/moubios32.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
static BYTE KeyboardQueue[KEYBOARD_BUFFER_SIZE];
|
||||
static BOOLEAN KeyboardQueueEmpty = TRUE;
|
||||
static UINT KeyboardQueueStart = 0;
|
||||
static UINT KeyboardQueueEnd = 0;
|
||||
static BYTE KeyboardData = 0, KeyboardResponse = 0;
|
||||
static BOOLEAN KeyboardReadResponse = FALSE, KeyboardWriteResponse = FALSE;
|
||||
static BYTE KeyboardConfig = PS2_DEFAULT_CONFIG;
|
||||
static HANDLE QueueMutex = NULL;
|
||||
#define BUFFER_SIZE 32
|
||||
|
||||
typedef struct _PS2_PORT
|
||||
{
|
||||
BOOLEAN IsEnabled;
|
||||
|
||||
BOOLEAN QueueEmpty;
|
||||
BYTE Queue[BUFFER_SIZE];
|
||||
UINT QueueStart;
|
||||
UINT QueueEnd;
|
||||
HANDLE QueueMutex;
|
||||
} PS2_PORT, *PPS2_PORT;
|
||||
|
||||
/*
|
||||
* Port 1: Keyboard
|
||||
* Port 2: Mouse
|
||||
*/
|
||||
#define PS2_PORTS 2
|
||||
static PS2_PORT Ports[PS2_PORTS];
|
||||
|
||||
#define PS2_DEFAULT_CONFIG 0x47
|
||||
static BYTE ControllerConfig = PS2_DEFAULT_CONFIG;
|
||||
static BYTE ControllerCommand = 0x00;
|
||||
|
||||
static BYTE StatusRegister = 0x00;
|
||||
// static BYTE InputBuffer = 0x00; // PS/2 Input Buffer
|
||||
static BYTE OutputBuffer = 0x00; // PS/2 Output Buffer
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
|
@ -34,31 +55,28 @@ static BYTE WINAPI PS2ReadPort(ULONG Port)
|
|||
{
|
||||
if (Port == PS2_CONTROL_PORT)
|
||||
{
|
||||
BYTE Status = 0;
|
||||
/* Be sure bit 2 is always set */
|
||||
StatusRegister |= 1 << 2;
|
||||
|
||||
/* Set the first bit if the data can be read */
|
||||
if (KeyboardReadResponse || !KeyboardQueueEmpty) Status |= 1 << 0;
|
||||
// FIXME: Should clear bits 6 and 7 because there are
|
||||
// no timeouts and no parity errors.
|
||||
|
||||
/* Always set bit 2 */
|
||||
Status |= 1 << 2;
|
||||
|
||||
/* Set bit 3 if the next byte goes to the controller */
|
||||
if (KeyboardWriteResponse) Status |= 1 << 3;
|
||||
|
||||
return Status;
|
||||
return StatusRegister;
|
||||
}
|
||||
else if (Port == PS2_DATA_PORT)
|
||||
{
|
||||
/* If there was a response byte from the controller, return it */
|
||||
if (KeyboardReadResponse)
|
||||
{
|
||||
KeyboardReadResponse = FALSE;
|
||||
KeyboardData = KeyboardResponse;
|
||||
}
|
||||
/*
|
||||
* If there is something to read (response byte from the
|
||||
* controller or data from a PS/2 device), read it.
|
||||
*/
|
||||
if (StatusRegister & (1 << 0)) // || StatusRegister & (1 << 5) for second PS/2 port
|
||||
StatusRegister &= ~(1 << 0); // StatusRegister &= ~(1 << 5);
|
||||
|
||||
return KeyboardData;
|
||||
/* Always return the available byte stored in the output buffer */
|
||||
return OutputBuffer;
|
||||
}
|
||||
else return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static VOID WINAPI PS2WritePort(ULONG Port, BYTE Data)
|
||||
|
@ -70,8 +88,8 @@ static VOID WINAPI PS2WritePort(ULONG Port, BYTE Data)
|
|||
/* Read configuration byte */
|
||||
case 0x20:
|
||||
{
|
||||
KeyboardResponse = KeyboardConfig;
|
||||
KeyboardReadResponse = TRUE;
|
||||
OutputBuffer = ControllerConfig;
|
||||
StatusRegister |= (1 << 0); // There is something to read
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -79,60 +97,68 @@ static VOID WINAPI PS2WritePort(ULONG Port, BYTE Data)
|
|||
case 0x60:
|
||||
/* Write controller output port */
|
||||
case 0xD1:
|
||||
/* Write keyboard output buffer */
|
||||
/* Write to the first PS/2 port output buffer */
|
||||
case 0xD2:
|
||||
/* Write mouse output buffer */
|
||||
/* Write to the second PS/2 port output buffer */
|
||||
case 0xD3:
|
||||
/* Write mouse input buffer */
|
||||
/* Write to the second PS/2 port input buffer */
|
||||
case 0xD4:
|
||||
{
|
||||
/* These commands require a response */
|
||||
KeyboardResponse = Data;
|
||||
KeyboardWriteResponse = TRUE;
|
||||
ControllerCommand = Data;
|
||||
StatusRegister |= (1 << 3); // This is a controller command
|
||||
break;
|
||||
}
|
||||
|
||||
/* Disable mouse */
|
||||
/* Disable second PS/2 port */
|
||||
case 0xA7:
|
||||
{
|
||||
// TODO: Not implemented
|
||||
Ports[1].IsEnabled = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable mouse */
|
||||
/* Enable second PS/2 port */
|
||||
case 0xA8:
|
||||
{
|
||||
// TODO: Not implemented
|
||||
Ports[1].IsEnabled = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Test mouse port */
|
||||
/* Test second PS/2 port */
|
||||
case 0xA9:
|
||||
{
|
||||
KeyboardResponse = 0;
|
||||
KeyboardReadResponse = TRUE;
|
||||
OutputBuffer = 0x00; // Success code
|
||||
StatusRegister |= (1 << 0); // There is something to read
|
||||
break;
|
||||
}
|
||||
|
||||
/* Test PS/2 controller */
|
||||
case 0xAA:
|
||||
{
|
||||
KeyboardResponse = 0x55;
|
||||
KeyboardReadResponse = TRUE;
|
||||
OutputBuffer = 0x55; // Success code
|
||||
StatusRegister |= (1 << 0); // There is something to read
|
||||
break;
|
||||
}
|
||||
|
||||
/* Disable keyboard */
|
||||
/* Test first PS/2 port */
|
||||
case 0xAB:
|
||||
{
|
||||
OutputBuffer = 0x00; // Success code
|
||||
StatusRegister |= (1 << 0); // There is something to read
|
||||
break;
|
||||
}
|
||||
|
||||
/* Disable first PS/2 port */
|
||||
case 0xAD:
|
||||
{
|
||||
// TODO: Not implemented
|
||||
Ports[0].IsEnabled = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable keyboard */
|
||||
/* Enable first PS/2 port */
|
||||
case 0xAE:
|
||||
{
|
||||
// TODO: Not implemented
|
||||
Ports[0].IsEnabled = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -162,17 +188,17 @@ static VOID WINAPI PS2WritePort(ULONG Port, BYTE Data)
|
|||
else if (Port == PS2_DATA_PORT)
|
||||
{
|
||||
/* Check if the controller is waiting for a response */
|
||||
if (KeyboardWriteResponse)
|
||||
if (StatusRegister & (1 << 3)) // If we have data for the controller
|
||||
{
|
||||
KeyboardWriteResponse = FALSE;
|
||||
StatusRegister &= ~(1 << 3);
|
||||
|
||||
/* Check which command it was */
|
||||
switch (KeyboardResponse)
|
||||
switch (ControllerCommand)
|
||||
{
|
||||
/* Write configuration byte */
|
||||
case 0x60:
|
||||
{
|
||||
KeyboardConfig = Data;
|
||||
ControllerConfig = Data;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -191,23 +217,31 @@ static VOID WINAPI PS2WritePort(ULONG Port, BYTE Data)
|
|||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Push the data byte into the first PS/2 port queue */
|
||||
case 0xD2:
|
||||
{
|
||||
/* Push the data byte to the keyboard queue */
|
||||
KeyboardQueuePush(Data);
|
||||
PS2QueuePush(0, Data);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Push the data byte into the second PS/2 port queue */
|
||||
case 0xD3:
|
||||
{
|
||||
// TODO: Mouse support
|
||||
PS2QueuePush(1, Data);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a command to the second PS/2 port (by default
|
||||
* it is a command for the first PS/2 port)
|
||||
*/
|
||||
case 0xD4:
|
||||
{
|
||||
MouseCommand(Data);
|
||||
if (Ports[1].IsEnabled)
|
||||
// Ports[1].Function
|
||||
MouseCommand(Data);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -216,156 +250,148 @@ static VOID WINAPI PS2WritePort(ULONG Port, BYTE Data)
|
|||
}
|
||||
|
||||
// TODO: Implement PS/2 device commands
|
||||
if (Ports[0].IsEnabled)
|
||||
// Ports[0].Function
|
||||
KeyboardCommand(Data);
|
||||
}
|
||||
}
|
||||
|
||||
static BOOLEAN PS2PortQueueRead(BYTE PS2Port)
|
||||
{
|
||||
BOOLEAN Result = TRUE;
|
||||
PPS2_PORT Port;
|
||||
|
||||
if (PS2Port >= PS2_PORTS) return FALSE;
|
||||
Port = &Ports[PS2Port];
|
||||
|
||||
if (!Port->IsEnabled) return FALSE;
|
||||
|
||||
/* Make sure the queue is not empty (fast check) */
|
||||
if (Port->QueueEmpty) return FALSE;
|
||||
|
||||
WaitForSingleObject(Port->QueueMutex, INFINITE);
|
||||
|
||||
/*
|
||||
* Recheck whether the queue is not empty (it may
|
||||
* have changed after having grabbed the mutex).
|
||||
*/
|
||||
if (Port->QueueEmpty)
|
||||
{
|
||||
Result = FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
/* Get the data */
|
||||
OutputBuffer = Port->Queue[Port->QueueStart];
|
||||
StatusRegister |= (1 << 0); // There is something to read
|
||||
// Sometimes StatusRegister |= (1 << 5); for the second PS/2 port
|
||||
|
||||
/* Remove the value from the queue */
|
||||
Port->QueueStart++;
|
||||
Port->QueueStart %= BUFFER_SIZE;
|
||||
|
||||
/* Check if the queue is now empty */
|
||||
if (Port->QueueStart == Port->QueueEnd)
|
||||
Port->QueueEmpty = TRUE;
|
||||
|
||||
Done:
|
||||
ReleaseMutex(Port->QueueMutex);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
BOOLEAN KeyboardQueuePush(BYTE ScanCode)
|
||||
// PS2SendToPort
|
||||
BOOLEAN PS2QueuePush(BYTE PS2Port, BYTE Data)
|
||||
{
|
||||
BOOLEAN Result = TRUE;
|
||||
PPS2_PORT Port;
|
||||
|
||||
WaitForSingleObject(QueueMutex, INFINITE);
|
||||
if (PS2Port >= PS2_PORTS) return FALSE;
|
||||
Port = &Ports[PS2Port];
|
||||
|
||||
/* Check if the keyboard queue is full */
|
||||
if (!KeyboardQueueEmpty && (KeyboardQueueStart == KeyboardQueueEnd))
|
||||
if (!Port->IsEnabled) return FALSE;
|
||||
|
||||
WaitForSingleObject(Port->QueueMutex, INFINITE);
|
||||
|
||||
/* Check if the queue is full */
|
||||
if (!Port->QueueEmpty && (Port->QueueStart == Port->QueueEnd))
|
||||
{
|
||||
Result = FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
/* Insert the value in the queue */
|
||||
KeyboardQueue[KeyboardQueueEnd] = ScanCode;
|
||||
KeyboardQueueEnd++;
|
||||
KeyboardQueueEnd %= KEYBOARD_BUFFER_SIZE;
|
||||
Port->Queue[Port->QueueEnd] = Data;
|
||||
Port->QueueEnd++;
|
||||
Port->QueueEnd %= BUFFER_SIZE;
|
||||
|
||||
/* Since we inserted a value, it's not empty anymore */
|
||||
KeyboardQueueEmpty = FALSE;
|
||||
Port->QueueEmpty = FALSE;
|
||||
|
||||
/*
|
||||
// Get the data
|
||||
OutputBuffer = Port->Queue[Port->QueueStart];
|
||||
StatusRegister |= (1 << 0); // There is something to read
|
||||
// FIXME: Sometimes StatusRegister |= (1 << 5); for the second PS/2 port
|
||||
|
||||
if (PS2Port == 0)
|
||||
PicInterruptRequest(1);
|
||||
else if (PS2Port == 1)
|
||||
PicInterruptRequest(12);
|
||||
*/
|
||||
|
||||
Done:
|
||||
ReleaseMutex(QueueMutex);
|
||||
ReleaseMutex(Port->QueueMutex);
|
||||
return Result;
|
||||
}
|
||||
|
||||
BOOLEAN KeyboardQueuePop(BYTE *ScanCode)
|
||||
VOID GenerateIrq1(VOID)
|
||||
{
|
||||
BOOLEAN Result = TRUE;
|
||||
|
||||
/* Make sure the keyboard queue is not empty (fast check) */
|
||||
if (KeyboardQueueEmpty) return FALSE;
|
||||
|
||||
WaitForSingleObject(QueueMutex, INFINITE);
|
||||
|
||||
/*
|
||||
* Recheck whether keyboard queue is not empty (it
|
||||
* may have changed after having grabbed the mutex).
|
||||
*/
|
||||
if (KeyboardQueueEmpty)
|
||||
/* Generate an interrupt if interrupts for the first PS/2 port are enabled */
|
||||
if (ControllerConfig & 0x01)
|
||||
{
|
||||
Result = FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
/* Get the scan code */
|
||||
*ScanCode = KeyboardQueue[KeyboardQueueStart];
|
||||
|
||||
/* Remove the value from the queue */
|
||||
KeyboardQueueStart++;
|
||||
KeyboardQueueStart %= KEYBOARD_BUFFER_SIZE;
|
||||
|
||||
/* Check if the queue is now empty */
|
||||
if (KeyboardQueueStart == KeyboardQueueEnd)
|
||||
{
|
||||
KeyboardQueueEmpty = TRUE;
|
||||
}
|
||||
|
||||
Done:
|
||||
ReleaseMutex(QueueMutex);
|
||||
return Result;
|
||||
}
|
||||
|
||||
VOID PS2Dispatch(PINPUT_RECORD InputRecord)
|
||||
{
|
||||
/* Check the event type */
|
||||
switch (InputRecord->EventType)
|
||||
{
|
||||
case KEY_EVENT:
|
||||
{
|
||||
WORD i;
|
||||
BYTE ScanCode = (BYTE)InputRecord->Event.KeyEvent.wVirtualScanCode;
|
||||
|
||||
/* If this is a key release, set the highest bit in the scan code */
|
||||
if (!InputRecord->Event.KeyEvent.bKeyDown) ScanCode |= 0x80;
|
||||
|
||||
/* Push the scan code onto the keyboard queue */
|
||||
for (i = 0; i < InputRecord->Event.KeyEvent.wRepeatCount; i++)
|
||||
{
|
||||
KeyboardQueuePush(ScanCode);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MOUSE_EVENT:
|
||||
{
|
||||
/* Notify the BIOS driver */
|
||||
MouseBiosUpdatePosition(&InputRecord->Event.MouseEvent.dwMousePosition);
|
||||
MouseBiosUpdateButtons(LOWORD(InputRecord->Event.MouseEvent.dwButtonState));
|
||||
|
||||
// TODO: PS/2, other stuff
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* We ignore all the rest */
|
||||
default:
|
||||
break;
|
||||
/* Generate an IRQ 1 if there is data ready in the output queue */
|
||||
if (PS2PortQueueRead(0)) PicInterruptRequest(1);
|
||||
}
|
||||
}
|
||||
|
||||
VOID GenerateKeyboardInterrupts(VOID)
|
||||
VOID GenerateIrq12(VOID)
|
||||
{
|
||||
/* Generate an IRQ 1 if there is a key ready in the queue */
|
||||
if (KeyboardQueuePop(&KeyboardData)) PicInterruptRequest(1);
|
||||
/* 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(HANDLE ConsoleInput)
|
||||
BOOLEAN PS2Initialize(VOID)
|
||||
{
|
||||
DWORD ConInMode;
|
||||
/* Initialize the PS/2 ports */
|
||||
Ports[0].IsEnabled = TRUE;
|
||||
Ports[0].QueueEmpty = TRUE;
|
||||
Ports[0].QueueStart = 0;
|
||||
Ports[0].QueueEnd = 0;
|
||||
Ports[0].QueueMutex = CreateMutex(NULL, FALSE, NULL);
|
||||
|
||||
/* Create the mutex */
|
||||
QueueMutex = CreateMutex(NULL, FALSE, NULL);
|
||||
Ports[1].IsEnabled = TRUE;
|
||||
Ports[1].QueueEmpty = TRUE;
|
||||
Ports[1].QueueStart = 0;
|
||||
Ports[1].QueueEnd = 0;
|
||||
Ports[1].QueueMutex = CreateMutex(NULL, FALSE, NULL);
|
||||
|
||||
/* Register the I/O Ports */
|
||||
RegisterIoPort(PS2_CONTROL_PORT, PS2ReadPort, PS2WritePort);
|
||||
RegisterIoPort(PS2_DATA_PORT , PS2ReadPort, PS2WritePort);
|
||||
|
||||
if (GetConsoleMode(ConsoleInput, &ConInMode))
|
||||
{
|
||||
#if 0
|
||||
if (MousePresent)
|
||||
{
|
||||
#endif
|
||||
/* Support mouse input events if there is a mouse on the system */
|
||||
ConInMode |= ENABLE_MOUSE_INPUT;
|
||||
#if 0
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Do not support mouse input events if there is no mouse on the system */
|
||||
ConInMode &= ~ENABLE_MOUSE_INPUT;
|
||||
}
|
||||
#endif
|
||||
|
||||
SetConsoleMode(ConsoleInput, ConInMode);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID PS2Cleanup(VOID)
|
||||
{
|
||||
CloseHandle(QueueMutex);
|
||||
CloseHandle(Ports[1].QueueMutex);
|
||||
CloseHandle(Ports[0].QueueMutex);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* FILE: ps2.h
|
||||
* PURPOSE: PS/2 controller emulation
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
||||
*/
|
||||
|
||||
#ifndef _PS2_H_
|
||||
|
@ -15,21 +16,17 @@
|
|||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define KEYBOARD_BUFFER_SIZE 32
|
||||
#define PS2_DATA_PORT 0x60
|
||||
#define PS2_CONTROL_PORT 0x64
|
||||
#define PS2_DEFAULT_CONFIG 0x05
|
||||
#define KEYBOARD_ACK 0xFA
|
||||
#define KEYBOARD_RESEND 0xFE
|
||||
#define PS2_DATA_PORT 0x60
|
||||
#define PS2_CONTROL_PORT 0x64
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
BOOLEAN KeyboardQueuePush(BYTE ScanCode);
|
||||
BOOLEAN KeyboardQueuePop(BYTE *ScanCode);
|
||||
VOID PS2Dispatch(PINPUT_RECORD InputRecord);
|
||||
VOID GenerateKeyboardInterrupts(VOID);
|
||||
BOOLEAN PS2QueuePush(BYTE PS2Port, BYTE Data);
|
||||
|
||||
BOOLEAN PS2Initialize(HANDLE ConsoleInput);
|
||||
VOID GenerateIrq1(VOID);
|
||||
VOID GenerateIrq12(VOID);
|
||||
|
||||
BOOLEAN PS2Initialize(VOID);
|
||||
VOID PS2Cleanup(VOID);
|
||||
|
||||
#endif // _PS2_H_
|
||||
|
|
|
@ -1917,6 +1917,11 @@ VOID VgaResetPalette(VOID)
|
|||
|
||||
|
||||
|
||||
VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent)
|
||||
{
|
||||
DPRINT1("Screen events not handled\n");
|
||||
}
|
||||
|
||||
BOOL VgaAttachToConsole(VOID)
|
||||
{
|
||||
//
|
||||
|
|
|
@ -250,6 +250,7 @@ typedef struct _VGA_REGISTERS
|
|||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent);
|
||||
BOOL VgaAttachToConsole(VOID);
|
||||
VOID VgaDetachFromConsole(BOOL ChangeMode);
|
||||
|
||||
|
|
|
@ -328,69 +328,32 @@ ConsoleCleanup(VOID)
|
|||
if (ConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleInput);
|
||||
}
|
||||
|
||||
DWORD
|
||||
WINAPI
|
||||
PumpConsoleInput(LPVOID Parameter)
|
||||
VOID MenuEventHandler(PMENU_EVENT_RECORD MenuEvent)
|
||||
{
|
||||
HANDLE ConsoleInput = (HANDLE)Parameter;
|
||||
INPUT_RECORD InputRecord;
|
||||
DWORD Count;
|
||||
|
||||
while (VdmRunning)
|
||||
switch (MenuEvent->dwCommandId)
|
||||
{
|
||||
/* Make sure the task event is signaled */
|
||||
WaitForSingleObject(VdmTaskEvent, INFINITE);
|
||||
case ID_SHOWHIDE_MOUSE:
|
||||
ShowHideMousePointer(ConsoleOutput, ShowPointer);
|
||||
ShowPointer = !ShowPointer;
|
||||
break;
|
||||
|
||||
/* Wait for an input record */
|
||||
if (!ReadConsoleInput(ConsoleInput, &InputRecord, 1, &Count))
|
||||
{
|
||||
DWORD LastError = GetLastError();
|
||||
DPRINT1("Error reading console input (0x%p, %lu) - Error %lu\n", ConsoleInput, Count, LastError);
|
||||
return LastError;
|
||||
}
|
||||
case ID_VDM_DUMPMEM:
|
||||
DumpMemory();
|
||||
break;
|
||||
|
||||
ASSERT(Count != 0);
|
||||
case ID_VDM_QUIT:
|
||||
/* Stop the VDM */
|
||||
EmulatorTerminate();
|
||||
break;
|
||||
|
||||
/* Check the event type */
|
||||
switch (InputRecord.EventType)
|
||||
{
|
||||
case KEY_EVENT:
|
||||
case MOUSE_EVENT:
|
||||
/* Send it to the PS/2 controller */
|
||||
PS2Dispatch(&InputRecord);
|
||||
break;
|
||||
|
||||
case MENU_EVENT:
|
||||
{
|
||||
switch (InputRecord.Event.MenuEvent.dwCommandId)
|
||||
{
|
||||
case ID_SHOWHIDE_MOUSE:
|
||||
ShowHideMousePointer(ConsoleOutput, ShowPointer);
|
||||
ShowPointer = !ShowPointer;
|
||||
break;
|
||||
|
||||
case ID_VDM_DUMPMEM:
|
||||
DumpMemory();
|
||||
break;
|
||||
|
||||
case ID_VDM_QUIT:
|
||||
/* Stop the VDM */
|
||||
EmulatorTerminate();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
VOID FocusEventHandler(PFOCUS_EVENT_RECORD FocusEvent)
|
||||
{
|
||||
DPRINT1("Focus events not handled\n");
|
||||
}
|
||||
|
||||
#ifndef STANDALONE
|
||||
|
|
|
@ -46,6 +46,9 @@ extern ULONG SessionId;
|
|||
|
||||
extern HANDLE VdmTaskEvent;
|
||||
|
||||
/*
|
||||
* Interface functions
|
||||
*/
|
||||
VOID DisplayMessage(LPCWSTR Format, ...);
|
||||
|
||||
/*static*/ VOID
|
||||
|
@ -53,6 +56,9 @@ CreateVdmMenu(HANDLE ConOutHandle);
|
|||
/*static*/ VOID
|
||||
DestroyVdmMenu(VOID);
|
||||
|
||||
VOID MenuEventHandler(PMENU_EVENT_RECORD MenuEvent);
|
||||
VOID FocusEventHandler(PFOCUS_EVENT_RECORD FocusEvent);
|
||||
|
||||
#endif // _NTVDM_H_
|
||||
|
||||
/* EOF */
|
||||
|
|
Loading…
Reference in a new issue