2019-05-29 07:17:59 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2014-01-17 10:58:48 -03:00
/* ir-sharp-decoder.c - handle Sharp IR Pulse/Space protocol
*
* Copyright ( C ) 2013 - 2014 Imagination Technologies Ltd .
*
* Based on NEC decoder :
2014-02-07 08:03:07 -02:00
* Copyright ( C ) 2010 by Mauro Carvalho Chehab
2014-01-17 10:58:48 -03:00
*/
# include <linux/bitrev.h>
# include <linux/module.h>
# include "rc-core-priv.h"
# define SHARP_NBITS 15
2020-08-23 19:23:05 +02:00
# define SHARP_UNIT 40 /* us */
2014-01-17 10:58:48 -03:00
# define SHARP_BIT_PULSE (8 * SHARP_UNIT) /* 320us */
# define SHARP_BIT_0_PERIOD (25 * SHARP_UNIT) /* 1ms (680us space) */
# define SHARP_BIT_1_PERIOD (50 * SHARP_UNIT) /* 2ms (1680ms space) */
# define SHARP_ECHO_SPACE (1000 * SHARP_UNIT) /* 40 ms */
# define SHARP_TRAILER_SPACE (125 * SHARP_UNIT) /* 5 ms (even longer) */
enum sharp_state {
STATE_INACTIVE ,
STATE_BIT_PULSE ,
STATE_BIT_SPACE ,
STATE_TRAILER_PULSE ,
STATE_ECHO_SPACE ,
STATE_TRAILER_SPACE ,
} ;
/**
* ir_sharp_decode ( ) - Decode one Sharp pulse or space
* @ dev : the struct rc_dev descriptor of the device
2017-11-29 03:46:30 -05:00
* @ ev : the struct ir_raw_event descriptor of the pulse / space
2014-01-17 10:58:48 -03:00
*
* This function returns - EINVAL if the pulse violates the state machine
*/
static int ir_sharp_decode ( struct rc_dev * dev , struct ir_raw_event ev )
{
struct sharp_dec * data = & dev - > raw - > sharp ;
u32 msg , echo , address , command , scancode ;
if ( ! is_timing_event ( ev ) ) {
2022-01-15 11:12:35 +01:00
if ( ev . overflow )
2014-01-17 10:58:48 -03:00
data - > state = STATE_INACTIVE ;
return 0 ;
}
2018-02-12 07:20:52 -05:00
dev_dbg ( & dev - > dev , " Sharp decode started at state %d (%uus %s) \n " ,
2020-08-23 19:23:05 +02:00
data - > state , ev . duration , TO_STR ( ev . pulse ) ) ;
2014-01-17 10:58:48 -03:00
switch ( data - > state ) {
case STATE_INACTIVE :
if ( ! ev . pulse )
break ;
if ( ! eq_margin ( ev . duration , SHARP_BIT_PULSE ,
SHARP_BIT_PULSE / 2 ) )
break ;
data - > count = 0 ;
data - > pulse_len = ev . duration ;
data - > state = STATE_BIT_SPACE ;
return 0 ;
case STATE_BIT_PULSE :
if ( ! ev . pulse )
break ;
if ( ! eq_margin ( ev . duration , SHARP_BIT_PULSE ,
SHARP_BIT_PULSE / 2 ) )
break ;
data - > pulse_len = ev . duration ;
data - > state = STATE_BIT_SPACE ;
return 0 ;
case STATE_BIT_SPACE :
if ( ev . pulse )
break ;
data - > bits < < = 1 ;
if ( eq_margin ( data - > pulse_len + ev . duration , SHARP_BIT_1_PERIOD ,
SHARP_BIT_PULSE * 2 ) )
data - > bits | = 1 ;
else if ( ! eq_margin ( data - > pulse_len + ev . duration ,
SHARP_BIT_0_PERIOD , SHARP_BIT_PULSE * 2 ) )
break ;
data - > count + + ;
if ( data - > count = = SHARP_NBITS | |
data - > count = = SHARP_NBITS * 2 )
data - > state = STATE_TRAILER_PULSE ;
else
data - > state = STATE_BIT_PULSE ;
return 0 ;
case STATE_TRAILER_PULSE :
if ( ! ev . pulse )
break ;
if ( ! eq_margin ( ev . duration , SHARP_BIT_PULSE ,
SHARP_BIT_PULSE / 2 ) )
break ;
if ( data - > count = = SHARP_NBITS ) {
/* exp,chk bits should be 1,0 */
2015-10-29 17:28:08 -02:00
if ( ( data - > bits & 0x3 ) ! = 0x2 & &
/* DENON variant, both chk bits 0 */
( data - > bits & 0x3 ) ! = 0x0 )
2014-01-17 10:58:48 -03:00
break ;
data - > state = STATE_ECHO_SPACE ;
} else {
data - > state = STATE_TRAILER_SPACE ;
}
return 0 ;
case STATE_ECHO_SPACE :
if ( ev . pulse )
break ;
if ( ! eq_margin ( ev . duration , SHARP_ECHO_SPACE ,
SHARP_ECHO_SPACE / 4 ) )
break ;
data - > state = STATE_BIT_PULSE ;
return 0 ;
case STATE_TRAILER_SPACE :
if ( ev . pulse )
break ;
if ( ! geq_margin ( ev . duration , SHARP_TRAILER_SPACE ,
SHARP_BIT_PULSE / 2 ) )
break ;
/* Validate - command, ext, chk should be inverted in 2nd */
msg = ( data - > bits > > 15 ) & 0x7fff ;
echo = data - > bits & 0x7fff ;
if ( ( msg ^ echo ) ! = 0x3ff ) {
2018-02-12 07:20:52 -05:00
dev_dbg ( & dev - > dev ,
" Sharp checksum error: received 0x%04x, 0x%04x \n " ,
msg , echo ) ;
2014-01-17 10:58:48 -03:00
break ;
}
address = bitrev8 ( ( msg > > 7 ) & 0xf8 ) ;
command = bitrev8 ( ( msg > > 2 ) & 0xff ) ;
scancode = address < < 8 | command ;
2018-02-12 07:20:52 -05:00
dev_dbg ( & dev - > dev , " Sharp scancode 0x%04x \n " , scancode ) ;
2014-01-17 10:58:48 -03:00
2017-08-07 16:20:58 -04:00
rc_keydown ( dev , RC_PROTO_SHARP , scancode , 0 ) ;
2014-01-17 10:58:48 -03:00
data - > state = STATE_INACTIVE ;
return 0 ;
}
2018-02-12 07:20:52 -05:00
dev_dbg ( & dev - > dev , " Sharp decode failed at count %d state %d (%uus %s) \n " ,
2020-08-23 19:23:05 +02:00
data - > count , data - > state , ev . duration , TO_STR ( ev . pulse ) ) ;
2014-01-17 10:58:48 -03:00
data - > state = STATE_INACTIVE ;
return - EINVAL ;
}
2016-12-06 18:11:30 -02:00
static const struct ir_raw_timings_pd ir_sharp_timings = {
. header_pulse = 0 ,
. header_space = 0 ,
. bit_pulse = SHARP_BIT_PULSE ,
. bit_space [ 0 ] = SHARP_BIT_0_PERIOD ,
. bit_space [ 1 ] = SHARP_BIT_1_PERIOD ,
. trailer_pulse = SHARP_BIT_PULSE ,
. trailer_space = SHARP_ECHO_SPACE ,
. msb_first = 1 ,
} ;
/**
* ir_sharp_encode ( ) - Encode a scancode as a stream of raw events
*
* @ protocol : protocol to encode
* @ scancode : scancode to encode
* @ events : array of raw ir events to write into
* @ max : maximum size of @ events
*
* Returns : The number of events written .
* - ENOBUFS if there isn ' t enough space in the array to fit the
* encoding . In this case all @ max events will have been written .
*/
2017-08-07 16:20:58 -04:00
static int ir_sharp_encode ( enum rc_proto protocol , u32 scancode ,
2016-12-06 18:11:30 -02:00
struct ir_raw_event * events , unsigned int max )
{
struct ir_raw_event * e = events ;
int ret ;
u32 raw ;
raw = ( ( ( bitrev8 ( scancode > > 8 ) > > 3 ) < < 8 ) & 0x1f00 ) |
bitrev8 ( scancode ) ;
ret = ir_raw_gen_pd ( & e , max , & ir_sharp_timings , SHARP_NBITS ,
( raw < < 2 ) | 2 ) ;
if ( ret < 0 )
return ret ;
max - = ret ;
raw = ( ( ( bitrev8 ( scancode > > 8 ) > > 3 ) < < 8 ) & 0x1f00 ) |
bitrev8 ( ~ scancode ) ;
ret = ir_raw_gen_pd ( & e , max , & ir_sharp_timings , SHARP_NBITS ,
( raw < < 2 ) | 1 ) ;
if ( ret < 0 )
return ret ;
return e - events ;
}
2014-01-17 10:58:48 -03:00
static struct ir_raw_handler sharp_handler = {
2017-08-07 16:20:58 -04:00
. protocols = RC_PROTO_BIT_SHARP ,
2014-01-17 10:58:48 -03:00
. decode = ir_sharp_decode ,
2016-12-06 18:11:30 -02:00
. encode = ir_sharp_encode ,
2017-02-25 06:51:30 -05:00
. carrier = 38000 ,
2018-03-23 16:47:37 -04:00
. min_timeout = SHARP_ECHO_SPACE + SHARP_ECHO_SPACE / 4 ,
2014-01-17 10:58:48 -03:00
} ;
static int __init ir_sharp_decode_init ( void )
{
ir_raw_handler_register ( & sharp_handler ) ;
pr_info ( " IR Sharp protocol handler initialized \n " ) ;
return 0 ;
}
static void __exit ir_sharp_decode_exit ( void )
{
ir_raw_handler_unregister ( & sharp_handler ) ;
}
module_init ( ir_sharp_decode_init ) ;
module_exit ( ir_sharp_decode_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
2017-10-04 23:10:59 +01:00
MODULE_AUTHOR ( " James Hogan <jhogan@kernel.org> " ) ;
2014-01-17 10:58:48 -03:00
MODULE_DESCRIPTION ( " Sharp IR protocol decoder " ) ;