diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/media/common/ir-common.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/media/common/ir-common.c')
-rw-r--r-- | drivers/media/common/ir-common.c | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c new file mode 100644 index 000000000000..8c842e2f59a2 --- /dev/null +++ b/drivers/media/common/ir-common.c | |||
@@ -0,0 +1,381 @@ | |||
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 | */ | ||