#if defined(i386) /*++ Copyright (c) 1990, 1991, 1992, 1993 Microsoft Corporation Copyright (c) 1992 Logitech Inc. Module Name: busmdep.c Abstract: The initialization and hardware-dependent portions of a Bus mouse port driver. Modifications to support new mice similar to the bus 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 "busmouse.h" #include "busmlog.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,BusConfiguration) #pragma alloc_text(INIT,BusPeripheralCallout) #pragma alloc_text(INIT,BusServiceParameters) #pragma alloc_text(INIT,BusInitializeHardware) #pragma alloc_text(INIT,BusBuildResourceList) #endif NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: This routine initializes the Bus 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. --*/ { PDEVICE_OBJECT portDeviceObject = NULL; PDEVICE_EXTENSION deviceExtension = NULL; DEVICE_EXTENSION tmpDeviceExtension; NTSTATUS status = STATUS_SUCCESS; KIRQL coordinatorIrql = 0; ULONG interruptVector; KIRQL interruptLevel; KAFFINITY affinity; PIO_ERROR_LOG_PACKET errorLogEntry; ULONG uniqueErrorValue; ULONG dumpCount = 0; NTSTATUS errorCode = STATUS_SUCCESS; PCM_RESOURCE_LIST resources = NULL; ULONG resourceListSize = 0; BOOLEAN conflictDetected; ULONG addressSpace; PHYSICAL_ADDRESS cardAddress; ULONG i; UNICODE_STRING fullDeviceName; UNICODE_STRING baseDeviceName; UNICODE_STRING deviceNameSuffix; UNICODE_STRING registryPath; #define NAME_MAX 256 WCHAR nameBuffer[NAME_MAX]; #define DUMP_COUNT 4 ULONG dumpData[DUMP_COUNT]; BusPrint((1,"\n\nBusInitialize: enter\n")); // // Zero-initialize various structures. // RtlZeroMemory(&tmpDeviceExtension, sizeof(tmpDeviceExtension)); for (i = 0; i < DUMP_COUNT; i++) dumpData[i] = 0; fullDeviceName.MaximumLength = 0; deviceNameSuffix.MaximumLength = 0; registryPath.MaximumLength = 0; RtlZeroMemory(nameBuffer, sizeof(nameBuffer)); baseDeviceName.Buffer = nameBuffer; baseDeviceName.Length = 0; baseDeviceName.MaximumLength = sizeof(nameBuffer); // // 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) { BusPrint(( 1, "BUSMOUSE-BusInitialize: Couldn't allocate pool for registry path\n" )); status = STATUS_UNSUCCESSFUL; errorCode = BUSMOUSE_INSUFFICIENT_RESOURCES; uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 2; dumpData[0] = (ULONG) RegistryPath->Length + sizeof(UNICODE_NULL); dumpCount = 1; goto BusInitializeExit; } else { 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. // BusConfiguration(&tmpDeviceExtension, ®istryPath, &baseDeviceName); if (tmpDeviceExtension.HardwarePresent == FALSE) { // // There is no Bus mouse attached. Return an unsuccessful status. // BusPrint((1,"BusInitialize: No mouse attached.\n")); status = STATUS_NO_SUCH_DEVICE; errorCode = BUSMOUSE_NO_SUCH_DEVICE; uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 4; dumpCount = 0; goto BusInitializeExit; } // // 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) + sizeof(UNICODE_NULL); deviceNameSuffix.Buffer = ExAllocatePool( PagedPool, deviceNameSuffix.MaximumLength ); if (!deviceNameSuffix.Buffer) { BusPrint(( 1, "BusInitialize: Couldn't allocate string for device object suffix\n" )); status = STATUS_UNSUCCESSFUL; errorCode = BUSMOUSE_INSUFFICIENT_RESOURCES; uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 6; dumpData[0] = (ULONG) deviceNameSuffix.MaximumLength; dumpCount = 1; goto BusInitializeExit; } 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) { BusPrint(( 1, "BusInitialize: Couldn't allocate string for device object name\n" )); status = STATUS_UNSUCCESSFUL; errorCode = BUSMOUSE_INSUFFICIENT_RESOURCES; uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 8; dumpData[0] = (ULONG) fullDeviceName.MaximumLength; dumpCount = 1; goto BusInitializeExit; } 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 ); BusPrint(( 1, "BusInitialize: Creating device object named %ws\n", fullDeviceName.Buffer )); // // Create device object for the Bus mouse port device. // status = IoCreateDevice( DriverObject, sizeof(DEVICE_EXTENSION), &fullDeviceName, FILE_DEVICE_BUS_PORT, 0, FALSE, &portDeviceObject ); if (NT_SUCCESS(status)) { // // We've successfully created a device object. // 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)) { BusPrint(( 1, "BusInitialize: Could not create port device object = %ws\n", fullDeviceName.Buffer )); errorCode = BUSMOUSE_INSUFFICIENT_RESOURCES; uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 10; dumpData[0] = (ULONG) i; dumpCount = 1; goto BusInitializeExit; } // // 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. // BusBuildResourceList(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. // BusPrint(( 1, "BusInitialize: Resource usage conflict\n" )); // // Log an error. // errorCode = BUSMOUSE_RESOURCE_CONFLICT; uniqueErrorValue = BUSMOUSE_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 BusInitializeExit; } // // Map the Bus 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]) { BusPrint(( 1, "BusInitialize: Couldn't map the device registers.\n" )); deviceExtension->Configuration.UnmapRegistersRequired = FALSE; status = STATUS_NONE_MAPPED; // // Log an error. // errorCode = BUSMOUSE_REGISTERS_NOT_MAPPED; uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 20; dumpData[0] = cardAddress.LowPart; dumpCount = 1; goto BusInitializeExit; } // // Initialize the Bus hardware to default values for the mouse. Note // that interrupts remain disabled until the class driver // requests a MOUSE_CONNECT internal device control. // status = BusInitializeHardware(portDeviceObject); if (!NT_SUCCESS(status)) { BusPrint(( 1, "BusInitialize: Could not initialize hardware\n" )); goto BusInitializeExit; } // // 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. // BusPrint(( 1, "BusInitialize: Could not allocate mouse input data queue\n" )); status = STATUS_INSUFFICIENT_RESOURCES; // // Log an error. // errorCode = BUSMOUSE_NO_BUFFER_ALLOCATED; uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 30; dumpData[0] = deviceExtension->Configuration.MouseAttributes.InputDataQueueLength; dumpCount = 1; goto BusInitializeExit; } 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. // BusInitializeDataQueue((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) DBusIsrDpc, portDeviceObject ); KeInitializeDpc( &deviceExtension->IsrDpcRetry, (PKDEFERRED_ROUTINE) DBusIsrDpc, 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) BusErrorLogDpc, 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) DBusInterruptService, (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. // BusPrint(( 1, "BusInitialize: Could not connect mouse interrupt\n" )); // // Log an error. // errorCode = BUSMOUSE_NO_INTERRUPT_CONNECTED; uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 40; dumpData[0] = interruptLevel; dumpCount = 1; goto BusInitializeExit; } // // 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)) { BusPrint(( 1, "BusInitialize: Could not store name in DeviceMap\n" )); errorCode = BUSMOUSE_NO_DEVICEMAP_CREATED; uniqueErrorValue = BUSMOUSE_ERROR_VALUE_BASE + 50; dumpCount = 0; goto BusInitializeExit; } else { BusPrint(( 1, "BusInitialize: Stored name in DeviceMap\n" )); } #ifdef PNP_IDENTIFY LinkDeviceToDescription( RegistryPath, &fullDeviceName, deviceExtension->Configuration.InterfaceType, deviceExtension->Configuration.BusNumber, deviceExtension->Configuration.ControllerType, deviceExtension->Configuration.ControllerNumber, deviceExtension->Configuration.PeripheralType, deviceExtension->Configuration.PeripheralNumber ); #endif ASSERT(status == STATUS_SUCCESS); // // Set up the device driver entry points. // DriverObject->DriverStartIo = DBusStartIo; DriverObject->MajorFunction[IRP_MJ_CREATE] = DBusOpenClose; DriverObject->MajorFunction[IRP_MJ_CLOSE] = DBusOpenClose; DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS]= DBusFlush; DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = DBusInternalDeviceControl; // // NOTE: Don't allow this driver to unload. Otherwise, we would set // DriverObject->DriverUnload = DBusUnload. // BusInitializeExit: // // 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); if (registryPath.MaximumLength != 0) ExFreePool(registryPath.Buffer); BusPrint((1,"BusInitialize: exit\n")); return(status); } BOOLEAN DBusInterruptService( 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; UCHAR previousButtons; PUCHAR port; UCHAR scratch; UCHAR status; UNREFERENCED_PARAMETER(Interrupt); BusPrint((3, "BusInterruptService: enter\n")); // // Get the device extension. // deviceObject = (PDEVICE_OBJECT) Context; deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension; // // Quit if the interrupt is not expected. // There is a problem right now when we connect the interrupt. It looks // like an interrupt is still registered even if we disabled // the device in the BusInitializeHardware routine. // if (deviceExtension->MouseEnableCount == 0) { BusPrint(( 1, "BusInterruptService: Received interrupt with hardware disabled\n")); return TRUE; } // // Get the Bus mouse port address. // port = deviceExtension->Configuration.DeviceRegisters[0]; // // 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 Bus hold bit. // WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE, BUS_CONTROL_COUNTER_CAPTURE); // // Read the position and buttons. // // The format is: // // BBBXMMMM // |||||--------- Movement selected by the control register // ||||---------- Not used (state of interrupt enable bit) // |||----------- 1 if button 3 is down (right button) // ||------------ 1 if button 2 is down (middle button) // |------------- 1 if button 1 is down (left button) // // NOTE: Optimize as follows. // // The bus mouse could be used as a clock because it interrupts the // system even if the device didn't move. Change the code to perform // no shifting/data handling in the initial part of the ISR. Process // the data only after the test for a null event. // // // X displacement // WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE, BUS_CONTROL_COUNTER_CAPTURE | BUS_CONTROL_X_LOW); deviceExtension->CurrentInput.LastX = (LONG)(SCHAR) READ_PORT_UCHAR((port + BUS_DATA_PORT_READ))& 0x0F; WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE, BUS_CONTROL_COUNTER_CAPTURE | BUS_CONTROL_X_HIGH); deviceExtension->CurrentInput.LastX |= (LONG)(SCHAR) ((READ_PORT_UCHAR((port + BUS_DATA_PORT_READ)) & 0x0F) << 4); BusPrint((3, "BusInterruptService: X displacement 0x%x\n", (int)deviceExtension->CurrentInput.LastX)); // // Y displacment // WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE, BUS_CONTROL_COUNTER_CAPTURE | BUS_CONTROL_Y_LOW); deviceExtension->CurrentInput.LastY = (LONG)(SCHAR) READ_PORT_UCHAR((port + BUS_DATA_PORT_READ)) & 0x0F; WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE, BUS_CONTROL_COUNTER_CAPTURE | BUS_CONTROL_Y_HIGH); scratch = READ_PORT_UCHAR((port + BUS_DATA_PORT_READ)); deviceExtension->CurrentInput.LastY |= (LONG)(SCHAR) ((scratch & 0x0F) << 4); BusPrint((3, "BusInterruptService: Y displacement 0x%x\n", (int)deviceExtension->CurrentInput.LastY)); // // Invert the button state (down = 1). // scratch = ~scratch; // // 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 & BUS_DATA_BUTTON_1)) && (scratch & BUS_DATA_BUTTON_1)) { deviceExtension->CurrentInput.Buttons |= MOUSE_LEFT_BUTTON_DOWN; } else if ((previousButtons & BUS_DATA_BUTTON_1) && !(scratch & BUS_DATA_BUTTON_1)) { deviceExtension->CurrentInput.Buttons |= MOUSE_LEFT_BUTTON_UP; } if ((!(previousButtons & BUS_DATA_BUTTON_2)) && (scratch & BUS_DATA_BUTTON_2)) { deviceExtension->CurrentInput.Buttons |= MOUSE_MIDDLE_BUTTON_DOWN; } else if ((previousButtons & BUS_DATA_BUTTON_2) && !(scratch & BUS_DATA_BUTTON_2)) { deviceExtension->CurrentInput.Buttons |= MOUSE_MIDDLE_BUTTON_UP; } if ((!(previousButtons & BUS_DATA_BUTTON_3)) && (scratch & BUS_DATA_BUTTON_3)) { deviceExtension->CurrentInput.Buttons |= MOUSE_RIGHT_BUTTON_DOWN; } else if ((previousButtons & BUS_DATA_BUTTON_3) && !(scratch & BUS_DATA_BUTTON_3)) { deviceExtension->CurrentInput.Buttons |= MOUSE_RIGHT_BUTTON_UP; } BusPrint((3, "BusInterruptService: Button state 0x%x\n", deviceExtension->CurrentInput.Buttons)); if (deviceExtension->CurrentInput.Buttons || deviceExtension->CurrentInput.LastX || deviceExtension->CurrentInput.LastY) { deviceExtension->CurrentInput.UnitId = deviceExtension->UnitId; // // Keep track of the state of the mouse buttons for the next // interrupt. // deviceExtension->PreviousButtons = scratch & (BUS_DATA_BUTTON_1|BUS_DATA_BUTTON_2|BUS_DATA_BUTTON_3); // // Clear the Bus hold bit. // WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE, 0x00); // // Write the input data to the queue and request the ISR DPC to // finish processing the interrupt at DISPATCH_LEVEL. // if (!BusWriteDataToQueue( 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. // BusPrint(( 1, "DBusInterruptService: queue overflow\n" )); if (deviceExtension->OkayToLogOverflow) { KeInsertQueueDpc( &deviceExtension->ErrorLogDpc, (PIRP) NULL, (PVOID) (ULONG) BUSMOUSE_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 { BusPrint(( 3, "DBusInterruptService: interrupt without button/motion change\n" )); // // Clear the Bus hold bit. // WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE, 0x00); } BusPrint((3, "DBusInterruptService: exit\n")); return(TRUE); } VOID BusUnload( IN PDRIVER_OBJECT DriverObject ) { UNREFERENCED_PARAMETER(DriverObject); BusPrint((2, "BusUnload: enter\n")); BusPrint((2, "BusUnload: exit\n")); } VOID BusBuildResourceList( 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; BusPrint((2, "BusBuildResourceList: Enter\n")); 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. // BusPrint(( 1, "BusBuildResourceList: 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 = BUSMOUSE_INSUFFICIENT_RESOURCES; errorLogEntry->DumpDataSize = sizeof(ULONG); errorLogEntry->SequenceNumber = 0; errorLogEntry->MajorFunctionCode = 0; errorLogEntry->IoControlCode = 0; errorLogEntry->RetryCount = 0; errorLogEntry->UniqueErrorValue = BUSMOUSE_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]; } BusPrint((2, "BusBuildResourceList: Exit\n")); } VOID BusConfiguration( IN PDEVICE_EXTENSION DeviceExtension, IN PUNICODE_STRING RegistryPath, IN PUNICODE_STRING DeviceName ) /*++ Routine Description: This routine retrieves the configuration information for the mouse. Arguments: DeviceExtension - Pointer to the (temporary) 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, may set DeviceExtension->HardwarePresent. --*/ { NTSTATUS status = STATUS_SUCCESS; PBUS_CONFIGURATION_INFORMATION configuration; INTERFACE_TYPE interfaceType; CONFIGURATION_TYPE controllerType = PointerController; CONFIGURATION_TYPE peripheralType = PointerPeripheral; ULONG i; BusPrint((2, "BusConfiguration: Enter\n")); // Loop through the different interface types (Eisa, Isa, ...) for (i = 0; i < MaximumInterfaceType; i++) { // // Get the registry information for this device. // interfaceType = i; status = IoQueryDeviceDescription(&interfaceType, NULL, &controllerType, NULL, &peripheralType, NULL, BusPeripheralCallout, (PVOID) DeviceExtension); if (DeviceExtension->HardwarePresent) { // // Get the service parameters (e.g., user-configurable // data input queue size, etc.). // BusServiceParameters(DeviceExtension, RegistryPath, DeviceName); configuration = &DeviceExtension->Configuration; // // Initialize mouse-specific configuration parameters. // configuration->MouseAttributes.MouseIdentifier = MOUSE_BUS_HARDWARE; break; } else { BusPrint(( 1, "BusConfiguration: IoQueryDeviceDescription for bus type %d failed\n", interfaceType )); } } BusPrint((2, "BusConfiguration: Exit\n")); } VOID BusDisableInterrupts( 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; // // 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 the interrupts // WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE, BUS_CONTROL_INTERRUPT_DISABLE); } } VOID BusEnableInterrupts( 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; enableCount = &((PDEVICE_EXTENSION) Context)->MouseEnableCount; if (*enableCount == 0) { // // Get the port register address. // port = ((PDEVICE_EXTENSION) Context)->Configuration.DeviceRegisters[0]; // // Enable the interrupts // WRITE_PORT_UCHAR((PUCHAR) port + BUS_CONTROL_PORT_WRITE, 0); } // // Increment the reference count for device enables. // *enableCount = *enableCount + 1; } NTSTATUS BusInitializeHardware( IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This routine initializes the Bus 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; BusPrint((2, "BusInitializeHardware: enter\n")); // // Grab useful configuration parameters from the device extension. // deviceExtension = DeviceObject->DeviceExtension; mousePort = deviceExtension->Configuration.DeviceRegisters[0]; BusPrint((2, "BusInitializeHardware: Port base value is: 0x%x\n", (int)mousePort)); // // Turn the bus interrupts off (in case). // WRITE_PORT_UCHAR((PUCHAR) mousePort + BUS_CONTROL_PORT_WRITE, BUS_CONTROL_INTERRUPT_DISABLE); // // Configure the controller. // // WRITE_PORT_UCHAR((PUCHAR) mousePort + BUS_CONFIGURATION_PORT_READ_WRITE, // BUS_CONFIGURATION_VALUE); // // Initialize the state of the mouse buttons. // deviceExtension->PreviousButtons = 0; BusPrint((2, "BusInitializeHardware: exit\n")); return(STATUS_SUCCESS); } NTSTATUS BusPeripheralCallout( 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 PointerController). 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; PBUS_CONFIGURATION_INFORMATION configuration; UNICODE_STRING unicodeIdentifier; PUCHAR controllerData; NTSTATUS status = STATUS_SUCCESS; ULONG i; ULONG listCount = 0; PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDescriptor; ANSI_STRING ansiString; BOOLEAN defaultInterruptShare; KINTERRUPT_MODE defaultInterruptMode; BusPrint(( 1, "BusPeripheralCallout: Enter\n" )); BusPrint(( 1, "BusPeripheralCallout: Path @ 0x%x, Bus Type 0x%x, Bus Number 0x%x\n", PathName, BusType, BusNumber )); BusPrint(( 1, " Controller Type 0x%x, Controller Number 0x%x, Controller info @ 0x%x\n", ControllerType, ControllerNumber, ControllerInformation )); BusPrint(( 1, " Peripheral Type 0x%x, Peripheral Number 0x%x, Peripheral info @ 0x%x\n", PeripheralType, PeripheralNumber, PeripheralInformation )); // // Get the length of the peripheral identifier information. // unicodeIdentifier.Length = (USHORT) (*(PeripheralInformation + IoQueryDeviceIdentifier))->DataLength; // // If we already have the configuration information for the // mouse peripheral, or if the peripheral identifier is missing, // just return. // deviceExtension = (PDEVICE_EXTENSION) Context; if ((deviceExtension->HardwarePresent) || (unicodeIdentifier.Length == 0)){ return (status); } // // Get the identifier information for the peripheral. // unicodeIdentifier.MaximumLength = unicodeIdentifier.Length; unicodeIdentifier.Buffer = (PWSTR) (((PUCHAR)(*(PeripheralInformation + IoQueryDeviceIdentifier))) + (*(PeripheralInformation + IoQueryDeviceIdentifier))->DataOffset); BusPrint(( 1, "BusPeripheralCallout: Mouse type %ws\n", unicodeIdentifier.Buffer )); // // Verify that this is a Bus mouse. // status = RtlUnicodeStringToAnsiString( &ansiString, &unicodeIdentifier, TRUE ); if (!NT_SUCCESS(status)) { BusPrint(( 1, "BusPeripheralCallout: Could not convert identifier to Ansi\n" )); return(status); } if (strstr(ansiString.Buffer, "BUS")) { // // There is a Bus mouse (at least a card) present. // deviceExtension->HardwarePresent = TRUE; } RtlFreeAnsiString(&ansiString); if (!deviceExtension->HardwarePresent) { return(status); } // // Get the bus information. // configuration = &deviceExtension->Configuration; configuration->InterfaceType = BusType; configuration->BusNumber = BusNumber; #ifdef PNP_IDENTIFY configuration->ControllerType = ControllerType; configuration->ControllerNumber = ControllerNumber; configuration->PeripheralType = PeripheralType; configuration->PeripheralNumber = PeripheralNumber; #endif configuration->FloatingSave = BUS_FLOATING_SAVE; if (BusType == MicroChannel) { defaultInterruptShare = TRUE; defaultInterruptMode = LevelSensitive; } else { defaultInterruptShare = BUS_INTERRUPT_SHARE; defaultInterruptMode = BUS_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 Bus mouse. // ASSERT(configuration->PortListCount == 0); configuration->PortList[configuration->PortListCount] = *resourceDescriptor; configuration->PortList[configuration->PortListCount].ShareDisposition = BUS_REGISTER_SHARE? CmResourceShareShared: CmResourceShareDeviceExclusive; configuration->PortListCount += 1; break; case CmResourceTypeInterrupt: // // Copy the interrupt information. // configuration->MouseInterrupt = *resourceDescriptor; configuration->MouseInterrupt.ShareDisposition = defaultInterruptShare? CmResourceShareShared : CmResourceShareDeviceExclusive; break; default: break; } } } // // If no interrupt configuration information was found, use the // driver defaults. // if (!(configuration->MouseInterrupt.Type & CmResourceTypeInterrupt)) { BusPrint(( 1, "BusPeripheralCallout: 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; } BusPrint(( 1, "BusPeripheralCallout: Mouse interrupt config --\n" )); BusPrint(( 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 )); // // 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. // BusPrint(( 1, "BusPeripheralCallout: Using default port config\n" )); configuration->PortList[0].Type = CmResourceTypePort; configuration->PortList[0].Flags = BUS_PORT_TYPE; configuration->PortList[0].ShareDisposition = BUS_REGISTER_SHARE? CmResourceShareShared: CmResourceShareDeviceExclusive; configuration->PortList[0].u.Port.Start.LowPart = BUS_PHYSICAL_BASE; configuration->PortList[0].u.Port.Start.HighPart = 0; configuration->PortList[0].u.Port.Length = BUS_REGISTER_LENGTH; configuration->PortListCount = 1; } for (i = 0; i < configuration->PortListCount; i++) { BusPrint(( 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 )); } BusPrint(( 1, "BusPeripheralCallout: Exit\n" )); return(status); } VOID BusServiceParameters( 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. --*/ { PBUS_CONFIGURATION_INFORMATION configuration; PRTL_QUERY_REGISTRY_TABLE parameters = NULL; UNICODE_STRING parametersPath; OBJECT_ATTRIBUTES parametersAttributes; ULONG defaultDataQueueSize = DATA_QUEUE_SIZE; ULONG numberOfButtons = MOUSE_NUMBER_OF_BUTTONS; USHORT defaultNumberOfButtons = MOUSE_NUMBER_OF_BUTTONS; ULONG sampleRate = MOUSE_SAMPLE_RATE_50HZ; UNICODE_STRING defaultUnicodeName; NTSTATUS status = STATUS_SUCCESS; PWSTR path = NULL; USHORT queriesPlusOne = 4; BusPrint(( 1, "BusServiceParameters: Enter\n" )); 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) { BusPrint(( 1, "BusServiceParameters: 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) { BusPrint(( 1, "BusServiceParameters: 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" ); BusPrint(( 1, "BusServiceParameters: 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"PointerDeviceBaseName"; parameters[2].EntryContext = DeviceName; parameters[2].DefaultType = REG_SZ; parameters[2].DefaultData = defaultUnicodeName.Buffer; parameters[2].DefaultLength = 0; status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, parametersPath.Buffer, parameters, NULL, NULL ); if (!NT_SUCCESS(status)) { BusPrint(( 1, "BusServiceParameters: RtlQueryRegistryValues failed with 0x%x\n", status )); } } if (!NT_SUCCESS(status)) { // // Go ahead and assign driver defaults. // configuration->MouseAttributes.InputDataQueueLength = defaultDataQueueSize; RtlCopyUnicodeString(DeviceName, &defaultUnicodeName); } BusPrint(( 1, "BusServiceParameters: Pointer port base name = %ws\n", DeviceName->Buffer )); if (configuration->MouseAttributes.InputDataQueueLength == 0) { BusPrint(( 1, "BusServiceParameters: overriding MouseInputDataQueueLength = 0x%x\n", configuration->MouseAttributes.InputDataQueueLength )); configuration->MouseAttributes.InputDataQueueLength = defaultDataQueueSize; } configuration->MouseAttributes.InputDataQueueLength *= sizeof(MOUSE_INPUT_DATA); BusPrint(( 1, "BusServiceParameters: MouseInputDataQueueLength = 0x%x\n", configuration->MouseAttributes.InputDataQueueLength )); configuration->MouseAttributes.NumberOfButtons = (USHORT) numberOfButtons; BusPrint(( 1, "BusServiceParameters: NumberOfButtons = %d\n", configuration->MouseAttributes.NumberOfButtons )); configuration->MouseAttributes.SampleRate = (USHORT) sampleRate; BusPrint(( 1, "BusServiceParameters: SampleRate = %d\n", configuration->MouseAttributes.SampleRate )); // // Free the allocated memory before returning. // if (parametersPath.Buffer) ExFreePool(parametersPath.Buffer); if (parameters) ExFreePool(parameters); BusPrint(( 1, "BusServiceParameters: Exit\n" )); } #endif