├── mouse.lnk ├── .gitignore ├── install.bat ├── setupenv.bat ├── mouse.def ├── oemsetup.inf ├── makefile ├── mouse.inc ├── README.md ├── mouse.asm └── ps2.asm /mouse.lnk: -------------------------------------------------------------------------------- 1 | mouse ps2 2 | vmwmouse.drv 3 | vmwmouse/map/al:16 4 | libw /NOD 5 | mouse.def 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # MASM cruft 2 | *.obj 3 | *.lst 4 | *.map 5 | *.sts 6 | *.sym 7 | # Finished object 8 | *.drv 9 | -------------------------------------------------------------------------------- /install.bat: -------------------------------------------------------------------------------- 1 | rem Adapt this to your Windows installation. 2 | rem Only use for development; "production" use should use INF 3 | copy vmwmouse.drv C:\windows\system\mouse.drv 4 | -------------------------------------------------------------------------------- /setupenv.bat: -------------------------------------------------------------------------------- 1 | rem Copy the DDK directory from the DDK CD to DEV. 2 | set PATH=C:\DEV\DDK\286\TOOLS;C:\MSVC\BIN;C:\WINDOWS;C:\DOS 3 | set LIB=C:\DEV\DDK\286\LIB 4 | set INCLUDE=C:\DEV\DDK\286\INC 5 | -------------------------------------------------------------------------------- /mouse.def: -------------------------------------------------------------------------------- 1 | LIBRARY MOUSE 2 | 3 | DESCRIPTION 'VMware Mouse' 4 | EXETYPE WINDOWS 5 | 6 | CODE PRELOAD DISCARDABLE 7 | DATA PRELOAD FIXED SINGLE 8 | 9 | EXPORTS 10 | Inquire @1 11 | Enable @2 12 | Disable @3 13 | MouseGetIntVect @4 14 | WEP 15 | 16 | -------------------------------------------------------------------------------- /oemsetup.inf: -------------------------------------------------------------------------------- 1 | [disks] 2 | 1=.,"VMware Mouse Disk" 3 | [pointing.device] 4 | ;profile = mouse driver, Mouse description, VMD, Optional work section 5 | vmwmouse = 1:vmwmouse.drv, "VMware mouse", x:*vmd 6 | ; XXX: Define a VMD device if we do it (i.e. a:vmwvmd.386) 7 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # Microsoft Mouse Driver 2 | # 3 | # Requirements: 4 | # 5 | # MASM 4.01 or greater with the environment variable INCLUDE set to 6 | # the directories containing CMACROS.INC, and WINDEFS.INC. 7 | # 8 | # MASM 4.00 or greater with the ASM inference definition changed to 9 | # include the directories containing CMACROS.INC, and WINDEFS.INC. 10 | 11 | 12 | # Options: 13 | # 14 | # The command line may define options to MASM by defining the OPT 15 | # macro. By defining the OPT parameter in the make file, any 16 | # possible interaction with an environment definition is avoided. 17 | 18 | OPT = -l #NOP the options feature 19 | 20 | 21 | # Define the default assemble command. This command could actually 22 | # be overridden from the command line, but shouldn't be. 23 | 24 | ASM = masm -v -ML $(OPT) # MASM 4.01 & > 25 | # ASM = masm -v -ML $(OPT) -I\finc # MASM 4.00 26 | 27 | 28 | # Define the default inference rules 29 | 30 | .asm.obj: 31 | $(ASM) $*,$@; 32 | 33 | vmwmouse: vmwmouse.drv 34 | 35 | mouse.obj: mouse.asm mouse.inc 36 | 37 | ps2.obj: ps2.asm mouse.inc 38 | 39 | vmwmouse.drv: mouse.def mouse.obj ps2.obj 40 | link @mouse.lnk 41 | rc vmwmouse.drv 42 | mapsym vmwmouse 43 | -------------------------------------------------------------------------------- /mouse.inc: -------------------------------------------------------------------------------- 1 | ;*************************************************************************** 2 | ; * 3 | ; Copyright (C) 1983,1984 by Microsoft Inc. * 4 | ; * 5 | ;*************************************************************************** 6 | 7 | ;*************************************************************************** 8 | ; * 9 | ; Header file for Microsoft mouse device driver. Contains all machine * 10 | ; specific constant and data structure definitions. * 11 | ; * 12 | ;*************************************************************************** 13 | 14 | extrn __ROMBIOS :abs 15 | 16 | wptr equ word ptr 17 | bptr equ byte ptr 18 | dptr equ dword ptr 19 | 20 | 21 | MASK_PORT equ 21h 22 | 23 | 24 | ; Symbolic equates for contents of the MOUSEINFO data structure 25 | 26 | NUMBER_BUTTONS equ 2 27 | X_SPEED equ 2 28 | Y_SPEED equ 2 29 | 30 | 31 | ; Definitions of the status word passed to the event_proc 32 | ; in the AX register. The registers passed to the event_proc 33 | ; are as follows: 34 | ; 35 | ; AX = status as defined below 36 | ; BX = delta X or normalized abs 37 | ; CX = delta Y or normalized abs 38 | ; DX = number of buttons 39 | ; 40 | ; If the SF_ABSOLUTE bit is clear in the status word, then the 41 | ; BX and CX are reporting relative motion from the last reported 42 | ; position. If this bit is set, then BX and CX contain normalized 43 | ; absolute coordinates between 0 and +65535, which will be mapped 44 | ; by the event_proc onto the display surface 45 | 46 | 47 | SF_MOVEMENT equ 0001h ;Movement occured 48 | SF_B1_DOWN equ 0002h ;Button 1 (SW1) changed to down 49 | SF_B1_UP equ 0004h ;Button 1 (SW1) changed to up 50 | SF_B2_DOWN equ 0008h ;Button 2 (SW3) changed to down 51 | SF_B2_UP equ 0010h ;Button 2 (SW3) changed to up 52 | SF_ABSOLUTE equ 8000h ;BX,CX are normalized absolute coords 53 | 54 | 55 | ; Definitions of the flag byte mouse_flags 56 | 57 | MF_ENABLED equ 00000001b ;Mouse is enabled 58 | MF_INT33H equ 00000010b ;Int 33h mouse found 59 | ; equ 00000100b ; 60 | ; equ 00001000b ; 61 | ; equ 00010000b ; 62 | ; equ 00100000b ; 63 | MF_ON_SLAVEPIC equ 01000000b ;Mouse is on slave PIC 64 | MF_MOUSE_EXISTS equ 10000000b ;Mouse was found at boot time 65 | 66 | 67 | ; Definitions of mouse types for mouse_type variable 68 | 69 | MT_NO_MOUSE equ 0 ;Zero only if MF_MOUSE_EXISTS = 0 70 | MT_BUS equ 1 71 | MT_SERIAL equ 2 72 | MT_INPORT equ 3 73 | MT_PS2 equ 4 74 | MT_HP equ 5 75 | 76 | ; Windows/386 mouse VxD device ID. 77 | 78 | VMD_DEVICE_ID equ 0000Ch 79 | 80 | 81 | ; INT 33h (Mouse) Function Numbers 82 | 83 | MOUSE_SYS_VEC equ 33h ;Software int to call MOUSE.SYS driver 84 | CALL_ON_ANY_INT equ 1Fh ; Call us on any interrupt 85 | CLEAR_COUNTERS equ 11 ; Clear dX and dY counters 86 | BASH_INT_PROC equ 12 ; Overwrite the interrupt routine 87 | SWAP_INT_PROC equ 20 ; Swap interrupt routine 88 | INT33H_RESET equ 00 ; Reset mouse 89 | INT33H_ENABLE equ 32 ; Enable mouse 90 | INT33H_GETINFO equ 24h ; Get mouse information 91 | 92 | ; type of the mouse as reported by the INT 33H driver 93 | 94 | INT33H_BUS equ 1 ; bus mouse 95 | INT33H_SERIAL equ 2 ; bus mouse 96 | INT33H_INPORT equ 3 ; bus mouse 97 | INT33H_PS_2 equ 4 ; bus mouse 98 | INT33H_HP equ 5 ; bus mouse 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **IMPORTANT**: I haven't touched this driver in a while, and there are some 2 | issues with it. I'm happy people got a lot of use and enjoyment out of this 3 | quick weekend hack, but it needs some work I don't have time to give it. 4 | 5 | I would recommend using Javier Pedro's [VBADOS][5] mouse driver, which has 6 | has the benefit of being a `mouse.com` that works with DOS applications, as 7 | well as with both VirtualBox and VMware. 8 | 9 | # VMware mouse driver for Windows 3.x 10 | 11 | Running Windows 3.1 in VMware, DOSBox-X, or QEMU, but annoyed by having to grab 12 | and ungrab the cursor manually? 13 | 14 | Wish you could just move the cursor in and out like a modern OS (one with USB 15 | tablet support or VMware Tools drivers), with no Ctrl+Alt(+G) dancing? 16 | 17 | Or want to control your cursor *at all* under the ESXi web UI? (It doesn't do 18 | relative input.) 19 | 20 | With this driver, now you can. It implements the interface that VMware uses 21 | (the [backdoor][1]), replacing the existing PS/2 mouse driver. 22 | 23 | https://user-images.githubusercontent.com/3161292/143529005-8bedce21-109d-43d1-96c9-8c958a613bd6.mp4 24 | 25 | https://user-images.githubusercontent.com/3161292/144170828-61b586f0-88f0-49b1-ba69-bc371f94753b.mp4 26 | 27 | ## Well, how does it work? 28 | 29 | Glad you asked! 30 | 31 | Normally, mice work by sending a delta of their movements. You'd have to trap 32 | the mouse inside of the guest for this to work; any tracking difference would 33 | result in a very hard to control cursor. Being able to send the absolute 34 | coordinates would be great, because you can know the exact point when the 35 | cursor hits the edge. 36 | 37 | However, there wasn't a standard way of doing absolute positioning with PC 38 | input devices until the USB tablet standard, and Windows 3.x/DOS massively 39 | predate USB, let alone have a USB stack. For those situations, VMware offers 40 | absolute positioning through a port I/O interface. 41 | 42 | So let's use [said interface][2]. What we need to do is threefold for an MVP: 43 | 44 | 1. On initialization, make the cursor absolute (four calls) 45 | 2. On deinitialization, make the cursor relative (a single call) 46 | 3. Instead of parsing PS/2 mouse events, ask VMware for mouse events instead 47 | 4. Well, we should check if we're even using a supported host, but hey... 48 | 49 | The challenge is doing this from real or 286 protected mode, because we need to 50 | set the 32-bit extended versions of the registers (i.e. `EAX` instead of `AX`). 51 | The toolchain we're using is MASM, since we're keeping this easy and using the 52 | example drivers from the DDK, just modified. This means we can just plop the 53 | `.386` directive in a suitable place in the code, and `EAX` will become 54 | available to use. 55 | 56 | One interesting bit with the mouse driver is the `SF_ABSOLUTE` bit in a Windows 57 | mouse driver. When passed as the flags for the mouse event (in `AX`), it'll be 58 | an absolute position instead of relative - exactly what we want, without any 59 | trickery! Even better, it takes a range of 0 through FFFFh, as basically a 60 | percentage of where it is on the screen, in `BX` and `CX`. This way, you don't 61 | need to know the resolution of the screen when calculating the absolute 62 | position. Turns out this is exactly how VMware sends the coordinates in `EBX` 63 | and `ECX`! 64 | 65 | The unfortunate difference is in button handling; VMware sends what buttons 66 | are currently held, while Windows wants to know when the button goes down and 67 | when it comes up. I've implemented a crude solution, but I think it could be 68 | done a lot better. Right now, only two buttons are supported, but in theory, 69 | we could send a third with a refactor to the driver. (We're also throwing away 70 | the wheel event - that could be four and five, considering Windows 3.x predates 71 | the wheel entirely.) 72 | 73 | One annoying thing about the sample driver is because the fact it supports 74 | multiple types of mouse, it uses a tactic of copying the interrupt handler into 75 | a specifically sized buffer. This means you can't go over 210 bytes for the 76 | interrupt handler right now; this could be alleviated with a major refactor or 77 | rewrite. For now, I've excised the normal PS/2 mouse handling in favour of only 78 | using the VMware backdoor. I've also had to occasionally be worried about the 79 | length of instructions; shaving things off by only using the 16-bit view of a 80 | register, for example. 81 | 82 | Overall, I'm glad this was surprisingly easy, considering I didn't know x86 83 | assembly before, and I only implemented this in a day - with lots of struggling 84 | against MASM and typos. 85 | 86 | (Updates: I've cleaned up button handling, and I'm experimenting on the wheel.) 87 | 88 | ## Supported hosts 89 | 90 | VMware and QEMU are supported. I have tested Workstation and ESXi. I can't test 91 | Fusion because my Mac is M1, so oh well. 92 | 93 | VMware will need no configuration. QEMU also needs no configuration - the vmmouse 94 | automatically gets attached when the backdoor is added. Don't try adding it any 95 | command line flags; you're likely to just crash it. 96 | 97 | (For QEMU, you can verify things by running `info mice` and `info qtree`.) 98 | 99 | ## Building from source 100 | 101 | Make sure you have the [Windows 3.1 Device Development Kit][3] installed. 102 | 103 | Inspect the values in `SETUPENV.BAT` and `INSTALL.BAT`, then run: 104 | 105 | ``` 106 | setupenv.bat 107 | nmake 108 | ``` 109 | 110 | ## Installation 111 | 112 | ### Source 113 | 114 | If building from source; after building, run `INSTALL.BAT`. This will overwrite 115 | the stock mouse driver, so make a backup. The INF install is less crumbly, so I 116 | recommend you go for that. 117 | 118 | ### Binaries 119 | 120 | If using binaries, run Windows Setup. Point where the driver and INF file are; 121 | if you're using the floppy, it'll likely be `A:`. Restart Windows and enjoy. 122 | Serve with garnish. 123 | 124 | Note that if you're using the GUI version of Windows Setup, after selecting 125 | the VMware mouse driver for the first time, the combo box might go blank. If 126 | that's the case, you need to select it again. This doesn't happen from the DOS 127 | version of Windows Setup (when setup is run outside of Windows or at install). 128 | 129 | ## Similar drivers 130 | 131 | * [Javier's VirtualBox mouse driver][4] 132 | 133 | [1]: https://wiki.osdev.org/VMware_tools 134 | [2]: https://wiki.osdev.org/VMware_tools#Absolute_Mouse_Coordinates 135 | [3]: https://winworldpc.com/download/3d0639c3-9e18-c39a-11c3-a4e284a2c3a5 136 | [4]: https://git.javispedro.com/cgit/vbmouse.git/tree/ 137 | [5]: https://git.javispedro.com/cgit/vbados.git/about/ 138 | -------------------------------------------------------------------------------- /mouse.asm: -------------------------------------------------------------------------------- 1 | page ,132 2 | ;-----------------------------Module-Header-----------------------------; 3 | ; Module Name: MOUSE.ASM 4 | ; 5 | ; Windows mouse driver data and initialization routines. 6 | ; 7 | ; Created: Yester-year 8 | ; Author: Walt Moore [waltm], Mr. Mouse, and a cast of tens. 9 | ; Sun 04-Dec-1988 21:31:36 -by- David N. Weise [davidw] 10 | ; Made it bi-modal. 11 | ; 03-May-1989 RAL -by- Ralph Lipe 12 | ; Calls Windows/386 VxD when mouse detected 13 | ; 14 | ; Copyright (c) 1987, 1988, 1989 Microsoft Corporation 15 | ; 16 | ; Exported Functions: 17 | ; 18 | ; Public Functions: 19 | ; 20 | ; Public Data: 21 | ; 22 | ; General Description: 23 | ; 24 | ; This segment contains all static data used by the mouse routines. The 25 | ; hardware interrupt routine is included in the static data so that it 26 | ; has addressability to the static data through the CS register. Thus 27 | ; the data segment of this module MUST be fixed in memory, while the 28 | ; code segment can be moveable and/or discardable. 29 | ; 30 | ;-----------------------------------------------------------------------; 31 | 32 | title Mouse - Main Mouse Module 33 | 34 | .xlist 35 | include cmacros.inc 36 | include windefs.inc 37 | include mouse.inc 38 | .list 39 | 40 | externNP ps2_search 41 | externNP ps2_enable 42 | externNP ps2_disable 43 | externNP ps2_int 44 | 45 | externA __WINFLAGS 46 | 47 | sBegin Data 48 | 49 | globalW WinFlags,__WINFLAGS ;Windows environment flags 50 | globalB vector,-1 ;Vector # of mouse interrupt 51 | globalB mask_8259,0FFh ;8259 interrupt enable mask, FF if none 52 | globalB old_8259_mask,0FFh ;Value of mouse irq bit before enable 53 | globalB mouse_flags,0 ;Various flags 54 | globalB mouse_type,0 ;Type of mouse (inport/bus/serial/etc.) 55 | 56 | even ;Want words on word boundary 57 | 58 | globalW io_base,0 ;Mouse port base address 59 | globalD event_proc,0 ;Mouse event procedure when enabled 60 | globalD bios_proc,0 ;Contents of old interrupt vector 61 | 62 | globalW interrupt_rate,30 ;Maximum interrupt rate of mouse 63 | 64 | page 65 | 66 | sEnd Data 67 | 68 | sBegin Code 69 | assumes cs,Code 70 | 71 | ;--------------------------Exported-Routine-----------------------------; 72 | ; int Inquire(lp_mouse_info); 73 | ; 74 | ; Information regarding the mouse is returned to the caller. 75 | ; 76 | ; Entry: 77 | ; None 78 | ; Returns: 79 | ; AX = # bytes returned in lp_mouse_info 80 | ; Error Returns: 81 | ; None 82 | ; Registers Preserved: 83 | ; SI,DI,DS,BP 84 | ; Registers Destroyed: 85 | ; AX,BX,CX,DX,ES,FLAGS 86 | ; Calls: 87 | ; None 88 | ; History: 89 | ; Fri 21-Aug-1987 11:43:42 -by- Walt Moore [waltm] & Mr. Mouse 90 | ; Initial version 91 | ;-----------------------------------------------------------------------; 92 | 93 | ;------------------------------Pseudo-Code------------------------------; 94 | ; { 95 | ; } 96 | ;-----------------------------------------------------------------------; 97 | 98 | assumes cs,Code 99 | assumes ds,Data 100 | 101 | cProc Inquire,, 102 | 103 | parmD lp_mouse_info 104 | 105 | cBegin 106 | les di,lp_mouse_info ;Get far pointer of destination area 107 | assumes es,nothing 108 | 109 | mov al,mouse_flags ;Get and save msExists, msRelative 110 | cbw 111 | xchg al,ah ;AL = 0FFh if mouse exists, 00 if not 112 | .errnz MF_MOUSE_EXISTS-80h 113 | 114 | mov ah,0 ;AH = 0FFh if relative coordinates 115 | stosw ; (but is currently ignored!) 116 | .errnz msExists 117 | .errnz msRelative-msExists-1 118 | 119 | mov ax,NUMBER_BUTTONS ;Return number of buttons 120 | stosw 121 | .errnz msNumButtons-msRelative-1 122 | 123 | mov ax,interrupt_rate ;Return maximum interrupt rate 124 | stosw 125 | .errnz msRate-msNumButtons-2 126 | 127 | mov ax,X_SPEED ;Return threshold before acceleration 128 | stosw 129 | .errnz msXThresh-msRate-2 130 | 131 | if Y_SPEED ne X_SPEED ;Generally they're the same 132 | mov ax,Y_SPEED ;Return threshold before acceleration 133 | endif 134 | stosw 135 | .errnz msYThresh-msXThresh-2 136 | 137 | xor ax,ax ;Return useless x,y resolution info 138 | stosw 139 | stosw 140 | .errnz msXRes-msYThresh-2 141 | .errnz msYRes-msXRes-2 142 | .errnz msYRes+2 - size MOUSEINFO 143 | 144 | mov ax,size MOUSEINFO ;Return size of info 145 | 146 | cEnd 147 | page 148 | 149 | ;--------------------------Exported-Routine-----------------------------; 150 | ; void Enable(lp_event_proc); 151 | ; 152 | ; Enable hardware mouse interrupts, with the passed procedure address 153 | ; being the target of all mouse events. 154 | ; 155 | ; This routine may be called while already enabled. In this case the 156 | ; passed event procedure should be saved, and all other initialization 157 | ; skipped. 158 | ; 159 | ; Entry: 160 | ; None 161 | ; Returns: 162 | ; None 163 | ; Error Returns: 164 | ; None 165 | ; Registers Preserved: 166 | ; SI,DI,DS,BP 167 | ; Registers Destroyed: 168 | ; AX,BX,CX,DX,ES,FLAGS 169 | ; Calls: 170 | ; ps2_enable 171 | ; History: 172 | ; Fri 21-Aug-1987 11:43:42 -by- Walt Moore [waltm] & Mr. Mouse 173 | ; Initial version 174 | ;-----------------------------------------------------------------------; 175 | 176 | ;------------------------------Pseudo-Code------------------------------; 177 | ; { 178 | ; } 179 | ;-----------------------------------------------------------------------; 180 | 181 | assumes cs,Code 182 | assumes ds,Data 183 | 184 | cProc Enable,, 185 | 186 | parmD new_event_proc 187 | 188 | cBegin 189 | 190 | ; The new event procedure is always saved regardless of the 191 | ; mouse already being enabled. This allows the event proc 192 | ; to be changed as needed. 193 | 194 | cli ;Protect against interrupt while 195 | mov ax,off_new_event_proc ; changing the vector 196 | mov wptr event_proc[0],ax 197 | mov ax,seg_new_event_proc 198 | mov wptr event_proc[2],ax 199 | sti 200 | 201 | ; If the mouse is already enabled, or it doesn't exist, then 202 | ; we're all done with the enable call. 203 | 204 | mov al,mouse_flags ;If enabled or mouse doesn't exist, 205 | xor al,MF_MOUSE_EXISTS ; then skip the enabling 206 | test al,MF_ENABLED+MF_MOUSE_EXISTS 207 | jnz enable_done 208 | call ps2_enable ;Mouse specific initialization 209 | or mouse_flags,MF_ENABLED ;Show enabled now 210 | 211 | enable_done: 212 | 213 | cEnd 214 | page 215 | 216 | ;--------------------------Exported-Routine-----------------------------; 217 | ; void Disable(); 218 | ; 219 | ; Disable hardware mouse interrupts, restoring the previous mouse 220 | ; interrupt handler and 8259 interrupt enable mask. 221 | ; 222 | ; This routine may be called while already disabled. In this case the 223 | ; disabling should be ignored. 224 | ; 225 | ; Entry: 226 | ; None 227 | ; Returns: 228 | ; None 229 | ; Error Returns: 230 | ; None 231 | ; Registers Preserved: 232 | ; SI,DI,DS,BP 233 | ; Registers Destroyed: 234 | ; AX,BX,CX,DX,ES,FLAGS 235 | ; Calls: 236 | ; ps2_disable 237 | ; History: 238 | ; Fri 21-Aug-1987 11:43:42 -by- Walt Moore [waltm] & Mr. Mouse 239 | ; Initial version 240 | ;-----------------------------------------------------------------------; 241 | 242 | ;------------------------------Pseudo-Code------------------------------; 243 | ; { 244 | ; } 245 | ;-----------------------------------------------------------------------; 246 | 247 | assumes cs,Code 248 | assumes ds,Data 249 | 250 | cProc Disable,, 251 | 252 | cBegin 253 | test mouse_flags,MF_ENABLED 254 | jz disable_done ;Mouse is already disabled 255 | call ps2_disable ;Disable as needed 256 | and mouse_flags,not MF_ENABLED 257 | 258 | disable_done: 259 | 260 | cEnd 261 | page 262 | 263 | ;--------------------------Exported-Routine-----------------------------; 264 | ; WORD WEP(); 265 | ; 266 | ; Generic WEP. 267 | ; 268 | ; Entry: 269 | ; None 270 | ; Returns: 271 | ; AX = 1 272 | ; Error Returns: 273 | ; None 274 | ; Registers Preserved: 275 | ; all 276 | ; Registers Destroyed: 277 | ; none 278 | ; Calls: 279 | ; nothing 280 | ; History: 281 | ; Wed 18-Oct-1989 11:44:39 -by- David N. Weise [davidw] 282 | ; Wrote it! 283 | ;-----------------------------------------------------------------------; 284 | 285 | ;------------------------------Pseudo-Code------------------------------; 286 | ; { 287 | ; } 288 | ;-----------------------------------------------------------------------; 289 | 290 | assumes cs,Code 291 | assumes ds,Data 292 | 293 | cProc WEP, 294 | ; parmW stuff 295 | cBegin nogen 296 | mov ax,1 297 | ret 2 298 | cEnd nogen 299 | page 300 | 301 | ;--------------------------Exported-Routine-----------------------------; 302 | ; int MouseGetIntVect(); 303 | ; 304 | ; The interrupt vector used by the mouse is returned to the caller. 305 | ; If no mouse is found, then -1 is returned. 306 | ; 307 | ; Entry: 308 | ; None 309 | ; Returns: 310 | ; AX = interrupt vector 311 | ; AX = -1 if no mouse was found 312 | ; Error Returns: 313 | ; None 314 | ; Registers Preserved: 315 | ; SI,DI,DS,BP 316 | ; Registers Destroyed: 317 | ; AX,BX,CX,DX,ES,FLAGS 318 | ; Calls: 319 | ; None 320 | ; History: 321 | ; Fri 21-Aug-1987 11:43:42 -by- Walt Moore [waltm] & Mr. Mouse 322 | ; Initial version 323 | ;-----------------------------------------------------------------------; 324 | 325 | ;------------------------------Pseudo-Code------------------------------; 326 | ; { 327 | ; } 328 | ;-----------------------------------------------------------------------; 329 | 330 | assumes cs,Code 331 | assumes ds,Data 332 | 333 | cProc MouseGetIntVect, 334 | 335 | cBegin 336 | 337 | ; NOTE! vector must be less than 7Fh for the sign extension to work 338 | 339 | mov al,vector ;Will be -1 if mouse wasn't found 340 | cbw ;AX = -1 if no mouse was found 341 | cEnd 342 | page 343 | 344 | ;---------------------------Public-Routine-----------------------------; 345 | ; hook_us_in 346 | ; 347 | ; This is a utility routine for the specific mouse handlers. The 348 | ; following initialization will be performed in preperation of 349 | ; hooking in the interrupt handler: 350 | ; 351 | ; save old 8259 mask 352 | ; disable our IRQ at the 8259 353 | ; save old interrupt vector contents 354 | ; set new interrupt vector 355 | ; 356 | ; Entry: 357 | ; None offset in Data segment of interrupt handler 358 | ; Returns: 359 | ; None 360 | ; Error Returns: 361 | ; None 362 | ; Registers Preserved: 363 | ; DI,SI,DS,BP 364 | ; Registers Destroyed: 365 | ; AX,BX,CX,DX,ES,FLAGS 366 | ; Calls: 367 | ; Int 21h 368 | ; History: 369 | ; Mon 24-Aug-1987 22:41:22 -by- Walt Moore [waltm] & Mr. Mouse 370 | ; Initial version 371 | ;-----------------------------------------------------------------------; 372 | 373 | ;------------------------------Pseudo-Code------------------------------; 374 | ; { 375 | ; } 376 | ;-----------------------------------------------------------------------; 377 | 378 | assumes cs,Code 379 | assumes ds,Data 380 | 381 | public hook_us_in 382 | hook_us_in proc near 383 | 384 | mov ah,mask_8259 ;Get our 8259 enable mask 385 | xor ah,0FFh ;A 1 bit for our IRQ (not AH) 386 | jz hook_us_in_no_irq ;No IRQ is involved 387 | cli 388 | in al,MASK_PORT ;Get current 8259 mask 389 | mov bl,al 390 | or al,ah 391 | and bl,ah ;Isolate old mouse IRQ bit 392 | out MASK_PORT,al ;Disable mouse int 393 | sti 394 | 395 | mov old_8259_mask,bl ;Will be 0 if previously enabled 396 | 397 | hook_us_in_no_irq: 398 | mov ah,35h ;Save old interrupt vector 399 | mov al,vector 400 | int 21h 401 | mov wptr bios_proc[0],bx 402 | mov wptr bios_proc[2],es 403 | 404 | push ds 405 | push seg ps2_int 406 | mov ah,25h ;Set our interrupt vector 407 | mov al,vector ; need the real DS here; cs[vector] bad 408 | pop ds ; now it's safe to set DS for DS:DX 409 | mov dx,CodeOFFSET ps2_int 410 | int 21h 411 | pop ds 412 | sti 413 | 414 | ret 415 | 416 | hook_us_in endp 417 | page 418 | 419 | ;---------------------------Public-Routine-----------------------------; 420 | ; unhook_us 421 | ; 422 | ; This is a utility routine for the specific mouse handlers. The 423 | ; interrupt vector will be restored to its previous value and the 424 | ; old IRQ enable bit will be restored. 425 | ; 426 | ; Entry: 427 | ; None 428 | ; Returns: 429 | ; 'Z' set if IRQ should be left enabled at the device 430 | ; 'Z' clear if IRQ should be left disabled at the device 431 | ; Error Returns: 432 | ; None 433 | ; Registers Preserved: 434 | ; SI,DI,DS,BP 435 | ; Registers Destroyed: 436 | ; AX,BX,CX,DX,ES,FLAGS 437 | ; Calls: 438 | ; Int 21h 439 | ; History: 440 | ; Mon 24-Aug-1987 22:41:22 -by- Walt Moore [waltm] & Mr. Mouse 441 | ; Initial version 442 | ;-----------------------------------------------------------------------; 443 | 444 | ;------------------------------Pseudo-Code------------------------------; 445 | ; { 446 | ; } 447 | ;-----------------------------------------------------------------------; 448 | 449 | assumes cs,Code 450 | assumes ds,Data 451 | 452 | public unhook_us 453 | unhook_us proc near 454 | 455 | mov ah,mask_8259 ;Disable our interrupt at the 456 | xor ah,0FFh ; 8259 before changing the (not AH) 457 | jz unhook_no_irq ; vector since old versions 458 | cli ; of DOS may not cli/sti 459 | in al,MASK_PORT ; while setting int vectors 460 | or al,ah 461 | out MASK_PORT,al 462 | sti 463 | 464 | unhook_no_irq: 465 | cmp wptr bios_proc[2],0 ; PS2 mouse may have failed enable 466 | jz unhook_no_bios_proc ; so bios proc might not be set. 467 | push ds 468 | mov ah,25h ;Restore old interrupt vector 469 | mov al,vector 470 | lds dx,bios_proc 471 | assumes ds,nothing 472 | 473 | int 21h 474 | 475 | pop ds 476 | assumes ds,Data 477 | 478 | unhook_no_bios_proc: 479 | 480 | ; If IRQ mask will be set to whatever value it was when we were 481 | ; enabled. If there is no Int 33h mouse driver in the system, 482 | ; then flag the caller that interrupts should be disabled at the 483 | ; device. If there is an Int33h mouse driver and interrupts 484 | ; were disabled upon entry, also flag the caller to disable 485 | ; interrupts at the device. Only allow device interrupts to 486 | ; continue being generated if there is an Int33h mouse and 487 | ; the IRQ was previously enabled. 488 | ; 489 | ; This is in part a fix for running on IRQ2 in Compaqs and 490 | ; other machines which try to allow this. I don't recommend 491 | ; IRQ2 for ATs and compatibles, but some people try and it 492 | ; almost seems to work if mouse.com is there to handle the 493 | ; interrupt. 494 | 495 | test old_8259_mask,0FFh ;If interrupts were previous disabled 496 | jnz unhook_exit ; then leave them disabled ('Z' clear) 497 | mov ah,mask_8259 498 | cli 499 | in al,MASK_PORT 500 | and al,ah 501 | out MASK_PORT,al 502 | sti 503 | mov al,mouse_flags 504 | not al 505 | and al,MF_INT33H ;'Z' clear if to disable at the device 506 | 507 | unhook_exit: 508 | ret 509 | 510 | unhook_us endp 511 | page 512 | 513 | ;---------------------------Public-Routine-----------------------------; 514 | ; Initialize 515 | ; 516 | ; All boot time initialization will be performed. This basically 517 | ; involves searching for a mouse in the system. The ordering in 518 | ; which we will search is as follows: 519 | ; 520 | ; VMware paravirtual mouse 521 | ; 522 | ; After a mouse handler has been found, the Data segment will be 523 | ; resized to the minimum needed to support the mouse in use. 524 | ; 525 | ; Entry: 526 | ; CX = size of heap 527 | ; DI = module handle 528 | ; DS = automatic data segment 529 | ; ES:SI = address of command line (not used) 530 | ; Returns: 531 | ; AX <> 0 to show success 532 | ; Error Returns: 533 | ; None 534 | ; Registers Preserved: 535 | ; SI,DI,DS,BP 536 | ; Registers Destroyed: 537 | ; AX,BX,CX,DX,ES,FLAGS 538 | ; Calls: 539 | ; PS2_search 540 | ; History: 541 | ; Fri 21-Aug-1987 11:43:42 -by- Walt Moore [waltm] & Mr. Mouse 542 | ; Initial version 543 | ;-----------------------------------------------------------------------; 544 | 545 | ;------------------------------Pseudo-Code------------------------------; 546 | ; { 547 | ; } 548 | ;-----------------------------------------------------------------------; 549 | 550 | assumes cs,Code 551 | assumes ds,Data 552 | 553 | cProc Initialize,, 554 | 555 | cBegin 556 | 557 | ;-----------------------------------------------------------------------; 558 | ; Regardless of using the Int33h mouse driver, we need to 559 | ; know if it is present for disabling IRQs when the mouse 560 | ; is disabled. 561 | ;-----------------------------------------------------------------------; 562 | 563 | if 0 ;---------------------------------------------------------------- 564 | 565 | ; This code was for earlier versions of the Microsoft mouse driver which 566 | ; didn't support the GetMouseInfo call. Windows 3.0 is shipping DOS 567 | ; mouse driver 7.0x. 6.?? added the GetMouseInfo call. 568 | 569 | ; We would have liked to have done a mouse reset to see if 570 | ; the mouse was installed. However, this disables any 571 | ; user-installed call out (like menus). What we will do 572 | ; instead is the following: 573 | ; 574 | ; Swap in a bogus interrupt procedure and an event 575 | ; mask which says don't call out. If the mouse driver 576 | ; is present, then we should get back something different 577 | ; than what was passed in. If we do get back something 578 | ; different, we'll restore that data and see if what is 579 | ; returned is what was originally passed in. If so, we 580 | ; have a mouse driver, version 6.00 or greater and menus 581 | ; will still be enabled. 582 | ; 583 | ; If the above test fails, we'll do the mouse reset to 584 | ; see if the mouse is installed. This will trash menus, 585 | ; but there isn't much we can do about it. 586 | 587 | test hello,1 ;!!! just for now (WinFlags) 588 | jnz check_ps2 589 | push cs ;ES:DX --> bogus_far_ret 590 | pop es 591 | mov dx,CodeOFFSET bogus_far_ret 592 | xor cx,cx ;Don't call installed int proc 593 | mov ax,SWAP_INT_PROC ;Swap interrupt routine 594 | int MOUSE_SYS_VEC 595 | cmp dx,CodeOFFSET bogus_far_ret 596 | jne swap_them_back ;Different interrupt proc address, 597 | mov ax,cs ; might be a mouse 598 | mov bx,es 599 | cmp ax,bx 600 | je try_mouse_reset ;Int proc address same, might be < 6.00 601 | 602 | ;-----------------------------------------------------------------------; 603 | ; The procedure address which was returned was different that what 604 | ; we passed in. Restore it and see if what is returned is what we 605 | ; had originally passed in. If so, this is a 6.00 or greater mouse. 606 | ;-----------------------------------------------------------------------; 607 | 608 | swap_them_back: 609 | mov ax,SWAP_INT_PROC ;Swap interrupt routine. Should get 610 | int MOUSE_SYS_VEC ; back what we set initially 611 | cmp dx,CodeOFFSET bogus_far_ret 612 | jne try_mouse_reset ;Not a 6.00+ mouse driver, go see 613 | mov ax,cs ; if it might some other version 614 | mov bx,es 615 | cmp ax,bx 616 | jne try_mouse_reset ;Not 6.00+ 617 | jcxz sys_mouse_present ;6.00 or greater 618 | 619 | else ;----------------------------------------------------------------- 620 | 621 | xor bx,bx ;Current DOS mouse drivers implement 622 | mov ax,INT33H_GETINFO ; a Get Mouse Info call 623 | int MOUSE_SYS_VEC 624 | cmp bh,6 ;Major version in bh, started @ 6.?? 625 | jb try_mouse_reset 626 | jmp short sys_mouse_present 627 | 628 | endif ;----------------------------------------------------------------- 629 | 630 | try_mouse_reset: 631 | xor ax,ax ;Check for DOS mouse driver 632 | .errnz INT33H_RESET 633 | int MOUSE_SYS_VEC 634 | or ax,ax ;Zero if no mouse installed 635 | jz check_ps2 636 | 637 | sys_mouse_present: 638 | or mouse_flags,MF_INT33H ;Show mouse driver is present 639 | 640 | check_ps2: 641 | mov mouse_type, MT_PS2 ;Assume PS/2 mouse 642 | call ps2_search ;PS/2 mouse port? 643 | jc got_mouse 644 | mov mouse_type, MT_NO_MOUSE ;Reset mouse type to none 645 | jmp short resize_ds 646 | 647 | got_mouse: 648 | ; 649 | ; If running under Windows/386 then tell the Win386 mouse driver what 650 | ; type of mouse we found. 651 | ; 652 | push ax 653 | push bx 654 | push di 655 | push es 656 | 657 | %OUT Test flags for Win386 here! 658 | xor di, di 659 | mov es, di 660 | mov ax, 1684h ;Get device API entry point 661 | mov bx, VMD_DEVICE_ID ;for the Virtual Mouse Device 662 | int 2Fh 663 | mov ax, es 664 | or ax, di ;Q: Does VMD have API entry point? 665 | jz copy_mouse_routines ; N: Done 666 | 667 | push cs ;Return to here after call to Win386 668 | mov bx, offset vmd_call_done;virtual mouse driver 669 | push bx 670 | push es ;Call this SEG:OFF by doing a far 671 | push di ;return 672 | 673 | mov ax, 100h ;Set mouse type & int VECTOR API call 674 | mov bl, mouse_type 675 | mov bh, vector 676 | 677 | BogusFarRetProc PROC FAR 678 | ret ;"Return" to VMD's API entry point 679 | BogusFarRetProc ENDP 680 | 681 | vmd_call_done: 682 | copy_mouse_routines: 683 | pop es 684 | pop di 685 | pop bx 686 | pop ax 687 | 688 | 689 | or mouse_flags,MF_MOUSE_EXISTS 690 | 691 | resize_ds: 692 | ; Claims to resize the data segment, but who cares anymore? 693 | 694 | mov ax,1 ;Successful initialization 695 | 696 | cEnd 697 | page 698 | 699 | ;-----------------------------------------------------------------------; 700 | ; bogus_far_ret is a far return instruction which can be 701 | ; passed off to the INT 33h mouse detection logic routine. 702 | ;-----------------------------------------------------------------------; 703 | 704 | bogus_far_ret proc far 705 | 706 | ret 707 | 708 | bogus_far_ret endp 709 | 710 | sEnd Code 711 | end Initialize 712 | -------------------------------------------------------------------------------- /ps2.asm: -------------------------------------------------------------------------------- 1 | page ,132 2 | ;-----------------------------Module-Header-----------------------------; 3 | ; Module Name: PS2.ASM 4 | ; 5 | ; Windows mouse driver data and initialization routines for using the 6 | ; PS/2 mouse port. 7 | ; 8 | ; Created: 21-Aug-1987 9 | ; Author: Mr. Mouse [mickeym], Walt Moore [waltm] 10 | ; 11 | ; Modifications: 12 | ; 13 | ; 28-Mar-1990 jimmat Also disabled interrupts on Int 33h enable 14 | ; call from ps2_disable routine. This has the same problem as the Int 15h 15 | ; calls documented below (in this case, it's the DOS mouse driver making 16 | ; the Int 15h calls, not the Windows driver). What a hack for these 17 | ; 2500 XL machines! They should fix their BIOS! 18 | ; 19 | ; 07-Feb-1990. -by- Jim Mathews [jimmat] & Amit Chatterjee [amitc] 20 | ; Across all INT 15H calls in the enable and disable procedures we will 21 | ; mask off all interrupts but for IRQ 1 & 2. This was done to fix a bug that 22 | ; occured on TANDY 2500XL machines. 23 | ; 24 | ; On these machines the mouse port communicates with the 8042 keyboard 25 | ; controller which is also used by HIMEM.SYS to toggle the state of the A20 26 | ; line. A command byte that is output to the 8042 and is intended for the 27 | ; mouse port is preceeded by a special 'escape' byte (D4H) which tells the 28 | ; 8042 that the next byte is for the mouse. If an interrupt causes the DOSX 29 | ; to switch to protected mode after the escape byte has been output but before 30 | ; the actual mouse command could be output, then DOSX would program the 8042 31 | ; to enable the A20 line and make the 8042 lose the synchronization with the 32 | ; BIOS code. To take care of this problem we disble all interrupts but for 33 | ; IRQ 1 & 2 when we make INT 15H mouse related calls. 34 | ; 35 | ; Copyright (c) 1986,1987 Microsoft Corporation 36 | ; 37 | ; Exported Functions: 38 | ; None 39 | ; Public Functions: 40 | ; ps2_enable 41 | ; ps2_disable 42 | ; ps2_search 43 | ; Public Data: 44 | ; None 45 | ; General Description: 46 | ; This module contains the functions to find, enable, disable, 47 | ; and process interrupts for an 8255 Bus Mouse. 48 | ;-----------------------------------------------------------------------; 49 | 50 | title PS/2 Mouse Hardware Dependent Code 51 | 52 | .xlist 53 | include cmacros.inc 54 | include mouse.inc 55 | .list 56 | .386 ; it must go here it seems 57 | 58 | ??_out PS2 59 | 60 | 61 | externNP hook_us_in ;Hook us into our interrupt 62 | externNP unhook_us ;Hook us out of our interrupt 63 | 64 | externFP GetModuleHandle 65 | externFP GetProcAddress 66 | externFP GetPrivateProfileInt 67 | 68 | 69 | ; (CB) Constants for VMware backdoor. 70 | VMWARE_MAGIC equ 564D5868h 71 | VMWARE_PORT equ 5658h 72 | ; commands are not hex 73 | CMD_GETVERSION equ 10 74 | CMD_ABSPOINTER_DATA equ 39 75 | CMD_ABSPOINTER_STATUS equ 40 76 | CMD_ABSPOINTER_COMMAND equ 41 77 | ABSPOINTER_ENABLE equ 45414552h 78 | ABSPOINTER_RELATIVE equ 0F5h 79 | ABSPOINTER_ABSOLUTE equ 53424152h 80 | 81 | ; Subfunctions to int 15h 82 | 83 | I15_GET_CONFIG equ 0C0h ;Get configuration 84 | I15_MOUSE_SUBFUNC equ 0C2h ;Mouse subfunction to int 15h 85 | 86 | PS2MSF_ENAB_DISAB equ 0 ; Enable/Disable subfunction 87 | PS2MSF_RESET equ 1 ; Reset 88 | PS2MSF_SET_SAMPLE equ 2 ; Set sample rate 89 | PS2MSF_SET_RES equ 3 ; Set resolution 90 | PS2MSF_INIT equ 5 ; Initialize subfunction 91 | PS2MSF_SET_SCALING equ 6 ; Set scaling 92 | PS2MSF_INSTALL_IH equ 7 ; Install interrupt handler 93 | 94 | ; parameters for the subfunctions, usually passed in BH 95 | 96 | PS2M_PACKET_SIZE equ 3 ;Use three byte packets for mouse 97 | PS2M_TRANS_ERROR equ 4 ;Transmission error code 98 | PS2M_CNTS_PER_MM equ 3 ;3 count per mm = ~ 200 ppi 99 | PS2M_DISABLE equ 0 ;Disable the mouse 100 | PS2M_ENABLE equ 1 ;Enable the mouse 101 | PS2M_SCALING equ 1 ;1:1 scaling 102 | PS2M_SAMPLING_40 equ 2 ;40 reports per second 103 | PS2M_SAMPLING_100 equ 5 ;100 reports per second 104 | 105 | 106 | ; PS_2 status byte definition 107 | 108 | VMWARE_LEFT equ 20h ; Status of left button 109 | VMWARE_RIGHT equ 10h ; Status of right button 110 | VMWARE_MIDDLE equ 08h ; Status of middle button 111 | 112 | ; dynamic runtime stuff 113 | 114 | POSTMESSAGE equ 110 ; export ordinal of PostMessage() 115 | 116 | sBegin Data 117 | 118 | externB vector ;Vector # of mouse interrupt 119 | externB mouse_flags ;Various flags as follows 120 | externD event_proc ;Mouse event procedure when enabled 121 | externD bios_proc ;Contents of old interrupt vector 122 | 123 | ; These used to be copied to device_int, but since we just keep the interrupt 124 | ; handler in the code segment, we move these to the data segment. 125 | 126 | ; PS2_DATA_FLAG is where the flag indicating there is 127 | ; valid mouse data is stored. If this location is non- 128 | ; zero, then the following locations contain valid data. 129 | globalB PS2_DATA_FLAG, 0 130 | 131 | globalW prev_x, 0 132 | globalW prev_y, 0 133 | globalW prev_state, 0 134 | 135 | globalW wheel_enabled, 0 136 | 137 | ;-----------------------------------------------------------------------; 138 | ; state_xlate 139 | ; 140 | ; state_xlate is used to translate the current and previous 141 | ; button state information into the values required by 142 | ; Windows. It is indexed as follows: 143 | ; 144 | ; pB2 pB1 cB2 cB1 145 | ; 146 | ; | | | | 147 | ; | | | --- 1 if button 1 is down, 0 if button 1 is up 148 | ; | | | 149 | ; | | ------- 1 if button 2 is down, 0 if button 2 is up 150 | ; | | 151 | ; | ----------- 1 if button 1 was down, 0 if button 1 was up 152 | ; | 153 | ; --------------- 1 if button 2 was down, 0 if button 2 was up 154 | ; 155 | ; This table must be copied to the data segment along with the 156 | ; interrupt handler. 157 | ; 158 | ;-----------------------------------------------------------------------; 159 | 160 | page 161 | 162 | state_xlate db 0 163 | ;db 0 shr 1 164 | db (SF_B1_DOWN) shr 1 165 | db (SF_B2_DOWN) shr 1 166 | db (SF_B2_DOWN+SF_B1_DOWN) shr 1 167 | 168 | db (SF_B1_UP) shr 1 169 | db 0 shr 1 170 | db (SF_B1_UP+SF_B2_DOWN) shr 1 171 | db (SF_B2_DOWN) shr 1 172 | 173 | db (SF_B2_UP) shr 1 174 | db (SF_B1_DOWN+SF_B2_UP) shr 1 175 | db 0 shr 1 176 | db (SF_B1_DOWN) shr 1 177 | 178 | db (SF_B2_UP+SF_B1_UP) shr 1 179 | db (SF_B2_UP) shr 1 180 | db (SF_B1_UP) shr 1 181 | db 0 shr 1 182 | 183 | .errnz NUMBER_BUTTONS-2 ;Won't work unless a two button mouse 184 | 185 | page 186 | 187 | ; Function pointers and names for dynamic usage, since we can't externFP USER. 188 | 189 | lpPostMessage dd 0 190 | lpGetFocus dd 0 191 | lpWindowFromPoint dd 0 192 | lpGetCursorPos dd 0 193 | szUser db 'USER',0 194 | szGetFocus db 'GetFocus',0 195 | szWindowFromPoint db 'WindowFromPoint',0 196 | szGetCursorPos db 'GetCursorPos',0 197 | szSection db 'VMwareMouse', 0 198 | szWheelEnabled db 'EnableWheel', 0 199 | szSYSTEMINI db 'SYSTEM.INI', 0 200 | 201 | sEnd Data 202 | 203 | 204 | sBegin Code 205 | assumes cs,Code 206 | page 207 | 208 | ;--------------------------Interrupt-Routine----------------------------; 209 | ; ps2_int - Mouse Interrupt Handler for the PS/2 Bus Mouse 210 | ; 211 | ; This is the handler for the interrupt generated by the PS/2 212 | ; mouse. It will reside in the Data segment. 213 | ; 214 | ; Entry: 215 | ; DS = Data 216 | ; Returns: 217 | ; AX = status 218 | ; BX = delta X 219 | ; CX = delta Y 220 | ; Error Returns: 221 | ; None 222 | ; Registers Preserved: 223 | ; SI,DS,ES,BP 224 | ; Registers Destroyed: 225 | ; AX,BX,CX,DX,DI,FLAGS 226 | ; Calls: 227 | ; None 228 | ; History: 229 | ; Fri 21-Aug-1987 11:43:42 -by- Walt Moore [waltm] & Mr. Mouse 230 | ; Initial version 231 | ;-----------------------------------------------------------------------; 232 | 233 | ;------------------------------Pseudo-Code------------------------------; 234 | ; { 235 | ; } 236 | ;-----------------------------------------------------------------------; 237 | 238 | assumes cs,Code 239 | assumes ds,nothing 240 | assumes es,nothing 241 | assumes ss,nothing 242 | 243 | public ps2_int ;Public for debugging 244 | ps2_int proc far 245 | 246 | ; The interrupt handler only has CS set. We need to restore DS. 247 | push ds 248 | push seg bios_proc 249 | pop ds 250 | assumes ds,Data 251 | pushf ;PS/2 mouse -- get data & issue EOI 252 | call bios_proc ; using the BIOS routines 253 | test PS2_DATA_FLAG,0FFh 254 | jz ps2_int_exit ;Not a valid PS/2 mouse interrupt 255 | 256 | push eax ;Save the world 257 | push ebx 258 | push ecx 259 | push edx 260 | push esi 261 | push edi 262 | push ebp 263 | push ds 264 | push es 265 | mov ax,_DATA 266 | mov ds,ax 267 | assumes ds,Data 268 | assumes cs,Code 269 | 270 | ; (old handling code removed to save space for VMware handler) 271 | 272 | ; VMware absolute status 273 | ; It seems we'll need to use the full 32-bit register... 274 | xor ebx, ebx 275 | mov ecx, CMD_ABSPOINTER_STATUS 276 | call Backdoor 277 | ; We need at least four bytes of data. 278 | cmp ax, 4 279 | jl ps2_no_data 280 | ; VMware absolute data 281 | mov ebx, 4 282 | mov ecx, CMD_ABSPOINTER_DATA 283 | call Backdoor 284 | ; VMware will return the following in E[ABCD]X 285 | ; EAX = flags, buttons (10h right 20h left 8h middle) 286 | ; EBX = x (0 - FFFFh scaled) 287 | ; ECX = y (ditto) 288 | ; EDX = z (scroll wheel as 8-bit signed) 289 | ; Windows wants: 290 | ; AX = flags (absolute, button transitions) 291 | ; BX = x (0 - FFFFh scaled, we caught a break) 292 | ; CX = y (ditto) 293 | ; DX = number of buttons 294 | push edx 295 | ; Translate the button state. 296 | mov dx, ax 297 | xor ax, ax 298 | test dx, VMWARE_LEFT 299 | jz not_left_click 300 | or ax, 1h 301 | not_left_click: 302 | test dx, VMWARE_RIGHT 303 | jz not_right_click 304 | or ax, 2h 305 | not_right_click: 306 | ; Blit the previous state as PPxx 307 | mov dx, prev_state 308 | shl dx, 2 309 | or ax, dx 310 | ; Save current state for the next time 311 | mov dx, ax 312 | and dx, 3 ; mask out all bit two lowest 313 | mov prev_state, dx 314 | ; XXX: Middle clicks? 315 | push bx ; save X pos because we need to do an indexed load 316 | mov bx, DataOFFSET state_xlate ; does indirect ref otherwise 317 | mov di, ax 318 | mov al, [bx + di] 319 | shl ax, 1 ; XXX: Why is it shifted in state_xlate? 320 | pop bx ; restore X pos 321 | ; end button code 322 | ; Only set SF_MOVEMENT if there was a difference 323 | xor dx, dx ; Use DX as scratch again 324 | cmp prev_x, bx 325 | jne not_same_x 326 | inc dx 327 | not_same_x: 328 | cmp prev_y, cx 329 | jne not_same_y 330 | inc dx 331 | not_same_y: 332 | cmp dx, 2 333 | je set_deltas 334 | or ax, SF_MOVEMENT 335 | set_deltas: 336 | mov prev_x, bx 337 | mov prev_y, cx 338 | or ax, SF_ABSOLUTE 339 | ; XXX: Can we add the middle button/wheel? 340 | mov dx, NUMBER_BUTTONS 341 | ; ESI/EDI are used by Pen Windows, so IDK. Already zeroed. 342 | xor si,si 343 | xor di,di 344 | sti 345 | call event_proc 346 | ; Call the wheel (restores state) 347 | pop edx 348 | ; but skip if unneeded 349 | cmp wheel_enabled, 0 350 | jz ps2_no_data 351 | cmp dx, 0 352 | jz ps2_no_data 353 | push dx 354 | cCall vmware_handle_wheel 355 | 356 | ps2_no_data: 357 | pop es 358 | pop ds 359 | pop ebp 360 | pop edi 361 | pop esi 362 | pop edx 363 | pop ecx 364 | pop ebx 365 | pop eax 366 | 367 | ps2_int_exit: 368 | pop ds 369 | iret 370 | 371 | ps2_int endp 372 | page 373 | 374 | ;--------------------------Interrupt-Routine----------------------------; 375 | ; ps2_soft_int - Mouse Interrupt Handler for the PS/2 Mouse 376 | ; 377 | ; This is the back end interrupt handler for the PS/2. This is the 378 | ; routine that the BIOS will call when it finally passes the mouse 379 | ; event on to the installed handler. 380 | ; 381 | ; This routine just stores the passed data and sets a flag for the 382 | ; front end indicating that there is mouse data available. This 383 | ; is required since the BIOS handler will not issue reenable mouse 384 | ; interrupts until this routine returns, which would allow interrupts 385 | ; to be missed. 386 | ; 387 | ; Entry: 388 | ; byte ptr ss:[sp][0Ch] = status 389 | ; byte ptr ss:[sp][0Ah] = delta X 390 | ; byte ptr ss:[sp][08h] = delta Y 391 | ; Returns: 392 | ; None 393 | ; Error Returns: 394 | ; None 395 | ; Registers Preserved: 396 | ; All 397 | ; Registers Destroyed: 398 | ; None 399 | ; Calls: 400 | ; None 401 | ; History: 402 | ; Fri 21-Aug-1987 11:43:42 -by- Walt Moore [waltm] & Mr. Mouse 403 | ; Initial version 404 | ;-----------------------------------------------------------------------; 405 | 406 | ;------------------------------Pseudo-Code------------------------------; 407 | ; { 408 | ; } 409 | ;-----------------------------------------------------------------------; 410 | 411 | ps2_soft_int proc far 412 | 413 | ; Great care was taken to not have any labels in the following 414 | ; code to prevent the stupid assembler from complaining (yes, 415 | ; we have to deal with MASM ourselves). 416 | 417 | assumes cs,Code 418 | assumes ds,Data 419 | assumes es,nothing 420 | assumes ss,nothing 421 | 422 | status equ byte ptr [bp+0ch] 423 | delta_x equ byte ptr [bp+0ah] 424 | delta_y equ byte ptr [bp+08h] 425 | 426 | push bp 427 | mov bp,sp 428 | push ax 429 | push ds 430 | mov ax,_DATA 431 | mov ds,ax 432 | ; Don't check the actual delta, since it's invalid. Or the buttons. 433 | ; We can recalculate in the proper interrupt handler. 434 | mov PS2_DATA_FLAG,0FFh 435 | pop ds 436 | pop ax 437 | pop bp 438 | ret ;Will restore the flags for us 439 | 440 | ps2_soft_int endp 441 | 442 | page 443 | 444 | ;---------------------------Public-Routine------------------------------; 445 | ; ps2_search - Search for active PS/2 mouse port 446 | ; 447 | ; A search will be made for a mouse attached to a PS/2 via the 448 | ; keyboard/mouse port. 449 | ; 450 | ; Entry: 451 | ; None 452 | ; Returns: 453 | ; 'C' set if found 454 | ; AX = address of interrupt routine if interrupt vector found 455 | ; SI = offset within the Code segment of the handler 456 | ; Error Returns: 457 | ; 'C' clear if not found 458 | ; Registers Preserved: 459 | ; DS,BP 460 | ; Registers Destroyed: 461 | ; AX,BX,DX,DI,SI,ES,FLAGS 462 | ; Calls: 463 | ; int 15h 464 | ; int 21h 465 | ; int 11h 466 | ; History: 467 | ; Fri 21-Aug-1987 11:43:42 -by- Walt Moore [waltm] & Mr. Mouse 468 | ; Initial version 469 | ;-----------------------------------------------------------------------; 470 | 471 | ;------------------------------Pseudo-Code------------------------------; 472 | ; { 473 | ; } 474 | ;-----------------------------------------------------------------------; 475 | 476 | assumes cs,Code 477 | assumes ds,Data 478 | 479 | public ps2_search 480 | ps2_search proc near 481 | 482 | ; Check for the VMware backdoor. 483 | xor ebx, ebx 484 | mov ecx, CMD_GETVERSION 485 | call Backdoor 486 | cmp eax, 0FFFFFFFFh ; -1 is failure 487 | je ps2_cant_use_it 488 | cmp ebx, VMWARE_MAGIC ; EBX will be the magic, even on QEMU 489 | jne ps2_cant_use_it 490 | ; Under hypervisors, always assume the 286/386 PS/2 mouse vector 491 | mov vector, 074h 492 | stc ;Show mouse was found 493 | ret 494 | 495 | ps2_cant_use_it: 496 | mov vector,-1 ;Restore to "no mouse" value 497 | 498 | ps2_machine_not_found: 499 | clc ;'C' clear shows not found 500 | ret 501 | 502 | ps2_search endp 503 | page 504 | 505 | ;---------------------------Private-Routine-----------------------------; 506 | ; ps2_enable - Enable PS/2 Mouse 507 | ; 508 | ; The PS/2 mouse will be initialized and the interrupt vector hooked. 509 | ; 510 | ; Entry: 511 | ; None 512 | ; Returns: 513 | ; None 514 | ; Error Returns: 515 | ; None 516 | ; Registers Preserved: 517 | ; DS,BP 518 | ; Registers Destroyed: 519 | ; AX,BX,CX,DX,SI,DI,ES ; nothing to preserve 817 | parmW wheel_dir 818 | localV cursor_point, 4 ; two ints for POINT? 819 | cBegin 820 | ; We need the addresses of some functions: 821 | ; - to get the current focus (vestigal right now) 822 | ; - to get the current cursor pos 823 | ; - to get the window under the cursor 824 | ; - we need to be able to post messages 825 | cmp word ptr lpGetFocus[2], 0 ;Q: ptr to proc valid? 826 | jne short gf_done ; Y: we can call it 827 | push ds ; N: get module handle of USER 828 | lea ax, szUser 829 | push ax 830 | cCall GetModuleHandle 831 | 832 | push ax ; module handle 833 | push ds ; i don't know the ordinal 834 | lea ax, szGetFocus 835 | push ax 836 | cCall GetProcAddress 837 | mov word ptr lpGetFocus[0], ax ; save received proc address 838 | mov word ptr lpGetFocus[2], dx 839 | gf_done: 840 | cmp word ptr lpGetCursorPos[2], 0 ;Q: ptr to proc valid? 841 | jne short gcp_done ; Y: we can call it 842 | push ds ; N: get module handle of USER 843 | lea ax, szUser 844 | push ax 845 | cCall GetModuleHandle 846 | 847 | push ax ; module handle 848 | push ds ; i don't know the ordinal 849 | lea ax, szGetCursorPos 850 | push ax 851 | cCall GetProcAddress 852 | mov word ptr lpGetCursorPos[0], ax ; save received proc address 853 | mov word ptr lpGetCursorPos[2], dx 854 | gcp_done: 855 | cmp word ptr lpWindowFromPoint[2], 0 ;Q: ptr to proc valid? 856 | jne short wfp_done ; Y: we can call it 857 | push ds ; N: get module handle of USER 858 | lea ax, szUser 859 | push ax 860 | cCall GetModuleHandle 861 | 862 | push ax ; module handle 863 | push ds ; i don't know the ordinal 864 | lea ax, szWindowFromPoint 865 | push ax 866 | cCall GetProcAddress 867 | mov word ptr lpWindowFromPoint[0], ax ; save received proc address 868 | mov word ptr lpWindowFromPoint[2], dx 869 | wfp_done: 870 | cmp word ptr lpPostMessage[2], 0 ;Q: gotten addr of PostMessage yet? 871 | jne short pm_done ; Y: 872 | push ds ; N: get module handle of USER 873 | lea ax, szUser 874 | push ax 875 | cCall GetModuleHandle 876 | 877 | push ax ; module handle 878 | mov ax, POSTMESSAGE 879 | cwd 880 | push dx 881 | push ax 882 | cCall GetProcAddress 883 | mov word ptr lpPostMessage[0], ax ; save received proc address 884 | mov word ptr lpPostMessage[2], dx 885 | pm_done: 886 | ; * GetCursorPos * 887 | push ss 888 | lea ax, cursor_point 889 | push ax 890 | cCall lpGetCursorPos 891 | ; * WindowFromPoint * 892 | ; this guy takes the args on stack, load like this for right way up 893 | mov ax, word ptr cursor_point[2] 894 | push ax 895 | mov ax, word ptr cursor_point[0] 896 | push ax 897 | cCall lpWindowFromPoint 898 | ; * PostMessage * 899 | ; HWND 900 | ;mov ax, 0FFFFh ; HWND_BROADCAST 901 | ; ax is saved from last call 902 | push ax 903 | ; Message (WM_VSCROLL) 904 | mov ax, 115h 905 | push ax 906 | ; wParam 907 | cmp wheel_dir, 0FFh 908 | jne other_way 909 | mov ax, 0 910 | jmp this_way 911 | ; for lines: up 0, down 1 912 | other_way: 913 | mov ax, 1 914 | this_way: 915 | push ax 916 | ; lParam (high word) 917 | mov ax, 0 918 | push ax 919 | ; lParam (low word) 920 | mov ax, 0 921 | push ax 922 | cCall lpPostMessage 923 | fin: 924 | ; ret 925 | cEnd 926 | page 927 | 928 | ;----------------------------------------------------------------------------; 929 | 930 | ; VMware hypercall 931 | ; Takes EBX and ECX as arguments. ESI and EDI are not used in this variant. 932 | ; Clobbers EAX and EDX in input, can return in all four registers. 933 | Backdoor proc near 934 | 935 | mov eax, VMWARE_MAGIC 936 | mov dx, VMWARE_PORT 937 | in eax, dx 938 | ret 939 | 940 | Backdoor endp 941 | 942 | ;----------------------------------------------------------------------------; 943 | sEnd Code 944 | end 945 | --------------------------------------------------------------------------------