]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - sound/drivers/aloop.c
ALSA: aloop: Fix access to not-yet-ready substream via cable
[linux.git] / sound / drivers / aloop.c
index 0333143a1fa7ad646c4da4b25eb653b2d3a1a3fb..1063a4377502a8338bfa3237183068eefcf0da0a 100644 (file)
@@ -192,6 +192,11 @@ static inline void loopback_timer_stop(struct loopback_pcm *dpcm)
        dpcm->timer.expires = 0;
 }
 
+static inline void loopback_timer_stop_sync(struct loopback_pcm *dpcm)
+{
+       del_timer_sync(&dpcm->timer);
+}
+
 #define CABLE_VALID_PLAYBACK   (1 << SNDRV_PCM_STREAM_PLAYBACK)
 #define CABLE_VALID_CAPTURE    (1 << SNDRV_PCM_STREAM_CAPTURE)
 #define CABLE_VALID_BOTH       (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE)
@@ -326,6 +331,8 @@ static int loopback_prepare(struct snd_pcm_substream *substream)
        struct loopback_cable *cable = dpcm->cable;
        int bps, salign;
 
+       loopback_timer_stop_sync(dpcm);
+
        salign = (snd_pcm_format_width(runtime->format) *
                                                runtime->channels) / 8;
        bps = salign * runtime->rate;
@@ -659,7 +666,9 @@ static void free_cable(struct snd_pcm_substream *substream)
                return;
        if (cable->streams[!substream->stream]) {
                /* other stream is still alive */
+               spin_lock_irq(&cable->lock);
                cable->streams[substream->stream] = NULL;
+               spin_unlock_irq(&cable->lock);
        } else {
                /* free the cable */
                loopback->cables[substream->number][dev] = NULL;
@@ -698,7 +707,6 @@ static int loopback_open(struct snd_pcm_substream *substream)
                loopback->cables[substream->number][dev] = cable;
        }
        dpcm->cable = cable;
-       cable->streams[substream->stream] = dpcm;
 
        snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
 
@@ -730,6 +738,11 @@ static int loopback_open(struct snd_pcm_substream *substream)
                runtime->hw = loopback_pcm_hardware;
        else
                runtime->hw = cable->hw;
+
+       spin_lock_irq(&cable->lock);
+       cable->streams[substream->stream] = dpcm;
+       spin_unlock_irq(&cable->lock);
+
  unlock:
        if (err < 0) {
                free_cable(substream);
@@ -744,7 +757,7 @@ static int loopback_close(struct snd_pcm_substream *substream)
        struct loopback *loopback = substream->private_data;
        struct loopback_pcm *dpcm = substream->runtime->private_data;
 
-       loopback_timer_stop(dpcm);
+       loopback_timer_stop_sync(dpcm);
        mutex_lock(&loopback->cable_lock);
        free_cable(substream);
        mutex_unlock(&loopback->cable_lock);