[NTVDM]
[reactos.git] / reactos / subsystems / mvdm / ntvdm / dos / mouse32.c
index 212e5ee..d2f2a31 100644 (file)
 
 #define NDEBUG
 
+#include "ntvdm.h"
 #include "emulator.h"
+
 #include "cpu/cpu.h"
 #include "int32.h"
+#include "hardware/mouse.h"
+#include "hardware/ps2.h"
+#include "hardware/pic.h"
+#include "hardware/video/vga.h"
 
 #include "mouse32.h"
 #include "bios/bios.h"
+#include "bios/bios32/bios32p.h"
 
 #include "io.h"
 #include "dos32krnl/dos.h"
 
 /* PRIVATE VARIABLES **********************************************************/
 
-static BOOLEAN DriverEnabled = TRUE;
-static MOUSE_DRIVER_STATE DriverState;
+// FIXME: Because I don't know a better place to store the string
+// I temporarily put it in BIOS space. This need to be moved to a
+// proper place when this driver is interfaced correctly with DOS.
+#define COPYRIGHT_POINTER MAKELONG(0xE100, 0xF000)
+static const CHAR MouseCopyright[] = "ROS PS/2 16/32-bit Mouse Driver Compatible MS-MOUSE 6.26 Copyright (C) ReactOS Team 1996-2015";
+
+// See FIXME from above.
+#define VERSION_POINTER MAKELONG(0xE160, 0xF000)
+static PWORD Version;
 
-/**/
-COORD DosNewPosition;
-WORD  DosButtonState;
-/**/
+#define MICKEYS_PER_CELL_HORIZ  8
+#define MICKEYS_PER_CELL_VERT   16
+
+static BOOLEAN DriverEnabled = FALSE;
+static MOUSE_DRIVER_STATE DriverState;
+static DWORD OldIrqHandler;
+static DWORD OldIntHandler;
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
 static VOID PaintMouseCursor(VOID)
 {
+    COORD Position = DriverState.Position;
+
+    /* Apply the clipping rectangle */
+    if (Position.X < DriverState.MinX) Position.X = DriverState.MinX;
+    if (Position.X > DriverState.MaxX) Position.X = DriverState.MaxX;
+    if (Position.Y < DriverState.MinY) Position.Y = DriverState.MinY;
+    if (Position.Y > DriverState.MaxY) Position.Y = DriverState.MaxY;
+
     if (Bda->VideoMode <= 3)
     {
         WORD Character;
+        WORD CellX = Position.X / 8;
+        WORD CellY = Position.Y / 8;
         DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize);
 
         EmulatorReadMemory(&EmulatorContext,
                            VideoAddress
-                           + (DriverState.Position.Y * Bda->ScreenColumns
-                           + DriverState.Position.X) * sizeof(WORD),
+                           + (CellY * Bda->ScreenColumns + CellX) * sizeof(WORD),
                            (LPVOID)&Character,
                            sizeof(WORD));
 
@@ -52,8 +78,7 @@ static VOID PaintMouseCursor(VOID)
 
         EmulatorWriteMemory(&EmulatorContext,
                             VideoAddress
-                            + (DriverState.Position.Y * Bda->ScreenColumns
-                            + DriverState.Position.X) * sizeof(WORD),
+                            + (CellY * Bda->ScreenColumns + CellX) * sizeof(WORD),
                             (LPVOID)&Character,
                             sizeof(WORD));
     }
@@ -66,14 +91,23 @@ static VOID PaintMouseCursor(VOID)
 
 static VOID EraseMouseCursor(VOID)
 {
+    COORD Position = DriverState.Position;
+
+    /* Apply the clipping rectangle */
+    if (Position.X < DriverState.MinX) Position.X = DriverState.MinX;
+    if (Position.X > DriverState.MaxX) Position.X = DriverState.MaxX;
+    if (Position.Y < DriverState.MinY) Position.Y = DriverState.MinY;
+    if (Position.Y > DriverState.MaxY) Position.Y = DriverState.MaxY;
+
     if (Bda->VideoMode <= 3)
     {
+        WORD CellX = Position.X / 8;
+        WORD CellY = Position.Y / 8;
         DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize);
 
         EmulatorWriteMemory(&EmulatorContext,
                             VideoAddress
-                            + (DriverState.Position.Y * Bda->ScreenColumns
-                            + DriverState.Position.X) * sizeof(WORD),
+                            + (CellY * Bda->ScreenColumns + CellX) * sizeof(WORD),
                             (LPVOID)&DriverState.Character,
                             sizeof(WORD));
     }
