/* * 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; }