/*++ Copyright (c) 1990-1998 Microsoft Corporation, All Rights Reserved Module Name: kbddep.c Abstract: The initialization and hardware-dependent portions of the Intel i8042 port driver which are specific to the keyboard. Environment: Kernel mode only. Notes: NOTES: (Future/outstanding issues) - Powerfail not implemented. - Consolidate duplicate code, where possible and appropriate. Revision History: --*/ #include "stdarg.h" #include "stdio.h" #include "string.h" #include #include #include #include "i8042prt.h" #include "i8042log.h" // // Use the alloc_text pragma to specify the driver initialization routines // (they can be paged out). // #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, I8xKeyboardConfiguration) #pragma alloc_text(PAGE, I8xInitializeKeyboard) #pragma alloc_text(PAGE, I8xKeyboardServiceParameters) #pragma alloc_text(PAGE, I8xServiceCrashDump) #endif #define BUFFER_FULL (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL) #define GET_MAKE_CODE(_sc_) (_sc_ & 0x7F) // // Tests for the top bit // #define IS_BREAK_CODE(_sc_) (_sc_ > (UCHAR) 0x7F) #define IS_MAKE_CODE(_sc_) (_sc_ <= (UCHAR) 0x7F) BOOLEAN I8042KeyboardInterruptService( IN PKINTERRUPT Interrupt, IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This routine performs the actual work. It either processes a keystroke or the results from a write to the device. Arguments: CallIsrContext - Contains the interrupt object and device object. Return Value: TRUE if the interrupt was truly ours --*/ { UCHAR scanCode, statusByte; PPORT_KEYBOARD_EXTENSION deviceExtension; KEYBOARD_SCAN_STATE *scanState; PKEYBOARD_INPUT_DATA input; ULONG i; #ifdef FE_SB PKEYBOARD_ID KeyboardId; #endif IsrPrint(DBG_KBISR_TRACE, ("enter\n")); // // Get the device extension. // deviceExtension = (PPORT_KEYBOARD_EXTENSION) DeviceObject->DeviceExtension; // // The interrupt will fire when we try to toggle the interrupts on the // controller itself. Don't touch any of the ports in this state and the // toggle will succeed. // if (deviceExtension->PowerState != PowerDeviceD0) { return FALSE; } #ifdef FE_SB // // Get a pointer to keyboard id. // KeyboardId = &deviceExtension->KeyboardAttributes.KeyboardIdentifier; #endif // // Verify that this device really interrupted. Check the status // register. The Output Buffer Full bit should be set, and the // Auxiliary Device Output Buffer Full bit should be clear. // statusByte = I8X_GET_STATUS_BYTE(Globals.ControllerData->DeviceRegisters[CommandPort]); if ((statusByte & BUFFER_FULL) != OUTPUT_BUFFER_FULL) { // // Stall and then try again. The Olivetti MIPS machine // sometimes gets an interrupt before the status // register is set. They do this for DOS compatibility (some // DOS apps do things in polled mode, until they see a character // in the keyboard buffer at which point they expect to get // an interrupt???). // for (i = 0; i < (ULONG)Globals.ControllerData->Configuration.PollStatusIterations; i++) { KeStallExecutionProcessor(1); statusByte = I8X_GET_STATUS_BYTE(Globals.ControllerData->DeviceRegisters[CommandPort]); if ((statusByte & BUFFER_FULL) == (OUTPUT_BUFFER_FULL)) { break; } } statusByte = I8X_GET_STATUS_BYTE(Globals.ControllerData->DeviceRegisters[CommandPort]); if ((statusByte & BUFFER_FULL) != (OUTPUT_BUFFER_FULL)) { // // Not our interrupt. // // NOTE: If the keyboard has not yet been "enabled", go ahead // and read a byte from the data port anyway. // This fixes weirdness on some Gateway machines, where // we get an interrupt sometime during driver initialization // after the interrupt is connected, but the output buffer // full bit never gets set. // IsrPrint(DBG_KBISR_ERROR|DBG_KBISR_INFO, ("not our interrupt!\n")); if (deviceExtension->EnableCount == 0) { scanCode = I8X_GET_DATA_BYTE(Globals.ControllerData->DeviceRegisters[DataPort]); } return FALSE; } } // // The interrupt is valid. Read the byte from the i8042 data port. // I8xGetByteAsynchronous( (CCHAR) KeyboardDeviceType, &scanCode ); deviceExtension->LastScanCode = deviceExtension->CurrentScanCode; deviceExtension->CurrentScanCode = scanCode; IsrPrint(DBG_KBISR_SCODE, ("scanCode 0x%x\n", scanCode)); if (deviceExtension->IsrHookCallback) { BOOLEAN cont = FALSE, ret; ret = (*deviceExtension->IsrHookCallback)( deviceExtension->HookContext, &deviceExtension->CurrentInput, &deviceExtension->CurrentOutput, statusByte, &scanCode, &cont, &deviceExtension->CurrentScanState ); if (!cont) { return ret; } } // // Take the appropriate action, depending on whether the byte read // is a keyboard command response or a real scan code. // switch(scanCode) { // // The keyboard controller requests a resend. If the resend count // has not been exceeded, re-initiate the I/O operation. // case RESEND: IsrPrint(DBG_KBISR_INFO, (" RESEND, retries = %d\n", deviceExtension->ResendCount + 1 )); // // If the timer count is zero, don't process the interrupt // further. The timeout routine will complete this request. // if (Globals.ControllerData->TimerCount == 0) { break; } // // Reset the timeout value to indicate no timeout. // Globals.ControllerData->TimerCount = I8042_ASYNC_NO_TIMEOUT; // // If the maximum number of retries has not been exceeded, // if ((deviceExtension->CurrentOutput.State == Idle) || (DeviceObject->CurrentIrp == NULL)) { // // We weren't sending a command or parameter to the hardware. // This must be a scan code. I hear the Brazilian keyboard // actually uses this. // goto ScanCodeCase; } else if (deviceExtension->ResendCount < Globals.ControllerData->Configuration.ResendIterations) { // // retard the byte count to resend the last byte // deviceExtension->CurrentOutput.CurrentByte -= 1; deviceExtension->ResendCount += 1; I8xInitiateIo(DeviceObject); } else { deviceExtension->CurrentOutput.State = Idle; KeInsertQueueDpc( &deviceExtension->RetriesExceededDpc, DeviceObject->CurrentIrp, NULL ); } break; // // The keyboard controller has acknowledged a previous send. // If there are more bytes to send for the current packet, initiate // the next send operation. Otherwise, queue the completion DPC. // case ACKNOWLEDGE: IsrPrint(DBG_KBISR_STATE, (": ACK, ")); // // If the timer count is zero, don't process the interrupt // further. The timeout routine will complete this request. // if (Globals.ControllerData->TimerCount == 0) { break; } // // We cannot clear the E0 or E1 bits b/c then the subsequent scan // code will be misinterpreted. ie, the OS should have seen 0x2d // with an extended bit, but instead it saw a plain 0x2d // // If the keyboard is using 0xE0 0x7A / 0xE0 0xFA as a make / break // code, then tough luck...bad choice, we do not support it. // #if 0 // // If the E0 or E1 is set, that means that this keyboard's // manufacturer made a poor choice for a scan code, 0x7A, whose // break code is 0xFA. Thankfully, they used the E0 or E1 prefix // so we can tell the difference. // if (deviceExtension->CurrentInput.Flags & (KEY_E0 | KEY_E1)) { // // The following sequence can occur which requires the driver to // ignore the spurious keystroke // // 1 write set typematic to the device (0xF3) // 2 device responds with an ACK, ISR sees 0xFA // 3 write typematic value to the device (0x??) // 4 user hits an extended key (left arrow for instance), ISR sees 0xE0 // 5 device response with an ACK to the typematic value, ISR sees 0xFA // before the actual scancode for the left arrow is sent to the ISR // // // Make sure we are trully not writing out data to the device // if (Globals.ControllerData->TimerCount == I8042_ASYNC_NO_TIMEOUT && deviceExtension->CurrentOutput.State == Idle) { IsrPrint(DBG_KBISR_INFO, ("BAD KEYBOARD: 0xFA used as a real scancode!\n")); goto ScanCodeCase; } else { // // Spurious keystroke case. // // Clear the E0 / E1 flag. the 2nd byte of the scan code will // never come through b/c it was preempted by the ACK for the // write to the device // deviceExtension->CurrentInput.Flags &= ~(KEY_E0 | KEY_E1); } } #endif // // Reset the timeout value to indicate no timeout. // Globals.ControllerData->TimerCount = I8042_ASYNC_NO_TIMEOUT; // // Reset resend count. // deviceExtension->ResendCount = 0; // // Make sure we are writing to the device if we are going to write // another byte or queue a DPC // if (deviceExtension->CurrentOutput.State == SendingBytes) { if (deviceExtension->CurrentOutput.CurrentByte < deviceExtension->CurrentOutput.ByteCount) { // // We've successfully sent the first byte of a 2-byte (or more) // command sequence. Initiate a send of the second byte. // IsrPrint(DBG_KBISR_STATE, ("now initiate send of byte #%d\n", deviceExtension->CurrentOutput.CurrentByte )); I8xInitiateIo(DeviceObject); } else { // // We've successfully sent all bytes in the command sequence. // Reset the current state and queue the completion DPC. // IsrPrint(DBG_KBISR_STATE, ("all bytes have been sent\n" )); deviceExtension->CurrentOutput.State = Idle; ASSERT(DeviceObject->CurrentIrp != NULL); IoRequestDpc( DeviceObject, DeviceObject->CurrentIrp, IntToPtr(IsrDpcCauseKeyboardWriteComplete) ); } } break; // // Assume we've got a real, live scan code (or perhaps a keyboard // overrun code, which we treat like a scan code). I.e., a key // has been pressed or released. Queue the ISR DPC to process // a complete scan code sequence. // ScanCodeCase: default: IsrPrint(DBG_KBISR_SCODE, ("real scan code\n")); // // Differentiate between an extended key sequence (first // byte is E0, followed by a normal make or break byte), or // a normal make code (one byte, the high bit is NOT set), // or a normal break code (one byte, same as the make code // but the high bit is set), or the key #126 byte sequence // (requires special handling -- sequence is E11D459DC5). // // If there is a key detection error/overrun, the keyboard // sends an overrun indicator (0xFF in scan code set 1). // Map it to the overrun indicator expected by the Windows // USER Raw Input Thread. // input = &deviceExtension->CurrentInput; scanState = &deviceExtension->CurrentScanState; if (scanCode == (UCHAR) 0xFF) { IsrPrint(DBG_KBISR_ERROR, ("OVERRUN\n")); input->MakeCode = KEYBOARD_OVERRUN_MAKE_CODE; input->Flags = 0; *scanState = Normal; } else { switch (*scanState) { case Normal: if (scanCode == (UCHAR) 0xE0) { input->Flags |= KEY_E0; *scanState = GotE0; IsrPrint(DBG_KBISR_STATE, ("change state to GotE0\n")); break; } else if (scanCode == (UCHAR) 0xE1) { input->Flags |= KEY_E1; *scanState = GotE1; IsrPrint(DBG_KBISR_STATE, ("change state to GotE1\n")); break; } // // Fall through to the GotE0/GotE1 case for the rest of the // Normal case. // case GotE0: case GotE1: if (deviceExtension->CrashFlags != 0x0) { I8xProcessCrashDump(deviceExtension, scanCode, *scanState); } if (IS_BREAK_CODE(scanCode)) { SYS_BUTTON_ACTION action; // // Got a break code. Strip the high bit off // to get the associated make code and set flags // to indicate a break code. // IsrPrint(DBG_KBISR_SCODE, ("BREAK code\n")); input->MakeCode = GET_MAKE_CODE(scanCode); input->Flags |= KEY_BREAK; if (input->Flags & KEY_E0) { switch (input->MakeCode) { case KEYBOARD_POWER_CODE: if (deviceExtension->PowerCaps & I8042_POWER_SYS_BUTTON) { IsrPrint(DBG_KBISR_POWER, ("Send Power Button\n")); action = SendAction; } else { IsrPrint(DBG_KBISR_POWER, ("Update Power Button\n")); action = UpdateAction; } break; case KEYBOARD_SLEEP_CODE: if (deviceExtension->PowerCaps & I8042_SLEEP_SYS_BUTTON) { IsrPrint(DBG_KBISR_POWER, ("Send Sleep Button\n")); action = SendAction; } else { IsrPrint(DBG_KBISR_POWER, ("Update Sleep Button\n")); action = UpdateAction; } break; case KEYBOARD_WAKE_CODE: if (deviceExtension->PowerCaps & I8042_WAKE_SYS_BUTTON) { IsrPrint(DBG_KBISR_POWER, ("Send Wake Button\n")); action = SendAction; } else { IsrPrint(DBG_KBISR_POWER, ("Update Wake Button\n")); action = UpdateAction; } break; default: action = NoAction; break; } if (action != NoAction) { // // Queue a DPC so that we can do the appropriate // action // KeInsertQueueDpc( &deviceExtension->SysButtonEventDpc, (PVOID) action, (PVOID) input->MakeCode ); } } } else { // // Got a make code. // IsrPrint(DBG_KBISR_SCODE, ("MAKE code\n")); input->MakeCode = scanCode; // // If the input scan code is debug stop, then drop // into the kernel debugger if it is active. // if ((KD_DEBUGGER_NOT_PRESENT == FALSE) && !(input->Flags & KEY_BREAK)) { if (ENHANCED_KEYBOARD( deviceExtension->KeyboardAttributes.KeyboardIdentifier )) { // // Enhanced 101 keyboard, SysReq key is 0xE0 0x37. // if ((input->MakeCode == KEYBOARD_DEBUG_HOTKEY_ENH) && (input->Flags & KEY_E0)) { try { if ((KD_DEBUGGER_ENABLED != FALSE) && Globals.BreakOnSysRq) { DbgBreakPointWithStatus(DBG_STATUS_SYSRQ); } } except(EXCEPTION_EXECUTE_HANDLER) { } } // // 84-key AT keyboard, SysReq key is 0xE0 0x54. // } else if ((input->MakeCode == KEYBOARD_DEBUG_HOTKEY_AT)) { try { if ((KD_DEBUGGER_ENABLED != FALSE) && Globals.BreakOnSysRq) { DbgBreakPointWithStatus(DBG_STATUS_SYSRQ); } } except(EXCEPTION_EXECUTE_HANDLER) { } } } } // // Reset the state to Normal. // *scanState = Normal; break; default: // // Queue a DPC to log an internal driver error. // KeInsertQueueDpc( &deviceExtension->ErrorLogDpc, (PIRP) NULL, LongToPtr(I8042_INVALID_ISR_STATE_KBD) ); ASSERT(FALSE); break; } } // // In the Normal state, if the keyboard device is enabled, // add the data to the InputData queue and queue the ISR DPC. // if (*scanState == Normal) { I8xQueueCurrentKeyboardInput(DeviceObject); } break; } IsrPrint(DBG_KBISR_TRACE, ("exit\n")); return TRUE; } VOID I8xProcessCrashDump( PPORT_KEYBOARD_EXTENSION DeviceExtension, UCHAR ScanCode, KEYBOARD_SCAN_STATE ScanState ) { LONG crashFlags; BOOLEAN processFlags; UCHAR crashScanCode, crashScanCode2; crashFlags = DeviceExtension->CrashFlags; crashScanCode = DeviceExtension->CrashScanCode; crashScanCode2 = DeviceExtension->CrashScanCode2; if (IS_MAKE_CODE(ScanCode)) { // // make code // // If it is one of the crash flag keys record it. // If it is a crash dump key record it // If it is neither, reset the current tracking state (CurrentCrashFlags) // switch (ScanCode) { case CTRL_SCANCODE: if (ScanState == Normal) { // Left DeviceExtension->CurrentCrashFlags |= CRASH_L_CTRL; } else if (ScanState == GotE0) { // Right DeviceExtension->CurrentCrashFlags |= CRASH_R_CTRL; } break; case ALT_SCANCODE: if (ScanState == Normal) { // Left DeviceExtension->CurrentCrashFlags |= CRASH_L_ALT; } else if (ScanState == GotE0) { // Right DeviceExtension->CurrentCrashFlags |= CRASH_R_ALT; } break; case LEFT_SHIFT_SCANCODE: if (ScanState == Normal) { DeviceExtension->CurrentCrashFlags |= CRASH_L_SHIFT; } break; case RIGHT_SHIFT_SCANCODE: if (ScanState == Normal) { DeviceExtension->CurrentCrashFlags |= CRASH_R_SHIFT; } break; default: if (IS_MAKE_CODE(crashScanCode)) { if (ScanState == Normal && crashScanCode == ScanCode) { break; } } else { if (ScanState == GotE0 && GET_MAKE_CODE(crashScanCode) == ScanCode) { break; } } if (IS_MAKE_CODE(crashScanCode2)) { if (ScanState == Normal && crashScanCode2 == ScanCode) { break; } } else { if (ScanState == GotE0 && GET_MAKE_CODE(crashScanCode2) == ScanCode) { break; } } // // Not a key we are interested in, reset our current state // DeviceExtension->CurrentCrashFlags = 0x0; break; } } else { // // break code // // If one of the modifer keys is released, our state is reset and all // keys have to be pressed again. // If it is a non modifier key, proceed with the processing if it is the // crash dump key, otherwise reset our tracking state // switch (GET_MAKE_CODE(ScanCode)) { case CTRL_SCANCODE: if (ScanState == Normal) { // Left DeviceExtension->CurrentCrashFlags &= ~(CRASH_BOTH_TIMES | CRASH_L_CTRL); } else if (ScanState == GotE0) { // Right DeviceExtension->CurrentCrashFlags &= ~(CRASH_BOTH_TIMES | CRASH_R_CTRL); } break; case ALT_SCANCODE: if (ScanState == Normal) { // Left DeviceExtension->CurrentCrashFlags &= ~(CRASH_BOTH_TIMES | CRASH_L_ALT); } else if (ScanState == GotE0) { // Right DeviceExtension->CurrentCrashFlags &= ~(CRASH_BOTH_TIMES | CRASH_R_ALT); } break; case RIGHT_SHIFT_SCANCODE: if (ScanState == Normal) { DeviceExtension->CurrentCrashFlags &= ~(CRASH_BOTH_TIMES | CRASH_R_SHIFT); } break; case LEFT_SHIFT_SCANCODE: if (ScanState == Normal) { DeviceExtension->CurrentCrashFlags &= ~(CRASH_BOTH_TIMES | CRASH_L_SHIFT); } break; default: processFlags = FALSE; if (IS_MAKE_CODE(crashScanCode)) { if (ScanState == Normal && crashScanCode == GET_MAKE_CODE(ScanCode)) processFlags = TRUE; } else { if (ScanState == GotE0 && crashScanCode == ScanCode) { processFlags = TRUE; } } if (IS_MAKE_CODE(crashScanCode2)) { if (ScanState == Normal && crashScanCode2 == GET_MAKE_CODE(ScanCode)) { processFlags = TRUE; } } else { if (ScanState == GotE0 && crashScanCode2 == ScanCode) processFlags = TRUE; } // // If this is the key we are interested in, continue, otherwise // our tracking state is reset // if (processFlags) { // // test to see if all the needed modifier // keys are down // if (crashFlags != (DeviceExtension->CurrentCrashFlags & crashFlags)) { break; } // // record how many times we have seen // this key // if (DeviceExtension->CurrentCrashFlags & CRASH_FIRST_TIME) { DeviceExtension->CurrentCrashFlags |= CRASH_SECOND_TIME; } else { DeviceExtension->CurrentCrashFlags |= CRASH_FIRST_TIME; } break; } DeviceExtension->CurrentCrashFlags = 0x0; break; } } crashFlags |= CRASH_BOTH_TIMES; if (DeviceExtension->CurrentCrashFlags == crashFlags) { DeviceExtension->CurrentCrashFlags = 0x0; // // Bring down the system in a somewhat controlled manner // KeBugCheckEx(MANUALLY_INITIATED_CRASH, 0, 0, 0, 0); } } // // The following table is used to convert typematic rate (keys per // second) into the value expected by the keyboard. The index into the // array is the number of keys per second. The resulting value is // the bit equate to send to the keyboard. // UCHAR I8xConvertTypematicParameters( IN USHORT Rate, IN USHORT Delay ) /*++ Routine Description: This routine converts the typematic rate and delay to the form the keyboard expects. The byte passed to the keyboard looks like this: - bit 7 is zero - bits 5 and 6 indicate the delay - bits 0-4 indicate the rate The delay is equal to 1 plus the binary value of bits 6 and 5, multiplied by 250 milliseconds. The period (interval from one typematic output to the next) is determined by the following equation: Period = (8 + A) x (2^B) x 0.00417 seconds where A = binary value of bits 0-2 B = binary value of bits 3 and 4 Arguments: Rate - Number of keys per second. Delay - Number of milliseconds to delay before the key repeat starts. Return Value: The byte to pass to the keyboard. --*/ { UCHAR value; UCHAR TypematicPeriod[] = { 31, // 0 keys per second 31, // 1 keys per second 28, // 2 keys per second, This is really 2.5, needed for NEXUS. 26, // 3 keys per second 23, // 4 keys per second 20, // 5 keys per second 18, // 6 keys per second 17, // 7 keys per second 15, // 8 keys per second 13, // 9 keys per second 12, // 10 keys per second 11, // 11 keys per second 10, // 12 keys per second 9, // 13 keys per second 9, // 14 keys per second 8, // 15 keys per second 7, // 16 keys per second 6, // 17 keys per second 5, // 18 keys per second 4, // 19 keys per second 4, // 20 keys per second 3, // 21 keys per second 3, // 22 keys per second 2, // 23 keys per second 2, // 24 keys per second 1, // 25 keys per second 1, // 26 keys per second 1 // 27 keys per second // > 27 keys per second, use 0 }; Print(DBG_CALL_TRACE, ("I8xConvertTypematicParameters: enter\n")); // // Calculate the delay bits. // value = (UCHAR) ((Delay / 250) - 1); // // Put delay bits in the right place. // value <<= 5; // // Get the typematic period from the table. If keys per second // is > 27, the typematic period value is zero. // if (Rate <= 27) { value |= TypematicPeriod[Rate]; } Print(DBG_CALL_TRACE, ("I8xConvertTypematicParameters: exit\n")); return(value); } #define KB_INIT_FAILED_RESET 0x00000001 #define KB_INIT_FAILED_XLATE_OFF 0x00000010 #define KB_INIT_FAILED_XLATE_ON 0x00000020 #define KB_INIT_FAILED_SET_TYPEMATIC 0x00000100 #define KB_INIT_FAILED_SET_TYPEMATIC_PARAM 0x00000200 #define KB_INIT_FAILED_SET_LEDS 0x00001000 #define KB_INIT_FAILED_SET_LEDS_PARAM 0x00002000 #define KB_INIT_FAILED_SELECT_SS 0x00010000 #define KB_INIT_FAILED_SELECT_SS_PARAM 0x00020000 #if KEYBOARD_RECORD_INIT ULONG KeyboardInitStatus; #define SET_KB_INIT_FAILURE(flag) KeyboardInitStatus |= flag #define KB_INIT_START() KeyboardInitStatus = 0x0; #else #define SET_KB_INIT_FAILURE(flag) #define KB_INIT_START() #endif // KEYBOARD_RECORD_INIT NTSTATUS I8xInitializeKeyboard( IN PPORT_KEYBOARD_EXTENSION KeyboardExtension ) /*++ Routine Description: This routine initializes the i8042 keyboard hardware. It is called only at initialization, and does not synchronize access to the hardware. Arguments: DeviceObject - Pointer to the device object. Return Value: Returns status. --*/ { NTSTATUS status; PKEYBOARD_ID id; PPORT_KEYBOARD_EXTENSION deviceExtension; PDEVICE_OBJECT deviceObject; UCHAR byte, failedResetResponseByte, failedResetResponseByte2; I8042_TRANSMIT_CCB_CONTEXT transmitCCBContext; ULONG i; ULONG limit; NTSTATUS failedLedsStatus, failedTypematicStatus, failedResetStatus, failedResetResponseStatus, failedResetResponseStatus2; PI8042_CONFIGURATION_INFORMATION configuration; PKEYBOARD_ID keyboardId; LARGE_INTEGER startOfSpin, nextQuery, difference, resetRespTimeout, li; BOOLEAN waitForAckOnReset = WAIT_FOR_ACKNOWLEDGE, translationOn = TRUE, failedReset = FALSE, failedResetResponse = FALSE, failedResetResponse2 = FALSE, failedTypematic = FALSE, failedLeds = FALSE; #define DUMP_COUNT 4 ULONG dumpData[DUMP_COUNT]; PAGED_CODE(); KB_INIT_START(); Print(DBG_SS_TRACE, ("I8xInitializeKeyboard, enter\n")); for (i = 0; i < DUMP_COUNT; i++) dumpData[i] = 0; // // Get the device extension. // deviceExtension = KeyboardExtension; deviceObject = deviceExtension->Self; // // Reset the keyboard. // StartOfReset: status = I8xPutBytePolled( (CCHAR) DataPort, waitForAckOnReset, (CCHAR) KeyboardDeviceType, (UCHAR) KEYBOARD_RESET ); if (!NT_SUCCESS(status)) { SET_KB_INIT_FAILURE(KB_INIT_FAILED_RESET); failedReset = TRUE; failedResetStatus = status; if (KeyboardExtension->FailedReset == FAILED_RESET_STOP) { // // If the device was reported, but not responding, it is phantom // status = STATUS_DEVICE_NOT_CONNECTED; SET_HW_FLAGS(PHANTOM_KEYBOARD_HARDWARE_REPORTED); Print(DBG_SS_INFO, ("kb failed reset Reset failed, stopping immediately\n")); goto I8xInitializeKeyboardExit; } else { // // NOTE: The Gateway 4DX2/66V has a problem when an old Compaq 286 // keyboard is attached. In this case, the keyboard reset // is not acknowledged (at least, the system never // receives the ack). Instead, the KEYBOARD_COMPLETE_SUCCESS // byte is sitting in the i8042 output buffer. The fix // is to ignore the keyboard reset failure and continue. // /* do nothing */; Print(DBG_SS_INFO, ("kb failed reset, proceeding\n")); } } // // Get the keyboard reset self-test response. A response byte of // KEYBOARD_COMPLETE_SUCCESS indicates success; KEYBOARD_COMPLETE_FAILURE // indicates failure. // // Note that it is usually necessary to stall a long time to get the // keyboard reset/self-test to work. // li.QuadPart = -100; resetRespTimeout.QuadPart = 50*10*1000*1000; KeQueryTickCount(&startOfSpin); while (TRUE) { status = I8xGetBytePolled( (CCHAR) KeyboardDeviceType, &byte ); if (NT_SUCCESS(status)) { if (byte == (UCHAR) KEYBOARD_COMPLETE_SUCCESS) { // // The reset completed successfully. // break; } else { // // There was some sort of failure during the reset // self-test. Continue anyway. // failedResetResponse = TRUE; failedResetResponseStatus = status; failedResetResponseByte = byte; break; } } else { if (status == STATUS_IO_TIMEOUT) { // // Stall, and then try again to get a response from // the reset. // KeDelayExecutionThread(KernelMode, FALSE, &li); KeQueryTickCount(&nextQuery); difference.QuadPart = nextQuery.QuadPart - startOfSpin.QuadPart; ASSERT(KeQueryTimeIncrement() <= MAXLONG); if (difference.QuadPart*KeQueryTimeIncrement() >= resetRespTimeout.QuadPart) { Print(DBG_SS_ERROR, ("no reset response, quitting\n")); break; } } else { break; } } } if (!NT_SUCCESS(status)) { if (waitForAckOnReset == WAIT_FOR_ACKNOWLEDGE) { waitForAckOnReset = NO_WAIT_FOR_ACKNOWLEDGE; goto StartOfReset; } failedResetResponse2 = TRUE; failedResetResponseStatus2 = status; failedResetResponseByte2 = byte; goto I8xInitializeKeyboardExit; } // // Turn off Keyboard Translate Mode. Call I8xTransmitControllerCommand // to read the Controller Command Byte, modify the appropriate bits, and // rewrite the Controller Command Byte. // transmitCCBContext.HardwareDisableEnableMask = 0; transmitCCBContext.AndOperation = AND_OPERATION; transmitCCBContext.ByteMask = (UCHAR) ~((UCHAR)CCB_KEYBOARD_TRANSLATE_MODE); I8xTransmitControllerCommand( (PVOID) &transmitCCBContext ); if (!NT_SUCCESS(transmitCCBContext.Status)) { // // If failure then retry once. This is for Toshiba T3400CT. // I8xTransmitControllerCommand( (PVOID) &transmitCCBContext ); } if (!NT_SUCCESS(transmitCCBContext.Status)) { Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: could not turn off translate\n" )); status = transmitCCBContext.Status; SET_KB_INIT_FAILURE(KB_INIT_FAILED_XLATE_OFF); goto I8xInitializeKeyboardExit; } // // Get a pointer to the keyboard identifier field. // id = &deviceExtension->KeyboardAttributes.KeyboardIdentifier; // // Set the typematic rate and delay. Send the Set Typematic Rate command // to the keyboard, followed by the typematic rate/delay parameter byte. // Note that it is often necessary to stall a long time to get this // to work. The stall value was determined by experimentation. Some // broken hardware does not accept this command, so ignore errors in the // hope that the keyboard will work okay anyway. // // if ((status = I8xPutBytePolled( (CCHAR) DataPort, WAIT_FOR_ACKNOWLEDGE, (CCHAR) KeyboardDeviceType, (UCHAR) SET_KEYBOARD_TYPEMATIC )) != STATUS_SUCCESS) { Print(DBG_SS_INFO, ("kb set typematic failed\n")); SET_KB_INIT_FAILURE(KB_INIT_FAILED_SET_TYPEMATIC); failedTypematic = TRUE; failedTypematicStatus = status; } else if ((status = I8xPutBytePolled( (CCHAR) DataPort, WAIT_FOR_ACKNOWLEDGE, (CCHAR) KeyboardDeviceType, I8xConvertTypematicParameters( deviceExtension->KeyRepeatCurrent.Rate, deviceExtension->KeyRepeatCurrent.Delay ))) != STATUS_SUCCESS) { SET_KB_INIT_FAILURE(KB_INIT_FAILED_SET_TYPEMATIC_PARAM); Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: could not send typematic param\n" )); // // Log an error. // dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM; dumpData[1] = DataPort; dumpData[2] = SET_KEYBOARD_TYPEMATIC; dumpData[3] = I8xConvertTypematicParameters( deviceExtension->KeyRepeatCurrent.Rate, deviceExtension->KeyRepeatCurrent.Delay ); I8xLogError( deviceObject, I8042_SET_TYPEMATIC_FAILED, I8042_ERROR_VALUE_BASE + 540, status, dumpData, 4 ); } status = STATUS_SUCCESS; // // Set the keyboard indicator lights. Ignore errors. // if ((status = I8xPutBytePolled( (CCHAR) DataPort, WAIT_FOR_ACKNOWLEDGE, (CCHAR) KeyboardDeviceType, (UCHAR) SET_KEYBOARD_INDICATORS )) != STATUS_SUCCESS) { Print(DBG_SS_INFO, ("kb set LEDs failed\n")); SET_KB_INIT_FAILURE(KB_INIT_FAILED_SET_LEDS); failedLeds = TRUE; failedLedsStatus = status; } else if ((status = I8xPutBytePolled( (CCHAR) DataPort, WAIT_FOR_ACKNOWLEDGE, (CCHAR) KeyboardDeviceType, (UCHAR) deviceExtension->KeyboardIndicators.LedFlags )) != STATUS_SUCCESS) { SET_KB_INIT_FAILURE(KB_INIT_FAILED_SET_LEDS_PARAM); Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: could not send SET LEDS param\n" )); // // Log an error. // dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM; dumpData[1] = DataPort; dumpData[2] = SET_KEYBOARD_INDICATORS; dumpData[3] = deviceExtension->KeyboardIndicators.LedFlags; I8xLogError( deviceObject, I8042_SET_LED_FAILED, I8042_ERROR_VALUE_BASE + 550, status, dumpData, 4 ); } status = STATUS_SUCCESS; #if !(defined(_X86_) || defined(_IA64_) || defined(_PPC_)) // IBMCPK: MIPS specific initialization // // NOTE: This code is necessary until the MIPS firmware stops // selecting scan code set 3. Select scan code set 2 here. // Since the translate bit is set, the net effect is that // we will receive scan code set 1 bytes. // if (ENHANCED_KEYBOARD(*id)) { status = I8xPutBytePolled( (CCHAR) DataPort, WAIT_FOR_ACKNOWLEDGE, (CCHAR) KeyboardDeviceType, (UCHAR) SELECT_SCAN_CODE_SET ); if (NT_SUCCESS(status)) { // // Send the associated parameter byte. // status = I8xPutBytePolled( (CCHAR) DataPort, WAIT_FOR_ACKNOWLEDGE, (CCHAR) KeyboardDeviceType, (UCHAR) 2 ); } if (!NT_SUCCESS(status)) { Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: could not send Select Scan command\n" )); // // This failed so probably what we have here isn't an enhanced // keyboard at all. Make this an old style keyboard. // configuration = &Globals.ControllerData->Configuration; keyboardId = &deviceExtension->KeyboardAttributes.KeyboardIdentifier; keyboardId->Type = 3; deviceExtension->KeyboardAttributes.NumberOfFunctionKeys = KeyboardTypeInformation[keyboardId->Type - 1].NumberOfFunctionKeys; deviceExtension->KeyboardAttributes.NumberOfIndicators = KeyboardTypeInformation[keyboardId->Type - 1].NumberOfIndicators; deviceExtension->KeyboardAttributes.NumberOfKeysTotal = KeyboardTypeInformation[keyboardId->Type - 1].NumberOfKeysTotal; status = STATUS_SUCCESS; } } #endif #if defined(FE_SB) if (IBM02_KEYBOARD(*id)) { // // IBM-J 5576-002 Keyboard should set local scan code set for // supplied NLS key. // status = I8xPutBytePolled( (CCHAR) DataPort, WAIT_FOR_ACKNOWLEDGE, (CCHAR) KeyboardDeviceType, (UCHAR) SELECT_SCAN_CODE_SET ); if (status != STATUS_SUCCESS) { Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: could not send Select Scan command\n" )); Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: WARNING - using scan set 82h\n" )); deviceExtension->KeyboardAttributes.KeyboardMode = 3; } else { // // Send the associated parameter byte. // status = I8xPutBytePolled( (CCHAR) DataPort, WAIT_FOR_ACKNOWLEDGE, (CCHAR) KeyboardDeviceType, (UCHAR) 0x82 ); if (status != STATUS_SUCCESS) { Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: could not send Select Scan param\n" )); Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: WARNING - using scan set 82h\n" )); deviceExtension->KeyboardAttributes.KeyboardMode = 3; } } } #endif // FE_SB if (deviceExtension->InitializationHookCallback) { (*deviceExtension->InitializationHookCallback) ( deviceExtension->HookContext, (PVOID) deviceObject, (PI8042_SYNCH_READ_PORT) I8xKeyboardSynchReadPort, (PI8042_SYNCH_WRITE_PORT) I8xKeyboardSynchWritePort, &translationOn ); } if (deviceExtension->KeyboardAttributes.KeyboardMode == 1 && translationOn) { // // Turn translate back on. The keyboard should, by default, send // scan code set 2. When the translate bit in the 8042 command byte // is on, the 8042 translates the scan code set 2 bytes to scan code // set 1 before sending them to the CPU. Scan code set 1 is // the industry standard scan code set. // // N.B. It does not appear to be possible to change the translate // bit on some models of PS/2. // transmitCCBContext.HardwareDisableEnableMask = 0; transmitCCBContext.AndOperation = OR_OPERATION; transmitCCBContext.ByteMask = (UCHAR) CCB_KEYBOARD_TRANSLATE_MODE; I8xTransmitControllerCommand( (PVOID) &transmitCCBContext ); if (!NT_SUCCESS(transmitCCBContext.Status)) { SET_KB_INIT_FAILURE(KB_INIT_FAILED_XLATE_ON); Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: couldn't turn on translate\n" )); if (transmitCCBContext.Status == STATUS_DEVICE_DATA_ERROR) { // // Could not turn translate back on. This happens on some // PS/2 machines. In this case, select scan code set 1 // for the keyboard, since the 8042 will not do the // translation from the scan code set 2, which is what the // KEYBOARD_RESET caused the keyboard to default to. // if (ENHANCED_KEYBOARD(*id)) { status = I8xPutBytePolled( (CCHAR) DataPort, WAIT_FOR_ACKNOWLEDGE, (CCHAR) KeyboardDeviceType, (UCHAR) SELECT_SCAN_CODE_SET ); if (!NT_SUCCESS(status)) { SET_KB_INIT_FAILURE(KB_INIT_FAILED_SELECT_SS); Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: could not send Select Scan command\n" )); Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: WARNING - using scan set 2\n" )); deviceExtension->KeyboardAttributes.KeyboardMode = 2; // // Log an error. // dumpData[0] = KBDMOU_COULD_NOT_SEND_COMMAND; dumpData[1] = DataPort; dumpData[2] = SELECT_SCAN_CODE_SET; I8xLogError( deviceObject, I8042_SELECT_SCANSET_FAILED, I8042_ERROR_VALUE_BASE + 555, status, dumpData, 3 ); } else { // // Send the associated parameter byte. // status = I8xPutBytePolled( (CCHAR) DataPort, WAIT_FOR_ACKNOWLEDGE, (CCHAR) KeyboardDeviceType, #ifdef FE_SB // I8xInitializeKeyboard() (UCHAR) (IBM02_KEYBOARD(*id) ? 0x81 : 1 ) #else (UCHAR) 1 #endif // FE_SB ); if (!NT_SUCCESS(status)) { SET_KB_INIT_FAILURE(KB_INIT_FAILED_SELECT_SS_PARAM); Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: could not send Select Scan param\n" )); Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: WARNING - using scan set 2\n" )); deviceExtension->KeyboardAttributes.KeyboardMode = 2; // // Log an error. // dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM; dumpData[1] = DataPort; dumpData[2] = SELECT_SCAN_CODE_SET; dumpData[3] = 1; I8xLogError( deviceObject, I8042_SELECT_SCANSET_FAILED, I8042_ERROR_VALUE_BASE + 560, status, dumpData, 4 ); } } } } else { status = transmitCCBContext.Status; goto I8xInitializeKeyboardExit; } } } I8xInitializeKeyboardExit: // // If all 3 of these have failed, then we have a device that was reported // present but is not plugged in. This usually happens on either an ACPI // enabled machine (where it always reports the PS/2 kbd and mouse present) // or on a machine which has legacy HID support (where the reported PS/2 // device(s) are really USB HID). // // If this is the case, then we will succeed the start and hide the device // in the UI // if (failedReset && failedTypematic && failedLeds) { if (KeyboardExtension->FailedReset == FAILED_RESET_PROCEED) { OBJECT_ATTRIBUTES oa; UNICODE_STRING string; HANDLE hService, hParameters; InitializeObjectAttributes(&oa, &Globals.RegistryPath, OBJ_CASE_INSENSITIVE, NULL, (PSECURITY_DESCRIPTOR) NULL); if (NT_SUCCESS(ZwOpenKey(&hService, KEY_ALL_ACCESS, &oa))) { RtlInitUnicodeString(&string, L"Parameters"); InitializeObjectAttributes(&oa, &string, OBJ_CASE_INSENSITIVE, hService, (PSECURITY_DESCRIPTOR) NULL); if (NT_SUCCESS(ZwOpenKey(&hParameters, KEY_ALL_ACCESS, &oa))) { ULONG tmp; RtlInitUnicodeString (&string, STR_FAILED_RESET); tmp = FAILED_RESET_STOP; Print(DBG_SS_INFO | DBG_SS_ERROR, ("Future failed kbd resets will stop init\n")); ZwSetValueKey(hParameters, &string, 0, REG_DWORD, &tmp, sizeof(tmp)); ZwClose(hParameters); } ZwClose(hService); } } Print(DBG_SS_INFO, ("kb, all 3 sets failed, assuming a phantom keyboard\n")); status = STATUS_DEVICE_NOT_CONNECTED; // errorCode = I8042_NO_KBD_DEVICE; SET_HW_FLAGS(PHANTOM_KEYBOARD_HARDWARE_REPORTED); if (Globals.ReportResetErrors) { I8xLogError(deviceObject, I8042_NO_KBD_DEVICE, 0, status, NULL, 0 ); } } else { if (failedReset) { Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: failed keyboard reset, status 0x%x\n", status )); if (Globals.ReportResetErrors) { dumpData[0] = KBDMOU_COULD_NOT_SEND_COMMAND; dumpData[1] = DataPort; dumpData[2] = KEYBOARD_RESET; I8xLogError(deviceObject, I8042_KBD_RESET_COMMAND_FAILED, I8042_ERROR_VALUE_BASE + 510, failedResetStatus, dumpData, 3 ); } } if (failedResetResponse2) { Print(DBG_SS_ERROR, ("I8xInitializeKeyboard, failed reset response, status 0x%x, byte 0x%x\n", status, byte )); // // Log a warning. // dumpData[0] = KBDMOU_INCORRECT_RESPONSE; dumpData[1] = KeyboardDeviceType; dumpData[2] = KEYBOARD_COMPLETE_SUCCESS; dumpData[3] = failedResetResponse2; I8xLogError( deviceObject, I8042_KBD_RESET_RESPONSE_FAILED, I8042_ERROR_VALUE_BASE + 520, failedResetResponseStatus2, dumpData, 4 ); } else if (failedResetResponse) { Print(DBG_SS_ERROR, ("kb failed reset response\n") ); // // Log a warning. // dumpData[0] = KBDMOU_INCORRECT_RESPONSE; dumpData[1] = KeyboardDeviceType; dumpData[2] = KEYBOARD_COMPLETE_SUCCESS; dumpData[3] = failedResetResponseByte; I8xLogError( deviceObject, I8042_KBD_RESET_RESPONSE_FAILED, I8042_ERROR_VALUE_BASE + 515, failedResetResponseStatus, dumpData, 4 ); } if (failedTypematic) { Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: could not send SET TYPEMATIC cmd\n" )); // // Log an error. // dumpData[0] = KBDMOU_COULD_NOT_SEND_COMMAND; dumpData[1] = DataPort; dumpData[2] = SET_KEYBOARD_TYPEMATIC; I8xLogError( deviceObject, I8042_SET_TYPEMATIC_FAILED, I8042_ERROR_VALUE_BASE + 535, failedTypematicStatus, dumpData, 3 ); } if (failedLeds) { Print(DBG_SS_ERROR, ("I8xInitializeKeyboard: could not send SET LEDS cmd\n" )); // // Log an error. // dumpData[0] = KBDMOU_COULD_NOT_SEND_COMMAND; dumpData[1] = DataPort; dumpData[2] = SET_KEYBOARD_INDICATORS; I8xLogError( deviceObject, I8042_SET_LED_FAILED, I8042_ERROR_VALUE_BASE + 545, failedLedsStatus, dumpData, 3 ); } } if (DEVICE_START_SUCCESS(status)) { SET_HW_FLAGS(KEYBOARD_HARDWARE_PRESENT | KEYBOARD_HARDWARE_INITIALIZED); } else { CLEAR_KEYBOARD_PRESENT(); } // // Initialize current keyboard set packet state. // deviceExtension->CurrentOutput.State = Idle; deviceExtension->CurrentOutput.Bytes = NULL; deviceExtension->CurrentOutput.ByteCount = 0; Print(DBG_SS_TRACE, ("I8xInitializeKeyboard (0x%x)\n", status)); return status; } NTSTATUS I8xKeyboardConfiguration( IN PPORT_KEYBOARD_EXTENSION KeyboardExtension, IN PCM_RESOURCE_LIST ResourceList ) /*++ Routine Description: This routine retrieves the configuration information for the keyboard. Arguments: KeyboardExtension - Keyboard extension ResourceList - Translated resource list give to us via the start IRP Return Value: STATUS_SUCCESS if all the resources required are presented --*/ { NTSTATUS status = STATUS_SUCCESS; PCM_PARTIAL_RESOURCE_LIST partialResList = NULL; PCM_PARTIAL_RESOURCE_DESCRIPTOR firstResDesc = NULL, currentResDesc = NULL; PCM_FULL_RESOURCE_DESCRIPTOR fullResDesc = NULL; PI8042_CONFIGURATION_INFORMATION configuration; PKEYBOARD_ID keyboardId; ULONG count, i; KINTERRUPT_MODE defaultInterruptMode; BOOLEAN defaultInterruptShare; PAGED_CODE(); if (!ResourceList) { Print(DBG_SS_INFO | DBG_SS_ERROR, ("keyboard with null resources\n")); return STATUS_INSUFFICIENT_RESOURCES; } fullResDesc = ResourceList->List; if (!fullResDesc) { // // this should never happen // ASSERT(fullResDesc != NULL); return STATUS_INSUFFICIENT_RESOURCES; } configuration = &Globals.ControllerData->Configuration; partialResList = &fullResDesc->PartialResourceList; currentResDesc = firstResDesc = partialResList->PartialDescriptors; count = partialResList->Count; configuration->FloatingSave = I8042_FLOATING_SAVE; configuration->BusNumber = fullResDesc->BusNumber; configuration->InterfaceType = fullResDesc->InterfaceType; if (configuration->InterfaceType == MicroChannel) { defaultInterruptShare = TRUE; defaultInterruptMode = LevelSensitive; } else { defaultInterruptShare = I8042_INTERRUPT_SHARE; defaultInterruptMode = I8042_INTERRUPT_MODE; } for (i = 0; i < count; i++, currentResDesc++) { switch (currentResDesc->Type) { case CmResourceTypeMemory: Globals.RegistersMapped = TRUE; case CmResourceTypePort: // // Copy the port information. We will sort the port list // into ascending order based on the starting port address // later (note that we *know* there are a max of two port // ranges for the i8042). // #if 0 if (currentResDesc->Flags == CM_RESOURCE_PORT_MEMORY) { Globals.RegistersMapped = TRUE; } #endif Print(DBG_SS_NOISE, ("port is %s.\n", Globals.RegistersMapped ? "memory" : "io")); if (configuration->PortListCount < MaximumPortCount) { configuration->PortList[configuration->PortListCount] = *currentResDesc; configuration->PortList[configuration->PortListCount].ShareDisposition = I8042_REGISTER_SHARE ? CmResourceShareShared: CmResourceShareDriverExclusive; configuration->PortListCount += 1; } else { Print(DBG_SS_INFO | DBG_SS_ERROR, ("KB::PortListCount already at max (%d)\n", configuration->PortListCount ) ); } break; case CmResourceTypeInterrupt: // // Copy the interrupt information. // KeyboardExtension->InterruptDescriptor = *currentResDesc; KeyboardExtension->InterruptDescriptor.ShareDisposition = defaultInterruptShare ? CmResourceShareShared : CmResourceShareDeviceExclusive; break; default: Print(DBG_ALWAYS, ("resource type 0x%x unhandled...\n", (LONG) currentResDesc->Type )); break; } } if (KeyboardExtension->InterruptDescriptor.Type & CmResourceTypeInterrupt) { Print(DBG_SS_INFO, ("Keyboard interrupt config --\n" " %s, %s, Irq = 0x%x\n", KeyboardExtension->InterruptDescriptor.ShareDisposition == CmResourceShareShared ? "Sharable" : "NonSharable", KeyboardExtension->InterruptDescriptor.Flags == CM_RESOURCE_INTERRUPT_LATCHED ? "Latched" : "Level Sensitive", KeyboardExtension->InterruptDescriptor.u.Interrupt.Vector )); } // // If no keyboard-specific information (i.e., keyboard type, subtype, // and initial LED settings) was found, use the keyboard driver // defaults. // if (KeyboardExtension->KeyboardAttributes.KeyboardIdentifier.Type == 0) { Print(DBG_SS_INFO, ("Using default keyboard type\n")); KeyboardExtension->KeyboardAttributes.KeyboardIdentifier.Type = KEYBOARD_TYPE_DEFAULT; KeyboardExtension->KeyboardIndicators.LedFlags = KEYBOARD_INDICATORS_DEFAULT; KeyboardExtension->KeyboardIdentifierEx.Type = KEYBOARD_TYPE_DEFAULT; } Print(DBG_SS_INFO, ("Keyboard device specific data --\n" " Type = %d, Subtype = %d, Initial LEDs = 0x%x\n", KeyboardExtension->KeyboardAttributes.KeyboardIdentifier.Type, KeyboardExtension->KeyboardAttributes.KeyboardIdentifier.Subtype, KeyboardExtension->KeyboardIndicators.LedFlags )); keyboardId = &KeyboardExtension->KeyboardAttributes.KeyboardIdentifier; if (!ENHANCED_KEYBOARD(*keyboardId)) { Print(DBG_SS_INFO, ("Old AT-style keyboard\n")); configuration->PollingIterations = configuration->PollingIterationsMaximum; } // // Initialize keyboard-specific configuration parameters. // if (FAREAST_KEYBOARD(*keyboardId)) { ULONG iIndex = 0; PKEYBOARD_TYPE_INFORMATION pKeyboardTypeInformation = NULL; while (KeyboardFarEastOemInformation[iIndex].KeyboardId.Type) { if ((KeyboardFarEastOemInformation[iIndex].KeyboardId.Type == keyboardId->Type) && (KeyboardFarEastOemInformation[iIndex].KeyboardId.Subtype == keyboardId->Subtype)) { pKeyboardTypeInformation = (PKEYBOARD_TYPE_INFORMATION) &(KeyboardFarEastOemInformation[iIndex].KeyboardTypeInformation); break; } iIndex++; } if (pKeyboardTypeInformation == NULL) { // // Set default... // pKeyboardTypeInformation = (PKEYBOARD_TYPE_INFORMATION) &(KeyboardTypeInformation[KEYBOARD_TYPE_DEFAULT-1]); } KeyboardExtension->KeyboardAttributes.NumberOfFunctionKeys = pKeyboardTypeInformation->NumberOfFunctionKeys; KeyboardExtension->KeyboardAttributes.NumberOfIndicators = pKeyboardTypeInformation->NumberOfIndicators; KeyboardExtension->KeyboardAttributes.NumberOfKeysTotal = pKeyboardTypeInformation->NumberOfKeysTotal; } else { KeyboardExtension->KeyboardAttributes.NumberOfFunctionKeys = KeyboardTypeInformation[keyboardId->Type - 1].NumberOfFunctionKeys; KeyboardExtension->KeyboardAttributes.NumberOfIndicators = KeyboardTypeInformation[keyboardId->Type - 1].NumberOfIndicators; KeyboardExtension->KeyboardAttributes.NumberOfKeysTotal = KeyboardTypeInformation[keyboardId->Type - 1].NumberOfKeysTotal; } KeyboardExtension->KeyboardAttributes.KeyboardMode = KEYBOARD_SCAN_CODE_SET; KeyboardExtension->KeyboardAttributes.KeyRepeatMinimum.Rate = KEYBOARD_TYPEMATIC_RATE_MINIMUM; KeyboardExtension->KeyboardAttributes.KeyRepeatMinimum.Delay = KEYBOARD_TYPEMATIC_DELAY_MINIMUM; KeyboardExtension->KeyboardAttributes.KeyRepeatMaximum.Rate = KEYBOARD_TYPEMATIC_RATE_MAXIMUM; KeyboardExtension->KeyboardAttributes.KeyRepeatMaximum.Delay = KEYBOARD_TYPEMATIC_DELAY_MAXIMUM; KeyboardExtension->KeyRepeatCurrent.Rate = KEYBOARD_TYPEMATIC_RATE_DEFAULT; KeyboardExtension->KeyRepeatCurrent.Delay = KEYBOARD_TYPEMATIC_DELAY_DEFAULT; return status; } #if defined(_X86_) ULONG I8042ConversionStatusForOasys( IN ULONG fOpen, IN ULONG ConvStatus) /*++ Routine Description: This routine convert ime open/close status and ime converion mode to FMV oyayubi-shift keyboard device internal input mode. Arguments: Return Value: FMV oyayubi-shift keyboard's internal input mode. --*/ { ULONG ImeMode = 0; if (fOpen) { if (ConvStatus & IME_CMODE_ROMAN) { if (ConvStatus & IME_CMODE_ALPHANUMERIC) { // // Alphanumeric, roman mode. // ImeMode = THUMB_ROMAN_ALPHA_CAPSON; } else if (ConvStatus & IME_CMODE_KATAKANA) { // // Katakana, roman mode. // ImeMode = THUMB_ROMAN_KATAKANA; } else if (ConvStatus & IME_CMODE_NATIVE) { // // Hiragana, roman mode. // ImeMode = THUMB_ROMAN_HIRAGANA; } else { ImeMode = THUMB_ROMAN_ALPHA_CAPSON; } } else { if (ConvStatus & IME_CMODE_ALPHANUMERIC) { // // Alphanumeric, no-roman mode. // ImeMode = THUMB_NOROMAN_ALPHA_CAPSON; } else if (ConvStatus & IME_CMODE_KATAKANA) { // // Katakana, no-roman mode. // ImeMode = THUMB_NOROMAN_KATAKANA; } else if (ConvStatus & IME_CMODE_NATIVE) { // // Hiragana, no-roman mode. // ImeMode = THUMB_NOROMAN_HIRAGANA; } else { ImeMode = THUMB_NOROMAN_ALPHA_CAPSON; } } } else { // // Ime close. In this case, internal mode is always this value. // (the both LED off roman and kana) // ImeMode = THUMB_NOROMAN_ALPHA_CAPSON; } return ImeMode; } ULONG I8042QueryIMEStatusForOasys( IN PKEYBOARD_IME_STATUS KeyboardIMEStatus ) { ULONG InternalMode; // // Map to IME mode to hardware mode. // InternalMode = I8042ConversionStatusForOasys( KeyboardIMEStatus->ImeOpen, KeyboardIMEStatus->ImeConvMode ); return InternalMode; } NTSTATUS I8042SetIMEStatusForOasys( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN OUT PINITIATE_OUTPUT_CONTEXT InitiateContext ) { PKEYBOARD_IME_STATUS KeyboardIMEStatus; PPORT_KEYBOARD_EXTENSION kbExtension; ULONG InternalMode; LARGE_INTEGER deltaTime; kbExtension = DeviceObject->DeviceExtension; // // Get pointer to KEYBOARD_IME_STATUS buffer. // KeyboardIMEStatus = (PKEYBOARD_IME_STATUS)(Irp->AssociatedIrp.SystemBuffer); // // Map IME mode to keyboard hardware mode. // InternalMode = I8042QueryIMEStatusForOasys(KeyboardIMEStatus); // // Set up the context structure for the InitiateIo wrapper. // InitiateContext->Bytes = Globals.ControllerData->DefaultBuffer; InitiateContext->DeviceObject = DeviceObject; InitiateContext->ByteCount = 3; InitiateContext->Bytes[0] = 0xF0; InitiateContext->Bytes[1] = 0x8C; InitiateContext->Bytes[2] = (UCHAR)InternalMode; return (STATUS_SUCCESS); } #endif // defined(_X86_) VOID I8xQueueCurrentKeyboardInput( IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This routine queues the current input data to be processed by a DPC outside the ISR Arguments: DeviceObject - Pointer to the device object Return Value: None --*/ { PPORT_KEYBOARD_EXTENSION deviceExtension; deviceExtension = DeviceObject->DeviceExtension; if (deviceExtension->EnableCount) { if (!I8xWriteDataToKeyboardQueue( deviceExtension, &deviceExtension->CurrentInput )) { // // The InputData queue overflowed. There is // not much that can be done about it, so just // continue (but don't queue the ISR DPC, since // no new packets were added to the queue). // // Queue a DPC to log an overrun error. // IsrPrint(DBG_KBISR_ERROR, ("queue overflow\n")); if (deviceExtension->OkayToLogOverflow) { KeInsertQueueDpc( &deviceExtension->ErrorLogDpc, (PIRP) NULL, LongToPtr(I8042_KBD_BUFFER_OVERFLOW) ); deviceExtension->OkayToLogOverflow = FALSE; } } else if (deviceExtension->DpcInterlockKeyboard >= 0) { // // The ISR DPC is already executing. Tell the ISR DPC // it has more work to do by incrementing // DpcInterlockKeyboard. // deviceExtension->DpcInterlockKeyboard += 1; } else { // // Queue the ISR DPC. // KeInsertQueueDpc( &deviceExtension->KeyboardIsrDpc, DeviceObject->CurrentIrp, NULL ); } } // // Reset the input state. // deviceExtension->CurrentInput.Flags = 0; } VOID I8xServiceCrashDump( IN PPORT_KEYBOARD_EXTENSION DeviceExtension, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: This routine retrieves this driver's service parameters information from the registry. Arguments: DeviceExtension - Pointer to the device extension. RegistryPath - Pointer to the null-terminated Unicode name of the registry path for this driver. Return Value: None. As a side-effect, sets fields in DeviceExtension->Dump1Keys & DeviceExtension->Dump2Key. --*/ { PRTL_QUERY_REGISTRY_TABLE parameters = NULL; UNICODE_STRING parametersPath; LONG defaultCrashFlags = 0; LONG crashFlags; LONG defaultKeyNumber = 0; LONG keyNumber; NTSTATUS status = STATUS_SUCCESS; PWSTR path = NULL; USHORT queriesPlusOne = 3; const UCHAR keyToScanTbl[134] = { 0x00,0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09, 0x0A,0x0B,0x0C,0x0D,0x7D,0x0E,0x0F,0x10,0x11,0x12, 0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x00, 0x3A,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26, 0x27,0x28,0x2B,0x1C,0x2A,0x00,0x2C,0x2D,0x2E,0x2F, 0x30,0x31,0x32,0x33,0x34,0x35,0x73,0x36,0x1D,0x00, 0x38,0x39,0xB8,0x00,0x9D,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xD2,0xD3,0x00,0x00,0xCB, 0xC7,0xCF,0x00,0xC8,0xD0,0xC9,0xD1,0x00,0x00,0xCD, 0x45,0x47,0x4B,0x4F,0x00,0xB5,0x48,0x4C,0x50,0x52, 0x37,0x49,0x4D,0x51,0x53,0x4A,0x4E,0x00,0x9C,0x00, 0x01,0x00,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42, 0x43,0x44,0x57,0x58,0x00,0x46,0x00,0x00,0x00,0x00, 0x00,0x7B,0x79,0x70 }; PAGED_CODE(); parametersPath.Buffer = NULL; // // Registry path is already null-terminated, so just use it. // path = RegistryPath->Buffer; if (NT_SUCCESS(status)) { // // Allocate the Rtl query table. // parameters = ExAllocatePool( PagedPool, sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne ); if (!parameters) { Print(DBG_SS_ERROR, ("I8xServiceCrashDump: Couldn't allocate table for Rtl query to parameters for %ws\n", path )); status = STATUS_UNSUCCESSFUL; } else { RtlZeroMemory( parameters, sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne ); // // Form a path to this driver's Parameters subkey. // RtlInitUnicodeString( ¶metersPath, NULL ); parametersPath.MaximumLength = RegistryPath->Length + sizeof(L"\\Crashdump"); parametersPath.Buffer = ExAllocatePool( PagedPool, parametersPath.MaximumLength ); if (!parametersPath.Buffer) { Print(DBG_SS_ERROR, ("I8xServiceCrashDump: Couldn't allocate string for path to parameters for %ws\n", path )); status = STATUS_UNSUCCESSFUL; } } } if (NT_SUCCESS(status)) { // // Form the parameters path. // RtlZeroMemory( parametersPath.Buffer, parametersPath.MaximumLength ); RtlAppendUnicodeToString( ¶metersPath, path ); RtlAppendUnicodeToString( ¶metersPath, L"\\Crashdump" ); Print(DBG_SS_INFO, ("I8xServiceCrashDump: crashdump path is %ws\n", parametersPath.Buffer )); // // Gather all of the "user specified" information from // the registry. // parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[0].Name = L"Dump1Keys"; parameters[0].EntryContext = &crashFlags; parameters[0].DefaultType = REG_DWORD; parameters[0].DefaultData = &defaultCrashFlags; parameters[0].DefaultLength = sizeof(LONG); parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[1].Name = L"Dump2Key"; parameters[1].EntryContext = &keyNumber; parameters[1].DefaultType = REG_DWORD; parameters[1].DefaultData = &defaultKeyNumber; parameters[1].DefaultLength = sizeof(LONG); status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, parametersPath.Buffer, parameters, NULL, NULL ); } if (!NT_SUCCESS(status)) { // // Go ahead and assign driver defaults. // DeviceExtension->CrashFlags = defaultCrashFlags; } else { DeviceExtension->CrashFlags = crashFlags; } if (DeviceExtension->CrashFlags) { if (keyNumber == 124) { DeviceExtension->CrashScanCode = KEYBOARD_DEBUG_HOTKEY_ENH | 0x80; DeviceExtension->CrashScanCode2 = KEYBOARD_DEBUG_HOTKEY_AT; } else { if(keyNumber <= 133) { DeviceExtension->CrashScanCode = keyToScanTbl[keyNumber]; } else { DeviceExtension->CrashScanCode = 0; } DeviceExtension->CrashScanCode2 = 0; } } Print(DBG_SS_NOISE, ("I8xServiceCrashDump: CrashFlags = 0x%x\n", DeviceExtension->CrashFlags )); Print(DBG_SS_NOISE, ("I8xServiceCrashDump: CrashScanCode = 0x%x, CrashScanCode2 = 0x%x\n", (ULONG) DeviceExtension->CrashScanCode, (ULONG) DeviceExtension->CrashScanCode2 )); // // Free the allocated memory before returning. // if (parametersPath.Buffer) ExFreePool(parametersPath.Buffer); if (parameters) ExFreePool(parameters); } VOID I8xKeyboardServiceParameters( IN PUNICODE_STRING RegistryPath, IN PPORT_KEYBOARD_EXTENSION KeyboardExtension ) /*++ Routine Description: This routine retrieves this driver's service parameters information from the registry. Overrides these values if they are present in the devnode. Arguments: RegistryPath - Pointer to the null-terminated Unicode name of the registry path for this driver. KeyboardExtension - Keyboard extension Return Value: None. --*/ { NTSTATUS status = STATUS_SUCCESS; PI8042_CONFIGURATION_INFORMATION configuration; PRTL_QUERY_REGISTRY_TABLE parameters = NULL; PWSTR path = NULL; ULONG defaultDataQueueSize = DATA_QUEUE_SIZE; ULONG invalidKeyboardSubtype = (ULONG) -1; ULONG invalidKeyboardType = 0; ULONG overrideKeyboardSubtype = (ULONG) -1; ULONG overrideKeyboardType = 0; ULONG pollStatusIterations = 0; ULONG defaultPowerCaps = 0x0, powerCaps = 0x0; ULONG failedReset = FAILED_RESET_DEFAULT, defaultFailedReset = FAILED_RESET_DEFAULT; ULONG i = 0; UNICODE_STRING parametersPath; HANDLE keyHandle; ULONG defaultPollStatusIterations = I8042_POLLING_DEFAULT; ULONG crashOnCtrlScroll = 0, defaultCrashOnCtrlScroll = 0; USHORT queries = 8; PAGED_CODE(); #if I8042_VERBOSE queries += 2; #endif configuration = &(Globals.ControllerData->Configuration); parametersPath.Buffer = NULL; // // Registry path is already null-terminated, so just use it. // path = RegistryPath->Buffer; if (NT_SUCCESS(status)) { // // Allocate the Rtl query table. // parameters = ExAllocatePool( PagedPool, sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1) ); if (!parameters) { Print(DBG_SS_ERROR, ("%s: couldn't allocate table for Rtl query to %ws for %ws\n", pFncServiceParameters, pwParameters, path )); status = STATUS_UNSUCCESSFUL; } else { RtlZeroMemory( parameters, sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1) ); // // Form a path to this driver's Parameters subkey. // RtlInitUnicodeString( ¶metersPath, NULL ); parametersPath.MaximumLength = RegistryPath->Length + (wcslen(pwParameters) * sizeof(WCHAR) ) + sizeof(UNICODE_NULL); parametersPath.Buffer = ExAllocatePool( PagedPool, parametersPath.MaximumLength ); if (!parametersPath.Buffer) { Print(DBG_SS_ERROR, ("%s: Couldn't allocate string for path to %ws for %ws\n", pFncServiceParameters, pwParameters, path )); status = STATUS_UNSUCCESSFUL; } } } if (NT_SUCCESS(status)) { // // Form the parameters path. // RtlZeroMemory( parametersPath.Buffer, parametersPath.MaximumLength ); RtlAppendUnicodeToString( ¶metersPath, path ); RtlAppendUnicodeToString( ¶metersPath, pwParameters ); // // Gather all of the "user specified" information from // the registry. // parameters[i].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[i].Name = pwKeyboardDataQueueSize; parameters[i].EntryContext = &KeyboardExtension->KeyboardAttributes.InputDataQueueLength; parameters[i].DefaultType = REG_DWORD; parameters[i].DefaultData = &defaultDataQueueSize; parameters[i].DefaultLength = sizeof(ULONG); parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[i].Name = pwOverrideKeyboardType; parameters[i].EntryContext = &overrideKeyboardType; parameters[i].DefaultType = REG_DWORD; parameters[i].DefaultData = &invalidKeyboardType; parameters[i].DefaultLength = sizeof(ULONG); parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[i].Name = pwOverrideKeyboardSubtype; parameters[i].EntryContext = &overrideKeyboardSubtype; parameters[i].DefaultType = REG_DWORD; parameters[i].DefaultData = &invalidKeyboardSubtype; parameters[i].DefaultLength = sizeof(ULONG); parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[i].Name = pwPollStatusIterations; parameters[i].EntryContext = &pollStatusIterations; parameters[i].DefaultType = REG_DWORD; parameters[i].DefaultData = &defaultPollStatusIterations; parameters[i].DefaultLength = sizeof(ULONG); parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[i].Name = pwPowerCaps; parameters[i].EntryContext = &powerCaps; parameters[i].DefaultType = REG_DWORD; parameters[i].DefaultData = &defaultPowerCaps; parameters[i].DefaultLength = sizeof(ULONG); parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[i].Name = L"CrashOnCtrlScroll"; parameters[i].EntryContext = &crashOnCtrlScroll; parameters[i].DefaultType = REG_DWORD; parameters[i].DefaultData = &defaultCrashOnCtrlScroll; parameters[i].DefaultLength = sizeof(ULONG); parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[i].Name = STR_FAILED_RESET; parameters[i].EntryContext = &failedReset; parameters[i].DefaultType = REG_DWORD; parameters[i].DefaultData = &defaultFailedReset; parameters[i].DefaultLength = sizeof(ULONG); status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, parametersPath.Buffer, parameters, NULL, NULL ); if (!NT_SUCCESS(status)) { Print(DBG_SS_INFO, ("kb RtlQueryRegistryValues failed (0x%x)\n", status )); } } if (!NT_SUCCESS(status)) { // // Go ahead and assign driver defaults. // configuration->PollStatusIterations = (USHORT) defaultPollStatusIterations; KeyboardExtension->KeyboardAttributes.InputDataQueueLength = defaultDataQueueSize; } else { configuration->PollStatusIterations = (USHORT) pollStatusIterations; } switch (failedReset) { case FAILED_RESET_STOP: case FAILED_RESET_PROCEED: case FAILED_RESET_PROCEED_ALWAYS: KeyboardExtension->FailedReset = (UCHAR) failedReset; break; default: KeyboardExtension->FailedReset = FAILED_RESET_DEFAULT; break; } Print(DBG_SS_NOISE, ("Failed reset is set to %d\n", KeyboardExtension->FailedReset)); status = IoOpenDeviceRegistryKey(KeyboardExtension->PDO, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_READ, &keyHandle ); if (NT_SUCCESS(status)) { // // If the value is not present in devnode, then the default is the value // read in from the Services\i8042prt\Parameters key // ULONG prevInputDataQueueLength, prevPowerCaps, prevOverrideKeyboardType, prevOverrideKeyboardSubtype, prevPollStatusIterations; prevInputDataQueueLength = KeyboardExtension->KeyboardAttributes.InputDataQueueLength; prevPowerCaps = powerCaps; prevOverrideKeyboardType = overrideKeyboardType; prevOverrideKeyboardSubtype = overrideKeyboardSubtype; prevPollStatusIterations = pollStatusIterations; RtlZeroMemory( parameters, sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1) ); i = 0; // // Gather all of the "user specified" information from // the registry (this time from the devnode) // parameters[i].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[i].Name = pwKeyboardDataQueueSize; parameters[i].EntryContext = &KeyboardExtension->KeyboardAttributes.InputDataQueueLength; parameters[i].DefaultType = REG_DWORD; parameters[i].DefaultData = &prevInputDataQueueLength; parameters[i].DefaultLength = sizeof(ULONG); parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[i].Name = pwOverrideKeyboardType; parameters[i].EntryContext = &overrideKeyboardType; parameters[i].DefaultType = REG_DWORD; parameters[i].DefaultData = &prevOverrideKeyboardType; parameters[i].DefaultLength = sizeof(ULONG); parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[i].Name = pwOverrideKeyboardSubtype; parameters[i].EntryContext = &overrideKeyboardSubtype; parameters[i].DefaultType = REG_DWORD; parameters[i].DefaultData = &prevOverrideKeyboardSubtype; parameters[i].DefaultLength = sizeof(ULONG); parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[i].Name = pwPollStatusIterations; parameters[i].EntryContext = &pollStatusIterations; parameters[i].DefaultType = REG_DWORD; parameters[i].DefaultData = &prevPollStatusIterations; parameters[i].DefaultLength = sizeof(ULONG); parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[i].Name = pwPowerCaps, parameters[i].EntryContext = &powerCaps; parameters[i].DefaultType = REG_DWORD; parameters[i].DefaultData = &prevPowerCaps; parameters[i].DefaultLength = sizeof(ULONG); status = RtlQueryRegistryValues( RTL_REGISTRY_HANDLE, (PWSTR) keyHandle, parameters, NULL, NULL ); if (!NT_SUCCESS(status)) { Print(DBG_SS_INFO, ("kb RtlQueryRegistryValues (via handle) failed (0x%x)\n", status )); } ZwClose(keyHandle); } else { Print(DBG_SS_INFO | DBG_SS_ERROR, ("kb, opening devnode handle failed (0x%x)\n", status )); } Print(DBG_SS_NOISE, ("I8xKeyboardServiceParameters results..\n")); Print(DBG_SS_NOISE, (pDumpDecimal, pwPollStatusIterations, configuration->PollStatusIterations )); if (KeyboardExtension->KeyboardAttributes.InputDataQueueLength == 0) { Print(DBG_SS_INFO | DBG_SS_ERROR, ("\toverriding %ws = 0x%x\n", pwKeyboardDataQueueSize, KeyboardExtension->KeyboardAttributes.InputDataQueueLength )); KeyboardExtension->KeyboardAttributes.InputDataQueueLength = defaultDataQueueSize; } KeyboardExtension->KeyboardAttributes.InputDataQueueLength *= sizeof(KEYBOARD_INPUT_DATA); KeyboardExtension->PowerCaps = (UCHAR) (powerCaps & I8042_SYS_BUTTONS); Print(DBG_SS_NOISE, (pDumpHex, pwPowerCaps, KeyboardExtension->PowerCaps)); if (overrideKeyboardType != invalidKeyboardType) { if (overrideKeyboardType <= NUM_KNOWN_KEYBOARD_TYPES) { Print(DBG_SS_NOISE, (pDumpDecimal, pwOverrideKeyboardType, overrideKeyboardType )); KeyboardExtension->KeyboardAttributes.KeyboardIdentifier.Type = (UCHAR) overrideKeyboardType; } else { Print(DBG_SS_NOISE, (pDumpDecimal, pwOverrideKeyboardType, overrideKeyboardType )); } KeyboardExtension->KeyboardIdentifierEx.Type = overrideKeyboardType; } if (overrideKeyboardSubtype != invalidKeyboardSubtype) { Print(DBG_SS_NOISE, (pDumpDecimal, pwOverrideKeyboardSubtype, overrideKeyboardSubtype )); KeyboardExtension->KeyboardAttributes.KeyboardIdentifier.Subtype = (UCHAR) overrideKeyboardSubtype; KeyboardExtension->KeyboardIdentifierEx.Subtype = overrideKeyboardSubtype; } if (crashOnCtrlScroll) { Print(DBG_SS_INFO, ("Crashing on Ctrl + Scroll Lock\n")); KeyboardExtension->CrashFlags = CRASH_R_CTRL; KeyboardExtension->CrashScanCode = SCROLL_LOCK_SCANCODE; KeyboardExtension->CrashScanCode2 = 0x0; } // // Free the allocated memory before returning. // if (parametersPath.Buffer) ExFreePool(parametersPath.Buffer); if (parameters) ExFreePool(parameters); }