Path: blob/master/drivers/media/rc/ir-jvc-decoder.c
15111 views
/* ir-jvc-decoder.c - handle JVC IR Pulse/Space protocol1*2* Copyright (C) 2010 by David Härdeman <[email protected]>3*4* This program is free software; you can redistribute it and/or modify5* it under the terms of the GNU General Public License as published by6* the Free Software Foundation version 2 of the License.7*8* This program is distributed in the hope that it will be useful,9* but WITHOUT ANY WARRANTY; without even the implied warranty of10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11* GNU General Public License for more details.12*/1314#include <linux/bitrev.h>15#include "rc-core-priv.h"1617#define JVC_NBITS 16 /* dev(8) + func(8) */18#define JVC_UNIT 525000 /* ns */19#define JVC_HEADER_PULSE (16 * JVC_UNIT) /* lack of header -> repeat */20#define JVC_HEADER_SPACE (8 * JVC_UNIT)21#define JVC_BIT_PULSE (1 * JVC_UNIT)22#define JVC_BIT_0_SPACE (1 * JVC_UNIT)23#define JVC_BIT_1_SPACE (3 * JVC_UNIT)24#define JVC_TRAILER_PULSE (1 * JVC_UNIT)25#define JVC_TRAILER_SPACE (35 * JVC_UNIT)2627enum jvc_state {28STATE_INACTIVE,29STATE_HEADER_SPACE,30STATE_BIT_PULSE,31STATE_BIT_SPACE,32STATE_TRAILER_PULSE,33STATE_TRAILER_SPACE,34STATE_CHECK_REPEAT,35};3637/**38* ir_jvc_decode() - Decode one JVC pulse or space39* @dev: the struct rc_dev descriptor of the device40* @duration: the struct ir_raw_event descriptor of the pulse/space41*42* This function returns -EINVAL if the pulse violates the state machine43*/44static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)45{46struct jvc_dec *data = &dev->raw->jvc;4748if (!(dev->raw->enabled_protocols & RC_TYPE_JVC))49return 0;5051if (!is_timing_event(ev)) {52if (ev.reset)53data->state = STATE_INACTIVE;54return 0;55}5657if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2))58goto out;5960IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n",61data->state, TO_US(ev.duration), TO_STR(ev.pulse));6263again:64switch (data->state) {6566case STATE_INACTIVE:67if (!ev.pulse)68break;6970if (!eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))71break;7273data->count = 0;74data->first = true;75data->toggle = !data->toggle;76data->state = STATE_HEADER_SPACE;77return 0;7879case STATE_HEADER_SPACE:80if (ev.pulse)81break;8283if (!eq_margin(ev.duration, JVC_HEADER_SPACE, JVC_UNIT / 2))84break;8586data->state = STATE_BIT_PULSE;87return 0;8889case STATE_BIT_PULSE:90if (!ev.pulse)91break;9293if (!eq_margin(ev.duration, JVC_BIT_PULSE, JVC_UNIT / 2))94break;9596data->state = STATE_BIT_SPACE;97return 0;9899case STATE_BIT_SPACE:100if (ev.pulse)101break;102103data->bits <<= 1;104if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {105data->bits |= 1;106decrease_duration(&ev, JVC_BIT_1_SPACE);107} else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))108decrease_duration(&ev, JVC_BIT_0_SPACE);109else110break;111data->count++;112113if (data->count == JVC_NBITS)114data->state = STATE_TRAILER_PULSE;115else116data->state = STATE_BIT_PULSE;117return 0;118119case STATE_TRAILER_PULSE:120if (!ev.pulse)121break;122123if (!eq_margin(ev.duration, JVC_TRAILER_PULSE, JVC_UNIT / 2))124break;125126data->state = STATE_TRAILER_SPACE;127return 0;128129case STATE_TRAILER_SPACE:130if (ev.pulse)131break;132133if (!geq_margin(ev.duration, JVC_TRAILER_SPACE, JVC_UNIT / 2))134break;135136if (data->first) {137u32 scancode;138scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |139(bitrev8((data->bits >> 0) & 0xff) << 0);140IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);141rc_keydown(dev, scancode, data->toggle);142data->first = false;143data->old_bits = data->bits;144} else if (data->bits == data->old_bits) {145IR_dprintk(1, "JVC repeat\n");146rc_repeat(dev);147} else {148IR_dprintk(1, "JVC invalid repeat msg\n");149break;150}151152data->count = 0;153data->state = STATE_CHECK_REPEAT;154return 0;155156case STATE_CHECK_REPEAT:157if (!ev.pulse)158break;159160if (eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))161data->state = STATE_INACTIVE;162else163data->state = STATE_BIT_PULSE;164goto again;165}166167out:168IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n",169data->state, TO_US(ev.duration), TO_STR(ev.pulse));170data->state = STATE_INACTIVE;171return -EINVAL;172}173174static struct ir_raw_handler jvc_handler = {175.protocols = RC_TYPE_JVC,176.decode = ir_jvc_decode,177};178179static int __init ir_jvc_decode_init(void)180{181ir_raw_handler_register(&jvc_handler);182183printk(KERN_INFO "IR JVC protocol handler initialized\n");184return 0;185}186187static void __exit ir_jvc_decode_exit(void)188{189ir_raw_handler_unregister(&jvc_handler);190}191192module_init(ir_jvc_decode_init);193module_exit(ir_jvc_decode_exit);194195MODULE_LICENSE("GPL");196MODULE_AUTHOR("David Härdeman <[email protected]>");197MODULE_DESCRIPTION("JVC IR protocol decoder");198199200