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"
29 #include "../console/video.h"
33 #include "bios/bios.h"
34 #include "bios/bios32/bios32p.h"
38 #include "dos32krnl/memory.h"
40 /* PRIVATE VARIABLES **********************************************************/
42 static const CHAR MouseCopyright
[] =
43 "ReactOS PS/2 16/32-bit Mouse Driver Compatible MS-MOUSE 6.26\r\n"
44 "Version "KERNEL_VERSION_STR
" (Build "KERNEL_VERSION_BUILD_STR
")\r\n"
45 "Copyright (C) ReactOS Team 1996-"COPYRIGHT_YEAR
"\0";
49 typedef struct _MOUSE_DRIVER
51 CHAR Copyright
[sizeof(MouseCopyright
)];
53 BYTE MouseContextScratch
[TRAMPOLINE_SIZE
];
54 BYTE MouseDosInt16Stub
[Int16To32StubSize
];
55 BYTE MouseIrqInt16Stub
[Int16To32StubSize
];
56 } MOUSE_DRIVER
, *PMOUSE_DRIVER
;
60 /* Global data contained in guest memory */
61 static WORD MouseDataSegment
;
62 static PMOUSE_DRIVER MouseData
;
63 static CALLBACK16 MouseContext
;
65 #define MICKEYS_PER_CELL_HORIZ 8
66 #define MICKEYS_PER_CELL_VERT 16
68 static BOOLEAN DriverEnabled
= FALSE
;
69 static MOUSE_DRIVER_STATE DriverState
;
70 static DWORD OldIrqHandler
;
71 static DWORD OldIntHandler
;
73 static WORD DefaultGfxScreenMask
[16] =
75 0xE7FF, // 1110011111111111
76 0xE3FF, // 1110001111111111
77 0xE1FF, // 1110000111111111
78 0xE0FF, // 1110000011111111
79 0xE07F, // 1110000001111111
80 0xE03F, // 1110000000111111
81 0xE01F, // 1110000000011111
82 0xE00F, // 1110000000001111
83 0xE007, // 1110000000000111
84 0xE007, // 1110000000000111
85 0xE03F, // 1110000000111111
86 0xE21F, // 1110001000011111
87 0xE61F, // 1110011000011111
88 0xFF0F, // 1111111100001111
89 0xFF0F, // 1111111100001111
90 0xFF8F, // 1111111110001111
93 static WORD DefaultGfxCursorMask
[16] =
95 0x0000, // 0000000000000000
96 0x0800, // 0000100000000000
97 0x0C00, // 0000110000000000
98 0x0E00, // 0000111000000000
99 0x0F00, // 0000111100000000
100 0x0F80, // 0000111110000000
101 0x0FC0, // 0000111111000000
102 0x0FE0, // 0000111111100000
103 0x0FF0, // 0000111111110000
104 0x0F80, // 0000111110000000
105 0x0D80, // 0000110110000000
106 0x08C0, // 0000100011000000
107 0x00C0, // 0000000011000000
108 0x0060, // 0000000001100000
109 0x0060, // 0000000001100000
110 0x0000, // 0000000000000000
113 /* PRIVATE FUNCTIONS **********************************************************/
116 VOID
BiosPs2Service(UCHAR Function
)
120 // USHORT BX = getBX();
123 * Set the parameters:
124 * AL contains the character to print (already set),
125 * BL contains the character attribute,
126 * BH contains the video page to use.
128 // setBL(DOS_CHAR_ATTRIBUTE);
129 // setBH(Bda->VideoPage);
132 /* Call the BIOS INT 15h, AH=C2h "Pointing Device BIOS Interface (PS)" */
134 Int32Call(&MouseContext
, BIOS_MISC_INTERRUPT
);
136 /* Restore AX and BX */
143 static VOID
DosMouseEnable(VOID
);
144 static VOID
DosMouseDisable(VOID
);
147 static VOID
PaintMouseCursor(VOID
)
149 if (Bda
->VideoMode
<= 3)
152 WORD CellX
= DriverState
.Position
.X
/ 8;
153 WORD CellY
= DriverState
.Position
.Y
/ 8;
154 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
);
156 EmulatorReadMemory(&EmulatorContext
,
158 + (CellY
* Bda
->ScreenColumns
+ CellX
) * sizeof(WORD
),
162 DriverState
.Character
= Character
;
163 Character
&= DriverState
.TextCursor
.ScreenMask
;
164 Character
^= DriverState
.TextCursor
.CursorMask
;
166 EmulatorWriteMemory(&EmulatorContext
,
168 + (CellY
* Bda
->ScreenColumns
+ CellX
) * sizeof(WORD
),
172 else if (Bda
->VideoMode
== 0x12)
178 /* Save the write mask */
179 IOWriteB(VGA_SEQ_INDEX
, VGA_SEQ_MASK_REG
);
180 OldMask
= IOReadB(VGA_SEQ_DATA
);
182 /* And the selected reading plane */
183 IOWriteB(VGA_GC_INDEX
, VGA_GC_READ_MAP_SEL_REG
);
184 OldMap
= IOReadB(VGA_GC_DATA
);
186 for (i
= 0; i
< 16; i
++)
189 DWORD VideoAddress
= TO_LINEAR(GRAPHICS_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
)
190 + ((DriverState
.Position
.Y
+ i
) * 640 + DriverState
.Position
.X
) / 8;
192 for (j
= 0; j
< 4; j
++)
194 /* Select the reading plane */
195 IOWriteB(VGA_GC_INDEX
, VGA_GC_READ_MAP_SEL_REG
);
196 IOWriteB(VGA_GC_DATA
, j
);
198 /* Read a part of the scanline */
199 EmulatorReadMemory(&EmulatorContext
, VideoAddress
, &CursorLine
[j
], sizeof(CursorLine
[j
]));
202 /* Save the data below the cursor */
203 for (j
= 0; j
< 16; j
++)
205 DriverState
.GraphicsData
[i
* 16 + j
] = 0;
207 if (CursorLine
[0] & (1 << j
)) DriverState
.GraphicsData
[i
* 16 + j
] |= 1 << 0;
208 if (CursorLine
[1] & (1 << j
)) DriverState
.GraphicsData
[i
* 16 + j
] |= 1 << 1;
209 if (CursorLine
[2] & (1 << j
)) DriverState
.GraphicsData
[i
* 16 + j
] |= 1 << 2;
210 if (CursorLine
[3] & (1 << j
)) DriverState
.GraphicsData
[i
* 16 + j
] |= 1 << 3;
213 for (j
= 0; j
< 4; j
++)
215 /* Apply the screen mask */
216 CursorLine
[j
] &= MAKEWORD(HIBYTE(DriverState
.GraphicsCursor
.ScreenMask
[i
]),
217 LOBYTE(DriverState
.GraphicsCursor
.ScreenMask
[i
]));
219 /* And the cursor mask */
220 CursorLine
[j
] ^= MAKEWORD(HIBYTE(DriverState
.GraphicsCursor
.CursorMask
[i
]),
221 LOBYTE(DriverState
.GraphicsCursor
.CursorMask
[i
]));
223 /* Select the writing plane */
224 IOWriteB(VGA_SEQ_INDEX
, VGA_SEQ_MASK_REG
);
225 IOWriteB(VGA_SEQ_DATA
, 1 << j
);
227 /* Write the cursor data for this scanline */
228 EmulatorWriteMemory(&EmulatorContext
, VideoAddress
, &CursorLine
[j
], sizeof(CursorLine
[j
]));
232 /* Restore the old mask */
233 IOWriteB(VGA_SEQ_INDEX
, VGA_SEQ_MASK_REG
);
234 IOWriteB(VGA_SEQ_DATA
, OldMask
);
236 /* And the old reading plane */
237 IOWriteB(VGA_GC_INDEX
, VGA_GC_READ_MAP_SEL_REG
);
238 IOWriteB(VGA_GC_DATA
, OldMap
);
240 else if (Bda
->VideoMode
== 0x13)
244 for (i
= 0; i
< 16; i
++)
247 DWORD VideoAddress
= TO_LINEAR(GRAPHICS_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
)
248 + (DriverState
.Position
.Y
+ i
) * 320 + DriverState
.Position
.X
;
250 /* Read a part of the scanline */
251 EmulatorReadMemory(&EmulatorContext
,
253 &DriverState
.GraphicsData
[i
* 16],
256 for (j
= 0; j
< 16; j
++)
258 /* Apply the screen mask by leaving only the masked pixels intact */
259 CursorLine
[j
] = (DriverState
.GraphicsCursor
.ScreenMask
[i
] & (1 << j
))
260 ? DriverState
.GraphicsData
[i
* 16]
263 /* Apply the cursor mask... */
264 if (DriverState
.GraphicsCursor
.CursorMask
[i
] & (1 << j
))
266 /* ... by inverting the color of each masked pixel */
267 CursorLine
[j
] ^= 0x0F;
271 /* Write the cursor data for this scanline */
272 EmulatorWriteMemory(&EmulatorContext
, VideoAddress
, &CursorLine
, sizeof(CursorLine
));
277 // TODO: NOT IMPLEMENTED
282 static VOID
EraseMouseCursor(VOID
)
284 if (Bda
->VideoMode
<= 3)
286 WORD CellX
= DriverState
.Position
.X
/ 8;
287 WORD CellY
= DriverState
.Position
.Y
/ 8;
288 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
);
290 EmulatorWriteMemory(&EmulatorContext
,
292 + (CellY
* Bda
->ScreenColumns
+ CellX
) * sizeof(WORD
),
293 (LPVOID
)&DriverState
.Character
,
296 else if (Bda
->VideoMode
== 0x12)
301 /* Save the write mask */
302 IOWriteB(VGA_SEQ_INDEX
, VGA_SEQ_MASK_REG
);
303 OldMask
= IOReadB(VGA_SEQ_DATA
);
305 for (i
= 0; i
< 16; i
++)
307 WORD CursorLine
[4] = {0};
308 DWORD VideoAddress
= TO_LINEAR(GRAPHICS_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
)
309 + ((DriverState
.Position
.Y
+ i
) * 640 + DriverState
.Position
.X
) / 8;
311 /* Restore the data that was below the cursor */
312 for (j
= 0; j
< 16; j
++)
314 if (DriverState
.GraphicsData
[i
* 16 + j
] & (1 << 0)) CursorLine
[0] |= 1 << j
;
315 if (DriverState
.GraphicsData
[i
* 16 + j
] & (1 << 1)) CursorLine
[1] |= 1 << j
;
316 if (DriverState
.GraphicsData
[i
* 16 + j
] & (1 << 2)) CursorLine
[2] |= 1 << j
;
317 if (DriverState
.GraphicsData
[i
* 16 + j
] & (1 << 3)) CursorLine
[3] |= 1 << j
;
320 for (j
= 0; j
< 4; j
++)
322 /* Select the writing plane */
323 IOWriteB(VGA_SEQ_INDEX
, VGA_SEQ_MASK_REG
);
324 IOWriteB(VGA_SEQ_DATA
, 1 << j
);
326 /* Write the original data for this scanline */
327 EmulatorWriteMemory(&EmulatorContext
, VideoAddress
, &CursorLine
[j
], sizeof(CursorLine
[j
]));
331 /* Restore the old mask */
332 IOWriteB(VGA_SEQ_INDEX
, VGA_SEQ_MASK_REG
);
333 IOWriteB(VGA_SEQ_DATA
, OldMask
);
335 else if (Bda
->VideoMode
== 0x13)
339 for (i
= 0; i
< 16; i
++)
341 DWORD VideoAddress
= TO_LINEAR(GRAPHICS_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
)
342 + (DriverState
.Position
.Y
+ i
) * 320 + DriverState
.Position
.X
;
344 /* Write the original data for this scanline */
345 EmulatorWriteMemory(&EmulatorContext
,
347 &DriverState
.GraphicsData
[i
* 16],
353 // TODO: NOT IMPLEMENTED
358 static VOID
ToMouseCoordinates(PCOORD Position
)
360 COORD Resolution
= VgaGetDisplayResolution();
361 DWORD Width
= DriverState
.MaxX
- DriverState
.MinX
+ 1;
362 DWORD Height
= DriverState
.MaxY
- DriverState
.MinY
+ 1;
364 if (!VgaGetDoubleVisionState(NULL
, NULL
))
370 Position
->X
= DriverState
.MinX
+ ((Position
->X
* Width
) / Resolution
.X
);
371 Position
->Y
= DriverState
.MinY
+ ((Position
->Y
* Height
) / Resolution
.Y
);
374 static VOID
FromMouseCoordinates(PCOORD Position
)
376 COORD Resolution
= VgaGetDisplayResolution();
377 DWORD Width
= DriverState
.MaxX
- DriverState
.MinX
+ 1;
378 DWORD Height
= DriverState
.MaxY
- DriverState
.MinY
+ 1;
380 if (!VgaGetDoubleVisionState(NULL
, NULL
))
386 Position
->X
= ((Position
->X
- DriverState
.MinX
) * Resolution
.X
) / Width
;
387 Position
->Y
= ((Position
->Y
- DriverState
.MinY
) * Resolution
.Y
) / Height
;
390 static VOID
CallMouseUserHandlers(USHORT CallMask
)
393 USHORT AX
, BX
, CX
, DX
, BP
, SI
, DI
, DS
, ES
;
394 COORD Position
= DriverState
.Position
;
396 ToMouseCoordinates(&Position
);
399 if ((DriverState
.Handler0
.CallMask
& CallMask
) != 0 &&
400 DriverState
.Handler0
.Callback
!= NULL32
)
403 * Set the parameters for the callback.
404 * NOTE: In text modes, the row and column will be reported
405 * as a multiple of the cell size, typically 8x8 pixels.
419 setBX(DriverState
.ButtonState
);
422 setSI(MICKEYS_PER_CELL_HORIZ
);
423 setDI(MICKEYS_PER_CELL_VERT
);
425 DPRINT("Calling Handler0 %04X:%04X with CallMask 0x%04X\n",
426 HIWORD(DriverState
.Handler0
.Callback
),
427 LOWORD(DriverState
.Handler0
.Callback
),
430 /* Call the callback */
431 RunCallback16(&MouseContext
, DriverState
.Handler0
.Callback
);
444 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
446 /* Call the suitable handlers */
447 if ((DriverState
.Handlers
[i
].CallMask
& CallMask
) != 0 &&
448 DriverState
.Handlers
[i
].Callback
!= NULL32
)
451 * Set the parameters for the callback.
452 * NOTE: In text modes, the row and column will be reported
453 * as a multiple of the cell size, typically 8x8 pixels.
467 setBX(DriverState
.ButtonState
);
470 setSI(MICKEYS_PER_CELL_HORIZ
);
471 setDI(MICKEYS_PER_CELL_VERT
);
473 DPRINT1("Calling Handler[%d] %04X:%04X with CallMask 0x%04X\n",
475 HIWORD(DriverState
.Handlers
[i
].Callback
),
476 LOWORD(DriverState
.Handlers
[i
].Callback
),
479 /* Call the callback */
480 RunCallback16(&MouseContext
, DriverState
.Handlers
[i
].Callback
);
495 static inline VOID
DosUpdatePosition(PCOORD NewPosition
)
497 COORD Resolution
= VgaGetDisplayResolution();
499 /* Check for text mode */
500 if (!VgaGetDoubleVisionState(NULL
, NULL
))
506 if (DriverState
.ShowCount
> 0) EraseMouseCursor();
507 DriverState
.Position
= *NewPosition
;
508 if (DriverState
.ShowCount
> 0) PaintMouseCursor();
510 /* Call the mouse handlers */
511 CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
514 static inline VOID
DosUpdateButtons(BYTE ButtonState
) // WORD ButtonState
517 USHORT CallMask
= 0x0000; // We use MS MOUSE v1.0+ format
519 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
521 BOOLEAN OldState
= (DriverState
.ButtonState
>> i
) & 1;
522 BOOLEAN NewState
= (ButtonState
>> i
) & 1;
524 if (NewState
> OldState
)
527 DriverState
.PressCount
[i
]++;
528 DriverState
.LastPress
[i
] = DriverState
.Position
;
530 CallMask
|= (1 << (2 * i
+ 1));
532 else if (NewState
< OldState
)
535 DriverState
.ReleaseCount
[i
]++;
536 DriverState
.LastRelease
[i
] = DriverState
.Position
;
538 CallMask
|= (1 << (2 * i
+ 2));
542 DriverState
.ButtonState
= ButtonState
;
544 /* Call the mouse handlers */
545 CallMouseUserHandlers(CallMask
);
548 static VOID WINAPI
DosMouseIrq(LPWORD Stack
)
551 SHORT DeltaX
, DeltaY
;
555 /* Read the whole packet at once */
556 Flags
= IOReadB(PS2_DATA_PORT
);
557 PS2PortQueueRead(1); // NOTE: Should be a IOReadB! But see r67231
558 DeltaX
= IOReadB(PS2_DATA_PORT
);
559 PS2PortQueueRead(1); // NOTE: Should be a IOReadB! But see r67231
560 DeltaY
= IOReadB(PS2_DATA_PORT
);
562 /* Adjust the sign */
563 if (Flags
& MOUSE_X_SIGN
) DeltaX
= -DeltaX
;
564 if (Flags
& MOUSE_Y_SIGN
) DeltaY
= -DeltaY
;
566 /* Update the counters */
567 DriverState
.HorizCount
+= DeltaX
;
568 DriverState
.VertCount
+= DeltaY
;
571 * Get the absolute position directly from the mouse, this is the only
572 * way to perfectly synchronize the host and guest mouse pointer.
574 MouseGetDataFast(&Position
, &ButtonState
);
576 /* Call the update subroutines */
577 DosUpdatePosition(&Position
);
578 DosUpdateButtons(ButtonState
);
580 /* Complete the IRQ */
581 PicIRQComplete(LOBYTE(Stack
[STACK_INT_NUM
]));
584 static VOID WINAPI
DosMouseService(LPWORD Stack
)
593 DriverState
.ShowCount
= 0;
594 DriverState
.ButtonState
= 0;
596 /* Initialize the default clipping range */
597 DriverState
.MinX
= 0;
598 DriverState
.MaxX
= MOUSE_MAX_HORIZ
- 1;
599 DriverState
.MinY
= 0;
600 DriverState
.MaxY
= MOUSE_MAX_VERT
- 1;
602 /* Set the default text cursor */
603 DriverState
.TextCursor
.ScreenMask
= 0xFFFF; /* Display everything */
604 DriverState
.TextCursor
.CursorMask
= 0xFF00; /* ... but with inverted attributes */
606 /* Set the default graphics cursor */
607 DriverState
.GraphicsCursor
.HotSpot
.X
= 3;
608 DriverState
.GraphicsCursor
.HotSpot
.Y
= 1;
610 RtlCopyMemory(DriverState
.GraphicsCursor
.ScreenMask
,
611 DefaultGfxScreenMask
,
612 sizeof(DriverState
.GraphicsCursor
.ScreenMask
));
614 RtlCopyMemory(DriverState
.GraphicsCursor
.CursorMask
,
615 DefaultGfxCursorMask
,
616 sizeof(DriverState
.GraphicsCursor
.CursorMask
));
618 /* Initialize the counters */
619 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
621 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
623 DriverState
.PressCount
[i
] = DriverState
.ReleaseCount
[i
] = 0;
626 /* Return mouse information */
627 setAX(0xFFFF); // Hardware & driver installed
628 setBX(NUM_MOUSE_BUTTONS
);
633 /* Show Mouse Cursor */
636 DriverState
.ShowCount
++;
637 if (DriverState
.ShowCount
== 1) PaintMouseCursor();
642 /* Hide Mouse Cursor */
645 DriverState
.ShowCount
--;
646 if (DriverState
.ShowCount
== 0) EraseMouseCursor();
651 /* Return Position and Button Status */
654 COORD Position
= DriverState
.Position
;
655 ToMouseCoordinates(&Position
);
657 setBX(DriverState
.ButtonState
);
663 /* Position Mouse Cursor */
666 COORD Position
= { getCX(), getDX() };
667 FromMouseCoordinates(&Position
);
669 DriverState
.Position
= Position
;
673 /* Return Button Press Data */
676 WORD Button
= getBX();
677 COORD LastPress
= DriverState
.LastPress
[Button
];
678 ToMouseCoordinates(&LastPress
);
680 setAX(DriverState
.ButtonState
);
681 setBX(DriverState
.PressCount
[Button
]);
685 /* Reset the counter */
686 DriverState
.PressCount
[Button
] = 0;
691 /* Return Button Release Data */
694 WORD Button
= getBX();
695 COORD LastRelease
= DriverState
.LastRelease
[Button
];
696 ToMouseCoordinates(&LastRelease
);
698 setAX(DriverState
.ButtonState
);
699 setBX(DriverState
.ReleaseCount
[Button
]);
700 setCX(LastRelease
.X
);
701 setDX(LastRelease
.Y
);
703 /* Reset the counter */
704 DriverState
.ReleaseCount
[Button
] = 0;
710 /* Define Horizontal Cursor Range */
716 if (!VgaGetDoubleVisionState(NULL
, NULL
))
723 DPRINT("Setting mouse horizontal range: %u - %u\n", Min
, Max
);
724 DriverState
.MinX
= Min
;
725 DriverState
.MaxX
= Max
;
729 /* Define Vertical Cursor Range */
735 if (!VgaGetDoubleVisionState(NULL
, NULL
))
742 DPRINT("Setting mouse vertical range: %u - %u\n", Min
, Max
);
743 DriverState
.MinY
= Min
;
744 DriverState
.MaxY
= Max
;
748 /* Define Graphics Cursor */
751 PWORD MaskBitmap
= (PWORD
)SEG_OFF_TO_PTR(getES(), getDX());
753 DriverState
.GraphicsCursor
.HotSpot
.X
= getBX();
754 DriverState
.GraphicsCursor
.HotSpot
.Y
= getCX();
756 RtlCopyMemory(DriverState
.GraphicsCursor
.ScreenMask
,
758 sizeof(DriverState
.GraphicsCursor
.ScreenMask
));
760 RtlCopyMemory(DriverState
.GraphicsCursor
.CursorMask
,
762 sizeof(DriverState
.GraphicsCursor
.CursorMask
));
767 /* Define Text Cursor */
774 /* Define software cursor */
775 DriverState
.TextCursor
.ScreenMask
= getCX();
776 DriverState
.TextCursor
.CursorMask
= getDX();
778 else if (BX
== 0x0001)
780 /* Define hardware cursor */
781 DPRINT1("Defining hardware cursor is unimplemented\n");
783 // CX == start scan line
784 // DX == end scan line
788 DPRINT1("Invalid BX value 0x%04X\n", BX
);
794 /* Read Motion Counters */
797 setCX(DriverState
.HorizCount
);
798 setDX(DriverState
.VertCount
);
800 /* Reset the counters */
801 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
806 /* Define Interrupt Subroutine Parameters, compatible MS MOUSE v1.0+ */
809 DriverState
.Handler0
.CallMask
= getCX();
810 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
811 DPRINT1("Define callback 0x%04X, %04X:%04X\n",
812 DriverState
.Handler0
.CallMask
,
813 HIWORD(DriverState
.Handler0
.Callback
),
814 LOWORD(DriverState
.Handler0
.Callback
));
818 /* Define Mickey/Pixel Ratio */
821 /* This call should be completely ignored */
825 /* Set Exclusion Area */
826 // http://www.ctyme.com/intr/rb-5972.htm
827 // http://www.techhelpmanual.com/849-int_33h_0010h__set_exclusion_area.html
832 /* Define Double-Speed Threshold */
835 DPRINT1("INT 33h, AH=13h: Mouse double-speed threshold is UNSUPPORTED\n");
839 /* Exchange Interrupt Subroutines, compatible MS MOUSE v3.0+ (see function 0x0C) */
842 USHORT OldCallMask
= DriverState
.Handler0
.CallMask
;
843 ULONG OldCallback
= DriverState
.Handler0
.Callback
;
845 DriverState
.Handler0
.CallMask
= getCX();
846 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
847 DPRINT1("Exchange old callback 0x%04X, %04X:%04X with new callback 0x%04X, %04X:%04X\n",
851 DriverState
.Handler0
.CallMask
,
852 HIWORD(DriverState
.Handler0
.Callback
),
853 LOWORD(DriverState
.Handler0
.Callback
));
855 /* Return old callmask in CX and callback vector in ES:DX */
857 setES(HIWORD(OldCallback
));
858 setDX(LOWORD(OldCallback
));
862 /* Return Driver Storage Requirements */
865 setBX(sizeof(MOUSE_DRIVER_STATE
));
869 /* Save Driver State */
872 /* Check whether the user buffer has correct size and fail if not */
873 if (getBX() != sizeof(MOUSE_DRIVER_STATE
)) break;
875 *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX())) = DriverState
;
879 /* Restore Driver State */
882 /* Check whether the user buffer has correct size and fail if not */
883 if (getBX() != sizeof(MOUSE_DRIVER_STATE
)) break;
885 DriverState
= *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX()));
889 /* Set Alternate Mouse User Handler, compatible MS MOUSE v6.0+ */
893 * Up to three handlers can be defined by separate calls to this
894 * function, each with a different combination of shift states in
895 * the call mask; calling this function again with a call mask of
896 * 0000h undefines the specified handler (official documentation);
897 * specifying the same call mask and an address of 0000h:0000h
898 * undefines the handler (real life).
899 * See Ralf Brown: http://www.ctyme.com/intr/rb-5981.htm
900 * for more information.
904 USHORT CallMask
= getCX();
905 ULONG Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
906 BOOLEAN Success
= FALSE
;
908 DPRINT1("Define v6.0+ callback 0x%04X, %04X:%04X\n",
909 CallMask
, HIWORD(Callback
), LOWORD(Callback
));
911 if (CallMask
== 0x0000)
914 * Find the handler entry corresponding to the given
915 * callback and undefine it.
917 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
919 if (DriverState
.Handlers
[i
].Callback
== Callback
)
921 /* Found it, undefine the handler */
922 DriverState
.Handlers
[i
].CallMask
= 0x0000;
923 DriverState
.Handlers
[i
].Callback
= NULL32
;
929 else if (Callback
== NULL32
)
932 * Find the handler entry corresponding to the given
933 * callmask and undefine it.
935 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
937 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
939 /* Found it, undefine the handler */
940 DriverState
.Handlers
[i
].CallMask
= 0x0000;
941 DriverState
.Handlers
[i
].Callback
= NULL32
;
950 * Try to find a handler entry corresponding to the given
951 * callmask to redefine it, otherwise find an empty handler
952 * entry and set the new handler in there.
955 USHORT EmptyHandler
= 0xFFFF; // Invalid handler
957 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
959 /* Find the first empty handler */
960 if (EmptyHandler
== 0xFFFF &&
961 DriverState
.Handlers
[i
].CallMask
== 0x0000 &&
962 DriverState
.Handlers
[i
].Callback
== NULL32
)
967 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
969 /* Found it, redefine the handler */
970 DriverState
.Handlers
[i
].CallMask
= CallMask
;
971 DriverState
.Handlers
[i
].Callback
= Callback
;
978 * If we haven't found anything and we found
979 * an empty handler, set it.
981 if (!Success
&& EmptyHandler
!= 0xFFFF
982 /* && EmptyHandler < ARRAYSIZE(DriverState.Handlers) */)
984 DriverState
.Handlers
[EmptyHandler
].CallMask
= CallMask
;
985 DriverState
.Handlers
[EmptyHandler
].Callback
= Callback
;
990 /* If we failed, set error code */
991 if (!Success
) setAX(0xFFFF);
996 /* Return User Alternate Interrupt Vector, compatible MS MOUSE v6.0+ */
1000 USHORT CallMask
= getCX();
1002 BOOLEAN Success
= FALSE
;
1005 * Find the handler entry corresponding to the given callmask.
1007 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
1009 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
1012 Callback
= DriverState
.Handlers
[i
].Callback
;
1020 /* Return the callback vector in BX:DX */
1021 setBX(HIWORD(Callback
));
1022 setDX(LOWORD(Callback
));
1026 /* We failed, set error code */
1033 /* Set Mouse Sensitivity */
1036 DPRINT1("INT 33h, AH=1Ah: Mouse sensitivity is UNSUPPORTED\n");
1038 // FIXME: Do that at runtime!
1040 // UCHAR BH = getBH();
1042 // BiosPs2Service(0x00);
1043 // FIXME: Check for return status in AH and CF
1049 /* Return Mouse Sensitivity */
1052 DPRINT1("INT 33h, AH=1Bh: Mouse sensitivity is UNSUPPORTED\n");
1054 /* Return default values */
1055 setBX(50); // Horizontal speed
1056 setCX(50); // Vertical speed
1057 setDX(50); // Double speed threshold
1059 // FIXME: Get that at runtime!
1061 // UCHAR BH = getBH();
1063 // BiosPs2Service(0x00);
1064 // FIXME: Check for return status in AH and CF
1070 /* Disable Mouse Driver */
1073 /* INT 33h vector before the mouse driver was first installed */
1074 setES(HIWORD(OldIntHandler
));
1075 setBX(LOWORD(OldIntHandler
));
1078 // UCHAR BH = getBH();
1080 // BiosPs2Service(0x00);
1081 // FIXME: Check for return status in AH and CF
1086 /* Enable Mouse Driver */
1090 // UCHAR BH = getBH();
1092 // BiosPs2Service(0x00);
1093 // FIXME: Check for return status in AH and CF
1098 /* Software Reset */
1102 * See: http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte3sq8.htm
1103 * for detailed information and differences with respect to subfunction 0x00:
1104 * http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte3j74.htm
1109 DriverState
.ShowCount
= 0;
1110 DriverState
.ButtonState
= 0;
1112 /* Initialize the default clipping range */
1113 DriverState
.MinX
= 0;
1114 DriverState
.MaxX
= MOUSE_MAX_HORIZ
- 1;
1115 DriverState
.MinY
= 0;
1116 DriverState
.MaxY
= MOUSE_MAX_VERT
- 1;
1118 /* Initialize the counters */
1119 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
1121 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
1123 DriverState
.PressCount
[i
] = DriverState
.ReleaseCount
[i
] = 0;
1126 /* Return mouse information */
1127 setAX(0xFFFF); // Hardware & driver installed
1128 setBX(NUM_MOUSE_BUTTONS
);
1133 /* Get Software Version, Mouse Type, and IRQ Number, compatible MS MOUSE v6.26+ */
1136 setBX(MOUSE_VERSION
); // Version Number
1139 * See Ralf Brown: http://www.ctyme.com/intr/rb-5993.htm
1140 * for the list of possible values.
1142 // FIXME: To be determined at runtime!
1143 setCH(0x04); // PS/2 Type
1144 setCL(0x00); // PS/2 Interrupt
1149 // BIOS Function INT 33h, AX = 0x0025 NOT IMPLEMENTED
1160 /* Get Maximum Virtual Coordinates */
1163 setBX(!DriverEnabled
);
1164 // FIXME: In fact the MaxX and MaxY here are
1165 // theoretical values for the current video mode.
1166 // They therefore can be different from the current
1168 // See http://www.ctyme.com/intr/rb-5995.htm
1169 // for more details.
1170 setCX(DriverState
.MaxX
);
1171 setDX(DriverState
.MaxY
);
1175 /* Get Current Minimum/Maximum Virtual Coordinates */
1178 setAX(DriverState
.MinX
);
1179 setBX(DriverState
.MinY
);
1180 setCX(DriverState
.MaxX
);
1181 setDX(DriverState
.MaxY
);
1189 * Related to http://www.ctyme.com/intr/rb-5985.htm
1190 * INT 33h, AX=001Ch "SET INTERRUPT RATE":
1192 * Values for mouse interrupt rate:
1194 00h no interrupts allowed
1203 /* Return Pointer to Copyright String */
1206 setES(MouseDataSegment
);
1207 setDI(FIELD_OFFSET(MOUSE_DRIVER
, Copyright
));
1211 /* Get Version String (pointer) */
1215 * The format of the version "string" is:
1216 * Offset Size Description
1217 * 00h BYTE major version
1218 * 01h BYTE minor version (BCD)
1220 setES(MouseDataSegment
);
1221 setDI(FIELD_OFFSET(MOUSE_DRIVER
, Version
));
1227 DPRINT1("BIOS Function INT 33h, AX = 0x%04X NOT IMPLEMENTED\n", getAX());
1232 /* PUBLIC FUNCTIONS ***********************************************************/
1235 VOID
DosMouseEnable(VOID
)
1237 if (DriverEnabled
) return;
1239 DriverEnabled
= TRUE
;
1241 /* Get the old IRQ handler */
1242 OldIrqHandler
= ((PDWORD
)BaseAddress
)[MOUSE_IRQ_INT
];
1244 /* Set the IRQ handler */
1245 RegisterInt32(MAKELONG(FIELD_OFFSET(MOUSE_DRIVER
, MouseIrqInt16Stub
), MouseDataSegment
),
1246 MOUSE_IRQ_INT
, DosMouseIrq
, NULL
);
1250 VOID
DosMouseDisable(VOID
)
1252 if (!DriverEnabled
) return;
1254 /* Restore the old IRQ handler */
1255 ((PDWORD
)BaseAddress
)[MOUSE_IRQ_INT
] = OldIrqHandler
;
1257 DriverEnabled
= FALSE
;
1260 BOOLEAN
DosMouseInitialize(VOID
)
1262 /* Initialize some memory for storing our data that should be available to DOS */
1263 MouseDataSegment
= DosAllocateMemory(sizeof(MOUSE_DRIVER
), NULL
);
1264 if (MouseDataSegment
== 0) return FALSE
;
1265 MouseData
= (PMOUSE_DRIVER
)SEG_OFF_TO_PTR(MouseDataSegment
, 0x0000);
1267 /* Initialize the callback context */
1268 InitializeContext(&MouseContext
, MouseDataSegment
, FIELD_OFFSET(MOUSE_DRIVER
, MouseContextScratch
));
1270 /* Clear the state */
1271 RtlZeroMemory(&DriverState
, sizeof(DriverState
));
1273 /* Mouse Driver Copyright */
1274 RtlCopyMemory(MouseData
->Copyright
, MouseCopyright
, sizeof(MouseCopyright
)-1);
1276 /* Mouse Driver Version in BCD format, compatible MS-MOUSE */
1277 MouseData
->Version
= MAKEWORD(MOUSE_VERSION
/0x0100, MOUSE_VERSION
%0x0100);
1279 /* Get the old mouse service interrupt handler */
1280 OldIntHandler
= ((PDWORD
)BaseAddress
)[DOS_MOUSE_INTERRUPT
];
1282 /* Initialize the interrupt handler */
1283 RegisterInt32(MAKELONG(FIELD_OFFSET(MOUSE_DRIVER
, MouseDosInt16Stub
), MouseDataSegment
),
1284 DOS_MOUSE_INTERRUPT
, DosMouseService
, NULL
);
1287 // UCHAR BH = getBH();
1289 // BiosPs2Service(0x00);
1290 // FIXME: Check for return status in AH and CF
1296 VOID
DosMouseCleanup(VOID
)
1298 if (DriverState
.ShowCount
> 0) EraseMouseCursor();
1300 // UCHAR BH = getBH();
1302 // BiosPs2Service(0x00);
1303 // FIXME: Check for return status in AH and CF
1306 /* Restore the old mouse service interrupt handler */
1307 ((PDWORD
)BaseAddress
)[DOS_MOUSE_INTERRUPT
] = OldIntHandler
;
1309 DosFreeMemory(MouseDataSegment
);
1310 MouseDataSegment
= 0;