diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-03-20 19:59:44 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-05-17 23:52:56 -0400 |
commit | a3572c34da8dacc78a629211a91cf34e9b408701 (patch) | |
tree | 281efd4d69b68bd4720668fd91cfcf16d1ed3089 /drivers/media/IR/ir-raw-event.c | |
parent | 0210894956cf57d525d56341cc3e0f3d5d2db659 (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.c | 117 |
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 | |||
20 | int 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 | } | ||
34 | EXPORT_SYMBOL_GPL(ir_raw_event_register); | ||
35 | |||
36 | void 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 | } | ||
47 | EXPORT_SYMBOL_GPL(ir_raw_event_unregister); | ||
48 | |||
49 | int 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 | } | ||
82 | EXPORT_SYMBOL_GPL(ir_raw_event_store); | ||
83 | |||
84 | int 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 | } | ||
117 | EXPORT_SYMBOL_GPL(ir_raw_event_handle); | ||