mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	ASoC: soc-pcm: add soc_pcm_clean() and call it from soc_pcm_open/close()
soc_pcm_open() does rollback when failed (A),
but, it is almost same as soc_pcm_close().
	static int soc_pcm_open(xxx)
	{
		...
		if (ret < 0)
			goto xxx_err;
		...
		return 0;
 ^	config_err:
 |		...
 |	rtd_startup_err:
(A)		...
 |	component_err:
 |		...
 v		return ret;
	}
The difference is
soc_pcm_close() is for all dai/component/substream,
rollback        is for succeeded part only.
This kind of duplicated code can be a hotbed of bugs,
thus, we want to share soc_pcm_close() and rollback.
Now, soc_pcm_open/close() are handling
	1) snd_soc_dai_startup/shutdown()
	2) snd_soc_link_startup/shutdown()
	3) snd_soc_component_module_get/put()
	4) snd_soc_component_open/close()
	5) pm_runtime_put/get()
Now, 1) to 5) are handled.
This patch adds new soc_pcm_clean() and call it from
soc_pcm_open() as rollback, and from soc_pcm_close() as
normal close handler.
One note here is that it don't need to call snd_soc_runtime_deactivate()
when rollback case, because it will be called without
snd_soc_runtime_activate().
It also don't need to call snd_soc_dapm_stream_stop() when rollback case.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87ft72bwn4.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
			
			
This commit is contained in:
		
							parent
							
								
									939a5cfb2a
								
							
						
					
					
						commit
						140a4532cd
					
				| @ -651,12 +651,7 @@ static int soc_pcm_components_close(struct snd_pcm_substream *substream, | |||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback) | ||||||
|  * Called by ALSA when a PCM substream is closed. Private data can be |  | ||||||
|  * freed here. The cpu DAI, codec DAI, machine and components are also |  | ||||||
|  * shutdown. |  | ||||||
|  */ |  | ||||||
| static int soc_pcm_close(struct snd_pcm_substream *substream) |  | ||||||
| { | { | ||||||
| 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); | 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); | ||||||
| 	struct snd_soc_component *component; | 	struct snd_soc_component *component; | ||||||
| @ -665,20 +660,22 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||||||
| 
 | 
 | ||||||
| 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); | 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); | ||||||
| 
 | 
 | ||||||
|  | 	if (!rollback) | ||||||
| 		snd_soc_runtime_deactivate(rtd, substream->stream); | 		snd_soc_runtime_deactivate(rtd, substream->stream); | ||||||
| 
 | 
 | ||||||
| 	for_each_rtd_dais(rtd, i, dai) | 	for_each_rtd_dais(rtd, i, dai) | ||||||
| 		snd_soc_dai_shutdown(dai, substream, 0); | 		snd_soc_dai_shutdown(dai, substream, rollback); | ||||||
| 
 | 
 | ||||||
| 	snd_soc_link_shutdown(substream, 0); | 	snd_soc_link_shutdown(substream, rollback); | ||||||
| 
 | 
 | ||||||
| 	soc_pcm_components_close(substream, 0); | 	soc_pcm_components_close(substream, rollback); | ||||||
| 
 | 
 | ||||||
|  | 	if (!rollback) | ||||||
| 		snd_soc_dapm_stream_stop(rtd, substream->stream); | 		snd_soc_dapm_stream_stop(rtd, substream->stream); | ||||||
| 
 | 
 | ||||||
| 	mutex_unlock(&rtd->card->pcm_mutex); | 	mutex_unlock(&rtd->card->pcm_mutex); | ||||||
| 
 | 
 | ||||||
| 	snd_soc_pcm_component_pm_runtime_put(rtd, substream, 0); | 	snd_soc_pcm_component_pm_runtime_put(rtd, substream, rollback); | ||||||
| 
 | 
 | ||||||
| 	for_each_rtd_components(rtd, i, component) | 	for_each_rtd_components(rtd, i, component) | ||||||
| 		if (!snd_soc_component_active(component)) | 		if (!snd_soc_component_active(component)) | ||||||
| @ -687,6 +684,16 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Called by ALSA when a PCM substream is closed. Private data can be | ||||||
|  |  * freed here. The cpu DAI, codec DAI, machine and components are also | ||||||
|  |  * shutdown. | ||||||
|  |  */ | ||||||
|  | static int soc_pcm_close(struct snd_pcm_substream *substream) | ||||||
|  | { | ||||||
|  | 	return soc_pcm_clean(substream, 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Called by ALSA when a PCM substream is opened, the runtime->hw record is |  * Called by ALSA when a PCM substream is opened, the runtime->hw record is | ||||||
|  * then initialized and any private data can be allocated. This also calls |  * then initialized and any private data can be allocated. This also calls | ||||||
| @ -707,17 +714,17 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||||||
| 
 | 
 | ||||||
| 	ret = snd_soc_pcm_component_pm_runtime_get(rtd, substream); | 	ret = snd_soc_pcm_component_pm_runtime_get(rtd, substream); | ||||||
| 	if (ret < 0) | 	if (ret < 0) | ||||||
| 		goto pm_err; | 		goto err; | ||||||
| 
 | 
 | ||||||
| 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); | 	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); | ||||||
| 
 | 
 | ||||||
