[DRIVERS] Use KeClearEvent instead of KeResetEvent where the previous state is not...
[reactos.git] / drivers / hid / mouhid / mouhid.c
index 037ed37..0450909 100644 (file)
@@ -10,7 +10,7 @@
 
 #include "mouhid.h"
 
-static USHORT MouHid_ButtonUpFlags[] = 
+static USHORT MouHid_ButtonUpFlags[] =
 {
     0xFF, /* unused */
     MOUSE_LEFT_BUTTON_DOWN,
@@ -20,7 +20,7 @@ static USHORT MouHid_ButtonUpFlags[] =
     MOUSE_BUTTON_5_DOWN
 };
 
-static USHORT MouHid_ButtonDownFlags[] = 
+static USHORT MouHid_ButtonDownFlags[] =
 {
     0xFF, /* unused */
     MOUSE_LEFT_BUTTON_UP,
@@ -30,6 +30,7 @@ static USHORT MouHid_ButtonDownFlags[] =
     MOUSE_BUTTON_5_UP
 };
 
+
 VOID
 MouHid_GetButtonMove(
     IN PMOUHID_DEVICE_EXTENSION DeviceExtension,
@@ -37,28 +38,148 @@ MouHid_GetButtonMove(
     OUT PLONG LastY)
 {
     NTSTATUS Status;
+    ULONG ValueX, ValueY;
 
     /* init result */
     *LastX = 0;
     *LastY = 0;
 
-    /* get scaled usage value x */
-    Status =  HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_X, (PLONG)LastX, DeviceExtension->PreparsedData, DeviceExtension->Report, DeviceExtension->ReportLength);
-    /* FIXME handle error */
-    ASSERT(Status == HIDP_STATUS_SUCCESS);
-
-    /* get scaled usage value y */
-    Status =  HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_Y, (PLONG)LastY, DeviceExtension->PreparsedData, DeviceExtension->Report, DeviceExtension->ReportLength);
-    /* FIXME handle error */
-    ASSERT(Status == HIDP_STATUS_SUCCESS);
+    if (!DeviceExtension->MouseAbsolute) 
+    {
+        /* get scaled usage value x */
+        Status =  HidP_GetScaledUsageValue(HidP_Input,
+                                       HID_USAGE_PAGE_GENERIC,
+                                       HIDP_LINK_COLLECTION_UNSPECIFIED,
+                                       HID_USAGE_GENERIC_X,
+                                       LastX,
+                                       DeviceExtension->PreparsedData,
+                                       DeviceExtension->Report,
+                                       DeviceExtension->ReportLength);
+
+        if (Status != HIDP_STATUS_SUCCESS)
+        {
+            /* FIXME: handle more errors */
+            if (Status == HIDP_STATUS_BAD_LOG_PHY_VALUES)
+            {
+                /* FIXME: assume it operates in absolute mode */
+                DeviceExtension->MouseAbsolute = TRUE;
+
+                /* get unscaled value */
+                Status = HidP_GetUsageValue(HidP_Input,
+                                        HID_USAGE_PAGE_GENERIC,
+                                        HIDP_LINK_COLLECTION_UNSPECIFIED,
+                                        HID_USAGE_GENERIC_X,
+                                        &ValueX,
+                                        DeviceExtension->PreparsedData,
+                                        DeviceExtension->Report,
+                                        DeviceExtension->ReportLength);
+
+                /* FIXME handle error */
+                ASSERT(Status == HIDP_STATUS_SUCCESS);
+
+                /* absolute pointing devices values need be in range 0 - 0xffff */
+                ASSERT(DeviceExtension->ValueCapsX.LogicalMax > 0);
+                ASSERT(DeviceExtension->ValueCapsX.LogicalMax > DeviceExtension->ValueCapsX.LogicalMin);
+
+                /* convert to logical range */
+                *LastX = (ValueX * VIRTUAL_SCREEN_SIZE_X) / DeviceExtension->ValueCapsX.LogicalMax;
+            }
+        }
+    }
+    else
+    {
+        /* get unscaled value */
+        Status = HidP_GetUsageValue(HidP_Input,
+                                    HID_USAGE_PAGE_GENERIC,
+                                    HIDP_LINK_COLLECTION_UNSPECIFIED,
+                                    HID_USAGE_GENERIC_X,
+                                    &ValueX,
+                                    DeviceExtension->PreparsedData,
+                                    DeviceExtension->Report,
+                                    DeviceExtension->ReportLength);
+
+        /* FIXME handle error */
+        ASSERT(Status == HIDP_STATUS_SUCCESS);
+
+        /* absolute pointing devices values need be in range 0 - 0xffff */
+        ASSERT(DeviceExtension->ValueCapsX.LogicalMax > 0);
+        ASSERT(DeviceExtension->ValueCapsX.LogicalMax > DeviceExtension->ValueCapsX.LogicalMin);
+
+        /* convert to logical range */
+        *LastX = (ValueX * VIRTUAL_SCREEN_SIZE_X) / DeviceExtension->ValueCapsX.LogicalMax;
+    }
 
