[alsa-devel] [PATCH] ASoC: Allocate PCM operations dynamically to support multiple DAIs
The original code does not cover the case that two DAIs(CPU) have different ASoC core PCM operations(like mmap, pointer...). Currently we have only one global soc_pcm_ops for ASoC core PCM operation. When two DAIs have different pointer functions, second DAI's pointer function is set for both first DAI and second DAI in case of original code.
This patch allocates ASoC core PCM operations dynamically for each DAIs. So each DAIs can have different ASoC core PCM operations. This is needed to support multiple DAIs.
Signed-off-by: Sangsu Park sangsu4u.park@samsung.com Signed-off-by: Sangbeom Kim sbkim73@samsung.com --- sound/core/pcm.c | 1 + sound/soc/soc-pcm.c | 44 ++++++++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 20 deletions(-)
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8928ca8..15cf27a 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -769,6 +769,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) substream_next = substream->next; snd_pcm_timer_done(substream); snd_pcm_substream_proc_done(substream); + kfree(substream->ops); kfree(substream); substream = substream_next; } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 8aa7cec..3a52534 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -598,17 +598,6 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) return offset; }
-/* ASoC PCM operations */ -static struct snd_pcm_ops soc_pcm_ops = { - .open = soc_pcm_open, - .close = soc_pcm_close, - .hw_params = soc_pcm_hw_params, - .hw_free = soc_pcm_hw_free, - .prepare = soc_pcm_prepare, - .trigger = soc_pcm_trigger, - .pointer = soc_pcm_pointer, -}; - /* create a new pcm */ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) { @@ -616,10 +605,25 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_pcm_ops *soc_pcm_ops; struct snd_pcm *pcm; char new_name[64]; int ret = 0, playback = 0, capture = 0;
+ soc_pcm_ops = kzalloc(sizeof(*soc_pcm_ops), GFP_KERNEL); + if (soc_pcm_ops == NULL) { + snd_printk(KERN_ERR "Cannot allocate PCM OPS\n"); + return -ENOMEM; + } + + soc_pcm_ops->open = soc_pcm_open; + soc_pcm_ops->close = soc_pcm_close; + soc_pcm_ops->hw_params = soc_pcm_hw_params; + soc_pcm_ops->hw_free = soc_pcm_hw_free; + soc_pcm_ops->prepare = soc_pcm_prepare; + soc_pcm_ops->trigger = soc_pcm_trigger; + soc_pcm_ops->pointer = soc_pcm_pointer; + /* check client and interface hw capabilities */ snprintf(new_name, sizeof(new_name), "%s %s-%d", rtd->dai_link->stream_name, codec_dai->name, num); @@ -643,20 +647,20 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->pcm = pcm; pcm->private_data = rtd; if (platform->driver->ops) { - soc_pcm_ops.mmap = platform->driver->ops->mmap; - soc_pcm_ops.pointer = platform->driver->ops->pointer; - soc_pcm_ops.ioctl = platform->driver->ops->ioctl; - soc_pcm_ops.copy = platform->driver->ops->copy; - soc_pcm_ops.silence = platform->driver->ops->silence; - soc_pcm_ops.ack = platform->driver->ops->ack; - soc_pcm_ops.page = platform->driver->ops->page; + soc_pcm_ops->mmap = platform->driver->ops->mmap; + soc_pcm_ops->pointer = platform->driver->ops->pointer; + soc_pcm_ops->ioctl = platform->driver->ops->ioctl; + soc_pcm_ops->copy = platform->driver->ops->copy; + soc_pcm_ops->silence = platform->driver->ops->silence; + soc_pcm_ops->ack = platform->driver->ops->ack; + soc_pcm_ops->page = platform->driver->ops->page; }
if (playback) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, soc_pcm_ops);
if (capture) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, soc_pcm_ops);
if (platform->driver->pcm_new) { ret = platform->driver->pcm_new(rtd);
On Fri, 2011-12-23 at 10:37 +0900, Sangbeom Kim wrote:
The original code does not cover the case that two DAIs(CPU) have different ASoC core PCM operations(like mmap, pointer...). Currently we have only one global soc_pcm_ops for ASoC core PCM operation. When two DAIs have different pointer functions, second DAI's pointer function is set for both first DAI and second DAI in case of original code.
This patch allocates ASoC core PCM operations dynamically for each DAIs. So each DAIs can have different ASoC core PCM operations. This is needed to support multiple DAIs.
I assume that you have two different DMA controllers (with a separate DMA platform drivers) here ?
If so, why can you not specify each DMA platform driver in your machine driver DAI link ?
Thanks
Liam
On Fri, Dec 23, 2011 at 09:42:01AM +0000, Liam Girdwood wrote:
I assume that you have two different DMA controllers (with a separate DMA platform drivers) here ?
If so, why can you not specify each DMA platform driver in your machine driver DAI link ?
Alan Tull reported the same problem before with a patch that needed respinning. The issue is that we have a static soc_pcm_ops and we don't properly indirect everything, we copy some of the ops into snd_pcm_ops directly. This means that if those ops end up being used then they end up being the same for both drivers.
I was actually intending to fix this over Christmas.
On Fri, Dec 23, 2011 at 10:37:51AM +0900, Sangbeom Kim wrote:
- soc_pcm_ops = kzalloc(sizeof(*soc_pcm_ops), GFP_KERNEL);
- if (soc_pcm_ops == NULL) {
snd_printk(KERN_ERR "Cannot allocate PCM OPS\n");
return -ENOMEM;
- }
This patch is good and fixes a real problem but can you please change it slightly so that instead of dynamically allocating the soc_pcm_ops we just embed it directly in the runtime structure. Since every runtime needs an ops structure we may as well just have it embedded directly and not write the allocation, freeing and error handling code.
participants (3)
-
Liam Girdwood
-
Mark Brown
-
Sangbeom Kim