You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2750 lines
82 KiB
2750 lines
82 KiB
/*++
|
|
|
|
Copyright (c) 1990-1998 Microsoft Corporation, All Rights Reserved
|
|
|
|
Module Name:
|
|
|
|
i8042cmn.c
|
|
|
|
Abstract:
|
|
|
|
The common portions of the Intel i8042 port driver which
|
|
apply to both the keyboard and the auxiliary (PS/2 mouse) device.
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Notes:
|
|
|
|
NOTES: (Future/outstanding issues)
|
|
|
|
- Powerfail not implemented.
|
|
|
|
- IOCTL_INTERNAL_KEYBOARD_DISCONNECT and IOCTL_INTERNAL_MOUSE_DISCONNECT
|
|
have not been implemented. They're not needed until the class
|
|
unload routine is implemented. Right now, we don't want to allow
|
|
either the keyboard or the mouse class driver to unload.
|
|
|
|
- Consolidate duplicate code, where possible and appropriate.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "stdarg.h"
|
|
#include "stdio.h"
|
|
#include "string.h"
|
|
#include "i8042prt.h"
|
|
#include "i8042log.h"
|
|
|
|
// sys button IOCTL definitions
|
|
#include "poclass.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, I8xClose)
|
|
#pragma alloc_text(PAGE, I8xCreate)
|
|
#pragma alloc_text(PAGE, I8xDeviceControl)
|
|
#pragma alloc_text(PAGE, I8xSanityCheckResources)
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
NTSTATUS
|
|
I8xCreate (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the dispatch routine for create/open requests.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
|
|
Irp - Pointer to the request packet.
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PCOMMON_DATA commonData = NULL;
|
|
|
|
Print(DBG_CC_TRACE, ("Create enter\n"));
|
|
|
|
PAGED_CODE();
|
|
|
|
commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
|
|
|
|
if (NULL == commonData->ConnectData.ClassService) {
|
|
//
|
|
// No Connection yet. How can we be enabled?
|
|
//
|
|
Print(DBG_IOCTL_ERROR | DBG_CC_ERROR,
|
|
("ERROR: enable before connect!\n"));
|
|
status = STATUS_INVALID_DEVICE_STATE;
|
|
}
|
|
else if (MANUALLY_REMOVED(commonData)) {
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
else
|
|
#if defined(_M_IX86) && (_MSC_FULL_VER < 13009175) // workaround for 13.00.9111 compiler (fixed in 9175 or better)
|
|
{
|
|
ULONG i = InterlockedIncrement(&commonData->EnableCount);
|
|
if (1 >= i) {
|
|
Print(DBG_CC_INFO,
|
|
("Enabling %s (%d)\n",
|
|
commonData->IsKeyboard ? "Keyboard" : "Mouse",
|
|
commonData->EnableCount
|
|
));
|
|
}
|
|
}
|
|
#else
|
|
if (1 >= InterlockedIncrement(&commonData->EnableCount)) {
|
|
Print(DBG_CC_INFO,
|
|
("Enabling %s (%d)\n",
|
|
commonData->IsKeyboard ? "Keyboard" : "Mouse",
|
|
commonData->EnableCount
|
|
));
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// No need to call the lower driver (the root bus) because it only handles
|
|
// Power and PnP Irps
|
|
//
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
Print(DBG_CC_TRACE, ("Create (%x)\n", status));
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
I8xClose (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the dispatch routine for close requests. This request
|
|
completes successfully.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
|
|
Irp - Pointer to the request packet.
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
PCOMMON_DATA commonData;
|
|
ULONG count;
|
|
|
|
PAGED_CODE();
|
|
|
|
Print(DBG_CC_TRACE, ("Close\n"));
|
|
|
|
commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
|
|
|
|
ASSERT(0 < commonData->EnableCount);
|
|
|
|
count = InterlockedDecrement(&commonData->EnableCount);
|
|
if (0 >= count) {
|
|
Print(DBG_IOCTL_INFO,
|
|
("Disabling %s (%d)\n",
|
|
commonData->IsKeyboard ? "Keyboard" : "Mouse",
|
|
commonData->EnableCount
|
|
));
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
I8042CompletionDpc(
|
|
IN PKDPC Dpc,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN ISR_DPC_CAUSE IsrDpcCause
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine runs at DISPATCH_LEVEL IRQL to complete requests.
|
|
It is queued by the ISR routine.
|
|
|
|
Arguments:
|
|
|
|
Dpc - Pointer to the DPC object.
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
|
|
Irp - Irp about to be completed
|
|
|
|
Context - Indicates type of error to log.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpSp;
|
|
PPORT_KEYBOARD_EXTENSION kbExtension = DeviceObject->DeviceExtension;
|
|
PPORT_MOUSE_EXTENSION mouseExtension = DeviceObject->DeviceExtension;
|
|
PCOMMON_DATA commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
|
|
|
|
UNREFERENCED_PARAMETER(Dpc);
|
|
UNREFERENCED_PARAMETER(IsrDpcCause);
|
|
|
|
Print(DBG_DPC_TRACE, ("I8042CompletionDpc: enter\n"));
|
|
|
|
// Stop the command timer.
|
|
KeCancelTimer(&Globals.ControllerData->CommandTimer);
|
|
|
|
ASSERT(Irp == DeviceObject->CurrentIrp);
|
|
ASSERT(Irp != NULL);
|
|
|
|
if (Irp == NULL) {
|
|
#if DBG
|
|
if (Globals.ControllerData->CurrentIoControlCode != 0x0) {
|
|
Print(DBG_DPC_ERROR,
|
|
("Current IOCTL code is 0x%x\n",
|
|
Globals.ControllerData->CurrentIoControlCode
|
|
));
|
|
}
|
|
#endif
|
|
|
|
goto CompletionDpcFinished;
|
|
}
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
#if DBG
|
|
ASSERT(irpSp->Parameters.DeviceIoControl.IoControlCode ==
|
|
Globals.ControllerData->CurrentIoControlCode);
|
|
|
|
Globals.ControllerData->CurrentIoControlCode = 0x0;
|
|
#endif
|
|
|
|
//
|
|
// We know we're completing an internal device control request. Switch
|
|
// on IoControlCode.
|
|
//
|
|
switch(irpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
|
|
//
|
|
// Complete the keyboard set indicators request.
|
|
//
|
|
case IOCTL_KEYBOARD_SET_INDICATORS:
|
|
|
|
Print(DBG_IOCTL_NOISE | DBG_DPC_NOISE,
|
|
("I8042CompletionDpc: keyboard set indicators updated\n"
|
|
));
|
|
|
|
//
|
|
// Update the current indicators flag in the device extension.
|
|
//
|
|
kbExtension->KeyboardIndicators =
|
|
*(PKEYBOARD_INDICATOR_PARAMETERS) Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
Print(DBG_IOCTL_INFO | DBG_DPC_INFO,
|
|
("I8042CompletionDpc: new LED flags 0x%x\n",
|
|
kbExtension->KeyboardIndicators.LedFlags
|
|
));
|
|
|
|
break;
|
|
|
|
//
|
|
// Complete the keyboard set typematic request.
|
|
//
|
|
case IOCTL_KEYBOARD_SET_TYPEMATIC:
|
|
|
|
Print(DBG_IOCTL_NOISE | DBG_DPC_NOISE,
|
|
("I8042CompletionDpc: keyboard set typematic updated\n"
|
|
));
|
|
|
|
//
|
|
// Update the current typematic rate/delay in the device extension.
|
|
//
|
|
kbExtension->KeyRepeatCurrent =
|
|
*(PKEYBOARD_TYPEMATIC_PARAMETERS) Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
Print(DBG_IOCTL_INFO | DBG_DPC_INFO,
|
|
("I8042CompletionDpc: new rate/delay 0x%x/%x\n",
|
|
kbExtension->KeyRepeatCurrent.Rate,
|
|
kbExtension->KeyRepeatCurrent.Delay
|
|
));
|
|
|
|
break;
|
|
|
|
case IOCTL_INTERNAL_MOUSE_RESET:
|
|
|
|
Print(DBG_IOCTL_NOISE | DBG_DPC_NOISE,
|
|
("I8042CompletionDpc: mouse reset complete\n"
|
|
));
|
|
|
|
I8xFinishResetRequest(mouseExtension,
|
|
FALSE, // success
|
|
FALSE, // at DISPATCH already
|
|
TRUE); // cancel the timer
|
|
return;
|
|
|
|
default:
|
|
|
|
Print(DBG_DPC_INFO, ("I8042CompletionDpc: miscellaneous\n"));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the completion status, start the next packet, and complete the
|
|
// request.
|
|
//
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest (Irp, IO_KEYBOARD_INCREMENT);
|
|
|
|
KeAcquireSpinLockAtDpcLevel(&Globals.ControllerData->BytesSpinLock);
|
|
if (commonData->CurrentOutput.Bytes &&
|
|
commonData->CurrentOutput.Bytes != Globals.ControllerData->DefaultBuffer) {
|
|
ExFreePool(commonData->CurrentOutput.Bytes);
|
|
}
|
|
#if DBG
|
|
else {
|
|
RtlZeroMemory(Globals.ControllerData->DefaultBuffer,
|
|
sizeof(Globals.ControllerData->DefaultBuffer));
|
|
}
|
|
#endif
|
|
commonData->CurrentOutput.Bytes = NULL;
|
|
KeReleaseSpinLockFromDpcLevel(&Globals.ControllerData->BytesSpinLock);
|
|
|
|
CompletionDpcFinished:
|
|
IoFreeController(Globals.ControllerData->ControllerObject);
|
|
IoStartNextPacket(DeviceObject, FALSE);
|
|
|
|
if (Irp != NULL) {
|
|
IoReleaseRemoveLock(&commonData->RemoveLock, Irp);
|
|
}
|
|
|
|
Print(DBG_DPC_TRACE, ("I8042CompletionDpc: exit\n"));
|
|
}
|
|
|
|
VOID
|
|
I8042ErrorLogDpc(
|
|
IN PKDPC Dpc,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine runs at DISPATCH_LEVEL IRQL to log errors that are
|
|
discovered at IRQL > DISPATCH_LEVEL (e.g., in the ISR routine or
|
|
in a routine that is executed via KeSynchronizeExecution). There
|
|
is not necessarily a current request associated with this condition.
|
|
|
|
Arguments:
|
|
|
|
Dpc - Pointer to the DPC object.
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
|
|
Irp - Not used.
|
|
|
|
Context - Indicates type of error to log.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PIO_ERROR_LOG_PACKET errorLogEntry;
|
|
|
|
UNREFERENCED_PARAMETER(Dpc);
|
|
UNREFERENCED_PARAMETER(Irp);
|
|
|
|
Print(DBG_DPC_TRACE, ("I8042ErrorLogDpc: enter\n"));
|
|
|
|
//
|
|
// Log an error packet.
|
|
//
|
|
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
|
|
DeviceObject,
|
|
sizeof(IO_ERROR_LOG_PACKET)
|
|
+ (2 * sizeof(ULONG))
|
|
);
|
|
if (errorLogEntry != NULL) {
|
|
|
|
errorLogEntry->DumpDataSize = 2 * sizeof(ULONG);
|
|
if ((ULONG_PTR) Context == I8042_KBD_BUFFER_OVERFLOW) {
|
|
errorLogEntry->UniqueErrorValue = I8042_ERROR_VALUE_BASE + 310;
|
|
errorLogEntry->DumpData[0] = sizeof(KEYBOARD_INPUT_DATA);
|
|
errorLogEntry->DumpData[1] = ((PPORT_KEYBOARD_EXTENSION)
|
|
DeviceObject->DeviceExtension)->KeyboardAttributes.InputDataQueueLength;
|
|
}
|
|
else if ((ULONG_PTR) Context == I8042_MOU_BUFFER_OVERFLOW) {
|
|
errorLogEntry->UniqueErrorValue = I8042_ERROR_VALUE_BASE + 320;
|
|
errorLogEntry->DumpData[0] = sizeof(MOUSE_INPUT_DATA);
|
|
errorLogEntry->DumpData[1] = ((PPORT_MOUSE_EXTENSION)
|
|
DeviceObject->DeviceExtension)->MouseAttributes.InputDataQueueLength;
|
|
}
|
|
else {
|
|
errorLogEntry->UniqueErrorValue = I8042_ERROR_VALUE_BASE + 330;
|
|
errorLogEntry->DumpData[0] = 0;
|
|
errorLogEntry->DumpData[1] = 0;
|
|
}
|
|
|
|
errorLogEntry->ErrorCode = (NTSTATUS)((ULONG_PTR)Context);
|
|
errorLogEntry->SequenceNumber = 0;
|
|
errorLogEntry->MajorFunctionCode = 0;
|
|
errorLogEntry->IoControlCode = 0;
|
|
errorLogEntry->RetryCount = 0;
|
|
errorLogEntry->FinalStatus = 0;
|
|
|
|
IoWriteErrorLogEntry(errorLogEntry);
|
|
}
|
|
|
|
Print(DBG_DPC_TRACE, ("I8042ErrorLogDpc: exit\n"));
|
|
}
|
|
|
|
NTSTATUS
|
|
I8xFlush(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unimplemented flush routine
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - An FDO
|
|
|
|
Irp - The flush request
|
|
|
|
Return Value:
|
|
|
|
STATUS_NOT_IMPLEMENTED;
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
UNREFERENCED_PARAMETER(Irp);
|
|
|
|
Print(DBG_CALL_TRACE, ("I8042Flush: enter\n"));
|
|
Print(DBG_CALL_TRACE, ("I8042Flush: exit\n"));
|
|
|
|
return(STATUS_NOT_IMPLEMENTED);
|
|
}
|
|
|
|
NTSTATUS
|
|
I8xDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PPORT_KEYBOARD_EXTENSION kbExtension;
|
|
PIO_STACK_LOCATION stack;
|
|
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Get a pointer to the device extension.
|
|
//
|
|
kbExtension = (PPORT_KEYBOARD_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
if (!kbExtension->IsKeyboard || !kbExtension->Started ||
|
|
MANUALLY_REMOVED(kbExtension)) {
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
else {
|
|
stack = IoGetCurrentIrpStackLocation(Irp);
|
|
switch (stack->Parameters.DeviceIoControl.IoControlCode) {
|
|
|
|
case IOCTL_GET_SYS_BUTTON_CAPS:
|
|
return I8xKeyboardGetSysButtonCaps(kbExtension, Irp);
|
|
|
|
case IOCTL_GET_SYS_BUTTON_EVENT:
|
|
return I8xKeyboardGetSysButtonEvent(kbExtension, Irp);
|
|
|
|
default:
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
I8xSendIoctl(
|
|
PDEVICE_OBJECT Target,
|
|
ULONG Ioctl,
|
|
PVOID InputBuffer,
|
|
ULONG InputBufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sends an internal IOCTL to the top of the stack.
|
|
|
|
Arguments:
|
|
|
|
Target - The top of the stack
|
|
|
|
Ioctl - The IOCTL to send
|
|
|
|
InputBuffer - The buffer to be filled if the IOCTL is handled on the way down
|
|
|
|
InputBufferLength - size, in bytes, of InputBuffer
|
|
|
|
Return Value:
|
|
|
|
STATUS_NOT_IMPLEMENTED;
|
|
|
|
--*/
|
|
{
|
|
KEVENT event;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
IO_STATUS_BLOCK iosb;
|
|
PIRP irp;
|
|
|
|
KeInitializeEvent(&event,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
|
|
//
|
|
// Allocate an IRP - No need to release
|
|
// When the next-lower driver completes this IRP, the I/O Manager releases it.
|
|
//
|
|
if (NULL == (irp = IoBuildDeviceIoControlRequest(Ioctl,
|
|
Target,
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
0,
|
|
0,
|
|
TRUE,
|
|
&event,
|
|
&iosb))) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
status = IoCallDriver(Target, irp);
|
|
Print(DBG_IOCTL_INFO,
|
|
("result of sending 0x%x was 0x%x\n",
|
|
Ioctl,
|
|
status
|
|
));
|
|
|
|
if (STATUS_PENDING == status) {
|
|
//
|
|
// wait for it...
|
|
//
|
|
status = KeWaitForSingleObject(&event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE, // Not alertable
|
|
NULL); // No timeout structure
|
|
|
|
ASSERT(STATUS_SUCCESS == status);
|
|
status = iosb.Status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
I8xInternalDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the dispatch routine for internal device control requests.
|
|
This routine cannot be paged because the class drivers send down internal
|
|
IOCTLs at DISPATCH_LEVEL.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
|
|
Irp - Pointer to the request packet.
|
|
|
|
Return Value:
|
|
|
|
Status is returned.
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpSp;
|
|
PPORT_MOUSE_EXTENSION mouseExtension = DeviceObject->DeviceExtension;
|
|
PPORT_KEYBOARD_EXTENSION kbExtension = DeviceObject->DeviceExtension;
|
|
|
|
NTSTATUS status;
|
|
PVOID parameters;
|
|
PKEYBOARD_ATTRIBUTES keyboardAttributes;
|
|
ULONG sizeOfTranslation;
|
|
|
|
PDEVICE_OBJECT topOfStack;
|
|
PINTERNAL_I8042_HOOK_KEYBOARD hookKeyboard;
|
|
PINTERNAL_I8042_HOOK_MOUSE hookMouse;
|
|
KEYBOARD_ID keyboardId;
|
|
|
|
Print(DBG_IOCTL_TRACE, ("IOCTL: enter\n"));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// Case on the device control subfunction that is being performed by the
|
|
// requestor.
|
|
//
|
|
switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
|
|
//
|
|
// Connect a keyboard class device driver to the port driver.
|
|
//
|
|
|
|
case IOCTL_INTERNAL_KEYBOARD_CONNECT:
|
|
//
|
|
// This really isn't something to worry about overall, but it is worthy
|
|
// enough to be noted and recorded. The multiple starts will be handled in
|
|
// I8xPnp and I8xKeyboardStartDevice routines
|
|
//
|
|
if (KEYBOARD_PRESENT()) {
|
|
Print(DBG_ALWAYS, ("Received 1+ kb connects!\n"));
|
|
SET_HW_FLAGS(DUP_KEYBOARD_HARDWARE_PRESENT);
|
|
}
|
|
|
|
InterlockedIncrement(&Globals.AddedKeyboards);
|
|
|
|
kbExtension->IsKeyboard = TRUE;
|
|
|
|
SET_HW_FLAGS(KEYBOARD_HARDWARE_PRESENT);
|
|
|
|
Print(DBG_IOCTL_INFO, ("IOCTL: keyboard connect\n"));
|
|
|
|
//
|
|
// Only allow a connection if the keyboard hardware is present.
|
|
// Also, only allow one connection.
|
|
//
|
|
if (kbExtension->ConnectData.ClassService != NULL) {
|
|
|
|
Print(DBG_IOCTL_ERROR, ("IOCTL: error - already connected\n"));
|
|
status = STATUS_SHARING_VIOLATION;
|
|
break;
|
|
}
|
|
else if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(CONNECT_DATA)) {
|
|
|
|
Print(DBG_IOCTL_ERROR, ("IOCTL: error - invalid buffer length\n"));
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Copy the connection parameters to the device extension.
|
|
//
|
|
|
|
kbExtension->ConnectData =
|
|
*((PCONNECT_DATA) (irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
|
|
|
|
hookKeyboard = ExAllocatePool(PagedPool,
|
|
sizeof(INTERNAL_I8042_HOOK_KEYBOARD)
|
|
);
|
|
if (hookKeyboard) {
|
|
topOfStack = IoGetAttachedDeviceReference(kbExtension->Self);
|
|
|
|
RtlZeroMemory(hookKeyboard,
|
|
sizeof(INTERNAL_I8042_HOOK_KEYBOARD)
|
|
);
|
|
|
|
hookKeyboard->CallContext = (PVOID) DeviceObject;
|
|
|
|
hookKeyboard->QueueKeyboardPacket = (PI8042_QUEUE_PACKET)
|
|
I8xQueueCurrentKeyboardInput;
|
|
|
|
hookKeyboard->IsrWritePort = (PI8042_ISR_WRITE_PORT)
|
|
I8xKeyboardIsrWritePort;
|
|
|
|
I8xSendIoctl(topOfStack,
|
|
IOCTL_INTERNAL_I8042_HOOK_KEYBOARD,
|
|
(PVOID) hookKeyboard,
|
|
sizeof(INTERNAL_I8042_HOOK_KEYBOARD)
|
|
);
|
|
|
|
ObDereferenceObject(topOfStack);
|
|
ExFreePool(hookKeyboard);
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
//
|
|
// Disconnect a keyboard class device driver from the port driver.
|
|
//
|
|
// NOTE: Not implemented.
|
|
//
|
|
case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
|
|
|
|
Print(DBG_IOCTL_INFO, ("IOCTL: keyboard disconnect\n"));
|
|
|
|
//
|
|
// Perform a keyboard interrupt disable call.
|
|
//
|
|
|
|
//
|
|
// Clear the connection parameters in the device extension.
|
|
// NOTE: Must synchronize this with the keyboard ISR.
|
|
//
|
|
//
|
|
//deviceExtension->KeyboardExtension.ConnectData.ClassDeviceObject =
|
|
// Null;
|
|
//deviceExtension->KeyboardExtension.ConnectData.ClassService =
|
|
// Null;
|
|
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:
|
|
|
|
Print(DBG_IOCTL_INFO, ("hook keyboard received!\n"));
|
|
|
|
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(INTERNAL_I8042_HOOK_KEYBOARD)) {
|
|
|
|
Print(DBG_IOCTL_ERROR,
|
|
("InternalIoctl error - invalid buffer length\n"
|
|
));
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else {
|
|
//
|
|
// Copy the values if they are filled in
|
|
//
|
|
hookKeyboard = (PINTERNAL_I8042_HOOK_KEYBOARD)
|
|
irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
|
|
kbExtension->HookContext = hookKeyboard->Context;
|
|
if (hookKeyboard->InitializationRoutine) {
|
|
Print(DBG_IOCTL_NOISE,
|
|
("KB Init Routine 0x%x\n",
|
|
hookKeyboard->IsrRoutine
|
|
));
|
|
kbExtension->InitializationHookCallback =
|
|
hookKeyboard->InitializationRoutine;
|
|
}
|
|
|
|
if (hookKeyboard->IsrRoutine) {
|
|
Print(DBG_IOCTL_NOISE,
|
|
("KB Hook Routine 0x%x\n",
|
|
hookKeyboard->IsrRoutine
|
|
));
|
|
kbExtension->IsrHookCallback = hookKeyboard->IsrRoutine;
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Connect a mouse class device driver to the port driver.
|
|
//
|
|
case IOCTL_INTERNAL_MOUSE_CONNECT:
|
|
|
|
//
|
|
// This really isn't something to worry about overall, but it is worthy
|
|
// enough to be noted and recorded. The multiple starts will be handled in
|
|
// I8xPnp and I8xMouseStartDevice routines
|
|
//
|
|
if (MOUSE_PRESENT()) {
|
|
Print(DBG_ALWAYS, ("Received 1+ mouse connects!\n"));
|
|
SET_HW_FLAGS(DUP_MOUSE_HARDWARE_PRESENT);
|
|
}
|
|
|
|
InterlockedIncrement(&Globals.AddedMice);
|
|
|
|
mouseExtension->IsKeyboard = FALSE;
|
|
|
|
SET_HW_FLAGS(MOUSE_HARDWARE_PRESENT);
|
|
|
|
Print(DBG_IOCTL_INFO, ("IOCTL: mouse connect\n"));
|
|
|
|
|
|
//
|
|
// Only allow a connection if the mouse hardware is present.
|
|
// Also, only allow one connection.
|
|
//
|
|
if (mouseExtension->ConnectData.ClassService != NULL) {
|
|
|
|
Print(DBG_IOCTL_ERROR, ("IOCTL: error - already connected\n"));
|
|
status = STATUS_SHARING_VIOLATION;
|
|
break;
|
|
}
|
|
else if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(CONNECT_DATA)) {
|
|
|
|
Print(DBG_IOCTL_ERROR, ("IOCTL: error - invalid buffer length\n"));
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Copy the connection parameters to the device extension.
|
|
//
|
|
mouseExtension->ConnectData =
|
|
*((PCONNECT_DATA) (irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
|
|
|
|
hookMouse = ExAllocatePool(PagedPool,
|
|
sizeof(INTERNAL_I8042_HOOK_MOUSE)
|
|
);
|
|
if (hookMouse) {
|
|
topOfStack = IoGetAttachedDeviceReference(mouseExtension->Self);
|
|
RtlZeroMemory(hookMouse,
|
|
sizeof(INTERNAL_I8042_HOOK_MOUSE)
|
|
);
|
|
|
|
hookMouse->CallContext = (PVOID) DeviceObject;
|
|
|
|
hookMouse->QueueMousePacket = (PI8042_QUEUE_PACKET)
|
|
I8xQueueCurrentMouseInput;
|
|
|
|
hookMouse->IsrWritePort = (PI8042_ISR_WRITE_PORT)
|
|
I8xMouseIsrWritePort;
|
|
|
|
I8xSendIoctl(topOfStack,
|
|
IOCTL_INTERNAL_I8042_HOOK_MOUSE,
|
|
(PVOID) hookMouse,
|
|
sizeof(INTERNAL_I8042_HOOK_MOUSE)
|
|
);
|
|
|
|
ObDereferenceObject(topOfStack);
|
|
ExFreePool(hookMouse);
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
//
|
|
// Disconnect a mouse class device driver from the port driver.
|
|
//
|
|
// NOTE: Not implemented.
|
|
//
|
|
case IOCTL_INTERNAL_MOUSE_DISCONNECT:
|
|
|
|
Print(DBG_IOCTL_INFO, ("IOCTL: mouse disconnect\n"));
|
|
|
|
//
|
|
// Perform a mouse interrupt disable call.
|
|
//
|
|
|
|
//
|
|
// Clear the connection parameters in the device extension.
|
|
// NOTE: Must synchronize this with the mouse ISR.
|
|
//
|
|
//
|
|
//deviceExtension->MouseExtension.ConnectData.ClassDeviceObject =
|
|
// Null;
|
|
//deviceExtension->MouseExtension.ConnectData.ClassService =
|
|
// Null;
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case IOCTL_INTERNAL_I8042_HOOK_MOUSE:
|
|
|
|
Print(DBG_IOCTL_INFO, ("hook mouse received!\n"));
|
|
|
|
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(INTERNAL_I8042_HOOK_MOUSE)) {
|
|
|
|
Print(DBG_IOCTL_ERROR,
|
|
("InternalIoctl error - invalid buffer length\n"
|
|
));
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else {
|
|
//
|
|
// Copy the values if they are filled in
|
|
//
|
|
hookMouse = (PINTERNAL_I8042_HOOK_MOUSE)
|
|
irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
|
|
mouseExtension->HookContext = hookMouse->Context;
|
|
if (hookMouse->IsrRoutine) {
|
|
Print(DBG_IOCTL_NOISE,
|
|
("Mou Hook Routine 0x%x\n",
|
|
hookMouse->IsrRoutine
|
|
));
|
|
mouseExtension->IsrHookCallback = hookMouse->IsrRoutine;
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Query the keyboard attributes. First check for adequate buffer
|
|
// length. Then, copy the keyboard attributes from the device
|
|
// extension to the output buffer.
|
|
//
|
|
case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
|
|
|
|
Print(DBG_IOCTL_NOISE, ("IOCTL: keyboard query attributes\n"));
|
|
|
|
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(KEYBOARD_ATTRIBUTES)) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else {
|
|
//
|
|
// Copy the attributes from the DeviceExtension to the
|
|
// buffer.
|
|
//
|
|
*(PKEYBOARD_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer =
|
|
kbExtension->KeyboardAttributes;
|
|
|
|
Irp->IoStatus.Information = sizeof(KEYBOARD_ATTRIBUTES);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// Query the scan code to indicator-light mapping. Validate the
|
|
// parameters, and copy the indicator mapping information from
|
|
// the port device extension to the SystemBuffer.
|
|
//
|
|
case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION: {
|
|
|
|
PKEYBOARD_INDICATOR_TRANSLATION translation;
|
|
|
|
ASSERT(kbExtension->IsKeyboard);
|
|
|
|
Print(DBG_IOCTL_NOISE, ("IOCTL: keyboard query indicator translation\n"));
|
|
|
|
sizeOfTranslation = sizeof(KEYBOARD_INDICATOR_TRANSLATION)
|
|
+ (sizeof(INDICATOR_LIST)
|
|
* (kbExtension->KeyboardAttributes.NumberOfIndicators - 1));
|
|
|
|
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeOfTranslation) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else {
|
|
//
|
|
// Copy the indicator mapping information to the system
|
|
// buffer.
|
|
//
|
|
|
|
translation = (PKEYBOARD_INDICATOR_TRANSLATION)
|
|
Irp->AssociatedIrp.SystemBuffer;
|
|
translation->NumberOfIndicatorKeys =
|
|
kbExtension->KeyboardAttributes.NumberOfIndicators;
|
|
|
|
RtlMoveMemory(
|
|
translation->IndicatorList,
|
|
(PCHAR) IndicatorList,
|
|
sizeof(INDICATOR_LIST) * translation->NumberOfIndicatorKeys
|
|
);
|
|
|
|
Irp->IoStatus.Information = sizeOfTranslation;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Query the keyboard indicators. Validate the parameters, and
|
|
// copy the indicator information from the port device extension to
|
|
// the SystemBuffer.
|
|
//
|
|
case IOCTL_KEYBOARD_QUERY_INDICATORS:
|
|
|
|
ASSERT(kbExtension->IsKeyboard);
|
|
|
|
Print(DBG_IOCTL_NOISE, ("IOCTL: keyboard query indicators\n"));
|
|
|
|
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else {
|
|
//
|
|
// Don't bother to synchronize access to the DeviceExtension
|
|
// KeyboardIndicators field while copying it. We don't
|
|
// really care if another process is setting the LEDs via
|
|
// StartIo running on another processor.
|
|
//
|
|
*(PKEYBOARD_INDICATOR_PARAMETERS) Irp->AssociatedIrp.SystemBuffer =
|
|
kbExtension->KeyboardIndicators;
|
|
#if defined(FE_SB)
|
|
keyboardId = kbExtension->KeyboardAttributes.KeyboardIdentifier;
|
|
if (DEC_KANJI_KEYBOARD(keyboardId)) {
|
|
//
|
|
// DEC LK411 keyboard does not have LED for NumLock,
|
|
// but the bit is used for KanaLock.
|
|
//
|
|
if (((PKEYBOARD_INDICATOR_PARAMETERS)
|
|
Irp->AssociatedIrp.SystemBuffer)->LedFlags & KEYBOARD_NUM_LOCK_ON) {
|
|
//
|
|
// KEYBOARD_KANA_LOCK_ON is mapped to KEYBOARD_NUM_LOCK_ON
|
|
//
|
|
((PKEYBOARD_INDICATOR_PARAMETERS)
|
|
Irp->AssociatedIrp.SystemBuffer)->LedFlags |= KEYBOARD_KANA_LOCK_ON;
|
|
((PKEYBOARD_INDICATOR_PARAMETERS)
|
|
Irp->AssociatedIrp.SystemBuffer)->LedFlags &= ~(KEYBOARD_NUM_LOCK_ON);
|
|
}
|
|
}
|
|
#endif
|
|
Irp->IoStatus.Information = sizeof(KEYBOARD_INDICATOR_PARAMETERS);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// Set the keyboard indicators (validate the parameters, mark the
|
|
// request pending, and handle it in StartIo).
|
|
//
|
|
case IOCTL_KEYBOARD_SET_INDICATORS:
|
|
|
|
if (!kbExtension->InterruptObject) {
|
|
status = STATUS_DEVICE_NOT_READY;
|
|
break;
|
|
}
|
|
|
|
if (kbExtension->PowerState != PowerDeviceD0) {
|
|
status = STATUS_POWER_STATE_INVALID;
|
|
break;
|
|
}
|
|
|
|
Print(DBG_IOCTL_NOISE, ("IOCTL: keyboard set indicators\n"));
|
|
|
|
#ifdef FE_SB // I8042InternalDeviceControl()
|
|
//
|
|
// Katakana keyboard indicator support on AX Japanese keyboard
|
|
//
|
|
if ((irpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(KEYBOARD_INDICATOR_PARAMETERS)) ||
|
|
((((PKEYBOARD_INDICATOR_PARAMETERS)
|
|
Irp->AssociatedIrp.SystemBuffer)->LedFlags
|
|
& ~(KEYBOARD_SCROLL_LOCK_ON
|
|
| KEYBOARD_NUM_LOCK_ON | KEYBOARD_CAPS_LOCK_ON
|
|
| KEYBOARD_KANA_LOCK_ON)) != 0)) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else {
|
|
keyboardId = kbExtension->KeyboardAttributes.KeyboardIdentifier;
|
|
if (DEC_KANJI_KEYBOARD(keyboardId)) {
|
|
//
|
|
// DEC LK411 keyboard does not have LED for NumLock,
|
|
// but the bit is used for KanaLock.
|
|
//
|
|
if (((PKEYBOARD_INDICATOR_PARAMETERS)
|
|
Irp->AssociatedIrp.SystemBuffer)->LedFlags & KEYBOARD_KANA_LOCK_ON) {
|
|
//
|
|
// KEYBOARD_KANA_LOCK_ON is mapped to KEYBOARD_NUM_LOCK_ON
|
|
//
|
|
((PKEYBOARD_INDICATOR_PARAMETERS)
|
|
Irp->AssociatedIrp.SystemBuffer)->LedFlags |= KEYBOARD_NUM_LOCK_ON;
|
|
((PKEYBOARD_INDICATOR_PARAMETERS)
|
|
Irp->AssociatedIrp.SystemBuffer)->LedFlags &= ~(KEYBOARD_KANA_LOCK_ON);
|
|
}
|
|
else {
|
|
//
|
|
// Ignore NumLock. (There is no LED for NumLock)
|
|
//
|
|
((PKEYBOARD_INDICATOR_PARAMETERS)
|
|
Irp->AssociatedIrp.SystemBuffer)->LedFlags &= ~(KEYBOARD_NUM_LOCK_ON);
|
|
}
|
|
}
|
|
else if (! AX_KEYBOARD(keyboardId) &&
|
|
(((PKEYBOARD_INDICATOR_PARAMETERS)
|
|
Irp->AssociatedIrp.SystemBuffer)->LedFlags
|
|
& KEYBOARD_KANA_LOCK_ON)) {
|
|
//
|
|
// If this is not AX keyboard, the keyboard dose
|
|
// have 'kana' LED, then just turn off the bit.
|
|
//
|
|
((PKEYBOARD_INDICATOR_PARAMETERS)
|
|
Irp->AssociatedIrp.SystemBuffer)->LedFlags &=
|
|
~(KEYBOARD_KANA_LOCK_ON);
|
|
}
|
|
status = STATUS_PENDING;
|
|
}
|
|
#else
|
|
if ((irpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(KEYBOARD_INDICATOR_PARAMETERS)) ||
|
|
((((PKEYBOARD_INDICATOR_PARAMETERS)
|
|
Irp->AssociatedIrp.SystemBuffer)->LedFlags
|
|
& ~(KEYBOARD_SCROLL_LOCK_ON
|
|
| KEYBOARD_NUM_LOCK_ON | KEYBOARD_CAPS_LOCK_ON)) != 0)) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else {
|
|
status = STATUS_PENDING;
|
|
}
|
|
#endif // FE_SB
|
|
|
|
break;
|
|
|
|
//
|
|
// Query the current keyboard typematic rate and delay. Validate
|
|
// the parameters, and copy the typematic information from the port
|
|
// device extension to the SystemBuffer.
|
|
//
|
|
case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
|
|
|
|
Print(DBG_IOCTL_NOISE, ("IOCTL: keyboard query typematic\n"));
|
|
|
|
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else {
|
|
//
|
|
// Don't bother to synchronize access to the DeviceExtension
|
|
// KeyRepeatCurrent field while copying it. We don't
|
|
// really care if another process is setting the typematic
|
|
// rate/delay via StartIo running on another processor.
|
|
//
|
|
|
|
*(PKEYBOARD_TYPEMATIC_PARAMETERS) Irp->AssociatedIrp.SystemBuffer =
|
|
kbExtension->KeyRepeatCurrent;
|
|
Irp->IoStatus.Information = sizeof(KEYBOARD_TYPEMATIC_PARAMETERS);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// Set the keyboard typematic rate and delay (validate the parameters,
|
|
// mark the request pending, and handle it in StartIo).
|
|
//
|
|
case IOCTL_KEYBOARD_SET_TYPEMATIC:
|
|
|
|
if (!kbExtension->InterruptObject) {
|
|
status = STATUS_DEVICE_NOT_READY;
|
|
break;
|
|
}
|
|
|
|
if (kbExtension->PowerState != PowerDeviceD0) {
|
|
status = STATUS_POWER_STATE_INVALID;
|
|
break;
|
|
}
|
|
|
|
Print(DBG_IOCTL_NOISE, ("IOCTL: keyboard set typematic\n"));
|
|
|
|
parameters = Irp->AssociatedIrp.SystemBuffer;
|
|
keyboardAttributes = &kbExtension->KeyboardAttributes;
|
|
|
|
if ((irpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) ||
|
|
(((PKEYBOARD_TYPEMATIC_PARAMETERS) parameters)->Rate <
|
|
keyboardAttributes->KeyRepeatMinimum.Rate) ||
|
|
(((PKEYBOARD_TYPEMATIC_PARAMETERS) parameters)->Rate >
|
|
keyboardAttributes->KeyRepeatMaximum.Rate) ||
|
|
(((PKEYBOARD_TYPEMATIC_PARAMETERS) parameters)->Delay <
|
|
keyboardAttributes->KeyRepeatMinimum.Delay) ||
|
|
(((PKEYBOARD_TYPEMATIC_PARAMETERS) parameters)->Delay >
|
|
keyboardAttributes->KeyRepeatMaximum.Delay)) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else {
|
|
status = STATUS_PENDING;
|
|
}
|
|
|
|
break;
|
|
|
|
#if defined(_X86_)
|
|
|
|
case IOCTL_KEYBOARD_SET_IME_STATUS:
|
|
|
|
Print(DBG_IOCTL_NOISE, ("IOCTL: keyboard set ime status\n"));
|
|
|
|
if (!kbExtension->InterruptObject) {
|
|
status = STATUS_DEVICE_NOT_READY;
|
|
break;
|
|
}
|
|
|
|
if (kbExtension->PowerState != PowerDeviceD0) {
|
|
status = STATUS_POWER_STATE_INVALID;
|
|
break;
|
|
}
|
|
|
|
keyboardId = kbExtension->KeyboardAttributes.KeyboardIdentifier;
|
|
if (!OYAYUBI_KEYBOARD(keyboardId)) {
|
|
//
|
|
// This ioctl supported on 'Fujitsu oyayubi' keyboard only...
|
|
//
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
else {
|
|
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(KEYBOARD_IME_STATUS)) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else {
|
|
ULONG InternalMode;
|
|
|
|
parameters = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
InternalMode = I8042QueryIMEStatusForOasys(
|
|
(PKEYBOARD_IME_STATUS)parameters
|
|
);
|
|
|
|
if ((InternalMode <= 0) || (InternalMode > 8)) {
|
|
//
|
|
// IME mode could not translate to hardware mode.
|
|
//
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else {
|
|
status = STATUS_PENDING;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
|
//
|
|
// Query the mouse attributes. First check for adequate buffer
|
|
// length. Then, copy the mouse attributes from the device
|
|
// extension to the output buffer.
|
|
//
|
|
case IOCTL_MOUSE_QUERY_ATTRIBUTES:
|
|
|
|
Print(DBG_IOCTL_NOISE, ("IOCTL: mouse query attributes\n"));
|
|
|
|
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(MOUSE_ATTRIBUTES)) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else {
|
|
//
|
|
// Copy the attributes from the DeviceExtension to the
|
|
// buffer.
|
|
//
|
|
*(PMOUSE_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer =
|
|
mouseExtension->MouseAttributes;
|
|
|
|
Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
|
|
case IOCTL_INTERNAL_I8042_KEYBOARD_START_INFORMATION:
|
|
case IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION:
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
|
|
case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
|
|
if (!mouseExtension->InterruptObject) {
|
|
status = STATUS_DEVICE_NOT_READY;
|
|
break;
|
|
}
|
|
|
|
if (mouseExtension->PowerState != PowerDeviceD0) {
|
|
status = STATUS_POWER_STATE_INVALID;
|
|
break;
|
|
}
|
|
|
|
Print(DBG_IOCTL_NOISE, ("IOCTL: mouse send buffer\n"));
|
|
|
|
if (irpSp->Parameters.DeviceIoControl.InputBufferLength < 1 ||
|
|
!irpSp->Parameters.DeviceIoControl.Type3InputBuffer) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else {
|
|
status = STATUS_PENDING;
|
|
}
|
|
break;
|
|
|
|
case IOCTL_INTERNAL_I8042_CONTROLLER_WRITE_BUFFER:
|
|
|
|
if (!kbExtension->IsKeyboard) {
|
|
//
|
|
// This should only be sent down the kb stack
|
|
//
|
|
Print(DBG_ALWAYS, ("Send this request down the kb stack!!!\n"));
|
|
ASSERT(FALSE);
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
else {
|
|
//
|
|
// We currently do not support this IOCTL
|
|
//
|
|
status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
Print(DBG_IOCTL_ERROR, ("IOCTL: INVALID REQUEST\n"));
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
if (status == STATUS_PENDING) {
|
|
Print(DBG_IOCTL_NOISE, ("Acquiring tag %p on remlock %p\n",
|
|
Irp,
|
|
&GET_COMMON_DATA(DeviceObject->DeviceExtension)->RemoveLock));
|
|
|
|
status = IoAcquireRemoveLock(
|
|
&GET_COMMON_DATA(DeviceObject->DeviceExtension)->RemoveLock,
|
|
Irp
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
else {
|
|
status = STATUS_PENDING;
|
|
IoMarkIrpPending(Irp);
|
|
IoStartPacket(DeviceObject,
|
|
Irp,
|
|
(PULONG) NULL,
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
else {
|
|
IoCompleteRequest(Irp,
|
|
IO_NO_INCREMENT
|
|
);
|
|
}
|
|
|
|
Print(DBG_IOCTL_TRACE, ("IOCTL: exit (0x%x)\n", status));
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
I8042RetriesExceededDpc(
|
|
IN PKDPC Dpc,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine runs at DISPATCH_LEVEL IRQL to complete requests that
|
|
have exceeded the maximum number of retries. It is queued in the
|
|
keyboard ISR.
|
|
|
|
Arguments:
|
|
|
|
Dpc - Pointer to the DPC object.
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
|
|
Irp - Pointer to the Irp.
|
|
|
|
Context - Not used.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PCOMMON_DATA commonData;
|
|
PIO_ERROR_LOG_PACKET errorLogEntry;
|
|
PIO_STACK_LOCATION irpSp;
|
|
ULONG i;
|
|
|
|
UNREFERENCED_PARAMETER(Dpc);
|
|
UNREFERENCED_PARAMETER(Context);
|
|
|
|
Print(DBG_DPC_TRACE, ("I8042RetriesExceededDpc: enter\n"));
|
|
|
|
commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
|
|
|
|
//
|
|
// Set the completion status.
|
|
//
|
|
Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
|
|
|
|
if(Globals.ReportResetErrors == TRUE)
|
|
{
|
|
//
|
|
// Log an error.
|
|
//
|
|
errorLogEntry = (PIO_ERROR_LOG_PACKET)
|
|
IoAllocateErrorLogEntry(DeviceObject,
|
|
(UCHAR) (sizeof(IO_ERROR_LOG_PACKET) +
|
|
commonData->CurrentOutput.ByteCount *
|
|
sizeof(ULONG))
|
|
);
|
|
|
|
KeAcquireSpinLockAtDpcLevel(&Globals.ControllerData->BytesSpinLock);
|
|
|
|
if (errorLogEntry != NULL) {
|
|
|
|
errorLogEntry->ErrorCode = commonData->IsKeyboard ?
|
|
I8042_RETRIES_EXCEEDED_KBD :
|
|
I8042_RETRIES_EXCEEDED_MOU;
|
|
|
|
errorLogEntry->DumpDataSize = (USHORT)
|
|
commonData->CurrentOutput.ByteCount * sizeof(ULONG);
|
|
errorLogEntry->SequenceNumber = commonData->SequenceNumber;
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
errorLogEntry->MajorFunctionCode = irpSp->MajorFunction;
|
|
errorLogEntry->IoControlCode =
|
|
irpSp->Parameters.DeviceIoControl.IoControlCode;
|
|
errorLogEntry->RetryCount = (UCHAR) commonData->ResendCount;
|
|
errorLogEntry->UniqueErrorValue = I8042_ERROR_VALUE_BASE + 210;
|
|
errorLogEntry->FinalStatus = Irp->IoStatus.Status;
|
|
|
|
if (commonData->CurrentOutput.Bytes) {
|
|
for (i = 0; i < commonData->CurrentOutput.ByteCount; i++) {
|
|
errorLogEntry->DumpData[i] = commonData->CurrentOutput.Bytes[i];
|
|
}
|
|
}
|
|
|
|
IoWriteErrorLogEntry(errorLogEntry);
|
|
}
|
|
}
|
|
else{
|
|
KeAcquireSpinLockAtDpcLevel(&Globals.ControllerData->BytesSpinLock);
|
|
}
|
|
|
|
if (commonData->CurrentOutput.Bytes &&
|
|
commonData->CurrentOutput.Bytes != Globals.ControllerData->DefaultBuffer) {
|
|
ExFreePool(commonData->CurrentOutput.Bytes);
|
|
}
|
|
commonData->CurrentOutput.Bytes = NULL;
|
|
KeReleaseSpinLockFromDpcLevel(&Globals.ControllerData->BytesSpinLock);
|
|
|
|
I8xCompletePendedRequest(DeviceObject, Irp, 0, STATUS_IO_TIMEOUT);
|
|
|
|
Print(DBG_DPC_TRACE, ("I8042RetriesExceededDpc: exit\n"));
|
|
}
|
|
|
|
VOID
|
|
I8xStartIo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine starts an I/O operation for the device which is further
|
|
controlled by the controller object
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
|
|
Irp - Pointer to the request packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
KIRQL cancelIrql;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PCOMMON_DATA common;
|
|
|
|
Print(DBG_IOCTL_TRACE, ("I8042StartIo: enter\n"));
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
switch(irpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
|
|
case IOCTL_KEYBOARD_SET_INDICATORS:
|
|
case IOCTL_KEYBOARD_SET_TYPEMATIC:
|
|
#if defined(_X86_)
|
|
case IOCTL_KEYBOARD_SET_IME_STATUS:
|
|
#endif
|
|
case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
|
|
case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
|
|
case IOCTL_INTERNAL_MOUSE_RESET:
|
|
IoAllocateController(Globals.ControllerData->ControllerObject,
|
|
DeviceObject,
|
|
I8xControllerRoutine,
|
|
NULL
|
|
);
|
|
break;
|
|
|
|
default:
|
|
|
|
Print(DBG_IOCTL_ERROR, ("I8042StartIo: INVALID REQUEST\n"));
|
|
|
|
//
|
|
// Log an internal error. Note that we're calling the
|
|
// error log DPC routine directly, rather than duplicating
|
|
// code.
|
|
//
|
|
common = GET_COMMON_DATA(DeviceObject->DeviceExtension);
|
|
I8042ErrorLogDpc((PKDPC) NULL,
|
|
DeviceObject,
|
|
Irp,
|
|
LongToPtr(common->IsKeyboard ?
|
|
I8042_INVALID_STARTIO_REQUEST_KBD :
|
|
I8042_INVALID_STARTIO_REQUEST_MOU)
|
|
);
|
|
|
|
IoAcquireCancelSpinLock(&cancelIrql);
|
|
IoSetCancelRoutine(Irp, NULL);
|
|
IoReleaseCancelSpinLock(cancelIrql);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
IoStartNextPacket(DeviceObject, FALSE);
|
|
|
|
//
|
|
// Release the lock we acquired when we started the packet
|
|
//
|
|
IoReleaseRemoveLock(&common->RemoveLock, Irp);
|
|
}
|
|
|
|
Print(DBG_IOCTL_TRACE, ("I8042StartIo: exit\n"));
|
|
}
|
|
|
|
IO_ALLOCATION_ACTION
|
|
I8xControllerRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID MapRegisterBase,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine synchronously writes the first byte to the intended device and
|
|
fires off a timer to assure the write took place.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The device object for which the write is meant for
|
|
|
|
Irp - Pointer to the request packet.
|
|
|
|
MapRegisterBase - Unused
|
|
|
|
Context - Unused
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PCOMMON_DATA commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
|
|
PPORT_KEYBOARD_EXTENSION kbExtension = DeviceObject->DeviceExtension;
|
|
PPORT_MOUSE_EXTENSION mouseExtension = DeviceObject->DeviceExtension;
|
|
|
|
KIRQL cancelIrql;
|
|
PIO_STACK_LOCATION irpSp;
|
|
INITIATE_OUTPUT_CONTEXT ic;
|
|
LARGE_INTEGER deltaTime;
|
|
LONG interlockedResult;
|
|
ULONG bufferLen;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
KEYBOARD_ID keyboardId;
|
|
|
|
commonData->SequenceNumber += 1;
|
|
|
|
UNREFERENCED_PARAMETER(MapRegisterBase);
|
|
UNREFERENCED_PARAMETER(Context);
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
#if DBG
|
|
Globals.ControllerData->CurrentIoControlCode =
|
|
irpSp->Parameters.DeviceIoControl.IoControlCode;
|
|
#endif
|
|
|
|
switch(irpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
|
|
//
|
|
// Set the keyboard indicators to the desired state.
|
|
//
|
|
case IOCTL_KEYBOARD_SET_INDICATORS:
|
|
|
|
Print(DBG_IOCTL_NOISE, ("I8xControllerRoutine: keyboard set indicators\n"));
|
|
|
|
if (kbExtension->KeyboardIndicators.LedFlags ==
|
|
((PKEYBOARD_INDICATOR_PARAMETERS)
|
|
Irp->AssociatedIrp.SystemBuffer)->LedFlags) {
|
|
|
|
ASSERT(Irp->CancelRoutine == NULL);
|
|
|
|
I8xCompletePendedRequest(DeviceObject,
|
|
Irp,
|
|
0,
|
|
STATUS_SUCCESS
|
|
);
|
|
|
|
//
|
|
// Tell the controller processing routine to stop processing packets
|
|
// because we called IoFreeController ourselves.
|
|
//
|
|
return KeepObject;
|
|
}
|
|
|
|
ic.Bytes = Globals.ControllerData->DefaultBuffer;
|
|
|
|
//
|
|
// Set up the context structure for the InitiateIo wrapper.
|
|
//
|
|
ic.DeviceObject = DeviceObject;
|
|
ic.ByteCount = 2;
|
|
ic.Bytes[0] = SET_KEYBOARD_INDICATORS;
|
|
ic.Bytes[1] = (UCHAR) ((PKEYBOARD_INDICATOR_PARAMETERS)
|
|
Irp->AssociatedIrp.SystemBuffer)->LedFlags;
|
|
|
|
break;
|
|
|
|
//
|
|
// Set the keyboard typematic rate and delay.
|
|
//
|
|
case IOCTL_KEYBOARD_SET_TYPEMATIC:
|
|
|
|
Print(DBG_IOCTL_NOISE, ("I8xControllerRoutine: keyboard set typematic\n"));
|
|
|
|
ic.Bytes = Globals.ControllerData->DefaultBuffer;
|
|
|
|
//
|
|
// Set up the context structure for the InitiateIo wrapper.
|
|
//
|
|
ic.DeviceObject = DeviceObject;
|
|
ic.ByteCount = 2;
|
|
ic.Bytes[0] = SET_KEYBOARD_TYPEMATIC;
|
|
ic.Bytes[1] =
|
|
I8xConvertTypematicParameters(
|
|
((PKEYBOARD_TYPEMATIC_PARAMETERS)
|
|
Irp->AssociatedIrp.SystemBuffer)->Rate,
|
|
((PKEYBOARD_TYPEMATIC_PARAMETERS)
|
|
Irp->AssociatedIrp.SystemBuffer)->Delay
|
|
);
|
|
break;
|
|
|
|
case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER: // Write data to the mouse
|
|
case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER: // Write data to the kb
|
|
|
|
#if DBG
|
|
if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
|
|
IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER) {
|
|
Print(DBG_IOCTL_NOISE, ("I8xControllerRoutine: mou write buffer\n"));
|
|
}
|
|
else {
|
|
Print(DBG_IOCTL_NOISE, ("I8xControllerRoutine: kb write buffer\n"));
|
|
}
|
|
#endif
|
|
|
|
bufferLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
if (bufferLen <= 4) {
|
|
ic.Bytes = Globals.ControllerData->DefaultBuffer;
|
|
}
|
|
else {
|
|
ic.Bytes = ExAllocatePool(NonPagedPool, bufferLen);
|
|
if (!ic.Bytes) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto ControllerRequestError;
|
|
}
|
|
}
|
|
|
|
ic.DeviceObject = DeviceObject;
|
|
RtlCopyMemory(ic.Bytes,
|
|
irpSp->Parameters.DeviceIoControl.Type3InputBuffer,
|
|
bufferLen);
|
|
ic.ByteCount = bufferLen;
|
|
|
|
break;
|
|
|
|
#if defined(_X86_)
|
|
case IOCTL_KEYBOARD_SET_IME_STATUS:
|
|
|
|
Print(DBG_IOCTL_NOISE, ("I8xControllerRoutine: keyboard set ime status\n"));
|
|
|
|
keyboardId = kbExtension->KeyboardAttributes.KeyboardIdentifier;
|
|
if (OYAYUBI_KEYBOARD(keyboardId)) {
|
|
status = I8042SetIMEStatusForOasys(DeviceObject,
|
|
Irp,
|
|
&ic);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto ControllerRequestError;
|
|
}
|
|
}
|
|
else {
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto ControllerRequestError;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case IOCTL_INTERNAL_MOUSE_RESET:
|
|
Print(DBG_IOCTL_NOISE, ("I8xControllerRoutine: internal reset mouse\n"));
|
|
I8xSendResetCommand(mouseExtension);
|
|
return KeepObject;
|
|
|
|
default:
|
|
Print(DBG_IOCTL_ERROR, ("I8xContollerRoutine: INVALID REQUEST\n"));
|
|
ASSERT(FALSE);
|
|
|
|
ControllerRequestError:
|
|
IoAcquireCancelSpinLock(&cancelIrql);
|
|
IoSetCancelRoutine(Irp, NULL);
|
|
IoReleaseCancelSpinLock(cancelIrql);
|
|
|
|
I8xCompletePendedRequest(DeviceObject, Irp, 0, status);
|
|
|
|
//
|
|
// Since we called IoFreeController already, tell the controller object
|
|
// routine to stop processing packets
|
|
//
|
|
return KeepObject;
|
|
}
|
|
|
|
KeSynchronizeExecution(
|
|
commonData->InterruptObject,
|
|
(PKSYNCHRONIZE_ROUTINE) I8xInitiateOutputWrapper,
|
|
(PVOID) &ic
|
|
);
|
|
|
|
deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
|
|
deltaTime.HighPart = -1;
|
|
|
|
KeSetTimer(&Globals.ControllerData->CommandTimer,
|
|
deltaTime,
|
|
&commonData->TimeOutDpc
|
|
);
|
|
|
|
return KeepObject;
|
|
}
|
|
|
|
VOID
|
|
I8xCompletePendedRequest(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp,
|
|
ULONG_PTR Information,
|
|
NTSTATUS Status
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION stack;
|
|
PCOMMON_DATA common;
|
|
|
|
stack = IoGetCurrentIrpStackLocation(Irp);
|
|
common = GET_COMMON_DATA(DeviceObject->DeviceExtension);
|
|
|
|
Irp->IoStatus.Information = Information;
|
|
Irp->IoStatus.Status = Status;
|
|
|
|
ASSERT(IOCTL_INTERNAL_MOUSE_RESET !=
|
|
IoGetCurrentIrpStackLocation(Irp)->
|
|
Parameters.DeviceIoControl.IoControlCode);
|
|
Print(DBG_IOCTL_INFO,
|
|
("Completing IOCTL irp %p, code 0x%x, status 0x%x\n",
|
|
Irp, stack->Parameters.DeviceIoControl.IoControlCode, Status));
|
|
ASSERT(stack->Control & SL_PENDING_RETURNED);
|
|
IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
|
|
|
|
//
|
|
// Start the next packet and complete the request.
|
|
//
|
|
// Order is important! If IoStartNextPacket is called first, then
|
|
// (potentially) the same device object will be enqueued twice on
|
|
// the controller object which will cause corruption in the
|
|
// controller object's list of allocated routines
|
|
//
|
|
IoFreeController(Globals.ControllerData->ControllerObject);
|
|
IoStartNextPacket(DeviceObject, FALSE);
|
|
|
|
//
|
|
// Release the lock we acquired in start io. Release this last so
|
|
// that lifetime is guaranteed for IoFreeController and IoStart
|
|
//
|
|
IoReleaseRemoveLock(&common->RemoveLock, Irp);
|
|
}
|
|
|
|
VOID
|
|
I8042TimeOutDpc(
|
|
IN PKDPC Dpc,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID SystemContext1,
|
|
IN PVOID SystemContext2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the driver's command timeout routine. It is called when the
|
|
command timer fires.
|
|
|
|
Arguments:
|
|
|
|
Dpc - Not Used.
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
|
|
SystemContext1 - Not Used.
|
|
|
|
SystemContext2 - Not Used.
|
|
|
|
Return Value:
|
|
|
|
None. As a side-effect, the timeout counter is updated and an error
|
|
is logged.
|
|
|
|
--*/
|
|
{
|
|
PCOMMON_DATA commonData;
|
|
KIRQL cancelIrql;
|
|
TIMER_CONTEXT timerContext;
|
|
PIRP irp;
|
|
PIO_ERROR_LOG_PACKET errorLogEntry;
|
|
PIO_STACK_LOCATION irpSp;
|
|
LARGE_INTEGER deltaTime;
|
|
ULONG i;
|
|
|
|
Print(DBG_DPC_TRACE, ("I8042TimeOutDpc: enter\n"));
|
|
|
|
//
|
|
// Get the device extension.
|
|
//
|
|
commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
|
|
|
|
//
|
|
// Acquire the cancel spinlock, verify that the CurrentIrp has not been
|
|
// cancelled (i.e., CurrentIrp != NULL), set the cancel routine to NULL,
|
|
// and release the cancel spinlock.
|
|
//
|
|
IoAcquireCancelSpinLock(&cancelIrql);
|
|
irp = DeviceObject->CurrentIrp;
|
|
if (irp == NULL) {
|
|
IoReleaseCancelSpinLock(cancelIrql);
|
|
Print(DBG_DPC_TRACE, ("I8042RetriesExceededDpc: exit (NULL irp)\n"));
|
|
return;
|
|
}
|
|
IoSetCancelRoutine(irp, NULL);
|
|
IoReleaseCancelSpinLock(cancelIrql);
|
|
|
|
//
|
|
// If the TimerCounter == 0 on entry to this routine, the last packet
|
|
// timed out and was completed. We just decrement TimerCounter
|
|
// (synchronously) to indicate that we're no longer timing.
|
|
//
|
|
// If the TimerCounter indicates no timeout (I8042_ASYNC_NO_TIMEOUT)
|
|
// on entry to this routine, there is no command being timed.
|
|
//
|
|
|
|
timerContext.DeviceObject = DeviceObject;
|
|
timerContext.TimerCounter = &Globals.ControllerData->TimerCount;
|
|
|
|
KeSynchronizeExecution(
|
|
commonData->InterruptObject,
|
|
(PKSYNCHRONIZE_ROUTINE) I8xDecrementTimer,
|
|
&timerContext
|
|
);
|
|
|
|
if (timerContext.NewTimerCount == 0) {
|
|
|
|
//
|
|
// Set up the IO Status Block prior to completing the request.
|
|
//
|
|
irp->IoStatus.Information = 0;
|
|
irp->IoStatus.Status = STATUS_IO_TIMEOUT;
|
|
|
|
if(Globals.ReportResetErrors == TRUE)
|
|
{
|
|
//
|
|
// Log a timeout error.
|
|
//
|
|
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
|
|
DeviceObject,
|
|
(UCHAR) (sizeof(IO_ERROR_LOG_PACKET) +
|
|
commonData->CurrentOutput.ByteCount * sizeof(ULONG))
|
|
);
|
|
|
|
KeAcquireSpinLockAtDpcLevel(&Globals.ControllerData->BytesSpinLock);
|
|
|
|
if (errorLogEntry != NULL) {
|
|
|
|
errorLogEntry->ErrorCode = commonData->IsKeyboard ?
|
|
I8042_TIMEOUT_KBD :
|
|
I8042_TIMEOUT_MOU;
|
|
errorLogEntry->DumpDataSize = (USHORT)
|
|
commonData->CurrentOutput.ByteCount * sizeof(ULONG);
|
|
errorLogEntry->SequenceNumber = commonData->SequenceNumber;
|
|
irpSp = IoGetCurrentIrpStackLocation(irp);
|
|
errorLogEntry->MajorFunctionCode = irpSp->MajorFunction;
|
|
errorLogEntry->IoControlCode =
|
|
irpSp->Parameters.DeviceIoControl.IoControlCode;
|
|
errorLogEntry->RetryCount = (UCHAR) commonData->ResendCount;
|
|
errorLogEntry->UniqueErrorValue = 90;
|
|
errorLogEntry->FinalStatus = STATUS_IO_TIMEOUT;
|
|
|
|
if (commonData->CurrentOutput.Bytes) {
|
|
for (i = 0; i < commonData->CurrentOutput.ByteCount; i++) {
|
|
errorLogEntry->DumpData[i] = commonData->CurrentOutput.Bytes[i];
|
|
}
|
|
}
|
|
|
|
IoWriteErrorLogEntry(errorLogEntry);
|
|
}
|
|
}
|
|
else{
|
|
KeAcquireSpinLockAtDpcLevel(&Globals.ControllerData->BytesSpinLock);
|
|
}
|
|
|
|
if (commonData->CurrentOutput.Bytes &&
|
|
commonData->CurrentOutput.Bytes != Globals.ControllerData->DefaultBuffer) {
|
|
ExFreePool(commonData->CurrentOutput.Bytes);
|
|
}
|
|
commonData->CurrentOutput.Bytes = NULL;
|
|
KeReleaseSpinLockFromDpcLevel(&Globals.ControllerData->BytesSpinLock);
|
|
|
|
I8xCompletePendedRequest(DeviceObject, irp, 0, irp->IoStatus.Status);
|
|
}
|
|
else {
|
|
//
|
|
// Restart the command timer. Once started, the timer stops only
|
|
// when the TimerCount goes to zero (indicating that the command
|
|
// has timed out) or when explicitly cancelled in the completion
|
|
// DPC (indicating that the command has successfully completed).
|
|
//
|
|
|
|
deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
|
|
deltaTime.HighPart = -1;
|
|
|
|
(VOID) KeSetTimer(
|
|
&Globals.ControllerData->CommandTimer,
|
|
deltaTime,
|
|
&commonData->TimeOutDpc
|
|
);
|
|
}
|
|
|
|
Print(DBG_DPC_TRACE, ("I8042TimeOutDpc: exit\n" ));
|
|
}
|
|
|
|
VOID
|
|
I8xDecrementTimer(
|
|
IN PTIMER_CONTEXT Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine decrements the timeout counter. It is called from
|
|
I8042TimeOutDpc.
|
|
|
|
Arguments:
|
|
|
|
Context - Points to the context structure containing a pointer
|
|
to the device object and a pointer to the timeout counter.
|
|
|
|
Return Value:
|
|
|
|
None. As a side-effect, the timeout counter is updated.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_OBJECT deviceObject;
|
|
PCOMMON_DATA commonData;
|
|
|
|
deviceObject = Context->DeviceObject;
|
|
commonData = GET_COMMON_DATA(deviceObject->DeviceExtension);
|
|
|
|
//
|
|
// Decrement the timeout counter.
|
|
//
|
|
|
|
if (*(Context->TimerCounter) != I8042_ASYNC_NO_TIMEOUT)
|
|
(*(Context->TimerCounter))--;
|
|
|
|
//
|
|
// Return the decremented timer count in NewTimerCount. The
|
|
// TimerCounter itself could change between the time this KeSynch'ed
|
|
// routine returns to the TimeOutDpc, and the time the TimeOutDpc
|
|
// looks at the value. The TimeOutDpc will use NewTimerCount.
|
|
//
|
|
|
|
Context->NewTimerCount = *(Context->TimerCounter);
|
|
|
|
//
|
|
// Reset the state and the resend count, if the timeout counter goes to 0.
|
|
//
|
|
|
|
if (*(Context->TimerCounter) == 0) {
|
|
commonData->CurrentOutput.State = Idle;
|
|
commonData->ResendCount = 0;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
I8xDpcVariableOperation(
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called synchronously by the ISR DPC to perform an
|
|
operation on the InterlockedDpcVariable. The operations that can be
|
|
performed include increment, decrement, write, and read. The ISR
|
|
itself reads and writes the InterlockedDpcVariable without calling this
|
|
routine.
|
|
|
|
Arguments:
|
|
|
|
Context - Pointer to a structure containing the address of the variable
|
|
to be operated on, the operation to perform, and the address at
|
|
which to copy the resulting value of the variable (the latter is also
|
|
used to pass in the value to write to the variable, on a write
|
|
operation).
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PVARIABLE_OPERATION_CONTEXT operationContext = Context;
|
|
|
|
Print(DBG_DPC_TRACE, ("I8xDpcVariableOperation: enter\n"));
|
|
Print(DBG_DPC_INFO,
|
|
("\tPerforming %s at 0x%x (current value 0x%x)\n",
|
|
(operationContext->Operation == IncrementOperation)? "increment":
|
|
(operationContext->Operation == DecrementOperation)? "decrement":
|
|
(operationContext->Operation == WriteOperation)? "write":
|
|
(operationContext->Operation == ReadOperation)? "read":"",
|
|
operationContext->VariableAddress,
|
|
*(operationContext->VariableAddress)
|
|
));
|
|
|
|
//
|
|
// Perform the specified operation at the specified address.
|
|
//
|
|
|
|
switch(operationContext->Operation) {
|
|
case IncrementOperation:
|
|
*(operationContext->VariableAddress) += 1;
|
|
break;
|
|
case DecrementOperation:
|
|
*(operationContext->VariableAddress) -= 1;
|
|
break;
|
|
case ReadOperation:
|
|
break;
|
|
case WriteOperation:
|
|
Print(DBG_DPC_INFO,
|
|
("\tWriting 0x%x\n",
|
|
*(operationContext->NewValue)
|
|
));
|
|
*(operationContext->VariableAddress) =
|
|
*(operationContext->NewValue);
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
*(operationContext->NewValue) = *(operationContext->VariableAddress);
|
|
|
|
Print(DBG_DPC_TRACE,
|
|
("I8xDpcVariableOperation: exit with value 0x%x\n",
|
|
*(operationContext->NewValue)
|
|
));
|
|
}
|
|
|
|
VOID
|
|
I8xGetDataQueuePointer(
|
|
IN PGET_DATA_POINTER_CONTEXT Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called synchronously to get the current DataIn and DataOut
|
|
pointers for the port InputData queue.
|
|
|
|
Arguments:
|
|
|
|
Context - Pointer to a structure containing the device extension,
|
|
device type, address at which to store the current DataIn pointer,
|
|
and the address at which to store the current DataOut pointer.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPORT_MOUSE_EXTENSION mouseExtension;
|
|
PPORT_KEYBOARD_EXTENSION kbExtension;
|
|
CCHAR deviceType;
|
|
|
|
Print(DBG_CALL_TRACE, ("I8xGetDataQueuePointer: enter\n"));
|
|
|
|
//
|
|
// Get address of device extension.
|
|
//
|
|
|
|
deviceType = (CCHAR) ((PGET_DATA_POINTER_CONTEXT) Context)->DeviceType;
|
|
|
|
//
|
|
// Get the DataIn and DataOut pointers for the indicated device.
|
|
//
|
|
|
|
if (deviceType == KeyboardDeviceType) {
|
|
kbExtension = (PPORT_KEYBOARD_EXTENSION) Context->DeviceExtension;
|
|
|
|
Print(DBG_CALL_INFO,
|
|
("I8xGetDataQueuePointer: keyboard\n"
|
|
));
|
|
Print(DBG_CALL_INFO,
|
|
("I8xGetDataQueuePointer: DataIn 0x%x, DataOut 0x%x\n",
|
|
kbExtension->DataIn,
|
|
kbExtension->DataOut
|
|
));
|
|
|
|
Context->DataIn = kbExtension->DataIn;
|
|
Context->DataOut = kbExtension->DataOut;
|
|
Context->InputCount = kbExtension->InputCount;
|
|
} else if (deviceType == MouseDeviceType) {
|
|
mouseExtension = (PPORT_MOUSE_EXTENSION) Context->DeviceExtension;
|
|
|
|
Print(DBG_CALL_INFO,
|
|
("I8xGetDataQueuePointer: mouse\n"
|
|
));
|
|
Print(DBG_CALL_INFO,
|
|
("I8xGetDataQueuePointer: DataIn 0x%x, DataOut 0x%x\n",
|
|
mouseExtension->DataIn,
|
|
mouseExtension->DataOut
|
|
));
|
|
|
|
Context->DataIn = mouseExtension->DataIn;
|
|
Context->DataOut = mouseExtension->DataOut;
|
|
Context->InputCount = mouseExtension->InputCount;
|
|
}
|
|
else {
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
Print(DBG_CALL_TRACE, ("I8xGetDataQueuePointer: exit\n"));
|
|
}
|
|
|
|
VOID
|
|
I8xInitializeDataQueue (
|
|
IN PI8042_INITIALIZE_DATA_CONTEXT InitializeDataContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the input data queue for the indicated device.
|
|
This routine is called via KeSynchronization, except when called from
|
|
the initialization routine.
|
|
|
|
Arguments:
|
|
|
|
Context - Pointer to a structure containing the device extension and
|
|
the device type.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPORT_KEYBOARD_EXTENSION kbExtension;
|
|
PPORT_MOUSE_EXTENSION mouseExtension;
|
|
CCHAR deviceType;
|
|
|
|
Print(DBG_CALL_TRACE, ("I8xInitializeDataQueue: enter\n"));
|
|
|
|
//
|
|
// Get address of device extension.
|
|
//
|
|
|
|
deviceType = InitializeDataContext->DeviceType;
|
|
|
|
//
|
|
// Initialize the input data queue for the indicated device.
|
|
//
|
|
if (deviceType == KeyboardDeviceType) {
|
|
kbExtension = (PPORT_KEYBOARD_EXTENSION)
|
|
InitializeDataContext->DeviceExtension;
|
|
kbExtension->InputCount = 0;
|
|
kbExtension->DataIn = kbExtension->InputData;
|
|
kbExtension->DataOut = kbExtension->InputData;
|
|
kbExtension->OkayToLogOverflow = TRUE;
|
|
|
|
Print(DBG_CALL_INFO, ("I8xInitializeDataQueue: keyboard\n"));
|
|
}
|
|
else if (deviceType == MouseDeviceType) {
|
|
mouseExtension = (PPORT_MOUSE_EXTENSION)
|
|
InitializeDataContext->DeviceExtension;
|
|
|
|
mouseExtension->InputCount = 0;
|
|
mouseExtension->DataIn = mouseExtension->InputData;
|
|
mouseExtension->DataOut = mouseExtension->InputData;
|
|
mouseExtension->OkayToLogOverflow = TRUE;
|
|
|
|
Print(DBG_CALL_INFO, ("I8xInitializeDataQueue: mouse\n"));
|
|
}
|
|
else {
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
Print(DBG_CALL_TRACE, ("I8xInitializeDataQueue: exit\n"));
|
|
|
|
}
|
|
|
|
VOID
|
|
I8xLogError(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN NTSTATUS ErrorCode,
|
|
IN ULONG UniqueErrorValue,
|
|
IN NTSTATUS FinalStatus,
|
|
IN PULONG DumpData,
|
|
IN ULONG DumpCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine contains common code to write an error log entry. It is
|
|
called from other routines, especially I8xInitializeKeyboard, to avoid
|
|
duplication of code. Note that some routines continue to have their
|
|
own error logging code (especially in the case where the error logging
|
|
can be localized and/or the routine has more data because there is
|
|
and IRP).
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
|
|
ErrorCode - The error code for the error log packet.
|
|
|
|
UniqueErrorValue - The unique error value for the error log packet.
|
|
|
|
FinalStatus - The final status of the operation for the error log packet.
|
|
|
|
DumpData - Pointer to an array of dump data for the error log packet.
|
|
|
|
DumpCount - The number of entries in the dump data array.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_ERROR_LOG_PACKET errorLogEntry;
|
|
ULONG i;
|
|
|
|
errorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(
|
|
DeviceObject,
|
|
(UCHAR)
|
|
(sizeof(IO_ERROR_LOG_PACKET)
|
|
+ (DumpCount * sizeof(ULONG)))
|
|
);
|
|
|
|
if (errorLogEntry != NULL) {
|
|
|
|
errorLogEntry->ErrorCode = ErrorCode;
|
|
errorLogEntry->DumpDataSize = (USHORT) (DumpCount * sizeof(ULONG));
|
|
errorLogEntry->SequenceNumber = 0;
|
|
errorLogEntry->MajorFunctionCode = 0;
|
|
errorLogEntry->IoControlCode = 0;
|
|
errorLogEntry->RetryCount = 0;
|
|
errorLogEntry->UniqueErrorValue = UniqueErrorValue;
|
|
errorLogEntry->FinalStatus = FinalStatus;
|
|
for (i = 0; i < DumpCount; i++)
|
|
errorLogEntry->DumpData[i] = DumpData[i];
|
|
|
|
IoWriteErrorLogEntry(errorLogEntry);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
I8xSetDataQueuePointer(
|
|
IN PSET_DATA_POINTER_CONTEXT SetDataPointerContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called synchronously to set the DataOut pointer
|
|
and InputCount for the port InputData queue.
|
|
|
|
Arguments:
|
|
|
|
Context - Pointer to a structure containing the device extension,
|
|
device type, and the new DataOut value for the port InputData queue.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPORT_MOUSE_EXTENSION mouseExtension;
|
|
PPORT_KEYBOARD_EXTENSION kbExtension;
|
|
CCHAR deviceType;
|
|
|
|
Print(DBG_CALL_TRACE, ("I8xSetDataQueuePointer: enter\n"));
|
|
|
|
//
|
|
// Get address of device extension.
|
|
//
|
|
|
|
deviceType = (CCHAR) SetDataPointerContext->DeviceType;
|
|
|
|
//
|
|
// Set the DataOut pointer for the indicated device.
|
|
//
|
|
|
|
if (deviceType == KeyboardDeviceType) {
|
|
kbExtension = (PPORT_KEYBOARD_EXTENSION)
|
|
SetDataPointerContext->DeviceExtension;
|
|
|
|
Print(DBG_CALL_INFO,
|
|
("I8xSetDataQueuePointer: old keyboard DataOut 0x%x, InputCount %d\n",
|
|
kbExtension->DataOut,
|
|
kbExtension->InputCount
|
|
));
|
|
kbExtension->DataOut = SetDataPointerContext->DataOut;
|
|
kbExtension->InputCount -= SetDataPointerContext->InputCount;
|
|
if (kbExtension->InputCount == 0) {
|
|
|
|
//
|
|
// Reset the flag that determines whether it is time to log
|
|
// queue overflow errors. We don't want to log errors too often.
|
|
// Instead, log an error on the first overflow that occurs after
|
|
// the ring buffer has been emptied, and then stop logging errors
|
|
// until it gets cleared out and overflows again.
|
|
//
|
|
|
|
Print(DBG_CALL_INFO,
|
|
("I8xSetDataQueuePointer: Okay to log keyboard overflow\n"
|
|
));
|
|
kbExtension->OkayToLogOverflow = TRUE;
|
|
}
|
|
Print(DBG_CALL_INFO,
|
|
("I8xSetDataQueuePointer: new keyboard DataOut 0x%x, InputCount %d\n",
|
|
kbExtension->DataOut,
|
|
kbExtension->InputCount
|
|
));
|
|
} else if (deviceType == MouseDeviceType) {
|
|
mouseExtension = (PPORT_MOUSE_EXTENSION)
|
|
SetDataPointerContext->DeviceExtension;
|
|
|
|
Print(DBG_CALL_INFO,
|
|
("I8xSetDataQueuePointer: old mouse DataOut 0x%x, InputCount %d\n",
|
|
mouseExtension->DataOut,
|
|
mouseExtension->InputCount
|
|
));
|
|
mouseExtension->DataOut = SetDataPointerContext->DataOut;
|
|
mouseExtension->InputCount -= SetDataPointerContext->InputCount;
|
|
if (mouseExtension->InputCount == 0) {
|
|
|
|
//
|
|
// Reset the flag that determines whether it is time to log
|
|
// queue overflow errors. We don't want to log errors too often.
|
|
// Instead, log an error on the first overflow that occurs after
|
|
// the ring buffer has been emptied, and then stop logging errors
|
|
// until it gets cleared out and overflows again.
|
|
//
|
|
|
|
Print(DBG_CALL_INFO,
|
|
("I8xSetDataQueuePointer: Okay to log mouse overflow\n"
|
|
));
|
|
mouseExtension->OkayToLogOverflow = TRUE;
|
|
}
|
|
Print(DBG_CALL_INFO,
|
|
("I8xSetDataQueuePointer: new mouse DataOut 0x%x, InputCount %d\n",
|
|
mouseExtension->DataOut,
|
|
mouseExtension->InputCount
|
|
));
|
|
} else {
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
Print(DBG_CALL_TRACE, ("I8xSetDataQueuePointer: exit\n"));
|
|
}
|
|
|
|
#if WRAP_IO_FUNCTIONS
|
|
UCHAR
|
|
NTAPI
|
|
I8xReadRegisterUchar(
|
|
PUCHAR Register
|
|
)
|
|
{
|
|
return READ_REGISTER_UCHAR(Register);
|
|
}
|
|
|
|
void
|
|
NTAPI
|
|
I8xWriteRegisterUchar(
|
|
PUCHAR Register,
|
|
UCHAR Value
|
|
)
|
|
{
|
|
WRITE_REGISTER_UCHAR(Register, Value);
|
|
}
|
|
|
|
UCHAR
|
|
NTAPI
|
|
I8xReadPortUchar(
|
|
PUCHAR Port
|
|
)
|
|
{
|
|
return READ_PORT_UCHAR(Port);
|
|
}
|
|
|
|
void
|
|
NTAPI
|
|
I8xWritePortUchar(
|
|
PUCHAR Port,
|
|
UCHAR Value
|
|
)
|
|
{
|
|
WRITE_PORT_UCHAR(Port, Value);
|
|
}
|
|
#endif // WRAP_IO_FUNCTIONS
|
|
|
|
BOOLEAN
|
|
I8xSanityCheckResources(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Upon receiving the last Start Device IRP, all of the necessary i/o ports are checked
|
|
to see if they exist. If not, try to acquire them the old (non PnP) way.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
ULONG interruptVector;
|
|
KIRQL interruptLevel;
|
|
PI8042_CONFIGURATION_INFORMATION configuration;
|
|
CM_PARTIAL_RESOURCE_DESCRIPTOR tmpResourceDescriptor;
|
|
|
|
PCM_RESOURCE_LIST resources = NULL;
|
|
ULONG resourceListSize = 0;
|
|
UNICODE_STRING resourceDeviceClass;
|
|
PDEVICE_OBJECT deviceObject = NULL;
|
|
ULONG dumpData[4];
|
|
BOOLEAN conflictDetected;
|
|
|
|
BOOLEAN resourcesOK = TRUE;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// If no port configuration information was found and we are at the last
|
|
// added device (in the PnP view of things), use the i8042 defaults.
|
|
//
|
|
configuration = &Globals.ControllerData->Configuration;
|
|
|
|
if (configuration->PortListCount == 0) {
|
|
//
|
|
// This state is now taken care of in IRP_MN_FILTER_RESOURCE_REQUIREMENTS,
|
|
// it should never happen!
|
|
//
|
|
return FALSE;
|
|
}
|
|
else if (configuration->PortListCount == 1) {
|
|
//
|
|
// Kludge for Jazz machines. Their ARC firmware neglects to
|
|
// separate out the port addresses, so fix that up here.
|
|
//
|
|
configuration->PortList[DataPort].u.Port.Length = I8042_REGISTER_LENGTH;
|
|
configuration->PortList[CommandPort] = configuration->PortList[DataPort];
|
|
configuration->PortList[CommandPort].u.Port.Start.LowPart +=
|
|
I8042_COMMAND_REGISTER_OFFSET;
|
|
configuration->PortListCount += 1;
|
|
}
|
|
|
|
//
|
|
// Put the lowest port address range in the DataPort element of
|
|
// the port list.
|
|
//
|
|
if (configuration->PortList[CommandPort].u.Port.Start.LowPart
|
|
< configuration->PortList[DataPort].u.Port.Start.LowPart) {
|
|
|
|
tmpResourceDescriptor = configuration->PortList[DataPort];
|
|
configuration->PortList[DataPort] =
|
|
configuration->PortList[CommandPort];
|
|
configuration->PortList[CommandPort] = tmpResourceDescriptor;
|
|
}
|
|
|
|
//
|
|
// Set the DeviceRegister, mapping them if necessary
|
|
//
|
|
if (Globals.ControllerData->DeviceRegisters[0] == NULL) {
|
|
if (Globals.RegistersMapped) {
|
|
Print(DBG_SS_INFO, ("\tMapping registers !!!\n\n"));
|
|
for (i=0; i < Globals.ControllerData->Configuration.PortListCount; i++) {
|
|
Globals.ControllerData->DeviceRegisters[i] = (PUCHAR)
|
|
MmMapIoSpace(
|
|
Globals.ControllerData->Configuration.PortList[i].u.Memory.Start,
|
|
Globals.ControllerData->Configuration.PortList[i].u.Memory.Length,
|
|
MmNonCached
|
|
);
|
|
}
|
|
#if WRAP_IO_FUNCTIONS
|
|
Globals.I8xReadXxxUchar = I8xReadRegisterUchar;
|
|
Globals.I8xWriteXxxUchar = I8xWriteRegisterUchar;
|
|
#else
|
|
Globals.I8xReadXxxUchar = READ_REGISTER_UCHAR;
|
|
Globals.I8xWriteXxxUchar = WRITE_REGISTER_UCHAR;
|
|
#endif
|
|
}
|
|
else {
|
|
for (i=0; i < Globals.ControllerData->Configuration.PortListCount; i++) {
|
|
Globals.ControllerData->DeviceRegisters[i] = (PUCHAR)
|
|
ULongToPtr(Globals.ControllerData->Configuration.PortList[i].u.Port.Start.LowPart);
|
|
}
|
|
|
|
#if WRAP_IO_FUNCTIONS
|
|
Globals.I8xReadXxxUchar = I8xReadPortUchar;
|
|
Globals.I8xWriteXxxUchar = I8xWritePortUchar;
|
|
#else
|
|
Globals.I8xReadXxxUchar = READ_PORT_UCHAR;
|
|
Globals.I8xWriteXxxUchar = WRITE_PORT_UCHAR;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < configuration->PortListCount; i++) {
|
|
|
|
Print(DBG_SS_INFO,
|
|
(" %s, Ports (#%d) 0x%x - 0x%x\n",
|
|
configuration->PortList[i].ShareDisposition
|
|
== CmResourceShareShared ? "Sharable" : "NonSharable",
|
|
i,
|
|
configuration->PortList[i].u.Port.Start.LowPart,
|
|
configuration->PortList[i].u.Port.Start.LowPart +
|
|
configuration->PortList[i].u.Port.Length - 1
|
|
));
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
I8xInitiateIo(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called synchronously from I8xKeyboardInitiateWrapper and
|
|
the ISR to initiate an I/O operation for the keyboard device.
|
|
|
|
Arguments:
|
|
|
|
Context - Pointer to the device object.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCOMMON_DATA commonData;
|
|
PUCHAR bytes;
|
|
|
|
Print(DBG_CALL_TRACE, ("I8xInitiateIo: enter\n"));
|
|
|
|
//
|
|
// Get the device extension.
|
|
//
|
|
commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);
|
|
|
|
//
|
|
// Set the timeout value.
|
|
//
|
|
Globals.ControllerData->TimerCount = I8042_ASYNC_TIMEOUT;
|
|
|
|
bytes = commonData->CurrentOutput.Bytes;
|
|
|
|
//
|
|
// Check to see if we have a valid buffer and we are actually transmitting.
|
|
// We can get a bytes == 0 and State != SendingBytes by timing out a request
|
|
// (a set lights for example) and then receiving the ACK for the request
|
|
// after the cancellation.
|
|
//
|
|
// I don't think we should log an error here because the timeout will have
|
|
// already done so and the relevant errror msg for this is too cryptic
|
|
// for the user to understand.
|
|
//
|
|
if (!bytes || commonData->CurrentOutput.State != SendingBytes) {
|
|
return;
|
|
}
|
|
|
|
if (commonData->CurrentOutput.CurrentByte <
|
|
commonData->CurrentOutput.ByteCount) {
|
|
|
|
Print(DBG_CALL_INFO,
|
|
("I8xInitiateIo: sending byte #%d (0x%x)\n",
|
|
commonData->CurrentOutput.CurrentByte,
|
|
bytes[commonData->CurrentOutput.CurrentByte]
|
|
));
|
|
|
|
//
|
|
// Send a byte of a command sequence to the keyboard/mouse
|
|
// asynchronously.
|
|
//
|
|
if (!commonData->IsKeyboard) {
|
|
I8X_WRITE_CMD_TO_MOUSE();
|
|
}
|
|
|
|
I8xPutByteAsynchronous(
|
|
(CCHAR) DataPort,
|
|
bytes[commonData->CurrentOutput.CurrentByte++]
|
|
);
|
|
}
|
|
else {
|
|
|
|
Print(DBG_CALL_ERROR | DBG_CALL_INFO,
|
|
("I8xInitiateIo: INVALID REQUEST\n"
|
|
));
|
|
|
|
//
|
|
// Queue a DPC to log an internal driver error.
|
|
//
|
|
KeInsertQueueDpc(
|
|
&commonData->ErrorLogDpc,
|
|
(PIRP) NULL,
|
|
LongToPtr(commonData->IsKeyboard ?
|
|
I8042_INVALID_INITIATE_STATE_KBD :
|
|
I8042_INVALID_INITIATE_STATE_MOU)
|
|
);
|
|
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
Print(DBG_CALL_TRACE, ("I8xInitiateIo: exit\n"));
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
I8xInitiateOutputWrapper(
|
|
IN PINITIATE_OUTPUT_CONTEXT InitiateContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called from StartIo synchronously. It sets up the
|
|
CurrentOutput and ResendCount fields in the device extension, and
|
|
then calls I8xKeyboardInitiateIo to do the real work.
|
|
|
|
Arguments:
|
|
|
|
Context - Pointer to the context structure containing the first and
|
|
last bytes of the send sequence.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_OBJECT deviceObject;
|
|
PCOMMON_DATA commonData;
|
|
LARGE_INTEGER li;
|
|
|
|
//
|
|
// Get a pointer to the device object from the context argument.
|
|
//
|
|
deviceObject = InitiateContext->DeviceObject;
|
|
|
|
//
|
|
// Set up CurrentOutput state for this operation.
|
|
//
|
|
|
|
commonData = GET_COMMON_DATA(deviceObject->DeviceExtension);
|
|
|
|
commonData->CurrentOutput.Bytes = InitiateContext->Bytes;
|
|
commonData->CurrentOutput.ByteCount = InitiateContext->ByteCount;
|
|
commonData->CurrentOutput.CurrentByte = 0;
|
|
commonData->CurrentOutput.State = SendingBytes;
|
|
|
|
//
|
|
// We're starting a new operation, so reset the resend count.
|
|
//
|
|
commonData->ResendCount = 0;
|
|
|
|
//
|
|
// Initiate the keyboard I/O operation. Note that we were called
|
|
// using KeSynchronizeExecution, so I8xKeyboardInitiateIo is also
|
|
// synchronized with the keyboard ISR.
|
|
//
|
|
|
|
I8xInitiateIo(deviceObject);
|
|
}
|