VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/i8042prt/kbddep.c@ 34079

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

Additions: whitespace cleanup

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

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