+static BOOLEAN
+MouclassCallback(
+ IN PDEVICE_OBJECT ClassDeviceObject,
+ IN OUT PMOUSE_INPUT_DATA MouseDataStart,
+ IN PMOUSE_INPUT_DATA MouseDataEnd,
+ IN OUT PULONG ConsumedCount)
+{
+ PMOUCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
+ PIRP Irp = NULL;
+ KIRQL OldIrql;
+ PIO_STACK_LOCATION Stack;
+ ULONG InputCount = MouseDataEnd - MouseDataStart;
+ ULONG ReadSize;
+
+ ASSERT(ClassDeviceExtension->Common.IsClassDO);
+
+ DPRINT("MouclassCallback()\n");
+ /* A filter driver might have consumed all the data already; I'm
+ * not sure if they are supposed to move the packets when they
+ * consume them though.
+ */
+ if (ClassDeviceExtension->ReadIsPending == TRUE && InputCount)
+ {
+ Irp = ClassDeviceObject->CurrentIrp;
+ ClassDeviceObject->CurrentIrp = NULL;
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+
+ /* A read request is waiting for input, so go straight to it */
+ RtlMoveMemory(
+ Irp->AssociatedIrp.SystemBuffer,
+ MouseDataStart,
+ sizeof(MOUSE_INPUT_DATA));
+
+ /* Go to next packet and complete this request with STATUS_SUCCESS */
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof(MOUSE_INPUT_DATA);
+ Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA);
+
+ ClassDeviceExtension->ReadIsPending = FALSE;
+
+ /* Skip the packet we just sent away */
+ MouseDataStart++;
+ (*ConsumedCount)++;
+ InputCount--;
+ }
+
+ /* If we have data from the port driver and a higher service to send the data to */
+ if (InputCount != 0)
+ {
+ KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
+
+ if (ClassDeviceExtension->InputCount + InputCount > ClassDeviceExtension->DriverExtension->MouseDataQueueSize)
+ ReadSize = ClassDeviceExtension->DriverExtension->MouseDataQueueSize - ClassDeviceExtension->InputCount;
+ else
+ ReadSize = InputCount;
+
+ /*
+ * FIXME: If we exceed the buffer, mouse data gets thrown away.. better
+ * solution?
+ */
+
+ /*
+ * Move the mouse input data from the port data queue to our class data
+ * queue.
+ */
+ RtlMoveMemory(
+ ClassDeviceExtension->PortData,
+ (PCHAR)MouseDataStart,
+ sizeof(MOUSE_INPUT_DATA) * ReadSize);
+
+ /* Move the pointer and counter up */
+ ClassDeviceExtension->PortData += ReadSize;
+ ClassDeviceExtension->InputCount += ReadSize;
+
+ KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
+ (*ConsumedCount) += ReadSize;
+ }
+ else
+ {
+ DPRINT("MouclassCallBack() entered, InputCount = %lu - DOING NOTHING\n", InputCount);
+ }
+
+ if (Irp != NULL)
+ {
+ IoStartNextPacket(ClassDeviceObject, FALSE);
+ IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
+ }
+
+ DPRINT("Leaving MouclassCallback()\n");
+ return TRUE;
+}
+
+/* Send IOCTL_INTERNAL_MOUSE_CONNECT to pointer port */
+static NTSTATUS
+ConnectMousePortDriver(
+ IN PDEVICE_OBJECT PointerPortDO,
+ IN PDEVICE_OBJECT PointerClassDO)
+{
+ KEVENT Event;
+ PIRP Irp;
+ IO_STATUS_BLOCK IoStatus;
+ CONNECT_DATA ConnectData;
+ NTSTATUS Status;
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ ConnectData.ClassDeviceObject = PointerClassDO;
+ ConnectData.ClassService = MouclassCallback;
+
+ Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT,
+ PointerPortDO,
+ &ConnectData, sizeof(CONNECT_DATA),
+ NULL, 0,
+ TRUE, &Event, &IoStatus);
+
+ Status = IoCallDriver(PointerPortDO, Irp);
+
+ if (Status == STATUS_PENDING)
+ KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
+ else
+ IoStatus.Status = Status;
+
+ return IoStatus.Status;
+}
+
+static NTSTATUS NTAPI
+MouclassAddDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT Pdo)
+{
+ PMOUCLASS_DRIVER_EXTENSION DriverExtension;
+ PDEVICE_OBJECT Fdo;
+ PMOUCLASS_DEVICE_EXTENSION DeviceExtension;
+ NTSTATUS Status;
+
+ DPRINT("MouclassAddDevice called. Pdo = 0x%p\n", Pdo);
+
+ DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
+
+ /* Create new device object */
+ Status = IoCreateDevice(
+ DriverObject,
+ sizeof(MOUCLASS_DEVICE_EXTENSION),
+ NULL,
+ Pdo->DeviceType,
+ FILE_DEVICE_SECURE_OPEN,
+ FALSE,
+ &Fdo);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
+ return Status;
+ }
+
+ DeviceExtension = (PMOUCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension;
+ RtlZeroMemory(DeviceExtension, sizeof(MOUCLASS_DEVICE_EXTENSION));
+ DeviceExtension->Common.IsClassDO = FALSE;
+ DeviceExtension->PnpState = dsStopped;
+ Fdo->Flags |= DO_POWER_PAGABLE;
+ Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
+ IoDeleteDevice(Fdo);
+ return Status;
+ }
+ Fdo->Flags |= DO_BUFFERED_IO;
+ Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ if (DriverExtension->ConnectMultiplePorts)
+ Status = ConnectMousePortDriver(Fdo, DriverExtension->MainMouclassDeviceObject);
+ else
+ Status = ConnectMousePortDriver(Fdo, Fdo);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ConnectMousePortDriver() failed with status 0x%08lx\n", Status);
+ /* FIXME: why can't I cleanup without error? */
+ //IoDetachDevice(Fdo);
+ //IoDeleteDevice(Fdo);
+ return Status;
+ }
+
+ /* Register GUID_DEVINTERFACE_MOUSE interface */
+ Status = IoRegisterDeviceInterface(
+ Pdo,
+ &GUID_DEVINTERFACE_MOUSE,
+ NULL,
+ &DeviceExtension->MouseInterfaceName);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status);
+ return Status;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static VOID NTAPI
+MouclassStartIo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PMOUCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
+
+ ASSERT(DeviceExtension->Common.IsClassDO);
+
+ if (DeviceExtension->InputCount > 0)
+ {
+ KIRQL oldIrql;
+
+ KeAcquireSpinLock(&DeviceExtension->SpinLock, &oldIrql);
+
+ RtlMoveMemory(
+ Irp->AssociatedIrp.SystemBuffer,
+ DeviceExtension->PortData - DeviceExtension->InputCount,
+ sizeof(MOUSE_INPUT_DATA));
+
+ if (DeviceExtension->InputCount > 1)
+ {
+ RtlMoveMemory(
+ DeviceExtension->PortData - DeviceExtension->InputCount,
+ DeviceExtension->PortData - DeviceExtension->InputCount + 1,
+ (DeviceExtension->InputCount - 1) * sizeof(MOUSE_INPUT_DATA));
+ }
+ DeviceExtension->PortData--;
+ DeviceExtension->InputCount--;
+ DeviceExtension->ReadIsPending = FALSE;
+
+ /* Go to next packet and complete this request with STATUS_SUCCESS */
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof(MOUSE_INPUT_DATA);
+ Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA);
+ IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
+
+ IoStartNextPacket(DeviceObject, FALSE);
+ KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
+ }
+ else
+ {
+ DeviceExtension->ReadIsPending = TRUE;
+ }
+}
+
+static NTSTATUS
+SearchForLegacyDrivers(
+ IN PMOUCLASS_DRIVER_EXTENSION DriverExtension)
+{
+ PDEVICE_OBJECT PortDeviceObject = NULL;
+ PFILE_OBJECT FileObject = NULL;
+ UNICODE_STRING PortName = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0");
+ NTSTATUS Status;
+
+ /* FIXME: search for more than once legacy driver */
+
+ Status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject);
+ if(Status != STATUS_SUCCESS)
+ {
+ DPRINT("Could not open old device object (Status 0x%08lx)\n", Status);
+ return Status;
+ }
+
+ if (DriverExtension->ConnectMultiplePorts)
+ Status = ConnectMousePortDriver(PortDeviceObject, DriverExtension->MainMouclassDeviceObject);
+ else
+ {
+ /* What to do */
+ KEBUGCHECK(0);
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ConnectMousePortDriver() failed with status 0x%08lx\n", Status);
+ return Status;
+ }
+ return STATUS_SUCCESS;
+}
+
+/*
+ * Standard DriverEntry method.
+ */
+NTSTATUS NTAPI
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath)