2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/dos/mouse32.c
5 * PURPOSE: VDM 32-bit compatible PS/2 MOUSE.COM driver
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
16 /* Driver Version number and Copyright */
17 #include <reactos/buildno.h>
18 #include <reactos/version.h>
24 #include "hardware/mouse.h"
25 #include "hardware/ps2.h"
26 #include "hardware/pic.h"
27 #include "hardware/video/svga.h"
30 #include "bios/bios.h"
31 #include "bios/bios32/bios32p.h"
35 #include "dos32krnl/memory.h"
37 /* PRIVATE VARIABLES **********************************************************/
39 static const CHAR MouseCopyright
[] =
40 "ReactOS PS/2 16/32-bit Mouse Driver Compatible MS-MOUSE 6.26\r\n"
41 "Version "KERNEL_VERSION_STR
" (Build "KERNEL_VERSION_BUILD_STR
")\r\n"
42 "Copyright (C) ReactOS Team 1996-"COPYRIGHT_YEAR
"\0";
46 typedef struct _MOUSE_DRIVER
48 CHAR Copyright
[sizeof(MouseCopyright
)];
50 BYTE MouseContextScratch
[TRAMPOLINE_SIZE
];
51 BYTE MouseDosInt16Stub
[Int16To32StubSize
];
52 BYTE MouseIrqInt16Stub
[Int16To32StubSize
];
53 } MOUSE_DRIVER
, *PMOUSE_DRIVER
;
57 /* Global data contained in guest memory */
58 static WORD MouseDataSegment
;
59 static PMOUSE_DRIVER MouseData
;
60 static CALLBACK16 MouseContext
;
62 #define MICKEYS_PER_CELL_HORIZ 8
63 #define MICKEYS_PER_CELL_VERT 16
65 static BOOLEAN DriverEnabled
= FALSE
;
66 static MOUSE_DRIVER_STATE DriverState
;
67 static DWORD OldIrqHandler
;
68 static DWORD OldIntHandler
;
70 static WORD DefaultGfxScreenMask
[16] =
72 0xC3FF, // 1100001111111111
73 0xC0FF, // 1100000011111111
74 0xC07F, // 1100000001111111
75 0xC01F, // 1100000000011111
76 0xC00F, // 1100000000001111
77 0xC007, // 1100000000000111
78 0xC003, // 1100000000000011
79 0xC007, // 1100000000000111
80 0xC01F, // 1100000000011111
81 0xC01F, // 1100000000011111
82 0xC00F, // 1100000000001111
83 0xC60F, // 1100011000001111
84 0xFF07, // 1111111100000111
85 0xFF07, // 1111111100000111
86 0xFF87, // 1111111110000111
87 0xFFCF, // 1111111111001111
90 static WORD DefaultGfxCursorMask
[16] =
92 0x0000, // 0000000000000000
93 0x1C00, // 0001110000000000
94 0x1F00, // 0001111100000000
95 0x1F80, // 0001111110000000
96 0x1FE0, // 0001111111100000
97 0x1FF0, // 0001111111110000
98 0x1FF8, // 0001111111111000
99 0x1FE0, // 0001111111100000
100 0x1FC0, // 0001111111000000
101 0x1FC0, // 0001111111000000
102 0x19E0, // 0001100111100000
103 0x00E0, // 0000000011100000
104 0x0070, // 0000000001110000
105 0x0070, // 0000000001110000
106 0x0030, // 0000000000110000
107 0x0000, // 0000000000000000
110 /* PRIVATE FUNCTIONS **********************************************************/
113 VOID
BiosPs2Service(UCHAR Function
)
117 // USHORT BX = getBX();
120 * Set the parameters:
121 * AL contains the character to print (already set),
122 * BL contains the character attribute,
123 * BH contains the video page to use.
125 // setBL(DOS_CHAR_ATTRIBUTE);
126 // setBH(Bda->VideoPage);
129 /* Call the BIOS INT 15h, AH=C2h "Pointing Device BIOS Interface (PS)" */
131 Int32Call(&MouseContext
, BIOS_MISC_INTERRUPT
);
133 /* Restore AX and BX */
140 static VOID
DosMouseEnable(VOID
);
141 static VOID
DosMouseDisable(VOID
);
144 static VOID
PaintMouseCursor(VOID
)
146 COORD Position
= DriverState
.Position
;
148 /* Apply the clipping rectangle */
149 if (Position
.X
< DriverState
.MinX
) Position
.X
= DriverState
.MinX
;
150 if (Position
.X
> DriverState
.MaxX
) Position
.X
= DriverState
.MaxX
;
151 if (Position
.Y
< DriverState
.MinY
) Position
.Y
= DriverState
.MinY
;
152 if (Position
.Y
> DriverState
.MaxY
) Position
.Y
= DriverState
.MaxY
;
154 if (Bda
->VideoMode
<= 3)
157 WORD CellX
= Position
.X
/ 8;
158 WORD CellY
= Position
.Y
/ 8;
159 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
);
161 EmulatorReadMemory(&EmulatorContext
,
163 + (CellY
* Bda
->ScreenColumns
+ CellX
) * sizeof(WORD
),
167 DriverState
.Character
= Character
;
168 Character
&= DriverState
.TextCursor
.ScreenMask
;
169 Character
^= DriverState
.TextCursor
.CursorMask
;
171 EmulatorWriteMemory(&EmulatorContext
,
173 + (CellY
* Bda
->ScreenColumns
+ CellX
) * sizeof(WORD
),
179 // TODO: NOT IMPLEMENTED
184 static VOID
EraseMouseCursor(VOID
)
186 COORD Position
= DriverState
.Position
;
188 /* Apply the clipping rectangle */
189 if (Position
.X
< DriverState
.MinX
) Position
.X
= DriverState
.MinX
;
190 if (Position
.X
> DriverState
.MaxX
) Position
.X
= DriverState
.MaxX
;
191 if (Position
.Y
< DriverState
.MinY
) Position
.Y
= DriverState
.MinY
;
192 if (Position
.Y
> DriverState
.MaxY
) Position
.Y
= DriverState
.MaxY
;
194 if (Bda
->VideoMode
<= 3)
196 WORD CellX
= Position
.X
/ 8;
197 WORD CellY
= Position
.Y
/ 8;
198 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
);
200 EmulatorWriteMemory(&EmulatorContext
,
202 + (CellY
* Bda
->ScreenColumns
+ CellX
) * sizeof(WORD
),
203 (LPVOID
)&DriverState
.Character
,
208 // TODO: NOT IMPLEMENTED
213 static VOID
ToMouseCoordinates(PCOORD Position
)
215 COORD Resolution
= VgaGetDisplayResolution();
216 DWORD Width
= DriverState
.MaxX
- DriverState
.MinX
+ 1;
217 DWORD Height
= DriverState
.MaxY
- DriverState
.MinY
+ 1;
219 if (!VgaGetDoubleVisionState(NULL
, NULL
))
225 Position
->X
= DriverState
.MinX
+ ((Position
->X
* Width
) / Resolution
.X
);
226 Position
->Y
= DriverState
.MinY
+ ((Position
->Y
* Height
) / Resolution
.Y
);
229 static VOID
FromMouseCoordinates(PCOORD Position
)
231 COORD Resolution
= VgaGetDisplayResolution();
232 DWORD Width
= DriverState
.MaxX
- DriverState
.MinX
+ 1;
233 DWORD Height
= DriverState
.MaxY
- DriverState
.MinY
+ 1;
235 if (!VgaGetDoubleVisionState(NULL
, NULL
))
241 Position
->X
= ((Position
->X
- DriverState
.MinX
) * Resolution
.X
) / Width
;
242 Position
->Y
= ((Position
->Y
- DriverState
.MinY
) * Resolution
.Y
) / Height
;
245 static VOID
CallMouseUserHandlers(USHORT CallMask
)
248 USHORT AX
, BX
, CX
, DX
, BP
, SI
, DI
, DS
, ES
;
249 COORD Position
= DriverState
.Position
;
251 ToMouseCoordinates(&Position
);
254 if ((DriverState
.Handler0
.CallMask
& CallMask
) != 0 &&
255 DriverState
.Handler0
.Callback
!= (ULONG
)NULL
)
258 * Set the parameters for the callback.
259 * NOTE: In text modes, the row and column will be reported
260 * as a multiple of the cell size, typically 8x8 pixels.
274 setBX(DriverState
.ButtonState
);
277 setSI(MICKEYS_PER_CELL_HORIZ
);
278 setDI(MICKEYS_PER_CELL_VERT
);
280 DPRINT("Calling Handler0 %04X:%04X with CallMask 0x%04X\n",
281 HIWORD(DriverState
.Handler0
.Callback
),
282 LOWORD(DriverState
.Handler0
.Callback
),
285 /* Call the callback */
286 RunCallback16(&MouseContext
, DriverState
.Handler0
.Callback
);
299 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
301 /* Call the suitable handlers */
302 if ((DriverState
.Handlers
[i
].CallMask
& CallMask
) != 0 &&
303 DriverState
.Handlers
[i
].Callback
!= (ULONG
)NULL
)
306 * Set the parameters for the callback.
307 * NOTE: In text modes, the row and column will be reported
308 * as a multiple of the cell size, typically 8x8 pixels.
322 setBX(DriverState
.ButtonState
);
325 setSI(MICKEYS_PER_CELL_HORIZ
);
326 setDI(MICKEYS_PER_CELL_VERT
);
328 DPRINT1("Calling Handler[%d] %04X:%04X with CallMask 0x%04X\n",
330 HIWORD(DriverState
.Handlers
[i
].Callback
),
331 LOWORD(DriverState
.Handlers
[i
].Callback
),
334 /* Call the callback */
335 RunCallback16(&MouseContext
, DriverState
.Handlers
[i
].Callback
);
350 static inline VOID
DosUpdatePosition(PCOORD NewPosition
)
352 COORD Resolution
= VgaGetDisplayResolution();
354 /* Check for text mode */
355 if (!VgaGetDoubleVisionState(NULL
, NULL
))
361 if (DriverState
.ShowCount
> 0) EraseMouseCursor();
362 DriverState
.Position
= *NewPosition
;
363 if (DriverState
.ShowCount
> 0) PaintMouseCursor();
365 /* Call the mouse handlers */
366 CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
369 static inline VOID
DosUpdateButtons(BYTE ButtonState
) // WORD ButtonState
372 USHORT CallMask
= 0x0000; // We use MS MOUSE v1.0+ format
374 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
376 BOOLEAN OldState
= (DriverState
.ButtonState
>> i
) & 1;
377 BOOLEAN NewState
= (ButtonState
>> i
) & 1;
379 if (NewState
> OldState
)
382 DriverState
.PressCount
[i
]++;
383 DriverState
.LastPress
[i
] = DriverState
.Position
;
385 CallMask
|= (1 << (2 * i
+ 1));
387 else if (NewState
< OldState
)
390 DriverState
.ReleaseCount
[i
]++;
391 DriverState
.LastRelease
[i
] = DriverState
.Position
;
393 CallMask
|= (1 << (2 * i
+ 2));
397 DriverState
.ButtonState
= ButtonState
;
399 /* Call the mouse handlers */
400 CallMouseUserHandlers(CallMask
);
403 static VOID WINAPI
DosMouseIrq(LPWORD Stack
)
406 SHORT DeltaX
, DeltaY
;
410 /* Read the whole packet at once */
411 Flags
= IOReadB(PS2_DATA_PORT
);
412 PS2PortQueueRead(1); // NOTE: Should be a IOReadB! But see r67231
413 DeltaX
= IOReadB(PS2_DATA_PORT
);
414 PS2PortQueueRead(1); // NOTE: Should be a IOReadB! But see r67231
415 DeltaY
= IOReadB(PS2_DATA_PORT
);
417 /* Adjust the sign */
418 if (Flags
& MOUSE_X_SIGN
) DeltaX
= -DeltaX
;
419 if (Flags
& MOUSE_Y_SIGN
) DeltaY
= -DeltaY
;
421 /* Update the counters */
422 DriverState
.HorizCount
+= DeltaX
;
423 DriverState
.VertCount
+= DeltaY
;
426 * Get the absolute position directly from the mouse, this is the only
427 * way to perfectly synchronize the host and guest mouse pointer.
429 MouseGetDataFast(&Position
, &ButtonState
);
431 /* Call the update subroutines */
432 DosUpdatePosition(&Position
);
433 DosUpdateButtons(ButtonState
);
435 /* Complete the IRQ */
436 PicIRQComplete(LOBYTE(Stack
[STACK_INT_NUM
]));
439 static VOID WINAPI
DosMouseService(LPWORD Stack
)
448 DriverState
.ShowCount
= 0;
449 DriverState
.ButtonState
= 0;
451 /* Initialize the default clipping range */
452 DriverState
.MinX
= 0;
453 DriverState
.MaxX
= MOUSE_MAX_HORIZ
- 1;
454 DriverState
.MinY
= 0;
455 DriverState
.MaxY
= MOUSE_MAX_VERT
- 1;
457 /* Set the default text cursor */
458 DriverState
.TextCursor
.ScreenMask
= 0xFFFF; /* Display everything */
459 DriverState
.TextCursor
.CursorMask
= 0xFF00; /* ... but with inverted attributes */
461 /* Set the default graphics cursor */
462 DriverState
.GraphicsCursor
.HotSpot
.X
= 3;
463 DriverState
.GraphicsCursor
.HotSpot
.Y
= 1;
465 RtlCopyMemory(DriverState
.GraphicsCursor
.ScreenMask
,
466 DefaultGfxScreenMask
,
467 sizeof(DriverState
.GraphicsCursor
.ScreenMask
));
469 RtlCopyMemory(DriverState
.GraphicsCursor
.CursorMask
,
470 DefaultGfxCursorMask
,
471 sizeof(DriverState
.GraphicsCursor
.CursorMask
));
473 /* Initialize the counters */
474 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
476 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
478 DriverState
.PressCount
[i
] = DriverState
.ReleaseCount
[i
] = 0;
481 /* Return mouse information */
482 setAX(0xFFFF); // Hardware & driver installed
483 setBX(NUM_MOUSE_BUTTONS
);
488 /* Show Mouse Cursor */
491 DriverState
.ShowCount
++;
492 if (DriverState
.ShowCount
== 1) PaintMouseCursor();
497 /* Hide Mouse Cursor */
500 DriverState
.ShowCount
--;
501 if (DriverState
.ShowCount
== 0) EraseMouseCursor();
506 /* Return Position and Button Status */
509 COORD Position
= DriverState
.Position
;
510 ToMouseCoordinates(&Position
);
512 setBX(DriverState
.ButtonState
);
518 /* Position Mouse Cursor */
521 COORD Position
= { getCX(), getDX() };
522 FromMouseCoordinates(&Position
);
524 DriverState
.Position
= Position
;
528 /* Return Button Press Data */
531 WORD Button
= getBX();
532 COORD LastPress
= DriverState
.LastPress
[Button
];
533 ToMouseCoordinates(&LastPress
);
535 setAX(DriverState
.ButtonState
);
536 setBX(DriverState
.PressCount
[Button
]);
540 /* Reset the counter */
541 DriverState
.PressCount
[Button
] = 0;
546 /* Return Button Release Data */
549 WORD Button
= getBX();
550 COORD LastRelease
= DriverState
.LastRelease
[Button
];
551 ToMouseCoordinates(&LastRelease
);
553 setAX(DriverState
.ButtonState
);
554 setBX(DriverState
.ReleaseCount
[Button
]);
555 setCX(LastRelease
.X
);
556 setDX(LastRelease
.Y
);
558 /* Reset the counter */
559 DriverState
.ReleaseCount
[Button
] = 0;
565 /* Define Horizontal Cursor Range */
571 if (!VgaGetDoubleVisionState(NULL
, NULL
))
578 DPRINT("Setting mouse horizontal range: %u - %u\n", Min
, Max
);
579 DriverState
.MinX
= Min
;
580 DriverState
.MaxX
= Max
;
584 /* Define Vertical Cursor Range */
590 if (!VgaGetDoubleVisionState(NULL
, NULL
))
597 DPRINT("Setting mouse vertical range: %u - %u\n", Min
, Max
);
598 DriverState
.MinY
= Min
;
599 DriverState
.MaxY
= Max
;
603 /* Define Graphics Cursor */
606 PWORD MaskBitmap
= (PWORD
)SEG_OFF_TO_PTR(getES(), getDX());
608 DriverState
.GraphicsCursor
.HotSpot
.X
= getBX();
609 DriverState
.GraphicsCursor
.HotSpot
.Y
= getCX();
611 RtlCopyMemory(DriverState
.GraphicsCursor
.ScreenMask
,
613 sizeof(DriverState
.GraphicsCursor
.ScreenMask
));
615 RtlCopyMemory(DriverState
.GraphicsCursor
.CursorMask
,
617 sizeof(DriverState
.GraphicsCursor
.CursorMask
));
622 /* Define Text Cursor */
629 /* Define software cursor */
630 DriverState
.TextCursor
.ScreenMask
= getCX();
631 DriverState
.TextCursor
.CursorMask
= getDX();
633 else if (BX
== 0x0001)
635 /* Define hardware cursor */
636 DPRINT1("Defining hardware cursor is unimplemented\n");
638 // CX == start scan line
639 // DX == end scan line
643 DPRINT1("Invalid BX value 0x%04X\n", BX
);
649 /* Read Motion Counters */
652 setCX(DriverState
.HorizCount
);
653 setDX(DriverState
.VertCount
);
655 /* Reset the counters */
656 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
661 /* Define Interrupt Subroutine Parameters, compatible MS MOUSE v1.0+ */
664 DriverState
.Handler0
.CallMask
= getCX();
665 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
666 DPRINT1("Define callback 0x%04X, %04X:%04X\n",
667 DriverState
.Handler0
.CallMask
,
668 HIWORD(DriverState
.Handler0
.Callback
),
669 LOWORD(DriverState
.Handler0
.Callback
));
673 /* Define Mickey/Pixel Ratio */
676 /* This call should be completely ignored */
680 /* Set Exclusion Area */
681 // http://www.ctyme.com/intr/rb-5972.htm
682 // http://www.techhelpmanual.com/849-int_33h_0010h__set_exclusion_area.html
687 /* Define Double-Speed Threshold */
690 DPRINT1("INT 33h, AH=13h: Mouse double-speed threshold is UNSUPPORTED\n");
694 /* Exchange Interrupt Subroutines, compatible MS MOUSE v3.0+ (see function 0x0C) */
697 USHORT OldCallMask
= DriverState
.Handler0
.CallMask
;
698 ULONG OldCallback
= DriverState
.Handler0
.Callback
;
700 DriverState
.Handler0
.CallMask
= getCX();
701 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
702 DPRINT1("Exchange old callback 0x%04X, %04X:%04X with new callback 0x%04X, %04X:%04X\n",
706 DriverState
.Handler0
.CallMask
,
707 HIWORD(DriverState
.Handler0
.Callback
),
708 LOWORD(DriverState
.Handler0
.Callback
));
710 /* Return old callmask in CX and callback vector in ES:DX */
712 setES(HIWORD(OldCallback
));
713 setDX(LOWORD(OldCallback
));
717 /* Return Driver Storage Requirements */
720 setBX(sizeof(MOUSE_DRIVER_STATE
));
724 /* Save Driver State */
727 /* Check whether the user buffer has correct size and fail if not */
728 if (getBX() != sizeof(MOUSE_DRIVER_STATE
)) break;
730 *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX())) = DriverState
;
734 /* Restore Driver State */
737 /* Check whether the user buffer has correct size and fail if not */
738 if (getBX() != sizeof(MOUSE_DRIVER_STATE
)) break;
740 DriverState
= *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX()));
744 /* Set Alternate Mouse User Handler, compatible MS MOUSE v6.0+ */
748 * Up to three handlers can be defined by separate calls to this
749 * function, each with a different combination of shift states in
750 * the call mask; calling this function again with a call mask of
751 * 0000h undefines the specified handler (official documentation);
752 * specifying the same call mask and an address of 0000h:0000h
753 * undefines the handler (real life).
754 * See Ralf Brown: http://www.ctyme.com/intr/rb-5981.htm
755 * for more information.
759 USHORT CallMask
= getCX();
760 ULONG Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
761 BOOLEAN Success
= FALSE
;
763 DPRINT1("Define v6.0+ callback 0x%04X, %04X:%04X\n",
764 CallMask
, HIWORD(Callback
), LOWORD(Callback
));
766 if (CallMask
== 0x0000)
769 * Find the handler entry corresponding to the given
770 * callback and undefine it.
772 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
774 if (DriverState
.Handlers
[i
].Callback
== Callback
)
776 /* Found it, undefine the handler */
777 DriverState
.Handlers
[i
].CallMask
= 0x0000;
778 DriverState
.Handlers
[i
].Callback
= (ULONG
)NULL
;
784 else if (Callback
== (ULONG
)NULL
)
787 * Find the handler entry corresponding to the given
788 * callmask and undefine it.
790 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
792 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
794 /* Found it, undefine the handler */
795 DriverState
.Handlers
[i
].CallMask
= 0x0000;
796 DriverState
.Handlers
[i
].Callback
= (ULONG
)NULL
;
805 * Try to find a handler entry corresponding to the given
806 * callmask to redefine it, otherwise find an empty handler
807 * entry and set the new handler in there.
810 USHORT EmptyHandler
= 0xFFFF; // Invalid handler
812 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
814 /* Find the first empty handler */
815 if (EmptyHandler
== 0xFFFF &&
816 DriverState
.Handlers
[i
].CallMask
== 0x0000 &&
817 DriverState
.Handlers
[i
].Callback
== (ULONG
)NULL
)
822 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
824 /* Found it, redefine the handler */
825 DriverState
.Handlers
[i
].CallMask
= CallMask
;
826 DriverState
.Handlers
[i
].Callback
= Callback
;
833 * If we haven't found anything and we found
834 * an empty handler, set it.
836 if (!Success
&& EmptyHandler
!= 0xFFFF
837 /* && EmptyHandler < ARRAYSIZE(DriverState.Handlers) */)
839 DriverState
.Handlers
[EmptyHandler
].CallMask
= CallMask
;
840 DriverState
.Handlers
[EmptyHandler
].Callback
= Callback
;
845 /* If we failed, set error code */
846 if (!Success
) setAX(0xFFFF);
851 /* Return User Alternate Interrupt Vector, compatible MS MOUSE v6.0+ */
855 USHORT CallMask
= getCX();
857 BOOLEAN Success
= FALSE
;
860 * Find the handler entry corresponding to the given callmask.
862 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
864 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
867 Callback
= DriverState
.Handlers
[i
].Callback
;
875 /* Return the callback vector in BX:DX */
876 setBX(HIWORD(Callback
));
877 setDX(LOWORD(Callback
));
881 /* We failed, set error code */
888 /* Set Mouse Sensitivity */
891 DPRINT1("INT 33h, AH=1Ah: Mouse sensitivity is UNSUPPORTED\n");
893 // FIXME: Do that at runtime!
895 // UCHAR BH = getBH();
897 // BiosPs2Service(0x00);
898 // FIXME: Check for return status in AH and CF
904 /* Return Mouse Sensitivity */
907 DPRINT1("INT 33h, AH=1Bh: Mouse sensitivity is UNSUPPORTED\n");
909 /* Return default values */
910 setBX(50); // Horizontal speed
911 setCX(50); // Vertical speed
912 setDX(50); // Double speed threshold
914 // FIXME: Get that at runtime!
916 // UCHAR BH = getBH();
918 // BiosPs2Service(0x00);
919 // FIXME: Check for return status in AH and CF
925 /* Disable Mouse Driver */
928 /* INT 33h vector before the mouse driver was first installed */
929 setES(HIWORD(OldIntHandler
));
930 setBX(LOWORD(OldIntHandler
));
933 // UCHAR BH = getBH();
935 // BiosPs2Service(0x00);
936 // FIXME: Check for return status in AH and CF
941 /* Enable Mouse Driver */
945 // UCHAR BH = getBH();
947 // BiosPs2Service(0x00);
948 // FIXME: Check for return status in AH and CF
957 * See: http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte3sq8.htm
958 * for detailed information and differences with respect to subfunction 0x00:
959 * http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte3j74.htm
964 DriverState
.ShowCount
= 0;
965 DriverState
.ButtonState
= 0;
967 /* Initialize the default clipping range */
968 DriverState
.MinX
= 0;
969 DriverState
.MaxX
= MOUSE_MAX_HORIZ
- 1;
970 DriverState
.MinY
= 0;
971 DriverState
.MaxY
= MOUSE_MAX_VERT
- 1;
973 /* Initialize the counters */
974 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
976 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
978 DriverState
.PressCount
[i
] = DriverState
.ReleaseCount
[i
] = 0;
981 /* Return mouse information */
982 setAX(0xFFFF); // Hardware & driver installed
983 setBX(NUM_MOUSE_BUTTONS
);
988 /* Get Software Version, Mouse Type, and IRQ Number, compatible MS MOUSE v6.26+ */
991 setBX(MOUSE_VERSION
); // Version Number
994 * See Ralf Brown: http://www.ctyme.com/intr/rb-5993.htm
995 * for the list of possible values.
997 // FIXME: To be determined at runtime!
998 setCH(0x04); // PS/2 Type
999 setCL(0x00); // PS/2 Interrupt
1004 // BIOS Function INT 33h, AX = 0x0025 NOT IMPLEMENTED
1015 /* Get Maximum Virtual Coordinates */
1018 setBX(!DriverEnabled
);
1019 // FIXME: In fact the MaxX and MaxY here are
1020 // theoretical values for the current video mode.
1021 // They therefore can be different from the current
1023 // See http://www.ctyme.com/intr/rb-5995.htm
1024 // for more details.
1025 setCX(DriverState
.MaxX
);
1026 setDX(DriverState
.MaxY
);
1030 /* Get Current Minimum/Maximum Virtual Coordinates */
1033 setAX(DriverState
.MinX
);
1034 setBX(DriverState
.MinY
);
1035 setCX(DriverState
.MaxX
);
1036 setDX(DriverState
.MaxY
);
1044 * Related to http://www.ctyme.com/intr/rb-5985.htm
1045 * INT 33h, AX=001Ch "SET INTERRUPT RATE":
1047 * Values for mouse interrupt rate:
1049 00h no interrupts allowed
1058 /* Return Pointer to Copyright String */
1061 setES(MouseDataSegment
);
1062 setDI(FIELD_OFFSET(MOUSE_DRIVER
, Copyright
));
1066 /* Get Version String (pointer) */
1070 * The format of the version "string" is:
1071 * Offset Size Description
1072 * 00h BYTE major version
1073 * 01h BYTE minor version (BCD)
1075 setES(MouseDataSegment
);
1076 setDI(FIELD_OFFSET(MOUSE_DRIVER
, Version
));
1082 DPRINT1("BIOS Function INT 33h, AX = 0x%04X NOT IMPLEMENTED\n", getAX());
1087 /* PUBLIC FUNCTIONS ***********************************************************/
1090 VOID
DosMouseEnable(VOID
)
1092 if (DriverEnabled
) return;
1094 DriverEnabled
= TRUE
;
1096 /* Get the old IRQ handler */
1097 OldIrqHandler
= ((PDWORD
)BaseAddress
)[MOUSE_IRQ_INT
];
1099 /* Set the IRQ handler */
1100 RegisterInt32(MAKELONG(FIELD_OFFSET(MOUSE_DRIVER
, MouseIrqInt16Stub
), MouseDataSegment
),
1101 MOUSE_IRQ_INT
, DosMouseIrq
, NULL
);
1105 VOID
DosMouseDisable(VOID
)
1107 if (!DriverEnabled
) return;
1109 /* Restore the old IRQ handler */
1110 ((PDWORD
)BaseAddress
)[MOUSE_IRQ_INT
] = OldIrqHandler
;
1112 DriverEnabled
= FALSE
;
1115 BOOLEAN
DosMouseInitialize(VOID
)
1117 /* Initialize some memory for storing our data that should be available to DOS */
1118 MouseDataSegment
= DosAllocateMemory(sizeof(MOUSE_DRIVER
), NULL
);
1119 if (MouseDataSegment
== 0) return FALSE
;
1120 MouseData
= (PMOUSE_DRIVER
)SEG_OFF_TO_PTR(MouseDataSegment
, 0x0000);
1122 /* Initialize the callback context */
1123 InitializeContext(&MouseContext
, MouseDataSegment
, FIELD_OFFSET(MOUSE_DRIVER
, MouseContextScratch
));
1125 /* Clear the state */
1126 RtlZeroMemory(&DriverState
, sizeof(DriverState
));
1128 /* Mouse Driver Copyright */
1129 RtlCopyMemory(MouseData
->Copyright
, MouseCopyright
, sizeof(MouseCopyright
)-1);
1131 /* Mouse Driver Version in BCD format, compatible MS-MOUSE */
1132 MouseData
->Version
= MAKEWORD(MOUSE_VERSION
/0x0100, MOUSE_VERSION
%0x0100);
1134 /* Get the old mouse service interrupt handler */
1135 OldIntHandler
= ((PDWORD
)BaseAddress
)[DOS_MOUSE_INTERRUPT
];
1137 /* Initialize the interrupt handler */
1138 RegisterInt32(MAKELONG(FIELD_OFFSET(MOUSE_DRIVER
, MouseDosInt16Stub
), MouseDataSegment
),
1139 DOS_MOUSE_INTERRUPT
, DosMouseService
, NULL
);
1142 // UCHAR BH = getBH();
1144 // BiosPs2Service(0x00);
1145 // FIXME: Check for return status in AH and CF
1151 VOID
DosMouseCleanup(VOID
)
1153 if (DriverState
.ShowCount
> 0) EraseMouseCursor();
1155 // UCHAR BH = getBH();
1157 // BiosPs2Service(0x00);
1158 // FIXME: Check for return status in AH and CF
1161 /* Restore the old mouse service interrupt handler */
1162 ((PDWORD
)BaseAddress
)[DOS_MOUSE_INTERRUPT
] = OldIntHandler
;
1164 DosFreeMemory(MouseDataSegment
);
1165 MouseDataSegment
= 0;