[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:
Родитель
dc961136b9
Коммит
06f08e3a4d
|
@ -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;
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче