blob: 01da1edc4994a18b98c90c956b078da79d23b941 [file] [log] [blame]
Iliyan Malchev4765c432012-06-11 14:36:16 -07001/*
Duy Truongeb337332013-01-17 10:33:22 -08002 * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Iliyan Malchev4765c432012-06-11 14:36:16 -07003 *
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.
Duy Truongeb337332013-01-17 10:33:22 -080013 * * Neither the name of The Linux Foundation nor the names of its
Iliyan Malchev4765c432012-06-11 14:36:16 -070014 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
Ajay Dudani9746c472012-06-18 16:01:16 -070029#define LOG_TAG "alsa_ucm"
30#define LOG_NDDEBUG 0
Iliyan Malchev4765c432012-06-11 14:36:16 -070031
32#ifdef ANDROID
33/* definitions for Android logging */
34#include <utils/Log.h>
35#include <cutils/properties.h>
36#else /* ANDROID */
37#include <math.h>
38#define strlcat g_strlcat
39#define strlcpy g_strlcpy
40#define ALOGI(...) fprintf(stdout, __VA_ARGS__)
41#define ALOGE(...) fprintf(stderr, __VA_ARGS__)
42#define ALOGV(...) fprintf(stderr, __VA_ARGS__)
43#define ALOGD(...) fprintf(stderr, __VA_ARGS__)
44#endif /* ANDROID */
45
46#include <stdio.h>
47#include <stdlib.h>
48#include <fcntl.h>
49#include <stdarg.h>
50#include <string.h>
51#include <errno.h>
52#include <unistd.h>
Steve Kondik8fadd472013-04-15 23:55:12 -070053#include <dlfcn.h>
Iliyan Malchev4765c432012-06-11 14:36:16 -070054#include <pthread.h>
55#include <ctype.h>
56#include <sys/stat.h>
57#include <sys/ioctl.h>
58#include <sys/mman.h>
59#include <sys/time.h>
60#include <sys/poll.h>
61#include <stdint.h>
62
63#include <linux/ioctl.h>
64#include "msm8960_use_cases.h"
Steve Kondik8fadd472013-04-15 23:55:12 -070065 static void (*acdb_send_voice_cal)(int, int);
66 static void (*acdb_send_audio_cal)(int, int);
67 static void (*acdb_send_anc_cal)(int);
Iliyan Malchev4765c432012-06-11 14:36:16 -070068#define PARSE_DEBUG 0
69
70/**
71 * Create an identifier
72 * fmt - sprintf like format,
73 * ... - Optional arguments
74 * returns - string allocated or NULL on error
75 */
76char *snd_use_case_identifier(const char *fmt, ...)
77{
78 ALOGE("API not implemented for now, to be updated if required");
79 return NULL;
80}
81
82/**
83 * Free a list
84 * list - list to free
85 * items - Count of strings
86 * Return Zero on success, otherwise a negative error code
87 */
88int snd_use_case_free_list(const char *list[], int items)
89{
90 /* list points to UCM internal static tables,
91 * hence there is no need to do a free call
92 * just set the list to NULL and return */
93 list = NULL;
94 return 0;
95}
96
97/**
98 * Obtain a list of entries
99 * uc_mgr - UCM structure pointer or NULL for card list
100 * identifier - NULL for card list
101 * list - Returns allocated list
102 * returns Number of list entries on success, otherwise a negative error code
103 */
104int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
105 const char *identifier,
106 const char **list[])
107{
108 use_case_verb_t *verb_list;
109 int verb_index, list_size, index = 0;
110
111 if (identifier == NULL) {
112 *list = card_list;
113 return ((int)MAX_NUM_CARDS);
114 }
115
116 pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
117 if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) ||
118 (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) {
119 ALOGE("snd_use_case_get_list(): failed, invalid arguments");
120 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
121 return -EINVAL;
122 }
123
124 if (!strncmp(identifier, "_verbs", 6)) {
125 while(strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
126 SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
127 ALOGV("Index:%d Verb:%s", index,
128 uc_mgr->card_ctxt_ptr->verb_list[index]);
129 index++;
130 }
131 *list = (char ***)uc_mgr->card_ctxt_ptr->verb_list;
132 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
133 return index;
134 } else if (!strncmp(identifier, "_devices", 8)) {
135 if (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
136 SND_USE_CASE_VERB_INACTIVE, strlen(SND_USE_CASE_VERB_INACTIVE))) {
137 ALOGE("Use case verb name not set, invalid current verb");
138 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
139 return -EINVAL;
140 }
141 verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
142 while(strncmp(uc_mgr->card_ctxt_ptr->current_verb,
143 verb_list[index].use_case_name,
144 (strlen(verb_list[index].use_case_name)+1))) {
145 index++;
146 }
147 verb_index = index;
148 index = 0;
149 while(strncmp(verb_list[verb_index].device_list[index],
150 SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
151 ALOGV("Index:%d Device:%s", index,
152 verb_list[verb_index].device_list[index]);
153 index++;
154 }
155 *list = verb_list[verb_index].device_list;
156 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
157 return index;
158 } else if (!strncmp(identifier, "_modifiers", 10)) {
159 if (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
160 SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN)) {
161 ALOGE("Use case verb name not set, invalid current verb");
162 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
163 return -EINVAL;
164 }
165 verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
166 while(strncmp(uc_mgr->card_ctxt_ptr->current_verb,
167 verb_list[index].use_case_name,
168 (strlen(verb_list[index].use_case_name)+1))) {
169 index++;
170 }
171 verb_index = index;
172 index = 0;
173 while(strncmp(verb_list[verb_index].modifier_list[index],
174 SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
175 ALOGV("Index:%d Modifier:%s", index,
176 verb_list[verb_index].modifier_list[index]);
177 index++;
178 }
179 *list = verb_list[verb_index].modifier_list;
180 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
181 return index;
182 } else if (!strncmp(identifier, "_enadevs", 8)) {
183 if (uc_mgr->device_list_count) {
184 for (index = 0; index < uc_mgr->device_list_count; index++) {
185 free(uc_mgr->current_device_list[index]);
186 uc_mgr->current_device_list[index] = NULL;
187 }
188 free(uc_mgr->current_device_list);
189 uc_mgr->current_device_list = NULL;
190 uc_mgr->device_list_count = 0;
191 }
192 list_size =
193 snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
194 uc_mgr->device_list_count = list_size;
SathishKumar Mani9efed762012-09-18 18:52:48 -0700195 if (list_size > 0) {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700196 uc_mgr->current_device_list =
197 (char **)malloc(sizeof(char *)*list_size);
198 if (uc_mgr->current_device_list == NULL) {
199 *list = NULL;
200 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
201 return -ENOMEM;
202 }
203 for (index = 0; index < list_size; index++) {
204 uc_mgr->current_device_list[index] =
205 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
206 index);
207 }
208 }
209 *list = (const char **)uc_mgr->current_device_list;
210 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
211 return (list_size);
212 } else if (!strncmp(identifier, "_enamods", 8)) {
213 if (uc_mgr->modifier_list_count) {
214 for (index = 0; index < uc_mgr->modifier_list_count; index++) {
215 free(uc_mgr->current_modifier_list[index]);
216 uc_mgr->current_modifier_list[index] = NULL;
217 }
218 free(uc_mgr->current_modifier_list);
219 uc_mgr->current_modifier_list = NULL;
220 uc_mgr->modifier_list_count = 0;
221 }
222 list_size =
223 snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
224 uc_mgr->modifier_list_count = list_size;
SathishKumar Mani9efed762012-09-18 18:52:48 -0700225 if (list_size > 0) {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700226 uc_mgr->current_modifier_list =
227 (char **)malloc(sizeof(char *) * list_size);
228 if (uc_mgr->current_modifier_list == NULL) {
229 *list = NULL;
230 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
231 return -ENOMEM;
232 }
233 for (index = 0; index < list_size; index++) {
234 uc_mgr->current_modifier_list[index] =
235 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
236 index);
237 }
238 }
239 *list = (const char **)uc_mgr->current_modifier_list;
240 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
241 return (list_size);
242 } else {
243 ALOGE("Invalid identifier: %s", identifier);
244 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
245 return -EINVAL;
246 }
247}
248
249
250/**
251 * Get current value of the identifier
252 * identifier - NULL for current card
253 * _verb
254 * <Name>/<_device/_modifier>
255 * Name - PlaybackPCM
256 * CapturePCM
257 * PlaybackCTL
258 * CaptureCTL
259 * value - Value pointer
260 * returns Zero if success, otherwise a negative error code
261 */
262int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
263 const char *identifier,
264 const char **value)
265{
266 card_mctrl_t *ctrl_list;
267 use_case_verb_t *verb_list;
268 char ident[MAX_STR_LEN], *ident1, *ident2, *temp_ptr;
269 int index, verb_index = 0, ret = 0;
270
Damir Didjusto7fa0f9f2013-04-19 13:38:58 -0700271 if (value != NULL) {
272 *value = NULL;
273 }
274
Iliyan Malchev4765c432012-06-11 14:36:16 -0700275 pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
276 if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) ||
277 (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) {
278 ALOGE("snd_use_case_get(): failed, invalid arguments");
279 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
280 return -EINVAL;
281 }
282
283 if (identifier == NULL) {
284 if (uc_mgr->card_ctxt_ptr->card_name != NULL) {
285 *value = strdup(uc_mgr->card_ctxt_ptr->card_name);
286 } else {
287 *value = NULL;
288 }
289 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
290 return 0;
291 }
292
293 if (!strncmp(identifier, "_verb", 5)) {
294 if (uc_mgr->card_ctxt_ptr->current_verb != NULL) {
295 *value = strdup(uc_mgr->card_ctxt_ptr->current_verb);
296 } else {
297 *value = NULL;
298 }
299 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
300 return 0;
301 }
302
303 strlcpy(ident, identifier, sizeof(ident));
304 if(!(ident1 = strtok_r(ident, "/", &temp_ptr))) {
305 ALOGE("No valid identifier found: %s", ident);
306 ret = -EINVAL;
307 } else {
308 if ((!strncmp(ident1, "PlaybackPCM", 11)) ||
309 (!strncmp(ident1, "CapturePCM", 10))) {
310 ident2 = strtok_r(NULL, "/", &temp_ptr);
311 index = 0;
312 if (ident2 != NULL) {
313 verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
314 verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
315 if((get_usecase_type(uc_mgr, ident2)) == CTRL_LIST_VERB) {
316 ctrl_list = verb_list[verb_index].verb_ctrls;
317 } else {
318 ctrl_list = verb_list[verb_index].mod_ctrls;
319 }
320 if((verb_index < 0) ||
321 (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
322 SND_UCM_END_OF_LIST, 3)) || (ctrl_list == NULL)) {
323 ALOGE("Invalid current verb value: %s - %d",
324 uc_mgr->card_ctxt_ptr->current_verb, verb_index);
325 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
326 return -EINVAL;
327 }
328 while(strncmp(ctrl_list[index].case_name, ident2,
329 (strlen(ident2)+1))) {
330 if (!strncmp(ctrl_list[index].case_name,
331 SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))){
332 *value = NULL;
333 ret = -EINVAL;
334 break;
335 } else {
336 index++;
337 }
338 }
339 } else {
340 ret = -EINVAL;
341 }
342 if (ret < 0) {
343 ALOGE("No valid device/modifier found with given identifier: %s",
344 ident2);
345 } else {
346 if(!strncmp(ident1, "PlaybackPCM", 11)) {
347 if (ctrl_list[index].playback_dev_name) {
348 *value = strdup(ctrl_list[index].playback_dev_name);
349 } else {
350 *value = NULL;
351 ret = -ENODEV;
352 }
353 } else if(!strncmp(ident1, "CapturePCM", 10)) {
354 if (ctrl_list[index].capture_dev_name) {
355 *value = strdup(ctrl_list[index].capture_dev_name);
356 } else {
357 *value = NULL;
358 ret = -ENODEV;
359 }
360 } else {
361 ALOGE("No valid device name exists for given identifier: %s",
362 ident2);
363 *value = NULL;
364 ret = -ENODEV;
365 }
366 }
367 } else if ((!strncmp(ident1, "PlaybackCTL", 11)) ||
368 (!strncmp(ident1, "CaptureCTL", 10))) {
369 if(uc_mgr->card_ctxt_ptr->control_device != NULL) {
370 *value = strdup(uc_mgr->card_ctxt_ptr->control_device);
371 } else {
372 ALOGE("No valid control device found");
373 *value = NULL;
374 ret = -ENODEV;
375 }
Damir Didjusto7fa0f9f2013-04-19 13:38:58 -0700376 } else if (!strncmp(ident1, "PlaybackVolume", 14)) {
377 ident2 = strtok_r(NULL, "/", &temp_ptr);
378 index = 0;
379 if (ident2 != NULL) {
380 verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
381 verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
382 if((get_usecase_type(uc_mgr, ident2)) == CTRL_LIST_VERB) {
383 ctrl_list = verb_list[verb_index].verb_ctrls;
384 } else {
385 ctrl_list = verb_list[verb_index].mod_ctrls;
386 }
387 if((verb_index < 0) ||
388 (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
389 SND_UCM_END_OF_LIST, 3)) || (ctrl_list == NULL)) {
390 ALOGE("Invalid current verb value: %s - %d",
391 uc_mgr->card_ctxt_ptr->current_verb, verb_index);
392 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
393 return -EINVAL;
394 }
395 while(strncmp(ctrl_list[index].case_name, ident2,
396 (strlen(ident2)+1))) {
397 if (!strncmp(ctrl_list[index].case_name,
398 SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))){
399 *value = NULL;
400 ret = -EINVAL;
401 break;
402 } else {
403 index++;
404 }
405 }
406 } else {
407 ret = -EINVAL;
408 }
409 if (ret < 0) {
410 ALOGE("No valid device/modifier found with given identifier: %s",
411 ident2);
412 } else {
413 if (ctrl_list[index].volume_mixer_ctl) {
414 *value = strdup(ctrl_list[index].volume_mixer_ctl);
415 } else {
416 *value = NULL;
417 ret = -ENODEV;
418 }
419 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700420 } else if (!strncmp(ident1, "ACDBID", 11)) {
421 ident2 = strtok_r(NULL, "/", &temp_ptr);
422 index = 0; verb_index = 0;
423 verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
424 if((verb_index < 0) ||
425 (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
426 SND_UCM_END_OF_LIST, 3)) ||
427 (verb_list[verb_index].verb_ctrls == NULL)) {
428 ALOGE("Invalid current verb value: %s - %d",
429 uc_mgr->card_ctxt_ptr->current_verb, verb_index);
430 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
431 return -EINVAL;
432 }
433 ctrl_list = verb_list[verb_index].device_ctrls;
434 if (ident2 != NULL) {
435 while(strncmp(ctrl_list[index].case_name, ident2,
436 MAX_LEN(ctrl_list[index].case_name,ident2))) {
437 if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
438 strlen(SND_UCM_END_OF_LIST))){
439 ret = -EINVAL;
440 break;
441 } else {
442 index++;
443 }
444 }
445 }
446 if (ret < 0) {
447 ALOGE("No valid device/modifier found with given identifier: %s",
448 ident2);
449 } else {
450 if (verb_list[verb_index].device_ctrls[index].acdb_id) {
451 ret = verb_list[verb_index].device_ctrls[index].acdb_id;
452 } else {
453 ret = -ENODEV;
454 }
455 }
Damir Didjusto7fa0f9f2013-04-19 13:38:58 -0700456 } else if (!strncmp(ident1, "CAPABILITY", 11)) {
457 ident2 = strtok_r(NULL, "/", &temp_ptr);
458 index = 0; verb_index = 0;
459 verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
460 if((verb_index < 0) ||
461 (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
462 SND_UCM_END_OF_LIST, 3)) ||
463 (verb_list[verb_index].verb_ctrls == NULL)) {
464 ALOGE("Invalid current verb value: %s - %d",
465 uc_mgr->card_ctxt_ptr->current_verb, verb_index);
466 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
467 return -EINVAL;
468 }
469 ctrl_list = verb_list[verb_index].device_ctrls;
470 if (ident2 != NULL) {
471 while(strncmp(ctrl_list[index].case_name, ident2,
472 MAX_LEN(ctrl_list[index].case_name,ident2))) {
473 if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
474 strlen(SND_UCM_END_OF_LIST))){
475 ret = -EINVAL;
476 break;
477 } else {
478 index++;
479 }
480 }
481 }
482 if (ret < 0) {
483 ALOGE("No valid device/modifier found with given identifier: %s",
484 ident2);
485 } else {
486 if (verb_list[verb_index].device_ctrls[index].capability) {
487 ret = verb_list[verb_index].device_ctrls[index].capability;
488 } else {
489 ret = -ENODEV;
490 }
491 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700492 } else if (!strncmp(ident1, "EffectsMixerCTL", 11)) {
493 ident2 = strtok_r(NULL, "/", &temp_ptr);
494 index = 0; verb_index = 0;
495 verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
496 if((verb_index < 0) ||
497 (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
498 SND_UCM_END_OF_LIST, 3)) ||
499 (verb_list[verb_index].verb_ctrls == NULL)) {
500 ALOGE("Invalid current verb value: %s - %d",
501 uc_mgr->card_ctxt_ptr->current_verb, verb_index);
502 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
503 return -EINVAL;
504 }
505 ctrl_list = verb_list[verb_index].device_ctrls;
506 if (ident2 != NULL) {
507 while(strncmp(ctrl_list[index].case_name, ident2, strlen(ident2)+1)) {
508 if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
509 strlen(SND_UCM_END_OF_LIST))){
510 ret = -EINVAL;
511 break;
512 } else {
513 index++;
514 }
515 }
516 }
517 if (ret < 0) {
518 ALOGE("No valid device/modifier found with given identifier: %s",
519 ident2);
520 } else {
521 if (verb_list[verb_index].device_ctrls[index].effects_mixer_ctl) {
522 *value = strdup(verb_list[verb_index].device_ctrls[index].effects_mixer_ctl);
523 } else {
524 *value = NULL;
525 ret = -ENODEV;
526 }
527 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800528 } else if (!strncmp(ident1, "EC_REF_RXMixerCTL", 17)) {
529 ident2 = strtok_r(NULL, "/", &temp_ptr);
530 index = 0; verb_index = 0;
531 verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
532 if((verb_index < 0) ||
533 (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
534 SND_UCM_END_OF_LIST, 3)) ||
535 (verb_list[verb_index].verb_ctrls == NULL)) {
536 ALOGE("Invalid current verb value: %s - %d",
537 uc_mgr->card_ctxt_ptr->current_verb, verb_index);
538 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
539 return -EINVAL;
540 }
541 ctrl_list = verb_list[verb_index].device_ctrls;
542 if (ident2 != NULL) {
543 while(strncmp(ctrl_list[index].case_name, ident2, strlen(ident2)+1)) {
544 if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
545 strlen(SND_UCM_END_OF_LIST))){
546 ret = -EINVAL;
547 break;
548 } else {
549 index++;
550 }
551 }
552 }
553 if (ret < 0) {
554 ALOGE("No valid device/modifier found with given identifier: %s",
555 ident2);
556 } else {
557 if (verb_list[verb_index].device_ctrls[index].ec_ref_rx_mixer_ctl) {
558 *value = strdup(verb_list[verb_index].device_ctrls[index].ec_ref_rx_mixer_ctl);
559 } else {
560 *value = NULL;
561 ret = -ENODEV;
562 }
563 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700564 } else {
565 ALOGE("Unsupported identifier value: %s", ident1);
566 *value = NULL;
567 ret = -EINVAL;
568 }
569 }
570 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
571 return ret;
572}
573
574/**
575 * Get current status
576 * uc_mgr - UCM structure
577 * identifier - _devstatus/<device>,
578 _modstatus/<modifier>
579 * value - result
580 * returns 0 on success, otherwise a negative error code
581 */
582int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
583 const char *identifier,
584 long *value)
585{
586 char ident[MAX_STR_LEN], *ident1, *ident2, *ident_value, *temp_ptr;
587 int index, list_size, ret = -EINVAL;
588
589 pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
590 if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) ||
591 (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL)) {
592 ALOGE("snd_use_case_geti(): failed, invalid arguments");
593 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
594 return -EINVAL;
595 }
596
597 *value = 0;
598 strlcpy(ident, identifier, sizeof(ident));
599 if(!(ident1 = strtok_r(ident, "/", &temp_ptr))) {
600 ALOGE("No valid identifier found: %s", ident);
601 ret = -EINVAL;
602 } else {
603 if (!strncmp(ident1, "_devstatus", 10)) {
604 ident2 = strtok_r(NULL, "/", &temp_ptr);
605 if (ident2 != NULL) {
606 list_size =
607 snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
608 for (index = 0; index < list_size; index++) {
609 if ((ident_value =
610 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
611 index))) {
612 if (!strncmp(ident2, ident_value,
613 (strlen(ident_value)+1))) {
614 *value = 1;
615 free(ident_value);
616 ident_value = NULL;
617 break;
618 } else {
619 free(ident_value);
620 ident_value = NULL;
621 }
622 }
623 }
624 ret = 0;
625 }
626 } else if (!strncmp(ident1, "_modstatus", 10)) {
627 ident2 = strtok_r(NULL, "/", &temp_ptr);
628 if (ident2 != NULL) {
629 list_size =
630 snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
631 for (index = 0; index < list_size; index++) {
632 if((ident_value =
633 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
634 index))) {
635 if (!strncmp(ident2, ident_value,
636 (strlen(ident_value)+1))) {
637 *value = 1;
638 free(ident_value);
639 ident_value = NULL;
640 break;
641 } else {
642 free(ident_value);
643 ident_value = NULL;
644 }
645 }
646 }
647 ret = 0;
648 }
649 } else {
650 ALOGE("Unknown identifier: %s", ident1);
651 }
652 }
653 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
654 return ret;
655}
656
SathishKumar Mani98580102012-09-20 14:46:37 -0700657static int check_devices_for_voice_call(snd_use_case_mgr_t *uc_mgr,
658const char *use_case)
659{
660 struct snd_ucm_ident_node *dev_node = NULL;
661 int index = 0, list_size = 0, rx_dev_status = 0, tx_dev_status = 0;
662
663 if ((!strncmp(use_case, SND_USE_CASE_VERB_VOICECALL,
664 strlen(SND_USE_CASE_VERB_VOICECALL))) ||
Neema Shetty83d616c2013-02-20 19:18:05 -0800665 (!strncmp(use_case, SND_USE_CASE_VERB_VOICE2,
666 strlen(SND_USE_CASE_VERB_VOICE2))) ||
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800667 (!strncmp(use_case, SND_USE_CASE_VERB_VOLTE,
668 strlen(SND_USE_CASE_VERB_VOLTE))) ||
SathishKumar Mani98580102012-09-20 14:46:37 -0700669 (!strncmp(use_case, SND_USE_CASE_VERB_IP_VOICECALL,
670 strlen(SND_USE_CASE_VERB_IP_VOICECALL))) ||
671 (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOICE,
672 strlen(SND_USE_CASE_MOD_PLAY_VOICE))) ||
Neema Shetty83d616c2013-02-20 19:18:05 -0800673 (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOICE2,
674 strlen(SND_USE_CASE_MOD_PLAY_VOICE2))) ||
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800675 (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOLTE,
676 strlen(SND_USE_CASE_MOD_PLAY_VOLTE))) ||
SathishKumar Mani98580102012-09-20 14:46:37 -0700677 (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOIP,
678 strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
679 ALOGV("check_devices_for_voice_call(): voice cap detected\n");
680 list_size =
681 snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
682 for (index = 0; index < list_size; index++) {
683 if ((dev_node =
684 snd_ucm_get_device_node(uc_mgr->card_ctxt_ptr->dev_list_head,
685 index))) {
686 if (dev_node->capability == CAP_RX && dev_node->active == 1) {
687 rx_dev_status = 1;
688 } else if (dev_node->capability == CAP_TX && dev_node->active == 1) {
689 tx_dev_status = 1;
690 }
691 }
692 }
693 if (rx_dev_status == 1 && tx_dev_status == 1) {
694 ALOGV("check_devices_for_voice_call(): Rx and Tx devices enabled\n");
695 return 0;
696 } else {
697 ALOGV("check_devices_for_voice_call(): Rx/Tx dev not enabled: \
698 %d,%d\n", rx_dev_status, tx_dev_status);
699 return 1;
700 }
701 }
702 return 0;
703}
704
Iliyan Malchev4765c432012-06-11 14:36:16 -0700705static int snd_use_case_apply_voice_acdb(snd_use_case_mgr_t *uc_mgr,
706int use_case_index)
707{
708 card_mctrl_t *ctrl_list;
709 int list_size, index, verb_index, ret = 0, voice_acdb = 0, rx_id, tx_id;
710 char *ident_value = NULL;
Sam Mortimer1d576d82013-09-02 20:25:08 -0700711 char current_mod[MAX_STR_LEN] = "";
Iliyan Malchev4765c432012-06-11 14:36:16 -0700712
713 /* Check if voice call use case/modifier exists */
714 if ((!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800715 SND_USE_CASE_VERB_VOLTE, strlen(SND_USE_CASE_VERB_VOLTE))) ||
716 (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
Iliyan Malchev4765c432012-06-11 14:36:16 -0700717 SND_USE_CASE_VERB_VOICECALL, strlen(SND_USE_CASE_VERB_VOICECALL))) ||
718 (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
Neema Shetty83d616c2013-02-20 19:18:05 -0800719 SND_USE_CASE_VERB_VOICE2, strlen(SND_USE_CASE_VERB_VOICE2))) ||
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800720 (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
Iliyan Malchev4765c432012-06-11 14:36:16 -0700721 SND_USE_CASE_VERB_IP_VOICECALL,
722 strlen(SND_USE_CASE_VERB_IP_VOICECALL)))) {
723 voice_acdb = 1;
724 }
Avinash Vaisha14aab22013-08-12 10:21:48 +0530725//The ident_value should store latest/current modifier
Iliyan Malchev4765c432012-06-11 14:36:16 -0700726 if (voice_acdb != 1) {
727 list_size =
728 snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
729 for (index = 0; index < list_size; index++) {
730 if ((ident_value =
731 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
732 index))) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800733 if ((!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOLTE,
734 strlen(SND_USE_CASE_MOD_PLAY_VOLTE))) ||
735 (!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOICE,
Iliyan Malchev4765c432012-06-11 14:36:16 -0700736 strlen(SND_USE_CASE_MOD_PLAY_VOICE))) ||
Neema Shetty83d616c2013-02-20 19:18:05 -0800737 (!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOICE2,
738 strlen(SND_USE_CASE_MOD_PLAY_VOICE2))) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -0700739 (!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOIP,
740 strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
741 voice_acdb = 1;
Jayasena Sangaraboina6c461b72013-01-29 11:09:34 -0800742 strlcpy(current_mod, ident_value, MAX_STR_LEN);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700743 }
744 free(ident_value);
745 ident_value = NULL;
746 }
747 }
748 }
749
750 verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
751 if((verb_index < 0) ||
752 (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
753 SND_UCM_END_OF_LIST, 3))) {
754 ALOGE("Invalid current verb value: %s - %d",
755 uc_mgr->card_ctxt_ptr->current_verb, verb_index);
756 return -EINVAL;
757 }
758 if (voice_acdb == 1) {
759 ctrl_list =
760 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
761 list_size =
762 snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
763 for (index = 0; index < list_size; index++) {
764 if ((ident_value =
765 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
766 index))) {
767 if (strncmp(ident_value, ctrl_list[use_case_index].case_name,
768 (strlen(ctrl_list[use_case_index].case_name)+1))) {
769 break;
770 }
771 free(ident_value);
772 ident_value = NULL;
773 }
774 }
775 index = 0;
776 if (ident_value != NULL) {
777 while(strncmp(ctrl_list[index].case_name, ident_value,
778 (strlen(ident_value)+1))) {
779 if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
780 strlen(SND_UCM_END_OF_LIST))) {
781 ret = -EINVAL;
782 break;
783 }
784 index++;
785 }
786 if (ret < 0) {
787 ALOGE("No valid device found: %s",ident_value);
788 } else {
789 if (ctrl_list[use_case_index].capability == CAP_RX) {
790 rx_id = ctrl_list[use_case_index].acdb_id;
791 tx_id = ctrl_list[index].acdb_id;
792 } else {
793 rx_id = ctrl_list[index].acdb_id;
794 tx_id = ctrl_list[use_case_index].acdb_id;
795 }
ehgrace.kim91e9fad2012-07-02 18:27:28 -0700796 if(((rx_id == DEVICE_SPEAKER_MONO_RX_ACDB_ID)||(rx_id == DEVICE_SPEAKER_STEREO_RX_ACDB_ID))
797 && tx_id == DEVICE_HANDSET_TX_ACDB_ID) {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700798 tx_id = DEVICE_SPEAKER_TX_ACDB_ID;
ehgrace.kim91e9fad2012-07-02 18:27:28 -0700799 } else if (((rx_id == DEVICE_SPEAKER_MONO_RX_ACDB_ID )||(rx_id == DEVICE_SPEAKER_STEREO_RX_ACDB_ID))
800 && tx_id == DEVICE_HANDSET_TX_FV5_ACDB_ID) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700801 tx_id = DEVICE_SPEAKER_TX_FV5_ACDB_ID;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700802 }
Avinash Vaisha14aab22013-08-12 10:21:48 +0530803/* Despite no change in rx and tx devices, calibration data can be required to be sent.
804This happens when the modifier changes*/
Iliyan Malchev4765c432012-06-11 14:36:16 -0700805 uc_mgr->current_rx_device = rx_id;
806 uc_mgr->current_tx_device = tx_id;
Jayasena Sangaraboina6c461b72013-01-29 11:09:34 -0800807 ALOGD("Voice acdb: rx id %d tx id %d verb:%s modifier:%s",
Iliyan Malchev4765c432012-06-11 14:36:16 -0700808 uc_mgr->current_rx_device,
Jayasena Sangaraboina6c461b72013-01-29 11:09:34 -0800809 uc_mgr->current_tx_device,
810 uc_mgr->card_ctxt_ptr->current_verb, current_mod);
811 if ((!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
812 SND_USE_CASE_VERB_IP_VOICECALL,
813 strlen(SND_USE_CASE_VERB_IP_VOICECALL)) ||
814 (!strncmp(current_mod, SND_USE_CASE_MOD_PLAY_VOIP,
815 strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) ||
Avinash Vaisha14aab22013-08-12 10:21:48 +0530816 (!uc_mgr->isFusion3Platform)) {
Steve Kondik8fadd472013-04-15 23:55:12 -0700817 if (uc_mgr->acdb_handle) {
818 acdb_send_voice_cal = dlsym(uc_mgr->acdb_handle,"acdb_loader_send_voice_cal");
819 if (acdb_send_voice_cal == NULL) {
820 ALOGE("Voice acdb: dlsym: Error:%s Loading acdb_loader_send_voice_cal", dlerror());
821 } else {
822 acdb_send_voice_cal(uc_mgr->current_rx_device,
823 uc_mgr->current_tx_device);
824 }
825 }
Avinash Vaisha14aab22013-08-12 10:21:48 +0530826 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700827 }
828 free(ident_value);
829 ident_value = NULL;
830 }
831 } else {
832 ALOGV("No voice use case found");
833 uc_mgr->current_rx_device = -1; uc_mgr->current_tx_device = -1;
834 ret = -ENODEV;
835 }
836 return ret;
837}
838
839int get_use_case_index(snd_use_case_mgr_t *uc_mgr, const char *use_case,
840int ctrl_list_type)
841{
842 use_case_verb_t *verb_list;
843 card_mctrl_t *ctrl_list;
844 int ret = 0, index = 0, verb_index;
845
846 verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
847 verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
Haynes Mathew George93601e92013-01-08 17:42:44 -0800848
849 if (verb_index < 0) {
850 ALOGE("Invalid verb_index %d", verb_index);
851 return -EINVAL;
852 }
853
Iliyan Malchev4765c432012-06-11 14:36:16 -0700854 if (ctrl_list_type == CTRL_LIST_VERB) {
855 ctrl_list =
856 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls;
857 } else if (ctrl_list_type == CTRL_LIST_DEVICE) {
858 ctrl_list =
859 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
860 } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
861 ctrl_list =
862 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].mod_ctrls;
863 } else {
864 ctrl_list = NULL;
865 }
Haynes Mathew George93601e92013-01-08 17:42:44 -0800866
867 if (!strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_UCM_END_OF_LIST, 3) ||
868 (ctrl_list == NULL) || (ctrl_list[index].case_name == NULL)) {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700869 ALOGE("Invalid current verb value: %s - %d",
870 uc_mgr->card_ctxt_ptr->current_verb, verb_index);
871 return -EINVAL;
872 }
873 while(strncmp(ctrl_list[index].case_name, use_case, (strlen(use_case)+1))) {
874 if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
875 strlen(SND_UCM_END_OF_LIST))) {
876 ret = -EINVAL;
877 break;
878 }
879 index++;
880 if (ctrl_list[index].case_name == NULL) {
881 ALOGE("Invalid case_name at index %d", index);
882 ret = -EINVAL;
883 break;
884 }
885 }
886 if (ret < 0) {
887 return ret;
888 } else {
889 return index;
890 }
891}
892
893/* Apply the required mixer controls for specific use case
894 * uc_mgr - UCM structure pointer
895 * use_case - use case name
896 * return 0 on sucess, otherwise a negative error code
897 */
898int snd_use_case_apply_mixer_controls(snd_use_case_mgr_t *uc_mgr,
899const char *use_case, int enable, int ctrl_list_type, int uc_index)
900{
901 card_mctrl_t *ctrl_list;
902 mixer_control_t *mixer_list;
903 struct mixer_ctl *ctl;
904 int i, ret = 0, index = 0, verb_index, mixer_count;
905
906 verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
907 if (ctrl_list_type == CTRL_LIST_VERB) {
908 ctrl_list =
909 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls;
910 } else if (ctrl_list_type == CTRL_LIST_DEVICE) {
911 ctrl_list =
912 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
913 } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
914 ctrl_list =
915 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].mod_ctrls;
916 } else {
917 ctrl_list = NULL;
918 }
919 if((verb_index < 0) ||
920 (!strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_UCM_END_OF_LIST, 3)) ||
921 (ctrl_list == NULL)) {
922 ALOGE("Invalid current verb value: %s - %d",
923 uc_mgr->card_ctxt_ptr->current_verb, verb_index);
924 return -EINVAL;
925 }
926 if (uc_index < 0) {
927 ALOGE("No valid use case found with the use case: %s", use_case);
928 ret = -ENODEV;
929 } else {
930 if (!uc_mgr->card_ctxt_ptr->mixer_handle) {
931 ALOGE("Control device not initialized");
932 ret = -ENODEV;
933 } else {
SathishKumar Mani98580102012-09-20 14:46:37 -0700934 if (enable &&
935 (check_devices_for_voice_call(uc_mgr, use_case) != NULL))
936 return ret;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700937 ALOGD("Set mixer controls for %s enable %d", use_case, enable);
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800938 if ((ctrl_list[uc_index].acdb_id >= 0) && ctrl_list[uc_index].capability) {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700939 if (enable) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800940 snd_use_case_apply_voice_acdb(uc_mgr, uc_index);
941 ALOGD("acdb_id %d cap %d enable %d",
942 ctrl_list[uc_index].acdb_id,
Iliyan Malchev4765c432012-06-11 14:36:16 -0700943 ctrl_list[uc_index].capability, enable);
Steve Kondik8fadd472013-04-15 23:55:12 -0700944 if (uc_mgr->acdb_handle) {
945 acdb_send_audio_cal = dlsym(uc_mgr->acdb_handle,"acdb_loader_send_audio_cal");
946 if (acdb_send_audio_cal == NULL) {
947 ALOGE("dlsym: Error:%s Loading acdb_loader_send_audio_cal", dlerror());
948 } else {
949 acdb_send_audio_cal(ctrl_list[uc_index].acdb_id,
950 ctrl_list[uc_index].capability);
951 }
952 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700953 }
954 }
955 if (enable) {
956 mixer_list = ctrl_list[uc_index].ena_mixer_list;
957 mixer_count = ctrl_list[uc_index].ena_mixer_count;
958 } else {
959 mixer_list = ctrl_list[uc_index].dis_mixer_list;
960 mixer_count = ctrl_list[uc_index].dis_mixer_count;
961 }
962 for(index = 0; index < mixer_count; index++) {
963 if (mixer_list == NULL) {
964 ALOGE("No valid controls exist for this case: %s", use_case);
965 break;
966 }
967 ctl = mixer_get_control(uc_mgr->card_ctxt_ptr->mixer_handle,
968 mixer_list[index].control_name, 0);
969 if (ctl) {
970 if (mixer_list[index].type == TYPE_INT) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800971 ALOGD("Setting mixer control: %s, value: %d",
Iliyan Malchev4765c432012-06-11 14:36:16 -0700972 mixer_list[index].control_name,
973 mixer_list[index].value);
974 ret = mixer_ctl_set(ctl, mixer_list[index].value);
975 } else if (mixer_list[index].type == TYPE_MULTI_VAL) {
976 ALOGD("Setting multi value: %s",
977 mixer_list[index].control_name);
978 ret = mixer_ctl_set_value(ctl, mixer_list[index].value,
979 mixer_list[index].mulval);
980 if (ret < 0)
981 ALOGE("Failed to set multi value control %s\n",
982 mixer_list[index].control_name);
983 } else {
Mingming Yinbbd94ad2012-11-29 20:04:36 -0800984 ALOGD("Setting mixer control: %s, value: %s",
Iliyan Malchev4765c432012-06-11 14:36:16 -0700985 mixer_list[index].control_name,
986 mixer_list[index].string);
987 ret = mixer_ctl_select(ctl, mixer_list[index].string);
988 }
989 if ((ret != 0) && enable) {
990 /* Disable all the mixer controls which are
991 * already enabled before failure */
992 mixer_list = ctrl_list[uc_index].dis_mixer_list;
993 mixer_count = ctrl_list[uc_index].dis_mixer_count;
994 for(i = 0; i < mixer_count; i++) {
995 ctl = mixer_get_control(
996 uc_mgr->card_ctxt_ptr->mixer_handle,
997 mixer_list[i].control_name, 0);
998 if (ctl) {
999 if (mixer_list[i].type == TYPE_INT) {
1000 ret = mixer_ctl_set(ctl,
1001 mixer_list[i].value);
1002 } else {
1003 ret = mixer_ctl_select(ctl,
1004 mixer_list[i].string);
1005 }
1006 }
1007 }
1008 ALOGE("Failed to enable the mixer controls for %s",
1009 use_case);
1010 break;
1011 }
1012 }
1013 }
1014 }
1015 }
1016 return ret;
1017}
1018
1019int getUseCaseType(const char *useCase)
1020{
1021 ALOGV("getUseCaseType: use case is %s\n", useCase);
1022 if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI,
1023 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI)) ||
SathishKumar Manid1c97002012-08-13 18:37:37 -07001024 !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
1025 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -07001026 !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
1027 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
1028 !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
1029 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001030 !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL2,
1031 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL2)) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -07001032 !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
1033 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI2)) ||
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001034 !strncmp(useCase, SND_USE_CASE_VERB_HIFI3,
1035 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI3)) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -07001036 !strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO,
1037 MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
1038 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
1039 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC)) ||
SathishKumar Manid1c97002012-08-13 18:37:37 -07001040 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
1041 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -07001042 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
1043 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001044 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC3,
1045 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC3)) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -07001046 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA,
1047 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LPA)) ||
1048 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
1049 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001050 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL2,
1051 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL2)) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -07001052 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM,
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001053 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))||
1054 !strncmp(useCase, SND_USE_CASE_MOD_PSEUDO_TUNNEL,
1055 MAX_LEN(useCase,SND_USE_CASE_MOD_PSEUDO_TUNNEL))||
1056 !strncmp(useCase, SND_USE_CASE_VERB_HIFI_PSEUDO_TUNNEL,
1057 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_PSEUDO_TUNNEL))) {
Iliyan Malchev4765c432012-06-11 14:36:16 -07001058 return CAP_RX;
1059 } else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC,
1060 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC)) ||
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001061 !strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC2,
1062 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC2)) ||
1063 !strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED,
1064 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -07001065 !strncmp(useCase, SND_USE_CASE_VERB_FM_REC,
1066 MAX_LEN(useCase,SND_USE_CASE_VERB_FM_REC)) ||
1067 !strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC,
1068 MAX_LEN(useCase,SND_USE_CASE_VERB_FM_A2DP_REC)) ||
1069 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC,
1070 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC)) ||
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001071 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC2,
1072 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC2)) ||
SathishKumar Manid1c97002012-08-13 18:37:37 -07001073 !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC,
1074 MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) ||
1075 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC,
1076 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) ||
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001077 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED,
1078 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED)) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -07001079 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM,
1080 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_FM)) ||
1081 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM,
1082 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_A2DP_FM))) {
1083 return CAP_TX;
1084 } else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL,
1085 MAX_LEN(useCase,SND_USE_CASE_VERB_VOICECALL)) ||
Neema Shetty83d616c2013-02-20 19:18:05 -08001086 !strncmp(useCase, SND_USE_CASE_VERB_VOICE2,
1087 MAX_LEN(useCase,SND_USE_CASE_VERB_VOICE2)) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -07001088 !strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL,
1089 MAX_LEN(useCase,SND_USE_CASE_VERB_IP_VOICECALL)) ||
1090 !strncmp(useCase, SND_USE_CASE_VERB_DL_REC,
1091 MAX_LEN(useCase,SND_USE_CASE_VERB_DL_REC)) ||
1092 !strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC,
1093 MAX_LEN(useCase,SND_USE_CASE_VERB_UL_DL_REC)) ||
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001094 !strncmp(useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL,
1095 MAX_LEN(useCase,SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL)) ||
1096 !strncmp(useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL,
1097 MAX_LEN(useCase,SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL)) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -07001098 !strncmp(useCase, SND_USE_CASE_VERB_INCALL_REC,
1099 MAX_LEN(useCase,SND_USE_CASE_VERB_INCALL_REC)) ||
1100 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE,
1101 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE)) ||
Neema Shetty83d616c2013-02-20 19:18:05 -08001102 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE2,
1103 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE2)) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -07001104 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP,
1105 MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
1106 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
1107 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) ||
1108 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
1109 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) ||
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001110 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL,
1111 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL)) ||
1112 !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL,
1113 MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL)) ||
Iliyan Malchev4765c432012-06-11 14:36:16 -07001114 !strncmp(useCase, SND_USE_CASE_VERB_VOLTE,
1115 MAX_LEN(useCase,SND_USE_CASE_VERB_VOLTE)) ||
1116 !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
1117 MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_VOLTE))) {
1118 return CAP_VOICE;
1119 } else {
1120 ALOGE("unknown use case %s, returning voice capablity", useCase);
1121 return CAP_VOICE;
1122 }
1123}
1124
1125/* Set/Reset mixer controls of specific use case for all current devices
1126 * uc_mgr - UCM structure pointer
1127 * ident - use case name (verb or modifier)
1128 * enable - 1 for enable and 0 for disable
1129 * return 0 on sucess, otherwise a negative error code
1130 */
1131static int set_controls_of_usecase_for_all_devices(snd_use_case_mgr_t *uc_mgr,
1132const char *ident, int enable, int ctrl_list_type)
1133{
1134 card_mctrl_t *dev_list, *uc_list;
1135 char *current_device, use_case[MAX_UC_LEN];
1136 int list_size, index, uc_index, ret = 0, intdev_flag = 0;
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001137 int verb_index, capability = 0, ident_cap = 0, dev_cap = 0;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001138
1139 ALOGV("set_use_case_ident_for_all_devices(): %s", ident);
1140 if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
1141 verb_index = 0;
1142 dev_list =
1143 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
1144 if (ctrl_list_type == CTRL_LIST_VERB) {
1145 uc_list =
1146 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls;
1147 } else if (ctrl_list_type == CTRL_LIST_MODIFIER) {
1148 uc_list =
1149 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].mod_ctrls;
1150 } else {
1151 uc_list = NULL;
1152 }
1153 ident_cap = getUseCaseType(ident);
1154 list_size = snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1155 for (index = 0; index < list_size; index++) {
1156 current_device =
1157 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head, index);
1158 if (current_device != NULL) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001159 if ((uc_index = get_use_case_index(uc_mgr, current_device,
1160 CTRL_LIST_DEVICE)) < 0) {
1161 ALOGE("No valid device found: %s", current_device);
Preetam Singh Ranawatfa1cacb2012-11-20 15:57:27 +05301162 free(current_device);
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001163 continue;
1164 }
SathishKumar Mani98580102012-09-20 14:46:37 -07001165 dev_cap = dev_list[uc_index].capability;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001166 if (!capability) {
1167 capability = dev_list[uc_index].capability;
1168 } else if (capability != dev_list[uc_index].capability) {
1169 capability = CAP_VOICE;
1170 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001171 if (ident_cap == CAP_VOICE || dev_cap == ident_cap) {
SathishKumar Mani98580102012-09-20 14:46:37 -07001172 if (enable) {
1173 if (!snd_ucm_get_status_at_index(
Iliyan Malchev4765c432012-06-11 14:36:16 -07001174 uc_mgr->card_ctxt_ptr->dev_list_head, current_device)) {
SathishKumar Mani98580102012-09-20 14:46:37 -07001175 if (uc_index >= 0) {
1176 ALOGV("Applying mixer controls for device: %s",
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001177 current_device);
SathishKumar Mani98580102012-09-20 14:46:37 -07001178 ret = snd_use_case_apply_mixer_controls(uc_mgr,
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001179 current_device, enable, CTRL_LIST_DEVICE,
1180 uc_index);
SathishKumar Mani98580102012-09-20 14:46:37 -07001181 if (!ret)
1182 snd_ucm_set_status_at_index(
1183 uc_mgr->card_ctxt_ptr->dev_list_head,
1184 current_device, enable, dev_cap);
1185 }
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001186 } else if (ident_cap == CAP_VOICE) {
SathishKumar Mani98580102012-09-20 14:46:37 -07001187 snd_use_case_apply_voice_acdb(uc_mgr, uc_index);
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001188 }
1189 }
1190 strlcpy(use_case, ident, sizeof(use_case));
1191 strlcat(use_case, current_device, sizeof(use_case));
1192 ALOGV("Applying mixer controls for use case: %s", use_case);
1193 if ((uc_index =
1194 get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
1195 ALOGV("No valid use case found: %s", use_case);
1196 intdev_flag++;
1197 } else {
1198 ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
1199 enable, ctrl_list_type, uc_index);
1200 }
1201 use_case[0] = 0;
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001202 }
Preetam Singh Ranawatfa1cacb2012-11-20 15:57:27 +05301203 free(current_device);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001204 }
1205 }
1206 if (intdev_flag) {
1207 if ((uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type)) < 0) {
1208 ALOGE("use case %s not valid without device combination", ident);
1209 } else {
1210 if (capability == CAP_VOICE || capability == ident_cap ||
1211 ident_cap == CAP_VOICE) {
1212 snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
1213 ctrl_list_type, uc_index);
1214 }
1215 }
1216 }
1217 return ret;
1218}
1219
1220/* Set/Reset mixer controls of specific use case for a specific device
1221 * uc_mgr - UCM structure pointer
1222 * ident - use case name (verb or modifier)
1223 * device - device for which use case needs to be set/reset
1224 * enable - 1 for enable and 0 for disable
1225 * return 0 on sucess, otherwise a negative error code
1226 */
1227static int set_controls_of_usecase_for_device(snd_use_case_mgr_t *uc_mgr,
1228const char *ident, const char *device, int enable, int ctrl_list_type)
1229{
SathishKumar Mani98580102012-09-20 14:46:37 -07001230 card_mctrl_t *dev_list;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001231 char use_case[MAX_UC_LEN];
1232 int list_size, index, dev_index, uc_index, ret = 0;
SathishKumar Mani98580102012-09-20 14:46:37 -07001233 int verb_index, capability = 0;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001234
1235 ALOGV("set_use_case_ident_for_device(): use case %s device %s", ident,
1236 device);
SathishKumar Mani98580102012-09-20 14:46:37 -07001237 if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
1238 verb_index = 0;
1239 dev_list =
1240 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001241 if (device != NULL) {
1242 if (enable) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001243 if ((dev_index =
1244 get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE)) < 0) {
1245 ALOGE("No valid device found: %s", device);
1246 return dev_index;
1247 }
SathishKumar Mani98580102012-09-20 14:46:37 -07001248 capability = dev_list[dev_index].capability;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001249 if (!snd_ucm_get_status_at_index(
1250 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1251 ret = snd_use_case_apply_mixer_controls(uc_mgr, device,
1252 enable, CTRL_LIST_DEVICE, dev_index);
1253 if (!ret)
1254 snd_ucm_set_status_at_index(
SathishKumar Mani98580102012-09-20 14:46:37 -07001255 uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
1256 capability);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001257 }
1258 }
1259 strlcpy(use_case, ident, sizeof(use_case));
1260 strlcat(use_case, device, sizeof(use_case));
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001261 ALOGV("Applying mixer controls for use case: %s", use_case);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001262 if ((uc_index = get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
1263 ALOGV("No valid use case found: %s", use_case );
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001264 if ((uc_index =
1265 get_use_case_index(uc_mgr, ident, ctrl_list_type)) < 0) {
1266 ALOGE("No valid use case found: %s", ident);
1267 return uc_index;
1268 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07001269 if (snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
1270 ctrl_list_type, uc_index) < 0) {
1271 ALOGV("use case %s not valid without device combination also",
1272 ident);
1273 }
1274 } else {
1275 ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case, enable,
1276 ctrl_list_type, uc_index);
1277 }
1278 } else {
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001279 if ((uc_index =
1280 get_use_case_index(uc_mgr, ident, ctrl_list_type)) < 0) {
1281 ALOGE("No valid use case found: %s", ident);
1282 return uc_index;
1283 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07001284 if (snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
1285 ctrl_list_type, uc_index) < 0) {
1286 ALOGV("use case %s not valid without device combination also",
1287 ident);
1288 }
1289 }
1290 return ret;
1291}
1292
1293/* Set/Reset mixer controls of specific device for all use cases
1294 * uc_mgr - UCM structure pointer
1295 * device - device name
1296 * enable - 1 for enable and 0 for disable
1297 * return 0 on sucess, otherwise a negative error code
1298 */
1299static int set_controls_of_device_for_all_usecases(snd_use_case_mgr_t *uc_mgr,
1300const char *device, int enable)
1301{
1302 card_mctrl_t *dev_list, *uc_list;
1303 char *ident_value, use_case[MAX_UC_LEN];
1304 int verb_index, uc_index, dev_index, capability = 0;
1305 int list_size, index = 0, ret = -ENODEV, flag = 0, intdev_flag = 0;
1306
1307 ALOGV("set_controls_of_device_for_all_usecases: %s", device);
1308 if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
1309 verb_index = 0;
1310 dev_list =
1311 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001312 if ((dev_index =
1313 get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE)) < 0) {
1314 ALOGE("No valid device %s found", device);
1315 return dev_index;
1316 }
ty.lee94de74c2012-09-03 17:03:12 +09001317 if (dev_index >= 0)
1318 capability = dev_list[dev_index].capability;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001319 if (strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_USE_CASE_VERB_INACTIVE,
1320 strlen(SND_USE_CASE_VERB_INACTIVE))) {
1321 uc_list =
1322 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls;
SathishKumar Mani98580102012-09-20 14:46:37 -07001323 if (capability == CAP_VOICE ||
1324 capability == getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ||
1325 getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) == CAP_VOICE) {
1326 strlcpy(use_case, uc_mgr->card_ctxt_ptr->current_verb,
1327 sizeof(use_case));
1328 strlcat(use_case, device, sizeof(use_case));
1329 if ((uc_index =
1330 get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB)) < 0) {
1331 ALOGV("No valid use case found: %s", use_case);
1332 intdev_flag = 1;
1333 } else {
1334 if (enable) {
1335 if (!snd_ucm_get_status_at_index(
1336 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1337 ret = snd_use_case_apply_mixer_controls(uc_mgr, device,
1338 enable, CTRL_LIST_DEVICE, dev_index);
1339 if (!ret)
1340 snd_ucm_set_status_at_index(
1341 uc_mgr->card_ctxt_ptr->dev_list_head, device,
1342 enable, capability);
1343 flag = 1;
1344 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07001345 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07001346 ALOGV("set %d for use case value: %s", enable, use_case);
1347 ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
1348 enable, CTRL_LIST_VERB, uc_index);
1349 if (ret != 0)
1350 ALOGE("No valid controls exists for usecase %s and device \
1351 %s, enable: %d", use_case, device, enable);
1352 }
1353 }
1354 if (intdev_flag) {
1355 if (enable && !flag) {
1356 if (!snd_ucm_get_status_at_index(
1357 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1358 ret = snd_use_case_apply_mixer_controls(uc_mgr,
1359 device, enable, CTRL_LIST_DEVICE, dev_index);
1360 if (!ret)
1361 snd_ucm_set_status_at_index(
SathishKumar Mani98580102012-09-20 14:46:37 -07001362 uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
1363 capability);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001364 flag = 1;
1365 }
1366 }
1367 use_case[0] = 0;
1368 strlcpy(use_case, uc_mgr->card_ctxt_ptr->current_verb,
1369 sizeof(use_case));
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001370 if ((uc_index =
1371 get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB)) < 0) {
1372 ALOGE("No valid use case %s found", use_case);
1373 } else if (capability == CAP_VOICE ||
Iliyan Malchev4765c432012-06-11 14:36:16 -07001374 capability ==
1375 getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ||
1376 getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ==
1377 CAP_VOICE) {
1378 ALOGV("set %d for use case value: %s", enable, use_case);
1379 ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
1380 enable, CTRL_LIST_VERB, uc_index);
1381 if (ret != 0)
1382 ALOGE("No valid controls exists for usecase %s and \
1383 device %s, enable: %d", use_case, device, enable);
1384 }
1385 intdev_flag = 0;
1386 }
1387 use_case[0] = 0;
1388 }
1389 snd_ucm_print_list(uc_mgr->card_ctxt_ptr->mod_list_head);
1390 uc_list =
1391 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].mod_ctrls;
1392 list_size = snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->mod_list_head);
1393 for (index = 0; index < list_size; index++) {
1394 if ((ident_value =
1395 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
1396 index))) {
SathishKumar Mani98580102012-09-20 14:46:37 -07001397 if (capability == CAP_VOICE ||
1398 getUseCaseType(ident_value) == CAP_VOICE ||
1399 capability == getUseCaseType(ident_value)) {
1400 strlcpy(use_case, ident_value, sizeof(use_case));
1401 strlcat(use_case, device, sizeof(use_case));
1402 if ((uc_index = get_use_case_index(uc_mgr, use_case,
1403 CTRL_LIST_MODIFIER)) < 0) {
1404 ALOGV("No valid use case found: %s", use_case);
1405 intdev_flag = 1;
1406 } else {
1407 if (enable && !flag) {
1408 if (!snd_ucm_get_status_at_index(
1409 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1410 ret = snd_use_case_apply_mixer_controls(uc_mgr,
1411 device, enable, CTRL_LIST_DEVICE,
1412 dev_index);
1413 if (!ret)
1414 snd_ucm_set_status_at_index(
1415 uc_mgr->card_ctxt_ptr->dev_list_head,
1416 device, enable, capability);
1417 flag = 1;
1418 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07001419 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07001420 ALOGV("set %d for use case value: %s", enable, use_case);
SathishKumar Mani98580102012-09-20 14:46:37 -07001421 ret = snd_use_case_apply_mixer_controls(uc_mgr,
1422 use_case, enable, CTRL_LIST_MODIFIER, uc_index);
1423 if (ret != 0)
1424 ALOGE("No valid controls exists for usecase %s and \
1425 device %s, enable: %d", use_case, device, enable);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001426 }
1427 }
1428 if (intdev_flag) {
1429 if (enable && !flag) {
1430 if (!snd_ucm_get_status_at_index(
1431 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1432 ret = snd_use_case_apply_mixer_controls(uc_mgr,
1433 device, enable, CTRL_LIST_DEVICE, dev_index);
1434 if (!ret)
1435 snd_ucm_set_status_at_index(
1436 uc_mgr->card_ctxt_ptr->dev_list_head, device,
SathishKumar Mani98580102012-09-20 14:46:37 -07001437 enable, capability);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001438 flag = 1;
1439 }
1440 }
1441 use_case[0] = 0;
1442 strlcpy(use_case, ident_value, sizeof(use_case));
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001443 if ((uc_index =
1444 get_use_case_index(uc_mgr, ident_value,
1445 CTRL_LIST_MODIFIER)) < 0) {
1446 ALOGE("No valid use case %s found", ident_value);
1447 } else if (capability == CAP_VOICE ||
Iliyan Malchev4765c432012-06-11 14:36:16 -07001448 capability == getUseCaseType(ident_value) ||
1449 getUseCaseType(ident_value) == CAP_VOICE) {
1450 ALOGV("set %d for use case value: %s", enable, use_case);
1451 ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
1452 enable, CTRL_LIST_MODIFIER, uc_index);
1453 if (ret != 0)
1454 ALOGE("No valid controls exists for usecase %s and \
1455 device %s, enable: %d", use_case, device, enable);
1456 }
1457 intdev_flag = 0;
1458 }
1459 use_case[0] = 0;
1460 free(ident_value);
1461 }
1462 }
1463 if (!enable) {
1464 ret = snd_use_case_apply_mixer_controls(uc_mgr, device, enable,
1465 CTRL_LIST_DEVICE, dev_index);
1466 if (!ret)
1467 snd_ucm_set_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
SathishKumar Mani98580102012-09-20 14:46:37 -07001468 device, enable, capability);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001469 }
1470 return ret;
1471}
1472
1473/* Returns usecase type i.e. either verb or modifier
1474 * uc_mgr - UCM structure pointer
1475 * usecase - usecase name either verb or modifier
1476 * return CTRL_LIST_VERB or CTRL_LIST_MODIFIER for verb/modifier respectively
1477 */
1478static int get_usecase_type(snd_use_case_mgr_t *uc_mgr, const char *usecase)
1479{
1480 int ret = -EINVAL, index = 0;
1481
1482 while (strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1483 SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
1484 if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index], usecase,
1485 (strlen(usecase)+1))) {
1486 ret = 0;
1487 break;
1488 }
1489 index++;
1490 }
1491 if (ret == 0)
1492 return CTRL_LIST_VERB;
1493 else
1494 return CTRL_LIST_MODIFIER;
1495}
1496
1497/* Set/Reset mixer controls of specific device and specific use cases
1498 * uc_mgr - UCM structure pointer
1499 * device - device name
1500 * usecase - use case for which device needs to be enabled
1501 * enable - 1 for enable and 0 for disable
1502 * return 0 on sucess, otherwise a negative error code
1503 */
1504static int set_controls_of_device_for_usecase(snd_use_case_mgr_t *uc_mgr,
1505 const char *device, const char *usecase, int enable)
1506{
SathishKumar Mani98580102012-09-20 14:46:37 -07001507 card_mctrl_t *dev_list;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001508 char use_case[MAX_UC_LEN];
1509 int ret = -ENODEV, uc_index, dev_index;
SathishKumar Mani98580102012-09-20 14:46:37 -07001510 int verb_index, capability = 0;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001511
1512 ALOGV("set_device_for_ident(): %s %s", device, usecase);
SathishKumar Mani98580102012-09-20 14:46:37 -07001513 if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
1514 verb_index = 0;
1515 dev_list =
1516 uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001517 if ((dev_index =
1518 get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE)) < 0) {
1519 ALOGE("No valid device %s found", device);
1520 return dev_index;
1521 }
SathishKumar Mani98580102012-09-20 14:46:37 -07001522 capability = dev_list[dev_index].capability;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001523 if (usecase != NULL) {
1524 strlcpy(use_case, usecase, sizeof(use_case));
1525 strlcat(use_case, device, sizeof(use_case));
1526 if ((uc_index = get_use_case_index(uc_mgr, use_case,
1527 get_usecase_type(uc_mgr, usecase))) < 0) {
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001528 ALOGV("No valid use case found: %s,\
1529 set %d for use case value: %s",use_case, enable, usecase);
1530 if ((uc_index =
1531 get_use_case_index(uc_mgr, usecase, get_usecase_type(uc_mgr, usecase))) < 0) {
1532 ALOGE("No valid use case found: %s", usecase);
1533 } else {
1534 ret = snd_use_case_apply_mixer_controls(uc_mgr, usecase, enable,
1535 get_usecase_type(uc_mgr, usecase), uc_index);
1536 if (ret != 0)
1537 ALOGE("No valid controls exists for usecase %s and device %s, \
1538 enable: %d", usecase, device, enable);
1539 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07001540 } else {
1541 if (enable) {
1542 if (!snd_ucm_get_status_at_index(
1543 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1544 ret = snd_use_case_apply_mixer_controls(uc_mgr, device,
1545 enable, CTRL_LIST_DEVICE, dev_index);
1546 if (!ret)
1547 snd_ucm_set_status_at_index
SathishKumar Mani98580102012-09-20 14:46:37 -07001548 (uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
1549 capability);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001550 }
1551 }
1552 ALOGV("set %d for use case value: %s", enable, use_case);
1553 ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case, enable,
1554 get_usecase_type(uc_mgr, usecase), uc_index);
1555 if (ret != 0)
1556 ALOGE("No valid controls exists for usecase %s and device %s, \
1557 enable: %d", use_case, device, enable);
1558 }
1559 use_case[0] = 0;
1560 } else {
1561 if (enable) {
1562 if (!snd_ucm_get_status_at_index(
1563 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
1564 ret = snd_use_case_apply_mixer_controls(uc_mgr, device, enable,
1565 CTRL_LIST_DEVICE, dev_index);
1566 if (!ret)
1567 snd_ucm_set_status_at_index(
SathishKumar Mani98580102012-09-20 14:46:37 -07001568 uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
1569 capability);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001570 }
1571 }
1572 }
1573 if (!enable) {
1574 ret = snd_use_case_apply_mixer_controls(uc_mgr, device, enable,
1575 CTRL_LIST_DEVICE, dev_index);
1576 if (!ret)
1577 snd_ucm_set_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
SathishKumar Mani98580102012-09-20 14:46:37 -07001578 device, enable, capability);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001579 }
1580 return ret;
1581}
1582
1583/**
1584 * Set new value for an identifier
1585 * uc_mgr - UCM structure
1586 * identifier - _verb, _enadev, _disdev, _enamod, _dismod
1587 * _swdev, _swmod
1588 * value - Value to be set
1589 * returns 0 on success, otherwise a negative error code
1590 */
1591int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
1592 const char *identifier,
1593 const char *value)
1594{
1595 use_case_verb_t *verb_list;
1596 char ident[MAX_STR_LEN], *ident1, *ident2, *temp_ptr;
1597 int verb_index, list_size, index = 0, ret = -EINVAL;
1598
1599 pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
1600 if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) || (value == NULL) ||
1601 (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL) ||
1602 (identifier == NULL)) {
1603 ALOGE("snd_use_case_set(): failed, invalid arguments");
1604 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1605 return -EINVAL;
1606 }
1607
1608 ALOGD("snd_use_case_set(): uc_mgr %p identifier %s value %s", uc_mgr,
1609 identifier, value);
1610 strlcpy(ident, identifier, sizeof(ident));
1611 if(!(ident1 = strtok_r(ident, "/", &temp_ptr))) {
1612 ALOGV("No multiple identifiers found in identifier value");
1613 ident[0] = 0;
1614 } else {
1615 if (!strncmp(ident1, "_swdev", 6)) {
1616 if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
1617 ALOGD("Invalid disable device value: %s, but enabling new \
1618 device", ident2);
1619 } else {
1620 ret = snd_ucm_del_ident_from_list(
1621 &uc_mgr->card_ctxt_ptr->dev_list_head, ident2);
1622 if (ret < 0) {
1623 ALOGV("Ignore device %s disable, device not part of \
1624 enabled list", ident2);
1625 } else {
1626 ALOGV("swdev: device value to be disabled: %s", ident2);
1627 /* Disable mixer controls for
1628 * corresponding use cases and device */
1629 ret = set_controls_of_device_for_all_usecases(uc_mgr,
1630 ident2, 0);
1631 if (ret < 0) {
1632 ALOGV("Device %s not disabled, no valid use case \
1633 found: %d", ident2, errno);
1634 }
1635 }
1636 }
1637 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1638 ret = snd_use_case_set(uc_mgr, "_enadev", value);
1639 if (ret < 0) {
1640 ALOGV("Device %s not enabled, no valid use case found: %d",
1641 value, errno);
1642 }
1643 return ret;
1644 } else if (!strncmp(ident1, "_swmod", 6)) {
1645 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1646 if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
1647 ALOGD("Invalid modifier value: %s, but enabling new modifier",
1648 ident2);
1649 } else {
1650 ret = snd_use_case_set(uc_mgr, "_dismod", ident2);
1651 if (ret < 0) {
1652 ALOGV("Modifier %s not disabled, no valid use case \
1653 found: %d", ident2, errno);
1654 }
1655 }
1656 ret = snd_use_case_set(uc_mgr, "_enamod", value);
1657 if (ret < 0) {
1658 ALOGV("Modifier %s not enabled, no valid use case found: %d",
1659 value, errno);
1660 }
1661 return ret;
1662 } else {
1663 ALOGV("No switch device/modifier option found: %s", ident1);
1664 }
1665 ident[0] = 0;
1666 }
1667
1668 if (!strncmp(identifier, "_verb", 5)) {
1669 /* Check if value is valid verb */
1670 while (strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1671 SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))) {
1672 if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index], value,
1673 (strlen(value)+1))) {
1674 ret = 0;
1675 break;
1676 }
1677 index++;
1678 }
1679 if ((ret < 0) && (strncmp(value, SND_USE_CASE_VERB_INACTIVE,
1680 strlen(SND_USE_CASE_VERB_INACTIVE)))) {
1681 ALOGE("Invalid verb identifier value");
1682 } else {
1683 ALOGV("Index:%d Verb:%s", index,
1684 uc_mgr->card_ctxt_ptr->verb_list[index]);
1685 /* Disable the mixer controls for current use case
1686 * for all the enabled devices */
1687 if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
1688 SND_USE_CASE_VERB_INACTIVE,
1689 strlen(SND_USE_CASE_VERB_INACTIVE))) {
1690 ret = set_controls_of_usecase_for_all_devices(uc_mgr,
1691 uc_mgr->card_ctxt_ptr->current_verb, 0, CTRL_LIST_VERB);
1692 if (ret != 0)
1693 ALOGE("Failed to disable controls for use case: %s",
1694 uc_mgr->card_ctxt_ptr->current_verb);
1695 }
1696 strlcpy(uc_mgr->card_ctxt_ptr->current_verb, value, MAX_STR_LEN);
1697 /* Enable the mixer controls for the new use case
1698 * for all the enabled devices */
1699 if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
1700 SND_USE_CASE_VERB_INACTIVE,
1701 strlen(SND_USE_CASE_VERB_INACTIVE))) {
1702 uc_mgr->card_ctxt_ptr->current_verb_index = index;
1703 ret = set_controls_of_usecase_for_all_devices(uc_mgr,
1704 uc_mgr->card_ctxt_ptr->current_verb, 1, CTRL_LIST_VERB);
1705 }
1706 }
1707 } else if (!strncmp(identifier, "_enadev", 7)) {
1708 index = 0; ret = 0;
1709 list_size =
1710 snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1711 for (index = 0; index < list_size; index++) {
1712 if ((ident1 =
1713 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1714 index))) {
1715 if (!strncmp(ident1, value, (strlen(value)+1))) {
1716 ALOGV("Ignore enable as %s device is already part of \
1717 enabled list", value);
1718 free(ident1);
1719 break;
1720 }
1721 free(ident1);
1722 }
1723 }
1724 if (index == list_size) {
1725 ALOGV("enadev: device value to be enabled: %s", value);
1726 snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1727 value);
1728 }
1729 snd_ucm_print_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1730 /* Apply Mixer controls of all verb and modifiers for this device*/
1731 ret = set_controls_of_device_for_all_usecases(uc_mgr, value, 1);
1732 } else if (!strncmp(identifier, "_disdev", 7)) {
1733 ret = snd_ucm_get_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1734 value);
1735 if (ret < 0) {
1736 ALOGD("disdev: device %s not enabled, no need to disable", value);
1737 } else if (ret == 0) {
1738 ALOGV("disdev: device %s not active, remove from the list", value);
1739 ret =
1740 snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1741 value);
1742 if (ret < 0) {
1743 ALOGE("Invalid device: Device not part of enabled device list");
1744 }
1745 } else {
1746 ret =
1747 snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1748 value);
1749 if (ret < 0) {
1750 ALOGE("Invalid device: Device not part of enabled device list");
1751 } else {
1752 ALOGV("disdev: device value to be disabled: %s", value);
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001753 if ((index =
1754 get_use_case_index(uc_mgr, value, CTRL_LIST_DEVICE)) < 0) {
1755 ALOGE("Device %s not found", value);
1756 ret = -EINVAL;
1757 } else {
1758 /* Apply Mixer controls for device and modifier */
1759 ret = snd_use_case_apply_mixer_controls(uc_mgr, value, 0,
Iliyan Malchev4765c432012-06-11 14:36:16 -07001760 CTRL_LIST_DEVICE, index);
Mingming Yinbbd94ad2012-11-29 20:04:36 -08001761 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07001762 }
1763 }
1764 } else if (!strncmp(identifier, "_enamod", 7)) {
1765 index = 0; ret = 0;
1766 verb_index = uc_mgr->card_ctxt_ptr->current_verb_index;
1767 if (verb_index < 0) {
1768 ALOGE("Invalid verb identifier value");
1769 } else {
1770 ALOGV("Index:%d Verb:%s", verb_index,
1771 uc_mgr->card_ctxt_ptr->verb_list[verb_index]);
1772 verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
1773 while(strncmp(verb_list[verb_index].modifier_list[index], value,
1774 (strlen(value)+1))) {
1775 if (!strncmp(verb_list[verb_index].modifier_list[index],
1776 SND_UCM_END_OF_LIST, strlen(SND_UCM_END_OF_LIST))){
1777 ret = -EINVAL;
1778 break;
1779 }
1780 index++;
1781 }
1782 if (ret < 0) {
1783 ALOGE("Invalid modifier identifier value");
1784 } else {
1785 snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
1786 value);
1787 /* Enable the mixer controls for the new use case
1788 * for all the enabled devices */
1789 ret = set_controls_of_usecase_for_all_devices(uc_mgr, value, 1,
1790 CTRL_LIST_MODIFIER);
1791 }
1792 }
1793 } else if (!strncmp(identifier, "_dismod", 7)) {
1794 ret = snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
1795 value);
1796 if (ret < 0) {
1797 ALOGE("Modifier not enabled currently, invalid modifier");
1798 } else {
1799 ALOGV("dismod: modifier value to be disabled: %s", value);
1800 /* Enable the mixer controls for the new use case
1801 * for all the enabled devices */
1802 ret = set_controls_of_usecase_for_all_devices(uc_mgr, value, 0,
1803 CTRL_LIST_MODIFIER);
1804 }
1805 } else {
1806 ALOGE("Unknown identifier value: %s", identifier);
1807 }
1808 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1809 return ret;
1810}
1811
1812/**
1813 * Set new value for an identifier based on use case
1814 * uc_mgr - UCM structure
1815 * identifier - _verb, _enadev, _disdev, _enamod, _dismod
1816 * _swdev, _swmod
1817 * value - Value to be set
1818 * usecase - usecase/device for which this command needs to be executed
1819 * returns 0 on success, otherwise a negative error code
1820 */
1821int snd_use_case_set_case(snd_use_case_mgr_t *uc_mgr,
1822 const char *identifier,
1823 const char *value, const char *usecase)
1824{
1825 use_case_verb_t *verb_list;
1826 char ident[MAX_STR_LEN], *ident1, *ident2, *temp_ptr;
1827 int verb_index, list_size, index = 0, ret = -EINVAL;
1828
1829 pthread_mutex_lock(&uc_mgr->card_ctxt_ptr->card_lock);
1830 if ((uc_mgr->snd_card_index >= (int)MAX_NUM_CARDS) || (value == NULL) ||
1831 (uc_mgr->snd_card_index < 0) || (uc_mgr->card_ctxt_ptr == NULL) ||
1832 (identifier == NULL)) {
1833 ALOGE("snd_use_case_set_case(): failed, invalid arguments");
1834 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1835 return -EINVAL;
1836 }
1837
1838 ALOGD("snd_use_case_set_case(): uc_mgr %p identifier %s value %s",
1839 uc_mgr, identifier, value);
1840 strlcpy(ident, identifier, sizeof(ident));
1841 if(!(ident1 = strtok_r(ident, "/", &temp_ptr))) {
1842 ALOGV("No multiple identifiers found in identifier value");
1843 ident[0] = 0;
1844 } else {
1845 if (!strncmp(ident1, "_swdev", 6)) {
1846 if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
1847 ALOGD("Invalid disable device value: %s, but enabling new \
1848 device", ident2);
1849 } else {
1850 ret = snd_ucm_del_ident_from_list(
1851 &uc_mgr->card_ctxt_ptr->dev_list_head, ident2);
1852 if (ret < 0) {
1853 ALOGV("Ignore device %s disable, device not part of \
1854 enabled list", ident2);
1855 } else {
1856 ALOGV("swdev: device value to be disabled: %s", ident2);
1857 /* Disable mixer controls for
1858 * corresponding use cases and device */
1859 ret = set_controls_of_device_for_usecase(uc_mgr, ident2,
1860 usecase, 0);
1861 if (ret < 0) {
1862 ALOGV("Device %s not disabled, no valid use case \
1863 found: %d", ident2, errno);
1864 }
1865 }
1866 }
1867 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1868 ret = snd_use_case_set_case(uc_mgr, "_enadev", value, usecase);
1869 if (ret < 0) {
1870 ALOGV("Device %s not enabled, no valid use case found: %d",
1871 value, errno);
1872 }
1873 return ret;
1874 } else if (!strncmp(ident1, "_swmod", 6)) {
1875 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
1876 if(!(ident2 = strtok_r(NULL, "/", &temp_ptr))) {
1877 ALOGD("Invalid modifier value: %s, but enabling new modifier",
1878 ident2);
1879 } else {
1880 ret = snd_use_case_set_case(uc_mgr, "_dismod", ident2, usecase);
1881 if (ret < 0) {
1882 ALOGV("Modifier %s not disabled, no valid use case \
1883 found: %d", ident2, errno);
1884 }
1885 }
1886 ret = snd_use_case_set_case(uc_mgr, "_enamod", value, usecase);
1887 if (ret < 0) {
1888 ALOGV("Modifier %s not enabled, no valid use case found: %d",
1889 value, errno);
1890 }
1891 return ret;
1892 } else {
1893 ALOGV("No switch device/modifier option found: %s", ident1);
1894 }
1895 ident[0] = 0;
1896 }
1897
1898 if (!strncmp(identifier, "_verb", 5)) {
1899 /* Check if value is valid verb */
1900 while (strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1901 SND_UCM_END_OF_LIST, MAX_STR_LEN)) {
1902 if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
1903 value, MAX_STR_LEN)) {
1904 ret = 0;
1905 break;
1906 }
1907 index++;
1908 }
1909 if ((ret < 0) && (strncmp(value, SND_USE_CASE_VERB_INACTIVE,
1910 MAX_STR_LEN))) {
1911 ALOGE("Invalid verb identifier value");
1912 } else {
1913 ALOGV("Index:%d Verb:%s", index,
1914 uc_mgr->card_ctxt_ptr->verb_list[index]);
1915 /* Disable the mixer controls for current use case
1916 * for specified device */
1917 if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
1918 SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN)) {
1919 ret = set_controls_of_usecase_for_device(uc_mgr,
1920 uc_mgr->card_ctxt_ptr->current_verb, usecase,
1921 0, CTRL_LIST_VERB);
1922 if (ret != 0)
1923 ALOGE("Failed to disable controls for use case: %s",
1924 uc_mgr->card_ctxt_ptr->current_verb);
1925 }
1926 strlcpy(uc_mgr->card_ctxt_ptr->current_verb, value, MAX_STR_LEN);
1927 /* Enable the mixer controls for the new use case
1928 * for specified device */
1929 if (strncmp(uc_mgr->card_ctxt_ptr->current_verb,
1930 SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN)) {
1931 uc_mgr->card_ctxt_ptr->current_verb_index = index;
1932 index = 0;
1933 list_size =
1934 snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1935 for (index = 0; index < list_size; index++) {
1936 if ((ident1 = snd_ucm_get_value_at_index(
1937 uc_mgr->card_ctxt_ptr->dev_list_head, index))) {
1938 if (!strncmp(ident1, usecase, MAX_STR_LEN)) {
1939 ALOGV("Device already part of enabled list: %s",
1940 usecase);
1941 free(ident1);
1942 break;
1943 }
1944 free(ident1);
1945 }
1946 }
1947 if (index == list_size) {
1948 ALOGV("enadev: device value to be enabled: %s", usecase);
1949 snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1950 usecase);
1951 }
1952 ret = set_controls_of_usecase_for_device(uc_mgr,
1953 uc_mgr->card_ctxt_ptr->current_verb, usecase,
1954 1, CTRL_LIST_VERB);
1955 }
1956 }
1957 } else if (!strncmp(identifier, "_enadev", 7)) {
1958 index = 0; ret = 0;
1959 list_size =
1960 snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1961 for (index = 0; index < list_size; index++) {
1962 if ((ident1 =
1963 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1964 index))) {
1965 if (!strncmp(ident1, value, MAX_STR_LEN)) {
1966 ALOGV("Device already part of enabled list: %s", value);
1967 free(ident1);
1968 break;
1969 }
1970 free(ident1);
1971 }
1972 }
1973 if (index == list_size) {
1974 ALOGV("enadev: device value to be enabled: %s", value);
1975 snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1976 value);
1977 }
1978 snd_ucm_print_list(uc_mgr->card_ctxt_ptr->dev_list_head);
1979 /* Apply Mixer controls of usecase for this device*/
1980 ret = set_controls_of_device_for_usecase(uc_mgr, value, usecase, 1);
1981 } else if (!strncmp(identifier, "_disdev", 7)) {
1982 ret = snd_ucm_get_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
1983 value);
1984 if (ret < 0) {
1985 ALOGD("disdev: device %s not enabled, no need to disable", value);
1986 } else if (ret == 0) {
1987 ALOGV("disdev: device %s not active, remove from the list", value);
1988 ret =
1989 snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1990 value);
1991 if (ret < 0) {
1992 ALOGE("Invalid device: Device not part of enabled device list");
1993 }
1994 } else {
1995 ret =
1996 snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
1997 value);
1998 if (ret < 0) {
1999 ALOGE("Invalid device: Device not part of enabled device list");
2000 } else {
2001 ALOGV("disdev: device value to be disabled: %s", value);
2002 /* Apply Mixer controls of usecase for this device*/
2003 ret = set_controls_of_device_for_usecase(uc_mgr, value,
2004 usecase, 0);
2005 }
2006 }
2007 } else if (!strncmp(identifier, "_enamod", 7)) {
2008 if (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
2009 SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN)) {
2010 ALOGE("Invalid use case verb value");
2011 ret = -EINVAL;
2012 } else {
2013 ret = 0;
2014 while(strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
2015 uc_mgr->card_ctxt_ptr->current_verb, MAX_STR_LEN)) {
2016 if (!strncmp(uc_mgr->card_ctxt_ptr->verb_list[index],
2017 SND_UCM_END_OF_LIST, MAX_STR_LEN)){
2018 ret = -EINVAL;
2019 break;
2020 }
2021 index++;
2022 }
2023 }
2024 if (ret < 0) {
2025 ALOGE("Invalid verb identifier value");
2026 } else {
2027 verb_index = index; index = 0; ret = 0;
2028 verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
2029 ALOGV("Index:%d Verb:%s", verb_index,
2030 uc_mgr->card_ctxt_ptr->verb_list[verb_index]);
2031 while(strncmp(verb_list[verb_index].modifier_list[index],
2032 value, MAX_STR_LEN)) {
2033 if (!strncmp(verb_list[verb_index].modifier_list[index],
2034 SND_UCM_END_OF_LIST, MAX_STR_LEN)){
2035 ret = -EINVAL;
2036 break;
2037 }
2038 index++;
2039 }
2040 if (ret < 0) {
2041 ALOGE("Invalid modifier identifier value");
2042 } else {
2043 index = 0;
2044 list_size =
2045 snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
2046 for (index = 0; index < list_size; index++) {
2047 if ((ident1 = snd_ucm_get_value_at_index(
2048 uc_mgr->card_ctxt_ptr->dev_list_head, index))) {
2049 if (!strncmp(ident1, usecase, MAX_STR_LEN)) {
2050 ALOGV("Device already part of enabled list: %s",
2051 usecase);
2052 free(ident1);
2053 break;
2054 }
2055 free(ident1);
2056 }
2057 }
2058 if (index == list_size) {
2059 ALOGV("enadev: device value to be enabled: %s", usecase);
2060 snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->dev_list_head,
2061 usecase);
2062 }
2063 snd_ucm_add_ident_to_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
2064 value);
2065 /* Enable the mixer controls for the new use case
2066 * for all the enabled devices */
2067 ret = set_controls_of_usecase_for_device(uc_mgr, value,
2068 usecase, 1, CTRL_LIST_MODIFIER);
2069 }
2070 }
2071 } else if (!strncmp(identifier, "_dismod", 7)) {
2072 ret = snd_ucm_del_ident_from_list(&uc_mgr->card_ctxt_ptr->mod_list_head,
2073 value);
2074 if (ret < 0) {
2075 ALOGE("Modifier not enabled currently, invalid modifier");
2076 } else {
2077 ALOGV("dismod: modifier value to be disabled: %s", value);
2078 /* Enable the mixer controls for the new use case
2079 * for all the enabled devices */
2080 ret = set_controls_of_usecase_for_device(uc_mgr, value, usecase,
2081 0, CTRL_LIST_MODIFIER);
2082 }
2083 } else {
2084 ALOGE("Unknown identifier value: %s", identifier);
2085 }
2086 pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
2087 return ret;
2088}
2089
2090/**
2091 * Open and initialise use case core for sound card
2092 * uc_mgr - Returned use case manager pointer
2093 * card_name - Sound card name.
2094 * returns 0 on success, otherwise a negative error code
2095 */
2096int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, const char *card_name)
2097{
2098 snd_use_case_mgr_t *uc_mgr_ptr = NULL;
2099 int index, ret = -EINVAL;
2100 char tmp[2];
2101
2102 ALOGV("snd_use_case_open(): card_name %s", card_name);
2103
2104 if (card_name == NULL) {
2105 ALOGE("snd_use_case_mgr_open: failed, invalid arguments");
2106 return ret;
2107 }
2108
2109 for (index = 0; index < (int)MAX_NUM_CARDS; index++) {
2110 if(!strncmp(card_name, card_mapping_list[index].card_name,
2111 (strlen(card_mapping_list[index].card_name)+1))) {
2112 ret = 0;
2113 break;
2114 }
2115 }
2116
2117 if (ret < 0) {
2118 ALOGE("Card %s not found", card_name);
2119 } else {
2120 uc_mgr_ptr = (snd_use_case_mgr_t *)calloc(1,
2121 sizeof(snd_use_case_mgr_t));
2122 if (uc_mgr_ptr == NULL) {
2123 ALOGE("Failed to allocate memory for instance");
2124 return -ENOMEM;
2125 }
2126 uc_mgr_ptr->snd_card_index = index;
2127 uc_mgr_ptr->card_ctxt_ptr = (card_ctxt_t *)calloc(1,
2128 sizeof(card_ctxt_t));
2129 if (uc_mgr_ptr->card_ctxt_ptr == NULL) {
2130 ALOGE("Failed to allocate memory for card context");
2131 free(uc_mgr_ptr);
2132 uc_mgr_ptr = NULL;
2133 return -ENOMEM;
2134 }
2135 uc_mgr_ptr->card_ctxt_ptr->card_number =
2136 card_mapping_list[index].card_number;
2137 uc_mgr_ptr->card_ctxt_ptr->card_name =
2138 (char *)malloc((strlen(card_name)+1)*sizeof(char));
2139 if (uc_mgr_ptr->card_ctxt_ptr->card_name == NULL) {
2140 ALOGE("Failed to allocate memory for card name");
2141 free(uc_mgr_ptr->card_ctxt_ptr);
2142 free(uc_mgr_ptr);
2143 uc_mgr_ptr = NULL;
2144 return -ENOMEM;
2145 }
2146 strlcpy(uc_mgr_ptr->card_ctxt_ptr->card_name, card_name,
2147 ((strlen(card_name)+1)*sizeof(char)));
2148 uc_mgr_ptr->card_ctxt_ptr->control_device =
2149 (char *)malloc((strlen("/dev/snd/controlC")+2)*sizeof(char));
2150 if (uc_mgr_ptr->card_ctxt_ptr->control_device == NULL) {
2151 ALOGE("Failed to allocate memory for control device string");
2152 free(uc_mgr_ptr->card_ctxt_ptr->card_name);
2153 free(uc_mgr_ptr->card_ctxt_ptr);
2154 free(uc_mgr_ptr);
2155 uc_mgr_ptr = NULL;
2156 return -ENOMEM;
2157 }
2158 strlcpy(uc_mgr_ptr->card_ctxt_ptr->control_device,
2159 "/dev/snd/controlC", 18);
2160 snprintf(tmp, sizeof(tmp), "%d",
2161 uc_mgr_ptr->card_ctxt_ptr->card_number);
2162 strlcat(uc_mgr_ptr->card_ctxt_ptr->control_device, tmp,
2163 (strlen("/dev/snd/controlC")+2)*sizeof(char));
2164 uc_mgr_ptr->device_list_count = 0;
2165 uc_mgr_ptr->modifier_list_count = 0;
2166 uc_mgr_ptr->current_device_list = NULL;
2167 uc_mgr_ptr->current_modifier_list = NULL;
2168 uc_mgr_ptr->current_tx_device = -1;
2169 uc_mgr_ptr->current_rx_device = -1;
2170 pthread_mutexattr_init(&uc_mgr_ptr->card_ctxt_ptr->card_lock_attr);
2171 pthread_mutex_init(&uc_mgr_ptr->card_ctxt_ptr->card_lock,
2172 &uc_mgr_ptr->card_ctxt_ptr->card_lock_attr);
2173 strlcpy(uc_mgr_ptr->card_ctxt_ptr->current_verb,
2174 SND_USE_CASE_VERB_INACTIVE, MAX_STR_LEN);
2175 /* Reset all mixer controls if any applied
2176 * previously for the same card */
SathishKumar Mani9efed762012-09-18 18:52:48 -07002177 snd_use_case_mgr_reset(uc_mgr_ptr);
Iliyan Malchev4765c432012-06-11 14:36:16 -07002178 uc_mgr_ptr->card_ctxt_ptr->current_verb_index = -1;
2179 /* Parse config files and update mixer controls */
2180 ret = snd_ucm_parse(&uc_mgr_ptr);
2181 if(ret < 0) {
2182 ALOGE("Failed to parse config files: %d", ret);
2183 snd_ucm_free_mixer_list(&uc_mgr_ptr);
2184 }
2185 ALOGV("Open mixer device: %s",
2186 uc_mgr_ptr->card_ctxt_ptr->control_device);
2187 uc_mgr_ptr->card_ctxt_ptr->mixer_handle =
2188 mixer_open(uc_mgr_ptr->card_ctxt_ptr->control_device);
2189 ALOGV("Mixer handle %p", uc_mgr_ptr->card_ctxt_ptr->mixer_handle);
Iliyan Malchev4765c432012-06-11 14:36:16 -07002190 *uc_mgr = uc_mgr_ptr;
2191 }
2192 ALOGV("snd_use_case_open(): returning instance %p", uc_mgr_ptr);
2193 return ret;
2194}
2195
2196
2197/**
2198 * \brief Reload and re-parse use case configuration files for sound card.
2199 * \param uc_mgr Use case manager
2200 * \return zero if success, otherwise a negative error code
2201 */
2202int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr) {
2203 ALOGE("Reload is not implemented for now as there is no use case currently");
2204 return 0;
2205}
2206
2207/**
2208 * \brief Close use case manager
2209 * \param uc_mgr Use case manager
2210 * \return zero if success, otherwise a negative error code
2211 */
2212int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
2213{
2214 int ret = 0;
2215
2216 if ((uc_mgr->