summaryrefslogtreecommitdiffstats
path: root/drivers/media/IR/ir-raw-event.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2010-03-20 20:59:44 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-05-18 00:52:56 -0300
commita3572c34da8dacc78a629211a91cf34e9b408701 (patch)
tree281efd4d69b68bd4720668fd91cfcf16d1ed3089 /drivers/media/IR/ir-raw-event.c
parent0210894956cf57d525d56341cc3e0f3d5d2db659 (diff)
V4L/DVB: ir-core: Add logic to decode IR protocols at the IR core
Adds a method to pass IR raw pulse/code events into ir-core. This is needed in order to support LIRC. It also helps to move common code from the drivers into the core. In order to allow testing, it implements a simple NEC protocol decoder at ir-nec-decoder.c file. The logic is about the same used at saa7134 driver that handles Avermedia M135A and Encore FM53 boards. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/IR/ir-raw-event.c')
-rw-r--r--drivers/media/IR/ir-raw-event.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c
new file mode 100644
index 000000000000..9c71ac858923
--- /dev/null
+++ b/drivers/media/IR/ir-raw-event.c
@@ -0,0 +1,117 @@
+/* ir-raw-event.c - handle IR Pulse/Space event
+ *
+ * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * 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 version 2 of the License.
+ *
+ * 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.
+ */
+
+#include <media/ir-core.h>
+
+/* Define the max number of bit transitions per IR keycode */
+#define MAX_IR_EVENT_SIZE 256
+
+int ir_raw_event_register(struct input_dev *input_dev)
+{
+ struct ir_input_dev *ir = input_get_drvdata(input_dev);
+ int rc, size;
+
+ ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
+
+ size = sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE * 2;
+ size = roundup_pow_of_two(size);
+
+ rc = kfifo_alloc(&ir->raw->kfifo, size, GFP_KERNEL);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_register);
+
+void ir_raw_event_unregister(struct input_dev *input_dev)
+{
+ struct ir_input_dev *ir = input_get_drvdata(input_dev);
+
+ if (!ir->raw)
+ return;
+
+ 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)
+{
+ struct ir_input_dev *ir = input_get_drvdata(input_dev);
+ struct timespec ts;
+ struct ir_raw_event event;
+ int rc;
+
+ if (!ir->raw)
+ return -EINVAL;
+
+ event.type = type;
+ event.delta.tv_sec = 0;
+ event.delta.tv_nsec = 0;
+
+ ktime_get_ts(&ts);
+
+ if (timespec_equal(&ir->raw->last_event, &event.delta))
+ event.type |= IR_START_EVENT;
+ else
+ event.delta = timespec_sub(ts, ir->raw->last_event);
+
+ memcpy(&ir->raw->last_event, &ts, sizeof(ts));
+
+ if (event.delta.tv_sec) {
+ event.type |= IR_START_EVENT;
+ event.delta.tv_sec = 0;
+ event.delta.tv_nsec = 0;
+ }
+
+ kfifo_in(&ir->raw->kfifo, &event, sizeof(event));
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_store);
+
+int 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 *evs;
+ 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(*evs);
+ if (!len)
+ return 0;
+ evs = kmalloc(len * sizeof(*evs), GFP_ATOMIC);
+
+ for (i = 0; i < len; i++) {
+ rc = kfifo_out(&ir->raw->kfifo, &evs[i], sizeof(*evs));
+ if (rc != sizeof(*evs)) {
+ IR_dprintk(1, "overflow error: received %d instead of %zd\n",
+ rc, sizeof(*evs));
+ return -EINVAL;
+ }
+ IR_dprintk(2, "event type %d, time before event: %07luus\n",
+ evs[i].type, (evs[i].delta.tv_nsec + 500) / 1000);
+ }
+
+ rc = ir_nec_decode(input_dev, evs, len);
+
+ kfree(evs);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_handle);