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