Commit 06f08e3a authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab

[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: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent dc961136
...@@ -201,6 +201,14 @@ static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream) ...@@ -201,6 +201,14 @@ static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream)
*/ */
static int snd_tm6000_close(struct snd_pcm_substream *substream) static int snd_tm6000_close(struct snd_pcm_substream *substream)
{ {
struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
struct tm6000_core *core = chip->core;
if (atomic_read(&core->stream_started) > 0) {
atomic_set(&core->stream_started, 0);
schedule_work(&core->wq_trigger);
}
return 0; return 0;
} }
...@@ -213,6 +221,9 @@ static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size) ...@@ -213,6 +221,9 @@ static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
unsigned int stride, buf_pos; unsigned int stride, buf_pos;
int length; int length;
if (atomic_read(&core->stream_started) == 0)
return 0;
if (!size || !substream) { if (!size || !substream) {
dprintk(1, "substream was NULL\n"); dprintk(1, "substream was NULL\n");
return -EINVAL; return -EINVAL;
...@@ -298,8 +309,12 @@ static int snd_tm6000_hw_params(struct snd_pcm_substream *substream, ...@@ -298,8 +309,12 @@ static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
static int snd_tm6000_hw_free(struct snd_pcm_substream *substream) static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
{ {
struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
struct tm6000_core *core = chip->core;
_tm6000_stop_audio_dma(chip); if (atomic_read(&core->stream_started) > 0) {
atomic_set(&core->stream_started, 0);
schedule_work(&core->wq_trigger);
}
return 0; return 0;
} }
...@@ -321,30 +336,42 @@ static int snd_tm6000_prepare(struct snd_pcm_substream *substream) ...@@ -321,30 +336,42 @@ static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
/* /*
* trigger callback * trigger callback
*/ */
static void audio_trigger(struct work_struct *work)
{
struct tm6000_core *core = container_of(work, struct tm6000_core,
wq_trigger);
struct snd_tm6000_card *chip = core->adev;
if (atomic_read(&core->stream_started)) {
dprintk(1, "starting capture");
_tm6000_start_audio_dma(chip);
} else {
dprintk(1, "stopping capture");
_tm6000_stop_audio_dma(chip);
}
}
static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd) static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
{ {
struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
int err; struct tm6000_core *core = chip->core;
int err = 0;
spin_lock(&chip->reg_lock);
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
err = _tm6000_start_audio_dma(chip); atomic_set(&core->stream_started, 1);
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
err = _tm6000_stop_audio_dma(chip); atomic_set(&core->stream_started, 0);
break; break;
default: default:
err = -EINVAL; err = -EINVAL;
break; break;
} }
schedule_work(&core->wq_trigger);
spin_unlock(&chip->reg_lock);
return err; return err;
} }
/* /*
* pointer callback * pointer callback
*/ */
...@@ -437,6 +464,7 @@ int tm6000_audio_init(struct tm6000_core *dev) ...@@ -437,6 +464,7 @@ int tm6000_audio_init(struct tm6000_core *dev)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
INIT_WORK(&dev->wq_trigger, audio_trigger);
rc = snd_card_register(card); rc = snd_card_register(card);
if (rc < 0) if (rc < 0)
goto error; goto error;
......
...@@ -205,6 +205,9 @@ struct tm6000_core { ...@@ -205,6 +205,9 @@ struct tm6000_core {
/* audio support */ /* audio support */
struct snd_tm6000_card *adev; struct snd_tm6000_card *adev;
struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
atomic_t stream_started; /* stream should be running if true */
struct tm6000_IR *ir; struct tm6000_IR *ir;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment