• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
snd_use_case_identifier(const char * fmt,...)77 char *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  */
snd_use_case_free_list(const char * list[],int items)89 int 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  */
snd_use_case_get_list(snd_use_case_mgr_t * uc_mgr,const char * identifier,const char ** list[])105 int 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  */
snd_use_case_get(snd_use_case_mgr_t * uc_mgr,const char * identifier,const char ** value)263 int 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  */
snd_use_case_geti(snd_use_case_mgr_t * uc_mgr,const char * identifier,long * value)463 int 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 
check_devices_for_voice_call(snd_use_case_mgr_t * uc_mgr,const char * use_case)538 static int check_devices_for_voice_call(snd_use_case_mgr_t *uc_mgr,
539 const 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 
snd_use_case_apply_voice_acdb(snd_use_case_mgr_t * uc_mgr,int use_case_index)578 static int snd_use_case_apply_voice_acdb(snd_use_case_mgr_t *uc_mgr,
579 int 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 
get_use_case_index(snd_use_case_mgr_t * uc_mgr,const char * use_case,int ctrl_list_type)702 int get_use_case_index(snd_use_case_mgr_t *uc_mgr, const char *use_case,
703 int 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  */
snd_use_case_apply_mixer_controls(snd_use_case_mgr_t * uc_mgr,const char * use_case,int enable,int ctrl_list_type,int uc_index)755 int snd_use_case_apply_mixer_controls(snd_use_case_mgr_t *uc_mgr,
756 const 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 
getUseCaseType(const char * useCase)877 int 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  */
set_controls_of_usecase_for_all_devices(snd_use_case_mgr_t * uc_mgr,const char * ident,int enable,int ctrl_list_type)957 static int set_controls_of_usecase_for_all_devices(snd_use_case_mgr_t *uc_mgr,
958 const 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  */
set_controls_of_usecase_for_device(snd_use_case_mgr_t * uc_mgr,const char * ident,const char * device,int enable,int ctrl_list_type)1051 static int set_controls_of_usecase_for_device(snd_use_case_mgr_t *uc_mgr,
1052 const 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  */
set_controls_of_device_for_all_usecases(snd_use_case_mgr_t * uc_mgr,const char * device,int enable)1111 static int set_controls_of_device_for_all_usecases(snd_use_case_mgr_t *uc_mgr,
1112 const 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  */
get_usecase_type(snd_use_case_mgr_t * uc_mgr,const char * usecase)1282 static 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  */
set_controls_of_device_for_usecase(snd_use_case_mgr_t * uc_mgr,const char * device,const char * usecase,int enable)1308 static 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  */
snd_use_case_set(snd_use_case_mgr_t * uc_mgr,const char * identifier,const char * value)1380 int 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  */
snd_use_case_set_case(snd_use_case_mgr_t * uc_mgr,const char * identifier,const char * value,const char * usecase)1605 int 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  */
snd_use_case_mgr_open(snd_use_case_mgr_t ** uc_mgr,const char * card_name)1880 int 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  */
snd_use_case_mgr_reload(snd_use_case_mgr_t * uc_mgr)1986 int 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  */
snd_use_case_mgr_close(snd_use_case_mgr_t * uc_mgr)1996 int 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  */
snd_use_case_mgr_reset(snd_use_case_mgr_t * uc_mgr)2035 int 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 */
second_stage_parsing_thread(void * uc_mgr_ptr)2118 void *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 */
snd_use_case_mgr_wait_for_parsing(snd_use_case_mgr_t * uc_mgr)2265 int 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  */
snd_ucm_parse(snd_use_case_mgr_t ** uc_mgr)2278 static 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  */
parse_single_config_format(snd_use_case_mgr_t ** uc_mgr,char * current_str,int num_verbs)2448 static int parse_single_config_format(snd_use_case_mgr_t **uc_mgr,
2449 char *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*/
get_num_verbs_config_format(const char * nxt_str)2704 static 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*/
get_num_device_config_format(const char * nxt_str)2738 static 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*/
get_num_mod_config_format(const char * nxt_str)2769 static 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 */
get_verb_count(const char * nxt_str)2800 static 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 */
is_single_config_format(const char * nxt_str)2831 static 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  */
snd_ucm_parse_verb(snd_use_case_mgr_t ** uc_mgr,const char * file_name,int index)2870 static int snd_ucm_parse_verb(snd_use_case_mgr_t **uc_mgr,
2871 const 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  */
print_list(card_mctrl_t * list,int verb_index,int count)3102 static 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  */
snd_ucm_print(snd_use_case_mgr_t * uc_mgr)3132 static 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 */
get_controls_count(const char * nxt_str)3178 static 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  */
snd_ucm_parse_section(snd_use_case_mgr_t ** uc_mgr,char ** cur_str,char ** nxt_str,int verb_index,int ctrl_list_type)3214 static int snd_ucm_parse_section(snd_use_case_mgr_t **uc_mgr, char **cur_str,
3215 char **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  */
snd_ucm_extract_name(char * buf,char ** case_name)3351 static 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  */
snd_ucm_extract_acdb(char * buf,int * id,int * cap)3376 static 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  */
snd_ucm_extract_effects_mixer_ctl(char * buf,char ** mixer_name)3401 static 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  */
snd_ucm_extract_dev_name(char * buf,char ** dev_name)3426 static 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 
get_num_values(const char * buf)3452 static 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  */
snd_ucm_extract_controls(char * buf,mixer_control_t ** mixer_list,int size)3478 static int snd_ucm_extract_controls(char *buf, mixer_control_t **mixer_list,
3479 int 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 
free_list(card_mctrl_t * list,int verb_index,int count)3583 void 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 
snd_ucm_free_mixer_list(snd_use_case_mgr_t ** uc_mgr)3645 void 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  */
snd_ucm_add_ident_to_list(struct snd_ucm_ident_node ** head,const char * value)3711 static int snd_ucm_add_ident_to_list(struct snd_ucm_ident_node **head,
3712 const 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  */
snd_ucm_get_status_at_index(struct snd_ucm_ident_node * head,const char * ident)3745 static int snd_ucm_get_status_at_index(struct snd_ucm_ident_node *head,
3746 const 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  */
snd_ucm_get_device_node(struct snd_ucm_ident_node * head,int index)3766 struct snd_ucm_ident_node *snd_ucm_get_device_node(struct snd_ucm_ident_node *head,
3767 int 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  */
snd_ucm_set_status_at_index(struct snd_ucm_ident_node * head,const char * ident,int status,int capability)3792 static void snd_ucm_set_status_at_index(struct snd_ucm_ident_node *head,
3793 const 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  */
snd_ucm_get_value_at_index(struct snd_ucm_ident_node * head,int index)3814 static char *snd_ucm_get_value_at_index(struct snd_ucm_ident_node *head,
3815 int 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  */
snd_ucm_get_size_of_list(struct snd_ucm_ident_node * head)3839 static 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 
snd_ucm_print_list(struct snd_ucm_ident_node * head)3856 static 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  */
snd_ucm_del_ident_from_list(struct snd_ucm_ident_node ** head,const char * value)3880 static int snd_ucm_del_ident_from_list(struct snd_ucm_ident_node **head,
3881 const 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