2 * $Id: saa7134-input.c,v 1.19 2005/06/07 18:02:26 nsh Exp $
4 * handle saa7134 IR remotes via linux kernel input layer.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <linux/module.h>
23 #include <linux/moduleparam.h>
24 #include <linux/init.h>
25 #include <linux/delay.h>
26 #include <linux/sched.h>
27 #include <linux/interrupt.h>
28 #include <linux/input.h>
30 #include "saa7134-reg.h"
33 static unsigned int disable_ir = 0;
34 module_param(disable_ir, int, 0444);
35 MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
37 static unsigned int ir_debug = 0;
38 module_param(ir_debug, int, 0644);
39 MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
41 #define dprintk(fmt, arg...) if (ir_debug) \
42 printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
44 /* ---------------------------------------------------------------------- */
46 static IR_KEYTAB_TYPE flyvideo_codes[IR_KEYTAB_SIZE] = {
58 [ 14 ] = KEY_TUNER, // Air/Cable
59 [ 17 ] = KEY_VIDEO, // Video
60 [ 21 ] = KEY_AUDIO, // Audio
61 [ 0 ] = KEY_POWER, // Pover
62 [ 2 ] = KEY_ZOOM, // Fullscreen
63 [ 27 ] = KEY_MUTE, // Mute
64 [ 20 ] = KEY_VOLUMEUP,
65 [ 23 ] = KEY_VOLUMEDOWN,
66 [ 18 ] = KEY_CHANNELUP, // Channel +
67 [ 19 ] = KEY_CHANNELDOWN, // Channel -
68 [ 6 ] = KEY_AGAIN, // Recal
69 [ 16 ] = KEY_KPENTER, // Enter
72 [ 26 ] = KEY_F22, // Stereo
73 [ 24 ] = KEY_EDIT, // AV Source
77 static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = {
90 [ 0x0b ] = KEY_PROG1, // app
91 [ 0x0c ] = KEY_ZOOM, // zoom/fullscreen
92 [ 0x0d ] = KEY_CHANNELUP, // channel
93 [ 0x0e ] = KEY_CHANNELDOWN, // channel-
94 [ 0x0f ] = KEY_VOLUMEUP,
95 [ 0x10 ] = KEY_VOLUMEDOWN,
96 [ 0x11 ] = KEY_TUNER, // AV
97 [ 0x12 ] = KEY_NUMLOCK, // -/--
98 [ 0x13 ] = KEY_AUDIO, // audio
103 [ 0x18 ] = KEY_RIGHT,
105 [ 0x1a ] = BTN_RIGHT,
106 [ 0x1b ] = KEY_WWW, // text
107 [ 0x1c ] = KEY_REWIND,
108 [ 0x1d ] = KEY_FORWARD,
109 [ 0x1e ] = KEY_RECORD,
111 [ 0x20 ] = KEY_PREVIOUSSONG,
112 [ 0x21 ] = KEY_NEXTSONG,
113 [ 0x22 ] = KEY_PAUSE,
117 /* Alfons Geser <a.geser@cox.net>
118 * updates from Job D. R. Borges <jobdrb@ig.com.br> */
119 static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
121 [ 1 ] = KEY_TV, // DVR
122 [ 21 ] = KEY_DVD, // DVD
123 [ 23 ] = KEY_AUDIO, // music
124 // DVR mode / DVD mode / music mode
126 [ 27 ] = KEY_MUTE, // mute
127 [ 2 ] = KEY_LANGUAGE, // MTS/SAP / audio / autoseek
128 [ 30 ] = KEY_SUBTITLE, // closed captioning / subtitle / seek
129 [ 22 ] = KEY_ZOOM, // full screen
130 [ 28 ] = KEY_VIDEO, // video source / eject / delall
131 [ 29 ] = KEY_RESTART, // playback / angle / del
132 [ 47 ] = KEY_SEARCH, // scan / menu / playlist
133 [ 48 ] = KEY_CHANNEL, // CH surfing / bookmark / memo
135 [ 49 ] = KEY_HELP, // help
136 [ 50 ] = KEY_MODE, // num/memo
137 [ 51 ] = KEY_ESC, // cancel
139 [ 12 ] = KEY_UP, // up
140 [ 16 ] = KEY_DOWN, // down
141 [ 8 ] = KEY_LEFT, // left
142 [ 4 ] = KEY_RIGHT, // right
143 [ 3 ] = KEY_SELECT, // select
145 [ 31 ] = KEY_REWIND, // rewind
146 [ 32 ] = KEY_PLAYPAUSE, // play/pause
147 [ 41 ] = KEY_FORWARD, // forward
148 [ 20 ] = KEY_AGAIN, // repeat
149 [ 43 ] = KEY_RECORD, // recording
150 [ 44 ] = KEY_STOP, // stop
151 [ 45 ] = KEY_PLAY, // play
152 [ 46 ] = KEY_SHUFFLE, // snapshot / shuffle
165 [ 42 ] = KEY_VOLUMEUP,
166 [ 17 ] = KEY_VOLUMEDOWN,
167 [ 24 ] = KEY_CHANNELUP, // CH.tracking up
168 [ 25 ] = KEY_CHANNELDOWN, // CH.tracking down
170 [ 19 ] = KEY_KPENTER, // enter
171 [ 33 ] = KEY_KPDOT, // . (decimal dot)
174 static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = {
175 [ 30 ] = KEY_POWER, // power
176 [ 28 ] = KEY_SEARCH, // scan
177 [ 7 ] = KEY_SELECT, // source
179 [ 22 ] = KEY_VOLUMEUP,
180 [ 20 ] = KEY_VOLUMEDOWN,
181 [ 31 ] = KEY_CHANNELUP,
182 [ 23 ] = KEY_CHANNELDOWN,
197 [ 3 ] = KEY_TUNER, // tv/fm
198 [ 4 ] = KEY_REWIND, // fm tuning left or function left
199 [ 12 ] = KEY_FORWARD, // fm tuning right or function right
206 [ 14 ] = KEY_MENU, // function
207 [ 19 ] = KEY_AGAIN, // recall
208 [ 29 ] = KEY_RESTART, // reset
211 [ 13 ] = KEY_F21, // mts
212 [ 15 ] = KEY_F22, // min
213 [ 26 ] = KEY_F23, // freeze
216 /* Alex Hermann <gaaf@gmx.net> */
217 static IR_KEYTAB_TYPE md2819_codes[IR_KEYTAB_SIZE] = {
229 [ 32 ] = KEY_TV, // TV/FM
230 [ 16 ] = KEY_CD, // CD
231 [ 48 ] = KEY_TEXT, // TELETEXT
232 [ 0 ] = KEY_POWER, // POWER
234 [ 8 ] = KEY_VIDEO, // VIDEO
235 [ 4 ] = KEY_AUDIO, // AUDIO
236 [ 12 ] = KEY_ZOOM, // FULL SCREEN
238 [ 18 ] = KEY_SUBTITLE, // DISPLAY - ???
239 [ 50 ] = KEY_REWIND, // LOOP - ???
240 [ 2 ] = KEY_PRINT, // PREVIEW - ???
242 [ 42 ] = KEY_SEARCH, // AUTOSCAN
243 [ 26 ] = KEY_SLEEP, // FREEZE - ???
244 [ 58 ] = KEY_SHUFFLE, // SNAPSHOT - ???
245 [ 10 ] = KEY_MUTE, // MUTE
247 [ 38 ] = KEY_RECORD, // RECORD
248 [ 22 ] = KEY_PAUSE, // PAUSE
249 [ 54 ] = KEY_STOP, // STOP
250 [ 6 ] = KEY_PLAY, // PLAY
252 [ 46 ] = KEY_RED, // <RED>
253 [ 33 ] = KEY_GREEN, // <GREEN>
254 [ 14 ] = KEY_YELLOW, // <YELLOW>
255 [ 1 ] = KEY_BLUE, // <BLUE>
257 [ 30 ] = KEY_VOLUMEDOWN, // VOLUME-
258 [ 62 ] = KEY_VOLUMEUP, // VOLUME+
259 [ 17 ] = KEY_CHANNELDOWN, // CHANNEL/PAGE-
260 [ 49 ] = KEY_CHANNELUP // CHANNEL/PAGE+
263 static IR_KEYTAB_TYPE videomate_tv_pvr_codes[IR_KEYTAB_SIZE] = {
272 [ 8 ] = KEY_PLAYPAUSE,
273 [ 15 ] = KEY_FORWARD,
275 [ 2 ] = KEY_PREVIOUS,
288 [ 34 ] = KEY_CHANNEL,
290 [ 18 ] = KEY_VOLUMEUP,
291 [ 21 ] = KEY_VOLUMEDOWN,
292 [ 16 ] = KEY_CHANNELUP,
293 [ 19 ] = KEY_CHANNELDOWN,
308 [ 32 ] = KEY_LANGUAGE,
312 /* Michael Tokarev <mjt@tls.msk.ru>
313 http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
314 keytable is used by MANLI MTV00[12] and BeholdTV 40[13] at
315 least, and probably other cards too.
316 The "ascii-art picture" below (in comments, first row
317 is the keycode in hex, and subsequent row(s) shows
318 the button labels (several variants when appropriate)
319 helps to descide which keycodes to assign to the buttons.
321 static IR_KEYTAB_TYPE manli_codes[IR_KEYTAB_SIZE] = {
327 [ 0x1c ] = KEY_RADIO, /*XXX*/
328 [ 0x12 ] = KEY_POWER,
353 [ 0x0a ] = KEY_AGAIN, /*XXX KEY_REWIND? */
355 [ 0x17 ] = KEY_DIGITS, /*XXX*/
372 [ 0x0b ] = KEY_UP, /*XXX KEY_SCROLLUP? */
373 [ 0x18 ] = KEY_LEFT, /*XXX KEY_BACK? */
374 [ 0x16 ] = KEY_OK, /*XXX KEY_SELECT? KEY_ENTER? */
375 [ 0x0c ] = KEY_RIGHT, /*XXX KEY_FORWARD? */
376 [ 0x15 ] = KEY_DOWN, /*XXX KEY_SCROLLDOWN? */
382 [ 0x11 ] = KEY_TV, /*XXX*/
383 [ 0x0d ] = KEY_MODE, /*XXX there's no KEY_STEREO */
392 [ 0x0f ] = KEY_AUDIO,
393 [ 0x1b ] = KEY_VOLUMEUP,
394 [ 0x1a ] = KEY_CHANNELUP,
395 [ 0x0e ] = KEY_SLEEP, /*XXX maybe KEY_PAUSE */
396 [ 0x1f ] = KEY_VOLUMEDOWN,
397 [ 0x1e ] = KEY_CHANNELDOWN,
403 [ 0x19 ] = KEY_RECORD, /*XXX*/
407 /* ---------------------------------------------------------------------- */
409 static int build_key(struct saa7134_dev *dev)
411 struct saa7134_ir *ir = dev->remote;
414 /* rising SAA7134_GPIO_GPRESCAN reads the status */
415 saa_clearb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
416 saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
418 gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
420 if (ir->last_gpio == gpio)
422 ir->last_gpio = gpio;
425 data = ir_extract_bits(gpio, ir->mask_keycode);
426 dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
427 gpio, ir->mask_keycode, data);
429 if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
430 (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
431 ir_input_keydown(&ir->dev,&ir->ir,data,data);
433 ir_input_nokey(&ir->dev,&ir->ir);
438 /* ---------------------------------------------------------------------- */
440 void saa7134_input_irq(struct saa7134_dev *dev)
442 struct saa7134_ir *ir = dev->remote;
448 static void saa7134_input_timer(unsigned long data)
450 struct saa7134_dev *dev = (struct saa7134_dev*)data;
451 struct saa7134_ir *ir = dev->remote;
452 unsigned long timeout;
455 timeout = jiffies + (ir->polling * HZ / 1000);
456 mod_timer(&ir->timer, timeout);
459 int saa7134_input_init1(struct saa7134_dev *dev)
461 struct saa7134_ir *ir;
462 IR_KEYTAB_TYPE *ir_codes = NULL;
463 u32 mask_keycode = 0;
464 u32 mask_keydown = 0;
467 int ir_type = IR_TYPE_OTHER;
469 if (!dev->has_remote)
474 /* detect & configure */
475 switch (dev->board) {
476 case SAA7134_BOARD_FLYVIDEO2000:
477 case SAA7134_BOARD_FLYVIDEO3000:
478 case SAA7134_BOARD_FLYTVPLATINUM_FM:
479 ir_codes = flyvideo_codes;
480 mask_keycode = 0xEC00000;
481 mask_keydown = 0x0040000;
483 case SAA7134_BOARD_CINERGY400:
484 case SAA7134_BOARD_CINERGY600:
485 case SAA7134_BOARD_CINERGY600_MK3:
486 ir_codes = cinergy_codes;
487 mask_keycode = 0x00003f;
488 mask_keyup = 0x040000;
490 case SAA7134_BOARD_ECS_TVP3XP:
491 case SAA7134_BOARD_ECS_TVP3XP_4CB5:
492 ir_codes = eztv_codes;
493 mask_keycode = 0x00017c;
494 mask_keyup = 0x000002;
497 case SAA7134_BOARD_AVACSSMARTTV:
498 ir_codes = avacssmart_codes;
499 mask_keycode = 0x00001F;
500 mask_keyup = 0x000020;
503 case SAA7134_BOARD_MD2819:
504 case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
505 case SAA7134_BOARD_AVERMEDIA_305:
506 case SAA7134_BOARD_AVERMEDIA_307:
507 case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
508 case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
509 case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
510 ir_codes = md2819_codes;
511 mask_keycode = 0x0007C8;
512 mask_keydown = 0x000010;
514 /* Set GPIO pin2 to high to enable the IR controller */
515 saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
516 saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
518 case SAA7134_BOARD_MANLI_MTV001:
519 case SAA7134_BOARD_MANLI_MTV002:
520 ir_codes = manli_codes;
521 mask_keycode = 0x001f00;
522 mask_keyup = 0x004000;
523 mask_keydown = 0x002000;
526 case SAA7134_BOARD_VIDEOMATE_TV_PVR:
527 ir_codes = videomate_tv_pvr_codes;
528 mask_keycode = 0x00003F;
529 mask_keyup = 0x400000;
533 if (NULL == ir_codes) {
534 printk("%s: Oops: IR config error [card=%d]\n",
535 dev->name, dev->board);
539 ir = kmalloc(sizeof(*ir),GFP_KERNEL);
542 memset(ir,0,sizeof(*ir));
544 /* init hardware-specific stuff */
545 ir->mask_keycode = mask_keycode;
546 ir->mask_keydown = mask_keydown;
547 ir->mask_keyup = mask_keyup;
548 ir->polling = polling;
550 /* init input device */
551 snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
552 saa7134_boards[dev->board].name);
553 snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
556 ir_input_init(&ir->dev, &ir->ir, ir_type, ir_codes);
557 ir->dev.name = ir->name;
558 ir->dev.phys = ir->phys;
559 ir->dev.id.bustype = BUS_PCI;
560 ir->dev.id.version = 1;
561 if (dev->pci->subsystem_vendor) {
562 ir->dev.id.vendor = dev->pci->subsystem_vendor;
563 ir->dev.id.product = dev->pci->subsystem_device;
565 ir->dev.id.vendor = dev->pci->vendor;
566 ir->dev.id.product = dev->pci->device;
572 init_timer(&ir->timer);
573 ir->timer.function = saa7134_input_timer;
574 ir->timer.data = (unsigned long)dev;
575 ir->timer.expires = jiffies + HZ;
576 add_timer(&ir->timer);
579 input_register_device(&dev->remote->dev);
580 printk("%s: registered input device for IR\n",dev->name);
584 void saa7134_input_fini(struct saa7134_dev *dev)
586 if (NULL == dev->remote)
589 input_unregister_device(&dev->remote->dev);
590 if (dev->remote->polling)
591 del_timer_sync(&dev->remote->timer);
596 /* ----------------------------------------------------------------------