[USBEHCI/USBOHCI]
[reactos.git] / drivers / usb / usbehci_new / hub_controller.cpp
index 05ca3ab..b24ab7d 100644 (file)
@@ -11,6 +11,9 @@
 #define INITGUID
 #include "usbehci.h"
 
+VOID StatusChangeEndpointCallBack(
+    PVOID Context);
+
 class CHubController : public IHubController,
                        public IDispatchIrp
 {
@@ -57,12 +60,18 @@ public:
     VOID SetNotification(PVOID CallbackContext, PRH_INIT_CALLBACK CallbackRoutine);
     // internal ioctl routines
     NTSTATUS HandleGetDescriptor(IN OUT PIRP Irp, PURB Urb);
+    NTSTATUS HandleGetDescriptorFromInterface(IN OUT PIRP Irp, PURB Urb);
     NTSTATUS HandleClassDevice(IN OUT PIRP Irp, PURB Urb);
     NTSTATUS HandleGetStatusFromDevice(IN OUT PIRP Irp, PURB Urb);
     NTSTATUS HandleSelectConfiguration(IN OUT PIRP Irp, PURB Urb);
+    NTSTATUS HandleSelectInterface(IN OUT PIRP Irp, PURB Urb);
     NTSTATUS HandleClassOther(IN OUT PIRP Irp, PURB Urb);
+    NTSTATUS HandleClassInterface(IN OUT PIRP Irp, PURB Urb);
+    NTSTATUS HandleClassEndpoint(IN OUT PIRP Irp, PURB Urb);
     NTSTATUS HandleBulkOrInterruptTransfer(IN OUT PIRP Irp, PURB Urb);
+    NTSTATUS HandleIsochronousTransfer(IN OUT PIRP Irp, PURB Urb);
 
+    friend VOID StatusChangeEndpointCallBack(PVOID Context);
 
     // constructor / destructor
     CHubController(IUnknown *OuterUnknown){}
@@ -90,6 +99,10 @@ protected:
     RTL_BITMAP m_DeviceAddressBitmap;
     PULONG m_DeviceAddressBitmapBuffer;
     LIST_ENTRY m_UsbDeviceList;
+    PIRP m_PendingSCEIrp;
+
+    //Internal Functions
+    BOOLEAN QueryStatusChageEndpoint(PIRP Irp);
 };
 
 typedef struct
@@ -119,42 +132,39 @@ const UCHAR ROOTHUB2_DEVICE_DESCRIPTOR [] =
 
 };
 
-const UCHAR ROOTHUB2_CONFIGURATION_DESCRIPTOR [] =
+const USB_CONFIGURATION_DESCRIPTOR ROOTHUB2_CONFIGURATION_DESCRIPTOR =
 {
-    /* one configuration */
-    0x09,       /* bLength; */
-    0x02,       /* bDescriptorType; Configuration */
-    0x19, 0x00, /* wTotalLength; */
-    0x01,       /* bNumInterfaces; (1) */
-    0x23,       /* bConfigurationValue; */
-    0x00,       /* iConfiguration; */
-    0x40,       /* bmAttributes; */
-    0x00        /* MaxPower; */
+    sizeof(USB_CONFIGURATION_DESCRIPTOR),
+    USB_CONFIGURATION_DESCRIPTOR_TYPE,
+    sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR),
+    1,
+    1,
+    0,
+    0x40, /* self powered */
+    0x0
 };
 
-const UCHAR ROOTHUB2_INTERFACE_DESCRIPTOR [] =
+const USB_INTERFACE_DESCRIPTOR ROOTHUB2_INTERFACE_DESCRIPTOR =
 {
-    /* one interface */
-    0x09,       /* bLength: Interface; */
-    0x04,       /* bDescriptorType; Interface */
-    0x00,       /* bInterfaceNumber; */
-    0x00,       /* bAlternateSetting; */
-    0x01,       /* bNumEndpoints; */
-    0x09,       /* bInterfaceClass; HUB_CLASSCODE */
-    0x01,       /* bInterfaceSubClass; */
-    0x00,       /* bInterfaceProtocol: */
-    0x00        /* iInterface; */
+    sizeof(USB_INTERFACE_DESCRIPTOR),                            /* bLength */
+    USB_INTERFACE_DESCRIPTOR_TYPE,                               /* bDescriptorType; Interface */
+    0,                                                           /* bInterfaceNumber; */
+    0,                                                           /* bAlternateSetting; */
+    0x1,                                                         /* bNumEndpoints; */
+    0x09,                                                        /* bInterfaceClass; HUB_CLASSCODE */
+    0x01,                                                        /* bInterfaceSubClass; */
+    0x00,                                                        /* bInterfaceProtocol: */
+    0x00,                                                        /* iInterface; */
 };
 
-const UCHAR ROOTHUB2_ENDPOINT_DESCRIPTOR [] =
+const USB_ENDPOINT_DESCRIPTOR ROOTHUB2_ENDPOINT_DESCRIPTOR =
 {
-    /* one endpoint (status change endpoint) */
-    0x07,       /* bLength; */
-    0x05,       /* bDescriptorType; Endpoint */
-    0x81,       /* bEndpointAddress; IN Endpoint 1 */
-    0x03,       /* bmAttributes; Interrupt */
-    0x08, 0x00, /* wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
-    0xFF        /* bInterval; (255ms -- usb 2.0 spec) */
+    sizeof(USB_ENDPOINT_DESCRIPTOR),                             /* bLength */
+    USB_ENDPOINT_DESCRIPTOR_TYPE,                                /* bDescriptorType */
+    0x81,                                                        /* bEndPointAddress */
+    USB_ENDPOINT_TYPE_INTERRUPT,                                 /* bmAttributes */
+    0x01,                                                        /* wMaxPacketSize */
+    0xC                                                          /* bInterval */
 };
 
 //----------------------------------------------------------------------------------------
@@ -252,15 +262,78 @@ CHubController::Initialize(
         m_DeviceDescriptor.bcdUSB = 0x200; //FIXME
     }
 
+    //
+    // Set the SCE Callback that the Hardware Device will call on port status change
+    //
+    Device->SetStatusChangeEndpointCallBack((PVOID)StatusChangeEndpointCallBack, this);
+
     //
     // clear init flag
     //
     m_HubControllerDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
 
-
     return STATUS_SUCCESS;
 }
 
