diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-14 15:23:43 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-15 15:42:14 -0400 |
commit | cb7a01ac324bf2ee2c666f37ac867e4135f9785a (patch) | |
tree | 7246b915a9334d4bc823c93ba9acab65ef882678 /drivers/media/i2c/ir-kbd-i2c.c | |
parent | f0af8fa4dad0839f844fd0633e1936493f6d685a (diff) |
[media] move i2c files into drivers/media/i2c
Move ancillary I2C drivers into drivers/media/i2c, in order to
better organize them.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/i2c/ir-kbd-i2c.c')
-rw-r--r-- | drivers/media/i2c/ir-kbd-i2c.c | 489 |
1 files changed, 489 insertions, 0 deletions
diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c new file mode 100644 index 000000000000..04f192a0398a --- /dev/null +++ b/drivers/media/i2c/ir-kbd-i2c.c | |||
@@ -0,0 +1,489 @@ | |||
1 | /* | ||
2 | * | ||
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> | ||
11 | * modified for em2820 based USB TV tuners by | ||
12 | * Markus Rechberger <mrechberger@gmail.com> | ||
13 | * modified for DViCO Fusion HDTV 5 RT GOLD by | ||
14 | * Chaogui Zhang <czhang1974@gmail.com> | ||
15 | * modified for MSI TV@nywhere Plus by | ||
16 | * Henry Wong <henry@stuffedcow.net> | ||
17 | * Mark Schultz <n9xmj@yahoo.com> | ||
18 | * Brian Rogers <brian_rogers@comcast.net> | ||
19 | * modified for AVerMedia Cardbus by | ||
20 | * Oldrich Jedlicka <oldium.pro@seznam.cz> | ||
21 | * | ||
22 | * This program is free software; you can redistribute it and/or modify | ||
23 | * it under the terms of the GNU General Public License as published by | ||
24 | * the Free Software Foundation; either version 2 of the License, or | ||
25 | * (at your option) any later version. | ||
26 | * | ||
27 | * This program is distributed in the hope that it will be useful, | ||
28 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
29 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
30 | * GNU General Public License for more details. | ||
31 | * | ||
32 | * You should have received a copy of the GNU General Public License | ||
33 | * along with this program; if not, write to the Free Software | ||
34 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
35 | * | ||
36 | */ | ||
37 | |||
38 | #include <linux/module.h> | ||
39 | #include <linux/init.h> | ||
40 | #include <linux/kernel.h> | ||
41 | #include <linux/string.h> | ||
42 | #include <linux/timer.h> | ||
43 | #include <linux/delay.h> | ||
44 | #include <linux/errno.h> | ||
45 | #include <linux/slab.h> | ||
46 | #include <linux/i2c.h> | ||
47 | #include <linux/workqueue.h> | ||
48 | |||
49 | #include <media/rc-core.h> | ||
50 | #include <media/ir-kbd-i2c.h> | ||
51 | |||
52 | /* ----------------------------------------------------------------------- */ | ||
53 | /* insmod parameters */ | ||
54 | |||
55 | static int debug; | ||
56 | module_param(debug, int, 0644); /* debug level (0,1,2) */ | ||
57 | |||
58 | |||
59 | #define MODULE_NAME "ir-kbd-i2c" | ||
60 | #define dprintk(level, fmt, arg...) if (debug >= level) \ | ||
61 | printk(KERN_DEBUG MODULE_NAME ": " fmt , ## arg) | ||
62 | |||
63 | /* ----------------------------------------------------------------------- */ | ||
64 | |||
65 | static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, | ||
66 | int size, int offset) | ||
67 | { | ||
68 | unsigned char buf[6]; | ||
69 | int start, range, toggle, dev, code, ircode; | ||
70 | |||
71 | /* poll IR chip */ | ||
72 | if (size != i2c_master_recv(ir->c, buf, size)) | ||
73 | return -EIO; | ||
74 | |||
75 | /* split rc5 data block ... */ | ||
76 | start = (buf[offset] >> 7) & 1; | ||
77 | range = (buf[offset] >> 6) & 1; | ||
78 | toggle = (buf[offset] >> 5) & 1; | ||
79 | dev = buf[offset] & 0x1f; | ||
80 | code = (buf[offset+1] >> 2) & 0x3f; | ||
81 | |||
82 | /* rc5 has two start bits | ||
83 | * the first bit must be one | ||
84 | * the second bit defines the command range (1 = 0-63, 0 = 64 - 127) | ||
85 | */ | ||
86 | if (!start) | ||
87 | /* no key pressed */ | ||
88 | return 0; | ||
89 | /* | ||
90 | * Hauppauge remotes (black/silver) always use | ||
91 | * specific device ids. If we do not filter the | ||
92 | * device ids then messages destined for devices | ||
93 | * such as TVs (id=0) will get through causing | ||
94 | * mis-fired events. | ||
95 | * | ||
96 | * We also filter out invalid key presses which | ||
97 | * produce annoying debug log entries. | ||
98 | */ | ||
99 | ircode= (start << 12) | (toggle << 11) | (dev << 6) | code; | ||
100 | if ((ircode & 0x1fff)==0x1fff) | ||
101 | /* invalid key press */ | ||
102 | return 0; | ||
103 | |||
104 | if (!range) | ||
105 | code += 64; | ||
106 | |||
107 | dprintk(1,"ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n", | ||
108 | start, range, toggle, dev, code); | ||
109 | |||
110 | /* return key */ | ||
111 | *ir_key = (dev << 8) | code; | ||
112 | *ir_raw = ircode; | ||
113 | return 1; | ||
114 | } | ||
115 | |||
116 | static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | ||
117 | { | ||
118 | return get_key_haup_common (ir, ir_key, ir_raw, 3, 0); | ||
119 | } | ||
120 | |||
121 | static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | ||
122 | { | ||
123 | int ret; | ||
124 | unsigned char buf[1] = { 0 }; | ||
125 | |||
126 | /* | ||
127 | * This is the same apparent "are you ready?" poll command observed | ||
128 | * watching Windows driver traffic and implemented in lirc_zilog. With | ||
129 | * this added, we get far saner remote behavior with z8 chips on usb | ||
130 | * connected devices, even with the default polling interval of 100ms. | ||
131 | */ | ||
132 | ret = i2c_master_send(ir->c, buf, 1); | ||
133 | if (ret != 1) | ||
134 | return (ret < 0) ? ret : -EINVAL; | ||
135 | |||
136 | return get_key_haup_common (ir, ir_key, ir_raw, 6, 3); | ||
137 | } | ||
138 | |||
139 | static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | ||
140 | { | ||
141 | unsigned char b; | ||
142 | |||
143 | /* poll IR chip */ | ||
144 | if (1 != i2c_master_recv(ir->c, &b, 1)) { | ||
145 | dprintk(1,"read error\n"); | ||
146 | return -EIO; | ||
147 | } | ||
148 | *ir_key = b; | ||
149 | *ir_raw = b; | ||
150 | return 1; | ||
151 | } | ||
152 | |||
153 | static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | ||
154 | { | ||
155 | unsigned char buf[4]; | ||
156 | |||
157 | /* poll IR chip */ | ||
158 | if (4 != i2c_master_recv(ir->c, buf, 4)) { | ||
159 | dprintk(1,"read error\n"); | ||
160 | return -EIO; | ||
161 | } | ||
162 | |||
163 | if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0) | ||
164 | dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __func__, | ||
165 | buf[0], buf[1], buf[2], buf[3]); | ||
166 | |||
167 | /* no key pressed or signal from other ir remote */ | ||
168 | if(buf[0] != 0x1 || buf[1] != 0xfe) | ||
169 | return 0; | ||
170 | |||
171 | *ir_key = buf[2]; | ||
172 | *ir_raw = (buf[2] << 8) | buf[3]; | ||
173 | |||
174 | return 1; | ||
175 | } | ||
176 | |||
177 | static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | ||
178 | { | ||
179 | unsigned char b; | ||
180 | |||
181 | /* poll IR chip */ | ||
182 | if (1 != i2c_master_recv(ir->c, &b, 1)) { | ||
183 | dprintk(1,"read error\n"); | ||
184 | return -EIO; | ||
185 | } | ||
186 | |||
187 | /* it seems that 0xFE indicates that a button is still hold | ||
188 | down, while 0xff indicates that no button is hold | ||
189 | down. 0xfe sequences are sometimes interrupted by 0xFF */ | ||
190 | |||
191 | dprintk(2,"key %02x\n", b); | ||
192 | |||
193 | if (b == 0xff) | ||
194 | return 0; | ||
195 | |||
196 | if (b == 0xfe) | ||
197 | /* keep old data */ | ||
198 | return 1; | ||
199 | |||
200 | *ir_key = b; | ||
201 | *ir_raw = b; | ||
202 | return 1; | ||
203 | } | ||
204 | |||
205 | static int get_key_avermedia_cardbus(struct IR_i2c *ir, | ||
206 | u32 *ir_key, u32 *ir_raw) | ||
207 | { | ||
208 | unsigned char subaddr, key, keygroup; | ||
209 | struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0, | ||
210 | .buf = &subaddr, .len = 1}, | ||
211 | { .addr = ir->c->addr, .flags = I2C_M_RD, | ||
212 | .buf = &key, .len = 1} }; | ||
213 | subaddr = 0x0d; | ||
214 | if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { | ||
215 | dprintk(1, "read error\n"); | ||
216 | return -EIO; | ||
217 | } | ||
218 | |||
219 | if (key == 0xff) | ||
220 | return 0; | ||
221 | |||
222 | subaddr = 0x0b; | ||
223 | msg[1].buf = &keygroup; | ||
224 | if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { | ||
225 | dprintk(1, "read error\n"); | ||
226 | return -EIO; | ||
227 | } | ||
228 | |||
229 | if (keygroup == 0xff) | ||
230 | return 0; | ||
231 | |||
232 | dprintk(1, "read key 0x%02x/0x%02x\n", key, keygroup); | ||
233 | if (keygroup < 2 || keygroup > 3) { | ||
234 | /* Only a warning */ | ||
235 | dprintk(1, "warning: invalid key group 0x%02x for key 0x%02x\n", | ||
236 | keygroup, key); | ||
237 | } | ||
238 | key |= (keygroup & 1) << 6; | ||
239 | |||
240 | *ir_key = key; | ||
241 | *ir_raw = key; | ||
242 | return 1; | ||
243 | } | ||
244 | |||
245 | /* ----------------------------------------------------------------------- */ | ||
246 | |||
247 | static int ir_key_poll(struct IR_i2c *ir) | ||
248 | { | ||
249 | static u32 ir_key, ir_raw; | ||
250 | int rc; | ||
251 | |||
252 | dprintk(3, "%s\n", __func__); | ||
253 | rc = ir->get_key(ir, &ir_key, &ir_raw); | ||
254 | if (rc < 0) { | ||
255 | dprintk(2,"error\n"); | ||
256 | return rc; | ||
257 | } | ||
258 | |||
259 | if (rc) { | ||
260 | dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key); | ||
261 | rc_keydown(ir->rc, ir_key, 0); | ||
262 | } | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static void ir_work(struct work_struct *work) | ||
267 | { | ||
268 | int rc; | ||
269 | struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work); | ||
270 | |||
271 | rc = ir_key_poll(ir); | ||
272 | if (rc == -ENODEV) { | ||
273 | rc_unregister_device(ir->rc); | ||
274 | ir->rc = NULL; | ||
275 | return; | ||
276 | } | ||
277 | |||
278 | schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval)); | ||
279 | } | ||
280 | |||
281 | /* ----------------------------------------------------------------------- */ | ||
282 | |||
283 | static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) | ||
284 | { | ||
285 | char *ir_codes = NULL; | ||
286 | const char *name = NULL; | ||
287 | u64 rc_type = RC_TYPE_UNKNOWN; | ||
288 | struct IR_i2c *ir; | ||
289 | struct rc_dev *rc = NULL; | ||
290 | struct i2c_adapter *adap = client->adapter; | ||
291 | unsigned short addr = client->addr; | ||
292 | int err; | ||
293 | |||
294 | ir = kzalloc(sizeof(struct IR_i2c), GFP_KERNEL); | ||
295 | if (!ir) | ||
296 | return -ENOMEM; | ||
297 | |||
298 | ir->c = client; | ||
299 | ir->polling_interval = DEFAULT_POLLING_INTERVAL; | ||
300 | i2c_set_clientdata(client, ir); | ||
301 | |||
302 | switch(addr) { | ||
303 | case 0x64: | ||
304 | name = "Pixelview"; | ||
305 | ir->get_key = get_key_pixelview; | ||
306 | rc_type = RC_TYPE_OTHER; | ||
307 | ir_codes = RC_MAP_EMPTY; | ||
308 | break; | ||
309 | case 0x18: | ||
310 | case 0x1f: | ||
311 | case 0x1a: | ||
312 | name = "Hauppauge"; | ||
313 | ir->get_key = get_key_haup; | ||
314 | rc_type = RC_TYPE_RC5; | ||
315 | ir_codes = RC_MAP_HAUPPAUGE; | ||
316 | break; | ||
317 | case 0x30: | ||
318 | name = "KNC One"; | ||
319 | ir->get_key = get_key_knc1; | ||
320 | rc_type = RC_TYPE_OTHER; | ||
321 | ir_codes = RC_MAP_EMPTY; | ||
322 | break; | ||
323 | case 0x6b: | ||
324 | name = "FusionHDTV"; | ||
325 | ir->get_key = get_key_fusionhdtv; | ||
326 | rc_type = RC_TYPE_RC5; | ||
327 | ir_codes = RC_MAP_FUSIONHDTV_MCE; | ||
328 | break; | ||
329 | case 0x40: | ||
330 | name = "AVerMedia Cardbus remote"; | ||
331 | ir->get_key = get_key_avermedia_cardbus; | ||
332 | rc_type = RC_TYPE_OTHER; | ||
333 | ir_codes = RC_MAP_AVERMEDIA_CARDBUS; | ||
334 | break; | ||
335 | case 0x71: | ||
336 | name = "Hauppauge/Zilog Z8"; | ||
337 | ir->get_key = get_key_haup_xvr; | ||
338 | rc_type = RC_TYPE_RC5; | ||
339 | ir_codes = RC_MAP_HAUPPAUGE; | ||
340 | break; | ||
341 | } | ||
342 | |||
343 | /* Let the caller override settings */ | ||
344 | if (client->dev.platform_data) { | ||
345 | const struct IR_i2c_init_data *init_data = | ||
346 | client->dev.platform_data; | ||
347 | |||
348 | ir_codes = init_data->ir_codes; | ||
349 | rc = init_data->rc_dev; | ||
350 | |||
351 | name = init_data->name; | ||
352 | if (init_data->type) | ||
353 | rc_type = init_data->type; | ||
354 | |||
355 | if (init_data->polling_interval) | ||
356 | ir->polling_interval = init_data->polling_interval; | ||
357 | |||
358 | switch (init_data->internal_get_key_func) { | ||
359 | case IR_KBD_GET_KEY_CUSTOM: | ||
360 | /* The bridge driver provided us its own function */ | ||
361 | ir->get_key = init_data->get_key; | ||
362 | break; | ||
363 | case IR_KBD_GET_KEY_PIXELVIEW: | ||
364 | ir->get_key = get_key_pixelview; | ||
365 | break; | ||
366 | case IR_KBD_GET_KEY_HAUP: | ||
367 | ir->get_key = get_key_haup; | ||
368 | break; | ||
369 | case IR_KBD_GET_KEY_KNC1: | ||
370 | ir->get_key = get_key_knc1; | ||
371 | break; | ||
372 | case IR_KBD_GET_KEY_FUSIONHDTV: | ||
373 | ir->get_key = get_key_fusionhdtv; | ||
374 | break; | ||
375 | case IR_KBD_GET_KEY_HAUP_XVR: | ||
376 | ir->get_key = get_key_haup_xvr; | ||
377 | break; | ||
378 | case IR_KBD_GET_KEY_AVERMEDIA_CARDBUS: | ||
379 | ir->get_key = get_key_avermedia_cardbus; | ||
380 | break; | ||
381 | } | ||
382 | } | ||
383 | |||
384 | if (!rc) { | ||
385 | /* | ||
386 | * If platform_data doesn't specify rc_dev, initilize it | ||
387 | * internally | ||
388 | */ | ||
389 | rc = rc_allocate_device(); | ||
390 | if (!rc) { | ||
391 | err = -ENOMEM; | ||
392 | goto err_out_free; | ||
393 | } | ||
394 | } | ||
395 | ir->rc = rc; | ||
396 | |||
397 | /* Make sure we are all setup before going on */ | ||
398 | if (!name || !ir->get_key || !rc_type || !ir_codes) { | ||
399 | dprintk(1, ": Unsupported device at address 0x%02x\n", | ||
400 | addr); | ||
401 | err = -ENODEV; | ||
402 | goto err_out_free; | ||
403 | } | ||
404 | |||
405 | /* Sets name */ | ||
406 | snprintf(ir->name, sizeof(ir->name), "i2c IR (%s)", name); | ||
407 | ir->ir_codes = ir_codes; | ||
408 | |||
409 | snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0", | ||
410 | dev_name(&adap->dev), | ||
411 | dev_name(&client->dev)); | ||
412 | |||
413 | /* | ||
414 | * Initialize input_dev fields | ||
415 | * It doesn't make sense to allow overriding them via platform_data | ||
416 | */ | ||
417 | rc->input_id.bustype = BUS_I2C; | ||
418 | rc->input_phys = ir->phys; | ||
419 | rc->input_name = ir->name; | ||
420 | |||
421 | /* | ||
422 | * Initialize the other fields of rc_dev | ||
423 | */ | ||
424 | rc->map_name = ir->ir_codes; | ||
425 | rc->allowed_protos = rc_type; | ||
426 | if (!rc->driver_name) | ||
427 | rc->driver_name = MODULE_NAME; | ||
428 | |||
429 | err = rc_register_device(rc); | ||
430 | if (err) | ||
431 | goto err_out_free; | ||
432 | |||
433 | printk(MODULE_NAME ": %s detected at %s [%s]\n", | ||
434 | ir->name, ir->phys, adap->name); | ||
435 | |||
436 | /* start polling via eventd */ | ||
437 | INIT_DELAYED_WORK(&ir->work, ir_work); | ||
438 | schedule_delayed_work(&ir->work, 0); | ||
439 | |||
440 | return 0; | ||
441 | |||
442 | err_out_free: | ||
443 | /* Only frees rc if it were allocated internally */ | ||
444 | rc_free_device(rc); | ||
445 | kfree(ir); | ||
446 | return err; | ||
447 | } | ||
448 | |||
449 | static int ir_remove(struct i2c_client *client) | ||
450 | { | ||
451 | struct IR_i2c *ir = i2c_get_clientdata(client); | ||
452 | |||
453 | /* kill outstanding polls */ | ||
454 | cancel_delayed_work_sync(&ir->work); | ||
455 | |||
456 | /* unregister device */ | ||
457 | if (ir->rc) | ||
458 | rc_unregister_device(ir->rc); | ||
459 | |||
460 | /* free memory */ | ||
461 | kfree(ir); | ||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static const struct i2c_device_id ir_kbd_id[] = { | ||
466 | /* Generic entry for any IR receiver */ | ||
467 | { "ir_video", 0 }, | ||
468 | /* IR device specific entries should be added here */ | ||
469 | { "ir_rx_z8f0811_haup", 0 }, | ||
470 | { "ir_rx_z8f0811_hdpvr", 0 }, | ||
471 | { } | ||
472 | }; | ||
473 | |||
474 | static struct i2c_driver ir_kbd_driver = { | ||
475 | .driver = { | ||
476 | .name = "ir-kbd-i2c", | ||
477 | }, | ||
478 | .probe = ir_probe, | ||
479 | .remove = ir_remove, | ||
480 | .id_table = ir_kbd_id, | ||
481 | }; | ||
482 | |||
483 | module_i2c_driver(ir_kbd_driver); | ||
484 | |||
485 | /* ----------------------------------------------------------------------- */ | ||
486 | |||
487 | MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller"); | ||
488 | MODULE_DESCRIPTION("input driver for i2c IR remote controls"); | ||
489 | MODULE_LICENSE("GPL"); | ||