C++程序  |  3918行  |  150.34 KB

/*
 * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Code Aurora Forum, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#define LOG_TAG "alsa_ucm"
//#define LOG_NDDEBUG 0

#ifdef ANDROID
/* definitions for Android logging */
#include <utils/Log.h>
#include <cutils/properties.h>
#else /* ANDROID */
#include <math.h>
#define strlcat g_strlcat
#define strlcpy g_strlcpy
#define ALOGI(...)      fprintf(stdout, __VA_ARGS__)
#define ALOGE(...)      fprintf(stderr, __VA_ARGS__)
#define ALOGV(...)      fprintf(stderr, __VA_ARGS__)
#define ALOGD(...)      fprintf(stderr, __VA_ARGS__)
#endif /* ANDROID */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/poll.h>
#include <stdint.h>
#include <dlfcn.h>

#include <linux/ioctl.h>
#include "msm8960_use_cases.h"
#if defined(QC_PROP)
    static void (*acdb_send_audio_cal)(int,int);
    static void (*acdb_send_voice_cal)(int,int);
#endif
#define PARSE_DEBUG 0

/**
 * Create an identifier
 * fmt - sprintf like format,
 * ... - Optional arguments
 * returns - string allocated or NULL on error
 */
char *snd_use_case_identifier(const char *fmt, ...)
{
    ALOGE("API not implemented for now, to be updated if required");
    return NULL;
}

/**
 * Free a list
 * list - list to free
 * items -  Count of strings
 * Return Zero on success, otherwise a negative error code
 */
int snd_use_case_free_list(const char *list[], int items)
{
    /* list points to UCM internal static tables,
     * hence there is no need to do a free call
     * just set the list to NULL and return */
    list = NULL;
    return 0;
}

/**
 * Obtain a list of entries
 * uc_mgr - UCM structure pointer or  NULL for card list
 * identifier - NULL for card list
 * list - Returns allocated list
 * returns Number of list entries on success, otherwise a negative error code
 */
int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
                          const char *identifier,
                          const char **list[])
{
    use_case_verb_t *verb_list;
    int verb_index, list_size, index = 0;

    if (identifier == NULL) {
        *list = card_list;
        return ((int)MAX_NUM_CARDS);
    }

    pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
    if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) ||
        (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) {
        ALOGE("snd_use_case_get_list(): failed, invalid arguments");
        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
        return -EINVAL;
    }

    if (!strncmp(identifier, "_verbs", 6)) {
        while(strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
            SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
            ALOGV("Index:%d Verb:%s", index,
                 uc_mgr->card_ctxt_ptr->verb_list[index]);
            index++;
        }
        *list = (char ***)uc_mgr->card_ctxt_ptr->verb_list;
        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
        return index;
    } else  if (!strncmp(identifier, "_devices", 8)) {
        if (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
            SND_USE_CASE_VERB_INACTIVE, strlen(SND_USE_CASE_VERB_INACTIVE))) {
            ALOGE("Use case verb name not set, invalid current verb");
            pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
            return -EINVAL;
        }
        verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
        while(strncmp(uc_mgr->card_ctxt_ptr->current_verb,
            verb_list[index].use_case_name,
            (strlen(verb_list[index].use_case_name)+1))) {
            index++;
        }
        verb_index = index;
        index = 0;
        while(strncmp(verb_list[verb_index].device_list[index],
            SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
            ALOGV("Index:%d Device:%s", index,
                 verb_list[verb_index].device_list[index]);
            index++;
        }
        *list = verb_list[verb_index].device_list;
        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
        return index;
    } else  if (!strncmp(identifier, "_modifiers", 10)) {
        if (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
                    SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN)) {
            ALOGE("Use case verb name not set, invalid current verb");
            pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
            return -EINVAL;
        }
        verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
        while(strncmp(uc_mgr->card_ctxt_ptr->current_verb,
            verb_list[index].use_case_name,
            (strlen(verb_list[index].use_case_name)+1))) {
            index++;
        }
        verb_index = index;
        index = 0;
        while(strncmp(verb_list[verb_index].modifier_list[index],
                    SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
            ALOGV("Index:%d Modifier:%s", index,
                 verb_list[verb_index].modifier_list[index]);
            index++;
        }
        *list = verb_list[verb_index].modifier_list;
        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
        return index;
    } else  if (!strncmp(identifier, "_enadevs", 8)) {
        if (uc_mgr->device_list_count) {
            for (index = 0; index < uc_mgr->device_list_count; index++) {
                free(uc_mgr->current_device_list[index]);
                uc_mgr->current_device_list[index] = NULL;
            }
            free(uc_mgr->current_device_list);
            uc_mgr->current_device_list = NULL;
            uc_mgr->device_list_count = 0;
        }
        list_size =
            snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
        uc_mgr->device_list_count = list_size;
    if (list_size > 0) {
            uc_mgr->current_device_list =
                (char **)malloc(sizeof(char *)*list_size);
            if (uc_mgr->current_device_list == NULL) {
                *list = NULL;
                pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
                return -ENOMEM;
            }
            for (index = 0; index < list_size; index++) {
                uc_mgr->current_device_list[index] =
                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
                index);
            }
        }
        *list = (const char **)uc_mgr->current_device_list;
        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
        return (list_size);
    } else  if (!strncmp(identifier, "_enamods", 8)) {
        if (uc_mgr->modifier_list_count) {
            for (index = 0; index < uc_mgr->modifier_list_count; index++) {
                free(uc_mgr->current_modifier_list[index]);
                uc_mgr->current_modifier_list[index] = NULL;
            }
            free(uc_mgr->current_modifier_list);
            uc_mgr->current_modifier_list = NULL;
            uc_mgr->modifier_list_count = 0;
        }
        list_size =
            snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
        uc_mgr->modifier_list_count = list_size;
    if (list_size > 0) {
            uc_mgr->current_modifier_list =
                (char **)malloc(sizeof(char *) * list_size);
            if (uc_mgr->current_modifier_list == NULL) {
                *list = NULL;
                pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
                return -ENOMEM;
            }
            for (index = 0; index < list_size; index++) {
                uc_mgr->current_modifier_list[index] =
                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
                index);
            }
        }
        *list = (const char **)uc_mgr->current_modifier_list;
        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
        return (list_size);
    } else {
        ALOGE("Invalid identifier: %s", identifier);
        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
        return -EINVAL;
    }
}


/**
 * Get current value of the identifier
 * identifier - NULL for current card
 *        _verb
 *        <Name>/<_device/_modifier>
 *    Name -    PlaybackPCM
 *        CapturePCM
 *        PlaybackCTL
 *        CaptureCTL
 * value - Value pointer
 * returns Zero if success, otherwise a negative error code
 */
int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
                     const char *identifier,
                     const char **value)
{
    card_mctrl_t *ctrl_list;
    use_case_verb_t *verb_list;
    char ident[MAX_STR_LEN], *ident1, *ident2, *temp_ptr;
    int index, verb_index = 0, ret = 0;

    pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
    if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) ||
        (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) {
        ALOGE("snd_use_case_get(): failed, invalid arguments");
        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
        return -EINVAL;
    }

    if (identifier == NULL) {
        if (uc_mgr->card_ctxt_ptr->card_name != NULL) {
            *value = strdup(uc_mgr->card_ctxt_ptr->card_name);
        } else {
            *value = NULL;
        }
        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
        return 0;
    }

    if (!strncmp(identifier, "_verb", 5)) {
        if (uc_mgr->card_ctxt_ptr->current_verb != NULL) {
            *value = strdup(uc_mgr->card_ctxt_ptr->current_verb);
        } else {
            *value = NULL;
        }
        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
        return 0;
    }

    strlcpy(ident, identifier, sizeof(ident));
    if(!(ident1 = strtok_r(ident, "/", &temp_ptr))) {
        ALOGE("No valid identifier found: %s", ident);
        ret = -EINVAL;
    } else {
        if ((!strncmp(ident1, "PlaybackPCM", 11)) ||
            (!strncmp(ident1, "CapturePCM", 10))) {
            ident2 = strtok_r(NULL, "/", &temp_ptr);
            index = 0;
            if (ident2 != NULL) {
                verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
                verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
                if((get_usecase_type(uc_mgr, ident2)) == CTRL_LIST_VERB) {
                    ctrl_list = verb_list[verb_index].verb_ctrls;
                } else {
                    ctrl_list = verb_list[verb_index].mod_ctrls;
                }
                if((verb_index < 0) ||
                    (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
                    SND_UCM_END_OF_LIST, 3)) || (ctrl_list == NULL)) {
                    ALOGE("Invalid current verb value: %s - %d",
                         uc_mgr->card_ctxt_ptr->current_verb, verb_index);
                    pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
                    return -EINVAL;
                }
                while(strncmp(ctrl_list[index].case_name, ident2,
                    (strlen(ident2)+1))) {
                    if (!strncmp(ctrl_list[index].case_name,
                        SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))){
                        *value = NULL;
                        ret = -EINVAL;
                        break;
                    } else {
                        index++;
                    }
                }
            } else {
                ret = -EINVAL;
            }
            if (ret < 0) {
                ALOGE("No valid device/modifier found with given identifier: %s",
                     ident2);
            } else {
                if(!strncmp(ident1, "PlaybackPCM", 11)) {
                    if (ctrl_list[index].playback_dev_name) {
                        *value = strdup(ctrl_list[index].playback_dev_name);
                    } else {
                        *value = NULL;
                        ret = -ENODEV;
                    }
                } else if(!strncmp(ident1, "CapturePCM", 10)) {
                    if (ctrl_list[index].capture_dev_name) {
                        *value = strdup(ctrl_list[index].capture_dev_name);
                    } else {
                        *value = NULL;
                        ret = -ENODEV;
                    }
                } else {
                    ALOGE("No valid device name exists for given identifier: %s",
                         ident2);
                    *value = NULL;
                    ret = -ENODEV;
                }
            }
        } else if ((!strncmp(ident1, "PlaybackCTL", 11)) ||
                   (!strncmp(ident1, "CaptureCTL", 10))) {
            if(uc_mgr->card_ctxt_ptr->control_device != NULL) {
                *value = strdup(uc_mgr->card_ctxt_ptr->control_device);
            } else {
                ALOGE("No valid control device found");
                *value = NULL;
                ret = -ENODEV;
            }
        } else if (!strncmp(ident1, "ACDBID", 11)) {
            ident2 = strtok_r(NULL, "/", &temp_ptr);
            index = 0; verb_index = 0;
            verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
            if((verb_index < 0) ||
               (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
                SND_UCM_END_OF_LIST, 3)) ||
                (verb_list[verb_index].verb_ctrls == NULL)) {
                ALOGE("Invalid current verb value: %s - %d",
                     uc_mgr->card_ctxt_ptr->current_verb, verb_index);
                pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
                return -EINVAL;
            }
            ctrl_list = verb_list[verb_index].device_ctrls;
            if (ident2 != NULL) {
                while(strncmp(ctrl_list[index].case_name, ident2,
                    MAX_LEN(ctrl_list[index].case_name,ident2))) {
                    if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
                        strlen(SND_UCM_END_OF_LIST))){
                        ret = -EINVAL;
                        break;
                    } else {
                        index++;
                    }
                }
            }
            if (ret < 0) {
                ALOGE("No valid device/modifier found with given identifier: %s",
                      ident2);
            } else {
                if (verb_list[verb_index].device_ctrls[index].acdb_id) {
                    ret = verb_list[verb_index].device_ctrls[index].acdb_id;
                } else {
                    ret = -ENODEV;
                }
            }
        } else if (!strncmp(ident1, "EffectsMixerCTL", 11)) {
            ident2 = strtok_r(NULL, "/", &temp_ptr);
            index = 0; verb_index = 0;
            verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
            if((verb_index < 0) ||
               (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
                SND_UCM_END_OF_LIST, 3)) ||
                (verb_list[verb_index].verb_ctrls == NULL)) {
                ALOGE("Invalid current verb value: %s - %d",
                     uc_mgr->card_ctxt_ptr->current_verb, verb_index);
                pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
                return -EINVAL;
            }
            ctrl_list = verb_list[verb_index].device_ctrls;
            if (ident2 != NULL) {
                while(strncmp(ctrl_list[index].case_name, ident2, strlen(ident2)+1)) {
                    if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
                        strlen(SND_UCM_END_OF_LIST))){
                        ret = -EINVAL;
                        break;
                    } else {
                        index++;
                    }
                }
            }
            if (ret < 0) {
                ALOGE("No valid device/modifier found with given identifier: %s",
                      ident2);
            } else {
                if (verb_list[verb_index].device_ctrls[index].effects_mixer_ctl) {
                    *value = strdup(verb_list[verb_index].device_ctrls[index].effects_mixer_ctl);
                } else {
                    *value = NULL;
                    ret = -ENODEV;
                }
            }
        } else {
            ALOGE("Unsupported identifier value: %s", ident1);
            *value = NULL;
            ret = -EINVAL;
        }
    }
    pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
    return ret;
}

/**
 * Get current status
 * uc_mgr - UCM structure
 * identifier - _devstatus/<device>,
        _modstatus/<modifier>
 * value - result
 * returns 0 on success, otherwise a negative error code
 */
int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
              const char *identifier,
              long *value)
{
    char ident[MAX_STR_LEN], *ident1, *ident2, *ident_value, *temp_ptr;
    int index, list_size, ret = -EINVAL;

    pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
    if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) ||
        (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) {
        ALOGE("snd_use_case_geti(): failed, invalid arguments");
        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
        return -EINVAL;
    }

    *value = 0;
    strlcpy(ident, identifier, sizeof(ident));
    if(!(ident1 = strtok_r(ident, "/", &temp_ptr))) {
        ALOGE("No valid identifier found: %s", ident);
        ret = -EINVAL;
    } else {
        if (!strncmp(ident1, "_devstatus", 10)) {
            ident2 = strtok_r(NULL, "/", &temp_ptr);
            if (ident2 != NULL) {
                list_size =
                snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
                for (index = 0; index < list_size; index++) {
                if ((ident_value =
                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
                index))) {
                        if (!strncmp(ident2, ident_value,
                            (strlen(ident_value)+1))) {
                            *value = 1;
                            free(ident_value);
                            ident_value = NULL;
                            break;
                        } else {
                            free(ident_value);
                            ident_value = NULL;
                        }
                    }
                }
                ret = 0;
            }
        } else if (!strncmp(ident1, "_modstatus", 10)) {
            ident2 = strtok_r(NULL, "/", &temp_ptr);
            if (ident2 != NULL) {
                list_size =
                snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
                for (index = 0; index < list_size; index++) {
                if((ident_value =
                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
                index))) {
                        if (!strncmp(ident2, ident_value,
                            (strlen(ident_value)+1))) {
                            *value = 1;
                            free(ident_value);
                            ident_value = NULL;
                            break;
                        } else {
                            free(ident_value);
                            ident_value = NULL;
                        }
                    }
                }
                ret = 0;
            }
        } else {
            ALOGE("Unknown identifier: %s", ident1);
        }
    }
    pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
    return ret;
}

static int check_devices_for_voice_call(snd_use_case_mgr_t *uc_mgr,
const char *use_case)
{
    struct snd_ucm_ident_node *dev_node = NULL;
    int index = 0, list_size = 0, rx_dev_status = 0, tx_dev_status = 0;

    if ((!strncmp(use_case, SND_USE_CASE_VERB_VOICECALL,
        strlen(SND_USE_CASE_VERB_VOICECALL))) ||
        (!strncmp(use_case, SND_USE_CASE_VERB_IP_VOICECALL,
        strlen(SND_USE_CASE_VERB_IP_VOICECALL))) ||
        (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOICE,
        strlen(SND_USE_CASE_MOD_PLAY_VOICE))) ||
        (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOIP,
        strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
        ALOGV("check_devices_for_voice_call(): voice cap detected\n");
        list_size =
        snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
        for (index = 0; index < list_size; index++) {
            if ((dev_node =
                snd_ucm_get_device_node(uc_mgr->card_ctxt_ptr->dev_list_head,
                index))) {
                if (dev_node->capability == CAP_RX && dev_node->active == 1) {
                    rx_dev_status = 1;
                } else if (dev_node->capability == CAP_TX && dev_node->active == 1) {
                    tx_dev_status = 1;
                }
            }
        }
        if (rx_dev_status == 1 && tx_dev_status == 1) {
            ALOGV("check_devices_for_voice_call(): Rx and Tx devices enabled\n");
            return 0;
        } else {
            ALOGV("check_devices_for_voice_call(): Rx/Tx dev not enabled: \
                  %d,%d\n", rx_dev_status, tx_dev_status);
            return 1;
        }
    }
    return 0;
}

