@@ -486,21 +486,24 @@ static void remove_widget(struct snd_soc_component *comp,
486
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
490
* The enum may either have an array of values or strings.
491
491
*/
492
492
if (dobj -> widget .kcontrol_enum ) {
493
493
/* enumerated widget mixer */
494
- struct soc_enum * se =
495
- (struct soc_enum * )w -> kcontrols [0 ]-> private_value ;
494
+ for (i = 0 ; i < w -> num_kcontrols ; i ++ ) {
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 );
500
- for (i = 0 ; i < se -> items ; i ++ )
501
- kfree (se -> dobj .control .dtexts [i ]);
501
+ kfree (se -> dobj .control .dvalues );
502
+ for (i = 0 ; i < se -> items ; i ++ )
503
+ kfree (se -> dobj .control .dtexts [i ]);
502
504
503
- kfree (se );
505
+ kfree (se );
506
+ }
504
507
kfree (w -> kcontrol_news );
505
508
} else {
506
509
/* non enumerated widget mixer */
@@ -1256,98 +1259,105 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
1256
1259
}
1257
1260
1258
1261
static 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
1264
struct snd_kcontrol_new * kc ;
1262
1265
struct snd_soc_tplg_enum_control * ec ;
1263
1266
struct soc_enum * se ;
1264
- int i , 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 ;
1267
+ int i , j , err ;
1274
1268
1275
- kc = kzalloc ( sizeof (* kc ), GFP_KERNEL );
1269
+ kc = kcalloc ( num_kcontrols , sizeof (* kc ), GFP_KERNEL );
1276
1270
if (kc == NULL )
1277
1271
return NULL ;
1278
1272
1279
- se = kzalloc (sizeof (* se ), GFP_KERNEL );
1280
- if (se == NULL )
1281
- goto err ;
1273
+ for (i = 0 ; i < num_kcontrols ; i ++ ) {
1274
+ ec = (struct snd_soc_tplg_enum_control * )tplg -> pos ;
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
- ec -> hdr .name );
1284
+ dev_dbg (tplg -> dev , " adding DAPM widget enum control %s\n" ,
1285
+ ec -> hdr .name );
1285
1286
1286
- kc -> name = ec -> hdr .name ;
1287
- kc -> private_value = (long )se ;
1288
- kc -> iface = SNDRV_CTL_ELEM_IFACE_MIXER ;
1289
- kc -> access = ec -> hdr .access ;
1287
+ kc [ i ]. name = ec -> hdr .name ;
1288
+ kc [ i ]. private_value = (long )se ;
1289
+ kc [ i ]. iface = SNDRV_CTL_ELEM_IFACE_MIXER ;
1290
+ kc [ i ]. access = ec -> hdr .access ;
1290
1291
1291
- /* we only support FL/FR channel mapping atm */
1292
- 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_r = tplc_chan_get_shift (tplg , ec -> channel , SNDRV_CHMAP_FR );
1292
+ /* we only support FL/FR channel mapping atm */
1293
+ se -> reg = tplc_chan_get_reg (tplg , ec -> channel , SNDRV_CHMAP_FL );
1294
+ se -> shift_l = tplc_chan_get_shift (tplg , ec -> channel ,
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 ;
1297
- se -> mask = ec -> mask ;
1298
- se -> dobj .index = tplg -> index ;
1299
+ se -> items = ec -> items ;
1300
+ se -> mask = ec -> mask ;
1301
+ se -> dobj .index = tplg -> index ;
1299
1302
1300
- switch (ec -> hdr .ops .info ) {
1301
- case SND_SOC_TPLG_CTL_ENUM_VALUE :
1302
- case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE :
1303
- err = soc_tplg_denum_create_values (se , ec );
1304
- if (err < 0 ) {
1305
- dev_err (tplg -> dev , "ASoC: could not create values for %s\n" ,
1306
- ec -> hdr .name );
1303
+ switch (ec -> hdr .ops .info ) {
1304
+ case SND_SOC_TPLG_CTL_ENUM_VALUE :
1305
+ case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE :
1306
+ err = soc_tplg_denum_create_values (se , ec );
1307
+ if (err < 0 ) {
1308
+ dev_err (tplg -> dev , "ASoC: could not create values for %s\n" ,
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
1326
goto err_se ;
1308
1327
}
1309
- /* fall through to create texts */
1310
- case SND_SOC_TPLG_CTL_ENUM :
1311
- case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE :
1312
- case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT :
1313
- err = soc_tplg_denum_create_texts (se , ec );
1328
+
1329
+ /* map io handlers */
1330
+ err = soc_tplg_kcontrol_bind_io (& ec -> hdr , & kc [i ], tplg );
1331
+ if (err ) {
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
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
1341
ec -> hdr .name );
1317
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 */
1327
- err = soc_tplg_kcontrol_bind_io (& ec -> hdr , kc , tplg );
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 ;
1345
+ tplg -> pos += (sizeof (struct snd_soc_tplg_enum_control ) +
1346
+ ec -> priv .size );
1340
1347
}
1341
1348
1342
1349
return kc ;
1343
1350
1344
1351
err_se :
1345
- /* free values and texts */
1346
- kfree (se -> dobj .control .dvalues );
1347
- for (i = 0 ; i < ec -> items ; i ++ )
1348
- kfree (se -> dobj .control .dtexts [i ]);
1352
+ for (; i >= 0 ; i -- ) {
1353
+ /* free values and texts */
1354
+ se = (struct soc_enum * )kc [i ].private_value ;
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
+ }
1351
1361
err :
1352
1362
kfree (kc );
1353
1363
@@ -1499,9 +1509,10 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
1499
1509
case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT :
1500
1510
case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE :
1501
1511
template .dobj .widget .kcontrol_enum = 1 ;
1502
- template .num_kcontrols = 1 ;
1512
+ template .num_kcontrols = w -> num_kcontrols ;
1503
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
1516
if (!template .kcontrol_news ) {
1506
1517
ret = - ENOMEM ;
1507
1518
goto hdr_err ;
0 commit comments