diff options
-rw-r--r-- | drivers/media/pci/tw686x/tw686x-audio.c | 20 | ||||
-rw-r--r-- | drivers/media/pci/tw686x/tw686x.h | 1 |
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 */ |