+    if (!DeviceExtension->MouseAbsolute)
+    {
+        /* get scaled usage value y */
+        Status =  HidP_GetScaledUsageValue(HidP_Input,
+                                       HID_USAGE_PAGE_GENERIC,
+                                       HIDP_LINK_COLLECTION_UNSPECIFIED,
+                                       HID_USAGE_GENERIC_Y,
+                                       LastY,
+                                       DeviceExtension->PreparsedData,
+                                       DeviceExtension->Report,
+                                       DeviceExtension->ReportLength);
+
+        if (Status != HIDP_STATUS_SUCCESS)
+        {
+            // FIXME: handle more errors
+            if (Status == HIDP_STATUS_BAD_LOG_PHY_VALUES)
+            {
+                // assume it operates in absolute mode
+                DeviceExtension->MouseAbsolute = TRUE;
+
+                // get unscaled value
+                Status = HidP_GetUsageValue(HidP_Input,
+                                        HID_USAGE_PAGE_GENERIC,
+                                        HIDP_LINK_COLLECTION_UNSPECIFIED,
+                                        HID_USAGE_GENERIC_Y,
+                                        &ValueY,
+                                        DeviceExtension->PreparsedData,
+                                        DeviceExtension->Report,
+                                        DeviceExtension->ReportLength);
+
+                /* FIXME handle error */
+                ASSERT(Status == HIDP_STATUS_SUCCESS);
+
+                /* absolute pointing devices values need be in range 0 - 0xffff */
+                ASSERT(DeviceExtension->ValueCapsY.LogicalMax > 0);
+                ASSERT(DeviceExtension->ValueCapsY.LogicalMax > DeviceExtension->ValueCapsY.LogicalMin);
+
+                /* convert to logical range */
+                *LastY = (ValueY * VIRTUAL_SCREEN_SIZE_Y) / DeviceExtension->ValueCapsY.LogicalMax;
+            }
+        }
+    }
+    else
+    {
+        // get unscaled value
+        Status = HidP_GetUsageValue(HidP_Input,
+                                HID_USAGE_PAGE_GENERIC,
+                                HIDP_LINK_COLLECTION_UNSPECIFIED,
+                                HID_USAGE_GENERIC_Y,
+                                &ValueY,
+                                DeviceExtension->PreparsedData,
+                                DeviceExtension->Report,
+                                DeviceExtension->ReportLength);
+
+        /* FIXME handle error */
+        ASSERT(Status == HIDP_STATUS_SUCCESS);
+
+        /* absolute pointing devices values need be in range 0 - 0xffff */
+        ASSERT(DeviceExtension->ValueCapsY.LogicalMax > 0);
+        ASSERT(DeviceExtension->ValueCapsY.LogicalMax > DeviceExtension->ValueCapsY.LogicalMin);
+
+        /* convert to logical range */
+        *LastY = (ValueY * VIRTUAL_SCREEN_SIZE_Y) / DeviceExtension->ValueCapsY.LogicalMax;
+    }
 }
 
