fixed some warnings when compiling with -O3
[reactos.git] / reactos / drivers / input / i8042prt / mouse.c
1 /*
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
6 * mouse specifics
7 * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
8 * Jason Filby (jasonfilby@yahoo.com)
9 * Tinus
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <ddk/ntddkbd.h>
16 #include <ddk/ntdd8042.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21 #include "i8042prt.h"
22
23 /*
24 * These functions are callbacks for filter driver custom interrupt
25 * service routines.
26 */
27 VOID STDCALL I8042IsrWritePortMouse(PVOID Context,
28 UCHAR Value)
29 {
30 I8042IsrWritePort(Context, Value, 0xD4);
31 }
32
33 NTSTATUS STDCALL I8042SynchWritePortMouse(PVOID Context,
34 UCHAR Value,
35 BOOLEAN WaitForAck)
36 {
37 return I8042SynchWritePort((PDEVICE_EXTENSION)Context,
38 0xD4,
39 Value,
40 WaitForAck);
41 }
42
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.
45 *
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.
52 */
53 static VOID STDCALL I8042MouseInputTestTimeout(PDEVICE_EXTENSION DevExt)
54 {
55 ULARGE_INTEGER Now;
56
57 if (DevExt->MouseState == MouseExpectingACK ||
58 DevExt->MouseState == MouseResetting)
59 return;
60
61 Now.QuadPart = KeQueryInterruptTime();
62
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;
69 }
70 }
71
72 if (DevExt->MouseState == MouseIdle)
73 DevExt->MousePacketStartTime.QuadPart = Now.QuadPart;
74 }
75
76 /*
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)
81 */
82 BOOLEAN STDCALL I8042MouseCallIsrHook(PDEVICE_EXTENSION DevExt,
83 UCHAR Status,
84 PUCHAR Input,
85 PBOOLEAN ToReturn)
86 {
87 BOOLEAN HookReturn, HookContinue;
88
89 HookContinue = FALSE;
90
91 if (DevExt->MouseHook.IsrRoutine) {
92 HookReturn = DevExt->MouseHook.IsrRoutine(
93 DevExt->MouseHook.Context,
94 DevExt->MouseBuffer + DevExt->MouseInBuffer,
95 &DevExt->Packet,
96 Status,
97 Input,
98 &HookContinue,
99 &DevExt->MouseState,
100 &DevExt->MouseResetState);
101
102 if (!HookContinue) {
103 *ToReturn = HookReturn;
104 return TRUE;
105 }
106 }
107 return FALSE;
108 }
109
110 BOOLEAN STDCALL I8042MouseResetIsr(PDEVICE_EXTENSION DevExt,
111 UCHAR Status,
112 PUCHAR Value)
113 {
114 BOOLEAN ToReturn = FALSE;
115
116 if (I8042MouseCallIsrHook(DevExt, Status, Value, &ToReturn))
117 return ToReturn;
118
119 if (MouseResetting != DevExt->MouseState) {
120 return FALSE;
121 }
122 DevExt->MouseTimeoutState = TimeoutStart;
123
124 switch (DevExt->MouseResetState) {
125 case 1100: /* the first ack, drop it. */
126 DevExt->MouseResetState = ExpectingReset;
127 return TRUE;
128 /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok,
129 * FC00 if not.
130 */
131 case ExpectingReset:
132 if (0xAA == *Value) {
133 DevExt->MouseResetState++;
134 } else {
135 DevExt->MouseExists = FALSE;
136 DevExt->MouseState = MouseIdle;
137 DPRINT("Mouse returned bad reset reply: "
138 "%x (expected aa)\n", *Value);
139 }
140 return TRUE;
141 case ExpectingResetId:
142 if (0x00 == *Value) {
143 DevExt->MouseResetState++;
144 DevExt->MouseType = GenericPS2;
145 I8042IsrWritePortMouse(DevExt, 0xF2);
146 } else {
147 DevExt->MouseExists = FALSE;
148 DevExt->MouseState = MouseIdle;
149 DPRINT1("Mouse returned bad reset reply part two: "
150 "%x (expected 0)\n", Value);
151 }
152 return TRUE;
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",
162 *Value, MOUSE_ACK);
163 *Value = 0;
164 I8042MouseResetIsr(DevExt, Status, Value);
165 }
166 return TRUE;
167 case ExpectingGetDeviceIdValue:
168 switch (*Value) {
169 case 0x02:
170 DevExt->MouseAttributes.MouseIdentifier =
171 BALLPOINT_I8042_HARDWARE;
172 break;
173 case 0x03:
174 case 0x04:
175 DevExt->MouseAttributes.MouseIdentifier =
176 WHEELMOUSE_I8042_HARDWARE;
177 break;
178 default:
179 DevExt->MouseAttributes.MouseIdentifier =
180 MOUSE_I8042_HARDWARE;
181 }
182 DevExt->MouseResetState++;
183 I8042IsrWritePortMouse(DevExt, 0xE8);
184 return TRUE;
185 case ExpectingSetResolutionDefaultACK:
186 DevExt->MouseResetState++;
187 I8042IsrWritePortMouse(DevExt, 0x00);
188 return TRUE;
189 case ExpectingSetResolutionDefaultValueACK:
190 DevExt->MouseResetState = ExpectingSetScaling1to1ACK;
191 I8042IsrWritePortMouse(DevExt, 0xE6);
192 return TRUE;
193 case ExpectingSetScaling1to1ACK:
194 case ExpectingSetScaling1to1ACK2:
195 DevExt->MouseResetState++;
196 I8042IsrWritePortMouse(DevExt, 0xE6);
197 return TRUE;
198 case ExpectingSetScaling1to1ACK3:
199 DevExt->MouseResetState++;
200 I8042IsrWritePortMouse(DevExt, 0xE9);
201 return TRUE;
202 case ExpectingReadMouseStatusACK:
203 DevExt->MouseResetState++;
204 return TRUE;
205 case ExpectingReadMouseStatusByte1:
206 DevExt->MouseLogiBuffer[0] = *Value;
207 DevExt->MouseResetState++;
208 return TRUE;
209 case ExpectingReadMouseStatusByte2:
210 DevExt->MouseLogiBuffer[1] = *Value;
211 DevExt->MouseResetState++;
212 return TRUE;
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.
220 */
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;
231 return TRUE;
232 /* TODO: Go through EnableWheel and Enable5Buttons */
233 }
234 DevExt->MouseResetState = EnableWheel;
235 I8042MouseResetIsr(DevExt, Status, Value);
236 return TRUE;
237 case EnableWheel:
238 I8042IsrWritePortMouse(DevExt, 0xf3);
239 DevExt->MouseResetState = 1001;
240 return TRUE;
241 case 1001:
242 I8042IsrWritePortMouse(DevExt, 0xc8);
243 DevExt->MouseResetState++;
244 return TRUE;
245 case 1002:
246 case 1004:
247 I8042IsrWritePortMouse(DevExt, 0xf3);
248 DevExt->MouseResetState++;
249 return TRUE;
250 case 1003:
251 I8042IsrWritePortMouse(DevExt, 0x64);
252 DevExt->MouseResetState++;
253 return TRUE;
254 case 1005:
255 I8042IsrWritePortMouse(DevExt, 0x50);
256 DevExt->MouseResetState++;
257 return TRUE;
258 case 1006:
259 I8042IsrWritePortMouse(DevExt, 0xf2);
260 DevExt->MouseResetState++;
261 return TRUE;
262 case 1007:
263 /* Ignore ACK */
264 DevExt->MouseResetState++;
265 return TRUE;
266 case 1008:
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);
276 return TRUE;
277 } /* Else, just set the default settings and be done */
278 I8042IsrWritePortMouse(DevExt, 0xf3);
279 DevExt->MouseResetState = ExpectingSetSamplingRateACK;
280 return TRUE;
281 case Enable5Buttons:
282 I8042IsrWritePortMouse(DevExt, 0xf3);
283 DevExt->MouseResetState = 1021;
284 return TRUE;
285 case 1022:
286 case 1024:
287 I8042IsrWritePortMouse(DevExt, 0xf3);
288 DevExt->MouseResetState++;
289 return TRUE;
290 case 1021:
291 case 1023:
292 I8042IsrWritePortMouse(DevExt, 0xc8);
293 DevExt->MouseResetState++;
294 return TRUE;
295 case 1025:
296 I8042IsrWritePortMouse(DevExt, 0x50);
297 DevExt->MouseResetState++;
298 return TRUE;
299 case 1026:
300 I8042IsrWritePortMouse(DevExt, 0xf2);
301 DevExt->MouseResetState++;
302 return TRUE;
303 case 1027:
304 if (0x04 == *Value) {
305 DevExt->MouseAttributes.NumberOfButtons = 5;
306 DevExt->MouseAttributes.MouseIdentifier =
307 WHEELMOUSE_I8042_HARDWARE;
308 DevExt->MouseType = IntellimouseExplorer;
309 }
310 I8042IsrWritePortMouse(DevExt, 0xf3);
311 DevExt->MouseResetState = ExpectingSetSamplingRateACK;
312 return TRUE;
313 case ExpectingSetSamplingRateACK:
314 I8042IsrWritePortMouse(DevExt,
315 DevExt->MouseAttributes.SampleRate);
316 DevExt->MouseResetState++;
317 return TRUE;
318 case ExpectingSetSamplingRateValueACK:
319 if (MOUSE_NACK == *Value) {
320 I8042IsrWritePortMouse(DevExt, 0x3c);
321 DevExt->MouseAttributes.SampleRate = 60;
322 DevExt->MouseResetState = 1040;
323 return TRUE;
324 }
325 case 1040: /* Fallthrough */
326 I8042IsrWritePortMouse(DevExt, 0xe8);
327 DevExt->MouseResetState = ExpectingFinalResolutionACK;
328 return TRUE;
329 case ExpectingFinalResolutionACK:
330 I8042IsrWritePortMouse(DevExt,
331 DevExt->Settings.MouseResolution & 0xff);
332 DPRINT("%x\n", DevExt->Settings.MouseResolution);
333 DevExt->MouseResetState = ExpectingFinalResolutionValueACK;
334 return TRUE;
335 case ExpectingFinalResolutionValueACK:
336 I8042IsrWritePortMouse(DevExt, 0xf4);
337 DevExt->MouseResetState = ExpectingEnableACK;
338 return TRUE;
339 case ExpectingEnableACK:
340 DevExt->MouseState = MouseIdle;
341 DevExt->MouseTimeoutState = TimeoutCancel;
342 DPRINT("Mouse type = %d\n", DevExt->MouseType);
343 return TRUE;
344 default:
345 if (DevExt->MouseResetState < 100 ||
346 DevExt->MouseResetState > 999)
347 DPRINT1("MouseResetState went out of range: %d\n",
348 DevExt->MouseResetState);
349 return FALSE;
350 }
351 }
352
353 /*
354 * Prepare for reading the next packet and queue the dpc for handling
355 * this one.
356 *
357 * Context is the device object.
358 */
359 VOID STDCALL I8042QueueMousePacket(PVOID Context)
360 {
361 PDEVICE_OBJECT DeviceObject = Context;
362 PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
363 PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
364
365 DevExt->MouseComplete = TRUE;
366 DevExt->MouseInBuffer++;
367 if (DevExt->MouseInBuffer >
368 DevExt->MouseAttributes.InputDataQueueLength) {
369 DPRINT1("Mouse buffer overflow\n");
370 DevExt->MouseInBuffer--;
371 }
372
373 DPRINT("Irq completes mouse packet\n");
374 KeInsertQueueDpc(&DevExt->DpcMouse, DevExt, NULL);
375 }
376
377 /*
378 * Updates ButtonFlags according to RawButtons and a saved state;
379 * Only takes in account the bits that are set in Mask
380 */
381 VOID STDCALL I8042MouseHandleButtons(PDEVICE_EXTENSION DevExt,
382 USHORT Mask)
383 {
384 PMOUSE_INPUT_DATA MouseInput = DevExt->MouseBuffer +
385 DevExt->MouseInBuffer;
386 USHORT NewButtonData = MouseInput->RawButtons & Mask;
387 USHORT ButtonDiff = (NewButtonData ^ DevExt->MouseButtonState) & Mask;
388
389 /* Note that the defines are such:
390 * MOUSE_LEFT_BUTTON_DOWN 1
391 * MOUSE_LEFT_BUTTON_UP 2
392 */
393 MouseInput->ButtonFlags |= (NewButtonData & ButtonDiff) |
394 (((~(NewButtonData)) << 1) &
395 (ButtonDiff << 1)) |
396 (MouseInput->RawButtons & 0xfc00);
397
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);
401
402 DevExt->MouseButtonState = (DevExt->MouseButtonState & ~Mask) |
403 (NewButtonData & Mask);
404 }
405
406 VOID STDCALL I8042MouseHandle(PDEVICE_EXTENSION DevExt,
407 BYTE Output)
408 {
409 PMOUSE_INPUT_DATA MouseInput = DevExt->MouseBuffer +
410 DevExt->MouseInBuffer;
411 CHAR Scroll;
412
413 switch (DevExt->MouseState) {
414 case MouseIdle:
415 /* This bit should be 1, if not drop the packet, we
416 * might be lucky and get in sync again
417 */
418 if (!(Output & 8)) {
419 DPRINT1("Bad input, dropping..\n");
420 return;
421 }
422
423 MouseInput->Buttons = 0;
424 MouseInput->RawButtons = 0;
425 MouseInput->Flags = MOUSE_MOVE_RELATIVE;
426
427 /* Note how we ignore the overflow bits, like Windows
428 * is said to do. There's no reasonable thing to do
429 * anyway.
430 */
431
432 if (Output & 16)
433 MouseInput->LastX = 1;
434 else
435 MouseInput->LastX = 0;
436
437 if (Output & 32)
438 MouseInput->LastY = 1;
439 else
440 MouseInput->LastY = 0;
441
442 if (Output & 1) {
443 MouseInput->RawButtons |= MOUSE_LEFT_BUTTON_DOWN;
444 }
445
446 if (Output & 2) {
447 MouseInput->RawButtons |= MOUSE_RIGHT_BUTTON_DOWN;
448 }
449
450 if (Output & 4) {
451 MouseInput->RawButtons |= MOUSE_MIDDLE_BUTTON_DOWN;
452 }
453 DevExt->MouseState = XMovement;
454 break;
455 case XMovement:
456 if (MouseInput->LastX)
457 MouseInput->LastX = (LONG) Output - 256;
458 else
459 MouseInput->LastX = Output;
460
461 DevExt->MouseState = YMovement;
462 break;
463 case YMovement:
464 if (MouseInput->LastY)
465 MouseInput->LastY = (LONG)Output - 256;
466 else
467 MouseInput->LastY = (LONG)Output;
468
469 /* Windows wants it the other way around */
470 MouseInput->LastY = -MouseInput->LastY;
471
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;
481 } else {
482 DevExt->MouseState = ZMovement;
483 }
484 break;
485 case ZMovement:
486 Scroll = Output & 0x0f;
487 if (Scroll & 8)
488 Scroll |= 0xf0;
489
490 if (Scroll) {
491 MouseInput->RawButtons |= MOUSE_WHEEL;
492 MouseInput->ButtonData = (USHORT)(Scroll * -WHEEL_DELTA);
493 }
494
495 if (DevExt->MouseType == IntellimouseExplorer) {
496 if (Output & 16)
497 MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
498
499 if (Output & 32)
500 MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
501 }
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;
509 break;
510 default:
511 DPRINT1("Unexpected state!\n");
512 }
513 }
514
515 BOOLEAN STDCALL I8042InterruptServiceMouse(struct _KINTERRUPT *Interrupt,
516 VOID *Context)
517 {
518 BYTE Output, PortStatus;
519 NTSTATUS Status;
520 PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) Context;
521 UINT Iterations = 0;
522
523 do {
524 Status = I8042ReadStatus(&PortStatus);
525 Status = I8042ReadData(&Output);
526 Iterations++;
527 if (STATUS_SUCCESS == Status)
528 break;
529 KeStallExecutionProcessor(1);
530 } while (Iterations < DevExt->Settings.PollStatusIterations);
531
532 if (STATUS_SUCCESS != Status) {
533 DPRINT1("Spurious I8042 mouse interrupt\n");
534 return FALSE;
535 }
536
537 DPRINT("Got: %x\n", Output);
538
539 if (I8042PacketIsr(DevExt, Output)) {
540 if (DevExt->PacketComplete) {
541 DPRINT("Packet complete\n");
542 KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
543 }
544 DPRINT("Irq eaten by packet\n");
545 return TRUE;
546 }
547
548 I8042MouseInputTestTimeout(DevExt);
549
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);
554 }
555 return TRUE;
556 }
557
558 if (DevExt->MouseType == Ps2pp)
559 I8042MouseHandlePs2pp(DevExt, Output);
560 else
561 I8042MouseHandle(DevExt, Output);
562
563 return TRUE;
564 }
565
566 VOID STDCALL I8042DpcRoutineMouse(PKDPC Dpc,
567 PVOID DeferredContext,
568 PVOID SystemArgument1,
569 PVOID SystemArgument2)
570 {
571 PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)SystemArgument1;
572 ULONG MouseTransferred = 0;
573 ULONG MouseInBufferCopy;
574 KIRQL Irql;
575 LARGE_INTEGER Timeout;
576
577 switch (DevExt->MouseTimeoutState) {
578 case TimeoutStart:
579 DevExt->MouseTimeoutState = NoChange;
580 if (DevExt->MouseTimeoutActive &&
581 !KeCancelTimer(&DevExt->TimerMouseTimeout)) {
582 /* The timer fired already, give up */
583 DevExt->MouseTimeoutActive = FALSE;
584 return;
585 }
586
587 Timeout.QuadPart = -15000000;
588 /* 1.5 seconds, should be enough */
589
590 KeSetTimer(&DevExt->TimerMouseTimeout,
591 Timeout,
592 &DevExt->DpcMouseTimeout);
593 DevExt->MouseTimeoutActive = TRUE;
594 return;
595 case TimeoutCancel:
596 DevExt->MouseTimeoutState = NoChange;
597 KeCancelTimer(&DevExt->TimerMouseTimeout);
598 DevExt->MouseTimeoutActive = FALSE;
599 default:
600 /* nothing, don't want a warning */ ;
601 }
602
603 /* Should be unlikely */
604 if (!DevExt->MouseComplete)
605 return;
606
607 Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
608
609 DevExt->MouseComplete = FALSE;
610 MouseInBufferCopy = DevExt->MouseInBuffer;
611
612 KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
613
614 DPRINT ("Send a mouse packet\n");
615
616 if (!DevExt->MouseData.ClassService)
617 return;
618
619 ((MOUSE_CLASS_SERVICE_CALLBACK) DevExt->MouseData.ClassService)(
620 DevExt->MouseData.ClassDeviceObject,
621 DevExt->MouseBuffer,
622 DevExt->MouseBuffer + MouseInBufferCopy,
623 &MouseTransferred);
624
625 Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
626
627 DevExt->MouseInBuffer -= MouseTransferred;
628 if (DevExt->MouseInBuffer)
629 RtlMoveMemory(DevExt->MouseBuffer,
630 DevExt->MouseBuffer+MouseTransferred,
631 DevExt->MouseInBuffer * sizeof(MOUSE_INPUT_DATA));
632
633 KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
634 }
635
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.
639 */
640 VOID STDCALL I8042DpcRoutineMouseTimeout(PKDPC Dpc,
641 PVOID DeferredContext,
642 PVOID SystemArgument1,
643 PVOID SystemArgument2)
644 {
645 PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)DeferredContext;
646 KIRQL Irql;
647
648 Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
649
650 DPRINT1("Mouse initialization timeout! (substate %x) "
651 "Disabling mouse.\n",
652 DevExt->MouseResetState);
653
654 if (!I8042MouseDisable(DevExt)) {
655 DPRINT1("Failed to disable mouse.\n");
656 }
657
658 DevExt->MouseExists = FALSE;
659
660 KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
661 }
662
663 /*
664 * Process the mouse internal device requests
665 * returns FALSE if it doesn't understand the
666 * call so someone else can handle it.
667 */
668 BOOLEAN STDCALL I8042StartIoMouse(PDEVICE_OBJECT DeviceObject, PIRP Irp)
669 {
670 PIO_STACK_LOCATION Stk;
671 PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
672 PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
673
674 Stk = IoGetCurrentIrpStackLocation(Irp);
675
676 switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
677 case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
678 I8042StartPacket(
679 DevExt,
680 DeviceObject,
681 Stk->Parameters.DeviceIoControl.Type3InputBuffer,
682 Stk->Parameters.DeviceIoControl.InputBufferLength,
683 Irp);
684 break;
685
686 default:
687 return FALSE;
688 }
689
690 return TRUE;
691 }
692
693 /*
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.
697 */
698 NTSTATUS STDCALL I8042InternalDeviceControlMouse(PDEVICE_OBJECT DeviceObject, PIRP Irp)
699 {
700 PIO_STACK_LOCATION Stk;
701 PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
702 PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
703
704 DPRINT("InternalDeviceControl\n");
705
706 Irp->IoStatus.Information = 0;
707 Stk = IoGetCurrentIrpStackLocation(Irp);
708
709 switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
710
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;
718 goto intcontfailure;
719 }
720
721 if (!DevExt->MouseExists) {
722 Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
723 goto intcontfailure;
724 }
725
726 if (DevExt->MouseClaimed) {
727 DPRINT1("IOCTL_INTERNAL_MOUSE_CONNECT: "
728 "Mouse is already claimed\n");
729 Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
730 goto intcontfailure;
731 }
732
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;
740
741 {
742 PIO_WORKITEM WorkItem;
743 PI8042_HOOK_WORKITEM WorkItemData;
744
745 WorkItem = IoAllocateWorkItem(DeviceObject);
746 if (!WorkItem) {
747 DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
748 "Can't allocate work item\n");
749 Irp->IoStatus.Status =
750 STATUS_INSUFFICIENT_RESOURCES;
751 goto intcontfailure;
752 }
753
754 WorkItemData = ExAllocatePoolWithTag(
755 NonPagedPool,
756 sizeof(I8042_HOOK_WORKITEM),
757 TAG_I8042);
758 if (!WorkItemData) {
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);
764 goto intcontfailure;
765 }
766 WorkItemData->WorkItem = WorkItem;
767 WorkItemData->Target =
768 DevExt->MouseData.ClassDeviceObject;
769 WorkItemData->Irp = Irp;
770
771 IoMarkIrpPending(Irp);
772 DevExt->MouseState = MouseResetting;
773 DevExt->MouseResetState = 1100;
774 IoQueueWorkItem(WorkItem,
775 I8042SendHookWorkItem,
776 DelayedWorkQueue,
777 WorkItemData);
778
779 Irp->IoStatus.Status = STATUS_PENDING;
780 }
781
782 break;
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;
787 goto intcontfailure;
788 }
789 if (!DevExt->MouseInterruptObject) {
790 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
791 goto intcontfailure;
792 }
793
794 IoMarkIrpPending(Irp);
795 IoStartPacket(DeviceObject, Irp, NULL, NULL);
796 Irp->IoStatus.Status = STATUS_PENDING;
797
798 break;
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;
806 goto intcontfailure;
807 }
808 memcpy(Irp->AssociatedIrp.SystemBuffer,
809 &DevExt->MouseAttributes,
810 sizeof(MOUSE_ATTRIBUTES));
811
812 Irp->IoStatus.Status = STATUS_SUCCESS;
813 break;
814 default:
815 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
816 break;
817 }
818
819 intcontfailure:
820 return Irp->IoStatus.Status;
821 }
822
823 BOOLEAN STDCALL I8042MouseEnable(PDEVICE_EXTENSION DevExt)
824 {
825 UCHAR Value;
826 NTSTATUS Status;
827
828 DPRINT("Enabling mouse\n");
829
830 if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
831 DPRINT1("Can't read i8042 mode\n");
832 return FALSE;
833 }
834
835 Status = I8042ReadDataWait(DevExt, &Value);
836 if (Status != STATUS_SUCCESS) {
837 DPRINT1("No response after read i8042 mode\n");
838 return FALSE;
839 }
840
841 Value &= ~(0x20); // don't disable mouse
842 Value |= 0x02; // enable mouse interrupts
843
844 if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
845 DPRINT1("Can't set i8042 mode\n");
846 return FALSE;
847 }
848
849 if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
850 DPRINT1("Can't send i8042 mode\n");
851 return FALSE;
852 }
853
854 return TRUE;
855 }
856
857 BOOLEAN STDCALL I8042MouseDisable(PDEVICE_EXTENSION DevExt)
858 {
859 UCHAR Value;
860 NTSTATUS Status;
861
862 DPRINT("Disabling mouse\n");
863
864 I8042Flush(); /* Just to be (kind of) sure */
865
866 if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
867 DPRINT1("Can't read i8042 mode\n");
868 return FALSE;
869 }
870
871 Status = I8042ReadDataWait(DevExt, &Value);
872 if (Status != STATUS_SUCCESS) {
873 DPRINT1("No response after read i8042 mode\n");
874 return FALSE;
875 }
876
877 Value |= 0x20; // don't disable mouse
878 Value &= ~(0x02); // enable mouse interrupts
879
880 if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
881 DPRINT1("Can't set i8042 mode\n");
882 return FALSE;
883 }
884
885 if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
886 DPRINT1("Can't send i8042 mode\n");
887 return FALSE;
888 }
889
890 I8042Flush();
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.
894 */
895
896 return TRUE;
897 }