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
80c4b226627b1e3f9bde1c6b08b338a25a3eddab05Eric Laurentstatic bool is_supported_ctl_type(enum mixer_ctl_type type)
81c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent{
82c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent    switch (type) {
83c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent    case MIXER_CTL_TYPE_BOOL:
84c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent    case MIXER_CTL_TYPE_INT:
85c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent    case MIXER_CTL_TYPE_ENUM:
86c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        return true;
87c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent    default:
88c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        return false;
89c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent    }
90c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent}
91c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent
92f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilsonstatic inline struct mixer_ctl *index_to_ctl(struct audio_route *ar,
93f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson                                             unsigned int ctl_index)
94f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson{
95f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson    return ar->mixer_state[ctl_index].ctl;
96f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson}
97f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson
98f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilsonstatic void path_print(struct audio_route *ar, struct mixer_path *path)
99cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
100cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int i;
101cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int j;
102cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
103cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    ALOGE("Path: %s, length: %d", path->name, path->length);
104cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    for (i = 0; i < path->length; i++) {
105f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson        struct mixer_ctl *ctl = index_to_ctl(ar, path->setting[i].ctl_index);
106f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson
10763b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        ALOGE("  id=%d: ctl=%s", i, mixer_ctl_get_name(ctl));
108cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        for (j = 0; j < path->setting[i].num_values; j++)
109cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            ALOGE("    id=%d value=%d", j, path->setting[i].value[j]);
110cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
111cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
112cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
113cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic void path_free(struct audio_route *ar)
114cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
115cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int i;
116cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
117cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    for (i = 0; i < ar->num_mixer_paths; i++) {
118cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (ar->mixer_path[i].name)
119cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            free(ar->mixer_path[i].name);
120cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (ar->mixer_path[i].setting) {
121cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            if (ar->mixer_path[i].setting->value)
122cef935958069ffba745cd091e6e1687095ea6785Simon Wilson                free(ar->mixer_path[i].setting->value);
123cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            free(ar->mixer_path[i].setting);
124cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        }
125cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
126cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    free(ar->mixer_path);
127cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
128cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
129cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic struct mixer_path *path_get_by_name(struct audio_route *ar,
130cef935958069ffba745cd091e6e1687095ea6785Simon Wilson                                           const char *name)
131cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
132cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int i;
133cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
134cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    for (i = 0; i < ar->num_mixer_paths; i++)
135cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (strcmp(ar->mixer_path[i].name, name) == 0)
136cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            return &ar->mixer_path[i];
137cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
138cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    return NULL;
139cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
140cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
141cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic struct mixer_path *path_create(struct audio_route *ar, const char *name)
142cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
143cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    struct mixer_path *new_mixer_path = NULL;
144cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
145cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (path_get_by_name(ar, name)) {
146cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        ALOGE("Path name '%s' already exists", name);
147cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        return NULL;
148cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
149cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
150cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    /* check if we need to allocate more space for mixer paths */
151cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (ar->mixer_path_size <= ar->num_mixer_paths) {
152cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (ar->mixer_path_size == 0)
153cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            ar->mixer_path_size = INITIAL_MIXER_PATH_SIZE;
154cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        else
155cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            ar->mixer_path_size *= 2;
156cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
157cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        new_mixer_path = realloc(ar->mixer_path, ar->mixer_path_size *
158cef935958069ffba745cd091e6e1687095ea6785Simon Wilson                                 sizeof(struct mixer_path));
159cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (new_mixer_path == NULL) {
160cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            ALOGE("Unable to allocate more paths");
161cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            return NULL;
162cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        } else {
163cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            ar->mixer_path = new_mixer_path;
164cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        }
165cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
166cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
167cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    /* initialise the new mixer path */
168cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    ar->mixer_path[ar->num_mixer_paths].name = strdup(name);
169cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    ar->mixer_path[ar->num_mixer_paths].size = 0;
170cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    ar->mixer_path[ar->num_mixer_paths].length = 0;
171cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    ar->mixer_path[ar->num_mixer_paths].setting = NULL;
172cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
173cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    /* return the mixer path just added, then increment number of them */
174cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    return &ar->mixer_path[ar->num_mixer_paths++];
175cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
176cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
177f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilsonstatic int find_ctl_index_in_path(struct mixer_path *path,
178f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson                                  unsigned int ctl_index)
179cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
180cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int i;
181cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
182cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    for (i = 0; i < path->length; i++)
183f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson        if (path->setting[i].ctl_index == ctl_index)
184cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            return i;
185cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
186cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    return -1;
187cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
188cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
189cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic int alloc_path_setting(struct mixer_path *path)
190cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
191cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    struct mixer_setting *new_path_setting;
192cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    int path_index;
193cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
194cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    /* check if we need to allocate more space for path settings */
195cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (path->size <= path->length) {
196cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (path->size == 0)
197cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            path->size = INITIAL_MIXER_PATH_SIZE;
198cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        else
199cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            path->size *= 2;
200cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
201cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        new_path_setting = realloc(path->setting,
202cef935958069ffba745cd091e6e1687095ea6785Simon Wilson                                   path->size * sizeof(struct mixer_setting));
203cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (new_path_setting == NULL) {
204cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            ALOGE("Unable to allocate more path settings");
205cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            return -1;
206cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        } else {
207cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            path->setting = new_path_setting;
208cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        }
209cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
210cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
211cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    path_index = path->length;
212cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    path->length++;
213cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
214cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    return path_index;
215cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
216cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
217f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilsonstatic int path_add_setting(struct audio_route *ar, struct mixer_path *path,
218cef935958069ffba745cd091e6e1687095ea6785Simon Wilson                            struct mixer_setting *setting)
219cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
220cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    int path_index;
221cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
222f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson    if (find_ctl_index_in_path(path, setting->ctl_index) != -1) {
223f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson        struct mixer_ctl *ctl = index_to_ctl(ar, setting->ctl_index);
224f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson
225cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        ALOGE("Control '%s' already exists in path '%s'",
226f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson              mixer_ctl_get_name(ctl), path->name);
227cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        return -1;
228cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
229cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
230cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    path_index = alloc_path_setting(path);
231cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (path_index < 0)
232cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        return -1;
233cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
234f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson    path->setting[path_index].ctl_index = setting->ctl_index;
235cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    path->setting[path_index].num_values = setting->num_values;
236cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    path->setting[path_index].value = malloc(setting->num_values * sizeof(int));
23763b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda    /* copy all values */
23863b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda    memcpy(path->setting[path_index].value, setting->value,
23963b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda           setting->num_values * sizeof(int));
240cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
241cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    return 0;
242cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
243cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
244f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilsonstatic int path_add_value(struct audio_route *ar, struct mixer_path *path,
245cef935958069ffba745cd091e6e1687095ea6785Simon Wilson                          struct mixer_value *mixer_value)
246cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
247cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int i;
248cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    int path_index;
249cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int num_values;
250f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson    struct mixer_ctl *ctl;
251cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
252cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    /* Check that mixer value index is within range */
253f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson    ctl = index_to_ctl(ar, mixer_value->ctl_index);
254f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson    num_values = mixer_ctl_get_num_values(ctl);
255cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (mixer_value->index >= (int)num_values) {
256cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        ALOGE("mixer index %d is out of range for '%s'", mixer_value->index,
257f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson              mixer_ctl_get_name(ctl));
258cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        return -1;
259cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
260cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
261f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson    path_index = find_ctl_index_in_path(path, mixer_value->ctl_index);
262cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (path_index < 0) {
263cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        /* New path */
264cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
265cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        path_index = alloc_path_setting(path);
266cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (path_index < 0)
267cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            return -1;
268cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
269cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        /* initialise the new path setting */
270f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson        path->setting[path_index].ctl_index = mixer_value->ctl_index;
271cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        path->setting[path_index].num_values = num_values;
272cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        path->setting[path_index].value = malloc(num_values * sizeof(int));
273cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        path->setting[path_index].value[0] = mixer_value->value;
274cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
275cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
276cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (mixer_value->index == -1) {
27763b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        /* set all values the same */
27863b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        for (i = 0; i < num_values; i++)
27963b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda            path->setting[path_index].value[i] = mixer_value->value;
280cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    } else {
28163b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        /* set only one value */
282cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        path->setting[path_index].value[mixer_value->index] = mixer_value->value;
283cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
284cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
285cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    return 0;
286cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
287cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
288f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilsonstatic int path_add_path(struct audio_route *ar, struct mixer_path *path,
289f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson                         struct mixer_path *sub_path)
290cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
291cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int i;
292cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
293cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    for (i = 0; i < sub_path->length; i++)
294f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson        if (path_add_setting(ar, path, &sub_path->setting[i]) < 0)
295cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            return -1;
296cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
297cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    return 0;
298cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
299cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
300cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic int path_apply(struct audio_route *ar, struct mixer_path *path)
301cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
302cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int i;
303cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int ctl_index;
304c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent    struct mixer_ctl *ctl;
305c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent    enum mixer_ctl_type type;
306cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
307cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    for (i = 0; i < path->length; i++) {
308f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson        ctl_index = path->setting[i].ctl_index;
309c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        ctl = index_to_ctl(ar, ctl_index);
310c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        type = mixer_ctl_get_type(ctl);
311c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        if (!is_supported_ctl_type(type))
312c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent            continue;
313cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
314cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        /* apply the new value(s) */
31563b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        memcpy(ar->mixer_state[ctl_index].new_value, path->setting[i].value,
31663b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda               path->setting[i].num_values * sizeof(int));
317cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
318cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
319cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    return 0;
320cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
321cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
32272c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamandastatic int path_reset(struct audio_route *ar, struct mixer_path *path)
32372c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda{
32472c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda    unsigned int i;
32572c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda    unsigned int j;
32672c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda    unsigned int ctl_index;
327c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent    struct mixer_ctl *ctl;
328c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent    enum mixer_ctl_type type;
32972c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda
33072c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda    for (i = 0; i < path->length; i++) {
331f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson        ctl_index = path->setting[i].ctl_index;
332c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        ctl = index_to_ctl(ar, ctl_index);
333c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        type = mixer_ctl_get_type(ctl);
334c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        if (!is_supported_ctl_type(type))
335c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent            continue;
33672c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda
33772c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda        /* reset the value(s) */
33863b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        memcpy(ar->mixer_state[ctl_index].new_value,
33963b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda               ar->mixer_state[ctl_index].reset_value,
34063b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda               ar->mixer_state[ctl_index].num_values * sizeof(int));
34172c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda    }
34272c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda
34372c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda    return 0;
34472c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda}
34572c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda
346cef935958069ffba745cd091e6e1687095ea6785Simon Wilson/* mixer helper function */
347cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string)
348cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
349cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int i;
350cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
351cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    /* Search the enum strings for a particular one */
352cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    for (i = 0; i < mixer_ctl_get_num_enums(ctl); i++) {
353cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0)
354cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            break;
355cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
356cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
357cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    return i;
358cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
359cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
360cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic void start_tag(void *data, const XML_Char *tag_name,
361cef935958069ffba745cd091e6e1687095ea6785Simon Wilson                      const XML_Char **attr)
362cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
363cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    const XML_Char *attr_name = NULL;
364cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    const XML_Char *attr_id = NULL;
365cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    const XML_Char *attr_value = NULL;
366cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    struct config_parse_state *state = data;
367cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    struct audio_route *ar = state->ar;
368cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int i;
369cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int ctl_index;
370cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    struct mixer_ctl *ctl;
371cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    int value;
372cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int id;
373cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    struct mixer_value mixer_value;
374c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent    enum mixer_ctl_type type;
375cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
376cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    /* Get name, id and value attributes (these may be empty) */
377cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    for (i = 0; attr[i]; i += 2) {
378cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (strcmp(attr[i], "name") == 0)
379cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            attr_name = attr[i + 1];
380cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (strcmp(attr[i], "id") == 0)
381cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            attr_id = attr[i + 1];
382cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        else if (strcmp(attr[i], "value") == 0)
383cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            attr_value = attr[i + 1];
384cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
385cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
386cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    /* Look at tags */
387cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (strcmp(tag_name, "path") == 0) {
388cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (attr_name == NULL) {
389cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            ALOGE("Unnamed path!");
390cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        } else {
391cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            if (state->level == 1) {
392cef935958069ffba745cd091e6e1687095ea6785Simon Wilson                /* top level path: create and stash the path */
393cef935958069ffba745cd091e6e1687095ea6785Simon Wilson                state->path = path_create(ar, (char *)attr_name);
394cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            } else {
395cef935958069ffba745cd091e6e1687095ea6785Simon Wilson                /* nested path */
396cef935958069ffba745cd091e6e1687095ea6785Simon Wilson                struct mixer_path *sub_path = path_get_by_name(ar, attr_name);
397f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson                path_add_path(ar, state->path, sub_path);
398cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            }
399cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        }
400cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
401cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
402cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    else if (strcmp(tag_name, "ctl") == 0) {
403cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        /* Obtain the mixer ctl and value */
404cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        ctl = mixer_get_ctl_by_name(ar->mixer, attr_name);
405d35bd63c74452b83eef34cff4f0831493d0781faSimon Wilson        if (ctl == NULL) {
406d35bd63c74452b83eef34cff4f0831493d0781faSimon Wilson            ALOGE("Control '%s' doesn't exist - skipping", attr_name);
407d35bd63c74452b83eef34cff4f0831493d0781faSimon Wilson            goto done;
408d35bd63c74452b83eef34cff4f0831493d0781faSimon Wilson        }
409d35bd63c74452b83eef34cff4f0831493d0781faSimon Wilson
410cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        switch (mixer_ctl_get_type(ctl)) {
411cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        case MIXER_CTL_TYPE_BOOL:
412cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        case MIXER_CTL_TYPE_INT:
41376824ba7db04ad3f2719d484b40a73b506aba587Johan Gustavsson            value = (int) strtol((char *)attr_value, NULL, 0);
414cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            break;
415cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        case MIXER_CTL_TYPE_ENUM:
416cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            value = mixer_enum_string_to_value(ctl, (char *)attr_value);
417cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            break;
418cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        default:
419cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            value = 0;
420cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            break;
421cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        }
422cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
423f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson        /* locate the mixer ctl in the list */
424f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson        for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) {
425f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson            if (ar->mixer_state[ctl_index].ctl == ctl)
426f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson                break;
427f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson        }
428f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson
429cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (state->level == 1) {
430cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            /* top level ctl (initial setting) */
431cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
432c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent            type = mixer_ctl_get_type(ctl);
433c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent            if (is_supported_ctl_type(type)) {
434c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent                /* apply the new value */
435c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent                if (attr_id) {
436c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent                    /* set only one value */
437c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent                    id = atoi((char *)attr_id);
438c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent                    if (id < ar->mixer_state[ctl_index].num_values)
439c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent                        ar->mixer_state[ctl_index].new_value[id] = value;
440c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent                    else
441c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent                        ALOGE("value id out of range for mixer ctl '%s'",
442c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent                              mixer_ctl_get_name(ctl));
443c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent                } else {
444c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent                    /* set all values the same */
445c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent                    for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++)
446c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent                        ar->mixer_state[ctl_index].new_value[i] = value;
447c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent                }
448cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            }
449cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        } else {
450cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            /* nested ctl (within a path) */
451f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson            mixer_value.ctl_index = ctl_index;
452cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            mixer_value.value = value;
453cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            if (attr_id)
454cef935958069ffba745cd091e6e1687095ea6785Simon Wilson                mixer_value.index = atoi((char *)attr_id);
455cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            else
456cef935958069ffba745cd091e6e1687095ea6785Simon Wilson                mixer_value.index = -1;
457f3090fa9ce87c45aecb95a2c98a5cfcc2d3ee99aSimon Wilson            path_add_value(ar, state->path, &mixer_value);
458cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        }
459cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
460cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
461d35bd63c74452b83eef34cff4f0831493d0781faSimon Wilsondone:
462cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    state->level++;
463cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
464cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
465cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic void end_tag(void *data, const XML_Char *tag_name)
466cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
467cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    struct config_parse_state *state = data;
468c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent    (void)tag_name;
469cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
470cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    state->level--;
471cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
472cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
473cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic int alloc_mixer_state(struct audio_route *ar)
474cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
475cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int i;
476cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int j;
477cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int num_values;
478cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    struct mixer_ctl *ctl;
47963b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda    enum mixer_ctl_type type;
480cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
481cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer);
482cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    ar->mixer_state = malloc(ar->num_mixer_ctls * sizeof(struct mixer_state));
483cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (!ar->mixer_state)
484cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        return -1;
485cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
486cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    for (i = 0; i < ar->num_mixer_ctls; i++) {
487cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        ctl = mixer_get_ctl(ar->mixer, i);
488cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        num_values = mixer_ctl_get_num_values(ctl);
489cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
49063b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        ar->mixer_state[i].ctl = ctl;
49163b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        ar->mixer_state[i].num_values = num_values;
49263b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda
49363b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        /* Skip unsupported types that are not supported yet in XML */
49463b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        type = mixer_ctl_get_type(ctl);
495c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent
496c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        if (!is_supported_ctl_type(type))
49763b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda            continue;
49863b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda
499cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        ar->mixer_state[i].old_value = malloc(num_values * sizeof(int));
500cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        ar->mixer_state[i].new_value = malloc(num_values * sizeof(int));
501cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        ar->mixer_state[i].reset_value = malloc(num_values * sizeof(int));
502cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
50363b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        if (type == MIXER_CTL_TYPE_ENUM)
50463b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda            ar->mixer_state[i].old_value[0] = mixer_ctl_get_value(ctl, 0);
50563b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        else
50663b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda            mixer_ctl_get_array(ctl, ar->mixer_state[i].old_value, num_values);
50763b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        memcpy(ar->mixer_state[i].new_value, ar->mixer_state[i].old_value,
50863b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda               num_values * sizeof(int));
509cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
510cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
511cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    return 0;
512cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
513cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
514cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic void free_mixer_state(struct audio_route *ar)
515cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
516cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int i;
517c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent    enum mixer_ctl_type type;
518cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
519cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    for (i = 0; i < ar->num_mixer_ctls; i++) {
520c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
521c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        if (!is_supported_ctl_type(type))
522c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent            continue;
523c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent
524cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        free(ar->mixer_state[i].old_value);
525cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        free(ar->mixer_state[i].new_value);
526cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        free(ar->mixer_state[i].reset_value);
527cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
528cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
529cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    free(ar->mixer_state);
530cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    ar->mixer_state = NULL;
531cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
532cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
533cef935958069ffba745cd091e6e1687095ea6785Simon Wilson/* Update the mixer with any changed values */
534cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonint audio_route_update_mixer(struct audio_route *ar)
535cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
536cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int i;
537cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int j;
53863b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda    struct mixer_ctl *ctl;
539cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
540cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    for (i = 0; i < ar->num_mixer_ctls; i++) {
541cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        unsigned int num_values = ar->mixer_state[i].num_values;
54263b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        enum mixer_ctl_type type;
54363b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda
54463b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        ctl = ar->mixer_state[i].ctl;
54563b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda
54663b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        /* Skip unsupported types */
54763b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        type = mixer_ctl_get_type(ctl);
548c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        if (!is_supported_ctl_type(type))
54963b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda            continue;
550cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
551cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        /* if the value has changed, update the mixer */
55263b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        bool changed = false;
55363b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        for (j = 0; j < num_values; j++) {
55463b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda            if (ar->mixer_state[i].old_value[j] != ar->mixer_state[i].new_value[j]) {
55563b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda                changed = true;
55663b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda                break;
557cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            }
558cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        }
55963b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        if (changed) {
56063b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda            if (type == MIXER_CTL_TYPE_ENUM)
56163b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda                mixer_ctl_set_value(ctl, 0, ar->mixer_state[i].new_value[0]);
56263b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda            else
56363b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda                mixer_ctl_set_array(ctl, ar->mixer_state[i].new_value, num_values);
56463b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda            memcpy(ar->mixer_state[i].old_value, ar->mixer_state[i].new_value,
56563b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda                   num_values * sizeof(int));
56663b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        }
567cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
568cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
569cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    return 0;
570cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
571cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
572cef935958069ffba745cd091e6e1687095ea6785Simon Wilson/* saves the current state of the mixer, for resetting all controls */
573cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstatic void save_mixer_state(struct audio_route *ar)
574cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
575cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int i;
576c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent    enum mixer_ctl_type type;
577cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
578cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    for (i = 0; i < ar->num_mixer_ctls; i++) {
579c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
580c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        if (!is_supported_ctl_type(type))
581c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent            continue;
582c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent
58363b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        memcpy(ar->mixer_state[i].reset_value, ar->mixer_state[i].new_value,
58463b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda               ar->mixer_state[i].num_values * sizeof(int));
585cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
586cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
587cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
588cef935958069ffba745cd091e6e1687095ea6785Simon Wilson/* Reset the audio routes back to the initial state */
589cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonvoid audio_route_reset(struct audio_route *ar)
590cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
591cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    unsigned int i;
592c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent    enum mixer_ctl_type type;
593cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
594cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    /* load all of the saved values */
595cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    for (i = 0; i < ar->num_mixer_ctls; i++) {
596c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
597c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent        if (!is_supported_ctl_type(type))
598c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent            continue;
599c5b5f6b344e3d8448e436835e5214364469614f6Eric Laurent
60063b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda        memcpy(ar->mixer_state[i].new_value, ar->mixer_state[i].reset_value,
60163b31c18b37409e1b024c50df94798aac9d0fa7dRavi Kumar Alamanda               ar->mixer_state[i].num_values * sizeof(int));
602cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
603cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
604cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
605cef935958069ffba745cd091e6e1687095ea6785Simon Wilson/* Apply an audio route path by name */
606cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonint audio_route_apply_path(struct audio_route *ar, const char *name)
607cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
608cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    struct mixer_path *path;
609cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
610cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (!ar) {
611cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        ALOGE("invalid audio_route");
612cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        return -1;
613cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
614cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
615cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    path = path_get_by_name(ar, name);
616cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (!path) {
617cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        ALOGE("unable to find path '%s'", name);
618cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        return -1;
619cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
620cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
621cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    path_apply(ar, path);
622cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
623cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    return 0;
624cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
625cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
62672c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda/* Reset an audio route path by name */
62772c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamandaint audio_route_reset_path(struct audio_route *ar, const char *name)
62872c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda{
62972c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda    struct mixer_path *path;
63072c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda
63172c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda    if (!ar) {
63272c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda        ALOGE("invalid audio_route");
63372c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda        return -1;
63472c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda    }
63572c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda
63672c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda    path = path_get_by_name(ar, name);
63772c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda    if (!path) {
63872c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda        ALOGE("unable to find path '%s'", name);
63972c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda        return -1;
64072c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda    }
64172c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda
64272c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda    path_reset(ar, path);
64372c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda
64472c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda    return 0;
64572c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda}
64672c277ef4859f7aa07ac43b3b9cc6754d6e3d505Ravi Kumar Alamanda
647a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George/*
648a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George * Operates on the specified path .. controls will be updated in the
649a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George * order listed in the XML file
650a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George */
651a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew Georgestatic int audio_route_update_path(struct audio_route *ar, const char *name, bool reverse)
652a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George{
653a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    struct mixer_path *path;
654a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    int32_t i, end;
655a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    unsigned int j;
656a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George
657a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    if (!ar) {
658a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        ALOGE("invalid audio_route");
659a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        return -1;
660a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    }
661a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George
662a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    path = path_get_by_name(ar, name);
663a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    if (!path) {
664a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        ALOGE("unable to find path '%s'", name);
665a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        return -1;
666a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    }
667a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George
668a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    i = reverse ? (path->length - 1) : 0;
669a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    end = reverse ? -1 : (int32_t)path->length;
670a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George
671a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    while (i != end) {
672a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        unsigned int ctl_index;
673a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        enum mixer_ctl_type type;
674a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George
675a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        ctl_index = path->setting[i].ctl_index;
676a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George
677a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        struct mixer_state * ms = &ar->mixer_state[ctl_index];
678a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George
679a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        type = mixer_ctl_get_type(ms->ctl);
680a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        if (!is_supported_ctl_type(type)) {
681a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George            continue;
682a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        }
683a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George
684a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        /* if any value has changed, update the mixer */
685a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        for (j = 0; j < ms->num_values; j++) {
686a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George            if (ms->old_value[j] != ms->new_value[j]) {
687a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George                if (type == MIXER_CTL_TYPE_ENUM)
688a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George                    mixer_ctl_set_value(ms->ctl, 0, ms->new_value[0]);
689a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George                else
690a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George                    mixer_ctl_set_array(ms->ctl, ms->new_value, ms->num_values);
691a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George                memcpy(ms->old_value, ms->new_value, ms->num_values * sizeof(int));
692a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George                break;
693a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George            }
694a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        }
695a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George
696a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        i = reverse ? (i - 1) : (i + 1);
697a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    }
698a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    return 0;
699a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George}
700a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George
701a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew Georgeint audio_route_apply_and_update_path(struct audio_route *ar, const char *name)
702a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George{
703a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    if (audio_route_apply_path(ar, name) < 0) {
704a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        return -1;
705a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    }
706a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    return audio_route_update_path(ar, name, false /*reverse*/);
707a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George}
708a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George
709a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew Georgeint audio_route_reset_and_update_path(struct audio_route *ar, const char *name)
710a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George{
711a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    if (audio_route_reset_path(ar, name) < 0) {
712a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George        return -1;
713a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    }
714a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George    return audio_route_update_path(ar, name, true /*reverse*/);
715a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George}
716a8070c02abafdfdd6a125710b1002c096ca3aa39Haynes Mathew George
717cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonstruct audio_route *audio_route_init(unsigned int card, const char *xml_path)
718cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
719cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    struct config_parse_state state;
720cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    XML_Parser parser;
721cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    FILE *file;
722cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    int bytes_read;
723cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    void *buf;
724cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    int i;
725cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    struct audio_route *ar;
726cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
727cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    ar = calloc(1, sizeof(struct audio_route));
728cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (!ar)
729cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        goto err_calloc;
730cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
731cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    ar->mixer = mixer_open(card);
732cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (!ar->mixer) {
733cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        ALOGE("Unable to open the mixer, aborting.");
734cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        goto err_mixer_open;
735cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
736cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
737cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    ar->mixer_path = NULL;
738cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    ar->mixer_path_size = 0;
739cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    ar->num_mixer_paths = 0;
740cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
741cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    /* allocate space for and read current mixer settings */
742cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (alloc_mixer_state(ar) < 0)
743cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        goto err_mixer_state;
744cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
745cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    /* use the default XML path if none is provided */
746cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (xml_path == NULL)
747cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        xml_path = MIXER_XML_PATH;
748cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
749cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    file = fopen(xml_path, "r");
750cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
751cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (!file) {
752cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        ALOGE("Failed to open %s", xml_path);
753cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        goto err_fopen;
754cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
755cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
756cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    parser = XML_ParserCreate(NULL);
757cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    if (!parser) {
758cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        ALOGE("Failed to create XML parser");
759cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        goto err_parser_create;
760cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
761cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
762cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    memset(&state, 0, sizeof(state));
763cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    state.ar = ar;
764cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    XML_SetUserData(parser, &state);
765cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    XML_SetElementHandler(parser, start_tag, end_tag);
766cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
767cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    for (;;) {
768cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        buf = XML_GetBuffer(parser, BUF_SIZE);
769cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (buf == NULL)
770cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            goto err_parse;
771cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
772cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        bytes_read = fread(buf, 1, BUF_SIZE, file);
773cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (bytes_read < 0)
774cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            goto err_parse;
775cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
776cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (XML_ParseBuffer(parser, bytes_read,
777cef935958069ffba745cd091e6e1687095ea6785Simon Wilson                            bytes_read == 0) == XML_STATUS_ERROR) {
778cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH);
779cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            goto err_parse;
780cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        }
781cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
782cef935958069ffba745cd091e6e1687095ea6785Simon Wilson        if (bytes_read == 0)
783cef935958069ffba745cd091e6e1687095ea6785Simon Wilson            break;
784cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    }
785cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
786cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    /* apply the initial mixer values, and save them so we can reset the
787cef935958069ffba745cd091e6e1687095ea6785Simon Wilson       mixer to the original values */
788cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    audio_route_update_mixer(ar);
789cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    save_mixer_state(ar);
790cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
791cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    XML_ParserFree(parser);
792cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    fclose(file);
793cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    return ar;
794cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
795cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonerr_parse:
796cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    XML_ParserFree(parser);
797cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonerr_parser_create:
798cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    fclose(file);
799cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonerr_fopen:
800cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    free_mixer_state(ar);
801cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonerr_mixer_state:
802cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    mixer_close(ar->mixer);
803cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonerr_mixer_open:
804cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    free(ar);
805cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    ar = NULL;
806cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonerr_calloc:
807cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    return NULL;
808cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
809cef935958069ffba745cd091e6e1687095ea6785Simon Wilson
810cef935958069ffba745cd091e6e1687095ea6785Simon Wilsonvoid audio_route_free(struct audio_route *ar)
811cef935958069ffba745cd091e6e1687095ea6785Simon Wilson{
812cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    free_mixer_state(ar);
813cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    mixer_close(ar->mixer);
814cef935958069ffba745cd091e6e1687095ea6785Simon Wilson    free(ar);
815cef935958069ffba745cd091e6e1687095ea6785Simon Wilson}
816