[HIDPARSE][HIDPARSER][LIBUSB][USBHUB] Merge USB stack improvements by Vardan Mikayely...
authorAmine Khaldi <amine.khaldi@reactos.org>
Fri, 27 Jan 2017 11:09:36 +0000 (11:09 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Fri, 27 Jan 2017 11:09:36 +0000 (11:09 +0000)
svn path=/trunk/; revision=73605

reactos/drivers/hid/hidparse/hidparse.c
reactos/drivers/usb/usbhub/CMakeLists.txt
reactos/drivers/usb/usbhub/fdo.c
reactos/drivers/usb/usbhub/misc.c
reactos/drivers/usb/usbhub/pdo.c
reactos/drivers/usb/usbhub/usbhub.c
reactos/drivers/usb/usbhub/usbhub.h
reactos/sdk/lib/drivers/hidparser/context.c
reactos/sdk/lib/drivers/hidparser/hidparser.c
reactos/sdk/lib/drivers/hidparser/parser.c
reactos/sdk/lib/drivers/libusb/hub_controller.cpp

index 6daed49..b3002a2 100644 (file)
@@ -125,6 +125,29 @@ HidP_GetCaps(
     return HidParser_GetCaps(&Parser, PreparsedData, Capabilities);
 }
 
+NTSTATUS
+TranslateStatusForUpperLayer(
+    IN HIDPARSER_STATUS Status)
+{
+    //
+    // now we are handling only this values, for others just return
+    // status as it is.
+    //
+    switch (Status)
+    {
+    case HIDPARSER_STATUS_INSUFFICIENT_RESOURCES:
+        return STATUS_INSUFFICIENT_RESOURCES;
+    case HIDPARSER_STATUS_INVALID_REPORT_TYPE:
+        return HIDP_STATUS_INVALID_REPORT_TYPE;
+    case HIDPARSER_STATUS_BUFFER_TOO_SMALL:
+        return STATUS_BUFFER_TOO_SMALL;
+    case HIDPARSER_STATUS_COLLECTION_NOT_FOUND:
+        return STATUS_NO_DATA_DETECTED;
+    default:
+        return Status;
+    }
+}
+
 NTSTATUS
 NTAPI
 HidP_GetCollectionDescription(
@@ -134,6 +157,7 @@ HidP_GetCollectionDescription(
     OUT PHIDP_DEVICE_DESC DeviceDescription)
 {
     HID_PARSER Parser;
+    NTSTATUS Status;
 
     //
     // init parser
@@ -143,7 +167,8 @@ HidP_GetCollectionDescription(
     //
     // get description;
     //
-    return HidParser_GetCollectionDescription(&Parser, ReportDesc, DescLength, PoolType, DeviceDescription);
+    Status = HidParser_GetCollectionDescription(&Parser, ReportDesc, DescLength, PoolType, DeviceDescription);
+    return TranslateStatusForUpperLayer(Status);
 }
 
 HIDAPI
index 2a8224d..db05f9f 100644 (file)
@@ -1,5 +1,6 @@
 
 add_definitions(-DDEBUG_MODE)
+add_definitions(-DNTDDI_VERSION=0x05020400)
 include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include)
 
 list(APPEND SOURCE
index 837a3a8..13b2081 100644 (file)
@@ -569,6 +569,11 @@ QueryInterface(
     Stack->Parameters.QueryInterface.Interface = Interface;
     Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
 
+    //
+    // Initialize the status block before sending the IRP
+    //
+    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+
     Status = IoCallDriver(DeviceObject, Irp);
 
     if (Status == STATUS_PENDING)
@@ -1089,8 +1094,7 @@ DestroyUsbChildDeviceObject(
     PDEVICE_OBJECT ChildDeviceObject = NULL;
     ULONG Index = 0;
 
-    DPRINT("Removing device on port %d (Child index: %d)\n", PortId, Index);
-
+    KeAcquireGuardedMutex(&HubDeviceExtension->HubMutexLock);
     for (Index = 0; Index < USB_MAXCHILDREN; Index++)
     {
         if (HubDeviceExtension->ChildDeviceObject[Index])
@@ -1111,12 +1115,17 @@ DestroyUsbChildDeviceObject(
     if (!ChildDeviceObject)
     {
         DPRINT1("Removal request for non-existant device!\n");
+        KeReleaseGuardedMutex(&HubDeviceExtension->HubMutexLock);
         return STATUS_UNSUCCESSFUL;
     }
 
+    DPRINT("Removing device on port %d (Child index: %d)\n", PortId, Index);
+
     /* Remove the device from the table */
     HubDeviceExtension->ChildDeviceObject[Index] = NULL;
 
+    KeReleaseGuardedMutex(&HubDeviceExtension->HubMutexLock);
+
     /* Invalidate device relations for the root hub */
     IoInvalidateDeviceRelations(HubDeviceExtension->RootHubPhysicalDeviceObject, BusRelations);
 
@@ -1147,26 +1156,6 @@ CreateUsbChildDeviceObject(
     HubInterface = &HubDeviceExtension->HubInterface;
     RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
     HubInterfaceBusContext = HubDeviceExtension->UsbDInterface.BusContext;
-    //
-    // Find an empty slot in the child device array
-    //
-    for (ChildDeviceCount = 0; ChildDeviceCount < USB_MAXCHILDREN; ChildDeviceCount++)
-    {
-        if (HubDeviceExtension->ChildDeviceObject[ChildDeviceCount] == NULL)
-        {
-        DPRINT("Found unused entry at %d\n", ChildDeviceCount);
-            break;
-        }
-    }
-
-    //
-    // Check if the limit has been reached for maximum usb devices
-    //
-    if (ChildDeviceCount == USB_MAXCHILDREN)
-    {
-        DPRINT1("USBHUB: Too many child devices!\n");
-        return STATUS_UNSUCCESSFUL;
-    }
 
     while (TRUE)
     {
@@ -1226,10 +1215,6 @@ CreateUsbChildDeviceObject(
     UsbChildExtension->ParentDeviceObject = UsbHubDeviceObject;
     UsbChildExtension->PortNumber = PortId;
 
-    // copy device interface
-    RtlCopyMemory(&UsbChildExtension->DeviceInterface, &HubDeviceExtension->DeviceInterface, sizeof(USB_BUS_INTERFACE_USBDI_V2));
-
-
     //
     // Create the UsbDeviceObject
     //
@@ -1244,12 +1229,6 @@ CreateUsbChildDeviceObject(
         goto Cleanup;
     }
 
-    // copy device interface
-    RtlCopyMemory(&UsbChildExtension->DeviceInterface, &HubDeviceExtension->DeviceInterface, sizeof(USB_BUS_INTERFACE_USBDI_V2));
-
-    // FIXME replace buscontext
-    UsbChildExtension->DeviceInterface.BusContext = UsbChildExtension->UsbDeviceHandle;
-
     //
     // Initialize UsbDevice
     //
@@ -1339,8 +1318,43 @@ CreateUsbChildDeviceObject(
         goto Cleanup;
     }
 
+    // copy device interface
+    RtlCopyMemory(&UsbChildExtension->DeviceInterface, &HubDeviceExtension->UsbDInterface, sizeof(USB_BUS_INTERFACE_USBDI_V2));
+    UsbChildExtension->DeviceInterface.InterfaceReference(UsbChildExtension->DeviceInterface.BusContext);
+
+    INITIALIZE_PNP_STATE(UsbChildExtension->Common);
+
+    IoInitializeRemoveLock(&UsbChildExtension->Common.RemoveLock, 'pbuH', 0, 0);
+
+    KeAcquireGuardedMutex(&HubDeviceExtension->HubMutexLock);
+
+    //
+    // Find an empty slot in the child device array
+    //
+    for (ChildDeviceCount = 0; ChildDeviceCount < USB_MAXCHILDREN; ChildDeviceCount++)
+    {
+        if (HubDeviceExtension->ChildDeviceObject[ChildDeviceCount] == NULL)
+        {
+            DPRINT("Found unused entry at %d\n", ChildDeviceCount);
+            break;
+        }
+    }
+
+    //
+    // Check if the limit has been reached for maximum usb devices
+    //
+    if (ChildDeviceCount == USB_MAXCHILDREN)
+    {
+        DPRINT1("USBHUB: Too many child devices!\n");
+        Status = STATUS_UNSUCCESSFUL;
+        KeReleaseGuardedMutex(&HubDeviceExtension->HubMutexLock);
+        UsbChildExtension->DeviceInterface.InterfaceDereference(UsbChildExtension->DeviceInterface.BusContext);
+        goto Cleanup;
+    }
+
     HubDeviceExtension->ChildDeviceObject[ChildDeviceCount] = NewChildDeviceObject;
     HubDeviceExtension->InstanceCount++;
+    KeReleaseGuardedMutex(&HubDeviceExtension->HubMutexLock);
 
     IoInvalidateDeviceRelations(RootHubDeviceObject, BusRelations);
     return STATUS_SUCCESS;
@@ -1384,16 +1398,20 @@ Cleanup:
 NTSTATUS
 USBHUB_FdoQueryBusRelations(
     IN PDEVICE_OBJECT DeviceObject,
+    IN PDEVICE_RELATIONS RelationsFromTop,
     OUT PDEVICE_RELATIONS* pDeviceRelations)
 {
     PHUB_DEVICE_EXTENSION HubDeviceExtension;
     PDEVICE_RELATIONS DeviceRelations;
     ULONG i;
+    ULONG ChildrenFromTop = 0;
     ULONG Children = 0;
     ULONG NeededSize;
 
     HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
 
+    KeAcquireGuardedMutex(&HubDeviceExtension->HubMutexLock);
+
     //
     // Count the number of children
     //
@@ -1407,9 +1425,19 @@ USBHUB_FdoQueryBusRelations(
         Children++;
     }
 
-    NeededSize = sizeof(DEVICE_RELATIONS);
-    if (Children > 1)
-        NeededSize += (Children - 1) * sizeof(PDEVICE_OBJECT);
+    if (RelationsFromTop)
+    {
+        ChildrenFromTop = RelationsFromTop->Count;
+        if (!Children)
+        {
+            // We have nothing to add
+            *pDeviceRelations = RelationsFromTop;
+            KeReleaseGuardedMutex(&HubDeviceExtension->HubMutexLock);
+            return STATUS_SUCCESS;
+        }
+    }
+
+    NeededSize = sizeof(DEVICE_RELATIONS) + (Children + ChildrenFromTop - 1) * sizeof(PDEVICE_OBJECT);
 
     //
     // Allocate DeviceRelations
@@ -1418,9 +1446,22 @@ USBHUB_FdoQueryBusRelations(
                                                         NeededSize);
 
     if (!DeviceRelations)
-        return STATUS_INSUFFICIENT_RESOURCES;
-    DeviceRelations->Count = Children;
-    Children = 0;
+    {
+        KeReleaseGuardedMutex(&HubDeviceExtension->HubMutexLock);
+        if (!RelationsFromTop)
+            return STATUS_INSUFFICIENT_RESOURCES;
+        else
+            return STATUS_NOT_SUPPORTED;
+    }
+    // Copy the objects coming from top
+    if (ChildrenFromTop)
+    {
+        RtlCopyMemory(DeviceRelations->Objects, RelationsFromTop->Objects,
+                      ChildrenFromTop * sizeof(PDEVICE_OBJECT));
+    }
+
+    DeviceRelations->Count = Children + ChildrenFromTop;
+    Children = ChildrenFromTop;
 
     //
     // Fill in return structure
@@ -1429,12 +1470,19 @@ USBHUB_FdoQueryBusRelations(
     {
         if (HubDeviceExtension->ChildDeviceObject[i])
         {
+            // The PnP Manager removes the reference when appropriate.
             ObReferenceObject(HubDeviceExtension->ChildDeviceObject[i]);
             HubDeviceExtension->ChildDeviceObject[i]->Flags &= ~DO_DEVICE_INITIALIZING;
             DeviceRelations->Objects[Children++] = HubDeviceExtension->ChildDeviceObject[i];
         }
     }
 
+    KeReleaseGuardedMutex(&HubDeviceExtension->HubMutexLock);
+
+    // We should do this, because replaced this with our's one
+    if (RelationsFromTop)
+        ExFreePool(RelationsFromTop);
+
     ASSERT(Children == DeviceRelations->Count);
     *pDeviceRelations = DeviceRelations;
 
@@ -1551,7 +1599,8 @@ USBHUB_FdoStartDevice(
     if (!Urb)
     {
          // no memory
-         return STATUS_INSUFFICIENT_RESOURCES;
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto cleanup;
     }
 
     // zero urb
@@ -1566,8 +1615,7 @@ USBHUB_FdoStartDevice(
     {
         // failed to obtain hub pdo
         DPRINT1("IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO failed with %x\n", Status);
-        ExFreePool(Urb);
-        return Status;
+        goto cleanup;
     }
 
     // sanity checks
@@ -1578,14 +1626,13 @@ USBHUB_FdoStartDevice(
     RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
 
     // Send the StartDevice to RootHub
-    Status = ForwardIrpAndWait(RootHubDeviceObject, Irp);
+    Status = ForwardIrpAndWait(HubDeviceExtension->LowerDeviceObject, Irp);
 
     if (!NT_SUCCESS(Status))
     {
         // failed to start pdo
         DPRINT1("Failed to start the RootHub PDO\n");
-        ExFreePool(Urb);
-        return Status;
+        goto cleanup;
     }
 
     // Get the current number of hubs
@@ -1596,8 +1643,7 @@ USBHUB_FdoStartDevice(
     {
         // failed to get number of hubs
         DPRINT1("IOCTL_INTERNAL_USB_GET_HUB_COUNT failed with %x\n", Status);
-        ExFreePool(Urb);
-        return Status;
+        goto cleanup;
     }
 
     // Get the Hub Interface
@@ -1611,8 +1657,7 @@ USBHUB_FdoStartDevice(
     {
         // failed to get root hub interface
         DPRINT1("Failed to get HUB_GUID interface with status 0x%08lx\n", Status);
-        ExFreePool(Urb);
-        return Status;
+        goto cleanup;
     }
 
     HubInterfaceBusContext = HubDeviceExtension->HubInterface.BusContext;
@@ -1628,8 +1673,7 @@ USBHUB_FdoStartDevice(
     {
         // failed to get usbdi interface
         DPRINT1("Failed to get USBDI_GUID interface with status 0x%08lx\n", Status);
-        ExFreePool(Urb);
-        return Status;
+        goto cleanup;
     }
 
     // Get Root Hub Device Handle
@@ -1642,8 +1686,7 @@ USBHUB_FdoStartDevice(
     {
         // failed
         DPRINT1("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE failed with status 0x%08lx\n", Status);
-        ExFreePool(Urb);
-        return Status;
+        goto cleanup;
     }
 
     //
@@ -1687,8 +1730,7 @@ USBHUB_FdoStartDevice(
     {
         // failed to get device descriptor of hub
         DPRINT1("Failed to get HubDeviceDescriptor!\n");
-        ExFreePool(Urb);
-        return Status;
+        goto cleanup;
     }
 
     // build configuration request
@@ -1715,8 +1757,7 @@ USBHUB_FdoStartDevice(
     {
         // failed to get configuration descriptor
         DPRINT1("Failed to get RootHub Configuration with status %x\n", Status);
-        ExFreePool(Urb);
-        return Status;
+        goto cleanup;
     }
 
     // sanity checks
@@ -1742,16 +1783,15 @@ USBHUB_FdoStartDevice(
     {
         // failed to get hub information
         DPRINT1("Failed to extended hub information. Unable to determine the number of ports!\n");
-        ExFreePool(Urb);
-        return Status;
+        goto cleanup;
     }
 
     if (!HubDeviceExtension->UsbExtHubInfo.NumberOfPorts)
     {
         // bogus port driver
         DPRINT1("Failed to retrieve the number of ports\n");
-        ExFreePool(Urb);
-        return STATUS_UNSUCCESSFUL;
+        Status = STATUS_UNSUCCESSFUL;
+        goto cleanup;
     }
 
     DPRINT("HubDeviceExtension->UsbExtHubInfo.NumberOfPorts %x\n", HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
@@ -1782,8 +1822,8 @@ USBHUB_FdoStartDevice(
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("Failed to get Hub Descriptor!\n");
-        ExFreePool(Urb);
-        return STATUS_UNSUCCESSFUL;
+        Status = STATUS_UNSUCCESSFUL;
+        goto cleanup;
     }
 
     // sanity checks
@@ -1811,8 +1851,8 @@ USBHUB_FdoStartDevice(
     {
         // failed to get hub status
         DPRINT1("Failed to get Hub Status!\n");
-        ExFreePool(Urb);
-        return STATUS_UNSUCCESSFUL;
+        Status = STATUS_UNSUCCESSFUL;
+        goto cleanup;
     }
 
     // Allocate memory for PortStatusChange to hold 2 USHORTs for each port on hub
@@ -1820,6 +1860,13 @@ USBHUB_FdoStartDevice(
                                                                     sizeof(ULONG) * HubDeviceExtension->UsbExtHubInfo.NumberOfPorts,
                                                                     USB_HUB_TAG);
 
+    if (!HubDeviceExtension->PortStatusChange)
+    {
+        DPRINT1("Failed to allocate pool for PortStatusChange!\n");
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto cleanup;
+    }
+
     // Get the first Configuration Descriptor
     Pid = USBD_ParseConfigurationDescriptorEx(&HubDeviceExtension->HubConfigDescriptor,
                                                 &HubDeviceExtension->HubConfigDescriptor,
@@ -1828,8 +1875,8 @@ USBHUB_FdoStartDevice(
     {
         // failed parse hub descriptor
         DPRINT1("Failed to parse configuration descriptor\n");
-        ExFreePool(Urb);
-        return STATUS_UNSUCCESSFUL;
+        Status = STATUS_UNSUCCESSFUL;
+        goto cleanup;
     }
 
     // create configuration request
@@ -1840,8 +1887,8 @@ USBHUB_FdoStartDevice(
     {
         // failed to build urb
         DPRINT1("Failed to allocate urb\n");
-        ExFreePool(Urb);
-        return STATUS_INSUFFICIENT_RESOURCES;
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto cleanup;
     }
 
     // send request
@@ -1853,9 +1900,7 @@ USBHUB_FdoStartDevice(
     {
         // failed to select configuration
         DPRINT1("Failed to select configuration with %x\n", Status);
-        ExFreePool(Urb);
-        ExFreePool(ConfigUrb);
-        return Status;
+        goto cleanup;
     }
 
     // store configuration & pipe handle
@@ -1863,12 +1908,6 @@ USBHUB_FdoStartDevice(
     HubDeviceExtension->PipeHandle = ConfigUrb->UrbSelectConfiguration.Interface.Pipes[0].PipeHandle;
     DPRINT("Configuration Handle %x\n", HubDeviceExtension->ConfigurationHandle);
 
-    FDO_QueryInterface(DeviceObject, &HubDeviceExtension->DeviceInterface);
-
-
-    // free urb
-    ExFreePool(ConfigUrb);
-
     // check if function is available
     if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed)
     {
@@ -1908,8 +1947,7 @@ USBHUB_FdoStartDevice(
         if (!NT_SUCCESS(Status))
         {
             DPRINT1("Failed to set callback\n");
-            ExFreePool(Urb);
-            return Status;
+            goto cleanup;
         }
     }
     else
@@ -1961,8 +1999,30 @@ USBHUB_FdoStartDevice(
     // free urb
     ExFreePool(Urb);
 
+    // free ConfigUrb
+    ExFreePool(ConfigUrb);
+
     // done
     return Status;
+
+cleanup:
+    if (Urb)
+        ExFreePool(Urb);
+
+    // Dereference interfaces
+    if (HubDeviceExtension->HubInterface.Size)
+        HubDeviceExtension->HubInterface.InterfaceDereference(HubDeviceExtension->HubInterface.BusContext);
+
+    if (HubDeviceExtension->UsbDInterface.Size)
+        HubDeviceExtension->UsbDInterface.InterfaceDereference(HubDeviceExtension->UsbDInterface.BusContext);
+
+    if (HubDeviceExtension->PortStatusChange)
+        ExFreePool(HubDeviceExtension->PortStatusChange);
+
+    if (ConfigUrb)
+        ExFreePool(ConfigUrb);
+
+    return Status;
 }
 
 NTSTATUS
@@ -1972,17 +2032,31 @@ USBHUB_FdoHandlePnp(
 {
     PIO_STACK_LOCATION Stack;
     NTSTATUS Status = STATUS_SUCCESS;
-    ULONG_PTR Information = 0;
+    PDEVICE_OBJECT ChildDeviceObject;
     PHUB_DEVICE_EXTENSION HubDeviceExtension;
+    PUSB_BUS_INTERFACE_HUB_V5 HubInterface;
+    PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension;
 
     HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
 
+    HubInterface = &HubDeviceExtension->HubInterface;
     Stack = IoGetCurrentIrpStackLocation(Irp);
 
+    Status = IoAcquireRemoveLock(&HubDeviceExtension->Common.RemoveLock, Irp);
+    if (!NT_SUCCESS(Status))
+    {
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return Status;
+    }
+
     switch (Stack->MinorFunction)
     {
+        int i;
+
         case IRP_MN_START_DEVICE:
         {
+            DPRINT("IRP_MN_START_DEVICE\n");
             if (USBHUB_IsRootHubFDO(DeviceObject))
             {
                 // start root hub fdo
@@ -1992,7 +2066,13 @@ USBHUB_FdoHandlePnp(
             {
                 Status = USBHUB_ParentFDOStartDevice(DeviceObject, Irp);
             }
-            break;
+
+            SET_NEW_PNP_STATE(HubDeviceExtension->Common, Started);
+
+            Irp->IoStatus.Status = Status;
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+            IoReleaseRemoveLock(&HubDeviceExtension->Common.RemoveLock, Irp);
+            return Status;
         }
 
         case IRP_MN_QUERY_DEVICE_RELATIONS:
@@ -2002,66 +2082,197 @@ USBHUB_FdoHandlePnp(
                 case BusRelations:
                 {
                     PDEVICE_RELATIONS DeviceRelations = NULL;
+                    PDEVICE_RELATIONS RelationsFromTop = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
                     DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
 
-                    Status = USBHUB_FdoQueryBusRelations(DeviceObject, &DeviceRelations);
+                    Status = USBHUB_FdoQueryBusRelations(DeviceObject, RelationsFromTop, &DeviceRelations);
+
+                    if (!NT_SUCCESS(Status))
+                    {
+                        if (Status == STATUS_NOT_SUPPORTED)
+                        {
+                            // We should process this to not lose relations from top.
+                            Irp->IoStatus.Status = STATUS_SUCCESS;
+                            break;
+                        }
+                        // We should fail an IRP
+                        Irp->IoStatus.Status = Status;
+                        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                        IoReleaseRemoveLock(&HubDeviceExtension->Common.RemoveLock, Irp);
+                        return Status;
+                    }
 
-                    Information = (ULONG_PTR)DeviceRelations;
+                    Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
+                    Irp->IoStatus.Status = Status;
                     break;
                 }
                 case RemovalRelations:
                 {
                     DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
-                    return ForwardIrpAndForget(DeviceObject, Irp);
+                    break;
                 }
                 default:
                     DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
                             Stack->Parameters.QueryDeviceRelations.Type);
-                    return ForwardIrpAndForget(DeviceObject, Irp);
+                    break;
             }
             break;
         }
-        case IRP_MN_QUERY_REMOVE_DEVICE:
         case IRP_MN_QUERY_STOP_DEVICE:
         {
+            //
+            // We should fail this request, because we're not handling
+            // IRP_MN_STOP_DEVICE for now.We'll receive this IRP ONLY when
+            // PnP manager rebalances resources.
+            //
+            Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+            return STATUS_NOT_SUPPORTED;
+        }
+        case IRP_MN_QUERY_REMOVE_DEVICE:
+        {
+            // No action is required from FDO because it have nothing to free.
+            DPRINT("IRP_MN_QUERY_REMOVE_DEVICE\n");
+
+            SET_NEW_PNP_STATE(HubDeviceExtension->Common, RemovePending);
+
             Irp->IoStatus.Status = STATUS_SUCCESS;
-            return ForwardIrpAndForget(DeviceObject, Irp);
+            break;
+        }
+        case IRP_MN_CANCEL_REMOVE_DEVICE:
+        {
+            DPRINT("IRP_MN_CANCEL_REMOVE_DEVICE\n");
+
+            if (HubDeviceExtension->Common.PnPState == RemovePending)
+                RESTORE_PREVIOUS_PNP_STATE(HubDeviceExtension->Common);
+
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            break;
+        }
+        case IRP_MN_SURPRISE_REMOVAL:
+        {
+            //
+            // We'll receive this IRP on HUB unexpected removal, or on USB
+            // controller removal from PCI port. Here we should "let know" all
+            // our children that their parent is removed and on next removal
+            // they also can be removed.
+            //
+            SET_NEW_PNP_STATE(HubDeviceExtension->Common, SurpriseRemovePending);
+
+            KeAcquireGuardedMutex(&HubDeviceExtension->HubMutexLock);
+
+            for (i = 0; i < USB_MAXCHILDREN; i++)
+            {
+                ChildDeviceObject = HubDeviceExtension->ChildDeviceObject[i];
+                if (ChildDeviceObject)
+                {
+                    ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)ChildDeviceObject->DeviceObjectExtension;
+                    ChildDeviceExtension->ParentDeviceObject = NULL;
+                }
+            }
+
+            KeReleaseGuardedMutex(&HubDeviceExtension->HubMutexLock);
+
+            // This IRP can't be failed
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            break;
         }
         case IRP_MN_REMOVE_DEVICE:
         {
+            DPRINT("IRP_MN_REMOVE_DEVICE\n");
+
+            SET_NEW_PNP_STATE(HubDeviceExtension->Common, Deleted);
+
+            IoReleaseRemoveLockAndWait(&HubDeviceExtension->Common.RemoveLock, Irp);
+
+            //
+            // Here we should remove all child PDOs. At this point all children
+            // received and returned from IRP_MN_REMOVE so remove synchronization
+            // isn't needed here
+            //
+
+            KeAcquireGuardedMutex(&HubDeviceExtension->HubMutexLock);
+
+            for (i = 0; i < USB_MAXCHILDREN; i++)
+            {
+                ChildDeviceObject = HubDeviceExtension->ChildDeviceObject[i];
+                if (ChildDeviceObject)
+                {
+                    PHUB_CHILDDEVICE_EXTENSION UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)ChildDeviceObject->DeviceExtension;
+
+                    SET_NEW_PNP_STATE(UsbChildExtension->Common, Deleted);
+
+                    // Remove the usb device
+                    if (UsbChildExtension->UsbDeviceHandle)
+                    {
+                        Status = HubInterface->RemoveUsbDevice(HubInterface->BusContext, UsbChildExtension->UsbDeviceHandle, 0);
+                        ASSERT(Status == STATUS_SUCCESS);
+                    }
+
+                    // Free full configuration descriptor
+                    if (UsbChildExtension->FullConfigDesc)
+                        ExFreePool(UsbChildExtension->FullConfigDesc);
+
+                    // Free ID buffers
+                    if (UsbChildExtension->usCompatibleIds.Buffer)
+                        ExFreePool(UsbChildExtension->usCompatibleIds.Buffer);
+
+                    if (UsbChildExtension->usDeviceId.Buffer)
+                        ExFreePool(UsbChildExtension->usDeviceId.Buffer);
+
+                    if (UsbChildExtension->usHardwareIds.Buffer)
+                        ExFreePool(UsbChildExtension->usHardwareIds.Buffer);
+
+                    if (UsbChildExtension->usInstanceId.Buffer)
+                        ExFreePool(UsbChildExtension->usInstanceId.Buffer);
+
+                    DPRINT("Deleting child PDO\n");
+                    IoDeleteDevice(DeviceObject);
+                    ChildDeviceObject = NULL;
+                }
+            }
+
+            KeReleaseGuardedMutex(&HubDeviceExtension->HubMutexLock);
+
             Irp->IoStatus.Status = STATUS_SUCCESS;
-            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+            Status = ForwardIrpAndForget(DeviceObject, Irp);
 
             IoDetachDevice(HubDeviceExtension->LowerDeviceObject);
+            DPRINT("Deleting FDO 0x%p\n", DeviceObject);
             IoDeleteDevice(DeviceObject);
 
-            return STATUS_SUCCESS;
+            return Status;
         }
         case IRP_MN_QUERY_BUS_INFORMATION:
         {
+            // Function drivers and filter drivers do not handle this IRP.
             DPRINT("IRP_MN_QUERY_BUS_INFORMATION\n");
             break;
         }
         case IRP_MN_QUERY_ID:
         {
             DPRINT("IRP_MN_QUERY_ID\n");
+            // Function drivers and filter drivers do not handle this IRP.
             break;
         }
         case IRP_MN_QUERY_CAPABILITIES:
         {
+            //
+            // If a function or filter driver does not handle this IRP, it
+            // should pass that down.
+            //
             DPRINT("IRP_MN_QUERY_CAPABILITIES\n");
             break;
         }
         default:
         {
             DPRINT(" IRP_MJ_PNP / unknown minor function 0x%lx\n", Stack->MinorFunction);
-            return ForwardIrpAndForget(DeviceObject, Irp);
+            break;
         }
     }
 
-    Irp->IoStatus.Information = Information;
-    Irp->IoStatus.Status = Status;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    Status = ForwardIrpAndForget(DeviceObject, Irp);
+    IoReleaseRemoveLock(&HubDeviceExtension->Common.RemoveLock, Irp);
     return Status;
 }
 
@@ -2086,6 +2297,25 @@ USBHUB_FdoHandleDeviceControl(
     // get device extension
     HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
 
+    Status = IoAcquireRemoveLock(&HubDeviceExtension->Common.RemoveLock, Irp);
+    if (!NT_SUCCESS(Status))
+    {
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return Status;
+    }
+
+    // Prevent handling of control requests in remove pending state
+    if (HubDeviceExtension->Common.PnPState == RemovePending)
+    {
+        DPRINT1("[USBHUB] Request for removed device object %p\n", DeviceObject);
+        Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        IoReleaseRemoveLock(&HubDeviceExtension->Common.RemoveLock, Irp);
+        return STATUS_DEVICE_NOT_CONNECTED;
+    }
+
     if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_INFORMATION)
     {
         // is the buffer big enough
@@ -2131,6 +2361,7 @@ USBHUB_FdoHandleDeviceControl(
             // sanity checks
             ASSERT(NodeConnectionInfo);
 
+            KeAcquireGuardedMutex(&HubDeviceExtension->HubMutexLock);
             for(Index = 0; Index < USB_MAXCHILDREN; Index++)
             {
                 if (HubDeviceExtension->ChildDeviceObject[Index] == NULL)
@@ -2157,6 +2388,7 @@ USBHUB_FdoHandleDeviceControl(
                 }
                 break;
             }
+            KeReleaseGuardedMutex(&HubDeviceExtension->HubMutexLock);
             // done
             Irp->IoStatus.Information = sizeof(USB_NODE_INFORMATION);
             Status = STATUS_SUCCESS;
@@ -2177,6 +2409,7 @@ USBHUB_FdoHandleDeviceControl(
             // sanity checks
             ASSERT(NodeKey);
 
+            KeAcquireGuardedMutex(&HubDeviceExtension->HubMutexLock);
             for(Index = 0; Index < USB_MAXCHILDREN; Index++)
             {
                 if (HubDeviceExtension->ChildDeviceObject[Index] == NULL)
@@ -2216,6 +2449,7 @@ USBHUB_FdoHandleDeviceControl(
                 NodeKey->ActualLength = Length + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
                 break;
             }
+            KeReleaseGuardedMutex(&HubDeviceExtension->HubMutexLock);
         }
     }
     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_CONNECTION_NAME)
@@ -2247,6 +2481,7 @@ USBHUB_FdoHandleDeviceControl(
     Irp->IoStatus.Status = Status;
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
+    IoReleaseRemoveLock(&HubDeviceExtension->Common.RemoveLock, Irp);
     return Status;
 }
 
index 0800c59..405fde8 100644 (file)
@@ -211,84 +211,3 @@ SubmitRequestToRootHub(
 
     return Status;
 }
-
-NTSTATUS
-NTAPI
-FDO_QueryInterfaceCompletionRoutine(
-    IN PDEVICE_OBJECT DeviceObject,
-    IN PIRP Irp,
-    IN PVOID Context)
-{
-    /* Set event */
-    KeSetEvent((PRKEVENT)Context, 0, FALSE);
-
-    /* Completion is done in the HidClassFDO_QueryCapabilities routine */
-    return STATUS_MORE_PROCESSING_REQUIRED;
-}
-
-NTSTATUS
-FDO_QueryInterface(
-    IN PDEVICE_OBJECT DeviceObject,
-    IN OUT PUSB_BUS_INTERFACE_USBDI_V2 Interface)
-{
-    PIRP Irp;
-    KEVENT Event;
-    NTSTATUS Status;
-    PIO_STACK_LOCATION IoStack;
-    PHUB_DEVICE_EXTENSION HubDeviceExtension;
-
-    /* Get device extension */
-    HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-    ASSERT(HubDeviceExtension->Common.IsFDO);
-
-    /* Init event */
-    KeInitializeEvent(&Event, NotificationEvent, FALSE);
-
-    /* Now allocate the irp */
-    Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
-    if (!Irp)
-    {
-        /* No memory */
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    /* Get next stack location */
-    IoStack = IoGetNextIrpStackLocation(Irp);
-
-    /* Init stack location */
-    IoStack->MajorFunction = IRP_MJ_PNP;
-    IoStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
-    IoStack->Parameters.QueryInterface.Interface = (PINTERFACE)Interface;
-    IoStack->Parameters.QueryInterface.InterfaceType = &USB_BUS_INTERFACE_USBDI_GUID;
-    IoStack->Parameters.QueryInterface.Version = USB_BUSIF_USBDI_VERSION_2;
-    IoStack->Parameters.QueryInterface.Size = sizeof(USB_BUS_INTERFACE_USBDI_V2);
-
-
-    /* Set completion routine */
-    IoSetCompletionRoutine(Irp,
-                           FDO_QueryInterfaceCompletionRoutine,
-                           (PVOID)&Event,
-                           TRUE,
-                           TRUE,
-                           TRUE);
-
-    /* Pnp irps have default completion code */
-    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
-
-    /* Call lower device */
-    Status = IoCallDriver(HubDeviceExtension->LowerDeviceObject, Irp);
-    if (Status == STATUS_PENDING)
-    {
-        /* Wait for completion */
-        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
-    }
-
-    /* Get status */
-    Status = Irp->IoStatus.Status;
-
-    /* Complete request */
-    IoFreeIrp(Irp);
-
-    /* Done */
-    return Status;
-}
index 6ddc070..daeed55 100644 (file)
@@ -146,16 +146,25 @@ IsValidPDO(
 
     ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)DeviceObject->DeviceExtension;
     ASSERT(ChildDeviceExtension->Common.IsFDO == FALSE);
+
+    // This can happen when parent device was surprise removed.
+    if (ChildDeviceExtension->ParentDeviceObject == NULL)
+        return FALSE;
+
     HubDeviceExtension = (PHUB_DEVICE_EXTENSION)ChildDeviceExtension->ParentDeviceObject->DeviceExtension;
 
+    KeAcquireGuardedMutex(&HubDeviceExtension->HubMutexLock);
     for(Index = 0; Index < USB_MAXCHILDREN; Index++)
     {
         if (HubDeviceExtension->ChildDeviceObject[Index] == DeviceObject)
         {
+            KeReleaseGuardedMutex(&HubDeviceExtension->HubMutexLock);
+
             /* PDO exists */
             return TRUE;
         }
     }
+    KeReleaseGuardedMutex(&HubDeviceExtension->HubMutexLock);
 
     /* invalid pdo */
     return FALSE;
@@ -190,18 +199,31 @@ USBHUB_PdoHandleInternalDeviceControl(
 
     ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)DeviceObject->DeviceExtension;
     ASSERT(ChildDeviceExtension->Common.IsFDO == FALSE);
-    HubDeviceExtension = (PHUB_DEVICE_EXTENSION)ChildDeviceExtension->ParentDeviceObject->DeviceExtension;
-    RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
 
-    if(!IsValidPDO(DeviceObject))
+    Status = IoAcquireRemoveLock(&ChildDeviceExtension->Common.RemoveLock, Irp);
+    if (!NT_SUCCESS(Status))
+    {
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return Status;
+    }
+
+    if (ChildDeviceExtension->Common.PnPState == SurpriseRemovePending ||
+        ChildDeviceExtension->Common.PnPState == RemovePending ||
+        ChildDeviceExtension->ParentDeviceObject == NULL)
     {
+        // Parent or child device was surprise removed.
         DPRINT1("[USBHUB] Request for removed device object %p\n", DeviceObject);
         Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
         Irp->IoStatus.Information = 0;
         IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        IoReleaseRemoveLock(&ChildDeviceExtension->Common.RemoveLock, Irp);
         return STATUS_DEVICE_NOT_CONNECTED;
     }
 
+    HubDeviceExtension = (PHUB_DEVICE_EXTENSION)ChildDeviceExtension->ParentDeviceObject->DeviceExtension;
+    RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
+
     switch (Stack->Parameters.DeviceIoControl.IoControlCode)
     {
         case IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO:
@@ -301,6 +323,7 @@ USBHUB_PdoHandleInternalDeviceControl(
             // Send the request to RootHub
             //
             Status = ForwardUrbToRootHub(RootHubDeviceObject, IOCTL_INTERNAL_USB_SUBMIT_URB, Irp, Urb, NULL);
+            IoReleaseRemoveLock(&ChildDeviceExtension->Common.RemoveLock, Irp);
             return Status;
         }
         //
@@ -397,6 +420,7 @@ USBHUB_PdoHandleInternalDeviceControl(
         Irp->IoStatus.Status = Status;
         IoCompleteRequest(Irp, IO_NO_INCREMENT);
     }
+    IoReleaseRemoveLock(&ChildDeviceExtension->Common.RemoveLock, Irp);
     return Status;
 }
 
@@ -421,6 +445,8 @@ USBHUB_PdoStartDevice(
     IoRegisterDeviceInterface(DeviceObject, &GUID_DEVINTERFACE_USB_DEVICE, NULL, &ChildDeviceExtension->SymbolicLinkName);
     IoSetDeviceInterfaceState(&ChildDeviceExtension->SymbolicLinkName, TRUE);
 
+    SET_NEW_PNP_STATE(ChildDeviceExtension->Common, Started);
+
     UNIMPLEMENTED
     return STATUS_SUCCESS;
 }
@@ -563,15 +589,20 @@ USBHUB_PdoHandlePnp(
     PIO_STACK_LOCATION Stack;
     ULONG_PTR Information = 0;
     PHUB_CHILDDEVICE_EXTENSION UsbChildExtension;
-    ULONG Index;
-    ULONG bFound;
     PDEVICE_RELATIONS DeviceRelation;
-    PDEVICE_OBJECT ParentDevice;
 
     UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)DeviceObject->DeviceExtension;
     Stack = IoGetCurrentIrpStackLocation(Irp);
     MinorFunction = Stack->MinorFunction;
 
+    Status = IoAcquireRemoveLock(&UsbChildExtension->Common.RemoveLock, Irp);
+    if (!NT_SUCCESS(Status))
+    {
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return Status;
+    }
+
     switch (MinorFunction)
     {
         case IRP_MN_START_DEVICE:
@@ -628,17 +659,20 @@ USBHUB_PdoHandlePnp(
         }
         case IRP_MN_QUERY_DEVICE_TEXT:
         {
+            DPRINT("IRP_MN_QUERY_DEVICE_TEXT\n");
             Status = USBHUB_PdoQueryDeviceText(DeviceObject, Irp, &Information);
             break;
         }
         case IRP_MN_QUERY_ID:
         {
+            DPRINT("IRP_MN_QUERY_ID\n");
             Status = USBHUB_PdoQueryId(DeviceObject, Irp, &Information);
             break;
         }
         case IRP_MN_QUERY_BUS_INFORMATION:
         {
             PPNP_BUS_INFORMATION BusInfo;
+            DPRINT("IRP_MN_QUERY_BUS_INFORMATION\n");
             BusInfo = (PPNP_BUS_INFORMATION)ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION));
             RtlCopyMemory(&BusInfo->BusTypeGuid,
                           &GUID_BUS_TYPE_USB,
@@ -654,42 +688,58 @@ USBHUB_PdoHandlePnp(
         {
             PHUB_DEVICE_EXTENSION HubDeviceExtension = (PHUB_DEVICE_EXTENSION)UsbChildExtension->ParentDeviceObject->DeviceExtension;
             PUSB_BUS_INTERFACE_HUB_V5 HubInterface = &HubDeviceExtension->HubInterface;
-            ParentDevice = UsbChildExtension->ParentDeviceObject;
 
             DPRINT("IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
 
-            /* remove us from pdo list */
-            bFound = FALSE;
-            for(Index = 0; Index < USB_MAXCHILDREN; Index++)
+            ASSERT((UsbChildExtension->Common.PnPState == RemovePending) ||
+                   (UsbChildExtension->Common.PnPState == SurpriseRemovePending));
+
+            SET_NEW_PNP_STATE(UsbChildExtension->Common, NotStarted);
+
+            if (!IsValidPDO(DeviceObject))
             {
-                if (HubDeviceExtension->ChildDeviceObject[Index] == DeviceObject)
-                {
-                     /* Remove the device */
-                     Status = HubInterface->RemoveUsbDevice(HubDeviceExtension->UsbDInterface.BusContext, UsbChildExtension->UsbDeviceHandle, 0);
+                // Parent or child device was surprise removed, freeing resources allocated for child device.
+                SET_NEW_PNP_STATE(UsbChildExtension->Common, Deleted);
 
-                     /* FIXME handle error */
-                     ASSERT(Status == STATUS_SUCCESS);
+                IoReleaseRemoveLockAndWait(&UsbChildExtension->Common.RemoveLock, Irp);
 
-                    /* remove us */
-                    HubDeviceExtension->ChildDeviceObject[Index] = NULL;
-                    bFound = TRUE;
-                    break;
+                // Remove the usb device
+                if (UsbChildExtension->UsbDeviceHandle)
+                {
+                    Status = HubInterface->RemoveUsbDevice(HubInterface->BusContext, UsbChildExtension->UsbDeviceHandle, 0);
+                    ASSERT(Status == STATUS_SUCCESS);
                 }
-            }
+                // Free full configuration descriptor
+                if (UsbChildExtension->FullConfigDesc)
+                    ExFreePool(UsbChildExtension->FullConfigDesc);
 
-            /* Complete the IRP */
-            Irp->IoStatus.Status = STATUS_SUCCESS;
-            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                // Free ID buffers
+                if (UsbChildExtension->usCompatibleIds.Buffer)
+                    ExFreePool(UsbChildExtension->usCompatibleIds.Buffer);
+
+                if (UsbChildExtension->usDeviceId.Buffer)
+                    ExFreePool(UsbChildExtension->usDeviceId.Buffer);
+
+                if (UsbChildExtension->usHardwareIds.Buffer)
+                    ExFreePool(UsbChildExtension->usHardwareIds.Buffer);
 
-            /* delete device */
-            IoDeleteDevice(DeviceObject);
+                if (UsbChildExtension->usInstanceId.Buffer)
+                    ExFreePool(UsbChildExtension->usInstanceId.Buffer);
 
-            if (bFound)
+                DPRINT("Deleting child PDO\n");
+                IoDeleteDevice(DeviceObject);
+            }
+            else
             {
-                /* invalidate device relations */
-                IoInvalidateDeviceRelations(ParentDevice, BusRelations);
+                IoReleaseRemoveLock(&UsbChildExtension->Common.RemoveLock, Irp);
             }
 
+            // If device is physically presented, we leave its PDO undeleted.
+
+            /* Complete the IRP */
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
             return STATUS_SUCCESS;
         }
         case IRP_MN_QUERY_DEVICE_RELATIONS:
@@ -699,6 +749,7 @@ USBHUB_PdoHandlePnp(
             {
                 /* not supported */
                 Status = Irp->IoStatus.Status;
+                Information = Irp->IoStatus.Information;
                 break;
             }
 
@@ -722,13 +773,46 @@ USBHUB_PdoHandlePnp(
             break;
         }
         case IRP_MN_QUERY_STOP_DEVICE:
+        {
+            //
+            // We should fail this request, because we're not handling IRP_MN_STOP_DEVICE for now.
+            // We'll receive this IRP ONLY when the PnP manager rebalances resources.
+            //
+            Status = STATUS_NOT_SUPPORTED;
+            break;
+        }
         case IRP_MN_QUERY_REMOVE_DEVICE:
         {
+            //
+            // Free interface obtained from bottom, according MSDN we should
+            // check interfaces provided to top, but here we are not checking.
+            // All checking will be performed in roothub driver's
+            // IRP_MN_QUERY_REMOVE_DEVICE handler. This will make problems when
+            // buggy driver is loaded on top of us. But we decided to keep source
+            // simpler, because in any case buggy driver will prevent removing of
+            // whole stack.
+            //
+            UsbChildExtension->DeviceInterface.InterfaceDereference(UsbChildExtension->DeviceInterface.BusContext);
+
+            SET_NEW_PNP_STATE(UsbChildExtension->Common, RemovePending);
+
             /* Sure, no problem */
             Status = STATUS_SUCCESS;
             Information = 0;
             break;
         }
+        case IRP_MN_CANCEL_REMOVE_DEVICE:
+        {
+            // Check to see have we received query-remove before
+            if (UsbChildExtension->Common.PnPState == RemovePending)
+            {
+                RESTORE_PREVIOUS_PNP_STATE(UsbChildExtension->Common);
+                UsbChildExtension->DeviceInterface.InterfaceReference(UsbChildExtension->DeviceInterface.BusContext);
+            }
+
+            Status = STATUS_SUCCESS;
+            break;
+        }
         case IRP_MN_QUERY_INTERFACE:
         {
             DPRINT1("IRP_MN_QUERY_INTERFACE\n");
@@ -736,17 +820,28 @@ USBHUB_PdoHandlePnp(
             {
                 DPRINT1("USB_BUS_INTERFACE_USBDI_GUID\n");
                 RtlCopyMemory(Stack->Parameters.QueryInterface.Interface, &UsbChildExtension->DeviceInterface, Stack->Parameters.QueryInterface.Size);
+                UsbChildExtension->DeviceInterface.InterfaceReference(UsbChildExtension->DeviceInterface.BusContext);
                 Status = STATUS_SUCCESS;
                 break;
             }
 
             // pass irp down
             IoSkipCurrentIrpStackLocation(Irp);
-            return IoCallDriver(UsbChildExtension->ParentDeviceObject, Irp);
+            Status = IoCallDriver(UsbChildExtension->ParentDeviceObject, Irp);
+            IoReleaseRemoveLock(&UsbChildExtension->Common.RemoveLock, Irp);
+            return Status;
         }
         case IRP_MN_SURPRISE_REMOVAL:
         {
             DPRINT("[USBHUB] HandlePnp IRP_MN_SURPRISE_REMOVAL\n");
+
+            //
+            // Here we should free all resources and stop all access, lets just set
+            // the flag and do further clean-up in subsequent IRP_MN_REMOVE_DEVICE
+            // We can receive this IRP when device is physically connected (on stop/start fail).
+            //
+            SET_NEW_PNP_STATE(UsbChildExtension->Common, SurpriseRemovePending);
+
             Status = STATUS_SUCCESS;
             break;
         }
@@ -758,6 +853,8 @@ USBHUB_PdoHandlePnp(
         }
     }
 
+    IoReleaseRemoveLock(&UsbChildExtension->Common.RemoveLock, Irp);
+
     Irp->IoStatus.Information = Information;
     Irp->IoStatus.Status = Status;
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
index 1596e21..022100b 100644 (file)
@@ -62,7 +62,7 @@ USBHUB_AddDevice(
     PDEVICE_OBJECT DeviceObject;
     PHUB_DEVICE_EXTENSION HubDeviceExtension;
     NTSTATUS Status;
-    DPRINT("USBHUB: AddDevice\n");
+    DPRINT("USBHUB: AddDevice (%p)\n", PhysicalDeviceObject);
     //
     // Create the Device Object
     //
@@ -86,12 +86,20 @@ USBHUB_AddDevice(
     HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
     RtlZeroMemory(HubDeviceExtension, sizeof(HUB_DEVICE_EXTENSION));
 
+    INITIALIZE_PNP_STATE(HubDeviceExtension->Common);
+
     //
     // Set this to Fdo
     //
     HubDeviceExtension->Common.IsFDO = TRUE;
     DeviceObject->Flags |= DO_POWER_PAGABLE;
 
+    // initialize mutex
+    KeInitializeGuardedMutex(&HubDeviceExtension->HubMutexLock);
+
+    // initialize remove lock
+    IoInitializeRemoveLock(&HubDeviceExtension->Common.RemoveLock, 'buH', 0, 0);
+
     //
     // initialize reset complete event
     //
@@ -158,6 +166,18 @@ USBHUB_DispatchDeviceControl(
         return USBHUB_IrpStub(DeviceObject, Irp);
 }
 
+NTSTATUS NTAPI
+USBHUB_DispatchSystemControl(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+{
+    DPRINT("Usbhub: DispatchSystemControl\n");
+    if (((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Common.IsFDO)
+        return USBHUB_IrpStub(DeviceObject, Irp);
+    else
+        return USBHUB_IrpStub(DeviceObject, Irp);
+}
+
 NTSTATUS NTAPI
 USBHUB_DispatchInternalDeviceControl(
     PDEVICE_OBJECT DeviceObject,
@@ -188,37 +208,59 @@ USBHUB_DispatchPower(
     PIRP Irp)
 {
     PIO_STACK_LOCATION IoStack;
-
+    PHUB_DEVICE_EXTENSION DeviceExtension;
+    NTSTATUS Status;
     IoStack = IoGetCurrentIrpStackLocation(Irp);
-    DPRINT1("Power Function %x\n", IoStack->MinorFunction);
+    DeviceExtension = DeviceObject->DeviceExtension;
 
-    if (IoStack->MinorFunction == IRP_MN_SET_POWER)
+    Status = IoAcquireRemoveLock(&DeviceExtension->Common.RemoveLock, Irp);
+    if (!NT_SUCCESS(Status))
     {
-        PoStartNextPowerIrp(Irp);
-        Irp->IoStatus.Status = STATUS_SUCCESS;
+        Irp->IoStatus.Status = Status;
         IoCompleteRequest(Irp, IO_NO_INCREMENT);
-        return STATUS_SUCCESS;
-
+        return Status;
     }
-    else if (IoStack->MinorFunction == IRP_MN_QUERY_POWER)
+
+    DPRINT1("Power Function %x\n", IoStack->MinorFunction);
+
+    if (DeviceExtension->Common.IsFDO)
     {
         PoStartNextPowerIrp(Irp);
-        Irp->IoStatus.Status = STATUS_SUCCESS;
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);
-        return STATUS_SUCCESS;
-
+        IoSkipCurrentIrpStackLocation(Irp);
+        Status = PoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
+        IoReleaseRemoveLock(&DeviceExtension->Common.RemoveLock, Irp);
+        return Status;
     }
-    else if (IoStack->MinorFunction == IRP_MN_WAIT_WAKE)
+
+    switch (IoStack->MinorFunction)
     {
-        PoStartNextPowerIrp(Irp);
-        Irp->IoStatus.Status = STATUS_SUCCESS;
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);
-        return STATUS_SUCCESS;
+        case IRP_MN_SET_POWER:
+        {
+            DPRINT("IRP_MN_SET_POWER\n");
+            break;
+        }
+        case IRP_MN_QUERY_POWER:
+        {
+            DPRINT("IRP_MN_QUERY_POWER\n");
+            break;
+        }
+        case IRP_MN_WAIT_WAKE:
+        {
+            DPRINT("IRP_MN_WAIT_WAKE\n");
+            break;
+        }
+        default:
+        {
+            DPRINT1("PDO IRP_MJ_POWER / unknown minor function 0x%lx\n", IoStack->MinorFunction);
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+            return Irp->IoStatus.Status;
+        }
     }
 
     PoStartNextPowerIrp(Irp);
     Irp->IoStatus.Status = STATUS_SUCCESS;
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    IoReleaseRemoveLock(&DeviceExtension->Common.RemoveLock, Irp);
     return STATUS_SUCCESS;
 }
 
@@ -245,6 +287,7 @@ DriverEntry(
     DriverObject->MajorFunction[IRP_MJ_CLOSE] = USBHUB_Close;
     DriverObject->MajorFunction[IRP_MJ_CLEANUP] = USBHUB_Cleanup;
     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = USBHUB_DispatchDeviceControl;
+    DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = USBHUB_DispatchSystemControl;
     DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = USBHUB_DispatchInternalDeviceControl;
     DriverObject->MajorFunction[IRP_MJ_PNP] = USBHUB_DispatchPnp;
     DriverObject->MajorFunction[IRP_MJ_POWER] =USBHUB_DispatchPower;
index 1241a81..6265fb0 100644 (file)
@@ -39,9 +39,43 @@ typedef struct _WORK_ITEM_DATA
     PVOID Context;
 } WORK_ITEM_DATA, *PWORK_ITEM_DATA;
 
+
+//
+// Definitions for device's PnP state tracking, all this states are described
+// in PnP Device States diagram of DDK documentation.
+//
+typedef enum _DEVICE_PNP_STATE {
+
+    NotStarted = 0,         // Not started
+    Started,                // After handling of START_DEVICE IRP
+    StopPending,            // After handling of QUERY_STOP IRP
+    Stopped,                // After handling of STOP_DEVICE IRP
+    RemovePending,          // After handling of QUERY_REMOVE IRP
+    SurpriseRemovePending,  // After handling of SURPRISE_REMOVE IRP
+    Deleted,                // After handling of REMOVE_DEVICE IRP
+    UnKnown                 // Unknown state
+
+} DEVICE_PNP_STATE;
+
+#define INITIALIZE_PNP_STATE(Data) \
+(Data).PnPState = NotStarted;\
+(Data).PreviousPnPState = NotStarted;
+
+#define SET_NEW_PNP_STATE(Data, state) \
+(Data).PreviousPnPState = (Data).PnPState;\
+(Data).PnPState = (state);
+
+#define RESTORE_PREVIOUS_PNP_STATE(Data) \
+(Data).PnPState = (Data).PreviousPnPState;
+
 typedef struct
 {
     BOOLEAN IsFDO;
+    // We'll track device PnP state via this variables
+    DEVICE_PNP_STATE PnPState;
+    DEVICE_PNP_STATE PreviousPnPState;
+    // Remove lock
+    IO_REMOVE_LOCK RemoveLock;
 } COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION;
 
 typedef struct _HUB_CHILDDEVICE_EXTENSION
@@ -72,6 +106,8 @@ typedef struct _HUB_DEVICE_EXTENSION
     PDEVICE_OBJECT RootHubPhysicalDeviceObject;
     PDEVICE_OBJECT RootHubFunctionalDeviceObject;
 
+    KGUARDED_MUTEX HubMutexLock;
+
     ULONG NumberOfHubs;
     KEVENT ResetComplete;
 
@@ -94,7 +130,6 @@ typedef struct _HUB_DEVICE_EXTENSION
     USBD_CONFIGURATION_HANDLE ConfigurationHandle;
     USBD_PIPE_HANDLE PipeHandle;
     PVOID RootHubHandle;
-    USB_BUS_INTERFACE_USBDI_V2 DeviceInterface;
 
     UNICODE_STRING SymbolicLinkName;
     ULONG InstanceCount;
index 3c66b3c..455d9af 100644 (file)
@@ -163,7 +163,7 @@ HidParser_StoreCollection(
         //
         // store offset
         //
-        TargetCollection->Offsets[Collection->NodeCount + Index] = CurrentOffset;
+        TargetCollection->Offsets[Collection->ReportCount + Index] = CurrentOffset;
 
         //
         // store sub collections
@@ -254,7 +254,7 @@ HidParser_SearchReportInCollection(
         //
         // get collection
         //
-        SubCollection = (PHID_COLLECTION)(CollectionContext->RawData + Collection->Offsets[Collection->NodeCount + Index]);
+        SubCollection = (PHID_COLLECTION)(CollectionContext->RawData + Collection->Offsets[Collection->ReportCount + Index]);
 
         //
         // recursively search collection
@@ -314,7 +314,7 @@ HidParser_GetCollectionCount(
         //
         // get offset to sub collection
         //
-        SubCollection = (PHID_COLLECTION)(CollectionContext->RawData + Collection->Offsets[Collection->NodeCount + Index]);
+        SubCollection = (PHID_COLLECTION)(CollectionContext->RawData + Collection->Offsets[Collection->ReportCount + Index]);
 
         //
         // count collection for sub nodes
index ca6be3c..6e9d4ef 100644 (file)
@@ -68,7 +68,7 @@ HidParser_GetCollectionDescription(
         // failed to parse report descriptor
         //
         Parser->Debug("[HIDPARSER] Failed to parse report descriptor with %x\n", ParserStatus);
-        return TranslateHidParserStatus(ParserStatus);
+        return ParserStatus;
     }
 
     //
@@ -126,7 +126,9 @@ HidParser_GetCollectionDescription(
             //
             // no memory
             //
-            return TranslateHidParserStatus(ParserStatus);
+            Parser->Free(DeviceDescription->CollectionDesc);
+            Parser->Free(DeviceDescription->ReportIDs);
+            return ParserStatus;
         }
 
         //
@@ -153,6 +155,13 @@ HidParser_GetCollectionDescription(
         // get collection usage page
         //
         ParserStatus = HidParser_GetCollectionUsagePage((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, &DeviceDescription->CollectionDesc[Index].Usage, &DeviceDescription->CollectionDesc[Index].UsagePage);
+        if (ParserStatus != HIDPARSER_STATUS_SUCCESS)
+        {
+            // collection not found
+            Parser->Free(DeviceDescription->CollectionDesc);
+            Parser->Free(DeviceDescription->ReportIDs);
+            return ParserStatus;
+        }
 
         //
         // windows seems to prepend the report id, regardless if it is required
index c314a96..e0208f6 100644 (file)
@@ -713,30 +713,6 @@ HidParser_AddMainItem(
     return HIDPARSER_STATUS_SUCCESS;
 }
 
-HIDPARSER_STATUS
-AllocateParserContext(
-    IN PHID_PARSER Parser,
-    OUT PHID_PARSER_CONTEXT *OutParserContext)
-{
-    PHID_PARSER_CONTEXT ParserContext;
-
-    ParserContext = Parser->Alloc(sizeof(HID_PARSER_CONTEXT));
-    if (!ParserContext)
-    {
-        //
-        // failed
-        //
-        return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    //
-    // store result
-    //
-    *OutParserContext = ParserContext;
-    return HIDPARSER_STATUS_SUCCESS;
-}
-
-
 HIDPARSER_STATUS
 HidParser_ParseReportDescriptor(
     IN PHID_PARSER Parser,
@@ -760,12 +736,18 @@ HidParser_ParseReportDescriptor(
     PMAIN_ITEM_DATA MainItemData;
     PHID_PARSER_CONTEXT ParserContext;
 
+    CurrentOffset = ReportDescriptor;
+    ReportEnd = ReportDescriptor + ReportLength;
+
+    if (ReportDescriptor >= ReportEnd)
+        return HIDPARSER_STATUS_COLLECTION_NOT_FOUND;
+
     //
     // allocate parser
     //
-    Status = AllocateParserContext(Parser, &ParserContext);
-    if (Status != HIDPARSER_STATUS_SUCCESS)
-        return Status;
+    ParserContext = Parser->Alloc(sizeof(HID_PARSER_CONTEXT));;
+    if (!ParserContext)
+        return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
 
 
     //
@@ -778,6 +760,7 @@ HidParser_ParseReportDescriptor(
         //
         // no memory
         //
+        Parser->Free(ParserContext);
         return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
     }
 
@@ -792,6 +775,7 @@ HidParser_ParseReportDescriptor(
         //
         Parser->Free(ParserContext->LocalItemState.UsageStack);
         ParserContext->LocalItemState.UsageStack = NULL;
+        Parser->Free(ParserContext);
         return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES;
     }
 
@@ -799,8 +783,6 @@ HidParser_ParseReportDescriptor(
     // start parsing
     //
     CurrentCollection = ParserContext->RootCollection;
-    CurrentOffset = ReportDescriptor;
-    ReportEnd = ReportDescriptor + ReportLength;
 
     do
     {
@@ -1230,8 +1212,7 @@ HidParser_ParseReportDescriptor(
         //
         CurrentOffset += CurrentItemSize + sizeof(ITEM_PREFIX);
 
-
-    }while(CurrentOffset < ReportEnd);
+    }while (CurrentOffset < ReportEnd);
 
 
     //
index d3a90a3..5f0ac07 100644 (file)
@@ -568,7 +568,8 @@ CHubController::HandlePnp(
                     break;
                 }
             }
-            Status = STATUS_SUCCESS;
+            // Here we should leave Status as is.
+            Status = Irp->IoStatus.Status;
             break;
         }
         case IRP_MN_QUERY_CAPABILITIES:
@@ -611,6 +612,14 @@ CHubController::HandlePnp(
             // handle device interface requests
             //
             Status = HandleQueryInterface(IoStack);
+
+            //
+            // If a bus driver does not export the requested interface, it
+            // should leave Status as is.
+            //
+            if (Status == STATUS_NOT_SUPPORTED)
+                Status = Irp->IoStatus.Status;
+
             break;
         }
         case IRP_MN_REMOVE_DEVICE:
@@ -3736,6 +3745,7 @@ CHubController::HandleQueryInterface(
             InterfaceHub->SetDeviceHandleData = USBHI_SetDeviceHandleData;
         }
 
+        InterfaceHub->InterfaceReference(InterfaceHub->BusContext);
         //
         // request completed
         //
@@ -3790,6 +3800,7 @@ CHubController::HandleQueryInterface(
             InterfaceDI->EnumLogEntry = USBDI_EnumLogEntry;
         }
 
+        InterfaceDI->InterfaceReference(InterfaceDI->BusContext);
         //
         // request completed
         //