2446 lines
70 KiB
C
2446 lines
70 KiB
C
/*++
|
||
|
||
Copyright (c) 1990, 1991, 1992, 1993 Microsoft Corporation
|
||
Copyright (c) 1993 Logitech Inc.
|
||
|
||
Module Name:
|
||
|
||
sermdep.c
|
||
|
||
Abstract:
|
||
|
||
The initialization and hardware-dependent portions of
|
||
the Microsoft serial (i8250) mouse port driver. Modifications
|
||
to support new mice similar to the serial 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.
|
||
|
||
- The serial ballpoint is supported. However, Windows USER does not
|
||
intend (right now) to use the ballpoint in anything except mouse
|
||
emulation mode. In ballpoint mode, there is extra functionality that
|
||
would need to be supported. E.g., the driver would need to pass
|
||
back extra button information from the 4th byte of the ballpoint
|
||
data packet. Windows USER would need/want to allow the user to select
|
||
which buttons are used, what the orientation of the ball is (esp.
|
||
important for lefthanders), sensitivity, and acceleration profile.
|
||
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
#include "stdarg.h"
|
||
#include "stdio.h"
|
||
#include "string.h"
|
||
#include "ntddk.h"
|
||
#include "sermouse.h"
|
||
#include "sermlog.h"
|
||
#include "cseries.h"
|
||
#include "mseries.h"
|
||
#include "debug.h"
|
||
|
||
#ifdef PNP_IDENTIFY
|
||
#include "devdesc.h"
|
||
#endif
|
||
|
||
//
|
||
// Use the alloc_text pragma to specify the driver initialization routines
|
||
// (they can be paged out).
|
||
//
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(INIT,DriverEntry)
|
||
#pragma alloc_text(INIT,SerMouConfiguration)
|
||
#pragma alloc_text(INIT,SerMouInitializeDevice)
|
||
#pragma alloc_text(INIT,SerMouPeripheralCallout)
|
||
#pragma alloc_text(INIT,SerMouPeripheralListCallout)
|
||
#pragma alloc_text(INIT,SerMouServiceParameters)
|
||
#pragma alloc_text(INIT,SerMouInitializeHardware)
|
||
#pragma alloc_text(INIT,SerMouBuildResourceList)
|
||
#endif
|
||
|
||
typedef struct _DEVICE_EXTENSION_LIST_ENTRY {
|
||
LIST_ENTRY ListEntry;
|
||
DEVICE_EXTENSION DeviceExtension;
|
||
|
||
#ifdef PNP_IDENTIFY
|
||
HWDESC_INFO HardwareInfo;
|
||
#endif
|
||
|
||
} DEVICE_EXTENSION_LIST_ENTRY, *PDEVICE_EXTENSION_LIST_ENTRY;
|
||
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the serial (i8250) 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.
|
||
|
||
--*/
|
||
|
||
{
|
||
#define NAME_MAX 256
|
||
|
||
PDEVICE_EXTENSION_LIST_ENTRY tmpDeviceExtension;
|
||
LIST_ENTRY tmpDeviceExtensionList;
|
||
UNICODE_STRING baseDeviceName;
|
||
UNICODE_STRING registryPath;
|
||
WCHAR nameBuffer[NAME_MAX];
|
||
PLIST_ENTRY head;
|
||
|
||
SerMouPrint((1,"\n\nSERMOUSE-SerialMouseInitialize: enter\n"));
|
||
|
||
RtlZeroMemory(nameBuffer, NAME_MAX * sizeof(WCHAR));
|
||
baseDeviceName.Buffer = nameBuffer;
|
||
baseDeviceName.Length = 0;
|
||
baseDeviceName.MaximumLength = NAME_MAX * sizeof(WCHAR);
|
||
|
||
//
|
||
// Need to ensure that the registry path is null-terminated.
|
||
// Allocate pool to hold a null-terminated copy of the path.
|
||
//
|
||
|
||
registryPath.Buffer = ExAllocatePool(
|
||
PagedPool,
|
||
RegistryPath->Length + sizeof(UNICODE_NULL)
|
||
);
|
||
|
||
if (!registryPath.Buffer) {
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerialMouseInitialize: Couldn't allocate pool for registry path\n"
|
||
));
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
registryPath.Length = RegistryPath->Length + sizeof(UNICODE_NULL);
|
||
registryPath.MaximumLength = registryPath.Length;
|
||
|
||
RtlZeroMemory(
|
||
registryPath.Buffer,
|
||
registryPath.Length
|
||
);
|
||
|
||
RtlMoveMemory(
|
||
registryPath.Buffer,
|
||
RegistryPath->Buffer,
|
||
RegistryPath->Length
|
||
);
|
||
|
||
|
||
//
|
||
// Get the configuration information for this driver.
|
||
//
|
||
|
||
InitializeListHead(&tmpDeviceExtensionList);
|
||
SerMouConfiguration(&tmpDeviceExtensionList, ®istryPath, &baseDeviceName);
|
||
|
||
while (!IsListEmpty(&tmpDeviceExtensionList)) {
|
||
|
||
head = RemoveHeadList(&tmpDeviceExtensionList);
|
||
tmpDeviceExtension = CONTAINING_RECORD(head,
|
||
DEVICE_EXTENSION_LIST_ENTRY,
|
||
ListEntry);
|
||
|
||
SerMouInitializeDevice(DriverObject,
|
||
&(tmpDeviceExtension->DeviceExtension),
|
||
®istryPath, &baseDeviceName);
|
||
|
||
ExFreePool(tmpDeviceExtension);
|
||
}
|
||
|
||
ExFreePool(registryPath.Buffer);
|
||
|
||
if (!DriverObject->DeviceObject) {
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
}
|
||
|
||
//
|
||
// Set up the device driver entry points.
|
||
//
|
||
|
||
DriverObject->DriverStartIo = SerialMouseStartIo;
|
||
DriverObject->MajorFunction[IRP_MJ_CREATE] = SerialMouseOpenClose;
|
||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SerialMouseOpenClose;
|
||
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] =
|
||
SerialMouseFlush;
|
||
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
|
||
SerialMouseInternalDeviceControl;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
VOID
|
||
SerMouInitializeDevice(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_EXTENSION TmpDeviceExtension,
|
||
IN PUNICODE_STRING RegistryPath,
|
||
IN PUNICODE_STRING BaseDeviceName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the device for the given device
|
||
extension.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Supplies the driver object.
|
||
|
||
TmpDeviceExtension - Supplies a temporary device extension for the
|
||
device to initialize.
|
||
|
||
RegistryPath - Supplies the registry path.
|
||
|
||
BaseDeviceName - Supplies the base device name to the device
|
||
to create.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_OBJECT portDeviceObject;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
KIRQL coordinatorIrql = 0;
|
||
ULONG interruptVector;
|
||
KIRQL interruptLevel;
|
||
KAFFINITY affinity;
|
||
PIO_ERROR_LOG_PACKET errorLogEntry;
|
||
ULONG uniqueErrorValue;
|
||
NTSTATUS errorCode = STATUS_SUCCESS;
|
||
ULONG dumpCount = 0;
|
||
PCM_RESOURCE_LIST resources = NULL;
|
||
ULONG resourceListSize = 0;
|
||
BOOLEAN conflictDetected;
|
||
ULONG addressSpace;
|
||
PHYSICAL_ADDRESS cardAddress;
|
||
ULONG i;
|
||
UNICODE_STRING fullDeviceName;
|
||
UNICODE_STRING deviceNameSuffix;
|
||
UNICODE_STRING servicesPath;
|
||
|
||
#ifdef PNP_IDENTIFY
|
||
PHWDESC_INFO hardwareInfo = (PHWDESC_INFO) (TmpDeviceExtension + 1);
|
||
#endif
|
||
|
||
#define DUMP_COUNT 4
|
||
ULONG dumpData[DUMP_COUNT];
|
||
|
||
for (i = 0; i < DUMP_COUNT; i++) {
|
||
dumpData[i] = 0;
|
||
}
|
||
|
||
//
|
||
// Set up space for the port's device object suffix. Note that
|
||
// we overallocate space for the suffix string because it is much
|
||
// easier than figuring out exactly how much space is required.
|
||
// The storage gets freed at the end of driver initialization, so
|
||
// who cares...
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&deviceNameSuffix,
|
||
NULL
|
||
);
|
||
|
||
deviceNameSuffix.MaximumLength = POINTER_PORTS_MAXIMUM * sizeof(WCHAR);
|
||
deviceNameSuffix.MaximumLength += sizeof(UNICODE_NULL);
|
||
|
||
deviceNameSuffix.Buffer = ExAllocatePool(
|
||
PagedPool,
|
||
deviceNameSuffix.MaximumLength
|
||
);
|
||
|
||
if (!deviceNameSuffix.Buffer) {
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerialMouseInitialize: Couldn't allocate string for device object suffix\n"
|
||
));
|
||
|
||
status = STATUS_UNSUCCESSFUL;
|
||
errorCode = SERMOUSE_INSUFFICIENT_RESOURCES;
|
||
uniqueErrorValue = SERIAL_MOUSE_ERROR_VALUE_BASE + 6;
|
||
dumpData[0] = (ULONG) deviceNameSuffix.MaximumLength;
|
||
dumpCount = 1;
|
||
goto SerialMouseInitializeExit;
|
||
|
||
}
|
||
|
||
RtlZeroMemory(
|
||
deviceNameSuffix.Buffer,
|
||
deviceNameSuffix.MaximumLength
|
||
);
|
||
|
||
//
|
||
// Set up space for the port's full device object name.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&fullDeviceName,
|
||
NULL
|
||
);
|
||
|
||
fullDeviceName.MaximumLength = sizeof(L"\\Device\\") +
|
||
BaseDeviceName->Length +
|
||
deviceNameSuffix.MaximumLength;
|
||
|
||
|
||
fullDeviceName.Buffer = ExAllocatePool(
|
||
PagedPool,
|
||
fullDeviceName.MaximumLength
|
||
);
|
||
|
||
if (!fullDeviceName.Buffer) {
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerialMouseInitialize: Couldn't allocate string for device object name\n"
|
||
));
|
||
|
||
status = STATUS_UNSUCCESSFUL;
|
||
errorCode = SERMOUSE_INSUFFICIENT_RESOURCES;
|
||
uniqueErrorValue = SERIAL_MOUSE_ERROR_VALUE_BASE + 8;
|
||
dumpData[0] = (ULONG) fullDeviceName.MaximumLength;
|
||
dumpCount = 1;
|
||
goto SerialMouseInitializeExit;
|
||
|
||
}
|
||
|
||
RtlZeroMemory(
|
||
fullDeviceName.Buffer,
|
||
fullDeviceName.MaximumLength
|
||
);
|
||
RtlAppendUnicodeToString(
|
||
&fullDeviceName,
|
||
L"\\Device\\"
|
||
);
|
||
RtlAppendUnicodeToString(
|
||
&fullDeviceName,
|
||
BaseDeviceName->Buffer
|
||
);
|
||
|
||
for (i = 0; i < POINTER_PORTS_MAXIMUM; i++) {
|
||
|
||
//
|
||
// Append the suffix to the device object name string. E.g., turn
|
||
// \Device\PointerPort into \Device\PointerPort0. Then we attempt
|
||
// to create the device object. If the device object already
|
||
// exists (because it was already created by another port driver),
|
||
// increment the suffix and try again.
|
||
//
|
||
|
||
status = RtlIntegerToUnicodeString(
|
||
i,
|
||
10,
|
||
&deviceNameSuffix
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
break;
|
||
}
|
||
|
||
RtlAppendUnicodeStringToString(
|
||
&fullDeviceName,
|
||
&deviceNameSuffix
|
||
);
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerialMouseInitialize: Creating device object named %ws\n",
|
||
fullDeviceName.Buffer
|
||
));
|
||
|
||
//
|
||
// Create a non-exclusive device object for the serial mouse
|
||
// port device.
|
||
//
|
||
|
||
status = IoCreateDevice(
|
||
DriverObject,
|
||
sizeof(DEVICE_EXTENSION),
|
||
&fullDeviceName,
|
||
FILE_DEVICE_SERIAL_MOUSE_PORT,
|
||
0,
|
||
FALSE,
|
||
&portDeviceObject
|
||
);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// We've successfully created a device object.
|
||
//
|
||
|
||
TmpDeviceExtension->UnitId = (USHORT) i;
|
||
break;
|
||
} else {
|
||
|
||
//
|
||
// We'll increment the suffix and try again. Note that we reset
|
||
// the length of the string here to get back to the beginning
|
||
// of the suffix portion of the name. Do not bother to
|
||
// zero the suffix, though, because the string for the
|
||
// incremented suffix will be at least as long as the previous
|
||
// one.
|
||
//
|
||
|
||
fullDeviceName.Length -= deviceNameSuffix.Length;
|
||
}
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerialMouseInitialize: Could not create port device object = %ws\n",
|
||
fullDeviceName.Buffer
|
||
));
|
||
errorCode = SERMOUSE_INSUFFICIENT_RESOURCES;
|
||
uniqueErrorValue = SERIAL_MOUSE_ERROR_VALUE_BASE + 10;
|
||
dumpData[0] = (ULONG) i;
|
||
dumpCount = 1;
|
||
goto SerialMouseInitializeExit;
|
||
}
|
||
|
||
//
|
||
// Do buffered I/O. I.e., the I/O system will copy to/from user data
|
||
// from/to a system buffer.
|
||
//
|
||
|
||
portDeviceObject->Flags |= DO_BUFFERED_IO;
|
||
|
||
//
|
||
// Set up the device extension.
|
||
//
|
||
|
||
deviceExtension =
|
||
(PDEVICE_EXTENSION) portDeviceObject->DeviceExtension;
|
||
*deviceExtension = *TmpDeviceExtension;
|
||
deviceExtension->DeviceObject = portDeviceObject;
|
||
|
||
//
|
||
// Set up the device resource list prior to reporting resource usage.
|
||
//
|
||
|
||
SerMouBuildResourceList(deviceExtension, &resources, &resourceListSize);
|
||
|
||
//
|
||
// Report resource usage for the registry.
|
||
//
|
||
|
||
IoReportResourceUsage(
|
||
BaseDeviceName,
|
||
DriverObject,
|
||
NULL,
|
||
0,
|
||
portDeviceObject,
|
||
resources,
|
||
resourceListSize,
|
||
FALSE,
|
||
&conflictDetected
|
||
);
|
||
|
||
if (conflictDetected) {
|
||
|
||
//
|
||
// Some other device already owns the ports or interrupts.
|
||
// Fatal error.
|
||
//
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerialMouseInitialize: Resource usage conflict\n"
|
||
));
|
||
|
||
//
|
||
// Log an error.
|
||
//
|
||
|
||
errorCode = SERMOUSE_RESOURCE_CONFLICT;
|
||
uniqueErrorValue = SERIAL_MOUSE_ERROR_VALUE_BASE + 15;
|
||
dumpData[0] = (ULONG)
|
||
resources->List[0].PartialResourceList.PartialDescriptors[0].u.Interrupt.Level;
|
||
dumpData[1] = (ULONG)
|
||
resources->List[0].PartialResourceList.PartialDescriptors[0].u.Interrupt.Vector;
|
||
dumpData[2] = (ULONG)
|
||
resources->List[0].PartialResourceList.PartialDescriptors[1].u.Interrupt.Level;
|
||
dumpData[3] = (ULONG)
|
||
resources->List[0].PartialResourceList.PartialDescriptors[1].u.Interrupt.Vector;
|
||
dumpCount = 4;
|
||
|
||
goto SerialMouseInitializeExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Map the serial mouse controller registers.
|
||
//
|
||
|
||
addressSpace = (deviceExtension->Configuration.PortList[0].Flags
|
||
& CM_RESOURCE_PORT_IO) == CM_RESOURCE_PORT_IO? 1:0;
|
||
|
||
if (!HalTranslateBusAddress(
|
||
deviceExtension->Configuration.InterfaceType,
|
||
deviceExtension->Configuration.BusNumber,
|
||
deviceExtension->Configuration.PortList[0].u.Port.Start,
|
||
&addressSpace,
|
||
&cardAddress
|
||
)) {
|
||
|
||
addressSpace = 1;
|
||
cardAddress.QuadPart = 0;
|
||
}
|
||
|
||
if (!addressSpace) {
|
||
|
||
deviceExtension->Configuration.UnmapRegistersRequired = TRUE;
|
||
deviceExtension->Configuration.DeviceRegisters[0] =
|
||
MmMapIoSpace(
|
||
cardAddress,
|
||
deviceExtension->Configuration.PortList[0].u.Port.Length,
|
||
FALSE
|
||
);
|
||
|
||
} else {
|
||
|
||
deviceExtension->Configuration.UnmapRegistersRequired = FALSE;
|
||
deviceExtension->Configuration.DeviceRegisters[0] =
|
||
(PVOID)cardAddress.LowPart;
|
||
|
||
}
|
||
|
||
if (!deviceExtension->Configuration.DeviceRegisters[0]) {
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerialMouseInitialize: Couldn't map the device registers.\n"
|
||
));
|
||
deviceExtension->Configuration.UnmapRegistersRequired = FALSE;
|
||
status = STATUS_NONE_MAPPED;
|
||
|
||
//
|
||
// Log an error.
|
||
//
|
||
|
||
errorCode = SERMOUSE_REGISTERS_NOT_MAPPED;
|
||
uniqueErrorValue = SERIAL_MOUSE_ERROR_VALUE_BASE + 20;
|
||
dumpData[0] = cardAddress.LowPart;
|
||
dumpCount = 1;
|
||
|
||
goto SerialMouseInitializeExit;
|
||
|
||
} else {
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerialMouseInitialize: Mapped device registers to 0x%x.\n",
|
||
deviceExtension->Configuration.DeviceRegisters[0]
|
||
));
|
||
}
|
||
|
||
//
|
||
// Initialize the serial mouse hardware to default values for the mouse.
|
||
// Note that interrupts remain disabled until the class driver
|
||
// requests a MOUSE_CONNECT internal device control.
|
||
//
|
||
|
||
status = SerMouInitializeHardware(portDeviceObject);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerialMouseInitialize: Could not initialize hardware\n"
|
||
));
|
||
goto SerialMouseInitializeExit;
|
||
}
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerialMouseInitialize: Could not allocate mouse input data queue\n"
|
||
));
|
||
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
//
|
||
// Log an error.
|
||
//
|
||
|
||
errorCode = SERMOUSE_NO_BUFFER_ALLOCATED;
|
||
uniqueErrorValue = SERIAL_MOUSE_ERROR_VALUE_BASE + 30;
|
||
dumpData[0] =
|
||
deviceExtension->Configuration.MouseAttributes.InputDataQueueLength;
|
||
dumpCount = 1;
|
||
|
||
goto SerialMouseInitializeExit;
|
||
}
|
||
|
||
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 connection data.
|
||
//
|
||
|
||
deviceExtension->ConnectData.ClassDeviceObject = NULL;
|
||
deviceExtension->ConnectData.ClassService = NULL;
|
||
|
||
//
|
||
// Initialize the input data queue.
|
||
//
|
||
|
||
SerMouInitializeDataQueue((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) SerialMouseIsrDpc,
|
||
portDeviceObject
|
||
);
|
||
|
||
KeInitializeDpc(
|
||
&deviceExtension->IsrDpcRetry,
|
||
(PKDEFERRED_ROUTINE) SerialMouseIsrDpc,
|
||
portDeviceObject
|
||
);
|
||
|
||
//
|
||
// 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) SerialMouseErrorLogDpc,
|
||
portDeviceObject
|
||
);
|
||
|
||
//
|
||
// From the Hal, get the interrupt vector and level.
|
||
//
|
||
|
||
interruptVector = HalGetInterruptVector(
|
||
deviceExtension->Configuration.InterfaceType,
|
||
deviceExtension->Configuration.BusNumber,
|
||
deviceExtension->Configuration.MouseInterrupt.u.Interrupt.Level,
|
||
deviceExtension->Configuration.MouseInterrupt.u.Interrupt.Vector,
|
||
&interruptLevel,
|
||
&affinity
|
||
);
|
||
|
||
//
|
||
// Initialize and connect the interrupt object for the mouse.
|
||
//
|
||
|
||
status = IoConnectInterrupt(
|
||
&(deviceExtension->InterruptObject),
|
||
(PKSERVICE_ROUTINE) SerialMouseInterruptService,
|
||
(PVOID) portDeviceObject,
|
||
(PKSPIN_LOCK)NULL,
|
||
interruptVector,
|
||
interruptLevel,
|
||
interruptLevel,
|
||
deviceExtension->Configuration.MouseInterrupt.Flags
|
||
== CM_RESOURCE_INTERRUPT_LATCHED ? Latched:LevelSensitive,
|
||
deviceExtension->Configuration.MouseInterrupt.ShareDisposition,
|
||
affinity,
|
||
deviceExtension->Configuration.FloatingSave
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Failed to install. Free up resources before exiting.
|
||
//
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerialMouseInitialize: Could not connect mouse interrupt\n"
|
||
));
|
||
|
||
//
|
||
// Log an error.
|
||
//
|
||
|
||
errorCode = SERMOUSE_NO_INTERRUPT_CONNECTED;
|
||
uniqueErrorValue = SERIAL_MOUSE_ERROR_VALUE_BASE + 40;
|
||
dumpData[0] = interruptLevel;
|
||
dumpCount = 1;
|
||
|
||
goto SerialMouseInitializeExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Once initialization is finished, load the device map information
|
||
// into the registry so that setup can determine which pointer port
|
||
// is active.
|
||
//
|
||
|
||
status = RtlWriteRegistryValue(
|
||
RTL_REGISTRY_DEVICEMAP,
|
||
BaseDeviceName->Buffer,
|
||
fullDeviceName.Buffer,
|
||
REG_SZ,
|
||
RegistryPath->Buffer,
|
||
RegistryPath->Length
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerialMouseInitialize: Could not store name in DeviceMap\n"
|
||
));
|
||
|
||
errorCode = SERMOUSE_NO_DEVICEMAP_CREATED;
|
||
uniqueErrorValue = SERIAL_MOUSE_ERROR_VALUE_BASE + 50;
|
||
dumpCount = 0;
|
||
|
||
goto SerialMouseInitializeExit;
|
||
|
||
} else {
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerialMouseInitialize: Stored name in DeviceMap\n"
|
||
));
|
||
}
|
||
|
||
ASSERT(status == STATUS_SUCCESS);
|
||
|
||
#ifdef PNP_IDENTIFY
|
||
|
||
//
|
||
// Pull off the UNICODE_NULL we appended to the string earlier for this
|
||
// routine
|
||
//
|
||
|
||
servicesPath = *RegistryPath;
|
||
servicesPath.Length -= sizeof(UNICODE_NULL);
|
||
|
||
status = LinkDeviceToDescription(
|
||
&servicesPath,
|
||
&fullDeviceName,
|
||
hardwareInfo->InterfaceType,
|
||
hardwareInfo->InterfaceNumber,
|
||
hardwareInfo->ControllerType,
|
||
hardwareInfo->ControllerNumber,
|
||
hardwareInfo->PeripheralType,
|
||
hardwareInfo->PeripheralNumber
|
||
);
|
||
|
||
#endif
|
||
|
||
if(!NT_SUCCESS(status)) {
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerialMouseInitialize: LinkDeviceToDescription returned "
|
||
"status %#08lx\n",
|
||
status
|
||
));
|
||
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
SerialMouseInitializeExit:
|
||
|
||
//
|
||
// Log an error, if necessary.
|
||
//
|
||
|
||
if (errorCode != STATUS_SUCCESS) {
|
||
errorLogEntry = (PIO_ERROR_LOG_PACKET)
|
||
IoAllocateErrorLogEntry(
|
||
(portDeviceObject == NULL) ?
|
||
(PVOID) DriverObject : (PVOID) portDeviceObject,
|
||
(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 = status;
|
||
for (i = 0; i < dumpCount; i++)
|
||
errorLogEntry->DumpData[i] = dumpData[i];
|
||
|
||
IoWriteErrorLogEntry(errorLogEntry);
|
||
}
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// The initialization failed. Cleanup resources before exiting.
|
||
//
|
||
//
|
||
// Note: No need/way to undo the KeInitializeDpc or
|
||
// KeInitializeTimer calls.
|
||
//
|
||
|
||
if (resources) {
|
||
|
||
//
|
||
// Call IoReportResourceUsage to remove the resources from
|
||
// the map.
|
||
//
|
||
|
||
resources->Count = 0;
|
||
|
||
IoReportResourceUsage(
|
||
BaseDeviceName,
|
||
DriverObject,
|
||
NULL,
|
||
0,
|
||
portDeviceObject,
|
||
resources,
|
||
resourceListSize,
|
||
FALSE,
|
||
&conflictDetected
|
||
);
|
||
|
||
}
|
||
|
||
if (deviceExtension) {
|
||
if (deviceExtension->InterruptObject != NULL)
|
||
IoDisconnectInterrupt(deviceExtension->InterruptObject);
|
||
if (deviceExtension->Configuration.UnmapRegistersRequired) {
|
||
|
||
MmUnmapIoSpace(
|
||
deviceExtension->Configuration.DeviceRegisters[0],
|
||
deviceExtension->Configuration.PortList[0].u.Port.Length
|
||
);
|
||
}
|
||
if (deviceExtension->InputData)
|
||
ExFreePool(deviceExtension->InputData);
|
||
}
|
||
if (portDeviceObject)
|
||
IoDeleteDevice(portDeviceObject);
|
||
}
|
||
|
||
//
|
||
// Free the resource list.
|
||
//
|
||
// N.B. If we ever decide to hang on to the resource list instead,
|
||
// we need to allocate it from non-paged pool (it is now paged pool).
|
||
//
|
||
|
||
if (resources)
|
||
ExFreePool(resources);
|
||
|
||
//
|
||
// Free the unicode strings.
|
||
//
|
||
|
||
if (deviceNameSuffix.MaximumLength != 0)
|
||
ExFreePool(deviceNameSuffix.Buffer);
|
||
if (fullDeviceName.MaximumLength != 0)
|
||
ExFreePool(fullDeviceName.Buffer);
|
||
|
||
|
||
SerMouPrint((1,"SERMOUSE-SerialMouseInitialize: exit\n"));
|
||
|
||
}
|
||
|
||
VOID
|
||
SerialMouseUnload(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
{
|
||
UNREFERENCED_PARAMETER(DriverObject);
|
||
|
||
SerMouPrint((2, "SERMOUSE-SerialMouseUnload: enter\n"));
|
||
SerMouPrint((2, "SERMOUSE-SerialMouseUnload: exit\n"));
|
||
}
|
||
|
||
VOID
|
||
SerMouBuildResourceList(
|
||
IN PDEVICE_EXTENSION DeviceExtension,
|
||
OUT PCM_RESOURCE_LIST *ResourceList,
|
||
OUT PULONG ResourceListSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates a resource list that is used to query or report resource usage.
|
||
|
||
Arguments:
|
||
|
||
DeviceExtension - Pointer to the port's device extension.
|
||
|
||
ResourceList - Pointer to a pointer to the resource list to be allocated
|
||
and filled.
|
||
|
||
ResourceListSize - Pointer to the returned size of the resource
|
||
list (in bytes).
|
||
|
||
Return Value:
|
||
|
||
None. If the call succeeded, *ResourceList points to the built
|
||
resource list and *ResourceListSize is set to the size (in bytes)
|
||
of the resource list; otherwise, *ResourceList is NULL.
|
||
|
||
Note:
|
||
|
||
Memory is allocated here for *ResourceList. It must be
|
||
freed up by the caller, by calling ExFreePool();
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG count = 0;
|
||
PIO_ERROR_LOG_PACKET errorLogEntry;
|
||
ULONG i = 0;
|
||
ULONG j = 0;
|
||
|
||
count += DeviceExtension->Configuration.PortListCount;
|
||
if (DeviceExtension->Configuration.MouseInterrupt.Type
|
||
== CmResourceTypeInterrupt)
|
||
count += 1;
|
||
|
||
*ResourceListSize = sizeof(CM_RESOURCE_LIST) +
|
||
((count - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
||
|
||
*ResourceList = (PCM_RESOURCE_LIST) ExAllocatePool(
|
||
PagedPool,
|
||
*ResourceListSize
|
||
);
|
||
|
||
//
|
||
// Return NULL if the structure could not be allocated.
|
||
// Otherwise, fill in the resource list.
|
||
//
|
||
|
||
if (!*ResourceList) {
|
||
|
||
//
|
||
// Could not allocate memory for the resource list.
|
||
//
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouBuildResourceList: Could not allocate resource list\n"
|
||
));
|
||
|
||
//
|
||
// Log an error.
|
||
//
|
||
|
||
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
|
||
DeviceExtension->DeviceObject,
|
||
sizeof(IO_ERROR_LOG_PACKET)
|
||
+ sizeof(ULONG)
|
||
);
|
||
|
||
if (errorLogEntry != NULL) {
|
||
|
||
errorLogEntry->ErrorCode = SERMOUSE_INSUFFICIENT_RESOURCES;
|
||
errorLogEntry->DumpDataSize = sizeof(ULONG);
|
||
errorLogEntry->SequenceNumber = 0;
|
||
errorLogEntry->MajorFunctionCode = 0;
|
||
errorLogEntry->IoControlCode = 0;
|
||
errorLogEntry->RetryCount = 0;
|
||
errorLogEntry->UniqueErrorValue =
|
||
SERIAL_MOUSE_ERROR_VALUE_BASE + 110;
|
||
errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
|
||
errorLogEntry->DumpData[0] = *ResourceListSize;
|
||
*ResourceListSize = 0;
|
||
|
||
IoWriteErrorLogEntry(errorLogEntry);
|
||
}
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
RtlZeroMemory(
|
||
*ResourceList,
|
||
*ResourceListSize
|
||
);
|
||
|
||
//
|
||
// Concoct one full resource descriptor.
|
||
//
|
||
|
||
(*ResourceList)->Count = 1;
|
||
|
||
(*ResourceList)->List[0].InterfaceType =
|
||
DeviceExtension->Configuration.InterfaceType;
|
||
(*ResourceList)->List[0].BusNumber =
|
||
DeviceExtension->Configuration.BusNumber;
|
||
|
||
//
|
||
// Build the partial resource descriptors for interrupt and port
|
||
// resources from the saved values.
|
||
//
|
||
|
||
(*ResourceList)->List[0].PartialResourceList.Count = count;
|
||
if (DeviceExtension->Configuration.MouseInterrupt.Type
|
||
== CmResourceTypeInterrupt)
|
||
(*ResourceList)->List[0].PartialResourceList.PartialDescriptors[i++] =
|
||
DeviceExtension->Configuration.MouseInterrupt;
|
||
|
||
for (j = 0; j < DeviceExtension->Configuration.PortListCount; j++) {
|
||
(*ResourceList)->List[0].PartialResourceList.PartialDescriptors[i++] =
|
||
DeviceExtension->Configuration.PortList[j];
|
||
}
|
||
|
||
}
|
||
|
||
VOID
|
||
SerMouConfiguration(
|
||
IN OUT PLIST_ENTRY DeviceExtensionList,
|
||
IN PUNICODE_STRING RegistryPath,
|
||
IN PUNICODE_STRING DeviceName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine retrieves the configuration information for the mouse.
|
||
|
||
Arguments:
|
||
|
||
DeviceExtensionList - Pointer to an empty list of device extensions.
|
||
|
||
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, may set DeviceExtension->HardwarePresent.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
INTERFACE_TYPE interfaceType;
|
||
CONFIGURATION_TYPE controllerType = SerialController;
|
||
CONFIGURATION_TYPE peripheralType = PointerPeripheral;
|
||
ULONG i;
|
||
PDEVICE_EXTENSION_LIST_ENTRY deviceExtensionListEntry;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
PLIST_ENTRY current;
|
||
|
||
for (i=0;
|
||
i < MaximumInterfaceType;
|
||
i++) {
|
||
|
||
//
|
||
// Get the hardware registry information for this device.
|
||
//
|
||
|
||
interfaceType = i;
|
||
|
||
status = IoQueryDeviceDescription(&interfaceType,
|
||
NULL,
|
||
&controllerType,
|
||
NULL,
|
||
&peripheralType,
|
||
NULL,
|
||
SerMouPeripheralListCallout,
|
||
(PVOID) DeviceExtensionList);
|
||
}
|
||
|
||
//
|
||
// Get the driver's service parameters from the registry (e.g.,
|
||
// user-configurable data input queue size, etc.). Note that the
|
||
// service parameters can override information from the hardware
|
||
// registry (e.g., the service parameters can specify that
|
||
// the hardware is on the system, regardless of what the
|
||
// detection logic recognized).
|
||
//
|
||
|
||
for (current = DeviceExtensionList->Flink;
|
||
current != DeviceExtensionList;
|
||
current = current->Flink) {
|
||
|
||
deviceExtensionListEntry = CONTAINING_RECORD(current,
|
||
DEVICE_EXTENSION_LIST_ENTRY,
|
||
ListEntry);
|
||
deviceExtension = &(deviceExtensionListEntry->DeviceExtension);
|
||
SerMouServiceParameters(deviceExtension, RegistryPath, DeviceName);
|
||
}
|
||
|
||
if (IsListEmpty(DeviceExtensionList)) {
|
||
|
||
//
|
||
// Get the driver's service parameters from the registry (e.g.,
|
||
// user-configurable data input queue size, etc.). Note that the
|
||
// service parameters can override information from the hardware
|
||
// registry (e.g., the service parameters can specify that
|
||
// the hardware is on the system, regardless of what the
|
||
// detection logic recognized).
|
||
//
|
||
|
||
deviceExtensionListEntry = ExAllocatePool(PagedPool,
|
||
sizeof(DEVICE_EXTENSION_LIST_ENTRY));
|
||
if (!deviceExtensionListEntry) {
|
||
return;
|
||
}
|
||
deviceExtension = &(deviceExtensionListEntry->DeviceExtension);
|
||
RtlZeroMemory(deviceExtension, sizeof(DEVICE_EXTENSION));
|
||
|
||
SerMouServiceParameters(
|
||
deviceExtension,
|
||
RegistryPath,
|
||
DeviceName
|
||
);
|
||
|
||
if (deviceExtension->Configuration.OverrideHardwarePresent !=
|
||
DEFAULT_OVERRIDE_HARDWARE) {
|
||
|
||
//
|
||
// There was no information about a pointer peripheral on a
|
||
// serial controller in the hardware registry, but the driver's
|
||
// service parameters specify that we should assume there is
|
||
// a serial mouse on the system anyway. Attempt to find the
|
||
// hardware registry information for the serial port specified
|
||
// in the override portion of the driver service parameters.
|
||
//
|
||
|
||
for (i=0;
|
||
i < MaximumInterfaceType && !deviceExtension->HardwarePresent;
|
||
i++) {
|
||
|
||
ULONG peripheralNumber =
|
||
deviceExtension->Configuration.OverrideHardwarePresent - 1;
|
||
|
||
//
|
||
// Get the hardware registry information for the serial
|
||
// peripheral specified as the "override".
|
||
//
|
||
|
||
interfaceType = i;
|
||
|
||
status = IoQueryDeviceDescription(
|
||
&interfaceType,
|
||
NULL,
|
||
&controllerType,
|
||
NULL,
|
||
NULL,
|
||
&peripheralNumber,
|
||
SerMouPeripheralCallout,
|
||
(PVOID) deviceExtension
|
||
);
|
||
|
||
if (!deviceExtension->HardwarePresent) {
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouConfiguration: IoQueryDeviceDescription for SerialPeripheral on bus type %d failed\n",
|
||
interfaceType
|
||
));
|
||
}
|
||
}
|
||
|
||
deviceExtension->HardwarePresent = MOUSE_HARDWARE_PRESENT;
|
||
|
||
InsertTailList(DeviceExtensionList,
|
||
&(deviceExtensionListEntry->ListEntry));
|
||
|
||
} else {
|
||
ExFreePool(deviceExtensionListEntry);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Initialize mouse-specific configuration parameters.
|
||
//
|
||
|
||
for (current = DeviceExtensionList->Flink;
|
||
current != DeviceExtensionList;
|
||
current = current->Flink) {
|
||
|
||
deviceExtensionListEntry = CONTAINING_RECORD(current,
|
||
DEVICE_EXTENSION_LIST_ENTRY,
|
||
ListEntry);
|
||
deviceExtension = &(deviceExtensionListEntry->DeviceExtension);
|
||
deviceExtension->Configuration.MouseAttributes.MouseIdentifier =
|
||
MOUSE_SERIAL_HARDWARE;
|
||
}
|
||
}
|
||
|
||
VOID
|
||
SerMouDisableInterrupts(
|
||
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 mask;
|
||
|
||
//
|
||
// 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];
|
||
|
||
//
|
||
// Disable hardware interrupts.
|
||
//
|
||
|
||
WRITE_PORT_UCHAR((PUCHAR) (port + ACE_IER), 0);
|
||
|
||
//
|
||
// Turn off modem control output line 2.
|
||
//
|
||
|
||
mask = READ_PORT_UCHAR((PUCHAR) (port + ACE_MCR));
|
||
WRITE_PORT_UCHAR((PUCHAR) (port + ACE_MCR), (UCHAR)(mask & ~ACE_OUT2));
|
||
}
|
||
}
|
||
|
||
VOID
|
||
SerMouEnableInterrupts(
|
||
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 mask;
|
||
|
||
|
||
enableCount = &((PDEVICE_EXTENSION) Context)->MouseEnableCount;
|
||
|
||
if (*enableCount == 0) {
|
||
|
||
//
|
||
// Get the port register address.
|
||
//
|
||
|
||
port = ((PDEVICE_EXTENSION) Context)->Configuration.DeviceRegisters[0];
|
||
|
||
//
|
||
// Enable the serial mouse's interrupt at the i8250.
|
||
//
|
||
|
||
WRITE_PORT_UCHAR((PUCHAR) (port + ACE_IER), ACE_ERBFI);
|
||
|
||
//
|
||
// Turn on modem control output line 2.
|
||
//
|
||
|
||
mask = READ_PORT_UCHAR((PUCHAR) (port + ACE_MCR));
|
||
WRITE_PORT_UCHAR((PUCHAR) (port + ACE_MCR), (UCHAR)(mask | ACE_OUT2));
|
||
|
||
//
|
||
// Clean possible garbage in uart input buffer.
|
||
//
|
||
|
||
UARTFlushReadBuffer(port);
|
||
}
|
||
|
||
//
|
||
// Increment the reference count for device enables.
|
||
//
|
||
|
||
*enableCount = *enableCount + 1;
|
||
}
|
||
|
||
NTSTATUS
|
||
SerMouInitializeHardware(
|
||
IN PDEVICE_OBJECT DeviceObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the serial mouse/ballpoint. Note that this
|
||
routine is only called at initialization time, so synchronization is
|
||
not required.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if a pointing device is detected, otherwise STATUS_UNSUCCESSFUL
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
PUCHAR port;
|
||
MOUSETYPE mouseType;
|
||
ULONG hardwareButtons;
|
||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||
|
||
SerMouPrint((2, "SERMOUSE-SerMouInitializeHardware: enter\n"));
|
||
|
||
//
|
||
// Grab useful configuration parameters from the device extension.
|
||
//
|
||
|
||
deviceExtension = DeviceObject->DeviceExtension;
|
||
port = deviceExtension->Configuration.DeviceRegisters[0];
|
||
|
||
//
|
||
// Save the UART initial state.
|
||
//
|
||
|
||
SerMouPrint
|
||
((
|
||
2,
|
||
"SERMOUSE-SerMouInitializeHardware: Saving UART state\n"
|
||
));
|
||
|
||
UARTGetState(
|
||
port,
|
||
&deviceExtension->Configuration.UartSaved,
|
||
deviceExtension->Configuration.BaudClock
|
||
);
|
||
|
||
//
|
||
// Disable interrupts at the i8250.
|
||
//
|
||
|
||
SerMouPrint
|
||
((
|
||
2,
|
||
"SERMOUSE-SerMouInitializeHardware: Disabling UART interrupts\n"
|
||
));
|
||
|
||
UARTSetInterruptCtrl(port, 0);
|
||
|
||
|
||
SerMouPrint
|
||
((
|
||
2,
|
||
"SERMOUSE-SerMouInitializeHardware: Setting UART line control\n"
|
||
));
|
||
|
||
if ((mouseType = MSerDetect(port, deviceExtension->Configuration.BaudClock))
|
||
!= NO_MOUSE) {
|
||
status = STATUS_SUCCESS;
|
||
switch (mouseType) {
|
||
case MOUSE_2B:
|
||
deviceExtension->ProtocolHandler =
|
||
MSerSetProtocol(port, MSER_PROTOCOL_MP);
|
||
hardwareButtons = 2;
|
||
deviceExtension->HardwarePresent = MOUSE_HARDWARE_PRESENT;
|
||
break;
|
||
case MOUSE_3B:
|
||
deviceExtension->ProtocolHandler =
|
||
MSerSetProtocol(port, MSER_PROTOCOL_MP);
|
||
hardwareButtons = 3;
|
||
deviceExtension->HardwarePresent = MOUSE_HARDWARE_PRESENT;
|
||
break;
|
||
case BALLPOINT:
|
||
deviceExtension->ProtocolHandler =
|
||
MSerSetProtocol(port, MSER_PROTOCOL_BP);
|
||
deviceExtension->HardwarePresent |= BALLPOINT_HARDWARE_PRESENT;
|
||
deviceExtension->Configuration.MouseAttributes.MouseIdentifier =
|
||
BALLPOINT_SERIAL_HARDWARE;
|
||
hardwareButtons = 2;
|
||
break;
|
||
case MOUSE_Z:
|
||
deviceExtension->ProtocolHandler =
|
||
MSerSetProtocol(port, MSER_PROTOCOL_Z);
|
||
hardwareButtons = 3;
|
||
deviceExtension->HardwarePresent |= WHEELMOUSE_HARDWARE_PRESENT;
|
||
deviceExtension->Configuration.MouseAttributes.MouseIdentifier =
|
||
WHEELMOUSE_SERIAL_HARDWARE;
|
||
break;
|
||
}
|
||
}
|
||
else if (CSerDetect(port, deviceExtension->Configuration.BaudClock,
|
||
&hardwareButtons)) {
|
||
status = STATUS_SUCCESS;
|
||
deviceExtension->ProtocolHandler =
|
||
CSerSetProtocol(port, CSER_PROTOCOL_MM);
|
||
}
|
||
else {
|
||
deviceExtension->ProtocolHandler = NULL;
|
||
hardwareButtons = MOUSE_NUMBER_OF_BUTTONS;
|
||
}
|
||
|
||
|
||
//
|
||
// If the hardware wasn't overridden, set the number of buttons
|
||
// according to the protocol.
|
||
//
|
||
|
||
if (deviceExtension->Configuration.OverrideHardwarePresent == DEFAULT_OVERRIDE_HARDWARE) {
|
||
|
||
deviceExtension->Configuration.MouseAttributes.NumberOfButtons =
|
||
(USHORT) hardwareButtons;
|
||
|
||
}
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Make sure the FIFO is turned off.
|
||
//
|
||
|
||
UARTSetFifo(port, 0);
|
||
|
||
//
|
||
// Clean up anything left in the receive buffer.
|
||
//
|
||
|
||
UARTFlushReadBuffer(port);
|
||
|
||
}
|
||
else {
|
||
|
||
//
|
||
// Restore the hardware to its previous state.
|
||
//
|
||
|
||
UARTSetState(
|
||
port,
|
||
&deviceExtension->Configuration.UartSaved,
|
||
deviceExtension->Configuration.BaudClock
|
||
);
|
||
}
|
||
|
||
SerMouPrint((2, "SERMOUSE-SerMouInitializeHardware: exit\n"));
|
||
|
||
return status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
SerMouPeripheralCallout(
|
||
IN PVOID Context,
|
||
IN PUNICODE_STRING PathName,
|
||
IN INTERFACE_TYPE BusType,
|
||
IN ULONG BusNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
|
||
IN CONFIGURATION_TYPE ControllerType,
|
||
IN ULONG ControllerNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
|
||
IN CONFIGURATION_TYPE PeripheralType,
|
||
IN ULONG PeripheralNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the callout routine sent as a parameter to
|
||
IoQueryDeviceDescription. It grabs the pointer controller and
|
||
peripheral configuration information.
|
||
|
||
Arguments:
|
||
|
||
Context - Context parameter that was passed in by the routine
|
||
that called IoQueryDeviceDescription.
|
||
|
||
PathName - The full pathname for the registry key.
|
||
|
||
BusType - Bus interface type (Isa, Eisa, Mca, etc.).
|
||
|
||
BusNumber - The bus sub-key (0, 1, etc.).
|
||
|
||
BusInformation - Pointer to the array of pointers to the full value
|
||
information for the bus.
|
||
|
||
ControllerType - The controller type (should be SerialController).
|
||
|
||
ControllerNumber - The controller sub-key (0, 1, etc.).
|
||
|
||
ControllerInformation - Pointer to the array of pointers to the full
|
||
value information for the controller key.
|
||
|
||
PeripheralType - The peripheral type (should be PointerPeripheral).
|
||
|
||
PeripheralNumber - The peripheral sub-key.
|
||
|
||
PeripheralInformation - Pointer to the array of pointers to the full
|
||
value information for the peripheral key.
|
||
|
||
|
||
Return Value:
|
||
|
||
None. If successful, will have the following side-effects:
|
||
|
||
- Sets DeviceObject->DeviceExtension->HardwarePresent.
|
||
- Sets configuration fields in
|
||
DeviceObject->DeviceExtension->Configuration.
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
PSERIAL_MOUSE_CONFIGURATION_INFORMATION configuration;
|
||
UNICODE_STRING unicodeIdentifier;
|
||
PUCHAR controllerData;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
ULONG i;
|
||
ULONG listCount;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDescriptor;
|
||
PCM_SERIAL_DEVICE_DATA serialSpecificData;
|
||
ANSI_STRING ansiString;
|
||
BOOLEAN defaultInterruptShare;
|
||
KINTERRUPT_MODE defaultInterruptMode;
|
||
|
||
#ifdef PNP_IDENTIFY
|
||
PHWDESC_INFO hardwareInfo;
|
||
#endif
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouPeripheralCallout: Path @ 0x%x, Bus Type 0x%x, Bus Number 0x%x\n",
|
||
PathName, BusType, BusNumber
|
||
));
|
||
SerMouPrint((
|
||
1,
|
||
" Controller Type 0x%x, Controller Number 0x%x, Controller info @ 0x%x\n",
|
||
ControllerType, ControllerNumber, ControllerInformation
|
||
));
|
||
SerMouPrint((
|
||
1,
|
||
" Peripheral Type 0x%x, Peripheral Number 0x%x, Peripheral info @ 0x%x\n",
|
||
PeripheralType, PeripheralNumber, PeripheralInformation
|
||
));
|
||
|
||
//
|
||
// If we already have the configuration information for the
|
||
// mouse peripheral, just return.
|
||
//
|
||
|
||
deviceExtension = (PDEVICE_EXTENSION) Context;
|
||
|
||
#ifdef PNP_IDENTIFY
|
||
|
||
//
|
||
// Kludge to identify ourselves so that PnP can determine which driver owns
|
||
// which arc device
|
||
//
|
||
|
||
hardwareInfo = (PHWDESC_INFO) ((PDEVICE_EXTENSION) deviceExtension + 1);
|
||
hardwareInfo->InterfaceType = BusType;
|
||
hardwareInfo->InterfaceNumber = BusNumber;
|
||
hardwareInfo->ControllerType = ControllerType;
|
||
hardwareInfo->ControllerNumber = ControllerNumber;
|
||
hardwareInfo->PeripheralType = PeripheralType;
|
||
hardwareInfo->PeripheralNumber = PeripheralNumber;
|
||
|
||
#endif
|
||
|
||
if (deviceExtension->HardwarePresent) {
|
||
|
||
//
|
||
// Future: Change driver to handle multiple port devices
|
||
// (create multiple port device objects).
|
||
//
|
||
|
||
return ( status );
|
||
}
|
||
|
||
configuration = &deviceExtension->Configuration;
|
||
|
||
//
|
||
// If OverrideHardwarePresent is zero, this routine was called
|
||
// as a result of the IoQueryDeviceDescription for serial
|
||
// PointerPeripheral information. Otherwise, it was called as
|
||
// a result of the IoQueryDeviceDescription for generic
|
||
// serial controller information. In the latter case, the
|
||
// mouse-specific code is skipped.
|
||
//
|
||
|
||
if (configuration->OverrideHardwarePresent == 0) {
|
||
|
||
//
|
||
// Get the identifier information for the peripheral. If
|
||
// the peripheral identifier is missing, just return.
|
||
//
|
||
|
||
unicodeIdentifier.Length = (USHORT)
|
||
(*(PeripheralInformation + IoQueryDeviceIdentifier))->DataLength;
|
||
if (unicodeIdentifier.Length == 0) {
|
||
return(status);
|
||
}
|
||
|
||
unicodeIdentifier.MaximumLength = unicodeIdentifier.Length;
|
||
unicodeIdentifier.Buffer = (PWSTR) (((PUCHAR)(*(PeripheralInformation +
|
||
IoQueryDeviceIdentifier))) +
|
||
(*(PeripheralInformation +
|
||
IoQueryDeviceIdentifier))->DataOffset);
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouPeripheralCallout: Mouse type %ws\n",
|
||
unicodeIdentifier.Buffer
|
||
));
|
||
|
||
//
|
||
// Verify that this is a serial mouse or ballpoint.
|
||
//
|
||
|
||
status = RtlUnicodeStringToAnsiString(
|
||
&ansiString,
|
||
&unicodeIdentifier,
|
||
TRUE
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouPeripheralCallout: Could not convert identifier to Ansi\n"
|
||
));
|
||
return(status);
|
||
}
|
||
|
||
if (strstr(ansiString.Buffer, "SERIAL MOUSE")) {
|
||
|
||
//
|
||
// There is a serial mouse/ballpoint.
|
||
//
|
||
|
||
deviceExtension->HardwarePresent = MOUSE_HARDWARE_PRESENT;
|
||
|
||
}
|
||
|
||
RtlFreeAnsiString(&ansiString);
|
||
} else {
|
||
|
||
//
|
||
// Go ahead and assume, because of the service parameter override,
|
||
// that there is serial mouse on this serial controller.
|
||
//
|
||
|
||
if ((ULONG)(configuration->OverrideHardwarePresent - 1) == ControllerNumber) {
|
||
deviceExtension->HardwarePresent = MOUSE_HARDWARE_PRESENT;
|
||
}
|
||
}
|
||
|
||
if (!deviceExtension->HardwarePresent)
|
||
return(status);
|
||
|
||
//
|
||
// Get the bus information.
|
||
//
|
||
|
||
configuration->InterfaceType = BusType;
|
||
configuration->BusNumber = BusNumber;
|
||
configuration->FloatingSave = SERIAL_MOUSE_FLOATING_SAVE;
|
||
|
||
if (BusType == MicroChannel) {
|
||
defaultInterruptShare = TRUE;
|
||
defaultInterruptMode = LevelSensitive;
|
||
} else {
|
||
defaultInterruptShare = SERIAL_MOUSE_INTERRUPT_SHARE;
|
||
defaultInterruptMode = SERIAL_MOUSE_INTERRUPT_MODE;
|
||
}
|
||
|
||
//
|
||
// Look through the resource list for interrupt and port
|
||
// configuration information.
|
||
//
|
||
|
||
if ((*(ControllerInformation + IoQueryDeviceConfigurationData))->DataLength != 0){
|
||
controllerData = ((PUCHAR) (*(ControllerInformation +
|
||
IoQueryDeviceConfigurationData))) +
|
||
(*(ControllerInformation +
|
||
IoQueryDeviceConfigurationData))->DataOffset;
|
||
|
||
controllerData += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
|
||
PartialResourceList);
|
||
|
||
listCount = ((PCM_PARTIAL_RESOURCE_LIST) controllerData)->Count;
|
||
|
||
resourceDescriptor =
|
||
((PCM_PARTIAL_RESOURCE_LIST) controllerData)->PartialDescriptors;
|
||
|
||
for (i = 0; i < listCount; i++, resourceDescriptor++) {
|
||
switch(resourceDescriptor->Type) {
|
||
case CmResourceTypePort:
|
||
|
||
//
|
||
// Copy the port information. Note that we only expect to
|
||
// find one port range for the serial mouse/ballpoint.
|
||
//
|
||
|
||
configuration->PortListCount = 0;
|
||
configuration->PortList[configuration->PortListCount] =
|
||
*resourceDescriptor;
|
||
configuration->PortList[configuration->PortListCount].ShareDisposition =
|
||
SERIAL_MOUSE_REGISTER_SHARE? CmResourceShareShared:
|
||
CmResourceShareDeviceExclusive;
|
||
configuration->PortListCount += 1;
|
||
|
||
break;
|
||
|
||
case CmResourceTypeInterrupt:
|
||
|
||
//
|
||
// Copy the interrupt information.
|
||
//
|
||
|
||
configuration->MouseInterrupt = *resourceDescriptor;
|
||
configuration->MouseInterrupt.ShareDisposition =
|
||
defaultInterruptShare? CmResourceShareShared :
|
||
CmResourceShareDeviceExclusive;
|
||
|
||
break;
|
||
|
||
case CmResourceTypeDeviceSpecific:
|
||
|
||
//
|
||
// Get the clock rate. This is used to determine the
|
||
// divisor for setting the serial baud rate.
|
||
//
|
||
|
||
serialSpecificData =
|
||
(PCM_SERIAL_DEVICE_DATA) (((PUCHAR) resourceDescriptor)
|
||
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
||
configuration->BaudClock =
|
||
serialSpecificData->BaudClock;
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// If no interrupt configuration information was found, use the
|
||
// driver defaults.
|
||
//
|
||
|
||
if (!(configuration->MouseInterrupt.Type & CmResourceTypeInterrupt)) {
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouPeripheralCallout: Using default mouse interrupt config\n"
|
||
));
|
||
|
||
configuration->MouseInterrupt.Type = CmResourceTypeInterrupt;
|
||
configuration->MouseInterrupt.ShareDisposition =
|
||
defaultInterruptShare? CmResourceShareShared :
|
||
CmResourceShareDeviceExclusive;
|
||
configuration->MouseInterrupt.Flags =
|
||
(defaultInterruptMode == Latched)?
|
||
CM_RESOURCE_INTERRUPT_LATCHED :
|
||
CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
|
||
configuration->MouseInterrupt.u.Interrupt.Level = MOUSE_IRQL;
|
||
configuration->MouseInterrupt.u.Interrupt.Vector = MOUSE_VECTOR;
|
||
}
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouPeripheralCallout: Mouse config --\n"
|
||
));
|
||
SerMouPrint((
|
||
1,
|
||
"\t%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
|
||
));
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouPeripheralCallout: Using default port config\n"
|
||
));
|
||
|
||
configuration->PortList[0].Type = CmResourceTypePort;
|
||
configuration->PortList[0].Flags = SERIAL_MOUSE_PORT_TYPE;
|
||
configuration->PortList[0].ShareDisposition =
|
||
SERIAL_MOUSE_REGISTER_SHARE? CmResourceShareShared:
|
||
CmResourceShareDeviceExclusive;
|
||
configuration->PortList[0].u.Port.Start.LowPart =
|
||
SERIAL_MOUSE_PHYSICAL_BASE;
|
||
configuration->PortList[0].u.Port.Start.HighPart = 0;
|
||
configuration->PortList[0].u.Port.Length =
|
||
SERIAL_MOUSE_REGISTER_LENGTH;
|
||
|
||
configuration->PortListCount = 1;
|
||
}
|
||
|
||
for (i = 0; i < configuration->PortListCount; i++) {
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"\t%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
|
||
));
|
||
}
|
||
|
||
//
|
||
// If no baud clock information was found, use the driver defaults.
|
||
//
|
||
|
||
if (configuration->BaudClock == 0) {
|
||
configuration->BaudClock = MOUSE_BAUD_CLOCK;
|
||
}
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"\tBaud clock %ld Hz\n",
|
||
configuration->BaudClock
|
||
));
|
||
|
||
return( status );
|
||
}
|
||
|
||
NTSTATUS
|
||
SerMouPeripheralListCallout(
|
||
IN PVOID Context,
|
||
IN PUNICODE_STRING PathName,
|
||
IN INTERFACE_TYPE BusType,
|
||
IN ULONG BusNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
|
||
IN CONFIGURATION_TYPE ControllerType,
|
||
IN ULONG ControllerNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
|
||
IN CONFIGURATION_TYPE PeripheralType,
|
||
IN ULONG PeripheralNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the callout routine sent as a parameter to
|
||
IoQueryDeviceDescription. It grabs the pointer controller and
|
||
peripheral configuration information.
|
||
|
||
Arguments:
|
||
|
||
Context - Context parameter that was passed in by the routine
|
||
that called IoQueryDeviceDescription.
|
||
|
||
PathName - The full pathname for the registry key.
|
||
|
||
BusType - Bus interface type (Isa, Eisa, Mca, etc.).
|
||
|
||
BusNumber - The bus sub-key (0, 1, etc.).
|
||
|
||
BusInformation - Pointer to the array of pointers to the full value
|
||
information for the bus.
|
||
|
||
ControllerType - The controller type (should be SerialController).
|
||
|
||
ControllerNumber - The controller sub-key (0, 1, etc.).
|
||
|
||
ControllerInformation - Pointer to the array of pointers to the full
|
||
value information for the controller key.
|
||
|
||
PeripheralType - The peripheral type (should be PointerPeripheral).
|
||
|
||
PeripheralNumber - The peripheral sub-key.
|
||
|
||
PeripheralInformation - Pointer to the array of pointers to the full
|
||
value information for the peripheral key.
|
||
|
||
|
||
Return Value:
|
||
|
||
None. If successful, will have the following side-effects:
|
||
|
||
- Sets DeviceObject->DeviceExtension->HardwarePresent.
|
||
- Sets configuration fields in
|
||
DeviceObject->DeviceExtension->Configuration.
|
||
|
||
--*/
|
||
{
|
||
PLIST_ENTRY deviceExtensionList = Context;
|
||
PDEVICE_EXTENSION_LIST_ENTRY deviceExtensionListEntry;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
NTSTATUS status;
|
||
|
||
deviceExtensionListEntry = ExAllocatePool(PagedPool,
|
||
sizeof(DEVICE_EXTENSION_LIST_ENTRY));
|
||
if (!deviceExtensionListEntry) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
deviceExtension = &(deviceExtensionListEntry->DeviceExtension);
|
||
RtlZeroMemory(deviceExtension, sizeof(DEVICE_EXTENSION));
|
||
|
||
status = SerMouPeripheralCallout(deviceExtension, PathName, BusType,
|
||
BusNumber, BusInformation, ControllerType,
|
||
ControllerNumber, ControllerInformation,
|
||
PeripheralType, PeripheralNumber,
|
||
PeripheralInformation);
|
||
|
||
if (deviceExtension->HardwarePresent) {
|
||
|
||
InsertTailList(deviceExtensionList,
|
||
&(deviceExtensionListEntry->ListEntry));
|
||
|
||
} else {
|
||
ExFreePool(deviceExtensionListEntry);
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
VOID
|
||
SerMouServiceParameters(
|
||
IN PDEVICE_EXTENSION DeviceExtension,
|
||
IN PUNICODE_STRING RegistryPath,
|
||
IN PUNICODE_STRING DeviceName
|
||
)
|
||
|
||
/*++
|
||
|
||
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.
|
||
|
||
--*/
|
||
|
||
{
|
||
PSERIAL_MOUSE_CONFIGURATION_INFORMATION configuration;
|
||
PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
|
||
UNICODE_STRING parametersPath;
|
||
ULONG defaultDataQueueSize = DATA_QUEUE_SIZE;
|
||
ULONG numberOfButtons = MOUSE_NUMBER_OF_BUTTONS;
|
||
USHORT defaultNumberOfButtons = MOUSE_NUMBER_OF_BUTTONS;
|
||
ULONG sampleRate = MOUSE_SAMPLE_RATE;
|
||
USHORT defaultSampleRate = MOUSE_SAMPLE_RATE;
|
||
UNICODE_STRING defaultUnicodeName;
|
||
LONG defaultHardwarePresent = DEFAULT_OVERRIDE_HARDWARE;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PWSTR path = NULL;
|
||
ULONG overrideBits, comPort, i;
|
||
USHORT queriesPlusOne = 6;
|
||
BOOLEAN defaultInterruptShare;
|
||
KINTERRUPT_MODE defaultInterruptMode;
|
||
|
||
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) {
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouServiceParameters: 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) {
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouServiceParameters: 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"
|
||
);
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouServiceParameters: 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"PointerDeviceBaseName";
|
||
parameters[3].EntryContext = DeviceName;
|
||
parameters[3].DefaultType = REG_SZ;
|
||
parameters[3].DefaultData = defaultUnicodeName.Buffer;
|
||
parameters[3].DefaultLength = 0;
|
||
|
||
parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[4].Name = L"OverrideHardwareBitstring";
|
||
parameters[4].EntryContext = &configuration->OverrideHardwarePresent;
|
||
parameters[4].DefaultType = REG_DWORD;
|
||
parameters[4].DefaultData = &defaultHardwarePresent;
|
||
parameters[4].DefaultLength = sizeof(LONG);
|
||
|
||
status = RtlQueryRegistryValues(
|
||
RTL_REGISTRY_ABSOLUTE,
|
||
parametersPath.Buffer,
|
||
parameters,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouServiceParameters: RtlQueryRegistryValues failed with 0x%x\n",
|
||
status
|
||
));
|
||
|
||
//
|
||
// Go ahead and assign driver defaults.
|
||
//
|
||
|
||
configuration->MouseAttributes.InputDataQueueLength =
|
||
defaultDataQueueSize;
|
||
configuration->OverrideHardwarePresent = DEFAULT_OVERRIDE_HARDWARE;
|
||
RtlCopyUnicodeString(DeviceName, &defaultUnicodeName);
|
||
}
|
||
|
||
//
|
||
// Check for overrides from the Service Parameters. Allow the
|
||
// information from the Hardware Registry to be overridden. For
|
||
// example, the Service Parameters can specify that the hardware
|
||
// is present on a given COM port, even though the Hardware Registry
|
||
// indicated otherwise.
|
||
//
|
||
|
||
if (configuration->OverrideHardwarePresent != defaultHardwarePresent) {
|
||
if ((!DeviceExtension->HardwarePresent) && (configuration->OverrideHardwarePresent)) {
|
||
|
||
//
|
||
// Behave as if the hardware is on the system, even though
|
||
// this conflicts with the Hardware Registry information. Set
|
||
// the hardware information fields in the device extension to
|
||
// system defaults depending on which COM port was specified
|
||
// by the OverrideHardwareBitstring in the registry. Any field
|
||
// overrides from the Service Parameters will be applied later.
|
||
//
|
||
|
||
for (overrideBits=configuration->OverrideHardwarePresent,comPort=0;
|
||
overrideBits != 0;
|
||
overrideBits >>= 1) {
|
||
|
||
//
|
||
// Get the desired COM port from the override bitstring.
|
||
// A 0x1 implies com1, 0x2 implies com2, 0x4 implies com3,
|
||
// 0x8 implies com4, and so on.
|
||
//
|
||
// NOTE: We really only support com1 and com2 today.
|
||
//
|
||
|
||
comPort += 1;
|
||
if (overrideBits & 1) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Set the common configuration fields.
|
||
//
|
||
|
||
configuration->InterfaceType = SERIAL_MOUSE_INTERFACE_TYPE;
|
||
configuration->BusNumber = SERIAL_MOUSE_BUS_NUMBER;
|
||
configuration->FloatingSave = SERIAL_MOUSE_FLOATING_SAVE;
|
||
configuration->MouseInterrupt.Type = CmResourceTypeInterrupt;
|
||
|
||
if (configuration->InterfaceType == MicroChannel) {
|
||
defaultInterruptShare = TRUE;
|
||
defaultInterruptMode = LevelSensitive;
|
||
} else {
|
||
defaultInterruptShare = SERIAL_MOUSE_INTERRUPT_SHARE;
|
||
defaultInterruptMode = SERIAL_MOUSE_INTERRUPT_MODE;
|
||
}
|
||
|
||
configuration->MouseInterrupt.ShareDisposition =
|
||
defaultInterruptShare? CmResourceShareShared :
|
||
CmResourceShareDeviceExclusive;
|
||
configuration->MouseInterrupt.Flags =
|
||
(defaultInterruptMode == Latched)?
|
||
CM_RESOURCE_INTERRUPT_LATCHED :
|
||
CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
|
||
|
||
configuration->PortList[0].Type = CmResourceTypePort;
|
||
configuration->PortList[0].Flags = SERIAL_MOUSE_PORT_TYPE;
|
||
configuration->PortList[0].ShareDisposition =
|
||
SERIAL_MOUSE_REGISTER_SHARE? CmResourceShareShared:
|
||
CmResourceShareDeviceExclusive;
|
||
configuration->PortList[0].u.Port.Start.HighPart = 0;
|
||
configuration->PortList[0].u.Port.Length =
|
||
SERIAL_MOUSE_REGISTER_LENGTH;
|
||
|
||
configuration->PortListCount = 1;
|
||
|
||
switch (comPort) {
|
||
case 2:
|
||
|
||
//
|
||
// Use com2 for the mouse.
|
||
//
|
||
|
||
configuration->MouseInterrupt.u.Interrupt.Level =
|
||
MOUSE_COM2_IRQL;
|
||
configuration->MouseInterrupt.u.Interrupt.Vector =
|
||
MOUSE_COM2_VECTOR;
|
||
configuration->PortList[0].u.Port.Start.LowPart =
|
||
SERIAL_MOUSE_COM2_PHYSICAL_BASE;
|
||
break;
|
||
|
||
case 1:
|
||
default:
|
||
|
||
//
|
||
// Assume com1 for the mouse, unless com2 was specified.
|
||
//
|
||
|
||
comPort = 1;
|
||
configuration->MouseInterrupt.u.Interrupt.Level =
|
||
MOUSE_COM1_IRQL;
|
||
configuration->MouseInterrupt.u.Interrupt.Vector =
|
||
MOUSE_COM1_VECTOR;
|
||
configuration->PortList[0].u.Port.Start.LowPart =
|
||
SERIAL_MOUSE_COM1_PHYSICAL_BASE;
|
||
break;
|
||
}
|
||
|
||
configuration->OverrideHardwarePresent = comPort;
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouServiceParameters: Overriding hardware registry --\n"
|
||
));
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouServiceParameters: Mouse config --\n"
|
||
));
|
||
SerMouPrint((
|
||
1,
|
||
"\t%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
|
||
));
|
||
|
||
for (i = 0; i < configuration->PortListCount; i++) {
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"\t%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
|
||
));
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if ((DeviceExtension->HardwarePresent) ||
|
||
(configuration->OverrideHardwarePresent != defaultHardwarePresent)) {
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouServiceParameters: Pointer port base name = %ws\n",
|
||
DeviceName->Buffer
|
||
));
|
||
|
||
if (configuration->MouseAttributes.InputDataQueueLength == 0) {
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouServiceParameters: overriding MouseInputDataQueueLength = 0x%x\n",
|
||
configuration->MouseAttributes.InputDataQueueLength
|
||
));
|
||
|
||
configuration->MouseAttributes.InputDataQueueLength =
|
||
defaultDataQueueSize;
|
||
}
|
||
|
||
configuration->MouseAttributes.InputDataQueueLength *=
|
||
sizeof(MOUSE_INPUT_DATA);
|
||
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouServiceParameters: MouseInputDataQueueLength = 0x%x\n",
|
||
configuration->MouseAttributes.InputDataQueueLength
|
||
));
|
||
|
||
configuration->MouseAttributes.NumberOfButtons = (USHORT) numberOfButtons;
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouServiceParameters: NumberOfButtons = %d\n",
|
||
configuration->MouseAttributes.NumberOfButtons
|
||
));
|
||
|
||
configuration->MouseAttributes.SampleRate = (USHORT) sampleRate;
|
||
SerMouPrint((
|
||
1,
|
||
"SERMOUSE-SerMouServiceParameters: SampleRate = %d\n",
|
||
configuration->MouseAttributes.SampleRate
|
||
));
|
||
}
|
||
|
||
//
|
||
// Free the allocated memory before returning.
|
||
//
|
||
|
||
if (parametersPath.Buffer)
|
||
ExFreePool(parametersPath.Buffer);
|
||
if (parameters)
|
||
ExFreePool(parameters);
|
||
|
||
}
|