2 * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/input/i8042prt/mouse.c
5 * PURPOSE: Mouse specific functions
6 * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
7 Copyright Jason Filby (jasonfilby@yahoo.com)
8 Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
9 Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
10 Copyright 2008 Colin Finck (mail@colinfinck.de)
13 /* INCLUDES ****************************************************************/
19 /* FUNCTIONS *****************************************************************/
22 * These functions are callbacks for filter driver custom interrupt
30 PI8042_MOUSE_EXTENSION DeviceExtension
;
32 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)Context
;
34 if (DeviceExtension
->MouseHook
.IsrWritePort
!= i8042MouIsrWritePort
)
36 DeviceExtension
->MouseHook
.IsrWritePort(
37 DeviceExtension
->MouseHook
.CallContext
,
41 i8042IsrWritePort(DeviceExtension
->Common
.PortDeviceExtension
, Value
, CTRL_WRITE_MOUSE
);
48 PI8042_MOUSE_EXTENSION DeviceExtension
;
50 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)Context
;
52 DeviceExtension
->MouseComplete
= TRUE
;
53 DeviceExtension
->MouseInBuffer
++;
54 if (DeviceExtension
->MouseInBuffer
>= DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseDataQueueSize
)
56 WARN_(I8042PRT
, "Mouse buffer overflow\n");
57 DeviceExtension
->MouseInBuffer
--;
60 TRACE_(I8042PRT
, "Irq completes mouse packet\n");
61 KeInsertQueueDpc(&DeviceExtension
->DpcMouse
, NULL
, NULL
);
66 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
69 PMOUSE_INPUT_DATA MouseInput
;
72 MouseInput
= DeviceExtension
->MouseBuffer
+ DeviceExtension
->MouseInBuffer
;
74 switch (DeviceExtension
->MouseState
)
77 /* This bit should be 1, if not drop the packet, we
78 * might be lucky and get in sync again
81 WARN_(I8042PRT
, "Bad input, dropping..\n");
85 MouseInput
->Buttons
= 0;
86 MouseInput
->RawButtons
= 0;
87 MouseInput
->Flags
= MOUSE_MOVE_RELATIVE
;
89 /* Note how we ignore the overflow bits, like Windows
90 * is said to do. There's no reasonable thing to do
95 MouseInput
->LastX
= 1;
97 MouseInput
->LastX
= 0;
99 MouseInput
->LastY
= 1;
101 MouseInput
->LastY
= 0;
104 MouseInput
->RawButtons
|= MOUSE_LEFT_BUTTON_DOWN
;
106 MouseInput
->RawButtons
|= MOUSE_RIGHT_BUTTON_DOWN
;
108 MouseInput
->RawButtons
|= MOUSE_MIDDLE_BUTTON_DOWN
;
110 DeviceExtension
->MouseState
= XMovement
;
114 if (MouseInput
->LastX
)
115 MouseInput
->LastX
= (LONG
) Output
- 256;
117 MouseInput
->LastX
= Output
;
119 DeviceExtension
->MouseState
= YMovement
;
123 if (MouseInput
->LastY
)
124 MouseInput
->LastY
= (LONG
)Output
- 256;
126 MouseInput
->LastY
= (LONG
)Output
;
128 /* Windows wants it the other way around */
129 MouseInput
->LastY
= -MouseInput
->LastY
;
131 if (DeviceExtension
->MouseType
== GenericPS2
||
132 DeviceExtension
->MouseType
== Ps2pp
)
134 i8042MouHandleButtons(
136 MOUSE_LEFT_BUTTON_DOWN
|
137 MOUSE_RIGHT_BUTTON_DOWN
|
138 MOUSE_MIDDLE_BUTTON_DOWN
);
139 DeviceExtension
->MouseHook
.QueueMousePacket(DeviceExtension
->MouseHook
.CallContext
);
140 DeviceExtension
->MouseState
= MouseIdle
;
144 DeviceExtension
->MouseState
= ZMovement
;
149 Scroll
= Output
& 0x0f;
155 MouseInput
->RawButtons
|= MOUSE_WHEEL
;
156 MouseInput
->ButtonData
= (USHORT
)(Scroll
* -WHEEL_DELTA
);
159 if (DeviceExtension
->MouseType
== IntellimouseExplorer
)
162 MouseInput
->RawButtons
|= MOUSE_BUTTON_4_DOWN
;
164 MouseInput
->RawButtons
|= MOUSE_BUTTON_5_DOWN
;
166 i8042MouHandleButtons(
168 MOUSE_LEFT_BUTTON_DOWN
|
169 MOUSE_RIGHT_BUTTON_DOWN
|
170 MOUSE_MIDDLE_BUTTON_DOWN
|
171 MOUSE_BUTTON_4_DOWN
|
172 MOUSE_BUTTON_5_DOWN
);
173 DeviceExtension
->MouseHook
.QueueMousePacket(DeviceExtension
->MouseHook
.CallContext
);
174 DeviceExtension
->MouseState
= MouseIdle
;
178 ERR_(I8042PRT
, "Unexpected state 0x%u!\n", DeviceExtension
->MouseState
);
184 * Updates ButtonFlags according to RawButtons and a saved state;
185 * Only takes in account the bits that are set in Mask
188 i8042MouHandleButtons(
189 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
192 PMOUSE_INPUT_DATA MouseInput
;
193 USHORT NewButtonData
;
196 MouseInput
= DeviceExtension
->MouseBuffer
+ DeviceExtension
->MouseInBuffer
;
197 NewButtonData
= (USHORT
)(MouseInput
->RawButtons
& Mask
);
198 ButtonDiff
= (NewButtonData
^ DeviceExtension
->MouseButtonState
) & Mask
;
200 /* Note that the defines are such:
201 * MOUSE_LEFT_BUTTON_DOWN 1
202 * MOUSE_LEFT_BUTTON_UP 2
204 MouseInput
->ButtonFlags
|= (NewButtonData
& ButtonDiff
) |
205 (((~(NewButtonData
)) << 1) & (ButtonDiff
<< 1)) |
206 (MouseInput
->RawButtons
& 0xfc00);
208 INFO_(I8042PRT
, "Left raw/up/down: %u/%u/%u\n",
209 MouseInput
->RawButtons
& MOUSE_LEFT_BUTTON_DOWN
,
210 MouseInput
->ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
,
211 MouseInput
->ButtonFlags
& MOUSE_LEFT_BUTTON_UP
);
213 DeviceExtension
->MouseButtonState
=
214 (DeviceExtension
->MouseButtonState
& ~Mask
) | (NewButtonData
& Mask
);
217 /* Does final initializations for the mouse. This method
218 * is called just before connecting the interrupt.
222 IN PI8042_MOUSE_EXTENSION DeviceExtension
)
227 /* Enable the PS/2 mouse port */
228 i8042Write(DeviceExtension
->Common
.PortDeviceExtension
, DeviceExtension
->Common
.PortDeviceExtension
->ControlPort
, MOUSE_ENAB
);
230 /* Enable the mouse */
231 if(!i8042IsrWritePort(DeviceExtension
->Common
.PortDeviceExtension
, MOU_ENAB
, CTRL_WRITE_MOUSE
))
233 WARN_(I8042PRT
, "Failed to enable mouse!\n");
234 return STATUS_IO_DEVICE_ERROR
;
237 Status
= i8042ReadDataWait(DeviceExtension
->Common
.PortDeviceExtension
, &Value
);
238 if (!NT_SUCCESS(Status
))
240 WARN_(I8042PRT
, "Failed to read the response of MOU_ENAB, status 0x%08lx\n", Status
);
244 if(Value
== MOUSE_ACK
)
246 INFO_(I8042PRT
, "Mouse was enabled successfully!\n");
247 return STATUS_SUCCESS
;
250 WARN_(I8042PRT
, "Got 0x%02x instead of 0xFA\n", Value
);
251 return STATUS_IO_DEVICE_ERROR
;
257 IN PVOID DeferredContext
,
258 IN PVOID SystemArgument1
,
259 IN PVOID SystemArgument2
)
261 PI8042_MOUSE_EXTENSION DeviceExtension
;
262 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
263 ULONG MouseTransferred
= 0;
264 ULONG MouseInBufferCopy
;
266 LARGE_INTEGER Timeout
;
268 UNREFERENCED_PARAMETER(Dpc
);
269 UNREFERENCED_PARAMETER(SystemArgument1
);
270 UNREFERENCED_PARAMETER(SystemArgument2
);
272 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)DeferredContext
;
273 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
275 switch (DeviceExtension
->MouseTimeoutState
)
279 DeviceExtension
->MouseTimeoutState
= NoChange
;
280 if (DeviceExtension
->MouseTimeoutActive
&&
281 !KeCancelTimer(&DeviceExtension
->TimerMouseTimeout
))
283 /* The timer fired already, give up */
284 DeviceExtension
->MouseTimeoutActive
= FALSE
;
288 Timeout
.QuadPart
= -15000000; /* 1.5 seconds, should be enough */
291 &DeviceExtension
->TimerMouseTimeout
,
293 &DeviceExtension
->DpcMouseTimeout
);
294 DeviceExtension
->MouseTimeoutActive
= TRUE
;
300 DeviceExtension
->MouseTimeoutState
= NoChange
;
301 KeCancelTimer(&DeviceExtension
->TimerMouseTimeout
);
302 DeviceExtension
->MouseTimeoutActive
= FALSE
;
306 ;/* nothing, don't want a warning */
309 /* Should be unlikely */
310 if (!DeviceExtension
->MouseComplete
)
313 Irql
= KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
315 DeviceExtension
->MouseComplete
= FALSE
;
316 MouseInBufferCopy
= DeviceExtension
->MouseInBuffer
;
318 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
320 TRACE_(I8042PRT
, "Send a mouse packet\n");
322 if (!DeviceExtension
->MouseData
.ClassService
)
325 INFO_(I8042PRT
, "Sending %lu mouse move(s)\n", MouseInBufferCopy
);
326 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->MouseData
.ClassService
)(
327 DeviceExtension
->MouseData
.ClassDeviceObject
,
328 DeviceExtension
->MouseBuffer
,
329 DeviceExtension
->MouseBuffer
+ MouseInBufferCopy
,
332 Irql
= KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
333 DeviceExtension
->MouseInBuffer
-= MouseTransferred
;
334 if (DeviceExtension
->MouseInBuffer
)
336 DeviceExtension
->MouseBuffer
,
337 DeviceExtension
->MouseBuffer
+ MouseTransferred
,
338 DeviceExtension
->MouseInBuffer
* sizeof(MOUSE_INPUT_DATA
));
339 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
342 /* This timer DPC will be called when the mouse reset times out.
343 * I'll just send the 'disable mouse port' command to the controller
344 * and say the mouse doesn't exist.
347 i8042DpcRoutineMouseTimeout(
349 IN PVOID DeferredContext
,
350 IN PVOID SystemArgument1
,
351 IN PVOID SystemArgument2
)
353 PI8042_MOUSE_EXTENSION DeviceExtension
;
354 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
357 UNREFERENCED_PARAMETER(Dpc
);
358 UNREFERENCED_PARAMETER(SystemArgument1
);
359 UNREFERENCED_PARAMETER(SystemArgument2
);
361 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)DeferredContext
;
362 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
364 Irql
= KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
366 WARN_(I8042PRT
, "Mouse initialization timeout! (substate %x)\n",
367 DeviceExtension
->MouseResetState
);
369 PortDeviceExtension
->Flags
&= ~MOUSE_PRESENT
;
371 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
375 * Runs the mouse IOCTL_INTERNAL dispatch.
378 i8042MouInternalDeviceControl(
379 IN PDEVICE_OBJECT DeviceObject
,
382 PIO_STACK_LOCATION Stack
;
383 PI8042_MOUSE_EXTENSION DeviceExtension
;
386 Stack
= IoGetCurrentIrpStackLocation(Irp
);
387 Irp
->IoStatus
.Information
= 0;
388 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)DeviceObject
->DeviceExtension
;
390 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
392 case IOCTL_INTERNAL_MOUSE_CONNECT
:
395 PIO_WORKITEM WorkItem
= NULL
;
396 PI8042_HOOK_WORKITEM WorkItemData
= NULL
;
398 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_CONNECT\n");
399 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(CONNECT_DATA
))
401 Status
= STATUS_INVALID_PARAMETER
;
405 DeviceExtension
->MouseData
=
406 *((PCONNECT_DATA
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
);
408 /* Send IOCTL_INTERNAL_I8042_HOOK_MOUSE to device stack */
409 WorkItem
= IoAllocateWorkItem(DeviceObject
);
412 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
413 Status
= STATUS_INSUFFICIENT_RESOURCES
;
416 WorkItemData
= ExAllocatePoolWithTag(
418 sizeof(I8042_HOOK_WORKITEM
),
422 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
423 Status
= STATUS_NO_MEMORY
;
426 WorkItemData
->WorkItem
= WorkItem
;
427 WorkItemData
->Irp
= Irp
;
429 /* Initialize extension */
430 DeviceExtension
->Common
.Type
= Mouse
;
431 Size
= DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseDataQueueSize
* sizeof(MOUSE_INPUT_DATA
);
432 DeviceExtension
->MouseBuffer
= ExAllocatePoolWithTag(
436 if (!DeviceExtension
->MouseBuffer
)
438 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
439 Status
= STATUS_NO_MEMORY
;
442 RtlZeroMemory(DeviceExtension
->MouseBuffer
, Size
);
443 DeviceExtension
->MouseAttributes
.InputDataQueueLength
=
444 DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseDataQueueSize
;
446 &DeviceExtension
->DpcMouse
,
450 &DeviceExtension
->DpcMouseTimeout
,
451 i8042DpcRoutineMouseTimeout
,
453 KeInitializeTimer(&DeviceExtension
->TimerMouseTimeout
);
454 DeviceExtension
->Common
.PortDeviceExtension
->MouseExtension
= DeviceExtension
;
455 DeviceExtension
->Common
.PortDeviceExtension
->Flags
|= MOUSE_CONNECTED
;
457 IoMarkIrpPending(Irp
);
458 DeviceExtension
->MouseState
= MouseResetting
;
459 DeviceExtension
->MouseResetState
= ExpectingReset
;
460 DeviceExtension
->MouseHook
.IsrWritePort
= i8042MouIsrWritePort
;
461 DeviceExtension
->MouseHook
.QueueMousePacket
= i8042MouQueuePacket
;
462 DeviceExtension
->MouseHook
.CallContext
= DeviceExtension
;
463 IoQueueWorkItem(WorkItem
,
464 i8042SendHookWorkItem
,
467 Status
= STATUS_PENDING
;
471 if (DeviceExtension
->MouseBuffer
)
472 ExFreePoolWithTag(DeviceExtension
->MouseBuffer
, I8042PRT_TAG
);
474 IoFreeWorkItem(WorkItem
);
476 ExFreePoolWithTag(WorkItemData
, I8042PRT_TAG
);
479 case IOCTL_INTERNAL_MOUSE_DISCONNECT
:
481 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_DISCONNECT\n");
482 /* MSDN says that operation is to implemented.
483 * To implement it, we just have to do:
484 * DeviceExtension->MouseData.ClassService = NULL;
486 Status
= STATUS_NOT_IMPLEMENTED
;
489 case IOCTL_INTERNAL_I8042_HOOK_MOUSE
:
491 PINTERNAL_I8042_HOOK_MOUSE MouseHook
;
492 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_MOUSE\n");
493 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(INTERNAL_I8042_HOOK_MOUSE
))
495 Status
= STATUS_INVALID_PARAMETER
;
498 MouseHook
= (PINTERNAL_I8042_HOOK_MOUSE
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
500 DeviceExtension
->MouseHook
.Context
= MouseHook
->Context
;
501 if (MouseHook
->IsrRoutine
)
502 DeviceExtension
->MouseHook
.IsrRoutine
= MouseHook
->IsrRoutine
;
504 Status
= STATUS_SUCCESS
;
507 case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER
:
509 DPRINT1("IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER not implemented\n");
510 Status
= STATUS_NOT_IMPLEMENTED
;
513 case IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION
:
515 DPRINT1("IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION not implemented\n");
516 Status
= STATUS_NOT_IMPLEMENTED
;
519 case IOCTL_MOUSE_QUERY_ATTRIBUTES
:
521 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_MOUSE_QUERY_ATTRIBUTES\n");
522 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUSE_ATTRIBUTES
))
524 Status
= STATUS_BUFFER_TOO_SMALL
;
528 *(PMOUSE_ATTRIBUTES
) Irp
->AssociatedIrp
.SystemBuffer
= DeviceExtension
->MouseAttributes
;
529 Irp
->IoStatus
.Information
= sizeof(MOUSE_ATTRIBUTES
);
530 Status
= STATUS_SUCCESS
;
535 ERR_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
536 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
538 return ForwardIrpAndForget(DeviceObject
, Irp
);
542 Irp
->IoStatus
.Status
= Status
;
543 if (Status
!= STATUS_PENDING
)
544 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
548 /* Test if packets are taking too long to come in. If they do, we
549 * might have gotten out of sync and should just drop what we have.
551 * If we want to be totally right, we'd also have to keep a count of
552 * errors, and totally reset the mouse after too much of them (can
553 * happen if the user is using a KVM switch and an OS on another port
554 * resets the mouse, or if the user hotplugs the mouse, or if we're just
555 * generally unlucky). Also note the input parsing routine where we
556 * drop invalid input packets.
559 i8042MouInputTestTimeout(
560 IN PI8042_MOUSE_EXTENSION DeviceExtension
)
564 if (DeviceExtension
->MouseState
== MouseExpectingACK
||
565 DeviceExtension
->MouseState
== MouseResetting
)
568 Now
.QuadPart
= KeQueryInterruptTime();
570 if (DeviceExtension
->MouseState
!= MouseIdle
) {
571 /* Check if the last byte came too long ago */
572 if (Now
.QuadPart
- DeviceExtension
->MousePacketStartTime
.QuadPart
>
573 DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseSynchIn100ns
)
575 WARN_(I8042PRT
, "Mouse input packet timeout\n");
576 DeviceExtension
->MouseState
= MouseIdle
;
580 if (DeviceExtension
->MouseState
== MouseIdle
)
581 DeviceExtension
->MousePacketStartTime
.QuadPart
= Now
.QuadPart
;
585 * Call the customization hook. The ToReturn parameter is about wether
586 * we should go on with the interrupt. The return value is what
587 * we should return (indicating to the system wether someone else
588 * should try to handle the interrupt)
592 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
595 OUT PBOOLEAN ToReturn
)
597 BOOLEAN HookReturn
, HookContinue
;
599 HookContinue
= FALSE
;
601 if (DeviceExtension
->MouseHook
.IsrRoutine
)
603 HookReturn
= DeviceExtension
->MouseHook
.IsrRoutine(
604 DeviceExtension
->MouseHook
.Context
,
605 DeviceExtension
->MouseBuffer
+ DeviceExtension
->MouseInBuffer
,
606 &DeviceExtension
->Common
.PortDeviceExtension
->Packet
,
610 &DeviceExtension
->MouseState
,
611 &DeviceExtension
->MouseResetState
);
615 *ToReturn
= HookReturn
;
624 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
628 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
629 BOOLEAN ToReturn
= FALSE
;
631 if (i8042MouCallIsrHook(DeviceExtension
, Status
, Value
, &ToReturn
))
634 if (MouseIdle
== DeviceExtension
->MouseState
)
636 /* Magic packet value that indicates a reset */
639 WARN_(I8042PRT
, "Hot plugged mouse!\n");
640 DeviceExtension
->MouseState
= MouseResetting
;
641 DeviceExtension
->MouseResetState
= ExpectingReset
;
646 else if (MouseResetting
!= DeviceExtension
->MouseState
)
649 DeviceExtension
->MouseTimeoutState
= TimeoutStart
;
650 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
652 switch ((ULONG
)DeviceExtension
->MouseResetState
)
655 if (MOUSE_ACK
== Value
)
657 WARN_(I8042PRT
, "Dropping extra ACK\n");
661 /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok, FC00 if not. */
664 DeviceExtension
->MouseResetState
++;
668 PortDeviceExtension
->Flags
&= ~MOUSE_PRESENT
;
669 DeviceExtension
->MouseState
= MouseIdle
;
670 WARN_(I8042PRT
, "Mouse returned bad reset reply: %x (expected aa)\n", Value
);
673 case ExpectingResetId
:
674 if (MOUSE_ACK
== Value
)
676 WARN_(I8042PRT
, "Dropping extra ACK #2\n");
682 DeviceExtension
->MouseResetState
++;
683 DeviceExtension
->MouseType
= GenericPS2
;
684 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF2);
688 PortDeviceExtension
->Flags
&= ~MOUSE_PRESENT
;
689 DeviceExtension
->MouseState
= MouseIdle
;
690 WARN_(I8042PRT
, "Mouse returned bad reset reply part two: %x (expected 0)\n", Value
);
693 case ExpectingGetDeviceIdACK
:
694 if (MOUSE_ACK
== Value
)
696 DeviceExtension
->MouseResetState
++;
698 else if (MOUSE_NACK
== Value
|| MOUSE_ERROR
== Value
)
700 DeviceExtension
->MouseResetState
++;
701 /* Act as if 00 (normal mouse) was received */
702 WARN_(I8042PRT
, "Mouse doesn't support 0xd2, (returns %x, expected %x), faking\n", Value
, MOUSE_ACK
);
703 i8042MouResetIsr(DeviceExtension
, Status
, 0);
706 case ExpectingGetDeviceIdValue
:
710 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
711 BALLPOINT_I8042_HARDWARE
;
715 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
716 WHEELMOUSE_I8042_HARDWARE
;
719 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
720 MOUSE_I8042_HARDWARE
;
722 DeviceExtension
->MouseResetState
++;
723 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE8);
725 case ExpectingSetResolutionDefaultACK
:
726 DeviceExtension
->MouseResetState
++;
727 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x00);
729 case ExpectingSetResolutionDefaultValueACK
:
730 DeviceExtension
->MouseResetState
= ExpectingSetScaling1to1ACK
;
731 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE6);
733 case ExpectingSetScaling1to1ACK
:
734 case ExpectingSetScaling1to1ACK2
:
735 DeviceExtension
->MouseResetState
++;
736 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE6);
738 case ExpectingSetScaling1to1ACK3
:
739 DeviceExtension
->MouseResetState
++;
740 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE9);
742 case ExpectingReadMouseStatusACK
:
743 DeviceExtension
->MouseResetState
++;
745 case ExpectingReadMouseStatusByte1
:
746 DeviceExtension
->MouseLogiBuffer
[0] = Value
;
747 DeviceExtension
->MouseResetState
++;
749 case ExpectingReadMouseStatusByte2
:
750 DeviceExtension
->MouseLogiBuffer
[1] = Value
;
751 DeviceExtension
->MouseResetState
++;
753 case ExpectingReadMouseStatusByte3
:
754 DeviceExtension
->MouseLogiBuffer
[2] = Value
;
755 /* Now MouseLogiBuffer is a set of info. If the second
756 * byte is 0, the mouse didn't understand the magic
757 * code. Otherwise, it it a Logitech and the second byte
758 * is the number of buttons, bit 7 of the first byte tells
759 * if it understands special E7 commands, the rest is an ID.
761 if (DeviceExtension
->MouseLogiBuffer
[1])
763 DeviceExtension
->MouseAttributes
.NumberOfButtons
=
764 DeviceExtension
->MouseLogiBuffer
[1];
765 DeviceExtension
->MouseType
= Ps2pp
;
766 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
767 DeviceExtension
->MouseResetState
= ExpectingSetSamplingRateACK
;
768 /* TODO: Go through EnableWheel and Enable5Buttons */
771 DeviceExtension
->MouseResetState
= EnableWheel
;
772 i8042MouResetIsr(DeviceExtension
, Status
, Value
);
775 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
776 DeviceExtension
->MouseResetState
= 1001;
779 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xC8);
780 DeviceExtension
->MouseResetState
++;
784 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
785 DeviceExtension
->MouseResetState
++;
788 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x64);
789 DeviceExtension
->MouseResetState
++;
792 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x50);
793 DeviceExtension
->MouseResetState
++;
796 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF2);
797 DeviceExtension
->MouseResetState
++;
801 DeviceExtension
->MouseResetState
++;
805 /* It's either an Intellimouse or Intellimouse Explorer. */
806 DeviceExtension
->MouseAttributes
.NumberOfButtons
= 3;
807 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
808 WHEELMOUSE_I8042_HARDWARE
;
809 DeviceExtension
->MouseType
= Intellimouse
;
810 DeviceExtension
->MouseResetState
= Enable5Buttons
;
811 i8042MouResetIsr(DeviceExtension
, Status
, Value
);
815 /* Just set the default settings and be done */
816 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
817 DeviceExtension
->MouseResetState
= ExpectingSetSamplingRateACK
;
821 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
822 DeviceExtension
->MouseResetState
= 1021;
826 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
827 DeviceExtension
->MouseResetState
++;
831 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xC8);
832 DeviceExtension
->MouseResetState
++;
835 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x50);
836 DeviceExtension
->MouseResetState
++;
839 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF2);
840 DeviceExtension
->MouseResetState
++;
845 DeviceExtension
->MouseAttributes
.NumberOfButtons
= 5;
846 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
847 WHEELMOUSE_I8042_HARDWARE
;
848 DeviceExtension
->MouseType
= IntellimouseExplorer
;
850 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
851 DeviceExtension
->MouseResetState
= ExpectingSetSamplingRateACK
;
853 case ExpectingSetSamplingRateACK
:
854 DeviceExtension
->MouseHook
.IsrWritePort(
855 DeviceExtension
->MouseHook
.CallContext
,
856 (UCHAR
)DeviceExtension
->MouseAttributes
.SampleRate
);
857 DeviceExtension
->MouseResetState
++;
859 case ExpectingSetSamplingRateValueACK
:
860 if (MOUSE_NACK
== Value
)
862 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x3C);
863 DeviceExtension
->MouseAttributes
.SampleRate
= (USHORT
)PortDeviceExtension
->Settings
.SampleRate
;
864 DeviceExtension
->MouseResetState
= 1040;
867 case 1040: /* Fallthrough */
868 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE8);
869 DeviceExtension
->MouseResetState
= ExpectingFinalResolutionACK
;
871 case ExpectingFinalResolutionACK
:
872 DeviceExtension
->MouseHook
.IsrWritePort(
873 DeviceExtension
->MouseHook
.CallContext
,
874 (UCHAR
)(PortDeviceExtension
->Settings
.MouseResolution
& 0xff));
875 INFO_(I8042PRT
, "Mouse resolution %lu\n",
876 PortDeviceExtension
->Settings
.MouseResolution
);
877 DeviceExtension
->MouseResetState
= ExpectingFinalResolutionValueACK
;
879 case ExpectingFinalResolutionValueACK
:
880 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF4);
881 DeviceExtension
->MouseResetState
= ExpectingEnableACK
;
883 case ExpectingEnableACK
:
884 PortDeviceExtension
->Flags
|= MOUSE_PRESENT
;
885 DeviceExtension
->MouseState
= MouseIdle
;
886 DeviceExtension
->MouseTimeoutState
= TimeoutCancel
;
887 INFO_(I8042PRT
, "Mouse type = %u\n", DeviceExtension
->MouseType
);
890 if (DeviceExtension
->MouseResetState
< 100 || DeviceExtension
->MouseResetState
> 999)
891 ERR_(I8042PRT
, "MouseResetState went out of range: %lu\n", DeviceExtension
->MouseResetState
);
897 i8042MouInterruptService(
898 IN PKINTERRUPT Interrupt
,
901 PI8042_MOUSE_EXTENSION DeviceExtension
;
902 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
904 UCHAR Output
= 0, PortStatus
= 0;
907 UNREFERENCED_PARAMETER(Interrupt
);
909 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)Context
;
910 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
911 Counter
= PortDeviceExtension
->Settings
.PollStatusIterations
;
915 Status
= i8042ReadStatus(PortDeviceExtension
, &PortStatus
);
916 if (!NT_SUCCESS(Status
))
918 WARN_(I8042PRT
, "i8042ReadStatus() failed with status 0x%08lx\n", Status
);
921 Status
= i8042ReadMouseData(PortDeviceExtension
, &Output
);
922 if (NT_SUCCESS(Status
))
924 KeStallExecutionProcessor(1);
929 WARN_(I8042PRT
, "Spurious i8042 mouse interrupt\n");
933 INFO_(I8042PRT
, "Got: 0x%02x\n", Output
);
935 if (i8042PacketIsr(PortDeviceExtension
, Output
))
937 if (PortDeviceExtension
->PacketComplete
)
939 TRACE_(I8042PRT
, "Packet complete\n");
940 KeInsertQueueDpc(&DeviceExtension
->DpcMouse
, NULL
, NULL
);
942 TRACE_(I8042PRT
, "Irq eaten by packet\n");
946 TRACE_(I8042PRT
, "Irq is mouse input\n");
948 i8042MouInputTestTimeout(DeviceExtension
);
950 if (i8042MouResetIsr(DeviceExtension
, PortStatus
, Output
))
952 TRACE_(I8042PRT
, "Handled by ResetIsr or hooked Isr\n");
953 if (NoChange
!= DeviceExtension
->MouseTimeoutState
) {
954 KeInsertQueueDpc(&DeviceExtension
->DpcMouse
, NULL
, NULL
);
959 if (DeviceExtension
->MouseType
== Ps2pp
)
960 i8042MouHandlePs2pp(DeviceExtension
, Output
);
962 i8042MouHandle(DeviceExtension
, Output
);