[LIBUSB]
[reactos.git] / reactos / lib / drivers / libusb / hub_controller.cpp
index c195ae7..59f5245 100644 (file)
@@ -69,6 +69,7 @@ public:
     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 HandleVendorDevice(IN OUT PIRP Irp, PURB Urb);
     NTSTATUS HandleBulkOrInterruptTransfer(IN OUT PIRP Irp, PURB Urb);
     NTSTATUS HandleIsochronousTransfer(IN OUT PIRP Irp, PURB Urb);
     NTSTATUS HandleClearStall(IN OUT PIRP Irp, PURB Urb);
@@ -94,7 +95,7 @@ protected:
     PDEVICE_OBJECT m_HubControllerDeviceObject;
     PDRIVER_OBJECT m_DriverObject;
 
-    PVOID m_HubCallbackContext; 
+    PVOID m_HubCallbackContext;
     PRH_INIT_CALLBACK m_HubCallbackRoutine;
 
     USB_DEVICE_DESCRIPTOR m_DeviceDescriptor;
@@ -433,7 +434,7 @@ CHubController::HandlePnp(
         {
             DPRINT("[USBLIB] HandlePnp IRP_MN_START_DEVICE\n");
             //
-            // register device interface 
+            // register device interface
             //
             Status = SetDeviceInterface(TRUE);
             break;
@@ -739,6 +740,12 @@ CHubController::HandlePnp(
             Status = STATUS_SUCCESS;
             break;
         }
+        case IRP_MN_SURPRISE_REMOVAL:
+        {
+            DPRINT("[USBLIB] HandlePnp IRP_MN_SURPRISE_REMOVAL\n");
+            Status = STATUS_SUCCESS;
+            break;
+        }
         default:
         {
             //
@@ -776,7 +783,7 @@ CHubController::HandlePower(
 //-----------------------------------------------------------------------------------------
 NTSTATUS
 CHubController::HandleIsochronousTransfer(
-    IN OUT PIRP Irp, 
+    IN OUT PIRP Irp,
     PURB Urb)
 {
     PUSBDEVICE UsbDevice;
@@ -798,6 +805,7 @@ CHubController::HandleIsochronousTransfer(
     // sanity checks
     //
     ASSERT(EndPointDesc);
+    DPRINT("HandleIsochronousTransfer EndPointDesc %p Address %x bmAttributes %x\n", EndPointDesc, EndPointDesc->bEndpointAddress, EndPointDesc->bmAttributes);
     ASSERT((EndPointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_ISOCHRONOUS);
 
     //
@@ -824,7 +832,7 @@ CHubController::HandleIsochronousTransfer(
 //-----------------------------------------------------------------------------------------
 NTSTATUS
 CHubController::HandleBulkOrInterruptTransfer(
-    IN OUT PIRP Irp, 
+    IN OUT PIRP Irp,
     PURB Urb)
 {
     PUSBDEVICE UsbDevice;
@@ -836,7 +844,7 @@ CHubController::HandleBulkOrInterruptTransfer(
     //
     // Is the Request for the root hub
     //
-    if (Urb->UrbHeader.UsbdDeviceHandle == 0)
+    if (Urb->UrbHeader.UsbdDeviceHandle == PVOID(this))
     {
         ASSERT(m_PendingSCEIrp == NULL);
         if (QueryStatusChageEndpoint(Irp))
@@ -888,7 +896,7 @@ CHubController::HandleBulkOrInterruptTransfer(
 //-----------------------------------------------------------------------------------------
 NTSTATUS
 CHubController::HandleClassOther(
-    IN OUT PIRP Irp, 
+    IN OUT PIRP Irp,
     PURB Urb)
 {
     NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
@@ -963,7 +971,7 @@ CHubController::HandleClassOther(
                     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("[USBLIB] Unknown Value for Clear Feature %x \n", Urb->UrbControlVendorClassRequest.Value);
@@ -1031,11 +1039,12 @@ CHubController::HandleClassOther(
 //-----------------------------------------------------------------------------------------
 NTSTATUS
 CHubController::HandleSelectConfiguration(
-    IN OUT PIRP Irp, 
+    IN OUT PIRP Irp,
     PURB Urb)
 {
     PUSBDEVICE UsbDevice;
     PUSBD_INTERFACE_INFORMATION InterfaceInfo;
+    NTSTATUS Status;
 
     //
     // is the request for the Root Hub
@@ -1102,14 +1111,20 @@ CHubController::HandleSelectConfiguration(
         //
         // select configuration
         //
-        return UsbDevice->SelectConfiguration(Urb->UrbSelectConfiguration.ConfigurationDescriptor, &Urb->UrbSelectConfiguration.Interface, &Urb->UrbSelectConfiguration.ConfigurationHandle);
+        Status = UsbDevice->SelectConfiguration(Urb->UrbSelectConfiguration.ConfigurationDescriptor, &Urb->UrbSelectConfiguration.Interface, &Urb->UrbSelectConfiguration.ConfigurationHandle);
+        if (NT_SUCCESS(Status)) 
+        {
+            // successfully configured device
+            Urb->UrbSelectConfiguration.Hdr.Status = USBD_STATUS_SUCCESS;
+        }
+        return Status;
     }
 }
 
 //-----------------------------------------------------------------------------------------
 NTSTATUS
 CHubController::HandleSelectInterface(
-    IN OUT PIRP Irp, 
+    IN OUT PIRP Irp,
     PURB Urb)
 {
     PUSBDEVICE UsbDevice;
@@ -1159,7 +1174,7 @@ CHubController::HandleSelectInterface(
 //-----------------------------------------------------------------------------------------
 NTSTATUS
 CHubController::HandleGetStatusFromDevice(
-    IN OUT PIRP Irp, 
+    IN OUT PIRP Irp,
     PURB Urb)
 {
     PUSHORT DeviceStatus;
@@ -1179,7 +1194,7 @@ CHubController::HandleGetStatusFromDevice(
     DeviceStatus = (PUSHORT)Urb->UrbControlGetStatusRequest.TransferBuffer;
 
 
-    if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
+    if (Urb->UrbHeader.UsbdDeviceHandle == PVOID(this))
     {
         //
         // FIXME need more flags ?
@@ -1207,31 +1222,30 @@ CHubController::HandleGetStatusFromDevice(
     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;
-
-
-     if (Urb->UrbHeader.Function == URB_FUNCTION_GET_STATUS_FROM_INTERFACE)
-     {
-         //
-         // add interface type
-         //
-         CtrlSetup.bmRequestType.B |= 0x01;
-     }
-     else if (Urb->UrbHeader.Function == URB_FUNCTION_GET_STATUS_FROM_ENDPOINT)
-     {
-         //
-         // add interface type
-         //
-         CtrlSetup.bmRequestType.B |= 0x02;
-     }
+    //
+    // 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;
+
+    if (Urb->UrbHeader.Function == URB_FUNCTION_GET_STATUS_FROM_INTERFACE)
+    {
+        //
+        // add interface type
+        //
+        CtrlSetup.bmRequestType.B |= 0x01;
+    }
+    else if (Urb->UrbHeader.Function == URB_FUNCTION_GET_STATUS_FROM_ENDPOINT)
+    {
+        //
+        // add interface type
+        //
+        CtrlSetup.bmRequestType.B |= 0x02;
+    }
 
     //
     // submit setup packet
@@ -1291,7 +1305,6 @@ CHubController::HandleClassDevice(
             // 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;
@@ -1311,46 +1324,66 @@ CHubController::HandleClassDevice(
                 case USB_DEVICE_CLASS_RESERVED: // FALL THROUGH
                 case USB_DEVICE_CLASS_HUB:
                 {
-                    //
-                    // sanity checks
-                    //
-                    PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer);
-                    PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength >= sizeof(USB_HUB_DESCRIPTOR));
+                    if (Urb->UrbHeader.UsbdDeviceHandle == PVOID(this))
+                    {
+                        //
+                        // sanity checks
+                        //
+                        PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer);
+                        PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength >= sizeof(USB_HUB_DESCRIPTOR));
 
-                    //
-                    // get hub descriptor
-                    //
-                    UsbHubDescriptor = (PUSB_HUB_DESCRIPTOR)Urb->UrbControlVendorClassRequest.TransferBuffer;
+                        //
+                        // get hub descriptor
+                        //
+                        UsbHubDescriptor = (PUSB_HUB_DESCRIPTOR)Urb->UrbControlVendorClassRequest.TransferBuffer;
 
-                    //
-                    // one hub is handled
-                    //
-                    UsbHubDescriptor->bDescriptorLength = sizeof(USB_HUB_DESCRIPTOR);
-                    Urb->UrbControlVendorClassRequest.TransferBufferLength = sizeof(USB_HUB_DESCRIPTOR);
+                        //
+                        // one hub is handled
+                        //
+                        UsbHubDescriptor->bDescriptorLength = sizeof(USB_HUB_DESCRIPTOR);
+                        Urb->UrbControlVendorClassRequest.TransferBufferLength = sizeof(USB_HUB_DESCRIPTOR);
 
-                    //
-                    // type should 0x29 according to msdn
-                    //
-                    UsbHubDescriptor->bDescriptorType = 0x29;
+                        //
+                        // type should 0x29 according to msdn
+                        //
+                        UsbHubDescriptor->bDescriptorType = 0x29;
 
-                    //
-                    // get port count
-                    //
-                    Status = m_Hardware->GetDeviceDetails(&Dummy1, &Dummy1, &PortCount, &Dummy2);
-                    PC_ASSERT(Status == STATUS_SUCCESS);
+                        //
+                        // get port count
+                        //
+                        Status = m_Hardware->GetDeviceDetails(&Dummy1, &Dummy1, &PortCount, &Dummy2);
+                        PC_ASSERT(Status == STATUS_SUCCESS);
 
-                    //
-                    // FIXME: retrieve values
-                    //
-                    UsbHubDescriptor->bNumberOfPorts = (UCHAR)PortCount;
-                    UsbHubDescriptor->wHubCharacteristics = 0x00;
-                    UsbHubDescriptor->bPowerOnToPowerGood = 0x01;
-                    UsbHubDescriptor->bHubControlCurrent = 0x00;
+                        //
+                        // FIXME: retrieve values
+                        //
+                        UsbHubDescriptor->bNumberOfPorts = (UCHAR)PortCount;
+                        UsbHubDescriptor->wHubCharacteristics = 0x00;
+                        UsbHubDescriptor->bPowerOnToPowerGood = 0x01;
+                        UsbHubDescriptor->bHubControlCurrent = 0x00;
 
-                    //
-                    // done
-                    //
-                    Status = STATUS_SUCCESS;
+                        //
+                        // done
+                        //
+                        Status = STATUS_SUCCESS;
+                    }
+                    else
+                    {
+                        if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+                        {
+                            DPRINT1("HandleClassDevice invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+                            //
+                            // invalid device handle
+                            //
+                            return STATUS_DEVICE_NOT_CONNECTED;
+                        }
+
+                        //
+                        // FIXME: implement support for real hubs
+                        //
+                        UNIMPLEMENTED
+                        Status = STATUS_NOT_IMPLEMENTED;
+                    }
                     break;
                }
                default:
@@ -1360,7 +1393,52 @@ CHubController::HandleClassDevice(
             break;
         }
         default:
-            DPRINT1("[USBLIB] HandleClassDevice Type %x not implemented\n", Urb->UrbControlVendorClassRequest.Request);
+        {
+            //
+            // 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.bmRequestType.B = 0;
+            CtrlSetup.bmRequestType._BM.Recipient = BMREQUEST_TO_DEVICE;
+            CtrlSetup.bmRequestType._BM.Type = BMREQUEST_CLASS;
+            CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request;
+            CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
+            CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
+            CtrlSetup.wLength = (USHORT)Urb->UrbControlVendorClassRequest.TransferBufferLength;
+
+            if (Urb->UrbControlVendorClassRequest.TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+            {
+                //
+                // data direction is device to host
+                //
+                CtrlSetup.bmRequestType._BM.Dir = BMREQUEST_DEVICE_TO_HOST;
+            }
+
+            //
+            // submit setup packet
+            //
+            Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
+            ASSERT(Status == STATUS_SUCCESS);
+
+            break;
+        }
     }
 
     return Status;
@@ -1414,7 +1492,10 @@ CHubController::HandleGetDescriptorFromInterface(
     // submit setup packet
     //
     Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
-    ASSERT(Status == STATUS_SUCCESS);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("[USBLIB] HandleGetDescriptorFromInterface failed with %x\n", Status);
+    }
 
     //
     // done
@@ -1429,13 +1510,12 @@ CHubController::HandleGetDescriptor(
     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;
+    ULONG Length, BufferLength;
 
-    DPRINT("[USBLIB] HandleGetDescriptor\n");
+    DPRINT("[USBLIB] HandleGetDescriptor Type %x\n", Urb->UrbControlDescriptorRequest.DescriptorType);
 
     //
     // check descriptor type
@@ -1450,12 +1530,14 @@ CHubController::HandleGetDescriptor(
             PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= sizeof(USB_DEVICE_DESCRIPTOR));
             PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
 
-            if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
+            if (Urb->UrbHeader.UsbdDeviceHandle == PVOID(this))
             {
                 //
                 // copy root hub device descriptor
                 //
                 RtlCopyMemory((PUCHAR)Urb->UrbControlDescriptorRequest.TransferBuffer, &m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
+                Irp->IoStatus.Information = sizeof(USB_DEVICE_DESCRIPTOR);
+                Urb->UrbControlDescriptorRequest.Hdr.Status = USBD_STATUS_SUCCESS;
                 Status = STATUS_SUCCESS;
             }
             else
@@ -1482,6 +1564,8 @@ CHubController::HandleGetDescriptor(
                 // retrieve device descriptor from device
                 //
                 UsbDevice->GetDeviceDescriptor((PUSB_DEVICE_DESCRIPTOR)Urb->UrbControlDescriptorRequest.TransferBuffer);
+                Irp->IoStatus.Information = sizeof(USB_DEVICE_DESCRIPTOR);
+                Urb->UrbControlDescriptorRequest.Hdr.Status = USBD_STATUS_SUCCESS;
                 Status = STATUS_SUCCESS;
             }
             break;
@@ -1492,44 +1576,70 @@ CHubController::HandleGetDescriptor(
             // sanity checks
             //
             PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
-            PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR));
+            //
+            // From MSDN
+            // The caller must allocate a buffer large enough to hold all of this information or the data is truncated without error.
+            //
+            BufferLength = Urb->UrbControlDescriptorRequest.TransferBufferLength;
+            Buffer = (PUCHAR) Urb->UrbControlDescriptorRequest.TransferBuffer;
 
-            if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
+            if (Urb->UrbHeader.UsbdDeviceHandle == PVOID(this))
             {
                 //
                 // request is for the root bus controller
                 //
-                RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer, &ROOTHUB2_CONFIGURATION_DESCRIPTOR, sizeof(USB_CONFIGURATION_DESCRIPTOR));
-
+                Length = BufferLength > sizeof(USB_CONFIGURATION_DESCRIPTOR) ?
+                    sizeof(USB_CONFIGURATION_DESCRIPTOR) : BufferLength;
+                RtlCopyMemory(Buffer, &ROOTHUB2_CONFIGURATION_DESCRIPTOR, Length);
+                
                 //
-                // get configuration descriptor, very retarded!
+                // Check if we still have some space left
                 //
-                ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)Urb->UrbControlDescriptorRequest.TransferBuffer;
+                if(Length == BufferLength)
+                {
+                    //
+                    // We copied all we could
+                    //
+                    Status = STATUS_SUCCESS;
+                    break;
+                }
+                //
+                // Go further
+                //
+                Buffer += Length;
+                BufferLength -= Length;
 
                 //
-                // check if buffer can hold interface and endpoint descriptor
+                // copy interface descriptor template
+                //
+                Length = BufferLength > sizeof(USB_INTERFACE_DESCRIPTOR) ?
+                    sizeof(USB_INTERFACE_DESCRIPTOR) : BufferLength;
+                RtlCopyMemory(Buffer, &ROOTHUB2_INTERFACE_DESCRIPTOR, Length);
+                
+                //
+                // Check if we still have some space left
                 //
-                if (ConfigurationDescriptor->wTotalLength > Urb->UrbControlDescriptorRequest.TransferBufferLength)
+                if(Length == BufferLength)
                 {
                     //
-                    // buffer too small
+                    // We copied all we could
                     //
                     Status = STATUS_SUCCESS;
-                    ASSERT(FALSE);
                     break;
                 }
-
                 //
-                // copy interface descriptor template
+                // Go further
                 //
-                Buffer = (PUCHAR)(ConfigurationDescriptor + 1);
-                RtlCopyMemory(Buffer, &ROOTHUB2_INTERFACE_DESCRIPTOR, sizeof(USB_INTERFACE_DESCRIPTOR));
-
+                Buffer += Length;
+                BufferLength -= Length;
+                
+                
                 //
                 // copy end point descriptor template
                 //
-                Buffer += sizeof(USB_INTERFACE_DESCRIPTOR);
-                RtlCopyMemory(Buffer, &ROOTHUB2_ENDPOINT_DESCRIPTOR, sizeof(USB_ENDPOINT_DESCRIPTOR));
+                Length = BufferLength > sizeof(USB_ENDPOINT_DESCRIPTOR) ?
+                    sizeof(USB_ENDPOINT_DESCRIPTOR) : BufferLength;
+                RtlCopyMemory(Buffer, &ROOTHUB2_ENDPOINT_DESCRIPTOR, Length);
 
                 //
                 // done
@@ -1556,30 +1666,41 @@ CHubController::HandleGetDescriptor(
                 // get device
                 //
                 UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
-
-                if (sizeof(USB_CONFIGURATION_DESCRIPTOR) > Urb->UrbControlDescriptorRequest.TransferBufferLength)
+                
+                //
+                // Allocate temporary buffer
+                //
+                BufferLength = UsbDevice->GetConfigurationDescriptorsLength();
+                Buffer = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, BufferLength, TAG_USBLIB);
+                if(!Buffer)
                 {
-                    //
-                    // buffer too small
-                    //
-                    Urb->UrbControlDescriptorRequest.TransferBufferLength = UsbDevice->GetConfigurationDescriptorsLength();
-
-                    //
-                    // bail out
-                    //
-                    Status = STATUS_SUCCESS;
+                    Status = STATUS_NO_MEMORY;
                     break;
                 }
 
                 //
                 // perform work in IUSBDevice
                 //
-                UsbDevice->GetConfigurationDescriptors((PUSB_CONFIGURATION_DESCRIPTOR)Urb->UrbControlDescriptorRequest.TransferBuffer, Urb->UrbControlDescriptorRequest.TransferBufferLength, &Length);
+                UsbDevice->GetConfigurationDescriptors((PUSB_CONFIGURATION_DESCRIPTOR)Buffer, BufferLength, &Length);
+                
+                //
+                // Copy what we can
+                //
+                Length = Urb->UrbControlDescriptorRequest.TransferBufferLength > Length ? 
+                    Length : Urb->UrbControlDescriptorRequest.TransferBufferLength;
+                RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer, Buffer, Length);
+                
+                //
+                // Free temporary buffer
+                //
+                ExFreePoolWithTag(Buffer, TAG_USBLIB);
 
                 //
                 // store result size
                 //
+                Irp->IoStatus.Information = Length;
                 Urb->UrbControlDescriptorRequest.TransferBufferLength = Length;
+                Urb->UrbControlDescriptorRequest.Hdr.Status = USBD_STATUS_SUCCESS;
                 Status = STATUS_SUCCESS;
             }
             break;
@@ -1691,7 +1812,7 @@ CHubController::HandleClassEndpoint(
     CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request;
     CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
     CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
-    CtrlSetup.wLength = Urb->UrbControlVendorClassRequest.TransferBufferLength;
+    CtrlSetup.wLength = (USHORT)Urb->UrbControlVendorClassRequest.TransferBufferLength;
 
     if (Urb->UrbControlVendorClassRequest.TransferFlags & USBD_TRANSFER_DIRECTION_IN)
     {
@@ -1719,6 +1840,75 @@ CHubController::HandleClassEndpoint(
     return Status;
 }
 
+//-----------------------------------------------------------------------------------------
+NTSTATUS
+CHubController::HandleVendorDevice(
+    IN OUT PIRP Irp,
+    IN OUT PURB Urb)
+{
+    NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
+    PUSBDEVICE UsbDevice;
+    USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
+
+    //DPRINT("CHubController::HandleVendorDevice Request %x\n", Urb->UrbControlVendorClassRequest.Request);
+
+    //
+    // sanity check
+    //
+    PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle);
+
+    //
+    // check if this is a valid usb device handle
+    //
+    if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
+    {
+        DPRINT1("[USBLIB] HandleVendorDevice invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
+
+        //
+        // invalid device handle
+        //
+        return STATUS_DEVICE_NOT_CONNECTED;
+    }
+
+    //
+    // get device
+    //
+    UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
+
+    //
+    // initialize setup packet
+    //
+    CtrlSetup.bmRequestType.B = 0;
+    CtrlSetup.bmRequestType._BM.Recipient = BMREQUEST_TO_DEVICE;
+    CtrlSetup.bmRequestType._BM.Type = BMREQUEST_VENDOR;
+    CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request;
+    CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
+    CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
+    CtrlSetup.wLength = (USHORT)Urb->UrbControlVendorClassRequest.TransferBufferLength;
+
+    if (Urb->UrbControlVendorClassRequest.TransferFlags & USBD_TRANSFER_DIRECTION_IN)
+    {
+        //
+        // data direction is device to host
+        //
+        CtrlSetup.bmRequestType._BM.Dir = BMREQUEST_DEVICE_TO_HOST;
+    }
+
+    //
+    // issue request
+    //
+    Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlVendorClassRequest.TransferBufferLength, Urb->UrbControlVendorClassRequest.TransferBuffer);
+    if (NT_SUCCESS(Status))
+    {
+        // success
+        Urb->UrbControlVendorClassRequest.Hdr.Status = USBD_STATUS_SUCCESS;
+        Irp->IoStatus.Information = Urb->UrbControlVendorClassRequest.TransferBufferLength;
+    }
+
+    return Status;
+}
+
+//-----------------------------------------------------------------------------------------
 NTSTATUS
 CHubController::HandleSyncResetAndClearStall(
     IN OUT PIRP Irp,
@@ -1759,7 +1949,7 @@ CHubController::HandleSyncResetAndClearStall(
         //
         DPRINT1("[USBLIB] failed to reset pipe %x\n", Status);
     }
+
 
     //
     // get endpoint descriptor
@@ -1782,8 +1972,8 @@ CHubController::HandleSyncResetAndClearStall(
     //
     // reset data toggle
     //
-    ASSERT(NT_SUCCESS(Status));
-    EndpointDescriptor->DataToggle = 0x0;
+    if (NT_SUCCESS(Status))
+        EndpointDescriptor->DataToggle = 0x0;
 
     //
     // done
@@ -1791,6 +1981,7 @@ CHubController::HandleSyncResetAndClearStall(
     return Status;
 }
 
+//-----------------------------------------------------------------------------------------
 NTSTATUS
 CHubController::HandleAbortPipe(
     IN OUT PIRP Irp,
@@ -1964,7 +2155,7 @@ CHubController::HandleClassInterface(
     CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request;
     CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
     CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
-    CtrlSetup.wLength = Urb->UrbControlVendorClassRequest.TransferBufferLength;
+    CtrlSetup.wLength = (USHORT)Urb->UrbControlVendorClassRequest.TransferBufferLength;
 
     if (Urb->UrbControlVendorClassRequest.TransferFlags & USBD_TRANSFER_DIRECTION_IN)
     {
@@ -2077,6 +2268,9 @@ CHubController::HandleDeviceControl(
                 case URB_FUNCTION_CLASS_ENDPOINT:
                     Status = HandleClassEndpoint(Irp, Urb);
                     break;
+                case URB_FUNCTION_VENDOR_DEVICE:
+                    Status = HandleVendorDevice(Irp, Urb);
+                    break;
                 default:
                     DPRINT1("[USBLIB] IOCTL_INTERNAL_USB_SUBMIT_URB Function %x NOT IMPLEMENTED\n", Urb->UrbHeader.Function);
                     break;
@@ -2146,7 +2340,7 @@ CHubController::HandleDeviceControl(
 
             //
             // after IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO is delivered, the usbhub driver
-            // requests this ioctl to deliver the number of presents. 
+            // requests this ioctl to deliver the number of presents.
 
             if (IoStack->Parameters.Others.Argument1)
             {
@@ -3076,7 +3270,7 @@ USBHI_GetExtendedHubInformation(
 
     //
     // sanity checks
-    // 
+    //
     PC_ASSERT(HubInformationBuffer);
     PC_ASSERT(HubInformationBufferLength == sizeof(USB_EXTHUB_INFORMATION_0));
     PC_ASSERT(LengthReturned);
@@ -3406,8 +3600,8 @@ USBDI_IsDeviceHighSpeed(
 NTSTATUS
 USB_BUSIFFN
 USBDI_EnumLogEntry(
-    PVOID BusContext, 
-    ULONG DriverTag, 
+    PVOID BusContext,
+    ULONG DriverTag,
     ULONG EnumTag,
     ULONG P1,
     ULONG P2)