nfsd4: fix bare destroy_session null dereference
[safe/jmp/linux-2.6] / sound / core / hrtimer.c
index b712d7f..7730575 100644 (file)
@@ -1,7 +1,25 @@
 /*
+ * ALSA timer back-end using hrtimer
+ * Copyright (C) 2008 Takashi Iwai
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
  */
 
 #include <linux/init.h>
+#include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/hrtimer.h>
@@ -20,14 +38,22 @@ static unsigned int resolution;
 struct snd_hrtimer {
        struct snd_timer *timer;
        struct hrtimer hrt;
+       atomic_t running;
 };
 
 static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
 {
        struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt);
        struct snd_timer *t = stime->timer;
-       hrtimer_forward_now(hrt, ktime_set(0, t->sticks * resolution));
+
+       if (!atomic_read(&stime->running))
+               return HRTIMER_NORESTART;
+
+       hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution));
        snd_timer_interrupt(stime->timer, t->sticks);
+
+       if (!atomic_read(&stime->running))
+               return HRTIMER_NORESTART;
        return HRTIMER_RESTART;
 }
 
@@ -40,8 +66,8 @@ static int snd_hrtimer_open(struct snd_timer *t)
                return -ENOMEM;
        hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        stime->timer = t;
-       stime->hrt.cb_mode = HRTIMER_CB_SOFTIRQ;
        stime->hrt.function = snd_hrtimer_callback;
+       atomic_set(&stime->running, 0);
        t->private_data = stime;
        return 0;
 }
@@ -62,23 +88,23 @@ static int snd_hrtimer_start(struct snd_timer *t)
 {
        struct snd_hrtimer *stime = t->private_data;
 
-       hrtimer_start(&stime->hrt, ktime_set(0, t->sticks * resolution),
+       atomic_set(&stime->running, 0);
+       hrtimer_cancel(&stime->hrt);
+       hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution),
                      HRTIMER_MODE_REL);
+       atomic_set(&stime->running, 1);
        return 0;
 }
 
 static int snd_hrtimer_stop(struct snd_timer *t)
 {
        struct snd_hrtimer *stime = t->private_data;
-
-       hrtimer_cancel(&stime->hrt);
+       atomic_set(&stime->running, 0);
        return 0;
 }
 
 static struct snd_timer_hardware hrtimer_hw = {
-       .flags =        (SNDRV_TIMER_HW_AUTO |
-                        /*SNDRV_TIMER_HW_FIRST |*/
-                        SNDRV_TIMER_HW_TASKLET),
+       .flags =        SNDRV_TIMER_HW_AUTO,
        .open =         snd_hrtimer_open,
        .close =        snd_hrtimer_close,
        .start =        snd_hrtimer_start,