1cef935958069ffba745cd091e6e1687095ea6785Simon Wilson/* 2cef935958069ffba745cd091e6e1687095ea6785Simon Wilson * Copyright (C) 2013 The Android Open Source Project 3cef935958069ffba745cd091e6e1687095ea6785Simon Wilson * Inspired by TinyHW, written by Mark Brown at Wolfson Micro 4cef935958069ffba745cd091e6e1687095ea6785Simon Wilson * 5cef935958069ffba745cd091e6e1687095ea6785Simon Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 6cef935958069ffba745cd091e6e1687095ea6785Simon Wilson * you may not use this file except in compliance with the License. 7cef935958069ffba745cd091e6e1687095ea6785Simon Wilson * You may obtain a copy of the License at 8cef935958069ffba745cd091e6e1687095ea6785Simon Wilson * 9cef935958069ffba745cd091e6e1687095ea6785Simon Wilson * http://www.apache.org/licenses/LICENSE-2.0 10cef935958069ffba745cd091e6e1687095ea6785Simon Wilson * 11cef935958069ffba745cd091e6e1687095ea6785Simon Wilson * Unless required by applicable law or agreed to in writing, software 12cef935958069ffba745cd091e6e1687095ea6785Simon Wilson * distributed under the License is distributed on an "AS IS" BASIS, 13cef935958069ffba745cd091e6e1687095ea6785Simon Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14cef935958069ffba745cd091e6e1687095ea6785Simon Wilson * See the License for the specific language governing permissions and 15cef935958069ffba745cd091e6e1687095ea6785Simon Wilson * limitations under the License. 16cef935958069ffba745cd091e6e1687095ea6785Simon Wilson */ 17cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 18cef935958069ffba745cd091e6e1687095ea6785Simon Wilson#define LOG_TAG "audio_route" 19cef935958069ffba745cd091e6e1687095ea6785Simon Wilson/*#define LOG_NDEBUG 0*/ 20cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 21cef935958069ffba745cd091e6e1687095ea6785Simon Wilson#include <errno.h> 22cef935958069ffba745cd091e6e1687095ea6785Simon Wilson#include <expat.h> 23cef935958069ffba745cd091e6e1687095ea6785Simon Wilson#include <stdbool.h> 24cef935958069ffba745cd091e6e1687095ea6785Simon Wilson#include <stdio.h> 25cef935958069ffba745cd091e6e1687095ea6785Simon Wilson#include <string.h> 26cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 27cef935958069ffba745cd091e6e1687095ea6785Simon Wilson#include <cutils/log.h> 28cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 29cef935958069ffba745cd091e6e1687095ea6785Simon Wilson#include <tinyalsa/asoundlib.h> 30cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 31cef935958069ffba745cd091e6e1687095ea6785Simon Wilson#define BUF_SIZE 1024 32cef935958069ffba745cd091e6e1687095ea6785Simon Wilson#define MIXER_XML_PATH "/system/etc/mixer_paths.xml" 33cef935958069ffba745cd091e6e1687095ea6785Simon Wilson#define INITIAL_MIXER_PATH_SIZE 8 34cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 35cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstruct mixer_state { 36cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct mixer_ctl *ctl; 37cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int num_values; 38cef935958069ffba745cd091e6e1687095ea6785Simon Wilson int *old_value; 39cef935958069ffba745cd091e6e1687095ea6785Simon Wilson int *new_value; 40cef935958069ffba745cd091e6e1687095ea6785Simon Wilson int *reset_value; 41cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}; 42cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 43cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstruct mixer_setting { 44f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson unsigned int ctl_index; 45cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int num_values; 46cef935958069ffba745cd091e6e1687095ea6785Simon Wilson int *value; 47cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}; 48cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 49cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstruct mixer_value { 50f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson unsigned int ctl_index; 51cef935958069ffba745cd091e6e1687095ea6785Simon Wilson int index; 52cef935958069ffba745cd091e6e1687095ea6785Simon Wilson int value; 53cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}; 54cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 55cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstruct mixer_path { 56cef935958069ffba745cd091e6e1687095ea6785Simon Wilson char *name; 57cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int size; 58cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int length; 59cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct mixer_setting *setting; 60cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}; 61cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 62cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstruct audio_route { 63cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct mixer *mixer; 64cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int num_mixer_ctls; 65cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct mixer_state *mixer_state; 66cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 67cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int mixer_path_size; 68cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int num_mixer_paths; 69cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct mixer_path *mixer_path; 70cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}; 71cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 72cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstruct config_parse_state { 73cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct audio_route *ar; 74cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct mixer_path *path; 75cef935958069ffba745cd091e6e1687095ea6785Simon Wilson int level; 76cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}; 77cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 78cef935958069ffba745cd091e6e1687095ea6785Simon Wilson/* path functions */ 79cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 80f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilsonstatic inline struct mixer_ctl *index_to_ctl(struct audio_route *ar, 81f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson unsigned int ctl_index) 82f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson{ 83f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson return ar->mixer_state[ctl_index].ctl; 84f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson} 85f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson 86f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilsonstatic void path_print(struct audio_route *ar, struct mixer_path *path) 87cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 88cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int i; 89cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int j; 90cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 91cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ALOGE("Path: %s, length: %d", path->name, path->length); 92cef935958069ffba745cd091e6e1687095ea6785Simon Wilson for (i = 0; i < path->length; i++) { 93f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson struct mixer_ctl *ctl = index_to_ctl(ar, path->setting[i].ctl_index); 94f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson 9563b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda ALOGE(" id=%d: ctl=%s", i, mixer_ctl_get_name(ctl)); 96cef935958069ffba745cd091e6e1687095ea6785Simon Wilson for (j = 0; j < path->setting[i].num_values; j++) 97cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ALOGE(" id=%d value=%d", j, path->setting[i].value[j]); 98cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 99cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 100cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 101cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic void path_free(struct audio_route *ar) 102cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 103cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int i; 104cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 105cef935958069ffba745cd091e6e1687095ea6785Simon Wilson for (i = 0; i < ar->num_mixer_paths; i++) { 106cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (ar->mixer_path[i].name) 107cef935958069ffba745cd091e6e1687095ea6785Simon Wilson free(ar->mixer_path[i].name); 108cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (ar->mixer_path[i].setting) { 109cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (ar->mixer_path[i].setting->value) 110cef935958069ffba745cd091e6e1687095ea6785Simon Wilson free(ar->mixer_path[i].setting->value); 111cef935958069ffba745cd091e6e1687095ea6785Simon Wilson free(ar->mixer_path[i].setting); 112cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 113cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 114cef935958069ffba745cd091e6e1687095ea6785Simon Wilson free(ar->mixer_path); 115cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 116cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 117cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic struct mixer_path *path_get_by_name(struct audio_route *ar, 118cef935958069ffba745cd091e6e1687095ea6785Simon Wilson const char *name) 119cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 120cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int i; 121cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 122cef935958069ffba745cd091e6e1687095ea6785Simon Wilson for (i = 0; i < ar->num_mixer_paths; i++) 123cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (strcmp(ar->mixer_path[i].name, name) == 0) 124cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return &ar->mixer_path[i]; 125cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 126cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return NULL; 127cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 128cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 129cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic struct mixer_path *path_create(struct audio_route *ar, const char *name) 130cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 131cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct mixer_path *new_mixer_path = NULL; 132cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 133cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (path_get_by_name(ar, name)) { 134cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ALOGE("Path name '%s' already exists", name); 135cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return NULL; 136cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 137cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 138cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* check if we need to allocate more space for mixer paths */ 139cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (ar->mixer_path_size <= ar->num_mixer_paths) { 140cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (ar->mixer_path_size == 0) 141cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer_path_size = INITIAL_MIXER_PATH_SIZE; 142cef935958069ffba745cd091e6e1687095ea6785Simon Wilson else 143cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer_path_size *= 2; 144cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 145cef935958069ffba745cd091e6e1687095ea6785Simon Wilson new_mixer_path = realloc(ar->mixer_path, ar->mixer_path_size * 146cef935958069ffba745cd091e6e1687095ea6785Simon Wilson sizeof(struct mixer_path)); 147cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (new_mixer_path == NULL) { 148cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ALOGE("Unable to allocate more paths"); 149cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return NULL; 150cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } else { 151cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer_path = new_mixer_path; 152cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 153cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 154cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 155cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* initialise the new mixer path */ 156cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer_path[ar->num_mixer_paths].name = strdup(name); 157cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer_path[ar->num_mixer_paths].size = 0; 158cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer_path[ar->num_mixer_paths].length = 0; 159cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer_path[ar->num_mixer_paths].setting = NULL; 160cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 161cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* return the mixer path just added, then increment number of them */ 162cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return &ar->mixer_path[ar->num_mixer_paths++]; 163cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 164cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 165f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilsonstatic int find_ctl_index_in_path(struct mixer_path *path, 166f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson unsigned int ctl_index) 167cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 168cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int i; 169cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 170cef935958069ffba745cd091e6e1687095ea6785Simon Wilson for (i = 0; i < path->length; i++) 171f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson if (path->setting[i].ctl_index == ctl_index) 172cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return i; 173cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 174cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return -1; 175cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 176cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 177cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic int alloc_path_setting(struct mixer_path *path) 178cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 179cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct mixer_setting *new_path_setting; 180cef935958069ffba745cd091e6e1687095ea6785Simon Wilson int path_index; 181cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 182cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* check if we need to allocate more space for path settings */ 183cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (path->size <= path->length) { 184cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (path->size == 0) 185cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path->size = INITIAL_MIXER_PATH_SIZE; 186cef935958069ffba745cd091e6e1687095ea6785Simon Wilson else 187cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path->size *= 2; 188cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 189cef935958069ffba745cd091e6e1687095ea6785Simon Wilson new_path_setting = realloc(path->setting, 190cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path->size * sizeof(struct mixer_setting)); 191cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (new_path_setting == NULL) { 192cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ALOGE("Unable to allocate more path settings"); 193cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return -1; 194cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } else { 195cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path->setting = new_path_setting; 196cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 197cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 198cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 199cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path_index = path->length; 200cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path->length++; 201cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 202cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return path_index; 203cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 204cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 205f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilsonstatic int path_add_setting(struct audio_route *ar, struct mixer_path *path, 206cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct mixer_setting *setting) 207cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 208cef935958069ffba745cd091e6e1687095ea6785Simon Wilson int path_index; 209cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 210f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson if (find_ctl_index_in_path(path, setting->ctl_index) != -1) { 211f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson struct mixer_ctl *ctl = index_to_ctl(ar, setting->ctl_index); 212f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson 213cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ALOGE("Control '%s' already exists in path '%s'", 214f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson mixer_ctl_get_name(ctl), path->name); 215cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return -1; 216cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 217cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 218cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path_index = alloc_path_setting(path); 219cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (path_index < 0) 220cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return -1; 221cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 222f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson path->setting[path_index].ctl_index = setting->ctl_index; 223cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path->setting[path_index].num_values = setting->num_values; 224cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path->setting[path_index].value = malloc(setting->num_values * sizeof(int)); 22563b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda /* copy all values */ 22663b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda memcpy(path->setting[path_index].value, setting->value, 22763b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda setting->num_values * sizeof(int)); 228cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 229cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return 0; 230cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 231cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 232f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilsonstatic int path_add_value(struct audio_route *ar, struct mixer_path *path, 233cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct mixer_value *mixer_value) 234cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 235cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int i; 236cef935958069ffba745cd091e6e1687095ea6785Simon Wilson int path_index; 237cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int num_values; 238f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson struct mixer_ctl *ctl; 239cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 240cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* Check that mixer value index is within range */ 241f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson ctl = index_to_ctl(ar, mixer_value->ctl_index); 242f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson num_values = mixer_ctl_get_num_values(ctl); 243cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (mixer_value->index >= (int)num_values) { 244cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ALOGE("mixer index %d is out of range for '%s'", mixer_value->index, 245f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson mixer_ctl_get_name(ctl)); 246cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return -1; 247cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 248cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 249f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson path_index = find_ctl_index_in_path(path, mixer_value->ctl_index); 250cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (path_index < 0) { 251cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* New path */ 252cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 253cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path_index = alloc_path_setting(path); 254cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (path_index < 0) 255cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return -1; 256cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 257cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* initialise the new path setting */ 258f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson path->setting[path_index].ctl_index = mixer_value->ctl_index; 259cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path->setting[path_index].num_values = num_values; 260cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path->setting[path_index].value = malloc(num_values * sizeof(int)); 261cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path->setting[path_index].value[0] = mixer_value->value; 262cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 263cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 264cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (mixer_value->index == -1) { 26563b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda /* set all values the same */ 26663b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda for (i = 0; i < num_values; i++) 26763b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda path->setting[path_index].value[i] = mixer_value->value; 268cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } else { 26963b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda /* set only one value */ 270cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path->setting[path_index].value[mixer_value->index] = mixer_value->value; 271cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 272cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 273cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return 0; 274cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 275cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 276f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilsonstatic int path_add_path(struct audio_route *ar, struct mixer_path *path, 277f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson struct mixer_path *sub_path) 278cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 279cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int i; 280cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 281cef935958069ffba745cd091e6e1687095ea6785Simon Wilson for (i = 0; i < sub_path->length; i++) 282f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson if (path_add_setting(ar, path, &sub_path->setting[i]) < 0) 283cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return -1; 284cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 285cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return 0; 286cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 287cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 288cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic int path_apply(struct audio_route *ar, struct mixer_path *path) 289cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 290cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int i; 291cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int ctl_index; 292cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 293cef935958069ffba745cd091e6e1687095ea6785Simon Wilson for (i = 0; i < path->length; i++) { 294f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson ctl_index = path->setting[i].ctl_index; 295cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 296cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* apply the new value(s) */ 29763b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda memcpy(ar->mixer_state[ctl_index].new_value, path->setting[i].value, 29863b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda path->setting[i].num_values * sizeof(int)); 299cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 300cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 301cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return 0; 302cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 303cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 30472c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamandastatic int path_reset(struct audio_route *ar, struct mixer_path *path) 30572c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda{ 30672c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda unsigned int i; 30772c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda unsigned int j; 30872c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda unsigned int ctl_index; 30972c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda 31072c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda for (i = 0; i < path->length; i++) { 311f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson ctl_index = path->setting[i].ctl_index; 31272c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda 31372c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda /* reset the value(s) */ 31463b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda memcpy(ar->mixer_state[ctl_index].new_value, 31563b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda ar->mixer_state[ctl_index].reset_value, 31663b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda ar->mixer_state[ctl_index].num_values * sizeof(int)); 31772c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda } 31872c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda 31972c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda return 0; 32072c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda} 32172c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda 322cef935958069ffba745cd091e6e1687095ea6785Simon Wilson/* mixer helper function */ 323cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string) 324cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 325cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int i; 326cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 327cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* Search the enum strings for a particular one */ 328cef935958069ffba745cd091e6e1687095ea6785Simon Wilson for (i = 0; i < mixer_ctl_get_num_enums(ctl); i++) { 329cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0) 330cef935958069ffba745cd091e6e1687095ea6785Simon Wilson break; 331cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 332cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 333cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return i; 334cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 335cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 336cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic void start_tag(void *data, const XML_Char *tag_name, 337cef935958069ffba745cd091e6e1687095ea6785Simon Wilson const XML_Char **attr) 338cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 339cef935958069ffba745cd091e6e1687095ea6785Simon Wilson const XML_Char *attr_name = NULL; 340cef935958069ffba745cd091e6e1687095ea6785Simon Wilson const XML_Char *attr_id = NULL; 341cef935958069ffba745cd091e6e1687095ea6785Simon Wilson const XML_Char *attr_value = NULL; 342cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct config_parse_state *state = data; 343cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct audio_route *ar = state->ar; 344cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int i; 345cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int ctl_index; 346cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct mixer_ctl *ctl; 347cef935958069ffba745cd091e6e1687095ea6785Simon Wilson int value; 348cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int id; 349cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct mixer_value mixer_value; 350cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 351cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* Get name, id and value attributes (these may be empty) */ 352cef935958069ffba745cd091e6e1687095ea6785Simon Wilson for (i = 0; attr[i]; i += 2) { 353cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (strcmp(attr[i], "name") == 0) 354cef935958069ffba745cd091e6e1687095ea6785Simon Wilson attr_name = attr[i + 1]; 355cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (strcmp(attr[i], "id") == 0) 356cef935958069ffba745cd091e6e1687095ea6785Simon Wilson attr_id = attr[i + 1]; 357cef935958069ffba745cd091e6e1687095ea6785Simon Wilson else if (strcmp(attr[i], "value") == 0) 358cef935958069ffba745cd091e6e1687095ea6785Simon Wilson attr_value = attr[i + 1]; 359cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 360cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 361cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* Look at tags */ 362cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (strcmp(tag_name, "path") == 0) { 363cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (attr_name == NULL) { 364cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ALOGE("Unnamed path!"); 365cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } else { 366cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (state->level == 1) { 367cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* top level path: create and stash the path */ 368cef935958069ffba745cd091e6e1687095ea6785Simon Wilson state->path = path_create(ar, (char *)attr_name); 369cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } else { 370cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* nested path */ 371cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct mixer_path *sub_path = path_get_by_name(ar, attr_name); 372f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson path_add_path(ar, state->path, sub_path); 373cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 374cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 375cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 376cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 377cef935958069ffba745cd091e6e1687095ea6785Simon Wilson else if (strcmp(tag_name, "ctl") == 0) { 378cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* Obtain the mixer ctl and value */ 379cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ctl = mixer_get_ctl_by_name(ar->mixer, attr_name); 380d35bd63c74452b83eef34cff4f0831493d0781faSimon Wilson if (ctl == NULL) { 381d35bd63c74452b83eef34cff4f0831493d0781faSimon Wilson ALOGE("Control '%s' doesn't exist - skipping", attr_name); 382d35bd63c74452b83eef34cff4f0831493d0781faSimon Wilson goto done; 383d35bd63c74452b83eef34cff4f0831493d0781faSimon Wilson } 384d35bd63c74452b83eef34cff4f0831493d0781faSimon Wilson 385cef935958069ffba745cd091e6e1687095ea6785Simon Wilson switch (mixer_ctl_get_type(ctl)) { 386cef935958069ffba745cd091e6e1687095ea6785Simon Wilson case MIXER_CTL_TYPE_BOOL: 387cef935958069ffba745cd091e6e1687095ea6785Simon Wilson case MIXER_CTL_TYPE_INT: 388cef935958069ffba745cd091e6e1687095ea6785Simon Wilson value = atoi((char *)attr_value); 389cef935958069ffba745cd091e6e1687095ea6785Simon Wilson break; 390cef935958069ffba745cd091e6e1687095ea6785Simon Wilson case MIXER_CTL_TYPE_ENUM: 391cef935958069ffba745cd091e6e1687095ea6785Simon Wilson value = mixer_enum_string_to_value(ctl, (char *)attr_value); 392cef935958069ffba745cd091e6e1687095ea6785Simon Wilson break; 393cef935958069ffba745cd091e6e1687095ea6785Simon Wilson default: 394cef935958069ffba745cd091e6e1687095ea6785Simon Wilson value = 0; 395cef935958069ffba745cd091e6e1687095ea6785Simon Wilson break; 396cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 397cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 398f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson /* locate the mixer ctl in the list */ 399f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) { 400f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson if (ar->mixer_state[ctl_index].ctl == ctl) 401f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson break; 402f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson } 403f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson 404cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (state->level == 1) { 405cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* top level ctl (initial setting) */ 406cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 407cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* apply the new value */ 408cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (attr_id) { 409cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* set only one value */ 410cef935958069ffba745cd091e6e1687095ea6785Simon Wilson id = atoi((char *)attr_id); 41163b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda if (id < ar->mixer_state[ctl_index].num_values) 412cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer_state[ctl_index].new_value[id] = value; 41363b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda else 414cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ALOGE("value id out of range for mixer ctl '%s'", 415cef935958069ffba745cd091e6e1687095ea6785Simon Wilson mixer_ctl_get_name(ctl)); 416cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } else { 41763b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda /* set all values the same */ 41863b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++) 41963b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda ar->mixer_state[ctl_index].new_value[i] = value; 420cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 421cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } else { 422cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* nested ctl (within a path) */ 423f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson mixer_value.ctl_index = ctl_index; 424cef935958069ffba745cd091e6e1687095ea6785Simon Wilson mixer_value.value = value; 425cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (attr_id) 426cef935958069ffba745cd091e6e1687095ea6785Simon Wilson mixer_value.index = atoi((char *)attr_id); 427cef935958069ffba745cd091e6e1687095ea6785Simon Wilson else 428cef935958069ffba745cd091e6e1687095ea6785Simon Wilson mixer_value.index = -1; 429f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson path_add_value(ar, state->path, &mixer_value); 430cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 431cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 432cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 433d35bd63c74452b83eef34cff4f0831493d0781faSimon Wilsondone: 434cef935958069ffba745cd091e6e1687095ea6785Simon Wilson state->level++; 435cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 436cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 437cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic void end_tag(void *data, const XML_Char *tag_name) 438cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 439cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct config_parse_state *state = data; 440cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 441cef935958069ffba745cd091e6e1687095ea6785Simon Wilson state->level--; 442cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 443cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 444cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic int alloc_mixer_state(struct audio_route *ar) 445cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 446cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int i; 447cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int j; 448cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int num_values; 449cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct mixer_ctl *ctl; 45063b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda enum mixer_ctl_type type; 451cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 452cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer); 453cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer_state = malloc(ar->num_mixer_ctls * sizeof(struct mixer_state)); 454cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (!ar->mixer_state) 455cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return -1; 456cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 457cef935958069ffba745cd091e6e1687095ea6785Simon Wilson for (i = 0; i < ar->num_mixer_ctls; i++) { 458cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ctl = mixer_get_ctl(ar->mixer, i); 459cef935958069ffba745cd091e6e1687095ea6785Simon Wilson num_values = mixer_ctl_get_num_values(ctl); 460cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 46163b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda ar->mixer_state[i].ctl = ctl; 46263b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda ar->mixer_state[i].num_values = num_values; 46363b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda 46463b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda /* Skip unsupported types that are not supported yet in XML */ 46563b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda type = mixer_ctl_get_type(ctl); 46663b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda if ((type != MIXER_CTL_TYPE_BOOL) && (type != MIXER_CTL_TYPE_INT) && 46763b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda (type != MIXER_CTL_TYPE_ENUM)) 46863b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda continue; 46963b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda 470cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer_state[i].old_value = malloc(num_values * sizeof(int)); 471cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer_state[i].new_value = malloc(num_values * sizeof(int)); 472cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer_state[i].reset_value = malloc(num_values * sizeof(int)); 473cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 47463b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda if (type == MIXER_CTL_TYPE_ENUM) 47563b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda ar->mixer_state[i].old_value[0] = mixer_ctl_get_value(ctl, 0); 47663b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda else 47763b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda mixer_ctl_get_array(ctl, ar->mixer_state[i].old_value, num_values); 47863b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda memcpy(ar->mixer_state[i].new_value, ar->mixer_state[i].old_value, 47963b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda num_values * sizeof(int)); 480cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 481cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 482cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return 0; 483cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 484cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 485cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic void free_mixer_state(struct audio_route *ar) 486cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 487cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int i; 488cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 489cef935958069ffba745cd091e6e1687095ea6785Simon Wilson for (i = 0; i < ar->num_mixer_ctls; i++) { 490cef935958069ffba745cd091e6e1687095ea6785Simon Wilson free(ar->mixer_state[i].old_value); 491cef935958069ffba745cd091e6e1687095ea6785Simon Wilson free(ar->mixer_state[i].new_value); 492cef935958069ffba745cd091e6e1687095ea6785Simon Wilson free(ar->mixer_state[i].reset_value); 493cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 494cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 495cef935958069ffba745cd091e6e1687095ea6785Simon Wilson free(ar->mixer_state); 496cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer_state = NULL; 497cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 498cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 499cef935958069ffba745cd091e6e1687095ea6785Simon Wilson/* Update the mixer with any changed values */ 500cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonint audio_route_update_mixer(struct audio_route *ar) 501cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 502cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int i; 503cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int j; 50463b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda struct mixer_ctl *ctl; 505cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 506cef935958069ffba745cd091e6e1687095ea6785Simon Wilson for (i = 0; i < ar->num_mixer_ctls; i++) { 507cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int num_values = ar->mixer_state[i].num_values; 50863b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda enum mixer_ctl_type type; 50963b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda 51063b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda ctl = ar->mixer_state[i].ctl; 51163b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda 51263b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda /* Skip unsupported types */ 51363b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda type = mixer_ctl_get_type(ctl); 51463b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda if ((type != MIXER_CTL_TYPE_BOOL) && (type != MIXER_CTL_TYPE_INT) && 51563b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda (type != MIXER_CTL_TYPE_ENUM)) 51663b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda continue; 517cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 518cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* if the value has changed, update the mixer */ 51963b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda bool changed = false; 52063b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda for (j = 0; j < num_values; j++) { 52163b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda if (ar->mixer_state[i].old_value[j] != ar->mixer_state[i].new_value[j]) { 52263b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda changed = true; 52363b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda break; 524cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 525cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 52663b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda if (changed) { 52763b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda if (type == MIXER_CTL_TYPE_ENUM) 52863b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda mixer_ctl_set_value(ctl, 0, ar->mixer_state[i].new_value[0]); 52963b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda else 53063b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda mixer_ctl_set_array(ctl, ar->mixer_state[i].new_value, num_values); 53163b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda memcpy(ar->mixer_state[i].old_value, ar->mixer_state[i].new_value, 53263b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda num_values * sizeof(int)); 53363b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda } 534cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 535cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 536cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return 0; 537cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 538cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 539cef935958069ffba745cd091e6e1687095ea6785Simon Wilson/* saves the current state of the mixer, for resetting all controls */ 540cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic void save_mixer_state(struct audio_route *ar) 541cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 542cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int i; 543cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 544cef935958069ffba745cd091e6e1687095ea6785Simon Wilson for (i = 0; i < ar->num_mixer_ctls; i++) { 54563b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda memcpy(ar->mixer_state[i].reset_value, ar->mixer_state[i].new_value, 54663b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda ar->mixer_state[i].num_values * sizeof(int)); 547cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 548cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 549cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 550cef935958069ffba745cd091e6e1687095ea6785Simon Wilson/* Reset the audio routes back to the initial state */ 551cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonvoid audio_route_reset(struct audio_route *ar) 552cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 553cef935958069ffba745cd091e6e1687095ea6785Simon Wilson unsigned int i; 554cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 555cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* load all of the saved values */ 556cef935958069ffba745cd091e6e1687095ea6785Simon Wilson for (i = 0; i < ar->num_mixer_ctls; i++) { 55763b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda memcpy(ar->mixer_state[i].new_value, ar->mixer_state[i].reset_value, 55863b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda ar->mixer_state[i].num_values * sizeof(int)); 559cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 560cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 561cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 562cef935958069ffba745cd091e6e1687095ea6785Simon Wilson/* Apply an audio route path by name */ 563cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonint audio_route_apply_path(struct audio_route *ar, const char *name) 564cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 565cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct mixer_path *path; 566cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 567cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (!ar) { 568cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ALOGE("invalid audio_route"); 569cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return -1; 570cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 571cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 572cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path = path_get_by_name(ar, name); 573cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (!path) { 574cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ALOGE("unable to find path '%s'", name); 575cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return -1; 576cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 577cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 578cef935958069ffba745cd091e6e1687095ea6785Simon Wilson path_apply(ar, path); 579cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 580cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return 0; 581cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 582cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 58372c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda/* Reset an audio route path by name */ 58472c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamandaint audio_route_reset_path(struct audio_route *ar, const char *name) 58572c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda{ 58672c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda struct mixer_path *path; 58772c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda 58872c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda if (!ar) { 58972c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda ALOGE("invalid audio_route"); 59072c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda return -1; 59172c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda } 59272c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda 59372c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda path = path_get_by_name(ar, name); 59472c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda if (!path) { 59572c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda ALOGE("unable to find path '%s'", name); 59672c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda return -1; 59772c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda } 59872c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda 59972c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda path_reset(ar, path); 60072c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda 60172c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda return 0; 60272c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda} 60372c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda 604cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstruct audio_route *audio_route_init(unsigned int card, const char *xml_path) 605cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 606cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct config_parse_state state; 607cef935958069ffba745cd091e6e1687095ea6785Simon Wilson XML_Parser parser; 608cef935958069ffba745cd091e6e1687095ea6785Simon Wilson FILE *file; 609cef935958069ffba745cd091e6e1687095ea6785Simon Wilson int bytes_read; 610cef935958069ffba745cd091e6e1687095ea6785Simon Wilson void *buf; 611cef935958069ffba745cd091e6e1687095ea6785Simon Wilson int i; 612cef935958069ffba745cd091e6e1687095ea6785Simon Wilson struct audio_route *ar; 613cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 614cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar = calloc(1, sizeof(struct audio_route)); 615cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (!ar) 616cef935958069ffba745cd091e6e1687095ea6785Simon Wilson goto err_calloc; 617cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 618cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer = mixer_open(card); 619cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (!ar->mixer) { 620cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ALOGE("Unable to open the mixer, aborting."); 621cef935958069ffba745cd091e6e1687095ea6785Simon Wilson goto err_mixer_open; 622cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 623cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 624cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer_path = NULL; 625cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->mixer_path_size = 0; 626cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar->num_mixer_paths = 0; 627cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 628cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* allocate space for and read current mixer settings */ 629cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (alloc_mixer_state(ar) < 0) 630cef935958069ffba745cd091e6e1687095ea6785Simon Wilson goto err_mixer_state; 631cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 632cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* use the default XML path if none is provided */ 633cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (xml_path == NULL) 634cef935958069ffba745cd091e6e1687095ea6785Simon Wilson xml_path = MIXER_XML_PATH; 635cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 636cef935958069ffba745cd091e6e1687095ea6785Simon Wilson file = fopen(xml_path, "r"); 637cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 638cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (!file) { 639cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ALOGE("Failed to open %s", xml_path); 640cef935958069ffba745cd091e6e1687095ea6785Simon Wilson goto err_fopen; 641cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 642cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 643cef935958069ffba745cd091e6e1687095ea6785Simon Wilson parser = XML_ParserCreate(NULL); 644cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (!parser) { 645cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ALOGE("Failed to create XML parser"); 646cef935958069ffba745cd091e6e1687095ea6785Simon Wilson goto err_parser_create; 647cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 648cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 649cef935958069ffba745cd091e6e1687095ea6785Simon Wilson memset(&state, 0, sizeof(state)); 650cef935958069ffba745cd091e6e1687095ea6785Simon Wilson state.ar = ar; 651cef935958069ffba745cd091e6e1687095ea6785Simon Wilson XML_SetUserData(parser, &state); 652cef935958069ffba745cd091e6e1687095ea6785Simon Wilson XML_SetElementHandler(parser, start_tag, end_tag); 653cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 654cef935958069ffba745cd091e6e1687095ea6785Simon Wilson for (;;) { 655cef935958069ffba745cd091e6e1687095ea6785Simon Wilson buf = XML_GetBuffer(parser, BUF_SIZE); 656cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (buf == NULL) 657cef935958069ffba745cd091e6e1687095ea6785Simon Wilson goto err_parse; 658cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 659cef935958069ffba745cd091e6e1687095ea6785Simon Wilson bytes_read = fread(buf, 1, BUF_SIZE, file); 660cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (bytes_read < 0) 661cef935958069ffba745cd091e6e1687095ea6785Simon Wilson goto err_parse; 662cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 663cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (XML_ParseBuffer(parser, bytes_read, 664cef935958069ffba745cd091e6e1687095ea6785Simon Wilson bytes_read == 0) == XML_STATUS_ERROR) { 665cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH); 666cef935958069ffba745cd091e6e1687095ea6785Simon Wilson goto err_parse; 667cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 668cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 669cef935958069ffba745cd091e6e1687095ea6785Simon Wilson if (bytes_read == 0) 670cef935958069ffba745cd091e6e1687095ea6785Simon Wilson break; 671cef935958069ffba745cd091e6e1687095ea6785Simon Wilson } 672cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 673cef935958069ffba745cd091e6e1687095ea6785Simon Wilson /* apply the initial mixer values, and save them so we can reset the 674cef935958069ffba745cd091e6e1687095ea6785Simon Wilson mixer to the original values */ 675cef935958069ffba745cd091e6e1687095ea6785Simon Wilson audio_route_update_mixer(ar); 676cef935958069ffba745cd091e6e1687095ea6785Simon Wilson save_mixer_state(ar); 677cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 678cef935958069ffba745cd091e6e1687095ea6785Simon Wilson XML_ParserFree(parser); 679cef935958069ffba745cd091e6e1687095ea6785Simon Wilson fclose(file); 680cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return ar; 681cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 682cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonerr_parse: 683cef935958069ffba745cd091e6e1687095ea6785Simon Wilson XML_ParserFree(parser); 684cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonerr_parser_create: 685cef935958069ffba745cd091e6e1687095ea6785Simon Wilson fclose(file); 686cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonerr_fopen: 687cef935958069ffba745cd091e6e1687095ea6785Simon Wilson free_mixer_state(ar); 688cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonerr_mixer_state: 689cef935958069ffba745cd091e6e1687095ea6785Simon Wilson mixer_close(ar->mixer); 690cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonerr_mixer_open: 691cef935958069ffba745cd091e6e1687095ea6785Simon Wilson free(ar); 692cef935958069ffba745cd091e6e1687095ea6785Simon Wilson ar = NULL; 693cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonerr_calloc: 694cef935958069ffba745cd091e6e1687095ea6785Simon Wilson return NULL; 695cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 696cef935958069ffba745cd091e6e1687095ea6785Simon Wilson 697cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonvoid audio_route_free(struct audio_route *ar) 698cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{ 699cef935958069ffba745cd091e6e1687095ea6785Simon Wilson free_mixer_state(ar); 700cef935958069ffba745cd091e6e1687095ea6785Simon Wilson mixer_close(ar->mixer); 701cef935958069ffba745cd091e6e1687095ea6785Simon Wilson free(ar); 702cef935958069ffba745cd091e6e1687095ea6785Simon Wilson} 703