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 ****************************************************************/
17 /* FUNCTIONS *****************************************************************/
20 * These functions are callbacks for filter driver custom interrupt
28 PI8042_MOUSE_EXTENSION DeviceExtension
;
30 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)Context
;
32 if (DeviceExtension
->MouseHook
.IsrWritePort
!= i8042MouIsrWritePort
)
34 DeviceExtension
->MouseHook
.IsrWritePort(
35 DeviceExtension
->MouseHook
.CallContext
,
39 i8042IsrWritePort(DeviceExtension
->Common
.PortDeviceExtension
, Value
, CTRL_WRITE_MOUSE
);
46 PI8042_MOUSE_EXTENSION DeviceExtension
;
48 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)Context
;
50 DeviceExtension
->MouseComplete
= TRUE
;
51 DeviceExtension
->MouseInBuffer
++;
52 if (DeviceExtension
->MouseInBuffer
> DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseDataQueueSize
)
54 WARN_(I8042PRT
, "Mouse buffer overflow\n");
55 DeviceExtension
->MouseInBuffer
--;
58 TRACE_(I8042PRT
, "Irq completes mouse packet\n");
59 KeInsertQueueDpc(&DeviceExtension
->DpcMouse
, NULL
, NULL
);
64 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
67 PMOUSE_INPUT_DATA MouseInput
;
70 MouseInput
= DeviceExtension
->MouseBuffer
+ DeviceExtension
->MouseInBuffer
;
72 switch (DeviceExtension
->MouseState
)
75 /* This bit should be 1, if not drop the packet, we
76 * might be lucky and get in sync again
79 WARN_(I8042PRT
, "Bad input, dropping..\n");
83 MouseInput
->Buttons
= 0;
84 MouseInput
->RawButtons
= 0;
85 MouseInput
->Flags
= MOUSE_MOVE_RELATIVE
;
87 /* Note how we ignore the overflow bits, like Windows
88 * is said to do. There's no reasonable thing to do
93 MouseInput
->LastX
= 1;
95 MouseInput
->LastX
= 0;
97 MouseInput
->LastY
= 1;
99 MouseInput
->LastY
= 0;
102 MouseInput
->RawButtons
|= MOUSE_LEFT_BUTTON_DOWN
;
104 MouseInput
->RawButtons
|= MOUSE_RIGHT_BUTTON_DOWN
;
106 MouseInput
->RawButtons
|= MOUSE_MIDDLE_BUTTON_DOWN
;
108 DeviceExtension
->MouseState
= XMovement
;
112 if (MouseInput
->LastX
)
113 MouseInput
->LastX
= (LONG
) Output
- 256;
115 MouseInput
->LastX
= Output
;
117 DeviceExtension
->MouseState
= YMovement
;
121 if (MouseInput
->LastY
)
122 MouseInput
->LastY
= (LONG
)Output
- 256;
124 MouseInput
->LastY
= (LONG
)Output
;
126 /* Windows wants it the other way around */
127 MouseInput
->LastY
= -MouseInput
->LastY
;
129 if (DeviceExtension
->MouseType
== GenericPS2
||
130 DeviceExtension
->MouseType
== Ps2pp
)
132 i8042MouHandleButtons(
134 MOUSE_LEFT_BUTTON_DOWN
|
135 MOUSE_RIGHT_BUTTON_DOWN
|
136 MOUSE_MIDDLE_BUTTON_DOWN
);
137 DeviceExtension
->MouseHook
.QueueMousePacket(DeviceExtension
->MouseHook
.CallContext
);
138 DeviceExtension
->MouseState
= MouseIdle
;
142 DeviceExtension
->MouseState
= ZMovement
;
147 Scroll
= Output
& 0x0f;
153 MouseInput
->RawButtons
|= MOUSE_WHEEL
;
154 MouseInput
->ButtonData
= (USHORT
)(Scroll
* -WHEEL_DELTA
);
157 if (DeviceExtension
->MouseType
== IntellimouseExplorer
)
160 MouseInput
->RawButtons
|= MOUSE_BUTTON_4_DOWN
;
162 MouseInput
->RawButtons
|= MOUSE_BUTTON_5_DOWN
;
164 i8042MouHandleButtons(
166 MOUSE_LEFT_BUTTON_DOWN
|
167 MOUSE_RIGHT_BUTTON_DOWN
|
168 MOUSE_MIDDLE_BUTTON_DOWN
|
169 MOUSE_BUTTON_4_DOWN
|
170 MOUSE_BUTTON_5_DOWN
);
171 DeviceExtension
->MouseHook
.QueueMousePacket(DeviceExtension
->MouseHook
.CallContext
);
172 DeviceExtension
->MouseState
= MouseIdle
;
176 ERR_(I8042PRT
, "Unexpected state 0x%u!\n", DeviceExtension
->MouseState
);
182 * Updates ButtonFlags according to RawButtons and a saved state;
183 * Only takes in account the bits that are set in Mask
186 i8042MouHandleButtons(
187 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
190 PMOUSE_INPUT_DATA MouseInput
;
191 USHORT NewButtonData
;
194 MouseInput
= DeviceExtension
->MouseBuffer
+ DeviceExtension
->MouseInBuffer
;
195 NewButtonData
= (USHORT
)(MouseInput
->RawButtons
& Mask
);
196 ButtonDiff
= (NewButtonData
^ DeviceExtension
->MouseButtonState
) & Mask
;
198 /* Note that the defines are such:
199 * MOUSE_LEFT_BUTTON_DOWN 1
200 * MOUSE_LEFT_BUTTON_UP 2
202 MouseInput
->ButtonFlags
|= (NewButtonData
& ButtonDiff
) |
203 (((~(NewButtonData
)) << 1) & (ButtonDiff
<< 1)) |
204 (MouseInput
->RawButtons
& 0xfc00);
206 INFO_(I8042PRT
, "Left raw/up/down: %u/%u/%u\n",
207 MouseInput
->RawButtons
& MOUSE_LEFT_BUTTON_DOWN
,
208 MouseInput
->ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
,
209 MouseInput
->ButtonFlags
& MOUSE_LEFT_BUTTON_UP
);
211 DeviceExtension
->MouseButtonState
=
212 (DeviceExtension
->MouseButtonState
& ~Mask
) | (NewButtonData
& Mask
);
215 /* Does lastest initializations for the mouse. This method
216 * is called just before connecting the interrupt.
220 IN PI8042_MOUSE_EXTENSION DeviceExtension
)
225 /* Enable the PS/2 mouse port */
226 i8042Write(DeviceExtension
->Common
.PortDeviceExtension
, DeviceExtension
->Common
.PortDeviceExtension
->ControlPort
, MOUSE_ENAB
);
228 /* Enable the mouse */
229 if(!i8042IsrWritePort(DeviceExtension
->Common
.PortDeviceExtension
, MOU_ENAB
, CTRL_WRITE_MOUSE
))
231 WARN_(I8042PRT
, "Failed to enable mouse!\n");
232 return STATUS_IO_DEVICE_ERROR
;
235 Status
= i8042ReadDataWait(DeviceExtension
->Common
.PortDeviceExtension
, &Value
);
236 if (!NT_SUCCESS(Status
))
238 WARN_(I8042PRT
, "Failed to read the response of MOU_ENAB, status 0x%08lx\n", Status
);
242 if(Value
== MOUSE_ACK
)
244 INFO_(I8042PRT
, "Mouse was enabled successfully!\n");
245 return STATUS_SUCCESS
;
248 WARN_(I8042PRT
, "Got 0x%02x instead of 0xFA\n", Value
);
249 return STATUS_IO_DEVICE_ERROR
;
255 IN PVOID DeferredContext
,
256 IN PVOID SystemArgument1
,
257 IN PVOID SystemArgument2
)
259 PI8042_MOUSE_EXTENSION DeviceExtension
;
260 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
261 ULONG MouseTransferred
= 0;
262 ULONG MouseInBufferCopy
;
264 LARGE_INTEGER Timeout
;
266 UNREFERENCED_PARAMETER(Dpc
);
267 UNREFERENCED_PARAMETER(SystemArgument1
);
268 UNREFERENCED_PARAMETER(SystemArgument2
);
270 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)DeferredContext
;
271 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
273 switch (DeviceExtension
->MouseTimeoutState
)
277 DeviceExtension
->MouseTimeoutState
= NoChange
;
278 if (DeviceExtension
->MouseTimeoutActive
&&
279 !KeCancelTimer(&DeviceExtension
->TimerMouseTimeout
))
281 /* The timer fired already, give up */
282 DeviceExtension
->MouseTimeoutActive
= FALSE
;
286 Timeout
.QuadPart
= -15000000; /* 1.5 seconds, should be enough */
289 &DeviceExtension
->TimerMouseTimeout
,
291 &DeviceExtension
->DpcMouseTimeout
);
292 DeviceExtension
->MouseTimeoutActive
= TRUE
;
298 DeviceExtension
->MouseTimeoutState
= NoChange
;
299 KeCancelTimer(&DeviceExtension
->TimerMouseTimeout
);
300 DeviceExtension
->MouseTimeoutActive
= FALSE
;
304 ;/* nothing, don't want a warning */
307 /* Should be unlikely */
308 if (!DeviceExtension
->MouseComplete
)
311 Irql
= KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
313 DeviceExtension
->MouseComplete
= FALSE
;
314 MouseInBufferCopy
= DeviceExtension
->MouseInBuffer
;
316 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
318 TRACE_(I8042PRT
, "Send a mouse packet\n");
320 if (!DeviceExtension
->MouseData
.ClassService
)
323 INFO_(I8042PRT
, "Sending %lu mouse move(s)\n", MouseInBufferCopy
);
324 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->MouseData
.ClassService
)(
325 DeviceExtension
->MouseData
.ClassDeviceObject
,
326 DeviceExtension
->MouseBuffer
,
327 DeviceExtension
->MouseBuffer
+ MouseInBufferCopy
,
330 Irql
= KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
331 DeviceExtension
->MouseInBuffer
-= MouseTransferred
;
332 if (DeviceExtension
->MouseInBuffer
)
334 DeviceExtension
->MouseBuffer
,
335 DeviceExtension
->MouseBuffer
+ MouseTransferred
,
336 DeviceExtension
->MouseInBuffer
* sizeof(MOUSE_INPUT_DATA
));
337 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
340 /* This timer DPC will be called when the mouse reset times out.
341 * I'll just send the 'disable mouse port' command to the controller
342 * and say the mouse doesn't exist.
345 i8042DpcRoutineMouseTimeout(
347 IN PVOID DeferredContext
,
348 IN PVOID SystemArgument1
,
349 IN PVOID SystemArgument2
)
351 PI8042_MOUSE_EXTENSION DeviceExtension
;
352 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
355 UNREFERENCED_PARAMETER(Dpc
);
356 UNREFERENCED_PARAMETER(SystemArgument1
);
357 UNREFERENCED_PARAMETER(SystemArgument2
);
359 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)DeferredContext
;
360 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
362 Irql
= KeAcquireInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
);
364 WARN_(I8042PRT
, "Mouse initialization timeout! (substate %x). Disabling mouse.\n",
365 DeviceExtension
->MouseResetState
);
367 i8042Flush(PortDeviceExtension
);
368 i8042ChangeMode(PortDeviceExtension
, CCB_MOUSE_INT_ENAB
, CCB_MOUSE_DISAB
);
369 i8042Flush(PortDeviceExtension
);
371 PortDeviceExtension
->Flags
&= ~MOUSE_PRESENT
;
373 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
377 * Runs the mouse IOCTL_INTERNAL dispatch.
380 i8042MouInternalDeviceControl(
381 IN PDEVICE_OBJECT DeviceObject
,
384 PIO_STACK_LOCATION Stack
;
385 PI8042_MOUSE_EXTENSION DeviceExtension
;
388 Stack
= IoGetCurrentIrpStackLocation(Irp
);
389 Irp
->IoStatus
.Information
= 0;
390 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)DeviceObject
->DeviceExtension
;
392 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
394 case IOCTL_INTERNAL_MOUSE_CONNECT
:
397 PIO_WORKITEM WorkItem
= NULL
;
398 PI8042_HOOK_WORKITEM WorkItemData
= NULL
;
400 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_CONNECT\n");
401 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(CONNECT_DATA
))
403 Status
= STATUS_INVALID_PARAMETER
;
407 DeviceExtension
->MouseData
=
408 *((PCONNECT_DATA
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
);
410 /* Send IOCTL_INTERNAL_I8042_HOOK_MOUSE to device stack */
411 WorkItem
= IoAllocateWorkItem(DeviceObject
);
414 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
415 Status
= STATUS_INSUFFICIENT_RESOURCES
;
418 WorkItemData
= ExAllocatePoolWithTag(
420 sizeof(I8042_HOOK_WORKITEM
),
424 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
425 Status
= STATUS_NO_MEMORY
;
428 WorkItemData
->WorkItem
= WorkItem
;
429 WorkItemData
->Irp
= Irp
;
431 /* Initialize extension */
432 DeviceExtension
->Common
.Type
= Mouse
;
433 Size
= DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseDataQueueSize
* sizeof(MOUSE_INPUT_DATA
);
434 DeviceExtension
->MouseBuffer
= ExAllocatePoolWithTag(
438 if (!DeviceExtension
->MouseBuffer
)
440 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
441 Status
= STATUS_NO_MEMORY
;
444 RtlZeroMemory(DeviceExtension
->MouseBuffer
, Size
);
445 DeviceExtension
->MouseAttributes
.InputDataQueueLength
=
446 DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseDataQueueSize
;
448 &DeviceExtension
->DpcMouse
,
452 &DeviceExtension
->DpcMouseTimeout
,
453 i8042DpcRoutineMouseTimeout
,
455 KeInitializeTimer(&DeviceExtension
->TimerMouseTimeout
);
456 DeviceExtension
->Common
.PortDeviceExtension
->MouseExtension
= DeviceExtension
;
457 DeviceExtension
->Common
.PortDeviceExtension
->Flags
|= MOUSE_CONNECTED
;
459 IoMarkIrpPending(Irp
);
460 DeviceExtension
->MouseState
= MouseResetting
;
461 DeviceExtension
->MouseResetState
= 1100;
462 DeviceExtension
->MouseHook
.IsrWritePort
= i8042MouIsrWritePort
;
463 DeviceExtension
->MouseHook
.QueueMousePacket
= i8042MouQueuePacket
;
464 DeviceExtension
->MouseHook
.CallContext
= DeviceExtension
;
465 IoQueueWorkItem(WorkItem
,
466 i8042SendHookWorkItem
,
469 Status
= STATUS_PENDING
;
473 if (DeviceExtension
->MouseBuffer
)
474 ExFreePoolWithTag(DeviceExtension
->MouseBuffer
, I8042PRT_TAG
);
476 IoFreeWorkItem(WorkItem
);
478 ExFreePoolWithTag(WorkItemData
, I8042PRT_TAG
);
481 case IOCTL_INTERNAL_MOUSE_DISCONNECT
:
483 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_DISCONNECT\n");
484 /* MSDN says that operation is to implemented.
485 * To implement it, we just have to do:
486 * DeviceExtension->MouseData.ClassService = NULL;
488 Status
= STATUS_NOT_IMPLEMENTED
;
491 case IOCTL_INTERNAL_I8042_HOOK_MOUSE
:
493 PINTERNAL_I8042_HOOK_MOUSE MouseHook
;
494 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_MOUSE\n");
495 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(CONNECT_DATA
))
497 Status
= STATUS_INVALID_PARAMETER
;
500 MouseHook
= (PINTERNAL_I8042_HOOK_MOUSE
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
502 DeviceExtension
->MouseHook
.Context
= MouseHook
->Context
;
503 if (MouseHook
->IsrRoutine
)
504 DeviceExtension
->MouseHook
.IsrRoutine
= MouseHook
->IsrRoutine
;
506 Status
= STATUS_SUCCESS
;
509 case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER
:
511 DPRINT1("IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER not implemented\n");
512 Status
= STATUS_NOT_IMPLEMENTED
;
515 case IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION
:
517 DPRINT1("IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION not implemented\n");
518 Status
= STATUS_NOT_IMPLEMENTED
;
521 case IOCTL_MOUSE_QUERY_ATTRIBUTES
:
523 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_MOUSE_QUERY_ATTRIBUTES\n");
524 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUSE_ATTRIBUTES
))
526 Status
= STATUS_BUFFER_TOO_SMALL
;
530 *(PMOUSE_ATTRIBUTES
) Irp
->AssociatedIrp
.SystemBuffer
= DeviceExtension
->MouseAttributes
;
531 Irp
->IoStatus
.Information
= sizeof(MOUSE_ATTRIBUTES
);
532 Status
= STATUS_SUCCESS
;
537 ERR_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
538 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
540 return ForwardIrpAndForget(DeviceObject
, Irp
);
544 Irp
->IoStatus
.Status
= Status
;
545 if (Status
!= STATUS_PENDING
)
546 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
550 /* Test if packets are taking too long to come in. If they do, we
551 * might have gotten out of sync and should just drop what we have.
553 * If we want to be totally right, we'd also have to keep a count of
554 * errors, and totally reset the mouse after too much of them (can
555 * happen if the user is using a KVM switch and an OS on another port
556 * resets the mouse, or if the user hotplugs the mouse, or if we're just
557 * generally unlucky). Also note the input parsing routine where we
558 * drop invalid input packets.
561 i8042MouInputTestTimeout(
562 IN PI8042_MOUSE_EXTENSION DeviceExtension
)
566 if (DeviceExtension
->MouseState
== MouseExpectingACK
||
567 DeviceExtension
->MouseState
== MouseResetting
)
570 Now
.QuadPart
= KeQueryInterruptTime();
572 if (DeviceExtension
->MouseState
!= MouseIdle
) {
573 /* Check if the last byte came too long ago */
574 if (Now
.QuadPart
- DeviceExtension
->MousePacketStartTime
.QuadPart
>
575 DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseSynchIn100ns
)
577 WARN_(I8042PRT
, "Mouse input packet timeout\n");
578 DeviceExtension
->MouseState
= MouseIdle
;
582 if (DeviceExtension
->MouseState
== MouseIdle
)
583 DeviceExtension
->MousePacketStartTime
.QuadPart
= Now
.QuadPart
;
587 * Call the customization hook. The ToReturn parameter is about wether
588 * we should go on with the interrupt. The return value is what
589 * we should return (indicating to the system wether someone else
590 * should try to handle the interrupt)
594 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
597 OUT PBOOLEAN ToReturn
)
599 BOOLEAN HookReturn
, HookContinue
;
601 HookContinue
= FALSE
;
603 if (DeviceExtension
->MouseHook
.IsrRoutine
)
605 HookReturn
= DeviceExtension
->MouseHook
.IsrRoutine(
606 DeviceExtension
->MouseHook
.Context
,
607 DeviceExtension
->MouseBuffer
+ DeviceExtension
->MouseInBuffer
,
608 &DeviceExtension
->Common
.PortDeviceExtension
->Packet
,
612 &DeviceExtension
->MouseState
,
613 &DeviceExtension
->MouseResetState
);
617 *ToReturn
= HookReturn
;
626 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
630 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
631 BOOLEAN ToReturn
= FALSE
;
633 if (i8042MouCallIsrHook(DeviceExtension
, Status
, Value
, &ToReturn
))
636 if (MouseResetting
!= DeviceExtension
->MouseState
)
638 DeviceExtension
->MouseTimeoutState
= TimeoutStart
;
639 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
641 switch ((ULONG
)DeviceExtension
->MouseResetState
)
643 case 1100: /* the first ack, drop it. */
644 DeviceExtension
->MouseResetState
= ExpectingReset
;
647 /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok, FC00 if not. */
650 DeviceExtension
->MouseResetState
++;
654 PortDeviceExtension
->Flags
&= ~MOUSE_PRESENT
;
655 DeviceExtension
->MouseState
= MouseIdle
;
656 WARN_(I8042PRT
, "Mouse returned bad reset reply: %x (expected aa)\n", Value
);
659 case ExpectingResetId
:
662 DeviceExtension
->MouseResetState
++;
663 DeviceExtension
->MouseType
= GenericPS2
;
664 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF2);
668 PortDeviceExtension
->Flags
&= ~MOUSE_PRESENT
;
669 DeviceExtension
->MouseState
= MouseIdle
;
670 WARN_(I8042PRT
, "Mouse returned bad reset reply part two: %x (expected 0)\n", Value
);
673 case ExpectingGetDeviceIdACK
:
674 if (MOUSE_ACK
== Value
)
676 DeviceExtension
->MouseResetState
++;
678 else if (MOUSE_NACK
== Value
|| MOUSE_ERROR
== Value
)
680 DeviceExtension
->MouseResetState
++;
681 /* Act as if 00 (normal mouse) was received */
682 WARN_(I8042PRT
, "Mouse doesn't support 0xd2, (returns %x, expected %x), faking\n", Value
, MOUSE_ACK
);
683 i8042MouResetIsr(DeviceExtension
, Status
, 0);
686 case ExpectingGetDeviceIdValue
:
690 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
691 BALLPOINT_I8042_HARDWARE
;
695 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
696 WHEELMOUSE_I8042_HARDWARE
;
699 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
700 MOUSE_I8042_HARDWARE
;
702 DeviceExtension
->MouseResetState
++;
703 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE8);
705 case ExpectingSetResolutionDefaultACK
:
706 DeviceExtension
->MouseResetState
++;
707 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x00);
709 case ExpectingSetResolutionDefaultValueACK
:
710 DeviceExtension
->MouseResetState
= ExpectingSetScaling1to1ACK
;
711 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE6);
713 case ExpectingSetScaling1to1ACK
:
714 case ExpectingSetScaling1to1ACK2
:
715 DeviceExtension
->MouseResetState
++;
716 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE6);
718 case ExpectingSetScaling1to1ACK3
:
719 DeviceExtension
->MouseResetState
++;
720 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE9);
722 case ExpectingReadMouseStatusACK
:
723 DeviceExtension
->MouseResetState
++;
725 case ExpectingReadMouseStatusByte1
:
726 DeviceExtension
->MouseLogiBuffer
[0] = Value
;
727 DeviceExtension
->MouseResetState
++;
729 case ExpectingReadMouseStatusByte2
:
730 DeviceExtension
->MouseLogiBuffer
[1] = Value
;
731 DeviceExtension
->MouseResetState
++;
733 case ExpectingReadMouseStatusByte3
:
734 DeviceExtension
->MouseLogiBuffer
[2] = Value
;
735 /* Now MouseLogiBuffer is a set of info. If the second
736 * byte is 0, the mouse didn't understand the magic
737 * code. Otherwise, it it a Logitech and the second byte
738 * is the number of buttons, bit 7 of the first byte tells
739 * if it understands special E7 commands, the rest is an ID.
741 if (DeviceExtension
->MouseLogiBuffer
[1])
743 DeviceExtension
->MouseAttributes
.NumberOfButtons
=
744 DeviceExtension
->MouseLogiBuffer
[1];
745 DeviceExtension
->MouseType
= Ps2pp
;
746 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
747 DeviceExtension
->MouseResetState
= ExpectingSetSamplingRateACK
;
748 /* TODO: Go through EnableWheel and Enable5Buttons */
751 DeviceExtension
->MouseResetState
= EnableWheel
;
752 i8042MouResetIsr(DeviceExtension
, Status
, Value
);
755 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
756 DeviceExtension
->MouseResetState
= 1001;
759 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xC8);
760 DeviceExtension
->MouseResetState
++;
764 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
765 DeviceExtension
->MouseResetState
++;
768 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x64);
769 DeviceExtension
->MouseResetState
++;
772 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x50);
773 DeviceExtension
->MouseResetState
++;
776 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF2);
777 DeviceExtension
->MouseResetState
++;
781 DeviceExtension
->MouseResetState
++;
785 /* It's either an Intellimouse or Intellimouse Explorer. */
786 DeviceExtension
->MouseAttributes
.NumberOfButtons
= 3;
787 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
788 WHEELMOUSE_I8042_HARDWARE
;
789 DeviceExtension
->MouseType
= Intellimouse
;
790 DeviceExtension
->MouseResetState
= Enable5Buttons
;
791 i8042MouResetIsr(DeviceExtension
, Status
, Value
);
795 /* Just set the default settings and be done */
796 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
797 DeviceExtension
->MouseResetState
= ExpectingSetSamplingRateACK
;
801 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
802 DeviceExtension
->MouseResetState
= 1021;
806 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
807 DeviceExtension
->MouseResetState
++;
811 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xC8);
812 DeviceExtension
->MouseResetState
++;
815 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x50);
816 DeviceExtension
->MouseResetState
++;
819 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF2);
820 DeviceExtension
->MouseResetState
++;
825 DeviceExtension
->MouseAttributes
.NumberOfButtons
= 5;
826 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
827 WHEELMOUSE_I8042_HARDWARE
;
828 DeviceExtension
->MouseType
= IntellimouseExplorer
;
830 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
831 DeviceExtension
->MouseResetState
= ExpectingSetSamplingRateACK
;
833 case ExpectingSetSamplingRateACK
:
834 DeviceExtension
->MouseHook
.IsrWritePort(
835 DeviceExtension
->MouseHook
.CallContext
,
836 (UCHAR
)DeviceExtension
->MouseAttributes
.SampleRate
);
837 DeviceExtension
->MouseResetState
++;
839 case ExpectingSetSamplingRateValueACK
:
840 if (MOUSE_NACK
== Value
)
842 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x3C);
843 DeviceExtension
->MouseAttributes
.SampleRate
= (USHORT
)PortDeviceExtension
->Settings
.SampleRate
;
844 DeviceExtension
->MouseResetState
= 1040;
847 case 1040: /* Fallthrough */
848 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE8);
849 DeviceExtension
->MouseResetState
= ExpectingFinalResolutionACK
;
851 case ExpectingFinalResolutionACK
:
852 DeviceExtension
->MouseHook
.IsrWritePort(
853 DeviceExtension
->MouseHook
.CallContext
,
854 (UCHAR
)(PortDeviceExtension
->Settings
.MouseResolution
& 0xff));
855 INFO_(I8042PRT
, "Mouse resolution %lu\n",
856 PortDeviceExtension
->Settings
.MouseResolution
);
857 DeviceExtension
->MouseResetState
= ExpectingFinalResolutionValueACK
;
859 case ExpectingFinalResolutionValueACK
:
860 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF4);
861 DeviceExtension
->MouseResetState
= ExpectingEnableACK
;
863 case ExpectingEnableACK
:
864 DeviceExtension
->MouseState
= MouseIdle
;
865 DeviceExtension
->MouseTimeoutState
= TimeoutCancel
;
866 INFO_(I8042PRT
, "Mouse type = %u\n", DeviceExtension
->MouseType
);
869 if (DeviceExtension
->MouseResetState
< 100 || DeviceExtension
->MouseResetState
> 999)
870 ERR_(I8042PRT
, "MouseResetState went out of range: %lu\n", DeviceExtension
->MouseResetState
);
876 i8042MouInterruptService(
877 IN PKINTERRUPT Interrupt
,
880 PI8042_MOUSE_EXTENSION DeviceExtension
;
881 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
883 UCHAR Output
= 0, PortStatus
= 0;
886 UNREFERENCED_PARAMETER(Interrupt
);
888 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)Context
;
889 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
890 Counter
= PortDeviceExtension
->Settings
.PollStatusIterations
;
894 Status
= i8042ReadStatus(PortDeviceExtension
, &PortStatus
);
895 if (!NT_SUCCESS(Status
))
897 WARN_(I8042PRT
, "i8042ReadStatus() failed with status 0x%08lx\n", Status
);
900 Status
= i8042ReadMouseData(PortDeviceExtension
, &Output
);
901 if (NT_SUCCESS(Status
))
903 KeStallExecutionProcessor(1);
908 WARN_(I8042PRT
, "Spurious i8042 mouse interrupt\n");
912 INFO_(I8042PRT
, "Got: 0x%02x\n", Output
);
914 if (i8042PacketIsr(PortDeviceExtension
, Output
))
916 if (PortDeviceExtension
->PacketComplete
)
918 TRACE_(I8042PRT
, "Packet complete\n");
919 KeInsertQueueDpc(&DeviceExtension
->DpcMouse
, NULL
, NULL
);
921 TRACE_(I8042PRT
, "Irq eaten by packet\n");
925 TRACE_(I8042PRT
, "Irq is mouse input\n");
927 i8042MouInputTestTimeout(DeviceExtension
);
929 if (i8042MouResetIsr(DeviceExtension
, PortStatus
, Output
))
931 TRACE_(I8042PRT
, "Handled by ResetIsr or hooked Isr\n");
932 if (NoChange
!= DeviceExtension
->MouseTimeoutState
) {
933 KeInsertQueueDpc(&DeviceExtension
->DpcMouse
, NULL
, NULL
);
938 if (DeviceExtension
->MouseType
== Ps2pp
)
939 i8042MouHandlePs2pp(DeviceExtension
, Output
);
941 i8042MouHandle(DeviceExtension
, Output
);