static int snd_use_case_apply_voice_acdb(snd_use_case_mgr_t *uc_mgr,
int use_case_index)
{
    card_mctrl_t *ctrl_list;
    int list_size, index, verb_index, ret = 0, voice_acdb = 0, rx_id, tx_id;
    char *ident_value = NULL;

    /* Check if voice call use case/modifier exists */
    if ((!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
        SND_USE_CASE_VERB_VOICECALL, strlen(SND_USE_CASE_VERB_VOICECALL))) ||
        (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
        SND_USE_CASE_VERB_IP_VOICECALL,
        strlen(SND_USE_CASE_VERB_IP_VOICECALL)))) {
        voice_acdb = 1;
    }
    if (voice_acdb != 1) {
        list_size =
        snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
        for (index = 0; index < list_size; index++) {
            if ((ident_value =
                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
                index))) {
                if ((!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOICE,
                    strlen(SND_USE_CASE_MOD_PLAY_VOICE))) ||
                    (!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOIP,
                    strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
                    voice_acdb = 1;
                    free(ident_value);
                    ident_value = NULL;
                    break;
                }
                free(ident_value);
                ident_value = NULL;
            }
        }
    }

    verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
    if((verb_index < 0) ||
        (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
        SND_UCM_END_OF_LIST, 3))) {
        ALOGE("Invalid current verb value: %s - %d",
            uc_mgr->card_ctxt_ptr->current_verb, verb_index);
        return -EINVAL;
    }
    if (voice_acdb == 1) {
        ctrl_list =
        uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
        list_size =
        snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
        for (index = 0; index < list_size; index++) {
            if ((ident_value =
                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
                index))) {
                if (strncmp(ident_value, ctrl_list[use_case_index].case_name,
                    (strlen(ctrl_list[use_case_index].case_name)+1))) {
                    break;
                }
                free(ident_value);
                ident_value = NULL;
            }
        }
        index = 0;
        if (ident_value != NULL) {
            while(strncmp(ctrl_list[index].case_name, ident_value,
                  (strlen(ident_value)+1))) {
                if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
                    strlen(SND_UCM_END_OF_LIST))) {
                    ret = -EINVAL;
                    break;
                }
                index++;
            }
            if (ret < 0) {
                ALOGE("No valid device found: %s",ident_value);
            } else {
                if (ctrl_list[use_case_index].capability == CAP_RX) {
                    rx_id = ctrl_list[use_case_index].acdb_id;
                    tx_id = ctrl_list[index].acdb_id;
                } else {
                    rx_id = ctrl_list[index].acdb_id;
                    tx_id = ctrl_list[use_case_index].acdb_id;
                }
                if(((rx_id == DEVICE_SPEAKER_MONO_RX_ACDB_ID)||(rx_id == DEVICE_SPEAKER_STEREO_RX_ACDB_ID))
                    && tx_id == DEVICE_HANDSET_TX_ACDB_ID) {
                    tx_id = DEVICE_SPEAKER_TX_ACDB_ID;
                } else if (((rx_id == DEVICE_SPEAKER_MONO_RX_ACDB_ID )||(rx_id == DEVICE_SPEAKER_STEREO_RX_ACDB_ID))
                    && tx_id == DEVICE_HANDSET_TX_FV5_ACDB_ID) {
                    tx_id = DEVICE_SPEAKER_TX_FV5_ACDB_ID;
                }

                if ((rx_id != uc_mgr->current_rx_device) ||
                    (tx_id != uc_mgr->current_tx_device)) {
                    uc_mgr->current_rx_device = rx_id;
                    uc_mgr->current_tx_device = tx_id;
                    ALOGD("Voice acdb: rx id %d tx id %d",
                          uc_mgr->current_rx_device,
                          uc_mgr->current_tx_device);
                    if (uc_mgr->acdb_handle && !uc_mgr->isFusion3Platform) {
                        acdb_send_voice_cal = dlsym(uc_mgr->acdb_handle,"acdb_loader_send_voice_cal");
                        if (acdb_send_voice_cal == NULL) {
                            ALOGE("ucm: dlsym: Error:%s Loading acdb_loader_send_voice_cal", dlerror());
                        }else {
                            acdb_send_voice_cal(uc_mgr->current_rx_device,
                                       uc_mgr->current_tx_device);
                        }
                   }
                } else {
                    ALOGV("Voice acdb: Required acdb already pushed \
                         rx id %d tx id %d", uc_mgr->current_rx_device,
                         uc_mgr->current_tx_device);
                }
            }
            free(ident_value);
            ident_value = NULL;
        }
    } else {
        ALOGV("No voice use case found");
        uc_mgr->current_rx_device = -1; uc_mgr->current_tx_device = -1;
        ret = -ENODEV;
    }
    return ret;
}

int get_use_case_index(snd_use_case_mgr_t *uc_mgr, const char *use_case,
int ctrl_list_type)
{
    use_case_verb_t *verb_list;
    card_mctrl_t *ctrl_list;
    int ret = 0, index = 0, verb_index;

    verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
    verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
    if (ctrl_list_type == CTRL_LIST_VERB) {
        ctrl_list =
            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls;
    } else if (ctrl_list_type == CTRL_LIST_DEVICE) {
        ctrl_list =
            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
    } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
        ctrl_list =
            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].mod_ctrls;
    } else {
        ctrl_list = NULL;
    }
    if((verb_index < 0) ||
      (!strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_UCM_END_OF_LIST, 3)) ||
      (ctrl_list == NULL) || (ctrl_list[index].case_name == NULL)) {
        ALOGE("Invalid current verb value: %s - %d",
                uc_mgr->card_ctxt_ptr->current_verb, verb_index);
        return -EINVAL;
    }
    while(strncmp(ctrl_list[index].case_name, use_case, (strlen(use_case)+1))) {
        if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
            strlen(SND_UCM_END_OF_LIST))) {
            ret = -EINVAL;
            break;
        }
        index++;
        if (ctrl_list[index].case_name == NULL) {
            ALOGE("Invalid case_name at index %d", index);
            ret = -EINVAL;
            break;
        }
    }
    if (ret < 0) {
        return ret;
    } else {
        return index;
    }
}

/* Apply the required mixer controls for specific use case
 * uc_mgr - UCM structure pointer
 * use_case - use case name
 * return 0 on sucess, otherwise a negative error code
 */
int snd_use_case_apply_mixer_controls(snd_use_case_mgr_t *uc_mgr,
const char *use_case, int enable, int ctrl_list_type, int uc_index)
{
    card_mctrl_t *ctrl_list;
    mixer_control_t *mixer_list;
    struct mixer_ctl *ctl;
    int i, ret = 0, index = 0, verb_index, mixer_count;

    verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
    if (ctrl_list_type == CTRL_LIST_VERB) {
        ctrl_list =
            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls;
    } else if (ctrl_list_type == CTRL_LIST_DEVICE) {
        ctrl_list =
            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
    } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
        ctrl_list =
            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].mod_ctrls;
    } else {
        ctrl_list = NULL;
    }
    if((verb_index < 0) ||
      (!strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_UCM_END_OF_LIST, 3)) ||
      (ctrl_list == NULL)) {
        ALOGE("Invalid current verb value: %s - %d",
            uc_mgr->card_ctxt_ptr->current_verb, verb_index);
        return -EINVAL;
    }
    if (uc_index < 0) {
        ALOGE("No valid use case found with the use case: %s", use_case);
        ret = -ENODEV;
    } else {
        if (!uc_mgr->card_ctxt_ptr->mixer_handle) {
            ALOGE("Control device not initialized");
            ret = -ENODEV;
        } else {
            if (enable &&
                (check_devices_for_voice_call(uc_mgr, use_case) != NULL))
                return ret;
            ALOGD("Set mixer controls for %s enable %d", use_case, enable);
            if (ctrl_list[uc_index].acdb_id && ctrl_list[uc_index].capability) {
                if (enable) {
                    if (snd_use_case_apply_voice_acdb(uc_mgr, uc_index)) {
                        ALOGV("acdb_id %d cap %d enable %d",
                            ctrl_list[uc_index].acdb_id,
                            ctrl_list[uc_index].capability, enable);
                        if (uc_mgr->acdb_handle) {
                            acdb_send_audio_cal = dlsym(uc_mgr->acdb_handle,"acdb_loader_send_audio_cal");
                            if (acdb_send_audio_cal == NULL) {
                                ALOGE("ucm:dlsym:Error:%s Loading acdb_loader_send_audio_cal", dlerror());
                            } else {
                                acdb_send_audio_cal(ctrl_list[uc_index].acdb_id,
                                                     ctrl_list[uc_index].capability);
                            }
                        }
                    }
                }
            }
            if (enable) {
                mixer_list = ctrl_list[uc_index].ena_mixer_list;
                mixer_count = ctrl_list[uc_index].ena_mixer_count;
            } else {
                mixer_list = ctrl_list[uc_index].dis_mixer_list;
                mixer_count = ctrl_list[uc_index].dis_mixer_count;
            }
            for(index = 0; index < mixer_count; index++) {
                if (mixer_list == NULL) {
                    ALOGE("No valid controls exist for this case: %s", use_case);
                    break;
                }
                ctl = mixer_get_control(uc_mgr->card_ctxt_ptr->mixer_handle,
                          mixer_list[index].control_name, 0);
                if (ctl) {
                    if (mixer_list[index].type == TYPE_INT) {
                        ALOGV("Setting mixer control: %s, value: %d",
                             mixer_list[index].control_name,
                             mixer_list[index].value);
                        ret = mixer_ctl_set(ctl, mixer_list[index].value);
                    } else if (mixer_list[index].type == TYPE_MULTI_VAL) {
                        ALOGD("Setting multi value: %s",
                            mixer_list[index].control_name);
                        ret = mixer_ctl_set_value(ctl, mixer_list[index].value,
                                mixer_list[index].mulval);
                        if (ret < 0)
                            ALOGE("Failed to set multi value control %s\n",
                                mixer_list[index].control_name);
                    } else {
                        ALOGV("Setting mixer control: %s, value: %s",
                            mixer_list[index].control_name,
                            mixer_list[index].string);
                        ret = mixer_ctl_select(ctl, mixer_list[index].string);
                    }
                    if ((ret != 0) && enable) {
                       /* Disable all the mixer controls which are
                        * already enabled before failure */
                       mixer_list = ctrl_list[uc_index].dis_mixer_list;
                       mixer_count = ctrl_list[uc_index].dis_mixer_count;
                       for(i = 0; i < mixer_count; i++) {
                           ctl = mixer_get_control(
                                     uc_mgr->card_ctxt_ptr->mixer_handle,
                                     mixer_list[i].control_name, 0);
                           if (ctl) {
                               if (mixer_list[i].type == TYPE_INT) {
                                   ret = mixer_ctl_set(ctl,
                                             mixer_list[i].value);
                               } else {
                                   ret = mixer_ctl_select(ctl,
                                             mixer_list[i].string);
                               }
                           }
                       }
                       ALOGE("Failed to enable the mixer controls for %s",
                            use_case);
                       break;
                    }
                }
            }
        }
    }
    return ret;
}

int getUseCaseType(const char *useCase)
{
    ALOGV("getUseCaseType: use case is %s\n", useCase);
    if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI,
           MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI)) ||
        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
           MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
           MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
        !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI2)) ||
        !strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO,
            MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC)) ||
        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA,
            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LPA)) ||
        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM,
            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))) {
        return CAP_RX;
    } else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC,
            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC)) ||
        !strncmp(useCase, SND_USE_CASE_VERB_FM_REC,
            MAX_LEN(useCase,SND_USE_CASE_VERB_FM_REC)) ||
        !strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC,
            MAX_LEN(useCase,SND_USE_CASE_VERB_FM_A2DP_REC)) ||
        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC,
            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC)) ||
        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC,
            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) ||
        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC,
            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) ||
        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM,
            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_FM)) ||
        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM,
            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_A2DP_FM))) {
        return CAP_TX;
    } else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL,
            MAX_LEN(useCase,SND_USE_CASE_VERB_VOICECALL)) ||
        !strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL,
            MAX_LEN(useCase,SND_USE_CASE_VERB_IP_VOICECALL)) ||
        !strncmp(useCase, SND_USE_CASE_VERB_DL_REC,
            MAX_LEN(useCase,SND_USE_CASE_VERB_DL_REC)) ||
        !strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC,
            MAX_LEN(useCase,SND_USE_CASE_VERB_UL_DL_REC)) ||
        !strncmp(useCase, SND_USE_CASE_VERB_INCALL_REC,
            MAX_LEN(useCase,SND_USE_CASE_VERB_INCALL_REC)) ||
        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE,
            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE)) ||
        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP,
            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) ||
        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) ||
        !strncmp(useCase, SND_USE_CASE_VERB_VOLTE,
            MAX_LEN(useCase,SND_USE_CASE_VERB_VOLTE)) ||
        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
            MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_VOLTE))) {
        return CAP_VOICE;
    } else {
        ALOGE("unknown use case %s, returning voice capablity", useCase);
        return CAP_VOICE;
    }
}

/* Set/Reset mixer controls of specific use case for all current devices
 * uc_mgr - UCM structure pointer
 * ident  - use case name (verb or modifier)
 * enable - 1 for enable and 0 for disable
 * return 0 on sucess, otherwise a negative error code
 */
static int set_controls_of_usecase_for_all_devices(snd_use_case_mgr_t *uc_mgr,
const char *ident, int enable, int ctrl_list_type)
{
    card_mctrl_t *dev_list, *uc_list;
    char *current_device, use_case[MAX_UC_LEN];
    int list_size, index, uc_index, ret = 0, intdev_flag = 0;
    int verb_index, capability = 0, ident_cap = 0, dev_cap =0;

    ALOGV("set_use_case_ident_for_all_devices(): %s", ident);
    if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
        verb_index = 0;
    dev_list =
        uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
    if (ctrl_list_type == CTRL_LIST_VERB) {
        uc_list =
            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls;
    } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
        uc_list =
            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].mod_ctrls;
    } else {
        uc_list = NULL;
    }
    ident_cap = getUseCaseType(ident);
    list_size = snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
    for (index = 0; index < list_size; index++) {
        current_device =
        snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head, index);
        if (current_device != NULL) {
            uc_index = get_use_case_index(uc_mgr, current_device,
                       CTRL_LIST_DEVICE);
            dev_cap = dev_list[uc_index].capability;
            if (!capability) {
                capability = dev_list[uc_index].capability;
            } else if (capability != dev_list[uc_index].capability) {
                capability = CAP_VOICE;
            }
            if (ident_cap == CAP_VOICE  || ident_cap == dev_cap) {
                if (enable) {
                    if (!snd_ucm_get_status_at_index(
                        uc_mgr->card_ctxt_ptr->dev_list_head, current_device)) {
                        if (uc_index >= 0) {
                            ALOGV("Applying mixer controls for device: %s",
                                  current_device);
                            ret = snd_use_case_apply_mixer_controls(uc_mgr,
                                  current_device, enable, CTRL_LIST_DEVICE, uc_index);
                            if (!ret)
                                snd_ucm_set_status_at_index(
                                  uc_mgr->card_ctxt_ptr->dev_list_head,
                                  current_device, enable, dev_cap);
                        }
                     } else if (ident_cap == CAP_VOICE) {
                        snd_use_case_apply_voice_acdb(uc_mgr, uc_index);
                     }
                 }
                 strlcpy(use_case, ident, sizeof(use_case));
                 strlcat(use_case, current_device, sizeof(use_case));
                 ALOGV("Applying mixer controls for use case: %s", use_case);
                 if ((uc_index =
                      get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
                      ALOGV("No valid use case found: %s", use_case);
                      intdev_flag++;
                 } else {
                      if (capability == CAP_VOICE || ident_cap == CAP_VOICE ||
                          capability == ident_cap) {
                          ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
                                enable, ctrl_list_type, uc_index);
                      }
                 }
                 use_case[0] = 0;
                 free(current_device);
             }
        }
    }
    if (intdev_flag) {
        if ((uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type)) < 0) {
            ALOGE("use case %s not valid without device combination", ident);
        } else {
            if (capability == CAP_VOICE || capability == ident_cap ||
                ident_cap == CAP_VOICE) {
                snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
                ctrl_list_type, uc_index);
            }
        }
    }
    return ret;
}

