diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-09-27 02:07:22 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-10-20 23:17:44 -0400 |
commit | 61b04cb24a129f2483d5110e119fc2e365177741 (patch) | |
tree | c3ea9f44bf374a1bec4c9163f582cb3fa79110e3 /drivers | |
parent | e350d44fed8eb86a7192a579e3687fcd76a4645b (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')
-rw-r--r-- | drivers/media/video/cx231xx/cx231xx-audio.c | 95 | ||||
-rw-r--r-- | drivers/media/video/cx231xx/cx231xx.h | 8 |
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 | |||
374 | static 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 | |||
402 | static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, | 379 | static 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 | ||
550 | static 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 | |||
565 | static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream, | 568 | static 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 | ||
593 | static snd_pcm_uframes_t snd_cx231xx_capture_pointer(struct snd_pcm_substream | 592 | static 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 */ |