]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/media/IR/ir-raw-event.c
Merge branch 'master' into for-linus
[mv-sheeva.git] / drivers / media / IR / ir-raw-event.c
index ddb3365adc82faa12bcd59b5e720bab21d6018b6..ea68a3f2effa1a973926e873f86e24ee48a7f4ab 100644 (file)
  *  GNU General Public License for more details.
  */
 
-#include <media/ir-core.h>
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
+#include <linux/sched.h>
+#include "ir-core-priv.h"
 
-/* Define the max number of bit transitions per IR keycode */
-#define MAX_IR_EVENT_SIZE      256
+/* Define the max number of pulse/space transitions to buffer */
+#define MAX_IR_EVENT_SIZE      512
 
 /* Used to handle IR raw handler extensions */
 static LIST_HEAD(ir_raw_handler_list);
@@ -49,23 +50,35 @@ static DEFINE_SPINLOCK(ir_raw_handler_lock);
        _sumrc;                                                             \
 })
 
-
+#ifdef MODULE
 /* Used to load the decoders */
 static struct work_struct wq_load;
+#endif
+
+static void ir_raw_event_work(struct work_struct *work)
+{
+       struct ir_raw_event ev;
+       struct ir_raw_event_ctrl *raw =
+               container_of(work, struct ir_raw_event_ctrl, rx_work);
+
+       while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev))
+               RUN_DECODER(decode, raw->input_dev, ev);
+}
 
 int ir_raw_event_register(struct input_dev *input_dev)
 {
        struct ir_input_dev *ir = input_get_drvdata(input_dev);
-       int rc, size;
+       int rc;
 
        ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
        if (!ir->raw)
                return -ENOMEM;
 
-       size = sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE * 2;
-       size = roundup_pow_of_two(size);
+       ir->raw->input_dev = input_dev;
+       INIT_WORK(&ir->raw->rx_work, ir_raw_event_work);
 
-       rc = kfifo_alloc(&ir->raw->kfifo, size, GFP_KERNEL);
+       rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE,
+                        GFP_KERNEL);
        if (rc < 0) {
                kfree(ir->raw);
                ir->raw = NULL;
@@ -82,7 +95,6 @@ int ir_raw_event_register(struct input_dev *input_dev)
 
        return rc;
 }
-EXPORT_SYMBOL_GPL(ir_raw_event_register);
 
 void ir_raw_event_unregister(struct input_dev *input_dev)
 {
@@ -91,82 +103,104 @@ void ir_raw_event_unregister(struct input_dev *input_dev)
        if (!ir->raw)
                return;
 
+       cancel_work_sync(&ir->raw->rx_work);
        RUN_DECODER(raw_unregister, input_dev);
 
        kfifo_free(&ir->raw->kfifo);
        kfree(ir->raw);
        ir->raw = NULL;
 }
-EXPORT_SYMBOL_GPL(ir_raw_event_unregister);
 
