[LIBUSB][USBCCGP]
[reactos.git] / reactos / drivers / usb / usbccgp / pdo.c
index e7a52b8..617b299 100644 (file)
@@ -136,7 +136,7 @@ USBCCGP_PdoAppendInterfaceNumber(
     // count length of string
     //
     String = DeviceId;
     // count length of string
     //
     String = DeviceId;
-    while(*String)
+    while (*String)
     {
         StringLength = wcslen(String) + 1;
         Length += StringLength;
     {
         StringLength = wcslen(String) + 1;
         Length += StringLength;
@@ -161,7 +161,7 @@ USBCCGP_PdoAppendInterfaceNumber(
     //
     *OutString = String;
 
     //
     *OutString = String;
 
-    while(*DeviceId)
+    while (*DeviceId)
     {
         StringLength = swprintf(String, L"%s&MI_%02x", DeviceId, InterfaceNumber) + 1;
         Length = wcslen(DeviceId) + 1;
     {
         StringLength = swprintf(String, L"%s&MI_%02x", DeviceId, InterfaceNumber) + 1;
         Length = wcslen(DeviceId) + 1;
@@ -225,7 +225,7 @@ USBCCGP_PdoHandleQueryId(
                 DPRINT("BusQueryDeviceID %S\n", Buffer);
 
                 ExFreePool((PVOID)Irp->IoStatus.Information);
                 DPRINT("BusQueryDeviceID %S\n", Buffer);
 
                 ExFreePool((PVOID)Irp->IoStatus.Information);
-                Irp->IoStatus .Information = (ULONG_PTR)Buffer;
+                Irp->IoStatus.Information = (ULONG_PTR)Buffer;
             }
             else
             {
             }
             else
             {
@@ -272,6 +272,13 @@ USBCCGP_PdoHandleQueryId(
         //
         DeviceString = &PDODeviceExtension->FunctionDescriptor->CompatibleId;
     }
         //
         DeviceString = &PDODeviceExtension->FunctionDescriptor->CompatibleId;
     }
+    else
+    {
+        //
+        // unsupported query
+        //
+        return Irp->IoStatus.Status;
+    }
 
     //
     // sanity check
 
     //
     // sanity check
@@ -294,6 +301,7 @@ USBCCGP_PdoHandleQueryId(
     // copy buffer
     //
     RtlCopyMemory(Buffer, DeviceString->Buffer, DeviceString->Length);
     // copy buffer
     //
     RtlCopyMemory(Buffer, DeviceString->Buffer, DeviceString->Length);
+    Buffer[DeviceString->Length / sizeof(WCHAR)] = UNICODE_NULL;
     Irp->IoStatus.Information = (ULONG_PTR)Buffer;
 
     return STATUS_SUCCESS;
     Irp->IoStatus.Information = (ULONG_PTR)Buffer;
 
     return STATUS_SUCCESS;
@@ -326,76 +334,76 @@ PDO_HandlePnp(
 
     switch(IoStack->MinorFunction)
     {
 
     switch(IoStack->MinorFunction)
     {
-       case IRP_MN_QUERY_DEVICE_RELATIONS:
-       {
-           //
-           // handle device relations
-           //
-           Status = USBCCGP_PdoHandleDeviceRelations(DeviceObject, Irp);
-           break;
-       }
-       case IRP_MN_QUERY_DEVICE_TEXT:
-       {
-           //
-           // handle query device text
-           //
-           Status = USBCCGP_PdoHandleQueryDeviceText(DeviceObject, Irp);
-           break;
-       }
-       case IRP_MN_QUERY_ID:
-       {
-           //
-           // handle request
-           //
-           Status = USBCCGP_PdoHandleQueryId(DeviceObject, Irp);
-           break;
-       }
-       case IRP_MN_REMOVE_DEVICE:
-       {
-           //
-           // remove us from the fdo's pdo list
-           //
-           bFound = FALSE;
-           for(Index = 0; Index < PDODeviceExtension->FDODeviceExtension->FunctionDescriptorCount; Index++)
-           {
-               if (PDODeviceExtension->FDODeviceExtension->ChildPDO[Index] == DeviceObject)
-               {
-                   //
-                   // remove us
-                   //
-                   PDODeviceExtension->FDODeviceExtension->ChildPDO[Index] = NULL;
-                   bFound = TRUE;
-                   break;
-               }
-           }
-
-           //
-           // Complete the IRP
-           //
-           Irp->IoStatus.Status = STATUS_SUCCESS;
-           IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
-           if (bFound)
-           {
-               //
-               // Delete the device object
-               //
-               IoDeleteDevice(DeviceObject);
-           }
-           return STATUS_SUCCESS;
-       }
-       case IRP_MN_QUERY_CAPABILITIES:
-       {
-           //
-           // copy device capabilities
-           //
-           RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, &PDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
-
-           /* Complete the IRP */
-           Irp->IoStatus.Status = STATUS_SUCCESS;
-           IoCompleteRequest(Irp, IO_NO_INCREMENT);
-           return STATUS_SUCCESS;
-       }
+        case IRP_MN_QUERY_DEVICE_RELATIONS:
+        {
+            //
+            // handle device relations
+            //
+            Status = USBCCGP_PdoHandleDeviceRelations(DeviceObject, Irp);
+            break;
+        }
+        case IRP_MN_QUERY_DEVICE_TEXT:
+        {
+            //
+            // handle query device text
+            //
+            Status = USBCCGP_PdoHandleQueryDeviceText(DeviceObject, Irp);
+            break;
+        }
+        case IRP_MN_QUERY_ID:
+        {
+            //
+            // handle request
+            //
+            Status = USBCCGP_PdoHandleQueryId(DeviceObject, Irp);
+            break;
+        }
+        case IRP_MN_REMOVE_DEVICE:
+        {
+            //
+            // remove us from the fdo's pdo list
+            //
+            bFound = FALSE;
+            for(Index = 0; Index < PDODeviceExtension->FDODeviceExtension->FunctionDescriptorCount; Index++)
+            {
+                if (PDODeviceExtension->FDODeviceExtension->ChildPDO[Index] == DeviceObject)
+                {
+                    //
+                    // remove us
+                    //
+                    PDODeviceExtension->FDODeviceExtension->ChildPDO[Index] = NULL;
+                    bFound = TRUE;
+                    break;
+                }
+            }
+
+            //
+            // Complete the IRP
+            //
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+            if (bFound)
+            {
+                //
+                // Delete the device object
+                //
+                IoDeleteDevice(DeviceObject);
+            }
+            return STATUS_SUCCESS;
+        }
+        case IRP_MN_QUERY_CAPABILITIES:
+        {
+            //
+            // copy device capabilities
+            //
+            RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, &PDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
+
+            /* Complete the IRP */
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+            return STATUS_SUCCESS;
+        }
         case IRP_MN_QUERY_REMOVE_DEVICE:
         case IRP_MN_QUERY_STOP_DEVICE:
         {
         case IRP_MN_QUERY_REMOVE_DEVICE:
         case IRP_MN_QUERY_STOP_DEVICE:
         {
@@ -405,16 +413,24 @@ PDO_HandlePnp(
             Status = STATUS_SUCCESS;
             break;
         }
             Status = STATUS_SUCCESS;
             break;
         }
-       case IRP_MN_START_DEVICE:
-       {
-           //
-           // no-op for PDO
-           //
-           DPRINT("[USBCCGP] PDO IRP_MN_START\n");
-           Status = STATUS_SUCCESS;
-           break;
-       }
-       default:
+        case IRP_MN_START_DEVICE:
+        {
+            //
+            // no-op for PDO
+            //
+            DPRINT("[USBCCGP] PDO IRP_MN_START\n");
+            Status = STATUS_SUCCESS;
+            break;
+        }
+        case IRP_MN_QUERY_INTERFACE:
+        {
+            //
+            // forward to lower device object
+            //
+            IoSkipCurrentIrpStackLocation(Irp);
+            return IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
+        }
+        default:
         {
             //
             // do nothing
         {
             //
             // do nothing
@@ -449,7 +465,7 @@ PDO_HandlePnp(
 
 NTSTATUS
 USBCCGP_BuildConfigurationDescriptor(
 
 NTSTATUS
 USBCCGP_BuildConfigurationDescriptor(
-    PDEVICE_OBJECT DeviceObject, 
+    PDEVICE_OBJECT DeviceObject,
     PIRP Irp)
 {
     PIO_STACK_LOCATION IoStack;
     PIRP Irp)
 {
     PIO_STACK_LOCATION IoStack;
@@ -457,9 +473,11 @@ USBCCGP_BuildConfigurationDescriptor(
     PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
     PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
     ULONG TotalSize, Index;
     PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
     PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
     ULONG TotalSize, Index;
+    ULONG Size;
     PURB Urb;
     PVOID Buffer;
     PUCHAR BufferPtr;
     PURB Urb;
     PVOID Buffer;
     PUCHAR BufferPtr;
+    UCHAR InterfaceNumber;
 
     //
     // get current stack location
 
     //
     // get current stack location
@@ -483,12 +501,13 @@ USBCCGP_BuildConfigurationDescriptor(
     //
     TotalSize = sizeof(USB_CONFIGURATION_DESCRIPTOR);
 
     //
     TotalSize = sizeof(USB_CONFIGURATION_DESCRIPTOR);
 
-    for(Index = 0; Index < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; Index++)
+    for (Index = 0; Index < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; Index++)
     {
         //
         // get current interface descriptor
         //
         InterfaceDescriptor = PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[Index];
     {
         //
         // get current interface descriptor
         //
         InterfaceDescriptor = PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[Index];
+        InterfaceNumber = InterfaceDescriptor->bInterfaceNumber;
 
         //
         // add to size and move to next descriptor
 
         //
         // add to size and move to next descriptor
@@ -513,10 +532,17 @@ USBCCGP_BuildConfigurationDescriptor(
             {
                 if (InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
                 {
             {
                 if (InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
                 {
+                    if (InterfaceNumber != InterfaceDescriptor->bInterfaceNumber)
+                    {
+                        //
+                        // reached next descriptor
+                        //
+                        break;
+                    }
+
                     //
                     //
-                    // reached next descriptor
+                    // include alternate descriptor
                     //
                     //
-                    break;
                 }
 
                 //
                 }
 
                 //
@@ -529,7 +555,7 @@ USBCCGP_BuildConfigurationDescriptor(
             // move to next descriptor
             //
             InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
             // move to next descriptor
             //
             InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
-        }while(TRUE);
+        } while(TRUE);
     }
 
     //
     }
 
     //
@@ -551,12 +577,13 @@ USBCCGP_BuildConfigurationDescriptor(
     RtlCopyMemory(Buffer, ConfigurationDescriptor, sizeof(USB_CONFIGURATION_DESCRIPTOR));
     BufferPtr = (PUCHAR)((ULONG_PTR)Buffer + ConfigurationDescriptor->bLength);
 
     RtlCopyMemory(Buffer, ConfigurationDescriptor, sizeof(USB_CONFIGURATION_DESCRIPTOR));
     BufferPtr = (PUCHAR)((ULONG_PTR)Buffer + ConfigurationDescriptor->bLength);
 
-    for(Index = 0; Index < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; Index++)
+    for (Index = 0; Index < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; Index++)
     {
         //
         // get current interface descriptor
         //
         InterfaceDescriptor = PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[Index];
     {
         //
         // get current interface descriptor
         //
         InterfaceDescriptor = PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[Index];
+        InterfaceNumber = InterfaceDescriptor->bInterfaceNumber;
 
         //
         // copy descriptor and move to next descriptor
 
         //
         // copy descriptor and move to next descriptor
@@ -582,10 +609,18 @@ USBCCGP_BuildConfigurationDescriptor(
             {
                 if (InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
                 {
             {
                 if (InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
                 {
+                    if (InterfaceNumber != InterfaceDescriptor->bInterfaceNumber)
+                    {
+                        //
+                        // reached next descriptor
+                        //
+                        break;
+                    }
+
                     //
                     //
-                    // reached next descriptor
+                    // include alternate descriptor
                     //
                     //
-                    break;
+                    DPRINT("InterfaceDescriptor %p Alternate %x InterfaceNumber %x\n", InterfaceDescriptor, InterfaceDescriptor->bAlternateSetting, InterfaceDescriptor->bInterfaceNumber);
                 }
 
                 //
                 }
 
                 //
@@ -599,14 +634,14 @@ USBCCGP_BuildConfigurationDescriptor(
             // move to next descriptor
             //
             InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
             // move to next descriptor
             //
             InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
-        }while(TRUE);
+        } while(TRUE);
     }
 
     //
     // modify configuration descriptor
     //
     ConfigurationDescriptor = Buffer;
     }
 
     //
     // modify configuration descriptor
     //
     ConfigurationDescriptor = Buffer;
-    ConfigurationDescriptor->wTotalLength = TotalSize;
+    ConfigurationDescriptor->wTotalLength = (USHORT)TotalSize;
     ConfigurationDescriptor->bNumInterfaces = PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces;
 
     //
     ConfigurationDescriptor->bNumInterfaces = PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces;
 
     //
@@ -618,12 +653,13 @@ USBCCGP_BuildConfigurationDescriptor(
     //
     // copy descriptor
     //
     //
     // copy descriptor
     //
-    RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer, Buffer, min(TotalSize, Urb->UrbControlDescriptorRequest.TransferBufferLength));
+    Size = min(TotalSize, Urb->UrbControlDescriptorRequest.TransferBufferLength);
+    RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer, Buffer, Size);
 
     //
     // store final size
     //
 
     //
     // store final size
     //
-    Urb->UrbControlDescriptorRequest.TransferBufferLength = TotalSize;
+    Urb->UrbControlDescriptorRequest.TransferBufferLength = Size;
 
     //
     // free buffer
 
     //
     // free buffer
@@ -638,14 +674,14 @@ USBCCGP_BuildConfigurationDescriptor(
 
 NTSTATUS
 USBCCGP_PDOSelectConfiguration(
 
 NTSTATUS
 USBCCGP_PDOSelectConfiguration(
-    PDEVICE_OBJECT DeviceObject, 
+    PDEVICE_OBJECT DeviceObject,
     PIRP Irp)
 {
     PIO_STACK_LOCATION IoStack;
     PPDO_DEVICE_EXTENSION PDODeviceExtension;
     PURB Urb, NewUrb;
     PUSBD_INTERFACE_INFORMATION InterfaceInformation;
     PIRP Irp)
 {
     PIO_STACK_LOCATION IoStack;
     PPDO_DEVICE_EXTENSION PDODeviceExtension;
     PURB Urb, NewUrb;
     PUSBD_INTERFACE_INFORMATION InterfaceInformation;
-    ULONG InterfaceInformationCount, Index, InterfaceIndex;
+    ULONG InterfaceIndex, Length;
     PUSBD_INTERFACE_LIST_ENTRY Entry;
     ULONG NeedSelect, FoundInterface;
     NTSTATUS Status;
     PUSBD_INTERFACE_LIST_ENTRY Entry;
     ULONG NeedSelect, FoundInterface;
     NTSTATUS Status;
@@ -677,33 +713,30 @@ USBCCGP_PDOSelectConfiguration(
         return STATUS_SUCCESS;
     }
 
         return STATUS_SUCCESS;
     }
 
-    //
-    // count interface information
-    //
-    InterfaceInformationCount = 0;
-    InterfaceInformation = &Urb->UrbSelectConfiguration.Interface;
-    do
-    {
-        InterfaceInformationCount++;
-        InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + InterfaceInformation->Length);
-    }while((ULONG_PTR)InterfaceInformation < (ULONG_PTR)Urb + Urb->UrbSelectConfiguration.Hdr.Length);
+    // sanity checks
+    //C_ASSERT(sizeof(struct _URB_HEADER) == 16);
+    //C_ASSERT(FIELD_OFFSET(struct _URB_SELECT_CONFIGURATION, Interface.Length) == 24);
+    //C_ASSERT(sizeof(USBD_INTERFACE_INFORMATION) == 36);
+    //C_ASSERT(sizeof(struct _URB_SELECT_CONFIGURATION) == 0x3C);
+
+    // available buffer length
+    Length = Urb->UrbSelectConfiguration.Hdr.Length - FIELD_OFFSET(struct _URB_SELECT_CONFIGURATION, Interface.Length);
 
     //
     // check all interfaces
     //
     InterfaceInformation = &Urb->UrbSelectConfiguration.Interface;
 
     //
     // check all interfaces
     //
     InterfaceInformation = &Urb->UrbSelectConfiguration.Interface;
-    Index = 0;
+
     Entry = NULL;
     Entry = NULL;
-    DPRINT("Count %x\n", InterfaceInformationCount);
     do
     {
     do
     {
-        DPRINT1("[USBCCGP] SelectConfiguration Function %x InterfaceNumber %x Alternative %x\n", PDODeviceExtension->FunctionDescriptor->FunctionNumber, InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting);
-
+        DPRINT1("[USBCCGP] SelectConfiguration Function %x InterfaceNumber %x Alternative %x Length %lu InterfaceInformation->Length %lu\n", PDODeviceExtension->FunctionDescriptor->FunctionNumber, InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting, Length, InterfaceInformation->Length);
+        ASSERT(InterfaceInformation->Length);
         //
         // search for the interface in the local interface list
         //
         FoundInterface = FALSE;
         //
         // search for the interface in the local interface list
         //
         FoundInterface = FALSE;
-        for(InterfaceIndex = 0; InterfaceIndex < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; InterfaceIndex++)
+        for (InterfaceIndex = 0; InterfaceIndex < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; InterfaceIndex++)
         {
             if (PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[InterfaceIndex]->bInterfaceNumber == InterfaceInformation->InterfaceNumber)
             {
         {
             if (PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[InterfaceIndex]->bInterfaceNumber == InterfaceInformation->InterfaceNumber)
             {
@@ -727,7 +760,7 @@ USBCCGP_PDOSelectConfiguration(
         // now query the total interface list
         //
         Entry = NULL;
         // now query the total interface list
         //
         Entry = NULL;
-        for(InterfaceIndex = 0; InterfaceIndex < PDODeviceExtension->InterfaceListCount; InterfaceIndex++)
+        for (InterfaceIndex = 0; InterfaceIndex < PDODeviceExtension->InterfaceListCount; InterfaceIndex++)
         {
             if (PDODeviceExtension->InterfaceList[InterfaceIndex].Interface->InterfaceNumber == InterfaceInformation->InterfaceNumber)
             {
         {
             if (PDODeviceExtension->InterfaceList[InterfaceIndex].Interface->InterfaceNumber == InterfaceInformation->InterfaceNumber)
             {
@@ -753,7 +786,6 @@ USBCCGP_PDOSelectConfiguration(
         NeedSelect = FALSE;
         if (Entry->InterfaceDescriptor->bAlternateSetting == InterfaceInformation->AlternateSetting)
         {
         NeedSelect = FALSE;
         if (Entry->InterfaceDescriptor->bAlternateSetting == InterfaceInformation->AlternateSetting)
         {
-            
             for(InterfaceIndex = 0; InterfaceIndex < InterfaceInformation->NumberOfPipes; InterfaceIndex++)
             {
                 if (InterfaceInformation->Pipes[InterfaceIndex].MaximumTransferSize != Entry->Interface->Pipes[InterfaceIndex].MaximumTransferSize)
             for(InterfaceIndex = 0; InterfaceIndex < InterfaceInformation->NumberOfPipes; InterfaceIndex++)
             {
                 if (InterfaceInformation->Pipes[InterfaceIndex].MaximumTransferSize != Entry->Interface->Pipes[InterfaceIndex].MaximumTransferSize)
@@ -778,7 +810,19 @@ USBCCGP_PDOSelectConfiguration(
             //
             // interface is already selected
             //
             //
             // interface is already selected
             //
-            RtlCopyMemory(InterfaceInformation, Entry->Interface, min(InterfaceInformation->Length, Entry->Interface->Length));
+            ASSERT(Length >= Entry->Interface->Length);
+            RtlCopyMemory(InterfaceInformation, Entry->Interface, Entry->Interface->Length);
+
+            //
+            // adjust remaining buffer size
+            //
+            ASSERT(Entry->Interface->Length);
+            Length -= Entry->Interface->Length;
+
+            //
+            // move to next output interface information
+            //
+            InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + Entry->Interface->Length);
         }
         else
         {
         }
         else
         {
@@ -803,7 +847,7 @@ USBCCGP_PDOSelectConfiguration(
             //
             // now prepare interface urb
             //
             //
             // now prepare interface urb
             //
-            UsbBuildSelectInterfaceRequest(NewUrb, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceInformation->NumberOfPipes), PDODeviceExtension->ConfigurationHandle, InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting);
+            UsbBuildSelectInterfaceRequest(NewUrb, (USHORT)GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceInformation->NumberOfPipes), PDODeviceExtension->ConfigurationHandle, InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting);
 
             //
             // now select the interface
 
             //
             // now select the interface
@@ -811,23 +855,37 @@ USBCCGP_PDOSelectConfiguration(
             Status = USBCCGP_SyncUrbRequest(PDODeviceExtension->NextDeviceObject, NewUrb);
             DPRINT1("SelectInterface Status %x\n", Status);
 
             Status = USBCCGP_SyncUrbRequest(PDODeviceExtension->NextDeviceObject, NewUrb);
             DPRINT1("SelectInterface Status %x\n", Status);
 
+            if (!NT_SUCCESS(Status))
+            {
+                 //
+                 // failed
+                 //
+                 break;
+            }
+
             //
             //
-            // did it succeeed
+            // update configuration info
             //
             //
-            if (NT_SUCCESS(Status))
-            {
-                //
-                // update configuration info
-                //
-                ASSERT(Entry->Interface->Length == NewUrb->UrbSelectInterface.Interface.Length);
-                ASSERT(InterfaceInformation->Length == NewUrb->UrbSelectInterface.Interface.Length);
-                RtlCopyMemory(Entry->Interface, &NewUrb->UrbSelectInterface.Interface, NewUrb->UrbSelectInterface.Interface.Length);
+            ASSERT(Entry->Interface->Length >= NewUrb->UrbSelectInterface.Interface.Length);
+            ASSERT(Length >= NewUrb->UrbSelectInterface.Interface.Length);
+            RtlCopyMemory(Entry->Interface, &NewUrb->UrbSelectInterface.Interface, NewUrb->UrbSelectInterface.Interface.Length);
 
 
-                //
-                // update provided interface information
-                //
-                RtlCopyMemory(InterfaceInformation, Entry->Interface, Entry->Interface->Length);
-            }
+            //
+            // update provided interface information
+            //
+            ASSERT(Length >= Entry->Interface->Length);
+            RtlCopyMemory(InterfaceInformation, Entry->Interface, Entry->Interface->Length);
+
+            //
+            // decrement remaining buffer size
+            //
+            ASSERT(Entry->Interface->Length);
+            Length -= Entry->Interface->Length;
+
+            //
+            // adjust output buffer offset
+            //
+            InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + Entry->Interface->Length);
 
             //
             // free urb
 
             //
             // free urb
@@ -835,12 +893,7 @@ USBCCGP_PDOSelectConfiguration(
             FreeItem(NewUrb);
         }
 
             FreeItem(NewUrb);
         }
 
-        //
-        // move to next information
-        //
-        InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + InterfaceInformation->Length);
-        Index++;
-    }while(Index < InterfaceInformationCount);
+    } while(Length);
 
     //
     // store configuration handle
 
     //
     // store configuration handle
@@ -857,7 +910,7 @@ USBCCGP_PDOSelectConfiguration(
 
 NTSTATUS
 PDO_HandleInternalDeviceControl(
 
 NTSTATUS
 PDO_HandleInternalDeviceControl(
-    PDEVICE_OBJECT DeviceObject, 
+    PDEVICE_OBJECT DeviceObject,
     PIRP Irp)
 {
     PIO_STACK_LOCATION IoStack;
     PIRP Irp)
 {
     PIO_STACK_LOCATION IoStack;
@@ -896,7 +949,7 @@ PDO_HandleInternalDeviceControl(
         }
         else if (Urb->UrbHeader.Function == URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE)
         {
         }
         else if (Urb->UrbHeader.Function == URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE)
         {
-            if(Urb->UrbControlDescriptorRequest.DescriptorType == USB_DEVICE_DESCRIPTOR_TYPE)
+            if (Urb->UrbControlDescriptorRequest.DescriptorType == USB_DEVICE_DESCRIPTOR_TYPE)
             {
                 //
                 // is the buffer big enough
             {
                 //
                 // is the buffer big enough
@@ -932,6 +985,40 @@ PDO_HandleInternalDeviceControl(
                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
                 return Status;
             }
                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
                 return Status;
             }
+            else if (Urb->UrbControlDescriptorRequest.DescriptorType == USB_STRING_DESCRIPTOR_TYPE)
+            {
+                PUSB_STRING_DESCRIPTOR StringDescriptor;
+
+                //
+                // get the requested string descriptor
+                //
+                ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
+                Status = USBCCGP_GetDescriptor(PDODeviceExtension->FDODeviceExtension->NextDeviceObject,
+                                               USB_STRING_DESCRIPTOR_TYPE,
+                                               Urb->UrbControlDescriptorRequest.TransferBufferLength,
+                                               Urb->UrbControlDescriptorRequest.Index,
+                                               Urb->UrbControlDescriptorRequest.LanguageId,
+                                               (PVOID*)&StringDescriptor);
+                if (NT_SUCCESS(Status))
+                {
+                    if (StringDescriptor->bLength == 2)
+                    {
+                        FreeItem(StringDescriptor);
+                        Status = STATUS_DEVICE_DATA_ERROR;
+                    }
+                    else
+                    {
+                        RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer,
+                                      StringDescriptor->bString,
+                                      StringDescriptor->bLength + sizeof(WCHAR));
+                        FreeItem(StringDescriptor);
+                        Status = STATUS_SUCCESS;
+                    }
+                }
+                Irp->IoStatus.Status = Status;
+                IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                return Status;
+            }
         }
         else
         {
         }
         else
         {
@@ -959,8 +1046,6 @@ PDO_HandleInternalDeviceControl(
         return Status;
     }
 
         return Status;
     }
 
-
-
     DPRINT1("IOCTL %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
     DPRINT1("InputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.InputBufferLength);
     DPRINT1("OutputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength);
     DPRINT1("IOCTL %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
     DPRINT1("InputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.InputBufferLength);
     DPRINT1("OutputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength);
@@ -976,7 +1061,7 @@ PDO_HandleInternalDeviceControl(
 
 NTSTATUS
 PDO_Dispatch(
 
 NTSTATUS
 PDO_Dispatch(
-    PDEVICE_OBJECT DeviceObject, 
+    PDEVICE_OBJECT DeviceObject,
     PIRP Irp)
 {
     PIO_STACK_LOCATION IoStack;
     PIRP Irp)
 {
     PIO_STACK_LOCATION IoStack;
@@ -997,5 +1082,4 @@ PDO_Dispatch(
             IoCompleteRequest(Irp, IO_NO_INCREMENT);
             return Status;
     }
             IoCompleteRequest(Irp, IO_NO_INCREMENT);
             return Status;
     }
-
 }
 }