[USBCCGP] Allow unconfiguring the device in USBCCGP_PDOSelectConfiguration.
[reactos.git] / drivers / usb / usbccgp / pdo.c
index a78f7ce..bcd0acb 100644 (file)
 
 #include "usbccgp.h"
 
+#include <ntddk.h>
+
+#define NDEBUG
+#include <debug.h>
+
 NTSTATUS
 USBCCGP_PdoHandleQueryDeviceText(
     IN PDEVICE_OBJECT DeviceObject,
@@ -52,7 +57,7 @@ USBCCGP_PdoHandleQueryDeviceText(
     //
     // FIXME use GenericCompositeUSBDeviceString
     //
-    UNIMPLEMENTED
+    UNIMPLEMENTED;
     Buffer = AllocateItem(PagedPool, (wcslen(GenericString) + 1) * sizeof(WCHAR));
     if (!Buffer)
     {
@@ -75,7 +80,7 @@ USBCCGP_PdoHandleDeviceRelations(
     PDEVICE_RELATIONS DeviceRelations;
     PIO_STACK_LOCATION IoStack;
 
-    DPRINT1("USBCCGP_PdoHandleDeviceRelations\n");
+    DPRINT("USBCCGP_PdoHandleDeviceRelations\n");
 
     //
     // get current irp stack location
@@ -136,7 +141,7 @@ USBCCGP_PdoAppendInterfaceNumber(
     // count length of string
     //
     String = DeviceId;
-    while(*String)
+    while (*String)
     {
         StringLength = wcslen(String) + 1;
         Length += StringLength;
@@ -161,11 +166,11 @@ USBCCGP_PdoAppendInterfaceNumber(
     //
     *OutString = String;
 
-    while(*DeviceId)
+    while (*DeviceId)
     {
-        StringLength = swprintf(String, L"%s&MI_%02x", DeviceId) + 1;
+        StringLength = swprintf(String, L"%s&MI_%02x", DeviceId, InterfaceNumber) + 1;
         Length = wcslen(DeviceId) + 1;
-        DPRINT1("String %p\n", String);
+        DPRINT("String %p\n", String);
 
         //
         // next string
@@ -222,10 +227,10 @@ USBCCGP_PdoHandleQueryId(
                 //
                 ASSERT(Irp->IoStatus.Information);
                 swprintf(Buffer, L"%s&MI_%02x", (LPWSTR)Irp->IoStatus.Information, PDODeviceExtension->FunctionDescriptor->FunctionNumber);
-                DPRINT1("BusQueryDeviceID %S\n", Buffer);
+                DPRINT("BusQueryDeviceID %S\n", Buffer);
 
                 ExFreePool((PVOID)Irp->IoStatus.Information);
-                Irp->IoStatus .Information = (ULONG_PTR)Buffer;
+                Irp->IoStatus.Information = (ULONG_PTR)Buffer;
             }
             else
             {
@@ -272,6 +277,13 @@ USBCCGP_PdoHandleQueryId(
         //
         DeviceString = &PDODeviceExtension->FunctionDescriptor->CompatibleId;
     }
+    else
+    {
+        //
+        // unsupported query
+        //
+        return Irp->IoStatus.Status;
+    }
 
     //
     // sanity check
@@ -294,6 +306,7 @@ USBCCGP_PdoHandleQueryId(
     // copy buffer
     //
     RtlCopyMemory(Buffer, DeviceString->Buffer, DeviceString->Length);
+    Buffer[DeviceString->Length / sizeof(WCHAR)] = UNICODE_NULL;
     Irp->IoStatus.Information = (ULONG_PTR)Buffer;
 
     return STATUS_SUCCESS;
@@ -307,7 +320,7 @@ PDO_HandlePnp(
     PIO_STACK_LOCATION IoStack;
     PPDO_DEVICE_EXTENSION PDODeviceExtension;
     NTSTATUS Status;
-    ULONG Index;
+    ULONG Index, bFound;
 
     //
     // get current stack location
@@ -326,71 +339,76 @@ PDO_HandlePnp(
 
     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
-           //
-           for(Index = 0; Index < PDODeviceExtension->FDODeviceExtension->FunctionDescriptorCount; Index++)
-           {
-               if (PDODeviceExtension->FDODeviceExtension->ChildPDO[Index] == DeviceObject)
-               {
-                   //
-                   // remove us
-                   //
-                   PDODeviceExtension->FDODeviceExtension->ChildPDO[Index] = NULL;
-                   break;
-               }
-           }
-
-           //
-           // Complete the IRP
-           //
-           Irp->IoStatus.Status = STATUS_SUCCESS;
-           IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
-           //
-           // 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:
         {
@@ -400,16 +418,24 @@ PDO_HandlePnp(
             Status = STATUS_SUCCESS;
             break;
         }
-       case IRP_MN_START_DEVICE:
-       {
-           //
-           // no-op for PDO
-           //
-           DPRINT1("[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
@@ -444,7 +470,7 @@ PDO_HandlePnp(
 
 NTSTATUS
 USBCCGP_BuildConfigurationDescriptor(
-    PDEVICE_OBJECT DeviceObject, 
+    PDEVICE_OBJECT DeviceObject,
     PIRP Irp)
 {
     PIO_STACK_LOCATION IoStack;
@@ -452,16 +478,18 @@ USBCCGP_BuildConfigurationDescriptor(
     PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
     PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
     ULONG TotalSize, Index;
+    ULONG Size;
     PURB Urb;
     PVOID Buffer;
     PUCHAR BufferPtr;
+    UCHAR InterfaceNumber;
 
     //
     // get current stack location
     //
     IoStack = IoGetCurrentIrpStackLocation(Irp);
 
-    DPRINT1("USBCCGP_BuildConfigurationDescriptor\n");
+    DPRINT("USBCCGP_BuildConfigurationDescriptor\n");
 
     //
     // get device extension
@@ -478,12 +506,13 @@ USBCCGP_BuildConfigurationDescriptor(
     //
     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];
+        InterfaceNumber = InterfaceDescriptor->bInterfaceNumber;
 
         //
         // add to size and move to next descriptor
@@ -508,10 +537,17 @@ USBCCGP_BuildConfigurationDescriptor(
             {
                 if (InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
                 {
+                    if (InterfaceNumber != InterfaceDescriptor->bInterfaceNumber)
+                    {
+                        //
+                        // reached next descriptor
+                        //
+                        break;
+                    }
+
                     //
-                    // reached next descriptor
+                    // include alternate descriptor
                     //
-                    break;
                 }
 
                 //
@@ -524,7 +560,7 @@ USBCCGP_BuildConfigurationDescriptor(
             // move to next descriptor
             //
             InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
-        }while(TRUE);
+        } while(TRUE);
     }
 
     //
@@ -546,12 +582,13 @@ USBCCGP_BuildConfigurationDescriptor(
     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];
+        InterfaceNumber = InterfaceDescriptor->bInterfaceNumber;
 
         //
         // copy descriptor and move to next descriptor
@@ -577,10 +614,18 @@ USBCCGP_BuildConfigurationDescriptor(
             {
                 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);
                 }
 
                 //
@@ -594,14 +639,14 @@ USBCCGP_BuildConfigurationDescriptor(
             // move to next descriptor
             //
             InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
-        }while(TRUE);
+        } while(TRUE);
     }
 
     //
     // modify configuration descriptor
     //
     ConfigurationDescriptor = Buffer;
-    ConfigurationDescriptor->wTotalLength = TotalSize;
+    ConfigurationDescriptor->wTotalLength = (USHORT)TotalSize;
     ConfigurationDescriptor->bNumInterfaces = PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces;
 
     //
@@ -613,12 +658,13 @@ USBCCGP_BuildConfigurationDescriptor(
     //
     // 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
     //
-    Urb->UrbControlDescriptorRequest.TransferBufferLength = TotalSize;
+    Urb->UrbControlDescriptorRequest.TransferBufferLength = Size;
 
     //
     // free buffer
@@ -633,14 +679,14 @@ USBCCGP_BuildConfigurationDescriptor(
 
 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;
-    ULONG InterfaceInformationCount, Index, InterfaceIndex;
+    ULONG InterfaceIndex, Length;
     PUSBD_INTERFACE_LIST_ENTRY Entry;
     ULONG NeedSelect, FoundInterface;
     NTSTATUS Status;
@@ -673,32 +719,37 @@ USBCCGP_PDOSelectConfiguration(
     }
 
     //
-    // count interface information
+    // if there is no configuration descriptor, unconfigure the device
     //
-    InterfaceInformationCount = 0;
-    InterfaceInformation = &Urb->UrbSelectConfiguration.Interface;
-    do
+    if (Urb->UrbSelectConfiguration.ConfigurationDescriptor == NULL)
     {
-        InterfaceInformationCount++;
-        InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + InterfaceInformation->Length);
-    }while((ULONG_PTR)InterfaceInformation < (ULONG_PTR)Urb + Urb->UrbSelectConfiguration.Hdr.Length);
+        return STATUS_SUCCESS;
+    }
+
+    // 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;
-    Index = 0;
+
     Entry = NULL;
-    DPRINT1("Count %x\n", InterfaceInformationCount);
     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;
-        for(InterfaceIndex = 0; InterfaceIndex < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; InterfaceIndex++)
+        for (InterfaceIndex = 0; InterfaceIndex < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; InterfaceIndex++)
         {
             if (PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[InterfaceIndex]->bInterfaceNumber == InterfaceInformation->InterfaceNumber)
             {
@@ -714,7 +765,6 @@ USBCCGP_PDOSelectConfiguration(
             // invalid parameter
             //
             DPRINT1("InterfaceInformation InterfaceNumber %x Alternative %x NumberOfPipes %x not found\n", InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting, InterfaceInformation->NumberOfPipes);
-            ASSERT(FALSE);
             return STATUS_INVALID_PARAMETER;
         }
 
@@ -722,7 +772,7 @@ USBCCGP_PDOSelectConfiguration(
         // 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)
             {
@@ -748,7 +798,6 @@ USBCCGP_PDOSelectConfiguration(
         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)
@@ -773,7 +822,19 @@ USBCCGP_PDOSelectConfiguration(
             //
             // 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
         {
@@ -798,7 +859,7 @@ USBCCGP_PDOSelectConfiguration(
             //
             // 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
@@ -806,23 +867,37 @@ USBCCGP_PDOSelectConfiguration(
             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
@@ -830,12 +905,7 @@ USBCCGP_PDOSelectConfiguration(
             FreeItem(NewUrb);
         }
 
-        //
-        // move to next information
-        //
-        InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + InterfaceInformation->Length);
-        Index++;
-    }while(Index < InterfaceInformationCount);
+    } while(Length);
 
     //
     // store configuration handle
@@ -852,7 +922,7 @@ USBCCGP_PDOSelectConfiguration(
 
 NTSTATUS
 PDO_HandleInternalDeviceControl(
-    PDEVICE_OBJECT DeviceObject, 
+    PDEVICE_OBJECT DeviceObject,
     PIRP Irp)
 {
     PIO_STACK_LOCATION IoStack;
@@ -891,7 +961,7 @@ PDO_HandleInternalDeviceControl(
         }
         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
@@ -927,6 +997,40 @@ PDO_HandleInternalDeviceControl(
                 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
         {
@@ -954,8 +1058,6 @@ PDO_HandleInternalDeviceControl(
         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);
@@ -971,7 +1073,7 @@ PDO_HandleInternalDeviceControl(
 
 NTSTATUS
 PDO_Dispatch(
-    PDEVICE_OBJECT DeviceObject, 
+    PDEVICE_OBJECT DeviceObject,
     PIRP Irp)
 {
     PIO_STACK_LOCATION IoStack;
@@ -986,12 +1088,15 @@ PDO_Dispatch(
             return PDO_HandlePnp(DeviceObject, Irp);
         case IRP_MJ_INTERNAL_DEVICE_CONTROL:
             return PDO_HandleInternalDeviceControl(DeviceObject, Irp);
+        case IRP_MJ_POWER:
+            PoStartNextPowerIrp(Irp);
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+            return STATUS_SUCCESS;
         default:
             DPRINT1("PDO_Dispatch Function %x not implemented\n", IoStack->MajorFunction);
-            ASSERT(FALSE);
             Status = Irp->IoStatus.Status;
             IoCompleteRequest(Irp, IO_NO_INCREMENT);
             return Status;
     }
-
 }