2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/input/i8042prt/mouse.c
5 * PURPOSE: i8042 (ps/2 keyboard-mouse controller) driver
7 * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
8 * Jason Filby (jasonfilby@yahoo.com)
12 /* INCLUDES ****************************************************************/
14 #include <ddk/ntddk.h>
15 #include <ddk/ntddkbd.h>
16 #include <ddk/ntdd8042.h>
24 * These functions are callbacks for filter driver custom interrupt
27 VOID STDCALL
I8042IsrWritePortMouse(PVOID Context
,
30 I8042IsrWritePort(Context
, Value
, 0xD4);
33 NTSTATUS STDCALL
I8042SynchWritePortMouse(PVOID Context
,
37 return I8042SynchWritePort((PDEVICE_EXTENSION
)Context
,
43 /* Test if packets are taking too long to come in. If they do, we
44 * might have gotten out of sync and should just drop what we have.
46 * If we want to be totally right, we'd also have to keep a count of
47 * errors, and totally reset the mouse after too much of them (can
48 * happen if the user is using a KVM switch and an OS on another port
49 * resets the mouse, or if the user hotplugs the mouse, or if we're just
50 * generally unlucky). Also note the input parsing routine where we
51 * drop invalid input packets.
53 static VOID STDCALL
I8042MouseInputTestTimeout(PDEVICE_EXTENSION DevExt
)
57 if (DevExt
->MouseState
== MouseExpectingACK
||
58 DevExt
->MouseState
== MouseResetting
)
61 Now
.QuadPart
= KeQueryInterruptTime();
63 if (DevExt
->MouseState
!= MouseIdle
) {
64 /* Check if the last byte came too long ago */
65 if (Now
.QuadPart
- DevExt
->MousePacketStartTime
.QuadPart
>
66 DevExt
->Settings
.MouseSynchIn100ns
) {
67 DPRINT1("Mouse input packet timeout\n");
68 DevExt
->MouseState
= MouseIdle
;
72 if (DevExt
->MouseState
== MouseIdle
)
73 DevExt
->MousePacketStartTime
.QuadPart
= Now
.QuadPart
;
77 * Call the customization hook. The Ret2 parameter is about wether
78 * we should go on with the interrupt. The return value is what
79 * we should return (indicating to the system wether someone else
80 * should try to handle the interrupt)
82 BOOLEAN STDCALL
I8042MouseCallIsrHook(PDEVICE_EXTENSION DevExt
,
87 BOOLEAN HookReturn
, HookContinue
;
91 if (DevExt
->MouseHook
.IsrRoutine
) {
92 HookReturn
= DevExt
->MouseHook
.IsrRoutine(
93 DevExt
->MouseHook
.Context
,
94 DevExt
->MouseBuffer
+ DevExt
->MouseInBuffer
,
100 &DevExt
->MouseResetState
);
103 *ToReturn
= HookReturn
;
110 BOOLEAN STDCALL
I8042MouseResetIsr(PDEVICE_EXTENSION DevExt
,
116 if (I8042MouseCallIsrHook(DevExt
, Status
, Value
, &ToReturn
))
119 if (MouseResetting
!= DevExt
->MouseState
) {
122 DevExt
->MouseTimeoutState
= TimeoutStart
;
124 switch (DevExt
->MouseResetState
) {
125 case 1100: /* the first ack, drop it. */
126 DevExt
->MouseResetState
= ExpectingReset
;
128 /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok,
132 if (0xAA == *Value
) {
133 DevExt
->MouseResetState
++;
135 DevExt
->MouseExists
= FALSE
;
136 DevExt
->MouseState
= MouseIdle
;
137 DPRINT("Mouse returned bad reset reply: "
138 "%x (expected aa)\n", *Value
);
141 case ExpectingResetId
:
142 if (0x00 == *Value
) {
143 DevExt
->MouseResetState
++;
144 DevExt
->MouseType
= GenericPS2
;
145 I8042IsrWritePortMouse(DevExt
, 0xF2);
147 DevExt
->MouseExists
= FALSE
;
148 DevExt
->MouseState
= MouseIdle
;
149 DPRINT1("Mouse returned bad reset reply part two: "
150 "%x (expected 0)\n", Value
);
153 case ExpectingGetDeviceIdACK
:
154 if (MOUSE_ACK
== *Value
) {
155 DevExt
->MouseResetState
++;
156 } else if (MOUSE_NACK
== *Value
||
157 MOUSE_ERROR
== *Value
) {
158 DevExt
->MouseResetState
++;
159 /* Act as if 00 (normal mouse) was received */
160 DPRINT("Mouse doesn't support 0xd2, "
161 "(returns %x, expected %x), faking.\n",
164 I8042MouseResetIsr(DevExt
, Status
, Value
);
167 case ExpectingGetDeviceIdValue
:
170 DevExt
->MouseAttributes
.MouseIdentifier
=
171 BALLPOINT_I8042_HARDWARE
;
175 DevExt
->MouseAttributes
.MouseIdentifier
=
176 WHEELMOUSE_I8042_HARDWARE
;
179 DevExt
->MouseAttributes
.MouseIdentifier
=
180 MOUSE_I8042_HARDWARE
;
182 DevExt
->MouseResetState
++;
183 I8042IsrWritePortMouse(DevExt
, 0xE8);
185 case ExpectingSetResolutionDefaultACK
:
186 DevExt
->MouseResetState
++;
187 I8042IsrWritePortMouse(DevExt
, 0x00);
189 case ExpectingSetResolutionDefaultValueACK
:
190 DevExt
->MouseResetState
= ExpectingSetScaling1to1ACK
;
191 I8042IsrWritePortMouse(DevExt
, 0xE6);
193 case ExpectingSetScaling1to1ACK
:
194 case ExpectingSetScaling1to1ACK2
:
195 DevExt
->MouseResetState
++;
196 I8042IsrWritePortMouse(DevExt
, 0xE6);
198 case ExpectingSetScaling1to1ACK3
:
199 DevExt
->MouseResetState
++;
200 I8042IsrWritePortMouse(DevExt
, 0xE9);
202 case ExpectingReadMouseStatusACK
:
203 DevExt
->MouseResetState
++;
205 case ExpectingReadMouseStatusByte1
:
206 DevExt
->MouseLogiBuffer
[0] = *Value
;
207 DevExt
->MouseResetState
++;
209 case ExpectingReadMouseStatusByte2
:
210 DevExt
->MouseLogiBuffer
[1] = *Value
;
211 DevExt
->MouseResetState
++;
213 case ExpectingReadMouseStatusByte3
:
214 DevExt
->MouseLogiBuffer
[2] = *Value
;
215 /* Now MouseLogiBuffer is a set of info. If the second
216 * byte is 0, the mouse didn't understand the magic
217 * code. Otherwise, it it a Logitech and the second byte
218 * is the number of buttons, bit 7 of the first byte tells
219 * if it understands special E7 commands, the rest is an ID.
221 if (DevExt
->MouseLogiBuffer
[1]) {
222 DevExt
->MouseAttributes
.NumberOfButtons
=
223 DevExt
->MouseLogiBuffer
[1];
224 /* For some reason the ID is the wrong way around */
225 DevExt
->MouseLogitechID
=
226 ((DevExt
->MouseLogiBuffer
[0] >> 4) & 0x07) |
227 ((DevExt
->MouseLogiBuffer
[0] << 3) & 0x78);
228 DevExt
->MouseType
= Ps2pp
;
229 I8042IsrWritePortMouse(DevExt
, 0xf3);
230 DevExt
->MouseResetState
= ExpectingSetSamplingRateACK
;
232 /* TODO: Go through EnableWheel and Enable5Buttons */
234 DevExt
->MouseResetState
= EnableWheel
;
235 I8042MouseResetIsr(DevExt
, Status
, Value
);
238 I8042IsrWritePortMouse(DevExt
, 0xf3);
239 DevExt
->MouseResetState
= 1001;
242 I8042IsrWritePortMouse(DevExt
, 0xc8);
243 DevExt
->MouseResetState
++;
247 I8042IsrWritePortMouse(DevExt
, 0xf3);
248 DevExt
->MouseResetState
++;
251 I8042IsrWritePortMouse(DevExt
, 0x64);
252 DevExt
->MouseResetState
++;
255 I8042IsrWritePortMouse(DevExt
, 0x50);
256 DevExt
->MouseResetState
++;
259 I8042IsrWritePortMouse(DevExt
, 0xf2);
260 DevExt
->MouseResetState
++;
264 DevExt
->MouseResetState
++;
267 /* Now if the value == 3, it's either an Intellimouse
268 * or Intellimouse Explorer. */
269 if (0x03 == *Value
) {
270 DevExt
->MouseAttributes
.NumberOfButtons
= 3;
271 DevExt
->MouseAttributes
.MouseIdentifier
=
272 WHEELMOUSE_I8042_HARDWARE
;
273 DevExt
->MouseType
= Intellimouse
;
274 DevExt
->MouseResetState
= Enable5Buttons
;
275 I8042MouseResetIsr(DevExt
, Status
, Value
);
277 } /* Else, just set the default settings and be done */
278 I8042IsrWritePortMouse(DevExt
, 0xf3);
279 DevExt
->MouseResetState
= ExpectingSetSamplingRateACK
;
282 I8042IsrWritePortMouse(DevExt
, 0xf3);
283 DevExt
->MouseResetState
= 1021;
287 I8042IsrWritePortMouse(DevExt
, 0xf3);
288 DevExt
->MouseResetState
++;
292 I8042IsrWritePortMouse(DevExt
, 0xc8);
293 DevExt
->MouseResetState
++;
296 I8042IsrWritePortMouse(DevExt
, 0x50);
297 DevExt
->MouseResetState
++;
300 I8042IsrWritePortMouse(DevExt
, 0xf2);
301 DevExt
->MouseResetState
++;
304 if (0x04 == *Value
) {
305 DevExt
->MouseAttributes
.NumberOfButtons
= 5;
306 DevExt
->MouseAttributes
.MouseIdentifier
=
307 WHEELMOUSE_I8042_HARDWARE
;
308 DevExt
->MouseType
= IntellimouseExplorer
;
310 I8042IsrWritePortMouse(DevExt
, 0xf3);
311 DevExt
->MouseResetState
= ExpectingSetSamplingRateACK
;
313 case ExpectingSetSamplingRateACK
:
314 I8042IsrWritePortMouse(DevExt
,
315 DevExt
->MouseAttributes
.SampleRate
);
316 DevExt
->MouseResetState
++;
318 case ExpectingSetSamplingRateValueACK
:
319 if (MOUSE_NACK
== *Value
) {
320 I8042IsrWritePortMouse(DevExt
, 0x3c);
321 DevExt
->MouseAttributes
.SampleRate
= 60;
322 DevExt
->MouseResetState
= 1040;
325 case 1040: /* Fallthrough */
326 I8042IsrWritePortMouse(DevExt
, 0xe8);
327 DevExt
->MouseResetState
= ExpectingFinalResolutionACK
;
329 case ExpectingFinalResolutionACK
:
330 I8042IsrWritePortMouse(DevExt
,
331 DevExt
->Settings
.MouseResolution
& 0xff);
332 DPRINT("%x\n", DevExt
->Settings
.MouseResolution
);
333 DevExt
->MouseResetState
= ExpectingFinalResolutionValueACK
;
335 case ExpectingFinalResolutionValueACK
:
336 I8042IsrWritePortMouse(DevExt
, 0xf4);
337 DevExt
->MouseResetState
= ExpectingEnableACK
;
339 case ExpectingEnableACK
:
340 DevExt
->MouseState
= MouseIdle
;
341 DevExt
->MouseTimeoutState
= TimeoutCancel
;
342 DPRINT("Mouse type = %d\n", DevExt
->MouseType
);
345 if (DevExt
->MouseResetState
< 100 ||
346 DevExt
->MouseResetState
> 999)
347 DPRINT1("MouseResetState went out of range: %d\n",
348 DevExt
->MouseResetState
);
354 * Prepare for reading the next packet and queue the dpc for handling
357 * Context is the device object.
359 VOID STDCALL
I8042QueueMousePacket(PVOID Context
)
361 PDEVICE_OBJECT DeviceObject
= Context
;
362 PFDO_DEVICE_EXTENSION FdoDevExt
= DeviceObject
->DeviceExtension
;
363 PDEVICE_EXTENSION DevExt
= FdoDevExt
->PortDevExt
;
365 DevExt
->MouseComplete
= TRUE
;
366 DevExt
->MouseInBuffer
++;
367 if (DevExt
->MouseInBuffer
>
368 DevExt
->MouseAttributes
.InputDataQueueLength
) {
369 DPRINT1("Mouse buffer overflow\n");
370 DevExt
->MouseInBuffer
--;
373 DPRINT("Irq completes mouse packet\n");
374 KeInsertQueueDpc(&DevExt
->DpcMouse
, DevExt
, NULL
);
378 * Updates ButtonFlags according to RawButtons and a saved state;
379 * Only takes in account the bits that are set in Mask
381 VOID STDCALL
I8042MouseHandleButtons(PDEVICE_EXTENSION DevExt
,
384 PMOUSE_INPUT_DATA MouseInput
= DevExt
->MouseBuffer
+
385 DevExt
->MouseInBuffer
;
386 USHORT NewButtonData
= MouseInput
->RawButtons
& Mask
;
387 USHORT ButtonDiff
= (NewButtonData
^ DevExt
->MouseButtonState
) & Mask
;
389 /* Note that the defines are such:
390 * MOUSE_LEFT_BUTTON_DOWN 1
391 * MOUSE_LEFT_BUTTON_UP 2
393 MouseInput
->ButtonFlags
|= (NewButtonData
& ButtonDiff
) |
394 (((~(NewButtonData
)) << 1) &
396 (MouseInput
->RawButtons
& 0xfc00);
398 DPRINT("Left raw/up/down: %d/%d/%d\n", MouseInput
->RawButtons
& MOUSE_LEFT_BUTTON_DOWN
,
399 MouseInput
->ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
,
400 MouseInput
->ButtonFlags
& MOUSE_LEFT_BUTTON_UP
);
402 DevExt
->MouseButtonState
= (DevExt
->MouseButtonState
& ~Mask
) |
403 (NewButtonData
& Mask
);
406 VOID STDCALL
I8042MouseHandle(PDEVICE_EXTENSION DevExt
,
409 PMOUSE_INPUT_DATA MouseInput
= DevExt
->MouseBuffer
+
410 DevExt
->MouseInBuffer
;
413 switch (DevExt
->MouseState
) {
415 /* This bit should be 1, if not drop the packet, we
416 * might be lucky and get in sync again
419 DPRINT1("Bad input, dropping..\n");
423 MouseInput
->Buttons
= 0;
424 MouseInput
->RawButtons
= 0;
425 MouseInput
->Flags
= MOUSE_MOVE_RELATIVE
;
427 /* Note how we ignore the overflow bits, like Windows
428 * is said to do. There's no reasonable thing to do
433 MouseInput
->LastX
= 1;
435 MouseInput
->LastX
= 0;
438 MouseInput
->LastY
= 1;
440 MouseInput
->LastY
= 0;
443 MouseInput
->RawButtons
|= MOUSE_LEFT_BUTTON_DOWN
;
447 MouseInput
->RawButtons
|= MOUSE_RIGHT_BUTTON_DOWN
;
451 MouseInput
->RawButtons
|= MOUSE_MIDDLE_BUTTON_DOWN
;
453 DevExt
->MouseState
= XMovement
;
456 if (MouseInput
->LastX
)
457 MouseInput
->LastX
= (LONG
) Output
- 256;
459 MouseInput
->LastX
= Output
;
461 DevExt
->MouseState
= YMovement
;
464 if (MouseInput
->LastY
)
465 MouseInput
->LastY
= (LONG
)Output
- 256;
467 MouseInput
->LastY
= (LONG
)Output
;
469 /* Windows wants it the other way around */
470 MouseInput
->LastY
= -MouseInput
->LastY
;
472 if (DevExt
->MouseType
== GenericPS2
||
473 DevExt
->MouseType
== Ps2pp
) {
474 I8042MouseHandleButtons(DevExt
,
475 MOUSE_LEFT_BUTTON_DOWN
|
476 MOUSE_RIGHT_BUTTON_DOWN
|
477 MOUSE_MIDDLE_BUTTON_DOWN
);
478 I8042QueueMousePacket(
479 DevExt
->MouseObject
);
480 DevExt
->MouseState
= MouseIdle
;
482 DevExt
->MouseState
= ZMovement
;
486 Scroll
= Output
& 0x0f;
491 MouseInput
->RawButtons
|= MOUSE_WHEEL
;
492 MouseInput
->ButtonData
= (USHORT
)(Scroll
* -WHEEL_DELTA
);
495 if (DevExt
->MouseType
== IntellimouseExplorer
) {
497 MouseInput
->RawButtons
|= MOUSE_BUTTON_4_DOWN
;
500 MouseInput
->RawButtons
|= MOUSE_BUTTON_5_DOWN
;
502 I8042MouseHandleButtons(DevExt
, MOUSE_LEFT_BUTTON_DOWN
|
503 MOUSE_RIGHT_BUTTON_DOWN
|
504 MOUSE_MIDDLE_BUTTON_DOWN
|
505 MOUSE_BUTTON_4_DOWN
|
506 MOUSE_BUTTON_5_DOWN
);
507 I8042QueueMousePacket(DevExt
->MouseObject
);
508 DevExt
->MouseState
= MouseIdle
;
511 DPRINT1("Unexpected state!\n");
515 BOOLEAN STDCALL
I8042InterruptServiceMouse(struct _KINTERRUPT
*Interrupt
,
518 BYTE Output
, PortStatus
;
520 PDEVICE_EXTENSION DevExt
= (PDEVICE_EXTENSION
) Context
;
524 Status
= I8042ReadStatus(&PortStatus
);
525 Status
= I8042ReadData(&Output
);
527 if (STATUS_SUCCESS
== Status
)
529 KeStallExecutionProcessor(1);
530 } while (Iterations
< DevExt
->Settings
.PollStatusIterations
);
532 if (STATUS_SUCCESS
!= Status
) {
533 DPRINT1("Spurious I8042 mouse interrupt\n");
537 DPRINT("Got: %x\n", Output
);
539 if (I8042PacketIsr(DevExt
, Output
)) {
540 if (DevExt
->PacketComplete
) {
541 DPRINT("Packet complete\n");
542 KeInsertQueueDpc(&DevExt
->DpcKbd
, DevExt
, NULL
);
544 DPRINT("Irq eaten by packet\n");
548 I8042MouseInputTestTimeout(DevExt
);
550 if (I8042MouseResetIsr(DevExt
, PortStatus
, &Output
)) {
551 DPRINT("Handled by ResetIsr or hooked Isr\n");
552 if (NoChange
!= DevExt
->MouseTimeoutState
) {
553 KeInsertQueueDpc(&DevExt
->DpcMouse
, DevExt
, NULL
);
558 if (DevExt
->MouseType
== Ps2pp
)
559 I8042MouseHandlePs2pp(DevExt
, Output
);
561 I8042MouseHandle(DevExt
, Output
);
566 VOID STDCALL
I8042DpcRoutineMouse(PKDPC Dpc
,
567 PVOID DeferredContext
,
568 PVOID SystemArgument1
,
569 PVOID SystemArgument2
)
571 PDEVICE_EXTENSION DevExt
= (PDEVICE_EXTENSION
)SystemArgument1
;
572 ULONG MouseTransferred
= 0;
573 ULONG MouseInBufferCopy
;
575 LARGE_INTEGER Timeout
;
577 switch (DevExt
->MouseTimeoutState
) {
579 DevExt
->MouseTimeoutState
= NoChange
;
580 if (DevExt
->MouseTimeoutActive
&&
581 !KeCancelTimer(&DevExt
->TimerMouseTimeout
)) {
582 /* The timer fired already, give up */
583 DevExt
->MouseTimeoutActive
= FALSE
;
587 Timeout
.QuadPart
= -15000000;
588 /* 1.5 seconds, should be enough */
590 KeSetTimer(&DevExt
->TimerMouseTimeout
,
592 &DevExt
->DpcMouseTimeout
);
593 DevExt
->MouseTimeoutActive
= TRUE
;
596 DevExt
->MouseTimeoutState
= NoChange
;
597 KeCancelTimer(&DevExt
->TimerMouseTimeout
);
598 DevExt
->MouseTimeoutActive
= FALSE
;
600 /* nothing, don't want a warning */ ;
603 /* Should be unlikely */
604 if (!DevExt
->MouseComplete
)
607 Irql
= KeAcquireInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
);
609 DevExt
->MouseComplete
= FALSE
;
610 MouseInBufferCopy
= DevExt
->MouseInBuffer
;
612 KeReleaseInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
, Irql
);
614 DPRINT ("Send a mouse packet\n");
616 if (!DevExt
->MouseData
.ClassService
)
619 ((MOUSE_CLASS_SERVICE_CALLBACK
) DevExt
->MouseData
.ClassService
)(
620 DevExt
->MouseData
.ClassDeviceObject
,
622 DevExt
->MouseBuffer
+ MouseInBufferCopy
,
625 Irql
= KeAcquireInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
);
627 DevExt
->MouseInBuffer
-= MouseTransferred
;
628 if (DevExt
->MouseInBuffer
)
629 RtlMoveMemory(DevExt
->MouseBuffer
,
630 DevExt
->MouseBuffer
+MouseTransferred
,
631 DevExt
->MouseInBuffer
* sizeof(MOUSE_INPUT_DATA
));
633 KeReleaseInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
, Irql
);
636 /* This timer DPC will be called when the mouse reset times out.
637 * I'll just send the 'disable mouse port' command to the controller
638 * and say the mouse doesn't exist.
640 VOID STDCALL
I8042DpcRoutineMouseTimeout(PKDPC Dpc
,
641 PVOID DeferredContext
,
642 PVOID SystemArgument1
,
643 PVOID SystemArgument2
)
645 PDEVICE_EXTENSION DevExt
= (PDEVICE_EXTENSION
)DeferredContext
;
648 Irql
= KeAcquireInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
);
650 DPRINT1("Mouse initialization timeout! (substate %x) "
651 "Disabling mouse.\n",
652 DevExt
->MouseResetState
);
654 if (!I8042MouseDisable(DevExt
)) {
655 DPRINT1("Failed to disable mouse.\n");
658 DevExt
->MouseExists
= FALSE
;
660 KeReleaseInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
, Irql
);
664 * Process the mouse internal device requests
665 * returns FALSE if it doesn't understand the
666 * call so someone else can handle it.
668 BOOLEAN STDCALL
I8042StartIoMouse(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
670 PIO_STACK_LOCATION Stk
;
671 PFDO_DEVICE_EXTENSION FdoDevExt
= DeviceObject
->DeviceExtension
;
672 PDEVICE_EXTENSION DevExt
= FdoDevExt
->PortDevExt
;
674 Stk
= IoGetCurrentIrpStackLocation(Irp
);
676 switch (Stk
->Parameters
.DeviceIoControl
.IoControlCode
) {
677 case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER
:
681 Stk
->Parameters
.DeviceIoControl
.Type3InputBuffer
,
682 Stk
->Parameters
.DeviceIoControl
.InputBufferLength
,
694 * Runs the mouse IOCTL_INTERNAL dispatch.
695 * Returns NTSTATUS_INVALID_DEVICE_REQUEST if it doesn't handle this request
696 * so someone else can have a try at it.
698 NTSTATUS STDCALL
I8042InternalDeviceControlMouse(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
700 PIO_STACK_LOCATION Stk
;
701 PFDO_DEVICE_EXTENSION FdoDevExt
= DeviceObject
->DeviceExtension
;
702 PDEVICE_EXTENSION DevExt
= FdoDevExt
->PortDevExt
;
704 DPRINT("InternalDeviceControl\n");
706 Irp
->IoStatus
.Information
= 0;
707 Stk
= IoGetCurrentIrpStackLocation(Irp
);
709 switch (Stk
->Parameters
.DeviceIoControl
.IoControlCode
) {
711 case IOCTL_INTERNAL_MOUSE_CONNECT
:
712 DPRINT("IOCTL_INTERNAL_MOUSE_CONNECT\n");
713 if (Stk
->Parameters
.DeviceIoControl
.InputBufferLength
<
714 sizeof(CONNECT_DATA
)) {
715 DPRINT1("Mouse IOCTL_INTERNAL_MOUSE_CONNECT "
716 "invalid buffer size\n");
717 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
721 if (!DevExt
->MouseExists
) {
722 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_CONNECTED
;
726 if (DevExt
->MouseClaimed
) {
727 DPRINT1("IOCTL_INTERNAL_MOUSE_CONNECT: "
728 "Mouse is already claimed\n");
729 Irp
->IoStatus
.Status
= STATUS_SHARING_VIOLATION
;
733 memcpy(&DevExt
->MouseData
,
734 Stk
->Parameters
.DeviceIoControl
.Type3InputBuffer
,
735 sizeof(CONNECT_DATA
));
736 DevExt
->MouseHook
.IsrWritePort
= I8042IsrWritePortMouse
;
737 DevExt
->MouseHook
.QueueMousePacket
=
738 I8042QueueMousePacket
;
739 DevExt
->MouseHook
.CallContext
= DevExt
;
742 PIO_WORKITEM WorkItem
;
743 PI8042_HOOK_WORKITEM WorkItemData
;
745 WorkItem
= IoAllocateWorkItem(DeviceObject
);
747 DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
748 "Can't allocate work item\n");
749 Irp
->IoStatus
.Status
=
750 STATUS_INSUFFICIENT_RESOURCES
;
754 WorkItemData
= ExAllocatePoolWithTag(
756 sizeof(I8042_HOOK_WORKITEM
),
759 DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
760 "Can't allocate work item data\n");
761 Irp
->IoStatus
.Status
=
762 STATUS_INSUFFICIENT_RESOURCES
;
763 IoFreeWorkItem(WorkItem
);
766 WorkItemData
->WorkItem
= WorkItem
;
767 WorkItemData
->Target
=
768 DevExt
->MouseData
.ClassDeviceObject
;
769 WorkItemData
->Irp
= Irp
;
771 IoMarkIrpPending(Irp
);
772 DevExt
->MouseState
= MouseResetting
;
773 DevExt
->MouseResetState
= 1100;
774 IoQueueWorkItem(WorkItem
,
775 I8042SendHookWorkItem
,
779 Irp
->IoStatus
.Status
= STATUS_PENDING
;
783 case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER
:
784 DPRINT("IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER\n");
785 if (Stk
->Parameters
.DeviceIoControl
.InputBufferLength
< 1) {
786 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
789 if (!DevExt
->MouseInterruptObject
) {
790 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
794 IoMarkIrpPending(Irp
);
795 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
796 Irp
->IoStatus
.Status
= STATUS_PENDING
;
799 case IOCTL_MOUSE_QUERY_ATTRIBUTES
:
800 DPRINT("IOCTL_MOUSE_QUERY_ATTRIBUTES\n");
801 if (Stk
->Parameters
.DeviceIoControl
.InputBufferLength
<
802 sizeof(MOUSE_ATTRIBUTES
)) {
803 DPRINT("Mouse IOCTL_MOUSE_QUERY_ATTRIBUTES "
804 "invalid buffer size\n");
805 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
808 memcpy(Irp
->AssociatedIrp
.SystemBuffer
,
809 &DevExt
->MouseAttributes
,
810 sizeof(MOUSE_ATTRIBUTES
));
812 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
815 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
820 return Irp
->IoStatus
.Status
;
823 BOOLEAN STDCALL
I8042MouseEnable(PDEVICE_EXTENSION DevExt
)
828 DPRINT("Enabling mouse\n");
830 if (!I8042Write(DevExt
, I8042_CTRL_PORT
, KBD_READ_MODE
)) {
831 DPRINT1("Can't read i8042 mode\n");
835 Status
= I8042ReadDataWait(DevExt
, &Value
);
836 if (Status
!= STATUS_SUCCESS
) {
837 DPRINT1("No response after read i8042 mode\n");
841 Value
&= ~(0x20); // don't disable mouse
842 Value
|= 0x02; // enable mouse interrupts
844 if (!I8042Write(DevExt
, I8042_CTRL_PORT
, KBD_WRITE_MODE
)) {
845 DPRINT1("Can't set i8042 mode\n");
849 if (!I8042Write(DevExt
, I8042_DATA_PORT
, Value
)) {
850 DPRINT1("Can't send i8042 mode\n");
857 BOOLEAN STDCALL
I8042MouseDisable(PDEVICE_EXTENSION DevExt
)
862 DPRINT("Disabling mouse\n");
864 I8042Flush(); /* Just to be (kind of) sure */
866 if (!I8042Write(DevExt
, I8042_CTRL_PORT
, KBD_READ_MODE
)) {
867 DPRINT1("Can't read i8042 mode\n");
871 Status
= I8042ReadDataWait(DevExt
, &Value
);
872 if (Status
!= STATUS_SUCCESS
) {
873 DPRINT1("No response after read i8042 mode\n");
877 Value
|= 0x20; // don't disable mouse
878 Value
&= ~(0x02); // enable mouse interrupts
880 if (!I8042Write(DevExt
, I8042_CTRL_PORT
, KBD_WRITE_MODE
)) {
881 DPRINT1("Can't set i8042 mode\n");
885 if (!I8042Write(DevExt
, I8042_DATA_PORT
, Value
)) {
886 DPRINT1("Can't send i8042 mode\n");
891 /* Just to be (kind of) sure; if the mouse would
892 * say something while we are disabling it, these bytes would
893 * block the keyboard.