|
|
1.1 root 1:
2: /*++
3:
4: Copyright (c) 1990, 1991, 1992, 1993 Microsoft Corporation
5:
6: Module Name:
7:
8: i8042cmn.c
9:
10: Abstract:
11:
12: The common portions of the Intel i8042 port driver which
13: apply to both the keyboard and the auxiliary (PS/2 mouse) device.
14:
15: Environment:
16:
17: Kernel mode only.
18:
19: Notes:
20:
21: NOTES: (Future/outstanding issues)
22:
23: - Powerfail not implemented.
24:
25: - IOCTL_INTERNAL_KEYBOARD_DISCONNECT and IOCTL_INTERNAL_MOUSE_DISCONNECT
26: have not been implemented. They're not needed until the class
27: unload routine is implemented. Right now, we don't want to allow
28: either the keyboard or the mouse class driver to unload.
29:
30: - Consolidate duplicate code, where possible and appropriate.
31:
32: Revision History:
33:
34: --*/
35:
36: #include "stdarg.h"
37: #include "stdio.h"
38: #include "string.h"
39: #include "ntddk.h"
40: #include "i8042prt.h"
41: #include "i8042log.h"
42:
43: //
44: // Declare the global debug flag for this driver.
45: //
46:
47: #if DBG
48: ULONG i8042Debug = 0;
49: #endif
50:
51:
52: VOID
53: I8042CompletionDpc(
54: IN PKDPC Dpc,
55: IN PDEVICE_OBJECT DeviceObject,
56: IN PIRP Irp,
57: IN PVOID Context
58:
59: /*++
60:
61: Routine Description:
62:
63: This routine runs at DISPATCH_LEVEL IRQL to complete requests.
64: It is queued by the ISR routine.
65:
66: Note: Currently, only the keyboard ISR queues this routine.
67: Only the keyboard ISR handles both input and output to
68: the device. The mouse is input-only once it is initialized.
69:
70: Arguments:
71:
72: Dpc - Pointer to the DPC object.
73:
74: DeviceObject - Pointer to the device object.
75:
76: Irp - Not used.
77:
78: Context - Indicates type of error to log.
79:
80: Return Value:
81:
82: None.
83:
84: --*/
85:
86: )
87: {
88: PDEVICE_EXTENSION deviceExtension;
89: PIO_STACK_LOCATION irpSp;
90:
91: UNREFERENCED_PARAMETER(Dpc);
92: UNREFERENCED_PARAMETER(Context);
93:
94: I8xPrint((2, "I8042PRT-I8042CompletionDpc: enter\n"));
95:
96: //
97: // Get the device extension and current IRP.
98: //
99:
100: deviceExtension = DeviceObject->DeviceExtension;
101:
102: //
103: // Stop the command timer.
104: //
105:
106: KeCancelTimer(&deviceExtension->CommandTimer);
107:
108: //
109: // Get the current IRP.
110: //
111:
112: Irp = DeviceObject->CurrentIrp;
113: ASSERT(Irp != NULL);
114:
115: //
116: // Get a pointer to the current parameters for this request. The
117: // information is contained in the current stack location.
118: //
119:
120: irpSp = IoGetCurrentIrpStackLocation(Irp);
121:
122: //
123: // We know we're completing an internal device control request. Switch
124: // on IoControlCode.
125: //
126:
127: switch(irpSp->Parameters.DeviceIoControl.IoControlCode) {
128:
129: //
130: // Complete the keyboard set indicators request.
131: //
132:
133: case IOCTL_KEYBOARD_SET_INDICATORS:
134:
135: I8xPrint((
136: 2,
137: "I8042PRT-I8042CompletionDpc: keyboard set indicators updated\n"
138: ));
139:
140: //
141: // Update the current indicators flag in the device extension.
142: //
143:
144: deviceExtension->Configuration.KeyboardIndicators =
145: *(PKEYBOARD_INDICATOR_PARAMETERS)
146: Irp->AssociatedIrp.SystemBuffer;
147:
148: I8xPrint((
149: 2,
150: "I8042PRT-I8042CompletionDpc: new LED flags 0x%x\n",
151: deviceExtension->Configuration.KeyboardIndicators.LedFlags
152: ));
153:
154: break;
155:
156: //
157: // Complete the keyboard set typematic request.
158: //
159:
160: case IOCTL_KEYBOARD_SET_TYPEMATIC:
161:
162: I8xPrint((
163: 2,
164: "I8042PRT-I8042CompletionDpc: keyboard set typematic updated\n"
165: ));
166:
167: //
168: // Update the current typematic rate/delay in the device extension.
169: //
170:
171: deviceExtension->Configuration.KeyRepeatCurrent =
172: *(PKEYBOARD_TYPEMATIC_PARAMETERS)
173: Irp->AssociatedIrp.SystemBuffer;
174:
175: I8xPrint((
176: 2,
177: "I8042PRT-I8042CompletionDpc: new rate/delay 0x%x/%x\n",
178: deviceExtension->Configuration.KeyRepeatCurrent.Rate,
179: deviceExtension->Configuration.KeyRepeatCurrent.Delay
180: ));
181:
182: break;
183:
184: default:
185:
186: I8xPrint((2, "I8042PRT-I8042CompletionDpc: miscellaneous\n"));
187:
188: break;
189:
190: }
191:
192: //
193: // Set the completion status, start the next packet, and complete the
194: // request.
195: //
196:
197: Irp->IoStatus.Status = STATUS_SUCCESS;
198: IoStartNextPacket(DeviceObject, FALSE);
199: IoCompleteRequest (Irp, IO_KEYBOARD_INCREMENT);
200:
201: I8xPrint((2, "I8042PRT-I8042CompletionDpc: exit\n"));
202: }
203:
204: VOID
205: I8042ErrorLogDpc(
206: IN PKDPC Dpc,
207: IN PDEVICE_OBJECT DeviceObject,
208: IN PIRP Irp,
209: IN PVOID Context
210: )
211:
212: /*++
213:
214: Routine Description:
215:
216: This routine runs at DISPATCH_LEVEL IRQL to log errors that are
217: discovered at IRQL > DISPATCH_LEVEL (e.g., in the ISR routine or
218: in a routine that is executed via KeSynchronizeExecution). There
219: is not necessarily a current request associated with this condition.
220:
221: Arguments:
222:
223: Dpc - Pointer to the DPC object.
224:
225: DeviceObject - Pointer to the device object.
226:
227: Irp - Not used.
228:
229: Context - Indicates type of error to log.
230:
231: Return Value:
232:
233: None.
234:
235: --*/
236:
237: {
238: PDEVICE_EXTENSION deviceExtension;
239: PIO_ERROR_LOG_PACKET errorLogEntry;
240:
241: UNREFERENCED_PARAMETER(Dpc);
242: UNREFERENCED_PARAMETER(Irp);
243:
244: I8xPrint((2, "I8042PRT-I8042ErrorLogDpc: enter\n"));
245:
246: deviceExtension = DeviceObject->DeviceExtension;
247:
248: //
249: // Log an error packet.
250: //
251:
252: errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
253: DeviceObject,
254: sizeof(IO_ERROR_LOG_PACKET)
255: + (2 * sizeof(ULONG))
256: );
257: if (errorLogEntry != NULL) {
258:
259: errorLogEntry->DumpDataSize = 2 * sizeof(ULONG);
260: if ((ULONG) Context == I8042_KBD_BUFFER_OVERFLOW) {
261: errorLogEntry->UniqueErrorValue = I8042_ERROR_VALUE_BASE + 310;
262: errorLogEntry->DumpData[0] = sizeof(KEYBOARD_INPUT_DATA);
263: errorLogEntry->DumpData[1] =
264: deviceExtension->Configuration.KeyboardAttributes.InputDataQueueLength;
265: } else if ((ULONG) Context == I8042_MOU_BUFFER_OVERFLOW) {
266: errorLogEntry->UniqueErrorValue = I8042_ERROR_VALUE_BASE + 320;
267: errorLogEntry->DumpData[0] = sizeof(MOUSE_INPUT_DATA);
268: errorLogEntry->DumpData[1] =
269: deviceExtension->Configuration.MouseAttributes.InputDataQueueLength;
270: } else {
271: errorLogEntry->UniqueErrorValue = I8042_ERROR_VALUE_BASE + 330;
272: errorLogEntry->DumpData[0] = 0;
273: errorLogEntry->DumpData[1] = 0;
274: }
275:
276: errorLogEntry->ErrorCode = (ULONG) Context;
277: errorLogEntry->SequenceNumber = 0;
278: errorLogEntry->MajorFunctionCode = 0;
279: errorLogEntry->IoControlCode = 0;
280: errorLogEntry->RetryCount = 0;
281: errorLogEntry->FinalStatus = 0;
282:
283: IoWriteErrorLogEntry(errorLogEntry);
284: }
285:
286: I8xPrint((2, "I8042PRT-I8042ErrorLogDpc: exit\n"));
287:
288: }
289:
290: NTSTATUS
291: I8042Flush(
292: IN PDEVICE_OBJECT DeviceObject,
293: IN PIRP Irp
294: )
295: {
296: UNREFERENCED_PARAMETER(DeviceObject);
297: UNREFERENCED_PARAMETER(Irp);
298:
299: I8xPrint((2,"I8042PRT-I8042Flush: enter\n"));
300: I8xPrint((2,"I8042PRT-I8042Flush: exit\n"));
301:
302: return(STATUS_NOT_IMPLEMENTED);
303: }
304:
305: NTSTATUS
306: I8042InternalDeviceControl(
307: IN PDEVICE_OBJECT DeviceObject,
308: IN PIRP Irp
309: )
310:
311: /*++
312:
313: Routine Description:
314:
315: This routine is the dispatch routine for internal device control requests.
316:
317: Arguments:
318:
319: DeviceObject - Pointer to the device object.
320:
321: Irp - Pointer to the request packet.
322:
323: Return Value:
324:
325: Status is returned.
326:
327: --*/
328:
329: {
330:
331: PIO_STACK_LOCATION irpSp;
332: PDEVICE_EXTENSION deviceExtension;
333: NTSTATUS status;
334: I8042_INITIALIZE_DATA_CONTEXT initializeDataContext;
335: PVOID parameters;
336: PKEYBOARD_ATTRIBUTES keyboardAttributes;
337: ULONG sizeOfTranslation;
338:
339: I8xPrint((2,"I8042PRT-I8042InternalDeviceControl: enter\n"));
340:
341: //
342: // Get a pointer to the device extension.
343: //
344:
345: deviceExtension = DeviceObject->DeviceExtension;
346:
347: //
348: // Initialize the returned Information field.
349: //
350:
351: Irp->IoStatus.Information = 0;
352:
353: //
354: // Get a pointer to the current parameters for this request. The
355: // information is contained in the current stack location.
356: //
357:
358: irpSp = IoGetCurrentIrpStackLocation(Irp);
359:
360: //
361: // Case on the device control subfunction that is being performed by the
362: // requestor.
363: //
364:
365: switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
366:
367: //
368: // Connect a keyboard class device driver to the port driver.
369: //
370:
371: case IOCTL_INTERNAL_KEYBOARD_CONNECT:
372:
373: I8xPrint((
374: 2,
375: "I8042PRT-I8042InternalDeviceControl: keyboard connect\n"
376: ));
377:
378: //
379: // Only allow a connection if the keyboard hardware is present.
380: // Also, only allow one connection.
381: //
382: // FUTURE: Consider allowing multiple connections, just for
383: // the sake of generality? It really makes no sense for the
384: // i8042, though.
385: //
386:
387: if ((deviceExtension->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
388: != KEYBOARD_HARDWARE_PRESENT) {
389:
390: I8xPrint((
391: 2,
392: "I8042PRT-I8042InternalDeviceControl: error - hardware not present\n"
393: ));
394:
395: status = STATUS_NO_SUCH_DEVICE;
396: break;
397: } else
398: if (deviceExtension->KeyboardExtension.ConnectData.ClassService
399: != NULL) {
400:
401: I8xPrint((
402: 2,
403: "I8042PRT-I8042InternalDeviceControl: error - already connected\n"
404: ));
405:
406: status = STATUS_SHARING_VIOLATION;
407: break;
408:
409: } else
410: if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
411: sizeof(CONNECT_DATA)) {
412:
413: I8xPrint((
414: 2,
415: "I8042PRT-I8042InternalDeviceControl: error - invalid buffer length\n"
416: ));
417:
418: status = STATUS_INVALID_PARAMETER;
419: break;
420: }
421:
422: //
423: // Copy the connection parameters to the device extension.
424: //
425:
426: deviceExtension->KeyboardExtension.ConnectData =
427: *((PCONNECT_DATA) (irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
428:
429: //
430: // Reinitialize the port input data queue.
431: //
432:
433: initializeDataContext.DeviceExtension = deviceExtension;
434: initializeDataContext.DeviceType = KeyboardDeviceType;
435:
436: KeSynchronizeExecution(
437: deviceExtension->KeyboardInterruptObject,
438: (PKSYNCHRONIZE_ROUTINE) I8xInitializeDataQueue,
439: (PVOID) &initializeDataContext
440: );
441:
442: //
443: // Set the completion status.
444: //
445:
446: status = STATUS_SUCCESS;
447: break;
448:
449: //
450: // Disconnect a keyboard class device driver from the port driver.
451: //
452: // NOTE: Not implemented.
453: //
454:
455: case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
456:
457: I8xPrint((
458: 2,
459: "I8042PRT-I8042InternalDeviceControl: keyboard disconnect\n"
460: ));
461:
462: //
463: // Perform a keyboard interrupt disable call.
464: //
465:
466: //
467: // Clear the connection parameters in the device extension.
468: // NOTE: Must synchronize this with the keyboard ISR.
469: //
470: //
471: //deviceExtension->KeyboardExtension.ConnectData.ClassDeviceObject =
472: // Null;
473: //deviceExtension->KeyboardExtension.ConnectData.ClassService =
474: // Null;
475:
476: //
477: // Set the completion status.
478: //
479:
480: status = STATUS_NOT_IMPLEMENTED;
481: break;
482:
483: //
484: // Connect a mouse class device driver to the port driver.
485: //
486:
487: case IOCTL_INTERNAL_MOUSE_CONNECT:
488:
489: I8xPrint((
490: 2,
491: "I8042PRT-I8042InternalDeviceControl: mouse connect\n"
492: ));
493:
494:
495: //
496: // Only allow a connection if the mouse hardware is present.
497: // Also, only allow one connection.
498: //
499: // FUTURE: Consider allowing multiple connections, just for
500: // the sake of generality? It really makes no sense for the
501: // i8042, though.
502: //
503:
504: if ((deviceExtension->HardwarePresent & MOUSE_HARDWARE_PRESENT)
505: != MOUSE_HARDWARE_PRESENT) {
506:
507: I8xPrint((
508: 2,
509: "I8042PRT-I8042InternalDeviceControl: error - hardware not present\n"
510: ));
511:
512: status = STATUS_NO_SUCH_DEVICE;
513: break;
514: } else
515: if (deviceExtension->MouseExtension.ConnectData.ClassService
516: != NULL) {
517:
518: I8xPrint((
519: 2,
520: "I8042PRT-I8042InternalDeviceControl: error - already connected\n"
521: ));
522:
523: status = STATUS_SHARING_VIOLATION;
524: break;
525:
526: } else
527: if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
528: sizeof(CONNECT_DATA)) {
529:
530: I8xPrint((
531: 2,
532: "I8042PRT-I8042InternalDeviceControl: error - invalid buffer length\n"
533: ));
534:
535: status = STATUS_INVALID_PARAMETER;
536: break;
537: }
538:
539: //
540: // Copy the connection parameters to the device extension.
541: //
542:
543: deviceExtension->MouseExtension.ConnectData =
544: *((PCONNECT_DATA) (irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
545:
546: //
547: // Reinitialize the port input data queue.
548: //
549:
550: initializeDataContext.DeviceExtension = deviceExtension;
551: initializeDataContext.DeviceType = MouseDeviceType;
552:
553: KeSynchronizeExecution(
554: deviceExtension->MouseInterruptObject,
555: (PKSYNCHRONIZE_ROUTINE) I8xInitializeDataQueue,
556: (PVOID) &initializeDataContext
557: );
558:
559: //
560: // Set the completion status.
561: //
562:
563: status = STATUS_SUCCESS;
564: break;
565:
566: //
567: // Disconnect a mouse class device driver from the port driver.
568: //
569: // NOTE: Not implemented.
570: //
571:
572: case IOCTL_INTERNAL_MOUSE_DISCONNECT:
573:
574: I8xPrint((
575: 2,
576: "I8042PRT-I8042InternalDeviceControl: mouse disconnect\n"
577: ));
578:
579: //
580: // Perform a mouse interrupt disable call.
581: //
582:
583: //
584: // Clear the connection parameters in the device extension.
585: // NOTE: Must synchronize this with the mouse ISR.
586: //
587: //
588: //deviceExtension->MouseExtension.ConnectData.ClassDeviceObject =
589: // Null;
590: //deviceExtension->MouseExtension.ConnectData.ClassService =
591: // Null;
592:
593: //
594: // Set the completion status.
595: //
596:
597: status = STATUS_NOT_IMPLEMENTED;
598: break;
599:
600: //
601: // Enable keyboard interrupts (mark the request pending and handle
602: // it in StartIo).
603: //
604:
605: case IOCTL_INTERNAL_KEYBOARD_ENABLE:
606:
607: I8xPrint((
608: 2,
609: "I8042PRT-I8042InternalDeviceControl: keyboard enable\n"
610: ));
611:
612: status = STATUS_PENDING;
613: break;
614:
615: //
616: // Disable keyboard interrupts (mark the request pending and handle
617: // it in StartIo).
618: //
619:
620: case IOCTL_INTERNAL_KEYBOARD_DISABLE:
621:
622: I8xPrint((
623: 2,
624: "I8042PRT-I8042InternalDeviceControl: keyboard disable\n"
625: ));
626:
627: status = STATUS_PENDING;
628: break;
629:
630: //
631: // Enable mouse interrupts (mark the request pending and handle
632: // it in StartIo).
633: //
634:
635: case IOCTL_INTERNAL_MOUSE_ENABLE:
636:
637: I8xPrint((
638: 2,
639: "I8042PRT-I8042InternalDeviceControl: mouse enable\n"
640: ));
641:
642: status = STATUS_PENDING;
643: break;
644:
645: //
646: // Disable mouse interrupts (mark the request pending and handle
647: // it in StartIo).
648: //
649:
650: case IOCTL_INTERNAL_MOUSE_DISABLE:
651:
652: I8xPrint((
653: 2,
654: "I8042PRT-I8042InternalDeviceControl: mouse disable\n"
655: ));
656:
657: status = STATUS_PENDING;
658: break;
659:
660: //
661: // Query the keyboard attributes. First check for adequate buffer
662: // length. Then, copy the keyboard attributes from the device
663: // extension to the output buffer.
664: //
665:
666: case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
667:
668: I8xPrint((
669: 2,
670: "I8042PRT-I8042InternalDeviceControl: keyboard query attributes\n"
671: ));
672:
673: if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
674: sizeof(KEYBOARD_ATTRIBUTES)) {
675: status = STATUS_BUFFER_TOO_SMALL;
676: } else {
677:
678: //
679: // Copy the attributes from the DeviceExtension to the
680: // buffer.
681: //
682:
683: *(PKEYBOARD_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer =
684: deviceExtension->Configuration.KeyboardAttributes;
685:
686: Irp->IoStatus.Information = sizeof(KEYBOARD_ATTRIBUTES);
687: status = STATUS_SUCCESS;
688: }
689:
690: break;
691:
692: //
693: // Query the scan code to indicator-light mapping. Validate the
694: // parameters, and copy the indicator mapping information from
695: // the port device extension to the SystemBuffer.
696: //
697:
698: case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
699:
700: I8xPrint((
701: 2,
702: "I8042PRT-I8042InternalDeviceControl: keyboard query indicator translation\n"
703: ));
704:
705: sizeOfTranslation = sizeof(KEYBOARD_INDICATOR_TRANSLATION)
706: + (sizeof(INDICATOR_LIST)
707: * (deviceExtension->Configuration.KeyboardAttributes.NumberOfIndicators - 1));
708:
709: if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
710: sizeOfTranslation) {
711: status = STATUS_BUFFER_TOO_SMALL;
712: } else {
713:
714: //
715: // Copy the indicator mapping information to the system
716: // buffer.
717: //
718:
719: ((PKEYBOARD_INDICATOR_TRANSLATION)
720: Irp->AssociatedIrp.SystemBuffer)->NumberOfIndicatorKeys =
721: deviceExtension->Configuration.KeyboardAttributes.NumberOfIndicators;
722: RtlMoveMemory(
723: ((PKEYBOARD_INDICATOR_TRANSLATION)
724: Irp->AssociatedIrp.SystemBuffer)->IndicatorList,
725: (PCHAR) IndicatorList,
726: sizeOfTranslation
727: );
728:
729: Irp->IoStatus.Information = sizeOfTranslation;
730: status = STATUS_SUCCESS;
731: }
732:
733: break;
734:
735: //
736: // Query the keyboard indicators. Validate the parameters, and
737: // copy the indicator information from the port device extension to
738: // the SystemBuffer.
739: //
740:
741: case IOCTL_KEYBOARD_QUERY_INDICATORS:
742:
743:
744: I8xPrint((
745: 2,
746: "I8042PRT-I8042InternalDeviceControl: keyboard query indicators\n"
747: ));
748:
749: if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
750: sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
751: status = STATUS_BUFFER_TOO_SMALL;
752: } else {
753:
754: //
755: // Don't bother to synchronize access to the DeviceExtension
756: // KeyboardIndicators field while copying it. We don't
757: // really care if another process is setting the LEDs via
758: // StartIo running on another processor.
759: //
760:
761: *(PKEYBOARD_INDICATOR_PARAMETERS)
762: Irp->AssociatedIrp.SystemBuffer =
763: deviceExtension->Configuration.KeyboardIndicators;
764: Irp->IoStatus.Information =
765: sizeof(KEYBOARD_INDICATOR_PARAMETERS);
766: status = STATUS_SUCCESS;
767: }
768:
769: break;
770:
771: //
772: // Set the keyboard indicators (validate the parameters, mark the
773: // request pending, and handle it in StartIo).
774: //
775:
776: case IOCTL_KEYBOARD_SET_INDICATORS:
777:
778: I8xPrint((
779: 2,
780: "I8042PRT-I8042InternalDeviceControl: keyboard set indicators\n"
781: ));
782:
783: if ((irpSp->Parameters.DeviceIoControl.InputBufferLength <
784: sizeof(KEYBOARD_INDICATOR_PARAMETERS)) ||
785: ((((PKEYBOARD_INDICATOR_PARAMETERS)
786: Irp->AssociatedIrp.SystemBuffer)->LedFlags
787: & ~(KEYBOARD_SCROLL_LOCK_ON
788: | KEYBOARD_NUM_LOCK_ON | KEYBOARD_CAPS_LOCK_ON)) != 0)) {
789: status = STATUS_INVALID_PARAMETER;
790: } else {
791: status = STATUS_PENDING;
792: }
793:
794: break;
795:
796: //
797: // Query the current keyboard typematic rate and delay. Validate
798: // the parameters, and copy the typematic information from the port
799: // device extension to the SystemBuffer.
800: //
801:
802: case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
803:
804: I8xPrint((
805: 2,
806: "I8042PRT-I8042InternalDeviceControl: keyboard query typematic\n"
807: ));
808:
809: if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
810: sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
811: status = STATUS_BUFFER_TOO_SMALL;
812: } else {
813:
814: //
815: // Don't bother to synchronize access to the DeviceExtension
816: // KeyRepeatCurrent field while copying it. We don't
817: // really care if another process is setting the typematic
818: // rate/delay via StartIo running on another processor.
819: //
820:
821: *(PKEYBOARD_TYPEMATIC_PARAMETERS)
822: Irp->AssociatedIrp.SystemBuffer =
823: deviceExtension->Configuration.KeyRepeatCurrent;
824: Irp->IoStatus.Information =
825: sizeof(KEYBOARD_TYPEMATIC_PARAMETERS);
826: status = STATUS_SUCCESS;
827: }
828:
829: break;
830:
831: //
832: // Set the keyboard typematic rate and delay (validate the parameters,
833: // mark the request pending, and handle it in StartIo).
834: //
835:
836: case IOCTL_KEYBOARD_SET_TYPEMATIC:
837:
838: I8xPrint((
839: 2,
840: "I8042PRT-I8042InternalDeviceControl: keyboard set typematic\n"
841: ));
842:
843: parameters = Irp->AssociatedIrp.SystemBuffer;
844: keyboardAttributes =
845: &deviceExtension->Configuration.KeyboardAttributes;
846:
847: if ((irpSp->Parameters.DeviceIoControl.InputBufferLength <
848: sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) ||
849: (((PKEYBOARD_TYPEMATIC_PARAMETERS) parameters)->Rate <
850: keyboardAttributes->KeyRepeatMinimum.Rate) ||
851: (((PKEYBOARD_TYPEMATIC_PARAMETERS) parameters)->Rate >
852: keyboardAttributes->KeyRepeatMaximum.Rate) ||
853: (((PKEYBOARD_TYPEMATIC_PARAMETERS) parameters)->Delay <
854: keyboardAttributes->KeyRepeatMinimum.Delay) ||
855: (((PKEYBOARD_TYPEMATIC_PARAMETERS) parameters)->Delay >
856: keyboardAttributes->KeyRepeatMaximum.Delay)) {
857: status = STATUS_INVALID_PARAMETER;
858: } else {
859: status = STATUS_PENDING;
860: }
861:
862: break;
863:
864: //
865: // Query the mouse attributes. First check for adequate buffer
866: // length. Then, copy the mouse attributes from the device
867: // extension to the output buffer.
868: //
869:
870: case IOCTL_MOUSE_QUERY_ATTRIBUTES:
871:
872: I8xPrint((
873: 2,
874: "I8042PRT-I8042InternalDeviceControl: mouse query attributes\n"
875: ));
876:
877: if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
878: sizeof(MOUSE_ATTRIBUTES)) {
879: status = STATUS_BUFFER_TOO_SMALL;
880: } else {
881:
882: //
883: // Copy the attributes from the DeviceExtension to the
884: // buffer.
885: //
886:
887: *(PMOUSE_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer =
888: deviceExtension->Configuration.MouseAttributes;
889:
890: Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
891: status = STATUS_SUCCESS;
892: }
893:
894: break;
895:
896: default:
897:
898: I8xPrint((
899: 2,
900: "I8042PRT-I8042InternalDeviceControl: INVALID REQUEST\n"
901: ));
902:
903: status = STATUS_INVALID_DEVICE_REQUEST;
904: break;
905: }
906:
907: Irp->IoStatus.Status = status;
908: if (status == STATUS_PENDING) {
909: IoMarkIrpPending(Irp);
910: IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
911: } else {
912: IoCompleteRequest(Irp, IO_NO_INCREMENT);
913: }
914:
915: I8xPrint((2,"I8042PRT-I8042InternalDeviceControl: exit\n"));
916:
917: return(status);
918:
919: }
920:
921: NTSTATUS
922: I8042OpenCloseDispatch(
923: IN PDEVICE_OBJECT DeviceObject,
924: IN PIRP Irp
925: )
926:
927: /*++
928:
929: Routine Description:
930:
931: This is the dispatch routine for create/open and close requests.
932: These requests complete successfully.
933:
934: Arguments:
935:
936: DeviceObject - Pointer to the device object.
937:
938: Irp - Pointer to the request packet.
939:
940: Return Value:
941:
942: Status is returned.
943:
944: --*/
945:
946: {
947:
948: UNREFERENCED_PARAMETER(DeviceObject);
949:
950: I8xPrint((3,"I8042PRT-I8042OpenCloseDispatch: enter\n"));
951:
952: //
953: // Complete the request with successful status.
954: //
955:
956: Irp->IoStatus.Status = STATUS_SUCCESS;
957: Irp->IoStatus.Information = 0;
958: IoCompleteRequest(Irp, IO_NO_INCREMENT);
959:
960: I8xPrint((3,"I8042PRT-I8042OpenCloseDispatch: exit\n"));
961:
962: return(STATUS_SUCCESS);
963:
964: }
965:
966: VOID
967: I8042RetriesExceededDpc(
968: IN PKDPC Dpc,
969: IN PDEVICE_OBJECT DeviceObject,
970: IN PIRP Irp,
971: IN PVOID Context
972: )
973:
974: /*++
975:
976: Routine Description:
977:
978: This routine runs at DISPATCH_LEVEL IRQL to complete requests that
979: have exceeded the maximum number of retries. It is queued in the
980: keyboard ISR.
981:
982: Arguments:
983:
984: Dpc - Pointer to the DPC object.
985:
986: DeviceObject - Pointer to the device object.
987:
988: Irp - Pointer to the Irp.
989:
990: Context - Not used.
991:
992: Return Value:
993:
994: None.
995:
996: --*/
997:
998: {
999: PDEVICE_EXTENSION deviceExtension;
1000: PIO_ERROR_LOG_PACKET errorLogEntry;
1001: PIO_STACK_LOCATION irpSp;
1002:
1003: UNREFERENCED_PARAMETER(Dpc);
1004: UNREFERENCED_PARAMETER(Context);
1005:
1006: I8xPrint((2, "I8042PRT-I8042RetriesExceededDpc: enter\n"));
1007:
1008: deviceExtension = DeviceObject->DeviceExtension;
1009:
1010: //
1011: // Set the completion status.
1012: //
1013:
1014: Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
1015:
1016: //
1017: // Log an error.
1018: //
1019:
1020: errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
1021: DeviceObject,
1022: sizeof(IO_ERROR_LOG_PACKET)
1023: + (3 * sizeof(ULONG))
1024: );
1025: if (errorLogEntry != NULL) {
1026:
1027: errorLogEntry->ErrorCode = I8042_RETRIES_EXCEEDED;
1028: errorLogEntry->DumpDataSize = 3 * sizeof(ULONG);
1029: errorLogEntry->SequenceNumber =
1030: deviceExtension->KeyboardExtension.SequenceNumber;
1031: irpSp = IoGetCurrentIrpStackLocation(Irp);
1032: errorLogEntry->MajorFunctionCode = irpSp->MajorFunction;
1033: errorLogEntry->IoControlCode =
1034: irpSp->Parameters.DeviceIoControl.IoControlCode;
1035: errorLogEntry->RetryCount =
1036: deviceExtension->KeyboardExtension.ResendCount;
1037: errorLogEntry->UniqueErrorValue = I8042_ERROR_VALUE_BASE + 210;
1038: errorLogEntry->FinalStatus = Irp->IoStatus.Status;
1039: errorLogEntry->DumpData[0] =
1040: deviceExtension->KeyboardExtension.CurrentOutput.State;
1041: errorLogEntry->DumpData[1] =
1042: deviceExtension->KeyboardExtension.CurrentOutput.FirstByte;
1043: errorLogEntry->DumpData[2] =
1044: deviceExtension->KeyboardExtension.CurrentOutput.LastByte;
1045:
1046: IoWriteErrorLogEntry(errorLogEntry);
1047: }
1048:
1049: //
1050: // Start the next packet and complete the request.
1051: //
1052:
1053: IoStartNextPacket(DeviceObject, FALSE);
1054: IoCompleteRequest (Irp, IO_KEYBOARD_INCREMENT);
1055:
1056: I8xPrint((2, "I8042PRT-I8042RetriesExceededDpc: exit\n"));
1057:
1058: }
1059:
1060: VOID
1061: I8042StartIo(
1062: IN PDEVICE_OBJECT DeviceObject,
1063: IN PIRP Irp
1064: )
1065:
1066: /*++
1067:
1068: Routine Description:
1069:
1070: This routine starts an I/O operation for the device.
1071:
1072: Arguments:
1073:
1074: DeviceObject - Pointer to the device object.
1075:
1076: Irp - Pointer to the request packet.
1077:
1078: Return Value:
1079:
1080: None.
1081:
1082: --*/
1083:
1084: {
1085: PDEVICE_EXTENSION deviceExtension;
1086: PIO_STACK_LOCATION irpSp;
1087: KEYBOARD_INITIATE_CONTEXT keyboardInitiateContext;
1088: LARGE_INTEGER deltaTime;
1089: INTERLOCKED_RESULT interlockedResult;
1090:
1091: I8xPrint((2, "I8042PRT-I8042StartIo: enter\n"));
1092:
1093: deviceExtension = DeviceObject->DeviceExtension;
1094:
1095: //
1096: // Bump the error log sequence number.
1097: //
1098:
1099: deviceExtension->KeyboardExtension.SequenceNumber += 1;
1100:
1101: //
1102: // Get a pointer to the current parameters for this request. The
1103: // information is contained in the current stack location.
1104: //
1105:
1106: irpSp = IoGetCurrentIrpStackLocation(Irp);
1107:
1108: //
1109: // We know we got here with an internal device control request. Switch
1110: // on IoControlCode.
1111: //
1112:
1113: switch(irpSp->Parameters.DeviceIoControl.IoControlCode) {
1114:
1115: //
1116: // Enable the keyboard device.
1117: //
1118:
1119: case IOCTL_INTERNAL_KEYBOARD_ENABLE:
1120:
1121: //
1122: // Enable keyboard by incrementing the KeyboardEnableCount
1123: // field. The keyboard ISR will start processing keyboard
1124: // interrupts when KeyboardEnableCount is non-zero. Note that
1125: // the keyboard device and its interrupts are *always* enabled
1126: // in the i8042 Controller Command Byte, following initialization.
1127: // Interrupts are ignored in the ISR, however, until the
1128: // KeyboardEnableCount is greater than zero (indicating that the
1129: // user has "enabled" the device).
1130: //
1131:
1132: interlockedResult = ExInterlockedIncrementLong(
1133: &deviceExtension->KeyboardEnableCount,
1134: &deviceExtension->SharedInterruptSpinLock
1135: );
1136:
1137: I8xPrint((
1138: 2,
1139: "I8042PRT-I8042StartIo: keyboard enable (count %d)\n",
1140: deviceExtension->KeyboardEnableCount
1141: ));
1142:
1143: Irp->IoStatus.Status = STATUS_SUCCESS;
1144:
1145: //
1146: // Complete the request.
1147: //
1148:
1149: IoStartNextPacket(DeviceObject, FALSE);
1150: IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
1151:
1152: break;
1153:
1154: //
1155: // Disable the keyboard device.
1156: //
1157:
1158: case IOCTL_INTERNAL_KEYBOARD_DISABLE:
1159:
1160: I8xPrint((2, "I8042PRT-I8042StartIo: keyboard disable"));
1161:
1162: if (deviceExtension->KeyboardEnableCount == 0) {
1163:
1164: //
1165: // Keyboard already disabled.
1166: //
1167:
1168: I8xPrint((2, " - error\n"));
1169:
1170: Irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
1171:
1172: } else {
1173:
1174: //
1175: // Disable keyboard by decrementing the KeyboardEnableCount
1176: // field. The keyboard ISR will ignore keyboard
1177: // interrupts when KeyboardEnableCount is zero.
1178: //
1179:
1180: interlockedResult =
1181: ExInterlockedDecrementLong(
1182: &deviceExtension->KeyboardEnableCount,
1183: &deviceExtension->SharedInterruptSpinLock
1184: );
1185:
1186: I8xPrint((
1187: 2,
1188: " (count %d)\n",
1189: deviceExtension->KeyboardEnableCount
1190: ));
1191:
1192: Irp->IoStatus.Status = STATUS_SUCCESS;
1193: }
1194:
1195: //
1196: // Complete the request.
1197: //
1198:
1199: IoStartNextPacket(DeviceObject, FALSE);
1200: IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
1201:
1202: break;
1203:
1204: //
1205: // Enable the mouse device.
1206: //
1207:
1208: case IOCTL_INTERNAL_MOUSE_ENABLE:
1209:
1210: //
1211: // Enable mouse by incrementing the MouseEnableCount
1212: // field. The mouse ISR will start processing mouse
1213: // interrupts when MouseEnableCount is non-zero. Note that
1214: // the mouse device and its interrupts are *always* enabled
1215: // in the i8042 Controller Command Byte, following initialization.
1216: // Interrupts are ignored in the ISR, however, until the
1217: // MouseEnableCount is greater than zero (indicating that the
1218: // user has "enabled" the device).
1219: //
1220:
1221:
1222: interlockedResult = ExInterlockedIncrementLong(
1223: &deviceExtension->MouseEnableCount,
1224: &deviceExtension->SharedInterruptSpinLock
1225: );
1226:
1227:
1228: I8xPrint((
1229: 2,
1230: "I8042PRT-I8042StartIo: mouse enable (count %d)\n",
1231: deviceExtension->MouseEnableCount
1232: ));
1233:
1234: Irp->IoStatus.Status = STATUS_SUCCESS;
1235:
1236: //
1237: // Complete the request.
1238: //
1239:
1240: IoStartNextPacket(DeviceObject, FALSE);
1241: IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
1242:
1243: break;
1244:
1245: //
1246: // Disable the mouse device.
1247: //
1248:
1249: case IOCTL_INTERNAL_MOUSE_DISABLE:
1250:
1251: I8xPrint((2, "I8042PRT-I8042StartIo: mouse disable"));
1252:
1253: if (deviceExtension->MouseEnableCount == 0) {
1254:
1255: //
1256: // Mouse already disabled.
1257: //
1258:
1259: I8xPrint((2, " - error\n"));
1260:
1261: Irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
1262:
1263: } else {
1264:
1265: //
1266: // Disable mouse by decrementing the MouseEnableCount
1267: // field. The mouse ISR will ignore keyboard
1268: // interrupts when MouseEnableCount is zero.
1269: //
1270:
1271: interlockedResult =
1272: ExInterlockedDecrementLong(
1273: &deviceExtension->MouseEnableCount,
1274: &deviceExtension->SharedInterruptSpinLock
1275: );
1276:
1277: I8xPrint((
1278: 2,
1279: " (count %d)\n",
1280: deviceExtension->MouseEnableCount
1281: ));
1282:
1283: Irp->IoStatus.Status = STATUS_SUCCESS;
1284: }
1285:
1286: //
1287: // Complete the request.
1288: //
1289:
1290: IoStartNextPacket(DeviceObject, FALSE);
1291: IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
1292:
1293: break;
1294:
1295: //
1296: // Set the keyboard indicators to the desired state.
1297: //
1298:
1299: case IOCTL_KEYBOARD_SET_INDICATORS:
1300:
1301: I8xPrint((2, "I8042PRT-I8042StartIo: keyboard set indicators\n"));
1302:
1303: //
1304: // Set up the context structure for the InitiateIo wrapper.
1305: //
1306:
1307: keyboardInitiateContext.DeviceObject = DeviceObject;
1308: keyboardInitiateContext.FirstByte = SET_KEYBOARD_INDICATORS;
1309: keyboardInitiateContext.LastByte =
1310: (UCHAR) ((PKEYBOARD_INDICATOR_PARAMETERS)
1311: Irp->AssociatedIrp.SystemBuffer)->LedFlags;
1312:
1313: //
1314: // Call the InitiateIo wrapper synchronously. The wrapper
1315: // stores the context parameters in the device extension,
1316: // and then initiates the I/O operation, all synchronized
1317: // with the keyboard ISR.
1318: //
1319:
1320: KeSynchronizeExecution(
1321: deviceExtension->KeyboardInterruptObject,
1322: (PKSYNCHRONIZE_ROUTINE) I8xKeyboardInitiateWrapper,
1323: (PVOID) &keyboardInitiateContext
1324: );
1325:
1326: //
1327: // Start the 1-second command timer. InitiateIo changed
1328: // the TimerCount already.
1329: //
1330:
1331: deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
1332: deltaTime.HighPart = -1;
1333:
1334: (VOID) KeSetTimer(
1335: &deviceExtension->CommandTimer,
1336: deltaTime,
1337: &deviceExtension->TimeOutDpc
1338: );
1339:
1340: break;
1341:
1342: //
1343: // Set the keyboard typematic rate and delay.
1344: //
1345:
1346: case IOCTL_KEYBOARD_SET_TYPEMATIC:
1347:
1348: I8xPrint((2, "I8042PRT-I8042StartIo: keyboard set typematic\n"));
1349:
1350: //
1351: // Set up the context structure for the InitiateIo wrapper.
1352: //
1353:
1354: keyboardInitiateContext.DeviceObject = DeviceObject;
1355: keyboardInitiateContext.FirstByte = SET_KEYBOARD_TYPEMATIC;
1356: keyboardInitiateContext.LastByte =
1357: I8xConvertTypematicParameters(
1358: ((PKEYBOARD_TYPEMATIC_PARAMETERS)
1359: Irp->AssociatedIrp.SystemBuffer)->Rate,
1360: ((PKEYBOARD_TYPEMATIC_PARAMETERS)
1361: Irp->AssociatedIrp.SystemBuffer)->Delay
1362: );
1363:
1364: //
1365: // Call the InitiateIo wrapper synchronously. The wrapper
1366: // stores the context parameters in the device extension,
1367: // and then initiates the I/O operation, all synchronized
1368: // with the keyboard ISR.
1369: //
1370:
1371: KeSynchronizeExecution(
1372: deviceExtension->KeyboardInterruptObject,
1373: (PKSYNCHRONIZE_ROUTINE) I8xKeyboardInitiateWrapper,
1374: (PVOID) &keyboardInitiateContext
1375: );
1376:
1377: //
1378: // Start the 1-second command timer. InitiateIo changed
1379: // the TimerCount already.
1380: //
1381:
1382: deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
1383: deltaTime.HighPart = -1;
1384:
1385: (VOID) KeSetTimer(
1386: &deviceExtension->CommandTimer,
1387: deltaTime,
1388: &deviceExtension->TimeOutDpc
1389: );
1390:
1391: break;
1392:
1393: default:
1394:
1395: I8xPrint((2, "I8042PRT-I8042StartIo: INVALID REQUEST\n"));
1396:
1397: //
1398: // Log an internal error. Note that we're calling the
1399: // error log DPC routine directly, rather than duplicating
1400: // code.
1401: //
1402:
1403: I8042ErrorLogDpc(
1404: (PKDPC) NULL,
1405: DeviceObject,
1406: Irp,
1407: (PVOID) (ULONG) I8042_INVALID_STARTIO_REQUEST
1408: );
1409:
1410: ASSERT(FALSE);
1411: break;
1412: }
1413:
1414: I8xPrint((2, "I8042PRT-I8042StartIo: exit\n"));
1415:
1416: return;
1417: }
1418:
1419: VOID
1420: I8042TimeOutDpc(
1421: IN PKDPC Dpc,
1422: IN PDEVICE_OBJECT DeviceObject,
1423: IN PVOID SystemContext1,
1424: IN PVOID SystemContext2
1425: )
1426:
1427: /*++
1428:
1429: Routine Description:
1430:
1431: This is the driver's command timeout routine. It is called when the
1432: command timer fires.
1433:
1434: Arguments:
1435:
1436: Dpc - Not Used.
1437:
1438: DeviceObject - Pointer to the device object.
1439:
1440: SystemContext1 - Not Used.
1441:
1442: SystemContext2 - Not Used.
1443:
1444: Return Value:
1445:
1446: None. As a side-effect, the timeout counter is updated and an error
1447: is logged.
1448:
1449: --*/
1450:
1451: {
1452: PDEVICE_EXTENSION deviceExtension;
1453: KIRQL cancelIrql;
1454: TIMER_CONTEXT timerContext;
1455: PIRP irp;
1456: PIO_ERROR_LOG_PACKET errorLogEntry;
1457: PIO_STACK_LOCATION irpSp;
1458: LARGE_INTEGER deltaTime;
1459:
1460: I8xPrint((3, "I8042PRT-I8042TimeOutDpc: enter\n"));
1461:
1462: //
1463: // Get the device extension.
1464: //
1465:
1466: deviceExtension = DeviceObject->DeviceExtension;
1467:
1468: //
1469: // Acquire the cancel spinlock, verify that the CurrentIrp has not been
1470: // cancelled (i.e., CurrentIrp != NULL), set the cancel routine to NULL,
1471: // and release the cancel spinlock.
1472: //
1473:
1474: IoAcquireCancelSpinLock(&cancelIrql);
1475: irp = DeviceObject->CurrentIrp;
1476: if (irp == NULL) {
1477: IoReleaseCancelSpinLock(cancelIrql);
1478: return;
1479: }
1480: IoSetCancelRoutine(irp, NULL);
1481: IoReleaseCancelSpinLock(cancelIrql);
1482:
1483: //
1484: // If the TimerCounter == 0 on entry to this routine, the last packet
1485: // timed out and was completed. We just decrement TimerCounter
1486: // (synchronously) to indicate that we're no longer timing.
1487: //
1488: // If the TimerCounter indicates no timeout (I8042_ASYNC_NO_TIMEOUT)
1489: // on entry to this routine, there is no command being timed.
1490: //
1491:
1492: timerContext.DeviceObject = DeviceObject;
1493: timerContext.TimerCounter = &deviceExtension->TimerCount;
1494:
1495: KeSynchronizeExecution(
1496: deviceExtension->KeyboardInterruptObject,
1497: (PKSYNCHRONIZE_ROUTINE) I8xDecrementTimer,
1498: &timerContext
1499: );
1500:
1501: if (timerContext.NewTimerCount == 0) {
1502:
1503: //
1504: // Set up the IO Status Block prior to completing the request.
1505: //
1506:
1507: DeviceObject->CurrentIrp->IoStatus.Information = 0;
1508: DeviceObject->CurrentIrp->IoStatus.Status = STATUS_IO_TIMEOUT;
1509:
1510: //
1511: // Log a timeout error.
1512: //
1513:
1514: errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
1515: DeviceObject,
1516: sizeof(IO_ERROR_LOG_PACKET)
1517: + (3 * sizeof(ULONG))
1518: );
1519:
1520: if (errorLogEntry != NULL) {
1521:
1522: errorLogEntry->ErrorCode = I8042_TIMEOUT;
1523: errorLogEntry->DumpDataSize = 3 * sizeof(ULONG);
1524: errorLogEntry->SequenceNumber =
1525: deviceExtension->KeyboardExtension.SequenceNumber;
1526: irpSp = IoGetCurrentIrpStackLocation(irp);
1527: errorLogEntry->MajorFunctionCode = irpSp->MajorFunction;
1528: errorLogEntry->IoControlCode =
1529: irpSp->Parameters.DeviceIoControl.IoControlCode;
1530: errorLogEntry->RetryCount =
1531: deviceExtension->KeyboardExtension.ResendCount;
1532: errorLogEntry->UniqueErrorValue = 90;
1533: errorLogEntry->FinalStatus = STATUS_IO_TIMEOUT;
1534: errorLogEntry->DumpData[0] =
1535: deviceExtension->KeyboardExtension.CurrentOutput.State;
1536: errorLogEntry->DumpData[1] =
1537: deviceExtension->KeyboardExtension.CurrentOutput.FirstByte;
1538: errorLogEntry->DumpData[2] =
1539: deviceExtension->KeyboardExtension.CurrentOutput.LastByte;
1540:
1541: IoWriteErrorLogEntry(errorLogEntry);
1542: }
1543:
1544: //
1545: // Start the next packet and complete the request.
1546: //
1547:
1548: IoStartNextPacket(DeviceObject, FALSE);
1549: IoCompleteRequest(irp, IO_KEYBOARD_INCREMENT);
1550:
1551: } else {
1552:
1553: //
1554: // Restart the command timer. Once started, the timer stops only
1555: // when the TimerCount goes to zero (indicating that the command
1556: // has timed out) or when explicitly cancelled in the completion
1557: // DPC (indicating that the command has successfully completed).
1558: //
1559:
1560: deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
1561: deltaTime.HighPart = -1;
1562:
1563: (VOID) KeSetTimer(
1564: &deviceExtension->CommandTimer,
1565: deltaTime,
1566: &deviceExtension->TimeOutDpc
1567: );
1568: }
1569:
1570: I8xPrint((3, "I8042PRT-I8042TimeOutDpc: exit\n"));
1571: }
1572:
1573: #if DBG
1574: VOID
1575: I8xDebugPrint(
1576: ULONG DebugPrintLevel,
1577: PCCHAR DebugMessage,
1578: ...
1579: )
1580:
1581: /*++
1582:
1583: Routine Description:
1584:
1585: Debug print routine.
1586:
1587: Arguments:
1588:
1589: Debug print level between 0 and 3, with 3 being the most verbose.
1590:
1591: Return Value:
1592:
1593: None.
1594:
1595: --*/
1596:
1597: {
1598: va_list ap;
1599:
1600: va_start(ap, DebugMessage);
1601:
1602: if (DebugPrintLevel <= i8042Debug) {
1603:
1604: char buffer[128];
1605:
1606: (VOID) vsprintf(buffer, DebugMessage, ap);
1607:
1608: DbgPrint(buffer);
1609: }
1610:
1611: va_end(ap);
1612:
1613: }
1614: #endif
1615:
1616:
1617: VOID
1618: I8xDecrementTimer(
1619: IN PTIMER_CONTEXT Context
1620: )
1621:
1622: /*++
1623:
1624: Routine Description:
1625:
1626: This routine decrements the timeout counter. It is called from
1627: I8042TimeOutDpc.
1628:
1629: Arguments:
1630:
1631: Context - Points to the context structure containing a pointer
1632: to the device object and a pointer to the timeout counter.
1633:
1634: Return Value:
1635:
1636: None. As a side-effect, the timeout counter is updated.
1637:
1638: --*/
1639:
1640: {
1641: PDEVICE_OBJECT deviceObject;
1642: PDEVICE_EXTENSION deviceExtension;
1643:
1644: deviceObject = Context->DeviceObject;
1645: deviceExtension = deviceObject->DeviceExtension;
1646:
1647: //
1648: // Decrement the timeout counter.
1649: //
1650:
1651: if (*(Context->TimerCounter) != I8042_ASYNC_NO_TIMEOUT)
1652: (*(Context->TimerCounter))--;
1653:
1654: //
1655: // Return the decremented timer count in NewTimerCount. The
1656: // TimerCounter itself could change between the time this KeSynch'ed
1657: // routine returns to the TimeOutDpc, and the time the TimeOutDpc
1658: // looks at the value. The TimeOutDpc will use NewTimerCount.
1659: //
1660:
1661: Context->NewTimerCount = *(Context->TimerCounter);
1662:
1663: //
1664: // Reset the state and the resend count, if the timeout counter goes to 0.
1665: //
1666:
1667: if (*(Context->TimerCounter) == 0) {
1668: deviceExtension->KeyboardExtension.CurrentOutput.State
1669: = Idle;
1670: deviceExtension->KeyboardExtension.ResendCount = 0;
1671: }
1672:
1673: }
1674:
1675: VOID
1676: I8xDpcVariableOperation(
1677: IN PVOID Context
1678: )
1679:
1680: /*++
1681:
1682: Routine Description:
1683:
1684: This routine is called synchronously by the ISR DPC to perform an
1685: operation on the InterlockedDpcVariable. The operations that can be
1686: performed include increment, decrement, write, and read. The ISR
1687: itself reads and writes the InterlockedDpcVariable without calling this
1688: routine.
1689:
1690: Arguments:
1691:
1692: Context - Pointer to a structure containing the address of the variable
1693: to be operated on, the operation to perform, and the address at
1694: which to copy the resulting value of the variable (the latter is also
1695: used to pass in the value to write to the variable, on a write
1696: operation).
1697:
1698: Return Value:
1699:
1700: None.
1701:
1702: --*/
1703:
1704: {
1705: PVARIABLE_OPERATION_CONTEXT operationContext = Context;
1706:
1707: I8xPrint((3,"I8042PRT-I8xDpcVariableOperation: enter\n"));
1708: I8xPrint((
1709: 3,
1710: "\tPerforming %s at 0x%x (current value 0x%x)\n",
1711: (operationContext->Operation == IncrementOperation)? "increment":
1712: (operationContext->Operation == DecrementOperation)? "decrement":
1713: (operationContext->Operation == WriteOperation)? "write":
1714: (operationContext->Operation == ReadOperation)? "read":"",
1715: operationContext->VariableAddress,
1716: *(operationContext->VariableAddress)
1717: ));
1718:
1719: //
1720: // Perform the specified operation at the specified address.
1721: //
1722:
1723: switch(operationContext->Operation) {
1724: case IncrementOperation:
1725: *(operationContext->VariableAddress) += 1;
1726: break;
1727: case DecrementOperation:
1728: *(operationContext->VariableAddress) -= 1;
1729: break;
1730: case ReadOperation:
1731: break;
1732: case WriteOperation:
1733: I8xPrint((
1734: 3,
1735: "\tWriting 0x%x\n",
1736: *(operationContext->NewValue)
1737: ));
1738: *(operationContext->VariableAddress) =
1739: *(operationContext->NewValue);
1740: break;
1741: default:
1742: ASSERT(FALSE);
1743: break;
1744: }
1745:
1746: *(operationContext->NewValue) = *(operationContext->VariableAddress);
1747:
1748: I8xPrint((
1749: 3,
1750: "I8042PRT-I8xDpcVariableOperation: exit with value 0x%x\n",
1751: *(operationContext->NewValue)
1752: ));
1753: }
1754:
1755: VOID
1756: I8xGetDataQueuePointer(
1757: IN PVOID Context
1758: )
1759:
1760: /*++
1761:
1762: Routine Description:
1763:
1764: This routine is called synchronously to get the current DataIn and DataOut
1765: pointers for the port InputData queue.
1766:
1767: Arguments:
1768:
1769: Context - Pointer to a structure containing the device extension,
1770: device type, address at which to store the current DataIn pointer,
1771: and the address at which to store the current DataOut pointer.
1772:
1773: Return Value:
1774:
1775: None.
1776:
1777: --*/
1778:
1779: {
1780: PDEVICE_EXTENSION deviceExtension;
1781: CCHAR deviceType;
1782:
1783: I8xPrint((3,"I8042PRT-I8xGetDataQueuePointer: enter\n"));
1784:
1785: //
1786: // Get address of device extension.
1787: //
1788:
1789: deviceExtension = (PDEVICE_EXTENSION)
1790: ((PGET_DATA_POINTER_CONTEXT) Context)->DeviceExtension;
1791: deviceType = (CCHAR) ((PGET_DATA_POINTER_CONTEXT) Context)->DeviceType;
1792:
1793: //
1794: // Get the DataIn and DataOut pointers for the indicated device.
1795: //
1796:
1797: if (deviceType == KeyboardDeviceType) {
1798: I8xPrint((3,"I8042PRT-I8xGetDataQueuePointer: keyboard\n"));
1799: I8xPrint((
1800: 3,
1801: "I8042PRT-I8xGetDataQueuePointer: DataIn 0x%x, DataOut 0x%x\n",
1802: deviceExtension->KeyboardExtension.DataIn,
1803: deviceExtension->KeyboardExtension.DataOut
1804: ));
1805: ((PGET_DATA_POINTER_CONTEXT) Context)->DataIn =
1806: deviceExtension->KeyboardExtension.DataIn;
1807: ((PGET_DATA_POINTER_CONTEXT) Context)->DataOut =
1808: deviceExtension->KeyboardExtension.DataOut;
1809: ((PGET_DATA_POINTER_CONTEXT) Context)->InputCount =
1810: deviceExtension->KeyboardExtension.InputCount;
1811: } else if (deviceType == MouseDeviceType) {
1812: I8xPrint((3,"I8042PRT-I8xGetDataQueuePointer: mouse\n"));
1813: I8xPrint((
1814: 3,
1815: "I8042PRT-I8xGetDataQueuePointer: DataIn 0x%x, DataOut 0x%x\n",
1816: deviceExtension->MouseExtension.DataIn,
1817: deviceExtension->MouseExtension.DataOut
1818: ));
1819: ((PGET_DATA_POINTER_CONTEXT) Context)->DataIn =
1820: deviceExtension->MouseExtension.DataIn;
1821: ((PGET_DATA_POINTER_CONTEXT) Context)->DataOut =
1822: deviceExtension->MouseExtension.DataOut;
1823: ((PGET_DATA_POINTER_CONTEXT) Context)->InputCount =
1824: deviceExtension->MouseExtension.InputCount;
1825: } else {
1826: ASSERT(FALSE);
1827: }
1828:
1829: I8xPrint((3,"I8042PRT-I8xGetDataQueuePointer: exit\n"));
1830: }
1831:
1832: VOID
1833: I8xInitializeDataQueue (
1834: IN PVOID Context
1835: )
1836:
1837: /*++
1838:
1839: Routine Description:
1840:
1841: This routine initializes the input data queue for the indicated device.
1842: This routine is called via KeSynchronization, except when called from
1843: the initialization routine.
1844:
1845: Arguments:
1846:
1847: Context - Pointer to a structure containing the device extension and
1848: the device type.
1849:
1850: Return Value:
1851:
1852: None.
1853:
1854: --*/
1855:
1856: {
1857:
1858: PDEVICE_EXTENSION deviceExtension;
1859: CCHAR deviceType;
1860:
1861: I8xPrint((3,"I8042PRT-I8xInitializeDataQueue: enter\n"));
1862:
1863: //
1864: // Get address of device extension.
1865: //
1866:
1867: deviceExtension = (PDEVICE_EXTENSION)
1868: ((PI8042_INITIALIZE_DATA_CONTEXT) Context)->DeviceExtension;
1869: deviceType = (CCHAR) ((PI8042_INITIALIZE_DATA_CONTEXT) Context)->DeviceType;
1870:
1871: //
1872: // Initialize the input data queue for the indicated device.
1873: //
1874:
1875: if (deviceType == KeyboardDeviceType) {
1876: deviceExtension->KeyboardExtension.InputCount = 0;
1877: deviceExtension->KeyboardExtension.DataIn =
1878: deviceExtension->KeyboardExtension.InputData;
1879: deviceExtension->KeyboardExtension.DataOut =
1880: deviceExtension->KeyboardExtension.InputData;
1881: deviceExtension->KeyboardExtension.OkayToLogOverflow = TRUE;
1882: I8xPrint((3,"I8042PRT-I8xInitializeDataQueue: keyboard\n"));
1883: } else if (deviceType == MouseDeviceType) {
1884: deviceExtension->MouseExtension.InputCount = 0;
1885: deviceExtension->MouseExtension.DataIn =
1886: deviceExtension->MouseExtension.InputData;
1887: deviceExtension->MouseExtension.DataOut =
1888: deviceExtension->MouseExtension.InputData;
1889: deviceExtension->MouseExtension.OkayToLogOverflow = TRUE;
1890: I8xPrint((3,"I8042PRT-I8xInitializeDataQueue: mouse\n"));
1891: } else {
1892: ASSERT(FALSE);
1893: }
1894:
1895: I8xPrint((3,"I8042PRT-I8xInitializeDataQueue: exit\n"));
1896:
1897: }
1898:
1899: VOID
1900: I8xLogError(
1901: IN PDEVICE_OBJECT DeviceObject,
1902: IN NTSTATUS ErrorCode,
1903: IN ULONG UniqueErrorValue,
1904: IN NTSTATUS FinalStatus,
1905: IN PULONG DumpData,
1906: IN ULONG DumpCount
1907: )
1908:
1909: /*++
1910:
1911: Routine Description:
1912:
1913: This routine contains common code to write an error log entry. It is
1914: called from other routines, especially I8xInitializeKeyboard, to avoid
1915: duplication of code. Note that some routines continue to have their
1916: own error logging code (especially in the case where the error logging
1917: can be localized and/or the routine has more data because there is
1918: and IRP).
1919:
1920: Arguments:
1921:
1922: DeviceObject - Pointer to the device object.
1923:
1924: ErrorCode - The error code for the error log packet.
1925:
1926: UniqueErrorValue - The unique error value for the error log packet.
1927:
1928: FinalStatus - The final status of the operation for the error log packet.
1929:
1930: DumpData - Pointer to an array of dump data for the error log packet.
1931:
1932: DumpCount - The number of entries in the dump data array.
1933:
1934:
1935: Return Value:
1936:
1937: None.
1938:
1939: --*/
1940:
1941: {
1942: PIO_ERROR_LOG_PACKET errorLogEntry;
1943: ULONG i;
1944:
1945: errorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(
1946: DeviceObject,
1947: (UCHAR)
1948: (sizeof(IO_ERROR_LOG_PACKET)
1949: + (DumpCount * sizeof(ULONG)))
1950: );
1951:
1952: if (errorLogEntry != NULL) {
1953:
1954: errorLogEntry->ErrorCode = ErrorCode;
1955: errorLogEntry->DumpDataSize = (USHORT) (DumpCount * sizeof(ULONG));
1956: errorLogEntry->SequenceNumber = 0;
1957: errorLogEntry->MajorFunctionCode = 0;
1958: errorLogEntry->IoControlCode = 0;
1959: errorLogEntry->RetryCount = 0;
1960: errorLogEntry->UniqueErrorValue = UniqueErrorValue;
1961: errorLogEntry->FinalStatus = FinalStatus;
1962: for (i = 0; i < DumpCount; i++)
1963: errorLogEntry->DumpData[i] = DumpData[i];
1964:
1965: IoWriteErrorLogEntry(errorLogEntry);
1966: }
1967: }
1968:
1969: VOID
1970: I8xSetDataQueuePointer(
1971: IN PVOID Context
1972: )
1973:
1974: /*++
1975:
1976: Routine Description:
1977:
1978: This routine is called synchronously to set the DataOut pointer
1979: and InputCount for the port InputData queue.
1980:
1981: Arguments:
1982:
1983: Context - Pointer to a structure containing the device extension,
1984: device type, and the new DataOut value for the port InputData queue.
1985:
1986: Return Value:
1987:
1988: None.
1989:
1990: --*/
1991:
1992: {
1993: PDEVICE_EXTENSION deviceExtension;
1994: CCHAR deviceType;
1995:
1996: I8xPrint((3,"I8042PRT-I8xSetDataQueuePointer: enter\n"));
1997:
1998: //
1999: // Get address of device extension.
2000: //
2001:
2002: deviceExtension = (PDEVICE_EXTENSION)
2003: ((PSET_DATA_POINTER_CONTEXT) Context)->DeviceExtension;
2004: deviceType = (CCHAR) ((PSET_DATA_POINTER_CONTEXT) Context)->DeviceType;
2005:
2006: //
2007: // Set the DataOut pointer for the indicated device.
2008: //
2009:
2010: if (deviceType == KeyboardDeviceType) {
2011: I8xPrint((
2012: 3,
2013: "I8042PRT-I8xSetDataQueuePointer: old keyboard DataOut 0x%x, InputCount %d\n",
2014: deviceExtension->KeyboardExtension.DataOut,
2015: deviceExtension->KeyboardExtension.InputCount
2016: ));
2017: deviceExtension->KeyboardExtension.DataOut =
2018: ((PSET_DATA_POINTER_CONTEXT) Context)->DataOut;
2019: deviceExtension->KeyboardExtension.InputCount -=
2020: ((PSET_DATA_POINTER_CONTEXT) Context)->InputCount;
2021: if (deviceExtension->KeyboardExtension.InputCount == 0) {
2022:
2023: //
2024: // Reset the flag that determines whether it is time to log
2025: // queue overflow errors. We don't want to log errors too often.
2026: // Instead, log an error on the first overflow that occurs after
2027: // the ring buffer has been emptied, and then stop logging errors
2028: // until it gets cleared out and overflows again.
2029: //
2030:
2031: I8xPrint((
2032: 1,
2033: "I8042PRT-I8xSetDataQueuePointer: Okay to log keyboard overflow\n"
2034: ));
2035: deviceExtension->KeyboardExtension.OkayToLogOverflow = TRUE;
2036: }
2037: I8xPrint((
2038: 3,
2039: "I8042PRT-I8xSetDataQueuePointer: new keyboard DataOut 0x%x, InputCount %d\n",
2040: deviceExtension->KeyboardExtension.DataOut,
2041: deviceExtension->KeyboardExtension.InputCount
2042: ));
2043: } else if (deviceType == MouseDeviceType) {
2044: I8xPrint((
2045: 3,
2046: "I8042PRT-I8xSetDataQueuePointer: old mouse DataOut 0x%x, InputCount %d\n",
2047: deviceExtension->MouseExtension.DataOut,
2048: deviceExtension->MouseExtension.InputCount
2049: ));
2050: deviceExtension->MouseExtension.DataOut =
2051: ((PSET_DATA_POINTER_CONTEXT) Context)->DataOut;
2052: deviceExtension->MouseExtension.InputCount -=
2053: ((PSET_DATA_POINTER_CONTEXT) Context)->InputCount;
2054: if (deviceExtension->MouseExtension.InputCount == 0) {
2055:
2056: //
2057: // Reset the flag that determines whether it is time to log
2058: // queue overflow errors. We don't want to log errors too often.
2059: // Instead, log an error on the first overflow that occurs after
2060: // the ring buffer has been emptied, and then stop logging errors
2061: // until it gets cleared out and overflows again.
2062: //
2063:
2064: I8xPrint((
2065: 1,
2066: "I8042PRT-I8xSetDataQueuePointer: Okay to log mouse overflow\n"
2067: ));
2068: deviceExtension->MouseExtension.OkayToLogOverflow = TRUE;
2069: }
2070: I8xPrint((
2071: 3,
2072: "I8042PRT-I8xSetDataQueuePointer: new mouse DataOut 0x%x, InputCount %d\n",
2073: deviceExtension->MouseExtension.DataOut,
2074: deviceExtension->MouseExtension.InputCount
2075: ));
2076: } else {
2077: ASSERT(FALSE);
2078: }
2079:
2080: I8xPrint((3,"I8042PRT-I8xSetDataQueuePointer: exit\n"));
2081: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.