mirror of
https://github.com/reactos/reactos.git
synced 2025-02-25 09:50:02 +00:00
364 lines
No EOL
13 KiB
C
364 lines
No EOL
13 KiB
C
/*
|
|
* 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;
|
|
} |