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