[USBHUB]
[reactos.git] / reactos / drivers / usb / usbhub / fdo.c
index 6333d1e..05cb20e 100644 (file)
@@ -27,71 +27,6 @@ DestroyUsbChildDeviceObject(
     IN PDEVICE_OBJECT UsbHubDeviceObject,
     IN LONG PortId);
 
-NTSTATUS
-SubmitRequestToRootHub(
-    IN PDEVICE_OBJECT RootHubDeviceObject,
-    IN ULONG IoControlCode,
-    OUT PVOID OutParameter1,
-    OUT PVOID OutParameter2)
-{
-    KEVENT Event;
-    PIRP Irp;
-    IO_STATUS_BLOCK IoStatus;
-    NTSTATUS Status;
-    PIO_STACK_LOCATION Stack = NULL;
-
-    KeInitializeEvent(&Event, NotificationEvent, FALSE);
-
-    //
-    // Build Control Request
-    //
-    Irp = IoBuildDeviceIoControlRequest(IoControlCode,
-                                        RootHubDeviceObject,
-                                        NULL, 0,
-                                        NULL, 0,
-                                        TRUE,
-                                        &Event,
-                                        &IoStatus);
-
-    if (Irp == NULL)
-    {
-        DPRINT("Usbhub: IoBuildDeviceIoControlRequest() failed\n");
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    //
-    // Initialize the status block before sending the IRP
-    //
-    IoStatus.Status = STATUS_NOT_SUPPORTED;
-    IoStatus.Information = 0;
-
-    //
-    // Get Next Stack Location and Initialize it
-    //
-    Stack = IoGetNextIrpStackLocation(Irp);
-    Stack->Parameters.Others.Argument1 = OutParameter1;
-    Stack->Parameters.Others.Argument2 = OutParameter2;
-
-    //
-    // Call RootHub
-    //
-    Status = IoCallDriver(RootHubDeviceObject, Irp);
-
-    //
-    // Its ok to block here as this function is called in an nonarbitrary thread
-    //
-    if    (Status == STATUS_PENDING)
-    {
-        KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
-        Status = IoStatus.Status;
-    }
-
-    //
-    // The IO Manager will free the IRP
-    //
-
-    return Status;
-}
 
 NTSTATUS
 GetPortStatusAndChange(
@@ -133,6 +68,10 @@ GetPortStatusAndChange(
                           sizeof(PORT_STATUS_CHANGE),
                           0);
 
+    // FIXME: support usb hubs
+    Urb->UrbHeader.UsbdDeviceHandle = NULL;
+
+
     //
     // Query the Root Hub
     //
@@ -185,6 +124,10 @@ SetPortFeature(
                           0,
                           0,
                           0);
+
+    // FIXME support usbhubs
+    Urb->UrbHeader.UsbdDeviceHandle = NULL;
+
     //
     // Query the Root Hub
     //
@@ -237,6 +180,10 @@ ClearPortFeature(
                           0,
                           0,
                           0);
+
+    // FIXME: support usb hubs
+    Urb->UrbHeader.UsbdDeviceHandle = NULL;
+
     //
     // Query the Root Hub
     //
@@ -300,6 +247,7 @@ DeviceStatusChangeThread(
             if (!NT_SUCCESS(Status))
             {
                 DPRINT1("Failed to clear connection change for port %d\n", PortId);
+                continue;
             }
 
             //
@@ -313,6 +261,7 @@ DeviceStatusChangeThread(
                 if (!NT_SUCCESS(Status))
                 {
                     DPRINT1("Failed to delete child device object after disconnect\n");
+                    continue;
                 }
             }
             else
@@ -328,6 +277,8 @@ DeviceStatusChangeThread(
                 if (!NT_SUCCESS(Status))
                 {
                     DPRINT1("Failed to reset port %d\n", PortId);
+                    SignalResetComplete = TRUE;
+                    continue;
                 }
             }
         }
@@ -340,10 +291,16 @@ DeviceStatusChangeThread(
             if (!NT_SUCCESS(Status))
             {
                 DPRINT1("Failed to clear enable change on port %d\n", PortId);
+                continue;
             }
         }
         else if (PortStatus.Change & USB_PORT_STATUS_RESET)
         {
+            //
+            // Request event signalling later
+            //
+            SignalResetComplete = TRUE;
+
             //
             // Clear Reset
             //
@@ -351,6 +308,7 @@ DeviceStatusChangeThread(
             if (!NT_SUCCESS(Status))
             {
                 DPRINT1("Failed to clear reset change on port %d\n", PortId);
+                continue;
             }
 
             //
@@ -373,6 +331,7 @@ DeviceStatusChangeThread(
             if(PortStatus.Change & USB_PORT_STATUS_RESET)
             {
                 DPRINT1("Port did not clear reset! Possible Hardware problem!\n");
+                continue;
             }
 
             //
@@ -405,11 +364,6 @@ DeviceStatusChangeThread(
             // This is a new device
             //
             Status = CreateUsbChildDeviceObject(DeviceObject, PortId, NULL, PortStatus.Status);
-
-            //
-            // Request event signalling later
-            //
-            SignalResetComplete = TRUE;
         }
     }
 
@@ -508,15 +462,12 @@ QueryStatusChangeEndpoint(
                                            USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
                                            NULL);
 
-    //
-    // Set the device handle to null for roothub
-    //
-    PendingSCEUrb->UrbHeader.UsbdDeviceHandle = NULL;//HubDeviceExtension->RootHubHandle;
+    // Set the device handle
+    PendingSCEUrb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
 
     //
     // Allocate an Irp
     //
-
     HubDeviceExtension->PendingSCEIrp = ExAllocatePoolWithTag(NonPagedPool,
                                                               IoSizeOfIrp(RootHubDeviceObject->StackSize),
                                                               USB_HUB_TAG);
@@ -791,12 +742,8 @@ GetUsbStringDescriptor(
         ExFreePool(StringDesc);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
-       DPRINT("Buffer %p\n", Buffer);
-    RtlZeroMemory(Buffer, SizeNeeded);
 
-       DPRINT("SizeNeeded %lu\n", SizeNeeded);
-       DPRINT("Offset %lu\n", FIELD_OFFSET(USB_STRING_DESCRIPTOR, bLength));
-    DPRINT("Length %lu\n", SizeNeeded - FIELD_OFFSET(USB_STRING_DESCRIPTOR, bLength));
+    RtlZeroMemory(Buffer, SizeNeeded);
 
     //
     // Copy the string to destination
@@ -872,6 +819,7 @@ CreateDeviceIds(
     LPWSTR DeviceString;
     WCHAR Buffer[200];
     PHUB_CHILDDEVICE_EXTENSION UsbChildExtension;
+    PHUB_DEVICE_EXTENSION HubDeviceExtension;
     PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;
     PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
     PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
@@ -881,6 +829,9 @@ CreateDeviceIds(
     //
     UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)UsbChildDeviceObject->DeviceExtension;
 
+    // get hub device extension
+    HubDeviceExtension = (PHUB_DEVICE_EXTENSION) UsbChildExtension->ParentDeviceObject->DeviceExtension;
+
     //
     // get device descriptor
     //
@@ -921,11 +872,6 @@ CreateDeviceIds(
     }
     else
     {
-        //
-        // sanity checks for simple usb device
-        //
-        ASSERT(ConfigurationDescriptor->bNumInterfaces == 1);
-
         //
         // FIXME: support multiple configurations
         //
@@ -1055,7 +1001,7 @@ CreateDeviceIds(
         if (!NT_SUCCESS(Status))
         {
             DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
-            RtlInitUnicodeString(&UsbChildExtension->usTextDescription, L"");
+            RtlInitUnicodeString(&UsbChildExtension->usTextDescription, L"USB Device"); // FIXME NON-NLS
         }
         else
         {
@@ -1069,10 +1015,12 @@ CreateDeviceIds(
     //
     if (UsbChildExtension->DeviceDesc.iSerialNumber)
     {
+       LPWSTR SerialBuffer = NULL;
+
         Status = GetUsbStringDescriptor(UsbChildDeviceObject,
                                         UsbChildExtension->DeviceDesc.iSerialNumber,
                                         0,
-                                        (PVOID*)&UsbChildExtension->usInstanceId.Buffer,
+                                        (PVOID*)&SerialBuffer,
                                         &UsbChildExtension->usInstanceId.Length);
         if (!NT_SUCCESS(Status))
         {
@@ -1080,15 +1028,31 @@ CreateDeviceIds(
             return Status;
         }
 
-        UsbChildExtension->usInstanceId.MaximumLength = UsbChildExtension->usInstanceId.Length;
-        DPRINT("Usb InstanceId %wZ\n", &UsbChildExtension->usInstanceId);
+        // construct instance id buffer
+        Index = swprintf(Buffer, L"%04d&%s", HubDeviceExtension->InstanceCount, SerialBuffer) + 1;
+        UsbChildExtension->usInstanceId.Buffer = (LPWSTR)ExAllocatePool(NonPagedPool, Index * sizeof(WCHAR));
+        if (UsbChildExtension->usInstanceId.Buffer == NULL)
+        {
+            DPRINT1("Error: failed to allocate %lu bytes\n", Index * sizeof(WCHAR));
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            return Status;
+        }
+
+        //
+        // copy instance id
+        //
+        RtlCopyMemory(UsbChildExtension->usInstanceId.Buffer, Buffer, Index * sizeof(WCHAR));
+        UsbChildExtension->usInstanceId.Length = UsbChildExtension->usInstanceId.MaximumLength = Index * sizeof(WCHAR);
+        ExFreePool(SerialBuffer);
+
+        DPRINT("Usb InstanceId %wZ InstanceCount %x\n", &UsbChildExtension->usInstanceId, HubDeviceExtension->InstanceCount);
     }
     else
     {
        //
        // the device did not provide a serial number, lets create a pseudo instance id
        //
-       Index = swprintf(Buffer, L"0&%04d", UsbChildExtension->PortNumber) + 1;
+       Index = swprintf(Buffer, L"%04d&%04d", HubDeviceExtension->InstanceCount, UsbChildExtension->PortNumber) + 1;
        UsbChildExtension->usInstanceId.Buffer = (LPWSTR)ExAllocatePool(NonPagedPool, Index * sizeof(WCHAR));
        if (UsbChildExtension->usInstanceId.Buffer == NULL)
        {
@@ -1106,7 +1070,7 @@ CreateDeviceIds(
        DPRINT("usDeviceId %wZ\n", &UsbChildExtension->usInstanceId);
     }
 
-    return Status;
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS
@@ -1169,7 +1133,7 @@ CreateUsbChildDeviceObject(
     ULONG ChildDeviceCount, UsbDeviceNumber = 0;
     WCHAR CharDeviceName[64];
     UNICODE_STRING DeviceName;
-    ULONG ConfigDescSize, DeviceDescSize;
+    ULONG ConfigDescSize, DeviceDescSize, DeviceInfoSize;
     PVOID HubInterfaceBusContext;
     USB_CONFIGURATION_DESCRIPTOR ConfigDesc;
 
@@ -1256,6 +1220,10 @@ CreateUsbChildDeviceObject(
     UsbChildExtension->ParentDeviceObject = UsbHubDeviceObject;
     UsbChildExtension->PortNumber = PortId;
 
+    // copy device interface
+    RtlCopyMemory(&UsbChildExtension->DeviceInterface, &HubDeviceExtension->DeviceInterface, sizeof(USB_BUS_INTERFACE_USBDI_V2));
+
+
     //
     // Create the UsbDeviceObject
     //
@@ -1270,6 +1238,12 @@ CreateUsbChildDeviceObject(
         goto Cleanup;
     }
 
+    // copy device interface
+    RtlCopyMemory(&UsbChildExtension->DeviceInterface, &HubDeviceExtension->DeviceInterface, sizeof(USB_BUS_INTERFACE_USBDI_V2));
+
+    // FIXME replace buscontext
+    UsbChildExtension->DeviceInterface.BusContext = UsbChildExtension->UsbDeviceHandle;
+
     //
     // Initialize UsbDevice
     //
@@ -1339,6 +1313,14 @@ CreateUsbChildDeviceObject(
         goto Cleanup;
     }
 
+    // query device details
+    Status = HubInterface->QueryDeviceInformation(HubInterfaceBusContext, 
+                                         UsbChildExtension->UsbDeviceHandle,
+                                         &UsbChildExtension->DeviceInformation,
+                                         sizeof(USB_DEVICE_INFORMATION_0),
+                                         &DeviceInfoSize);
+
+
     //DumpFullConfigurationDescriptor(UsbChildExtension->FullConfigDesc);
 
     //
@@ -1352,6 +1334,7 @@ CreateUsbChildDeviceObject(
     }
 
     HubDeviceExtension->ChildDeviceObject[ChildDeviceCount] = NewChildDeviceObject;
+    HubDeviceExtension->InstanceCount++;
 
     IoInvalidateDeviceRelations(RootHubDeviceObject, BusRelations);
     return STATUS_SUCCESS;
@@ -1495,401 +1478,505 @@ RootHubInitCallbackFunction(
     }
 }
 
+BOOLEAN
+USBHUB_IsRootHubFDO(
+   IN PDEVICE_OBJECT DeviceObject)
+{
+    NTSTATUS Status;
+    PDEVICE_OBJECT RootHubPhysicalDeviceObject = NULL;
+    PHUB_DEVICE_EXTENSION HubDeviceExtension;
+
+    // get hub device extension
+    HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+    // Get the Root Hub Pdo
+    Status = SubmitRequestToRootHub(HubDeviceExtension->LowerDeviceObject,
+                                    IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
+                                    &RootHubPhysicalDeviceObject,
+                                    NULL);
+
+    // FIXME handle error
+    ASSERT(NT_SUCCESS(Status));
+
+    // physical device object is only obtained for root hubs
+    return (RootHubPhysicalDeviceObject != NULL);
+}
+
+
 NTSTATUS
-USBHUB_FdoHandlePnp(
-    IN PDEVICE_OBJECT DeviceObject,
-    IN PIRP Irp)
+USBHUB_FdoStartDevice(
+   IN PDEVICE_OBJECT DeviceObject,
+   IN PIRP Irp)
 {
+    PURB Urb;
+    PUSB_INTERFACE_DESCRIPTOR Pid;
+    ULONG Result = 0, PortId;
+    USBD_INTERFACE_LIST_ENTRY InterfaceList[2] = {{NULL, NULL}, {NULL, NULL}};
+    PURB ConfigUrb = NULL;
+    ULONG HubStatus;
     PIO_STACK_LOCATION Stack;
     NTSTATUS Status = STATUS_SUCCESS;
-    ULONG_PTR Information = 0;
     PHUB_DEVICE_EXTENSION HubDeviceExtension;
     PDEVICE_OBJECT RootHubDeviceObject;
     PVOID HubInterfaceBusContext , UsbDInterfaceBusContext;
     PORT_STATUS_CHANGE StatusChange;
 
+    // get current stack location
+    Stack = IoGetCurrentIrpStackLocation(Irp);
+
+    // get hub device extension
     HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
 
-    Stack = IoGetCurrentIrpStackLocation(Irp);
+    DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
 
-    switch (Stack->MinorFunction)
+    // Allocated size including the sizeof USBD_INTERFACE_LIST_ENTRY
+    Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY), USB_HUB_TAG);
+    if (!Urb)
     {
-        case IRP_MN_START_DEVICE:
-        {
-            PURB Urb;
-            PUSB_INTERFACE_DESCRIPTOR Pid;
-            ULONG Result = 0, PortId;
-            USBD_INTERFACE_LIST_ENTRY InterfaceList[2] = {{NULL, NULL}, {NULL, NULL}};
-            PURB ConfigUrb = NULL;
-            ULONG HubStatus;
+         // no memory
+         return STATUS_INSUFFICIENT_RESOURCES;
+    }
 
-            DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
+    // zero urb
+    RtlZeroMemory(Urb, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY));
 
-            //
-            // Allocated size including the sizeof USBD_INTERFACE_LIST_ENTRY
-            //
-            Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY), USB_HUB_TAG);
-            RtlZeroMemory(Urb, sizeof(URB) + sizeof(USBD_INTERFACE_LIST_ENTRY));
+    // Get the Root Hub Pdo
+    Status = SubmitRequestToRootHub(HubDeviceExtension->LowerDeviceObject,
+                                    IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
+                                    &HubDeviceExtension->RootHubPhysicalDeviceObject,
+                                    &HubDeviceExtension->RootHubFunctionalDeviceObject);
+    if (!NT_SUCCESS(Status))
+    {
+        // failed to obtain hub pdo
+        DPRINT1("IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO failed with %x\n", Status);
+        ExFreePool(Urb);
+        return Status;
+    }
 
-            //
-            // Get the Root Hub Pdo
-            //
-            SubmitRequestToRootHub(HubDeviceExtension->LowerDeviceObject,
-                                   IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO,
-                                   &HubDeviceExtension->RootHubPhysicalDeviceObject,
-                                   &HubDeviceExtension->RootHubFunctionalDeviceObject);
-
-            RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
-            ASSERT(HubDeviceExtension->RootHubPhysicalDeviceObject);
-            ASSERT(HubDeviceExtension->RootHubFunctionalDeviceObject);
-            DPRINT("RootPdo %x, RootFdo %x\n",
-                    HubDeviceExtension->RootHubPhysicalDeviceObject,
-                    HubDeviceExtension->RootHubFunctionalDeviceObject);
+    // sanity checks
+    ASSERT(HubDeviceExtension->RootHubPhysicalDeviceObject);
+    ASSERT(HubDeviceExtension->RootHubFunctionalDeviceObject);
 
-            //
-            // Send the StartDevice to RootHub
-            //
-            Status = ForwardIrpAndWait(RootHubDeviceObject, Irp);
+    // get roothub
+    RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
 
-            if (!NT_SUCCESS(Status))
-            {
-                DPRINT1("Failed to start the RootHub PDO\n");
-                ASSERT(FALSE);
-            }
+    // Send the StartDevice to RootHub
+    Status = ForwardIrpAndWait(RootHubDeviceObject, Irp);
 
-            //
-            // Get the current number of hubs
-            //
-            Status = SubmitRequestToRootHub(RootHubDeviceObject,
-                                            IOCTL_INTERNAL_USB_GET_HUB_COUNT,
-                                            &HubDeviceExtension->NumberOfHubs, NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        // failed to start pdo
+        DPRINT1("Failed to start the RootHub PDO\n");
+        ExFreePool(Urb);
+        return Status;
+    }
 
-            //
-            // Get the Hub Interface
-            //
-            Status = QueryInterface(RootHubDeviceObject,
-                                    USB_BUS_INTERFACE_HUB_GUID,
-                                    sizeof(USB_BUS_INTERFACE_HUB_V5),
-                                    5,
-                                    (PVOID)&HubDeviceExtension->HubInterface);
+    // Get the current number of hubs
+    Status = SubmitRequestToRootHub(RootHubDeviceObject,
+                                    IOCTL_INTERNAL_USB_GET_HUB_COUNT,
+                                    &HubDeviceExtension->NumberOfHubs, NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        // failed to get number of hubs
+        DPRINT1("IOCTL_INTERNAL_USB_GET_HUB_COUNT failed with %x\n", Status);
+        ExFreePool(Urb);
+        return Status;
+    }
 
-            if (!NT_SUCCESS(Status))
-            {
-                DPRINT1("Failed to get HUB_GUID interface with status 0x%08lx\n", Status);
-                return STATUS_UNSUCCESSFUL;
-            }
+    // Get the Hub Interface
+    Status = QueryInterface(RootHubDeviceObject,
+                            USB_BUS_INTERFACE_HUB_GUID,
+                            sizeof(USB_BUS_INTERFACE_HUB_V5),
+                            USB_BUSIF_HUB_VERSION_5,
+                            (PVOID)&HubDeviceExtension->HubInterface);
 
-            HubInterfaceBusContext = HubDeviceExtension->HubInterface.BusContext;
+    if (!NT_SUCCESS(Status))
+    {
+        // failed to get root hub interface
+        DPRINT1("Failed to get HUB_GUID interface with status 0x%08lx\n", Status);
+        ExFreePool(Urb);
+        return Status;
+    }
 
-            //
-            // Get the USBDI Interface
-            //
-            Status = QueryInterface(RootHubDeviceObject,
-                                    USB_BUS_INTERFACE_USBDI_GUID,
-                                    sizeof(USB_BUS_INTERFACE_USBDI_V2),
-                                    2,
-                                    (PVOID)&HubDeviceExtension->UsbDInterface);
+    HubInterfaceBusContext = HubDeviceExtension->HubInterface.BusContext;
 
-            if (!NT_SUCCESS(Status))
-            {
-                DPRINT1("Failed to get USBDI_GUID interface with status 0x%08lx\n", Status);
-                return Status;
-            }
+    // Get the USBDI Interface
+    Status = QueryInterface(RootHubDeviceObject,
+                            USB_BUS_INTERFACE_USBDI_GUID,
+                            sizeof(USB_BUS_INTERFACE_USBDI_V2),
+                            USB_BUSIF_USBDI_VERSION_2,
+                            (PVOID)&HubDeviceExtension->UsbDInterface);
 
-            UsbDInterfaceBusContext = HubDeviceExtension->UsbDInterface.BusContext;
+    if (!NT_SUCCESS(Status))
+    {
+        // failed to get usbdi interface
+        DPRINT1("Failed to get USBDI_GUID interface with status 0x%08lx\n", Status);
+        ExFreePool(Urb);
+        return Status;
+    }
 
-            //
-            // Get Root Hub Device Handle
-            //
-            Status = SubmitRequestToRootHub(RootHubDeviceObject,
-                                            IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE,
-                                            &HubDeviceExtension->RootHubHandle,
-                                            NULL);
+    UsbDInterfaceBusContext = HubDeviceExtension->UsbDInterface.BusContext;
 
-            if (!NT_SUCCESS(Status))
-            {
-                DPRINT1("GetRootHubDeviceHandle failed with status 0x%08lx\n", Status);
-                return Status;
-            }
+    // Get Root Hub Device Handle
+    Status = SubmitRequestToRootHub(RootHubDeviceObject,
+                                    IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE,
+                                    &HubDeviceExtension->RootHubHandle,
+                                    NULL);
 
-            //
-            // Get Hub Device Information
-            //
-            Status = HubDeviceExtension->HubInterface.QueryDeviceInformation(HubInterfaceBusContext,
-                                                                             HubDeviceExtension->RootHubHandle,
-                                                                             &HubDeviceExtension->DeviceInformation,
-                                                                             sizeof(USB_DEVICE_INFORMATION_0),
-                                                                             &Result);
-
-            DPRINT1("Status %x, Result 0x%08lx\n", Status, Result);
-            DPRINT1("InformationLevel %x\n", HubDeviceExtension->DeviceInformation.InformationLevel);
-            DPRINT1("ActualLength %x\n", HubDeviceExtension->DeviceInformation.ActualLength);
-            DPRINT1("PortNumber %x\n", HubDeviceExtension->DeviceInformation.PortNumber);
-            DPRINT1("DeviceDescriptor %x\n", HubDeviceExtension->DeviceInformation.DeviceDescriptor);
-            DPRINT1("HubAddress %x\n", HubDeviceExtension->DeviceInformation.HubAddress);
-            DPRINT1("NumberofPipes %x\n", HubDeviceExtension->DeviceInformation.NumberOfOpenPipes);
+    if (!NT_SUCCESS(Status))
+    {
+        // failed
+        DPRINT1("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE failed with status 0x%08lx\n", Status);
+        ExFreePool(Urb);
+        return Status;
+    }
 
-            //
-            // Get Root Hubs Device Descriptor
-            //
-            UsbBuildGetDescriptorRequest(Urb,
-                                         sizeof(Urb->UrbControlDescriptorRequest),
-                                         USB_DEVICE_DESCRIPTOR_TYPE,
-                                         0,
-                                         0,
-                                         &HubDeviceExtension->HubDeviceDescriptor,
-                                         NULL,
-                                         sizeof(USB_DEVICE_DESCRIPTOR),
-                                         NULL);
-
-            Urb->UrbHeader.UsbdDeviceHandle = NULL;//HubDeviceExtension->RootHubHandle;
-
-            Status = SubmitRequestToRootHub(RootHubDeviceObject,
-                                            IOCTL_INTERNAL_USB_SUBMIT_URB,
-                                            Urb,
-                                            NULL);
+    //
+    // Get Hub Device Information
+    //
+    Status = HubDeviceExtension->HubInterface.QueryDeviceInformation(HubInterfaceBusContext,
+                                                                        HubDeviceExtension->RootHubHandle,
+                                                                        &HubDeviceExtension->DeviceInformation,
+                                                                        sizeof(USB_DEVICE_INFORMATION_0),
+                                                                        &Result);
 
-            if (!NT_SUCCESS(Status))
-            {
-                DPRINT1("Failed to get HubDeviceDescriptor!\n");
-            }
+    DPRINT1("Status %x, Result 0x%08lx\n", Status, Result);
+    DPRINT1("InformationLevel %x\n", HubDeviceExtension->DeviceInformation.InformationLevel);
+    DPRINT1("ActualLength %x\n", HubDeviceExtension->DeviceInformation.ActualLength);
+    DPRINT1("PortNumber %x\n", HubDeviceExtension->DeviceInformation.PortNumber);
+    DPRINT1("DeviceDescriptor %x\n", HubDeviceExtension->DeviceInformation.DeviceDescriptor);
+    DPRINT1("HubAddress %x\n", HubDeviceExtension->DeviceInformation.HubAddress);
+    DPRINT1("NumberofPipes %x\n", HubDeviceExtension->DeviceInformation.NumberOfOpenPipes);
 
-            DumpDeviceDescriptor(&HubDeviceExtension->HubDeviceDescriptor);
+    // Get Root Hubs Device Descriptor
+    UsbBuildGetDescriptorRequest(Urb,
+                                    sizeof(Urb->UrbControlDescriptorRequest),
+                                    USB_DEVICE_DESCRIPTOR_TYPE,
+                                    0,
+                                    0,
+                                    &HubDeviceExtension->HubDeviceDescriptor,
+                                    NULL,
+                                    sizeof(USB_DEVICE_DESCRIPTOR),
+                                    NULL);
 
-            //
-            // Get Root Hubs Configuration Descriptor
-            //
-            UsbBuildGetDescriptorRequest(Urb,
-                                         sizeof(Urb->UrbControlDescriptorRequest),
-                                         USB_CONFIGURATION_DESCRIPTOR_TYPE,
-                                         0,
-                                         0,
-                                         &HubDeviceExtension->HubConfigDescriptor,
-                                         NULL,
-                                         sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR),
-                                         NULL);
-
-            DPRINT("RootHub Handle %x\n", HubDeviceExtension->RootHubHandle);
-            Urb->UrbHeader.UsbdDeviceHandle = NULL;//HubDeviceExtension->RootHubHandle;
-
-            Status = SubmitRequestToRootHub(RootHubDeviceObject,
-                                            IOCTL_INTERNAL_USB_SUBMIT_URB,
-                                            Urb,
-                                            NULL);
+    // set device handle
+    Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
 
-            if (!NT_SUCCESS(Status))
-            {
-                DPRINT1("Failed to get RootHub Configuration with status %x\n", Status);
-                ASSERT(FALSE);
-            }
-            ASSERT(HubDeviceExtension->HubConfigDescriptor.wTotalLength);
+    // get hub device descriptor
+    Status = SubmitRequestToRootHub(RootHubDeviceObject,
+                                    IOCTL_INTERNAL_USB_SUBMIT_URB,
+                                    Urb,
+                                    NULL);
 
-            DumpConfigurationDescriptor(&HubDeviceExtension->HubConfigDescriptor);
+    if (!NT_SUCCESS(Status))
+    {
+        // failed to get device descriptor of hub
+        DPRINT1("Failed to get HubDeviceDescriptor!\n");
+        ExFreePool(Urb);
+        return Status;
+    }
 
-            Status = HubDeviceExtension->HubInterface.GetExtendedHubInformation(HubInterfaceBusContext,
-                                                                                RootHubDeviceObject,
-                                                                                &HubDeviceExtension->UsbExtHubInfo,
-                                                                                sizeof(USB_EXTHUB_INFORMATION_0),
-                                                                                &Result);
-            if (!NT_SUCCESS(Status))
-            {
-                DPRINT1("Failed to extended hub information. Unable to determine the number of ports!\n");
-                ASSERT(FALSE);
-            }
+    // build configuration request
+    UsbBuildGetDescriptorRequest(Urb,
+                                    sizeof(Urb->UrbControlDescriptorRequest),
+                                    USB_CONFIGURATION_DESCRIPTOR_TYPE,
+                                    0,
+                                    0,
+                                    &HubDeviceExtension->HubConfigDescriptor,
+                                    NULL,
+                                    sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR),
+                                    NULL);
 
-            DPRINT1("HubDeviceExtension->UsbExtHubInfo.NumberOfPorts %x\n", HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
+    // set device handle
+    Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
 
-            //
-            // Get the Hub Descriptor
-            //
-            UsbBuildVendorRequest(Urb,
-                                  URB_FUNCTION_CLASS_DEVICE,
-                                  sizeof(Urb->UrbControlVendorClassRequest),
-                                  USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
-                                  0,
-                                  USB_REQUEST_GET_DESCRIPTOR,
-                                  USB_DEVICE_CLASS_RESERVED,
-                                  0,
-                                  &HubDeviceExtension->HubDescriptor,
-                                  NULL,
-                                  sizeof(USB_HUB_DESCRIPTOR),
-                                  NULL);
-
-            Urb->UrbHeader.UsbdDeviceHandle = NULL;//HubDeviceExtension->RootHubHandle;
-
-            Status = SubmitRequestToRootHub(RootHubDeviceObject,
-                                            IOCTL_INTERNAL_USB_SUBMIT_URB,
-                                            Urb,
-                                            NULL);
-
-            DPRINT1("bDescriptorType %x\n", HubDeviceExtension->HubDescriptor.bDescriptorType);
+    // request configuration descriptor
+    Status = SubmitRequestToRootHub(RootHubDeviceObject,
+                                    IOCTL_INTERNAL_USB_SUBMIT_URB,
+                                    Urb,
+                                    NULL);
 
-            if (!NT_SUCCESS(Status))
-            {
-                DPRINT1("Failed to get Hub Descriptor!\n");
-                ExFreePool(Urb);
-                return STATUS_UNSUCCESSFUL;
-            }
+    if (!NT_SUCCESS(Status))
+    {
+        // failed to get configuration descriptor
+        DPRINT1("Failed to get RootHub Configuration with status %x\n", Status);
+        ExFreePool(Urb);
+        return Status;
+    }
 
-            HubStatus = 0;
-            UsbBuildGetStatusRequest(Urb,
-                                     URB_FUNCTION_GET_STATUS_FROM_DEVICE,
-                                     0,
-                                     &HubStatus,
-                                     0,
-                                     NULL);
-            Urb->UrbHeader.UsbdDeviceHandle = NULL;//HubDeviceExtension->RootHubHandle;
-
-            Status = SubmitRequestToRootHub(RootHubDeviceObject,
-                                            IOCTL_INTERNAL_USB_SUBMIT_URB,
-                                            Urb,
-                                            NULL);
-            if (!NT_SUCCESS(Status))
-            {
-                DPRINT1("Failed to get Hub Status!\n");
-                ExFreePool(Urb);
-                return STATUS_UNSUCCESSFUL;
-            }
+    // sanity checks
+    ASSERT(HubDeviceExtension->HubConfigDescriptor.wTotalLength == sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR));
+    ASSERT(HubDeviceExtension->HubConfigDescriptor.bDescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE);
+    ASSERT(HubDeviceExtension->HubConfigDescriptor.bLength == sizeof(USB_CONFIGURATION_DESCRIPTOR));
+    ASSERT(HubDeviceExtension->HubConfigDescriptor.bNumInterfaces == 1);
+    ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
+    ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
+    ASSERT(HubDeviceExtension->HubInterfaceDescriptor.bNumEndpoints == 1);
+    ASSERT(HubDeviceExtension->HubEndPointDescriptor.bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE);
+    ASSERT(HubDeviceExtension->HubEndPointDescriptor.bLength == sizeof(USB_ENDPOINT_DESCRIPTOR));
+    ASSERT(HubDeviceExtension->HubEndPointDescriptor.bmAttributes == USB_ENDPOINT_TYPE_INTERRUPT);
+    ASSERT(HubDeviceExtension->HubEndPointDescriptor.bEndpointAddress == 0x81); // interrupt in
+
+    // get hub information
+    Status = HubDeviceExtension->HubInterface.GetExtendedHubInformation(HubInterfaceBusContext,
+                                                                        RootHubDeviceObject,
+                                                                        &HubDeviceExtension->UsbExtHubInfo,
+                                                                        sizeof(USB_EXTHUB_INFORMATION_0),
+                                                                        &Result);
+    if (!NT_SUCCESS(Status))
+    {
+        // failed to get hub information
+        DPRINT1("Failed to extended hub information. Unable to determine the number of ports!\n");
+        ExFreePool(Urb);
+        return Status;
+    }
 
-            DPRINT1("HubStatus %x\n", HubStatus);
+    if (!HubDeviceExtension->UsbExtHubInfo.NumberOfPorts)
+    {
+        // bogus port driver
+        DPRINT1("Failed to retrieve the number of ports\n");
+        ExFreePool(Urb);
+        return STATUS_UNSUCCESSFUL;
+    }
 
-            //
-            // Allocate memory for PortStatusChange to hold 2 USHORTs for each port on hub
-            //
-            HubDeviceExtension->PortStatusChange = ExAllocatePoolWithTag(NonPagedPool,
-                                                                         sizeof(ULONG) * HubDeviceExtension->UsbExtHubInfo.NumberOfPorts,
-                                                                         USB_HUB_TAG);
+    DPRINT1("HubDeviceExtension->UsbExtHubInfo.NumberOfPorts %x\n", HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
 
-            //
-            // Get the first Configuration Descriptor
-            //
-            Pid = USBD_ParseConfigurationDescriptorEx(&HubDeviceExtension->HubConfigDescriptor,
-                                                      &HubDeviceExtension->HubConfigDescriptor,
-                                                     -1, -1, -1, -1, -1);
+    // Build hub descriptor request
+    UsbBuildVendorRequest(Urb,
+                            URB_FUNCTION_CLASS_DEVICE,
+                            sizeof(Urb->UrbControlVendorClassRequest),
+                            USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
+                            0,
+                            USB_REQUEST_GET_DESCRIPTOR,
+                            USB_DEVICE_CLASS_RESERVED,
+                            0,
+                            &HubDeviceExtension->HubDescriptor,
+                            NULL,
+                            sizeof(USB_HUB_DESCRIPTOR),
+                            NULL);
+
+    // set device handle
+    Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
+
+    // send request
+    Status = SubmitRequestToRootHub(RootHubDeviceObject,
+                                    IOCTL_INTERNAL_USB_SUBMIT_URB,
+                                    Urb,
+                                    NULL);
 
-            ASSERT(Pid != NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to get Hub Descriptor!\n");
+        ExFreePool(Urb);
+        return STATUS_UNSUCCESSFUL;
+    }
 
-            InterfaceList[0].InterfaceDescriptor = Pid;
-            ConfigUrb = USBD_CreateConfigurationRequestEx(&HubDeviceExtension->HubConfigDescriptor,
-                                                          (PUSBD_INTERFACE_LIST_ENTRY)&InterfaceList);
-            ASSERT(ConfigUrb != NULL);
+    // sanity checks
+    ASSERT(HubDeviceExtension->HubDescriptor.bDescriptorLength == sizeof(USB_HUB_DESCRIPTOR));
+    ASSERT(HubDeviceExtension->HubDescriptor.bNumberOfPorts == HubDeviceExtension->UsbExtHubInfo.NumberOfPorts);
+    ASSERT(HubDeviceExtension->HubDescriptor.bDescriptorType == 0x29);
+
+    // build get status request
+    HubStatus = 0;
+    UsbBuildGetStatusRequest(Urb,
+                                URB_FUNCTION_GET_STATUS_FROM_DEVICE,
+                                0,
+                                &HubStatus,
+                                0,
+                                NULL);
+    // set device handle
+    Urb->UrbHeader.UsbdDeviceHandle = HubDeviceExtension->RootHubHandle;
+
+    // send request
+    Status = SubmitRequestToRootHub(RootHubDeviceObject,
+                                    IOCTL_INTERNAL_USB_SUBMIT_URB,
+                                    Urb,
+                                    NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        // failed to get hub status
+        DPRINT1("Failed to get Hub Status!\n");
+        ExFreePool(Urb);
+        return STATUS_UNSUCCESSFUL;
+    }
 
-            Status = SubmitRequestToRootHub(RootHubDeviceObject,
-                                            IOCTL_INTERNAL_USB_SUBMIT_URB,
-                                            ConfigUrb,
-                                            NULL);
+    // Allocate memory for PortStatusChange to hold 2 USHORTs for each port on hub
+    HubDeviceExtension->PortStatusChange = ExAllocatePoolWithTag(NonPagedPool,
+                                                                    sizeof(ULONG) * HubDeviceExtension->UsbExtHubInfo.NumberOfPorts,
+                                                                    USB_HUB_TAG);
 
-            HubDeviceExtension->ConfigurationHandle = ConfigUrb->UrbSelectConfiguration.ConfigurationHandle;
-            HubDeviceExtension->PipeHandle = ConfigUrb->UrbSelectConfiguration.Interface.Pipes[0].PipeHandle;
-            DPRINT("Configuration Handle %x\n", HubDeviceExtension->ConfigurationHandle);
+    // Get the first Configuration Descriptor
+    Pid = USBD_ParseConfigurationDescriptorEx(&HubDeviceExtension->HubConfigDescriptor,
+                                                &HubDeviceExtension->HubConfigDescriptor,
+                                                -1, -1, -1, -1, -1);
+    if (Pid == NULL)
+    {
+        // failed parse hub descriptor
+        DPRINT1("Failed to parse configuration descriptor\n");
+        ExFreePool(Urb);
+        return STATUS_UNSUCCESSFUL;
+    }
 
-            //
-            // check if function is available
-            //
-            if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed)
-            {
-                //
-                // is it high speed bus
-                //
-                if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed(HubInterfaceBusContext))
-                {
-                    //
-                    // initialize usb 2.0 hub
-                    //
-                    Status = HubDeviceExtension->HubInterface.Initialize20Hub(HubInterfaceBusContext,
-                                                                              HubDeviceExtension->RootHubHandle, 1);
-                    DPRINT("Status %x\n", Status);
+    // create configuration request
+    InterfaceList[0].InterfaceDescriptor = Pid;
+    ConfigUrb = USBD_CreateConfigurationRequestEx(&HubDeviceExtension->HubConfigDescriptor,
+                                                    (PUSBD_INTERFACE_LIST_ENTRY)&InterfaceList);
+    if (ConfigUrb == NULL)
+    {
+        // failed to build urb
+        DPRINT1("Failed to allocate urb\n");
+        ExFreePool(Urb);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
 
-                    //
-                    // FIXME handle error
-                    //
-                    ASSERT(Status == STATUS_SUCCESS);
-                }
-            }
+    // send request
+    Status = SubmitRequestToRootHub(RootHubDeviceObject,
+                                    IOCTL_INTERNAL_USB_SUBMIT_URB,
+                                    ConfigUrb,
+                                    NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        // failed to select configuration
+        DPRINT1("Failed to select configuration with %x\n", Status);
+        ExFreePool(Urb);
+        ExFreePool(ConfigUrb);
+        return Status;
+    }
 
-            ExFreePool(ConfigUrb);
+    // store configuration & pipe handle
+    HubDeviceExtension->ConfigurationHandle = ConfigUrb->UrbSelectConfiguration.ConfigurationHandle;
+    HubDeviceExtension->PipeHandle = ConfigUrb->UrbSelectConfiguration.Interface.Pipes[0].PipeHandle;
+    DPRINT("Configuration Handle %x\n", HubDeviceExtension->ConfigurationHandle);
 
-            //
-            // Enable power on all ports
-            //
+    FDO_QueryInterface(DeviceObject, &HubDeviceExtension->DeviceInterface);
 
-            DPRINT("Enabling PortPower on all ports!\n");
 
-            for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
-            {
-                Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_POWER);
-                if (!NT_SUCCESS(Status))
-                    DPRINT1("Failed to power on port %d\n", PortId);
+    // free urb
+    ExFreePool(ConfigUrb);
 
-                Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_CONNECTION);
-                if (!NT_SUCCESS(Status))
-                    DPRINT1("Failed to power on port %d\n", PortId);
-            }
+    // check if function is available
+    if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed)
+    {
+        // is it high speed bus
+        if (HubDeviceExtension->UsbDInterface.IsDeviceHighSpeed(HubInterfaceBusContext))
+        {
+            // initialize usb 2.0 hub
+            Status = HubDeviceExtension->HubInterface.Initialize20Hub(HubInterfaceBusContext,
+                                                                        HubDeviceExtension->RootHubHandle, 1);
+            DPRINT("Status %x\n", Status);
+
+            // FIXME handle error
+            ASSERT(Status == STATUS_SUCCESS);
+        }
+    }
+
+
+    // Enable power on all ports
+    DPRINT("Enabling PortPower on all ports!\n");
+    for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
+    {
+        Status = SetPortFeature(RootHubDeviceObject, PortId, PORT_POWER);
+        if (!NT_SUCCESS(Status))
+            DPRINT1("Failed to power on port %d\n", PortId);
+
+        Status = ClearPortFeature(RootHubDeviceObject, PortId, C_PORT_CONNECTION);
+        if (!NT_SUCCESS(Status))
+            DPRINT1("Failed to power on port %d\n", PortId);
+    }
 
-            DPRINT("RootHubInitNotification %x\n", HubDeviceExtension->HubInterface.RootHubInitNotification);
+    // init root hub notification
+    if (HubDeviceExtension->HubInterface.RootHubInitNotification)
+    {
+        Status = HubDeviceExtension->HubInterface.RootHubInitNotification(HubInterfaceBusContext,
+                                                                            DeviceObject,
+                                                                            RootHubInitCallbackFunction);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to set callback\n");
+            ExFreePool(Urb);
+            return Status;
+        }
+    }
+    else
+    {
+        // Send the first SCE Request
+        QueryStatusChangeEndpoint(DeviceObject);
 
+        //
+        // reset ports
+        //
+        for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
+        {
             //
-            // init root hub notification
+            // get port status
             //
-            if (HubDeviceExtension->HubInterface.RootHubInitNotification)
+            Status = GetPortStatusAndChange(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, &StatusChange);
+            if (NT_SUCCESS(Status))
             {
-                Status = HubDeviceExtension->HubInterface.RootHubInitNotification(HubInterfaceBusContext,
-                                                                                  DeviceObject,
-                                                                                  RootHubInitCallbackFunction);
-                if (!NT_SUCCESS(Status))
-                {
-                    DPRINT1("Failed to set callback\n");
-                }
-            }
-            else
-            {
-                //
-                // Send the first SCE Request
                 //
-                QueryStatusChangeEndpoint(DeviceObject);
-
-                //
-                // reset ports
+                // is there a device connected
                 //
-                for (PortId = 1; PortId <= HubDeviceExtension->HubDescriptor.bNumberOfPorts; PortId++)
+                if (StatusChange.Status & USB_PORT_STATUS_CONNECT)
                 {
                     //
-                    // get port status
+                    // reset port
                     //
-                    Status = GetPortStatusAndChange(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, &StatusChange);
-                    if (NT_SUCCESS(Status))
+                    Status = SetPortFeature(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, PORT_RESET);
+                    if (!NT_SUCCESS(Status))
+                    {
+                        DPRINT1("Failed to reset on port %d\n", PortId);
+                    }
+                    else
                     {
                         //
-                        // is there a device connected
+                        // wait for the reset to be handled since we want to enumerate synchronously
                         //
-                        if (StatusChange.Status & USB_PORT_STATUS_CONNECT)
-                        {
-                            //
-                            // reset port
-                            //
-                            Status = SetPortFeature(HubDeviceExtension->RootHubPhysicalDeviceObject, PortId, PORT_RESET);
-                            if (!NT_SUCCESS(Status))
-                            {
-                                DPRINT1("Failed to reset on port %d\n", PortId);
-                            }
-                            else
-                            {
-                                //
-                                // wait for the reset to be handled since we want to enumerate synchronously
-                                //
-                                KeWaitForSingleObject(&HubDeviceExtension->ResetComplete,
-                                                      Executive,
-                                                      KernelMode,
-                                                      FALSE,
-                                                      NULL);
-                                KeClearEvent(&HubDeviceExtension->ResetComplete);
-                            }
-                        }
+                        KeWaitForSingleObject(&HubDeviceExtension->ResetComplete,
+                                                Executive,
+                                                KernelMode,
+                                                FALSE,
+                                                NULL);
+                        KeClearEvent(&HubDeviceExtension->ResetComplete);
                     }
                 }
             }
+        }
+    }
 
-            ExFreePool(Urb);
+    // free urb
+    ExFreePool(Urb);
+
+    // done
+    return Status;
+}
+
+NTSTATUS
+USBHUB_FdoHandlePnp(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    PIO_STACK_LOCATION Stack;
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG_PTR Information = 0;
+    PHUB_DEVICE_EXTENSION HubDeviceExtension;
+
+    HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+    Stack = IoGetCurrentIrpStackLocation(Irp);
+
+    switch (Stack->MinorFunction)
+    {
+        case IRP_MN_START_DEVICE:
+        {
+            if (USBHUB_IsRootHubFDO(DeviceObject))
+            {
+                // start root hub fdo
+                Status = USBHUB_FdoStartDevice(DeviceObject, Irp);
+            }
+            else
+            {
+                Status = USBHUB_ParentFDOStartDevice(DeviceObject, Irp);
+            }
             break;
         }
 
@@ -1968,8 +2055,164 @@ USBHUB_FdoHandleDeviceControl(
     IN PDEVICE_OBJECT DeviceObject,
     IN PIRP Irp)
 {
-    DPRINT1("FdoHandleDeviceControl\n");
-    UNIMPLEMENTED
-    return STATUS_NOT_IMPLEMENTED;
+    PIO_STACK_LOCATION IoStack;
+    NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
+    PUSB_NODE_INFORMATION NodeInformation;
+    PHUB_DEVICE_EXTENSION HubDeviceExtension;
+    PUSB_NODE_CONNECTION_INFORMATION NodeConnectionInfo;
+    PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension;
+    PUSB_NODE_CONNECTION_DRIVERKEY_NAME NodeKey;
+    ULONG Index, Length;
+
+    // get stack location
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    // get device extension
+    HubDeviceExtension = (PHUB_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+    if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_INFORMATION)
+    {
+        // is the buffer big enough
+        if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(USB_NODE_INFORMATION))
+        {
+            // buffer too small
+            Status = STATUS_BUFFER_TOO_SMALL;
+        }
+        else
+        {
+            // get buffer
+            NodeInformation = (PUSB_NODE_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+            // sanity check
+            ASSERT(NodeInformation);
+
+            // init buffer
+            NodeInformation->NodeType = UsbHub;
+            RtlCopyMemory(&NodeInformation->u.HubInformation.HubDescriptor, &HubDeviceExtension->HubDescriptor, sizeof(USB_HUB_DESCRIPTOR));
+
+            // FIXME is hub powered
+            NodeInformation->u.HubInformation.HubIsBusPowered = TRUE;
+
+            // done
+            Irp->IoStatus.Information = sizeof(USB_NODE_INFORMATION);
+            Status = STATUS_SUCCESS;
+        }
+
+
+    }
+    else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_CONNECTION_INFORMATION)
+    {
+        if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(USB_NODE_CONNECTION_INFORMATION))
+        {
+            // buffer too small
+            Status = STATUS_BUFFER_TOO_SMALL;
+        }
+        else
+        {
+            // get node connection info
+            NodeConnectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+            // sanity checks
+            ASSERT(NodeConnectionInfo);
+
+            for(Index = 0; Index < USB_MAXCHILDREN; Index++)
+            {
+                if (HubDeviceExtension->ChildDeviceObject[Index] == NULL)
+                    continue;
+
+                // get child device extension
+                ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)HubDeviceExtension->ChildDeviceObject[Index]->DeviceExtension;
+
+                if (ChildDeviceExtension->PortNumber != NodeConnectionInfo->ConnectionIndex)
+                   continue;
+
+                // init node connection info
+                RtlCopyMemory(&NodeConnectionInfo->DeviceDescriptor, &ChildDeviceExtension->DeviceDesc, sizeof(USB_DEVICE_DESCRIPTOR));
+                NodeConnectionInfo->CurrentConfigurationValue = ChildDeviceExtension->FullConfigDesc->bConfigurationValue;
+                NodeConnectionInfo->DeviceIsHub = FALSE; //FIXME support hubs
+                NodeConnectionInfo->LowSpeed = ChildDeviceExtension->DeviceInformation.DeviceSpeed == UsbLowSpeed;
+                NodeConnectionInfo->DeviceAddress = ChildDeviceExtension->DeviceInformation.DeviceAddress;
+                NodeConnectionInfo->NumberOfOpenPipes = ChildDeviceExtension->DeviceInformation.NumberOfOpenPipes;
+                NodeConnectionInfo->ConnectionStatus = DeviceConnected; //FIXME
+
+                if (NodeConnectionInfo->NumberOfOpenPipes)
+                {
+                    DPRINT1("Need to copy pipe information\n");
+                }
+                break;
+            }
+
+            // done
+            Irp->IoStatus.Information = sizeof(USB_NODE_INFORMATION);
+            Status = STATUS_SUCCESS;
+        }
+    }
+    else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME)
+    {
+        if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(USB_NODE_CONNECTION_INFORMATION))
+        {
+            // buffer too small
+            Status = STATUS_BUFFER_TOO_SMALL;
+        }
+        else
+        {
+            // get node connection info
+            NodeKey = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)Irp->AssociatedIrp.SystemBuffer;
+
+            // sanity checks
+            ASSERT(NodeKey);
+
+            for(Index = 0; Index < USB_MAXCHILDREN; Index++)
+            {
+                if (HubDeviceExtension->ChildDeviceObject[Index] == NULL)
+                    continue;
+
+                // get child device extension
+                ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)HubDeviceExtension->ChildDeviceObject[Index]->DeviceExtension;
+
+                if (ChildDeviceExtension->PortNumber != NodeKey->ConnectionIndex)
+                   continue;
+
+                // get driver key
+                Status = IoGetDeviceProperty(HubDeviceExtension->ChildDeviceObject[Index], DevicePropertyDriverKeyName,
+                                             IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME),
+                                             NodeKey->DriverKeyName,
+                                             &Length);
+
+                if (Status == STATUS_BUFFER_TOO_SMALL)
+                {
+                    // normalize status
+                    Status = STATUS_SUCCESS;
+                }
+
+                if (Length + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME) > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
+                {
+                    // terminate node key name
+                    NodeKey->DriverKeyName[0] = 0;
+                    Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
+                }
+                else
+                {
+                    // result size
+                    Irp->IoStatus.Information = Length + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
+                }
+
+                // length of driver name
+                NodeKey->ActualLength = Length + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
+                break;
+            }
+        }
+    }
+    else
+    {
+        DPRINT1("UNIMPLEMENTED FdoHandleDeviceControl IoCtl %x InputBufferLength %x OutputBufferLength %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode, 
+           IoStack->Parameters.DeviceIoControl.InputBufferLength, IoStack->Parameters.DeviceIoControl.OutputBufferLength);
+    }
+
+    // finish irp
+    Irp->IoStatus.Status = Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return Status;
 }