xref: /reactos/drivers/usb/usbccgp/pdo.c (revision 11345aed)
1 /*
2  * PROJECT:     ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        drivers/usb/usbccgp/pdo.c
5  * PURPOSE:     USB  device driver.
6  * PROGRAMMERS:
7  *              Michael Martin (michael.martin@reactos.org)
8  *              Johannes Anderwald (johannes.anderwald@reactos.org)
9  *              Cameron Gutman
10  */
11 
12 #include "usbccgp.h"
13 
14 #include <ntddk.h>
15 
16 #define NDEBUG
17 #include <debug.h>
18 
19 NTSTATUS
20 USBCCGP_PdoHandleQueryDeviceText(
21     IN PDEVICE_OBJECT DeviceObject,
22     IN OUT PIRP Irp)
23 {
24     PIO_STACK_LOCATION IoStack;
25     LPWSTR Buffer;
26     PPDO_DEVICE_EXTENSION PDODeviceExtension;
27     LPWSTR GenericString = L"Composite USB Device";
28 
29     //
30     // get current irp stack location
31     //
32     IoStack = IoGetCurrentIrpStackLocation(Irp);
33 
34     //
35     // get device extension
36     //
37     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
38 
39     //
40     // check if type is description
41     //
42     if (IoStack->Parameters.QueryDeviceText.DeviceTextType != DeviceTextDescription)
43     {
44         //
45         // we only handle description
46         //
47         return Irp->IoStatus.Status;
48     }
49 
50     //
51     // is there a device description
52     //
53     if (PDODeviceExtension->FunctionDescriptor->FunctionDescription.Length)
54     {
55         //
56         // allocate buffer
57         //
58         Buffer = AllocateItem(NonPagedPool, PDODeviceExtension->FunctionDescriptor->FunctionDescription.Length + sizeof(WCHAR));
59         if (!Buffer)
60         {
61             //
62             // no memory
63             //
64             return STATUS_INSUFFICIENT_RESOURCES;
65         }
66 
67         //
68         // copy buffer
69         //
70         Irp->IoStatus.Information = (ULONG_PTR)Buffer;
71         RtlCopyMemory(Buffer, PDODeviceExtension->FunctionDescriptor->FunctionDescription.Buffer, PDODeviceExtension->FunctionDescriptor->FunctionDescription.Length);
72         return STATUS_SUCCESS;
73     }
74 
75     //
76     // FIXME use GenericCompositeUSBDeviceString
77     //
78     UNIMPLEMENTED;
79     Buffer = AllocateItem(PagedPool, (wcslen(GenericString) + 1) * sizeof(WCHAR));
80     if (!Buffer)
81     {
82         //
83         // no memory
84         //
85         return STATUS_INSUFFICIENT_RESOURCES;
86     }
87     RtlCopyMemory(Buffer, GenericString, (wcslen(GenericString) + 1) * sizeof(WCHAR));
88     Irp->IoStatus.Information = (ULONG_PTR)Buffer;
89 
90     return STATUS_SUCCESS;
91 }
92 
93 NTSTATUS
94 USBCCGP_PdoHandleDeviceRelations(
95     IN PDEVICE_OBJECT DeviceObject,
96     IN OUT PIRP Irp)
97 {
98     PDEVICE_RELATIONS DeviceRelations;
99     PIO_STACK_LOCATION IoStack;
100 
101     DPRINT("USBCCGP_PdoHandleDeviceRelations\n");
102 
103     //
104     // get current irp stack location
105     //
106     IoStack = IoGetCurrentIrpStackLocation(Irp);
107 
108     //
109     // check if relation type is BusRelations
110     //
111     if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
112     {
113         //
114         // PDO handles only target device relation
115         //
116         return Irp->IoStatus.Status;
117     }
118 
119     //
120     // allocate device relations
121     //
122     DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS));
123     if (!DeviceRelations)
124     {
125         //
126         // no memory
127         //
128         return STATUS_INSUFFICIENT_RESOURCES;
129     }
130 
131     //
132     // initialize device relations
133     //
134     DeviceRelations->Count = 1;
135     DeviceRelations->Objects[0] = DeviceObject;
136     ObReferenceObject(DeviceObject);
137 
138     //
139     // store result
140     //
141     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
142 
143     //
144     // completed successfully
145     //
146     return STATUS_SUCCESS;
147 }
148 
149 NTSTATUS
150 USBCCGP_PdoAppendInterfaceNumber(
151     IN LPWSTR DeviceId,
152     IN ULONG InterfaceNumber,
153     OUT LPWSTR *OutString)
154 {
155     ULONG Length = 0, StringLength;
156     LPWSTR String;
157 
158     //
159     // count length of string
160     //
161     String = DeviceId;
162     while (*String)
163     {
164         StringLength = wcslen(String) + 1;
165         Length += StringLength;
166         Length += 6; //&MI_XX
167         String += StringLength;
168     }
169 
170     //
171     // now allocate the buffer
172     //
173     String = AllocateItem(NonPagedPool, (Length + 2) * sizeof(WCHAR));
174     if (!String)
175     {
176         //
177         // no memory
178         //
179         return STATUS_INSUFFICIENT_RESOURCES;
180     }
181 
182     //
183     // store result
184     //
185     *OutString = String;
186 
187     while (*DeviceId)
188     {
189         StringLength = swprintf(String, L"%s&MI_%02x", DeviceId, InterfaceNumber) + 1;
190         Length = wcslen(DeviceId) + 1;
191         DPRINT("String %p\n", String);
192 
193         //
194         // next string
195         //
196         String += StringLength;
197         DeviceId += Length;
198     }
199 
200     //
201     // success
202     //
203     return STATUS_SUCCESS;
204 }
205 
206 
207 NTSTATUS
208 USBCCGP_PdoHandleQueryId(
209     PDEVICE_OBJECT DeviceObject,
210     PIRP Irp)
211 {
212     PIO_STACK_LOCATION IoStack;
213     PUNICODE_STRING DeviceString = NULL;
214     PPDO_DEVICE_EXTENSION PDODeviceExtension;
215     NTSTATUS Status;
216     LPWSTR Buffer;
217 
218     //
219     // get current irp stack location
220     //
221     IoStack = IoGetCurrentIrpStackLocation(Irp);
222 
223     //
224     // get device extension
225     //
226     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
227 
228 
229     if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID)
230     {
231         //
232         // handle query device id
233         //
234         Status = USBCCGP_SyncForwardIrp(PDODeviceExtension->NextDeviceObject, Irp);
235         if (NT_SUCCESS(Status))
236         {
237             //
238             // allocate buffer
239             //
240             Buffer = AllocateItem(NonPagedPool, (wcslen((LPWSTR)Irp->IoStatus.Information) + 7) * sizeof(WCHAR));
241             if (Buffer)
242             {
243                 //
244                 // append interface number
245                 //
246                 ASSERT(Irp->IoStatus.Information);
247                 swprintf(Buffer, L"%s&MI_%02x", (LPWSTR)Irp->IoStatus.Information, PDODeviceExtension->FunctionDescriptor->FunctionNumber);
248                 DPRINT("BusQueryDeviceID %S\n", Buffer);
249 
250                 ExFreePool((PVOID)Irp->IoStatus.Information);
251                 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
252             }
253             else
254             {
255                 //
256                 // no memory
257                 //
258                 Status = STATUS_INSUFFICIENT_RESOURCES;
259             }
260         }
261         return Status;
262     }
263     else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
264     {
265         //
266         // handle instance id
267         //
268         DeviceString = &PDODeviceExtension->FunctionDescriptor->HardwareId;
269     }
270     else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
271     {
272         //
273         // handle instance id
274         //
275         Buffer = AllocateItem(NonPagedPool, 5 * sizeof(WCHAR));
276         if (!Buffer)
277         {
278             //
279             // no memory
280             //
281             return STATUS_INSUFFICIENT_RESOURCES;
282         }
283 
284         //
285         // use function number
286         //
287         swprintf(Buffer, L"%04x", PDODeviceExtension->FunctionDescriptor->FunctionNumber);
288         Irp->IoStatus.Information = (ULONG_PTR)Buffer;
289         return STATUS_SUCCESS;
290     }
291     else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
292     {
293         //
294         // handle instance id
295         //
296         DeviceString = &PDODeviceExtension->FunctionDescriptor->CompatibleId;
297     }
298     else
299     {
300         //
301         // unsupported query
302         //
303         return Irp->IoStatus.Status;
304     }
305 
306     //
307     // sanity check
308     //
309     ASSERT(DeviceString != NULL);
310 
311     //
312     // allocate buffer
313     //
314     Buffer = AllocateItem(NonPagedPool, DeviceString->Length + sizeof(WCHAR));
315     if (!Buffer)
316     {
317         //
318         // no memory
319         //
320         return STATUS_INSUFFICIENT_RESOURCES;
321     }
322 
323     //
324     // copy buffer
325     //
326     RtlCopyMemory(Buffer, DeviceString->Buffer, DeviceString->Length);
327     Buffer[DeviceString->Length / sizeof(WCHAR)] = UNICODE_NULL;
328     Irp->IoStatus.Information = (ULONG_PTR)Buffer;
329 
330     return STATUS_SUCCESS;
331 }
332 
333 NTSTATUS
334 PDO_HandlePnp(
335     PDEVICE_OBJECT DeviceObject,
336     PIRP Irp)
337 {
338     PIO_STACK_LOCATION IoStack;
339     PPDO_DEVICE_EXTENSION PDODeviceExtension;
340     NTSTATUS Status;
341     ULONG Index, bFound;
342 
343     //
344     // get current stack location
345     //
346     IoStack = IoGetCurrentIrpStackLocation(Irp);
347 
348     //
349     // get device extension
350     //
351     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
352 
353     //
354     // sanity check
355     //
356     ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
357 
358     switch(IoStack->MinorFunction)
359     {
360         case IRP_MN_QUERY_DEVICE_RELATIONS:
361         {
362             //
363             // handle device relations
364             //
365             Status = USBCCGP_PdoHandleDeviceRelations(DeviceObject, Irp);
366             break;
367         }
368         case IRP_MN_QUERY_DEVICE_TEXT:
369         {
370             //
371             // handle query device text
372             //
373             Status = USBCCGP_PdoHandleQueryDeviceText(DeviceObject, Irp);
374             break;
375         }
376         case IRP_MN_QUERY_ID:
377         {
378             //
379             // handle request
380             //
381             Status = USBCCGP_PdoHandleQueryId(DeviceObject, Irp);
382             break;
383         }
384         case IRP_MN_REMOVE_DEVICE:
385         {
386             //
387             // remove us from the fdo's pdo list
388             //
389             bFound = FALSE;
390             for(Index = 0; Index < PDODeviceExtension->FDODeviceExtension->FunctionDescriptorCount; Index++)
391             {
392                 if (PDODeviceExtension->FDODeviceExtension->ChildPDO[Index] == DeviceObject)
393                 {
394                     //
395                     // remove us
396                     //
397                     PDODeviceExtension->FDODeviceExtension->ChildPDO[Index] = NULL;
398                     bFound = TRUE;
399                     break;
400                 }
401             }
402 
403             //
404             // Complete the IRP
405             //
406             Irp->IoStatus.Status = STATUS_SUCCESS;
407             IoCompleteRequest(Irp, IO_NO_INCREMENT);
408 
409             if (bFound)
410             {
411                 //
412                 // Delete the device object
413                 //
414                 IoDeleteDevice(DeviceObject);
415             }
416             return STATUS_SUCCESS;
417         }
418         case IRP_MN_QUERY_CAPABILITIES:
419         {
420             //
421             // copy device capabilities
422             //
423             RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, &PDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
424 
425             /* Complete the IRP */
426             Irp->IoStatus.Status = STATUS_SUCCESS;
427             IoCompleteRequest(Irp, IO_NO_INCREMENT);
428             return STATUS_SUCCESS;
429         }
430         case IRP_MN_QUERY_REMOVE_DEVICE:
431         case IRP_MN_QUERY_STOP_DEVICE:
432         {
433             //
434             // sure
435             //
436             Status = STATUS_SUCCESS;
437             break;
438         }
439         case IRP_MN_START_DEVICE:
440         {
441             //
442             // no-op for PDO
443             //
444             DPRINT("[USBCCGP] PDO IRP_MN_START\n");
445             Status = STATUS_SUCCESS;
446             break;
447         }
448         case IRP_MN_QUERY_INTERFACE:
449         {
450             //
451             // forward to lower device object
452             //
453             IoSkipCurrentIrpStackLocation(Irp);
454             return IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
455         }
456         default:
457         {
458             //
459             // do nothing
460             //
461             Status = Irp->IoStatus.Status;
462             break;
463         }
464     }
465 
466     //
467     // complete request
468     //
469     if (Status != STATUS_PENDING)
470     {
471         //
472         // store result
473         //
474         Irp->IoStatus.Status = Status;
475 
476         //
477         // complete request
478         //
479         IoCompleteRequest(Irp, IO_NO_INCREMENT);
480     }
481 
482     //
483     // done processing
484     //
485     return Status;
486 
487 }
488 
489 NTSTATUS
490 USBCCGP_BuildConfigurationDescriptor(
491     PDEVICE_OBJECT DeviceObject,
492     PIRP Irp)
493 {
494     PIO_STACK_LOCATION IoStack;
495     PPDO_DEVICE_EXTENSION PDODeviceExtension;
496     PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
497     PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
498     ULONG TotalSize, Index;
499     ULONG Size;
500     PURB Urb;
501     PVOID Buffer;
502     PUCHAR BufferPtr;
503     UCHAR InterfaceNumber;
504 
505     //
506     // get current stack location
507     //
508     IoStack = IoGetCurrentIrpStackLocation(Irp);
509 
510     DPRINT("USBCCGP_BuildConfigurationDescriptor\n");
511 
512     //
513     // get device extension
514     //
515     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
516 
517     //
518     // get configuration descriptor
519     //
520     ConfigurationDescriptor = PDODeviceExtension->ConfigurationDescriptor;
521 
522     //
523     // calculate size of configuration descriptor
524     //
525     TotalSize = sizeof(USB_CONFIGURATION_DESCRIPTOR);
526 
527     for (Index = 0; Index < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; Index++)
528     {
529         //
530         // get current interface descriptor
531         //
532         InterfaceDescriptor = PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[Index];
533         InterfaceNumber = InterfaceDescriptor->bInterfaceNumber;
534 
535         //
536         // add to size and move to next descriptor
537         //
538         TotalSize += InterfaceDescriptor->bLength;
539         InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
540 
541         do
542         {
543             if ((ULONG_PTR)InterfaceDescriptor >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
544             {
545                 //
546                 // reached end of configuration descriptor
547                 //
548                 break;
549             }
550 
551             //
552             // association descriptors are removed
553             //
554             if (InterfaceDescriptor->bDescriptorType != USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE)
555             {
556                 if (InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
557                 {
558                     if (InterfaceNumber != InterfaceDescriptor->bInterfaceNumber)
559                     {
560                         //
561                         // reached next descriptor
562                         //
563                         break;
564                     }
565 
566                     //
567                     // include alternate descriptor
568                     //
569                 }
570 
571                 //
572                 // append size
573                 //
574                 TotalSize += InterfaceDescriptor->bLength;
575             }
576 
577             //
578             // move to next descriptor
579             //
580             InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
581         } while(TRUE);
582     }
583 
584     //
585     // now allocate temporary buffer for the configuration descriptor
586     //
587     Buffer = AllocateItem(NonPagedPool, TotalSize);
588     if (!Buffer)
589     {
590         //
591         // failed to allocate buffer
592         //
593         DPRINT1("[USBCCGP] Failed to allocate %lu Bytes\n", TotalSize);
594         return STATUS_INSUFFICIENT_RESOURCES;
595     }
596 
597     //
598     // first copy the configuration descriptor
599     //
600     RtlCopyMemory(Buffer, ConfigurationDescriptor, sizeof(USB_CONFIGURATION_DESCRIPTOR));
601     BufferPtr = (PUCHAR)((ULONG_PTR)Buffer + ConfigurationDescriptor->bLength);
602 
603     for (Index = 0; Index < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; Index++)
604     {
605         //
606         // get current interface descriptor
607         //
608         InterfaceDescriptor = PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[Index];
609         InterfaceNumber = InterfaceDescriptor->bInterfaceNumber;
610 
611         //
612         // copy descriptor and move to next descriptor
613         //
614         RtlCopyMemory(BufferPtr, InterfaceDescriptor, InterfaceDescriptor->bLength);
615         BufferPtr += InterfaceDescriptor->bLength;
616         InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
617 
618         do
619         {
620             if ((ULONG_PTR)InterfaceDescriptor >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
621             {
622                 //
623                 // reached end of configuration descriptor
624                 //
625                 break;
626             }
627 
628             //
629             // association descriptors are removed
630             //
631             if (InterfaceDescriptor->bDescriptorType != USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE)
632             {
633                 if (InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
634                 {
635                     if (InterfaceNumber != InterfaceDescriptor->bInterfaceNumber)
636                     {
637                         //
638                         // reached next descriptor
639                         //
640                         break;
641                     }
642 
643                     //
644                     // include alternate descriptor
645                     //
646                     DPRINT("InterfaceDescriptor %p Alternate %x InterfaceNumber %x\n", InterfaceDescriptor, InterfaceDescriptor->bAlternateSetting, InterfaceDescriptor->bInterfaceNumber);
647                 }
648 
649                 //
650                 // copy descriptor
651                 //
652                 RtlCopyMemory(BufferPtr, InterfaceDescriptor, InterfaceDescriptor->bLength);
653                 BufferPtr += InterfaceDescriptor->bLength;
654             }
655 
656             //
657             // move to next descriptor
658             //
659             InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
660         } while(TRUE);
661     }
662 
663     //
664     // modify configuration descriptor
665     //
666     ConfigurationDescriptor = Buffer;
667     ConfigurationDescriptor->wTotalLength = (USHORT)TotalSize;
668     ConfigurationDescriptor->bNumInterfaces = PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces;
669 
670     //
671     // get urb
672     //
673     Urb = (PURB)IoStack->Parameters.Others.Argument1;
674     ASSERT(Urb);
675 
676     //
677     // copy descriptor
678     //
679     Size = min(TotalSize, Urb->UrbControlDescriptorRequest.TransferBufferLength);
680     RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer, Buffer, Size);
681 
682     //
683     // store final size
684     //
685     Urb->UrbControlDescriptorRequest.TransferBufferLength = Size;
686 
687     //
688     // free buffer
689     //
690     FreeItem(Buffer);
691 
692     //
693     // done
694     //
695     return STATUS_SUCCESS;
696 }
697 
698 NTSTATUS
699 USBCCGP_PDOSelectConfiguration(
700     PDEVICE_OBJECT DeviceObject,
701     PIRP Irp)
702 {
703     PIO_STACK_LOCATION IoStack;
704     PPDO_DEVICE_EXTENSION PDODeviceExtension;
705     PURB Urb, NewUrb;
706     PUSBD_INTERFACE_INFORMATION InterfaceInformation;
707     ULONG InterfaceIndex, Length;
708     PUSBD_INTERFACE_LIST_ENTRY Entry;
709     ULONG NeedSelect, FoundInterface;
710     NTSTATUS Status;
711 
712     //
713     // get current stack location
714     //
715     IoStack = IoGetCurrentIrpStackLocation(Irp);
716 
717     //
718     // get device extension
719     //
720     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
721 
722     //
723     // get urb
724     //
725     Urb = (PURB)IoStack->Parameters.Others.Argument1;
726     ASSERT(Urb);
727 
728     //
729     // is there already an configuration handle
730     //
731     if (Urb->UrbSelectConfiguration.ConfigurationHandle)
732     {
733         //
734         // nothing to do
735         //
736         return STATUS_SUCCESS;
737     }
738 
739     //
740     // if there is no configuration descriptor, unconfigure the device
741     //
742     if (Urb->UrbSelectConfiguration.ConfigurationDescriptor == NULL)
743     {
744         return STATUS_SUCCESS;
745     }
746 
747     // sanity checks
748     //C_ASSERT(sizeof(struct _URB_HEADER) == 16);
749     //C_ASSERT(FIELD_OFFSET(struct _URB_SELECT_CONFIGURATION, Interface.Length) == 24);
750     //C_ASSERT(sizeof(USBD_INTERFACE_INFORMATION) == 36);
751     //C_ASSERT(sizeof(struct _URB_SELECT_CONFIGURATION) == 0x3C);
752 
753     // available buffer length
754     Length = Urb->UrbSelectConfiguration.Hdr.Length - FIELD_OFFSET(struct _URB_SELECT_CONFIGURATION, Interface.Length);
755 
756     //
757     // check all interfaces
758     //
759     InterfaceInformation = &Urb->UrbSelectConfiguration.Interface;
760 
761     Entry = NULL;
762     do
763     {
764         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);
765         ASSERT(InterfaceInformation->Length);
766         //
767         // search for the interface in the local interface list
768         //
769         FoundInterface = FALSE;
770         for (InterfaceIndex = 0; InterfaceIndex < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; InterfaceIndex++)
771         {
772             if (PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[InterfaceIndex]->bInterfaceNumber == InterfaceInformation->InterfaceNumber)
773             {
774                 // found interface entry
775                 FoundInterface = TRUE;
776                 break;
777             }
778         }
779 
780         if (!FoundInterface)
781         {
782             //
783             // invalid parameter
784             //
785             DPRINT1("InterfaceInformation InterfaceNumber %x Alternative %x NumberOfPipes %x not found\n", InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting, InterfaceInformation->NumberOfPipes);
786             return STATUS_INVALID_PARAMETER;
787         }
788 
789         //
790         // now query the total interface list
791         //
792         Entry = NULL;
793         for (InterfaceIndex = 0; InterfaceIndex < PDODeviceExtension->InterfaceListCount; InterfaceIndex++)
794         {
795             if (PDODeviceExtension->InterfaceList[InterfaceIndex].Interface->InterfaceNumber == InterfaceInformation->InterfaceNumber)
796             {
797                 //
798                 // found entry
799                 //
800                 Entry = &PDODeviceExtension->InterfaceList[InterfaceIndex];
801             }
802         }
803 
804         //
805         // sanity check
806         //
807         ASSERT(Entry);
808         if (!Entry)
809         {
810             //
811             // corruption detected
812             //
813             KeBugCheck(0);
814         }
815 
816         NeedSelect = FALSE;
817         if (Entry->InterfaceDescriptor->bAlternateSetting == InterfaceInformation->AlternateSetting)
818         {
819             for(InterfaceIndex = 0; InterfaceIndex < InterfaceInformation->NumberOfPipes; InterfaceIndex++)
820             {
821                 if (InterfaceInformation->Pipes[InterfaceIndex].MaximumTransferSize != Entry->Interface->Pipes[InterfaceIndex].MaximumTransferSize)
822                 {
823                     //
824                     // changed interface
825                     //
826                     NeedSelect = TRUE;
827                 }
828             }
829         }
830         else
831         {
832             //
833             // need select as the interface number differ
834             //
835             NeedSelect = TRUE;
836         }
837 
838         if (!NeedSelect)
839         {
840             //
841             // interface is already selected
842             //
843             ASSERT(Length >= Entry->Interface->Length);
844             RtlCopyMemory(InterfaceInformation, Entry->Interface, Entry->Interface->Length);
845 
846             //
847             // adjust remaining buffer size
848             //
849             ASSERT(Entry->Interface->Length);
850             Length -= Entry->Interface->Length;
851 
852             //
853             // move to next output interface information
854             //
855             InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + Entry->Interface->Length);
856         }
857         else
858         {
859             //
860             // select interface
861             //
862             DPRINT1("Selecting InterfaceIndex %lu AlternateSetting %lu NumberOfPipes %lu\n", InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting, InterfaceInformation->NumberOfPipes);
863             ASSERT(InterfaceInformation->Length == Entry->Interface->Length);
864 
865             //
866             // build urb
867             //
868             NewUrb = AllocateItem(NonPagedPool, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceInformation->NumberOfPipes));
869             if (!NewUrb)
870             {
871                 //
872                 // no memory
873                 //
874                 return STATUS_INSUFFICIENT_RESOURCES;
875             }
876 
877             //
878             // now prepare interface urb
879             //
880             UsbBuildSelectInterfaceRequest(NewUrb, (USHORT)GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceInformation->NumberOfPipes), PDODeviceExtension->ConfigurationHandle, InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting);
881 
882             //
883             // now select the interface
884             //
885             Status = USBCCGP_SyncUrbRequest(PDODeviceExtension->NextDeviceObject, NewUrb);
886             DPRINT1("SelectInterface Status %x\n", Status);
887 
888             if (!NT_SUCCESS(Status))
889             {
890                  //
891                  // failed
892                  //
893                  break;
894             }
895 
896             //
897             // update configuration info
898             //
899             ASSERT(Entry->Interface->Length >= NewUrb->UrbSelectInterface.Interface.Length);
900             ASSERT(Length >= NewUrb->UrbSelectInterface.Interface.Length);
901             RtlCopyMemory(Entry->Interface, &NewUrb->UrbSelectInterface.Interface, NewUrb->UrbSelectInterface.Interface.Length);
902 
903             //
904             // update provided interface information
905             //
906             ASSERT(Length >= Entry->Interface->Length);
907             RtlCopyMemory(InterfaceInformation, Entry->Interface, Entry->Interface->Length);
908 
909             //
910             // decrement remaining buffer size
911             //
912             ASSERT(Entry->Interface->Length);
913             Length -= Entry->Interface->Length;
914 
915             //
916             // adjust output buffer offset
917             //
918             InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + Entry->Interface->Length);
919 
920             //
921             // free urb
922             //
923             FreeItem(NewUrb);
924         }
925 
926     } while(Length);
927 
928     //
929     // store configuration handle
930     //
931     Urb->UrbSelectConfiguration.ConfigurationHandle = PDODeviceExtension->ConfigurationHandle;
932 
933     DPRINT1("[USBCCGP] SelectConfiguration Function %x Completed\n", PDODeviceExtension->FunctionDescriptor->FunctionNumber);
934 
935     //
936     // done
937     //
938     return STATUS_SUCCESS;
939 }
940 
941 NTSTATUS
942 PDO_HandleInternalDeviceControl(
943     PDEVICE_OBJECT DeviceObject,
944     PIRP Irp)
945 {
946     PIO_STACK_LOCATION IoStack;
947     PPDO_DEVICE_EXTENSION PDODeviceExtension;
948     NTSTATUS Status;
949     PURB Urb;
950 
951     //
952     // get current stack location
953     //
954     IoStack = IoGetCurrentIrpStackLocation(Irp);
955 
956     //
957     // get device extension
958     //
959     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
960 
961     if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB)
962     {
963         //
964         // get urb
965         //
966         Urb = (PURB)IoStack->Parameters.Others.Argument1;
967         ASSERT(Urb);
968         DPRINT("IOCTL_INTERNAL_USB_SUBMIT_URB Function %x\n", Urb->UrbHeader.Function);
969 
970         if (Urb->UrbHeader.Function == URB_FUNCTION_SELECT_CONFIGURATION)
971         {
972             //
973             // select configuration
974             //
975             Status = USBCCGP_PDOSelectConfiguration(DeviceObject, Irp);
976             Irp->IoStatus.Status = Status;
977             IoCompleteRequest(Irp, IO_NO_INCREMENT);
978             return Status;
979         }
980         else if (Urb->UrbHeader.Function == URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE)
981         {
982             if (Urb->UrbControlDescriptorRequest.DescriptorType == USB_DEVICE_DESCRIPTOR_TYPE)
983             {
984                 //
985                 // is the buffer big enough
986                 //
987                 if (Urb->UrbControlDescriptorRequest.TransferBufferLength < sizeof(USB_DEVICE_DESCRIPTOR))
988                 {
989                     //
990                     // invalid buffer size
991                     //
992                     DPRINT1("[USBCCGP] invalid device descriptor size %lu\n", Urb->UrbControlDescriptorRequest.TransferBufferLength);
993                     Urb->UrbControlDescriptorRequest.TransferBufferLength = sizeof(USB_DEVICE_DESCRIPTOR);
994                     Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
995                     IoCompleteRequest(Irp, IO_NO_INCREMENT);
996                     return STATUS_INVALID_BUFFER_SIZE;
997                 }
998 
999                 //
1000                 // copy device descriptor
1001                 //
1002                 ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
1003                 RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer, &PDODeviceExtension->DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
1004                 Irp->IoStatus.Status = STATUS_SUCCESS;
1005                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1006                 return STATUS_SUCCESS;
1007             }
1008             else if (Urb->UrbControlDescriptorRequest.DescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE)
1009             {
1010                 //
1011                 // build configuration descriptor
1012                 //
1013                 Status = USBCCGP_BuildConfigurationDescriptor(DeviceObject, Irp);
1014                 Irp->IoStatus.Status = Status;
1015                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1016                 return Status;
1017             }
1018             else if (Urb->UrbControlDescriptorRequest.DescriptorType == USB_STRING_DESCRIPTOR_TYPE)
1019             {
1020                 PUSB_STRING_DESCRIPTOR StringDescriptor;
1021 
1022                 //
1023                 // get the requested string descriptor
1024                 //
1025                 ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
1026                 Status = USBCCGP_GetDescriptor(PDODeviceExtension->FDODeviceExtension->NextDeviceObject,
1027                                                USB_STRING_DESCRIPTOR_TYPE,
1028                                                Urb->UrbControlDescriptorRequest.TransferBufferLength,
1029                                                Urb->UrbControlDescriptorRequest.Index,
1030                                                Urb->UrbControlDescriptorRequest.LanguageId,
1031                                                (PVOID*)&StringDescriptor);
1032                 if (NT_SUCCESS(Status))
1033                 {
1034                     if (StringDescriptor->bLength == 2)
1035                     {
1036                         FreeItem(StringDescriptor);
1037                         Status = STATUS_DEVICE_DATA_ERROR;
1038                     }
1039                     else
1040                     {
1041                         RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer,
1042                                       StringDescriptor->bString,
1043                                       StringDescriptor->bLength + sizeof(WCHAR));
1044                         FreeItem(StringDescriptor);
1045                         Status = STATUS_SUCCESS;
1046                     }
1047                 }
1048                 Irp->IoStatus.Status = Status;
1049                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1050                 return Status;
1051             }
1052         }
1053         else
1054         {
1055             IoSkipCurrentIrpStackLocation(Irp);
1056             Status = IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
1057             return Status;
1058         }
1059     }
1060     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_GET_PORT_STATUS)
1061     {
1062         IoSkipCurrentIrpStackLocation(Irp);
1063         Status = IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
1064         return Status;
1065     }
1066     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_RESET_PORT)
1067     {
1068         IoSkipCurrentIrpStackLocation(Irp);
1069         Status = IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
1070         return Status;
1071     }
1072     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_CYCLE_PORT)
1073     {
1074         IoSkipCurrentIrpStackLocation(Irp);
1075         Status = IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
1076         return Status;
1077     }
1078 
1079     DPRINT1("IOCTL %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
1080     DPRINT1("InputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.InputBufferLength);
1081     DPRINT1("OutputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength);
1082     DPRINT1("Type3InputBuffer %p\n", IoStack->Parameters.DeviceIoControl.Type3InputBuffer);
1083 
1084     ASSERT(FALSE);
1085 
1086     Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
1087     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1088     return STATUS_NOT_IMPLEMENTED;
1089 }
1090 
1091 NTSTATUS
1092 PDO_HandlePower(
1093     PDEVICE_OBJECT DeviceObject,
1094     PIRP Irp)
1095 {
1096     NTSTATUS Status;
1097     PIO_STACK_LOCATION IoStack;
1098 
1099     IoStack = IoGetCurrentIrpStackLocation(Irp);
1100 
1101     switch (IoStack->MinorFunction)
1102     {
1103         case IRP_MN_SET_POWER:
1104         case IRP_MN_QUERY_POWER:
1105             Irp->IoStatus.Status = STATUS_SUCCESS;
1106             break;
1107     }
1108 
1109     Status = Irp->IoStatus.Status;
1110     PoStartNextPowerIrp(Irp);
1111     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1112     return Status;
1113 }
1114 
1115 
1116 NTSTATUS
1117 PDO_Dispatch(
1118     PDEVICE_OBJECT DeviceObject,
1119     PIRP Irp)
1120 {
1121     PIO_STACK_LOCATION IoStack;
1122     NTSTATUS Status;
1123 
1124     /* get stack location */
1125     IoStack = IoGetCurrentIrpStackLocation(Irp);
1126 
1127     switch(IoStack->MajorFunction)
1128     {
1129         case IRP_MJ_PNP:
1130             return PDO_HandlePnp(DeviceObject, Irp);
1131         case IRP_MJ_INTERNAL_DEVICE_CONTROL:
1132             return PDO_HandleInternalDeviceControl(DeviceObject, Irp);
1133         case IRP_MJ_POWER:
1134             return PDO_HandlePower(DeviceObject, Irp);
1135         default:
1136             DPRINT1("PDO_Dispatch Function %x not implemented\n", IoStack->MajorFunction);
1137             Status = Irp->IoStatus.Status;
1138             IoCompleteRequest(Irp, IO_NO_INCREMENT);
1139             return Status;
1140     }
1141 }
1142