2006-03-03 12:13:42 -03: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/string.h>
2006-12-27 14:04:09 -02:00
# include <linux/jiffies.h>
2006-03-03 12:13:42 -03: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) " ) ;
2008-04-22 14:41:48 -03:00
static int debug ; /* debug level (0,1,2) */
2006-03-03 12:13:42 -03:00
module_param ( debug , int , 0644 ) ;
# define dprintk(level, fmt, arg...) if (debug >= level) \
printk ( KERN_DEBUG fmt , # # arg )
/* -------------------------------------------------------------------------- */
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 ) ;
}
2008-07-17 22:28:56 -03:00
EXPORT_SYMBOL_GPL ( ir_input_init ) ;
2006-03-03 12:13:42 -03:00
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 ) ;
}
}
2008-07-17 22:28:56 -03:00
EXPORT_SYMBOL_GPL ( ir_input_nokey ) ;
2006-03-03 12:13:42 -03:00
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 ) ;
}
}
2008-07-17 22:28:56 -03:00
EXPORT_SYMBOL_GPL ( ir_input_keydown ) ;
2006-03-03 12:13:42 -03:00
/* -------------------------------------------------------------------------- */
2007-07-11 20:28:44 -03:00
/* extract mask bits out of data and pack them into the result */
2006-03-03 12:13:42 -03:00
u32 ir_extract_bits ( u32 data , u32 mask )
{
2007-07-11 20:28:44 -03:00
u32 vbit = 1 , value = 0 ;
do {
if ( mask & 1 ) {
if ( data & 1 )
value | = vbit ;
vbit < < = 1 ;
}
data > > = 1 ;
} while ( mask > > = 1 ) ;
2006-03-03 12:13:42 -03:00
return value ;
}
2008-07-17 22:28:56 -03:00
EXPORT_SYMBOL_GPL ( ir_extract_bits ) ;
2006-03-03 12:13:42 -03:00
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 ;
}
2008-07-17 22:28:56 -03:00
EXPORT_SYMBOL_GPL ( ir_dump_samples ) ;
2006-03-03 12:13:42 -03: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 ;
}
2008-07-17 22:28:56 -03:00
EXPORT_SYMBOL_GPL ( ir_decode_pulsedistance ) ;
2006-03-03 12:13:42 -03: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 ;
}
2008-07-17 22:28:56 -03:00
EXPORT_SYMBOL_GPL ( ir_decode_biphase ) ;
2006-03-03 12:13:42 -03:00
2006-12-07 21:45:28 -03:00
/* RC5 decoding stuff, moved from bttv-input.c to share it with
* saa7134 */
/* decode raw bit pattern to RC5 code */
2007-11-05 14:07:18 -03:00
static u32 ir_rc5_decode ( unsigned int code )
2006-12-07 21:45:28 -03:00
{
unsigned int org_code = code ;
unsigned int pair ;
unsigned int rc5 = 0 ;
int i ;
for ( i = 0 ; i < 14 ; + + i ) {
pair = code & 0x3 ;
code > > = 2 ;
rc5 < < = 1 ;
switch ( pair ) {
case 0 :
case 2 :
break ;
case 1 :
rc5 | = 1 ;
break ;
case 3 :
dprintk ( 1 , " ir-common: ir_rc5_decode(%x) bad code \n " , org_code ) ;
return 0 ;
}
}
dprintk ( 1 , " ir-common: code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
" instr=%x \n " , rc5 , org_code , RC5_START ( rc5 ) ,
RC5_TOGGLE ( rc5 ) , RC5_ADDR ( rc5 ) , RC5_INSTR ( rc5 ) ) ;
return rc5 ;
}
void ir_rc5_timer_end ( unsigned long data )
{
struct card_ir * ir = ( struct card_ir * ) data ;
struct timeval tv ;
unsigned long current_jiffies , timeout ;
u32 gap ;
u32 rc5 = 0 ;
/* get time */
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 ;
}
2007-03-25 11:58:23 -03:00
/* signal we're ready to start a new code */
ir - > active = 0 ;
/* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */
2006-12-07 21:45:28 -03:00
if ( gap < 28000 ) {
dprintk ( 1 , " ir-common: spurious timer_end \n " ) ;
return ;
}
if ( ir - > last_bit < 20 ) {
/* ignore spurious codes (caused by light/other remotes) */
dprintk ( 1 , " ir-common: short code: %x \n " , ir - > code ) ;
} else {
ir - > code = ( ir - > code < < ir - > shift_by ) | 1 ;
rc5 = ir_rc5_decode ( ir - > code ) ;
/* two start bits? */
if ( RC5_START ( rc5 ) ! = ir - > start ) {
dprintk ( 1 , " ir-common: rc5 start bits invalid: %u \n " , RC5_START ( rc5 ) ) ;
/* right address? */
} else if ( RC5_ADDR ( rc5 ) = = ir - > addr ) {
u32 toggle = RC5_TOGGLE ( rc5 ) ;
u32 instr = RC5_INSTR ( rc5 ) ;
/* Good code, decide if repeat/repress */
if ( toggle ! = RC5_TOGGLE ( ir - > last_rc5 ) | |
instr ! = RC5_INSTR ( ir - > last_rc5 ) ) {
dprintk ( 1 , " ir-common: instruction %x, toggle %x \n " , instr ,
toggle ) ;
ir_input_nokey ( ir - > dev , & ir - > ir ) ;
ir_input_keydown ( ir - > dev , & ir - > ir , instr ,
instr ) ;
}
/* Set/reset key-up timer */
2007-07-17 16:27:30 -03:00
timeout = current_jiffies +
msecs_to_jiffies ( ir - > rc5_key_timeout ) ;
2006-12-07 21:45:28 -03:00
mod_timer ( & ir - > timer_keyup , timeout ) ;
/* Save code for repeat test */
ir - > last_rc5 = rc5 ;
}
}
}
2008-07-17 22:28:56 -03:00
EXPORT_SYMBOL_GPL ( ir_rc5_timer_end ) ;
2006-12-07 21:45:28 -03:00
void ir_rc5_timer_keyup ( unsigned long data )
{
struct card_ir * ir = ( struct card_ir * ) data ;
dprintk ( 1 , " ir-common: key released \n " ) ;
ir_input_nokey ( ir - > dev , & ir - > ir ) ;
}
EXPORT_SYMBOL_GPL ( ir_rc5_timer_keyup ) ;