aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ir-kbd-i2c.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/media/video/ir-kbd-i2c.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/video/ir-kbd-i2c.c')
-rw-r--r--drivers/media/video/ir-kbd-i2c.c492
1 files changed, 492 insertions, 0 deletions
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
new file mode 100644
index 000000000000..92664f75d327
--- /dev/null
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -0,0 +1,492 @@
1/*
2 * $Id: ir-kbd-i2c.c,v 1.10 2004/12/09 12:51:35 kraxel Exp $
3 *
4 * keyboard input driver for i2c IR remote controls
5 *
6 * Copyright (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org>
7 * modified for PixelView (BT878P+W/FM) by
8 * Michal Kochanowicz <mkochano@pld.org.pl>
9 * Christoph Bartelmus <lirc@bartelmus.de>
10 * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
11 * Ulrich Mueller <ulrich.mueller42@web.de>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 *
27 */
28
29#include <linux/module.h>
30#include <linux/moduleparam.h>
31#include <linux/init.h>
32#include <linux/kernel.h>
33#include <linux/sched.h>
34#include <linux/string.h>
35#include <linux/timer.h>
36#include <linux/delay.h>
37#include <linux/errno.h>
38#include <linux/slab.h>
39#include <linux/i2c.h>
40#include <linux/workqueue.h>
41
42#include <asm/semaphore.h>
43
44#include <media/ir-common.h>
45
46/* Mark Phalan <phalanm@o2.ie> */
47static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
48 [ 0 ] = KEY_KP0,
49 [ 1 ] = KEY_KP1,
50 [ 2 ] = KEY_KP2,
51 [ 3 ] = KEY_KP3,
52 [ 4 ] = KEY_KP4,
53 [ 5 ] = KEY_KP5,
54 [ 6 ] = KEY_KP6,
55 [ 7 ] = KEY_KP7,
56 [ 8 ] = KEY_KP8,
57 [ 9 ] = KEY_KP9,
58
59 [ 18 ] = KEY_POWER,
60 [ 16 ] = KEY_MUTE,
61 [ 31 ] = KEY_VOLUMEDOWN,
62 [ 27 ] = KEY_VOLUMEUP,
63 [ 26 ] = KEY_CHANNELUP,
64 [ 30 ] = KEY_CHANNELDOWN,
65 [ 14 ] = KEY_PAGEUP,
66 [ 29 ] = KEY_PAGEDOWN,
67 [ 19 ] = KEY_SOUND,
68
69 [ 24 ] = KEY_KPPLUSMINUS, // CH +/-
70 [ 22 ] = KEY_SUBTITLE, // CC
71 [ 13 ] = KEY_TEXT, // TTX
72 [ 11 ] = KEY_TV, // AIR/CBL
73 [ 17 ] = KEY_PC, // PC/TV
74 [ 23 ] = KEY_OK, // CH RTN
75 [ 25 ] = KEY_MODE, // FUNC
76 [ 12 ] = KEY_SEARCH, // AUTOSCAN
77
78 /* Not sure what to do with these ones! */
79 [ 15 ] = KEY_SELECT, // SOURCE
80 [ 10 ] = KEY_KPPLUS, // +100
81 [ 20 ] = KEY_KPEQUAL, // SYNC
82 [ 28 ] = KEY_MEDIA, // PC/TV
83};
84
85static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
86 [ 0x3 ] = KEY_POWER,
87 [ 0x6f ] = KEY_MUTE,
88 [ 0x10 ] = KEY_BACKSPACE, // Recall
89
90 [ 0x11 ] = KEY_KP0,
91 [ 0x4 ] = KEY_KP1,
92 [ 0x5 ] = KEY_KP2,
93 [ 0x6 ] = KEY_KP3,
94 [ 0x8 ] = KEY_KP4,
95 [ 0x9 ] = KEY_KP5,
96 [ 0xa ] = KEY_KP6,
97 [ 0xc ] = KEY_KP7,
98 [ 0xd ] = KEY_KP8,
99 [ 0xe ] = KEY_KP9,
100 [ 0x12 ] = KEY_KPDOT, // 100+
101
102 [ 0x7 ] = KEY_VOLUMEUP,
103 [ 0xb ] = KEY_VOLUMEDOWN,
104 [ 0x1a ] = KEY_KPPLUS,
105 [ 0x18 ] = KEY_KPMINUS,
106 [ 0x15 ] = KEY_UP,
107 [ 0x1d ] = KEY_DOWN,
108 [ 0xf ] = KEY_CHANNELUP,
109 [ 0x13 ] = KEY_CHANNELDOWN,
110 [ 0x48 ] = KEY_ZOOM,
111
112 [ 0x1b ] = KEY_VIDEO, // Video source
113#if 0
114 [ 0x1f ] = KEY_S, // Snapshot
115#endif
116 [ 0x49 ] = KEY_LANGUAGE, // MTS Select
117 [ 0x19 ] = KEY_SEARCH, // Auto Scan
118
119 [ 0x4b ] = KEY_RECORD,
120 [ 0x46 ] = KEY_PLAY,
121 [ 0x45 ] = KEY_PAUSE, // Pause
122 [ 0x44 ] = KEY_STOP,
123#if 0
124 [ 0x43 ] = KEY_T, // Time Shift
125 [ 0x47 ] = KEY_Y, // Time Shift OFF
126 [ 0x4a ] = KEY_O, // TOP
127 [ 0x17 ] = KEY_F, // SURF CH
128#endif
129 [ 0x40 ] = KEY_FORWARD, // Forward ?
130 [ 0x42 ] = KEY_REWIND, // Backward ?
131
132};
133
134struct IR;
135struct IR {
136 struct i2c_client c;
137 struct input_dev input;
138 struct ir_input_state ir;
139
140 struct work_struct work;
141 struct timer_list timer;
142 char phys[32];
143 int (*get_key)(struct IR*, u32*, u32*);
144};
145
146/* ----------------------------------------------------------------------- */
147/* insmod parameters */
148
149static int debug;
150module_param(debug, int, 0644); /* debug level (0,1,2) */
151
152#define DEVNAME "ir-kbd-i2c"
153#define dprintk(level, fmt, arg...) if (debug >= level) \
154 printk(KERN_DEBUG DEVNAME ": " fmt , ## arg)
155
156/* ----------------------------------------------------------------------- */
157
158static int get_key_haup(struct IR *ir, u32 *ir_key, u32 *ir_raw)
159{
160 unsigned char buf[3];
161 int start, toggle, dev, code;
162
163 /* poll IR chip */
164 if (3 != i2c_master_recv(&ir->c,buf,3))
165 return -EIO;
166
167 /* split rc5 data block ... */
168 start = (buf[0] >> 6) & 3;
169 toggle = (buf[0] >> 5) & 1;
170 dev = buf[0] & 0x1f;
171 code = (buf[1] >> 2) & 0x3f;
172
173 if (3 != start)
174 /* no key pressed */
175 return 0;
176 dprintk(1,"ir hauppauge (rc5): s%d t%d dev=%d code=%d\n",
177 start, toggle, dev, code);
178
179 /* return key */
180 *ir_key = code;
181 *ir_raw = (start << 12) | (toggle << 11) | (dev << 6) | code;
182 return 1;
183}
184
185static int get_key_pixelview(struct IR *ir, u32 *ir_key, u32 *ir_raw)
186{
187 unsigned char b;
188
189 /* poll IR chip */
190 if (1 != i2c_master_recv(&ir->c,&b,1)) {
191 dprintk(1,"read error\n");
192 return -EIO;
193 }
194 *ir_key = b;
195 *ir_raw = b;
196 return 1;
197}
198
199static int get_key_pv951(struct IR *ir, u32 *ir_key, u32 *ir_raw)
200{
201 unsigned char b;
202
203 /* poll IR chip */
204 if (1 != i2c_master_recv(&ir->c,&b,1)) {
205 dprintk(1,"read error\n");
206 return -EIO;
207 }
208
209 /* ignore 0xaa */
210 if (b==0xaa)
211 return 0;
212 dprintk(2,"key %02x\n", b);
213
214 *ir_key = b;
215 *ir_raw = b;
216 return 1;
217}
218
219static int get_key_knc1(struct IR *ir, u32 *ir_key, u32 *ir_raw)
220{
221 unsigned char b;
222
223 /* poll IR chip */
224 if (1 != i2c_master_recv(&ir->c,&b,1)) {
225 dprintk(1,"read error\n");
226 return -EIO;
227 }
228
229 /* it seems that 0xFE indicates that a button is still hold
230 down, while 0xFF indicates that no button is hold
231 down. 0xFE sequences are sometimes interrupted by 0xFF */
232
233 dprintk(2,"key %02x\n", b);
234
235 if (b == 0xFF)
236 return 0;
237
238 if (b == 0xFE)
239 /* keep old data */
240 return 1;
241
242 *ir_key = b;
243 *ir_raw = b;
244 return 1;
245}
246
247static int get_key_purpletv(struct IR *ir, u32 *ir_key, u32 *ir_raw)
248{
249 unsigned char b;
250
251 /* poll IR chip */
252 if (1 != i2c_master_recv(&ir->c,&b,1)) {
253 dprintk(1,"read error\n");
254 return -EIO;
255 }
256
257 /* no button press */
258 if (b==0)
259 return 0;
260
261 /* repeating */
262 if (b & 0x80)
263 return 1;
264
265 *ir_key = b;
266 *ir_raw = b;
267 return 1;
268}
269/* ----------------------------------------------------------------------- */
270
271static void ir_key_poll(struct IR *ir)
272{
273 static u32 ir_key, ir_raw;
274 int rc;
275
276 dprintk(2,"ir_poll_key\n");
277 rc = ir->get_key(ir, &ir_key, &ir_raw);
278 if (rc < 0) {
279 dprintk(2,"error\n");
280 return;
281 }
282
283 if (0 == rc) {
284 ir_input_nokey(&ir->input,&ir->ir);
285 } else {
286 ir_input_keydown(&ir->input,&ir->ir, ir_key, ir_raw);
287 }
288}
289
290static void ir_timer(unsigned long data)
291{
292 struct IR *ir = (struct IR*)data;
293 schedule_work(&ir->work);
294}
295
296static void ir_work(void *data)
297{
298 struct IR *ir = data;
299 ir_key_poll(ir);
300 mod_timer(&ir->timer, jiffies+HZ/10);
301}
302
303/* ----------------------------------------------------------------------- */
304
305static int ir_attach(struct i2c_adapter *adap, int addr,
306 unsigned short flags, int kind);
307static int ir_detach(struct i2c_client *client);
308static int ir_probe(struct i2c_adapter *adap);
309
310static struct i2c_driver driver = {
311 .name = "ir remote kbd driver",
312 .id = I2C_DRIVERID_EXP3, /* FIXME */
313 .flags = I2C_DF_NOTIFY,
314 .attach_adapter = ir_probe,
315 .detach_client = ir_detach,
316};
317
318static struct i2c_client client_template =
319{
320 I2C_DEVNAME("unset"),
321 .driver = &driver
322};
323
324static int ir_attach(struct i2c_adapter *adap, int addr,
325 unsigned short flags, int kind)
326{
327 IR_KEYTAB_TYPE *ir_codes = NULL;
328 char *name;
329 int ir_type;
330 struct IR *ir;
331
332 if (NULL == (ir = kmalloc(sizeof(struct IR),GFP_KERNEL)))
333 return -ENOMEM;
334 memset(ir,0,sizeof(*ir));
335 ir->c = client_template;
336
337 i2c_set_clientdata(&ir->c, ir);
338 ir->c.adapter = adap;
339 ir->c.addr = addr;
340
341 switch(addr) {
342 case 0x64:
343 name = "Pixelview";
344 ir->get_key = get_key_pixelview;
345 ir_type = IR_TYPE_OTHER;
346 ir_codes = ir_codes_empty;
347 break;
348 case 0x4b:
349 name = "PV951";
350 ir->get_key = get_key_pv951;
351 ir_type = IR_TYPE_OTHER;
352 ir_codes = ir_codes_pv951;
353 break;
354 case 0x18:
355 case 0x1a:
356 name = "Hauppauge";
357 ir->get_key = get_key_haup;
358 ir_type = IR_TYPE_RC5;
359 ir_codes = ir_codes_rc5_tv;
360 break;
361 case 0x30:
362 name = "KNC One";
363 ir->get_key = get_key_knc1;
364 ir_type = IR_TYPE_OTHER;
365 ir_codes = ir_codes_empty;
366 break;
367 case 0x7a:
368 name = "Purple TV";
369 ir->get_key = get_key_purpletv;
370 ir_type = IR_TYPE_OTHER;
371 ir_codes = ir_codes_purpletv;
372 break;
373 default:
374 /* shouldn't happen */
375 printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n",addr);
376 kfree(ir);
377 return -1;
378 }
379
380 /* register i2c device */
381 i2c_attach_client(&ir->c);
382 snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name);
383 snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0",
384 ir->c.adapter->dev.bus_id,
385 ir->c.dev.bus_id);
386
387 /* init + register input device */
388 ir_input_init(&ir->input,&ir->ir,ir_type,ir_codes);
389 ir->input.id.bustype = BUS_I2C;
390 ir->input.name = ir->c.name;
391 ir->input.phys = ir->phys;
392 input_register_device(&ir->input);
393 printk(DEVNAME ": %s detected at %s [%s]\n",
394 ir->input.name,ir->input.phys,adap->name);
395
396 /* start polling via eventd */
397 INIT_WORK(&ir->work, ir_work, ir);
398 init_timer(&ir->timer);
399 ir->timer.function = ir_timer;
400 ir->timer.data = (unsigned long)ir;
401 schedule_work(&ir->work);
402
403 return 0;
404}
405
406static int ir_detach(struct i2c_client *client)
407{
408 struct IR *ir = i2c_get_clientdata(client);
409
410 /* kill outstanding polls */
411 del_timer(&ir->timer);
412 flush_scheduled_work();
413
414 /* unregister devices */
415 input_unregister_device(&ir->input);
416 i2c_detach_client(&ir->c);
417
418 /* free memory */
419 kfree(ir);
420 return 0;
421}
422
423static int ir_probe(struct i2c_adapter *adap)
424{
425
426 /* The external IR receiver is at i2c address 0x34 (0x35 for
427 reads). Future Hauppauge cards will have an internal
428 receiver at 0x30 (0x31 for reads). In theory, both can be
429 fitted, and Hauppauge suggest an external overrides an
430 internal.
431
432 That's why we probe 0x1a (~0x34) first. CB
433 */
434
435 static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
436 static const int probe_saa7134[] = { 0x7a, -1 };
437 const int *probe = NULL;
438 struct i2c_client c; char buf; int i,rc;
439
440 switch (adap->id) {
441 case I2C_ALGO_BIT | I2C_HW_B_BT848:
442 probe = probe_bttv;
443 break;
444 case I2C_ALGO_SAA7134:
445 probe = probe_saa7134;
446 break;
447 }
448 if (NULL == probe)
449 return 0;
450
451 memset(&c,0,sizeof(c));
452 c.adapter = adap;
453 for (i = 0; -1 != probe[i]; i++) {
454 c.addr = probe[i];
455 rc = i2c_master_recv(&c,&buf,1);
456 dprintk(1,"probe 0x%02x @ %s: %s\n",
457 probe[i], adap->name,
458 (1 == rc) ? "yes" : "no");
459 if (1 == rc) {
460 ir_attach(adap,probe[i],0,0);
461 break;
462 }
463 }
464 return 0;
465}
466
467/* ----------------------------------------------------------------------- */
468
469MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller");
470MODULE_DESCRIPTION("input driver for i2c IR remote controls");
471MODULE_LICENSE("GPL");
472
473static int __init ir_init(void)
474{
475 return i2c_add_driver(&driver);
476}
477
478static void __exit ir_fini(void)
479{
480 i2c_del_driver(&driver);
481}
482
483module_init(ir_init);
484module_exit(ir_fini);
485
486/*
487 * Overrides for Emacs so that we follow Linus's tabbing style.
488 * ---------------------------------------------------------------------------
489 * Local variables:
490 * c-basic-offset: 8
491 * End:
492 */