Memory corruption in ASoC
Subsystems (6)
Hi,
I've been hunting a serious memory corruption in the ASoC core for some time now and finally managed to figure out where the actual problem lies.
We're currently using a 2.6.32.10, on a PXA303 based series of devices (see sound/soc/pxa/raumfeld.c).
So here's the demo program, reduced to the max:
http://caiaq.de/download/tmp/alsa.c
The thread launched to call getifaddrs() every 10ms is actually just there because
a) this was the way the bug was originally triggered in our application and
b) this seems to be a good way to put the kernel's memory management under fire, so you don't have to wait long for a crash.
Important to mention is that the bug is only triggered when snd_pcm_set_params() is called for both streams, and only if more than one device is opened.
This sources smash my kernel more or less instantly with a backtrace similar to the one at the end of this mail. You might also end up getting hung tasks, and the kernel detector which complains about them after awhile also points out code somewhere in the netlink area (which is of course innocent, we clearly deal with a memory corruption here).
So - look at these simplified sniplets:
// called for stream #0
pxa_ssp_hw_params(...) { // sound/soc/pxa/pxa-ssp.c
...
cpu_dai->dma_data = ssp_get_dma_params(...)
...
}
// called for stream #1
pxa_ssp_startup(...) { // sound/soc/pxa/pxa-ssp.c
...
if (cpu_dai->dma_data) {
kfree(cpu_dai->dma_data);
...
}
}
// called for stream #0
__pxa2xx_pcm_hw_free(...) { // sound/arm/pxa2xx-pcm-lib.c
...
if (rtd && rtd->params && rtd->params->drcmr)
*rtd->params->drcmr = 0; // <-- BOOM
...
}So the first stream (PLAYBACK) already exported its dma_data which is now freed by the code initializing the second stream (CAPTURE). This corrupts all existing users of course, and in this particular case, the cleanup in __pxa2xx_pcm_hw_free() dereferences a pointer which is bogus.
What I really don't understand is why this didn't crash a lot earlier for many more users.
So how is this supposed to be fixed? Should dma_data become a member of some per-stream instance? I believe that also other platforms than PXA are actually affected - am I right?
Daniel
[ 42.158232] Unable to handle kernel NULL pointer dereference at virtual address 00000008 [ 42.166289] pgd = c7f14000 [ 42.168970] [00000008] *pgd=a7eff031, *pte=00000000, *ppte=00000000 [ 42.175187] Internal error: Oops: 17 [#1] [ 42.179163] last sysfs file: /sys/devices/virtual/vc/vcsa1/dev [ 42.184950] Modules linked in: [ 42.187983] CPU: 0 Not tainted (2.6.32.10 #99) [ 42.192769] PC is at netlink_dump_start+0x154/0x190 [ 42.197609] LR is at 0x306874 [ 42.200552] pc : [<c029dc38>] lr : [<00306874>] psr: 20000093 [ 42.200562] sp : c7ecdd10 ip : 00000000 fp : c053c648 [ 42.211954] r10: c7844000 r9 : c7ec8200 r8 : 0000045e [ 42.217141] r7 : c7edc140 r6 : c7ec8600 r5 : 00000000 r4 : 00000000 [ 42.223620] r3 : 20000093 r2 : 20000013 r1 : c79df600 r0 : 0000006c [ 42.230102] Flags: nzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user [ 42.237276] Control: 0000397f Table: a7f14018 DAC: 00000015 [ 42.242979] Process alsa (pid: 1118, stack limit = 0xc7ecc278) [ 42.248769] Stack: (0xc7ecdd10 to 0xc7ece000) [ 42.253099] dd00: c0296b94 c7ec8200 00000006 00000000 [ 42.261227] dd20: c7ec8600 c0298118 00000000 c7ecde40 c7ecdd5c c7ed8a80 c005030c c7ec8200 [ 42.269359] dd40: c7ed8a80 c0298040 c7ecdd7c c7ec8600 00000000 00000038 c053c648 c029ea10 [ 42.277493] dd60: c7ed8a80 00000014 c7ed8a80 c0298030 c7844000 c029e6e0 00000014 7fffffff [ 42.285625] dd80: 00000014 00000000 c7ed8a80 c7ec8600 c7ecdf5c c7672580 c7ecde80 00000000 [ 42.293748] dda0: 00000014 c029efb0 00000000 c005118c 00000000 00000000 0000045e 00000000 [ 42.301872] ddc0: 00000000 00000000 00000000 00000000 00000000 c7ecdf5c 00000014 be1ff9ec [ 42.309997] dde0: c7ecc000 0000000c be1ffa84 c027f730 c0069880 c7ecddf4 00000000 00000001 [ 42.318120] de00: ffffffff 00000000 00000000 00000000 00000000 00000000 c7a10f00 00000000 [ 42.326247] de20: 00000000 00000000 be1ff9ec c7a10f00 c0069880 c7ecde34 c7ecde34 00120000 [ 42.334379] de40: 00000014 be1ff9ec c7ecde80 00001000 c7672580 c0050518 c7ecdd68 c7ecdf5c [ 42.342503] de60: 00000000 be1ffa2c c7672580 be1ffa28 be1ffa44 be1ffa44 0000000c 00000000 [ 42.350628] de80: 0000000c c02802c4 c7672580 00000014 c7672580 c0280420 c7ecddb8 c7ecdf5c [ 42.358751] dea0: 00000000 00000000 c027ea8c 00000000 c7ecdedc 00000014 be1ff9ec c7ecdedc [ 42.366876] dec0: 0000000c c7672580 00000000 c7ecdedc 00000014 c027fa08 c00440c4 00000010 [ 42.375001] dee0: 00000000 00000000 0000000c c02802c4 0000000c c7672580 c7ecdf04 c0280690 [ 42.383124] df00: c7ecdf08 00000010 0000045e 00000000 00000000 c76747d8 c7674780 be1fea1c [ 42.391249] df20: 00000fec c7ecdf4c 00000005 c7ec9f80 c7672580 00000000 c03fd590 c027f3d8 [ 42.399373] df40: c03fd590 c0532ab0 c7e8ad80 00000000 00000000 c047c88f 00000005 c7ecdedc [ 42.407497] df60: 0000000c c7ecdf78 00000001 00000000 00000000 00000000 be1ff9ec 00000000 [ 42.415620] df80: 00000001 00000000 00000000 be1ff9ec 0000000c 0000000c 00000122 c00440c4 [ 42.423746] dfa0: 00000000 c0043f40 be1ff9ec 0000000c 00000005 be1ff9d8 00000014 00000000 [ 42.431870] dfc0: be1ff9ec 0000000c 0000000c 00000122 be1ff9ec 00001000 00000000 be1ffa84 [ 42.439995] dfe0: 00000000 be1ff9c0 4011e8a4 40123848 60000010 00000005 00000000 00000000 [ 42.448139] [<c029dc38>] (netlink_dump_start+0x154/0x190) from [<c0298118>] (rtnetlink_rcv_msg+0xd8/0x220) [ 42.457739] [<c0298118>] (rtnetlink_rcv_msg+0xd8/0x220) from [<c029ea10>] (netlink_rcv_skb+0x4c/0xb0) [ 42.466904] [<c029ea10>] (netlink_rcv_skb+0x4c/0xb0) from [<c0298030>] (rtnetlink_rcv+0x1c/0x2c) [ 42.475640] [<c0298030>] (rtnetlink_rcv+0x1c/0x2c) from [<c029e6e0>] (netlink_unicast+0x22c/0x2d0) [ 42.484550] [<c029e6e0>] (netlink_unicast+0x22c/0x2d0) from [<c029efb0>] (netlink_sendmsg+0x260/0x274) [ 42.493806] [<c029efb0>] (netlink_sendmsg+0x260/0x274) from [<c027f730>] (sock_sendmsg+0xa0/0xc4) [ 42.502630] [<c027f730>] (sock_sendmsg+0xa0/0xc4) from [<c027fa08>] (sys_sendto+0xb0/0xd4) [ 42.510866] [<c027fa08>] (sys_sendto+0xb0/0xd4) from [<c0043f40>] (ret_fast_syscall+0x0/0x28) [ 42.519344] Code: ebfffe2e e10f2000 e3823080 e121f003 (e5943008) [ 42.525679] ---[ end trace 3209e05a50ffc8c1 ]---
Quoted 6 lines · Daniel Mack
So the first stream (PLAYBACK) already exported its
dma_datawhich is now freed by the code initializing the second stream (CAPTURE). This corrupts all existing users of course, and in this particular case, the cleanup in__pxa2xx_pcm_hw_free()dereferences a pointer which is bogus.
Quoted 6 lines
What I really don't understand is why this didn't crash a lot earlier for many more users.
So how is this supposed to be fixed? Should
dma_databecome a member of some per-stream instance? I believe that also other platforms than PXA are actually affected - am I right?
It should really be per-substream, yes.
It's relatively hard to trigger problems on a lot of platform since the DAI data pointer is often only really used at stream setup, meaning that triggering a problem requires that a system not only does simultaneous playback and capture but also has overlapping startup of the two. PXA is also very rare in doing dynamic allocation here, most drivers use statically allocated resources which would make any problems much less obvious.
There's some more generic issues there to do with imposing constraints but that's a separate thing.
Quoted 8 lines · Mark Brown
Quoted 5 lines · Daniel Mack
So the first stream (PLAYBACK) already exported its
dma_datawhich is now freed by the code initializing the second stream (CAPTURE). This corrupts all existing users of course, and in this particular case, the cleanup in__pxa2xx_pcm_hw_free()dereferences a pointer which is bogus.
Quoted 8 lines
Quoted 6 lines
What I really don't understand is why this didn't crash a lot earlier for many more users.
So how is this supposed to be fixed? Should
dma_databecome a member of some per-stream instance? I believe that also other platforms than PXA are actually affected - am I right?It should really be per-substream, yes.
Do you want me to fix this or are you working on this already?
I know there are some pxa-ssp related things pending which will also cause merge conflicts - which tree should thing apply to currently?
Quoted 4 lines
It's relatively hard to trigger problems on a lot of platform since the DAI data pointer is often only really used at stream setup, meaning that triggering a problem requires that a system not only does simultaneous playback and capture but also has overlapping startup of the two.
Well, how would you initialize them in a non-overlapping way? The example I sent does the setup fairly straight-forward, doesn't it?
I'd say any full-duplex system is affected.
Daniel
Quoted 5 lines · Daniel Mack
Quoted 1 line · Mark Brown
It should really be per-substream, yes.
Do you want me to fix this or are you working on this already?
I'm all in favour of approaches that involve me doing less work :) Though watch out for a mail from Liam shortly...
Quoted 2 lines
I know there are some pxa-ssp related things pending which will also cause merge conflicts - which tree should thing apply to currently?
ASoC. I guess 2.6.35 - this is going to be an invasive fix and people can backport if they actually notice.
Quoted 7 lines
Quoted 4 lines
It's relatively hard to trigger problems on a lot of platform since the DAI data pointer is often only really used at stream setup, meaning that triggering a problem requires that a system not only does simultaneous playback and capture but also has overlapping startup of the two.
Well, how would you initialize them in a non-overlapping way? The example I sent does the setup fairly straight-forward, doesn't it?
You are doing non-overlapping initialisation, overlapping would be if you were doing the two open() calls followed by two set_params() calls rather than doing each stream in turn.
Quoted 1 line
I'd say any full-duplex system is affected.
There's a race on any system using the DAI dma_data, but your program either won't trigger it or will trigger it in a way that's not so obvious on quite a few systems.
You're not overlapping the startup of the two streams so your program will run OK if the drivers only use the pointer during setup - the program will only trigger a problem if the pointer is also used in the teardown path. Many systems will also be saved by the fact that they use static data rather than dynamically allocated so they'll end up operating on the wrong DMA stream but this probably won't have any user noticable problems if both streams are being shut down, the DMA controller will just be stalled waiting for the port instead of properly stopped.
Quoted 10 lines · Mark Brown
Quoted 5 lines · Daniel Mack
Quoted 1 line · Mark Brown
It should really be per-substream, yes.
Do you want me to fix this or are you working on this already?
I'm all in favour of approaches that involve me doing less work :) Though watch out for a mail from Liam shortly...
Please do.
Fwiw we do have some unnecessary complexity in our hw_params() and hw_free() calls in order to support OSS emulation. i.e. hw_params() can be called several times for each substream by OSS emulation with different audio parameters each time (hence the need to always free and re-config resources). This is not needed for native alsa.
Mark and I have just agreed we will accept patches that remove this sort of complexity and hence OSS emulation support. OSS is being dropped by distro's anyway now and we haven't been testing OSS emu on new ASoC drivers for a while either.....
So don't feel obliged to support OSS emulation in your fix.
Quoted 3 lines
Quoted 2 lines
I know there are some pxa-ssp related things pending which will also cause merge conflicts - which tree should thing apply to currently?
The major work Mark mentioned is the multi-codec + multi-platform (Audio Engine) support. Mark and I are just finalising the API changes and there is some a development branch here :-
http://git.kernel.org/?p=linux/kernel/git/lrg/asoc-2.6.git;a=shortlog;h=refs/heads/topic/multi-codec
The API move things closer the the driver model and are being aimed at 2.6.35.
Liam
Signature · 3 lines
Freelance Developer, SlimLogic Ltd ASoC and Voltage Regulator Maintainer. http://www.slimlogic.co.uk
PATCH 1/1 ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
This fixes a memory corruption when using ASoC devices are used in full-duplex mode. Specifically for pxa-ssp code, where this pointer is dynamically allocated for each direction and destroyed upon each stream start.
All other platforms are fixed blindly, I couldn't even compile-test them. Sorry for any breakage I may have caused.
--- include/sound/soc-dai.h | 18 +++++++++++++++++- include/sound/soc.h | 1 + sound/soc/atmel/atmel-pcm.c | 2 +- sound/soc/atmel/atmel_ssc_dai.c | 6 +++--- sound/soc/davinci/davinci-i2s.c | 3 ++- sound/soc/davinci/davinci-mcasp.c | 3 ++- sound/soc/davinci/davinci-pcm.c | 4 +++- sound/soc/omap/omap-mcbsp.c | 4 +++- sound/soc/omap/omap-pcm.c | 4 +++- sound/soc/pxa/pxa-ssp.c | 23 ++++++++++++----------- sound/soc/pxa/pxa2xx-pcm.c | 4 +++- 11 files changed, 50 insertions(+), 22 deletions(-)
include/sound/soc-dai.h +17 -1
@@ -224,7 +224,6 @@ struct snd_soc_dai {struct snd_soc_codec *codec;unsigned int active; unsigned char pop_wait:1; -void *dma_data;/* DAI private data */ void *private_data;
@@ -235,4 +234,21 @@ struct snd_soc_dai { struct list_head list; }; +static inline void *snd_soc_dai_get_dma_data (const struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss) +{ +return (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) ? + dai->playback.dma_data : dai->capture.dma_data; +} + +static inline void snd_soc_dai_set_dma_data (struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss, +void *data) +{ +if (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) + dai->playback.dma_data = data; +else + dai->capture.dma_data = data; +} +#endif
include/sound/soc.h +1 -0
@@ -376,6 +376,7 @@ struct snd_soc_pcm_stream {unsigned int channels_min;/* min channels */ unsigned int channels_max;/* max channels */ unsigned int active;/* num of active users of the stream */ +void *dma_data;/* used by platform code */ };/* SoC audio ops */
sound/soc/atmel/atmel-pcm.c +1 -1
@@ -180,7 +180,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,snd_pcm_set_runtime_buffer (substream, &substream->dma_buffer); runtime->dma_bytes =params_buffer_bytes (params); - prtd->params = rtd->dai->cpu_dai->dma_data; + prtd->params =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); prtd->params->dma_intr_handler = atmel_pcm_dma_irq; prtd->dma_buffer = runtime->dma_addr;
sound/soc/atmel/atmel_ssc_dai.c +3 -3
@@ -363,12 +363,12 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ssc_p->dma_params[dir] = dma_params;/* -* The cpu_dai->dma_data field is only used to communicate the -* appropriate DMA parameters to the pcm driver hw_params() +* The snd_soc_pcm_stream->dma_data field is only used to communicate +* the appropriate DMA parameters to the pcm driver hw_params() * function. It should not be used for other purposes * as it is common to all substreams. */ - rtd->dai->cpu_dai->dma_data = dma_params; +snd_soc_dai_set_dma_data (rtd->dai->cpu_dai, substream, dma_params); channels =params_channels (params);
sound/soc/davinci/davinci-i2s.c +2 -1
@@ -585,7 +585,8 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev->dma_params[SNDRV_PCM_STREAM_CAPTURE ].channel = res->start; davinci_i2s_dai.private_data = dev; - davinci_i2s_dai.dma_data = dev->dma_params; + davinci_i2s_dai.capture.dma_data = dev->dma_params; + davinci_i2s_dai.playback.dma_data = dev->dma_params; ret =snd_soc_register_dai (&davinci_i2s_dai);if (ret !=0 ) goto err_free_mem;
sound/soc/davinci/davinci-mcasp.c +2 -1
@@ -917,7 +917,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data->channel = res->start; davinci_mcasp_dai[pdata->op_mode].private_data = dev; - davinci_mcasp_dai[pdata->op_mode].dma_data = dev->dma_params; + davinci_mcasp_dai[pdata->op_mode].capture.dma_data = dev->dma_params; + davinci_mcasp_dai[pdata->op_mode].playback.dma_data = dev->dma_params; davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev; ret =snd_soc_register_dai (&davinci_mcasp_dai[pdata->op_mode]);
sound/soc/davinci/davinci-pcm.c +3 -1
@@ -649,8 +649,10 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream)struct snd_pcm_hardware *ppcm;int ret =0 ;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct davinci_pcm_dma_params *pa = rtd->dai->cpu_dai->dma_data; +struct davinci_pcm_dma_params *pa;struct davinci_pcm_dma_params *params; + + pa =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);if (!pa)return -ENODEV ; params = &pa[substream->stream];
sound/soc/omap/omap-mcbsp.c +3 -1
@@ -322,7 +322,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; omap_mcbsp_dai_dma_params[id][substream->stream].data_type =OMAP_DMA_DATA_TYPE_S16 ; - cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; + +snd_soc_dai_set_dma_data (cpu_dai, substream, + &omap_mcbsp_dai_dma_params[id][substream->stream]);if (mcbsp_data->configured) {/* McBSP already configured by another stream */
sound/soc/omap/omap-pcm.c +3 -1
@@ -100,9 +100,11 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct snd_soc_pcm_runtime *rtd = substream->private_data;struct omap_runtime_data *prtd = runtime->private_data; -struct omap_pcm_dma_data *dma_data = rtd->dai->cpu_dai->dma_data; +struct omap_pcm_dma_data *dma_data;int err =0 ; + dma_data =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); +/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma_data)
sound/soc/pxa/pxa-ssp.c +12 -11
@@ -121,10 +121,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,ssp_disable (ssp); } -if (cpu_dai->dma_data) { -kfree (cpu_dai->dma_data); - cpu_dai->dma_data =NULL ; - } +kfree (snd_soc_dai_get_dma_data (cpu_dai, substream)); +snd_soc_dai_set_dma_data (cpu_dai, substream,NULL ); +return ret; }
@@ -141,10 +140,8 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,clk_disable (ssp->clk); } -if (cpu_dai->dma_data) { -kfree (cpu_dai->dma_data); - cpu_dai->dma_data =NULL ; - } +kfree (snd_soc_dai_get_dma_data (cpu_dai, substream)); +snd_soc_dai_set_dma_data (cpu_dai, substream,NULL ); }#ifdef CONFIG_PM
@@ -569,19 +566,23 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,u32 sspsp;int width =snd_pcm_format_physical_width (params_format (params));int ttsa =ssp_read_reg (ssp,SSTSA ) &0xf ; +struct pxa2xx_pcm_dma_params *dma_data; + + dma_data =snd_soc_dai_get_dma_data (dai, substream);/* generate correct DMA params */ -if (cpu_dai->dma_data) -kfree (cpu_dai->dma_data); +kfree (dma_data);/* Network mode with one active slot (ttsa == 1) can be used * to force 16-bit frame width on the wire (for S16_LE), even * with two channels. Use 16-bit DMA transfers for this case. */ - cpu_dai->dma_data =ssp_get_dma_params (ssp, + dma_data =ssp_get_dma_params (ssp, ((chn ==2 ) && (ttsa !=1 )) || (width ==32 ), substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ); +snd_soc_dai_set_dma_data (dai, substream, dma_data); +/* we can only change the settings if the port is not in use */ if (ssp_read_reg (ssp,SSCR0 ) &SSCR0_SSE )return 0 ;
sound/soc/pxa/pxa2xx-pcm.c +3 -1
@@ -25,9 +25,11 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct pxa2xx_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; +struct pxa2xx_pcm_dma_params *dma;int ret; + dma =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); +/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma)
Signature · 1 line
1.6.6.2
Re: [PATCH] ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
Quoted 2 lines · Daniel Mack
This fixes a memory corruption when using ASoC devices are used in full-duplex mode. Specifically for pxa-ssp code, where this pointer
Sorry - in case the patch is ok, could you please fix up my grammar bug?
Thanks,
Daniel
Re: [PATCH] ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
In reply to Daniel MackQuoted 7 lines · Daniel Mack
This fixes a memory corruption when using ASoC devices are used in full-duplex mode. Specifically for pxa-ssp code, where this pointer is dynamically allocated for each direction and destroyed upon each stream start.
All other platforms are fixed blindly, I couldn't even compile-test them. Sorry for any breakage I may have caused.
Looks good at first pass, though I think there's some more platforms have been missed? I'm just about to leave for today, Liam and I will check properly tomorrow. Thanks for diagnosing this!
Quoted 6 lines
include/sound/soc-dai.h +6
-0+static inline void *snd_soc_dai_get_dma_data (const struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss) +{ +return (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) ? + dai->playback.dma_data : dai->capture.dma_data; +}
include/sound/soc-dai.h struct snd_soc_dai { · line 252
Quoted 10 lines
include/sound/soc-dai.h +10
-0+ +static inline void snd_soc_dai_set_dma_data (struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss, +void *data) +{ +if (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) + dai->playback.dma_data = data; +else + dai->capture.dma_data = data; +}
Make your mind up if you like the ternery operator :P
Re: [PATCH] ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
Quoted 6 lines · Mark Brown
Quoted 4 lines · Daniel Mack
This fixes a memory corruption when using ASoC devices are used in full-duplex mode. Specifically for pxa-ssp code, where this pointer is dynamically allocated for each direction and destroyed upon each stream start.
Quoted 6 lines
Quoted 2 lines
All other platforms are fixed blindly, I couldn't even compile-test them. Sorry for any breakage I may have caused.
Looks good at first pass, though I think there's some more platforms have been missed? I'm just about to leave for today, Liam and I will check properly tomorrow. Thanks for diagnosing this!
This is all 'git grep' brought up. Other places should be easy to fix though in case I missed any. Thanks for double-checking.
Quoted 10 lines
Quoted 10 lines
include/sound/soc-dai.h +10
-0+static inline void *snd_soc_dai_get_dma_data (const struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss) +{ +return (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) ? + dai->playback.dma_data : dai->capture.dma_data; +} + +static inline void snd_soc_dai_set_dma_data (struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss, +void *data)
Quoted 8 lines
include/sound/soc-dai.h struct snd_soc_dai { · line 252
Quoted 6 lines
include/sound/soc-dai.h +6
-0+{ +if (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) + dai->playback.dma_data = data; +else + dai->capture.dma_data = data; +}Make your mind up if you like the ternery operator :P
Well - I do, and I use it whereever I can. But in the 'set' case, I can't. Or did I miss the joke? ;)
PATCH 1/1 ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
In reply to Mark BrownThis fixes a memory corruption when ASoC devices are used in full-duplex mode. Specifically for pxa-ssp code, where this pointer is dynamically allocated for each direction and destroyed upon each stream start.
All other platforms are fixed blindly, I couldn't even compile-test them. Sorry for any breakage I may have caused.
---
I indeed missed quite a few platforms, you were right. Hope I got them all now. Better check again - thanks!
include/sound/soc-dai.h | 18 +++++++++++++++- include/sound/soc.h | 1 + sound/soc/atmel/atmel-pcm.c | 2 +- sound/soc/atmel/atmel_ssc_dai.c | 6 ++-- sound/soc/davinci/davinci-i2s.c | 3 +- sound/soc/davinci/davinci-mcasp.c | 3 +- sound/soc/davinci/davinci-pcm.c | 4 ++- sound/soc/davinci/davinci-vcif.c | 3 +- sound/soc/imx/imx-pcm-dma-mx2.c | 8 +++++- sound/soc/imx/imx-ssi.c | 7 ++++- sound/soc/omap/omap-mcbsp.c | 4 ++- sound/soc/omap/omap-mcpdm.c | 3 +- sound/soc/omap/omap-pcm.c | 4 ++- sound/soc/pxa/pxa-ssp.c | 23 +++++++++++---------- sound/soc/pxa/pxa2xx-ac97.c | 17 +++++++++++---- sound/soc/pxa/pxa2xx-i2s.c | 7 ++++- sound/soc/pxa/pxa2xx-pcm.c | 4 ++- sound/soc/s3c24xx/s3c-ac97.c | 21 +++++++++++-------- sound/soc/s3c24xx/s3c-dma.c | 4 ++- sound/soc/s3c24xx/s3c-i2s-v2.c | 13 +++++++---- sound/soc/s3c24xx/s3c-pcm.c | 7 ++++- sound/soc/s3c24xx/s3c2412-i2s.c | 7 ++++- sound/soc/s3c24xx/s3c24xx-i2s.c | 19 +++++++++-------- sound/soc/s6000/s6000-i2s.c | 3 +- sound/soc/s6000/s6000-pcm.c | 40 ++++++++++++++++++++++++++---------- 25 files changed, 156 insertions(+), 75 deletions(-)
include/sound/soc-dai.h +17 -1
@@ -224,7 +224,6 @@ struct snd_soc_dai {struct snd_soc_codec *codec;unsigned int active; unsigned char pop_wait:1; -void *dma_data;/* DAI private data */ void *private_data;
@@ -235,4 +234,21 @@ struct snd_soc_dai { struct list_head list; }; +static inline void *snd_soc_dai_get_dma_data (const struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss) +{ +return (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) ? + dai->playback.dma_data : dai->capture.dma_data; +} + +static inline void snd_soc_dai_set_dma_data (struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss, +void *data) +{ +if (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) + dai->playback.dma_data = data; +else + dai->capture.dma_data = data; +} +#endif
include/sound/soc.h +1 -0
@@ -376,6 +376,7 @@ struct snd_soc_pcm_stream {unsigned int channels_min;/* min channels */ unsigned int channels_max;/* max channels */ unsigned int active;/* num of active users of the stream */ +void *dma_data;/* used by platform code */ };/* SoC audio ops */
sound/soc/atmel/atmel-pcm.c +1 -1
@@ -180,7 +180,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,snd_pcm_set_runtime_buffer (substream, &substream->dma_buffer); runtime->dma_bytes =params_buffer_bytes (params); - prtd->params = rtd->dai->cpu_dai->dma_data; + prtd->params =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); prtd->params->dma_intr_handler = atmel_pcm_dma_irq; prtd->dma_buffer = runtime->dma_addr;
sound/soc/atmel/atmel_ssc_dai.c +3 -3
@@ -363,12 +363,12 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ssc_p->dma_params[dir] = dma_params;/* -* The cpu_dai->dma_data field is only used to communicate the -* appropriate DMA parameters to the pcm driver hw_params() +* The snd_soc_pcm_stream->dma_data field is only used to communicate +* the appropriate DMA parameters to the pcm driver hw_params() * function. It should not be used for other purposes * as it is common to all substreams. */ - rtd->dai->cpu_dai->dma_data = dma_params; +snd_soc_dai_set_dma_data (rtd->dai->cpu_dai, substream, dma_params); channels =params_channels (params);
sound/soc/davinci/davinci-i2s.c +2 -1
@@ -585,7 +585,8 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev->dma_params[SNDRV_PCM_STREAM_CAPTURE ].channel = res->start; davinci_i2s_dai.private_data = dev; - davinci_i2s_dai.dma_data = dev->dma_params; + davinci_i2s_dai.capture.dma_data = dev->dma_params; + davinci_i2s_dai.playback.dma_data = dev->dma_params; ret =snd_soc_register_dai (&davinci_i2s_dai);if (ret !=0 ) goto err_free_mem;
sound/soc/davinci/davinci-mcasp.c +2 -1
@@ -917,7 +917,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data->channel = res->start; davinci_mcasp_dai[pdata->op_mode].private_data = dev; - davinci_mcasp_dai[pdata->op_mode].dma_data = dev->dma_params; + davinci_mcasp_dai[pdata->op_mode].capture.dma_data = dev->dma_params; + davinci_mcasp_dai[pdata->op_mode].playback.dma_data = dev->dma_params; davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev; ret =snd_soc_register_dai (&davinci_mcasp_dai[pdata->op_mode]);
sound/soc/davinci/davinci-pcm.c +3 -1
@@ -649,8 +649,10 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream)struct snd_pcm_hardware *ppcm;int ret =0 ;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct davinci_pcm_dma_params *pa = rtd->dai->cpu_dai->dma_data; +struct davinci_pcm_dma_params *pa;struct davinci_pcm_dma_params *params; + + pa =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);if (!pa)return -ENODEV ; params = &pa[substream->stream];
sound/soc/davinci/davinci-vcif.c +2 -1
@@ -222,7 +222,8 @@ static int davinci_vcif_probe(struct platform_device *pdev) davinci_vc->davinci_vcif.dma_rx_addr; davinci_vcif_dai.dev = &pdev->dev; - davinci_vcif_dai.dma_data = davinci_vcif_dev->dma_params; + davinci_vcif_dai.capture.dma_data = davinci_vcif_dev->dma_params; + davinci_vcif_dai.playback.dma_data = davinci_vcif_dev->dma_params; davinci_vcif_dai.private_data = davinci_vcif_dev; ret =snd_soc_register_dai (&davinci_vcif_dai);
sound/soc/imx/imx-pcm-dma-mx2.c +6 -2
@@ -83,11 +83,13 @@ static void snd_imx_dma_err_callback(int channel, void *data, int err)static int imx_ssi_dma_alloc (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; +struct imx_pcm_dma_params *dma_params;struct snd_pcm_runtime *runtime = substream->runtime;struct imx_pcm_runtime_data *iprtd = runtime->private_data;int ret; + dma_params =snd_soc_get_dma_data (rtd->dai->cpu_dai, substream); + iprtd->dma =imx_dma_request_by_prio (DRV_NAME ,DMA_PRIO_HIGH );if (iprtd->dma <0 ) {pr_err ("Failed to claim the audio DMA\n" );
@@ -192,10 +194,12 @@ static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) {struct snd_pcm_runtime *runtime = substream->runtime;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; +struct imx_pcm_dma_params *dma_params;struct imx_pcm_runtime_data *iprtd = runtime->private_data;int err; + dma_params =snd_soc_get_dma_data (rtd->dai->cpu_dai, substream); + iprtd->substream = substream; iprtd->buf = (unsigned int *)substream->dma_buffer.area; iprtd->period_cnt =0 ;
sound/soc/imx/imx-ssi.c +5 -2
@@ -234,17 +234,20 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) {struct imx_ssi *ssi = cpu_dai->private_data; +struct imx_pcm_dma_params *dma_data;u32 reg, sccr;/* Tx/Rx config */ if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) { reg =SSI_STCCR ; - cpu_dai->dma_data = &ssi->dma_params_tx; + dma_data = &ssi->dma_params_tx; }else { reg =SSI_SRCCR ; - cpu_dai->dma_data = &ssi->dma_params_rx; + dma_data = &ssi->dma_params_rx; } +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data); + sccr =readl (ssi->base + reg) & ~SSI_STCCR_WL_MASK ;/* DAI data (word) size */
sound/soc/omap/omap-mcbsp.c +3 -1
@@ -322,7 +322,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; omap_mcbsp_dai_dma_params[id][substream->stream].data_type =OMAP_DMA_DATA_TYPE_S16 ; - cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; + +snd_soc_dai_set_dma_data (cpu_dai, substream, + &omap_mcbsp_dai_dma_params[id][substream->stream]);if (mcbsp_data->configured) {/* McBSP already configured by another stream */
sound/soc/omap/omap-mcpdm.c +2 -1
@@ -150,7 +150,8 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,int stream = substream->stream;int channels, err, link_mask =0 ; - cpu_dai->dma_data = &omap_mcpdm_dai_dma_params[stream]; +snd_soc_dai_set_dma_data (cpu_dai, substream, + &omap_mcpdm_dai_dma_params[stream]); channels =params_channels (params);switch (channels) {
sound/soc/omap/omap-pcm.c +3 -1
@@ -100,9 +100,11 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct snd_soc_pcm_runtime *rtd = substream->private_data;struct omap_runtime_data *prtd = runtime->private_data; -struct omap_pcm_dma_data *dma_data = rtd->dai->cpu_dai->dma_data; +struct omap_pcm_dma_data *dma_data;int err =0 ; + dma_data =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); +/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma_data)
sound/soc/pxa/pxa-ssp.c +12 -11
@@ -121,10 +121,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,ssp_disable (ssp); } -if (cpu_dai->dma_data) { -kfree (cpu_dai->dma_data); - cpu_dai->dma_data =NULL ; - } +kfree (snd_soc_dai_get_dma_data (cpu_dai, substream)); +snd_soc_dai_set_dma_data (cpu_dai, substream,NULL ); +return ret; }
@@ -141,10 +140,8 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,clk_disable (ssp->clk); } -if (cpu_dai->dma_data) { -kfree (cpu_dai->dma_data); - cpu_dai->dma_data =NULL ; - } +kfree (snd_soc_dai_get_dma_data (cpu_dai, substream)); +snd_soc_dai_set_dma_data (cpu_dai, substream,NULL ); }#ifdef CONFIG_PM
@@ -569,19 +566,23 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,u32 sspsp;int width =snd_pcm_format_physical_width (params_format (params));int ttsa =ssp_read_reg (ssp,SSTSA ) &0xf ; +struct pxa2xx_pcm_dma_params *dma_data; + + dma_data =snd_soc_dai_get_dma_data (dai, substream);/* generate correct DMA params */ -if (cpu_dai->dma_data) -kfree (cpu_dai->dma_data); +kfree (dma_data);/* Network mode with one active slot (ttsa == 1) can be used * to force 16-bit frame width on the wire (for S16_LE), even * with two channels. Use 16-bit DMA transfers for this case. */ - cpu_dai->dma_data =ssp_get_dma_params (ssp, + dma_data =ssp_get_dma_params (ssp, ((chn ==2 ) && (ttsa !=1 )) || (width ==32 ), substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ); +snd_soc_dai_set_dma_data (dai, substream, dma_data); +/* we can only change the settings if the port is not in use */ if (ssp_read_reg (ssp,SSCR0 ) &SSCR0_SSE )return 0 ;
sound/soc/pxa/pxa2xx-ac97.c +12 -5
@@ -122,11 +122,14 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; + dma_data = &pxa2xx_ac97_pcm_stereo_out;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_in; + dma_data = &pxa2xx_ac97_pcm_stereo_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);return 0 ; }
@@ -137,11 +140,14 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; + dma_data = &pxa2xx_ac97_pcm_aux_mono_out;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);return 0 ; }
@@ -156,7 +162,8 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK )return -ENODEV ;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_mic_mono_in; +snd_soc_dai_set_dma_data (cpu_dai, substream, + &pxa2xx_ac97_pcm_mic_mono_in);return 0 ; }
sound/soc/pxa/pxa2xx-i2s.c +5 -2
@@ -164,6 +164,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;BUG_ON (IS_ERR (clk_i2s));clk_enable (clk_i2s);
@@ -171,9 +172,11 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,pxa_i2s_wait ();if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out; + dma_data = &pxa2xx_i2s_pcm_stereo_out;else - cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in; + dma_data = &pxa2xx_i2s_pcm_stereo_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);/* is port used by another stream */ if (!(SACR0 &SACR0_ENB )) {
sound/soc/pxa/pxa2xx-pcm.c +3 -1
@@ -25,9 +25,11 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct pxa2xx_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; +struct pxa2xx_pcm_dma_params *dma;int ret; + dma =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); +/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma)
sound/soc/s3c24xx/s3c-ac97.c +12 -9
@@ -224,11 +224,14 @@ static int s3c_ac97_hw_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct s3c_dma_params *dma_data;if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &s3c_ac97_pcm_out; + dma_data = &s3c_ac97_pcm_out;else - cpu_dai->dma_data = &s3c_ac97_pcm_in; + dma_data = &s3c_ac97_pcm_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);return 0 ; }
@@ -238,8 +241,8 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, {u32 ac_glbctrl;struct snd_soc_pcm_runtime *rtd = substream->private_data; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); ac_glbctrl =readl (s3c_ac97.regs +S3C_AC97_GLBCTRL );if (substream->stream ==SNDRV_PCM_STREAM_CAPTURE )
@@ -265,7 +268,7 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,writel (ac_glbctrl, s3c_ac97.regs +S3C_AC97_GLBCTRL ); -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );return 0 ; }
@@ -280,7 +283,7 @@ static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream,if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK )return -ENODEV ;else - cpu_dai->dma_data = &s3c_ac97_mic_in; +snd_soc_dai_set_dma_data (cpu_dai, substream, &s3c_ac97_mic_in);return 0 ; }
@@ -290,8 +293,8 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, {u32 ac_glbctrl;struct snd_soc_pcm_runtime *rtd = substream->private_data; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); ac_glbctrl =readl (s3c_ac97.regs +S3C_AC97_GLBCTRL ); ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK ;
@@ -311,7 +314,7 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,writel (ac_glbctrl, s3c_ac97.regs +S3C_AC97_GLBCTRL ); -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );return 0 ; }
sound/soc/s3c24xx/s3c-dma.c +3 -1
@@ -145,10 +145,12 @@ static int s3c_dma_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct s3c24xx_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct s3c_dma_params *dma = rtd->dai->cpu_dai->dma_data;unsigned long totbytes =params_buffer_bytes (params); +struct s3c_dma_params *dma = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);int ret =0 ; +pr_debug ("Entered %s\n" , __func__);/* return if this is a bufferless transfer e.g.
sound/soc/s3c24xx/s3c-i2s-v2.c +8 -5
@@ -333,14 +333,17 @@ static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai_link *dai = rtd->dai;struct s3c_i2sv2_info *i2s =to_info (dai->cpu_dai); +struct s3c_dma_params *dma_data;u32 iismod;pr_debug ("Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - dai->cpu_dai->dma_data = i2s->dma_playback; + dma_data = i2s->dma_playback;else - dai->cpu_dai->dma_data = i2s->dma_capture; + dma_data = i2s->dma_capture; + +snd_soc_dai_set_dma_data (dai->cpu_dai, substream, dma_data);/* Working copies of register */ iismod =readl (i2s->regs +S3C2412_IISMOD );
@@ -372,8 +375,8 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,int capture = (substream->stream ==SNDRV_PCM_STREAM_CAPTURE );unsigned long irqs;int ret =0 ; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);pr_debug ("Entered %s\n" , __func__);
@@ -409,7 +412,7 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,* of the auto reload mechanism of S3C24XX. * This call won't bother S3C64XX. */ -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );break ;
sound/soc/s3c24xx/s3c-pcm.c +5 -2
@@ -178,6 +178,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai_link *dai = rtd->dai;struct s3c_pcm_info *pcm =to_info (dai->cpu_dai); +struct s3c_dma_params *dma_data;void __iomem *regs = pcm->regs;struct clk *clk;int sclk_div, sync_div;
@@ -187,9 +188,11 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,dev_dbg (pcm->dev,"Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - dai->cpu_dai->dma_data = pcm->dma_playback; + dma_data = pcm->dma_playback;else - dai->cpu_dai->dma_data = pcm->dma_capture; + dma_data = pcm->dma_capture; + +snd_soc_dai_set_dma_data (dai->cpu_dai, substream, dma_data);/* Strictly check for sample size */ switch (params_format (params)) {
sound/soc/s3c24xx/s3c2412-i2s.c +5 -2
@@ -151,14 +151,17 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) {struct s3c_i2sv2_info *i2s =to_info (cpu_dai); +struct s3c_dma_params *dma_data;u32 iismod;pr_debug ("Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = i2s->dma_playback; + dma_data = i2s->dma_playback;else - cpu_dai->dma_data = i2s->dma_capture; + dma_data = i2s->dma_capture; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data); iismod =readl (i2s->regs +S3C2412_IISMOD );pr_debug ("%s: r: IISMOD: %x\n" , __func__, iismod);
sound/soc/s3c24xx/s3c24xx-i2s.c +10 -9
@@ -242,14 +242,17 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) {struct snd_soc_pcm_runtime *rtd = substream->private_data; +struct s3c_dma_params *dma_data;u32 iismod;pr_debug ("Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out; + dma_data = &s3c24xx_i2s_pcm_stereo_out;else - rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_in; + dma_data = &s3c24xx_i2s_pcm_stereo_in; + +snd_soc_dai_set_dma_data (rtd->dai->cpu_dai, substream, dma_data);/* Working copies of register */ iismod =readl (s3c24xx_i2s.regs +S3C2410_IISMOD );
@@ -258,13 +261,11 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,switch (params_format (params)) {case SNDRV_PCM_FORMAT_S8 : iismod &= ~S3C2410_IISMOD_16BIT ; - ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size =1 ; + dma_data->dma_size =1 ;break ;case SNDRV_PCM_FORMAT_S16_LE : iismod |=S3C2410_IISMOD_16BIT ; - ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size =2 ; + dma_data->dma_size =2 ;break ;default :return -EINVAL ;
@@ -280,8 +281,8 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, {int ret =0 ;struct snd_soc_pcm_runtime *rtd = substream->private_data; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);pr_debug ("Entered %s\n" , __func__);
@@ -300,7 +301,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,else s3c24xx_snd_txctrl (1 ); -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );break ;case SNDRV_PCM_TRIGGER_STOP :case SNDRV_PCM_TRIGGER_SUSPEND :
sound/soc/s6000/s6000-i2s.c +2 -1
@@ -518,7 +518,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev) s6000_i2s_dai.dev = &pdev->dev; s6000_i2s_dai.private_data = dev; - s6000_i2s_dai.dma_data = &dev->dma_params; + s6000_i2s_dai.capture.dma_data = &dev->dma_params; + s6000_i2s_dai.playback.dma_data = &dev->dma_params; dev->sifbase = sifmem->start; dev->scbbase = mmio;
sound/soc/s6000/s6000-pcm.c +29 -11
@@ -58,13 +58,15 @@ static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream)struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int channel;unsigned int period_size;unsigned int dma_offset;dma_addr_t dma_pos;dma_addr_t src, dst; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); + period_size =snd_pcm_lib_period_bytes (substream); dma_offset = prtd->period * period_size; dma_pos = runtime->dma_addr + dma_offset;
@@ -101,7 +103,8 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data) {struct snd_pcm *pcm = data;struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);struct s6000_runtime_data *prtd;unsigned int has_xrun;int i, ret =IRQ_NONE ;
@@ -172,11 +175,13 @@ static int s6000_pcm_start(struct snd_pcm_substream *substream) {struct s6000_runtime_data *prtd = substream->runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;unsigned long flags;int srcinc;u32 dma; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +spin_lock_irqsave (&prtd->lock, flags);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) {
@@ -212,10 +217,12 @@ static int s6000_pcm_stop(struct snd_pcm_substream *substream) {struct s6000_runtime_data *prtd = substream->runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;unsigned long flags;u32 channel; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) channel = par->dma_out;else
@@ -236,9 +243,11 @@ static int s6000_pcm_stop(struct snd_pcm_substream *substream)static int s6000_pcm_trigger (struct snd_pcm_substream *substream,int cmd) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int ret; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); + ret = par->trigger (substream, cmd,0 );if (ret <0 )return ret;
@@ -275,13 +284,15 @@ static int s6000_pcm_prepare(struct snd_pcm_substream *substream)static snd_pcm_uframes_t s6000_pcm_pointer (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd = runtime->private_data;unsigned long flags;unsigned int offset;dma_addr_t count; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +spin_lock_irqsave (&prtd->lock, flags);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK )
@@ -305,11 +316,12 @@ static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream)static int s6000_pcm_open (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd;int ret; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);snd_soc_set_runtime_hwparams (substream, &s6000_pcm_hardware); ret = snd_pcm_hw_constraint_step(runtime, 0,
@@ -364,7 +376,7 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int ret; ret =snd_pcm_lib_malloc_pages (substream,params_buffer_bytes (hw_params));
@@ -373,6 +385,8 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,return ret; } + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (par->same_rate) {spin_lock (&par->lock); if (par->rate == -1 ||
@@ -392,7 +406,8 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,static int s6000_pcm_hw_free (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);spin_lock (&par->lock); par->in_use &= ~(1 << substream->stream);
@@ -417,7 +432,8 @@ static struct snd_pcm_ops s6000_pcm_ops = {static void s6000_pcm_free (struct snd_pcm *pcm) {struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);free_irq (params->irq, pcm);snd_pcm_lib_preallocate_free_for_all (pcm);
@@ -429,9 +445,11 @@ static int s6000_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm) { struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params;int res; + params =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (!card->dev->dma_mask) card->dev->dma_mask = &s6000_pcm_dmamask;if (!card->dev->coherent_dma_mask)
Signature · 1 line
1.6.6.2
Re: [PATCH] ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
Hello,
Quoted 7 lines · On Thursday 18 March 2010 21:23:58 ext Daniel Mack wrote:
This fixes a memory corruption when ASoC devices are used in full-duplex mode. Specifically for pxa-ssp code, where this pointer is dynamically allocated for each direction and destroyed upon each stream start.
All other platforms are fixed blindly, I couldn't even compile-test them. Sorry for any breakage I may have caused.
At least the OMAP code should not be affected by the bug, that you have with the pxa-ssp. I think the bug could be also fixed within the pxa code, since the whole thing goes down to inconsistent memory management within the pxa code.
Having said that, I do think having separate dma_data for each streams is a really good idea.
One thing that I can think of in OMAP case, where this could fix a nasty race condition is (have never seen it, but it is in theory possible):
Also in duplex case, when the second hw_param gets called after the first omap_mcbsp_hw_params, and before the omap_pcm_hw_params for the first stream. The second omap_mcbsp_hw_params will override the dma_data, thus we would set bogus parameters for the first stream.
I do have comment however (down).
For the omap-mcbsp.c and omap-pcm.c changes:
..
Quoted 24 lines
b/sound/soc/atmel/atmel_ssc_dai.cindex e588e63..0b59806 100644sound/soc/atmel/atmel_ssc_dai.c +1
-2@@ -363,12 +363,12 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ssc_p->dma_params[dir] = dma_params;/* -* The cpu_dai->dma_data field is only used to communicate the -* appropriate DMA parameters to the pcm driver hw_params() +* The snd_soc_pcm_stream->dma_data field is only used to communicate + * the appropriate DMA parameters to the pcm driver
hw_params()* function. It should not be used for other purposes
* as it is common to all substreams.
*/sound/soc/atmel/atmel_ssc_dai.c +1
-1- rtd->dai->cpu_dai->dma_data = dma_params; +snd_soc_dai_set_dma_data (rtd->dai->cpu_dai, substream, dma_params); channels =params_channels (params);(quoted diff) +0
-0
b/sound/soc/davinci/davinci-i2s.cindex 6362ca0..4aad7ec 100644
sound/soc/davinci/davinci-i2s.c static int davinci_i2s_probe(struct platform_device · line 589
Quoted 6 lines
sound/soc/davinci/davinci-i2s.c +2
-1@@ -585,7 +585,8 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start; davinci_i2s_dai.private_data = dev; - davinci_i2s_dai.dma_data = dev->dma_params; + davinci_i2s_dai.capture.dma_data = dev->dma_params; + davinci_i2s_dai.playback.dma_data = dev->dma_params;
Would not be more consistent around the places to actually use the
snd_soc_dai_set_dma_data(...);
function instead of direct assignment here, and there randomly?
Quoted 3 lines
sound/soc/davinci/davinci-i2s.c +0
-0ret =snd_soc_register_dai (&davinci_i2s_dai);if (ret !=0 ) goto err_free_mem;
Signature · 1 line
Péter
Re: [PATCH] ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
Quoted 6 lines · Peter Ujfalusi
Quoted 5 lines · On Thursday 18 March 2010 21:23:58 ext Daniel Mack wrote:
This fixes a memory corruption when ASoC devices are used in full-duplex mode. Specifically for pxa-ssp code, where this pointer is dynamically allocated for each direction and destroyed upon each stream start.
Quoted 6 lines
Quoted 2 lines
All other platforms are fixed blindly, I couldn't even compile-test them. Sorry for any breakage I may have caused.
At least the OMAP code should not be affected by the bug, that you have with the pxa-ssp. I think the bug could be also fixed within the pxa code, since the whole thing goes down to inconsistent memory management within the pxa code.
Maybe OMAP is not affected, but I've seen other platforms that also use this dma_data pointer at many more other callbacks and the code seems to believe the pointer is still set to what has been given in the hw_param call (think it was S6000).
Quoted 8 lines
Having said that, I do think having separate
dma_datafor each streams is a really good idea.
One thing that I can think of in OMAP case, where this could fix a nasty race condition is (have never seen it, but it is in theory possible):
Also in duplex case, when the secondhw_paramgets called after the firstomap_mcbsp_hw_params, and before theomap_pcm_hw_paramsfor the first stream. The secondomap_mcbsp_hw_paramswill override thedma_data, thus we would set bogus parameters for the first stream.
Right.
Quoted 2 lines
For the
omap-mcbsp.candomap-pcm.cchanges:Acked-by Peter Ujfalusi <[email protected]>
Thanks!
Quoted 26 lines
Quoted 26 lines
b/sound/soc/atmel/atmel_ssc_dai.cindex e588e63..0b59806 100644sound/soc/atmel/atmel_ssc_dai.c +1
-2@@ -363,12 +363,12 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ssc_p->dma_params[dir] = dma_params;/* -* The cpu_dai->dma_data field is only used to communicate the -* appropriate DMA parameters to the pcm driver hw_params() +* The snd_soc_pcm_stream->dma_data field is only used to communicate + * the appropriate DMA parameters to the pcm driver
hw_params()* function. It should not be used for other purposes
* as it is common to all substreams.
*/sound/soc/atmel/atmel_ssc_dai.c +1
-1- rtd->dai->cpu_dai->dma_data = dma_params; +snd_soc_dai_set_dma_data (rtd->dai->cpu_dai, substream, dma_params); channels =params_channels (params);(quoted diff) +0
-0
b/sound/soc/davinci/davinci-i2s.cindex 6362ca0..4aad7ec 100644sound/soc/davinci/davinci-i2s.c +0
-0@@ -585,7 +585,8 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
Quoted 8 lines
sound/soc/davinci/davinci-i2s.c static int davinci_i2s_probe(struct platform_device *pdev) · line 589
Quoted 4 lines
sound/soc/davinci/davinci-i2s.c +2
-1davinci_i2s_dai.private_data = dev; - davinci_i2s_dai.dma_data = dev->dma_params; + davinci_i2s_dai.capture.dma_data = dev->dma_params; + davinci_i2s_dai.playback.dma_data = dev->dma_params;Would not be more consistent around the places to actually use the
snd_soc_dai_set_dma_data(...);function instead of direct assignment here, and there randomly?
Sure. Now that this is possible, the davinvi code should be cleaned up. But as I say - I couldn't even compile-test these changes, so I didn't want to break the code flow logic as well. Davinci is special though, other drivers should be more consistent.
Daniel
Re: [PATCH] ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
Quoted 17 lines · Daniel Mack
Quoted 6 lines · Peter Ujfalusi
Quoted 6 lines
b/sound/soc/davinci/davinci-i2s.cindex 6362ca0..4aad7ec 100644sound/soc/davinci/davinci-i2s.c +0
-0@@ -585,7 +585,8 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;Quoted 8 lines
sound/soc/davinci/davinci-i2s.c static int davinci_i2s_probe(struct platform_device *pdev) · line 589
Quoted 4 lines
sound/soc/davinci/davinci-i2s.c +2
-1davinci_i2s_dai.private_data = dev; - davinci_i2s_dai.dma_data = dev->dma_params; + davinci_i2s_dai.capture.dma_data = dev->dma_params; + davinci_i2s_dai.playback.dma_data = dev->dma_params;Would not be more consistent around the places to actually use the
snd_soc_dai_set_dma_data(...);function instead of direct assignment here, and there randomly?
Quoted 4 lines
Sure. Now that this is possible, the davinvi code should be cleaned up. But as I say - I couldn't even compile-test these changes, so I didn't want to break the code flow logic as well. Davinci is special though, other drivers should be more consistent.
I agree with both of you, we can always tidy the code up later but cross platform changes need some sync. I've applied the patch, thanks once again for analysing this and to everyone else for their review.
Re: [PATCH] ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
Quoted 3 lines · Mark Brown
I agree with both of you, we can always tidy the code up later but cross platform changes need some sync. I've applied the patch, thanks once again for analysing this and to everyone else for their review.
Thanks! I assume this is going to be taken for .34 and .35? And how is backporting done - I think we should probably also get this into .33 and .32?
Daniel
Re: [PATCH] ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
Quoted 7 lines · Daniel Mack
Quoted 3 lines · Mark Brown
I agree with both of you, we can always tidy the code up later but cross platform changes need some sync. I've applied the patch, thanks once again for analysing this and to everyone else for their review.
Thanks! I assume this is going to be taken for .34 and .35?
I've applied it for 2.6.35 only at present, I'd rather let it cook for a little before picking it back - like you I can only test a limited set of architectures. Unfortunately it doesn't cherry pick backwards either, but the updates required do appear to be trivial.
Quoted 2 lines
And how is backporting done - I think we should probably also get this into .33 and .32?
CCing [email protected] is trivial but since there are new architectures involved the patch won't trivially apply and someone will need to CC Greg.
Re: [PATCH] ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
Quoted 7 lines · Mark Brown
Quoted 1 line · Daniel Mack
Thanks! I assume this is going to be taken for .34 and .35?
I've applied it for 2.6.35 only at present, I'd rather let it cook for a little before picking it back - like you I can only test a limited set of architectures. Unfortunately it doesn't cherry pick backwards either, but the updates required do appear to be trivial.
Agreed. However, I believe when pushed to .34, it will get greater exposion, and regressions would more likely be found and get fixed. Faster than in your for-2.6.35 branch I mean.
Daniel
Re: [PATCH] ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
Quoted 3 lines · Daniel Mack
Agreed. However, I believe when pushed to .34, it will get greater exposion, and regressions would more likely be found and get fixed. Faster than in your for-2.6.35 branch I mean.
I want it to at least appear in -next for a few days before backporting. That will get a moderate amount of automatic cover, and would make me much more happy about pushing a version for .34. If you want to do the backport to .34 that'd be helpful.
PATCH 1/1 ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
This fixes a memory corruption when ASoC devices are used in full-duplex mode. Specifically for pxa-ssp code, where this pointer is dynamically allocated for each direction and destroyed upon each stream start.
All other platforms are fixed blindly, I couldn't even compile-test them. Sorry for any breakage I may have caused.
---
This is a backported version for 2.6.34.
include/sound/soc-dai.h | 18 +++++++++++++++- include/sound/soc.h | 1 + sound/soc/atmel/atmel-pcm.c | 2 +- sound/soc/atmel/atmel_ssc_dai.c | 6 ++-- sound/soc/davinci/davinci-i2s.c | 3 +- sound/soc/davinci/davinci-mcasp.c | 3 +- sound/soc/davinci/davinci-pcm.c | 4 ++- sound/soc/imx/imx-pcm-dma-mx2.c | 8 +++++- sound/soc/imx/imx-ssi.c | 7 ++++- sound/soc/omap/omap-mcbsp.c | 4 ++- sound/soc/omap/omap-mcpdm.c | 3 +- sound/soc/omap/omap-pcm.c | 4 ++- sound/soc/pxa/pxa-ssp.c | 23 +++++++++++---------- sound/soc/pxa/pxa2xx-ac97.c | 17 +++++++++++---- sound/soc/pxa/pxa2xx-i2s.c | 7 ++++- sound/soc/pxa/pxa2xx-pcm.c | 4 ++- sound/soc/s3c24xx/s3c-ac97.c | 21 +++++++++++-------- sound/soc/s3c24xx/s3c-dma.c | 4 ++- sound/soc/s3c24xx/s3c-i2s-v2.c | 13 +++++++---- sound/soc/s3c24xx/s3c-pcm.c | 7 ++++- sound/soc/s3c24xx/s3c24xx-i2s.c | 19 +++++++++-------- sound/soc/s6000/s6000-i2s.c | 3 +- sound/soc/s6000/s6000-pcm.c | 40 ++++++++++++++++++++++++++---------- 23 files changed, 149 insertions(+), 72 deletions(-)
include/sound/soc-dai.h +17 -1
@@ -219,7 +219,6 @@ struct snd_soc_dai {struct snd_soc_codec *codec;unsigned int active; unsigned char pop_wait:1; -void *dma_data;/* DAI private data */ void *private_data;
@@ -230,4 +229,21 @@ struct snd_soc_dai { struct list_head list; }; +static inline void *snd_soc_dai_get_dma_data (const struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss) +{ +return (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) ? + dai->playback.dma_data : dai->capture.dma_data; +} + +static inline void snd_soc_dai_set_dma_data (struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss, +void *data) +{ +if (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) + dai->playback.dma_data = data; +else + dai->capture.dma_data = data; +} +#endif
include/sound/soc.h +1 -0
@@ -375,6 +375,7 @@ struct snd_soc_pcm_stream {unsigned int channels_min;/* min channels */ unsigned int channels_max;/* max channels */ unsigned int active:1; /* stream is in use */ +void *dma_data;/* used by platform code */ };/* SoC audio ops */
sound/soc/atmel/atmel-pcm.c +1 -1
@@ -180,7 +180,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,snd_pcm_set_runtime_buffer (substream, &substream->dma_buffer); runtime->dma_bytes =params_buffer_bytes (params); - prtd->params = rtd->dai->cpu_dai->dma_data; + prtd->params =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); prtd->params->dma_intr_handler = atmel_pcm_dma_irq; prtd->dma_buffer = runtime->dma_addr;
sound/soc/atmel/atmel_ssc_dai.c +3 -3
@@ -363,12 +363,12 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ssc_p->dma_params[dir] = dma_params;/* -* The cpu_dai->dma_data field is only used to communicate the -* appropriate DMA parameters to the pcm driver hw_params() +* The snd_soc_pcm_stream->dma_data field is only used to communicate +* the appropriate DMA parameters to the pcm driver hw_params() * function. It should not be used for other purposes * as it is common to all substreams. */ - rtd->dai->cpu_dai->dma_data = dma_params; +snd_soc_dai_set_dma_data (rtd->dai->cpu_dai, substream, dma_params); channels =params_channels (params);
sound/soc/davinci/davinci-i2s.c +2 -1
@@ -585,7 +585,8 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev->dma_params[SNDRV_PCM_STREAM_CAPTURE ].channel = res->start; davinci_i2s_dai.private_data = dev; - davinci_i2s_dai.dma_data = dev->dma_params; + davinci_i2s_dai.capture.dma_data = dev->dma_params; + davinci_i2s_dai.playback.dma_data = dev->dma_params; ret =snd_soc_register_dai (&davinci_i2s_dai);if (ret !=0 ) goto err_free_mem;
sound/soc/davinci/davinci-mcasp.c +2 -1
@@ -917,7 +917,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data->channel = res->start; davinci_mcasp_dai[pdata->op_mode].private_data = dev; - davinci_mcasp_dai[pdata->op_mode].dma_data = dev->dma_params; + davinci_mcasp_dai[pdata->op_mode].capture.dma_data = dev->dma_params; + davinci_mcasp_dai[pdata->op_mode].playback.dma_data = dev->dma_params; davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev; ret =snd_soc_register_dai (&davinci_mcasp_dai[pdata->op_mode]);
sound/soc/davinci/davinci-pcm.c +3 -1
@@ -649,8 +649,10 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream)struct snd_pcm_hardware *ppcm;int ret =0 ;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct davinci_pcm_dma_params *pa = rtd->dai->cpu_dai->dma_data; +struct davinci_pcm_dma_params *pa;struct davinci_pcm_dma_params *params; + + pa =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);if (!pa)return -ENODEV ; params = &pa[substream->stream];
sound/soc/imx/imx-pcm-dma-mx2.c +6 -2
@@ -83,11 +83,13 @@ static void snd_imx_dma_err_callback(int channel, void *data, int err)static int imx_ssi_dma_alloc (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; +struct imx_pcm_dma_params *dma_params;struct snd_pcm_runtime *runtime = substream->runtime;struct imx_pcm_runtime_data *iprtd = runtime->private_data;int ret; + dma_params =snd_soc_get_dma_data (rtd->dai->cpu_dai, substream); + iprtd->dma =imx_dma_request_by_prio (DRV_NAME ,DMA_PRIO_HIGH );if (iprtd->dma <0 ) {pr_err ("Failed to claim the audio DMA\n" );
@@ -192,10 +194,12 @@ static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) {struct snd_pcm_runtime *runtime = substream->runtime;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; +struct imx_pcm_dma_params *dma_params;struct imx_pcm_runtime_data *iprtd = runtime->private_data;int err; + dma_params =snd_soc_get_dma_data (rtd->dai->cpu_dai, substream); + iprtd->substream = substream; iprtd->buf = (unsigned int *)substream->dma_buffer.area; iprtd->period_cnt =0 ;
sound/soc/imx/imx-ssi.c +5 -2
@@ -234,17 +234,20 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) {struct imx_ssi *ssi = cpu_dai->private_data; +struct imx_pcm_dma_params *dma_data;u32 reg, sccr;/* Tx/Rx config */ if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) { reg =SSI_STCCR ; - cpu_dai->dma_data = &ssi->dma_params_tx; + dma_data = &ssi->dma_params_tx; }else { reg =SSI_SRCCR ; - cpu_dai->dma_data = &ssi->dma_params_rx; + dma_data = &ssi->dma_params_rx; } +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data); + sccr =readl (ssi->base + reg) & ~SSI_STCCR_WL_MASK ;/* DAI data (word) size */
sound/soc/omap/omap-mcbsp.c +3 -1
@@ -297,7 +297,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; omap_mcbsp_dai_dma_params[id][substream->stream].data_type =OMAP_DMA_DATA_TYPE_S16 ; - cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; + +snd_soc_dai_set_dma_data (cpu_dai, substream, + &omap_mcbsp_dai_dma_params[id][substream->stream]);if (mcbsp_data->configured) {/* McBSP already configured by another stream */
sound/soc/omap/omap-mcpdm.c +2 -1
@@ -150,7 +150,8 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,int stream = substream->stream;int channels, err, link_mask =0 ; - cpu_dai->dma_data = &omap_mcpdm_dai_dma_params[stream]; +snd_soc_dai_set_dma_data (cpu_dai, substream, + &omap_mcpdm_dai_dma_params[stream]); channels =params_channels (params);switch (channels) {
sound/soc/omap/omap-pcm.c +3 -1
@@ -100,9 +100,11 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct snd_soc_pcm_runtime *rtd = substream->private_data;struct omap_runtime_data *prtd = runtime->private_data; -struct omap_pcm_dma_data *dma_data = rtd->dai->cpu_dai->dma_data; +struct omap_pcm_dma_data *dma_data;int err =0 ; + dma_data =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); +/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma_data)
sound/soc/pxa/pxa-ssp.c +12 -11
@@ -121,10 +121,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,ssp_disable (ssp); } -if (cpu_dai->dma_data) { -kfree (cpu_dai->dma_data); - cpu_dai->dma_data =NULL ; - } +kfree (snd_soc_dai_get_dma_data (cpu_dai, substream)); +snd_soc_dai_set_dma_data (cpu_dai, substream,NULL ); +return ret; }
@@ -141,10 +140,8 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,clk_disable (ssp->clk); } -if (cpu_dai->dma_data) { -kfree (cpu_dai->dma_data); - cpu_dai->dma_data =NULL ; - } +kfree (snd_soc_dai_get_dma_data (cpu_dai, substream)); +snd_soc_dai_set_dma_data (cpu_dai, substream,NULL ); }#ifdef CONFIG_PM
@@ -569,19 +566,23 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,u32 sspsp;int width =snd_pcm_format_physical_width (params_format (params));int ttsa =ssp_read_reg (ssp,SSTSA ) &0xf ; +struct pxa2xx_pcm_dma_params *dma_data; + + dma_data =snd_soc_dai_get_dma_data (dai, substream);/* generate correct DMA params */ -if (cpu_dai->dma_data) -kfree (cpu_dai->dma_data); +kfree (dma_data);/* Network mode with one active slot (ttsa == 1) can be used * to force 16-bit frame width on the wire (for S16_LE), even * with two channels. Use 16-bit DMA transfers for this case. */ - cpu_dai->dma_data =ssp_get_dma_params (ssp, + dma_data =ssp_get_dma_params (ssp, ((chn ==2 ) && (ttsa !=1 )) || (width ==32 ), substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ); +snd_soc_dai_set_dma_data (dai, substream, dma_data); +/* we can only change the settings if the port is not in use */ if (ssp_read_reg (ssp,SSCR0 ) &SSCR0_SSE )return 0 ;
sound/soc/pxa/pxa2xx-ac97.c +12 -5
@@ -122,11 +122,14 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; + dma_data = &pxa2xx_ac97_pcm_stereo_out;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_in; + dma_data = &pxa2xx_ac97_pcm_stereo_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);return 0 ; }
@@ -137,11 +140,14 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; + dma_data = &pxa2xx_ac97_pcm_aux_mono_out;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);return 0 ; }
@@ -156,7 +162,8 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK )return -ENODEV ;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_mic_mono_in; +snd_soc_dai_set_dma_data (cpu_dai, substream, + &pxa2xx_ac97_pcm_mic_mono_in);return 0 ; }
sound/soc/pxa/pxa2xx-i2s.c +5 -2
@@ -164,6 +164,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;BUG_ON (IS_ERR (clk_i2s));clk_enable (clk_i2s);
@@ -171,9 +172,11 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,pxa_i2s_wait ();if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out; + dma_data = &pxa2xx_i2s_pcm_stereo_out;else - cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in; + dma_data = &pxa2xx_i2s_pcm_stereo_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);/* is port used by another stream */ if (!(SACR0 &SACR0_ENB )) {
sound/soc/pxa/pxa2xx-pcm.c +3 -1
@@ -25,9 +25,11 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct pxa2xx_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; +struct pxa2xx_pcm_dma_params *dma;int ret; + dma =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); +/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma)
sound/soc/s3c24xx/s3c-ac97.c +12 -9
@@ -224,11 +224,14 @@ static int s3c_ac97_hw_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct s3c_dma_params *dma_data;if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &s3c_ac97_pcm_out; + dma_data = &s3c_ac97_pcm_out;else - cpu_dai->dma_data = &s3c_ac97_pcm_in; + dma_data = &s3c_ac97_pcm_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);return 0 ; }
@@ -238,8 +241,8 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, {u32 ac_glbctrl;struct snd_soc_pcm_runtime *rtd = substream->private_data; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); ac_glbctrl =readl (s3c_ac97.regs +S3C_AC97_GLBCTRL );if (substream->stream ==SNDRV_PCM_STREAM_CAPTURE )
@@ -265,7 +268,7 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,writel (ac_glbctrl, s3c_ac97.regs +S3C_AC97_GLBCTRL ); -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );return 0 ; }
@@ -280,7 +283,7 @@ static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream,if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK )return -ENODEV ;else - cpu_dai->dma_data = &s3c_ac97_mic_in; +snd_soc_dai_set_dma_data (cpu_dai, substream, &s3c_ac97_mic_in);return 0 ; }
@@ -290,8 +293,8 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, {u32 ac_glbctrl;struct snd_soc_pcm_runtime *rtd = substream->private_data; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); ac_glbctrl =readl (s3c_ac97.regs +S3C_AC97_GLBCTRL ); ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK ;
@@ -311,7 +314,7 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,writel (ac_glbctrl, s3c_ac97.regs +S3C_AC97_GLBCTRL ); -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );return 0 ; }
sound/soc/s3c24xx/s3c-dma.c +3 -1
@@ -145,10 +145,12 @@ static int s3c_dma_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct s3c24xx_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct s3c_dma_params *dma = rtd->dai->cpu_dai->dma_data;unsigned long totbytes =params_buffer_bytes (params); +struct s3c_dma_params *dma = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);int ret =0 ; +pr_debug ("Entered %s\n" , __func__);/* return if this is a bufferless transfer e.g.
sound/soc/s3c24xx/s3c-i2s-v2.c +8 -5
@@ -339,14 +339,17 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai_link *dai = rtd->dai;struct s3c_i2sv2_info *i2s =to_info (dai->cpu_dai); +struct s3c_dma_params *dma_data;u32 iismod;pr_debug ("Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - dai->cpu_dai->dma_data = i2s->dma_playback; + dma_data = i2s->dma_playback;else - dai->cpu_dai->dma_data = i2s->dma_capture; + dma_data = i2s->dma_capture; + +snd_soc_dai_set_dma_data (dai->cpu_dai, substream, dma_data);/* Working copies of register */ iismod =readl (i2s->regs +S3C2412_IISMOD );
@@ -394,8 +397,8 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,int capture = (substream->stream ==SNDRV_PCM_STREAM_CAPTURE );unsigned long irqs;int ret =0 ; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);pr_debug ("Entered %s\n" , __func__);
@@ -431,7 +434,7 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,* of the auto reload mechanism of S3C24XX. * This call won't bother S3C64XX. */ -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );break ;
sound/soc/s3c24xx/s3c-pcm.c +5 -2
@@ -178,6 +178,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai_link *dai = rtd->dai;struct s3c_pcm_info *pcm =to_info (dai->cpu_dai); +struct s3c_dma_params *dma_data;void __iomem *regs = pcm->regs;struct clk *clk;int sclk_div, sync_div;
@@ -187,9 +188,11 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,dev_dbg (pcm->dev,"Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - dai->cpu_dai->dma_data = pcm->dma_playback; + dma_data = pcm->dma_playback;else - dai->cpu_dai->dma_data = pcm->dma_capture; + dma_data = pcm->dma_capture; + +snd_soc_dai_set_dma_data (dai->cpu_dai, substream, dma_data);/* Strictly check for sample size */ switch (params_format (params)) {
sound/soc/s3c24xx/s3c24xx-i2s.c +10 -9
@@ -242,14 +242,17 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) {struct snd_soc_pcm_runtime *rtd = substream->private_data; +struct s3c_dma_params *dma_data;u32 iismod;pr_debug ("Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out; + dma_data = &s3c24xx_i2s_pcm_stereo_out;else - rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_in; + dma_data = &s3c24xx_i2s_pcm_stereo_in; + +snd_soc_dai_set_dma_data (rtd->dai->cpu_dai, substream, dma_data);/* Working copies of register */ iismod =readl (s3c24xx_i2s.regs +S3C2410_IISMOD );
@@ -258,13 +261,11 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,switch (params_format (params)) {case SNDRV_PCM_FORMAT_S8 : iismod &= ~S3C2410_IISMOD_16BIT ; - ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size =1 ; + dma_data->dma_size =1 ;break ;case SNDRV_PCM_FORMAT_S16_LE : iismod |=S3C2410_IISMOD_16BIT ; - ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size =2 ; + dma_data->dma_size =2 ;break ;default :return -EINVAL ;
@@ -280,8 +281,8 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, {int ret =0 ;struct snd_soc_pcm_runtime *rtd = substream->private_data; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);pr_debug ("Entered %s\n" , __func__);
@@ -300,7 +301,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,else s3c24xx_snd_txctrl (1 ); -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );break ;case SNDRV_PCM_TRIGGER_STOP :case SNDRV_PCM_TRIGGER_SUSPEND :
sound/soc/s6000/s6000-i2s.c +2 -1
@@ -518,7 +518,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev) s6000_i2s_dai.dev = &pdev->dev; s6000_i2s_dai.private_data = dev; - s6000_i2s_dai.dma_data = &dev->dma_params; + s6000_i2s_dai.capture.dma_data = &dev->dma_params; + s6000_i2s_dai.playback.dma_data = &dev->dma_params; dev->sifbase = sifmem->start; dev->scbbase = mmio;
sound/soc/s6000/s6000-pcm.c +29 -11
@@ -58,13 +58,15 @@ static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream)struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int channel;unsigned int period_size;unsigned int dma_offset;dma_addr_t dma_pos;dma_addr_t src, dst; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); + period_size =snd_pcm_lib_period_bytes (substream); dma_offset = prtd->period * period_size; dma_pos = runtime->dma_addr + dma_offset;
@@ -101,7 +103,8 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data) {struct snd_pcm *pcm = data;struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);struct s6000_runtime_data *prtd;unsigned int has_xrun;int i, ret =IRQ_NONE ;
@@ -172,11 +175,13 @@ static int s6000_pcm_start(struct snd_pcm_substream *substream) {struct s6000_runtime_data *prtd = substream->runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;unsigned long flags;int srcinc;u32 dma; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +spin_lock_irqsave (&prtd->lock, flags);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) {
@@ -212,10 +217,12 @@ static int s6000_pcm_stop(struct snd_pcm_substream *substream) {struct s6000_runtime_data *prtd = substream->runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;unsigned long flags;u32 channel; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) channel = par->dma_out;else
@@ -236,9 +243,11 @@ static int s6000_pcm_stop(struct snd_pcm_substream *substream)static int s6000_pcm_trigger (struct snd_pcm_substream *substream,int cmd) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int ret; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); + ret = par->trigger (substream, cmd,0 );if (ret <0 )return ret;
@@ -275,13 +284,15 @@ static int s6000_pcm_prepare(struct snd_pcm_substream *substream)static snd_pcm_uframes_t s6000_pcm_pointer (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd = runtime->private_data;unsigned long flags;unsigned int offset;dma_addr_t count; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +spin_lock_irqsave (&prtd->lock, flags);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK )
@@ -305,11 +316,12 @@ static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream)static int s6000_pcm_open (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd;int ret; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);snd_soc_set_runtime_hwparams (substream, &s6000_pcm_hardware); ret = snd_pcm_hw_constraint_step(runtime, 0,
@@ -364,7 +376,7 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int ret; ret =snd_pcm_lib_malloc_pages (substream,params_buffer_bytes (hw_params));
@@ -373,6 +385,8 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,return ret; } + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (par->same_rate) {spin_lock (&par->lock); if (par->rate == -1 ||
@@ -392,7 +406,8 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,static int s6000_pcm_hw_free (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);spin_lock (&par->lock); par->in_use &= ~(1 << substream->stream);
@@ -417,7 +432,8 @@ static struct snd_pcm_ops s6000_pcm_ops = {static void s6000_pcm_free (struct snd_pcm *pcm) {struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);free_irq (params->irq, pcm);snd_pcm_lib_preallocate_free_for_all (pcm);
@@ -429,9 +445,11 @@ static int s6000_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm) { struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params;int res; + params =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (!card->dev->dma_mask) card->dev->dma_mask = &s6000_pcm_dmamask;if (!card->dev->coherent_dma_mask)
Signature · 1 line
1.7.0
Re: [PATCH] ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
Quoted 1 line · Daniel Mack
This is a backported version for 2.6.34.
You really should say this a little more obviously as part of the changelog, preferably referencing the master commit as well.
PATCH 1/1 ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
This fixes a memory corruption when ASoC devices are used in full-duplex mode. Specifically for pxa-ssp code, where this pointer is dynamically allocated for each direction and destroyed upon each stream start.
All other platforms are fixed blindly, I couldn't even compile-test them. Sorry for any breakage I may have caused.
[Note that this is a backported version for 2.6.33.
Upstream commit is fd23b7dee]
--- include/sound/soc-dai.h | 18 +++++++++++++++- include/sound/soc.h | 1 + sound/soc/atmel/atmel-pcm.c | 2 +- sound/soc/atmel/atmel_ssc_dai.c | 6 ++-- sound/soc/davinci/davinci-i2s.c | 3 +- sound/soc/davinci/davinci-mcasp.c | 3 +- sound/soc/davinci/davinci-pcm.c | 4 ++- sound/soc/omap/omap-mcbsp.c | 4 ++- sound/soc/omap/omap-pcm.c | 4 ++- sound/soc/pxa/pxa-ssp.c | 23 +++++++++++---------- sound/soc/pxa/pxa2xx-ac97.c | 17 +++++++++++---- sound/soc/pxa/pxa2xx-i2s.c | 7 ++++- sound/soc/pxa/pxa2xx-pcm.c | 4 ++- sound/soc/s3c24xx/s3c-dma.c | 4 ++- sound/soc/s3c24xx/s3c-i2s-v2.c | 13 +++++++---- sound/soc/s3c24xx/s3c-pcm.c | 7 ++++- sound/soc/s3c24xx/s3c24xx-i2s.c | 19 +++++++++-------- sound/soc/s6000/s6000-i2s.c | 3 +- sound/soc/s6000/s6000-pcm.c | 40 ++++++++++++++++++++++++++---------- 19 files changed, 124 insertions(+), 58 deletions(-)
include/sound/soc-dai.h +17 -1
@@ -217,7 +217,6 @@ struct snd_soc_dai {struct snd_soc_codec *codec;unsigned int active; unsigned char pop_wait:1; -void *dma_data;/* DAI private data */ void *private_data;
@@ -228,4 +227,21 @@ struct snd_soc_dai { struct list_head list; }; +static inline void *snd_soc_dai_get_dma_data (const struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss) +{ +return (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) ? + dai->playback.dma_data : dai->capture.dma_data; +} + +static inline void snd_soc_dai_set_dma_data (struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss, +void *data) +{ +if (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) + dai->playback.dma_data = data; +else + dai->capture.dma_data = data; +} +#endif
include/sound/soc.h +1 -0
@@ -355,6 +355,7 @@ struct snd_soc_pcm_stream {unsigned int channels_min;/* min channels */ unsigned int channels_max;/* max channels */ unsigned int active:1; /* stream is in use */ +void *dma_data;/* used by platform code */ };/* SoC audio ops */
sound/soc/atmel/atmel-pcm.c +1 -1
@@ -180,7 +180,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,snd_pcm_set_runtime_buffer (substream, &substream->dma_buffer); runtime->dma_bytes =params_buffer_bytes (params); - prtd->params = rtd->dai->cpu_dai->dma_data; + prtd->params =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); prtd->params->dma_intr_handler = atmel_pcm_dma_irq; prtd->dma_buffer = runtime->dma_addr;
sound/soc/atmel/atmel_ssc_dai.c +3 -3
@@ -363,12 +363,12 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ssc_p->dma_params[dir] = dma_params;/* -* The cpu_dai->dma_data field is only used to communicate the -* appropriate DMA parameters to the pcm driver hw_params() +* The snd_soc_pcm_stream->dma_data field is only used to communicate +* the appropriate DMA parameters to the pcm driver hw_params() * function. It should not be used for other purposes * as it is common to all substreams. */ - rtd->dai->cpu_dai->dma_data = dma_params; +snd_soc_dai_set_dma_data (rtd->dai->cpu_dai, substream, dma_params); channels =params_channels (params);
sound/soc/davinci/davinci-i2s.c +2 -1
@@ -585,7 +585,8 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev->dma_params[SNDRV_PCM_STREAM_CAPTURE ].channel = res->start; davinci_i2s_dai.private_data = dev; - davinci_i2s_dai.dma_data = dev->dma_params; + davinci_i2s_dai.capture.dma_data = dev->dma_params; + davinci_i2s_dai.playback.dma_data = dev->dma_params; ret =snd_soc_register_dai (&davinci_i2s_dai);if (ret !=0 ) goto err_free_mem;
sound/soc/davinci/davinci-mcasp.c +2 -1
@@ -904,7 +904,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data->channel = res->start; davinci_mcasp_dai[pdata->op_mode].private_data = dev; - davinci_mcasp_dai[pdata->op_mode].dma_data = dev->dma_params; + davinci_mcasp_dai[pdata->op_mode].capture.dma_data = dev->dma_params; + davinci_mcasp_dai[pdata->op_mode].playback.dma_data = dev->dma_params; davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev; ret =snd_soc_register_dai (&davinci_mcasp_dai[pdata->op_mode]);
sound/soc/davinci/davinci-pcm.c +3 -1
@@ -649,8 +649,10 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream)struct snd_pcm_hardware *ppcm;int ret =0 ;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct davinci_pcm_dma_params *pa = rtd->dai->cpu_dai->dma_data; +struct davinci_pcm_dma_params *pa;struct davinci_pcm_dma_params *params; + + pa =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);if (!pa)return -ENODEV ; params = &pa[substream->stream];
sound/soc/omap/omap-mcbsp.c +3 -1
@@ -287,7 +287,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; - cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; + +snd_soc_dai_set_dma_data (cpu_dai, substream, + &omap_mcbsp_dai_dma_params[id][substream->stream]);if (mcbsp_data->configured) {/* McBSP already configured by another stream */
sound/soc/omap/omap-pcm.c +3 -1
@@ -99,9 +99,11 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct snd_soc_pcm_runtime *rtd = substream->private_data;struct omap_runtime_data *prtd = runtime->private_data; -struct omap_pcm_dma_data *dma_data = rtd->dai->cpu_dai->dma_data; +struct omap_pcm_dma_data *dma_data;int err =0 ; + dma_data =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); +/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma_data)
sound/soc/pxa/pxa-ssp.c +12 -11
@@ -103,10 +103,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,ssp_disable (&priv->dev); } -if (cpu_dai->dma_data) { -kfree (cpu_dai->dma_data); - cpu_dai->dma_data =NULL ; - } +kfree (snd_soc_dai_get_dma_data (cpu_dai, substream)); +snd_soc_dai_set_dma_data (cpu_dai, substream,NULL ); +return ret; }
@@ -122,10 +121,8 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,clk_disable (priv->dev.ssp->clk); } -if (cpu_dai->dma_data) { -kfree (cpu_dai->dma_data); - cpu_dai->dma_data =NULL ; - } +kfree (snd_soc_dai_get_dma_data (cpu_dai, substream)); +snd_soc_dai_set_dma_data (cpu_dai, substream,NULL ); }#ifdef CONFIG_PM
@@ -536,19 +533,23 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,u32 sspsp;int width =snd_pcm_format_physical_width (params_format (params));int ttsa =ssp_read_reg (ssp,SSTSA ) &0xf ; +struct pxa2xx_pcm_dma_params *dma_data; + + dma_data =snd_soc_dai_get_dma_data (dai, substream);/* generate correct DMA params */ -if (cpu_dai->dma_data) -kfree (cpu_dai->dma_data); +kfree (dma_data);/* Network mode with one active slot (ttsa == 1) can be used * to force 16-bit frame width on the wire (for S16_LE), even * with two channels. Use 16-bit DMA transfers for this case. */ - cpu_dai->dma_data =ssp_get_dma_params (ssp, + dma_data =ssp_get_dma_params (ssp, ((chn ==2 ) && (ttsa !=1 )) || (width ==32 ), substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ); +snd_soc_dai_set_dma_data (dai, substream, dma_data); +/* we can only change the settings if the port is not in use */ if (ssp_read_reg (ssp,SSCR0 ) &SSCR0_SSE )return 0 ;
sound/soc/pxa/pxa2xx-ac97.c +12 -5
@@ -122,11 +122,14 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; + dma_data = &pxa2xx_ac97_pcm_stereo_out;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_in; + dma_data = &pxa2xx_ac97_pcm_stereo_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);return 0 ; }
@@ -137,11 +140,14 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; + dma_data = &pxa2xx_ac97_pcm_aux_mono_out;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);return 0 ; }
@@ -156,7 +162,8 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK )return -ENODEV ;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_mic_mono_in; +snd_soc_dai_set_dma_data (cpu_dai, substream, + &pxa2xx_ac97_pcm_mic_mono_in);return 0 ; }
sound/soc/pxa/pxa2xx-i2s.c +5 -2
@@ -164,6 +164,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;BUG_ON (IS_ERR (clk_i2s));clk_enable (clk_i2s);
@@ -171,9 +172,11 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,pxa_i2s_wait ();if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out; + dma_data = &pxa2xx_i2s_pcm_stereo_out;else - cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in; + dma_data = &pxa2xx_i2s_pcm_stereo_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);/* is port used by another stream */ if (!(SACR0 &SACR0_ENB )) {
sound/soc/pxa/pxa2xx-pcm.c +3 -1
@@ -25,9 +25,11 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct pxa2xx_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; +struct pxa2xx_pcm_dma_params *dma;int ret; + dma =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); +/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma)
sound/soc/s3c24xx/s3c-dma.c +3 -1
@@ -145,10 +145,12 @@ static int s3c_dma_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct s3c24xx_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct s3c_dma_params *dma = rtd->dai->cpu_dai->dma_data;unsigned long totbytes =params_buffer_bytes (params); +struct s3c_dma_params *dma = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);int ret =0 ; +pr_debug ("Entered %s\n" , __func__);/* return if this is a bufferless transfer e.g.
sound/soc/s3c24xx/s3c-i2s-v2.c +8 -5
@@ -339,14 +339,17 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai_link *dai = rtd->dai;struct s3c_i2sv2_info *i2s =to_info (dai->cpu_dai); +struct s3c_dma_params *dma_data;u32 iismod;pr_debug ("Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - dai->cpu_dai->dma_data = i2s->dma_playback; + dma_data = i2s->dma_playback;else - dai->cpu_dai->dma_data = i2s->dma_capture; + dma_data = i2s->dma_capture; + +snd_soc_dai_set_dma_data (dai->cpu_dai, substream, dma_data);/* Working copies of register */ iismod =readl (i2s->regs +S3C2412_IISMOD );
@@ -394,8 +397,8 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,int capture = (substream->stream ==SNDRV_PCM_STREAM_CAPTURE );unsigned long irqs;int ret =0 ; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);pr_debug ("Entered %s\n" , __func__);
@@ -431,7 +434,7 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,* of the auto reload mechanism of S3C24XX. * This call won't bother S3C64XX. */ -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );break ;
sound/soc/s3c24xx/s3c-pcm.c +5 -2
@@ -178,6 +178,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai_link *dai = rtd->dai;struct s3c_pcm_info *pcm =to_info (dai->cpu_dai); +struct s3c_dma_params *dma_data;void __iomem *regs = pcm->regs;struct clk *clk;int sclk_div, sync_div;
@@ -187,9 +188,11 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,dev_dbg (pcm->dev,"Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - dai->cpu_dai->dma_data = pcm->dma_playback; + dma_data = pcm->dma_playback;else - dai->cpu_dai->dma_data = pcm->dma_capture; + dma_data = pcm->dma_capture; + +snd_soc_dai_set_dma_data (dai->cpu_dai, substream, dma_data);/* Strictly check for sample size */ switch (params_format (params)) {
sound/soc/s3c24xx/s3c24xx-i2s.c +10 -9
@@ -242,14 +242,17 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) {struct snd_soc_pcm_runtime *rtd = substream->private_data; +struct s3c_dma_params *dma_data;u32 iismod;pr_debug ("Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out; + dma_data = &s3c24xx_i2s_pcm_stereo_out;else - rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_in; + dma_data = &s3c24xx_i2s_pcm_stereo_in; + +snd_soc_dai_set_dma_data (rtd->dai->cpu_dai, substream, dma_data);/* Working copies of register */ iismod =readl (s3c24xx_i2s.regs +S3C2410_IISMOD );
@@ -258,13 +261,11 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,switch (params_format (params)) {case SNDRV_PCM_FORMAT_S8 : iismod &= ~S3C2410_IISMOD_16BIT ; - ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size =1 ; + dma_data->dma_size =1 ;break ;case SNDRV_PCM_FORMAT_S16_LE : iismod |=S3C2410_IISMOD_16BIT ; - ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size =2 ; + dma_data->dma_size =2 ;break ;default :return -EINVAL ;
@@ -280,8 +281,8 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, {int ret =0 ;struct snd_soc_pcm_runtime *rtd = substream->private_data; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);pr_debug ("Entered %s\n" , __func__);
@@ -300,7 +301,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,else s3c24xx_snd_txctrl (1 ); -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );break ;case SNDRV_PCM_TRIGGER_STOP :case SNDRV_PCM_TRIGGER_SUSPEND :
sound/soc/s6000/s6000-i2s.c +2 -1
@@ -518,7 +518,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev) s6000_i2s_dai.dev = &pdev->dev; s6000_i2s_dai.private_data = dev; - s6000_i2s_dai.dma_data = &dev->dma_params; + s6000_i2s_dai.capture.dma_data = &dev->dma_params; + s6000_i2s_dai.playback.dma_data = &dev->dma_params; dev->sifbase = sifmem->start; dev->scbbase = mmio;
sound/soc/s6000/s6000-pcm.c +29 -11
@@ -58,13 +58,15 @@ static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream)struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int channel;unsigned int period_size;unsigned int dma_offset;dma_addr_t dma_pos;dma_addr_t src, dst; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); + period_size =snd_pcm_lib_period_bytes (substream); dma_offset = prtd->period * period_size; dma_pos = runtime->dma_addr + dma_offset;
@@ -101,7 +103,8 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data) {struct snd_pcm *pcm = data;struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);struct s6000_runtime_data *prtd;unsigned int has_xrun;int i, ret =IRQ_NONE ;
@@ -172,11 +175,13 @@ static int s6000_pcm_start(struct snd_pcm_substream *substream) {struct s6000_runtime_data *prtd = substream->runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;unsigned long flags;int srcinc;u32 dma; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +spin_lock_irqsave (&prtd->lock, flags);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) {
@@ -212,10 +217,12 @@ static int s6000_pcm_stop(struct snd_pcm_substream *substream) {struct s6000_runtime_data *prtd = substream->runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;unsigned long flags;u32 channel; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) channel = par->dma_out;else
@@ -236,9 +243,11 @@ static int s6000_pcm_stop(struct snd_pcm_substream *substream)static int s6000_pcm_trigger (struct snd_pcm_substream *substream,int cmd) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int ret; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); + ret = par->trigger (substream, cmd,0 );if (ret <0 )return ret;
@@ -275,13 +284,15 @@ static int s6000_pcm_prepare(struct snd_pcm_substream *substream)static snd_pcm_uframes_t s6000_pcm_pointer (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd = runtime->private_data;unsigned long flags;unsigned int offset;dma_addr_t count; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +spin_lock_irqsave (&prtd->lock, flags);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK )
@@ -305,11 +316,12 @@ static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream)static int s6000_pcm_open (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd;int ret; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);snd_soc_set_runtime_hwparams (substream, &s6000_pcm_hardware); ret = snd_pcm_hw_constraint_step(runtime, 0,
@@ -364,7 +376,7 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int ret; ret =snd_pcm_lib_malloc_pages (substream,params_buffer_bytes (hw_params));
@@ -373,6 +385,8 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,return ret; } + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (par->same_rate) {spin_lock (&par->lock); if (par->rate == -1 ||
@@ -392,7 +406,8 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,static int s6000_pcm_hw_free (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);spin_lock (&par->lock); par->in_use &= ~(1 << substream->stream);
@@ -417,7 +432,8 @@ static struct snd_pcm_ops s6000_pcm_ops = {static void s6000_pcm_free (struct snd_pcm *pcm) {struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);free_irq (params->irq, pcm);snd_pcm_lib_preallocate_free_for_all (pcm);
@@ -429,9 +445,11 @@ static int s6000_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm) { struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params;int res; + params =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (!card->dev->dma_mask) card->dev->dma_mask = &s6000_pcm_dmamask;if (!card->dev->coherent_dma_mask)
Signature · 1 line
1.7.0
PATCH 1/1 ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
In reply to Mark BrownThis fixes a memory corruption when ASoC devices are used in full-duplex mode. Specifically for pxa-ssp code, where this pointer is dynamically allocated for each direction and destroyed upon each stream start.
All other platforms are fixed blindly, I couldn't even compile-test them. Sorry for any breakage I may have caused.
[Note that this is a backported version for 2.6.34.
Upstream commit is fd23b7dee]
--- include/sound/soc-dai.h | 18 +++++++++++++++- include/sound/soc.h | 1 + sound/soc/atmel/atmel-pcm.c | 2 +- sound/soc/atmel/atmel_ssc_dai.c | 6 ++-- sound/soc/davinci/davinci-i2s.c | 3 +- sound/soc/davinci/davinci-mcasp.c | 3 +- sound/soc/davinci/davinci-pcm.c | 4 ++- sound/soc/imx/imx-pcm-dma-mx2.c | 8 +++++- sound/soc/imx/imx-ssi.c | 7 ++++- sound/soc/omap/omap-mcbsp.c | 4 ++- sound/soc/omap/omap-mcpdm.c | 3 +- sound/soc/omap/omap-pcm.c | 4 ++- sound/soc/pxa/pxa-ssp.c | 23 +++++++++++---------- sound/soc/pxa/pxa2xx-ac97.c | 17 +++++++++++---- sound/soc/pxa/pxa2xx-i2s.c | 7 ++++- sound/soc/pxa/pxa2xx-pcm.c | 4 ++- sound/soc/s3c24xx/s3c-ac97.c | 21 +++++++++++-------- sound/soc/s3c24xx/s3c-dma.c | 4 ++- sound/soc/s3c24xx/s3c-i2s-v2.c | 13 +++++++---- sound/soc/s3c24xx/s3c-pcm.c | 7 ++++- sound/soc/s3c24xx/s3c24xx-i2s.c | 19 +++++++++-------- sound/soc/s6000/s6000-i2s.c | 3 +- sound/soc/s6000/s6000-pcm.c | 40 ++++++++++++++++++++++++++---------- 23 files changed, 149 insertions(+), 72 deletions(-)
include/sound/soc-dai.h +17 -1
@@ -219,7 +219,6 @@ struct snd_soc_dai {struct snd_soc_codec *codec;unsigned int active; unsigned char pop_wait:1; -void *dma_data;/* DAI private data */ void *private_data;
@@ -230,4 +229,21 @@ struct snd_soc_dai { struct list_head list; }; +static inline void *snd_soc_dai_get_dma_data (const struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss) +{ +return (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) ? + dai->playback.dma_data : dai->capture.dma_data; +} + +static inline void snd_soc_dai_set_dma_data (struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss, +void *data) +{ +if (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) + dai->playback.dma_data = data; +else + dai->capture.dma_data = data; +} +#endif
include/sound/soc.h +1 -0
@@ -375,6 +375,7 @@ struct snd_soc_pcm_stream {unsigned int channels_min;/* min channels */ unsigned int channels_max;/* max channels */ unsigned int active:1; /* stream is in use */ +void *dma_data;/* used by platform code */ };/* SoC audio ops */
sound/soc/atmel/atmel-pcm.c +1 -1
@@ -180,7 +180,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,snd_pcm_set_runtime_buffer (substream, &substream->dma_buffer); runtime->dma_bytes =params_buffer_bytes (params); - prtd->params = rtd->dai->cpu_dai->dma_data; + prtd->params =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); prtd->params->dma_intr_handler = atmel_pcm_dma_irq; prtd->dma_buffer = runtime->dma_addr;
sound/soc/atmel/atmel_ssc_dai.c +3 -3
@@ -363,12 +363,12 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ssc_p->dma_params[dir] = dma_params;/* -* The cpu_dai->dma_data field is only used to communicate the -* appropriate DMA parameters to the pcm driver hw_params() +* The snd_soc_pcm_stream->dma_data field is only used to communicate +* the appropriate DMA parameters to the pcm driver hw_params() * function. It should not be used for other purposes * as it is common to all substreams. */ - rtd->dai->cpu_dai->dma_data = dma_params; +snd_soc_dai_set_dma_data (rtd->dai->cpu_dai, substream, dma_params); channels =params_channels (params);
sound/soc/davinci/davinci-i2s.c +2 -1
@@ -585,7 +585,8 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev->dma_params[SNDRV_PCM_STREAM_CAPTURE ].channel = res->start; davinci_i2s_dai.private_data = dev; - davinci_i2s_dai.dma_data = dev->dma_params; + davinci_i2s_dai.capture.dma_data = dev->dma_params; + davinci_i2s_dai.playback.dma_data = dev->dma_params; ret =snd_soc_register_dai (&davinci_i2s_dai);if (ret !=0 ) goto err_free_mem;
sound/soc/davinci/davinci-mcasp.c +2 -1
@@ -917,7 +917,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data->channel = res->start; davinci_mcasp_dai[pdata->op_mode].private_data = dev; - davinci_mcasp_dai[pdata->op_mode].dma_data = dev->dma_params; + davinci_mcasp_dai[pdata->op_mode].capture.dma_data = dev->dma_params; + davinci_mcasp_dai[pdata->op_mode].playback.dma_data = dev->dma_params; davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev; ret =snd_soc_register_dai (&davinci_mcasp_dai[pdata->op_mode]);
sound/soc/davinci/davinci-pcm.c +3 -1
@@ -649,8 +649,10 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream)struct snd_pcm_hardware *ppcm;int ret =0 ;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct davinci_pcm_dma_params *pa = rtd->dai->cpu_dai->dma_data; +struct davinci_pcm_dma_params *pa;struct davinci_pcm_dma_params *params; + + pa =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);if (!pa)return -ENODEV ; params = &pa[substream->stream];
sound/soc/imx/imx-pcm-dma-mx2.c +6 -2
@@ -83,11 +83,13 @@ static void snd_imx_dma_err_callback(int channel, void *data, int err)static int imx_ssi_dma_alloc (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; +struct imx_pcm_dma_params *dma_params;struct snd_pcm_runtime *runtime = substream->runtime;struct imx_pcm_runtime_data *iprtd = runtime->private_data;int ret; + dma_params =snd_soc_get_dma_data (rtd->dai->cpu_dai, substream); + iprtd->dma =imx_dma_request_by_prio (DRV_NAME ,DMA_PRIO_HIGH );if (iprtd->dma <0 ) {pr_err ("Failed to claim the audio DMA\n" );
@@ -192,10 +194,12 @@ static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) {struct snd_pcm_runtime *runtime = substream->runtime;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; +struct imx_pcm_dma_params *dma_params;struct imx_pcm_runtime_data *iprtd = runtime->private_data;int err; + dma_params =snd_soc_get_dma_data (rtd->dai->cpu_dai, substream); + iprtd->substream = substream; iprtd->buf = (unsigned int *)substream->dma_buffer.area; iprtd->period_cnt =0 ;
sound/soc/imx/imx-ssi.c +5 -2
@@ -234,17 +234,20 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) {struct imx_ssi *ssi = cpu_dai->private_data; +struct imx_pcm_dma_params *dma_data;u32 reg, sccr;/* Tx/Rx config */ if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) { reg =SSI_STCCR ; - cpu_dai->dma_data = &ssi->dma_params_tx; + dma_data = &ssi->dma_params_tx; }else { reg =SSI_SRCCR ; - cpu_dai->dma_data = &ssi->dma_params_rx; + dma_data = &ssi->dma_params_rx; } +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data); + sccr =readl (ssi->base + reg) & ~SSI_STCCR_WL_MASK ;/* DAI data (word) size */
sound/soc/omap/omap-mcbsp.c +3 -1
@@ -297,7 +297,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; omap_mcbsp_dai_dma_params[id][substream->stream].data_type =OMAP_DMA_DATA_TYPE_S16 ; - cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; + +snd_soc_dai_set_dma_data (cpu_dai, substream, + &omap_mcbsp_dai_dma_params[id][substream->stream]);if (mcbsp_data->configured) {/* McBSP already configured by another stream */
sound/soc/omap/omap-mcpdm.c +2 -1
@@ -150,7 +150,8 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,int stream = substream->stream;int channels, err, link_mask =0 ; - cpu_dai->dma_data = &omap_mcpdm_dai_dma_params[stream]; +snd_soc_dai_set_dma_data (cpu_dai, substream, + &omap_mcpdm_dai_dma_params[stream]); channels =params_channels (params);switch (channels) {
sound/soc/omap/omap-pcm.c +3 -1
@@ -100,9 +100,11 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct snd_soc_pcm_runtime *rtd = substream->private_data;struct omap_runtime_data *prtd = runtime->private_data; -struct omap_pcm_dma_data *dma_data = rtd->dai->cpu_dai->dma_data; +struct omap_pcm_dma_data *dma_data;int err =0 ; + dma_data =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); +/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma_data)
sound/soc/pxa/pxa-ssp.c +12 -11
@@ -121,10 +121,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,ssp_disable (ssp); } -if (cpu_dai->dma_data) { -kfree (cpu_dai->dma_data); - cpu_dai->dma_data =NULL ; - } +kfree (snd_soc_dai_get_dma_data (cpu_dai, substream)); +snd_soc_dai_set_dma_data (cpu_dai, substream,NULL ); +return ret; }
@@ -141,10 +140,8 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,clk_disable (ssp->clk); } -if (cpu_dai->dma_data) { -kfree (cpu_dai->dma_data); - cpu_dai->dma_data =NULL ; - } +kfree (snd_soc_dai_get_dma_data (cpu_dai, substream)); +snd_soc_dai_set_dma_data (cpu_dai, substream,NULL ); }#ifdef CONFIG_PM
@@ -569,19 +566,23 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,u32 sspsp;int width =snd_pcm_format_physical_width (params_format (params));int ttsa =ssp_read_reg (ssp,SSTSA ) &0xf ; +struct pxa2xx_pcm_dma_params *dma_data; + + dma_data =snd_soc_dai_get_dma_data (dai, substream);/* generate correct DMA params */ -if (cpu_dai->dma_data) -kfree (cpu_dai->dma_data); +kfree (dma_data);/* Network mode with one active slot (ttsa == 1) can be used * to force 16-bit frame width on the wire (for S16_LE), even * with two channels. Use 16-bit DMA transfers for this case. */ - cpu_dai->dma_data =ssp_get_dma_params (ssp, + dma_data =ssp_get_dma_params (ssp, ((chn ==2 ) && (ttsa !=1 )) || (width ==32 ), substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ); +snd_soc_dai_set_dma_data (dai, substream, dma_data); +/* we can only change the settings if the port is not in use */ if (ssp_read_reg (ssp,SSCR0 ) &SSCR0_SSE )return 0 ;
sound/soc/pxa/pxa2xx-ac97.c +12 -5
@@ -122,11 +122,14 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; + dma_data = &pxa2xx_ac97_pcm_stereo_out;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_in; + dma_data = &pxa2xx_ac97_pcm_stereo_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);return 0 ; }
@@ -137,11 +140,14 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; + dma_data = &pxa2xx_ac97_pcm_aux_mono_out;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);return 0 ; }
@@ -156,7 +162,8 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK )return -ENODEV ;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_mic_mono_in; +snd_soc_dai_set_dma_data (cpu_dai, substream, + &pxa2xx_ac97_pcm_mic_mono_in);return 0 ; }
sound/soc/pxa/pxa2xx-i2s.c +5 -2
@@ -164,6 +164,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;BUG_ON (IS_ERR (clk_i2s));clk_enable (clk_i2s);
@@ -171,9 +172,11 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,pxa_i2s_wait ();if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out; + dma_data = &pxa2xx_i2s_pcm_stereo_out;else - cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in; + dma_data = &pxa2xx_i2s_pcm_stereo_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);/* is port used by another stream */ if (!(SACR0 &SACR0_ENB )) {
sound/soc/pxa/pxa2xx-pcm.c +3 -1
@@ -25,9 +25,11 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct pxa2xx_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; +struct pxa2xx_pcm_dma_params *dma;int ret; + dma =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); +/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma)
sound/soc/s3c24xx/s3c-ac97.c +12 -9
@@ -224,11 +224,14 @@ static int s3c_ac97_hw_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct s3c_dma_params *dma_data;if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &s3c_ac97_pcm_out; + dma_data = &s3c_ac97_pcm_out;else - cpu_dai->dma_data = &s3c_ac97_pcm_in; + dma_data = &s3c_ac97_pcm_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);return 0 ; }
@@ -238,8 +241,8 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, {u32 ac_glbctrl;struct snd_soc_pcm_runtime *rtd = substream->private_data; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); ac_glbctrl =readl (s3c_ac97.regs +S3C_AC97_GLBCTRL );if (substream->stream ==SNDRV_PCM_STREAM_CAPTURE )
@@ -265,7 +268,7 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,writel (ac_glbctrl, s3c_ac97.regs +S3C_AC97_GLBCTRL ); -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );return 0 ; }
@@ -280,7 +283,7 @@ static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream,if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK )return -ENODEV ;else - cpu_dai->dma_data = &s3c_ac97_mic_in; +snd_soc_dai_set_dma_data (cpu_dai, substream, &s3c_ac97_mic_in);return 0 ; }
@@ -290,8 +293,8 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, {u32 ac_glbctrl;struct snd_soc_pcm_runtime *rtd = substream->private_data; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); ac_glbctrl =readl (s3c_ac97.regs +S3C_AC97_GLBCTRL ); ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK ;
@@ -311,7 +314,7 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,writel (ac_glbctrl, s3c_ac97.regs +S3C_AC97_GLBCTRL ); -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );return 0 ; }
sound/soc/s3c24xx/s3c-dma.c +3 -1
@@ -145,10 +145,12 @@ static int s3c_dma_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct s3c24xx_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct s3c_dma_params *dma = rtd->dai->cpu_dai->dma_data;unsigned long totbytes =params_buffer_bytes (params); +struct s3c_dma_params *dma = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);int ret =0 ; +pr_debug ("Entered %s\n" , __func__);/* return if this is a bufferless transfer e.g.
sound/soc/s3c24xx/s3c-i2s-v2.c +8 -5
@@ -339,14 +339,17 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai_link *dai = rtd->dai;struct s3c_i2sv2_info *i2s =to_info (dai->cpu_dai); +struct s3c_dma_params *dma_data;u32 iismod;pr_debug ("Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - dai->cpu_dai->dma_data = i2s->dma_playback; + dma_data = i2s->dma_playback;else - dai->cpu_dai->dma_data = i2s->dma_capture; + dma_data = i2s->dma_capture; + +snd_soc_dai_set_dma_data (dai->cpu_dai, substream, dma_data);/* Working copies of register */ iismod =readl (i2s->regs +S3C2412_IISMOD );
@@ -394,8 +397,8 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,int capture = (substream->stream ==SNDRV_PCM_STREAM_CAPTURE );unsigned long irqs;int ret =0 ; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);pr_debug ("Entered %s\n" , __func__);
@@ -431,7 +434,7 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,* of the auto reload mechanism of S3C24XX. * This call won't bother S3C64XX. */ -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );break ;
sound/soc/s3c24xx/s3c-pcm.c +5 -2
@@ -178,6 +178,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai_link *dai = rtd->dai;struct s3c_pcm_info *pcm =to_info (dai->cpu_dai); +struct s3c_dma_params *dma_data;void __iomem *regs = pcm->regs;struct clk *clk;int sclk_div, sync_div;
@@ -187,9 +188,11 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,dev_dbg (pcm->dev,"Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - dai->cpu_dai->dma_data = pcm->dma_playback; + dma_data = pcm->dma_playback;else - dai->cpu_dai->dma_data = pcm->dma_capture; + dma_data = pcm->dma_capture; + +snd_soc_dai_set_dma_data (dai->cpu_dai, substream, dma_data);/* Strictly check for sample size */ switch (params_format (params)) {
sound/soc/s3c24xx/s3c24xx-i2s.c +10 -9
@@ -242,14 +242,17 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) {struct snd_soc_pcm_runtime *rtd = substream->private_data; +struct s3c_dma_params *dma_data;u32 iismod;pr_debug ("Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out; + dma_data = &s3c24xx_i2s_pcm_stereo_out;else - rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_in; + dma_data = &s3c24xx_i2s_pcm_stereo_in; + +snd_soc_dai_set_dma_data (rtd->dai->cpu_dai, substream, dma_data);/* Working copies of register */ iismod =readl (s3c24xx_i2s.regs +S3C2410_IISMOD );
@@ -258,13 +261,11 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,switch (params_format (params)) {case SNDRV_PCM_FORMAT_S8 : iismod &= ~S3C2410_IISMOD_16BIT ; - ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size =1 ; + dma_data->dma_size =1 ;break ;case SNDRV_PCM_FORMAT_S16_LE : iismod |=S3C2410_IISMOD_16BIT ; - ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size =2 ; + dma_data->dma_size =2 ;break ;default :return -EINVAL ;
@@ -280,8 +281,8 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, {int ret =0 ;struct snd_soc_pcm_runtime *rtd = substream->private_data; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);pr_debug ("Entered %s\n" , __func__);
@@ -300,7 +301,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,else s3c24xx_snd_txctrl (1 ); -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );break ;case SNDRV_PCM_TRIGGER_STOP :case SNDRV_PCM_TRIGGER_SUSPEND :
sound/soc/s6000/s6000-i2s.c +2 -1
@@ -518,7 +518,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev) s6000_i2s_dai.dev = &pdev->dev; s6000_i2s_dai.private_data = dev; - s6000_i2s_dai.dma_data = &dev->dma_params; + s6000_i2s_dai.capture.dma_data = &dev->dma_params; + s6000_i2s_dai.playback.dma_data = &dev->dma_params; dev->sifbase = sifmem->start; dev->scbbase = mmio;
sound/soc/s6000/s6000-pcm.c +29 -11
@@ -58,13 +58,15 @@ static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream)struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int channel;unsigned int period_size;unsigned int dma_offset;dma_addr_t dma_pos;dma_addr_t src, dst; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); + period_size =snd_pcm_lib_period_bytes (substream); dma_offset = prtd->period * period_size; dma_pos = runtime->dma_addr + dma_offset;
@@ -101,7 +103,8 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data) {struct snd_pcm *pcm = data;struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);struct s6000_runtime_data *prtd;unsigned int has_xrun;int i, ret =IRQ_NONE ;
@@ -172,11 +175,13 @@ static int s6000_pcm_start(struct snd_pcm_substream *substream) {struct s6000_runtime_data *prtd = substream->runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;unsigned long flags;int srcinc;u32 dma; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +spin_lock_irqsave (&prtd->lock, flags);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) {
@@ -212,10 +217,12 @@ static int s6000_pcm_stop(struct snd_pcm_substream *substream) {struct s6000_runtime_data *prtd = substream->runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;unsigned long flags;u32 channel; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) channel = par->dma_out;else
@@ -236,9 +243,11 @@ static int s6000_pcm_stop(struct snd_pcm_substream *substream)static int s6000_pcm_trigger (struct snd_pcm_substream *substream,int cmd) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int ret; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); + ret = par->trigger (substream, cmd,0 );if (ret <0 )return ret;
@@ -275,13 +284,15 @@ static int s6000_pcm_prepare(struct snd_pcm_substream *substream)static snd_pcm_uframes_t s6000_pcm_pointer (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd = runtime->private_data;unsigned long flags;unsigned int offset;dma_addr_t count; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +spin_lock_irqsave (&prtd->lock, flags);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK )
@@ -305,11 +316,12 @@ static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream)static int s6000_pcm_open (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd;int ret; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);snd_soc_set_runtime_hwparams (substream, &s6000_pcm_hardware); ret = snd_pcm_hw_constraint_step(runtime, 0,
@@ -364,7 +376,7 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int ret; ret =snd_pcm_lib_malloc_pages (substream,params_buffer_bytes (hw_params));
@@ -373,6 +385,8 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,return ret; } + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (par->same_rate) {spin_lock (&par->lock); if (par->rate == -1 ||
@@ -392,7 +406,8 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,static int s6000_pcm_hw_free (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);spin_lock (&par->lock); par->in_use &= ~(1 << substream->stream);
@@ -417,7 +432,8 @@ static struct snd_pcm_ops s6000_pcm_ops = {static void s6000_pcm_free (struct snd_pcm *pcm) {struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);free_irq (params->irq, pcm);snd_pcm_lib_preallocate_free_for_all (pcm);
@@ -429,9 +445,11 @@ static int s6000_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm) { struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params;int res; + params =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (!card->dev->dma_mask) card->dev->dma_mask = &s6000_pcm_dmamask;if (!card->dev->coherent_dma_mask)
Signature · 1 line
1.7.0
PATCH 1/1 ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
In reply to Mark BrownThis fixes a memory corruption when ASoC devices are used in full-duplex mode. Specifically for pxa-ssp code, where this pointer is dynamically allocated for each direction and destroyed upon each stream start.
All other platforms are fixed blindly, I couldn't even compile-test them. Sorry for any breakage I may have caused.
[Note that this is a backported version for 2.6.32.
Upstream commit is fd23b7dee]
--- include/sound/soc-dai.h | 18 +++++++++++++++- include/sound/soc.h | 1 + sound/soc/atmel/atmel-pcm.c | 2 +- sound/soc/atmel/atmel_ssc_dai.c | 6 ++-- sound/soc/davinci/davinci-i2s.c | 2 + sound/soc/davinci/davinci-mcasp.c | 2 + sound/soc/davinci/davinci-pcm.c | 10 ++++++-- sound/soc/omap/omap-mcbsp.c | 4 ++- sound/soc/omap/omap-pcm.c | 4 ++- sound/soc/pxa/pxa-ssp.c | 23 +++++++++++---------- sound/soc/pxa/pxa2xx-ac97.c | 17 +++++++++++---- sound/soc/pxa/pxa2xx-i2s.c | 7 ++++- sound/soc/pxa/pxa2xx-pcm.c | 4 ++- sound/soc/s3c24xx/s3c-i2s-v2.c | 13 +++++++---- sound/soc/s3c24xx/s3c24xx-i2s.c | 19 +++++++++-------- sound/soc/s6000/s6000-i2s.c | 3 +- sound/soc/s6000/s6000-pcm.c | 40 ++++++++++++++++++++++++++---------- 17 files changed, 120 insertions(+), 55 deletions(-)
include/sound/soc-dai.h +17 -1
@@ -209,7 +209,6 @@ struct snd_soc_dai {struct snd_soc_codec *codec;unsigned int active; unsigned char pop_wait:1; -void *dma_data;/* DAI private data */ void *private_data;
@@ -220,4 +219,21 @@ struct snd_soc_dai { struct list_head list; }; +static inline void *snd_soc_dai_get_dma_data (const struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss) +{ +return (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) ? + dai->playback.dma_data : dai->capture.dma_data; +} + +static inline void snd_soc_dai_set_dma_data (struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss, +void *data) +{ +if (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) + dai->playback.dma_data = data; +else + dai->capture.dma_data = data; +} +#endif
include/sound/soc.h +1 -0
@@ -353,6 +353,7 @@ struct snd_soc_pcm_stream {unsigned int channels_min;/* min channels */ unsigned int channels_max;/* max channels */ unsigned int active:1; /* stream is in use */ +void *dma_data;/* used by platform code */ };/* SoC audio ops */
sound/soc/atmel/atmel-pcm.c +1 -1
@@ -180,7 +180,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,snd_pcm_set_runtime_buffer (substream, &substream->dma_buffer); runtime->dma_bytes =params_buffer_bytes (params); - prtd->params = rtd->dai->cpu_dai->dma_data; + prtd->params =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); prtd->params->dma_intr_handler = atmel_pcm_dma_irq; prtd->dma_buffer = runtime->dma_addr;
sound/soc/atmel/atmel_ssc_dai.c +3 -3
@@ -363,12 +363,12 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ssc_p->dma_params[dir] = dma_params;/* -* The cpu_dai->dma_data field is only used to communicate the -* appropriate DMA parameters to the pcm driver hw_params() +* The snd_soc_pcm_stream->dma_data field is only used to communicate +* the appropriate DMA parameters to the pcm driver hw_params() * function. It should not be used for other purposes * as it is common to all substreams. */ - rtd->dai->cpu_dai->dma_data = dma_params; +snd_soc_dai_set_dma_data (rtd->dai->cpu_dai, substream, dma_params); channels =params_channels (params);
sound/soc/davinci/davinci-i2s.c +2 -0
@@ -547,6 +547,8 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev->dma_params[SNDRV_PCM_STREAM_CAPTURE ].channel = res->start; davinci_i2s_dai.private_data = dev; + davinci_i2s_dai.capture.dma_data = dev->dma_params; + davinci_i2s_dai.playback.dma_data = dev->dma_params; ret =snd_soc_register_dai (&davinci_i2s_dai);if (ret !=0 ) goto err_free_mem;
sound/soc/davinci/davinci-mcasp.c +2 -0
@@ -907,6 +907,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data->channel = res->start; davinci_mcasp_dai[pdata->op_mode].private_data = dev; + davinci_mcasp_dai[pdata->op_mode].capture.dma_data = dev->dma_params; + davinci_mcasp_dai[pdata->op_mode].playback.dma_data = dev->dma_params; davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev; ret =snd_soc_register_dai (&davinci_mcasp_dai[pdata->op_mode]);
sound/soc/davinci/davinci-pcm.c +7 -3
@@ -238,11 +238,15 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream)struct davinci_runtime_data *prtd;int ret =0 ;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct davinci_pcm_dma_params *pa = rtd->dai->cpu_dai->private_data; -struct davinci_pcm_dma_params *params = &pa[substream->stream]; -if (!params) +struct davinci_pcm_dma_params *pa; +struct davinci_pcm_dma_params *params; + + pa =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); +if (!pa)return -ENODEV ; + params = &pa[substream->stream]; +snd_soc_set_runtime_hwparams (substream, &davinci_pcm_hardware);/* ensure that buffer size is a multiple of period size */ ret = snd_pcm_hw_constraint_integer(runtime,
sound/soc/omap/omap-mcbsp.c +3 -1
@@ -285,7 +285,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; - cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; + +snd_soc_dai_set_dma_data (cpu_dai, substream, + &omap_mcbsp_dai_dma_params[id][substream->stream]);if (mcbsp_data->configured) {/* McBSP already configured by another stream */
sound/soc/omap/omap-pcm.c +3 -1
@@ -99,9 +99,11 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct snd_soc_pcm_runtime *rtd = substream->private_data;struct omap_runtime_data *prtd = runtime->private_data; -struct omap_pcm_dma_data *dma_data = rtd->dai->cpu_dai->dma_data; +struct omap_pcm_dma_data *dma_data;int err =0 ; + dma_data =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); +/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma_data)
sound/soc/pxa/pxa-ssp.c +12 -11
@@ -103,10 +103,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,ssp_disable (&priv->dev); } -if (cpu_dai->dma_data) { -kfree (cpu_dai->dma_data); - cpu_dai->dma_data =NULL ; - } +kfree (snd_soc_dai_get_dma_data (cpu_dai, substream)); +snd_soc_dai_set_dma_data (cpu_dai, substream,NULL ); +return ret; }
@@ -122,10 +121,8 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,clk_disable (priv->dev.ssp->clk); } -if (cpu_dai->dma_data) { -kfree (cpu_dai->dma_data); - cpu_dai->dma_data =NULL ; - } +kfree (snd_soc_dai_get_dma_data (cpu_dai, substream)); +snd_soc_dai_set_dma_data (cpu_dai, substream,NULL ); }#ifdef CONFIG_PM
@@ -536,19 +533,23 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,u32 sspsp;int width =snd_pcm_format_physical_width (params_format (params));int ttsa =ssp_read_reg (ssp,SSTSA ) &0xf ; +struct pxa2xx_pcm_dma_params *dma_data; + + dma_data =snd_soc_dai_get_dma_data (dai, substream);/* generate correct DMA params */ -if (cpu_dai->dma_data) -kfree (cpu_dai->dma_data); +kfree (dma_data);/* Network mode with one active slot (ttsa == 1) can be used * to force 16-bit frame width on the wire (for S16_LE), even * with two channels. Use 16-bit DMA transfers for this case. */ - cpu_dai->dma_data =ssp_get_dma_params (ssp, + dma_data =ssp_get_dma_params (ssp, ((chn ==2 ) && (ttsa !=1 )) || (width ==32 ), substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ); +snd_soc_dai_set_dma_data (dai, substream, dma_data); +/* we can only change the settings if the port is not in use */ if (ssp_read_reg (ssp,SSCR0 ) &SSCR0_SSE )return 0 ;
sound/soc/pxa/pxa2xx-ac97.c +12 -5
@@ -122,11 +122,14 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; + dma_data = &pxa2xx_ac97_pcm_stereo_out;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_in; + dma_data = &pxa2xx_ac97_pcm_stereo_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);return 0 ; }
@@ -137,11 +140,14 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; + dma_data = &pxa2xx_ac97_pcm_aux_mono_out;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);return 0 ; }
@@ -156,7 +162,8 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK )return -ENODEV ;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_mic_mono_in; +snd_soc_dai_set_dma_data (cpu_dai, substream, + &pxa2xx_ac97_pcm_mic_mono_in);return 0 ; }
sound/soc/pxa/pxa2xx-i2s.c +5 -2
@@ -164,6 +164,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;BUG_ON (IS_ERR (clk_i2s));clk_enable (clk_i2s);
@@ -171,9 +172,11 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,pxa_i2s_wait ();if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out; + dma_data = &pxa2xx_i2s_pcm_stereo_out;else - cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in; + dma_data = &pxa2xx_i2s_pcm_stereo_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);/* is port used by another stream */ if (!(SACR0 &SACR0_ENB )) {
sound/soc/pxa/pxa2xx-pcm.c +3 -1
@@ -25,9 +25,11 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct pxa2xx_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; +struct pxa2xx_pcm_dma_params *dma;int ret; + dma =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); +/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma)
sound/soc/s3c24xx/s3c-i2s-v2.c +8 -5
@@ -337,14 +337,17 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai_link *dai = rtd->dai;struct s3c_i2sv2_info *i2s =to_info (dai->cpu_dai); +struct s3c_dma_params *dma_data;u32 iismod;pr_debug ("Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - dai->cpu_dai->dma_data = i2s->dma_playback; + dma_data = i2s->dma_playback;else - dai->cpu_dai->dma_data = i2s->dma_capture; + dma_data = i2s->dma_capture; + +snd_soc_dai_set_dma_data (dai->cpu_dai, substream, dma_data);/* Working copies of register */ iismod =readl (i2s->regs +S3C2412_IISMOD );
@@ -392,8 +395,8 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,int capture = (substream->stream ==SNDRV_PCM_STREAM_CAPTURE );unsigned long irqs;int ret =0 ; -int channel = ((struct s3c24xx_pcm_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);pr_debug ("Entered %s\n" , __func__);
@@ -429,7 +432,7 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,* of the auto reload mechanism of S3C24XX. * This call won't bother S3C64XX. */ -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );break ;
sound/soc/s3c24xx/s3c24xx-i2s.c +10 -9
@@ -242,14 +242,17 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) {struct snd_soc_pcm_runtime *rtd = substream->private_data; +struct s3c_dma_params *dma_data;u32 iismod;pr_debug ("Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out; + dma_data = &s3c24xx_i2s_pcm_stereo_out;else - rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_in; + dma_data = &s3c24xx_i2s_pcm_stereo_in; + +snd_soc_dai_set_dma_data (rtd->dai->cpu_dai, substream, dma_data);/* Working copies of register */ iismod =readl (s3c24xx_i2s.regs +S3C2410_IISMOD );
@@ -258,13 +261,11 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,switch (params_format (params)) {case SNDRV_PCM_FORMAT_S8 : iismod &= ~S3C2410_IISMOD_16BIT ; - ((struct s3c24xx_pcm_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size =1 ; + dma_data->dma_size =1 ;break ;case SNDRV_PCM_FORMAT_S16_LE : iismod |=S3C2410_IISMOD_16BIT ; - ((struct s3c24xx_pcm_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size =2 ; + dma_data->dma_size =2 ;break ;default :return -EINVAL ;
@@ -280,8 +281,8 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, {int ret =0 ;struct snd_soc_pcm_runtime *rtd = substream->private_data; -int channel = ((struct s3c24xx_pcm_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);pr_debug ("Entered %s\n" , __func__);
@@ -300,7 +301,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,else s3c24xx_snd_txctrl (1 ); -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );break ;case SNDRV_PCM_TRIGGER_STOP :case SNDRV_PCM_TRIGGER_SUSPEND :
sound/soc/s6000/s6000-i2s.c +2 -1
@@ -518,7 +518,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev) s6000_i2s_dai.dev = &pdev->dev; s6000_i2s_dai.private_data = dev; - s6000_i2s_dai.dma_data = &dev->dma_params; + s6000_i2s_dai.capture.dma_data = &dev->dma_params; + s6000_i2s_dai.playback.dma_data = &dev->dma_params; dev->sifbase = sifmem->start; dev->scbbase = mmio;
sound/soc/s6000/s6000-pcm.c +29 -11
@@ -58,13 +58,15 @@ static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream)struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int channel;unsigned int period_size;unsigned int dma_offset;dma_addr_t dma_pos;dma_addr_t src, dst; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); + period_size =snd_pcm_lib_period_bytes (substream); dma_offset = prtd->period * period_size; dma_pos = runtime->dma_addr + dma_offset;
@@ -101,7 +103,8 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data) {struct snd_pcm *pcm = data;struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);struct s6000_runtime_data *prtd;unsigned int has_xrun;int i, ret =IRQ_NONE ;
@@ -172,11 +175,13 @@ static int s6000_pcm_start(struct snd_pcm_substream *substream) {struct s6000_runtime_data *prtd = substream->runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;unsigned long flags;int srcinc;u32 dma; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +spin_lock_irqsave (&prtd->lock, flags);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) {
@@ -212,10 +217,12 @@ static int s6000_pcm_stop(struct snd_pcm_substream *substream) {struct s6000_runtime_data *prtd = substream->runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;unsigned long flags;u32 channel; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) channel = par->dma_out;else
@@ -236,9 +243,11 @@ static int s6000_pcm_stop(struct snd_pcm_substream *substream)static int s6000_pcm_trigger (struct snd_pcm_substream *substream,int cmd) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int ret; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); + ret = par->trigger (substream, cmd,0 );if (ret <0 )return ret;
@@ -275,13 +284,15 @@ static int s6000_pcm_prepare(struct snd_pcm_substream *substream)static snd_pcm_uframes_t s6000_pcm_pointer (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd = runtime->private_data;unsigned long flags;unsigned int offset;dma_addr_t count; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +spin_lock_irqsave (&prtd->lock, flags);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK )
@@ -305,11 +316,12 @@ static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream)static int s6000_pcm_open (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd;int ret; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);snd_soc_set_runtime_hwparams (substream, &s6000_pcm_hardware); ret = snd_pcm_hw_constraint_step(runtime, 0,
@@ -364,7 +376,7 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int ret; ret =snd_pcm_lib_malloc_pages (substream,params_buffer_bytes (hw_params));
@@ -373,6 +385,8 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,return ret; } + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (par->same_rate) {spin_lock (&par->lock); if (par->rate == -1 ||
@@ -392,7 +406,8 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,static int s6000_pcm_hw_free (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);spin_lock (&par->lock); par->in_use &= ~(1 << substream->stream);
@@ -417,7 +432,8 @@ static struct snd_pcm_ops s6000_pcm_ops = {static void s6000_pcm_free (struct snd_pcm *pcm) {struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);free_irq (params->irq, pcm);snd_pcm_lib_preallocate_free_for_all (pcm);
@@ -429,9 +445,11 @@ static int s6000_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm) { struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params;int res; + params =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (!card->dev->dma_mask) card->dev->dma_mask = &s6000_pcm_dmamask;if (!card->dev->coherent_dma_mask)
Signature · 1 line
1.7.0.3
PATCH 1/1 ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
In reply to Mark BrownThis fixes a memory corruption when ASoC devices are used in full-duplex mode. Specifically for pxa-ssp code, where this pointer is dynamically allocated for each direction and destroyed upon each stream start.
All other platforms are fixed blindly, I couldn't even compile-test them. Sorry for any breakage I may have caused.
---
This is a backported version for 2.6.33.
include/sound/soc-dai.h | 18 +++++++++++++++- include/sound/soc.h | 1 + sound/soc/atmel/atmel-pcm.c | 2 +- sound/soc/atmel/atmel_ssc_dai.c | 6 ++-- sound/soc/davinci/davinci-i2s.c | 3 +- sound/soc/davinci/davinci-mcasp.c | 3 +- sound/soc/davinci/davinci-pcm.c | 4 ++- sound/soc/omap/omap-mcbsp.c | 4 ++- sound/soc/omap/omap-pcm.c | 4 ++- sound/soc/pxa/pxa-ssp.c | 23 +++++++++++---------- sound/soc/pxa/pxa2xx-ac97.c | 17 +++++++++++---- sound/soc/pxa/pxa2xx-i2s.c | 7 ++++- sound/soc/pxa/pxa2xx-pcm.c | 4 ++- sound/soc/s3c24xx/s3c-dma.c | 4 ++- sound/soc/s3c24xx/s3c-i2s-v2.c | 13 +++++++---- sound/soc/s3c24xx/s3c-pcm.c | 7 ++++- sound/soc/s3c24xx/s3c24xx-i2s.c | 19 +++++++++-------- sound/soc/s6000/s6000-i2s.c | 3 +- sound/soc/s6000/s6000-pcm.c | 40 ++++++++++++++++++++++++++---------- 19 files changed, 124 insertions(+), 58 deletions(-)
include/sound/soc-dai.h +17 -1
@@ -217,7 +217,6 @@ struct snd_soc_dai {struct snd_soc_codec *codec;unsigned int active; unsigned char pop_wait:1; -void *dma_data;/* DAI private data */ void *private_data;
@@ -228,4 +227,21 @@ struct snd_soc_dai { struct list_head list; }; +static inline void *snd_soc_dai_get_dma_data (const struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss) +{ +return (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) ? + dai->playback.dma_data : dai->capture.dma_data; +} + +static inline void snd_soc_dai_set_dma_data (struct snd_soc_dai *dai, +const struct snd_pcm_substream *ss, +void *data) +{ +if (ss->stream ==SNDRV_PCM_STREAM_PLAYBACK ) + dai->playback.dma_data = data; +else + dai->capture.dma_data = data; +} +#endif
include/sound/soc.h +1 -0
@@ -355,6 +355,7 @@ struct snd_soc_pcm_stream {unsigned int channels_min;/* min channels */ unsigned int channels_max;/* max channels */ unsigned int active:1; /* stream is in use */ +void *dma_data;/* used by platform code */ };/* SoC audio ops */
sound/soc/atmel/atmel-pcm.c +1 -1
@@ -180,7 +180,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,snd_pcm_set_runtime_buffer (substream, &substream->dma_buffer); runtime->dma_bytes =params_buffer_bytes (params); - prtd->params = rtd->dai->cpu_dai->dma_data; + prtd->params =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); prtd->params->dma_intr_handler = atmel_pcm_dma_irq; prtd->dma_buffer = runtime->dma_addr;
sound/soc/atmel/atmel_ssc_dai.c +3 -3
@@ -363,12 +363,12 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ssc_p->dma_params[dir] = dma_params;/* -* The cpu_dai->dma_data field is only used to communicate the -* appropriate DMA parameters to the pcm driver hw_params() +* The snd_soc_pcm_stream->dma_data field is only used to communicate +* the appropriate DMA parameters to the pcm driver hw_params() * function. It should not be used for other purposes * as it is common to all substreams. */ - rtd->dai->cpu_dai->dma_data = dma_params; +snd_soc_dai_set_dma_data (rtd->dai->cpu_dai, substream, dma_params); channels =params_channels (params);
sound/soc/davinci/davinci-i2s.c +2 -1
@@ -585,7 +585,8 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev->dma_params[SNDRV_PCM_STREAM_CAPTURE ].channel = res->start; davinci_i2s_dai.private_data = dev; - davinci_i2s_dai.dma_data = dev->dma_params; + davinci_i2s_dai.capture.dma_data = dev->dma_params; + davinci_i2s_dai.playback.dma_data = dev->dma_params; ret =snd_soc_register_dai (&davinci_i2s_dai);if (ret !=0 ) goto err_free_mem;
sound/soc/davinci/davinci-mcasp.c +2 -1
@@ -904,7 +904,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data->channel = res->start; davinci_mcasp_dai[pdata->op_mode].private_data = dev; - davinci_mcasp_dai[pdata->op_mode].dma_data = dev->dma_params; + davinci_mcasp_dai[pdata->op_mode].capture.dma_data = dev->dma_params; + davinci_mcasp_dai[pdata->op_mode].playback.dma_data = dev->dma_params; davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev; ret =snd_soc_register_dai (&davinci_mcasp_dai[pdata->op_mode]);
sound/soc/davinci/davinci-pcm.c +3 -1
@@ -649,8 +649,10 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream)struct snd_pcm_hardware *ppcm;int ret =0 ;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct davinci_pcm_dma_params *pa = rtd->dai->cpu_dai->dma_data; +struct davinci_pcm_dma_params *pa;struct davinci_pcm_dma_params *params; + + pa =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);if (!pa)return -ENODEV ; params = &pa[substream->stream];
sound/soc/omap/omap-mcbsp.c +3 -1
@@ -287,7 +287,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; - cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; + +snd_soc_dai_set_dma_data (cpu_dai, substream, + &omap_mcbsp_dai_dma_params[id][substream->stream]);if (mcbsp_data->configured) {/* McBSP already configured by another stream */
sound/soc/omap/omap-pcm.c +3 -1
@@ -99,9 +99,11 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct snd_soc_pcm_runtime *rtd = substream->private_data;struct omap_runtime_data *prtd = runtime->private_data; -struct omap_pcm_dma_data *dma_data = rtd->dai->cpu_dai->dma_data; +struct omap_pcm_dma_data *dma_data;int err =0 ; + dma_data =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); +/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma_data)
sound/soc/pxa/pxa-ssp.c +12 -11
@@ -103,10 +103,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,ssp_disable (&priv->dev); } -if (cpu_dai->dma_data) { -kfree (cpu_dai->dma_data); - cpu_dai->dma_data =NULL ; - } +kfree (snd_soc_dai_get_dma_data (cpu_dai, substream)); +snd_soc_dai_set_dma_data (cpu_dai, substream,NULL ); +return ret; }
@@ -122,10 +121,8 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,clk_disable (priv->dev.ssp->clk); } -if (cpu_dai->dma_data) { -kfree (cpu_dai->dma_data); - cpu_dai->dma_data =NULL ; - } +kfree (snd_soc_dai_get_dma_data (cpu_dai, substream)); +snd_soc_dai_set_dma_data (cpu_dai, substream,NULL ); }#ifdef CONFIG_PM
@@ -536,19 +533,23 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,u32 sspsp;int width =snd_pcm_format_physical_width (params_format (params));int ttsa =ssp_read_reg (ssp,SSTSA ) &0xf ; +struct pxa2xx_pcm_dma_params *dma_data; + + dma_data =snd_soc_dai_get_dma_data (dai, substream);/* generate correct DMA params */ -if (cpu_dai->dma_data) -kfree (cpu_dai->dma_data); +kfree (dma_data);/* Network mode with one active slot (ttsa == 1) can be used * to force 16-bit frame width on the wire (for S16_LE), even * with two channels. Use 16-bit DMA transfers for this case. */ - cpu_dai->dma_data =ssp_get_dma_params (ssp, + dma_data =ssp_get_dma_params (ssp, ((chn ==2 ) && (ttsa !=1 )) || (width ==32 ), substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ); +snd_soc_dai_set_dma_data (dai, substream, dma_data); +/* we can only change the settings if the port is not in use */ if (ssp_read_reg (ssp,SSCR0 ) &SSCR0_SSE )return 0 ;
sound/soc/pxa/pxa2xx-ac97.c +12 -5
@@ -122,11 +122,14 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; + dma_data = &pxa2xx_ac97_pcm_stereo_out;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_in; + dma_data = &pxa2xx_ac97_pcm_stereo_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);return 0 ; }
@@ -137,11 +140,14 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; + dma_data = &pxa2xx_ac97_pcm_aux_mono_out;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + dma_data = &pxa2xx_ac97_pcm_aux_mono_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);return 0 ; }
@@ -156,7 +162,8 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK )return -ENODEV ;else - cpu_dai->dma_data = &pxa2xx_ac97_pcm_mic_mono_in; +snd_soc_dai_set_dma_data (cpu_dai, substream, + &pxa2xx_ac97_pcm_mic_mono_in);return 0 ; }
sound/soc/pxa/pxa2xx-i2s.c +5 -2
@@ -164,6 +164,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, {struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; +struct pxa2xx_pcm_dma_params *dma_data;BUG_ON (IS_ERR (clk_i2s));clk_enable (clk_i2s);
@@ -171,9 +172,11 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,pxa_i2s_wait ();if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out; + dma_data = &pxa2xx_i2s_pcm_stereo_out;else - cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in; + dma_data = &pxa2xx_i2s_pcm_stereo_in; + +snd_soc_dai_set_dma_data (cpu_dai, substream, dma_data);/* is port used by another stream */ if (!(SACR0 &SACR0_ENB )) {
sound/soc/pxa/pxa2xx-pcm.c +3 -1
@@ -25,9 +25,11 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct pxa2xx_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; +struct pxa2xx_pcm_dma_params *dma;int ret; + dma =snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream); +/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma)
sound/soc/s3c24xx/s3c-dma.c +3 -1
@@ -145,10 +145,12 @@ static int s3c_dma_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_runtime *runtime = substream->runtime;struct s3c24xx_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *rtd = substream->private_data; -struct s3c_dma_params *dma = rtd->dai->cpu_dai->dma_data;unsigned long totbytes =params_buffer_bytes (params); +struct s3c_dma_params *dma = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);int ret =0 ; +pr_debug ("Entered %s\n" , __func__);/* return if this is a bufferless transfer e.g.
sound/soc/s3c24xx/s3c-i2s-v2.c +8 -5
@@ -339,14 +339,17 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai_link *dai = rtd->dai;struct s3c_i2sv2_info *i2s =to_info (dai->cpu_dai); +struct s3c_dma_params *dma_data;u32 iismod;pr_debug ("Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - dai->cpu_dai->dma_data = i2s->dma_playback; + dma_data = i2s->dma_playback;else - dai->cpu_dai->dma_data = i2s->dma_capture; + dma_data = i2s->dma_capture; + +snd_soc_dai_set_dma_data (dai->cpu_dai, substream, dma_data);/* Working copies of register */ iismod =readl (i2s->regs +S3C2412_IISMOD );
@@ -394,8 +397,8 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,int capture = (substream->stream ==SNDRV_PCM_STREAM_CAPTURE );unsigned long irqs;int ret =0 ; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);pr_debug ("Entered %s\n" , __func__);
@@ -431,7 +434,7 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,* of the auto reload mechanism of S3C24XX. * This call won't bother S3C64XX. */ -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );break ;
sound/soc/s3c24xx/s3c-pcm.c +5 -2
@@ -178,6 +178,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,struct snd_soc_pcm_runtime *rtd = substream->private_data;struct snd_soc_dai_link *dai = rtd->dai;struct s3c_pcm_info *pcm =to_info (dai->cpu_dai); +struct s3c_dma_params *dma_data;void __iomem *regs = pcm->regs;struct clk *clk;int sclk_div, sync_div;
@@ -187,9 +188,11 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,dev_dbg (pcm->dev,"Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - dai->cpu_dai->dma_data = pcm->dma_playback; + dma_data = pcm->dma_playback;else - dai->cpu_dai->dma_data = pcm->dma_capture; + dma_data = pcm->dma_capture; + +snd_soc_dai_set_dma_data (dai->cpu_dai, substream, dma_data);/* Strictly check for sample size */ switch (params_format (params)) {
sound/soc/s3c24xx/s3c24xx-i2s.c +10 -9
@@ -242,14 +242,17 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) {struct snd_soc_pcm_runtime *rtd = substream->private_data; +struct s3c_dma_params *dma_data;u32 iismod;pr_debug ("Entered %s\n" , __func__);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) - rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out; + dma_data = &s3c24xx_i2s_pcm_stereo_out;else - rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_in; + dma_data = &s3c24xx_i2s_pcm_stereo_in; + +snd_soc_dai_set_dma_data (rtd->dai->cpu_dai, substream, dma_data);/* Working copies of register */ iismod =readl (s3c24xx_i2s.regs +S3C2410_IISMOD );
@@ -258,13 +261,11 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,switch (params_format (params)) {case SNDRV_PCM_FORMAT_S8 : iismod &= ~S3C2410_IISMOD_16BIT ; - ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size =1 ; + dma_data->dma_size =1 ;break ;case SNDRV_PCM_FORMAT_S16_LE : iismod |=S3C2410_IISMOD_16BIT ; - ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size =2 ; + dma_data->dma_size =2 ;break ;default :return -EINVAL ;
@@ -280,8 +281,8 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, {int ret =0 ;struct snd_soc_pcm_runtime *rtd = substream->private_data; -int channel = ((struct s3c_dma_params *) - rtd->dai->cpu_dai->dma_data)->channel; +struct s3c_dma_params *dma_data = +snd_soc_dai_get_dma_data (rtd->dai->cpu_dai, substream);pr_debug ("Entered %s\n" , __func__);
@@ -300,7 +301,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,else s3c24xx_snd_txctrl (1 ); -s3c2410_dma_ctrl (channel,S3C2410_DMAOP_STARTED ); +s3c2410_dma_ctrl (dma_data->channel,S3C2410_DMAOP_STARTED );break ;case SNDRV_PCM_TRIGGER_STOP :case SNDRV_PCM_TRIGGER_SUSPEND :
sound/soc/s6000/s6000-i2s.c +2 -1
@@ -518,7 +518,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev) s6000_i2s_dai.dev = &pdev->dev; s6000_i2s_dai.private_data = dev; - s6000_i2s_dai.dma_data = &dev->dma_params; + s6000_i2s_dai.capture.dma_data = &dev->dma_params; + s6000_i2s_dai.playback.dma_data = &dev->dma_params; dev->sifbase = sifmem->start; dev->scbbase = mmio;
sound/soc/s6000/s6000-pcm.c +29 -11
@@ -58,13 +58,15 @@ static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream)struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int channel;unsigned int period_size;unsigned int dma_offset;dma_addr_t dma_pos;dma_addr_t src, dst; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); + period_size =snd_pcm_lib_period_bytes (substream); dma_offset = prtd->period * period_size; dma_pos = runtime->dma_addr + dma_offset;
@@ -101,7 +103,8 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data) {struct snd_pcm *pcm = data;struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);struct s6000_runtime_data *prtd;unsigned int has_xrun;int i, ret =IRQ_NONE ;
@@ -172,11 +175,13 @@ static int s6000_pcm_start(struct snd_pcm_substream *substream) {struct s6000_runtime_data *prtd = substream->runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;unsigned long flags;int srcinc;u32 dma; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +spin_lock_irqsave (&prtd->lock, flags);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) {
@@ -212,10 +217,12 @@ static int s6000_pcm_stop(struct snd_pcm_substream *substream) {struct s6000_runtime_data *prtd = substream->runtime->private_data;struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;unsigned long flags;u32 channel; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ) channel = par->dma_out;else
@@ -236,9 +243,11 @@ static int s6000_pcm_stop(struct snd_pcm_substream *substream)static int s6000_pcm_trigger (struct snd_pcm_substream *substream,int cmd) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int ret; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); + ret = par->trigger (substream, cmd,0 );if (ret <0 )return ret;
@@ -275,13 +284,15 @@ static int s6000_pcm_prepare(struct snd_pcm_substream *substream)static snd_pcm_uframes_t s6000_pcm_pointer (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd = runtime->private_data;unsigned long flags;unsigned int offset;dma_addr_t count; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +spin_lock_irqsave (&prtd->lock, flags);if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK )
@@ -305,11 +316,12 @@ static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream)static int s6000_pcm_open (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;struct snd_pcm_runtime *runtime = substream->runtime;struct s6000_runtime_data *prtd;int ret; + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);snd_soc_set_runtime_hwparams (substream, &s6000_pcm_hardware); ret = snd_pcm_hw_constraint_step(runtime, 0,
@@ -364,7 +376,7 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par;int ret; ret =snd_pcm_lib_malloc_pages (substream,params_buffer_bytes (hw_params));
@@ -373,6 +385,8 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,return ret; } + par =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (par->same_rate) {spin_lock (&par->lock); if (par->rate == -1 ||
@@ -392,7 +406,8 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,static int s6000_pcm_hw_free (struct snd_pcm_substream *substream) {struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; -struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *par = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);spin_lock (&par->lock); par->in_use &= ~(1 << substream->stream);
@@ -417,7 +432,8 @@ static struct snd_pcm_ops s6000_pcm_ops = {static void s6000_pcm_free (struct snd_pcm *pcm) {struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params = +snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream);free_irq (params->irq, pcm);snd_pcm_lib_preallocate_free_for_all (pcm);
@@ -429,9 +445,11 @@ static int s6000_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm) { struct snd_soc_pcm_runtime *runtime = pcm->private_data; -struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; +struct s6000_pcm_dma_params *params;int res; + params =snd_soc_dai_get_dma_data (soc_runtime->dai->cpu_dai, substream); +if (!card->dev->dma_mask) card->dev->dma_mask = &s6000_pcm_dmamask;if (!card->dev->coherent_dma_mask)
Signature · 1 line
1.7.0
Jarkko Nikula
Acked-byRe: [PATCH] ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
In reply to Peter UjfalusiQuoted 4 lines · On Fri, 19 Mar 2010 08:56:40 +0200 Peter Ujfalusi <[email protected]>…
At least the OMAP code should not be affected by the bug, that you have with the pxa-ssp. I think the bug could be also fixed within the pxa code, since the whole thing goes down to inconsistent memory management within the pxa code.
Quoted 9 lines
Having said that, I do think having separate
dma_datafor each streams is a really good idea.
One thing that I can think of in OMAP case, where this could fix a nasty race condition is (have never seen it, but it is in theory possible):
Also in duplex case, when the secondhw_paramgets called after the firstomap_mcbsp_hw_params, and before theomap_pcm_hw_paramsfor the first stream. The secondomap_mcbsp_hw_paramswill override thedma_data, thus we would set bogus parameters for the first stream.
There shouldn't be this kind of race in OMAP since the soc_pcm_hw_params protects the hw_params calls with a mutex and the omap_pcm_hw_params takes a copy from parameters passed from DAI driver's hw_params.
But yes, I agree that the stream specific dma_data is good idea.
Quoted 3 lines
For the
omap-mcbsp.candomap-pcm.cchanges:Acked-by Peter Ujfalusi <[email protected]>
Re: [PATCH] ALSA: ASoC: move dma_data from snd_soc_dai to snd_soc_pcm_stream
In reply to Daniel MackQuoted 15 lines · Daniel Mack
This fixes a memory corruption when ASoC devices are used in full-duplex mode. Specifically for pxa-ssp code, where this pointer is dynamically allocated for each direction and destroyed upon each stream start.
All other platforms are fixed blindly, I couldn't even compile-test them. Sorry for any breakage I may have caused.
Signed-off-by Daniel Mack <[email protected]>Cc Liam Girdwood <[email protected]>Cc Mark Brown <[email protected]>Cc Sven Neumann <[email protected]>Cc Michael Hirsch <[email protected]>Reported-by Sven Neumann <[email protected]>Reported-by Michael Hirsch <[email protected]>
Quoted 5 lines
---
I indeed missed quite a few platforms, you were right. Hope I got them all now. Better check again - thanks!
All the platforms here look fine.
Signature · 3 lines
Freelance Developer, SlimLogic Ltd ASoC and Voltage Regulator Maintainer. http://www.slimlogic.co.uk