[USBHUB_NEW] Bring-in the USB Hub driver created by Vadim Galyant. GitHub PR #29...
authorAmine Khaldi <amine.khaldi@reactos.org>
Wed, 28 Jun 2017 23:23:01 +0000 (23:23 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Wed, 28 Jun 2017 23:23:01 +0000 (23:23 +0000)
svn path=/trunk/; revision=75227

reactos/drivers/usb/CMakeLists.txt
reactos/drivers/usb/usbhub_new/CMakeLists.txt [new file with mode: 0644]
reactos/drivers/usb/usbhub_new/dbg_uhub.h [new file with mode: 0644]
reactos/drivers/usb/usbhub_new/debug.c [new file with mode: 0644]
reactos/drivers/usb/usbhub_new/guid.c [new file with mode: 0644]
reactos/drivers/usb/usbhub_new/ioctl.c [new file with mode: 0644]
reactos/drivers/usb/usbhub_new/pnp.c [new file with mode: 0644]
reactos/drivers/usb/usbhub_new/power.c [new file with mode: 0644]
reactos/drivers/usb/usbhub_new/usbhub.c [new file with mode: 0644]
reactos/drivers/usb/usbhub_new/usbhub.h [new file with mode: 0644]
reactos/drivers/usb/usbhub_new/usbhub.rc [new file with mode: 0644]

index d8e07f9..d47a55c 100644 (file)
@@ -2,6 +2,7 @@ add_subdirectory(usbccgp)
 add_subdirectory(usbd)
 add_subdirectory(usbehci)
 add_subdirectory(usbhub)
 add_subdirectory(usbd)
 add_subdirectory(usbehci)
 add_subdirectory(usbhub)
+#add_subdirectory(usbhub_new)
 add_subdirectory(usbohci)
 add_subdirectory(usbport)
 add_subdirectory(usbstor)
 add_subdirectory(usbohci)
 add_subdirectory(usbport)
 add_subdirectory(usbstor)
diff --git a/reactos/drivers/usb/usbhub_new/CMakeLists.txt b/reactos/drivers/usb/usbhub_new/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a1355df
--- /dev/null
@@ -0,0 +1,22 @@
+
+add_definitions(-DDEBUG_MODE)
+include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include)
+
+list(APPEND SOURCE
+    debug.c
+    ioctl.c
+    pnp.c
+    power.c
+    usbhub.c
+    usbhub.h)
+
+add_library(usbhub SHARED
+    ${SOURCE}
+    guid.c
+    usbhub.rc)
+
+target_link_libraries(usbhub ${PSEH_LIB})
+set_module_type(usbhub kernelmodedriver)
+add_importlibs(usbhub ntoskrnl hal wmilib usbd)
+add_pch(usbhub usbhub.h SOURCE)
+add_cd_file(TARGET usbhub DESTINATION reactos/system32/drivers NO_CAB FOR all)
diff --git a/reactos/drivers/usb/usbhub_new/dbg_uhub.h b/reactos/drivers/usb/usbhub_new/dbg_uhub.h
new file mode 100644 (file)
index 0000000..03c18c1
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef DBG_UHUB_H__
+#define DBG_UHUB_H__
+
+#if DBG
+
+    #ifndef NDEBUG_USBHUB_IOCTL
+
+        #define DPRINT_IOCTL(fmt, ...) do { \
+            if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__))  \
+                DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
+        } while (0)
+
+    #else
+
+#if defined(_MSC_VER)
+        #define DPRINT_IOCTL   __noop
+#else
+        #define DPRINT_IOCTL(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+#endif
+
+    #endif
+
+    #ifndef NDEBUG_USBHUB_POWER
+
+        #define DPRINT_PWR(fmt, ...) do { \
+            if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__))  \
+                DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
+        } while (0)
+
+    #else
+
+#if defined(_MSC_VER)
+        #define DPRINT_PWR   __noop
+#else
+        #define DPRINT_PWR(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+#endif
+
+    #endif
+
+    #ifndef NDEBUG_USBHUB_PNP
+
+        #define DPRINT_PNP(fmt, ...) do { \
+            if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__))  \
+                DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
+        } while (0)
+
+    #else
+
+#if defined(_MSC_VER)
+        #define DPRINT_PNP   __noop
+#else
+        #define DPRINT_PNP(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+#endif
+
+    #endif
+
+    #ifndef NDEBUG_USBHUB_SCE
+
+        #define DPRINT_SCE(fmt, ...) do { \
+            if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__))  \
+                DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
+        } while (0)
+
+    #else
+
+#if defined(_MSC_VER)
+        #define DPRINT_SCE   __noop
+#else
+        #define DPRINT_SCE(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+#endif
+
+    #endif
+
+    #ifndef NDEBUG_USBHUB_ENUM
+
+        #define DPRINT_ENUM(fmt, ...) do { \
+            if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__))  \
+                DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
+        } while (0)
+
+    #else
+
+#if defined(_MSC_VER)
+        #define DPRINT_ENUM  __noop
+#else
+        #define DPRINT_ENUM(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+#endif
+
+    #endif
+
+#else /* not DBG */
+
+#if defined(_MSC_VER)
+    #define DPRINT_IOCTL  __noop
+    #define DPRINT_PWR    __noop
+    #define DPRINT_PNP    __noop
+    #define DPRINT_SCE    __noop
+    #define DPRINT_ENUM   __noop
+#else
+    #define DPRINT_IOCTL(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+    #define DPRINT_PWR(...)   do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+    #define DPRINT_PNP(...)   do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+    #define DPRINT_SCE(...)   do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+    #define DPRINT_ENUM(...)  do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
+#endif /* _MSC_VER */
+
+#endif /* not DBG */
+
+#endif /* DBG_UHUB_H__ */
diff --git a/reactos/drivers/usb/usbhub_new/debug.c b/reactos/drivers/usb/usbhub_new/debug.c
new file mode 100644 (file)
index 0000000..d0b4039
--- /dev/null
@@ -0,0 +1,125 @@
+#include "usbhub.h"
+
+//#define NDEBUG
+#include <debug.h>
+
+VOID
+NTAPI
+USBHUB_DumpingDeviceDescriptor(IN PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
+{
+    if (!DeviceDescriptor)
+    {
+        return;
+    }
+
+    DPRINT("Dumping Device Descriptor - %p\n", DeviceDescriptor);
+    DPRINT("bLength             - %x\n", DeviceDescriptor->bLength);
+    DPRINT("bDescriptorType     - %x\n", DeviceDescriptor->bDescriptorType);
+    DPRINT("bcdUSB              - %x\n", DeviceDescriptor->bcdUSB);
+    DPRINT("bDeviceClass        - %x\n", DeviceDescriptor->bDeviceClass);
+    DPRINT("bDeviceSubClass     - %x\n", DeviceDescriptor->bDeviceSubClass);
+    DPRINT("bDeviceProtocol     - %x\n", DeviceDescriptor->bDeviceProtocol);
+    DPRINT("bMaxPacketSize0     - %x\n", DeviceDescriptor->bMaxPacketSize0);
+    DPRINT("idVendor            - %x\n", DeviceDescriptor->idVendor);
+    DPRINT("idProduct           - %x\n", DeviceDescriptor->idProduct);
+    DPRINT("bcdDevice           - %x\n", DeviceDescriptor->bcdDevice);
+    DPRINT("iManufacturer       - %x\n", DeviceDescriptor->iManufacturer);
+    DPRINT("iProduct            - %x\n", DeviceDescriptor->iProduct);
+    DPRINT("iSerialNumber       - %x\n", DeviceDescriptor->iSerialNumber);
+    DPRINT("bNumConfigurations  - %x\n", DeviceDescriptor->bNumConfigurations);
+}
+
+VOID
+NTAPI
+USBHUB_DumpingConfiguration(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor)
+{
+    PUSB_COMMON_DESCRIPTOR Descriptor;
+    PUSB_CONFIGURATION_DESCRIPTOR cDescriptor;
+    PUSB_INTERFACE_DESCRIPTOR iDescriptor;
+    PUSB_ENDPOINT_DESCRIPTOR eDescriptor;
+
+    if (!ConfigDescriptor)
+    {
+        return;
+    }
+
+    Descriptor = (PUSB_COMMON_DESCRIPTOR)ConfigDescriptor;
+
+    while ((ULONG_PTR)Descriptor < 
+           ((ULONG_PTR)ConfigDescriptor + ConfigDescriptor->wTotalLength) &&
+           Descriptor->bLength)
+    {
+        if (Descriptor->bDescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE)
+        {
+            cDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)Descriptor;
+
+            DPRINT("Dumping cDescriptor - %p\n", cDescriptor);
+            DPRINT("bLength             - %x\n", cDescriptor->bLength);
+            DPRINT("bDescriptorType     - %x\n", cDescriptor->bDescriptorType);
+            DPRINT("wTotalLength        - %x\n", cDescriptor->wTotalLength);
+            DPRINT("bNumInterfaces      - %x\n", cDescriptor->bNumInterfaces);
+            DPRINT("bConfigurationValue - %x\n", cDescriptor->bConfigurationValue);
+            DPRINT("iConfiguration      - %x\n", cDescriptor->iConfiguration);
+            DPRINT("bmAttributes        - %x\n", cDescriptor->bmAttributes);
+            DPRINT("MaxPower            - %x\n", cDescriptor->MaxPower);
+        }
+        else if (Descriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
+        {
+            iDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Descriptor;
+
+            DPRINT("Dumping iDescriptor - %p\n", iDescriptor);
+            DPRINT("bLength             - %x\n", iDescriptor->bLength);
+            DPRINT("bDescriptorType     - %x\n", iDescriptor->bDescriptorType);
+            DPRINT("bInterfaceNumber    - %x\n", iDescriptor->bInterfaceNumber);
+            DPRINT("bAlternateSetting   - %x\n", iDescriptor->bAlternateSetting);
+            DPRINT("bNumEndpoints       - %x\n", iDescriptor->bNumEndpoints);
+            DPRINT("bInterfaceClass     - %x\n", iDescriptor->bInterfaceClass);
+            DPRINT("bInterfaceSubClass  - %x\n", iDescriptor->bInterfaceSubClass);
+            DPRINT("bInterfaceProtocol  - %x\n", iDescriptor->bInterfaceProtocol);
+            DPRINT("iInterface          - %x\n", iDescriptor->iInterface);
+        }
+        else if (Descriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE)
+        {
+            eDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Descriptor;
+
+            DPRINT("Dumping Descriptor  - %p\n", eDescriptor);
+            DPRINT("bLength             - %x\n", eDescriptor->bLength);
+            DPRINT("bDescriptorType     - %x\n", eDescriptor->bDescriptorType);
+            DPRINT("bEndpointAddress    - %x\n", eDescriptor->bEndpointAddress);
+            DPRINT("bmAttributes        - %x\n", eDescriptor->bmAttributes);
+            DPRINT("wMaxPacketSize      - %x\n", eDescriptor->wMaxPacketSize);
+            DPRINT("bInterval           - %x\n", eDescriptor->bInterval);
+        }
+        else
+        {
+            DPRINT("bDescriptorType - %x\n", Descriptor->bDescriptorType);
+        }
+
+        Descriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)Descriptor +
+                                              Descriptor->bLength);
+    }
+}
+
+VOID
+NTAPI
+USBHUB_DumpingIDs(IN PVOID Id)
+{
+    PWSTR Ptr;
+    ULONG Length;
+    ULONG TotalLength = 0;
+
+    Ptr = Id;
+    DPRINT("USBHUB_DumpingIDs:\n");
+
+    while (*Ptr)
+    {
+        DPRINT("  %S\n", Ptr);
+        Length = wcslen(Ptr) + 1;
+
+        Ptr += Length;
+        TotalLength += Length;
+    }
+
+    DPRINT("TotalLength: %hu\n", TotalLength);
+    DPRINT("\n");
+}
diff --git a/reactos/drivers/usb/usbhub_new/guid.c b/reactos/drivers/usb/usbhub_new/guid.c
new file mode 100644 (file)
index 0000000..b6cc0a3
--- /dev/null
@@ -0,0 +1,11 @@
+/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */
+
+#include <wdm.h>
+#include <initguid.h>
+#include <wdmguid.h>
+#include <usb.h>
+#include <usbiodef.h>
+#include <hubbusif.h>
+#include <usbbusif.h>
+
+/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */
diff --git a/reactos/drivers/usb/usbhub_new/ioctl.c b/reactos/drivers/usb/usbhub_new/ioctl.c
new file mode 100644 (file)
index 0000000..fd99604
--- /dev/null
@@ -0,0 +1,1408 @@
+#include "usbhub.h"
+
+#define NDEBUG
+#include <debug.h>
+
+#define NDEBUG_USBHUB_IOCTL
+#include "dbg_uhub.h"
+
+NTSTATUS
+NTAPI
+USBH_SelectConfigOrInterfaceComplete(IN PDEVICE_OBJECT DeviceObject,
+                                     IN PIRP Irp,
+                                     IN PVOID Context)
+{
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    PVOID TimeoutContext; // PUSBHUB_BANDWIDTH_TIMEOUT_CONTEXT
+    PUSBHUB_PORT_DATA PortData = NULL;
+    NTSTATUS Status;
+    KIRQL OldIrql;
+
+    DPRINT("USBH_SelectConfigOrInterfaceComplete ... \n");
+
+    if (Irp->PendingReturned)
+    {
+        IoMarkIrpPending(Irp);
+    }
+
+    PortExtension = Context;
+    HubExtension = PortExtension->HubExtension;
+
+    ASSERT(PortExtension->PortNumber > 0);
+
+    if (HubExtension)
+    {
+        PortData = &HubExtension->PortData[PortExtension->PortNumber - 1];
+    }
+
+    Status = Irp->IoStatus.Status;
+
+    if (NT_SUCCESS(Irp->IoStatus.Status))
+    {
+        KeAcquireSpinLock(&PortExtension->PortTimeoutSpinLock, &OldIrql);
+
+        TimeoutContext = PortExtension->BndwTimeoutContext;
+
+        if (TimeoutContext)
+        {
+            DPRINT1("USBH_SelectConfigOrInterfaceComplete: TimeoutContext != NULL. FIXME\n");
+            DbgBreakPoint();
+        }
+
+        KeReleaseSpinLock(&PortExtension->PortTimeoutSpinLock, OldIrql);
+
+        PortExtension->PortPdoFlags &= ~(USBHUB_PDO_FLAG_PORT_RESTORE_FAIL |
+                                         USBHUB_PDO_FLAG_ALLOC_BNDW_FAILED);
+
+        if (PortData && PortData->ConnectionStatus != DeviceHubNestedTooDeeply)
+        {
+            PortData->ConnectionStatus = DeviceConnected;
+        }
+    }
+    else
+    {
+        DPRINT1("USBH_SelectConfigOrInterfaceComplete: Status != STATUS_SUCCESS. FIXME\n");
+        DbgBreakPoint();
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoUrbFilter(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, 
+                  IN PIRP Irp)
+{
+    PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    PDEVICE_OBJECT DeviceObject;
+    PURB Urb;
+    USHORT Function;
+    ULONG MaxPower;
+    USBD_STATUS UrbStatus;
+    BOOLEAN IsValidConfig;
+
+    HubExtension = PortExtension->HubExtension;
+    DeviceObject = PortExtension->Common.SelfDevice;
+
+    Urb = URB_FROM_IRP(Irp);
+
+    DPRINT_IOCTL("USBH_PdoUrbFilter: Device - %p, Irp - %p, Urb - %p\n",
+                 DeviceObject,
+                 Irp,
+                 Urb);
+
+    if (PortExtension->PortPdoFlags & (USBHUB_PDO_FLAG_PORT_RESTORE_FAIL |
+                                       USBHUB_PDO_FLAG_PORT_RESSETING))
+    {
+        Urb->UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER;
+        USBH_CompleteIrp(Irp, STATUS_INVALID_PARAMETER);
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Function = Urb->UrbHeader.Function;
+
+    switch (Function)
+    {
+        case URB_FUNCTION_SELECT_CONFIGURATION:
+        {
+            ConfigDescriptor = Urb->UrbSelectConfiguration.ConfigurationDescriptor;
+
+            if (ConfigDescriptor)
+            {
+                IsValidConfig = TRUE;
+
+                if (ConfigDescriptor->bDescriptorType != USB_CONFIGURATION_DESCRIPTOR_TYPE)
+                {
+                    DPRINT1("USBH_PdoUrbFilter: Not valid Cfg. bDescriptorType\n");
+                    IsValidConfig = FALSE;
+                    UrbStatus = USBD_STATUS_INVALID_CONFIGURATION_DESCRIPTOR;
+                }
+
+                if (ConfigDescriptor->bLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))
+                {
+                    DPRINT1("USBH_PdoUrbFilter: Size Cfg. descriptor is too small\n");
+                    IsValidConfig = FALSE;
+                    UrbStatus = USBD_STATUS_INVALID_CONFIGURATION_DESCRIPTOR;
+                }
+
+                if (!IsValidConfig)
+                {
+                    Urb->UrbHeader.Status = UrbStatus;
+                    USBH_CompleteIrp(Irp, STATUS_INVALID_PARAMETER);
+                    return STATUS_INVALID_PARAMETER;
+                }
+
+                MaxPower = 2 * ConfigDescriptor->MaxPower;
+                PortExtension->MaxPower = MaxPower;
+
+                if (HubExtension->MaxPowerPerPort < MaxPower)
+                {
+                    PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_INSUFFICIENT_PWR;
+
+                    DPRINT1("USBH_PdoUrbFilter: USBH_InvalidatePortDeviceState() UNIMPLEMENTED. FIXME\n");
+                    DbgBreakPoint();
+
+                    USBH_CompleteIrp(Irp, STATUS_INVALID_PARAMETER);
+                    return STATUS_INVALID_PARAMETER;
+                }
+            }
+        }
+
+        /* fall through */
+
+        case URB_FUNCTION_SELECT_INTERFACE:
+        {
+            IoCopyCurrentIrpStackLocationToNext(Irp);
+
+            IoSetCompletionRoutine(Irp,
+                                   USBH_SelectConfigOrInterfaceComplete,
+                                   PortExtension,
+                                   TRUE,
+                                   TRUE,
+                                   TRUE);
+
+            return IoCallDriver(HubExtension->RootHubPdo2, Irp);
+        }
+
+        case URB_FUNCTION_CONTROL_TRANSFER:
+        case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
+        case URB_FUNCTION_ISOCH_TRANSFER:
+        {
+            if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_DELETE_PENDING)
+            {
+                Urb->UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER;
+                USBH_CompleteIrp(Irp, STATUS_DELETE_PENDING);
+                return STATUS_DELETE_PENDING;
+            }
+
+            break;
+        }
+
+        case URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR:
+            DPRINT1("USBH_PdoUrbFilter: URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR UNIMPLEMENTED. FIXME\n");
+            USBH_CompleteIrp(Irp, STATUS_NOT_IMPLEMENTED);
+            return STATUS_NOT_IMPLEMENTED;
+
+        default:
+            break;
+    }
+
+    return USBH_PassIrp(HubExtension->RootHubPdo2, Irp);
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoIoctlSubmitUrb(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+                       IN PIRP Irp)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    PURB Urb;
+    NTSTATUS Status;
+
+    DPRINT_IOCTL("USBH_PdoIoctlSubmitUrb ... \n");
+
+    HubExtension = PortExtension->HubExtension;
+
+    Urb = URB_FROM_IRP(Irp);
+
+    if (PortExtension->DeviceHandle == NULL)
+    {
+        Urb->UrbHeader.UsbdDeviceHandle = NULL;
+        Status = USBH_PassIrp(HubExtension->RootHubPdo2, Irp);
+    }
+    else
+    {
+        Urb->UrbHeader.UsbdDeviceHandle = PortExtension->DeviceHandle;
+        Status = USBH_PdoUrbFilter(PortExtension, Irp);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoIoctlGetPortStatus(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+                           IN PIRP Irp)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    PUSBHUB_PORT_DATA PortData;
+    PIO_STACK_LOCATION IoStack;
+    PULONG PortStatus;
+    NTSTATUS Status;
+
+    DPRINT("USBH_PdoIoctlGetPortStatus ... \n");
+
+    HubExtension = PortExtension->HubExtension;
+
+    InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+    KeWaitForSingleObject(&HubExtension->HubSemaphore,
+                          Executive,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    ASSERT(PortExtension->PortNumber > 0);
+    PortData = &HubExtension->PortData[PortExtension->PortNumber - 1];
+
+    Status = USBH_SyncGetPortStatus(HubExtension,
+                                    PortExtension->PortNumber,
+                                    &PortData->PortStatus,
+                                    sizeof(USBHUB_PORT_STATUS));
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    PortStatus = IoStack->Parameters.Others.Argument1;
+
+    *PortStatus = 0;
+
+    if (PortExtension->Common.SelfDevice == PortData->DeviceObject)
+    {
+        if (PortData->PortStatus.UsbPortStatus.Usb20PortStatus.PortEnabledDisabled)
+        {
+            *PortStatus |= USBD_PORT_ENABLED;
+        }
+
+        if (PortData->PortStatus.UsbPortStatus.Usb20PortStatus.CurrentConnectStatus)
+        {
+            *PortStatus |= USBD_PORT_CONNECTED;
+        }
+    }
+
+    KeReleaseSemaphore(&HubExtension->HubSemaphore,
+                       LOW_REALTIME_PRIORITY,
+                       1,
+                       FALSE);
+
+    if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+    {
+        KeSetEvent(&HubExtension->PendingRequestEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+    }
+
+    USBH_CompleteIrp(Irp, Status);
+
+    return Status;
+}
+
+VOID
+NTAPI
+USBH_ResetPortWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                     IN PVOID Context)
+{
+    PUSBHUB_RESET_PORT_CONTEXT WorkItemReset;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    PUSB_DEVICE_HANDLE DeviceHandle;
+    NTSTATUS Status;
+    USHORT Port;
+
+    DPRINT("USBH_ResetPortWorker ... \n");
+
+    WorkItemReset = Context;
+
+    PortExtension = WorkItemReset->PortExtension;
+
+    if (!HubExtension)
+    {
+        Status = STATUS_UNSUCCESSFUL;
+        goto Exit;
+    }
+
+    InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+    KeWaitForSingleObject(&HubExtension->HubSemaphore,
+                          Executive,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    Port = PortExtension->PortNumber;
+    DeviceHandle = PortExtension->DeviceHandle;
+
+    ASSERT(Port > 0);
+
+    if (PortExtension->Common.SelfDevice == HubExtension->PortData[Port-1].DeviceObject &&
+        DeviceHandle != NULL)
+    {
+        USBD_RemoveDeviceEx(HubExtension,
+                            DeviceHandle,
+                            USBD_MARK_DEVICE_BUSY);
+
+        Status = USBH_ResetDevice(HubExtension,
+                                  Port,
+                                  TRUE,
+                                  FALSE);
+    }
+    else
+    {
+        Status = STATUS_INVALID_PARAMETER;
+    }
+
+    KeReleaseSemaphore(&HubExtension->HubSemaphore,
+                       LOW_REALTIME_PRIORITY,
+                       1,
+                       FALSE);
+
+    if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+    {
+        KeSetEvent(&HubExtension->PendingRequestEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+    }
+
+Exit:
+
+    PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_PORT_RESSETING;
+
+    USBH_CompleteIrp(WorkItemReset->Irp, Status);
+
+    WorkItemReset->PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_PORT_RESTORE_FAIL;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoIoctlResetPort(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+                       IN PIRP Irp)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    PUSBHUB_RESET_PORT_CONTEXT HubWorkItemBuffer;
+    PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
+    NTSTATUS Status;
+
+    HubExtension = PortExtension->HubExtension;
+
+    DPRINT("USBH_PdoIoctlResetPort ... \n");
+
+    if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_PORT_RESSETING)
+    {
+        Status = STATUS_UNSUCCESSFUL;
+        USBH_CompleteIrp(Irp, Status);
+        return Status;
+    }
+
+    Status = USBH_AllocateWorkItem(HubExtension,
+                                   &HubIoWorkItem,
+                                   USBH_ResetPortWorker,
+                                   sizeof(USBHUB_RESET_PORT_CONTEXT),
+                                   (PVOID *)&HubWorkItemBuffer,
+                                   DelayedWorkQueue);
+
+    if (!NT_SUCCESS(Status))
+    {
+        Status = STATUS_UNSUCCESSFUL;
+        USBH_CompleteIrp(Irp, Status);
+        return Status;
+    }
+
+    PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_PORT_RESSETING;
+    IoMarkIrpPending(Irp);
+
+    HubWorkItemBuffer->PortExtension = PortExtension;
+    HubWorkItemBuffer->Irp = Irp;
+
+    Status = STATUS_PENDING;
+
+    USBH_QueueWorkItem(PortExtension->HubExtension, HubIoWorkItem);
+
+    return Status;
+}
+
+VOID
+NTAPI
+USBH_PortIdleNotificationCancelRoutine(IN PDEVICE_OBJECT Device,
+                                       IN PIRP Irp)
+{
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    PIRP PendingIdleIrp = NULL;
+    PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
+    PUSBHUB_IDLE_PORT_CANCEL_CONTEXT HubWorkItemBuffer;
+    NTSTATUS Status;
+
+    DPRINT("USBH_PortIdleNotificationCancelRoutine ... \n");
+
+    PortExtension = Device->DeviceExtension;
+    PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_IDLE_NOTIFICATION;
+
+    HubExtension = PortExtension->HubExtension;
+    ASSERT(HubExtension);
+
+    PortExtension->IdleNotificationIrp = NULL;
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
+    {
+        PendingIdleIrp = HubExtension->PendingIdleIrp;
+        HubExtension->PendingIdleIrp = NULL;
+    }
+
+    IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+    if (PendingIdleIrp)
+    {
+        USBH_HubCancelIdleIrp(HubExtension, PendingIdleIrp);
+    }
+
+    if (HubExtension->CurrentPowerState.DeviceState == PowerDeviceD0)
+    {
+        goto ErrorExit;
+    }
+
+    Status = USBH_AllocateWorkItem(HubExtension,
+                                   &HubIoWorkItem, 
+                                   USBH_IdleCancelPowerHubWorker,
+                                   sizeof(USBHUB_IDLE_PORT_CANCEL_CONTEXT),
+                                   (PVOID *)&HubWorkItemBuffer,
+                                   DelayedWorkQueue);
+
+    if (NT_SUCCESS(Status))
+    {
+        HubWorkItemBuffer->Irp = Irp;
+        USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
+        return;
+    }
+
+ErrorExit:
+
+    Irp->IoStatus.Status = STATUS_CANCELLED;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+NTSTATUS
+NTAPI
+USBH_PortIdleNotificationRequest(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+                                 IN PIRP Irp)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    PIO_STACK_LOCATION IoStack;
+    PUSB_IDLE_CALLBACK_INFO IdleCallbackInfo;
+    NTSTATUS Status;
+    KIRQL Irql;
+
+    DPRINT("USBH_PortIdleNotificationRequest ... \n");
+
+    HubExtension = PortExtension->HubExtension;
+
+    IoAcquireCancelSpinLock(&Irql);
+
+    if (PortExtension->IdleNotificationIrp)
+    {
+        IoReleaseCancelSpinLock(Irql);
+        Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return STATUS_DEVICE_BUSY;
+    }
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    IdleCallbackInfo = IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
+
+    if (!IdleCallbackInfo || !IdleCallbackInfo->IdleCallback)
+    {
+        IoReleaseCancelSpinLock(Irql);
+
+        Status = STATUS_NO_CALLBACK_ACTIVE;
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+        return Status;
+    }
+
+    IoSetCancelRoutine(Irp, USBH_PortIdleNotificationCancelRoutine);
+
+    if (Irp->Cancel)
+    {
+        if (IoSetCancelRoutine(Irp, NULL))
+        {
+            IoReleaseCancelSpinLock(Irql);
+            Status = STATUS_CANCELLED;
+            Irp->IoStatus.Status = STATUS_CANCELLED;
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        }
+        else
+        {
+            IoMarkIrpPending(Irp);
+            IoReleaseCancelSpinLock(Irql);
+            Status = STATUS_PENDING;
+        }
+    }
+    else
+    {
+        PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_IDLE_NOTIFICATION;
+
+        PortExtension->IdleNotificationIrp = Irp;
+        IoMarkIrpPending(Irp);
+
+        IoReleaseCancelSpinLock(Irql);
+        Status = STATUS_PENDING;
+
+        DPRINT("USBH_PortIdleNotificationRequest: IdleNotificationIrp - %p\n",
+               PortExtension->IdleNotificationIrp);
+
+        USBH_CheckIdleDeferred(HubExtension);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_IoctlGetNodeName(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                      IN PIRP Irp)
+{
+    PUSB_NODE_CONNECTION_NAME ConnectionName;
+    PDEVICE_OBJECT PortDevice;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    ULONG LengthSkip;
+    PWCHAR Buffer;
+    ULONG BufferLength;
+    PWCHAR BufferEnd;
+    ULONG LengthReturned;
+    ULONG LengthName;
+    ULONG Length;
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IoStack;
+    ULONG_PTR Information;
+
+    DPRINT("USBH_IoctlGetNodeName ... \n");
+
+    Status = STATUS_SUCCESS;
+
+    ConnectionName = Irp->AssociatedIrp.SystemBuffer;
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    Length = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+    if (Length < sizeof(USB_NODE_CONNECTION_NAME))
+    {
+        Status = STATUS_BUFFER_TOO_SMALL;
+        Information = Irp->IoStatus.Information;
+        goto Exit;
+    }
+
+    if (ConnectionName->ConnectionIndex == 0 ||
+        ConnectionName->ConnectionIndex > HubExtension->HubDescriptor->bNumberOfPorts)
+    {
+        Status = STATUS_INVALID_PARAMETER;
+        Information = Irp->IoStatus.Information;
+        goto Exit;
+    }
+
+    PortDevice = HubExtension->PortData[ConnectionName->ConnectionIndex - 1].DeviceObject;
+
+    if (!PortDevice)
+    {
+        ConnectionName->NodeName[0] = 0;
+        ConnectionName->ActualLength = sizeof(USB_NODE_CONNECTION_NAME);
+
+        Information = sizeof(USB_NODE_CONNECTION_NAME);
+        goto Exit;
+    }
+
+    PortExtension = PortDevice->DeviceExtension;
+
+    if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE) ||
+        !(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_DEVICE_STARTED) ||
+        !(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REG_DEV_INTERFACE))
+    {
+        ConnectionName->NodeName[0] = 0;
+        ConnectionName->ActualLength = sizeof(USB_NODE_CONNECTION_NAME);
+
+        Information = sizeof(USB_NODE_CONNECTION_NAME);
+        goto Exit;
+    }
+
+    Buffer = PortExtension->SymbolicLinkName.Buffer;
+    BufferLength = PortExtension->SymbolicLinkName.Length;
+
+    ASSERT(Buffer[BufferLength / sizeof(WCHAR)] == UNICODE_NULL);
+
+    LengthSkip = 0;
+
+    if (*Buffer == L'\\')
+    {
+        BufferEnd = wcschr(Buffer + 1, L'\\');
+
+        if (BufferEnd != NULL)
+        {
+            LengthSkip = (BufferEnd + 1 - Buffer) * sizeof(WCHAR);
+        }
+        else
+        {
+            LengthSkip = PortExtension->SymbolicLinkName.Length;
+        }
+    }
+
+    LengthName = BufferLength - LengthSkip;
+
+    ConnectionName->ActualLength = 0;
+
+    RtlZeroMemory(ConnectionName->NodeName,
+                  Length - FIELD_OFFSET(USB_NODE_CONNECTION_NAME, NodeName));
+
+    LengthReturned = sizeof(USB_NODE_CONNECTION_NAME) + LengthName;
+
+    if (Length < LengthReturned)
+    {
+        ConnectionName->NodeName[0] = 0;
+        ConnectionName->ActualLength = LengthReturned;
+
+        Information = sizeof(USB_NODE_CONNECTION_NAME);
+        goto Exit;
+    }
+
+    RtlCopyMemory(&ConnectionName->NodeName[0],
+                  &Buffer[LengthSkip / sizeof(WCHAR)],
+                  LengthName);
+
+    ConnectionName->ActualLength = LengthReturned;
+
+    Status = STATUS_SUCCESS;
+    Information = LengthReturned;
+
+Exit:
+    Irp->IoStatus.Information = Information;
+    USBH_CompleteIrp(Irp, Status);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_IoctlGetNodeInformation(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                             IN PIRP Irp)
+{
+    PUSB_NODE_INFORMATION NodeInfo;
+    PIO_STACK_LOCATION IoStack;
+    ULONG BufferLength;
+    NTSTATUS Status;
+    BOOLEAN HubIsBusPowered;
+
+    DPRINT("USBH_IoctlGetNodeInformation ... \n");
+
+    Status = STATUS_SUCCESS;
+
+    NodeInfo = Irp->AssociatedIrp.SystemBuffer;
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+    RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, BufferLength);
+
+    if (BufferLength < sizeof(USB_NODE_INFORMATION))
+    {
+        Status = STATUS_BUFFER_TOO_SMALL;
+        USBH_CompleteIrp(Irp, Status);
+        return Status;
+    }
+
+    NodeInfo->NodeType = UsbHub;
+
+    RtlCopyMemory(&NodeInfo->u.HubInformation.HubDescriptor,
+                  HubExtension->HubDescriptor,
+                  sizeof(USB_HUB_DESCRIPTOR));
+
+    HubIsBusPowered = USBH_HubIsBusPowered(HubExtension->Common.SelfDevice,
+                                           HubExtension->HubConfigDescriptor);
+
+    NodeInfo->u.HubInformation.HubIsBusPowered = HubIsBusPowered;
+
+    Irp->IoStatus.Information = sizeof(USB_NODE_INFORMATION);
+
+    USBH_CompleteIrp(Irp, Status);
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_IoctlGetHubCapabilities(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                             IN PIRP Irp)
+{
+    PUSB_HUB_CAPABILITIES Capabilities;
+    PIO_STACK_LOCATION IoStack;
+    ULONG BufferLength;
+    ULONG Length;
+    USB_HUB_CAPABILITIES HubCaps;
+
+    DPRINT("USBH_IoctlGetHubCapabilities ... \n");
+
+    Capabilities = Irp->AssociatedIrp.SystemBuffer;
+
+    HubCaps.HubIs2xCapable = (HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB) ==
+                              USBHUB_FDO_FLAG_USB20_HUB;
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+    if (BufferLength == 0)
+    {
+        Irp->IoStatus.Information = BufferLength;
+        USBH_CompleteIrp(Irp, STATUS_INVALID_PARAMETER);
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if (BufferLength <= sizeof(HubCaps))
+    {
+        Length = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+    }
+    else
+    {
+        Length = sizeof(HubCaps);
+    }
+
+    RtlZeroMemory(Capabilities, BufferLength);
+    RtlCopyMemory(Capabilities, &HubCaps, Length);
+
+    Irp->IoStatus.Information = Length;
+
+    USBH_CompleteIrp(Irp, STATUS_SUCCESS);
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+USBH_IoctlGetNodeConnectionAttributes(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                                      IN PIRP Irp)
+{
+    PUSB_NODE_CONNECTION_ATTRIBUTES Attributes;
+    ULONG ConnectionIndex;
+    ULONG NumPorts;
+    NTSTATUS Status;
+    PUSBHUB_PORT_DATA PortData;
+    PIO_STACK_LOCATION IoStack;
+    ULONG BufferLength;
+
+    DPRINT("USBH_IoctlGetNodeConnectionAttributes ... \n");
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+    if (BufferLength < sizeof(USB_NODE_CONNECTION_ATTRIBUTES))
+    {
+        Status = STATUS_BUFFER_TOO_SMALL;
+        goto Exit;
+    }
+
+    Attributes = Irp->AssociatedIrp.SystemBuffer;
+
+    ConnectionIndex = Attributes->ConnectionIndex;
+    RtlZeroMemory(Attributes, BufferLength);
+    Attributes->ConnectionIndex = ConnectionIndex;
+
+    Status = STATUS_INVALID_PARAMETER;
+
+    NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+
+    if (NumPorts == 0 ||
+        ConnectionIndex == 0 ||
+        ConnectionIndex > NumPorts)
+    {
+        goto Exit;
+    }
+
+    PortData = HubExtension->PortData + (ConnectionIndex - 1);
+
+    Attributes->ConnectionStatus = PortData->ConnectionStatus;
+    Attributes->PortAttributes = PortData->PortAttributes;
+
+    Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_ATTRIBUTES);
+    Status = STATUS_SUCCESS;
+
+Exit:
+
+    USBH_CompleteIrp(Irp, Status);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_IoctlGetNodeConnectionInformation(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                                       IN PIRP Irp,
+                                       IN BOOLEAN IsExt)
+{
+    PUSBHUB_PORT_DATA PortData;
+    ULONG BufferLength;
+    PUSB_NODE_CONNECTION_INFORMATION_EX Info;
+    ULONG ConnectionIndex;
+    ULONG NumPorts;
+    NTSTATUS Status;
+    PDEVICE_OBJECT DeviceObject;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    PIO_STACK_LOCATION IoStack;
+
+    DPRINT("USBH_IoctlGetNodeConnectionInformation ... \n");
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+    if (BufferLength < (ULONG)FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION_EX,
+                                           PipeList))
+    {
+        Status = STATUS_BUFFER_TOO_SMALL;
+        goto Exit;
+    }
+
+    Info = Irp->AssociatedIrp.SystemBuffer;
+
+    ConnectionIndex = Info->ConnectionIndex;
+    RtlZeroMemory(Info, BufferLength);
+    Info->ConnectionIndex = ConnectionIndex;
+
+    Status = STATUS_INVALID_PARAMETER;
+
+    NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+
+    if (NumPorts == 0 ||
+        ConnectionIndex == 0 ||
+        ConnectionIndex > NumPorts)
+    {
+        goto Exit;
+    }
+
+    PortData = HubExtension->PortData + (ConnectionIndex - 1);
+    DeviceObject = PortData->DeviceObject;
+
+    if (!DeviceObject)
+    {
+        Info->ConnectionStatus = PortData->ConnectionStatus;
+
+        Irp->IoStatus.Information = FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION_EX,
+                                                 PipeList);
+        Status = STATUS_SUCCESS;
+        goto Exit;
+    }
+
+    PortExtension = DeviceObject->DeviceExtension;
+
+    Info->ConnectionStatus = PortData->ConnectionStatus;
+
+    Info->DeviceIsHub = (PortExtension->PortPdoFlags &
+                         USBHUB_PDO_FLAG_HUB_DEVICE) == 
+                         USBHUB_PDO_FLAG_HUB_DEVICE;
+
+    RtlCopyMemory(&Info->DeviceDescriptor,
+                  &PortExtension->DeviceDescriptor,
+                  sizeof(USB_DEVICE_DESCRIPTOR));
+
+    if (PortExtension->DeviceHandle)
+    {
+        Status = USBD_GetDeviceInformationEx(PortExtension,
+                                             HubExtension,
+                                             Info,
+                                             BufferLength,
+                                             PortExtension->DeviceHandle);
+    }
+    else
+    {
+        Status = STATUS_SUCCESS;
+    }
+
+    if (NT_SUCCESS(Status))
+    {
+        if (!IsExt)
+        {
+            /* IOCTL_USB_GET_NODE_CONNECTION_INFORMATION request reports
+               only low and full speed connections. Info->Speed member
+               is Info->LowSpeed in the non-EX version of the structure */
+
+            Info->Speed = (Info->Speed == UsbLowSpeed);
+        }
+
+        Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) +
+                                    (Info->NumberOfOpenPipes - 1) * sizeof(USB_PIPE_INFO);
+        goto Exit;
+    }
+
+    if (Status != STATUS_BUFFER_TOO_SMALL)
+    {
+        goto Exit;
+    }
+
+    Irp->IoStatus.Information = FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION_EX,
+                                             PipeList);
+    Status = STATUS_SUCCESS;
+
+Exit:
+    USBH_CompleteIrp(Irp, Status);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_IoctlGetNodeConnectionDriverKeyName(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                                         IN PIRP Irp)
+{
+    PUSBHUB_PORT_DATA PortData;
+    PDEVICE_OBJECT PortDevice;
+    ULONG Length;
+    ULONG ResultLength;
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IoStack;
+    ULONG BufferLength;
+    PUSB_NODE_CONNECTION_DRIVERKEY_NAME KeyName;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+
+    DPRINT("USBH_IoctlGetNodeConnectionDriverKeyName ... \n");
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+    if (BufferLength < sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME) ||
+        HubExtension->HubDescriptor->bNumberOfPorts == 0)
+    {
+        Status = STATUS_BUFFER_TOO_SMALL;
+        goto Exit;
+    }
+
+    KeyName = Irp->AssociatedIrp.SystemBuffer;
+    Status = STATUS_INVALID_PARAMETER;
+
+    PortData = &HubExtension->PortData[KeyName->ConnectionIndex - 1];
+    PortDevice = PortData->DeviceObject;
+
+    if (!PortDevice)
+    {
+        goto Exit;
+    }
+
+    PortExtension = PortDevice->DeviceExtension;
+
+    if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_ENUMERATED))
+    {
+        Status = STATUS_INVALID_DEVICE_STATE;
+        goto Exit;
+    }
+
+    ResultLength = BufferLength - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
+
+    Status = IoGetDeviceProperty(PortDevice,
+                                 DevicePropertyDriverKeyName,
+                                 BufferLength - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME),
+                                 &KeyName->DriverKeyName,
+                                 &ResultLength);
+
+    if (Status == STATUS_BUFFER_TOO_SMALL)
+    {
+        Status = STATUS_SUCCESS;
+    }
+
+    Length = ResultLength + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
+    KeyName->ActualLength = Length;
+
+    if (BufferLength < Length)
+    {
+        KeyName->DriverKeyName[0] = 0;
+        Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
+    }
+    else
+    {
+        Irp->IoStatus.Information = Length;
+    }
+
+Exit:
+    USBH_CompleteIrp(Irp, Status);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_IoctlGetDescriptor(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                        IN PIRP Irp)
+{
+    ULONG BufferLength;
+    PUSBHUB_PORT_DATA PortData;
+    PUSB_DESCRIPTOR_REQUEST UsbRequest;
+    PDEVICE_OBJECT PortDevice;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    struct _URB_CONTROL_TRANSFER * Urb;
+    NTSTATUS Status;
+    ULONG RequestBufferLength;
+    PIO_STACK_LOCATION IoStack;
+    ULONG NumPorts;
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+    DPRINT("USBH_IoctlGetDescriptor: BufferLength - %x\n", BufferLength);
+
+    if (BufferLength < sizeof(USB_DESCRIPTOR_REQUEST))
+    {
+        Status = STATUS_BUFFER_TOO_SMALL;
+        goto Exit;
+    }
+
+    UsbRequest = Irp->AssociatedIrp.SystemBuffer;
+    RequestBufferLength = UsbRequest->SetupPacket.wLength;
+
+    if (RequestBufferLength > BufferLength -
+                              FIELD_OFFSET(USB_DESCRIPTOR_REQUEST, Data))
+    {
+        DPRINT("USBH_IoctlGetDescriptor: RequestBufferLength - %x\n",
+               RequestBufferLength);
+
+        Status = STATUS_BUFFER_TOO_SMALL;
+        goto Exit;
+    }
+
+    Status = STATUS_INVALID_PARAMETER;
+
+    NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+
+    if (NumPorts == 0 ||
+        UsbRequest->ConnectionIndex == 0 ||
+        UsbRequest->ConnectionIndex > NumPorts)
+    {
+        goto Exit;
+    }
+
+    PortData = HubExtension->PortData + (UsbRequest->ConnectionIndex - 1);
+    PortDevice = PortData->DeviceObject;
+
+    if (!PortDevice)
+    {
+        goto Exit;
+    }
+
+    PortExtension = PortDevice->DeviceExtension;
+
+    if (UsbRequest->SetupPacket.bmRequest == USB_CONFIGURATION_DESCRIPTOR_TYPE &&
+        RequestBufferLength == sizeof(USB_CONFIGURATION_DESCRIPTOR))
+    {
+        Status = STATUS_SUCCESS;
+
+        RtlCopyMemory(&UsbRequest->Data[0],
+                      &PortExtension->ConfigDescriptor,
+                      sizeof(USB_CONFIGURATION_DESCRIPTOR));
+
+        Irp->IoStatus.Information = sizeof(USB_DESCRIPTOR_REQUEST) - sizeof(UCHAR) +
+                                    sizeof(USB_CONFIGURATION_DESCRIPTOR);
+        goto Exit;
+    }
+
+    Urb = ExAllocatePoolWithTag(NonPagedPool,
+                                sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+                                USB_HUB_TAG);
+
+    if (!Urb)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto Exit;
+    }
+
+    RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
+
+    Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
+    Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
+
+    Urb->TransferBuffer = &UsbRequest->Data[0];
+    Urb->TransferBufferLength = RequestBufferLength;
+    Urb->TransferBufferMDL = NULL;
+    Urb->UrbLink = NULL;
+
+    RtlCopyMemory(Urb->SetupPacket,
+                  &UsbRequest->SetupPacket,
+                  sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
+
+    Status = USBH_SyncSubmitUrb(PortExtension->Common.SelfDevice,
+                                (PURB)Urb);
+
+    Irp->IoStatus.Information = (sizeof(USB_DESCRIPTOR_REQUEST) - sizeof(UCHAR)) +
+                                Urb->TransferBufferLength;
+
+    ExFreePoolWithTag(Urb, USB_HUB_TAG);
+
+Exit:
+    USBH_CompleteIrp(Irp, Status);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_DeviceControl(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                   IN PIRP Irp)
+{
+    NTSTATUS Status = STATUS_DEVICE_BUSY;
+    PIO_STACK_LOCATION IoStack;
+    ULONG ControlCode;
+    BOOLEAN IsCheckHubIdle = FALSE; 
+
+    DPRINT("USBH_DeviceControl: HubExtension - %p, Irp - %p\n",
+           HubExtension,
+           Irp);
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
+    DPRINT("USBH_DeviceControl: ControlCode - %lX\n", ControlCode);
+
+    if ((HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0) &&
+        (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED))
+    {
+        IsCheckHubIdle = TRUE;
+        USBH_HubSetD0(HubExtension);
+    }
+
+    switch (ControlCode)
+    {
+        case IOCTL_USB_GET_HUB_CAPABILITIES:
+            DPRINT("USBH_DeviceControl: IOCTL_USB_GET_HUB_CAPABILITIES\n");
+            if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+            {
+                Status = USBH_IoctlGetHubCapabilities(HubExtension, Irp);
+                break;
+            }
+
+            USBH_CompleteIrp(Irp, Status);
+            break;
+
+        case IOCTL_USB_HUB_CYCLE_PORT:
+            DPRINT1("USBH_DeviceControl: IOCTL_USB_HUB_CYCLE_PORT UNIMPLEMENTED. FIXME\n");
+            DbgBreakPoint();
+            break;
+
+        case IOCTL_USB_GET_NODE_INFORMATION:
+            DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_INFORMATION\n");
+            if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+            {
+                Status = USBH_IoctlGetNodeInformation(HubExtension, Irp);
+                break;
+            }
+
+            USBH_CompleteIrp(Irp, Status);
+            break;
+
+        case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION:
+            DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_INFORMATION\n");
+            if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+            {
+                Status = USBH_IoctlGetNodeConnectionInformation(HubExtension,
+                                                                Irp,
+                                                                FALSE);
+                break;
+            }
+
+            USBH_CompleteIrp(Irp, Status);
+            break;
+
+        case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX:
+            DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX\n");
+            if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+            {
+                Status = USBH_IoctlGetNodeConnectionInformation(HubExtension,
+                                                                Irp,
+                                                                TRUE);
+                break;
+            }
+
+            USBH_CompleteIrp(Irp, Status);
+            break;
+
+        case IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES:
+            DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES\n");
+            if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+            {
+                Status = USBH_IoctlGetNodeConnectionAttributes(HubExtension, Irp);
+                break;
+            }
+
+            USBH_CompleteIrp(Irp, Status);
+            break;
+
+        case IOCTL_USB_GET_NODE_CONNECTION_NAME:
+            DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_NAME\n");
+            if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+            {
+                Status = USBH_IoctlGetNodeName(HubExtension, Irp);
+                break;
+            }
+
+            USBH_CompleteIrp(Irp, Status);
+            break;
+
+        case IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME:
+            DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME\n");
+            if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+            {
+                Status = USBH_IoctlGetNodeConnectionDriverKeyName(HubExtension, Irp);
+                break;
+            }
+
+            USBH_CompleteIrp(Irp, Status);
+            break;
+
+        case IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION:
+            DPRINT("USBH_DeviceControl: IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION\n");
+            if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+            {
+                Status = USBH_IoctlGetDescriptor(HubExtension, Irp);
+                break;
+            }
+
+            USBH_CompleteIrp(Irp, Status);
+            break;
+
+        case IOCTL_KS_PROPERTY:
+            DPRINT("USBH_DeviceControl: IOCTL_KS_PROPERTY\n");
+            Status = STATUS_INVALID_DEVICE_REQUEST;
+            USBH_CompleteIrp(Irp, Status);
+            break;
+
+        default:
+            DPRINT1("USBH_DeviceControl: Unhandled IOCTL_ - %lX\n", ControlCode);
+            Status = USBH_PassIrp(HubExtension->RootHubPdo, Irp);
+            break;
+    }
+
+    if (IsCheckHubIdle)
+    {
+        USBH_CheckHubIdle(HubExtension);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoInternalControl(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+                        IN PIRP Irp)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    NTSTATUS Status = STATUS_NOT_SUPPORTED;
+    ULONG ControlCode;
+    PIO_STACK_LOCATION IoStack;
+    PULONG HubCount;
+
+    DPRINT_IOCTL("USBH_PdoInternalControl: PortExtension - %p, Irp - %p\n",
+                 PortExtension,
+                 Irp);
+
+    HubExtension = PortExtension->HubExtension;
+
+    if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_NOT_CONNECTED)
+    {
+        Status = STATUS_DEVICE_NOT_CONNECTED;
+        goto Exit;
+    }
+
+    if (PortExtension->CurrentPowerState.DeviceState != PowerDeviceD0)
+    {
+        Status = STATUS_DEVICE_POWERED_OFF;
+        goto Exit;
+    }
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
+
+    if (ControlCode == IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO)
+    {
+        HubExtension = PortExtension->RootHubExtension;
+        DPRINT("USBH_PdoInternalControl: HubExtension - %p\n", HubExtension);
+    }
+
+    if (!HubExtension)
+    {
+        Status = STATUS_DEVICE_BUSY;
+        goto Exit;
+    }
+
+    switch (ControlCode)
+    {
+        case IOCTL_INTERNAL_USB_SUBMIT_URB:
+            return USBH_PdoIoctlSubmitUrb(PortExtension, Irp);
+
+        case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION:
+            DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION\n");
+            return USBH_PortIdleNotificationRequest(PortExtension, Irp);
+
+        case IOCTL_INTERNAL_USB_GET_PORT_STATUS:
+            DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_PORT_STATUS\n");
+            return USBH_PdoIoctlGetPortStatus(PortExtension, Irp);
+
+        case IOCTL_INTERNAL_USB_RESET_PORT:
+            DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_RESET_PORT\n");
+            return USBH_PdoIoctlResetPort(PortExtension, Irp);
+
+        case IOCTL_INTERNAL_USB_ENABLE_PORT:
+            DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_ENABLE_PORT\n");
+            DbgBreakPoint();
+            break;
+
+        case IOCTL_INTERNAL_USB_CYCLE_PORT:
+            DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_CYCLE_PORT\n");
+            DbgBreakPoint();
+            break;
+
+        case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE:
+            DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE\n");
+            *(PVOID *)IoStack->Parameters.Others.Argument1 = PortExtension->DeviceHandle;
+            Status = STATUS_SUCCESS;
+            break;
+
+        case IOCTL_INTERNAL_USB_GET_HUB_COUNT:
+            DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_HUB_COUNT. PortPdoFlags - %lX\n",
+                   PortExtension->PortPdoFlags);
+
+            if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+
+            HubCount = IoStack->Parameters.Others.Argument1;
+
+            ++*HubCount;
+
+            Status = USBH_SyncGetHubCount(HubExtension->LowerDevice,
+                                          HubCount);
+
+            DPRINT("USBH_PdoInternalControl: *HubCount - %x\n", *HubCount);
+            break;
+
+        case IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO:
+            DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO. PortPdoFlags - %lX\n",
+                   PortExtension->PortPdoFlags);
+
+            if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE))
+            {
+                DbgBreakPoint();
+                Status = STATUS_SUCCESS;
+
+                *(PVOID *)IoStack->Parameters.Others.Argument1 = NULL;
+
+                USBH_CompleteIrp(Irp, Status);
+                break;
+            }
+
+            ASSERT(HubExtension->RootHubPdo);
+            return USBH_PassIrp(HubExtension->RootHubPdo, Irp);
+
+        case IOCTL_INTERNAL_USB_GET_HUB_NAME:
+            DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_HUB_NAME\n");
+            DbgBreakPoint();
+            break;
+
+        case IOCTL_GET_HCD_DRIVERKEY_NAME:
+            DPRINT1("USBH_PdoInternalControl: IOCTL_GET_HCD_DRIVERKEY_NAME\n");
+            DbgBreakPoint();
+            break;
+
+        case IOCTL_INTERNAL_USB_GET_BUS_INFO:
+            DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_BUS_INFO\n");
+            DbgBreakPoint();
+            break;
+
+        case IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO:
+            DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO\n");
+            DbgBreakPoint();
+            break;
+
+        default:
+            DPRINT1("USBH_PdoInternalControl: unhandled IOCTL_ - %lX\n", ControlCode);
+            break;
+    }
+
+Exit:
+    USBH_CompleteIrp(Irp, Status);
+    return Status;
+}
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;
+}
diff --git a/reactos/drivers/usb/usbhub_new/power.c b/reactos/drivers/usb/usbhub_new/power.c
new file mode 100644 (file)
index 0000000..172e709
--- /dev/null
@@ -0,0 +1,794 @@
+#include "usbhub.h"
+
+#define NDEBUG
+#include <debug.h>
+
+#define NDEBUG_USBHUB_POWER
+#include "dbg_uhub.h"
+
+VOID
+NTAPI
+USBH_CompletePowerIrp(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                      IN PIRP Irp,
+                      IN NTSTATUS NtStatus)
+{
+    DPRINT("USBH_CompletePowerIrp: HubExtension - %p, Irp - %p, NtStatus - %lX\n",
+           HubExtension,
+           Irp,
+           NtStatus);
+
+    Irp->IoStatus.Status = NtStatus;
+
+    PoStartNextPowerIrp(Irp);
+
+    if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+    {
+        KeSetEvent(&HubExtension->PendingRequestEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+    }
+
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+VOID
+NTAPI
+USBH_HubCancelWakeIrp(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                      IN PIRP Irp)
+{
+    DPRINT("USBH_HubCancelWakeIrp: HubExtension - %p, Irp - %p\n",
+           HubExtension,
+           Irp);
+
+    IoCancelIrp(Irp);
+
+    if (InterlockedExchange((PLONG)&HubExtension->FdoWaitWakeLock, 1))
+    {
+        PoStartNextPowerIrp(Irp);
+        Irp->IoStatus.Status = STATUS_CANCELLED;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    }
+}
+
+VOID
+NTAPI
+USBH_HubESDRecoverySetD3Completion(IN PDEVICE_OBJECT DeviceObject,
+                                   IN UCHAR MinorFunction,
+                                   IN POWER_STATE PowerState,
+                                   IN PVOID Context,
+                                   IN PIO_STATUS_BLOCK IoStatus)
+{
+    DPRINT("USBH_HubESDRecoverySetD3Completion ... \n");
+
+    KeSetEvent((PRKEVENT)Context,
+               EVENT_INCREMENT,
+               FALSE);
+}
+
+NTSTATUS
+NTAPI
+USBH_HubSetD0(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    PUSBHUB_FDO_EXTENSION RootHubDevExt;
+    NTSTATUS Status;
+    KEVENT Event;
+    POWER_STATE PowerState;
+
+    DPRINT("USBH_HubSetD0: HubExtension - %p\n", HubExtension);
+
+    RootHubDevExt = USBH_GetRootHubExtension(HubExtension);
+
+    if (RootHubDevExt->SystemPowerState.SystemState != PowerSystemWorking)
+    {
+        Status = STATUS_INVALID_DEVICE_STATE;
+        return Status;
+    }
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
+    {
+        DPRINT("USBH_HubSetD0: HubFlags - %lX\n", HubExtension->HubFlags);
+
+        KeWaitForSingleObject(&HubExtension->IdleEvent,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    PowerState.DeviceState = PowerDeviceD0;
+
+    Status = PoRequestPowerIrp(HubExtension->LowerPDO,
+                               IRP_MN_SET_POWER,
+                               PowerState,
+                               USBH_HubESDRecoverySetD3Completion,
+                               &Event,
+                               NULL);
+
+    if (Status == STATUS_PENDING)
+    {
+       Status = KeWaitForSingleObject(&Event,
+                                      Suspended,
+                                      KernelMode,
+                                      FALSE,
+                                      NULL);
+    }
+
+    while (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAKEUP_START)
+    {
+        USBH_Wait(10);
+    }
+
+    return Status;
+}
+
+VOID
+NTAPI
+USBH_IdleCancelPowerHubWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                              IN PVOID Context)
+{
+    PUSBHUB_IDLE_PORT_CANCEL_CONTEXT WorkItemIdlePower;
+    PIRP Irp;
+
+    DPRINT("USBH_IdleCancelPowerHubWorker: ... \n");
+
+    WorkItemIdlePower = Context;
+
+    if (HubExtension &&
+        HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0 &&
+        HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
+    {
+        USBH_HubSetD0(HubExtension);
+    }
+
+    Irp = WorkItemIdlePower->Irp;
+    Irp->IoStatus.Status = STATUS_CANCELLED;
+
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+VOID
+NTAPI
+USBH_HubQueuePortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                          IN PLIST_ENTRY ListIrps)
+{
+    PDEVICE_OBJECT PortDevice;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    USHORT NumPorts;
+    USHORT Port;
+    PIRP WakeIrp;
+    KIRQL OldIrql;
+
+    DPRINT("USBH_HubQueuePortWakeIrps ... \n");
+
+    NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+
+    InitializeListHead(ListIrps);
+
+    IoAcquireCancelSpinLock(&OldIrql);
+
+    for (Port = 0; Port < NumPorts; ++Port)
+    {
+        PortDevice = HubExtension->PortData[Port].DeviceObject;
+
+        if (PortDevice)
+        {
+            PortExtension = PortDevice->DeviceExtension;
+
+            WakeIrp = PortExtension->PdoWaitWakeIrp;
+            PortExtension->PdoWaitWakeIrp = NULL;
+
+            if (WakeIrp)
+            {
+                DPRINT1("USBH_HubQueuePortWakeIrps: UNIMPLEMENTED. FIXME\n");
+                DbgBreakPoint();
+            }
+        }
+    }
+
+    IoReleaseCancelSpinLock(OldIrql);
+}
+
+VOID
+NTAPI
+USBH_HubCompleteQueuedPortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                                   IN PLIST_ENTRY ListIrps,
+                                   IN NTSTATUS NtStatus)
+{
+    DPRINT("USBH_HubCompleteQueuedPortWakeIrps ... \n");
+
+    while (!IsListEmpty(ListIrps))
+    {
+        DPRINT1("USBH_HubCompleteQueuedPortWakeIrps: UNIMPLEMENTED. FIXME\n");
+        DbgBreakPoint();
+    }
+}
+
+VOID
+NTAPI
+USBH_HubCompletePortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                             IN NTSTATUS NtStatus)
+{
+    LIST_ENTRY ListIrps;
+
+    DPRINT("USBH_HubCompletePortWakeIrps: NtStatus - %x\n", NtStatus);
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
+    {
+        USBH_HubQueuePortWakeIrps(HubExtension, &ListIrps);
+
+        USBH_HubCompleteQueuedPortWakeIrps(HubExtension,
+                                           &ListIrps,
+                                           NtStatus);
+    }
+}
+
+VOID
+NTAPI
+USBH_FdoPoRequestD0Completion(IN PDEVICE_OBJECT DeviceObject,
+                              IN UCHAR MinorFunction,
+                              IN POWER_STATE PowerState,
+                              IN PVOID Context,
+                              IN PIO_STATUS_BLOCK IoStatus)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+
+    DPRINT("USBH_FdoPoRequestD0Completion ... \n");
+
+    HubExtension = Context;
+
+    USBH_HubCompletePortWakeIrps(HubExtension, STATUS_SUCCESS);
+
+    HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAKEUP_START;
+
+    if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+    {
+        KeSetEvent(&HubExtension->PendingRequestEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+    }
+}
+
+VOID
+NTAPI
+USBH_CompletePortWakeIrpsWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                                IN PVOID Context)
+{
+    DPRINT1("USBH_CompletePortWakeIrpsWorker: UNIMPLEMENTED. FIXME\n");
+    DbgBreakPoint();
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoWWIrpIoCompletion(IN PDEVICE_OBJECT DeviceObject,
+                          IN PIRP Irp,
+                          IN PVOID Context)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    NTSTATUS Status;
+    KIRQL OldIrql;
+    POWER_STATE PowerState;
+    PIRP WakeIrp;
+
+    DPRINT("USBH_FdoWWIrpIoCompletion: DeviceObject - %p, Irp - %p\n",
+            DeviceObject,
+            Irp);
+
+    HubExtension = Context;
+
+    Status = Irp->IoStatus.Status;
+
+    IoAcquireCancelSpinLock(&OldIrql);
+
+    HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_PENDING_WAKE_IRP;
+
+    WakeIrp = InterlockedExchangePointer((PVOID *)&HubExtension->PendingWakeIrp,
+                                         NULL);
+
+    if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+    {
+        KeSetEvent(&HubExtension->PendingRequestEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+    }
+
+    IoReleaseCancelSpinLock(OldIrql);
+
+    DPRINT("USBH_FdoWWIrpIoCompletion: Status - %lX\n", Status);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("USBH_FdoWWIrpIoCompletion: DbgBreakPoint() \n");
+        DbgBreakPoint();
+    }
+    else
+    {
+        PowerState.DeviceState = PowerDeviceD0;
+
+        HubExtension->HubFlags |= USBHUB_FDO_FLAG_WAKEUP_START;
+        InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+        Status = STATUS_SUCCESS;
+
+        PoRequestPowerIrp(HubExtension->LowerPDO,
+                          IRP_MN_SET_POWER,
+                          PowerState,
+                          USBH_FdoPoRequestD0Completion,
+                          (PVOID)HubExtension,
+                          NULL);
+    }
+
+    if (!WakeIrp)
+    {
+        if (!InterlockedExchange(&HubExtension->FdoWaitWakeLock, 1))
+        {
+            Status = STATUS_MORE_PROCESSING_REQUIRED;
+        }
+    }
+
+    DPRINT("USBH_FdoWWIrpIoCompletion: Status - %lX\n", Status);
+
+    if (Status != STATUS_MORE_PROCESSING_REQUIRED)
+    {
+        PoStartNextPowerIrp(Irp);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject,
+                        IN PIRP Irp,
+                        IN PVOID Context)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    PIO_STACK_LOCATION IoStack;
+    DEVICE_POWER_STATE OldDeviceState;
+    NTSTATUS Status;
+    POWER_STATE PowerState;
+
+    DPRINT("USBH_PowerIrpCompletion: DeviceObject - %p, Irp - %p\n",
+           DeviceObject,
+           Irp);
+
+    HubExtension = Context;
+
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    PowerState = IoStack->Parameters.Power.State;
+
+    Status = Irp->IoStatus.Status;
+    DPRINT("USBH_PowerIrpCompletion: Status - %lX\n", Status);
+
+    if (!NT_SUCCESS(Status))
+    {
+        if (PowerState.DeviceState == PowerDeviceD0)
+        {
+            PoStartNextPowerIrp(Irp);
+            HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_SET_D0_STATE;
+        }
+    }
+    else if (PowerState.DeviceState == PowerDeviceD0)
+    {
+        HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_SET_D0_STATE;
+
+        OldDeviceState = HubExtension->CurrentPowerState.DeviceState;
+        HubExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
+
+        DPRINT("USBH_PowerIrpCompletion: OldDeviceState - %x\n", OldDeviceState);
+
+        if (HubExtension->HubFlags & USBHUB_FDO_FLAG_HIBERNATE_STATE)
+        {
+            DPRINT1("USBH_PowerIrpCompletion: USBHUB_FDO_FLAG_HIBERNATE_STATE. FIXME\n");
+            DbgBreakPoint();
+        }
+
+        HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_HIBERNATE_STATE;
+
+        if (OldDeviceState == PowerDeviceD3)
+        {
+            DPRINT1("USBH_PowerIrpCompletion: PowerDeviceD3. FIXME\n");
+            DbgBreakPoint();
+        }
+
+        if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED) &&
+            HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION)
+        {
+            USBH_SubmitStatusChangeTransfer(HubExtension);
+        }
+
+        DPRINT("USBH_PowerIrpCompletion: Status - %lX\n", Status);
+
+        if (Status != STATUS_MORE_PROCESSING_REQUIRED)
+        {
+            PoStartNextPowerIrp(Irp);
+            return Status;
+        }
+    }
+
+    return Status;
+}
+
+VOID
+NTAPI
+USBH_FdoDeferPoRequestCompletion(IN PDEVICE_OBJECT DeviceObject,
+                                 IN UCHAR MinorFunction,
+                                 IN POWER_STATE PowerState,
+                                 IN PVOID Context,
+                                 IN PIO_STATUS_BLOCK IoStatus)
+{
+    PUSBHUB_FDO_EXTENSION Extension;
+    PUSBHUB_FDO_EXTENSION HubExtension = NULL;
+    PIRP PowerIrp;
+    PIO_STACK_LOCATION IoStack;
+
+    DPRINT("USBH_FdoDeferPoRequestCompletion ... \n");
+
+    Extension = Context;
+
+    PowerIrp = Extension->PowerIrp;
+
+    if (Extension->Common.ExtensionType == USBH_EXTENSION_TYPE_HUB)
+    {
+        HubExtension = Context;
+    }
+
+    IoStack = IoGetCurrentIrpStackLocation(PowerIrp);
+
+    if (IoStack->Parameters.Power.State.SystemState == PowerSystemWorking &&
+        HubExtension && HubExtension->LowerPDO == HubExtension->RootHubPdo)
+    {
+        HubExtension->SystemPowerState.SystemState = PowerSystemWorking;
+        USBH_CheckIdleDeferred(HubExtension);
+    }
+
+    IoCopyCurrentIrpStackLocationToNext(PowerIrp);
+    PoStartNextPowerIrp(PowerIrp);
+    PoCallDriver(Extension->LowerDevice, PowerIrp);
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoPower(IN PUSBHUB_FDO_EXTENSION HubExtension,
+              IN PIRP Irp,
+              IN UCHAR Minor)
+{
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IoStack;
+    POWER_STATE PowerState;
+    POWER_STATE DevicePwrState;
+    BOOLEAN IsAllPortsD3;
+    PUSBHUB_PORT_DATA PortData;
+    PDEVICE_OBJECT PdoDevice;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    ULONG Port;
+
+    DPRINT_PWR("USBH_FdoPower: HubExtension - %p, Irp - %p, Minor - %X\n",
+               HubExtension,
+               Irp,
+               Minor);
+
+    switch (Minor)
+    {
+        case IRP_MN_WAIT_WAKE:
+            DPRINT_PWR("USBH_FdoPower: IRP_MN_WAIT_WAKE\n");
+
+            IoCopyCurrentIrpStackLocationToNext(Irp);
+
+            IoSetCompletionRoutine(Irp,
+                                   USBH_FdoWWIrpIoCompletion,
+                                   HubExtension,
+                                   TRUE,
+                                   TRUE,
+                                   TRUE);
+
+            PoStartNextPowerIrp(Irp);
+            IoMarkIrpPending(Irp);
+            PoCallDriver(HubExtension->LowerDevice, Irp);
+
+            return STATUS_PENDING;
+
+        case IRP_MN_POWER_SEQUENCE:
+            DPRINT_PWR("USBH_FdoPower: IRP_MN_POWER_SEQUENCE\n");
+            break;
+
+        case IRP_MN_SET_POWER:
+            DPRINT_PWR("USBH_FdoPower: IRP_MN_SET_POWER\n");
+
+            IoStack = IoGetCurrentIrpStackLocation(Irp);
+            DPRINT_PWR("USBH_FdoPower: IRP_MN_SET_POWER/DevicePowerState\n");
+            PowerState = IoStack->Parameters.Power.State;
+
+            if (IoStack->Parameters.Power.Type == DevicePowerState)
+            {
+                DPRINT_PWR("USBH_FdoPower: PowerState - %x\n",
+                           PowerState.DeviceState);
+
+                if (HubExtension->CurrentPowerState.DeviceState == PowerState.DeviceState)
+                {
+                    IoCopyCurrentIrpStackLocationToNext(Irp);
+
+                    PoStartNextPowerIrp(Irp);
+                    IoMarkIrpPending(Irp);
+                    PoCallDriver(HubExtension->LowerDevice, Irp);
+
+                    return STATUS_PENDING;
+                }
+
+                switch (PowerState.DeviceState)
+                {
+                    case PowerDeviceD0:
+                        if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_SET_D0_STATE))
+                        {
+                            HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_NOT_D0_STATE |
+                                                        USBHUB_FDO_FLAG_DEVICE_STOPPING);
+
+                            HubExtension->HubFlags |= USBHUB_FDO_FLAG_SET_D0_STATE;
+
+                            IoCopyCurrentIrpStackLocationToNext(Irp);
+
+                            IoSetCompletionRoutine(Irp,
+                                                   USBH_PowerIrpCompletion,
+                                                   HubExtension,
+                                                   TRUE,
+                                                   TRUE,
+                                                   TRUE);
+                        }
+                        else
+                        {
+                            IoCopyCurrentIrpStackLocationToNext(Irp);
+                            PoStartNextPowerIrp(Irp);
+                        }
+
+                        IoMarkIrpPending(Irp);
+                        PoCallDriver(HubExtension->LowerDevice, Irp);
+                        return STATUS_PENDING;
+
+                    case PowerDeviceD1:
+                    case PowerDeviceD2:
+                    case PowerDeviceD3:
+                        if (HubExtension->ResetRequestCount)
+                        {
+                            IoCancelIrp(HubExtension->ResetPortIrp);
+
+                            KeWaitForSingleObject(&HubExtension->ResetEvent,
+                                                  Executive,
+                                                  KernelMode,
+                                                  FALSE,
+                                                  NULL);
+                        }
+
+                        if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+                        {
+                            HubExtension->HubFlags |= (USBHUB_FDO_FLAG_NOT_D0_STATE |
+                                                       USBHUB_FDO_FLAG_DEVICE_STOPPING);
+
+                            IoCancelIrp(HubExtension->SCEIrp);
+
+                            KeWaitForSingleObject(&HubExtension->StatusChangeEvent,
+                                                  Executive,
+                                                  KernelMode,
+                                                  FALSE,
+                                                  NULL);
+                        }
+
+                        HubExtension->CurrentPowerState.DeviceState = PowerState.DeviceState;
+
+                        if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_SUSPENSE &&
+                            USBH_CheckIdleAbort(HubExtension, TRUE, TRUE) == TRUE)
+                        {
+                            HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_NOT_D0_STATE |
+                                                        USBHUB_FDO_FLAG_DEVICE_STOPPING);
+
+                            HubExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
+
+                            USBH_SubmitStatusChangeTransfer(HubExtension);
+
+                            PoStartNextPowerIrp(Irp);
+
+                            Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+                            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+                            HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DO_SUSPENSE;
+
+                            KeReleaseSemaphore(&HubExtension->IdleSemaphore,
+                                               LOW_REALTIME_PRIORITY,
+                                               1,
+                                               FALSE);
+
+                            return STATUS_UNSUCCESSFUL;
+                        }
+
+                        IoCopyCurrentIrpStackLocationToNext(Irp);
+
+                        IoSetCompletionRoutine(Irp,
+                                               USBH_PowerIrpCompletion,
+                                               HubExtension,
+                                               TRUE,
+                                               TRUE,
+                                               TRUE);
+
+                        PoStartNextPowerIrp(Irp);
+                        IoMarkIrpPending(Irp);
+                        PoCallDriver(HubExtension->LowerDevice, Irp);
+
+                        if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_SUSPENSE)
+                        {
+                            HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DO_SUSPENSE;
+
+                            KeReleaseSemaphore(&HubExtension->IdleSemaphore,
+                                               LOW_REALTIME_PRIORITY,
+                                               1,
+                                               FALSE);
+                        }
+
+                        return STATUS_PENDING;
+
+                    default:
+                        DPRINT1("USBH_FdoPower: Unsupported PowerState.DeviceState\n");
+                        DbgBreakPoint();
+                        break;
+                }
+            }
+            else
+            {
+                if (PowerState.SystemState != PowerSystemWorking)
+                {
+                    USBH_GetRootHubExtension(HubExtension)->SystemPowerState.SystemState =
+                                                            PowerState.SystemState;
+                }
+
+                if (PowerState.SystemState == PowerSystemHibernate)
+                {
+                    HubExtension->HubFlags |= USBHUB_FDO_FLAG_HIBERNATE_STATE;
+                }
+
+                PortData = HubExtension->PortData;
+
+                IsAllPortsD3 = TRUE;
+
+                if (PortData && HubExtension->HubDescriptor)
+                {
+                    for (Port = 0;
+                         Port < HubExtension->HubDescriptor->bNumberOfPorts;
+                         Port++)
+                    {
+                        PdoDevice = PortData[Port].DeviceObject;
+
+                        if (PdoDevice)
+                        {
+                            PortExtension = PdoDevice->DeviceExtension;
+
+                            if (PortExtension->CurrentPowerState.DeviceState != PowerDeviceD3)
+                            {
+                                IsAllPortsD3 = FALSE;
+                                break;
+                            }
+                        }
+                    }
+                }
+
+                if (PowerState.SystemState == PowerSystemWorking)
+                {
+                    DevicePwrState.DeviceState = PowerDeviceD0;
+                }
+                else if (HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP ||
+                         !IsAllPortsD3)
+                {
+                    DevicePwrState.DeviceState = HubExtension->DeviceState[PowerState.SystemState];
+
+                    if (DevicePwrState.DeviceState == PowerDeviceUnspecified)
+                    {
+                        goto Exit;
+                    }
+                }
+                else
+                {
+                    DevicePwrState.DeviceState = PowerDeviceD3;
+                }
+
+                if (DevicePwrState.DeviceState != HubExtension->CurrentPowerState.DeviceState &&
+                    HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
+                {
+                    HubExtension->PowerIrp = Irp;
+
+                    IoMarkIrpPending(Irp);
+
+                    if (PoRequestPowerIrp(HubExtension->LowerPDO,
+                                          IRP_MN_SET_POWER,
+                                          DevicePwrState,
+                                          USBH_FdoDeferPoRequestCompletion,
+                                          (PVOID)HubExtension,
+                                          NULL) == STATUS_PENDING)
+                    {
+                        return STATUS_PENDING;
+                    }
+
+                    IoCopyCurrentIrpStackLocationToNext(Irp);
+                    PoStartNextPowerIrp(Irp);
+                    PoCallDriver(HubExtension->LowerDevice, Irp);
+
+                    return STATUS_PENDING;
+                }
+
+            Exit:
+
+                HubExtension->SystemPowerState.SystemState = PowerState.SystemState;
+
+                if (PowerState.SystemState == PowerSystemWorking)
+                {
+                    USBH_CheckIdleDeferred(HubExtension);
+                }
+
+                IoCopyCurrentIrpStackLocationToNext(Irp);
+                PoStartNextPowerIrp(Irp);
+
+                return PoCallDriver(HubExtension->LowerDevice, Irp);
+            }
+
+            break;
+
+        case IRP_MN_QUERY_POWER:
+            DPRINT_PWR("USBH_FdoPower: IRP_MN_QUERY_POWER\n");
+            break;
+
+        default:
+            DPRINT1("USBH_FdoPower: unknown IRP_MN_POWER!\n");
+            break;
+    }
+
+    IoCopyCurrentIrpStackLocationToNext(Irp);
+    PoStartNextPowerIrp(Irp);
+    Status = PoCallDriver(HubExtension->LowerDevice, Irp);
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_PdoPower(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+              IN PIRP Irp,
+              IN UCHAR Minor)
+{
+    NTSTATUS Status = Irp->IoStatus.Status;
+
+    DPRINT_PWR("USBH_FdoPower: PortExtension - %p, Irp - %p, Minor - %X\n",
+               PortExtension,
+               Irp,
+               Minor);
+
+    switch (Minor)
+    {
+      case IRP_MN_WAIT_WAKE:
+          DPRINT_PWR("USBHUB_PdoPower: IRP_MN_WAIT_WAKE\n");
+          PoStartNextPowerIrp(Irp);
+          break;
+
+      case IRP_MN_POWER_SEQUENCE:
+          DPRINT_PWR("USBHUB_PdoPower: IRP_MN_POWER_SEQUENCE\n");
+          PoStartNextPowerIrp(Irp);
+          break;
+
+      case IRP_MN_SET_POWER:
+          DPRINT_PWR("USBHUB_PdoPower: IRP_MN_SET_POWER\n");
+          PoStartNextPowerIrp(Irp);
+          break;
+
+      case IRP_MN_QUERY_POWER:
+          DPRINT_PWR("USBHUB_PdoPower: IRP_MN_QUERY_POWER\n");
+          PoStartNextPowerIrp(Irp);
+          break;
+
+      default:
+          DPRINT1("USBHUB_PdoPower: unknown IRP_MN_POWER!\n");
+          PoStartNextPowerIrp(Irp);
+          break;
+    }
+
+    Irp->IoStatus.Status = Status;
+    Irp->IoStatus.Information = 0;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return Status;
+}
diff --git a/reactos/drivers/usb/usbhub_new/usbhub.c b/reactos/drivers/usb/usbhub_new/usbhub.c
new file mode 100644 (file)
index 0000000..6f3ea06
--- /dev/null
@@ -0,0 +1,5047 @@
+#include "usbhub.h"
+
+#define NDEBUG
+#include <debug.h>
+
+#define NDEBUG_USBHUB_SCE
+#define NDEBUG_USBHUB_PNP
+#include "dbg_uhub.h"
+
+#include <ntddstor.h>
+
+PWSTR GenericUSBDeviceString = NULL;
+
+NTSTATUS
+NTAPI
+USBH_Wait(IN ULONG Milliseconds)
+{
+    LARGE_INTEGER Interval;
+
+    DPRINT("USBH_Wait: Milliseconds - %x\n", Milliseconds);
+    Interval.QuadPart = -10000 * Milliseconds + (KeQueryTimeIncrement() - 1);
+    return KeDelayExecutionThread(KernelMode, FALSE, &Interval);
+}
+
+NTSTATUS
+NTAPI
+USBH_GetConfigValue(IN PWSTR ValueName,
+                    IN ULONG ValueType,
+                    IN PVOID ValueData,
+                    IN ULONG ValueLength,
+                    IN PVOID Context,
+                    IN PVOID EntryContext)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    DPRINT("USBHUB_GetConfigValue: ... \n");
+
+    if (ValueType == REG_BINARY)
+    {
+        *(PUCHAR)EntryContext = *(PUCHAR)ValueData;
+    }
+    else if (ValueType == REG_DWORD)
+    {
+        *(PULONG)EntryContext = *(PULONG)ValueData;
+    }
+    else
+    {
+        Status = STATUS_INVALID_PARAMETER;
+    }
+
+    return Status;
+}
+
+VOID
+NTAPI
+USBH_CompleteIrp(IN PIRP Irp,
+                 IN NTSTATUS CompleteStatus)
+{
+    if (CompleteStatus != STATUS_SUCCESS)
+    {
+        DPRINT1("USBH_CompleteIrp: Irp - %p, CompleteStatus - %X\n",
+                Irp,
+                CompleteStatus);
+    }
+
+    Irp->IoStatus.Status = CompleteStatus;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+NTSTATUS
+NTAPI
+USBH_PassIrp(IN PDEVICE_OBJECT DeviceObject,
+             IN PIRP Irp)
+{
+    DPRINT_PNP("USBH_PassIrp: DeviceObject - %p, Irp - %p\n",
+               DeviceObject,
+               Irp);
+
+    IoSkipCurrentIrpStackLocation(Irp);
+    return IoCallDriver(DeviceObject, Irp);
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncIrpComplete(IN PDEVICE_OBJECT DeviceObject,
+                     IN PIRP Irp,
+                     IN PVOID Context)
+{
+    PUSBHUB_URB_TIMEOUT_CONTEXT HubTimeoutContext;
+    KIRQL OldIrql;
+    BOOLEAN TimerCancelled;
+
+    DPRINT("USBH_SyncIrpComplete: ... \n");
+
+    HubTimeoutContext = Context;
+
+    KeAcquireSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, &OldIrql);
+    HubTimeoutContext->IsNormalCompleted = TRUE;
+    TimerCancelled = KeCancelTimer(&HubTimeoutContext->UrbTimeoutTimer);
+    KeReleaseSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, OldIrql);
+
+    if (TimerCancelled)
+    {
+        KeSetEvent(&HubTimeoutContext->UrbTimeoutEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+    }
+
+    return STATUS_SUCCESS;
+}
+
+BOOLEAN
+NTAPI
+IsBitSet(IN PUCHAR BitMapAddress,
+         IN USHORT Bit)
+{
+    BOOLEAN IsSet;
+
+    IsSet = (BitMapAddress[Bit / 8] & (1 << (Bit & 7))) != 0;
+    DPRINT("IsBitSet: Bit - %lX, IsSet - %x\n", Bit, IsSet);
+    return IsSet;
+}
+
+PUSBHUB_PORT_PDO_EXTENSION
+NTAPI
+PdoExt(IN PDEVICE_OBJECT DeviceObject)
+{
+    PVOID PdoExtension;
+
+    DPRINT("PdoExt: DeviceObject - %p\n", DeviceObject);
+
+    if (DeviceObject)
+    {
+        PdoExtension = DeviceObject->DeviceExtension;
+    }
+    else
+    {
+        PdoExtension = NULL;
+    }
+
+    return (PUSBHUB_PORT_PDO_EXTENSION)PdoExtension;
+}
+
+NTSTATUS
+NTAPI
+USBH_WriteFailReasonID(IN PDEVICE_OBJECT DeviceObject,
+                       IN ULONG FailReason)
+{
+    NTSTATUS Status;
+    HANDLE KeyHandle;
+    UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"FailReasonID");
+
+    DPRINT("USBH_WriteFailReason: ID - %x\n", FailReason);
+
+    Status = IoOpenDeviceRegistryKey(DeviceObject,
+                                     PLUGPLAY_REGKEY_DEVICE,
+                                     STANDARD_RIGHTS_ALL,
+                                     &KeyHandle);
+
+    if (NT_SUCCESS(Status))
+    {
+        ZwSetValueKey(KeyHandle,
+                      &ValueName,
+                      0,
+                      REG_DWORD,
+                      &FailReason,
+                      sizeof(FailReason));
+
+        ZwClose(KeyHandle);
+    }
+
+    return Status;
+}
+
+VOID
+NTAPI
+USBH_UrbTimeoutDPC(IN PKDPC Dpc,
+                   IN PVOID DeferredContext,
+                   IN PVOID SystemArgument1,
+                   IN PVOID SystemArgument2)
+{
+    PUSBHUB_URB_TIMEOUT_CONTEXT HubTimeoutContext;
+    KIRQL OldIrql;
+    BOOL IsCompleted;
+
+    DPRINT("USBH_TimeoutDPC ... \n");
+
+    HubTimeoutContext = DeferredContext;
+
+    KeAcquireSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, &OldIrql);
+    IsCompleted = HubTimeoutContext->IsNormalCompleted;
+    KeReleaseSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, OldIrql);
+
+    if (!IsCompleted)
+    {
+        IoCancelIrp(HubTimeoutContext->Irp);
+    }
+
+    KeSetEvent(&HubTimeoutContext->UrbTimeoutEvent,
+               EVENT_INCREMENT,
+               FALSE);
+}
+
+NTSTATUS
+NTAPI
+USBH_SetPdoRegistryParameter(IN PDEVICE_OBJECT DeviceObject,
+                             IN PCWSTR ValueName,
+                             IN PVOID Data,
+                             IN ULONG DataSize,
+                             IN ULONG Type,
+                             IN ULONG DevInstKeyType)
+{
+    NTSTATUS Status;
+    UNICODE_STRING ValueNameString;
+    HANDLE KeyHandle;
+
+    DPRINT("USBH_SetPdoRegistryParameter ... \n");
+
+    RtlInitUnicodeString(&ValueNameString, ValueName);
+
+    Status = IoOpenDeviceRegistryKey(DeviceObject,
+                                     DevInstKeyType,
+                                     STANDARD_RIGHTS_ALL,
+                                     &KeyHandle);
+
+    if (NT_SUCCESS(Status))
+    {
+         ZwSetValueKey(KeyHandle,
+                       &ValueNameString,
+                       0,
+                       Type,
+                       Data,
+                       DataSize);
+
+        ZwClose(KeyHandle);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncSubmitUrb(IN PDEVICE_OBJECT DeviceObject,
+                   IN PURB Urb)
+{
+    KEVENT Event;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PIRP Irp;
+    PIO_STACK_LOCATION IoStack;
+    PUSBHUB_URB_TIMEOUT_CONTEXT HubTimeoutContext;
+    BOOLEAN IsWaitTimeout = FALSE;
+    LARGE_INTEGER DueTime;
+    NTSTATUS Status;
+
+    DPRINT("USBH_SyncSubmitUrb: ... \n");
+
+    Urb->UrbHeader.UsbdDeviceHandle = NULL;
+
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
+                                        DeviceObject,
+                                        NULL,
+                                        0,
+                                        NULL,
+                                        0,
+                                        TRUE,
+                                        &Event,
+                                        &IoStatusBlock);
+
+    if (!Irp)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    IoStack = IoGetNextIrpStackLocation(Irp);
+    IoStack->Parameters.Others.Argument1 = Urb;
+
+    HubTimeoutContext = ExAllocatePoolWithTag(NonPagedPool,
+                                              sizeof(USBHUB_URB_TIMEOUT_CONTEXT),
+                                              USB_HUB_TAG);
+
+    if (HubTimeoutContext)
+    {
+        RtlZeroMemory(HubTimeoutContext, sizeof(USBHUB_URB_TIMEOUT_CONTEXT));
+
+        HubTimeoutContext->Irp = Irp;
+        HubTimeoutContext->IsNormalCompleted = FALSE;
+
+        KeInitializeEvent(&HubTimeoutContext->UrbTimeoutEvent,
+                          NotificationEvent,
+                          FALSE);
+
+        KeInitializeSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock);
+        KeInitializeTimer(&HubTimeoutContext->UrbTimeoutTimer);
+
+        KeInitializeDpc(&HubTimeoutContext->UrbTimeoutDPC,
+                        USBH_UrbTimeoutDPC,
+                        HubTimeoutContext);
+
+        DueTime.QuadPart = -5000 * 10000; // Timeout 5 sec.
+
+        KeSetTimer(&HubTimeoutContext->UrbTimeoutTimer,
+                   DueTime,
+                   &HubTimeoutContext->UrbTimeoutDPC);
+
+        IoSetCompletionRoutine(Irp,
+                               USBH_SyncIrpComplete,
+                               HubTimeoutContext,
+                               TRUE,
+                               TRUE,
+                               TRUE);
+
+        IsWaitTimeout = TRUE;
+    }
+
+    Status = IoCallDriver(DeviceObject, Irp);
+
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+    else
+    {
+        IoStatusBlock.Status = Status;
+    }
+
+    if (IsWaitTimeout)
+    {
+        KeWaitForSingleObject(&HubTimeoutContext->UrbTimeoutEvent,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+
+        ExFreePoolWithTag(HubTimeoutContext, USB_HUB_TAG);
+    }
+
+    return IoStatusBlock.Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoSyncSubmitUrb(IN PDEVICE_OBJECT FdoDevice,
+                      IN PURB Urb)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+
+    DPRINT("USBH_FdoSyncSubmitUrb: FdoDevice - %p, Urb - %p\n",
+           FdoDevice,
+           Urb);
+
+    HubExtension = FdoDevice->DeviceExtension;
+    return USBH_SyncSubmitUrb(HubExtension->LowerDevice, Urb);
+}
+
+NTSTATUS
+NTAPI
+USBH_Transact(IN PUSBHUB_FDO_EXTENSION HubExtension,
+              IN PVOID TransferBuffer,
+              IN ULONG BufferLen,
+              IN BOOLEAN IsDeviceToHost,
+              IN USHORT Function,
+              IN BM_REQUEST_TYPE RequestType,
+              IN UCHAR Request,
+              IN USHORT RequestValue,
+              IN USHORT RequestIndex)
+{
+    struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb;
+    ULONG TransferFlags;
+    PVOID Buffer = NULL;
+    ULONG Length;
+    NTSTATUS Status;
+
+    DPRINT("USBH_Transact: ... \n");
+
+    if (BufferLen)
+    {
+        Length = ALIGN_DOWN_BY(BufferLen + sizeof(ULONG), sizeof(ULONG));
+
+        Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, USB_HUB_TAG);
+
+        if (!Buffer)
+        {
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        RtlZeroMemory(Buffer, Length);
+    }
+
+    Urb = ExAllocatePoolWithTag(NonPagedPool,
+                                sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
+                                USB_HUB_TAG);
+
+    if (!Urb)
+    {
+        if (Buffer)
+        {
+            ExFreePoolWithTag(Buffer, USB_HUB_TAG);
+        }
+
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
+
+    if (IsDeviceToHost)
+    {
+        if (BufferLen)
+        {
+            RtlZeroMemory(TransferBuffer, BufferLen);
+        }
+
+        TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
+    }
+    else
+    {
+        if (BufferLen)
+        {
+            RtlCopyMemory(Buffer, TransferBuffer, BufferLen);
+        }
+
+        TransferFlags = USBD_TRANSFER_DIRECTION_OUT;
+    }
+
+    Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
+    Urb->Hdr.Function = Function;
+    Urb->Hdr.UsbdDeviceHandle = NULL;
+
+    Urb->TransferFlags = TransferFlags;
+    Urb->TransferBuffer = BufferLen != 0 ? Buffer : NULL;
+    Urb->TransferBufferLength = BufferLen;
+    Urb->TransferBufferMDL = NULL;
+    Urb->UrbLink = NULL;
+
+    Urb->RequestTypeReservedBits = RequestType.B;
+    Urb->Request = Request;
+    Urb->Value = RequestValue;
+    Urb->Index = RequestIndex;
+
+    Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice, (PURB)Urb);
+
+    if (IsDeviceToHost && BufferLen)
+    {
+        RtlCopyMemory(TransferBuffer, Buffer, BufferLen);
+    }
+
+    if (Buffer)
+    {
+        ExFreePoolWithTag(Buffer, USB_HUB_TAG);
+    }
+
+    ExFreePoolWithTag(Urb, USB_HUB_TAG);
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncResetPort(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                   IN USHORT Port)
+{
+    USBHUB_PORT_STATUS PortStatus;
+    KEVENT Event;
+    LARGE_INTEGER Timeout;
+    ULONG ResetRetry = 0;
+    NTSTATUS Status;
+
+    DPRINT("USBH_SyncResetPort: Port - %x\n", Port);
+
+    InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+    KeWaitForSingleObject(&HubExtension->HubPortSemaphore,
+                          Executive,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    Status = USBH_SyncGetPortStatus(HubExtension,
+                                    Port,
+                                    &PortStatus,
+                                    sizeof(USBHUB_PORT_STATUS));
+
+    if (NT_SUCCESS(Status) &&
+        (PortStatus.UsbPortStatus.Usb20PortStatus.CurrentConnectStatus == 0))
+    {
+        Status = STATUS_UNSUCCESSFUL;
+        goto Exit;
+    }
+
+    HubExtension->HubFlags |= USBHUB_FDO_FLAG_RESET_PORT_LOCK;
+
+    while (TRUE)
+    {
+        BM_REQUEST_TYPE RequestType;
+
+        KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+        InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
+                                   &Event);
+
+        RequestType.B = 0;
+        RequestType.Recipient = BMREQUEST_TO_DEVICE;
+        RequestType.Type = BMREQUEST_CLASS;
+        RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
+
+        Status = USBH_Transact(HubExtension,
+                               NULL,
+                               0,
+                               BMREQUEST_HOST_TO_DEVICE,
+                               URB_FUNCTION_CLASS_OTHER,
+                               RequestType,
+                               USB_REQUEST_SET_FEATURE,
+                               USBHUB_FEATURE_PORT_RESET,
+                               Port);
+
+        Timeout.QuadPart = -5000 * 10000;
+
+        if (!NT_SUCCESS(Status))
+        {
+            InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
+                                       NULL);
+
+            USBH_Wait(10);
+            HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_RESET_PORT_LOCK;
+
+            goto Exit;
+        }
+
+        Status = KeWaitForSingleObject(&Event,
+                                       Suspended,
+                                       KernelMode,
+                                       FALSE,
+                                       &Timeout);
+
+        if (Status != STATUS_TIMEOUT)
+        {
+            break;
+        }
+
+        Status = USBH_SyncGetPortStatus(HubExtension,
+                                        Port,
+                                        &PortStatus,
+                                        sizeof(USBHUB_PORT_STATUS));
+
+        if (!NT_SUCCESS(Status) ||
+            (PortStatus.UsbPortStatus.Usb20PortStatus.CurrentConnectStatus == 0) ||
+            ResetRetry >= USBHUB_RESET_PORT_MAX_RETRY)
+        {
+            InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
+                                       NULL);
+
+            USBH_Wait(10);
+            HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_RESET_PORT_LOCK;
+
+            Status = STATUS_DEVICE_DATA_ERROR;
+            goto Exit;
+        }
+
+        ResetRetry++;
+    }
+
+    Status = USBH_SyncGetPortStatus(HubExtension,
+                                    Port,
+                                    &PortStatus,
+                                    sizeof(USBHUB_PORT_STATUS));
+
+    if ((PortStatus.UsbPortStatus.Usb20PortStatus.CurrentConnectStatus == 0) &&
+        NT_SUCCESS(Status) &&
+        HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB)
+    {
+        Status = STATUS_DEVICE_DATA_ERROR;
+    }
+
+    USBH_Wait(10);
+    HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_RESET_PORT_LOCK;
+
+Exit:
+
+    KeReleaseSemaphore(&HubExtension->HubPortSemaphore,
+                       LOW_REALTIME_PRIORITY,
+                       1,
+                       FALSE);
+
+    if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+    {
+        KeSetEvent(&HubExtension->PendingRequestEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_GetDeviceType(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                   IN PUSB_DEVICE_HANDLE DeviceHandle,
+                   OUT USB_DEVICE_TYPE * OutDeviceType)
+{
+    PUSB_BUSIFFN_GET_DEVICE_INFORMATION QueryDeviceInformation;
+    PUSB_DEVICE_INFORMATION_0 DeviceInfo;
+    SIZE_T DeviceInformationBufferLength;
+    USB_DEVICE_TYPE DeviceType = Usb11Device;
+    ULONG dummy;
+    NTSTATUS Status;
+
+    DPRINT("USBH_GetDeviceType: ... \n");
+
+    QueryDeviceInformation = HubExtension->BusInterface.QueryDeviceInformation;
+
+    if (!QueryDeviceInformation)
+    {
+        DPRINT1("USBH_GetDeviceType: no QueryDeviceInformation()\n");
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    DeviceInformationBufferLength = sizeof(USB_DEVICE_INFORMATION_0);
+
+    while (TRUE)
+    {
+        DeviceInfo = ExAllocatePoolWithTag(PagedPool,
+                                           DeviceInformationBufferLength,
+                                           USB_HUB_TAG);
+
+        if (!DeviceInfo)
+        {
+            DPRINT1("USBH_GetDeviceType: ExAllocatePoolWithTag() failed\n");
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            break;
+        }
+
+        RtlZeroMemory(DeviceInfo, DeviceInformationBufferLength);
+
+        DeviceInfo->InformationLevel = 0;
+
+        Status = QueryDeviceInformation(HubExtension->BusInterface.BusContext,
+                                        DeviceHandle,
+                                        DeviceInfo,
+                                        DeviceInformationBufferLength,
+                                        &dummy);
+
+        if (Status != STATUS_BUFFER_TOO_SMALL)
+        {
+            if (NT_SUCCESS(Status))
+            {
+                DeviceType = DeviceInfo->DeviceType;
+            }
+
+            ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
+            break;
+        }
+
+        DeviceInformationBufferLength = DeviceInfo->ActualLength;
+        ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
+    }
+
+    if (OutDeviceType)
+    {
+        *OutDeviceType = DeviceType;
+        DPRINT("USBH_GetDeviceType: DeviceType - %x\n", DeviceType);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBHUB_GetExtendedHubInfo(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                          IN PUSB_EXTHUB_INFORMATION_0 HubInfoBuffer)
+{
+    PUSB_BUSIFFN_GET_EXTENDED_HUB_INFO GetExtendedHubInformation;
+    ULONG dummy = 0;
+
+    DPRINT("USBHUB_GetExtendedHubInfo: ... \n");
+
+    GetExtendedHubInformation = HubExtension->BusInterface.GetExtendedHubInformation;
+
+    return GetExtendedHubInformation(HubExtension->BusInterface.BusContext,
+                                     HubExtension->LowerPDO,
+                                     HubInfoBuffer,
+                                     sizeof(USB_EXTHUB_INFORMATION_0),
+                                     &dummy);
+}
+
+PUSBHUB_FDO_EXTENSION
+NTAPI
+USBH_GetRootHubExtension(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    PDEVICE_OBJECT Device;
+    PUSBHUB_FDO_EXTENSION RootHubExtension;
+
+    DPRINT("USBH_GetRootHubExtension: HubExtension - %p\n", HubExtension);
+
+    RootHubExtension = HubExtension;
+
+    if (HubExtension->LowerPDO != HubExtension->RootHubPdo)
+    {
+        Device = HubExtension->RootHubPdo;
+
+        do
+        {
+            Device = Device->AttachedDevice;
+        }
+        while (Device->DriverObject != HubExtension->Common.SelfDevice->DriverObject);
+
+        RootHubExtension = Device->DeviceExtension;
+    }
+
+    DPRINT("USBH_GetRootHubExtension: RootHubExtension - %p\n", RootHubExtension);
+
+    return RootHubExtension;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncGetRootHubPdo(IN PDEVICE_OBJECT DeviceObject,
+                       IN OUT PDEVICE_OBJECT * OutPdo1,
+                       IN OUT PDEVICE_OBJECT * OutPdo2)
+{
+    KEVENT Event;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PIRP Irp;
+    PIO_STACK_LOCATION IoStack;
+    NTSTATUS Status;
+
+    DPRINT("USBH_SyncGetRootHubPdo: ... \n");
+
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
+                                        DeviceObject,
+                                        NULL,
+                                        0,
+                                        NULL,
+                                        0,
+                                        TRUE,
+                                        &Event,
+                                        &IoStatusBlock);
+
+    if (!Irp)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    IoStack = IoGetNextIrpStackLocation(Irp);
+    IoStack->Parameters.Others.Argument1 = OutPdo1;
+    IoStack->Parameters.Others.Argument2 = OutPdo2;
+
+    Status = IoCallDriver(DeviceObject, Irp);
+
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+    else
+    {
+        IoStatusBlock.Status = Status;
+    }
+
+    return IoStatusBlock.Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncGetHubCount(IN PDEVICE_OBJECT DeviceObject,
+                     IN OUT PULONG OutHubCount)
+{
+    KEVENT Event;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PIRP Irp;
+    PIO_STACK_LOCATION IoStack;
+    NTSTATUS Status;
+
+    DPRINT("USBH_SyncGetHubCount: *OutHubCount - %x\n", *OutHubCount);
+
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_HUB_COUNT,
+                                        DeviceObject,
+                                        NULL,
+                                        0,
+                                        NULL,
+                                        0,
+                                        TRUE,
+                                        &Event,
+                                        &IoStatusBlock);
+
+    if (!Irp)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    IoStack = IoGetNextIrpStackLocation(Irp);
+    IoStack->Parameters.Others.Argument1 = OutHubCount;
+
+    Status = IoCallDriver(DeviceObject, Irp);
+
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+    else
+    {
+        IoStatusBlock.Status = Status;
+    }
+
+    return IoStatusBlock.Status;
+}
+
+PUSB_DEVICE_HANDLE
+NTAPI
+USBH_SyncGetDeviceHandle(IN PDEVICE_OBJECT DeviceObject)
+{
+    PIRP Irp;
+    KEVENT Event;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PUSB_DEVICE_HANDLE DeviceHandle = NULL;
+    PIO_STACK_LOCATION IoStack;
+
+    DPRINT("USBH_SyncGetDeviceHandle: ... \n");
+
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE,
+                                        DeviceObject,
+                                        NULL,
+                                        0,
+                                        NULL,
+                                        0,
+                                        TRUE,
+                                        &Event,
+                                        &IoStatusBlock);
+
+    if (!Irp)
+    {
+        DPRINT1("USBH_SyncGetDeviceHandle: Irp - NULL!\n");
+        return NULL;
+    }
+
+    IoStack = IoGetNextIrpStackLocation(Irp);
+    IoStack->Parameters.Others.Argument1 = &DeviceHandle;
+
+    if (IoCallDriver(DeviceObject, Irp) == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+
+    return DeviceHandle;
+}
+
+NTSTATUS
+NTAPI
+USBH_GetDeviceDescriptor(IN PDEVICE_OBJECT DeviceObject,
+                         IN PUSB_DEVICE_DESCRIPTOR HubDeviceDescriptor)
+{
+    struct _URB_CONTROL_DESCRIPTOR_REQUEST * Urb;
+    NTSTATUS Status;
+
+    DPRINT("USBH_GetDeviceDescriptor: ... \n");
+
+    Urb = ExAllocatePoolWithTag(NonPagedPool,
+                                sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+                                USB_HUB_TAG);
+
+    if (!Urb)
+    {
+        DPRINT1("USBH_SyncGetDeviceHandle: Urb - NULL!\n");
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
+
+    Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
+    Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
+
+    Urb->TransferBufferLength = sizeof(USB_DEVICE_DESCRIPTOR);
+    Urb->TransferBuffer = HubDeviceDescriptor;
+    Urb->DescriptorType = USB_DEVICE_DESCRIPTOR_TYPE;
+
+    Status = USBH_FdoSyncSubmitUrb(DeviceObject, (PURB)Urb);
+
+    ExFreePoolWithTag(Urb, USB_HUB_TAG);
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncGetDeviceConfigurationDescriptor(IN PDEVICE_OBJECT DeviceObject,
+                                          IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor,
+                                          IN ULONG NumberOfBytes,
+                                          IN PULONG OutLength)
+{
+    PCOMMON_DEVICE_EXTENSION DeviceExtension;
+    struct _URB_CONTROL_DESCRIPTOR_REQUEST * Urb;
+    NTSTATUS Status;
+
+    DPRINT("USBH_SyncGetDeviceConfigurationDescriptor: ... \n");
+
+    DeviceExtension = DeviceObject->DeviceExtension;
+
+    if (OutLength)
+    {
+        *OutLength = 0;
+    }
+
+    Urb = ExAllocatePoolWithTag(NonPagedPool,
+                                sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+                                USB_HUB_TAG);
+
+    if (!Urb)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
+
+    Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
+    Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
+
+    Urb->TransferBufferLength = NumberOfBytes;
+    Urb->TransferBuffer = ConfigDescriptor;
+    Urb->DescriptorType = USB_CONFIGURATION_DESCRIPTOR_TYPE;
+
+    if (DeviceExtension->ExtensionType == USBH_EXTENSION_TYPE_HUB ||
+        DeviceExtension->ExtensionType == USBH_EXTENSION_TYPE_PARENT)
+    {
+        Status = USBH_FdoSyncSubmitUrb(DeviceObject, (PURB)Urb);
+    }
+    else
+    {
+        Status = USBH_SyncSubmitUrb(DeviceObject, (PURB)Urb);
+    }
+
+    if (OutLength)
+    {
+        *OutLength = Urb->TransferBufferLength;
+    }
+
+    if (Urb)
+    {
+        ExFreePoolWithTag(Urb, USB_HUB_TAG);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_GetConfigurationDescriptor(IN PDEVICE_OBJECT DeviceObject,
+                                IN PUSB_CONFIGURATION_DESCRIPTOR * OutDescriptor)
+{
+    PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
+    ULONG ReturnedLen;
+    SIZE_T DescriptorLen;
+    NTSTATUS Status;
+
+    DPRINT("USBH_GetConfigurationDescriptor: ... \n");
+
+    DescriptorLen = MAXUCHAR;
+
+    while (TRUE)
+    {
+        ConfigDescriptor = ExAllocatePoolWithTag(NonPagedPool,
+                                                 DescriptorLen,
+                                                 USB_HUB_TAG);
+
+        if (!ConfigDescriptor)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            break;
+        }
+
+        Status = USBH_SyncGetDeviceConfigurationDescriptor(DeviceObject,
+                                                           ConfigDescriptor,
+                                                           DescriptorLen,
+                                                           &ReturnedLen);
+
+        if (ReturnedLen < sizeof(USB_CONFIGURATION_DESCRIPTOR))
+        {
+            Status = STATUS_DEVICE_DATA_ERROR;
+        }
+
+        if (!NT_SUCCESS(Status))
+        {
+            break;
+        }
+
+        *OutDescriptor = ConfigDescriptor;
+
+        if (ConfigDescriptor->wTotalLength <= DescriptorLen)
+        {
+            break;
+        }
+
+        DescriptorLen = ConfigDescriptor->wTotalLength;
+
+        ExFreePool(ConfigDescriptor);
+        *OutDescriptor = NULL;
+    }
+
+    if (NT_SUCCESS(Status))
+    {
+        if (ReturnedLen < ConfigDescriptor->wTotalLength)
+        {
+            Status = STATUS_DEVICE_DATA_ERROR;
+        }
+    }
+    else
+    {
+        if (ConfigDescriptor)
+        {
+            ExFreePool(ConfigDescriptor);
+        }
+
+        *OutDescriptor = NULL;
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncGetHubDescriptor(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    PUSB_EXTHUB_INFORMATION_0 ExtendedHubInfo;
+    ULONG NumberPorts;
+    PUSBHUB_PORT_DATA PortData;
+    USHORT RequestValue;
+    ULONG NumberOfBytes;
+    NTSTATUS Status;
+    PUSB_HUB_DESCRIPTOR HubDescriptor = NULL;
+    ULONG ix;
+    ULONG Retry;
+
+    DPRINT("USBH_SyncGetHubDescriptor: ... \n");
+
+    ExtendedHubInfo = ExAllocatePoolWithTag(NonPagedPool,
+                                            sizeof(USB_EXTHUB_INFORMATION_0),
+                                            USB_HUB_TAG);
+
+    if (!ExtendedHubInfo)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto ErrorExit;
+    }
+
+    RtlZeroMemory(ExtendedHubInfo, sizeof(USB_EXTHUB_INFORMATION_0));
+
+    Status = USBHUB_GetExtendedHubInfo(HubExtension, ExtendedHubInfo);
+
+    if (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(ExtendedHubInfo, USB_HUB_TAG);
+        ExtendedHubInfo = NULL;
+    }
+
+    NumberOfBytes = sizeof(USB_HUB_DESCRIPTOR);
+
+    HubDescriptor = ExAllocatePoolWithTag(NonPagedPool,
+                                          NumberOfBytes,
+                                          USB_HUB_TAG);
+
+    if (!HubDescriptor)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto ErrorExit;
+    }
+
+    RtlZeroMemory(HubDescriptor, NumberOfBytes);
+
+    RequestValue = 0;
+    Retry = 0;
+
+    while (TRUE)
+    {
+        while (Retry <= 5)
+        {
+            BM_REQUEST_TYPE RequestType;
+
+            RequestType.B = 0;
+            RequestType.Recipient = BMREQUEST_TO_DEVICE;
+            RequestType.Type = BMREQUEST_STANDARD;
+            RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
+
+            Status = USBH_Transact(HubExtension,
+                                   HubDescriptor,
+                                   NumberOfBytes,
+                                   BMREQUEST_DEVICE_TO_HOST,
+                                   URB_FUNCTION_CLASS_DEVICE,
+                                   RequestType,
+                                   USB_REQUEST_GET_DESCRIPTOR,
+                                   RequestValue,
+                                   0);
+
+            if (NT_SUCCESS(Status))
+            {
+                break;
+            }
+
+            RequestValue = 0x2900; // Hub DescriptorType - 0x29
+
+            Retry++;
+        }
+
+        if (HubDescriptor->bDescriptorLength <= NumberOfBytes)
+        {
+            break;
+        }
+
+        NumberOfBytes = HubDescriptor->bDescriptorLength;
+        ExFreePoolWithTag(HubDescriptor, USB_HUB_TAG);
+
+        if (Retry >= 5)
+        {
+            Status = STATUS_DEVICE_DATA_ERROR;
+            HubDescriptor = NULL;
+            goto ErrorExit;
+        }
+
+        HubDescriptor = ExAllocatePoolWithTag(NonPagedPool,
+                                              NumberOfBytes,
+                                              USB_HUB_TAG);
+
+        if (!HubDescriptor)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            goto ErrorExit;
+        }
+
+        RtlZeroMemory(HubDescriptor, NumberOfBytes);
+    }
+
+    NumberPorts = HubDescriptor->bNumberOfPorts;
+
+    if (HubExtension->PortData)
+    {
+        PortData = HubExtension->PortData;
+
+        for (ix = 0; ix < NumberPorts; ix++)
+        {
+            PortData[ix].PortStatus.AsULONG = 0;
+
+            if (ExtendedHubInfo)
+            {
+                PortData[ix].PortAttributes = ExtendedHubInfo->Port[ix].PortAttributes;
+            }
+            else
+            {
+                PortData[ix].PortAttributes = 0;
+            }
+
+            PortData[ix].ConnectionStatus = NoDeviceConnected;
+
+            if (PortData[ix].DeviceObject != NULL)
+            {
+                PortData[ix].ConnectionStatus = DeviceConnected;
+            }
+        }
+    }
+    else
+    {
+        PortData = NULL;
+
+        if (HubDescriptor->bNumberOfPorts)
+        {
+            PortData = ExAllocatePoolWithTag(NonPagedPool,
+                                             NumberPorts * sizeof(USBHUB_PORT_DATA),
+                                             USB_HUB_TAG);
+        }
+
+        if (!PortData)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            goto ErrorExit;
+        }
+
+        RtlZeroMemory(PortData, NumberPorts * sizeof(USBHUB_PORT_DATA));
+
+        for (ix = 0; ix < NumberPorts; ix++)
+        {
+            PortData[ix].ConnectionStatus = NoDeviceConnected;
+
+            if (ExtendedHubInfo)
+            {
+                PortData[ix].PortAttributes = ExtendedHubInfo->Port[ix].PortAttributes;
+            }
+        }
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        goto ErrorExit;
+    }
+
+    HubExtension->HubDescriptor = HubDescriptor;
+
+    HubExtension->PortData = PortData;
+
+    if (ExtendedHubInfo)
+    {
+        ExFreePoolWithTag(ExtendedHubInfo, USB_HUB_TAG);
+    }
+
+    return Status;
+
+ErrorExit:
+
+    if (HubDescriptor)
+    {
+        ExFreePoolWithTag(HubDescriptor, USB_HUB_TAG);
+    }
+
+    if (ExtendedHubInfo)
+    {
+        ExFreePoolWithTag(ExtendedHubInfo, USB_HUB_TAG);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncGetStringDescriptor(IN PDEVICE_OBJECT DeviceObject,
+                             IN UCHAR Index,
+                             IN USHORT LanguageId,
+                             IN PUSB_STRING_DESCRIPTOR Descriptor,
+                             IN ULONG NumberOfBytes,
+                             IN PULONG OutLength,
+                             IN BOOLEAN IsValidateLength)
+{
+    struct _URB_CONTROL_DESCRIPTOR_REQUEST * Urb;
+    ULONG TransferedLength;
+    NTSTATUS Status;
+
+    DPRINT("USBH_SyncGetStringDescriptor: Index - %x, LanguageId - %x\n",
+           Index,
+           LanguageId);
+
+    Urb = ExAllocatePoolWithTag(NonPagedPool,
+                                sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
+                                USB_HUB_TAG);
+
+    if (!Urb)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
+
+    Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
+    Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
+
+    Urb->TransferBuffer = Descriptor;
+    Urb->TransferBufferLength = NumberOfBytes;
+
+    Urb->Index = Index;
+    Urb->DescriptorType = USB_STRING_DESCRIPTOR_TYPE;
+    Urb->LanguageId = LanguageId;
+
+    Status = USBH_SyncSubmitUrb(DeviceObject, (PURB)Urb);
+
+    if (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(Urb, USB_HUB_TAG);
+        return Status;
+    }
+
+    TransferedLength = Urb->TransferBufferLength;
+
+    if (TransferedLength > NumberOfBytes)
+    {
+        Status = STATUS_DEVICE_DATA_ERROR;
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(Urb, USB_HUB_TAG);
+        return Status;
+    }
+
+    if (OutLength)
+    {
+        *OutLength = TransferedLength;
+    }
+
+    if (IsValidateLength && TransferedLength != Descriptor->bLength)
+    {
+        Status = STATUS_DEVICE_DATA_ERROR;
+    }
+
+    ExFreePoolWithTag(Urb, USB_HUB_TAG);
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncGetStatus(IN PDEVICE_OBJECT DeviceObject,
+                   IN PUSHORT OutStatus,
+                   IN USHORT Function,
+                   IN USHORT RequestIndex)
+{
+    struct _URB_CONTROL_GET_STATUS_REQUEST * Urb;
+    NTSTATUS NtStatus;
+    USHORT UsbStatus;
+
+    DPRINT("USBH_SyncGetStatus: ... \n");
+
+    Urb = ExAllocatePoolWithTag(NonPagedPool,
+                                sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST),
+                                USB_HUB_TAG);
+
+    if (!Urb)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST));
+
+    Urb->Hdr.Length = sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST);
+    Urb->Hdr.Function = Function;
+
+    Urb->TransferBuffer = &UsbStatus;
+    Urb->TransferBufferLength = sizeof(UsbStatus);
+    Urb->Index = RequestIndex;
+
+    NtStatus = USBH_FdoSyncSubmitUrb(DeviceObject, (PURB)Urb);
+
+    *OutStatus = UsbStatus;
+
+    ExFreePoolWithTag(Urb, USB_HUB_TAG);
+
+    return NtStatus;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncGetPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                       IN USHORT Port,
+                       IN PUSBHUB_PORT_STATUS PortStatus,
+                       IN ULONG Length)
+{
+    BM_REQUEST_TYPE RequestType;
+
+    DPRINT("USBH_SyncGetPortStatus: Port - %x\n", Port);
+
+    RequestType.B = 0;
+    RequestType.Recipient = BMREQUEST_TO_OTHER;
+    RequestType.Type = BMREQUEST_CLASS;
+    RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
+
+    return USBH_Transact(HubExtension,
+                         PortStatus,
+                         Length,
+                         BMREQUEST_DEVICE_TO_HOST,
+                         URB_FUNCTION_CLASS_OTHER,
+                         RequestType,
+                         USB_REQUEST_GET_STATUS,
+                         0,
+                         Port);
+}
+
+
+NTSTATUS
+NTAPI
+USBH_SyncClearPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                         IN USHORT Port,
+                         IN USHORT RequestValue)
+{
+    BM_REQUEST_TYPE RequestType;
+
+    DPRINT("USBH_SyncClearPortStatus: Port - %x, RequestValue - %x\n",
+           Port,
+           RequestValue);
+
+    RequestType.B = 0;
+    RequestType.Recipient = BMREQUEST_TO_DEVICE;
+    RequestType.Type = BMREQUEST_CLASS;
+    RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
+
+    return USBH_Transact(HubExtension,
+                         NULL,
+                         0,
+                         BMREQUEST_HOST_TO_DEVICE,
+                         URB_FUNCTION_CLASS_OTHER,
+                         RequestType,
+                         USB_REQUEST_CLEAR_FEATURE,
+                         RequestValue,
+                         Port);
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncPowerOnPort(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                     IN USHORT Port,
+                     IN BOOLEAN IsWait)
+{
+    PUSBHUB_PORT_DATA PortData;
+    PUSB_HUB_DESCRIPTOR HubDescriptor;
+    NTSTATUS Status = STATUS_SUCCESS;
+    BM_REQUEST_TYPE RequestType;
+    PUSBHUB_PORT_STATUS PortStatus;
+
+    DPRINT("USBH_SyncPowerOnPort: Port - %x, IsWait - %x\n", Port, IsWait);
+
+    ASSERT(Port > 0);
+    PortData = &HubExtension->PortData[Port - 1];
+    PortStatus = &PortData->PortStatus;
+
+    if (PortStatus->UsbPortStatus.Usb20PortStatus.CurrentConnectStatus == 1)
+    {
+        return Status;
+    }
+
+    RequestType.B = 0;
+    RequestType.Recipient = BMREQUEST_TO_DEVICE;
+    RequestType.Type = BMREQUEST_CLASS;
+    RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
+
+    Status = USBH_Transact(HubExtension,
+                           NULL,
+                           0,
+                           BMREQUEST_HOST_TO_DEVICE,
+                           URB_FUNCTION_CLASS_OTHER,
+                           RequestType,
+                           USB_REQUEST_SET_FEATURE,
+                           USBHUB_FEATURE_PORT_POWER,
+                           Port);
+
+    if (NT_SUCCESS(Status))
+    {
+        if (IsWait)
+        {
+            HubDescriptor = HubExtension->HubDescriptor;
+            USBH_Wait(2 * HubDescriptor->bPowerOnToPowerGood);
+        }
+
+        PortStatus->UsbPortStatus.Usb20PortStatus.CurrentConnectStatus = 1;
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncPowerOnPorts(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    PUSB_HUB_DESCRIPTOR HubDescriptor;
+    NTSTATUS Status = STATUS_UNSUCCESSFUL;
+    USHORT Port;
+    UCHAR NumberOfPorts;
+
+    DPRINT("USBH_SyncPowerOnPorts: ... \n");
+
+    HubDescriptor = HubExtension->HubDescriptor;
+    NumberOfPorts = HubDescriptor->bNumberOfPorts;
+
+    for (Port = 1; Port <= NumberOfPorts; ++Port)
+    {
+        Status = USBH_SyncPowerOnPort(HubExtension, Port, 0);
+
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("USBH_SyncPowerOnPorts: USBH_SyncPowerOnPort() failed - %lX\n",
+                    Status);
+            break;
+        }
+    }
+
+    USBH_Wait(2 * HubDescriptor->bPowerOnToPowerGood);
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_SyncDisablePort(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                     IN USHORT Port)
+{
+    PUSBHUB_PORT_DATA PortData;
+    NTSTATUS Status;
+    BM_REQUEST_TYPE RequestType;
+
+    DPRINT("USBH_SyncDisablePort ... \n");
+
+    PortData = &HubExtension->PortData[Port - 1];
+
+    RequestType.B = 0;
+    RequestType.Recipient = BMREQUEST_TO_DEVICE;
+    RequestType.Type = BMREQUEST_CLASS;
+    RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
+
+    Status = USBH_Transact(HubExtension,
+                           NULL,
+                           0,
+                           BMREQUEST_HOST_TO_DEVICE,
+                           URB_FUNCTION_CLASS_OTHER,
+                           RequestType,
+                           USB_REQUEST_CLEAR_FEATURE,
+                           USBHUB_FEATURE_PORT_ENABLE,
+                           Port);
+
+    if (NT_SUCCESS(Status))
+    {
+        PortData->PortStatus.UsbPortStatus.Usb20PortStatus.PortEnabledDisabled = 0;
+    }
+
+    return Status;
+}
+
+BOOLEAN
+NTAPI
+USBH_HubIsBusPowered(IN PDEVICE_OBJECT DeviceObject,
+                     IN PUSB_CONFIGURATION_DESCRIPTOR HubConfigDescriptor)
+{
+    BOOLEAN Result;
+    USHORT UsbStatus;
+    NTSTATUS Status;
+
+    DPRINT("USBH_HubIsBusPowered: ... \n");
+
+    Status = USBH_SyncGetStatus(DeviceObject,
+                                &UsbStatus,
+                                URB_FUNCTION_GET_STATUS_FROM_DEVICE,
+                                0);
+
+    if (!NT_SUCCESS(Status))
+    {
+        Result = (HubConfigDescriptor->bmAttributes & USB_CONFIG_POWERED_MASK)
+                                                   == USB_CONFIG_BUS_POWERED;
+    }
+    else
+    {
+        Result = (UsbStatus & USB_GETSTATUS_SELF_POWERED) == 0;
+    }
+
+    return Result;
+}
+
+NTSTATUS
+NTAPI
+USBH_ChangeIndicationAckChangeComplete(IN PDEVICE_OBJECT DeviceObject,
+                                       IN PIRP Irp,
+                                       IN PVOID Context)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    PVOID Event;
+    USHORT Port;
+
+    HubExtension = Context;
+
+    DPRINT_SCE("USBH_ChangeIndicationAckChangeComplete: ... \n");
+
+    ASSERT(HubExtension->Port > 0);
+    Port = HubExtension->Port - 1;
+
+    HubExtension->PortData[Port].PortStatus = HubExtension->PortStatus;
+
+    Event = InterlockedExchangePointer((PVOID)&HubExtension->pResetPortEvent,
+                                       NULL);
+
+    if (Event)
+    {
+        KeSetEvent(Event, EVENT_INCREMENT, FALSE);
+    }
+
+    USBH_SubmitStatusChangeTransfer(HubExtension);
+
+    if (!InterlockedDecrement(&HubExtension->ResetRequestCount))
+    {
+        KeSetEvent(&HubExtension->ResetEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+    }
+
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+NTAPI
+USBH_ChangeIndicationAckChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                               IN PIRP Irp,
+                               IN struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb,
+                               IN USHORT Port,
+                               IN USHORT RequestValue)
+{
+    PIO_STACK_LOCATION IoStack;
+    BM_REQUEST_TYPE RequestType;
+
+    DPRINT_SCE("USBH_ChangeIndicationAckChange: ... \n");
+
+    Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
+    Urb->Hdr.Function = URB_FUNCTION_CLASS_OTHER;
+    Urb->Hdr.UsbdDeviceHandle = NULL;
+
+    Urb->TransferFlags = USBD_SHORT_TRANSFER_OK;
+    Urb->TransferBufferLength = 0;
+    Urb->TransferBuffer = NULL;
+    Urb->TransferBufferMDL = NULL;
+    Urb->UrbLink = NULL;
+
+    RequestType.B = 0;
+    RequestType.Recipient = BMREQUEST_TO_OTHER;
+    RequestType.Type = BMREQUEST_CLASS;
+    RequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
+
+    Urb->RequestTypeReservedBits = RequestType.B;
+    Urb->Request = USB_REQUEST_CLEAR_FEATURE;
+    Urb->Index = Port;
+    Urb->Value = RequestValue;
+
+    IoInitializeIrp(Irp,
+                    IoSizeOfIrp(HubExtension->LowerDevice->StackSize),
+                    HubExtension->LowerDevice->StackSize);
+
+    IoStack = IoGetNextIrpStackLocation(Irp);
+
+    IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+    IoStack->Parameters.Others.Argument1 = Urb;
+    IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+
+    IoSetCompletionRoutine(Irp,
+                           USBH_ChangeIndicationAckChangeComplete,
+                           HubExtension,
+                           TRUE,
+                           TRUE,
+                           TRUE);
+
+    return IoCallDriver(HubExtension->LowerDevice, Irp);
+}
+
+NTSTATUS
+NTAPI
+USBH_ChangeIndicationProcessChange(IN PDEVICE_OBJECT DeviceObject,
+                                   IN PIRP Irp,
+                                   IN PVOID Context)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    PUSBHUB_IO_WORK_ITEM WorkItem;
+    USHORT RequestValue;
+
+    HubExtension = Context;
+
+    DPRINT_SCE("USBH_ChangeIndicationProcessChange: PortStatus - %lX\n",
+               HubExtension->PortStatus.AsULONG);
+
+    if ((NT_SUCCESS(Irp->IoStatus.Status) ||
+        USBD_SUCCESS(HubExtension->SCEWorkerUrb.Hdr.Status)) &&
+        (HubExtension->PortStatus.UsbPortStatusChange.ResetChange ||
+         HubExtension->PortStatus.UsbPortStatusChange.PortEnableDisableChange))
+    {
+        if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+        {
+            KeSetEvent(&HubExtension->PendingRequestEvent,
+                       EVENT_INCREMENT,
+                       FALSE);
+        }
+
+        USBH_FreeWorkItem(HubExtension->WorkItemToQueue);
+
+        HubExtension->WorkItemToQueue = NULL;
+
+        if (HubExtension->PortStatus.UsbPortStatusChange.ResetChange)
+        {
+           RequestValue = USBHUB_FEATURE_C_PORT_RESET;
+        }
+        else
+        {
+            RequestValue = USBHUB_FEATURE_C_PORT_ENABLE;
+        }
+
+        USBH_ChangeIndicationAckChange(HubExtension,
+                                       HubExtension->ResetPortIrp,
+                                       &HubExtension->SCEWorkerUrb,
+                                       HubExtension->Port,
+                                       RequestValue);
+    }
+    else
+    {
+        ASSERT(HubExtension->WorkItemToQueue != NULL);
+
+        WorkItem = HubExtension->WorkItemToQueue;
+        HubExtension->WorkItemToQueue = NULL;
+
+        USBH_QueueWorkItem(HubExtension, WorkItem);
+    }
+
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+NTAPI
+USBH_ChangeIndicationQueryChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                                 IN PIRP Irp,
+                                 IN struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb,
+                                 IN USHORT Port)
+{
+    PUSBHUB_IO_WORK_ITEM WorkItem;
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IoStack;
+    BM_REQUEST_TYPE RequestType;
+
+    DPRINT_SCE("USBH_ChangeIndicationQueryChange: Port - %x\n", Port);
+
+    InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+    if (!Port)
+    {
+        ASSERT(HubExtension->WorkItemToQueue != NULL);
+
+        WorkItem = HubExtension->WorkItemToQueue;
+        HubExtension->WorkItemToQueue = NULL;
+
+        USBH_QueueWorkItem(HubExtension, WorkItem);
+
+        return STATUS_SUCCESS;
+    }
+
+    Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
+    Urb->Hdr.UsbdDeviceHandle = NULL;
+    Urb->Hdr.Function = URB_FUNCTION_CLASS_OTHER;
+
+    Urb->TransferFlags = USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN;
+    Urb->TransferBuffer = &HubExtension->PortStatus;
+    Urb->TransferBufferLength = sizeof(HubExtension->PortStatus);
+    Urb->TransferBufferMDL = NULL;
+    Urb->UrbLink = NULL;
+
+    RequestType.B = 0;
+    RequestType.Recipient = BMREQUEST_TO_OTHER;
+    RequestType.Type = BMREQUEST_CLASS;
+    RequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
+
+    Urb->RequestTypeReservedBits = RequestType.B;
+    Urb->Request = USB_REQUEST_GET_STATUS;
+    Urb->Value = 0;
+    Urb->Index = Port;
+
+    HubExtension->Port = Port;
+
+    IoInitializeIrp(Irp,
+                    IoSizeOfIrp(HubExtension->LowerDevice->StackSize),
+                    HubExtension->LowerDevice->StackSize);
+
+    IoStack = IoGetNextIrpStackLocation(Irp);
+
+    IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+    IoStack->Parameters.Others.Argument1 = Urb;
+    IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+
+    IoSetCompletionRoutine(Irp,
+                           USBH_ChangeIndicationProcessChange,
+                           HubExtension,
+                           TRUE,
+                           TRUE,
+                           TRUE);
+
+    Status = IoCallDriver(HubExtension->LowerDevice, Irp);
+
+    return Status;
+}
+
+VOID
+NTAPI
+USBH_ProcessPortStateChange(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                            IN USHORT Port,
+                            IN PUSBHUB_PORT_STATUS PortStatus)
+{
+    PUSBHUB_PORT_DATA PortData;
+    USB_PORT_STATUS_CHANGE PortStatusChange;
+    PDEVICE_OBJECT PortDevice;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    PVOID SerialNumber;
+    PVOID DeviceHandle;
+    USHORT RequestValue;
+    KIRQL Irql;
+
+    DPRINT_SCE("USBH_ProcessPortStateChange ... \n");
+
+    ASSERT(Port > 0);
+    PortData = &HubExtension->PortData[Port - 1];
+
+    PortStatusChange = PortStatus->UsbPortStatusChange;
+
+    if (PortStatusChange.ConnectStatusChange)
+    {
+        PortData->PortStatus.AsULONG = *(PULONG)PortStatus;
+
+        USBH_SyncClearPortStatus(HubExtension,
+                                 Port,
+                                 USBHUB_FEATURE_C_PORT_CONNECTION);
+
+        PortData = &HubExtension->PortData[Port - 1];
+
+        PortDevice = PortData->DeviceObject;
+
+        if (!PortDevice)
+        {
+            IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
+            return;
+        }
+
+        PortExtension = PortDevice->DeviceExtension;
+
+        if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_OVERCURRENT_PORT)
+        {
+            return;
+        }
+
+        KeAcquireSpinLock(&HubExtension->RelationsWorkerSpinLock, &Irql);
+
+        if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3)
+        {
+            KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, Irql);
+            IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
+            return;
+        }
+
+        PortData->DeviceObject = NULL;
+        PortData->ConnectionStatus = NoDeviceConnected;
+
+        HubExtension->HubFlags |= USBHUB_FDO_FLAG_STATE_CHANGING;
+
+        InsertTailList(&HubExtension->PdoList, &PortExtension->PortLink);
+
+        KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, Irql);
+
+        SerialNumber = InterlockedExchangePointer((PVOID)&PortExtension->SerialNumber,
+                                                  NULL);
+
+        if (SerialNumber)
+        {
+            ExFreePoolWithTag(SerialNumber, USB_HUB_TAG);
+        }
+
+        DeviceHandle = InterlockedExchangePointer(&PortExtension->DeviceHandle,
+                                                  NULL);
+
+        if (DeviceHandle)
+        {
+            USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0);
+            USBH_SyncDisablePort(HubExtension, Port);
+        }
+
+        IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
+    }
+    else if (PortStatusChange.PortEnableDisableChange)
+    {
+        RequestValue = USBHUB_FEATURE_C_PORT_ENABLE;
+        PortData->PortStatus = *PortStatus;
+        USBH_SyncClearPortStatus(HubExtension, Port, RequestValue);
+        return;
+    }
+    else if (PortStatusChange.SuspendChange)
+    {
+        DPRINT1("USBH_ProcessPortStateChange: SuspendChange UNIMPLEMENTED. FIXME\n");
+        DbgBreakPoint();
+    }
+    else if (PortStatusChange.OverCurrentIndicatorChange)
+    {
+        DPRINT1("USBH_ProcessPortStateChange: OverCurrentIndicatorChange UNIMPLEMENTED. FIXME\n");
+        DbgBreakPoint();
+    }
+    else if (PortStatusChange.ResetChange)
+    {
+        RequestValue = USBHUB_FEATURE_C_PORT_RESET;
+        PortData->PortStatus = *PortStatus;
+        USBH_SyncClearPortStatus(HubExtension, Port, RequestValue);
+    }
+}
+
+NTSTATUS
+NTAPI
+USBH_GetPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                   IN PULONG PortStatus)
+{
+    PIRP Irp;
+    PIO_STACK_LOCATION IoStack;
+    NTSTATUS Status;
+    KEVENT Event;
+    IO_STATUS_BLOCK IoStatusBlock;
+
+    DPRINT("USBH_GetPortStatus ... \n");
+
+    *PortStatus = 0;
+
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_PORT_STATUS,
+                                        HubExtension->LowerDevice,
+                                        NULL,
+                                        0,
+                                        NULL,
+                                        0,
+                                        TRUE,
+                                        &Event,
+                                        &IoStatusBlock);
+
+    if (!Irp)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    IoStack = IoGetNextIrpStackLocation(Irp);
+    IoStack->Parameters.Others.Argument1 = PortStatus;
+
+    Status = IoCallDriver(HubExtension->LowerDevice, Irp);
+
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+    else
+    {
+        IoStatusBlock.Status = Status;
+    }
+
+    return IoStatusBlock.Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_EnableParentPort(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    PIRP Irp;
+    NTSTATUS Status;
+    KEVENT Event;
+    IO_STATUS_BLOCK IoStatusBlock;
+
+    DPRINT("USBH_EnableParentPort ... \n");
+
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_ENABLE_PORT,
+                                        HubExtension->LowerDevice,
+                                        NULL,
+                                        0,
+                                        NULL,
+                                        0,
+                                        TRUE,
+                                        &Event,
+                                        &IoStatusBlock);
+
+    if (!Irp)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Status = IoCallDriver(HubExtension->LowerDevice, Irp);
+
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event,
+                              Suspended,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+    else
+    {
+        IoStatusBlock.Status = Status;
+    }
+
+    return IoStatusBlock.Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_ResetInterruptPipe(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    struct _URB_PIPE_REQUEST * Urb;
+    NTSTATUS Status;
+
+    DPRINT("USBH_ResetInterruptPipe ... \n");
+
+    Urb = ExAllocatePoolWithTag(NonPagedPool,
+                                sizeof(struct _URB_PIPE_REQUEST),
+                                USB_HUB_TAG);
+
+    if (Urb)
+    {
+        RtlZeroMemory(Urb, sizeof(struct _URB_PIPE_REQUEST));
+
+        Urb->Hdr.Length = sizeof(struct _URB_PIPE_REQUEST);
+        Urb->Hdr.Function = URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL;
+        Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle;
+
+        Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice,
+                                       (PURB)Urb);
+
+        ExFreePoolWithTag(Urb, USB_HUB_TAG);
+    }
+    else
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    if (NT_SUCCESS(Status))
+    {
+        HubExtension->RequestErrors = 0;
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_ResetHub(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    NTSTATUS Status;
+    ULONG PortStatusFlags = 0;
+
+    DPRINT("USBH_ResetHub: ... \n");
+
+    Status = USBH_GetPortStatus(HubExtension, &PortStatusFlags);
+
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    if (!(PortStatusFlags & USBD_PORT_ENABLED))
+    {
+        if (PortStatusFlags & USBD_PORT_CONNECTED)
+        {
+            USBH_EnableParentPort(HubExtension);
+        }
+    }
+
+    Status = USBH_ResetInterruptPipe(HubExtension);
+
+    return Status;
+}
+
+VOID
+NTAPI
+USBH_ChangeIndicationWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                            IN PVOID Context)
+{
+    PUSBHUB_FDO_EXTENSION LowerHubExtension;
+    PUSBHUB_PORT_PDO_EXTENSION LowerPortExtension;
+    PUSBHUB_STATUS_CHANGE_CONTEXT WorkItem;
+    USBHUB_PORT_STATUS PortStatus;
+    NTSTATUS Status;
+    USHORT Port = 0;
+
+    DPRINT_SCE("USBH_ChangeIndicationWorker ... \n");
+
+    WorkItem = Context;
+
+    KeWaitForSingleObject(&HubExtension->HubSemaphore,
+                          Executive,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING)
+    {
+        KeSetEvent(&HubExtension->StatusChangeEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+
+        goto Exit;
+    }
+
+    if (!HubExtension->RequestErrors)
+    {
+        goto Enum;
+    }
+
+    DPRINT_SCE("USBH_ChangeIndicationWorker: RequestErrors - %x\n",
+               HubExtension->RequestErrors);
+
+    if (HubExtension->LowerPDO == HubExtension->RootHubPdo)
+    {
+        goto Enum;
+    }
+
+    LowerPortExtension = HubExtension->LowerPDO->DeviceExtension;
+
+    if (LowerPortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D1_OR_D2)
+    {
+        goto Enum;
+    }
+
+    LowerHubExtension = LowerPortExtension->HubExtension;
+
+    if (!LowerHubExtension)
+    {
+        goto Enum;
+    }
+
+    Status = USBH_SyncGetPortStatus(LowerHubExtension,
+                                    LowerPortExtension->PortNumber,
+                                    &PortStatus,
+                                    sizeof(USBHUB_PORT_STATUS));
+
+    if (!NT_SUCCESS(Status) ||
+        !PortStatus.UsbPortStatus.Usb20PortStatus.CurrentConnectStatus)
+    {
+        HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_REMOVED;
+
+        KeSetEvent(&HubExtension->StatusChangeEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+
+        goto Exit;
+    }
+
+    if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING))
+    {
+        HubExtension->HubFlags |= USBHUB_FDO_FLAG_ESD_RECOVERING;
+
+        DPRINT1("USBH_ChangeIndicationWorker: USBHUB_FDO_FLAG_ESD_RECOVERING FIXME\n");
+        DbgBreakPoint();
+
+        goto Exit;
+    }
+
+Enum:
+
+    if (WorkItem->IsRequestErrors)
+    {
+        USBH_ResetHub(HubExtension);
+    }
+    else
+    {
+        for (Port = 0;
+             Port < HubExtension->HubDescriptor->bNumberOfPorts;
+             Port++)
+        {
+            if (IsBitSet((PUCHAR)(WorkItem + 1), Port))
+            {
+                break;
+            }
+        }
+
+        if (Port)
+        {
+            Status = USBH_SyncGetPortStatus(HubExtension,
+                                            Port,
+                                            &PortStatus,
+                                            sizeof(USBHUB_PORT_STATUS));
+        }
+        else
+        {
+            DPRINT1("USBH_ChangeIndicationWorker: USBH_SyncGetHubStatus() UNIMPLEMENTED. FIXME\n");
+            DbgBreakPoint();
+            Status = STATUS_ASSERTION_FAILURE;
+        }
+
+        if (NT_SUCCESS(Status))
+        {
+            if (Port)
+            {
+                USBH_ProcessPortStateChange(HubExtension,
+                                            Port,
+                                            &PortStatus);
+            }
+            else
+            {
+                 DPRINT1("USBH_ChangeIndicationWorker: USBH_ProcessHubStateChange() UNIMPLEMENTED. FIXME\n");
+                 DbgBreakPoint();
+            }
+        }
+        else
+        {
+            HubExtension->RequestErrors++;
+
+            if (HubExtension->RequestErrors > USBHUB_MAX_REQUEST_ERRORS)
+            {
+                HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
+                goto Exit;
+            }
+        }
+    }
+
+    USBH_SubmitStatusChangeTransfer(HubExtension);
+
+Exit:
+
+    KeReleaseSemaphore(&HubExtension->HubSemaphore,
+                       LOW_REALTIME_PRIORITY,
+                       1,
+                       FALSE);
+
+    if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+    {
+        KeSetEvent(&HubExtension->PendingRequestEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+    }
+
+    if (!InterlockedDecrement((PLONG)&HubExtension->ResetRequestCount))
+    {
+        KeSetEvent(&HubExtension->ResetEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+
+        if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEFER_CHECK_IDLE)
+        {
+            USBH_CheckHubIdle(HubExtension);
+        }
+    }
+}
+
+NTSTATUS
+NTAPI
+USBH_ChangeIndication(IN PDEVICE_OBJECT DeviceObject,
+                      IN PIRP Irp,
+                      IN PVOID Context)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    USBD_STATUS UrbStatus;
+    BOOLEAN IsErrors = FALSE;
+    PUSBHUB_IO_WORK_ITEM HubWorkItem;
+    PUSBHUB_STATUS_CHANGE_CONTEXT HubWorkItemBuffer;
+    USHORT NumPorts;
+    USHORT Port;
+    NTSTATUS Status;
+    PVOID Bitmap;
+    ULONG BufferLength;
+
+    HubExtension = Context;
+    UrbStatus = HubExtension->SCEWorkerUrb.Hdr.Status;
+
+    DPRINT_SCE("USBH_ChangeIndication: IrpStatus - %x, UrbStatus - %x, HubFlags - %lX\n",
+               Irp->IoStatus.Status,
+               UrbStatus,
+               HubExtension->HubFlags);
+
+    if (NT_ERROR(Irp->IoStatus.Status) || USBD_ERROR(UrbStatus) ||
+       (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED) ||
+       (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING))
+    {
+        HubExtension->RequestErrors++;
+
+        IsErrors = TRUE;
+
+        KeSetEvent(&HubExtension->StatusChangeEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+
+        if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING ||
+            HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED ||
+            HubExtension->RequestErrors > USBHUB_MAX_REQUEST_ERRORS ||
+            Irp->IoStatus.Status == STATUS_DELETE_PENDING)
+        {
+            DPRINT_SCE("USBH_ChangeIndication: HubExtension->RequestErrors - %x\n",
+                       HubExtension->RequestErrors);
+
+            return STATUS_MORE_PROCESSING_REQUIRED;
+        }
+
+        DPRINT_SCE("USBH_ChangeIndication: HubExtension->RequestErrors - %x\n",
+                   HubExtension->RequestErrors);
+    }
+    else
+    {
+        HubExtension->RequestErrors = 0;
+    }
+
+    BufferLength = sizeof(USBHUB_STATUS_CHANGE_CONTEXT) +
+                   HubExtension->SCEBitmapLength;
+
+    Status = USBH_AllocateWorkItem(HubExtension,
+                                   &HubWorkItem,
+                                   USBH_ChangeIndicationWorker,
+                                   BufferLength,
+                                   (PVOID *)&HubWorkItemBuffer,
+                                   DelayedWorkQueue);
+
+    if (!NT_SUCCESS(Status))
+    {
+        return STATUS_MORE_PROCESSING_REQUIRED;
+    }
+
+    RtlZeroMemory(HubWorkItemBuffer, BufferLength);
+
+    HubWorkItemBuffer->IsRequestErrors = FALSE;
+
+    if (IsErrors)
+    {
+        HubWorkItemBuffer->IsRequestErrors = TRUE;
+    }
+
+    if (InterlockedIncrement(&HubExtension->ResetRequestCount) == 1)
+    {
+        KeResetEvent(&HubExtension->ResetEvent);
+    }
+
+    HubWorkItemBuffer->HubExtension = HubExtension;
+
+    HubExtension->WorkItemToQueue = HubWorkItem;
+
+    Bitmap = HubWorkItemBuffer + 1;
+
+    RtlCopyMemory(Bitmap,
+                  HubExtension->SCEBitmap,
+                  HubExtension->SCEBitmapLength);
+
+    NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+
+    for (Port = 0; Port <= NumPorts; ++Port)
+    {
+        if (IsBitSet(Bitmap, Port))
+        {
+            break;
+        }
+    }
+
+    if (Port > NumPorts)
+    {
+        Port = 0;
+    }
+
+    Status = USBH_ChangeIndicationQueryChange(HubExtension,
+                                              HubExtension->ResetPortIrp,
+                                              &HubExtension->SCEWorkerUrb,
+                                              Port);
+
+    if (NT_ERROR(Status))
+    {
+        HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED;
+    }
+
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+NTAPI
+USBH_SubmitStatusChangeTransfer(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    PIRP Irp;
+    NTSTATUS Status;
+    struct _URB_BULK_OR_INTERRUPT_TRANSFER * Urb;
+    PIO_STACK_LOCATION IoStack;
+
+    DPRINT_SCE("USBH_SubmitStatusChangeTransfer: HubExtension - %p, SCEIrp - %p\n",
+               HubExtension,
+               HubExtension->SCEIrp);
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_NOT_D0_STATE)
+    {
+        DPRINT_SCE("USBH_SubmitStatusChangeTransfer: USBHUB_FDO_FLAG_NOT_D0_STATE\n");
+        DPRINT_SCE("USBH_SubmitStatusChangeTransfer: HubFlags - %lX\n",
+                   HubExtension->HubFlags);
+
+        return STATUS_INVALID_DEVICE_STATE;
+    }
+
+    Irp = HubExtension->SCEIrp;
+
+    if (!Irp)
+    {
+        return STATUS_INVALID_DEVICE_STATE;
+    }
+
+    Urb = (struct _URB_BULK_OR_INTERRUPT_TRANSFER *)&HubExtension->SCEWorkerUrb;
+
+    Urb->Hdr.Length = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
+    Urb->Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
+    Urb->Hdr.UsbdDeviceHandle = NULL;
+
+    Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle;
+    Urb->TransferFlags = USBD_SHORT_TRANSFER_OK;
+    Urb->TransferBuffer = HubExtension->SCEBitmap;
+    Urb->TransferBufferLength = HubExtension->SCEBitmapLength;
+    Urb->TransferBufferMDL = NULL;
+    Urb->UrbLink = NULL;
+
+    IoInitializeIrp(Irp,
+                    IoSizeOfIrp(HubExtension->LowerDevice->StackSize),
+                    HubExtension->LowerDevice->StackSize);
+
+    IoStack = IoGetNextIrpStackLocation(Irp);
+
+    IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+    IoStack->Parameters.Others.Argument1 = &HubExtension->SCEWorkerUrb;
+    IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+
+    IoSetCompletionRoutine(Irp,
+                           USBH_ChangeIndication,
+                           HubExtension,
+                           TRUE,
+                           TRUE,
+                           TRUE);
+
+    KeResetEvent(&HubExtension->StatusChangeEvent);
+
+    Status = IoCallDriver(HubExtension->LowerDevice, Irp);
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBD_CreateDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                    IN PUSB_DEVICE_HANDLE * OutDeviceHandle,
+                    IN USB_PORT_STATUS UsbPortStatus,
+                    IN USHORT Port)
+{
+    PUSB_DEVICE_HANDLE HubDeviceHandle;
+    PUSB_BUSIFFN_CREATE_USB_DEVICE CreateUsbDevice;
+
+    DPRINT("USBD_CreateDeviceEx: Port - %x, UsbPortStatus - 0x%04X\n",
+           Port,
+           UsbPortStatus.AsUshort16);
+
+    CreateUsbDevice = HubExtension->BusInterface.CreateUsbDevice;
+
+    if (!CreateUsbDevice)
+    {
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    HubDeviceHandle = USBH_SyncGetDeviceHandle(HubExtension->LowerDevice);
+
+    return CreateUsbDevice(HubExtension->BusInterface.BusContext,
+                           OutDeviceHandle,
+                           HubDeviceHandle,
+                           UsbPortStatus.AsUshort16,
+                           Port);
+}
+
+NTSTATUS
+NTAPI
+USBD_RemoveDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                    IN PUSB_DEVICE_HANDLE DeviceHandle,
+                    IN ULONG Flags)
+{
+    PUSB_BUSIFFN_REMOVE_USB_DEVICE RemoveUsbDevice;
+
+    DPRINT("USBD_RemoveDeviceEx: DeviceHandle - %p, Flags - %X\n",
+           DeviceHandle,
+           Flags);
+
+    RemoveUsbDevice = HubExtension->BusInterface.RemoveUsbDevice;
+
+    if (!RemoveUsbDevice)
+    {
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    return RemoveUsbDevice(HubExtension->BusInterface.BusContext,
+                           DeviceHandle,
+                           Flags);
+}
+
+NTSTATUS
+NTAPI
+USBD_InitializeDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                        IN PUSB_DEVICE_HANDLE DeviceHandle,
+                        IN PUCHAR DeviceDescriptorBuffer,
+                        IN ULONG DeviceDescriptorBufferLength,
+                        IN PUCHAR ConfigDescriptorBuffer,
+                        IN ULONG ConfigDescriptorBufferLength)
+{
+    NTSTATUS Status;
+    PUSB_BUSIFFN_INITIALIZE_USB_DEVICE InitializeUsbDevice;
+    PUSB_BUSIFFN_GET_USB_DESCRIPTORS GetUsbDescriptors;
+
+    DPRINT("USBD_InitializeDeviceEx: ... \n");
+
+    InitializeUsbDevice = HubExtension->BusInterface.InitializeUsbDevice;
+    GetUsbDescriptors = HubExtension->BusInterface.GetUsbDescriptors;
+
+    if (!InitializeUsbDevice || !GetUsbDescriptors)
+    {
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    Status = InitializeUsbDevice(HubExtension->BusInterface.BusContext,
+                                 DeviceHandle);
+
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    return GetUsbDescriptors(HubExtension->BusInterface.BusContext,
+                             DeviceHandle,
+                             DeviceDescriptorBuffer,
+                             &DeviceDescriptorBufferLength,
+                             ConfigDescriptorBuffer,
+                             &ConfigDescriptorBufferLength);
+}
+
+VOID
+NTAPI
+USBHUB_SetDeviceHandleData(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                           IN PDEVICE_OBJECT UsbDevicePdo,
+                           IN PVOID DeviceHandle)
+{
+    PUSB_BUSIFFN_SET_DEVHANDLE_DATA SetDeviceHandleData;
+
+    DPRINT("USBHUB_SetDeviceHandleData ... \n");
+
+    SetDeviceHandleData = HubExtension->BusInterface.SetDeviceHandleData;
+
+    if (!SetDeviceHandleData)
+    {
+        return;
+    }
+
+    SetDeviceHandleData(HubExtension->BusInterface.BusContext,
+                        DeviceHandle,
+                        UsbDevicePdo);
+}
+
+VOID
+NTAPI
+USBHUB_FlushAllTransfers(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    PUSB_BUSIFFN_FLUSH_TRANSFERS FlushTransfers;
+
+    DPRINT("USBHUB_FlushAllTransfers ... \n");
+
+    FlushTransfers = HubExtension->BusInterface.FlushTransfers;
+
+    if (FlushTransfers)
+    {
+        FlushTransfers(HubExtension->BusInterface.BusContext, NULL);
+    }
+}
+
+NTSTATUS
+NTAPI
+USBD_GetDeviceInformationEx(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension,
+                            IN PUSBHUB_FDO_EXTENSION HubExtension,
+                            IN PUSB_NODE_CONNECTION_INFORMATION_EX Info,
+                            IN ULONG Length,
+                            IN PUSB_DEVICE_HANDLE DeviceHandle)
+{
+    PUSB_BUSIFFN_GET_DEVICE_INFORMATION QueryDeviceInformation;
+    PUSB_DEVICE_INFORMATION_0 DeviceInfo;
+    SIZE_T DeviceInfoLength;
+    PUSB_NODE_CONNECTION_INFORMATION_EX NodeInfo;
+    SIZE_T NodeInfoLength;
+    ULONG PipeNumber;
+    ULONG dummy;
+    NTSTATUS Status;
+
+    DPRINT("USBD_GetDeviceInformationEx ... \n");
+
+    QueryDeviceInformation = HubExtension->BusInterface.QueryDeviceInformation;
+
+    if (!QueryDeviceInformation)
+    {
+        Status = STATUS_NOT_IMPLEMENTED;
+        return Status;
+    }
+
+    DeviceInfoLength = sizeof(USB_DEVICE_INFORMATION_0);
+
+    while (TRUE)
+    {
+        DeviceInfo = ExAllocatePoolWithTag(PagedPool,
+                                           DeviceInfoLength,
+                                           USB_HUB_TAG);
+
+        if (!DeviceInfo)
+        {
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        RtlZeroMemory(DeviceInfo, DeviceInfoLength);
+
+        DeviceInfo->InformationLevel = 0;
+
+        Status = QueryDeviceInformation(HubExtension->BusInterface.BusContext,
+                                        DeviceHandle,
+                                        DeviceInfo,
+                                        DeviceInfoLength,
+                                        &dummy);
+
+        if (Status != STATUS_BUFFER_TOO_SMALL)
+        {
+            break;
+        }
+
+        DeviceInfoLength = DeviceInfo->ActualLength;
+
+        ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
+    }
+
+    NodeInfo = NULL;
+    NodeInfoLength = 0;
+
+    if (NT_SUCCESS(Status))
+    {
+        NodeInfoLength = (sizeof(USB_NODE_CONNECTION_INFORMATION_EX) - sizeof(USB_PIPE_INFO)) +
+                         DeviceInfo->NumberOfOpenPipes * sizeof(USB_PIPE_INFO);
+
+        NodeInfo = ExAllocatePoolWithTag(PagedPool, NodeInfoLength, USB_HUB_TAG);
+
+        if (!NodeInfo)
+        {
+            ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        RtlZeroMemory(NodeInfo, NodeInfoLength);
+
+        NodeInfo->ConnectionIndex = Info->ConnectionIndex;
+
+        RtlCopyMemory(&NodeInfo->DeviceDescriptor,
+                      &DeviceInfo->DeviceDescriptor,
+                      sizeof(USB_DEVICE_DESCRIPTOR));
+
+        NodeInfo->CurrentConfigurationValue = DeviceInfo->CurrentConfigurationValue;
+        NodeInfo->Speed = DeviceInfo->DeviceSpeed;
+        NodeInfo->DeviceIsHub = PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE;
+        NodeInfo->DeviceAddress = DeviceInfo->DeviceAddress;
+        NodeInfo->NumberOfOpenPipes = DeviceInfo->NumberOfOpenPipes;
+        NodeInfo->ConnectionStatus = Info->ConnectionStatus;
+
+        for (PipeNumber = 0;
+             PipeNumber < DeviceInfo->NumberOfOpenPipes;
+             PipeNumber++)
+        {
+            RtlCopyMemory(&NodeInfo->PipeList[PipeNumber],
+                          &DeviceInfo->PipeList[PipeNumber],
+                          sizeof(USB_PIPE_INFO));
+        }
+    }
+
+    ExFreePoolWithTag(DeviceInfo, USB_HUB_TAG);
+
+    if (NodeInfo)
+    {
+        if (NodeInfoLength <= Length)
+        {
+            Length = NodeInfoLength;
+        }
+        else
+        {
+            Status = STATUS_BUFFER_TOO_SMALL;
+        }
+
+        RtlCopyMemory(Info, NodeInfo, Length);
+
+        ExFreePoolWithTag(NodeInfo, USB_HUB_TAG);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBD_RestoreDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                     IN OUT PUSB_DEVICE_HANDLE OldDeviceHandle,
+                     IN OUT PUSB_DEVICE_HANDLE NewDeviceHandle)
+{
+    PUSB_BUSIFFN_RESTORE_DEVICE RestoreUsbDevice;
+    NTSTATUS Status;
+
+    DPRINT("USBD_RestoreDeviceEx: HubExtension - %p, OldDeviceHandle - %p, NewDeviceHandle - %p\n",
+           HubExtension,
+           OldDeviceHandle,
+           NewDeviceHandle);
+
+    RestoreUsbDevice = HubExtension->BusInterface.RestoreUsbDevice;
+
+    if (RestoreUsbDevice)
+    {
+        Status = RestoreUsbDevice(HubExtension->BusInterface.BusContext,
+                                  OldDeviceHandle,
+                                  NewDeviceHandle);
+    }
+    else
+    {
+        Status = STATUS_NOT_IMPLEMENTED;
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_AllocateWorkItem(PUSBHUB_FDO_EXTENSION HubExtension,
+                      PUSBHUB_IO_WORK_ITEM * OutHubIoWorkItem,
+                      PUSBHUB_WORKER_ROUTINE WorkerRoutine,
+                      SIZE_T BufferLength,
+                      PVOID * OutHubWorkItemBuffer,
+                      WORK_QUEUE_TYPE Type)
+{
+    PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
+    PIO_WORKITEM WorkItem;
+    PVOID WorkItemBuffer;
+
+    DPRINT("USBH_AllocateWorkItem: ... \n");
+
+    if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_WITEM_INIT))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    HubIoWorkItem = ExAllocatePoolWithTag(NonPagedPool,
+                                          sizeof(USBHUB_IO_WORK_ITEM),
+                                          USB_HUB_TAG);
+
+    if (!HubIoWorkItem)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(HubIoWorkItem, sizeof(USBHUB_IO_WORK_ITEM));
+
+    WorkItem = IoAllocateWorkItem(HubExtension->Common.SelfDevice);
+
+    HubIoWorkItem->HubWorkItem = WorkItem;
+
+    if (!WorkItem)
+    {
+        ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    if (BufferLength && OutHubWorkItemBuffer)
+    {
+        WorkItemBuffer = ExAllocatePoolWithTag(NonPagedPool,
+                                               BufferLength,
+                                               USB_HUB_TAG);
+
+        HubIoWorkItem->HubWorkItemBuffer = WorkItemBuffer;
+
+        if (!WorkItemBuffer)
+        {
+            IoFreeWorkItem(HubIoWorkItem->HubWorkItem);
+            ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
+
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        RtlZeroMemory(WorkItemBuffer, BufferLength);
+    }
+    else
+    {
+        HubIoWorkItem->HubWorkItemBuffer = NULL;
+    }
+
+    HubIoWorkItem->HubWorkItemType = Type;
+    HubIoWorkItem->HubExtension = HubExtension;
+    HubIoWorkItem->HubWorkerRoutine = WorkerRoutine;
+
+    if (OutHubIoWorkItem)
+    {
+        *OutHubIoWorkItem = HubIoWorkItem;
+    }
+
+    if (OutHubWorkItemBuffer)
+    {
+        *OutHubWorkItemBuffer = HubIoWorkItem->HubWorkItemBuffer;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+USBH_Worker(IN PDEVICE_OBJECT DeviceObject,
+            IN PVOID Context)
+{
+    PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    KIRQL OldIrql;
+    PIO_WORKITEM WorkItem;
+
+    DPRINT("USBH_Worker: HubIoWorkItem - %p\n", Context);
+
+    HubIoWorkItem = Context;
+
+    InterlockedDecrement(&HubIoWorkItem->HubWorkerQueued);
+
+    HubExtension = HubIoWorkItem->HubExtension;
+    WorkItem = HubIoWorkItem->HubWorkItem;
+
+    HubIoWorkItem->HubWorkerRoutine(HubIoWorkItem->HubExtension,
+                                    HubIoWorkItem->HubWorkItemBuffer);
+
+    KeAcquireSpinLock(&HubExtension->WorkItemSpinLock, &OldIrql);
+    RemoveEntryList(&HubIoWorkItem->HubWorkItemLink);
+    KeReleaseSpinLock(&HubExtension->WorkItemSpinLock, OldIrql);
+
+    if (HubIoWorkItem->HubWorkItemBuffer)
+    {
+        ExFreePoolWithTag(HubIoWorkItem->HubWorkItemBuffer, USB_HUB_TAG);
+    }
+
+    ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
+
+    if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+    {
+        KeSetEvent(&HubExtension->PendingRequestEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+    }
+
+    IoFreeWorkItem(WorkItem);
+
+    DPRINT("USBH_Worker: HubIoWorkItem %p complete\n", Context);
+}
+
+VOID
+NTAPI
+USBH_QueueWorkItem(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                   IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem)
+{
+    DPRINT("USBH_QueueWorkItem: ... \n");
+
+    InterlockedIncrement(&HubExtension->PendingRequestCount);
+    InterlockedIncrement(&HubIoWorkItem->HubWorkerQueued);
+
+    ExInterlockedInsertTailList(&HubExtension->WorkItemList,
+                                &HubIoWorkItem->HubWorkItemLink,
+                                &HubExtension->WorkItemSpinLock);
+
+    IoQueueWorkItem(HubIoWorkItem->HubWorkItem,
+                    USBH_Worker,
+                    HubIoWorkItem->HubWorkItemType,
+                    HubIoWorkItem);
+}
+
+VOID
+NTAPI
+USBH_FreeWorkItem(IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem)
+{
+    PIO_WORKITEM WorkItem;
+
+    DPRINT("USBH_FreeWorkItem: ... \n");
+
+    WorkItem = HubIoWorkItem->HubWorkItem;
+
+    if (HubIoWorkItem->HubWorkItemBuffer)
+    {
+        ExFreePoolWithTag(HubIoWorkItem->HubWorkItemBuffer, USB_HUB_TAG);
+    }
+
+    ExFreePoolWithTag(HubIoWorkItem, USB_HUB_TAG);
+
+    IoFreeWorkItem(WorkItem);
+}
+
+VOID
+NTAPI
+USBHUB_RootHubCallBack(IN PVOID Context)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+
+    DPRINT("USBHUB_RootHubCallBack: ... \n");
+
+    HubExtension = Context;
+
+    if (HubExtension->SCEIrp)
+    {
+        HubExtension->HubFlags |= (USBHUB_FDO_FLAG_DO_ENUMERATION |
+                                   USBHUB_FDO_FLAG_NOT_ENUMERATED);
+
+        USBH_SubmitStatusChangeTransfer(HubExtension);
+
+        IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations);
+    }
+    else
+    {
+        HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_ENUMERATION;
+    }
+
+    KeSetEvent(&HubExtension->RootHubNotificationEvent,
+               EVENT_INCREMENT,
+               FALSE);
+}
+
+NTSTATUS
+NTAPI
+USBD_RegisterRootHubCallBack(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    PUSB_BUSIFFN_ROOTHUB_INIT_NOTIFY RootHubInitNotification;
+
+    DPRINT("USBD_RegisterRootHubCallBack: ... \n");
+
+    RootHubInitNotification = HubExtension->BusInterface.RootHubInitNotification;
+
+    if (!RootHubInitNotification)
+    {
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    KeResetEvent(&HubExtension->RootHubNotificationEvent);
+
+    return RootHubInitNotification(HubExtension->BusInterface.BusContext,
+                                   HubExtension,
+                                   USBHUB_RootHubCallBack);
+}
+
+NTSTATUS
+NTAPI
+USBD_UnRegisterRootHubCallBack(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    PUSB_BUSIFFN_ROOTHUB_INIT_NOTIFY RootHubInitNotification;
+    NTSTATUS Status;
+
+    DPRINT("USBD_UnRegisterRootHubCallBack ... \n");
+
+    RootHubInitNotification = HubExtension->BusInterface.RootHubInitNotification;
+
+    if (!RootHubInitNotification)
+    {
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    Status = RootHubInitNotification(HubExtension->BusInterface.BusContext,
+                                     NULL,
+                                     NULL);
+
+    if (!NT_SUCCESS(Status))
+    {
+        KeWaitForSingleObject(&HubExtension->RootHubNotificationEvent,
+                              Executive,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+
+    return Status;
+}
+
+VOID
+NTAPI
+USBH_HubSetDWakeCompletion(IN PDEVICE_OBJECT DeviceObject,
+                           IN UCHAR MinorFunction,
+                           IN POWER_STATE PowerState,
+                           IN PVOID Context,
+                           IN PIO_STATUS_BLOCK IoStatus)
+{
+    DPRINT("USBH_HubSetDWakeCompletion: ... \n");
+    KeSetEvent((PRKEVENT)Context, IO_NO_INCREMENT, FALSE);
+}
+
+VOID
+NTAPI
+USBH_HubQueuePortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                          IN PLIST_ENTRY IdleList)
+{
+    PDEVICE_OBJECT PortDevice;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    PIRP IdleIrp;
+    PIRP HubIdleIrp;
+    ULONG NumPorts;
+    ULONG Port;
+    KIRQL Irql;
+
+    DPRINT("USBH_HubQueuePortIdleIrps ... \n");
+
+    InitializeListHead(IdleList);
+
+    IoAcquireCancelSpinLock(&Irql);
+
+    NumPorts = HubExtension->HubDescriptor->bNumberOfPorts;
+
+    for (Port = 0; Port < NumPorts; ++Port)
+    {
+        PortDevice = HubExtension->PortData[Port].DeviceObject;
+
+        if (PortDevice)
+        {
+            PortExtension = PortDevice->DeviceExtension;
+
+            IdleIrp = PortExtension->IdleNotificationIrp;
+            PortExtension->IdleNotificationIrp = NULL;
+
+            if (IdleIrp && IoSetCancelRoutine(IdleIrp, NULL))
+            {
+                DPRINT1("USBH_HubQueuePortIdleIrps: IdleIrp != NULL. FIXME\n");
+                DbgBreakPoint();
+            }
+        }
+    }
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
+    {
+        HubIdleIrp = HubExtension->PendingIdleIrp;
+        HubExtension->PendingIdleIrp = NULL;
+    }
+    else
+    {
+        HubIdleIrp = NULL;
+    }
+
+    IoReleaseCancelSpinLock(Irql);
+
+    if (HubIdleIrp)
+    {
+        USBH_HubCancelIdleIrp(HubExtension, HubIdleIrp);
+    }
+}
+
+VOID
+NTAPI
+USBH_HubCompleteQueuedPortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                                   IN PLIST_ENTRY IdleList,
+                                   IN NTSTATUS NtStatus)
+{
+    DPRINT("USBH_HubCompleteQueuedPortIdleIrps ... \n");
+
+    while (!IsListEmpty(IdleList))
+    {
+        DPRINT1("USBH_HubCompleteQueuedPortIdleIrps: IdleList not Empty. FIXME\n");
+        DbgBreakPoint();
+    }
+}
+
+VOID
+NTAPI
+USBH_FlushPortPwrList(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    PDEVICE_OBJECT PortDevice;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    PLIST_ENTRY Entry;
+    ULONG Port;
+
+    DPRINT("USBH_FlushPortPwrList ... \n");
+
+    InterlockedIncrement((PLONG)&HubExtension->PendingRequestCount);
+
+    KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
+                          Executive,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    for (Port = 0; Port < HubExtension->HubDescriptor->bNumberOfPorts; ++Port)
+    {
+        PortDevice = HubExtension->PortData[Port].DeviceObject;
+
+        if (!PortDevice)
+        {
+            continue;
+        }
+
+        PortExtension = PortDevice->DeviceExtension;
+
+        InterlockedExchange((PLONG)&PortExtension->StateBehindD2, 0);
+
+        while (TRUE)
+        {
+            Entry = ExInterlockedRemoveHeadList(&PortExtension->PortPowerList,
+                                                &PortExtension->PortPowerListSpinLock);
+
+            if (!Entry)
+            {
+                break;
+            }
+
+            DPRINT1("USBH_FlushPortPwrList: PortPowerList FIXME\n");
+            DbgBreakPoint();
+        }
+    }
+
+    KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
+                       LOW_REALTIME_PRIORITY,
+                       1,
+                       FALSE);
+
+    if (!InterlockedDecrement((PLONG)&HubExtension->PendingRequestCount))
+    {
+        KeSetEvent(&HubExtension->PendingRequestEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+    }
+}
+
+VOID
+NTAPI
+USBH_HubCompletePortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                             IN NTSTATUS NtStatus)
+{
+    LIST_ENTRY IdleList;
+
+    DPRINT("USBH_HubCompletePortIdleIrps ... \n");
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
+    {
+        USBH_HubQueuePortIdleIrps(HubExtension, &IdleList);
+
+        USBH_HubCompleteQueuedPortIdleIrps(HubExtension,
+                                           &IdleList,
+                                           NtStatus);
+
+        USBH_FlushPortPwrList(HubExtension);
+    }
+}
+
+VOID
+NTAPI
+USBH_HubCancelIdleIrp(IN PUSBHUB_FDO_EXTENSION HubExtension, 
+                      IN PIRP IdleIrp)
+{
+    DPRINT("USBH_HubCancelIdleIrp ... \n");
+
+    IoCancelIrp(IdleIrp);
+
+    if (InterlockedExchange(&HubExtension->IdleRequestLock, 1))
+    {
+        IoFreeIrp(IdleIrp);
+    }
+}
+
+BOOLEAN
+NTAPI
+USBH_CheckIdleAbort(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                    IN BOOLEAN IsWait,
+                    IN BOOLEAN IsExtCheck)
+{
+    PDEVICE_OBJECT PdoDevice;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    PUSBHUB_PORT_DATA PortData;
+    ULONG Port;
+    BOOLEAN Result = FALSE;
+
+    DPRINT("USBH_CheckIdleAbort: ... \n");
+
+    InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+    if (IsWait == TRUE)
+    {
+        KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
+                              Executive,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+    }
+
+    PortData = HubExtension->PortData;
+
+    for (Port = 0; Port < HubExtension->HubDescriptor->bNumberOfPorts; Port++)
+    {
+        PdoDevice = PortData[Port].DeviceObject;
+
+        if (PdoDevice)
+        {
+            PortExtension = PdoDevice->DeviceExtension;
+
+            if (PortExtension->PoRequestCounter)
+            {
+                Result = TRUE;
+                goto Wait;
+            }
+        }
+    }
+
+    if (IsExtCheck == TRUE)
+    {
+        PortData = HubExtension->PortData;
+
+        for (Port = 0;
+             Port < HubExtension->HubDescriptor->bNumberOfPorts;
+             Port++)
+        {
+            PdoDevice = PortData[Port].DeviceObject;
+
+            if (PdoDevice)
+            {
+                PortExtension = PdoDevice->DeviceExtension;
+                InterlockedExchange(&PortExtension->StateBehindD2, 0);
+            }
+        }
+    }
+
+Wait:
+
+    if (IsWait == TRUE)
+    {
+        KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
+                           LOW_REALTIME_PRIORITY,
+                           1,
+                           FALSE);
+    }
+
+    if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+    {
+        KeSetEvent(&HubExtension->PendingRequestEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+    }
+
+    return Result;
+}
+
+VOID
+NTAPI
+USBH_FdoWaitWakeIrpCompletion(IN PDEVICE_OBJECT DeviceObject, 
+                              IN UCHAR MinorFunction,
+                              IN POWER_STATE PowerState,
+                              IN PVOID Context,
+                              IN PIO_STATUS_BLOCK IoStatus)
+{
+    DPRINT("USBH_FdoWaitWakeIrpCompletion ... \n");
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoSubmitWaitWakeIrp(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    POWER_STATE PowerState;
+    NTSTATUS Status;
+    PIRP Irp = NULL;
+    KIRQL Irql;
+
+    DPRINT("USBH_FdoSubmitWaitWakeIrp: ... \n");
+
+    PowerState.SystemState = HubExtension->SystemWake;
+    HubExtension->HubFlags |= USBHUB_FDO_FLAG_PENDING_WAKE_IRP;
+
+    InterlockedIncrement(&HubExtension->PendingRequestCount);
+    InterlockedExchange(&HubExtension->FdoWaitWakeLock, 0);
+
+    Status = PoRequestPowerIrp(HubExtension->LowerPDO,
+                               IRP_MN_WAIT_WAKE,
+                               PowerState,
+                               USBH_FdoWaitWakeIrpCompletion,
+                               HubExtension,
+                               &Irp);
+
+    IoAcquireCancelSpinLock(&Irql);
+
+    if (Status == STATUS_PENDING)
+    {
+        if (HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP)
+        {
+            HubExtension->PendingWakeIrp = Irp;
+            DPRINT("USBH_FdoSubmitWaitWakeIrp: PendingWakeIrp - %p\n",
+                   HubExtension->PendingWakeIrp);
+        }
+    }
+    else
+    {
+        HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_PENDING_WAKE_IRP;
+
+        if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+        {
+            KeSetEvent(&HubExtension->PendingRequestEvent,
+                       EVENT_INCREMENT,
+                       FALSE);
+        }
+    }
+
+    IoReleaseCancelSpinLock(Irql);
+
+    return Status;
+}
+
+VOID
+NTAPI
+USBH_FdoIdleNotificationCallback(IN PVOID Context)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    PUSBHUB_PORT_DATA PortData;
+    PDEVICE_OBJECT PortDevice;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    PIRP Irp = NULL;
+    PIRP IdleIrp;
+    POWER_STATE PowerState;
+    KEVENT Event;
+    ULONG Port;
+    PIO_STACK_LOCATION IoStack;
+    PUSB_IDLE_CALLBACK_INFO CallbackInfo;
+    BOOLEAN IsReady;
+    KIRQL OldIrql;
+    NTSTATUS Status;
+
+    HubExtension = Context;
+
+    DPRINT("USBH_FdoIdleNotificationCallback: HubExtension - %p, HubFlags - %lX\n",
+           HubExtension,
+           HubExtension->HubFlags);
+
+    if (HubExtension->HubFlags & (USBHUB_FDO_FLAG_ENUM_POST_RECOVER |
+                                  USBHUB_FDO_FLAG_WAKEUP_START |
+                                  USBHUB_FDO_FLAG_DEVICE_REMOVED |
+                                  USBHUB_FDO_FLAG_STATE_CHANGING |
+                                  USBHUB_FDO_FLAG_ESD_RECOVERING |
+                                  USBHUB_FDO_FLAG_DEVICE_FAILED |
+                                  USBHUB_FDO_FLAG_DEVICE_STOPPING))
+    {
+        DbgBreakPoint();
+        return;
+    }
+
+    HubExtension->HubFlags |= USBHUB_FDO_FLAG_GOING_IDLE;
+
+    if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP))
+    {
+        Status = USBH_FdoSubmitWaitWakeIrp(HubExtension);
+
+        if (Status != STATUS_PENDING)
+        {
+            DPRINT("Status != STATUS_PENDING. DbgBreakPoint()\n");
+            DbgBreakPoint();
+            HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_GOING_IDLE;
+            return;
+        }
+    }
+
+    InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+    KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
+                          Executive,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    PortData = HubExtension->PortData;
+    IsReady = TRUE;
+
+    for (Port = 0;
+         Port < HubExtension->HubDescriptor->bNumberOfPorts;
+         Port++)
+    {
+        PortDevice = PortData[Port].DeviceObject;
+
+        if (PortDevice)
+        {
+            PortExtension = PortDevice->DeviceExtension;
+
+            IdleIrp = PortExtension->IdleNotificationIrp;
+
+            if (!IdleIrp)
+            {
+                IsReady = FALSE;
+                goto IdleHub;
+            }
+
+            IoStack = IoGetCurrentIrpStackLocation(IdleIrp);
+
+            CallbackInfo = IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
+
+            if (!CallbackInfo)
+            {
+                IsReady = FALSE;
+                goto IdleHub;
+            }
+
+            if (!CallbackInfo->IdleCallback)
+            {
+                IsReady = FALSE;
+                goto IdleHub;
+            }
+
+            if (PortExtension->PendingSystemPoRequest)
+            {
+                IsReady = FALSE;
+                goto IdleHub;
+            }
+
+            if (InterlockedCompareExchange(&PortExtension->StateBehindD2,
+                                           1,
+                                           0))
+            {
+                IsReady = FALSE;
+                goto IdleHub;
+            }
+
+            DPRINT("USBH_FdoIdleNotificationCallback: IdleContext - %p\n",
+                   CallbackInfo->IdleContext);
+
+            CallbackInfo->IdleCallback(CallbackInfo->IdleContext);
+
+            if (PortExtension->CurrentPowerState.DeviceState == PowerDeviceD0)
+            {
+                IsReady = FALSE;
+                goto IdleHub;
+            }
+        }
+    }
+
+    if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING) &&
+        (USBH_CheckIdleAbort(HubExtension, FALSE, FALSE) == TRUE))
+    {
+        IsReady = FALSE;
+    }
+
+IdleHub:
+
+    KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
+                       LOW_REALTIME_PRIORITY,
+                       1,
+                       FALSE);
+
+    if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+    {
+        KeSetEvent(&HubExtension->PendingRequestEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+    }
+
+    if (!IsReady ||
+        (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_SUSPENDED))
+    {
+        DPRINT1("USBH_FdoIdleNotificationCallback: HubFlags - %lX\n",
+                HubExtension->HubFlags);
+
+        HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_DEVICE_SUSPENDED |
+                                    USBHUB_FDO_FLAG_GOING_IDLE);
+
+        /* Aborting Idle for Hub */
+        IoAcquireCancelSpinLock(&OldIrql);
+
+        if (HubExtension->PendingIdleIrp)
+        {
+            Irp = HubExtension->PendingIdleIrp;
+            HubExtension->PendingIdleIrp = NULL;
+        }
+
+        IoReleaseCancelSpinLock(OldIrql);
+
+        if (Irp)
+        {
+            USBH_HubCancelIdleIrp(HubExtension, Irp);
+        }
+
+        DbgBreakPoint();
+        USBH_HubCompletePortIdleIrps(HubExtension, STATUS_CANCELLED);
+    }
+    else
+    {
+        PowerState.DeviceState = HubExtension->DeviceWake;
+
+        KeWaitForSingleObject(&HubExtension->IdleSemaphore,
+                              Executive,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+
+        HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_GOING_IDLE;
+        HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_SUSPENSE;
+
+        KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+        DPRINT("USBH_FdoIdleNotificationCallback: LowerPdo - %p\n",
+                HubExtension->LowerPDO);
+
+        DPRINT("USBH_FdoIdleNotificationCallback: PowerState.DeviceState - %x\n",
+               PowerState.DeviceState);
+
+        Status = PoRequestPowerIrp(HubExtension->LowerPDO,
+                                   IRP_MN_SET_POWER,
+                                   PowerState,
+                                   USBH_HubSetDWakeCompletion,
+                                   &Event,
+                                   NULL);
+
+        if (Status == STATUS_PENDING)
+        {
+            KeWaitForSingleObject(&Event,
+                                  Executive,
+                                  KernelMode,
+                                  FALSE,
+                                  NULL);
+        }
+    }
+}
+
+VOID
+NTAPI
+USBH_CompletePortIdleIrpsWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                                IN PVOID Context)
+{
+    PUSBHUB_IDLE_PORT_CONTEXT IdlePortContext;
+    NTSTATUS NtStatus;
+    NTSTATUS Status;
+    BOOLEAN IsFlush = FALSE;
+
+    DPRINT("USBH_CompletePortIdleIrpsWorker ... \n");
+
+    IdlePortContext = Context;
+    NtStatus = IdlePortContext->Status;
+
+    USBH_HubCompleteQueuedPortIdleIrps(HubExtension,
+                                       &IdlePortContext->PwrList,
+                                       NtStatus);
+
+    DPRINT1("USBH_CompletePortIdleIrpsWorker: USBH_RegQueryFlushPortPowerIrpsFlag() UNIMPLEMENTED. FIXME\n");
+    Status = STATUS_NOT_IMPLEMENTED;// USBH_RegQueryFlushPortPowerIrpsFlag(&IsFlush);
+
+    if (NT_SUCCESS(Status))
+    {
+        if (IsFlush)
+        {
+            USBH_FlushPortPwrList(HubExtension);
+        }
+    }
+}
+
+VOID
+NTAPI
+USBH_IdleCompletePowerHubWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                                IN PVOID Context)
+{
+    PUSBHUB_IDLE_HUB_CONTEXT HubWorkItemBuffer;
+
+    DPRINT("USBH_IdleCompletePowerHubWorker ... \n");
+
+    if (HubExtension &&
+        HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0 &&
+        HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)
+    {
+        USBH_HubSetD0(HubExtension);
+    }
+
+    HubWorkItemBuffer = Context;
+
+    USBH_HubCompletePortIdleIrps(HubExtension, HubWorkItemBuffer->Status);
+
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoIdleNotificationRequestComplete(IN PDEVICE_OBJECT DeviceObject,
+                                        IN PIRP Irp,
+                                        IN PVOID Context)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    NTSTATUS NtStatus;
+    PVOID IdleIrp;
+    KIRQL Irql;
+    NTSTATUS Status;
+    PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
+
+    IoAcquireCancelSpinLock(&Irql);
+
+    HubExtension = Context;
+    HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
+
+    IdleIrp = InterlockedExchangePointer((PVOID)&HubExtension->PendingIdleIrp,
+                                         NULL);
+
+    DPRINT("USBH_FdoIdleNotificationRequestComplete: IdleIrp - %p\n", IdleIrp);
+
+    if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+    {
+        KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE);
+    }
+
+    IoReleaseCancelSpinLock(Irql);
+
+    NtStatus = Irp->IoStatus.Status;
+
+    DPRINT("USBH_FdoIdleNotificationRequestComplete: NtStatus - %lX\n",
+           NtStatus);
+
+    if (!NT_SUCCESS(NtStatus) &&
+        NtStatus != STATUS_POWER_STATE_INVALID &&
+        !(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED) &&
+        !(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED))
+    {
+        DPRINT("USBH_FdoIdleNotificationRequestComplete: DeviceState - %x\n",
+               HubExtension->CurrentPowerState.DeviceState);
+
+        if (HubExtension->CurrentPowerState.DeviceState == PowerDeviceD0)
+        {
+            PUSBHUB_IDLE_PORT_CONTEXT HubWorkItemBuffer;
+
+            Status = USBH_AllocateWorkItem(HubExtension,
+                                           &HubIoWorkItem,
+                                           USBH_CompletePortIdleIrpsWorker,
+                                           sizeof(USBHUB_IDLE_PORT_CONTEXT),
+                                           (PVOID *)&HubWorkItemBuffer,
+                                           DelayedWorkQueue);
+
+            if (NT_SUCCESS(Status))
+            {
+                HubWorkItemBuffer->Status = NtStatus;
+
+                USBH_HubQueuePortIdleIrps(HubExtension,
+                                          &HubWorkItemBuffer->PwrList);
+
+                USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
+            }
+        }
+        else
+        {
+            PUSBHUB_IDLE_HUB_CONTEXT HubWorkItemBuffer;
+
+            Status = USBH_AllocateWorkItem(HubExtension,
+                                           &HubIoWorkItem,
+                                           USBH_IdleCompletePowerHubWorker,
+                                           sizeof(USBHUB_IDLE_HUB_CONTEXT),
+                                           (PVOID *)&HubWorkItemBuffer,
+                                           DelayedWorkQueue);
+
+            if (NT_SUCCESS(Status))
+            {
+                HubWorkItemBuffer->Status = NtStatus;
+                USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
+            }
+        }
+    }
+
+    if (IdleIrp ||
+        InterlockedExchange((PLONG)&HubExtension->IdleRequestLock, 1))
+    {
+        DPRINT("USBH_FdoIdleNotificationRequestComplete: Irp - %p\n", Irp);
+        IoFreeIrp(Irp);
+    }
+
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+NTAPI
+USBH_FdoSubmitIdleRequestIrp(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    NTSTATUS Status;
+    ULONG HubFlags;
+    PDEVICE_OBJECT LowerPDO;
+    PIRP Irp;
+    PIO_STACK_LOCATION IoStack;
+    KIRQL Irql;
+
+    DPRINT("USBH_FdoSubmitIdleRequestIrp: HubExtension - %p, PendingIdleIrp - %p\n",
+           HubExtension,
+           HubExtension->PendingIdleIrp);
+
+    if (HubExtension->PendingIdleIrp)
+    {
+        Status = STATUS_DEVICE_BUSY;
+        KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
+        return Status;
+    }
+
+    HubFlags = HubExtension->HubFlags;
+
+    if (HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING ||
+        HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED)
+    {
+        HubExtension->HubFlags = HubFlags & ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
+        KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
+        return STATUS_DEVICE_REMOVED;
+    }
+
+    LowerPDO = HubExtension->LowerPDO;
+
+    HubExtension->IdleCallbackInfo.IdleCallback = USBH_FdoIdleNotificationCallback;
+    HubExtension->IdleCallbackInfo.IdleContext = HubExtension;
+
+    Irp = IoAllocateIrp(LowerPDO->StackSize, FALSE);
+
+    if (!Irp)
+    {
+        HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+
+        KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
+        return Status;
+    }
+    IoStack = IoGetNextIrpStackLocation(Irp);
+
+    IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+
+    IoStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(USB_IDLE_CALLBACK_INFO);
+    IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
+    IoStack->Parameters.DeviceIoControl.Type3InputBuffer = &HubExtension->IdleCallbackInfo;
+
+    IoSetCompletionRoutine(Irp,
+                           USBH_FdoIdleNotificationRequestComplete,
+                           HubExtension,
+                           TRUE,
+                           TRUE,
+                           TRUE);
+
+    InterlockedIncrement(&HubExtension->PendingRequestCount);
+    InterlockedExchange(&HubExtension->IdleRequestLock, 0);
+
+    HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_DEVICE_SUSPENDED |
+                                USBHUB_FDO_FLAG_GOING_IDLE);
+
+    Status = IoCallDriver(HubExtension->LowerPDO, Irp);
+
+    IoAcquireCancelSpinLock(&Irql);
+
+    if (Status == STATUS_PENDING &&
+        HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)
+    {
+        HubExtension->PendingIdleIrp = Irp;
+    }
+
+    IoReleaseCancelSpinLock(Irql);
+
+    KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE);
+
+    return Status;
+}
+
+VOID
+NTAPI
+USBH_CheckHubIdle(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    PDEVICE_OBJECT PdoDevice;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    PUSBHUB_PORT_DATA PortData;
+    ULONG HubFlags;
+    ULONG Port;
+    KIRQL Irql;
+    BOOLEAN IsHubIdle = FALSE;
+    BOOLEAN IsAllPortsIdle;
+    BOOLEAN IsHubCheck = TRUE;
+
+    DPRINT("USBH_CheckHubIdle: FIXME !!! HubExtension - %p\n", HubExtension);
+
+return; //HACK: delete it line after fixing Power Manager!!!
+
+    KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql);
+
+    if (HubExtension->HubFlags & USBHUB_FDO_FLAG_CHECK_IDLE_LOCK)
+    {
+        KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
+        return;
+    }
+
+    HubExtension->HubFlags |= USBHUB_FDO_FLAG_CHECK_IDLE_LOCK;
+    KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
+
+    if (USBH_GetRootHubExtension(HubExtension)->SystemPowerState.SystemState != PowerSystemWorking)
+    {
+        KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql);
+        HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_CHECK_IDLE_LOCK;
+        KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
+        return;
+    }
+
+    HubFlags = HubExtension->HubFlags;
+    DPRINT("USBH_CheckHubIdle: HubFlags - %lX\n", HubFlags);
+
+    if (!(HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) ||
+        !(HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION))
+    {
+        goto Exit;
+    }
+
+    if (HubFlags & USBHUB_FDO_FLAG_NOT_ENUMERATED ||
+        HubFlags & USBHUB_FDO_FLAG_ENUM_POST_RECOVER ||
+        HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED ||
+        HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING ||
+        HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED ||
+        HubFlags & USBHUB_FDO_FLAG_STATE_CHANGING ||
+        HubFlags & USBHUB_FDO_FLAG_WAKEUP_START ||
+        HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING)
+    {
+        goto Exit;
+    }
+
+    if (HubExtension->ResetRequestCount)
+    {
+        HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEFER_CHECK_IDLE;
+        goto Exit;
+    }
+
+    HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DEFER_CHECK_IDLE;
+
+    InterlockedIncrement(&HubExtension->PendingRequestCount);
+
+    KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore,
+                          Executive,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    IoAcquireCancelSpinLock(&Irql);
+
+    IsAllPortsIdle = TRUE;
+
+    PortData = HubExtension->PortData;
+
+    for (Port = 0;
+         Port < HubExtension->HubDescriptor->bNumberOfPorts;
+         Port++)
+    {
+        PdoDevice = PortData[Port].DeviceObject;
+
+        if (PdoDevice)
+        {
+            PortExtension = PdoDevice->DeviceExtension;
+
+            if (!PortExtension->IdleNotificationIrp)
+            {
+                DPRINT("USBH_CheckHubIdle: PortExtension - %p\n",
+                       PortExtension);
+
+                IsAllPortsIdle = FALSE;
+                IsHubCheck = FALSE;
+
+                break;
+            }
+        }
+    }
+
+    if (IsHubCheck &&
+        !(HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST))
+    {
+        KeResetEvent(&HubExtension->IdleEvent);
+        HubExtension->HubFlags |= USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST;
+        IsHubIdle = TRUE;
+    }
+
+    IoReleaseCancelSpinLock(Irql);
+
+    KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore,
+                       LOW_REALTIME_PRIORITY,
+                       1,
+                       FALSE);
+
+    if (!InterlockedDecrement(&HubExtension->PendingRequestCount))
+    {
+        KeSetEvent(&HubExtension->PendingRequestEvent,
+                   EVENT_INCREMENT,
+                   FALSE);
+    }
+
+    DPRINT("USBH_CheckHubIdle: IsAllPortsIdle - %x, IsHubIdle - %x\n",
+           IsAllPortsIdle,
+           IsHubIdle);
+
+    if (IsAllPortsIdle && IsHubIdle)
+    {
+        USBH_FdoSubmitIdleRequestIrp(HubExtension);
+    }
+
+Exit:
+    KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql);
+    HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_CHECK_IDLE_LOCK;
+    KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql);
+}
+
+VOID
+NTAPI
+USBH_CheckIdleWorker(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                     IN PVOID Context)
+{
+    DPRINT("USBH_CheckIdleWorker: ... \n");
+    USBH_CheckHubIdle(HubExtension);
+}
+
+VOID
+NTAPI
+USBH_CheckIdleDeferred(IN PUSBHUB_FDO_EXTENSION HubExtension)
+{
+    PUSBHUB_IO_WORK_ITEM HubIoWorkItem;
+    NTSTATUS Status;
+
+    DPRINT("USBH_CheckIdleDeferred: HubExtension - %p\n", HubExtension);
+
+    Status = USBH_AllocateWorkItem(HubExtension,
+                                   &HubIoWorkItem,
+                                   USBH_CheckIdleWorker,
+                                   0,
+                                   NULL,
+                                   DelayedWorkQueue);
+
+    DPRINT("USBH_CheckIdleDeferred: HubIoWorkItem - %p\n", HubIoWorkItem);
+
+    if (NT_SUCCESS(Status))
+    {
+        USBH_QueueWorkItem(HubExtension, HubIoWorkItem);
+    }
+}
+
+VOID
+NTAPI
+USBH_PdoSetCapabilities(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension)
+{
+    PUSBHUB_FDO_EXTENSION HubExtension;
+    ULONG State;
+    SYSTEM_POWER_STATE SystemPowerState;
+    PDEVICE_POWER_STATE pDeviceState;
+
+    DPRINT("USBH_PdoSetCapabilities ... \n");
+
+    HubExtension = PortExtension->HubExtension;
+
+    PortExtension->Capabilities.Size = 64;
+    PortExtension->Capabilities.Version = 1;
+
+    PortExtension->Capabilities.Removable = 1;
+    PortExtension->Capabilities.Address = PortExtension->PortNumber;
+
+    if (PortExtension->SerialNumber)
+    {
+        PortExtension->Capabilities.UniqueID = 1;
+    }
+    else
+    {
+        PortExtension->Capabilities.UniqueID = 0;
+    }
+
+    PortExtension->Capabilities.RawDeviceOK = 0;
+
+    RtlCopyMemory(PortExtension->Capabilities.DeviceState,
+                  HubExtension->DeviceState,
+                  (PowerSystemMaximum + 2) * sizeof(POWER_STATE));
+
+    PortExtension->Capabilities.DeviceState[1] = PowerDeviceD0;
+
+    if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REMOTE_WAKEUP)
+    {
+        PortExtension->Capabilities.DeviceWake = PowerDeviceD2;
+
+        PortExtension->Capabilities.DeviceD1 = 1;
+        PortExtension->Capabilities.DeviceD2 = 1;
+
+        PortExtension->Capabilities.WakeFromD0 = 1;
+        PortExtension->Capabilities.WakeFromD1 = 1;
+        PortExtension->Capabilities.WakeFromD2 = 1;
+
+        pDeviceState = &PortExtension->Capabilities.DeviceState[2];
+
+        for (State = 2; State <= 5; State++)
+        {
+            SystemPowerState = State;
+
+            if (PortExtension->Capabilities.SystemWake < SystemPowerState)
+            {
+                *pDeviceState = PowerDeviceD3;
+            }
+            else
+            {
+                *pDeviceState = PowerDeviceD2;
+            }
+
+            ++pDeviceState;
+        }
+    }
+    else
+    {
+        PortExtension->Capabilities.DeviceWake = PowerDeviceD0;
+        PortExtension->Capabilities.DeviceState[2] = PowerDeviceD3;
+        PortExtension->Capabilities.DeviceState[3] = PowerDeviceD3;
+        PortExtension->Capabilities.DeviceState[4] = PowerDeviceD3;
+        PortExtension->Capabilities.DeviceState[5] = PowerDeviceD3;
+    }
+}
+
+NTSTATUS
+NTAPI
+USBH_ProcessDeviceInformation(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension)
+{
+    PUSB_INTERFACE_DESCRIPTOR Pid;
+    PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
+    NTSTATUS Status;
+
+    DPRINT("USBH_ProcessDeviceInformation ... \n");
+
+    ConfigDescriptor = NULL;
+
+    RtlZeroMemory(&PortExtension->InterfaceDescriptor,
+                  sizeof(PortExtension->InterfaceDescriptor));
+
+    PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_HUB_DEVICE;
+
+    Status = USBH_GetConfigurationDescriptor(PortExtension->Common.SelfDevice,
+                                             &ConfigDescriptor);
+
+    if (!NT_SUCCESS(Status))
+    {
+        if (ConfigDescriptor)
+        {
+            ExFreePool(ConfigDescriptor);
+        }
+
+        return Status;
+    }
+
+    PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REMOTE_WAKEUP;
+
+    if (ConfigDescriptor->bmAttributes & 0x20)
+    {
+        /* device configuration supports remote wakeup */
+        PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_REMOTE_WAKEUP;
+    }
+
+    USBHUB_DumpingDeviceDescriptor(&PortExtension->DeviceDescriptor);
+    USBHUB_DumpingConfiguration(ConfigDescriptor);
+
+    DPRINT_PNP("USBH_ProcessDeviceInformation: Class - %x, SubClass - %x, Protocol - %x\n",
+               PortExtension->DeviceDescriptor.bDeviceClass,
+               PortExtension->DeviceDescriptor.bDeviceSubClass,
+               PortExtension->DeviceDescriptor.bDeviceProtocol);
+
+    DPRINT_PNP("USBH_ProcessDeviceInformation: bNumConfigurations - %x, bNumInterfaces - %x\n",
+               PortExtension->DeviceDescriptor.bNumConfigurations,
+               ConfigDescriptor->bNumInterfaces);
+
+
+    /* Enumeration of USB Composite Devices (msdn):
+       1) The device class field of the device descriptor (bDeviceClass) must contain a value of zero,
+       or the class (bDeviceClass), subclass (bDeviceSubClass), and protocol (bDeviceProtocol)
+       fields of the device descriptor must have the values 0xEF, 0x02 and 0x01 respectively,
+       as explained in USB Interface Association Descriptor.
+       2) The device must have multiple interfaces
+       3) The device must have a single configuration.
+    */
+
+    if (((PortExtension->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_RESERVED) ||
+        (PortExtension->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_MISCELLANEOUS &&
+         PortExtension->DeviceDescriptor.bDeviceSubClass == 0x02 &&
+         PortExtension->DeviceDescriptor.bDeviceProtocol == 0x01)) &&
+         (ConfigDescriptor->bNumInterfaces > 1) &&
+         (PortExtension->DeviceDescriptor.bNumConfigurations < 2))
+    {
+        DPRINT("USBH_ProcessDeviceInformation: Multi-Interface configuration\n");
+
+        PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_MULTI_INTERFACE;
+
+        if (ConfigDescriptor)
+        {
+            ExFreePool(ConfigDescriptor);
+        }
+
+        return Status;
+    }
+
+    Pid = USBD_ParseConfigurationDescriptorEx(ConfigDescriptor,
+                                              ConfigDescriptor,
+                                              -1,
+                                              -1,
+                                              -1,
+                                              -1,
+                                              -1);
+    if (Pid)
+    {
+        RtlCopyMemory(&PortExtension->InterfaceDescriptor,
+                      Pid,
+                      sizeof(PortExtension->InterfaceDescriptor));
+
+        if (Pid->bInterfaceClass == USB_DEVICE_CLASS_HUB)
+        {
+            PortExtension->PortPdoFlags |= (USBHUB_PDO_FLAG_HUB_DEVICE |
+                                            USBHUB_PDO_FLAG_REMOTE_WAKEUP);
+        }
+    }
+    else
+    {
+        Status = STATUS_UNSUCCESSFUL;
+    }
+
+    if (ConfigDescriptor)
+    {
+        ExFreePool(ConfigDescriptor);
+    }
+
+    return Status;
+}
+
+BOOLEAN
+NTAPI
+USBH_CheckDeviceIDUnique(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                         IN USHORT idVendor,
+                         IN USHORT idProduct,
+                         IN PVOID SerialNumber,
+                         IN USHORT SN_DescriptorLength)
+{
+    PDEVICE_OBJECT PortDevice;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    ULONG Port;
+    SIZE_T NumberBytes;
+
+    DPRINT("USBH_CheckDeviceIDUnique: idVendor - 0x%04X, idProduct - 0x%04X\n",
+           idVendor,
+           idProduct);
+
+    if (!HubExtension->HubDescriptor->bNumberOfPorts)
+    {
+        return TRUE;
+    }
+
+    for (Port = 0; Port < HubExtension->HubDescriptor->bNumberOfPorts; Port++)
+    {
+        PortDevice = HubExtension->PortData[Port].DeviceObject;
+
+        if (PortDevice)
+        {
+            PortExtension = PortDevice->DeviceExtension;
+
+            if (PortExtension->DeviceDescriptor.idVendor == idVendor &&
+                PortExtension->DeviceDescriptor.idProduct == idProduct &&
+                PortExtension->SN_DescriptorLength == SN_DescriptorLength)
+            {
+                if (PortExtension->SerialNumber)
+                {
+                    NumberBytes = RtlCompareMemory(PortExtension->SerialNumber,
+                                                   SerialNumber,
+                                                   SN_DescriptorLength);
+
+                    if (NumberBytes == SN_DescriptorLength)
+                    {
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    return FALSE;
+}
+
+BOOLEAN
+NTAPI
+USBH_ValidateSerialNumberString(IN PUSHORT SerialNumberString)
+{
+    USHORT ix;
+    USHORT Symbol;
+
+    DPRINT("USBH_ValidateSerialNumberString: ... \n");
+
+    for (ix = 0; SerialNumberString[ix] != UNICODE_NULL; ix++)
+    {
+        Symbol = SerialNumberString[ix];
+
+        if (Symbol < 0x20 || Symbol > 0x7F || Symbol == 0x2C) // ','
+        {
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+
+NTSTATUS
+NTAPI
+USBH_CheckDeviceLanguage(IN PDEVICE_OBJECT DeviceObject,
+                         IN USHORT LanguageId)
+{
+    PUSB_STRING_DESCRIPTOR Descriptor;
+    NTSTATUS Status;
+    ULONG NumSymbols;
+    ULONG ix;
+    PWCHAR pSymbol;
+    ULONG Length;
+
+    DPRINT("USBH_CheckDeviceLanguage: LanguageId - 0x%04X\n", LanguageId);
+
+    Descriptor = ExAllocatePoolWithTag(NonPagedPool,
+                                       MAXIMUM_USB_STRING_LENGTH,
+                                       USB_HUB_TAG);
+
+    if (!Descriptor)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(Descriptor, MAXIMUM_USB_STRING_LENGTH);
+
+    Status = USBH_SyncGetStringDescriptor(DeviceObject,
+                                          0,
+                                          0,
+                                          Descriptor,
+                                          MAXIMUM_USB_STRING_LENGTH,
+                                          &Length,
+                                          TRUE);
+
+    if (!NT_SUCCESS(Status) ||
+        Length < sizeof(USB_COMMON_DESCRIPTOR))
+    {
+        goto Exit;
+    }
+
+    NumSymbols = (Length -
+                  FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString)) / sizeof(WCHAR);
+
+    pSymbol = Descriptor->bString;
+
+    for (ix = 1; ix < NumSymbols; ix++)
+    {
+        if (*pSymbol == (WCHAR)LanguageId)
+        {
+            Status = STATUS_SUCCESS;
+            goto Exit;
+        }
+
+        pSymbol++;
+    }
+
+    Status = STATUS_NOT_SUPPORTED;
+
+Exit:
+    ExFreePoolWithTag(Descriptor, USB_HUB_TAG);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_GetSerialNumberString(IN PDEVICE_OBJECT DeviceObject,
+                           IN LPWSTR * OutSerialNumber,
+                           IN PUSHORT OutDescriptorLength,
+                           IN USHORT LanguageId,
+                           IN UCHAR Index)
+{
+    PUSB_STRING_DESCRIPTOR Descriptor;
+    NTSTATUS Status;
+    LPWSTR SerialNumberBuffer = NULL;
+    UCHAR StringLength;
+    UCHAR Length;
+
+    DPRINT("USBH_GetSerialNumberString: ... \n");
+
+    *OutSerialNumber = NULL;
+    *OutDescriptorLength = 0;
+
+    Descriptor = ExAllocatePoolWithTag(NonPagedPool,
+                                       MAXIMUM_USB_STRING_LENGTH,
+                                       USB_HUB_TAG);
+
+    if (!Descriptor)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(Descriptor, MAXIMUM_USB_STRING_LENGTH);
+
+    Status = USBH_CheckDeviceLanguage(DeviceObject, LanguageId);
+
+    if (!NT_SUCCESS(Status))
+    {
+        goto Exit;
+    }
+
+    Status = USBH_SyncGetStringDescriptor(DeviceObject,
+                                          Index,
+                                          LanguageId,
+                                          Descriptor,
+                                          MAXIMUM_USB_STRING_LENGTH,
+                                          NULL,
+                                          TRUE);
+
+    if (!NT_SUCCESS(Status) ||
+        Descriptor->bLength <= sizeof(USB_COMMON_DESCRIPTOR))
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto Exit;
+    }
+
+    StringLength = Descriptor->bLength -
+                   FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString);
+
+    Length = StringLength + sizeof(UNICODE_NULL);
+
+    SerialNumberBuffer = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG);
+
+    if (!SerialNumberBuffer)
+    {
+        goto Exit;
+    }
+
+    RtlZeroMemory(SerialNumberBuffer, Length);
+    RtlCopyMemory(SerialNumberBuffer, Descriptor->bString, StringLength);
+
+    *OutSerialNumber = SerialNumberBuffer;
+    *OutDescriptorLength = Length;
+
+Exit:
+    ExFreePoolWithTag(Descriptor, USB_HUB_TAG);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBH_CreateDevice(IN PUSBHUB_FDO_EXTENSION HubExtension,
+                  IN USHORT Port,
+                  IN USB_PORT_STATUS UsbPortStatus,
+                  IN ULONG IsWait)
+{
+    ULONG PdoNumber = 0;
+    WCHAR CharDeviceName[64];
+    UNICODE_STRING DeviceName;
+    PDEVICE_OBJECT DeviceObject = NULL;
+    PUSBHUB_PORT_PDO_EXTENSION PortExtension;
+    PUSB_DEVICE_HANDLE DeviceHandle;
+    LPWSTR SerialNumberBuffer;
+    BOOLEAN IsHsDevice;
+    BOOLEAN IsLsDevice;
+    BOOLEAN IgnoringHwSerial = FALSE;
+    NTSTATUS Status;
+    UNICODE_STRING DestinationString;
+
+    DPRINT("USBH_CreateDevice: Port - %x, UsbPortStatus - %lX\n",
+           Port,
+           UsbPortStatus.AsUshort16);
+
+    do
+    {
+        RtlStringCbPrintfW(CharDeviceName,
+                           sizeof(CharDeviceName),
+                           L"\\Device\\USBPDO-%d",
+                           PdoNumber);
+
+        RtlInitUnicodeString(&DeviceName, CharDeviceName);
+
+        Status = IoCreateDevice(HubExtension->Common.SelfDevice->DriverObject,
+                                sizeof(USBHUB_PORT_PDO_EXTENSION),
+                                &DeviceName,
+                                FILE_DEVICE_USB,
+                                0,
+                                FALSE,
+                                &DeviceObject);
+
+        ++PdoNumber;
+    }
+    while (Status == STATUS_OBJECT_NAME_COLLISION);
+
+    if (!NT_SUCCESS(Status))
+    {
+        ASSERT(Port > 0);
+        HubExtension->PortData[Port-1].DeviceObject = DeviceObject;
+        return Status;
+    }
+
+    DeviceObject->StackSize = HubExtension->RootHubPdo2->StackSize;
+
+    PortExtension = DeviceObject->DeviceExtension;
+
+    DPRINT("USBH_CreateDevice: PortDevice - %p, <%wZ>\n", DeviceObject, &DeviceName);
+    DPRINT("USBH_CreateDevice: PortExtension - %p\n", PortExtension);
+
+    RtlZeroMemory(PortExtension, sizeof(USBHUB_PORT_PDO_EXTENSION));
+
+    PortExtension->Common.ExtensionType = USBH_EXTENSION_TYPE_PORT;
+    PortExtension->Common.SelfDevice = DeviceObject;
+
+    PortExtension->HubExtension = HubExtension;
+    PortExtension->RootHubExtension = HubExtension;
+
+    PortExtension->PortNumber = Port;
+    PortExtension->CurrentPowerState.DeviceState = PowerDeviceD0;
+    PortExtension->IgnoringHwSerial = FALSE;
+
+    KeInitializeSpinLock(&PortExtension->PortTimeoutSpinLock);
+
+    InitializeListHead(&PortExtension->PortPowerList);
+    KeInitializeSpinLock(&PortExtension->PortPowerListSpinLock);
+
+    PortExtension->PoRequestCounter = 0;
+    PortExtension->PendingSystemPoRequest = 0;
+    PortExtension->PendingDevicePoRequest = 0;
+    PortExtension->StateBehindD2 = 0;
+
+    SerialNumberBuffer = NULL;
+
+    IsHsDevice = UsbPortStatus.Usb20PortStatus.HighSpeedDeviceAttached;
+    IsLsDevice = UsbPortStatus.Usb20PortStatus.LowSpeedDeviceAttached;
+
+    if (IsLsDevice == 0)
+    {
+        if (IsHsDevice)
+        {
+            PortExtension->PortPdoFlags = USBHUB_PDO_FLAG_PORT_HIGH_SPEED;
+        }
+    }
+    else
+    {
+        PortExtension->PortPdoFlags = USBHUB_PDO_FLAG_PORT_LOW_SPEED;
+    }
+
+    /* Initialize PortExtension->InstanceID */
+    RtlInitUnicodeString(&DestinationString, (PCWSTR)&PortExtension->InstanceID);
+    DestinationString.MaximumLength = 4 * sizeof(WCHAR);
+    Status = RtlIntegerToUnicodeString(Port, 10, &DestinationString);
+
+    DeviceObject->Flags |= DO_POWER_PAGABLE;
+    DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("USBH_CreateDevice: IoCreateDevice() failed - %lX\n", Status);
+        goto ErrorExit;
+    }
+
+    Status = USBD_CreateDeviceEx(HubExtension,
+                                 &PortExtension->DeviceHandle,
+                                 UsbPortStatus,
+                                 Port);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("USBH_CreateDevice: USBD_CreateDeviceEx() failed - %lX\n", Status);
+        goto ErrorExit;
+    }
+
+    Status = USBH_SyncResetPort(HubExtension, Port);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("USBH_CreateDevice: USBH_SyncResetPort() failed - %lX\n", Status);
+        goto ErrorExit;
+    }
+
+    if (IsWait)
+    {
+        USBH_Wait(50);
+    }
+
+    Status = USBD_InitializeDeviceEx(HubExtension,
+                                     PortExtension->DeviceHandle,
+                                     (PUCHAR)&PortExtension->DeviceDescriptor,
+                                     sizeof(USB_DEVICE_DESCRIPTOR),
+                                     (PUCHAR)&PortExtension->ConfigDescriptor,
+                                     sizeof(USB_CONFIGURATION_DESCRIPTOR));
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("USBH_CreateDevice: USBD_InitializeDeviceEx() failed - %lX\n", Status);
+        PortExtension->DeviceHandle = NULL;
+        goto ErrorExit;
+    }
+
+    DPRINT1("USBH_RegQueryDeviceIgnoreHWSerNumFlag UNIMPLEMENTED. FIXME\n");
+    //Status = USBH_RegQueryDeviceIgnoreHWSerNumFlag(PortExtension->DeviceDescriptor.idVendor,
+    //                                               PortExtension->DeviceDescriptor.idProduct,
+    //                                               &IgnoringHwSerial);
+
+  &n