summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/media/pci/tw686x/tw686x-audio.c20
-rw-r--r--drivers/media/pci/tw686x/tw686x.h1
2 files changed, 17 insertions, 4 deletions
diff --git a/drivers/media/pci/tw686x/tw686x-audio.c b/drivers/media/pci/tw686x/tw686x-audio.c
index 987a22663525..96e444c49173 100644
--- a/drivers/media/pci/tw686x/tw686x-audio.c
+++ b/drivers/media/pci/tw686x/tw686x-audio.c
@@ -94,10 +94,8 @@ static int tw686x_pcm_hw_free(struct snd_pcm_substream *ss)
/*
* Audio parameters are global and shared among all
- * capture channels. The driver makes no effort to prevent
- * any modifications. User is free change the audio rate,
- * or period size, thus changing parameters for all capture
- * sub-devices.
+ * capture channels. The driver prevents changes to
+ * the parameters if any audio channel is capturing.
*/
static const struct snd_pcm_hardware tw686x_capture_hw = {
.info = (SNDRV_PCM_INFO_MMAP |
@@ -154,6 +152,14 @@ static int tw686x_pcm_prepare(struct snd_pcm_substream *ss)
int i;
spin_lock_irqsave(&dev->lock, flags);
+ /*
+ * Given the audio parameters are global (i.e. shared across
+ * DMA channels), we need to check new params are allowed.
+ */
+ if (((dev->audio_rate != rt->rate) ||
+ (dev->period_size != period_size)) && dev->audio_enabled)
+ goto err_audio_busy;
+
tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch);
spin_unlock_irqrestore(&dev->lock, flags);
@@ -210,6 +216,10 @@ static int tw686x_pcm_prepare(struct snd_pcm_substream *ss)
spin_unlock_irqrestore(&ac->lock, flags);
return 0;
+
+err_audio_busy:
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return -EBUSY;
}
static int tw686x_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
@@ -223,6 +233,7 @@ static int tw686x_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
case SNDRV_PCM_TRIGGER_START:
if (ac->curr_bufs[0] && ac->curr_bufs[1]) {
spin_lock_irqsave(&dev->lock, flags);
+ dev->audio_enabled = 1;
tw686x_enable_channel(dev,
AUDIO_CHANNEL_OFFSET + ac->ch);
spin_unlock_irqrestore(&dev->lock, flags);
@@ -235,6 +246,7 @@ static int tw686x_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
break;
case SNDRV_PCM_TRIGGER_STOP:
spin_lock_irqsave(&dev->lock, flags);
+ dev->audio_enabled = 0;
tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch);
spin_unlock_irqrestore(&dev->lock, flags);
diff --git a/drivers/media/pci/tw686x/tw686x.h b/drivers/media/pci/tw686x/tw686x.h
index 4acb90543174..35d7bc94f78f 100644
--- a/drivers/media/pci/tw686x/tw686x.h
+++ b/drivers/media/pci/tw686x/tw686x.h
@@ -141,6 +141,7 @@ struct tw686x_dev {
/* Per-device audio parameters */
int audio_rate;
int period_size;
+ int audio_enabled;
struct timer_list dma_delay_timer;
u32 pending_dma_en; /* must be protected by lock */