blob: 0cd1fc89b2d01e04e44316205fed5d8b779cd1c9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
3 * keyboard input driver for i2c IR remote controls
4 *
5 * Copyright (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org>
6 * modified for PixelView (BT878P+W/FM) by
7 * Michal Kochanowicz <mkochano@pld.org.pl>
8 * Christoph Bartelmus <lirc@bartelmus.de>
9 * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
10 * Ulrich Mueller <ulrich.mueller42@web.de>
Markus Rechbergerc3658642005-11-08 21:37:21 -080011 * modified for em2820 based USB TV tuners by
12 * Markus Rechberger <mrechberger@gmail.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 */
29
30#include <linux/module.h>
31#include <linux/moduleparam.h>
32#include <linux/init.h>
33#include <linux/kernel.h>
34#include <linux/sched.h>
35#include <linux/string.h>
36#include <linux/timer.h>
37#include <linux/delay.h>
38#include <linux/errno.h>
39#include <linux/slab.h>
40#include <linux/i2c.h>
41#include <linux/workqueue.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <asm/semaphore.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <media/ir-common.h>
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -080044#include <media/ir-kbd-i2c.h>
Markus Rechbergerc3658642005-11-08 21:37:21 -080045
Linus Torvalds1da177e2005-04-16 15:20:36 -070046/* Mark Phalan <phalanm@o2.ie> */
47static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -080048 [ 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,
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -080059 [ 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,
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -080069 [ 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78 /* Not sure what to do with these ones! */
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -080079 [ 15 ] = KEY_SELECT, /* SOURCE */
80 [ 10 ] = KEY_KPPLUS, /* +100 */
81 [ 20 ] = KEY_KPEQUAL, /* SYNC */
82 [ 28 ] = KEY_MEDIA, /* PC/TV */
Linus Torvalds1da177e2005-04-16 15:20:36 -070083};
84
85static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -080086 [ 0x3 ] = KEY_POWER,
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 [ 0x6f ] = KEY_MUTE,
Mauro Carvalho Chehabde9c6342005-07-12 13:58:41 -070088 [ 0x10 ] = KEY_BACKSPACE, /* Recall */
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90 [ 0x11 ] = KEY_KP0,
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -080091 [ 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,
Mauro Carvalho Chehabde9c6342005-07-12 13:58:41 -0700100 [ 0x12 ] = KEY_KPDOT, /* 100+ */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800102 [ 0x7 ] = KEY_VOLUMEUP,
103 [ 0xb ] = KEY_VOLUMEDOWN,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 [ 0x1a ] = KEY_KPPLUS,
105 [ 0x18 ] = KEY_KPMINUS,
106 [ 0x15 ] = KEY_UP,
107 [ 0x1d ] = KEY_DOWN,
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800108 [ 0xf ] = KEY_CHANNELUP,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 [ 0x13 ] = KEY_CHANNELDOWN,
110 [ 0x48 ] = KEY_ZOOM,
111
Mauro Carvalho Chehabde9c6342005-07-12 13:58:41 -0700112 [ 0x1b ] = KEY_VIDEO, /* Video source */
113 [ 0x49 ] = KEY_LANGUAGE, /* MTS Select */
114 [ 0x19 ] = KEY_SEARCH, /* Auto Scan */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
116 [ 0x4b ] = KEY_RECORD,
117 [ 0x46 ] = KEY_PLAY,
Mauro Carvalho Chehabde9c6342005-07-12 13:58:41 -0700118 [ 0x45 ] = KEY_PAUSE, /* Pause */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 [ 0x44 ] = KEY_STOP,
Mauro Carvalho Chehabde9c6342005-07-12 13:58:41 -0700120 [ 0x40 ] = KEY_FORWARD, /* Forward ? */
121 [ 0x42 ] = KEY_REWIND, /* Backward ? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
123};
124
Ricardo Cerqueirac2f6f9d2005-11-08 21:37:51 -0800125static IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
126 [ 0x59 ] = KEY_MUTE,
127 [ 0x4a ] = KEY_POWER,
128
129 [ 0x18 ] = KEY_TEXT,
130 [ 0x26 ] = KEY_TV,
131 [ 0x3d ] = KEY_PRINT,
132
133 [ 0x48 ] = KEY_RED,
134 [ 0x04 ] = KEY_GREEN,
135 [ 0x11 ] = KEY_YELLOW,
136 [ 0x00 ] = KEY_BLUE,
137
138 [ 0x2d ] = KEY_VOLUMEUP,
139 [ 0x1e ] = KEY_VOLUMEDOWN,
140
141 [ 0x49 ] = KEY_MENU,
142
143 [ 0x16 ] = KEY_CHANNELUP,
144 [ 0x17 ] = KEY_CHANNELDOWN,
145
146 [ 0x20 ] = KEY_UP,
147 [ 0x21 ] = KEY_DOWN,
148 [ 0x22 ] = KEY_LEFT,
149 [ 0x23 ] = KEY_RIGHT,
150 [ 0x0d ] = KEY_SELECT,
151
152
153
154 [ 0x08 ] = KEY_BACK,
155 [ 0x07 ] = KEY_REFRESH,
156
157 [ 0x2f ] = KEY_ZOOM,
158 [ 0x29 ] = KEY_RECORD,
159
160 [ 0x4b ] = KEY_PAUSE,
161 [ 0x4d ] = KEY_REWIND,
162 [ 0x2e ] = KEY_PLAY,
163 [ 0x4e ] = KEY_FORWARD,
164 [ 0x53 ] = KEY_PREVIOUS,
165 [ 0x4c ] = KEY_STOP,
166 [ 0x54 ] = KEY_NEXT,
167
168 [ 0x69 ] = KEY_KP0,
169 [ 0x6a ] = KEY_KP1,
170 [ 0x6b ] = KEY_KP2,
171 [ 0x6c ] = KEY_KP3,
172 [ 0x6d ] = KEY_KP4,
173 [ 0x6e ] = KEY_KP5,
174 [ 0x6f ] = KEY_KP6,
175 [ 0x70 ] = KEY_KP7,
176 [ 0x71 ] = KEY_KP8,
177 [ 0x72 ] = KEY_KP9,
178
179 [ 0x74 ] = KEY_CHANNEL,
180 [ 0x0a ] = KEY_BACKSPACE,
181};
182
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183/* ----------------------------------------------------------------------- */
184/* insmod parameters */
185
186static int debug;
187module_param(debug, int, 0644); /* debug level (0,1,2) */
188
189#define DEVNAME "ir-kbd-i2c"
190#define dprintk(level, fmt, arg...) if (debug >= level) \
191 printk(KERN_DEBUG DEVNAME ": " fmt , ## arg)
192
193/* ----------------------------------------------------------------------- */
194
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800195static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196{
197 unsigned char buf[3];
198 int start, toggle, dev, code;
199
200 /* poll IR chip */
201 if (3 != i2c_master_recv(&ir->c,buf,3))
202 return -EIO;
203
204 /* split rc5 data block ... */
205 start = (buf[0] >> 6) & 3;
206 toggle = (buf[0] >> 5) & 1;
207 dev = buf[0] & 0x1f;
208 code = (buf[1] >> 2) & 0x3f;
209
210 if (3 != start)
211 /* no key pressed */
212 return 0;
213 dprintk(1,"ir hauppauge (rc5): s%d t%d dev=%d code=%d\n",
214 start, toggle, dev, code);
215
216 /* return key */
217 *ir_key = code;
218 *ir_raw = (start << 12) | (toggle << 11) | (dev << 6) | code;
219 return 1;
220}
221
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800222static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800224 unsigned char b;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
226 /* poll IR chip */
227 if (1 != i2c_master_recv(&ir->c,&b,1)) {
228 dprintk(1,"read error\n");
229 return -EIO;
230 }
231 *ir_key = b;
232 *ir_raw = b;
233 return 1;
234}
235
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800236static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800238 unsigned char b;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
240 /* poll IR chip */
241 if (1 != i2c_master_recv(&ir->c,&b,1)) {
242 dprintk(1,"read error\n");
243 return -EIO;
244 }
245
246 /* ignore 0xaa */
247 if (b==0xaa)
248 return 0;
249 dprintk(2,"key %02x\n", b);
250
251 *ir_key = b;
252 *ir_raw = b;
253 return 1;
254}
255
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800256static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257{
258 unsigned char b;
259
260 /* poll IR chip */
261 if (1 != i2c_master_recv(&ir->c,&b,1)) {
262 dprintk(1,"read error\n");
263 return -EIO;
264 }
265
266 /* it seems that 0xFE indicates that a button is still hold
Mauro Carvalho Chehab4f9c05a2005-11-08 21:37:36 -0800267 down, while 0xff indicates that no button is hold
268 down. 0xfe sequences are sometimes interrupted by 0xFF */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
270 dprintk(2,"key %02x\n", b);
271
Mauro Carvalho Chehab4f9c05a2005-11-08 21:37:36 -0800272 if (b == 0xff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 return 0;
274
Mauro Carvalho Chehab4f9c05a2005-11-08 21:37:36 -0800275 if (b == 0xfe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 /* keep old data */
277 return 1;
278
279 *ir_key = b;
280 *ir_raw = b;
281 return 1;
282}
283
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800284static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800286 unsigned char b;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288 /* poll IR chip */
289 if (1 != i2c_master_recv(&ir->c,&b,1)) {
290 dprintk(1,"read error\n");
291 return -EIO;
292 }
293
294 /* no button press */
295 if (b==0)
296 return 0;
297
298 /* repeating */
299 if (b & 0x80)
300 return 1;
301
302 *ir_key = b;
303 *ir_raw = b;
304 return 1;
305}
Ricardo Cerqueirac2f6f9d2005-11-08 21:37:51 -0800306
307/* The new pinnacle PCTV remote (with the colored buttons)
308 *
309 * Ricardo Cerqueira <v4l@cerqueira.org>
310 */
311
312static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
313{
314 unsigned char b[4];
315 unsigned int start = 0,parity = 0,code = 0;
316
317 /* poll IR chip */
318 if (4 != i2c_master_recv(&ir->c,b,4)) {
319 dprintk(1,"read error\n");
320 return -EIO;
321 }
322
323 for (start = 0; start<4; start++) {
324 if (b[start] == 0x80) {
325 code=b[(start+3)%4];
326 parity=b[(start+2)%4];
327 }
328 }
329
330 /* Empty Request */
331 if (parity==0)
332 return 0;
333
334 /* Repeating... */
335 if (ir->old == parity)
336 return 0;
337
338
339 ir->old = parity;
340
341 /* Reduce code value to fit inside IR_KEYTAB_SIZE
342 *
343 * this is the only value that results in 42 unique
344 * codes < 128
345 */
346
347 code %= 0x88;
348
349 *ir_raw = code;
350 *ir_key = code;
351
352 dprintk(1,"Pinnacle PCTV key %02x\n", code);
353
354 return 1;
355}
356
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358/* ----------------------------------------------------------------------- */
359
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800360static void ir_key_poll(struct IR_i2c *ir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361{
362 static u32 ir_key, ir_raw;
363 int rc;
364
365 dprintk(2,"ir_poll_key\n");
366 rc = ir->get_key(ir, &ir_key, &ir_raw);
367 if (rc < 0) {
368 dprintk(2,"error\n");
369 return;
370 }
371
372 if (0 == rc) {
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500373 ir_input_nokey(ir->input, &ir->ir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 } else {
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500375 ir_input_keydown(ir->input, &ir->ir, ir_key, ir_raw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 }
377}
378
379static void ir_timer(unsigned long data)
380{
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800381 struct IR_i2c *ir = (struct IR_i2c*)data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 schedule_work(&ir->work);
383}
384
385static void ir_work(void *data)
386{
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800387 struct IR_i2c *ir = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 ir_key_poll(ir);
389 mod_timer(&ir->timer, jiffies+HZ/10);
390}
391
392/* ----------------------------------------------------------------------- */
393
394static int ir_attach(struct i2c_adapter *adap, int addr,
395 unsigned short flags, int kind);
396static int ir_detach(struct i2c_client *client);
397static int ir_probe(struct i2c_adapter *adap);
398
399static struct i2c_driver driver = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800400 .name = "ir remote kbd driver",
401 .id = I2C_DRIVERID_EXP3, /* FIXME */
402 .flags = I2C_DF_NOTIFY,
403 .attach_adapter = ir_probe,
404 .detach_client = ir_detach,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405};
406
407static struct i2c_client client_template =
408{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800409 .name = "unset",
410 .driver = &driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411};
412
413static int ir_attach(struct i2c_adapter *adap, int addr,
414 unsigned short flags, int kind)
415{
416 IR_KEYTAB_TYPE *ir_codes = NULL;
417 char *name;
418 int ir_type;
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800419 struct IR_i2c *ir;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500420 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800422 ir = kzalloc(sizeof(struct IR_i2c), GFP_KERNEL);
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500423 input_dev = input_allocate_device();
424 if (!ir || !input_dev) {
425 kfree(ir);
426 input_free_device(input_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 return -ENOMEM;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500428 }
429
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 ir->c = client_template;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500431 ir->input = input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
433 i2c_set_clientdata(&ir->c, ir);
434 ir->c.adapter = adap;
435 ir->c.addr = addr;
436
437 switch(addr) {
438 case 0x64:
439 name = "Pixelview";
440 ir->get_key = get_key_pixelview;
441 ir_type = IR_TYPE_OTHER;
442 ir_codes = ir_codes_empty;
443 break;
444 case 0x4b:
445 name = "PV951";
446 ir->get_key = get_key_pv951;
447 ir_type = IR_TYPE_OTHER;
448 ir_codes = ir_codes_pv951;
449 break;
450 case 0x18:
451 case 0x1a:
452 name = "Hauppauge";
453 ir->get_key = get_key_haup;
454 ir_type = IR_TYPE_RC5;
455 ir_codes = ir_codes_rc5_tv;
456 break;
457 case 0x30:
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800458 name = "KNC One";
459 ir->get_key = get_key_knc1;
460 ir_type = IR_TYPE_OTHER;
461 ir_codes = ir_codes_empty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 break;
Ricardo Cerqueirac2f6f9d2005-11-08 21:37:51 -0800463 case 0x47:
464 name = "Pinnacle PCTV";
465 ir->get_key = get_key_pinnacle;
466 ir_type = IR_TYPE_OTHER;
467 ir_codes = ir_codes_pinnacle;
468 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 case 0x7a:
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800470 name = "Purple TV";
471 ir->get_key = get_key_purpletv;
472 ir_type = IR_TYPE_OTHER;
473 ir_codes = ir_codes_purpletv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 break;
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800475
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 default:
477 /* shouldn't happen */
478 printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n",addr);
479 kfree(ir);
480 return -1;
481 }
482
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800483 /* Sets name and its physical addr */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name);
485 snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0",
486 ir->c.adapter->dev.bus_id,
487 ir->c.dev.bus_id);
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800488 ir->ir_codes=ir_codes;
489
490 /* register i2c device
491 * At device register, IR codes may be changed to be
492 * board dependent.
493 */
494 i2c_attach_client(&ir->c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
496 /* init + register input device */
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500497 ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
498 input_dev->id.bustype = BUS_I2C;
499 input_dev->name = ir->c.name;
500 input_dev->phys = ir->phys;
501
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800502 /* register event device */
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500503 input_register_device(ir->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
505 /* start polling via eventd */
506 INIT_WORK(&ir->work, ir_work, ir);
507 init_timer(&ir->timer);
508 ir->timer.function = ir_timer;
509 ir->timer.data = (unsigned long)ir;
510 schedule_work(&ir->work);
511
512 return 0;
513}
514
515static int ir_detach(struct i2c_client *client)
516{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800517 struct IR_i2c *ir = i2c_get_clientdata(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
519 /* kill outstanding polls */
520 del_timer(&ir->timer);
521 flush_scheduled_work();
522
523 /* unregister devices */
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500524 input_unregister_device(ir->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 i2c_detach_client(&ir->c);
526
527 /* free memory */
528 kfree(ir);
529 return 0;
530}
531
532static int ir_probe(struct i2c_adapter *adap)
533{
534
535 /* The external IR receiver is at i2c address 0x34 (0x35 for
536 reads). Future Hauppauge cards will have an internal
537 receiver at 0x30 (0x31 for reads). In theory, both can be
538 fitted, and Hauppauge suggest an external overrides an
539 internal.
540
541 That's why we probe 0x1a (~0x34) first. CB
542 */
543
544 static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
Ricardo Cerqueirac2f6f9d2005-11-08 21:37:51 -0800545 static const int probe_saa7134[] = { 0x7a, 0x47, -1 };
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800546 static const int probe_em2820[] = { 0x30, 0x47, -1 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 const int *probe = NULL;
Mauro Carvalho Chehab4f9c05a2005-11-08 21:37:36 -0800548 struct i2c_client c;
549 unsigned char buf;
550 int i,rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
552 switch (adap->id) {
Jean Delvarec7a46532005-08-11 23:41:56 +0200553 case I2C_HW_B_BT848:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 probe = probe_bttv;
555 break;
Jean Delvare1684a9842005-08-11 23:51:10 +0200556 case I2C_HW_SAA7134:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 probe = probe_saa7134;
558 break;
Markus Rechbergerc3658642005-11-08 21:37:21 -0800559 case I2C_HW_B_EM2820:
560 probe = probe_em2820;
561 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 }
563 if (NULL == probe)
564 return 0;
565
566 memset(&c,0,sizeof(c));
567 c.adapter = adap;
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800568 for (i = 0; -1 != probe[i]; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 c.addr = probe[i];
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800570 rc = i2c_master_recv(&c,&buf,0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 dprintk(1,"probe 0x%02x @ %s: %s\n",
572 probe[i], adap->name,
Mauro Carvalho Chehabd5e52652005-11-08 21:37:32 -0800573 (0 == rc) ? "yes" : "no");
574 if (0 == rc) {
575 ir_attach(adap,probe[i],0,0);
576 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 }
578 }
579 return 0;
580}
581
582/* ----------------------------------------------------------------------- */
583
584MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller");
585MODULE_DESCRIPTION("input driver for i2c IR remote controls");
586MODULE_LICENSE("GPL");
587
588static int __init ir_init(void)
589{
590 return i2c_add_driver(&driver);
591}
592
593static void __exit ir_fini(void)
594{
595 i2c_del_driver(&driver);
596}
597
598module_init(ir_init);
599module_exit(ir_fini);
600
601/*
602 * Overrides for Emacs so that we follow Linus's tabbing style.
603 * ---------------------------------------------------------------------------
604 * Local variables:
605 * c-basic-offset: 8
606 * End:
607 */