|
|
/*++
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 <ntddk.h>
#include <windef.h>
#include <imm.h>
#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 = 10*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); }
|