Synchronize with trunk revision 59636 (just before Alex's CreateProcess revamp).
[reactos.git] / drivers / hid / hidusb / hidusb.c
index 7b3ffbd..d750fcc 100644 (file)
@@ -16,21 +16,21 @@ HidUsb_GetInputInterruptInterfaceHandle(
 {
     ULONG Index;
 
-     //
-     // sanity check
-     //
-     ASSERT(InterfaceInformation->NumberOfPipes);
-
-     for(Index = 0; Index < InterfaceInformation->NumberOfPipes; Index++)
-     {
-         //DPRINT1("[HIDUSB] EndpointAddress %x PipeType %x PipeHandle %x\n", InterfaceInformation->Pipes[Index].EndpointAddress, InterfaceInformation->Pipes[Index].PipeType, InterfaceInformation->Pipes[Index].PipeHandle);
-         if (InterfaceInformation->Pipes[Index].PipeType == UsbdPipeTypeInterrupt && (InterfaceInformation->Pipes[Index].EndpointAddress & USB_ENDPOINT_DIRECTION_MASK))
-         {
-             //
-             // found handle
-             //
-             return &InterfaceInformation->Pipes[Index];
-         }
+    //
+    // sanity check
+    //
+    ASSERT(InterfaceInformation->NumberOfPipes);
+
+    for (Index = 0; Index < InterfaceInformation->NumberOfPipes; Index++)
+    {
+        //DPRINT1("[HIDUSB] EndpointAddress %x PipeType %x PipeHandle %x\n", InterfaceInformation->Pipes[Index].EndpointAddress, InterfaceInformation->Pipes[Index].PipeType, InterfaceInformation->Pipes[Index].PipeHandle);
+        if (InterfaceInformation->Pipes[Index].PipeType == UsbdPipeTypeInterrupt && (InterfaceInformation->Pipes[Index].EndpointAddress & USB_ENDPOINT_DIRECTION_MASK))
+        {
+            //
+            // found handle
+            //
+            return &InterfaceInformation->Pipes[Index];
+        }
     }
 
     //
@@ -54,7 +54,7 @@ HidUsb_GetPortStatus(
     //
     // get device extension
     //
-    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
 
     //
     // init result
@@ -69,7 +69,15 @@ HidUsb_GetPortStatus(
     //
     // build irp
     //
-    Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_PORT_STATUS, DeviceExtension->NextDeviceObject, NULL, 0, NULL, 0, TRUE, &Event, &IoStatus);
+    Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_PORT_STATUS,
+                                        DeviceExtension->NextDeviceObject,
+                                        NULL,
+                                        0,
+                                        NULL,
+                                        0,
+                                        TRUE,
+                                        &Event,
+                                        &IoStatus);
     if (!Irp)
     {
         //
@@ -86,25 +94,25 @@ HidUsb_GetPortStatus(
     //
     // store result buffer
     //
-   IoStack->Parameters.Others.Argument1 = (PVOID)PortStatus;
-
-   //
-   // call driver
-   //
-   Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
-   if (Status == STATUS_PENDING)
-   {
-       //
-       // wait for completion
-       //
-       KeWaitForSingleObject(&Event, Executive, KernelMode, 0, NULL);
-       return IoStatus.Status;
-   }
-
-   //
-   // done
-   //
-   return Status;
+    IoStack->Parameters.Others.Argument1 = PortStatus;
+
+    //
+    // call driver
+    //
+    Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+    if (Status == STATUS_PENDING)
+    {
+        //
+        // wait for completion
+        //
+        KeWaitForSingleObject(&Event, Executive, KernelMode, 0, NULL);
+        return IoStatus.Status;
+    }
+
+    //
+    // done
+    //
+    return Status;
 }
 
 NTSTATUS
@@ -120,8 +128,8 @@ HidUsb_ResetInterruptPipe(
     //
     // get device extension
     //
-    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-    HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
+    HidDeviceExtension = DeviceExtension->MiniDeviceExtension;
 
     //
     // get interrupt pipe handle
@@ -134,7 +142,7 @@ HidUsb_ResetInterruptPipe(
     //
     // allocate urb
     //
-    Urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST));
+    Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST), HIDUSB_URB_TAG);
     if (!Urb)
     {
         //
@@ -159,7 +167,7 @@ HidUsb_ResetInterruptPipe(
     //
     // free urb
     //
-    ExFreePool(Urb);
+    ExFreePoolWithTag(Urb, HIDUSB_URB_TAG);
 
     //
     // done
@@ -175,17 +183,18 @@ HidUsb_AbortPipe(
     PHID_DEVICE_EXTENSION DeviceExtension;
     PURB Urb;
     NTSTATUS Status;
+    PUSBD_PIPE_INFORMATION PipeInformation;
 
     //
     // get device extension
     //
-    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-    HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
+    HidDeviceExtension = DeviceExtension->MiniDeviceExtension;
 
     //
     // allocate urb
     //
-    Urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST));
+    Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST), HIDUSB_URB_TAG);
     if (!Urb)
     {
         //
@@ -194,13 +203,20 @@ HidUsb_AbortPipe(
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
+    //
+    // get pipe information
+    //
+    PipeInformation = HidUsb_GetInputInterruptInterfaceHandle(HidDeviceExtension->InterfaceInfo);
+    ASSERT(PipeInformation);
+    ASSERT(PipeInformation->PipeHandle);
+
     //
     // init urb
     //
     RtlZeroMemory(Urb, sizeof(struct _URB_PIPE_REQUEST));
     Urb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
     Urb->UrbHeader.Length = sizeof(struct _URB_PIPE_REQUEST);
-    Urb->UrbPipeRequest.PipeHandle = HidDeviceExtension->ConfigurationHandle;
+    Urb->UrbPipeRequest.PipeHandle = PipeInformation->PipeHandle;
 
     //
     // dispatch request
@@ -210,7 +226,7 @@ HidUsb_AbortPipe(
     //
     // free urb
     //
-    ExFreePool(Urb);
+    ExFreePoolWithTag(Urb, HIDUSB_URB_TAG);
 
     //
     // done
@@ -218,7 +234,64 @@ HidUsb_AbortPipe(
     return Status;
 }
 
+NTSTATUS
+HidUsb_ResetPort(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    KEVENT Event;
+    PIRP Irp;
+    PHID_DEVICE_EXTENSION DeviceExtension;
+    IO_STATUS_BLOCK IoStatusBlock;
+    NTSTATUS Status;
+
+    //
+    // get device extension
+    //
+    DeviceExtension = DeviceObject->DeviceExtension;
+
+    //
+    // init event
+    //
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    //
+    // build irp
+    //
+    Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_RESET_PORT,
+                                        DeviceExtension->NextDeviceObject,
+                                        NULL,
+                                        0,
+                                        NULL,
+                                        0,
+                                        TRUE,
+                                        &Event,
+                                        &IoStatusBlock);
+    if (!Irp)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
 
+    //
+    // send the irp
+    //
+    Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+    if (Status == STATUS_PENDING)
+    {
+        //
+        // wait for request completion
+        //
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+        Status = IoStatusBlock.Status;
+    }
+
+    //
+    // done
+    //
+    return IoStatusBlock.Status;
+}
 
 NTSTATUS
 NTAPI
@@ -238,6 +311,11 @@ HidCreate(
     //
     ASSERT(IoStack->MajorFunction == IRP_MJ_CREATE || IoStack->MajorFunction == IRP_MJ_CLOSE);
 
+    //
+    // informational debug print
+    //
+    DPRINT("HIDUSB Request: %x\n", IoStack->MajorFunction);
+
     //
     // complete request
     //
@@ -246,16 +324,96 @@ HidCreate(
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
     //
-    // informal debug print
+    // done
     //
-    DPRINT1("HIDUSB Request: %x\n", IoStack->MajorFunction);
+    return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+HidUsb_ResetWorkerRoutine(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PVOID Ctx)
+{
+    NTSTATUS Status;
+    ULONG PortStatus;
+    PHID_USB_RESET_CONTEXT ResetContext;
+    PHID_DEVICE_EXTENSION DeviceExtension;
+
+    DPRINT("[HIDUSB] ResetWorkerRoutine\n");
 
     //
-    // done
+    // get context
     //
-    return STATUS_SUCCESS;
+    ResetContext = Ctx;
+
+    //
+    // get device extension
+    //
+    DeviceExtension = ResetContext->DeviceObject->DeviceExtension;
+
+    //
+    // get port status
+    //
+    Status = HidUsb_GetPortStatus(ResetContext->DeviceObject, &PortStatus);
+    DPRINT("[HIDUSB] ResetWorkerRoutine GetPortStatus %x PortStatus %x\n", Status, PortStatus);
+    if (NT_SUCCESS(Status))
+    {
+        if (!(PortStatus & USB_PORT_STATUS_ENABLE))
+        {
+            //
+            // port is disabled
+            //
+            Status = HidUsb_ResetInterruptPipe(ResetContext->DeviceObject);
+            DPRINT1("[HIDUSB] ResetWorkerRoutine ResetPipe %x\n", Status);
+        }
+        else
+        {
+            //
+            // abort pipe
+            //
+            Status = HidUsb_AbortPipe(ResetContext->DeviceObject);
+            DPRINT1("[HIDUSB] ResetWorkerRoutine AbortPipe %x\n", Status);
+            if (NT_SUCCESS(Status))
+            {
+                //
+                // reset port
+                //
+                Status = HidUsb_ResetPort(ResetContext->DeviceObject);
+                DPRINT1("[HIDUSB] ResetPort %x\n", Status);
+                if (Status == STATUS_DEVICE_DATA_ERROR)
+                {
+                    //
+                    // invalidate device state
+                    //
+                    IoInvalidateDeviceState(DeviceExtension->PhysicalDeviceObject);
+                }
+
+                //
+                // reset interrupt pipe
+                //
+                if (NT_SUCCESS(Status))
+                {
+                    //
+                    // reset pipe
+                    //
+                    Status = HidUsb_ResetInterruptPipe(ResetContext->DeviceObject);
+                    DPRINT1("[HIDUSB] ResetWorkerRoutine ResetPipe %x\n", Status);
+                }
+            }
+        }
+    }
+
+    //
+    // cleanup
+    //
+    ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
+    IoFreeWorkItem(ResetContext->WorkItem);
+    IoCompleteRequest(ResetContext->Irp, IO_NO_INCREMENT);
+    ExFreePoolWithTag(ResetContext, HIDUSB_TAG);
 }
 
+
 NTSTATUS
 NTAPI
 HidUsb_ReadReportCompletion(
@@ -263,47 +421,99 @@ HidUsb_ReadReportCompletion(
     IN PIRP Irp,
     IN PVOID Context)
 {
-    PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
-    PHID_DEVICE_EXTENSION DeviceExtension;
     PURB Urb;
-    PUCHAR Buffer;
-
-    //
-    // get device extension
-    //
-    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-    HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+    PHID_USB_RESET_CONTEXT ResetContext;
 
     //
     // get urb
     //
-    Urb = (PURB)Context;
+    Urb = Context;
     ASSERT(Urb);
 
+    DPRINT("[HIDUSB] HidUsb_ReadReportCompletion %p Status %x Urb Status %x\n", Irp, Irp->IoStatus, Urb->UrbHeader.Status);
+
+    if (Irp->PendingReturned)
+    {
+        //
+        // mark irp pending
+        //
+        IoMarkIrpPending(Irp);
+    }
+
     //
-    // FIXME handle error
+    // did the reading report succeed / cancelled
     //
-    ASSERT(Urb->UrbHeader.Status == USBD_STATUS_SUCCESS);
+    if (NT_SUCCESS(Irp->IoStatus.Status) || Irp->IoStatus.Status == STATUS_CANCELLED || Irp->IoStatus.Status == STATUS_DEVICE_NOT_CONNECTED)
+    {
+        //
+        // store result length
+        //
+        Irp->IoStatus.Information = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
+
+        //
+        // FIXME handle error
+        //
+        ASSERT(Urb->UrbHeader.Status == USBD_STATUS_SUCCESS);
+
+        //
+        // free the urb
+        //
+        ExFreePoolWithTag(Urb, HIDUSB_URB_TAG);
+
+        //
+        // finish completion
+        //
+        return STATUS_CONTINUE_COMPLETION;
+    }
 
     //
-    // FIXME handle error
+    // allocate reset context
     //
-    ASSERT(Irp->IoStatus.Status == STATUS_SUCCESS);
+    ResetContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(HID_USB_RESET_CONTEXT), HIDUSB_TAG);
+    if (ResetContext)
+    {
+        //
+        // allocate work item
+        //
+        ResetContext->WorkItem = IoAllocateWorkItem(DeviceObject);
+        if (ResetContext->WorkItem)
+        {
+            //
+            // init reset context
+            //
+            ResetContext->Irp = Irp;
+            ResetContext->DeviceObject = DeviceObject;
+
+            //
+            // queue the work item
+            //
+            IoQueueWorkItem(ResetContext->WorkItem, HidUsb_ResetWorkerRoutine, DelayedWorkQueue, ResetContext);
+
+            //
+            // free urb
+            //
+            ExFreePoolWithTag(Urb, HIDUSB_URB_TAG);
 
-    Buffer = Urb->UrbBulkOrInterruptTransfer.TransferBuffer;
-    ASSERT(Urb->UrbBulkOrInterruptTransfer.TransferBufferLength == 4);
+            //
+            // defer completion
+            //
+            return STATUS_MORE_PROCESSING_REQUIRED;
+        }
+        //
+        // free context
+        //
+        ExFreePoolWithTag(ResetContext, HIDUSB_TAG);
+    }
 
     //
-    // store result
+    // free urb
     //
-    Irp->IoStatus.Information = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
-
-    DPRINT("[HIDUSB] ReadCompletion Information %lu Buffer %x %x %x %x\n", Buffer[0] & 0xFF, Buffer[1] & 0xFF, Buffer[2] & 0xFF, Buffer[3] & 0xFF);
+    ExFreePoolWithTag(Urb, HIDUSB_URB_TAG);
 
     //
     // complete request
     //
-    return STATUS_SUCCESS;
+    return STATUS_CONTINUE_COMPLETION;
 }
 
 
@@ -322,8 +532,8 @@ HidUsb_ReadReport(
     //
     // get device extension
     //
-    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-    HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
+    HidDeviceExtension = DeviceExtension->MiniDeviceExtension;
 
     //
     // get current stack location
@@ -346,7 +556,7 @@ HidUsb_ReadReport(
     //
     // lets allocate urb
     //
-    Urb = (PURB)ExAllocatePool(NonPagedPool, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
+    Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), HIDUSB_URB_TAG);
     if (!Urb)
     {
         //
@@ -360,6 +570,13 @@ HidUsb_ReadReport(
     //
     RtlZeroMemory(Urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
 
+    //
+    // sanity check
+    //
+    ASSERT(Irp->UserBuffer);
+    ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength);
+    ASSERT(PipeInformation->PipeHandle);
+
     //
     // build the urb
     //
@@ -372,6 +589,11 @@ HidUsb_ReadReport(
                                            USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
                                            NULL);
 
+    //
+    // store configuration handle
+    //
+    Urb->UrbHeader.UsbdDeviceHandle = HidDeviceExtension->ConfigurationHandle;
+
     //
     // get next location to setup irp
     //
@@ -381,13 +603,17 @@ HidUsb_ReadReport(
     // init irp for lower driver
     //
     IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
-    IoStack->Parameters.Others.Argument1 = (PVOID)Urb;
     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+    IoStack->Parameters.DeviceIoControl.InputBufferLength = 0;
+    IoStack->Parameters.DeviceIoControl.OutputBufferLength = 0;
+    IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
+    IoStack->Parameters.Others.Argument1 = Urb;
+
 
     //
     // set completion routine
     //
-    IoSetCompletionRoutine(Irp, HidUsb_ReadReportCompletion, (PVOID)Urb, TRUE, TRUE, TRUE);
+    IoSetCompletionRoutine(Irp, HidUsb_ReadReportCompletion, Urb, TRUE, TRUE, TRUE);
 
     //
     // call driver
@@ -404,7 +630,7 @@ HidUsb_GetReportDescriptor(
 {
     PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
     PHID_DEVICE_EXTENSION DeviceExtension;
-    PUCHAR Report = NULL;
+    PVOID Report = NULL;
     ULONG BufferLength, Length;
     PIO_STACK_LOCATION IoStack;
     NTSTATUS Status;
@@ -412,8 +638,8 @@ HidUsb_GetReportDescriptor(
     //
     // get device extension
     //
-    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-    HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
+    HidDeviceExtension = DeviceExtension->MiniDeviceExtension;
 
     //
     // sanity checks
@@ -428,22 +654,41 @@ HidUsb_GetReportDescriptor(
     // FIXME: support old hid version
     //
     BufferLength = HidDeviceExtension->HidDescriptor->DescriptorList[0].wReportLength;
-    Status = Hid_GetDescriptor(DeviceObject, URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), &Report, &BufferLength, HidDeviceExtension->HidDescriptor->DescriptorList[0].bReportType, 0, 0);
+    Status = Hid_GetDescriptor(DeviceObject,
+                               URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE,
+                               sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+                               &Report,
+                               &BufferLength,
+                               HidDeviceExtension->HidDescriptor->DescriptorList[0].bReportType,
+                               0,
+                               HidDeviceExtension->InterfaceInfo->InterfaceNumber);
     if (!NT_SUCCESS(Status))
     {
         //
         // failed to get descriptor
+        // try with old hid version
         //
-        DPRINT("[HIDUSB] failed to get report descriptor with %x\n", Status);
-        ASSERT(FALSE);
-        return Status;
+        BufferLength = HidDeviceExtension->HidDescriptor->DescriptorList[0].wReportLength;
+        Status = Hid_GetDescriptor(DeviceObject,
+                                   URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT,
+                                   sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+                                   &Report,
+                                   &BufferLength,
+                                   HidDeviceExtension->HidDescriptor->DescriptorList[0].bReportType,
+                                   0,
+                                   0 /* FIXME*/);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT("[HIDUSB] failed to get report descriptor with %x\n", Status);
+            return Status;
+        }
     }
 
     //
     // get current stack location
     //
     IoStack = IoGetCurrentIrpStackLocation(Irp);
-    DPRINT1("[HIDUSB] GetReportDescriptor: Status %x ReportLength %lu OutputBufferLength %lu TransferredLength %lu\n", Status, HidDeviceExtension->HidDescriptor->DescriptorList[0].wReportLength, IoStack->Parameters.DeviceIoControl.OutputBufferLength, BufferLength);
+    DPRINT("[HIDUSB] GetReportDescriptor: Status %x ReportLength %lu OutputBufferLength %lu TransferredLength %lu\n", Status, HidDeviceExtension->HidDescriptor->DescriptorList[0].wReportLength, IoStack->Parameters.DeviceIoControl.OutputBufferLength, BufferLength);
 
     //
     // get length to copy
@@ -461,6 +706,11 @@ HidUsb_GetReportDescriptor(
     //
     Irp->IoStatus.Information = Length;
 
+    //
+    // free the report buffer
+    //
+    ExFreePoolWithTag(Report, HIDUSB_TAG);
+
     //
     // done
     //
@@ -484,15 +734,15 @@ HidInternalDeviceControl(
     //
     // get device extension
     //
-    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-    HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
+    HidDeviceExtension = DeviceExtension->MiniDeviceExtension;
 
     //
     // get current stack location
     //
     IoStack = IoGetCurrentIrpStackLocation(Irp);
 
-    switch(IoStack->Parameters.DeviceIoControl.IoControlCode)
+    switch (IoStack->Parameters.DeviceIoControl.IoControlCode)
     {
         case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
         {
@@ -509,10 +759,10 @@ HidInternalDeviceControl(
             //
             // store result
             //
-            DPRINT1("[HIDUSB] IOCTL_HID_GET_DEVICE_ATTRIBUTES\n");
+            DPRINT("[HIDUSB] IOCTL_HID_GET_DEVICE_ATTRIBUTES\n");
             ASSERT(HidDeviceExtension->DeviceDescriptor);
             Irp->IoStatus.Information = sizeof(HID_DESCRIPTOR);
-            Attributes = (PHID_DEVICE_ATTRIBUTES)Irp->UserBuffer;
+            Attributes = Irp->UserBuffer;
             Attributes->Size = sizeof(HID_DEVICE_ATTRIBUTES);
             Attributes->VendorID = HidDeviceExtension->DeviceDescriptor->idVendor;
             Attributes->ProductID = HidDeviceExtension->DeviceDescriptor->idProduct;
@@ -531,7 +781,7 @@ HidInternalDeviceControl(
             // sanity check
             //
             ASSERT(HidDeviceExtension->HidDescriptor);
-            DPRINT1("[HIDUSB] IOCTL_HID_GET_DEVICE_DESCRIPTOR DescriptorLength %lu OutputBufferLength %lu\n", HidDeviceExtension->HidDescriptor->bLength, IoStack->Parameters.DeviceIoControl.OutputBufferLength);
+            DPRINT("[HIDUSB] IOCTL_HID_GET_DEVICE_DESCRIPTOR DescriptorLength %lu OutputBufferLength %lu\n", HidDeviceExtension->HidDescriptor->bLength, IoStack->Parameters.DeviceIoControl.OutputBufferLength);
 
             //
             // store length
@@ -556,14 +806,14 @@ HidInternalDeviceControl(
         case IOCTL_HID_GET_REPORT_DESCRIPTOR:
         {
             Status = HidUsb_GetReportDescriptor(DeviceObject, Irp);
-            DPRINT1("[HIDUSB] IOCTL_HID_GET_REPORT_DESCRIPTOR Status %x\n", Status);
+            DPRINT("[HIDUSB] IOCTL_HID_GET_REPORT_DESCRIPTOR Status %x\n", Status);
             Irp->IoStatus.Status = Status;
             IoCompleteRequest(Irp, IO_NO_INCREMENT);
             return Status;
         }
         case IOCTL_HID_READ_REPORT:
         {
-            //DPRINT1("[HIDUSB] IOCTL_HID_READ_REPORT\n");
+            DPRINT("[HIDUSB] IOCTL_HID_READ_REPORT\n");
             Status = HidUsb_ReadReport(DeviceObject, Irp);
             return Status;
         }
@@ -656,9 +906,12 @@ HidPower(
     IN PDEVICE_OBJECT DeviceObject,
     IN PIRP Irp)
 {
-    UNIMPLEMENTED
-    ASSERT(FALSE);
-    return STATUS_NOT_IMPLEMENTED;
+    PHID_DEVICE_EXTENSION DeviceExtension;
+
+    DeviceExtension = DeviceObject->DeviceExtension;
+    PoStartNextPowerIrp(Irp);
+    IoSkipCurrentIrpStackLocation(Irp);
+    return PoCallDriver(DeviceExtension->NextDeviceObject, Irp);
 }
 
 NTSTATUS
@@ -672,12 +925,12 @@ HidSystemControl(
     //
     // get hid device extension
     //
-    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
 
     //
-    // copy stack location
+    // skip stack location
     //
-    IoCopyCurrentIrpStackLocationToNext(Irp);
+    IoSkipCurrentIrpStackLocation(Irp);
 
     //
     // submit request
@@ -695,7 +948,7 @@ Hid_PnpCompletion(
     //
     // signal event
     //
-    KeSetEvent((PRKEVENT)Context, 0, FALSE);
+    KeSetEvent(Context, 0, FALSE);
 
     //
     // done
@@ -710,7 +963,6 @@ Hid_DispatchUrb(
 {
     PIRP Irp;
     KEVENT Event;
-    PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
     PHID_DEVICE_EXTENSION DeviceExtension;
     IO_STATUS_BLOCK IoStatus;
     PIO_STACK_LOCATION IoStack;
@@ -724,14 +976,20 @@ Hid_DispatchUrb(
     //
     // get device extension
     //
-    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-    HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
-
+    DeviceExtension = DeviceObject->DeviceExtension;
 
     //
     // build irp
     //
-    Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB, DeviceExtension->NextDeviceObject, NULL, 0, NULL, 0, TRUE, &Event, &IoStatus);
+    Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
+                                        DeviceExtension->NextDeviceObject,
+                                        NULL,
+                                        0,
+                                        NULL,
+                                        0,
+                                        TRUE,
+                                        &Event,
+                                        &IoStatus);
     if (!Irp)
     {
         //
@@ -748,12 +1006,12 @@ Hid_DispatchUrb(
     //
     // store urb
     //
-    IoStack->Parameters.Others.Argument1 = (PVOID)Urb;
+    IoStack->Parameters.Others.Argument1 = Urb;
 
     //
     // set completion routine
     //
-    IoSetCompletionRoutine(Irp, Hid_PnpCompletion, (PVOID)&Event, TRUE, TRUE, TRUE);
+    IoSetCompletionRoutine(Irp, Hid_PnpCompletion, &Event, TRUE, TRUE, TRUE);
 
     //
     // call driver
@@ -781,7 +1039,7 @@ Hid_DispatchUrb(
         Status = IoStatus.Status;
     }
 
-    DPRINT1("[HIDUSB] DispatchUrb %x\n", Status);
+    DPRINT("[HIDUSB] DispatchUrb %x\n", Status);
 
 
     //
@@ -797,7 +1055,7 @@ Hid_GetDescriptor(
     IN USHORT UrbLength,
     IN OUT PVOID *UrbBuffer,
     IN OUT PULONG UrbBufferLength,
-    IN UCHAR DescriptorType, 
+    IN UCHAR DescriptorType,
     IN UCHAR Index,
     IN USHORT LanguageIndex)
 {
@@ -808,7 +1066,7 @@ Hid_GetDescriptor(
     //
     // allocate urb
     //
-    Urb = (PURB)ExAllocatePool(NonPagedPool, UrbLength);
+    Urb = ExAllocatePoolWithTag(NonPagedPool, UrbLength, HIDUSB_URB_TAG);
     if (!Urb)
     {
         //
@@ -825,13 +1083,13 @@ Hid_GetDescriptor(
         //
         // allocate buffer
         //
-        *UrbBuffer = ExAllocatePool(NonPagedPool, *UrbBufferLength);
+        *UrbBuffer = ExAllocatePoolWithTag(NonPagedPool, *UrbBufferLength, HIDUSB_TAG);
         if (!*UrbBuffer)
         {
             //
             // no memory
             //
-            ExFreePool(Urb);
+            ExFreePoolWithTag(Urb, HIDUSB_URB_TAG);
             return STATUS_INSUFFICIENT_RESOURCES;
         }
 
@@ -855,7 +1113,7 @@ Hid_GetDescriptor(
     //
     // set urb function
     //
-   Urb->UrbHeader.Function = UrbFunction;
+    Urb->UrbHeader.Function = UrbFunction;
 
     //
     // dispatch urb
@@ -872,14 +1130,14 @@ Hid_GetDescriptor(
             //
             // free allocated buffer
             //
-            ExFreePool(*UrbBuffer);
+            ExFreePoolWithTag(*UrbBuffer, HIDUSB_TAG);
             *UrbBuffer = NULL;
         }
 
         //
         // free urb
         //
-        ExFreePool(Urb);
+        ExFreePoolWithTag(Urb, HIDUSB_URB_TAG);
         *UrbBufferLength = 0;
         return Status;
     }
@@ -894,14 +1152,14 @@ Hid_GetDescriptor(
             //
             // free allocated buffer
             //
-            ExFreePool(*UrbBuffer);
+            ExFreePoolWithTag(*UrbBuffer, HIDUSB_TAG);
             *UrbBuffer = NULL;
         }
 
         //
         // free urb
         //
-        ExFreePool(Urb);
+        ExFreePoolWithTag(Urb, HIDUSB_URB_TAG);
         *UrbBufferLength = 0;
         return STATUS_UNSUCCESSFUL;
     }
@@ -914,7 +1172,7 @@ Hid_GetDescriptor(
     //
     // free urb
     //
-    ExFreePool(Urb);
+    ExFreePoolWithTag(Urb, HIDUSB_URB_TAG);
 
     //
     // completed successfully
@@ -936,8 +1194,8 @@ Hid_SelectConfiguration(
     //
     // get device extension
     //
-    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-    HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
+    HidDeviceExtension = DeviceExtension->MiniDeviceExtension;
 
     //
     // now parse the descriptors
@@ -949,6 +1207,13 @@ Hid_SelectConfiguration(
                                                               USB_DEVICE_CLASS_HUMAN_INTERFACE,
                                                              -1,
                                                              -1);
+    if (!InterfaceDescriptor)
+    {
+        //
+        // bogus configuration descriptor
+        //
+        return STATUS_INVALID_PARAMETER;
+    }
 
     //
     // sanity check
@@ -990,7 +1255,7 @@ Hid_SelectConfiguration(
         //
         // copy interface info
         //
-        HidDeviceExtension->InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)ExAllocatePool(NonPagedPool, Urb->UrbSelectConfiguration.Interface.Length);
+        HidDeviceExtension->InterfaceInfo = ExAllocatePoolWithTag(NonPagedPool, Urb->UrbSelectConfiguration.Interface.Length, HIDUSB_TAG);
         if (HidDeviceExtension->InterfaceInfo)
         {
             //
@@ -1003,7 +1268,91 @@ Hid_SelectConfiguration(
     //
     // free urb request
     //
-    ExFreePool(Urb);
+    ExFreePoolWithTag(Urb, 0);
+
+    //
+    // done
+    //
+    return Status;
+}
+
+NTSTATUS
+Hid_DisableConfiguration(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    PHID_DEVICE_EXTENSION DeviceExtension;
+    PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+    NTSTATUS Status;
+    PURB Urb;
+
+    //
+    // get device extension
+    //
+    DeviceExtension = DeviceObject->DeviceExtension;
+    HidDeviceExtension = DeviceExtension->MiniDeviceExtension;
+
+    //
+    // build urb
+    //
+    Urb = ExAllocatePoolWithTag(NonPagedPool,
+                                sizeof(struct _URB_SELECT_CONFIGURATION),
+                                HIDUSB_URB_TAG);
+    if (!Urb)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // format urb
+    //
+    UsbBuildSelectConfigurationRequest(Urb,
+                                       sizeof(struct _URB_SELECT_CONFIGURATION),
+                                       NULL);
+
+    //
+    // dispatch request
+    //
+    Status = Hid_DispatchUrb(DeviceObject, Urb);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("[HIDUSB] Dispatching unconfigure URB failed with %lx\n", Status);
+    }
+    else if (!USBD_SUCCESS(Urb->UrbHeader.Status))
+    {
+        DPRINT("[HIDUSB] Unconfigure URB failed with %lx\n", Status);
+    }
+
+    //
+    // free urb
+    //
+    ExFreePoolWithTag(Urb, HIDUSB_URB_TAG);
+
+    //
+    // free resources
+    //
+    HidDeviceExtension->ConfigurationHandle = NULL;
+
+    if (HidDeviceExtension->InterfaceInfo)
+    {
+        ExFreePoolWithTag(HidDeviceExtension->InterfaceInfo, HIDUSB_TAG);
+        HidDeviceExtension->InterfaceInfo = NULL;
+    }
+
+    if (HidDeviceExtension->ConfigurationDescriptor)
+    {
+        ExFreePoolWithTag(HidDeviceExtension->ConfigurationDescriptor, HIDUSB_TAG);
+        HidDeviceExtension->ConfigurationDescriptor = NULL;
+        HidDeviceExtension->HidDescriptor = NULL;
+    }
+
+    if (HidDeviceExtension->DeviceDescriptor)
+    {
+        ExFreePoolWithTag(HidDeviceExtension->DeviceDescriptor, HIDUSB_TAG);
+        HidDeviceExtension->DeviceDescriptor = NULL;
+    }
 
     //
     // done
@@ -1011,6 +1360,147 @@ Hid_SelectConfiguration(
     return Status;
 }
 
+NTSTATUS
+Hid_SetIdle(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    PURB Urb;
+    NTSTATUS Status;
+
+    //
+    // allocate urb
+    //
+    Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), HIDUSB_URB_TAG);
+    if (!Urb)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // zero urb
+    //
+    RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
+
+    //
+    // format urb
+    //
+    UsbBuildVendorRequest(Urb,
+                          URB_FUNCTION_CLASS_INTERFACE,
+                          sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
+                          0,
+                          0,
+                          USB_SET_IDLE_REQUEST, // HID_SET_IDLE
+                          0,
+                          0,
+                          NULL,
+                          NULL,
+                          0,
+                          NULL);
+
+    //
+    // dispatch urb
+    //
+    Status = Hid_DispatchUrb(DeviceObject, Urb);
+
+    //
+    // free urb
+    //
+    ExFreePoolWithTag(Urb, HIDUSB_URB_TAG);
+
+    //
+    // print status
+    //
+    DPRINT1("Status %x\n", Status);
+    return Status;
+}
+
+
+VOID
+Hid_GetProtocol(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+    PHID_DEVICE_EXTENSION DeviceExtension;
+    PURB Urb;
+    UCHAR Protocol[1];
+
+    //
+    // get device extension
+    //
+    DeviceExtension = DeviceObject->DeviceExtension;
+    HidDeviceExtension = DeviceExtension->MiniDeviceExtension;
+    ASSERT(HidDeviceExtension->InterfaceInfo);
+
+    if (HidDeviceExtension->InterfaceInfo->SubClass != 0x1)
+    {
+        //
+        // device does not support the boot protocol
+        //
+        return;
+    }
+
+    //
+    // allocate urb
+    //
+    Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), HIDUSB_URB_TAG);
+    if (!Urb)
+    {
+        //
+        // no memory
+        //
+        return;
+    }
+
+    //
+    // zero urb
+    //
+    RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
+
+    //
+    // format urb
+    //
+    UsbBuildVendorRequest(Urb,
+                          URB_FUNCTION_CLASS_INTERFACE,
+                          sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
+                          USBD_TRANSFER_DIRECTION_IN,
+                          0,
+                          USB_GET_PROTOCOL_REQUEST,
+                          0,
+                          0,
+                          Protocol,
+                          NULL,
+                          1,
+                          NULL);
+    Protocol[0] = 0xFF;
+
+    //
+    // dispatch urb
+    //
+    Hid_DispatchUrb(DeviceObject, Urb);
+
+    //
+    // free urb
+    //
+    ExFreePoolWithTag(Urb, HIDUSB_URB_TAG);
+
+    //
+    // boot protocol active 0x00 disabled 0x1
+    //
+    if (Protocol[0] != 0x1)
+    {
+        if (Protocol[0] == 0x00)
+        {
+            DPRINT1("[HIDUSB] Need to disable boot protocol!\n");
+        }
+        else
+        {
+            DPRINT1("[HIDUSB] Unexpected protocol value %x\n", Protocol[0] & 0xFF);
+        }
+    }
+}
 
 NTSTATUS
 Hid_PnpStart(
@@ -1026,14 +1516,21 @@ Hid_PnpStart(
     //
     // get device extension
     //
-    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-    HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
+    HidDeviceExtension = DeviceExtension->MiniDeviceExtension;
 
     //
     // get device descriptor
     //
     DescriptorLength = sizeof(USB_DEVICE_DESCRIPTOR);
-    Status = Hid_GetDescriptor(DeviceObject, URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), (PVOID*)&HidDeviceExtension->DeviceDescriptor, &DescriptorLength, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0);
+    Status = Hid_GetDescriptor(DeviceObject,
+                               URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE,
+                               sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+                               (PVOID *)&HidDeviceExtension->DeviceDescriptor,
+                               &DescriptorLength,
+                               USB_DEVICE_DESCRIPTOR_TYPE,
+                               0,
+                               0);
     if (!NT_SUCCESS(Status))
     {
         //
@@ -1047,7 +1544,14 @@ Hid_PnpStart(
     // now get the configuration descriptor
     //
     DescriptorLength = sizeof(USB_CONFIGURATION_DESCRIPTOR);
-    Status = Hid_GetDescriptor(DeviceObject, URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), (PVOID*)&HidDeviceExtension->ConfigurationDescriptor, &DescriptorLength, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0);
+    Status = Hid_GetDescriptor(DeviceObject,
+                               URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE,
+                               sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+                               (PVOID *)&HidDeviceExtension->ConfigurationDescriptor,
+                               &DescriptorLength,
+                               USB_CONFIGURATION_DESCRIPTOR_TYPE,
+                               0,
+                               0);
     if (!NT_SUCCESS(Status))
     {
         //
@@ -1072,13 +1576,20 @@ Hid_PnpStart(
     //
     // delete partial configuration descriptor
     //
-    ExFreePool(HidDeviceExtension->ConfigurationDescriptor);
+    ExFreePoolWithTag(HidDeviceExtension->ConfigurationDescriptor, HIDUSB_TAG);
     HidDeviceExtension->ConfigurationDescriptor = NULL;
 
     //
     // get full configuration descriptor
     //
-    Status = Hid_GetDescriptor(DeviceObject, URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), (PVOID*)&HidDeviceExtension->ConfigurationDescriptor, &DescriptorLength, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0);
+    Status = Hid_GetDescriptor(DeviceObject,
+                               URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE,
+                               sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+                               (PVOID *)&HidDeviceExtension->ConfigurationDescriptor,
+                               &DescriptorLength,
+                               USB_CONFIGURATION_DESCRIPTOR_TYPE,
+                               0,
+                               0);
     if (!NT_SUCCESS(Status))
     {
         //
@@ -1103,7 +1614,7 @@ Hid_PnpStart(
         //
         // no interface class
         //
-        DPRINT1("[HIDUSB] HID Class found\n");
+        DPRINT1("[HIDUSB] HID Interface descriptor not found\n");
         return STATUS_UNSUCCESSFUL;
     }
 
@@ -1139,15 +1650,33 @@ Hid_PnpStart(
         // done
         //
         DPRINT1("[HIDUSB] SelectConfiguration %x\n", Status);
-        return Status;
-    }
 
-    //
-    // FIXME parse hid descriptor
-    //
-    UNIMPLEMENTED
-    ASSERT(FALSE);
-    return STATUS_SUCCESS;
+        if (NT_SUCCESS(Status))
+        {
+            //
+            // now set the device idle
+            //
+            Hid_SetIdle(DeviceObject);
+
+            //
+            // get protocol
+            //
+            Hid_GetProtocol(DeviceObject);
+            return Status;
+        }
+    }
+    else
+    {
+        //
+        // FIXME parse hid descriptor
+        // select configuration
+        // set idle
+        // and get protocol
+        //
+        UNIMPLEMENTED
+        ASSERT(FALSE);
+    }
+    return Status;
 }
 
 
@@ -1159,58 +1688,70 @@ HidPnp(
 {
     NTSTATUS Status;
     PIO_STACK_LOCATION IoStack;
-    PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
     PHID_DEVICE_EXTENSION DeviceExtension;
     KEVENT Event;
 
     //
     // get device extension
     //
-    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-    HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
 
     //
     // get current stack location
     //
     IoStack = IoGetCurrentIrpStackLocation(Irp);
-    DPRINT1("[HIDUSB] Pnp %x\n", IoStack->MinorFunction);
+    DPRINT("[HIDUSB] Pnp %x\n", IoStack->MinorFunction);
 
     //
     // handle requests based on request type
     //
-    switch(IoStack->MinorFunction)
+    switch (IoStack->MinorFunction)
     {
         case IRP_MN_REMOVE_DEVICE:
         {
+            //
+            // unconfigure device
+            // FIXME: Call this on IRP_MN_SURPRISE_REMOVAL, but don't send URBs
+            // FIXME: Don't call this after we've already seen a surprise removal or stop
+            //
+            Hid_DisableConfiguration(DeviceObject);
+
             //
             // pass request onto lower driver
             //
             IoSkipCurrentIrpStackLocation(Irp);
             Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+
+            return Status;
+        }
+        case IRP_MN_QUERY_PNP_DEVICE_STATE:
+        {
             //
-            // free resources
+            // device can not be disabled
             //
-            if (HidDeviceExtension->HidDescriptor)
-            {
-                ExFreePool(HidDeviceExtension->HidDescriptor);
-                HidDeviceExtension->HidDescriptor = NULL;
-            }
+            Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
+
+            //
+            // pass request to next request
+            //
+            IoSkipCurrentIrpStackLocation(Irp);
+            Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
 
             //
             // done
             //
             return Status;
         }
-        case IRP_MN_QUERY_PNP_DEVICE_STATE:
+        case IRP_MN_QUERY_STOP_DEVICE:
+        case IRP_MN_QUERY_REMOVE_DEVICE:
         {
             //
-            // device can not be disabled
+            // we're fine with it
             //
-            Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
+            Irp->IoStatus.Status = STATUS_SUCCESS;
 
             //
-            // pass request to next request
+            // pass request to next driver
             //
             IoSkipCurrentIrpStackLocation(Irp);
             Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
@@ -1223,15 +1764,16 @@ HidPnp(
         case IRP_MN_STOP_DEVICE:
         {
             //
-            // FIXME: unconfigure the device
+            // unconfigure device
             //
+            Hid_DisableConfiguration(DeviceObject);
 
             //
             // prepare irp
             //
             KeInitializeEvent(&Event, NotificationEvent, FALSE);
             IoCopyCurrentIrpStackLocationToNext(Irp);
-            IoSetCompletionRoutine(Irp, Hid_PnpCompletion, (PVOID)&Event, TRUE, TRUE, TRUE);
+            IoSetCompletionRoutine(Irp, Hid_PnpCompletion, &Event, TRUE, TRUE, TRUE);
 
             //
             // send irp and wait for completion
@@ -1243,15 +1785,6 @@ HidPnp(
                 Status = Irp->IoStatus.Status;
             }
 
-            //
-            // free resources
-            //
-            if (HidDeviceExtension->HidDescriptor)
-            {
-                ExFreePool(HidDeviceExtension->HidDescriptor);
-                HidDeviceExtension->HidDescriptor = NULL;
-            }
-
             //
             // done
             //
@@ -1265,7 +1798,7 @@ HidPnp(
             //
             KeInitializeEvent(&Event, NotificationEvent, FALSE);
             IoCopyCurrentIrpStackLocationToNext(Irp);
-            IoSetCompletionRoutine(Irp, Hid_PnpCompletion, (PVOID)&Event, TRUE, TRUE, TRUE);
+            IoSetCompletionRoutine(Irp, Hid_PnpCompletion, &Event, TRUE, TRUE, TRUE);
 
             //
             // send irp and wait for completion
@@ -1277,13 +1810,12 @@ HidPnp(
                 Status = Irp->IoStatus.Status;
             }
 
-            if (NT_SUCCESS(Status))
+            if (NT_SUCCESS(Status) && IoStack->Parameters.DeviceCapabilities.Capabilities != NULL)
             {
                 //
-                // driver supports D1 & D2
+                // don't need to safely remove
                 //
-                IoStack->Parameters.DeviceCapabilities.Capabilities->DeviceD1 = TRUE;
-                IoStack->Parameters.DeviceCapabilities.Capabilities->DeviceD2 = TRUE;
+                IoStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
             }
 
             //
@@ -1299,7 +1831,7 @@ HidPnp(
             //
             KeInitializeEvent(&Event, NotificationEvent, FALSE);
             IoCopyCurrentIrpStackLocationToNext(Irp);
-            IoSetCompletionRoutine(Irp, Hid_PnpCompletion, (PVOID)&Event, TRUE, TRUE, TRUE);
+            IoSetCompletionRoutine(Irp, Hid_PnpCompletion, &Event, TRUE, TRUE, TRUE);
 
             //
             // send irp and wait for completion
@@ -1333,6 +1865,7 @@ HidPnp(
             // complete request
             //
             Irp->IoStatus.Status = Status;
+            DPRINT("[HIDUSB] IRP_MN_START_DEVICE Status %x\n", Status);
             IoCompleteRequest(Irp, IO_NO_INCREMENT);
             return Status;
         }
@@ -1359,8 +1892,8 @@ HidAddDevice(
     //
     // get device extension
     //
-    DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-    HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+    DeviceExtension = DeviceObject->DeviceExtension;
+    HidDeviceExtension = DeviceExtension->MiniDeviceExtension;
 
     //
     // init event
@@ -1373,6 +1906,15 @@ HidAddDevice(
     return STATUS_SUCCESS;
 }
 
+VOID
+NTAPI
+Hid_Unload(
+    IN PDRIVER_OBJECT DriverObject)
+{
+    UNIMPLEMENTED
+}
+
+
 NTSTATUS
 NTAPI
 DriverEntry(
@@ -1392,6 +1934,7 @@ DriverEntry(
     DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HidSystemControl;
     DriverObject->MajorFunction[IRP_MJ_PNP] = HidPnp;
     DriverObject->DriverExtension->AddDevice = HidAddDevice;
+    DriverObject->DriverUnload = Hid_Unload;
 
     //
     // prepare registration info
@@ -1415,8 +1958,8 @@ DriverEntry(
     //
     // informal debug
     //
-    DPRINT1("********* HIDUSB *********\n");
-    DPRINT1("HIDUSB Registration Status %x\n", Status);
+    DPRINT("********* HIDUSB *********\n");
+    DPRINT("HIDUSB Registration Status %x\n", Status);
 
     return Status;
 }