#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