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