Annotation of ntddk/src/input/i8042prt/kbddep.c, revision 1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.