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