aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2010-10-09 20:15:33 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-21 09:36:07 -0400
commit06f08e3a4d86e746f5e8e09030e6560e37386b7f (patch)
tree98ae69fa1fef476615aa0cc19427d6f4806ec21c
parentdc961136b982c4260b6701d9c619bf7a4a7ac6ed (diff)
[media] tm6000-alsa: fix some locking issues
Those locking issues affect tvtime, causing a kernel oops/panic, due to a race condition. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/staging/tm6000/tm6000-alsa.c46
-rw-r--r--drivers/staging/tm6000/tm6000.h3
2 files changed, 40 insertions, 9 deletions
diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c
index a99101fef1a3..e379e3ec4442 100644
--- a/drivers/staging/tm6000/tm6000-alsa.c
+++ b/drivers/staging/tm6000/tm6000-alsa.c
@@ -201,6 +201,14 @@ _error:
201 */ 201 */
202static int snd_tm6000_close(struct snd_pcm_substream *substream) 202static int snd_tm6000_close(struct snd_pcm_substream *substream)
203{ 203{
204 struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
205 struct tm6000_core *core = chip->core;
206
207 if (atomic_read(&core->stream_started) > 0) {
208 atomic_set(&core->stream_started, 0);
209 schedule_work(&core->wq_trigger);
210 }
211
204 return 0; 212 return 0;
205} 213}
206 214
@@ -213,6 +221,9 @@ static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
213 unsigned int stride, buf_pos; 221 unsigned int stride, buf_pos;
214 int length; 222 int length;
215 223
224 if (atomic_read(&core->stream_started) == 0)
225 return 0;
226
216 if (!size || !substream) { 227 if (!size || !substream) {
217 dprintk(1, "substream was NULL\n"); 228 dprintk(1, "substream was NULL\n");
218 return -EINVAL; 229 return -EINVAL;
@@ -298,8 +309,12 @@ static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
298static int snd_tm6000_hw_free(struct snd_pcm_substream *substream) 309static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
299{ 310{
300 struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); 311 struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
312 struct tm6000_core *core = chip->core;
301 313
302 _tm6000_stop_audio_dma(chip); 314 if (atomic_read(&core->stream_started) > 0) {
315 atomic_set(&core->stream_started, 0);
316 schedule_work(&core->wq_trigger);
317 }
303 318
304 return 0; 319 return 0;
305} 320}
@@ -321,30 +336,42 @@ static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
321/* 336/*
322 * trigger callback 337 * trigger callback
323 */ 338 */
339static void audio_trigger(struct work_struct *work)
340{
341 struct tm6000_core *core = container_of(work, struct tm6000_core,
342 wq_trigger);
343 struct snd_tm6000_card *chip = core->adev;
344
345 if (atomic_read(&core->stream_started)) {
346 dprintk(1, "starting capture");
347 _tm6000_start_audio_dma(chip);
348 } else {
349 dprintk(1, "stopping capture");
350 _tm6000_stop_audio_dma(chip);
351 }
352}
353
324static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd) 354static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
325{ 355{
326 struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); 356 struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
327 int err; 357 struct tm6000_core *core = chip->core;
328 358 int err = 0;
329 spin_lock(&chip->reg_lock);
330 359
331 switch (cmd) { 360 switch (cmd) {
332 case SNDRV_PCM_TRIGGER_START: 361 case SNDRV_PCM_TRIGGER_START:
333 err = _tm6000_start_audio_dma(chip); 362 atomic_set(&core->stream_started, 1);
334 break; 363 break;
335 case SNDRV_PCM_TRIGGER_STOP: 364 case SNDRV_PCM_TRIGGER_STOP:
336 err = _tm6000_stop_audio_dma(chip); 365 atomic_set(&core->stream_started, 0);
337 break; 366 break;
338 default: 367 default:
339 err = -EINVAL; 368 err = -EINVAL;
340 break; 369 break;
341 } 370 }
342 371 schedule_work(&core->wq_trigger);
343 spin_unlock(&chip->reg_lock);
344 372
345 return err; 373 return err;
346} 374}
347
348/* 375/*
349 * pointer callback 376 * pointer callback
350 */ 377 */
@@ -437,6 +464,7 @@ int tm6000_audio_init(struct tm6000_core *dev)
437 464
438 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops); 465 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
439 466
467 INIT_WORK(&dev->wq_trigger, audio_trigger);
440 rc = snd_card_register(card); 468 rc = snd_card_register(card);
441 if (rc < 0) 469 if (rc < 0)
442 goto error; 470 goto error;
diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h
index 1ec1bff9b294..5d9dcab5c87d 100644
--- a/drivers/staging/tm6000/tm6000.h
+++ b/drivers/staging/tm6000/tm6000.h
@@ -205,6 +205,9 @@ struct tm6000_core {
205 205
206 /* audio support */ 206 /* audio support */
207 struct snd_tm6000_card *adev; 207 struct snd_tm6000_card *adev;
208 struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
209 atomic_t stream_started; /* stream should be running if true */
210
208 211
209 struct tm6000_IR *ir; 212 struct tm6000_IR *ir;
210 213