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 *******************************************************************/
13 /* Driver Version number and Copyright */
14 #include <reactos/buildno.h>
15 #include <reactos/version.h>
22 #include "hardware/mouse.h"
23 #include "hardware/ps2.h"
24 #include "hardware/pic.h"
25 #include "hardware/video/svga.h"
28 #include "bios/bios.h"
29 #include "bios/bios32/bios32p.h"
33 #include "dos32krnl/memory.h"
35 /* PRIVATE VARIABLES **********************************************************/
37 static const CHAR MouseCopyright
[] =
38 "ReactOS PS/2 16/32-bit Mouse Driver Compatible MS-MOUSE 6.26\r\n"
39 "Version "KERNEL_VERSION_STR
" (Build "KERNEL_VERSION_BUILD_STR
")\r\n"
40 "Copyright (C) ReactOS Team 1996-"COPYRIGHT_YEAR
"\0";
44 typedef struct _MOUSE_DRIVER
46 CHAR Copyright
[sizeof(MouseCopyright
)];
48 BYTE MouseContextScratch
[TRAMPOLINE_SIZE
];
49 BYTE MouseDosInt16Stub
[Int16To32StubSize
];
50 BYTE MouseIrqInt16Stub
[Int16To32StubSize
];
51 } MOUSE_DRIVER
, *PMOUSE_DRIVER
;
55 /* Global data contained in guest memory */
56 static WORD MouseDataSegment
;
57 static PMOUSE_DRIVER MouseData
;
58 static CALLBACK16 MouseContext
;
60 #define MICKEYS_PER_CELL_HORIZ 8
61 #define MICKEYS_PER_CELL_VERT 16
63 static BOOLEAN DriverEnabled
= FALSE
;
64 static MOUSE_DRIVER_STATE DriverState
;
65 static DWORD OldIrqHandler
;
66 static DWORD OldIntHandler
;
68 static WORD DefaultGfxScreenMask
[16] =
70 0xC3FF, // 1100001111111111
71 0xC0FF, // 1100000011111111
72 0xC07F, // 1100000001111111
73 0xC01F, // 1100000000011111
74 0xC00F, // 1100000000001111
75 0xC007, // 1100000000000111
76 0xC003, // 1100000000000011
77 0xC007, // 1100000000000111
78 0xC01F, // 1100000000011111
79 0xC01F, // 1100000000011111
80 0xC00F, // 1100000000001111
81 0xC60F, // 1100011000001111
82 0xFF07, // 1111111100000111
83 0xFF07, // 1111111100000111
84 0xFF87, // 1111111110000111
85 0xFFCF, // 1111111111001111
88 static WORD DefaultGfxCursorMask
[16] =
90 0x0000, // 0000000000000000
91 0x1C00, // 0001110000000000
92 0x1F00, // 0001111100000000
93 0x1F80, // 0001111110000000
94 0x1FE0, // 0001111111100000
95 0x1FF0, // 0001111111110000
96 0x1FF8, // 0001111111111000
97 0x1FE0, // 0001111111100000
98 0x1FC0, // 0001111111000000
99 0x1FC0, // 0001111111000000
100 0x19E0, // 0001100111100000
101 0x00E0, // 0000000011100000
102 0x0070, // 0000000001110000
103 0x0070, // 0000000001110000
104 0x0030, // 0000000000110000
105 0x0000, // 0000000000000000
108 /* PRIVATE FUNCTIONS **********************************************************/
111 VOID
BiosPs2Service(UCHAR Function
)
115 // USHORT BX = getBX();
118 * Set the parameters:
119 * AL contains the character to print (already set),
120 * BL contains the character attribute,
121 * BH contains the video page to use.
123 // setBL(DOS_CHAR_ATTRIBUTE);
124 // setBH(Bda->VideoPage);
127 /* Call the BIOS INT 15h, AH=C2h "Pointing Device BIOS Interface (PS)" */
129 Int32Call(&MouseContext
, BIOS_MISC_INTERRUPT
);
131 /* Restore AX and BX */
138 static VOID
DosMouseEnable(VOID
);
139 static VOID
DosMouseDisable(VOID
);
142 static VOID
PaintMouseCursor(VOID
)
144 COORD Position
= DriverState
.Position
;
146 /* Apply the clipping rectangle */
147 if (Position
.X
< DriverState
.MinX
) Position
.X
= DriverState
.MinX
;
148 if (Position
.X
> DriverState
.MaxX
) Position
.X
= DriverState
.MaxX
;
149 if (Position
.Y
< DriverState
.MinY
) Position
.Y
= DriverState
.MinY
;
150 if (Position
.Y
> DriverState
.MaxY
) Position
.Y
= DriverState
.MaxY
;
152 if (Bda
->VideoMode
<= 3)
155 WORD CellX
= Position
.X
/ 8;
156 WORD CellY
= Position
.Y
/ 8;
157 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
);
159 EmulatorReadMemory(&EmulatorContext
,
161 + (CellY
* Bda
->ScreenColumns
+ CellX
) * sizeof(WORD
),
165 DriverState
.Character
= Character
;
166 Character
&= DriverState
.TextCursor
.ScreenMask
;
167 Character
^= DriverState
.TextCursor
.CursorMask
;
169 EmulatorWriteMemory(&EmulatorContext
,
171 + (CellY
* Bda
->ScreenColumns
+ CellX
) * sizeof(WORD
),
177 // TODO: NOT IMPLEMENTED
182 static VOID
EraseMouseCursor(VOID
)
184 COORD Position
= DriverState
.Position
;
186 /* Apply the clipping rectangle */
187 if (Position
.X
< DriverState
.MinX
) Position
.X
= DriverState
.MinX
;
188 if (Position
.X
> DriverState
.MaxX
) Position
.X
= DriverState
.MaxX
;
189 if (Position
.Y
< DriverState
.MinY
) Position
.Y
= DriverState
.MinY
;
190 if (Position
.Y
> DriverState
.MaxY
) Position
.Y
= DriverState
.MaxY
;
192 if (Bda
->VideoMode
<= 3)
194 WORD CellX
= Position
.X
/ 8;
195 WORD CellY
= Position
.Y
/ 8;
196 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
);
198 EmulatorWriteMemory(&EmulatorContext
,
200 + (CellY
* Bda
->ScreenColumns
+ CellX
) * sizeof(WORD
),
201 (LPVOID
)&DriverState
.Character
,
206 // TODO: NOT IMPLEMENTED
211 static VOID
ToMouseCoordinates(PCOORD Position
)
213 COORD Resolution
= VgaGetDisplayResolution();
214 DWORD Width
= DriverState
.MaxX
- DriverState
.MinX
+ 1;
215 DWORD Height
= DriverState
.MaxY
- DriverState
.MinY
+ 1;
217 if (!VgaGetDoubleVisionState(NULL
, NULL
))
223 Position
->X
= DriverState
.MinX
+ ((Position
->X
* Width
) / Resolution
.X
);
224 Position
->Y
= DriverState
.MinY
+ ((Position
->Y
* Height
) / Resolution
.Y
);
227 static VOID
FromMouseCoordinates(PCOORD Position
)
229 COORD Resolution
= VgaGetDisplayResolution();
230 DWORD Width
= DriverState
.MaxX
- DriverState
.MinX
+ 1;
231 DWORD Height
= DriverState
.MaxY
- DriverState
.MinY
+ 1;
233 if (!VgaGetDoubleVisionState(NULL
, NULL
))
239 Position
->X
= ((Position
->X
- DriverState
.MinX
) * Resolution
.X
) / Width
;
240 Position
->Y
= ((Position
->Y
- DriverState
.MinY
) * Resolution
.Y
) / Height
;
243 static VOID
CallMouseUserHandlers(USHORT CallMask
)
246 USHORT AX
, BX
, CX
, DX
, BP
, SI
, DI
, DS
, ES
;
247 COORD Position
= DriverState
.Position
;
249 ToMouseCoordinates(&Position
);
252 if ((DriverState
.Handler0
.CallMask
& CallMask
) != 0 &&
253 DriverState
.Handler0
.Callback
!= (ULONG
)NULL
)
256 * Set the parameters for the callback.
257 * NOTE: In text modes, the row and column will be reported
258 * as a multiple of the cell size, typically 8x8 pixels.
272 setBX(DriverState
.ButtonState
);
275 setSI(MICKEYS_PER_CELL_HORIZ
);
276 setDI(MICKEYS_PER_CELL_VERT
);
278 DPRINT("Calling Handler0 %04X:%04X with CallMask 0x%04X\n",
279 HIWORD(DriverState
.Handler0
.Callback
),
280 LOWORD(DriverState
.Handler0
.Callback
),
283 /* Call the callback */
284 RunCallback16(&MouseContext
, DriverState
.Handler0
.Callback
);
297 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
299 /* Call the suitable handlers */
300 if ((DriverState
.Handlers
[i
].CallMask
& CallMask
) != 0 &&
301 DriverState
.Handlers
[i
].Callback
!= (ULONG
)NULL
)
304 * Set the parameters for the callback.
305 * NOTE: In text modes, the row and column will be reported
306 * as a multiple of the cell size, typically 8x8 pixels.
320 setBX(DriverState
.ButtonState
);
323 setSI(MICKEYS_PER_CELL_HORIZ
);
324 setDI(MICKEYS_PER_CELL_VERT
);
326 DPRINT1("Calling Handler[%d] %04X:%04X with CallMask 0x%04X\n",
328 HIWORD(DriverState
.Handlers
[i
].Callback
),
329 LOWORD(DriverState
.Handlers
[i
].Callback
),
332 /* Call the callback */
333 RunCallback16(&MouseContext
, DriverState
.Handlers
[i
].Callback
);
348 static inline VOID
DosUpdatePosition(PCOORD NewPosition
)
350 COORD Resolution
= VgaGetDisplayResolution();
352 /* Check for text mode */
353 if (!VgaGetDoubleVisionState(NULL
, NULL
))
359 if (DriverState
.ShowCount
> 0) EraseMouseCursor();
360 DriverState
.Position
= *NewPosition
;
361 if (DriverState
.ShowCount
> 0) PaintMouseCursor();
363 /* Call the mouse handlers */
364 CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
367 static inline VOID
DosUpdateButtons(BYTE ButtonState
) // WORD ButtonState
370 USHORT CallMask
= 0x0000; // We use MS MOUSE v1.0+ format
372 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
374 BOOLEAN OldState
= (DriverState
.ButtonState
>> i
) & 1;
375 BOOLEAN NewState
= (ButtonState
>> i
) & 1;
377 if (NewState
> OldState
)
380 DriverState
.PressCount
[i
]++;
381 DriverState
.LastPress
[i
] = DriverState
.Position
;
383 CallMask
|= (1 << (2 * i
+ 1));
385 else if (NewState
< OldState
)
388 DriverState
.ReleaseCount
[i
]++;
389 DriverState
.LastRelease
[i
] = DriverState
.Position
;
391 CallMask
|= (1 << (2 * i
+ 2));
395 DriverState
.ButtonState
= ButtonState
;
397 /* Call the mouse handlers */
398 CallMouseUserHandlers(CallMask
);
401 static VOID WINAPI
DosMouseIrq(LPWORD Stack
)
404 SHORT DeltaX
, DeltaY
;
408 /* Read the whole packet at once */
409 Flags
= IOReadB(PS2_DATA_PORT
);
410 PS2PortQueueRead(1); // NOTE: Should be a IOReadB! But see r67231
411 DeltaX
= IOReadB(PS2_DATA_PORT
);
412 PS2PortQueueRead(1); // NOTE: Should be a IOReadB! But see r67231
413 DeltaY
= IOReadB(PS2_DATA_PORT
);
415 /* Adjust the sign */
416 if (Flags
& MOUSE_X_SIGN
) DeltaX
= -DeltaX
;
417 if (Flags
& MOUSE_Y_SIGN
) DeltaY
= -DeltaY
;
419 /* Update the counters */
420 DriverState
.HorizCount
+= DeltaX
;
421 DriverState
.VertCount
+= DeltaY
;
424 * Get the absolute position directly from the mouse, this is the only
425 * way to perfectly synchronize the host and guest mouse pointer.
427 MouseGetDataFast(&Position
, &ButtonState
);
429 /* Call the update subroutines */
430 DosUpdatePosition(&Position
);
431 DosUpdateButtons(ButtonState
);
433 /* Complete the IRQ */
434 PicIRQComplete(LOBYTE(Stack
[STACK_INT_NUM
]));
437 static VOID WINAPI
DosMouseService(LPWORD Stack
)
446 DriverState
.ShowCount
= 0;
447 DriverState
.ButtonState
= 0;
449 /* Initialize the default clipping range */
450 DriverState
.MinX
= 0;
451 DriverState
.MaxX
= MOUSE_MAX_HORIZ
- 1;
452 DriverState
.MinY
= 0;
453 DriverState
.MaxY
= MOUSE_MAX_VERT
- 1;
455 /* Set the default text cursor */
456 DriverState
.TextCursor
.ScreenMask
= 0xFFFF; /* Display everything */
457 DriverState
.TextCursor
.CursorMask
= 0xFF00; /* ... but with inverted attributes */
459 /* Set the default graphics cursor */
460 DriverState
.GraphicsCursor
.HotSpot
.X
= 3;
461 DriverState
.GraphicsCursor
.HotSpot
.Y
= 1;
463 RtlCopyMemory(DriverState
.GraphicsCursor
.ScreenMask
,
464 DefaultGfxScreenMask
,
465 sizeof(DriverState
.GraphicsCursor
.ScreenMask
));
467 RtlCopyMemory(DriverState
.GraphicsCursor
.CursorMask
,
468 DefaultGfxCursorMask
,
469 sizeof(DriverState
.GraphicsCursor
.CursorMask
));
471 /* Initialize the counters */
472 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
474 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
476 DriverState
.PressCount
[i
] = DriverState
.ReleaseCount
[i
] = 0;
479 /* Return mouse information */
480 setAX(0xFFFF); // Hardware & driver installed
481 setBX(NUM_MOUSE_BUTTONS
);
486 /* Show Mouse Cursor */
489 DriverState
.ShowCount
++;
490 if (DriverState
.ShowCount
== 1) PaintMouseCursor();
495 /* Hide Mouse Cursor */
498 DriverState
.ShowCount
--;
499 if (DriverState
.ShowCount
== 0) EraseMouseCursor();
504 /* Return Position and Button Status */
507 COORD Position
= DriverState
.Position
;
508 ToMouseCoordinates(&Position
);
510 setBX(DriverState
.ButtonState
);
516 /* Position Mouse Cursor */
519 COORD Position
= { getCX(), getDX() };
520 FromMouseCoordinates(&Position
);
522 DriverState
.Position
= Position
;
526 /* Return Button Press Data */
529 WORD Button
= getBX();
530 COORD LastPress
= DriverState
.LastPress
[Button
];
531 ToMouseCoordinates(&LastPress
);
533 setAX(DriverState
.ButtonState
);
534 setBX(DriverState
.PressCount
[Button
]);
538 /* Reset the counter */
539 DriverState
.PressCount
[Button
] = 0;
544 /* Return Button Release Data */
547 WORD Button
= getBX();
548 COORD LastRelease
= DriverState
.LastRelease
[Button
];
549 ToMouseCoordinates(&LastRelease
);
551 setAX(DriverState
.ButtonState
);
552 setBX(DriverState
.ReleaseCount
[Button
]);
553 setCX(LastRelease
.X
);
554 setDX(LastRelease
.Y
);
556 /* Reset the counter */
557 DriverState
.ReleaseCount
[Button
] = 0;
563 /* Define Horizontal Cursor Range */
569 if (!VgaGetDoubleVisionState(NULL
, NULL
))
576 DPRINT("Setting mouse horizontal range: %u - %u\n", Min
, Max
);
577 DriverState
.MinX
= Min
;
578 DriverState
.MaxX
= Max
;
582 /* Define Vertical Cursor Range */
588 if (!VgaGetDoubleVisionState(NULL
, NULL
))
595 DPRINT("Setting mouse vertical range: %u - %u\n", Min
, Max
);
596 DriverState
.MinY
= Min
;
597 DriverState
.MaxY
= Max
;
601 /* Define Graphics Cursor */
604 PWORD MaskBitmap
= (PWORD
)SEG_OFF_TO_PTR(getES(), getDX());
606 DriverState
.GraphicsCursor
.HotSpot
.X
= getBX();
607 DriverState
.GraphicsCursor
.HotSpot
.Y
= getCX();
609 RtlCopyMemory(DriverState
.GraphicsCursor
.ScreenMask
,
611 sizeof(DriverState
.GraphicsCursor
.ScreenMask
));
613 RtlCopyMemory(DriverState
.GraphicsCursor
.CursorMask
,
615 sizeof(DriverState
.GraphicsCursor
.CursorMask
));
620 /* Define Text Cursor */
627 /* Define software cursor */
628 DriverState
.TextCursor
.ScreenMask
= getCX();
629 DriverState
.TextCursor
.CursorMask
= getDX();
631 else if (BX
== 0x0001)
633 /* Define hardware cursor */
634 DPRINT1("Defining hardware cursor is unimplemented\n");
636 // CX == start scan line
637 // DX == end scan line
641 DPRINT1("Invalid BX value 0x%04X\n", BX
);
647 /* Read Motion Counters */
650 setCX(DriverState
.HorizCount
);
651 setDX(DriverState
.VertCount
);
653 /* Reset the counters */
654 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
659 /* Define Interrupt Subroutine Parameters, compatible MS MOUSE v1.0+ */
662 DriverState
.Handler0
.CallMask
= getCX();
663 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
664 DPRINT1("Define callback 0x%04X, %04X:%04X\n",
665 DriverState
.Handler0
.CallMask
,
666 HIWORD(DriverState
.Handler0
.Callback
),
667 LOWORD(DriverState
.Handler0
.Callback
));
671 /* Define Mickey/Pixel Ratio */
674 /* This call should be completely ignored */
678 /* Set Exclusion Area */
679 // http://www.ctyme.com/intr/rb-5972.htm
680 // http://www.techhelpmanual.com/849-int_33h_0010h__set_exclusion_area.html
685 /* Define Double-Speed Threshold */
688 DPRINT1("INT 33h, AH=13h: Mouse double-speed threshold is UNSUPPORTED\n");
692 /* Exchange Interrupt Subroutines, compatible MS MOUSE v3.0+ (see function 0x0C) */
695 USHORT OldCallMask
= DriverState
.Handler0
.CallMask
;
696 ULONG OldCallback
= DriverState
.Handler0
.Callback
;
698 DriverState
.Handler0
.CallMask
= getCX();
699 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
700 DPRINT1("Exchange old callback 0x%04X, %04X:%04X with new callback 0x%04X, %04X:%04X\n",
704 DriverState
.Handler0
.CallMask
,
705 HIWORD(DriverState
.Handler0
.Callback
),
706 LOWORD(DriverState
.Handler0
.Callback
));
708 /* Return old callmask in CX and callback vector in ES:DX */
710 setES(HIWORD(OldCallback
));
711 setDX(LOWORD(OldCallback
));
715 /* Return Driver Storage Requirements */
718 setBX(sizeof(MOUSE_DRIVER_STATE
));
722 /* Save Driver State */
725 /* Check whether the user buffer has correct size and fail if not */
726 if (getBX() != sizeof(MOUSE_DRIVER_STATE
)) break;
728 *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX())) = DriverState
;
732 /* Restore Driver State */
735 /* Check whether the user buffer has correct size and fail if not */
736 if (getBX() != sizeof(MOUSE_DRIVER_STATE
)) break;
738 DriverState
= *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX()));
742 /* Set Alternate Mouse User Handler, compatible MS MOUSE v6.0+ */
746 * Up to three handlers can be defined by separate calls to this
747 * function, each with a different combination of shift states in
748 * the call mask; calling this function again with a call mask of
749 * 0000h undefines the specified handler (official documentation);
750 * specifying the same call mask and an address of 0000h:0000h
751 * undefines the handler (real life).
752 * See Ralf Brown: http://www.ctyme.com/intr/rb-5981.htm
753 * for more information.
757 USHORT CallMask
= getCX();
758 ULONG Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
759 BOOLEAN Success
= FALSE
;
761 DPRINT1("Define v6.0+ callback 0x%04X, %04X:%04X\n",
762 CallMask
, HIWORD(Callback
), LOWORD(Callback
));
764 if (CallMask
== 0x0000)
767 * Find the handler entry corresponding to the given
768 * callback and undefine it.
770 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
772 if (DriverState
.Handlers
[i
].Callback
== Callback
)
774 /* Found it, undefine the handler */
775 DriverState
.Handlers
[i
].CallMask
= 0x0000;
776 DriverState
.Handlers
[i
].Callback
= (ULONG
)NULL
;
782 else if (Callback
== (ULONG
)NULL
)
785 * Find the handler entry corresponding to the given
786 * callmask and undefine it.
788 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
790 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
792 /* Found it, undefine the handler */
793 DriverState
.Handlers
[i
].CallMask
= 0x0000;
794 DriverState
.Handlers
[i
].Callback
= (ULONG
)NULL
;
803 * Try to find a handler entry corresponding to the given
804 * callmask to redefine it, otherwise find an empty handler
805 * entry and set the new handler in there.
808 USHORT EmptyHandler
= 0xFFFF; // Invalid handler
810 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
812 /* Find the first empty handler */
813 if (EmptyHandler
== 0xFFFF &&
814 DriverState
.Handlers
[i
].CallMask
== 0x0000 &&
815 DriverState
.Handlers
[i
].Callback
== (ULONG
)NULL
)
820 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
822 /* Found it, redefine the handler */
823 DriverState
.Handlers
[i
].CallMask
= CallMask
;
824 DriverState
.Handlers
[i
].Callback
= Callback
;
831 * If we haven't found anything and we found
832 * an empty handler, set it.
834 if (!Success
&& EmptyHandler
!= 0xFFFF
835 /* && EmptyHandler < ARRAYSIZE(DriverState.Handlers) */)
837 DriverState
.Handlers
[EmptyHandler
].CallMask
= CallMask
;
838 DriverState
.Handlers
[EmptyHandler
].Callback
= Callback
;
843 /* If we failed, set error code */
844 if (!Success
) setAX(0xFFFF);
849 /* Return User Alternate Interrupt Vector, compatible MS MOUSE v6.0+ */
853 USHORT CallMask
= getCX();
855 BOOLEAN Success
= FALSE
;
858 * Find the handler entry corresponding to the given callmask.
860 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
862 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
865 Callback
= DriverState
.Handlers
[i
].Callback
;
873 /* Return the callback vector in BX:DX */
874 setBX(HIWORD(Callback
));
875 setDX(LOWORD(Callback
));
879 /* We failed, set error code */
886 /* Set Mouse Sensitivity */
889 DPRINT1("INT 33h, AH=1Ah: Mouse sensitivity is UNSUPPORTED\n");
891 // FIXME: Do that at runtime!
893 // UCHAR BH = getBH();
895 // BiosPs2Service(0x00);
896 // FIXME: Check for return status in AH and CF
902 /* Return Mouse Sensitivity */
905 DPRINT1("INT 33h, AH=1Bh: Mouse sensitivity is UNSUPPORTED\n");
907 /* Return default values */
908 setBX(50); // Horizontal speed
909 setCX(50); // Vertical speed
910 setDX(50); // Double speed threshold
912 // FIXME: Get that at runtime!
914 // UCHAR BH = getBH();
916 // BiosPs2Service(0x00);
917 // FIXME: Check for return status in AH and CF
923 /* Disable Mouse Driver */
926 /* INT 33h vector before the mouse driver was first installed */
927 setES(HIWORD(OldIntHandler
));
928 setBX(LOWORD(OldIntHandler
));
931 // UCHAR BH = getBH();
933 // BiosPs2Service(0x00);
934 // FIXME: Check for return status in AH and CF
939 /* Enable Mouse Driver */
943 // UCHAR BH = getBH();
945 // BiosPs2Service(0x00);
946 // FIXME: Check for return status in AH and CF
955 * See: http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte3sq8.htm
956 * for detailed information and differences with respect to subfunction 0x00:
957 * http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte3j74.htm
962 DriverState
.ShowCount
= 0;
963 DriverState
.ButtonState
= 0;
965 /* Initialize the default clipping range */
966 DriverState
.MinX
= 0;
967 DriverState
.MaxX
= MOUSE_MAX_HORIZ
- 1;
968 DriverState
.MinY
= 0;
969 DriverState
.MaxY
= MOUSE_MAX_VERT
- 1;
971 /* Initialize the counters */
972 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
974 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
976 DriverState
.PressCount
[i
] = DriverState
.ReleaseCount
[i
] = 0;
979 /* Return mouse information */
980 setAX(0xFFFF); // Hardware & driver installed
981 setBX(NUM_MOUSE_BUTTONS
);
986 /* Get Software Version, Mouse Type, and IRQ Number, compatible MS MOUSE v6.26+ */
989 setBX(MOUSE_VERSION
); // Version Number
992 * See Ralf Brown: http://www.ctyme.com/intr/rb-5993.htm
993 * for the list of possible values.
995 // FIXME: To be determined at runtime!
996 setCH(0x04); // PS/2 Type
997 setCL(0x00); // PS/2 Interrupt
1002 // BIOS Function INT 33h, AX = 0x0025 NOT IMPLEMENTED
1013 /* Get Maximum Virtual Coordinates */
1016 setBX(!DriverEnabled
);
1017 // FIXME: In fact the MaxX and MaxY here are
1018 // theoretical values for the current video mode.
1019 // They therefore can be different from the current
1021 // See http://www.ctyme.com/intr/rb-5995.htm
1022 // for more details.
1023 setCX(DriverState
.MaxX
);
1024 setDX(DriverState
.MaxY
);
1028 /* Get Current Minimum/Maximum Virtual Coordinates */
1031 setAX(DriverState
.MinX
);
1032 setBX(DriverState
.MinY
);
1033 setCX(DriverState
.MaxX
);
1034 setDX(DriverState
.MaxY
);
1042 * Related to http://www.ctyme.com/intr/rb-5985.htm
1043 * INT 33h, AX=001Ch "SET INTERRUPT RATE":
1045 * Values for mouse interrupt rate:
1047 00h no interrupts allowed
1056 /* Return Pointer to Copyright String */
1059 setES(MouseDataSegment
);
1060 setDI(FIELD_OFFSET(MOUSE_DRIVER
, Copyright
));
1064 /* Get Version String (pointer) */
1068 * The format of the version "string" is:
1069 * Offset Size Description
1070 * 00h BYTE major version
1071 * 01h BYTE minor version (BCD)
1073 setES(MouseDataSegment
);
1074 setDI(FIELD_OFFSET(MOUSE_DRIVER
, Version
));
1080 DPRINT1("BIOS Function INT 33h, AX = 0x%04X NOT IMPLEMENTED\n", getAX());
1085 /* PUBLIC FUNCTIONS ***********************************************************/
1088 VOID
DosMouseEnable(VOID
)
1090 if (DriverEnabled
) return;
1092 DriverEnabled
= TRUE
;
1094 /* Get the old IRQ handler */
1095 OldIrqHandler
= ((PDWORD
)BaseAddress
)[MOUSE_IRQ_INT
];
1097 /* Set the IRQ handler */
1098 RegisterInt32(MAKELONG(FIELD_OFFSET(MOUSE_DRIVER
, MouseIrqInt16Stub
), MouseDataSegment
),
1099 MOUSE_IRQ_INT
, DosMouseIrq
, NULL
);
1103 VOID
DosMouseDisable(VOID
)
1105 if (!DriverEnabled
) return;
1107 /* Restore the old IRQ handler */
1108 ((PDWORD
)BaseAddress
)[MOUSE_IRQ_INT
] = OldIrqHandler
;
1110 DriverEnabled
= FALSE
;
1113 BOOLEAN
DosMouseInitialize(VOID
)
1115 /* Initialize some memory for storing our data that should be available to DOS */
1116 MouseDataSegment
= DosAllocateMemory(sizeof(MOUSE_DRIVER
), NULL
);
1117 if (MouseDataSegment
== 0) return FALSE
;
1118 MouseData
= (PMOUSE_DRIVER
)SEG_OFF_TO_PTR(MouseDataSegment
, 0x0000);
1120 /* Initialize the callback context */
1121 InitializeContext(&MouseContext
, MouseDataSegment
, FIELD_OFFSET(MOUSE_DRIVER
, MouseContextScratch
));
1123 /* Clear the state */
1124 RtlZeroMemory(&DriverState
, sizeof(DriverState
));
1126 /* Mouse Driver Copyright */
1127 RtlCopyMemory(MouseData
->Copyright
, MouseCopyright
, sizeof(MouseCopyright
)-1);
1129 /* Mouse Driver Version in BCD format, compatible MS-MOUSE */
1130 MouseData
->Version
= MAKEWORD(MOUSE_VERSION
/0x0100, MOUSE_VERSION
%0x0100);
1132 /* Get the old mouse service interrupt handler */
1133 OldIntHandler
= ((PDWORD
)BaseAddress
)[DOS_MOUSE_INTERRUPT
];
1135 /* Initialize the interrupt handler */
1136 RegisterInt32(MAKELONG(FIELD_OFFSET(MOUSE_DRIVER
, MouseDosInt16Stub
), MouseDataSegment
),
1137 DOS_MOUSE_INTERRUPT
, DosMouseService
, NULL
);
1140 // UCHAR BH = getBH();
1142 // BiosPs2Service(0x00);
1143 // FIXME: Check for return status in AH and CF
1149 VOID
DosMouseCleanup(VOID
)
1151 if (DriverState
.ShowCount
> 0) EraseMouseCursor();
1153 // UCHAR BH = getBH();
1155 // BiosPs2Service(0x00);
1156 // FIXME: Check for return status in AH and CF
1159 /* Restore the old mouse service interrupt handler */
1160 ((PDWORD
)BaseAddress
)[DOS_MOUSE_INTERRUPT
] = OldIntHandler
;
1162 DosFreeMemory(MouseDataSegment
);
1163 MouseDataSegment
= 0;