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