/* Set/Reset mixer controls of specific use case for a specific device
 * uc_mgr - UCM structure pointer
 * ident  - use case name (verb or modifier)
 * device - device for which use case needs to be set/reset
 * enable - 1 for enable and 0 for disable
 * return 0 on sucess, otherwise a negative error code
 */
static int set_controls_of_usecase_for_device(snd_use_case_mgr_t *uc_mgr,
const char *ident, const char *device, int enable, int ctrl_list_type)
{
    card_mctrl_t *dev_list;
    char use_case[MAX_UC_LEN];
    int list_size, index, dev_index, uc_index, ret = 0;
    int verb_index, capability = 0;

    ALOGV("set_use_case_ident_for_device(): use case %s device %s", ident,
        device);
    if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
        verb_index = 0;
    dev_list =
        uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
    if (device != NULL) {
        if (enable) {
            dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
            capability = dev_list[dev_index].capability;
            if (!snd_ucm_get_status_at_index(
                uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
                ret = snd_use_case_apply_mixer_controls(uc_mgr, device,
                         enable, CTRL_LIST_DEVICE, dev_index);
                if (!ret)
                    snd_ucm_set_status_at_index(
                    uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
                    capability);
            }
        }
        strlcpy(use_case, ident, sizeof(use_case));
        strlcat(use_case, device, sizeof(use_case));
    ALOGV("Applying mixer controls for use case: %s", use_case);
        if ((uc_index = get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
            ALOGV("No valid use case found: %s", use_case );
            uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type);
            if (snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
                ctrl_list_type, uc_index) < 0) {
                 ALOGV("use case %s not valid without device combination also",
                     ident);
            }
        } else {
            ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case, enable,
                      ctrl_list_type, uc_index);
        }
    } else {
        uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type);
        if (snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
            ctrl_list_type, uc_index) < 0) {
             ALOGV("use case %s not valid without device combination also",
                 ident);
        }
    }
    return ret;
}

/* Set/Reset mixer controls of specific device for all use cases
 * uc_mgr - UCM structure pointer
 * device - device name
 * enable - 1 for enable and 0 for disable
 * return 0 on sucess, otherwise a negative error code
 */
static int set_controls_of_device_for_all_usecases(snd_use_case_mgr_t *uc_mgr,
const char *device, int enable)
{
    card_mctrl_t *dev_list, *uc_list;
    char *ident_value, use_case[MAX_UC_LEN];
    int verb_index, uc_index, dev_index, capability = 0;
    int list_size, index = 0, ret = -ENODEV, flag = 0, intdev_flag = 0;

    ALOGV("set_controls_of_device_for_all_usecases: %s", device);
    if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
        verb_index = 0;
    dev_list =
         uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
    dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
    if (dev_index >= 0)
        capability = dev_list[dev_index].capability;
    if (strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_USE_CASE_VERB_INACTIVE,
        strlen(SND_USE_CASE_VERB_INACTIVE))) {
        uc_list =
            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls;
        if (capability == CAP_VOICE ||
            capability == getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ||
            getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) == CAP_VOICE) {
            strlcpy(use_case, uc_mgr->card_ctxt_ptr->current_verb,
                sizeof(use_case));
            strlcat(use_case, device, sizeof(use_case));
            if ((uc_index =
                get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB)) < 0) {
                ALOGV("No valid use case found: %s", use_case);
                intdev_flag = 1;
            } else {
                if (enable) {
                    if (!snd_ucm_get_status_at_index(
                        uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
                        ret = snd_use_case_apply_mixer_controls(uc_mgr, device,
                                  enable, CTRL_LIST_DEVICE, dev_index);
                        if (!ret)
                            snd_ucm_set_status_at_index(
                            uc_mgr->card_ctxt_ptr->dev_list_head, device,
                            enable, capability);
                            flag = 1;
                    }
                }
                ALOGV("set %d for use case value: %s", enable, use_case);
                ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
                          enable, CTRL_LIST_VERB, uc_index);
                if (ret != 0)
                     ALOGE("No valid controls exists for usecase %s and device \
                          %s, enable: %d", use_case, device, enable);
            }
        }
        if (intdev_flag) {
            if (enable && !flag) {
                if (!snd_ucm_get_status_at_index(
                    uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
                    ret = snd_use_case_apply_mixer_controls(uc_mgr,
                              device, enable, CTRL_LIST_DEVICE, dev_index);
                    if (!ret)
                        snd_ucm_set_status_at_index(
                        uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
                        capability);
                    flag = 1;
                }
            }
            use_case[0] = 0;
            strlcpy(use_case, uc_mgr->card_ctxt_ptr->current_verb,
                sizeof(use_case));
            uc_index = get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB);
            if (capability == CAP_VOICE ||
                capability ==
                getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ||
                getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ==
                CAP_VOICE) {
                ALOGV("set %d for use case value: %s", enable, use_case);
                ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
                          enable, CTRL_LIST_VERB, uc_index);
                if (ret != 0)
                      ALOGE("No valid controls exists for usecase %s and \
                           device %s, enable: %d", use_case, device, enable);
            }
            intdev_flag = 0;
        }
        use_case[0] = 0;
    }
    snd_ucm_print_list(uc_mgr->card_ctxt_ptr->mod_list_head);
    uc_list =
        uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].mod_ctrls;
    list_size = snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
    for (index = 0; index < list_size; index++) {
        if ((ident_value =
            snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
            index))) {
            if (capability == CAP_VOICE ||
                getUseCaseType(ident_value) == CAP_VOICE ||
                capability == getUseCaseType(ident_value)) {
                strlcpy(use_case, ident_value, sizeof(use_case));
                strlcat(use_case, device, sizeof(use_case));
                if ((uc_index = get_use_case_index(uc_mgr, use_case,
                    CTRL_LIST_MODIFIER)) < 0) {
                    ALOGV("No valid use case found: %s", use_case);
                    intdev_flag = 1;
                } else {
                    if (enable && !flag) {
                        if (!snd_ucm_get_status_at_index(
                            uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
                            ret = snd_use_case_apply_mixer_controls(uc_mgr,
                                      device, enable, CTRL_LIST_DEVICE,
                                      dev_index);
                            if (!ret)
                                snd_ucm_set_status_at_index(
                                    uc_mgr->card_ctxt_ptr->dev_list_head,
                                    device, enable, capability);
                            flag = 1;
                        }
                    }
                    ALOGV("set %d for use case value: %s", enable, use_case);
                    ret = snd_use_case_apply_mixer_controls(uc_mgr,
                          use_case, enable, CTRL_LIST_MODIFIER, uc_index);
                    if (ret != 0)
                        ALOGE("No valid controls exists for usecase %s and \
                            device %s, enable: %d", use_case, device, enable);
                }
            }
            if (intdev_flag) {
                if (enable && !flag) {
                    if (!snd_ucm_get_status_at_index(
                         uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
                        ret = snd_use_case_apply_mixer_controls(uc_mgr,
                                  device, enable, CTRL_LIST_DEVICE, dev_index);
                        if (!ret)
                            snd_ucm_set_status_at_index(
                            uc_mgr->card_ctxt_ptr->dev_list_head, device,
                            enable, capability);
                        flag = 1;
                    }
                }
                use_case[0] = 0;
                strlcpy(use_case, ident_value, sizeof(use_case));
                uc_index =
                    get_use_case_index(uc_mgr, ident_value, CTRL_LIST_MODIFIER);
                if (capability == CAP_VOICE ||
                    capability == getUseCaseType(ident_value) ||
                    getUseCaseType(ident_value) == CAP_VOICE) {
                    ALOGV("set %d for use case value: %s", enable, use_case);
                    ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
                          enable, CTRL_LIST_MODIFIER, uc_index);
                    if (ret != 0)
                         ALOGE("No valid controls exists for usecase %s and \
                              device %s, enable: %d", use_case, device, enable);
                }
                intdev_flag = 0;
            }
            use_case[0] = 0;
            free(ident_value);
        }
    }
    if (!enable) {
        ret = snd_use_case_apply_mixer_controls(uc_mgr, device, enable,
                  CTRL_LIST_DEVICE, dev_index);
        if (!ret)
            snd_ucm_set_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
                device, enable, capability);
    }
    return ret;
}

/* Returns usecase type i.e. either verb or modifier
 * uc_mgr - UCM structure pointer
 * usecase - usecase name either verb or modifier
 * return CTRL_LIST_VERB or CTRL_LIST_MODIFIER for verb/modifier respectively
 */
static int get_usecase_type(snd_use_case_mgr_t *uc_mgr, const char *usecase)
{
    int ret = -EINVAL, index = 0;

    while (strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
        SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
        if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index], usecase,
            (strlen(usecase)+1))) {
            ret = 0;
            break;
        }
        index++;
    }
    if (ret == 0)
        return CTRL_LIST_VERB;
    else
        return CTRL_LIST_MODIFIER;
}

/* Set/Reset mixer controls of specific device and specific use cases
 * uc_mgr - UCM structure pointer
 * device - device name
 * usecase - use case for which device needs to be enabled
 * enable - 1 for enable and 0 for disable
 * return 0 on sucess, otherwise a negative error code
 */
static int set_controls_of_device_for_usecase(snd_use_case_mgr_t *uc_mgr,
    const char *device, const char *usecase, int enable)
{
    card_mctrl_t *dev_list;
    char use_case[MAX_UC_LEN];
    int ret = -ENODEV, uc_index, dev_index;
    int verb_index, capability = 0;

    ALOGV("set_device_for_ident(): %s %s", device, usecase);
    if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
        verb_index = 0;
    dev_list =
         uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
    dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
    capability = dev_list[dev_index].capability;
    if (usecase != NULL) {
        strlcpy(use_case, usecase, sizeof(use_case));
        strlcat(use_case, device, sizeof(use_case));
        if ((uc_index = get_use_case_index(uc_mgr, use_case,
            get_usecase_type(uc_mgr, usecase))) < 0) {
            ALOGV("No valid use case found: %s", use_case);
        } else {
            if (enable) {
                if (!snd_ucm_get_status_at_index(
                    uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
                    ret = snd_use_case_apply_mixer_controls(uc_mgr, device,
                          enable, CTRL_LIST_DEVICE, dev_index);
                    if (!ret)
                        snd_ucm_set_status_at_index
                        (uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
                        capability);
                }
            }
            ALOGV("set %d for use case value: %s", enable, use_case);
            ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case, enable,
                      get_usecase_type(uc_mgr, usecase), uc_index);
            if (ret != 0)
                ALOGE("No valid controls exists for usecase %s and device %s, \
                     enable: %d", use_case, device, enable);
        }
        use_case[0] = 0;
    } else {
        if (enable) {
            if (!snd_ucm_get_status_at_index(
                 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
                ret = snd_use_case_apply_mixer_controls(uc_mgr, device, enable,
                          CTRL_LIST_DEVICE, dev_index);
                if (!ret)
                    snd_ucm_set_status_at_index(
                        uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
                        capability);
            }
        }
    }
    if (!enable) {
        ret = snd_use_case_apply_mixer_controls(uc_mgr, device, enable,
                  CTRL_LIST_DEVICE, dev_index);
        if (!ret)
            snd_ucm_set_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
                device, enable, capability);
    }
    return ret;
}

/**
 * Set new value for an identifier
 * uc_mgr - UCM structure
 * identifier - _verb, _enadev, _disdev, _enamod, _dismod
 *        _swdev, _swmod
 * value - Value to be set
 * returns 0 on success, otherwise a negative error code
 */
int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
                     const char *identifier,
                     const char *value)
{
    use_case_verb_t *verb_list;
    char ident[MAX_STR_LEN], *ident1, *ident2, *temp_ptr;
    int verb_index, list_size, index = 0, ret = -EINVAL;

    pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
    if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) || (value == NULL) ||
        (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL) ||
        (identifier == NULL)) {
        ALOGE("snd_use_case_set(): failed, invalid arguments");
        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
        return -EINVAL;
    }

    ALOGD("snd_use_case_set(): uc_mgr %p identifier %s value %s", uc_mgr,
         identifier, value);
    strlcpy(ident, identifier, sizeof(ident));
    if(!(ident1 = strtok_r(ident, "/", &temp_ptr))) {
        ALOGV("No multiple identifiers found in identifier value");
        ident[0] = 0;
    } else {
        if (!strncmp(ident1, "_swdev", 6)) {
            if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
                ALOGD("Invalid disable device value: %s, but enabling new \
                     device", ident2);
            } else {
                ret = snd_ucm_del_ident_from_list(
                          &uc_mgr->card_ctxt_ptr->dev_list_head, ident2);
                if (ret < 0) {
                    ALOGV("Ignore device %s disable, device not part of \
                         enabled list", ident2);
                } else {
                    ALOGV("swdev: device value to be disabled: %s", ident2);
                    /* Disable mixer controls for
                     * corresponding use cases and device */
                    ret = set_controls_of_device_for_all_usecases(uc_mgr,
                              ident2, 0);
                    if (ret < 0) {
                        ALOGV("Device %s not disabled, no valid use case \
                              found: %d", ident2, errno);
                    }
                }
            }
            pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
            ret = snd_use_case_set(uc_mgr, "_enadev", value);
            if (ret < 0) {
                ALOGV("Device %s not enabled, no valid use case found: %d",
                    value, errno);
            }
            return ret;
        } else if (!strncmp(ident1, "_swmod", 6)) {
            pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
            if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
                ALOGD("Invalid modifier value: %s, but enabling new modifier",
                    ident2);
            } else {
                ret = snd_use_case_set(uc_mgr, "_dismod", ident2);
                if (ret < 0) {
                    ALOGV("Modifier %s not disabled, no valid use case \
                         found: %d", ident2, errno);
                }
            }
            ret = snd_use_case_set(uc_mgr, "_enamod", value);
            if (ret < 0) {
                ALOGV("Modifier %s not enabled, no valid use case found: %d",
                    value, errno);
            }
            return ret;
        } else {
            ALOGV("No switch device/modifier option found: %s", ident1);
        }
        ident[0] = 0;
    }

    if (!strncmp(identifier, "_verb", 5)) {
        /* Check if value is valid verb */
        while (strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
               SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
            if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index], value,
                (strlen(value)+1))) {
                ret = 0;
                break;
            }
            index++;
        }
        if ((ret < 0) && (strncmp(value, SND_USE_CASE_VERB_INACTIVE,
            strlen(SND_USE_CASE_VERB_INACTIVE)))) {
            ALOGE("Invalid verb identifier value");
        } else {
            ALOGV("Index:%d Verb:%s", index,
                uc_mgr->card_ctxt_ptr->verb_list[index]);
            /* Disable the mixer controls for current use case
             * for all the enabled devices */
            if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
                SND_USE_CASE_VERB_INACTIVE,
                strlen(SND_USE_CASE_VERB_INACTIVE))) {
                ret = set_controls_of_usecase_for_all_devices(uc_mgr,
                      uc_mgr->card_ctxt_ptr->current_verb, 0, CTRL_LIST_VERB);
                if (ret != 0)
                    ALOGE("Failed to disable controls for use case: %s",
                        uc_mgr->card_ctxt_ptr->current_verb);
            }
            strlcpy(uc_mgr->card_ctxt_ptr->current_verb, value, MAX_STR_LEN);
            /* Enable the mixer controls for the new use case
             * for all the enabled devices */
            if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
               SND_USE_CASE_VERB_INACTIVE,
               strlen(SND_USE_CASE_VERB_INACTIVE))) {
               uc_mgr->card_ctxt_ptr->current_verb_index = index;
               ret = set_controls_of_usecase_for_all_devices(uc_mgr,
                     uc_mgr->card_ctxt_ptr->current_verb, 1, CTRL_LIST_VERB);
            }
        }
    } else if (!strncmp(identifier, "_enadev", 7)) {
        index = 0; ret = 0;
        list_size =
            snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
        for (index = 0; index < list_size; index++) {
            if ((ident1 =
                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
                index))) {
                if (!strncmp(ident1, value, (strlen(value)+1))) {
                    ALOGV("Ignore enable as %s device is already part of \
                         enabled list", value);
                    free(ident1);
                    break;
                }
                free(ident1);
            }
        }
        if (index == list_size) {
            ALOGV("enadev: device value to be enabled: %s", value);
            snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
                value);
        }
        snd_ucm_print_list(uc_mgr->card_ctxt_ptr->dev_list_head);
        /* Apply Mixer controls of all verb and modifiers for this device*/
        ret = set_controls_of_device_for_all_usecases(uc_mgr, value, 1);
    } else if (!strncmp(identifier, "_disdev", 7)) {
        ret = snd_ucm_get_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
                  value);
        if (ret < 0) {
            ALOGD("disdev: device %s not enabled, no need to disable", value);
        } else if (ret == 0) {
            ALOGV("disdev: device %s not active, remove from the list", value);
            ret =
            snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
            value);
            if (ret < 0) {
                ALOGE("Invalid device: Device not part of enabled device list");
            }
        } else {
            ret =
            snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
            value);
            if (ret < 0) {
                ALOGE("Invalid device: Device not part of enabled device list");
            } else {
                ALOGV("disdev: device value to be disabled: %s", value);
                index = get_use_case_index(uc_mgr, value, CTRL_LIST_DEVICE);
                /* Apply Mixer controls for corresponding device and modifier */
                ret = snd_use_case_apply_mixer_controls(uc_mgr, value, 0,
                          CTRL_LIST_DEVICE, index);
            }
        }
    } else if (!strncmp(identifier, "_enamod", 7)) {
        index = 0; ret = 0;
        verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
        if (verb_index < 0) {
            ALOGE("Invalid verb identifier value");
        } else {
            ALOGV("Index:%d Verb:%s", verb_index,
                 uc_mgr->card_ctxt_ptr->verb_list[verb_index]);
            verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
            while(strncmp(verb_list[verb_index].modifier_list[index], value,
                  (strlen(value)+1))) {
                if (!strncmp(verb_list[verb_index].modifier_list[index],
                    SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))){
                    ret = -EINVAL;
                    break;
                }
                index++;
            }
            if (ret < 0) {
                ALOGE("Invalid modifier identifier value");
            } else {
                snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
                    value);
                /* Enable the mixer controls for the new use case
                 * for all the enabled devices */
                ret = set_controls_of_usecase_for_all_devices(uc_mgr, value, 1,
                          CTRL_LIST_MODIFIER);
            }
        }
    } else if (!strncmp(identifier, "_dismod", 7)) {
        ret = snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
                  value);
        if (ret < 0) {
            ALOGE("Modifier not enabled currently, invalid modifier");
        } else {
            ALOGV("dismod: modifier value to be disabled: %s", value);
            /* Enable the mixer controls for the new use case
             * for all the enabled devices */
            ret = set_controls_of_usecase_for_all_devices(uc_mgr, value, 0,
                      CTRL_LIST_MODIFIER);
        }
    } else {
        ALOGE("Unknown identifier value: %s", identifier);
    }
    pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
    return ret;
}

