[USB-BRINGUP-TRUNK]
[reactos.git] / reactos / drivers / input / mouclass / mouclass.c
diff --git a/reactos/drivers/input/mouclass/mouclass.c b/reactos/drivers/input/mouclass/mouclass.c
deleted file mode 100644 (file)
index 99818bb..0000000
+++ /dev/null
@@ -1,1007 +0,0 @@
-/*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS Mouse class driver
- * FILE:            drivers/mouclass/mouclass.c
- * PURPOSE:         Mouse class driver
- *
- * PROGRAMMERS:     HervĂ© Poussineau (hpoussin@reactos.org)
- */
-
-#define INITGUID
-#include "mouclass.h"
-
-static DRIVER_UNLOAD DriverUnload;
-static DRIVER_DISPATCH ClassCreate;
-static DRIVER_DISPATCH ClassClose;
-static DRIVER_DISPATCH ClassCleanup;
-static DRIVER_DISPATCH ClassRead;
-static DRIVER_DISPATCH ClassDeviceControl;
-static DRIVER_DISPATCH IrpStub;
-static DRIVER_ADD_DEVICE ClassAddDevice;
-static DRIVER_STARTIO ClassStartIo;
-static DRIVER_CANCEL ClassCancelRoutine;
-static NTSTATUS
-HandleReadIrp(
-       IN PDEVICE_OBJECT DeviceObject,
-       IN PIRP Irp,
-       BOOLEAN IsInStartIo);
-
-static VOID NTAPI
-DriverUnload(IN PDRIVER_OBJECT DriverObject)
-{
-       // nothing to do here yet
-}
-
-static NTSTATUS NTAPI
-ClassCreate(
-       IN PDEVICE_OBJECT DeviceObject,
-       IN PIRP Irp)
-{
-       TRACE_(CLASS_NAME, "IRP_MJ_CREATE\n");
-
-       if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
-               return ForwardIrpAndForget(DeviceObject, Irp);
-
-       /* FIXME: open all associated Port devices */
-       Irp->IoStatus.Status = STATUS_SUCCESS;
-       Irp->IoStatus.Information = 0;
-       IoCompleteRequest(Irp, IO_NO_INCREMENT);
-       return STATUS_SUCCESS;
-}
-
-static NTSTATUS NTAPI
-ClassClose(
-       IN PDEVICE_OBJECT DeviceObject,
-       IN PIRP Irp)
-{
-       TRACE_(CLASS_NAME, "IRP_MJ_CLOSE\n");
-
-       if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
-               return ForwardIrpAndForget(DeviceObject, Irp);
-
-       /* FIXME: close all associated Port devices */
-       Irp->IoStatus.Status = STATUS_SUCCESS;
-       Irp->IoStatus.Information = 0;
-       IoCompleteRequest(Irp, IO_NO_INCREMENT);
-       return STATUS_SUCCESS;
-}
-
-static NTSTATUS NTAPI
-ClassCleanup(
-       IN PDEVICE_OBJECT DeviceObject,
-       IN PIRP Irp)
-{
-       TRACE_(CLASS_NAME, "IRP_MJ_CLEANUP\n");
-
-       if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
-               return ForwardIrpAndForget(DeviceObject, Irp);
-
-       /* FIXME: cleanup all associated Port devices */
-       Irp->IoStatus.Status = STATUS_SUCCESS;
-       Irp->IoStatus.Information = 0;
-       IoCompleteRequest(Irp, IO_NO_INCREMENT);
-       return STATUS_SUCCESS;
-}
-
-static NTSTATUS NTAPI
-ClassRead(
-       IN PDEVICE_OBJECT DeviceObject,
-       IN PIRP Irp)
-{
-       PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
-       KIRQL OldIrql;
-       NTSTATUS Status;
-
-       TRACE_(CLASS_NAME, "IRP_MJ_READ\n");
-
-       ASSERT(DeviceExtension->Common.IsClassDO);
-
-       if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
-               return ForwardIrpAndForget(DeviceObject, Irp);
-
-       if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length < sizeof(MOUSE_INPUT_DATA))
-       {
-               Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
-               Irp->IoStatus.Information = 0;
-               IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
-               return STATUS_BUFFER_TOO_SMALL;
-       }
-
-       KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
-       Status = HandleReadIrp(DeviceObject, Irp, FALSE);
-       KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
-       return Status;
-}
-
-static NTSTATUS NTAPI
-ClassDeviceControl(
-       IN PDEVICE_OBJECT DeviceObject,
-       IN PIRP Irp)
-{
-       //PCLASS_DEVICE_EXTENSION DeviceExtension;
-       NTSTATUS Status = STATUS_NOT_SUPPORTED;
-
-       TRACE_(CLASS_NAME, "IRP_MJ_DEVICE_CONTROL\n");
-
-       if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
-               return ForwardIrpAndForget(DeviceObject, Irp);
-
-       //DeviceExtension = (PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-
-       switch (IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode)
-       {
-               case IOCTL_MOUSE_QUERY_ATTRIBUTES:
-               {
-                       /* FIXME: We hope that all devices will return the same result.
-                        * Ask only the first one */
-                       PLIST_ENTRY Head = &((PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->ListHead;
-                       if (Head->Flink != Head)
-                       {
-                               /* We have at least one device */
-                               PPORT_DEVICE_EXTENSION DevExt = CONTAINING_RECORD(Head->Flink, PORT_DEVICE_EXTENSION, ListEntry);
-                               IoGetCurrentIrpStackLocation(Irp)->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
-                               IoSkipCurrentIrpStackLocation(Irp);
-                               return IoCallDriver(DevExt->DeviceObject, Irp);
-                       }
-                       break;
-               }
-               default:
-                       WARN_(CLASS_NAME, "IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n",
-                               IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode);
-                       ASSERT(FALSE);
-                       break;
-       }
-
-       Irp->IoStatus.Status = Status;
-       Irp->IoStatus.Information = 0;
-       IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
-       return Status;
-}
-
-static NTSTATUS NTAPI
-IrpStub(
-       IN PDEVICE_OBJECT DeviceObject,
-       IN PIRP Irp)
-{
-       NTSTATUS Status = STATUS_NOT_SUPPORTED;
-
-       if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
-       {
-               /* Forward some IRPs to lower device */
-               switch (IoGetCurrentIrpStackLocation(Irp)->MajorFunction)
-               {
-                       case IRP_MJ_PNP:
-                       case IRP_MJ_INTERNAL_DEVICE_CONTROL:
-                               return ForwardIrpAndForget(DeviceObject, Irp);
-                       default:
-                       {
-                               ERR_(CLASS_NAME, "Port DO stub for major function 0x%lx\n",
-                                       IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
-                               ASSERT(FALSE);
-                       }
-               }
-       }
-       else
-       {
-               ERR_(CLASS_NAME, "Class DO stub for major function 0x%lx\n",
-                       IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
-               ASSERT(FALSE);
-       }
-
-       Irp->IoStatus.Status = Status;
-       IoCompleteRequest(Irp, IO_NO_INCREMENT);
-       return Status;
-}
-
-static NTSTATUS
-ReadRegistryEntries(
-       IN PUNICODE_STRING RegistryPath,
-       IN PCLASS_DRIVER_EXTENSION DriverExtension)
-{
-       UNICODE_STRING ParametersRegistryKey;
-       RTL_QUERY_REGISTRY_TABLE Parameters[4];
-       NTSTATUS Status;
-
-       ULONG DefaultConnectMultiplePorts = 1;
-       ULONG DefaultDataQueueSize = 0x64;
-       PCWSTR DefaultDeviceBaseName = L"PointerClass";
-
-       ParametersRegistryKey.Length = 0;
-       ParametersRegistryKey.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters") + sizeof(UNICODE_NULL);
-       ParametersRegistryKey.Buffer = ExAllocatePoolWithTag(PagedPool, ParametersRegistryKey.MaximumLength, CLASS_TAG);
-       if (!ParametersRegistryKey.Buffer)
-       {
-               WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n");
-               return STATUS_NO_MEMORY;
-       }
-       RtlCopyUnicodeString(&ParametersRegistryKey, RegistryPath);
-       RtlAppendUnicodeToString(&ParametersRegistryKey, L"\\Parameters");
-       ParametersRegistryKey.Buffer[ParametersRegistryKey.Length / sizeof(WCHAR)] = UNICODE_NULL;
-
-       RtlZeroMemory(Parameters, sizeof(Parameters));
-
-       Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
-       Parameters[0].Name = L"ConnectMultiplePorts";
-       Parameters[0].EntryContext = &DriverExtension->ConnectMultiplePorts;
-       Parameters[0].DefaultType = REG_DWORD;
-       Parameters[0].DefaultData = &DefaultConnectMultiplePorts;
-       Parameters[0].DefaultLength = sizeof(ULONG);
-
-       Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
-       Parameters[1].Name = L"MouseDataQueueSize";
-       Parameters[1].EntryContext = &DriverExtension->DataQueueSize;
-       Parameters[1].DefaultType = REG_DWORD;
-       Parameters[1].DefaultData = &DefaultDataQueueSize;
-       Parameters[1].DefaultLength = sizeof(ULONG);
-
-       Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
-       Parameters[2].Name = L"PointerDeviceBaseName";
-       Parameters[2].EntryContext = &DriverExtension->DeviceBaseName;
-       Parameters[2].DefaultType = REG_SZ;
-       Parameters[2].DefaultData = (PVOID)DefaultDeviceBaseName;
-       Parameters[2].DefaultLength = 0;
-
-       Status = RtlQueryRegistryValues(
-               RTL_REGISTRY_ABSOLUTE,
-               ParametersRegistryKey.Buffer,
-               Parameters,
-               NULL,
-               NULL);
-
-       if (NT_SUCCESS(Status))
-       {
-               /* Check values */
-               if (DriverExtension->ConnectMultiplePorts != 0
-                       && DriverExtension->ConnectMultiplePorts != 1)
-               {
-                       DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
-               }
-               if (DriverExtension->DataQueueSize == 0)
-               {
-                       DriverExtension->DataQueueSize = DefaultDataQueueSize;
-               }
-       }
-       else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
-       {
-               /* Registry path doesn't exist. Set defaults */
-               DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
-               DriverExtension->DataQueueSize = DefaultDataQueueSize;
-               if (RtlCreateUnicodeString(&DriverExtension->DeviceBaseName, DefaultDeviceBaseName))
-                       Status = STATUS_SUCCESS;
-               else
-                       Status = STATUS_NO_MEMORY;
-       }
-
-       ExFreePoolWithTag(ParametersRegistryKey.Buffer, CLASS_TAG);
-       return Status;
-}
-
-static NTSTATUS
-CreateClassDeviceObject(
-       IN PDRIVER_OBJECT DriverObject,
-       OUT PDEVICE_OBJECT *ClassDO OPTIONAL)
-{
-       PCLASS_DRIVER_EXTENSION DriverExtension;
-       ULONG DeviceId = 0;
-       ULONG PrefixLength;
-       UNICODE_STRING DeviceNameU;
-       PWSTR DeviceIdW = NULL; /* Pointer into DeviceNameU.Buffer */
-       PDEVICE_OBJECT Fdo;
-       PCLASS_DEVICE_EXTENSION DeviceExtension;
-       NTSTATUS Status;
-
-       TRACE_(CLASS_NAME, "CreateClassDeviceObject(0x%p)\n", DriverObject);
-
-       /* Create new device object */
-       DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
-       DeviceNameU.Length = 0;
-       DeviceNameU.MaximumLength =
-               wcslen(L"\\Device\\") * sizeof(WCHAR)    /* "\Device\" */
-               + DriverExtension->DeviceBaseName.Length /* "PointerClass" */
-               + 4 * sizeof(WCHAR)                      /* Id between 0 and 9999 */
-               + sizeof(UNICODE_NULL);                  /* Final NULL char */
-       DeviceNameU.Buffer = ExAllocatePoolWithTag(PagedPool, DeviceNameU.MaximumLength, CLASS_TAG);
-       if (!DeviceNameU.Buffer)
-       {
-               WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n");
-               return STATUS_NO_MEMORY;
-       }
-       Status = RtlAppendUnicodeToString(&DeviceNameU, L"\\Device\\");
-       if (!NT_SUCCESS(Status))
-       {
-               WARN_(CLASS_NAME, "RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status);
-               goto cleanup;
-       }
-       Status = RtlAppendUnicodeStringToString(&DeviceNameU, &DriverExtension->DeviceBaseName);
-       if (!NT_SUCCESS(Status))
-       {
-               WARN_(CLASS_NAME, "RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
-               goto cleanup;
-       }
-       PrefixLength = DeviceNameU.MaximumLength - 4 * sizeof(WCHAR) - sizeof(UNICODE_NULL);
-       DeviceIdW = &DeviceNameU.Buffer[PrefixLength / sizeof(WCHAR)];
-       while (DeviceId < 9999)
-       {
-               DeviceNameU.Length = (USHORT)(PrefixLength + swprintf(DeviceIdW, L"%lu", DeviceId) * sizeof(WCHAR));
-               Status = IoCreateDevice(
-                       DriverObject,
-                       sizeof(CLASS_DEVICE_EXTENSION),
-                       &DeviceNameU,
-                       FILE_DEVICE_MOUSE,
-                       FILE_DEVICE_SECURE_OPEN,
-                       FALSE,
-                       &Fdo);
-               if (NT_SUCCESS(Status))
-                       goto cleanup;
-               else if (Status != STATUS_OBJECT_NAME_COLLISION)
-               {
-                       WARN_(CLASS_NAME, "IoCreateDevice() failed with status 0x%08lx\n", Status);
-                       goto cleanup;
-               }
-               DeviceId++;
-       }
-       WARN_(CLASS_NAME, "Too many devices starting with '\\Device\\%wZ'\n", &DriverExtension->DeviceBaseName);
-       Status = STATUS_TOO_MANY_NAMES;
-cleanup:
-       if (!NT_SUCCESS(Status))
-       {
-               ExFreePoolWithTag(DeviceNameU.Buffer, CLASS_TAG);
-               return Status;
-       }
-
-       DeviceExtension = (PCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension;
-       RtlZeroMemory(DeviceExtension, sizeof(CLASS_DEVICE_EXTENSION));
-       DeviceExtension->Common.IsClassDO = TRUE;
-       DeviceExtension->DriverExtension = DriverExtension;
-       InitializeListHead(&DeviceExtension->ListHead);
-       KeInitializeSpinLock(&DeviceExtension->ListSpinLock);
-       KeInitializeSpinLock(&DeviceExtension->SpinLock);
-       DeviceExtension->InputCount = 0;
-       DeviceExtension->PortData = ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->DriverExtension->DataQueueSize * sizeof(MOUSE_INPUT_DATA), CLASS_TAG);
-       if (!DeviceExtension->PortData)
-       {
-               ExFreePoolWithTag(DeviceNameU.Buffer, CLASS_TAG);
-               return STATUS_NO_MEMORY;
-       }
-       DeviceExtension->DeviceName = DeviceNameU.Buffer;
-       Fdo->Flags |= DO_POWER_PAGABLE;
-       Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
-    Fdo->Flags |= DO_BUFFERED_IO;
-
-       /* Add entry entry to HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
-       RtlWriteRegistryValue(
-               RTL_REGISTRY_DEVICEMAP,
-               DriverExtension->DeviceBaseName.Buffer,
-               DeviceExtension->DeviceName,
-               REG_SZ,
-               DriverExtension->RegistryPath.Buffer,
-               DriverExtension->RegistryPath.MaximumLength);
-
-       if (ClassDO)
-               *ClassDO = Fdo;
-
-       return STATUS_SUCCESS;
-}
-
-static NTSTATUS
-FillEntries(
-       IN PDEVICE_OBJECT ClassDeviceObject,
-       IN PIRP Irp,
-       IN PMOUSE_INPUT_DATA DataStart,
-       IN SIZE_T NumberOfEntries)
-{
-       NTSTATUS Status = STATUS_SUCCESS;
-
-       if (ClassDeviceObject->Flags & DO_BUFFERED_IO)
-       {
-               RtlCopyMemory(
-                       Irp->AssociatedIrp.SystemBuffer,
-                       DataStart,
-                       NumberOfEntries * sizeof(MOUSE_INPUT_DATA));
-       }
-       else if (ClassDeviceObject->Flags & DO_DIRECT_IO)
-       {
-               PVOID DestAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
-               if (DestAddress)
-               {
-                       RtlCopyMemory(
-                               DestAddress,
-                               DataStart,
-                               NumberOfEntries * sizeof(MOUSE_INPUT_DATA));
-               }
-               else
-                       Status = STATUS_UNSUCCESSFUL;
-       }
-       else
-       {
-               _SEH2_TRY
-               {
-                       RtlCopyMemory(
-                               Irp->UserBuffer,
-                               DataStart,
-                               NumberOfEntries * sizeof(MOUSE_INPUT_DATA));
-               }
-               _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-               {
-                       Status = _SEH2_GetExceptionCode();
-               }
-               _SEH2_END;
-       }
-
-       return Status;
-}
-
-static BOOLEAN NTAPI
-ClassCallback(
-       IN PDEVICE_OBJECT ClassDeviceObject,
-       IN OUT PMOUSE_INPUT_DATA DataStart,
-       IN PMOUSE_INPUT_DATA DataEnd,
-       IN OUT PULONG ConsumedCount)
-{
-       PCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
-       KIRQL OldIrql;
-       SIZE_T InputCount = DataEnd - DataStart;
-       SIZE_T ReadSize;
-
-       TRACE_(CLASS_NAME, "ClassCallback()\n");
-
-       ASSERT(ClassDeviceExtension->Common.IsClassDO);
-
-       KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
-       if (InputCount > 0)
-       {
-               if (ClassDeviceExtension->InputCount + InputCount > ClassDeviceExtension->DriverExtension->DataQueueSize)
-               {
-                       /*
-                        * We're exceeding the buffer, and data will be thrown away...
-                        * FIXME: What could we do, as we are at DISPATCH_LEVEL?
-                        */
-                       ReadSize = ClassDeviceExtension->DriverExtension->DataQueueSize - ClassDeviceExtension->InputCount;
-               }
-               else
-                       ReadSize = InputCount;
-
-               /*
-                * Move the input data from the port data queue to our class data
-                * queue.
-                */
-               RtlCopyMemory(
-                       &ClassDeviceExtension->PortData[ClassDeviceExtension->InputCount],
-                       (PCHAR)DataStart,
-                       sizeof(MOUSE_INPUT_DATA) * ReadSize);
-
-               /* Move the counter up */
-               ClassDeviceExtension->InputCount += ReadSize;
-
-               (*ConsumedCount) += (ULONG)ReadSize;
-
-               /* Complete pending IRP (if any) */
-               if (ClassDeviceExtension->PendingIrp)
-                       HandleReadIrp(ClassDeviceObject, ClassDeviceExtension->PendingIrp, FALSE);
-       }
-       KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
-
-       TRACE_(CLASS_NAME, "Leaving ClassCallback()\n");
-       return TRUE;
-}
-
-/* Send IOCTL_INTERNAL_*_CONNECT to port */
-static NTSTATUS
-ConnectPortDriver(
-       IN PDEVICE_OBJECT PortDO,
-       IN PDEVICE_OBJECT ClassDO)
-{
-       KEVENT Event;
-       PIRP Irp;
-       IO_STATUS_BLOCK IoStatus;
-       CONNECT_DATA ConnectData;
-       NTSTATUS Status;
-
-       TRACE_(CLASS_NAME, "Connecting PortDO %p to ClassDO %p\n", PortDO, ClassDO);
-
-       KeInitializeEvent(&Event, NotificationEvent, FALSE);
-
-       ConnectData.ClassDeviceObject = ClassDO;
-       ConnectData.ClassService      = ClassCallback;
-
-       Irp = IoBuildDeviceIoControlRequest(
-               IOCTL_INTERNAL_MOUSE_CONNECT,
-               PortDO,
-               &ConnectData, sizeof(CONNECT_DATA),
-               NULL, 0,
-               TRUE, &Event, &IoStatus);
-       if (!Irp)
-               return STATUS_INSUFFICIENT_RESOURCES;
-
-       Status = IoCallDriver(PortDO, Irp);
-
-       if (Status == STATUS_PENDING)
-               KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
-       else
-               IoStatus.Status = Status;
-
-       if (NT_SUCCESS(IoStatus.Status))
-       {
-               ObReferenceObject(PortDO);
-               ExInterlockedInsertTailList(
-                       &((PCLASS_DEVICE_EXTENSION)ClassDO->DeviceExtension)->ListHead,
-                       &((PPORT_DEVICE_EXTENSION)PortDO->DeviceExtension)->ListEntry,
-                       &((PCLASS_DEVICE_EXTENSION)ClassDO->DeviceExtension)->ListSpinLock);
-               if (ClassDO->StackSize <= PortDO->StackSize)
-               {
-                       /* Increase the stack size, in case we have to
-                        * forward some IRPs to the port device object
-                        */
-                       ClassDO->StackSize = PortDO->StackSize + 1;
-               }
-       }
-
-       return IoStatus.Status;
-}
-
-/* Send IOCTL_INTERNAL_*_DISCONNECT to port + destroy the Port DO */
-static VOID
-DestroyPortDriver(
-       IN PDEVICE_OBJECT PortDO)
-{
-       PPORT_DEVICE_EXTENSION DeviceExtension;
-       PCLASS_DEVICE_EXTENSION ClassDeviceExtension;
-       PCLASS_DRIVER_EXTENSION DriverExtension;
-       KEVENT Event;
-       PIRP Irp;
-       IO_STATUS_BLOCK IoStatus;
-       KIRQL OldIrql;
-       NTSTATUS Status;
-
-       TRACE_(CLASS_NAME, "Destroying PortDO %p\n", PortDO);
-
-       DeviceExtension = (PPORT_DEVICE_EXTENSION)PortDO->DeviceExtension;
-       ClassDeviceExtension = DeviceExtension->ClassDO->DeviceExtension;
-       DriverExtension = IoGetDriverObjectExtension(PortDO->DriverObject, PortDO->DriverObject);
-
-       /* Send IOCTL_INTERNAL_*_DISCONNECT */
-       KeInitializeEvent(&Event, NotificationEvent, FALSE);
-       Irp = IoBuildDeviceIoControlRequest(
-               IOCTL_INTERNAL_MOUSE_DISCONNECT,
-               PortDO,
-               NULL, 0,
-               NULL, 0,
-               TRUE, &Event, &IoStatus);
-       if (Irp)
-       {
-               Status = IoCallDriver(PortDO, Irp);
-               if (Status == STATUS_PENDING)
-                       KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
-       }
-
-       /* Remove from ClassDeviceExtension->ListHead list */
-       KeAcquireSpinLock(&ClassDeviceExtension->ListSpinLock, &OldIrql);
-       RemoveHeadList(DeviceExtension->ListEntry.Blink);
-       KeReleaseSpinLock(&ClassDeviceExtension->ListSpinLock, OldIrql);
-
-       /* Remove entry from HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
-       RtlDeleteRegistryValue(
-               RTL_REGISTRY_DEVICEMAP,
-               DriverExtension->DeviceBaseName.Buffer,
-               ClassDeviceExtension->DeviceName);
-
-       if (DeviceExtension->LowerDevice)
-               IoDetachDevice(DeviceExtension->LowerDevice);
-       ObDereferenceObject(PortDO);
-
-       if (!DriverExtension->ConnectMultiplePorts && DeviceExtension->ClassDO)
-       {
-               ExFreePoolWithTag(ClassDeviceExtension->PortData, CLASS_TAG);
-               ExFreePoolWithTag((PVOID)ClassDeviceExtension->DeviceName, CLASS_TAG);
-               IoDeleteDevice(DeviceExtension->ClassDO);
-       }
-
-       IoDeleteDevice(PortDO);
-}
-
-static NTSTATUS NTAPI
-ClassAddDevice(
-       IN PDRIVER_OBJECT DriverObject,
-       IN PDEVICE_OBJECT Pdo)
-{
-       PCLASS_DRIVER_EXTENSION DriverExtension;
-       PDEVICE_OBJECT Fdo = NULL;
-       PPORT_DEVICE_EXTENSION DeviceExtension = NULL;
-       NTSTATUS Status;
-
-       TRACE_(CLASS_NAME, "ClassAddDevice called. Pdo = 0x%p\n", Pdo);
-
-       DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
-
-       if (Pdo == NULL)
-               /* We may get a NULL Pdo at the first call as we're a legacy driver. Ignore it */
-               return STATUS_SUCCESS;
-
-       /* Create new device object */
-       Status = IoCreateDevice(
-               DriverObject,
-               sizeof(PORT_DEVICE_EXTENSION),
-               NULL,
-               Pdo->DeviceType,
-               Pdo->Characteristics & FILE_DEVICE_SECURE_OPEN ? FILE_DEVICE_SECURE_OPEN : 0,
-               FALSE,
-               &Fdo);
-       if (!NT_SUCCESS(Status))
-       {
-               WARN_(CLASS_NAME, "IoCreateDevice() failed with status 0x%08lx\n", Status);
-               goto cleanup;
-       }
-       IoSetStartIoAttributes(Fdo, TRUE, TRUE);
-
-       DeviceExtension = (PPORT_DEVICE_EXTENSION)Fdo->DeviceExtension;
-       RtlZeroMemory(DeviceExtension, sizeof(PORT_DEVICE_EXTENSION));
-       DeviceExtension->Common.IsClassDO = FALSE;
-       DeviceExtension->DeviceObject = Fdo;
-       DeviceExtension->PnpState = dsStopped;
-       Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
-       if (!NT_SUCCESS(Status))
-       {
-               WARN_(CLASS_NAME, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
-               goto cleanup;
-       }
-       if (DeviceExtension->LowerDevice->Flags & DO_POWER_PAGABLE)
-               Fdo->Flags |= DO_POWER_PAGABLE;
-       if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO)
-               Fdo->Flags |= DO_BUFFERED_IO;
-       if (DeviceExtension->LowerDevice->Flags & DO_DIRECT_IO)
-               Fdo->Flags |= DO_DIRECT_IO;
-
-       if (DriverExtension->ConnectMultiplePorts)
-               DeviceExtension->ClassDO = DriverExtension->MainClassDeviceObject;
-       else
-       {
-               /* We need a new class device object for this Fdo */
-               Status = CreateClassDeviceObject(
-                       DriverObject,
-                       &DeviceExtension->ClassDO);
-               if (!NT_SUCCESS(Status))
-               {
-                       WARN_(CLASS_NAME, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status);
-                       goto cleanup;
-               }
-       }
-       Status = ConnectPortDriver(Fdo, DeviceExtension->ClassDO);
-       if (!NT_SUCCESS(Status))
-       {
-               WARN_(CLASS_NAME, "ConnectPortDriver() failed with status 0x%08lx\n", Status);
-               goto cleanup;
-       }
-       Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
-
-       /* Register interface ; ignore the error (if any) as having
-        * a registred interface is not so important... */
-       Status = IoRegisterDeviceInterface(
-               Pdo,
-               &GUID_DEVINTERFACE_MOUSE,
-               NULL,
-               &DeviceExtension->InterfaceName);
-       if (!NT_SUCCESS(Status))
-               DeviceExtension->InterfaceName.Length = 0;
-
-       return STATUS_SUCCESS;
-
-cleanup:
-       if (Fdo)
-               DestroyPortDriver(Fdo);
-       return Status;
-}
-
-static VOID NTAPI
-ClassCancelRoutine(
-       IN PDEVICE_OBJECT DeviceObject,
-       IN PIRP Irp)
-{
-       PCLASS_DEVICE_EXTENSION ClassDeviceExtension = DeviceObject->DeviceExtension;
-       KIRQL OldIrql;
-       BOOLEAN wasQueued = FALSE;
-
-       TRACE_(CLASS_NAME, "ClassCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
-
-       ASSERT(ClassDeviceExtension->Common.IsClassDO);
-
-       IoReleaseCancelSpinLock(Irp->CancelIrql);
-
-       KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
-
-       if (ClassDeviceExtension->PendingIrp == Irp)
-       {
-               ClassDeviceExtension->PendingIrp = NULL;
-               wasQueued = TRUE;
-       }
-       KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
-
-       if (wasQueued)
-       {
-               Irp->IoStatus.Status = STATUS_CANCELLED;
-               Irp->IoStatus.Information = 0;
-               IoCompleteRequest(Irp, IO_NO_INCREMENT);
-       }
-       else
-       {
-               /* Hm, this shouldn't happen */
-               ASSERT(FALSE);
-       }
-}
-
-static NTSTATUS
-HandleReadIrp(
-       IN PDEVICE_OBJECT DeviceObject,
-       IN PIRP Irp,
-       BOOLEAN IsInStartIo)
-{
-       PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
-       NTSTATUS Status;
-       KIRQL OldIrql;
-
-       TRACE_(CLASS_NAME, "HandleReadIrp(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
-
-       ASSERT(DeviceExtension->Common.IsClassDO);
-
-       if (DeviceExtension->InputCount > 0)
-       {
-               SIZE_T NumberOfEntries;
-
-               NumberOfEntries = MIN(
-                       DeviceExtension->InputCount,
-                       IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length / sizeof(MOUSE_INPUT_DATA));
-
-               Status = FillEntries(
-                       DeviceObject,
-                       Irp,
-                       DeviceExtension->PortData,
-                       NumberOfEntries);
-
-               if (NT_SUCCESS(Status))
-               {
-                       if (DeviceExtension->InputCount > NumberOfEntries)
-                       {
-                               RtlMoveMemory(
-                                       &DeviceExtension->PortData[0],
-                                       &DeviceExtension->PortData[NumberOfEntries],
-                                       (DeviceExtension->InputCount - NumberOfEntries) * sizeof(MOUSE_INPUT_DATA));
-                       }
-
-                       DeviceExtension->InputCount -= NumberOfEntries;
-
-                       Irp->IoStatus.Information = NumberOfEntries * sizeof(MOUSE_INPUT_DATA);
-               }
-
-               /* Go to next packet and complete this request */
-               Irp->IoStatus.Status = Status;
-
-               (VOID)IoSetCancelRoutine(Irp, NULL);
-               IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
-               DeviceExtension->PendingIrp = NULL;
-       }
-       else
-       {
-               IoAcquireCancelSpinLock(&OldIrql);
-               if (Irp->Cancel)
-               {
-                       DeviceExtension->PendingIrp = NULL;
-                       Status = STATUS_CANCELLED;
-               }
-               else
-               {
-                       IoMarkIrpPending(Irp);
-                       DeviceExtension->PendingIrp = Irp;
-                       (VOID)IoSetCancelRoutine(Irp, ClassCancelRoutine);
-                       Status = STATUS_PENDING;
-               }
-               IoReleaseCancelSpinLock(OldIrql);
-       }
-       return Status;
-}
-
-static VOID NTAPI
-ClassStartIo(
-       IN PDEVICE_OBJECT DeviceObject,
-       IN PIRP Irp)
-{
-       PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
-       KIRQL OldIrql;
-
-       TRACE_(CLASS_NAME, "ClassStartIo(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
-
-       ASSERT(DeviceExtension->Common.IsClassDO);
-
-       KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
-       HandleReadIrp(DeviceObject, Irp, TRUE);
-       KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
-}
-
-static VOID NTAPI
-SearchForLegacyDrivers(
-       IN PDRIVER_OBJECT DriverObject,
-       IN PVOID Context, /* PCLASS_DRIVER_EXTENSION */
-       IN ULONG Count)
-{
-       UNICODE_STRING DeviceMapKeyU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
-       PCLASS_DRIVER_EXTENSION DriverExtension;
-       UNICODE_STRING PortBaseName = { 0, 0, NULL };
-       PKEY_VALUE_BASIC_INFORMATION KeyValueInformation = NULL;
-       OBJECT_ATTRIBUTES ObjectAttributes;
-       HANDLE hDeviceMapKey = (HANDLE)-1;
-       HANDLE hPortKey = (HANDLE)-1;
-       ULONG Index = 0;
-       ULONG Size, ResultLength;
-       NTSTATUS Status;
-
-       TRACE_(CLASS_NAME, "SearchForLegacyDrivers(%p %p %lu)\n",
-               DriverObject, Context, Count);
-
-       if (Count != 1)
-               return;
-       DriverExtension = (PCLASS_DRIVER_EXTENSION)Context;
-
-       /* Create port base name, by replacing Class by Port at the end of the class base name */
-       Status = DuplicateUnicodeString(
-               RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
-               &DriverExtension->DeviceBaseName,
-               &PortBaseName);
-       if (!NT_SUCCESS(Status))
-       {
-               WARN_(CLASS_NAME, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status);
-               goto cleanup;
-       }
-       PortBaseName.Length -= (sizeof(L"Class") - sizeof(UNICODE_NULL));
-       RtlAppendUnicodeToString(&PortBaseName, L"Port");
-
-       /* Allocate memory */
-       Size = sizeof(KEY_VALUE_BASIC_INFORMATION) + MAX_PATH;
-       KeyValueInformation = ExAllocatePoolWithTag(PagedPool, Size, CLASS_TAG);
-       if (!KeyValueInformation)
-       {
-               WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n");
-               Status = STATUS_NO_MEMORY;
-               goto cleanup;
-       }
-
-       /* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
-       InitializeObjectAttributes(&ObjectAttributes, &DeviceMapKeyU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
-       Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
-       if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
-       {
-               INFO_(CLASS_NAME, "HKLM\\HARDWARE\\DEVICEMAP is non-existent\n");
-               Status = STATUS_SUCCESS;
-               goto cleanup;
-       }
-       else if (!NT_SUCCESS(Status))
-       {
-               WARN_(CLASS_NAME, "ZwOpenKey() failed with status 0x%08lx\n", Status);
-               goto cleanup;
-       }
-
-       /* Open sub key */
-       InitializeObjectAttributes(&ObjectAttributes, &PortBaseName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hDeviceMapKey, NULL);
-       Status = ZwOpenKey(&hPortKey, KEY_QUERY_VALUE, &ObjectAttributes);
-       if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
-       {
-               INFO_(CLASS_NAME, "HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName);
-               Status = STATUS_SUCCESS;
-               goto cleanup;
-       }
-       else if (!NT_SUCCESS(Status))
-       {
-               WARN_(CLASS_NAME, "ZwOpenKey() failed with status 0x%08lx\n", Status);
-               goto cleanup;
-       }
-
-       /* Read each value name */
-       while (ZwEnumerateValueKey(hPortKey, Index++, KeyValueBasicInformation, KeyValueInformation, Size, &ResultLength) == STATUS_SUCCESS)
-       {
-               UNICODE_STRING PortName;
-               PDEVICE_OBJECT PortDeviceObject = NULL;
-               PFILE_OBJECT FileObject = NULL;
-
-               PortName.Length = PortName.MaximumLength = (USHORT)KeyValueInformation->NameLength;
-               PortName.Buffer = KeyValueInformation->Name;
-
-               /* Open the device object pointer */
-               Status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject);
-               if (!NT_SUCCESS(Status))
-               {
-                       WARN_(CLASS_NAME, "IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", &PortName, Status);
-                       continue;
-               }
-               INFO_(CLASS_NAME, "Legacy driver found\n");
-
-               Status = ClassAddDevice(DriverObject, PortDeviceObject);
-               if (!NT_SUCCESS(Status))
-               {
-                       /* FIXME: Log the error */
-                       WARN_(CLASS_NAME, "ClassAddDevice() failed with status 0x%08lx\n", Status);
-               }
-       }
-
-cleanup:
-       if (KeyValueInformation != NULL)
-               ExFreePoolWithTag(KeyValueInformation, CLASS_TAG);
-       if (hDeviceMapKey != (HANDLE)-1)
-               ZwClose(hDeviceMapKey);
-       if (hPortKey != (HANDLE)-1)
-               ZwClose(hPortKey);
-}
-
-/*
- * Standard DriverEntry method.
- */
-NTSTATUS NTAPI
-DriverEntry(
-       IN PDRIVER_OBJECT DriverObject,
-       IN PUNICODE_STRING RegistryPath)
-{
-       PCLASS_DRIVER_EXTENSION DriverExtension;
-       ULONG i;
-       NTSTATUS Status;
-
-       Status = IoAllocateDriverObjectExtension(
-               DriverObject,
-               DriverObject,
-               sizeof(CLASS_DRIVER_EXTENSION),
-               (PVOID*)&DriverExtension);
-       if (!NT_SUCCESS(Status))
-       {
-               WARN_(CLASS_NAME, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
-               return Status;
-       }
-       RtlZeroMemory(DriverExtension, sizeof(CLASS_DRIVER_EXTENSION));
-
-       Status = DuplicateUnicodeString(
-               RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
-               RegistryPath,
-               &DriverExtension->RegistryPath);
-       if (!NT_SUCCESS(Status))
-       {
-               WARN_(CLASS_NAME, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status);
-               return Status;
-       }
-
-       Status = ReadRegistryEntries(RegistryPath, DriverExtension);
-       if (!NT_SUCCESS(Status))
-       {
-               WARN_(CLASS_NAME, "ReadRegistryEntries() failed with status 0x%08lx\n", Status);
-               return Status;
-       }
-
-       if (DriverExtension->ConnectMultiplePorts == 1)
-       {
-               Status = CreateClassDeviceObject(
-                       DriverObject,
-                       &DriverExtension->MainClassDeviceObject);
-               if (!NT_SUCCESS(Status))
-               {
-                       WARN_(CLASS_NAME, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status);
-                       return Status;
-               }
-       }
-
-       DriverObject->DriverExtension->AddDevice = ClassAddDevice;
-       DriverObject->DriverUnload = DriverUnload;
-
-       for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
-               DriverObject->MajorFunction[i] = IrpStub;
-
-       DriverObject->MajorFunction[IRP_MJ_CREATE]         = ClassCreate;
-       DriverObject->MajorFunction[IRP_MJ_CLOSE]          = ClassClose;
-       DriverObject->MajorFunction[IRP_MJ_CLEANUP]        = ClassCleanup;
-       DriverObject->MajorFunction[IRP_MJ_READ]           = ClassRead;
-       DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControl;
-       DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ForwardIrpAndForget;
-       DriverObject->DriverStartIo                        = ClassStartIo;
-
-       /* We will detect the legacy devices later */
-       IoRegisterDriverReinitialization(
-               DriverObject,
-               SearchForLegacyDrivers,
-               DriverExtension);
-
-       return STATUS_SUCCESS;
-}