[USBHUB_NEW]
[reactos.git] / drivers / usb / usbhub_new / fdo.c
index 04f1871..89bc706 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * PROJECT:         ReactOS Universal Serial Bus Hub Driver
  * LICENSE:         GPL - See COPYING in the top level directory
  * FILE:            drivers/usb/usbhub/fdo.c
@@ -9,8 +9,6 @@
  */
 
 #define INITGUID
-
-#define NDEBUG
 #include "usbhub.h"
 
 NTSTATUS
@@ -23,6 +21,11 @@ CreateUsbChildDeviceObject(
     IN LONG PortId,
     OUT PDEVICE_OBJECT *UsbChildDeviceObject);
 
+NTSTATUS
+DestroyUsbChildDeviceObject(
+    IN PDEVICE_OBJECT UsbHubDeviceObject,
+    IN LONG PortId);
+
 NTSTATUS
 SubmitRequestToRootHub(
     IN PDEVICE_OBJECT RootHubDeviceObject,
@@ -73,12 +76,19 @@ SubmitRequestToRootHub(
     //
     Status = IoCallDriver(RootHubDeviceObject, Irp);
 
-    if (Status == STATUS_PENDING)
+    //
+    // 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;
 }
 
@@ -107,7 +117,7 @@ GetPortStatusAndChange(
     RtlZeroMemory(Urb, sizeof(URB));
 
     //
-    // Create URB for getting Port Status
+    // Initialize URB for getting Port Status
     //
     UsbBuildVendorRequest(Urb,
                           URB_FUNCTION_CLASS_OTHER,
@@ -160,7 +170,7 @@ SetPortFeature(
     RtlZeroMemory(Urb, sizeof(URB));
 
     //
-    // Create URB for Clearing Port Reset
+    // Initialize URB for Clearing Port Reset
     //
     UsbBuildVendorRequest(Urb,
                           URB_FUNCTION_CLASS_OTHER,
@@ -212,7 +222,7 @@ ClearPortFeature(
     RtlZeroMemory(Urb, sizeof(URB));
 
     //
-    // Create URB for Clearing Port Reset
+    // Initialize URB for Clearing Port Reset
     //
     UsbBuildVendorRequest(Urb,
                           URB_FUNCTION_CLASS_OTHER,
@@ -249,9 +259,11 @@ DeviceStatusChangeThread(
     PWORK_ITEM_DATA WorkItemData;
     PORT_STATUS_CHANGE PortStatus;
     LONG PortId;
-    DPRINT1("Entered DeviceStatusChangeThread, Context %x\n", Context);
+
     static LONG failsafe = 0;
 
+    DPRINT1("Entered DeviceStatusChangeThread, Context %x\n", Context);
+
     WorkItemData = (PWORK_ITEM_DATA)Context;
     DeviceObject = (PDEVICE_OBJECT)WorkItemData->Context;
     HubDeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
@@ -297,16 +309,18 @@ DeviceStatusChangeThread(
             {
                 DPRINT1("Device disconnected from port %d\n", PortId);
 
-                //
-                // FIXME: Remove the device, and deallocate memory
-                //
+                Status = DestroyUsbChildDeviceObject(DeviceObject, PortId);
+                if (!NT_SUCCESS(Status))
+                {
+                    DPRINT1("Failed to delete child device object after disconnect\n");
+                }
             }
             else
             {
                 DPRINT1("Device connected from port %d\n", PortId);
 
                 // No SCE completion done for clearing C_PORT_CONNECT
-    
+
                 //
                 // Reset Port
                 //
@@ -315,7 +329,7 @@ DeviceStatusChangeThread(
                 {
                     DPRINT1("Failed to reset port %d\n", PortId);
                 }
-            }    
+            }
         }
         else if (PortStatus.Change & USB_PORT_STATUS_ENABLE)
         {
@@ -353,11 +367,23 @@ DeviceStatusChangeThread(
             DPRINT1("Port %d Status %x\n", PortId, PortStatus.Status);
             DPRINT1("Port %d Change %x\n", PortId, PortStatus.Change);
 
+            //
+            // Check that reset was cleared
+            //
             if(PortStatus.Change & USB_PORT_STATUS_RESET)
             {
                 DPRINT1("Port did not clear reset! Possible Hardware problem!\n");
             }
 
+            //
+            // Check if the device is still connected
+            //
+            if (!(PortStatus.Status & USB_PORT_STATUS_CONNECT))
+            {
+                DPRINT1("Device has been disconnected\n");
+                continue;
+            }
+
             //
             // Make sure its Connected and Enabled
             //
@@ -409,6 +435,7 @@ DeviceStatusChangeThread(
 }
 
 NTSTATUS
+NTAPI
 StatusChangeEndpointCompletion(
     IN PDEVICE_OBJECT DeviceObject,
     IN PIRP Irp,
@@ -438,7 +465,7 @@ StatusChangeEndpointCompletion(
     }
     WorkItemData->Context = RealDeviceObject;
     DPRINT1("Initialize work item\n");
-    ExInitializeWorkItem(&WorkItemData->WorkItem, (PWORKER_THREAD_ROUTINE)DeviceStatusChangeThread, (PVOID)WorkItemData);
+    ExInitializeWorkItem(&WorkItemData->WorkItem, DeviceStatusChangeThread, (PVOID)WorkItemData);
 
     //
     // Queue the work item to handle initializing the device
@@ -531,7 +558,7 @@ QueryStatusChangeEndpoint(
     // Set the completion routine for when device is connected to root hub
     //
     IoSetCompletionRoutine(HubDeviceExtension->PendingSCEIrp,
-                           (PIO_COMPLETION_ROUTINE) StatusChangeEndpointCompletion,
+                           StatusChangeEndpointCompletion,
                            DeviceObject,
                            TRUE,
                            TRUE,
@@ -638,7 +665,7 @@ GetUsbDeviceDescriptor(
     RtlZeroMemory(Urb, sizeof(URB));
 
     //
-    // Create URB for getting device descriptor
+    // Initialize URB for getting device descriptor
     //
     UsbBuildGetDescriptorRequest(Urb,
                                  sizeof(Urb->UrbControlDescriptorRequest),
@@ -671,7 +698,8 @@ GetUsbStringDescriptor(
     IN PDEVICE_OBJECT ChildDeviceObject,
     IN UCHAR Index,
     IN USHORT LangId,
-    OUT PVOID *TransferBuffer)
+    OUT PVOID *TransferBuffer,
+    OUT USHORT *Size)
 {
     NTSTATUS Status;
     PUSB_STRING_DESCRIPTOR StringDesc = NULL;
@@ -702,8 +730,17 @@ GetUsbStringDescriptor(
         ExFreePool(StringDesc);
         return Status;
     }
-
     DPRINT1("StringDesc->bLength %d\n", StringDesc->bLength);
+
+    //
+    // Did we get something more than the length of the first two fields of structure?
+    //
+    if (StringDesc->bLength == 2)
+    {
+        DPRINT1("USB Device Error!\n");
+        ExFreePool(StringDesc);
+        return STATUS_DEVICE_DATA_ERROR;
+    }
     SizeNeeded = StringDesc->bLength + sizeof(WCHAR);
 
     //
@@ -760,12 +797,261 @@ GetUsbStringDescriptor(
     // Copy the string to destination
     //
     RtlCopyMemory(*TransferBuffer, StringDesc->bString, SizeNeeded - FIELD_OFFSET(USB_STRING_DESCRIPTOR, bLength));
+    *Size = SizeNeeded;
 
     ExFreePool(StringDesc);
 
     return STATUS_SUCCESS;
 }
 
+NTSTATUS
+CreateDeviceIds(
+    PDEVICE_OBJECT UsbChildDeviceObject)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG Index;
+    PWCHAR BufferPtr;
+    WCHAR Buffer[100];
+    PHUB_CHILDDEVICE_EXTENSION UsbChildExtension;
+
+    UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)UsbChildDeviceObject->DeviceExtension;
+
+    //
+    // Initialize the CompatibleIds String
+    //
+    UsbChildExtension->usCompatibleIds.Length = 144;
+    UsbChildExtension->usCompatibleIds.MaximumLength = UsbChildExtension->usCompatibleIds.Length;
+
+    BufferPtr = ExAllocatePoolWithTag(NonPagedPool,
+                                      UsbChildExtension->usCompatibleIds.Length,
+                                      USB_HUB_TAG);
+    if (!BufferPtr)
+    {
+        DPRINT1("Failed to allocate memory\n");
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(BufferPtr, UsbChildExtension->usCompatibleIds.Length);
+
+    Index = 0;
+    //
+    // Construct the CompatibleIds
+    //
+    if (UsbChildExtension->DeviceDesc.bDeviceClass == 0)
+    {
+        PUSB_INTERFACE_DESCRIPTOR InterDesc = (PUSB_INTERFACE_DESCRIPTOR)
+            ((ULONG_PTR)UsbChildExtension->FullConfigDesc + sizeof(USB_CONFIGURATION_DESCRIPTOR));
+
+        Index += swprintf(&BufferPtr[Index], 
+                          L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
+                          InterDesc->bInterfaceClass,InterDesc->bInterfaceSubClass,InterDesc->bInterfaceProtocol) + 1;
+        Index += swprintf(&BufferPtr[Index],
+                          L"USB\\Class_%02x&SubClass_%02x",
+                          InterDesc->bInterfaceClass,InterDesc->bInterfaceSubClass) + 1;
+        Index += swprintf(&BufferPtr[Index],
+                          L"USB\\Class_%02x",
+                          InterDesc->bInterfaceClass) + 1;
+    }
+    else
+    {
+        PUSB_DEVICE_DESCRIPTOR DevDesc = &UsbChildExtension->DeviceDesc;
+        Index += swprintf(&BufferPtr[Index], 
+                          L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
+                          DevDesc->bDeviceClass,DevDesc->bDeviceSubClass,DevDesc->bDeviceProtocol) + 1;
+        Index += swprintf(&BufferPtr[Index],
+                          L"USB\\Class_%02x&SubClass_%02x",
+                          DevDesc->bDeviceClass,DevDesc->bDeviceSubClass) + 1;
+        Index += swprintf(&BufferPtr[Index],
+                          L"USB\\Class_%02x",
+                          DevDesc->bDeviceClass) + 1;
+    }
+    BufferPtr[Index] = UNICODE_NULL;
+    UsbChildExtension->usCompatibleIds.Buffer = BufferPtr;
+    DPRINT1("usCompatibleIds %wZ\n", &UsbChildExtension->usCompatibleIds);
+
+    //
+    // Initialize the DeviceId String
+    //
+    UsbChildExtension->usDeviceId.Length = 44;
+    UsbChildExtension->usDeviceId.MaximumLength  = UsbChildExtension->usDeviceId.Length;
+    BufferPtr = ExAllocatePoolWithTag(NonPagedPool,
+                                      UsbChildExtension->usDeviceId.Length,
+                                      USB_HUB_TAG);
+    if (!BufferPtr)
+    {
+        DPRINT1("Failed to allocate memory\n");
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto Cleanup;
+    }
+
+    //
+    // Construct DeviceId
+    //
+    swprintf(BufferPtr, L"USB\\Vid_%04x&Pid_%04x\0", UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct);
+    UsbChildExtension->usDeviceId.Buffer = BufferPtr;
+    DPRINT1("usDeviceId %wZ\n", &UsbChildExtension->usDeviceId);
+
+    //
+    // Initialize the HardwareId String
+    //
+    UsbChildExtension->usHardwareIds.Length = 110;
+    UsbChildExtension->usHardwareIds.MaximumLength = UsbChildExtension->usHardwareIds.Length;
+    BufferPtr = ExAllocatePoolWithTag(NonPagedPool, UsbChildExtension->usHardwareIds.Length, USB_HUB_TAG);
+    if (!BufferPtr)
+    {
+        DPRINT1("Failed to allocate memory\n");
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto Cleanup;
+    }
+
+    RtlZeroMemory(BufferPtr, UsbChildExtension->usHardwareIds.Length);
+
+    //
+    // Consturct HardwareIds
+    //
+    Index = 0;
+    Index += swprintf(&BufferPtr[Index], 
+                      L"USB\\Vid_%04x&Pid_%04x&Rev_%04x",
+                      UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct, UsbChildExtension->DeviceDesc.bcdDevice) + 1;
+    Index += swprintf(&BufferPtr[Index],
+                      L"USB\\Vid_%04x&Pid_%04x",
+                      UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct) + 1;
+    BufferPtr[Index] = UNICODE_NULL;
+    UsbChildExtension->usHardwareIds.Buffer = BufferPtr;
+    DPRINT1("usHardWareIds %wZ\n", &UsbChildExtension->usHardwareIds);
+
+    //
+    // FIXME: Handle Lang ids
+    //
+
+    //
+    // Get the product string if obe provided
+    //
+    if (UsbChildExtension->DeviceDesc.iProduct)
+    {
+        Status = GetUsbStringDescriptor(UsbChildDeviceObject,
+                                        UsbChildExtension->DeviceDesc.iProduct,
+                                        0,
+                                        (PVOID*)&UsbChildExtension->usTextDescription.Buffer,
+                                        &UsbChildExtension->usTextDescription.Length);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
+            goto Cleanup;
+        }
+
+        UsbChildExtension->usTextDescription.MaximumLength = UsbChildExtension->usTextDescription.Length;
+        DPRINT1("Usb TextDescription %wZ\n", &UsbChildExtension->usTextDescription);
+    }
+
+    //
+    // Get the Serial Number string if obe provided
+    //
+    if (UsbChildExtension->DeviceDesc.iSerialNumber)
+    {
+        Status = GetUsbStringDescriptor(UsbChildDeviceObject,
+                                        UsbChildExtension->DeviceDesc.iSerialNumber,
+                                        0,
+                                        (PVOID*)&UsbChildExtension->usInstanceId.Buffer,
+                                        &UsbChildExtension->usInstanceId.Length);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
+            goto Cleanup;
+        }
+
+        UsbChildExtension->usInstanceId.MaximumLength = UsbChildExtension->usInstanceId.Length;
+        DPRINT1("Usb InstanceId %wZ\n", &UsbChildExtension->usInstanceId);
+    }
+    else
+    {
+       //
+       // the device did not provide a serial number, lets create a pseudo instance id
+       //
+       Index = swprintf(Buffer, L"0&%04d", UsbChildExtension->PortNumber) + 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;
+           goto Cleanup;
+       }
+
+       //
+       // copy instance id
+       //
+       RtlCopyMemory(UsbChildExtension->usInstanceId.Buffer, Buffer, Index * sizeof(WCHAR));
+       UsbChildExtension->usInstanceId.Length = UsbChildExtension->usDeviceId.MaximumLength = Index * sizeof(WCHAR);
+
+       DPRINT1("usDeviceId %wZ\n", &UsbChildExtension->usInstanceId);
+    }
+
+
+    return Status;
+
+Cleanup:
+    //
+    // Free Memory
+    //
+    if (UsbChildExtension->usCompatibleIds.Buffer)
+        ExFreePool(UsbChildExtension->usCompatibleIds.Buffer);
+    if (UsbChildExtension->usDeviceId.Buffer)
+        ExFreePool(UsbChildExtension->usDeviceId.Buffer);
+    if (UsbChildExtension->usHardwareIds.Buffer)
+        ExFreePool(UsbChildExtension->usHardwareIds.Buffer);
+    if (UsbChildExtension->usTextDescription.Buffer)
+        ExFreePool(UsbChildExtension->usTextDescription.Buffer);
+    if (UsbChildExtension->usInstanceId.Buffer)
+        ExFreePool(UsbChildExtension->usInstanceId.Buffer);
+
+    return Status;
+}
+
+NTSTATUS
+DestroyUsbChildDeviceObject(
+    IN PDEVICE_OBJECT UsbHubDeviceObject,
+    IN LONG PortId)
+{
+    PHUB_DEVICE_EXTENSION HubDeviceExtension = (PHUB_DEVICE_EXTENSION)UsbHubDeviceObject->DeviceExtension;
+    PHUB_CHILDDEVICE_EXTENSION UsbChildExtension = NULL;
+    PDEVICE_OBJECT ChildDeviceObject = NULL;
+    ULONG Index = 0;
+
+    DPRINT1("Removing device on port %d (Child index: %d)\n", PortId, Index);
+
+    for (Index = 0; Index < USB_MAXCHILDREN; Index++)
+    {
+        if (HubDeviceExtension->ChildDeviceObject[Index])
+        {
+            UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)HubDeviceExtension->ChildDeviceObject[Index]->DeviceExtension;
+
+            /* Check if it matches the port ID */
+            if (UsbChildExtension->PortNumber == PortId)
+            {
+                /* We found it */
+                ChildDeviceObject = HubDeviceExtension->ChildDeviceObject[Index];
+                break;
+            }
+        }
+    }
+
+    /* Fail the request if the device doesn't exist */
+    if (!ChildDeviceObject)
+    {
+        DPRINT1("Removal request for non-existant device!\n");
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    /* Remove the device from the table */
+    HubDeviceExtension->ChildDeviceObject[Index] = NULL;
+
+    /* Invalidate device relations for the root hub */
+    IoInvalidateDeviceRelations(HubDeviceExtension->RootHubPhysicalDeviceObject, BusRelations);
+
+    /* The rest of the removal process takes place in IRP_MN_REMOVE_DEVICE handling for the PDO */
+    return STATUS_SUCCESS;
+}
+
 NTSTATUS
 CreateUsbChildDeviceObject(
     IN PDEVICE_OBJECT UsbHubDeviceObject,
@@ -782,6 +1068,7 @@ CreateUsbChildDeviceObject(
     UNICODE_STRING DeviceName;
     ULONG ConfigDescSize, DeviceDescSize;
     PVOID HubInterfaceBusContext;
+    USB_CONFIGURATION_DESCRIPTOR ConfigDesc;
 
     HubDeviceExtension = (PHUB_DEVICE_EXTENSION) UsbHubDeviceObject->DeviceExtension;
     HubInterface = &HubDeviceExtension->HubInterface;
@@ -823,7 +1110,6 @@ CreateUsbChildDeviceObject(
         //
         // Create a DeviceObject
         //
-
         Status = IoCreateDevice(UsbHubDeviceObject->DriverObject,
                                 sizeof(HUB_CHILDDEVICE_EXTENSION),
                                 NULL,
@@ -865,6 +1151,7 @@ CreateUsbChildDeviceObject(
     UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)NewChildDeviceObject->DeviceExtension;
     RtlZeroMemory(UsbChildExtension, sizeof(HUB_CHILDDEVICE_EXTENSION));
     UsbChildExtension->ParentDeviceObject = UsbHubDeviceObject;
+    UsbChildExtension->PortNumber = PortId;
 
     //
     // Create the UsbDeviceObject
@@ -902,7 +1189,7 @@ CreateUsbChildDeviceObject(
                                              UsbChildExtension->UsbDeviceHandle,
                                              (PUCHAR)&UsbChildExtension->DeviceDesc,
                                              &DeviceDescSize,
-                                             (PUCHAR)&UsbChildExtension->ConfigDesc,
+                                             (PUCHAR)&ConfigDesc,
                                              &ConfigDescSize);
     if (!NT_SUCCESS(Status))
     {
@@ -911,47 +1198,53 @@ CreateUsbChildDeviceObject(
     }
 
     DumpDeviceDescriptor(&UsbChildExtension->DeviceDesc);
+    DumpConfigurationDescriptor(&ConfigDesc);
 
     //
-    // Allocate memory for DeviceId
+    // FIXME: Support more than one configuration and one interface?
     //
-    UsbChildExtension->DeviceId = ExAllocatePoolWithTag(NonPagedPool, 32 * sizeof(WCHAR), USB_HUB_TAG);
+    if (UsbChildExtension->DeviceDesc.bNumConfigurations > 1)
+    {
+        DPRINT1("Warning: Device has more than one configuration. Only one configuration (the first) is supported!\n");
+    }
 
-    //
-    // Construct DeviceId from vendor and product values
-    //
-    swprintf(UsbChildExtension->DeviceId, L"USB\\Vid_%04x&Pid_%04x", UsbChildExtension->DeviceDesc.idVendor, UsbChildExtension->DeviceDesc.idProduct);
+    if (ConfigDesc.bNumInterfaces > 1)
+    {
+        DPRINT1("Warning: Device has more that one interface. Only one interface (the first) is currently supported\n");
+    }
 
-    DPRINT1("Usb Device Id %S\n", UsbChildExtension->DeviceId);
+    ConfigDescSize = ConfigDesc.wTotalLength;
 
     //
-    // FIXME: Handle Lang ids, will use default for now
+    // Allocate memory for the first full descriptor, including interfaces and endpoints.
     //
+    UsbChildExtension->FullConfigDesc = ExAllocatePoolWithTag(PagedPool, ConfigDescSize, USB_HUB_TAG);
 
     //
-    // Get the product string
+    // Retrieve the full configuration descriptor
     //
-    Status = GetUsbStringDescriptor(NewChildDeviceObject,
-                                    UsbChildExtension->DeviceDesc.iProduct,
+    Status = GetUsbDeviceDescriptor(NewChildDeviceObject,
+                                    USB_CONFIGURATION_DESCRIPTOR_TYPE,
+                                    0,
                                     0,
-                                    (PVOID*)&UsbChildExtension->TextDescription);
+                                    UsbChildExtension->FullConfigDesc,
+                                    ConfigDescSize);
+
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
+        DPRINT1("USBHUB: GetUsbDeviceDescriptor failed with status %x\n", Status);
         goto Cleanup;
     }
 
-    DPRINT1("Usb TextDescription %S\n", UsbChildExtension->TextDescription);
-
-    Status = GetUsbStringDescriptor(NewChildDeviceObject,
-                                    UsbChildExtension->DeviceDesc.iSerialNumber,
-                                    0,
-                                    (PVOID*)&UsbChildExtension->InstanceId);
+    DumpFullConfigurationDescriptor(UsbChildExtension->FullConfigDesc);
 
-    DPRINT1("Usb InstanceId %S\n", UsbChildExtension->InstanceId);
+    //
+    // Construct all the strings that will described the device to PNP
+    //
+    Status = CreateDeviceIds(NewChildDeviceObject);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("USBHUB: GetUsbStringDescriptor failed with status %x\n", Status);
+        DPRINT1("Failed to create strings needed to describe device to PNP.\n");
         goto Cleanup;
     }
 
@@ -962,6 +1255,21 @@ CreateUsbChildDeviceObject(
 
 Cleanup:
 
+    //
+    // Remove the usb device if it was created
+    //
+    if (UsbChildExtension->UsbDeviceHandle)
+        HubInterface->RemoveUsbDevice(HubInterfaceBusContext, UsbChildExtension->UsbDeviceHandle, 0);
+
+    //
+    // Free full configuration descriptor if one was allocated
+    //
+    if (UsbChildExtension->FullConfigDesc)
+        ExFreePool(UsbChildExtension->FullConfigDesc);
+
+    //
+    // Delete the device object
+    //
     IoDeleteDevice(NewChildDeviceObject);
     return Status;
 }
@@ -1027,6 +1335,7 @@ USBHUB_FdoQueryBusRelations(
 }
 
 VOID
+NTAPI
 RootHubInitCallbackFunction(
     PVOID Context)
 {
@@ -1328,11 +1637,28 @@ USBHUB_FdoHandlePnp(
             DPRINT1("Configuration Handle %x\n", HubDeviceExtension->ConfigurationHandle);
 
             //
-            // Initialize the Hub
+            // check if function is available
             //
-            Status = HubDeviceExtension->HubInterface.Initialize20Hub(HubInterfaceBusContext,
-                                                                      HubDeviceExtension->RootHubHandle, 1);
-            DPRINT1("Status %x\n", Status);
+            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);
+                    DPRINT1("Status %x\n", Status);
+
+                    //
+                    // FIXME handle error
+                    //
+                    ASSERT(Status == STATUS_SUCCESS);
+                }
+            }
 
             ExFreePool(ConfigUrb);
 
@@ -1352,16 +1678,21 @@ USBHUB_FdoHandlePnp(
                 if (!NT_SUCCESS(Status))
                     DPRINT1("Failed to power on port %d\n", PortId);
             }
-            
+
             DPRINT1("RootHubInitNotification %x\n", HubDeviceExtension->HubInterface.RootHubInitNotification);
+
             //
-            //
+            // init roo hub notification
             //
             if (HubDeviceExtension->HubInterface.RootHubInitNotification)
             {
                 Status = HubDeviceExtension->HubInterface.RootHubInitNotification(HubInterfaceBusContext,
                                                                                   DeviceObject,
-                                                                                  (PRH_INIT_CALLBACK)RootHubInitCallbackFunction);
+                                                                                  RootHubInitCallbackFunction);
+                if (!NT_SUCCESS(Status))
+                {
+                    DPRINT1("Failed to set callback\n");
+                }
             }
             else
             {
@@ -1371,11 +1702,6 @@ USBHUB_FdoHandlePnp(
                 QueryStatusChangeEndpoint(DeviceObject);
             }
 
-            if (!NT_SUCCESS(Status))
-            {
-                DPRINT1("Failed to set callback\n");
-            }
-
             ExFreePool(Urb);
             break;
         }