ALSA: timer: Fix zero-division by continue of uninitialized instance
[pandora-kernel.git] / sound / core / timer.c
index ffecc44..5628b65 100644 (file)
@@ -34,6 +34,9 @@
 #include <sound/initval.h>
 #include <linux/kmod.h>
 
+/* internal flags */
+#define SNDRV_TIMER_IFLG_PAUSED                0x00010000
+
 #if defined(CONFIG_SND_HRTIMER) || defined(CONFIG_SND_HRTIMER_MODULE)
 #define DEFAULT_TIMER_LIMIT 4
 #elif defined(CONFIG_SND_RTCTIMER) || defined(CONFIG_SND_RTCTIMER_MODULE)
@@ -552,6 +555,10 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, int event)
                }
        }
        timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START);
+       if (event == SNDRV_TIMER_EVENT_STOP)
+               timeri->flags &= ~SNDRV_TIMER_IFLG_PAUSED;
+       else
+               timeri->flags |= SNDRV_TIMER_IFLG_PAUSED;
        spin_unlock_irqrestore(&timer->lock, flags);
       __end:
        if (event != SNDRV_TIMER_EVENT_RESOLUTION)
@@ -594,6 +601,10 @@ int snd_timer_continue(struct snd_timer_instance *timeri)
 
        if (timeri == NULL)
                return result;
+       /* timer can continue only after pause */
+       if (!(timeri->flags & SNDRV_TIMER_IFLG_PAUSED))
+               return -EINVAL;
+
        if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
                return snd_timer_start_slave(timeri);
        timer = timeri->timer;
@@ -1798,6 +1809,9 @@ static int snd_timer_user_continue(struct file *file)
        tu = file->private_data;
        if (!tu->timeri)
                return -EBADFD;
+       /* start timer instead of continue if it's not used before */
+       if (!(tu->timeri->flags & SNDRV_TIMER_IFLG_PAUSED))
+               return snd_timer_user_start(file);
        tu->timeri->lost = 0;
        return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
 }