|
|
1.1 root 1:
2: /*++
3:
4: Copyright (c) 1990, 1991, 1992, 1993 Microsoft Corporation
5:
6: Module Name:
7:
8: kbddep.c
9:
10: Abstract:
11:
12: The initialization and hardware-dependent portions of
13: the Intel i8042 port driver which are specific to the
14: keyboard.
15:
16: Environment:
17:
18: Kernel mode only.
19:
20: Notes:
21:
22: NOTES: (Future/outstanding issues)
23:
24: - Powerfail not implemented.
25:
26: - Consolidate duplicate code, where possible and appropriate.
27:
28: Revision History:
29:
30: --*/
31:
32: #include "stdarg.h"
33: #include "stdio.h"
34: #include "string.h"
35: #include "ntddk.h"
36: #include "i8042prt.h"
37: #include "i8042log.h"
38:
39: //
40: // Use the alloc_text pragma to specify the driver initialization routines
41: // (they can be paged out).
42: //
43:
44: #ifdef ALLOC_PRAGMA
45: #pragma alloc_text(init,I8xKeyboardConfiguration)
46: #pragma alloc_text(init,I8xKeyboardPeripheralCallout)
47: #pragma alloc_text(init,I8xInitializeKeyboard)
48: #endif
49:
50:
51: BOOLEAN
52: I8042KeyboardInterruptService(
53: IN PKINTERRUPT Interrupt,
54: IN PVOID Context
55: )
56:
57: /*++
58:
59: Routine Description:
60:
61: This is the interrupt service routine for the keyboard device when
62: scan code set 1 is in use.
63:
64: Arguments:
65:
66: Interrupt - A pointer to the interrupt object for this interrupt.
67:
68: Context - A pointer to the device object.
69:
70: Return Value:
71:
72: Returns TRUE if the interrupt was expected (and therefore processed);
73: otherwise, FALSE is returned.
74:
75: --*/
76:
77: {
78: UCHAR scanCode;
79: PDEVICE_EXTENSION deviceExtension;
80: PDEVICE_OBJECT deviceObject;
81: KEYBOARD_SCAN_STATE *scanState;
82: PKEYBOARD_INPUT_DATA input;
83: ULONG i;
84:
85: UNREFERENCED_PARAMETER(Interrupt);
86:
87: I8xPrint((2, "I8042PRT-I8042KeyboardInterruptService: enter\n"));
88:
89: //
90: // Get the device extension.
91: //
92:
93: deviceObject = (PDEVICE_OBJECT) Context;
94: deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
95:
96: //
97: // Verify that this device really interrupted. Check the status
98: // register. The Output Buffer Full bit should be set, and the
99: // Auxiliary Device Output Buffer Full bit should be clear.
100: //
101:
102: if ((I8X_GET_STATUS_BYTE(deviceExtension->DeviceRegisters[CommandPort])
103: & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
104: != OUTPUT_BUFFER_FULL) {
105:
106: //
107: // Stall and then try again. The Olivetti MIPS machine
108: // sometimes gets an interrupt before the status
109: // register is set. They do this for DOS compatibility (some
110: // DOS apps do things in polled mode, until they see a character
111: // in the keyboard buffer at which point they expect to get
112: // an interrupt???).
113: //
114:
115: for (i = 0; i < (ULONG)deviceExtension->Configuration.PollStatusIterations; i++) {
116: KeStallExecutionProcessor(1);
117: if ((I8X_GET_STATUS_BYTE(deviceExtension->DeviceRegisters[CommandPort])
118: & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
119: == (OUTPUT_BUFFER_FULL))
120: break;
121: }
122:
123: if ((I8X_GET_STATUS_BYTE(deviceExtension->DeviceRegisters[CommandPort])
124: & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
125: != (OUTPUT_BUFFER_FULL)) {
126:
127: //
128: // Not our interrupt.
129: //
130: // NOTE: If the keyboard has not yet been "enabled", go ahead
131: // and read a byte from the data port anyway.
132: // This fixes weirdness on some Gateway machines, where
133: // we get an interrupt sometime during driver initialization
134: // after the interrupt is connected, but the output buffer
135: // full bit never gets set.
136: //
137:
138: I8xPrint((
139: 1,
140: "I8042PRT-I8042KeyboardInterruptService: not our interrupt!\n"
141: ));
142:
143: if (deviceExtension->KeyboardEnableCount == 0) {
144: scanCode =
145: I8X_GET_DATA_BYTE(deviceExtension->DeviceRegisters[DataPort]);
146: }
147:
148: return(FALSE);
149: }
150: }
151:
152: //
153: // The interrupt is valid. Read the byte from the i8042 data port.
154: //
155:
156: I8xGetByteAsynchronous(
157: (CCHAR) KeyboardDeviceType,
158: deviceExtension,
159: &scanCode
160: );
161:
162: I8xPrint((
163: 2,
164: "I8042PRT-I8042KeyboardInterruptService: scanCode 0x%x\n",
165: scanCode
166: ));
167:
168: //
169: // Take the appropriate action, depending on whether the byte read
170: // is a keyboard command response or a real scan code.
171: //
172:
173: switch(scanCode) {
174:
175: //
176: // The keyboard controller requests a resend. If the resend count
177: // has not been exceeded, re-initiate the I/O operation.
178: //
179:
180: case RESEND:
181:
182: I8xPrint((
183: 3,
184: "I8042PRT-I8042KeyboardInterruptService: RESEND, retries = %d\n",
185: deviceExtension->KeyboardExtension.ResendCount + 1
186: ));
187:
188: //
189: // If the timer count is zero, don't process the interrupt
190: // further. The timeout routine will complete this request.
191: //
192:
193: if (deviceExtension->TimerCount == 0) {
194: break;
195: }
196:
197: //
198: // Reset the timeout value to indicate no timeout.
199: //
200:
201: deviceExtension->TimerCount = I8042_ASYNC_NO_TIMEOUT;
202:
203: //
204: // If the maximum number of retries has not been exceeded,
205: // re-initiate the operation; otherwise, queue the DPC to
206: // complete this request.
207: //
208:
209: if ((deviceExtension->KeyboardExtension.CurrentOutput.State==Idle)
210: || (deviceObject->CurrentIrp == NULL)) {
211:
212: //
213: // We weren't sending a command or parameter to the hardware.
214: // Why would the hardware give us a resend??? Log an error.
215: //
216:
217: KeInsertQueueDpc(
218: &deviceExtension->ErrorLogDpc,
219: (PIRP) NULL,
220: (PVOID) (ULONG) I8042_UNEXPECTED_RESEND);
221:
222: } else if (deviceExtension->KeyboardExtension.ResendCount
223: < deviceExtension->Configuration.ResendIterations) {
224:
225: deviceExtension->KeyboardExtension.ResendCount += 1;
226: I8xKeyboardInitiateIo((PVOID) deviceObject);
227:
228: } else {
229:
230: KeInsertQueueDpc(
231: &deviceExtension->RetriesExceededDpc,
232: deviceObject->CurrentIrp,
233: NULL
234: );
235: }
236:
237: break;
238:
239: //
240: // The keyboard controller has acknowledged a previous send.
241: // If there are more bytes to send for the current packet, initiate
242: // the next send operation. Otherwise, queue the completion DPC.
243: //
244:
245: case ACKNOWLEDGE:
246:
247: I8xPrint((
248: 3,
249: "I8042PRT-I8042KeyboardInterruptService: ACK, "
250: ));
251:
252: //
253: // If the timer count is zero, don't process the interrupt
254: // further. The timeout routine will complete this request.
255: //
256:
257: if (deviceExtension->TimerCount == 0) {
258: break;
259: }
260:
261: //
262: // Reset the timeout value to indicate no timeout.
263: //
264:
265: deviceExtension->TimerCount = I8042_ASYNC_NO_TIMEOUT;
266:
267: //
268: // Reset resend count.
269: //
270:
271: deviceExtension->KeyboardExtension.ResendCount = 0;
272:
273: if (deviceExtension->KeyboardExtension.CurrentOutput.State
274: == SendFirstByte) {
275:
276: //
277: // We've successfully sent the first byte of a 2-byte
278: // command sequence. Initiate a send of the second byte.
279: //
280:
281: I8xPrint((
282: 3,
283: "now initiate send of last byte\n"
284: ));
285:
286: deviceExtension->KeyboardExtension.CurrentOutput.State =
287: SendLastByte;
288:
289: I8xKeyboardInitiateIo((PVOID) deviceObject);
290:
291: } else if (deviceExtension->KeyboardExtension.CurrentOutput.State
292: == SendLastByte) {
293:
294: //
295: // We've successfully sent all bytes in the command sequence.
296: // Reset the current state and queue the completion DPC.
297: //
298:
299: I8xPrint((
300: 3,
301: "all bytes have been sent\n"
302: ));
303:
304: deviceExtension->KeyboardExtension.CurrentOutput.State = Idle;
305:
306: IoRequestDpc(
307: deviceObject,
308: deviceObject->CurrentIrp,
309: NULL
310: );
311:
312: } else {
313: I8xPrint((
314: 1,
315: "unexpected, State is 0x%x\n",
316: deviceExtension->KeyboardExtension.CurrentOutput.State
317: ));
318: //
319: // Queue a DPC to log an internal driver error.
320: //
321:
322: KeInsertQueueDpc(
323: &deviceExtension->ErrorLogDpc,
324: (PIRP) NULL,
325: (PVOID) (ULONG) I8042_INVALID_ISR_STATE);
326:
327: //
328: // Note: We don't ASSERT here, because there are some
329: // machines (e.g., Compaq 386/25) that send back an
330: // extra ACK in response to the SETLED sequence. We've
331: // noticed this when, for example, CAPSLOCK is pressed
332: // at the same time as a normal key. Just ignore
333: // random ACKs.
334: //
335: }
336:
337: break;
338:
339: //
340: // Assume we've got a real, live scan code (or perhaps a keyboard
341: // overrun code, which we treat like a scan code). I.e., a key
342: // has been pressed or released. Queue the ISR DPC to process
343: // a complete scan code sequence.
344: //
345:
346: default:
347:
348: I8xPrint((
349: 3,
350: "I8042PRT-I8042KeyboardInterruptService: real scan code\n"
351: ));
352:
353: //
354: // Differentiate between an extended key sequence (first
355: // byte is E0, followed by a normal make or break byte), or
356: // a normal make code (one byte, the high bit is NOT set),
357: // or a normal break code (one byte, same as the make code
358: // but the high bit is set), or the key #126 byte sequence
359: // (requires special handling -- sequence is E11D459DC5).
360: //
361: // If there is a key detection error/overrun, the keyboard
362: // sends an overrun indicator (0xFF in scan code set 1).
363: // Map it to the overrun indicator expected by the Windows
364: // USER Raw Input Thread.
365: //
366:
367: input = &deviceExtension->KeyboardExtension.CurrentInput;
368: scanState = &deviceExtension->KeyboardExtension.CurrentScanState;
369:
370: if (scanCode == (UCHAR) 0xFF) {
371: I8xPrint((
372: 1,
373: "I8042PRT-I8042KeyboardInterruptService: OVERRUN\n"
374: ));
375: input->MakeCode = KEYBOARD_OVERRUN_MAKE_CODE;
376: input->Flags = 0;
377: *scanState = Normal;
378: } else {
379:
380: switch (*scanState) {
381: case Normal:
382: if (scanCode == (UCHAR) 0xE0) {
383: input->Flags |= KEY_E0;
384: *scanState = GotE0;
385: I8xPrint((
386: 3,
387: "I8042PRT-I8042KeyboardInterruptService: change state to GotE0\n"
388: ));
389: break;
390: } else if (scanCode == (UCHAR) 0xE1) {
391: input->Flags |= KEY_E1;
392: *scanState = GotE1;
393: I8xPrint((
394: 3,
395: "I8042PRT-I8042KeyboardInterruptService: change state to GotE1\n"
396: ));
397: break;
398: }
399:
400: //
401: // Fall through to the GotE0/GotE1 case for the rest of the
402: // Normal case.
403: //
404:
405: case GotE0:
406: case GotE1:
407:
408: if (scanCode > 0x7F) {
409:
410: //
411: // Got a break code. Strip the high bit off
412: // to get the associated make code and set flags
413: // to indicate a break code.
414: //
415:
416: I8xPrint((
417: 3,
418: "I8042PRT-I8042KeyboardInterruptService: BREAK code\n"
419: ));
420:
421: input->MakeCode = scanCode & 0x7F;
422: input->Flags |= KEY_BREAK;
423:
424: } else {
425:
426: //
427: // Got a make code.
428: //
429:
430: I8xPrint((
431: 3,
432: "I8042PRT-I8042KeyboardInterruptService: MAKE code\n"
433: ));
434:
435: input->MakeCode = scanCode;
436:
437: //
438: // If the input scan code is debug stop, then drop
439: // into the kernel debugger if it is active.
440: //
441:
442: if (*((PBOOLEAN)(*(PLONG)&KdDebuggerNotPresent))
443: == FALSE && !(input->Flags & KEY_BREAK)) {
444: if (ENHANCED_KEYBOARD(
445: deviceExtension->Configuration.KeyboardAttributes.KeyboardIdentifier
446: )) {
447: //
448: // Enhanced 101 keyboard, SysReq key is 0xE0 0x37.
449: //
450:
451: if ((input->MakeCode == KEYBOARD_DEBUG_HOTKEY_ENH) &&
452: (input->Flags & KEY_E0)) {
453: try {
454: DbgBreakPoint();
455:
456: } except(EXCEPTION_EXECUTE_HANDLER) {
457: }
458: }
459: //
460: // 84-key AT keyboard, SysReq key is 0xE0 0x54.
461: //
462:
463: } else if ((input->MakeCode == KEYBOARD_DEBUG_HOTKEY_AT)) {
464: try {
465: DbgBreakPoint();
466:
467: } except(EXCEPTION_EXECUTE_HANDLER) {
468: }
469: }
470: }
471: }
472:
473: //
474: // Reset the state to Normal.
475: //
476:
477: *scanState = Normal;
478: break;
479:
480: default:
481:
482: //
483: // Queue a DPC to log an internal driver error.
484: //
485:
486: KeInsertQueueDpc(
487: &deviceExtension->ErrorLogDpc,
488: (PIRP) NULL,
489: (PVOID) (ULONG) I8042_INVALID_ISR_STATE);
490:
491: ASSERT(FALSE);
492: break;
493: }
494: }
495:
496: //
497: // In the Normal state, if the keyboard device is enabled,
498: // add the data to the InputData queue and queue the ISR DPC.
499: //
500:
501: if (*scanState == Normal) {
502:
503: if (deviceExtension->KeyboardEnableCount) {
504: deviceExtension->KeyboardExtension.CurrentInput.UnitId =
505: deviceExtension->KeyboardExtension.UnitId;
506: if (!I8xWriteDataToKeyboardQueue(
507: &deviceExtension->KeyboardExtension,
508: input
509: )) {
510:
511: //
512: // The InputData queue overflowed. There is
513: // not much that can be done about it, so just
514: // continue (but don't queue the ISR DPC, since
515: // no new packets were added to the queue).
516: //
517: // Queue a DPC to log an overrun error.
518: //
519:
520: I8xPrint((
521: 1,
522: "I8042PRT-I8042KeyboardInterruptService: queue overflow\n"
523: ));
524:
525: if (deviceExtension->KeyboardExtension.OkayToLogOverflow) {
526: KeInsertQueueDpc(
527: &deviceExtension->ErrorLogDpc,
528: (PIRP) NULL,
529: (PVOID) (ULONG) I8042_KBD_BUFFER_OVERFLOW
530: );
531: deviceExtension->KeyboardExtension.OkayToLogOverflow = FALSE;
532: }
533:
534: } else if (deviceExtension->DpcInterlockKeyboard >= 0) {
535:
536: //
537: // The ISR DPC is already executing. Tell the ISR DPC
538: // it has more work to do by incrementing
539: // DpcInterlockKeyboard.
540: //
541:
542: deviceExtension->DpcInterlockKeyboard += 1;
543:
544: } else {
545:
546: //
547: // Queue the ISR DPC.
548: //
549:
550: KeInsertQueueDpc(
551: &deviceExtension->KeyboardIsrDpc,
552: deviceObject->CurrentIrp,
553: NULL
554: );
555: }
556: }
557:
558: //
559: // Reset the input state.
560: //
561:
562: input->Flags = 0;
563: }
564:
565: break;
566:
567: }
568:
569: I8xPrint((2, "I8042PRT-I8042KeyboardInterruptService: exit\n"));
570:
571: return(TRUE);
572: }
573:
574: //
575: // The following table is used to convert typematic rate (keys per
576: // second) into the value expected by the keyboard. The index into the
577: // array is the number of keys per second. The resulting value is
578: // the bit equate to send to the keyboard.
579: //
580:
581: UCHAR TypematicPeriod[] = {
582: 31, // 0 keys per second
583: 31, // 1 keys per second
584: 31, // 2 keys per second
585: 26, // 3 keys per second
586: 23, // 4 keys per second
587: 20, // 5 keys per second
588: 18, // 6 keys per second
589: 17, // 7 keys per second
590: 15, // 8 keys per second
591: 13, // 9 keys per second
592: 12, // 10 keys per second
593: 11, // 11 keys per second
594: 10, // 12 keys per second
595: 9, // 13 keys per second
596: 9, // 14 keys per second
597: 8, // 15 keys per second
598: 7, // 16 keys per second
599: 6, // 17 keys per second
600: 5, // 18 keys per second
601: 4, // 19 keys per second
602: 4, // 20 keys per second
603: 3, // 21 keys per second
604: 3, // 22 keys per second
605: 2, // 23 keys per second
606: 2, // 24 keys per second
607: 1, // 25 keys per second
608: 1, // 26 keys per second
609: 1 // 27 keys per second
610: // > 27 keys per second, use 0
611: };
612:
613: UCHAR
614: I8xConvertTypematicParameters(
615: IN USHORT Rate,
616: IN USHORT Delay
617: )
618:
619: /*++
620:
621: Routine Description:
622:
623: This routine converts the typematic rate and delay to the form the
624: keyboard expects.
625:
626: The byte passed to the keyboard looks like this:
627:
628: - bit 7 is zero
629: - bits 5 and 6 indicate the delay
630: - bits 0-4 indicate the rate
631:
632: The delay is equal to 1 plus the binary value of bits 6 and 5,
633: multiplied by 250 milliseconds.
634:
635: The period (interval from one typematic output to the next) is
636: determined by the following equation:
637:
638: Period = (8 + A) x (2^B) x 0.00417 seconds
639: where
640: A = binary value of bits 0-2
641: B = binary value of bits 3 and 4
642:
643:
644: Arguments:
645:
646: Rate - Number of keys per second.
647:
648: Delay - Number of milliseconds to delay before the key repeat starts.
649:
650: Return Value:
651:
652: The byte to pass to the keyboard.
653:
654: --*/
655:
656: {
657: UCHAR value;
658:
659: I8xPrint((2, "I8042PRT-I8xConvertTypematicParameters: enter\n"));
660:
661: //
662: // Calculate the delay bits.
663: //
664:
665: value = (UCHAR) ((Delay / 250) - 1);
666:
667: //
668: // Put delay bits in the right place.
669: //
670:
671: value <<= 5;
672:
673: //
674: // Get the typematic period from the table. If keys per second
675: // is > 27, the typematic period value is zero.
676: //
677:
678: if (Rate <= 27) {
679: value |= TypematicPeriod[Rate];
680: }
681:
682: I8xPrint((2, "I8042PRT-I8xConvertTypematicParameters: exit\n"));
683:
684: return(value);
685: }
686:
687: NTSTATUS
688: I8xInitializeKeyboard(
689: IN PDEVICE_OBJECT DeviceObject
690: )
691:
692: /*++
693:
694: Routine Description:
695:
696: This routine initializes the i8042 keyboard hardware. It is called
697: only at initialization, and does not synchronize access to the hardware.
698:
699: Arguments:
700:
701: DeviceObject - Pointer to the device object.
702:
703: Return Value:
704:
705: Returns status.
706:
707: --*/
708:
709: {
710: NTSTATUS status;
711: PKEYBOARD_ID id;
712: PDEVICE_EXTENSION deviceExtension;
713: UCHAR byte;
714: I8042_TRANSMIT_CCB_CONTEXT transmitCCBContext;
715: ULONG i;
716: PIO_ERROR_LOG_PACKET errorLogEntry;
717: ULONG uniqueErrorValue;
718: NTSTATUS errorCode = STATUS_SUCCESS;
719: ULONG dumpCount;
720:
721: #define DUMP_COUNT 4
722: ULONG dumpData[DUMP_COUNT];
723:
724: I8xPrint((2, "I8042PRT-I8xInitializeKeyboard: enter\n"));
725:
726: for (i = 0; i < DUMP_COUNT; i++)
727: dumpData[i] = 0;
728:
729: //
730: // Get the device extension.
731: //
732:
733: deviceExtension = DeviceObject->DeviceExtension;
734:
735: //
736: // Reset the keyboard.
737: //
738:
739: status = I8xPutBytePolled(
740: (CCHAR) DataPort,
741: WAIT_FOR_ACKNOWLEDGE,
742: (CCHAR) KeyboardDeviceType,
743: deviceExtension,
744: (UCHAR) KEYBOARD_RESET
745: );
746: if (!NT_SUCCESS(status)) {
747: I8xPrint((
748: 1,
749: "I8042PRT-I8xInitializeKeyboard: failed keyboard reset, status 0x%x\n",
750: status
751: ));
752:
753: //
754: // Set up error log info.
755: //
756:
757: errorCode = I8042_KBD_RESET_COMMAND_FAILED;
758: uniqueErrorValue = I8042_ERROR_VALUE_BASE + 510;
759: dumpData[0] = KBDMOU_COULD_NOT_SEND_COMMAND;
760: dumpData[1] = DataPort;
761: dumpData[2] = KEYBOARD_RESET;
762: dumpCount = 3;
763:
764: //
765: // NOTE: The following line was commented out to work around a
766: // problem with the Gateway 4DX2/66V when an old Compaq 286
767: // keyboard is attached. In this case, the keyboard reset
768: // is not acknowledged (at least, the system never
769: // receives the ack). Instead, the KEYBOARD_COMPLETE_SUCCESS
770: // byte is sitting in the i8042 output buffer. The workaround
771: // is to ignore the keyboard reset failure and continue.
772: //
773: // goto I8xInitializeKeyboardExit;
774: }
775:
776: //
777: // Get the keyboard reset self-test response. A response byte of
778: // KEYBOARD_COMPLETE_SUCCESS indicates success; KEYBOARD_COMPLETE_FAILURE
779: // indicates failure.
780: //
781: // Note that it is usually necessary to stall a long time to get the
782: // keyboard reset/self-test to work. The stall value was determined by
783: // experimentation.
784: //
785:
786: for (i = 0; i < 11200; i++) {
787:
788: status = I8xGetBytePolled(
789: (CCHAR) KeyboardDeviceType,
790: deviceExtension,
791: &byte
792: );
793:
794: if (NT_SUCCESS(status)) {
795: if (byte == (UCHAR) KEYBOARD_COMPLETE_SUCCESS) {
796:
797: //
798: // The reset completed successfully.
799: //
800:
801: break;
802:
803: } else {
804:
805: //
806: // There was some sort of failure during the reset
807: // self-test. Continue anyway.
808: //
809:
810: //
811: // Log a warning.
812: //
813:
814:
815: dumpData[0] = KBDMOU_INCORRECT_RESPONSE;
816: dumpData[1] = KeyboardDeviceType;
817: dumpData[2] = KEYBOARD_COMPLETE_SUCCESS;
818: dumpData[3] = byte;
819:
820: I8xLogError(
821: DeviceObject,
822: I8042_KBD_RESET_RESPONSE_FAILED,
823: I8042_ERROR_VALUE_BASE + 515,
824: status,
825: dumpData,
826: 4
827: );
828:
829: break;
830: }
831:
832:
833: } else {
834:
835: if (status == STATUS_IO_TIMEOUT) {
836:
837: //
838: // Stall, and then try again to get a response from
839: // the reset.
840: //
841:
842: KeStallExecutionProcessor(50);
843:
844: } else {
845:
846: break;
847:
848: }
849:
850: }
851: }
852:
853: if (!NT_SUCCESS(status)) {
854: I8xPrint((
855: 1,
856: "I8042PRT-I8xInitializeKeyboard: failed reset response, status 0x%x, byte 0x%x\n",
857: status,
858: byte
859: ));
860:
861: //
862: // Set up error log info.
863: //
864:
865: errorCode = I8042_KBD_RESET_RESPONSE_FAILED;
866: uniqueErrorValue = I8042_ERROR_VALUE_BASE + 520;
867: dumpData[0] = KBDMOU_INCORRECT_RESPONSE;
868: dumpData[1] = KeyboardDeviceType;
869: dumpData[2] = KEYBOARD_COMPLETE_SUCCESS;
870: dumpData[3] = byte;
871: dumpCount = 4;
872:
873: goto I8xInitializeKeyboardExit;
874: }
875:
876: //
877: // Turn off Keyboard Translate Mode. Call I8xTransmitControllerCommand
878: // to read the Controller Command Byte, modify the appropriate bits, and
879: // rewrite the Controller Command Byte.
880: //
881:
882: transmitCCBContext.HardwareDisableEnableMask = 0;
883: transmitCCBContext.AndOperation = AND_OPERATION;
884: transmitCCBContext.ByteMask = (UCHAR) ~((UCHAR)CCB_KEYBOARD_TRANSLATE_MODE);
885:
886: I8xTransmitControllerCommand(
887: deviceExtension,
888: (PVOID) &transmitCCBContext
889: );
890:
891: if (!NT_SUCCESS(transmitCCBContext.Status)) {
892: I8xPrint((
893: 1,
894: "I8042PRT-I8xInitializeKeyboard: could not turn off translate\n"
895: ));
896: status = transmitCCBContext.Status;
897: goto I8xInitializeKeyboardExit;
898: }
899:
900: //
901: // Get a pointer to the keyboard identifier field.
902: //
903:
904: id = &deviceExtension->Configuration.KeyboardAttributes.KeyboardIdentifier;
905:
906: //
907: // Set the typematic rate and delay. Send the Set Typematic Rate command
908: // to the keyboard, followed by the typematic rate/delay parameter byte.
909: // Note that it is often necessary to stall a long time to get this
910: // to work. The stall value was determined by experimentation. Some
911: // broken hardware does not accept this command, so ignore errors in the
912: // hope that the keyboard will work okay anyway.
913: //
914: //
915:
916: if ((status = I8xPutBytePolled(
917: (CCHAR) DataPort,
918: WAIT_FOR_ACKNOWLEDGE,
919: (CCHAR) KeyboardDeviceType,
920: deviceExtension,
921: (UCHAR) SET_KEYBOARD_TYPEMATIC
922: )) != STATUS_SUCCESS) {
923: I8xPrint((
924: 1,
925: "I8042PRT-I8xInitializeKeyboard: could not send SET TYPEMATIC cmd\n"
926: ));
927:
928: //
929: // Log an error.
930: //
931:
932: dumpData[0] = KBDMOU_COULD_NOT_SEND_COMMAND;
933: dumpData[1] = DataPort;
934: dumpData[2] = SET_KEYBOARD_TYPEMATIC;
935:
936: I8xLogError(
937: DeviceObject,
938: I8042_SET_TYPEMATIC_FAILED,
939: I8042_ERROR_VALUE_BASE + 535,
940: status,
941: dumpData,
942: 3
943: );
944:
945: } else if ((status = I8xPutBytePolled(
946: (CCHAR) DataPort,
947: WAIT_FOR_ACKNOWLEDGE,
948: (CCHAR) KeyboardDeviceType,
949: deviceExtension,
950: I8xConvertTypematicParameters(
951: deviceExtension->Configuration.KeyRepeatCurrent.Rate,
952: deviceExtension->Configuration.KeyRepeatCurrent.Delay
953: ))) != STATUS_SUCCESS) {
954: I8xPrint((
955: 1,
956: "I8042PRT-I8xInitializeKeyboard: could not send typematic param\n"
957: ));
958:
959: //
960: // Log an error.
961: //
962:
963: dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
964: dumpData[1] = DataPort;
965: dumpData[2] = SET_KEYBOARD_TYPEMATIC;
966: dumpData[3] =
967: I8xConvertTypematicParameters(
968: deviceExtension->Configuration.KeyRepeatCurrent.Rate,
969: deviceExtension->Configuration.KeyRepeatCurrent.Delay
970: );
971:
972: I8xLogError(
973: DeviceObject,
974: I8042_SET_TYPEMATIC_FAILED,
975: I8042_ERROR_VALUE_BASE + 540,
976: status,
977: dumpData,
978: 4
979: );
980:
981: }
982:
983: status = STATUS_SUCCESS;
984:
985: //
986: // Set the keyboard indicator lights. Ignore errors.
987: //
988:
989: if ((status = I8xPutBytePolled(
990: (CCHAR) DataPort,
991: WAIT_FOR_ACKNOWLEDGE,
992: (CCHAR) KeyboardDeviceType,
993: deviceExtension,
994: (UCHAR) SET_KEYBOARD_INDICATORS
995: )) != STATUS_SUCCESS) {
996: I8xPrint((
997: 1,
998: "I8042PRT-I8xInitializeKeyboard: could not send SET LEDS cmd\n"
999: ));
1000:
1001: //
1002: // Log an error.
1003: //
1004:
1005: dumpData[0] = KBDMOU_COULD_NOT_SEND_COMMAND;
1006: dumpData[1] = DataPort;
1007: dumpData[2] = SET_KEYBOARD_INDICATORS;
1008:
1009: I8xLogError(
1010: DeviceObject,
1011: I8042_SET_LED_FAILED,
1012: I8042_ERROR_VALUE_BASE + 545,
1013: status,
1014: dumpData,
1015: 3
1016: );
1017:
1018: } else if ((status = I8xPutBytePolled(
1019: (CCHAR) DataPort,
1020: WAIT_FOR_ACKNOWLEDGE,
1021: (CCHAR) KeyboardDeviceType,
1022: deviceExtension,
1023: (UCHAR) deviceExtension->Configuration.KeyboardIndicators.LedFlags
1024: )) != STATUS_SUCCESS) {
1025: I8xPrint((
1026: 1,
1027: "I8042PRT-I8xInitializeKeyboard: could not send SET LEDS param\n"
1028: ));
1029:
1030: //
1031: // Log an error.
1032: //
1033:
1034: dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
1035: dumpData[1] = DataPort;
1036: dumpData[2] = SET_KEYBOARD_INDICATORS;
1037: dumpData[3] =
1038: deviceExtension->Configuration.KeyboardIndicators.LedFlags;
1039:
1040: I8xLogError(
1041: DeviceObject,
1042: I8042_SET_LED_FAILED,
1043: I8042_ERROR_VALUE_BASE + 550,
1044: status,
1045: dumpData,
1046: 4
1047: );
1048:
1049: }
1050:
1051: status = STATUS_SUCCESS;
1052:
1053: #ifndef i386
1054:
1055: //
1056: // BUGBUG: This code is necessary until the MIPS firmware stops
1057: // selecting scan code set 3. Select scan code set 2 here.
1058: // Since the translate bit is set, the net effect is that
1059: // we will receive scan code set 1 bytes.
1060: //
1061:
1062: if (ENHANCED_KEYBOARD(*id)) {
1063: status = I8xPutBytePolled(
1064: (CCHAR) DataPort,
1065: WAIT_FOR_ACKNOWLEDGE,
1066: (CCHAR) KeyboardDeviceType,
1067: deviceExtension,
1068: (UCHAR) SELECT_SCAN_CODE_SET
1069: );
1070: if (!NT_SUCCESS(status)) {
1071: I8xPrint((
1072: 1,
1073: "I8042PRT-I8xInitializeKeyboard: could not send Select Scan command\n"
1074: ));
1075: I8xPrint((
1076: 0,
1077: "I8042PRT-I8xInitializeKeyboard: WARNING - using scan set 3\n"
1078: ));
1079: deviceExtension->Configuration.KeyboardAttributes.KeyboardMode = 3;
1080: } else {
1081:
1082: //
1083: // Send the associated parameter byte.
1084: //
1085:
1086: status = I8xPutBytePolled(
1087: (CCHAR) DataPort,
1088: WAIT_FOR_ACKNOWLEDGE,
1089: (CCHAR) KeyboardDeviceType,
1090: deviceExtension,
1091: (UCHAR) 2
1092: );
1093: if (!NT_SUCCESS(status)) {
1094: I8xPrint((
1095: 1,
1096: "I8042PRT-I8xInitializeKeyboard: could not send Select Scan param\n"
1097: ));
1098: I8xPrint((
1099: 0,
1100: "I8042PRT-I8xInitializeKeyboard: WARNING - using scan set 3\n"
1101: ));
1102: deviceExtension->Configuration.KeyboardAttributes.KeyboardMode = 3;
1103: }
1104: }
1105: }
1106: #endif
1107:
1108: if (deviceExtension->Configuration.KeyboardAttributes.KeyboardMode == 1) {
1109:
1110: //
1111: // Turn translate back on. The keyboard should, by default, send
1112: // scan code set 2. When the translate bit in the 8042 command byte
1113: // is on, the 8042 translates the scan code set 2 bytes to scan code
1114: // set 1 before sending them to the CPU. Scan code set 1 is
1115: // the industry standard scan code set.
1116: //
1117: // N.B. It does not appear to be possible to change the translate
1118: // bit on some models of PS/2.
1119: //
1120:
1121: transmitCCBContext.HardwareDisableEnableMask = 0;
1122: transmitCCBContext.AndOperation = OR_OPERATION;
1123: transmitCCBContext.ByteMask = (UCHAR) CCB_KEYBOARD_TRANSLATE_MODE;
1124:
1125: I8xTransmitControllerCommand(
1126: deviceExtension,
1127: (PVOID) &transmitCCBContext
1128: );
1129:
1130: if (!NT_SUCCESS(transmitCCBContext.Status)) {
1131: I8xPrint((
1132: 1,
1133: "I8042PRT-I8xInitializeKeyboard: couldn't turn on translate\n"
1134: ));
1135: if (transmitCCBContext.Status == STATUS_DEVICE_DATA_ERROR) {
1136:
1137: //
1138: // Could not turn translate back on. This happens on some
1139: // PS/2 machines. In this case, select scan code set 1
1140: // for the keyboard, since the 8042 will not do the
1141: // translation from the scan code set 2, which is what the
1142: // KEYBOARD_RESET caused the keyboard to default to.
1143: //
1144:
1145: if (ENHANCED_KEYBOARD(*id)) {
1146: status = I8xPutBytePolled(
1147: (CCHAR) DataPort,
1148: WAIT_FOR_ACKNOWLEDGE,
1149: (CCHAR) KeyboardDeviceType,
1150: deviceExtension,
1151: (UCHAR) SELECT_SCAN_CODE_SET
1152: );
1153: if (!NT_SUCCESS(status)) {
1154: I8xPrint((
1155: 1,
1156: "I8042PRT-I8xInitializeKeyboard: could not send Select Scan command\n"
1157: ));
1158: I8xPrint((
1159: 0,
1160: "I8042PRT-I8xInitializeKeyboard: WARNING - using scan set 2\n"
1161: ));
1162: deviceExtension->Configuration.KeyboardAttributes.KeyboardMode = 2;
1163: //
1164: // Log an error.
1165: //
1166:
1167: dumpData[0] = KBDMOU_COULD_NOT_SEND_COMMAND;
1168: dumpData[1] = DataPort;
1169: dumpData[2] = SELECT_SCAN_CODE_SET;
1170:
1171: I8xLogError(
1172: DeviceObject,
1173: I8042_SELECT_SCANSET_FAILED,
1174: I8042_ERROR_VALUE_BASE + 555,
1175: status,
1176: dumpData,
1177: 3
1178: );
1179:
1180: } else {
1181:
1182: //
1183: // Send the associated parameter byte.
1184: //
1185:
1186: status = I8xPutBytePolled(
1187: (CCHAR) DataPort,
1188: WAIT_FOR_ACKNOWLEDGE,
1189: (CCHAR) KeyboardDeviceType,
1190: deviceExtension,
1191: (UCHAR) 1
1192: );
1193: if (!NT_SUCCESS(status)) {
1194: I8xPrint((
1195: 1,
1196: "I8042PRT-I8xInitializeKeyboard: could not send Select Scan param\n"
1197: ));
1198: I8xPrint((
1199: 0,
1200: "I8042PRT-I8xInitializeKeyboard: WARNING - using scan set 2\n"
1201: ));
1202: deviceExtension->Configuration.KeyboardAttributes.KeyboardMode = 2;
1203: //
1204: // Log an error.
1205: //
1206:
1207: dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
1208: dumpData[1] = DataPort;
1209: dumpData[2] = SELECT_SCAN_CODE_SET;
1210: dumpData[3] = 1;
1211:
1212: I8xLogError(
1213: DeviceObject,
1214: I8042_SELECT_SCANSET_FAILED,
1215: I8042_ERROR_VALUE_BASE + 560,
1216: status,
1217: dumpData,
1218: 4
1219: );
1220:
1221: }
1222: }
1223: }
1224:
1225: } else {
1226: status = transmitCCBContext.Status;
1227: goto I8xInitializeKeyboardExit;
1228: }
1229: }
1230: }
1231:
1232: I8xInitializeKeyboardExit:
1233:
1234: //
1235: // If the keyboard initialization failed, log an error.
1236: //
1237:
1238: if (errorCode != STATUS_SUCCESS) {
1239:
1240: errorLogEntry = (PIO_ERROR_LOG_PACKET)
1241: IoAllocateErrorLogEntry(
1242: DeviceObject,
1243: (UCHAR) (sizeof(IO_ERROR_LOG_PACKET)
1244: + (dumpCount * sizeof(ULONG)))
1245: );
1246:
1247: if (errorLogEntry != NULL) {
1248:
1249: errorLogEntry->ErrorCode = errorCode;
1250: errorLogEntry->DumpDataSize = dumpCount * sizeof(ULONG);
1251: errorLogEntry->SequenceNumber = 0;
1252: errorLogEntry->MajorFunctionCode = 0;
1253: errorLogEntry->IoControlCode = 0;
1254: errorLogEntry->RetryCount = 0;
1255: errorLogEntry->UniqueErrorValue = uniqueErrorValue;
1256: errorLogEntry->FinalStatus = status;
1257: for (i = 0; i < dumpCount; i++)
1258: errorLogEntry->DumpData[i] = dumpData[i];
1259:
1260: IoWriteErrorLogEntry(errorLogEntry);
1261: }
1262: }
1263:
1264: //
1265: // Initialize current keyboard set packet state.
1266: //
1267:
1268: deviceExtension->KeyboardExtension.CurrentOutput.State = Idle;
1269: deviceExtension->KeyboardExtension.CurrentOutput.FirstByte = 0;
1270: deviceExtension->KeyboardExtension.CurrentOutput.LastByte = 0;
1271:
1272: I8xPrint((2, "I8042PRT-I8xInitializeKeyboard: exit\n"));
1273:
1274: return(status);
1275: }
1276:
1277: VOID
1278: I8xKeyboardConfiguration(
1279: IN PDEVICE_EXTENSION DeviceExtension,
1280: IN PUNICODE_STRING RegistryPath,
1281: IN PUNICODE_STRING KeyboardDeviceName,
1282: IN PUNICODE_STRING PointerDeviceName
1283: )
1284:
1285: /*++
1286:
1287: Routine Description:
1288:
1289: This routine retrieves the configuration information for the keyboard.
1290:
1291: Arguments:
1292:
1293: DeviceExtension - Pointer to the device extension.
1294:
1295: RegistryPath - Pointer to the null-terminated Unicode name of the
1296: registry path for this driver.
1297:
1298: KeyboardDeviceName - Pointer to the Unicode string that will receive
1299: the keyboard port device name.
1300:
1301: PointerDeviceName - Pointer to the Unicode string that will receive
1302: the pointer port device name.
1303:
1304: Return Value:
1305:
1306: None. As a side-effect, may set DeviceExtension->HardwarePresent.
1307:
1308: --*/
1309: {
1310: NTSTATUS status = STATUS_SUCCESS;
1311: PI8042_CONFIGURATION_INFORMATION configuration;
1312: INTERFACE_TYPE interfaceType;
1313: CONFIGURATION_TYPE controllerType = KeyboardController;
1314: CONFIGURATION_TYPE peripheralType = KeyboardPeripheral;
1315: PKEYBOARD_ID keyboardId;
1316: ULONG i;
1317:
1318: for (i = 0; i < MaximumInterfaceType; i++) {
1319:
1320: //
1321: // Get the registry information for this device.
1322: //
1323:
1324: interfaceType = i;
1325: status = IoQueryDeviceDescription(&interfaceType,
1326: NULL,
1327: &controllerType,
1328: NULL,
1329: &peripheralType,
1330: NULL,
1331: I8xKeyboardPeripheralCallout,
1332: (PVOID) DeviceExtension);
1333:
1334: if (DeviceExtension->HardwarePresent & KEYBOARD_HARDWARE_PRESENT) {
1335:
1336: //
1337: // Get the service parameters (e.g., user-configurable number
1338: // of resends, polling iterations, etc.).
1339: //
1340:
1341: I8xServiceParameters(
1342: DeviceExtension,
1343: RegistryPath,
1344: KeyboardDeviceName,
1345: PointerDeviceName
1346: );
1347: configuration = &DeviceExtension->Configuration;
1348:
1349: keyboardId = &configuration->KeyboardAttributes.KeyboardIdentifier;
1350: if (!ENHANCED_KEYBOARD(*keyboardId)) {
1351: I8xPrint((
1352: 1,
1353: "I8042PRT-I8xKeyboardConfiguration: Old AT-style keyboard\n"
1354: ));
1355: configuration->PollingIterations =
1356: configuration->PollingIterationsMaximum;
1357: }
1358:
1359: //
1360: // Initialize keyboard-specific configuration parameters.
1361: //
1362:
1363: configuration->KeyboardAttributes.NumberOfFunctionKeys =
1364: KeyboardTypeInformation[keyboardId->Type - 1].NumberOfFunctionKeys;
1365: configuration->KeyboardAttributes.NumberOfIndicators =
1366: KeyboardTypeInformation[keyboardId->Type - 1].NumberOfIndicators;
1367: configuration->KeyboardAttributes.NumberOfKeysTotal =
1368: KeyboardTypeInformation[keyboardId->Type - 1].NumberOfKeysTotal;
1369:
1370: configuration->KeyboardAttributes.KeyboardMode =
1371: KEYBOARD_SCAN_CODE_SET;
1372:
1373: configuration->KeyboardAttributes.KeyRepeatMinimum.Rate =
1374: KEYBOARD_TYPEMATIC_RATE_MINIMUM;
1375: configuration->KeyboardAttributes.KeyRepeatMinimum.Delay =
1376: KEYBOARD_TYPEMATIC_DELAY_MINIMUM;
1377: configuration->KeyboardAttributes.KeyRepeatMaximum.Rate =
1378: KEYBOARD_TYPEMATIC_RATE_MAXIMUM;
1379: configuration->KeyboardAttributes.KeyRepeatMaximum.Delay =
1380: KEYBOARD_TYPEMATIC_DELAY_MAXIMUM;
1381: configuration->KeyRepeatCurrent.Rate =
1382: KEYBOARD_TYPEMATIC_RATE_DEFAULT;
1383: configuration->KeyRepeatCurrent.Delay =
1384: KEYBOARD_TYPEMATIC_DELAY_DEFAULT;
1385:
1386: break;
1387:
1388: } else {
1389: I8xPrint((
1390: 1,
1391: "I8042PRT-I8xKeyboardConfiguration: IoQueryDeviceDescription for bus type %d failed\n",
1392: interfaceType
1393: ));
1394: }
1395: }
1396: }
1397:
1398: VOID
1399: I8xKeyboardInitiateIo(
1400: IN PVOID Context
1401: )
1402:
1403: /*++
1404:
1405: Routine Description:
1406:
1407: This routine is called synchronously from I8xKeyboardInitiateWrapper and
1408: the ISR to initiate an I/O operation for the keyboard device.
1409:
1410: Arguments:
1411:
1412: Context - Pointer to the device object.
1413:
1414: Return Value:
1415:
1416: None.
1417:
1418: --*/
1419:
1420: {
1421: PDEVICE_EXTENSION deviceExtension;
1422: PDEVICE_OBJECT deviceObject;
1423: KEYBOARD_SET_PACKET keyboardPacket;
1424:
1425: I8xPrint((2, "I8042PRT-I8xKeyboardInitiateIo: enter\n"));
1426:
1427: //
1428: // Get the device extension.
1429: //
1430:
1431: deviceObject = (PDEVICE_OBJECT) Context;
1432: deviceExtension = deviceObject->DeviceExtension;
1433:
1434: //
1435: // Set the timeout value.
1436: //
1437:
1438: deviceExtension->TimerCount = I8042_ASYNC_TIMEOUT;
1439:
1440: //
1441: // Get the current set request packet to work on.
1442: //
1443:
1444: keyboardPacket = deviceExtension->KeyboardExtension.CurrentOutput;
1445:
1446: if (deviceExtension->KeyboardExtension.CurrentOutput.State
1447: == SendFirstByte){
1448:
1449: I8xPrint((
1450: 2,
1451: "I8042PRT-I8xKeyboardInitiateIo: send first byte 0x%x\n",
1452: keyboardPacket.FirstByte
1453: ));
1454:
1455: //
1456: // Send the first byte of a 2-byte command sequence to the
1457: // keyboard controller, asynchronously.
1458: //
1459:
1460: I8xPutByteAsynchronous(
1461: (CCHAR) DataPort,
1462: deviceExtension,
1463: keyboardPacket.FirstByte
1464: );
1465:
1466: } else if (deviceExtension->KeyboardExtension.CurrentOutput.State
1467: == SendLastByte) {
1468:
1469: I8xPrint((
1470: 2,
1471: "I8042PRT-I8xKeyboardInitiateIo: send last byte 0x%x\n",
1472: keyboardPacket.LastByte
1473: ));
1474:
1475: //
1476: // Send the last byte of a command sequence to the keyboard
1477: // controller, asynchronously.
1478: //
1479:
1480: I8xPutByteAsynchronous(
1481: (CCHAR) DataPort,
1482: deviceExtension,
1483: keyboardPacket.LastByte
1484: );
1485:
1486: } else {
1487:
1488: I8xPrint((2, "I8042PRT-I8xKeyboardInitiateIo: INVALID REQUEST\n"));
1489:
1490: //
1491: // Queue a DPC to log an internal driver error.
1492: //
1493:
1494: KeInsertQueueDpc(
1495: &deviceExtension->ErrorLogDpc,
1496: (PIRP) NULL,
1497: (PVOID) (ULONG) I8042_INVALID_INITIATE_STATE);
1498:
1499: ASSERT(FALSE);
1500: }
1501:
1502: I8xPrint((2, "I8042PRT-I8xKeyboardInitiateIo: exit\n"));
1503:
1504: return;
1505: }
1506:
1507: VOID
1508: I8xKeyboardInitiateWrapper(
1509: IN PVOID Context
1510: )
1511:
1512: /*++
1513:
1514: Routine Description:
1515:
1516: This routine is called from StartIo synchronously. It sets up the
1517: CurrentOutput and ResendCount fields in the device extension, and
1518: then calls I8xKeyboardInitiateIo to do the real work.
1519:
1520: Arguments:
1521:
1522: Context - Pointer to the context structure containing the first and
1523: last bytes of the send sequence.
1524:
1525: Return Value:
1526:
1527: None.
1528:
1529: --*/
1530:
1531: {
1532: PDEVICE_OBJECT deviceObject;
1533: PDEVICE_EXTENSION deviceExtension;
1534:
1535: //
1536: // Get a pointer to the device object from the context argument.
1537: //
1538:
1539: deviceObject = ((PKEYBOARD_INITIATE_CONTEXT) Context)->DeviceObject;
1540:
1541: //
1542: // Set up CurrentOutput state for this operation.
1543: //
1544:
1545: deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
1546:
1547: deviceExtension->KeyboardExtension.CurrentOutput.State = SendFirstByte;
1548: deviceExtension->KeyboardExtension.CurrentOutput.FirstByte =
1549: ((PKEYBOARD_INITIATE_CONTEXT) Context)->FirstByte;
1550: deviceExtension->KeyboardExtension.CurrentOutput.LastByte =
1551: ((PKEYBOARD_INITIATE_CONTEXT) Context)->LastByte;
1552:
1553: //
1554: // We're starting a new operation, so reset the resend count.
1555: //
1556:
1557: deviceExtension->KeyboardExtension.ResendCount = 0;
1558:
1559: //
1560: // Initiate the keyboard I/O operation. Note that we were called
1561: // using KeSynchronizeExecution, so I8xKeyboardInitiateIo is also
1562: // synchronized with the keyboard ISR.
1563: //
1564:
1565: I8xKeyboardInitiateIo((PVOID) deviceObject);
1566:
1567: }
1568:
1569: NTSTATUS
1570: I8xKeyboardPeripheralCallout(
1571: IN PVOID Context,
1572: IN PUNICODE_STRING PathName,
1573: IN INTERFACE_TYPE BusType,
1574: IN ULONG BusNumber,
1575: IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
1576: IN CONFIGURATION_TYPE ControllerType,
1577: IN ULONG ControllerNumber,
1578: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
1579: IN CONFIGURATION_TYPE PeripheralType,
1580: IN ULONG PeripheralNumber,
1581: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
1582: )
1583:
1584: /*++
1585:
1586: Routine Description:
1587:
1588: This is the callout routine sent as a parameter to
1589: IoQueryDeviceDescription. It grabs the keyboard controller and
1590: peripheral configuration information.
1591:
1592: Arguments:
1593:
1594: Context - Context parameter that was passed in by the routine
1595: that called IoQueryDeviceDescription.
1596:
1597: PathName - The full pathname for the registry key.
1598:
1599: BusType - Bus interface type (Isa, Eisa, Mca, etc.).
1600:
1601: BusNumber - The bus sub-key (0, 1, etc.).
1602:
1603: BusInformation - Pointer to the array of pointers to the full value
1604: information for the bus.
1605:
1606: ControllerType - The controller type (should be KeyboardController).
1607:
1608: ControllerNumber - The controller sub-key (0, 1, etc.).
1609:
1610: ControllerInformation - Pointer to the array of pointers to the full
1611: value information for the controller key.
1612:
1613: PeripheralType - The peripheral type (should be KeyboardPeripheral).
1614:
1615: PeripheralNumber - The peripheral sub-key.
1616:
1617: PeripheralInformation - Pointer to the array of pointers to the full
1618: value information for the peripheral key.
1619:
1620:
1621: Return Value:
1622:
1623: None. If successful, will have the following side-effects:
1624:
1625: - Sets DeviceObject->DeviceExtension->HardwarePresent.
1626: - Sets configuration fields in
1627: DeviceObject->DeviceExtension->Configuration.
1628:
1629: --*/
1630: {
1631: PDEVICE_EXTENSION deviceExtension;
1632: PI8042_CONFIGURATION_INFORMATION configuration;
1633: UNICODE_STRING unicodeIdentifier;
1634: PUCHAR controllerData;
1635: PUCHAR peripheralData;
1636: NTSTATUS status = STATUS_SUCCESS;
1637: ULONG i;
1638: ULONG listCount;
1639: PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDescriptor;
1640: CM_PARTIAL_RESOURCE_DESCRIPTOR tmpResourceDescriptor;
1641: PCM_KEYBOARD_DEVICE_DATA keyboardSpecificData;
1642: BOOLEAN defaultInterruptShare;
1643: KINTERRUPT_MODE defaultInterruptMode;
1644:
1645: I8xPrint((
1646: 1,
1647: "I8042PRT-I8xKeyboardPeripheralCallout: Path @ 0x%x, Bus Type 0x%x, Bus Number 0x%x\n",
1648: PathName, BusType, BusNumber
1649: ));
1650: I8xPrint((
1651: 1,
1652: " Controller Type 0x%x, Controller Number 0x%x, Controller info @ 0x%x\n",
1653: ControllerType, ControllerNumber, ControllerInformation
1654: ));
1655: I8xPrint((
1656: 1,
1657: " Peripheral Type 0x%x, Peripheral Number 0x%x, Peripheral info @ 0x%x\n",
1658: PeripheralType, PeripheralNumber, PeripheralInformation
1659: ));
1660:
1661:
1662: //
1663: // Get the length of the peripheral identifier information.
1664: //
1665:
1666: unicodeIdentifier.Length =
1667: (*(PeripheralInformation + IoQueryDeviceIdentifier))->DataLength;
1668:
1669: //
1670: // If we already have the configuration information for the
1671: // keyboard peripheral, or if the peripheral identifier is missing,
1672: // just return.
1673: //
1674:
1675: deviceExtension = (PDEVICE_EXTENSION) Context;
1676: if ((deviceExtension->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
1677: || (unicodeIdentifier.Length == 0)) {
1678: return (status);
1679: }
1680:
1681: configuration = &deviceExtension->Configuration;
1682:
1683: //
1684: // Get the identifier information for the peripheral.
1685: //
1686:
1687: unicodeIdentifier.MaximumLength = unicodeIdentifier.Length;
1688: unicodeIdentifier.Buffer = (PWSTR) (((PUCHAR)(*(PeripheralInformation +
1689: IoQueryDeviceIdentifier))) +
1690: (*(PeripheralInformation +
1691: IoQueryDeviceIdentifier))->DataOffset);
1692: I8xPrint((
1693: 1,
1694: "I8042PRT-I8xKeyboardPeripheralCallout: Keyboard type %ws\n",
1695: unicodeIdentifier.Buffer
1696: ));
1697:
1698: deviceExtension->HardwarePresent |= KEYBOARD_HARDWARE_PRESENT;
1699:
1700: //
1701: // Initialize the Keyboard Type to unknown.
1702: //
1703:
1704: configuration->KeyboardAttributes.KeyboardIdentifier.Type = 0;
1705: configuration->KeyboardAttributes.KeyboardIdentifier.Subtype = 0;
1706:
1707: //
1708: // Look through the peripheral's resource list for device-specific
1709: // information. The keyboard-specific information is defined
1710: // in sdk\inc\ntconfig.h.
1711: //
1712:
1713: if ((*(PeripheralInformation + IoQueryDeviceConfigurationData))->DataLength != 0){
1714: peripheralData = ((PUCHAR) (*(PeripheralInformation +
1715: IoQueryDeviceConfigurationData))) +
1716: (*(PeripheralInformation +
1717: IoQueryDeviceConfigurationData))->DataOffset;
1718:
1719: peripheralData += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
1720: PartialResourceList);
1721:
1722: listCount = ((PCM_PARTIAL_RESOURCE_LIST) peripheralData)->Count;
1723:
1724: resourceDescriptor =
1725: ((PCM_PARTIAL_RESOURCE_LIST) peripheralData)->PartialDescriptors;
1726:
1727: for (i = 0; i < listCount; i++, resourceDescriptor++) {
1728: switch(resourceDescriptor->Type) {
1729:
1730: case CmResourceTypeDeviceSpecific:
1731:
1732: //
1733: // Get the keyboard type, subtype, and the initial
1734: // settings for the LEDs.
1735: //
1736:
1737: keyboardSpecificData =
1738: (PCM_KEYBOARD_DEVICE_DATA)(((PUCHAR)resourceDescriptor)
1739: + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
1740: if (keyboardSpecificData->Type<= NUM_KNOWN_KEYBOARD_TYPES){
1741: configuration->KeyboardAttributes.KeyboardIdentifier.Type =
1742: keyboardSpecificData->Type;
1743: }
1744: configuration->KeyboardAttributes.KeyboardIdentifier.Subtype =
1745: keyboardSpecificData->Subtype;
1746: configuration->KeyboardIndicators.LedFlags =
1747: (keyboardSpecificData->KeyboardFlags >> 4) & 7;
1748:
1749: break;
1750:
1751: default:
1752: break;
1753: }
1754: }
1755: }
1756:
1757: //
1758: // If no keyboard-specific information (i.e., keyboard type, subtype,
1759: // and initial LED settings) was found, use the keyboard driver
1760: // defaults.
1761: //
1762:
1763: if (configuration->KeyboardAttributes.KeyboardIdentifier.Type == 0) {
1764:
1765: I8xPrint((
1766: 1,
1767: "I8042PRT-I8xKeyboardPeripheralCallout: Using default keyboard type\n"
1768: ));
1769:
1770: configuration->KeyboardAttributes.KeyboardIdentifier.Type =
1771: KEYBOARD_TYPE_DEFAULT;
1772: configuration->KeyboardIndicators.LedFlags =
1773: KEYBOARD_INDICATORS_DEFAULT;
1774:
1775: }
1776:
1777: I8xPrint((
1778: 1,
1779: "I8042PRT-I8xKeyboardPeripheralCallout: Keyboard device specific data --\n"
1780: ));
1781: I8xPrint((
1782: 1,
1783: " Type = %d, Subtype = %d, Initial LEDs = 0x%x\n",
1784: configuration->KeyboardAttributes.KeyboardIdentifier.Type,
1785: configuration->KeyboardAttributes.KeyboardIdentifier.Subtype,
1786: configuration->KeyboardIndicators.LedFlags
1787: ));
1788:
1789: //
1790: // Get the bus information.
1791: //
1792:
1793: configuration->InterfaceType = BusType;
1794: configuration->BusNumber = BusNumber;
1795: configuration->FloatingSave = I8042_FLOATING_SAVE;
1796:
1797: if (BusType == MicroChannel) {
1798: defaultInterruptShare = TRUE;
1799: defaultInterruptMode = LevelSensitive;
1800: } else {
1801: defaultInterruptShare = I8042_INTERRUPT_SHARE;
1802: defaultInterruptMode = I8042_INTERRUPT_MODE;
1803: }
1804:
1805: //
1806: // Look through the controller's resource list for interrupt and port
1807: // configuration information.
1808: //
1809:
1810: if ((*(ControllerInformation + IoQueryDeviceConfigurationData))->DataLength != 0){
1811: controllerData = ((PUCHAR) (*(ControllerInformation +
1812: IoQueryDeviceConfigurationData))) +
1813: (*(ControllerInformation +
1814: IoQueryDeviceConfigurationData))->DataOffset;
1815:
1816: controllerData += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
1817: PartialResourceList);
1818:
1819: listCount = ((PCM_PARTIAL_RESOURCE_LIST) controllerData)->Count;
1820:
1821: resourceDescriptor =
1822: ((PCM_PARTIAL_RESOURCE_LIST) controllerData)->PartialDescriptors;
1823:
1824: for (i = 0; i < listCount; i++, resourceDescriptor++) {
1825: switch(resourceDescriptor->Type) {
1826: case CmResourceTypePort:
1827:
1828: //
1829: // Copy the port information. We will sort the port list
1830: // into ascending order based on the starting port address
1831: // later (note that we *know* there are a max of two port
1832: // ranges for the i8042).
1833: //
1834:
1835: ASSERT(configuration->PortListCount < MaximumPortCount);
1836: configuration->PortList[configuration->PortListCount] =
1837: *resourceDescriptor;
1838: configuration->PortList[configuration->PortListCount].ShareDisposition =
1839: I8042_REGISTER_SHARE? CmResourceShareShared:
1840: CmResourceShareDriverExclusive;
1841: configuration->PortListCount += 1;
1842:
1843: break;
1844:
1845: case CmResourceTypeInterrupt:
1846:
1847: //
1848: // Copy the interrupt information.
1849: //
1850:
1851: configuration->KeyboardInterrupt = *resourceDescriptor;
1852: configuration->KeyboardInterrupt.ShareDisposition =
1853: defaultInterruptShare? CmResourceShareShared :
1854: CmResourceShareDeviceExclusive;
1855:
1856: break;
1857:
1858: case CmResourceTypeDeviceSpecific:
1859: break;
1860:
1861: default:
1862: break;
1863: }
1864: }
1865: }
1866:
1867: //
1868: // If no interrupt configuration information was found, use the
1869: // keyboard driver defaults.
1870: //
1871:
1872: if (!(configuration->KeyboardInterrupt.Type & CmResourceTypeInterrupt)) {
1873:
1874: I8xPrint((
1875: 1,
1876: "I8042PRT-I8xKeyboardPeripheralCallout: Using default keyboard interrupt config\n"
1877: ));
1878:
1879: configuration->KeyboardInterrupt.Type = CmResourceTypeInterrupt;
1880: configuration->KeyboardInterrupt.ShareDisposition =
1881: defaultInterruptShare? CmResourceShareShared :
1882: CmResourceShareDeviceExclusive;
1883: configuration->KeyboardInterrupt.Flags =
1884: (defaultInterruptMode == Latched)? CM_RESOURCE_INTERRUPT_LATCHED :
1885: CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
1886: configuration->KeyboardInterrupt.u.Interrupt.Level = KEYBOARD_IRQL;
1887: configuration->KeyboardInterrupt.u.Interrupt.Vector = KEYBOARD_VECTOR;
1888: }
1889:
1890: I8xPrint((
1891: 1,
1892: "I8042PRT-I8xKeyboardPeripheralCallout: Keyboard interrupt config --\n"
1893: ));
1894: I8xPrint((
1895: 1,
1896: " %s, %s, Irq = %d\n",
1897: configuration->KeyboardInterrupt.ShareDisposition == CmResourceShareShared?
1898: "Sharable" : "NonSharable",
1899: configuration->KeyboardInterrupt.Flags == CM_RESOURCE_INTERRUPT_LATCHED?
1900: "Latched" : "Level Sensitive",
1901: configuration->KeyboardInterrupt.u.Interrupt.Vector
1902: ));
1903:
1904: //
1905: // If no port configuration information was found, use the
1906: // keyboard driver defaults.
1907: //
1908:
1909: if (configuration->PortListCount == 0) {
1910:
1911: //
1912: // No port configuration information was found, so use
1913: // the driver defaults.
1914: //
1915:
1916: I8xPrint((
1917: 1,
1918: "I8042PRT-I8xKeyboardPeripheralCallout: Using default port config\n"
1919: ));
1920:
1921: configuration->PortList[DataPort].Type = CmResourceTypePort;
1922: configuration->PortList[DataPort].Flags = I8042_PORT_TYPE;
1923: configuration->PortList[DataPort].ShareDisposition =
1924: I8042_REGISTER_SHARE? CmResourceShareShared:
1925: CmResourceShareDriverExclusive;
1926: configuration->PortList[DataPort].u.Port.Start.LowPart =
1927: I8042_PHYSICAL_BASE + I8042_DATA_REGISTER_OFFSET;
1928: configuration->PortList[DataPort].u.Port.Start.HighPart = 0;
1929: configuration->PortList[DataPort].u.Port.Length = I8042_REGISTER_LENGTH;
1930:
1931: configuration->PortList[CommandPort].Type = CmResourceTypePort;
1932: configuration->PortList[CommandPort].Flags = I8042_PORT_TYPE;
1933: configuration->PortList[CommandPort].ShareDisposition =
1934: I8042_REGISTER_SHARE? CmResourceShareShared:
1935: CmResourceShareDriverExclusive;
1936: configuration->PortList[CommandPort].u.Port.Start.LowPart =
1937: I8042_PHYSICAL_BASE + I8042_COMMAND_REGISTER_OFFSET;
1938: configuration->PortList[CommandPort].u.Port.Start.HighPart = 0;
1939: configuration->PortList[CommandPort].u.Port.Length = I8042_REGISTER_LENGTH;
1940:
1941: configuration->PortListCount = 2;
1942: } else if (configuration->PortListCount == 1) {
1943:
1944: //
1945: // Kludge for Jazz machines. Their ARC firmware neglects to
1946: // separate out the port addresses, so fix that up here.
1947: //
1948:
1949: configuration->PortList[DataPort].u.Port.Length = I8042_REGISTER_LENGTH;
1950: configuration->PortList[CommandPort] = configuration->PortList[DataPort];
1951: configuration->PortList[CommandPort].u.Port.Start.LowPart +=
1952: I8042_COMMAND_REGISTER_OFFSET;
1953: configuration->PortListCount += 1;
1954: } else {
1955:
1956: //
1957: // Put the lowest port address range in the DataPort element of
1958: // the port list.
1959: //
1960:
1961: if (configuration->PortList[CommandPort].u.Port.Start.LowPart
1962: < configuration->PortList[DataPort].u.Port.Start.LowPart) {
1963: tmpResourceDescriptor = configuration->PortList[DataPort];
1964: configuration->PortList[DataPort] =
1965: configuration->PortList[CommandPort];
1966: configuration->PortList[CommandPort] = tmpResourceDescriptor;
1967: }
1968: }
1969:
1970: for (i = 0; i < configuration->PortListCount; i++) {
1971:
1972: I8xPrint((
1973: 1,
1974: " %s, Ports 0x%x - 0x%x\n",
1975: configuration->PortList[i].ShareDisposition
1976: == CmResourceShareShared? "Sharable" : "NonSharable",
1977: configuration->PortList[i].u.Port.Start.LowPart,
1978: configuration->PortList[i].u.Port.Start.LowPart +
1979: configuration->PortList[i].u.Port.Length - 1
1980: ));
1981: }
1982:
1983: return(status);
1984: }
1985:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.