[USBHUB_NEW] Bring-in the USB Hub driver created by Vadim Galyant. GitHub PR #29...
[reactos.git] / reactos / drivers / usb / usbhub_new / pnp.c
diff --git a/reactos/drivers/usb/usbhub_new/pnp.c b/reactos/drivers/usb/usbhub_new/pnp.c
new file mode 100644 (file)
index 0000000..bfdd8e1
--- /dev/null
@@ -0,0 +1,2811 @@
+#include "usbhub.h"
+
+#define NDEBUG
+#include <debug.h>
+
+#define NDEBUG_USBHUB_PNP
+#define NDEBUG_USBHUB_ENUM
+#include "dbg_uhub.h"
+
+NTSTATUS
+NTAPI
+USBH_IrpCompletion(IN PDEVICE_OBJECT DeviceObject,
+                   IN PIRP Irp,
+                   IN PVOID Context)
+{
+    PRKEVENT Event;
+
+    DPRINT("USBH_IrpCompletion: Irp - %p\n", Irp);
+
+    Event = Context;
+    KeSetEvent(Event, EVENT_INCREMENT, FALSE);
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+NTAPI
+USBH_HubPnPIrpComplete(IN PDEVICE_OBJECT DeviceObject,
+                       IN PIRP Irp,
+                       IN PVOID Context)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+
+    DPRINT("USBH_HubPnPIrpComplete: Irp - %p\n", Irp);
+
+     HubExtension = Context;
+
+    if (!NT_SUCCESS(Irp->IoStatus.Status))
+    {
+        DPRINT1("USBH_HubPnPIrpComplete: Irp failed - %lX\n", Irp->IoStatus.Status);
+        HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
+    }
+
+    Irp->IoStatus.Status = STATUS_MORE_PROCESSING_REQUIRED;
+
+    KeSetEvent(&HubExtension->LowerDeviceEvent, EVENT_INCREMENT, FALSE);
+
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+NTAPI
+USBH_QueryCapsComplete(IN PDEVICE_OBJECT DeviceObject,
+                       IN PIRP Irp,
+                       IN PVOID Context)
+{
+    PIO_STACK_LOCATION IoStack;
+    PDEVICE_CAPABILITIES Capabilities;
+
+    DPRINT("USBH_QueryCapsComplete: ... \n");
+
+    ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
+
+    if (Irp->PendingReturned)
+    {
+        IoMarkIrpPending(Irp);
+    }
+
+    IoStack= IoGetCurrentIrpStackLocation(Irp);
+    Capabilities = IoStack->Parameters.DeviceCapabilities.Capabilities;
+
+    Capabilities->SurpriseRemovalOK = 1;
+
+    return STATUS_CONTINUE_COMPLETION;
+}
+
+NTSTATUS
+NTAPI
+USBHUB_GetBusInterface(IN PDEVICE_OBJECT DeviceObject,
+                       OUT PUSB_BUS_INTERFACE_HUB_V5 BusInterface)
+{
+    PIRP Irp;
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IoStack;
+    KEVENT Event;
+
+    DPRINT("USBHUB_GetBusInterface: ... \n");
+
+    Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
+
+    if (!Irp)
+    {
+        DPRINT1("USBHUB_GetBusInterface: IoAllocateIrp() failed\n");
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    IoSetCompletionRoutine(Irp,
+                           USBH_IrpCompletion,
+                           &Event,
+                           TRUE,
+                           TRUE,
+                           TRUE);
+
+    IoStack = IoGetNextIrpStackLocation(Irp);
+
+    IoStack->MajorFunction = IRP_MJ_PNP;
+    IoStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
+
+    IoStack->Parameters.QueryInterface.InterfaceType = &USB_BUS_INTERFACE_HUB_GUID;
+    IoStack->Parameters.QueryInterface.Size = sizeof(USB_BUS_INTERFACE_HUB_V5);
+    IoStack->Parameters.QueryInterface.Version = USB_BUSIF_HUB_VERSION_5;
+    IoStack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface;
+    IoStack->Parameters.QueryInterface.InterfaceSpecificData = DeviceObject;
+
+    Status = IoCallDriver(DeviceObject, Irp);
+
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+
+        Status = Irp->IoStatus.Status;
+    }
+
+    IoFreeIrp(Irp);
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBHUB_GetBusInterfaceUSBDI(IN PDEVICE_OBJECT DeviceObject,
+                            OUT PUSB_BUS_INTERFACE_USBDI_V2 BusInterfaceUSBDI)
+{
+    PIRP Irp;
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IoStack;
+    KEVENT Event;
+
+    DPRINT("USBHUB_GetBusInterfaceUSBDI: ... \n");
+
+    Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
+
+    if (!Irp)
+    {
+        DPRINT1("USBHUB_GetBusInterfaceUSBDI: IoAllocateIrp() failed\n");
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    IoSetCompletionRoutine(Irp,
+                           USBH_IrpCompletion,
+                           &Event,
+                           TRUE,
+                           TRUE,
+                           TRUE);
+
+    IoStack = IoGetNextIrpStackLocation(Irp);
+
+    IoStack->MajorFunction = IRP_MJ_PNP;
+    IoStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
+
+    IoStack->Parameters.QueryInterface.InterfaceType = &USB_BUS_INTERFACE_USBDI_GUID;
+    IoStack->Parameters.QueryInterface.Size = sizeof(USB_BUS_INTERFACE_USBDI_V2);
+    IoStack->Parameters.QueryInterface.Version = USB_BUSIF_USBDI_VERSION_2;
+    IoStack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterfaceUSBDI;
+    IoStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
+
+    Status = IoCallDriver(DeviceObject, Irp);
+
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+
+        Status = Irp->IoStatus.Status;
+    }
+
+    IoFreeIrp(Irp);
+
+    return Status;
+}
+
+VOID
+NTAPI
+USBH_QueryCapabilities(IN PDEVICE_OBJECT DeviceObject,
+                       IN PDEVICE_CAPABILITIES DeviceCapabilities)
+{
+    PIRP Irp;
+    PIO_STACK_LOCATION IoStack;
+    KEVENT Event;
+
+    DPRINT("USBH_QueryCapabilities: ... \n");
+
+    RtlZeroMemory(DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
+
+    Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
+
+    if (!Irp)
+    {
+        DPRINT1("USBH_QueryCapabilities: IoAllocateIrp() failed\n");
+        return;
+    }
+
+    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    IoSetCompletionRoutine(Irp,
+                           USBH_IrpCompletion,
+                           &Event,
+                           TRUE,
+                           TRUE,
+                           TRUE);
+
+    IoStack = IoGetNextIrpStackLocation(Irp);
+    IoStack->MajorFunction = IRP_MJ_PNP;
+    IoStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
+
+    IoStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
+    IoStack->Parameters.DeviceCapabilities.Capabilities->Size = sizeof(DEVICE_CAPABILITIES);
+    IoStack->Parameters.DeviceCapabilities.Capabilities->Version = 1;
+    IoStack->Parameters.DeviceCapabilities.Capabilities->Address = MAXULONG;
+    IoStack->Parameters.DeviceCapabilities.Capabilities->UINumber = MAXULONG;
+
+    if (IoCallDriver(DeviceObject, Irp) == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+
+    IoFreeIrp(Irp);
+}
+
+NTSTATUS
+NTAPI
+USBH_OpenConfiguration(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    PUSB_INTERFACE_DESCRIPTOR Pid;
+    PURB Urb;
+    NTSTATUS Status;
+    USBD_INTERFACE_LIST_ENTRY InterfaceList[2] = {{NULL, NULL}, {NULL, NULL}};
+
+    DPRINT("USBH_OpenConfiguration ... \n");
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB && 
+        HubExtension->LowerPDO != HubExtension->RootHubPdo)
+    {
+        Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor,
+                                                  HubExtension->HubConfigDescriptor,
+                                                  -1,
+                                                  -1,
+                                                  USB_DEVICE_CLASS_HUB,
+                                                  -1,
+                                                  2);
+
+        if (Pid)
+        {
+            HubExtension->HubFlags |= USBHUB_FDO_FLAG_MULTIPLE_TTS;
+        }
+        else
+        {
+            Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor,
+                                                      HubExtension->HubConfigDescriptor,
+                                                      -1,
+                                                      -1,
+                                                      USB_DEVICE_CLASS_HUB,
+                                                      -1,
+                                                      1);
+
+            if (Pid)
+            {
+                goto Next;
+            }
+
+            Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor,
+                                                      HubExtension->HubConfigDescriptor,
+                                                      -1,
+                                                      -1,
+                                                      USB_DEVICE_CLASS_HUB,
+                                                      -1,
+                                                      0);
+        }
+    }
+    else
+    {
+        Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor,
+                                                  HubExtension->HubConfigDescriptor,
+                                                  -1,
+                                                  -1,
+                                                  USB_DEVICE_CLASS_HUB,
+                                                  -1,
+                                                  -1);
+    }
+
+    if (!Pid)
+    {
+        return STATUS_UNSUCCESSFUL;
+    }
+
+  Next:
+
+    if (Pid->bInterfaceClass != USB_DEVICE_CLASS_HUB)
+    {
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    InterfaceList[0].InterfaceDescriptor = Pid;
+
+    Urb = USBD_CreateConfigurationRequestEx(HubExtension->HubConfigDescriptor,
+                                            InterfaceList);
+
+    if (!Urb)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice, Urb);
+
+    if (NT_SUCCESS(Status))
+    {
+        RtlCopyMemory(&HubExtension->PipeInfo,
+                      InterfaceList[0].Interface->Pipes,
+                      sizeof(USBD_PIPE_INFORMATION));
+
+        HubExtension->ConfigHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
+    }
+
+    ExFreePool(Urb);
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBD_Initialize20Hub(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    PUSB_BUSIFFN_INITIALIZE_20HUB Initialize20Hub;
+    ULONG TtCount;
+    PUSB_DEVICE_HANDLE DeviceHandle;
+
+    DPRINT("USBD_InitUsb2Hub ... \n");
+
+    Initialize20Hub = HubExtension->BusInterface.Initialize20Hub;
+
+    if (!Initialize20Hub)
+    {
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    TtCount = 1;
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_MULTIPLE_TTS)
+    {
+        TtCount = HubExtension->HubDescriptor->bNumberOfPorts;
+    }
+
+    DeviceHandle = USBH_SyncGetDeviceHandle(HubExtension->LowerDevice);
+
+    return Initialize20Hub(HubExtension->BusInterface.BusContext,
+                           DeviceHandle,
+                           TtCount);
+}
+
+NTSTATUS
+NTAPI
+USBH_AbortInterruptPipe(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    struct _URB_PIPE_REQUEST * Urb;
+    NTSTATUS Status;
+
+    DPRINT("USBH_AbortInterruptPipe: HubExtension - %p\n", HubExtension);
+
+    Urb = ExAllocatePoolWithTag(NonPagedPool,
+                                sizeof(struct _URB_PIPE_REQUEST),
+                                USB_HUB_TAG);
+
+    if (!Urb)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(Urb, sizeof(struct _URB_PIPE_REQUEST));
+
+    Urb->Hdr.Length = sizeof(struct _URB_PIPE_REQUEST);
+    Urb->Hdr.Function = URB_FUNCTION_ABORT_PIPE;
+    Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle;
+
+    Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice,
+                                   (PURB)Urb);
+
+    if (NT_SUCCESS(Status))
+    {
+        KeWaitForSingleObject(&HubExtension->StatusChangeEvent,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+
+    ExFreePoolWithTag(Urb, USB_HUB_TAG);
+
+    return Status;
+}
+
+VOID
+NTAPI
+USBH_FdoCleanup(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    PIRP IdleIrp = NULL;
+    PIRP WakeIrp = NULL;
+    PUSBHUB_PORT_DATA PortData;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    PIRP PortIdleIrp = NULL;
+    PIRP PortWakeIrp = NULL;
+    PVOID DeviceHandle;
+    NTSTATUS Status;
+    USHORT Port;
+    UCHAR NumberPorts;
+    KIRQL Irql;
+
+    DPRINT("USBH_FdoCleanup: HubExtension - %p\n", HubExtension);
+
+    USBD_UnRegisterRootHubCallBack(HubExtension);
+
+    HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_STOPPING;
+
+    if (HubExtension->ResetRequestCount)
+    {
+        IoCancelIrp(HubExtension->ResetPortIrp);
+
+        KeWaitForSingleObject(&HubExtension->IdleEvent,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+
+    IoFreeIrp(HubExtension->ResetPortIrp);
+
+    HubExtension->ResetPortIrp = NULL;
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
+    {
+        KeWaitForSingleObject(&HubExtension->IdleEvent,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+
+    IoAcquireCancelSpinLock(&Irql);
+
+    if (HubExtension->PendingWakeIrp)
+    {
+        WakeIrp = HubExtension->PendingWakeIrp;
+        HubExtension->PendingWakeIrp = NULL;
+    }
+
+    if (HubExtension->PendingIdleIrp)
+    {
+        IdleIrp = HubExtension->PendingIdleIrp;
+        HubExtension->PendingIdleIrp = NULL;
+    }
+
+    IoReleaseCancelSpinLock(Irql);
+
+    if (WakeIrp)
+    {
+        USBH_HubCancelWakeIrp(HubExtension, WakeIrp);
+    }
+
+    USBH_HubCompletePortWakeIrps(HubExtension, STATUS_DELETE_PENDING);
+
+    if (IdleIrp)
+    {
+        USBH_HubCancelIdleIrp(HubExtension, IdleIrp);
+    }
+
+    if (InterlockedDecrement(&HubExtension->PendingRequestCount) > 0)
+    {
+        KeWaitForSingleObject(&HubExtension->PendingRequestEvent,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+
+    if (HubExtension->SCEIrp)
+    {
+        Status = USBH_AbortInterruptPipe(HubExtension);
+
+        if (!NT_SUCCESS(Status) && IoCancelIrp(HubExtension->SCEIrp))
+        {
+            KeWaitForSingleObject(&HubExtension->StatusChangeEvent,
+                                  Suspended,
+                                  KernelMode,
+                                  FALSE,
+                                  NULL);
+        }
+
+        IoFreeIrp(HubExtension->SCEIrp);
+
+        HubExtension->SCEIrp = NULL;
+    }
+
+    if (!HubExtension->PortData ||
+        !HubExtension->HubDescriptor)
+    {
+        goto Exit;
+    }
+
+    PortData = HubExtension->PortData;
+    NumberPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+
+    for (Port = 0; Port < NumberPorts; Port++)
+    {
+        if (PortData[Port].DeviceObject)
+        {
+            PortExtension = PortData[Port].DeviceObject->DeviceExtension;
+
+            IoAcquireCancelSpinLock(&Irql);
+
+            PortIdleIrp = PortExtension->IdleNotificationIrp;
+
+            if (PortIdleIrp)
+            {
+                PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_IDLE_NOTIFICATION;
+                PortExtension->IdleNotificationIrp = NULL;
+
+                if (PortIdleIrp->Cancel)
+                {
+                    PortIdleIrp = NULL;
+                }
+
+                if (PortIdleIrp)
+                {
+                    IoSetCancelRoutine(PortIdleIrp, NULL);
+                }
+            }
+
+            PortWakeIrp = PortExtension->PdoWaitWakeIrp;
+
+            if (PortWakeIrp)
+            {
+                PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_WAIT_WAKE;
+                PortExtension->PdoWaitWakeIrp = NULL;
+
+                if (PortWakeIrp->Cancel || !IoSetCancelRoutine(PortWakeIrp, NULL))
+                {
+                    PortWakeIrp = NULL;
+
+                    if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+                    {
+                        KeSetEvent(&HubExtension->PendingRequestEvent,
+                                   EVENT_INCREMENT,
+                                   FALSE);
+                    }
+                }
+            }
+
+            IoReleaseCancelSpinLock(Irql);
+
+            if (PortIdleIrp)
+            {
+                PortIdleIrp->IoStatus.Status = STATUS_CANCELLED;
+                IoCompleteRequest(PortIdleIrp, IO_NO_INCREMENT);
+            }
+
+            if (PortWakeIrp)
+            {
+                USBH_CompletePowerIrp(HubExtension,
+                                      PortWakeIrp,
+                                      STATUS_CANCELLED);
+            }
+
+            if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3))
+            {
+                DeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
+                                                          NULL);
+
+                if (DeviceHandle)
+                {
+                    USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
+                }
+
+                PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_POWER_D3;
+            }
+        }
+
+        USBH_SyncDisablePort(HubExtension, Port + 1);
+    }
+
+Exit:
+
+    if (HubExtension->SCEBitmap)
+    {
+        ExFreePoolWithTag(HubExtension->SCEBitmap, USB_HUB_TAG);
+    }
+
+    if (HubExtension->HubDescriptor)
+    {
+        ExFreePoolWithTag(HubExtension->HubDescriptor, USB_HUB_TAG);
+    }
+
+    if (HubExtension->HubConfigDescriptor)
+    {
+        ExFreePoolWithTag(HubExtension->HubConfigDescriptor, USB_HUB_TAG);
+    }
+
+    HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DEVICE_STARTED;
+
+    HubExtension->HubDescriptor = NULL;
+    HubExtension->HubConfigDescriptor = NULL;
+
+    HubExtension->SCEIrp = NULL;
+    HubExtension->SCEBitmap = NULL;
+}
+
+NTSTATUS
+NTAPI
+USBH_StartHubFdoDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                       IN PIRP Irp)
+{
+    NTSTATUS Status;
+    ULONG DisableRemoteWakeup = 0;
+    ULONG HubCount = 0;
+    PUSB_DEVICE_HANDLE DeviceHandle;
+    USB_DEVICE_TYPE DeviceType;
+    DEVICE_CAPABILITIES  DeviceCapabilities;
+    BOOLEAN IsBusPowered;
+    static WCHAR DisableWakeValueName[] = L"DisableRemoteWakeup";
+
+    DPRINT("USBH_StartHubFdoDevice: ... \n");
+
+    KeInitializeEvent(&HubExtension->IdleEvent, NotificationEvent, FALSE);
+    KeInitializeEvent(&HubExtension->ResetEvent, NotificationEvent, TRUE);
+    KeInitializeEvent(&HubExtension->PendingRequestEvent, NotificationEvent, FALSE);
+    KeInitializeEvent(&HubExtension->LowerDeviceEvent, NotificationEvent, FALSE);
+    KeInitializeEvent(&HubExtension->StatusChangeEvent, NotificationEvent, TRUE);
+    KeInitializeEvent(&HubExtension->RootHubNotificationEvent,
+                      NotificationEvent,
+                      TRUE);
+
+    KeInitializeSpinLock(&HubExtension->RelationsWorkerSpinLock);
+    KeInitializeSpinLock(&HubExtension->CheckIdleSpinLock);
+
+    KeInitializeSemaphore(&HubExtension->ResetDeviceSemaphore, 1, 1);
+    KeInitializeSemaphore(&HubExtension->HubPortSemaphore, 1, 1);
+    KeInitializeSemaphore(&HubExtension->HubSemaphore, 1, 1);
+
+    HubExtension->HubFlags = 0;
+    HubExtension->HubConfigDescriptor = NULL;
+    HubExtension->HubDescriptor = NULL;
+    HubExtension->SCEIrp = NULL;
+    HubExtension->SCEBitmap = NULL;
+    HubExtension->SystemPowerState.SystemState = PowerSystemWorking;
+    HubExtension->PendingRequestCount = 1;
+    HubExtension->ResetRequestCount = 0;
+    HubExtension->PendingIdleIrp = NULL;
+    HubExtension->PendingWakeIrp = NULL;
+
+    InitializeListHead(&HubExtension->PdoList);
+
+    HubExtension->HubFlags |= USBHUB_FDO_FLAG_WITEM_INIT;
+    InitializeListHead(&HubExtension->WorkItemList);
+    KeInitializeSpinLock(&HubExtension->WorkItemSpinLock);
+
+    IoCopyCurrentIrpStackLocationToNext(Irp);
+
+    IoSetCompletionRoutine(Irp,
+                           USBH_HubPnPIrpComplete,
+                           HubExtension,
+                           TRUE,
+                           TRUE,
+                           TRUE);
+
+    if (IoCallDriver(HubExtension->LowerDevice, Irp) == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&HubExtension->LowerDeviceEvent,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+
+    HubExtension->RootHubPdo = NULL;
+
+    Status = USBH_SyncGetRootHubPdo(HubExtension->LowerDevice,
+                                    &HubExtension->RootHubPdo,
+                                    &HubExtension->RootHubPdo2);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("USBH_SyncGetRootHubPdo() failed - %lX\n", Status);
+        goto ErrorExit;
+    }
+
+    USBH_WriteFailReasonID(HubExtension->LowerPDO, USBHUB_FAIL_NO_FAIL);
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED)
+    {
+        DPRINT1("USBH_StartHubFdoDevice: USBHUB_FDO_FLAG_DEVICE_FAILED - TRUE\n");
+        Status = STATUS_UNSUCCESSFUL;
+        goto ErrorExit;
+    }
+
+    HubExtension->HubFlags |= USBHUB_FDO_FLAG_REMOTE_WAKEUP;
+
+    Status = USBD_GetPdoRegistryParameter(HubExtension->LowerPDO,
+                                          &DisableRemoteWakeup,
+                                          sizeof(DisableRemoteWakeup),
+                                          DisableWakeValueName,
+                                          sizeof(DisableWakeValueName));
+
+    if (NT_SUCCESS(Status) && DisableRemoteWakeup)
+    {
+        DPRINT("USBH_StartHubFdoDevice: DisableRemoteWakeup - TRUE\n");
+        HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_REMOTE_WAKEUP;
+    }
+
+    HubExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
+
+    USBH_SyncGetHubCount(HubExtension->LowerDevice,
+                         &HubCount);
+
+    Status = USBHUB_GetBusInterface(HubExtension->RootHubPdo,
+                                    &HubExtension->BusInterface);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("USBH_StartHubFdoDevice: USBHUB_GetBusInterface() failed - %lX\n",
+                Status);
+        goto ErrorExit;
+    }
+
+    Status = USBHUB_GetBusInterfaceUSBDI(HubExtension->LowerDevice,
+                                         &HubExtension->BusInterfaceUSBDI);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("USBH_StartHubFdoDevice: USBHUB_GetBusInterfaceUSBDI() failed - %lX\n",
+                Status);
+        goto ErrorExit;
+    }
+
+    DeviceHandle = USBH_SyncGetDeviceHandle(HubExtension->LowerDevice);
+
+    if (DeviceHandle)
+    {
+        Status = USBH_GetDeviceType(HubExtension, DeviceHandle, &DeviceType);
+
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("USBH_StartHubFdoDevice: USBH_GetDeviceType() failed - %lX\n",
+                    Status);
+
+            goto ErrorExit;
+        }
+
+        if (DeviceType == Usb20Device)
+        {
+            HubExtension->HubFlags |= USBHUB_FDO_FLAG_USB20_HUB;
+        }
+    }
+
+    if (HubCount > USBHUB_MAX_CASCADE_LEVELS)
+    {
+        PUSBHUB_PORT_PDO_EXTENSION ParentPdoExtension;
+        PUSBHUB_FDO_EXTENSION ParentHubExtension;
+        USHORT ParentPort;
+        PUSBHUB_PORT_DATA PortData;
+
+        DPRINT1("USBH_StartHubFdoDevice: HubCount > 6 - %x\n", HubCount);
+
+        USBH_WriteFailReasonID(HubExtension->LowerPDO,
+                               USBHUB_FAIL_NESTED_TOO_DEEPLY);
+
+        ParentPdoExtension = HubExtension->LowerPDO->DeviceExtension;
+        ParentHubExtension = ParentPdoExtension->HubExtension;
+
+        ParentPort = ParentPdoExtension->PortNumber - 1;
+        PortData = &ParentHubExtension->PortData[ParentPort];
+        PortData->ConnectionStatus = DeviceHubNestedTooDeeply;
+
+        HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
+    }
+
+    USBH_QueryCapabilities(HubExtension->LowerDevice, &DeviceCapabilities);
+
+    HubExtension->SystemWake = DeviceCapabilities.SystemWake;
+    HubExtension->DeviceWake = DeviceCapabilities.DeviceWake;
+
+    RtlCopyMemory(HubExtension->DeviceState,
+                  &DeviceCapabilities.DeviceState,
+                  POWER_SYSTEM_MAXIMUM * sizeof(DEVICE_POWER_STATE));
+
+    Status = USBH_GetDeviceDescriptor(HubExtension->Common.SelfDevice,
+                                      &HubExtension->HubDeviceDescriptor);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("USBH_StartHubFdoDevice: USBH_GetDeviceDescriptor() failed - %lX\n",
+                Status);
+        goto ErrorExit;
+    }
+
+    Status = USBH_GetConfigurationDescriptor(HubExtension->Common.SelfDevice,
+                                             &HubExtension->HubConfigDescriptor);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("USBH_StartHubFdoDevice: USBH_GetConfigurationDescriptor() failed - %lX\n",
+                Status);
+        goto ErrorExit;
+    }
+
+    Status = USBH_SyncGetHubDescriptor(HubExtension);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("USBH_StartHubFdoDevice: USBH_SyncGetHubDescriptor() failed - %lX\n",
+                Status);
+        goto ErrorExit;
+    }
+
+    IsBusPowered = USBH_HubIsBusPowered(HubExtension->Common.SelfDevice,
+                                        HubExtension->HubConfigDescriptor);
+
+    if (IsBusPowered)
+    {
+        /* bus-powered hub is allowed a maximum of 100 mA only for each port */
+        HubExtension->MaxPowerPerPort = 100;
+
+        /* can have 4 ports (4 * 100 mA) and 100 mA remains for itself;
+           expressed in 2 mA units (i.e., 250 = 500 mA). */
+        HubExtension->HubConfigDescriptor->MaxPower = 250;
+    }
+    else
+    {
+        /* self-powered hub is allowed a maximum of 500 mA for each port */
+        HubExtension->MaxPowerPerPort = 500;
+    }
+
+    Status = USBH_OpenConfiguration(HubExtension);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("USBH_StartHubFdoDevice: USBH_OpenConfiguration() failed - %lX\n",
+                Status);
+        goto ErrorExit;
+    }
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB)
+    {
+        Status = USBD_Initialize20Hub(HubExtension);
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        goto ErrorExit;
+    }
+
+    HubExtension->SCEIrp = IoAllocateIrp(HubExtension->Common.SelfDevice->StackSize,
+                                         FALSE);
+
+    HubExtension->ResetPortIrp = IoAllocateIrp(HubExtension->Common.SelfDevice->StackSize,
+                                               FALSE);
+
+    if (!HubExtension->SCEIrp || !HubExtension->ResetPortIrp)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto ErrorExit;
+    }
+
+    HubExtension->SCEBitmapLength = HubExtension->PipeInfo.MaximumPacketSize;
+
+    HubExtension->SCEBitmap = ExAllocatePoolWithTag(NonPagedPool,
+                                                    HubExtension->SCEBitmapLength,
+                                                    USB_HUB_TAG);
+
+    if (!HubExtension->SCEBitmap)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto ErrorExit;
+    }
+
+    RtlZeroMemory(HubExtension->SCEBitmap, HubExtension->SCEBitmapLength);
+
+    Status = USBH_SyncPowerOnPorts(HubExtension);
+
+    if (!NT_SUCCESS(Status))
+    {
+        goto ErrorExit;
+    }
+    else
+    {
+        USHORT Port;
+
+        HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_STARTED;
+
+        for (Port = 1;
+             Port <= HubExtension->HubDescriptor->bNumberOfPorts;
+             Port++)
+        {
+            USBH_SyncClearPortStatus(HubExtension,
+                                     Port,
+                                     USBHUB_FEATURE_C_PORT_CONNECTION);
+        }
+    }
+
+    if (HubExtension->LowerPDO == HubExtension->RootHubPdo)
+    {
+        USBD_RegisterRootHubCallBack(HubExtension);
+    }
+    else
+    {
+        HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_ENUMERATION;
+        USBH_SubmitStatusChangeTransfer(HubExtension);
+    }
+
+    goto Exit;
+
+  ErrorExit:
+
+    if (HubExtension->HubDescriptor)
+    {
+        ExFreePoolWithTag(HubExtension->HubDescriptor, USB_HUB_TAG);
+        HubExtension->HubDescriptor = NULL;
+    }
+
+    if (HubExtension->SCEIrp)
+    {
+        IoFreeIrp(HubExtension->SCEIrp);
+        HubExtension->SCEIrp = NULL;
+    }
+
+    if (HubExtension->ResetPortIrp)
+    {
+        IoFreeIrp(HubExtension->ResetPortIrp);
+        HubExtension->ResetPortIrp = NULL;
+    }
+
+    if (HubExtension->SCEBitmap)
+    {
+        ExFreePoolWithTag(HubExtension->SCEBitmap, USB_HUB_TAG);
+        HubExtension->SCEBitmap = NULL;
+    }
+
+    if (HubExtension->HubConfigDescriptor)
+    {
+        ExFreePoolWithTag(HubExtension->HubConfigDescriptor, USB_HUB_TAG);
+        HubExtension->HubConfigDescriptor = NULL;
+    }
+
+  Exit:
+
+    USBH_CompleteIrp(Irp, Status);
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoStartDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                    IN PIRP Irp)
+{
+    NTSTATUS Status;
+
+    DPRINT("USBH_FdoStartDevice: HubExtension - %p\n", HubExtension);
+
+    HubExtension->RootHubPdo = NULL;
+
+    Status = USBH_SyncGetRootHubPdo(HubExtension->LowerDevice,
+                                    &HubExtension->RootHubPdo,
+                                    &HubExtension->RootHubPdo2);
+
+    if (NT_SUCCESS(Status))
+    {
+        if (HubExtension->RootHubPdo)
+        {
+            Status = USBH_StartHubFdoDevice(HubExtension, Irp);
+        }
+        else
+        {
+            DPRINT1("USBH_FdoStartDevice: FIXME. start ParentDevice\n");
+            DbgBreakPoint();
+        }
+    }
+    else
+    {
+        DPRINT1("USBH_FdoStartDevice: FIXME. USBH_SyncGetRootHubPdo return - %lX\n",
+                Status);
+
+        DbgBreakPoint();
+        USBH_CompleteIrp(Irp, Status);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoQueryBusRelations(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                          IN PIRP Irp)
+{
+    PDEVICE_RELATIONS DeviceRelations = NULL;
+    NTSTATUS Status = STATUS_SUCCESS;
+    LIST_ENTRY GhostPdoList;
+    KIRQL OldIrql;
+    PLIST_ENTRY PdoList;
+    UCHAR NumberPorts;
+    USHORT Port;
+    USHORT GhostPort;
+    PUSBHUB_PORT_DATA PortData;
+    PDEVICE_OBJECT PdoDevice;
+    PUSBHUB_PORT_PDO_EXTENSION PdoExtension;
+    PUSBHUB_PORT_PDO_EXTENSION pdoExtension;
+    NTSTATUS NtStatus;
+    PVOID SerialNumber;
+    PVOID DeviceHandle;
+    USB_PORT_STATUS UsbPortStatus;
+    PLIST_ENTRY Entry;
+    ULONG Length;
+
+    DPRINT_ENUM("USBH_FdoQueryBusRelations: HubFlags - %lX\n",
+                HubExtension->HubFlags);
+
+    if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED))
+    {
+       Status = STATUS_INVALID_DEVICE_STATE;
+       goto RelationsWorker;
+    }
+
+    if (!HubExtension->HubDescriptor)
+    {
+        Status = STATUS_UNSUCCESSFUL;
+        goto RelationsWorker;
+    }
+
+    if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION))
+    {
+        DPRINT_ENUM("USBH_FdoQueryBusRelations: Skip enumeration\n");
+        goto RelationsWorker;
+    }
+
+    InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+    KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
+                          Executive,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    NumberPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+    DPRINT_ENUM("USBH_FdoQueryBusRelations: NumberPorts - %x\n", NumberPorts);
+
+    Length = FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
+             NumberPorts * sizeof(PDEVICE_OBJECT);
+
+    if (Irp->IoStatus.Information)
+    {
+        DPRINT1("FIXME: leaking old bus relations\n");
+    }
+
+    DeviceRelations = ExAllocatePoolWithTag(NonPagedPool, Length, USB_HUB_TAG);
+
+    if (!DeviceRelations)
+    {
+        HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_NOT_ENUMERATED;
+
+        KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
+                           LOW_REALTIME_PRIORITY,
+                           1,
+                           FALSE);
+
+        if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+        {
+            KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE);
+        }
+
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto RelationsWorker;
+    }
+
+    RtlZeroMemory(DeviceRelations, Length);
+
+    DeviceRelations->Count = 0;
+
+EnumStart:
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING)
+    {
+        HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_NOT_ENUMERATED;
+
+        KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
+                           LOW_REALTIME_PRIORITY,
+                           1,
+                           FALSE);
+
+        if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+        {
+            KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE);
+        }
+
+        Status = STATUS_SUCCESS;
+        goto RelationsWorker;
+    }
+
+    HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_ENUM_POST_RECOVER;
+
+    for (Port = 1; Port <= NumberPorts; Port++)
+    {
+        PortData = &HubExtension->PortData[Port - 1];
+
+        DPRINT_ENUM("USBH_FdoQueryBusRelations: Port - %x, ConnectStatus - %x\n",
+                    Port,
+                    PortData->PortStatus.UsbPortStatus.Usb20PortStatus.CurrentConnectStatus);
+
+        if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED)
+        {
+            continue;
+        }
+
+        Status = USBH_SyncGetPortStatus(HubExtension,
+                                        Port,
+                                        &PortData->PortStatus,
+                                        sizeof(USBHUB_PORT_STATUS));
+
+        if (!NT_SUCCESS(Status))
+        {
+            HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
+            DeviceRelations->Count = 0;
+            goto EnumStart;
+        }
+
+        PdoDevice = PortData->DeviceObject;
+
+        if (PortData->DeviceObject)
+        {
+            PdoExtension = PdoDevice->DeviceExtension;
+
+            if (PdoExtension->PortPdoFlags & USBHUB_PDO_FLAG_OVERCURRENT_PORT)
+            {
+                PortData->PortStatus.UsbPortStatus.Usb20PortStatus.CurrentConnectStatus = 1;
+            }
+        }
+
+        if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED)
+        {
+            DPRINT1("USBH_FdoQueryBusRelations: DbgBreakPoint() \n");
+            DbgBreakPoint();
+        }
+
+        if (!PortData->PortStatus.UsbPortStatus.Usb20PortStatus.CurrentConnectStatus)
+        {
+            if (PdoDevice)
+            {
+                PdoExtension = PdoDevice->DeviceExtension;
+
+                PdoExtension->PortPdoFlags |= USBHUB_PDO_FLAG_DELETE_PENDING;
+                PdoExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT;
+
+                SerialNumber = InterlockedExchangePointer((PVOID)&PdoExtension->SerialNumber,
+                                                          NULL);
+
+                if (SerialNumber)
+                {
+                    ExFreePoolWithTag(SerialNumber, USB_HUB_TAG);
+                }
+
+                DeviceHandle = InterlockedExchangePointer(&PdoExtension->DeviceHandle,
+                                                          NULL);
+
+                if (DeviceHandle)
+                {
+                    USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
+                    USBH_SyncDisablePort(HubExtension, Port);
+                }
+            }
+
+            PortData->DeviceObject = NULL;
+            PortData->ConnectionStatus = NoDeviceConnected;
+            continue;
+        }
+
+        if (PdoDevice)
+        {
+            ObReferenceObject(PdoDevice);
+
+            PdoDevice->Flags |= DO_POWER_PAGABLE;
+            PdoDevice->Flags &= ~DO_DEVICE_INITIALIZING;
+
+            DeviceRelations->Objects[DeviceRelations->Count++] = PdoDevice;
+
+            PdoExtension = PdoDevice->DeviceExtension;
+            PdoExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_POWER_D1_OR_D2;
+
+            continue;
+        }
+
+        USBH_Wait(100);
+
+        NtStatus = USBH_SyncResetPort(HubExtension, Port);
+
+        if (!NT_SUCCESS(NtStatus))
+        {
+            if (HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB)
+            {
+                PortData->DeviceObject = NULL;
+                PortData->ConnectionStatus = NoDeviceConnected;
+                continue;
+            }
+        }
+        else
+        {
+            NtStatus = USBH_SyncGetPortStatus(HubExtension,
+                                              Port,
+                                              &PortData->PortStatus,
+                                              sizeof(USBHUB_PORT_STATUS));
+
+            UsbPortStatus = PortData->PortStatus.UsbPortStatus;
+
+            if (NT_SUCCESS(NtStatus))
+            {
+                ULONG ix = 0;
+
+                for (NtStatus = USBH_CreateDevice(HubExtension, Port, UsbPortStatus, ix);
+                     !NT_SUCCESS(NtStatus);
+                     NtStatus = USBH_CreateDevice(HubExtension, Port, UsbPortStatus, ix))
+                {
+                    USBH_Wait(500);
+
+                    if (ix >= 2)
+                    {
+                        break;
+                    }
+
+                    if (PortData->DeviceObject)
+                    {
+                        IoDeleteDevice(PortData->DeviceObject);
+                        PortData->DeviceObject = NULL;
+                        PortData->ConnectionStatus = NoDeviceConnected;
+                    }
+
+                    USBH_SyncResetPort(HubExtension, Port);
+
+                    ix++;
+                }
+
+                if (NT_SUCCESS(NtStatus))
+                {
+                    PdoExtension = PortData->DeviceObject->DeviceExtension;
+
+                    if (!(PdoExtension->PortPdoFlags & USBHUB_PDO_FLAG_PORT_LOW_SPEED) &&
+                        !(PdoExtension->PortPdoFlags & USBHUB_PDO_FLAG_PORT_HIGH_SPEED) &&
+                        !(HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB))
+                    {
+                        DPRINT1("USBH_FdoQueryBusRelations: FIXME USBH_DeviceIs2xDualMode()\n");
+
+                        if (0)//USBH_DeviceIs2xDualMode(PdoExtension))
+                        {
+                            PdoExtension->PortPdoFlags |= USBHUB_PDO_FLAG_HS_USB1_DUALMODE;
+                        }
+                    }
+
+                    ObReferenceObject(PortData->DeviceObject);
+
+                    DeviceRelations->Objects[DeviceRelations->Count] = PortData->DeviceObject;
+
+                    PortData->DeviceObject->Flags |= DO_POWER_PAGABLE;
+                    PortData->DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+                    DeviceRelations->Count++;
+
+                    PortData->ConnectionStatus = DeviceConnected;
+
+                    continue;
+                }
+            }
+        }
+
+        PortData->ConnectionStatus = DeviceFailedEnumeration;
+
+        if (NT_ERROR(USBH_SyncDisablePort(HubExtension, Port)))
+        {
+            HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
+        }
+
+        if (PortData->DeviceObject)
+        {
+            ObReferenceObject(PortData->DeviceObject);
+            PortData->DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+            DeviceRelations->Objects[DeviceRelations->Count++] = PortData->DeviceObject;
+        }
+    }
+
+    HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_NOT_ENUMERATED;
+
+    KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
+                       LOW_REALTIME_PRIORITY,
+                       1,
+                       FALSE);
+
+    if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+    {
+        KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE);
+    }
+
+RelationsWorker:
+
+    Irp->IoStatus.Status = Status;
+
+    if (!NT_SUCCESS(Status))
+    {
+        //Irp->IoStatus.Information = 0;
+
+        if (DeviceRelations)
+        {
+            ExFreePoolWithTag(DeviceRelations, USB_HUB_TAG);
+        }
+
+        USBH_CompleteIrp(Irp, Status);
+
+        return Status;
+    }
+
+    KeAcquireSpinLock(&HubExtension->RelationsWorkerSpinLock, &OldIrql);
+
+    if (DeviceRelations && DeviceRelations->Count)
+    {
+        for (Port = 0; Port < DeviceRelations->Count; Port++)
+        {
+            PdoDevice = DeviceRelations->Objects[Port];
+            Entry = HubExtension->PdoList.Flink;
+
+            while (Entry != &HubExtension->PdoList)
+            {
+                pdoExtension = CONTAINING_RECORD(Entry,
+                                                 USBHUB_PORT_PDO_EXTENSION,
+                                                 PortLink);
+
+                if (pdoExtension == PdoDevice->DeviceExtension)
+                {
+                    PdoExt(PdoDevice)->EnumFlags |= USBHUB_ENUM_FLAG_GHOST_DEVICE;
+                    goto PortNext;
+                }
+
+                Entry = Entry->Flink;
+            }
+
+            PdoExt(PdoDevice)->EnumFlags |= USBHUB_ENUM_FLAG_DEVICE_PRESENT;
+
+    PortNext:;
+        }
+
+        for (Port = 0; Port < DeviceRelations->Count; Port++)
+        {
+            PdoDevice = DeviceRelations->Objects[Port];
+
+            if (PdoExt(PdoDevice)->EnumFlags & USBHUB_ENUM_FLAG_GHOST_DEVICE)
+            {
+                for (GhostPort = Port;
+                     GhostPort < DeviceRelations->Count;
+                     GhostPort++)
+                {
+                    DeviceRelations->Objects[GhostPort] =
+                    DeviceRelations->Objects[GhostPort + 1];
+                }
+
+                ObDereferenceObject(PdoDevice);
+
+                DeviceRelations->Count--;
+
+                if (PdoExt(PdoDevice)->EnumFlags & USBHUB_ENUM_FLAG_DEVICE_PRESENT)
+                {
+                    PdoExt(PdoDevice)->EnumFlags &= ~USBHUB_ENUM_FLAG_GHOST_DEVICE;
+                }
+            }
+        }
+    }
+
+    Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
+
+    InitializeListHead(&GhostPdoList);
+    PdoList = &HubExtension->PdoList;
+
+    while (!IsListEmpty(PdoList))
+    {
+        Entry = RemoveHeadList(PdoList);
+
+        PdoExtension = CONTAINING_RECORD(Entry,
+                                         USBHUB_PORT_PDO_EXTENSION,
+                                         PortLink);
+
+        PdoExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT;
+
+        if (PdoExtension->EnumFlags & USBHUB_ENUM_FLAG_GHOST_DEVICE)
+        {
+            InsertTailList(&GhostPdoList, &PdoExtension->PortLink);
+        }
+    }
+
+    KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, OldIrql);
+
+    while (!IsListEmpty(&GhostPdoList))
+    {
+        Entry = RemoveHeadList(&GhostPdoList);
+
+        PdoExtension = CONTAINING_RECORD(Entry,
+                                         USBHUB_PORT_PDO_EXTENSION,
+                                         PortLink);
+
+        IoDeleteDevice(PdoExtension->Common.SelfDevice);
+    }
+
+    return USBH_PassIrp(HubExtension->LowerDevice, Irp);
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoStopDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                   IN PIRP Irp)
+{
+    DPRINT1("USBH_FdoStopDevice: UNIMPLEMENTED. FIXME\n");
+    DbgBreakPoint();
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoRemoveDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                     IN PIRP Irp)
+{
+    PUSB_HUB_DESCRIPTOR HubDescriptor;
+    PUSBHUB_PORT_DATA PortData;
+    USHORT NumPorts;
+    USHORT ix;
+    PDEVICE_OBJECT PortDevice;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    NTSTATUS Status;
+
+    DPRINT("USBH_FdoRemoveDevice: HubExtension - %p\n", HubExtension);
+
+    HubDescriptor = HubExtension->HubDescriptor;
+
+    if (HubDescriptor && HubExtension->PortData)
+    {
+        NumPorts = HubDescriptor->bNumberOfPorts;
+
+        for (ix = 0; ix < NumPorts; ++ix)
+        {
+            PortData = HubExtension->PortData + ix;
+
+            PortDevice = PortData->DeviceObject;
+
+            if (PortDevice)
+            {
+                PortData->PortStatus.AsULONG = 0;
+                PortData->DeviceObject = NULL;
+
+                PortExtension = PortDevice->DeviceExtension;
+                PortExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT;
+
+                USBH_PdoRemoveDevice(PortExtension, HubExtension);
+            }
+        }
+    }
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
+    {
+        USBH_FdoCleanup(HubExtension);
+    }
+
+    if (HubExtension->PortData)
+    {
+        ExFreePoolWithTag(HubExtension->PortData, USB_HUB_TAG);
+        HubExtension->PortData = NULL;
+    }
+
+    DPRINT1("USBH_FdoRemoveDevice: call IoWMIRegistrationControl UNIMPLEMENTED. FIXME\n");
+
+    Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+
+    IoDetachDevice(HubExtension->LowerDevice);
+    IoDeleteDevice(HubExtension->Common.SelfDevice);
+
+    return Status;
+}
+
+VOID
+NTAPI
+USBH_FdoSurpriseRemoveDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                             IN PIRP Irp)
+{
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    PUSBHUB_PORT_DATA PortData;
+    ULONG NumberPorts;
+    ULONG Port;
+
+    DPRINT("USBH_FdoSurpriseRemoveDevice: HubExtension - %p, Irp - %p\n",
+           HubExtension,
+           Irp);
+
+    if (!HubExtension->PortData ||
+        !HubExtension->HubDescriptor)
+    {
+        return;
+    }
+
+    PortData = HubExtension->PortData;
+    NumberPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+
+    for (Port = 0; Port < NumberPorts; Port++)
+    {
+        if (PortData[Port].DeviceObject)
+        {
+            PortExtension = PdoExt(PortData[Port].DeviceObject);
+            PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_DELETE_PENDING;
+            PortExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT;
+
+            PortData[Port].DeviceObject = NULL;
+            PortData[Port].ConnectionStatus = NoDeviceConnected;
+        }
+    }
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoQueryId(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+                IN PIRP Irp)
+{
+    ULONG IdType;
+    WCHAR Buffer[200];
+    PWCHAR EndBuffer;
+    size_t Remaining = sizeof(Buffer);
+    ULONG Length;
+    PWCHAR Id = NULL;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;
+    PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+
+    IdType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryId.IdType;
+    DeviceDescriptor = &PortExtension->DeviceDescriptor;
+    InterfaceDescriptor = &PortExtension->InterfaceDescriptor;
+
+    RtlZeroMemory(Buffer, sizeof(Buffer));
+
+    switch (IdType)
+    {
+        case BusQueryDeviceID:
+            DPRINT("USBH_PdoQueryId: BusQueryDeviceID\n");
+
+            if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
+            {
+                RtlStringCbPrintfExW(Buffer,
+                                     Remaining,
+                                     NULL,
+                                     &Remaining,
+                                     0,
+                                     L"USB\\Vid_0000&Pid0000");
+            }
+            else
+            {
+                RtlStringCbPrintfExW(Buffer,
+                                     Remaining,
+                                     NULL,
+                                     &Remaining,
+                                     0,
+                                     L"USB\\Vid_%04x&Pid_%04x",
+                                     DeviceDescriptor->idVendor,
+                                     DeviceDescriptor->idProduct);
+            }
+
+            Length = sizeof(Buffer) - (Remaining - sizeof(UNICODE_NULL));
+
+            Id = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
+
+            if (!Id)
+            {
+                break;
+            }
+
+            RtlCopyMemory(Id, Buffer, Length);
+            DPRINT("USBH_PdoQueryId: BusQueryDeviceID - %S\n", Id);
+            break;
+
+        case BusQueryHardwareIDs:
+            DPRINT("USBH_PdoQueryId: BusQueryHardwareIDs\n");
+
+            if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
+            {
+                RtlStringCbPrintfExW(Buffer,
+                                     Remaining,
+                                     NULL,
+                                     &Remaining,
+                                     0,
+                                     L"USB\\UNKNOWN");
+            }
+            else
+            {
+                RtlStringCbPrintfExW(Buffer,
+                                     Remaining,
+                                     &EndBuffer,
+                                     &Remaining,
+                                     0,
+                                     L"USB\\Vid_%04x&Pid_%04x&Rev_%04x",
+                                     DeviceDescriptor->idVendor,
+                                     DeviceDescriptor->idProduct,
+                                     DeviceDescriptor->bcdDevice);
+
+                EndBuffer++;
+                Remaining -= sizeof(UNICODE_NULL);
+
+                RtlStringCbPrintfExW(EndBuffer,
+                                     Remaining,
+                                     NULL,
+                                     &Remaining,
+                                     0,
+                                     L"USB\\Vid_%04x&Pid_%04x",
+                                     DeviceDescriptor->idVendor,
+                                     DeviceDescriptor->idProduct);
+            }
+
+            Length = sizeof(Buffer) - (Remaining - sizeof(UNICODE_NULL));
+
+            Id = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
+
+            if (!Id)
+            {
+                break;
+            }
+
+            RtlCopyMemory(Id, Buffer, Length);
+
+            if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
+            {
+                DPRINT("USBH_PdoQueryId: BusQueryInstanceID - %S\n", Id);
+            }
+            else
+            {
+                USBHUB_DumpingIDs(Id);
+            }
+
+            break;
+
+        case BusQueryCompatibleIDs:
+            DPRINT("USBH_PdoQueryId: BusQueryCompatibleIDs\n");
+
+            if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
+            {
+                RtlStringCbPrintfExW(Buffer,
+                                     Remaining,
+                                     NULL,
+                                     &Remaining,
+                                     0,
+                                     L"USB\\UNKNOWN");
+            }
+            else if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_MULTI_INTERFACE)
+            {
+                RtlStringCbPrintfExW(Buffer,
+                                     Remaining,
+                                     &EndBuffer,
+                                     &Remaining,
+                                     0,
+                                     L"USB\\DevClass_%02x&SubClass_%02x&Prot_%02x",
+                                     InterfaceDescriptor->bInterfaceClass,
+                                     InterfaceDescriptor->bInterfaceSubClass,
+                                     InterfaceDescriptor->bInterfaceProtocol);
+
+                EndBuffer++;
+                Remaining -= sizeof(UNICODE_NULL);
+
+                RtlStringCbPrintfExW(EndBuffer,
+                                     Remaining,
+                                     &EndBuffer,
+                                     &Remaining,
+                                     0,
+                                     L"USB\\DevClass_%02x&SubClass_%02x",
+                                     InterfaceDescriptor->bInterfaceClass,
+                                     InterfaceDescriptor->bInterfaceSubClass);
+
+                EndBuffer++;
+                Remaining -= sizeof(UNICODE_NULL);
+
+                RtlStringCbPrintfExW(EndBuffer,
+                                     Remaining,
+                                     &EndBuffer,
+                                     &Remaining,
+                                     0,
+                                     L"USB\\DevClass_%02x",
+                                     InterfaceDescriptor->bInterfaceClass);
+
+                EndBuffer++;
+                Remaining -= sizeof(UNICODE_NULL);
+
+                RtlStringCbPrintfExW(EndBuffer,
+                                     Remaining,
+                                     NULL,
+                                     &Remaining,
+                                     0,
+                                     L"USB\\COMPOSITE");
+            }
+            else
+            {
+                RtlStringCbPrintfExW(Buffer,
+                                     Remaining,
+                                     &EndBuffer,
+                                     &Remaining,
+                                     0,
+                                     L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
+                                     InterfaceDescriptor->bInterfaceClass,
+                                     InterfaceDescriptor->bInterfaceSubClass,
+                                     InterfaceDescriptor->bInterfaceProtocol);
+
+                EndBuffer++;
+                Remaining -= sizeof(UNICODE_NULL);
+
+                RtlStringCbPrintfExW(EndBuffer,
+                                     Remaining,
+                                     &EndBuffer,
+                                     &Remaining,
+                                     0,
+                                     L"USB\\Class_%02x&SubClass_%02x",
+                                     InterfaceDescriptor->bInterfaceClass,
+                                     InterfaceDescriptor->bInterfaceSubClass);
+
+                EndBuffer++;
+                Remaining -= sizeof(UNICODE_NULL);
+
+                RtlStringCbPrintfExW(EndBuffer,
+                                     Remaining,
+                                     NULL,
+                                     &Remaining,
+                                     0,
+                                     L"USB\\Class_%02x",
+                                     InterfaceDescriptor->bInterfaceClass);
+            }
+
+            Length = sizeof(Buffer) - (Remaining - sizeof(UNICODE_NULL));
+
+            Id = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
+
+            if (!Id)
+            {
+                break;
+            }
+
+            RtlCopyMemory(Id, Buffer, Length);
+
+            if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)
+            {
+                DPRINT("USBH_PdoQueryId: BusQueryInstanceID - %S\n", Id);
+            }
+            else
+            {
+                USBHUB_DumpingIDs(Id);
+            }
+
+            break;
+
+        case BusQueryInstanceID:
+            DPRINT("USBH_PdoQueryId: BusQueryInstanceID\n");
+
+            if (PortExtension->SerialNumber)
+            {
+                Id = ExAllocatePoolWithTag(PagedPool,
+                                           PortExtension->SN_DescriptorLength,
+                                           USB_HUB_TAG);
+
+                if (Id)
+                {
+                    RtlZeroMemory(Id, PortExtension->SN_DescriptorLength);
+
+                    RtlCopyMemory(Id,
+                                  PortExtension->SerialNumber,
+                                  PortExtension->SN_DescriptorLength);
+                }
+            }
+            else
+            {
+                 Length = sizeof(PortExtension->InstanceID) +
+                          sizeof(UNICODE_NULL);
+
+                 Id = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
+
+                 if (Id)
+                 {
+                     RtlZeroMemory(Id, Length);
+
+                     RtlCopyMemory(Id,
+                                   PortExtension->InstanceID,
+                                   sizeof(PortExtension->InstanceID));
+                 }
+            }
+
+            DPRINT("USBH_PdoQueryId: BusQueryInstanceID - %S\n", Id);
+            break;
+
+        default:
+            DPRINT1("USBH_PdoQueryId: unknown query id type 0x%lx\n", IdType);
+            return Irp->IoStatus.Status;
+    }
+
+    Irp->IoStatus.Information = (ULONG_PTR)Id;
+
+    if (!Id)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoQueryDeviceText(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+                        IN PIRP Irp)
+{
+    PDEVICE_OBJECT DeviceObject;
+    PIO_STACK_LOCATION IoStack;
+    DEVICE_TEXT_TYPE DeviceTextType;
+    USHORT LanguageId;
+    USHORT DefaultId;
+    PUSB_STRING_DESCRIPTOR Descriptor;
+    PWCHAR DeviceText;
+    UCHAR iProduct = 0;
+    NTSTATUS Status;
+    ULONG NumSymbols;
+    ULONG Length;
+
+    DPRINT("USBH_PdoQueryDeviceText ... \n");
+
+    DeviceObject = PortExtension->Common.SelfDevice;
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    DeviceTextType = IoStack->Parameters.QueryDeviceText.DeviceTextType;
+
+    if (DeviceTextType != DeviceTextDescription &&
+        DeviceTextType != DeviceTextLocationInformation)
+    {
+        return Irp->IoStatus.Status;
+    }
+
+    LanguageId = LANGIDFROMLCID(IoStack->Parameters.QueryDeviceText.LocaleId);
+    DefaultId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
+
+    if (!LanguageId)
+    {
+        LanguageId = DefaultId;
+    }
+
+    iProduct = PortExtension->DeviceDescriptor.iProduct;
+
+    if (PortExtension->DeviceHandle && iProduct &&
+        !PortExtension->IgnoringHwSerial &&
+        !(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED))
+    {
+        Descriptor = ExAllocatePoolWithTag(NonPagedPool,
+                                           MAXIMUM_USB_STRING_LENGTH,
+                                           USB_HUB_TAG);
+
+        if (Descriptor)
+        {
+            RtlZeroMemory(Descriptor, MAXIMUM_USB_STRING_LENGTH);
+
+            for (Status = USBH_CheckDeviceLanguage(DeviceObject, LanguageId);
+                 ; 
+                 Status = USBH_CheckDeviceLanguage(DeviceObject, DefaultId))
+            {
+                if (NT_SUCCESS(Status))
+                {
+                    Status = USBH_SyncGetStringDescriptor(DeviceObject,
+                                                          iProduct,
+                                                          LanguageId,
+                                                          Descriptor,
+                                                          MAXIMUM_USB_STRING_LENGTH,
+                                                          NULL,
+                                                          TRUE);
+
+                    if (NT_SUCCESS(Status))
+                    {
+                        break;
+                    }
+                }
+
+                if (LanguageId == DefaultId)
+                {
+                    goto Exit;
+                }
+
+                LanguageId = DefaultId;
+            }
+
+            if (Descriptor->bLength <= sizeof(USB_COMMON_DESCRIPTOR))
+            {
+                Status = STATUS_UNSUCCESSFUL;
+            }
+
+            if (NT_SUCCESS(Status))
+            {
+                Length = Descriptor->bLength -
+                         FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString);
+
+                DeviceText = ExAllocatePoolWithTag(PagedPool,
+                                                   Length + sizeof(UNICODE_NULL),
+                                                   USB_HUB_TAG);
+
+                if (DeviceText)
+                {
+                    RtlZeroMemory(DeviceText, Length + sizeof(UNICODE_NULL));
+
+                    RtlCopyMemory(DeviceText, Descriptor->bString, Length);
+
+                    Irp->IoStatus.Information = (ULONG_PTR)DeviceText;
+
+                    DPRINT("USBH_PdoQueryDeviceText: Descriptor->bString - %S\n",
+                           DeviceText);
+                }
+                else
+                {
+                    Status = STATUS_INSUFFICIENT_RESOURCES;
+                }
+            }
+
+        Exit:
+
+            ExFreePoolWithTag(Descriptor, USB_HUB_TAG);
+
+            if (NT_SUCCESS(Status))
+            {
+                return Status;
+            }
+        }
+        else
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+        }
+    }
+    else
+    {
+        Status = STATUS_NOT_SUPPORTED;
+    }
+
+    if (!GenericUSBDeviceString)
+    {
+        return Status;
+    }
+
+    NumSymbols = wcslen(GenericUSBDeviceString);
+    Length = (NumSymbols + 1) * sizeof(WCHAR);
+
+    DeviceText = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
+
+    if (!DeviceText)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(DeviceText, Length);
+
+    RtlCopyMemory(DeviceText,
+                  GenericUSBDeviceString,
+                  NumSymbols * sizeof(WCHAR));
+
+    Irp->IoStatus.Information = (ULONG_PTR)DeviceText;
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+USBH_SymbolicLink(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+                  IN const GUID * InterfaceClassGuid,
+                  IN BOOLEAN IsEnable)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    PVOID NameBuffer;
+
+    DPRINT("USBH_SymbolicLink ... \n");
+
+    if (IsEnable)
+    {
+        Status = IoRegisterDeviceInterface(PortExtension->Common.SelfDevice,
+                                           InterfaceClassGuid,
+                                           NULL,
+                                           &PortExtension->SymbolicLinkName);
+
+        if (NT_SUCCESS(Status))
+        {
+            USBH_SetPdoRegistryParameter(PortExtension->Common.SelfDevice,
+                                         L"SymbolicName",
+                                         PortExtension->SymbolicLinkName.Buffer,
+                                         PortExtension->SymbolicLinkName.Length,
+                                         REG_SZ,
+                                         PLUGPLAY_REGKEY_DEVICE);
+
+            Status = IoSetDeviceInterfaceState(&PortExtension->SymbolicLinkName,
+                                               TRUE);
+        }
+    }
+    else
+    {
+        NameBuffer = PortExtension->SymbolicLinkName.Buffer;
+
+        if (NameBuffer)
+        {
+            Status = IoSetDeviceInterfaceState(&PortExtension->SymbolicLinkName,
+                                               FALSE);
+
+            ExFreePool(PortExtension->SymbolicLinkName.Buffer);
+
+            PortExtension->SymbolicLinkName.Buffer = NULL;
+        }
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_RestoreDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+                   IN BOOLEAN IsKeepDeviceData)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    PUSBHUB_PORT_DATA PortData;
+    NTSTATUS Status;
+    ULONG ix;
+
+    DPRINT("USBH_RestoreDevice ... \n");
+
+    HubExtension = PortExtension->HubExtension;
+
+    if (!HubExtension)
+    {
+        Status = STATUS_UNSUCCESSFUL;
+        return Status;
+    }
+
+    ASSERT(PortExtension->PortNumber > 0);
+    PortData = &HubExtension->PortData[PortExtension->PortNumber - 1];
+
+    if (PortExtension->Common.SelfDevice == PortData->DeviceObject)
+    {
+        Status = STATUS_UNSUCCESSFUL;
+        return Status;
+    }
+
+    Status = USBH_SyncGetPortStatus(HubExtension,
+                                    PortExtension->PortNumber,
+                                    &PortData->PortStatus,
+                                    sizeof(USBHUB_PORT_STATUS));
+
+    if (NT_SUCCESS(Status))
+    {
+        for (ix = 0; ix < 3; ix++)
+        {
+            Status = USBH_ResetDevice((PUSBHUB_FDO_EXTENSION)HubExtension,
+                                      PortExtension->PortNumber,
+                                      IsKeepDeviceData,
+                                      ix == 0);
+
+            if (NT_SUCCESS(Status) || Status == STATUS_NO_SUCH_DEVICE)
+            {
+                break;
+            }
+
+            USBH_Wait(1000);
+        }
+    }
+
+    PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_POWER_D3;
+
+    if (NT_SUCCESS(Status))
+    {
+        PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_PORT_RESTORE_FAIL;
+    }
+    else
+    {
+        PortExtension->PortPdoFlags |= (USBHUB_PDO_FLAG_INIT_PORT_FAILED |
+                                        USBHUB_PDO_FLAG_PORT_RESTORE_FAIL);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoStartDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+                    IN PIRP Irp)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    const GUID * Guid;
+    NTSTATUS Status;
+
+    DPRINT("USBH_PdoStartDevice: PortExtension - %p\n", PortExtension);
+
+    if (!PortExtension->HubExtension &&
+        PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3)
+    {
+        PortExtension->HubExtension = PortExtension->RootHubExtension;
+    }
+
+    HubExtension = PortExtension->HubExtension;
+
+    if (HubExtension)
+    {
+        USBHUB_SetDeviceHandleData(HubExtension,
+                                   PortExtension->Common.SelfDevice,
+                                   PortExtension->DeviceHandle);
+    }
+
+    if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE)
+    {
+        Guid = &GUID_DEVINTERFACE_USB_HUB;
+    }
+    else
+    {
+        Guid = &GUID_DEVINTERFACE_USB_DEVICE;
+    }
+
+    Status = USBH_SymbolicLink(PortExtension, Guid, TRUE);
+
+    if (NT_SUCCESS(Status))
+    {
+        PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_REG_DEV_INTERFACE;
+    }
+
+    if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3)
+    {
+        Status = USBH_RestoreDevice(PortExtension, 0);
+    }
+
+    PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_DEVICE_STARTED;
+
+    PortExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
+
+    DPRINT1("USBH_PdoStartDevice: call IoWMIRegistrationControl UNIMPLEMENTED. FIXME\n");
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoRemoveDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+                     IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    PDEVICE_OBJECT PortDevice;
+    PUSBHUB_PORT_PDO_EXTENSION PortExt;
+    PUSBHUB_PORT_DATA PortData;
+    PIRP IdleNotificationIrp;
+    PIRP WakeIrp;
+    PVOID DeviceHandle;
+    PDEVICE_OBJECT Pdo;
+    PVOID SerialNumber;
+    USHORT Port;
+    KIRQL Irql;
+
+    DPRINT("USBH_PdoRemoveDevice ... \n");
+
+    PortDevice = PortExtension->Common.SelfDevice;
+    PortExtension->HubExtension = NULL;
+
+    Port = PortExtension->PortNumber;
+    ASSERT(Port > 0);
+
+    ASSERT(HubExtension);
+
+    if (HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0 &&
+        (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) != 0)
+    {
+        USBH_HubSetD0(HubExtension);
+    }
+
+    IoAcquireCancelSpinLock(&Irql);
+    IdleNotificationIrp = PortExtension->IdleNotificationIrp;
+
+    if (IdleNotificationIrp)
+    {
+        PortExtension->IdleNotificationIrp = NULL;
+        PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_IDLE_NOTIFICATION;
+
+        if (IdleNotificationIrp->Cancel)
+        {
+            IdleNotificationIrp = NULL;
+        }
+
+        if (IdleNotificationIrp)
+        {
+            IoSetCancelRoutine(IdleNotificationIrp, NULL);
+        }
+    }
+
+    WakeIrp = PortExtension->PdoWaitWakeIrp;
+
+    if (WakeIrp)
+    {
+        PortExtension->PdoWaitWakeIrp = NULL;
+        PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_WAIT_WAKE;
+
+        if (WakeIrp->Cancel || !IoSetCancelRoutine(WakeIrp, NULL))
+        {
+            WakeIrp = NULL;
+
+            if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+            {
+                KeSetEvent(&HubExtension->PendingRequestEvent,
+                           EVENT_INCREMENT,
+                           FALSE);
+            }
+        }
+    }
+
+    IoReleaseCancelSpinLock(Irql);
+
+    if (IdleNotificationIrp)
+    {
+        IdleNotificationIrp->IoStatus.Status = STATUS_CANCELLED;
+        IoCompleteRequest(IdleNotificationIrp, IO_NO_INCREMENT);
+    }
+
+    if (WakeIrp)
+    {
+        USBH_CompletePowerIrp(HubExtension, WakeIrp, STATUS_CANCELLED);
+    }
+
+    PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_POWER_D3;
+
+    if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REG_DEV_INTERFACE)
+    {
+        Status = USBH_SymbolicLink(PortExtension, NULL, FALSE);
+
+        if (NT_SUCCESS(Status))
+        {
+            PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REG_DEV_INTERFACE;
+        }
+    }
+
+    DeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
+                                              NULL);
+
+    if (DeviceHandle)
+    {
+        Status = USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
+
+        if (HubExtension->PortData &&
+            HubExtension->PortData[Port - 1].DeviceObject == PortDevice)
+        {
+            USBH_SyncDisablePort(HubExtension, Port);
+        }
+    }
+
+    if (NT_SUCCESS(Status))
+    {
+        PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_DEVICE_STARTED;
+
+        if (HubExtension->PortData)
+        {
+            PortData = &HubExtension->PortData[Port - 1];
+
+            if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_DELETE_PENDING)
+            {
+                Pdo = PortData->DeviceObject;
+
+                if (Pdo)
+                {
+                    PortData->DeviceObject = NULL;
+                    PortData->ConnectionStatus = NoDeviceConnected;
+
+                    if (PdoExt(Pdo)->EnumFlags & USBHUB_ENUM_FLAG_DEVICE_PRESENT)
+                    {
+                        PortExt = PdoExt(Pdo);
+
+                        InsertTailList(&HubExtension->PdoList,
+                                       &PortExt->PortLink);
+                    }
+                }
+            }
+        }
+
+        if (!(PortExtension->EnumFlags & USBHUB_ENUM_FLAG_DEVICE_PRESENT) &&
+            !(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_NOT_CONNECTED))
+        {
+            PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_NOT_CONNECTED;
+
+            SerialNumber = InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber,
+                                                      NULL);
+
+            if (SerialNumber)
+            {
+                ExFreePoolWithTag(SerialNumber, USB_HUB_TAG);
+            }
+
+            DPRINT1("USBH_PdoRemoveDevice: call IoWMIRegistrationControl UNIMPLEMENTED. FIXME\n");
+
+            USBHUB_FlushAllTransfers(HubExtension);
+
+            IoDeleteDevice(PortDevice);
+        }
+    }
+
+    DPRINT("USBH_PdoRemoveDevice: call USBH_CheckIdleDeferred()\n");
+    USBH_CheckIdleDeferred(HubExtension);
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoStopDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+                   IN PIRP Irp)
+{
+    DPRINT1("USBH_PdoStopDevice: UNIMPLEMENTED. FIXME\n");
+    DbgBreakPoint();
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoPnP(IN PUSBHUB_FDO_EXTENSION HubExtension,
+            IN PIRP Irp,
+            IN UCHAR Minor)
+{
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IoStack;
+    DEVICE_RELATION_TYPE RelationsType;
+    BOOLEAN IsCheckIdle;
+
+    DPRINT_PNP("USBH_FdoPnP: HubExtension - %p, Irp - %p, Minor - %X\n",
+               HubExtension,
+               Irp,
+               Minor);
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST &&
+        (Minor == IRP_MN_REMOVE_DEVICE || Minor == IRP_MN_STOP_DEVICE))
+    {
+        HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_SUSPENDED;
+    }
+
+    KeWaitForSingleObject(&HubExtension->IdleSemaphore,
+                          Executive,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    DPRINT_PNP("USBH_FdoPnP: HubFlags - %lX\n", HubExtension->HubFlags);
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_GOING_IDLE)
+    {
+        HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_SUSPENDED;
+    }
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    RelationsType = IoStack->Parameters.QueryDeviceRelations.Type;
+
+    if ((HubExtension->CurrentPowerState.DeviceState == PowerDeviceD0) ||
+        !(HubExtension->HubFlags & (USBHUB_FDO_FLAG_DEVICE_STOPPED | USBHUB_FDO_FLAG_DEVICE_STARTED)) ||
+        (Minor == IRP_MN_QUERY_DEVICE_RELATIONS && RelationsType == TargetDeviceRelation))
+    {
+        IsCheckIdle = FALSE;
+    }
+    else
+    {
+        DPRINT_PNP("USBH_FdoPnP: IsCheckIdle - TRUE\n");
+        IsCheckIdle = TRUE;
+        USBH_HubSetD0(HubExtension);
+    }
+
+    switch (Minor)
+    {
+        case IRP_MN_START_DEVICE:
+            DPRINT_PNP("FDO IRP_MN_START_DEVICE\n");
+            IsCheckIdle = FALSE;
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            Status = USBH_FdoStartDevice(HubExtension, Irp);
+            break;
+
+        case IRP_MN_QUERY_REMOVE_DEVICE:
+            DPRINT_PNP("FDO IRP_MN_QUERY_REMOVE_DEVICE\n");
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_REMOVE_DEVICE:
+            DPRINT_PNP("FDO IRP_MN_REMOVE_DEVICE\n");
+            IsCheckIdle = FALSE;
+            HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_REMOVED;
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            Status = USBH_FdoRemoveDevice(HubExtension, Irp);
+            break;
+
+        case IRP_MN_CANCEL_REMOVE_DEVICE:
+            DPRINT_PNP("FDO IRP_MN_CANCEL_REMOVE_DEVICE\n");
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_STOP_DEVICE:
+            DPRINT_PNP("FDO IRP_MN_STOP_DEVICE\n");
+            IsCheckIdle = FALSE;
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            Status = USBH_FdoStopDevice(HubExtension, Irp);
+            break;
+
+        case IRP_MN_QUERY_STOP_DEVICE:
+            DPRINT_PNP("FDO IRP_MN_QUERY_STOP_DEVICE\n");
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_CANCEL_STOP_DEVICE:
+            DPRINT_PNP("FDO IRP_MN_CANCEL_STOP_DEVICE\n");
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_QUERY_DEVICE_RELATIONS:
+            DPRINT_PNP("FDO IRP_MN_QUERY_DEVICE_RELATIONS\n");
+
+            if (RelationsType != BusRelations)
+            {
+                Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+                break;
+            }
+
+            HubExtension->HubFlags |= USBHUB_FDO_FLAG_HUB_BUSY;
+
+            IsCheckIdle = TRUE;
+            DPRINT_PNP("USBH_FdoPnP: IsCheckIdle - TRUE\n");
+
+            Status = USBH_FdoQueryBusRelations(HubExtension, Irp);
+
+            HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_HUB_BUSY;
+            break;
+
+        case IRP_MN_QUERY_INTERFACE:
+            DPRINT_PNP("FDO IRP_MN_QUERY_INTERFACE\n");
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_QUERY_CAPABILITIES:
+            DPRINT_PNP("FDO IRP_MN_QUERY_CAPABILITIES\n");
+            IoCopyCurrentIrpStackLocationToNext(Irp);
+
+            IoSetCompletionRoutine(Irp,
+                                   USBH_QueryCapsComplete,
+                                   HubExtension,
+                                   TRUE,
+                                   FALSE,
+                                   FALSE);
+
+            Status = IoCallDriver(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_QUERY_RESOURCES:
+            DPRINT_PNP("FDO IRP_MN_QUERY_RESOURCES\n");
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
+            DPRINT_PNP("FDO IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_QUERY_DEVICE_TEXT:
+            DPRINT_PNP("FDO IRP_MN_QUERY_DEVICE_TEXT\n");
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
+            DPRINT_PNP("FDO IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_READ_CONFIG:
+            DPRINT_PNP("FDO IRP_MN_READ_CONFIG\n");
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_WRITE_CONFIG:
+            DPRINT_PNP("FDO IRP_MN_WRITE_CONFIG\n");
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_EJECT:
+            DPRINT_PNP("FDO IRP_MN_EJECT\n");
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_SET_LOCK:
+            DPRINT_PNP("FDO IRP_MN_SET_LOCK\n");
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_QUERY_ID:
+            DPRINT_PNP("FDO IRP_MN_QUERY_ID\n");
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_QUERY_PNP_DEVICE_STATE:
+            DPRINT_PNP("FDO IRP_MN_QUERY_PNP_DEVICE_STATE\n");
+
+            if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED)
+            {
+                Irp->IoStatus.Information |= PNP_DEVICE_FAILED;
+            }
+
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_QUERY_BUS_INFORMATION:
+            DPRINT_PNP("FDO IRP_MN_QUERY_BUS_INFORMATION\n");
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_DEVICE_USAGE_NOTIFICATION:
+            DPRINT_PNP("FDO IRP_MN_DEVICE_USAGE_NOTIFICATION\n");
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        case IRP_MN_SURPRISE_REMOVAL:
+            DPRINT_PNP("FDO IRP_MN_SURPRISE_REMOVAL\n");
+            USBH_FdoSurpriseRemoveDevice(HubExtension, Irp);
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+
+        default:
+            DPRINT_PNP("FDO unknown IRP_MN_???\n");
+            Status = USBH_PassIrp(HubExtension->LowerDevice, Irp);
+            break;
+    }
+
+    KeReleaseSemaphore(&HubExtension->IdleSemaphore,
+                       LOW_REALTIME_PRIORITY,
+                       1,
+                       FALSE);
+
+    if (IsCheckIdle)
+    {
+        DPRINT_PNP("USBH_FdoPnP: call USBH_CheckIdleDeferred()\n");
+        USBH_CheckIdleDeferred(HubExtension);
+    }
+
+    HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_STATE_CHANGING;
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoPnP(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+            IN PIRP Irp,
+            IN UCHAR Minor,
+            OUT BOOLEAN * IsCompleteIrp)
+{
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IoStack;
+    PPNP_BUS_INFORMATION BusInfo;
+    PDEVICE_CAPABILITIES DeviceCapabilities;
+    USHORT Size;
+    USHORT Version;
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    PDEVICE_RELATIONS DeviceRelation;
+
+    DPRINT_PNP("USBH_PdoPnP: PortExtension - %p, Irp - %p, Minor - %X\n",
+               PortExtension,
+               Irp,
+               Minor);
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    *IsCompleteIrp = TRUE;
+
+    switch (Minor)
+    {
+        case IRP_MN_START_DEVICE:
+            DPRINT_PNP("PDO IRP_MN_START_DEVICE\n");
+            return USBH_PdoStartDevice(PortExtension, Irp);
+
+        case IRP_MN_QUERY_REMOVE_DEVICE:
+            DPRINT_PNP("PDO IRP_MN_QUERY_REMOVE_DEVICE\n");
+            return STATUS_SUCCESS;
+
+        case IRP_MN_REMOVE_DEVICE:
+            DPRINT_PNP("PDO IRP_MN_REMOVE_DEVICE\n");
+            return USBH_PdoRemoveDevice(PortExtension, PortExtension->HubExtension);
+
+        case IRP_MN_CANCEL_REMOVE_DEVICE:
+            DPRINT_PNP("PDO IRP_MN_CANCEL_REMOVE_DEVICE\n");
+            return STATUS_SUCCESS;
+
+        case IRP_MN_STOP_DEVICE:
+            DPRINT_PNP("PDO IRP_MN_STOP_DEVICE\n");
+            return USBH_PdoStopDevice(PortExtension, Irp);
+
+        case IRP_MN_QUERY_STOP_DEVICE:
+            DPRINT_PNP("PDO IRP_MN_QUERY_STOP_DEVICE\n");
+            return STATUS_SUCCESS;
+
+        case IRP_MN_CANCEL_STOP_DEVICE:
+            DPRINT_PNP("PDO IRP_MN_CANCEL_STOP_DEVICE\n");
+            return STATUS_SUCCESS;
+
+        case IRP_MN_QUERY_DEVICE_RELATIONS:
+            DPRINT_PNP("PDO IRP_MN_QUERY_DEVICE_RELATIONS\n");
+
+            if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
+            {
+                return Irp->IoStatus.Status;
+            }
+  
+            DeviceRelation = ExAllocatePoolWithTag(PagedPool,
+                                                   sizeof(DEVICE_RELATIONS),
+                                                   USB_HUB_TAG);
+
+            if (DeviceRelation)
+            {
+                RtlZeroMemory(DeviceRelation, sizeof(DEVICE_RELATIONS));
+
+                DeviceRelation->Count = 1;
+                DeviceRelation->Objects[0] = PortExtension->Common.SelfDevice;
+
+                ObReferenceObject(DeviceRelation->Objects[0]);
+
+                Status = STATUS_SUCCESS;
+            }
+            else
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+            }
+  
+            Irp->IoStatus.Information = (ULONG_PTR)DeviceRelation;
+            break;
+
+        case IRP_MN_QUERY_INTERFACE:
+            DPRINT_PNP("PDO IRP_MN_QUERY_INTERFACE\n");
+
+            *IsCompleteIrp = 0;
+
+            if (IsEqualGUIDAligned(IoStack->Parameters.QueryInterface.InterfaceType,
+                                   &USB_BUS_INTERFACE_USBDI_GUID))
+            {
+                IoStack->Parameters.QueryInterface.InterfaceSpecificData = PortExtension->DeviceHandle;
+            }
+
+            HubExtension = PortExtension->HubExtension;
+
+            if (!HubExtension)
+            {
+                HubExtension = PortExtension->RootHubExtension;
+            }
+
+            Status = USBH_PassIrp(HubExtension->RootHubPdo, Irp);
+            break;
+
+        case IRP_MN_QUERY_CAPABILITIES:
+            DPRINT_PNP("PDO IRP_MN_QUERY_CAPABILITIES\n");
+
+            DeviceCapabilities = IoStack->Parameters.DeviceCapabilities.Capabilities;
+
+            Size = DeviceCapabilities->Size;
+            Version = DeviceCapabilities->Version;
+
+            RtlCopyMemory(DeviceCapabilities,
+                          &PortExtension->Capabilities,
+                          sizeof(DEVICE_CAPABILITIES));
+
+            DeviceCapabilities->Size = Size;
+            DeviceCapabilities->Version = Version;
+
+            Status = STATUS_SUCCESS;
+            break;
+
+        case IRP_MN_QUERY_RESOURCES:
+            DPRINT_PNP("PDO IRP_MN_QUERY_RESOURCES\n");
+            Status = Irp->IoStatus.Status;
+            break;
+
+        case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
+            DPRINT_PNP("PDO IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
+            PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_ENUMERATED;
+
+            /* FIXME HKEY_LOCAL_MACHINE\SYSTEM\ControlSetXXX\Enum\USB\
+               Vid_????&Pid_????\????????????\Device Parameters\
+               if (ExtPropDescSemaphore)
+            */
+
+            Status = STATUS_SUCCESS;
+            break;
+
+        case IRP_MN_QUERY_DEVICE_TEXT:
+            DPRINT_PNP("PDO IRP_MN_QUERY_DEVICE_TEXT\n");
+            return USBH_PdoQueryDeviceText(PortExtension, Irp);
+
+        case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
+            DPRINT_PNP("PDO IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
+            Status = Irp->IoStatus.Status;
+            break;
+
+        case IRP_MN_READ_CONFIG:
+            DPRINT_PNP("PDO IRP_MN_READ_CONFIG\n");
+            DbgBreakPoint();
+            Status = Irp->IoStatus.Status;
+            break;
+
+        case IRP_MN_WRITE_CONFIG:
+            DPRINT_PNP("PDO IRP_MN_WRITE_CONFIG\n");
+            DbgBreakPoint();
+            Status = Irp->IoStatus.Status;
+            break;
+
+        case IRP_MN_EJECT:
+            DPRINT_PNP("PDO IRP_MN_EJECT\n");
+            DbgBreakPoint();
+            Status = Irp->IoStatus.Status;
+            break;
+
+        case IRP_MN_SET_LOCK:
+            DPRINT_PNP("PDO IRP_MN_SET_LOCK\n");
+            DbgBreakPoint();
+            Status = Irp->IoStatus.Status;
+            break;
+
+        case IRP_MN_QUERY_ID:
+            DPRINT_PNP("PDO IRP_MN_QUERY_ID\n");
+            return USBH_PdoQueryId(PortExtension, Irp);
+
+        case IRP_MN_QUERY_PNP_DEVICE_STATE:
+            DPRINT_PNP("PDO IRP_MN_QUERY_PNP_DEVICE_STATE\n");
+            if (PortExtension->PortPdoFlags & (USBHUB_PDO_FLAG_INSUFFICIENT_PWR |
+                                               USBHUB_PDO_FLAG_OVERCURRENT_PORT |
+                                               USBHUB_PDO_FLAG_PORT_RESTORE_FAIL |
+                                               USBHUB_PDO_FLAG_INIT_PORT_FAILED))
+            {
+                Irp->IoStatus.Information |= PNP_DEVICE_FAILED;
+            }
+
+            Status = STATUS_SUCCESS;
+            break;
+
+        case IRP_MN_QUERY_BUS_INFORMATION:
+            DPRINT_PNP("PDO IRP_MN_QUERY_BUS_INFORMATION\n");
+
+            BusInfo = ExAllocatePoolWithTag(PagedPool,
+                                            sizeof(PNP_BUS_INFORMATION),
+                                            USB_HUB_TAG);
+
+            if (!BusInfo)
+            {
+                return STATUS_INSUFFICIENT_RESOURCES;
+            }
+
+            RtlZeroMemory(BusInfo, sizeof(PNP_BUS_INFORMATION));
+
+            RtlCopyMemory(&BusInfo->BusTypeGuid,
+                          &GUID_BUS_TYPE_USB,
+                          sizeof(BusInfo->BusTypeGuid));
+
+            BusInfo->LegacyBusType = PNPBus;
+            BusInfo->BusNumber = 0;
+
+            Irp->IoStatus.Information = (ULONG_PTR)BusInfo;
+            Status = STATUS_SUCCESS;
+            break;
+
+        case IRP_MN_DEVICE_USAGE_NOTIFICATION:
+            DPRINT_PNP("PDO IRP_MN_DEVICE_USAGE_NOTIFICATION\n");
+            DbgBreakPoint();
+            Status = Irp->IoStatus.Status;
+            break;
+
+        case IRP_MN_SURPRISE_REMOVAL:
+            DPRINT_PNP("PDO IRP_MN_SURPRISE_REMOVAL\n");
+            if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REG_DEV_INTERFACE)
+            {
+                Status = USBH_SymbolicLink(PortExtension, NULL, FALSE);
+
+                if (NT_SUCCESS(Status))
+                {
+                    PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REG_DEV_INTERFACE;
+                }
+            }
+
+            Status = STATUS_SUCCESS;
+            break;
+
+        default:
+            DPRINT_PNP("PDO unknown IRP_MN_???\n");
+            Status = Irp->IoStatus.Status;
+            break;
+    }
+
+    return Status;
+}