2010-04-16 01:46:10 +04:00
/* ir-sony-decoder.c - handle Sony IR Pulse/Space protocol
*
* Copyright ( C ) 2010 by David Härdeman < david @ hardeman . nu >
*
* 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 version 2 of the License .
*
* 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 .
*/
# include <linux/bitrev.h>
2011-07-03 22:03:12 +04:00
# include <linux/module.h>
2010-11-10 05:09:57 +03:00
# include "rc-core-priv.h"
2010-04-16 01:46:10 +04:00
# define SONY_UNIT 600000 /* ns */
# define SONY_HEADER_PULSE (4 * SONY_UNIT)
# define SONY_HEADER_SPACE (1 * SONY_UNIT)
# define SONY_BIT_0_PULSE (1 * SONY_UNIT)
# define SONY_BIT_1_PULSE (2 * SONY_UNIT)
# define SONY_BIT_SPACE (1 * SONY_UNIT)
# define SONY_TRAILER_SPACE (10 * SONY_UNIT) /* minimum */
enum sony_state {
STATE_INACTIVE ,
STATE_HEADER_SPACE ,
STATE_BIT_PULSE ,
STATE_BIT_SPACE ,
STATE_FINISHED ,
} ;
/**
* ir_sony_decode ( ) - Decode one Sony pulse or space
2010-10-29 23:08:23 +04:00
* @ dev : the struct rc_dev descriptor of the device
2010-04-16 01:46:10 +04:00
* @ ev : the struct ir_raw_event descriptor of the pulse / space
*
* This function returns - EINVAL if the pulse violates the state machine
*/
2010-10-29 23:08:23 +04:00
static int ir_sony_decode ( struct rc_dev * dev , struct ir_raw_event ev )
2010-04-16 01:46:10 +04:00
{
2010-10-29 23:08:23 +04:00
struct sony_dec * data = & dev - > raw - > sony ;
2014-04-04 03:31:30 +04:00
enum rc_type protocol ;
2010-04-16 01:46:10 +04:00
u32 scancode ;
u8 device , subdevice , function ;
2014-04-04 03:32:21 +04:00
if ( ! ( dev - > enabled_protocols &
( RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 ) ) )
2010-04-16 01:46:10 +04:00
return 0 ;
2010-10-17 02:56:28 +04:00
if ( ! is_timing_event ( ev ) ) {
if ( ev . reset )
data - > state = STATE_INACTIVE ;
2010-04-16 01:46:10 +04:00
return 0 ;
}
if ( ! geq_margin ( ev . duration , SONY_UNIT , SONY_UNIT / 2 ) )
goto out ;
IR_dprintk ( 2 , " Sony decode started at state %d (%uus %s) \n " ,
data - > state , TO_US ( ev . duration ) , TO_STR ( ev . pulse ) ) ;
switch ( data - > state ) {
case STATE_INACTIVE :
if ( ! ev . pulse )
break ;
if ( ! eq_margin ( ev . duration , SONY_HEADER_PULSE , SONY_UNIT / 2 ) )
break ;
data - > count = 0 ;
data - > state = STATE_HEADER_SPACE ;
return 0 ;
case STATE_HEADER_SPACE :
if ( ev . pulse )
break ;
if ( ! eq_margin ( ev . duration , SONY_HEADER_SPACE , SONY_UNIT / 2 ) )
break ;
data - > state = STATE_BIT_PULSE ;
return 0 ;
case STATE_BIT_PULSE :
if ( ! ev . pulse )
break ;
2010-06-14 00:29:36 +04:00
data - > bits < < = 1 ;
2010-04-16 01:46:10 +04:00
if ( eq_margin ( ev . duration , SONY_BIT_1_PULSE , SONY_UNIT / 2 ) )
2010-06-14 00:29:36 +04:00
data - > bits | = 1 ;
2010-04-16 01:46:10 +04:00
else if ( ! eq_margin ( ev . duration , SONY_BIT_0_PULSE , SONY_UNIT / 2 ) )
break ;
data - > count + + ;
data - > state = STATE_BIT_SPACE ;
return 0 ;
case STATE_BIT_SPACE :
if ( ev . pulse )
break ;
if ( ! geq_margin ( ev . duration , SONY_BIT_SPACE , SONY_UNIT / 2 ) )
break ;
decrease_duration ( & ev , SONY_BIT_SPACE ) ;
if ( ! geq_margin ( ev . duration , SONY_UNIT , SONY_UNIT / 2 ) ) {
data - > state = STATE_BIT_PULSE ;
return 0 ;
}
data - > state = STATE_FINISHED ;
/* Fall through */
case STATE_FINISHED :
if ( ev . pulse )
break ;
if ( ! geq_margin ( ev . duration , SONY_TRAILER_SPACE , SONY_UNIT / 2 ) )
break ;
switch ( data - > count ) {
case 12 :
2014-04-04 03:32:21 +04:00
if ( ! ( dev - > enabled_protocols & RC_BIT_SONY12 ) ) {
2012-10-12 02:11:54 +04:00
data - > state = STATE_INACTIVE ;
return 0 ;
}
2010-06-14 00:29:36 +04:00
device = bitrev8 ( ( data - > bits < < 3 ) & 0xF8 ) ;
2010-04-16 01:46:10 +04:00
subdevice = 0 ;
2010-06-14 00:29:36 +04:00
function = bitrev8 ( ( data - > bits > > 4 ) & 0xFE ) ;
2014-04-04 03:31:30 +04:00
protocol = RC_TYPE_SONY12 ;
2010-04-16 01:46:10 +04:00
break ;
case 15 :
2014-04-04 03:32:21 +04:00
if ( ! ( dev - > enabled_protocols & RC_BIT_SONY15 ) ) {
2012-10-12 02:11:54 +04:00
data - > state = STATE_INACTIVE ;
return 0 ;
}
2010-06-14 00:29:36 +04:00
device = bitrev8 ( ( data - > bits > > 0 ) & 0xFF ) ;
2010-04-16 01:46:10 +04:00
subdevice = 0 ;
2012-02-20 13:13:54 +04:00
function = bitrev8 ( ( data - > bits > > 7 ) & 0xFE ) ;
2014-04-04 03:31:30 +04:00
protocol = RC_TYPE_SONY15 ;
2010-04-16 01:46:10 +04:00
break ;
case 20 :
2014-04-04 03:32:21 +04:00
if ( ! ( dev - > enabled_protocols & RC_BIT_SONY20 ) ) {
2012-10-12 02:11:54 +04:00
data - > state = STATE_INACTIVE ;
return 0 ;
}
2010-06-14 00:29:36 +04:00
device = bitrev8 ( ( data - > bits > > 5 ) & 0xF8 ) ;
subdevice = bitrev8 ( ( data - > bits > > 0 ) & 0xFF ) ;
function = bitrev8 ( ( data - > bits > > 12 ) & 0xFE ) ;
2014-04-04 03:31:30 +04:00
protocol = RC_TYPE_SONY20 ;
2010-04-16 01:46:10 +04:00
break ;
default :
IR_dprintk ( 1 , " Sony invalid bitcount %u \n " , data - > count ) ;
goto out ;
}
scancode = device < < 16 | subdevice < < 8 | function ;
IR_dprintk ( 1 , " Sony(%u) scancode 0x%05x \n " , data - > count , scancode ) ;
2014-04-04 03:31:30 +04:00
rc_keydown ( dev , protocol , scancode , 0 ) ;
2010-04-16 01:46:10 +04:00
data - > state = STATE_INACTIVE ;
return 0 ;
}
out :
IR_dprintk ( 1 , " Sony decode failed at state %d (%uus %s) \n " ,
data - > state , TO_US ( ev . duration ) , TO_STR ( ev . pulse ) ) ;
data - > state = STATE_INACTIVE ;
return - EINVAL ;
}
static struct ir_raw_handler sony_handler = {
2012-10-12 02:11:54 +04:00
. protocols = RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 ,
2010-04-16 01:46:10 +04:00
. decode = ir_sony_decode ,
} ;
static int __init ir_sony_decode_init ( void )
{
ir_raw_handler_register ( & sony_handler ) ;
printk ( KERN_INFO " IR Sony protocol handler initialized \n " ) ;
return 0 ;
}
static void __exit ir_sony_decode_exit ( void )
{
ir_raw_handler_unregister ( & sony_handler ) ;
}
module_init ( ir_sony_decode_init ) ;
module_exit ( ir_sony_decode_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " David Härdeman <david@hardeman.nu> " ) ;
MODULE_DESCRIPTION ( " Sony IR protocol decoder " ) ;