]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * $Id: ir-common.c,v 1.8 2005/02/22 12:28:40 kraxel Exp $ | |
3 | * | |
4 | * some common structs and functions to handle infrared remotes via | |
5 | * input layer ... | |
6 | * | |
7 | * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 | */ | |
23 | ||
24 | #include <linux/module.h> | |
25 | #include <linux/moduleparam.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 | 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] = { | |
49 | [ 0x00 ] = KEY_KP0, // 0 | |
50 | [ 0x01 ] = KEY_KP1, // 1 | |
51 | [ 0x02 ] = KEY_KP2, // 2 | |
52 | [ 0x03 ] = KEY_KP3, // 3 | |
53 | [ 0x04 ] = KEY_KP4, // 4 | |
54 | [ 0x05 ] = KEY_KP5, // 5 | |
55 | [ 0x06 ] = KEY_KP6, // 6 | |
56 | [ 0x07 ] = KEY_KP7, // 7 | |
57 | [ 0x08 ] = KEY_KP8, // 8 | |
58 | [ 0x09 ] = KEY_KP9, // 9 | |
59 | ||
60 | [ 0x0b ] = KEY_CHANNEL, // channel / program (japan: 11) | |
61 | [ 0x0c ] = KEY_POWER, // standby | |
62 | [ 0x0d ] = KEY_MUTE, // mute / demute | |
63 | [ 0x0f ] = KEY_TV, // display | |
64 | [ 0x10 ] = KEY_VOLUMEUP, // volume + | |
65 | [ 0x11 ] = KEY_VOLUMEDOWN, // volume - | |
66 | [ 0x12 ] = KEY_BRIGHTNESSUP, // brightness + | |
67 | [ 0x13 ] = KEY_BRIGHTNESSDOWN, // brightness - | |
68 | [ 0x1e ] = KEY_SEARCH, // search + | |
69 | [ 0x20 ] = KEY_CHANNELUP, // channel / program + | |
70 | [ 0x21 ] = KEY_CHANNELDOWN, // channel / program - | |
71 | [ 0x22 ] = KEY_CHANNEL, // alt / channel | |
72 | [ 0x23 ] = KEY_LANGUAGE, // 1st / 2nd language | |
73 | [ 0x26 ] = KEY_SLEEP, // sleeptimer | |
74 | [ 0x2e ] = KEY_MENU, // 2nd controls (USA: menu) | |
75 | [ 0x30 ] = KEY_PAUSE, // pause | |
76 | [ 0x32 ] = KEY_REWIND, // rewind | |
77 | [ 0x33 ] = KEY_GOTO, // go to | |
78 | [ 0x35 ] = KEY_PLAY, // play | |
79 | [ 0x36 ] = KEY_STOP, // stop | |
80 | [ 0x37 ] = KEY_RECORD, // recording | |
81 | [ 0x3c ] = KEY_TEXT, // teletext submode (Japan: 12) | |
82 | [ 0x3d ] = KEY_SUSPEND, // system standby | |
83 | ||
84 | #if 0 /* FIXME */ | |
85 | [ 0x0a ] = KEY_RESERVED, // 1/2/3 digits (japan: 10) | |
86 | [ 0x0e ] = KEY_RESERVED, // P.P. (personal preference) | |
87 | [ 0x14 ] = KEY_RESERVED, // colour saturation + | |
88 | [ 0x15 ] = KEY_RESERVED, // colour saturation - | |
89 | [ 0x16 ] = KEY_RESERVED, // bass + | |
90 | [ 0x17 ] = KEY_RESERVED, // bass - | |
91 | [ 0x18 ] = KEY_RESERVED, // treble + | |
92 | [ 0x19 ] = KEY_RESERVED, // treble - | |
93 | [ 0x1a ] = KEY_RESERVED, // balance right | |
94 | [ 0x1b ] = KEY_RESERVED, // balance left | |
95 | [ 0x1c ] = KEY_RESERVED, // contrast + | |
96 | [ 0x1d ] = KEY_RESERVED, // contrast - | |
97 | [ 0x1f ] = KEY_RESERVED, // tint/hue + | |
98 | [ 0x24 ] = KEY_RESERVED, // spacial stereo on/off | |
99 | [ 0x25 ] = KEY_RESERVED, // mono / stereo (USA) | |
100 | [ 0x27 ] = KEY_RESERVED, // tint / hue - | |
101 | [ 0x28 ] = KEY_RESERVED, // RF switch/PIP select | |
102 | [ 0x29 ] = KEY_RESERVED, // vote | |
103 | [ 0x2a ] = KEY_RESERVED, // timed page/channel clck | |
104 | [ 0x2b ] = KEY_RESERVED, // increment (USA) | |
105 | [ 0x2c ] = KEY_RESERVED, // decrement (USA) | |
106 | [ 0x2d ] = KEY_RESERVED, // | |
107 | [ 0x2f ] = KEY_RESERVED, // PIP shift | |
108 | [ 0x31 ] = KEY_RESERVED, // erase | |
109 | [ 0x34 ] = KEY_RESERVED, // wind | |
110 | [ 0x38 ] = KEY_RESERVED, // external 1 | |
111 | [ 0x39 ] = KEY_RESERVED, // external 2 | |
112 | [ 0x3a ] = KEY_RESERVED, // PIP display mode | |
113 | [ 0x3b ] = KEY_RESERVED, // view data mode / advance | |
114 | [ 0x3e ] = KEY_RESERVED, // crispener on/off | |
115 | [ 0x3f ] = KEY_RESERVED, // system select | |
116 | #endif | |
117 | }; | |
118 | EXPORT_SYMBOL_GPL(ir_codes_rc5_tv); | |
119 | ||
120 | /* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */ | |
121 | IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = { | |
122 | [ 5 ] = KEY_KP1, | |
123 | [ 6 ] = KEY_KP2, | |
124 | [ 7 ] = KEY_KP3, | |
125 | [ 9 ] = KEY_KP4, | |
126 | [ 10 ] = KEY_KP5, | |
127 | [ 11 ] = KEY_KP6, | |
128 | [ 13 ] = KEY_KP7, | |
129 | [ 14 ] = KEY_KP8, | |
130 | [ 15 ] = KEY_KP9, | |
131 | [ 18 ] = KEY_KP0, | |
132 | ||
133 | [ 0 ] = KEY_POWER, | |
134 | // [ 27 ] = MTS button | |
135 | [ 2 ] = KEY_TUNER, // TV/FM | |
136 | [ 30 ] = KEY_VIDEO, | |
137 | // [ 22 ] = display button | |
138 | [ 4 ] = KEY_VOLUMEUP, | |
139 | [ 8 ] = KEY_VOLUMEDOWN, | |
140 | [ 12 ] = KEY_CHANNELUP, | |
141 | [ 16 ] = KEY_CHANNELDOWN, | |
142 | [ 3 ] = KEY_ZOOM, // fullscreen | |
143 | [ 31 ] = KEY_SUBTITLE, // closed caption/teletext | |
144 | [ 32 ] = KEY_SLEEP, | |
145 | // [ 41 ] = boss key | |
146 | [ 20 ] = KEY_MUTE, | |
147 | [ 43 ] = KEY_RED, | |
148 | [ 44 ] = KEY_GREEN, | |
149 | [ 45 ] = KEY_YELLOW, | |
150 | [ 46 ] = KEY_BLUE, | |
151 | [ 24 ] = KEY_KPPLUS, //fine tune + | |
152 | [ 25 ] = KEY_KPMINUS, //fine tune - | |
153 | // [ 42 ] = picture in picture | |
154 | [ 33 ] = KEY_KPDOT, | |
155 | [ 19 ] = KEY_KPENTER, | |
156 | // [ 17 ] = recall | |
157 | [ 34 ] = KEY_BACK, | |
158 | [ 35 ] = KEY_PLAYPAUSE, | |
159 | [ 36 ] = KEY_NEXT, | |
160 | // [ 37 ] = time shifting | |
161 | [ 38 ] = KEY_STOP, | |
162 | [ 39 ] = KEY_RECORD | |
163 | // [ 40 ] = snapshot | |
164 | }; | |
165 | EXPORT_SYMBOL_GPL(ir_codes_winfast); | |
166 | ||
167 | /* empty keytable, can be used as placeholder for not-yet created keytables */ | |
168 | IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = { | |
169 | [ 42 ] = KEY_COFFEE, | |
170 | }; | |
171 | EXPORT_SYMBOL_GPL(ir_codes_empty); | |
172 | ||
173 | /* Hauppauge: the newer, gray remotes (seems there are multiple | |
174 | * slightly different versions), shipped with cx88+ivtv cards. | |
175 | * almost rc5 coding, but some non-standard keys */ | |
176 | IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = { | |
177 | [ 0x00 ] = KEY_KP0, // 0 | |
178 | [ 0x01 ] = KEY_KP1, // 1 | |
179 | [ 0x02 ] = KEY_KP2, // 2 | |
180 | [ 0x03 ] = KEY_KP3, // 3 | |
181 | [ 0x04 ] = KEY_KP4, // 4 | |
182 | [ 0x05 ] = KEY_KP5, // 5 | |
183 | [ 0x06 ] = KEY_KP6, // 6 | |
184 | [ 0x07 ] = KEY_KP7, // 7 | |
185 | [ 0x08 ] = KEY_KP8, // 8 | |
186 | [ 0x09 ] = KEY_KP9, // 9 | |
187 | [ 0x0b ] = KEY_RED, // red button | |
188 | [ 0x0c ] = KEY_OPTION, // black key without text | |
189 | [ 0x0d ] = KEY_MENU, // menu | |
190 | [ 0x0f ] = KEY_MUTE, // mute | |
191 | [ 0x10 ] = KEY_VOLUMEUP, // volume + | |
192 | [ 0x11 ] = KEY_VOLUMEDOWN, // volume - | |
193 | [ 0x1e ] = KEY_NEXT, // skip >| | |
194 | [ 0x1f ] = KEY_EXIT, // back/exit | |
195 | [ 0x20 ] = KEY_CHANNELUP, // channel / program + | |
196 | [ 0x21 ] = KEY_CHANNELDOWN, // channel / program - | |
197 | [ 0x22 ] = KEY_CHANNEL, // source (old black remote) | |
198 | [ 0x24 ] = KEY_PREVIOUS, // replay |< | |
199 | [ 0x25 ] = KEY_ENTER, // OK | |
200 | [ 0x26 ] = KEY_SLEEP, // minimize (old black remote) | |
201 | [ 0x29 ] = KEY_BLUE, // blue key | |
202 | [ 0x2e ] = KEY_GREEN, // green button | |
203 | [ 0x30 ] = KEY_PAUSE, // pause | |
204 | [ 0x32 ] = KEY_REWIND, // backward << | |
205 | [ 0x34 ] = KEY_FASTFORWARD, // forward >> | |
206 | [ 0x35 ] = KEY_PLAY, // play | |
207 | [ 0x36 ] = KEY_STOP, // stop | |
208 | [ 0x37 ] = KEY_RECORD, // recording | |
209 | [ 0x38 ] = KEY_YELLOW, // yellow key | |
210 | [ 0x3b ] = KEY_SELECT, // top right button | |
211 | [ 0x3c ] = KEY_ZOOM, // full | |
212 | [ 0x3d ] = KEY_POWER, // system power (green button) | |
213 | }; | |
214 | EXPORT_SYMBOL(ir_codes_hauppauge_new); | |
215 | ||
216 | /* -------------------------------------------------------------------------- */ | |
217 | ||
218 | static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir) | |
219 | { | |
220 | if (KEY_RESERVED == ir->keycode) { | |
221 | printk(KERN_INFO "%s: unknown key: key=0x%02x raw=0x%02x down=%d\n", | |
222 | dev->name,ir->ir_key,ir->ir_raw,ir->keypressed); | |
223 | return; | |
224 | } | |
225 | dprintk(1,"%s: key event code=%d down=%d\n", | |
226 | dev->name,ir->keycode,ir->keypressed); | |
227 | input_report_key(dev,ir->keycode,ir->keypressed); | |
228 | input_sync(dev); | |
229 | } | |
230 | ||
231 | /* -------------------------------------------------------------------------- */ | |
232 | ||
233 | void ir_input_init(struct input_dev *dev, struct ir_input_state *ir, | |
234 | int ir_type, IR_KEYTAB_TYPE *ir_codes) | |
235 | { | |
236 | int i; | |
237 | ||
238 | ir->ir_type = ir_type; | |
239 | if (ir_codes) | |
240 | memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes)); | |
241 | ||
242 | init_input_dev(dev); | |
243 | dev->keycode = ir->ir_codes; | |
244 | dev->keycodesize = sizeof(IR_KEYTAB_TYPE); | |
245 | dev->keycodemax = IR_KEYTAB_SIZE; | |
246 | for (i = 0; i < IR_KEYTAB_SIZE; i++) | |
247 | set_bit(ir->ir_codes[i], dev->keybit); | |
248 | clear_bit(0, dev->keybit); | |
249 | ||
250 | set_bit(EV_KEY, dev->evbit); | |
251 | if (repeat) | |
252 | set_bit(EV_REP, dev->evbit); | |
253 | } | |
254 | ||
255 | void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir) | |
256 | { | |
257 | if (ir->keypressed) { | |
258 | ir->keypressed = 0; | |
259 | ir_input_key_event(dev,ir); | |
260 | } | |
261 | } | |
262 | ||
263 | void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir, | |
264 | u32 ir_key, u32 ir_raw) | |
265 | { | |
266 | u32 keycode = IR_KEYCODE(ir->ir_codes, ir_key); | |
267 | ||
268 | if (ir->keypressed && ir->keycode != keycode) { | |
269 | ir->keypressed = 0; | |
270 | ir_input_key_event(dev,ir); | |
271 | } | |
272 | if (!ir->keypressed) { | |
273 | ir->ir_key = ir_key; | |
274 | ir->ir_raw = ir_raw; | |
275 | ir->keycode = keycode; | |
276 | ir->keypressed = 1; | |
277 | ir_input_key_event(dev,ir); | |
278 | } | |
279 | #if 0 | |
280 | /* maybe do something like this ??? */ | |
281 | input_event(a, EV_IR, ir->ir_type, ir->ir_raw); | |
282 | #endif | |
283 | } | |
284 | ||
285 | /* -------------------------------------------------------------------------- */ | |
286 | ||
287 | u32 ir_extract_bits(u32 data, u32 mask) | |
288 | { | |
289 | int mbit, vbit; | |
290 | u32 value; | |
291 | ||
292 | value = 0; | |
293 | vbit = 0; | |
294 | for (mbit = 0; mbit < 32; mbit++) { | |
295 | if (!(mask & ((u32)1 << mbit))) | |
296 | continue; | |
297 | if (data & ((u32)1 << mbit)) | |
298 | value |= (1 << vbit); | |
299 | vbit++; | |
300 | } | |
301 | return value; | |
302 | } | |
303 | ||
304 | static int inline getbit(u32 *samples, int bit) | |
305 | { | |
306 | return (samples[bit/32] & (1 << (31-(bit%32)))) ? 1 : 0; | |
307 | } | |
308 | ||
309 | /* sump raw samples for visual debugging ;) */ | |
310 | int ir_dump_samples(u32 *samples, int count) | |
311 | { | |
312 | int i, bit, start; | |
313 | ||
314 | printk(KERN_DEBUG "ir samples: "); | |
315 | start = 0; | |
316 | for (i = 0; i < count * 32; i++) { | |
317 | bit = getbit(samples,i); | |
318 | if (bit) | |
319 | start = 1; | |
320 | if (0 == start) | |
321 | continue; | |
322 | printk("%s", bit ? "#" : "_"); | |
323 | } | |
324 | printk("\n"); | |
325 | return 0; | |
326 | } | |
327 | ||
328 | /* decode raw samples, biphase coding, used by rc5 for example */ | |
329 | int ir_decode_biphase(u32 *samples, int count, int low, int high) | |
330 | { | |
331 | int i,last,bit,len,flips; | |
332 | u32 value; | |
333 | ||
334 | /* find start bit (1) */ | |
335 | for (i = 0; i < 32; i++) { | |
336 | bit = getbit(samples,i); | |
337 | if (bit) | |
338 | break; | |
339 | } | |
340 | ||
341 | /* go decoding */ | |
342 | len = 0; | |
343 | flips = 0; | |
344 | value = 1; | |
345 | for (; i < count * 32; i++) { | |
346 | if (len > high) | |
347 | break; | |
348 | if (flips > 1) | |
349 | break; | |
350 | last = bit; | |
351 | bit = getbit(samples,i); | |
352 | if (last == bit) { | |
353 | len++; | |
354 | continue; | |
355 | } | |
356 | if (len < low) { | |
357 | len++; | |
358 | flips++; | |
359 | continue; | |
360 | } | |
361 | value <<= 1; | |
362 | value |= bit; | |
363 | flips = 0; | |
364 | len = 1; | |
365 | } | |
366 | return value; | |
367 | } | |
368 | ||
369 | EXPORT_SYMBOL_GPL(ir_input_init); | |
370 | EXPORT_SYMBOL_GPL(ir_input_nokey); | |
371 | EXPORT_SYMBOL_GPL(ir_input_keydown); | |
372 | ||
373 | EXPORT_SYMBOL_GPL(ir_extract_bits); | |
374 | EXPORT_SYMBOL_GPL(ir_dump_samples); | |
375 | EXPORT_SYMBOL_GPL(ir_decode_biphase); | |
376 | ||
377 | /* | |
378 | * Local variables: | |
379 | * c-basic-offset: 8 | |
380 | * End: | |
381 | */ |