xref: /reactos/drivers/usb/usbccgp/function.c (revision 8a978a17)
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/descriptor.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 #define NDEBUG
15 #include <debug.h>
16 
17 NTSTATUS
18 USBCCGP_QueryInterface(
19     IN PDEVICE_OBJECT DeviceObject,
20     OUT PUSBC_DEVICE_CONFIGURATION_INTERFACE_V1 BusInterface)
21 {
22     KEVENT Event;
23     NTSTATUS Status;
24     PIRP Irp;
25     IO_STATUS_BLOCK IoStatus;
26     PIO_STACK_LOCATION Stack;
27 
28     /* Sanity checks */
29     ASSERT(DeviceObject);
30 
31     /* Initialize event */
32     KeInitializeEvent(&Event, NotificationEvent, FALSE);
33 
34     /* Init interface */
35     RtlZeroMemory(BusInterface, sizeof(USBC_DEVICE_CONFIGURATION_INTERFACE_V1));
36     BusInterface->Version = USBC_DEVICE_CONFIGURATION_INTERFACE_VERSION_1;
37     BusInterface->Size = sizeof(USBC_DEVICE_CONFIGURATION_INTERFACE_V1);
38 
39     /* Create irp */
40     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
41                                        DeviceObject,
42                                        NULL,
43                                        0,
44                                        NULL,
45                                        &Event,
46                                        &IoStatus);
47 
48     //
49     // was irp built
50     //
51     if (Irp == NULL)
52     {
53         //
54         // no memory
55         //
56         return STATUS_INSUFFICIENT_RESOURCES;
57     }
58 
59     //
60     // initialize request
61     //
62     Stack = IoGetNextIrpStackLocation(Irp);
63     Stack->MajorFunction = IRP_MJ_PNP;
64     Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
65     Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
66     Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&USB_BUS_INTERFACE_USBC_CONFIGURATION_GUID;
67     Stack->Parameters.QueryInterface.Version = 2;
68     Stack->Parameters.QueryInterface.Interface = (PINTERFACE)&BusInterface;
69     Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
70     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
71 
72     //
73     // call driver
74     //
75     Status = IoCallDriver(DeviceObject, Irp);
76 
77     //
78     // did operation complete
79     //
80     if (Status == STATUS_PENDING)
81     {
82         //
83         // wait for completion
84         //
85         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
86 
87         //
88         // collect status
89         //
90         Status = IoStatus.Status;
91     }
92 
93     return Status;
94 }
95 
96 NTSTATUS
97 USBCCGP_CustomEnumWithInterface(
98     IN PDEVICE_OBJECT DeviceObject)
99 {
100     PFDO_DEVICE_EXTENSION FDODeviceExtension;
101     ULONG FunctionDescriptorBufferLength = 0;
102     NTSTATUS Status;
103     PUSBC_FUNCTION_DESCRIPTOR  FunctionDescriptorBuffer = NULL;
104 
105     //
106     // get device extension
107     //
108     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
109     ASSERT(FDODeviceExtension->Common.IsFDO);
110 
111     if (FDODeviceExtension->BusInterface.StartDeviceCallback == NULL)
112     {
113         //
114         // not supported
115         //
116         return STATUS_NOT_SUPPORTED;
117     }
118 
119     //
120     // invoke callback
121     //
122     Status = FDODeviceExtension->BusInterface.StartDeviceCallback(FDODeviceExtension->DeviceDescriptor,
123                                                                   FDODeviceExtension->ConfigurationDescriptor,
124                                                                   &FunctionDescriptorBuffer,
125                                                                   &FunctionDescriptorBufferLength,
126                                                                   DeviceObject,
127                                                                   FDODeviceExtension->PhysicalDeviceObject);
128 
129     DPRINT("USBCCGP_CustomEnumWithInterface Status %lx\n", Status);
130     if (!NT_SUCCESS(Status))
131     {
132         //
133         // failed
134         //
135         return Status;
136     }
137 
138     DPRINT("FunctionDescriptorBufferLength %lu\n", FunctionDescriptorBufferLength);
139     DPRINT("FunctionDescriptorBuffer %p\n", FunctionDescriptorBuffer);
140 
141     //
142     // assume length % function buffer size
143     //
144     ASSERT(FunctionDescriptorBufferLength);
145     ASSERT(FunctionDescriptorBufferLength % sizeof(USBC_FUNCTION_DESCRIPTOR) == 0);
146 
147     //
148     // store result
149     //
150     FDODeviceExtension->FunctionDescriptor = FunctionDescriptorBuffer;
151     FDODeviceExtension->FunctionDescriptorCount = FunctionDescriptorBufferLength / sizeof(USBC_FUNCTION_DESCRIPTOR);
152 
153     //
154     // success
155     //
156     return STATUS_SUCCESS;
157 }
158 
159 ULONG
160 USBCCGP_CountAssociationDescriptors(
161     IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
162 {
163     PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR Descriptor;
164     PUCHAR Offset, End;
165     ULONG Count = 0;
166 
167     //
168     // init offsets
169     //
170     Offset = (PUCHAR)ConfigurationDescriptor + ConfigurationDescriptor->bLength;
171     End = (PUCHAR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength;
172 
173     while (Offset < End)
174     {
175         //
176         // get association descriptor
177         //
178         Descriptor = (PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR)Offset;
179 
180         if (Descriptor->bLength == sizeof(USB_INTERFACE_ASSOCIATION_DESCRIPTOR) && Descriptor->bDescriptorType == USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE)
181         {
182             //
183             // found descriptor
184             //
185             Count++;
186         }
187 
188         //
189         // move to next descriptor
190         //
191         Offset += Descriptor->bLength;
192     }
193 
194     //
195     // done
196     //
197     return Count;
198 }
199 
200 PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR
201 USBCCGP_GetAssociationDescriptorAtIndex(
202     IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
203     IN ULONG Index)
204 {
205     PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR Descriptor;
206     PUCHAR Offset, End;
207     ULONG Count = 0;
208 
209     //
210     // init offsets
211     //
212     Offset = (PUCHAR)ConfigurationDescriptor + ConfigurationDescriptor->bLength;
213     End = (PUCHAR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength;
214 
215     while (Offset < End)
216     {
217         //
218         // get association descriptor
219         //
220         Descriptor = (PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR)Offset;
221 
222         if (Descriptor->bLength == sizeof(USB_INTERFACE_ASSOCIATION_DESCRIPTOR) && Descriptor->bDescriptorType == USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE)
223         {
224             if (Index == Count)
225             {
226                 //
227                 // found descriptor
228                 //
229                 return Descriptor;
230             }
231 
232             //
233             // not the searched one
234             //
235             Count++;
236         }
237 
238         //
239         // move to next descriptor
240         //
241         Offset += Descriptor->bLength;
242     }
243 
244     //
245     // failed to find descriptor at the specified index
246     //
247     return NULL;
248 }
249 
250 NTSTATUS
251 USBCCGP_InitInterfaceListOfFunctionDescriptor(
252     IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
253     IN PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR AssociationDescriptor,
254     OUT PUSBC_FUNCTION_DESCRIPTOR FunctionDescriptor)
255 {
256     PUSB_INTERFACE_DESCRIPTOR Descriptor;
257     PUCHAR Offset, End;
258     ULONG Count = 0;
259 
260     //
261     // init offsets
262     //
263     Offset = (PUCHAR)AssociationDescriptor + AssociationDescriptor->bLength;
264     End = (PUCHAR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength;
265 
266     while (Offset < End)
267     {
268         //
269         // get association descriptor
270         //
271         Descriptor = (PUSB_INTERFACE_DESCRIPTOR)Offset;
272 
273         if (Descriptor->bLength == sizeof(USB_INTERFACE_DESCRIPTOR) && Descriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
274         {
275             //
276             // store interface descriptor
277             //
278             FunctionDescriptor->InterfaceDescriptorList[Count] = Descriptor;
279             Count++;
280 
281             if (Count == AssociationDescriptor->bInterfaceCount)
282             {
283                 //
284                 // got all interfaces
285                 //
286                 return STATUS_SUCCESS;
287             }
288         }
289 
290         if (Descriptor->bLength == sizeof(USB_INTERFACE_ASSOCIATION_DESCRIPTOR) && Descriptor->bDescriptorType == USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE)
291         {
292             //
293             // WTF? a association descriptor which overlaps the next association descriptor
294             //
295             DPRINT1("Invalid association descriptor\n");
296             ASSERT(FALSE);
297             return STATUS_UNSUCCESSFUL;
298         }
299 
300         //
301         // move to next descriptor
302         //
303         Offset += Descriptor->bLength;
304     }
305 
306     //
307     // invalid association descriptor
308     //
309     DPRINT1("Invalid association descriptor\n");
310     return STATUS_UNSUCCESSFUL;
311 }
312 
313 NTSTATUS
314 USBCCGP_InitFunctionDescriptor(
315     IN PFDO_DEVICE_EXTENSION FDODeviceExtension,
316     IN ULONG FunctionNumber,
317     OUT PUSBC_FUNCTION_DESCRIPTOR FunctionDescriptor)
318 {
319     PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR Descriptor;
320     NTSTATUS Status;
321     LPWSTR DescriptionBuffer;
322     WCHAR Buffer[100];
323     ULONG Index;
324 
325     // init function number
326     FunctionDescriptor->FunctionNumber = (UCHAR)FunctionNumber;
327 
328     // get association descriptor
329     Descriptor = USBCCGP_GetAssociationDescriptorAtIndex(FDODeviceExtension->ConfigurationDescriptor, FunctionNumber);
330     ASSERT(Descriptor);
331 
332     // store number interfaces
333     FunctionDescriptor->NumberOfInterfaces = Descriptor->bInterfaceCount;
334 
335     // allocate array for interface count
336     FunctionDescriptor->InterfaceDescriptorList = AllocateItem(NonPagedPool, sizeof(PUSB_INTERFACE_DESCRIPTOR) * Descriptor->bInterfaceCount);
337     if (!FunctionDescriptor->InterfaceDescriptorList)
338     {
339         //
340         // no memory
341         //
342         return STATUS_INSUFFICIENT_RESOURCES;
343     }
344 
345     // init interface list
346     Status = USBCCGP_InitInterfaceListOfFunctionDescriptor(FDODeviceExtension->ConfigurationDescriptor, Descriptor, FunctionDescriptor);
347     if (!NT_SUCCESS(Status))
348     {
349         //
350         // failed
351         //
352         return Status;
353     }
354 
355     //
356     // now init interface description
357     //
358     if (Descriptor->iFunction)
359     {
360         //
361         // get interface description
362         //
363          Status = USBCCGP_GetStringDescriptor(FDODeviceExtension->NextDeviceObject,
364                                               100 * sizeof(WCHAR),
365                                               Descriptor->iFunction,
366                                               0x0409, //FIXME
367                                               (PVOID*)&DescriptionBuffer);
368         if (!NT_SUCCESS(Status))
369         {
370             //
371             // no description
372             //
373             RtlInitUnicodeString(&FunctionDescriptor->FunctionDescription, L"");
374         }
375         else
376         {
377             //
378             // init description
379             //
380             RtlInitUnicodeString(&FunctionDescriptor->FunctionDescription, DescriptionBuffer);
381         }
382         DPRINT1("FunctionDescription %wZ\n", &FunctionDescriptor->FunctionDescription);
383     }
384 
385     //
386     // now init hardware id
387     //
388     Index = swprintf(Buffer, L"USB\\VID_%04x&PID_%04x&Rev_%04x&MI_%02x", FDODeviceExtension->DeviceDescriptor->idVendor,
389                                                                          FDODeviceExtension->DeviceDescriptor->idProduct,
390                                                                          FDODeviceExtension->DeviceDescriptor->bcdDevice,
391                                                                          Descriptor->bFirstInterface) + 1;
392     Index += swprintf(&Buffer[Index], L"USB\\VID_%04x&PID_%04x&MI_%02x", FDODeviceExtension->DeviceDescriptor->idVendor,
393                                                                          FDODeviceExtension->DeviceDescriptor->idProduct,
394                                                                          Descriptor->bFirstInterface) + 1;
395 
396     // allocate result buffer
397     DescriptionBuffer = AllocateItem(NonPagedPool, (Index + 1) * sizeof(WCHAR));
398     if (!DescriptionBuffer)
399     {
400         //
401         // failed to allocate memory
402         //
403         return STATUS_INSUFFICIENT_RESOURCES;
404     }
405 
406     // copy description
407     RtlCopyMemory(DescriptionBuffer, Buffer, (Index + 1) * sizeof(WCHAR));
408     FunctionDescriptor->HardwareId.Buffer = DescriptionBuffer;
409     FunctionDescriptor->HardwareId.Length = Index * sizeof(WCHAR);
410     FunctionDescriptor->HardwareId.MaximumLength = (Index + 1) * sizeof(WCHAR);
411 
412     //
413     // now init the compatible id
414     //
415     Index = swprintf(Buffer, L"USB\\Class_%02x&SubClass_%02x&Prot_%02x", Descriptor->bFunctionClass, Descriptor->bFunctionSubClass, Descriptor->bFunctionProtocol) + 1;
416     Index += swprintf(&Buffer[Index], L"USB\\Class_%02x&SubClass_%02x",  Descriptor->bFunctionClass, Descriptor->bFunctionSubClass) + 1;
417     Index += swprintf(&Buffer[Index], L"USB\\Class_%02x", Descriptor->bFunctionClass) + 1;
418 
419     // allocate result buffer
420     DescriptionBuffer = AllocateItem(NonPagedPool, (Index + 1) * sizeof(WCHAR));
421     if (!DescriptionBuffer)
422     {
423         //
424         // failed to allocate memory
425         //
426         return STATUS_INSUFFICIENT_RESOURCES;
427     }
428 
429     // copy description
430     RtlCopyMemory(DescriptionBuffer, Buffer, (Index + 1) * sizeof(WCHAR));
431     FunctionDescriptor->CompatibleId.Buffer = DescriptionBuffer;
432     FunctionDescriptor->CompatibleId.Length = Index * sizeof(WCHAR);
433     FunctionDescriptor->CompatibleId.MaximumLength = (Index + 1) * sizeof(WCHAR);
434 
435     //
436     // done
437     //
438     return STATUS_SUCCESS;
439 }
440 
441 NTSTATUS
442 USBCCGP_EnumWithAssociationDescriptor(
443     IN PDEVICE_OBJECT DeviceObject)
444 {
445     ULONG DescriptorCount, Index;
446     PFDO_DEVICE_EXTENSION FDODeviceExtension;
447     NTSTATUS Status = STATUS_SUCCESS;
448 
449     //
450     // get device extension
451     //
452     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
453     ASSERT(FDODeviceExtension->Common.IsFDO);
454 
455     //
456     // count association descriptors
457     //
458     DescriptorCount = USBCCGP_CountAssociationDescriptors(FDODeviceExtension->ConfigurationDescriptor);
459     if (!DescriptorCount)
460     {
461         //
462         // no descriptors found
463         //
464         return STATUS_NOT_SUPPORTED;
465     }
466 
467     //
468     // allocate function descriptor array
469     //
470     FDODeviceExtension->FunctionDescriptor = AllocateItem(NonPagedPool, sizeof(USBC_FUNCTION_DESCRIPTOR) * DescriptorCount);
471     if (!FDODeviceExtension->FunctionDescriptor)
472     {
473         //
474         // no memory
475         //
476         DPRINT1("USBCCGP_EnumWithAssociationDescriptor failed to allocate function descriptor count %x\n", DescriptorCount);
477         return STATUS_INSUFFICIENT_RESOURCES;
478     }
479 
480     for (Index = 0; Index < DescriptorCount; Index++)
481     {
482         //
483         // init function descriptors
484         //
485         Status = USBCCGP_InitFunctionDescriptor(FDODeviceExtension, Index, &FDODeviceExtension->FunctionDescriptor[Index]);
486         if (!NT_SUCCESS(Status))
487         {
488             //
489             // failed
490             //
491             return Status;
492         }
493     }
494 
495     //
496     // store function descriptor count
497     //
498     FDODeviceExtension->FunctionDescriptorCount = DescriptorCount;
499 
500     //
501     // done
502     //
503     return Status;
504 }
505 
506 NTSTATUS
507 USBCCG_InitIdsWithInterfaceDescriptor(
508     IN PFDO_DEVICE_EXTENSION FDODeviceExtension,
509     IN PUSB_INTERFACE_DESCRIPTOR Descriptor,
510     IN ULONG FunctionIndex,
511     OUT PUSBC_FUNCTION_DESCRIPTOR FunctionDescriptor)
512 {
513     ULONG Index;
514     WCHAR Buffer[200];
515     LPWSTR DescriptionBuffer;
516     NTSTATUS Status;
517 
518     //
519     // now init interface description
520     //
521     if (Descriptor->iInterface)
522     {
523         //
524         // get interface description
525         //
526          Status = USBCCGP_GetStringDescriptor(FDODeviceExtension->NextDeviceObject,
527                                               100 * sizeof(WCHAR),
528                                               Descriptor->iInterface,
529                                               0x0409, //FIXME
530                                               (PVOID*)&DescriptionBuffer);
531         if (!NT_SUCCESS(Status))
532         {
533             //
534             // no description
535             //
536             RtlInitUnicodeString(&FunctionDescriptor->FunctionDescription, L"");
537         }
538         else
539         {
540             //
541             // init description
542             //
543             RtlInitUnicodeString(&FunctionDescriptor->FunctionDescription, DescriptionBuffer);
544         }
545         DPRINT1("FunctionDescription %wZ\n", &FunctionDescriptor->FunctionDescription);
546     }
547 
548 
549     //
550     // now init hardware id
551     //
552     Index = swprintf(Buffer, L"USB\\VID_%04x&PID_%04x&Rev_%04x&MI_%02x", FDODeviceExtension->DeviceDescriptor->idVendor,
553                                                                          FDODeviceExtension->DeviceDescriptor->idProduct,
554                                                                          FDODeviceExtension->DeviceDescriptor->bcdDevice,
555                                                                          FunctionIndex) + 1;
556     Index += swprintf(&Buffer[Index], L"USB\\VID_%04x&PID_%04x&MI_%02x", FDODeviceExtension->DeviceDescriptor->idVendor,
557                                                                          FDODeviceExtension->DeviceDescriptor->idProduct,
558                                                                          FunctionIndex) + 1;
559 
560     // allocate result buffer
561     DescriptionBuffer = AllocateItem(NonPagedPool, (Index + 1) * sizeof(WCHAR));
562     if (!DescriptionBuffer)
563     {
564         //
565         // failed to allocate memory
566         //
567         return STATUS_INSUFFICIENT_RESOURCES;
568     }
569 
570     // copy description
571     RtlCopyMemory(DescriptionBuffer, Buffer, (Index + 1) * sizeof(WCHAR));
572     FunctionDescriptor->HardwareId.Buffer = DescriptionBuffer;
573     FunctionDescriptor->HardwareId.Length = Index * sizeof(WCHAR);
574     FunctionDescriptor->HardwareId.MaximumLength = (Index + 1) * sizeof(WCHAR);
575 
576     //
577     // now init the compatible id
578     //
579     Index = swprintf(Buffer, L"USB\\Class_%02x&SubClass_%02x&Prot_%02x", Descriptor->bInterfaceClass, Descriptor->bInterfaceSubClass, Descriptor->bInterfaceProtocol) + 1;
580     Index += swprintf(&Buffer[Index], L"USB\\Class_%02x&SubClass_%02x",  Descriptor->bInterfaceClass, Descriptor->bInterfaceSubClass) + 1;
581     Index += swprintf(&Buffer[Index], L"USB\\Class_%02x", Descriptor->bInterfaceClass) + 1;
582 
583     // allocate result buffer
584     DescriptionBuffer = AllocateItem(NonPagedPool, (Index + 1) * sizeof(WCHAR));
585     if (!DescriptionBuffer)
586     {
587         //
588         // failed to allocate memory
589         //
590         return STATUS_INSUFFICIENT_RESOURCES;
591     }
592 
593     // copy description
594     RtlCopyMemory(DescriptionBuffer, Buffer, (Index + 1) * sizeof(WCHAR));
595     FunctionDescriptor->CompatibleId.Buffer = DescriptionBuffer;
596     FunctionDescriptor->CompatibleId.Length = Index * sizeof(WCHAR);
597     FunctionDescriptor->CompatibleId.MaximumLength = (Index + 1) * sizeof(WCHAR);
598 
599     //
600     // done
601     //
602     return STATUS_SUCCESS;
603 }
604 
605 
606 NTSTATUS
607 USBCCGP_LegacyEnum(
608     IN PDEVICE_OBJECT DeviceObject)
609 {
610     ULONG Index;
611     PFDO_DEVICE_EXTENSION FDODeviceExtension;
612     NTSTATUS Status = STATUS_SUCCESS;
613     PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
614 
615     //
616     // get device extension
617     //
618     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
619     ASSERT(FDODeviceExtension->Common.IsFDO);
620 
621     //
622     // sanity check
623     //
624     ASSERT(FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces);
625 
626     //
627     // allocate function array
628     //
629     FDODeviceExtension->FunctionDescriptor = AllocateItem(NonPagedPool, sizeof(USBC_FUNCTION_DESCRIPTOR) * FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces);
630     if (!FDODeviceExtension->FunctionDescriptor)
631     {
632         //
633         // no memory
634         //
635         DPRINT1("USBCCGP_EnumWithAssociationDescriptor failed to allocate function descriptor %lu\n", FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces);
636         return STATUS_INSUFFICIENT_RESOURCES;
637     }
638 
639     //
640     // init function descriptors
641     //
642     FDODeviceExtension->FunctionDescriptorCount = 0;
643     for (Index = 0; Index < FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces; Index++)
644     {
645         // get interface descriptor
646         InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(FDODeviceExtension->ConfigurationDescriptor, FDODeviceExtension->ConfigurationDescriptor, Index, 0, -1, -1, -1);
647         if (InterfaceDescriptor == NULL)
648         {
649             //
650             // failed to find interface descriptor
651             //
652             DPRINT1("[USBCCGP] Failed to find interface descriptor index %lu\n", Index);
653             ASSERT(FALSE);
654             return STATUS_UNSUCCESSFUL;
655         }
656 
657         //
658         // init function descriptor
659         //
660         FDODeviceExtension->FunctionDescriptor[Index].FunctionNumber = Index;
661         FDODeviceExtension->FunctionDescriptor[Index].NumberOfInterfaces = 1;
662         FDODeviceExtension->FunctionDescriptor[Index].InterfaceDescriptorList = AllocateItem(NonPagedPool, sizeof(PUSB_INTERFACE_DESCRIPTOR) * 1);
663         if (!FDODeviceExtension->FunctionDescriptor[Index].InterfaceDescriptorList)
664         {
665             //
666             // no memory
667             //
668             return STATUS_INSUFFICIENT_RESOURCES;
669         }
670 
671         //
672         // store interface descriptor
673         //
674         FDODeviceExtension->FunctionDescriptor[Index].InterfaceDescriptorList[0] = InterfaceDescriptor;
675 
676         //
677         // now init the device ids
678         //
679         Status = USBCCG_InitIdsWithInterfaceDescriptor(FDODeviceExtension, InterfaceDescriptor, Index, &FDODeviceExtension->FunctionDescriptor[Index]);
680         if (!NT_SUCCESS(Status))
681         {
682             //
683             // failed to init ids
684             //
685             DPRINT1("[USBCCGP] Failed to init ids with %lx\n", Status);
686             return Status;
687         }
688 
689         //
690         // store function count
691         //
692         FDODeviceExtension->FunctionDescriptorCount++;
693     }
694 
695     //
696     // done
697     //
698     return Status;
699 }
700 
701 NTSTATUS
702 USBCCGP_EnumWithUnionFunctionDescriptors(
703     IN PDEVICE_OBJECT DeviceObject)
704 {
705     UNIMPLEMENTED;
706     return STATUS_NOT_IMPLEMENTED;
707 }
708 
709 NTSTATUS
710 USBCCGP_EnumWithAudioLegacy(
711     IN PDEVICE_OBJECT DeviceObject)
712 {
713     ULONG Index;
714     PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor, FirstDescriptor = NULL;
715     PFDO_DEVICE_EXTENSION FDODeviceExtension;
716     NTSTATUS Status = STATUS_SUCCESS;
717 
718     //
719     // get device extension
720     //
721     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
722     ASSERT(FDODeviceExtension->Common.IsFDO);
723 
724 
725     //
726     // first check if all interfaces belong to the same audio class
727     //
728     for (Index = 0; Index < FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces; Index++)
729     {
730         //
731         // get interface descriptor
732         //
733         InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(FDODeviceExtension->ConfigurationDescriptor, FDODeviceExtension->ConfigurationDescriptor, Index, 0, -1, -1, -1);
734         DPRINT1("Index %lu Descriptor %p\n", Index, InterfaceDescriptor);
735         ASSERT(InterfaceDescriptor);
736 
737         if (InterfaceDescriptor->bInterfaceClass != 0x1)
738         {
739             //
740             // collection contains non audio class
741             //
742             return STATUS_UNSUCCESSFUL;
743         }
744 
745         if (FirstDescriptor == NULL)
746         {
747             //
748             // store interface descriptor
749             //
750             FirstDescriptor = InterfaceDescriptor;
751             continue;
752         }
753 
754         if (FirstDescriptor->bInterfaceSubClass == InterfaceDescriptor->bInterfaceSubClass)
755         {
756             //
757             // interface subclass must be different from the first interface
758             //
759             return STATUS_UNSUCCESSFUL;
760         }
761     }
762 
763     //
764     // this is an composite audio device
765     //
766     DPRINT("[USBCCGP] Audio Composite Device detected\n");
767 
768     //
769     // audio interfaces are all grouped into one single function
770     //
771     FDODeviceExtension->FunctionDescriptor = AllocateItem(NonPagedPool, sizeof(USBC_FUNCTION_DESCRIPTOR));
772     if (!FDODeviceExtension->FunctionDescriptor)
773     {
774         //
775         // no memory
776         //
777         DPRINT1("USBCCGP_EnumWithAssociationDescriptor failed to allocate function descriptor count\n");
778         return STATUS_INSUFFICIENT_RESOURCES;
779     }
780 
781     //
782     // init function number
783     //
784     FDODeviceExtension->FunctionDescriptor[0].FunctionNumber = 0;
785 
786     //
787     // store interfaces
788     //
789     Status = AllocateInterfaceDescriptorsArray(FDODeviceExtension->ConfigurationDescriptor, &FDODeviceExtension->FunctionDescriptor[0].InterfaceDescriptorList);
790     if (!NT_SUCCESS(Status))
791     {
792         //
793         // failed to allocate descriptor array
794         //
795         DPRINT1("[USBCCGP] Failed to allocate descriptor array %lx\n", Status);
796         return Status;
797     }
798 
799     //
800     // now init the device ids
801     //
802     Status = USBCCG_InitIdsWithInterfaceDescriptor(FDODeviceExtension, FirstDescriptor, 0, &FDODeviceExtension->FunctionDescriptor[0]);
803     if (!NT_SUCCESS(Status))
804     {
805         //
806         // failed to init ids
807         //
808         DPRINT1("[USBCCGP] Failed to init ids with %lx\n", Status);
809         return Status;
810     }
811 
812     //
813     // number of interfaces
814     //
815     FDODeviceExtension->FunctionDescriptor[0].NumberOfInterfaces = FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces;
816 
817     //
818     // store function count
819     //
820     FDODeviceExtension->FunctionDescriptorCount = 1;
821 
822     //
823     // done
824     //
825     return STATUS_SUCCESS;
826 }
827 
828 NTSTATUS
829 USBCCGP_EnumerateFunctions(
830     IN PDEVICE_OBJECT DeviceObject)
831 {
832     NTSTATUS Status;
833     PFDO_DEVICE_EXTENSION FDODeviceExtension;
834 
835     //
836     // get device extension
837     //
838     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
839     ASSERT(FDODeviceExtension->Common.IsFDO);
840 
841     //
842     // first try with filter driver
843     //
844     Status = USBCCGP_CustomEnumWithInterface(DeviceObject);
845     if (NT_SUCCESS(Status))
846     {
847         //
848         // succeeded
849         //
850         return Status;
851     }
852 
853     //
854     // enumerate functions with interface association descriptor
855     //
856     Status = USBCCGP_EnumWithAssociationDescriptor(DeviceObject);
857     if (NT_SUCCESS(Status))
858     {
859         //
860         // succeeded
861         //
862         return Status;
863     }
864 
865 #if 0
866     //
867     // try with union function descriptors
868     //
869     Status = USBCCGP_EnumWithUnionFunctionDescriptors(DeviceObject);
870     if (NT_SUCCESS(Status))
871     {
872         //
873         // succeeded
874         //
875         return Status;
876     }
877 #endif
878 
879     //
880     // try with legacy audio methods
881     //
882     Status = USBCCGP_EnumWithAudioLegacy(DeviceObject);
883     if (NT_SUCCESS(Status))
884     {
885         //
886         // succeeded
887         //
888         return Status;
889     }
890 
891     //
892     // try with legacy enumeration
893     //
894     return USBCCGP_LegacyEnum(DeviceObject);
895 }
896