ReactOS  0.4.13-dev-544-gede3fdd
moubios32.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: GPL - See COPYING in the top level directory
3  * PROJECT: ReactOS Virtual DOS Machine
4  * FILE: subsystems/mvdm/ntvdm/bios/bios32/moubios32.c
5  * PURPOSE: VDM 32-bit PS/2 Mouse BIOS
6  * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7  * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8  *
9  * NOTE: Based from VirtualBox OSE ROM BIOS, and SeaBIOS.
10  */
11 
12 /* INCLUDES *******************************************************************/
13 
14 #include "ntvdm.h"
15 
16 #define NDEBUG
17 #include <debug.h>
18 
19 #include "emulator.h"
20 #include "cpu/cpu.h" // for EMULATOR_FLAG_CF
21 
22 #include "moubios32.h"
23 #include "bios32p.h"
24 
25 #include "io.h"
26 #include "hardware/mouse.h"
27 #include "hardware/ps2.h"
28 
29 /* PRIVATE VARIABLES **********************************************************/
30 
31 #define MOUSE_IRQ_INT 0x74
32 
35 
36 /*
37  * Far pointer to a device handler. In compatible PS/2, it is stored in the EBDA.
38  *
39  * See Ralf Brown: http://www.ctyme.com/intr/rb-1603.htm
40  * for more information. In particular:
41  * when the subroutine is called, it is given 4 WORD values on the stack;
42  * the handler should return with a FAR return without popping the stack.
43  */
44 static ULONG DeviceHandler = 0;
45 
46 /* PRIVATE FUNCTIONS **********************************************************/
47 
49 {
51 
52  /* Clear the mouse queue */
53  while (PS2PortQueueRead(1)) ; // NOTE: Should be a IOReadB! But see r67231
54 
55  /* Disable mouse interrupt and events */
58  ControllerConfig &= ~0x02; // Turn off IRQ12
59  ControllerConfig |= 0x20; // Disable mouse clock line
62 }
63 
65 {
67 
68  /* Clear the mouse queue */
69  while (PS2PortQueueRead(1)) ; // NOTE: Should be a IOReadB! But see r67231
70 
71  /* Enable mouse interrupt and events */
74  ControllerConfig |= 0x02; // Turn on IRQ12
75  ControllerConfig &= ~0x20; // Enable mouse clock line
78 }
79 
80 static inline
82 {
83  /* Clear the mouse queue */
84  while (PS2PortQueueRead(1)) ; // NOTE: Should be a IOReadB! But see r67231
85 
86  /* Send the command */
89 }
90 
91 static inline
93 {
94  PS2PortQueueRead(1); // NOTE: Should be a IOReadB! But see r67231
95  return IOReadB(PS2_DATA_PORT);
96 }
97 
98 
99 static
101 {
102  if (MouseEnabled) return;
103 
104  MouseEnabled = TRUE;
105 
106  /* Get the old IRQ handler */
108 
109  /* Set the IRQ handler */
110  //RegisterInt32(MAKELONG(FIELD_OFFSET(MOUSE_DRIVER, MouseIrqInt16Stub), MouseDataSegment),
111  // MOUSE_IRQ_INT, DosMouseIrq, NULL);
112 }
113 
114 static
116 {
117  if (!MouseEnabled) return;
118 
119  /* Restore the old IRQ handler */
120  // ((PDWORD)BaseAddress)[MOUSE_IRQ_INT] = OldIrqHandler;
121 
123 }
124 
125 
126 // Mouse IRQ 12
128 {
129  DPRINT1("PS/2 Mouse IRQ! DeviceHandler = 0x%04X:0x%04X\n",
131 
132  if (DeviceHandler != 0)
133  {
134  /*
135  * Prepare the stack for the mouse device handler:
136  * push Status, X and Y data, and a zero word.
137  */
138  setSP(getSP() - sizeof(WORD));
139  *((LPWORD)SEG_OFF_TO_PTR(getSS(), getSP())) = 0; // Status
140  setSP(getSP() - sizeof(WORD));
141  *((LPWORD)SEG_OFF_TO_PTR(getSS(), getSP())) = 0; // X data (high byte = 0)
142  setSP(getSP() - sizeof(WORD));
143  *((LPWORD)SEG_OFF_TO_PTR(getSS(), getSP())) = 0; // Y data (high byte = 0)
144  setSP(getSP() - sizeof(WORD));
145  *((LPWORD)SEG_OFF_TO_PTR(getSS(), getSP())) = 0; // Zero
146 
147  /* Call the device handler */
149 
150  /* Pop the stack */
151  setSP(getSP() + 4*sizeof(WORD));
152  }
153 
155 }
156 
158 {
159  /* Disable mouse interrupt and events */
160  DisableMouseInt();
161 
162  switch (getAL())
163  {
164  /* Enable / Disable */
165  case 0x00:
166  {
167  UCHAR State = getBH();
168 
169  if (State > 2)
170  {
171  /* Invalid function */
172  setAH(0x01);
173  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
174  break;
175  }
176 
177  if (State == 0x00)
178  {
180 
181  /* Disable packet reporting */
182  SendMouseCommand(0xF5);
183  }
184  else // if (State == 0x01)
185  {
186  /* Check for the presence of the device handler */
187  if (DeviceHandler == 0)
188  {
189  /* No device handler installed */
190  setAH(0x05);
191  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
192  break;
193  }
194 
195  BiosMouseEnable();
196 
197  /* Enable packet reporting */
198  SendMouseCommand(0xF4);
199  }
200 
201  if (ReadMouseData() != MOUSE_ACK)
202  {
203  /* Failure */
204  setAH(0x03);
205  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
206  break;
207  }
208 
209  /* Success */
210  setAH(0x00);
211  Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
212  break;
213  }
214 
215  /* Initialize */
216  case 0x05:
217  {
218  // Fall through
219  }
220 
221  /* Reset */
222  case 0x01:
223  {
224  UCHAR Answer;
225 
226  SendMouseCommand(0xFF);
227  Answer = ReadMouseData();
228  /* A "Resend" signal (0xFE) is sent if no mouse is attached */
229  if (Answer == 0xFE)
230  {
231  /* Resend */
232  setAH(0x04);
233  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
234  break;
235  }
236  else if (Answer != MOUSE_ACK)
237  {
238  /* Failure */
239  setAH(0x03);
240  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
241  break;
242  }
243 
244  setBL(ReadMouseData()); // Should be MOUSE_BAT_SUCCESS
245  setBH(ReadMouseData()); // Mouse ID
246 
247  /* Success */
248  setAH(0x00);
249  Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
250  break;
251  }
252 
253  /* Set Sampling Rate */
254  case 0x02:
255  {
256  UCHAR SampleRate = 0;
257 
258  switch (getBH())
259  {
260  case 0x00: SampleRate = 10; break; // 10 reports/sec
261  case 0x01: SampleRate = 20; break; // 20 " "
262  case 0x02: SampleRate = 40; break; // 40 " "
263  case 0x03: SampleRate = 60; break; // 60 " "
264  case 0x04: SampleRate = 80; break; // 80 " "
265  case 0x05: SampleRate = 100; break; // 100 " "
266  case 0x06: SampleRate = 200; break; // 200 " "
267  default: SampleRate = 0;
268  }
269 
270  if (SampleRate == 0)
271  {
272  /* Invalid input */
273  setAH(0x02);
274  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
275  break;
276  }
277 
278  SendMouseCommand(0xF3);
279  if (ReadMouseData() != MOUSE_ACK)
280  {
281  /* Failure */
282  setAH(0x03);
283  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
284  break;
285  }
286 
287  SendMouseCommand(SampleRate);
288  if (ReadMouseData() != MOUSE_ACK)
289  {
290  /* Failure */
291  setAH(0x03);
292  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
293  break;
294  }
295 
296  /* Success */
297  setAH(0x00);
298  Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
299  break;
300  }
301 
302  /* Set Resolution */
303  case 0x03:
304  {
305  UCHAR Resolution = getBH();
306 
307  /*
308  * 0: 25 dpi, 1 count per millimeter
309  * 1: 50 dpi, 2 counts per millimeter
310  * 2: 100 dpi, 4 counts per millimeter
311  * 3: 200 dpi, 8 counts per millimeter
312  */
313  if (Resolution > 3)
314  {
315  /* Invalid input */
316  setAH(0x02);
317  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
318  break;
319  }
320 
321  SendMouseCommand(0xE8);
322  if (ReadMouseData() != MOUSE_ACK)
323  {
324  /* Failure */
325  setAH(0x03);
326  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
327  break;
328  }
329 
331  if (ReadMouseData() != MOUSE_ACK)
332  {
333  /* Failure */
334  setAH(0x03);
335  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
336  break;
337  }
338 
339  /* Success */
340  setAH(0x00);
341  Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
342  break;
343  }
344 
345  /* Get Type */
346  case 0x04:
347  {
348  SendMouseCommand(0xF2);
349  if (ReadMouseData() != MOUSE_ACK)
350  {
351  /* Failure */
352  setAH(0x03);
353  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
354  break;
355  }
356 
357  setBH(ReadMouseData());
358 
359  /* Success */
360  setAH(0x00);
361  Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
362  break;
363  }
364 
365  /* Extended Commands (Return Status and Set Scaling Factor) */
366  case 0x06:
367  {
368  UCHAR Command = getBH();
369 
370  switch (Command)
371  {
372  /* Return Status */
373  case 0x00:
374  {
375  SendMouseCommand(0xE9);
376  if (ReadMouseData() != MOUSE_ACK)
377  {
378  /* Failure */
379  setAH(0x03);
380  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
381  break;
382  }
383 
384  setBL(ReadMouseData()); // Status
385  setCL(ReadMouseData()); // Resolution
386  setDL(ReadMouseData()); // Sample rate
387 
388  /* Success */
389  setAH(0x00);
390  Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
391  break;
392  }
393 
394  /* Set Scaling Factor to 1:1 */
395  case 0x01:
396  /* Set Scaling Factor to 2:1 */
397  case 0x02:
398  {
399  SendMouseCommand(Command == 0x01 ? 0xE6 : 0xE7);
400  if (ReadMouseData() != MOUSE_ACK)
401  {
402  /* Failure */
403  setAH(0x03);
404  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
405  break;
406  }
407 
408  /* Success */
409  setAH(0x00);
410  Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
411  break;
412  }
413 
414  default:
415  {
416  /* Invalid function */
417  setAH(0x01);
418  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
419  break;
420  }
421  }
422 
423  break;
424  }
425 
426  /* Set Device Handler Address */
427  case 0x07:
428  {
429  /* ES:BX == 0000h:0000h removes the device handler */
431 
432  /* Success */
433  setAH(0x00);
434  Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
435  break;
436  }
437 
438  /* Write to Pointer Port */
439  case 0x08:
440  {
442  if (ReadMouseData() != MOUSE_ACK)
443  {
444  /* Failure */
445  setAH(0x03);
446  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
447  break;
448  }
449 
450  /* Success */
451  setAH(0x00);
452  Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
453  break;
454  }
455 
456  /* Read from Pointer Port */
457  case 0x09:
458  {
459  setBL(ReadMouseData());
460  setCL(ReadMouseData());
461  setDL(ReadMouseData());
462 
463  /* Success */
464  setAH(0x00);
465  Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
466  break;
467  }
468 
469  default:
470  {
471  DPRINT1("INT 15h, AH = C2h, AL = %02Xh NOT IMPLEMENTED\n",
472  getAL());
473 
474  /* Unknown function */
475  setAH(0x01);
476  Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
477  }
478  }
479 
480  /* Reenable mouse interrupt and events */
481  EnableMouseInt();
482 }
483 
484 /* PUBLIC FUNCTIONS ***********************************************************/
485 
487 {
488  UCHAR Answer;
489 
490  /* Initialize PS/2 mouse port */
491  // Enable the port
492  IOWriteB(PS2_CONTROL_PORT, 0xA8);
493 
494  /* Detect mouse presence by attempting a reset */
495  SendMouseCommand(0xFF);
496  Answer = ReadMouseData();
497  /* A "Resend" signal (0xFE) is sent if no mouse is attached */
498  if (Answer == 0xFE)
499  {
500  DPRINT1("No mouse present!\n");
501  }
502  else if (Answer != MOUSE_ACK)
503  {
504  DPRINT1("Mouse reset failure!\n");
505  }
506  else
507  {
508  /* Mouse present, try to completely enable it */
509 
510  // FIXME: The following is temporary until
511  // this is moved into the mouse driver!!
512 
513  /* Enable packet reporting */
514  SendMouseCommand(0xF4);
515  if (ReadMouseData() != MOUSE_ACK)
516  {
517  DPRINT1("Failed to enable mouse!\n");
518  }
519  else
520  {
521  /* Enable mouse interrupt and events */
522  EnableMouseInt();
523  }
524  }
525 
526  /* No mouse driver available so far */
527  RegisterBiosInt32(0x33, NULL);
528 
529  /* Set up the HW vector interrupts */
531 }
532 
534 {
535  return TRUE;
536 }
537 
539 {
540 }
static UCHAR ReadMouseData(VOID)
Definition: moubios32.c:92
#define STACK_INT_NUM
Definition: int32.h:30
#define PS2_DATA_PORT
Definition: ps2.h:16
VOID BiosMousePs2Interface(LPWORD Stack)
Definition: moubios32.c:157
USHORT WINAPI getBX(VOID)
Definition: registers.c:170
#define TRUE
Definition: types.h:120
VOID WINAPI setBL(UCHAR)
Definition: registers.c:205
#define LOBYTE(W)
Definition: jmemdos.c:487
VOID WINAPI setAH(UCHAR)
Definition: registers.c:135
static VOID BiosMouseDisable(VOID)
Definition: moubios32.c:115
USHORT WINAPI getSS(VOID)
Definition: registers.c:494
UCHAR WINAPI getAL(VOID)
Definition: registers.c:142
Definition: shell.h:41
#define MOUSE_IRQ_INT
Definition: moubios32.c:31
#define ControllerConfig
Definition: ps2.c:55
static VOID SendMouseCommand(UCHAR Command)
Definition: moubios32.c:81
#define SEG_OFF_TO_PTR(seg, off)
Definition: emulator.h:28
static VOID BiosMouseEnable(VOID)
Definition: moubios32.c:100
#define RegisterBiosInt32(IntNumber, IntHandler)
Definition: bios32p.h:34
#define EMULATOR_FLAG_CF
Definition: cpu.h:19
VOID WINAPI setSP(USHORT)
Definition: registers.c:351
static VOID WINAPI BiosMouseIrq(LPWORD Stack)
Definition: moubios32.c:127
UCHAR IOReadB(USHORT Port)
Definition: io.c:64
#define MAKELONG(a, b)
Definition: typedefs.h:248
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define STACK_FLAGS
Definition: int32.h:35
VOID IOWriteB(USHORT Port, UCHAR Buffer)
Definition: io.c:111
static BOOLEAN MouseEnabled
Definition: moubios32.c:33
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
VOID EnableHwIRQ(UCHAR hwirq, EMULATOR_INT32_PROC func)
Definition: bios32.c:798
BOOLEAN PS2PortQueueRead(BYTE PS2Port)
Definition: ps2.c:415
USHORT WINAPI getES(VOID)
Definition: registers.c:522
VOID PicIRQComplete(BYTE IntNum)
Definition: bios32.c:812
CALLBACK16 BiosContext
Definition: bios32.c:45
#define WINAPI
Definition: msvc.h:8
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned long DWORD
Definition: ntddk_ex.h:95
static VOID EnableMouseInt(VOID)
Definition: moubios32.c:64
UCHAR WINAPI getBH(VOID)
Definition: registers.c:184
VOID MouseBios32Cleanup(VOID)
Definition: moubios32.c:538
unsigned char UCHAR
Definition: xmlstorage.h:181
#define PS2_CONTROL_PORT
Definition: ps2.h:17
#define MOUSE_ACK
Definition: i8042prt.h:285
unsigned char BYTE
Definition: mem.h:68
VOID WINAPI setBH(UCHAR)
Definition: registers.c:191
uint16_t * LPWORD
Definition: typedefs.h:54
UCHAR WINAPI getBL(VOID)
Definition: registers.c:198
VOID WINAPI setDL(UCHAR)
Definition: registers.c:321
DWORD * PDWORD
Definition: pedump.c:68
static DWORD OldIrqHandler
Definition: moubios32.c:34
VOID MouseBios32Post(VOID)
Definition: moubios32.c:486
#define DPRINT1
Definition: precomp.h:8
VOID RunCallback16(IN PCALLBACK16 Context, IN ULONG FarPtr)
Definition: callback.c:93
static ULONG DeviceHandler
Definition: moubios32.c:44
static BYTE Resolution
Definition: mouse.c:35
#define HIWORD(l)
Definition: typedefs.h:246
unsigned int ULONG
Definition: retypes.h:1
static VOID DisableMouseInt(VOID)
Definition: moubios32.c:48
USHORT WINAPI getSP(VOID)
Definition: registers.c:344
BOOLEAN MouseBiosInitialize(VOID)
Definition: moubios32.c:533
VOID WINAPI setCL(UCHAR)
Definition: registers.c:263
#define LOWORD(l)
Definition: pedump.c:82