2005-04-16 15:20:36 -07:00
/*
*
* some common structs and functions to handle infrared remotes via
* input layer . . .
*
* ( c ) 2003 Gerd Knorr < kraxel @ bytesex . org > [ SuSE Labs ]
*
* 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>
2005-10-30 15:03:48 -08:00
# include <linux/string.h>
2005-04-16 15:20:36 -07:00
# include <media/ir-common.h>
/* -------------------------------------------------------------------------- */
MODULE_AUTHOR ( " Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] " ) ;
MODULE_LICENSE ( " GPL " ) ;
static int repeat = 1 ;
module_param ( repeat , int , 0444 ) ;
MODULE_PARM_DESC ( repeat , " auto-repeat for IR keys (default: on) " ) ;
static int debug = 0 ; /* debug level (0,1,2) */
module_param ( debug , int , 0644 ) ;
# define dprintk(level, fmt, arg...) if (debug >= level) \
printk ( KERN_DEBUG fmt , # # arg )
/* -------------------------------------------------------------------------- */
/* generic RC5 keytable */
/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
/* used by old (black) Hauppauge remotes */
IR_KEYTAB_TYPE ir_codes_rc5_tv [ IR_KEYTAB_SIZE ] = {
2005-07-12 13:58:52 -07:00
/* Keys 0 to 9 */
[ 0x00 ] = KEY_KP0 ,
[ 0x01 ] = KEY_KP1 ,
[ 0x02 ] = KEY_KP2 ,
[ 0x03 ] = KEY_KP3 ,
[ 0x04 ] = KEY_KP4 ,
[ 0x05 ] = KEY_KP5 ,
[ 0x06 ] = KEY_KP6 ,
[ 0x07 ] = KEY_KP7 ,
[ 0x08 ] = KEY_KP8 ,
[ 0x09 ] = KEY_KP9 ,
[ 0x0b ] = KEY_CHANNEL , /* channel / program (japan: 11) */
[ 0x0c ] = KEY_POWER , /* standby */
[ 0x0d ] = KEY_MUTE , /* mute / demute */
[ 0x0f ] = KEY_TV , /* display */
[ 0x10 ] = KEY_VOLUMEUP ,
[ 0x11 ] = KEY_VOLUMEDOWN ,
[ 0x12 ] = KEY_BRIGHTNESSUP ,
[ 0x13 ] = KEY_BRIGHTNESSDOWN ,
[ 0x1e ] = KEY_SEARCH , /* search + */
[ 0x20 ] = KEY_CHANNELUP , /* channel / program + */
[ 0x21 ] = KEY_CHANNELDOWN , /* channel / program - */
[ 0x22 ] = KEY_CHANNEL , /* alt / channel */
[ 0x23 ] = KEY_LANGUAGE , /* 1st / 2nd language */
[ 0x26 ] = KEY_SLEEP , /* sleeptimer */
[ 0x2e ] = KEY_MENU , /* 2nd controls (USA: menu) */
[ 0x30 ] = KEY_PAUSE ,
[ 0x32 ] = KEY_REWIND ,
[ 0x33 ] = KEY_GOTO ,
[ 0x35 ] = KEY_PLAY ,
[ 0x36 ] = KEY_STOP ,
[ 0x37 ] = KEY_RECORD , /* recording */
[ 0x3c ] = KEY_TEXT , /* teletext submode (Japan: 12) */
[ 0x3d ] = KEY_SUSPEND , /* system standby */
2005-04-16 15:20:36 -07:00
} ;
EXPORT_SYMBOL_GPL ( ir_codes_rc5_tv ) ;
/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
IR_KEYTAB_TYPE ir_codes_winfast [ IR_KEYTAB_SIZE ] = {
2005-07-12 13:58:52 -07:00
/* Keys 0 to 9 */
[ 18 ] = KEY_KP0 ,
2005-04-16 15:20:36 -07:00
[ 5 ] = KEY_KP1 ,
[ 6 ] = KEY_KP2 ,
[ 7 ] = KEY_KP3 ,
[ 9 ] = KEY_KP4 ,
[ 10 ] = KEY_KP5 ,
[ 11 ] = KEY_KP6 ,
[ 13 ] = KEY_KP7 ,
[ 14 ] = KEY_KP8 ,
[ 15 ] = KEY_KP9 ,
[ 0 ] = KEY_POWER ,
2005-07-12 13:58:52 -07:00
[ 2 ] = KEY_TUNER , /* TV/FM */
2005-04-16 15:20:36 -07:00
[ 30 ] = KEY_VIDEO ,
[ 4 ] = KEY_VOLUMEUP ,
[ 8 ] = KEY_VOLUMEDOWN ,
[ 12 ] = KEY_CHANNELUP ,
[ 16 ] = KEY_CHANNELDOWN ,
2005-07-12 13:58:52 -07:00
[ 3 ] = KEY_ZOOM , /* fullscreen */
[ 31 ] = KEY_SUBTITLE , /* closed caption/teletext */
2005-04-16 15:20:36 -07:00
[ 32 ] = KEY_SLEEP ,
[ 20 ] = KEY_MUTE ,
[ 43 ] = KEY_RED ,
[ 44 ] = KEY_GREEN ,
[ 45 ] = KEY_YELLOW ,
[ 46 ] = KEY_BLUE ,
2005-07-12 13:58:52 -07:00
[ 24 ] = KEY_KPPLUS , /* fine tune + */
[ 25 ] = KEY_KPMINUS , /* fine tune - */
2005-06-23 22:05:07 -07:00
[ 33 ] = KEY_KPDOT ,
2005-04-16 15:20:36 -07:00
[ 19 ] = KEY_KPENTER ,
[ 34 ] = KEY_BACK ,
[ 35 ] = KEY_PLAYPAUSE ,
[ 36 ] = KEY_NEXT ,
[ 38 ] = KEY_STOP ,
2005-06-23 22:05:07 -07:00
[ 39 ] = KEY_RECORD
2005-04-16 15:20:36 -07:00
} ;
EXPORT_SYMBOL_GPL ( ir_codes_winfast ) ;
/* empty keytable, can be used as placeholder for not-yet created keytables */
IR_KEYTAB_TYPE ir_codes_empty [ IR_KEYTAB_SIZE ] = {
[ 42 ] = KEY_COFFEE ,
} ;
EXPORT_SYMBOL_GPL ( ir_codes_empty ) ;
/* Hauppauge: the newer, gray remotes (seems there are multiple
* slightly different versions ) , shipped with cx88 + ivtv cards .
* almost rc5 coding , but some non - standard keys */
IR_KEYTAB_TYPE ir_codes_hauppauge_new [ IR_KEYTAB_SIZE ] = {
2005-07-12 13:58:52 -07:00
/* Keys 0 to 9 */
[ 0x00 ] = KEY_KP0 ,
[ 0x01 ] = KEY_KP1 ,
[ 0x02 ] = KEY_KP2 ,
[ 0x03 ] = KEY_KP3 ,
[ 0x04 ] = KEY_KP4 ,
[ 0x05 ] = KEY_KP5 ,
[ 0x06 ] = KEY_KP6 ,
[ 0x07 ] = KEY_KP7 ,
[ 0x08 ] = KEY_KP8 ,
[ 0x09 ] = KEY_KP9 ,
[ 0x0a ] = KEY_TEXT , /* keypad asterisk as well */
[ 0x0b ] = KEY_RED , /* red button */
[ 0x0c ] = KEY_RADIO ,
[ 0x0d ] = KEY_MENU ,
[ 0x0e ] = KEY_SUBTITLE , /* also the # key */
[ 0x0f ] = KEY_MUTE ,
[ 0x10 ] = KEY_VOLUMEUP ,
[ 0x11 ] = KEY_VOLUMEDOWN ,
[ 0x12 ] = KEY_PREVIOUS , /* previous channel */
[ 0x14 ] = KEY_UP ,
[ 0x15 ] = KEY_DOWN ,
[ 0x16 ] = KEY_LEFT ,
[ 0x17 ] = KEY_RIGHT ,
[ 0x18 ] = KEY_VIDEO , /* Videos */
[ 0x19 ] = KEY_AUDIO , /* Music */
/* 0x1a: Pictures - presume this means
" Multimedia Home Platform " -
no " PICTURES " key in input . h
*/
[ 0x1a ] = KEY_MHP ,
[ 0x1b ] = KEY_EPG , /* Guide */
[ 0x1c ] = KEY_TV ,
[ 0x1e ] = KEY_NEXTSONG , /* skip >| */
[ 0x1f ] = KEY_EXIT , /* back/exit */
[ 0x20 ] = KEY_CHANNELUP , /* channel / program + */
[ 0x21 ] = KEY_CHANNELDOWN , /* channel / program - */
[ 0x22 ] = KEY_CHANNEL , /* source (old black remote) */
[ 0x24 ] = KEY_PREVIOUSSONG , /* replay |< */
[ 0x25 ] = KEY_ENTER , /* OK */
[ 0x26 ] = KEY_SLEEP , /* minimize (old black remote) */
[ 0x29 ] = KEY_BLUE , /* blue key */
[ 0x2e ] = KEY_GREEN , /* green button */
[ 0x30 ] = KEY_PAUSE , /* pause */
[ 0x32 ] = KEY_REWIND , /* backward << */
[ 0x34 ] = KEY_FASTFORWARD , /* forward >> */
[ 0x35 ] = KEY_PLAY ,
[ 0x36 ] = KEY_STOP ,
[ 0x37 ] = KEY_RECORD , /* recording */
[ 0x38 ] = KEY_YELLOW , /* yellow key */
[ 0x3b ] = KEY_SELECT , /* top right button */
[ 0x3c ] = KEY_ZOOM , /* full */
[ 0x3d ] = KEY_POWER , /* system power (green button) */
2005-04-16 15:20:36 -07:00
} ;
EXPORT_SYMBOL ( ir_codes_hauppauge_new ) ;
2005-06-23 22:04:53 -07:00
IR_KEYTAB_TYPE ir_codes_pixelview [ IR_KEYTAB_SIZE ] = {
[ 2 ] = KEY_KP0 ,
[ 1 ] = KEY_KP1 ,
[ 11 ] = KEY_KP2 ,
[ 27 ] = KEY_KP3 ,
[ 5 ] = KEY_KP4 ,
[ 9 ] = KEY_KP5 ,
[ 21 ] = KEY_KP6 ,
[ 6 ] = KEY_KP7 ,
[ 10 ] = KEY_KP8 ,
[ 18 ] = KEY_KP9 ,
2005-07-12 13:58:52 -07:00
[ 3 ] = KEY_TUNER , /* TV/FM */
[ 7 ] = KEY_SEARCH , /* scan */
[ 28 ] = KEY_ZOOM , /* full screen */
2005-06-23 22:04:53 -07:00
[ 30 ] = KEY_POWER ,
[ 23 ] = KEY_VOLUMEDOWN ,
[ 31 ] = KEY_VOLUMEUP ,
[ 20 ] = KEY_CHANNELDOWN ,
[ 22 ] = KEY_CHANNELUP ,
[ 24 ] = KEY_MUTE ,
2005-07-12 13:58:52 -07:00
[ 0 ] = KEY_LIST , /* source */
[ 19 ] = KEY_INFO , /* loop */
[ 16 ] = KEY_LAST , /* +100 */
[ 13 ] = KEY_CLEAR , /* reset */
[ 12 ] = BTN_RIGHT , /* fun++ */
[ 4 ] = BTN_LEFT , /* fun-- */
[ 14 ] = KEY_GOTO , /* function */
[ 15 ] = KEY_STOP , /* freeze */
2005-06-23 22:04:53 -07:00
} ;
EXPORT_SYMBOL ( ir_codes_pixelview ) ;
2005-04-16 15:20:36 -07:00
/* -------------------------------------------------------------------------- */
static void ir_input_key_event ( struct input_dev * dev , struct ir_input_state * ir )
{
if ( KEY_RESERVED = = ir - > keycode ) {
printk ( KERN_INFO " %s: unknown key: key=0x%02x raw=0x%02x down=%d \n " ,
dev - > name , ir - > ir_key , ir - > ir_raw , ir - > keypressed ) ;
return ;
}
dprintk ( 1 , " %s: key event code=%d down=%d \n " ,
dev - > name , ir - > keycode , ir - > keypressed ) ;
input_report_key ( dev , ir - > keycode , ir - > keypressed ) ;
input_sync ( dev ) ;
}
/* -------------------------------------------------------------------------- */
void ir_input_init ( struct input_dev * dev , struct ir_input_state * ir ,
int ir_type , IR_KEYTAB_TYPE * ir_codes )
{
int i ;
ir - > ir_type = ir_type ;
if ( ir_codes )
memcpy ( ir - > ir_codes , ir_codes , sizeof ( ir - > ir_codes ) ) ;
dev - > keycode = ir - > ir_codes ;
dev - > keycodesize = sizeof ( IR_KEYTAB_TYPE ) ;
dev - > keycodemax = IR_KEYTAB_SIZE ;
for ( i = 0 ; i < IR_KEYTAB_SIZE ; i + + )
set_bit ( ir - > ir_codes [ i ] , dev - > keybit ) ;
clear_bit ( 0 , dev - > keybit ) ;
set_bit ( EV_KEY , dev - > evbit ) ;
if ( repeat )
set_bit ( EV_REP , dev - > evbit ) ;
}
void ir_input_nokey ( struct input_dev * dev , struct ir_input_state * ir )
{
if ( ir - > keypressed ) {
ir - > keypressed = 0 ;
ir_input_key_event ( dev , ir ) ;
}
}
void ir_input_keydown ( struct input_dev * dev , struct ir_input_state * ir ,
u32 ir_key , u32 ir_raw )
{
u32 keycode = IR_KEYCODE ( ir - > ir_codes , ir_key ) ;
if ( ir - > keypressed & & ir - > keycode ! = keycode ) {
ir - > keypressed = 0 ;
ir_input_key_event ( dev , ir ) ;
}
if ( ! ir - > keypressed ) {
ir - > ir_key = ir_key ;
ir - > ir_raw = ir_raw ;
ir - > keycode = keycode ;
ir - > keypressed = 1 ;
ir_input_key_event ( dev , ir ) ;
}
}
/* -------------------------------------------------------------------------- */
u32 ir_extract_bits ( u32 data , u32 mask )
{
int mbit , vbit ;
u32 value ;
value = 0 ;
vbit = 0 ;
for ( mbit = 0 ; mbit < 32 ; mbit + + ) {
if ( ! ( mask & ( ( u32 ) 1 < < mbit ) ) )
continue ;
if ( data & ( ( u32 ) 1 < < mbit ) )
value | = ( 1 < < vbit ) ;
vbit + + ;
}
return value ;
}
static int inline getbit ( u32 * samples , int bit )
{
return ( samples [ bit / 32 ] & ( 1 < < ( 31 - ( bit % 32 ) ) ) ) ? 1 : 0 ;
}
/* sump raw samples for visual debugging ;) */
int ir_dump_samples ( u32 * samples , int count )
{
int i , bit , start ;
printk ( KERN_DEBUG " ir samples: " ) ;
start = 0 ;
for ( i = 0 ; i < count * 32 ; i + + ) {
bit = getbit ( samples , i ) ;
if ( bit )
start = 1 ;
if ( 0 = = start )
continue ;
printk ( " %s " , bit ? " # " : " _ " ) ;
}
printk ( " \n " ) ;
return 0 ;
}
2005-09-09 13:03:37 -07:00
/* decode raw samples, pulse distance coding used by NEC remotes */
int ir_decode_pulsedistance ( u32 * samples , int count , int low , int high )
{
int i , last , bit , len ;
u32 curBit ;
u32 value ;
/* find start burst */
for ( i = len = 0 ; i < count * 32 ; i + + ) {
bit = getbit ( samples , i ) ;
if ( bit ) {
len + + ;
} else {
if ( len > = 29 )
break ;
len = 0 ;
}
}
/* start burst to short */
if ( len < 29 )
return 0xffffffff ;
/* find start silence */
for ( len = 0 ; i < count * 32 ; i + + ) {
bit = getbit ( samples , i ) ;
if ( bit ) {
break ;
} else {
len + + ;
}
}
/* silence to short */
if ( len < 7 )
return 0xffffffff ;
/* go decoding */
len = 0 ;
last = 1 ;
value = 0 ; curBit = 1 ;
for ( ; i < count * 32 ; i + + ) {
bit = getbit ( samples , i ) ;
if ( last ) {
if ( bit ) {
continue ;
} else {
len = 1 ;
}
} else {
if ( bit ) {
if ( len > ( low + high ) / 2 )
value | = curBit ;
curBit < < = 1 ;
if ( curBit = = 1 )
break ;
} else {
len + + ;
}
}
last = bit ;
}
return value ;
}
2005-04-16 15:20:36 -07:00
/* decode raw samples, biphase coding, used by rc5 for example */
int ir_decode_biphase ( u32 * samples , int count , int low , int high )
{
int i , last , bit , len , flips ;
u32 value ;
/* find start bit (1) */
for ( i = 0 ; i < 32 ; i + + ) {
bit = getbit ( samples , i ) ;
if ( bit )
break ;
}
/* go decoding */
len = 0 ;
flips = 0 ;
value = 1 ;
for ( ; i < count * 32 ; i + + ) {
if ( len > high )
break ;
if ( flips > 1 )
break ;
last = bit ;
bit = getbit ( samples , i ) ;
if ( last = = bit ) {
len + + ;
continue ;
}
if ( len < low ) {
len + + ;
flips + + ;
continue ;
}
value < < = 1 ;
value | = bit ;
flips = 0 ;
len = 1 ;
}
return value ;
}
EXPORT_SYMBOL_GPL ( ir_input_init ) ;
EXPORT_SYMBOL_GPL ( ir_input_nokey ) ;
EXPORT_SYMBOL_GPL ( ir_input_keydown ) ;
EXPORT_SYMBOL_GPL ( ir_extract_bits ) ;
EXPORT_SYMBOL_GPL ( ir_dump_samples ) ;
EXPORT_SYMBOL_GPL ( ir_decode_biphase ) ;
2005-09-09 13:03:37 -07:00
EXPORT_SYMBOL_GPL ( ir_decode_pulsedistance ) ;
2005-04-16 15:20:36 -07:00
/*
* Local variables :
* c - basic - offset : 8
* End :
*/
2005-06-23 22:05:07 -07:00