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 <linux/module.h> 17 #include "rc-core-priv.h" 18 19 #define JVC_NBITS 16 /* dev(8) + func(8) */ 20 #define JVC_UNIT 525000 /* ns */ 21 #define JVC_HEADER_PULSE (16 * JVC_UNIT) /* lack of header -> repeat */ 22 #define JVC_HEADER_SPACE (8 * JVC_UNIT) 23 #define JVC_BIT_PULSE (1 * JVC_UNIT) 24 #define JVC_BIT_0_SPACE (1 * JVC_UNIT) 25 #define JVC_BIT_1_SPACE (3 * JVC_UNIT) 26 #define JVC_TRAILER_PULSE (1 * JVC_UNIT) 27 #define JVC_TRAILER_SPACE (35 * JVC_UNIT) 28 29 enum jvc_state { 30 STATE_INACTIVE, 31 STATE_HEADER_SPACE, 32 STATE_BIT_PULSE, 33 STATE_BIT_SPACE, 34 STATE_TRAILER_PULSE, 35 STATE_TRAILER_SPACE, 36 STATE_CHECK_REPEAT, 37 }; 38 39 /** 40 * ir_jvc_decode() - Decode one JVC pulse or space 41 * @dev: the struct rc_dev descriptor of the device 42 * @ev: the struct ir_raw_event descriptor of the pulse/space 43 * 44 * This function returns -EINVAL if the pulse violates the state machine 45 */ 46 static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev) 47 { 48 struct jvc_dec *data = &dev->raw->jvc; 49 50 if (!is_timing_event(ev)) { 51 if (ev.reset) 52 data->state = STATE_INACTIVE; 53 return 0; 54 } 55 56 if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2)) 57 goto out; 58 59 IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n", 60 data->state, TO_US(ev.duration), TO_STR(ev.pulse)); 61 62 again: 63 switch (data->state) { 64 65 case STATE_INACTIVE: 66 if (!ev.pulse) 67 break; 68 69 if (!eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2)) 70 break; 71 72 data->count = 0; 73 data->first = true; 74 data->toggle = !data->toggle; 75 data->state = STATE_HEADER_SPACE; 76 return 0; 77 78 case STATE_HEADER_SPACE: 79 if (ev.pulse) 80 break; 81 82 if (!eq_margin(ev.duration, JVC_HEADER_SPACE, JVC_UNIT / 2)) 83 break; 84 85 data->state = STATE_BIT_PULSE; 86 return 0; 87 88 case STATE_BIT_PULSE: 89 if (!ev.pulse) 90 break; 91 92 if (!eq_margin(ev.duration, JVC_BIT_PULSE, JVC_UNIT / 2)) 93 break; 94 95 data->state = STATE_BIT_SPACE; 96 return 0; 97 98 case STATE_BIT_SPACE: 99 if (ev.pulse) 100 break; 101 102 data->bits <<= 1; 103 if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) { 104 data->bits |= 1; 105 decrease_duration(&ev, JVC_BIT_1_SPACE); 106 } else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2)) 107 decrease_duration(&ev, JVC_BIT_0_SPACE); 108 else 109 break; 110 data->count++; 111 112 if (data->count == JVC_NBITS) 113 data->state = STATE_TRAILER_PULSE; 114 else 115 data->state = STATE_BIT_PULSE; 116 return 0; 117 118 case STATE_TRAILER_PULSE: 119 if (!ev.pulse) 120 break; 121 122 if (!eq_margin(ev.duration, JVC_TRAILER_PULSE, JVC_UNIT / 2)) 123 break; 124 125 data->state = STATE_TRAILER_SPACE; 126 return 0; 127 128 case STATE_TRAILER_SPACE: 129 if (ev.pulse) 130 break; 131 132 if (!geq_margin(ev.duration, JVC_TRAILER_SPACE, JVC_UNIT / 2)) 133 break; 134 135 if (data->first) { 136 u32 scancode; 137 scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) | 138 (bitrev8((data->bits >> 0) & 0xff) << 0); 139 IR_dprintk(1, "JVC scancode 0x%04x\n", scancode); 140 rc_keydown(dev, RC_PROTO_JVC, scancode, data->toggle); 141 data->first = false; 142 data->old_bits = data->bits; 143 } else if (data->bits == data->old_bits) { 144 IR_dprintk(1, "JVC repeat\n"); 145 rc_repeat(dev); 146 } else { 147 IR_dprintk(1, "JVC invalid repeat msg\n"); 148 break; 149 } 150 151 data->count = 0; 152 data->state = STATE_CHECK_REPEAT; 153 return 0; 154 155 case STATE_CHECK_REPEAT: 156 if (!ev.pulse) 157 break; 158 159 if (eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2)) 160 data->state = STATE_INACTIVE; 161 else 162 data->state = STATE_BIT_PULSE; 163 goto again; 164 } 165 166 out: 167 IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n", 168 data->state, TO_US(ev.duration), TO_STR(ev.pulse)); 169 data->state = STATE_INACTIVE; 170 return -EINVAL; 171 } 172 173 static const struct ir_raw_timings_pd ir_jvc_timings = { 174 .header_pulse = JVC_HEADER_PULSE, 175 .header_space = JVC_HEADER_SPACE, 176 .bit_pulse = JVC_BIT_PULSE, 177 .bit_space[0] = JVC_BIT_0_SPACE, 178 .bit_space[1] = JVC_BIT_1_SPACE, 179 .trailer_pulse = JVC_TRAILER_PULSE, 180 .trailer_space = JVC_TRAILER_SPACE, 181 .msb_first = 1, 182 }; 183 184 /** 185 * ir_jvc_encode() - Encode a scancode as a stream of raw events 186 * 187 * @protocol: protocol to encode 188 * @scancode: scancode to encode 189 * @events: array of raw ir events to write into 190 * @max: maximum size of @events 191 * 192 * Returns: The number of events written. 193 * -ENOBUFS if there isn't enough space in the array to fit the 194 * encoding. In this case all @max events will have been written. 195 */ 196 static int ir_jvc_encode(enum rc_proto protocol, u32 scancode, 197 struct ir_raw_event *events, unsigned int max) 198 { 199 struct ir_raw_event *e = events; 200 int ret; 201 u32 raw = (bitrev8((scancode >> 8) & 0xff) << 8) | 202 (bitrev8((scancode >> 0) & 0xff) << 0); 203 204 ret = ir_raw_gen_pd(&e, max, &ir_jvc_timings, JVC_NBITS, raw); 205 if (ret < 0) 206 return ret; 207 208 return e - events; 209 } 210 211 static struct ir_raw_handler jvc_handler = { 212 .protocols = RC_PROTO_BIT_JVC, 213 .decode = ir_jvc_decode, 214 .encode = ir_jvc_encode, 215 }; 216 217 static int __init ir_jvc_decode_init(void) 218 { 219 ir_raw_handler_register(&jvc_handler); 220 221 printk(KERN_INFO "IR JVC protocol handler initialized\n"); 222 return 0; 223 } 224 225 static void __exit ir_jvc_decode_exit(void) 226 { 227 ir_raw_handler_unregister(&jvc_handler); 228 } 229 230 module_init(ir_jvc_decode_init); 231 module_exit(ir_jvc_decode_exit); 232 233 MODULE_LICENSE("GPL"); 234 MODULE_AUTHOR("David Härdeman <david@hardeman.nu>"); 235 MODULE_DESCRIPTION("JVC IR protocol decoder"); 236