blob: 72ce6c65d94fe524d0fe610bddc7b8a241554ae5 [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;
201 if (list_size > 0) {
202 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;
231 if (list_size > 0) {
232 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 {
Ajay Dudani86c852b2012-07-19 15:28:45 -0700756#if LOCAL_LOGD
Iliyan Malchev4765c432012-06-11 14:36:16 -0700757 ALOGD("Set mixer controls for %s enable %d", use_case, enable);
Ajay Dudani86c852b2012-07-19 15:28:45 -0700758#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700759 if (ctrl_list[uc_index].acdb_id && ctrl_list[uc_index].capability) {
760 if (enable) {
761 if (snd_use_case_apply_voice_acdb(uc_mgr, uc_index)) {
Ajay Dudani86c852b2012-07-19 15:28:45 -0700762#if LOCAL_LOGD
Iliyan Malchev4765c432012-06-11 14:36:16 -0700763 ALOGD("acdb_id %d cap %d enable %d",
764 ctrl_list[uc_index].acdb_id,
765 ctrl_list[uc_index].capability, enable);
Ajay Dudani86c852b2012-07-19 15:28:45 -0700766#endif
SathishKumar Mani5ff7a022012-09-14 11:36:35 -0700767 if (uc_mgr->acdb_handle) {
768 acdb_send_audio_cal = dlsym(uc_mgr->acdb_handle,"acdb_loader_send_audio_cal");
769 if (acdb_send_audio_cal == NULL) {
770 ALOGE("ucm:dlsym:Error:%s Loading acdb_loader_send_audio_cal", dlerror());
771 } else {
772 acdb_send_audio_cal(ctrl_list[uc_index].acdb_id,
773 ctrl_list[uc_index].capability);
774 }
775 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700776 }
777 }
778 }
779 if (enable) {
780 mixer_list = ctrl_list[uc_index].ena_mixer_list;
781 mixer_count = ctrl_list[uc_index].ena_mixer_count;
782 } else {
783 mixer_list = ctrl_list[uc_index].dis_mixer_list;
784 mixer_count = ctrl_list[uc_index].dis_mixer_count;
785 }
786 for(index = 0; index < mixer_count; index++) {
787 if (mixer_list == NULL) {
788 ALOGE("No valid controls exist for this case: %s", use_case);
789 break;
790 }
791 ctl = mixer_get_control(uc_mgr->card_ctxt_ptr->mixer_handle,
792 mixer_list[index].control_name, 0);
793 if (ctl) {
794 if (mixer_list[index].type == TYPE_INT) {
Ajay Dudani86c852b2012-07-19 15:28:45 -0700795#if LOCAL_LOGD
Iliyan Malchev4765c432012-06-11 14:36:16 -0700796 ALOGD("Setting mixer control: %s, value: %d",
797 mixer_list[index].control_name,
798 mixer_list[index].value);
Ajay Dudani86c852b2012-07-19 15:28:45 -0700799#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700800 ret = mixer_ctl_set(ctl, mixer_list[index].value);
801 } else if (mixer_list[index].type == TYPE_MULTI_VAL) {
802 ALOGD("Setting multi value: %s",
803 mixer_list[index].control_name);
804 ret = mixer_ctl_set_value(ctl, mixer_list[index].value,
805 mixer_list[index].mulval);
806 if (ret < 0)
807 ALOGE("Failed to set multi value control %s\n",
808 mixer_list[index].control_name);
809 } else {
Ajay Dudani86c852b2012-07-19 15:28:45 -0700810#if LOCAL_LOGD
Iliyan Malchev4765c432012-06-11 14:36:16 -0700811 ALOGD("Setting mixer control: %s, value: %s",
812 mixer_list[index].control_name,
813 mixer_list[index].string);
Ajay Dudani86c852b2012-07-19 15:28:45 -0700814#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700815 ret = mixer_ctl_select(ctl, mixer_list[index].string);
816 }
817 if ((ret != 0) && enable) {
818 /* Disable all the mixer controls which are
819 * already enabled before failure */
820 mixer_list = ctrl_list[uc_index].dis_mixer_list;
821 mixer_count = ctrl_list[uc_index].dis_mixer_count;
822 for(i = 0; i < mixer_count; i++) {
823 ctl = mixer_get_control(
824 uc_mgr->card_ctxt_ptr->mixer_handle,
825 mixer_list[i].control_name, 0);
826 if (ctl) {
827 if (mixer_list[i].type == TYPE_INT) {
828 ret = mixer_ctl_set(ctl,
829 mixer_list[i].value);
830 } else {
831 ret = mixer_ctl_select(ctl,
832 mixer_list[i].string);
833 }
834 }
835 }
836 ALOGE("Failed to enable the mixer controls for %s",
837 use_case);
838 break;
839 }
840 }
841 }
842 }
843 }
844 return ret;
845}
846
847int getUseCaseType(const char *useCase)
848{
849 ALOGV("getUseCaseType: use case is %s\n", useCase);
850 if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI,
851 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI)) ||
SathishKumar Manid1c97002012-08-13 18:37:37 -0700852 !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
853 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -0700854 !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
855 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
856 !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
857 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
858 !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
859 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI2)) ||
860 !strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO,
861 MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
862 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
863 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC)) ||
SathishKumar Manid1c97002012-08-13 18:37:37 -0700864 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
865 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -0700866 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
867 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
868 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA,
869 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LPA)) ||
870 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
871 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
872 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM,
873 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))) {
874 return CAP_RX;
875 } else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC,
876 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC)) ||
877 !strncmp(useCase, SND_USE_CASE_VERB_FM_REC,
878 MAX_LEN(useCase,SND_USE_CASE_VERB_FM_REC)) ||
879 !strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC,
880 MAX_LEN(useCase,SND_USE_CASE_VERB_FM_A2DP_REC)) ||
881 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC,
882 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC)) ||
SathishKumar Manid1c97002012-08-13 18:37:37 -0700883 !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC,
884 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) ||
885 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC,
886 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -0700887 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM,
888 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_FM)) ||
889 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM,
890 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_A2DP_FM))) {
891 return CAP_TX;
892 } else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL,
893 MAX_LEN(useCase,SND_USE_CASE_VERB_VOICECALL)) ||
894 !strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL,
895 MAX_LEN(useCase,SND_USE_CASE_VERB_IP_VOICECALL)) ||
896 !strncmp(useCase, SND_USE_CASE_VERB_DL_REC,
897 MAX_LEN(useCase,SND_USE_CASE_VERB_DL_REC)) ||
898 !strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC,
899 MAX_LEN(useCase,SND_USE_CASE_VERB_UL_DL_REC)) ||
900 !strncmp(useCase, SND_USE_CASE_VERB_INCALL_REC,
901 MAX_LEN(useCase,SND_USE_CASE_VERB_INCALL_REC)) ||
902 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE,
903 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE)) ||
904 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP,
905 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
906 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
907 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) ||
908 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
909 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) ||
910 !strncmp(useCase, SND_USE_CASE_VERB_VOLTE,
911 MAX_LEN(useCase,SND_USE_CASE_VERB_VOLTE)) ||
912 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
913 MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_VOLTE))) {
914 return CAP_VOICE;
915 } else {
916 ALOGE("unknown use case %s, returning voice capablity", useCase);
917 return CAP_VOICE;
918 }
919}
920
921/* Set/Reset mixer controls of specific use case for all current devices
922 * uc_mgr - UCM structure pointer
923 * ident - use case name (verb or modifier)
924 * enable - 1 for enable and 0 for disable
925 * return 0 on sucess, otherwise a negative error code
926 */
927static int set_controls_of_usecase_for_all_devices(snd_use_case_mgr_t *uc_mgr,
928const char *ident, int enable, int ctrl_list_type)
929{
930 card_mctrl_t *dev_list, *uc_list;
931 char *current_device, use_case[MAX_UC_LEN];
932 int list_size, index, uc_index, ret = 0, intdev_flag = 0;
933 int verb_index, capability = 0, ident_cap = 0;
934
935 ALOGV("set_use_case_ident_for_all_devices(): %s", ident);
936 if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
937 verb_index = 0;
938 dev_list =
939 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
940 if (ctrl_list_type == CTRL_LIST_VERB) {
941 uc_list =
942 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls;
943 } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
944 uc_list =
945 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].mod_ctrls;
946 } else {
947 uc_list = NULL;
948 }
949 ident_cap = getUseCaseType(ident);
950 list_size = snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
951 for (index = 0; index < list_size; index++) {
952 current_device =
953 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head, index);
954 if (current_device != NULL) {
955 uc_index = get_use_case_index(uc_mgr, current_device,
956 CTRL_LIST_DEVICE);
957 if (!capability) {
958 capability = dev_list[uc_index].capability;
959 } else if (capability != dev_list[uc_index].capability) {
960 capability = CAP_VOICE;
961 }
962 if (enable) {
963 if (!snd_ucm_get_status_at_index(
964 uc_mgr->card_ctxt_ptr->dev_list_head, current_device)) {
965 if (uc_index >= 0) {
966 ALOGV("Applying mixer controls for device: %s",
967 current_device);
968 ret = snd_use_case_apply_mixer_controls(uc_mgr,
969 current_device, enable, CTRL_LIST_DEVICE, uc_index);
970 if (!ret)
971 snd_ucm_set_status_at_index(
972 uc_mgr->card_ctxt_ptr->dev_list_head,
973 current_device, enable);
974 }
975 } else if (ident_cap == CAP_VOICE) {
976 snd_use_case_apply_voice_acdb(uc_mgr, uc_index);
977 }
978 }
979 strlcpy(use_case, ident, sizeof(use_case));
980 strlcat(use_case, current_device, sizeof(use_case));
981 ALOGV("Applying mixer controls for use case: %s", use_case);
982 if ((uc_index =
983 get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
984 ALOGV("No valid use case found: %s", use_case);
985 intdev_flag++;
986 } else {
987 if (capability == CAP_VOICE || ident_cap == CAP_VOICE ||
988 capability == ident_cap) {
989 ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
990 enable, ctrl_list_type, uc_index);
991 }
992 }
993 use_case[0] = 0;
994 free(current_device);
995 }
996 }
997 if (intdev_flag) {
998 if ((uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type)) < 0) {
999 ALOGE("use case %s not valid without device combination", ident);
1000 } else {
1001 if (capability == CAP_VOICE || capability == ident_cap ||
1002 ident_cap == CAP_VOICE) {
1003 snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
1004 ctrl_list_type, uc_index);
1005 }
1006 }
1007 }
1008 return ret;
1009}
1010
1011/* Set/Reset mixer controls of specific use case for a specific device
1012 * uc_mgr - UCM structure pointer
1013 * ident - use case name (verb or modifier)
1014 * device - device for which use case needs to be set/reset
1015 * enable - 1 for enable and 0 for disable
1016 * return 0 on sucess, otherwise a negative error code
1017 */
1018static int set_controls_of_usecase_for_device(snd_use_case_mgr_t *uc_mgr,
1019const char *ident, const char *device, int enable, int ctrl_list_type)
1020{
1021 char use_case[MAX_UC_LEN];
1022 int list_size, index, dev_index, uc_index, ret = 0;
1023
1024 ALOGV("set_use_case_ident_for_device(): use case %s device %s", ident,
1025 device);
1026 if (device != NULL) {
1027 if (enable) {
1028 dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
1029 if (!snd_ucm_get_status_at_index(
1030 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1031 ret = snd_use_case_apply_mixer_controls(uc_mgr, device,
1032 enable, CTRL_LIST_DEVICE, dev_index);
1033 if (!ret)
1034 snd_ucm_set_status_at_index(
1035 uc_mgr->card_ctxt_ptr->dev_list_head, device, enable);
1036 }
1037 }
1038 strlcpy(use_case, ident, sizeof(use_case));
1039 strlcat(use_case, device, sizeof(use_case));
1040 ALOGV("Applying mixer controls for use case: %s", use_case);
1041 if ((uc_index = get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
1042 ALOGV("No valid use case found: %s", use_case );
1043 uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type);
1044 if (snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
1045 ctrl_list_type, uc_index) < 0) {
1046 ALOGV("use case %s not valid without device combination also",
1047 ident);
1048 }
1049 } else {
1050 ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case, enable,
1051 ctrl_list_type, uc_index);
1052 }
1053 } else {
1054 uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type);
1055 if (snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
1056 ctrl_list_type, uc_index) < 0) {
1057 ALOGV("use case %s not valid without device combination also",
1058 ident);
1059 }
1060 }
1061 return ret;
1062}
1063
1064/* Set/Reset mixer controls of specific device for all use cases
1065 * uc_mgr - UCM structure pointer
1066 * device - device name
1067 * enable - 1 for enable and 0 for disable
1068 * return 0 on sucess, otherwise a negative error code
1069 */
1070static int set_controls_of_device_for_all_usecases(snd_use_case_mgr_t *uc_mgr,
1071const char *device, int enable)
1072{
1073 card_mctrl_t *dev_list, *uc_list;
1074 char *ident_value, use_case[MAX_UC_LEN];
1075 int verb_index, uc_index, dev_index, capability = 0;
1076 int list_size, index = 0, ret = -ENODEV, flag = 0, intdev_flag = 0;
1077
1078 ALOGV("set_controls_of_device_for_all_usecases: %s", device);
1079 if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
1080 verb_index = 0;
1081 dev_list =
1082 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
1083 dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
ty.lee94de74c2012-09-03 17:03:12 +09001084 if (dev_index >= 0)
1085 capability = dev_list[dev_index].capability;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001086 if (strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_USE_CASE_VERB_INACTIVE,
1087 strlen(SND_USE_CASE_VERB_INACTIVE))) {
1088 uc_list =
1089 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls;
1090 strlcpy(use_case, uc_mgr->card_ctxt_ptr->current_verb,
1091 sizeof(use_case));
1092 strlcat(use_case, device, sizeof(use_case));
1093 if ((uc_index =
1094 get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB)) < 0) {
1095 ALOGV("No valid use case found: %s", use_case);
1096 intdev_flag = 1;
1097 } else {
1098 if (enable) {
1099 if (!snd_ucm_get_status_at_index(
1100 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1101 ret = snd_use_case_apply_mixer_controls(uc_mgr, device,
1102 enable, CTRL_LIST_DEVICE, dev_index);
1103 if (!ret)
1104 snd_ucm_set_status_at_index(
1105 uc_mgr->card_ctxt_ptr->dev_list_head, device, enable);
1106 flag = 1;
1107 }
1108 }
1109 if (capability == CAP_VOICE ||
1110 capability ==
1111 getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ||
1112 getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ==
1113 CAP_VOICE) {
1114 ALOGV("set %d for use case value: %s", enable, use_case);
1115 ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
1116 enable, CTRL_LIST_VERB, uc_index);
1117 if (ret != 0)
1118 ALOGE("No valid controls exists for usecase %s and device \
1119 %s, enable: %d", use_case, device, enable);
1120 }
1121 }
1122 if (intdev_flag) {
1123 if (enable && !flag) {
1124 if (!snd_ucm_get_status_at_index(
1125 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1126 ret = snd_use_case_apply_mixer_controls(uc_mgr,
1127 device, enable, CTRL_LIST_DEVICE, dev_index);
1128 if (!ret)
1129 snd_ucm_set_status_at_index(
1130 uc_mgr->card_ctxt_ptr->dev_list_head, device, enable);
1131 flag = 1;
1132 }
1133 }
1134 use_case[0] = 0;
1135 strlcpy(use_case, uc_mgr->card_ctxt_ptr->current_verb,
1136 sizeof(use_case));
1137 uc_index = get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB);
1138 if (capability == CAP_VOICE ||
1139 capability ==
1140 getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ||
1141 getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ==
1142 CAP_VOICE) {
1143 ALOGV("set %d for use case value: %s", enable, use_case);
1144 ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
1145 enable, CTRL_LIST_VERB, uc_index);
1146 if (ret != 0)
1147 ALOGE("No valid controls exists for usecase %s and \
1148 device %s, enable: %d", use_case, device, enable);
1149 }
1150 intdev_flag = 0;
1151 }
1152 use_case[0] = 0;
1153 }
1154 snd_ucm_print_list(uc_mgr->card_ctxt_ptr->mod_list_head);
1155 uc_list =
1156 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].mod_ctrls;
1157 list_size = snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
1158 for (index = 0; index < list_size; index++) {
1159 if ((ident_value =
1160 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
1161 index))) {
1162 strlcpy(use_case, ident_value, sizeof(use_case));
1163 strlcat(use_case, device, sizeof(use_case));
1164 if ((uc_index = get_use_case_index(uc_mgr, use_case,
1165 CTRL_LIST_MODIFIER)) < 0) {
1166 ALOGV("No valid use case found: %s", use_case);
1167 intdev_flag = 1;
1168 } else {
1169 if (enable && !flag) {
1170 if (!snd_ucm_get_status_at_index(
1171 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1172 ret = snd_use_case_apply_mixer_controls(uc_mgr,
1173 device, enable, CTRL_LIST_DEVICE, dev_index);
1174 if (!ret)
1175 snd_ucm_set_status_at_index(
1176 uc_mgr->card_ctxt_ptr->dev_list_head,
1177 device, enable);
1178 flag = 1;
1179 }
1180 }
1181 if (capability == CAP_VOICE ||
1182 getUseCaseType(ident_value) == CAP_VOICE ||
1183 capability == getUseCaseType(ident_value)) {
1184 ALOGV("set %d for use case value: %s", enable, use_case);
1185 ret = snd_use_case_apply_mixer_controls(uc_mgr,
1186 use_case, enable, CTRL_LIST_MODIFIER, uc_index);
1187 if (ret != 0)
1188 ALOGE("No valid controls exists for usecase %s and \
1189 device %s, enable: %d", use_case, device, enable);
1190 }
1191 }
1192 if (intdev_flag) {
1193 if (enable && !flag) {
1194 if (!snd_ucm_get_status_at_index(
1195 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1196 ret = snd_use_case_apply_mixer_controls(uc_mgr,
1197 device, enable, CTRL_LIST_DEVICE, dev_index);
1198 if (!ret)
1199 snd_ucm_set_status_at_index(
1200 uc_mgr->card_ctxt_ptr->dev_list_head, device,
1201 enable);
1202 flag = 1;
1203 }
1204 }
1205 use_case[0] = 0;
1206 strlcpy(use_case, ident_value, sizeof(use_case));
1207 uc_index =
1208 get_use_case_index(uc_mgr, ident_value, CTRL_LIST_MODIFIER);
1209 if (capability == CAP_VOICE ||
1210 capability == getUseCaseType(ident_value) ||
1211 getUseCaseType(ident_value) == CAP_VOICE) {
1212 ALOGV("set %d for use case value: %s", enable, use_case);
1213 ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
1214 enable, CTRL_LIST_MODIFIER, uc_index);
1215 if (ret != 0)
1216 ALOGE("No valid controls exists for usecase %s and \
1217 device %s, enable: %d", use_case, device, enable);
1218 }
1219 intdev_flag = 0;
1220 }
1221 use_case[0] = 0;
1222 free(ident_value);
1223 }
1224 }
1225 if (!enable) {
1226 ret = snd_use_case_apply_mixer_controls(uc_mgr, device, enable,
1227 CTRL_LIST_DEVICE, dev_index);
1228 if (!ret)
1229 snd_ucm_set_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1230 device, enable);
1231 }
1232 return ret;
1233}
1234
1235/* Returns usecase type i.e. either verb or modifier
1236 * uc_mgr - UCM structure pointer
1237 * usecase - usecase name either verb or modifier
1238 * return CTRL_LIST_VERB or CTRL_LIST_MODIFIER for verb/modifier respectively
1239 */
1240static int get_usecase_type(snd_use_case_mgr_t *uc_mgr, const char *usecase)
1241{
1242 int ret = -EINVAL, index = 0;
1243
1244 while (strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1245 SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
1246 if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index], usecase,
1247 (strlen(usecase)+1))) {
1248 ret = 0;
1249 break;
1250 }
1251 index++;
1252 }
1253 if (ret == 0)
1254 return CTRL_LIST_VERB;
1255 else
1256 return CTRL_LIST_MODIFIER;
1257}
1258
1259/* Set/Reset mixer controls of specific device and specific use cases
1260 * uc_mgr - UCM structure pointer
1261 * device - device name
1262 * usecase - use case for which device needs to be enabled
1263 * enable - 1 for enable and 0 for disable
1264 * return 0 on sucess, otherwise a negative error code
1265 */
1266static int set_controls_of_device_for_usecase(snd_use_case_mgr_t *uc_mgr,
1267 const char *device, const char *usecase, int enable)
1268{
1269 char use_case[MAX_UC_LEN];
1270 int ret = -ENODEV, uc_index, dev_index;
1271
1272 ALOGV("set_device_for_ident(): %s %s", device, usecase);
1273 dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
1274 if (usecase != NULL) {
1275 strlcpy(use_case, usecase, sizeof(use_case));
1276 strlcat(use_case, device, sizeof(use_case));
1277 if ((uc_index = get_use_case_index(uc_mgr, use_case,
1278 get_usecase_type(uc_mgr, usecase))) < 0) {
1279 ALOGV("No valid use case found: %s", use_case);
1280 } else {
1281 if (enable) {
1282 if (!snd_ucm_get_status_at_index(
1283 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1284 ret = snd_use_case_apply_mixer_controls(uc_mgr, device,
1285 enable, CTRL_LIST_DEVICE, dev_index);
1286 if (!ret)
1287 snd_ucm_set_status_at_index
1288 (uc_mgr->card_ctxt_ptr->dev_list_head, device, enable);
1289 }
1290 }
1291 ALOGV("set %d for use case value: %s", enable, use_case);
1292 ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case, enable,
1293 get_usecase_type(uc_mgr, usecase), uc_index);
1294 if (ret != 0)
1295 ALOGE("No valid controls exists for usecase %s and device %s, \
1296 enable: %d", use_case, device, enable);
1297 }
1298 use_case[0] = 0;
1299 } else {
1300 if (enable) {
1301 if (!snd_ucm_get_status_at_index(
1302 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1303 ret = snd_use_case_apply_mixer_controls(uc_mgr, device, enable,
1304 CTRL_LIST_DEVICE, dev_index);
1305 if (!ret)
1306 snd_ucm_set_status_at_index(
1307 uc_mgr->card_ctxt_ptr->dev_list_head, device, enable);
1308 }
1309 }
1310 }
1311 if (!enable) {
1312 ret = snd_use_case_apply_mixer_controls(uc_mgr, device, enable,
1313 CTRL_LIST_DEVICE, dev_index);
1314 if (!ret)
1315 snd_ucm_set_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1316 device, enable);
1317 }
1318 return ret;
1319}
1320
1321/**
1322 * Set new value for an identifier
1323 * uc_mgr - UCM structure
1324 * identifier - _verb, _enadev, _disdev, _enamod, _dismod
1325 * _swdev, _swmod
1326 * value - Value to be set
1327 * returns 0 on success, otherwise a negative error code
1328 */
1329int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
1330 const char *identifier,
1331 const char *value)
1332{
1333 use_case_verb_t *verb_list;
1334 char ident[MAX_STR_LEN], *ident1, *ident2, *temp_ptr;
1335 int verb_index, list_size, index = 0, ret = -EINVAL;
1336
1337 pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
1338 if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) || (value == NULL) ||
1339 (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL) ||
1340 (identifier == NULL)) {
1341 ALOGE("snd_use_case_set(): failed, invalid arguments");
1342 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1343 return -EINVAL;
1344 }
1345
Ajay Dudani86c852b2012-07-19 15:28:45 -07001346#if LOCAL_LOGD
Iliyan Malchev4765c432012-06-11 14:36:16 -07001347 ALOGD("snd_use_case_set(): uc_mgr %p identifier %s value %s", uc_mgr,
1348 identifier, value);
Ajay Dudani86c852b2012-07-19 15:28:45 -07001349#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -07001350 strlcpy(ident, identifier, sizeof(ident));
1351 if(!(ident1 = strtok_r(ident, "/", &temp_ptr))) {
1352 ALOGV("No multiple identifiers found in identifier value");
1353 ident[0] = 0;
1354 } else {
1355 if (!strncmp(ident1, "_swdev", 6)) {
1356 if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
1357 ALOGD("Invalid disable device value: %s, but enabling new \
1358 device", ident2);
1359 } else {
1360 ret = snd_ucm_del_ident_from_list(
1361 &uc_mgr->card_ctxt_ptr->dev_list_head, ident2);
1362 if (ret < 0) {
1363 ALOGV("Ignore device %s disable, device not part of \
1364 enabled list", ident2);
1365 } else {
1366 ALOGV("swdev: device value to be disabled: %s", ident2);
1367 /* Disable mixer controls for
1368 * corresponding use cases and device */
1369 ret = set_controls_of_device_for_all_usecases(uc_mgr,
1370 ident2, 0);
1371 if (ret < 0) {
1372 ALOGV("Device %s not disabled, no valid use case \
1373 found: %d", ident2, errno);
1374 }
1375 }
1376 }
1377 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1378 ret = snd_use_case_set(uc_mgr, "_enadev", value);
1379 if (ret < 0) {
1380 ALOGV("Device %s not enabled, no valid use case found: %d",
1381 value, errno);
1382 }
1383 return ret;
1384 } else if (!strncmp(ident1, "_swmod", 6)) {
1385 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1386 if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
1387 ALOGD("Invalid modifier value: %s, but enabling new modifier",
1388 ident2);
1389 } else {
1390 ret = snd_use_case_set(uc_mgr, "_dismod", ident2);
1391 if (ret < 0) {
1392 ALOGV("Modifier %s not disabled, no valid use case \
1393 found: %d", ident2, errno);
1394 }
1395 }
1396 ret = snd_use_case_set(uc_mgr, "_enamod", value);
1397 if (ret < 0) {
1398 ALOGV("Modifier %s not enabled, no valid use case found: %d",
1399 value, errno);
1400 }
1401 return ret;
1402 } else {
1403 ALOGV("No switch device/modifier option found: %s", ident1);
1404 }
1405 ident[0] = 0;
1406 }
1407
1408 if (!strncmp(identifier, "_verb", 5)) {
1409 /* Check if value is valid verb */
1410 while (strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1411 SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
1412 if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index], value,
1413 (strlen(value)+1))) {
1414 ret = 0;
1415 break;
1416 }
1417 index++;
1418 }
1419 if ((ret < 0) && (strncmp(value, SND_USE_CASE_VERB_INACTIVE,
1420 strlen(SND_USE_CASE_VERB_INACTIVE)))) {
1421 ALOGE("Invalid verb identifier value");
1422 } else {
1423 ALOGV("Index:%d Verb:%s", index,
1424 uc_mgr->card_ctxt_ptr->verb_list[index]);
1425 /* Disable the mixer controls for current use case
1426 * for all the enabled devices */
1427 if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
1428 SND_USE_CASE_VERB_INACTIVE,
1429 strlen(SND_USE_CASE_VERB_INACTIVE))) {
1430 ret = set_controls_of_usecase_for_all_devices(uc_mgr,
1431 uc_mgr->card_ctxt_ptr->current_verb, 0, CTRL_LIST_VERB);
1432 if (ret != 0)
1433 ALOGE("Failed to disable controls for use case: %s",
1434 uc_mgr->card_ctxt_ptr->current_verb);
1435 }
1436 strlcpy(uc_mgr->card_ctxt_ptr->current_verb, value, MAX_STR_LEN);
1437 /* Enable the mixer controls for the new use case
1438 * for all the enabled devices */
1439 if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
1440 SND_USE_CASE_VERB_INACTIVE,
1441 strlen(SND_USE_CASE_VERB_INACTIVE))) {
1442 uc_mgr->card_ctxt_ptr->current_verb_index = index;
1443 ret = set_controls_of_usecase_for_all_devices(uc_mgr,
1444 uc_mgr->card_ctxt_ptr->current_verb, 1, CTRL_LIST_VERB);
1445 }
1446 }
1447 } else if (!strncmp(identifier, "_enadev", 7)) {
1448 index = 0; ret = 0;
1449 list_size =
1450 snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1451 for (index = 0; index < list_size; index++) {
1452 if ((ident1 =
1453 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1454 index))) {
1455 if (!strncmp(ident1, value, (strlen(value)+1))) {
1456 ALOGV("Ignore enable as %s device is already part of \
1457 enabled list", value);
1458 free(ident1);
1459 break;
1460 }
1461 free(ident1);
1462 }
1463 }
1464 if (index == list_size) {
1465 ALOGV("enadev: device value to be enabled: %s", value);
1466 snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1467 value);
1468 }
1469 snd_ucm_print_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1470 /* Apply Mixer controls of all verb and modifiers for this device*/
1471 ret = set_controls_of_device_for_all_usecases(uc_mgr, value, 1);
1472 } else if (!strncmp(identifier, "_disdev", 7)) {
1473 ret = snd_ucm_get_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1474 value);
1475 if (ret < 0) {
1476 ALOGD("disdev: device %s not enabled, no need to disable", value);
1477 } else if (ret == 0) {
1478 ALOGV("disdev: device %s not active, remove from the list", value);
1479 ret =
1480 snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1481 value);
1482 if (ret < 0) {
1483 ALOGE("Invalid device: Device not part of enabled device list");
1484 }
1485 } else {
1486 ret =
1487 snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1488 value);
1489 if (ret < 0) {
1490 ALOGE("Invalid device: Device not part of enabled device list");
1491 } else {
1492 ALOGV("disdev: device value to be disabled: %s", value);
1493 index = get_use_case_index(uc_mgr, value, CTRL_LIST_DEVICE);
1494 /* Apply Mixer controls for corresponding device and modifier */
1495 ret = snd_use_case_apply_mixer_controls(uc_mgr, value, 0,
1496 CTRL_LIST_DEVICE, index);
1497 }
1498 }
1499 } else if (!strncmp(identifier, "_enamod", 7)) {
1500 index = 0; ret = 0;
1501 verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
1502 if (verb_index < 0) {
1503 ALOGE("Invalid verb identifier value");
1504 } else {
1505 ALOGV("Index:%d Verb:%s", verb_index,
1506 uc_mgr->card_ctxt_ptr->verb_list[verb_index]);
1507 verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
1508 while(strncmp(verb_list[verb_index].modifier_list[index], value,
1509 (strlen(value)+1))) {
1510 if (!strncmp(verb_list[verb_index].modifier_list[index],
1511 SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))){
1512 ret = -EINVAL;
1513 break;
1514 }
1515 index++;
1516 }
1517 if (ret < 0) {
1518 ALOGE("Invalid modifier identifier value");
1519 } else {
1520 snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
1521 value);
1522 /* Enable the mixer controls for the new use case
1523 * for all the enabled devices */
1524 ret = set_controls_of_usecase_for_all_devices(uc_mgr, value, 1,
1525 CTRL_LIST_MODIFIER);
1526 }
1527 }
1528 } else if (!strncmp(identifier, "_dismod", 7)) {
1529 ret = snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
1530 value);
1531 if (ret < 0) {
1532 ALOGE("Modifier not enabled currently, invalid modifier");
1533 } else {
1534 ALOGV("dismod: modifier value to be disabled: %s", value);
1535 /* Enable the mixer controls for the new use case
1536 * for all the enabled devices */
1537 ret = set_controls_of_usecase_for_all_devices(uc_mgr, value, 0,
1538 CTRL_LIST_MODIFIER);
1539 }
1540 } else {
1541 ALOGE("Unknown identifier value: %s", identifier);
1542 }
1543 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1544 return ret;
1545}
1546
1547/**
1548 * Set new value for an identifier based on use case
1549 * uc_mgr - UCM structure
1550 * identifier - _verb, _enadev, _disdev, _enamod, _dismod
1551 * _swdev, _swmod
1552 * value - Value to be set
1553 * usecase - usecase/device for which this command needs to be executed
1554 * returns 0 on success, otherwise a negative error code
1555 */
1556int snd_use_case_set_case(snd_use_case_mgr_t *uc_mgr,
1557 const char *identifier,
1558 const char *value, const char *usecase)
1559{
1560 use_case_verb_t *verb_list;
1561 char ident[MAX_STR_LEN], *ident1, *ident2, *temp_ptr;
1562 int verb_index, list_size, index = 0, ret = -EINVAL;
1563
1564 pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
1565 if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) || (value == NULL) ||
1566 (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL) ||
1567 (identifier == NULL)) {
1568 ALOGE("snd_use_case_set_case(): failed, invalid arguments");
1569 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1570 return -EINVAL;
1571 }
1572
1573 ALOGD("snd_use_case_set_case(): uc_mgr %p identifier %s value %s",
1574 uc_mgr, identifier, value);
1575 strlcpy(ident, identifier, sizeof(ident));
1576 if(!(ident1 = strtok_r(ident, "/", &temp_ptr))) {
1577 ALOGV("No multiple identifiers found in identifier value");
1578 ident[0] = 0;
1579 } else {
1580 if (!strncmp(ident1, "_swdev", 6)) {
1581 if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
1582 ALOGD("Invalid disable device value: %s, but enabling new \
1583 device", ident2);
1584 } else {
1585 ret = snd_ucm_del_ident_from_list(
1586 &uc_mgr->card_ctxt_ptr->dev_list_head, ident2);
1587 if (ret < 0) {
1588 ALOGV("Ignore device %s disable, device not part of \
1589 enabled list", ident2);
1590 } else {
1591 ALOGV("swdev: device value to be disabled: %s", ident2);
1592 /* Disable mixer controls for
1593 * corresponding use cases and device */
1594 ret = set_controls_of_device_for_usecase(uc_mgr, ident2,
1595 usecase, 0);
1596 if (ret < 0) {
1597 ALOGV("Device %s not disabled, no valid use case \
1598 found: %d", ident2, errno);
1599 }
1600 }
1601 }
1602 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1603 ret = snd_use_case_set_case(uc_mgr, "_enadev", value, usecase);
1604 if (ret < 0) {
1605 ALOGV("Device %s not enabled, no valid use case found: %d",
1606 value, errno);
1607 }
1608 return ret;
1609 } else if (!strncmp(ident1, "_swmod", 6)) {
1610 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1611 if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
1612 ALOGD("Invalid modifier value: %s, but enabling new modifier",
1613 ident2);
1614 } else {
1615 ret = snd_use_case_set_case(uc_mgr, "_dismod", ident2, usecase);
1616 if (ret < 0) {
1617 ALOGV("Modifier %s not disabled, no valid use case \
1618 found: %d", ident2, errno);
1619 }
1620 }
1621 ret = snd_use_case_set_case(uc_mgr, "_enamod", value, usecase);
1622 if (ret < 0) {
1623 ALOGV("Modifier %s not enabled, no valid use case found: %d",
1624 value, errno);
1625 }
1626 return ret;
1627 } else {
1628 ALOGV("No switch device/modifier option found: %s", ident1);
1629 }
1630 ident[0] = 0;
1631 }
1632
1633 if (!strncmp(identifier, "_verb", 5)) {
1634 /* Check if value is valid verb */
1635 while (strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1636 SND_UCM_END_OF_LIST, MAX_STR_LEN)) {
1637 if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1638 value, MAX_STR_LEN)) {
1639 ret = 0;
1640 break;
1641 }
1642 index++;
1643 }
1644 if ((ret < 0) && (strncmp(value, SND_USE_CASE_VERB_INACTIVE,
1645 MAX_STR_LEN))) {
1646 ALOGE("Invalid verb identifier value");
1647 } else {
1648 ALOGV("Index:%d Verb:%s", index,
1649 uc_mgr->card_ctxt_ptr->verb_list[index]);
1650 /* Disable the mixer controls for current use case
1651 * for specified device */
1652 if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
1653 SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN)) {
1654 ret = set_controls_of_usecase_for_device(uc_mgr,
1655 uc_mgr->card_ctxt_ptr->current_verb, usecase,
1656 0, CTRL_LIST_VERB);
1657 if (ret != 0)
1658 ALOGE("Failed to disable controls for use case: %s",
1659 uc_mgr->card_ctxt_ptr->current_verb);
1660 }
1661 strlcpy(uc_mgr->card_ctxt_ptr->current_verb, value, MAX_STR_LEN);
1662 /* Enable the mixer controls for the new use case
1663 * for specified device */
1664 if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
1665 SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN)) {
1666 uc_mgr->card_ctxt_ptr->current_verb_index = index;
1667 index = 0;
1668 list_size =
1669 snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1670 for (index = 0; index < list_size; index++) {
1671 if ((ident1 = snd_ucm_get_value_at_index(
1672 uc_mgr->card_ctxt_ptr->dev_list_head, index))) {
1673 if (!strncmp(ident1, usecase, MAX_STR_LEN)) {
1674 ALOGV("Device already part of enabled list: %s",
1675 usecase);
1676 free(ident1);
1677 break;
1678 }
1679 free(ident1);
1680 }
1681 }
1682 if (index == list_size) {
1683 ALOGV("enadev: device value to be enabled: %s", usecase);
1684 snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1685 usecase);
1686 }
1687 ret = set_controls_of_usecase_for_device(uc_mgr,
1688 uc_mgr->card_ctxt_ptr->current_verb, usecase,
1689 1, CTRL_LIST_VERB);
1690 }
1691 }
1692 } else if (!strncmp(identifier, "_enadev", 7)) {
1693 index = 0; ret = 0;
1694 list_size =
1695 snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1696 for (index = 0; index < list_size; index++) {
1697 if ((ident1 =
1698 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1699 index))) {
1700 if (!strncmp(ident1, value, MAX_STR_LEN)) {
1701 ALOGV("Device already part of enabled list: %s", value);
1702 free(ident1);
1703 break;
1704 }
1705 free(ident1);
1706 }
1707 }
1708 if (index == list_size) {
1709 ALOGV("enadev: device value to be enabled: %s", value);
1710 snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1711 value);
1712 }
1713 snd_ucm_print_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1714 /* Apply Mixer controls of usecase for this device*/
1715 ret = set_controls_of_device_for_usecase(uc_mgr, value, usecase, 1);
1716 } else if (!strncmp(identifier, "_disdev", 7)) {
1717 ret = snd_ucm_get_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1718 value);
1719 if (ret < 0) {
1720 ALOGD("disdev: device %s not enabled, no need to disable", value);
1721 } else if (ret == 0) {
1722 ALOGV("disdev: device %s not active, remove from the list", value);
1723 ret =
1724 snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1725 value);
1726 if (ret < 0) {
1727 ALOGE("Invalid device: Device not part of enabled device list");
1728 }
1729 } else {
1730 ret =
1731 snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1732 value);
1733 if (ret < 0) {
1734 ALOGE("Invalid device: Device not part of enabled device list");
1735 } else {
1736 ALOGV("disdev: device value to be disabled: %s", value);
1737 /* Apply Mixer controls of usecase for this device*/
1738 ret = set_controls_of_device_for_usecase(uc_mgr, value,
1739 usecase, 0);
1740 }
1741 }
1742 } else if (!strncmp(identifier, "_enamod", 7)) {
1743 if (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
1744 SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN)) {
1745 ALOGE("Invalid use case verb value");
1746 ret = -EINVAL;
1747 } else {
1748 ret = 0;
1749 while(strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1750 uc_mgr->card_ctxt_ptr->current_verb, MAX_STR_LEN)) {
1751 if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1752 SND_UCM_END_OF_LIST, MAX_STR_LEN)){
1753 ret = -EINVAL;
1754 break;
1755 }
1756 index++;
1757 }
1758 }
1759 if (ret < 0) {
1760 ALOGE("Invalid verb identifier value");
1761 } else {
1762 verb_index = index; index = 0; ret = 0;
1763 verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
1764 ALOGV("Index:%d Verb:%s", verb_index,
1765 uc_mgr->card_ctxt_ptr->verb_list[verb_index]);
1766 while(strncmp(verb_list[verb_index].modifier_list[index],
1767 value, MAX_STR_LEN)) {
1768 if (!strncmp(verb_list[verb_index].modifier_list[index],
1769 SND_UCM_END_OF_LIST, MAX_STR_LEN)){
1770 ret = -EINVAL;
1771 break;
1772 }
1773 index++;
1774 }
1775 if (ret < 0) {
1776 ALOGE("Invalid modifier identifier value");
1777 } else {
1778 index = 0;
1779 list_size =
1780 snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1781 for (index = 0; index < list_size; index++) {
1782 if ((ident1 = snd_ucm_get_value_at_index(
1783 uc_mgr->card_ctxt_ptr->dev_list_head, index))) {
1784 if (!strncmp(ident1, usecase, MAX_STR_LEN)) {
1785 ALOGV("Device already part of enabled list: %s",
1786 usecase);
1787 free(ident1);
1788 break;
1789 }
1790 free(ident1);
1791 }
1792 }
1793 if (index == list_size) {
1794 ALOGV("enadev: device value to be enabled: %s", usecase);
1795 snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1796 usecase);
1797 }
1798 snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
1799 value);
1800 /* Enable the mixer controls for the new use case
1801 * for all the enabled devices */
1802 ret = set_controls_of_usecase_for_device(uc_mgr, value,
1803 usecase, 1, CTRL_LIST_MODIFIER);
1804 }
1805 }
1806 } else if (!strncmp(identifier, "_dismod", 7)) {
1807 ret = snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
1808 value);
1809 if (ret < 0) {
1810 ALOGE("Modifier not enabled currently, invalid modifier");
1811 } else {
1812 ALOGV("dismod: modifier value to be disabled: %s", value);
1813 /* Enable the mixer controls for the new use case
1814 * for all the enabled devices */
1815 ret = set_controls_of_usecase_for_device(uc_mgr, value, usecase,
1816 0, CTRL_LIST_MODIFIER);
1817 }
1818 } else {
1819 ALOGE("Unknown identifier value: %s", identifier);
1820 }
1821 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1822 return ret;
1823}
1824
1825/**
1826 * Open and initialise use case core for sound card
1827 * uc_mgr - Returned use case manager pointer
1828 * card_name - Sound card name.
1829 * returns 0 on success, otherwise a negative error code
1830 */
1831int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, const char *card_name)
1832{
1833 snd_use_case_mgr_t *uc_mgr_ptr = NULL;
1834 int index, ret = -EINVAL;
1835 char tmp[2];
1836
1837 ALOGV("snd_use_case_open(): card_name %s", card_name);
1838
1839 if (card_name == NULL) {
1840 ALOGE("snd_use_case_mgr_open: failed, invalid arguments");
1841 return ret;
1842 }
1843
1844 for (index = 0; index < (int)MAX_NUM_CARDS; index++) {
1845 if(!strncmp(card_name, card_mapping_list[index].card_name,
1846 (strlen(card_mapping_list[index].card_name)+1))) {
1847 ret = 0;
1848 break;
1849 }
1850 }
1851
1852 if (ret < 0) {
1853 ALOGE("Card %s not found", card_name);
1854 } else {
1855 uc_mgr_ptr = (snd_use_case_mgr_t *)calloc(1,
1856 sizeof(snd_use_case_mgr_t));
1857 if (uc_mgr_ptr == NULL) {
1858 ALOGE("Failed to allocate memory for instance");
1859 return -ENOMEM;
1860 }
1861 uc_mgr_ptr->snd_card_index = index;
1862 uc_mgr_ptr->card_ctxt_ptr = (card_ctxt_t *)calloc(1,
1863 sizeof(card_ctxt_t));
1864 if (uc_mgr_ptr->card_ctxt_ptr == NULL) {
1865 ALOGE("Failed to allocate memory for card context");
1866 free(uc_mgr_ptr);
1867 uc_mgr_ptr = NULL;
1868 return -ENOMEM;
1869 }
1870 uc_mgr_ptr->card_ctxt_ptr->card_number =
1871 card_mapping_list[index].card_number;
1872 uc_mgr_ptr->card_ctxt_ptr->card_name =
1873 (char *)malloc((strlen(card_name)+1)*sizeof(char));
1874 if (uc_mgr_ptr->card_ctxt_ptr->card_name == NULL) {
1875 ALOGE("Failed to allocate memory for card name");
1876 free(uc_mgr_ptr->card_ctxt_ptr);
1877 free(uc_mgr_ptr);
1878 uc_mgr_ptr = NULL;
1879 return -ENOMEM;
1880 }
1881 strlcpy(uc_mgr_ptr->card_ctxt_ptr->card_name, card_name,
1882 ((strlen(card_name)+1)*sizeof(char)));
1883 uc_mgr_ptr->card_ctxt_ptr->control_device =
1884 (char *)malloc((strlen("/dev/snd/controlC")+2)*sizeof(char));
1885 if (uc_mgr_ptr->card_ctxt_ptr->control_device == NULL) {
1886 ALOGE("Failed to allocate memory for control device string");
1887 free(uc_mgr_ptr->card_ctxt_ptr->card_name);
1888 free(uc_mgr_ptr->card_ctxt_ptr);
1889 free(uc_mgr_ptr);
1890 uc_mgr_ptr = NULL;
1891 return -ENOMEM;
1892 }
1893 strlcpy(uc_mgr_ptr->card_ctxt_ptr->control_device,
1894 "/dev/snd/controlC", 18);
1895 snprintf(tmp, sizeof(tmp), "%d",
1896 uc_mgr_ptr->card_ctxt_ptr->card_number);
1897 strlcat(uc_mgr_ptr->card_ctxt_ptr->control_device, tmp,
1898 (strlen("/dev/snd/controlC")+2)*sizeof(char));
1899 uc_mgr_ptr->device_list_count = 0;
1900 uc_mgr_ptr->modifier_list_count = 0;
1901 uc_mgr_ptr->current_device_list = NULL;
1902 uc_mgr_ptr->current_modifier_list = NULL;
1903 uc_mgr_ptr->current_tx_device = -1;
1904 uc_mgr_ptr->current_rx_device = -1;
1905 pthread_mutexattr_init(&uc_mgr_ptr->card_ctxt_ptr->card_lock_attr);
1906 pthread_mutex_init(&uc_mgr_ptr->card_ctxt_ptr->card_lock,
1907 &uc_mgr_ptr->card_ctxt_ptr->card_lock_attr);
1908 strlcpy(uc_mgr_ptr->card_ctxt_ptr->current_verb,
1909 SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN);
1910 /* Reset all mixer controls if any applied
1911 * previously for the same card */
1912 snd_use_case_mgr_reset(uc_mgr_ptr);
1913 uc_mgr_ptr->card_ctxt_ptr->current_verb_index = -1;
1914 /* Parse config files and update mixer controls */
1915 ret = snd_ucm_parse(&uc_mgr_ptr);
1916 if(ret < 0) {
1917 ALOGE("Failed to parse config files: %d", ret);
1918 snd_ucm_free_mixer_list(&uc_mgr_ptr);
1919 }
1920 ALOGV("Open mixer device: %s",
1921 uc_mgr_ptr->card_ctxt_ptr->control_device);
1922 uc_mgr_ptr->card_ctxt_ptr->mixer_handle =
1923 mixer_open(uc_mgr_ptr->card_ctxt_ptr->control_device);
1924 ALOGV("Mixer handle %p", uc_mgr_ptr->card_ctxt_ptr->mixer_handle);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001925 *uc_mgr = uc_mgr_ptr;
1926 }
1927 ALOGV("snd_use_case_open(): returning instance %p", uc_mgr_ptr);
1928 return ret;
1929}
1930
1931
1932/**
1933 * \brief Reload and re-parse use case configuration files for sound card.
1934 * \param uc_mgr Use case manager
1935 * \return zero if success, otherwise a negative error code
1936 */
1937int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr) {
1938 ALOGE("Reload is not implemented for now as there is no use case currently");
1939 return 0;
1940}
1941
1942/**
1943 * \brief Close use case manager
1944 * \param uc_mgr Use case manager
1945 * \return zero if success, otherwise a negative error code
1946 */
1947int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
1948{
1949 int ret = 0;
1950
1951 if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) ||
1952 (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) {
1953 ALOGE("snd_use_case_mgr_close(): failed, invalid arguments");
1954 return -EINVAL;
1955 }
1956
1957 ALOGV("snd_use_case_close(): instance %p", uc_mgr);
1958 ret = snd_use_case_mgr_reset(uc_mgr);
1959 if (ret < 0)
1960 ALOGE("Failed to reset ucm session");
1961 snd_ucm_free_mixer_list(&uc_mgr);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001962 pthread_mutexattr_destroy(&uc_mgr->card_ctxt_ptr->card_lock_attr);
1963 pthread_mutex_destroy(&uc_mgr->card_ctxt_ptr->card_lock);
1964 if (uc_mgr->card_ctxt_ptr->mixer_handle) {
1965 mixer_close(uc_mgr->card_ctxt_ptr->mixer_handle);
1966 uc_mgr->card_ctxt_ptr->mixer_handle = NULL;
1967 }
1968 uc_mgr->snd_card_index = -1;
1969 uc_mgr->current_tx_device = -1;
1970 uc_mgr->current_rx_device = -1;
1971 free(uc_mgr->card_ctxt_ptr->control_device);
1972 free(uc_mgr->card_ctxt_ptr->card_name);
1973 free(uc_mgr->card_ctxt_ptr);
1974 uc_mgr->card_ctxt_ptr = NULL;
1975 free(uc_mgr);
1976 uc_mgr = NULL;
1977 ALOGV("snd_use_case_mgr_close(): card instace closed successfully");
1978 return ret;
1979}
1980
1981/**
1982 * \brief Reset use case manager verb, device, modifier to deafult settings.
1983 * \param uc_mgr Use case manager
1984 * \return zero if success, otherwise a negative error code
1985 */
1986int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
1987{
1988 char *ident_value;
1989 int index, list_size, ret = 0;
1990
1991 ALOGV("snd_use_case_reset(): instance %p", uc_mgr);
1992 pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
1993 if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) ||
1994 (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) {
1995 ALOGE("snd_use_case_mgr_reset(): failed, invalid arguments");
1996 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1997 return -EINVAL;
1998 }
1999
2000 /* Disable mixer controls of all the enabled modifiers */
2001 list_size = snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
2002 for (index = (list_size-1); index >= 0; index--) {
2003 if ((ident_value =
2004 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
2005 index))) {
2006 snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
2007 ident_value);
2008 ret = set_controls_of_usecase_for_all_devices(uc_mgr,
2009 ident_value, 0, CTRL_LIST_MODIFIER);
2010 if (ret != 0)
2011 ALOGE("Failed to disable mixer controls for %s", ident_value);
2012 free(ident_value);
2013 }
2014 }
2015 /* Clear the enabled modifiers list */
2016 if (uc_mgr->modifier_list_count) {
2017 for (index = 0; index < uc_mgr->modifier_list_count; index++) {
2018 free(uc_mgr->current_modifier_list[index]);
2019 uc_mgr->current_modifier_list[index] = NULL;
2020 }
2021 free(uc_mgr->current_modifier_list);
2022 uc_mgr->current_modifier_list = NULL;
2023 uc_mgr->modifier_list_count = 0;
2024 }
2025 /* Disable mixer controls of current use case verb */
2026 if(strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_USE_CASE_VERB_INACTIVE,
2027 strlen(SND_USE_CASE_VERB_INACTIVE))) {
2028 ret = set_controls_of_usecase_for_all_devices(uc_mgr,
2029 uc_mgr->card_ctxt_ptr->current_verb, 0, CTRL_LIST_VERB);
2030 if (ret != 0)
2031 ALOGE("Failed to disable mixer controls for %s",
2032 uc_mgr->card_ctxt_ptr->current_verb);
2033 strlcpy(uc_mgr->card_ctxt_ptr->current_verb, SND_USE_CASE_VERB_INACTIVE,
2034 MAX_STR_LEN);
2035 }
2036 /* Disable mixer controls of all the enabled devices */
2037 list_size = snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
2038 for (index = (list_size-1); index >= 0; index--) {
2039 if ((ident_value =
2040 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
2041 index))) {
2042 snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
2043 ident_value);
2044 ret = set_controls_of_device_for_all_usecases(uc_mgr,
2045 ident_value, 0);
2046 if (ret != 0)
2047 ALOGE("Failed to disable or no mixer controls set for %s",
2048 ident_value);
2049 free(ident_value);
2050 }
2051 }
2052 /* Clear the enabled devices list */
2053 if (uc_mgr->device_list_count) {
2054 for (index = 0; index < uc_mgr->device_list_count; index++) {
2055 free(uc_mgr->current_device_list[index]);
2056 uc_mgr->current_device_list[index] = NULL;
2057 }
2058 free(uc_mgr->current_device_list);
2059 uc_mgr->current_device_list = NULL;
2060 uc_mgr->device_list_count = 0;
2061 }
2062 uc_mgr->current_tx_device = -1;
2063 uc_mgr->current_rx_device = -1;
2064 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
2065 return ret;
2066}
2067
2068/* 2nd stage parsing done in seperate thread */
2069void *second_stage_parsing_thread(void *uc_mgr_ptr)
2070{
2071 use_case_verb_t *verb_list;
2072 char path[200];
2073 struct stat st;
2074 int fd, index = 0, ret = 0, rc = 0;
2075 char *read_buf = NULL, *next_str = NULL, *current_str = NULL, *buf = NULL;
2076 char *p = NULL, *verb_name = NULL, *file_name = NULL, *temp_ptr = NULL;
2077 snd_use_case_mgr_t **uc_mgr = (snd_use_case_mgr_t **)&uc_mgr_ptr;
2078
2079 strlcpy(path, CONFIG_DIR, (strlen(CONFIG_DIR)+1));
2080 strlcat(path, (*uc_mgr)->card_ctxt_ptr->card_name, sizeof(path));
2081 ALOGV("master config file path:%s", path);
2082 fd = open(path, O_RDONLY);
2083 if (fd < 0) {
2084 ALOGE("failed to open config file %s error %d\n", path, errno);
2085 return NULL;
2086 }
2087 if (fstat(fd, &st) < 0) {
2088 ALOGE("failed to stat %s error %d\n", path, errno);
2089 close(fd);
2090 return NULL;
2091 }
2092 read_buf = (char *) mmap(0, st.st_size, PROT_READ | PROT_WRITE,
2093 MAP_PRIVATE, fd, 0);
2094 if (read_buf == MAP_FAILED) {
2095 ALOGE("failed to mmap file error %d\n", errno);
2096 close(fd);
2097 return NULL;
2098 }
2099 current_str = read_buf;
2100 verb_name = NULL;
2101 while (*current_str != (char)EOF) {
2102 next_str = strchr(current_str, '\n');
2103 if (!next_str)
2104 break;
2105 *next_str++ = '\0';
2106 if (verb_name == NULL) {
2107 buf = strstr(current_str, "SectionUseCase");
2108 if (buf == NULL) {
2109 if((current_str = next_str) == NULL)
2110 break;
2111 else
2112 continue;
2113 }
2114 /* Ignore parsing first use case (HiFi) as it is already parsed
2115 * in 1st stage of parsing */
2116 if (index == 0) {
2117 index++;
2118 if((current_str = next_str) == NULL)
2119 break;
2120 else
2121 continue;
2122 }
2123 p = strtok_r(buf, ".", &temp_ptr);
2124 while (p != NULL) {
2125 p = strtok_r(NULL, "\"", &temp_ptr);
2126 if (p == NULL)
2127 break;
2128 verb_name = (char *)malloc((strlen(p)+1)*sizeof(char));
2129 if(verb_name == NULL) {
2130 ret = -ENOMEM;
2131 break;
2132 }
2133 strlcpy(verb_name, p, (strlen(p)+1)*sizeof(char));
2134 break;
2135 }
2136 } else {
2137 buf = strstr(current_str, "File");
2138 if (buf == NULL) {
2139 if((current_str = next_str) == NULL)
2140 break;
2141 else
2142 continue;
2143 }
2144 p = strtok_r(buf, "\"", &temp_ptr);
2145 while (p != NULL) {
2146 p = strtok_r(NULL, "\"", &temp_ptr);
2147 if (p == NULL)
2148 break;
2149 file_name = (char *)malloc((strlen(p)+1)*sizeof(char));
2150 if(file_name == NULL) {
2151 ret = -ENOMEM;
2152 break;
2153 }
2154 strlcpy(file_name, p, (strlen(p)+1)*sizeof(char));
2155 break;
2156 }
2157 verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
2158 if (file_name != NULL) {
2159 ret = snd_ucm_parse_verb(uc_mgr, file_name, index);
2160 verb_list[index].use_case_name =
2161 (char *)malloc((strlen(verb_name)+1)*sizeof(char));
2162 strlcpy(verb_list[index].use_case_name, verb_name,
2163 ((strlen(verb_name)+1)*sizeof(char)));
2164 /* Verb list might have been appended with END OF LIST in
2165 * 1st stage parsing. Delete this entry so that new verbs
2166 * are appended from here and END OF LIST will be added
2167 * again at the end of 2nd stage parsing
2168 */
2169 if((*uc_mgr)->card_ctxt_ptr->verb_list[index]) {
2170 free((*uc_mgr)->card_ctxt_ptr->verb_list[index]);
2171 (*uc_mgr)->card_ctxt_ptr->verb_list[index] = NULL;
2172 }
2173 (*uc_mgr)->card_ctxt_ptr->verb_list[index] =
2174 (char *)malloc((strlen(verb_name)+1)*sizeof(char));
2175 strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index], verb_name,
2176 ((strlen(verb_name)+1)*sizeof(char)));
2177 free(verb_name);
2178 verb_name = NULL;
2179 free(file_name);
2180 file_name = NULL;
2181 }
2182 index++;
2183 (*uc_mgr)->card_ctxt_ptr->verb_list[index] =
2184 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2185 strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index],
2186 SND_UCM_END_OF_LIST,
2187 ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
2188 }
2189 if((current_str = next_str) == NULL)
2190 break;
2191 }
2192 if (verb_name != NULL) {
2193 free(verb_name);
2194 verb_name = NULL;
2195 }
2196 if (file_name != NULL) {
2197 free(file_name);
2198 file_name = NULL;
2199 }
2200 munmap(read_buf, st.st_size);
2201 close(fd);
2202#if PARSE_DEBUG
2203 /* Prints use cases and mixer controls parsed from config files */
2204 snd_ucm_print((*uc_mgr));
2205#endif
2206 if(ret < 0)
2207 ALOGE("Failed to parse config files: %d", ret);
2208 ALOGE("Exiting parsing thread uc_mgr %p\n", uc_mgr);
2209 return NULL;
2210}
2211
2212/* Function can be used by UCM clients to wait until parsing completes
2213 * uc_mgr - use case manager structure
2214 * Returns 0 on success, error number otherwise
2215*/
2216int snd_use_case_mgr_wait_for_parsing(snd_use_case_mgr_t *uc_mgr)
2217{
2218 int ret;
2219
2220 ret = pthread_join(uc_mgr->thr, NULL);
2221 return ret;
2222}
2223
2224/* Parse config files and update mixer controls for the use cases
2225 * 1st stage parsing done to parse HiFi config file
2226 * uc_mgr - use case manager structure
2227 * Returns 0 on sucess, negative error code otherwise
2228 */
2229static int snd_ucm_parse(snd_use_case_mgr_t **uc_mgr)
2230{
2231 use_case_verb_t *verb_list;
2232 struct stat st;
2233 int fd, verb_count, index = 0, ret = 0, rc;
2234 char *read_buf, *next_str, *current_str, *buf, *p, *verb_name;
2235 char *file_name = NULL, *temp_ptr;
2236 char path[200];
2237
2238 strlcpy(path, CONFIG_DIR, (strlen(CONFIG_DIR)+1));
2239 strlcat(path, (*uc_mgr)->card_ctxt_ptr->card_name, sizeof(path));
2240 ALOGV("master config file path:%s", path);
2241 fd = open(path, O_RDONLY);
2242 if (fd < 0) {
2243 ALOGE("failed to open config file %s error %d\n", path, errno);
2244 return -EINVAL;
2245 }
2246 if (fstat(fd, &st) < 0) {
2247 ALOGE("failed to stat %s error %d\n", path, errno);
2248 close(fd);
2249 return -EINVAL;
2250 }
2251 read_buf = (char *) mmap(0, st.st_size, PROT_READ | PROT_WRITE,
2252 MAP_PRIVATE, fd, 0);
2253 if (read_buf == MAP_FAILED) {
2254 ALOGE("failed to mmap file error %d\n", errno);
2255 close(fd);
2256 return -EINVAL;
2257 }
2258 current_str = read_buf;
2259 verb_count = get_verb_count(current_str);
2260 (*uc_mgr)->card_ctxt_ptr->use_case_verb_list =
2261 (use_case_verb_t *)malloc((verb_count+1)*(sizeof(use_case_verb_t)));
2262 if ((*uc_mgr)->card_ctxt_ptr->use_case_verb_list == NULL) {
2263 ALOGE("failed to allocate memory for use case verb list\n");
2264 munmap(read_buf, st.st_size);
2265 close(fd);
2266 return -ENOMEM;
2267 }
2268 if (((*uc_mgr)->card_ctxt_ptr->verb_list =
2269 (char **)malloc((verb_count+2)*(sizeof(char *)))) == NULL) {
2270 ALOGE("failed to allocate memory for verb list\n");
2271 munmap(read_buf, st.st_size);
2272 close(fd);
2273 return -ENOMEM;
2274 }
2275 verb_name = NULL;
2276 if ((ret = is_single_config_format(current_str))) {
2277 ALOGD("Single config file format detected\n");
2278 ret = parse_single_config_format(uc_mgr, current_str, verb_count);
2279 munmap(read_buf, st.st_size);
2280 close(fd);
2281 return ret;
2282 }
2283 while (*current_str != (char)EOF) {
2284 next_str = strchr(current_str, '\n');
2285 if (!next_str)
2286 break;
2287 *next_str++ = '\0';
2288 if (verb_name == NULL) {
2289 buf = strstr(current_str, "SectionUseCase");
2290 if (buf == NULL) {
2291 if((current_str = next_str) == NULL)
2292 break;
2293 else
2294 continue;
2295 }
2296 verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
2297 p = strtok_r(buf, ".", &temp_ptr);
2298 while (p != NULL) {
2299 p = strtok_r(NULL, "\"", &temp_ptr);
2300 if (p == NULL)
2301 break;
2302 verb_name = (char *)malloc((strlen(p)+1)*sizeof(char));
2303 if(verb_name == NULL) {
2304 ret = -ENOMEM;
2305 break;
2306 }
2307 strlcpy(verb_name, p, (strlen(p)+1)*sizeof(char));
2308 if ((verb_list[index].use_case_name =
2309 (char *)malloc((strlen(verb_name)+1)*sizeof(char)))) {
2310 strlcpy(verb_list[index].use_case_name,
2311 verb_name, ((strlen(verb_name)+1)*sizeof(char)));
2312 } else {
2313 ret = -ENOMEM;
2314 break;
2315 }
2316 if (((*uc_mgr)->card_ctxt_ptr->verb_list[index] =
2317 (char *)malloc((strlen(verb_name)+1)*sizeof(char)))) {
2318 strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index],
2319 verb_name, ((strlen(verb_name)+1)*sizeof(char)));
2320 } else {
2321 ret = -ENOMEM;
2322 break;
2323 }
2324 break;
2325 }
2326 } else {
2327 buf = strstr(current_str, "File");
2328 if (buf == NULL) {
2329 if((current_str = next_str) == NULL)
2330 break;
2331 else
2332 continue;
2333 }
2334 p = strtok_r(buf, "\"", &temp_ptr);
2335 while (p != NULL) {
2336 p = strtok_r(NULL, "\"", &temp_ptr);
2337 if (p == NULL)
2338 break;
2339 file_name = (char *)malloc((strlen(p)+1)*sizeof(char));
2340 if(file_name == NULL) {
2341 ret = -ENOMEM;
2342 break;
2343 }
2344 strlcpy(file_name, p, (strlen(p)+1)*sizeof(char));
2345 break;
2346 }
2347 if (file_name != NULL) {
2348 ret = snd_ucm_parse_verb(uc_mgr, file_name, index);
2349 if (ret < 0)
2350 ALOGE("Failed to parse config file %s\n", file_name);
2351 free(verb_name);
2352 verb_name = NULL;
2353 free(file_name);
2354 file_name = NULL;
2355 }
2356 index++;
2357 /* Break here so that only one first use case config file (HiFi)
2358 * from master config file is parsed initially and all other
2359 * config files are parsed in seperate thread created below so
2360 * that audio HAL can initialize faster during boot-up
2361 */
2362 break;
2363 }
2364 if((current_str = next_str) == NULL)
2365 break;
2366 }
2367 munmap(read_buf, st.st_size);
2368 close(fd);
2369 if (((*uc_mgr)->card_ctxt_ptr->verb_list[index] =
2370 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)))) {
2371 strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index], SND_UCM_END_OF_LIST,
2372 ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
2373 } else {
2374 ALOGE("Failed to allocate memory\n");
2375 ret = -ENOMEM;
2376 }
2377 if (!ret) {
2378 ALOGD("Creating Parsing thread uc_mgr %p\n", uc_mgr);
2379 rc = pthread_create(&(*uc_mgr)->thr, 0, second_stage_parsing_thread,
2380 (void*)(*uc_mgr));
2381 if(rc < 0) {
2382 ALOGE("Failed to create parsing thread rc %d errno %d\n", rc, errno);
2383 } else {
2384 ALOGV("Prasing thread created successfully\n");
2385 }
2386 }
2387 if (verb_name)
2388 free(verb_name);
2389 if (file_name)
2390 free(file_name);
2391 return ret;
2392}
2393
2394/* Parse a single config file format
2395 * uc_mgr - use case manager structure
2396 * buf - config file buffer to be parsed
2397 * Returns 0 on sucess, negative error code otherwise
2398 */
2399static int parse_single_config_format(snd_use_case_mgr_t **uc_mgr,
2400char *current_str, int num_verbs)
2401{
2402 struct stat st;
2403 card_mctrl_t *list;
2404 use_case_verb_t *verb_list;
2405 int verb_count = 0, device_count = 0, mod_count = 0, index = -1, ret = 0;
2406 char *next_str, *buf, *p, *verb_ptr, *temp_ptr;
2407
2408 verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
2409 while (*current_str != (char)EOF) {
2410 next_str = strchr(current_str, '\n');
2411 if (!next_str)
2412 break;
2413 *next_str++ = '\0';
2414 if ((buf = strcasestr(current_str, "SectionUseCase")) != NULL) {
2415 if (index != -1) {
2416 list = (verb_list[index].verb_ctrls +
2417 verb_list[index].verb_count);
2418 list->case_name = (char *)
2419 malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2420 if(list->case_name == NULL) {
2421 free(verb_list[index].verb_ctrls);
2422 return -ENOMEM;
2423 }
2424 strlcpy(list->case_name, SND_UCM_END_OF_LIST,
2425 (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2426 list->ena_mixer_list = NULL;
2427 list->dis_mixer_list = NULL;
2428 list->ena_mixer_count = 0;
2429 list->dis_mixer_count = 0;
2430 list->playback_dev_name = NULL;
2431 list->capture_dev_name = NULL;
2432 list->acdb_id = 0;
2433 list->capability = 0;
2434 }
2435 index++;
2436 p = strtok_r(buf, ".", &temp_ptr);
2437 while (p != NULL) {
2438 p = strtok_r(NULL, "\"", &temp_ptr);
2439 if (p == NULL)
2440 break;
2441 if ((verb_list[index].use_case_name =
2442 (char *)malloc((strlen(p)+1)*sizeof(char)))) {
2443 strlcpy(verb_list[index].use_case_name,
2444 p, ((strlen(p)+1)*sizeof(char)));
2445 } else {
2446 ret = -ENOMEM;
2447 break;
2448 }
2449 if (((*uc_mgr)->card_ctxt_ptr->verb_list[index] =
2450 (char *)malloc((strlen(p)+1)*sizeof(char)))) {
2451 strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index],
2452 p, ((strlen(p)+1)*sizeof(char)));
2453 } else {
2454 ret = -ENOMEM;
2455 break;
2456 }
2457 break;
2458 }
2459 verb_list[index].verb_count = 0;
2460 verb_list[index].device_count = 0;
2461 verb_list[index].mod_count = 0;
2462 verb_list[index].device_list = NULL;
2463 verb_list[index].modifier_list = NULL;
2464 verb_list[index].verb_ctrls = NULL;
2465 verb_list[index].device_ctrls = NULL;
2466 verb_list[index].mod_ctrls = NULL;
2467 verb_count = get_num_verbs_config_format(next_str);
2468 verb_list[index].verb_ctrls = (card_mctrl_t *)
2469 malloc((verb_count+1)*sizeof(card_mctrl_t));
2470 if (verb_list[index].verb_ctrls == NULL) {
2471 ret = -ENOMEM;
2472 break;
2473 }
2474 verb_list[index].verb_count = 0;
2475 } else if (!strncasecmp(current_str, "SectionVerb", 11)) {
2476 ret = snd_ucm_parse_section(uc_mgr, &current_str,
2477 &next_str, index, CTRL_LIST_VERB);
2478 if (ret < 0)
2479 break;
2480 } else if (!strncasecmp(current_str, "SectionDevice", 13)) {
2481 if (device_count == 0) {
2482 device_count = get_num_device_config_format(next_str);
2483 verb_list[0].device_ctrls = (card_mctrl_t *)
2484 malloc((device_count+1)*sizeof(card_mctrl_t));
2485 if (verb_list[0].device_ctrls == NULL) {
2486 ret = -ENOMEM;
2487 break;
2488 }
2489 verb_list[0].device_list =
2490 (char **)malloc((device_count+1)*sizeof(char *));
2491 if (verb_list[0].device_list == NULL)
2492 return -ENOMEM;
2493 verb_list[0].device_count = 0;
2494 }
2495 ret = snd_ucm_parse_section(uc_mgr, &current_str,
2496 &next_str, 0, CTRL_LIST_DEVICE);
2497 if (ret < 0) {
2498 break;
2499 } else {
2500 list = (verb_list[0].device_ctrls +
2501 (verb_list[0].device_count - 1));
2502 verb_ptr = (char *)
2503 malloc((strlen(list->case_name)+1)*sizeof(char));
2504 if (verb_ptr == NULL) {
2505 ret = -ENOMEM;
2506 break;
2507 }
2508 strlcpy(verb_ptr, list->case_name,
2509 ((strlen(list->case_name)+1)*sizeof(char)));
2510 verb_list[0].device_list[(verb_list[0].device_count-1)]
2511 = verb_ptr;
2512 }
2513 } else if (!strncasecmp(current_str, "SectionModifier", 15)) {
2514 if (mod_count == 0) {
2515 mod_count = get_num_mod_config_format(next_str);
2516 verb_list[0].mod_ctrls = (card_mctrl_t *)
2517 malloc((mod_count+1)*sizeof(card_mctrl_t));
2518 if (verb_list[0].mod_ctrls == NULL) {
2519 ret = -ENOMEM;
2520 break;
2521 }
2522 verb_list[0].modifier_list =
2523 (char **)malloc((mod_count+1)*sizeof(char *));
2524 if (verb_list[0].modifier_list == NULL)
2525 return -ENOMEM;
2526 verb_list[0].mod_count = 0;
2527 }
2528 ret = snd_ucm_parse_section(uc_mgr, &current_str,
2529 &next_str, 0, CTRL_LIST_MODIFIER);
2530 if (ret < 0) {
2531 break;
2532 } else {
2533 list = (verb_list[0].mod_ctrls +
2534 (verb_list[0].mod_count - 1));
2535 verb_ptr = (char *)
2536 malloc((strlen(list->case_name)+1)*sizeof(char));
2537 if (verb_ptr == NULL) {
2538 ret = -ENOMEM;
2539 break;
2540 }
2541 strlcpy(verb_ptr, list->case_name,
2542 ((strlen(list->case_name)+1)*sizeof(char)));
2543 verb_list[0].modifier_list[(verb_list[0].mod_count - 1)]
2544 = verb_ptr;
2545 }
2546 }
2547 if((current_str = next_str) == NULL)
2548 break;
2549 }
2550 list = (verb_list[index].verb_ctrls +
2551 verb_list[index].verb_count);
2552 list->case_name =
2553 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2554 if(list->case_name == NULL) {
2555 free(verb_list[index].verb_ctrls);
2556 return -ENOMEM;
2557 }
2558 strlcpy(list->case_name, SND_UCM_END_OF_LIST,
2559 (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2560 list->ena_mixer_list = NULL;
2561 list->dis_mixer_list = NULL;
2562 list->ena_mixer_count = 0;
2563 list->dis_mixer_count = 0;
2564 list->playback_dev_name = NULL;
2565 list->capture_dev_name = NULL;
2566 list->acdb_id = 0;
2567 list->capability = 0;
2568 index++;
2569 if (index != -1) {
2570 if (((*uc_mgr)->card_ctxt_ptr->verb_list[index] =
2571 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)))) {
2572 strlcpy((*uc_mgr)->card_ctxt_ptr->verb_list[index],
2573 SND_UCM_END_OF_LIST,
2574 ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
2575 } else {
2576 ALOGE("Failed to allocate memory\n");
2577 ret = -ENOMEM;
2578 }
2579 }
2580 /* Add end of list to device list */
2581 verb_ptr =
2582 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2583 if (verb_ptr == NULL)
2584 return -ENOMEM;
2585 strlcpy(verb_ptr, SND_UCM_END_OF_LIST,
2586 ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
2587 verb_list[0].device_list[verb_list[0].device_count] = verb_ptr;
2588 /* Add end of list to modifier list */
2589 verb_ptr =
2590 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2591 if (verb_ptr == NULL)
2592 return -ENOMEM;
2593 strlcpy(verb_ptr, SND_UCM_END_OF_LIST,
2594 ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
2595 verb_list[0].modifier_list[verb_list[0].mod_count] = verb_ptr;
2596 /* Add end of list to device controls list */
2597 list = (verb_list[0].device_ctrls +
2598 verb_list[0].device_count);
2599 list->case_name =
2600 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2601 if(list->case_name == NULL) {
2602 free(verb_list[0].device_ctrls);
2603 return -ENOMEM;
2604 }
2605 strlcpy(list->case_name, SND_UCM_END_OF_LIST,
2606 (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2607 list->ena_mixer_list = NULL;
2608 list->dis_mixer_list = NULL;
2609 list->ena_mixer_count = 0;
2610 list->dis_mixer_count = 0;
2611 list->playback_dev_name = NULL;
2612 list->capture_dev_name = NULL;
2613 list->acdb_id = 0;
2614 list->capability = 0;
2615 /* Add end of list to modifier controls list */
2616 list = (verb_list[0].mod_ctrls +
2617 verb_list[0].mod_count);
2618 list->case_name =
2619 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2620 if(list->case_name == NULL) {
2621 free(verb_list[0].mod_ctrls);
2622 return -ENOMEM;
2623 }
2624 strlcpy(list->case_name, SND_UCM_END_OF_LIST,
2625 (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2626 list->ena_mixer_list = NULL;
2627 list->dis_mixer_list = NULL;
2628 list->ena_mixer_count = 0;
2629 list->dis_mixer_count = 0;
2630 list->playback_dev_name = NULL;
2631 list->capture_dev_name = NULL;
2632 list->acdb_id = 0;
2633 list->capability = 0;
2634 for (index = 1; index < num_verbs; index++) {
2635 verb_list[index].device_ctrls = verb_list[0].device_ctrls;
2636 verb_list[index].device_list = verb_list[0].device_list;
2637 verb_list[index].device_count = verb_list[0].device_count;
2638 verb_list[index].mod_ctrls = verb_list[0].mod_ctrls;
2639 verb_list[index].modifier_list = verb_list[0].modifier_list;
2640 verb_list[index].mod_count = verb_list[0].mod_count;
2641 }
2642 if (ret < 0) {
2643 ALOGE("Failed to parse config file ret %d errno %d\n", ret, errno);
2644 } else {
2645 ALOGV("Prasing done successfully\n");
2646#if PARSE_DEBUG
2647 /* Prints use cases and mixer controls parsed from config files */
2648 snd_ucm_print((*uc_mgr));
2649#endif
2650 }
2651 return ret;
2652}
2653
2654/* Returns number of verb sections for specific use case verb*/
2655static int get_num_verbs_config_format(const char *nxt_str)
2656{
2657 char *current_str, *next_str, *str_addr, *buf;
2658 int count = 0;
2659
2660 next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
2661 if (next_str == NULL) {
2662 ALOGE("Failed to allocate memory");
2663 return -ENOMEM;
2664 }
2665 strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
2666 str_addr = next_str;
2667 current_str = next_str;
2668 while(1) {
2669 next_str = strchr(current_str, '\n');
2670 if (!next_str)
2671 break;
2672 *next_str++ = '\0';
2673 buf = strcasestr(current_str, "SectionUseCase");
2674 if (buf != NULL)
2675 break;
2676 buf = strcasestr(current_str, "SectionVerb");
2677 if (buf != NULL)
2678 count++;
2679 if (*next_str == (char)EOF)
2680 break;
2681 if((current_str = next_str) == NULL)
2682 break;
2683 }
2684 free(str_addr);
2685 return count;
2686}
2687
2688/* Returns number of common device sections for all use case verbs*/
2689static int get_num_device_config_format(const char *nxt_str)
2690{
2691 char *current_str, *next_str, *str_addr, *buf;
2692 int count = 1;
2693
2694 next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
2695 if (next_str == NULL) {
2696 ALOGE("Failed to allocate memory");
2697 return -ENOMEM;
2698 }
2699 strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
2700 str_addr = next_str;
2701 current_str = next_str;
2702 while(1) {
2703 next_str = strchr(current_str, '\n');
2704 if (!next_str)
2705 break;
2706 *next_str++ = '\0';
2707 buf = strcasestr(current_str, "SectionDevice");
2708 if (buf != NULL)
2709 count++;
2710 if (*next_str == (char)EOF)
2711 break;
2712 if((current_str = next_str) == NULL)
2713 break;
2714 }
2715 free(str_addr);
2716 return count;
2717}
2718
2719/* Returns number of common modifier sections for all use case verbs*/
2720static int get_num_mod_config_format(const char *nxt_str)
2721{
2722 char *current_str, *next_str, *str_addr, *buf;
2723 int count = 1;
2724
2725 next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
2726 if (next_str == NULL) {
2727 ALOGE("Failed to allocate memory");
2728 return -ENOMEM;
2729 }
2730 strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
2731 str_addr = next_str;
2732 current_str = next_str;
2733 while(1) {
2734 next_str = strchr(current_str, '\n');
2735 if (!next_str)
2736 break;
2737 *next_str++ = '\0';
2738 buf = strcasestr(current_str, "SectionModifier");
2739 if (buf != NULL)
2740 count++;
2741 if (*next_str == (char)EOF)
2742 break;
2743 if((current_str = next_str) == NULL)
2744 break;
2745 }
2746 free(str_addr);
2747 return count;
2748}
2749
2750/* Gets the number of use case verbs defined by master config file */
2751static int get_verb_count(const char *nxt_str)
2752{
2753 char *current_str, *next_str, *str_addr, *buf, *p;
2754 int count = 0;
2755
2756 next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
2757 if (next_str == NULL) {
2758 ALOGE("Failed to allocate memory");
2759 return -ENOMEM;
2760 }
2761 strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
2762 str_addr = next_str;
2763 current_str = next_str;
2764 while(1) {
2765 next_str = strchr(current_str, '\n');
2766 if (!next_str)
2767 break;
2768 *next_str++ = '\0';
2769 buf = strstr(current_str, "SectionUseCase");
2770 if (buf != NULL)
2771 count++;
2772 if (*next_str == (char)EOF)
2773 break;
2774 if((current_str = next_str) == NULL)
2775 break;
2776 }
2777 free(str_addr);
2778 return count;
2779}
2780
2781/* Returns one if single config file per sound card format is being used */
2782static int is_single_config_format(const char *nxt_str)
2783{
2784 char *current_str, *next_str, *str_addr, *buf;
2785 int ret = 1, count = 0;
2786
2787 next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
2788 if (next_str == NULL) {
2789 ALOGE("Failed to allocate memory");
2790 return -ENOMEM;
2791 }
2792 strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
2793 str_addr = next_str;
2794 current_str = next_str;
2795 while(1) {
2796 next_str = strchr(current_str, '\n');
2797 if (!next_str)
2798 break;
2799 *next_str++ = '\0';
2800 buf = strstr(current_str, "SectionUseCase");
2801 if (buf != NULL)
2802 count++;
2803 buf = strstr(current_str, "File");
2804 if (buf != NULL)
2805 ret = 0;
2806 if ((*next_str == (char)EOF) || (count == 2))
2807 break;
2808 if((current_str = next_str) == NULL)
2809 break;
2810 }
2811 free(str_addr);
2812 return ret;
2813}
2814
2815/* Parse a use case verb config files and update mixer controls for the verb
2816 * uc_mgr - use case manager structure
2817 * file_name - use case verb config file name
2818 * index - index of the verb in the list
2819 * Returns 0 on sucess, negative error code otherwise
2820 */
2821static int snd_ucm_parse_verb(snd_use_case_mgr_t **uc_mgr,
2822const char *file_name, int index)
2823{
2824 struct stat st;
2825 card_mctrl_t *list;
2826 int device_count, modifier_count;
2827 int fd, ret = 0, parse_count = 0;
2828 char *read_buf, *next_str, *current_str, *verb_ptr;
2829 char path[200];
2830 use_case_verb_t *verb_list;
2831
2832 strlcpy(path, CONFIG_DIR, (strlen(CONFIG_DIR)+1));
2833 strlcat(path, file_name, sizeof(path));
2834 ALOGV("path:%s", path);
2835 verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
2836 while(1) {
2837 device_count = 0; modifier_count = 0;
2838 if (parse_count == 0) {
2839 verb_list[index].verb_count = 0;
2840 verb_list[index].device_count = 0;
2841 verb_list[index].mod_count = 0;
2842 verb_list[index].device_list = NULL;
2843 verb_list[index].modifier_list = NULL;
2844 verb_list[index].verb_ctrls = NULL;
2845 verb_list[index].device_ctrls = NULL;
2846 verb_list[index].mod_ctrls = NULL;
2847 }
2848 fd = open(path, O_RDONLY);
2849 if (fd < 0) {
2850 ALOGE("failed to open config file %s error %d\n", path, errno);
2851 return -EINVAL;
2852 }
2853 if (fstat(fd, &st) < 0) {
2854 ALOGE("failed to stat %s error %d\n", path, errno);
2855 close(fd);
2856 return -EINVAL;
2857 }
2858 read_buf = (char *) mmap(0, st.st_size, PROT_READ | PROT_WRITE,
2859 MAP_PRIVATE, fd, 0);
2860 if (read_buf == MAP_FAILED) {
2861 ALOGE("failed to mmap file error %d\n", errno);
2862 close(fd);
2863 return -EINVAL;
2864 }
2865 current_str = read_buf;
2866 while (*current_str != (char)EOF) {
2867 next_str = strchr(current_str, '\n');
2868 if (!next_str)
2869 break;
2870 *next_str++ = '\0';
2871 if (!strncasecmp(current_str, "SectionVerb", 11)) {
2872 if (parse_count == 0) {
2873 verb_list[index].verb_count++;
2874 } else {
2875 ret = snd_ucm_parse_section(uc_mgr, &current_str,
2876 &next_str, index, CTRL_LIST_VERB);
2877 if (ret < 0)
2878 break;
2879 }
2880 } else if (!strncasecmp(current_str, "SectionDevice", 13)) {
2881 if (parse_count == 0) {
2882 verb_list[index].device_count++;
2883 device_count++;
2884 } else {
2885 ret = snd_ucm_parse_section(uc_mgr, &current_str,
2886 &next_str, index, CTRL_LIST_DEVICE);
2887 if (ret < 0) {
2888 break;
2889 } else {
2890 list = (verb_list[index].device_ctrls +
2891 (verb_list[index].device_count - 1));
2892 verb_ptr = (char *)
2893 malloc((strlen(list->case_name)+1)*sizeof(char));
2894 if (verb_ptr == NULL) {
2895 ret = -ENOMEM;
2896 break;
2897 }
2898 strlcpy(verb_ptr, list->case_name,
2899 ((strlen(list->case_name)+1)*sizeof(char)));
2900 verb_list[index].device_list[device_count] = verb_ptr;
2901 device_count++;
2902 }
2903 }
2904 } else if (!strncasecmp(current_str, "SectionModifier", 15)) {
2905 if (parse_count == 0) {
2906 verb_list[index].mod_count++;
2907 modifier_count++;
2908 } else {
2909 ret = snd_ucm_parse_section(uc_mgr, &current_str,
2910 &next_str, index, CTRL_LIST_MODIFIER);
2911 if (ret < 0) {
2912 break;
2913 } else {
2914 list = (verb_list[index].mod_ctrls +
2915 (verb_list[index].mod_count - 1));
2916 verb_ptr = (char *)
2917 malloc((strlen(list->case_name)+1)*sizeof(char));
2918 if (verb_ptr == NULL) {
2919 ret = -ENOMEM;
2920 break;
2921 }
2922 strlcpy(verb_ptr, list->case_name,
2923 ((strlen(list->case_name)+1)*sizeof(char)));
2924 verb_list[index].modifier_list[modifier_count]
2925 = verb_ptr;
2926 modifier_count++;
2927 }
2928 }
2929 }
2930 if((current_str = next_str) == NULL)
2931 break;
2932 }
2933 munmap(read_buf, st.st_size);
2934 close(fd);
2935 if(ret < 0)
2936 return ret;
2937 if (parse_count == 0) {
2938 verb_list[index].device_list =
2939 (char **)malloc((device_count+1)*sizeof(char *));
2940 if (verb_list[index].device_list == NULL)
2941 return -ENOMEM;
2942 verb_list[index].modifier_list =
2943 (char **)malloc((modifier_count+1)*sizeof(char *));
2944 if (verb_list[index].modifier_list == NULL)
2945 return -ENOMEM;
2946 parse_count += verb_list[index].verb_count;
2947 verb_list[index].verb_ctrls = (card_mctrl_t *)
2948 malloc((verb_list[index].verb_count+1)*sizeof(card_mctrl_t));
2949 if (verb_list[index].verb_ctrls == NULL) {
2950 ret = -ENOMEM;
2951 break;
2952 }
2953 verb_list[index].verb_count = 0;
2954 parse_count += verb_list[index].device_count;
2955 verb_list[index].device_ctrls = (card_mctrl_t *)
2956 malloc((verb_list[index].device_count+1)*sizeof(card_mctrl_t));
2957 if (verb_list[index].device_ctrls == NULL) {
2958 ret = -ENOMEM;
2959 break;
2960 }
2961 verb_list[index].device_count = 0;
2962 parse_count += verb_list[index].mod_count;
2963 verb_list[index].mod_ctrls = (card_mctrl_t *)
2964 malloc((verb_list[index].mod_count+1)*sizeof(card_mctrl_t));
2965 if (verb_list[index].mod_ctrls == NULL) {
2966 ret = -ENOMEM;
2967 break;
2968 }
2969 verb_list[index].mod_count = 0;
2970 continue;
2971 } else {
2972 verb_ptr =
2973 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2974 if (verb_ptr == NULL)
2975 return -ENOMEM;
2976 strlcpy(verb_ptr, SND_UCM_END_OF_LIST,
2977 ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
2978 verb_list[index].device_list[device_count] = verb_ptr;
2979 verb_ptr =
2980 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2981 if (verb_ptr == NULL)
2982 return -ENOMEM;
2983 strlcpy(verb_ptr, SND_UCM_END_OF_LIST,
2984 ((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char)));
2985 verb_list[index].modifier_list[modifier_count] = verb_ptr;
2986 list = (verb_list[index].verb_ctrls +
2987 verb_list[index].verb_count);
2988 list->case_name =
2989 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2990 if(list->case_name == NULL) {
2991 free(verb_list[index].verb_ctrls);
2992 return -ENOMEM;
2993 }
2994 strlcpy(list->case_name, SND_UCM_END_OF_LIST,
2995 (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
2996 list->ena_mixer_list = NULL;
2997 list->dis_mixer_list = NULL;
2998 list->ena_mixer_count = 0;
2999 list->dis_mixer_count = 0;
3000 list->playback_dev_name = NULL;
3001 list->capture_dev_name = NULL;
3002 list->acdb_id = 0;
3003 list->capability = 0;
3004 list = (verb_list[index].device_ctrls +
3005 verb_list[index].device_count);
3006 list->case_name =
3007 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
3008 if(list->case_name == NULL) {
3009 free(verb_list[index].device_ctrls);
3010 return -ENOMEM;
3011 }
3012 strlcpy(list->case_name, SND_UCM_END_OF_LIST,
3013 (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
3014 list->ena_mixer_list = NULL;
3015 list->dis_mixer_list = NULL;
3016 list->ena_mixer_count = 0;
3017 list->dis_mixer_count = 0;
3018 list->playback_dev_name = NULL;
3019 list->capture_dev_name = NULL;
3020 list->acdb_id = 0;
3021 list->capability = 0;
3022 list = (verb_list[index].mod_ctrls +
3023 verb_list[index].mod_count);
3024 list->case_name =
3025 (char *)malloc((strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
3026 if(list->case_name == NULL) {
3027 free(verb_list[index].mod_ctrls);
3028 return -ENOMEM;
3029 }
3030 strlcpy(list->case_name, SND_UCM_END_OF_LIST,
3031 (strlen(SND_UCM_END_OF_LIST)+1)*sizeof(char));
3032 list->ena_mixer_list = NULL;
3033 list->dis_mixer_list = NULL;
3034 list->ena_mixer_count = 0;
3035 list->dis_mixer_count = 0;
3036 list->playback_dev_name = NULL;
3037 list->capture_dev_name = NULL;
3038 list->acdb_id = 0;
3039 list->capability = 0;
3040 parse_count = 0;
3041 break;
3042 }
3043 }
3044 return ret;
3045}
3046
3047/* Print mixer controls in a specific list
3048 * list - list to be printed
3049 * verb_index - verb index
3050 * count - number of elements in the list
3051 * Returns 0 on sucess, negative error code otherwise
3052 */
3053static int print_list(card_mctrl_t *list, int verb_index, int count)
3054{
3055 int i, j;
3056
3057 for(i=0; i < count; i++) {
3058 ALOGD("\tcase name: %s\n", list[i].case_name);
3059 ALOGD("\tEnable sequence: %d\n", list[i].ena_mixer_count);
3060 for(j=0; j<list[i].ena_mixer_count; j++) {
SathishKumar Mani0a019912012-09-11 12:33:11 -07003061 ALOGD("\t\t%s : %d : %d: %s\n",
Iliyan Malchev4765c432012-06-11 14:36:16 -07003062 list[i].ena_mixer_list[j].control_name,
3063 list[i].ena_mixer_list[j].type,
3064 list[i].ena_mixer_list[j].value,
3065 list[i].ena_mixer_list[j].string);
3066 }
3067 ALOGD("\tDisable sequence: %d\n", list[i].dis_mixer_count);
3068 for(j=0; j<list[i].dis_mixer_count; j++) {
SathishKumar Mani0a019912012-09-11 12:33:11 -07003069 ALOGD("\t\t%s : %d : %d : %s\n",
Iliyan Malchev4765c432012-06-11 14:36:16 -07003070 list[i].dis_mixer_list[j].control_name,
3071 list[i].dis_mixer_list[j].type,
3072 list[i].dis_mixer_list[j].value,
3073 list[i].dis_mixer_list[j].string);
3074 }
3075 }
3076 return 0;
3077}
3078
3079/* Print mixer controls extracted from config files
3080 * uc_mgr - use case manager structure
3081 * Returns 0 on sucess, negative error code otherwise
3082 */
3083static int snd_ucm_print(snd_use_case_mgr_t *uc_mgr)
3084{
3085 card_mctrl_t *list;
3086 int i, j, verb_index = 0;
3087 use_case_verb_t *verb_list;
3088
3089 pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
3090 verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
3091 while(strncmp(uc_mgr->card_ctxt_ptr->verb_list[verb_index],
3092 SND_UCM_END_OF_LIST, 3)) {
3093 ALOGD("\nuse case verb: %s\n",
3094 uc_mgr->card_ctxt_ptr->verb_list[verb_index]);
3095 if(verb_list[verb_index].device_list) {
3096 ALOGD("\tValid device list:");
3097 i = 0;
3098 while(strncmp(verb_list[verb_index].device_list[i],
3099 SND_UCM_END_OF_LIST, 3)) {
3100 ALOGD("\t\t%s", verb_list[verb_index].device_list[i]);
3101 i++;
3102 }
3103 }
3104 if(verb_list[verb_index].modifier_list) {
3105 ALOGD("\tValid modifier list:");
3106 i = 0;
3107 while(strncmp(verb_list[verb_index].modifier_list[i],
3108 SND_UCM_END_OF_LIST, 3)) {
3109 ALOGD("\t\t%s", verb_list[verb_index].modifier_list[i]);
3110 i++;
3111 }
3112 }
3113 ALOGD("Verbs:\n");
3114 list = verb_list[verb_index].verb_ctrls;
3115 print_list(list, verb_index, verb_list[verb_index].verb_count);
3116 ALOGD("Devices:\n");
3117 list = verb_list[verb_index].device_ctrls;
3118 print_list(list, verb_index, verb_list[verb_index].device_count);
3119 ALOGD("Modifier:\n");
3120 list = verb_list[verb_index].mod_ctrls;
3121 print_list(list, verb_index, verb_list[verb_index].mod_count);
3122 verb_index++;
3123 }
3124 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
3125 return 0;
3126}
3127
3128/* Gets the number of controls for specific sequence of a use cae */
3129static int get_controls_count(const char *nxt_str)
3130{
3131 char *current_str, *next_str, *str_addr;
3132 int count = 0;
3133
3134 next_str = (char *)malloc((strlen(nxt_str)+1)*sizeof(char));
3135 if (next_str == NULL) {
3136 ALOGE("Failed to allocate memory");
3137 return -ENOMEM;
3138 }
3139 strlcpy(next_str, nxt_str, ((strlen(nxt_str)+1)*sizeof(char)));
3140 str_addr = next_str;
3141 while(1) {
3142 current_str = next_str;
3143 next_str = strchr(current_str, '\n');
3144 if ((!next_str) || (!strncasecmp(current_str, "EndSection", 10)))
3145 break;
3146 *next_str++ = '\0';
3147 if (strcasestr(current_str, "EndSequence") != NULL) {
3148 break;
3149 } else {
3150 count++;
3151 }
3152 if (*next_str == (char)EOF)
3153 break;
3154 if(!strncasecmp(current_str, "EndSection", 10))
3155 break;
3156 }
3157 free(str_addr);
3158 return count;
3159}
3160
3161/* Parse a section of config files
3162 * uc_mgr - use case manager structure
3163 * Returns 0 on sucess, negative error code otherwise
3164 */
3165static int snd_ucm_parse_section(snd_use_case_mgr_t **uc_mgr, char **cur_str,
3166char **nxt_str, int verb_index, int ctrl_list_type)
3167{
3168 use_case_verb_t *verb_list;
3169 card_mctrl_t *list;
3170 int enable_seq = 0, disable_seq = 0, controls_count = 0, ret = 0;
3171 char *p, *current_str, *next_str, *name;
3172
3173 verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
3174 if (ctrl_list_type == CTRL_LIST_VERB) {
3175 list = (verb_list[verb_index].verb_ctrls +
3176 verb_list[verb_index].verb_count);
3177 } else if (ctrl_list_type == CTRL_LIST_DEVICE) {
3178 list = (verb_list[verb_index].device_ctrls +
3179 verb_list[verb_index].device_count);
3180 } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
3181 list = (verb_list[verb_index].mod_ctrls +
3182 verb_list[verb_index].mod_count);
3183 } else {
3184 ALOGE("Invalid list type: %d\n", ctrl_list_type);
3185 return -EINVAL;
3186 }
3187 list->case_name = NULL;
3188 list->ena_mixer_list = NULL;
3189 list->dis_mixer_list = NULL;
3190 list->ena_mixer_count = 0;
3191 list->dis_mixer_count = 0;
3192 list->playback_dev_name = NULL;
3193 list->capture_dev_name = NULL;
3194 list->acdb_id = 0;
3195 list->capability = 0;
3196 list->effects_mixer_ctl = NULL;
3197 current_str = *cur_str; next_str = *nxt_str;
3198 while(strncasecmp(current_str, "EndSection", 10)) {
3199 current_str = next_str;
3200 next_str = strchr(current_str, '\n');
3201 if ((!next_str) || (!strncasecmp(current_str, "EndSection", 10)))
3202 break;
3203 *next_str++ = '\0';
3204 if (strcasestr(current_str, "EndSequence") != NULL) {
3205 if (enable_seq == 1)
3206 enable_seq = 0;
3207 else if (disable_seq == 1)
3208 disable_seq = 0;
3209 else
3210 ALOGE("Error: improper config file\n");
3211 }
3212 if (enable_seq == 1) {
3213 ret = snd_ucm_extract_controls(current_str, &list->ena_mixer_list,
3214 list->ena_mixer_count);
3215 if (ret < 0)
3216 break;
3217 list->ena_mixer_count++;
3218 } else if (disable_seq == 1) {
3219 ret = snd_ucm_extract_controls(current_str, &list->dis_mixer_list,
3220 list->dis_mixer_count);
3221 if (ret < 0)
3222 break;
3223 list->dis_mixer_count++;
3224 } else if (strcasestr(current_str, "Name") != NULL) {
3225 ret = snd_ucm_extract_name(current_str, &list->case_name);
3226 if (ret < 0)
3227 break;
3228 ALOGV("Name of section is %s\n", list->case_name);
3229 } else if (strcasestr(current_str, "PlaybackPCM") != NULL) {
3230 ret = snd_ucm_extract_dev_name(current_str,
3231 &list->playback_dev_name);
3232 if (ret < 0)
3233 break;
3234 ALOGV("Device name of playback is %s\n",
3235 list->playback_dev_name);
3236 } else if (strcasestr(current_str, "CapturePCM") != NULL) {
3237 ret = snd_ucm_extract_dev_name(current_str,
3238 &list->capture_dev_name);
3239 if (ret < 0)
3240 break;
3241 ALOGV("Device name of capture is %s\n", list->capture_dev_name);
3242 } else if (strcasestr(current_str, "ACDBID") != NULL) {
3243 ret = snd_ucm_extract_acdb(current_str, &list->acdb_id,
3244 &list->capability);
3245 if (ret < 0)
3246 break;
3247 ALOGV("ACDB ID: %d CAPABILITY: %d\n", list->acdb_id,
3248 list->capability);
3249 } else if (strcasestr(current_str, "EffectsMixerCTL") != NULL) {
3250 ret = snd_ucm_extract_effects_mixer_ctl(current_str,
3251 &list->effects_mixer_ctl);
3252 if (ret < 0)
3253 break;
3254 ALOGV("Effects mixer ctl: %s: %d\n", list->effects_mixer_ctl);
3255 }
3256 if (strcasestr(current_str, "EnableSequence") != NULL) {
3257 controls_count = get_controls_count(next_str);
3258 if (controls_count < 0) {
3259 ret = -ENOMEM;
3260 break;
3261 }
3262 list->ena_mixer_list =
3263 (mixer_control_t *)malloc((controls_count*sizeof(mixer_control_t)));
3264 if (list->ena_mixer_list == NULL) {
3265 ret = -ENOMEM;
3266 break;
3267 }
3268 enable_seq = 1;
3269 } else if (strcasestr(current_str, "DisableSequence") != NULL) {
3270 controls_count = get_controls_count(next_str);
3271 if (controls_count < 0) {
3272 ret = -ENOMEM;
3273 break;
3274 }
3275 list->dis_mixer_list =
3276 (mixer_control_t *)malloc((controls_count*sizeof(mixer_control_t)));
3277 if (list->dis_mixer_list == NULL) {
3278 ret = -ENOMEM;
3279 break;
3280 }
3281 disable_seq = 1;
3282 }
3283 if (*next_str == (char)EOF)
3284 break;
3285 }
3286 if(ret == 0) {
3287 *cur_str = current_str; *nxt_str = next_str;
3288 if (ctrl_list_type == CTRL_LIST_VERB) {
3289 verb_list[verb_index].verb_count++;
3290 } else if (ctrl_list_type == CTRL_LIST_DEVICE) {
3291 verb_list[verb_index].device_count++;
3292 } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
3293 verb_list[verb_index].mod_count++;
3294 }
3295 }
3296 return ret;
3297}
3298
3299/* Extract a mixer control name from config file
3300 * Returns 0 on sucess, negative error code otherwise
3301 */
3302static int snd_ucm_extract_name(char *buf, char **case_name)
3303{
3304 int ret = 0;
3305 char *p, *name = *case_name, *temp_ptr;
3306
3307 p = strtok_r(buf, "\"", &temp_ptr);
3308 while (p != NULL) {
3309 p = strtok_r(NULL, "\"", &temp_ptr);
3310 if (p == NULL)
3311 break;
3312 name = (char *)malloc((strlen(p)+1)*sizeof(char));
3313 if(name == NULL) {
3314 ret = -ENOMEM;
3315 break;
3316 }
3317 strlcpy(name, p, (strlen(p)+1)*sizeof(char));
3318 *case_name = name;
3319 break;
3320 }
3321 return ret;
3322}
3323
3324/* Extract a ACDB ID and capability of use case from config file
3325 * Returns 0 on sucess, negative error code otherwise
3326 */
3327static int snd_ucm_extract_acdb(char *buf, int *id, int *cap)
3328{
3329 char *p, key[] = "0123456789", *temp_ptr;
3330
3331 p = strpbrk(buf, key);
3332 if (p == NULL) {
3333 *id = 0;
3334 *cap = 0;
3335 } else {
3336 p = strtok_r(p, ":", &temp_ptr);
3337 while (p != NULL) {
3338 *id = atoi(p);
3339 p = strtok_r(NULL, "\0", &temp_ptr);
3340 if (p == NULL)
3341 break;
3342 *cap = atoi(p);
3343 break;
3344 }
3345 }
3346 return 0;
3347}
3348
3349/* Extract Effects Mixer ID of device from config file
3350 * Returns 0 on sucess, negative error code otherwise
3351 */
3352static int snd_ucm_extract_effects_mixer_ctl(char *buf, char **mixer_name)
3353{
3354 int ret = 0;
3355 char *p, *name = *mixer_name, *temp_ptr;
3356
3357 p = strtok_r(buf, "\"", &temp_ptr);
3358 while (p != NULL) {
3359 p = strtok_r(NULL, "\"", &temp_ptr);
3360 if (p == NULL)
3361 break;
3362 name = (char *)malloc((strlen(p)+1)*sizeof(char));
3363 if(name == NULL) {
3364 ret = -ENOMEM;
3365 break;
3366 }
3367 strlcpy(name, p, (strlen(p)+1)*sizeof(char));
3368 *mixer_name = name;
3369 break;
3370 }
3371 return ret;
3372}
3373
3374/* Extract a playback and capture device name of use case from config file
3375 * Returns 0 on sucess, negative error code otherwise
3376 */
3377static int snd_ucm_extract_dev_name(char *buf, char **dev_name)
3378{
3379 char key[] = "0123456789";
3380 char *p, *name = *dev_name;
3381 char dev_pre[] = "hw:0,";
3382 char *temp_ptr;
3383
3384 p = strpbrk(buf, key);
3385 if (p == NULL) {
3386 *dev_name = NULL;
3387 } else {
3388 p = strtok_r(p, "\r\n", &temp_ptr);
3389 if (p == NULL) {
3390 *dev_name = NULL;
3391 } else {
3392 name = (char *)malloc((strlen(p)+strlen(dev_pre)+1)*sizeof(char));
3393 if(name == NULL)
3394 return -ENOMEM;
3395 strlcpy(name, dev_pre, (strlen(p)+strlen(dev_pre)+1)*sizeof(char));
3396 strlcat(name, p, (strlen(p)+strlen(dev_pre)+1)*sizeof(char));
3397 *dev_name = name;
3398 }
3399 }
3400 return 0;
3401}
3402
3403static int get_num_values(const char *buf)
3404{
3405 char *buf_addr, *p;
3406 int count = 0;
3407 char *temp_ptr;
3408
3409 buf_addr = (char *)malloc((strlen(buf)+1)*sizeof(char));
3410 if (buf_addr == NULL) {
3411 ALOGE("Failed to allocate memory");
3412 return -ENOMEM;
3413 }
3414 strlcpy(buf_addr, buf, ((strlen(buf)+1)*sizeof(char)));
3415 p = strtok_r(buf_addr, " ", &temp_ptr);
3416 while (p != NULL) {
3417 count++;
3418 p = strtok_r(NULL, " ", &temp_ptr);
3419 if (p == NULL)
3420 break;
3421 }
3422 free(buf_addr);
3423 return count;
3424}
3425
3426/* Extract a mixer control from config file
3427 * Returns 0 on sucess, negative error code otherwise
3428 */
3429static int snd_ucm_extract_controls(char *buf, mixer_control_t **mixer_list,
3430int size)
3431{
3432 unsigned long temp;
3433 int ret = -EINVAL, i, index = 0, count = 0;
3434 char *p, *ps, *pmv, temp_coeff[20];
3435 mixer_control_t *list;
3436 static const char *const seps = "\r\n";
3437 char *temp_ptr, *temp_vol_ptr;
3438
3439 p = strtok_r(buf, "'", &temp_ptr);
3440 while (p != NULL) {
3441 p = strtok_r(NULL, "'", &temp_ptr);
3442 if (p == NULL)
3443 break;
3444 list = ((*mixer_list)+size);
3445 list->control_name = (char *)malloc((strlen(p)+1)*sizeof(char));
3446 if(list->control_name == NULL) {
3447 ret = -ENOMEM;
3448 free((*mixer_list));
3449 break;
3450 }
3451 strlcpy(list->control_name, p, (strlen(p)+1)*sizeof(char));
3452 p = strtok_r(NULL, ":", &temp_ptr);
3453 if (p == NULL)
3454 break;
3455 if(!strncmp(p, "0", 1)) {
3456 list->type = TYPE_STR;
3457 } else if(!strncmp(p, "1", 1)) {
3458 list->type = TYPE_INT;
3459 } else if(!strncmp(p, "2", 1)) {
3460 list->type = TYPE_MULTI_VAL;
3461 } else {
3462 ALOGE("Unknown type: p %s\n", p);
3463 }
3464 p = strtok_r(NULL, seps, &temp_ptr);
3465 if (p == NULL)
3466 break;
3467 if(list->type == TYPE_INT) {
3468 list->value = atoi(p);
3469 list->string = NULL;
3470 list->mulval = NULL;
3471 } else if(list->type == TYPE_STR) {
3472 list->value = -1;
3473 list->string = (char *)malloc((strlen(p)+1)*sizeof(char));
3474 list->mulval = NULL;
3475 if(list->string == NULL) {
3476 ret = -ENOMEM;
3477 free((*mixer_list));
3478 free(list->control_name);
3479 break;
3480 }
3481 strlcpy(list->string, p, (strlen(p)+1)*sizeof(char));
3482 } else if(list->type == TYPE_MULTI_VAL) {
3483 if (p != NULL) {
3484 count = get_num_values(p);
3485 list->mulval = (char **)malloc(count*sizeof(char *));
3486 if (list->mulval == NULL) {
3487 ret = -ENOMEM;
3488 free((*mixer_list));
3489 free(list->control_name);
3490 break;
3491 }
3492 index = 0;
3493 /* To support volume values in percentage */
3494 if ((count == 1) && (strstr(p, "%") != NULL)) {
3495 pmv = strtok_r(p, " ", &temp_vol_ptr);
3496 while (pmv != NULL) {
3497 list->mulval[index] =
3498 (char *)malloc((strlen(pmv)+1)*sizeof(char));
3499 strlcpy(list->mulval[index], pmv, (strlen(pmv)+1));
3500 index++;
3501 pmv = strtok_r(NULL, " ", &temp_vol_ptr);
3502 if (pmv == NULL)
3503 break;
3504 }
3505 } else {
3506 pmv = strtok_r(p, " ", &temp_vol_ptr);
3507 while (pmv != NULL) {
3508 temp = strtoul(pmv, &ps, 16);
3509 snprintf(temp_coeff, sizeof(temp_coeff),"%lu", temp);
3510 list->mulval[index] =
3511 (char *)malloc((strlen(temp_coeff)+1)*sizeof(char));
3512 strlcpy(list->mulval[index], temp_coeff,
3513 (strlen(temp_coeff)+1));
3514 index++;
3515 pmv = strtok_r(NULL, " ", &temp_vol_ptr);
3516 if (pmv == NULL)
3517 break;
3518 }
3519 }
3520 list->value = count;
3521 list->string = NULL;
3522 }
3523 } else {
3524 ALOGE("Unknown type: p %s\n", p);
3525 list->value = -1;
3526 list->string = NULL;
3527 }
3528 ret = 0;
3529 break;
3530 }
3531 return ret;
3532}
3533
3534void free_list(card_mctrl_t *list, int verb_index, int count)
3535{
3536 int case_index = 0, index = 0, mindex = 0;
3537
3538 for(case_index = 0; case_index < count; case_index++) {
3539 for(index = 0; index < list[case_index].ena_mixer_count; index++) {
3540 if(list[case_index].ena_mixer_list[index].control_name) {
3541 free(list[case_index].ena_mixer_list[index].control_name);
3542 }
3543 if(list[case_index].ena_mixer_list[index].string) {
3544 free(list[case_index].ena_mixer_list[index].string);
3545 }
3546 if(list[case_index].ena_mixer_list[index].mulval) {
3547 for(mindex = 0;
3548 mindex < list[case_index].ena_mixer_list[index].value;
3549 mindex++) {
3550 free(list[case_index].ena_mixer_list[index].mulval[mindex]);
3551 }
Ajay Dudani9746c472012-06-18 16:01:16 -07003552 if(list[case_index].ena_mixer_list[index].mulval) {
3553 free(list[case_index].ena_mixer_list[index].mulval);
3554 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07003555 }
3556 }
3557 for(index = 0; index < list[case_index].dis_mixer_count; index++) {
3558 if(list[case_index].dis_mixer_list[index].control_name) {
3559 free(list[case_index].dis_mixer_list[index].control_name);
3560 }
3561 if(list[case_index].dis_mixer_list[index].string) {
3562 free(list[case_index].dis_mixer_list[index].string);
3563 }
Ajay Dudani9746c472012-06-18 16:01:16 -07003564 if(list[case_index].dis_mixer_list[index].mulval) {
3565 for(mindex = 0;
3566 mindex < list[case_index].dis_mixer_list[index].value;
3567 mindex++) {
3568 free(list[case_index].dis_mixer_list[index].mulval[mindex]);
3569 }
3570 if(list[case_index].dis_mixer_list[index].mulval) {
3571 free(list[case_index].dis_mixer_list[index].mulval);
3572 }
3573 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07003574 }
3575 if(list[case_index].case_name) {
3576 free(list[case_index].case_name);
3577 }
3578 if(list[case_index].ena_mixer_list) {
3579 free(list[case_index].ena_mixer_list);
3580 }
3581 if(list[case_index].dis_mixer_list) {
3582 free(list[case_index].dis_mixer_list);
3583 }
3584 if(list[case_index].playback_dev_name) {
3585 free(list[case_index].playback_dev_name);
3586 }
3587 if(list[case_index].capture_dev_name) {
3588 free(list[case_index].capture_dev_name);
3589 }
Ajay Dudani9746c472012-06-18 16:01:16 -07003590 if(list[case_index].effects_mixer_ctl) {
3591 list[case_index].effects_mixer_ctl = NULL;
3592 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07003593 }
3594}
3595
3596void snd_ucm_free_mixer_list(snd_use_case_mgr_t **uc_mgr)
3597{
3598 card_mctrl_t *ctrl_list;
3599 use_case_verb_t *verb_list;
3600 int index = 0, verb_index = 0;
3601
3602 pthread_mutex_lock(&(*uc_mgr)->card_ctxt_ptr->card_lock);
Ajay Dudani9746c472012-06-18 16:01:16 -07003603 verb_list = (*uc_mgr)->card_ctxt_ptr->use_case_verb_list;
Iliyan Malchev4765c432012-06-11 14:36:16 -07003604 while(strncmp((*uc_mgr)->card_ctxt_ptr->verb_list[verb_index],
3605 SND_UCM_END_OF_LIST, 3)) {
Iliyan Malchev4765c432012-06-11 14:36:16 -07003606 ctrl_list = verb_list[verb_index].verb_ctrls;
3607 free_list(ctrl_list, verb_index, verb_list[verb_index].verb_count);
Iliyan Malchev4765c432012-06-11 14:36:16 -07003608 if(verb_list[verb_index].use_case_name)
3609 free(verb_list[verb_index].use_case_name);
3610 if((*uc_mgr)->card_ctxt_ptr->verb_list[verb_index]) {
3611 free((*uc_mgr)->card_ctxt_ptr->verb_list[verb_index]);
3612 }
3613 verb_index++;
3614 }
Ajay Dudani9746c472012-06-18 16:01:16 -07003615 verb_index -= 1;
3616 ctrl_list = verb_list[verb_index].device_ctrls;
3617 free_list(ctrl_list, verb_index, verb_list[verb_index].device_count);
3618 ctrl_list = verb_list[verb_index].mod_ctrls;
3619 free_list(ctrl_list, verb_index, verb_list[verb_index].mod_count);
3620 index = 0;
3621 while(1) {
3622 if (verb_list[verb_index].device_list[index]) {
3623 if (!strncmp(verb_list[verb_index].device_list[index],
3624 SND_UCM_END_OF_LIST, 3)) {
3625 free(verb_list[verb_index].device_list[index]);
3626 break;
3627 } else {
3628 free(verb_list[verb_index].device_list[index]);
3629 index++;
3630 }
3631 }
3632 }
3633 if (verb_list[verb_index].device_list)
3634 free(verb_list[verb_index].device_list);
3635 index = 0;
3636 while(1) {
3637 if (verb_list[verb_index].modifier_list[index]) {
3638 if (!strncmp(verb_list[verb_index].modifier_list[index],
3639 SND_UCM_END_OF_LIST, 3)) {
3640 free(verb_list[verb_index].modifier_list[index]);
3641 break;
3642 } else {
3643 free(verb_list[verb_index].modifier_list[index]);
3644 index++;
3645 }
3646 }
3647 }
3648 if (verb_list[verb_index].modifier_list)
3649 free(verb_list[verb_index].modifier_list);
Iliyan Malchev4765c432012-06-11 14:36:16 -07003650 if((*uc_mgr)->card_ctxt_ptr->use_case_verb_list)
3651 free((*uc_mgr)->card_ctxt_ptr->use_case_verb_list);
3652 if((*uc_mgr)->card_ctxt_ptr->verb_list)
3653 free((*uc_mgr)->card_ctxt_ptr->verb_list);
3654 pthread_mutex_unlock(&(*uc_mgr)->card_ctxt_ptr->card_lock);
3655}
3656
3657/* Add an identifier to the respective list
3658 * head - list head
3659 * value - node value that needs to be added
3660 * Returns 0 on sucess, negative error code otherwise
3661 */
3662static int snd_ucm_add_ident_to_list(struct snd_ucm_ident_node **head,
3663const char *value)
3664{
3665 struct snd_ucm_ident_node *temp, *node;
3666
3667 node =
3668 (struct snd_ucm_ident_node *)malloc(sizeof(struct snd_ucm_ident_node));
3669 if (node == NULL) {
3670 ALOGE("Failed to allocate memory for new node");
3671 return -ENOMEM;
3672 } else {
3673 node->next = NULL;
3674 strlcpy(node->ident, value, MAX_STR_LEN);
3675 node->active = 0;
3676 }
3677 if (*head == NULL) {
3678 *head = node;
3679 } else {
3680 temp = *head;
3681 while (temp->next != NULL) {
3682 temp = temp->next;
3683 }
3684 temp->next = node;
3685 }
3686 ALOGV("add_to_list: head %p, value %s", *head, node->ident);
3687 return 0;
3688}
3689
3690/* Get the status of identifier at particulare index of the list
3691 * head - list head
3692 * ident - identifier value for which status needs to be get
3693 * status - status to be set (1 - active, 0 - inactive)
3694 */
3695static int snd_ucm_get_status_at_index(struct snd_ucm_ident_node *head,
3696const char *ident)
3697{
3698 while (head != NULL) {
3699 if(!strncmp(ident, head->ident, (strlen(head->ident)+1))) {
3700 break;
3701 }
3702 head = head->next;
3703 }
3704 if (head == NULL) {
3705 ALOGV("Element not found in the list");
3706 } else {
3707 return(head->active);
3708 }
3709 return -EINVAL;
3710}
3711
3712/* Set the status of identifier at particulare index of the list
3713 * head - list head
3714 * ident - identifier value for which status needs to be set
3715 * status - status to be set (1 - active, 0 - inactive)
3716 */
3717static void snd_ucm_set_status_at_index(struct snd_ucm_ident_node *head,
3718const char *ident, int status)
3719{
3720 while (head != NULL) {
3721 if(!strncmp(ident, head->ident, (strlen(head->ident)+1))) {
3722 break;
3723 }
3724 head = head->next;
3725 }
3726 if (head == NULL) {
3727 ALOGE("Element not found to set the status");
3728 } else {
3729 head->active = status;
3730 }
3731}
3732
3733/* Get the identifier value at particulare index of the list
3734 * head - list head
3735 * index - node index value
3736 * Returns node idetifier value at index on sucess, NULL otherwise
3737 */
3738static char *snd_ucm_get_value_at_index(struct snd_ucm_ident_node *head,
3739int index)
3740{
3741 if (head == NULL) {
3742 ALOGV("Empty list");
3743 return NULL;
3744 }
3745
3746 if ((index < 0) || (index >= (snd_ucm_get_size_of_list(head)))) {
3747 ALOGE("Element with given index %d doesn't exist in the list", index);
3748 return NULL;
3749 }
3750
3751 while (index) {
3752 head = head->next;
3753 index--;
3754 }
3755
3756 return (strdup(head->ident));
3757}
3758
3759/* Get the size of the list
3760 * head - list head
3761 * Returns size of list on sucess, negative error code otherwise
3762 */
3763static int snd_ucm_get_size_of_list(struct snd_ucm_ident_node *head)
3764{
3765 int index = 0;
3766
3767 if (head == NULL) {
3768 ALOGV("Empty list");
3769 return 0;
3770 }
3771
3772 while (head->next != NULL) {
3773 index++;
3774 head = head->next;
3775 }
3776
3777 return (index+1);
3778}
3779
3780static void snd_ucm_print_list(struct snd_ucm_ident_node *head)
3781{
3782 int index = 0;
3783
3784 ALOGV("print_list: head %p", head);
3785 if (head == NULL) {
3786 ALOGV("Empty list");
3787 return;
3788 }
3789
3790 while (head->next != NULL) {
3791 ALOGV("index: %d, value: %s", index, head->ident);
3792 index++;
3793 head = head->next;
3794 }
3795 ALOGV("index: %d, value: %s", index, head->ident);
3796}
3797
3798/* Delete an identifier from respective list
3799 * head - list head
3800 * value - node value that needs to be deleted
3801 * Returns 0 on sucess, negative error code otherwise
3802 *
3803 */
3804static int snd_ucm_del_ident_from_list(struct snd_ucm_ident_node **head,
3805const char *value)
3806{
3807 struct snd_ucm_ident_node *temp1, *temp2;
3808 int ret = -EINVAL;
3809
3810 if (*head == NULL) {
3811 ALOGE("del_from_list: Empty list");
3812 return -EINVAL;
3813 } else if (!strncmp((*head)->ident, value, (strlen(value)+1))) {
3814 temp2 = *head;
3815 *head = temp2->next;
3816 ret = 0;
3817 } else {
3818 temp1 = *head;
3819 temp2 = temp1->next;
3820 while (temp2 != NULL) {
3821 if (!strncmp(temp2->ident, value, (strlen(value)+1))) {
3822 temp1->next = temp2->next;
3823 ret = 0;
3824 break;
3825 }
3826 temp1 = temp1->next;
3827 temp2 = temp1->next;
3828 }
3829 }
3830 if (ret < 0) {
3831 ALOGE("Element not found in enabled list");
3832 } else {
3833 temp2->next = NULL;
3834 temp2->ident[0] = 0;
3835 temp2->active = 0;
3836 free(temp2);
3837 temp2 = NULL;
3838 }
3839 return ret;
3840}