2005-04-16 15:20:36 -07:00
/*
*
* handle saa7134 IR remotes via linux kernel input layer .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/interrupt.h>
# include <linux/input.h>
# include "saa7134-reg.h"
# include "saa7134.h"
static unsigned int disable_ir = 0 ;
module_param ( disable_ir , int , 0444 ) ;
MODULE_PARM_DESC ( disable_ir , " disable infrared remote support " ) ;
static unsigned int ir_debug = 0 ;
module_param ( ir_debug , int , 0644 ) ;
MODULE_PARM_DESC ( ir_debug , " enable debug messages [IR] " ) ;
2006-03-25 23:14:42 -03:00
static int pinnacle_remote = 0 ;
module_param ( pinnacle_remote , int , 0644 ) ; /* Choose Pinnacle PCTV remote */
MODULE_PARM_DESC ( pinnacle_remote , " Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0) " ) ;
2006-12-07 21:45:28 -03:00
int ir_rc5_remote_gap = 885 ;
module_param ( ir_rc5_remote_gap , int , 0644 ) ;
int ir_rc5_key_timeout = 115 ;
module_param ( ir_rc5_key_timeout , int , 0644 ) ;
2005-04-16 15:20:36 -07:00
# define dprintk(fmt, arg...) if (ir_debug) \
printk ( KERN_DEBUG " %s/ir: " fmt , dev - > name , # # arg )
2005-11-08 21:37:56 -08:00
# define i2cdprintk(fmt, arg...) if (ir_debug) \
printk ( KERN_DEBUG " %s/ir: " fmt , ir - > c . name , # # arg )
2005-04-16 15:20:36 -07:00
2006-12-07 21:45:28 -03:00
/** rc5 functions */
static int saa7134_rc5_irq ( struct saa7134_dev * dev ) ;
2005-11-08 21:37:56 -08:00
/* -------------------- GPIO generic keycode builder -------------------- */
2005-04-16 15:20:36 -07:00
static int build_key ( struct saa7134_dev * dev )
{
2006-12-07 21:45:28 -03:00
struct card_ir * ir = dev - > remote ;
2005-04-16 15:20:36 -07:00
u32 gpio , data ;
/* rising SAA7134_GPIO_GPRESCAN reads the status */
saa_clearb ( SAA7134_GPIO_GPMODE3 , SAA7134_GPIO_GPRESCAN ) ;
saa_setb ( SAA7134_GPIO_GPMODE3 , SAA7134_GPIO_GPRESCAN ) ;
gpio = saa_readl ( SAA7134_GPIO_GPSTATUS0 > > 2 ) ;
2005-11-08 21:37:43 -08:00
if ( ir - > polling ) {
if ( ir - > last_gpio = = gpio )
return 0 ;
ir - > last_gpio = gpio ;
}
2005-04-16 15:20:36 -07:00
2005-11-08 21:37:43 -08:00
data = ir_extract_bits ( gpio , ir - > mask_keycode ) ;
2005-04-16 15:20:36 -07:00
dprintk ( " build_key gpio=0x%x mask=0x%x data=%d \n " ,
gpio , ir - > mask_keycode , data ) ;
2006-01-09 18:21:23 -02:00
if ( ir - > polling ) {
if ( ( ir - > mask_keydown & & ( 0 ! = ( gpio & ir - > mask_keydown ) ) ) | |
( ir - > mask_keyup & & ( 0 = = ( gpio & ir - > mask_keyup ) ) ) ) {
ir_input_keydown ( ir - > dev , & ir - > ir , data , data ) ;
} else {
ir_input_nokey ( ir - > dev , & ir - > ir ) ;
}
2005-04-16 15:20:36 -07:00
}
2006-01-09 18:21:23 -02:00
else { /* IRQ driven mode - handle key press and release in one go */
if ( ( ir - > mask_keydown & & ( 0 ! = ( gpio & ir - > mask_keydown ) ) ) | |
( ir - > mask_keyup & & ( 0 = = ( gpio & ir - > mask_keyup ) ) ) ) {
ir_input_keydown ( ir - > dev , & ir - > ir , data , data ) ;
ir_input_nokey ( ir - > dev , & ir - > ir ) ;
}
}
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-08 21:37:56 -08:00
/* --------------------- Chip specific I2C key builders ----------------- */
static int get_key_purpletv ( struct IR_i2c * ir , u32 * ir_key , u32 * ir_raw )
{
unsigned char b ;
/* poll IR chip */
if ( 1 ! = i2c_master_recv ( & ir - > c , & b , 1 ) ) {
i2cdprintk ( " read error \n " ) ;
return - EIO ;
}
/* no button press */
if ( b = = 0 )
return 0 ;
/* repeating */
if ( b & 0x80 )
return 1 ;
* ir_key = b ;
* ir_raw = b ;
return 1 ;
}
2006-11-29 21:57:24 -03:00
static int get_key_hvr1110 ( struct IR_i2c * ir , u32 * ir_key , u32 * ir_raw )
{
unsigned char buf [ 5 ] , cod4 , code3 , code4 ;
/* poll IR chip */
if ( 5 ! = i2c_master_recv ( & ir - > c , buf , 5 ) )
return - EIO ;
cod4 = buf [ 4 ] ;
code4 = ( cod4 > > 2 ) ;
code3 = buf [ 3 ] ;
if ( code3 = = 0 )
/* no key pressed */
return 0 ;
/* return key */
* ir_key = code4 ;
* ir_raw = code4 ;
return 1 ;
}
2005-04-16 15:20:36 -07:00
void saa7134_input_irq ( struct saa7134_dev * dev )
{
2006-12-07 21:45:28 -03:00
struct card_ir * ir = dev - > remote ;
2005-04-16 15:20:36 -07:00
2006-12-07 21:45:28 -03:00
if ( ! ir - > polling & & ! ir - > rc5_gpio ) {
2005-04-16 15:20:36 -07:00
build_key ( dev ) ;
2006-12-07 21:45:28 -03:00
} else if ( ir - > rc5_gpio ) {
saa7134_rc5_irq ( dev ) ;
}
2005-04-16 15:20:36 -07:00
}
static void saa7134_input_timer ( unsigned long data )
{
struct saa7134_dev * dev = ( struct saa7134_dev * ) data ;
2006-12-07 21:45:28 -03:00
struct card_ir * ir = dev - > remote ;
2005-04-16 15:20:36 -07:00
unsigned long timeout ;
build_key ( dev ) ;
timeout = jiffies + ( ir - > polling * HZ / 1000 ) ;
mod_timer ( & ir - > timer , timeout ) ;
}
2006-12-07 21:45:28 -03:00
static void saa7134_ir_start ( struct saa7134_dev * dev , struct card_ir * ir )
2006-11-20 10:23:04 -03:00
{
if ( ir - > polling ) {
init_timer ( & ir - > timer ) ;
ir - > timer . function = saa7134_input_timer ;
ir - > timer . data = ( unsigned long ) dev ;
ir - > timer . expires = jiffies + HZ ;
add_timer ( & ir - > timer ) ;
2006-12-07 21:45:28 -03:00
} else if ( ir - > rc5_gpio ) {
/* set timer_end for code completion */
init_timer ( & ir - > timer_end ) ;
ir - > timer_end . function = ir_rc5_timer_end ;
ir - > timer_end . data = ( unsigned long ) ir ;
init_timer ( & ir - > timer_keyup ) ;
ir - > timer_keyup . function = ir_rc5_timer_keyup ;
ir - > timer_keyup . data = ( unsigned long ) ir ;
ir - > shift_by = 2 ;
ir - > start = 0x2 ;
ir - > addr = 0x17 ;
ir - > rc5_key_timeout = ir_rc5_key_timeout ;
ir - > rc5_remote_gap = ir_rc5_remote_gap ;
2006-11-20 10:23:04 -03:00
}
}
static void saa7134_ir_stop ( struct saa7134_dev * dev )
{
if ( dev - > remote - > polling )
del_timer_sync ( & dev - > remote - > timer ) ;
}
2005-04-16 15:20:36 -07:00
int saa7134_input_init1 ( struct saa7134_dev * dev )
{
2006-12-07 21:45:28 -03:00
struct card_ir * ir ;
2005-09-15 02:01:53 -05:00
struct input_dev * input_dev ;
2005-04-16 15:20:36 -07:00
IR_KEYTAB_TYPE * ir_codes = NULL ;
u32 mask_keycode = 0 ;
u32 mask_keydown = 0 ;
u32 mask_keyup = 0 ;
int polling = 0 ;
2006-12-07 21:45:28 -03:00
int rc5_gpio = 0 ;
2005-04-16 15:20:36 -07:00
int ir_type = IR_TYPE_OTHER ;
2006-11-20 10:23:04 -03:00
int err ;
2005-04-16 15:20:36 -07:00
2005-11-08 21:38:47 -08:00
if ( dev - > has_remote ! = SAA7134_REMOTE_GPIO )
2005-04-16 15:20:36 -07:00
return - ENODEV ;
if ( disable_ir )
return - ENODEV ;
/* detect & configure */
switch ( dev - > board ) {
case SAA7134_BOARD_FLYVIDEO2000 :
case SAA7134_BOARD_FLYVIDEO3000 :
2005-11-08 21:37:43 -08:00
case SAA7134_BOARD_FLYTVPLATINUM_FM :
2005-11-08 21:36:55 -08:00
case SAA7134_BOARD_FLYTVPLATINUM_MINI2 :
2006-01-23 09:42:06 -02:00
ir_codes = ir_codes_flyvideo ;
2005-04-16 15:20:36 -07:00
mask_keycode = 0xEC00000 ;
mask_keydown = 0x0040000 ;
break ;
case SAA7134_BOARD_CINERGY400 :
case SAA7134_BOARD_CINERGY600 :
case SAA7134_BOARD_CINERGY600_MK3 :
2006-01-23 09:42:06 -02:00
ir_codes = ir_codes_cinergy ;
2005-04-16 15:20:36 -07:00
mask_keycode = 0x00003f ;
mask_keyup = 0x040000 ;
break ;
case SAA7134_BOARD_ECS_TVP3XP :
case SAA7134_BOARD_ECS_TVP3XP_4CB5 :
2006-01-23 09:42:06 -02:00
ir_codes = ir_codes_eztv ;
2005-07-12 13:59:01 -07:00
mask_keycode = 0x00017c ;
mask_keyup = 0x000002 ;
2005-04-16 15:20:36 -07:00
polling = 50 ; // ms
2005-07-12 13:59:01 -07:00
break ;
case SAA7134_BOARD_KWORLD_XPERT :
2005-04-16 15:20:36 -07:00
case SAA7134_BOARD_AVACSSMARTTV :
2006-01-23 09:44:10 -02:00
ir_codes = ir_codes_pixelview ;
2005-04-16 15:20:36 -07:00
mask_keycode = 0x00001F ;
mask_keyup = 0x000020 ;
polling = 50 ; // ms
break ;
case SAA7134_BOARD_MD2819 :
2005-06-23 22:05:09 -07:00
case SAA7134_BOARD_KWORLD_VSTREAM_XPERT :
2005-04-16 15:20:36 -07:00
case SAA7134_BOARD_AVERMEDIA_305 :
case SAA7134_BOARD_AVERMEDIA_307 :
2005-06-23 22:05:09 -07:00
case SAA7134_BOARD_AVERMEDIA_STUDIO_305 :
case SAA7134_BOARD_AVERMEDIA_STUDIO_307 :
2006-10-06 20:23:47 -03:00
case SAA7134_BOARD_AVERMEDIA_STUDIO_507 :
2005-06-23 22:05:09 -07:00
case SAA7134_BOARD_AVERMEDIA_GO_007_FM :
2006-01-23 09:44:10 -02:00
ir_codes = ir_codes_avermedia ;
2005-04-16 15:20:36 -07:00
mask_keycode = 0x0007C8 ;
mask_keydown = 0x000010 ;
polling = 50 ; // ms
/* Set GPIO pin2 to high to enable the IR controller */
saa_setb ( SAA7134_GPIO_GPMODE0 , 0x4 ) ;
saa_setb ( SAA7134_GPIO_GPSTATUS0 , 0x4 ) ;
break ;
2006-11-12 14:22:32 -03:00
case SAA7134_BOARD_AVERMEDIA_777 :
2006-11-12 14:23:32 -03:00
case SAA7134_BOARD_AVERMEDIA_A16AR :
2006-11-12 14:22:32 -03:00
ir_codes = ir_codes_avermedia ;
mask_keycode = 0x02F200 ;
mask_keydown = 0x000400 ;
polling = 50 ; // ms
/* Without this we won't receive key up events */
saa_setb ( SAA7134_GPIO_GPMODE1 , 0x1 ) ;
saa_setb ( SAA7134_GPIO_GPSTATUS1 , 0x1 ) ;
2006-11-13 09:50:11 -08:00
break ;
2005-11-08 21:37:43 -08:00
case SAA7134_BOARD_KWORLD_TERMINATOR :
2006-01-23 09:44:10 -02:00
ir_codes = ir_codes_pixelview ;
2005-11-08 21:37:00 -08:00
mask_keycode = 0x00001f ;
mask_keyup = 0x000060 ;
polling = 50 ; // ms
break ;
2005-06-23 22:05:09 -07:00
case SAA7134_BOARD_MANLI_MTV001 :
case SAA7134_BOARD_MANLI_MTV002 :
2005-11-08 21:36:16 -08:00
case SAA7134_BOARD_BEHOLD_409FM :
2006-01-23 09:42:06 -02:00
ir_codes = ir_codes_manli ;
2005-06-23 22:05:09 -07:00
mask_keycode = 0x001f00 ;
mask_keyup = 0x004000 ;
polling = 50 ; // ms
break ;
2005-11-08 21:38:47 -08:00
case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS :
2006-01-23 09:42:06 -02:00
ir_codes = ir_codes_pctv_sedna ;
2005-11-08 21:38:43 -08:00
mask_keycode = 0x001f00 ;
mask_keyup = 0x004000 ;
polling = 50 ; // ms
break ;
2005-11-08 21:37:43 -08:00
case SAA7134_BOARD_GOTVIEW_7135 :
2006-01-23 09:42:06 -02:00
ir_codes = ir_codes_gotview7135 ;
2005-11-08 21:36:22 -08:00
mask_keycode = 0x0003EC ;
mask_keyup = 0x008000 ;
mask_keydown = 0x000010 ;
polling = 50 ; // ms
break ;
2005-04-16 15:20:36 -07:00
case SAA7134_BOARD_VIDEOMATE_TV_PVR :
2006-01-09 15:25:33 -02:00
case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS :
2005-07-12 13:59:01 -07:00
case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII :
2006-01-23 09:42:06 -02:00
ir_codes = ir_codes_videomate_tv_pvr ;
2005-04-16 15:20:36 -07:00
mask_keycode = 0x00003F ;
mask_keyup = 0x400000 ;
polling = 50 ; // ms
break ;
2006-09-13 16:42:42 -03:00
case SAA7134_BOARD_PROTEUS_2309 :
ir_codes = ir_codes_proteus_2309 ;
mask_keycode = 0x00007F ;
mask_keyup = 0x000080 ;
polling = 50 ; // ms
break ;
2005-11-08 21:37:43 -08:00
case SAA7134_BOARD_VIDEOMATE_DVBT_300 :
case SAA7134_BOARD_VIDEOMATE_DVBT_200 :
2006-01-23 09:42:06 -02:00
ir_codes = ir_codes_videomate_tv_pvr ;
2005-11-08 21:36:47 -08:00
mask_keycode = 0x003F00 ;
mask_keyup = 0x040000 ;
break ;
2006-02-07 06:49:09 -02:00
case SAA7134_BOARD_FLYDVBT_LR301 :
2006-02-27 00:08:46 -03:00
case SAA7134_BOARD_FLYDVBTDUO :
2006-02-07 06:49:09 -02:00
ir_codes = ir_codes_flydvb ;
mask_keycode = 0x0001F00 ;
mask_keydown = 0x0040000 ;
break ;
2006-12-07 21:45:28 -03:00
case SAA7134_BOARD_ASUSTeK_P7131_DUAL :
ir_codes = ir_codes_asus_pc39 ;
mask_keydown = 0x0040000 ;
rc5_gpio = 1 ;
break ;
2006-12-27 12:46:36 -03:00
case SAA7134_BOARD_ENCORE_ENLTV :
case SAA7134_BOARD_ENCORE_ENLTV_FM :
ir_codes = ir_codes_encore_enltv ;
mask_keycode = 0x00007f ;
mask_keyup = 0x040000 ;
polling = 50 ; // ms
break ;
2005-04-16 15:20:36 -07:00
}
if ( NULL = = ir_codes ) {
printk ( " %s: Oops: IR config error [card=%d] \n " ,
dev - > name , dev - > board ) ;
return - ENODEV ;
}
2005-09-15 02:01:53 -05:00
ir = kzalloc ( sizeof ( * ir ) , GFP_KERNEL ) ;
input_dev = input_allocate_device ( ) ;
if ( ! ir | | ! input_dev ) {
2006-11-20 10:23:04 -03:00
err = - ENOMEM ;
goto err_out_free ;
2005-09-15 02:01:53 -05:00
}
2005-04-16 15:20:36 -07:00
2005-11-20 00:56:54 -05:00
ir - > dev = input_dev ;
2005-04-16 15:20:36 -07:00
/* init hardware-specific stuff */
ir - > mask_keycode = mask_keycode ;
ir - > mask_keydown = mask_keydown ;
ir - > mask_keyup = mask_keyup ;
2005-11-08 21:37:43 -08:00
ir - > polling = polling ;
2006-12-07 21:45:28 -03:00
ir - > rc5_gpio = rc5_gpio ;
2005-04-16 15:20:36 -07:00
/* init input device */
snprintf ( ir - > name , sizeof ( ir - > name ) , " saa7134 IR (%s) " ,
saa7134_boards [ dev - > board ] . name ) ;
snprintf ( ir - > phys , sizeof ( ir - > phys ) , " pci-%s/ir0 " ,
pci_name ( dev - > pci ) ) ;
2005-09-15 02:01:53 -05:00
ir_input_init ( input_dev , & ir - > ir , ir_type , ir_codes ) ;
input_dev - > name = ir - > name ;
input_dev - > phys = ir - > phys ;
input_dev - > id . bustype = BUS_PCI ;
input_dev - > id . version = 1 ;
2005-04-16 15:20:36 -07:00
if ( dev - > pci - > subsystem_vendor ) {
2005-09-15 02:01:53 -05:00
input_dev - > id . vendor = dev - > pci - > subsystem_vendor ;
input_dev - > id . product = dev - > pci - > subsystem_device ;
2005-04-16 15:20:36 -07:00
} else {
2005-09-15 02:01:53 -05:00
input_dev - > id . vendor = dev - > pci - > vendor ;
input_dev - > id . product = dev - > pci - > device ;
2005-04-16 15:20:36 -07:00
}
2005-09-15 02:01:53 -05:00
input_dev - > cdev . dev = & dev - > pci - > dev ;
2005-04-16 15:20:36 -07:00
dev - > remote = ir ;
2006-11-20 10:23:04 -03:00
saa7134_ir_start ( dev , ir ) ;
err = input_register_device ( ir - > dev ) ;
if ( err )
goto err_out_stop ;
2005-04-16 15:20:36 -07:00
return 0 ;
2006-11-20 10:23:04 -03:00
err_out_stop :
saa7134_ir_stop ( dev ) ;
dev - > remote = NULL ;
err_out_free :
input_free_device ( input_dev ) ;
kfree ( ir ) ;
return err ;
2005-04-16 15:20:36 -07:00
}
void saa7134_input_fini ( struct saa7134_dev * dev )
{
if ( NULL = = dev - > remote )
return ;
2006-11-20 10:23:04 -03:00
saa7134_ir_stop ( dev ) ;
2005-09-15 02:01:53 -05:00
input_unregister_device ( dev - > remote - > dev ) ;
2005-04-16 15:20:36 -07:00
kfree ( dev - > remote ) ;
dev - > remote = NULL ;
}
2005-11-08 21:37:56 -08:00
void saa7134_set_i2c_ir ( struct saa7134_dev * dev , struct IR_i2c * ir )
{
if ( disable_ir ) {
2005-11-08 21:38:47 -08:00
dprintk ( " Found supported i2c remote, but IR has been disabled \n " ) ;
2005-11-08 21:37:56 -08:00
ir - > get_key = NULL ;
return ;
}
switch ( dev - > board ) {
case SAA7134_BOARD_PINNACLE_PCTV_110i :
2006-10-12 19:46:16 -03:00
case SAA7134_BOARD_PINNACLE_PCTV_310i :
2005-11-08 21:37:56 -08:00
snprintf ( ir - > c . name , sizeof ( ir - > c . name ) , " Pinnacle PCTV " ) ;
2006-03-25 23:14:42 -03:00
if ( pinnacle_remote = = 0 ) {
ir - > get_key = get_key_pinnacle_color ;
ir - > ir_codes = ir_codes_pinnacle_color ;
} else {
ir - > get_key = get_key_pinnacle_grey ;
ir - > ir_codes = ir_codes_pinnacle_grey ;
}
2005-11-08 21:37:56 -08:00
break ;
case SAA7134_BOARD_UPMOST_PURPLE_TV :
snprintf ( ir - > c . name , sizeof ( ir - > c . name ) , " Purple TV " ) ;
ir - > get_key = get_key_purpletv ;
ir - > ir_codes = ir_codes_purpletv ;
break ;
2006-11-29 21:57:24 -03:00
case SAA7134_BOARD_HAUPPAUGE_HVR1110 :
snprintf ( ir - > c . name , sizeof ( ir - > c . name ) , " HVR 1110 " ) ;
ir - > get_key = get_key_hvr1110 ;
ir - > ir_codes = ir_codes_hauppauge_new ;
break ;
2005-11-08 21:37:56 -08:00
default :
dprintk ( " Shouldn't get here: Unknown board %x for I2C IR? \n " , dev - > board ) ;
break ;
}
}
2006-12-07 21:45:28 -03:00
static int saa7134_rc5_irq ( struct saa7134_dev * dev )
{
struct card_ir * ir = dev - > remote ;
struct timeval tv ;
u32 gap ;
unsigned long current_jiffies , timeout ;
/* get time of bit */
current_jiffies = jiffies ;
do_gettimeofday ( & tv ) ;
/* avoid overflow with gap >1s */
if ( tv . tv_sec - ir - > base_time . tv_sec > 1 ) {
gap = 200000 ;
} else {
gap = 1000000 * ( tv . tv_sec - ir - > base_time . tv_sec ) +
tv . tv_usec - ir - > base_time . tv_usec ;
}
/* active code => add bit */
if ( ir - > active ) {
/* only if in the code (otherwise spurious IRQ or timer
late ) */
if ( ir - > last_bit < 28 ) {
ir - > last_bit = ( gap - ir_rc5_remote_gap / 2 ) /
ir_rc5_remote_gap ;
ir - > code | = 1 < < ir - > last_bit ;
}
/* starting new code */
} else {
ir - > active = 1 ;
ir - > code = 0 ;
ir - > base_time = tv ;
ir - > last_bit = 0 ;
timeout = current_jiffies + ( 500 + 30 * HZ ) / 1000 ;
mod_timer ( & ir - > timer_end , timeout ) ;
}
return 1 ;
}
2005-04-16 15:20:36 -07:00
/* ----------------------------------------------------------------------
* Local variables :
* c - basic - offset : 8
* End :
*/