aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/IR/ir-raw-event.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2010-03-20 19:59:44 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-05-17 23:52:56 -0400
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 @@
1/* ir-raw-event.c - handle IR Pulse/Space event
2 *
3 * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <media/ir-core.h>
16
17/* Define the max number of bit transitions per IR keycode */
18#define MAX_IR_EVENT_SIZE 256
19
20int ir_raw_event_register(struct input_dev *input_dev)
21{
22 struct ir_input_dev *ir = input_get_drvdata(input_dev);
23 int rc, size;
24
25 ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
26
27 size = sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE * 2;
28 size = roundup_pow_of_two(size);
29
30 rc = kfifo_alloc(&ir->raw->kfifo, size, GFP_KERNEL);
31
32 return rc;
33}
34EXPORT_SYMBOL_GPL(ir_raw_event_register);
35
36void ir_raw_event_unregister(struct input_dev *input_dev)
37{
38 struct ir_input_dev *ir = input_get_drvdata(input_dev);
39
40 if (!ir->raw)
41 return;
42
43 kfifo_free(&ir->raw->kfifo);
44 kfree(ir->raw);
45 ir->raw = NULL;
46}
47EXPORT_SYMBOL_GPL(ir_raw_event_unregister);
48
49int ir_raw_event_store(struct input_dev *input_dev, enum raw_event_type type)
50{
51 struct ir_input_dev *ir = input_get_drvdata(input_dev);
52 struct timespec ts;
53 struct ir_raw_event event;
54 int rc;
55
56 if (!ir->raw)
57 return -EINVAL;
58
59 event.type = type;
60 event.delta.tv_sec = 0;
61 event.delta.tv_nsec = 0;
62
63 ktime_get_ts(&ts);
64
65 if (timespec_equal(&ir->raw->last_event, &event.delta))
66 event.type |= IR_START_EVENT;
67 else
68 event.delta = timespec_sub(ts, ir->raw->last_event);
69
70 memcpy(&ir->raw->last_event, &ts, sizeof(ts));
71
72 if (event.delta.tv_sec) {
73 event.type |= IR_START_EVENT;
74 event.delta.tv_sec = 0;
75 event.delta.tv_nsec = 0;
76 }
77
78 kfifo_in(&ir->raw->kfifo, &event, sizeof(event));
79
80 return rc;
81}
82EXPORT_SYMBOL_GPL(ir_raw_event_store);
83
84int ir_raw_event_handle(struct input_dev *input_dev)
85{
86 struct ir_input_dev *ir = input_get_drvdata(input_dev);
87 int rc;
88 struct ir_raw_event *evs;
89 int len, i;
90
91 /*
92 * Store the events into a temporary buffer. This allows calling more than
93 * one decoder to deal with the received data
94 */
95 len = kfifo_len(&ir->raw->kfifo) / sizeof(*evs);
96 if (!len)
97 return 0;
98 evs = kmalloc(len * sizeof(*evs), GFP_ATOMIC);
99
100 for (i = 0; i < len; i++) {
101 rc = kfifo_out(&ir->raw->kfifo, &evs[i], sizeof(*evs));
102 if (rc != sizeof(*evs)) {
103 IR_dprintk(1, "overflow error: received %d instead of %zd\n",
104 rc, sizeof(*evs));
105 return -EINVAL;
106 }
107 IR_dprintk(2, "event type %d, time before event: %07luus\n",
108 evs[i].type, (evs[i].delta.tv_nsec + 500) / 1000);
109 }
110
111 rc = ir_nec_decode(input_dev, evs, len);
112
113 kfree(evs);
114
115 return rc;
116}
117EXPORT_SYMBOL_GPL(ir_raw_event_handle);