/**
 * Set new value for an identifier based on use case
 * uc_mgr - UCM structure
 * identifier - _verb, _enadev, _disdev, _enamod, _dismod
 *        _swdev, _swmod
 * value - Value to be set
 * usecase - usecase/device for which this command needs to be executed
 * returns 0 on success, otherwise a negative error code
 */
int snd_use_case_set_case(snd_use_case_mgr_t *uc_mgr,
                     const char *identifier,
                     const char *value, const char *usecase)
{
    use_case_verb_t *verb_list;
    char ident[MAX_STR_LEN], *ident1, *ident2, *temp_ptr;
    int verb_index, list_size, index = 0, ret = -EINVAL;

    pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
    if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) || (value == NULL) ||
        (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL) ||
        (identifier == NULL)) {
        ALOGE("snd_use_case_set_case(): failed, invalid arguments");
        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
        return -EINVAL;
    }

    ALOGD("snd_use_case_set_case(): uc_mgr %p identifier %s value %s",
        uc_mgr, identifier, value);
    strlcpy(ident, identifier, sizeof(ident));
    if(!(ident1 = strtok_r(ident, "/", &temp_ptr))) {
        ALOGV("No multiple identifiers found in identifier value");
        ident[0] = 0;
    } else {
        if (!strncmp(ident1, "_swdev", 6)) {
            if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
                ALOGD("Invalid disable device value: %s, but enabling new \
                     device", ident2);
            } else {
                ret = snd_ucm_del_ident_from_list(
                          &uc_mgr->card_ctxt_ptr->dev_list_head, ident2);
                if (ret < 0) {
                    ALOGV("Ignore device %s disable, device not part of \
                         enabled list", ident2);
                } else {
                    ALOGV("swdev: device value to be disabled: %s", ident2);
                    /* Disable mixer controls for
                     * corresponding use cases and device */
                    ret = set_controls_of_device_for_usecase(uc_mgr, ident2,
                              usecase, 0);
                    if (ret < 0) {
                        ALOGV("Device %s not disabled, no valid use case \
                             found: %d", ident2, errno);
                    }
                }
            }
            pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
            ret = snd_use_case_set_case(uc_mgr, "_enadev", value, usecase);
            if (ret < 0) {
                ALOGV("Device %s not enabled, no valid use case found: %d",
                    value, errno);
            }
            return ret;
        } else if (!strncmp(ident1, "_swmod", 6)) {
            pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
            if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
                ALOGD("Invalid modifier value: %s, but enabling new modifier",
                    ident2);
            } else {
                ret = snd_use_case_set_case(uc_mgr, "_dismod", ident2, usecase);
                if (ret < 0) {
                    ALOGV("Modifier %s not disabled, no valid use case \
                         found: %d", ident2, errno);
                }
            }
            ret = snd_use_case_set_case(uc_mgr, "_enamod", value, usecase);
            if (ret < 0) {
                ALOGV("Modifier %s not enabled, no valid use case found: %d",
                    value, errno);
            }
            return ret;
        } else {
            ALOGV("No switch device/modifier option found: %s", ident1);
        }
        ident[0] = 0;
    }

    if (!strncmp(identifier, "_verb", 5)) {
        /* Check if value is valid verb */
        while (strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
               SND_UCM_END_OF_LIST, MAX_STR_LEN)) {
            if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
                value, MAX_STR_LEN)) {
                ret = 0;
                break;
            }
            index++;
        }
        if ((ret < 0) && (strncmp(value, SND_USE_CASE_VERB_INACTIVE,
            MAX_STR_LEN))) {
            ALOGE("Invalid verb identifier value");
        } else {
            ALOGV("Index:%d Verb:%s", index,
                 uc_mgr->card_ctxt_ptr->verb_list[index]);
            /* Disable the mixer controls for current use case
             * for specified device */
            if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
                SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN)) {
                ret = set_controls_of_usecase_for_device(uc_mgr,
                          uc_mgr->card_ctxt_ptr->current_verb, usecase,
                          0, CTRL_LIST_VERB);
                if (ret != 0)
                    ALOGE("Failed to disable controls for use case: %s",
                        uc_mgr->card_ctxt_ptr->current_verb);
            }
            strlcpy(uc_mgr->card_ctxt_ptr->current_verb, value, MAX_STR_LEN);
            /* Enable the mixer controls for the new use case
             * for specified device */
            if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
                SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN)) {
               uc_mgr->card_ctxt_ptr->current_verb_index = index;
               index = 0;
               list_size =
               snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
               for (index = 0; index < list_size; index++) {
                   if ((ident1 = snd_ucm_get_value_at_index(
                       uc_mgr->card_ctxt_ptr->dev_list_head, index))) {
                       if (!strncmp(ident1, usecase, MAX_STR_LEN)) {
                           ALOGV("Device already part of enabled list: %s",
                               usecase);
                           free(ident1);
                           break;
                       }
                       free(ident1);
                   }
               }
               if (index == list_size) {
                   ALOGV("enadev: device value to be enabled: %s", usecase);
                   snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
                        usecase);
               }
               ret = set_controls_of_usecase_for_device(uc_mgr,
                         uc_mgr->card_ctxt_ptr->current_verb, usecase,
                         1, CTRL_LIST_VERB);
            }
        }
    } else if (!strncmp(identifier, "_enadev", 7)) {
        index = 0; ret = 0;
        list_size =
            snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
        for (index = 0; index < list_size; index++) {
            if ((ident1 =
                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
                index))) {
                if (!strncmp(ident1, value, MAX_STR_LEN)) {
                    ALOGV("Device already part of enabled list: %s", value);
                    free(ident1);
                    break;
                }
                free(ident1);
            }
        }
        if (index == list_size) {
            ALOGV("enadev: device value to be enabled: %s", value);
            snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
                value);
        }
        snd_ucm_print_list(uc_mgr->card_ctxt_ptr->dev_list_head);
        /* Apply Mixer controls of usecase for this device*/
        ret = set_controls_of_device_for_usecase(uc_mgr, value, usecase, 1);
    } else if (!strncmp(identifier, "_disdev", 7)) {
        ret = snd_ucm_get_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
                  value);
        if (ret < 0) {
            ALOGD("disdev: device %s not enabled, no need to disable", value);
        } else if (ret == 0) {
            ALOGV("disdev: device %s not active, remove from the list", value);
            ret =
            snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
            value);
            if (ret < 0) {
                ALOGE("Invalid device: Device not part of enabled device list");
            }
        } else {
            ret =
            snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
            value);
            if (ret < 0) {
                ALOGE("Invalid device: Device not part of enabled device list");
            } else {
                ALOGV("disdev: device value to be disabled: %s", value);
                /* Apply Mixer controls of usecase for this device*/
                ret = set_controls_of_device_for_usecase(uc_mgr, value,
                          usecase, 0);
            }
        }
    } else if (!strncmp(identifier, "_enamod", 7)) {
        if (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
            SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN)) {
            ALOGE("Invalid use case verb value");
            ret = -EINVAL;
        } else {
            ret = 0;
            while(strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
                  uc_mgr->card_ctxt_ptr->current_verb, MAX_STR_LEN)) {
                if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
                    SND_UCM_END_OF_LIST, MAX_STR_LEN)){
                    ret = -EINVAL;
                    break;
                }
                index++;
            }
        }
        if (ret < 0) {
            ALOGE("Invalid verb identifier value");
        } else {
            verb_index = index; index = 0; ret = 0;
            verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
            ALOGV("Index:%d Verb:%s", verb_index,
                 uc_mgr->card_ctxt_ptr->verb_list[verb_index]);
            while(strncmp(verb_list[verb_index].modifier_list[index],
                value, MAX_STR_LEN)) {
                if (!strncmp(verb_list[verb_index].modifier_list[index],
                    SND_UCM_END_OF_LIST, MAX_STR_LEN)){
                    ret = -EINVAL;
                    break;
                }
                index++;
            }
            if (ret < 0) {
                ALOGE("Invalid modifier identifier value");
            } else {
                index = 0;
                list_size =
                snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
                for (index = 0; index < list_size; index++) {
                    if ((ident1 = snd_ucm_get_value_at_index(
                        uc_mgr->card_ctxt_ptr->dev_list_head, index))) {
                        if (!strncmp(ident1, usecase, MAX_STR_LEN)) {
                            ALOGV("Device already part of enabled list: %s",
                                usecase);
                            free(ident1);
                            break;
                        }
                        free(ident1);
                    }
                }
                if (index == list_size) {
                    ALOGV("enadev: device value to be enabled: %s", usecase);
                    snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
                         usecase);
                }
                snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
                    value);
                /* Enable the mixer controls for the new use case
                 * for all the enabled devices */
                ret = set_controls_of_usecase_for_device(uc_mgr, value,
                      usecase, 1, CTRL_LIST_MODIFIER);
            }
        }
    } else if (!strncmp(identifier, "_dismod", 7)) {
        ret = snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
              value);
        if (ret < 0) {
            ALOGE("Modifier not enabled currently, invalid modifier");
        } else {
            ALOGV("dismod: modifier value to be disabled: %s", value);
            /* Enable the mixer controls for the new use case
             * for all the enabled devices */
            ret = set_controls_of_usecase_for_device(uc_mgr, value, usecase,
                      0, CTRL_LIST_MODIFIER);
        }
    } else {
        ALOGE("Unknown identifier value: %s", identifier);
    }
    pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
    return ret;
}

/**
 * Open and initialise use case core for sound card
 * uc_mgr - Returned use case manager pointer
 * card_name - Sound card name.
 * returns 0 on success, otherwise a negative error code
 */
int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, const char *card_name)
{
    snd_use_case_mgr_t *uc_mgr_ptr = NULL;
    int index, ret = -EINVAL;
    char tmp[2];

    ALOGV("snd_use_case_open(): card_name %s", card_name);

    if (card_name == NULL) {
        ALOGE("snd_use_case_mgr_open: failed, invalid arguments");
        return ret;
    }

    for (index = 0; index < (int)MAX_NUM_CARDS; index++) {
        if(!strncmp(card_name, card_mapping_list[index].card_name,
           (strlen(card_mapping_list[index].card_name)+1))) {
            ret = 0;
            break;
        }
    }

    if (ret < 0) {
        ALOGE("Card %s not found", card_name);
    } else {
        uc_mgr_ptr = (snd_use_case_mgr_t *)calloc(1,
                         sizeof(snd_use_case_mgr_t));
        if (uc_mgr_ptr == NULL) {
            ALOGE("Failed to allocate memory for instance");
            return -ENOMEM;
        }
        uc_mgr_ptr->snd_card_index = index;
        uc_mgr_ptr->card_ctxt_ptr = (card_ctxt_t *)calloc(1,
                                        sizeof(card_ctxt_t));
        if (uc_mgr_ptr->card_ctxt_ptr == NULL) {
            ALOGE("Failed to allocate memory for card context");
            free(uc_mgr_ptr);
            uc_mgr_ptr = NULL;
            return -ENOMEM;
        }
        uc_mgr_ptr->card_ctxt_ptr->card_number =
            card_mapping_list[index].card_number;
        uc_mgr_ptr->card_ctxt_ptr->card_name =
            (char *)malloc((strlen(card_name)+1)*sizeof(char));
        if (uc_mgr_ptr->card_ctxt_ptr->card_name == NULL) {
            ALOGE("Failed to allocate memory for card name");
            free(uc_mgr_ptr->card_ctxt_ptr);
            free(uc_mgr_ptr);
            uc_mgr_ptr = NULL;
            return -ENOMEM;
        }
        strlcpy(uc_mgr_ptr->card_ctxt_ptr->card_name, card_name,
            ((strlen(card_name)+1)*sizeof(char)));
        uc_mgr_ptr->card_ctxt_ptr->control_device =
            (char *)malloc((strlen("/dev/snd/controlC")+2)*sizeof(char));
        if (uc_mgr_ptr->card_ctxt_ptr->control_device == NULL) {
            ALOGE("Failed to allocate memory for control device string");
            free(uc_mgr_ptr->card_ctxt_ptr->card_name);
            free(uc_mgr_ptr->card_ctxt_ptr);
            free(uc_mgr_ptr);
            uc_mgr_ptr = NULL;
            return -ENOMEM;
        }
        strlcpy(uc_mgr_ptr->card_ctxt_ptr->control_device,
            "/dev/snd/controlC", 18);
        snprintf(tmp, sizeof(tmp), "%d",
            uc_mgr_ptr->card_ctxt_ptr->card_number);
        strlcat(uc_mgr_ptr->card_ctxt_ptr->control_device, tmp,
            (strlen("/dev/snd/controlC")+2)*sizeof(char));
        uc_mgr_ptr->device_list_count = 0;
        uc_mgr_ptr->modifier_list_count = 0;
        uc_mgr_ptr->current_device_list = NULL;
        uc_mgr_ptr->current_modifier_list = NULL;
        uc_mgr_ptr->current_tx_device = -1;
        uc_mgr_ptr->current_rx_device = -1;
        pthread_mutexattr_init(&uc_mgr_ptr->card_ctxt_ptr->card_lock_attr);
        pthread_mutex_init(&uc_mgr_ptr->card_ctxt_ptr->card_lock,
            &uc_mgr_ptr->card_ctxt_ptr->card_lock_attr);
        strlcpy(uc_mgr_ptr->card_ctxt_ptr->current_verb,
                SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN);
        /* Reset all mixer controls if any applied
         * previously for the same card */
    snd_use_case_mgr_reset(uc_mgr_ptr);
        uc_mgr_ptr->card_ctxt_ptr->current_verb_index = -1;
        /* Parse config files and update mixer controls */
        ret = snd_ucm_parse(&uc_mgr_ptr);
        if(ret < 0) {
            ALOGE("Failed to parse config files: %d", ret);
            snd_ucm_free_mixer_list(&uc_mgr_ptr);
        }
        ALOGV("Open mixer device: %s",
            uc_mgr_ptr->card_ctxt_ptr->control_device);
        uc_mgr_ptr->card_ctxt_ptr->mixer_handle =
            mixer_open(uc_mgr_ptr->card_ctxt_ptr->control_device);
        ALOGV("Mixer handle %p", uc_mgr_ptr->card_ctxt_ptr->mixer_handle);
        *uc_mgr = uc_mgr_ptr;
    }
    ALOGV("snd_use_case_open(): returning instance %p", uc_mgr_ptr);
    return ret;
}


