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>
14 /* PRIVATE VARIABLES **********************************************************/
16 static const CHAR MouseCopyright
[] =
17 "ReactOS PS/2 16/32-bit Mouse Driver Compatible MS-MOUSE 6.26\r\n"
18 "Version "KERNEL_VERSION_STR
" (Build "KERNEL_VERSION_BUILD_STR
")\r\n"
19 "Copyright (C) ReactOS Team 1996-"COPYRIGHT_YEAR
"\0";
23 typedef struct _MOUSE_DRIVER
25 CHAR Copyright
[sizeof(MouseCopyright
)];
27 BYTE MouseContextScratch
[TRAMPOLINE_SIZE
];
28 BYTE MouseDosInt16Stub
[Int16To32StubSize
];
29 BYTE MouseIrqInt16Stub
[Int16To32StubSize
];
30 } MOUSE_DRIVER
, *PMOUSE_DRIVER
;
34 /* Global data contained in guest memory */
35 static WORD MouseDataSegment
;
36 static PMOUSE_DRIVER MouseData
;
37 static CALLBACK16 MouseContext
;
39 #define MICKEYS_PER_CELL_HORIZ 8
40 #define MICKEYS_PER_CELL_VERT 16
42 static BOOLEAN DriverEnabled
= FALSE
;
43 static MOUSE_DRIVER_STATE DriverState
;
44 static DWORD OldIrqHandler
;
45 static DWORD OldIntHandler
;
47 static WORD DefaultGfxScreenMask
[16] =
49 0xC3FF, // 1100001111111111
50 0xC0FF, // 1100000011111111
51 0xC07F, // 1100000001111111
52 0xC01F, // 1100000000011111
53 0xC00F, // 1100000000001111
54 0xC007, // 1100000000000111
55 0xC003, // 1100000000000011
56 0xC007, // 1100000000000111
57 0xC01F, // 1100000000011111
58 0xC01F, // 1100000000011111
59 0xC00F, // 1100000000001111
60 0xC60F, // 1100011000001111
61 0xFF07, // 1111111100000111
62 0xFF07, // 1111111100000111
63 0xFF87, // 1111111110000111
64 0xFFCF, // 1111111111001111
67 static WORD DefaultGfxCursorMask
[16] =
69 0x0000, // 0000000000000000
70 0x1C00, // 0001110000000000
71 0x1F00, // 0001111100000000
72 0x1F80, // 0001111110000000
73 0x1FE0, // 0001111111100000
74 0x1FF0, // 0001111111110000
75 0x1FF8, // 0001111111111000
76 0x1FE0, // 0001111111100000
77 0x1FC0, // 0001111111000000
78 0x1FC0, // 0001111111000000
79 0x19E0, // 0001100111100000
80 0x00E0, // 0000000011100000
81 0x0070, // 0000000001110000
82 0x0070, // 0000000001110000
83 0x0030, // 0000000000110000
84 0x0000, // 0000000000000000
87 /* PRIVATE FUNCTIONS **********************************************************/
90 VOID
BiosPs2Service(UCHAR Function
)
94 // USHORT BX = getBX();
98 * AL contains the character to print (already set),
99 * BL contains the character attribute,
100 * BH contains the video page to use.
102 // setBL(DOS_CHAR_ATTRIBUTE);
103 // setBH(Bda->VideoPage);
106 /* Call the BIOS INT 15h, AH=C2h "Pointing Device BIOS Interface (PS)" */
108 Int32Call(&MouseContext
, BIOS_MISC_INTERRUPT
);
110 /* Restore AX and BX */
117 static VOID
DosMouseEnable(VOID
);
118 static VOID
DosMouseDisable(VOID
);
121 static VOID
PaintMouseCursor(VOID
)
123 COORD Position
= DriverState
.Position
;
125 /* Apply the clipping rectangle */
126 if (Position
.X
< DriverState
.MinX
) Position
.X
= DriverState
.MinX
;
127 if (Position
.X
> DriverState
.MaxX
) Position
.X
= DriverState
.MaxX
;
128 if (Position
.Y
< DriverState
.MinY
) Position
.Y
= DriverState
.MinY
;
129 if (Position
.Y
> DriverState
.MaxY
) Position
.Y
= DriverState
.MaxY
;
131 if (Bda
->VideoMode
<= 3)
134 WORD CellX
= Position
.X
/ 8;
135 WORD CellY
= Position
.Y
/ 8;
136 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
);
138 EmulatorReadMemory(&EmulatorContext
,
140 + (CellY
* Bda
->ScreenColumns
+ CellX
) * sizeof(WORD
),
144 DriverState
.Character
= Character
;
145 Character
&= DriverState
.TextCursor
.ScreenMask
;
146 Character
^= DriverState
.TextCursor
.CursorMask
;
148 EmulatorWriteMemory(&EmulatorContext
,
150 + (CellY
* Bda
->ScreenColumns
+ CellX
) * sizeof(WORD
),
156 // TODO: NOT IMPLEMENTED
161 static VOID
EraseMouseCursor(VOID
)
163 COORD Position
= DriverState
.Position
;
165 /* Apply the clipping rectangle */
166 if (Position
.X
< DriverState
.MinX
) Position
.X
= DriverState
.MinX
;
167 if (Position
.X
> DriverState
.MaxX
) Position
.X
= DriverState
.MaxX
;
168 if (Position
.Y
< DriverState
.MinY
) Position
.Y
= DriverState
.MinY
;
169 if (Position
.Y
> DriverState
.MaxY
) Position
.Y
= DriverState
.MaxY
;
171 if (Bda
->VideoMode
<= 3)
173 WORD CellX
= Position
.X
/ 8;
174 WORD CellY
= Position
.Y
/ 8;
175 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
);
177 EmulatorWriteMemory(&EmulatorContext
,
179 + (CellY
* Bda
->ScreenColumns
+ CellX
) * sizeof(WORD
),
180 (LPVOID
)&DriverState
.Character
,
185 // TODO: NOT IMPLEMENTED
190 static VOID
ToMouseCoordinates(PCOORD Position
)
192 COORD Resolution
= VgaGetDisplayResolution();
193 DWORD Width
= DriverState
.MaxX
- DriverState
.MinX
+ 1;
194 DWORD Height
= DriverState
.MaxY
- DriverState
.MinY
+ 1;
196 if (!VgaGetDoubleVisionState(NULL
, NULL
))
202 Position
->X
= DriverState
.MinX
+ ((Position
->X
* Width
) / Resolution
.X
);
203 Position
->Y
= DriverState
.MinY
+ ((Position
->Y
* Height
) / Resolution
.Y
);
206 static VOID
FromMouseCoordinates(PCOORD Position
)
208 COORD Resolution
= VgaGetDisplayResolution();
209 DWORD Width
= DriverState
.MaxX
- DriverState
.MinX
+ 1;
210 DWORD Height
= DriverState
.MaxY
- DriverState
.MinY
+ 1;
212 if (!VgaGetDoubleVisionState(NULL
, NULL
))
218 Position
->X
= ((Position
->X
- DriverState
.MinX
) * Resolution
.X
) / Width
;
219 Position
->Y
= ((Position
->Y
- DriverState
.MinY
) * Resolution
.Y
) / Height
;
222 static VOID
CallMouseUserHandlers(USHORT CallMask
)
225 USHORT AX
, BX
, CX
, DX
, BP
, SI
, DI
, DS
, ES
;
226 COORD Position
= DriverState
.Position
;
228 ToMouseCoordinates(&Position
);
231 if ((DriverState
.Handler0
.CallMask
& CallMask
) != 0 &&
232 DriverState
.Handler0
.Callback
!= (ULONG
)NULL
)
235 * Set the parameters for the callback.
236 * NOTE: In text modes, the row and column will be reported
237 * as a multiple of the cell size, typically 8x8 pixels.
251 setBX(DriverState
.ButtonState
);
254 setSI(MICKEYS_PER_CELL_HORIZ
);
255 setDI(MICKEYS_PER_CELL_VERT
);
257 DPRINT("Calling Handler0 %04X:%04X with CallMask 0x%04X\n",
258 HIWORD(DriverState
.Handler0
.Callback
),
259 LOWORD(DriverState
.Handler0
.Callback
),
262 /* Call the callback */
263 RunCallback16(&MouseContext
, DriverState
.Handler0
.Callback
);
276 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
278 /* Call the suitable handlers */
279 if ((DriverState
.Handlers
[i
].CallMask
& CallMask
) != 0 &&
280 DriverState
.Handlers
[i
].Callback
!= (ULONG
)NULL
)
283 * Set the parameters for the callback.
284 * NOTE: In text modes, the row and column will be reported
285 * as a multiple of the cell size, typically 8x8 pixels.
299 setBX(DriverState
.ButtonState
);
302 setSI(MICKEYS_PER_CELL_HORIZ
);
303 setDI(MICKEYS_PER_CELL_VERT
);
305 DPRINT1("Calling Handler[%d] %04X:%04X with CallMask 0x%04X\n",
307 HIWORD(DriverState
.Handlers
[i
].Callback
),
308 LOWORD(DriverState
.Handlers
[i
].Callback
),
311 /* Call the callback */
312 RunCallback16(&MouseContext
, DriverState
.Handlers
[i
].Callback
);
327 static inline VOID
DosUpdatePosition(PCOORD NewPosition
)
329 COORD Resolution
= VgaGetDisplayResolution();
331 /* Check for text mode */
332 if (!VgaGetDoubleVisionState(NULL
, NULL
))
338 if (DriverState
.ShowCount
> 0) EraseMouseCursor();
339 DriverState
.Position
= *NewPosition
;
340 if (DriverState
.ShowCount
> 0) PaintMouseCursor();
342 /* Call the mouse handlers */
343 CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
346 static inline VOID
DosUpdateButtons(BYTE ButtonState
) // WORD ButtonState
349 USHORT CallMask
= 0x0000; // We use MS MOUSE v1.0+ format
351 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
353 BOOLEAN OldState
= (DriverState
.ButtonState
>> i
) & 1;
354 BOOLEAN NewState
= (ButtonState
>> i
) & 1;
356 if (NewState
> OldState
)
359 DriverState
.PressCount
[i
]++;
360 DriverState
.LastPress
[i
] = DriverState
.Position
;
362 CallMask
|= (1 << (2 * i
+ 1));
364 else if (NewState
< OldState
)
367 DriverState
.ReleaseCount
[i
]++;
368 DriverState
.LastRelease
[i
] = DriverState
.Position
;
370 CallMask
|= (1 << (2 * i
+ 2));
374 DriverState
.ButtonState
= ButtonState
;
376 /* Call the mouse handlers */
377 CallMouseUserHandlers(CallMask
);
380 static VOID WINAPI
DosMouseIrq(LPWORD Stack
)
383 SHORT DeltaX
, DeltaY
;
387 /* Read the whole packet at once */
388 Flags
= IOReadB(PS2_DATA_PORT
);
389 PS2PortQueueRead(1); // NOTE: Should be a IOReadB! But see r67231
390 DeltaX
= IOReadB(PS2_DATA_PORT
);
391 PS2PortQueueRead(1); // NOTE: Should be a IOReadB! But see r67231
392 DeltaY
= IOReadB(PS2_DATA_PORT
);
394 /* Adjust the sign */
395 if (Flags
& MOUSE_X_SIGN
) DeltaX
= -DeltaX
;
396 if (Flags
& MOUSE_Y_SIGN
) DeltaY
= -DeltaY
;
398 /* Update the counters */
399 DriverState
.HorizCount
+= DeltaX
;
400 DriverState
.VertCount
+= DeltaY
;
403 * Get the absolute position directly from the mouse, this is the only
404 * way to perfectly synchronize the host and guest mouse pointer.
406 MouseGetDataFast(&Position
, &ButtonState
);
408 /* Call the update subroutines */
409 DosUpdatePosition(&Position
);
410 DosUpdateButtons(ButtonState
);
412 /* Complete the IRQ */
413 PicIRQComplete(LOBYTE(Stack
[STACK_INT_NUM
]));
416 static VOID WINAPI
DosMouseService(LPWORD Stack
)
425 DriverState
.ShowCount
= 0;
426 DriverState
.ButtonState
= 0;
428 /* Initialize the default clipping range */
429 DriverState
.MinX
= 0;
430 DriverState
.MaxX
= MOUSE_MAX_HORIZ
- 1;
431 DriverState
.MinY
= 0;
432 DriverState
.MaxY
= MOUSE_MAX_VERT
- 1;
434 /* Set the default text cursor */
435 DriverState
.TextCursor
.ScreenMask
= 0xFFFF; /* Display everything */
436 DriverState
.TextCursor
.CursorMask
= 0xFF00; /* ... but with inverted attributes */
438 /* Set the default graphics cursor */
439 DriverState
.GraphicsCursor
.HotSpot
.X
= 3;
440 DriverState
.GraphicsCursor
.HotSpot
.Y
= 1;
442 RtlCopyMemory(DriverState
.GraphicsCursor
.ScreenMask
,
443 DefaultGfxScreenMask
,
444 sizeof(DriverState
.GraphicsCursor
.ScreenMask
));
446 RtlCopyMemory(DriverState
.GraphicsCursor
.CursorMask
,
447 DefaultGfxCursorMask
,
448 sizeof(DriverState
.GraphicsCursor
.CursorMask
));
450 /* Initialize the counters */
451 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
453 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
455 DriverState
.PressCount
[i
] = DriverState
.ReleaseCount
[i
] = 0;
458 /* Return mouse information */
459 setAX(0xFFFF); // Hardware & driver installed
460 setBX(NUM_MOUSE_BUTTONS
);
465 /* Show Mouse Cursor */
468 DriverState
.ShowCount
++;
469 if (DriverState
.ShowCount
== 1) PaintMouseCursor();
474 /* Hide Mouse Cursor */
477 DriverState
.ShowCount
--;
478 if (DriverState
.ShowCount
== 0) EraseMouseCursor();
483 /* Return Position and Button Status */
486 COORD Position
= DriverState
.Position
;
487 ToMouseCoordinates(&Position
);
489 setBX(DriverState
.ButtonState
);
495 /* Position Mouse Cursor */
498 COORD Position
= { getCX(), getDX() };
499 FromMouseCoordinates(&Position
);
501 DriverState
.Position
= Position
;
505 /* Return Button Press Data */
508 WORD Button
= getBX();
509 COORD LastPress
= DriverState
.LastPress
[Button
];
510 ToMouseCoordinates(&LastPress
);
512 setAX(DriverState
.ButtonState
);
513 setBX(DriverState
.PressCount
[Button
]);
517 /* Reset the counter */
518 DriverState
.PressCount
[Button
] = 0;
523 /* Return Button Release Data */
526 WORD Button
= getBX();
527 COORD LastRelease
= DriverState
.LastRelease
[Button
];
528 ToMouseCoordinates(&LastRelease
);
530 setAX(DriverState
.ButtonState
);
531 setBX(DriverState
.ReleaseCount
[Button
]);
532 setCX(LastRelease
.X
);
533 setDX(LastRelease
.Y
);
535 /* Reset the counter */
536 DriverState
.ReleaseCount
[Button
] = 0;
542 /* Define Horizontal Cursor Range */
548 if (!VgaGetDoubleVisionState(NULL
, NULL
))
555 DPRINT("Setting mouse horizontal range: %u - %u\n", Min
, Max
);
556 DriverState
.MinX
= Min
;
557 DriverState
.MaxX
= Max
;
561 /* Define Vertical Cursor Range */
567 if (!VgaGetDoubleVisionState(NULL
, NULL
))
574 DPRINT("Setting mouse vertical range: %u - %u\n", Min
, Max
);
575 DriverState
.MinY
= Min
;
576 DriverState
.MaxY
= Max
;
580 /* Define Graphics Cursor */
583 PWORD MaskBitmap
= (PWORD
)SEG_OFF_TO_PTR(getES(), getDX());
585 DriverState
.GraphicsCursor
.HotSpot
.X
= getBX();
586 DriverState
.GraphicsCursor
.HotSpot
.Y
= getCX();
588 RtlCopyMemory(DriverState
.GraphicsCursor
.ScreenMask
,
590 sizeof(DriverState
.GraphicsCursor
.ScreenMask
));
592 RtlCopyMemory(DriverState
.GraphicsCursor
.CursorMask
,
594 sizeof(DriverState
.GraphicsCursor
.CursorMask
));
599 /* Define Text Cursor */
606 /* Define software cursor */
607 DriverState
.TextCursor
.ScreenMask
= getCX();
608 DriverState
.TextCursor
.CursorMask
= getDX();
610 else if (BX
== 0x0001)
612 /* Define hardware cursor */
613 DPRINT1("Defining hardware cursor is unimplemented\n");
615 // CX == start scan line
616 // DX == end scan line
620 DPRINT1("Invalid BX value 0x%04X\n", BX
);
626 /* Read Motion Counters */
629 setCX(DriverState
.HorizCount
);
630 setDX(DriverState
.VertCount
);
632 /* Reset the counters */
633 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
638 /* Define Interrupt Subroutine Parameters, compatible MS MOUSE v1.0+ */
641 DriverState
.Handler0
.CallMask
= getCX();
642 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
643 DPRINT1("Define callback 0x%04X, %04X:%04X\n",
644 DriverState
.Handler0
.CallMask
,
645 HIWORD(DriverState
.Handler0
.Callback
),
646 LOWORD(DriverState
.Handler0
.Callback
));
650 /* Define Mickey/Pixel Ratio */
653 /* This call should be completely ignored */
657 /* Set Exclusion Area */
658 // http://www.ctyme.com/intr/rb-5972.htm
659 // http://www.techhelpmanual.com/849-int_33h_0010h__set_exclusion_area.html
664 /* Define Double-Speed Threshold */
667 DPRINT1("INT 33h, AH=13h: Mouse double-speed threshold is UNSUPPORTED\n");
671 /* Exchange Interrupt Subroutines, compatible MS MOUSE v3.0+ (see function 0x0C) */
674 USHORT OldCallMask
= DriverState
.Handler0
.CallMask
;
675 ULONG OldCallback
= DriverState
.Handler0
.Callback
;
677 DriverState
.Handler0
.CallMask
= getCX();
678 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
679 DPRINT1("Exchange old callback 0x%04X, %04X:%04X with new callback 0x%04X, %04X:%04X\n",
683 DriverState
.Handler0
.CallMask
,
684 HIWORD(DriverState
.Handler0
.Callback
),
685 LOWORD(DriverState
.Handler0
.Callback
));
687 /* Return old callmask in CX and callback vector in ES:DX */
689 setES(HIWORD(OldCallback
));
690 setDX(LOWORD(OldCallback
));
694 /* Return Driver Storage Requirements */
697 setBX(sizeof(MOUSE_DRIVER_STATE
));
701 /* Save Driver State */
704 /* Check whether the user buffer has correct size and fail if not */
705 if (getBX() != sizeof(MOUSE_DRIVER_STATE
)) break;
707 *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX())) = DriverState
;
711 /* Restore Driver State */
714 /* Check whether the user buffer has correct size and fail if not */
715 if (getBX() != sizeof(MOUSE_DRIVER_STATE
)) break;
717 DriverState
= *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX()));
721 /* Set Alternate Mouse User Handler, compatible MS MOUSE v6.0+ */
725 * Up to three handlers can be defined by separate calls to this
726 * function, each with a different combination of shift states in
727 * the call mask; calling this function again with a call mask of
728 * 0000h undefines the specified handler (official documentation);
729 * specifying the same call mask and an address of 0000h:0000h
730 * undefines the handler (real life).
731 * See Ralf Brown: http://www.ctyme.com/intr/rb-5981.htm
732 * for more information.
736 USHORT CallMask
= getCX();
737 ULONG Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
738 BOOLEAN Success
= FALSE
;
740 DPRINT1("Define v6.0+ callback 0x%04X, %04X:%04X\n",
741 CallMask
, HIWORD(Callback
), LOWORD(Callback
));
743 if (CallMask
== 0x0000)
746 * Find the handler entry corresponding to the given
747 * callback and undefine it.
749 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
751 if (DriverState
.Handlers
[i
].Callback
== Callback
)
753 /* Found it, undefine the handler */
754 DriverState
.Handlers
[i
].CallMask
= 0x0000;
755 DriverState
.Handlers
[i
].Callback
= (ULONG
)NULL
;
761 else if (Callback
== (ULONG
)NULL
)
764 * Find the handler entry corresponding to the given
765 * callmask and undefine it.
767 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
769 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
771 /* Found it, undefine the handler */
772 DriverState
.Handlers
[i
].CallMask
= 0x0000;
773 DriverState
.Handlers
[i
].Callback
= (ULONG
)NULL
;
782 * Try to find a handler entry corresponding to the given
783 * callmask to redefine it, otherwise find an empty handler
784 * entry and set the new handler in there.
787 USHORT EmptyHandler
= 0xFFFF; // Invalid handler
789 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
791 /* Find the first empty handler */
792 if (EmptyHandler
== 0xFFFF &&
793 DriverState
.Handlers
[i
].CallMask
== 0x0000 &&
794 DriverState
.Handlers
[i
].Callback
== (ULONG
)NULL
)
799 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
801 /* Found it, redefine the handler */
802 DriverState
.Handlers
[i
].CallMask
= CallMask
;
803 DriverState
.Handlers
[i
].Callback
= Callback
;
810 * If we haven't found anything and we found
811 * an empty handler, set it.
813 if (!Success
&& EmptyHandler
!= 0xFFFF
814 /* && EmptyHandler < ARRAYSIZE(DriverState.Handlers) */)
816 DriverState
.Handlers
[EmptyHandler
].CallMask
= CallMask
;
817 DriverState
.Handlers
[EmptyHandler
].Callback
= Callback
;
822 /* If we failed, set error code */
823 if (!Success
) setAX(0xFFFF);
828 /* Return User Alternate Interrupt Vector, compatible MS MOUSE v6.0+ */
832 USHORT CallMask
= getCX();
834 BOOLEAN Success
= FALSE
;
837 * Find the handler entry corresponding to the given callmask.
839 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
841 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
844 Callback
= DriverState
.Handlers
[i
].Callback
;
852 /* Return the callback vector in BX:DX */
853 setBX(HIWORD(Callback
));
854 setDX(LOWORD(Callback
));
858 /* We failed, set error code */
865 /* Set Mouse Sensitivity */
868 DPRINT1("INT 33h, AH=1Ah: Mouse sensitivity is UNSUPPORTED\n");
870 // FIXME: Do that at runtime!
872 // UCHAR BH = getBH();
874 // BiosPs2Service(0x00);
875 // FIXME: Check for return status in AH and CF
881 /* Return Mouse Sensitivity */
884 DPRINT1("INT 33h, AH=1Bh: Mouse sensitivity is UNSUPPORTED\n");
886 /* Return default values */
887 setBX(50); // Horizontal speed
888 setCX(50); // Vertical speed
889 setDX(50); // Double speed threshold
891 // FIXME: Get that at runtime!
893 // UCHAR BH = getBH();
895 // BiosPs2Service(0x00);
896 // FIXME: Check for return status in AH and CF
902 /* Disable Mouse Driver */
905 /* INT 33h vector before the mouse driver was first installed */
906 setES(HIWORD(OldIntHandler
));
907 setBX(LOWORD(OldIntHandler
));
910 // UCHAR BH = getBH();
912 // BiosPs2Service(0x00);
913 // FIXME: Check for return status in AH and CF
918 /* Enable Mouse Driver */
922 // UCHAR BH = getBH();
924 // BiosPs2Service(0x00);
925 // FIXME: Check for return status in AH and CF
934 * See: http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte3sq8.htm
935 * for detailed information and differences with respect to subfunction 0x00:
936 * http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte3j74.htm
941 DriverState
.ShowCount
= 0;
942 DriverState
.ButtonState
= 0;
944 /* Initialize the default clipping range */
945 DriverState
.MinX
= 0;
946 DriverState
.MaxX
= MOUSE_MAX_HORIZ
- 1;
947 DriverState
.MinY
= 0;
948 DriverState
.MaxY
= MOUSE_MAX_VERT
- 1;
950 /* Initialize the counters */
951 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
953 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
955 DriverState
.PressCount
[i
] = DriverState
.ReleaseCount
[i
] = 0;
958 /* Return mouse information */
959 setAX(0xFFFF); // Hardware & driver installed
960 setBX(NUM_MOUSE_BUTTONS
);
965 /* Get Software Version, Mouse Type, and IRQ Number, compatible MS MOUSE v6.26+ */
968 setBX(MOUSE_VERSION
); // Version Number
971 * See Ralf Brown: http://www.ctyme.com/intr/rb-5993.htm
972 * for the list of possible values.
974 // FIXME: To be determined at runtime!
975 setCH(0x04); // PS/2 Type
976 setCL(0x00); // PS/2 Interrupt
981 // BIOS Function INT 33h, AX = 0x0025 NOT IMPLEMENTED
992 /* Get Maximum Virtual Coordinates */
995 setBX(!DriverEnabled
);
996 // FIXME: In fact the MaxX and MaxY here are
997 // theoretical values for the current video mode.
998 // They therefore can be different from the current
1000 // See http://www.ctyme.com/intr/rb-5995.htm
1001 // for more details.
1002 setCX(DriverState
.MaxX
);
1003 setDX(DriverState
.MaxY
);
1007 /* Get Current Minimum/Maximum Virtual Coordinates */
1010 setAX(DriverState
.MinX
);
1011 setBX(DriverState
.MinY
);
1012 setCX(DriverState
.MaxX
);
1013 setDX(DriverState
.MaxY
);
1021 * Related to http://www.ctyme.com/intr/rb-5985.htm
1022 * INT 33h, AX=001Ch "SET INTERRUPT RATE":
1024 * Values for mouse interrupt rate:
1026 00h no interrupts allowed
1035 /* Return Pointer to Copyright String */
1038 setES(MouseDataSegment
);
1039 setDI(FIELD_OFFSET(MOUSE_DRIVER
, Copyright
));
1043 /* Get Version String (pointer) */
1047 * The format of the version "string" is:
1048 * Offset Size Description
1049 * 00h BYTE major version
1050 * 01h BYTE minor version (BCD)
1052 setES(MouseDataSegment
);
1053 setDI(FIELD_OFFSET(MOUSE_DRIVER
, Version
));
1059 DPRINT1("BIOS Function INT 33h, AX = 0x%04X NOT IMPLEMENTED\n", getAX());
1064 /* PUBLIC FUNCTIONS ***********************************************************/
1067 VOID
DosMouseEnable(VOID
)
1069 if (DriverEnabled
) return;
1071 DriverEnabled
= TRUE
;
1073 /* Get the old IRQ handler */
1074 OldIrqHandler
= ((PDWORD
)BaseAddress
)[MOUSE_IRQ_INT
];
1076 /* Set the IRQ handler */
1077 RegisterInt32(MAKELONG(FIELD_OFFSET(MOUSE_DRIVER
, MouseIrqInt16Stub
), MouseDataSegment
),
1078 MOUSE_IRQ_INT
, DosMouseIrq
, NULL
);
1082 VOID
DosMouseDisable(VOID
)
1084 if (!DriverEnabled
) return;
1086 /* Restore the old IRQ handler */
1087 ((PDWORD
)BaseAddress
)[MOUSE_IRQ_INT
] = OldIrqHandler
;
1089 DriverEnabled
= FALSE
;
1092 BOOLEAN
DosMouseInitialize(VOID
)
1094 /* Initialize some memory for storing our data that should be available to DOS */
1095 MouseDataSegment
= DosAllocateMemory(sizeof(MOUSE_DRIVER
), NULL
);
1096 if (MouseDataSegment
== 0) return FALSE
;
1097 MouseData
= (PMOUSE_DRIVER
)SEG_OFF_TO_PTR(MouseDataSegment
, 0x0000);
1099 /* Initialize the callback context */
1100 InitializeContext(&MouseContext
, MouseDataSegment
, FIELD_OFFSET(MOUSE_DRIVER
, MouseContextScratch
));
1102 /* Clear the state */
1103 RtlZeroMemory(&DriverState
, sizeof(DriverState
));
1105 /* Mouse Driver Copyright */
1106 RtlCopyMemory(MouseData
->Copyright
, MouseCopyright
, sizeof(MouseCopyright
)-1);
1108 /* Mouse Driver Version in BCD format, compatible MS-MOUSE */
1109 MouseData
->Version
= MAKEWORD(MOUSE_VERSION
/0x0100, MOUSE_VERSION
%0x0100);
1111 /* Get the old mouse service interrupt handler */
1112 OldIntHandler
= ((PDWORD
)BaseAddress
)[DOS_MOUSE_INTERRUPT
];
1114 /* Initialize the interrupt handler */
1115 RegisterInt32(MAKELONG(FIELD_OFFSET(MOUSE_DRIVER
, MouseDosInt16Stub
), MouseDataSegment
),
1116 DOS_MOUSE_INTERRUPT
, DosMouseService
, NULL
);
1119 // UCHAR BH = getBH();
1121 // BiosPs2Service(0x00);
1122 // FIXME: Check for return status in AH and CF
1128 VOID
DosMouseCleanup(VOID
)
1130 if (DriverState
.ShowCount
> 0) EraseMouseCursor();
1132 // UCHAR BH = getBH();
1134 // BiosPs2Service(0x00);
1135 // FIXME: Check for return status in AH and CF
1138 /* Restore the old mouse service interrupt handler */
1139 ((PDWORD
)BaseAddress
)[DOS_MOUSE_INTERRUPT
] = OldIntHandler
;
1141 DosFreeMemory(MouseDataSegment
);
1142 MouseDataSegment
= 0;