mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
[LIBUSBAUDIO]
- Start implementing a library which is used to parse USB configuration descriptors and construct KSFILTER_DESCRIPTOR structure, which is used with the kernel streaming driver (ks.sys) - The library will be used in USBAUDIO driver svn path=/trunk/; revision=58033
This commit is contained in:
parent
426a79eba3
commit
d697105863
6 changed files with 1160 additions and 0 deletions
13
reactos/lib/drivers/sound/libusbaudio/CMakeLists.txt
Normal file
13
reactos/lib/drivers/sound/libusbaudio/CMakeLists.txt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
add_definitions(
|
||||||
|
-DUNICODE -D_UNICODE
|
||||||
|
-DNDEBUG=1)
|
||||||
|
|
||||||
|
list(APPEND SOURCE
|
||||||
|
libusbaudio.c
|
||||||
|
parser.c
|
||||||
|
format.c)
|
||||||
|
|
||||||
|
add_library(libusbaudio ${SOURCE})
|
||||||
|
add_dependencies(libusbaudio bugcodes)
|
||||||
|
|
155
reactos/lib/drivers/sound/libusbaudio/format.c
Normal file
155
reactos/lib/drivers/sound/libusbaudio/format.c
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS Kernel Streaming
|
||||||
|
* FILE: lib/drivers/sound/libusbaudio/format.c
|
||||||
|
* PURPOSE: USB AUDIO Parser
|
||||||
|
* PROGRAMMER: Johannes Anderwald
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "priv.h"
|
||||||
|
|
||||||
|
KSDATARANGE StandardDataRange =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
sizeof(KSDATARANGE),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
{STATIC_KSDATAFORMAT_TYPE_AUDIO},
|
||||||
|
{STATIC_KSDATAFORMAT_SUBTYPE_ANALOG},
|
||||||
|
{STATIC_KSDATAFORMAT_SPECIFIER_NONE}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
GUID DataFormatTypeAudio = {STATIC_KSDATAFORMAT_TYPE_AUDIO};
|
||||||
|
GUID DataFormatSubTypePCM = {STATIC_KSDATAFORMAT_SUBTYPE_PCM};
|
||||||
|
GUID DataFormatSpecifierWaveFormat = {STATIC_KSDATAFORMAT_SPECIFIER_WAVEFORMATEX};
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_AssignDataRanges(
|
||||||
|
IN PUSBAUDIO_CONTEXT Context,
|
||||||
|
IN PUCHAR ConfigurationDescriptor,
|
||||||
|
IN ULONG ConfigurationDescriptorSize,
|
||||||
|
IN PKSFILTER_DESCRIPTOR FilterDescriptor,
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR * InterfaceDescriptors,
|
||||||
|
IN ULONG InterfaceCount,
|
||||||
|
IN ULONG InterfaceIndex,
|
||||||
|
IN PULONG TerminalIds)
|
||||||
|
{
|
||||||
|
ULONG Count, Index;
|
||||||
|
USBAUDIO_STATUS Status;
|
||||||
|
PUSB_COMMON_DESCRIPTOR * Descriptors;
|
||||||
|
PUSB_AUDIO_STREAMING_INTERFACE_DESCRIPTOR HeaderDescriptor;
|
||||||
|
PKSDATAFORMAT_WAVEFORMATEX WaveFormat;
|
||||||
|
PKSDATARANGE *DataRanges;
|
||||||
|
PKSPIN_DESCRIPTOR PinDescriptor;
|
||||||
|
PUSB_AUDIO_STREAMING_FORMAT_TYPE_1 FormatType;
|
||||||
|
|
||||||
|
/* count audio descriptors */
|
||||||
|
Status = UsbAudio_CountAudioDescriptors(ConfigurationDescriptor, ConfigurationDescriptorSize, InterfaceDescriptors, InterfaceCount, InterfaceIndex, &Count);
|
||||||
|
if (Status != UA_STATUS_SUCCESS || Count < 2)
|
||||||
|
{
|
||||||
|
/* ignore failure */
|
||||||
|
DPRINT1("[LIBUSBAUDIO] Failed to count descriptors with %x Count %lx for InterfaceIndex %lx InterfaceCount %lx\n", Status, Count, InterfaceIndex, InterfaceCount);
|
||||||
|
return UA_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create descriptor array */
|
||||||
|
Status = UsbAudio_CreateAudioDescriptorArray(Context, ConfigurationDescriptor, ConfigurationDescriptorSize, InterfaceDescriptors, InterfaceCount, InterfaceIndex, Count, &Descriptors);
|
||||||
|
if (Status != UA_STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
/* ignore failure */
|
||||||
|
DPRINT1("[LIBUSBAUDIO] Failed to create audio descriptor array Count %lx Status %x\n", Count, Status);
|
||||||
|
return UA_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get header */
|
||||||
|
HeaderDescriptor = (PUSB_AUDIO_STREAMING_INTERFACE_DESCRIPTOR)Descriptors[0];
|
||||||
|
if (!HeaderDescriptor || HeaderDescriptor->bDescriptorType != USB_AUDIO_STREAMING_INTERFACE_INTERFACE_DESCRIPTOR_TYPE ||
|
||||||
|
HeaderDescriptor->bDescriptorSubtype != 0x01)
|
||||||
|
{
|
||||||
|
/* header missing or mis-aligned */
|
||||||
|
DPRINT1("[LIBUSBAUDIO] Failed to retrieve audio header %p\n", HeaderDescriptor);
|
||||||
|
return UA_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: only PCM is supported */
|
||||||
|
if (HeaderDescriptor->wFormatTag != WAVE_FORMAT_PCM)
|
||||||
|
{
|
||||||
|
/* not supported */
|
||||||
|
DPRINT1("[LIBUSBAUDIO] Only PCM is currenly supported wFormatTag %x\n", HTONS(HeaderDescriptor->wFormatTag));
|
||||||
|
return UA_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check format descriptor */
|
||||||
|
FormatType = (PUSB_AUDIO_STREAMING_FORMAT_TYPE_1)Descriptors[1];
|
||||||
|
if (!FormatType || FormatType->bDescriptorType != USB_AUDIO_STREAMING_INTERFACE_INTERFACE_DESCRIPTOR_TYPE ||
|
||||||
|
FormatType->bDescriptorSubtype != 0x02 || FormatType->bFormatType != 0x01 || FormatType->bSamFreqType != 1)
|
||||||
|
{
|
||||||
|
/* unexpected format descriptor */
|
||||||
|
DPRINT1("[LIBUSBAUDIO] Unexpected format descriptor %p bDescriptorType %x bDescriptorSubtype %x bFormatType %x bSamFreqType %x\n", FormatType,
|
||||||
|
FormatType->bDescriptorType, FormatType->bDescriptorSubtype, FormatType->bFormatType, FormatType->bSamFreqType);
|
||||||
|
return UA_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* now search pin position */
|
||||||
|
for(Index = 0; Index < FilterDescriptor->PinDescriptorsCount; Index++)
|
||||||
|
{
|
||||||
|
//DPRINT("bTerminalLink %x Ids %lx\n", HeaderDescriptor->bTerminalLink, TerminalIds[Index]);
|
||||||
|
if (HeaderDescriptor->bTerminalLink == TerminalIds[Index])
|
||||||
|
{
|
||||||
|
/* alloc wave format */
|
||||||
|
WaveFormat = (PKSDATAFORMAT_WAVEFORMATEX)Context->Alloc(sizeof(KSDATAFORMAT_WAVEFORMATEX));
|
||||||
|
if (!WaveFormat)
|
||||||
|
return UA_STATUS_NO_MEMORY;
|
||||||
|
|
||||||
|
/* init wave format */
|
||||||
|
WaveFormat->WaveFormatEx.cbSize = sizeof(WAVEFORMATEX);
|
||||||
|
WaveFormat->WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
|
WaveFormat->WaveFormatEx.nChannels = FormatType->bNrChannels;
|
||||||
|
WaveFormat->WaveFormatEx.wBitsPerSample = FormatType->bBitResolution;
|
||||||
|
WaveFormat->WaveFormatEx.nSamplesPerSec = ((FormatType->tSamFreq[2] & 0xFF) << 16) | ((FormatType->tSamFreq[1] & 0xFF)<< 8) | (FormatType->tSamFreq[0] & 0xFF);
|
||||||
|
WaveFormat->WaveFormatEx.nBlockAlign = (WaveFormat->WaveFormatEx.nChannels * WaveFormat->WaveFormatEx.wBitsPerSample) / 8;
|
||||||
|
WaveFormat->WaveFormatEx.nAvgBytesPerSec = WaveFormat->WaveFormatEx.nSamplesPerSec * WaveFormat->WaveFormatEx.nBlockAlign;
|
||||||
|
|
||||||
|
/* FIXME apply padding */
|
||||||
|
WaveFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT_WAVEFORMATEX);
|
||||||
|
Context->Copy(&WaveFormat->DataFormat.MajorFormat, &DataFormatTypeAudio, sizeof(GUID));
|
||||||
|
Context->Copy(&WaveFormat->DataFormat.SubFormat, &DataFormatSubTypePCM, sizeof(GUID));
|
||||||
|
Context->Copy(&WaveFormat->DataFormat.Specifier, &DataFormatSpecifierWaveFormat, sizeof(GUID));
|
||||||
|
|
||||||
|
//C_ASSERT(sizeof(WAVEFORMATEX) + sizeof(KSDATAFORMAT) == 82);
|
||||||
|
|
||||||
|
/* get corresponding pin descriptor */
|
||||||
|
PinDescriptor = (PKSPIN_DESCRIPTOR)&FilterDescriptor->PinDescriptors[Index].PinDescriptor;
|
||||||
|
|
||||||
|
/* alloc data range */
|
||||||
|
DataRanges = (PKSDATARANGE*)Context->Alloc(sizeof(PKSDATARANGE) * (PinDescriptor->DataRangesCount+1));
|
||||||
|
if (!DataRanges)
|
||||||
|
{
|
||||||
|
Context->Free(WaveFormat);
|
||||||
|
return UA_STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PinDescriptor->DataRangesCount)
|
||||||
|
{
|
||||||
|
/* copy old range */
|
||||||
|
Context->Copy(DataRanges, (PVOID)PinDescriptor->DataRanges, sizeof(PKSDATARANGE) * PinDescriptor->DataRangesCount);
|
||||||
|
|
||||||
|
/* free old range */
|
||||||
|
Context->Free((PVOID)PinDescriptor->DataRanges);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assign new range */
|
||||||
|
PinDescriptor->DataRanges = DataRanges;
|
||||||
|
DataRanges[PinDescriptor->DataRangesCount] = (PKSDATARANGE)WaveFormat;
|
||||||
|
PinDescriptor->DataRangesCount++;
|
||||||
|
return UA_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return UA_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
364
reactos/lib/drivers/sound/libusbaudio/libusbaudio.c
Normal file
364
reactos/lib/drivers/sound/libusbaudio/libusbaudio.c
Normal file
|
@ -0,0 +1,364 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
56
reactos/lib/drivers/sound/libusbaudio/libusbaudio.h
Normal file
56
reactos/lib/drivers/sound/libusbaudio/libusbaudio.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
UA_STATUS_SUCCESS = 0,
|
||||||
|
UA_STATUS_NOTINITIALIZED,
|
||||||
|
UA_STATUS_NOT_IMPLEMENTED,
|
||||||
|
UA_STATUS_NO_MORE_DEVICES,
|
||||||
|
UA_STATUS_MORE_ENTRIES,
|
||||||
|
UA_STATUS_INVALID_PARAMETER,
|
||||||
|
UA_STATUS_UNSUCCESSFUL,
|
||||||
|
UA_STATUS_NO_MEMORY
|
||||||
|
}USBAUDIO_STATUS;
|
||||||
|
|
||||||
|
typedef PVOID (*PUSBAUDIO_ALLOC)(
|
||||||
|
IN ULONG NumberOfBytes);
|
||||||
|
|
||||||
|
typedef VOID (*PUSBAUDIO_FREE)(
|
||||||
|
IN PVOID Block);
|
||||||
|
|
||||||
|
typedef VOID (*PUSBAUDIO_COPY)(
|
||||||
|
IN PVOID Dst,
|
||||||
|
IN PVOID Src,
|
||||||
|
IN ULONG Length);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ULONG Size;
|
||||||
|
PVOID Context;
|
||||||
|
|
||||||
|
PUSBAUDIO_ALLOC Alloc;
|
||||||
|
PUSBAUDIO_FREE Free;
|
||||||
|
PUSBAUDIO_COPY Copy;
|
||||||
|
|
||||||
|
|
||||||
|
}USBAUDIO_CONTEXT, *PUSBAUDIO_CONTEXT;
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_InitializeContext(
|
||||||
|
IN PUSBAUDIO_CONTEXT Context,
|
||||||
|
IN PUSBAUDIO_ALLOC Alloc,
|
||||||
|
IN PUSBAUDIO_FREE Free,
|
||||||
|
IN PUSBAUDIO_COPY Copy);
|
||||||
|
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_ParseConfigurationDescriptor(
|
||||||
|
IN PUSBAUDIO_CONTEXT Context,
|
||||||
|
IN PUCHAR ConfigurationDescriptor,
|
||||||
|
IN ULONG ConfigurationDescriptorSize);
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_GetFilter(
|
||||||
|
IN PUSBAUDIO_CONTEXT Context,
|
||||||
|
OUT PVOID * OutFilterDescriptor);
|
||||||
|
|
390
reactos/lib/drivers/sound/libusbaudio/parser.c
Normal file
390
reactos/lib/drivers/sound/libusbaudio/parser.c
Normal file
|
@ -0,0 +1,390 @@
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_CountDescriptors(
|
||||||
|
IN PUCHAR ConfigurationDescriptor,
|
||||||
|
IN ULONG ConfigurationDescriptorLength,
|
||||||
|
IN UCHAR DescriptorType,
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR StartPosition,
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR EndPosition,
|
||||||
|
OUT PULONG DescriptorCount)
|
||||||
|
{
|
||||||
|
PUSB_COMMON_DESCRIPTOR Descriptor;
|
||||||
|
ULONG Count = 0;
|
||||||
|
|
||||||
|
/* init result */
|
||||||
|
*DescriptorCount = 0;
|
||||||
|
|
||||||
|
/* enumerate descriptors */
|
||||||
|
Descriptor = StartPosition;
|
||||||
|
if (Descriptor == NULL)
|
||||||
|
Descriptor = (PUSB_COMMON_DESCRIPTOR)ConfigurationDescriptor;
|
||||||
|
|
||||||
|
if (EndPosition == NULL)
|
||||||
|
EndPosition = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptorLength);
|
||||||
|
|
||||||
|
|
||||||
|
while((ULONG_PTR)Descriptor < ((ULONG_PTR)EndPosition))
|
||||||
|
{
|
||||||
|
if (!Descriptor->bLength || !Descriptor->bDescriptorType)
|
||||||
|
{
|
||||||
|
/* bogus descriptor */
|
||||||
|
return UA_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Descriptor->bDescriptorType == DescriptorType)
|
||||||
|
{
|
||||||
|
/* found descriptor */
|
||||||
|
Count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* move to next descriptor */
|
||||||
|
Descriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)Descriptor + Descriptor->bLength);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store result */
|
||||||
|
*DescriptorCount = Count;
|
||||||
|
return UA_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_GetDescriptors(
|
||||||
|
IN PUCHAR ConfigurationDescriptor,
|
||||||
|
IN ULONG ConfigurationDescriptorLength,
|
||||||
|
IN UCHAR DescriptorType,
|
||||||
|
IN ULONG DescriptorCount,
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR StartPosition,
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR EndPosition,
|
||||||
|
OUT PUSB_COMMON_DESCRIPTOR *Descriptors)
|
||||||
|
{
|
||||||
|
PUSB_COMMON_DESCRIPTOR Descriptor;
|
||||||
|
ULONG Count = 0;
|
||||||
|
|
||||||
|
/* enumerate descriptors */
|
||||||
|
Descriptor = StartPosition;
|
||||||
|
if (Descriptor == NULL)
|
||||||
|
Descriptor = (PUSB_COMMON_DESCRIPTOR)ConfigurationDescriptor;
|
||||||
|
|
||||||
|
if (EndPosition == NULL)
|
||||||
|
EndPosition = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptorLength);
|
||||||
|
|
||||||
|
while((ULONG_PTR)Descriptor < ((ULONG_PTR)EndPosition))
|
||||||
|
{
|
||||||
|
if (!Descriptor->bLength || !Descriptor->bDescriptorType)
|
||||||
|
{
|
||||||
|
/* bogus descriptor */
|
||||||
|
return UA_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Descriptor->bDescriptorType == DescriptorType)
|
||||||
|
{
|
||||||
|
/* found descriptor */
|
||||||
|
if (Count >= DescriptorCount)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* store result */
|
||||||
|
Descriptors[Count] = Descriptor;
|
||||||
|
Count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* move to next descriptor */
|
||||||
|
Descriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)Descriptor + Descriptor->bLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* done */
|
||||||
|
return UA_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_CountInterfaceDescriptors(
|
||||||
|
IN PUCHAR ConfigurationDescriptor,
|
||||||
|
IN ULONG ConfigurationDescriptorLength,
|
||||||
|
OUT PULONG DescriptorCount)
|
||||||
|
{
|
||||||
|
return UsbAudio_CountDescriptors(ConfigurationDescriptor, ConfigurationDescriptorLength, USB_INTERFACE_DESCRIPTOR_TYPE, NULL, NULL, DescriptorCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_CreateDescriptorArray(
|
||||||
|
IN PUSBAUDIO_CONTEXT Context,
|
||||||
|
IN PUCHAR ConfigurationDescriptor,
|
||||||
|
IN ULONG ConfigurationDescriptorLength,
|
||||||
|
IN ULONG ArrayLength,
|
||||||
|
IN ULONG DescriptorType,
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR StartPosition,
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR EndPosition,
|
||||||
|
OUT PUSB_COMMON_DESCRIPTOR ** Array)
|
||||||
|
{
|
||||||
|
USBAUDIO_STATUS Status;
|
||||||
|
PUSB_COMMON_DESCRIPTOR * Descriptors;
|
||||||
|
|
||||||
|
/* zero result */
|
||||||
|
*Array = NULL;
|
||||||
|
|
||||||
|
/* first allocate descriptor array */
|
||||||
|
Descriptors = (PUSB_COMMON_DESCRIPTOR*)Context->Alloc(sizeof(PUSB_COMMON_DESCRIPTOR) * ArrayLength);
|
||||||
|
if (!Descriptors)
|
||||||
|
{
|
||||||
|
/* no memory */
|
||||||
|
return UA_STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* extract control terminal descriptors */
|
||||||
|
Status = UsbAudio_GetDescriptors(ConfigurationDescriptor, ConfigurationDescriptorLength, DescriptorType, ArrayLength, StartPosition, EndPosition, Descriptors);
|
||||||
|
if (Status != UA_STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
/* failed */
|
||||||
|
Context->Free(Descriptors);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store result */
|
||||||
|
*Array = Descriptors;
|
||||||
|
return UA_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_CountAudioDescriptors(
|
||||||
|
IN PUCHAR ConfigurationDescriptor,
|
||||||
|
IN ULONG ConfigurationDescriptorLength,
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR * InterfaceDescriptors,
|
||||||
|
IN ULONG InterfaceDescriptorCount,
|
||||||
|
IN ULONG InterfaceDescriptorIndex,
|
||||||
|
OUT PULONG DescriptorCount)
|
||||||
|
{
|
||||||
|
if (InterfaceDescriptorIndex + 1 == InterfaceDescriptorCount)
|
||||||
|
return UsbAudio_CountDescriptors(ConfigurationDescriptor, ConfigurationDescriptorLength, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE, InterfaceDescriptors[InterfaceDescriptorIndex], NULL, DescriptorCount);
|
||||||
|
else
|
||||||
|
return UsbAudio_CountDescriptors(ConfigurationDescriptor, ConfigurationDescriptorLength, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE, InterfaceDescriptors[InterfaceDescriptorIndex], InterfaceDescriptors[InterfaceDescriptorIndex + 1], DescriptorCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_CreateInterfaceDescriptorsArray(
|
||||||
|
IN PUSBAUDIO_CONTEXT Context,
|
||||||
|
IN PUCHAR ConfigurationDescriptor,
|
||||||
|
IN ULONG ConfigurationDescriptorLength,
|
||||||
|
IN ULONG ArrayLength,
|
||||||
|
OUT PUSB_COMMON_DESCRIPTOR ** Array)
|
||||||
|
{
|
||||||
|
return UsbAudio_CreateDescriptorArray(Context, ConfigurationDescriptor, ConfigurationDescriptorLength, ArrayLength, USB_INTERFACE_DESCRIPTOR_TYPE, NULL, NULL, Array);
|
||||||
|
}
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_CreateAudioDescriptorArray(
|
||||||
|
IN PUSBAUDIO_CONTEXT Context,
|
||||||
|
IN PUCHAR ConfigurationDescriptor,
|
||||||
|
IN ULONG ConfigurationDescriptorLength,
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR * InterfaceDescriptors,
|
||||||
|
IN ULONG InterfaceDescriptorCount,
|
||||||
|
IN ULONG InterfaceDescriptorIndex,
|
||||||
|
IN ULONG ArrayLength,
|
||||||
|
OUT PUSB_COMMON_DESCRIPTOR ** Array)
|
||||||
|
{
|
||||||
|
if (InterfaceDescriptorIndex + 1 == InterfaceDescriptorCount)
|
||||||
|
return UsbAudio_CreateDescriptorArray(Context, ConfigurationDescriptor, ConfigurationDescriptorLength, ArrayLength, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE, InterfaceDescriptors[InterfaceDescriptorIndex], NULL, Array);
|
||||||
|
else
|
||||||
|
return UsbAudio_CreateDescriptorArray(Context, ConfigurationDescriptor, ConfigurationDescriptorLength, ArrayLength, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE,
|
||||||
|
InterfaceDescriptors[InterfaceDescriptorIndex], InterfaceDescriptors[InterfaceDescriptorIndex + 1], Array);
|
||||||
|
}
|
||||||
|
|
||||||
|
PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR
|
||||||
|
UsbAudio_GetTerminalDescriptorById(
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR *Descriptors,
|
||||||
|
IN ULONG DescriptorCount,
|
||||||
|
IN ULONG TerminalId)
|
||||||
|
{
|
||||||
|
ULONG Index;
|
||||||
|
PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR Descriptor;
|
||||||
|
|
||||||
|
for(Index = 0; Index < DescriptorCount; Index++)
|
||||||
|
{
|
||||||
|
/* get descriptor */
|
||||||
|
Descriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)Descriptors[Index];
|
||||||
|
|
||||||
|
/* is it an input / output terminal */
|
||||||
|
DPRINT("Descriptor %p Type %x SubType %x TerminalID %x\n", Descriptor, Descriptor->bDescriptorType, Descriptor->bDescriptorSubtype, Descriptor->bTerminalID);
|
||||||
|
if (Descriptor->bDescriptorSubtype != USB_AUDIO_INPUT_TERMINAL && Descriptor->bDescriptorSubtype != USB_AUDIO_OUTPUT_TERMINAL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (Descriptor->bTerminalID == TerminalId)
|
||||||
|
return Descriptor;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG
|
||||||
|
UsbAudio_GetAudioControlInterfaceIndex(
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR * InterfaceDescriptors,
|
||||||
|
IN ULONG DescriptorCount)
|
||||||
|
{
|
||||||
|
ULONG Index;
|
||||||
|
PUSB_INTERFACE_DESCRIPTOR Descriptor;
|
||||||
|
|
||||||
|
|
||||||
|
for(Index = 0; Index < DescriptorCount; Index++)
|
||||||
|
{
|
||||||
|
/* get descriptor */
|
||||||
|
Descriptor = (PUSB_INTERFACE_DESCRIPTOR)InterfaceDescriptors[Index];
|
||||||
|
ASSERT(Descriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
|
||||||
|
ASSERT(Descriptor->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
|
||||||
|
|
||||||
|
/* compare interface class */
|
||||||
|
if (Descriptor->bInterfaceClass == 0x01 && Descriptor->bInterfaceSubClass == 0x01)
|
||||||
|
{
|
||||||
|
/* found audio control class */
|
||||||
|
return Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not found */
|
||||||
|
return MAXULONG;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_FindTerminalDescriptorAtIndexWithSubtypeAndTerminalType(
|
||||||
|
IN ULONG DescriptorCount,
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR *Descriptors,
|
||||||
|
IN ULONG DescriptorIndex,
|
||||||
|
IN UCHAR Subtype,
|
||||||
|
IN USHORT TerminalType,
|
||||||
|
OUT PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR * OutDescriptor,
|
||||||
|
OUT PULONG OutDescriptorIndex)
|
||||||
|
{
|
||||||
|
ULONG Index;
|
||||||
|
ULONG Count = 0;
|
||||||
|
PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR CurrentDescriptor;
|
||||||
|
|
||||||
|
for(Index = 0; Index < DescriptorCount; Index++)
|
||||||
|
{
|
||||||
|
/* get current descriptor */
|
||||||
|
CurrentDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)Descriptors[Index];
|
||||||
|
ASSERT(CurrentDescriptor->bDescriptorType == USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE);
|
||||||
|
|
||||||
|
if (CurrentDescriptor->bDescriptorSubtype == Subtype &&
|
||||||
|
(TerminalType == USB_AUDIO_UNDEFINED_TERMINAL_TYPE || CurrentDescriptor->wTerminalType == TerminalType))
|
||||||
|
{
|
||||||
|
/* found descriptor */
|
||||||
|
if (Count == DescriptorIndex)
|
||||||
|
{
|
||||||
|
/* store result */
|
||||||
|
*OutDescriptor = CurrentDescriptor;
|
||||||
|
*OutDescriptorIndex = Index;
|
||||||
|
return UA_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not found */
|
||||||
|
return UA_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_AssignTerminalIds(
|
||||||
|
IN PUSBAUDIO_CONTEXT Context,
|
||||||
|
IN ULONG TerminalIdsLength,
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR * TerminalIds,
|
||||||
|
OUT PULONG PinArray,
|
||||||
|
OUT PULONG PinArrayCount)
|
||||||
|
{
|
||||||
|
ULONG Consumed = 0;
|
||||||
|
ULONG PinIndex = 0;
|
||||||
|
ULONG Index, DescriptorIndex;
|
||||||
|
PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR Descriptor;
|
||||||
|
USBAUDIO_STATUS Status;
|
||||||
|
|
||||||
|
/* FIXME: support more than 32 terminals */
|
||||||
|
ASSERT(TerminalIdsLength <= 32);
|
||||||
|
|
||||||
|
/* first search for an output terminal with streaming type */
|
||||||
|
Status = UsbAudio_FindTerminalDescriptorAtIndexWithSubtypeAndTerminalType(TerminalIdsLength, TerminalIds, 0, USB_AUDIO_OUTPUT_TERMINAL, USB_AUDIO_STREAMING_TERMINAL_TYPE, &Descriptor, &DescriptorIndex);
|
||||||
|
if (Status == UA_STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
/* found output terminal */
|
||||||
|
PinArray[PinIndex] = Descriptor->bTerminalID;
|
||||||
|
Consumed |= 1 << DescriptorIndex;
|
||||||
|
DPRINT("Assigned TerminalId %x to PinIndex %lx Consumed %lx DescriptorIndex %lx\n", Descriptor->bTerminalID, PinIndex, Consumed, DescriptorIndex);
|
||||||
|
PinIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now search for an input terminal with streaming type */
|
||||||
|
Status = UsbAudio_FindTerminalDescriptorAtIndexWithSubtypeAndTerminalType(TerminalIdsLength, TerminalIds, 0, USB_AUDIO_INPUT_TERMINAL, USB_AUDIO_STREAMING_TERMINAL_TYPE, &Descriptor, &DescriptorIndex);
|
||||||
|
if (Status == UA_STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
/* found output terminal */
|
||||||
|
PinArray[PinIndex] = Descriptor->bTerminalID;
|
||||||
|
Consumed |= 1 << DescriptorIndex;
|
||||||
|
PinIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now assign all other input terminals */
|
||||||
|
Index = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* find an input terminal */
|
||||||
|
Status = UsbAudio_FindTerminalDescriptorAtIndexWithSubtypeAndTerminalType(TerminalIdsLength, TerminalIds, Index, USB_AUDIO_INPUT_TERMINAL, USB_AUDIO_UNDEFINED_TERMINAL_TYPE, &Descriptor, &DescriptorIndex);
|
||||||
|
if (Status != UA_STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
/* no more items */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Consumed & (1 << DescriptorIndex))
|
||||||
|
{
|
||||||
|
/* terminal has already been assigned to an pin */
|
||||||
|
Index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assign terminal */
|
||||||
|
PinArray[PinIndex] = Descriptor->bTerminalID;
|
||||||
|
Consumed |= 1 << DescriptorIndex;
|
||||||
|
PinIndex++;
|
||||||
|
Index++;
|
||||||
|
|
||||||
|
}while(Status == UA_STATUS_SUCCESS);
|
||||||
|
|
||||||
|
|
||||||
|
/* now assign all other output terminals */
|
||||||
|
Index = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* find an input terminal */
|
||||||
|
Status = UsbAudio_FindTerminalDescriptorAtIndexWithSubtypeAndTerminalType(TerminalIdsLength, TerminalIds, Index, USB_AUDIO_OUTPUT_TERMINAL, USB_AUDIO_UNDEFINED_TERMINAL_TYPE, &Descriptor, &DescriptorIndex);
|
||||||
|
if (Status != UA_STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
/* no more items */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Consumed & (1 << DescriptorIndex))
|
||||||
|
{
|
||||||
|
/* terminal has already been assigned to an pin */
|
||||||
|
Index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assign terminal */
|
||||||
|
PinArray[PinIndex] = Descriptor->bTerminalID;
|
||||||
|
Consumed |= 1 << DescriptorIndex;
|
||||||
|
PinIndex++;
|
||||||
|
Index++;
|
||||||
|
|
||||||
|
}while(Status == UA_STATUS_SUCCESS);
|
||||||
|
|
||||||
|
/* store pin count */
|
||||||
|
DPRINT("Consumed %lx PinIndex %lu\n", Consumed, PinIndex);
|
||||||
|
*PinArrayCount = PinIndex;
|
||||||
|
return UA_STATUS_SUCCESS;
|
||||||
|
}
|
182
reactos/lib/drivers/sound/libusbaudio/priv.h
Normal file
182
reactos/lib/drivers/sound/libusbaudio/priv.h
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <pseh/pseh2.h>
|
||||||
|
#include <ntddk.h>
|
||||||
|
|
||||||
|
#include <windef.h>
|
||||||
|
#define NOBITMAP
|
||||||
|
#include <mmreg.h>
|
||||||
|
#include <ks.h>
|
||||||
|
#include <ksmedia.h>
|
||||||
|
#include <mmreg.h>
|
||||||
|
#include <mmsystem.h>
|
||||||
|
#include "Usb100.h"
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include "libusbaudio.h"
|
||||||
|
|
||||||
|
#define USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE (0x24)
|
||||||
|
#define USB_AUDIO_STREAMING_INTERFACE_INTERFACE_DESCRIPTOR_TYPE (0x24)
|
||||||
|
|
||||||
|
#define USB_AUDIO_INPUT_TERMINAL (0x02)
|
||||||
|
#define USB_AUDIO_OUTPUT_TERMINAL (0x03)
|
||||||
|
|
||||||
|
/* Universal Serial Bus Device Class Definition for Terminal Types Section A 1.1 */
|
||||||
|
#define USB_AUDIO_PCM_DATA_FORMAT (0x01)
|
||||||
|
#define USB_AUDIO_PCM8_DATA_FORMAT (0x02)
|
||||||
|
#define USB_AUDIO_IEEE_FLOAT_DATA_FORMAT (0x03)
|
||||||
|
#define USB_AUDIO_ALAW_DATA_FORMAT (0x04)
|
||||||
|
#define USB_AUDIO_MULAW_DATA_FORMAT (0x05)
|
||||||
|
|
||||||
|
/* Universal Serial Bus Device Class Definition for Terminal Types Section A 1.1 */
|
||||||
|
#define USB_AUDIO_DATA_FORMAT_TYPE_1 (0x01)
|
||||||
|
#define USB_AUDIO_DATA_FORMAT_TYPE_2 (0x02)
|
||||||
|
#define USB_AUDIO_DATA_FORMAT_TYPE_3 (0x03)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Universal Serial Bus Device Class Definition for Terminal Types Section 2.2 */
|
||||||
|
#define USB_AUDIO_STREAMING_TERMINAL_TYPE (0x0101)
|
||||||
|
|
||||||
|
#define USB_AUDIO_MICROPHONE_TERMINAL_TYPE (0x0201)
|
||||||
|
#define USB_AUDIO_DESKTOP_MICROPHONE_TERMINAL_TYPE (0x0202)
|
||||||
|
#define USB_AUDIO_PERSONAL_MICROPHONE_TERMINAL_TYPE (0x0203)
|
||||||
|
#define USB_AUDIO_OMMNI_MICROPHONE_TERMINAL_TYPE (0x0204)
|
||||||
|
#define USB_AUDIO_ARRAY_MICROPHONE_TERMINAL_TYPE (0x0205)
|
||||||
|
#define USB_AUDIO_ARRAY_PROCESSING_MICROPHONE_TERMINAL_TYPE (0x0206)
|
||||||
|
|
||||||
|
#define USB_AUDIO_SPEAKER_TERMINAL_TYPE (0x0301)
|
||||||
|
#define USB_HEADPHONES_SPEAKER_TERMINAL_TYPE (0x0302)
|
||||||
|
#define USB_AUDIO_HMDA_TERMINAL_TYPE (0x0303)
|
||||||
|
#define USB_AUDIO_DESKTOP_SPEAKER_TERMINAL_TYPE (0x0304)
|
||||||
|
#define USB_AUDIO_ROOM_SPEAKER_TERMINAL_TYPE (0x0305)
|
||||||
|
#define USB_AUDIO_COMMUNICATION_SPEAKER_TERMINAL_TYPE (0x0306)
|
||||||
|
#define USB_AUDIO_SUBWOOFER_TERMINAL_TYPE (0x0307)
|
||||||
|
#define USB_AUDIO_UNDEFINED_TERMINAL_TYPE (0xFFFF)
|
||||||
|
|
||||||
|
#define HTONS(x) ( ( (((unsigned short)(x)) >>8) & 0xff) | \
|
||||||
|
((((unsigned short)(x)) & 0xff)<<8) )
|
||||||
|
|
||||||
|
#include <pshpack1.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UCHAR bLength;
|
||||||
|
UCHAR bDescriptorType;
|
||||||
|
UCHAR bDescriptorSubtype;
|
||||||
|
UCHAR bTerminalID;
|
||||||
|
USHORT wTerminalType;
|
||||||
|
UCHAR bAssocTerminal;
|
||||||
|
UCHAR bSourceID;
|
||||||
|
UCHAR iTerminal;
|
||||||
|
}USB_AUDIO_CONTROL_OUTPUT_TERMINAL_DESCRIPTOR, *PUSB_AUDIO_CONTROL_OUTPUT_TERMINAL_DESCRIPTOR;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UCHAR bLength;
|
||||||
|
UCHAR bDescriptorType;
|
||||||
|
UCHAR bDescriptorSubtype;
|
||||||
|
UCHAR bTerminalID;
|
||||||
|
USHORT wTerminalType;
|
||||||
|
UCHAR bAssocTerminal;
|
||||||
|
UCHAR bNrChannels;
|
||||||
|
USHORT wChannelConfig;
|
||||||
|
UCHAR iChannelNames;
|
||||||
|
UCHAR iTerminal;
|
||||||
|
}USB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR, *PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UCHAR bLength;
|
||||||
|
UCHAR bDescriptorType;
|
||||||
|
UCHAR bDescriptorSubtype;
|
||||||
|
UCHAR bTerminalLink;
|
||||||
|
UCHAR bDelay;
|
||||||
|
USHORT wFormatTag;
|
||||||
|
}USB_AUDIO_STREAMING_INTERFACE_DESCRIPTOR, *PUSB_AUDIO_STREAMING_INTERFACE_DESCRIPTOR;
|
||||||
|
C_ASSERT(sizeof(USB_AUDIO_STREAMING_INTERFACE_DESCRIPTOR) == 0x07);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UCHAR bLength;
|
||||||
|
UCHAR bDescriptorType;
|
||||||
|
UCHAR bDescriptorSubtype;
|
||||||
|
UCHAR bFormatType;
|
||||||
|
UCHAR bNrChannels;
|
||||||
|
UCHAR bSubframeSize;
|
||||||
|
UCHAR bBitResolution;
|
||||||
|
UCHAR bSamFreqType;
|
||||||
|
UCHAR tSamFreq[3];
|
||||||
|
}USB_AUDIO_STREAMING_FORMAT_TYPE_1, *PUSB_AUDIO_STREAMING_FORMAT_TYPE_1;
|
||||||
|
C_ASSERT(sizeof(USB_AUDIO_STREAMING_FORMAT_TYPE_1) == 0x0B);
|
||||||
|
|
||||||
|
/* format.c */
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_AssignDataRanges(
|
||||||
|
IN PUSBAUDIO_CONTEXT Context,
|
||||||
|
IN PUCHAR ConfigurationDescriptor,
|
||||||
|
IN ULONG ConfigurationDescriptorSize,
|
||||||
|
IN PKSFILTER_DESCRIPTOR FilterDescriptor,
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR * InterfaceDescriptors,
|
||||||
|
IN ULONG InterfaceCount,
|
||||||
|
IN ULONG InterfaceIndex,
|
||||||
|
IN PULONG TerminalIds);
|
||||||
|
|
||||||
|
|
||||||
|
/* parser.c */
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_CountInterfaceDescriptors(
|
||||||
|
IN PUCHAR ConfigurationDescriptor,
|
||||||
|
IN ULONG ConfigurationDescriptorLength,
|
||||||
|
OUT PULONG DescriptorCount);
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_CreateInterfaceDescriptorsArray(
|
||||||
|
IN PUSBAUDIO_CONTEXT Context,
|
||||||
|
IN PUCHAR ConfigurationDescriptor,
|
||||||
|
IN ULONG ConfigurationDescriptorLength,
|
||||||
|
IN ULONG ArrayLength,
|
||||||
|
OUT PUSB_COMMON_DESCRIPTOR ** Array);
|
||||||
|
|
||||||
|
ULONG
|
||||||
|
UsbAudio_GetAudioControlInterfaceIndex(
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR * InterfaceDescriptors,
|
||||||
|
IN ULONG DescriptorCount);
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_CountAudioDescriptors(
|
||||||
|
IN PUCHAR ConfigurationDescriptor,
|
||||||
|
IN ULONG ConfigurationDescriptorLength,
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR * InterfaceDescriptors,
|
||||||
|
IN ULONG InterfaceDescriptorCount,
|
||||||
|
IN ULONG InterfaceDescriptorIndex,
|
||||||
|
OUT PULONG DescriptorCount);
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_CreateAudioDescriptorArray(
|
||||||
|
IN PUSBAUDIO_CONTEXT Context,
|
||||||
|
IN PUCHAR ConfigurationDescriptor,
|
||||||
|
IN ULONG ConfigurationDescriptorLength,
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR * InterfaceDescriptors,
|
||||||
|
IN ULONG InterfaceDescriptorCount,
|
||||||
|
IN ULONG InterfaceDescriptorIndex,
|
||||||
|
IN ULONG ArrayLength,
|
||||||
|
OUT PUSB_COMMON_DESCRIPTOR ** Array);
|
||||||
|
|
||||||
|
USBAUDIO_STATUS
|
||||||
|
UsbAudio_AssignTerminalIds(
|
||||||
|
IN PUSBAUDIO_CONTEXT Context,
|
||||||
|
IN ULONG TerminalIdsLength,
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR * TerminalIds,
|
||||||
|
OUT PULONG PinArray,
|
||||||
|
OUT PULONG PinArrayCount);
|
||||||
|
|
||||||
|
PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR
|
||||||
|
UsbAudio_GetTerminalDescriptorById(
|
||||||
|
IN PUSB_COMMON_DESCRIPTOR *Descriptors,
|
||||||
|
IN ULONG DescriptorCount,
|
||||||
|
IN ULONG TerminalId);
|
||||||
|
|
Loading…
Reference in a new issue