aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/soc-topology.c163
1 files changed, 87 insertions, 76 deletions
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 4dfdc656cce6..63e1a50f2161 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -486,21 +486,24 @@ static void remove_widget(struct snd_soc_component *comp,
486 dobj->ops->widget_unload(comp, dobj); 486 dobj->ops->widget_unload(comp, dobj);
487 487
488 /* 488 /*
489 * Dynamic Widgets either have 1 enum kcontrol or 1..N mixers. 489 * Dynamic Widgets either have 1..N enum kcontrols or mixers.
490 * The enum may either have an array of values or strings. 490 * The enum may either have an array of values or strings.
491 */ 491 */
492 if (dobj->widget.kcontrol_enum) { 492 if (dobj->widget.kcontrol_enum) {
493 /* enumerated widget mixer */ 493 /* enumerated widget mixer */
494 struct soc_enum *se = 494 for (i = 0; i < w->num_kcontrols; i++) {
495 (struct soc_enum *)w->kcontrols[0]->private_value; 495 struct snd_kcontrol *kcontrol = w->kcontrols[i];
496 struct soc_enum *se =
497 (struct soc_enum *)kcontrol->private_value;
496 498
497 snd_ctl_remove(card, w->kcontrols[0]); 499 snd_ctl_remove(card, kcontrol);
498 500
499 kfree(se->dobj.control.dvalues); 501 kfree(se->dobj.control.dvalues);
500 for (i = 0; i < se->items; i++) 502 for (i = 0; i < se->items; i++)
501 kfree(se->dobj.control.dtexts[i]); 503 kfree(se->dobj.control.dtexts[i]);
502 504
503 kfree(se); 505 kfree(se);
506 }
504 kfree(w->kcontrol_news); 507 kfree(w->kcontrol_news);
505 } else { 508 } else {
506 /* non enumerated widget mixer */ 509 /* non enumerated widget mixer */
@@ -1256,98 +1259,105 @@ err:
1256} 1259}
1257 1260
1258static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( 1261static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
1259 struct soc_tplg *tplg) 1262 struct soc_tplg *tplg, int num_kcontrols)
1260{ 1263{
1261 struct snd_kcontrol_new *kc; 1264 struct snd_kcontrol_new *kc;
1262 struct snd_soc_tplg_enum_control *ec; 1265 struct snd_soc_tplg_enum_control *ec;
1263 struct soc_enum *se; 1266 struct soc_enum *se;
1264 int i, err; 1267 int i, j, err;
1265
1266 ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
1267 tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
1268 ec->priv.size);
1269
1270 /* validate kcontrol */
1271 if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1272 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1273 return NULL;
1274 1268
1275 kc = kzalloc(sizeof(*kc), GFP_KERNEL); 1269 kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL);
1276 if (kc == NULL) 1270 if (kc == NULL)
1277 return NULL; 1271 return NULL;
1278 1272
1279 se = kzalloc(sizeof(*se), GFP_KERNEL); 1273 for (i = 0; i < num_kcontrols; i++) {
1280 if (se == NULL) 1274 ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
1281 goto err; 1275 /* validate kcontrol */
1276 if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1277 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1278 return NULL;
1279
1280 se = kzalloc(sizeof(*se), GFP_KERNEL);
1281 if (se == NULL)
1282 goto err;
1282 1283
1283 dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", 1284 dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n",
1284 ec->hdr.name); 1285 ec->hdr.name);
1285 1286
1286 kc->name = ec->hdr.name; 1287 kc[i].name = ec->hdr.name;
1287 kc->private_value = (long)se; 1288 kc[i].private_value = (long)se;
1288 kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; 1289 kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1289 kc->access = ec->hdr.access; 1290 kc[i].access = ec->hdr.access;
1290 1291
1291 /* we only support FL/FR channel mapping atm */ 1292 /* we only support FL/FR channel mapping atm */
1292 se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); 1293 se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
1293 se->shift_l = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL); 1294 se->shift_l = tplc_chan_get_shift(tplg, ec->channel,
1294 se->shift_r = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FR); 1295 SNDRV_CHMAP_FL);
1296 se->shift_r = tplc_chan_get_shift(tplg, ec->channel,
1297 SNDRV_CHMAP_FR);
1295 1298
1296 se->items = ec->items; 1299 se->items = ec->items;
1297 se->mask = ec->mask; 1300 se->mask = ec->mask;
1298 se->dobj.index = tplg->index; 1301 se->dobj.index = tplg->index;
1299 1302
1300 switch (ec->hdr.ops.info) { 1303 switch (ec->hdr.ops.info) {
1301 case SND_SOC_TPLG_CTL_ENUM_VALUE: 1304 case SND_SOC_TPLG_CTL_ENUM_VALUE:
1302 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: 1305 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1303 err = soc_tplg_denum_create_values(se, ec); 1306 err = soc_tplg_denum_create_values(se, ec);
1304 if (err < 0) { 1307 if (err < 0) {
1305 dev_err(tplg->dev, "ASoC: could not create values for %s\n", 1308 dev_err(tplg->dev, "ASoC: could not create values for %s\n",
1306 ec->hdr.name); 1309 ec->hdr.name);
1310 goto err_se;
1311 }
1312 /* fall through to create texts */
1313 case SND_SOC_TPLG_CTL_ENUM:
1314 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
1315 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1316 err = soc_tplg_denum_create_texts(se, ec);
1317 if (err < 0) {
1318 dev_err(tplg->dev, "ASoC: could not create texts for %s\n",
1319 ec->hdr.name);
1320 goto err_se;
1321 }
1322 break;
1323 default:
1324 dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n",
1325 ec->hdr.ops.info, ec->hdr.name);
1307 goto err_se; 1326 goto err_se;
1308 } 1327 }
1309 /* fall through to create texts */ 1328
1310 case SND_SOC_TPLG_CTL_ENUM: 1329 /* map io handlers */
1311 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: 1330 err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc[i], tplg);
1312 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: 1331 if (err) {
1313 err = soc_tplg_denum_create_texts(se, ec); 1332 soc_control_err(tplg, &ec->hdr, ec->hdr.name);
1333 goto err_se;
1334 }
1335
1336 /* pass control to driver for optional further init */
1337 err = soc_tplg_init_kcontrol(tplg, &kc[i],
1338 (struct snd_soc_tplg_ctl_hdr *)ec);
1314 if (err < 0) { 1339 if (err < 0) {
1315 dev_err(tplg->dev, "ASoC: could not create texts for %s\n", 1340 dev_err(tplg->dev, "ASoC: failed to init %s\n",
1316 ec->hdr.name); 1341 ec->hdr.name);
1317 goto err_se; 1342 goto err_se;
1318 } 1343 }
1319 break;
1320 default:
1321 dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n",
1322 ec->hdr.ops.info, ec->hdr.name);
1323 goto err_se;
1324 }
1325 1344
1326 /* map io handlers */ 1345 tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
1327 err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg); 1346 ec->priv.size);
1328 if (err) {
1329 soc_control_err(tplg, &ec->hdr, ec->hdr.name);
1330 goto err_se;
1331 }
1332
1333 /* pass control to driver for optional further init */
1334 err = soc_tplg_init_kcontrol(tplg, kc,
1335 (struct snd_soc_tplg_ctl_hdr *)ec);
1336 if (err < 0) {
1337 dev_err(tplg->dev, "ASoC: failed to init %s\n",
1338 ec->hdr.name);
1339 goto err_se;
1340 } 1347 }
1341 1348
1342 return kc; 1349 return kc;
1343 1350
1344err_se: 1351err_se:
1345 /* free values and texts */ 1352 for (; i >= 0; i--) {
1346 kfree(se->dobj.control.dvalues); 1353 /* free values and texts */
1347 for (i = 0; i < ec->items; i++) 1354 se = (struct soc_enum *)kc[i].private_value;
1348 kfree(se->dobj.control.dtexts[i]); 1355 kfree(se->dobj.control.dvalues);
1356 for (j = 0; j < ec->items; j++)
1357 kfree(se->dobj.control.dtexts[j]);
1349 1358
1350 kfree(se); 1359 kfree(se);
1360 }
1351err: 1361err:
1352 kfree(kc); 1362 kfree(kc);
1353 1363
@@ -1499,9 +1509,10 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
1499 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: 1509 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1500 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: 1510 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1501 template.dobj.widget.kcontrol_enum = 1; 1511 template.dobj.widget.kcontrol_enum = 1;
1502 template.num_kcontrols = 1; 1512 template.num_kcontrols = w->num_kcontrols;
1503 template.kcontrol_news = 1513 template.kcontrol_news =
1504 soc_tplg_dapm_widget_denum_create(tplg); 1514 soc_tplg_dapm_widget_denum_create(tplg,
1515 template.num_kcontrols);
1505 if (!template.kcontrol_news) { 1516 if (!template.kcontrol_news) {
1506 ret = -ENOMEM; 1517 ret = -ENOMEM;
1507 goto hdr_err; 1518 goto hdr_err;