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