/**
 * \brief Reload and re-parse use case configuration files for sound card.
 * \param uc_mgr Use case manager
 * \return zero if success, otherwise a negative error code
 */
int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr) {
    ALOGE("Reload is not implemented for now as there is no use case currently");
    return 0;
}

/**
 * \brief Close use case manager
 * \param uc_mgr Use case manager
 * \return zero if success, otherwise a negative error code
 */
int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
{
    int ret = 0;

    if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) ||
        (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) {
        ALOGE("snd_use_case_mgr_close(): failed, invalid arguments");
        return -EINVAL;
    }

    ALOGV("snd_use_case_close(): instance %p", uc_mgr);
    ret = snd_use_case_mgr_reset(uc_mgr);
    if (ret < 0)
        ALOGE("Failed to reset ucm session");
    snd_ucm_free_mixer_list(&uc_mgr);
    pthread_mutexattr_destroy(&uc_mgr->card_ctxt_ptr->card_lock_attr);
    pthread_mutex_destroy(&uc_mgr->card_ctxt_ptr->card_lock);
    if (uc_mgr->card_ctxt_ptr->mixer_handle) {
        mixer_close(uc_mgr->card_ctxt_ptr->mixer_handle);
        uc_mgr->card_ctxt_ptr->mixer_handle = NULL;
    }
    uc_mgr->snd_card_index = -1;
    uc_mgr->current_tx_device = -1;
    uc_mgr->current_rx_device = -1;
    free(uc_mgr->card_ctxt_ptr->control_device);
    free(uc_mgr->card_ctxt_ptr->card_name);
    free(uc_mgr->card_ctxt_ptr);
    uc_mgr->card_ctxt_ptr = NULL;
    free(uc_mgr);
    uc_mgr = NULL;
    ALOGV("snd_use_case_mgr_close(): card instace closed successfully");
    return ret;
}

/**
 * \brief Reset use case manager verb, device, modifier to deafult settings.
 * \param uc_mgr Use case manager
 * \return zero if success, otherwise a negative error code
 */
int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
{
    char *ident_value;
    int index, list_size, ret = 0;

    ALOGV("snd_use_case_reset(): instance %p", uc_mgr);
    pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
    if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) ||
        (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) {
        ALOGE("snd_use_case_mgr_reset(): failed, invalid arguments");
        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
        return -EINVAL;
    }

    /* Disable mixer controls of all the enabled modifiers */
    list_size = snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
    for (index = (list_size-1); index >= 0; index--) {
        if ((ident_value =
            snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
                index))) {
            snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
                ident_value);
            ret = set_controls_of_usecase_for_all_devices(uc_mgr,
                      ident_value, 0, CTRL_LIST_MODIFIER);
        if (ret != 0)
                ALOGE("Failed to disable mixer controls for %s", ident_value);
            free(ident_value);
        }
    }
    /* Clear the enabled modifiers list */
    if (uc_mgr->modifier_list_count) {
        for (index = 0; index < uc_mgr->modifier_list_count; index++) {
            free(uc_mgr->current_modifier_list[index]);
            uc_mgr->current_modifier_list[index] = NULL;
        }
        free(uc_mgr->current_modifier_list);
        uc_mgr->current_modifier_list = NULL;
        uc_mgr->modifier_list_count = 0;
    }
    /* Disable mixer controls of current use case verb */
    if(strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_USE_CASE_VERB_INACTIVE,
       strlen(SND_USE_CASE_VERB_INACTIVE))) {
        ret = set_controls_of_usecase_for_all_devices(uc_mgr,
                  uc_mgr->card_ctxt_ptr->current_verb, 0, CTRL_LIST_VERB);
        if (ret != 0)
            ALOGE("Failed to disable mixer controls for %s",
                uc_mgr->card_ctxt_ptr->current_verb);
        strlcpy(uc_mgr->card_ctxt_ptr->current_verb, SND_USE_CASE_VERB_INACTIVE,
            MAX_STR_LEN);
    }
    /* Disable mixer controls of all the enabled devices */
    list_size = snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
    for (index = (list_size-1); index >= 0; index--) {
        if ((ident_value =
            snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
                index))) {
            snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
                ident_value);
            ret = set_controls_of_device_for_all_usecases(uc_mgr,
                      ident_value, 0);
        if (ret != 0)
                ALOGE("Failed to disable or no mixer controls set for %s",
                    ident_value);
        free(ident_value);
        }
    }
    /* Clear the enabled devices list */
    if (uc_mgr->device_list_count) {
        for (index = 0; index < uc_mgr->device_list_count; index++) {
            free(uc_mgr->current_device_list[index]);
            uc_mgr->current_device_list[index] = NULL;
        }
        free(uc_mgr->current_device_list);
        uc_mgr->current_device_list = NULL;
        uc_mgr->device_list_count = 0;
    }
    uc_mgr->current_tx_device = -1;
    uc_mgr->current_rx_device = -1;
    pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
    return ret;
}

/* 2nd stage parsing done in seperate thread */
void *second_stage_parsing_thread(void *uc_mgr_ptr)
{
    use_case_verb_t *verb_list;
    char path[200];
    struct stat st;
    int fd, index = 0, ret = 0, rc = 0;
    char *read_buf = NULL, *next_str = NULL, *current_str = NULL, *buf = NULL;
    char *p = NULL, *verb_name = NULL, *file_name = NULL, *temp_ptr = NULL;
    snd_use_case_mgr_t **uc_mgr = (snd_use_case_mgr_t **)&uc_mgr_ptr;

    strlcpy(path, CONFIG_DIR, (strlen(CONFIG_DIR)+1));
    strlcat(path, (*uc_mgr)->card_ctxt_ptr->card_name, sizeof(path));
    ALOGV("master config file path:%s", path);
    fd = open(path, O_RDONLY);
    if (fd < 0) {
        ALOGE("failed to open config file %s error %d\n", path, errno);
        return NULL;
    }
    if (fstat(fd, &st) < 0) {
        ALOGE("failed to stat %s error %d\n", path, errno);
        close(fd);
        return NULL;
    }
    read_buf = (char *) mmap(0, st.st_size, PROT_READ | PROT_WRITE,
               MAP_PRIVATE, fd, 0);
    if (read_buf == MAP_FAILED) {
        ALOGE("failed to mmap file error %d\n", errno);
        close(fd);
        return NULL;
    }
    current_str = read_buf;
    verb_name = NULL;
    while (*current_str != (char)EOF)  {
        next_str = strchr(current_str, '\n');
        if (!next_str)
            break;
        *next_str++ = '\0';
        if (verb_name == NULL) {
            buf = strstr(current_str, "SectionUseCase");
            if (buf == NULL) {
                if((current_str = next_str) == NULL)
                    break;
                else
                    continue;
            }
            /* Ignore parsing first use case (HiFi) as it is already parsed
             * in 1st stage of parsing */
            if (index == 0) {
                index++;
                if((current_str = next_str) == NULL)
                    break;
                else
                    continue;
            }
            p = strtok_r(buf, ".", &temp_ptr);
            while (p != NULL) {
                p = strtok_r(NULL, "\"", &temp_ptr);
                if (p == NULL)
                    break;
                verb_name = (char *)malloc((strlen(p)+1)*sizeof(char));
                if(verb_name == NULL) {
                    ret = -ENOMEM;
                    break;
                }
                strlcpy(verb_name, p, (strlen(p)+1)*sizeof(char));
                break;
            }
        } else {
            buf = strstr(current_str, "File");
            if (buf == NULL) {
                if((current_str = next_str) == NULL)
                    break;
                else
                    continue;
            }
            p = strtok_r(buf, "\"", &temp_ptr);
            while (p != NULL) {
                p = strtok_r(NULL, "\"", &temp_ptr);
                if (p == NULL)
                    break;
                file_name = (char *)malloc((strlen(p)+1)*sizeof(char));
                if(file_name == NULL) {
                    ret = -ENOMEM;
                    break;
                }
                strlcpy(file_name, p, (strlen(p)+1)*sizeof(char));
                break;
            }
            verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
            if (file_name != NULL) {
                ret = snd_ucm_parse_verb(uc_mgr, file_name, index);
                verb_list[index].use_case_name =
                    (char *)malloc((strlen(verb_name)+1)*sizeof(char));
                strlcpy(verb_list[index].use_case_name, verb_name,
                    ((strlen(verb_name)+1)*sizeof(char)));
                /* Verb list might have been appended with END OF LIST in
                 * 1st stage parsing. Delete this entry so that new verbs
                 * are appended from here and END OF LIST will be added
                 * again at the end of 2nd stage parsing
                 */
                if((*uc_mgr)->card_ctxt_ptr->verb_list[index]) {
                    free((*uc_mgr)->card_ctxt_ptr->verb_list[index]);
                    (*uc_mgr)->card_ctxt_ptr->verb_list[index] = NULL;
                }
                (*uc_mgr)->card_ctxt_ptr->verb_list[index] =
                    (char *)malloc((strlen(verb_name)+1)*sizeof(char));
                strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index], verb_name,
                    ((strlen(verb_name)+1)*sizeof(char)));
                free(verb_name);
                verb_name = NULL;
                free(file_name);
                file_name = NULL;
            }
            index++;
            (*uc_mgr)->card_ctxt_ptr->verb_list[index] =
                (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
            strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index],
                 SND_UCM_END_OF_LIST,
                 ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
        }
        if((current_str = next_str) == NULL)
            break;
    }
    if (verb_name != NULL) {
        free(verb_name);
        verb_name = NULL;
    }
    if (file_name != NULL) {
        free(file_name);
        file_name = NULL;
    }
    munmap(read_buf, st.st_size);
    close(fd);
#if PARSE_DEBUG
        /* Prints use cases and mixer controls parsed from config files */
        snd_ucm_print((*uc_mgr));
#endif
    if(ret < 0)
        ALOGE("Failed to parse config files: %d", ret);
    ALOGE("Exiting parsing thread uc_mgr %p\n", uc_mgr);
    return NULL;
}

/* Function can be used by UCM clients to wait until parsing completes
 * uc_mgr - use case manager structure
 * Returns 0 on success, error number otherwise
*/
int snd_use_case_mgr_wait_for_parsing(snd_use_case_mgr_t *uc_mgr)
{
    int ret;

    ret = pthread_join(uc_mgr->thr, NULL);
    return ret;
}

/* Parse config files and update mixer controls for the use cases
 * 1st stage parsing done to parse HiFi config file
 * uc_mgr - use case manager structure
 * Returns 0 on sucess, negative error code otherwise
 */
static int snd_ucm_parse(snd_use_case_mgr_t **uc_mgr)
{
    use_case_verb_t *verb_list;
    struct stat st;
    int fd, verb_count, index = 0, ret = 0, rc;
    char *read_buf, *next_str, *current_str, *buf, *p, *verb_name;
    char *file_name = NULL, *temp_ptr;
    char path[200];

    strlcpy(path, CONFIG_DIR, (strlen(CONFIG_DIR)+1));
    strlcat(path, (*uc_mgr)->card_ctxt_ptr->card_name, sizeof(path));
    ALOGV("master config file path:%s", path);
    fd = open(path, O_RDONLY);
    if (fd < 0) {
        ALOGE("failed to open config file %s error %d\n", path, errno);
        return -EINVAL;
    }
    if (fstat(fd, &st) < 0) {
        ALOGE("failed to stat %s error %d\n", path, errno);
        close(fd);
        return -EINVAL;
    }
    read_buf = (char *) mmap(0, st.st_size, PROT_READ | PROT_WRITE,
               MAP_PRIVATE, fd, 0);
    if (read_buf == MAP_FAILED) {
        ALOGE("failed to mmap file error %d\n", errno);
        close(fd);
        return -EINVAL;
    }
    current_str = read_buf;
    verb_count = get_verb_count(current_str);
    (*uc_mgr)->card_ctxt_ptr->use_case_verb_list =
        (use_case_verb_t *)malloc((verb_count+1)*(sizeof(use_case_verb_t)));
    if ((*uc_mgr)->card_ctxt_ptr->use_case_verb_list == NULL) {
        ALOGE("failed to allocate memory for use case verb list\n");
        munmap(read_buf, st.st_size);
        close(fd);
        return -ENOMEM;
    }
    if (((*uc_mgr)->card_ctxt_ptr->verb_list =
        (char **)malloc((verb_count+2)*(sizeof(char *)))) == NULL) {
        ALOGE("failed to allocate memory for verb list\n");
        munmap(read_buf, st.st_size);
        close(fd);
        return -ENOMEM;
    }
    verb_name = NULL;
    if ((ret = is_single_config_format(current_str))) {
        ALOGD("Single config file format detected\n");
        ret = parse_single_config_format(uc_mgr, current_str, verb_count);
        munmap(read_buf, st.st_size);
        close(fd);
        return ret;
    }
    while (*current_str != (char)EOF)  {
        next_str = strchr(current_str, '\n');
        if (!next_str)
            break;
        *next_str++ = '\0';
        if (verb_name == NULL) {
            buf = strstr(current_str, "SectionUseCase");
            if (buf == NULL) {
                if((current_str = next_str) == NULL)
                    break;
                else
                    continue;
            }
            verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
            p = strtok_r(buf, ".", &temp_ptr);
            while (p != NULL) {
                p = strtok_r(NULL, "\"", &temp_ptr);
                if (p == NULL)
                    break;
                verb_name = (char *)malloc((strlen(p)+1)*sizeof(char));
                if(verb_name == NULL) {
                    ret = -ENOMEM;
                    break;
                }
                strlcpy(verb_name, p, (strlen(p)+1)*sizeof(char));
                if ((verb_list[index].use_case_name =
                    (char *)malloc((strlen(verb_name)+1)*sizeof(char)))) {
                    strlcpy(verb_list[index].use_case_name,
                        verb_name, ((strlen(verb_name)+1)*sizeof(char)));
                } else {
                    ret = -ENOMEM;
                    break;
                }
                if (((*uc_mgr)->card_ctxt_ptr->verb_list[index] =
                    (char *)malloc((strlen(verb_name)+1)*sizeof(char)))) {
                    strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index],
                        verb_name, ((strlen(verb_name)+1)*sizeof(char)));
                } else {
                    ret = -ENOMEM;
                    break;
                }
                break;
            }
        } else {
            buf = strstr(current_str, "File");
            if (buf == NULL) {
                if((current_str = next_str) == NULL)
                    break;
                else
                    continue;
            }
            p = strtok_r(buf, "\"", &temp_ptr);
            while (p != NULL) {
                p = strtok_r(NULL, "\"", &temp_ptr);
                if (p == NULL)
                    break;
                file_name = (char *)malloc((strlen(p)+1)*sizeof(char));
                if(file_name == NULL) {
                    ret = -ENOMEM;
                    break;
                }
                strlcpy(file_name, p, (strlen(p)+1)*sizeof(char));
                break;
            }
            if (file_name != NULL) {
                ret = snd_ucm_parse_verb(uc_mgr, file_name, index);
                if (ret < 0)
                    ALOGE("Failed to parse config file %s\n", file_name);
                free(verb_name);
                verb_name = NULL;
                free(file_name);
                file_name = NULL;
            }
            index++;
            /* Break here so that only one first use case config file (HiFi)
             * from master config file is parsed initially and all other
             * config files are parsed in seperate thread created below so
             * that audio HAL can initialize faster during boot-up
             */
            break;
        }
        if((current_str = next_str) == NULL)
            break;
    }
    munmap(read_buf, st.st_size);
    close(fd);
    if (((*uc_mgr)->card_ctxt_ptr->verb_list[index] =
        (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)))) {
        strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index], SND_UCM_END_OF_LIST,
                ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
    } else {
        ALOGE("Failed to allocate memory\n");
        ret = -ENOMEM;
    }
    if (!ret) {
        ALOGD("Creating Parsing thread uc_mgr %p\n", uc_mgr);
        rc = pthread_create(&(*uc_mgr)->thr, 0, second_stage_parsing_thread,
                 (void*)(*uc_mgr));
        if(rc < 0) {
            ALOGE("Failed to create parsing thread rc %d errno %d\n", rc, errno);
        } else {
            ALOGV("Prasing thread created successfully\n");
        }
    }
    if (verb_name)
        free(verb_name);
    if (file_name)
        free(file_name);
    return ret;
}

