2005-04-17 02:20:36 +04:00
/*
*
* keyboard input driver for i2c IR remote controls
*
* Copyright ( c ) 2000 - 2003 Gerd Knorr < kraxel @ bytesex . org >
* modified for PixelView ( BT878P + W / FM ) by
* Michal Kochanowicz < mkochano @ pld . org . pl >
* Christoph Bartelmus < lirc @ bartelmus . de >
* modified for KNC ONE TV Station / Anubis Typhoon TView Tuner by
* Ulrich Mueller < ulrich . mueller42 @ web . de >
2005-11-09 08:37:21 +03:00
* modified for em2820 based USB TV tuners by
* Markus Rechberger < mrechberger @ gmail . com >
2007-08-24 08:02:32 +04:00
* modified for DViCO Fusion HDTV 5 RT GOLD by
* Chaogui Zhang < czhang1974 @ gmail . com >
2008-10-13 15:37:06 +04:00
* modified for MSI TV @ nywhere Plus by
* Henry Wong < henry @ stuffedcow . net >
* Mark Schultz < n9xmj @ yahoo . com >
* Brian Rogers < brian_rogers @ comcast . net >
2009-02-12 09:43:11 +03:00
* modified for AVerMedia Cardbus by
* Oldrich Jedlicka < oldium . pro @ seznam . cz >
2005-04-17 02:20:36 +04:00
*
* 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/init.h>
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/timer.h>
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <linux/i2c.h>
# include <linux/workqueue.h>
2005-12-12 11:37:28 +03:00
2010-11-17 19:28:38 +03:00
# include <media/rc-core.h>
2005-11-09 08:37:32 +03:00
# include <media/ir-kbd-i2c.h>
2005-11-09 08:37:21 +03:00
2005-04-17 02:20:36 +04:00
/* ----------------------------------------------------------------------- */
/* insmod parameters */
static int debug ;
module_param ( debug , int , 0644 ) ; /* debug level (0,1,2) */
2008-04-22 21:41:48 +04:00
static int hauppauge ;
2006-01-23 14:34:06 +03:00
module_param ( hauppauge , int , 0644 ) ; /* Choose Hauppauge remote */
MODULE_PARM_DESC ( hauppauge , " Specify Hauppauge remote: 0=black, 1=grey (defaults to 0) " ) ;
2010-03-13 03:18:14 +03:00
# define MODULE_NAME "ir-kbd-i2c"
2005-04-17 02:20:36 +04:00
# define dprintk(level, fmt, arg...) if (debug >= level) \
2010-03-13 03:18:14 +03:00
printk ( KERN_DEBUG MODULE_NAME " : " fmt , # # arg )
2005-04-17 02:20:36 +04:00
/* ----------------------------------------------------------------------- */
2007-06-25 21:34:06 +04:00
static int get_key_haup_common ( struct IR_i2c * ir , u32 * ir_key , u32 * ir_raw ,
int size , int offset )
2005-04-17 02:20:36 +04:00
{
2007-06-25 21:34:06 +04:00
unsigned char buf [ 6 ] ;
2008-09-22 07:54:59 +04:00
int start , range , toggle , dev , code , ircode ;
2005-04-17 02:20:36 +04:00
/* poll IR chip */
2009-05-13 23:48:50 +04:00
if ( size ! = i2c_master_recv ( ir - > c , buf , size ) )
2005-04-17 02:20:36 +04:00
return - EIO ;
/* split rc5 data block ... */
2007-06-25 21:34:06 +04:00
start = ( buf [ offset ] > > 7 ) & 1 ;
range = ( buf [ offset ] > > 6 ) & 1 ;
toggle = ( buf [ offset ] > > 5 ) & 1 ;
dev = buf [ offset ] & 0x1f ;
code = ( buf [ offset + 1 ] > > 2 ) & 0x3f ;
2005-04-17 02:20:36 +04:00
2006-09-26 23:39:00 +04:00
/* rc5 has two start bits
* the first bit must be one
* the second bit defines the command range ( 1 = 0 - 63 , 0 = 64 - 127 )
*/
if ( ! start )
2005-04-17 02:20:36 +04:00
/* no key pressed */
return 0 ;
2008-09-22 07:54:59 +04:00
/*
* Hauppauge remotes ( black / silver ) always use
* specific device ids . If we do not filter the
* device ids then messages destined for devices
* such as TVs ( id = 0 ) will get through causing
* mis - fired events .
*
* We also filter out invalid key presses which
* produce annoying debug log entries .
*/
ircode = ( start < < 12 ) | ( toggle < < 11 ) | ( dev < < 6 ) | code ;
if ( ( ircode & 0x1fff ) = = 0x1fff )
/* invalid key press */
return 0 ;
if ( dev ! = 0x1e & & dev ! = 0x1f )
/* not a hauppauge remote */
return 0 ;
2006-09-26 23:39:00 +04:00
if ( ! range )
code + = 64 ;
dprintk ( 1 , " ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d \n " ,
start , range , toggle , dev , code ) ;
2005-04-17 02:20:36 +04:00
/* return key */
* ir_key = code ;
2008-09-22 07:54:59 +04:00
* ir_raw = ircode ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
2009-07-28 18:41:35 +04:00
static int get_key_haup ( struct IR_i2c * ir , u32 * ir_key , u32 * ir_raw )
2007-06-25 21:34:06 +04:00
{
return get_key_haup_common ( ir , ir_key , ir_raw , 3 , 0 ) ;
}
2009-07-28 18:41:35 +04:00
static int get_key_haup_xvr ( struct IR_i2c * ir , u32 * ir_key , u32 * ir_raw )
2007-06-25 21:34:06 +04:00
{
return get_key_haup_common ( ir , ir_key , ir_raw , 6 , 3 ) ;
}
2005-11-09 08:37:32 +03:00
static int get_key_pixelview ( struct IR_i2c * ir , u32 * ir_key , u32 * ir_raw )
2005-04-17 02:20:36 +04:00
{
2005-11-09 08:37:43 +03:00
unsigned char b ;
2005-04-17 02:20:36 +04:00
/* poll IR chip */
2009-05-13 23:48:50 +04:00
if ( 1 ! = i2c_master_recv ( ir - > c , & b , 1 ) ) {
2005-04-17 02:20:36 +04:00
dprintk ( 1 , " read error \n " ) ;
return - EIO ;
}
* ir_key = b ;
* ir_raw = b ;
return 1 ;
}
2007-08-24 08:07:12 +04:00
static int get_key_fusionhdtv ( struct IR_i2c * ir , u32 * ir_key , u32 * ir_raw )
2007-08-24 08:02:32 +04:00
{
unsigned char buf [ 4 ] ;
/* poll IR chip */
2009-05-13 23:48:50 +04:00
if ( 4 ! = i2c_master_recv ( ir - > c , buf , 4 ) ) {
2007-08-24 08:02:32 +04:00
dprintk ( 1 , " read error \n " ) ;
return - EIO ;
}
if ( buf [ 0 ] ! = 0 | | buf [ 1 ] ! = 0 | | buf [ 2 ] ! = 0 | | buf [ 3 ] ! = 0 )
2008-04-09 06:20:00 +04:00
dprintk ( 2 , " %s: 0x%2x 0x%2x 0x%2x 0x%2x \n " , __func__ ,
2007-08-24 08:02:32 +04:00
buf [ 0 ] , buf [ 1 ] , buf [ 2 ] , buf [ 3 ] ) ;
/* no key pressed or signal from other ir remote */
if ( buf [ 0 ] ! = 0x1 | | buf [ 1 ] ! = 0xfe )
return 0 ;
* ir_key = buf [ 2 ] ;
* ir_raw = ( buf [ 2 ] < < 8 ) | buf [ 3 ] ;
return 1 ;
}
2005-11-09 08:37:32 +03:00
static int get_key_knc1 ( struct IR_i2c * ir , u32 * ir_key , u32 * ir_raw )
2005-04-17 02:20:36 +04:00
{
unsigned char b ;
/* poll IR chip */
2009-05-13 23:48:50 +04:00
if ( 1 ! = i2c_master_recv ( ir - > c , & b , 1 ) ) {
2005-04-17 02:20:36 +04:00
dprintk ( 1 , " read error \n " ) ;
return - EIO ;
}
/* it seems that 0xFE indicates that a button is still hold
2005-11-09 08:37:36 +03:00
down , while 0xff indicates that no button is hold
down . 0xfe sequences are sometimes interrupted by 0xFF */
2005-04-17 02:20:36 +04:00
dprintk ( 2 , " key %02x \n " , b ) ;
2005-11-09 08:37:36 +03:00
if ( b = = 0xff )
2005-04-17 02:20:36 +04:00
return 0 ;
2005-11-09 08:37:36 +03:00
if ( b = = 0xfe )
2005-04-17 02:20:36 +04:00
/* keep old data */
return 1 ;
* ir_key = b ;
* ir_raw = b ;
return 1 ;
}
2009-02-12 09:43:11 +03:00
static int get_key_avermedia_cardbus ( struct IR_i2c * ir ,
u32 * ir_key , u32 * ir_raw )
{
unsigned char subaddr , key , keygroup ;
2009-05-13 23:48:50 +04:00
struct i2c_msg msg [ ] = { { . addr = ir - > c - > addr , . flags = 0 ,
2009-02-12 09:43:11 +03:00
. buf = & subaddr , . len = 1 } ,
2009-05-13 23:48:50 +04:00
{ . addr = ir - > c - > addr , . flags = I2C_M_RD ,
2009-02-12 09:43:11 +03:00
. buf = & key , . len = 1 } } ;
subaddr = 0x0d ;
2009-05-13 23:48:50 +04:00
if ( 2 ! = i2c_transfer ( ir - > c - > adapter , msg , 2 ) ) {
2009-02-12 09:43:11 +03:00
dprintk ( 1 , " read error \n " ) ;
return - EIO ;
}
if ( key = = 0xff )
return 0 ;
subaddr = 0x0b ;
msg [ 1 ] . buf = & keygroup ;
2009-05-13 23:48:50 +04:00
if ( 2 ! = i2c_transfer ( ir - > c - > adapter , msg , 2 ) ) {
2009-02-12 09:43:11 +03:00
dprintk ( 1 , " read error \n " ) ;
return - EIO ;
}
if ( keygroup = = 0xff )
return 0 ;
dprintk ( 1 , " read key 0x%02x/0x%02x \n " , key , keygroup ) ;
if ( keygroup < 2 | | keygroup > 3 ) {
/* Only a warning */
dprintk ( 1 , " warning: invalid key group 0x%02x for key 0x%02x \n " ,
keygroup , key ) ;
}
key | = ( keygroup & 1 ) < < 6 ;
* ir_key = key ;
* ir_raw = key ;
return 1 ;
}
2005-04-17 02:20:36 +04:00
/* ----------------------------------------------------------------------- */
2005-11-09 08:37:32 +03:00
static void ir_key_poll ( struct IR_i2c * ir )
2005-04-17 02:20:36 +04:00
{
static u32 ir_key , ir_raw ;
int rc ;
2011-01-12 19:50:01 +03:00
dprintk ( 3 , " %s \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
rc = ir - > get_key ( ir , & ir_key , & ir_raw ) ;
if ( rc < 0 ) {
dprintk ( 2 , " error \n " ) ;
return ;
}
2011-01-12 19:50:01 +03:00
if ( rc ) {
dprintk ( 1 , " %s: keycode = 0x%04x \n " , __func__ , ir_key ) ;
2010-11-17 19:53:11 +03:00
rc_keydown ( ir - > rc , ir_key , 0 ) ;
2011-01-12 19:50:01 +03:00
}
2005-04-17 02:20:36 +04:00
}
2006-11-22 17:57:56 +03:00
static void ir_work ( struct work_struct * work )
2005-04-17 02:20:36 +04:00
{
2009-03-07 13:43:43 +03:00
struct IR_i2c * ir = container_of ( work , struct IR_i2c , work . work ) ;
2007-05-21 18:51:11 +04:00
2005-04-17 02:20:36 +04:00
ir_key_poll ( ir ) ;
2010-09-23 08:23:10 +04:00
schedule_delayed_work ( & ir - > work , msecs_to_jiffies ( ir - > polling_interval ) ) ;
2005-04-17 02:20:36 +04:00
}
/* ----------------------------------------------------------------------- */
2009-05-13 23:48:50 +04:00
static int ir_probe ( struct i2c_client * client , const struct i2c_device_id * id )
2005-04-17 02:20:36 +04:00
{
2010-04-03 03:01:00 +04:00
char * ir_codes = NULL ;
2009-05-13 23:50:11 +04:00
const char * name = NULL ;
2010-11-17 20:20:52 +03:00
u64 rc_type = RC_TYPE_UNKNOWN ;
2005-12-12 11:37:27 +03:00
struct IR_i2c * ir ;
2010-11-12 15:02:40 +03:00
struct rc_dev * rc = NULL ;
2009-05-13 23:48:50 +04:00
struct i2c_adapter * adap = client - > adapter ;
unsigned short addr = client - > addr ;
2006-11-20 16:23:04 +03:00
int err ;
2005-04-17 02:20:36 +04:00
2010-11-12 15:02:40 +03:00
ir = kzalloc ( sizeof ( struct IR_i2c ) , GFP_KERNEL ) ;
if ( ! ir )
return - ENOMEM ;
2005-09-15 11:01:53 +04:00
2009-05-13 23:48:50 +04:00
ir - > c = client ;
2010-09-23 08:23:10 +04:00
ir - > polling_interval = DEFAULT_POLLING_INTERVAL ;
2009-05-13 23:48:50 +04:00
i2c_set_clientdata ( client , ir ) ;
2006-01-09 20:25:21 +03:00
2005-04-17 02:20:36 +04:00
switch ( addr ) {
case 0x64 :
name = " Pixelview " ;
ir - > get_key = get_key_pixelview ;
2010-11-17 20:20:52 +03:00
rc_type = RC_TYPE_OTHER ;
2010-04-03 03:01:00 +04:00
ir_codes = RC_MAP_EMPTY ;
2005-04-17 02:20:36 +04:00
break ;
case 0x18 :
2009-11-13 11:48:24 +03:00
case 0x1f :
2005-04-17 02:20:36 +04:00
case 0x1a :
name = " Hauppauge " ;
ir - > get_key = get_key_haup ;
2010-11-17 20:20:52 +03:00
rc_type = RC_TYPE_RC5 ;
2006-01-23 14:34:06 +03:00
if ( hauppauge = = 1 ) {
2010-04-03 03:01:00 +04:00
ir_codes = RC_MAP_HAUPPAUGE_NEW ;
2006-01-23 14:34:06 +03:00
} else {
2010-04-03 03:01:00 +04:00
ir_codes = RC_MAP_RC5_TV ;
2006-01-23 14:34:06 +03:00
}
2005-04-17 02:20:36 +04:00
break ;
case 0x30 :
2005-11-09 08:37:32 +03:00
name = " KNC One " ;
ir - > get_key = get_key_knc1 ;
2010-11-17 20:20:52 +03:00
rc_type = RC_TYPE_OTHER ;
2010-04-03 03:01:00 +04:00
ir_codes = RC_MAP_EMPTY ;
2005-04-17 02:20:36 +04:00
break ;
2007-08-24 08:02:32 +04:00
case 0x6b :
2007-08-24 08:07:12 +04:00
name = " FusionHDTV " ;
ir - > get_key = get_key_fusionhdtv ;
2010-11-17 20:20:52 +03:00
rc_type = RC_TYPE_RC5 ;
2010-04-03 03:01:00 +04:00
ir_codes = RC_MAP_FUSIONHDTV_MCE ;
2007-08-24 08:02:32 +04:00
break ;
2009-02-12 09:43:11 +03:00
case 0x40 :
name = " AVerMedia Cardbus remote " ;
ir - > get_key = get_key_avermedia_cardbus ;
2010-11-17 20:20:52 +03:00
rc_type = RC_TYPE_OTHER ;
2010-04-03 03:01:00 +04:00
ir_codes = RC_MAP_AVERMEDIA_CARDBUS ;
2009-02-12 09:43:11 +03:00
break ;
2005-04-17 02:20:36 +04:00
}
2009-05-13 23:49:32 +04:00
/* Let the caller override settings */
if ( client - > dev . platform_data ) {
const struct IR_i2c_init_data * init_data =
client - > dev . platform_data ;
ir_codes = init_data - > ir_codes ;
2010-11-12 15:02:40 +03:00
rc = init_data - > rc_dev ;
2009-05-13 23:49:32 +04:00
name = init_data - > name ;
2009-07-28 18:44:05 +04:00
if ( init_data - > type )
2010-11-17 20:20:52 +03:00
rc_type = init_data - > type ;
2009-07-28 18:44:05 +04:00
2010-09-23 08:23:10 +04:00
if ( init_data - > polling_interval )
ir - > polling_interval = init_data - > polling_interval ;
2009-07-28 18:44:05 +04:00
switch ( init_data - > internal_get_key_func ) {
case IR_KBD_GET_KEY_CUSTOM :
/* The bridge driver provided us its own function */
ir - > get_key = init_data - > get_key ;
break ;
case IR_KBD_GET_KEY_PIXELVIEW :
ir - > get_key = get_key_pixelview ;
break ;
case IR_KBD_GET_KEY_HAUP :
ir - > get_key = get_key_haup ;
break ;
case IR_KBD_GET_KEY_KNC1 :
ir - > get_key = get_key_knc1 ;
break ;
case IR_KBD_GET_KEY_FUSIONHDTV :
ir - > get_key = get_key_fusionhdtv ;
break ;
case IR_KBD_GET_KEY_HAUP_XVR :
ir - > get_key = get_key_haup_xvr ;
break ;
case IR_KBD_GET_KEY_AVERMEDIA_CARDBUS :
ir - > get_key = get_key_avermedia_cardbus ;
break ;
}
2009-05-13 23:49:32 +04:00
}
2010-11-12 15:02:40 +03:00
if ( ! rc ) {
/*
* If platform_data doesn ' t specify rc_dev , initilize it
* internally
*/
rc = rc_allocate_device ( ) ;
if ( ! rc ) {
err = - ENOMEM ;
goto err_out_free ;
}
}
ir - > rc = rc ;
2009-05-13 23:50:11 +04:00
/* Make sure we are all setup before going on */
2010-11-17 20:20:52 +03:00
if ( ! name | | ! ir - > get_key | | ! rc_type | | ! ir_codes ) {
2009-11-24 18:06:52 +03:00
dprintk ( 1 , " : Unsupported device at address 0x%02x \n " ,
2009-05-13 23:50:11 +04:00
addr ) ;
err = - ENODEV ;
goto err_out_free ;
}
2005-11-09 08:37:56 +03:00
/* Sets name */
2009-05-13 23:48:07 +04:00
snprintf ( ir - > name , sizeof ( ir - > name ) , " i2c IR (%s) " , name ) ;
2006-11-20 16:23:04 +03:00
ir - > ir_codes = ir_codes ;
2005-11-09 08:37:32 +03:00
2005-11-09 08:37:56 +03:00
snprintf ( ir - > phys , sizeof ( ir - > phys ) , " %s/%s/ir0 " ,
2009-05-13 23:48:50 +04:00
dev_name ( & adap - > dev ) ,
dev_name ( & client - > dev ) ) ;
2005-11-09 08:37:56 +03:00
2010-11-12 15:02:40 +03:00
/*
* Initialize input_dev fields
* It doesn ' t make sense to allow overriding them via platform_data
*/
2010-10-29 23:08:23 +04:00
rc - > input_id . bustype = BUS_I2C ;
rc - > input_phys = ir - > phys ;
2010-11-12 15:02:40 +03:00
rc - > input_name = ir - > name ;
/*
* Initialize the other fields of rc_dev
*/
rc - > map_name = ir - > ir_codes ;
2010-11-17 20:20:52 +03:00
rc - > allowed_protos = rc_type ;
2010-11-12 15:02:40 +03:00
if ( ! rc - > driver_name )
rc - > driver_name = MODULE_NAME ;
2005-09-15 11:01:53 +04:00
2010-10-29 23:08:23 +04:00
err = rc_register_device ( rc ) ;
2006-11-20 16:23:04 +03:00
if ( err )
2009-05-13 23:48:50 +04:00
goto err_out_free ;
2006-11-20 16:23:04 +03:00
2010-03-13 03:18:14 +03:00
printk ( MODULE_NAME " : %s detected at %s [%s] \n " ,
2010-10-29 23:08:23 +04:00
ir - > name , ir - > phys , adap - > name ) ;
2005-04-17 02:20:36 +04:00
/* start polling via eventd */
2009-03-07 13:43:43 +03:00
INIT_DELAYED_WORK ( & ir - > work , ir_work ) ;
schedule_delayed_work ( & ir - > work , 0 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
2006-11-20 16:23:04 +03:00
err_out_free :
2010-11-12 15:02:40 +03:00
/* Only frees rc if it were allocated internally */
2010-10-29 23:08:23 +04:00
rc_free_device ( rc ) ;
2006-11-20 16:23:04 +03:00
kfree ( ir ) ;
return err ;
2005-04-17 02:20:36 +04:00
}
2009-05-13 23:48:50 +04:00
static int ir_remove ( struct i2c_client * client )
2005-04-17 02:20:36 +04:00
{
2005-11-09 08:37:43 +03:00
struct IR_i2c * ir = i2c_get_clientdata ( client ) ;
2005-04-17 02:20:36 +04:00
/* kill outstanding polls */
2009-03-07 13:43:43 +03:00
cancel_delayed_work_sync ( & ir - > work ) ;
2005-04-17 02:20:36 +04:00
2009-05-13 23:48:50 +04:00
/* unregister device */
2010-10-29 23:08:23 +04:00
rc_unregister_device ( ir - > rc ) ;
2005-04-17 02:20:36 +04:00
/* free memory */
kfree ( ir ) ;
return 0 ;
}
2009-05-13 23:48:50 +04:00
static const struct i2c_device_id ir_kbd_id [ ] = {
/* Generic entry for any IR receiver */
{ " ir_video " , 0 } ,
2009-07-28 18:50:14 +04:00
/* IR device specific entries should be added here */
{ " ir_rx_z8f0811_haup " , 0 } ,
2010-12-29 04:47:46 +03:00
{ " ir_rx_z8f0811_hdpvr " , 0 } ,
2009-05-13 23:48:50 +04:00
{ }
} ;
2009-02-12 09:43:11 +03:00
2009-05-13 23:48:50 +04:00
static struct i2c_driver driver = {
. driver = {
. name = " ir-kbd-i2c " ,
} ,
. probe = ir_probe ,
. remove = ir_remove ,
. id_table = ir_kbd_id ,
} ;
2005-04-17 02:20:36 +04:00
/* ----------------------------------------------------------------------- */
MODULE_AUTHOR ( " Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller " ) ;
MODULE_DESCRIPTION ( " input driver for i2c IR remote controls " ) ;
MODULE_LICENSE ( " GPL " ) ;
static int __init ir_init ( void )
{
return i2c_add_driver ( & driver ) ;
}
static void __exit ir_fini ( void )
{
i2c_del_driver ( & driver ) ;
}
module_init ( ir_init ) ;
module_exit ( ir_fini ) ;
/*
* Overrides for Emacs so that we follow Linus ' s tabbing style .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Local variables :
* c - basic - offset : 8
* End :
*/