Patch by Jonathon Wilson:
[reactos.git] / reactos / drivers / input / psaux / mouse.c
1 /*
2 ** PS/2 Mouse Driver
3 ** Written by Thomas Weidenmueller (w3seek@users.sourceforge.net)
4 ** For ReactOS (www.reactos.com)
5 ** Adapted from the linux 2.6 mouse driver
6 */
7
8 #include <ddk/ntddk.h>
9 #include <ddk/ntddmou.h>
10 #include "controller.h"
11 #include "mouse.h"
12 #include "psaux.h"
13 #include <debug.h>
14
15
16 int InitSynaptics(PDEVICE_EXTENSION DeviceExtension);
17 void PS2PPProcessPacket(PDEVICE_EXTENSION DeviceExtension, PMOUSE_INPUT_DATA Input, int *wheel);
18 void PS2PPSet800dpi(PDEVICE_EXTENSION DeviceExtension);
19 int PS2PPDetectModel(PDEVICE_EXTENSION DeviceExtension, unsigned char *param);
20
21 // Parse incoming packets
22 BOOLEAN FASTCALL
23 ParsePackets(PDEVICE_EXTENSION DeviceExtension, PMOUSE_INPUT_DATA Input)
24 {
25 ULONG ButtonsDiff;
26 int wheel = 0;
27 unsigned char *packet = DeviceExtension->MouseBuffer;
28
29 /* Determine the current state of the buttons */
30 Input->RawButtons = ((packet[0] & 1) ? GPM_B_LEFT : 0);
31 Input->RawButtons |= (((packet[0] >> 1) & 1) ? GPM_B_RIGHT : 0);
32 Input->RawButtons |= (((packet[0] >> 2) & 1) ? GPM_B_MIDDLE : 0);
33
34 /*
35 * The PS2++ protocol is a little bit complex
36 */
37
38 if(DeviceExtension->MouseType == PSMOUSE_PS2PP || DeviceExtension->MouseType == PSMOUSE_PS2TPP)
39 PS2PPProcessPacket(DeviceExtension, Input, &wheel);
40
41 /*
42 * Scroll wheel on IntelliMice, scroll buttons on NetMice
43 */
44
45 if(DeviceExtension->MouseType == PSMOUSE_IMPS || DeviceExtension->MouseType == PSMOUSE_GENPS)
46 {
47 wheel = (int)(-(signed char) packet[3]);
48 }
49
50 /*
51 * Scroll wheel and buttons on IntelliMouse Explorer
52 */
53
54 if(DeviceExtension->MouseType == PSMOUSE_IMEX)
55 {
56 wheel = (int)(packet[3] & 8) - (int)(packet[3] & 7);
57 Input->RawButtons |= (((packet[3] >> 4) & 1) ? GPM_B_FOURTH : 0);
58 Input->RawButtons |= (((packet[3] >> 5) & 1) ? GPM_B_FIFTH : 0);
59 }
60
61 /*
62 * Extra buttons on Genius NewNet 3D
63 */
64
65 if(DeviceExtension->MouseType == PSMOUSE_GENPS)
66 {
67 Input->RawButtons |= (((packet[0] >> 6) & 1) ? GPM_B_FOURTH : 0);
68 Input->RawButtons |= (((packet[0] >> 7) & 1) ? GPM_B_FIFTH : 0);
69 }
70
71 /*
72 * Determine ButtonFlags
73 */
74
75 Input->ButtonFlags = 0;
76 ButtonsDiff = DeviceExtension->PreviousButtons ^ Input->RawButtons;
77
78 /*
79 * Generic PS/2 Mouse
80 */
81
82 if(ButtonsDiff & GPM_B_LEFT)
83 Input->ButtonFlags |= ((Input->RawButtons & GPM_B_LEFT) ? MOUSE_BUTTON_1_DOWN : MOUSE_BUTTON_1_UP);
84
85 if(ButtonsDiff & GPM_B_RIGHT)
86 Input->ButtonFlags |= ((Input->RawButtons & GPM_B_RIGHT) ? MOUSE_BUTTON_2_DOWN : MOUSE_BUTTON_2_UP);
87
88 if(ButtonsDiff & GPM_B_MIDDLE)
89 Input->ButtonFlags |= ((Input->RawButtons & GPM_B_MIDDLE) ? MOUSE_BUTTON_3_DOWN : MOUSE_BUTTON_3_UP);
90
91 if(ButtonsDiff & GPM_B_FOURTH)
92 Input->ButtonFlags |= ((Input->RawButtons & GPM_B_FOURTH) ? MOUSE_BUTTON_4_DOWN : MOUSE_BUTTON_4_UP);
93
94 if(ButtonsDiff & GPM_B_FIFTH)
95 Input->ButtonFlags |= ((Input->RawButtons & GPM_B_FIFTH) ? MOUSE_BUTTON_5_DOWN : MOUSE_BUTTON_5_UP);
96
97 /* Some PS/2 mice send reports with negative bit set in data[0] and zero for
98 * movement. I think this is a bug in the mouse, but working around it only
99 * causes artifacts when the actual report is -256; they'll be treated as zero.
100 * This should be rare if the mouse sampling rate is set to a reasonable value;
101 * the default of 100 Hz is plenty. (Stephen Tell) */
102
103 /* Determine LastX */
104 if(packet[1])
105 Input->LastX = ((packet[0] & 0x10) ? (int)(packet[1] - 256) : (int) packet[1]);
106 else
107 Input->LastX = 0;
108
109 /* Determine LastY */
110 if(packet[2])
111 Input->LastY = -((packet[0] & 0x20) ? (int)(packet[2] - 256) : (int) packet[2]);
112 else
113 Input->LastY = 0;
114
115 /* Copy RawButtons to Previous Buttons for Input */
116 DeviceExtension->PreviousButtons = Input->RawButtons;
117
118 if((wheel != 0) && (wheel >= -8) && (wheel <= 7))
119 {
120 Input->ButtonFlags |= MOUSE_WHEEL;
121 Input->ButtonData = (UINT)(wheel * WHEEL_DELTA);
122 }
123
124 return TRUE;
125 }
126
127 // Handle a mouse event
128 BOOLEAN STDCALL
129 MouseHandler(PKINTERRUPT Interrupt, PVOID ServiceContext)
130 {
131 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
132 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
133 PMOUSE_INPUT_DATA Input;
134 ULONG Queue;
135 BOOLEAN ret;
136 unsigned scancode;
137 unsigned status = controller_read_status();
138 scancode = controller_read_input();
139
140 /* Don't handle the mouse event if we aren't connected to the mouse class driver */
141 if (DeviceExtension->ClassInformation.CallBack == NULL)
142 {
143 return FALSE;
144 }
145
146 if ((status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) != 0)
147 {
148 // mouse_handle_event(scancode); proceed to handle it
149 }
150 else
151 {
152 return FALSE; // keyboard_handle_event(scancode);
153 }
154
155 /* Add this scancode to the mouse event queue. */
156 DeviceExtension->MouseBuffer[DeviceExtension->MouseBufferPosition] = scancode;
157 DeviceExtension->MouseBufferPosition++;
158
159 /* If the buffer is full, parse this event */
160 if (DeviceExtension->MouseBufferPosition == DeviceExtension->MouseBufferSize)
161 {
162 Queue = DeviceExtension->ActiveQueue % 2;
163
164 /* Reset the buffer state. */
165 DeviceExtension->MouseBufferPosition = 0;
166
167 /* Prevent buffer overflow */
168 if (DeviceExtension->InputDataCount[Queue] == MOUSE_BUFFER_SIZE)
169 {
170 return TRUE;
171 }
172
173 Input = &DeviceExtension->MouseInputData[Queue]
174 [DeviceExtension->InputDataCount[Queue]];
175
176 ret = ParsePackets(DeviceExtension, Input);
177
178 /* Send the Input data to the Mouse Class driver */
179 DeviceExtension->InputDataCount[Queue]++;
180 KeInsertQueueDpc(&DeviceExtension->IsrDpc, DeviceObject->CurrentIrp, NULL);
181
182 return ret;
183 }
184 return TRUE;
185 }
186
187
188 // Write a PS/2 mouse command.
189 static void mouse_write_command(int command)
190 {
191 controller_wait();
192 controller_write_command(CONTROLLER_COMMAND_WRITE_MODE);
193 controller_wait();
194 controller_write_output(command);
195 }
196
197
198 // Sends a byte to the mouse
199 static int SendByte(PDEVICE_EXTENSION DeviceExtension, unsigned char byte)
200 {
201 int timeout = 100; /* 100 msec */
202 int scancode;
203 unsigned char status;
204 LARGE_INTEGER Millisecond_Timeout;
205
206 Millisecond_Timeout.QuadPart = 1;
207
208 DeviceExtension->ack = 0;
209 DeviceExtension->acking = 1;
210
211 controller_wait();
212 controller_write_command(CONTROLLER_COMMAND_WRITE_MOUSE);
213 controller_wait();
214 controller_write_output(byte);
215 while ((DeviceExtension->ack == 0) && timeout--)
216 {
217 status = controller_read_status();
218 if((status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
219 {
220 scancode = controller_read_input();
221 if(scancode >= 0)
222 {
223 switch(scancode)
224 {
225 case PSMOUSE_RET_ACK:
226 DeviceExtension->ack = 1;
227 break;
228 case PSMOUSE_RET_NAK:
229 DeviceExtension->ack = -1;
230 break;
231 default:
232 DeviceExtension->ack = 1; /* Workaround for mice which don't ACK the Get ID command */
233 if (DeviceExtension->RepliesExpected)
234 DeviceExtension->pkt[--DeviceExtension->RepliesExpected] = scancode;
235 break;
236 }
237 return (int)(-(DeviceExtension->ack <= 0));
238 }
239 }
240 KeDelayExecutionThread (KernelMode, FALSE, &Millisecond_Timeout);
241 }
242 return (int)(-(DeviceExtension->ack <= 0));
243 }
244
245
246 // Send a PS/2 command to the mouse.
247 int SendCommand(PDEVICE_EXTENSION DeviceExtension, unsigned char *param, int command)
248 {
249 LARGE_INTEGER Millisecond_Timeout;
250 unsigned char status;
251 int scancode;
252 int timeout = 500; /* 500 msec */
253 int send = (command >> 12) & 0xf;
254 int receive = (command >> 8) & 0xf;
255 int i;
256
257 Millisecond_Timeout.QuadPart = 1;
258
259 DeviceExtension->RepliesExpected = receive;
260 if (command == PSMOUSE_CMD_RESET_BAT)
261 timeout = 2000; /* 2 sec */
262
263 if (command & 0xff)
264 if (SendByte(DeviceExtension, command & 0xff))
265 return (int)(DeviceExtension->RepliesExpected = 0) - 1;
266
267 for (i = 0; i < send; i++)
268 if (SendByte(DeviceExtension, param[i]))
269 return (int)(DeviceExtension->RepliesExpected = 0) - 1;
270
271 while (DeviceExtension->RepliesExpected && timeout--)
272 {
273 if (DeviceExtension->RepliesExpected == 1 && command == PSMOUSE_CMD_RESET_BAT)
274 timeout = 100;
275
276 if (DeviceExtension->RepliesExpected == 1 && command == PSMOUSE_CMD_GETID &&
277 DeviceExtension->pkt[1] != 0xab && DeviceExtension->pkt[1] != 0xac)
278 {
279 DeviceExtension->RepliesExpected = 0;
280 break;
281 }
282
283 status = controller_read_status();
284 if((status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
285 {
286 scancode = controller_read_input();
287 if(scancode >= 0)
288 {
289 DeviceExtension->pkt[--DeviceExtension->RepliesExpected] = scancode;
290 }
291 }
292
293 KeDelayExecutionThread (KernelMode, FALSE, &Millisecond_Timeout);
294 }
295
296 for (i = 0; i < receive; i++)
297 param[i] = DeviceExtension->pkt[(receive - 1) - i];
298
299 if (DeviceExtension->RepliesExpected)
300 return (int)(DeviceExtension->RepliesExpected = 0) - 1;
301
302 return 0;
303 }
304
305
306 // changes the resolution of the mouse
307 void SetResolution(PDEVICE_EXTENSION DeviceExtension)
308 {
309 unsigned char param[1];
310
311 if(DeviceExtension->MouseType == PSMOUSE_PS2PP && DeviceExtension->Resolution > 400)
312 {
313 PS2PPSet800dpi(DeviceExtension);
314 return;
315 }
316
317 if(!DeviceExtension->Resolution || DeviceExtension->Resolution >= 200)
318 param[0] = 3;
319 else if(DeviceExtension->Resolution >= 100)
320 param[0] = 2;
321 else if(DeviceExtension->Resolution >= 50)
322 param[0] = 1;
323 else if(DeviceExtension->Resolution )
324 param[0] = 0;
325
326 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETRES);
327 }
328
329
330 // Detect mouse models
331 int TestMouseExtensions(PDEVICE_EXTENSION DeviceExtension)
332 {
333 unsigned char param[4];
334 int type = 0;
335
336 param[0] = 0;
337
338 // vendor = Generic
339 // name = Mouse
340 DeviceExtension->MouseModel = 0;
341
342 /*
343 * Try Synaptics TouchPad magic ID
344 */
345 param[0] = 0;
346 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETRES);
347 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETRES);
348 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETRES);
349 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETRES);
350 SendCommand(DeviceExtension, param, PSMOUSE_CMD_GETINFO);
351 if(param[1] == 0x47)
352 {
353 // vendor = Synaptics
354 // name = TouchPad
355 if(!InitSynaptics(DeviceExtension))
356 return PSMOUSE_SYNAPTICS;
357 else
358 return PSMOUSE_PS2;
359 }
360
361 /*
362 * Try Genius NetMouse magic init.
363 */
364 param[0] = 3;
365 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETRES);
366 SendCommand(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11);
367 SendCommand(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11);
368 SendCommand(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11);
369 SendCommand(DeviceExtension, param, PSMOUSE_CMD_GETINFO);
370 if(param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55)
371 {
372 // vendor = Genius
373 // name = Wheel Mouse
374 // Features = 4th, 5th, Wheel
375 return PSMOUSE_GENPS;
376 }
377
378 /*
379 * Try Logitech magic ID.
380 */
381 param[0] = 0;
382 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETRES);
383 SendCommand(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11);
384 SendCommand(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11);
385 SendCommand(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11);
386 param[1] = 0;
387 SendCommand(DeviceExtension, param, PSMOUSE_CMD_GETINFO);
388 if(param[1])
389 {
390 type = PS2PPDetectModel(DeviceExtension, param);
391 if(type)
392 return type;
393 }
394
395 /*
396 * Try IntelliMouse magic init.
397 */
398 param[0] = 200;
399 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETRATE);
400 param[0] = 100;
401 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETRATE);
402 param[0] = 80;
403 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETRATE);
404 SendCommand(DeviceExtension, param, PSMOUSE_CMD_GETID);
405 if(param[0] == 3)
406 {
407 // Features = Wheel
408
409 /*
410 * Try IntelliMouse/Explorer magic init.
411 */
412 param[0] = 200;
413 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETRATE);
414 param[0] = 200;
415 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETRATE);
416 param[0] = 80;
417 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETRATE);
418 SendCommand(DeviceExtension, param, PSMOUSE_CMD_GETID);
419 if(param[0] == 4)
420 {
421 // name = Explorer Mouse
422 // Features = 4th, 5th, Wheel
423 return PSMOUSE_IMEX;
424 }
425
426 // name = Wheel Mouse
427 return PSMOUSE_IMPS;
428 }
429
430 /*
431 * Okay, all failed, we have a standard mouse here. The number of the buttons
432 * is still a question, though. We assume 3.
433 */
434 return PSMOUSE_PS2;
435 }
436
437
438 // Detect if mouse is just a standard ps/2 mouse
439 int TestMouse(PDEVICE_EXTENSION DeviceExtension)
440 {
441 unsigned char param[4];
442
443 param[0] = param[1] = 0xa5;
444
445 /*
446 * First, we check if it's a mouse. It should send 0x00 or 0x03
447 * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
448 */
449 if(SendCommand(DeviceExtension, param, PSMOUSE_CMD_GETID))
450 return -1;
451
452 if(param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
453 return -1;
454
455 /*
456 * Then we reset and disable the mouse so that it doesn't generate events.
457 */
458
459 if(DeviceExtension->NoExtensions)
460 {
461 return DeviceExtension->MouseType = PSMOUSE_PS2;
462 }
463
464 if(SendCommand(DeviceExtension, NULL, PSMOUSE_CMD_RESET_DIS))
465 return -1;
466
467 return DeviceExtension->MouseType = TestMouseExtensions(DeviceExtension);
468 }
469
470
471 // Initialize and enable the mouse
472 void InitializeMouse(PDEVICE_EXTENSION DeviceExtension)
473 {
474 unsigned char param[4];
475
476 /*
477 * We set the mouse report rate to a highest possible value.
478 * We try 100 first in case mouse fails to set 200.
479 */
480
481 param[0] = 200;
482 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETRATE);
483
484 param[0] = 100;
485 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETRATE);
486
487 SetResolution(DeviceExtension);
488 SendCommand(DeviceExtension, NULL, PSMOUSE_CMD_SETSCALE11);
489
490 /*
491 * We set the mouse into streaming mode.
492 */
493
494 SendCommand(DeviceExtension, param, PSMOUSE_CMD_SETSTREAM);
495
496 /*
497 * Last, we enable the mouse so that we get reports from it.
498 */
499
500 if(SendCommand(DeviceExtension, NULL, PSMOUSE_CMD_ENABLE))
501 DbgPrint("mouse.c: Failed to enable mouse!\n");
502 }
503
504
505 // Load settings from registry (by Filip Navara)
506 BOOL LoadMouseSettings(PDEVICE_EXTENSION DeviceExtension, PUNICODE_STRING RegistryPath)
507 {
508 /*
509 * Get the parameters from registry
510 */
511 ULONG DefaultMouseResolution = 0;
512 ULONG DisableExtensionDetection = 1;
513 UNICODE_STRING ParametersPath;
514 RTL_QUERY_REGISTRY_TABLE Parameters[3];
515 PWSTR ParametersKeyPath = L"\\Parameters";
516 NTSTATUS Status;
517
518 RtlZeroMemory(Parameters, sizeof(Parameters));
519
520 /*
521 * Formulate path to registry
522 */
523 RtlInitUnicodeString(&ParametersPath, NULL);
524 ParametersPath.MaximumLength = RegistryPath->Length +
525 (wcslen(ParametersKeyPath) * sizeof(WCHAR)) + sizeof(UNICODE_NULL);
526 ParametersPath.Buffer = ExAllocatePool(PagedPool,
527 ParametersPath.MaximumLength);
528 if (!ParametersPath.Buffer)
529 {
530 DPRINT("Can't allocate buffer for parameters\n");
531 return FALSE;
532 }
533 RtlZeroMemory(ParametersPath.Buffer, ParametersPath.MaximumLength);
534 RtlAppendUnicodeToString(&ParametersPath, RegistryPath->Buffer);
535 RtlAppendUnicodeToString(&ParametersPath, ParametersKeyPath);
536 DPRINT("Parameters Path: %wZ\n", &ParametersPath);
537
538 Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
539 Parameters[0].Name = L"Resolution";
540 Parameters[0].EntryContext = &DeviceExtension->Resolution;
541 Parameters[0].DefaultType = REG_DWORD;
542 Parameters[0].DefaultData = &DefaultMouseResolution;
543 Parameters[0].DefaultLength = sizeof(ULONG);
544
545 Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
546 Parameters[1].Name = L"DisableExtensionDetection";
547 Parameters[1].EntryContext = &DeviceExtension->NoExtensions;
548 Parameters[1].DefaultType = REG_DWORD;
549 Parameters[1].DefaultData = &DisableExtensionDetection;
550 Parameters[1].DefaultLength = sizeof(ULONG);
551
552 Status = RtlQueryRegistryValues(
553 RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
554 ParametersPath.Buffer,
555 Parameters,
556 NULL,
557 NULL);
558
559 if (!NT_SUCCESS(Status))
560 {
561 DPRINT("RtlQueryRegistryValues failed (0x%x)\n", Status);
562 return FALSE;
563 }
564 return TRUE;
565 }
566
567
568 // Initialize the PS/2 mouse support
569 BOOLEAN SetupMouse(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING RegistryPath)
570 {
571 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
572 ULONG MappedIrq;
573 KIRQL Dirql;
574 KAFFINITY Affinity;
575 LARGE_INTEGER Millisecond_Timeout;
576
577 Millisecond_Timeout.QuadPart = 1;
578
579 /* setup */
580 DeviceExtension->NoExtensions = 0;
581 DeviceExtension->InputDataCount[0] = 0;
582 DeviceExtension->InputDataCount[1] = 0;
583 DeviceExtension->ActiveQueue = 0;
584 DeviceExtension->MouseBufferPosition = 0;
585 DeviceExtension->MouseBufferSize = 3;
586 DeviceExtension->Resolution = 0;
587 DeviceExtension->RepliesExpected = 0;
588 DeviceExtension->PreviousButtons = 0;
589 DeviceExtension->SmartScroll = 1;
590 DeviceExtension->ack = 0;
591 DeviceExtension->acking = 0;
592
593 LoadMouseSettings(DeviceExtension, RegistryPath);
594
595 // Enable the PS/2 mouse port
596 controller_write_command_word (CONTROLLER_COMMAND_MOUSE_ENABLE);
597
598 //InitializeMouse(DeviceExtension);
599 DeviceExtension->MouseType = TestMouse(DeviceExtension);
600
601 if(DeviceExtension->MouseType > 0)
602 {
603 /* set the incoming buffer to 4 if needed */
604 DeviceExtension->MouseBufferSize += (DeviceExtension->MouseType >= PSMOUSE_GENPS);
605
606 DPRINT("Detected Mouse: 0x%x\n", DeviceExtension->MouseType);
607
608 InitializeMouse(DeviceExtension);
609
610 // Enable controller interrupts
611 mouse_write_command (MOUSE_INTERRUPTS_ON);
612
613 // Connect the interrupt for the mouse irq
614 MappedIrq = HalGetInterruptVector(Internal, 0, 0, MOUSE_IRQ, &Dirql, &Affinity);
615
616 IoConnectInterrupt(&DeviceExtension->MouseInterrupt, MouseHandler, DeviceObject, NULL, MappedIrq,
617 Dirql, Dirql, 0, FALSE, Affinity, FALSE);
618 }
619 else
620 {
621 /* FIXME - this fixes the crash if no mouse was detected */
622
623 // Connect the interrupt for the mouse irq
624 MappedIrq = HalGetInterruptVector(Internal, 0, 0, MOUSE_IRQ, &Dirql, &Affinity);
625
626 IoConnectInterrupt(&DeviceExtension->MouseInterrupt, MouseHandler, DeviceObject, NULL, MappedIrq,
627 Dirql, Dirql, 0, FALSE, Affinity, FALSE);
628 }
629
630 return TRUE;
631 }
632
633
634 // Check if this is a dual port controller.
635 BOOLEAN DetectPS2Port(void)
636 {
637 int loops;
638 unsigned scancode;
639 BOOLEAN return_value = FALSE;
640 LARGE_INTEGER Millisecond_Timeout;
641
642 Millisecond_Timeout.QuadPart = 1;
643
644 //return TRUE; // The rest of this code fails under BOCHs
645
646 /* Put the value 0x5A in the output buffer using the "WriteAuxiliary Device Output Buffer" command (0xD3).
647 Poll the Status Register for a while to see if the value really turns up in the Data Register. If the
648 KEYBOARD_STATUS_MOUSE_OBF bit is also set to 1 in the Status Register, we assume this controller has an
649 Auxiliary Port (a.k.a. Mouse Port). */
650
651 controller_wait ();
652 controller_write_command(CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER);
653 controller_wait ();
654
655 /* 0x5A is a random dummy value */
656 controller_write_output(0x5A);
657
658 for (loops = 0; loops < 10; loops++)
659 {
660 unsigned char status = controller_read_status();
661
662 if((status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
663 {
664 scancode = controller_read_input();
665 if((status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) != 0)
666 {
667 return_value = TRUE;
668 }
669 break;
670 }
671
672 KeDelayExecutionThread(KernelMode, FALSE, &Millisecond_Timeout);
673 }
674
675 return return_value;
676 }
677