+//
+// Queries the ports to see if there has been a device connected or removed.
+//
+BOOLEAN
+CHubController::QueryStatusChageEndpoint(
+    PIRP Irp)
+{
+    ULONG PortCount, PortId;
+    PIO_STACK_LOCATION IoStack;
+    USHORT PortStatus, PortChange;
+    PURB Urb;
+    PUCHAR TransferBuffer;
+    UCHAR Changed = FALSE;
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    ASSERT(IoStack);
+
+    //
+    // Get the Urb
+    //
+    Urb = (PURB)IoStack->Parameters.Others.Argument1;
+    ASSERT(Urb);
+
+    //
+    // Get the number of ports and check each one for device connected
+    //
+    m_Hardware->GetDeviceDetails(NULL, NULL, &PortCount, NULL);
+    DPRINT1("SCE Request %p TransferBufferLength %lu Flags %x MDL %p\n", Urb->UrbBulkOrInterruptTransfer.TransferBuffer, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength, Urb->UrbBulkOrInterruptTransfer.TransferFlags, Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL);
+
+    TransferBuffer = (PUCHAR)Urb->UrbBulkOrInterruptTransfer.TransferBuffer;
+
+    //
+    // Loop the ports
+    //
+    for (PortId = 0; PortId < PortCount; PortId++)
+    {
+        m_Hardware->GetPortStatus(PortId, &PortStatus, &PortChange);
+
+        DPRINT1("Port %d: Status %x, Change %x\n", PortId, PortStatus, PortChange);
+
+
+        //
+        // If theres a flag in PortChange return TRUE so the SCE Irp will be completed
+        //
+        if (PortChange != 0)
+        {
+            DPRINT1("Change state on port %d\n", PortId);
+            // Set the value for the port number
+             *TransferBuffer = 1 << ((PortId + 1) & 7);
+            Changed = TRUE;
+        }
+    }
+
+    return Changed;
+}
+
 //-----------------------------------------------------------------------------------------
 NTSTATUS
 CHubController::GetHubControllerDeviceObject(PDEVICE_OBJECT * HubDeviceObject)
@@ -287,7 +360,7 @@ CHubController::GetHubControllerSymbolicLink(
         return STATUS_UNSUCCESSFUL;
     }
 
