Reactos
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
17NTSTATUS
18USBCCGP_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
96NTSTATUS
97USBCCGP_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
159ULONG
160USBCCGP_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
200PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR
201USBCCGP_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
250NTSTATUS
251USBCCGP_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
313NTSTATUS
314USBCCGP_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
441NTSTATUS
442USBCCGP_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
506NTSTATUS
507USBCCG_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
606NTSTATUS
607USBCCGP_LegacyEnum(
608 IN PDEVICE_OBJECT DeviceObject)
609{
610 ULONG Index, SubIndex;
611 PFDO_DEVICE_EXTENSION FDODeviceExtension;
612 NTSTATUS Status = STATUS_SUCCESS;
613 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor, NextInterfaceDescriptor;
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 = FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces;
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 SubIndex = 0;
658 if (InterfaceDescriptor->bInterfaceClass == USB_DEVICE_CLASS_AUDIO)
659 {
660 // AUDIO CLASS lets group all audio interfaces together
661 //
662 // init function descriptor
663 //
664 FDODeviceExtension->FunctionDescriptor[Index].FunctionNumber = Index;
665 FDODeviceExtension->FunctionDescriptor[Index].NumberOfInterfaces = 1;
666 FDODeviceExtension->FunctionDescriptor[Index].InterfaceDescriptorList = AllocateItem(NonPagedPool, sizeof(PUSB_INTERFACE_DESCRIPTOR) * FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces);
667 if (!FDODeviceExtension->FunctionDescriptor[Index].InterfaceDescriptorList)
668 {
669 //
670 // no memory
671 //
672 FreeItem(FDODeviceExtension->FunctionDescriptor);
673 FDODeviceExtension->FunctionDescriptor = NULL;
674 FDODeviceExtension->FunctionDescriptorCount = 0;
675 return STATUS_INSUFFICIENT_RESOURCES;
676 }
677
678 //
679 // store interface descriptor
680 //
681 FDODeviceExtension->FunctionDescriptor[Index].InterfaceDescriptorList[SubIndex] = InterfaceDescriptor;
682 while (TRUE)
683 {
684 NextInterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(FDODeviceExtension->ConfigurationDescriptor, FDODeviceExtension->ConfigurationDescriptor, Index + SubIndex + 1, 0, -1, -1, -1);
685 if (!NextInterfaceDescriptor || NextInterfaceDescriptor->bInterfaceClass != USB_DEVICE_CLASS_AUDIO)
686 {
687 // end of collection
688 break;
689 }
690 SubIndex++;
691 ASSERT(SubIndex < FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces);
692 FDODeviceExtension->FunctionDescriptor[Index].NumberOfInterfaces++;
693 FDODeviceExtension->FunctionDescriptor[Index].InterfaceDescriptorList[SubIndex] = NextInterfaceDescriptor;
694 }
695 }
696 else
697 {
698 //
699 // init function descriptor
700 //
701 FDODeviceExtension->FunctionDescriptor[Index].FunctionNumber = Index;
702 FDODeviceExtension->FunctionDescriptor[Index].NumberOfInterfaces = 1;
703 FDODeviceExtension->FunctionDescriptor[Index].InterfaceDescriptorList = AllocateItem(NonPagedPool, sizeof(PUSB_INTERFACE_DESCRIPTOR));
704 if (!FDODeviceExtension->FunctionDescriptor[Index].InterfaceDescriptorList)
705 {
706 //
707 // no memory
708 //
709 return STATUS_INSUFFICIENT_RESOURCES;
710 }
711
712 //
713 // store interface descriptor
714 //
715 FDODeviceExtension->FunctionDescriptor[Index].InterfaceDescriptorList[0] = InterfaceDescriptor;
716 }
717
718 //
719 // now init the device ids
720 //
721 Status = USBCCG_InitIdsWithInterfaceDescriptor(FDODeviceExtension, InterfaceDescriptor, Index, &FDODeviceExtension->FunctionDescriptor[Index]);
722 if (!NT_SUCCESS(Status))
723 {
724 //
725 // failed to init ids
726 //
727 DPRINT1("[USBCCGP] Failed to init ids with %lx\n", Status);
728 return Status;
729 }
730 //
731 // increment interface count
732 //
733 Index += SubIndex;
734 }
735
736 //
737 // done
738 //
739 return Status;
740}
741
742NTSTATUS
743USBCCGP_EnumWithUnionFunctionDescriptors(
744 IN PDEVICE_OBJECT DeviceObject)
745{
746 UNIMPLEMENTED;
747 return STATUS_NOT_IMPLEMENTED;
748}
749
750NTSTATUS
751USBCCGP_EnumWithAudioLegacy(
752 IN PDEVICE_OBJECT DeviceObject)
753{
754 ULONG Index;
755 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor, FirstDescriptor = NULL;
756 PFDO_DEVICE_EXTENSION FDODeviceExtension;
757 NTSTATUS Status = STATUS_SUCCESS;
758
759 //
760 // get device extension
761 //
762 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
763 ASSERT(FDODeviceExtension->Common.IsFDO);
764
765
766 //
767 // first check if all interfaces belong to the same audio class
768 //
769 for (Index = 0; Index < FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces; Index++)
770 {
771 //
772 // get interface descriptor
773 //
774 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(FDODeviceExtension->ConfigurationDescriptor, FDODeviceExtension->ConfigurationDescriptor, Index, 0, -1, -1, -1);
775 DPRINT1("Index %lu Descriptor %p\n", Index, InterfaceDescriptor);
776 ASSERT(InterfaceDescriptor);
777
778 if (InterfaceDescriptor->bInterfaceClass != USB_DEVICE_CLASS_AUDIO)
779 {
780 //
781 // collection contains non audio class
782 //
783 return STATUS_UNSUCCESSFUL;
784 }
785
786 if (FirstDescriptor == NULL)
787 {
788 //
789 // store interface descriptor
790 //
791 FirstDescriptor = InterfaceDescriptor;
792 continue;
793 }
794
795 if (FirstDescriptor->bInterfaceSubClass == InterfaceDescriptor->bInterfaceSubClass)
796 {
797 //
798 // interface subclass must be different from the first interface
799 //
800 return STATUS_UNSUCCESSFUL;
801 }
802 }
803
804 //
805 // this is an composite audio device
806 //
807 DPRINT("[USBCCGP] Audio Composite Device detected\n");
808
809 //
810 // audio interfaces are all grouped into one single function
811 //
812 FDODeviceExtension->FunctionDescriptor = AllocateItem(NonPagedPool, sizeof(USBC_FUNCTION_DESCRIPTOR));
813 if (!FDODeviceExtension->FunctionDescriptor)
814 {
815 //
816 // no memory
817 //
818 DPRINT1("USBCCGP_EnumWithAssociationDescriptor failed to allocate function descriptor count\n");
819 return STATUS_INSUFFICIENT_RESOURCES;
820 }
821
822 //
823 // init function number
824 //
825 FDODeviceExtension->FunctionDescriptor[0].FunctionNumber = 0;
826
827 //
828 // store interfaces
829 //
830 Status = AllocateInterfaceDescriptorsArray(FDODeviceExtension->ConfigurationDescriptor, &FDODeviceExtension->FunctionDescriptor[0].InterfaceDescriptorList);
831 if (!NT_SUCCESS(Status))
832 {
833 //
834 // failed to allocate descriptor array
835 //
836 DPRINT1("[USBCCGP] Failed to allocate descriptor array %lx\n", Status);
837 return Status;
838 }
839
840 //
841 // now init the device ids
842 //
843 Status = USBCCG_InitIdsWithInterfaceDescriptor(FDODeviceExtension, FirstDescriptor, 0, &FDODeviceExtension->FunctionDescriptor[0]);
844 if (!NT_SUCCESS(Status))
845 {
846 //
847 // failed to init ids
848 //
849 DPRINT1("[USBCCGP] Failed to init ids with %lx\n", Status);
850 return Status;
851 }
852
853 //
854 // number of interfaces
855 //
856 FDODeviceExtension->FunctionDescriptor[0].NumberOfInterfaces = FDODeviceExtension->ConfigurationDescriptor->bNumInterfaces;
857
858 //
859 // store function count
860 //
861 FDODeviceExtension->FunctionDescriptorCount = 1;
862
863 //
864 // done
865 //
866 return STATUS_SUCCESS;
867}
868
869NTSTATUS
870USBCCGP_EnumerateFunctions(
871 IN PDEVICE_OBJECT DeviceObject)
872{
873 NTSTATUS Status;
874 PFDO_DEVICE_EXTENSION FDODeviceExtension;
875
876 //
877 // get device extension
878 //
879 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
880 ASSERT(FDODeviceExtension->Common.IsFDO);
881
882 //
883 // first try with filter driver
884 //
885 Status = USBCCGP_CustomEnumWithInterface(DeviceObject);
886 if (NT_SUCCESS(Status))
887 {
888 //
889 // succeeded
890 //
891 return Status;
892 }
893
894 //
895 // enumerate functions with interface association descriptor
896 //
897 Status = USBCCGP_EnumWithAssociationDescriptor(DeviceObject);
898 if (NT_SUCCESS(Status))
899 {
900 //
901 // succeeded
902 //
903 return Status;
904 }
905
906#if 0
907 //
908 // try with union function descriptors
909 //
910 Status = USBCCGP_EnumWithUnionFunctionDescriptors(DeviceObject);
911 if (NT_SUCCESS(Status))
912 {
913 //
914 // succeeded
915 //
916 return Status;
917 }
918#endif
919
920 //
921 // try with legacy audio methods
922 //
923 Status = USBCCGP_EnumWithAudioLegacy(DeviceObject);
924 if (NT_SUCCESS(Status))
925 {
926 //
927 // succeeded
928 //
929 return Status;
930 }
931
932 //
933 // try with legacy enumeration
934 //
935 return USBCCGP_LegacyEnum(DeviceObject);
936}