USB: Fix up full-speed bInterval values in high-speed interrupt descriptor
[pandora-kernel.git] / kernel / itimer.c
index 379be2f..3205e8e 100644 (file)
@@ -7,7 +7,6 @@
 /* These are all the functions necessary to implement itimers */
 
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/syscalls.h>
 #include <linux/time.h>
@@ -128,21 +127,22 @@ asmlinkage long sys_getitimer(int which, struct itimerval __user *value)
 /*
  * The timer is automagically restarted, when interval != 0
  */
-int it_real_fn(void *data)
+enum hrtimer_restart it_real_fn(struct hrtimer *timer)
 {
-       struct task_struct *tsk = (struct task_struct *) data;
+       struct signal_struct *sig =
+           container_of(timer, struct signal_struct, real_timer);
 
-       send_group_sig_info(SIGALRM, SEND_SIG_PRIV, tsk);
+       send_group_sig_info(SIGALRM, SEND_SIG_PRIV, sig->tsk);
 
-       if (tsk->signal->it_real_incr.tv64 != 0) {
-               hrtimer_forward(&tsk->signal->real_timer,
-                              tsk->signal->it_real_incr);
-
-               return HRTIMER_RESTART;
-       }
        return HRTIMER_NORESTART;
 }
 
+/*
+ * Returns true if the timeval is in canonical form
+ */
+#define timeval_valid(t) \
+       (((t)->tv_sec >= 0) && (((unsigned long) (t)->tv_usec) < USEC_PER_SEC))
+
 int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
 {
        struct task_struct *tsk = current;
@@ -150,6 +150,13 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
        ktime_t expires;
        cputime_t cval, cinterval, nval, ninterval;
 
+       /*
+        * Validate the timevals in value.
+        */
+       if (!timeval_valid(&value->it_value) ||
+           !timeval_valid(&value->it_interval))
+               return -EINVAL;
+
        switch (which) {
        case ITIMER_REAL:
 again:
@@ -165,11 +172,14 @@ again:
                        spin_unlock_irq(&tsk->sighand->siglock);
                        goto again;
                }
-               tsk->signal->it_real_incr =
-                       timeval_to_ktime(value->it_interval);
                expires = timeval_to_ktime(value->it_value);
-               if (expires.tv64 != 0)
-                       hrtimer_start(timer, expires, HRTIMER_REL);
+               if (expires.tv64 != 0) {
+                       tsk->signal->it_real_incr =
+                               timeval_to_ktime(value->it_interval);
+                       hrtimer_start(timer, expires, HRTIMER_MODE_REL);
+               } else
+                       tsk->signal->it_real_incr.tv64 = 0;
+
                spin_unlock_irq(&tsk->sighand->siglock);
                break;
        case ITIMER_VIRTUAL:
@@ -226,6 +236,43 @@ again:
        return 0;
 }
 
+/**
+ * alarm_setitimer - set alarm in seconds
+ *
+ * @seconds:   number of seconds until alarm
+ *             0 disables the alarm
+ *
+ * Returns the remaining time in seconds of a pending timer or 0 when
+ * the timer is not active.
+ *
+ * On 32 bit machines the seconds value is limited to (INT_MAX/2) to avoid
+ * negative timeval settings which would cause immediate expiry.
+ */
+unsigned int alarm_setitimer(unsigned int seconds)
+{
+       struct itimerval it_new, it_old;
+
+#if BITS_PER_LONG < 64
+       if (seconds > INT_MAX)
+               seconds = INT_MAX;
+#endif
+       it_new.it_value.tv_sec = seconds;
+       it_new.it_value.tv_usec = 0;
+       it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
+
+       do_setitimer(ITIMER_REAL, &it_new, &it_old);
+
+       /*
+        * We can't return 0 if we have an alarm pending ...  And we'd
+        * better return too much than too little anyway
+        */
+       if ((!it_old.it_value.tv_sec && it_old.it_value.tv_usec) ||
+             it_old.it_value.tv_usec >= 500000)
+               it_old.it_value.tv_sec++;
+
+       return it_old.it_value.tv_sec;
+}
+
 asmlinkage long sys_setitimer(int which,
                              struct itimerval __user *value,
                              struct itimerval __user *ovalue)