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/sched.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] " ) ;
# 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
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 )
{
struct saa7134_ir * ir = dev - > remote ;
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 ;
}
2005-04-16 15:20:36 -07:00
void saa7134_input_irq ( struct saa7134_dev * dev )
{
2005-11-08 21:37:43 -08:00
struct saa7134_ir * ir = dev - > remote ;
2005-04-16 15:20:36 -07:00
2005-11-08 21:37:43 -08:00
if ( ! ir - > polling )
2005-04-16 15:20:36 -07:00
build_key ( dev ) ;
}
static void saa7134_input_timer ( unsigned long data )
{
struct saa7134_dev * dev = ( struct saa7134_dev * ) data ;
struct saa7134_ir * ir = dev - > remote ;
unsigned long timeout ;
build_key ( dev ) ;
timeout = jiffies + ( ir - > polling * HZ / 1000 ) ;
mod_timer ( & ir - > timer , timeout ) ;
}
int saa7134_input_init1 ( struct saa7134_dev * dev )
{
struct saa7134_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 ;
int ir_type = IR_TYPE_OTHER ;
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:42:06 -02:00
ir_codes = ir_codes_avacssmart ;
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 :
case SAA7134_BOARD_AVERMEDIA_GO_007_FM :
2006-01-23 09:42:06 -02:00
ir_codes = ir_codes_md2819 ;
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 ;
2005-11-08 21:37:43 -08:00
case SAA7134_BOARD_KWORLD_TERMINATOR :
2006-01-23 09:42:06 -02:00
ir_codes = ir_codes_avacssmart ;
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 ;
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 ;
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 ) {
kfree ( ir ) ;
input_free_device ( input_dev ) ;
2005-04-16 15:20:36 -07:00
return - ENOMEM ;
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 ;
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
/* all done */
dev - > remote = ir ;
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 ) ;
}
2005-09-15 02:01:53 -05:00
input_register_device ( ir - > dev ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
void saa7134_input_fini ( struct saa7134_dev * dev )
{
if ( NULL = = dev - > remote )
return ;
if ( dev - > remote - > polling )
del_timer_sync ( & dev - > remote - > timer ) ;
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 :
snprintf ( ir - > c . name , sizeof ( ir - > c . name ) , " Pinnacle PCTV " ) ;
ir - > get_key = get_key_pinnacle ;
ir - > ir_codes = ir_codes_pinnacle ;
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 ;
default :
dprintk ( " Shouldn't get here: Unknown board %x for I2C IR? \n " , dev - > board ) ;
break ;
}
}
2005-04-16 15:20:36 -07:00
/* ----------------------------------------------------------------------
* Local variables :
* c - basic - offset : 8
* End :
*/