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)\n",
365 DeviceExtension
->MouseResetState
);
367 PortDeviceExtension
->Flags
&= ~MOUSE_PRESENT
;
369 KeReleaseInterruptSpinLock(PortDeviceExtension
->HighestDIRQLInterrupt
, Irql
);
373 * Runs the mouse IOCTL_INTERNAL dispatch.
376 i8042MouInternalDeviceControl(
377 IN PDEVICE_OBJECT DeviceObject
,
380 PIO_STACK_LOCATION Stack
;
381 PI8042_MOUSE_EXTENSION DeviceExtension
;
384 Stack
= IoGetCurrentIrpStackLocation(Irp
);
385 Irp
->IoStatus
.Information
= 0;
386 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)DeviceObject
->DeviceExtension
;
388 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
390 case IOCTL_INTERNAL_MOUSE_CONNECT
:
393 PIO_WORKITEM WorkItem
= NULL
;
394 PI8042_HOOK_WORKITEM WorkItemData
= NULL
;
396 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_CONNECT\n");
397 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(CONNECT_DATA
))
399 Status
= STATUS_INVALID_PARAMETER
;
403 DeviceExtension
->MouseData
=
404 *((PCONNECT_DATA
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
);
406 /* Send IOCTL_INTERNAL_I8042_HOOK_MOUSE to device stack */
407 WorkItem
= IoAllocateWorkItem(DeviceObject
);
410 WARN_(I8042PRT
, "IoAllocateWorkItem() failed\n");
411 Status
= STATUS_INSUFFICIENT_RESOURCES
;
414 WorkItemData
= ExAllocatePoolWithTag(
416 sizeof(I8042_HOOK_WORKITEM
),
420 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
421 Status
= STATUS_NO_MEMORY
;
424 WorkItemData
->WorkItem
= WorkItem
;
425 WorkItemData
->Irp
= Irp
;
427 /* Initialize extension */
428 DeviceExtension
->Common
.Type
= Mouse
;
429 Size
= DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseDataQueueSize
* sizeof(MOUSE_INPUT_DATA
);
430 DeviceExtension
->MouseBuffer
= ExAllocatePoolWithTag(
434 if (!DeviceExtension
->MouseBuffer
)
436 WARN_(I8042PRT
, "ExAllocatePoolWithTag() failed\n");
437 Status
= STATUS_NO_MEMORY
;
440 RtlZeroMemory(DeviceExtension
->MouseBuffer
, Size
);
441 DeviceExtension
->MouseAttributes
.InputDataQueueLength
=
442 DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseDataQueueSize
;
444 &DeviceExtension
->DpcMouse
,
448 &DeviceExtension
->DpcMouseTimeout
,
449 i8042DpcRoutineMouseTimeout
,
451 KeInitializeTimer(&DeviceExtension
->TimerMouseTimeout
);
452 DeviceExtension
->Common
.PortDeviceExtension
->MouseExtension
= DeviceExtension
;
453 DeviceExtension
->Common
.PortDeviceExtension
->Flags
|= MOUSE_CONNECTED
;
455 IoMarkIrpPending(Irp
);
456 DeviceExtension
->MouseState
= MouseResetting
;
457 DeviceExtension
->MouseResetState
= ExpectingReset
;
458 DeviceExtension
->MouseHook
.IsrWritePort
= i8042MouIsrWritePort
;
459 DeviceExtension
->MouseHook
.QueueMousePacket
= i8042MouQueuePacket
;
460 DeviceExtension
->MouseHook
.CallContext
= DeviceExtension
;
461 IoQueueWorkItem(WorkItem
,
462 i8042SendHookWorkItem
,
465 Status
= STATUS_PENDING
;
469 if (DeviceExtension
->MouseBuffer
)
470 ExFreePoolWithTag(DeviceExtension
->MouseBuffer
, I8042PRT_TAG
);
472 IoFreeWorkItem(WorkItem
);
474 ExFreePoolWithTag(WorkItemData
, I8042PRT_TAG
);
477 case IOCTL_INTERNAL_MOUSE_DISCONNECT
:
479 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_DISCONNECT\n");
480 /* MSDN says that operation is to implemented.
481 * To implement it, we just have to do:
482 * DeviceExtension->MouseData.ClassService = NULL;
484 Status
= STATUS_NOT_IMPLEMENTED
;
487 case IOCTL_INTERNAL_I8042_HOOK_MOUSE
:
489 PINTERNAL_I8042_HOOK_MOUSE MouseHook
;
490 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_MOUSE\n");
491 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(INTERNAL_I8042_HOOK_MOUSE
))
493 Status
= STATUS_INVALID_PARAMETER
;
496 MouseHook
= (PINTERNAL_I8042_HOOK_MOUSE
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
498 DeviceExtension
->MouseHook
.Context
= MouseHook
->Context
;
499 if (MouseHook
->IsrRoutine
)
500 DeviceExtension
->MouseHook
.IsrRoutine
= MouseHook
->IsrRoutine
;
502 Status
= STATUS_SUCCESS
;
505 case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER
:
507 DPRINT1("IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER not implemented\n");
508 Status
= STATUS_NOT_IMPLEMENTED
;
511 case IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION
:
513 DPRINT1("IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION not implemented\n");
514 Status
= STATUS_NOT_IMPLEMENTED
;
517 case IOCTL_MOUSE_QUERY_ATTRIBUTES
:
519 TRACE_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_MOUSE_QUERY_ATTRIBUTES\n");
520 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUSE_ATTRIBUTES
))
522 Status
= STATUS_BUFFER_TOO_SMALL
;
526 *(PMOUSE_ATTRIBUTES
) Irp
->AssociatedIrp
.SystemBuffer
= DeviceExtension
->MouseAttributes
;
527 Irp
->IoStatus
.Information
= sizeof(MOUSE_ATTRIBUTES
);
528 Status
= STATUS_SUCCESS
;
533 ERR_(I8042PRT
, "IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
534 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
536 return ForwardIrpAndForget(DeviceObject
, Irp
);
540 Irp
->IoStatus
.Status
= Status
;
541 if (Status
!= STATUS_PENDING
)
542 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
546 /* Test if packets are taking too long to come in. If they do, we
547 * might have gotten out of sync and should just drop what we have.
549 * If we want to be totally right, we'd also have to keep a count of
550 * errors, and totally reset the mouse after too much of them (can
551 * happen if the user is using a KVM switch and an OS on another port
552 * resets the mouse, or if the user hotplugs the mouse, or if we're just
553 * generally unlucky). Also note the input parsing routine where we
554 * drop invalid input packets.
557 i8042MouInputTestTimeout(
558 IN PI8042_MOUSE_EXTENSION DeviceExtension
)
562 if (DeviceExtension
->MouseState
== MouseExpectingACK
||
563 DeviceExtension
->MouseState
== MouseResetting
)
566 Now
.QuadPart
= KeQueryInterruptTime();
568 if (DeviceExtension
->MouseState
!= MouseIdle
) {
569 /* Check if the last byte came too long ago */
570 if (Now
.QuadPart
- DeviceExtension
->MousePacketStartTime
.QuadPart
>
571 DeviceExtension
->Common
.PortDeviceExtension
->Settings
.MouseSynchIn100ns
)
573 WARN_(I8042PRT
, "Mouse input packet timeout\n");
574 DeviceExtension
->MouseState
= MouseIdle
;
578 if (DeviceExtension
->MouseState
== MouseIdle
)
579 DeviceExtension
->MousePacketStartTime
.QuadPart
= Now
.QuadPart
;
583 * Call the customization hook. The ToReturn parameter is about wether
584 * we should go on with the interrupt. The return value is what
585 * we should return (indicating to the system wether someone else
586 * should try to handle the interrupt)
590 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
593 OUT PBOOLEAN ToReturn
)
595 BOOLEAN HookReturn
, HookContinue
;
597 HookContinue
= FALSE
;
599 if (DeviceExtension
->MouseHook
.IsrRoutine
)
601 HookReturn
= DeviceExtension
->MouseHook
.IsrRoutine(
602 DeviceExtension
->MouseHook
.Context
,
603 DeviceExtension
->MouseBuffer
+ DeviceExtension
->MouseInBuffer
,
604 &DeviceExtension
->Common
.PortDeviceExtension
->Packet
,
608 &DeviceExtension
->MouseState
,
609 &DeviceExtension
->MouseResetState
);
613 *ToReturn
= HookReturn
;
622 IN PI8042_MOUSE_EXTENSION DeviceExtension
,
626 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
627 BOOLEAN ToReturn
= FALSE
;
629 if (i8042MouCallIsrHook(DeviceExtension
, Status
, Value
, &ToReturn
))
632 if (MouseIdle
== DeviceExtension
->MouseState
)
634 /* Magic packet value that indicates a reset */
637 WARN_(I8042PRT
, "Hot plugged mouse!\n");
638 DeviceExtension
->MouseState
= MouseResetting
;
639 DeviceExtension
->MouseResetState
= ExpectingReset
;
644 else if (MouseResetting
!= DeviceExtension
->MouseState
)
647 DeviceExtension
->MouseTimeoutState
= TimeoutStart
;
648 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
650 switch ((ULONG
)DeviceExtension
->MouseResetState
)
653 if (MOUSE_ACK
== Value
)
655 WARN_(I8042PRT
, "Dropping extra ACK\n");
659 /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok, FC00 if not. */
662 DeviceExtension
->MouseResetState
++;
666 PortDeviceExtension
->Flags
&= ~MOUSE_PRESENT
;
667 DeviceExtension
->MouseState
= MouseIdle
;
668 WARN_(I8042PRT
, "Mouse returned bad reset reply: %x (expected aa)\n", Value
);
671 case ExpectingResetId
:
672 if (MOUSE_ACK
== Value
)
674 WARN_(I8042PRT
, "Dropping extra ACK #2\n");
680 DeviceExtension
->MouseResetState
++;
681 DeviceExtension
->MouseType
= GenericPS2
;
682 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF2);
686 PortDeviceExtension
->Flags
&= ~MOUSE_PRESENT
;
687 DeviceExtension
->MouseState
= MouseIdle
;
688 WARN_(I8042PRT
, "Mouse returned bad reset reply part two: %x (expected 0)\n", Value
);
691 case ExpectingGetDeviceIdACK
:
692 if (MOUSE_ACK
== Value
)
694 DeviceExtension
->MouseResetState
++;
696 else if (MOUSE_NACK
== Value
|| MOUSE_ERROR
== Value
)
698 DeviceExtension
->MouseResetState
++;
699 /* Act as if 00 (normal mouse) was received */
700 WARN_(I8042PRT
, "Mouse doesn't support 0xd2, (returns %x, expected %x), faking\n", Value
, MOUSE_ACK
);
701 i8042MouResetIsr(DeviceExtension
, Status
, 0);
704 case ExpectingGetDeviceIdValue
:
708 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
709 BALLPOINT_I8042_HARDWARE
;
713 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
714 WHEELMOUSE_I8042_HARDWARE
;
717 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
718 MOUSE_I8042_HARDWARE
;
720 DeviceExtension
->MouseResetState
++;
721 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE8);
723 case ExpectingSetResolutionDefaultACK
:
724 DeviceExtension
->MouseResetState
++;
725 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x00);
727 case ExpectingSetResolutionDefaultValueACK
:
728 DeviceExtension
->MouseResetState
= ExpectingSetScaling1to1ACK
;
729 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE6);
731 case ExpectingSetScaling1to1ACK
:
732 case ExpectingSetScaling1to1ACK2
:
733 DeviceExtension
->MouseResetState
++;
734 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE6);
736 case ExpectingSetScaling1to1ACK3
:
737 DeviceExtension
->MouseResetState
++;
738 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE9);
740 case ExpectingReadMouseStatusACK
:
741 DeviceExtension
->MouseResetState
++;
743 case ExpectingReadMouseStatusByte1
:
744 DeviceExtension
->MouseLogiBuffer
[0] = Value
;
745 DeviceExtension
->MouseResetState
++;
747 case ExpectingReadMouseStatusByte2
:
748 DeviceExtension
->MouseLogiBuffer
[1] = Value
;
749 DeviceExtension
->MouseResetState
++;
751 case ExpectingReadMouseStatusByte3
:
752 DeviceExtension
->MouseLogiBuffer
[2] = Value
;
753 /* Now MouseLogiBuffer is a set of info. If the second
754 * byte is 0, the mouse didn't understand the magic
755 * code. Otherwise, it it a Logitech and the second byte
756 * is the number of buttons, bit 7 of the first byte tells
757 * if it understands special E7 commands, the rest is an ID.
759 if (DeviceExtension
->MouseLogiBuffer
[1])
761 DeviceExtension
->MouseAttributes
.NumberOfButtons
=
762 DeviceExtension
->MouseLogiBuffer
[1];
763 DeviceExtension
->MouseType
= Ps2pp
;
764 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
765 DeviceExtension
->MouseResetState
= ExpectingSetSamplingRateACK
;
766 /* TODO: Go through EnableWheel and Enable5Buttons */
769 DeviceExtension
->MouseResetState
= EnableWheel
;
770 i8042MouResetIsr(DeviceExtension
, Status
, Value
);
773 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
774 DeviceExtension
->MouseResetState
= 1001;
777 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xC8);
778 DeviceExtension
->MouseResetState
++;
782 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
783 DeviceExtension
->MouseResetState
++;
786 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x64);
787 DeviceExtension
->MouseResetState
++;
790 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x50);
791 DeviceExtension
->MouseResetState
++;
794 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF2);
795 DeviceExtension
->MouseResetState
++;
799 DeviceExtension
->MouseResetState
++;
803 /* It's either an Intellimouse or Intellimouse Explorer. */
804 DeviceExtension
->MouseAttributes
.NumberOfButtons
= 3;
805 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
806 WHEELMOUSE_I8042_HARDWARE
;
807 DeviceExtension
->MouseType
= Intellimouse
;
808 DeviceExtension
->MouseResetState
= Enable5Buttons
;
809 i8042MouResetIsr(DeviceExtension
, Status
, Value
);
813 /* Just set the default settings and be done */
814 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
815 DeviceExtension
->MouseResetState
= ExpectingSetSamplingRateACK
;
819 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
820 DeviceExtension
->MouseResetState
= 1021;
824 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
825 DeviceExtension
->MouseResetState
++;
829 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xC8);
830 DeviceExtension
->MouseResetState
++;
833 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x50);
834 DeviceExtension
->MouseResetState
++;
837 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF2);
838 DeviceExtension
->MouseResetState
++;
843 DeviceExtension
->MouseAttributes
.NumberOfButtons
= 5;
844 DeviceExtension
->MouseAttributes
.MouseIdentifier
=
845 WHEELMOUSE_I8042_HARDWARE
;
846 DeviceExtension
->MouseType
= IntellimouseExplorer
;
848 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF3);
849 DeviceExtension
->MouseResetState
= ExpectingSetSamplingRateACK
;
851 case ExpectingSetSamplingRateACK
:
852 DeviceExtension
->MouseHook
.IsrWritePort(
853 DeviceExtension
->MouseHook
.CallContext
,
854 (UCHAR
)DeviceExtension
->MouseAttributes
.SampleRate
);
855 DeviceExtension
->MouseResetState
++;
857 case ExpectingSetSamplingRateValueACK
:
858 if (MOUSE_NACK
== Value
)
860 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0x3C);
861 DeviceExtension
->MouseAttributes
.SampleRate
= (USHORT
)PortDeviceExtension
->Settings
.SampleRate
;
862 DeviceExtension
->MouseResetState
= 1040;
865 case 1040: /* Fallthrough */
866 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xE8);
867 DeviceExtension
->MouseResetState
= ExpectingFinalResolutionACK
;
869 case ExpectingFinalResolutionACK
:
870 DeviceExtension
->MouseHook
.IsrWritePort(
871 DeviceExtension
->MouseHook
.CallContext
,
872 (UCHAR
)(PortDeviceExtension
->Settings
.MouseResolution
& 0xff));
873 INFO_(I8042PRT
, "Mouse resolution %lu\n",
874 PortDeviceExtension
->Settings
.MouseResolution
);
875 DeviceExtension
->MouseResetState
= ExpectingFinalResolutionValueACK
;
877 case ExpectingFinalResolutionValueACK
:
878 DeviceExtension
->MouseHook
.IsrWritePort(DeviceExtension
->MouseHook
.CallContext
, 0xF4);
879 DeviceExtension
->MouseResetState
= ExpectingEnableACK
;
881 case ExpectingEnableACK
:
882 PortDeviceExtension
->Flags
|= MOUSE_PRESENT
;
883 DeviceExtension
->MouseState
= MouseIdle
;
884 DeviceExtension
->MouseTimeoutState
= TimeoutCancel
;
885 INFO_(I8042PRT
, "Mouse type = %u\n", DeviceExtension
->MouseType
);
888 if (DeviceExtension
->MouseResetState
< 100 || DeviceExtension
->MouseResetState
> 999)
889 ERR_(I8042PRT
, "MouseResetState went out of range: %lu\n", DeviceExtension
->MouseResetState
);
895 i8042MouInterruptService(
896 IN PKINTERRUPT Interrupt
,
899 PI8042_MOUSE_EXTENSION DeviceExtension
;
900 PPORT_DEVICE_EXTENSION PortDeviceExtension
;
902 UCHAR Output
= 0, PortStatus
= 0;
905 UNREFERENCED_PARAMETER(Interrupt
);
907 DeviceExtension
= (PI8042_MOUSE_EXTENSION
)Context
;
908 PortDeviceExtension
= DeviceExtension
->Common
.PortDeviceExtension
;
909 Counter
= PortDeviceExtension
->Settings
.PollStatusIterations
;
913 Status
= i8042ReadStatus(PortDeviceExtension
, &PortStatus
);
914 if (!NT_SUCCESS(Status
))
916 WARN_(I8042PRT
, "i8042ReadStatus() failed with status 0x%08lx\n", Status
);
919 Status
= i8042ReadMouseData(PortDeviceExtension
, &Output
);
920 if (NT_SUCCESS(Status
))
922 KeStallExecutionProcessor(1);
927 WARN_(I8042PRT
, "Spurious i8042 mouse interrupt\n");
931 INFO_(I8042PRT
, "Got: 0x%02x\n", Output
);
933 if (i8042PacketIsr(PortDeviceExtension
, Output
))
935 if (PortDeviceExtension
->PacketComplete
)
937 TRACE_(I8042PRT
, "Packet complete\n");
938 KeInsertQueueDpc(&DeviceExtension
->DpcMouse
, NULL
, NULL
);
940 TRACE_(I8042PRT
, "Irq eaten by packet\n");
944 TRACE_(I8042PRT
, "Irq is mouse input\n");
946 i8042MouInputTestTimeout(DeviceExtension
);
948 if (i8042MouResetIsr(DeviceExtension
, PortStatus
, Output
))
950 TRACE_(I8042PRT
, "Handled by ResetIsr or hooked Isr\n");
951 if (NoChange
!= DeviceExtension
->MouseTimeoutState
) {
952 KeInsertQueueDpc(&DeviceExtension
->DpcMouse
, NULL
, NULL
);
957 if (DeviceExtension
->MouseType
== Ps2pp
)
958 i8042MouHandlePs2pp(DeviceExtension
, Output
);
960 i8042MouHandle(DeviceExtension
, Output
);