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