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>
16 #include <ntos/keyboard.h>
17 #include <ntos/minmax.h>
18 #include <rosrtl/string.h>
20 #include <ddk/ntddkbd.h>
21 #include <ddk/ntdd8042.h>
29 * These functions are callbacks for filter driver custom interrupt
32 VOID STDCALL
I8042IsrWritePortMouse(PVOID Context
,
35 I8042IsrWritePort(Context
, Value
, 0xD4);
38 NTSTATUS STDCALL
I8042SynchWritePortMouse(PVOID Context
,
42 return I8042SynchWritePort((PDEVICE_EXTENSION
)Context
,
49 * Call the customization hook. The Ret2 parameter is about wether
50 * we should go on with the interrupt. The return value is what
51 * we should return (indicating to the system wether someone else
52 * should try to handle the interrupt)
54 BOOLEAN STDCALL
I8042MouseCallIsrHook(PDEVICE_EXTENSION DevExt
,
59 BOOLEAN HookReturn
, HookContinue
;
63 if (DevExt
->MouseHook
.IsrRoutine
) {
64 HookReturn
= DevExt
->MouseHook
.IsrRoutine(
65 DevExt
->MouseHook
.Context
,
66 DevExt
->MouseBuffer
+ DevExt
->MouseInBuffer
,
72 &DevExt
->MouseResetState
);
75 *ToReturn
= HookReturn
;
82 BOOLEAN STDCALL
I8042MouseResetIsr(PDEVICE_EXTENSION DevExt
,
88 if (I8042MouseCallIsrHook(DevExt
, Status
, Value
, &ToReturn
))
91 if (MouseResetting
!= DevExt
->MouseState
) {
94 DevExt
->MouseTimeoutState
= TimeoutStart
;
96 switch (DevExt
->MouseResetState
) {
97 case 1100: /* the first ack, drop it. */
98 DevExt
->MouseResetState
= ExpectingReset
;
100 /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok,
104 if (0xAA == *Value
) {
105 DevExt
->MouseResetState
++;
107 DevExt
->MouseExists
= FALSE
;
108 DevExt
->MouseState
= MouseIdle
;
109 DPRINT("Mouse returned bad reset reply: "
110 "%x (expected aa)\n", *Value
);
113 case ExpectingResetId
:
114 if (0x00 == *Value
) {
115 DevExt
->MouseResetState
++;
116 DevExt
->MouseType
= GenericPS2
;
117 I8042IsrWritePortMouse(DevExt
, 0xF2);
119 DevExt
->MouseExists
= FALSE
;
120 DevExt
->MouseState
= MouseIdle
;
121 DPRINT1("Mouse returned bad reset reply part two: "
122 "%x (expected 0)\n", Value
);
125 case ExpectingGetDeviceIdACK
:
126 if (MOUSE_ACK
== *Value
) {
127 DevExt
->MouseResetState
++;
128 } else if (MOUSE_NACK
== *Value
||
129 MOUSE_ERROR
== *Value
) {
130 DevExt
->MouseResetState
++;
131 /* Act as if 00 (normal mouse) was received */
132 DPRINT("Mouse doesn't support 0xd2, "
133 "(returns %x, expected %x), faking.\n",
136 I8042MouseResetIsr(DevExt
, Status
, Value
);
139 case ExpectingGetDeviceIdValue
:
142 DevExt
->MouseAttributes
.MouseIdentifier
=
143 BALLPOINT_I8042_HARDWARE
;
147 DevExt
->MouseAttributes
.MouseIdentifier
=
148 WHEELMOUSE_I8042_HARDWARE
;
151 DevExt
->MouseAttributes
.MouseIdentifier
=
152 MOUSE_I8042_HARDWARE
;
154 DevExt
->MouseResetState
++;
155 I8042IsrWritePortMouse(DevExt
, 0xE8);
157 case ExpectingSetResolutionDefaultACK
:
158 DevExt
->MouseResetState
++;
159 I8042IsrWritePortMouse(DevExt
, 0x00);
161 case ExpectingSetResolutionDefaultValueACK
:
162 DevExt
->MouseResetState
= ExpectingSetScaling1to1ACK
;
163 I8042IsrWritePortMouse(DevExt
, 0xE6);
165 case ExpectingSetScaling1to1ACK
:
166 case ExpectingSetScaling1to1ACK2
:
167 DevExt
->MouseResetState
++;
168 I8042IsrWritePortMouse(DevExt
, 0xE6);
170 case ExpectingSetScaling1to1ACK3
:
171 DevExt
->MouseResetState
++;
172 I8042IsrWritePortMouse(DevExt
, 0xE9);
174 case ExpectingReadMouseStatusACK
:
175 DevExt
->MouseResetState
++;
177 case ExpectingReadMouseStatusByte1
:
178 DevExt
->MouseLogiBuffer
[0] = *Value
;
179 DevExt
->MouseResetState
++;
181 case ExpectingReadMouseStatusByte2
:
182 DevExt
->MouseLogiBuffer
[1] = *Value
;
183 DevExt
->MouseResetState
++;
185 case ExpectingReadMouseStatusByte3
:
186 DevExt
->MouseLogiBuffer
[2] = *Value
;
187 /* Now MouseLogiBuffer is a set of info. If the second
188 * byte is 0, the mouse didn't understand the magic
189 * code. Otherwise, it it a Logitech and the second byte
190 * is the number of buttons, bit 7 of the first byte tells
191 * if it understands special E7 commands, the rest is an ID.
193 if (DevExt
->MouseLogiBuffer
[1]) {
194 DevExt
->MouseAttributes
.NumberOfButtons
=
195 DevExt
->MouseLogiBuffer
[1];
196 /* For some reason the ID is the wrong way around */
197 DevExt
->MouseLogitechID
=
198 ((DevExt
->MouseLogiBuffer
[0] >> 4) & 0x07) |
199 ((DevExt
->MouseLogiBuffer
[0] << 3) & 0x78);
200 DevExt
->MouseType
= Ps2pp
;
201 I8042IsrWritePortMouse(DevExt
, 0xf3);
202 DevExt
->MouseResetState
= ExpectingSetSamplingRateACK
;
204 /* TODO: Go through EnableWheel and Enable5Buttons */
206 DevExt
->MouseResetState
= EnableWheel
;
207 I8042MouseResetIsr(DevExt
, Status
, Value
);
210 I8042IsrWritePortMouse(DevExt
, 0xf3);
211 DevExt
->MouseResetState
= 1001;
214 I8042IsrWritePortMouse(DevExt
, 0xc8);
215 DevExt
->MouseResetState
++;
219 I8042IsrWritePortMouse(DevExt
, 0xf3);
220 DevExt
->MouseResetState
++;
223 I8042IsrWritePortMouse(DevExt
, 0x64);
224 DevExt
->MouseResetState
++;
227 I8042IsrWritePortMouse(DevExt
, 0x50);
228 DevExt
->MouseResetState
++;
231 I8042IsrWritePortMouse(DevExt
, 0xf2);
232 DevExt
->MouseResetState
++;
236 DevExt
->MouseResetState
++;
239 /* Now if the value == 3, it's either an Intellimouse
240 * or Intellimouse Explorer. */
241 if (0x03 == *Value
) {
242 DevExt
->MouseAttributes
.NumberOfButtons
= 3;
243 DevExt
->MouseAttributes
.MouseIdentifier
=
244 WHEELMOUSE_I8042_HARDWARE
;
245 DevExt
->MouseType
= Intellimouse
;
246 DevExt
->MouseResetState
= Enable5Buttons
;
247 I8042MouseResetIsr(DevExt
, Status
, Value
);
249 } /* Else, just set the default settings and be done */
250 I8042IsrWritePortMouse(DevExt
, 0xf3);
251 DevExt
->MouseResetState
= ExpectingSetSamplingRateACK
;
254 I8042IsrWritePortMouse(DevExt
, 0xf3);
255 DevExt
->MouseResetState
= 1021;
259 I8042IsrWritePortMouse(DevExt
, 0xf3);
260 DevExt
->MouseResetState
++;
264 I8042IsrWritePortMouse(DevExt
, 0xc8);
265 DevExt
->MouseResetState
++;
268 I8042IsrWritePortMouse(DevExt
, 0x50);
269 DevExt
->MouseResetState
++;
272 I8042IsrWritePortMouse(DevExt
, 0xf2);
273 DevExt
->MouseResetState
++;
276 if (0x04 == *Value
) {
277 DevExt
->MouseAttributes
.NumberOfButtons
= 5;
278 DevExt
->MouseAttributes
.MouseIdentifier
=
279 WHEELMOUSE_I8042_HARDWARE
;
280 DevExt
->MouseType
= IntellimouseExplorer
;
282 I8042IsrWritePortMouse(DevExt
, 0xf3);
283 DevExt
->MouseResetState
= ExpectingSetSamplingRateACK
;
285 case ExpectingSetSamplingRateACK
:
286 I8042IsrWritePortMouse(DevExt
,
287 DevExt
->MouseAttributes
.SampleRate
);
288 DevExt
->MouseResetState
++;
290 case ExpectingSetSamplingRateValueACK
:
291 if (MOUSE_NACK
== *Value
) {
292 I8042IsrWritePortMouse(DevExt
, 0x3c);
293 DevExt
->MouseAttributes
.SampleRate
= 60;
294 DevExt
->MouseResetState
= 1040;
297 case 1040: /* Fallthrough */
298 I8042IsrWritePortMouse(DevExt
, 0xe8);
299 DevExt
->MouseResetState
= ExpectingFinalResolutionACK
;
301 case ExpectingFinalResolutionACK
:
302 I8042IsrWritePortMouse(DevExt
, 0x03);
303 DevExt
->MouseResetState
= ExpectingFinalResolutionValueACK
;
305 case ExpectingFinalResolutionValueACK
:
306 I8042IsrWritePortMouse(DevExt
, 0xf4);
307 DevExt
->MouseResetState
= ExpectingEnableACK
;
309 case ExpectingEnableACK
:
310 DevExt
->MouseState
= MouseIdle
;
311 DevExt
->MouseTimeoutState
= TimeoutCancel
;
312 DPRINT("Mouse type = %d\n", DevExt
->MouseType
);
315 if (DevExt
->MouseResetState
< 100 ||
316 DevExt
->MouseResetState
> 999)
317 DPRINT1("MouseResetState went out of range: %d\n",
318 DevExt
->MouseResetState
);
324 * Prepare for reading the next packet and queue the dpc for handling
327 * Context is the device object.
329 VOID STDCALL
I8042QueueMousePacket(PVOID Context
)
331 PDEVICE_OBJECT DeviceObject
= Context
;
332 PFDO_DEVICE_EXTENSION FdoDevExt
= DeviceObject
->DeviceExtension
;
333 PDEVICE_EXTENSION DevExt
= FdoDevExt
->PortDevExt
;
335 DevExt
->MouseComplete
= TRUE
;
336 DevExt
->MouseInBuffer
++;
337 if (DevExt
->MouseInBuffer
>
338 DevExt
->MouseAttributes
.InputDataQueueLength
) {
339 DPRINT1("Mouse buffer overflow\n");
340 DevExt
->MouseInBuffer
--;
343 DPRINT("Irq completes mouse packet\n");
344 KeInsertQueueDpc(&DevExt
->DpcMouse
, DevExt
, NULL
);
348 * Updates ButtonFlags according to RawButtons and a saved state;
349 * Only takes in account the bits that are set in Mask
351 VOID STDCALL
I8042MouseHandleButtons(PDEVICE_EXTENSION DevExt
,
354 PMOUSE_INPUT_DATA MouseInput
= DevExt
->MouseBuffer
+
355 DevExt
->MouseInBuffer
;
356 USHORT NewButtonData
= MouseInput
->RawButtons
& Mask
;
357 USHORT ButtonDiff
= (NewButtonData
^ DevExt
->MouseButtonState
) & Mask
;
359 /* Note that the defines are such:
360 * MOUSE_LEFT_BUTTON_DOWN 1
361 * MOUSE_LEFT_BUTTON_UP 2
363 MouseInput
->ButtonFlags
|= (NewButtonData
& ButtonDiff
) |
364 (((~(NewButtonData
)) << 1) &
366 (MouseInput
->RawButtons
& 0xfc00);
368 DPRINT("Left raw/up/down: %d/%d/%d\n", MouseInput
->RawButtons
& MOUSE_LEFT_BUTTON_DOWN
,
369 MouseInput
->ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
,
370 MouseInput
->ButtonFlags
& MOUSE_LEFT_BUTTON_UP
);
372 DevExt
->MouseButtonState
= (DevExt
->MouseButtonState
& ~Mask
) |
373 (NewButtonData
& Mask
);
376 VOID STDCALL
I8042MouseHandle(PDEVICE_EXTENSION DevExt
,
379 PMOUSE_INPUT_DATA MouseInput
= DevExt
->MouseBuffer
+
380 DevExt
->MouseInBuffer
;
383 switch (DevExt
->MouseState
) {
385 /* This bit should be 1, if not drop the packet, we
386 * might be lucky and get in sync again
389 DPRINT1("Bad input, dropping..\n");
393 MouseInput
->Buttons
= 0;
394 MouseInput
->RawButtons
= 0;
395 MouseInput
->Flags
= MOUSE_MOVE_RELATIVE
;
397 /* Note how we ignore the overflow bits, like Windows
398 * is said to do. There's no reasonable thing to do
403 MouseInput
->LastX
= 1;
405 MouseInput
->LastX
= 0;
408 MouseInput
->LastY
= 1;
410 MouseInput
->LastY
= 0;
413 MouseInput
->RawButtons
|= MOUSE_LEFT_BUTTON_DOWN
;
417 MouseInput
->RawButtons
|= MOUSE_RIGHT_BUTTON_DOWN
;
421 MouseInput
->RawButtons
|= MOUSE_MIDDLE_BUTTON_DOWN
;
423 DevExt
->MouseState
= XMovement
;
426 if (MouseInput
->LastX
)
427 MouseInput
->LastX
= (LONG
) Output
- 256;
429 MouseInput
->LastX
= Output
;
431 DevExt
->MouseState
= YMovement
;
434 if (MouseInput
->LastY
)
435 MouseInput
->LastY
= (LONG
)Output
- 256;
437 MouseInput
->LastY
= (LONG
)Output
;
439 /* Windows wants it the other way around */
440 MouseInput
->LastY
= -MouseInput
->LastY
;
442 if (DevExt
->MouseType
== GenericPS2
||
443 DevExt
->MouseType
== Ps2pp
) {
444 I8042MouseHandleButtons(DevExt
,
445 MOUSE_LEFT_BUTTON_DOWN
|
446 MOUSE_RIGHT_BUTTON_DOWN
|
447 MOUSE_MIDDLE_BUTTON_DOWN
);
448 I8042QueueMousePacket(
449 DevExt
->MouseObject
);
450 DevExt
->MouseState
= MouseIdle
;
452 DevExt
->MouseState
= ZMovement
;
456 Scroll
= Output
& 0x0f;
461 MouseInput
->RawButtons
|= MOUSE_WHEEL
;
462 MouseInput
->ButtonData
= (USHORT
) Scroll
;
465 if (DevExt
->MouseType
== IntellimouseExplorer
) {
467 MouseInput
->RawButtons
|= MOUSE_BUTTON_4_DOWN
;
470 MouseInput
->RawButtons
|= MOUSE_BUTTON_5_DOWN
;
472 I8042MouseHandleButtons(DevExt
, MOUSE_LEFT_BUTTON_DOWN
|
473 MOUSE_RIGHT_BUTTON_DOWN
|
474 MOUSE_MIDDLE_BUTTON_DOWN
|
475 MOUSE_BUTTON_4_DOWN
|
476 MOUSE_BUTTON_5_DOWN
);
477 I8042QueueMousePacket(DevExt
->MouseObject
);
478 DevExt
->MouseState
= MouseIdle
;
481 DPRINT1("Unexpected state!\n");
485 BOOLEAN STDCALL
I8042InterruptServiceMouse(struct _KINTERRUPT
*Interrupt
,
488 BYTE Output
, PortStatus
;
490 PDEVICE_EXTENSION DevExt
= (PDEVICE_EXTENSION
) Context
;
494 Status
= I8042ReadStatus(&PortStatus
);
495 Status
= I8042ReadData(&Output
);
497 if (STATUS_SUCCESS
== Status
)
499 KeStallExecutionProcessor(1);
500 } while (Iterations
< DevExt
->Settings
.PollStatusIterations
);
502 if (STATUS_SUCCESS
!= Status
) {
503 DPRINT1("Spurious I8042 mouse interrupt\n");
507 DPRINT("Got: %x\n", Output
);
509 if (I8042PacketIsr(DevExt
, Output
)) {
510 if (DevExt
->PacketComplete
) {
511 DPRINT("Packet complete\n");
512 KeInsertQueueDpc(&DevExt
->DpcKbd
, DevExt
, NULL
);
514 DPRINT("Irq eaten by packet\n");
518 if (I8042MouseResetIsr(DevExt
, PortStatus
, &Output
)) {
519 DPRINT("Handled by ResetIsr or hooked Isr\n");
520 if (NoChange
!= DevExt
->MouseTimeoutState
) {
521 KeInsertQueueDpc(&DevExt
->DpcMouse
, DevExt
, NULL
);
526 if (DevExt
->MouseType
== Ps2pp
)
527 I8042MouseHandlePs2pp(DevExt
, Output
);
529 I8042MouseHandle(DevExt
, Output
);
534 VOID STDCALL
I8042DpcRoutineMouse(PKDPC Dpc
,
535 PVOID DeferredContext
,
536 PVOID SystemArgument1
,
537 PVOID SystemArgument2
)
539 PDEVICE_EXTENSION DevExt
= (PDEVICE_EXTENSION
)SystemArgument1
;
540 ULONG MouseTransferred
= 0;
541 ULONG MouseInBufferCopy
;
543 LARGE_INTEGER Timeout
;
545 switch (DevExt
->MouseTimeoutState
) {
547 DevExt
->MouseTimeoutState
= NoChange
;
548 if (DevExt
->MouseTimeoutActive
&&
549 !KeCancelTimer(&DevExt
->TimerMouseTimeout
)) {
550 /* The timer fired already, give up */
551 DevExt
->MouseTimeoutActive
= FALSE
;
555 Timeout
.QuadPart
= -15000000;
556 /* 1.5 seconds, should be enough */
558 KeSetTimer(&DevExt
->TimerMouseTimeout
,
560 &DevExt
->DpcMouseTimeout
);
561 DevExt
->MouseTimeoutActive
= TRUE
;
564 DevExt
->MouseTimeoutState
= NoChange
;
565 KeCancelTimer(&DevExt
->TimerMouseTimeout
);
566 DevExt
->MouseTimeoutActive
= FALSE
;
568 /* nothing, don't want a warning */ ;
571 /* Should be unlikely */
572 if (!DevExt
->MouseComplete
)
575 Irql
= KeAcquireInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
);
577 DevExt
->MouseComplete
= FALSE
;
578 MouseInBufferCopy
= DevExt
->MouseInBuffer
;
580 KeReleaseInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
, Irql
);
582 DPRINT ("Send a mouse packet\n");
584 if (!DevExt
->MouseData
.ClassService
)
587 ((MOUSE_CLASS_SERVICE_CALLBACK
) DevExt
->MouseData
.ClassService
)(
588 DevExt
->MouseData
.ClassDeviceObject
,
590 DevExt
->MouseBuffer
+ MouseInBufferCopy
,
593 Irql
= KeAcquireInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
);
595 DevExt
->MouseInBuffer
-= MouseTransferred
;
596 if (DevExt
->MouseInBuffer
)
597 RtlMoveMemory(DevExt
->MouseBuffer
,
598 DevExt
->MouseBuffer
+MouseTransferred
,
599 DevExt
->MouseInBuffer
* sizeof(MOUSE_INPUT_DATA
));
601 KeReleaseInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
, Irql
);
604 /* This timer DPC will be called when the mouse reset times out.
605 * I'll just send the 'disable mouse port' command to the controller
606 * and say the mouse doesn't exist.
608 VOID STDCALL
I8042DpcRoutineMouseTimeout(PKDPC Dpc
,
609 PVOID DeferredContext
,
610 PVOID SystemArgument1
,
611 PVOID SystemArgument2
)
613 PDEVICE_EXTENSION DevExt
= (PDEVICE_EXTENSION
)DeferredContext
;
616 Irql
= KeAcquireInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
);
618 DPRINT1("Mouse initialization timeout! (substate %x) "
619 "Disabling mouse.\n",
620 DevExt
->MouseResetState
);
622 if (!I8042MouseDisable(DevExt
)) {
623 DPRINT1("Failed to disable mouse.\n");
626 DevExt
->MouseExists
= FALSE
;
628 KeReleaseInterruptSpinLock(DevExt
->HighestDIRQLInterrupt
, Irql
);
632 * Process the mouse internal device requests
633 * returns FALSE if it doesn't understand the
634 * call so someone else can handle it.
636 BOOLEAN STDCALL
I8042StartIoMouse(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
638 PIO_STACK_LOCATION Stk
;
639 PFDO_DEVICE_EXTENSION FdoDevExt
= DeviceObject
->DeviceExtension
;
640 PDEVICE_EXTENSION DevExt
= FdoDevExt
->PortDevExt
;
642 Stk
= IoGetCurrentIrpStackLocation(Irp
);
644 switch (Stk
->Parameters
.DeviceIoControl
.IoControlCode
) {
645 case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER
:
649 Stk
->Parameters
.DeviceIoControl
.Type3InputBuffer
,
650 Stk
->Parameters
.DeviceIoControl
.InputBufferLength
,
662 * Runs the mouse IOCTL_INTERNAL dispatch.
663 * Returns NTSTATUS_INVALID_DEVICE_REQUEST if it doesn't handle this request
664 * so someone else can have a try at it.
666 NTSTATUS STDCALL
I8042InternalDeviceControlMouse(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
668 PIO_STACK_LOCATION Stk
;
669 PFDO_DEVICE_EXTENSION FdoDevExt
= DeviceObject
->DeviceExtension
;
670 PDEVICE_EXTENSION DevExt
= FdoDevExt
->PortDevExt
;
672 DPRINT("InternalDeviceControl\n");
674 Irp
->IoStatus
.Information
= 0;
675 Stk
= IoGetCurrentIrpStackLocation(Irp
);
677 switch (Stk
->Parameters
.DeviceIoControl
.IoControlCode
) {
679 case IOCTL_INTERNAL_MOUSE_CONNECT
:
680 DPRINT("IOCTL_INTERNAL_MOUSE_CONNECT\n");
681 if (Stk
->Parameters
.DeviceIoControl
.InputBufferLength
<
682 sizeof(CONNECT_DATA
)) {
683 DPRINT1("Mouse IOCTL_INTERNAL_MOUSE_CONNECT "
684 "invalid buffer size\n");
685 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
689 if (!DevExt
->MouseExists
) {
690 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_CONNECTED
;
694 if (DevExt
->MouseClaimed
) {
695 DPRINT1("IOCTL_INTERNAL_MOUSE_CONNECT: "
696 "Mouse is already claimed\n");
697 Irp
->IoStatus
.Status
= STATUS_SHARING_VIOLATION
;
701 memcpy(&DevExt
->MouseData
,
702 Stk
->Parameters
.DeviceIoControl
.Type3InputBuffer
,
703 sizeof(CONNECT_DATA
));
704 DevExt
->MouseHook
.IsrWritePort
= I8042IsrWritePortMouse
;
705 DevExt
->MouseHook
.QueueMousePacket
=
706 I8042QueueMousePacket
;
707 DevExt
->MouseHook
.CallContext
= DevExt
;
710 PIO_WORKITEM WorkItem
;
711 PI8042_HOOK_WORKITEM WorkItemData
;
713 WorkItem
= IoAllocateWorkItem(DeviceObject
);
715 DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
716 "Can't allocate work item\n");
717 Irp
->IoStatus
.Status
=
718 STATUS_INSUFFICIENT_RESOURCES
;
722 WorkItemData
= ExAllocatePoolWithTag(
724 sizeof(I8042_HOOK_WORKITEM
),
727 DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
728 "Can't allocate work item data\n");
729 Irp
->IoStatus
.Status
=
730 STATUS_INSUFFICIENT_RESOURCES
;
731 IoFreeWorkItem(WorkItem
);
734 WorkItemData
->WorkItem
= WorkItem
;
735 WorkItemData
->Target
=
736 DevExt
->MouseData
.ClassDeviceObject
;
737 WorkItemData
->Irp
= Irp
;
739 IoMarkIrpPending(Irp
);
740 DevExt
->MouseState
= MouseResetting
;
741 DevExt
->MouseResetState
= 1100;
742 IoQueueWorkItem(WorkItem
,
743 I8042SendHookWorkItem
,
747 Irp
->IoStatus
.Status
= STATUS_PENDING
;
751 case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER
:
752 DPRINT("IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER\n");
753 if (Stk
->Parameters
.DeviceIoControl
.InputBufferLength
< 1) {
754 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
757 if (!DevExt
->MouseInterruptObject
) {
758 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_READY
;
762 IoMarkIrpPending(Irp
);
763 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
764 Irp
->IoStatus
.Status
= STATUS_PENDING
;
767 case IOCTL_MOUSE_QUERY_ATTRIBUTES
:
768 DPRINT("IOCTL_MOUSE_QUERY_ATTRIBUTES\n");
769 if (Stk
->Parameters
.DeviceIoControl
.InputBufferLength
<
770 sizeof(MOUSE_ATTRIBUTES
)) {
771 DPRINT("Mouse IOCTL_MOUSE_QUERY_ATTRIBUTES "
772 "invalid buffer size\n");
773 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
776 memcpy(Irp
->AssociatedIrp
.SystemBuffer
,
777 &DevExt
->MouseAttributes
,
778 sizeof(MOUSE_ATTRIBUTES
));
780 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
783 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
788 return Irp
->IoStatus
.Status
;
791 BOOLEAN STDCALL
I8042MouseEnable(PDEVICE_EXTENSION DevExt
)
796 DPRINT("Enabling mouse\n");
798 if (!I8042Write(DevExt
, I8042_CTRL_PORT
, KBD_READ_MODE
)) {
799 DPRINT1("Can't read i8042 mode\n");
803 Status
= I8042ReadDataWait(DevExt
, &Value
);
804 if (Status
!= STATUS_SUCCESS
) {
805 DPRINT1("No response after read i8042 mode\n");
809 Value
&= ~(0x20); // don't disable mouse
810 Value
|= 0x02; // enable mouse interrupts
812 if (!I8042Write(DevExt
, I8042_CTRL_PORT
, KBD_WRITE_MODE
)) {
813 DPRINT1("Can't set i8042 mode\n");
817 if (!I8042Write(DevExt
, I8042_DATA_PORT
, Value
)) {
818 DPRINT1("Can't send i8042 mode\n");
825 BOOLEAN STDCALL
I8042MouseDisable(PDEVICE_EXTENSION DevExt
)
830 DPRINT("Disabling mouse\n");
832 I8042Flush(); /* Just to be (kind of) sure */
834 if (!I8042Write(DevExt
, I8042_CTRL_PORT
, KBD_READ_MODE
)) {
835 DPRINT1("Can't read i8042 mode\n");
839 Status
= I8042ReadDataWait(DevExt
, &Value
);
840 if (Status
!= STATUS_SUCCESS
) {
841 DPRINT1("No response after read i8042 mode\n");
845 Value
|= 0x20; // don't disable mouse
846 Value
&= ~(0x02); // enable mouse interrupts
848 if (!I8042Write(DevExt
, I8042_CTRL_PORT
, KBD_WRITE_MODE
)) {
849 DPRINT1("Can't set i8042 mode\n");
853 if (!I8042Write(DevExt
, I8042_DATA_PORT
, Value
)) {
854 DPRINT1("Can't send i8042 mode\n");
859 /* Just to be (kind of) sure; if the mouse would
860 * say something while we are disabling it, these bytes would
861 * block the keyboard.