| 	ret = soc_pcm_components_open(substream); | 	ret = soc_pcm_components_open(substream); | ||||||
| 	if (ret < 0) | 	if (ret < 0) | ||||||
| 		goto component_err; | 		goto err; | ||||||
| 
 | 
 | ||||||
| 	ret = snd_soc_link_startup(substream); | 	ret = snd_soc_link_startup(substream); | ||||||
| 	if (ret < 0) | 	if (ret < 0) | ||||||
| 		goto rtd_startup_err; | 		goto err; | ||||||
| 
 | 
 | ||||||
| 	/* startup the audio subsystem */ | 	/* startup the audio subsystem */ | ||||||
| 	for_each_rtd_dais(rtd, i, dai) { | 	for_each_rtd_dais(rtd, i, dai) { | ||||||
| @ -726,7 +733,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||||||
| 			dev_err(dai->dev, | 			dev_err(dai->dev, | ||||||
| 				"ASoC: can't open DAI %s: %d\n", | 				"ASoC: can't open DAI %s: %d\n", | ||||||
| 				dai->name, ret); | 				dai->name, ret); | ||||||
| 			goto config_err; | 			goto err; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||||||
| @ -755,18 +762,18 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||||||
| 	if (!runtime->hw.rates) { | 	if (!runtime->hw.rates) { | ||||||
| 		printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n", | 		printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n", | ||||||
| 			codec_dai_name, cpu_dai_name); | 			codec_dai_name, cpu_dai_name); | ||||||
| 		goto config_err; | 		goto err; | ||||||
| 	} | 	} | ||||||
| 	if (!runtime->hw.formats) { | 	if (!runtime->hw.formats) { | ||||||
| 		printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n", | 		printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n", | ||||||
| 			codec_dai_name, cpu_dai_name); | 			codec_dai_name, cpu_dai_name); | ||||||
| 		goto config_err; | 		goto err; | ||||||
| 	} | 	} | ||||||
| 	if (!runtime->hw.channels_min || !runtime->hw.channels_max || | 	if (!runtime->hw.channels_min || !runtime->hw.channels_max || | ||||||
| 	    runtime->hw.channels_min > runtime->hw.channels_max) { | 	    runtime->hw.channels_min > runtime->hw.channels_max) { | ||||||
| 		printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n", | 		printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n", | ||||||
| 				codec_dai_name, cpu_dai_name); | 				codec_dai_name, cpu_dai_name); | ||||||
| 		goto config_err; | 		goto err; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	soc_pcm_apply_msb(substream); | 	soc_pcm_apply_msb(substream); | ||||||
| @ -776,7 +783,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||||||
| 		if (snd_soc_dai_active(dai)) { | 		if (snd_soc_dai_active(dai)) { | ||||||
| 			ret = soc_pcm_apply_symmetry(substream, dai); | 			ret = soc_pcm_apply_symmetry(substream, dai); | ||||||
| 			if (ret != 0) | 			if (ret != 0) | ||||||
| 				goto config_err; | 				goto err; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -787,29 +794,13 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||||||
| 		 runtime->hw.channels_max); | 		 runtime->hw.channels_max); | ||||||
| 	pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min, | 	pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min, | ||||||
| 		 runtime->hw.rate_max); | 		 runtime->hw.rate_max); | ||||||
| 
 |  | ||||||
| dynamic: | dynamic: | ||||||
| 
 |  | ||||||
| 	snd_soc_runtime_activate(rtd, substream->stream); | 	snd_soc_runtime_activate(rtd, substream->stream); | ||||||
| 
 | err: | ||||||
| 	mutex_unlock(&rtd->card->pcm_mutex); | 	mutex_unlock(&rtd->card->pcm_mutex); | ||||||
| 	return 0; |  | ||||||
| 
 | 
 | ||||||
| config_err: | 	if (ret < 0) | ||||||
| 	for_each_rtd_dais_rollback(rtd, i, dai) | 		soc_pcm_clean(substream, 1); | ||||||
| 		snd_soc_dai_shutdown(dai, substream, 1); |  | ||||||
| 
 |  | ||||||
| 	snd_soc_link_shutdown(substream, 1); |  | ||||||
| rtd_startup_err: |  | ||||||
| 	soc_pcm_components_close(substream, 1); |  | ||||||
| component_err: |  | ||||||
| 	mutex_unlock(&rtd->card->pcm_mutex); |  | ||||||
| pm_err: |  | ||||||
| 	snd_soc_pcm_component_pm_runtime_put(rtd, substream, 1); |  | ||||||
| 
 |  | ||||||
| 	for_each_rtd_components(rtd, i, component) |  | ||||||
| 		if (!snd_soc_component_active(component)) |  | ||||||
| 			pinctrl_pm_select_sleep_state(component->dev); |  | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Kuninori Morimoto
						Kuninori Morimoto