]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/media/IR/ir-raw-event.c
617e437e2bebb22181e93733b2153d2eeb05fd4f
[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             *evs;
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(*evs);
149         if (!len)
150                 return 0;
151         evs = kmalloc(len * sizeof(*evs), GFP_ATOMIC);
152
153         for (i = 0; i < len; i++) {
154                 rc = kfifo_out(&ir->raw->kfifo, &evs[i], sizeof(*evs));
155                 if (rc != sizeof(*evs)) {
156                         IR_dprintk(1, "overflow error: received %d instead of %zd\n",
157                                    rc, sizeof(*evs));
158                         return -EINVAL;
159                 }
160                 IR_dprintk(2, "event type %d, time before event: %07luus\n",
161                         evs[i].type, (evs[i].delta.tv_nsec + 500) / 1000);
162         }
163
164         /*
165          * Call all ir decoders. This allows decoding the same event with
166          * more than one protocol handler. It returns the number of keystrokes
167          * sent to the event interface
168          */
169         rc = RUN_DECODER(decode, input_dev, evs, len);
170
171         kfree(evs);
172
173         return rc;
174 }
175 EXPORT_SYMBOL_GPL(ir_raw_event_handle);
176
177 /*
178  * Extension interface - used to register the IR decoders
179  */
180
181 int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
182 {
183         spin_lock(&ir_raw_handler_lock);
184         list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
185         spin_unlock(&ir_raw_handler_lock);
186         return 0;
187 }
188 EXPORT_SYMBOL(ir_raw_handler_register);
189
190 void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
191 {
192         spin_lock(&ir_raw_handler_lock);
193         list_del(&ir_raw_handler->list);
194         spin_unlock(&ir_raw_handler_lock);
195 }
196 EXPORT_SYMBOL(ir_raw_handler_unregister);
197
198 static void init_decoders(struct work_struct *work)
199 {
200         /* Load the decoder modules */
201
202         load_nec_decode();
203         load_rc5_decode();
204
205         /* If needed, we may later add some init code. In this case,
206            it is needed to change the CONFIG_MODULE test at ir-core.h
207          */
208 }
209
210 void ir_raw_init(void)
211 {
212         spin_lock_init(&ir_raw_handler_lock);
213
214 #ifdef MODULE
215         INIT_WORK(&wq_load, init_decoders);
216         schedule_work(&wq_load);
217 #endif
218 }