1/*
2 * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *   * Redistributions of source code must retain the above copyright
8 *     notice, this list of conditions and the following disclaimer.
9 *   * Redistributions in binary form must reproduce the above
10 *     copyright notice, this list of conditions and the following
11 *     disclaimer in the documentation and/or other materials provided
12 *     with the distribution.
13 *   * Neither the name of Code Aurora Forum, Inc. nor the names of its
14 *     contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29#define LOG_TAG "alsa_ucm"
30//#define LOG_NDDEBUG 0
31
32#ifdef ANDROID
33/* definitions for Android logging */
34#include <utils/Log.h>
35#include <cutils/properties.h>
36#else /* ANDROID */
37#include <math.h>
38#define strlcat g_strlcat
39#define strlcpy g_strlcpy
40#define ALOGI(...)      fprintf(stdout, __VA_ARGS__)
41#define ALOGE(...)      fprintf(stderr, __VA_ARGS__)
42#define ALOGV(...)      fprintf(stderr, __VA_ARGS__)
43#define ALOGD(...)      fprintf(stderr, __VA_ARGS__)
44#endif /* ANDROID */
45
46#include <stdio.h>
47#include <stdlib.h>
48#include <fcntl.h>
49#include <stdarg.h>
50#include <string.h>
51#include <errno.h>
52#include <unistd.h>
53#include <pthread.h>
54#include <ctype.h>
55#include <sys/stat.h>
56#include <sys/ioctl.h>
57#include <sys/mman.h>
58#include <sys/time.h>
59#include <sys/poll.h>
60#include <stdint.h>
61#include <dlfcn.h>
62
63#include <linux/ioctl.h>
64#include "msm8960_use_cases.h"
65#if defined(QC_PROP)
66    static void (*acdb_send_audio_cal)(int,int);
67    static void (*acdb_send_voice_cal)(int,int);
68#endif
69#define PARSE_DEBUG 0
70
71/**
72 * Create an identifier
73 * fmt - sprintf like format,
74 * ... - Optional arguments
75 * returns - string allocated or NULL on error
76 */
77char *snd_use_case_identifier(const char *fmt, ...)
78{
79    ALOGE("API not implemented for now, to be updated if required");
80    return NULL;
81}
82
83/**
84 * Free a list
85 * list - list to free
86 * items -  Count of strings
87 * Return Zero on success, otherwise a negative error code
88 */
89int snd_use_case_free_list(const char *list[], int items)
90{
91    /* list points to UCM internal static tables,
92     * hence there is no need to do a free call
93     * just set the list to NULL and return */
94    list = NULL;
95    return 0;
96}
97
98/**
99 * Obtain a list of entries
100 * uc_mgr - UCM structure pointer or  NULL for card list
101 * identifier - NULL for card list
102 * list - Returns allocated list
103 * returns Number of list entries on success, otherwise a negative error code
104 */
105int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
106                          const char *identifier,
107                          const char **list[])
108{
109    use_case_verb_t *verb_list;
110    int verb_index, list_size, index = 0;
111
112    if (identifier == NULL) {
113        *list = card_list;
114        return ((int)MAX_NUM_CARDS);
115    }
116
117    pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
118    if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) ||
119        (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) {
120        ALOGE("snd_use_case_get_list(): failed, invalid arguments");
121        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
122        return -EINVAL;
123    }
124
125    if (!strncmp(identifier, "_verbs", 6)) {
126        while(strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
127            SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
128            ALOGV("Index:%d Verb:%s", index,
129                 uc_mgr->card_ctxt_ptr->verb_list[index]);
130            index++;
131        }
132        *list = (char ***)uc_mgr->card_ctxt_ptr->verb_list;
133        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
134        return index;
135    } else  if (!strncmp(identifier, "_devices", 8)) {
136        if (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
137            SND_USE_CASE_VERB_INACTIVE, strlen(SND_USE_CASE_VERB_INACTIVE))) {
138            ALOGE("Use case verb name not set, invalid current verb");
139            pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
140            return -EINVAL;
141        }
142        verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
143        while(strncmp(uc_mgr->card_ctxt_ptr->current_verb,
144            verb_list[index].use_case_name,
145            (strlen(verb_list[index].use_case_name)+1))) {
146            index++;
147        }
148        verb_index = index;
149        index = 0;
150        while(strncmp(verb_list[verb_index].device_list[index],
151            SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
152            ALOGV("Index:%d Device:%s", index,
153                 verb_list[verb_index].device_list[index]);
154            index++;
155        }
156        *list = verb_list[verb_index].device_list;
157        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
158        return index;
159    } else  if (!strncmp(identifier, "_modifiers", 10)) {
160        if (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
161                    SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN)) {
162            ALOGE("Use case verb name not set, invalid current verb");
163            pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
164            return -EINVAL;
165        }
166        verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
167        while(strncmp(uc_mgr->card_ctxt_ptr->current_verb,
168            verb_list[index].use_case_name,
169            (strlen(verb_list[index].use_case_name)+1))) {
170            index++;
171        }
172        verb_index = index;
173        index = 0;
174        while(strncmp(verb_list[verb_index].modifier_list[index],
175                    SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
176            ALOGV("Index:%d Modifier:%s", index,
177                 verb_list[verb_index].modifier_list[index]);
178            index++;
179        }
180        *list = verb_list[verb_index].modifier_list;
181        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
182        return index;
183    } else  if (!strncmp(identifier, "_enadevs", 8)) {
184        if (uc_mgr->device_list_count) {
185            for (index = 0; index < uc_mgr->device_list_count; index++) {
186                free(uc_mgr->current_device_list[index]);
187                uc_mgr->current_device_list[index] = NULL;
188            }
189            free(uc_mgr->current_device_list);
190            uc_mgr->current_device_list = NULL;
191            uc_mgr->device_list_count = 0;
192        }
193        list_size =
194            snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
195        uc_mgr->device_list_count = list_size;
196    if (list_size > 0) {
197            uc_mgr->current_device_list =
198                (char **)malloc(sizeof(char *)*list_size);
199            if (uc_mgr->current_device_list == NULL) {
200                *list = NULL;
201                pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
202                return -ENOMEM;
203            }
204            for (index = 0; index < list_size; index++) {
205                uc_mgr->current_device_list[index] =
206                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
207                index);
208            }
209        }
210        *list = (const char **)uc_mgr->current_device_list;
211        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
212        return (list_size);
213    } else  if (!strncmp(identifier, "_enamods", 8)) {
214        if (uc_mgr->modifier_list_count) {
215            for (index = 0; index < uc_mgr->modifier_list_count; index++) {
216                free(uc_mgr->current_modifier_list[index]);
217                uc_mgr->current_modifier_list[index] = NULL;
218            }
219            free(uc_mgr->current_modifier_list);
220            uc_mgr->current_modifier_list = NULL;
221            uc_mgr->modifier_list_count = 0;
222        }
223        list_size =
224            snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
225        uc_mgr->modifier_list_count = list_size;
226    if (list_size > 0) {
227            uc_mgr->current_modifier_list =
228                (char **)malloc(sizeof(char *) * list_size);
229            if (uc_mgr->current_modifier_list == NULL) {
230                *list = NULL;
231                pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
232                return -ENOMEM;
233            }
234            for (index = 0; index < list_size; index++) {
235                uc_mgr->current_modifier_list[index] =
236                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
237                index);
238            }
239        }
240        *list = (const char **)uc_mgr->current_modifier_list;
241        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
242        return (list_size);
243    } else {
244        ALOGE("Invalid identifier: %s", identifier);
245        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
246        return -EINVAL;
247    }
248}
249
250
251/**
252 * Get current value of the identifier
253 * identifier - NULL for current card
254 *        _verb
255 *        <Name>/<_device/_modifier>
256 *    Name -    PlaybackPCM
257 *        CapturePCM
258 *        PlaybackCTL
259 *        CaptureCTL
260 * value - Value pointer
261 * returns Zero if success, otherwise a negative error code
262 */
263int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
264                     const char *identifier,
265                     const char **value)
266{
267    card_mctrl_t *ctrl_list;
268    use_case_verb_t *verb_list;
269    char ident[MAX_STR_LEN], *ident1, *ident2, *temp_ptr;
270    int index, verb_index = 0, ret = 0;
271
272    pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
273    if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) ||
274        (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) {
275        ALOGE("snd_use_case_get(): failed, invalid arguments");
276        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
277        return -EINVAL;
278    }
279
280    if (identifier == NULL) {
281        if (uc_mgr->card_ctxt_ptr->card_name != NULL) {
282            *value = strdup(uc_mgr->card_ctxt_ptr->card_name);
283        } else {
284            *value = NULL;
285        }
286        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
287        return 0;
288    }
289
290    if (!strncmp(identifier, "_verb", 5)) {
291        if (uc_mgr->card_ctxt_ptr->current_verb != NULL) {
292            *value = strdup(uc_mgr->card_ctxt_ptr->current_verb);
293        } else {
294            *value = NULL;
295        }
296        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
297        return 0;
298    }
299
300    strlcpy(ident, identifier, sizeof(ident));
301    if(!(ident1 = strtok_r(ident, "/", &temp_ptr))) {
302        ALOGE("No valid identifier found: %s", ident);
303        ret = -EINVAL;
304    } else {
305        if ((!strncmp(ident1, "PlaybackPCM", 11)) ||
306            (!strncmp(ident1, "CapturePCM", 10))) {
307            ident2 = strtok_r(NULL, "/", &temp_ptr);
308            index = 0;
309            if (ident2 != NULL) {
310                verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
311                verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
312                if((get_usecase_type(uc_mgr, ident2)) == CTRL_LIST_VERB) {
313                    ctrl_list = verb_list[verb_index].verb_ctrls;
314                } else {
315                    ctrl_list = verb_list[verb_index].mod_ctrls;
316                }
317                if((verb_index < 0) ||
318                    (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
319                    SND_UCM_END_OF_LIST, 3)) || (ctrl_list == NULL)) {
320                    ALOGE("Invalid current verb value: %s - %d",
321                         uc_mgr->card_ctxt_ptr->current_verb, verb_index);
322                    pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
323                    return -EINVAL;
324                }
325                while(strncmp(ctrl_list[index].case_name, ident2,
326                    (strlen(ident2)+1))) {
327                    if (!strncmp(ctrl_list[index].case_name,
328                        SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))){
329                        *value = NULL;
330                        ret = -EINVAL;
331                        break;
332                    } else {
333                        index++;
334                    }
335                }
336            } else {
337                ret = -EINVAL;
338            }
339            if (ret < 0) {
340                ALOGE("No valid device/modifier found with given identifier: %s",
341                     ident2);
342            } else {
343                if(!strncmp(ident1, "PlaybackPCM", 11)) {
344                    if (ctrl_list[index].playback_dev_name) {
345                        *value = strdup(ctrl_list[index].playback_dev_name);
346                    } else {
347                        *value = NULL;
348                        ret = -ENODEV;
349                    }
350                } else if(!strncmp(ident1, "CapturePCM", 10)) {
351                    if (ctrl_list[index].capture_dev_name) {
352                        *value = strdup(ctrl_list[index].capture_dev_name);
353                    } else {
354                        *value = NULL;
355                        ret = -ENODEV;
356                    }
357                } else {
358                    ALOGE("No valid device name exists for given identifier: %s",
359                         ident2);
360                    *value = NULL;
361                    ret = -ENODEV;
362                }
363            }
364        } else if ((!strncmp(ident1, "PlaybackCTL", 11)) ||
365                   (!strncmp(ident1, "CaptureCTL", 10))) {
366            if(uc_mgr->card_ctxt_ptr->control_device != NULL) {
367                *value = strdup(uc_mgr->card_ctxt_ptr->control_device);
368            } else {
369                ALOGE("No valid control device found");
370                *value = NULL;
371                ret = -ENODEV;
372            }
373        } else if (!strncmp(ident1, "ACDBID", 11)) {
374            ident2 = strtok_r(NULL, "/", &temp_ptr);
375            index = 0; verb_index = 0;
376            verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
377            if((verb_index < 0) ||
378               (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
379                SND_UCM_END_OF_LIST, 3)) ||
380                (verb_list[verb_index].verb_ctrls == NULL)) {
381                ALOGE("Invalid current verb value: %s - %d",
382                     uc_mgr->card_ctxt_ptr->current_verb, verb_index);
383                pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
384                return -EINVAL;
385            }
386            ctrl_list = verb_list[verb_index].device_ctrls;
387            if (ident2 != NULL) {
388                while(strncmp(ctrl_list[index].case_name, ident2,
389                    MAX_LEN(ctrl_list[index].case_name,ident2))) {
390                    if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
391                        strlen(SND_UCM_END_OF_LIST))){
392                        ret = -EINVAL;
393                        break;
394                    } else {
395                        index++;
396                    }
397                }
398            }
399            if (ret < 0) {
400                ALOGE("No valid device/modifier found with given identifier: %s",
401                      ident2);
402            } else {
403                if (verb_list[verb_index].device_ctrls[index].acdb_id) {
404                    ret = verb_list[verb_index].device_ctrls[index].acdb_id;
405                } else {
406                    ret = -ENODEV;
407                }
408            }
409        } else if (!strncmp(ident1, "EffectsMixerCTL", 11)) {
410            ident2 = strtok_r(NULL, "/", &temp_ptr);
411            index = 0; verb_index = 0;
412            verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
413            if((verb_index < 0) ||
414               (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
415                SND_UCM_END_OF_LIST, 3)) ||
416                (verb_list[verb_index].verb_ctrls == NULL)) {
417                ALOGE("Invalid current verb value: %s - %d",
418                     uc_mgr->card_ctxt_ptr->current_verb, verb_index);
419                pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
420                return -EINVAL;
421            }
422            ctrl_list = verb_list[verb_index].device_ctrls;
423            if (ident2 != NULL) {
424                while(strncmp(ctrl_list[index].case_name, ident2, strlen(ident2)+1)) {
425                    if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
426                        strlen(SND_UCM_END_OF_LIST))){
427                        ret = -EINVAL;
428                        break;
429                    } else {
430                        index++;
431                    }
432                }
433            }
434            if (ret < 0) {
435                ALOGE("No valid device/modifier found with given identifier: %s",
436                      ident2);
437            } else {
438                if (verb_list[verb_index].device_ctrls[index].effects_mixer_ctl) {
439                    *value = strdup(verb_list[verb_index].device_ctrls[index].effects_mixer_ctl);
440                } else {
441                    *value = NULL;
442                    ret = -ENODEV;
443                }
444            }
445        } else {
446            ALOGE("Unsupported identifier value: %s", ident1);
447            *value = NULL;
448            ret = -EINVAL;
449        }
450    }
451    pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
452    return ret;
453}
454
455/**
456 * Get current status
457 * uc_mgr - UCM structure
458 * identifier - _devstatus/<device>,
459        _modstatus/<modifier>
460 * value - result
461 * returns 0 on success, otherwise a negative error code
462 */
463int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
464              const char *identifier,
465              long *value)
466{
467    char ident[MAX_STR_LEN], *ident1, *ident2, *ident_value, *temp_ptr;
468    int index, list_size, ret = -EINVAL;
469
470    pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
471    if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) ||
472        (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) {
473        ALOGE("snd_use_case_geti(): failed, invalid arguments");
474        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
475        return -EINVAL;
476    }
477
478    *value = 0;
479    strlcpy(ident, identifier, sizeof(ident));
480    if(!(ident1 = strtok_r(ident, "/", &temp_ptr))) {
481        ALOGE("No valid identifier found: %s", ident);
482        ret = -EINVAL;
483    } else {
484        if (!strncmp(ident1, "_devstatus", 10)) {
485            ident2 = strtok_r(NULL, "/", &temp_ptr);
486            if (ident2 != NULL) {
487                list_size =
488                snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
489                for (index = 0; index < list_size; index++) {
490                if ((ident_value =
491                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
492                index))) {
493                        if (!strncmp(ident2, ident_value,
494                            (strlen(ident_value)+1))) {
495                            *value = 1;
496                            free(ident_value);
497                            ident_value = NULL;
498                            break;
499                        } else {
500                            free(ident_value);
501                            ident_value = NULL;
502                        }
503                    }
504                }
505                ret = 0;
506            }
507        } else if (!strncmp(ident1, "_modstatus", 10)) {
508            ident2 = strtok_r(NULL, "/", &temp_ptr);
509            if (ident2 != NULL) {
510                list_size =
511                snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
512                for (index = 0; index < list_size; index++) {
513                if((ident_value =
514                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
515                index))) {
516                        if (!strncmp(ident2, ident_value,
517                            (strlen(ident_value)+1))) {
518                            *value = 1;
519                            free(ident_value);
520                            ident_value = NULL;
521                            break;
522                        } else {
523                            free(ident_value);
524                            ident_value = NULL;
525                        }
526                    }
527                }
528                ret = 0;
529            }
530        } else {
531            ALOGE("Unknown identifier: %s", ident1);
532        }
533    }
534    pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
535    return ret;
536}
537
538static int check_devices_for_voice_call(snd_use_case_mgr_t *uc_mgr,
539const char *use_case)
540{
541    struct snd_ucm_ident_node *dev_node = NULL;
542    int index = 0, list_size = 0, rx_dev_status = 0, tx_dev_status = 0;
543
544    if ((!strncmp(use_case, SND_USE_CASE_VERB_VOICECALL,
545        strlen(SND_USE_CASE_VERB_VOICECALL))) ||
546        (!strncmp(use_case, SND_USE_CASE_VERB_IP_VOICECALL,
547        strlen(SND_USE_CASE_VERB_IP_VOICECALL))) ||
548        (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOICE,
549        strlen(SND_USE_CASE_MOD_PLAY_VOICE))) ||
550        (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOIP,
551        strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
552        ALOGV("check_devices_for_voice_call(): voice cap detected\n");
553        list_size =
554        snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
555        for (index = 0; index < list_size; index++) {
556            if ((dev_node =
557                snd_ucm_get_device_node(uc_mgr->card_ctxt_ptr->dev_list_head,
558                index))) {
559                if (dev_node->capability == CAP_RX && dev_node->active == 1) {
560                    rx_dev_status = 1;
561                } else if (dev_node->capability == CAP_TX && dev_node->active == 1) {
562                    tx_dev_status = 1;
563                }
564            }
565        }
566        if (rx_dev_status == 1 && tx_dev_status == 1) {
567            ALOGV("check_devices_for_voice_call(): Rx and Tx devices enabled\n");
568            return 0;
569        } else {
570            ALOGV("check_devices_for_voice_call(): Rx/Tx dev not enabled: \
571                  %d,%d\n", rx_dev_status, tx_dev_status);
572            return 1;
573        }
574    }
575    return 0;
576}
577
578static int snd_use_case_apply_voice_acdb(snd_use_case_mgr_t *uc_mgr,
579int use_case_index)
580{
581    card_mctrl_t *ctrl_list;
582    int list_size, index, verb_index, ret = 0, voice_acdb = 0, rx_id, tx_id;
583    char *ident_value = NULL;
584
585    /* Check if voice call use case/modifier exists */
586    if ((!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
587        SND_USE_CASE_VERB_VOICECALL, strlen(SND_USE_CASE_VERB_VOICECALL))) ||
588        (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
589        SND_USE_CASE_VERB_IP_VOICECALL,
590        strlen(SND_USE_CASE_VERB_IP_VOICECALL)))) {
591        voice_acdb = 1;
592    }
593    if (voice_acdb != 1) {
594        list_size =
595        snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
596        for (index = 0; index < list_size; index++) {
597            if ((ident_value =
598                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
599                index))) {
600                if ((!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOICE,
601                    strlen(SND_USE_CASE_MOD_PLAY_VOICE))) ||
602                    (!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOIP,
603                    strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
604                    voice_acdb = 1;
605                    free(ident_value);
606                    ident_value = NULL;
607                    break;
608                }
609                free(ident_value);
610                ident_value = NULL;
611            }
612        }
613    }
614
615    verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
616    if((verb_index < 0) ||
617        (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
618        SND_UCM_END_OF_LIST, 3))) {
619        ALOGE("Invalid current verb value: %s - %d",
620            uc_mgr->card_ctxt_ptr->current_verb, verb_index);
621        return -EINVAL;
622    }
623    if (voice_acdb == 1) {
624        ctrl_list =
625        uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
626        list_size =
627        snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
628        for (index = 0; index < list_size; index++) {
629            if ((ident_value =
630                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
631                index))) {
632                if (strncmp(ident_value, ctrl_list[use_case_index].case_name,
633                    (strlen(ctrl_list[use_case_index].case_name)+1))) {
634                    break;
635                }
636                free(ident_value);
637                ident_value = NULL;
638            }
639        }
640        index = 0;
641        if (ident_value != NULL) {
642            while(strncmp(ctrl_list[index].case_name, ident_value,
643                  (strlen(ident_value)+1))) {
644                if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
645                    strlen(SND_UCM_END_OF_LIST))) {
646                    ret = -EINVAL;
647                    break;
648                }
649                index++;
650            }
651            if (ret < 0) {
652                ALOGE("No valid device found: %s",ident_value);
653            } else {
654                if (ctrl_list[use_case_index].capability == CAP_RX) {
655                    rx_id = ctrl_list[use_case_index].acdb_id;
656                    tx_id = ctrl_list[index].acdb_id;
657                } else {
658                    rx_id = ctrl_list[index].acdb_id;
659                    tx_id = ctrl_list[use_case_index].acdb_id;
660                }
661                if(((rx_id == DEVICE_SPEAKER_MONO_RX_ACDB_ID)||(rx_id == DEVICE_SPEAKER_STEREO_RX_ACDB_ID))
662                    && tx_id == DEVICE_HANDSET_TX_ACDB_ID) {
663                    tx_id = DEVICE_SPEAKER_TX_ACDB_ID;
664                } else if (((rx_id == DEVICE_SPEAKER_MONO_RX_ACDB_ID )||(rx_id == DEVICE_SPEAKER_STEREO_RX_ACDB_ID))
665                    && tx_id == DEVICE_HANDSET_TX_FV5_ACDB_ID) {
666                    tx_id = DEVICE_SPEAKER_TX_FV5_ACDB_ID;
667                }
668
669                if ((rx_id != uc_mgr->current_rx_device) ||
670                    (tx_id != uc_mgr->current_tx_device)) {
671                    uc_mgr->current_rx_device = rx_id;
672                    uc_mgr->current_tx_device = tx_id;
673                    ALOGD("Voice acdb: rx id %d tx id %d",
674                          uc_mgr->current_rx_device,
675                          uc_mgr->current_tx_device);
676                    if (uc_mgr->acdb_handle && !uc_mgr->isFusion3Platform) {
677                        acdb_send_voice_cal = dlsym(uc_mgr->acdb_handle,"acdb_loader_send_voice_cal");
678                        if (acdb_send_voice_cal == NULL) {
679                            ALOGE("ucm: dlsym: Error:%s Loading acdb_loader_send_voice_cal", dlerror());
680                        }else {
681                            acdb_send_voice_cal(uc_mgr->current_rx_device,
682                                       uc_mgr->current_tx_device);
683                        }
684                   }
685                } else {
686                    ALOGV("Voice acdb: Required acdb already pushed \
687                         rx id %d tx id %d", uc_mgr->current_rx_device,
688                         uc_mgr->current_tx_device);
689                }
690            }
691            free(ident_value);
692            ident_value = NULL;
693        }
694    } else {
695        ALOGV("No voice use case found");
696        uc_mgr->current_rx_device = -1; uc_mgr->current_tx_device = -1;
697        ret = -ENODEV;
698    }
699    return ret;
700}
701
702int get_use_case_index(snd_use_case_mgr_t *uc_mgr, const char *use_case,
703int ctrl_list_type)
704{
705    use_case_verb_t *verb_list;
706    card_mctrl_t *ctrl_list;
707    int ret = 0, index = 0, verb_index;
708
709    verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
710    verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
711    if (ctrl_list_type == CTRL_LIST_VERB) {
712        ctrl_list =
713            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls;
714    } else if (ctrl_list_type == CTRL_LIST_DEVICE) {
715        ctrl_list =
716            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
717    } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
718        ctrl_list =
719            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].mod_ctrls;
720    } else {
721        ctrl_list = NULL;
722    }
723    if((verb_index < 0) ||
724      (!strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_UCM_END_OF_LIST, 3)) ||
725      (ctrl_list == NULL) || (ctrl_list[index].case_name == NULL)) {
726        ALOGE("Invalid current verb value: %s - %d",
727                uc_mgr->card_ctxt_ptr->current_verb, verb_index);
728        return -EINVAL;
729    }
730    while(strncmp(ctrl_list[index].case_name, use_case, (strlen(use_case)+1))) {
731        if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
732            strlen(SND_UCM_END_OF_LIST))) {
733            ret = -EINVAL;
734            break;
735        }
736        index++;
737        if (ctrl_list[index].case_name == NULL) {
738            ALOGE("Invalid case_name at index %d", index);
739            ret = -EINVAL;
740            break;
741        }
742    }
743    if (ret < 0) {
744        return ret;
745    } else {
746        return index;
747    }
748}
749
750/* Apply the required mixer controls for specific use case
751 * uc_mgr - UCM structure pointer
752 * use_case - use case name
753 * return 0 on sucess, otherwise a negative error code
754 */
755int snd_use_case_apply_mixer_controls(snd_use_case_mgr_t *uc_mgr,
756const char *use_case, int enable, int ctrl_list_type, int uc_index)
757{
758    card_mctrl_t *ctrl_list;
759    mixer_control_t *mixer_list;
760    struct mixer_ctl *ctl;
761    int i, ret = 0, index = 0, verb_index, mixer_count;
762
763    verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
764    if (ctrl_list_type == CTRL_LIST_VERB) {
765        ctrl_list =
766            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls;
767    } else if (ctrl_list_type == CTRL_LIST_DEVICE) {
768        ctrl_list =
769            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
770    } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
771        ctrl_list =
772            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].mod_ctrls;
773    } else {
774        ctrl_list = NULL;
775    }
776    if((verb_index < 0) ||
777      (!strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_UCM_END_OF_LIST, 3)) ||
778      (ctrl_list == NULL)) {
779        ALOGE("Invalid current verb value: %s - %d",
780            uc_mgr->card_ctxt_ptr->current_verb, verb_index);
781        return -EINVAL;
782    }
783    if (uc_index < 0) {
784        ALOGE("No valid use case found with the use case: %s", use_case);
785        ret = -ENODEV;
786    } else {
787        if (!uc_mgr->card_ctxt_ptr->mixer_handle) {
788            ALOGE("Control device not initialized");
789            ret = -ENODEV;
790        } else {
791            if (enable &&
792                (check_devices_for_voice_call(uc_mgr, use_case) != NULL))
793                return ret;
794            ALOGD("Set mixer controls for %s enable %d", use_case, enable);
795            if (ctrl_list[uc_index].acdb_id && ctrl_list[uc_index].capability) {
796                if (enable) {
797                    if (snd_use_case_apply_voice_acdb(uc_mgr, uc_index)) {
798                        ALOGV("acdb_id %d cap %d enable %d",
799                            ctrl_list[uc_index].acdb_id,
800                            ctrl_list[uc_index].capability, enable);
801                        if (uc_mgr->acdb_handle) {
802                            acdb_send_audio_cal = dlsym(uc_mgr->acdb_handle,"acdb_loader_send_audio_cal");
803                            if (acdb_send_audio_cal == NULL) {
804                                ALOGE("ucm:dlsym:Error:%s Loading acdb_loader_send_audio_cal", dlerror());
805                            } else {
806                                acdb_send_audio_cal(ctrl_list[uc_index].acdb_id,
807                                                     ctrl_list[uc_index].capability);
808                            }
809                        }
810                    }
811                }
812            }
813            if (enable) {
814                mixer_list = ctrl_list[uc_index].ena_mixer_list;
815                mixer_count = ctrl_list[uc_index].ena_mixer_count;
816            } else {
817                mixer_list = ctrl_list[uc_index].dis_mixer_list;
818                mixer_count = ctrl_list[uc_index].dis_mixer_count;
819            }
820            for(index = 0; index < mixer_count; index++) {
821                if (mixer_list == NULL) {
822                    ALOGE("No valid controls exist for this case: %s", use_case);
823                    break;
824                }
825                ctl = mixer_get_control(uc_mgr->card_ctxt_ptr->mixer_handle,
826                          mixer_list[index].control_name, 0);
827                if (ctl) {
828                    if (mixer_list[index].type == TYPE_INT) {
829                        ALOGV("Setting mixer control: %s, value: %d",
830                             mixer_list[index].control_name,
831                             mixer_list[index].value);
832                        ret = mixer_ctl_set(ctl, mixer_list[index].value);
833                    } else if (mixer_list[index].type == TYPE_MULTI_VAL) {
834                        ALOGD("Setting multi value: %s",
835                            mixer_list[index].control_name);
836                        ret = mixer_ctl_set_value(ctl, mixer_list[index].value,
837                                mixer_list[index].mulval);
838                        if (ret < 0)
839                            ALOGE("Failed to set multi value control %s\n",
840                                mixer_list[index].control_name);
841                    } else {
842                        ALOGV("Setting mixer control: %s, value: %s",
843                            mixer_list[index].control_name,
844                            mixer_list[index].string);
845                        ret = mixer_ctl_select(ctl, mixer_list[index].string);
846                    }
847                    if ((ret != 0) && enable) {
848                       /* Disable all the mixer controls which are
849                        * already enabled before failure */
850                       mixer_list = ctrl_list[uc_index].dis_mixer_list;
851                       mixer_count = ctrl_list[uc_index].dis_mixer_count;
852                       for(i = 0; i < mixer_count; i++) {
853                           ctl = mixer_get_control(
854                                     uc_mgr->card_ctxt_ptr->mixer_handle,
855                                     mixer_list[i].control_name, 0);
856                           if (ctl) {
857                               if (mixer_list[i].type == TYPE_INT) {
858                                   ret = mixer_ctl_set(ctl,
859                                             mixer_list[i].value);
860                               } else {
861                                   ret = mixer_ctl_select(ctl,
862                                             mixer_list[i].string);
863                               }
864                           }
865                       }
866                       ALOGE("Failed to enable the mixer controls for %s",
867                            use_case);
868                       break;
869                    }
870                }
871            }
872        }
873    }
874    return ret;
875}
876
877int getUseCaseType(const char *useCase)
878{
879    ALOGV("getUseCaseType: use case is %s\n", useCase);
880    if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI,
881           MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI)) ||
882        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
883           MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
884        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
885           MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
886        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
887            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
888        !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
889            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI2)) ||
890        !strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO,
891            MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
892        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
893            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC)) ||
894        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
895            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
896        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
897            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
898        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA,
899            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LPA)) ||
900        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
901            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
902        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM,
903            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))) {
904        return CAP_RX;
905    } else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC,
906            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC)) ||
907        !strncmp(useCase, SND_USE_CASE_VERB_FM_REC,
908            MAX_LEN(useCase,SND_USE_CASE_VERB_FM_REC)) ||
909        !strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC,
910            MAX_LEN(useCase,SND_USE_CASE_VERB_FM_A2DP_REC)) ||
911        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC,
912            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC)) ||
913        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC,
914            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) ||
915        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC,
916            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) ||
917        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM,
918            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_FM)) ||
919        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM,
920            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_A2DP_FM))) {
921        return CAP_TX;
922    } else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL,
923            MAX_LEN(useCase,SND_USE_CASE_VERB_VOICECALL)) ||
924        !strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL,
925            MAX_LEN(useCase,SND_USE_CASE_VERB_IP_VOICECALL)) ||
926        !strncmp(useCase, SND_USE_CASE_VERB_DL_REC,
927            MAX_LEN(useCase,SND_USE_CASE_VERB_DL_REC)) ||
928        !strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC,
929            MAX_LEN(useCase,SND_USE_CASE_VERB_UL_DL_REC)) ||
930        !strncmp(useCase, SND_USE_CASE_VERB_INCALL_REC,
931            MAX_LEN(useCase,SND_USE_CASE_VERB_INCALL_REC)) ||
932        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE,
933            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE)) ||
934        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP,
935            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
936        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
937            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) ||
938        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
939            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) ||
940        !strncmp(useCase, SND_USE_CASE_VERB_VOLTE,
941            MAX_LEN(useCase,SND_USE_CASE_VERB_VOLTE)) ||
942        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
943            MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_VOLTE))) {
944        return CAP_VOICE;
945    } else {
946        ALOGE("unknown use case %s, returning voice capablity", useCase);
947        return CAP_VOICE;
948    }
949}
950
951/* Set/Reset mixer controls of specific use case for all current devices
952 * uc_mgr - UCM structure pointer
953 * ident  - use case name (verb or modifier)
954 * enable - 1 for enable and 0 for disable
955 * return 0 on sucess, otherwise a negative error code
956 */
957static int set_controls_of_usecase_for_all_devices(snd_use_case_mgr_t *uc_mgr,
958const char *ident, int enable, int ctrl_list_type)
959{
960    card_mctrl_t *dev_list, *uc_list;
961    char *current_device, use_case[MAX_UC_LEN];
962    int list_size, index, uc_index, ret = 0, intdev_flag = 0;
963    int verb_index, capability = 0, ident_cap = 0, dev_cap =0;
964
965    ALOGV("set_use_case_ident_for_all_devices(): %s", ident);
966    if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
967        verb_index = 0;
968    dev_list =
969        uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
970    if (ctrl_list_type == CTRL_LIST_VERB) {
971        uc_list =
972            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls;
973    } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
974        uc_list =
975            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].mod_ctrls;
976    } else {
977        uc_list = NULL;
978    }
979    ident_cap = getUseCaseType(ident);
980    list_size = snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
981    for (index = 0; index < list_size; index++) {
982        current_device =
983        snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head, index);
984        if (current_device != NULL) {
985            uc_index = get_use_case_index(uc_mgr, current_device,
986                       CTRL_LIST_DEVICE);
987            dev_cap = dev_list[uc_index].capability;
988            if (!capability) {
989                capability = dev_list[uc_index].capability;
990            } else if (capability != dev_list[uc_index].capability) {
991                capability = CAP_VOICE;
992            }
993            if (ident_cap == CAP_VOICE  || ident_cap == dev_cap) {
994                if (enable) {
995                    if (!snd_ucm_get_status_at_index(
996                        uc_mgr->card_ctxt_ptr->dev_list_head, current_device)) {
997                        if (uc_index >= 0) {
998                            ALOGV("Applying mixer controls for device: %s",
999                                  current_device);
1000                            ret = snd_use_case_apply_mixer_controls(uc_mgr,
1001                                  current_device, enable, CTRL_LIST_DEVICE, uc_index);
1002                            if (!ret)
1003                                snd_ucm_set_status_at_index(
1004                                  uc_mgr->card_ctxt_ptr->dev_list_head,
1005                                  current_device, enable, dev_cap);
1006                        }
1007                     } else if (ident_cap == CAP_VOICE) {
1008                        snd_use_case_apply_voice_acdb(uc_mgr, uc_index);
1009                     }
1010                 }
1011                 strlcpy(use_case, ident, sizeof(use_case));
1012                 strlcat(use_case, current_device, sizeof(use_case));
1013                 ALOGV("Applying mixer controls for use case: %s", use_case);
1014                 if ((uc_index =
1015                      get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
1016                      ALOGV("No valid use case found: %s", use_case);
1017                      intdev_flag++;
1018                 } else {
1019                      if (capability == CAP_VOICE || ident_cap == CAP_VOICE ||
1020                          capability == ident_cap) {
1021                          ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
1022                                enable, ctrl_list_type, uc_index);
1023                      }
1024                 }
1025                 use_case[0] = 0;
1026                 free(current_device);
1027             }
1028        }
1029    }
1030    if (intdev_flag) {
1031        if ((uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type)) < 0) {
1032            ALOGE("use case %s not valid without device combination", ident);
1033        } else {
1034            if (capability == CAP_VOICE || capability == ident_cap ||
1035                ident_cap == CAP_VOICE) {
1036                snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
1037                ctrl_list_type, uc_index);
1038            }
1039        }
1040    }
1041    return ret;
1042}
1043
1044/* Set/Reset mixer controls of specific use case for a specific device
1045 * uc_mgr - UCM structure pointer
1046 * ident  - use case name (verb or modifier)
1047 * device - device for which use case needs to be set/reset
1048 * enable - 1 for enable and 0 for disable
1049 * return 0 on sucess, otherwise a negative error code
1050 */
1051static int set_controls_of_usecase_for_device(snd_use_case_mgr_t *uc_mgr,
1052const char *ident, const char *device, int enable, int ctrl_list_type)
1053{
1054    card_mctrl_t *dev_list;
1055    char use_case[MAX_UC_LEN];
1056    int list_size, index, dev_index, uc_index, ret = 0;
1057    int verb_index, capability = 0;
1058
1059    ALOGV("set_use_case_ident_for_device(): use case %s device %s", ident,
1060        device);
1061    if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
1062        verb_index = 0;
1063    dev_list =
1064        uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
1065    if (device != NULL) {
1066        if (enable) {
1067            dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
1068            capability = dev_list[dev_index].capability;
1069            if (!snd_ucm_get_status_at_index(
1070                uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1071                ret = snd_use_case_apply_mixer_controls(uc_mgr, device,
1072                         enable, CTRL_LIST_DEVICE, dev_index);
1073                if (!ret)
1074                    snd_ucm_set_status_at_index(
1075                    uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
1076                    capability);
1077            }
1078        }
1079        strlcpy(use_case, ident, sizeof(use_case));
1080        strlcat(use_case, device, sizeof(use_case));
1081    ALOGV("Applying mixer controls for use case: %s", use_case);
1082        if ((uc_index = get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
1083            ALOGV("No valid use case found: %s", use_case );
1084            uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type);
1085            if (snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
1086                ctrl_list_type, uc_index) < 0) {
1087                 ALOGV("use case %s not valid without device combination also",
1088                     ident);
1089            }
1090        } else {
1091            ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case, enable,
1092                      ctrl_list_type, uc_index);
1093        }
1094    } else {
1095        uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type);
1096        if (snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
1097            ctrl_list_type, uc_index) < 0) {
1098             ALOGV("use case %s not valid without device combination also",
1099                 ident);
1100        }
1101    }
1102    return ret;
1103}
1104
1105/* Set/Reset mixer controls of specific device for all use cases
1106 * uc_mgr - UCM structure pointer
1107 * device - device name
1108 * enable - 1 for enable and 0 for disable
1109 * return 0 on sucess, otherwise a negative error code
1110 */
1111static int set_controls_of_device_for_all_usecases(snd_use_case_mgr_t *uc_mgr,
1112const char *device, int enable)
1113{
1114    card_mctrl_t *dev_list, *uc_list;
1115    char *ident_value, use_case[MAX_UC_LEN];
1116    int verb_index, uc_index, dev_index, capability = 0;
1117    int list_size, index = 0, ret = -ENODEV, flag = 0, intdev_flag = 0;
1118
1119    ALOGV("set_controls_of_device_for_all_usecases: %s", device);
1120    if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
1121        verb_index = 0;
1122    dev_list =
1123         uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
1124    dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
1125    if (dev_index >= 0)
1126        capability = dev_list[dev_index].capability;
1127    if (strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_USE_CASE_VERB_INACTIVE,
1128        strlen(SND_USE_CASE_VERB_INACTIVE))) {
1129        uc_list =
1130            uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls;
1131        if (capability == CAP_VOICE ||
1132            capability == getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ||
1133            getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) == CAP_VOICE) {
1134            strlcpy(use_case, uc_mgr->card_ctxt_ptr->current_verb,
1135                sizeof(use_case));
1136            strlcat(use_case, device, sizeof(use_case));
1137            if ((uc_index =
1138                get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB)) < 0) {
1139                ALOGV("No valid use case found: %s", use_case);
1140                intdev_flag = 1;
1141            } else {
1142                if (enable) {
1143                    if (!snd_ucm_get_status_at_index(
1144                        uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1145                        ret = snd_use_case_apply_mixer_controls(uc_mgr, device,
1146                                  enable, CTRL_LIST_DEVICE, dev_index);
1147                        if (!ret)
1148                            snd_ucm_set_status_at_index(
1149                            uc_mgr->card_ctxt_ptr->dev_list_head, device,
1150                            enable, capability);
1151                            flag = 1;
1152                    }
1153                }
1154                ALOGV("set %d for use case value: %s", enable, use_case);
1155                ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
1156                          enable, CTRL_LIST_VERB, uc_index);
1157                if (ret != 0)
1158                     ALOGE("No valid controls exists for usecase %s and device \
1159                          %s, enable: %d", use_case, device, enable);
1160            }
1161        }
1162        if (intdev_flag) {
1163            if (enable && !flag) {
1164                if (!snd_ucm_get_status_at_index(
1165                    uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1166                    ret = snd_use_case_apply_mixer_controls(uc_mgr,
1167                              device, enable, CTRL_LIST_DEVICE, dev_index);
1168                    if (!ret)
1169                        snd_ucm_set_status_at_index(
1170                        uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
1171                        capability);
1172                    flag = 1;
1173                }
1174            }
1175            use_case[0] = 0;
1176            strlcpy(use_case, uc_mgr->card_ctxt_ptr->current_verb,
1177                sizeof(use_case));
1178            uc_index = get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB);
1179            if (capability == CAP_VOICE ||
1180                capability ==
1181                getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ||
1182                getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ==
1183                CAP_VOICE) {
1184                ALOGV("set %d for use case value: %s", enable, use_case);
1185                ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
1186                          enable, CTRL_LIST_VERB, uc_index);
1187                if (ret != 0)
1188                      ALOGE("No valid controls exists for usecase %s and \
1189                           device %s, enable: %d", use_case, device, enable);
1190            }
1191            intdev_flag = 0;
1192        }
1193        use_case[0] = 0;
1194    }
1195    snd_ucm_print_list(uc_mgr->card_ctxt_ptr->mod_list_head);
1196    uc_list =
1197        uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].mod_ctrls;
1198    list_size = snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
1199    for (index = 0; index < list_size; index++) {
1200        if ((ident_value =
1201            snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
1202            index))) {
1203            if (capability == CAP_VOICE ||
1204                getUseCaseType(ident_value) == CAP_VOICE ||
1205                capability == getUseCaseType(ident_value)) {
1206                strlcpy(use_case, ident_value, sizeof(use_case));
1207                strlcat(use_case, device, sizeof(use_case));
1208                if ((uc_index = get_use_case_index(uc_mgr, use_case,
1209                    CTRL_LIST_MODIFIER)) < 0) {
1210                    ALOGV("No valid use case found: %s", use_case);
1211                    intdev_flag = 1;
1212                } else {
1213                    if (enable && !flag) {
1214                        if (!snd_ucm_get_status_at_index(
1215                            uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1216                            ret = snd_use_case_apply_mixer_controls(uc_mgr,
1217                                      device, enable, CTRL_LIST_DEVICE,
1218                                      dev_index);
1219                            if (!ret)
1220                                snd_ucm_set_status_at_index(
1221                                    uc_mgr->card_ctxt_ptr->dev_list_head,
1222                                    device, enable, capability);
1223                            flag = 1;
1224                        }
1225                    }
1226                    ALOGV("set %d for use case value: %s", enable, use_case);
1227                    ret = snd_use_case_apply_mixer_controls(uc_mgr,
1228                          use_case, enable, CTRL_LIST_MODIFIER, uc_index);
1229                    if (ret != 0)
1230                        ALOGE("No valid controls exists for usecase %s and \
1231                            device %s, enable: %d", use_case, device, enable);
1232                }
1233            }
1234            if (intdev_flag) {
1235                if (enable && !flag) {
1236                    if (!snd_ucm_get_status_at_index(
1237                         uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1238                        ret = snd_use_case_apply_mixer_controls(uc_mgr,
1239                                  device, enable, CTRL_LIST_DEVICE, dev_index);
1240                        if (!ret)
1241                            snd_ucm_set_status_at_index(
1242                            uc_mgr->card_ctxt_ptr->dev_list_head, device,
1243                            enable, capability);
1244                        flag = 1;
1245                    }
1246                }
1247                use_case[0] = 0;
1248                strlcpy(use_case, ident_value, sizeof(use_case));
1249                uc_index =
1250                    get_use_case_index(uc_mgr, ident_value, CTRL_LIST_MODIFIER);
1251                if (capability == CAP_VOICE ||
1252                    capability == getUseCaseType(ident_value) ||
1253                    getUseCaseType(ident_value) == CAP_VOICE) {
1254                    ALOGV("set %d for use case value: %s", enable, use_case);
1255                    ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
1256                          enable, CTRL_LIST_MODIFIER, uc_index);
1257                    if (ret != 0)
1258                         ALOGE("No valid controls exists for usecase %s and \
1259                              device %s, enable: %d", use_case, device, enable);
1260                }
1261                intdev_flag = 0;
1262            }
1263            use_case[0] = 0;
1264            free(ident_value);
1265        }
1266    }
1267    if (!enable) {
1268        ret = snd_use_case_apply_mixer_controls(uc_mgr, device, enable,
1269                  CTRL_LIST_DEVICE, dev_index);
1270        if (!ret)
1271            snd_ucm_set_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1272                device, enable, capability);
1273    }
1274    return ret;
1275}
1276
1277/* Returns usecase type i.e. either verb or modifier
1278 * uc_mgr - UCM structure pointer
1279 * usecase - usecase name either verb or modifier
1280 * return CTRL_LIST_VERB or CTRL_LIST_MODIFIER for verb/modifier respectively
1281 */
1282static int get_usecase_type(snd_use_case_mgr_t *uc_mgr, const char *usecase)
1283{
1284    int ret = -EINVAL, index = 0;
1285
1286    while (strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1287        SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
1288        if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index], usecase,
1289            (strlen(usecase)+1))) {
1290            ret = 0;
1291            break;
1292        }
1293        index++;
1294    }
1295    if (ret == 0)
1296        return CTRL_LIST_VERB;
1297    else
1298        return CTRL_LIST_MODIFIER;
1299}
1300
1301/* Set/Reset mixer controls of specific device and specific use cases
1302 * uc_mgr - UCM structure pointer
1303 * device - device name
1304 * usecase - use case for which device needs to be enabled
1305 * enable - 1 for enable and 0 for disable
1306 * return 0 on sucess, otherwise a negative error code
1307 */
1308static int set_controls_of_device_for_usecase(snd_use_case_mgr_t *uc_mgr,
1309    const char *device, const char *usecase, int enable)
1310{
1311    card_mctrl_t *dev_list;
1312    char use_case[MAX_UC_LEN];
1313    int ret = -ENODEV, uc_index, dev_index;
1314    int verb_index, capability = 0;
1315
1316    ALOGV("set_device_for_ident(): %s %s", device, usecase);
1317    if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
1318        verb_index = 0;
1319    dev_list =
1320         uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
1321    dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
1322    capability = dev_list[dev_index].capability;
1323    if (usecase != NULL) {
1324        strlcpy(use_case, usecase, sizeof(use_case));
1325        strlcat(use_case, device, sizeof(use_case));
1326        if ((uc_index = get_use_case_index(uc_mgr, use_case,
1327            get_usecase_type(uc_mgr, usecase))) < 0) {
1328            ALOGV("No valid use case found: %s", use_case);
1329        } else {
1330            if (enable) {
1331                if (!snd_ucm_get_status_at_index(
1332                    uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1333                    ret = snd_use_case_apply_mixer_controls(uc_mgr, device,
1334                          enable, CTRL_LIST_DEVICE, dev_index);
1335                    if (!ret)
1336                        snd_ucm_set_status_at_index
1337                        (uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
1338                        capability);
1339                }
1340            }
1341            ALOGV("set %d for use case value: %s", enable, use_case);
1342            ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case, enable,
1343                      get_usecase_type(uc_mgr, usecase), uc_index);
1344            if (ret != 0)
1345                ALOGE("No valid controls exists for usecase %s and device %s, \
1346                     enable: %d", use_case, device, enable);
1347        }
1348        use_case[0] = 0;
1349    } else {
1350        if (enable) {
1351            if (!snd_ucm_get_status_at_index(
1352                 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1353                ret = snd_use_case_apply_mixer_controls(uc_mgr, device, enable,
1354                          CTRL_LIST_DEVICE, dev_index);
1355                if (!ret)
1356                    snd_ucm_set_status_at_index(
1357                        uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
1358                        capability);
1359            }
1360        }
1361    }
1362    if (!enable) {
1363        ret = snd_use_case_apply_mixer_controls(uc_mgr, device, enable,
1364                  CTRL_LIST_DEVICE, dev_index);
1365        if (!ret)
1366            snd_ucm_set_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1367                device, enable, capability);
1368    }
1369    return ret;
1370}
1371
1372/**
1373 * Set new value for an identifier
1374 * uc_mgr - UCM structure
1375 * identifier - _verb, _enadev, _disdev, _enamod, _dismod
1376 *        _swdev, _swmod
1377 * value - Value to be set
1378 * returns 0 on success, otherwise a negative error code
1379 */
1380int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
1381                     const char *identifier,
1382                     const char *value)
1383{
1384    use_case_verb_t *verb_list;
1385    char ident[MAX_STR_LEN], *ident1, *ident2, *temp_ptr;
1386    int verb_index, list_size, index = 0, ret = -EINVAL;
1387
1388    pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
1389    if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) || (value == NULL) ||
1390        (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL) ||
1391        (identifier == NULL)) {
1392        ALOGE("snd_use_case_set(): failed, invalid arguments");
1393        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1394        return -EINVAL;
1395    }
1396
1397    ALOGD("snd_use_case_set(): uc_mgr %p identifier %s value %s", uc_mgr,
1398         identifier, value);
1399    strlcpy(ident, identifier, sizeof(ident));
1400    if(!(ident1 = strtok_r(ident, "/", &temp_ptr))) {
1401        ALOGV("No multiple identifiers found in identifier value");
1402        ident[0] = 0;
1403    } else {
1404        if (!strncmp(ident1, "_swdev", 6)) {
1405            if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
1406                ALOGD("Invalid disable device value: %s, but enabling new \
1407                     device", ident2);
1408            } else {
1409                ret = snd_ucm_del_ident_from_list(
1410                          &uc_mgr->card_ctxt_ptr->dev_list_head, ident2);
1411                if (ret < 0) {
1412                    ALOGV("Ignore device %s disable, device not part of \
1413                         enabled list", ident2);
1414                } else {
1415                    ALOGV("swdev: device value to be disabled: %s", ident2);
1416                    /* Disable mixer controls for
1417                     * corresponding use cases and device */
1418                    ret = set_controls_of_device_for_all_usecases(uc_mgr,
1419                              ident2, 0);
1420                    if (ret < 0) {
1421                        ALOGV("Device %s not disabled, no valid use case \
1422                              found: %d", ident2, errno);
1423                    }
1424                }
1425            }
1426            pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1427            ret = snd_use_case_set(uc_mgr, "_enadev", value);
1428            if (ret < 0) {
1429                ALOGV("Device %s not enabled, no valid use case found: %d",
1430                    value, errno);
1431            }
1432            return ret;
1433        } else if (!strncmp(ident1, "_swmod", 6)) {
1434            pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1435            if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
1436                ALOGD("Invalid modifier value: %s, but enabling new modifier",
1437                    ident2);
1438            } else {
1439                ret = snd_use_case_set(uc_mgr, "_dismod", ident2);
1440                if (ret < 0) {
1441                    ALOGV("Modifier %s not disabled, no valid use case \
1442                         found: %d", ident2, errno);
1443                }
1444            }
1445            ret = snd_use_case_set(uc_mgr, "_enamod", value);
1446            if (ret < 0) {
1447                ALOGV("Modifier %s not enabled, no valid use case found: %d",
1448                    value, errno);
1449            }
1450            return ret;
1451        } else {
1452            ALOGV("No switch device/modifier option found: %s", ident1);
1453        }
1454        ident[0] = 0;
1455    }
1456
1457    if (!strncmp(identifier, "_verb", 5)) {
1458        /* Check if value is valid verb */
1459        while (strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1460               SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
1461            if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index], value,
1462                (strlen(value)+1))) {
1463                ret = 0;
1464                break;
1465            }
1466            index++;
1467        }
1468        if ((ret < 0) && (strncmp(value, SND_USE_CASE_VERB_INACTIVE,
1469            strlen(SND_USE_CASE_VERB_INACTIVE)))) {
1470            ALOGE("Invalid verb identifier value");
1471        } else {
1472            ALOGV("Index:%d Verb:%s", index,
1473                uc_mgr->card_ctxt_ptr->verb_list[index]);
1474            /* Disable the mixer controls for current use case
1475             * for all the enabled devices */
1476            if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
1477                SND_USE_CASE_VERB_INACTIVE,
1478                strlen(SND_USE_CASE_VERB_INACTIVE))) {
1479                ret = set_controls_of_usecase_for_all_devices(uc_mgr,
1480                      uc_mgr->card_ctxt_ptr->current_verb, 0, CTRL_LIST_VERB);
1481                if (ret != 0)
1482                    ALOGE("Failed to disable controls for use case: %s",
1483                        uc_mgr->card_ctxt_ptr->current_verb);
1484            }
1485            strlcpy(uc_mgr->card_ctxt_ptr->current_verb, value, MAX_STR_LEN);
1486            /* Enable the mixer controls for the new use case
1487             * for all the enabled devices */
1488            if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
1489               SND_USE_CASE_VERB_INACTIVE,
1490               strlen(SND_USE_CASE_VERB_INACTIVE))) {
1491               uc_mgr->card_ctxt_ptr->current_verb_index = index;
1492               ret = set_controls_of_usecase_for_all_devices(uc_mgr,
1493                     uc_mgr->card_ctxt_ptr->current_verb, 1, CTRL_LIST_VERB);
1494            }
1495        }
1496    } else if (!strncmp(identifier, "_enadev", 7)) {
1497        index = 0; ret = 0;
1498        list_size =
1499            snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1500        for (index = 0; index < list_size; index++) {
1501            if ((ident1 =
1502                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1503                index))) {
1504                if (!strncmp(ident1, value, (strlen(value)+1))) {
1505                    ALOGV("Ignore enable as %s device is already part of \
1506                         enabled list", value);
1507                    free(ident1);
1508                    break;
1509                }
1510                free(ident1);
1511            }
1512        }
1513        if (index == list_size) {
1514            ALOGV("enadev: device value to be enabled: %s", value);
1515            snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1516                value);
1517        }
1518        snd_ucm_print_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1519        /* Apply Mixer controls of all verb and modifiers for this device*/
1520        ret = set_controls_of_device_for_all_usecases(uc_mgr, value, 1);
1521    } else if (!strncmp(identifier, "_disdev", 7)) {
1522        ret = snd_ucm_get_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1523                  value);
1524        if (ret < 0) {
1525            ALOGD("disdev: device %s not enabled, no need to disable", value);
1526        } else if (ret == 0) {
1527            ALOGV("disdev: device %s not active, remove from the list", value);
1528            ret =
1529            snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1530            value);
1531            if (ret < 0) {
1532                ALOGE("Invalid device: Device not part of enabled device list");
1533            }
1534        } else {
1535            ret =
1536            snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1537            value);
1538            if (ret < 0) {
1539                ALOGE("Invalid device: Device not part of enabled device list");
1540            } else {
1541                ALOGV("disdev: device value to be disabled: %s", value);
1542                index = get_use_case_index(uc_mgr, value, CTRL_LIST_DEVICE);
1543                /* Apply Mixer controls for corresponding device and modifier */
1544                ret = snd_use_case_apply_mixer_controls(uc_mgr, value, 0,
1545                          CTRL_LIST_DEVICE, index);
1546            }
1547        }
1548    } else if (!strncmp(identifier, "_enamod", 7)) {
1549        index = 0; ret = 0;
1550        verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
1551        if (verb_index < 0) {
1552            ALOGE("Invalid verb identifier value");
1553        } else {
1554            ALOGV("Index:%d Verb:%s", verb_index,
1555                 uc_mgr->card_ctxt_ptr->verb_list[verb_index]);
1556            verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
1557            while(strncmp(verb_list[verb_index].modifier_list[index], value,
1558                  (strlen(value)+1))) {
1559                if (!strncmp(verb_list[verb_index].modifier_list[index],
1560                    SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))){
1561                    ret = -EINVAL;
1562                    break;
1563                }
1564                index++;
1565            }
1566            if (ret < 0) {
1567                ALOGE("Invalid modifier identifier value");
1568            } else {
1569                snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
1570                    value);
1571                /* Enable the mixer controls for the new use case
1572                 * for all the enabled devices */
1573                ret = set_controls_of_usecase_for_all_devices(uc_mgr, value, 1,
1574                          CTRL_LIST_MODIFIER);
1575            }
1576        }
1577    } else if (!strncmp(identifier, "_dismod", 7)) {
1578        ret = snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
1579                  value);
1580        if (ret < 0) {
1581            ALOGE("Modifier not enabled currently, invalid modifier");
1582        } else {
1583            ALOGV("dismod: modifier value to be disabled: %s", value);
1584            /* Enable the mixer controls for the new use case
1585             * for all the enabled devices */
1586            ret = set_controls_of_usecase_for_all_devices(uc_mgr, value, 0,
1587                      CTRL_LIST_MODIFIER);
1588        }
1589    } else {
1590        ALOGE("Unknown identifier value: %s", identifier);
1591    }
1592    pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1593    return ret;
1594}
1595
1596/**
1597 * Set new value for an identifier based on use case
1598 * uc_mgr - UCM structure
1599 * identifier - _verb, _enadev, _disdev, _enamod, _dismod
1600 *        _swdev, _swmod
1601 * value - Value to be set
1602 * usecase - usecase/device for which this command needs to be executed
1603 * returns 0 on success, otherwise a negative error code
1604 */
1605int snd_use_case_set_case(snd_use_case_mgr_t *uc_mgr,
1606                     const char *identifier,
1607                     const char *value, const char *usecase)
1608{
1609    use_case_verb_t *verb_list;
1610    char ident[MAX_STR_LEN], *ident1, *ident2, *temp_ptr;
1611    int verb_index, list_size, index = 0, ret = -EINVAL;
1612
1613    pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
1614    if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) || (value == NULL) ||
1615        (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL) ||
1616        (identifier == NULL)) {
1617        ALOGE("snd_use_case_set_case(): failed, invalid arguments");
1618        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1619        return -EINVAL;
1620    }
1621
1622    ALOGD("snd_use_case_set_case(): uc_mgr %p identifier %s value %s",
1623        uc_mgr, identifier, value);
1624    strlcpy(ident, identifier, sizeof(ident));
1625    if(!(ident1 = strtok_r(ident, "/", &temp_ptr))) {
1626        ALOGV("No multiple identifiers found in identifier value");
1627        ident[0] = 0;
1628    } else {
1629        if (!strncmp(ident1, "_swdev", 6)) {
1630            if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
1631                ALOGD("Invalid disable device value: %s, but enabling new \
1632                     device", ident2);
1633            } else {
1634                ret = snd_ucm_del_ident_from_list(
1635                          &uc_mgr->card_ctxt_ptr->dev_list_head, ident2);
1636                if (ret < 0) {
1637                    ALOGV("Ignore device %s disable, device not part of \
1638                         enabled list", ident2);
1639                } else {
1640                    ALOGV("swdev: device value to be disabled: %s", ident2);
1641                    /* Disable mixer controls for
1642                     * corresponding use cases and device */
1643                    ret = set_controls_of_device_for_usecase(uc_mgr, ident2,
1644                              usecase, 0);
1645                    if (ret < 0) {
1646                        ALOGV("Device %s not disabled, no valid use case \
1647                             found: %d", ident2, errno);
1648                    }
1649                }
1650            }
1651            pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1652            ret = snd_use_case_set_case(uc_mgr, "_enadev", value, usecase);
1653            if (ret < 0) {
1654                ALOGV("Device %s not enabled, no valid use case found: %d",
1655                    value, errno);
1656            }
1657            return ret;
1658        } else if (!strncmp(ident1, "_swmod", 6)) {
1659            pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1660            if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
1661                ALOGD("Invalid modifier value: %s, but enabling new modifier",
1662                    ident2);
1663            } else {
1664                ret = snd_use_case_set_case(uc_mgr, "_dismod", ident2, usecase);
1665                if (ret < 0) {
1666                    ALOGV("Modifier %s not disabled, no valid use case \
1667                         found: %d", ident2, errno);
1668                }
1669            }
1670            ret = snd_use_case_set_case(uc_mgr, "_enamod", value, usecase);
1671            if (ret < 0) {
1672                ALOGV("Modifier %s not enabled, no valid use case found: %d",
1673                    value, errno);
1674            }
1675            return ret;
1676        } else {
1677            ALOGV("No switch device/modifier option found: %s", ident1);
1678        }
1679        ident[0] = 0;
1680    }
1681
1682    if (!strncmp(identifier, "_verb", 5)) {
1683        /* Check if value is valid verb */
1684        while (strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1685               SND_UCM_END_OF_LIST, MAX_STR_LEN)) {
1686            if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1687                value, MAX_STR_LEN)) {
1688                ret = 0;
1689                break;
1690            }
1691            index++;
1692        }
1693        if ((ret < 0) && (strncmp(value, SND_USE_CASE_VERB_INACTIVE,
1694            MAX_STR_LEN))) {
1695            ALOGE("Invalid verb identifier value");
1696        } else {
1697            ALOGV("Index:%d Verb:%s", index,
1698                 uc_mgr->card_ctxt_ptr->verb_list[index]);
1699            /* Disable the mixer controls for current use case
1700             * for specified device */
1701            if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
1702                SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN)) {
1703                ret = set_controls_of_usecase_for_device(uc_mgr,
1704                          uc_mgr->card_ctxt_ptr->current_verb, usecase,
1705                          0, CTRL_LIST_VERB);
1706                if (ret != 0)
1707                    ALOGE("Failed to disable controls for use case: %s",
1708                        uc_mgr->card_ctxt_ptr->current_verb);
1709            }
1710            strlcpy(uc_mgr->card_ctxt_ptr->current_verb, value, MAX_STR_LEN);
1711            /* Enable the mixer controls for the new use case
1712             * for specified device */
1713            if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
1714                SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN)) {
1715               uc_mgr->card_ctxt_ptr->current_verb_index = index;
1716               index = 0;
1717               list_size =
1718               snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1719               for (index = 0; index < list_size; index++) {
1720                   if ((ident1 = snd_ucm_get_value_at_index(
1721                       uc_mgr->card_ctxt_ptr->dev_list_head, index))) {
1722                       if (!strncmp(ident1, usecase, MAX_STR_LEN)) {
1723                           ALOGV("Device already part of enabled list: %s",
1724                               usecase);
1725                           free(ident1);
1726                           break;
1727                       }
1728                       free(ident1);
1729                   }
1730               }
1731               if (index == list_size) {
1732                   ALOGV("enadev: device value to be enabled: %s", usecase);
1733                   snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1734                        usecase);
1735               }
1736               ret = set_controls_of_usecase_for_device(uc_mgr,
1737                         uc_mgr->card_ctxt_ptr->current_verb, usecase,
1738                         1, CTRL_LIST_VERB);
1739            }
1740        }
1741    } else if (!strncmp(identifier, "_enadev", 7)) {
1742        index = 0; ret = 0;
1743        list_size =
1744            snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1745        for (index = 0; index < list_size; index++) {
1746            if ((ident1 =
1747                snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1748                index))) {
1749                if (!strncmp(ident1, value, MAX_STR_LEN)) {
1750                    ALOGV("Device already part of enabled list: %s", value);
1751                    free(ident1);
1752                    break;
1753                }
1754                free(ident1);
1755            }
1756        }
1757        if (index == list_size) {
1758            ALOGV("enadev: device value to be enabled: %s", value);
1759            snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1760                value);
1761        }
1762        snd_ucm_print_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1763        /* Apply Mixer controls of usecase for this device*/
1764        ret = set_controls_of_device_for_usecase(uc_mgr, value, usecase, 1);
1765    } else if (!strncmp(identifier, "_disdev", 7)) {
1766        ret = snd_ucm_get_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1767                  value);
1768        if (ret < 0) {
1769            ALOGD("disdev: device %s not enabled, no need to disable", value);
1770        } else if (ret == 0) {
1771            ALOGV("disdev: device %s not active, remove from the list", value);
1772            ret =
1773            snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1774            value);
1775            if (ret < 0) {
1776                ALOGE("Invalid device: Device not part of enabled device list");
1777            }
1778        } else {
1779            ret =
1780            snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1781            value);
1782            if (ret < 0) {
1783                ALOGE("Invalid device: Device not part of enabled device list");
1784            } else {
1785                ALOGV("disdev: device value to be disabled: %s", value);
1786                /* Apply Mixer controls of usecase for this device*/
1787                ret = set_controls_of_device_for_usecase(uc_mgr, value,
1788                          usecase, 0);
1789            }
1790        }
1791    } else if (!strncmp(identifier, "_enamod", 7)) {
1792        if (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
1793            SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN)) {
1794            ALOGE("Invalid use case verb value");
1795            ret = -EINVAL;
1796        } else {
1797            ret = 0;
1798            while(strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1799                  uc_mgr->card_ctxt_ptr->current_verb, MAX_STR_LEN)) {
1800                if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1801                    SND_UCM_END_OF_LIST, MAX_STR_LEN)){
1802                    ret = -EINVAL;
1803                    break;
1804                }
1805                index++;
1806            }
1807        }
1808        if (ret < 0) {
1809            ALOGE("Invalid verb identifier value");
1810        } else {
1811            verb_index = index; index = 0; ret = 0;
1812            verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
1813            ALOGV("Index:%d Verb:%s", verb_index,
1814                 uc_mgr->card_ctxt_ptr->verb_list[verb_index]);
1815            while(strncmp(verb_list[verb_index].modifier_list[index],
1816                value, MAX_STR_LEN)) {
1817                if (!strncmp(verb_list[verb_index].modifier_list[index],
1818                    SND_UCM_END_OF_LIST, MAX_STR_LEN)){
1819                    ret = -EINVAL;
1820                    break;
1821                }
1822                index++;
1823            }
1824            if (ret < 0) {
1825                ALOGE("Invalid modifier identifier value");
1826            } else {
1827                index = 0;
1828                list_size =
1829                snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1830                for (index = 0; index < list_size; index++) {
1831                    if ((ident1 = snd_ucm_get_value_at_index(
1832                        uc_mgr->card_ctxt_ptr->dev_list_head, index))) {
1833                        if (!strncmp(ident1, usecase, MAX_STR_LEN)) {
1834                            ALOGV("Device already part of enabled list: %s",
1835                                usecase);
1836                            free(ident1);
1837                            break;
1838                        }
1839                        free(ident1);
1840                    }
1841                }
1842                if (index == list_size) {
1843                    ALOGV("enadev: device value to be enabled: %s", usecase);
1844                    snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1845                         usecase);
1846                }
1847                snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
1848                    value);
1849                /* Enable the mixer controls for the new use case
1850                 * for all the enabled devices */
1851                ret = set_controls_of_usecase_for_device(uc_mgr, value,
1852                      usecase, 1, CTRL_LIST_MODIFIER);
1853            }
1854        }
1855    } else if (!strncmp(identifier, "_dismod", 7)) {
1856        ret = snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
1857              value);
1858        if (ret < 0) {
1859            ALOGE("Modifier not enabled currently, invalid modifier");
1860        } else {
1861            ALOGV("dismod: modifier value to be disabled: %s", value);
1862            /* Enable the mixer controls for the new use case
1863             * for all the enabled devices */
1864            ret = set_controls_of_usecase_for_device(uc_mgr, value, usecase,
1865                      0, CTRL_LIST_MODIFIER);
1866        }
1867    } else {
1868        ALOGE("Unknown identifier value: %s", identifier);
1869    }
1870    pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1871    return ret;
1872}
1873
1874/**
1875 * Open and initialise use case core for sound card
1876 * uc_mgr - Returned use case manager pointer
1877 * card_name - Sound card name.
1878 * returns 0 on success, otherwise a negative error code
1879 */
1880int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, const char *card_name)
1881{
1882    snd_use_case_mgr_t *uc_mgr_ptr = NULL;
1883    int index, ret = -EINVAL;
1884    char tmp[2];
1885
1886    ALOGV("snd_use_case_open(): card_name %s", card_name);
1887
1888    if (card_name == NULL) {
1889        ALOGE("snd_use_case_mgr_open: failed, invalid arguments");
1890        return ret;
1891    }
1892
1893    for (index = 0; index < (int)MAX_NUM_CARDS; index++) {
1894        if(!strncmp(card_name, card_mapping_list[index].card_name,
1895           (strlen(card_mapping_list[index].card_name)+1))) {
1896            ret = 0;
1897            break;
1898        }
1899    }
1900
1901    if (ret < 0) {
1902        ALOGE("Card %s not found", card_name);
1903    } else {
1904        uc_mgr_ptr = (snd_use_case_mgr_t *)calloc(1,
1905                         sizeof(snd_use_case_mgr_t));
1906        if (uc_mgr_ptr == NULL) {
1907            ALOGE("Failed to allocate memory for instance");
1908            return -ENOMEM;
1909        }
1910        uc_mgr_ptr->snd_card_index = index;
1911        uc_mgr_ptr->card_ctxt_ptr = (card_ctxt_t *)calloc(1,
1912                                        sizeof(card_ctxt_t));
1913        if (uc_mgr_ptr->card_ctxt_ptr == NULL) {
1914            ALOGE("Failed to allocate memory for card context");
1915            free(uc_mgr_ptr);
1916            uc_mgr_ptr = NULL;
1917            return -ENOMEM;
1918        }
1919        uc_mgr_ptr->card_ctxt_ptr->card_number =
1920            card_mapping_list[index].card_number;
1921        uc_mgr_ptr->card_ctxt_ptr->card_name =
1922            (char *)malloc((strlen(card_name)+1)*sizeof(char));
1923        if (uc_mgr_ptr->card_ctxt_ptr->card_name == NULL) {
1924            ALOGE("Failed to allocate memory for card name");
1925            free(uc_mgr_ptr->card_ctxt_ptr);
1926            free(uc_mgr_ptr);
1927            uc_mgr_ptr = NULL;
1928            return -ENOMEM;
1929        }
1930        strlcpy(uc_mgr_ptr->card_ctxt_ptr->card_name, card_name,
1931            ((strlen(card_name)+1)*sizeof(char)));
1932        uc_mgr_ptr->card_ctxt_ptr->control_device =
1933            (char *)malloc((strlen("/dev/snd/controlC")+2)*sizeof(char));
1934        if (uc_mgr_ptr->card_ctxt_ptr->control_device == NULL) {
1935            ALOGE("Failed to allocate memory for control device string");
1936            free(uc_mgr_ptr->card_ctxt_ptr->card_name);
1937            free(uc_mgr_ptr->card_ctxt_ptr);
1938            free(uc_mgr_ptr);
1939            uc_mgr_ptr = NULL;
1940            return -ENOMEM;
1941        }
1942        strlcpy(uc_mgr_ptr->card_ctxt_ptr->control_device,
1943            "/dev/snd/controlC", 18);
1944        snprintf(tmp, sizeof(tmp), "%d",
1945            uc_mgr_ptr->card_ctxt_ptr->card_number);
1946        strlcat(uc_mgr_ptr->card_ctxt_ptr->control_device, tmp,
1947            (strlen("/dev/snd/controlC")+2)*sizeof(char));
1948        uc_mgr_ptr->device_list_count = 0;
1949        uc_mgr_ptr->modifier_list_count = 0;
1950        uc_mgr_ptr->current_device_list = NULL;
1951        uc_mgr_ptr->current_modifier_list = NULL;
1952        uc_mgr_ptr->current_tx_device = -1;
1953        uc_mgr_ptr->current_rx_device = -1;
1954        pthread_mutexattr_init(&uc_mgr_ptr->card_ctxt_ptr->card_lock_attr);
1955        pthread_mutex_init(&uc_mgr_ptr->card_ctxt_ptr->card_lock,
1956            &uc_mgr_ptr->card_ctxt_ptr->card_lock_attr);
1957        strlcpy(uc_mgr_ptr->card_ctxt_ptr->current_verb,
1958                SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN);
1959        /* Reset all mixer controls if any applied
1960         * previously for the same card */
1961    snd_use_case_mgr_reset(uc_mgr_ptr);
1962        uc_mgr_ptr->card_ctxt_ptr->current_verb_index = -1;
1963        /* Parse config files and update mixer controls */
1964        ret = snd_ucm_parse(&uc_mgr_ptr);
1965        if(ret < 0) {
1966            ALOGE("Failed to parse config files: %d", ret);
1967            snd_ucm_free_mixer_list(&uc_mgr_ptr);
1968        }
1969        ALOGV("Open mixer device: %s",
1970            uc_mgr_ptr->card_ctxt_ptr->control_device);
1971        uc_mgr_ptr->card_ctxt_ptr->mixer_handle =
1972            mixer_open(uc_mgr_ptr->card_ctxt_ptr->control_device);
1973        ALOGV("Mixer handle %p", uc_mgr_ptr->card_ctxt_ptr->mixer_handle);
1974        *uc_mgr = uc_mgr_ptr;
1975    }
1976    ALOGV("snd_use_case_open(): returning instance %p", uc_mgr_ptr);
1977    return ret;
1978}
1979
1980
1981/**
1982 * \brief Reload and re-parse use case configuration files for sound card.
1983 * \param uc_mgr Use case manager
1984 * \return zero if success, otherwise a negative error code
1985 */
1986int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr) {
1987    ALOGE("Reload is not implemented for now as there is no use case currently");
1988    return 0;
1989}
1990
1991/**
1992 * \brief Close use case manager
1993 * \param uc_mgr Use case manager
1994 * \return zero if success, otherwise a negative error code
1995 */
1996int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
1997{
1998    int ret = 0;
1999
2000    if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) ||
2001        (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) {
2002        ALOGE("snd_use_case_mgr_close(): failed, invalid arguments");
2003        return -EINVAL;
2004    }
2005
2006    ALOGV("snd_use_case_close(): instance %p", uc_mgr);
2007    ret = snd_use_case_mgr_reset(uc_mgr);
2008    if (ret < 0)
2009        ALOGE("Failed to reset ucm session");
2010    snd_ucm_free_mixer_list(&uc_mgr);
2011    pthread_mutexattr_destroy(&uc_mgr->card_ctxt_ptr->card_lock_attr);
2012    pthread_mutex_destroy(&uc_mgr->card_ctxt_ptr->card_lock);
2013    if (uc_mgr->card_ctxt_ptr->mixer_handle) {
2014        mixer_close(uc_mgr->card_ctxt_ptr->mixer_handle);
2015        uc_mgr->card_ctxt_ptr->mixer_handle = NULL;
2016    }
2017    uc_mgr->snd_card_index = -1;
2018    uc_mgr->current_tx_device = -1;
2019    uc_mgr->current_rx_device = -1;
2020    free(uc_mgr->card_ctxt_ptr->control_device);
2021    free(uc_mgr->card_ctxt_ptr->card_name);
2022    free(uc_mgr->card_ctxt_ptr);
2023    uc_mgr->card_ctxt_ptr = NULL;
2024    free(uc_mgr);
2025    uc_mgr = NULL;
2026    ALOGV("snd_use_case_mgr_close(): card instace closed successfully");
2027    return ret;
2028}
2029
2030/**
2031 * \brief Reset use case manager verb, device, modifier to deafult settings.
2032 * \param uc_mgr Use case manager
2033 * \return zero if success, otherwise a negative error code
2034 */
2035int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
2036{
2037    char *ident_value;
2038    int index, list_size, ret = 0;
2039
2040    ALOGV("snd_use_case_reset(): instance %p", uc_mgr);
2041    pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
2042    if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) ||
2043        (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) {
2044        ALOGE("snd_use_case_mgr_reset(): failed, invalid arguments");
2045        pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
2046        return -EINVAL;
2047    }
2048
2049    /* Disable mixer controls of all the enabled modifiers */
2050    list_size = snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
2051    for (index = (list_size-1); index >= 0; index--) {
2052        if ((ident_value =
2053            snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
2054                index))) {
2055            snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
2056                ident_value);
2057            ret = set_controls_of_usecase_for_all_devices(uc_mgr,
2058                      ident_value, 0, CTRL_LIST_MODIFIER);
2059        if (ret != 0)
2060                ALOGE("Failed to disable mixer controls for %s", ident_value);
2061            free(ident_value);
2062        }
2063    }
2064    /* Clear the enabled modifiers list */
2065    if (uc_mgr->modifier_list_count) {
2066        for (index = 0; index < uc_mgr->modifier_list_count; index++) {
2067            free(uc_mgr->current_modifier_list[index]);
2068            uc_mgr->current_modifier_list[index] = NULL;
2069        }
2070        free(uc_mgr->current_modifier_list);
2071        uc_mgr->current_modifier_list = NULL;
2072        uc_mgr->modifier_list_count = 0;
2073    }
2074    /* Disable mixer controls of current use case verb */
2075    if(strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_USE_CASE_VERB_INACTIVE,
2076       strlen(SND_USE_CASE_VERB_INACTIVE))) {
2077        ret = set_controls_of_usecase_for_all_devices(uc_mgr,
2078                  uc_mgr->card_ctxt_ptr->current_verb, 0, CTRL_LIST_VERB);
2079        if (ret != 0)
2080            ALOGE("Failed to disable mixer controls for %s",
2081                uc_mgr->card_ctxt_ptr->current_verb);
2082        strlcpy(uc_mgr->card_ctxt_ptr->current_verb, SND_USE_CASE_VERB_INACTIVE,
2083            MAX_STR_LEN);
2084    }
2085    /* Disable mixer controls of all the enabled devices */
2086    list_size = snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
2087    for (index = (list_size-1); index >= 0; index--) {
2088        if ((ident_value =
2089            snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
2090                index))) {
2091            snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
2092                ident_value);
2093            ret = set_controls_of_device_for_all_usecases(uc_mgr,
2094                      ident_value, 0);
2095        if (ret != 0)
2096                ALOGE("Failed to disable or no mixer controls set for %s",
2097                    ident_value);
2098        free(ident_value);
2099        }
2100    }
2101    /* Clear the enabled devices list */
2102    if (uc_mgr->device_list_count) {
2103        for (index = 0; index < uc_mgr->device_list_count; index++) {
2104            free(uc_mgr->current_device_list[index]);
2105            uc_mgr->current_device_list[index] = NULL;
2106        }
2107        free(uc_mgr->current_device_list);
2108        uc_mgr->current_device_list = NULL;
2109        uc_mgr->device_list_count = 0;
2110    }
2111    uc_mgr->current_tx_device = -1;
2112    uc_mgr->current_rx_device = -1;
2113    pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
2114    return ret;
2115}
2116
2117/* 2nd stage parsing done in seperate thread */
2118void *second_stage_parsing_thread(void *uc_mgr_ptr)
2119{
2120    use_case_verb_t *verb_list;
2121    char path[200];
2122    struct stat st;
2123    int fd, index = 0, ret = 0, rc = 0;
2124    char *read_buf = NULL, *next_str = NULL, *current_str = NULL, *buf = NULL;
2125    char *p = NULL, *verb_name = NULL, *file_name = NULL, *temp_ptr = NULL;
2126    snd_use_case_mgr_t **uc_mgr = (snd_use_case_mgr_t **)&uc_mgr_ptr;
2127
2128    strlcpy(path, CONFIG_DIR, (strlen(CONFIG_DIR)+1));
2129    strlcat(path, (*uc_mgr)->card_ctxt_ptr->card_name, sizeof(path));
2130    ALOGV("master config file path:%s", path);
2131    fd = open(path, O_RDONLY);
2132    if (fd < 0) {
2133        ALOGE("failed to open config file %s error %d\n", path, errno);
2134        return NULL;
2135    }
2136    if (fstat(fd, &st) < 0) {
2137        ALOGE("failed to stat %s error %d\n", path, errno);
2138        close(fd);
2139        return NULL;
2140    }
2141    read_buf = (char *) mmap(0, st.st_size, PROT_READ | PROT_WRITE,
2142               MAP_PRIVATE, fd, 0);
2143    if (read_buf == MAP_FAILED) {
2144        ALOGE("failed to mmap file error %d\n", errno);
2145        close(fd);
2146        return NULL;
2147    }
2148    current_str = read_buf;
2149    verb_name = NULL;
2150    while (*current_str != (char)EOF)  {
2151        next_str = strchr(current_str, '\n');
2152        if (!next_str)
2153            break;
2154        *next_str++ = '\0';
2155        if (verb_name == NULL) {
2156            buf = strstr(current_str, "SectionUseCase");
2157            if (buf == NULL) {
2158                if((current_str = next_str) == NULL)
2159                    break;
2160                else
2161                    continue;
2162            }
2163            /* Ignore parsing first use case (HiFi) as it is already parsed
2164             * in 1st stage of parsing */
2165            if (index == 0) {
2166                index++;
2167                if((current_str = next_str) == NULL)
2168                    break;
2169                else
2170                    continue;
2171            }
2172            p = strtok_r(buf, ".", &temp_ptr);
2173            while (p != NULL) {
2174                p = strtok_r(NULL, "\"", &temp_ptr);
2175                if (p == NULL)
2176                    break;
2177                verb_name = (char *)malloc((strlen(p)+1)*sizeof(char));
2178                if(verb_name == NULL) {
2179                    ret = -ENOMEM;
2180                    break;
2181                }
2182                strlcpy(verb_name, p, (strlen(p)+1)*sizeof(char));
2183                break;
2184            }
2185        } else {
2186            buf = strstr(current_str, "File");
2187            if (buf == NULL) {
2188                if((current_str = next_str) == NULL)
2189                    break;
2190                else
2191                    continue;
2192            }
2193            p = strtok_r(buf, "\"", &temp_ptr);
2194            while (p != NULL) {
2195                p = strtok_r(NULL, "\"", &temp_ptr);
2196                if (p == NULL)
2197                    break;
2198                file_name = (char *)malloc((strlen(p)+1)*sizeof(char));
2199                if(file_name == NULL) {
2200                    ret = -ENOMEM;
2201                    break;
2202                }
2203                strlcpy(file_name, p, (strlen(p)+1)*sizeof(char));
2204                break;
2205            }
2206            verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
2207            if (file_name != NULL) {
2208                ret = snd_ucm_parse_verb(uc_mgr, file_name, index);
2209                verb_list[index].use_case_name =
2210                    (char *)malloc((strlen(verb_name)+1)*sizeof(char));
2211                strlcpy(verb_list[index].use_case_name, verb_name,
2212                    ((strlen(verb_name)+1)*sizeof(char)));
2213                /* Verb list might have been appended with END OF LIST in
2214                 * 1st stage parsing. Delete this entry so that new verbs
2215                 * are appended from here and END OF LIST will be added
2216                 * again at the end of 2nd stage parsing
2217                 */
2218                if((*uc_mgr)->card_ctxt_ptr->verb_list[index]) {
2219                    free((*uc_mgr)->card_ctxt_ptr->verb_list[index]);
2220                    (*uc_mgr)->card_ctxt_ptr->verb_list[index] = NULL;
2221                }
2222                (*uc_mgr)->card_ctxt_ptr->verb_list[index] =
2223                    (char *)malloc((strlen(verb_name)+1)*sizeof(char));
2224                strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index], verb_name,
2225                    ((strlen(verb_name)+1)*sizeof(char)));
2226                free(verb_name);
2227                verb_name = NULL;
2228                free(file_name);
2229                file_name = NULL;
2230            }
2231            index++;
2232            (*uc_mgr)->card_ctxt_ptr->verb_list[index] =
2233                (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2234            strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index],
2235                 SND_UCM_END_OF_LIST,
2236                 ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
2237        }
2238        if((current_str = next_str) == NULL)
2239            break;
2240    }
2241    if (verb_name != NULL) {
2242        free(verb_name);
2243        verb_name = NULL;
2244    }
2245    if (file_name != NULL) {
2246        free(file_name);
2247        file_name = NULL;
2248    }
2249    munmap(read_buf, st.st_size);
2250    close(fd);
2251#if PARSE_DEBUG
2252        /* Prints use cases and mixer controls parsed from config files */
2253        snd_ucm_print((*uc_mgr));
2254#endif
2255    if(ret < 0)
2256        ALOGE("Failed to parse config files: %d", ret);
2257    ALOGE("Exiting parsing thread uc_mgr %p\n", uc_mgr);
2258    return NULL;
2259}
2260
2261/* Function can be used by UCM clients to wait until parsing completes
2262 * uc_mgr - use case manager structure
2263 * Returns 0 on success, error number otherwise
2264*/
2265int snd_use_case_mgr_wait_for_parsing(snd_use_case_mgr_t *uc_mgr)
2266{
2267    int ret;
2268
2269    ret = pthread_join(uc_mgr->thr, NULL);
2270    return ret;
2271}
2272
2273/* Parse config files and update mixer controls for the use cases
2274 * 1st stage parsing done to parse HiFi config file
2275 * uc_mgr - use case manager structure
2276 * Returns 0 on sucess, negative error code otherwise
2277 */
2278static int snd_ucm_parse(snd_use_case_mgr_t **uc_mgr)
2279{
2280    use_case_verb_t *verb_list;
2281    struct stat st;
2282    int fd, verb_count, index = 0, ret = 0, rc;
2283    char *read_buf, *next_str, *current_str, *buf, *p, *verb_name;
2284    char *file_name = NULL, *temp_ptr;
2285    char path[200];
2286
2287    strlcpy(path, CONFIG_DIR, (strlen(CONFIG_DIR)+1));
2288    strlcat(path, (*uc_mgr)->card_ctxt_ptr->card_name, sizeof(path));
2289    ALOGV("master config file path:%s", path);
2290    fd = open(path, O_RDONLY);
2291    if (fd < 0) {
2292        ALOGE("failed to open config file %s error %d\n", path, errno);
2293        return -EINVAL;
2294    }
2295    if (fstat(fd, &st) < 0) {
2296        ALOGE("failed to stat %s error %d\n", path, errno);
2297        close(fd);
2298        return -EINVAL;
2299    }
2300    read_buf = (char *) mmap(0, st.st_size, PROT_READ | PROT_WRITE,
2301               MAP_PRIVATE, fd, 0);
2302    if (read_buf == MAP_FAILED) {
2303        ALOGE("failed to mmap file error %d\n", errno);
2304        close(fd);
2305        return -EINVAL;
2306    }
2307    current_str = read_buf;
2308    verb_count = get_verb_count(current_str);
2309    (*uc_mgr)->card_ctxt_ptr->use_case_verb_list =
2310        (use_case_verb_t *)malloc((verb_count+1)*(sizeof(use_case_verb_t)));
2311    if ((*uc_mgr)->card_ctxt_ptr->use_case_verb_list == NULL) {
2312        ALOGE("failed to allocate memory for use case verb list\n");
2313        munmap(read_buf, st.st_size);
2314        close(fd);
2315        return -ENOMEM;
2316    }
2317    if (((*uc_mgr)->card_ctxt_ptr->verb_list =
2318        (char **)malloc((verb_count+2)*(sizeof(char *)))) == NULL) {
2319        ALOGE("failed to allocate memory for verb list\n");
2320        munmap(read_buf, st.st_size);
2321        close(fd);
2322        return -ENOMEM;
2323    }
2324    verb_name = NULL;
2325    if ((ret = is_single_config_format(current_str))) {
2326        ALOGD("Single config file format detected\n");
2327        ret = parse_single_config_format(uc_mgr, current_str, verb_count);
2328        munmap(read_buf, st.st_size);
2329        close(fd);
2330        return ret;
2331    }
2332    while (*current_str != (char)EOF)  {
2333        next_str = strchr(current_str, '\n');
2334        if (!next_str)
2335            break;
2336        *next_str++ = '\0';
2337        if (verb_name == NULL) {
2338            buf = strstr(current_str, "SectionUseCase");
2339            if (buf == NULL) {
2340                if((current_str = next_str) == NULL)
2341                    break;
2342                else
2343                    continue;
2344            }
2345            verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
2346            p = strtok_r(buf, ".", &temp_ptr);
2347            while (p != NULL) {
2348                p = strtok_r(NULL, "\"", &temp_ptr);
2349                if (p == NULL)
2350                    break;
2351                verb_name = (char *)malloc((strlen(p)+1)*sizeof(char));
2352                if(verb_name == NULL) {
2353                    ret = -ENOMEM;
2354                    break;
2355                }
2356                strlcpy(verb_name, p, (strlen(p)+1)*sizeof(char));
2357                if ((verb_list[index].use_case_name =
2358                    (char *)malloc((strlen(verb_name)+1)*sizeof(char)))) {
2359                    strlcpy(verb_list[index].use_case_name,
2360                        verb_name, ((strlen(verb_name)+1)*sizeof(char)));
2361                } else {
2362                    ret = -ENOMEM;
2363                    break;
2364                }
2365                if (((*uc_mgr)->card_ctxt_ptr->verb_list[index] =
2366                    (char *)malloc((strlen(verb_name)+1)*sizeof(char)))) {
2367                    strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index],
2368                        verb_name, ((strlen(verb_name)+1)*sizeof(char)));
2369                } else {
2370                    ret = -ENOMEM;
2371                    break;
2372                }
2373                break;
2374            }
2375        } else {
2376            buf = strstr(current_str, "File");
2377            if (buf == NULL) {
2378                if((current_str = next_str) == NULL)
2379                    break;
2380                else
2381                    continue;
2382            }
2383            p = strtok_r(buf, "\"", &temp_ptr);
2384            while (p != NULL) {
2385                p = strtok_r(NULL, "\"", &temp_ptr);
2386                if (p == NULL)
2387                    break;
2388                file_name = (char *)malloc((strlen(p)+1)*sizeof(char));
2389                if(file_name == NULL) {
2390                    ret = -ENOMEM;
2391                    break;
2392                }
2393                strlcpy(file_name, p, (strlen(p)+1)*sizeof(char));
2394                break;
2395            }
2396            if (file_name != NULL) {
2397                ret = snd_ucm_parse_verb(uc_mgr, file_name, index);
2398                if (ret < 0)
2399                    ALOGE("Failed to parse config file %s\n", file_name);
2400                free(verb_name);
2401                verb_name = NULL;
2402                free(file_name);
2403                file_name = NULL;
2404            }
2405            index++;
2406            /* Break here so that only one first use case config file (HiFi)
2407             * from master config file is parsed initially and all other
2408             * config files are parsed in seperate thread created below so
2409             * that audio HAL can initialize faster during boot-up
2410             */
2411            break;
2412        }
2413        if((current_str = next_str) == NULL)
2414            break;
2415    }
2416    munmap(read_buf, st.st_size);
2417    close(fd);
2418    if (((*uc_mgr)->card_ctxt_ptr->verb_list[index] =
2419        (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)))) {
2420        strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index], SND_UCM_END_OF_LIST,
2421                ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
2422    } else {
2423        ALOGE("Failed to allocate memory\n");
2424        ret = -ENOMEM;
2425    }
2426    if (!ret) {
2427        ALOGD("Creating Parsing thread uc_mgr %p\n", uc_mgr);
2428        rc = pthread_create(&(*uc_mgr)->thr, 0, second_stage_parsing_thread,
2429                 (void*)(*uc_mgr));
2430        if(rc < 0) {
2431            ALOGE("Failed to create parsing thread rc %d errno %d\n", rc, errno);
2432        } else {
2433            ALOGV("Prasing thread created successfully\n");
2434        }
2435    }
2436    if (verb_name)
2437        free(verb_name);
2438    if (file_name)
2439        free(file_name);
2440    return ret;
2441}
2442
2443/* Parse a single config file format
2444 * uc_mgr - use case manager structure
2445 * buf - config file buffer to be parsed
2446 * Returns 0 on sucess, negative error code otherwise
2447 */
2448static int parse_single_config_format(snd_use_case_mgr_t **uc_mgr,
2449char *current_str, int num_verbs)
2450{
2451    struct stat st;
2452    card_mctrl_t *list;
2453    use_case_verb_t *verb_list;
2454    int verb_count = 0, device_count = 0, mod_count = 0, index = -1, ret = 0;
2455    char *next_str, *buf, *p, *verb_ptr, *temp_ptr;
2456
2457    verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
2458    while (*current_str != (char)EOF)  {
2459        next_str = strchr(current_str, '\n');
2460        if (!next_str)
2461            break;
2462        *next_str++ = '\0';
2463        if ((buf = strcasestr(current_str, "SectionUseCase")) != NULL) {
2464            if (index != -1) {
2465                list = (verb_list[index].verb_ctrls +
2466                            verb_list[index].verb_count);
2467                list->case_name = (char *)
2468                    malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2469                if(list->case_name == NULL) {
2470                    free(verb_list[index].verb_ctrls);
2471                    return -ENOMEM;
2472                }
2473                strlcpy(list->case_name, SND_UCM_END_OF_LIST,
2474                   (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2475                list->ena_mixer_list = NULL;
2476                list->dis_mixer_list = NULL;
2477                list->ena_mixer_count = 0;
2478                list->dis_mixer_count = 0;
2479                list->playback_dev_name = NULL;
2480                list->capture_dev_name = NULL;
2481                list->acdb_id = 0;
2482                list->capability = 0;
2483            }
2484            index++;
2485            p = strtok_r(buf, ".", &temp_ptr);
2486            while (p != NULL) {
2487                p = strtok_r(NULL, "\"", &temp_ptr);
2488                if (p == NULL)
2489                    break;
2490                if ((verb_list[index].use_case_name =
2491                    (char *)malloc((strlen(p)+1)*sizeof(char)))) {
2492                    strlcpy(verb_list[index].use_case_name,
2493                        p, ((strlen(p)+1)*sizeof(char)));
2494                } else {
2495                    ret = -ENOMEM;
2496                    break;
2497                }
2498                if (((*uc_mgr)->card_ctxt_ptr->verb_list[index] =
2499                    (char *)malloc((strlen(p)+1)*sizeof(char)))) {
2500                    strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index],
2501                       p, ((strlen(p)+1)*sizeof(char)));
2502                } else {
2503                    ret = -ENOMEM;
2504                    break;
2505                }
2506                break;
2507            }
2508            verb_list[index].verb_count = 0;
2509            verb_list[index].device_count = 0;
2510            verb_list[index].mod_count = 0;
2511            verb_list[index].device_list = NULL;
2512            verb_list[index].modifier_list = NULL;
2513            verb_list[index].verb_ctrls = NULL;
2514            verb_list[index].device_ctrls = NULL;
2515            verb_list[index].mod_ctrls = NULL;
2516            verb_count = get_num_verbs_config_format(next_str);
2517            verb_list[index].verb_ctrls = (card_mctrl_t *)
2518                malloc((verb_count+1)*sizeof(card_mctrl_t));
2519            if (verb_list[index].verb_ctrls == NULL) {
2520               ret = -ENOMEM;
2521               break;
2522            }
2523            verb_list[index].verb_count = 0;
2524        } else if (!strncasecmp(current_str, "SectionVerb", 11)) {
2525            ret = snd_ucm_parse_section(uc_mgr, &current_str,
2526                    &next_str, index, CTRL_LIST_VERB);
2527            if (ret < 0)
2528                break;
2529        } else if (!strncasecmp(current_str, "SectionDevice", 13)) {
2530            if (device_count == 0) {
2531                device_count = get_num_device_config_format(next_str);
2532                verb_list[0].device_ctrls = (card_mctrl_t *)
2533                    malloc((device_count+1)*sizeof(card_mctrl_t));
2534                if (verb_list[0].device_ctrls == NULL) {
2535                    ret = -ENOMEM;
2536                    break;
2537                }
2538                verb_list[0].device_list =
2539                    (char **)malloc((device_count+1)*sizeof(char *));
2540                if (verb_list[0].device_list == NULL)
2541                    return -ENOMEM;
2542                verb_list[0].device_count = 0;
2543            }
2544            ret = snd_ucm_parse_section(uc_mgr, &current_str,
2545                      &next_str, 0, CTRL_LIST_DEVICE);
2546            if (ret < 0) {
2547                break;
2548            } else {
2549                list = (verb_list[0].device_ctrls +
2550                           (verb_list[0].device_count - 1));
2551                verb_ptr = (char *)
2552                    malloc((strlen(list->case_name)+1)*sizeof(char));
2553                    if (verb_ptr == NULL) {
2554                        ret = -ENOMEM;
2555                        break;
2556                    }
2557                    strlcpy(verb_ptr, list->case_name,
2558                        ((strlen(list->case_name)+1)*sizeof(char)));
2559                    verb_list[0].device_list[(verb_list[0].device_count-1)]
2560                        = verb_ptr;
2561            }
2562        } else if (!strncasecmp(current_str, "SectionModifier", 15)) {
2563            if (mod_count == 0) {
2564                mod_count = get_num_mod_config_format(next_str);
2565                verb_list[0].mod_ctrls = (card_mctrl_t *)
2566                    malloc((mod_count+1)*sizeof(card_mctrl_t));
2567                if (verb_list[0].mod_ctrls == NULL) {
2568                    ret = -ENOMEM;
2569                    break;
2570                }
2571                verb_list[0].modifier_list =
2572                    (char **)malloc((mod_count+1)*sizeof(char *));
2573                if (verb_list[0].modifier_list == NULL)
2574                    return -ENOMEM;
2575                verb_list[0].mod_count = 0;
2576            }
2577            ret = snd_ucm_parse_section(uc_mgr, &current_str,
2578                     &next_str, 0, CTRL_LIST_MODIFIER);
2579            if (ret < 0) {
2580                break;
2581            } else {
2582                list = (verb_list[0].mod_ctrls +
2583                        (verb_list[0].mod_count - 1));
2584                verb_ptr = (char *)
2585                    malloc((strlen(list->case_name)+1)*sizeof(char));
2586                if (verb_ptr == NULL) {
2587                    ret = -ENOMEM;
2588                    break;
2589                }
2590                strlcpy(verb_ptr, list->case_name,
2591                   ((strlen(list->case_name)+1)*sizeof(char)));
2592                verb_list[0].modifier_list[(verb_list[0].mod_count - 1)]
2593                    = verb_ptr;
2594            }
2595        }
2596        if((current_str = next_str) == NULL)
2597            break;
2598    }
2599    list = (verb_list[index].verb_ctrls +
2600            verb_list[index].verb_count);
2601    list->case_name =
2602        (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2603    if(list->case_name == NULL) {
2604        free(verb_list[index].verb_ctrls);
2605        return -ENOMEM;
2606    }
2607    strlcpy(list->case_name, SND_UCM_END_OF_LIST,
2608        (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2609    list->ena_mixer_list = NULL;
2610    list->dis_mixer_list = NULL;
2611    list->ena_mixer_count = 0;
2612    list->dis_mixer_count = 0;
2613    list->playback_dev_name = NULL;
2614    list->capture_dev_name = NULL;
2615    list->acdb_id = 0;
2616    list->capability = 0;
2617    index++;
2618    if (index != -1) {
2619        if (((*uc_mgr)->card_ctxt_ptr->verb_list[index] =
2620            (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)))) {
2621            strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index],
2622                SND_UCM_END_OF_LIST,
2623                ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
2624        } else {
2625            ALOGE("Failed to allocate memory\n");
2626            ret = -ENOMEM;
2627        }
2628    }
2629    /* Add end of list to device list */
2630    verb_ptr =
2631       (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2632    if (verb_ptr == NULL)
2633        return -ENOMEM;
2634    strlcpy(verb_ptr, SND_UCM_END_OF_LIST,
2635        ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
2636    verb_list[0].device_list[verb_list[0].device_count] = verb_ptr;
2637    /* Add end of list to modifier list */
2638    verb_ptr =
2639    (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2640        if (verb_ptr == NULL)
2641            return -ENOMEM;
2642    strlcpy(verb_ptr, SND_UCM_END_OF_LIST,
2643        ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
2644    verb_list[0].modifier_list[verb_list[0].mod_count] = verb_ptr;
2645    /* Add end of list to device controls list */
2646    list = (verb_list[0].device_ctrls +
2647               verb_list[0].device_count);
2648    list->case_name =
2649        (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2650    if(list->case_name == NULL) {
2651        free(verb_list[0].device_ctrls);
2652        return -ENOMEM;
2653    }
2654    strlcpy(list->case_name, SND_UCM_END_OF_LIST,
2655        (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2656    list->ena_mixer_list = NULL;
2657    list->dis_mixer_list = NULL;
2658    list->ena_mixer_count = 0;
2659    list->dis_mixer_count = 0;
2660    list->playback_dev_name = NULL;
2661    list->capture_dev_name = NULL;
2662    list->acdb_id = 0;
2663    list->capability = 0;
2664    /* Add end of list to modifier controls list */
2665    list = (verb_list[0].mod_ctrls +
2666        verb_list[0].mod_count);
2667    list->case_name =
2668        (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2669    if(list->case_name == NULL) {
2670        free(verb_list[0].mod_ctrls);
2671        return -ENOMEM;
2672    }
2673    strlcpy(list->case_name, SND_UCM_END_OF_LIST,
2674        (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2675    list->ena_mixer_list = NULL;
2676    list->dis_mixer_list = NULL;
2677    list->ena_mixer_count = 0;
2678    list->dis_mixer_count = 0;
2679    list->playback_dev_name = NULL;
2680    list->capture_dev_name = NULL;
2681    list->acdb_id = 0;
2682    list->capability = 0;
2683    for (index = 1; index < num_verbs; index++) {
2684        verb_list[index].device_ctrls = verb_list[0].device_ctrls;
2685        verb_list[index].device_list = verb_list[0].device_list;
2686        verb_list[index].device_count = verb_list[0].device_count;
2687        verb_list[index].mod_ctrls = verb_list[0].mod_ctrls;
2688        verb_list[index].modifier_list = verb_list[0].modifier_list;
2689        verb_list[index].mod_count = verb_list[0].mod_count;
2690    }
2691    if (ret < 0) {
2692        ALOGE("Failed to parse config file ret %d errno %d\n", ret, errno);
2693    } else {
2694        ALOGV("Prasing done successfully\n");
2695#if PARSE_DEBUG
2696        /* Prints use cases and mixer controls parsed from config files */
2697        snd_ucm_print((*uc_mgr));
2698#endif
2699    }
2700    return ret;
2701}
2702
2703/* Returns number of verb sections for specific use case verb*/
2704static int get_num_verbs_config_format(const char *nxt_str)
2705{
2706    char *current_str, *next_str, *str_addr, *buf;
2707    int count = 0;
2708
2709    next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
2710    if (next_str == NULL) {
2711        ALOGE("Failed to allocate memory");
2712        return -ENOMEM;
2713    }
2714    strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
2715    str_addr = next_str;
2716    current_str = next_str;
2717    while(1) {
2718        next_str = strchr(current_str, '\n');
2719        if (!next_str)
2720            break;
2721        *next_str++ = '\0';
2722        buf = strcasestr(current_str, "SectionUseCase");
2723        if (buf != NULL)
2724            break;
2725        buf = strcasestr(current_str, "SectionVerb");
2726        if (buf != NULL)
2727            count++;
2728        if (*next_str == (char)EOF)
2729            break;
2730        if((current_str = next_str) == NULL)
2731            break;
2732    }
2733    free(str_addr);
2734    return count;
2735}
2736
2737/* Returns number of common device sections for all use case verbs*/
2738static int get_num_device_config_format(const char *nxt_str)
2739{
2740    char *current_str, *next_str, *str_addr, *buf;
2741    int count = 1;
2742
2743    next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
2744    if (next_str == NULL) {
2745        ALOGE("Failed to allocate memory");
2746        return -ENOMEM;
2747    }
2748    strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
2749    str_addr = next_str;
2750    current_str = next_str;
2751    while(1) {
2752        next_str = strchr(current_str, '\n');
2753        if (!next_str)
2754            break;
2755        *next_str++ = '\0';
2756        buf = strcasestr(current_str, "SectionDevice");
2757        if (buf != NULL)
2758            count++;
2759        if (*next_str == (char)EOF)
2760            break;
2761        if((current_str = next_str) == NULL)
2762            break;
2763    }
2764    free(str_addr);
2765    return count;
2766}
2767
2768/* Returns number of common modifier sections for all use case verbs*/
2769static int get_num_mod_config_format(const char *nxt_str)
2770{
2771    char *current_str, *next_str, *str_addr, *buf;
2772    int count = 1;
2773
2774    next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
2775    if (next_str == NULL) {
2776        ALOGE("Failed to allocate memory");
2777        return -ENOMEM;
2778    }
2779    strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
2780    str_addr = next_str;
2781    current_str = next_str;
2782    while(1) {
2783        next_str = strchr(current_str, '\n');
2784        if (!next_str)
2785            break;
2786        *next_str++ = '\0';
2787        buf = strcasestr(current_str, "SectionModifier");
2788        if (buf != NULL)
2789            count++;
2790        if (*next_str == (char)EOF)
2791            break;
2792        if((current_str = next_str) == NULL)
2793            break;
2794    }
2795    free(str_addr);
2796    return count;
2797}
2798
2799/* Gets the number of use case verbs defined by master config file */
2800static int get_verb_count(const char *nxt_str)
2801{
2802    char *current_str, *next_str, *str_addr, *buf, *p;
2803    int count = 0;
2804
2805    next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
2806    if (next_str == NULL) {
2807        ALOGE("Failed to allocate memory");
2808        return -ENOMEM;
2809    }
2810    strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
2811    str_addr = next_str;
2812    current_str = next_str;
2813    while(1) {
2814        next_str = strchr(current_str, '\n');
2815        if (!next_str)
2816            break;
2817        *next_str++ = '\0';
2818        buf = strstr(current_str, "SectionUseCase");
2819        if (buf != NULL)
2820            count++;
2821        if (*next_str == (char)EOF)
2822            break;
2823        if((current_str = next_str) == NULL)
2824            break;
2825    }
2826    free(str_addr);
2827    return count;
2828}
2829
2830/* Returns one if single config file per sound card format is being used */
2831static int is_single_config_format(const char *nxt_str)
2832{
2833    char *current_str, *next_str, *str_addr, *buf;
2834    int ret = 1, count = 0;
2835
2836    next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
2837    if (next_str == NULL) {
2838        ALOGE("Failed to allocate memory");
2839        return -ENOMEM;
2840    }
2841    strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
2842    str_addr = next_str;
2843    current_str = next_str;
2844    while(1) {
2845        next_str = strchr(current_str, '\n');
2846        if (!next_str)
2847            break;
2848        *next_str++ = '\0';
2849        buf = strstr(current_str, "SectionUseCase");
2850        if (buf != NULL)
2851            count++;
2852        buf = strstr(current_str, "File");
2853        if (buf != NULL)
2854            ret = 0;
2855        if ((*next_str == (char)EOF) || (count == 2))
2856            break;
2857        if((current_str = next_str) == NULL)
2858            break;
2859    }
2860    free(str_addr);
2861    return ret;
2862}
2863
2864/* Parse a use case verb config files and update mixer controls for the verb
2865 * uc_mgr - use case manager structure
2866 * file_name - use case verb config file name
2867 * index - index of the verb in the list
2868 * Returns 0 on sucess, negative error code otherwise
2869 */
2870static int snd_ucm_parse_verb(snd_use_case_mgr_t **uc_mgr,
2871const char *file_name, int index)
2872{
2873    struct stat st;
2874    card_mctrl_t *list;
2875    int device_count, modifier_count;
2876    int fd, ret = 0, parse_count = 0;
2877    char *read_buf, *next_str, *current_str, *verb_ptr;
2878    char path[200];
2879    use_case_verb_t *verb_list;
2880
2881    strlcpy(path, CONFIG_DIR, (strlen(CONFIG_DIR)+1));
2882    strlcat(path, file_name, sizeof(path));
2883    ALOGV("path:%s", path);
2884    verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
2885    while(1) {
2886        device_count = 0; modifier_count = 0;
2887        if (parse_count == 0) {
2888            verb_list[index].verb_count = 0;
2889            verb_list[index].device_count = 0;
2890            verb_list[index].mod_count = 0;
2891            verb_list[index].device_list = NULL;
2892            verb_list[index].modifier_list = NULL;
2893            verb_list[index].verb_ctrls = NULL;
2894            verb_list[index].device_ctrls = NULL;
2895            verb_list[index].mod_ctrls = NULL;
2896        }
2897        fd = open(path, O_RDONLY);
2898        if (fd < 0) {
2899             ALOGE("failed to open config file %s error %d\n", path, errno);
2900             return -EINVAL;
2901        }
2902        if (fstat(fd, &st) < 0) {
2903            ALOGE("failed to stat %s error %d\n", path, errno);
2904            close(fd);
2905            return -EINVAL;
2906        }
2907        read_buf = (char *) mmap(0, st.st_size, PROT_READ | PROT_WRITE,
2908                   MAP_PRIVATE, fd, 0);
2909        if (read_buf == MAP_FAILED) {
2910            ALOGE("failed to mmap file error %d\n", errno);
2911            close(fd);
2912            return -EINVAL;
2913        }
2914        current_str = read_buf;
2915        while (*current_str != (char)EOF)  {
2916            next_str = strchr(current_str, '\n');
2917            if (!next_str)
2918                break;
2919            *next_str++ = '\0';
2920            if (!strncasecmp(current_str, "SectionVerb", 11)) {
2921                if (parse_count == 0) {
2922                    verb_list[index].verb_count++;
2923                } else {
2924                    ret = snd_ucm_parse_section(uc_mgr, &current_str,
2925                              &next_str, index, CTRL_LIST_VERB);
2926                    if (ret < 0)
2927                        break;
2928                }
2929            } else if (!strncasecmp(current_str, "SectionDevice", 13)) {
2930                if (parse_count == 0) {
2931                    verb_list[index].device_count++;
2932                    device_count++;
2933                } else {
2934                    ret = snd_ucm_parse_section(uc_mgr, &current_str,
2935                              &next_str, index, CTRL_LIST_DEVICE);
2936                    if (ret < 0) {
2937                        break;
2938                    } else {
2939                        list = (verb_list[index].device_ctrls +
2940                                   (verb_list[index].device_count - 1));
2941                        verb_ptr = (char *)
2942                            malloc((strlen(list->case_name)+1)*sizeof(char));
2943                        if (verb_ptr == NULL) {
2944                            ret = -ENOMEM;
2945                            break;
2946                        }
2947                        strlcpy(verb_ptr, list->case_name,
2948                            ((strlen(list->case_name)+1)*sizeof(char)));
2949                        verb_list[index].device_list[device_count] = verb_ptr;
2950                        device_count++;
2951                    }
2952                }
2953            } else if (!strncasecmp(current_str, "SectionModifier", 15)) {
2954                if (parse_count == 0) {
2955                    verb_list[index].mod_count++;
2956                    modifier_count++;
2957                } else {
2958                    ret = snd_ucm_parse_section(uc_mgr, &current_str,
2959                              &next_str, index, CTRL_LIST_MODIFIER);
2960                    if (ret < 0) {
2961                        break;
2962                    } else {
2963                        list = (verb_list[index].mod_ctrls +
2964                               (verb_list[index].mod_count - 1));
2965                        verb_ptr = (char *)
2966                            malloc((strlen(list->case_name)+1)*sizeof(char));
2967                        if (verb_ptr == NULL) {
2968                            ret = -ENOMEM;
2969                            break;
2970                        }
2971                        strlcpy(verb_ptr, list->case_name,
2972                            ((strlen(list->case_name)+1)*sizeof(char)));
2973                        verb_list[index].modifier_list[modifier_count]
2974                            = verb_ptr;
2975                        modifier_count++;
2976                    }
2977                }
2978            }
2979            if((current_str = next_str) == NULL)
2980                break;
2981        }
2982        munmap(read_buf, st.st_size);
2983        close(fd);
2984        if(ret < 0)
2985            return ret;
2986        if (parse_count == 0) {
2987            verb_list[index].device_list =
2988                (char **)malloc((device_count+1)*sizeof(char *));
2989            if (verb_list[index].device_list == NULL)
2990                return -ENOMEM;
2991            verb_list[index].modifier_list =
2992                (char **)malloc((modifier_count+1)*sizeof(char *));
2993            if (verb_list[index].modifier_list == NULL)
2994                return -ENOMEM;
2995            parse_count += verb_list[index].verb_count;
2996            verb_list[index].verb_ctrls = (card_mctrl_t *)
2997                malloc((verb_list[index].verb_count+1)*sizeof(card_mctrl_t));
2998            if (verb_list[index].verb_ctrls == NULL) {
2999               ret = -ENOMEM;
3000               break;
3001            }
3002            verb_list[index].verb_count = 0;
3003            parse_count += verb_list[index].device_count;
3004            verb_list[index].device_ctrls = (card_mctrl_t *)
3005                malloc((verb_list[index].device_count+1)*sizeof(card_mctrl_t));
3006            if (verb_list[index].device_ctrls == NULL) {
3007               ret = -ENOMEM;
3008               break;
3009            }
3010            verb_list[index].device_count = 0;
3011            parse_count += verb_list[index].mod_count;
3012            verb_list[index].mod_ctrls = (card_mctrl_t *)
3013                malloc((verb_list[index].mod_count+1)*sizeof(card_mctrl_t));
3014            if (verb_list[index].mod_ctrls == NULL) {
3015               ret = -ENOMEM;
3016               break;
3017            }
3018            verb_list[index].mod_count = 0;
3019            continue;
3020        } else {
3021            verb_ptr =
3022            (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
3023            if (verb_ptr == NULL)
3024                return -ENOMEM;
3025            strlcpy(verb_ptr, SND_UCM_END_OF_LIST,
3026                ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
3027            verb_list[index].device_list[device_count] = verb_ptr;
3028            verb_ptr =
3029            (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
3030            if (verb_ptr == NULL)
3031                return -ENOMEM;
3032            strlcpy(verb_ptr, SND_UCM_END_OF_LIST,
3033                ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
3034            verb_list[index].modifier_list[modifier_count] = verb_ptr;
3035            list = (verb_list[index].verb_ctrls +
3036                       verb_list[index].verb_count);
3037            list->case_name =
3038                 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
3039            if(list->case_name == NULL) {
3040                free(verb_list[index].verb_ctrls);
3041                return -ENOMEM;
3042            }
3043            strlcpy(list->case_name, SND_UCM_END_OF_LIST,
3044               (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
3045            list->ena_mixer_list = NULL;
3046            list->dis_mixer_list = NULL;
3047            list->ena_mixer_count = 0;
3048            list->dis_mixer_count = 0;
3049            list->playback_dev_name = NULL;
3050            list->capture_dev_name = NULL;
3051            list->acdb_id = 0;
3052            list->capability = 0;
3053            list = (verb_list[index].device_ctrls +
3054                       verb_list[index].device_count);
3055            list->case_name =
3056                 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
3057            if(list->case_name == NULL) {
3058                free(verb_list[index].device_ctrls);
3059                return -ENOMEM;
3060            }
3061            strlcpy(list->case_name, SND_UCM_END_OF_LIST,
3062               (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
3063            list->ena_mixer_list = NULL;
3064            list->dis_mixer_list = NULL;
3065            list->ena_mixer_count = 0;
3066            list->dis_mixer_count = 0;
3067            list->playback_dev_name = NULL;
3068            list->capture_dev_name = NULL;
3069            list->acdb_id = 0;
3070            list->capability = 0;
3071            list = (verb_list[index].mod_ctrls +
3072                       verb_list[index].mod_count);
3073            list->case_name =
3074                 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
3075            if(list->case_name == NULL) {
3076                free(verb_list[index].mod_ctrls);
3077                return -ENOMEM;
3078            }
3079            strlcpy(list->case_name, SND_UCM_END_OF_LIST,
3080               (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
3081            list->ena_mixer_list = NULL;
3082            list->dis_mixer_list = NULL;
3083            list->ena_mixer_count = 0;
3084            list->dis_mixer_count = 0;
3085            list->playback_dev_name = NULL;
3086            list->capture_dev_name = NULL;
3087            list->acdb_id = 0;
3088            list->capability = 0;
3089            parse_count = 0;
3090            break;
3091        }
3092    }
3093    return ret;
3094}
3095
3096/* Print mixer controls in a specific list
3097 * list - list to be printed
3098 * verb_index - verb index
3099 * count - number of elements in the list
3100 * Returns 0 on sucess, negative error code otherwise
3101 */
3102static int print_list(card_mctrl_t *list, int verb_index, int count)
3103{
3104    int i, j;
3105
3106    for(i=0; i < count; i++) {
3107        ALOGD("\tcase name: %s\n", list[i].case_name);
3108        ALOGD("\tEnable sequence: %d\n", list[i].ena_mixer_count);
3109        for(j=0; j<list[i].ena_mixer_count; j++) {
3110            ALOGD("\t\t%s : %d : %d: %s\n",
3111                list[i].ena_mixer_list[j].control_name,
3112                list[i].ena_mixer_list[j].type,
3113                list[i].ena_mixer_list[j].value,
3114                list[i].ena_mixer_list[j].string);
3115        }
3116        ALOGD("\tDisable sequence: %d\n", list[i].dis_mixer_count);
3117        for(j=0; j<list[i].dis_mixer_count; j++) {
3118            ALOGD("\t\t%s : %d : %d : %s\n",
3119                list[i].dis_mixer_list[j].control_name,
3120                list[i].dis_mixer_list[j].type,
3121                list[i].dis_mixer_list[j].value,
3122                list[i].dis_mixer_list[j].string);
3123        }
3124    }
3125    return 0;
3126}
3127
3128/* Print mixer controls extracted from config files
3129 * uc_mgr - use case manager structure
3130 * Returns 0 on sucess, negative error code otherwise
3131 */
3132static int snd_ucm_print(snd_use_case_mgr_t *uc_mgr)
3133{
3134    card_mctrl_t *list;
3135    int i, j, verb_index = 0;
3136    use_case_verb_t *verb_list;
3137
3138    pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
3139    verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
3140    while(strncmp(uc_mgr->card_ctxt_ptr->verb_list[verb_index],
3141         SND_UCM_END_OF_LIST, 3)) {
3142        ALOGD("\nuse case verb: %s\n",
3143            uc_mgr->card_ctxt_ptr->verb_list[verb_index]);
3144        if(verb_list[verb_index].device_list) {
3145            ALOGD("\tValid device list:");
3146            i = 0;
3147            while(strncmp(verb_list[verb_index].device_list[i],
3148                  SND_UCM_END_OF_LIST, 3)) {
3149                ALOGD("\t\t%s", verb_list[verb_index].device_list[i]);
3150                i++;
3151            }
3152        }
3153        if(verb_list[verb_index].modifier_list) {
3154            ALOGD("\tValid modifier list:");
3155            i = 0;
3156            while(strncmp(verb_list[verb_index].modifier_list[i],
3157                  SND_UCM_END_OF_LIST, 3)) {
3158                ALOGD("\t\t%s", verb_list[verb_index].modifier_list[i]);
3159                i++;
3160            }
3161        }
3162        ALOGD("Verbs:\n");
3163        list = verb_list[verb_index].verb_ctrls;
3164        print_list(list, verb_index, verb_list[verb_index].verb_count);
3165        ALOGD("Devices:\n");
3166        list = verb_list[verb_index].device_ctrls;
3167        print_list(list, verb_index, verb_list[verb_index].device_count);
3168        ALOGD("Modifier:\n");
3169        list = verb_list[verb_index].mod_ctrls;
3170        print_list(list, verb_index, verb_list[verb_index].mod_count);
3171        verb_index++;
3172    }
3173    pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
3174    return 0;
3175}
3176
3177/* Gets the number of controls for specific sequence of a use cae */
3178static int get_controls_count(const char *nxt_str)
3179{
3180    char *current_str, *next_str, *str_addr;
3181    int count = 0;
3182
3183    next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
3184    if (next_str == NULL) {
3185        ALOGE("Failed to allocate memory");
3186        return -ENOMEM;
3187    }
3188    strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
3189    str_addr = next_str;
3190    while(1) {
3191        current_str = next_str;
3192        next_str = strchr(current_str, '\n');
3193        if ((!next_str) || (!strncasecmp(current_str, "EndSection", 10)))
3194            break;
3195        *next_str++ = '\0';
3196        if (strcasestr(current_str, "EndSequence") != NULL) {
3197            break;
3198        } else {
3199            count++;
3200        }
3201        if (*next_str == (char)EOF)
3202            break;
3203        if(!strncasecmp(current_str, "EndSection", 10))
3204            break;
3205    }
3206    free(str_addr);
3207    return count;
3208}
3209
3210/* Parse a section of config files
3211 * uc_mgr - use case manager structure
3212 * Returns 0 on sucess, negative error code otherwise
3213 */
3214static int snd_ucm_parse_section(snd_use_case_mgr_t **uc_mgr, char **cur_str,
3215char **nxt_str, int verb_index, int ctrl_list_type)
3216{
3217    use_case_verb_t *verb_list;
3218    card_mctrl_t *list;
3219    int enable_seq = 0, disable_seq = 0, controls_count = 0, ret = 0;
3220    char *p, *current_str, *next_str, *name;
3221
3222    verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
3223    if (ctrl_list_type == CTRL_LIST_VERB) {
3224        list = (verb_list[verb_index].verb_ctrls +
3225            verb_list[verb_index].verb_count);
3226    } else if (ctrl_list_type == CTRL_LIST_DEVICE) {
3227        list = (verb_list[verb_index].device_ctrls +
3228            verb_list[verb_index].device_count);
3229    } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
3230        list = (verb_list[verb_index].mod_ctrls +
3231            verb_list[verb_index].mod_count);
3232    } else {
3233        ALOGE("Invalid list type: %d\n", ctrl_list_type);
3234        return -EINVAL;
3235    }
3236    list->case_name = NULL;
3237    list->ena_mixer_list = NULL;
3238    list->dis_mixer_list = NULL;
3239    list->ena_mixer_count = 0;
3240    list->dis_mixer_count = 0;
3241    list->playback_dev_name = NULL;
3242    list->capture_dev_name = NULL;
3243    list->acdb_id = 0;
3244    list->capability = 0;
3245    list->effects_mixer_ctl = NULL;
3246    current_str = *cur_str; next_str = *nxt_str;
3247    while(strncasecmp(current_str, "EndSection", 10)) {
3248        current_str = next_str;
3249        next_str = strchr(current_str, '\n');
3250        if ((!next_str) || (!strncasecmp(current_str, "EndSection", 10)))
3251            break;
3252        *next_str++ = '\0';
3253        if (strcasestr(current_str, "EndSequence") != NULL) {
3254            if (enable_seq == 1)
3255                enable_seq = 0;
3256            else if (disable_seq == 1)
3257                disable_seq = 0;
3258            else
3259                ALOGE("Error: improper config file\n");
3260        }
3261        if (enable_seq == 1) {
3262            ret = snd_ucm_extract_controls(current_str, &list->ena_mixer_list,
3263                  list->ena_mixer_count);
3264            if (ret < 0)
3265                break;
3266            list->ena_mixer_count++;
3267        } else if (disable_seq == 1) {
3268            ret = snd_ucm_extract_controls(current_str, &list->dis_mixer_list,
3269                  list->dis_mixer_count);
3270            if (ret < 0)
3271                break;
3272            list->dis_mixer_count++;
3273        } else if (strcasestr(current_str, "Name") != NULL) {
3274            ret = snd_ucm_extract_name(current_str, &list->case_name);
3275            if (ret < 0)
3276                break;
3277            ALOGV("Name of section is %s\n", list->case_name);
3278        } else if (strcasestr(current_str, "PlaybackPCM") != NULL) {
3279            ret = snd_ucm_extract_dev_name(current_str,
3280                      &list->playback_dev_name);
3281            if (ret < 0)
3282                break;
3283            ALOGV("Device name of playback is %s\n",
3284                list->playback_dev_name);
3285        } else if (strcasestr(current_str, "CapturePCM") != NULL) {
3286            ret = snd_ucm_extract_dev_name(current_str,
3287                      &list->capture_dev_name);
3288            if (ret < 0)
3289                break;
3290            ALOGV("Device name of capture is %s\n", list->capture_dev_name);
3291        } else if (strcasestr(current_str, "ACDBID") != NULL) {
3292            ret = snd_ucm_extract_acdb(current_str, &list->acdb_id,
3293                      &list->capability);
3294            if (ret < 0)
3295                break;
3296            ALOGV("ACDB ID: %d CAPABILITY: %d\n", list->acdb_id,
3297                list->capability);
3298        } else if (strcasestr(current_str, "EffectsMixerCTL") != NULL) {
3299            ret = snd_ucm_extract_effects_mixer_ctl(current_str,
3300                      &list->effects_mixer_ctl);
3301            if (ret < 0)
3302                break;
3303            ALOGV("Effects mixer ctl: %s: %d\n", list->effects_mixer_ctl);
3304        }
3305        if (strcasestr(current_str, "EnableSequence") != NULL) {
3306            controls_count = get_controls_count(next_str);
3307            if (controls_count < 0) {
3308                ret = -ENOMEM;
3309                break;
3310            }
3311            list->ena_mixer_list =
3312            (mixer_control_t *)malloc((controls_count*sizeof(mixer_control_t)));
3313            if (list->ena_mixer_list == NULL) {
3314                ret = -ENOMEM;
3315                break;
3316            }
3317            enable_seq = 1;
3318        } else if (strcasestr(current_str, "DisableSequence") != NULL) {
3319            controls_count = get_controls_count(next_str);
3320            if (controls_count < 0) {
3321                ret = -ENOMEM;
3322                break;
3323            }
3324            list->dis_mixer_list =
3325            (mixer_control_t *)malloc((controls_count*sizeof(mixer_control_t)));
3326            if (list->dis_mixer_list == NULL) {
3327                ret = -ENOMEM;
3328                break;
3329            }
3330            disable_seq = 1;
3331        }
3332        if (*next_str == (char)EOF)
3333             break;
3334    }
3335    if(ret == 0) {
3336        *cur_str = current_str; *nxt_str = next_str;
3337        if (ctrl_list_type == CTRL_LIST_VERB) {
3338            verb_list[verb_index].verb_count++;
3339        } else if (ctrl_list_type == CTRL_LIST_DEVICE) {
3340            verb_list[verb_index].device_count++;
3341        } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
3342            verb_list[verb_index].mod_count++;
3343        }
3344    }
3345    return ret;
3346}
3347
3348/* Extract a mixer control name from config file
3349 * Returns 0 on sucess, negative error code otherwise
3350 */
3351static int snd_ucm_extract_name(char *buf, char **case_name)
3352{
3353    int ret = 0;
3354    char *p, *name = *case_name, *temp_ptr;
3355
3356    p = strtok_r(buf, "\"", &temp_ptr);
3357    while (p != NULL) {
3358        p = strtok_r(NULL, "\"", &temp_ptr);
3359        if (p == NULL)
3360            break;
3361        name = (char *)malloc((strlen(p)+1)*sizeof(char));
3362        if(name == NULL) {
3363            ret = -ENOMEM;
3364            break;
3365        }
3366        strlcpy(name, p, (strlen(p)+1)*sizeof(char));
3367        *case_name = name;
3368        break;
3369    }
3370    return ret;
3371}
3372
3373/* Extract a ACDB ID and capability of use case from config file
3374 * Returns 0 on sucess, negative error code otherwise
3375 */
3376static int snd_ucm_extract_acdb(char *buf, int *id, int *cap)
3377{
3378    char *p, key[] = "0123456789", *temp_ptr;
3379
3380    p = strpbrk(buf, key);
3381    if (p == NULL) {
3382        *id = 0;
3383        *cap = 0;
3384    } else {
3385        p = strtok_r(p, ":", &temp_ptr);
3386        while (p != NULL) {
3387            *id = atoi(p);
3388            p = strtok_r(NULL, "\0", &temp_ptr);
3389            if (p == NULL)
3390                break;
3391            *cap = atoi(p);
3392            break;
3393        }
3394    }
3395    return 0;
3396}
3397
3398/* Extract Effects Mixer ID of device from config file
3399 * Returns 0 on sucess, negative error code otherwise
3400 */
3401static int snd_ucm_extract_effects_mixer_ctl(char *buf, char **mixer_name)
3402{
3403    int ret = 0;
3404    char *p, *name = *mixer_name, *temp_ptr;
3405
3406    p = strtok_r(buf, "\"", &temp_ptr);
3407    while (p != NULL) {
3408        p = strtok_r(NULL, "\"", &temp_ptr);
3409        if (p == NULL)
3410            break;
3411        name = (char *)malloc((strlen(p)+1)*sizeof(char));
3412        if(name == NULL) {
3413            ret = -ENOMEM;
3414            break;
3415        }
3416        strlcpy(name, p, (strlen(p)+1)*sizeof(char));
3417        *mixer_name = name;
3418        break;
3419    }
3420    return ret;
3421}
3422
3423/* Extract a playback and capture device name of use case from config file
3424 * Returns 0 on sucess, negative error code otherwise
3425 */
3426static int snd_ucm_extract_dev_name(char *buf, char **dev_name)
3427{
3428    char key[] = "0123456789";
3429    char *p, *name = *dev_name;
3430    char dev_pre[] = "hw:0,";
3431    char *temp_ptr;
3432
3433    p = strpbrk(buf, key);
3434    if (p == NULL) {
3435        *dev_name = NULL;
3436    } else {
3437        p = strtok_r(p, "\r\n", &temp_ptr);
3438        if (p == NULL) {
3439            *dev_name = NULL;
3440        } else {
3441            name = (char *)malloc((strlen(p)+strlen(dev_pre)+1)*sizeof(char));
3442            if(name == NULL)
3443                 return -ENOMEM;
3444            strlcpy(name, dev_pre, (strlen(p)+strlen(dev_pre)+1)*sizeof(char));
3445            strlcat(name, p, (strlen(p)+strlen(dev_pre)+1)*sizeof(char));
3446            *dev_name = name;
3447        }
3448    }
3449    return 0;
3450}
3451
3452static int get_num_values(const char *buf)
3453{
3454    char *buf_addr, *p;
3455    int count = 0;
3456    char *temp_ptr;
3457
3458    buf_addr = (char *)malloc((strlen(buf)+1)*sizeof(char));
3459    if (buf_addr == NULL) {
3460        ALOGE("Failed to allocate memory");
3461        return -ENOMEM;
3462    }
3463    strlcpy(buf_addr, buf, ((strlen(buf)+1)*sizeof(char)));
3464    p = strtok_r(buf_addr, " ", &temp_ptr);
3465    while (p != NULL) {
3466        count++;
3467        p = strtok_r(NULL, " ", &temp_ptr);
3468        if (p == NULL)
3469            break;
3470    }
3471    free(buf_addr);
3472    return count;
3473}
3474
3475/* Extract a mixer control from config file
3476 * Returns 0 on sucess, negative error code otherwise
3477 */
3478static int snd_ucm_extract_controls(char *buf, mixer_control_t **mixer_list,
3479int size)
3480{
3481    unsigned long temp;
3482    int ret = -EINVAL, i, index = 0, count = 0;
3483    char *p, *ps, *pmv, temp_coeff[20];
3484    mixer_control_t *list;
3485    static const char *const seps = "\r\n";
3486    char *temp_ptr, *temp_vol_ptr;
3487
3488    p = strtok_r(buf, "'", &temp_ptr);
3489    while (p != NULL) {
3490        p = strtok_r(NULL, "'", &temp_ptr);
3491        if (p == NULL)
3492            break;
3493        list = ((*mixer_list)+size);
3494        list->control_name = (char *)malloc((strlen(p)+1)*sizeof(char));
3495        if(list->control_name == NULL) {
3496            ret = -ENOMEM;
3497            free((*mixer_list));
3498            break;
3499        }
3500        strlcpy(list->control_name, p, (strlen(p)+1)*sizeof(char));
3501        p = strtok_r(NULL, ":", &temp_ptr);
3502        if (p == NULL)
3503            break;
3504        if(!strncmp(p, "0", 1)) {
3505            list->type = TYPE_STR;
3506        } else if(!strncmp(p, "1", 1)) {
3507            list->type = TYPE_INT;
3508        } else if(!strncmp(p, "2", 1)) {
3509            list->type = TYPE_MULTI_VAL;
3510        } else {
3511            ALOGE("Unknown type: p %s\n", p);
3512        }
3513        p = strtok_r(NULL, seps, &temp_ptr);
3514        if (p == NULL)
3515            break;
3516        if(list->type == TYPE_INT) {
3517            list->value = atoi(p);
3518            list->string = NULL;
3519            list->mulval = NULL;
3520        } else if(list->type == TYPE_STR) {
3521            list->value = -1;
3522            list->string = (char *)malloc((strlen(p)+1)*sizeof(char));
3523            list->mulval = NULL;
3524            if(list->string == NULL) {
3525                ret = -ENOMEM;
3526                free((*mixer_list));
3527                free(list->control_name);
3528                break;
3529            }
3530            strlcpy(list->string, p, (strlen(p)+1)*sizeof(char));
3531        } else if(list->type == TYPE_MULTI_VAL) {
3532            if (p != NULL) {
3533                count = get_num_values(p);
3534                list->mulval = (char **)malloc(count*sizeof(char *));
3535                if (list->mulval == NULL) {
3536                    ret = -ENOMEM;
3537                    free((*mixer_list));
3538                    free(list->control_name);
3539                    break;
3540                }
3541                index = 0;
3542                /* To support volume values in percentage */
3543                if ((count == 1) && (strstr(p, "%") != NULL)) {
3544                    pmv = strtok_r(p, " ", &temp_vol_ptr);
3545                    while (pmv != NULL) {
3546                        list->mulval[index] =
3547                            (char *)malloc((strlen(pmv)+1)*sizeof(char));
3548                        strlcpy(list->mulval[index], pmv, (strlen(pmv)+1));
3549                        index++;
3550                        pmv = strtok_r(NULL, " ", &temp_vol_ptr);
3551                        if (pmv == NULL)
3552                            break;
3553                    }
3554                } else {
3555                    pmv = strtok_r(p, " ", &temp_vol_ptr);
3556                    while (pmv != NULL) {
3557                        temp = strtoul(pmv, &ps, 16);
3558                        snprintf(temp_coeff, sizeof(temp_coeff),"%lu", temp);
3559                        list->mulval[index] =
3560                            (char *)malloc((strlen(temp_coeff)+1)*sizeof(char));
3561                        strlcpy(list->mulval[index], temp_coeff,
3562                            (strlen(temp_coeff)+1));
3563                        index++;
3564                        pmv = strtok_r(NULL, " ", &temp_vol_ptr);
3565                        if (pmv == NULL)
3566                            break;
3567                    }
3568                }
3569                list->value = count;
3570                list->string = NULL;
3571            }
3572        } else {
3573            ALOGE("Unknown type: p %s\n", p);
3574            list->value = -1;
3575            list->string = NULL;
3576        }
3577        ret = 0;
3578        break;
3579    }
3580    return ret;
3581}
3582
3583void free_list(card_mctrl_t *list, int verb_index, int count)
3584{
3585    int case_index = 0, index = 0, mindex = 0;
3586
3587    for(case_index = 0; case_index < count; case_index++) {
3588        for(index = 0; index < list[case_index].ena_mixer_count; index++) {
3589            if(list[case_index].ena_mixer_list[index].control_name) {
3590                free(list[case_index].ena_mixer_list[index].control_name);
3591            }
3592            if(list[case_index].ena_mixer_list[index].string) {
3593                free(list[case_index].ena_mixer_list[index].string);
3594            }
3595            if(list[case_index].ena_mixer_list[index].mulval) {
3596                for(mindex = 0;
3597                    mindex < list[case_index].ena_mixer_list[index].value;
3598                    mindex++) {
3599                    free(list[case_index].ena_mixer_list[index].mulval[mindex]);
3600                }
3601                if(list[case_index].ena_mixer_list[index].mulval) {
3602                    free(list[case_index].ena_mixer_list[index].mulval);
3603                }
3604            }
3605        }
3606        for(index = 0; index < list[case_index].dis_mixer_count; index++) {
3607            if(list[case_index].dis_mixer_list[index].control_name) {
3608                free(list[case_index].dis_mixer_list[index].control_name);
3609            }
3610            if(list[case_index].dis_mixer_list[index].string) {
3611                free(list[case_index].dis_mixer_list[index].string);
3612            }
3613            if(list[case_index].dis_mixer_list[index].mulval) {
3614                for(mindex = 0;
3615                    mindex < list[case_index].dis_mixer_list[index].value;
3616                    mindex++) {
3617                    free(list[case_index].dis_mixer_list[index].mulval[mindex]);
3618                }
3619                if(list[case_index].dis_mixer_list[index].mulval) {
3620                    free(list[case_index].dis_mixer_list[index].mulval);
3621                }
3622            }
3623        }
3624        if(list[case_index].case_name) {
3625            free(list[case_index].case_name);
3626        }
3627        if(list[case_index].ena_mixer_list) {
3628            free(list[case_index].ena_mixer_list);
3629        }
3630        if(list[case_index].dis_mixer_list) {
3631            free(list[case_index].dis_mixer_list);
3632        }
3633        if(list[case_index].playback_dev_name) {
3634            free(list[case_index].playback_dev_name);
3635        }
3636        if(list[case_index].capture_dev_name) {
3637            free(list[case_index].capture_dev_name);
3638        }
3639        if(list[case_index].effects_mixer_ctl) {
3640            list[case_index].effects_mixer_ctl = NULL;
3641        }
3642    }
3643}
3644
3645void snd_ucm_free_mixer_list(snd_use_case_mgr_t **uc_mgr)
3646{
3647    card_mctrl_t *ctrl_list;
3648    use_case_verb_t *verb_list;
3649    int index = 0, verb_index = 0;
3650
3651    pthread_mutex_lock(&(*uc_mgr)->card_ctxt_ptr->card_lock);
3652    verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
3653    while(strncmp((*uc_mgr)->card_ctxt_ptr->verb_list[verb_index],
3654          SND_UCM_END_OF_LIST, 3)) {
3655        ctrl_list = verb_list[verb_index].verb_ctrls;
3656        free_list(ctrl_list, verb_index, verb_list[verb_index].verb_count);
3657        if(verb_list[verb_index].use_case_name)
3658            free(verb_list[verb_index].use_case_name);
3659        if((*uc_mgr)->card_ctxt_ptr->verb_list[verb_index]) {
3660            free((*uc_mgr)->card_ctxt_ptr->verb_list[verb_index]);
3661        }
3662        verb_index++;
3663    }
3664    verb_index -= 1;
3665    ctrl_list = verb_list[verb_index].device_ctrls;
3666    free_list(ctrl_list, verb_index, verb_list[verb_index].device_count);
3667    ctrl_list = verb_list[verb_index].mod_ctrls;
3668    free_list(ctrl_list, verb_index, verb_list[verb_index].mod_count);
3669    index = 0;
3670    while(1) {
3671        if (verb_list[verb_index].device_list[index]) {
3672            if (!strncmp(verb_list[verb_index].device_list[index],
3673                SND_UCM_END_OF_LIST, 3)) {
3674                free(verb_list[verb_index].device_list[index]);
3675                break;
3676            } else {
3677                free(verb_list[verb_index].device_list[index]);
3678                index++;
3679            }
3680        }
3681    }
3682    if (verb_list[verb_index].device_list)
3683        free(verb_list[verb_index].device_list);
3684    index = 0;
3685    while(1) {
3686        if (verb_list[verb_index].modifier_list[index]) {
3687            if (!strncmp(verb_list[verb_index].modifier_list[index],
3688                SND_UCM_END_OF_LIST, 3)) {
3689                free(verb_list[verb_index].modifier_list[index]);
3690                break;
3691            } else {
3692                free(verb_list[verb_index].modifier_list[index]);
3693                index++;
3694            }
3695        }
3696    }
3697    if (verb_list[verb_index].modifier_list)
3698        free(verb_list[verb_index].modifier_list);
3699    if((*uc_mgr)->card_ctxt_ptr->use_case_verb_list)
3700        free((*uc_mgr)->card_ctxt_ptr->use_case_verb_list);
3701    if((*uc_mgr)->card_ctxt_ptr->verb_list)
3702        free((*uc_mgr)->card_ctxt_ptr->verb_list);
3703    pthread_mutex_unlock(&(*uc_mgr)->card_ctxt_ptr->card_lock);
3704}
3705
3706/* Add an identifier to the respective list
3707 * head - list head
3708 * value - node value that needs to be added
3709 * Returns 0 on sucess, negative error code otherwise
3710 */
3711static int snd_ucm_add_ident_to_list(struct snd_ucm_ident_node **head,
3712const char *value)
3713{
3714    struct snd_ucm_ident_node *temp, *node;
3715
3716    node =
3717        (struct snd_ucm_ident_node *)malloc(sizeof(struct snd_ucm_ident_node));
3718    if (node == NULL) {
3719        ALOGE("Failed to allocate memory for new node");
3720        return -ENOMEM;
3721    } else {
3722        node->next = NULL;
3723        strlcpy(node->ident, value, MAX_STR_LEN);
3724        node->active = 0;
3725        node->capability = 0;
3726    }
3727    if (*head == NULL) {
3728        *head = node;
3729    } else {
3730        temp = *head;
3731        while (temp->next != NULL) {
3732            temp = temp->next;
3733        }
3734        temp->next = node;
3735    }
3736    ALOGV("add_to_list: head %p, value %s", *head, node->ident);
3737    return 0;
3738}
3739
3740/* Get the status of identifier at particulare index of the list
3741 * head - list head
3742 * ident - identifier value for which status needs to be get
3743 * status - status to be set (1 - active, 0 - inactive)
3744 */
3745static int snd_ucm_get_status_at_index(struct snd_ucm_ident_node *head,
3746const char *ident)
3747{
3748    while (head != NULL) {
3749        if(!strncmp(ident, head->ident, (strlen(head->ident)+1))) {
3750            break;
3751        }
3752        head = head->next;
3753    }
3754    if (head == NULL) {
3755        ALOGV("Element not found in the list");
3756    } else {
3757        return(head->active);
3758    }
3759    return -EINVAL;
3760}
3761
3762/* Get the node at particular index
3763 * head - list head
3764 * index - index value
3765 */
3766struct snd_ucm_ident_node *snd_ucm_get_device_node(struct snd_ucm_ident_node *head,
3767int index)
3768{
3769    if (head == NULL) {
3770        ALOGV("Empty list");
3771        return NULL;
3772    }
3773
3774    if ((index < 0) || (index >= (snd_ucm_get_size_of_list(head)))) {
3775        ALOGE("Element with given index %d doesn't exist in the list", index);
3776        return NULL;
3777    }
3778
3779    while (index) {
3780        head = head->next;
3781        index--;
3782    }
3783
3784    return head;
3785}
3786
3787/* Set the status of identifier at particulare index of the list
3788 * head - list head
3789 * ident - identifier value for which status needs to be set
3790 * status - status to be set (1 - active, 0 - inactive)
3791 */
3792static void snd_ucm_set_status_at_index(struct snd_ucm_ident_node *head,
3793const char *ident, int status, int capability)
3794{
3795    while (head != NULL) {
3796        if(!strncmp(ident, head->ident, (strlen(head->ident)+1))) {
3797            break;
3798        }
3799        head = head->next;
3800    }
3801    if (head == NULL) {
3802        ALOGE("Element not found to set the status");
3803    } else {
3804        head->active = status;
3805        head->capability = capability;
3806    }
3807}
3808
3809/* Get the identifier value at particulare index of the list
3810 * head - list head
3811 * index - node index value
3812 * Returns node idetifier value at index on sucess, NULL otherwise
3813 */
3814static char *snd_ucm_get_value_at_index(struct snd_ucm_ident_node *head,
3815int index)
3816{
3817    if (head == NULL) {
3818        ALOGV("Empty list");
3819        return NULL;
3820    }
3821
3822    if ((index < 0) || (index >= (snd_ucm_get_size_of_list(head)))) {
3823        ALOGE("Element with given index %d doesn't exist in the list", index);
3824        return NULL;
3825    }
3826
3827    while (index) {
3828        head = head->next;
3829        index--;
3830    }
3831
3832    return (strdup(head->ident));
3833}
3834
3835/* Get the size of the list
3836 * head - list head
3837 * Returns size of list on sucess, negative error code otherwise
3838 */
3839static int snd_ucm_get_size_of_list(struct snd_ucm_ident_node *head)
3840{
3841    int index = 0;
3842
3843    if (head == NULL) {
3844        ALOGV("Empty list");
3845        return 0;
3846    }
3847
3848    while (head->next != NULL) {
3849        index++;
3850        head = head->next;
3851    }
3852
3853    return (index+1);
3854}
3855
3856static void snd_ucm_print_list(struct snd_ucm_ident_node *head)
3857{
3858    int index = 0;
3859
3860    ALOGV("print_list: head %p", head);
3861    if (head == NULL) {
3862        ALOGV("Empty list");
3863        return;
3864    }
3865
3866    while (head->next != NULL) {
3867        ALOGV("index: %d, value: %s", index, head->ident);
3868        index++;
3869        head = head->next;
3870    }
3871    ALOGV("index: %d, value: %s", index, head->ident);
3872}
3873
3874/* Delete an identifier from respective list
3875 * head - list head
3876 * value - node value that needs to be deleted
3877 * Returns 0 on sucess, negative error code otherwise
3878 *
3879 */
3880static int snd_ucm_del_ident_from_list(struct snd_ucm_ident_node **head,
3881const char *value)
3882{
3883    struct snd_ucm_ident_node *temp1, *temp2;
3884    int ret = -EINVAL;
3885
3886    if (*head == NULL) {
3887        ALOGE("del_from_list: Empty list");
3888        return -EINVAL;
3889    } else if (!strncmp((*head)->ident, value, (strlen(value)+1))) {
3890            temp2 = *head;
3891            *head = temp2->next;
3892            ret = 0;
3893    } else {
3894        temp1 = *head;
3895        temp2 = temp1->next;
3896        while (temp2 != NULL) {
3897            if (!strncmp(temp2->ident, value, (strlen(value)+1))) {
3898                temp1->next = temp2->next;
3899                ret = 0;
3900                break;
3901            }
3902            temp1 = temp1->next;
3903            temp2 = temp1->next;
3904        }
3905    }
3906    if (ret < 0) {
3907        ALOGE("Element not found in enabled list");
3908    } else {
3909        temp2->next = NULL;
3910        temp2->ident[0] = 0;
3911        temp2->active = 0;
3912        temp2->capability = 0;
3913        free(temp2);
3914        temp2 = NULL;
3915    }
3916    return ret;
3917}
3918