[NTVDM]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Tue, 16 Sep 2014 00:51:15 +0000 (00:51 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Tue, 16 Sep 2014 00:51:15 +0000 (00:51 +0000)
- 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

17 files changed:
reactos/subsystems/ntvdm/CMakeLists.txt
reactos/subsystems/ntvdm/bios/bios32/moubios32.c
reactos/subsystems/ntvdm/clock.c
reactos/subsystems/ntvdm/dos/dem.c
reactos/subsystems/ntvdm/dos/mouse32.c [new file with mode: 0644]
reactos/subsystems/ntvdm/dos/mouse32.h [new file with mode: 0644]
reactos/subsystems/ntvdm/emulator.c
reactos/subsystems/ntvdm/hardware/keyboard.c [new file with mode: 0644]
reactos/subsystems/ntvdm/hardware/keyboard.h [new file with mode: 0644]
reactos/subsystems/ntvdm/hardware/mouse.c
reactos/subsystems/ntvdm/hardware/mouse.h
reactos/subsystems/ntvdm/hardware/ps2.c
reactos/subsystems/ntvdm/hardware/ps2.h
reactos/subsystems/ntvdm/hardware/vga.c
reactos/subsystems/ntvdm/hardware/vga.h
reactos/subsystems/ntvdm/ntvdm.c
reactos/subsystems/ntvdm/ntvdm.h

index 43ac966..92b03b4 100644 (file)
@@ -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
index 5df683e..720182c 100644 (file)
 
 /* 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)
-{
-    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)
+// Mouse IRQ 12
+static VOID WINAPI BiosMouseIrq(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();
 }
index 74e1fe4..c283d32 100644 (file)
@@ -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)
+    {
+        GenerateIrq1();
+        Irq1Counter = 0;
+    }
+
+    if (++Irq12Counter == IRQ12_CYCLES)
     {
-        GenerateKeyboardInterrupts();
-        KeyboardIntCounter = 0;
+        GenerateIrq12();
+        Irq12Counter = 0;
     }
 
     /* Horizontal retrace occurs as fast as possible */
index 6f060c4..b751e4b 100644 (file)
@@ -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;
diff --git a/reactos/subsystems/ntvdm/dos/mouse32.c b/reactos/subsystems/ntvdm/dos/mouse32.c
new file mode 100644 (file)
index 0000000..62ab8fa
--- /dev/null
@@ -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();
+}
diff --git a/reactos/subsystems/ntvdm/dos/mouse32.h b/reactos/subsystems/ntvdm/dos/mouse32.h
new file mode 100644 (file)
index 0000000..1bbf31a
--- /dev/null
@@ -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 */
index 78168a7..42b5f19 100644 (file)
@@ -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 */
diff --git a/reactos/subsystems/ntvdm/hardware/keyboard.c b/reactos/subsystems/ntvdm/hardware/keyboard.c
new file mode 100644 (file)
index 0000000..d5669ce
--- /dev/null
@@ -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;
+}
diff --git a/reactos/subsystems/ntvdm/hardware/keyboard.h b/reactos/subsystems/ntvdm/hardware/keyboard.h
new file mode 100644 (file)
index 0000000..bbbe9be
--- /dev/null
@@ -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_
index 65727d1..9956afb 100644 (file)
@@ -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;
 }
index 49136dc..d3ad0b9 100644 (file)
@@ -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_
index 0937ffc..c78453b 100644 (file)
@@ -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 *******************************************************************/
 #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;
-
-        /* Set the first bit if the data can be read */
-        if (KeyboardReadResponse || !KeyboardQueueEmpty) Status |= 1 << 0;
+        /* Be sure bit 2 is always set */
+        StatusRegister |= 1 << 2;
 
-        /* Always set bit 2 */
-        Status |= 1 << 2;
+        // FIXME: Should clear bits 6 and 7 because there are
+        // no timeouts and no parity errors.
 
