reactos/lib/drivers/sound/libusbaudio/parser.c
Amine Khaldi 527f2f9057 [SHELL/EXPERIMENTS]
* Create a branch for some evul shell experiments.

svn path=/branches/shell-experiments/; revision=61927
2014-02-02 19:37:27 +00:00

391 lines
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"
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;
}