@@ -84,10 +118,45 @@ static VOID EraseMouseCursor(VOID)
     }
 }
 
+static VOID ToMouseCoordinates(PCOORD Position)
+{
+    COORD Resolution = VgaGetDisplayResolution();
+    WORD Width = DriverState.MaxX - DriverState.MinX + 1;
+    WORD Height = DriverState.MaxY - DriverState.MinY + 1;
+
+    if (!VgaGetDoubleVisionState(NULL, NULL))
+    {
+        Resolution.X *= 8;
+        Resolution.Y *= 8;
+    }
+
+    Position->X = DriverState.MinX + ((Position->X * Width) / Resolution.X);
+    Position->Y = DriverState.MinY + ((Position->Y * Height) / Resolution.Y);
+}
+
+static VOID FromMouseCoordinates(PCOORD Position)
+{
+    COORD Resolution = VgaGetDisplayResolution();
+    WORD Width = DriverState.MaxX - DriverState.MinX + 1;
+    WORD Height = DriverState.MaxY - DriverState.MinY + 1;
+
+    if (!VgaGetDoubleVisionState(NULL, NULL))
+    {
+        Resolution.X *= 8;
+        Resolution.Y *= 8;
+    }
+
+    Position->X = ((Position->X - DriverState.MinX) * Resolution.X) / Width;
+    Position->Y = ((Position->Y - DriverState.MinY) * Resolution.Y) / Height;
+}
+
 static VOID CallMouseUserHandlers(USHORT CallMask)
 {
     USHORT i;
     USHORT AX, BX, CX, DX, SI, DI;
+    COORD Position = DriverState.Position;
+
+    ToMouseCoordinates(&Position);
 
     /* Call handler 0 */
     if ((DriverState.Handler0.CallMask & CallMask) != 0 &&
@@ -108,10 +177,10 @@ static VOID CallMouseUserHandlers(USHORT CallMask)
 
         setAX(CallMask);
         setBX(DriverState.ButtonState);
-        setCX(DriverState.Position.X);
-        setDX(DriverState.Position.Y);
-        setSI(DriverState.MickeysPerCellHoriz);
-        setDI(DriverState.MickeysPerCellVert);
+        setCX(Position.X);
+        setDX(Position.Y);
+        setSI(MICKEYS_PER_CELL_HORIZ);
+        setDI(MICKEYS_PER_CELL_VERT);
 
         DPRINT("Calling Handler0 %04X:%04X with CallMask 0x%04X\n",
                HIWORD(DriverState.Handler0.Callback),
@@ -129,7 +198,7 @@ static VOID CallMouseUserHandlers(USHORT CallMask)
         setDI(DI);
     }
 
-    for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
+    for (i = 0; i < ARRAYSIZE(DriverState.Handlers); ++i)
     {
         /* Call the suitable handlers */
         if ((DriverState.Handlers[i].CallMask & CallMask) != 0 &&
@@ -150,10 +219,10 @@ static VOID CallMouseUserHandlers(USHORT CallMask)
 
             setAX(CallMask);
             setBX(DriverState.ButtonState);
-            setCX(DriverState.Position.X);
-            setDX(DriverState.Position.Y);
-            setSI(DriverState.MickeysPerCellHoriz);
-            setDI(DriverState.MickeysPerCellVert);
+            setCX(Position.X);
+            setDX(Position.Y);
+            setSI(MICKEYS_PER_CELL_HORIZ);
+            setDI(MICKEYS_PER_CELL_VERT);
 
             DPRINT1("Calling Handler[%d] %04X:%04X with CallMask 0x%04X\n",
                     i,
@@ -174,6 +243,95 @@ static VOID CallMouseUserHandlers(USHORT CallMask)
     }
 }
 
+static inline VOID DosUpdatePosition(PCOORD NewPosition)
+{
+    COORD Resolution = VgaGetDisplayResolution();
+
+    /* Check for text mode */
+    if (!VgaGetDoubleVisionState(NULL, NULL))
+    {
+        Resolution.X *= 8;
+        Resolution.Y *= 8;
+    }
+
+    if (DriverState.ShowCount > 0) EraseMouseCursor();
+    DriverState.Position = *NewPosition;
+    if (DriverState.ShowCount > 0) PaintMouseCursor();
+
+    /* Call the mouse handlers */
+    CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
+}
+
+static inline VOID DosUpdateButtons(BYTE ButtonState)
+{
+    USHORT i;
+    USHORT CallMask = 0x0000; // We use MS MOUSE v1.0+ format
+
+    for (i = 0; i < NUM_MOUSE_BUTTONS; i++)
+    {
+        BOOLEAN OldState = (DriverState.ButtonState >> i) & 1;
+        BOOLEAN NewState = (ButtonState >> i) & 1;
+
+        if (NewState > OldState)
+        {
+            /* Mouse press */
+            DriverState.PressCount[i]++;
+            DriverState.LastPress[i] = DriverState.Position;
+
+            CallMask |= (1 << (2 * i + 1));
+        }
+        else if (NewState < OldState)
+        {
+            /* Mouse release */
+            DriverState.ReleaseCount[i]++;
+            DriverState.LastRelease[i] = DriverState.Position;
+
+            CallMask |= (1 << (2 * i + 2));
+        }
+    }
+
+    DriverState.ButtonState = ButtonState;
+
+    /* Call the mouse handlers */
+    CallMouseUserHandlers(CallMask);
+}
+
+static VOID WINAPI DosMouseIrq(LPWORD Stack)
+{
+    BYTE Flags;
+    SHORT DeltaX, DeltaY;
+    COORD Position;
+    BYTE ButtonState;
+
+    /* Read the whole packet at once */
+    Flags = IOReadB(PS2_DATA_PORT);
+    PS2PortQueueRead(1);
+    DeltaX = IOReadB(PS2_DATA_PORT);
+    PS2PortQueueRead(1);
+    DeltaY = IOReadB(PS2_DATA_PORT);
+
+    /* Adjust the sign */
+    if (Flags & MOUSE_X_SIGN) DeltaX = -DeltaX;
+    if (Flags & MOUSE_Y_SIGN) DeltaY = -DeltaY;
+
+    /* Update the counters */
+    DriverState.HorizCount += DeltaX;
+    DriverState.VertCount  += DeltaY;
+
+    /*
+     * Get the absolute position directly from the mouse, this is the only
+     * way to perfectly synchronize the host and guest mouse pointer.
+     */
+    MouseGetDataFast(&Position, &ButtonState);
+
+    /* Call the update subroutines */
+    DosUpdatePosition(&Position);
+    DosUpdateButtons(ButtonState);
+
+    /* Complete the IRQ */
+    PicIRQComplete(Stack);
+}
+
 static VOID WINAPI DosMouseService(LPWORD Stack)
 {
     switch (getAX())
@@ -183,10 +341,15 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
         {
             SHORT i;
 
-            DriverEnabled = TRUE;
             DriverState.ShowCount = 0;
             DriverState.ButtonState = 0;
 
+            /* Initialize the default clipping range */
+            DriverState.MinX = 0;
+            DriverState.MaxX = MOUSE_MAX_HORIZ - 1;
+            DriverState.MinY = 0;
+            DriverState.MaxY = MOUSE_MAX_VERT - 1;
+
             /* Set the default text cursor */
             DriverState.TextCursor.ScreenMask = 0xFFFF; /* Display everything */
             DriverState.TextCursor.CursorMask = 0xFF00; /* ... but with inverted attributes */
@@ -237,10 +400,6 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
                 DriverState.PressCount[i] = DriverState.ReleaseCount[i] = 0;
             }
 
-            /* Initialize the resolution */
-            DriverState.MickeysPerCellHoriz = 8;
-            DriverState.MickeysPerCellVert = 16;
-
             /* Return mouse information */
             setAX(0xFFFF);  // Hardware & driver installed
             setBX(NUM_MOUSE_BUTTONS);
@@ -252,7 +411,7 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
         case 0x01:
         {
             DriverState.ShowCount++;
-            if (DriverState.ShowCount > 0) PaintMouseCursor();
+            if (DriverState.ShowCount == 1) PaintMouseCursor();
 
             break;
         }
@@ -261,7 +420,7 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
         case 0x02:
         {
             DriverState.ShowCount--;
-            if (DriverState.ShowCount <= 0) EraseMouseCursor();
+            if (DriverState.ShowCount == 0) EraseMouseCursor();
 
             break;
         }
@@ -269,23 +428,22 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
         /* Return Position And Button Status */
         case 0x03:
         {
+            COORD Position = DriverState.Position;
+            ToMouseCoordinates(&Position);
+
             setBX(DriverState.ButtonState);
-            setCX(DriverState.Position.X);
-            setDX(DriverState.Position.Y);
+            setCX(Position.X);
+            setDX(Position.Y);
             break;
         }
 
         /* Position Mouse Cursor */
         case 0x04:
         {
-            POINT Point;
-
-            Point.x = getCX();
-            Point.y = getDX();
-
-            ClientToScreen(GetConsoleWindow(), &Point);
-            SetCursorPos(Point.x, Point.y);
+            COORD Position = { getCX(), getDX() };
+            FromMouseCoordinates(&Position);
 
+            DriverState.Position = Position;
             break;
         }
 
@@ -293,11 +451,13 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
         case 0x05:
         {
             WORD Button = getBX();
+            COORD LastPress = DriverState.LastPress[Button];
+            ToMouseCoordinates(&LastPress);
 
             setAX(DriverState.ButtonState);
             setBX(DriverState.PressCount[Button]);
-            setCX(DriverState.LastPress[Button].X);
-            setDX(DriverState.LastPress[Button].Y);
+            setCX(LastPress.X);
+            setDX(LastPress.Y);
 
             /* Reset the counter */
             DriverState.PressCount[Button] = 0;
@@ -309,11 +469,13 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
         case 0x06:
         {
             WORD Button = getBX();
+            COORD LastRelease = DriverState.LastRelease[Button];
+            ToMouseCoordinates(&LastRelease);
 
             setAX(DriverState.ButtonState);
             setBX(DriverState.ReleaseCount[Button]);
-            setCX(DriverState.LastRelease[Button].X);
-            setDX(DriverState.LastRelease[Button].Y);
+            setCX(LastRelease.X);
+            setDX(LastRelease.Y);
 
             /* Reset the counter */
             DriverState.ReleaseCount[Button] = 0;
@@ -322,6 +484,44 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
 
         }
 
+        /* Define Horizontal Cursor Range */
+        case 0x07:
+        {
+            WORD Min = getCX();
+            WORD Max = getDX();
+
+            if (!VgaGetDoubleVisionState(NULL, NULL))
+            {
+                /* Text mode */
+                Min &= ~0x07;
+                Max |= 0x07;
+            }
+
+            DPRINT("Setting mouse horizontal range: %u - %u\n", Min, Max);
+            DriverState.MinX = Min;
+            DriverState.MaxX = Max;
+            break;
+        }
+
+        /* Define Vertical Cursor Range */
+        case 0x08:
+        {
+            WORD Min = getCX();
+            WORD Max = getDX();
+
+            if (!VgaGetDoubleVisionState(NULL, NULL))
+            {
+                /* Text mode */
+                Min &= ~0x07;
+                Max |= 0x07;
+            }
+
+            DPRINT("Setting mouse vertical range: %u - %u\n", Min, Max);
+            DriverState.MinY = Min;
+            DriverState.MaxY = Max;
+            break;
+        }
+
         /* Define Graphics Cursor */
         case 0x09:
         {
@@ -395,8 +595,14 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
         /* Define Mickey/Pixel Ratio */
         case 0x0F:
         {
-            DriverState.MickeysPerCellHoriz = getCX();
-            DriverState.MickeysPerCellVert  = getDX();
+            /* This call should be completely ignored */
+            break;
+        }
+
+        /* Define Double-Speed Threshold */
+        case 0x13:
+        {
+            DPRINT1("INT 33h, AH=13h: Mouse double-speed threshold is UNSUPPORTED\n");
             break;
         }
 
@@ -466,7 +672,7 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
                  * Find the handler entry corresponding to the given
                  * callback and undefine it.
                  */
-                for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
+                for (i = 0; i < ARRAYSIZE(DriverState.Handlers); ++i)
                 {
                     if (DriverState.Handlers[i].Callback == Callback)
                     {
@@ -484,7 +690,7 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
                  * Find the handler entry corresponding to the given
                  * callmask and undefine it.
                  */
-                for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
+                for (i = 0; i < ARRAYSIZE(DriverState.Handlers); ++i)
                 {
                     if (DriverState.Handlers[i].CallMask == CallMask)
                     {
@@ -506,7 +712,7 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
 
                 USHORT EmptyHandler = 0xFFFF; // Invalid handler
 
-                for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
+                for (i = 0; i < ARRAYSIZE(DriverState.Handlers); ++i)
                 {
                     /* Find the first empty handler */
                     if (EmptyHandler == 0xFFFF &&
@@ -531,7 +737,7 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
                  * an empty handler, set it.
                  */
                 if (!Success && EmptyHandler != 0xFFFF
-                    /* && EmptyHandler < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]) */)
+                    /* && EmptyHandler < ARRAYSIZE(DriverState.Handlers) */)
                 {
                     DriverState.Handlers[EmptyHandler].CallMask = CallMask;
                     DriverState.Handlers[EmptyHandler].Callback = Callback;
@@ -556,7 +762,7 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
             /*
              * Find the handler entry corresponding to the given callmask.
              */
-            for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
+            for (i = 0; i < ARRAYSIZE(DriverState.Handlers); ++i)
             {
                 if (DriverState.Handlers[i].CallMask == CallMask)
                 {
@@ -582,20 +788,109 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
             break;
         }
 
+        /* Set Mouse Sensitivity */
+        case 0x1A:
+        {
+            DPRINT1("INT 33h, AH=1Ah: Mouse sensitivity is UNSUPPORTED\n");
+            break;
+        }
+
+        /* Return Mouse Sensitivity */
+        case 0x1B:
+        {
+            DPRINT1("INT 33h, AH=1Bh: Mouse sensitivity is UNSUPPORTED\n");
+
+            /* Return default values */
+            setBX(50); // Horizontal speed
+            setCX(50); //   Vertical speed
+            setDX(50); // Double speed threshold
+            break;
+        }
+
         /* Disable Mouse Driver */
         case 0x1F:
         {
-            setES(0x0000);
-            setBX(0x0000);
+            /* INT 33h vector before the mouse driver was first installed */
+            setES(HIWORD(OldIntHandler));
+            setBX(LOWORD(OldIntHandler));
 
-            DriverEnabled = FALSE;
+            DosMouseDisable();
             break;
         }
 
         /* Enable Mouse Driver */
         case 0x20:
         {
-            DriverEnabled = TRUE;
+            DosMouseEnable();
+            break;
+        }
+
+        /* Software Reset */
+        case 0x21:
+        {
+            /*
+             * See: http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte3sq8.htm
+             * for detailed information and differences with respect to subfunction 0x00:
+             * http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte3j74.htm
+             */
+
+            SHORT i;
+
+            DriverState.ShowCount = 0;
+            DriverState.ButtonState = 0;
+
+            /* Initialize the default clipping range */
+            DriverState.MinX = 0;
+            DriverState.MaxX = MOUSE_MAX_HORIZ - 1;
+            DriverState.MinY = 0;
+            DriverState.MaxY = MOUSE_MAX_VERT - 1;
+
+            /* Initialize the counters */
+            DriverState.HorizCount = DriverState.VertCount = 0;
+
+            for (i = 0; i < NUM_MOUSE_BUTTONS; i++)
+            {
+                DriverState.PressCount[i] = DriverState.ReleaseCount[i] = 0;
+            }
+
+            /* Return mouse information */
+            setAX(0xFFFF);  // Hardware & driver installed
+            setBX(NUM_MOUSE_BUTTONS);
+
+            break;
+        }
+
+        /* Get Software Version, Mouse Type, and IRQ Number, compatible MS MOUSE v6.26+ */
+        case 0x24:
+        {
+            setBX(MOUSE_VERSION); // Version Number
+
+            // FIXME: To be determined at runtime!
+            setCH(0x04); // PS/2 Type
+            setCL(0x00); // PS/2 Interrupt
+
+            break;
+        }
+
+        /* Return Pointer to Copyright String */
+        case 0x4D:
+        {
+            setES(HIWORD(COPYRIGHT_POINTER));
+            setDI(LOWORD(COPYRIGHT_POINTER));
+            break;
+        }
+
+        /* Get Version String (pointer) */
+        case 0x6D:
+        {
+            /*
+             * The format of the version "string" is:
+             * Offset  Size    Description
+             * 00h     BYTE    major version
+             * 01h     BYTE    minor version (BCD)
+             */
+            setES(HIWORD(VERSION_POINTER));
+            setDI(LOWORD(VERSION_POINTER));
             break;
         }
 
@@ -608,6 +903,31 @@ static VOID WINAPI DosMouseService(LPWORD Stack)
 
 /* PUBLIC FUNCTIONS ***********************************************************/
 
+VOID DosMouseEnable(VOID)
+{
+    if (!DriverEnabled)
+    {
+        DriverEnabled = TRUE;
+
+        /* Get the old IRQ handler */
+        OldIrqHandler = ((PDWORD)BaseAddress)[MOUSE_IRQ_INT];
+
+        /* Set the IRQ handler */
+        RegisterDosInt32(MOUSE_IRQ_INT, DosMouseIrq);
+    }
+}
+
+VOID DosMouseDisable(VOID)
+{
+    if (DriverEnabled)
+    {
+        /* Restore the old IRQ handler */
+        ((PDWORD)BaseAddress)[MOUSE_IRQ_INT] = OldIrqHandler;
+
+        DriverEnabled = FALSE;
+    }
+}
+
 VOID DosMouseUpdatePosition(PCOORD NewPosition)
 {
     SHORT DeltaX = NewPosition->X - DriverState.Position.X;
@@ -615,8 +935,8 @@ VOID DosMouseUpdatePosition(PCOORD NewPosition)
 
     if (!DriverEnabled) return;
 
-    DriverState.HorizCount += (DeltaX * (SHORT)DriverState.MickeysPerCellHoriz) / 8;
-    DriverState.VertCount  += (DeltaY * (SHORT)DriverState.MickeysPerCellVert ) / 8;
+    DriverState.HorizCount += (DeltaX * MICKEYS_PER_CELL_HORIZ) / 8;
+    DriverState.VertCount  += (DeltaY * MICKEYS_PER_CELL_VERT) / 8;
 
     if (DriverState.ShowCount > 0) EraseMouseCursor();
     DriverState.Position = *NewPosition;
@@ -668,13 +988,28 @@ BOOLEAN DosMouseInitialize(VOID)
     /* Clear the state */
     RtlZeroMemory(&DriverState, sizeof(DriverState));
 
+    /* Setup the version variable in BCD format, compatible MS-MOUSE */
+    Version  = (PWORD)FAR_POINTER(VERSION_POINTER);
+    *Version = MAKEWORD(MOUSE_VERSION/0x0100, MOUSE_VERSION%0x0100);
+
+    /* Mouse Driver Copyright */
+    RtlCopyMemory(FAR_POINTER(COPYRIGHT_POINTER), MouseCopyright, sizeof(MouseCopyright)-1);
+
+    /* Get the old mouse service interrupt handler */
+    OldIntHandler = ((PDWORD)BaseAddress)[DOS_MOUSE_INTERRUPT];
+
     /* Initialize the interrupt handler */
     RegisterDosInt32(DOS_MOUSE_INTERRUPT, DosMouseService);
 
+    DosMouseEnable();
     return TRUE;
 }
 
 VOID DosMouseCleanup(VOID)
 {
+    /* Restore the old mouse service interrupt handler */
+    ((PDWORD)BaseAddress)[DOS_MOUSE_INTERRUPT] = OldIntHandler;
+
     if (DriverState.ShowCount > 0) EraseMouseCursor();
+    DosMouseDisable();
 }