1d5ac70f0Sopenharmony_ci/* 2d5ac70f0Sopenharmony_ci Copyright(c) 2014-2015 Intel Corporation 3d5ac70f0Sopenharmony_ci All rights reserved. 4d5ac70f0Sopenharmony_ci 5d5ac70f0Sopenharmony_ci This library is free software; you can redistribute it and/or modify 6d5ac70f0Sopenharmony_ci it under the terms of the GNU Lesser General Public License as 7d5ac70f0Sopenharmony_ci published by the Free Software Foundation; either version 2.1 of 8d5ac70f0Sopenharmony_ci the License, or (at your option) any later version. 9d5ac70f0Sopenharmony_ci 10d5ac70f0Sopenharmony_ci This program is distributed in the hope that it will be useful, 11d5ac70f0Sopenharmony_ci but WITHOUT ANY WARRANTY; without even the implied warranty of 12d5ac70f0Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13d5ac70f0Sopenharmony_ci GNU Lesser General Public License for more details. 14d5ac70f0Sopenharmony_ci 15d5ac70f0Sopenharmony_ci Authors: Mengdong Lin <mengdong.lin@intel.com> 16d5ac70f0Sopenharmony_ci Yao Jin <yao.jin@intel.com> 17d5ac70f0Sopenharmony_ci Liam Girdwood <liam.r.girdwood@linux.intel.com> 18d5ac70f0Sopenharmony_ci*/ 19d5ac70f0Sopenharmony_ci 20d5ac70f0Sopenharmony_ci#include "tplg_local.h" 21d5ac70f0Sopenharmony_ci 22d5ac70f0Sopenharmony_ci/* mapping of kcontrol text names to types */ 23d5ac70f0Sopenharmony_cistatic const struct map_elem control_map[] = { 24d5ac70f0Sopenharmony_ci {"volsw", SND_SOC_TPLG_CTL_VOLSW}, 25d5ac70f0Sopenharmony_ci {"volsw_sx", SND_SOC_TPLG_CTL_VOLSW_SX}, 26d5ac70f0Sopenharmony_ci {"volsw_xr_sx", SND_SOC_TPLG_CTL_VOLSW_XR_SX}, 27d5ac70f0Sopenharmony_ci {"enum", SND_SOC_TPLG_CTL_ENUM}, 28d5ac70f0Sopenharmony_ci {"bytes", SND_SOC_TPLG_CTL_BYTES}, 29d5ac70f0Sopenharmony_ci {"enum_value", SND_SOC_TPLG_CTL_ENUM_VALUE}, 30d5ac70f0Sopenharmony_ci {"range", SND_SOC_TPLG_CTL_RANGE}, 31d5ac70f0Sopenharmony_ci {"strobe", SND_SOC_TPLG_CTL_STROBE}, 32d5ac70f0Sopenharmony_ci}; 33d5ac70f0Sopenharmony_ci 34d5ac70f0Sopenharmony_cistatic int lookup_ops(const char *c) 35d5ac70f0Sopenharmony_ci{ 36d5ac70f0Sopenharmony_ci int i; 37d5ac70f0Sopenharmony_ci long ret; 38d5ac70f0Sopenharmony_ci 39d5ac70f0Sopenharmony_ci for (i = 0; i < (int)ARRAY_SIZE(control_map); i++) { 40d5ac70f0Sopenharmony_ci if (strcmp(control_map[i].name, c) == 0) 41d5ac70f0Sopenharmony_ci return control_map[i].id; 42d5ac70f0Sopenharmony_ci } 43d5ac70f0Sopenharmony_ci 44d5ac70f0Sopenharmony_ci /* cant find string name in our table so we use its ID number */ 45d5ac70f0Sopenharmony_ci i = safe_strtol(c, &ret); 46d5ac70f0Sopenharmony_ci if (i < 0) { 47d5ac70f0Sopenharmony_ci SNDERR("wrong kcontrol ops value string '%s'", c); 48d5ac70f0Sopenharmony_ci return i; 49d5ac70f0Sopenharmony_ci } 50d5ac70f0Sopenharmony_ci 51d5ac70f0Sopenharmony_ci return ret; 52d5ac70f0Sopenharmony_ci} 53d5ac70f0Sopenharmony_ci 54d5ac70f0Sopenharmony_ciconst char *tplg_ops_name(int type) 55d5ac70f0Sopenharmony_ci{ 56d5ac70f0Sopenharmony_ci unsigned int i; 57d5ac70f0Sopenharmony_ci 58d5ac70f0Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(control_map); i++) { 59d5ac70f0Sopenharmony_ci if (control_map[i].id == type) 60d5ac70f0Sopenharmony_ci return control_map[i].name; 61d5ac70f0Sopenharmony_ci } 62d5ac70f0Sopenharmony_ci 63d5ac70f0Sopenharmony_ci return NULL; 64d5ac70f0Sopenharmony_ci} 65d5ac70f0Sopenharmony_ci 66d5ac70f0Sopenharmony_ci/* Parse Control operations. Ops can come from standard names above or 67d5ac70f0Sopenharmony_ci * bespoke driver controls with numbers >= 256 68d5ac70f0Sopenharmony_ci */ 69d5ac70f0Sopenharmony_ciint tplg_parse_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, snd_config_t *cfg, 70d5ac70f0Sopenharmony_ci void *private) 71d5ac70f0Sopenharmony_ci{ 72d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 73d5ac70f0Sopenharmony_ci snd_config_t *n; 74d5ac70f0Sopenharmony_ci struct snd_soc_tplg_ctl_hdr *hdr = private; 75d5ac70f0Sopenharmony_ci const char *id, *value; 76d5ac70f0Sopenharmony_ci int ival; 77d5ac70f0Sopenharmony_ci 78d5ac70f0Sopenharmony_ci tplg_dbg("\tOps"); 79d5ac70f0Sopenharmony_ci hdr->size = sizeof(*hdr); 80d5ac70f0Sopenharmony_ci 81d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 82d5ac70f0Sopenharmony_ci 83d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 84d5ac70f0Sopenharmony_ci 85d5ac70f0Sopenharmony_ci /* get id */ 86d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 87d5ac70f0Sopenharmony_ci continue; 88d5ac70f0Sopenharmony_ci 89d5ac70f0Sopenharmony_ci /* get value - try strings then ints */ 90d5ac70f0Sopenharmony_ci if (snd_config_get_type(n) == SND_CONFIG_TYPE_STRING) { 91d5ac70f0Sopenharmony_ci if (snd_config_get_string(n, &value) < 0) 92d5ac70f0Sopenharmony_ci continue; 93d5ac70f0Sopenharmony_ci ival = lookup_ops(value); 94d5ac70f0Sopenharmony_ci } else { 95d5ac70f0Sopenharmony_ci if (tplg_get_integer(n, &ival, 0)) 96d5ac70f0Sopenharmony_ci continue; 97d5ac70f0Sopenharmony_ci } 98d5ac70f0Sopenharmony_ci 99d5ac70f0Sopenharmony_ci if (strcmp(id, "info") == 0) 100d5ac70f0Sopenharmony_ci hdr->ops.info = ival; 101d5ac70f0Sopenharmony_ci else if (strcmp(id, "put") == 0) 102d5ac70f0Sopenharmony_ci hdr->ops.put = ival; 103d5ac70f0Sopenharmony_ci else if (strcmp(id, "get") == 0) 104d5ac70f0Sopenharmony_ci hdr->ops.get = ival; 105d5ac70f0Sopenharmony_ci 106d5ac70f0Sopenharmony_ci tplg_dbg("\t\t%s = %d", id, ival); 107d5ac70f0Sopenharmony_ci } 108d5ac70f0Sopenharmony_ci 109d5ac70f0Sopenharmony_ci return 0; 110d5ac70f0Sopenharmony_ci} 111d5ac70f0Sopenharmony_ci 112d5ac70f0Sopenharmony_ci/* save control operations */ 113d5ac70f0Sopenharmony_ciint tplg_save_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, 114d5ac70f0Sopenharmony_ci struct snd_soc_tplg_ctl_hdr *hdr, 115d5ac70f0Sopenharmony_ci struct tplg_buf *dst, const char *pfx) 116d5ac70f0Sopenharmony_ci{ 117d5ac70f0Sopenharmony_ci const char *s; 118d5ac70f0Sopenharmony_ci int err; 119d5ac70f0Sopenharmony_ci 120d5ac70f0Sopenharmony_ci if (hdr->ops.info + hdr->ops.get + hdr->ops.put == 0) 121d5ac70f0Sopenharmony_ci return 0; 122d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "ops.0 {\n"); 123d5ac70f0Sopenharmony_ci if (err >= 0 && hdr->ops.info > 0) { 124d5ac70f0Sopenharmony_ci s = tplg_ops_name(hdr->ops.info); 125d5ac70f0Sopenharmony_ci if (s == NULL) 126d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\tinfo %u\n", 127d5ac70f0Sopenharmony_ci hdr->ops.info); 128d5ac70f0Sopenharmony_ci else 129d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\tinfo %s\n", s); 130d5ac70f0Sopenharmony_ci } 131d5ac70f0Sopenharmony_ci if (err >= 0 && hdr->ops.get > 0) { 132d5ac70f0Sopenharmony_ci s = tplg_ops_name(hdr->ops.get); 133d5ac70f0Sopenharmony_ci if (s == NULL) 134d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\tget %u\n", 135d5ac70f0Sopenharmony_ci hdr->ops.get); 136d5ac70f0Sopenharmony_ci else 137d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\tget %s\n", s); 138d5ac70f0Sopenharmony_ci } 139d5ac70f0Sopenharmony_ci if (err >= 0 && hdr->ops.put > 0) { 140d5ac70f0Sopenharmony_ci s = tplg_ops_name(hdr->ops.put); 141d5ac70f0Sopenharmony_ci if (s == NULL) 142d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\tput %u\n", 143d5ac70f0Sopenharmony_ci hdr->ops.put); 144d5ac70f0Sopenharmony_ci else 145d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\tput %s\n", s); 146d5ac70f0Sopenharmony_ci } 147d5ac70f0Sopenharmony_ci if (err >= 0) 148d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "}\n"); 149d5ac70f0Sopenharmony_ci return err; 150d5ac70f0Sopenharmony_ci} 151d5ac70f0Sopenharmony_ci 152d5ac70f0Sopenharmony_ci/* Parse External Control operations. Ops can come from standard names above or 153d5ac70f0Sopenharmony_ci * bespoke driver controls with numbers >= 256 154d5ac70f0Sopenharmony_ci */ 155d5ac70f0Sopenharmony_ciint tplg_parse_ext_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, 156d5ac70f0Sopenharmony_ci snd_config_t *cfg, void *private) 157d5ac70f0Sopenharmony_ci{ 158d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 159d5ac70f0Sopenharmony_ci snd_config_t *n; 160d5ac70f0Sopenharmony_ci struct snd_soc_tplg_bytes_control *be = private; 161d5ac70f0Sopenharmony_ci const char *id, *value; 162d5ac70f0Sopenharmony_ci int ival; 163d5ac70f0Sopenharmony_ci 164d5ac70f0Sopenharmony_ci tplg_dbg("\tExt Ops"); 165d5ac70f0Sopenharmony_ci 166d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 167d5ac70f0Sopenharmony_ci 168d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 169d5ac70f0Sopenharmony_ci 170d5ac70f0Sopenharmony_ci /* get id */ 171d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 172d5ac70f0Sopenharmony_ci continue; 173d5ac70f0Sopenharmony_ci 174d5ac70f0Sopenharmony_ci /* get value - try strings then ints */ 175d5ac70f0Sopenharmony_ci if (snd_config_get_type(n) == SND_CONFIG_TYPE_STRING) { 176d5ac70f0Sopenharmony_ci if (snd_config_get_string(n, &value) < 0) 177d5ac70f0Sopenharmony_ci continue; 178d5ac70f0Sopenharmony_ci ival = lookup_ops(value); 179d5ac70f0Sopenharmony_ci } else { 180d5ac70f0Sopenharmony_ci if (tplg_get_integer(n, &ival, 0)) 181d5ac70f0Sopenharmony_ci continue; 182d5ac70f0Sopenharmony_ci } 183d5ac70f0Sopenharmony_ci 184d5ac70f0Sopenharmony_ci if (strcmp(id, "info") == 0) 185d5ac70f0Sopenharmony_ci be->ext_ops.info = ival; 186d5ac70f0Sopenharmony_ci else if (strcmp(id, "put") == 0) 187d5ac70f0Sopenharmony_ci be->ext_ops.put = ival; 188d5ac70f0Sopenharmony_ci else if (strcmp(id, "get") == 0) 189d5ac70f0Sopenharmony_ci be->ext_ops.get = ival; 190d5ac70f0Sopenharmony_ci 191d5ac70f0Sopenharmony_ci tplg_dbg("\t\t%s = %s", id, value); 192d5ac70f0Sopenharmony_ci } 193d5ac70f0Sopenharmony_ci 194d5ac70f0Sopenharmony_ci return 0; 195d5ac70f0Sopenharmony_ci} 196d5ac70f0Sopenharmony_ci 197d5ac70f0Sopenharmony_ci/* save external control operations */ 198d5ac70f0Sopenharmony_ciint tplg_save_ext_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, 199d5ac70f0Sopenharmony_ci struct snd_soc_tplg_bytes_control *be, 200d5ac70f0Sopenharmony_ci struct tplg_buf *dst, const char *pfx) 201d5ac70f0Sopenharmony_ci{ 202d5ac70f0Sopenharmony_ci const char *s; 203d5ac70f0Sopenharmony_ci int err; 204d5ac70f0Sopenharmony_ci 205d5ac70f0Sopenharmony_ci if (be->ext_ops.info + be->ext_ops.get + be->ext_ops.put == 0) 206d5ac70f0Sopenharmony_ci return 0; 207d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "extops.0 {\n"); 208d5ac70f0Sopenharmony_ci if (err >= 0 && be->ext_ops.info > 0) { 209d5ac70f0Sopenharmony_ci s = tplg_ops_name(be->ext_ops.info); 210d5ac70f0Sopenharmony_ci if (s == NULL) 211d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\tinfo %u\n", 212d5ac70f0Sopenharmony_ci be->ext_ops.info); 213d5ac70f0Sopenharmony_ci else 214d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\tinfo %s\n", s); 215d5ac70f0Sopenharmony_ci } 216d5ac70f0Sopenharmony_ci if (err >= 0 && be->ext_ops.get > 0) { 217d5ac70f0Sopenharmony_ci s = tplg_ops_name(be->ext_ops.get); 218d5ac70f0Sopenharmony_ci if (s == NULL) 219d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\tget %u\n", 220d5ac70f0Sopenharmony_ci be->ext_ops.get); 221d5ac70f0Sopenharmony_ci else 222d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\tget %s\n", s); 223d5ac70f0Sopenharmony_ci } 224d5ac70f0Sopenharmony_ci if (err >= 0 && be->ext_ops.put > 0) { 225d5ac70f0Sopenharmony_ci s = tplg_ops_name(be->ext_ops.put); 226d5ac70f0Sopenharmony_ci if (s == NULL) 227d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\tput %u\n", 228d5ac70f0Sopenharmony_ci be->ext_ops.put); 229d5ac70f0Sopenharmony_ci else 230d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\tput %s\n", s); 231d5ac70f0Sopenharmony_ci } 232d5ac70f0Sopenharmony_ci if (err >= 0) 233d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "}\n"); 234d5ac70f0Sopenharmony_ci return err; 235d5ac70f0Sopenharmony_ci} 236