2 * $Id: saa7134-input.c,v 1.21 2005/06/22 23:37:34 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
71 [ 26 ] = KEY_F22, // Stereo
72 [ 24 ] = KEY_EDIT, // AV Source
75 static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = {
88 [ 0x0b ] = KEY_PROG1, // app
89 [ 0x0c ] = KEY_ZOOM, // zoom/fullscreen
90 [ 0x0d ] = KEY_CHANNELUP, // channel
91 [ 0x0e ] = KEY_CHANNELDOWN, // channel-
92 [ 0x0f ] = KEY_VOLUMEUP,
93 [ 0x10 ] = KEY_VOLUMEDOWN,
94 [ 0x11 ] = KEY_TUNER, // AV
95 [ 0x12 ] = KEY_NUMLOCK, // -/--
96 [ 0x13 ] = KEY_AUDIO, // audio
101 [ 0x18 ] = KEY_RIGHT,
103 [ 0x1a ] = BTN_RIGHT,
104 [ 0x1b ] = KEY_WWW, // text
105 [ 0x1c ] = KEY_REWIND,
106 [ 0x1d ] = KEY_FORWARD,
107 [ 0x1e ] = KEY_RECORD,
109 [ 0x20 ] = KEY_PREVIOUSSONG,
110 [ 0x21 ] = KEY_NEXTSONG,
111 [ 0x22 ] = KEY_PAUSE,
115 /* Alfons Geser <a.geser@cox.net>
116 * updates from Job D. R. Borges <jobdrb@ig.com.br> */
117 static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
119 [ 1 ] = KEY_TV, // DVR
120 [ 21 ] = KEY_DVD, // DVD
121 [ 23 ] = KEY_AUDIO, // music
122 // DVR mode / DVD mode / music mode
124 [ 27 ] = KEY_MUTE, // mute
125 [ 2 ] = KEY_LANGUAGE, // MTS/SAP / audio / autoseek
126 [ 30 ] = KEY_SUBTITLE, // closed captioning / subtitle / seek
127 [ 22 ] = KEY_ZOOM, // full screen
128 [ 28 ] = KEY_VIDEO, // video source / eject / delall
129 [ 29 ] = KEY_RESTART, // playback / angle / del
130 [ 47 ] = KEY_SEARCH, // scan / menu / playlist
131 [ 48 ] = KEY_CHANNEL, // CH surfing / bookmark / memo
133 [ 49 ] = KEY_HELP, // help
134 [ 50 ] = KEY_MODE, // num/memo
135 [ 51 ] = KEY_ESC, // cancel
137 [ 12 ] = KEY_UP, // up
138 [ 16 ] = KEY_DOWN, // down
139 [ 8 ] = KEY_LEFT, // left
140 [ 4 ] = KEY_RIGHT, // right
141 [ 3 ] = KEY_SELECT, // select
143 [ 31 ] = KEY_REWIND, // rewind
144 [ 32 ] = KEY_PLAYPAUSE, // play/pause
145 [ 41 ] = KEY_FORWARD, // forward
146 [ 20 ] = KEY_AGAIN, // repeat
147 [ 43 ] = KEY_RECORD, // recording
148 [ 44 ] = KEY_STOP, // stop
149 [ 45 ] = KEY_PLAY, // play
150 [ 46 ] = KEY_SHUFFLE, // snapshot / shuffle
163 [ 42 ] = KEY_VOLUMEUP,
164 [ 17 ] = KEY_VOLUMEDOWN,
165 [ 24 ] = KEY_CHANNELUP, // CH.tracking up
166 [ 25 ] = KEY_CHANNELDOWN, // CH.tracking down
168 [ 19 ] = KEY_KPENTER, // enter
169 [ 33 ] = KEY_KPDOT, // . (decimal dot)
172 static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = {
173 [ 30 ] = KEY_POWER, // power
174 [ 28 ] = KEY_SEARCH, // scan
175 [ 7 ] = KEY_SELECT, // source
177 [ 22 ] = KEY_VOLUMEUP,
178 [ 20 ] = KEY_VOLUMEDOWN,
179 [ 31 ] = KEY_CHANNELUP,
180 [ 23 ] = KEY_CHANNELDOWN,
195 [ 3 ] = KEY_TUNER, // tv/fm
196 [ 4 ] = KEY_REWIND, // fm tuning left or function left
197 [ 12 ] = KEY_FORWARD, // fm tuning right or function right
204 [ 14 ] = KEY_MENU, // function
205 [ 19 ] = KEY_AGAIN, // recall
206 [ 29 ] = KEY_RESTART, // reset
207 [ 26 ] = KEY_SHUFFLE, // snapshot/shuffle
210 [ 13 ] = KEY_F21, // mts
211 [ 15 ] = KEY_F22, // min
214 /* Alex Hermann <gaaf@gmx.net> */
215 static IR_KEYTAB_TYPE md2819_codes[IR_KEYTAB_SIZE] = {
227 [ 32 ] = KEY_TV, // TV/FM
228 [ 16 ] = KEY_CD, // CD
229 [ 48 ] = KEY_TEXT, // TELETEXT
230 [ 0 ] = KEY_POWER, // POWER
232 [ 8 ] = KEY_VIDEO, // VIDEO
233 [ 4 ] = KEY_AUDIO, // AUDIO
234 [ 12 ] = KEY_ZOOM, // FULL SCREEN
236 [ 18 ] = KEY_SUBTITLE, // DISPLAY - ???
237 [ 50 ] = KEY_REWIND, // LOOP - ???
238 [ 2 ] = KEY_PRINT, // PREVIEW - ???
240 [ 42 ] = KEY_SEARCH, // AUTOSCAN
241 [ 26 ] = KEY_SLEEP, // FREEZE - ???
242 [ 58 ] = KEY_SHUFFLE, // SNAPSHOT - ???
243 [ 10 ] = KEY_MUTE, // MUTE
245 [ 38 ] = KEY_RECORD, // RECORD
246 [ 22 ] = KEY_PAUSE, // PAUSE
247 [ 54 ] = KEY_STOP, // STOP
248 [ 6 ] = KEY_PLAY, // PLAY
250 [ 46 ] = KEY_RED, // <RED>
251 [ 33 ] = KEY_GREEN, // <GREEN>
252 [ 14 ] = KEY_YELLOW, // <YELLOW>
253 [ 1 ] = KEY_BLUE, // <BLUE>
255 [ 30 ] = KEY_VOLUMEDOWN, // VOLUME-
256 [ 62 ] = KEY_VOLUMEUP, // VOLUME+
257 [ 17 ] = KEY_CHANNELDOWN, // CHANNEL/PAGE-
258 [ 49 ] = KEY_CHANNELUP // CHANNEL/PAGE+
261 static IR_KEYTAB_TYPE videomate_tv_pvr_codes[IR_KEYTAB_SIZE] = {
270 [ 8 ] = KEY_PLAYPAUSE,
271 [ 15 ] = KEY_FORWARD,
273 [ 2 ] = KEY_PREVIOUS,
286 [ 34 ] = KEY_CHANNEL,
288 [ 18 ] = KEY_VOLUMEUP,
289 [ 21 ] = KEY_VOLUMEDOWN,
290 [ 16 ] = KEY_CHANNELUP,
291 [ 19 ] = KEY_CHANNELDOWN,
306 [ 32 ] = KEY_LANGUAGE,
310 /* Michael Tokarev <mjt@tls.msk.ru>
311 http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
312 keytable is used by MANLI MTV00[12] and BeholdTV 40[13] at
313 least, and probably other cards too.
314 The "ascii-art picture" below (in comments, first row
315 is the keycode in hex, and subsequent row(s) shows
316 the button labels (several variants when appropriate)
317 helps to descide which keycodes to assign to the buttons.
319 static IR_KEYTAB_TYPE manli_codes[IR_KEYTAB_SIZE] = {
325 [ 0x1c ] = KEY_RADIO, /*XXX*/
326 [ 0x12 ] = KEY_POWER,
351 [ 0x0a ] = KEY_AGAIN, /*XXX KEY_REWIND? */
353 [ 0x17 ] = KEY_DIGITS, /*XXX*/
370 [ 0x0b ] = KEY_UP, /*XXX KEY_SCROLLUP? */
371 [ 0x18 ] = KEY_LEFT, /*XXX KEY_BACK? */
372 [ 0x16 ] = KEY_OK, /*XXX KEY_SELECT? KEY_ENTER? */
373 [ 0x0c ] = KEY_RIGHT, /*XXX KEY_FORWARD? */
374 [ 0x15 ] = KEY_DOWN, /*XXX KEY_SCROLLDOWN? */
380 [ 0x11 ] = KEY_TV, /*XXX*/
381 [ 0x0d ] = KEY_MODE, /*XXX there's no KEY_STEREO */
390 [ 0x0f ] = KEY_AUDIO,
391 [ 0x1b ] = KEY_VOLUMEUP,
392 [ 0x1a ] = KEY_CHANNELUP,
393 [ 0x0e ] = KEY_SLEEP, /*XXX maybe KEY_PAUSE */
394 [ 0x1f ] = KEY_VOLUMEDOWN,
395 [ 0x1e ] = KEY_CHANNELDOWN,
401 [ 0x19 ] = KEY_RECORD, /*XXX*/
405 /* ---------------------------------------------------------------------- */
407 static int build_key(struct saa7134_dev *dev)
409 struct saa7134_ir *ir = dev->remote;
412 /* rising SAA7134_GPIO_GPRESCAN reads the status */
413 saa_clearb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
414 saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
416 gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
418 if (ir->last_gpio == gpio)
420 ir->last_gpio = gpio;
423 data = ir_extract_bits(gpio, ir->mask_keycode);
424 dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
425 gpio, ir->mask_keycode, data);
427 if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
428 (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
429 ir_input_keydown(&ir->dev,&ir->ir,data,data);
431 ir_input_nokey(&ir->dev,&ir->ir);
436 /* ---------------------------------------------------------------------- */
438 void saa7134_input_irq(struct saa7134_dev *dev)
440 struct saa7134_ir *ir = dev->remote;
446 static void saa7134_input_timer(unsigned long data)
448 struct saa7134_dev *dev = (struct saa7134_dev*)data;
449 struct saa7134_ir *ir = dev->remote;
450 unsigned long timeout;
453 timeout = jiffies + (ir->polling * HZ / 1000);
454 mod_timer(&ir->timer, timeout);
457 int saa7134_input_init1(struct saa7134_dev *dev)
459 struct saa7134_ir *ir;
460 IR_KEYTAB_TYPE *ir_codes = NULL;
461 u32 mask_keycode = 0;
462 u32 mask_keydown = 0;
465 int ir_type = IR_TYPE_OTHER;
467 if (!dev->has_remote)
472 /* detect & configure */
473 switch (dev->board) {
474 case SAA7134_BOARD_FLYVIDEO2000:
475 case SAA7134_BOARD_FLYVIDEO3000:
476 case SAA7134_BOARD_FLYTVPLATINUM_FM:
477 ir_codes = flyvideo_codes;
478 mask_keycode = 0xEC00000;
479 mask_keydown = 0x0040000;
481 case SAA7134_BOARD_CINERGY400:
482 case SAA7134_BOARD_CINERGY600:
483 case SAA7134_BOARD_CINERGY600_MK3:
484 ir_codes = cinergy_codes;
485 mask_keycode = 0x00003f;
486 mask_keyup = 0x040000;
488 case SAA7134_BOARD_ECS_TVP3XP:
489 case SAA7134_BOARD_ECS_TVP3XP_4CB5:
490 ir_codes = eztv_codes;
491 mask_keycode = 0x00017c;
492 mask_keyup = 0x000002;
495 case SAA7134_BOARD_KWORLD_XPERT:
496 case SAA7134_BOARD_AVACSSMARTTV:
497 ir_codes = avacssmart_codes;
498 mask_keycode = 0x00001F;
499 mask_keyup = 0x000020;
502 case SAA7134_BOARD_MD2819:
503 case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
504 case SAA7134_BOARD_AVERMEDIA_305:
505 case SAA7134_BOARD_AVERMEDIA_307:
506 case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
507 case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
508 case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
509 ir_codes = md2819_codes;
510 mask_keycode = 0x0007C8;
511 mask_keydown = 0x000010;
513 /* Set GPIO pin2 to high to enable the IR controller */
514 saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
515 saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
517 case SAA7134_BOARD_MANLI_MTV001:
518 case SAA7134_BOARD_MANLI_MTV002:
519 ir_codes = manli_codes;
520 mask_keycode = 0x001f00;
521 mask_keyup = 0x004000;
522 mask_keydown = 0x002000;
525 case SAA7134_BOARD_VIDEOMATE_TV_PVR:
526 case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
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 /* ----------------------------------------------------------------------