Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b9f3e65 authored by Stephen Warren's avatar Stephen Warren Committed by Mark Brown
Browse files

ASoC: don't leak on error in snd_dmaengine_pcm_register



If snd_dmaengine_pcm_register()'s call to snd_soc_add_platform() fails,
all objects allocated during registration are leaked. Fix this by adding
error-handling code.

Signed-off-by: default avatarStephen Warren <swarren@nvidia.com>
Acked-by: default avatarLars-Peter Clausen <lars@metafoo.de>
Signed-off-by: default avatarMark Brown <broonie@linaro.org>
parent 6ce4eac1
Loading
Loading
Loading
Loading
+27 −11
Original line number Original line Diff line number Diff line
@@ -305,6 +305,20 @@ static void dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm,
	}
	}
}
}


static void dmaengine_pcm_release_chan(struct dmaengine_pcm *pcm)
{
	unsigned int i;

	for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE;
	     i++) {
		if (!pcm->chan[i])
			continue;
		dma_release_channel(pcm->chan[i]);
		if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX)
			break;
	}
}

/**
/**
 * snd_dmaengine_pcm_register - Register a dmaengine based PCM device
 * snd_dmaengine_pcm_register - Register a dmaengine based PCM device
 * @dev: The parent device for the PCM device
 * @dev: The parent device for the PCM device
@@ -315,6 +329,7 @@ int snd_dmaengine_pcm_register(struct device *dev,
	const struct snd_dmaengine_pcm_config *config, unsigned int flags)
	const struct snd_dmaengine_pcm_config *config, unsigned int flags)
{
{
	struct dmaengine_pcm *pcm;
	struct dmaengine_pcm *pcm;
	int ret;


	pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
	pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
	if (!pcm)
	if (!pcm)
@@ -326,11 +341,20 @@ int snd_dmaengine_pcm_register(struct device *dev,
	dmaengine_pcm_request_chan_of(pcm, dev);
	dmaengine_pcm_request_chan_of(pcm, dev);


	if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
	if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
		return snd_soc_add_platform(dev, &pcm->platform,
		ret = snd_soc_add_platform(dev, &pcm->platform,
				&dmaengine_no_residue_pcm_platform);
				&dmaengine_no_residue_pcm_platform);
	else
	else
		return snd_soc_add_platform(dev, &pcm->platform,
		ret = snd_soc_add_platform(dev, &pcm->platform,
				&dmaengine_pcm_platform);
				&dmaengine_pcm_platform);
	if (ret)
		goto err_free_dma;

	return 0;

err_free_dma:
	dmaengine_pcm_release_chan(pcm);
	kfree(pcm);
	return ret;
}
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register);
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register);


@@ -345,7 +369,6 @@ void snd_dmaengine_pcm_unregister(struct device *dev)
{
{
	struct snd_soc_platform *platform;
	struct snd_soc_platform *platform;
	struct dmaengine_pcm *pcm;
	struct dmaengine_pcm *pcm;
	unsigned int i;


	platform = snd_soc_lookup_platform(dev);
	platform = snd_soc_lookup_platform(dev);
	if (!platform)
	if (!platform)
@@ -353,15 +376,8 @@ void snd_dmaengine_pcm_unregister(struct device *dev)


	pcm = soc_platform_to_pcm(platform);
	pcm = soc_platform_to_pcm(platform);


	for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
		if (pcm->chan[i]) {
			dma_release_channel(pcm->chan[i]);
			if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX)
				break;
		}
	}

	snd_soc_remove_platform(platform);
	snd_soc_remove_platform(platform);
	dmaengine_pcm_release_chan(pcm);
	kfree(pcm);
	kfree(pcm);
}
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_unregister);
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_unregister);