2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: VDM 32-bit compatible MOUSE.COM driver
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
18 #include "hardware/mouse.h"
19 #include "hardware/ps2.h"
20 #include "hardware/pic.h"
21 #include "hardware/video/svga.h"
24 #include "bios/bios.h"
25 #include "bios/bios32/bios32p.h"
29 #include "dos32krnl/memory.h"
31 /* PRIVATE VARIABLES **********************************************************/
33 static const CHAR MouseCopyright
[] = "ROS PS/2 16/32-bit Mouse Driver Compatible MS-MOUSE 6.26 Copyright (C) ReactOS Team 1996-2015\0";
37 typedef struct _MOUSE_DRIVER
39 CHAR Copyright
[sizeof(MouseCopyright
)];
41 BYTE MouseContextScratch
[TRAMPOLINE_SIZE
];
42 BYTE MouseDosInt16Stub
[Int16To32StubSize
];
43 BYTE MouseIrqInt16Stub
[Int16To32StubSize
];
44 } MOUSE_DRIVER
, *PMOUSE_DRIVER
;
48 /* Global data contained in guest memory */
49 static WORD MouseDataSegment
;
50 static PMOUSE_DRIVER MouseData
;
51 static CALLBACK16 MouseContext
;
53 #define MICKEYS_PER_CELL_HORIZ 8
54 #define MICKEYS_PER_CELL_VERT 16
56 static BOOLEAN DriverEnabled
= FALSE
;
57 static MOUSE_DRIVER_STATE DriverState
;
58 static DWORD OldIrqHandler
;
59 static DWORD OldIntHandler
;
61 /* PRIVATE FUNCTIONS **********************************************************/
63 static VOID
PaintMouseCursor(VOID
)
65 COORD Position
= DriverState
.Position
;
67 /* Apply the clipping rectangle */
68 if (Position
.X
< DriverState
.MinX
) Position
.X
= DriverState
.MinX
;
69 if (Position
.X
> DriverState
.MaxX
) Position
.X
= DriverState
.MaxX
;
70 if (Position
.Y
< DriverState
.MinY
) Position
.Y
= DriverState
.MinY
;
71 if (Position
.Y
> DriverState
.MaxY
) Position
.Y
= DriverState
.MaxY
;
73 if (Bda
->VideoMode
<= 3)
76 WORD CellX
= Position
.X
/ 8;
77 WORD CellY
= Position
.Y
/ 8;
78 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
);
80 EmulatorReadMemory(&EmulatorContext
,
82 + (CellY
* Bda
->ScreenColumns
+ CellX
) * sizeof(WORD
),
86 DriverState
.Character
= Character
;
87 Character
&= DriverState
.TextCursor
.ScreenMask
;
88 Character
^= DriverState
.TextCursor
.CursorMask
;
90 EmulatorWriteMemory(&EmulatorContext
,
92 + (CellY
* Bda
->ScreenColumns
+ CellX
) * sizeof(WORD
),
98 // TODO: NOT IMPLEMENTED
103 static VOID
EraseMouseCursor(VOID
)
105 COORD Position
= DriverState
.Position
;
107 /* Apply the clipping rectangle */
108 if (Position
.X
< DriverState
.MinX
) Position
.X
= DriverState
.MinX
;
109 if (Position
.X
> DriverState
.MaxX
) Position
.X
= DriverState
.MaxX
;
110 if (Position
.Y
< DriverState
.MinY
) Position
.Y
= DriverState
.MinY
;
111 if (Position
.Y
> DriverState
.MaxY
) Position
.Y
= DriverState
.MaxY
;
113 if (Bda
->VideoMode
<= 3)
115 WORD CellX
= Position
.X
/ 8;
116 WORD CellY
= Position
.Y
/ 8;
117 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
);
119 EmulatorWriteMemory(&EmulatorContext
,
121 + (CellY
* Bda
->ScreenColumns
+ CellX
) * sizeof(WORD
),
122 (LPVOID
)&DriverState
.Character
,
127 // TODO: NOT IMPLEMENTED
132 static VOID
ToMouseCoordinates(PCOORD Position
)
134 COORD Resolution
= VgaGetDisplayResolution();
135 WORD Width
= DriverState
.MaxX
- DriverState
.MinX
+ 1;
136 WORD Height
= DriverState
.MaxY
- DriverState
.MinY
+ 1;
138 if (!VgaGetDoubleVisionState(NULL
, NULL
))
144 Position
->X
= DriverState
.MinX
+ ((Position
->X
* Width
) / Resolution
.X
);
145 Position
->Y
= DriverState
.MinY
+ ((Position
->Y
* Height
) / Resolution
.Y
);
148 static VOID
FromMouseCoordinates(PCOORD Position
)
150 COORD Resolution
= VgaGetDisplayResolution();
151 WORD Width
= DriverState
.MaxX
- DriverState
.MinX
+ 1;
152 WORD Height
= DriverState
.MaxY
- DriverState
.MinY
+ 1;
154 if (!VgaGetDoubleVisionState(NULL
, NULL
))
160 Position
->X
= ((Position
->X
- DriverState
.MinX
) * Resolution
.X
) / Width
;
161 Position
->Y
= ((Position
->Y
- DriverState
.MinY
) * Resolution
.Y
) / Height
;
164 static VOID
CallMouseUserHandlers(USHORT CallMask
)
167 USHORT AX
, BX
, CX
, DX
, SI
, DI
;
168 COORD Position
= DriverState
.Position
;
170 ToMouseCoordinates(&Position
);
173 if ((DriverState
.Handler0
.CallMask
& CallMask
) != 0 &&
174 DriverState
.Handler0
.Callback
!= (ULONG
)NULL
)
177 * Set the parameters for the callback.
178 * NOTE: In text modes, the row and column will be reported
179 * as a multiple of the cell size, typically 8x8 pixels.
190 setBX(DriverState
.ButtonState
);
193 setSI(MICKEYS_PER_CELL_HORIZ
);
194 setDI(MICKEYS_PER_CELL_VERT
);
196 DPRINT("Calling Handler0 %04X:%04X with CallMask 0x%04X\n",
197 HIWORD(DriverState
.Handler0
.Callback
),
198 LOWORD(DriverState
.Handler0
.Callback
),
201 /* Call the callback */
202 RunCallback16(&MouseContext
, DriverState
.Handler0
.Callback
);
212 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
214 /* Call the suitable handlers */
215 if ((DriverState
.Handlers
[i
].CallMask
& CallMask
) != 0 &&
216 DriverState
.Handlers
[i
].Callback
!= (ULONG
)NULL
)
219 * Set the parameters for the callback.
220 * NOTE: In text modes, the row and column will be reported
221 * as a multiple of the cell size, typically 8x8 pixels.
232 setBX(DriverState
.ButtonState
);
235 setSI(MICKEYS_PER_CELL_HORIZ
);
236 setDI(MICKEYS_PER_CELL_VERT
);
238 DPRINT1("Calling Handler[%d] %04X:%04X with CallMask 0x%04X\n",
240 HIWORD(DriverState
.Handlers
[i
].Callback
),
241 LOWORD(DriverState
.Handlers
[i
].Callback
),
244 /* Call the callback */
245 RunCallback16(&MouseContext
, DriverState
.Handlers
[i
].Callback
);
257 static inline VOID
DosUpdatePosition(PCOORD NewPosition
)
259 COORD Resolution
= VgaGetDisplayResolution();
261 /* Check for text mode */
262 if (!VgaGetDoubleVisionState(NULL
, NULL
))
268 if (DriverState
.ShowCount
> 0) EraseMouseCursor();
269 DriverState
.Position
= *NewPosition
;
270 if (DriverState
.ShowCount
> 0) PaintMouseCursor();
272 /* Call the mouse handlers */
273 CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
276 static inline VOID
DosUpdateButtons(BYTE ButtonState
)
279 USHORT CallMask
= 0x0000; // We use MS MOUSE v1.0+ format
281 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
283 BOOLEAN OldState
= (DriverState
.ButtonState
>> i
) & 1;
284 BOOLEAN NewState
= (ButtonState
>> i
) & 1;
286 if (NewState
> OldState
)
289 DriverState
.PressCount
[i
]++;
290 DriverState
.LastPress
[i
] = DriverState
.Position
;
292 CallMask
|= (1 << (2 * i
+ 1));
294 else if (NewState
< OldState
)
297 DriverState
.ReleaseCount
[i
]++;
298 DriverState
.LastRelease
[i
] = DriverState
.Position
;
300 CallMask
|= (1 << (2 * i
+ 2));
304 DriverState
.ButtonState
= ButtonState
;
306 /* Call the mouse handlers */
307 CallMouseUserHandlers(CallMask
);
310 static VOID WINAPI
DosMouseIrq(LPWORD Stack
)
313 SHORT DeltaX
, DeltaY
;
317 /* Read the whole packet at once */
318 Flags
= IOReadB(PS2_DATA_PORT
);
320 DeltaX
= IOReadB(PS2_DATA_PORT
);
322 DeltaY
= IOReadB(PS2_DATA_PORT
);
324 /* Adjust the sign */
325 if (Flags
& MOUSE_X_SIGN
) DeltaX
= -DeltaX
;
326 if (Flags
& MOUSE_Y_SIGN
) DeltaY
= -DeltaY
;
328 /* Update the counters */
329 DriverState
.HorizCount
+= DeltaX
;
330 DriverState
.VertCount
+= DeltaY
;
333 * Get the absolute position directly from the mouse, this is the only
334 * way to perfectly synchronize the host and guest mouse pointer.
336 MouseGetDataFast(&Position
, &ButtonState
);
338 /* Call the update subroutines */
339 DosUpdatePosition(&Position
);
340 DosUpdateButtons(ButtonState
);
342 /* Complete the IRQ */
343 PicIRQComplete(LOBYTE(Stack
[STACK_INT_NUM
]));
346 static VOID WINAPI
DosMouseService(LPWORD Stack
)
355 DriverState
.ShowCount
= 0;
356 DriverState
.ButtonState
= 0;
358 /* Initialize the default clipping range */
359 DriverState
.MinX
= 0;
360 DriverState
.MaxX
= MOUSE_MAX_HORIZ
- 1;
361 DriverState
.MinY
= 0;
362 DriverState
.MaxY
= MOUSE_MAX_VERT
- 1;
364 /* Set the default text cursor */
365 DriverState
.TextCursor
.ScreenMask
= 0xFFFF; /* Display everything */
366 DriverState
.TextCursor
.CursorMask
= 0xFF00; /* ... but with inverted attributes */
368 /* Set the default graphics cursor */
369 DriverState
.GraphicsCursor
.HotSpot
.X
= 3;
370 DriverState
.GraphicsCursor
.HotSpot
.Y
= 1;
372 DriverState
.GraphicsCursor
.ScreenMask
[0] = 0xC3FF; // 1100001111111111
373 DriverState
.GraphicsCursor
.ScreenMask
[1] = 0xC0FF; // 1100000011111111
374 DriverState
.GraphicsCursor
.ScreenMask
[2] = 0xC07F; // 1100000001111111
375 DriverState
.GraphicsCursor
.ScreenMask
[3] = 0xC01F; // 1100000000011111
376 DriverState
.GraphicsCursor
.ScreenMask
[4] = 0xC00F; // 1100000000001111
377 DriverState
.GraphicsCursor
.ScreenMask
[5] = 0xC007; // 1100000000000111
378 DriverState
.GraphicsCursor
.ScreenMask
[6] = 0xC003; // 1100000000000011
379 DriverState
.GraphicsCursor
.ScreenMask
[7] = 0xC007; // 1100000000000111
380 DriverState
.GraphicsCursor
.ScreenMask
[8] = 0xC01F; // 1100000000011111
381 DriverState
.GraphicsCursor
.ScreenMask
[9] = 0xC01F; // 1100000000011111
382 DriverState
.GraphicsCursor
.ScreenMask
[10] = 0xC00F; // 1100000000001111
383 DriverState
.GraphicsCursor
.ScreenMask
[11] = 0xC60F; // 1100011000001111
384 DriverState
.GraphicsCursor
.ScreenMask
[12] = 0xFF07; // 1111111100000111
385 DriverState
.GraphicsCursor
.ScreenMask
[13] = 0xFF07; // 1111111100000111
386 DriverState
.GraphicsCursor
.ScreenMask
[14] = 0xFF87; // 1111111110000111
387 DriverState
.GraphicsCursor
.ScreenMask
[15] = 0xFFCF; // 1111111111001111
389 DriverState
.GraphicsCursor
.CursorMask
[0] = 0x0000; // 0000000000000000
390 DriverState
.GraphicsCursor
.CursorMask
[1] = 0x1C00; // 0001110000000000
391 DriverState
.GraphicsCursor
.CursorMask
[2] = 0x1F00; // 0001111100000000
392 DriverState
.GraphicsCursor
.CursorMask
[3] = 0x1F80; // 0001111110000000
393 DriverState
.GraphicsCursor
.CursorMask
[4] = 0x1FE0; // 0001111111100000
394 DriverState
.GraphicsCursor
.CursorMask
[5] = 0x1FF0; // 0001111111110000
395 DriverState
.GraphicsCursor
.CursorMask
[6] = 0x1FF8; // 0001111111111000
396 DriverState
.GraphicsCursor
.CursorMask
[7] = 0x1FE0; // 0001111111100000
397 DriverState
.GraphicsCursor
.CursorMask
[8] = 0x1FC0; // 0001111111000000
398 DriverState
.GraphicsCursor
.CursorMask
[9] = 0x1FC0; // 0001111111000000
399 DriverState
.GraphicsCursor
.CursorMask
[10] = 0x19E0; // 0001100111100000
400 DriverState
.GraphicsCursor
.CursorMask
[11] = 0x00E0; // 0000000011100000
401 DriverState
.GraphicsCursor
.CursorMask
[12] = 0x0070; // 0000000001110000
402 DriverState
.GraphicsCursor
.CursorMask
[13] = 0x0070; // 0000000001110000
403 DriverState
.GraphicsCursor
.CursorMask
[14] = 0x0030; // 0000000000110000
404 DriverState
.GraphicsCursor
.CursorMask
[15] = 0x0000; // 0000000000000000
406 /* Initialize the counters */
407 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
409 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
411 DriverState
.PressCount
[i
] = DriverState
.ReleaseCount
[i
] = 0;
414 /* Return mouse information */
415 setAX(0xFFFF); // Hardware & driver installed
416 setBX(NUM_MOUSE_BUTTONS
);
421 /* Show Mouse Cursor */
424 DriverState
.ShowCount
++;
425 if (DriverState
.ShowCount
== 1) PaintMouseCursor();
430 /* Hide Mouse Cursor */
433 DriverState
.ShowCount
--;
434 if (DriverState
.ShowCount
== 0) EraseMouseCursor();
439 /* Return Position And Button Status */
442 COORD Position
= DriverState
.Position
;
443 ToMouseCoordinates(&Position
);
445 setBX(DriverState
.ButtonState
);
451 /* Position Mouse Cursor */
454 COORD Position
= { getCX(), getDX() };
455 FromMouseCoordinates(&Position
);
457 DriverState
.Position
= Position
;
461 /* Return Button Press Data */
464 WORD Button
= getBX();
465 COORD LastPress
= DriverState
.LastPress
[Button
];
466 ToMouseCoordinates(&LastPress
);
468 setAX(DriverState
.ButtonState
);
469 setBX(DriverState
.PressCount
[Button
]);
473 /* Reset the counter */
474 DriverState
.PressCount
[Button
] = 0;
479 /* Return Button Release Data */
482 WORD Button
= getBX();
483 COORD LastRelease
= DriverState
.LastRelease
[Button
];
484 ToMouseCoordinates(&LastRelease
);
486 setAX(DriverState
.ButtonState
);
487 setBX(DriverState
.ReleaseCount
[Button
]);
488 setCX(LastRelease
.X
);
489 setDX(LastRelease
.Y
);
491 /* Reset the counter */
492 DriverState
.ReleaseCount
[Button
] = 0;
498 /* Define Horizontal Cursor Range */
504 if (!VgaGetDoubleVisionState(NULL
, NULL
))
511 DPRINT("Setting mouse horizontal range: %u - %u\n", Min
, Max
);
512 DriverState
.MinX
= Min
;
513 DriverState
.MaxX
= Max
;
517 /* Define Vertical Cursor Range */
523 if (!VgaGetDoubleVisionState(NULL
, NULL
))
530 DPRINT("Setting mouse vertical range: %u - %u\n", Min
, Max
);
531 DriverState
.MinY
= Min
;
532 DriverState
.MaxY
= Max
;
536 /* Define Graphics Cursor */
539 PWORD MaskBitmap
= (PWORD
)SEG_OFF_TO_PTR(getES(), getDX());
541 DriverState
.GraphicsCursor
.HotSpot
.X
= getBX();
542 DriverState
.GraphicsCursor
.HotSpot
.Y
= getCX();
544 RtlCopyMemory(DriverState
.GraphicsCursor
.ScreenMask
,
546 sizeof(DriverState
.GraphicsCursor
.ScreenMask
));
548 RtlCopyMemory(DriverState
.GraphicsCursor
.CursorMask
,
550 sizeof(DriverState
.GraphicsCursor
.CursorMask
));
555 /* Define Text Cursor */
562 /* Define software cursor */
563 DriverState
.TextCursor
.ScreenMask
= getCX();
564 DriverState
.TextCursor
.CursorMask
= getDX();
566 else if (BX
== 0x0001)
568 /* Define hardware cursor */
569 DPRINT1("Defining hardware cursor is unimplemented\n");
571 // CX == start scan line
572 // DX == end scan line
576 DPRINT1("Invalid BX value 0x%04X\n", BX
);
582 /* Read Motion Counters */
585 setCX(DriverState
.HorizCount
);
586 setDX(DriverState
.VertCount
);
588 /* Reset the counters */
589 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
594 /* Define Interrupt Subroutine Parameters, compatible MS MOUSE v1.0+ */
597 DriverState
.Handler0
.CallMask
= getCX();
598 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
599 DPRINT1("Define callback 0x%04X, %04X:%04X\n",
600 DriverState
.Handler0
.CallMask
,
601 HIWORD(DriverState
.Handler0
.Callback
),
602 LOWORD(DriverState
.Handler0
.Callback
));
606 /* Define Mickey/Pixel Ratio */
609 /* This call should be completely ignored */
613 /* Define Double-Speed Threshold */
616 DPRINT1("INT 33h, AH=13h: Mouse double-speed threshold is UNSUPPORTED\n");
620 /* Exchange Interrupt Subroutines, compatible MS MOUSE v3.0+ (see function 0x0C) */
623 USHORT OldCallMask
= DriverState
.Handler0
.CallMask
;
624 ULONG OldCallback
= DriverState
.Handler0
.Callback
;
626 DriverState
.Handler0
.CallMask
= getCX();
627 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
629 /* Return old callmask in CX and callback vector in ES:DX */
631 setES(HIWORD(OldCallback
));
632 setDX(LOWORD(OldCallback
));
637 /* Return Driver Storage Requirements */
640 setBX(sizeof(MOUSE_DRIVER_STATE
));
644 /* Save Driver State */
647 *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX())) = DriverState
;
651 /* Restore Driver State */
654 DriverState
= *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX()));
658 /* Set Alternate Mouse User Handler, compatible MS MOUSE v6.0+ */
662 * Up to three handlers can be defined by separate calls to this
663 * function, each with a different combination of shift states in
664 * the call mask; calling this function again with a call mask of
665 * 0000h undefines the specified handler (official documentation);
666 * specifying the same call mask and an address of 0000h:0000h
667 * undefines the handler (real life).
668 * See Ralf Brown: http://www.ctyme.com/intr/rb-5981.htm
669 * for more information.
673 USHORT CallMask
= getCX();
674 ULONG Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
675 BOOLEAN Success
= FALSE
;
677 DPRINT1("Define v6.0+ callback 0x%04X, %04X:%04X\n",
678 CallMask
, HIWORD(Callback
), LOWORD(Callback
));
680 if (CallMask
== 0x0000)
683 * Find the handler entry corresponding to the given
684 * callback and undefine it.
686 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
688 if (DriverState
.Handlers
[i
].Callback
== Callback
)
690 /* Found it, undefine the handler */
691 DriverState
.Handlers
[i
].CallMask
= 0x0000;
692 DriverState
.Handlers
[i
].Callback
= (ULONG
)NULL
;
698 else if (Callback
== (ULONG
)NULL
)
701 * Find the handler entry corresponding to the given
702 * callmask and undefine it.
704 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
706 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
708 /* Found it, undefine the handler */
709 DriverState
.Handlers
[i
].CallMask
= 0x0000;
710 DriverState
.Handlers
[i
].Callback
= (ULONG
)NULL
;
719 * Try to find a handler entry corresponding to the given
720 * callmask to redefine it, otherwise find an empty handler
721 * entry and set the new handler in there.
724 USHORT EmptyHandler
= 0xFFFF; // Invalid handler
726 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
728 /* Find the first empty handler */
729 if (EmptyHandler
== 0xFFFF &&
730 DriverState
.Handlers
[i
].CallMask
== 0x0000 &&
731 DriverState
.Handlers
[i
].Callback
== (ULONG
)NULL
)
736 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
738 /* Found it, redefine the handler */
739 DriverState
.Handlers
[i
].CallMask
= CallMask
;
740 DriverState
.Handlers
[i
].Callback
= Callback
;
747 * If we haven't found anything and we found
748 * an empty handler, set it.
750 if (!Success
&& EmptyHandler
!= 0xFFFF
751 /* && EmptyHandler < ARRAYSIZE(DriverState.Handlers) */)
753 DriverState
.Handlers
[EmptyHandler
].CallMask
= CallMask
;
754 DriverState
.Handlers
[EmptyHandler
].Callback
= Callback
;
759 /* If we failed, set error code */
760 if (!Success
) setAX(0xFFFF);
765 /* Return User Alternate Interrupt Vector, compatible MS MOUSE v6.0+ */
769 USHORT CallMask
= getCX();
771 BOOLEAN Success
= FALSE
;
774 * Find the handler entry corresponding to the given callmask.
776 for (i
= 0; i
< ARRAYSIZE(DriverState
.Handlers
); ++i
)
778 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
781 Callback
= DriverState
.Handlers
[i
].Callback
;
789 /* Return the callback vector in BX:DX */
790 setBX(HIWORD(Callback
));
791 setDX(LOWORD(Callback
));
795 /* We failed, set error code */
802 /* Set Mouse Sensitivity */
805 DPRINT1("INT 33h, AH=1Ah: Mouse sensitivity is UNSUPPORTED\n");
809 /* Return Mouse Sensitivity */
812 DPRINT1("INT 33h, AH=1Bh: Mouse sensitivity is UNSUPPORTED\n");
814 /* Return default values */
815 setBX(50); // Horizontal speed
816 setCX(50); // Vertical speed
817 setDX(50); // Double speed threshold
821 /* Disable Mouse Driver */
824 /* INT 33h vector before the mouse driver was first installed */
825 setES(HIWORD(OldIntHandler
));
826 setBX(LOWORD(OldIntHandler
));
832 /* Enable Mouse Driver */
843 * See: http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte3sq8.htm
844 * for detailed information and differences with respect to subfunction 0x00:
845 * http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte3j74.htm
850 DriverState
.ShowCount
= 0;
851 DriverState
.ButtonState
= 0;
853 /* Initialize the default clipping range */
854 DriverState
.MinX
= 0;
855 DriverState
.MaxX
= MOUSE_MAX_HORIZ
- 1;
856 DriverState
.MinY
= 0;
857 DriverState
.MaxY
= MOUSE_MAX_VERT
- 1;
859 /* Initialize the counters */
860 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
862 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
864 DriverState
.PressCount
[i
] = DriverState
.ReleaseCount
[i
] = 0;
867 /* Return mouse information */
868 setAX(0xFFFF); // Hardware & driver installed
869 setBX(NUM_MOUSE_BUTTONS
);
874 /* Get Software Version, Mouse Type, and IRQ Number, compatible MS MOUSE v6.26+ */
877 setBX(MOUSE_VERSION
); // Version Number
879 // FIXME: To be determined at runtime!
880 setCH(0x04); // PS/2 Type
881 setCL(0x00); // PS/2 Interrupt
886 /* Return Pointer to Copyright String */
889 setES(MouseDataSegment
);
890 setDI(FIELD_OFFSET(MOUSE_DRIVER
, Copyright
));
894 /* Get Version String (pointer) */
898 * The format of the version "string" is:
899 * Offset Size Description
900 * 00h BYTE major version
901 * 01h BYTE minor version (BCD)
903 setES(MouseDataSegment
);
904 setDI(FIELD_OFFSET(MOUSE_DRIVER
, Version
));
910 DPRINT1("BIOS Function INT 33h, AX = 0x%04X NOT IMPLEMENTED\n", getAX());
915 /* PUBLIC FUNCTIONS ***********************************************************/
917 VOID
DosMouseEnable(VOID
)
919 if (DriverEnabled
) return;
921 DriverEnabled
= TRUE
;
923 /* Get the old IRQ handler */
924 OldIrqHandler
= ((PDWORD
)BaseAddress
)[MOUSE_IRQ_INT
];
926 /* Set the IRQ handler */
927 RegisterInt32(MAKELONG(FIELD_OFFSET(MOUSE_DRIVER
, MouseIrqInt16Stub
), MouseDataSegment
),
928 MOUSE_IRQ_INT
, DosMouseIrq
, NULL
);
931 VOID
DosMouseDisable(VOID
)
933 if (!DriverEnabled
) return;
935 /* Restore the old IRQ handler */
936 ((PDWORD
)BaseAddress
)[MOUSE_IRQ_INT
] = OldIrqHandler
;
938 DriverEnabled
= FALSE
;
941 VOID
DosMouseUpdatePosition(PCOORD NewPosition
)
943 SHORT DeltaX
= NewPosition
->X
- DriverState
.Position
.X
;
944 SHORT DeltaY
= NewPosition
->Y
- DriverState
.Position
.Y
;
946 if (!DriverEnabled
) return;
948 DriverState
.HorizCount
+= (DeltaX
* MICKEYS_PER_CELL_HORIZ
) / 8;
949 DriverState
.VertCount
+= (DeltaY
* MICKEYS_PER_CELL_VERT
) / 8;
951 if (DriverState
.ShowCount
> 0) EraseMouseCursor();
952 DriverState
.Position
= *NewPosition
;
953 if (DriverState
.ShowCount
> 0) PaintMouseCursor();
955 /* Call the mouse handlers */
956 // if (DeltaX || DeltaY)
957 CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
960 VOID
DosMouseUpdateButtons(WORD ButtonState
)
963 USHORT CallMask
= 0x0000; // We use MS MOUSE v1.0+ format
965 if (!DriverEnabled
) return;
967 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
969 BOOLEAN OldState
= (DriverState
.ButtonState
>> i
) & 1;
970 BOOLEAN NewState
= (ButtonState
>> i
) & 1;
972 if (NewState
> OldState
)
975 DriverState
.PressCount
[i
]++;
976 DriverState
.LastPress
[i
] = DriverState
.Position
;
978 CallMask
|= (1 << (2 * i
+ 1));
980 else if (NewState
< OldState
)
983 DriverState
.ReleaseCount
[i
]++;
984 DriverState
.LastRelease
[i
] = DriverState
.Position
;
986 CallMask
|= (1 << (2 * i
+ 2));
990 DriverState
.ButtonState
= ButtonState
;
992 /* Call the mouse handlers */
993 CallMouseUserHandlers(CallMask
);
996 BOOLEAN
DosMouseInitialize(VOID
)
998 /* Initialize some memory for storing our data that should be available to DOS */
999 MouseDataSegment
= DosAllocateMemory(sizeof(MOUSE_DRIVER
), NULL
);
1000 if (MouseDataSegment
== 0) return FALSE
;
1001 MouseData
= (PMOUSE_DRIVER
)SEG_OFF_TO_PTR(MouseDataSegment
, 0x0000);
1003 /* Initialize the callback context */
1004 InitializeContext(&MouseContext
, MouseDataSegment
, FIELD_OFFSET(MOUSE_DRIVER
, MouseContextScratch
));
1006 /* Clear the state */
1007 RtlZeroMemory(&DriverState
, sizeof(DriverState
));
1009 /* Mouse Driver Copyright */
1010 RtlCopyMemory(MouseData
->Copyright
, MouseCopyright
, sizeof(MouseCopyright
)-1);
1012 /* Mouse Driver Version in BCD format, compatible MS-MOUSE */
1013 MouseData
->Version
= MAKEWORD(MOUSE_VERSION
/0x0100, MOUSE_VERSION
%0x0100);
1015 /* Get the old mouse service interrupt handler */
1016 OldIntHandler
= ((PDWORD
)BaseAddress
)[DOS_MOUSE_INTERRUPT
];
1018 /* Initialize the interrupt handler */
1019 RegisterInt32(MAKELONG(FIELD_OFFSET(MOUSE_DRIVER
, MouseDosInt16Stub
), MouseDataSegment
),
1020 DOS_MOUSE_INTERRUPT
, DosMouseService
, NULL
);
1026 VOID
DosMouseCleanup(VOID
)
1028 /* Restore the old mouse service interrupt handler */
1029 ((PDWORD
)BaseAddress
)[DOS_MOUSE_INTERRUPT
] = OldIntHandler
;
1031 if (DriverState
.ShowCount
> 0) EraseMouseCursor();