3 * handle saa7134 IR remotes via linux kernel input layer.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <linux/module.h>
22 #include <linux/moduleparam.h>
23 #include <linux/init.h>
24 #include <linux/delay.h>
25 #include <linux/sched.h>
26 #include <linux/interrupt.h>
27 #include <linux/input.h>
29 #include "saa7134-reg.h"
32 static unsigned int disable_ir
= 0;
33 module_param(disable_ir
, int, 0444);
34 MODULE_PARM_DESC(disable_ir
,"disable infrared remote support");
36 static unsigned int ir_debug
= 0;
37 module_param(ir_debug
, int, 0644);
38 MODULE_PARM_DESC(ir_debug
,"enable debug messages [IR]");
40 #define dprintk(fmt, arg...) if (ir_debug) \
41 printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
43 /* ---------------------------------------------------------------------- */
45 static IR_KEYTAB_TYPE flyvideo_codes
[IR_KEYTAB_SIZE
] = {
57 [ 14 ] = KEY_TUNER
, // Air/Cable
58 [ 17 ] = KEY_VIDEO
, // Video
59 [ 21 ] = KEY_AUDIO
, // Audio
60 [ 0 ] = KEY_POWER
, // Pover
61 [ 2 ] = KEY_ZOOM
, // Fullscreen
62 [ 27 ] = KEY_MUTE
, // Mute
63 [ 20 ] = KEY_VOLUMEUP
,
64 [ 23 ] = KEY_VOLUMEDOWN
,
65 [ 18 ] = KEY_CHANNELUP
, // Channel +
66 [ 19 ] = KEY_CHANNELDOWN
, // Channel -
67 [ 6 ] = KEY_AGAIN
, // Recal
68 [ 16 ] = KEY_KPENTER
, // Enter
70 [ 26 ] = KEY_F22
, // Stereo
71 [ 24 ] = KEY_EDIT
, // AV Source
74 static IR_KEYTAB_TYPE cinergy_codes
[IR_KEYTAB_SIZE
] = {
87 [ 0x0b ] = KEY_PROG1
, // app
88 [ 0x0c ] = KEY_ZOOM
, // zoom/fullscreen
89 [ 0x0d ] = KEY_CHANNELUP
, // channel
90 [ 0x0e ] = KEY_CHANNELDOWN
, // channel-
91 [ 0x0f ] = KEY_VOLUMEUP
,
92 [ 0x10 ] = KEY_VOLUMEDOWN
,
93 [ 0x11 ] = KEY_TUNER
, // AV
94 [ 0x12 ] = KEY_NUMLOCK
, // -/--
95 [ 0x13 ] = KEY_AUDIO
, // audio
100 [ 0x18 ] = KEY_RIGHT
,
102 [ 0x1a ] = BTN_RIGHT
,
103 [ 0x1b ] = KEY_WWW
, // text
104 [ 0x1c ] = KEY_REWIND
,
105 [ 0x1d ] = KEY_FORWARD
,
106 [ 0x1e ] = KEY_RECORD
,
108 [ 0x20 ] = KEY_PREVIOUSSONG
,
109 [ 0x21 ] = KEY_NEXTSONG
,
110 [ 0x22 ] = KEY_PAUSE
,
114 /* Alfons Geser <a.geser@cox.net>
115 * updates from Job D. R. Borges <jobdrb@ig.com.br> */
116 static IR_KEYTAB_TYPE eztv_codes
[IR_KEYTAB_SIZE
] = {
118 [ 1 ] = KEY_TV
, // DVR
119 [ 21 ] = KEY_DVD
, // DVD
120 [ 23 ] = KEY_AUDIO
, // music
121 // DVR mode / DVD mode / music mode
123 [ 27 ] = KEY_MUTE
, // mute
124 [ 2 ] = KEY_LANGUAGE
, // MTS/SAP / audio / autoseek
125 [ 30 ] = KEY_SUBTITLE
, // closed captioning / subtitle / seek
126 [ 22 ] = KEY_ZOOM
, // full screen
127 [ 28 ] = KEY_VIDEO
, // video source / eject / delall
128 [ 29 ] = KEY_RESTART
, // playback / angle / del
129 [ 47 ] = KEY_SEARCH
, // scan / menu / playlist
130 [ 48 ] = KEY_CHANNEL
, // CH surfing / bookmark / memo
132 [ 49 ] = KEY_HELP
, // help
133 [ 50 ] = KEY_MODE
, // num/memo
134 [ 51 ] = KEY_ESC
, // cancel
136 [ 12 ] = KEY_UP
, // up
137 [ 16 ] = KEY_DOWN
, // down
138 [ 8 ] = KEY_LEFT
, // left
139 [ 4 ] = KEY_RIGHT
, // right
140 [ 3 ] = KEY_SELECT
, // select
142 [ 31 ] = KEY_REWIND
, // rewind
143 [ 32 ] = KEY_PLAYPAUSE
, // play/pause
144 [ 41 ] = KEY_FORWARD
, // forward
145 [ 20 ] = KEY_AGAIN
, // repeat
146 [ 43 ] = KEY_RECORD
, // recording
147 [ 44 ] = KEY_STOP
, // stop
148 [ 45 ] = KEY_PLAY
, // play
149 [ 46 ] = KEY_SHUFFLE
, // snapshot / shuffle
162 [ 42 ] = KEY_VOLUMEUP
,
163 [ 17 ] = KEY_VOLUMEDOWN
,
164 [ 24 ] = KEY_CHANNELUP
, // CH.tracking up
165 [ 25 ] = KEY_CHANNELDOWN
, // CH.tracking down
167 [ 19 ] = KEY_KPENTER
, // enter
168 [ 33 ] = KEY_KPDOT
, // . (decimal dot)
171 static IR_KEYTAB_TYPE avacssmart_codes
[IR_KEYTAB_SIZE
] = {
172 [ 30 ] = KEY_POWER
, // power
173 [ 28 ] = KEY_SEARCH
, // scan
174 [ 7 ] = KEY_SELECT
, // source
176 [ 22 ] = KEY_VOLUMEUP
,
177 [ 20 ] = KEY_VOLUMEDOWN
,
178 [ 31 ] = KEY_CHANNELUP
,
179 [ 23 ] = KEY_CHANNELDOWN
,
194 [ 3 ] = KEY_TUNER
, // tv/fm
195 [ 4 ] = KEY_REWIND
, // fm tuning left or function left
196 [ 12 ] = KEY_FORWARD
, // fm tuning right or function right
203 [ 14 ] = KEY_MENU
, // function
204 [ 19 ] = KEY_AGAIN
, // recall
205 [ 29 ] = KEY_RESTART
, // reset
206 [ 26 ] = KEY_SHUFFLE
, // snapshot/shuffle
209 [ 13 ] = KEY_F21
, // mts
210 [ 15 ] = KEY_F22
, // min
213 /* Alex Hermann <gaaf@gmx.net> */
214 static IR_KEYTAB_TYPE md2819_codes
[IR_KEYTAB_SIZE
] = {
226 [ 32 ] = KEY_TV
, // TV/FM
227 [ 16 ] = KEY_CD
, // CD
228 [ 48 ] = KEY_TEXT
, // TELETEXT
229 [ 0 ] = KEY_POWER
, // POWER
231 [ 8 ] = KEY_VIDEO
, // VIDEO
232 [ 4 ] = KEY_AUDIO
, // AUDIO
233 [ 12 ] = KEY_ZOOM
, // FULL SCREEN
235 [ 18 ] = KEY_SUBTITLE
, // DISPLAY - ???
236 [ 50 ] = KEY_REWIND
, // LOOP - ???
237 [ 2 ] = KEY_PRINT
, // PREVIEW - ???
239 [ 42 ] = KEY_SEARCH
, // AUTOSCAN
240 [ 26 ] = KEY_SLEEP
, // FREEZE - ???
241 [ 58 ] = KEY_SHUFFLE
, // SNAPSHOT - ???
242 [ 10 ] = KEY_MUTE
, // MUTE
244 [ 38 ] = KEY_RECORD
, // RECORD
245 [ 22 ] = KEY_PAUSE
, // PAUSE
246 [ 54 ] = KEY_STOP
, // STOP
247 [ 6 ] = KEY_PLAY
, // PLAY
249 [ 46 ] = KEY_RED
, // <RED>
250 [ 33 ] = KEY_GREEN
, // <GREEN>
251 [ 14 ] = KEY_YELLOW
, // <YELLOW>
252 [ 1 ] = KEY_BLUE
, // <BLUE>
254 [ 30 ] = KEY_VOLUMEDOWN
, // VOLUME-
255 [ 62 ] = KEY_VOLUMEUP
, // VOLUME+
256 [ 17 ] = KEY_CHANNELDOWN
, // CHANNEL/PAGE-
257 [ 49 ] = KEY_CHANNELUP
// CHANNEL/PAGE+
260 static IR_KEYTAB_TYPE videomate_tv_pvr_codes
[IR_KEYTAB_SIZE
] = {
269 [ 8 ] = KEY_PLAYPAUSE
,
270 [ 15 ] = KEY_FORWARD
,
272 [ 2 ] = KEY_PREVIOUS
,
285 [ 34 ] = KEY_CHANNEL
,
287 [ 18 ] = KEY_VOLUMEUP
,
288 [ 21 ] = KEY_VOLUMEDOWN
,
289 [ 16 ] = KEY_CHANNELUP
,
290 [ 19 ] = KEY_CHANNELDOWN
,
305 [ 32 ] = KEY_LANGUAGE
,
309 /* Michael Tokarev <mjt@tls.msk.ru>
310 http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
311 keytable is used by MANLI MTV00[12] and BeholdTV 40[13] at
312 least, and probably other cards too.
313 The "ascii-art picture" below (in comments, first row
314 is the keycode in hex, and subsequent row(s) shows
315 the button labels (several variants when appropriate)
316 helps to descide which keycodes to assign to the buttons.
318 static IR_KEYTAB_TYPE manli_codes
[IR_KEYTAB_SIZE
] = {
324 [ 0x1c ] = KEY_RADIO
, /*XXX*/
325 [ 0x12 ] = KEY_POWER
,
350 [ 0x0a ] = KEY_AGAIN
, /*XXX KEY_REWIND? */
352 [ 0x17 ] = KEY_DIGITS
, /*XXX*/
369 [ 0x0b ] = KEY_UP
, /*XXX KEY_SCROLLUP? */
370 [ 0x18 ] = KEY_LEFT
, /*XXX KEY_BACK? */
371 [ 0x16 ] = KEY_OK
, /*XXX KEY_SELECT? KEY_ENTER? */
372 [ 0x0c ] = KEY_RIGHT
, /*XXX KEY_FORWARD? */
373 [ 0x15 ] = KEY_DOWN
, /*XXX KEY_SCROLLDOWN? */
379 [ 0x11 ] = KEY_TV
, /*XXX*/
380 [ 0x0d ] = KEY_MODE
, /*XXX there's no KEY_STEREO */
389 [ 0x0f ] = KEY_AUDIO
,
390 [ 0x1b ] = KEY_VOLUMEUP
,
391 [ 0x1a ] = KEY_CHANNELUP
,
392 [ 0x0e ] = KEY_SLEEP
, /*XXX maybe KEY_PAUSE */
393 [ 0x1f ] = KEY_VOLUMEDOWN
,
394 [ 0x1e ] = KEY_CHANNELDOWN
,
400 [ 0x19 ] = KEY_RECORD
, /*XXX*/
406 /* Mike Baikov <mike@baikov.com> */
407 static IR_KEYTAB_TYPE gotview7135_codes
[IR_KEYTAB_SIZE
] = {
421 [ 115] = KEY_AGAIN
, /* LOOP */
423 [ 97 ] = KEY_PRINT
, /* PREVIEW */
425 [ 32 ] = KEY_CHANNELUP
,
426 [ 64 ] = KEY_CHANNELDOWN
,
427 [ 24 ] = KEY_VOLUMEDOWN
,
428 [ 80 ] = KEY_VOLUMEUP
,
431 [ 123] = KEY_SHUFFLE
, /* SNAPSHOT */
437 [ 25 ] = KEY_FORWARD
,
440 [ 82 ] = KEY_F21
, /* LIVE TIMESHIFT */
441 [ 26 ] = KEY_F22
, /* MIN TIMESHIFT */
442 [ 58 ] = KEY_F23
, /* TIMESHIFT */
443 [ 112] = KEY_F24
, /* NORMAL TIMESHIFT */
446 /* ---------------------------------------------------------------------- */
448 static int build_key(struct saa7134_dev
*dev
)
450 struct saa7134_ir
*ir
= dev
->remote
;
453 /* rising SAA7134_GPIO_GPRESCAN reads the status */
454 saa_clearb(SAA7134_GPIO_GPMODE3
,SAA7134_GPIO_GPRESCAN
);
455 saa_setb(SAA7134_GPIO_GPMODE3
,SAA7134_GPIO_GPRESCAN
);
457 gpio
= saa_readl(SAA7134_GPIO_GPSTATUS0
>> 2);
459 if (ir
->last_gpio
== gpio
)
461 ir
->last_gpio
= gpio
;
464 data
= ir_extract_bits(gpio
, ir
->mask_keycode
);
465 dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
466 gpio
, ir
->mask_keycode
, data
);
468 if ((ir
->mask_keydown
&& (0 != (gpio
& ir
->mask_keydown
))) ||
469 (ir
->mask_keyup
&& (0 == (gpio
& ir
->mask_keyup
)))) {
470 ir_input_keydown(ir
->dev
, &ir
->ir
, data
, data
);
472 ir_input_nokey(ir
->dev
, &ir
->ir
);
477 /* ---------------------------------------------------------------------- */
479 void saa7134_input_irq(struct saa7134_dev
*dev
)
481 struct saa7134_ir
*ir
= dev
->remote
;
487 static void saa7134_input_timer(unsigned long data
)
489 struct saa7134_dev
*dev
= (struct saa7134_dev
*)data
;
490 struct saa7134_ir
*ir
= dev
->remote
;
491 unsigned long timeout
;
494 timeout
= jiffies
+ (ir
->polling
* HZ
/ 1000);
495 mod_timer(&ir
->timer
, timeout
);
498 int saa7134_input_init1(struct saa7134_dev
*dev
)
500 struct saa7134_ir
*ir
;
501 struct input_dev
*input_dev
;
502 IR_KEYTAB_TYPE
*ir_codes
= NULL
;
503 u32 mask_keycode
= 0;
504 u32 mask_keydown
= 0;
507 int ir_type
= IR_TYPE_OTHER
;
509 if (!dev
->has_remote
)
514 /* detect & configure */
515 switch (dev
->board
) {
516 case SAA7134_BOARD_FLYVIDEO2000
:
517 case SAA7134_BOARD_FLYVIDEO3000
:
518 case SAA7134_BOARD_FLYTVPLATINUM_FM
:
519 case SAA7134_BOARD_FLYTVPLATINUM_MINI2
:
520 ir_codes
= flyvideo_codes
;
521 mask_keycode
= 0xEC00000;
522 mask_keydown
= 0x0040000;
524 case SAA7134_BOARD_CINERGY400
:
525 case SAA7134_BOARD_CINERGY600
:
526 case SAA7134_BOARD_CINERGY600_MK3
:
527 ir_codes
= cinergy_codes
;
528 mask_keycode
= 0x00003f;
529 mask_keyup
= 0x040000;
531 case SAA7134_BOARD_ECS_TVP3XP
:
532 case SAA7134_BOARD_ECS_TVP3XP_4CB5
:
533 ir_codes
= eztv_codes
;
534 mask_keycode
= 0x00017c;
535 mask_keyup
= 0x000002;
538 case SAA7134_BOARD_KWORLD_XPERT
:
539 case SAA7134_BOARD_AVACSSMARTTV
:
540 ir_codes
= avacssmart_codes
;
541 mask_keycode
= 0x00001F;
542 mask_keyup
= 0x000020;
545 case SAA7134_BOARD_MD2819
:
546 case SAA7134_BOARD_KWORLD_VSTREAM_XPERT
:
547 case SAA7134_BOARD_AVERMEDIA_305
:
548 case SAA7134_BOARD_AVERMEDIA_307
:
549 case SAA7134_BOARD_AVERMEDIA_STUDIO_305
:
550 case SAA7134_BOARD_AVERMEDIA_STUDIO_307
:
551 case SAA7134_BOARD_AVERMEDIA_GO_007_FM
:
552 ir_codes
= md2819_codes
;
553 mask_keycode
= 0x0007C8;
554 mask_keydown
= 0x000010;
556 /* Set GPIO pin2 to high to enable the IR controller */
557 saa_setb(SAA7134_GPIO_GPMODE0
, 0x4);
558 saa_setb(SAA7134_GPIO_GPSTATUS0
, 0x4);
560 case SAA7134_BOARD_KWORLD_TERMINATOR
:
561 ir_codes
= avacssmart_codes
;
562 mask_keycode
= 0x00001f;
563 mask_keyup
= 0x000060;
566 case SAA7134_BOARD_MANLI_MTV001
:
567 case SAA7134_BOARD_MANLI_MTV002
:
568 case SAA7134_BOARD_BEHOLD_409FM
:
569 ir_codes
= manli_codes
;
570 mask_keycode
= 0x001f00;
571 mask_keyup
= 0x004000;
574 case SAA7134_BOARD_GOTVIEW_7135
:
575 ir_codes
= gotview7135_codes
;
576 mask_keycode
= 0x0003EC;
577 mask_keyup
= 0x008000;
578 mask_keydown
= 0x000010;
581 case SAA7134_BOARD_VIDEOMATE_TV_PVR
:
582 case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII
:
583 ir_codes
= videomate_tv_pvr_codes
;
584 mask_keycode
= 0x00003F;
585 mask_keyup
= 0x400000;
588 case SAA7134_BOARD_VIDEOMATE_DVBT_300
:
589 case SAA7134_BOARD_VIDEOMATE_DVBT_200
:
590 ir_codes
= videomate_tv_pvr_codes
;
591 mask_keycode
= 0x003F00;
592 mask_keyup
= 0x040000;
595 if (NULL
== ir_codes
) {
596 printk("%s: Oops: IR config error [card=%d]\n",
597 dev
->name
, dev
->board
);
601 ir
= kzalloc(sizeof(*ir
), GFP_KERNEL
);
602 input_dev
= input_allocate_device();
603 if (!ir
|| !input_dev
) {
605 input_free_device(input_dev
);
609 /* init hardware-specific stuff */
610 ir
->mask_keycode
= mask_keycode
;
611 ir
->mask_keydown
= mask_keydown
;
612 ir
->mask_keyup
= mask_keyup
;
613 ir
->polling
= polling
;
615 /* init input device */
616 snprintf(ir
->name
, sizeof(ir
->name
), "saa7134 IR (%s)",
617 saa7134_boards
[dev
->board
].name
);
618 snprintf(ir
->phys
, sizeof(ir
->phys
), "pci-%s/ir0",
621 ir_input_init(input_dev
, &ir
->ir
, ir_type
, ir_codes
);
622 input_dev
->name
= ir
->name
;
623 input_dev
->phys
= ir
->phys
;
624 input_dev
->id
.bustype
= BUS_PCI
;
625 input_dev
->id
.version
= 1;
626 if (dev
->pci
->subsystem_vendor
) {
627 input_dev
->id
.vendor
= dev
->pci
->subsystem_vendor
;
628 input_dev
->id
.product
= dev
->pci
->subsystem_device
;
630 input_dev
->id
.vendor
= dev
->pci
->vendor
;
631 input_dev
->id
.product
= dev
->pci
->device
;
633 input_dev
->cdev
.dev
= &dev
->pci
->dev
;
638 init_timer(&ir
->timer
);
639 ir
->timer
.function
= saa7134_input_timer
;
640 ir
->timer
.data
= (unsigned long)dev
;
641 ir
->timer
.expires
= jiffies
+ HZ
;
642 add_timer(&ir
->timer
);
645 input_register_device(ir
->dev
);
649 void saa7134_input_fini(struct saa7134_dev
*dev
)
651 if (NULL
== dev
->remote
)
654 if (dev
->remote
->polling
)
655 del_timer_sync(&dev
->remote
->timer
);
656 input_unregister_device(dev
->remote
->dev
);
661 /* ----------------------------------------------------------------------