[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: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Mauro Carvalho Chehab 2010-10-09 21:15:33 -03:00
Родитель dc961136b9
Коммит 06f08e3a4d
2 изменённых файлов: 40 добавлений и 9 удалений

Просмотреть файл

@ -201,6 +201,14 @@ _error:
*/ */
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)
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,
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)
/* /*
* 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)
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 {
/* 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;