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