--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Kernel Streaming
+ * FILE: lib/drivers/sound/libusbaudio/libusbaudio.c
+ * PURPOSE: USB AUDIO Parser
+ * PROGRAMMER: Johannes Anderwald
+ */
+#include "priv.h"
+
+GUID NodeTypeMicrophone = {STATIC_KSNODETYPE_MICROPHONE};
+GUID NodeTypeDesktopMicrophone = {STATIC_KSNODETYPE_DESKTOP_MICROPHONE};
+GUID NodeTypePersonalMicrophone = {STATIC_KSNODETYPE_PERSONAL_MICROPHONE};
+GUID NodeTypeOmmniMicrophone = {STATIC_KSNODETYPE_OMNI_DIRECTIONAL_MICROPHONE};
+GUID NodeTypeArrayMicrophone = {STATIC_KSNODETYPE_MICROPHONE_ARRAY};
+GUID NodeTypeProcessingArrayMicrophone = {STATIC_KSNODETYPE_PROCESSING_MICROPHONE_ARRAY};
+GUID NodeTypeSpeaker = {STATIC_KSNODETYPE_SPEAKER};
+GUID NodeTypeHeadphonesSpeaker = {STATIC_KSNODETYPE_HEADPHONES};
+GUID NodeTypeHMDA = {STATIC_KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO};
+GUID NodeTypeDesktopSpeaker = {STATIC_KSNODETYPE_DESKTOP_SPEAKER};
+GUID NodeTypeRoomSpeaker = {STATIC_KSNODETYPE_ROOM_SPEAKER};
+GUID NodeTypeCommunicationSpeaker = {STATIC_KSNODETYPE_COMMUNICATION_SPEAKER};
+GUID NodeTypeSubwoofer = {STATIC_KSNODETYPE_LOW_FREQUENCY_EFFECTS_SPEAKER};
+GUID NodeTypeCapture = {STATIC_PINNAME_CAPTURE};
+GUID NodeTypePlayback = {STATIC_KSCATEGORY_AUDIO};
+
+
+KSPIN_INTERFACE StandardPinInterface =
+{
+ {STATIC_KSINTERFACESETID_Standard},
+ KSINTERFACE_STANDARD_STREAMING,
+ 0
+};
+
+KSPIN_MEDIUM StandardPinMedium =
+{
+ {STATIC_KSMEDIUMSETID_Standard},
+ KSMEDIUM_TYPE_ANYINSTANCE,
+ 0
+};
+
+USBAUDIO_STATUS
+UsbAudio_InitializeContext(
+ IN PUSBAUDIO_CONTEXT Context,
+ IN PUSBAUDIO_ALLOC Alloc,
+ IN PUSBAUDIO_FREE Free,
+ IN PUSBAUDIO_COPY Copy)
+{
+
+ /* verify parameters */
+ if (!Context || !Alloc || !Free || !Copy)
+ {
+ /* invalid parameter */
+ return UA_STATUS_INVALID_PARAMETER;
+ }
+
+ /* initialize context */
+ Context->Size = sizeof(USBAUDIO_CONTEXT);
+ Context->Alloc = Alloc;
+ Context->Free = Free;
+ Context->Copy = Copy;
+
+ /* done */
+ return UA_STATUS_SUCCESS;
+}
+
+LPGUID
+UsbAudio_GetPinCategoryFromTerminalDescriptor(
+ IN PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR TerminalDescriptor)
+{
+ if (TerminalDescriptor->wTerminalType == USB_AUDIO_MICROPHONE_TERMINAL_TYPE)
+ return &NodeTypeMicrophone;
+ else if (TerminalDescriptor->wTerminalType == USB_AUDIO_DESKTOP_MICROPHONE_TERMINAL_TYPE)
+ return &NodeTypeDesktopMicrophone;
+ else if (TerminalDescriptor->wTerminalType == USB_AUDIO_PERSONAL_MICROPHONE_TERMINAL_TYPE)
+ return &NodeTypePersonalMicrophone;
+ else if (TerminalDescriptor->wTerminalType == USB_AUDIO_OMMNI_MICROPHONE_TERMINAL_TYPE)
+ return &NodeTypeOmmniMicrophone;
+ else if (TerminalDescriptor->wTerminalType == USB_AUDIO_ARRAY_MICROPHONE_TERMINAL_TYPE)
+ return &NodeTypeArrayMicrophone;
+ else if (TerminalDescriptor->wTerminalType == USB_AUDIO_ARRAY_PROCESSING_MICROPHONE_TERMINAL_TYPE)
+ return &NodeTypeProcessingArrayMicrophone;
+
+ /* playback types */
+ if (TerminalDescriptor->wTerminalType == USB_AUDIO_SPEAKER_TERMINAL_TYPE)
+ return &NodeTypeSpeaker;
+ else if (TerminalDescriptor->wTerminalType == USB_HEADPHONES_SPEAKER_TERMINAL_TYPE)
+ return &NodeTypeHeadphonesSpeaker;
+ else if (TerminalDescriptor->wTerminalType == USB_AUDIO_HMDA_TERMINAL_TYPE)
+ return &NodeTypeHMDA;
+ else if (TerminalDescriptor->wTerminalType == USB_AUDIO_DESKTOP_SPEAKER_TERMINAL_TYPE)
+ return &NodeTypeDesktopSpeaker;
+ else if (TerminalDescriptor->wTerminalType == USB_AUDIO_ROOM_SPEAKER_TERMINAL_TYPE)
+ return &NodeTypeRoomSpeaker;
+ else if (TerminalDescriptor->wTerminalType == USB_AUDIO_COMMUNICATION_SPEAKER_TERMINAL_TYPE)
+ return &NodeTypeCommunicationSpeaker;
+ else if (TerminalDescriptor->wTerminalType == USB_AUDIO_SUBWOOFER_TERMINAL_TYPE)
+ return &NodeTypeSubwoofer;
+
+ if (TerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE)
+ {
+ if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_OUTPUT_TERMINAL)
+ return &NodeTypeCapture;
+ else if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_INPUT_TERMINAL)
+ return &NodeTypePlayback;
+
+ }
+ return NULL;
+}
+
+USBAUDIO_STATUS
+UsbAudio_InitPinDescriptor(
+ IN PUCHAR ConfigurationDescriptor,
+ IN ULONG ConfigurationDescriptorLength,
+ IN PKSPIN_DESCRIPTOR_EX PinDescriptor,
+ IN ULONG TerminalCount,
+ IN PUSB_COMMON_DESCRIPTOR * Descriptors,
+ IN ULONG TerminalId)
+{
+ PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR TerminalDescriptor;
+
+ TerminalDescriptor = UsbAudio_GetTerminalDescriptorById(Descriptors, TerminalCount, TerminalId);
+ if (!TerminalDescriptor)
+ {
+ /* failed to find terminal descriptor */
+ return UA_STATUS_UNSUCCESSFUL;
+ }
+
+ /* init pin descriptor */
+ PinDescriptor->PinDescriptor.InterfacesCount = 1;
+ PinDescriptor->PinDescriptor.Interfaces = &StandardPinInterface;
+ PinDescriptor->PinDescriptor.MediumsCount = 1;
+ PinDescriptor->PinDescriptor.Mediums = &StandardPinMedium;
+ PinDescriptor->PinDescriptor.Category = UsbAudio_GetPinCategoryFromTerminalDescriptor(TerminalDescriptor);
+
+ if (TerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE)
+ {
+ if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_OUTPUT_TERMINAL)
+ {
+ PinDescriptor->PinDescriptor.Communication = KSPIN_COMMUNICATION_SINK;
+ PinDescriptor->PinDescriptor.DataFlow = KSPIN_DATAFLOW_OUT;
+ }
+ else if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_INPUT_TERMINAL)
+ {
+ PinDescriptor->PinDescriptor.Communication = KSPIN_COMMUNICATION_SINK;
+ PinDescriptor->PinDescriptor.DataFlow = KSPIN_DATAFLOW_IN;
+ }
+
+ /* irp sinks / sources can be instantiated */
+ PinDescriptor->InstancesPossible = 1;
+
+ }
+ else if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_INPUT_TERMINAL)
+ {
+ PinDescriptor->PinDescriptor.Communication = KSPIN_COMMUNICATION_BRIDGE;
+ PinDescriptor->PinDescriptor.DataFlow = KSPIN_DATAFLOW_IN;
+ }
+ else if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_OUTPUT_TERMINAL)
+ {
+ PinDescriptor->PinDescriptor.Communication = KSPIN_COMMUNICATION_BRIDGE;
+ PinDescriptor->PinDescriptor.DataFlow = KSPIN_DATAFLOW_OUT;
+ }
+
+ return UA_STATUS_SUCCESS;
+}
+
+USBAUDIO_STATUS
+UsbAudio_ParseConfigurationDescriptor(
+ IN PUSBAUDIO_CONTEXT Context,
+ IN PUCHAR ConfigurationDescriptor,
+ IN ULONG ConfigurationDescriptorSize)
+{
+ USBAUDIO_STATUS Status;
+ PKSFILTER_DESCRIPTOR FilterDescriptor;
+ PUSB_COMMON_DESCRIPTOR * Descriptors;
+ PUSB_COMMON_DESCRIPTOR * InterfaceDescriptors;
+ PULONG TerminalIds;
+ ULONG Index, AudioControlInterfaceIndex;
+ ULONG InterfaceCount, DescriptorCount, NewDescriptorCount;
+ PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+
+
+ if (!Context || !ConfigurationDescriptor || !ConfigurationDescriptorSize)
+ {
+ /* invalid parameter */
+ return UA_STATUS_INVALID_PARAMETER;
+ }
+
+ /* count usb interface descriptors */
+ Status = UsbAudio_CountInterfaceDescriptors(ConfigurationDescriptor, ConfigurationDescriptorSize, &InterfaceCount);
+ if (Status != UA_STATUS_SUCCESS || InterfaceCount == 0)
+ {
+ /* invalid parameter */
+ return UA_STATUS_INVALID_PARAMETER;
+ }
+
+ /* construct interface array */
+ Status = UsbAudio_CreateInterfaceDescriptorsArray(Context, ConfigurationDescriptor, ConfigurationDescriptorSize, InterfaceCount, &InterfaceDescriptors);
+ if (Status != UA_STATUS_SUCCESS)
+ {
+ /* invalid parameter */
+ return UA_STATUS_INVALID_PARAMETER;
+ }
+
+ /* get audio control interface index */
+ AudioControlInterfaceIndex = UsbAudio_GetAudioControlInterfaceIndex(InterfaceDescriptors, InterfaceCount);
+ if (AudioControlInterfaceIndex == MAXULONG)
+ {
+ /* invalid configuration descriptor */
+ Context->Free(InterfaceDescriptors);
+ return UA_STATUS_INVALID_PARAMETER;
+ }
+
+ /* count audio terminal descriptors */
+ Status = UsbAudio_CountAudioDescriptors(ConfigurationDescriptor, ConfigurationDescriptorSize, InterfaceDescriptors, InterfaceCount, AudioControlInterfaceIndex, &DescriptorCount);
+ if (Status != UA_STATUS_SUCCESS || DescriptorCount == 0)
+ {
+ /* invalid parameter */
+ Context->Free(InterfaceDescriptors);
+ return UA_STATUS_INVALID_PARAMETER;
+ }
+
+ /* construct terminal descriptor array */
+ Status = UsbAudio_CreateAudioDescriptorArray(Context, ConfigurationDescriptor, ConfigurationDescriptorSize, InterfaceDescriptors, InterfaceCount, AudioControlInterfaceIndex, DescriptorCount, &Descriptors);
+ if (Status != UA_STATUS_SUCCESS)
+ {
+ /* no memory */
+ Context->Free(InterfaceDescriptors);
+ //DPRINT("[LIBUSBAUDIO] Failed to create descriptor array with %x\n", Status);
+ return Status;
+ }
+
+ /* construct filter */
+ FilterDescriptor = (PKSFILTER_DESCRIPTOR)Context->Alloc(sizeof(KSFILTER_DESCRIPTOR));
+ if (!FilterDescriptor)
+ {
+ /* no memory */
+ Context->Free(InterfaceDescriptors);
+ Context->Free(Descriptors);
+ return UA_STATUS_NO_MEMORY;
+ }
+
+
+ /* construct pin id array */
+ TerminalIds = (PULONG)Context->Alloc(sizeof(ULONG) * DescriptorCount);
+ if (!TerminalIds)
+ {
+ /* no memory */
+ Context->Free(InterfaceDescriptors);
+ Context->Free(FilterDescriptor);
+ Context->Free(Descriptors);
+ return UA_STATUS_NO_MEMORY;
+ }
+
+ /* now assign terminal ids */
+ Status = UsbAudio_AssignTerminalIds(Context, DescriptorCount, Descriptors, TerminalIds, &NewDescriptorCount);
+ if(Status != UA_STATUS_SUCCESS || NewDescriptorCount == 0)
+ {
+ /* failed to initialize */
+ Context->Free(InterfaceDescriptors);
+ Context->Free(FilterDescriptor);
+ Context->Free(Descriptors);
+ Context->Free(TerminalIds);
+ DPRINT1("[LIBUSBAUDIO] Failed to assign terminal ids with %x DescriptorCount %lx\n", Status, DescriptorCount);
+ return UA_STATUS_UNSUCCESSFUL;
+ }
+
+
+ /* init filter */
+ FilterDescriptor->Version = KSFILTER_DESCRIPTOR_VERSION;
+ FilterDescriptor->Flags = 0; /* FIXME */
+ FilterDescriptor->PinDescriptorsCount = NewDescriptorCount;
+ FilterDescriptor->PinDescriptorSize = sizeof(KSPIN_DESCRIPTOR_EX);
+ FilterDescriptor->PinDescriptors = Context->Alloc(sizeof(KSPIN_DESCRIPTOR_EX) * FilterDescriptor->PinDescriptorsCount);
+ if (!FilterDescriptor->PinDescriptors)
+ {
+ /* no memory */
+ Context->Free(InterfaceDescriptors);
+ Context->Free(FilterDescriptor);
+ Context->Free(Descriptors);
+ Context->Free(TerminalIds);
+ return UA_STATUS_NO_MEMORY;
+ }
+
+ /* now init pin properties */
+ for(Index = 0; Index < FilterDescriptor->PinDescriptorsCount; Index++)
+ {
+ /* now init every pin descriptor */
+ Status = UsbAudio_InitPinDescriptor(ConfigurationDescriptor, ConfigurationDescriptorSize, (PKSPIN_DESCRIPTOR_EX)&FilterDescriptor->PinDescriptors[Index], DescriptorCount, Descriptors, TerminalIds[Index]);
+ if (Status != UA_STATUS_SUCCESS)
+ break;
+ }
+
+ if (Status != UA_STATUS_SUCCESS)
+ {
+ /* failed to init pin descriptor */
+ Context->Free(InterfaceDescriptors);
+ Context->Free((PVOID)FilterDescriptor->PinDescriptors);
+ Context->Free(FilterDescriptor);
+ Context->Free(Descriptors);
+ Context->Free(TerminalIds);
+ DPRINT1("[LIBUSBAUDIO] Failed to init pin with %x\n", Status);
+ return Status;
+ }
+
+
+ /* now assign data ranges to the pins */
+ for(Index = 0; Index < InterfaceCount; Index++)
+ {
+ /* get descriptor */
+ InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)InterfaceDescriptors[Index];
+
+ /* sanity check */
+ ASSERT(InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
+ DPRINT1("InterfaceNumber %d bInterfaceClass %x bInterfaceSubClass %x\n", InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bInterfaceClass, InterfaceDescriptor->bInterfaceSubClass);
+
+ if (InterfaceDescriptor->bInterfaceClass != 0x01 && InterfaceDescriptor->bInterfaceSubClass != 0x02)
+ continue;
+
+ /* assign data ranges */
+ Status = UsbAudio_AssignDataRanges(Context, ConfigurationDescriptor, ConfigurationDescriptorSize, FilterDescriptor, InterfaceDescriptors, InterfaceCount, Index, TerminalIds);
+ if (Status != UA_STATUS_SUCCESS)
+ break;
+ }
+
+ if (Status != UA_STATUS_SUCCESS)
+ {
+ /* failed to init pin descriptor */
+ Context->Free(InterfaceDescriptors);
+ Context->Free((PVOID)FilterDescriptor->PinDescriptors);
+ Context->Free(FilterDescriptor);
+ Context->Free(Descriptors);
+ Context->Free(TerminalIds);
+ return Status;
+ }
+
+
+
+ if (Status != UA_STATUS_SUCCESS)
+ {
+ /* failed to init pin descriptor */
+ Context->Free(InterfaceDescriptors);
+ Context->Free((PVOID)FilterDescriptor->PinDescriptors);
+ Context->Free(FilterDescriptor);
+ Context->Free(Descriptors);
+ Context->Free(TerminalIds);
+ return Status;
+ }
+
+ Context->Context = FilterDescriptor;
+ return Status;
+
+}
+
+USBAUDIO_STATUS
+UsbAudio_GetFilter(
+ IN PUSBAUDIO_CONTEXT Context,
+ OUT PVOID * OutFilterDescriptor)
+{
+ if (!OutFilterDescriptor)
+ return UA_STATUS_INVALID_PARAMETER;
+
+ *OutFilterDescriptor = Context->Context;
+ return UA_STATUS_SUCCESS;
+}
\ No newline at end of file