/* Parse a single config file format
 * uc_mgr - use case manager structure
 * buf - config file buffer to be parsed
 * Returns 0 on sucess, negative error code otherwise
 */
static int parse_single_config_format(snd_use_case_mgr_t **uc_mgr,
char *current_str, int num_verbs)
{
    struct stat st;
    card_mctrl_t *list;
    use_case_verb_t *verb_list;
    int verb_count = 0, device_count = 0, mod_count = 0, index = -1, ret = 0;
    char *next_str, *buf, *p, *verb_ptr, *temp_ptr;

    verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
    while (*current_str != (char)EOF)  {
        next_str = strchr(current_str, '\n');
        if (!next_str)
            break;
        *next_str++ = '\0';
        if ((buf = strcasestr(current_str, "SectionUseCase")) != NULL) {
            if (index != -1) {
                list = (verb_list[index].verb_ctrls +
                            verb_list[index].verb_count);
                list->case_name = (char *)
                    malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
                if(list->case_name == NULL) {
                    free(verb_list[index].verb_ctrls);
                    return -ENOMEM;
                }
                strlcpy(list->case_name, SND_UCM_END_OF_LIST,
                   (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
                list->ena_mixer_list = NULL;
                list->dis_mixer_list = NULL;
                list->ena_mixer_count = 0;
                list->dis_mixer_count = 0;
                list->playback_dev_name = NULL;
                list->capture_dev_name = NULL;
                list->acdb_id = 0;
                list->capability = 0;
            }
            index++;
            p = strtok_r(buf, ".", &temp_ptr);
            while (p != NULL) {
                p = strtok_r(NULL, "\"", &temp_ptr);
                if (p == NULL)
                    break;
                if ((verb_list[index].use_case_name =
                    (char *)malloc((strlen(p)+1)*sizeof(char)))) {
                    strlcpy(verb_list[index].use_case_name,
                        p, ((strlen(p)+1)*sizeof(char)));
                } else {
                    ret = -ENOMEM;
                    break;
                }
                if (((*uc_mgr)->card_ctxt_ptr->verb_list[index] =
                    (char *)malloc((strlen(p)+1)*sizeof(char)))) {
                    strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index],
                       p, ((strlen(p)+1)*sizeof(char)));
                } else {
                    ret = -ENOMEM;
                    break;
                }
                break;
            }
            verb_list[index].verb_count = 0;
            verb_list[index].device_count = 0;
            verb_list[index].mod_count = 0;
            verb_list[index].device_list = NULL;
            verb_list[index].modifier_list = NULL;
            verb_list[index].verb_ctrls = NULL;
            verb_list[index].device_ctrls = NULL;
            verb_list[index].mod_ctrls = NULL;
            verb_count = get_num_verbs_config_format(next_str);
            verb_list[index].verb_ctrls = (card_mctrl_t *)
                malloc((verb_count+1)*sizeof(card_mctrl_t));
            if (verb_list[index].verb_ctrls == NULL) {
               ret = -ENOMEM;
               break;
            }
            verb_list[index].verb_count = 0;
        } else if (!strncasecmp(current_str, "SectionVerb", 11)) {
            ret = snd_ucm_parse_section(uc_mgr, &current_str,
                    &next_str, index, CTRL_LIST_VERB);
            if (ret < 0)
                break;
        } else if (!strncasecmp(current_str, "SectionDevice", 13)) {
            if (device_count == 0) {
                device_count = get_num_device_config_format(next_str);
                verb_list[0].device_ctrls = (card_mctrl_t *)
                    malloc((device_count+1)*sizeof(card_mctrl_t));
                if (verb_list[0].device_ctrls == NULL) {
                    ret = -ENOMEM;
                    break;
                }
                verb_list[0].device_list =
                    (char **)malloc((device_count+1)*sizeof(char *));
                if (verb_list[0].device_list == NULL)
                    return -ENOMEM;
                verb_list[0].device_count = 0;
            }
            ret = snd_ucm_parse_section(uc_mgr, &current_str,
                      &next_str, 0, CTRL_LIST_DEVICE);
            if (ret < 0) {
                break;
            } else {
                list = (verb_list[0].device_ctrls +
                           (verb_list[0].device_count - 1));
                verb_ptr = (char *)
                    malloc((strlen(list->case_name)+1)*sizeof(char));
                    if (verb_ptr == NULL) {
                        ret = -ENOMEM;
                        break;
                    }
                    strlcpy(verb_ptr, list->case_name,
                        ((strlen(list->case_name)+1)*sizeof(char)));
                    verb_list[0].device_list[(verb_list[0].device_count-1)]
                        = verb_ptr;
            }
        } else if (!strncasecmp(current_str, "SectionModifier", 15)) {
            if (mod_count == 0) {
                mod_count = get_num_mod_config_format(next_str);
                verb_list[0].mod_ctrls = (card_mctrl_t *)
                    malloc((mod_count+1)*sizeof(card_mctrl_t));
                if (verb_list[0].mod_ctrls == NULL) {
                    ret = -ENOMEM;
                    break;
                }
                verb_list[0].modifier_list =
                    (char **)malloc((mod_count+1)*sizeof(char *));
                if (verb_list[0].modifier_list == NULL)
                    return -ENOMEM;
                verb_list[0].mod_count = 0;
            }
            ret = snd_ucm_parse_section(uc_mgr, &current_str,
                     &next_str, 0, CTRL_LIST_MODIFIER);
            if (ret < 0) {
                break;
            } else {
                list = (verb_list[0].mod_ctrls +
                        (verb_list[0].mod_count - 1));
                verb_ptr = (char *)
                    malloc((strlen(list->case_name)+1)*sizeof(char));
                if (verb_ptr == NULL) {
                    ret = -ENOMEM;
                    break;
                }
                strlcpy(verb_ptr, list->case_name,
                   ((strlen(list->case_name)+1)*sizeof(char)));
                verb_list[0].modifier_list[(verb_list[0].mod_count - 1)]
                    = verb_ptr;
            }
        }
        if((current_str = next_str) == NULL)
            break;
    }
    list = (verb_list[index].verb_ctrls +
            verb_list[index].verb_count);
    list->case_name =
        (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
    if(list->case_name == NULL) {
        free(verb_list[index].verb_ctrls);
        return -ENOMEM;
    }
    strlcpy(list->case_name, SND_UCM_END_OF_LIST,
        (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
    list->ena_mixer_list = NULL;
    list->dis_mixer_list = NULL;
    list->ena_mixer_count = 0;
    list->dis_mixer_count = 0;
    list->playback_dev_name = NULL;
    list->capture_dev_name = NULL;
    list->acdb_id = 0;
    list->capability = 0;
    index++;
    if (index != -1) {
        if (((*uc_mgr)->card_ctxt_ptr->verb_list[index] =
            (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)))) {
            strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index],
                SND_UCM_END_OF_LIST,
                ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
        } else {
            ALOGE("Failed to allocate memory\n");
            ret = -ENOMEM;
        }
    }
    /* Add end of list to device list */
    verb_ptr =
       (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
    if (verb_ptr == NULL)
        return -ENOMEM;
    strlcpy(verb_ptr, SND_UCM_END_OF_LIST,
        ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
    verb_list[0].device_list[verb_list[0].device_count] = verb_ptr;
    /* Add end of list to modifier list */
    verb_ptr =
    (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
        if (verb_ptr == NULL)
            return -ENOMEM;
    strlcpy(verb_ptr, SND_UCM_END_OF_LIST,
        ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
    verb_list[0].modifier_list[verb_list[0].mod_count] = verb_ptr;
    /* Add end of list to device controls list */
    list = (verb_list[0].device_ctrls +
               verb_list[0].device_count);
    list->case_name =
        (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
    if(list->case_name == NULL) {
        free(verb_list[0].device_ctrls);
        return -ENOMEM;
    }
    strlcpy(list->case_name, SND_UCM_END_OF_LIST,
        (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
    list->ena_mixer_list = NULL;
    list->dis_mixer_list = NULL;
    list->ena_mixer_count = 0;
    list->dis_mixer_count = 0;
    list->playback_dev_name = NULL;
    list->capture_dev_name = NULL;
    list->acdb_id = 0;
    list->capability = 0;
    /* Add end of list to modifier controls list */
    list = (verb_list[0].mod_ctrls +
        verb_list[0].mod_count);
    list->case_name =
        (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
    if(list->case_name == NULL) {
        free(verb_list[0].mod_ctrls);
        return -ENOMEM;
    }
    strlcpy(list->case_name, SND_UCM_END_OF_LIST,
        (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
    list->ena_mixer_list = NULL;
    list->dis_mixer_list = NULL;
    list->ena_mixer_count = 0;
    list->dis_mixer_count = 0;
    list->playback_dev_name = NULL;
    list->capture_dev_name = NULL;
    list->acdb_id = 0;
    list->capability = 0;
    for (index = 1; index < num_verbs; index++) {
        verb_list[index].device_ctrls = verb_list[0].device_ctrls;
        verb_list[index].device_list = verb_list[0].device_list;
        verb_list[index].device_count = verb_list[0].device_count;
        verb_list[index].mod_ctrls = verb_list[0].mod_ctrls;
        verb_list[index].modifier_list = verb_list[0].modifier_list;
        verb_list[index].mod_count = verb_list[0].mod_count;
    }
    if (ret < 0) {
        ALOGE("Failed to parse config file ret %d errno %d\n", ret, errno);
    } else {
        ALOGV("Prasing done successfully\n");
#if PARSE_DEBUG
        /* Prints use cases and mixer controls parsed from config files */
        snd_ucm_print((*uc_mgr));
#endif
    }
    return ret;
}

/* Returns number of verb sections for specific use case verb*/
static int get_num_verbs_config_format(const char *nxt_str)
{
    char *current_str, *next_str, *str_addr, *buf;
    int count = 0;

    next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
    if (next_str == NULL) {
        ALOGE("Failed to allocate memory");
        return -ENOMEM;
    }
    strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
    str_addr = next_str;
    current_str = next_str;
    while(1) {
        next_str = strchr(current_str, '\n');
        if (!next_str)
            break;
        *next_str++ = '\0';
        buf = strcasestr(current_str, "SectionUseCase");
        if (buf != NULL)
            break;
        buf = strcasestr(current_str, "SectionVerb");
        if (buf != NULL)
            count++;
        if (*next_str == (char)EOF)
            break;
        if((current_str = next_str) == NULL)
            break;
    }
    free(str_addr);
    return count;
}

/* Returns number of common device sections for all use case verbs*/
static int get_num_device_config_format(const char *nxt_str)
{
    char *current_str, *next_str, *str_addr, *buf;
    int count = 1;

    next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
    if (next_str == NULL) {
        ALOGE("Failed to allocate memory");
        return -ENOMEM;
    }
    strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
    str_addr = next_str;
    current_str = next_str;
    while(1) {
        next_str = strchr(current_str, '\n');
        if (!next_str)
            break;
        *next_str++ = '\0';
        buf = strcasestr(current_str, "SectionDevice");
        if (buf != NULL)
            count++;
        if (*next_str == (char)EOF)
            break;
        if((current_str = next_str) == NULL)
            break;
    }
    free(str_addr);
    return count;
}

/* Returns number of common modifier sections for all use case verbs*/
static int get_num_mod_config_format(const char *nxt_str)
{
    char *current_str, *next_str, *str_addr, *buf;
    int count = 1;

    next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
    if (next_str == NULL) {
        ALOGE("Failed to allocate memory");
        return -ENOMEM;
    }
    strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
    str_addr = next_str;
    current_str = next_str;
    while(1) {
        next_str = strchr(current_str, '\n');
        if (!next_str)
            break;
        *next_str++ = '\0';
        buf = strcasestr(current_str, "SectionModifier");
        if (buf != NULL)
            count++;
        if (*next_str == (char)EOF)
            break;
        if((current_str = next_str) == NULL)
            break;
    }
    free(str_addr);
    return count;
}

/* Gets the number of use case verbs defined by master config file */
static int get_verb_count(const char *nxt_str)
{
    char *current_str, *next_str, *str_addr, *buf, *p;
    int count = 0;

    next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
    if (next_str == NULL) {
        ALOGE("Failed to allocate memory");
        return -ENOMEM;
    }
    strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
    str_addr = next_str;
    current_str = next_str;
    while(1) {
        next_str = strchr(current_str, '\n');
        if (!next_str)
            break;
        *next_str++ = '\0';
        buf = strstr(current_str, "SectionUseCase");
        if (buf != NULL)
            count++;
        if (*next_str == (char)EOF)
            break;
        if((current_str = next_str) == NULL)
            break;
    }
    free(str_addr);
    return count;
}

/* Returns one if single config file per sound card format is being used */
static int is_single_config_format(const char *nxt_str)
{
    char *current_str, *next_str, *str_addr, *buf;
    int ret = 1, count = 0;

    next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
    if (next_str == NULL) {
        ALOGE("Failed to allocate memory");
        return -ENOMEM;
    }
    strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
    str_addr = next_str;
    current_str = next_str;
    while(1) {
        next_str = strchr(current_str, '\n');
        if (!next_str)
            break;
        *next_str++ = '\0';
        buf = strstr(current_str, "SectionUseCase");
        if (buf != NULL)
            count++;
        buf = strstr(current_str, "File");
        if (buf != NULL)
            ret = 0;
        if ((*next_str == (char)EOF) || (count == 2))
            break;
        if((current_str = next_str) == NULL)
            break;
    }
    free(str_addr);
    return ret;
}

/* Parse a use case verb config files and update mixer controls for the verb
 * uc_mgr - use case manager structure
 * file_name - use case verb config file name
 * index - index of the verb in the list
 * Returns 0 on sucess, negative error code otherwise
 */
static int snd_ucm_parse_verb(snd_use_case_mgr_t **uc_mgr,
const char *file_name, int index)
{
    struct stat st;
    card_mctrl_t *list;
    int device_count, modifier_count;
    int fd, ret = 0, parse_count = 0;
    char *read_buf, *next_str, *current_str, *verb_ptr;
    char path[200];
    use_case_verb_t *verb_list;

    strlcpy(path, CONFIG_DIR, (strlen(CONFIG_DIR)+1));
    strlcat(path, file_name, sizeof(path));
    ALOGV("path:%s", path);
    verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
    while(1) {
        device_count = 0; modifier_count = 0;
        if (parse_count == 0) {
            verb_list[index].verb_count = 0;
            verb_list[index].device_count = 0;
            verb_list[index].mod_count = 0;
            verb_list[index].device_list = NULL;
            verb_list[index].modifier_list = NULL;
            verb_list[index].verb_ctrls = NULL;
            verb_list[index].device_ctrls = NULL;
            verb_list[index].mod_ctrls = NULL;
        }
        fd = open(path, O_RDONLY);
        if (fd < 0) {
             ALOGE("failed to open config file %s error %d\n", path, errno);
             return -EINVAL;
        }
        if (fstat(fd, &st) < 0) {
            ALOGE("failed to stat %s error %d\n", path, errno);
            close(fd);
            return -EINVAL;
        }
        read_buf = (char *) mmap(0, st.st_size, PROT_READ | PROT_WRITE,
                   MAP_PRIVATE, fd, 0);
        if (read_buf == MAP_FAILED) {
            ALOGE("failed to mmap file error %d\n", errno);
            close(fd);
            return -EINVAL;
        }
        current_str = read_buf;
        while (*current_str != (char)EOF)  {
            next_str = strchr(current_str, '\n');
            if (!next_str)
                break;
            *next_str++ = '\0';
            if (!strncasecmp(current_str, "SectionVerb", 11)) {
                if (parse_count == 0) {
                    verb_list[index].verb_count++;
                } else {
                    ret = snd_ucm_parse_section(uc_mgr, &current_str,
                              &next_str, index, CTRL_LIST_VERB);
                    if (ret < 0)
                        break;
                }
            } else if (!strncasecmp(current_str, "SectionDevice", 13)) {
                if (parse_count == 0) {
                    verb_list[index].device_count++;
                    device_count++;
                } else {
                    ret = snd_ucm_parse_section(uc_mgr, &current_str,
                              &next_str, index, CTRL_LIST_DEVICE);
                    if (ret < 0) {
                        break;
                    } else {
                        list = (verb_list[index].device_ctrls +
                                   (verb_list[index].device_count - 1));
                        verb_ptr = (char *)
                            malloc((strlen(list->case_name)+1)*sizeof(char));
                        if (verb_ptr == NULL) {
                            ret = -ENOMEM;
                            break;
                        }
                        strlcpy(verb_ptr, list->case_name,
                            ((strlen(list->case_name)+1)*sizeof(char)));
                        verb_list[index].device_list[device_count] = verb_ptr;
                        device_count++;
                    }
                }
            } else if (!strncasecmp(current_str, "SectionModifier", 15)) {
                if (parse_count == 0) {
                    verb_list[index].mod_count++;
                    modifier_count++;
                } else {
                    ret = snd_ucm_parse_section(uc_mgr, &current_str,
                              &next_str, index, CTRL_LIST_MODIFIER);
                    if (ret < 0) {
                        break;
                    } else {
                        list = (verb_list[index].mod_ctrls +
                               (verb_list[index].mod_count - 1));
                        verb_ptr = (char *)
                            malloc((strlen(list->case_name)+1)*sizeof(char));
                        if (verb_ptr == NULL) {
                            ret = -ENOMEM;
                            break;
                        }
                        strlcpy(verb_ptr, list->case_name,
                            ((strlen(list->case_name)+1)*sizeof(char)));
                        verb_list[index].modifier_list[modifier_count]
                            = verb_ptr;
                        modifier_count++;
                    }
                }
            }
            if((current_str = next_str) == NULL)
                break;
        }
        munmap(read_buf, st.st_size);
        close(fd);
        if(ret < 0)
            return ret;
        if (parse_count == 0) {
            verb_list[index].device_list =
                (char **)malloc((device_count+1)*sizeof(char *));
            if (verb_list[index].device_list == NULL)
                return -ENOMEM;
            verb_list[index].modifier_list =
                (char **)malloc((modifier_count+1)*sizeof(char *));
            if (verb_list[index].modifier_list == NULL)
                return -ENOMEM;
            parse_count += verb_list[index].verb_count;
            verb_list[index].verb_ctrls = (card_mctrl_t *)
                malloc((verb_list[index].verb_count+1)*sizeof(card_mctrl_t));
            if (verb_list[index].verb_ctrls == NULL) {
               ret = -ENOMEM;
               break;
            }
            verb_list[index].verb_count = 0;
            parse_count += verb_list[index].device_count;
            verb_list[index].device_ctrls = (card_mctrl_t *)
                malloc((verb_list[index].device_count+1)*sizeof(card_mctrl_t));
            if (verb_list[index].device_ctrls == NULL) {
               ret = -ENOMEM;
               break;
            }
            verb_list[index].device_count = 0;
            parse_count += verb_list[index].mod_count;
            verb_list[index].mod_ctrls = (card_mctrl_t *)
                malloc((verb_list[index].mod_count+1)*sizeof(card_mctrl_t));
            if (verb_list[index].mod_ctrls == NULL) {
               ret = -ENOMEM;
               break;
            }
            verb_list[index].mod_count = 0;
            continue;
        } else {
            verb_ptr =
            (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
            if (verb_ptr == NULL)
                return -ENOMEM;
            strlcpy(verb_ptr, SND_UCM_END_OF_LIST,
                ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
            verb_list[index].device_list[device_count] = verb_ptr;
            verb_ptr =
            (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
            if (verb_ptr == NULL)
                return -ENOMEM;
            strlcpy(verb_ptr, SND_UCM_END_OF_LIST,
                ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
            verb_list[index].modifier_list[modifier_count] = verb_ptr;
            list = (verb_list[index].verb_ctrls +
                       verb_list[index].verb_count);
            list->case_name =
                 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
            if(list->case_name == NULL) {
                free(verb_list[index].verb_ctrls);
                return -ENOMEM;
            }
            strlcpy(list->case_name, SND_UCM_END_OF_LIST,
               (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
            list->ena_mixer_list = NULL;
            list->dis_mixer_list = NULL;
            list->ena_mixer_count = 0;
            list->dis_mixer_count = 0;
            list->playback_dev_name = NULL;
            list->capture_dev_name = NULL;
            list->acdb_id = 0;
            list->capability = 0;
            list = (verb_list[index].device_ctrls +
                       verb_list[index].device_count);
            list->case_name =
                 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
            if(list->case_name == NULL) {
                free(verb_list[index].device_ctrls);
                return -ENOMEM;
            }
            strlcpy(list->case_name, SND_UCM_END_OF_LIST,
               (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
            list->ena_mixer_list = NULL;
            list->dis_mixer_list = NULL;
            list->ena_mixer_count = 0;
            list->dis_mixer_count = 0;
            list->playback_dev_name = NULL;
            list->capture_dev_name = NULL;
            list->acdb_id = 0;
            list->capability = 0;
            list = (verb_list[index].mod_ctrls +
                       verb_list[index].mod_count);
            list->case_name =
                 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
            if(list->case_name == NULL) {
                free(verb_list[index].mod_ctrls);
                return -ENOMEM;
            }
            strlcpy(list->case_name, SND_UCM_END_OF_LIST,
               (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
            list->ena_mixer_list = NULL;
            list->dis_mixer_list = NULL;
            list->ena_mixer_count = 0;
            list->dis_mixer_count = 0;
            list->playback_dev_name = NULL;
            list->capture_dev_name = NULL;
            list->acdb_id = 0;
            list->capability = 0;
            parse_count = 0;
            break;
        }
    }
    return ret;
}

/* Print mixer controls in a specific list
 * list - list to be printed
 * verb_index - verb index
 * count - number of elements in the list
 * Returns 0 on sucess, negative error code otherwise
 */
static int print_list(card_mctrl_t *list, int verb_index, int count)
{
    int i, j;

    for(i=0; i < count; i++) {
        ALOGD("\tcase name: %s\n", list[i].case_name);
        ALOGD("\tEnable sequence: %d\n", list[i].ena_mixer_count);
        for(j=0; j<list[i].ena_mixer_count; j++) {
            ALOGD("\t\t%s : %d : %d: %s\n",
                list[i].ena_mixer_list[j].control_name,
                list[i].ena_mixer_list[j].type,
                list[i].ena_mixer_list[j].value,
                list[i].ena_mixer_list[j].string);
        }
        ALOGD("\tDisable sequence: %d\n", list[i].dis_mixer_count);
        for(j=0; j<list[i].dis_mixer_count; j++) {
            ALOGD("\t\t%s : %d : %d : %s\n",
                list[i].dis_mixer_list[j].control_name,
                list[i].dis_mixer_list[j].type,
                list[i].dis_mixer_list[j].value,
                list[i].dis_mixer_list[j].string);
        }
    }
    return 0;
}

/* Print mixer controls extracted from config files
 * uc_mgr - use case manager structure
 * Returns 0 on sucess, negative error code otherwise
 */
static int snd_ucm_print(snd_use_case_mgr_t *uc_mgr)
{
    card_mctrl_t *list;
    int i, j, verb_index = 0;
    use_case_verb_t *verb_list;

    pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
    verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
    while(strncmp(uc_mgr->card_ctxt_ptr->verb_list[verb_index],
         SND_UCM_END_OF_LIST, 3)) {
        ALOGD("\nuse case verb: %s\n",
            uc_mgr->card_ctxt_ptr->verb_list[verb_index]);
        if(verb_list[verb_index].device_list) {
            ALOGD("\tValid device list:");
            i = 0;
            while(strncmp(verb_list[verb_index].device_list[i],
                  SND_UCM_END_OF_LIST, 3)) {
                ALOGD("\t\t%s", verb_list[verb_index].device_list[i]);
                i++;
            }
        }
        if(verb_list[verb_index].modifier_list) {
            ALOGD("\tValid modifier list:");
            i = 0;
            while(strncmp(verb_list[verb_index].modifier_list[i],
                  SND_UCM_END_OF_LIST, 3)) {
                ALOGD("\t\t%s", verb_list[verb_index].modifier_list[i]);
                i++;
            }
        }
        ALOGD("Verbs:\n");
        list = verb_list[verb_index].verb_ctrls;
        print_list(list, verb_index, verb_list[verb_index].verb_count);
        ALOGD("Devices:\n");
        list = verb_list[verb_index].device_ctrls;
        print_list(list, verb_index, verb_list[verb_index].device_count);
        ALOGD("Modifier:\n");
        list = verb_list[verb_index].mod_ctrls;
        print_list(list, verb_index, verb_list[verb_index].mod_count);
        verb_index++;
    }
    pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
    return 0;
}

/* Gets the number of controls for specific sequence of a use cae */
static int get_controls_count(const char *nxt_str)
{
    char *current_str, *next_str, *str_addr;
    int count = 0;

    next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
    if (next_str == NULL) {
        ALOGE("Failed to allocate memory");
        return -ENOMEM;
    }
    strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
    str_addr = next_str;
    while(1) {
        current_str = next_str;
        next_str = strchr(current_str, '\n');
        if ((!next_str) || (!strncasecmp(current_str, "EndSection", 10)))
            break;
        *next_str++ = '\0';
        if (strcasestr(current_str, "EndSequence") != NULL) {
            break;
        } else {
            count++;
        }
        if (*next_str == (char)EOF)
            break;
        if(!strncasecmp(current_str, "EndSection", 10))
            break;
    }
    free(str_addr);
    return count;
}

/* Parse a section of config files
 * uc_mgr - use case manager structure
 * Returns 0 on sucess, negative error code otherwise
 */
static int snd_ucm_parse_section(snd_use_case_mgr_t **uc_mgr, char **cur_str,
char **nxt_str, int verb_index, int ctrl_list_type)
{
    use_case_verb_t *verb_list;
    card_mctrl_t *list;
    int enable_seq = 0, disable_seq = 0, controls_count = 0, ret = 0;
    char *p, *current_str, *next_str, *name;

    verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
    if (ctrl_list_type == CTRL_LIST_VERB) {
        list = (verb_list[verb_index].verb_ctrls +
            verb_list[verb_index].verb_count);
    } else if (ctrl_list_type == CTRL_LIST_DEVICE) {
        list = (verb_list[verb_index].device_ctrls +
            verb_list[verb_index].device_count);
    } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
        list = (verb_list[verb_index].mod_ctrls +
            verb_list[verb_index].mod_count);
    } else {
        ALOGE("Invalid list type: %d\n", ctrl_list_type);
        return -EINVAL;
    }
    list->case_name = NULL;
    list->ena_mixer_list = NULL;
    list->dis_mixer_list = NULL;
    list->ena_mixer_count = 0;
    list->dis_mixer_count = 0;
    list->playback_dev_name = NULL;
    list->capture_dev_name = NULL;
    list->acdb_id = 0;
    list->capability = 0;
    list->effects_mixer_ctl = NULL;
    current_str = *cur_str; next_str = *nxt_str;
    while(strncasecmp(current_str, "EndSection", 10)) {
        current_str = next_str;
        next_str = strchr(current_str, '\n');
        if ((!next_str) || (!strncasecmp(current_str, "EndSection", 10)))
            break;
        *next_str++ = '\0';
        if (strcasestr(current_str, "EndSequence") != NULL) {
            if (enable_seq == 1)
                enable_seq = 0;
            else if (disable_seq == 1)
                disable_seq = 0;
            else
                ALOGE("Error: improper config file\n");
        }
        if (enable_seq == 1) {
            ret = snd_ucm_extract_controls(current_str, &list->ena_mixer_list,
                  list->ena_mixer_count);
            if (ret < 0)
                break;
            list->ena_mixer_count++;
        } else if (disable_seq == 1) {
            ret = snd_ucm_extract_controls(current_str, &list->dis_mixer_list,
                  list->dis_mixer_count);
            if (ret < 0)
                break;
            list->dis_mixer_count++;
        } else if (strcasestr(current_str, "Name") != NULL) {
            ret = snd_ucm_extract_name(current_str, &list->case_name);
            if (ret < 0)
                break;
            ALOGV("Name of section is %s\n", list->case_name);
        } else if (strcasestr(current_str, "PlaybackPCM") != NULL) {
            ret = snd_ucm_extract_dev_name(current_str,
                      &list->playback_dev_name);
            if (ret < 0)
                break;
            ALOGV("Device name of playback is %s\n",
                list->playback_dev_name);
        } else if (strcasestr(current_str, "CapturePCM") != NULL) {
            ret = snd_ucm_extract_dev_name(current_str,
                      &list->capture_dev_name);
            if (ret < 0)
                break;
            ALOGV("Device name of capture is %s\n", list->capture_dev_name);
        } else if (strcasestr(current_str, "ACDBID") != NULL) {
            ret = snd_ucm_extract_acdb(current_str, &list->acdb_id,
                      &list->capability);
            if (ret < 0)
                break;
            ALOGV("ACDB ID: %d CAPABILITY: %d\n", list->acdb_id,
                list->capability);
        } else if (strcasestr(current_str, "EffectsMixerCTL") != NULL) {
            ret = snd_ucm_extract_effects_mixer_ctl(current_str,
                      &list->effects_mixer_ctl);
            if (ret < 0)
                break;
            ALOGV("Effects mixer ctl: %s: %d\n", list->effects_mixer_ctl);
        }
        if (strcasestr(current_str, "EnableSequence") != NULL) {
            controls_count = get_controls_count(next_str);
            if (controls_count < 0) {
                ret = -ENOMEM;
                break;
            }
            list->ena_mixer_list =
            (mixer_control_t *)malloc((controls_count*sizeof(mixer_control_t)));
            if (list->ena_mixer_list == NULL) {
                ret = -ENOMEM;
                break;
            }
            enable_seq = 1;
        } else if (strcasestr(current_str, "DisableSequence") != NULL) {
            controls_count = get_controls_count(next_str);
            if (controls_count < 0) {
                ret = -ENOMEM;
                break;
            }
            list->dis_mixer_list =
            (mixer_control_t *)malloc((controls_count*sizeof(mixer_control_t)));
            if (list->dis_mixer_list == NULL) {
                ret = -ENOMEM;
                break;
            }
            disable_seq = 1;
        }
        if (*next_str == (char)EOF)
             break;
    }
    if(ret == 0) {
        *cur_str = current_str; *nxt_str = next_str;
        if (ctrl_list_type == CTRL_LIST_VERB) {
            verb_list[verb_index].verb_count++;
        } else if (ctrl_list_type == CTRL_LIST_DEVICE) {
            verb_list[verb_index].device_count++;
        } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
            verb_list[verb_index].mod_count++;
        }
    }
    return ret;
}

/* Extract a mixer control name from config file
 * Returns 0 on sucess, negative error code otherwise
 */
static int snd_ucm_extract_name(char *buf, char **case_name)
{
    int ret = 0;
    char *p, *name = *case_name, *temp_ptr;

    p = strtok_r(buf, "\"", &temp_ptr);
    while (p != NULL) {
        p = strtok_r(NULL, "\"", &temp_ptr);
        if (p == NULL)
            break;
        name = (char *)malloc((strlen(p)+1)*sizeof(char));
        if(name == NULL) {
            ret = -ENOMEM;
            break;
        }
        strlcpy(name, p, (strlen(p)+1)*sizeof(char));
        *case_name = name;
        break;
    }
    return ret;
}

/* Extract a ACDB ID and capability of use case from config file
 * Returns 0 on sucess, negative error code otherwise
 */
static int snd_ucm_extract_acdb(char *buf, int *id, int *cap)
{
    char *p, key[] = "0123456789", *temp_ptr;

    p = strpbrk(buf, key);
    if (p == NULL) {
        *id = 0;
        *cap = 0;
    } else {
        p = strtok_r(p, ":", &temp_ptr);
        while (p != NULL) {
            *id = atoi(p);
            p = strtok_r(NULL, "\0", &temp_ptr);
            if (p == NULL)
                break;
            *cap = atoi(p);
            break;
        }
    }
    return 0;
}

/* Extract Effects Mixer ID of device from config file
 * Returns 0 on sucess, negative error code otherwise
 */
static int snd_ucm_extract_effects_mixer_ctl(char *buf, char **mixer_name)
{
    int ret = 0;
    char *p, *name = *mixer_name, *temp_ptr;

    p = strtok_r(buf, "\"", &temp_ptr);
    while (p != NULL) {
        p = strtok_r(NULL, "\"", &temp_ptr);
        if (p == NULL)
            break;
        name = (char *)malloc((strlen(p)+1)*sizeof(char));
        if(name == NULL) {
            ret = -ENOMEM;
            break;
        }
        strlcpy(name, p, (strlen(p)+1)*sizeof(char));
        *mixer_name = name;
        break;
    }
    return ret;
}

/* Extract a playback and capture device name of use case from config file
 * Returns 0 on sucess, negative error code otherwise
 */
static int snd_ucm_extract_dev_name(char *buf, char **dev_name)
{
    char key[] = "0123456789";
    char *p, *name = *dev_name;
    char dev_pre[] = "hw:0,";
    char *temp_ptr;

    p = strpbrk(buf, key);
    if (p == NULL) {
        *dev_name = NULL;
    } else {
        p = strtok_r(p, "\r\n", &temp_ptr);
        if (p == NULL) {
            *dev_name = NULL;
        } else {
            name = (char *)malloc((strlen(p)+strlen(dev_pre)+1)*sizeof(char));
            if(name == NULL)
                 return -ENOMEM;
            strlcpy(name, dev_pre, (strlen(p)+strlen(dev_pre)+1)*sizeof(char));
            strlcat(name, p, (strlen(p)+strlen(dev_pre)+1)*sizeof(char));
            *dev_name = name;
        }
    }
    return 0;
}

static int get_num_values(const char *buf)
{
    char *buf_addr, *p;
    int count = 0;
    char *temp_ptr;

    buf_addr = (char *)malloc((strlen(buf)+1)*sizeof(char));
    if (buf_addr == NULL) {
        ALOGE("Failed to allocate memory");
        return -ENOMEM;
    }
    strlcpy(buf_addr, buf, ((strlen(buf)+1)*sizeof(char)));
    p = strtok_r(buf_addr, " ", &temp_ptr);
    while (p != NULL) {
        count++;
        p = strtok_r(NULL, " ", &temp_ptr);
        if (p == NULL)
            break;
    }
    free(buf_addr);
    return count;
}

/* Extract a mixer control from config file
 * Returns 0 on sucess, negative error code otherwise
 */
static int snd_ucm_extract_controls(char *buf, mixer_control_t **mixer_list,
int size)
{
    unsigned long temp;
    int ret = -EINVAL, i, index = 0, count = 0;
    char *p, *ps, *pmv, temp_coeff[20];
    mixer_control_t *list;
    static const char *const seps = "\r\n";
    char *temp_ptr, *temp_vol_ptr;

    p = strtok_r(buf, "'", &temp_ptr);
    while (p != NULL) {
        p = strtok_r(NULL, "'", &temp_ptr);
        if (p == NULL)
            break;
        list = ((*mixer_list)+size);
        list->control_name = (char *)malloc((strlen(p)+1)*sizeof(char));
        if(list->control_name == NULL) {
            ret = -ENOMEM;
            free((*mixer_list));
            break;
        }
        strlcpy(list->control_name, p, (strlen(p)+1)*sizeof(char));
        p = strtok_r(NULL, ":", &temp_ptr);
        if (p == NULL)
            break;
        if(!strncmp(p, "0", 1)) {
            list->type = TYPE_STR;
        } else if(!strncmp(p, "1", 1)) {
            list->type = TYPE_INT;
        } else if(!strncmp(p, "2", 1)) {
            list->type = TYPE_MULTI_VAL;
        } else {
            ALOGE("Unknown type: p %s\n", p);
        }
        p = strtok_r(NULL, seps, &temp_ptr);
        if (p == NULL)
            break;
        if(list->type == TYPE_INT) {
            list->value = atoi(p);
            list->string = NULL;
            list->mulval = NULL;
        } else if(list->type == TYPE_STR) {
            list->value = -1;
            list->string = (char *)malloc((strlen(p)+1)*sizeof(char));
            list->mulval = NULL;
            if(list->string == NULL) {
                ret = -ENOMEM;
                free((*mixer_list));
                free(list->control_name);
                break;
            }
            strlcpy(list->string, p, (strlen(p)+1)*sizeof(char));
        } else if(list->type == TYPE_MULTI_VAL) {
            if (p != NULL) {
                count = get_num_values(p);
                list->mulval = (char **)malloc(count*sizeof(char *));
                if (list->mulval == NULL) {
                    ret = -ENOMEM;
                    free((*mixer_list));
                    free(list->control_name);
                    break;
                }
                index = 0;
                /* To support volume values in percentage */
                if ((count == 1) && (strstr(p, "%") != NULL)) {
                    pmv = strtok_r(p, " ", &temp_vol_ptr);
                    while (pmv != NULL) {
                        list->mulval[index] =
                            (char *)malloc((strlen(pmv)+1)*sizeof(char));
                        strlcpy(list->mulval[index], pmv, (strlen(pmv)+1));
                        index++;
                        pmv = strtok_r(NULL, " ", &temp_vol_ptr);
                        if (pmv == NULL)
                            break;
                    }
                } else {
                    pmv = strtok_r(p, " ", &temp_vol_ptr);
                    while (pmv != NULL) {
                        temp = strtoul(pmv, &ps, 16);
                        snprintf(temp_coeff, sizeof(temp_coeff),"%lu", temp);
                        list->mulval[index] =
                            (char *)malloc((strlen(temp_coeff)+1)*sizeof(char));
                        strlcpy(list->mulval[index], temp_coeff,
                            (strlen(temp_coeff)+1));
                        index++;
                        pmv = strtok_r(NULL, " ", &temp_vol_ptr);
                        if (pmv == NULL)
                            break;
                    }
                }
                list->value = count;
                list->string = NULL;
            }
        } else {
            ALOGE("Unknown type: p %s\n", p);
            list->value = -1;
            list->string = NULL;
        }
        ret = 0;
        break;
    }
    return ret;
}

void free_list(card_mctrl_t *list, int verb_index, int count)
{
    int case_index = 0, index = 0, mindex = 0;

    for(case_index = 0; case_index < count; case_index++) {
        for(index = 0; index < list[case_index].ena_mixer_count; index++) {
            if(list[case_index].ena_mixer_list[index].control_name) {
                free(list[case_index].ena_mixer_list[index].control_name);
            }
            if(list[case_index].ena_mixer_list[index].string) {
                free(list[case_index].ena_mixer_list[index].string);
            }
            if(list[case_index].ena_mixer_list[index].mulval) {
                for(mindex = 0;
                    mindex < list[case_index].ena_mixer_list[index].value;
                    mindex++) {
                    free(list[case_index].ena_mixer_list[index].mulval[mindex]);
                }
                if(list[case_index].ena_mixer_list[index].mulval) {
                    free(list[case_index].ena_mixer_list[index].mulval);
                }
            }
        }
        for(index = 0; index < list[case_index].dis_mixer_count; index++) {
            if(list[case_index].dis_mixer_list[index].control_name) {
                free(list[case_index].dis_mixer_list[index].control_name);
            }
            if(list[case_index].dis_mixer_list[index].string) {
                free(list[case_index].dis_mixer_list[index].string);
            }
            if(list[case_index].dis_mixer_list[index].mulval) {
                for(mindex = 0;
                    mindex < list[case_index].dis_mixer_list[index].value;
                    mindex++) {
                    free(list[case_index].dis_mixer_list[index].mulval[mindex]);
                }
                if(list[case_index].dis_mixer_list[index].mulval) {
                    free(list[case_index].dis_mixer_list[index].mulval);
                }
            }
        }
        if(list[case_index].case_name) {
            free(list[case_index].case_name);
        }
        if(list[case_index].ena_mixer_list) {
            free(list[case_index].ena_mixer_list);
        }
        if(list[case_index].dis_mixer_list) {
            free(list[case_index].dis_mixer_list);
        }
        if(list[case_index].playback_dev_name) {
            free(list[case_index].playback_dev_name);
        }
        if(list[case_index].capture_dev_name) {
            free(list[case_index].capture_dev_name);
        }
        if(list[case_index].effects_mixer_ctl) {
            list[case_index].effects_mixer_ctl = NULL;
        }
    }
}

void snd_ucm_free_mixer_list(snd_use_case_mgr_t **uc_mgr)
{
    card_mctrl_t *ctrl_list;
    use_case_verb_t *verb_list;
    int index = 0, verb_index = 0;

    pthread_mutex_lock(&(*uc_mgr)->card_ctxt_ptr->card_lock);
    verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
    while(strncmp((*uc_mgr)->card_ctxt_ptr->verb_list[verb_index],
          SND_UCM_END_OF_LIST, 3)) {
        ctrl_list = verb_list[verb_index].verb_ctrls;
        free_list(ctrl_list, verb_index, verb_list[verb_index].verb_count);
        if(verb_list[verb_index].use_case_name)
            free(verb_list[verb_index].use_case_name);
        if((*uc_mgr)->card_ctxt_ptr->verb_list[verb_index]) {
            free((*uc_mgr)->card_ctxt_ptr->verb_list[verb_index]);
        }
        verb_index++;
    }
    verb_index -= 1;
    ctrl_list = verb_list[verb_index].device_ctrls;
    free_list(ctrl_list, verb_index, verb_list[verb_index].device_count);
    ctrl_list = verb_list[verb_index].mod_ctrls;
    free_list(ctrl_list, verb_index, verb_list[verb_index].mod_count);
    index = 0;
    while(1) {
        if (verb_list[verb_index].device_list[index]) {
            if (!strncmp(verb_list[verb_index].device_list[index],
                SND_UCM_END_OF_LIST, 3)) {
                free(verb_list[verb_index].device_list[index]);
                break;
            } else {
                free(verb_list[verb_index].device_list[index]);
                index++;
            }
        }
    }
    if (verb_list[verb_index].device_list)
        free(verb_list[verb_index].device_list);
    index = 0;
    while(1) {
        if (verb_list[verb_index].modifier_list[index]) {
            if (!strncmp(verb_list[verb_index].modifier_list[index],
                SND_UCM_END_OF_LIST, 3)) {
                free(verb_list[verb_index].modifier_list[index]);
                break;
            } else {
                free(verb_list[verb_index].modifier_list[index]);
                index++;
            }
        }
    }
    if (verb_list[verb_index].modifier_list)
        free(verb_list[verb_index].modifier_list);
    if((*uc_mgr)->card_ctxt_ptr->use_case_verb_list)
        free((*uc_mgr)->card_ctxt_ptr->use_case_verb_list);
    if((*uc_mgr)->card_ctxt_ptr->verb_list)
        free((*uc_mgr)->card_ctxt_ptr->verb_list);
    pthread_mutex_unlock(&(*uc_mgr)->card_ctxt_ptr->card_lock);
}

/* Add an identifier to the respective list
 * head - list head
 * value - node value that needs to be added
 * Returns 0 on sucess, negative error code otherwise
 */
static int snd_ucm_add_ident_to_list(struct snd_ucm_ident_node **head,
const char *value)
{
    struct snd_ucm_ident_node *temp, *node;

    node =
        (struct snd_ucm_ident_node *)malloc(sizeof(struct snd_ucm_ident_node));
    if (node == NULL) {
        ALOGE("Failed to allocate memory for new node");
        return -ENOMEM;
    } else {
        node->next = NULL;
        strlcpy(node->ident, value, MAX_STR_LEN);
        node->active = 0;
        node->capability = 0;
    }
    if (*head == NULL) {
        *head = node;
    } else {
        temp = *head;
        while (temp->next != NULL) {
            temp = temp->next;
        }
        temp->next = node;
    }
    ALOGV("add_to_list: head %p, value %s", *head, node->ident);
    return 0;
}

/* Get the status of identifier at particulare index of the list
 * head - list head
 * ident - identifier value for which status needs to be get
 * status - status to be set (1 - active, 0 - inactive)
 */
static int snd_ucm_get_status_at_index(struct snd_ucm_ident_node *head,
const char *ident)
{
    while (head != NULL) {
        if(!strncmp(ident, head->ident, (strlen(head->ident)+1))) {
            break;
        }
        head = head->next;
    }
    if (head == NULL) {
        ALOGV("Element not found in the list");
    } else {
        return(head->active);
    }
    return -EINVAL;
}

/* Get the node at particular index
 * head - list head
 * index - index value
 */
struct snd_ucm_ident_node *snd_ucm_get_device_node(struct snd_ucm_ident_node *head,
int index)
{
    if (head == NULL) {
        ALOGV("Empty list");
        return NULL;
    }

    if ((index < 0) || (index >= (snd_ucm_get_size_of_list(head)))) {
        ALOGE("Element with given index %d doesn't exist in the list", index);
        return NULL;
    }

    while (index) {
        head = head->next;
        index--;
    }

    return head;
}

/* Set the status of identifier at particulare index of the list
 * head - list head
 * ident - identifier value for which status needs to be set
 * status - status to be set (1 - active, 0 - inactive)
 */
static void snd_ucm_set_status_at_index(struct snd_ucm_ident_node *head,
const char *ident, int status, int capability)
{
    while (head != NULL) {
        if(!strncmp(ident, head->ident, (strlen(head->ident)+1))) {
            break;
        }
        head = head->next;
    }
    if (head == NULL) {
        ALOGE("Element not found to set the status");
    } else {
        head->active = status;
        head->capability = capability;
    }
}

/* Get the identifier value at particulare index of the list
 * head - list head
 * index - node index value
 * Returns node idetifier value at index on sucess, NULL otherwise
 */
static char *snd_ucm_get_value_at_index(struct snd_ucm_ident_node *head,
int index)
{
    if (head == NULL) {
        ALOGV("Empty list");
        return NULL;
    }

    if ((index < 0) || (index >= (snd_ucm_get_size_of_list(head)))) {
        ALOGE("Element with given index %d doesn't exist in the list", index);
        return NULL;
    }

    while (index) {
        head = head->next;
        index--;
    }

    return (strdup(head->ident));
}

/* Get the size of the list
 * head - list head
 * Returns size of list on sucess, negative error code otherwise
 */
static int snd_ucm_get_size_of_list(struct snd_ucm_ident_node *head)
{
    int index = 0;

    if (head == NULL) {
        ALOGV("Empty list");
        return 0;
    }

    while (head->next != NULL) {
        index++;
        head = head->next;
    }

    return (index+1);
}

static void snd_ucm_print_list(struct snd_ucm_ident_node *head)
{
    int index = 0;

    ALOGV("print_list: head %p", head);
    if (head == NULL) {
        ALOGV("Empty list");
        return;
    }

    while (head->next != NULL) {
        ALOGV("index: %d, value: %s", index, head->ident);
        index++;
        head = head->next;
    }
    ALOGV("index: %d, value: %s", index, head->ident);
}

/* Delete an identifier from respective list
 * head - list head
 * value - node value that needs to be deleted
 * Returns 0 on sucess, negative error code otherwise
 *
 */
static int snd_ucm_del_ident_from_list(struct snd_ucm_ident_node **head,
const char *value)
{
    struct snd_ucm_ident_node *temp1, *temp2;
    int ret = -EINVAL;

    if (*head == NULL) {
        ALOGE("del_from_list: Empty list");
        return -EINVAL;
    } else if (!strncmp((*head)->ident, value, (strlen(value)+1))) {
            temp2 = *head;
            *head = temp2->next;
            ret = 0;
    } else {
        temp1 = *head;
        temp2 = temp1->next;
        while (temp2 != NULL) {
            if (!strncmp(temp2->ident, value, (strlen(value)+1))) {
                temp1->next = temp2->next;
                ret = 0;
                break;
            }
            temp1 = temp1->next;
            temp2 = temp1->next;
        }
    }
    if (ret < 0) {
        ALOGE("Element not found in enabled list");
    } else {
        temp2->next = NULL;
        temp2->ident[0] = 0;
        temp2->active = 0;
        temp2->capability = 0;
        free(temp2);
        temp2 = NULL;
    }
    return ret;
}