Synchronize with trunk revision 59636 (just before Alex's CreateProcess revamp).
[reactos.git] / drivers / usb / usbhub / pdo.c
index f217c6d..ddd50df 100644 (file)
-/*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         USB hub driver
- * FILE:            drivers/usb/cromwell/hub/pdo.c
- * PURPOSE:         IRP_MJ_PNP operations for PDOs
- *
- * PROGRAMMERS:     Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
- *                  2010 Michael Martin (michael.martin@reactos.org)
+/*
+ * PROJECT:         ReactOS Universal Serial Bus Hub Driver
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * FILE:            drivers/usb/usbhub/fdo.c
+ * PURPOSE:         Handle PDO
+ * PROGRAMMERS:
+ *                  Hervé Poussineau (hpoussin@reactos.org)
+ *                  Michael Martin (michael.martin@reactos.org)
+ *                  Johannes Anderwald (johannes.anderwald@reactos.org)
  */
 
-#define NDEBUG
-#include <stdio.h>
 #include "usbhub.h"
 
 #define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
 
 NTSTATUS
-UsbhubInternalDeviceControlPdo(
+NTAPI
+UrbCompletion(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp,
+    PVOID Context)
+{
+    PIRP OriginalIrp;
+    DPRINT("Entered Urb Completion\n");
+
+    //
+    // Get the original Irp
+    //
+    OriginalIrp = (PIRP)Context;
+
+    //
+    // Update it to match what was returned for the IRP that was passed to RootHub
+    //
+    OriginalIrp->IoStatus.Status = Irp->IoStatus.Status;
+    OriginalIrp->IoStatus.Information = Irp->IoStatus.Information;
+    DPRINT("Status %x, Information %x\n", Irp->IoStatus.Status, Irp->IoStatus.Information);
+
+    //
+    // Complete the original Irp
+    //
+    IoCompleteRequest(OriginalIrp, IO_NO_INCREMENT);
+
+    //
+    // Return this status so the IO Manager doesnt mess with the Irp
+    //
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+FowardUrbToRootHub(
+    PDEVICE_OBJECT RootHubDeviceObject,
+    IN ULONG IoControlCode,
+    PIRP Irp,
+    OUT PVOID OutParameter1,
+    OUT PVOID OutParameter2)
+{
+    PIRP ForwardIrp;
+    IO_STATUS_BLOCK IoStatus;
+    PIO_STACK_LOCATION ForwardStack, CurrentStack;
+    PURB Urb;
+
+    //
+    // Get the current stack location for the Irp
+    //
+    CurrentStack = IoGetCurrentIrpStackLocation(Irp);
+    ASSERT(CurrentStack);
+
+    //
+    // Pull the Urb from that stack, it will be reused in the Irp sent to RootHub
+    //
+    Urb = (PURB)CurrentStack->Parameters.Others.Argument1;
+    ASSERT(Urb);
+
+    //
+    // Create the Irp to forward to RootHub
+    //
+    ForwardIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_SHUTDOWN,
+                                               RootHubDeviceObject,
+                                               NULL,
+                                               0,
+                                               0,
+                                               &IoStatus);
+    if (!ForwardIrp)
+    {
+        DPRINT1("Failed to allocate IRP\n");
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // Get the new Irps next stack
+    //
+    ForwardStack = IoGetNextIrpStackLocation(ForwardIrp);
+
+    //
+    // Copy the stack for the current irp into the next stack of new irp
+    //
+    RtlCopyMemory(ForwardStack, CurrentStack, sizeof(IO_STACK_LOCATION));
+
+    IoStatus.Status = STATUS_NOT_SUPPORTED;
+    IoStatus.Information = 0;
+
+    //
+    // Mark the Irp from upper driver as pending
+    //
+    IoMarkIrpPending(Irp);
+
+    //
+    // Now set the completion routine for the new Irp.
+    //
+    IoSetCompletionRoutine(ForwardIrp,
+                           UrbCompletion,
+                           Irp,
+                           TRUE,
+                           TRUE,
+                           TRUE);
+
+    IoCallDriver(RootHubDeviceObject, ForwardIrp);
+
+    //
+    // Always return pending as the completion routine will take care of it
+    //
+    return STATUS_PENDING;
+}
+
+BOOLEAN
+IsValidPDO(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    ULONG Index;
+    PHUB_DEVICE_EXTENSION HubDeviceExtension;
+    PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension;
+
+
+    ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    ASSERT(ChildDeviceExtension->Common.IsFDO == FALSE);
+    HubDeviceExtension = (PHUB_DEVICE_EXTENSION)ChildDeviceExtension->ParentDeviceObject->DeviceExtension;
+
+    for(Index = 0; Index < USB_MAXCHILDREN; Index++)
+    {
+        if (HubDeviceExtension->ChildDeviceObject[Index] == DeviceObject)
+        {
+            /* PDO exists */
+            return TRUE;
+        }
+    }
+
+    /* invalid pdo */
+    return FALSE;
+}
+
+
+NTSTATUS
+USBHUB_PdoHandleInternalDeviceControl(
     IN PDEVICE_OBJECT DeviceObject,
     IN PIRP Irp)
 {
+    NTSTATUS Status;
     PIO_STACK_LOCATION Stack;
     ULONG_PTR Information = 0;
-    NTSTATUS Status;
+    PHUB_DEVICE_EXTENSION HubDeviceExtension;
+    PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension;
+    PDEVICE_OBJECT RootHubDeviceObject;
+    PURB Urb;
 
-    DPRINT1("Usbhub: UsbhubInternalDeviceControlPdo() called\n");
+    //DPRINT1("UsbhubInternalDeviceControlPdo(%x) called\n", DeviceObject);
 
+    //
+    // get current stack location
+    //
     Stack = IoGetCurrentIrpStackLocation(Irp);
+    ASSERT(Stack);
+
+    //
+    // Set default status
+    //
     Status = Irp->IoStatus.Status;
 
+    ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    ASSERT(ChildDeviceExtension->Common.IsFDO == FALSE);
+    HubDeviceExtension = (PHUB_DEVICE_EXTENSION)ChildDeviceExtension->ParentDeviceObject->DeviceExtension;
+    RootHubDeviceObject = HubDeviceExtension->RootHubPhysicalDeviceObject;
+
+    if(!IsValidPDO(DeviceObject))
+    {
+        DPRINT1("[USBHUB] Request for removed device object %p\n", DeviceObject);
+        Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return STATUS_DEVICE_NOT_CONNECTED;
+    }
+
     switch (Stack->Parameters.DeviceIoControl.IoControlCode)
     {
         case IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO:
         {
-            PHUB_DEVICE_EXTENSION DeviceExtension;
-
-            DPRINT1("Usbhub: IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO\n");
+            DPRINT("IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO\n");
             if (Irp->AssociatedIrp.SystemBuffer == NULL
                 || Stack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(PVOID))
             {
@@ -43,264 +202,543 @@ UsbhubInternalDeviceControlPdo(
             else
             {
                 PVOID* pHubPointer;
-                DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
 
                 pHubPointer = (PVOID*)Irp->AssociatedIrp.SystemBuffer;
-                *pHubPointer = DeviceExtension->dev;
+                // FIXME
+                *pHubPointer = NULL;
                 Information = sizeof(PVOID);
                 Status = STATUS_SUCCESS;
             }
             break;
         }
+        case IOCTL_INTERNAL_USB_SUBMIT_URB:
+        {
+            //DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_URB\n");
+
+            //
+            // Get the Urb
+            //
+            Urb = (PURB)Stack->Parameters.Others.Argument1;
+            ASSERT(Urb);
+
+            //
+            // Set the real device handle
+            //
+            //DPRINT("UsbdDeviceHandle %x, ChildDeviceHandle %x\n", Urb->UrbHeader.UsbdDeviceHandle, ChildDeviceExtension->UsbDeviceHandle);
+
+            Urb->UrbHeader.UsbdDeviceHandle = ChildDeviceExtension->UsbDeviceHandle;
+
+            //
+            // Submit to RootHub
+            //
+            switch (Urb->UrbHeader.Function)
+            {
+                //
+                // Debugging only
+                //
+                case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
+                    DPRINT1("URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n");
+                    break;
+                case URB_FUNCTION_CLASS_DEVICE:
+                    DPRINT1("URB_FUNCTION_CLASS_DEVICE\n");
+                    break;
+                case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
+                    DPRINT1("URB_FUNCTION_GET_STATUS_FROM_DEVICE\n");
+                    break;
+                case URB_FUNCTION_SELECT_CONFIGURATION:
+                    DPRINT1("URB_FUNCTION_SELECT_CONFIGURATION\n");
+                    break;
+                case URB_FUNCTION_SELECT_INTERFACE:
+                    DPRINT1("URB_FUNCTION_SELECT_INTERFACE\n");
+                    break;
+                case URB_FUNCTION_CLASS_OTHER:
+                    DPRINT1("URB_FUNCTION_CLASS_OTHER\n");
+                    break;
+                case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
+                {
+                /*
+                    DPRINT1("URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n");
+                    DPRINT1("PipeHandle %x\n", Urb->UrbBulkOrInterruptTransfer.PipeHandle);
+                    DPRINT1("TransferFlags %x\n", Urb->UrbBulkOrInterruptTransfer.TransferFlags);
+                    DPRINT1("Buffer %x\n", Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
+                    DPRINT1("BufferMDL %x\n", Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL);
+                    DPRINT1("Length %x\n", Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
+                    DPRINT1("UrbLink %x\n", Urb->UrbBulkOrInterruptTransfer.UrbLink);
+                    DPRINT1("hca %x\n", Urb->UrbBulkOrInterruptTransfer.hca);
+                    if (Urb->UrbBulkOrInterruptTransfer.TransferFlags == USBD_SHORT_TRANSFER_OK)
+                    {
+                    }
+                */
+                    break;
+
+                }
+                case URB_FUNCTION_CLASS_INTERFACE:
+                    DPRINT1("URB_FUNCTION_CLASS_INTERFACE\n");
+                    break;
+                case URB_FUNCTION_VENDOR_DEVICE:
+                    DPRINT("URB_FUNCTION_VENDOR_DEVICE\n");
+                    break;
+                default:
+                    DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_URB Function %x NOT IMPLEMENTED\n", Urb->UrbHeader.Function);
+                    break;
+            }
+            Urb->UrbHeader.UsbdDeviceHandle = ChildDeviceExtension->UsbDeviceHandle;
+            //DPRINT1("Stack->CompletionRoutine %x\n", Stack->CompletionRoutine);
+            //
+            // Send the request to RootHub
+            //
+            Status = FowardUrbToRootHub(RootHubDeviceObject, IOCTL_INTERNAL_USB_SUBMIT_URB, Irp, Urb, NULL);
+            return Status;
+            break;
+        }
+        //
+        // FIXME: Can these be sent to RootHub?
+        //
+        case IOCTL_INTERNAL_USB_RESET_PORT:
+            DPRINT1("IOCTL_INTERNAL_USB_RESET_PORT\n");
+            break;
+        case IOCTL_INTERNAL_USB_GET_PORT_STATUS:
+        {
+            PORT_STATUS_CHANGE PortStatus;
+            LONG PortId;
+            PUCHAR PortStatusBits;
+
+            PortStatusBits = (PUCHAR)Stack->Parameters.Others.Argument1;
+            //
+            // USBD_PORT_ENABLED (bit 0) or USBD_PORT_CONNECTED (bit 1)
+            //
+            DPRINT1("IOCTL_INTERNAL_USB_GET_PORT_STATUS\n");
+            DPRINT("Arg1 %x\n", *PortStatusBits);
+            *PortStatusBits = 0;
+            if (Stack->Parameters.Others.Argument1)
+            {
+                for (PortId = 1; PortId <= HubDeviceExtension->UsbExtHubInfo.NumberOfPorts; PortId++)
+                {
+                    Status = GetPortStatusAndChange(RootHubDeviceObject, PortId, &PortStatus);
+                    if (NT_SUCCESS(Status))
+                    {
+                        DPRINT("Connect %x\n", ((PortStatus.Status & USB_PORT_STATUS_CONNECT) << 1) << ((PortId - 1) * 2));
+                        DPRINT("Enable %x\n", ((PortStatus.Status & USB_PORT_STATUS_ENABLE) >> 1) << ((PortId - 1) * 2));
+                        *PortStatusBits +=
+                            (((PortStatus.Status & USB_PORT_STATUS_CONNECT) << 1) << ((PortId - 1) * 2)) +
+                            (((PortStatus.Status & USB_PORT_STATUS_ENABLE) >> 1) << ((PortId - 1) * 2));
+
+                    }
+                }
+            }
+
+            DPRINT1("Arg1 %x\n", *PortStatusBits);
+            Status = STATUS_SUCCESS;
+            break;
+        }
+        case IOCTL_INTERNAL_USB_ENABLE_PORT:
+            DPRINT1("IOCTL_INTERNAL_USB_ENABLE_PORT\n");
+            break;
+        case IOCTL_INTERNAL_USB_CYCLE_PORT:
+            DPRINT1("IOCTL_INTERNAL_USB_CYCLE_PORT\n");
+            break;
+        case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE:
+        {
+            DPRINT1("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE\n");
+            if (Stack->Parameters.Others.Argument1)
+            {
+                // store device handle
+                *(PVOID *)Stack->Parameters.Others.Argument1 = (PVOID)ChildDeviceExtension->UsbDeviceHandle;
+                Status = STATUS_SUCCESS;
+            }
+            else
+            {
+                // invalid parameter
+                Status = STATUS_INVALID_PARAMETER;
+            }
+            break;
+        }
+        case IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO:
+        {
+            if (Stack->Parameters.Others.Argument1)
+            {
+                // inform caller that it is a real usb hub
+                *(PVOID *)Stack->Parameters.Others.Argument1 = NULL;
+            }
+
+            if (Stack->Parameters.Others.Argument2)
+            {
+                // output device object
+                *(PVOID *)Stack->Parameters.Others.Argument2 = DeviceObject;
+            }
+
+            // done
+            Status = STATUS_SUCCESS;
+            break;
+        }
         default:
         {
-            DPRINT1("Usbhub: Unknown IOCTL code 0x%lx\n", Stack->Parameters.DeviceIoControl.IoControlCode);
+            DPRINT1("Unknown IOCTL code 0x%lx\n", Stack->Parameters.DeviceIoControl.IoControlCode);
             Information = Irp->IoStatus.Information;
             Status = Irp->IoStatus.Status;
         }
     }
 
-    Irp->IoStatus.Information = Information;
-    Irp->IoStatus.Status = Status;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    if (Status != STATUS_PENDING)
+    {
+        Irp->IoStatus.Information = Information;
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    }
     return Status;
 }
 
-static NTSTATUS
-UsbhubPdoStartDevice(
+NTSTATUS
+USBHUB_PdoStartDevice(
     IN PDEVICE_OBJECT DeviceObject,
     IN PIRP Irp)
 {
-    PHUB_DEVICE_EXTENSION DeviceExtension;
-    NTSTATUS Status = STATUS_UNSUCCESSFUL;
-
-    DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-
-    /* Register and activate device interface */
-/*
-    Status = IoRegisterDeviceInterface(
-        DeviceObject,
-        DeviceExtension->dev->descriptor.bDeviceClass == USB_CLASS_HUB ?
-            &GUID_DEVINTERFACE_USB_HUB :
-            &GUID_DEVINTERFACE_USB_DEVICE,
-        NULL,
-        &DeviceExtension->SymbolicLinkName);
-*/
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("Usbhub: IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status);
-        return Status;
-    }
+    PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension;
+    //NTSTATUS Status;
+    DPRINT("USBHUB_PdoStartDevice %x\n", DeviceObject);
+    ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)DeviceObject->DeviceExtension;
 
-    //Status = IoSetDeviceInterfaceState(&DeviceExtension->SymbolicLinkName, TRUE);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("Usbhub: IoSetDeviceInterfaceState() failed with status 0x%08lx\n", Status);
-        return Status;
-    }
+    //
+    // This should be a PDO
+    //
+    ASSERT(ChildDeviceExtension->Common.IsFDO == FALSE);
 
+    //
+    // FIXME: Fow now assume success
+    //
+
+    UNIMPLEMENTED
     return STATUS_SUCCESS;
 }
 
-static NTSTATUS
-UsbhubPdoQueryId(
+NTSTATUS
+USBHUB_PdoQueryId(
     IN PDEVICE_OBJECT DeviceObject,
     IN PIRP Irp,
     OUT ULONG_PTR* Information)
 {
-    PHUB_CHILDDEVICE_EXTENSION DeviceExtension;
+    PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension;
     ULONG IdType;
-    PWCHAR SourceString = NULL;
+    PUNICODE_STRING SourceString = NULL;
+    PWCHAR ReturnString = NULL;
     NTSTATUS Status = STATUS_SUCCESS;
 
     IdType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryId.IdType;
-    DeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)DeviceObject->DeviceExtension;
 
     switch (IdType)
     {
-    case BusQueryDeviceID:
+        case BusQueryDeviceID:
         {
-            DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
-            SourceString = DeviceExtension->DeviceId;
+            DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
+            SourceString = &ChildDeviceExtension->usDeviceId;
             break;
         }
-        /* FIXME: Implement */
         case BusQueryHardwareIDs:
         {
-            DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs\n");
-            SourceString = DeviceExtension->HardwareIds;
-            Status = STATUS_NOT_SUPPORTED;
+            DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs\n");
+            SourceString = &ChildDeviceExtension->usHardwareIds;
             break;
         }
-        /* FIXME: Implement */
         case BusQueryCompatibleIDs:
         {
-            DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryCompatibleIDs\n");
-            SourceString = DeviceExtension->CompatibleIds;
-            Status = STATUS_NOT_SUPPORTED;
+            DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryCompatibleIDs\n");
+            SourceString = &ChildDeviceExtension->usCompatibleIds;
             break;
         }
         case BusQueryInstanceID:
         {
-            DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
-            SourceString = DeviceExtension->InstanceId;
+            DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
+            SourceString = &ChildDeviceExtension->usInstanceId;
             break;
         }
         default:
-            DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
+            DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
             return STATUS_NOT_SUPPORTED;
     }
 
-    *Information = (ULONG_PTR)SourceString;
+    if (SourceString)
+    {
+        //
+        // allocate buffer
+        //
+        ReturnString = ExAllocatePool(PagedPool, SourceString->MaximumLength);
+        if (!ReturnString)
+        {
+            //
+            // no memory
+            //
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        //
+        // copy buffer
+        //
+        RtlCopyMemory(ReturnString, SourceString->Buffer, SourceString->MaximumLength);
+    }
+
+    *Information = (ULONG_PTR)ReturnString;
+
     return Status;
 }
 
-static NTSTATUS
-UsbhubPdoQueryDeviceText(
+NTSTATUS
+USBHUB_PdoQueryDeviceText(
     IN PDEVICE_OBJECT DeviceObject,
     IN PIRP Irp,
     OUT ULONG_PTR* Information)
 {
-    PHUB_CHILDDEVICE_EXTENSION DeviceExtension;
+    PHUB_CHILDDEVICE_EXTENSION ChildDeviceExtension;
     DEVICE_TEXT_TYPE DeviceTextType;
-    LCID LocaleId;
+    PUNICODE_STRING SourceString = NULL;
+    PWCHAR ReturnString = NULL;
+    NTSTATUS Status = STATUS_SUCCESS;
 
     DeviceTextType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryDeviceText.DeviceTextType;
-    LocaleId = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryDeviceText.LocaleId;
-    DeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    ChildDeviceExtension = (PHUB_CHILDDEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // FIXME: LocaleId
+    //
 
     switch (DeviceTextType)
     {
         case DeviceTextDescription:
         case DeviceTextLocationInformation:
         {
-            if (DeviceTextType == DeviceTextDescription)
+            DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
+
+            //
+            // does the device provide a text description
+            //
+            if (ChildDeviceExtension->usTextDescription.Buffer && ChildDeviceExtension->usTextDescription.Length)
             {
-                *Information = (ULONG_PTR)DeviceExtension->TextDescription;
-                DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
+                //
+                // use device text
+                //
+                SourceString = &ChildDeviceExtension->usTextDescription;
             }
-            else
-                DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextLocationInformation\n");
-
-/*            if (!DeviceExtension->dev->descriptor.iProduct)
-                return STATUS_NOT_SUPPORTED;*/
-
-            return STATUS_SUCCESS;
+            break;
         }
         default:
-            DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown device text type 0x%lx\n", DeviceTextType);
-            return STATUS_NOT_SUPPORTED;
+        {
+            DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown device text type 0x%lx\n", DeviceTextType);
+            Status = STATUS_NOT_SUPPORTED;
+            break;
+        }
+    }
+
+    if (SourceString)
+    {
+        ReturnString = ExAllocatePool(PagedPool, SourceString->MaximumLength);
+        RtlCopyMemory(ReturnString, SourceString->Buffer, SourceString->MaximumLength);
+        DPRINT1("%S\n", ReturnString);
+        *Information = (ULONG_PTR)ReturnString;
     }
+
+    return Status;
 }
 
-NTSTATUS NTAPI
-UsbhubPnpPdo(
+NTSTATUS
+USBHUB_PdoHandlePnp(
     IN PDEVICE_OBJECT DeviceObject,
     IN PIRP Irp)
 {
+    NTSTATUS Status;
     ULONG MinorFunction;
     PIO_STACK_LOCATION Stack;
     ULONG_PTR Information = 0;
-    NTSTATUS Status;
+    PHUB_CHILDDEVICE_EXTENSION UsbChildExtension;
+    ULONG Index;
+    ULONG bFound;
+    PDEVICE_RELATIONS DeviceRelation;
+    PDEVICE_OBJECT ParentDevice;
 
+    UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)DeviceObject->DeviceExtension;
     Stack = IoGetCurrentIrpStackLocation(Irp);
     MinorFunction = Stack->MinorFunction;
 
     switch (MinorFunction)
     {
-        case IRP_MN_START_DEVICE: /* 0x0 */
+        case IRP_MN_START_DEVICE:
         {
-            DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
-            Status = UsbhubPdoStartDevice(DeviceObject, Irp);
+            DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
+            Status = USBHUB_PdoStartDevice(DeviceObject, Irp);
             break;
         }
-        case IRP_MN_QUERY_CAPABILITIES: /* 0x09 */
+        case IRP_MN_QUERY_CAPABILITIES:
         {
             PDEVICE_CAPABILITIES DeviceCapabilities;
             ULONG i;
-            DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
+            DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
 
             DeviceCapabilities = (PDEVICE_CAPABILITIES)Stack->Parameters.DeviceCapabilities.Capabilities;
-            /* FIXME: capabilities can change with connected device */
-            DeviceCapabilities->LockSupported = TRUE;
+            // FIXME: capabilities can change with connected device
+            DeviceCapabilities->LockSupported = FALSE;
             DeviceCapabilities->EjectSupported = FALSE;
-            DeviceCapabilities->Removable = FALSE;
+            DeviceCapabilities->Removable = TRUE;
             DeviceCapabilities->DockDevice = FALSE;
             DeviceCapabilities->UniqueID = FALSE;
-            DeviceCapabilities->SilentInstall = TRUE;
+            DeviceCapabilities->SilentInstall = FALSE;
             DeviceCapabilities->RawDeviceOK = FALSE;
             DeviceCapabilities->SurpriseRemovalOK = FALSE;
-            DeviceCapabilities->HardwareDisabled = FALSE; /* FIXME */
-            //DeviceCapabilities->NoDisplayInUI = FALSE; /* FIXME */
-            DeviceCapabilities->DeviceState[0] = PowerDeviceD0; /* FIXME */
-            for (i = 0; i < PowerSystemMaximum; i++)
-                DeviceCapabilities->DeviceState[i] = PowerDeviceD3; /* FIXME */
-            //DeviceCapabilities->DeviceWake = PowerDeviceUndefined; /* FIXME */
-            DeviceCapabilities->D1Latency = 0; /* FIXME */
-            DeviceCapabilities->D2Latency = 0; /* FIXME */
-            DeviceCapabilities->D3Latency = 0; /* FIXME */
+            DeviceCapabilities->HardwareDisabled = FALSE;
+            //DeviceCapabilities->NoDisplayInUI = FALSE;
+            DeviceCapabilities->Address = UsbChildExtension->PortNumber;
+            DeviceCapabilities->UINumber = 0;
+            DeviceCapabilities->DeviceState[0] = PowerDeviceD0;
+            for (i = 1; i < PowerSystemMaximum; i++)
+                DeviceCapabilities->DeviceState[i] = PowerDeviceD3;
+            //DeviceCapabilities->DeviceWake = PowerDeviceUndefined;
+            DeviceCapabilities->D1Latency = 0;
+            DeviceCapabilities->D2Latency = 0;
+            DeviceCapabilities->D3Latency = 0;
+            Status = STATUS_SUCCESS;
+            break;
+        }
+        case IRP_MN_QUERY_RESOURCES:
+        {
+            DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
+
+            Information = Irp->IoStatus.Information;
+            Status = Irp->IoStatus.Status;
+            break;
+        }
+        case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
+        {
+            DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
+
+            Information = Irp->IoStatus.Information;
+            Status = Irp->IoStatus.Status;
+            break;
+        }
+        case IRP_MN_QUERY_DEVICE_TEXT:
+        {
+            Status = USBHUB_PdoQueryDeviceText(DeviceObject, Irp, &Information);
+            break;
+        }
+        case IRP_MN_QUERY_ID:
+        {
+            Status = USBHUB_PdoQueryId(DeviceObject, Irp, &Information);
+            break;
+        }
+        case IRP_MN_QUERY_BUS_INFORMATION:
+        {
+            PPNP_BUS_INFORMATION BusInfo;
+            BusInfo = (PPNP_BUS_INFORMATION)ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION));
+            RtlCopyMemory(&BusInfo->BusTypeGuid,
+                          &GUID_BUS_TYPE_USB,
+                          sizeof(BusInfo->BusTypeGuid));
+            BusInfo->LegacyBusType = PNPBus;
+            // FIXME
+            BusInfo->BusNumber = 0;
+            Information = (ULONG_PTR)BusInfo;
             Status = STATUS_SUCCESS;
             break;
         }
-        case IRP_MN_QUERY_RESOURCES: /* 0x0a */
+        case IRP_MN_REMOVE_DEVICE:
         {
-            PCM_RESOURCE_LIST ResourceList;
+            PHUB_DEVICE_EXTENSION HubDeviceExtension = (PHUB_DEVICE_EXTENSION)UsbChildExtension->ParentDeviceObject->DeviceExtension;
+            PUSB_BUS_INTERFACE_HUB_V5 HubInterface = &HubDeviceExtension->HubInterface;
+            ParentDevice = UsbChildExtension->ParentDeviceObject;
+
+            DPRINT("IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
 
-            DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
-            ResourceList = ExAllocatePool(PagedPool, sizeof(CM_RESOURCE_LIST));
-            if (!ResourceList)
+            /* remove us from pdo list */
+            bFound = FALSE;
+            for(Index = 0; Index < USB_MAXCHILDREN; Index++)
             {
-                DPRINT1("Usbhub: ExAllocatePool() failed\n");
-                Status = STATUS_INSUFFICIENT_RESOURCES;
+                if (HubDeviceExtension->ChildDeviceObject[Index] == DeviceObject)
+                {
+                     /* Remove the device */
+                     Status = HubInterface->RemoveUsbDevice(HubDeviceExtension->UsbDInterface.BusContext, UsbChildExtension->UsbDeviceHandle, 0);
+
+                     /* FIXME handle error */
+                     ASSERT(Status == STATUS_SUCCESS);
+
+                    /* remove us */
+                    HubDeviceExtension->ChildDeviceObject[Index] = NULL;
+                    bFound = TRUE;
+                    break;
+                }
             }
-            else
+
+            /* Complete the IRP */
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+            /* delete device */
+            IoDeleteDevice(DeviceObject);
+
+            if (bFound)
             {
-                ResourceList->Count = 0;
-                Information = (ULONG_PTR)ResourceList;
-                Status = STATUS_SUCCESS;
+                /* invalidate device relations */
+                IoInvalidateDeviceRelations(ParentDevice, BusRelations);
             }
-            break;
+
+            return STATUS_SUCCESS;
         }
-        case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0x0b */
+        case IRP_MN_QUERY_DEVICE_RELATIONS:
         {
-            PIO_RESOURCE_REQUIREMENTS_LIST ResourceList;
-
-            DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
-            ResourceList = ExAllocatePool(PagedPool, sizeof(IO_RESOURCE_REQUIREMENTS_LIST));
-            if (!ResourceList)
+            /* only target relations are supported */
+            if (Stack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
             {
-                DPRINT1("Usbhub: ExAllocatePool() failed\n");
-                Status = STATUS_INSUFFICIENT_RESOURCES;
+                /* not supported */
+                Status = Irp->IoStatus.Status;
+                break;
             }
-            else
+
+            /* allocate device relations */
+            DeviceRelation = (PDEVICE_RELATIONS)ExAllocatePool(NonPagedPool, sizeof(DEVICE_RELATIONS));
+            if (!DeviceRelation)
             {
-                RtlZeroMemory(ResourceList, sizeof(IO_RESOURCE_REQUIREMENTS_LIST));
-                ResourceList->ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
-                ResourceList->AlternativeLists = 1;
-                ResourceList->List->Version = 1;
-                ResourceList->List->Revision = 1;
-                ResourceList->List->Count = 0;
-                Information = (ULONG_PTR)ResourceList;
-                Status = STATUS_SUCCESS;
+                /* no memory */
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
             }
+
+            /* init device relation */
+            DeviceRelation->Count = 1;
+            DeviceRelation->Objects[0] = DeviceObject;
+            ObReferenceObject(DeviceRelation->Objects[0]);
+
+            /* store result */
+            Irp->IoStatus.Information = (ULONG_PTR)DeviceRelation;
+            Status = STATUS_SUCCESS;
             break;
         }
-        case IRP_MN_QUERY_DEVICE_TEXT: /* 0x0c */
+        case IRP_MN_QUERY_STOP_DEVICE:
+        case IRP_MN_QUERY_REMOVE_DEVICE:
         {
-            Status = UsbhubPdoQueryDeviceText(DeviceObject, Irp, &Information);
+            /* Sure, no problem */
+            Status = STATUS_SUCCESS;
+            Information = 0;
             break;
         }
-        case IRP_MN_QUERY_ID: /* 0x13 */
+        case IRP_MN_QUERY_INTERFACE:
         {
-            Status = UsbhubPdoQueryId(DeviceObject, Irp, &Information);
+            DPRINT1("IRP_MN_QUERY_INTERFACE\n");
+            if (IsEqualGUIDAligned(Stack->Parameters.QueryInterface.InterfaceType, &USB_BUS_INTERFACE_USBDI_GUID))
+            {
+                DPRINT1("USB_BUS_INTERFACE_USBDI_GUID\n");
+                RtlCopyMemory(Stack->Parameters.QueryInterface.Interface, &UsbChildExtension->DeviceInterface, Stack->Parameters.QueryInterface.Size);
+                Status = STATUS_SUCCESS;
+                break;
+            }
+
+            // pass irp down
+            IoSkipCurrentIrpStackLocation(Irp);
+            return IoCallDriver(UsbChildExtension->ParentDeviceObject, Irp);
+        }
+        case IRP_MN_SURPRISE_REMOVAL:
+        {
+            DPRINT("[USBHUB] HandlePnp IRP_MN_SURPRISE_REMOVAL\n");
+            Status = STATUS_SUCCESS;
             break;
         }
         default:
         {
-            /* We can't forward request to the lower driver, because
-             * we are a Pdo, so we don't have lower driver...
-             */
-            DPRINT1("Usbhub: IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
+            DPRINT1("PDO IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
             Information = Irp->IoStatus.Information;
             Status = Irp->IoStatus.Status;
         }