-    if (BufferLength < m_HubDeviceInterfaceString.Length - 8)
+    if (BufferLength < (ULONG)m_HubDeviceInterfaceString.Length - 8)
     {
         //
         // buffer too small
@@ -520,7 +593,7 @@ CHubController::HandlePnp(
             DeviceCapabilities->HardwareDisabled = FALSE;
             DeviceCapabilities->NoDisplayInUI = FALSE;
             DeviceCapabilities->DeviceState[0] = PowerDeviceD0;
-            for (Index = 0; Index < PowerSystemMaximum; Index++)
+            for (Index = 1; Index < PowerSystemMaximum; Index++)
                 DeviceCapabilities->DeviceState[Index] = PowerDeviceD3;
             DeviceCapabilities->DeviceWake = PowerDeviceUnspecified;
             DeviceCapabilities->D1Latency = 0;
@@ -686,14 +759,118 @@ CHubController::HandlePower(
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
     return STATUS_NOT_IMPLEMENTED;
 }
+
+//-----------------------------------------------------------------------------------------
+NTSTATUS
+CHubController::HandleIsochronousTransfer(
+    IN OUT PIRP Irp, 
+    PURB Urb)
+{
+    PUSBDEVICE UsbDevice;
+    PUSB_ENDPOINT_DESCRIPTOR EndPointDesc = NULL;
+
+    //
+    // Check PipeHandle to determine if this is a Bulk or Interrupt Transfer Request
+    //
+    EndPointDesc = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbIsochronousTransfer.PipeHandle;
+
+    if (!EndPointDesc)
+    {
+        DPRINT1("No EndpointDesc\n");
+        Urb->UrbIsochronousTransfer.Hdr.Status = USBD_STATUS_INVALID_PIPE_HANDLE;
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    //
+    // sanity checks
+    //
+    ASSERT(EndPointDesc);
+    ASSERT((EndPointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_ISOCHRONOUS);
+
+    //
+    // check if this is a valid usb device handle
+    //
+    if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+    {
+        DPRINT1("HandleIsochronousTransfer invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+        //
+        // invalid device handle
+        //
+        return STATUS_DEVICE_NOT_CONNECTED;
+    }
+
+    //
+    // get device
+    //
+    UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+    return UsbDevice->SubmitIrp(Irp);
+}
+
 //-----------------------------------------------------------------------------------------
 NTSTATUS
 CHubController::HandleBulkOrInterruptTransfer(
     IN OUT PIRP Irp, 
     PURB Urb)
 {
-    UNIMPLEMENTED
-    return STATUS_NOT_IMPLEMENTED;
+    PUSBDEVICE UsbDevice;
+    PUSB_ENDPOINT_DESCRIPTOR EndPointDesc = NULL;
+    //
+    // First check if the request is for the Status Change Endpoint
+    //
+
+    //
+    // Is the Request for the root hub
+    //
+    if (Urb->UrbHeader.UsbdDeviceHandle == 0)
+    {
+        ASSERT(m_PendingSCEIrp == NULL);
+        if (QueryStatusChageEndpoint(Irp))
+        {
+            StatusChangeEndpointCallBack(this);
+            return STATUS_SUCCESS;
+        }
+
+        //
+        // Else pend the IRP, to be completed when a device connects or disconnects.
+        //
+        DPRINT1("Pending SCE Irp\n");;
+        m_PendingSCEIrp = Irp;
+        IoMarkIrpPending(Irp);
+        return STATUS_PENDING;
+    }
+
+    //
+    // Check PipeHandle to determine if this is a Bulk or Interrupt Transfer Request
+    //
+    EndPointDesc = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
+
+    //
+    // sanity checks
+    //
+    ASSERT(EndPointDesc);
+    ASSERT((EndPointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK || (EndPointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT);
+
+    //
+    // check if this is a valid usb device handle
+    //
+    if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+    {
+        DPRINT1("HandleBulkOrInterruptTransfer invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+        //
+        // invalid device handle
+        //
+        return STATUS_DEVICE_NOT_CONNECTED;
+    }
+
+    //
+    // get device
+    //
+    UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+    return UsbDevice->SubmitIrp(Irp);
 }
 
 //-----------------------------------------------------------------------------------------
@@ -708,7 +885,7 @@ CHubController::HandleClassOther(
     ULONG NumPort;
     ULONG PortId;
 
-    //DPRINT1("CHubController::HandleClassOther> Request %x Value %x not implemented\n", Urb->UrbControlVendorClassRequest.Request, Urb->UrbControlVendorClassRequest.Value);
+    DPRINT("CHubController::HandleClassOther> Request %x Value %x\n", Urb->UrbControlVendorClassRequest.Request, Urb->UrbControlVendorClassRequest.Value);
 
     //
     // get number of ports available
@@ -719,7 +896,7 @@ CHubController::HandleClassOther(
     //
     // sanity check
     //
-    PC_ASSERT(Urb->UrbControlVendorClassRequest.Index - 1 < NumPort);
+    PC_ASSERT(Urb->UrbControlVendorClassRequest.Index - 1 < (USHORT)NumPort);
 
     //
     // port range reported start from 1 -n
@@ -743,14 +920,14 @@ CHubController::HandleClassOther(
             //
             // get port status
             //
-            //Status = m_Hardware->GetPortStatus(PortId, &PortStatus, &PortChange);
+            Status = m_Hardware->GetPortStatus(PortId, &PortStatus, &PortChange);
 
-            Status = STATUS_SUCCESS;
             if (NT_SUCCESS(Status))
             {
                 //
                 // request contains buffer of 2 ushort which are used from submitting port status and port change status
                 //
+                DPRINT("PortId %x PortStatus %x PortChange %x\n", PortId, PortStatus, PortChange);
                 Buffer = (PUSHORT)Urb->UrbControlVendorClassRequest.TransferBuffer;
 
                 //
@@ -771,14 +948,13 @@ CHubController::HandleClassOther(
             switch (Urb->UrbControlVendorClassRequest.Value)
             {
                 case C_PORT_CONNECTION:
-                    //Status = m_Hardware->ClearPortStatus(PortId, C_PORT_CONNECTION);
+                    Status = m_Hardware->ClearPortStatus(PortId, C_PORT_CONNECTION);
                     break;
                 case C_PORT_RESET:
-                    //Status= m_Hardware->ClearPortStatus(PortId, C_PORT_RESET);
+                    Status= m_Hardware->ClearPortStatus(PortId, C_PORT_RESET);
                     break;
                 default:
                     DPRINT("Unknown Value for Clear Feature %x \n", Urb->UrbControlVendorClassRequest.Value);
-                    PC_ASSERT(FALSE);
                     break;
            }
 
@@ -806,7 +982,7 @@ CHubController::HandleClassOther(
                     //
                     // set suspend port feature
                     //
-                    Status = STATUS_SUCCESS; //m_Hardware->SetPortFeature(PortId, PORT_SUSPEND);
+                    Status = m_Hardware->SetPortFeature(PortId, PORT_SUSPEND);
                     break;
                 }
                 case PORT_POWER:
@@ -814,7 +990,7 @@ CHubController::HandleClassOther(
                     //
                     // set power feature on port
                     //
-                    Status = STATUS_SUCCESS; //m_Hardware->SetPortFeature(PortId, PORT_POWER);
+                    Status = m_Hardware->SetPortFeature(PortId, PORT_POWER);
                     break;
                 }
 
@@ -823,7 +999,7 @@ CHubController::HandleClassOther(
                     //
                     // reset port feature
                     //
-                    Status = m_Hardware->ResetPort(PortId);
+                    Status = m_Hardware->SetPortFeature(PortId, PORT_RESET);
                     PC_ASSERT(Status == STATUS_SUCCESS);
                     break;
                 }
@@ -838,9 +1014,7 @@ CHubController::HandleClassOther(
             PC_ASSERT(0);
             Status = STATUS_INVALID_DEVICE_REQUEST;
     }
-
-
-    return STATUS_SUCCESS;
+    return Status;
 }
 
 //-----------------------------------------------------------------------------------------
@@ -849,29 +1023,126 @@ CHubController::HandleSelectConfiguration(
     IN OUT PIRP Irp, 
     PURB Urb)
 {
-    //
-    // sanity checks
-    //
+    PUSBDEVICE UsbDevice;
+    PUSBD_INTERFACE_INFORMATION InterfaceInfo;
 
     //
-    // FIXME: support devices
+    // is the request for the Root Hub
     //
-    PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle == NULL); 
+    if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
+    {
+        //
+        // FIXME: support setting device to unconfigured state
+        //
+        PC_ASSERT(Urb->UrbSelectConfiguration.ConfigurationDescriptor);
 
-    //
-    // FIXME: support setting device to unconfigured state
-    //
-    PC_ASSERT(Urb->UrbSelectConfiguration.ConfigurationDescriptor);
+        //
+        // set device handle
+        //
+        Urb->UrbSelectConfiguration.ConfigurationHandle = (PVOID)&ROOTHUB2_CONFIGURATION_DESCRIPTOR;
+
+        //
+        // copy interface info
+        //
+        InterfaceInfo = &Urb->UrbSelectConfiguration.Interface;
+
+        InterfaceInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)&ROOTHUB2_INTERFACE_DESCRIPTOR;
+        InterfaceInfo->Class = ROOTHUB2_INTERFACE_DESCRIPTOR.bInterfaceClass;
+        InterfaceInfo->SubClass = ROOTHUB2_INTERFACE_DESCRIPTOR.bInterfaceSubClass;
+        InterfaceInfo->Protocol = ROOTHUB2_INTERFACE_DESCRIPTOR.bInterfaceProtocol;
+        InterfaceInfo->Reserved = 0;
+
+        //
+        // sanity check
+        //
+        PC_ASSERT(InterfaceInfo->NumberOfPipes == 1);
+
+        //
+        // copy pipe info
+        //
+        InterfaceInfo->Pipes[0].MaximumPacketSize = ROOTHUB2_ENDPOINT_DESCRIPTOR.wMaxPacketSize;
+        InterfaceInfo->Pipes[0].EndpointAddress = ROOTHUB2_ENDPOINT_DESCRIPTOR.bEndpointAddress;
+        InterfaceInfo->Pipes[0].Interval = ROOTHUB2_ENDPOINT_DESCRIPTOR.bInterval;
+        InterfaceInfo->Pipes[0].PipeType = (USBD_PIPE_TYPE)(ROOTHUB2_ENDPOINT_DESCRIPTOR.bmAttributes & USB_ENDPOINT_TYPE_MASK);
+        InterfaceInfo->Pipes[0].PipeHandle = (PVOID)&ROOTHUB2_ENDPOINT_DESCRIPTOR;
+
+        return STATUS_SUCCESS;
+    }
+    else
+    {
+        //
+        // check if this is a valid usb device handle
+        //
+        if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+        {
+            DPRINT1("HandleSelectConfiguration invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+            //
+            // invalid device handle
+            //
+            return STATUS_DEVICE_NOT_CONNECTED;
+        }
+
+        //
+        // get device
+        //
+        UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+        //
+        // select configuration
+        //
+        return UsbDevice->SelectConfiguration(Urb->UrbSelectConfiguration.ConfigurationDescriptor, &Urb->UrbSelectConfiguration.Interface, &Urb->UrbSelectConfiguration.ConfigurationHandle);
+    }
+}
+
+//-----------------------------------------------------------------------------------------
+NTSTATUS
+CHubController::HandleSelectInterface(
+    IN OUT PIRP Irp, 
+    PURB Urb)
+{
+    PUSBDEVICE UsbDevice;
 
     //
-    // set device handle
+    // sanity check
     //
-    Urb->UrbSelectConfiguration.ConfigurationHandle = (PVOID)ROOTHUB2_CONFIGURATION_DESCRIPTOR;
+    PC_ASSERT(Urb->UrbSelectInterface.ConfigurationHandle);
 
     //
-    // TODO: copy interface info
+    // is the request for the Root Hub
     //
-    return STATUS_SUCCESS;
+    if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
+    {
+        //
+        // no op for root hub
+        //
+        return STATUS_SUCCESS;
+    }
+    else
+    {
+        //
+        // check if this is a valid usb device handle
+        //
+        if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+        {
+            DPRINT1("HandleSelectInterface invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+            //
+            // invalid device handle
+            //
+            return STATUS_DEVICE_NOT_CONNECTED;
+        }
+
+        //
+        // get device
+        //
+        UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+        //
+        // select interface
+        //
+        return UsbDevice->SelectInterface(Urb->UrbSelectInterface.ConfigurationHandle, &Urb->UrbSelectInterface.Interface);
+    }
 }
 
 //-----------------------------------------------------------------------------------------
@@ -880,7 +1151,10 @@ CHubController::HandleGetStatusFromDevice(
     IN OUT PIRP Irp, 
     PURB Urb)
 {
-    PUSHORT Status;
+    PUSHORT DeviceStatus;
+    USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+    NTSTATUS Status;
+    PUSBDEVICE UsbDevice;
 
     //
     // sanity checks
@@ -888,22 +1162,62 @@ CHubController::HandleGetStatusFromDevice(
     PC_ASSERT(Urb->UrbControlGetStatusRequest.Index == 0);
     PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBufferLength >= sizeof(USHORT));
     PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBuffer);
-    PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle == NULL); 
 
     //
     // get status buffer
     //
-    Status = (PUSHORT)Urb->UrbControlGetStatusRequest.TransferBuffer;
+    DeviceStatus = (PUSHORT)Urb->UrbControlGetStatusRequest.TransferBuffer;
+
+
+    if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
+    {
+        //
+        // FIXME need more flags ?
+        //
+        *DeviceStatus = USB_PORT_STATUS_CONNECT;
+        return STATUS_SUCCESS;
+    }
+
+    //
+    // check if this is a valid usb device handle
+    //
+    if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+    {
+        DPRINT1("HandleGetStatusFromDevice invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+        //
+        // invalid device handle
+        //
+        return STATUS_DEVICE_NOT_CONNECTED;
+    }
 
     //
-    // FIXME need more flags ?
+    // get device
     //
-    *Status = USB_PORT_STATUS_CONNECT;
+    UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+
+     //
+     // generate setup packet
+     //
+     CtrlSetup.bRequest = USB_REQUEST_GET_STATUS;
+     CtrlSetup.wValue.LowByte = 0;
+     CtrlSetup.wValue.HiByte = 0;
+     CtrlSetup.wIndex.W = Urb->UrbControlGetStatusRequest.Index; 
+     CtrlSetup.wLength = (USHORT)Urb->UrbControlGetStatusRequest.TransferBufferLength;
+     CtrlSetup.bmRequestType.B = 0x80;
+
+    //
+    // submit setup packet
+    //
+    Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
+    ASSERT(Status == STATUS_SUCCESS);
+    DPRINT1("CHubController::HandleGetStatusFromDevice Status %x Length %lu DeviceStatus %x\n", Status, Urb->UrbControlDescriptorRequest.TransferBufferLength, *DeviceStatus);
 
     //
     // done
     //
-    return STATUS_SUCCESS;
+    return Status;
 }
 
 //-----------------------------------------------------------------------------------------
@@ -916,12 +1230,54 @@ CHubController::HandleClassDevice(
     PUSB_HUB_DESCRIPTOR UsbHubDescriptor;
     ULONG PortCount, Dummy2;
     USHORT Dummy1;
+    PUSBDEVICE UsbDevice;
+    USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+
+    DPRINT("CHubController::HandleClassDevice Request %x Class %x\n", Urb->UrbControlVendorClassRequest.Request, Urb->UrbControlVendorClassRequest.Value >> 8);
 
     //
     // check class request type
     //
     switch(Urb->UrbControlVendorClassRequest.Request)
     {
+        case USB_REQUEST_GET_STATUS:
+        {
+            //
+            // check if this is a valid usb device handle
+            //
+            if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+            {
+                DPRINT1("HandleClassDevice invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+                //
+                // invalid device handle
+                //
+                return STATUS_DEVICE_NOT_CONNECTED;
+            }
+
+            //
+            // get device
+            //
+            UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+
+            //
+            // generate setup packet
+            //
+            CtrlSetup.bRequest = USB_REQUEST_GET_STATUS;
+            CtrlSetup.wValue.LowByte = Urb->UrbControlVendorClassRequest.Index;
+            CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
+            CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
+            CtrlSetup.wLength = (USHORT)Urb->UrbControlGetStatusRequest.TransferBufferLength;
+            CtrlSetup.bmRequestType.B = 0xA0;
+
+            //
+            // submit setup packet
+            //
+            Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
+            ASSERT(Status == STATUS_SUCCESS);
+            break;
+        }
         case USB_REQUEST_GET_DESCRIPTOR:
         {
             switch (Urb->UrbControlVendorClassRequest.Value >> 8)
@@ -960,8 +1316,8 @@ CHubController::HandleClassDevice(
                     //
                     // FIXME: retrieve values
                     //
-                    UsbHubDescriptor->bNumberOfPorts = PortCount;
-                    UsbHubDescriptor->wHubCharacteristics = 0x0012;
+                    UsbHubDescriptor->bNumberOfPorts = (UCHAR)PortCount;
+                    UsbHubDescriptor->wHubCharacteristics = 0x00;
                     UsbHubDescriptor->bPowerOnToPowerGood = 0x01;
                     UsbHubDescriptor->bHubControlCurrent = 0x00;
 
@@ -970,106 +1326,284 @@ CHubController::HandleClassDevice(
                     //
                     Status = STATUS_SUCCESS;
                     break;
-               }
-               default:
-                   DPRINT1("CHubController::HandleClassDevice Class %x not implemented\n", Urb->UrbControlVendorClassRequest.Value >> 8);
-                   break;
-            }
-            break;
-        }
-        default:
-            DPRINT1("CHubController::HandleClassDevice Type %x not implemented\n", Urb->UrbControlVendorClassRequest.Request);
-    }
+               }
+               default:
+                   DPRINT1("CHubController::HandleClassDevice Class %x not implemented\n", Urb->UrbControlVendorClassRequest.Value >> 8);
+                   break;
+            }
+            break;
+        }
+        default:
+            DPRINT1("CHubController::HandleClassDevice Type %x not implemented\n", Urb->UrbControlVendorClassRequest.Request);
+    }
+
+    return Status;
+}
+
+//-----------------------------------------------------------------------------------------
+NTSTATUS
+CHubController::HandleGetDescriptorFromInterface(
+    IN OUT PIRP Irp,
+    IN OUT PURB Urb)
+{
+    PUSBDEVICE UsbDevice;
+    USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+    NTSTATUS Status;
+
+    //
+    // sanity check
+    //
+    ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength);
+    ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
+
+    //
+    // check if this is a valid usb device handle
+    //
+    if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+    {
+        DPRINT1("HandleGetDescriptorFromInterface invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+        //
+        // invalid device handle
+        //
+        return STATUS_DEVICE_NOT_CONNECTED;
+    }
+
+    //
+    // get device
+    //
+    UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+    //
+    // generate setup packet
+    //
+    CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
+    CtrlSetup.wValue.LowByte = Urb->UrbControlDescriptorRequest.Index;
+    CtrlSetup.wValue.HiByte = Urb->UrbControlDescriptorRequest.DescriptorType;
+    CtrlSetup.wIndex.W = Urb->UrbControlDescriptorRequest.LanguageId;
+    CtrlSetup.wLength = (USHORT)Urb->UrbControlDescriptorRequest.TransferBufferLength;
+    CtrlSetup.bmRequestType.B = 0x81;
+
+    //
+    // submit setup packet
+    //
+    Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
+    ASSERT(Status == STATUS_SUCCESS);
+
+    //
+    // done
+    //
+    return Status;
+}
+
+//-----------------------------------------------------------------------------------------
+NTSTATUS
+CHubController::HandleGetDescriptor(
+    IN OUT PIRP Irp,
+    IN OUT PURB Urb)
+{
+    NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
+    PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
+    USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+    PUCHAR Buffer;
+    PUSBDEVICE UsbDevice;
+    ULONG Length;
+
+    DPRINT("CHubController::HandleGetDescriptor\n");
+
+    //
+    // check descriptor type
+    //
+    switch(Urb->UrbControlDescriptorRequest.DescriptorType)
+    {
+        case USB_DEVICE_DESCRIPTOR_TYPE:
+        {
+            //
+            // sanity check
+            //
+            PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= sizeof(USB_DEVICE_DESCRIPTOR));
+            PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
+
+            if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
+            {
+                //
+                // copy root hub device descriptor
+                //
+                RtlCopyMemory((PUCHAR)Urb->UrbControlDescriptorRequest.TransferBuffer, &m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
+                Status = STATUS_SUCCESS;
+            }
+            else
+            {
+                //
+                // check if this is a valid usb device handle
+                //
+                if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+                {
+                    DPRINT1("HandleGetDescriptor invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+                    //
+                    // invalid device handle
+                    //
+                    return STATUS_DEVICE_NOT_CONNECTED;
+                }
+
+                //
+                // get device
+                //
+                UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+                //
+                // retrieve device descriptor from device
+                //
+                UsbDevice->GetDeviceDescriptor((PUSB_DEVICE_DESCRIPTOR)Urb->UrbControlDescriptorRequest.TransferBuffer);
+                Status = STATUS_SUCCESS;
+            }
+            break;
+        }
+       case USB_CONFIGURATION_DESCRIPTOR_TYPE:
+        {
+            //
+            // sanity checks
+            //
+            PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
+            PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR));
+
+            if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
+            {
+                //
+                // request is for the root bus controller
+                //
+                RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer, &ROOTHUB2_CONFIGURATION_DESCRIPTOR, sizeof(USB_CONFIGURATION_DESCRIPTOR));
+
+                //
+                // get configuration descriptor, very retarded!
+                //
+                ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)Urb->UrbControlDescriptorRequest.TransferBuffer;
+
+                //
+                // check if buffer can hold interface and endpoint descriptor
+                //
+                if (ConfigurationDescriptor->wTotalLength > Urb->UrbControlDescriptorRequest.TransferBufferLength)
+                {
+                    //
+                    // buffer too small
+                    //
+                    Status = STATUS_SUCCESS;
+                    ASSERT(FALSE);
+                    break;
+                }
+
+                //
+                // copy interface descriptor template
+                //
+                Buffer = (PUCHAR)(ConfigurationDescriptor + 1);
+                RtlCopyMemory(Buffer, &ROOTHUB2_INTERFACE_DESCRIPTOR, sizeof(USB_INTERFACE_DESCRIPTOR));
+
+                //
+                // copy end point descriptor template
+                //
+                Buffer += sizeof(USB_INTERFACE_DESCRIPTOR);
+                RtlCopyMemory(Buffer, &ROOTHUB2_ENDPOINT_DESCRIPTOR, sizeof(USB_ENDPOINT_DESCRIPTOR));
+
+                //
+                // done
+                //
+                Status = STATUS_SUCCESS;
+
+            }
+            else
+            {
+                //
+                // check if this is a valid usb device handle
+                //
+                if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+                {
+                    DPRINT1("USB_CONFIGURATION_DESCRIPTOR_TYPE invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+                    //
+                    // invalid device handle
+                    //
+                    return STATUS_DEVICE_NOT_CONNECTED;
+                }
+
+                //
+                // get device
+                //
+                UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+                if (sizeof(USB_CONFIGURATION_DESCRIPTOR) > Urb->UrbControlDescriptorRequest.TransferBufferLength)
+                {
+                    //
+                    // buffer too small
+                    //
+                    Urb->UrbControlDescriptorRequest.TransferBufferLength = UsbDevice->GetConfigurationDescriptorsLength();
+
+                    //
+                    // bail out
+                    //
+                    Status = STATUS_SUCCESS;
+                    break;
+                }
 
-    return Status;
-}
-//-----------------------------------------------------------------------------------------
-NTSTATUS
-CHubController::HandleGetDescriptor(
-    IN OUT PIRP Irp,
-    IN OUT PURB Urb)
-{
-    NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
-    PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
-    PUCHAR Buffer;
+                //
+                // perform work in IUSBDevice
+                //
+                UsbDevice->GetConfigurationDescriptors((PUSB_CONFIGURATION_DESCRIPTOR)Urb->UrbControlDescriptorRequest.TransferBuffer, Urb->UrbControlDescriptorRequest.TransferBufferLength, &Length);
 
-    //
-    // check descriptor type
-    //
-    switch(Urb->UrbControlDescriptorRequest.DescriptorType)
-    {
-        case USB_DEVICE_DESCRIPTOR_TYPE:
-        {
-            //
-            // sanity check
-            //
-            PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= sizeof(USB_DEVICE_DESCRIPTOR));
+                //
+                // sanity check
+                //
+                PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= Length);
 
-            if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
-            {
                 //
-                // copy root hub device descriptor
+                // store result size
                 //
-                RtlCopyMemory((PUCHAR)Urb->UrbControlDescriptorRequest.TransferBuffer, &m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
+                Urb->UrbControlDescriptorRequest.TransferBufferLength = Length;
                 Status = STATUS_SUCCESS;
-                break;
             }
             break;
         }
-       case USB_CONFIGURATION_DESCRIPTOR_TYPE:
+        case USB_STRING_DESCRIPTOR_TYPE:
         {
             //
-            // sanity checks
+            // sanity check
             //
             PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
-            PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR));
-
-            //
-            // FIXME: support devices
-            //
-            PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle == NULL);
+            PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength);
 
-            //
-            // copy configuration descriptor template
-            //
-            C_ASSERT(sizeof(ROOTHUB2_CONFIGURATION_DESCRIPTOR) == sizeof(USB_CONFIGURATION_DESCRIPTOR));
-            RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer, ROOTHUB2_CONFIGURATION_DESCRIPTOR, sizeof(USB_CONFIGURATION_DESCRIPTOR));
-
-            //
-            // get configuration descriptor, very retarded!
-            //
-            ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)Urb->UrbControlDescriptorRequest.TransferBuffer;
 
             //
-            // check if buffer can hold interface and endpoint descriptor
+            // check if this is a valid usb device handle
             //
-            if (ConfigurationDescriptor->wTotalLength > Urb->UrbControlDescriptorRequest.TransferBufferLength)
+            if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
             {
+                DPRINT1("USB_STRING_DESCRIPTOR_TYPE invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
                 //
-                // buffer too small
+                // invalid device handle
                 //
-                Status = STATUS_SUCCESS;
-                break;
+                return STATUS_DEVICE_NOT_CONNECTED;
             }
 
             //
-            // copy interface descriptor template
+            // get device
             //
-            Buffer = (PUCHAR)(ConfigurationDescriptor + 1);
-            C_ASSERT(sizeof(ROOTHUB2_INTERFACE_DESCRIPTOR) == sizeof(USB_INTERFACE_DESCRIPTOR));
-            RtlCopyMemory(Buffer, ROOTHUB2_INTERFACE_DESCRIPTOR, sizeof(USB_INTERFACE_DESCRIPTOR));
+            UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
 
             //
-            // copy end point descriptor template
+            // generate setup packet
             //
-            Buffer += sizeof(USB_INTERFACE_DESCRIPTOR);
-            C_ASSERT(sizeof(ROOTHUB2_ENDPOINT_DESCRIPTOR) == sizeof(USB_ENDPOINT_DESCRIPTOR));
-            RtlCopyMemory(Buffer, ROOTHUB2_ENDPOINT_DESCRIPTOR, sizeof(USB_ENDPOINT_DESCRIPTOR));
+            CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
+            CtrlSetup.wValue.LowByte = Urb->UrbControlDescriptorRequest.Index;
+            CtrlSetup.wValue.HiByte = Urb->UrbControlDescriptorRequest.DescriptorType;
+            CtrlSetup.wIndex.W = Urb->UrbControlDescriptorRequest.LanguageId;
+            CtrlSetup.wLength = (USHORT)Urb->UrbControlDescriptorRequest.TransferBufferLength;
+            CtrlSetup.bmRequestType.B = 0x80;
 
             //
-            // done
+            // submit setup packet
             //
-            Status = STATUS_SUCCESS;
+            Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
             break;
         }
         default:
@@ -1083,6 +1617,150 @@ CHubController::HandleGetDescriptor(
     return Status;
 }
 
+//-----------------------------------------------------------------------------------------
+NTSTATUS
+CHubController::HandleClassEndpoint(
+    IN OUT PIRP Irp,
+    IN OUT PURB Urb)
+{
+    USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+    NTSTATUS Status;
+    PUSBDEVICE UsbDevice;
+
+    //
+    // sanity check
+    //
+    PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer);
+    PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength);
+    PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle);
+
+    //
+    // check if this is a valid usb device handle
+    //
+    if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+    {
+        DPRINT1("HandleClassEndpoint invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+        //
+        // invalid device handle
+        //
+        return STATUS_DEVICE_NOT_CONNECTED;
+    }
+
+    //
+    // get device
+    //
+    UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+
+    DPRINT1("URB_FUNCTION_CLASS_ENDPOINT\n");
+    DPRINT1("TransferFlags %x\n", Urb->UrbControlVendorClassRequest.TransferFlags);
+    DPRINT1("TransferBufferLength %x\n", Urb->UrbControlVendorClassRequest.TransferBufferLength);
+    DPRINT1("TransferBuffer %x\n", Urb->UrbControlVendorClassRequest.TransferBuffer);
+    DPRINT1("TransferBufferMDL %x\n", Urb->UrbControlVendorClassRequest.TransferBufferMDL);
+    DPRINT1("RequestTypeReservedBits %x\n", Urb->UrbControlVendorClassRequest.RequestTypeReservedBits);
+    DPRINT1("Request %x\n", Urb->UrbControlVendorClassRequest.Request);
+    DPRINT1("Value %x\n", Urb->UrbControlVendorClassRequest.Value);
+    DPRINT1("Index %x\n", Urb->UrbControlVendorClassRequest.Index);
+
+    //
+    // initialize setup packet
+    //
+    CtrlSetup.bmRequestType.B = 0xa2; //FIXME: Const.
+    CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request;
+    CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
+    CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
+    CtrlSetup.wLength = Urb->UrbControlVendorClassRequest.TransferBufferLength;
+
+    //
+    // issue request
+    //
+    Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlVendorClassRequest.TransferBufferLength, Urb->UrbControlVendorClassRequest.TransferBuffer);
+
+    //
+    // assert on failure
+    //
+    PC_ASSERT(NT_SUCCESS(Status));
+
+
+    //
+    // done
+    //
+    return Status;
+}
+
+//-----------------------------------------------------------------------------------------
+NTSTATUS
+CHubController::HandleClassInterface(
+    IN OUT PIRP Irp,
+    IN OUT PURB Urb)
+{
+    USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+    NTSTATUS Status;
+    PUSBDEVICE UsbDevice;
+
+    //
+    // sanity check
+    //
+    //ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer || Urb->UrbControlVendorClassRequest.TransferBufferMDL);
+    //ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength);
+    PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle);
+
+    //
+    // check if this is a valid usb device handle
+    //
+    if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+    {
+        DPRINT1("HandleClassInterface invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+        //
+        // invalid device handle
+        //
+        return STATUS_DEVICE_NOT_CONNECTED;
+    }
+
+    //
+    // get device
+    //
+    UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+
+    DPRINT1("URB_FUNCTION_CLASS_INTERFACE\n");
+    DPRINT1("TransferFlags %x\n", Urb->UrbControlVendorClassRequest.TransferFlags);
+    DPRINT1("TransferBufferLength %x\n", Urb->UrbControlVendorClassRequest.TransferBufferLength);
+    DPRINT1("TransferBuffer %x\n", Urb->UrbControlVendorClassRequest.TransferBuffer);
+    DPRINT1("TransferBufferMDL %x\n", Urb->UrbControlVendorClassRequest.TransferBufferMDL);
+    DPRINT1("RequestTypeReservedBits %x\n", Urb->UrbControlVendorClassRequest.RequestTypeReservedBits);
+    DPRINT1("Request %x\n", Urb->UrbControlVendorClassRequest.Request);
+    DPRINT1("Value %x\n", Urb->UrbControlVendorClassRequest.Value);
+    DPRINT1("Index %x\n", Urb->UrbControlVendorClassRequest.Index);
+
+    //
+    // initialize setup packet
+    //
+    CtrlSetup.bmRequestType.B = 0xa1; //FIXME: Const.
+    CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request;
+    CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
+    CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
+    CtrlSetup.wLength = Urb->UrbControlVendorClassRequest.TransferBufferLength;
+
+    //
+    // issue request
+    //
+    Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlVendorClassRequest.TransferBufferLength, Urb->UrbControlVendorClassRequest.TransferBuffer);
+
+    //
+    // assert on failure
+    //
+    PC_ASSERT(NT_SUCCESS(Status));
+
+
+    //
+    // done
+    //
+    return Status;
+}
+
 //-----------------------------------------------------------------------------------------
 NTSTATUS
 CHubController::HandleDeviceControl(
@@ -1119,6 +1797,9 @@ CHubController::HandleDeviceControl(
 
             switch (Urb->UrbHeader.Function)
             {
+                case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE:
+                    Status = HandleGetDescriptorFromInterface(Irp, Urb);
+                    break;
                 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
                     Status = HandleGetDescriptor(Irp, Urb);
                     break;
@@ -1131,12 +1812,24 @@ CHubController::HandleDeviceControl(
                 case URB_FUNCTION_SELECT_CONFIGURATION:
                     Status = HandleSelectConfiguration(Irp, Urb);
                     break;
+                case URB_FUNCTION_SELECT_INTERFACE:
+                    Status = HandleSelectInterface(Irp, Urb);
+                    break;
                 case URB_FUNCTION_CLASS_OTHER:
                     Status = HandleClassOther(Irp, Urb);
                     break;
                 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
                     Status = HandleBulkOrInterruptTransfer(Irp, Urb);
                     break;
+                case URB_FUNCTION_ISOCH_TRANSFER:
+                    Status = HandleIsochronousTransfer(Irp, Urb);
+                    break;
+                case URB_FUNCTION_CLASS_INTERFACE:
+                    Status = HandleClassInterface(Irp, Urb);
+                    break;
+                case URB_FUNCTION_CLASS_ENDPOINT:
+                    Status = HandleClassEndpoint(Irp, Urb);
+                    break;
                 default:
                     DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_URB Function %x NOT IMPLEMENTED\n", Urb->UrbHeader.Function);
                     break;
@@ -1148,7 +1841,7 @@ CHubController::HandleDeviceControl(
         }
         case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE:
         {
-            DPRINT("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE\n");
+            DPRINT("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE %p\n", this);
 
             if (IoStack->Parameters.Others.Argument1)
             {
@@ -1223,6 +1916,12 @@ CHubController::HandleDeviceControl(
             Irp->IoStatus.Information = sizeof(ULONG);
             break;
         }
+        case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION:
+        {
+            DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION UNIMPLEMENTED\n");
+            Status = STATUS_SUCCESS;
+            break;
+        }
         default:
         {
             DPRINT1("HandleDeviceControl>Type: IoCtl %x InputBufferLength %lu OutputBufferLength %lu NOT IMPLEMENTED\n",
@@ -1232,9 +1931,12 @@ CHubController::HandleDeviceControl(
             break;
         }
     }
+    if (Status != STATUS_PENDING)
+    {
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    }
 
-    Irp->IoStatus.Status = Status;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
     return Status;
 }
 
@@ -1266,7 +1968,7 @@ CHubController::AcquireDeviceAddress()
         //
         // reserve address
         //
-        RtlSetBit(&m_DeviceAddressBitmap, DeviceAddress);
+        RtlSetBits(&m_DeviceAddressBitmap, DeviceAddress, 1);
 
         //
         // device addresses start from 0x1 - 0xFF
@@ -1309,7 +2011,7 @@ CHubController::ReleaseDeviceAddress(
     //
     // clear bit
     //
-    RtlClearBit(&m_DeviceAddressBitmap, DeviceAddress);
+    RtlClearBits(&m_DeviceAddressBitmap, DeviceAddress, 1);
 
     //
     // release lock
@@ -1703,12 +2405,12 @@ USBHI_InitializeUsbDevice(
         //
         // now set the device address
         //
-        Status = UsbDevice->SetDeviceAddress(DeviceAddress);
+        Status = UsbDevice->SetDeviceAddress((UCHAR)DeviceAddress);
 
         if (NT_SUCCESS(Status))
             break;
 
-    }while(Index++ < 3 );
+    }while(Index++ < 3    );
 
     //
     // check for failure
@@ -1749,8 +2451,6 @@ USBHI_GetUsbDescriptors(
 {
     PUSBDEVICE UsbDevice;
     CHubController * Controller;
-    NTSTATUS Status;
-    PURB Urb;
 
     DPRINT1("USBHI_GetUsbDescriptors\n");
 
@@ -1758,7 +2458,10 @@ USBHI_GetUsbDescriptors(
     // sanity check
     //
     PC_ASSERT(DeviceDescriptorBuffer);
+    PC_ASSERT(DeviceDescriptorBufferLength);
     PC_ASSERT(*DeviceDescriptorBufferLength >= sizeof(USB_DEVICE_DESCRIPTOR));
+    PC_ASSERT(ConfigDescriptorBufferLength);
+    PC_ASSERT(*ConfigDescriptorBufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR));
 
     //
     // first get controller
@@ -1797,53 +2500,14 @@ USBHI_GetUsbDescriptors(
     *DeviceDescriptorBufferLength = sizeof(USB_DEVICE_DESCRIPTOR);
 
     //
-    // allocate urb
-    //
-    Urb = (PURB)ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), TAG_USBEHCI);
-    if (!Urb)
-    {
-        //
-        // no memory
-        // 
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    //
-    // zero request
-    //
-    RtlZeroMemory(Urb, sizeof(URB));
-
-    //
-    // initialize request
-    //
-    Urb->UrbHeader.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
-    Urb->UrbHeader.Length = sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST);
-    Urb->UrbControlDescriptorRequest.DescriptorType = USB_CONFIGURATION_DESCRIPTOR_TYPE;
-    Urb->UrbControlDescriptorRequest.TransferBuffer = ConfigDescriptorBuffer;
-    Urb->UrbControlDescriptorRequest.TransferBufferLength = *ConfigDescriptorBufferLength;
-
-    //
-    // submit urb
-    //
-    Status = UsbDevice->SubmitUrb(Urb);
-
-    if (NT_SUCCESS(Status))
-    {
-        //
-        // TransferBufferLength holds the number of bytes transferred
-        //
-        *ConfigDescriptorBufferLength = Urb->UrbControlDescriptorRequest.TransferBufferLength;
-    }
-
-    //
-    // free urb
+    // get configuration descriptor
     //
-    ExFreePoolWithTag(Urb, TAG_USBEHCI);
+    UsbDevice->GetConfigurationDescriptors((PUSB_CONFIGURATION_DESCRIPTOR)ConfigDescriptorBuffer, *ConfigDescriptorBufferLength, ConfigDescriptorBufferLength);
 
     //
     // complete the request
     //
-    return Status;
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS
@@ -1927,18 +2591,40 @@ USBHI_RestoreUsbDevice(
     PUSB_DEVICE_HANDLE OldDeviceHandle,
     PUSB_DEVICE_HANDLE NewDeviceHandle)
 {
-    UNIMPLEMENTED
-    return STATUS_NOT_IMPLEMENTED;
-}
+    PUSBDEVICE OldUsbDevice, NewUsbDevice;
+    CHubController * Controller;
 
-NTSTATUS
-USB_BUSIFFN
-USBHI_GetPortHackFlags(
-    PVOID BusContext,
-    PULONG Flags)
-{
-    UNIMPLEMENTED
-    return STATUS_NOT_IMPLEMENTED;
+    DPRINT1("USBHI_RestoreUsbDevice\n");
+
+    //
+    // first get controller
+    //
+    Controller = (CHubController *)BusContext;
+    PC_ASSERT(Controller);
+
+    //
+    // get device object
+    //
+    OldUsbDevice = (PUSBDEVICE)OldDeviceHandle;
+    NewUsbDevice = (PUSBDEVICE)NewDeviceHandle;
+    PC_ASSERT(OldUsbDevice);
+    PC_ASSERT(NewDeviceHandle);
+
+    //
+    // validate device handle
+    //
+    PC_ASSERT(Controller->ValidateUsbDevice(NewUsbDevice));
+    PC_ASSERT(Controller->ValidateUsbDevice(OldUsbDevice));
+
+    DPRINT1("NewUsbDevice: DeviceAddress %x\n", NewUsbDevice->GetDeviceAddress());
+    DPRINT1("OldUsbDevice: DeviceAddress %x\n", OldUsbDevice->GetDeviceAddress());
+
+    //
+    // remove old device handle
+    //
+    USBHI_RemoveUsbDevice(BusContext, OldDeviceHandle, 0);
+
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS
@@ -2044,8 +2730,9 @@ USBHI_QueryDeviceInformation(
     DeviceInfo->NumberOfOpenPipes = 0; //FIXME
 
     //
-    // FIXME get device descriptor
+    // get device descriptor
     //
+    RtlMoveMemory(&DeviceInfo->DeviceDescriptor, ROOTHUB2_DEVICE_DESCRIPTOR, sizeof(USB_DEVICE_DESCRIPTOR));
 
     //
     // FIXME return pipe information
@@ -2054,8 +2741,11 @@ USBHI_QueryDeviceInformation(
     //
     // store result length
     //
-    *LengthReturned = sizeof(USB_DEVICE_INFORMATION_0);
-
+#ifdef _MSC_VER
+    *LengthReturned = FIELD_OFFSET(USB_DEVICE_INFORMATION_0, PipeList[DeviceInfo->NumberOfOpenPipes]);
+#else
+    *LengthReturned = sizeof(USB_DEVICE_INFORMATION_0) + (DeviceInfo->NumberOfOpenPipes > 1 ? (DeviceInfo->NumberOfOpenPipes - 1) * sizeof(USB_PIPE_INFORMATION_0) : 0);
+#endif
     //
     // done
     //
@@ -2101,7 +2791,11 @@ USBHI_GetControllerInformation(
     // set length returned
     //
     *LengthReturned = ControllerInfo->ActualLength;
-    return STATUS_NOT_IMPLEMENTED;
+
+    //
+    // done
+    //
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS
@@ -2235,7 +2929,7 @@ USBHI_Initialize20Hub(
     PUSB_DEVICE_HANDLE HubDeviceHandle,
     ULONG TtCount)
 {
-    UNIMPLEMENTED
+    DPRINT("USBHI_Initialize20Hub HubDeviceHandle %p UNIMPLEMENTED TtCount %lu\n", HubDeviceHandle, TtCount);
     return STATUS_SUCCESS;
 }
 
@@ -2248,7 +2942,7 @@ USBHI_RootHubInitNotification(
 {
     CHubController * Controller;
 
-    DPRINT1("USBHI_RootHubInitNotification\n");
+    DPRINT("USBHI_RootHubInitNotification %p \n", CallbackContext);
 
     //
     // get controller object
@@ -2314,11 +3008,31 @@ USBHI_SetDeviceHandleData(
         //
         return;
     }
+    else
+    {
+        //
+        // usbhub sends this request as a part of the Pnp startup sequence
+        // looks like we need apply a dragon voodoo to fixup the device stack
+        // otherwise usbhub will cause a bugcheck
+        //
+        DPRINT1("USBHI_SetDeviceHandleData %p\n", UsbDevicePdo);
 
-    //
-    // set device handle data
-    //
-    UsbDevice->SetDeviceHandleData(UsbDevicePdo);
+        //
+        // sanity check
+        //
+        PC_ASSERT(UsbDevicePdo->AttachedDevice);
+
+        //
+        // should be usbstor
+        // fixup device stack voodoo part #2
+        //
+        UsbDevicePdo->AttachedDevice->StackSize++;
+
+        //
+        // set device handle data
+        //
+        UsbDevice->SetDeviceHandleData(UsbDevicePdo);
+    }
 }
 
 //=================================================================================================
@@ -2506,7 +3220,6 @@ CHubController::HandleQueryInterface(
             InterfaceHub->GetUsbDescriptors = USBHI_GetUsbDescriptors;
             InterfaceHub->RemoveUsbDevice = USBHI_RemoveUsbDevice;
             InterfaceHub->RestoreUsbDevice = USBHI_RestoreUsbDevice;
-            InterfaceHub->GetPortHackFlags = USBHI_GetPortHackFlags;
             InterfaceHub->QueryDeviceInformation = USBHI_QueryDeviceInformation;
         }
 
@@ -2682,7 +3395,7 @@ CHubController::SetDeviceInterface(
     //
     // done
     //
-    return Status;
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS
@@ -2746,6 +3459,11 @@ CHubController::CreatePDO(
 
     DPRINT1("CHubController::CreatePDO: DeviceName %wZ\n", &DeviceName);
 
+    //
+    // fixup device stack voodoo part #1
+    //
+    (*OutDeviceObject)->StackSize++;
+
     /* done */
     return Status;
 }
@@ -2785,3 +3503,27 @@ CreateHubController(
     //
     return STATUS_SUCCESS;
 }
+
+VOID StatusChangeEndpointCallBack(PVOID Context)
+{
+    CHubController* This;
+    PIRP Irp;
+    This = (CHubController*)Context;
+
+    ASSERT(This);
+
+    Irp = This->m_PendingSCEIrp;
+    if (!Irp)
+    {
+        DPRINT1("There was no pending IRP for SCE. Did the usb hub 2.0 driver (usbhub2) load?\n");
+        return;
+    }
+
+    This->m_PendingSCEIrp = NULL;
+    This->QueryStatusChageEndpoint(Irp);
+
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    Irp->IoStatus.Information = 0;
+
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}