Merge branch 'imx-for-2.6.38' of git://git.pengutronix.de/git/ukl/linux-2.6 into...
[pandora-kernel.git] / drivers / media / IR / ir-raw-event.c
index 8e0e1b1..a06a07e 100644 (file)
@@ -39,22 +39,34 @@ static int ir_raw_event_thread(void *data)
        struct ir_raw_event ev;
        struct ir_raw_handler *handler;
        struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
+       int retval;
 
        while (!kthread_should_stop()) {
-               try_to_freeze();
 
-               mutex_lock(&ir_raw_handler_lock);
+               spin_lock_irq(&raw->lock);
+               retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
+
+               if (!retval) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+
+                       if (kthread_should_stop())
+                               set_current_state(TASK_RUNNING);
 
-               while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) {
-                       list_for_each_entry(handler, &ir_raw_handler_list, list)
-                               handler->decode(raw->input_dev, ev);
-                       raw->prev_ev = ev;
+                       spin_unlock_irq(&raw->lock);
+                       schedule();
+                       continue;
                }
 
-               mutex_unlock(&ir_raw_handler_lock);
+               spin_unlock_irq(&raw->lock);
+
 
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule();
+               BUG_ON(retval != sizeof(ev));
+
+               mutex_lock(&ir_raw_handler_lock);
+               list_for_each_entry(handler, &ir_raw_handler_list, list)
+                       handler->decode(raw->input_dev, ev);
+               raw->prev_ev = ev;
+               mutex_unlock(&ir_raw_handler_lock);
        }
 
        return 0;
@@ -77,7 +89,7 @@ int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev)
        if (!ir->raw)
                return -EINVAL;
 
-       IR_dprintk(2, "sample: (05%dus %s)\n",
+       IR_dprintk(2, "sample: (%05dus %s)\n",
                TO_US(ev->duration), TO_STR(ev->pulse));
 
        if (kfifo_in(&ir->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
@@ -162,7 +174,7 @@ int ir_raw_event_store_with_filter(struct input_dev *input_dev,
        if (ir->idle && !ev->pulse)
                return 0;
        else if (ir->idle)
-               ir_raw_event_set_idle(input_dev, 0);
+               ir_raw_event_set_idle(input_dev, false);
 
        if (!raw->this_ev.duration) {
                raw->this_ev = *ev;
@@ -175,48 +187,35 @@ int ir_raw_event_store_with_filter(struct input_dev *input_dev,
 
        /* Enter idle mode if nessesary */
        if (!ev->pulse && ir->props->timeout &&
-               raw->this_ev.duration >= ir->props->timeout)
-               ir_raw_event_set_idle(input_dev, 1);
+               raw->this_ev.duration >= ir->props->timeout) {
+               ir_raw_event_set_idle(input_dev, true);
+       }
        return 0;
 }
 EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
 
-void ir_raw_event_set_idle(struct input_dev *input_dev, int idle)
+/**
+ * ir_raw_event_set_idle() - hint the ir core if device is receiving
+ * IR data or not
+ * @input_dev: the struct input_dev device descriptor
+ * @idle: the hint value
+ */
+void ir_raw_event_set_idle(struct input_dev *input_dev, bool idle)
 {
        struct ir_input_dev *ir = input_get_drvdata(input_dev);
        struct ir_raw_event_ctrl *raw = ir->raw;
-       ktime_t now;
-       u64 delta;
 
-       if (!ir->props)
+       if (!ir->props || !ir->raw)
                return;
 
-       if (!ir->raw)
-               goto out;
+       IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
 
        if (idle) {
-               IR_dprintk(2, "enter idle mode\n");
-               raw->last_event = ktime_get();
-       } else {
-               IR_dprintk(2, "exit idle mode\n");
-
-               now = ktime_get();
-               delta = ktime_to_ns(ktime_sub(now, ir->raw->last_event));
-
-               WARN_ON(raw->this_ev.pulse);
-
-               raw->this_ev.duration =
-                       min(raw->this_ev.duration + delta,
-                                               (u64)IR_MAX_DURATION);
-
+               raw->this_ev.timeout = true;
                ir_raw_event_store(input_dev, &raw->this_ev);
-
-               if (raw->this_ev.duration == IR_MAX_DURATION)
-                       ir_raw_event_reset(input_dev);
-
-               raw->this_ev.duration = 0;
+               init_ir_raw_event(&raw->this_ev);
        }
-out:
+
        if (ir->props->s_idle)
                ir->props->s_idle(ir->props->priv, idle);
        ir->idle = idle;
@@ -232,11 +231,14 @@ EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
 void ir_raw_event_handle(struct input_dev *input_dev)
 {
        struct ir_input_dev *ir = input_get_drvdata(input_dev);
+       unsigned long flags;
 
        if (!ir->raw)
                return;
 
+       spin_lock_irqsave(&ir->raw->lock, flags);
        wake_up_process(ir->raw->thread);
+       spin_unlock_irqrestore(&ir->raw->lock, flags);
 }
 EXPORT_SYMBOL_GPL(ir_raw_event_handle);
 
@@ -275,6 +277,7 @@ int ir_raw_event_register(struct input_dev *input_dev)
                return rc;
        }
 
+       spin_lock_init(&ir->raw->lock);
        ir->raw->thread = kthread_run(ir_raw_event_thread, ir->raw,
                        "rc%u",  (unsigned int)ir->devno);