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 *****************************************************************/
21 static KDEFERRED_ROUTINE i8042MouDpcRoutine
;
22 static KDEFERRED_ROUTINE i8042DpcRoutineMouseTimeout
;
25 * These functions are callbacks for filter driver custom interrupt
33 PI8042_MOUSE_EXTENSION DeviceExtension
;
35 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)Context
;
37 if (DeviceExtension
->MouseHook
.IsrWritePort
!= i8042MouIsrWritePort
)
39 DeviceExtension
->MouseHook
.IsrWritePort(
40 DeviceExtension
->MouseHook
.CallContext
,
44 i8042IsrWritePort(DeviceExtension
->Common
.PortDeviceExtension
, Value
, CTRL_WRITE_MOUSE
);
51 PI8042_MOUSE_EXTENSION DeviceExtension
;
53 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)Context
;
55 DeviceExtension
->MouseComplete
= TRUE
;
56 DeviceExtension
->MouseInBuffer
++;
57 if (DeviceExtension
->MouseInBuffer
>= DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseDataQueueSize
)
59 WARN_(I8042PRT
, "Mouse buffer overflow\n");
60 DeviceExtension
->MouseInBuffer
--;
63 TRACE_(I8042PRT
, "Irq completes mouse packet\n");
64 KeInsertQueueDpc(&DeviceExtension
->DpcMouse
, NULL
, NULL
);
69 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
72 PMOUSE_INPUT_DATA MouseInput
;
75 MouseInput
= DeviceExtension
->MouseBuffer
+ DeviceExtension
->MouseInBuffer
;
77 switch (DeviceExtension
->MouseState
)
80 /* This bit should be 1, if not drop the packet, we
81 * might be lucky and get in sync again
84 WARN_(I8042PRT
, "Bad input, dropping..\n");
88 MouseInput
->Buttons
= 0;
89 MouseInput
->RawButtons
= 0;
90 MouseInput
->Flags
= MOUSE_MOVE_RELATIVE
;
92 /* Note how we ignore the overflow bits, like Windows
93 * is said to do. There's no reasonable thing to do
98 MouseInput
->LastX
= 1;
100 MouseInput
->LastX
= 0;
102 MouseInput
->LastY
= 1;
104 MouseInput
->LastY
= 0;
107 MouseInput
->RawButtons
|= MOUSE_LEFT_BUTTON_DOWN
;
109 MouseInput
->RawButtons
|= MOUSE_RIGHT_BUTTON_DOWN
;
111 MouseInput
->RawButtons
|= MOUSE_MIDDLE_BUTTON_DOWN
;
113 DeviceExtension
->MouseState
= XMovement
;
117 if (MouseInput
->LastX
)
118 MouseInput
->LastX
= (LONG
) Output
- 256;
120 MouseInput
->LastX
= Output
;
122 DeviceExtension
->MouseState
= YMovement
;
126 if (MouseInput
->LastY
)
127 MouseInput
->LastY
= (LONG
)Output
- 256;
129 MouseInput
->LastY
= (LONG
)Output
;
131 /* Windows wants it the other way around */
132 MouseInput
->LastY
= -MouseInput
->LastY
;
134 if (DeviceExtension
->MouseType
== GenericPS2
||
135 DeviceExtension
->MouseType
== Ps2pp
)
137 i8042MouHandleButtons(
139 MOUSE_LEFT_BUTTON_DOWN
|
140 MOUSE_RIGHT_BUTTON_DOWN
|
141 MOUSE_MIDDLE_BUTTON_DOWN
);
142 DeviceExtension
->MouseHook
.QueueMousePacket(DeviceExtension
->MouseHook
.CallContext
);
143 DeviceExtension
->MouseState
= MouseIdle
;
147 DeviceExtension
->MouseState
= ZMovement
;
152 Scroll
= Output
& 0x0f;
158 MouseInput
->RawButtons
|= MOUSE_WHEEL
;
159 MouseInput
->ButtonData
= (USHORT
)(Scroll
* -WHEEL_DELTA
);
162 if (DeviceExtension
->MouseType
== IntellimouseExplorer
)
165 MouseInput
->RawButtons
|= MOUSE_BUTTON_4_DOWN
;
167 MouseInput
->RawButtons
|= MOUSE_BUTTON_5_DOWN
;
169 i8042MouHandleButtons(
171 MOUSE_LEFT_BUTTON_DOWN
|
172 MOUSE_RIGHT_BUTTON_DOWN
|
173 MOUSE_MIDDLE_BUTTON_DOWN
|
174 MOUSE_BUTTON_4_DOWN
|
175 MOUSE_BUTTON_5_DOWN
);
176 DeviceExtension
->MouseHook
.QueueMousePacket(DeviceExtension
->MouseHook
.CallContext
);
177 DeviceExtension
->MouseState
= MouseIdle
;
181 ERR_(I8042PRT
, "Unexpected state 0x%lx!\n", DeviceExtension
->MouseState
);
187 * Updates ButtonFlags according to RawButtons and a saved state;
188 * Only takes in account the bits that are set in Mask
191 i8042MouHandleButtons(
192 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
195 PMOUSE_INPUT_DATA MouseInput
;
196 USHORT NewButtonData
;
199 MouseInput
= DeviceExtension
->MouseBuffer
+ DeviceExtension
->MouseInBuffer
;
200 NewButtonData
= (USHORT
)(MouseInput
->RawButtons
& Mask
);
201 ButtonDiff
= (NewButtonData
^ DeviceExtension
->MouseButtonState
) & Mask
;
203 /* Note that the defines are such:
204 * MOUSE_LEFT_BUTTON_DOWN 1
205 * MOUSE_LEFT_BUTTON_UP 2
207 MouseInput
->ButtonFlags
|= (NewButtonData
& ButtonDiff
) |
208 (((~(NewButtonData
)) << 1) & (ButtonDiff
<< 1)) |
209 (MouseInput
->RawButtons
& 0xfc00);
211 INFO_(I8042PRT
, "Left raw/up/down: %u/%u/%u\n",
212 MouseInput
->RawButtons
& MOUSE_LEFT_BUTTON_DOWN
,
213 MouseInput
->ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
,
214 MouseInput
->ButtonFlags
& MOUSE_LEFT_BUTTON_UP
);
216 DeviceExtension
->MouseButtonState
=
217 (DeviceExtension
->MouseButtonState
& ~Mask
) | (NewButtonData
& Mask
);
220 /* Does final initializations for the mouse. This method
221 * is called just before connecting the interrupt.
225 IN PI8042_MOUSE_EXTENSION DeviceExtension
)
230 /* Enable the PS/2 mouse port */
231 i8042Write(DeviceExtension
->Common
.PortDeviceExtension
, DeviceExtension
->Common
.PortDeviceExtension
->ControlPort
, MOUSE_ENAB
);
233 /* Enable the mouse */
234 if(!i8042IsrWritePort(DeviceExtension
->Common
.PortDeviceExtension
, MOU_ENAB
, CTRL_WRITE_MOUSE
))
236 WARN_(I8042PRT
, "Failed to enable mouse!\n");
237 return STATUS_IO_DEVICE_ERROR
;
240 Status
= i8042ReadDataWait(DeviceExtension
->Common
.PortDeviceExtension
, &Value
);
241 if (!NT_SUCCESS(Status
))
243 WARN_(I8042PRT
, "Failed to read the response of MOU_ENAB, status 0x%08lx\n", Status
);
247 if(Value
== MOUSE_ACK
)
249 INFO_(I8042PRT
, "Mouse was enabled successfully!\n");
250 return STATUS_SUCCESS
;
253 WARN_(I8042PRT
, "Got 0x%02x instead of 0xFA\n", Value
);
254 return STATUS_IO_DEVICE_ERROR
;
260 IN PVOID DeferredContext
,
261 IN PVOID SystemArgument1
,
262 IN PVOID SystemArgument2
)
264 PI8042_MOUSE_EXTENSION DeviceExtension
;
265 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
266 ULONG MouseTransferred
= 0;
267 ULONG MouseInBufferCopy
;
269 LARGE_INTEGER Timeout
;
271 UNREFERENCED_PARAMETER(Dpc
);
272 UNREFERENCED_PARAMETER(SystemArgument1
);
273 UNREFERENCED_PARAMETER(SystemArgument2
);
275 __analysis_assume(DeferredContext
!= NULL
);
276 DeviceExtension
= DeferredContext
;
277 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
279 switch (DeviceExtension
->MouseTimeoutState
)
283 DeviceExtension
->MouseTimeoutState
= NoChange
;
284 if (DeviceExtension
->MouseTimeoutActive
&&
285 !KeCancelTimer(&DeviceExtension
->TimerMouseTimeout
))
287 /* The timer fired already, give up */
288 DeviceExtension
->MouseTimeoutActive
= FALSE
;
292 Timeout
.QuadPart
= -15000000; /* 1.5 seconds, should be enough */
295 &DeviceExtension
->TimerMouseTimeout
,
297 &DeviceExtension
->DpcMouseTimeout
);
298 DeviceExtension
->MouseTimeoutActive
= TRUE
;
304 DeviceExtension
->MouseTimeoutState
= NoChange
;
305 KeCancelTimer(&DeviceExtension
->TimerMouseTimeout
);
306 DeviceExtension
->MouseTimeoutActive
= FALSE
;
310 ;/* nothing, don't want a warning */
313 /* Should be unlikely */
314 if (!DeviceExtension
->MouseComplete
)
317 Irql
= KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
319 DeviceExtension
->MouseComplete
= FALSE
;
320 MouseInBufferCopy
= DeviceExtension
->MouseInBuffer
;
322 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
324 TRACE_(I8042PRT
, "Send a mouse packet\n");
326 if (!DeviceExtension
->MouseData
.ClassService
)
329 INFO_(I8042PRT
, "Sending %lu mouse move(s)\n", MouseInBufferCopy
);
330 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->MouseData
.ClassService
)(
331 DeviceExtension
->MouseData
.ClassDeviceObject
,
332 DeviceExtension
->MouseBuffer
,
333 DeviceExtension
->MouseBuffer
+ MouseInBufferCopy
,
336 Irql
= KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
337 DeviceExtension
->MouseInBuffer
-= MouseTransferred
;
338 if (DeviceExtension
->MouseInBuffer
)
340 DeviceExtension
->MouseBuffer
,
341 DeviceExtension
->MouseBuffer
+ MouseTransferred
,
342 DeviceExtension
->MouseInBuffer
* sizeof(MOUSE_INPUT_DATA
));
343 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
346 /* This timer DPC will be called when the mouse reset times out.
347 * I'll just send the 'disable mouse port' command to the controller
348 * and say the mouse doesn't exist.
351 i8042DpcRoutineMouseTimeout(
353 IN PVOID DeferredContext
,
354 IN PVOID SystemArgument1
,
355 IN PVOID SystemArgument2
)
357 PI8042_MOUSE_EXTENSION DeviceExtension
;
358 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
361 UNREFERENCED_PARAMETER(Dpc
);
362 UNREFERENCED_PARAMETER(SystemArgument1
);
363 UNREFERENCED_PARAMETER(SystemArgument2
);
365 __analysis_assume(DeferredContext
!= NULL
);
366 DeviceExtension
= DeferredContext
;
367 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
369 Irql
= KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
371 WARN_(I8042PRT
, "Mouse initialization timeout! (substate %x)\n",
372 DeviceExtension
->MouseResetState
);
374 PortDeviceExtension
->Flags
&= ~MOUSE_PRESENT
;
376 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
380 * Runs the mouse IOCTL_INTERNAL dispatch.
383 i8042MouInternalDeviceControl(
384 IN PDEVICE_OBJECT DeviceObject
,
387 PIO_STACK_LOCATION Stack
;
388 PI8042_MOUSE_EXTENSION DeviceExtension
;
391 Stack
= IoGetCurrentIrpStackLocation(Irp
);
392 Irp
->IoStatus
.Information
= 0;
393 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)DeviceObject
->DeviceExtension
;
395 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
397 case IOCTL_INTERNAL_MOUSE_CONNECT
:
400 PIO_WORKITEM WorkItem
= NULL
;
401 PI8042_HOOK_WORKITEM WorkItemData
= NULL
;
403 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_CONNECT\n");
404 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(CONNECT_DATA
))
406 Status
= STATUS_INVALID_PARAMETER
;
410 DeviceExtension
->MouseData
=
411 *((PCONNECT_DATA
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
);
413 /* Send IOCTL_INTERNAL_I8042_HOOK_MOUSE to device stack */
414 WorkItem
= IoAllocateWorkItem(DeviceObject
);
417 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
418 Status
= STATUS_INSUFFICIENT_RESOURCES
;
421 WorkItemData
= ExAllocatePoolWithTag(
423 sizeof(I8042_HOOK_WORKITEM
),
427 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
428 Status
= STATUS_NO_MEMORY
;
431 WorkItemData
->WorkItem
= WorkItem
;
432 WorkItemData
->Irp
= Irp
;
434 /* Initialize extension */
435 DeviceExtension
->Common
.Type
= Mouse
;
436 Size
= DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseDataQueueSize
* sizeof(MOUSE_INPUT_DATA
);
437 DeviceExtension
->MouseBuffer
= ExAllocatePoolWithTag(
441 if (!DeviceExtension
->MouseBuffer
)
443 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
444 Status
= STATUS_NO_MEMORY
;
447 RtlZeroMemory(DeviceExtension
->MouseBuffer
, Size
);
448 DeviceExtension
->MouseAttributes
.InputDataQueueLength
=
449 DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseDataQueueSize
;
451 &DeviceExtension
->DpcMouse
,
455 &DeviceExtension
->DpcMouseTimeout
,
456 i8042DpcRoutineMouseTimeout
,
458 KeInitializeTimer(&DeviceExtension
->TimerMouseTimeout
);
459 DeviceExtension
->Common
.PortDeviceExtension
->MouseExtension
= DeviceExtension
;
460 DeviceExtension
->Common
.PortDeviceExtension
->Flags
|= MOUSE_CONNECTED
;
462 IoMarkIrpPending(Irp
);
463 DeviceExtension
->MouseState
= MouseResetting
;
464 DeviceExtension
->MouseResetState
= ExpectingReset
;
465 DeviceExtension
->MouseHook
.IsrWritePort
= i8042MouIsrWritePort
;
466 DeviceExtension
->MouseHook
.QueueMousePacket
= i8042MouQueuePacket
;
467 DeviceExtension
->MouseHook
.CallContext
= DeviceExtension
;
468 IoQueueWorkItem(WorkItem
,
469 i8042SendHookWorkItem
,
472 Status
= STATUS_PENDING
;
476 if (DeviceExtension
->MouseBuffer
)
477 ExFreePoolWithTag(DeviceExtension
->MouseBuffer
, I8042PRT_TAG
);
479 IoFreeWorkItem(WorkItem
);
481 ExFreePoolWithTag(WorkItemData
, I8042PRT_TAG
);
484 case IOCTL_INTERNAL_MOUSE_DISCONNECT
:
486 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_DISCONNECT\n");
487 /* MSDN says that operation is to implemented.
488 * To implement it, we just have to do:
489 * DeviceExtension->MouseData.ClassService = NULL;
491 Status
= STATUS_NOT_IMPLEMENTED
;
494 case IOCTL_INTERNAL_I8042_HOOK_MOUSE
:
496 PINTERNAL_I8042_HOOK_MOUSE MouseHook
;
497 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_MOUSE\n");
498 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(INTERNAL_I8042_HOOK_MOUSE
))
500 Status
= STATUS_INVALID_PARAMETER
;
503 MouseHook
= (PINTERNAL_I8042_HOOK_MOUSE
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
505 DeviceExtension
->MouseHook
.Context
= MouseHook
->Context
;
506 if (MouseHook
->IsrRoutine
)
507 DeviceExtension
->MouseHook
.IsrRoutine
= MouseHook
->IsrRoutine
;
509 Status
= STATUS_SUCCESS
;
512 case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER
:
514 DPRINT1("IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER not implemented\n");
515 Status
= STATUS_NOT_IMPLEMENTED
;
518 case IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION
:
520 DPRINT1("IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION not implemented\n");
521 Status
= STATUS_NOT_IMPLEMENTED
;
524 case IOCTL_MOUSE_QUERY_ATTRIBUTES
:
526 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_MOUSE_QUERY_ATTRIBUTES\n");
527 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUSE_ATTRIBUTES
))
529 Status
= STATUS_BUFFER_TOO_SMALL
;
533 *(PMOUSE_ATTRIBUTES
) Irp
->AssociatedIrp
.SystemBuffer
= DeviceExtension
->MouseAttributes
;
534 Irp
->IoStatus
.Information
= sizeof(MOUSE_ATTRIBUTES
);
535 Status
= STATUS_SUCCESS
;
540 ERR_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
541 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
543 return ForwardIrpAndForget(DeviceObject
, Irp
);
547 if (Status
!= STATUS_PENDING
)
549 Irp
->IoStatus
.Status
= Status
;
550 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
555 /* Test if packets are taking too long to come in. If they do, we
556 * might have gotten out of sync and should just drop what we have.
558 * If we want to be totally right, we'd also have to keep a count of
559 * errors, and totally reset the mouse after too much of them (can
560 * happen if the user is using a KVM switch and an OS on another port
561 * resets the mouse, or if the user hotplugs the mouse, or if we're just
562 * generally unlucky). Also note the input parsing routine where we
563 * drop invalid input packets.
566 i8042MouInputTestTimeout(
567 IN PI8042_MOUSE_EXTENSION DeviceExtension
)
571 if (DeviceExtension
->MouseState
== MouseExpectingACK
||
572 DeviceExtension
->MouseState
== MouseResetting
)
575 Now
.QuadPart
= KeQueryInterruptTime();
577 if (DeviceExtension
->MouseState
!= MouseIdle
) {
578 /* Check if the last byte came too long ago */
579 if (Now
.QuadPart
- DeviceExtension
->MousePacketStartTime
.QuadPart
>
580 DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseSynchIn100ns
)
582 WARN_(I8042PRT
, "Mouse input packet timeout\n");
583 DeviceExtension
->MouseState
= MouseIdle
;
587 if (DeviceExtension
->MouseState
== MouseIdle
)
588 DeviceExtension
->MousePacketStartTime
.QuadPart
= Now
.QuadPart
;
592 * Call the customization hook. The ToReturn parameter is about wether
593 * we should go on with the interrupt. The return value is what
594 * we should return (indicating to the system wether someone else
595 * should try to handle the interrupt)
599 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
602 OUT PBOOLEAN ToReturn
)
604 BOOLEAN HookReturn
, HookContinue
;
606 HookContinue
= FALSE
;
608 if (DeviceExtension
->MouseHook
.IsrRoutine
)
610 HookReturn
= DeviceExtension
->MouseHook
.IsrRoutine(
611 DeviceExtension
->MouseHook
.Context
,
612 DeviceExtension
->MouseBuffer
+ DeviceExtension
->MouseInBuffer
,
613 &DeviceExtension
->Common
.PortDeviceExtension
->Packet
,
617 &DeviceExtension
->MouseState
,
618 &DeviceExtension
->MouseResetState
);
622 *ToReturn
= HookReturn
;
631 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
635 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
636 BOOLEAN ToReturn
= FALSE
;
638 if (i8042MouCallIsrHook(DeviceExtension
, Status
, Value
, &ToReturn
))
641 if (MouseIdle
== DeviceExtension
->MouseState
)
643 /* Magic packet value that indicates a reset */
646 WARN_(I8042PRT
, "Hot plugged mouse!\n");
647 DeviceExtension
->MouseState
= MouseResetting
;
648 DeviceExtension
->MouseResetState
= ExpectingReset
;
653 else if (MouseResetting
!= DeviceExtension
->MouseState
)
656 DeviceExtension
->MouseTimeoutState
= TimeoutStart
;
657 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
659 switch ((ULONG
)DeviceExtension
->MouseResetState
)
662 if (MOUSE_ACK
== Value
)
664 WARN_(I8042PRT
, "Dropping extra ACK\n");
668 /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok, FC00 if not. */
671 DeviceExtension
->MouseResetState
++;
675 PortDeviceExtension
->Flags
&= ~MOUSE_PRESENT
;
676 DeviceExtension
->MouseState
= MouseIdle
;
677 WARN_(I8042PRT
, "Mouse returned bad reset reply: %x (expected aa)\n", Value
);
680 case ExpectingResetId
:
681 if (MOUSE_ACK
== Value
)
683 WARN_(I8042PRT
, "Dropping extra ACK #2\n");
689 DeviceExtension
->MouseResetState
++;
690 DeviceExtension
->MouseType
= GenericPS2
;
691 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF2);
695 PortDeviceExtension
->Flags
&= ~MOUSE_PRESENT
;
696 DeviceExtension
->MouseState
= MouseIdle
;
697 WARN_(I8042PRT
, "Mouse returned bad reset reply part two: %x (expected 0)\n", Value
);
700 case ExpectingGetDeviceIdACK
:
701 if (MOUSE_ACK
== Value
)
703 DeviceExtension
->MouseResetState
++;
705 else if (MOUSE_NACK
== Value
|| MOUSE_ERROR
== Value
)
707 DeviceExtension
->MouseResetState
++;
708 /* Act as if 00 (normal mouse) was received */
709 WARN_(I8042PRT
, "Mouse doesn't support 0xd2, (returns %x, expected %x), faking\n", Value
, MOUSE_ACK
);
710 i8042MouResetIsr(DeviceExtension
, Status
, 0);
713 case ExpectingGetDeviceIdValue
:
717 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
718 BALLPOINT_I8042_HARDWARE
;
722 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
723 WHEELMOUSE_I8042_HARDWARE
;
726 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
727 MOUSE_I8042_HARDWARE
;
729 DeviceExtension
->MouseResetState
++;
730 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE8);
732 case ExpectingSetResolutionDefaultACK
:
733 DeviceExtension
->MouseResetState
++;
734 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x00);
736 case ExpectingSetResolutionDefaultValueACK
:
737 DeviceExtension
->MouseResetState
= ExpectingSetScaling1to1ACK
;
738 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE6);
740 case ExpectingSetScaling1to1ACK
:
741 case ExpectingSetScaling1to1ACK2
:
742 DeviceExtension
->MouseResetState
++;
743 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE6);
745 case ExpectingSetScaling1to1ACK3
:
746 DeviceExtension
->MouseResetState
++;
747 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE9);
749 case ExpectingReadMouseStatusACK
:
750 DeviceExtension
->MouseResetState
++;
752 case ExpectingReadMouseStatusByte1
:
753 DeviceExtension
->MouseLogiBuffer
[0] = Value
;
754 DeviceExtension
->MouseResetState
++;
756 case ExpectingReadMouseStatusByte2
:
757 DeviceExtension
->MouseLogiBuffer
[1] = Value
;
758 DeviceExtension
->MouseResetState
++;
760 case ExpectingReadMouseStatusByte3
:
761 DeviceExtension
->MouseLogiBuffer
[2] = Value
;
762 /* Now MouseLogiBuffer is a set of info. If the second
763 * byte is 0, the mouse didn't understand the magic
764 * code. Otherwise, it it a Logitech and the second byte
765 * is the number of buttons, bit 7 of the first byte tells
766 * if it understands special E7 commands, the rest is an ID.
768 if (DeviceExtension
->MouseLogiBuffer
[1])
770 DeviceExtension
->MouseAttributes
.NumberOfButtons
=
771 DeviceExtension
->MouseLogiBuffer
[1];
772 DeviceExtension
->MouseType
= Ps2pp
;
773 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
774 DeviceExtension
->MouseResetState
= ExpectingSetSamplingRateACK
;
775 /* TODO: Go through EnableWheel and Enable5Buttons */
778 DeviceExtension
->MouseResetState
= EnableWheel
;
779 i8042MouResetIsr(DeviceExtension
, Status
, Value
);
782 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
783 DeviceExtension
->MouseResetState
= 1001;
786 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xC8);
787 DeviceExtension
->MouseResetState
++;
791 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
792 DeviceExtension
->MouseResetState
++;
795 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x64);
796 DeviceExtension
->MouseResetState
++;
799 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x50);
800 DeviceExtension
->MouseResetState
++;
803 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF2);
804 DeviceExtension
->MouseResetState
++;
808 DeviceExtension
->MouseResetState
++;
812 /* It's either an Intellimouse or Intellimouse Explorer. */
813 DeviceExtension
->MouseAttributes
.NumberOfButtons
= 3;
814 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
815 WHEELMOUSE_I8042_HARDWARE
;
816 DeviceExtension
->MouseType
= Intellimouse
;
817 DeviceExtension
->MouseResetState
= Enable5Buttons
;
818 i8042MouResetIsr(DeviceExtension
, Status
, Value
);
822 /* Just set the default settings and be done */
823 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
824 DeviceExtension
->MouseResetState
= ExpectingSetSamplingRateACK
;
828 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
829 DeviceExtension
->MouseResetState
= 1021;
833 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
834 DeviceExtension
->MouseResetState
++;
838 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xC8);
839 DeviceExtension
->MouseResetState
++;
842 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x50);
843 DeviceExtension
->MouseResetState
++;
846 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF2);
847 DeviceExtension
->MouseResetState
++;
852 DeviceExtension
->MouseAttributes
.NumberOfButtons
= 5;
853 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
854 WHEELMOUSE_I8042_HARDWARE
;
855 DeviceExtension
->MouseType
= IntellimouseExplorer
;
857 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
858 DeviceExtension
->MouseResetState
= ExpectingSetSamplingRateACK
;
860 case ExpectingSetSamplingRateACK
:
861 DeviceExtension
->MouseHook
.IsrWritePort(
862 DeviceExtension
->MouseHook
.CallContext
,
863 (UCHAR
)DeviceExtension
->MouseAttributes
.SampleRate
);
864 DeviceExtension
->MouseResetState
++;
866 case ExpectingSetSamplingRateValueACK
:
867 if (MOUSE_NACK
== Value
)
869 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x3C);
870 DeviceExtension
->MouseAttributes
.SampleRate
= (USHORT
)PortDeviceExtension
->Settings
.SampleRate
;
871 DeviceExtension
->MouseResetState
= 1040;
874 case 1040: /* Fallthrough */
875 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE8);
876 DeviceExtension
->MouseResetState
= ExpectingFinalResolutionACK
;
878 case ExpectingFinalResolutionACK
:
879 DeviceExtension
->MouseHook
.IsrWritePort(
880 DeviceExtension
->MouseHook
.CallContext
,
881 (UCHAR
)(PortDeviceExtension
->Settings
.MouseResolution
& 0xff));
882 INFO_(I8042PRT
, "Mouse resolution %lu\n",
883 PortDeviceExtension
->Settings
.MouseResolution
);
884 DeviceExtension
->MouseResetState
= ExpectingFinalResolutionValueACK
;
886 case ExpectingFinalResolutionValueACK
:
887 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF4);
888 DeviceExtension
->MouseResetState
= ExpectingEnableACK
;
890 case ExpectingEnableACK
:
891 PortDeviceExtension
->Flags
|= MOUSE_PRESENT
;
892 DeviceExtension
->MouseState
= MouseIdle
;
893 DeviceExtension
->MouseTimeoutState
= TimeoutCancel
;
894 INFO_(I8042PRT
, "Mouse type = %u\n", DeviceExtension
->MouseType
);
897 if (DeviceExtension
->MouseResetState
< 100 || DeviceExtension
->MouseResetState
> 999)
898 ERR_(I8042PRT
, "MouseResetState went out of range: %lu\n", DeviceExtension
->MouseResetState
);
904 i8042MouInterruptService(
905 IN PKINTERRUPT Interrupt
,
908 PI8042_MOUSE_EXTENSION DeviceExtension
;
909 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
911 UCHAR Output
= 0, PortStatus
= 0;
914 UNREFERENCED_PARAMETER(Interrupt
);
916 __analysis_assume(Context
!= NULL
);
917 DeviceExtension
= Context
;
918 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
919 Counter
= PortDeviceExtension
->Settings
.PollStatusIterations
;
923 Status
= i8042ReadStatus(PortDeviceExtension
, &PortStatus
);
924 if (!NT_SUCCESS(Status
))
926 WARN_(I8042PRT
, "i8042ReadStatus() failed with status 0x%08lx\n", Status
);
929 Status
= i8042ReadMouseData(PortDeviceExtension
, &Output
);
930 if (NT_SUCCESS(Status
))
932 KeStallExecutionProcessor(1);
937 WARN_(I8042PRT
, "Spurious i8042 mouse interrupt\n");
941 INFO_(I8042PRT
, "Got: 0x%02x\n", Output
);
943 if (i8042PacketIsr(PortDeviceExtension
, Output
))
945 if (PortDeviceExtension
->PacketComplete
)
947 TRACE_(I8042PRT
, "Packet complete\n");
948 KeInsertQueueDpc(&DeviceExtension
->DpcMouse
, NULL
, NULL
);
950 TRACE_(I8042PRT
, "Irq eaten by packet\n");
954 TRACE_(I8042PRT
, "Irq is mouse input\n");
956 i8042MouInputTestTimeout(DeviceExtension
);
958 if (i8042MouResetIsr(DeviceExtension
, PortStatus
, Output
))
960 TRACE_(I8042PRT
, "Handled by ResetIsr or hooked Isr\n");
961 if (NoChange
!= DeviceExtension
->MouseTimeoutState
) {
962 KeInsertQueueDpc(&DeviceExtension
->DpcMouse
, NULL
, NULL
);
967 if (DeviceExtension
->MouseType
== Ps2pp
)
968 i8042MouHandlePs2pp(DeviceExtension
, Output
);
970 i8042MouHandle(DeviceExtension
, Output
);