-        /* 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;
-        }
-
-        return KeyboardData;
+        /*
+         * 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);
+
+        /* 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);
     }
 }
 
-/* PUBLIC FUNCTIONS ***********************************************************/
-
-BOOLEAN KeyboardQueuePush(BYTE ScanCode)
+static BOOLEAN PS2PortQueueRead(BYTE PS2Port)
 {
     BOOLEAN Result = TRUE;
+    PPS2_PORT Port;
+
+    if (PS2Port >= PS2_PORTS) return FALSE;
+    Port = &Ports[PS2Port];
 
-    WaitForSingleObject(QueueMutex, INFINITE);
+    if (!Port->IsEnabled) return FALSE;
 
-    /* Check if the keyboard queue is full */
-    if (!KeyboardQueueEmpty && (KeyboardQueueStart == KeyboardQueueEnd))
+    /* 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;
     }
 
-    /* Insert the value in the queue */
-    KeyboardQueue[KeyboardQueueEnd] = ScanCode;
-    KeyboardQueueEnd++;
-    KeyboardQueueEnd %= KEYBOARD_BUFFER_SIZE;
+    /* 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
 
-    /* Since we inserted a value, it's not empty anymore */
-    KeyboardQueueEmpty = FALSE;
+    /* 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(QueueMutex);
+    ReleaseMutex(Port->QueueMutex);
     return Result;
 }
 
-BOOLEAN KeyboardQueuePop(BYTE *ScanCode)
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+// PS2SendToPort
+BOOLEAN PS2QueuePush(BYTE PS2Port, BYTE Data)
 {
     BOOLEAN Result = TRUE;
+    PPS2_PORT Port;
 
-    /* Make sure the keyboard queue is not empty (fast check) */
-    if (KeyboardQueueEmpty) return FALSE;
+    if (PS2Port >= PS2_PORTS) return FALSE;
+    Port = &Ports[PS2Port];
 
-    WaitForSingleObject(QueueMutex, INFINITE);
+    if (!Port->IsEnabled) return FALSE;
 
-    /*
-     * Recheck whether keyboard queue is not empty (it
-     * may have changed after having grabbed the mutex).
-     */
-    if (KeyboardQueueEmpty)
+    WaitForSingleObject(Port->QueueMutex, INFINITE);
+
+    /* Check if the queue is full */
+    if (!Port->QueueEmpty && (Port->QueueStart == Port->QueueEnd))
     {
         Result = FALSE;
         goto Done;
     }
 
-    /* Get the scan code */
-    *ScanCode = KeyboardQueue[KeyboardQueueStart];
+    /* Insert the value in the queue */
+    Port->Queue[Port->QueueEnd] = Data;
+    Port->QueueEnd++;
+    Port->QueueEnd %= BUFFER_SIZE;
 
-    /* Remove the value from the queue */
-    KeyboardQueueStart++;
-    KeyboardQueueStart %= KEYBOARD_BUFFER_SIZE;
+    /* Since we inserted a value, it's not empty anymore */
+    Port->QueueEmpty = FALSE;
 
-    /* Check if the queue is now empty */
-    if (KeyboardQueueStart == KeyboardQueueEnd)
-    {
-        KeyboardQueueEmpty = TRUE;
-    }
+/*
+    // 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;
 }
 
-VOID PS2Dispatch(PINPUT_RECORD InputRecord)
+VOID GenerateIrq1(VOID)
 {
-    /* Check the event type */
-    switch (InputRecord->EventType)
+    /* Generate an interrupt if interrupts for the first PS/2 port are enabled */
+    if (ControllerConfig & 0x01)
     {
-        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;
-
-    /* Create the mutex */
-    QueueMutex = CreateMutex(NULL, FALSE, NULL);
+    /* 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);
+
+    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 */
index e0eca52..2bf21f2 100644 (file)
@@ -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_
 
 /* 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_
index af9c0e0..3dc376d 100644 (file)
@@ -1917,6 +1917,11 @@ VOID VgaResetPalette(VOID)
 
 
 
+VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent)
+{
+    DPRINT1("Screen events not handled\n");
+}
+
 BOOL VgaAttachToConsole(VOID)
 {
     //
index ca6de8d..51ecb04 100644 (file)
@@ -250,6 +250,7 @@ typedef struct _VGA_REGISTERS
 
 /* FUNCTIONS ******************************************************************/
 
+VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent);
 BOOL VgaAttachToConsole(VOID);
 VOID VgaDetachFromConsole(BOOL ChangeMode);
 
index 9fd9d4a..42ed45b 100644 (file)
@@ -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);
-
-        /* 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)
-        {
-            case KEY_EVENT:
-            case MOUSE_EVENT:
-                /* Send it to the PS/2 controller */
-                PS2Dispatch(&InputRecord);
-                break;
+        case ID_SHOWHIDE_MOUSE:
+            ShowHideMousePointer(ConsoleOutput, ShowPointer);
+            ShowPointer = !ShowPointer;
+            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;
-                }
+        case ID_VDM_DUMPMEM:
+            DumpMemory();
+            break;
 
-                break;
-            }
+        case ID_VDM_QUIT:
+            /* Stop the VDM */
+            EmulatorTerminate();
+            break;
 
-            default:
-                break;
-        }
+        default:
+            break;
     }
+}
 
-    return 0;
+VOID FocusEventHandler(PFOCUS_EVENT_RECORD FocusEvent)
+{
+    DPRINT1("Focus events not handled\n");
 }
 
 #ifndef STANDALONE
index 0a4ecc1..68ca34c 100644 (file)
@@ -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 */