|
|
#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
|