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%u!\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 Irp
->IoStatus
.Status
= Status
;
548 if (Status
!= STATUS_PENDING
)
549 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
553 /* Test if packets are taking too long to come in. If they do, we
554 * might have gotten out of sync and should just drop what we have.
556 * If we want to be totally right, we'd also have to keep a count of
557 * errors, and totally reset the mouse after too much of them (can
558 * happen if the user is using a KVM switch and an OS on another port
559 * resets the mouse, or if the user hotplugs the mouse, or if we're just
560 * generally unlucky). Also note the input parsing routine where we
561 * drop invalid input packets.
564 i8042MouInputTestTimeout(
565 IN PI8042_MOUSE_EXTENSION DeviceExtension
)
569 if (DeviceExtension
->MouseState
== MouseExpectingACK
||
570 DeviceExtension
->MouseState
== MouseResetting
)
573 Now
.QuadPart
= KeQueryInterruptTime();
575 if (DeviceExtension
->MouseState
!= MouseIdle
) {
576 /* Check if the last byte came too long ago */
577 if (Now
.QuadPart
- DeviceExtension
->MousePacketStartTime
.QuadPart
>
578 DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseSynchIn100ns
)
580 WARN_(I8042PRT
, "Mouse input packet timeout\n");
581 DeviceExtension
->MouseState
= MouseIdle
;
585 if (DeviceExtension
->MouseState
== MouseIdle
)
586 DeviceExtension
->MousePacketStartTime
.QuadPart
= Now
.QuadPart
;
590 * Call the customization hook. The ToReturn parameter is about wether
591 * we should go on with the interrupt. The return value is what
592 * we should return (indicating to the system wether someone else
593 * should try to handle the interrupt)
597 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
600 OUT PBOOLEAN ToReturn
)
602 BOOLEAN HookReturn
, HookContinue
;
604 HookContinue
= FALSE
;
606 if (DeviceExtension
->MouseHook
.IsrRoutine
)
608 HookReturn
= DeviceExtension
->MouseHook
.IsrRoutine(
609 DeviceExtension
->MouseHook
.Context
,
610 DeviceExtension
->MouseBuffer
+ DeviceExtension
->MouseInBuffer
,
611 &DeviceExtension
->Common
.PortDeviceExtension
->Packet
,
615 &DeviceExtension
->MouseState
,
616 &DeviceExtension
->MouseResetState
);
620 *ToReturn
= HookReturn
;
629 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
633 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
634 BOOLEAN ToReturn
= FALSE
;
636 if (i8042MouCallIsrHook(DeviceExtension
, Status
, Value
, &ToReturn
))
639 if (MouseIdle
== DeviceExtension
->MouseState
)
641 /* Magic packet value that indicates a reset */
644 WARN_(I8042PRT
, "Hot plugged mouse!\n");
645 DeviceExtension
->MouseState
= MouseResetting
;
646 DeviceExtension
->MouseResetState
= ExpectingReset
;
651 else if (MouseResetting
!= DeviceExtension
->MouseState
)
654 DeviceExtension
->MouseTimeoutState
= TimeoutStart
;
655 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
657 switch ((ULONG
)DeviceExtension
->MouseResetState
)
660 if (MOUSE_ACK
== Value
)
662 WARN_(I8042PRT
, "Dropping extra ACK\n");
666 /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok, FC00 if not. */
669 DeviceExtension
->MouseResetState
++;
673 PortDeviceExtension
->Flags
&= ~MOUSE_PRESENT
;
674 DeviceExtension
->MouseState
= MouseIdle
;
675 WARN_(I8042PRT
, "Mouse returned bad reset reply: %x (expected aa)\n", Value
);
678 case ExpectingResetId
:
679 if (MOUSE_ACK
== Value
)
681 WARN_(I8042PRT
, "Dropping extra ACK #2\n");
687 DeviceExtension
->MouseResetState
++;
688 DeviceExtension
->MouseType
= GenericPS2
;
689 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF2);
693 PortDeviceExtension
->Flags
&= ~MOUSE_PRESENT
;
694 DeviceExtension
->MouseState
= MouseIdle
;
695 WARN_(I8042PRT
, "Mouse returned bad reset reply part two: %x (expected 0)\n", Value
);
698 case ExpectingGetDeviceIdACK
:
699 if (MOUSE_ACK
== Value
)
701 DeviceExtension
->MouseResetState
++;
703 else if (MOUSE_NACK
== Value
|| MOUSE_ERROR
== Value
)
705 DeviceExtension
->MouseResetState
++;
706 /* Act as if 00 (normal mouse) was received */
707 WARN_(I8042PRT
, "Mouse doesn't support 0xd2, (returns %x, expected %x), faking\n", Value
, MOUSE_ACK
);
708 i8042MouResetIsr(DeviceExtension
, Status
, 0);
711 case ExpectingGetDeviceIdValue
:
715 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
716 BALLPOINT_I8042_HARDWARE
;
720 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
721 WHEELMOUSE_I8042_HARDWARE
;
724 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
725 MOUSE_I8042_HARDWARE
;
727 DeviceExtension
->MouseResetState
++;
728 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE8);
730 case ExpectingSetResolutionDefaultACK
:
731 DeviceExtension
->MouseResetState
++;
732 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x00);
734 case ExpectingSetResolutionDefaultValueACK
:
735 DeviceExtension
->MouseResetState
= ExpectingSetScaling1to1ACK
;
736 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE6);
738 case ExpectingSetScaling1to1ACK
:
739 case ExpectingSetScaling1to1ACK2
:
740 DeviceExtension
->MouseResetState
++;
741 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE6);
743 case ExpectingSetScaling1to1ACK3
:
744 DeviceExtension
->MouseResetState
++;
745 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE9);
747 case ExpectingReadMouseStatusACK
:
748 DeviceExtension
->MouseResetState
++;
750 case ExpectingReadMouseStatusByte1
:
751 DeviceExtension
->MouseLogiBuffer
[0] = Value
;
752 DeviceExtension
->MouseResetState
++;
754 case ExpectingReadMouseStatusByte2
:
755 DeviceExtension
->MouseLogiBuffer
[1] = Value
;
756 DeviceExtension
->MouseResetState
++;
758 case ExpectingReadMouseStatusByte3
:
759 DeviceExtension
->MouseLogiBuffer
[2] = Value
;
760 /* Now MouseLogiBuffer is a set of info. If the second
761 * byte is 0, the mouse didn't understand the magic
762 * code. Otherwise, it it a Logitech and the second byte
763 * is the number of buttons, bit 7 of the first byte tells
764 * if it understands special E7 commands, the rest is an ID.
766 if (DeviceExtension
->MouseLogiBuffer
[1])
768 DeviceExtension
->MouseAttributes
.NumberOfButtons
=
769 DeviceExtension
->MouseLogiBuffer
[1];
770 DeviceExtension
->MouseType
= Ps2pp
;
771 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
772 DeviceExtension
->MouseResetState
= ExpectingSetSamplingRateACK
;
773 /* TODO: Go through EnableWheel and Enable5Buttons */
776 DeviceExtension
->MouseResetState
= EnableWheel
;
777 i8042MouResetIsr(DeviceExtension
, Status
, Value
);
780 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
781 DeviceExtension
->MouseResetState
= 1001;
784 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xC8);
785 DeviceExtension
->MouseResetState
++;
789 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
790 DeviceExtension
->MouseResetState
++;
793 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x64);
794 DeviceExtension
->MouseResetState
++;
797 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x50);
798 DeviceExtension
->MouseResetState
++;
801 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF2);
802 DeviceExtension
->MouseResetState
++;
806 DeviceExtension
->MouseResetState
++;
810 /* It's either an Intellimouse or Intellimouse Explorer. */
811 DeviceExtension
->MouseAttributes
.NumberOfButtons
= 3;
812 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
813 WHEELMOUSE_I8042_HARDWARE
;
814 DeviceExtension
->MouseType
= Intellimouse
;
815 DeviceExtension
->MouseResetState
= Enable5Buttons
;
816 i8042MouResetIsr(DeviceExtension
, Status
, Value
);
820 /* Just set the default settings and be done */
821 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
822 DeviceExtension
->MouseResetState
= ExpectingSetSamplingRateACK
;
826 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
827 DeviceExtension
->MouseResetState
= 1021;
831 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
832 DeviceExtension
->MouseResetState
++;
836 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xC8);
837 DeviceExtension
->MouseResetState
++;
840 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x50);
841 DeviceExtension
->MouseResetState
++;
844 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF2);
845 DeviceExtension
->MouseResetState
++;
850 DeviceExtension
->MouseAttributes
.NumberOfButtons
= 5;
851 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
852 WHEELMOUSE_I8042_HARDWARE
;
853 DeviceExtension
->MouseType
= IntellimouseExplorer
;
855 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
856 DeviceExtension
->MouseResetState
= ExpectingSetSamplingRateACK
;
858 case ExpectingSetSamplingRateACK
:
859 DeviceExtension
->MouseHook
.IsrWritePort(
860 DeviceExtension
->MouseHook
.CallContext
,
861 (UCHAR
)DeviceExtension
->MouseAttributes
.SampleRate
);
862 DeviceExtension
->MouseResetState
++;
864 case ExpectingSetSamplingRateValueACK
:
865 if (MOUSE_NACK
== Value
)
867 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x3C);
868 DeviceExtension
->MouseAttributes
.SampleRate
= (USHORT
)PortDeviceExtension
->Settings
.SampleRate
;
869 DeviceExtension
->MouseResetState
= 1040;
872 case 1040: /* Fallthrough */
873 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE8);
874 DeviceExtension
->MouseResetState
= ExpectingFinalResolutionACK
;
876 case ExpectingFinalResolutionACK
:
877 DeviceExtension
->MouseHook
.IsrWritePort(
878 DeviceExtension
->MouseHook
.CallContext
,
879 (UCHAR
)(PortDeviceExtension
->Settings
.MouseResolution
& 0xff));
880 INFO_(I8042PRT
, "Mouse resolution %lu\n",
881 PortDeviceExtension
->Settings
.MouseResolution
);
882 DeviceExtension
->MouseResetState
= ExpectingFinalResolutionValueACK
;
884 case ExpectingFinalResolutionValueACK
:
885 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF4);
886 DeviceExtension
->MouseResetState
= ExpectingEnableACK
;
888 case ExpectingEnableACK
:
889 PortDeviceExtension
->Flags
|= MOUSE_PRESENT
;
890 DeviceExtension
->MouseState
= MouseIdle
;
891 DeviceExtension
->MouseTimeoutState
= TimeoutCancel
;
892 INFO_(I8042PRT
, "Mouse type = %u\n", DeviceExtension
->MouseType
);
895 if (DeviceExtension
->MouseResetState
< 100 || DeviceExtension
->MouseResetState
> 999)
896 ERR_(I8042PRT
, "MouseResetState went out of range: %lu\n", DeviceExtension
->MouseResetState
);
902 i8042MouInterruptService(
903 IN PKINTERRUPT Interrupt
,
906 PI8042_MOUSE_EXTENSION DeviceExtension
;
907 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
909 UCHAR Output
= 0, PortStatus
= 0;
912 UNREFERENCED_PARAMETER(Interrupt
);
914 __analysis_assume(Context
!= NULL
);
915 DeviceExtension
= Context
;
916 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
917 Counter
= PortDeviceExtension
->Settings
.PollStatusIterations
;
921 Status
= i8042ReadStatus(PortDeviceExtension
, &PortStatus
);
922 if (!NT_SUCCESS(Status
))
924 WARN_(I8042PRT
, "i8042ReadStatus() failed with status 0x%08lx\n", Status
);
927 Status
= i8042ReadMouseData(PortDeviceExtension
, &Output
);
928 if (NT_SUCCESS(Status
))
930 KeStallExecutionProcessor(1);
935 WARN_(I8042PRT
, "Spurious i8042 mouse interrupt\n");
939 INFO_(I8042PRT
, "Got: 0x%02x\n", Output
);
941 if (i8042PacketIsr(PortDeviceExtension
, Output
))
943 if (PortDeviceExtension
->PacketComplete
)
945 TRACE_(I8042PRT
, "Packet complete\n");
946 KeInsertQueueDpc(&DeviceExtension
->DpcMouse
, NULL
, NULL
);
948 TRACE_(I8042PRT
, "Irq eaten by packet\n");
952 TRACE_(I8042PRT
, "Irq is mouse input\n");
954 i8042MouInputTestTimeout(DeviceExtension
);
956 if (i8042MouResetIsr(DeviceExtension
, PortStatus
, Output
))
958 TRACE_(I8042PRT
, "Handled by ResetIsr or hooked Isr\n");
959 if (NoChange
!= DeviceExtension
->MouseTimeoutState
) {
960 KeInsertQueueDpc(&DeviceExtension
->DpcMouse
, NULL
, NULL
);
965 if (DeviceExtension
->MouseType
== Ps2pp
)
966 i8042MouHandlePs2pp(DeviceExtension
, Output
);
968 i8042MouHandle(DeviceExtension
, Output
);