]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/media/IR/ir-raw-event.c
V4L-DVB: ir-core: remove the ancillary buffer
[net-next-2.6.git] / drivers / media / IR / ir-raw-event.c
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 #include <linux/workqueue.h>
17 #include <linux/spinlock.h>
18
19 /* Define the max number of bit transitions per IR keycode */
20 #define MAX_IR_EVENT_SIZE       256
21
22 /* Used to handle IR raw handler extensions */
23 static LIST_HEAD(ir_raw_handler_list);
24 static spinlock_t ir_raw_handler_lock;
25
26 /**
27  * RUN_DECODER()        - runs an operation on all IR decoders
28  * @ops:        IR raw handler operation to be called
29  * @arg:        arguments to be passed to the callback
30  *
31  * Calls ir_raw_handler::ops for all registered IR handlers. It prevents
32  * new decode addition/removal while running, by locking ir_raw_handler_lock
33  * mutex. If an error occurs, it stops the ops. Otherwise, it returns a sum
34  * of the return codes.
35  */
36 #define RUN_DECODER(ops, ...) ({                                            \
37         struct ir_raw_handler           *_ir_raw_handler;                   \
38         int _sumrc = 0, _rc;                                                \
39         spin_lock(&ir_raw_handler_lock);                                    \
40         list_for_each_entry(_ir_raw_handler, &ir_raw_handler_list, list) {  \
41                 if (_ir_raw_handler->ops) {                                 \
42                         _rc = _ir_raw_handler->ops(__VA_ARGS__);            \
43                         if (_rc < 0)                                        \
44                                 break;                                      \
45                         _sumrc += _rc;                                      \
46                 }                                                           \
47         }                                                                   \
48         spin_unlock(&ir_raw_handler_lock);                                  \
49         _sumrc;                                                             \
50 })
51
52
53 /* Used to load the decoders */
54 static struct work_struct wq_load;
55
56 int ir_raw_event_register(struct input_dev *input_dev)
57 {
58         struct ir_input_dev *ir = input_get_drvdata(input_dev);
59         int rc, size;
60
61         ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
62         if (!ir->raw)
63                 return -ENOMEM;
64
65         size = sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE * 2;
66         size = roundup_pow_of_two(size);
67
68         rc = kfifo_alloc(&ir->raw->kfifo, size, GFP_KERNEL);
69         if (rc < 0) {
70                 kfree(ir->raw);
71                 ir->raw = NULL;
72                 return rc;
73         }
74
75         rc = RUN_DECODER(raw_register, input_dev);
76         if (rc < 0) {
77                 kfifo_free(&ir->raw->kfifo);
78                 kfree(ir->raw);
79                 ir->raw = NULL;
80                 return rc;
81         }
82
83         return rc;
84 }
85 EXPORT_SYMBOL_GPL(ir_raw_event_register);
86
87 void ir_raw_event_unregister(struct input_dev *input_dev)
88 {
89         struct ir_input_dev *ir = input_get_drvdata(input_dev);
90
91         if (!ir->raw)
92                 return;
93
94         RUN_DECODER(raw_unregister, input_dev);
95
96         kfifo_free(&ir->raw->kfifo);
97         kfree(ir->raw);
98         ir->raw = NULL;
99 }
100 EXPORT_SYMBOL_GPL(ir_raw_event_unregister);
101
102 int ir_raw_event_store(struct input_dev *input_dev, enum raw_event_type type)
103 {
104         struct ir_input_dev     *ir = input_get_drvdata(input_dev);
105         struct timespec         ts;
106         struct ir_raw_event     event;
107         int                     rc;
108
109         if (!ir->raw)
110                 return -EINVAL;
111
112         event.type = type;
113         event.delta.tv_sec = 0;
114         event.delta.tv_nsec = 0;
115
116         ktime_get_ts(&ts);
117
118         if (timespec_equal(&ir->raw->last_event, &event.delta))
119                 event.type |= IR_START_EVENT;
120         else
121                 event.delta = timespec_sub(ts, ir->raw->last_event);
122
123         memcpy(&ir->raw->last_event, &ts, sizeof(ts));
124
125         if (event.delta.tv_sec) {
126                 event.type |= IR_START_EVENT;
127                 event.delta.tv_sec = 0;
128                 event.delta.tv_nsec = 0;
129         }
130
131         kfifo_in(&ir->raw->kfifo, &event, sizeof(event));
132
133         return rc;
134 }
135 EXPORT_SYMBOL_GPL(ir_raw_event_store);
136
137 int ir_raw_event_handle(struct input_dev *input_dev)
138 {
139         struct ir_input_dev             *ir = input_get_drvdata(input_dev);
140         int                             rc;
141         struct ir_raw_event             ev;
142         int                             len, i;
143
144         /*
145          * Store the events into a temporary buffer. This allows calling more than
146          * one decoder to deal with the received data
147          */
148         len = kfifo_len(&ir->raw->kfifo) / sizeof(ev);
149         if (!len)
150                 return 0;
151
152         for (i = 0; i < len; i++) {
153                 rc = kfifo_out(&ir->raw->kfifo, &ev, sizeof(ev));
154                 if (rc != sizeof(ev)) {
155                         IR_dprintk(1, "overflow error: received %d instead of %zd\n",
156                                    rc, sizeof(ev));
157                         return -EINVAL;
158                 }
159                 IR_dprintk(2, "event type %d, time before event: %07luus\n",
160                         ev.type, (ev.delta.tv_nsec + 500) / 1000);
161                 rc = RUN_DECODER(decode, input_dev, &ev);
162         }
163
164         /*
165          * Call all ir decoders. This allows decoding the same event with
166          * more than one protocol handler.
167          */
168
169         return rc;
170 }
171 EXPORT_SYMBOL_GPL(ir_raw_event_handle);
172
173 /*
174  * Extension interface - used to register the IR decoders
175  */
176
177 int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
178 {
179         spin_lock(&ir_raw_handler_lock);
180         list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
181         spin_unlock(&ir_raw_handler_lock);
182         return 0;
183 }
184 EXPORT_SYMBOL(ir_raw_handler_register);
185
186 void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
187 {
188         spin_lock(&ir_raw_handler_lock);
189         list_del(&ir_raw_handler->list);
190         spin_unlock(&ir_raw_handler_lock);
191 }
192 EXPORT_SYMBOL(ir_raw_handler_unregister);
193
194 static void init_decoders(struct work_struct *work)
195 {
196         /* Load the decoder modules */
197
198         load_nec_decode();
199         load_rc5_decode();
200
201         /* If needed, we may later add some init code. In this case,
202            it is needed to change the CONFIG_MODULE test at ir-core.h
203          */
204 }
205
206 void ir_raw_init(void)
207 {
208         spin_lock_init(&ir_raw_handler_lock);
209
210 #ifdef MODULE
211         INIT_WORK(&wq_load, init_decoders);
212         schedule_work(&wq_load);
213 #endif
214 }