-
 VOID
 MouHid_GetButtonFlags(
     IN PMOUHID_DEVICE_EXTENSION DeviceExtension,
-    OUT PUSHORT ButtonFlags)
+    OUT PUSHORT ButtonFlags,
+    OUT PUSHORT Flags)
 {
     NTSTATUS Status;
     USAGE Usage;
@@ -68,10 +189,18 @@ MouHid_GetButtonFlags(
 
     /* init flags */
     *ButtonFlags = 0;
+    *Flags = 0;
 
     /* get usages */
     CurrentUsageListLength = DeviceExtension->UsageListLength;
-    Status = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, HIDP_LINK_COLLECTION_UNSPECIFIED, DeviceExtension->CurrentUsageList, &CurrentUsageListLength, DeviceExtension->PreparsedData, DeviceExtension->Report, DeviceExtension->ReportLength);
+    Status = HidP_GetUsages(HidP_Input,
+                            HID_USAGE_PAGE_BUTTON,
+                            HIDP_LINK_COLLECTION_UNSPECIFIED,
+                            DeviceExtension->CurrentUsageList,
+                            &CurrentUsageListLength,
+                            DeviceExtension->PreparsedData,
+                            DeviceExtension->Report,
+                            DeviceExtension->ReportLength);
     if (Status != HIDP_STATUS_SUCCESS)
     {
         DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status);
@@ -79,7 +208,11 @@ MouHid_GetButtonFlags(
     }
 
     /* extract usage list difference */
-    Status = HidP_UsageListDifference(DeviceExtension->PreviousUsageList, DeviceExtension->CurrentUsageList, DeviceExtension->BreakUsageList, DeviceExtension->MakeUsageList, DeviceExtension->UsageListLength);
+    Status = HidP_UsageListDifference(DeviceExtension->PreviousUsageList,
+                                      DeviceExtension->CurrentUsageList,
+                                      DeviceExtension->BreakUsageList,
+                                      DeviceExtension->MakeUsageList,
+                                      DeviceExtension->UsageListLength);
     if (Status != HIDP_STATUS_SUCCESS)
     {
         DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status);
@@ -132,6 +265,12 @@ MouHid_GetButtonFlags(
     TempList = DeviceExtension->CurrentUsageList;
     DeviceExtension->CurrentUsageList = DeviceExtension->PreviousUsageList;
     DeviceExtension->PreviousUsageList = TempList;
+
+    if (DeviceExtension->MouseAbsolute)
+    {
+        // mouse operates absolute
+        *Flags |= MOUSE_MOVE_ABSOLUTE;
+    }
 }
 
 VOID
@@ -172,9 +311,10 @@ MouHid_ReadCompletion(
     NTSTATUS Status;
     LONG LastX, LastY;
     MOUSE_INPUT_DATA MouseInputData;
+    USHORT Flags;
 
     /* get device extension */
-    DeviceExtension = (PMOUHID_DEVICE_EXTENSION)Context;
+    DeviceExtension = Context;
 
     if (Irp->IoStatus.Status == STATUS_PRIVILEGE_NOT_HELD ||
         Irp->IoStatus.Status == STATUS_DEVICE_NOT_CONNECTED ||
@@ -195,17 +335,18 @@ MouHid_ReadCompletion(
         return STATUS_MORE_PROCESSING_REQUIRED;
     }
 
-    /* get mouse change flags */
-    MouHid_GetButtonFlags(DeviceExtension, &ButtonFlags);
-
     /* get mouse change */
     MouHid_GetButtonMove(DeviceExtension, &LastX, &LastY);
 
+    /* get mouse change flags */
+    MouHid_GetButtonFlags(DeviceExtension, &ButtonFlags, &Flags);
+
     /* init input data */
     RtlZeroMemory(&MouseInputData, sizeof(MOUSE_INPUT_DATA));
 
     /* init input data */
     MouseInputData.ButtonFlags = ButtonFlags;
+    MouseInputData.Flags = Flags;
     MouseInputData.LastX = LastX;
     MouseInputData.LastY = LastY;
 
@@ -214,20 +355,33 @@ MouHid_ReadCompletion(
     {
         /* get usage */
         UsageValue = 0;
-        Status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_WHEEL, &UsageValue, DeviceExtension->PreparsedData, DeviceExtension->Report, DeviceExtension->ReportLength);
-        if (Status == HIDP_STATUS_SUCCESS)
+        Status = HidP_GetScaledUsageValue(HidP_Input,
+                                          HID_USAGE_PAGE_GENERIC,
+                                          HIDP_LINK_COLLECTION_UNSPECIFIED,
+                                          HID_USAGE_GENERIC_WHEEL,
+                                          &UsageValue,
+                                          DeviceExtension->PreparsedData,
+                                          DeviceExtension->Report,
+                                          DeviceExtension->ReportLength);
+        if (Status == HIDP_STATUS_SUCCESS && UsageValue != 0)
         {
             /* store wheel status */
             MouseInputData.ButtonFlags |= MOUSE_WHEEL;
-            MouseInputData.ButtonData = (USHORT)UsageValue; /* FIXME */
+            MouseInputData.ButtonData = (USHORT)(UsageValue * WHEEL_DELTA);
         }
         else
         {
-            DPRINT1("[MOUHID] failed to get wheel status with %x\n", Status);
+            DPRINT("[MOUHID] failed to get wheel status with %x\n", Status);
         }
     }
 
-    DPRINT1("[MOUHID] LastX %ld LastY %ld Flags %x ButtonData %x\n", MouseInputData.LastX, MouseInputData.LastY, MouseInputData.ButtonFlags, MouseInputData.ButtonData);
+    DPRINT("[MOUHID] ReportData %02x %02x %02x %02x %02x %02x %02x\n",
+        DeviceExtension->Report[0] & 0xFF,
+        DeviceExtension->Report[1] & 0xFF, DeviceExtension->Report[2] & 0xFF,
+        DeviceExtension->Report[3] & 0xFF, DeviceExtension->Report[4] & 0xFF,
+        DeviceExtension->Report[5] & 0xFF, DeviceExtension->Report[6] & 0xFF);
+
+    DPRINT("[MOUHID] LastX %ld LastY %ld Flags %x ButtonFlags %x ButtonData %x\n", MouseInputData.LastX, MouseInputData.LastY, MouseInputData.Flags, MouseInputData.ButtonFlags, MouseInputData.ButtonData);
 
     /* dispatch mouse action */
     MouHid_DispatchInputData(DeviceExtension, &MouseInputData);
@@ -282,7 +436,7 @@ MouHid_CreateCompletion(
     IN PIRP  Irp,
     IN PVOID  Context)
 {
-    KeSetEvent((PKEVENT)Context, 0, FALSE);
+    KeSetEvent(Context, 0, FALSE);
     return STATUS_MORE_PROCESSING_REQUIRED;
 }
 
@@ -298,10 +452,10 @@ MouHid_Create(
     KEVENT Event;
     PMOUHID_DEVICE_EXTENSION DeviceExtension;
 
-    DPRINT1("MOUHID: IRP_MJ_CREATE\n");
+    DPRINT("MOUHID: IRP_MJ_CREATE\n");
 
     /* get device extension */
-    DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
 
     /* get stack location */
     IoStack = IoGetCurrentIrpStackLocation(Irp);
@@ -343,11 +497,11 @@ MouHid_Create(
              DeviceExtension->FileObject = IoStack->FileObject;
 
              /* reset event */
-             KeResetEvent(&DeviceExtension->ReadCompletionEvent);
+             KeClearEvent(&DeviceExtension->ReadCompletionEvent);
 
              /* initiating read */
              Status = MouHid_InitiateRead(DeviceExtension);
-             DPRINT1("[MOUHID] MouHid_InitiateRead: status %x\n", Status);
+             DPRINT("[MOUHID] MouHid_InitiateRead: status %x\n", Status);
              if (Status == STATUS_PENDING)
              {
                  /* report irp is pending */
@@ -372,7 +526,7 @@ MouHid_Close(
     PMOUHID_DEVICE_EXTENSION DeviceExtension;
 
     /* get device extension */
-    DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
 
     DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive);
 
@@ -414,14 +568,15 @@ MouHid_InternalDeviceControl(
     /* get current stack location */
     IoStack = IoGetCurrentIrpStackLocation(Irp);
 
-    DPRINT1("[MOUHID] InternalDeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
+    DPRINT("[MOUHID] InternalDeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
 
     /* get device extension */
-    DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
 
     /* handle requests */
-    if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_MOUSE_QUERY_ATTRIBUTES)
+    switch (IoStack->Parameters.DeviceIoControl.IoControlCode)
     {
+    case IOCTL_MOUSE_QUERY_ATTRIBUTES:
          /* verify output buffer length */
          if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES))
          {
@@ -433,7 +588,7 @@ MouHid_InternalDeviceControl(
          }
 
          /* get output buffer */
-         Attributes = (PMOUSE_ATTRIBUTES)Irp->AssociatedIrp.SystemBuffer;
+         Attributes = Irp->AssociatedIrp.SystemBuffer;
 
          /* type of mouse */
          Attributes->MouseIdentifier = DeviceExtension->MouseIdentifier;
@@ -447,19 +602,18 @@ MouHid_InternalDeviceControl(
          /* queue length */
          Attributes->InputDataQueueLength = 2;
 
-         DPRINT1("[MOUHID] MouseIdentifier %x\n", Attributes->MouseIdentifier);
-         DPRINT1("[MOUHID] NumberOfButtons %x\n", Attributes->NumberOfButtons);
-         DPRINT1("[MOUHID] SampleRate %x\n", Attributes->SampleRate);
-         DPRINT1("[MOUHID] InputDataQueueLength %x\n", Attributes->InputDataQueueLength);
+         DPRINT("[MOUHID] MouseIdentifier %x\n", Attributes->MouseIdentifier);
+         DPRINT("[MOUHID] NumberOfButtons %x\n", Attributes->NumberOfButtons);
+         DPRINT("[MOUHID] SampleRate %x\n", Attributes->SampleRate);
+         DPRINT("[MOUHID] InputDataQueueLength %x\n", Attributes->InputDataQueueLength);
 
          /* complete request */
          Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
          Irp->IoStatus.Status = STATUS_SUCCESS;
          IoCompleteRequest(Irp, IO_NO_INCREMENT);
          return STATUS_SUCCESS;
-    }
-    else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_CONNECT)
-    {
+
+    case IOCTL_INTERNAL_MOUSE_CONNECT:
          /* verify input buffer length */
          if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA))
          {
@@ -479,7 +633,7 @@ MouHid_InternalDeviceControl(
          }
 
          /* get connect data */
-         Data = (PCONNECT_DATA)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
+         Data = IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
 
          /* store connect details */
          DeviceExtension->ClassDeviceObject = Data->ClassDeviceObject;
@@ -489,23 +643,20 @@ MouHid_InternalDeviceControl(
          Irp->IoStatus.Status = STATUS_SUCCESS;
          IoCompleteRequest(Irp, IO_NO_INCREMENT);
          return STATUS_SUCCESS;
-    }
-    else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_DISCONNECT)
-    {
+
+    case IOCTL_INTERNAL_MOUSE_DISCONNECT:
         /* not supported */
         Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
         IoCompleteRequest(Irp, IO_NO_INCREMENT);
         return STATUS_NOT_IMPLEMENTED;
-    }
-    else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_ENABLE)
-    {
+
+    case IOCTL_INTERNAL_MOUSE_ENABLE:
         /* not supported */
         Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
         IoCompleteRequest(Irp, IO_NO_INCREMENT);
         return STATUS_NOT_SUPPORTED;
-    }
-    else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_DISABLE)
-    {
+
+    case IOCTL_INTERNAL_MOUSE_DISABLE:
         /* not supported */
         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
         IoCompleteRequest(Irp, IO_NO_INCREMENT);
@@ -528,7 +679,7 @@ MouHid_DeviceControl(
     PMOUHID_DEVICE_EXTENSION DeviceExtension;
 
     /* get device extension */
-    DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
 
     /* skip stack location */
     IoSkipCurrentIrpStackLocation(Irp);
@@ -543,8 +694,25 @@ MouHid_Power(
     IN PDEVICE_OBJECT DeviceObject,
     IN PIRP Irp)
 {
-    UNIMPLEMENTED
-    return STATUS_NOT_IMPLEMENTED;
+    PMOUHID_DEVICE_EXTENSION DeviceExtension;
+
+    DeviceExtension = DeviceObject->DeviceExtension;
+    PoStartNextPowerIrp(Irp);
+    IoSkipCurrentIrpStackLocation(Irp);
+    return PoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+}
+
+NTSTATUS
+NTAPI
+MouHid_SystemControl(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    PMOUHID_DEVICE_EXTENSION DeviceExtension;
+
+    DeviceExtension = DeviceObject->DeviceExtension;
+    IoSkipCurrentIrpStackLocation(Irp);
+    return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
 }
 
 NTSTATUS
@@ -563,13 +731,21 @@ MouHid_SubmitRequest(
     IO_STATUS_BLOCK IoStatus;
 
     /* get device extension */
-    DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
 
     /* init event */
     KeInitializeEvent(&Event, NotificationEvent, FALSE);
 
     /* build request */
-    Irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceExtension->NextDeviceObject, InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize, FALSE, &Event, &IoStatus);
+    Irp = IoBuildDeviceIoControlRequest(IoControlCode,
+                                        DeviceExtension->NextDeviceObject,
+                                        InputBuffer,
+                                        InputBufferSize,
+                                        OutputBuffer,
+                                        OutputBufferSize,
+                                        FALSE,
+                                        &Event,
+                                        &IoStatus);
     if (!Irp)
     {
         /* no memory */
@@ -599,16 +775,21 @@ MouHid_StartDevice(
     HID_COLLECTION_INFORMATION Information;
     PVOID PreparsedData;
     HIDP_CAPS Capabilities;
-    ULONG ValueCapsLength;
+    USHORT ValueCapsLength;
     HIDP_VALUE_CAPS ValueCaps;
     PMOUHID_DEVICE_EXTENSION DeviceExtension;
-    PUSHORT Buffer;
+    PUSAGE Buffer;
 
     /* get device extension */
-    DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
 
     /* query collection information */
-    Status = MouHid_SubmitRequest(DeviceObject, IOCTL_HID_GET_COLLECTION_INFORMATION, 0, NULL, sizeof(HID_COLLECTION_INFORMATION), &Information);
+    Status = MouHid_SubmitRequest(DeviceObject,
+                                  IOCTL_HID_GET_COLLECTION_INFORMATION,
+                                  0,
+                                  NULL,
+                                  sizeof(HID_COLLECTION_INFORMATION),
+                                  &Information);
     if (!NT_SUCCESS(Status))
     {
         /* failed to query collection information */
@@ -617,7 +798,7 @@ MouHid_StartDevice(
     }
 
     /* lets allocate space for preparsed data */
-    PreparsedData = ExAllocatePool(NonPagedPool, Information.DescriptorSize);
+    PreparsedData = ExAllocatePoolWithTag(NonPagedPool, Information.DescriptorSize, MOUHID_TAG);
     if (!PreparsedData)
     {
         /* no memory */
@@ -626,62 +807,74 @@ MouHid_StartDevice(
     }
 
     /* now obtain the preparsed data */
-    Status = MouHid_SubmitRequest(DeviceObject, IOCTL_HID_GET_COLLECTION_DESCRIPTOR, 0, NULL, Information.DescriptorSize, PreparsedData);
+    Status = MouHid_SubmitRequest(DeviceObject,
+                                  IOCTL_HID_GET_COLLECTION_DESCRIPTOR,
+                                  0,
+                                  NULL,
+                                  Information.DescriptorSize,
+                                  PreparsedData);
     if (!NT_SUCCESS(Status))
     {
         /* failed to get preparsed data */
         DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status);
-        ExFreePool(PreparsedData);
+        ExFreePoolWithTag(PreparsedData, MOUHID_TAG);
         return Status;
     }
 
     /* lets get the caps */
     Status = HidP_GetCaps(PreparsedData, &Capabilities);
-    if (!NT_SUCCESS(Status))
+    if (Status != HIDP_STATUS_SUCCESS)
     {
         /* failed to get capabilities */
         DPRINT1("[MOUHID] failed to obtain caps with %x\n", Status);
-        ExFreePool(PreparsedData);
+        ExFreePoolWithTag(PreparsedData, MOUHID_TAG);
         return Status;
     }
 
-    DPRINT1("[MOUHID] Usage %x UsagePage %x\n", Capabilities.Usage, Capabilities.UsagePage, Capabilities.InputReportByteLength);
+    DPRINT("[MOUHID] Usage %x UsagePage %x InputReportLength %lu\n", Capabilities.Usage, Capabilities.UsagePage, Capabilities.InputReportByteLength);
 
     /* verify capabilities */
-    if (Capabilities.Usage != HID_USAGE_GENERIC_POINTER && Capabilities.Usage != HID_USAGE_GENERIC_MOUSE || Capabilities.UsagePage != HID_USAGE_PAGE_GENERIC)
+    if ((Capabilities.Usage != HID_USAGE_GENERIC_POINTER && Capabilities.Usage != HID_USAGE_GENERIC_MOUSE) || Capabilities.UsagePage != HID_USAGE_PAGE_GENERIC)
     {
         /* not supported */
-        ExFreePool(PreparsedData);
+        ExFreePoolWithTag(PreparsedData, MOUHID_TAG);
         return STATUS_UNSUCCESSFUL;
     }
 
-    /* init input report*/
+    /* init input report */
     DeviceExtension->ReportLength = Capabilities.InputReportByteLength;
     ASSERT(DeviceExtension->ReportLength);
-    DeviceExtension->Report = (PUCHAR)ExAllocatePool(NonPagedPool, DeviceExtension->ReportLength);
+    DeviceExtension->Report = ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->ReportLength, MOUHID_TAG);
     ASSERT(DeviceExtension->Report);
     RtlZeroMemory(DeviceExtension->Report, DeviceExtension->ReportLength);
 
     /* build mdl */
-    DeviceExtension->ReportMDL = IoAllocateMdl(DeviceExtension->Report, DeviceExtension->ReportLength, FALSE, FALSE, NULL);
+    DeviceExtension->ReportMDL = IoAllocateMdl(DeviceExtension->Report,
+                                               DeviceExtension->ReportLength,
+                                               FALSE,
+                                               FALSE,
+                                               NULL);
     ASSERT(DeviceExtension->ReportMDL);
 
     /* init mdl */
     MmBuildMdlForNonPagedPool(DeviceExtension->ReportMDL);
 
     /* get max number of buttons */
-    Buttons = HidP_MaxUsageListLength(HidP_Input, HID_USAGE_PAGE_BUTTON, PreparsedData);
-    DPRINT1("[MOUHID] Buttons %lu\n", Buttons);
+    Buttons = HidP_MaxUsageListLength(HidP_Input,
+                                      HID_USAGE_PAGE_BUTTON,
+                                      PreparsedData);
+    DPRINT("[MOUHID] Buttons %lu\n", Buttons);
     ASSERT(Buttons > 0);
 
     /* now allocate an array for those buttons */
-    Buffer = ExAllocatePool(NonPagedPool, sizeof(USAGE) * 4 * Buttons);
+    Buffer = ExAllocatePoolWithTag(NonPagedPool, sizeof(USAGE) * 4 * Buttons, MOUHID_TAG);
     if (!Buffer)
     {
         /* no memory */
-        ExFreePool(PreparsedData);
+        ExFreePoolWithTag(PreparsedData, MOUHID_TAG);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
+    DeviceExtension->UsageListBuffer = Buffer;
 
     /* init usage lists */
     RtlZeroMemory(Buffer, sizeof(USAGE) * 4 * Buttons);
@@ -700,35 +893,67 @@ MouHid_StartDevice(
     DeviceExtension->PreparsedData = PreparsedData;
 
     ValueCapsLength = 1;
-    HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_X, &ValueCaps, &ValueCapsLength, PreparsedData);
+    HidP_GetSpecificValueCaps(HidP_Input,
+                              HID_USAGE_PAGE_GENERIC,
+                              HIDP_LINK_COLLECTION_UNSPECIFIED,
+                              HID_USAGE_GENERIC_X,
+                              &DeviceExtension->ValueCapsX,
+                              &ValueCapsLength,
+                              PreparsedData);
 
     ValueCapsLength = 1;
-    HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_Y, &ValueCaps, &ValueCapsLength, PreparsedData);
+    HidP_GetSpecificValueCaps(HidP_Input,
+                              HID_USAGE_PAGE_GENERIC,
+                              HIDP_LINK_COLLECTION_UNSPECIFIED,
+                              HID_USAGE_GENERIC_Y,
+                              &DeviceExtension->ValueCapsY,
+                              &ValueCapsLength,
+                              PreparsedData);
 
     /* now check for wheel mouse support */
     ValueCapsLength = 1;
-    Status = HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_WHEEL, &ValueCaps, &ValueCapsLength, PreparsedData);
+    Status = HidP_GetSpecificValueCaps(HidP_Input,
+                                       HID_USAGE_PAGE_GENERIC,
+                                       HIDP_LINK_COLLECTION_UNSPECIFIED,
+                                       HID_USAGE_GENERIC_WHEEL,
+                                       &ValueCaps,
+                                       &ValueCapsLength,
+                                       PreparsedData);
     if (Status == HIDP_STATUS_SUCCESS )
     {
         /* mouse has wheel support */
         DeviceExtension->MouseIdentifier = WHEELMOUSE_HID_HARDWARE;
         DeviceExtension->WheelUsagePage = ValueCaps.UsagePage;
-        DPRINT1("[MOUHID] mouse wheel support detected\n", Status);
+        DPRINT("[MOUHID] mouse wheel support detected\n", Status);
     }
     else
     {
         /* check if the mouse has z-axis */
         ValueCapsLength = 1;
-        Status = HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_Z, &ValueCaps, &ValueCapsLength, PreparsedData);
+        Status = HidP_GetSpecificValueCaps(HidP_Input,
+                                           HID_USAGE_PAGE_GENERIC,
+                                           HIDP_LINK_COLLECTION_UNSPECIFIED,
+                                           HID_USAGE_GENERIC_Z,
+                                           &ValueCaps,
+                                           &ValueCapsLength,
+                                           PreparsedData);
         if (Status == HIDP_STATUS_SUCCESS && ValueCapsLength == 1)
         {
             /* wheel support */
             DeviceExtension->MouseIdentifier = WHEELMOUSE_HID_HARDWARE;
             DeviceExtension->WheelUsagePage = ValueCaps.UsagePage;
-            DPRINT1("[MOUHID] mouse wheel support detected with z-axis\n", Status);
+            DPRINT("[MOUHID] mouse wheel support detected with z-axis\n", Status);
         }
     }
 
+    /* check if mice is absolute */
+    if (DeviceExtension->ValueCapsY.LogicalMax > DeviceExtension->ValueCapsY.LogicalMin ||
+        DeviceExtension->ValueCapsX.LogicalMax > DeviceExtension->ValueCapsX.LogicalMin)
+    {
+        /* mice is absolute */
+        DeviceExtension->MouseAbsolute = TRUE;
+    }
+
     /* completed successfully */
     return STATUS_SUCCESS;
 }
@@ -740,10 +965,52 @@ MouHid_StartDeviceCompletion(
     IN PIRP  Irp,
     IN PVOID  Context)
 {
-    KeSetEvent((PKEVENT)Context, 0, FALSE);
+    KeSetEvent(Context, 0, FALSE);
     return STATUS_MORE_PROCESSING_REQUIRED;
 }
 
+NTSTATUS
+NTAPI
+MouHid_FreeResources(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    PMOUHID_DEVICE_EXTENSION DeviceExtension;
+
+    /* get device extension */
+    DeviceExtension = DeviceObject->DeviceExtension;
+
+    /* free resources */
+    if (DeviceExtension->PreparsedData)
+    {
+        ExFreePoolWithTag(DeviceExtension->PreparsedData, MOUHID_TAG);
+        DeviceExtension->PreparsedData = NULL;
+    }
+
+    if (DeviceExtension->UsageListBuffer)
+    {
+        ExFreePoolWithTag(DeviceExtension->UsageListBuffer, MOUHID_TAG);
+        DeviceExtension->UsageListBuffer = NULL;
+        DeviceExtension->CurrentUsageList = NULL;
+        DeviceExtension->PreviousUsageList = NULL;
+        DeviceExtension->MakeUsageList = NULL;
+        DeviceExtension->BreakUsageList = NULL;
+    }
+
+    if (DeviceExtension->ReportMDL)
+    {
+        IoFreeMdl(DeviceExtension->ReportMDL);
+        DeviceExtension->ReportMDL = NULL;
+    }
+
+    if (DeviceExtension->Report)
+    {
+        ExFreePoolWithTag(DeviceExtension->Report, MOUHID_TAG);
+        DeviceExtension->Report = NULL;
+    }
+
+    return STATUS_SUCCESS;
+}
+
 NTSTATUS
 NTAPI
 MouHid_Flush(
@@ -754,7 +1021,7 @@ MouHid_Flush(
     PMOUHID_DEVICE_EXTENSION DeviceExtension;
 
     /* get device extension */
-    DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
 
     /* skip current stack location */
     IoSkipCurrentIrpStackLocation(Irp);
@@ -782,14 +1049,22 @@ MouHid_Pnp(
     PMOUHID_DEVICE_EXTENSION DeviceExtension;
 
     /* get device extension */
-    DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
 
     /* get current irp stack */
     IoStack = IoGetCurrentIrpStackLocation(Irp);
-    DPRINT1("[MOUHID] IRP_MJ_PNP Request: %x\n", IoStack->MinorFunction);
+    DPRINT("[MOUHID] IRP_MJ_PNP Request: %x\n", IoStack->MinorFunction);
 
-    if (IoStack->MinorFunction == IRP_MN_STOP_DEVICE || IoStack->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE || IoStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE || IoStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE)
+    switch (IoStack->MinorFunction)
     {
+    case IRP_MN_STOP_DEVICE:
+    case IRP_MN_SURPRISE_REMOVAL:
+        /* free resources */
+        MouHid_FreeResources(DeviceObject);
+    case IRP_MN_CANCEL_REMOVE_DEVICE:
+    case IRP_MN_QUERY_STOP_DEVICE:
+    case IRP_MN_CANCEL_STOP_DEVICE:
+    case IRP_MN_QUERY_REMOVE_DEVICE:
         /* indicate success */
         Irp->IoStatus.Status = STATUS_SUCCESS;
 
@@ -798,14 +1073,19 @@ MouHid_Pnp(
 
         /* dispatch to lower device */
         return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
-    }
-    else if (IoStack->MinorFunction == IRP_MN_REMOVE_DEVICE)
-    {
+
+    case IRP_MN_REMOVE_DEVICE:
         /* FIXME synchronization */
 
+        /* request stop */
+        DeviceExtension->StopReadReport = TRUE;
+
         /* cancel irp */
         IoCancelIrp(DeviceExtension->Irp);
 
+        /* free resources */
+        MouHid_FreeResources(DeviceObject);
+
         /* indicate success */
         Irp->IoStatus.Status = STATUS_SUCCESS;
 
@@ -815,13 +1095,22 @@ MouHid_Pnp(
         /* dispatch to lower device */
         Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
 
+        /* wait for completion of stop event */
+        KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL);
+
+        /* free irp */
         IoFreeIrp(DeviceExtension->Irp);
+
+        /* detach device */
         IoDetachDevice(DeviceExtension->NextDeviceObject);
+
+        /* delete device */
         IoDeleteDevice(DeviceObject);
+
+        /* done */
         return Status;
-    }
-    else if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
-    {
+
+    case IRP_MN_START_DEVICE:
         /* init event */
         KeInitializeEvent(&Event, NotificationEvent, FALSE);
 
@@ -850,7 +1139,7 @@ MouHid_Pnp(
 
         /* lets start the device */
         Status = MouHid_StartDevice(DeviceObject);
-        DPRINT1("MouHid_StartDevice %x\n", Status);
+        DPRINT("MouHid_StartDevice %x\n", Status);
 
         /* complete request */
         Irp->IoStatus.Status = Status;
@@ -858,9 +1147,8 @@ MouHid_Pnp(
 
         /* done */
         return Status;
-    }
-    else
-    {
+
+    default:
         /* skip irp stack location */
         IoSkipCurrentIrpStackLocation(Irp);
 
@@ -881,7 +1169,13 @@ MouHid_AddDevice(
     POWER_STATE State;
 
     /* create device object */
-    Status = IoCreateDevice(DriverObject, sizeof(MOUHID_DEVICE_EXTENSION), NULL, FILE_DEVICE_MOUSE, 0, FALSE, &DeviceObject);
+    Status = IoCreateDevice(DriverObject,
+                            sizeof(MOUHID_DEVICE_EXTENSION),
+                            NULL,
+                            FILE_DEVICE_MOUSE,
+                            0,
+                            FALSE,
+                            &DeviceObject);
     if (!NT_SUCCESS(Status))
     {
         /* failed to create device object */
@@ -898,7 +1192,7 @@ MouHid_AddDevice(
     }
 
     /* get device extension */
-    DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
 
     /* zero extension */
     RtlZeroMemory(DeviceExtension, sizeof(MOUHID_DEVICE_EXTENSION));
@@ -932,7 +1226,7 @@ NTAPI
 MouHid_Unload(
     IN PDRIVER_OBJECT DriverObject)
 {
-    UNIMPLEMENTED
+    UNIMPLEMENTED;
 }
 
 
@@ -945,8 +1239,6 @@ DriverEntry(
     /* FIXME check for parameters 'UseOnlyMice', 'TreatAbsoluteAsRelative', 'TreatAbsolutePointerAsAbsolute' */
 
     /* initialize driver object */
-    DriverObject->DriverUnload = MouHid_Unload;
-    DriverObject->DriverExtension->AddDevice = MouHid_AddDevice;
     DriverObject->MajorFunction[IRP_MJ_CREATE] = MouHid_Create;
     DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouHid_Close;
     DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = MouHid_Flush;
@@ -954,6 +1246,7 @@ DriverEntry(
     DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = MouHid_InternalDeviceControl;
     DriverObject->MajorFunction[IRP_MJ_POWER] = MouHid_Power;
     DriverObject->MajorFunction[IRP_MJ_PNP] = MouHid_Pnp;
+    DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = MouHid_SystemControl;
     DriverObject->DriverUnload = MouHid_Unload;
     DriverObject->DriverExtension->AddDevice = MouHid_AddDevice;