aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorOskar Schirmer <oskar@scara.com>2013-11-12 10:46:38 -0500
committerMark Brown <broonie@linaro.org>2013-11-14 07:59:44 -0500
commitfc7dc61d9a87011aaf8a6eb3144ebf9552adf5d2 (patch)
tree4d6e4007b7fd6bd144fadd4ef01390728304876d /sound/soc
parent71d0c3a876e007f68fc2ed433119dd4f4dc408a7 (diff)
ASoC: fsl: imx-pcm-fiq: omit fiq counter to avoid harm in unbalanced situations
Unbalanced calls to snd_imx_pcm_trigger() may result in endless FIQ activity and thus provoke eternal sound. While on the first glance, the switch statement looks pretty symmetric, the SUSPEND/RESUME pair is not: the suspend case comes along snd_pcm_suspend_all(), which for fsl/imx-pcm-fiq is called only at snd_soc_suspend(), but the resume case originates straight from the SNDRV_PCM_IOCTL_RESUME. This way userland may provoke an unbalanced resume, which might cause the fiq_enable counter to increase and never return to zero again, so eventually imx_pcm_fiq is never disabled. Simply removing the fiq_enable will solve the problem, as long as one never goes play and capture game simultaneously, but beware trying both at once, the early TRIGGER_STOP will cut off the other activity prematurely. So now playing and capturing is scrutinized separately, instead of by counting. Signed-off-by: Oskar Schirmer <oskar@scara.com> Signed-off-by: Mark Brown <broonie@linaro.org> Cc: stable@vger.kernel.org
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c29
1 files changed, 17 insertions, 12 deletions
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 34043c55f2a6..2fc872b2deff 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -44,7 +44,8 @@ struct imx_pcm_runtime_data {
44 struct hrtimer hrt; 44 struct hrtimer hrt;
45 int poll_time_ns; 45 int poll_time_ns;
46 struct snd_pcm_substream *substream; 46 struct snd_pcm_substream *substream;
47 atomic_t running; 47 atomic_t playing;
48 atomic_t capturing;
48}; 49};
49 50
50static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) 51static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
@@ -56,7 +57,7 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
56 struct pt_regs regs; 57 struct pt_regs regs;
57 unsigned long delta; 58 unsigned long delta;
58 59
59 if (!atomic_read(&iprtd->running)) 60 if (!atomic_read(&iprtd->playing) && !atomic_read(&iprtd->capturing))
60 return HRTIMER_NORESTART; 61 return HRTIMER_NORESTART;
61 62
62 get_fiq_regs(&regs); 63 get_fiq_regs(&regs);
@@ -124,7 +125,6 @@ static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
124 return 0; 125 return 0;
125} 126}
126 127
127static int fiq_enable;
128static int imx_pcm_fiq; 128static int imx_pcm_fiq;
129 129
130static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 130static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
@@ -136,23 +136,27 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
136 case SNDRV_PCM_TRIGGER_START: 136 case SNDRV_PCM_TRIGGER_START:
137 case SNDRV_PCM_TRIGGER_RESUME: 137 case SNDRV_PCM_TRIGGER_RESUME:
138 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 138 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
139 atomic_set(&iprtd->running, 1); 139 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
140 atomic_set(&iprtd->playing, 1);
141 else
142 atomic_set(&iprtd->capturing, 1);
140 hrtimer_start(&iprtd->hrt, ns_to_ktime(iprtd->poll_time_ns), 143 hrtimer_start(&iprtd->hrt, ns_to_ktime(iprtd->poll_time_ns),
141 HRTIMER_MODE_REL); 144 HRTIMER_MODE_REL);
142 if (++fiq_enable == 1) 145 enable_fiq(imx_pcm_fiq);
143 enable_fiq(imx_pcm_fiq);
144
145 break; 146 break;
146 147
147 case SNDRV_PCM_TRIGGER_STOP: 148 case SNDRV_PCM_TRIGGER_STOP:
148 case SNDRV_PCM_TRIGGER_SUSPEND: 149 case SNDRV_PCM_TRIGGER_SUSPEND:
149 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 150 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
150 atomic_set(&iprtd->running, 0); 151 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
151 152 atomic_set(&iprtd->playing, 0);
152 if (--fiq_enable == 0) 153 else
154 atomic_set(&iprtd->capturing, 0);
155 if (!atomic_read(&iprtd->playing) &&
156 !atomic_read(&iprtd->capturing))
153 disable_fiq(imx_pcm_fiq); 157 disable_fiq(imx_pcm_fiq);
154
155 break; 158 break;
159
156 default: 160 default:
157 return -EINVAL; 161 return -EINVAL;
158 } 162 }
@@ -200,7 +204,8 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
200 204
201 iprtd->substream = substream; 205 iprtd->substream = substream;
202 206
203 atomic_set(&iprtd->running, 0); 207 atomic_set(&iprtd->playing, 0);
208 atomic_set(&iprtd->capturing, 0);
204 hrtimer_init(&iprtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 209 hrtimer_init(&iprtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
205 iprtd->hrt.function = snd_hrtimer_callback; 210 iprtd->hrt.function = snd_hrtimer_callback;
206 211