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