1 // SPDX-License-Identifier: GPL-2.0+ 2 // ir-rcmm-decoder.c - A decoder for the RCMM IR protocol 3 // 4 // Copyright (C) 2018 by Patrick Lerda <patrick9876@free.fr> 5 6 #include "rc-core-priv.h" 7 #include <linux/module.h> 8 #include <linux/version.h> 9 10 #define RCMM_UNIT 166667 /* nanosecs */ 11 #define RCMM_PREFIX_PULSE 416666 /* 166666.666666666*2.5 */ 12 #define RCMM_PULSE_0 277777 /* 166666.666666666*(1+2/3) */ 13 #define RCMM_PULSE_1 444444 /* 166666.666666666*(2+2/3) */ 14 #define RCMM_PULSE_2 611111 /* 166666.666666666*(3+2/3) */ 15 #define RCMM_PULSE_3 777778 /* 166666.666666666*(4+2/3) */ 16 17 enum rcmm_state { 18 STATE_INACTIVE, 19 STATE_LOW, 20 STATE_BUMP, 21 STATE_VALUE, 22 STATE_FINISHED, 23 }; 24 25 static bool rcmm_mode(const struct rcmm_dec *data) 26 { 27 return !((0x000c0000 & data->bits) == 0x000c0000); 28 } 29 30 static int rcmm_miscmode(struct rc_dev *dev, struct rcmm_dec *data) 31 { 32 switch (data->count) { 33 case 24: 34 if (dev->enabled_protocols & RC_PROTO_BIT_RCMM24) { 35 rc_keydown(dev, RC_PROTO_RCMM24, data->bits, 0); 36 data->state = STATE_INACTIVE; 37 return 0; 38 } 39 return -1; 40 41 case 12: 42 if (dev->enabled_protocols & RC_PROTO_BIT_RCMM12) { 43 rc_keydown(dev, RC_PROTO_RCMM12, data->bits, 0); 44 data->state = STATE_INACTIVE; 45 return 0; 46 } 47 return -1; 48 } 49 50 return -1; 51 } 52 53 /** 54 * ir_rcmm_decode() - Decode one RCMM pulse or space 55 * @dev: the struct rc_dev descriptor of the device 56 * @ev: the struct ir_raw_event descriptor of the pulse/space 57 * 58 * This function returns -EINVAL if the pulse violates the state machine 59 */ 60 static int ir_rcmm_decode(struct rc_dev *dev, struct ir_raw_event ev) 61 { 62 struct rcmm_dec *data = &dev->raw->rcmm; 63 u32 scancode; 64 u8 toggle; 65 int value; 66 67 if (!(dev->enabled_protocols & (RC_PROTO_BIT_RCMM32 | 68 RC_PROTO_BIT_RCMM24 | 69 RC_PROTO_BIT_RCMM12))) 70 return 0; 71 72 if (!is_timing_event(ev)) { 73 if (ev.reset) 74 data->state = STATE_INACTIVE; 75 return 0; 76 } 77 78 switch (data->state) { 79 case STATE_INACTIVE: 80 if (!ev.pulse) 81 break; 82 83 if (!eq_margin(ev.duration, RCMM_PREFIX_PULSE, RCMM_UNIT / 2)) 84 break; 85 86 data->state = STATE_LOW; 87 data->count = 0; 88 data->bits = 0; 89 return 0; 90 91 case STATE_LOW: 92 if (ev.pulse) 93 break; 94 95 if (!eq_margin(ev.duration, RCMM_PULSE_0, RCMM_UNIT / 2)) 96 break; 97 98 data->state = STATE_BUMP; 99 return 0; 100 101 case STATE_BUMP: 102 if (!ev.pulse) 103 break; 104 105 if (!eq_margin(ev.duration, RCMM_UNIT, RCMM_UNIT / 2)) 106 break; 107 108 data->state = STATE_VALUE; 109 return 0; 110 111 case STATE_VALUE: 112 if (ev.pulse) 113 break; 114 115 if (eq_margin(ev.duration, RCMM_PULSE_0, RCMM_UNIT / 2)) 116 value = 0; 117 else if (eq_margin(ev.duration, RCMM_PULSE_1, RCMM_UNIT / 2)) 118 value = 1; 119 else if (eq_margin(ev.duration, RCMM_PULSE_2, RCMM_UNIT / 2)) 120 value = 2; 121 else if (eq_margin(ev.duration, RCMM_PULSE_3, RCMM_UNIT / 2)) 122 value = 3; 123 else 124 value = -1; 125 126 if (value == -1) { 127 if (!rcmm_miscmode(dev, data)) 128 return 0; 129 break; 130 } 131 132 data->bits <<= 2; 133 data->bits |= value; 134 135 data->count += 2; 136 137 if (data->count < 32) 138 data->state = STATE_BUMP; 139 else 140 data->state = STATE_FINISHED; 141 142 return 0; 143 144 case STATE_FINISHED: 145 if (!ev.pulse) 146 break; 147 148 if (!eq_margin(ev.duration, RCMM_UNIT, RCMM_UNIT / 2)) 149 break; 150 151 if (rcmm_mode(data)) { 152 toggle = !!(0x8000 & data->bits); 153 scancode = data->bits & ~0x8000; 154 } else { 155 toggle = 0; 156 scancode = data->bits; 157 } 158 159 if (dev->enabled_protocols & RC_PROTO_BIT_RCMM32) { 160 rc_keydown(dev, RC_PROTO_RCMM32, scancode, toggle); 161 data->state = STATE_INACTIVE; 162 return 0; 163 } 164 165 break; 166 } 167 168 data->state = STATE_INACTIVE; 169 return -EINVAL; 170 } 171 172 static const int rcmmspace[] = { 173 RCMM_PULSE_0, 174 RCMM_PULSE_1, 175 RCMM_PULSE_2, 176 RCMM_PULSE_3, 177 }; 178 179 static int ir_rcmm_rawencoder(struct ir_raw_event **ev, unsigned int max, 180 unsigned int n, u32 data) 181 { 182 int i; 183 int ret; 184 185 ret = ir_raw_gen_pulse_space(ev, &max, RCMM_PREFIX_PULSE, RCMM_PULSE_0); 186 if (ret) 187 return ret; 188 189 for (i = n - 2; i >= 0; i -= 2) { 190 const unsigned int space = rcmmspace[(data >> i) & 3]; 191 192 ret = ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, space); 193 if (ret) 194 return ret; 195 } 196 197 return ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, RCMM_PULSE_3 * 2); 198 } 199 200 static int ir_rcmm_encode(enum rc_proto protocol, u32 scancode, 201 struct ir_raw_event *events, unsigned int max) 202 { 203 struct ir_raw_event *e = events; 204 int ret; 205 206 switch (protocol) { 207 case RC_PROTO_RCMM32: 208 ret = ir_rcmm_rawencoder(&e, max, 32, scancode); 209 break; 210 case RC_PROTO_RCMM24: 211 ret = ir_rcmm_rawencoder(&e, max, 24, scancode); 212 break; 213 case RC_PROTO_RCMM12: 214 ret = ir_rcmm_rawencoder(&e, max, 12, scancode); 215 break; 216 default: 217 ret = -EINVAL; 218 } 219 220 if (ret < 0) 221 return ret; 222 223 return e - events; 224 } 225 226 static struct ir_raw_handler rcmm_handler = { 227 .protocols = RC_PROTO_BIT_RCMM32 | 228 RC_PROTO_BIT_RCMM24 | 229 RC_PROTO_BIT_RCMM12, 230 .decode = ir_rcmm_decode, 231 .encode = ir_rcmm_encode, 232 .carrier = 36000, 233 .min_timeout = RCMM_PULSE_3 + RCMM_UNIT, 234 }; 235 236 static int __init ir_rcmm_decode_init(void) 237 { 238 ir_raw_handler_register(&rcmm_handler); 239 240 pr_info("IR RCMM protocol handler initialized\n"); 241 return 0; 242 } 243 244 static void __exit ir_rcmm_decode_exit(void) 245 { 246 ir_raw_handler_unregister(&rcmm_handler); 247 } 248 249 module_init(ir_rcmm_decode_init); 250 module_exit(ir_rcmm_decode_exit); 251 252 MODULE_LICENSE("GPL"); 253 MODULE_AUTHOR("Patrick Lerda"); 254 MODULE_DESCRIPTION("RCMM IR protocol decoder"); 255