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