2019-05-29 07:17:59 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2010-04-15 18:46:05 -03:00
/* ir-jvc-decoder.c - handle JVC IR Pulse/Space protocol
*
* Copyright ( C ) 2010 by David Härdeman < david @ hardeman . nu >
*/
# include <linux/bitrev.h>
2011-07-03 14:03:12 -04:00
# include <linux/module.h>
2010-11-09 23:09:57 -03:00
# include "rc-core-priv.h"
2010-04-15 18:46:05 -03:00
# define JVC_NBITS 16 /* dev(8) + func(8) */
2020-08-23 19:23:05 +02:00
# define JVC_UNIT 525 /* us */
2010-04-15 18:46:05 -03:00
# define JVC_HEADER_PULSE (16 * JVC_UNIT) /* lack of header -> repeat */
# define JVC_HEADER_SPACE (8 * JVC_UNIT)
# define JVC_BIT_PULSE (1 * JVC_UNIT)
# define JVC_BIT_0_SPACE (1 * JVC_UNIT)
# define JVC_BIT_1_SPACE (3 * JVC_UNIT)
# define JVC_TRAILER_PULSE (1 * JVC_UNIT)
# define JVC_TRAILER_SPACE (35 * JVC_UNIT)
enum jvc_state {
STATE_INACTIVE ,
STATE_HEADER_SPACE ,
STATE_BIT_PULSE ,
STATE_BIT_SPACE ,
STATE_TRAILER_PULSE ,
STATE_TRAILER_SPACE ,
2010-07-31 11:59:18 -03:00
STATE_CHECK_REPEAT ,
2010-04-15 18:46:05 -03:00
} ;
/**
* ir_jvc_decode ( ) - Decode one JVC pulse or space
2010-10-29 16:08:23 -03:00
* @ 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
2010-04-15 18:46:05 -03:00
*
* This function returns - EINVAL if the pulse violates the state machine
*/
2010-10-29 16:08:23 -03:00
static int ir_jvc_decode ( struct rc_dev * dev , struct ir_raw_event ev )
2010-04-15 18:46:05 -03:00
{
2010-10-29 16:08:23 -03:00
struct jvc_dec * data = & dev - > raw - > jvc ;
2010-04-15 18:46:05 -03:00
2010-10-16 19:56:28 -03:00
if ( ! is_timing_event ( ev ) ) {
if ( ev . reset )
data - > state = STATE_INACTIVE ;
2010-04-15 18:46:05 -03:00
return 0 ;
}
if ( ! geq_margin ( ev . duration , JVC_UNIT , JVC_UNIT / 2 ) )
goto out ;
2018-02-12 07:20:52 -05:00
dev_dbg ( & dev - > dev , " JVC decode started at state %d (%uus %s) \n " ,
2020-08-23 19:23:05 +02:00
data - > state , ev . duration , TO_STR ( ev . pulse ) ) ;
2010-04-15 18:46:05 -03:00
2010-07-31 11:59:18 -03:00
again :
2010-04-15 18:46:05 -03:00
switch ( data - > state ) {
case STATE_INACTIVE :
if ( ! ev . pulse )
break ;
if ( ! eq_margin ( ev . duration , JVC_HEADER_PULSE , JVC_UNIT / 2 ) )
break ;
data - > count = 0 ;
data - > first = true ;
data - > toggle = ! data - > toggle ;
data - > state = STATE_HEADER_SPACE ;
return 0 ;
case STATE_HEADER_SPACE :
if ( ev . pulse )
break ;
if ( ! eq_margin ( ev . duration , JVC_HEADER_SPACE , JVC_UNIT / 2 ) )
break ;
data - > state = STATE_BIT_PULSE ;
return 0 ;
case STATE_BIT_PULSE :
if ( ! ev . pulse )
break ;
if ( ! eq_margin ( ev . duration , JVC_BIT_PULSE , JVC_UNIT / 2 ) )
break ;
data - > state = STATE_BIT_SPACE ;
return 0 ;
case STATE_BIT_SPACE :
if ( ev . pulse )
break ;
2010-06-13 17:29:36 -03:00
data - > bits < < = 1 ;
2010-04-15 18:46:05 -03:00
if ( eq_margin ( ev . duration , JVC_BIT_1_SPACE , JVC_UNIT / 2 ) ) {
2010-06-13 17:29:36 -03:00
data - > bits | = 1 ;
2010-04-15 18:46:05 -03:00
decrease_duration ( & ev , JVC_BIT_1_SPACE ) ;
} else if ( eq_margin ( ev . duration , JVC_BIT_0_SPACE , JVC_UNIT / 2 ) )
decrease_duration ( & ev , JVC_BIT_0_SPACE ) ;
else
break ;
data - > count + + ;
if ( data - > count = = JVC_NBITS )
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 , JVC_TRAILER_PULSE , JVC_UNIT / 2 ) )
break ;
data - > state = STATE_TRAILER_SPACE ;
return 0 ;
case STATE_TRAILER_SPACE :
if ( ev . pulse )
break ;
if ( ! geq_margin ( ev . duration , JVC_TRAILER_SPACE , JVC_UNIT / 2 ) )
break ;
if ( data - > first ) {
u32 scancode ;
2010-06-13 17:29:36 -03:00
scancode = ( bitrev8 ( ( data - > bits > > 8 ) & 0xff ) < < 8 ) |
( bitrev8 ( ( data - > bits > > 0 ) & 0xff ) < < 0 ) ;
2018-02-12 07:20:52 -05:00
dev_dbg ( & dev - > dev , " JVC scancode 0x%04x \n " , scancode ) ;
2017-08-07 16:20:58 -04:00
rc_keydown ( dev , RC_PROTO_JVC , scancode , data - > toggle ) ;
2010-04-15 18:46:05 -03:00
data - > first = false ;
2010-06-13 17:29:36 -03:00
data - > old_bits = data - > bits ;
} else if ( data - > bits = = data - > old_bits ) {
2018-02-12 07:20:52 -05:00
dev_dbg ( & dev - > dev , " JVC repeat \n " ) ;
2010-11-17 13:53:11 -03:00
rc_repeat ( dev ) ;
2010-04-15 18:46:05 -03:00
} else {
2018-02-12 07:20:52 -05:00
dev_dbg ( & dev - > dev , " JVC invalid repeat msg \n " ) ;
2010-04-15 18:46:05 -03:00
break ;
}
data - > count = 0 ;
2010-07-31 11:59:18 -03:00
data - > state = STATE_CHECK_REPEAT ;
2010-04-15 18:46:05 -03:00
return 0 ;
2010-07-31 11:59:18 -03:00
case STATE_CHECK_REPEAT :
if ( ! ev . pulse )
break ;
if ( eq_margin ( ev . duration , JVC_HEADER_PULSE , JVC_UNIT / 2 ) )
data - > state = STATE_INACTIVE ;
else
data - > state = STATE_BIT_PULSE ;
goto again ;
2010-04-15 18:46:05 -03:00
}
out :
2018-02-12 07:20:52 -05:00
dev_dbg ( & dev - > dev , " JVC decode failed at state %d (%uus %s) \n " ,
2020-08-23 19:23:05 +02:00
data - > state , ev . duration , TO_STR ( ev . pulse ) ) ;
2010-04-15 18:46:05 -03:00
data - > state = STATE_INACTIVE ;
return - EINVAL ;
}
2016-12-06 17:01:03 -02:00
static const struct ir_raw_timings_pd ir_jvc_timings = {
. header_pulse = JVC_HEADER_PULSE ,
. header_space = JVC_HEADER_SPACE ,
. bit_pulse = JVC_BIT_PULSE ,
. bit_space [ 0 ] = JVC_BIT_0_SPACE ,
. bit_space [ 1 ] = JVC_BIT_1_SPACE ,
. trailer_pulse = JVC_TRAILER_PULSE ,
. trailer_space = JVC_TRAILER_SPACE ,
. msb_first = 1 ,
} ;
/**
* ir_jvc_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_jvc_encode ( enum rc_proto protocol , u32 scancode ,
2016-12-06 17:01:03 -02:00
struct ir_raw_event * events , unsigned int max )
{
struct ir_raw_event * e = events ;
int ret ;
u32 raw = ( bitrev8 ( ( scancode > > 8 ) & 0xff ) < < 8 ) |
( bitrev8 ( ( scancode > > 0 ) & 0xff ) < < 0 ) ;
ret = ir_raw_gen_pd ( & e , max , & ir_jvc_timings , JVC_NBITS , raw ) ;
if ( ret < 0 )
return ret ;
return e - events ;
}
2010-04-15 18:46:05 -03:00
static struct ir_raw_handler jvc_handler = {
2017-08-07 16:20:58 -04:00
. protocols = RC_PROTO_BIT_JVC ,
2010-04-15 18:46:05 -03:00
. decode = ir_jvc_decode ,
2016-12-06 17:01:03 -02:00
. encode = ir_jvc_encode ,
2017-02-25 06:51:30 -05:00
. carrier = 38000 ,
2018-03-23 16:47:37 -04:00
. min_timeout = JVC_TRAILER_SPACE ,
2010-04-15 18:46:05 -03:00
} ;
static int __init ir_jvc_decode_init ( void )
{
ir_raw_handler_register ( & jvc_handler ) ;
printk ( KERN_INFO " IR JVC protocol handler initialized \n " ) ;
return 0 ;
}
static void __exit ir_jvc_decode_exit ( void )
{
ir_raw_handler_unregister ( & jvc_handler ) ;
}
module_init ( ir_jvc_decode_init ) ;
module_exit ( ir_jvc_decode_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " David Härdeman <david@hardeman.nu> " ) ;
MODULE_DESCRIPTION ( " JVC IR protocol decoder " ) ;