diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-12-11 06:00:00 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-12-15 21:18:42 -0500 |
commit | e27d38112eb727df189a9ebf560aa104cb102253 (patch) | |
tree | 454d8cff41ebe8027ecd74d809ed415e427782b3 /drivers/media/IR/ir-functions.c | |
parent | 909d15a70d6a269ba599c539c55a574482355ff1 (diff) |
V4L/DVB (13612): IR: Move common IR code to drivers/media/IR
This is the first step of creating a common code for IR that can be
used by other input devices.
For now, keep IR dir at drivers/media, to easy the movement of the IR files,
but later patches may move it to drivers/IR or drivers/input/IR.
No functional changes is done on this patch.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/IR/ir-functions.c')
-rw-r--r-- | drivers/media/IR/ir-functions.c | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/drivers/media/IR/ir-functions.c b/drivers/media/IR/ir-functions.c new file mode 100644 index 000000000000..e616f624ceaa --- /dev/null +++ b/drivers/media/IR/ir-functions.c | |||
@@ -0,0 +1,373 @@ | |||
1 | /* | ||
2 | * | ||
3 | * some common structs and functions to handle infrared remotes via | ||
4 | * input layer ... | ||
5 | * | ||
6 | * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/string.h> | ||
25 | #include <linux/jiffies.h> | ||
26 | #include <media/ir-common.h> | ||
27 | |||
28 | /* -------------------------------------------------------------------------- */ | ||
29 | |||
30 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | static int repeat = 1; | ||
34 | module_param(repeat, int, 0444); | ||
35 | MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)"); | ||
36 | |||
37 | int media_ir_debug; /* media_ir_debug level (0,1,2) */ | ||
38 | module_param_named(debug, media_ir_debug, int, 0644); | ||
39 | |||
40 | /* -------------------------------------------------------------------------- */ | ||
41 | |||
42 | static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir) | ||
43 | { | ||
44 | if (KEY_RESERVED == ir->keycode) { | ||
45 | printk(KERN_INFO "%s: unknown key: key=0x%02x down=%d\n", | ||
46 | dev->name, ir->ir_key, ir->keypressed); | ||
47 | return; | ||
48 | } | ||
49 | IR_dprintk(1,"%s: key event code=%d down=%d\n", | ||
50 | dev->name,ir->keycode,ir->keypressed); | ||
51 | input_report_key(dev,ir->keycode,ir->keypressed); | ||
52 | input_sync(dev); | ||
53 | } | ||
54 | |||
55 | /* -------------------------------------------------------------------------- */ | ||
56 | |||
57 | int ir_input_init(struct input_dev *dev, struct ir_input_state *ir, | ||
58 | int ir_type, struct ir_scancode_table *ir_codes) | ||
59 | { | ||
60 | ir->ir_type = ir_type; | ||
61 | |||
62 | ir->keytable.size = ir_roundup_tablesize(ir_codes->size); | ||
63 | ir->keytable.scan = kzalloc(ir->keytable.size * | ||
64 | sizeof(struct ir_scancode), GFP_KERNEL); | ||
65 | if (!ir->keytable.scan) | ||
66 | return -ENOMEM; | ||
67 | |||
68 | IR_dprintk(1, "Allocated space for %d keycode entries (%zd bytes)\n", | ||
69 | ir->keytable.size, | ||
70 | ir->keytable.size * sizeof(ir->keytable.scan)); | ||
71 | |||
72 | ir_copy_table(&ir->keytable, ir_codes); | ||
73 | ir_set_keycode_table(dev, &ir->keytable); | ||
74 | |||
75 | clear_bit(0, dev->keybit); | ||
76 | set_bit(EV_KEY, dev->evbit); | ||
77 | if (repeat) | ||
78 | set_bit(EV_REP, dev->evbit); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | EXPORT_SYMBOL_GPL(ir_input_init); | ||
83 | |||
84 | |||
85 | void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir) | ||
86 | { | ||
87 | if (ir->keypressed) { | ||
88 | ir->keypressed = 0; | ||
89 | ir_input_key_event(dev,ir); | ||
90 | } | ||
91 | } | ||
92 | EXPORT_SYMBOL_GPL(ir_input_nokey); | ||
93 | |||
94 | void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir, | ||
95 | u32 ir_key) | ||
96 | { | ||
97 | u32 keycode = ir_g_keycode_from_table(dev, ir_key); | ||
98 | |||
99 | if (ir->keypressed && ir->keycode != keycode) { | ||
100 | ir->keypressed = 0; | ||
101 | ir_input_key_event(dev,ir); | ||
102 | } | ||
103 | if (!ir->keypressed) { | ||
104 | ir->ir_key = ir_key; | ||
105 | ir->keycode = keycode; | ||
106 | ir->keypressed = 1; | ||
107 | ir_input_key_event(dev,ir); | ||
108 | } | ||
109 | } | ||
110 | EXPORT_SYMBOL_GPL(ir_input_keydown); | ||
111 | |||
112 | /* -------------------------------------------------------------------------- */ | ||
113 | /* extract mask bits out of data and pack them into the result */ | ||
114 | u32 ir_extract_bits(u32 data, u32 mask) | ||
115 | { | ||
116 | u32 vbit = 1, value = 0; | ||
117 | |||
118 | do { | ||
119 | if (mask&1) { | ||
120 | if (data&1) | ||
121 | value |= vbit; | ||
122 | vbit<<=1; | ||
123 | } | ||
124 | data>>=1; | ||
125 | } while (mask>>=1); | ||
126 | |||
127 | return value; | ||
128 | } | ||
129 | EXPORT_SYMBOL_GPL(ir_extract_bits); | ||
130 | |||
131 | static int inline getbit(u32 *samples, int bit) | ||
132 | { | ||
133 | return (samples[bit/32] & (1 << (31-(bit%32)))) ? 1 : 0; | ||
134 | } | ||
135 | |||
136 | /* sump raw samples for visual debugging ;) */ | ||
137 | int ir_dump_samples(u32 *samples, int count) | ||
138 | { | ||
139 | int i, bit, start; | ||
140 | |||
141 | printk(KERN_DEBUG "ir samples: "); | ||
142 | start = 0; | ||
143 | for (i = 0; i < count * 32; i++) { | ||
144 | bit = getbit(samples,i); | ||
145 | if (bit) | ||
146 | start = 1; | ||
147 | if (0 == start) | ||
148 | continue; | ||
149 | printk("%s", bit ? "#" : "_"); | ||
150 | } | ||
151 | printk("\n"); | ||
152 | return 0; | ||
153 | } | ||
154 | EXPORT_SYMBOL_GPL(ir_dump_samples); | ||
155 | |||
156 | /* decode raw samples, pulse distance coding used by NEC remotes */ | ||
157 | int ir_decode_pulsedistance(u32 *samples, int count, int low, int high) | ||
158 | { | ||
159 | int i,last,bit,len; | ||
160 | u32 curBit; | ||
161 | u32 value; | ||
162 | |||
163 | /* find start burst */ | ||
164 | for (i = len = 0; i < count * 32; i++) { | ||
165 | bit = getbit(samples,i); | ||
166 | if (bit) { | ||
167 | len++; | ||
168 | } else { | ||
169 | if (len >= 29) | ||
170 | break; | ||
171 | len = 0; | ||
172 | } | ||
173 | } | ||
174 | |||
175 | /* start burst to short */ | ||
176 | if (len < 29) | ||
177 | return 0xffffffff; | ||
178 | |||
179 | /* find start silence */ | ||
180 | for (len = 0; i < count * 32; i++) { | ||
181 | bit = getbit(samples,i); | ||
182 | if (bit) { | ||
183 | break; | ||
184 | } else { | ||
185 | len++; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | /* silence to short */ | ||
190 | if (len < 7) | ||
191 | return 0xffffffff; | ||
192 | |||
193 | /* go decoding */ | ||
194 | len = 0; | ||
195 | last = 1; | ||
196 | value = 0; curBit = 1; | ||
197 | for (; i < count * 32; i++) { | ||
198 | bit = getbit(samples,i); | ||
199 | if (last) { | ||
200 | if(bit) { | ||
201 | continue; | ||
202 | } else { | ||
203 | len = 1; | ||
204 | } | ||
205 | } else { | ||
206 | if (bit) { | ||
207 | if (len > (low + high) /2) | ||
208 | value |= curBit; | ||
209 | curBit <<= 1; | ||
210 | if (curBit == 1) | ||
211 | break; | ||
212 | } else { | ||
213 | len++; | ||
214 | } | ||
215 | } | ||
216 | last = bit; | ||
217 | } | ||
218 | |||
219 | return value; | ||
220 | } | ||
221 | EXPORT_SYMBOL_GPL(ir_decode_pulsedistance); | ||
222 | |||
223 | /* decode raw samples, biphase coding, used by rc5 for example */ | ||
224 | int ir_decode_biphase(u32 *samples, int count, int low, int high) | ||
225 | { | ||
226 | int i,last,bit,len,flips; | ||
227 | u32 value; | ||
228 | |||
229 | /* find start bit (1) */ | ||
230 | for (i = 0; i < 32; i++) { | ||
231 | bit = getbit(samples,i); | ||
232 | if (bit) | ||
233 | break; | ||
234 | } | ||
235 | |||
236 | /* go decoding */ | ||
237 | len = 0; | ||
238 | flips = 0; | ||
239 | value = 1; | ||
240 | for (; i < count * 32; i++) { | ||
241 | if (len > high) | ||
242 | break; | ||
243 | if (flips > 1) | ||
244 | break; | ||
245 | last = bit; | ||
246 | bit = getbit(samples,i); | ||
247 | if (last == bit) { | ||
248 | len++; | ||
249 | continue; | ||
250 | } | ||
251 | if (len < low) { | ||
252 | len++; | ||
253 | flips++; | ||
254 | continue; | ||
255 | } | ||
256 | value <<= 1; | ||
257 | value |= bit; | ||
258 | flips = 0; | ||
259 | len = 1; | ||
260 | } | ||
261 | return value; | ||
262 | } | ||
263 | EXPORT_SYMBOL_GPL(ir_decode_biphase); | ||
264 | |||
265 | /* RC5 decoding stuff, moved from bttv-input.c to share it with | ||
266 | * saa7134 */ | ||
267 | |||
268 | /* decode raw bit pattern to RC5 code */ | ||
269 | u32 ir_rc5_decode(unsigned int code) | ||
270 | { | ||
271 | unsigned int org_code = code; | ||
272 | unsigned int pair; | ||
273 | unsigned int rc5 = 0; | ||
274 | int i; | ||
275 | |||
276 | for (i = 0; i < 14; ++i) { | ||
277 | pair = code & 0x3; | ||
278 | code >>= 2; | ||
279 | |||
280 | rc5 <<= 1; | ||
281 | switch (pair) { | ||
282 | case 0: | ||
283 | case 2: | ||
284 | break; | ||
285 | case 1: | ||
286 | rc5 |= 1; | ||
287 | break; | ||
288 | case 3: | ||
289 | IR_dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code); | ||
290 | return 0; | ||
291 | } | ||
292 | } | ||
293 | IR_dprintk(1, "ir-common: code=%x, rc5=%x, start=%x, toggle=%x, address=%x, " | ||
294 | "instr=%x\n", rc5, org_code, RC5_START(rc5), | ||
295 | RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5)); | ||
296 | return rc5; | ||
297 | } | ||
298 | EXPORT_SYMBOL_GPL(ir_rc5_decode); | ||
299 | |||
300 | void ir_rc5_timer_end(unsigned long data) | ||
301 | { | ||
302 | struct card_ir *ir = (struct card_ir *)data; | ||
303 | struct timeval tv; | ||
304 | unsigned long current_jiffies, timeout; | ||
305 | u32 gap; | ||
306 | u32 rc5 = 0; | ||
307 | |||
308 | /* get time */ | ||
309 | current_jiffies = jiffies; | ||
310 | do_gettimeofday(&tv); | ||
311 | |||
312 | /* avoid overflow with gap >1s */ | ||
313 | if (tv.tv_sec - ir->base_time.tv_sec > 1) { | ||
314 | gap = 200000; | ||
315 | } else { | ||
316 | gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + | ||
317 | tv.tv_usec - ir->base_time.tv_usec; | ||
318 | } | ||
319 | |||
320 | /* signal we're ready to start a new code */ | ||
321 | ir->active = 0; | ||
322 | |||
323 | /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */ | ||
324 | if (gap < 28000) { | ||
325 | IR_dprintk(1, "ir-common: spurious timer_end\n"); | ||
326 | return; | ||
327 | } | ||
328 | |||
329 | if (ir->last_bit < 20) { | ||
330 | /* ignore spurious codes (caused by light/other remotes) */ | ||
331 | IR_dprintk(1, "ir-common: short code: %x\n", ir->code); | ||
332 | } else { | ||
333 | ir->code = (ir->code << ir->shift_by) | 1; | ||
334 | rc5 = ir_rc5_decode(ir->code); | ||
335 | |||
336 | /* two start bits? */ | ||
337 | if (RC5_START(rc5) != ir->start) { | ||
338 | IR_dprintk(1, "ir-common: rc5 start bits invalid: %u\n", RC5_START(rc5)); | ||
339 | |||
340 | /* right address? */ | ||
341 | } else if (RC5_ADDR(rc5) == ir->addr) { | ||
342 | u32 toggle = RC5_TOGGLE(rc5); | ||
343 | u32 instr = RC5_INSTR(rc5); | ||
344 | |||
345 | /* Good code, decide if repeat/repress */ | ||
346 | if (toggle != RC5_TOGGLE(ir->last_rc5) || | ||
347 | instr != RC5_INSTR(ir->last_rc5)) { | ||
348 | IR_dprintk(1, "ir-common: instruction %x, toggle %x\n", instr, | ||
349 | toggle); | ||
350 | ir_input_nokey(ir->dev, &ir->ir); | ||
351 | ir_input_keydown(ir->dev, &ir->ir, instr); | ||
352 | } | ||
353 | |||
354 | /* Set/reset key-up timer */ | ||
355 | timeout = current_jiffies + | ||
356 | msecs_to_jiffies(ir->rc5_key_timeout); | ||
357 | mod_timer(&ir->timer_keyup, timeout); | ||
358 | |||
359 | /* Save code for repeat test */ | ||
360 | ir->last_rc5 = rc5; | ||
361 | } | ||
362 | } | ||
363 | } | ||
364 | EXPORT_SYMBOL_GPL(ir_rc5_timer_end); | ||
365 | |||
366 | void ir_rc5_timer_keyup(unsigned long data) | ||
367 | { | ||
368 | struct card_ir *ir = (struct card_ir *)data; | ||
369 | |||
370 | IR_dprintk(1, "ir-common: key released\n"); | ||
371 | ir_input_nokey(ir->dev, &ir->ir); | ||
372 | } | ||
373 | EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup); | ||