VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/i8042prt/moudep.c@ 21226

Last change on this file since 21226 was 21226, checked in by vboxsync, 15 years ago

VMMDev.h: cleanup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.8 KB
Line 
1
2/*++
3
4Copyright (c) 1990, 1991, 1992, 1993 Microsoft Corporation
5
6Module Name:
7
8 moudep.c
9
10Abstract:
11
12 The initialization and hardware-dependent portions of
13 the Intel i8042 port driver which are specific to
14 the auxiliary (PS/2 mouse) device.
15
16Environment:
17
18 Kernel mode only.
19
20Notes:
21
22 NOTES: (Future/outstanding issues)
23
24 - Powerfail not implemented.
25
26 - Consolidate duplicate code, where possible and appropriate.
27
28Revision History:
29
30--*/
31
32// VBOX begin
33// VBOX backdoor logging
34//#define LOG_ENABLED
35#include <VBox/err.h>
36// VBOX end
37
38#include "stdarg.h"
39#include "stdio.h"
40#include "string.h"
41#include "ntddk.h"
42#include "i8042prt.h"
43#include "i8042log.h"
44
45//
46// Use the alloc_text pragma to specify the driver initialization routines
47// (they can be paged out).
48//
49
50#ifdef ALLOC_PRAGMA
51#pragma alloc_text(INIT,I8xMouseConfiguration)
52#pragma alloc_text(INIT,I8xMousePeripheralCallout)
53#pragma alloc_text(INIT,I8xInitializeMouse)
54#pragma alloc_text(INIT,I8xFindWheelMouse)
55#endif
56
57
58
59BOOLEAN
60I8042MouseInterruptService(
61 IN PKINTERRUPT Interrupt,
62 IN PVOID Context
63 )
64
65/*++
66
67Routine Description:
68
69 This is the interrupt service routine for the mouse device.
70
71Arguments:
72
73 Interrupt - A pointer to the interrupt object for this interrupt.
74
75 Context - A pointer to the device object.
76
77Return Value:
78
79 Returns TRUE if the interrupt was expected (and therefore processed);
80 otherwise, FALSE is returned.
81
82--*/
83
84{
85 PDEVICE_EXTENSION deviceExtension;
86 PDEVICE_OBJECT deviceObject;
87 LARGE_INTEGER tickDelta, newTick;
88 UCHAR previousButtons;
89 UCHAR previousSignAndOverflow;
90 UCHAR byte;
91
92 UNREFERENCED_PARAMETER(Interrupt);
93
94 I8xPrint((2, "I8042PRT-I8042MouseInterruptService: enter\n"));
95
96 deviceObject = (PDEVICE_OBJECT) Context;
97 deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
98
99 //
100 // Verify that this device really interrupted. Check the status
101 // register. The Output Buffer Full bit should be set, and the
102 // Auxiliary Device Output Buffer Full bit should be set.
103 //
104
105 if ((I8X_GET_STATUS_BYTE(deviceExtension->DeviceRegisters[CommandPort])
106 & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
107 != (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL)) {
108
109 //
110 // Stall and then try again. The Olivetti MIPS machine
111 // sometimes gets a mouse interrupt before the status
112 // register is set.
113 //
114
115 KeStallExecutionProcessor(10);
116 if ((I8X_GET_STATUS_BYTE(deviceExtension->DeviceRegisters[CommandPort])
117 & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
118 != (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL)) {
119
120 //
121 // Not our interrupt.
122 //
123
124 I8xPrint((
125 1,
126 "I8042PRT-I8042MouseInterruptService: not our interrupt!\n"
127 ));
128 return(FALSE);
129 }
130 }
131
132 //
133 // Read the byte from the i8042 data port.
134 //
135
136 I8xGetByteAsynchronous(
137 (CCHAR) MouseDeviceType,
138 deviceExtension,
139 &byte
140 );
141
142 I8xPrint((
143 3,
144 "I8042PRT-I8042MouseInterruptService: byte 0x%x\n",
145 byte
146 ));
147
148 //
149 // Watch the data stream for a reset completion (0xaa) followed by the
150 // device id
151 //
152 // this pattern can appear as part of a normal data packet as well. This
153 // code assumes that sending an enable to an already enabled mouse will:
154 // * not hang the mouse
155 // * abort the current packet and return an ACK.
156 //
157
158 if((deviceExtension->MouseExtension.LastByteReceived == 0xaa) &&
159 (byte == 0x00)) {
160
161 PIO_ERROR_LOG_PACKET errorLogEntry;
162 UCHAR errorPacketSize;
163
164 I8xPrint((
165 1,
166 "I8042PRT-18042MouseInterruptService: reset detected in "
167 "data stream - current state is %d\n",
168 deviceExtension->MouseExtension.InputState
169 ));
170
171 //
172 // Log a message/warning that the mouse has been reset - this should
173 // help us track down any wierd problems in the field
174 //
175
176 errorPacketSize = sizeof(IO_ERROR_LOG_PACKET);
177
178 errorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(
179 deviceObject,
180 errorPacketSize
181 );
182
183 if (errorLogEntry != NULL) {
184
185 //
186 // If a reset occurred with the wheel mouse enabled make the message
187 // a warning and include the fact that the wheel is disabled in the
188 // message text
189 //
190
191 if(deviceExtension->HardwarePresent & WHEELMOUSE_HARDWARE_PRESENT) {
192 errorLogEntry->ErrorCode = I8042_UNEXPECTED_WHEEL_MOUSE_RESET;
193 } else {
194 errorLogEntry->ErrorCode = I8042_UNEXPECTED_MOUSE_RESET;
195 }
196
197 errorLogEntry->DumpDataSize = 0;
198 errorLogEntry->SequenceNumber = 0;
199 errorLogEntry->MajorFunctionCode = 0;
200 errorLogEntry->IoControlCode = 0;
201 errorLogEntry->RetryCount = 0;
202 errorLogEntry->UniqueErrorValue = 0xaa00;
203 errorLogEntry->FinalStatus = 0;
204
205 IoWriteErrorLogEntry(errorLogEntry);
206 }
207
208 deviceExtension->HardwarePresent &= ~WHEELMOUSE_HARDWARE_PRESENT;
209 deviceExtension->Configuration.MouseAttributes.NumberOfButtons = 2;
210
211 //
212 // send the command to enable the mouse and wait for acknowledge.
213 //
214 // NOTE - this should be synchronized with the keyboard code
215 //
216
217 I8xPutByteAsynchronous(
218 (CCHAR) CommandPort,
219 deviceExtension,
220 (UCHAR) I8042_WRITE_TO_AUXILIARY_DEVICE
221 );
222
223 I8xPutByteAsynchronous(
224 (CCHAR) DataPort,
225 deviceExtension,
226 (UCHAR) ENABLE_MOUSE_TRANSMISSION
227 );
228
229 //
230 // Set up state machine to look for acknowledgement.
231 //
232
233 deviceExtension->MouseExtension.InputState = MouseExpectingACK;
234
235 }
236
237 deviceExtension->MouseExtension.LastByteReceived = byte;
238
239 //
240 // Take the appropriate action, depending on the current state.
241 // When the state is Idle, we expect to receive mouse button
242 // data. When the state is XMovement, we expect to receive mouse
243 // motion in the X direction data. When the state is YMovement,
244 // we expect to receive mouse motion in the Y direction data. Once
245 // the Y motion data has been received, the data is queued to the
246 // mouse InputData queue, the mouse ISR DPC is requested, and the
247 // state returns to Idle.
248 //
249
250 KeQueryTickCount(&newTick);
251 tickDelta.QuadPart =
252 newTick.QuadPart -
253 deviceExtension->MouseExtension.PreviousTick.QuadPart;
254
255 if ((deviceExtension->MouseExtension.InputState != MouseIdle)
256 && (deviceExtension->MouseExtension.InputState != MouseExpectingACK)
257 && ((tickDelta.LowPart >= deviceExtension->MouseExtension.SynchTickCount)
258 || (tickDelta.HighPart != 0))) {
259
260 //
261 // It has been a long time since we got a byte of
262 // the data packet. Assume that we are now receiving
263 // the first byte of a new packet, and discard any
264 // partially received packet.
265 //
266 // N.B. We assume that SynchTickCount is ULONG, and avoid
267 // a LARGE_INTEGER compare with tickDelta...
268 //
269
270 I8xPrint((
271 1,
272 "I8042PRT-I8042MouseInterruptService: State was %d, synching\n",
273 deviceExtension->MouseExtension.InputState
274 ));
275
276 deviceExtension->MouseExtension.InputState = MouseIdle;
277 }
278
279 deviceExtension->MouseExtension.PreviousTick = newTick;
280
281 switch(deviceExtension->MouseExtension.InputState) {
282
283 //
284 // The mouse interrupted with a status byte. The status byte
285 // contains information on the mouse button state along with
286 // the sign and overflow bits for the (yet-to-be-received)
287 // X and Y motion bytes.
288 //
289
290 case MouseIdle: {
291
292 I8xPrint((
293 3,
294 "I8042PRT-I8042MouseInterruptService: mouse status byte\n"
295 ));
296
297 //
298 // Update CurrentInput with button transition data.
299 // I.e., set a button up/down bit in the Buttons field if
300 // the state of a given button has changed since we
301 // received the last packet.
302 //
303
304 previousButtons =
305 deviceExtension->MouseExtension.PreviousButtons;
306
307 deviceExtension->MouseExtension.CurrentInput.ButtonFlags = 0;
308 deviceExtension->MouseExtension.CurrentInput.ButtonData = 0;
309
310 if ((!(previousButtons & LEFT_BUTTON_DOWN))
311 && (byte & LEFT_BUTTON_DOWN)) {
312 deviceExtension->MouseExtension.CurrentInput.ButtonFlags |=
313 MOUSE_LEFT_BUTTON_DOWN;
314 } else
315 if ((previousButtons & LEFT_BUTTON_DOWN)
316 && !(byte & LEFT_BUTTON_DOWN)) {
317 deviceExtension->MouseExtension.CurrentInput.ButtonFlags |=
318 MOUSE_LEFT_BUTTON_UP;
319 }
320 if ((!(previousButtons & RIGHT_BUTTON_DOWN))
321 && (byte & RIGHT_BUTTON_DOWN)) {
322 deviceExtension->MouseExtension.CurrentInput.ButtonFlags |=
323 MOUSE_RIGHT_BUTTON_DOWN;
324 } else
325 if ((previousButtons & RIGHT_BUTTON_DOWN)
326 && !(byte & RIGHT_BUTTON_DOWN)) {
327 deviceExtension->MouseExtension.CurrentInput.ButtonFlags |=
328 MOUSE_RIGHT_BUTTON_UP;
329 }
330 if ((!(previousButtons & MIDDLE_BUTTON_DOWN))
331 && (byte & MIDDLE_BUTTON_DOWN)) {
332 deviceExtension->MouseExtension.CurrentInput.ButtonFlags |=
333 MOUSE_MIDDLE_BUTTON_DOWN;
334 } else
335 if ((previousButtons & MIDDLE_BUTTON_DOWN)
336 && !(byte & MIDDLE_BUTTON_DOWN)) {
337 deviceExtension->MouseExtension.CurrentInput.ButtonFlags |=
338 MOUSE_MIDDLE_BUTTON_UP;
339 }
340
341 //
342 // Save the button state for comparison the next time around.
343 //
344
345 deviceExtension->MouseExtension.PreviousButtons =
346 byte & (RIGHT_BUTTON_DOWN|MIDDLE_BUTTON_DOWN|LEFT_BUTTON_DOWN);
347
348 //
349 // Save the sign and overflow information from the current byte.
350 //
351
352 deviceExtension->MouseExtension.CurrentSignAndOverflow =
353 (UCHAR) (byte & MOUSE_SIGN_OVERFLOW_MASK);
354
355 //
356 // Update to the next state.
357 //
358
359 deviceExtension->MouseExtension.InputState = XMovement;
360
361 break;
362 }
363
364 //
365 // The mouse interrupted with the X motion byte. Apply
366 // the sign and overflow bits from the mouse status byte received
367 // previously. Attempt to correct for bogus changes in sign
368 // that occur with large, rapid mouse movements.
369 //
370
371 case XMovement: {
372
373 I8xPrint((
374 3,
375 "I8042PRT-I8042MouseInterruptService: mouse LastX byte\n"
376 ));
377
378 //
379 // Update CurrentInput with the X motion data.
380 //
381
382 if (deviceExtension->MouseExtension.CurrentSignAndOverflow
383 & X_OVERFLOW) {
384
385 //
386 // Handle overflow in the X direction. If the previous
387 // mouse movement overflowed too, ensure that the current
388 // overflow is in the same direction (i.e., that the sign
389 // is the same as it was for the previous event). We do this
390 // to correct for hardware problems -- it should not be possible
391 // to overflow in one direction and then immediately overflow
392 // in the opposite direction.
393 //
394
395 previousSignAndOverflow =
396 deviceExtension->MouseExtension.PreviousSignAndOverflow;
397 if (previousSignAndOverflow & X_OVERFLOW) {
398 if ((previousSignAndOverflow & X_DATA_SIGN) !=
399 (deviceExtension->MouseExtension.CurrentSignAndOverflow
400 & X_DATA_SIGN)) {
401 deviceExtension->MouseExtension.CurrentSignAndOverflow
402 ^= X_DATA_SIGN;
403 }
404 }
405
406 if (deviceExtension->MouseExtension.CurrentSignAndOverflow &
407 X_DATA_SIGN)
408 deviceExtension->MouseExtension.CurrentInput.LastX =
409 (LONG) MOUSE_MAXIMUM_NEGATIVE_DELTA;
410 else
411 deviceExtension->MouseExtension.CurrentInput.LastX =
412 (LONG) MOUSE_MAXIMUM_POSITIVE_DELTA;
413
414 } else {
415
416 //
417 // No overflow. Just store the data, correcting for the
418 // sign if necessary.
419 //
420
421 deviceExtension->MouseExtension.CurrentInput.LastX =
422 (ULONG) byte;
423 if (deviceExtension->MouseExtension.CurrentSignAndOverflow &
424 X_DATA_SIGN)
425 deviceExtension->MouseExtension.CurrentInput.LastX |=
426 MOUSE_MAXIMUM_NEGATIVE_DELTA;
427 }
428
429 //
430 // Update to the next state.
431 //
432
433 deviceExtension->MouseExtension.InputState = YMovement;
434
435 break;
436 }
437
438 //
439 // The mouse interrupted with the Y motion byte. Apply
440 // the sign and overflow bits from the mouse status byte received
441 // previously. [Attempt to correct for bogus changes in sign
442 // that occur with large, rapid mouse movements.] Write the
443 // data to the mouse InputData queue, and queue the mouse ISR DPC
444 // to complete the interrupt processing.
445 //
446
447 case YMovement: {
448
449 I8xPrint((
450 3,
451 "I8042PRT-I8042MouseInterruptService: mouse LastY byte\n"
452 ));
453
454 //
455 // Update CurrentInput with the Y motion data.
456 //
457
458 if (deviceExtension->MouseExtension.CurrentSignAndOverflow
459 & Y_OVERFLOW) {
460
461 //
462 // Handle overflow in the Y direction. If the previous
463 // mouse movement overflowed too, ensure that the current
464 // overflow is in the same direction (i.e., that the sign
465 // is the same as it was for the previous event). We do this
466 // to correct for hardware problems -- it should not be possible
467 // to overflow in one direction and then immediately overflow
468 // in the opposite direction.
469 //
470
471 previousSignAndOverflow =
472 deviceExtension->MouseExtension.PreviousSignAndOverflow;
473 if (previousSignAndOverflow & Y_OVERFLOW) {
474 if ((previousSignAndOverflow & Y_DATA_SIGN) !=
475 (deviceExtension->MouseExtension.CurrentSignAndOverflow
476 & Y_DATA_SIGN)) {
477 deviceExtension->MouseExtension.CurrentSignAndOverflow
478 ^= Y_DATA_SIGN;
479 }
480 }
481
482 if (deviceExtension->MouseExtension.CurrentSignAndOverflow &
483 Y_DATA_SIGN)
484 deviceExtension->MouseExtension.CurrentInput.LastY =
485 (LONG) MOUSE_MAXIMUM_POSITIVE_DELTA;
486 else
487 deviceExtension->MouseExtension.CurrentInput.LastY =
488 (LONG) MOUSE_MAXIMUM_NEGATIVE_DELTA;
489
490 } else {
491
492 //
493 // No overflow. Just store the data, correcting for the
494 // sign if necessary.
495 //
496
497 deviceExtension->MouseExtension.CurrentInput.LastY =
498 (ULONG) byte;
499 if (deviceExtension->MouseExtension.CurrentSignAndOverflow &
500 Y_DATA_SIGN)
501 deviceExtension->MouseExtension.CurrentInput.LastY |=
502 MOUSE_MAXIMUM_NEGATIVE_DELTA;
503
504 //
505 // Negate the LastY value (the hardware reports positive
506 // motion in the direction that we consider negative).
507 //
508
509 deviceExtension->MouseExtension.CurrentInput.LastY =
510 -deviceExtension->MouseExtension.CurrentInput.LastY;
511
512 }
513
514 //
515 // Update our notion of the previous sign and overflow bits for
516 // the start of the next mouse input sequence.
517 //
518
519 deviceExtension->MouseExtension.PreviousSignAndOverflow =
520 deviceExtension->MouseExtension.CurrentSignAndOverflow;
521
522 //
523 // Choose the next state. The WheelMouse has an extra byte of data
524 // for us
525 //
526
527 if(deviceExtension->HardwarePresent & WHEELMOUSE_HARDWARE_PRESENT) {
528
529 deviceExtension->MouseExtension.InputState = ZMovement;
530
531 } else {
532// VBOX begin
533 // this field is sticky, so first reset it for original behavior
534 deviceExtension->MouseExtension.CurrentInput.Flags = MOUSE_MOVE_RELATIVE;
535
536 { // open a new scope
537 VMMDevReqMouseStatus *req = deviceExtension->reqIS;
538
539 if (req)
540 {
541 int rc = VbglGRPerform (&req->header);
542
543 if (RT_SUCCESS(rc) && RT_SUCCESS(req->header.rc))
544 {
545 if (req->mouseFeatures & VMMDEV_MOUSE_HOST_CAN_ABSOLUTE)
546 {
547 // make it an absolute move
548 deviceExtension->MouseExtension.CurrentInput.Flags = MOUSE_MOVE_ABSOLUTE;
549 deviceExtension->MouseExtension.CurrentInput.LastX = req->pointerXPos;
550 deviceExtension->MouseExtension.CurrentInput.LastY = req->pointerYPos;
551 }
552 }
553 else
554 {
555 dprintf(("i8042prt: ERROR querying mouse capabilities from VMMDev."
556 "rc = %Rrc, VMMDev rc = %Rrc\n", rc, req->header.rc));
557 }
558 }
559 } // close scope
560// VBOX end
561 I8xQueueCurrentInput(deviceObject);
562 deviceExtension->MouseExtension.InputState = MouseIdle;
563
564 }
565 break;
566 }
567
568 case ZMovement: {
569
570 I8xPrint((
571 3,
572 "I8042PRT-I8042MouseInterruptService: mouse LastZ byte\n"
573 ));
574
575 //
576 // Check to see if we got any z data
577 // If there were any changes in the button state, ignore the
578 // z data
579 //
580
581// if((byte)&&(deviceExtension->MouseExtension.CurrentInput.Buttons == 0)) {
582 if(byte) {
583
584 //
585 // Sign extend the Z information and store it into the extra
586 // information field
587 //
588
589 if(byte & 0x80) {
590 deviceExtension->MouseExtension.CurrentInput.ButtonData = 0x0078;
591 } else {
592 deviceExtension->MouseExtension.CurrentInput.ButtonData = 0xFF88;
593 }
594
595 deviceExtension->MouseExtension.CurrentInput.ButtonFlags |= MOUSE_WHEEL;
596
597 }
598// VBOX begin
599 // this field is sticky, so first reset it for original behavior
600 deviceExtension->MouseExtension.CurrentInput.Flags = MOUSE_MOVE_RELATIVE;
601
602 { // open a new scope
603 VMMDevReqMouseStatus *req = deviceExtension->reqIS;
604
605 if (req)
606 {
607 int rc = VbglGRPerform (&req->header);
608
609 if (RT_SUCCESS(rc) && RT_SUCCESS(req->header.rc))
610 {
611 if (req->mouseFeatures & VMMDEV_MOUSE_HOST_CAN_ABSOLUTE)
612 {
613 // make it an absolute move
614 deviceExtension->MouseExtension.CurrentInput.Flags = MOUSE_MOVE_ABSOLUTE;
615 deviceExtension->MouseExtension.CurrentInput.LastX = req->pointerXPos;
616 deviceExtension->MouseExtension.CurrentInput.LastY = req->pointerYPos;
617 }
618 }
619 else
620 {
621 dprintf(("i8042prt: ERROR querying mouse capabilities from VMMDev."
622 "rc = %Rrc, VMMDev rc = %Rrc\n", rc, req->header.rc));
623 }
624 }
625 } // close scope
626// VBOX end
627
628 //
629 // Pack the data on to the class driver
630 //
631
632 I8xQueueCurrentInput(deviceObject);
633
634 //
635 // Reset the state
636 //
637
638 deviceExtension->MouseExtension.InputState = MouseIdle;
639
640 break;
641 }
642
643 case MouseExpectingACK: {
644
645 //
646 // This is a special case. We hit this on one of the very
647 // first mouse interrupts following the IoConnectInterrupt.
648 // The interrupt is caused when we enable mouse transmissions
649 // via I8xMouseEnableTransmission() -- the hardware returns
650 // an ACK. Just toss this byte away, and set the input state
651 // to coincide with the start of a new mouse data packet.
652 //
653
654 I8xPrint((
655 1,
656 "I8042PRT-I8042MouseInterruptService: expecting ACK (0x%x), got 0x%x\n",
657 (ULONG) ACKNOWLEDGE,
658 (ULONG) byte
659 ));
660
661 if (byte == (UCHAR) ACKNOWLEDGE) {
662 deviceExtension->MouseExtension.InputState = MouseIdle;
663 } else if (byte == (UCHAR) RESEND) {
664
665 //
666 // Resend the "Enable Mouse Transmission" sequence.
667 //
668 // NOTE: This is a hack for the Olivetti MIPS machine,
669 // which sends a resend response if a key is held down
670 // while we're attempting the I8xMouseEnableTransmission.
671 //
672
673 I8xPutByteAsynchronous(
674 (CCHAR) CommandPort,
675 deviceExtension,
676 (UCHAR) I8042_WRITE_TO_AUXILIARY_DEVICE
677 );
678
679 I8xPutByteAsynchronous(
680 (CCHAR) DataPort,
681 deviceExtension,
682 (UCHAR) ENABLE_MOUSE_TRANSMISSION
683 );
684 }
685
686 break;
687 }
688
689 default: {
690
691 I8xPrint((
692 3,
693 "I8042PRT-I8042MouseInterruptService: INVALID STATE\n"
694 ));
695
696 //
697 // Queue a DPC to log an internal driver error.
698 //
699
700 KeInsertQueueDpc(
701 &deviceExtension->ErrorLogDpc,
702 (PIRP) NULL,
703 (PVOID) (ULONG) I8042_INVALID_ISR_STATE
704 );
705
706 ASSERT(FALSE);
707 break;
708 }
709
710 }
711
712 I8xPrint((2, "I8042PRT-I8042MouseInterruptService: exit\n"));
713
714 return(TRUE);
715}
716
717
718NTSTATUS
719I8xQueryNumberOfMouseButtons(
720 IN PDEVICE_OBJECT DeviceObject,
721 OUT PUCHAR NumberOfMouseButtons
722 )
723
724/*++
725
726Routine Description:
727
728 This implements logitech's method for detecting the number of
729 mouse buttons. If anything doesn't go as expected then 0
730 is returned.
731
732 Calling this routine will set the mouse resolution to something
733 really low. The mouse resolution should be reset after this
734 call.
735
736Arguments:
737
738 DeviceObject - Supplies the device object.
739
740 NumberOfMouseButtons - Returns the number of mouse buttons or 0 if
741 the device did not support this type of
742 mouse button detection.
743
744Return Value:
745
746 An NTSTATUS code indicating success or failure.
747
748--*/
749
750{
751 NTSTATUS status;
752 PDEVICE_EXTENSION deviceExtension;
753 ULONG i;
754 UCHAR byte, buttons;
755
756 deviceExtension = DeviceObject->DeviceExtension;
757
758 status = I8xPutBytePolled((CCHAR) DataPort, WAIT_FOR_ACKNOWLEDGE,
759 (CCHAR) MouseDeviceType, deviceExtension,
760 (UCHAR) SET_MOUSE_RESOLUTION);
761 if (!NT_SUCCESS(status)) {
762 return status;
763 }
764
765 status = I8xPutBytePolled((CCHAR) DataPort, WAIT_FOR_ACKNOWLEDGE,
766 (CCHAR) MouseDeviceType, deviceExtension,
767 (UCHAR) 0x00);
768
769 if (!NT_SUCCESS(status)) {
770 return status;
771 }
772
773 for (i = 0; i < 3; i++) {
774
775 status = I8xPutBytePolled((CCHAR) DataPort, WAIT_FOR_ACKNOWLEDGE,
776 (CCHAR) MouseDeviceType, deviceExtension,
777 (UCHAR) SET_MOUSE_SCALING_1TO1);
778
779 if (!NT_SUCCESS(status)) {
780 return status;
781 }
782 }
783
784 status = I8xPutBytePolled((CCHAR) DataPort, WAIT_FOR_ACKNOWLEDGE,
785 (CCHAR) MouseDeviceType, deviceExtension,
786 (UCHAR) READ_MOUSE_STATUS);
787
788 if (!NT_SUCCESS(status)) {
789 return status;
790 }
791
792 status = I8xGetBytePolled((CCHAR) ControllerDeviceType, deviceExtension,
793 &byte);
794
795
796 if (!NT_SUCCESS(status)) {
797 return status;
798 }
799
800 status = I8xGetBytePolled((CCHAR) ControllerDeviceType, deviceExtension,
801 &buttons);
802
803
804 if (!NT_SUCCESS(status)) {
805 return status;
806 }
807
808 status = I8xGetBytePolled((CCHAR) ControllerDeviceType, deviceExtension,
809 &byte);
810
811
812 if (!NT_SUCCESS(status)) {
813 return status;
814 }
815
816 if (buttons == 2 || buttons == 3) {
817 *NumberOfMouseButtons = buttons;
818 } else {
819 *NumberOfMouseButtons = 0;
820 }
821
822 return status;
823}
824
825
826NTSTATUS
827I8xInitializeMouse(
828 IN PDEVICE_OBJECT DeviceObject
829 )
830
831/*++
832
833Routine Description:
834
835 This routine initializes the i8042 mouse hardware. It is called
836 only at initialization, and does not synchronize access to the hardware.
837
838Arguments:
839
840 DeviceObject - Pointer to the device object.
841
842Return Value:
843
844 Returns status.
845
846--*/
847
848{
849 NTSTATUS status;
850 PDEVICE_EXTENSION deviceExtension;
851 UCHAR byte;
852 ULONG i;
853 PIO_ERROR_LOG_PACKET errorLogEntry;
854 ULONG uniqueErrorValue;
855 NTSTATUS errorCode = STATUS_SUCCESS;
856 ULONG dumpCount = 0;
857 UCHAR numButtons;
858
859#define DUMP_COUNT 4
860 ULONG dumpData[DUMP_COUNT];
861
862 I8xPrint((2, "I8042PRT-I8xInitializeMouse: enter\n"));
863
864 for (i = 0; i < DUMP_COUNT; i++)
865 dumpData[i] = 0;
866
867 //
868 // Get the device extension.
869 //
870
871 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
872
873 //
874 // Reset the mouse. Send a Write To Auxiliary Device command to the
875 // 8042 controller. Then send the Reset Mouse command to the mouse
876 // through the 8042 data register. Expect to get back an ACK, followed
877 // by a completion code and the ID code (0x00).
878 //
879
880 status = I8xPutBytePolled(
881 (CCHAR) DataPort,
882 WAIT_FOR_ACKNOWLEDGE,
883 (CCHAR) MouseDeviceType,
884 deviceExtension,
885 (UCHAR) MOUSE_RESET
886 );
887 if (!NT_SUCCESS(status)) {
888 I8xPrint((
889 1,
890 "I8042PRT-I8xInitializeMouse: failed mouse reset, status 0x%x\n",
891 status
892 ));
893
894 //
895 // Set up error log info.
896 //
897
898 errorCode = I8042_MOU_RESET_COMMAND_FAILED;
899 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 415;
900 dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
901 dumpData[1] = DataPort;
902 dumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
903 dumpData[3] = MOUSE_RESET;
904 dumpCount = 4;
905
906 goto I8xInitializeMouseExit;
907 }
908
909 //
910 // Get the mouse reset responses. The first response should be a
911 // MOUSE_COMPLETE. The second response should be the mouse ID.
912 // Note that it is usually necessary to stall a long time to get the
913 // mouse reset/self-test to work. The stall value was determined by
914 // experimentation.
915 //
916 //
917
918 for (i = 0; i < 11200; i++) {
919
920 status = I8xGetBytePolled(
921 (CCHAR) ControllerDeviceType,
922 deviceExtension,
923 &byte
924 );
925
926 if (NT_SUCCESS(status) && (byte == (UCHAR) MOUSE_COMPLETE)) {
927
928 //
929 // The reset completed successfully.
930 //
931
932 break;
933
934
935 } else {
936
937 //
938 // Stall, and then try again to get a response from
939 // the reset.
940 //
941
942 if (status == STATUS_IO_TIMEOUT) {
943
944 //
945 // Stall, and then try again to get a response from
946 // the reset.
947 //
948
949 KeStallExecutionProcessor(50);
950
951 } else {
952
953 break;
954
955 }
956 }
957 }
958
959 if (!NT_SUCCESS(status)) {
960 I8xPrint((
961 1,
962 "I8042PRT-I8xInitializeMouse: failed reset response 1, status 0x%x, byte 0x%x\n",
963 status,
964 byte
965 ));
966
967 //
968 // Set up error log info.
969 //
970
971 errorCode = I8042_MOU_RESET_RESPONSE_FAILED;
972 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 420;
973 dumpData[0] = KBDMOU_INCORRECT_RESPONSE;
974 dumpData[1] = ControllerDeviceType;
975 dumpData[2] = MOUSE_COMPLETE;
976 dumpData[3] = byte;
977 dumpCount = 4;
978
979 goto I8xInitializeMouseExit;
980 }
981
982 status = I8xGetBytePolled(
983 (CCHAR) ControllerDeviceType,
984 deviceExtension,
985 &byte
986 );
987
988 if ((!NT_SUCCESS(status)) || (byte != MOUSE_ID_BYTE)) {
989 I8xPrint((
990 1,
991 "I8042PRT-I8xInitializeMouse: failed reset response 2, status 0x%x, byte 0x%x\n",
992 status,
993 byte
994 ));
995
996 //
997 // Set up error log info.
998 //
999
1000 errorCode = I8042_MOU_RESET_RESPONSE_FAILED;
1001 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 425;
1002 dumpData[0] = KBDMOU_INCORRECT_RESPONSE;
1003 dumpData[1] = ControllerDeviceType;
1004 dumpData[2] = MOUSE_ID_BYTE;
1005 dumpData[3] = byte;
1006 dumpCount = 4;
1007
1008 goto I8xInitializeMouseExit;
1009 }
1010
1011 //
1012 // Check to see if this is a wheel mouse
1013 //
1014
1015 I8xFindWheelMouse(DeviceObject);
1016
1017 //
1018 // Try to detect the number of mouse buttons.
1019 //
1020
1021 status = I8xQueryNumberOfMouseButtons(DeviceObject, &numButtons);
1022 if (!NT_SUCCESS(status)) {
1023 I8xPrint((
1024 1,
1025 "I8042PRT-I8xInitializeMouse: failed to get buttons, status 0x%x\n",
1026 status
1027 ));
1028
1029 //
1030 // Set up error log info.
1031 //
1032
1033 errorCode = I8042_ERROR_DURING_BUTTONS_DETECT;
1034 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 426;
1035 dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
1036 dumpData[1] = DataPort;
1037 dumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
1038 dumpCount = 3;
1039
1040 goto I8xInitializeMouseExit;
1041 } else if (numButtons) {
1042 deviceExtension->Configuration.MouseAttributes.NumberOfButtons =
1043 numButtons;
1044 }
1045
1046
1047 //
1048 // Set mouse sampling rate. Send a Write To Auxiliary Device command
1049 // to the 8042 controller. Then send the Set Mouse Sampling Rate
1050 // command to the mouse through the 8042 data register,
1051 // followed by its parameter.
1052 //
1053
1054 status = I8xPutBytePolled(
1055 (CCHAR) DataPort,
1056 WAIT_FOR_ACKNOWLEDGE,
1057 (CCHAR) MouseDeviceType,
1058 deviceExtension,
1059 (UCHAR) SET_MOUSE_SAMPLING_RATE
1060 );
1061 if (!NT_SUCCESS(status)) {
1062 I8xPrint((
1063 1,
1064 "I8042PRT-I8xInitializeMouse: failed write set sample rate, status 0x%x\n",
1065 status
1066 ));
1067
1068 //
1069 // Set up error log info.
1070 //
1071
1072 errorCode = I8042_SET_SAMPLE_RATE_FAILED;
1073 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 435;
1074 dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
1075 dumpData[1] = DataPort;
1076 dumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
1077 dumpData[3] = SET_MOUSE_SAMPLING_RATE;
1078 dumpCount = 4;
1079
1080 goto I8xInitializeMouseExit;
1081 }
1082
1083 status = I8xPutBytePolled(
1084 (CCHAR) DataPort,
1085 WAIT_FOR_ACKNOWLEDGE,
1086 (CCHAR) MouseDeviceType,
1087 deviceExtension,
1088 (UCHAR) MOUSE_SAMPLE_RATE
1089 );
1090 if (!NT_SUCCESS(status)) {
1091 I8xPrint((
1092 1,
1093 "I8042PRT-I8xInitializeMouse: failed write sample rate, status 0x%x\n",
1094 status
1095 ));
1096
1097 //
1098 // Set up error log info.
1099 //
1100
1101 errorCode = I8042_SET_SAMPLE_RATE_FAILED;
1102 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 445;
1103 dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
1104 dumpData[1] = DataPort;
1105 dumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
1106 dumpData[3] = MOUSE_SAMPLE_RATE;
1107 dumpCount = 4;
1108
1109 goto I8xInitializeMouseExit;
1110 }
1111
1112 //
1113 // Set the mouse resolution. Send a Write To Auxiliary Device command
1114 // to the 8042 controller. Then send the Set Mouse Resolution
1115 // command to the mouse through the 8042 data register,
1116 // followed by its parameter.
1117 //
1118
1119 status = I8xPutBytePolled(
1120 (CCHAR) DataPort,
1121 WAIT_FOR_ACKNOWLEDGE,
1122 (CCHAR) MouseDeviceType,
1123 deviceExtension,
1124 (UCHAR) SET_MOUSE_RESOLUTION
1125 );
1126 if (!NT_SUCCESS(status)) {
1127 I8xPrint((
1128 1,
1129 "I8042PRT-I8xInitializeMouse: failed write set resolution, status 0x%x\n",
1130 status
1131 ));
1132
1133 //
1134 // Set up error log info.
1135 //
1136
1137 errorCode = I8042_SET_RESOLUTION_FAILED;
1138 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 455;
1139 dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
1140 dumpData[1] = DataPort;
1141 dumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
1142 dumpData[3] = SET_MOUSE_RESOLUTION;
1143 dumpCount = 4;
1144
1145 goto I8xInitializeMouseExit;
1146 }
1147
1148 status = I8xPutBytePolled(
1149 (CCHAR) DataPort,
1150 WAIT_FOR_ACKNOWLEDGE,
1151 (CCHAR) MouseDeviceType,
1152 deviceExtension,
1153 (UCHAR) deviceExtension->Configuration.MouseResolution
1154 );
1155 if (!NT_SUCCESS(status)) {
1156 I8xPrint((
1157 1,
1158 "I8042PRT-I8xInitializeMouse: failed set mouse resolution, status 0x%x\n",
1159 status
1160 ));
1161
1162 //
1163 // Set up error log info.
1164 //
1165
1166 errorCode = I8042_SET_RESOLUTION_FAILED;
1167 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 465;
1168 dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
1169 dumpData[1] = DataPort;
1170 dumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
1171 dumpData[3] = deviceExtension->Configuration.MouseResolution;
1172 dumpCount = 4;
1173
1174 goto I8xInitializeMouseExit;
1175 }
1176
1177I8xInitializeMouseExit:
1178
1179 if (!NT_SUCCESS(status)) {
1180
1181 //
1182 // The mouse initialization failed. Log an error.
1183 //
1184
1185 if (errorCode != STATUS_SUCCESS) {
1186 errorLogEntry = (PIO_ERROR_LOG_PACKET)
1187 IoAllocateErrorLogEntry(
1188 DeviceObject,
1189 (UCHAR) (sizeof(IO_ERROR_LOG_PACKET)
1190 + (dumpCount * sizeof(ULONG)))
1191 );
1192
1193 if (errorLogEntry != NULL) {
1194
1195 errorLogEntry->ErrorCode = errorCode;
1196 errorLogEntry->DumpDataSize = (USHORT) dumpCount * sizeof(ULONG);
1197 errorLogEntry->SequenceNumber = 0;
1198 errorLogEntry->MajorFunctionCode = 0;
1199 errorLogEntry->IoControlCode = 0;
1200 errorLogEntry->RetryCount = 0;
1201 errorLogEntry->UniqueErrorValue = uniqueErrorValue;
1202 errorLogEntry->FinalStatus = status;
1203 for (i = 0; i < dumpCount; i++)
1204 errorLogEntry->DumpData[i] = dumpData[i];
1205
1206 IoWriteErrorLogEntry(errorLogEntry);
1207 }
1208 }
1209 }
1210
1211 //
1212 // Initialize current mouse input packet state.
1213 //
1214
1215 deviceExtension->MouseExtension.PreviousSignAndOverflow = 0;
1216 deviceExtension->MouseExtension.InputState = MouseExpectingACK;
1217 deviceExtension->MouseExtension.LastByteReceived = 0;
1218
1219 I8xPrint((2, "I8042PRT-I8xInitializeMouse: exit\n"));
1220
1221 return(status);
1222}
1223
1224
1225VOID
1226I8xMouseConfiguration(
1227 IN PINIT_EXTENSION InitializationData,
1228 IN PUNICODE_STRING RegistryPath,
1229 IN PUNICODE_STRING KeyboardDeviceName,
1230 IN PUNICODE_STRING PointerDeviceName
1231 )
1232
1233/*++
1234
1235Routine Description:
1236
1237 This routine retrieves the configuration information for the mouse.
1238
1239Arguments:
1240
1241 InitializationData - Pointer to the temporary device extension and some
1242 additional configuration information
1243
1244 RegistryPath - Pointer to the null-terminated Unicode name of the
1245 registry path for this driver.
1246
1247 KeyboardDeviceName - Pointer to the Unicode string that will receive
1248 the keyboard port device name.
1249
1250 PointerDeviceName - Pointer to the Unicode string that will receive
1251 the pointer port device name.
1252
1253
1254Return Value:
1255
1256 None. As a side-effect, may set DeviceExtension->HardwarePresent.
1257
1258--*/
1259{
1260 PDEVICE_EXTENSION deviceExtension = &(InitializationData->DeviceExtension);
1261 NTSTATUS status = STATUS_SUCCESS;
1262 INTERFACE_TYPE interfaceType;
1263 CONFIGURATION_TYPE controllerType = PointerController;
1264 CONFIGURATION_TYPE peripheralType = PointerPeripheral;
1265 ULONG i;
1266
1267 for (i = 0; i < MaximumInterfaceType; i++) {
1268
1269 //
1270 // Get the registry information for this device.
1271 //
1272
1273 interfaceType = i;
1274 status = IoQueryDeviceDescription(&interfaceType,
1275 NULL,
1276 &controllerType,
1277 NULL,
1278 &peripheralType,
1279 NULL,
1280 I8xMousePeripheralCallout,
1281 (PVOID) InitializationData);
1282
1283 if (InitializationData->DeviceExtension.HardwarePresent &
1284 MOUSE_HARDWARE_PRESENT) {
1285
1286 //
1287 // If we didn't already get these when determining the keyboard
1288 // configuration, get the service parameters now (e.g.,
1289 // user-configurable number of resends, polling iterations, etc.).
1290 //
1291
1292 if (!(InitializationData->DeviceExtension.HardwarePresent &
1293 KEYBOARD_HARDWARE_PRESENT))
1294 I8xServiceParameters(
1295 InitializationData,
1296 RegistryPath,
1297 KeyboardDeviceName,
1298 PointerDeviceName
1299 );
1300
1301 //
1302 // Initialize mouse-specific configuration parameters.
1303 //
1304
1305 InitializationData->DeviceExtension.Configuration.MouseAttributes.
1306 MouseIdentifier =
1307 MOUSE_I8042_HARDWARE;
1308
1309 break;
1310
1311 } else {
1312 I8xPrint((
1313 1,
1314 "I8042PRT-I8xMouseConfiguration: IoQueryDeviceDescription for bus type %d failed\n",
1315 interfaceType
1316 ));
1317 }
1318 }
1319}
1320
1321
1322NTSTATUS
1323I8xMouseEnableTransmission(
1324 IN PDEVICE_OBJECT DeviceObject
1325 )
1326
1327/*++
1328
1329Routine Description:
1330
1331 This routine sends an Enable command to the mouse hardware, causing
1332 the mouse to begin transmissions. It is called at initialization
1333 time, but only after the interrupt has been connected. This is
1334 necessary so the driver can keep its notion of the mouse input data
1335 state in sync with the hardware (i.e., for this type of mouse there is no
1336 way to differentiate the first byte of a packet; if the user is randomly
1337 moving the mouse during boot/initialization, the first mouse interrupt we
1338 receive following IoConnectInterrupt could be for a byte that is not the
1339 start of a packet, and we have no way to know that).
1340
1341Arguments:
1342
1343 DeviceObject - Pointer to the device object.
1344
1345Return Value:
1346
1347 Returns status.
1348
1349--*/
1350
1351{
1352 NTSTATUS status;
1353 PDEVICE_EXTENSION deviceExtension;
1354 ULONG uniqueErrorValue;
1355 NTSTATUS errorCode = STATUS_SUCCESS;
1356 ULONG i;
1357 ULONG dumpCount = 0;
1358
1359#define DUMP_COUNT 4
1360 ULONG dumpData[DUMP_COUNT];
1361
1362 I8xPrint((2, "I8042PRT-I8xMouseEnableTransmission: enter\n"));
1363
1364 for (i = 0; i < DUMP_COUNT; i++)
1365 dumpData[i] = 0;
1366
1367 //
1368 // Get the device extension.
1369 //
1370
1371 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
1372
1373 //
1374 // Re-enable the mouse at the mouse hardware, so that it can transmit
1375 // data packets in continuous mode. Note that this is not the same
1376 // as enabling the mouse device at the 8042 controller. The mouse
1377 // hardware is sent an Enable command here, because it was
1378 // Disabled as a result of the mouse reset command performed
1379 // in I8xInitializeMouse().
1380 //
1381 // Note that we don't wait for an ACKNOWLEDGE back. The
1382 // ACKNOWLEDGE back will actually cause a mouse interrupt, which
1383 // then gets handled in the mouse ISR.
1384 //
1385
1386 status = I8xPutBytePolled(
1387 (CCHAR) DataPort,
1388 NO_WAIT_FOR_ACKNOWLEDGE,
1389 (CCHAR) MouseDeviceType,
1390 deviceExtension,
1391 (UCHAR) ENABLE_MOUSE_TRANSMISSION
1392 );
1393 if (!NT_SUCCESS(status)) {
1394 I8xPrint((
1395 1,
1396 "I8042PRT-I8xMouseEnableTransmission: failed write enable transmission, status 0x%x\n",
1397 status
1398 ));
1399
1400 //
1401 // Set up error log info.
1402 //
1403
1404 errorCode = I8042_MOU_ENABLE_XMIT;
1405 uniqueErrorValue = I8042_ERROR_VALUE_BASE + 475;
1406 dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
1407 dumpData[1] = DataPort;
1408 dumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
1409 dumpData[3] = ENABLE_MOUSE_TRANSMISSION;
1410 dumpCount = 4;
1411
1412 }
1413
1414 I8xPrint((2, "I8042PRT-I8xMouseEnableTransmission: exit\n"));
1415
1416 return(status);
1417}
1418
1419
1420NTSTATUS
1421I8xMousePeripheralCallout(
1422 IN PVOID Context,
1423 IN PUNICODE_STRING PathName,
1424 IN INTERFACE_TYPE BusType,
1425 IN ULONG BusNumber,
1426 IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
1427 IN CONFIGURATION_TYPE ControllerType,
1428 IN ULONG ControllerNumber,
1429 IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
1430 IN CONFIGURATION_TYPE PeripheralType,
1431 IN ULONG PeripheralNumber,
1432 IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
1433 )
1434
1435/*++
1436
1437Routine Description:
1438
1439 This is the callout routine sent as a parameter to
1440 IoQueryDeviceDescription. It grabs the pointer controller and
1441 peripheral configuration information.
1442
1443Arguments:
1444
1445 Context - Context parameter that was passed in by the routine
1446 that called IoQueryDeviceDescription.
1447
1448 PathName - The full pathname for the registry key.
1449
1450 BusType - Bus interface type (Isa, Eisa, Mca, etc.).
1451
1452 BusNumber - The bus sub-key (0, 1, etc.).
1453
1454 BusInformation - Pointer to the array of pointers to the full value
1455 information for the bus.
1456
1457 ControllerType - The controller type (should be PointerController).
1458
1459 ControllerNumber - The controller sub-key (0, 1, etc.).
1460
1461 ControllerInformation - Pointer to the array of pointers to the full
1462 value information for the controller key.
1463
1464 PeripheralType - The peripheral type (should be PointerPeripheral).
1465
1466 PeripheralNumber - The peripheral sub-key.
1467
1468 PeripheralInformation - Pointer to the array of pointers to the full
1469 value information for the peripheral key.
1470
1471
1472Return Value:
1473
1474 None. If successful, will have the following side-effects:
1475
1476 - Sets DeviceObject->DeviceExtension->HardwarePresent.
1477 - Sets configuration fields in
1478 DeviceObject->DeviceExtension->Configuration.
1479
1480--*/
1481{
1482 PDEVICE_EXTENSION deviceExtension;
1483 PINIT_EXTENSION initializationData;
1484 PI8042_CONFIGURATION_INFORMATION configuration;
1485 UNICODE_STRING unicodeIdentifier;
1486 ANSI_STRING ansiString;
1487 PUCHAR controllerData;
1488 NTSTATUS status = STATUS_SUCCESS;
1489 ULONG i;
1490 ULONG listCount;
1491 PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDescriptor;
1492 CM_PARTIAL_RESOURCE_DESCRIPTOR tmpResourceDescriptor;
1493 BOOLEAN portInfoNeeded;
1494 BOOLEAN defaultInterruptShare;
1495 KINTERRUPT_MODE defaultInterruptMode;
1496
1497 I8xPrint((
1498 1,
1499 "I8042PRT-I8xMousePeripheralCallout: Path @ 0x%x, Bus Type 0x%x, Bus Number 0x%x\n",
1500 PathName, BusType, BusNumber
1501 ));
1502 I8xPrint((
1503 1,
1504 " Controller Type 0x%x, Controller Number 0x%x, Controller info @ 0x%x\n",
1505 ControllerType, ControllerNumber, ControllerInformation
1506 ));
1507 I8xPrint((
1508 1,
1509 " Peripheral Type 0x%x, Peripheral Number 0x%x, Peripheral info @ 0x%x\n",
1510 PeripheralType, PeripheralNumber, PeripheralInformation
1511 ));
1512
1513 //
1514 // Get the length of the peripheral identifier information.
1515 //
1516
1517 unicodeIdentifier.Length = (USHORT)
1518 (*(PeripheralInformation + IoQueryDeviceIdentifier))->DataLength;
1519
1520 //
1521 // If we already have the configuration information for the
1522 // pointer peripheral, or if the peripheral identifier is missing,
1523 // just return.
1524 //
1525
1526 initializationData = (PINIT_EXTENSION) Context;
1527 deviceExtension = &(initializationData->DeviceExtension);
1528
1529 if ((deviceExtension->HardwarePresent & MOUSE_HARDWARE_PRESENT)
1530 || (unicodeIdentifier.Length == 0)) {
1531 return (status);
1532 }
1533
1534 configuration = &deviceExtension->Configuration;
1535
1536 //
1537 // Get the identifier information for the peripheral.
1538 //
1539
1540 unicodeIdentifier.MaximumLength = unicodeIdentifier.Length;
1541 unicodeIdentifier.Buffer = (PWSTR) (((PUCHAR)(*(PeripheralInformation +
1542 IoQueryDeviceIdentifier))) +
1543 (*(PeripheralInformation +
1544 IoQueryDeviceIdentifier))->DataOffset);
1545 I8xPrint((
1546 1,
1547 "I8042PRT-I8xMousePeripheralCallout: Mouse type %ws\n",
1548 unicodeIdentifier.Buffer));
1549
1550 //
1551 // Verify that this is an i8042 mouse.
1552 //
1553
1554 status = RtlUnicodeStringToAnsiString(
1555 &ansiString,
1556 &unicodeIdentifier,
1557 TRUE
1558 );
1559
1560 if (!NT_SUCCESS(status)) {
1561 I8xPrint((
1562 1,
1563 "I8042PRT-I8xMousePeripheralCallout: Could not convert identifier to Ansi\n"
1564 ));
1565 return(status);
1566 }
1567
1568 if (strstr(ansiString.Buffer, "PS2")) {
1569
1570 //
1571 // There is a mouse on the i8042 controller.
1572 //
1573
1574 deviceExtension->HardwarePresent |= MOUSE_HARDWARE_PRESENT;
1575 }
1576
1577 RtlFreeAnsiString(&ansiString);
1578
1579 if (!(deviceExtension->HardwarePresent & MOUSE_HARDWARE_PRESENT)) {
1580 return(status);
1581 }
1582
1583 if (!(deviceExtension->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)) {
1584
1585 //
1586 // If we don't already have the bus information as the result
1587 // of the keyboard configuration, grab it now.
1588 //
1589
1590 configuration->InterfaceType = BusType;
1591 configuration->BusNumber = BusNumber;
1592 configuration->FloatingSave = I8042_FLOATING_SAVE;
1593 }
1594
1595 if (configuration->InterfaceType == MicroChannel) {
1596 defaultInterruptShare = TRUE;
1597 defaultInterruptMode = LevelSensitive;
1598 } else {
1599 defaultInterruptShare = I8042_INTERRUPT_SHARE;
1600 defaultInterruptMode = I8042_INTERRUPT_MODE;
1601 }
1602
1603 //
1604 // Look through the controller's resource list for interrupt
1605 // and (possibly) port configuration information.
1606 //
1607
1608 if ((*(ControllerInformation + IoQueryDeviceConfigurationData))->DataLength != 0){
1609 controllerData = ((PUCHAR) (*(ControllerInformation +
1610 IoQueryDeviceConfigurationData))) +
1611 (*(ControllerInformation +
1612 IoQueryDeviceConfigurationData))->DataOffset;
1613
1614 controllerData += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
1615 PartialResourceList);
1616
1617 listCount = ((PCM_PARTIAL_RESOURCE_LIST) controllerData)->Count;
1618
1619 resourceDescriptor =
1620 ((PCM_PARTIAL_RESOURCE_LIST) controllerData)->PartialDescriptors;
1621
1622 portInfoNeeded = configuration->PortListCount? FALSE:TRUE;
1623
1624 for (i = 0; i < listCount; i++, resourceDescriptor++) {
1625 switch(resourceDescriptor->Type) {
1626 case CmResourceTypePort:
1627
1628 if (portInfoNeeded) {
1629
1630 //
1631 // If we don't already have the port information as
1632 // a result of the keyboard configuration, copy it
1633 // to the port list.
1634 //
1635
1636 configuration->PortList[configuration->PortListCount] =
1637 *resourceDescriptor;
1638 configuration->PortList[configuration->PortListCount].ShareDisposition =
1639 I8042_REGISTER_SHARE? CmResourceShareShared:
1640 CmResourceShareDriverExclusive;
1641 configuration->PortListCount += 1;
1642
1643 }
1644
1645 break;
1646
1647 case CmResourceTypeInterrupt:
1648
1649 //
1650 // Copy the interrupt information.
1651 //
1652
1653 configuration->MouseInterrupt = *resourceDescriptor;
1654 configuration->MouseInterrupt.ShareDisposition =
1655 defaultInterruptShare? CmResourceShareShared :
1656 CmResourceShareDeviceExclusive;
1657
1658 break;
1659
1660 default:
1661 break;
1662 }
1663 }
1664 }
1665
1666 //
1667 // If no interrupt configuration information was found, use the
1668 // mouse driver defaults.
1669 //
1670
1671 if (!(configuration->MouseInterrupt.Type & CmResourceTypeInterrupt)) {
1672
1673 I8xPrint((
1674 1,
1675 "I8042PRT-I8xMousePeripheralCallout: Using default mouse interrupt config\n"
1676 ));
1677
1678 configuration->MouseInterrupt.Type = CmResourceTypeInterrupt;
1679 configuration->MouseInterrupt.ShareDisposition =
1680 defaultInterruptShare? CmResourceShareShared :
1681 CmResourceShareDeviceExclusive;
1682 configuration->MouseInterrupt.Flags =
1683 (defaultInterruptMode == Latched)? CM_RESOURCE_INTERRUPT_LATCHED :
1684 CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
1685 configuration->MouseInterrupt.u.Interrupt.Level = MOUSE_IRQL;
1686 configuration->MouseInterrupt.u.Interrupt.Vector = MOUSE_VECTOR;
1687 }
1688
1689 I8xPrint((
1690 1,
1691 "I8042PRT-I8xMousePeripheralCallout: Mouse interrupt config --\n"
1692 ));
1693 I8xPrint((
1694 1,
1695 "%s, %s, Irq = %d\n",
1696 configuration->MouseInterrupt.ShareDisposition == CmResourceShareShared?
1697 "Sharable" : "NonSharable",
1698 configuration->MouseInterrupt.Flags == CM_RESOURCE_INTERRUPT_LATCHED?
1699 "Latched" : "Level Sensitive",
1700 configuration->MouseInterrupt.u.Interrupt.Vector
1701 ));
1702
1703 //
1704 // If no port configuration information was found, use the
1705 // mouse driver defaults.
1706 //
1707
1708 if (configuration->PortListCount == 0) {
1709
1710 //
1711 // No port configuration information was found, so use
1712 // the driver defaults.
1713 //
1714
1715 I8xPrint((
1716 1,
1717 "I8042PRT-I8xMousePeripheralCallout: Using default port config\n"
1718 ));
1719
1720 configuration->PortList[DataPort].Type = CmResourceTypePort;
1721 configuration->PortList[DataPort].Flags = I8042_PORT_TYPE;
1722 configuration->PortList[DataPort].ShareDisposition =
1723 I8042_REGISTER_SHARE? CmResourceShareShared:
1724 CmResourceShareDriverExclusive;
1725 configuration->PortList[DataPort].u.Port.Start.LowPart =
1726 I8042_PHYSICAL_BASE + I8042_DATA_REGISTER_OFFSET;
1727 configuration->PortList[DataPort].u.Port.Start.HighPart = 0;
1728 configuration->PortList[DataPort].u.Port.Length = I8042_REGISTER_LENGTH;
1729
1730 configuration->PortList[CommandPort].Type = CmResourceTypePort;
1731 configuration->PortList[CommandPort].Flags = I8042_PORT_TYPE;
1732 configuration->PortList[CommandPort].ShareDisposition =
1733 I8042_REGISTER_SHARE? CmResourceShareShared:
1734 CmResourceShareDriverExclusive;
1735 configuration->PortList[CommandPort].u.Port.Start.LowPart =
1736 I8042_PHYSICAL_BASE + I8042_COMMAND_REGISTER_OFFSET;
1737 configuration->PortList[CommandPort].u.Port.Start.HighPart = 0;
1738 configuration->PortList[CommandPort].u.Port.Length = I8042_REGISTER_LENGTH;
1739
1740 configuration->PortListCount = 2;
1741 } else if (configuration->PortListCount == 1) {
1742
1743 //
1744 // Kludge for Jazz machines. Their ARC firmware neglects to
1745 // separate out the port addresses, so fix that up here.
1746 //
1747
1748 configuration->PortList[CommandPort] = configuration->PortList[DataPort];
1749 configuration->PortList[CommandPort].u.Port.Start.LowPart +=
1750 I8042_COMMAND_REGISTER_OFFSET;
1751 configuration->PortListCount += 1;
1752 } else {
1753
1754 //
1755 // Put the lowest port address range in the DataPort element of
1756 // the port list.
1757 //
1758
1759 if (configuration->PortList[CommandPort].u.Port.Start.LowPart
1760 < configuration->PortList[DataPort].u.Port.Start.LowPart) {
1761 tmpResourceDescriptor = configuration->PortList[DataPort];
1762 configuration->PortList[DataPort] =
1763 configuration->PortList[CommandPort];
1764 configuration->PortList[CommandPort] = tmpResourceDescriptor;
1765 }
1766 }
1767
1768#ifdef PNP_IDENTIFY
1769 //
1770 // In any event we're going to use the pointer based on this data,
1771 // so make sure we can tell PNP that we've claimed it later on
1772 //
1773
1774 initializationData->MouseConfig.InterfaceType = BusType;
1775 initializationData->MouseConfig.InterfaceNumber = BusNumber;
1776 initializationData->MouseConfig.ControllerType = ControllerType;
1777 initializationData->MouseConfig.ControllerNumber = ControllerNumber;
1778 initializationData->MouseConfig.PeripheralType = PeripheralType;
1779 initializationData->MouseConfig.PeripheralNumber = PeripheralNumber;
1780#endif
1781
1782 for (i = 0; i < configuration->PortListCount; i++) {
1783
1784 I8xPrint((
1785 1,
1786 " %s, Ports 0x%x - 0x%x\n",
1787 configuration->PortList[i].ShareDisposition
1788 == CmResourceShareShared? "Sharable" : "NonSharable",
1789 configuration->PortList[i].u.Port.Start.LowPart,
1790 configuration->PortList[i].u.Port.Start.LowPart +
1791 configuration->PortList[i].u.Port.Length - 1
1792 ));
1793 }
1794
1795 return(status);
1796}
1797
1798
1799
1800NTSTATUS
1801I8xFindWheelMouse(
1802 IN PDEVICE_OBJECT DeviceObject
1803 )
1804
1805/*++
1806
1807Routine Description:
1808
1809 This routine determines if the mouse is a Zoom mouse. The method
1810 of detection is to set the sample rate to 200Hz, then 100Hz, then 80Hz
1811 and then read the device ID. An ID of 3 indicates a zoom mouse.
1812
1813 If the registry entry "EnableWheelDetection" is false then this
1814 routine will just return STATUS_NO_SUCH_DEVICE.
1815
1816Arguments:
1817
1818 DeviceObject - Pointer to the device object
1819
1820Return Value:
1821
1822 Returns status
1823
1824Remarks:
1825
1826 As a side effect the sample rate is left at 80Hz and if a wheelmouse is
1827 attached it is in the wheel mode where packets are different.
1828
1829--*/
1830
1831{
1832 NTSTATUS status;
1833 PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
1834 UCHAR byte;
1835 ULONG i;
1836 PIO_ERROR_LOG_PACKET errorLogEntry;
1837 ULONG uniqueErrorValue = I8042_ERROR_VALUE_BASE + 480;
1838 NTSTATUS errorCode = STATUS_SUCCESS;
1839 ULONG dumpCount = 0;
1840#define DUMP_COUNT 4
1841 ULONG dumpData[DUMP_COUNT];
1842 UCHAR ucCommands[] = {SET_MOUSE_SAMPLING_RATE, 200,
1843 SET_MOUSE_SAMPLING_RATE, 100,
1844 SET_MOUSE_SAMPLING_RATE, 80,
1845 GET_DEVICE_ID, 0 // NULL terminate
1846 };
1847 UCHAR commandCount = 0;
1848
1849 I8xPrint((1, "I8042PRT-I8xFindWheelMouse: enter\n"));
1850
1851 if(!deviceExtension->Configuration.EnableWheelDetection) {
1852
1853 I8xPrint((1,
1854 "I8042PRT-I8xFindWheelMouse: Detection disabled in registry\n"
1855 ));
1856 return STATUS_NO_SUCH_DEVICE;
1857 }
1858
1859 for(i = 0; i < DUMP_COUNT; i++)
1860 dumpData[i] = 0;
1861
1862 KeStallExecutionProcessor(50);
1863
1864 while(ucCommands[commandCount] != 0) {
1865
1866 status = I8xPutBytePolled(
1867 (CCHAR) DataPort,
1868 WAIT_FOR_ACKNOWLEDGE,
1869 (CCHAR) MouseDeviceType,
1870 deviceExtension,
1871 ucCommands[commandCount]
1872 );
1873
1874 if(!NT_SUCCESS(status)) {
1875
1876 I8xPrint((
1877 1,
1878 "I8042PRT-I8xFindWheelMouse: failed write set sample rate, status 0x%x\n",
1879 status
1880 ));
1881
1882 //
1883 // Set up error log info
1884 //
1885
1886 errorCode = I8042_SET_SAMPLE_RATE_FAILED;
1887 dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
1888 dumpData[1] = DataPort;
1889 dumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
1890 dumpData[3] = ucCommands[commandCount];
1891 dumpCount = 4;
1892
1893 goto I8xFindWheelMouseExit;
1894 }
1895
1896 commandCount++;
1897 uniqueErrorValue += 5;
1898 KeStallExecutionProcessor(50);
1899
1900 }
1901
1902 //
1903 // Get the mouse ID
1904 //
1905
1906 for(i = 0; i < 5; i++) {
1907
1908 status = I8xGetBytePolled(
1909 (CCHAR) ControllerDeviceType,
1910 deviceExtension,
1911 &byte
1912 );
1913
1914 if(NT_SUCCESS(status)) {
1915
1916 //
1917 // Read was successful - the ID has been returned
1918
1919 break;
1920
1921 }
1922
1923 //
1924 // If the read timed out, stall and retry.
1925 // If some other error occurred handle it outside the loop
1926 //
1927
1928 if(status == STATUS_IO_TIMEOUT) {
1929
1930 KeStallExecutionProcessor(50);
1931
1932 } else {
1933
1934 break;
1935
1936 }
1937
1938 }
1939
1940 if((!NT_SUCCESS(status)) ||
1941 ((byte != MOUSE_ID_BYTE) && (byte != WHEELMOUSE_ID_BYTE))) {
1942
1943 I8xPrint((
1944 1,
1945 "I8042PRT-I8xFindWheelMouse: failed ID, status 0x%x, byte 0x%x\n",
1946 status,
1947 byte
1948 ));
1949
1950 //
1951 // Set up error log info
1952 //
1953
1954 errorCode = I8042_MOU_RESET_RESPONSE_FAILED;
1955 dumpData[0] = KBDMOU_INCORRECT_RESPONSE;
1956 dumpData[1] = ControllerDeviceType;
1957 dumpData[2] = MOUSE_ID_BYTE;
1958 dumpData[3] = byte;
1959 dumpCount = 4;
1960
1961 goto I8xFindWheelMouseExit;
1962
1963 } else if( byte == WHEELMOUSE_ID_BYTE) {
1964
1965 //
1966 // Update the HardwarePresent to show a Z mouse is operational,
1967 // and set the appropriate mouse type flags
1968 //
1969
1970 deviceExtension->HardwarePresent |=
1971 (WHEELMOUSE_HARDWARE_PRESENT | MOUSE_HARDWARE_PRESENT);
1972
1973// deviceExtension->MouseExtension.MsData.MouseType |=
1974// (DT_Z_MOUSE | DT_MOUSE);
1975
1976 deviceExtension->Configuration.MouseAttributes.MouseIdentifier =
1977 WHEELMOUSE_I8042_HARDWARE;
1978
1979 I8xPrint((
1980 1,
1981 "I8042PRT-I8xFindWheelMouse: wheel mouse attached - running in wheel mode.\n"
1982 ));
1983 } else {
1984 deviceExtension->HardwarePresent |= MOUSE_HARDWARE_PRESENT;
1985
1986 I8xPrint((
1987 1,
1988 "I8042PRT-I8xFindWheelMouse: Mouse attached - running in mouse mode.\n"
1989 ));
1990 }
1991
1992I8xFindWheelMouseExit:
1993
1994 if (!NT_SUCCESS(status)) {
1995
1996 //
1997 // The mouse initialization failed. Log an error.
1998 //
1999
2000 if(errorCode != STATUS_SUCCESS) {
2001 errorLogEntry = (PIO_ERROR_LOG_PACKET)
2002 IoAllocateErrorLogEntry(
2003 DeviceObject,
2004 (UCHAR) (sizeof(IO_ERROR_LOG_PACKET) +
2005 (dumpCount * sizeof(ULONG)))
2006 );
2007
2008 if(errorLogEntry != NULL) {
2009
2010 errorLogEntry->ErrorCode = errorCode;
2011 errorLogEntry->DumpDataSize = (USHORT) dumpCount * sizeof(ULONG);
2012 errorLogEntry->SequenceNumber = 0;
2013 errorLogEntry->MajorFunctionCode = 0;
2014 errorLogEntry->IoControlCode = 0;
2015 errorLogEntry->RetryCount = 0;
2016 errorLogEntry->UniqueErrorValue = uniqueErrorValue;
2017 errorLogEntry->FinalStatus = status;
2018 for(i = 0; i < dumpCount; i++) {
2019 errorLogEntry->DumpData[i] = dumpData[i];
2020 }
2021
2022 IoWriteErrorLogEntry(errorLogEntry);
2023 }
2024 }
2025 }
2026
2027 //
2028 // Initialize current mouse input packet state
2029 //
2030
2031 deviceExtension->MouseExtension.PreviousSignAndOverflow = 0;
2032 deviceExtension->MouseExtension.InputState = MouseExpectingACK;
2033
2034 I8xPrint((2, "I8042PRT-I8xFindWheelMouse: exit\n"));
2035
2036 return status;
2037}
2038
2039
2040
2041VOID
2042I8xQueueCurrentInput(
2043 IN PDEVICE_OBJECT DeviceObject
2044 )
2045
2046/*++
2047
2048Routine Description:
2049
2050 This routine queues the current input data to be processed by a
2051 DPC outside the ISR
2052
2053Arguments:
2054
2055 DeviceObject - Pointer to the device object
2056
2057Return Value:
2058
2059 None
2060
2061--*/
2062
2063{
2064
2065 PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
2066#if 0 /* bird: unused */
2067 UCHAR buttonsDelta;
2068 UCHAR previousButtons;
2069#endif
2070
2071 //
2072 // If the mouse is enabled, add the data to the InputData queue
2073 // and queue the ISR DPC. One might wonder why we bother to
2074 // do all this processing of the mouse packet, only to toss it
2075 // away (i.e., not queue it) at this point. The answer is that
2076 // this mouse provides no data to allow the driver to determine
2077 // when the first byte of a packet is received -- if the driver
2078 // doesn't process all interrupts from the start, there is no
2079 // way to keep MouseExtension.InputState in synch with hardware
2080 // reality.
2081 //
2082
2083 if (deviceExtension->MouseEnableCount) {
2084 deviceExtension->MouseExtension.CurrentInput.UnitId = deviceExtension->MouseExtension.UnitId;
2085
2086 if (!I8xWriteDataToMouseQueue(
2087 &deviceExtension->MouseExtension,
2088 &deviceExtension->MouseExtension.CurrentInput
2089 )) {
2090
2091 //
2092 // InputData queue overflowed.
2093 //
2094 // Queue a DPC to log an overrun error.
2095 //
2096
2097 I8xPrint((
2098 1,
2099 "I8042PRT-I8042MouseInterruptService: queue overflow\n"
2100 ));
2101
2102 if (deviceExtension->MouseExtension.OkayToLogOverflow) {
2103 KeInsertQueueDpc(
2104 &deviceExtension->ErrorLogDpc,
2105 (PIRP) NULL,
2106 (PVOID) (ULONG) I8042_MOU_BUFFER_OVERFLOW
2107 );
2108 deviceExtension->MouseExtension.OkayToLogOverflow =
2109 FALSE;
2110 }
2111
2112 } else if (deviceExtension->DpcInterlockMouse >= 0) {
2113
2114 //
2115 // The ISR DPC is already executing. Tell the ISR DPC it has
2116 // more work to do by incrementing DpcInterlockMouse.
2117 //
2118
2119 deviceExtension->DpcInterlockMouse += 1;
2120
2121 } else {
2122
2123 //
2124 // Queue the ISR DPC.
2125 //
2126
2127 KeInsertQueueDpc(
2128 &deviceExtension->MouseIsrDpc,
2129 DeviceObject->CurrentIrp,
2130 NULL
2131 );
2132 }
2133
2134 }
2135
2136 return;
2137}
2138
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette