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