NT4/private/ntos/dd/i8042prt/kbdcmn.c
2020-09-30 17:12:29 +02:00

435 lines
14 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990, 1991, 1992, 1993 Microsoft Corporation
Module Name:
kbdcmn.c
Abstract:
The common portions of the Intel i8042 port driver which
apply to the keyboard device.
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 "i8042prt.h"
VOID
I8042KeyboardIsrDpc(
IN PKDPC Dpc,
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routine runs at DISPATCH_LEVEL IRQL to finish processing
keyboard interrupts. It is queued in the keyboard ISR. The real
work is done via a callback to the connected keyboard class driver.
Arguments:
Dpc - Pointer to the DPC object.
DeviceObject - Pointer to the device object.
Irp - Pointer to the Irp.
Context - Not used.
Return Value:
None.
--*/
{
PDEVICE_EXTENSION deviceExtension;
GET_DATA_POINTER_CONTEXT getPointerContext;
SET_DATA_POINTER_CONTEXT setPointerContext;
VARIABLE_OPERATION_CONTEXT operationContext;
PVOID classService;
PVOID classDeviceObject;
LONG interlockedResult;
BOOLEAN moreDpcProcessing;
ULONG dataNotConsumed = 0;
ULONG inputDataConsumed = 0;
LARGE_INTEGER deltaTime;
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(Irp);
UNREFERENCED_PARAMETER(Context);
I8xPrint((2, "I8042PRT-I8042KeyboardIsrDpc: enter\n"));
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
//
// Use DpcInterlockKeyboard to determine whether the DPC is running
// concurrently on another processor. We only want one instantiation
// of the DPC to actually do any work. DpcInterlockKeyboard is -1
// when no DPC is executing. We increment it, and if the result is
// zero then the current instantiation is the only one executing, and it
// is okay to proceed. Otherwise, we just return.
//
//
operationContext.VariableAddress =
&deviceExtension->DpcInterlockKeyboard;
operationContext.Operation = IncrementOperation;
operationContext.NewValue = &interlockedResult;
KeSynchronizeExecution(
deviceExtension->KeyboardInterruptObject,
(PKSYNCHRONIZE_ROUTINE) I8xDpcVariableOperation,
(PVOID) &operationContext
);
moreDpcProcessing = (interlockedResult == 0)? TRUE:FALSE;
while (moreDpcProcessing) {
dataNotConsumed = 0;
inputDataConsumed = 0;
//
// Get the port InputData queue pointers synchronously.
//
getPointerContext.DeviceExtension = deviceExtension;
setPointerContext.DeviceExtension = deviceExtension;
getPointerContext.DeviceType = (CCHAR) KeyboardDeviceType;
setPointerContext.DeviceType = (CCHAR) KeyboardDeviceType;
setPointerContext.InputCount = 0;
KeSynchronizeExecution(
deviceExtension->KeyboardInterruptObject,
(PKSYNCHRONIZE_ROUTINE) I8xGetDataQueuePointer,
(PVOID) &getPointerContext
);
if (getPointerContext.InputCount != 0) {
//
// Call the connected class driver's callback ISR with the
// port InputData queue pointers. If we have to wrap the queue,
// break the operation into two pieces, and call the class
// callback ISR once for each piece.
//
classDeviceObject =
deviceExtension->KeyboardExtension.ConnectData.ClassDeviceObject;
classService =
deviceExtension->KeyboardExtension.ConnectData.ClassService;
ASSERT(classService != NULL);
if (getPointerContext.DataOut >= getPointerContext.DataIn) {
//
// We'll have to wrap the InputData circular buffer. Call
// the class callback ISR with the chunk of data starting at
// DataOut and ending at the end of the queue.
//
I8xPrint((
2,
"I8042PRT-I8042KeyboardIsrDpc: calling class callback\n"
));
I8xPrint((
2,
"I8042PRT-I8042KeyboardIsrDpc: with Start 0x%x and End 0x%x\n",
getPointerContext.DataOut,
deviceExtension->KeyboardExtension.DataEnd
));
(*(PSERVICE_CALLBACK_ROUTINE) classService)(
classDeviceObject,
getPointerContext.DataOut,
deviceExtension->KeyboardExtension.DataEnd,
&inputDataConsumed
);
dataNotConsumed = (((PUCHAR)
deviceExtension->KeyboardExtension.DataEnd -
(PUCHAR) getPointerContext.DataOut)
/ sizeof(KEYBOARD_INPUT_DATA)) - inputDataConsumed;
I8xPrint((
2,
"I8042PRT-I8042KeyboardIsrDpc: (Wrap) Call callback consumed %d items, left %d\n",
inputDataConsumed,
dataNotConsumed
));
setPointerContext.InputCount += inputDataConsumed;
if (dataNotConsumed) {
setPointerContext.DataOut =
((PUCHAR)getPointerContext.DataOut) +
(inputDataConsumed * sizeof(KEYBOARD_INPUT_DATA));
} else {
setPointerContext.DataOut =
deviceExtension->KeyboardExtension.InputData;
getPointerContext.DataOut = setPointerContext.DataOut;
}
}
//
// Call the class callback ISR with data remaining in the queue.
//
if ((dataNotConsumed == 0) &&
(inputDataConsumed < getPointerContext.InputCount)){
I8xPrint((
2,
"I8042PRT-I8042KeyboardIsrDpc: calling class callback\n"
));
I8xPrint((
2,
"I8042PRT-I8042KeyboardIsrDpc: with Start 0x%x and End 0x%x\n",
getPointerContext.DataOut,
getPointerContext.DataIn
));
(*(PSERVICE_CALLBACK_ROUTINE) classService)(
classDeviceObject,
getPointerContext.DataOut,
getPointerContext.DataIn,
&inputDataConsumed
);
dataNotConsumed = (((PUCHAR) getPointerContext.DataIn -
(PUCHAR) getPointerContext.DataOut)
/ sizeof(KEYBOARD_INPUT_DATA)) - inputDataConsumed;
I8xPrint((
2,
"I8042PRT-I8042KeyboardIsrDpc: Call callback consumed %d items, left %d\n",
inputDataConsumed,
dataNotConsumed
));
setPointerContext.DataOut =
((PUCHAR)getPointerContext.DataOut) +
(inputDataConsumed * sizeof(KEYBOARD_INPUT_DATA));
setPointerContext.InputCount += inputDataConsumed;
}
//
// Update the port InputData queue DataOut pointer and InputCount
// synchronously.
//
KeSynchronizeExecution(
deviceExtension->KeyboardInterruptObject,
(PKSYNCHRONIZE_ROUTINE) I8xSetDataQueuePointer,
(PVOID) &setPointerContext
);
}
if (dataNotConsumed) {
//
// The class driver was unable to consume all the data.
// Reset the interlocked variable to -1. We do not want
// to attempt to move more data to the class driver at this
// point, because it is already overloaded. Need to wait a
// while to give the Raw Input Thread a chance to read some
// of the data out of the class driver's queue. We accomplish
// this "wait" via a timer.
//
I8xPrint((2, "I8042PRT-I8042KeyboardIsrDpc: set timer in DPC\n"));
operationContext.Operation = WriteOperation;
interlockedResult = -1;
operationContext.NewValue = &interlockedResult;
KeSynchronizeExecution(
deviceExtension->KeyboardInterruptObject,
(PKSYNCHRONIZE_ROUTINE) I8xDpcVariableOperation,
(PVOID) &operationContext
);
deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
deltaTime.HighPart = -1;
(VOID) KeSetTimer(
&deviceExtension->KeyboardExtension.DataConsumptionTimer,
deltaTime,
&deviceExtension->KeyboardIsrDpcRetry
);
moreDpcProcessing = FALSE;
} else {
//
// Decrement DpcInterlockKeyboard. If the result goes negative,
// then we're all finished processing the DPC. Otherwise, either
// the ISR incremented DpcInterlockKeyboard because it has more
// work for the ISR DPC to do, or a concurrent DPC executed on
// some processor while the current DPC was running (the
// concurrent DPC wouldn't have done any work). Make sure that
// the current DPC handles any extra work that is ready to be
// done.
//
operationContext.Operation = DecrementOperation;
operationContext.NewValue = &interlockedResult;
KeSynchronizeExecution(
deviceExtension->KeyboardInterruptObject,
(PKSYNCHRONIZE_ROUTINE) I8xDpcVariableOperation,
(PVOID) &operationContext
);
if (interlockedResult != -1) {
//
// The interlocked variable is still greater than or equal to
// zero. Reset it to zero, so that we execute the loop one
// more time (assuming no more DPCs execute and bump the
// variable up again).
//
operationContext.Operation = WriteOperation;
interlockedResult = 0;
operationContext.NewValue = &interlockedResult;
KeSynchronizeExecution(
deviceExtension->KeyboardInterruptObject,
(PKSYNCHRONIZE_ROUTINE) I8xDpcVariableOperation,
(PVOID) &operationContext
);
I8xPrint((2, "I8042PRT-I8042KeyboardIsrDpc: loop in DPC\n"));
} else {
moreDpcProcessing = FALSE;
}
}
}
I8xPrint((2, "I8042PRT-I8042KeyboardIsrDpc: exit\n"));
}
BOOLEAN
I8xWriteDataToKeyboardQueue(
PPORT_KEYBOARD_EXTENSION KeyboardExtension,
IN PKEYBOARD_INPUT_DATA InputData
)
/*++
Routine Description:
This routine adds input data from the keyboard to the InputData queue.
Arguments:
KeyboardExtension - Pointer to the keyboard portion of the device extension.
InputData - Pointer to the data to add to the InputData queue.
Return Value:
Returns TRUE if the data was added, otherwise FALSE.
--*/
{
PKEYBOARD_INPUT_DATA previousDataIn;
I8xPrint((2,"I8042PRT-I8xWriteDataToKeyboardQueue: enter\n"));
I8xPrint((
3,
"I8042PRT-I8xWriteDataToKeyboardQueue: DataIn 0x%x, DataOut 0x%x\n",
KeyboardExtension->DataIn,
KeyboardExtension->DataOut
));
I8xPrint((
3,
"I8042PRT-I8xWriteDataToKeyboardQueue: InputCount %d\n",
KeyboardExtension->InputCount
));
//
// Check for full input data queue.
//
if ((KeyboardExtension->DataIn == KeyboardExtension->DataOut) &&
(KeyboardExtension->InputCount != 0)) {
//
// Queue overflow. Replace the previous input data packet
// with a keyboard overrun data packet, thus losing both the
// previous and the current input data packet.
//
I8xPrint((1,"I8042PRT-I8xWriteDataToKeyboardQueue: OVERFLOW\n"));
if (KeyboardExtension->DataIn == KeyboardExtension->InputData) {
I8xPrint((2,"I8042PRT-I8xWriteDataToKeyboardQueue: wrap buffer\n"));
previousDataIn = KeyboardExtension->DataEnd;
} else {
previousDataIn = KeyboardExtension->DataIn - 1;
}
previousDataIn->MakeCode = KEYBOARD_OVERRUN_MAKE_CODE;
previousDataIn->Flags = 0;
I8xPrint((2,"I8042PRT-I8xWriteDataToKeyboardQueue: exit\n"));
return(FALSE);
} else {
*(KeyboardExtension->DataIn) = *InputData;
KeyboardExtension->InputCount += 1;
KeyboardExtension->DataIn++;
I8xPrint((
2,
"I8042PRT-I8xWriteDataToKeyboardQueue: new InputCount %d\n",
KeyboardExtension->InputCount
));
if (KeyboardExtension->DataIn ==
KeyboardExtension->DataEnd) {
I8xPrint((2,"I8042PRT-I8xWriteDataToKeyboardQueue: wrap buffer\n"));
KeyboardExtension->DataIn = KeyboardExtension->InputData;
}
}
I8xPrint((2,"I8042PRT-I8xWriteDataToKeyboardQueue: exit\n"));
return(TRUE);
}