@@ -2410,12 +2410,11 @@ static void dapm_free_path(struct snd_soc_dapm_path *path)
24102410 kfree (path );
24112411}
24122412
2413- void snd_soc_dapm_free_widget (struct snd_soc_dapm_widget * w )
2413+ static void snd_soc_dapm_free_widget_data (struct snd_soc_dapm_widget * w )
24142414{
24152415 struct snd_soc_dapm_path * p , * next_p ;
24162416 enum snd_soc_dapm_direction dir ;
24172417
2418- list_del (& w -> list );
24192418 /*
24202419 * remove source and sink paths associated to this widget.
24212420 * While removing the path, remove reference to it from both
@@ -2428,6 +2427,12 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
24282427
24292428 kfree (w -> kcontrols );
24302429 kfree_const (w -> name );
2430+ }
2431+
2432+ void snd_soc_dapm_free_widget (struct snd_soc_dapm_widget * w )
2433+ {
2434+ list_del (& w -> list );
2435+ snd_soc_dapm_free_widget_data (w );
24312436 kfree (w );
24322437}
24332438
@@ -3046,11 +3051,16 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
30463051 */
30473052int snd_soc_dapm_new_widgets (struct snd_soc_card * card )
30483053{
3049- struct snd_soc_dapm_widget * w ;
3054+ struct snd_soc_dapm_widget * w , * last ;
30503055 unsigned int val ;
3056+ int ret = 0 ;
30513057
30523058 mutex_lock_nested (& card -> dapm_mutex , SND_SOC_DAPM_CLASS_INIT );
30533059
3060+ /*
3061+ * widgets with the snd_soc_dapm_kcontrol ID and .num_controls = 0 can
3062+ * be appended to the list while scanning it, this is safe.
3063+ */
30543064 list_for_each_entry (w , & card -> widgets , list )
30553065 {
30563066 if (w -> new )
@@ -3061,33 +3071,39 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
30613071 sizeof (struct snd_kcontrol * ),
30623072 GFP_KERNEL );
30633073 if (!w -> kcontrols ) {
3064- mutex_unlock ( & card -> dapm_mutex ) ;
3065- return - ENOMEM ;
3074+ ret = - ENOMEM ;
3075+ goto out_free ;
30663076 }
30673077 }
30683078
30693079 switch (w -> id ) {
30703080 case snd_soc_dapm_switch :
30713081 case snd_soc_dapm_mixer :
30723082 case snd_soc_dapm_mixer_named_ctl :
3073- dapm_new_mixer (w );
3083+ ret = dapm_new_mixer (w );
30743084 break ;
30753085 case snd_soc_dapm_mux :
30763086 case snd_soc_dapm_demux :
3077- dapm_new_mux (w );
3087+ ret = dapm_new_mux (w );
30783088 break ;
30793089 case snd_soc_dapm_pga :
30803090 case snd_soc_dapm_effect :
30813091 case snd_soc_dapm_out_drv :
3082- dapm_new_pga (w );
3092+ ret = dapm_new_pga (w );
30833093 break ;
30843094 case snd_soc_dapm_dai_link :
3085- dapm_new_dai_link (w );
3095+ ret = dapm_new_dai_link (w );
30863096 break ;
30873097 default :
30883098 break ;
30893099 }
30903100
3101+ if (ret < 0 ) {
3102+ kfree (w -> kcontrols );
3103+ w -> kcontrols = NULL ;
3104+ goto out_free ;
3105+ }
3106+
30913107 /* Read the initial power state from the device */
30923108 if (w -> reg >= 0 ) {
30933109 soc_dapm_read (w -> dapm , w -> reg , & val );
@@ -3096,6 +3112,11 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
30963112 if (val == w -> on_val )
30973113 w -> power = 1 ;
30983114 }
3115+ }
3116+
3117+ list_for_each_entry (w , & card -> widgets , list ) {
3118+ if (w -> new )
3119+ continue ;
30993120
31003121 w -> new = 1 ;
31013122
@@ -3106,6 +3127,66 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
31063127 dapm_power_widgets (card , SND_SOC_DAPM_STREAM_NOP );
31073128 mutex_unlock (& card -> dapm_mutex );
31083129 return 0 ;
3130+
3131+ out_free :
3132+ last = w ;
3133+
3134+ /*
3135+ * If any new widgets have been created above for .autodisable = 1
3136+ * controls, they are also on this list, but at its very end. We're
3137+ * processing an error case, so the loop above was interrupted before
3138+ * reaching dynamically added widgets, since the latter cannot fail -
3139+ * their .num_controls = 0, so allocation cannot fail, and their type is
3140+ * snd_soc_dapm_kcontrol, those cannot fail either. Therefore "last"
3141+ * points to a widget before the first dynamic one.
3142+ */
3143+ list_for_each_entry (w , & card -> widgets , list ) {
3144+ unsigned int i ;
3145+
3146+ if (w -> new )
3147+ continue ;
3148+
3149+ if (w == last )
3150+ break ;
3151+
3152+ switch (w -> id ) {
3153+ case snd_soc_dapm_switch :
3154+ case snd_soc_dapm_mixer :
3155+ case snd_soc_dapm_mixer_named_ctl :
3156+ for (i = 0 ; i < w -> num_kcontrols ; i ++ ) {
3157+ struct snd_kcontrol * kcontrol = w -> kcontrols [i ];
3158+ struct dapm_kcontrol_data * data =
3159+ kcontrol -> private_data ;
3160+ struct soc_mixer_control * mc =
3161+ (struct soc_mixer_control * )
3162+ kcontrol -> private_value ;
3163+
3164+ if (mc -> autodisable )
3165+ snd_soc_dapm_free_widget (data -> widget );
3166+ }
3167+ break ;
3168+ case snd_soc_dapm_demux :
3169+ case snd_soc_dapm_mux :
3170+ for (i = 0 ; i < w -> num_kcontrols ; i ++ ) {
3171+ struct snd_kcontrol * kcontrol = w -> kcontrols [i ];
3172+ struct dapm_kcontrol_data * data =
3173+ kcontrol -> private_data ;
3174+ struct soc_enum * e = (struct soc_enum * )
3175+ kcontrol -> private_value ;
3176+
3177+ if (e -> autodisable )
3178+ snd_soc_dapm_free_widget (data -> widget );
3179+ }
3180+ break ;
3181+ default :
3182+ break ;
3183+ }
3184+
3185+ snd_soc_dapm_free_widget_data (w );
3186+ }
3187+
3188+ mutex_unlock (& card -> dapm_mutex );
3189+ return ret ;
31093190}
31103191EXPORT_SYMBOL_GPL (snd_soc_dapm_new_widgets );
31113192
0 commit comments