/***************************************************************************
 * Copyright (c) 2024 Microsoft Corporation
 * Copyright (c) 2026-present Eclipse ThreadX contributors
 *
 * This program and the accompanying materials are made available under the
 * terms of the MIT License which is available at
 * https://opensource.org/licenses/MIT.
 *
 * SPDX-License-Identifier: MIT
 **************************************************************************/


/**************************************************************************/
/**************************************************************************/
/**                                                                       */
/** USBX Component                                                        */
/**                                                                       */
/**   Audio Class                                                         */
/**                                                                       */
/**************************************************************************/
/**************************************************************************/


/* Include necessary system files.  */

#define UX_SOURCE_CODE

#include "ux_api.h"
#include "ux_host_class_audio.h"
#include "ux_host_stack.h"


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _ux_host_class_audio_streaming_sampling_get         PORTABLE C      */
/*                                                           6.1.12       */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Chaoqiong Xiao, Microsoft Corporation                               */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function obtains successive sampling characteristics for the   */
/*    audio streaming channel.                                            */
/*                                                                        */
/*    Note only Audio 1.0 and RAW (PCM like) format is supported.         */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    audio                                 Pointer to audio class        */
/*    audio_sampling                        Pointer to audio sampling     */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    Completion Status                                                   */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _ux_host_stack_class_instance_verify  Verify instance is valid      */
/*    _ux_utility_descriptor_parse          Parse the descriptor          */
/*    _ux_host_mutex_on                     Get mutex                     */
/*    _ux_host_mutex_off                    Put mutex                     */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application                                                         */
/*    Audio Class                                                         */
/*                                                                        */
/**************************************************************************/
UINT  _ux_host_class_audio_streaming_sampling_get(UX_HOST_CLASS_AUDIO *audio, UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *audio_sampling)
{

UCHAR *                                  descriptor;
UX_INTERFACE_DESCRIPTOR                  interface_descriptor;
UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR audio_interface_descriptor;
ULONG                                    total_descriptor_length;
UINT                                     descriptor_length;
UINT                                     descriptor_type;
UINT                                     descriptor_subtype;
UINT                                     interface_found;
ULONG                                    lower_frequency;
ULONG                                    higher_frequency;
UINT                                     specific_frequency_count;
UINT                                     previous_match_found;

    /* If trace is enabled, insert this event into the trace buffer.  */
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_AUDIO_STREAMING_SAMPLING_GET, audio, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)

    /* Ensure the instance is valid.  */
    if (_ux_host_stack_class_instance_verify(_ux_system_host_class_audio_name, (VOID *) audio) != UX_SUCCESS)
    {

        /* Error trap. */
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);

        /* If trace is enabled, insert this event into the trace buffer.  */
        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, audio, 0, 0, UX_TRACE_ERRORS, 0, 0)

        return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
    }

    /* Protect thread reentry to this instance.  */
    _ux_host_mutex_on(&audio -> ux_host_class_audio_mutex);

    /* Reset the match flag.  */
    previous_match_found =  UX_FALSE;

    /* Get the descriptor to the entire configuration.  */
    descriptor =               audio -> ux_host_class_audio_configuration_descriptor;
    total_descriptor_length =  audio -> ux_host_class_audio_configuration_descriptor_length;

    /* Default is Interface descriptor not yet found.  */
    interface_found =  UX_FALSE;

    /* Scan the descriptor for the Audio Streaming interface.  */
    while (total_descriptor_length)
    {

        /* Gather the length, type and subtype of the descriptor.  */
        descriptor_length =   *descriptor;

        /* Make sure this descriptor has at least the minimum length.  */
        if (descriptor_length < 3)
        {

            /* Error trap. */
            _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);

            /* If trace is enabled, insert this event into the trace buffer.  */
            UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)

            /* Unprotect thread reentry to this instance.  */
            _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);

            return(UX_DESCRIPTOR_CORRUPTED);
        }

        descriptor_type =     *(descriptor + 1);
        descriptor_subtype =  *(descriptor + 2);

        /* Process relative to descriptor type.  */
        switch(descriptor_type)
        {


        case UX_INTERFACE_DESCRIPTOR_ITEM:

            /* Parse the interface descriptor and make it machine independent */
            _ux_utility_descriptor_parse(descriptor, _ux_system_interface_descriptor_structure,
                                            UX_INTERFACE_DESCRIPTOR_ENTRIES, (UCHAR *) &interface_descriptor);

            /* Ensure we have the correct interface for Audio streaming.  */
            if ((interface_descriptor.bInterfaceClass == UX_HOST_CLASS_AUDIO_CLASS) &&
                (interface_descriptor.bInterfaceSubClass == UX_HOST_CLASS_AUDIO_SUBCLASS_STREAMING))
            {

                /* Mark we have found it.  */
                interface_found =  UX_TRUE;
            }
            else
            {
                interface_found =  UX_FALSE;
            }
            break;


        case UX_HOST_CLASS_AUDIO_CS_INTERFACE:

            /* First make sure we have found the correct generic interface descriptor.  */
            if ((interface_found == UX_TRUE) && (descriptor_subtype == UX_HOST_CLASS_AUDIO_CS_FORMAT_TYPE))
            {

                /* Parse the FORMAT_TYPE descriptor and make it machine independent.  */
                _ux_utility_descriptor_parse(descriptor, _ux_system_class_audio_interface_descriptor_structure,
                                                UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_ENTRIES, (UCHAR *) &audio_interface_descriptor);

                /* This descriptor must refer to a PCM audio type.  */
                if (audio_interface_descriptor.bFormatType != UX_HOST_CLASS_AUDIO_FORMAT_TYPE_I)
                    break;

                /* If this is the first time we ask for a streaming interface characteristics
                   we return the first we find.  */
                if ((audio_sampling -> ux_host_class_audio_sampling_characteristics_channels == 0) &&
                    (audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution == 0))
                {

                    audio_sampling -> ux_host_class_audio_sampling_characteristics_channels =    audio_interface_descriptor.bNrChannels;
                    audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution =  audio_interface_descriptor.bBitResolution;

                    if (audio_interface_descriptor.bSamFreqType == 0)
                    {

                        if (descriptor_length < (UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 6))
                        {
                          /* Error trap. */
                          _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);

                          /* If trace is enabled, insert this event into the trace buffer.  */
                          UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)

                          /* Unprotect thread reentry to this instance.  */
                          _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);

                          return(UX_DESCRIPTOR_CORRUPTED);
                        }

                        /* The declaration of frequency is contiguous, so get the minimum and maximum */
                        audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low =
                                                                          (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH) |
                                                                          ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1)) << 8 |
                                                                          ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2)) << 16;

                        audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high =
                                                                          (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 3) |
                                                                          ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 4)) << 8 |
                                                                          ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 5)) << 16;
                    }
                    else
                    {

                        if (descriptor_length < (UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + (UINT)(3 * audio_interface_descriptor.bSamFreqType)))
                        {
                          /* Error trap. */
                          _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);

                          /* If trace is enabled, insert this event into the trace buffer.  */
                          UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)

                          /* Unprotect thread reentry to this instance.  */
                          _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);

                          return(UX_DESCRIPTOR_CORRUPTED);
                        }

                        /* The declaration of the frequency is declared as an array of specific values.
                           We take the first one here.  */
                        audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low =
                                                                          (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH ) |
                                                                          ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1 )) << 8 |
                                                                          ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2 )) << 16;

                        /* High and low frequencies are the same here.  */
                        audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high =  audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low;

                        /* Unprotect thread reentry to this instance.  */
                        _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);

                        /* We have found the first streaming characteristics.  */
                        return(UX_SUCCESS);
                    }
                }
                else
                {

                    /* This is not the second time we ask for the characteristics, we need
                       to find 1st where we left off and look at the next characteristics.  */
                    if ((audio_sampling -> ux_host_class_audio_sampling_characteristics_channels == audio_interface_descriptor.bNrChannels) &&
                        (audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution == audio_interface_descriptor.bBitResolution))
                    {

                          if (audio_interface_descriptor.bSamFreqType == 0)
                          {

                            if (descriptor_length < (UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 6))
                            {
                              /* Error trap. */
                              _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);

                              /* If trace is enabled, insert this event into the trace buffer.  */
                              UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)

                              /* Unprotect thread reentry to this instance.  */
                              _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);

                              return(UX_DESCRIPTOR_CORRUPTED);
                            }

                            /* The declaration of frequency is contiguous, so get the minimum and maximum.  */
                            lower_frequency =  (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH) |
                                               ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1)) << 8 |
                                               ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2)) << 16;

                            higher_frequency =  (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 3) |
                                                ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 4)) << 8 |
                                                ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 5)) << 16;

                            if ((audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low == lower_frequency) &&
                                (audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high == higher_frequency))
                            {

                                /* We have a match.  */
                                previous_match_found =  UX_TRUE;
                                break;
                            }
                        }
                        else
                        {

                            if (descriptor_length < UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + (UINT)(3 * audio_interface_descriptor.bSamFreqType))
                            {
                              /* Error trap. */
                              _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);

                              /* If trace is enabled, insert this event into the trace buffer.  */
                              UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)

                              /* Unprotect thread reentry to this instance.  */
                              _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);

                              return(UX_DESCRIPTOR_CORRUPTED);
                            }

                            /* The declaration of the frequency is declared as an array of specific values.  */
                            for (specific_frequency_count = 0; specific_frequency_count < audio_interface_descriptor.bSamFreqType; specific_frequency_count++)
                            {

                                lower_frequency =  (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + (specific_frequency_count * 3)) |
                                                   ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1 + (specific_frequency_count * 3))) << 8 |
                                                   ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2 + (specific_frequency_count * 3))) << 16;

                                /* Compare the frequency.  */
                                if (audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low == lower_frequency)
                                {

                                    previous_match_found =  UX_TRUE;
                                }
                                else
                                {

                                    /* Now the frequency is different, if we had a match before
                                       this becomes the next characteristics found.  */
                                    if (previous_match_found == UX_TRUE)
                                    {

                                        /* We return this characteristics.  */
                                        audio_sampling -> ux_host_class_audio_sampling_characteristics_channels =        audio_interface_descriptor.bNrChannels;
                                        audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution =      audio_interface_descriptor.bBitResolution;
                                        audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low =   lower_frequency;
                                        audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high =  lower_frequency;

                                        /* Unprotect thread reentry to this instance.  */
                                        _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);

                                        /* Return successful completion.  */
                                        return(UX_SUCCESS);
                                    }
                                }
                            }
                        }
                    }
                    else
                    {

                        /* We come here when the current characteristics does not match
                           the one given by the application. We need to check if we had found a match
                           before in which case, this is the one we need to return.  */
                        if (previous_match_found == UX_TRUE)
                        {

                            /* We return this characteristics.  */
                            audio_sampling -> ux_host_class_audio_sampling_characteristics_channels =    audio_interface_descriptor.bNrChannels;
                            audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution =  audio_interface_descriptor.bBitResolution;

                            if (audio_interface_descriptor.bSamFreqType == 0)
                            {

                                /* The declaration of frequency is contiguous, so get the minimum and maximum.  */
                                lower_frequency =  (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH) |
                                                   ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1)) << 8 |
                                                   ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2)) << 16;

                                higher_frequency =  (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 3) |
                                                    ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 4)) << 8 |
                                                    ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 5)) << 16;

                                audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low =   lower_frequency;
                                audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high =  higher_frequency;

                                /* Unprotect thread reentry to this instance.  */
                                _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);

                                /* Return successful completion.  */
                                return(UX_SUCCESS);
                            }
                            else
                            {

                                lower_frequency =  (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH) |
                                                   ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1)) << 8 |
                                                   ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2)) << 16;

                                audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low =   lower_frequency;
                                audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high =  lower_frequency;

                                /* Unprotect thread reentry to this instance.  */
                                _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);

                                /* Return successful completion.  */
                                return(UX_SUCCESS);
                            }
                        }
                    }
                }
            }
        }

        /* Verify the descriptor is still valid.  */
        if (descriptor_length > total_descriptor_length)
        {

            /* Error trap. */
            _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);

            /* If trace is enabled, insert this event into the trace buffer.  */
            UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)

            /* Unprotect thread reentry to this instance.  */
            _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);

            return(UX_DESCRIPTOR_CORRUPTED);
        }

        /* Jump to the next descriptor if we have not reached the end.  */
        descriptor +=  descriptor_length;

        /* And adjust the length left to parse in the descriptor.  */
        total_descriptor_length -=  descriptor_length;
    }

    /* Unprotect thread reentry to this instance.  */
    _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);

    /* Error trap. */
    _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_NO_ALTERNATE_SETTING);

    /* If trace is enabled, insert this event into the trace buffer.  */
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_NO_ALTERNATE_SETTING, audio, 0, 0, UX_TRACE_ERRORS, 0, 0)

    /* We get here when either the report descriptor has a problem or we could
       not find the right audio device.  */
    return(UX_NO_ALTERNATE_SETTING);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _uxe_host_class_audio_streaming_sampling_get        PORTABLE C      */
/*                                                           6.3.0        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Chaoqiong Xiao, Microsoft Corporation                               */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function checks errors in audio sampling characteristics get   */
/*    function call.                                                      */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    audio                                 Pointer to audio class        */
/*    audio_sampling                        Pointer to audio sampling     */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    Status                                                              */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _ux_host_class_audio_streaming_sampling_get                         */
/*                                          Get sampling characteristics  */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application                                                         */
/*                                                                        */
/**************************************************************************/
UINT  _uxe_host_class_audio_streaming_sampling_get(UX_HOST_CLASS_AUDIO *audio, UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *audio_sampling)
{

    /* Sanity checks.  */
    if ((audio == UX_NULL) || (audio_sampling == UX_NULL))
        return(UX_INVALID_PARAMETER);

    /* Invoke sampling characteristics get function.  */
    return(_ux_host_class_audio_streaming_sampling_get(audio, audio_sampling));
}
