1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "audio_hw_acdb"
18 //#define LOG_NDEBUG 0
19 #define LOG_NDDEBUG 0
20
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
24 #include <dlfcn.h>
25 #include <log/log.h>
26 #include <cutils/str_parms.h>
27 #include <system/audio.h>
28 #include <tinyalsa/asoundlib.h>
29 #include "acdb.h"
30 #include <platform_api.h>
31
32 #define PLATFORM_CONFIG_KEY_SOUNDCARD_NAME "snd_card_name"
33
acdb_init(int snd_card_num)34 int acdb_init(int snd_card_num)
35 {
36
37 int result = -1;
38 char *cvd_version = NULL;
39
40 char *snd_card_name = NULL;
41 struct mixer *mixer = NULL;
42 struct acdb_platform_data *my_data = NULL;
43
44 if(snd_card_num < 0) {
45 ALOGE("invalid sound card number");
46 return result;
47 }
48
49 mixer = mixer_open(snd_card_num);
50 if (!mixer) {
51 ALOGE("%s: Unable to open the mixer card: %d", __func__,
52 snd_card_num);
53 goto cleanup;
54 }
55
56 my_data = calloc(1, sizeof(struct acdb_platform_data));
57 if (!my_data) {
58 ALOGE("failed to allocate acdb platform data");
59 goto cleanup;
60 }
61
62 list_init(&my_data->acdb_meta_key_list);
63
64 my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
65 if (my_data->acdb_handle == NULL) {
66 ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER);
67 goto cleanup;
68 }
69
70 ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER);
71
72 my_data->acdb_init_v3 = (acdb_init_v3_t)dlsym(my_data->acdb_handle,
73 "acdb_loader_init_v3");
74 if (my_data->acdb_init_v3 == NULL)
75 ALOGE("%s: dlsym error %s for acdb_loader_init_v3", __func__, dlerror());
76
77 my_data->acdb_init_v2 = (acdb_init_v2_cvd_t)dlsym(my_data->acdb_handle,
78 "acdb_loader_init_v2");
79 if (my_data->acdb_init_v2 == NULL)
80 ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__, dlerror());
81
82 my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
83 "acdb_loader_init_ACDB");
84 if (my_data->acdb_init == NULL && my_data->acdb_init_v2 == NULL
85 && my_data->acdb_init_v3 == NULL) {
86 ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__, dlerror());
87 goto cleanup;
88 }
89
90 /* Get CVD version */
91 cvd_version = calloc(1, MAX_CVD_VERSION_STRING_SIZE);
92 if (!cvd_version) {
93 ALOGE("%s: Failed to allocate cvd version", __func__);
94 goto cleanup;
95 } else {
96 struct mixer_ctl *ctl = NULL;
97 int count = 0;
98
99 ctl = mixer_get_ctl_by_name(mixer, CVD_VERSION_MIXER_CTL);
100 if (!ctl) {
101 ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__, CVD_VERSION_MIXER_CTL);
102 goto cleanup;
103 }
104 mixer_ctl_update(ctl);
105
106 count = mixer_ctl_get_num_values(ctl);
107 if (count > MAX_CVD_VERSION_STRING_SIZE)
108 count = MAX_CVD_VERSION_STRING_SIZE;
109
110 result = mixer_ctl_get_array(ctl, cvd_version, count);
111 if (result != 0) {
112 ALOGE("%s: ERROR! mixer_ctl_get_array() failed to get CVD Version", __func__);
113 goto cleanup;
114 }
115 }
116
117 /* Get Sound card name */
118 snd_card_name = strdup(mixer_get_name(mixer));
119 if (!snd_card_name) {
120 ALOGE("failed to allocate memory for snd_card_name");
121 result = -1;
122 goto cleanup;
123 }
124
125 if (my_data->acdb_init_v3)
126 result = my_data->acdb_init_v3(snd_card_name, cvd_version,
127 &my_data->acdb_meta_key_list);
128 else if (my_data->acdb_init_v2)
129 result = my_data->acdb_init_v2(snd_card_name, cvd_version, 0);
130 else
131 result = my_data->acdb_init();
132
133 cleanup:
134 if (NULL != my_data) {
135 if (my_data->acdb_handle)
136 dlclose(my_data->acdb_handle);
137
138 struct listnode *node;
139 struct meta_key_list *key_info;
140 list_for_each(node, &my_data->acdb_meta_key_list) {
141 key_info = node_to_item(node, struct meta_key_list, list);
142 free(key_info);
143 }
144 free(my_data);
145 }
146
147 mixer_close(mixer);
148 free(cvd_version);
149 free(snd_card_name);
150
151 return result;
152 }
153
acdb_set_parameters(void * platform,struct str_parms * parms)154 int acdb_set_parameters(void *platform, struct str_parms *parms)
155 {
156 struct acdb_platform_data *my_data = (struct acdb_platform_data *)platform;
157 char value[128];
158 char *kv_pairs = str_parms_to_str(parms);
159 int ret = 0;
160
161 if (kv_pairs == NULL) {
162 ret = -EINVAL;
163 ALOGE("%s: key-value pair is NULL",__func__);
164 goto done;
165 }
166
167 ret = str_parms_get_str(parms, PLATFORM_CONFIG_KEY_SOUNDCARD_NAME,
168 value, sizeof(value));
169 if (ret >= 0) {
170 str_parms_del(parms, PLATFORM_CONFIG_KEY_SOUNDCARD_NAME);
171 my_data->snd_card_name = strdup(value);
172 ALOGV("%s: sound card name %s", __func__, my_data->snd_card_name);
173 }
174
175 done:
176 free(kv_pairs);
177
178 return ret;
179 }
180