1790 lines
50 KiB
C
1790 lines
50 KiB
C
#if defined(i386)
|
||
|
||
/*++
|
||
|
||
Copyright (c) 1989, 1990, 1991, 1992, 1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
inpdep.c
|
||
|
||
Abstract:
|
||
|
||
The initialization and hardware-dependent portions of
|
||
the Microsoft InPort mouse port driver. Modifications to
|
||
support new mice similar to the InPort mouse should be
|
||
localized to this file.
|
||
|
||
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 "inport.h"
|
||
#include "inplog.h"
|
||
|
||
#if defined(NEC_98)
|
||
ULONG EventStatus = 0;
|
||
#endif // defined(NEC_98)
|
||
|
||
//
|
||
// Use the alloc_text pragma to specify the driver initialization routines
|
||
// (they can be paged out).
|
||
//
|
||
#ifdef ALLOC_PRAGMA
|
||
// #pragma alloc_text(INIT,InpConfiguration)
|
||
// #pragma alloc_text(INIT,InpPeripheralCallout)
|
||
// #pragma alloc_text(INIT,InpBuildResourceList)
|
||
#pragma alloc_text(INIT,DriverEntry)
|
||
#pragma alloc_text(PAGE,InpServiceParameters)
|
||
#pragma alloc_text(PAGE,InpInitializeHardware)
|
||
#if defined(NEC_98)
|
||
#pragma alloc_text(INIT,QueryEventMode)
|
||
#endif // defined(NEC_98)
|
||
#endif
|
||
|
||
GLOBALS Globals;
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the Inport mouse port driver.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to driver object created by system.
|
||
|
||
RegistryPath - Pointer to the Unicode name of the registry path
|
||
for this driver.
|
||
|
||
Return Value:
|
||
|
||
The function value is the final status from the initialization operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PIO_ERROR_LOG_PACKET errorLogEntry;
|
||
NTSTATUS errorCode;
|
||
ULONG uniqueErrorValue, dumpCount;
|
||
#define NAME_MAX 256
|
||
WCHAR nameBuffer[NAME_MAX];
|
||
|
||
ULONG dumpData[4];
|
||
|
||
|
||
InpPrint((1,"\n\nINPORT-InportDriverEntry: enter\n"));
|
||
|
||
//
|
||
// Need to ensure that the registry path is null-terminated.
|
||
// Allocate pool to hold a null-terminated copy of the path.
|
||
//
|
||
Globals.RegistryPath.MaximumLength = 0;
|
||
Globals.RegistryPath.Buffer = ExAllocatePool(
|
||
PagedPool,
|
||
RegistryPath->Length + sizeof(UNICODE_NULL)
|
||
);
|
||
|
||
if (!Globals.RegistryPath.Buffer) {
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InportDriverEntry: Couldn't allocate pool for registry path\n"
|
||
));
|
||
|
||
dumpData[0] = (ULONG) RegistryPath->Length + sizeof(UNICODE_NULL);
|
||
dumpCount = 1;
|
||
|
||
InpLogError(
|
||
(PDEVICE_OBJECT)DriverObject,
|
||
INPORT_INSUFFICIENT_RESOURCES,
|
||
INPORT_ERROR_VALUE_BASE + 2,
|
||
STATUS_UNSUCCESSFUL,
|
||
dumpData,
|
||
1
|
||
);
|
||
|
||
} else {
|
||
|
||
Globals.RegistryPath.Length = RegistryPath->Length + sizeof(UNICODE_NULL);
|
||
Globals.RegistryPath.MaximumLength = Globals.RegistryPath.Length;
|
||
|
||
RtlZeroMemory(
|
||
Globals.RegistryPath.Buffer,
|
||
Globals.RegistryPath.Length
|
||
);
|
||
|
||
RtlMoveMemory(
|
||
Globals.RegistryPath.Buffer,
|
||
RegistryPath->Buffer,
|
||
RegistryPath->Length
|
||
);
|
||
|
||
}
|
||
|
||
//
|
||
// Set up the device driver entry points.
|
||
//
|
||
DriverObject->DriverStartIo = InportStartIo;
|
||
DriverObject->DriverExtension->AddDevice = InportAddDevice;
|
||
DriverObject->MajorFunction[IRP_MJ_CREATE] = InportCreate;
|
||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = InportClose;
|
||
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] =
|
||
InportFlush;
|
||
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
|
||
InportInternalDeviceControl;
|
||
|
||
DriverObject->MajorFunction[IRP_MJ_PNP] = InportPnP;
|
||
DriverObject->MajorFunction[IRP_MJ_POWER] = InportPower;
|
||
|
||
//
|
||
// NOTE: Don't allow this driver to unload. Otherwise, we would set
|
||
// DriverObject->DriverUnload = InportUnload.
|
||
//
|
||
|
||
#if defined(NEC_98)
|
||
//
|
||
// Is "Event Interrupt Mode" available on this machine?
|
||
//
|
||
QueryEventMode();
|
||
#endif // defined(NEC_98)
|
||
|
||
InpPrint((1,"INPORT-InportDriverEntry: exit\n"));
|
||
|
||
return(status);
|
||
|
||
}
|
||
|
||
BOOLEAN
|
||
InportInterruptService(
|
||
IN PKINTERRUPT Interrupt,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the interrupt service routine for the mouse device.
|
||
|
||
Arguments:
|
||
|
||
Interrupt - A pointer to the interrupt object for this interrupt.
|
||
|
||
Context - A pointer to the device object.
|
||
|
||
Return Value:
|
||
|
||
Returns TRUE if the interrupt was expected (and therefore processed);
|
||
otherwise, FALSE is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
PDEVICE_OBJECT deviceObject;
|
||
PUCHAR port;
|
||
UCHAR previousButtons;
|
||
UCHAR mode;
|
||
UCHAR status;
|
||
#if defined(NEC_98)
|
||
PINPORT_CONFIGURATION_INFORMATION Configuration;
|
||
#endif // defined(NEC_98)
|
||
|
||
UNREFERENCED_PARAMETER(Interrupt);
|
||
|
||
InpPrint((3, "INPORT-InportInterruptService: enter\n"));
|
||
|
||
//
|
||
// Get the device extension.
|
||
//
|
||
|
||
deviceObject = (PDEVICE_OBJECT) Context;
|
||
deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
|
||
#if defined(NEC_98)
|
||
Configuration = &deviceExtension->Configuration;
|
||
|
||
if (Configuration->MouseInterrupt.Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) {
|
||
if ((READ_PORT_UCHAR((PUCHAR)PC98_MOUSE_INT_SHARE_CHECK_PORT) & PC98_MOUSE_INT_SERVICE)
|
||
!= PC98_MOUSE_INT_SERVICE) {
|
||
InpPrint((1, "InportInterruptService: exit [NOT Mouse Service]\n"));
|
||
return(FALSE);
|
||
}
|
||
}
|
||
|
||
if (deviceExtension->ConnectData.ClassService == NULL) {
|
||
InpPrint((1, "InportInterruptService: exit [not connected yet]\n"));
|
||
return(TRUE);
|
||
}
|
||
#endif // defined(NEC_98)
|
||
|
||
//
|
||
// Get the Inport mouse port address.
|
||
//
|
||
|
||
port = deviceExtension->Configuration.DeviceRegisters[0];
|
||
|
||
#if defined(NEC_98)
|
||
WRITE_PORT_UCHAR(port + PC98_WritePortC2, PC98_TimerIntDisable);
|
||
|
||
//
|
||
// Read X Data.
|
||
//
|
||
WRITE_PORT_UCHAR(port + PC98_WritePortC2, PC98_X_ReadCommandHi);
|
||
status = (UCHAR)(LONG)(SCHAR) READ_PORT_UCHAR((PUCHAR)(port + PC98_ReadPortA));
|
||
deviceExtension->CurrentInput.LastX = status & 0x000f;
|
||
|
||
WRITE_PORT_UCHAR(port + PC98_WritePortC2, PC98_X_ReadCommandLow);
|
||
deviceExtension->CurrentInput.LastX =
|
||
(LONG)(SCHAR) ((deviceExtension->CurrentInput.LastX << 4) |
|
||
(READ_PORT_UCHAR(port + PC98_ReadPortA) & 0x000f));
|
||
|
||
//
|
||
// Read Y Data.
|
||
//
|
||
WRITE_PORT_UCHAR(port + PC98_WritePortC2, PC98_Y_ReadCommandHi);
|
||
status = (UCHAR)(LONG)(SCHAR) READ_PORT_UCHAR((PUCHAR)(port + PC98_ReadPortA));
|
||
deviceExtension->CurrentInput.LastY = status & 0x000f;
|
||
|
||
WRITE_PORT_UCHAR(port + PC98_WritePortC2, PC98_Y_ReadCommandLow);
|
||
deviceExtension->CurrentInput.LastY =
|
||
(LONG)(SCHAR) ((deviceExtension->CurrentInput.LastY << 4) |
|
||
(READ_PORT_UCHAR(port + PC98_ReadPortA) & 0x000f));
|
||
|
||
//
|
||
// Set Mouse Button Status.
|
||
//
|
||
status = ~status;
|
||
#else // defined(NEC_98)
|
||
//
|
||
// Note: It would be nice to verify that the interrupt really
|
||
// belongs to this driver, but it is currently not known how to
|
||
// make that determination.
|
||
//
|
||
|
||
//
|
||
// Set the Inport hold bit. Note that there is a bug in the 1.1 version
|
||
// of the Inport chip in DATA mode. The interrupt signal doesn't get
|
||
// cleared in some cases, thus effectively disabling the device. The
|
||
// workaround is to set the HOLD bit twice.
|
||
//
|
||
|
||
WRITE_PORT_UCHAR((PUCHAR) port, INPORT_MODE_REGISTER);
|
||
mode = READ_PORT_UCHAR((PUCHAR) (port + INPORT_DATA_REGISTER_1));
|
||
WRITE_PORT_UCHAR(
|
||
(PUCHAR) (port + INPORT_DATA_REGISTER_1),
|
||
(UCHAR) (mode | INPORT_MODE_HOLD)
|
||
);
|
||
WRITE_PORT_UCHAR(
|
||
(PUCHAR) (port + INPORT_DATA_REGISTER_1),
|
||
(UCHAR) (mode | INPORT_MODE_HOLD)
|
||
);
|
||
|
||
//
|
||
// Read the Inport status register. It contains the following information:
|
||
//
|
||
// XXXXXXXX
|
||
// | | |------ 1 if button 3 is down (right button)
|
||
// | |-------- 1 if button 1 is down (left button)
|
||
// |------------ 1 if the mouse has moved
|
||
//
|
||
|
||
WRITE_PORT_UCHAR((PUCHAR) port, INPORT_STATUS_REGISTER);
|
||
status = READ_PORT_UCHAR((PUCHAR) (port + INPORT_DATA_REGISTER_1));
|
||
|
||
InpPrint((3, "INPORT-InportInterruptService: status byte 0x%x\n", status));
|
||
#endif // defined(NEC_98)
|
||
|
||
//
|
||
// Update CurrentInput with button transition data.
|
||
// I.e., set a button up/down bit in the Buttons field if
|
||
// the state of a given button has changed since we
|
||
// received the last packet.
|
||
//
|
||
|
||
previousButtons =
|
||
deviceExtension->PreviousButtons;
|
||
|
||
deviceExtension->CurrentInput.Buttons = 0;
|
||
|
||
if ((!(previousButtons & INPORT_STATUS_BUTTON1))
|
||
&& (status & INPORT_STATUS_BUTTON1)) {
|
||
deviceExtension->CurrentInput.Buttons |=
|
||
MOUSE_LEFT_BUTTON_DOWN;
|
||
} else
|
||
if ((previousButtons & INPORT_STATUS_BUTTON1)
|
||
&& !(status & INPORT_STATUS_BUTTON1)) {
|
||
deviceExtension->CurrentInput.Buttons |=
|
||
MOUSE_LEFT_BUTTON_UP;
|
||
}
|
||
if ((!(previousButtons & INPORT_STATUS_BUTTON3))
|
||
&& (status & INPORT_STATUS_BUTTON3)) {
|
||
deviceExtension->CurrentInput.Buttons |=
|
||
MOUSE_RIGHT_BUTTON_DOWN;
|
||
} else
|
||
if ((previousButtons & INPORT_STATUS_BUTTON3)
|
||
&& !(status & INPORT_STATUS_BUTTON3)) {
|
||
deviceExtension->CurrentInput.Buttons |=
|
||
MOUSE_RIGHT_BUTTON_UP;
|
||
}
|
||
|
||
//
|
||
// If the button position changed or the mouse moved, continue to process
|
||
// the interrupt. Otherwise, just clear the hold bit and ignore this
|
||
// interrupt's data.
|
||
//
|
||
|
||
#if defined(NEC_98)
|
||
if ((deviceExtension->PreviousButtons ^ deviceExtension->CurrentInput.Buttons)
|
||
|| (deviceExtension->CurrentInput.LastX | deviceExtension->CurrentInput.LastY)) {
|
||
#else // defined(NEC_98)
|
||
if (deviceExtension->CurrentInput.Buttons
|
||
|| (status & INPORT_STATUS_MOVEMENT)) {
|
||
|
||
deviceExtension->CurrentInput.UnitId = deviceExtension->UnitId;
|
||
#endif // defined(NEC_98)
|
||
|
||
//
|
||
// Keep track of the state of the mouse buttons for the next
|
||
// interrupt.
|
||
//
|
||
|
||
deviceExtension->PreviousButtons =
|
||
status & (INPORT_STATUS_BUTTON1 | INPORT_STATUS_BUTTON3);
|
||
|
||
#if defined(NEC_98)
|
||
//
|
||
// If mouse not movement was recorded, set the X and Y motion 0 data.
|
||
//
|
||
if (!(deviceExtension->CurrentInput.LastX | deviceExtension->CurrentInput.LastY)) {
|
||
deviceExtension->CurrentInput.LastX = 0;
|
||
deviceExtension->CurrentInput.LastY = 0;
|
||
}
|
||
WRITE_PORT_UCHAR(port + PC98_WritePortC2, PC98_TimerIntEnable);
|
||
#else // defined(NEC_98)
|
||
//
|
||
// If mouse movement was recorded, get the X and Y motion data.
|
||
//
|
||
|
||
if (status & INPORT_STATUS_MOVEMENT) {
|
||
|
||
//
|
||
// Select the Data1 register as the current data register, and
|
||
// get the X motion byte.
|
||
//
|
||
|
||
WRITE_PORT_UCHAR((PUCHAR) port, INPORT_DATA_REGISTER_1);
|
||
deviceExtension->CurrentInput.LastX =
|
||
(LONG)(SCHAR) READ_PORT_UCHAR(
|
||
(PUCHAR) (port + INPORT_DATA_REGISTER_1));
|
||
|
||
//
|
||
// Select the Data2 register as the current data register, and
|
||
// get the Y motion byte.
|
||
//
|
||
|
||
WRITE_PORT_UCHAR((PUCHAR) port, INPORT_DATA_REGISTER_2);
|
||
deviceExtension->CurrentInput.LastY =
|
||
(LONG)(SCHAR) READ_PORT_UCHAR(
|
||
(PUCHAR) (port + INPORT_DATA_REGISTER_1));
|
||
} else {
|
||
deviceExtension->CurrentInput.LastX = 0;
|
||
deviceExtension->CurrentInput.LastY = 0;
|
||
}
|
||
|
||
//
|
||
// Clear the Inport hold bit.
|
||
//
|
||
|
||
WRITE_PORT_UCHAR((PUCHAR) port, INPORT_MODE_REGISTER);
|
||
mode = READ_PORT_UCHAR((PUCHAR) (port + INPORT_DATA_REGISTER_1));
|
||
WRITE_PORT_UCHAR(
|
||
(PUCHAR) (port + INPORT_DATA_REGISTER_1),
|
||
(UCHAR) (mode & ~INPORT_MODE_HOLD)
|
||
);
|
||
#endif // defined(NEC_98)
|
||
|
||
//
|
||
// Write the input data to the queue and request the ISR DPC to
|
||
// finish processing the interrupt at DISPATCH_LEVEL.
|
||
//
|
||
|
||
if (!InpWriteDataToQueue(
|
||
deviceExtension,
|
||
&deviceExtension->CurrentInput
|
||
)) {
|
||
|
||
//
|
||
// The mouse input data queue is full. Just drop the
|
||
// latest input on the floor.
|
||
//
|
||
// Queue a DPC to log an overrun error.
|
||
//
|
||
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InportInterruptService: queue overflow\n"
|
||
));
|
||
|
||
if (deviceExtension->OkayToLogOverflow) {
|
||
KeInsertQueueDpc(
|
||
&deviceExtension->ErrorLogDpc,
|
||
(PIRP) NULL,
|
||
(PVOID) (ULONG) INPORT_MOU_BUFFER_OVERFLOW
|
||
);
|
||
deviceExtension->OkayToLogOverflow = FALSE;
|
||
}
|
||
|
||
} else if (deviceExtension->DpcInterlockVariable >= 0) {
|
||
|
||
//
|
||
// The ISR DPC is already executing. Tell the ISR DPC it has
|
||
// more work to do by incrementing the DpcInterlockVariable.
|
||
//
|
||
|
||
deviceExtension->DpcInterlockVariable += 1;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Queue the ISR DPC.
|
||
//
|
||
|
||
KeInsertQueueDpc(
|
||
&deviceExtension->IsrDpc,
|
||
deviceObject->CurrentIrp,
|
||
NULL
|
||
);
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
InpPrint((
|
||
3,
|
||
"INPORT-InportInterruptService: interrupt without button/motion change\n"
|
||
));
|
||
|
||
|
||
//
|
||
// Clear the Inport hold bit.
|
||
//
|
||
|
||
#if defined(NEC_98)
|
||
WRITE_PORT_UCHAR(port + PC98_WritePortC2, PC98_TimerIntEnable);
|
||
#else // defined(NEC_98)
|
||
WRITE_PORT_UCHAR((PUCHAR) port, INPORT_MODE_REGISTER);
|
||
mode = READ_PORT_UCHAR((PUCHAR) (port + INPORT_DATA_REGISTER_1));
|
||
WRITE_PORT_UCHAR(
|
||
(PUCHAR) (port + INPORT_DATA_REGISTER_1),
|
||
(UCHAR) (mode & ~INPORT_MODE_HOLD)
|
||
);
|
||
#endif // defined(NEC_98)
|
||
|
||
}
|
||
|
||
InpPrint((3, "INPORT-InportInterruptService: exit\n"));
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
VOID
|
||
InportUnload(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
{
|
||
UNREFERENCED_PARAMETER(DriverObject);
|
||
|
||
InpPrint((2, "INPORT-InportUnload: enter\n"));
|
||
|
||
ExFreePool(Globals.RegistryPath.Buffer);
|
||
|
||
InpPrint((2, "INPORT-InportUnload: exit\n"));
|
||
}
|
||
|
||
|
||
|
||
|
||
#define DUMP_COUNT 4
|
||
NTSTATUS
|
||
InpConfigureDevice(
|
||
IN OUT PDEVICE_EXTENSION DeviceExtension,
|
||
IN PCM_RESOURCE_LIST ResourceList
|
||
)
|
||
{
|
||
PINPORT_CONFIGURATION_INFORMATION configuration;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
ULONG i, count;
|
||
BOOLEAN defaultInterruptShare;
|
||
KINTERRUPT_MODE defaultInterruptMode;
|
||
|
||
PCM_PARTIAL_RESOURCE_LIST partialResList = NULL;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR currentResDesc = NULL;
|
||
PCM_FULL_RESOURCE_DESCRIPTOR fullResDesc = NULL;
|
||
|
||
configuration = &DeviceExtension->Configuration;
|
||
|
||
if (!ResourceList) {
|
||
InpPrint((1, "INPORT-InpConfigureDevice: mouse with null resources\n"));
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
fullResDesc = ResourceList->List;
|
||
if (!fullResDesc) {
|
||
//
|
||
// this should never happen
|
||
//
|
||
ASSERT(fullResDesc != NULL);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
partialResList = &fullResDesc->PartialResourceList;
|
||
currentResDesc = partialResList->PartialDescriptors;
|
||
count = partialResList->Count;
|
||
|
||
configuration->BusNumber = fullResDesc->BusNumber;
|
||
configuration->InterfaceType = fullResDesc->InterfaceType;
|
||
|
||
configuration->FloatingSave = INPORT_FLOATING_SAVE;
|
||
|
||
if (configuration->InterfaceType == MicroChannel) {
|
||
defaultInterruptShare = TRUE;
|
||
defaultInterruptMode = LevelSensitive;
|
||
} else {
|
||
defaultInterruptShare = INPORT_INTERRUPT_SHARE;
|
||
defaultInterruptMode = INPORT_INTERRUPT_MODE;
|
||
}
|
||
|
||
DeviceExtension->Configuration.UnmapRegistersRequired = FALSE;
|
||
|
||
//
|
||
// Look through the resource list for interrupt and port
|
||
// configuration information.
|
||
//
|
||
for (i = 0; i < count; i++, currentResDesc++) {
|
||
switch(currentResDesc->Type) {
|
||
case CmResourceTypePort:
|
||
|
||
#if defined(NEC_98)
|
||
//
|
||
// Copy the port information. Note that we expect to
|
||
// find more than one port ranges for the NEC98 Bus Mouse.
|
||
//
|
||
ASSERT(configuration->PortListCount < (sizeof(configuration->PortList) / sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)));
|
||
#else // defined(NEC_98)
|
||
//
|
||
// Copy the port information. Note that we only expect to
|
||
// find one port range for the Inport mouse.
|
||
//
|
||
ASSERT(configuration->PortListCount == 0);
|
||
#endif // defined(NEC_98)
|
||
configuration->PortList[configuration->PortListCount] =
|
||
*currentResDesc;
|
||
configuration->PortList[configuration->PortListCount].ShareDisposition =
|
||
INPORT_REGISTER_SHARE? CmResourceShareShared:
|
||
CmResourceShareDeviceExclusive;
|
||
configuration->PortListCount += 1;
|
||
if (currentResDesc->Flags == CM_RESOURCE_PORT_MEMORY) {
|
||
DeviceExtension->Configuration.UnmapRegistersRequired = TRUE;
|
||
}
|
||
|
||
break;
|
||
|
||
case CmResourceTypeInterrupt:
|
||
|
||
//
|
||
// Copy the interrupt information.
|
||
//
|
||
|
||
configuration->MouseInterrupt = *currentResDesc;
|
||
configuration->MouseInterrupt.ShareDisposition =
|
||
defaultInterruptShare? CmResourceShareShared :
|
||
CmResourceShareDeviceExclusive;
|
||
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!(configuration->MouseInterrupt.Type & CmResourceTypeInterrupt)) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
#if defined(NEC_98)
|
||
if (configuration->MouseInterrupt.Flags != CM_RESOURCE_INTERRUPT_LATCHED) {
|
||
configuration->MouseInterrupt.ShareDisposition = CmResourceShareShared;
|
||
}
|
||
#endif // defined(NEC_98)
|
||
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpConfigureDevice: Mouse interrupt config --\n"
|
||
));
|
||
InpPrint((
|
||
1,
|
||
" %s, %s, Irq = %d\n",
|
||
configuration->MouseInterrupt.ShareDisposition == CmResourceShareShared?
|
||
"Sharable" : "NonSharable",
|
||
configuration->MouseInterrupt.Flags == CM_RESOURCE_INTERRUPT_LATCHED?
|
||
"Latched" : "Level Sensitive",
|
||
configuration->MouseInterrupt.u.Interrupt.Vector
|
||
));
|
||
|
||
//
|
||
// Again, if we must check for this condition in IRP_MN_FILTER_RESOURCE_REQUIREMENTS
|
||
//
|
||
#if 0
|
||
//
|
||
// If no port configuration information was found, use the
|
||
// driver defaults.
|
||
//
|
||
if (configuration->PortListCount == 0) {
|
||
|
||
//
|
||
// No port configuration information was found, so use
|
||
// the driver defaults.
|
||
//
|
||
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpConfigureDevice: Using default port config\n"
|
||
));
|
||
|
||
configuration->PortList[0].Type = CmResourceTypePort;
|
||
configuration->PortList[0].Flags = INPORT_PORT_TYPE;
|
||
configuration->PortList[0].Flags = CM_RESOURCE_PORT_IO;
|
||
configuration->PortList[0].ShareDisposition =
|
||
INPORT_REGISTER_SHARE? CmResourceShareShared:
|
||
CmResourceShareDeviceExclusive;
|
||
configuration->PortList[0].u.Port.Start.LowPart =
|
||
INPORT_PHYSICAL_BASE;
|
||
configuration->PortList[0].u.Port.Start.HighPart = 0;
|
||
configuration->PortList[0].u.Port.Length = INPORT_REGISTER_LENGTH;
|
||
|
||
configuration->PortListCount = 1;
|
||
}
|
||
#else
|
||
if (configuration->PortListCount == 0) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
#endif
|
||
|
||
#if defined(NEC_98)
|
||
configuration->PortList[0].u.Port.Length = 1;
|
||
#endif // defined(NEC_98)
|
||
for (i = 0; i < configuration->PortListCount; i++) {
|
||
|
||
InpPrint((
|
||
1,
|
||
" %s, Ports 0x%x - 0x%x\n",
|
||
configuration->PortList[i].ShareDisposition
|
||
== CmResourceShareShared? "Sharable" : "NonSharable",
|
||
configuration->PortList[i].u.Port.Start.LowPart,
|
||
configuration->PortList[i].u.Port.Start.LowPart +
|
||
configuration->PortList[i].u.Port.Length - 1
|
||
));
|
||
}
|
||
|
||
//
|
||
// Set the DeviceRegister, mapping them if necessary
|
||
//
|
||
if (DeviceExtension->Configuration.DeviceRegisters[0] == NULL) {
|
||
if (DeviceExtension->Configuration.UnmapRegistersRequired) {
|
||
InpPrint((1, "INPORT-InpConfigureDevice:Mapping registers\n"));
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpConfigureDevice: Start = 0x%x, Length = 0x%x\n",
|
||
DeviceExtension->Configuration.PortList[0].u.Port.Start,
|
||
DeviceExtension->Configuration.PortList[0].u.Port.Length
|
||
));
|
||
DeviceExtension->Configuration.DeviceRegisters[0] = (PUCHAR)
|
||
MmMapIoSpace(
|
||
DeviceExtension->Configuration.PortList[0].u.Port.Start,
|
||
DeviceExtension->Configuration.PortList[0].u.Port.Length,
|
||
MmNonCached
|
||
);
|
||
} else {
|
||
InpPrint((1, "INPORT-InpConfigureDevice:Not Mapping registers\n"));
|
||
DeviceExtension->Configuration.DeviceRegisters[0] = (PUCHAR)
|
||
DeviceExtension->Configuration.PortList[0].u.Port.Start.LowPart;
|
||
}
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
InpStartDevice(
|
||
IN OUT PDEVICE_EXTENSION DeviceExtension,
|
||
IN PCM_RESOURCE_LIST ResourceList
|
||
)
|
||
{
|
||
PINPORT_CONFIGURATION_INFORMATION configuration;
|
||
NTSTATUS status;
|
||
ULONG dumpData[1],
|
||
dumpCount,
|
||
uniqueErrorValue,
|
||
errorCode;
|
||
|
||
InpPrint((2, "INPORT-InpStartDevice: enter\n"));
|
||
|
||
InpServiceParameters(DeviceExtension,
|
||
&Globals.RegistryPath);
|
||
|
||
status = InpConfigureDevice(DeviceExtension,
|
||
ResourceList);
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
status = InpInitializeHardware(DeviceExtension->Self);
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Allocate the ring buffer for the mouse input data.
|
||
//
|
||
DeviceExtension->InputData =
|
||
ExAllocatePool(
|
||
NonPagedPool,
|
||
DeviceExtension->Configuration.MouseAttributes.InputDataQueueLength
|
||
);
|
||
|
||
if (!DeviceExtension->InputData) {
|
||
|
||
//
|
||
// Could not allocate memory for the mouse data queue.
|
||
//
|
||
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpStartDevice: Could not allocate mouse input data queue\n"
|
||
));
|
||
|
||
//
|
||
// Log an error.
|
||
//
|
||
|
||
dumpData[0] =
|
||
DeviceExtension->Configuration.MouseAttributes.InputDataQueueLength;
|
||
dumpCount = 1;
|
||
|
||
InpLogError(
|
||
DeviceExtension->Self,
|
||
INPORT_NO_BUFFER_ALLOCATED,
|
||
INPORT_ERROR_VALUE_BASE + 30,
|
||
STATUS_INSUFFICIENT_RESOURCES,
|
||
dumpData,
|
||
1
|
||
);
|
||
|
||
}
|
||
|
||
DeviceExtension->DataEnd =
|
||
(PMOUSE_INPUT_DATA) ((PCHAR) (DeviceExtension->InputData)
|
||
+ DeviceExtension->Configuration.MouseAttributes.InputDataQueueLength);
|
||
|
||
//
|
||
// Zero the mouse input data ring buffer.
|
||
//
|
||
|
||
RtlZeroMemory(
|
||
DeviceExtension->InputData,
|
||
DeviceExtension->Configuration.MouseAttributes.InputDataQueueLength
|
||
);
|
||
|
||
//
|
||
// Initialize the input data queue.
|
||
//
|
||
InpInitializeDataQueue((PVOID) DeviceExtension);
|
||
|
||
//
|
||
// Initialize the port ISR DPC. The ISR DPC is responsible for
|
||
// calling the connected class driver's callback routine to process
|
||
// the input data queue.
|
||
//
|
||
|
||
DeviceExtension->DpcInterlockVariable = -1;
|
||
|
||
KeInitializeSpinLock(&DeviceExtension->SpinLock);
|
||
|
||
KeInitializeDpc(
|
||
&DeviceExtension->IsrDpc,
|
||
(PKDEFERRED_ROUTINE) InportIsrDpc,
|
||
DeviceExtension->Self
|
||
);
|
||
|
||
KeInitializeDpc(
|
||
&DeviceExtension->IsrDpcRetry,
|
||
(PKDEFERRED_ROUTINE) InportIsrDpc,
|
||
DeviceExtension->Self
|
||
);
|
||
|
||
//
|
||
// Initialize the mouse data consumption timer.
|
||
//
|
||
KeInitializeTimer(&DeviceExtension->DataConsumptionTimer);
|
||
|
||
//
|
||
// Initialize the port DPC queue to log overrun and internal
|
||
// driver errors.
|
||
//
|
||
KeInitializeDpc(
|
||
&DeviceExtension->ErrorLogDpc,
|
||
(PKDEFERRED_ROUTINE) InportErrorLogDpc,
|
||
DeviceExtension->Self
|
||
);
|
||
|
||
configuration = &DeviceExtension->Configuration;
|
||
//
|
||
// Initialize and connect the interrupt object for the mouse.
|
||
//
|
||
|
||
status = IoConnectInterrupt(
|
||
&(DeviceExtension->InterruptObject),
|
||
(PKSERVICE_ROUTINE) InportInterruptService,
|
||
(PVOID) DeviceExtension->Self,
|
||
(PKSPIN_LOCK) NULL,
|
||
configuration->MouseInterrupt.u.Interrupt.Vector,
|
||
(KIRQL) configuration->MouseInterrupt.u.Interrupt.Level,
|
||
(KIRQL) configuration->MouseInterrupt.u.Interrupt.Level,
|
||
configuration->MouseInterrupt.Flags
|
||
== CM_RESOURCE_INTERRUPT_LATCHED ? Latched:LevelSensitive,
|
||
(BOOLEAN) (configuration->MouseInterrupt.ShareDisposition
|
||
== CmResourceShareShared),
|
||
configuration->MouseInterrupt.u.Interrupt.Affinity,
|
||
configuration->FloatingSave
|
||
);
|
||
|
||
|
||
InpPrint((2, "INPORT-InpStartDevice: exit (%x)\n", status));
|
||
|
||
return status;
|
||
}
|
||
|
||
VOID
|
||
InpDisableInterrupts(
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called from StartIo synchronously. It touches the
|
||
hardware to disable interrupts.
|
||
|
||
Arguments:
|
||
|
||
Context - Pointer to the device extension.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PUCHAR port;
|
||
PLONG enableCount;
|
||
UCHAR mode;
|
||
|
||
InpPrint((2, "INPORT-InpDisableInterrupts: enter\n"));
|
||
|
||
//
|
||
// Decrement the reference count for device enables.
|
||
//
|
||
|
||
enableCount = &((PDEVICE_EXTENSION) Context)->MouseEnableCount;
|
||
*enableCount = *enableCount - 1;
|
||
|
||
if (*enableCount == 0) {
|
||
|
||
//
|
||
// Get the port register address.
|
||
//
|
||
|
||
port = ((PDEVICE_EXTENSION) Context)->Configuration.DeviceRegisters[0];
|
||
|
||
#if defined(NEC_98)
|
||
//
|
||
// Mouse Timer Intrrupt Enable
|
||
//
|
||
WRITE_PORT_UCHAR(port + PC98_WritePortC2, (UCHAR)PC98_TimerIntDisable);
|
||
#else // defined(NEC_98)
|
||
//
|
||
// Select the mode register as the current data register.
|
||
//
|
||
|
||
WRITE_PORT_UCHAR((PUCHAR) port, INPORT_MODE_REGISTER);
|
||
|
||
//
|
||
// Read the current mode.
|
||
//
|
||
|
||
mode = READ_PORT_UCHAR((PUCHAR) (port + INPORT_DATA_REGISTER_1));
|
||
|
||
//
|
||
// Rewrite the mode byte with the interrupt disabled.
|
||
//
|
||
|
||
WRITE_PORT_UCHAR(
|
||
(PUCHAR) (port + INPORT_DATA_REGISTER_1),
|
||
(UCHAR) (mode & ~INPORT_DATA_INTERRUPT_ENABLE)
|
||
);
|
||
#endif // defined(NEC_98)
|
||
}
|
||
|
||
InpPrint((2, "INPORT-InpDisableInterrupts: exit\n"));
|
||
|
||
}
|
||
|
||
VOID
|
||
InpEnableInterrupts(
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called from StartIo synchronously. It touches the
|
||
hardware to enable interrupts.
|
||
|
||
Arguments:
|
||
|
||
Context - Pointer to the device extension.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PUCHAR port;
|
||
PLONG enableCount;
|
||
UCHAR mode;
|
||
#if defined(NEC_98)
|
||
UCHAR HzMode;
|
||
#endif // defined(NEC_98)
|
||
|
||
InpPrint((2, "INPORT-InpEnableInterrupts: enter\n"));
|
||
|
||
enableCount = &((PDEVICE_EXTENSION) Context)->MouseEnableCount;
|
||
|
||
if (*enableCount == 0) {
|
||
|
||
//
|
||
// Get the port register address.
|
||
//
|
||
|
||
port = ((PDEVICE_EXTENSION) Context)->Configuration.DeviceRegisters[0];
|
||
|
||
#if defined(NEC_98)
|
||
//
|
||
// Switch to event interrupt mode.
|
||
//
|
||
if (EventStatus) {
|
||
_asm { cli }
|
||
WRITE_PORT_UCHAR((PUCHAR)PC98_ConfigurationPort, PC98_EventIntPort);
|
||
WRITE_PORT_UCHAR((PUCHAR)PC98_ConfigurationDataPort, PC98_EventIntMode);
|
||
_asm { sti }
|
||
}
|
||
|
||
//
|
||
// Reset the Inport chip, leaving interrupts off.
|
||
//
|
||
WRITE_PORT_UCHAR(port + PC98_WriteModePort, PC98_InitializeCommand);
|
||
|
||
//
|
||
// Select the mode register as the current data register.
|
||
// Set the Inport mouse up for quadrature mode,
|
||
// and set the sample rate (i.e., the interrupt Hz rate).
|
||
// Leave interrupts disabled.
|
||
//
|
||
if (EventStatus) {
|
||
HzMode = (((PDEVICE_EXTENSION) Context)->Configuration.HzMode == 0)?
|
||
(UCHAR)PC98_EVENT_MODE_120HZ : (UCHAR)PC98_EVENT_MODE_60HZ;
|
||
} else {
|
||
HzMode = ((PDEVICE_EXTENSION) Context)->Configuration.HzMode;
|
||
}
|
||
|
||
WRITE_PORT_UCHAR(
|
||
(PUCHAR)PC98_WriteTimerPort,
|
||
(UCHAR)(HzMode|INPORT_MODE_QUADRATURE)
|
||
);
|
||
|
||
//
|
||
// Mouse Timer Intrrupt Enable.
|
||
//
|
||
WRITE_PORT_UCHAR(port + PC98_WritePortC2, (UCHAR)PC98_TimerIntEnable);
|
||
#else // defined(NEC_98)
|
||
//
|
||
// Select the mode register as the current data register.
|
||
//
|
||
|
||
WRITE_PORT_UCHAR((PUCHAR) port, INPORT_MODE_REGISTER);
|
||
|
||
//
|
||
// Read the current mode.
|
||
//
|
||
|
||
mode = READ_PORT_UCHAR((PUCHAR) (port + INPORT_DATA_REGISTER_1));
|
||
|
||
//
|
||
// Rewrite the mode byte with the interrupt enabled.
|
||
//
|
||
|
||
WRITE_PORT_UCHAR(
|
||
(PUCHAR) (port + INPORT_DATA_REGISTER_1),
|
||
(UCHAR) (mode | INPORT_DATA_INTERRUPT_ENABLE)
|
||
);
|
||
#endif // defined(NEC_98)
|
||
}
|
||
|
||
//
|
||
// Increment the reference count for device enables.
|
||
//
|
||
|
||
*enableCount = *enableCount + 1;
|
||
|
||
InpPrint((2, "INPORT-InpEnableInterrupts: exit\n"));
|
||
}
|
||
|
||
NTSTATUS
|
||
InpInitializeHardware(
|
||
IN PDEVICE_OBJECT DeviceObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the Inport mouse. Note that this routine is
|
||
only called at initialization time, so synchronization is not required.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
PUCHAR mousePort;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
|
||
InpPrint((2, "INPORT-InpInitializeHardware: enter\n"));
|
||
|
||
//
|
||
// Grab useful configuration parameters from the device extension.
|
||
//
|
||
|
||
deviceExtension = DeviceObject->DeviceExtension;
|
||
mousePort = deviceExtension->Configuration.DeviceRegisters[0];
|
||
|
||
#if defined(NEC_98)
|
||
//
|
||
// Interrupt Disable NEC mouse chip,
|
||
// because mouse interrupt Enable at ROM bios started.
|
||
//
|
||
WRITE_PORT_UCHAR(mousePort + PC98_WriteModePort, PC98_MouseDisable);
|
||
#else // defined(NEC_98)
|
||
//
|
||
// Reset the Inport chip, leaving interrupts off.
|
||
//
|
||
|
||
WRITE_PORT_UCHAR((PUCHAR) mousePort, INPORT_RESET);
|
||
|
||
//
|
||
// Select the mode register as the current data register. Set the
|
||
// Inport mouse up for quadrature mode, and set the sample
|
||
// rate (i.e., the interrupt Hz rate). Leave interrupts disabled.
|
||
//
|
||
|
||
WRITE_PORT_UCHAR((PUCHAR) mousePort, INPORT_MODE_REGISTER);
|
||
WRITE_PORT_UCHAR(
|
||
(PUCHAR) ((ULONG)mousePort + INPORT_DATA_REGISTER_1),
|
||
(UCHAR) (deviceExtension->Configuration.HzMode
|
||
| INPORT_MODE_QUADRATURE)
|
||
);
|
||
#endif // defined(NEC_98)
|
||
|
||
InpPrint((2, "INPORT-InpInitializeHardware: exit\n"));
|
||
|
||
return(status);
|
||
|
||
}
|
||
|
||
VOID
|
||
InpServiceParameters(
|
||
IN PDEVICE_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.
|
||
|
||
DeviceName - Pointer to the Unicode string that will receive
|
||
the port device name.
|
||
|
||
Return Value:
|
||
|
||
None. As a side-effect, sets fields in DeviceExtension->Configuration.
|
||
|
||
--*/
|
||
|
||
{
|
||
PINPORT_CONFIGURATION_INFORMATION configuration;
|
||
PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
|
||
UNICODE_STRING parametersPath;
|
||
HANDLE keyHandle;
|
||
ULONG defaultDataQueueSize = DATA_QUEUE_SIZE;
|
||
ULONG numberOfButtons = MOUSE_NUMBER_OF_BUTTONS;
|
||
USHORT defaultNumberOfButtons = MOUSE_NUMBER_OF_BUTTONS;
|
||
#if defined(NEC_98)
|
||
ULONG sampleRate = PC98_MOUSE_SAMPLE_RATE_120HZ;
|
||
USHORT defaultSampleRate = PC98_MOUSE_SAMPLE_RATE_120HZ;
|
||
ULONG hzMode = PC98_MODE_120HZ;
|
||
USHORT defaultHzMode = PC98_MODE_120HZ;
|
||
#else // defined(NEC_98)
|
||
ULONG sampleRate = MOUSE_SAMPLE_RATE_50HZ;
|
||
USHORT defaultSampleRate = MOUSE_SAMPLE_RATE_50HZ;
|
||
ULONG hzMode = INPORT_MODE_50HZ;
|
||
USHORT defaultHzMode = INPORT_MODE_50HZ;
|
||
#endif // defined(NEC_98)
|
||
UNICODE_STRING defaultUnicodeName;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PWSTR path = NULL;
|
||
USHORT queriesPlusOne = 6;
|
||
#if !defined(NEC_98)
|
||
ULONG defaultInterrupt = INP_DEF_VECTOR, interruptOverride;
|
||
#endif
|
||
|
||
configuration = &DeviceExtension->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) * queriesPlusOne
|
||
);
|
||
|
||
if (!parameters) {
|
||
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpServiceParameters: 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"\\Parameters");
|
||
|
||
parametersPath.Buffer = ExAllocatePool(
|
||
PagedPool,
|
||
parametersPath.MaximumLength
|
||
);
|
||
|
||
if (!parametersPath.Buffer) {
|
||
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpServiceParameters: 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"\\Parameters"
|
||
);
|
||
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpServiceParameters: parameters path is %ws\n",
|
||
parametersPath.Buffer
|
||
));
|
||
|
||
//
|
||
// Form the default pointer port device name, in case it is not
|
||
// specified in the registry.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&defaultUnicodeName,
|
||
DD_POINTER_PORT_BASE_NAME_U
|
||
);
|
||
|
||
//
|
||
// Gather all of the "user specified" information from
|
||
// the registry.
|
||
//
|
||
|
||
parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[0].Name = L"MouseDataQueueSize";
|
||
parameters[0].EntryContext =
|
||
&configuration->MouseAttributes.InputDataQueueLength;
|
||
parameters[0].DefaultType = REG_DWORD;
|
||
parameters[0].DefaultData = &defaultDataQueueSize;
|
||
parameters[0].DefaultLength = sizeof(ULONG);
|
||
|
||
parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[1].Name = L"NumberOfButtons";
|
||
parameters[1].EntryContext = &numberOfButtons;
|
||
parameters[1].DefaultType = REG_DWORD;
|
||
parameters[1].DefaultData = &defaultNumberOfButtons;
|
||
parameters[1].DefaultLength = sizeof(USHORT);
|
||
|
||
parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[2].Name = L"SampleRate";
|
||
parameters[2].EntryContext = &sampleRate;
|
||
parameters[2].DefaultType = REG_DWORD;
|
||
parameters[2].DefaultData = &defaultSampleRate;
|
||
parameters[2].DefaultLength = sizeof(USHORT);
|
||
|
||
parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[3].Name = L"HzMode";
|
||
parameters[3].EntryContext = &hzMode;
|
||
parameters[3].DefaultType = REG_DWORD;
|
||
parameters[3].DefaultData = &defaultHzMode;
|
||
parameters[3].DefaultLength = sizeof(USHORT);
|
||
|
||
#if 0
|
||
parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[4].Name = L"PointerDeviceBaseName";
|
||
parameters[4].EntryContext = DeviceName;
|
||
parameters[4].DefaultType = REG_SZ;
|
||
parameters[4].DefaultData = defaultUnicodeName.Buffer;
|
||
parameters[4].DefaultLength = 0;
|
||
#endif
|
||
|
||
#if !defined(NEC_98)
|
||
parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[4].Name = L"InterruptOverride";
|
||
parameters[4].EntryContext = &configuration->MouseInterrupt.u.Interrupt.Level;
|
||
parameters[4].DefaultType = REG_DWORD;
|
||
parameters[4].DefaultData = &defaultInterrupt;
|
||
parameters[4].DefaultLength = sizeof(ULONG);
|
||
#endif
|
||
|
||
status = RtlQueryRegistryValues(
|
||
RTL_REGISTRY_ABSOLUTE,
|
||
parametersPath.Buffer,
|
||
parameters,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpServiceParameters: RtlQueryRegistryValues failed with 0x%x\n",
|
||
status
|
||
));
|
||
}
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Go ahead and assign driver defaults.
|
||
//
|
||
|
||
configuration->MouseAttributes.InputDataQueueLength =
|
||
defaultDataQueueSize;
|
||
// RtlCopyUnicodeString(DeviceName, &defaultUnicodeName);
|
||
}
|
||
|
||
//
|
||
// Gather all of the "user specified" information from
|
||
// the registry (this time from the devnode)
|
||
//
|
||
|
||
status = IoOpenDeviceRegistryKey(DeviceExtension->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\inport\Parameters key
|
||
//
|
||
ULONG prevDataQueueSize,
|
||
prevNumberOfButtons,
|
||
prevSampleRate,
|
||
prevHzMode;
|
||
#if 0
|
||
UNICODE_STRING prevUnicodeName;
|
||
#endif
|
||
|
||
prevDataQueueSize =
|
||
configuration->MouseAttributes.InputDataQueueLength;
|
||
prevNumberOfButtons = numberOfButtons;
|
||
prevSampleRate = sampleRate;
|
||
prevHzMode = hzMode;
|
||
#if 0
|
||
RtlCopyUnicodeString(prevUnicodeName, DeviceName);
|
||
#endif
|
||
|
||
parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[0].Name = L"MouseDataQueueSize";
|
||
parameters[0].EntryContext =
|
||
&configuration->MouseAttributes.InputDataQueueLength;
|
||
parameters[0].DefaultType = REG_DWORD;
|
||
parameters[0].DefaultData = &prevDataQueueSize;
|
||
parameters[0].DefaultLength = sizeof(ULONG);
|
||
|
||
parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[1].Name = L"NumberOfButtons";
|
||
parameters[1].EntryContext = &numberOfButtons;
|
||
parameters[1].DefaultType = REG_DWORD;
|
||
parameters[1].DefaultData = &prevNumberOfButtons;
|
||
parameters[1].DefaultLength = sizeof(USHORT);
|
||
|
||
parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[2].Name = L"SampleRate";
|
||
parameters[2].EntryContext = &sampleRate;
|
||
parameters[2].DefaultType = REG_DWORD;
|
||
parameters[2].DefaultData = &prevSampleRate;
|
||
parameters[2].DefaultLength = sizeof(USHORT);
|
||
|
||
parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[3].Name = L"HzMode";
|
||
parameters[3].EntryContext = &hzMode;
|
||
parameters[3].DefaultType = REG_DWORD;
|
||
parameters[3].DefaultData = &prevHzMode;
|
||
parameters[3].DefaultLength = sizeof(USHORT);
|
||
|
||
#if 0
|
||
parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[4].Name = L"PointerDeviceBaseName";
|
||
parameters[4].EntryContext = DeviceName;
|
||
parameters[4].DefaultType = REG_SZ;
|
||
parameters[4].DefaultData = prevUnicodeName.Buffer;
|
||
parameters[4].DefaultLength = 0;
|
||
#endif
|
||
|
||
#if !defined(NEC_98)
|
||
parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[4].Name = L"InterruptOverride";
|
||
parameters[4].EntryContext = &configuration->MouseInterrupt.u.Interrupt.Level;
|
||
parameters[4].DefaultType = REG_DWORD;
|
||
parameters[4].DefaultData = &defaultInterrupt;
|
||
parameters[4].DefaultLength = sizeof(ULONG);
|
||
#endif
|
||
|
||
status = RtlQueryRegistryValues(
|
||
RTL_REGISTRY_HANDLE,
|
||
(PWSTR) keyHandle,
|
||
parameters,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpServiceParameters: RtlQueryRegistryValues (via handle) failed (0x%x)\n",
|
||
status
|
||
));
|
||
}
|
||
|
||
ZwClose(keyHandle);
|
||
}
|
||
else {
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpServiceParameters: opening devnode handle failed (0x%x)\n",
|
||
status
|
||
));
|
||
}
|
||
|
||
#if 0
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpServiceParameters: Pointer port base name = %ws\n",
|
||
DeviceName->Buffer
|
||
));
|
||
#endif 0
|
||
|
||
if (configuration->MouseAttributes.InputDataQueueLength == 0) {
|
||
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpServiceParameters: overriding MouseInputDataQueueLength = 0x%x\n",
|
||
configuration->MouseAttributes.InputDataQueueLength
|
||
));
|
||
|
||
configuration->MouseAttributes.InputDataQueueLength =
|
||
defaultDataQueueSize;
|
||
}
|
||
|
||
configuration->MouseAttributes.InputDataQueueLength *=
|
||
sizeof(MOUSE_INPUT_DATA);
|
||
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpServiceParameters: MouseInputDataQueueLength = 0x%x\n",
|
||
configuration->MouseAttributes.InputDataQueueLength
|
||
));
|
||
|
||
configuration->MouseAttributes.NumberOfButtons = (USHORT) numberOfButtons;
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpServiceParameters: NumberOfButtons = %d\n",
|
||
configuration->MouseAttributes.NumberOfButtons
|
||
));
|
||
|
||
configuration->MouseAttributes.SampleRate = (USHORT) sampleRate;
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpServiceParameters: SampleRate = %d\n",
|
||
configuration->MouseAttributes.SampleRate
|
||
));
|
||
|
||
configuration->HzMode = (UCHAR) hzMode;
|
||
InpPrint((
|
||
1,
|
||
"INPORT-InpServiceParameters: HzMode = %d\n",
|
||
configuration->HzMode
|
||
));
|
||
|
||
//
|
||
// Free the allocated memory before returning.
|
||
//
|
||
|
||
if (parametersPath.Buffer)
|
||
ExFreePool(parametersPath.Buffer);
|
||
if (parameters)
|
||
ExFreePool(parameters);
|
||
|
||
}
|
||
#if defined(NEC_98)
|
||
#define ISA_BUS_NODE "\\Registry\\MACHINE\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter\\%d"
|
||
ULONG
|
||
QueryEventMode(
|
||
IN OUT VOID
|
||
)
|
||
{
|
||
ULONG NodeNumber = 0;
|
||
NTSTATUS Status;
|
||
RTL_QUERY_REGISTRY_TABLE parameters[2];
|
||
|
||
UNICODE_STRING invalidBusName;
|
||
UNICODE_STRING targetBusName;
|
||
UNICODE_STRING isaBusName;
|
||
|
||
UCHAR Configuration_Data1[1192];
|
||
ULONG Configuration;
|
||
RTL_QUERY_REGISTRY_TABLE QueryTable[] =
|
||
{
|
||
{NULL,
|
||
RTL_QUERY_REGISTRY_DIRECT,
|
||
L"Configuration Data",
|
||
Configuration_Data1,
|
||
REG_DWORD,
|
||
(PVOID) &Configuration,
|
||
0},
|
||
{NULL, 0, NULL, NULL, REG_NONE, NULL, 0}
|
||
};
|
||
|
||
InpPrint((2,"INPORT-QueryEventMode: enter\n"));
|
||
|
||
//
|
||
// Initialize invalid bus name.
|
||
//
|
||
RtlInitUnicodeString(&invalidBusName,L"BADBUS");
|
||
|
||
//
|
||
// Initialize "ISA" bus name.
|
||
//
|
||
RtlInitUnicodeString(&isaBusName,L"ISA");
|
||
|
||
parameters[0].QueryRoutine = NULL;
|
||
parameters[0].Flags = RTL_QUERY_REGISTRY_REQUIRED |
|
||
RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[0].Name = L"Identifier";
|
||
parameters[0].EntryContext = &targetBusName;
|
||
parameters[0].DefaultType = REG_SZ;
|
||
parameters[0].DefaultData = &invalidBusName;
|
||
parameters[0].DefaultLength = 0;
|
||
|
||
parameters[1].QueryRoutine = NULL;
|
||
parameters[1].Flags = 0;
|
||
parameters[1].Name = NULL;
|
||
parameters[1].EntryContext = NULL;
|
||
|
||
do {
|
||
CHAR AnsiBuffer[512];
|
||
|
||
ANSI_STRING AnsiString;
|
||
UNICODE_STRING registryPath;
|
||
|
||
//
|
||
// Initialize receive buffer.
|
||
//
|
||
targetBusName.Buffer = NULL;
|
||
|
||
//
|
||
// Build path buffer...
|
||
//
|
||
sprintf(AnsiBuffer,ISA_BUS_NODE,NodeNumber);
|
||
RtlInitAnsiString(&AnsiString,AnsiBuffer);
|
||
Status = RtlAnsiStringToUnicodeString(®istryPath,&AnsiString,TRUE);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
//
|
||
// Cannot get memory for registry path(query fails)
|
||
//
|
||
InpPrint((1,"INPORT-QueryEventMode: cannot get registryPath\n"));
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Query it.
|
||
//
|
||
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
||
registryPath.Buffer,
|
||
parameters,
|
||
NULL,
|
||
NULL);
|
||
|
||
if (!NT_SUCCESS(Status) || (targetBusName.Buffer == NULL)) {
|
||
RtlFreeUnicodeString(®istryPath);
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Is this "ISA" node ?
|
||
//
|
||
if (RtlCompareUnicodeString(&targetBusName,&isaBusName,TRUE) == 0) {
|
||
|
||
//
|
||
// Found.
|
||
//
|
||
((PULONG)Configuration_Data1)[0] = 1192;
|
||
RtlQueryRegistryValues(
|
||
RTL_REGISTRY_ABSOLUTE,
|
||
registryPath.Buffer,
|
||
QueryTable,
|
||
NULL,
|
||
NULL);
|
||
RtlFreeUnicodeString(®istryPath);
|
||
|
||
if ((((PCONFIGURATION_DATA) Configuration_Data1)->COM_ID[0] == 0x98) &&
|
||
(((PCONFIGURATION_DATA) Configuration_Data1)->COM_ID[1] == 0x21)) {
|
||
EventStatus = ((PCONFIGURATION_DATA)Configuration_Data1)->EventMouseID.EventMouse;
|
||
}
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Can we find any node for this ??
|
||
//
|
||
if (RtlCompareUnicodeString(&targetBusName,&invalidBusName,TRUE) == 0) {
|
||
//
|
||
// Not found.
|
||
//
|
||
InpPrint((1, "INPORT-QueryEventMode: ISA not found"));
|
||
RtlFreeUnicodeString(®istryPath);
|
||
break;
|
||
}
|
||
|
||
RtlFreeUnicodeString(&targetBusName);
|
||
|
||
//
|
||
// Next node number..
|
||
//
|
||
NodeNumber++;
|
||
|
||
} while (TRUE);
|
||
|
||
if (targetBusName.Buffer) {
|
||
RtlFreeUnicodeString(&targetBusName);
|
||
}
|
||
|
||
InpPrint((2, "INPORT-QueryEventMode: Event Interrupt mode is "));
|
||
if (EventStatus) {
|
||
InpPrint((2, "available\n"));
|
||
} else {
|
||
InpPrint((2, "not available\n"));
|
||
}
|
||
|
||
InpPrint((2,"INPORT-QueryEventMode: exit\n"));
|
||
|
||
return EventStatus;
|
||
}
|
||
|
||
VOID
|
||
InportReinitializeHardware (
|
||
PWORK_QUEUE_ITEM Item
|
||
)
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PDEVICE_OBJECT DeviceObject;
|
||
PDEVICE_EXTENSION DeviceExtension;
|
||
PUCHAR port;
|
||
UCHAR HzMode;
|
||
|
||
DeviceObject = Globals.DeviceObject;
|
||
InpPrint((2,"INPORT-InportReinitializeHardware: enter\n"));
|
||
|
||
status = InpInitializeHardware(DeviceObject);
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
DeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
||
InpEnableInterrupts(DeviceExtension);
|
||
|
||
//
|
||
// Enable interrupt of hibernation/sleep for NEC_98.
|
||
//
|
||
//
|
||
// Get the port register address.
|
||
//
|
||
port = DeviceExtension->Configuration.DeviceRegisters[0];
|
||
|
||
//
|
||
// Switch to event interrupt mode.
|
||
//
|
||
if (EventStatus) {
|
||
_asm { cli }
|
||
WRITE_PORT_UCHAR((PUCHAR)PC98_ConfigurationPort, PC98_EventIntPort);
|
||
WRITE_PORT_UCHAR((PUCHAR)PC98_ConfigurationDataPort, PC98_EventIntMode);
|
||
_asm { sti }
|
||
}
|
||
|
||
//
|
||
// Reset the Inport chip, leaving interrupts off.
|
||
//
|
||
WRITE_PORT_UCHAR(port + PC98_WriteModePort, PC98_InitializeCommand);
|
||
|
||
//
|
||
// Select the mode register as the current data register.
|
||
// Set the Inport mouse up for quadrature mode,
|
||
// and set the sample rate (i.e., the interrupt Hz rate).
|
||
// Leave interrupts disabled.
|
||
//
|
||
if (EventStatus) {
|
||
HzMode = (DeviceExtension->Configuration.HzMode == 0)?
|
||
(UCHAR)PC98_EVENT_MODE_120HZ : (UCHAR)PC98_EVENT_MODE_60HZ;
|
||
} else {
|
||
HzMode = (UCHAR)(DeviceExtension->Configuration.HzMode|INPORT_MODE_QUADRATURE);
|
||
}
|
||
|
||
WRITE_PORT_UCHAR(
|
||
(PUCHAR)PC98_WriteTimerPort,
|
||
(UCHAR)(HzMode|INPORT_MODE_QUADRATURE)
|
||
);
|
||
|
||
//
|
||
// Mouse Timer Intrrupt Enable.
|
||
//
|
||
WRITE_PORT_UCHAR(port + PC98_WritePortC2, (UCHAR)PC98_TimerIntEnable);
|
||
|
||
}
|
||
else {
|
||
InpPrint((1,"INPORT-InportReinitializeHardware: failed, 0x%x\n", status));
|
||
}
|
||
|
||
ExFreePool(Item);
|
||
InpPrint((2,"INPORT-InportReinitializeHardware: exit\n"));
|
||
|
||
}
|
||
|
||
#endif // defined(NEC_98)
|
||
|
||
#endif
|