1/* ir-jvc-decoder.c - handle JVC IR Pulse/Space protocol 2 * 3 * Copyright (C) 2010 by David H��rdeman <david@hardeman.nu> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation version 2 of the License. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 */ 14 15#include <linux/bitrev.h> 16#include "ir-core-priv.h" 17 18#define JVC_NBITS 16 /* dev(8) + func(8) */ 19#define JVC_UNIT 525000 /* ns */ 20#define JVC_HEADER_PULSE (16 * JVC_UNIT) /* lack of header -> repeat */ 21#define JVC_HEADER_SPACE (8 * JVC_UNIT) 22#define JVC_BIT_PULSE (1 * JVC_UNIT) 23#define JVC_BIT_0_SPACE (1 * JVC_UNIT) 24#define JVC_BIT_1_SPACE (3 * JVC_UNIT) 25#define JVC_TRAILER_PULSE (1 * JVC_UNIT) 26#define JVC_TRAILER_SPACE (35 * JVC_UNIT) 27 28enum jvc_state { 29 STATE_INACTIVE, 30 STATE_HEADER_SPACE, 31 STATE_BIT_PULSE, 32 STATE_BIT_SPACE, 33 STATE_TRAILER_PULSE, 34 STATE_TRAILER_SPACE, 35 STATE_CHECK_REPEAT, 36}; 37 38/** 39 * ir_jvc_decode() - Decode one JVC pulse or space 40 * @input_dev: the struct input_dev descriptor of the device 41 * @duration: the struct ir_raw_event descriptor of the pulse/space 42 * 43 * This function returns -EINVAL if the pulse violates the state machine 44 */ 45static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev) 46{ 47 struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); 48 struct jvc_dec *data = &ir_dev->raw->jvc; 49 50 if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC)) 51 return 0; 52 53 if (IS_RESET(ev)) { 54 data->state = STATE_INACTIVE; 55 return 0; 56 } 57 58 if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2)) 59 goto out; 60 61 IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n", 62 data->state, TO_US(ev.duration), TO_STR(ev.pulse)); 63 64again: 65 switch (data->state) { 66 67 case STATE_INACTIVE: 68 if (!ev.pulse) 69 break; 70 71 if (!eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2)) 72 break; 73 74 data->count = 0; 75 data->first = true; 76 data->toggle = !data->toggle; 77 data->state = STATE_HEADER_SPACE; 78 return 0; 79 80 case STATE_HEADER_SPACE: 81 if (ev.pulse) 82 break; 83 84 if (!eq_margin(ev.duration, JVC_HEADER_SPACE, JVC_UNIT / 2)) 85 break; 86 87 data->state = STATE_BIT_PULSE; 88 return 0; 89 90 case STATE_BIT_PULSE: 91 if (!ev.pulse) 92 break; 93 94 if (!eq_margin(ev.duration, JVC_BIT_PULSE, JVC_UNIT / 2)) 95 break; 96 97 data->state = STATE_BIT_SPACE; 98 return 0; 99 100 case STATE_BIT_SPACE: 101 if (ev.pulse) 102 break; 103 104 data->bits <<= 1; 105 if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) { 106 data->bits |= 1; 107 decrease_duration(&ev, JVC_BIT_1_SPACE); 108 } else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2)) 109 decrease_duration(&ev, JVC_BIT_0_SPACE); 110 else 111 break; 112 data->count++; 113 114 if (data->count == JVC_NBITS) 115 data->state = STATE_TRAILER_PULSE; 116 else 117 data->state = STATE_BIT_PULSE; 118 return 0; 119 120 case STATE_TRAILER_PULSE: 121 if (!ev.pulse) 122 break; 123 124 if (!eq_margin(ev.duration, JVC_TRAILER_PULSE, JVC_UNIT / 2)) 125 break; 126 127 data->state = STATE_TRAILER_SPACE; 128 return 0; 129 130 case STATE_TRAILER_SPACE: 131 if (ev.pulse) 132 break; 133 134 if (!geq_margin(ev.duration, JVC_TRAILER_SPACE, JVC_UNIT / 2)) 135 break; 136 137 if (data->first) { 138 u32 scancode; 139 scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) | 140 (bitrev8((data->bits >> 0) & 0xff) << 0); 141 IR_dprintk(1, "JVC scancode 0x%04x\n", scancode); 142 ir_keydown(input_dev, scancode, data->toggle); 143 data->first = false; 144 data->old_bits = data->bits; 145 } else if (data->bits == data->old_bits) { 146 IR_dprintk(1, "JVC repeat\n"); 147 ir_repeat(input_dev); 148 } else { 149 IR_dprintk(1, "JVC invalid repeat msg\n"); 150 break; 151 } 152 153 data->count = 0; 154 data->state = STATE_CHECK_REPEAT; 155 return 0; 156 157 case STATE_CHECK_REPEAT: 158 if (!ev.pulse) 159 break; 160 161 if (eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2)) 162 data->state = STATE_INACTIVE; 163 else 164 data->state = STATE_BIT_PULSE; 165 goto again; 166 } 167 168out: 169 IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n", 170 data->state, TO_US(ev.duration), TO_STR(ev.pulse)); 171 data->state = STATE_INACTIVE; 172 return -EINVAL; 173} 174 175static struct ir_raw_handler jvc_handler = { 176 .protocols = IR_TYPE_JVC, 177 .decode = ir_jvc_decode, 178}; 179 180static int __init ir_jvc_decode_init(void) 181{ 182 ir_raw_handler_register(&jvc_handler); 183 184 printk(KERN_INFO "IR JVC protocol handler initialized\n"); 185 return 0; 186} 187 188static void __exit ir_jvc_decode_exit(void) 189{ 190 ir_raw_handler_unregister(&jvc_handler); 191} 192 193module_init(ir_jvc_decode_init); 194module_exit(ir_jvc_decode_exit); 195 196MODULE_LICENSE("GPL"); 197MODULE_AUTHOR("David H��rdeman <david@hardeman.nu>"); 198MODULE_DESCRIPTION("JVC IR protocol decoder"); 199