1 /* ir-rc6-decoder.c - A decoder for the RC6 IR 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 "rc-core-priv.h" 16 #include <linux/module.h> 17 18 /* 19 * This decoder currently supports: 20 * RC6-0-16 (standard toggle bit in header) 21 * RC6-6A-24 (no toggle bit) 22 * RC6-6A-32 (MCE version with toggle bit in body) 23 */ 24 25 #define RC6_UNIT 444444 /* us */ 26 #define RC6_HEADER_NBITS 4 /* not including toggle bit */ 27 #define RC6_0_NBITS 16 28 #define RC6_6A_SMALL_NBITS 24 29 #define RC6_6A_LARGE_NBITS 32 30 #define RC6_PREFIX_PULSE (6 * RC6_UNIT) 31 #define RC6_PREFIX_SPACE (2 * RC6_UNIT) 32 #define RC6_BIT_START (1 * RC6_UNIT) 33 #define RC6_BIT_END (1 * RC6_UNIT) 34 #define RC6_TOGGLE_START (2 * RC6_UNIT) 35 #define RC6_TOGGLE_END (2 * RC6_UNIT) 36 #define RC6_MODE_MASK 0x07 /* for the header bits */ 37 #define RC6_STARTBIT_MASK 0x08 /* for the header bits */ 38 #define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */ 39 40 enum rc6_mode { 41 RC6_MODE_0, 42 RC6_MODE_6A, 43 RC6_MODE_UNKNOWN, 44 }; 45 46 enum rc6_state { 47 STATE_INACTIVE, 48 STATE_PREFIX_SPACE, 49 STATE_HEADER_BIT_START, 50 STATE_HEADER_BIT_END, 51 STATE_TOGGLE_START, 52 STATE_TOGGLE_END, 53 STATE_BODY_BIT_START, 54 STATE_BODY_BIT_END, 55 STATE_FINISHED, 56 }; 57 58 static enum rc6_mode rc6_mode(struct rc6_dec *data) 59 { 60 switch (data->header & RC6_MODE_MASK) { 61 case 0: 62 return RC6_MODE_0; 63 case 6: 64 if (!data->toggle) 65 return RC6_MODE_6A; 66 /* fall through */ 67 default: 68 return RC6_MODE_UNKNOWN; 69 } 70 } 71 72 /** 73 * ir_rc6_decode() - Decode one RC6 pulse or space 74 * @dev: the struct rc_dev descriptor of the device 75 * @ev: the struct ir_raw_event descriptor of the pulse/space 76 * 77 * This function returns -EINVAL if the pulse violates the state machine 78 */ 79 static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev) 80 { 81 struct rc6_dec *data = &dev->raw->rc6; 82 u32 scancode; 83 u8 toggle; 84 85 if (!(dev->raw->enabled_protocols & RC_TYPE_RC6)) 86 return 0; 87 88 if (!is_timing_event(ev)) { 89 if (ev.reset) 90 data->state = STATE_INACTIVE; 91 return 0; 92 } 93 94 if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) 95 goto out; 96 97 again: 98 IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n", 99 data->state, TO_US(ev.duration), TO_STR(ev.pulse)); 100 101 if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) 102 return 0; 103 104 switch (data->state) { 105 106 case STATE_INACTIVE: 107 if (!ev.pulse) 108 break; 109 110 /* Note: larger margin on first pulse since each RC6_UNIT 111 is quite short and some hardware takes some time to 112 adjust to the signal */ 113 if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT)) 114 break; 115 116 data->state = STATE_PREFIX_SPACE; 117 data->count = 0; 118 return 0; 119 120 case STATE_PREFIX_SPACE: 121 if (ev.pulse) 122 break; 123 124 if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2)) 125 break; 126 127 data->state = STATE_HEADER_BIT_START; 128 return 0; 129 130 case STATE_HEADER_BIT_START: 131 if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) 132 break; 133 134 data->header <<= 1; 135 if (ev.pulse) 136 data->header |= 1; 137 data->count++; 138 data->state = STATE_HEADER_BIT_END; 139 return 0; 140 141 case STATE_HEADER_BIT_END: 142 if (!is_transition(&ev, &dev->raw->prev_ev)) 143 break; 144 145 if (data->count == RC6_HEADER_NBITS) 146 data->state = STATE_TOGGLE_START; 147 else 148 data->state = STATE_HEADER_BIT_START; 149 150 decrease_duration(&ev, RC6_BIT_END); 151 goto again; 152 153 case STATE_TOGGLE_START: 154 if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2)) 155 break; 156 157 data->toggle = ev.pulse; 158 data->state = STATE_TOGGLE_END; 159 return 0; 160 161 case STATE_TOGGLE_END: 162 if (!is_transition(&ev, &dev->raw->prev_ev) || 163 !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2)) 164 break; 165 166 if (!(data->header & RC6_STARTBIT_MASK)) { 167 IR_dprintk(1, "RC6 invalid start bit\n"); 168 break; 169 } 170 171 data->state = STATE_BODY_BIT_START; 172 decrease_duration(&ev, RC6_TOGGLE_END); 173 data->count = 0; 174 175 switch (rc6_mode(data)) { 176 case RC6_MODE_0: 177 data->wanted_bits = RC6_0_NBITS; 178 break; 179 case RC6_MODE_6A: 180 /* This might look weird, but we basically 181 check the value of the first body bit to 182 determine the number of bits in mode 6A */ 183 if ((!ev.pulse && !geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) || 184 geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) 185 data->wanted_bits = RC6_6A_LARGE_NBITS; 186 else 187 data->wanted_bits = RC6_6A_SMALL_NBITS; 188 break; 189 default: 190 IR_dprintk(1, "RC6 unknown mode\n"); 191 goto out; 192 } 193 goto again; 194 195 case STATE_BODY_BIT_START: 196 if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) 197 break; 198 199 data->body <<= 1; 200 if (ev.pulse) 201 data->body |= 1; 202 data->count++; 203 data->state = STATE_BODY_BIT_END; 204 return 0; 205 206 case STATE_BODY_BIT_END: 207 if (!is_transition(&ev, &dev->raw->prev_ev)) 208 break; 209 210 if (data->count == data->wanted_bits) 211 data->state = STATE_FINISHED; 212 else 213 data->state = STATE_BODY_BIT_START; 214 215 decrease_duration(&ev, RC6_BIT_END); 216 goto again; 217 218 case STATE_FINISHED: 219 if (ev.pulse) 220 break; 221 222 switch (rc6_mode(data)) { 223 case RC6_MODE_0: 224 scancode = data->body & 0xffff; 225 toggle = data->toggle; 226 IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n", 227 scancode, toggle); 228 break; 229 case RC6_MODE_6A: 230 if (data->wanted_bits == RC6_6A_LARGE_NBITS) { 231 toggle = data->body & RC6_6A_MCE_TOGGLE_MASK ? 1 : 0; 232 scancode = data->body & ~RC6_6A_MCE_TOGGLE_MASK; 233 } else { 234 toggle = 0; 235 scancode = data->body & 0xffffff; 236 } 237 238 IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n", 239 scancode, toggle); 240 break; 241 default: 242 IR_dprintk(1, "RC6 unknown mode\n"); 243 goto out; 244 } 245 246 rc_keydown(dev, scancode, toggle); 247 data->state = STATE_INACTIVE; 248 return 0; 249 } 250 251 out: 252 IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n", 253 data->state, TO_US(ev.duration), TO_STR(ev.pulse)); 254 data->state = STATE_INACTIVE; 255 return -EINVAL; 256 } 257 258 static struct ir_raw_handler rc6_handler = { 259 .protocols = RC_TYPE_RC6, 260 .decode = ir_rc6_decode, 261 }; 262 263 static int __init ir_rc6_decode_init(void) 264 { 265 ir_raw_handler_register(&rc6_handler); 266 267 printk(KERN_INFO "IR RC6 protocol handler initialized\n"); 268 return 0; 269 } 270 271 static void __exit ir_rc6_decode_exit(void) 272 { 273 ir_raw_handler_unregister(&rc6_handler); 274 } 275 276 module_init(ir_rc6_decode_init); 277 module_exit(ir_rc6_decode_exit); 278 279 MODULE_LICENSE("GPL"); 280 MODULE_AUTHOR("David Härdeman <david@hardeman.nu>"); 281 MODULE_DESCRIPTION("RC6 IR protocol decoder"); 282