-int ir_raw_event_store(struct input_dev *input_dev, enum raw_event_type type)
+/**
+ * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
+ * @input_dev: the struct input_dev device descriptor
+ * @ev:                the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This routine (which may be called from an interrupt context) stores a
+ * pulse/space duration for the raw ir decoding state machines. Pulses are
+ * signalled as positive values and spaces as negative values. A zero value
+ * will reset the decoding state machines.
+ */
+int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev)
 {
-       struct ir_input_dev     *ir = input_get_drvdata(input_dev);
-       struct timespec         ts;
-       struct ir_raw_event     event;
-       int                     rc;
+       struct ir_input_dev *ir = input_get_drvdata(input_dev);
 
        if (!ir->raw)
                return -EINVAL;
 
-       event.type = type;
-       event.delta.tv_sec = 0;
-       event.delta.tv_nsec = 0;
+       if (kfifo_in(&ir->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
+               return -ENOMEM;
 
-       ktime_get_ts(&ts);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_store);
 
-       if (timespec_equal(&ir->raw->last_event, &event.delta))
-               event.type |= IR_START_EVENT;
-       else
-               event.delta = timespec_sub(ts, ir->raw->last_event);
+/**
+ * ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space
+ * @input_dev: the struct input_dev device descriptor
+ * @type:      the type of the event that has occurred
+ *
+ * This routine (which may be called from an interrupt context) is used to
+ * store the beginning of an ir pulse or space (or the start/end of ir
+ * reception) for the raw ir decoding state machines. This is used by
+ * hardware which does not provide durations directly but only interrupts
+ * (or similar events) on state change.
+ */
+int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type type)
+{
+       struct ir_input_dev     *ir = input_get_drvdata(input_dev);
+       ktime_t                 now;
+       s64                     delta; /* ns */
+       struct ir_raw_event     ev;
+       int                     rc = 0;
 
-       memcpy(&ir->raw->last_event, &ts, sizeof(ts));
+       if (!ir->raw)
+               return -EINVAL;
 
-       if (event.delta.tv_sec) {
-               event.type |= IR_START_EVENT;
-               event.delta.tv_sec = 0;
-               event.delta.tv_nsec = 0;
-       }
+       now = ktime_get();
+       delta = ktime_to_ns(ktime_sub(now, ir->raw->last_event));
 
-       kfifo_in(&ir->raw->kfifo, &event, sizeof(event));
+       /* Check for a long duration since last event or if we're
+        * being called for the first time, note that delta can't
+        * possibly be negative.
+        */
+       ev.duration = 0;
+       if (delta > IR_MAX_DURATION || !ir->raw->last_type)
+               type |= IR_START_EVENT;
+       else
+               ev.duration = delta;
+
+       if (type & IR_START_EVENT)
+               ir_raw_event_reset(input_dev);
+       else if (ir->raw->last_type & IR_SPACE) {
+               ev.pulse = false;
+               rc = ir_raw_event_store(input_dev, &ev);
+       } else if (ir->raw->last_type & IR_PULSE) {
+               ev.pulse = true;
+               rc = ir_raw_event_store(input_dev, &ev);
+       } else
+               return 0;
 
+       ir->raw->last_event = now;
+       ir->raw->last_type = type;
        return rc;
 }
-EXPORT_SYMBOL_GPL(ir_raw_event_store);
+EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
 
-int ir_raw_event_handle(struct input_dev *input_dev)
+/**
+ * ir_raw_event_handle() - schedules the decoding of stored ir data
+ * @input_dev: the struct input_dev device descriptor
+ *
+ * This routine will signal the workqueue to start decoding stored ir data.
+ */
+void ir_raw_event_handle(struct input_dev *input_dev)
 {
-       struct ir_input_dev             *ir = input_get_drvdata(input_dev);
-       int                             rc;
-       struct ir_raw_event             ev;
-       int                             len, i;
-
-       /*
-        * Store the events into a temporary buffer. This allows calling more than
-        * one decoder to deal with the received data
-        */
-       len = kfifo_len(&ir->raw->kfifo) / sizeof(ev);
-       if (!len)
-               return 0;
-
-       for (i = 0; i < len; i++) {
-               rc = kfifo_out(&ir->raw->kfifo, &ev, sizeof(ev));
-               if (rc != sizeof(ev)) {
-                       IR_dprintk(1, "overflow error: received %d instead of %zd\n",
-                                  rc, sizeof(ev));
-                       return -EINVAL;
-               }
-               IR_dprintk(2, "event type %d, time before event: %07luus\n",
-                       ev.type, (ev.delta.tv_nsec + 500) / 1000);
-               rc = RUN_DECODER(decode, input_dev, &ev);
-       }
+       struct ir_input_dev *ir = input_get_drvdata(input_dev);
 
-       /*
-        * Call all ir decoders. This allows decoding the same event with
-        * more than one protocol handler.
-        */
+       if (!ir->raw)
+               return;
 
-       return rc;
+       schedule_work(&ir->raw->rx_work);
 }
 EXPORT_SYMBOL_GPL(ir_raw_event_handle);
 
@@ -191,17 +225,22 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
 }
 EXPORT_SYMBOL(ir_raw_handler_unregister);
 
+#ifdef MODULE
 static void init_decoders(struct work_struct *work)
 {
        /* Load the decoder modules */
 
        load_nec_decode();
        load_rc5_decode();
+       load_rc6_decode();
+       load_jvc_decode();
+       load_sony_decode();
 
        /* If needed, we may later add some init code. In this case,
           it is needed to change the CONFIG_MODULE test at ir-core.h
         */
 }
+#endif
 
 void ir_raw_init(void)
 {