aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx231xx
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2010-09-27 02:07:22 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-20 23:17:44 -0400
commit61b04cb24a129f2483d5110e119fc2e365177741 (patch)
treec3ea9f44bf374a1bec4c9163f582cb3fa79110e3 /drivers/media/video/cx231xx
parente350d44fed8eb86a7192a579e3687fcd76a4645b (diff)
[media] cx231xx-audio: fix some locking issues
Acked-by: Sri Deevi <Srinivasa.Deevi@conexant.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx231xx')
-rw-r--r--drivers/media/video/cx231xx/cx231xx-audio.c95
-rw-r--r--drivers/media/video/cx231xx/cx231xx.h8
2 files changed, 52 insertions, 51 deletions
diff --git a/drivers/media/video/cx231xx/cx231xx-audio.c b/drivers/media/video/cx231xx/cx231xx-audio.c
index 6ac418cc6895..30d13c15739a 100644
--- a/drivers/media/video/cx231xx/cx231xx-audio.c
+++ b/drivers/media/video/cx231xx/cx231xx-audio.c
@@ -124,6 +124,9 @@ static void cx231xx_audio_isocirq(struct urb *urb)
124 break; 124 break;
125 } 125 }
126 126
127 if (atomic_read(&dev->stream_started) == 0)
128 return;
129
127 if (dev->adev.capture_pcm_substream) { 130 if (dev->adev.capture_pcm_substream) {
128 substream = dev->adev.capture_pcm_substream; 131 substream = dev->adev.capture_pcm_substream;
129 runtime = substream->runtime; 132 runtime = substream->runtime;
@@ -206,6 +209,9 @@ static void cx231xx_audio_bulkirq(struct urb *urb)
206 break; 209 break;
207 } 210 }
208 211
212 if (atomic_read(&dev->stream_started) == 0)
213 return;
214
209 if (dev->adev.capture_pcm_substream) { 215 if (dev->adev.capture_pcm_substream) {
210 substream = dev->adev.capture_pcm_substream; 216 substream = dev->adev.capture_pcm_substream;
211 runtime = substream->runtime; 217 runtime = substream->runtime;
@@ -370,35 +376,6 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev)
370 return errCode; 376 return errCode;
371} 377}
372 378
373
374static int cx231xx_cmd(struct cx231xx *dev, int cmd, int arg)
375{
376 dprintk("%s transfer\n", (dev->adev.capture_stream == STREAM_ON) ?
377 "stop" : "start");
378
379 switch (cmd) {
380 case CX231XX_CAPTURE_STREAM_EN:
381 if (dev->adev.capture_stream == STREAM_OFF && arg == 1) {
382 dev->adev.capture_stream = STREAM_ON;
383 if (is_fw_load(dev) == 0)
384 cx25840_call(dev, core, load_fw);
385 if (dev->USE_ISO)
386 cx231xx_init_audio_isoc(dev);
387 else
388 cx231xx_init_audio_bulk(dev);
389 } else if (dev->adev.capture_stream == STREAM_ON && arg == 0) {
390 dev->adev.capture_stream = STREAM_OFF;
391 cx231xx_isoc_audio_deinit(dev);
392 } else {
393 cx231xx_errdev("An underrun very likely occurred. "
394 "Ignoring it.\n");
395 }
396 return 0;
397 default:
398 return -EINVAL;
399 }
400}
401
402static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, 379static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
403 size_t size) 380 size_t size)
404{ 381{
@@ -460,22 +437,24 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream)
460 437
461 /* set alternate setting for audio interface */ 438 /* set alternate setting for audio interface */
462 /* 1 - 48000 samples per sec */ 439 /* 1 - 48000 samples per sec */
440 mutex_lock(&dev->lock);
463 if (dev->USE_ISO) 441 if (dev->USE_ISO)
464 ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1); 442 ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1);
465 else 443 else
466 ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0); 444 ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0);
445 mutex_unlock(&dev->lock);
467 if (ret < 0) { 446 if (ret < 0) {
468 cx231xx_errdev("failed to set alternate setting !\n"); 447 cx231xx_errdev("failed to set alternate setting !\n");
469 448
470 return ret; 449 return ret;
471 } 450 }
472 451
473 /* inform hardware to start streaming */
474 ret = cx231xx_capture_start(dev, 1, Audio);
475
476 runtime->hw = snd_cx231xx_hw_capture; 452 runtime->hw = snd_cx231xx_hw_capture;
477 453
478 mutex_lock(&dev->lock); 454 mutex_lock(&dev->lock);
455 /* inform hardware to start streaming */
456 ret = cx231xx_capture_start(dev, 1, Audio);
457
479 dev->adev.users++; 458 dev->adev.users++;
480 mutex_unlock(&dev->lock); 459 mutex_unlock(&dev->lock);
481 460
@@ -493,7 +472,8 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
493 472
494 dprintk("closing device\n"); 473 dprintk("closing device\n");
495 474
496 /* inform hardware to start streaming */ 475 /* inform hardware to stop streaming */
476 mutex_lock(&dev->lock);
497 ret = cx231xx_capture_start(dev, 0, Audio); 477 ret = cx231xx_capture_start(dev, 0, Audio);
498 478
499 /* set alternate setting for audio interface */ 479 /* set alternate setting for audio interface */
@@ -502,11 +482,11 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
502 if (ret < 0) { 482 if (ret < 0) {
503 cx231xx_errdev("failed to set alternate setting !\n"); 483 cx231xx_errdev("failed to set alternate setting !\n");
504 484
485 mutex_unlock(&dev->lock);
505 return ret; 486 return ret;
506 } 487 }
507 488
508 dev->mute = 1; 489 dev->mute = 1;
509 mutex_lock(&dev->lock);
510 dev->adev.users--; 490 dev->adev.users--;
511 mutex_unlock(&dev->lock); 491 mutex_unlock(&dev->lock);
512 492
@@ -515,7 +495,10 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
515 dprintk("disabling audio stream!\n"); 495 dprintk("disabling audio stream!\n");
516 dev->adev.shutdown = 0; 496 dev->adev.shutdown = 0;
517 dprintk("released lock\n"); 497 dprintk("released lock\n");
518 cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, 0); 498 if (atomic_read(&dev->stream_started) > 0) {
499 atomic_set(&dev->stream_started, 0);
500 schedule_work(&dev->wq_trigger);
501 }
519 } 502 }
520 return 0; 503 return 0;
521} 504}
@@ -546,8 +529,10 @@ static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream)
546 529
547 dprintk("Stop capture, if needed\n"); 530 dprintk("Stop capture, if needed\n");
548 531
549 if (dev->adev.capture_stream == STREAM_ON) 532 if (atomic_read(&dev->stream_started) > 0) {
550 cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, CX231XX_STOP_AUDIO); 533 atomic_set(&dev->stream_started, 0);
534 schedule_work(&dev->wq_trigger);
535 }
551 536
552 return 0; 537 return 0;
553} 538}
@@ -562,32 +547,46 @@ static int snd_cx231xx_prepare(struct snd_pcm_substream *substream)
562 return 0; 547 return 0;
563} 548}
564 549
550static void audio_trigger(struct work_struct *work)
551{
552 struct cx231xx *dev = container_of(work, struct cx231xx, wq_trigger);
553
554 if (atomic_read(&dev->stream_started)) {
555 dprintk("starting capture");
556 if (is_fw_load(dev) == 0)
557 cx25840_call(dev, core, load_fw);
558 if (dev->USE_ISO)
559 cx231xx_init_audio_isoc(dev);
560 else
561 cx231xx_init_audio_bulk(dev);
562 } else {
563 dprintk("stopping capture");
564 cx231xx_isoc_audio_deinit(dev);
565 }
566}
567
565static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream, 568static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream,
566 int cmd) 569 int cmd)
567{ 570{
568 struct cx231xx *dev = snd_pcm_substream_chip(substream); 571 struct cx231xx *dev = snd_pcm_substream_chip(substream);
569 int retval; 572 int retval;
570 573
571 dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START) ?
572 "start" : "stop");
573
574 spin_lock(&dev->adev.slock); 574 spin_lock(&dev->adev.slock);
575 switch (cmd) { 575 switch (cmd) {
576 case SNDRV_PCM_TRIGGER_START: 576 case SNDRV_PCM_TRIGGER_START:
577 cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, 577 atomic_set(&dev->stream_started, 1);
578 CX231XX_START_AUDIO);
579 retval = 0;
580 break; 578 break;
581 case SNDRV_PCM_TRIGGER_STOP: 579 case SNDRV_PCM_TRIGGER_STOP:
582 cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, CX231XX_STOP_AUDIO); 580 atomic_set(&dev->stream_started, 0);
583 retval = 0;
584 break; 581 break;
585 default: 582 default:
586 retval = -EINVAL; 583 retval = -EINVAL;
587 } 584 }
588
589 spin_unlock(&dev->adev.slock); 585 spin_unlock(&dev->adev.slock);
590 return retval; 586
587 schedule_work(&dev->wq_trigger);
588
589 return 0;
591} 590}
592 591
593static snd_pcm_uframes_t snd_cx231xx_capture_pointer(struct snd_pcm_substream 592static snd_pcm_uframes_t snd_cx231xx_capture_pointer(struct snd_pcm_substream
@@ -668,6 +667,8 @@ static int cx231xx_audio_init(struct cx231xx *dev)
668 strcpy(card->shortname, "Cx231xx Audio"); 667 strcpy(card->shortname, "Cx231xx Audio");
669 strcpy(card->longname, "Conexant cx231xx Audio"); 668 strcpy(card->longname, "Conexant cx231xx Audio");
670 669
670 INIT_WORK(&dev->wq_trigger, audio_trigger);
671
671 err = snd_card_register(card); 672 err = snd_card_register(card);
672 if (err < 0) { 673 if (err < 0) {
673 snd_card_free(card); 674 snd_card_free(card);
diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h
index d0794332114c..f9cdc01a7faa 100644
--- a/drivers/media/video/cx231xx/cx231xx.h
+++ b/drivers/media/video/cx231xx/cx231xx.h
@@ -27,6 +27,7 @@
27#include <linux/ioctl.h> 27#include <linux/ioctl.h>
28#include <linux/i2c.h> 28#include <linux/i2c.h>
29#include <linux/i2c-algo-bit.h> 29#include <linux/i2c-algo-bit.h>
30#include <linux/workqueue.h>
30#include <linux/mutex.h> 31#include <linux/mutex.h>
31 32
32#include <media/cx2341x.h> 33#include <media/cx2341x.h>
@@ -387,9 +388,6 @@ enum AUDIO_INPUT {
387#define CX231XX_AUDIO_BUFS 5 388#define CX231XX_AUDIO_BUFS 5
388#define CX231XX_NUM_AUDIO_PACKETS 16 389#define CX231XX_NUM_AUDIO_PACKETS 16
389#define CX231XX_ISO_NUM_AUDIO_PACKETS 64 390#define CX231XX_ISO_NUM_AUDIO_PACKETS 64
390#define CX231XX_CAPTURE_STREAM_EN 1
391#define CX231XX_STOP_AUDIO 0
392#define CX231XX_START_AUDIO 1
393 391
394/* cx231xx extensions */ 392/* cx231xx extensions */
395#define CX231XX_AUDIO 0x10 393#define CX231XX_AUDIO 0x10
@@ -407,7 +405,6 @@ struct cx231xx_audio {
407 struct snd_card *sndcard; 405 struct snd_card *sndcard;
408 406
409 int users, shutdown; 407 int users, shutdown;
410 enum cx231xx_stream_state capture_stream;
411 /* locks */ 408 /* locks */
412 spinlock_t slock; 409 spinlock_t slock;
413 410
@@ -624,6 +621,9 @@ struct cx231xx {
624 621
625 struct cx231xx_IR *ir; 622 struct cx231xx_IR *ir;
626 623
624 struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
625 atomic_t stream_started; /* stream should be running if true */
626
627 struct list_head devlist; 627 struct list_head devlist;
628 628
629 int tuner_type; /* type of the tuner */ 629 int tuner_type; /* type of the tuner */