]>
Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
1da177e4 LT |
2 | * |
3 | * some common structs and functions to handle infrared remotes via | |
4 | * input layer ... | |
5 | * | |
6 | * (c) 2003 Gerd Knorr <[email protected]> [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/moduleparam.h> | |
4e57b681 | 25 | #include <linux/string.h> |
1da177e4 LT |
26 | #include <media/ir-common.h> |
27 | ||
28 | /* -------------------------------------------------------------------------- */ | |
29 | ||
30 | MODULE_AUTHOR("Gerd Knorr <[email protected]> [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 | static int debug = 0; /* debug level (0,1,2) */ | |
38 | module_param(debug, int, 0644); | |
39 | ||
40 | #define dprintk(level, fmt, arg...) if (debug >= level) \ | |
41 | printk(KERN_DEBUG fmt , ## arg) | |
42 | ||
43 | /* -------------------------------------------------------------------------- */ | |
44 | ||
45 | /* generic RC5 keytable */ | |
46 | /* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */ | |
47 | /* used by old (black) Hauppauge remotes */ | |
48 | IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE] = { | |
60acbc99 MCC |
49 | /* Keys 0 to 9 */ |
50 | [ 0x00 ] = KEY_KP0, | |
51 | [ 0x01 ] = KEY_KP1, | |
52 | [ 0x02 ] = KEY_KP2, | |
53 | [ 0x03 ] = KEY_KP3, | |
54 | [ 0x04 ] = KEY_KP4, | |
55 | [ 0x05 ] = KEY_KP5, | |
56 | [ 0x06 ] = KEY_KP6, | |
57 | [ 0x07 ] = KEY_KP7, | |
58 | [ 0x08 ] = KEY_KP8, | |
59 | [ 0x09 ] = KEY_KP9, | |
60 | ||
61 | [ 0x0b ] = KEY_CHANNEL, /* channel / program (japan: 11) */ | |
62 | [ 0x0c ] = KEY_POWER, /* standby */ | |
63 | [ 0x0d ] = KEY_MUTE, /* mute / demute */ | |
64 | [ 0x0f ] = KEY_TV, /* display */ | |
65 | [ 0x10 ] = KEY_VOLUMEUP, | |
66 | [ 0x11 ] = KEY_VOLUMEDOWN, | |
67 | [ 0x12 ] = KEY_BRIGHTNESSUP, | |
68 | [ 0x13 ] = KEY_BRIGHTNESSDOWN, | |
69 | [ 0x1e ] = KEY_SEARCH, /* search + */ | |
70 | [ 0x20 ] = KEY_CHANNELUP, /* channel / program + */ | |
71 | [ 0x21 ] = KEY_CHANNELDOWN, /* channel / program - */ | |
72 | [ 0x22 ] = KEY_CHANNEL, /* alt / channel */ | |
73 | [ 0x23 ] = KEY_LANGUAGE, /* 1st / 2nd language */ | |
74 | [ 0x26 ] = KEY_SLEEP, /* sleeptimer */ | |
75 | [ 0x2e ] = KEY_MENU, /* 2nd controls (USA: menu) */ | |
76 | [ 0x30 ] = KEY_PAUSE, | |
77 | [ 0x32 ] = KEY_REWIND, | |
78 | [ 0x33 ] = KEY_GOTO, | |
79 | [ 0x35 ] = KEY_PLAY, | |
80 | [ 0x36 ] = KEY_STOP, | |
81 | [ 0x37 ] = KEY_RECORD, /* recording */ | |
82 | [ 0x3c ] = KEY_TEXT, /* teletext submode (Japan: 12) */ | |
83 | [ 0x3d ] = KEY_SUSPEND, /* system standby */ | |
84 | ||
1da177e4 LT |
85 | }; |
86 | EXPORT_SYMBOL_GPL(ir_codes_rc5_tv); | |
87 | ||
88 | /* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */ | |
89 | IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = { | |
60acbc99 MCC |
90 | /* Keys 0 to 9 */ |
91 | [ 18 ] = KEY_KP0, | |
1da177e4 LT |
92 | [ 5 ] = KEY_KP1, |
93 | [ 6 ] = KEY_KP2, | |
94 | [ 7 ] = KEY_KP3, | |
95 | [ 9 ] = KEY_KP4, | |
96 | [ 10 ] = KEY_KP5, | |
97 | [ 11 ] = KEY_KP6, | |
98 | [ 13 ] = KEY_KP7, | |
99 | [ 14 ] = KEY_KP8, | |
100 | [ 15 ] = KEY_KP9, | |
1da177e4 LT |
101 | |
102 | [ 0 ] = KEY_POWER, | |
60acbc99 | 103 | [ 2 ] = KEY_TUNER, /* TV/FM */ |
1da177e4 | 104 | [ 30 ] = KEY_VIDEO, |
1da177e4 LT |
105 | [ 4 ] = KEY_VOLUMEUP, |
106 | [ 8 ] = KEY_VOLUMEDOWN, | |
107 | [ 12 ] = KEY_CHANNELUP, | |
108 | [ 16 ] = KEY_CHANNELDOWN, | |
60acbc99 MCC |
109 | [ 3 ] = KEY_ZOOM, /* fullscreen */ |
110 | [ 31 ] = KEY_SUBTITLE, /* closed caption/teletext */ | |
1da177e4 | 111 | [ 32 ] = KEY_SLEEP, |
1da177e4 LT |
112 | [ 20 ] = KEY_MUTE, |
113 | [ 43 ] = KEY_RED, | |
114 | [ 44 ] = KEY_GREEN, | |
115 | [ 45 ] = KEY_YELLOW, | |
116 | [ 46 ] = KEY_BLUE, | |
60acbc99 MCC |
117 | [ 24 ] = KEY_KPPLUS, /* fine tune + */ |
118 | [ 25 ] = KEY_KPMINUS, /* fine tune - */ | |
56fc08ca | 119 | [ 33 ] = KEY_KPDOT, |
1da177e4 | 120 | [ 19 ] = KEY_KPENTER, |
1da177e4 LT |
121 | [ 34 ] = KEY_BACK, |
122 | [ 35 ] = KEY_PLAYPAUSE, | |
123 | [ 36 ] = KEY_NEXT, | |
1da177e4 | 124 | [ 38 ] = KEY_STOP, |
56fc08ca | 125 | [ 39 ] = KEY_RECORD |
1da177e4 LT |
126 | }; |
127 | EXPORT_SYMBOL_GPL(ir_codes_winfast); | |
128 | ||
129 | /* empty keytable, can be used as placeholder for not-yet created keytables */ | |
130 | IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = { | |
131 | [ 42 ] = KEY_COFFEE, | |
132 | }; | |
133 | EXPORT_SYMBOL_GPL(ir_codes_empty); | |
134 | ||
135 | /* Hauppauge: the newer, gray remotes (seems there are multiple | |
136 | * slightly different versions), shipped with cx88+ivtv cards. | |
137 | * almost rc5 coding, but some non-standard keys */ | |
138 | IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = { | |
60acbc99 MCC |
139 | /* Keys 0 to 9 */ |
140 | [ 0x00 ] = KEY_KP0, | |
141 | [ 0x01 ] = KEY_KP1, | |
142 | [ 0x02 ] = KEY_KP2, | |
143 | [ 0x03 ] = KEY_KP3, | |
144 | [ 0x04 ] = KEY_KP4, | |
145 | [ 0x05 ] = KEY_KP5, | |
146 | [ 0x06 ] = KEY_KP6, | |
147 | [ 0x07 ] = KEY_KP7, | |
148 | [ 0x08 ] = KEY_KP8, | |
149 | [ 0x09 ] = KEY_KP9, | |
150 | ||
151 | [ 0x0a ] = KEY_TEXT, /* keypad asterisk as well */ | |
152 | [ 0x0b ] = KEY_RED, /* red button */ | |
153 | [ 0x0c ] = KEY_RADIO, | |
154 | [ 0x0d ] = KEY_MENU, | |
155 | [ 0x0e ] = KEY_SUBTITLE, /* also the # key */ | |
156 | [ 0x0f ] = KEY_MUTE, | |
157 | [ 0x10 ] = KEY_VOLUMEUP, | |
158 | [ 0x11 ] = KEY_VOLUMEDOWN, | |
159 | [ 0x12 ] = KEY_PREVIOUS, /* previous channel */ | |
160 | [ 0x14 ] = KEY_UP, | |
161 | [ 0x15 ] = KEY_DOWN, | |
162 | [ 0x16 ] = KEY_LEFT, | |
163 | [ 0x17 ] = KEY_RIGHT, | |
164 | [ 0x18 ] = KEY_VIDEO, /* Videos */ | |
165 | [ 0x19 ] = KEY_AUDIO, /* Music */ | |
166 | /* 0x1a: Pictures - presume this means | |
167 | "Multimedia Home Platform" - | |
168 | no "PICTURES" key in input.h | |
169 | */ | |
170 | [ 0x1a ] = KEY_MHP, | |
171 | ||
172 | [ 0x1b ] = KEY_EPG, /* Guide */ | |
173 | [ 0x1c ] = KEY_TV, | |
174 | [ 0x1e ] = KEY_NEXTSONG, /* skip >| */ | |
175 | [ 0x1f ] = KEY_EXIT, /* back/exit */ | |
176 | [ 0x20 ] = KEY_CHANNELUP, /* channel / program + */ | |
177 | [ 0x21 ] = KEY_CHANNELDOWN, /* channel / program - */ | |
178 | [ 0x22 ] = KEY_CHANNEL, /* source (old black remote) */ | |
179 | [ 0x24 ] = KEY_PREVIOUSSONG, /* replay |< */ | |
180 | [ 0x25 ] = KEY_ENTER, /* OK */ | |
181 | [ 0x26 ] = KEY_SLEEP, /* minimize (old black remote) */ | |
182 | [ 0x29 ] = KEY_BLUE, /* blue key */ | |
183 | [ 0x2e ] = KEY_GREEN, /* green button */ | |
184 | [ 0x30 ] = KEY_PAUSE, /* pause */ | |
185 | [ 0x32 ] = KEY_REWIND, /* backward << */ | |
186 | [ 0x34 ] = KEY_FASTFORWARD, /* forward >> */ | |
187 | [ 0x35 ] = KEY_PLAY, | |
188 | [ 0x36 ] = KEY_STOP, | |
189 | [ 0x37 ] = KEY_RECORD, /* recording */ | |
190 | [ 0x38 ] = KEY_YELLOW, /* yellow key */ | |
191 | [ 0x3b ] = KEY_SELECT, /* top right button */ | |
192 | [ 0x3c ] = KEY_ZOOM, /* full */ | |
193 | [ 0x3d ] = KEY_POWER, /* system power (green button) */ | |
1da177e4 LT |
194 | }; |
195 | EXPORT_SYMBOL(ir_codes_hauppauge_new); | |
196 | ||
239df2e2 MC |
197 | IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = { |
198 | [ 2 ] = KEY_KP0, | |
199 | [ 1 ] = KEY_KP1, | |
200 | [ 11 ] = KEY_KP2, | |
201 | [ 27 ] = KEY_KP3, | |
202 | [ 5 ] = KEY_KP4, | |
203 | [ 9 ] = KEY_KP5, | |
204 | [ 21 ] = KEY_KP6, | |
205 | [ 6 ] = KEY_KP7, | |
206 | [ 10 ] = KEY_KP8, | |
207 | [ 18 ] = KEY_KP9, | |
208 | ||
60acbc99 MCC |
209 | [ 3 ] = KEY_TUNER, /* TV/FM */ |
210 | [ 7 ] = KEY_SEARCH, /* scan */ | |
211 | [ 28 ] = KEY_ZOOM, /* full screen */ | |
239df2e2 MC |
212 | [ 30 ] = KEY_POWER, |
213 | [ 23 ] = KEY_VOLUMEDOWN, | |
214 | [ 31 ] = KEY_VOLUMEUP, | |
215 | [ 20 ] = KEY_CHANNELDOWN, | |
216 | [ 22 ] = KEY_CHANNELUP, | |
217 | [ 24 ] = KEY_MUTE, | |
218 | ||
60acbc99 MCC |
219 | [ 0 ] = KEY_LIST, /* source */ |
220 | [ 19 ] = KEY_INFO, /* loop */ | |
221 | [ 16 ] = KEY_LAST, /* +100 */ | |
222 | [ 13 ] = KEY_CLEAR, /* reset */ | |
223 | [ 12 ] = BTN_RIGHT, /* fun++ */ | |
224 | [ 4 ] = BTN_LEFT, /* fun-- */ | |
225 | [ 14 ] = KEY_GOTO, /* function */ | |
226 | [ 15 ] = KEY_STOP, /* freeze */ | |
239df2e2 MC |
227 | }; |
228 | EXPORT_SYMBOL(ir_codes_pixelview); | |
229 | ||
1da177e4 LT |
230 | /* -------------------------------------------------------------------------- */ |
231 | ||
232 | static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir) | |
233 | { | |
234 | if (KEY_RESERVED == ir->keycode) { | |
235 | printk(KERN_INFO "%s: unknown key: key=0x%02x raw=0x%02x down=%d\n", | |
236 | dev->name,ir->ir_key,ir->ir_raw,ir->keypressed); | |
237 | return; | |
238 | } | |
239 | dprintk(1,"%s: key event code=%d down=%d\n", | |
240 | dev->name,ir->keycode,ir->keypressed); | |
241 | input_report_key(dev,ir->keycode,ir->keypressed); | |
242 | input_sync(dev); | |
243 | } | |
244 | ||
245 | /* -------------------------------------------------------------------------- */ | |
246 | ||
247 | void ir_input_init(struct input_dev *dev, struct ir_input_state *ir, | |
248 | int ir_type, IR_KEYTAB_TYPE *ir_codes) | |
249 | { | |
250 | int i; | |
251 | ||
252 | ir->ir_type = ir_type; | |
253 | if (ir_codes) | |
254 | memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes)); | |
255 | ||
1da177e4 LT |
256 | dev->keycode = ir->ir_codes; |
257 | dev->keycodesize = sizeof(IR_KEYTAB_TYPE); | |
258 | dev->keycodemax = IR_KEYTAB_SIZE; | |
259 | for (i = 0; i < IR_KEYTAB_SIZE; i++) | |
260 | set_bit(ir->ir_codes[i], dev->keybit); | |
261 | clear_bit(0, dev->keybit); | |
262 | ||
263 | set_bit(EV_KEY, dev->evbit); | |
264 | if (repeat) | |
265 | set_bit(EV_REP, dev->evbit); | |
266 | } | |
267 | ||
268 | void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir) | |
269 | { | |
270 | if (ir->keypressed) { | |
271 | ir->keypressed = 0; | |
272 | ir_input_key_event(dev,ir); | |
273 | } | |
274 | } | |
275 | ||
276 | void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir, | |
277 | u32 ir_key, u32 ir_raw) | |
278 | { | |
279 | u32 keycode = IR_KEYCODE(ir->ir_codes, ir_key); | |
280 | ||
281 | if (ir->keypressed && ir->keycode != keycode) { | |
282 | ir->keypressed = 0; | |
283 | ir_input_key_event(dev,ir); | |
284 | } | |
285 | if (!ir->keypressed) { | |
286 | ir->ir_key = ir_key; | |
287 | ir->ir_raw = ir_raw; | |
288 | ir->keycode = keycode; | |
289 | ir->keypressed = 1; | |
290 | ir_input_key_event(dev,ir); | |
291 | } | |
1da177e4 LT |
292 | } |
293 | ||
294 | /* -------------------------------------------------------------------------- */ | |
295 | ||
296 | u32 ir_extract_bits(u32 data, u32 mask) | |
297 | { | |
298 | int mbit, vbit; | |
299 | u32 value; | |
300 | ||
301 | value = 0; | |
302 | vbit = 0; | |
303 | for (mbit = 0; mbit < 32; mbit++) { | |
304 | if (!(mask & ((u32)1 << mbit))) | |
305 | continue; | |
306 | if (data & ((u32)1 << mbit)) | |
307 | value |= (1 << vbit); | |
308 | vbit++; | |
309 | } | |
310 | return value; | |
311 | } | |
312 | ||
313 | static int inline getbit(u32 *samples, int bit) | |
314 | { | |
315 | return (samples[bit/32] & (1 << (31-(bit%32)))) ? 1 : 0; | |
316 | } | |
317 | ||
318 | /* sump raw samples for visual debugging ;) */ | |
319 | int ir_dump_samples(u32 *samples, int count) | |
320 | { | |
321 | int i, bit, start; | |
322 | ||
323 | printk(KERN_DEBUG "ir samples: "); | |
324 | start = 0; | |
325 | for (i = 0; i < count * 32; i++) { | |
326 | bit = getbit(samples,i); | |
327 | if (bit) | |
328 | start = 1; | |
329 | if (0 == start) | |
330 | continue; | |
331 | printk("%s", bit ? "#" : "_"); | |
332 | } | |
333 | printk("\n"); | |
334 | return 0; | |
335 | } | |
336 | ||
793cf9e6 MCC |
337 | /* decode raw samples, pulse distance coding used by NEC remotes */ |
338 | int ir_decode_pulsedistance(u32 *samples, int count, int low, int high) | |
339 | { | |
340 | int i,last,bit,len; | |
341 | u32 curBit; | |
342 | u32 value; | |
343 | ||
344 | /* find start burst */ | |
345 | for (i = len = 0; i < count * 32; i++) { | |
346 | bit = getbit(samples,i); | |
347 | if (bit) { | |
348 | len++; | |
349 | } else { | |
350 | if (len >= 29) | |
351 | break; | |
352 | len = 0; | |
353 | } | |
354 | } | |
355 | ||
356 | /* start burst to short */ | |
357 | if (len < 29) | |
358 | return 0xffffffff; | |
359 | ||
360 | /* find start silence */ | |
361 | for (len = 0; i < count * 32; i++) { | |
362 | bit = getbit(samples,i); | |
363 | if (bit) { | |
364 | break; | |
365 | } else { | |
366 | len++; | |
367 | } | |
368 | } | |
369 | ||
370 | /* silence to short */ | |
371 | if (len < 7) | |
372 | return 0xffffffff; | |
373 | ||
374 | /* go decoding */ | |
375 | len = 0; | |
376 | last = 1; | |
377 | value = 0; curBit = 1; | |
378 | for (; i < count * 32; i++) { | |
379 | bit = getbit(samples,i); | |
380 | if (last) { | |
381 | if(bit) { | |
382 | continue; | |
383 | } else { | |
384 | len = 1; | |
385 | } | |
386 | } else { | |
387 | if (bit) { | |
388 | if (len > (low + high) /2) | |
389 | value |= curBit; | |
390 | curBit <<= 1; | |
391 | if (curBit == 1) | |
392 | break; | |
393 | } else { | |
394 | len++; | |
395 | } | |
396 | } | |
397 | last = bit; | |
398 | } | |
399 | ||
400 | return value; | |
401 | } | |
402 | ||
1da177e4 LT |
403 | /* decode raw samples, biphase coding, used by rc5 for example */ |
404 | int ir_decode_biphase(u32 *samples, int count, int low, int high) | |
405 | { | |
406 | int i,last,bit,len,flips; | |
407 | u32 value; | |
408 | ||
409 | /* find start bit (1) */ | |
410 | for (i = 0; i < 32; i++) { | |
411 | bit = getbit(samples,i); | |
412 | if (bit) | |
413 | break; | |
414 | } | |
415 | ||
416 | /* go decoding */ | |
417 | len = 0; | |
418 | flips = 0; | |
419 | value = 1; | |
420 | for (; i < count * 32; i++) { | |
421 | if (len > high) | |
422 | break; | |
423 | if (flips > 1) | |
424 | break; | |
425 | last = bit; | |
426 | bit = getbit(samples,i); | |
427 | if (last == bit) { | |
428 | len++; | |
429 | continue; | |
430 | } | |
431 | if (len < low) { | |
432 | len++; | |
433 | flips++; | |
434 | continue; | |
435 | } | |
436 | value <<= 1; | |
437 | value |= bit; | |
438 | flips = 0; | |
439 | len = 1; | |
440 | } | |
441 | return value; | |
442 | } | |
443 | ||
444 | EXPORT_SYMBOL_GPL(ir_input_init); | |
445 | EXPORT_SYMBOL_GPL(ir_input_nokey); | |
446 | EXPORT_SYMBOL_GPL(ir_input_keydown); | |
447 | ||
448 | EXPORT_SYMBOL_GPL(ir_extract_bits); | |
449 | EXPORT_SYMBOL_GPL(ir_dump_samples); | |
450 | EXPORT_SYMBOL_GPL(ir_decode_biphase); | |
793cf9e6 | 451 | EXPORT_SYMBOL_GPL(ir_decode_pulsedistance); |
1da177e4 LT |
452 | |
453 | /* | |
454 | * Local variables: | |
455 | * c-basic-offset: 8 | |
456 | * End: | |
457 | */ | |
56fc08ca | 458 |